From 2307c9515e8b2c8b8c9df1d8ef64cbf0d3a6683d Mon Sep 17 00:00:00 2001 From: noisyfox Date: Wed, 29 Jun 2016 18:21:11 +0800 Subject: [PATCH 1/5] add proxy settings --- .../Controller/ShadowsocksController.cs | 14 ++ shadowsocks-csharp/Data/cn.txt | 8 + shadowsocks-csharp/Model/Configuration.cs | 5 +- shadowsocks-csharp/View/MenuViewController.cs | 28 +++ shadowsocks-csharp/View/ProxyForm.Designer.cs | 218 ++++++++++++++++++ shadowsocks-csharp/View/ProxyForm.cs | 116 ++++++++++ shadowsocks-csharp/View/ProxyForm.resx | 120 ++++++++++ shadowsocks-csharp/shadowsocks-csharp.csproj | 9 + 8 files changed, 517 insertions(+), 1 deletion(-) create mode 100644 shadowsocks-csharp/View/ProxyForm.Designer.cs create mode 100644 shadowsocks-csharp/View/ProxyForm.cs create mode 100644 shadowsocks-csharp/View/ProxyForm.resx diff --git a/shadowsocks-csharp/Controller/ShadowsocksController.cs b/shadowsocks-csharp/Controller/ShadowsocksController.cs index 643d68ab..b4c80379 100755 --- a/shadowsocks-csharp/Controller/ShadowsocksController.cs +++ b/shadowsocks-csharp/Controller/ShadowsocksController.cs @@ -191,6 +191,20 @@ namespace Shadowsocks.Controller } } + public void DisableProxy() + { + _config.useProxy = false; + SaveConfig(_config); + } + + public void EnableProxy(string proxy, int port) + { + _config.useProxy = true; + _config.proxyServer = proxy; + _config.proxyPort = port; + SaveConfig(_config); + } + public void SelectServerIndex(int index) { _config.index = index; diff --git a/shadowsocks-csharp/Data/cn.txt b/shadowsocks-csharp/Data/cn.txt index a1211fb4..644b2d24 100644 --- a/shadowsocks-csharp/Data/cn.txt +++ b/shadowsocks-csharp/Data/cn.txt @@ -12,6 +12,7 @@ Servers=服务器 Edit Servers...=编辑服务器... Statistics Config...=统计配置... Start on Boot=开机启动 +Proxy...=代理设置... Allow Clients from LAN=允许来自局域网的连接 Local PAC=使用本地 PAC Online PAC=使用在线 PAC @@ -50,6 +51,13 @@ New server=未配置的服务器 Move &Up=上移(&U) Move D&own=下移(&O) +# Proxy Form + +Edit Proxy=代理设置 +Use Proxy=使用代理 +Proxy Addr=代理地址 +Proxy Port=代理端口 + # Log Form &File=文件(&F) diff --git a/shadowsocks-csharp/Model/Configuration.cs b/shadowsocks-csharp/Model/Configuration.cs index 10a42124..0df1e94e 100755 --- a/shadowsocks-csharp/Model/Configuration.cs +++ b/shadowsocks-csharp/Model/Configuration.cs @@ -25,6 +25,9 @@ namespace Shadowsocks.Model public bool availabilityStatistics; public bool autoCheckUpdate; public LogViewerConfig logViewer; + public bool useProxy; + public string proxyServer; + public int proxyPort; private static string CONFIG_FILE = "gui-config.json"; @@ -128,7 +131,7 @@ namespace Shadowsocks.Model throw new ArgumentException(I18N.GetString("Password can not be blank")); } - private static void CheckServer(string server) + public static void CheckServer(string server) { if (server.IsNullOrEmpty()) throw new ArgumentException(I18N.GetString("Server IP can not be blank")); diff --git a/shadowsocks-csharp/View/MenuViewController.cs b/shadowsocks-csharp/View/MenuViewController.cs index fab3d729..d7bd99ff 100755 --- a/shadowsocks-csharp/View/MenuViewController.cs +++ b/shadowsocks-csharp/View/MenuViewController.cs @@ -45,7 +45,9 @@ namespace Shadowsocks.View private MenuItem editGFWUserRuleItem; private MenuItem editOnlinePACItem; private MenuItem autoCheckUpdatesToggleItem; + private MenuItem proxyItem; private ConfigForm configForm; + private ProxyForm proxyForm; private List logForms = new List(); private bool logFormsVisible = false; private string _urlToOpen; @@ -211,6 +213,7 @@ namespace Shadowsocks.View this.editGFWUserRuleItem = CreateMenuItem("Edit User Rule for GFWList...", new EventHandler(this.EditUserRuleFileForGFWListItem_Click)), this.editOnlinePACItem = CreateMenuItem("Edit Online PAC URL...", new EventHandler(this.UpdateOnlinePACURLItem_Click)), }), + this.proxyItem = CreateMenuItem("Proxy...", new EventHandler(this.proxyItem_Click)), new MenuItem("-"), this.AutoStartupItem = CreateMenuItem("Start on Boot", new EventHandler(this.AutoStartupItem_Click)), this.ShareOverLANItem = CreateMenuItem("Allow Clients from LAN", new EventHandler(this.ShareOverLANItem_Click)), @@ -377,6 +380,20 @@ namespace Shadowsocks.View } } + private void ShowProxyForm() + { + if (proxyForm != null) + { + proxyForm.Activate(); + } + else + { + proxyForm = new ProxyForm(controller); + proxyForm.Show(); + proxyForm.FormClosed += proxyForm_FormClosed; + } + } + private void ShowLogForms() { if (logForms.Count == 0) @@ -415,6 +432,12 @@ namespace Shadowsocks.View } } + void proxyForm_FormClosed(object sender, FormClosedEventArgs e) + { + proxyForm = null; + Utils.ReleaseMemory(true); + } + private void Config_Click(object sender, EventArgs e) { ShowConfigForm(); @@ -721,5 +744,10 @@ namespace Shadowsocks.View { updateChecker.CheckUpdate(controller.GetConfigurationCopy()); } + + private void proxyItem_Click(object sender, EventArgs e) + { + ShowProxyForm(); + } } } diff --git a/shadowsocks-csharp/View/ProxyForm.Designer.cs b/shadowsocks-csharp/View/ProxyForm.Designer.cs new file mode 100644 index 00000000..991da996 --- /dev/null +++ b/shadowsocks-csharp/View/ProxyForm.Designer.cs @@ -0,0 +1,218 @@ +namespace Shadowsocks.View +{ + partial class ProxyForm + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); + this.tableLayoutPanel3 = new System.Windows.Forms.TableLayoutPanel(); + this.MyCancelButton = new System.Windows.Forms.Button(); + this.OKButton = new System.Windows.Forms.Button(); + this.UseProxyCheckBox = new System.Windows.Forms.CheckBox(); + this.tableLayoutPanel2 = new System.Windows.Forms.TableLayoutPanel(); + this.ProxyAddrLabel = new System.Windows.Forms.Label(); + this.ProxyServerTextBox = new System.Windows.Forms.TextBox(); + this.ProxyPortLable = new System.Windows.Forms.Label(); + this.ProxyPortTextBox = new System.Windows.Forms.TextBox(); + this.tableLayoutPanel1.SuspendLayout(); + this.tableLayoutPanel3.SuspendLayout(); + this.tableLayoutPanel2.SuspendLayout(); + this.SuspendLayout(); + // + // tableLayoutPanel1 + // + this.tableLayoutPanel1.AutoSize = true; + this.tableLayoutPanel1.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this.tableLayoutPanel1.ColumnCount = 1; + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel1.Controls.Add(this.tableLayoutPanel3, 0, 2); + this.tableLayoutPanel1.Controls.Add(this.UseProxyCheckBox, 0, 0); + this.tableLayoutPanel1.Controls.Add(this.tableLayoutPanel2, 0, 1); + this.tableLayoutPanel1.Location = new System.Drawing.Point(15, 15); + this.tableLayoutPanel1.Name = "tableLayoutPanel1"; + this.tableLayoutPanel1.RowCount = 3; + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel1.Size = new System.Drawing.Size(395, 87); + this.tableLayoutPanel1.TabIndex = 0; + // + // tableLayoutPanel3 + // + this.tableLayoutPanel3.AutoSize = true; + this.tableLayoutPanel3.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this.tableLayoutPanel3.ColumnCount = 2; + this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 20F)); + this.tableLayoutPanel3.Controls.Add(this.MyCancelButton, 1, 0); + this.tableLayoutPanel3.Controls.Add(this.OKButton, 0, 0); + this.tableLayoutPanel3.Dock = System.Windows.Forms.DockStyle.Right; + this.tableLayoutPanel3.Location = new System.Drawing.Point(236, 58); + this.tableLayoutPanel3.Margin = new System.Windows.Forms.Padding(3, 3, 0, 3); + this.tableLayoutPanel3.Name = "tableLayoutPanel3"; + this.tableLayoutPanel3.RowCount = 1; + this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel3.Size = new System.Drawing.Size(159, 26); + this.tableLayoutPanel3.TabIndex = 9; + // + // MyCancelButton + // + this.MyCancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.MyCancelButton.Dock = System.Windows.Forms.DockStyle.Right; + this.MyCancelButton.Location = new System.Drawing.Point(84, 3); + this.MyCancelButton.Margin = new System.Windows.Forms.Padding(3, 3, 0, 0); + this.MyCancelButton.Name = "MyCancelButton"; + this.MyCancelButton.Size = new System.Drawing.Size(75, 23); + this.MyCancelButton.TabIndex = 13; + this.MyCancelButton.Text = "Cancel"; + this.MyCancelButton.UseVisualStyleBackColor = true; + this.MyCancelButton.Click += new System.EventHandler(this.CancelButton_Click); + // + // OKButton + // + this.OKButton.DialogResult = System.Windows.Forms.DialogResult.OK; + this.OKButton.Dock = System.Windows.Forms.DockStyle.Right; + this.OKButton.Location = new System.Drawing.Point(3, 3); + this.OKButton.Margin = new System.Windows.Forms.Padding(3, 3, 3, 0); + this.OKButton.Name = "OKButton"; + this.OKButton.Size = new System.Drawing.Size(75, 23); + this.OKButton.TabIndex = 12; + this.OKButton.Text = "OK"; + this.OKButton.UseVisualStyleBackColor = true; + this.OKButton.Click += new System.EventHandler(this.OKButton_Click); + // + // UseProxyCheckBox + // + this.UseProxyCheckBox.AutoSize = true; + this.UseProxyCheckBox.Location = new System.Drawing.Point(3, 3); + this.UseProxyCheckBox.Name = "UseProxyCheckBox"; + this.UseProxyCheckBox.Size = new System.Drawing.Size(78, 16); + this.UseProxyCheckBox.TabIndex = 0; + this.UseProxyCheckBox.Text = "Use Proxy"; + this.UseProxyCheckBox.UseVisualStyleBackColor = true; + this.UseProxyCheckBox.CheckedChanged += new System.EventHandler(this.UseProxyCheckBox_CheckedChanged); + // + // tableLayoutPanel2 + // + this.tableLayoutPanel2.AutoSize = true; + this.tableLayoutPanel2.ColumnCount = 4; + this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel2.Controls.Add(this.ProxyAddrLabel, 0, 0); + this.tableLayoutPanel2.Controls.Add(this.ProxyServerTextBox, 1, 0); + this.tableLayoutPanel2.Controls.Add(this.ProxyPortLable, 2, 0); + this.tableLayoutPanel2.Controls.Add(this.ProxyPortTextBox, 3, 0); + this.tableLayoutPanel2.Location = new System.Drawing.Point(3, 25); + this.tableLayoutPanel2.Name = "tableLayoutPanel2"; + this.tableLayoutPanel2.RowCount = 1; + this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel2.Size = new System.Drawing.Size(389, 27); + this.tableLayoutPanel2.TabIndex = 1; + // + // ProxyAddrLabel + // + this.ProxyAddrLabel.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.ProxyAddrLabel.AutoSize = true; + this.ProxyAddrLabel.Location = new System.Drawing.Point(3, 7); + this.ProxyAddrLabel.Name = "ProxyAddrLabel"; + this.ProxyAddrLabel.Size = new System.Drawing.Size(65, 12); + this.ProxyAddrLabel.TabIndex = 0; + this.ProxyAddrLabel.Text = "Proxy Addr"; + // + // ProxyServerTextBox + // + this.ProxyServerTextBox.Location = new System.Drawing.Point(74, 3); + this.ProxyServerTextBox.MaxLength = 512; + this.ProxyServerTextBox.Name = "ProxyServerTextBox"; + this.ProxyServerTextBox.Size = new System.Drawing.Size(135, 21); + this.ProxyServerTextBox.TabIndex = 1; + this.ProxyServerTextBox.WordWrap = false; + // + // ProxyPortLable + // + this.ProxyPortLable.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.ProxyPortLable.AutoSize = true; + this.ProxyPortLable.Location = new System.Drawing.Point(215, 7); + this.ProxyPortLable.Name = "ProxyPortLable"; + this.ProxyPortLable.Size = new System.Drawing.Size(65, 12); + this.ProxyPortLable.TabIndex = 2; + this.ProxyPortLable.Text = "Proxy Port"; + // + // ProxyPortTextBox + // + this.ProxyPortTextBox.Location = new System.Drawing.Point(286, 3); + this.ProxyPortTextBox.MaxLength = 10; + this.ProxyPortTextBox.Name = "ProxyPortTextBox"; + this.ProxyPortTextBox.Size = new System.Drawing.Size(100, 21); + this.ProxyPortTextBox.TabIndex = 3; + this.ProxyPortTextBox.WordWrap = false; + // + // ProxyForm + // + this.AcceptButton = this.OKButton; + this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; + this.AutoSize = true; + this.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this.CancelButton = this.MyCancelButton; + this.ClientSize = new System.Drawing.Size(441, 149); + this.Controls.Add(this.tableLayoutPanel1); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "ProxyForm"; + this.Padding = new System.Windows.Forms.Padding(12, 12, 12, 9); + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; + this.Text = "Edit Proxy"; + this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.ProxyForm_FormClosed); + this.tableLayoutPanel1.ResumeLayout(false); + this.tableLayoutPanel1.PerformLayout(); + this.tableLayoutPanel3.ResumeLayout(false); + this.tableLayoutPanel2.ResumeLayout(false); + this.tableLayoutPanel2.PerformLayout(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1; + private System.Windows.Forms.CheckBox UseProxyCheckBox; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel2; + private System.Windows.Forms.Label ProxyAddrLabel; + private System.Windows.Forms.TextBox ProxyServerTextBox; + private System.Windows.Forms.Label ProxyPortLable; + private System.Windows.Forms.TextBox ProxyPortTextBox; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel3; + private System.Windows.Forms.Button MyCancelButton; + private System.Windows.Forms.Button OKButton; + } +} \ No newline at end of file diff --git a/shadowsocks-csharp/View/ProxyForm.cs b/shadowsocks-csharp/View/ProxyForm.cs new file mode 100644 index 00000000..4f2a900d --- /dev/null +++ b/shadowsocks-csharp/View/ProxyForm.cs @@ -0,0 +1,116 @@ +using System; +using System.Drawing; +using System.Windows.Forms; +using Shadowsocks.Controller; +using Shadowsocks.Model; +using Shadowsocks.Properties; + +namespace Shadowsocks.View +{ + public partial class ProxyForm : Form + { + private ShadowsocksController controller; + + // this is a copy of configuration that we are working on + private Configuration _modifiedConfiguration; + + public ProxyForm(ShadowsocksController controller) + { + this.Font = System.Drawing.SystemFonts.MessageBoxFont; + InitializeComponent(); + + UpdateTexts(); + this.Icon = Icon.FromHandle(Resources.ssw128.GetHicon()); + + this.controller = controller; + controller.ConfigChanged += controller_ConfigChanged; + + UpdateEnabled(); + LoadCurrentConfiguration(); + } + + private void UpdateTexts() + { + UseProxyCheckBox.Text = I18N.GetString("Use Proxy"); + ProxyAddrLabel.Text = I18N.GetString("Proxy Addr"); + ProxyPortLable.Text = I18N.GetString("Proxy Port"); + OKButton.Text = I18N.GetString("OK"); + MyCancelButton.Text = I18N.GetString("Cancel"); + this.Text = I18N.GetString("Edit Proxy"); + } + + private void controller_ConfigChanged(object sender, EventArgs e) + { + LoadCurrentConfiguration(); + } + + private void LoadCurrentConfiguration() + { + _modifiedConfiguration = controller.GetConfigurationCopy(); + + UseProxyCheckBox.Checked = _modifiedConfiguration.useProxy; + ProxyServerTextBox.Text = _modifiedConfiguration.proxyServer; + ProxyPortTextBox.Text = _modifiedConfiguration.proxyPort.ToString(); + } + + private void OKButton_Click(object sender, EventArgs e) + { + if (UseProxyCheckBox.Checked) + { + try + { + var proxy = ProxyServerTextBox.Text; + var port = int.Parse(ProxyPortTextBox.Text); + Configuration.CheckServer(proxy); + Configuration.CheckPort(port); + + controller.EnableProxy(proxy, port); + } + catch (FormatException) + { + MessageBox.Show(I18N.GetString("Illegal port number format")); + return; + } + catch (Exception ex) + { + MessageBox.Show(ex.Message); + return; + } + } + else + { + controller.DisableProxy(); + } + this.Close(); + } + + private void CancelButton_Click(object sender, EventArgs e) + { + this.Close(); + } + + private void ProxyForm_FormClosed(object sender, FormClosedEventArgs e) + { + controller.ConfigChanged -= controller_ConfigChanged; + } + + private void UseProxyCheckBox_CheckedChanged(object sender, EventArgs e) + { + UpdateEnabled(); + } + + private void UpdateEnabled() + { + if (UseProxyCheckBox.Checked) + { + ProxyServerTextBox.Enabled = true; + ProxyPortTextBox.Enabled = true; + } + else + { + ProxyServerTextBox.Enabled = false; + ProxyPortTextBox.Enabled = false; + } + } + } +} diff --git a/shadowsocks-csharp/View/ProxyForm.resx b/shadowsocks-csharp/View/ProxyForm.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/shadowsocks-csharp/View/ProxyForm.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/shadowsocks-csharp/shadowsocks-csharp.csproj b/shadowsocks-csharp/shadowsocks-csharp.csproj index 008134ae..d339b634 100644 --- a/shadowsocks-csharp/shadowsocks-csharp.csproj +++ b/shadowsocks-csharp/shadowsocks-csharp.csproj @@ -232,6 +232,12 @@ LogForm.cs + + Form + + + ProxyForm.cs + Form @@ -262,6 +268,9 @@ LogForm.cs + + ProxyForm.cs + QRCodeForm.cs From 95d4e3a0c03b8ba19439ad2a5859f87fced38755 Mon Sep 17 00:00:00 2001 From: noisyfox Date: Wed, 29 Jun 2016 22:38:51 +0800 Subject: [PATCH 2/5] Add proxy support --- .../Controller/Service/TCPRelay.cs | 111 ++++++++++++++---- .../Controller/ShadowsocksController.cs | 2 +- shadowsocks-csharp/Proxy/DirectConnect.cs | 98 ++++++++++++++++ shadowsocks-csharp/Proxy/IProxy.cs | 38 ++++++ shadowsocks-csharp/shadowsocks-csharp.csproj | 2 + 5 files changed, 230 insertions(+), 21 deletions(-) create mode 100644 shadowsocks-csharp/Proxy/DirectConnect.cs create mode 100644 shadowsocks-csharp/Proxy/IProxy.cs diff --git a/shadowsocks-csharp/Controller/Service/TCPRelay.cs b/shadowsocks-csharp/Controller/Service/TCPRelay.cs index 9c162780..31def20c 100644 --- a/shadowsocks-csharp/Controller/Service/TCPRelay.cs +++ b/shadowsocks-csharp/Controller/Service/TCPRelay.cs @@ -7,6 +7,7 @@ using System.Timers; using Shadowsocks.Controller.Strategy; using Shadowsocks.Encryption; using Shadowsocks.Model; +using Shadowsocks.Proxy; namespace Shadowsocks.Controller { @@ -14,15 +15,17 @@ namespace Shadowsocks.Controller { private ShadowsocksController _controller; private DateTime _lastSweepTime; + private Configuration _config; public ISet Handlers { get; set; } - public TCPRelay(ShadowsocksController controller) + public TCPRelay(ShadowsocksController controller, Configuration conf) { _controller = controller; + _config = conf; Handlers = new HashSet(); _lastSweepTime = DateTime.Now; } @@ -91,7 +94,7 @@ namespace Shadowsocks.Controller public IEncryptor encryptor; public Server server; // Client socket. - public Socket remote; + public IProxy remote; public Socket connection; public ShadowsocksController controller; public TCPRelay relay; @@ -100,7 +103,8 @@ namespace Shadowsocks.Controller private const int maxRetry = 4; private int retryCount = 0; - private bool connected; + private bool proxyConnected; + private bool destConnected; private byte command; private byte[] _firstPacket; @@ -345,7 +349,7 @@ namespace Shadowsocks.Controller if (ar.AsyncState != null) { connection.EndSend(ar); - Logging.Debug(remote, RecvSize, "TCP Relay"); + Logging.Debug(remote.LocalEndPoint, remote.DestEndPoint, RecvSize, "TCP Relay"); connection.BeginReceive(connetionRecvBuffer, 0, RecvSize, 0, new AsyncCallback(ReadAll), null); } else @@ -353,7 +357,7 @@ namespace Shadowsocks.Controller int bytesRead = connection.EndReceive(ar); if (bytesRead > 0) { - Logging.Debug(remote, RecvSize, "TCP Relay"); + Logging.Debug(remote.LocalEndPoint, remote.DestEndPoint, RecvSize, "TCP Relay"); connection.BeginReceive(connetionRecvBuffer, 0, RecvSize, 0, new AsyncCallback(ReadAll), null); } else @@ -386,6 +390,16 @@ namespace Shadowsocks.Controller } // inner class + private class ProxyTimer : Timer + { + public EndPoint DestEndPoint; + public Server Server; + + public ProxyTimer(int p) : base(p) + { + } + } + private class ServerTimer : Timer { public Server Server; @@ -411,31 +425,88 @@ namespace Shadowsocks.Controller } IPEndPoint remoteEP = new IPEndPoint(ipAddress, server.server_port); - remote = new Socket(ipAddress.AddressFamily, - SocketType.Stream, ProtocolType.Tcp); - remote.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true); + remote = new DirectConnect(); + + ProxyTimer proxyTimer = new ProxyTimer(3000); + proxyTimer.AutoReset = false; + proxyTimer.Elapsed += proxyConnectTimer_Elapsed; + proxyTimer.Enabled = true; + proxyTimer.DestEndPoint = remoteEP; + proxyTimer.Server = server; + + proxyConnected = false; + + // Connect to the proxy server. + remote.BeginConnectProxy(remoteEP, new AsyncCallback(ProxyConnectCallback), proxyTimer); + } + catch (Exception e) + { + Logging.LogUsefulException(e); + Close(); + } + } + + private void proxyConnectTimer_Elapsed(object sender, ElapsedEventArgs e) + { + if (proxyConnected || destConnected) + { + return; + } + var ep = ((ProxyTimer)sender).DestEndPoint; + + Logging.Info($"Proxy {ep} timed out"); + remote.Close(); + RetryConnect(); + } + + private void ProxyConnectCallback(IAsyncResult ar) + { + Server server = null; + if (closed) + { + return; + } + try + { + ProxyTimer timer = (ProxyTimer)ar.AsyncState; + var destEP = timer.DestEndPoint; + server = timer.Server; + timer.Elapsed -= proxyConnectTimer_Elapsed; + timer.Enabled = false; + timer.Dispose(); + + // Complete the connection. + remote.EndConnectProxy(ar); + + proxyConnected = true; + + Logging.Debug($"Socket connected to proxy {remote.ProxyEndPoint}"); + _startConnectTime = DateTime.Now; ServerTimer connectTimer = new ServerTimer(3000); connectTimer.AutoReset = false; - connectTimer.Elapsed += connectTimer_Elapsed; + connectTimer.Elapsed += destConnectTimer_Elapsed; connectTimer.Enabled = true; connectTimer.Server = server; - connected = false; + destConnected = false; // Connect to the remote endpoint. - remote.BeginConnect(remoteEP, new AsyncCallback(ConnectCallback), connectTimer); + remote.BeginConnectDest(destEP, new AsyncCallback(ConnectCallback), connectTimer); + } + catch (ArgumentException) + { } catch (Exception e) { Logging.LogUsefulException(e); - Close(); + RetryConnect(); } } - private void connectTimer_Elapsed(object sender, ElapsedEventArgs e) + private void destConnectTimer_Elapsed(object sender, ElapsedEventArgs e) { - if (connected) + if (destConnected) { return; } @@ -475,16 +546,16 @@ namespace Shadowsocks.Controller { ServerTimer timer = (ServerTimer)ar.AsyncState; server = timer.Server; - timer.Elapsed -= connectTimer_Elapsed; + timer.Elapsed -= destConnectTimer_Elapsed; timer.Enabled = false; timer.Dispose(); // Complete the connection. - remote.EndConnect(ar); + remote.EndConnectDest(ar); - connected = true; + destConnected = true; - Logging.Debug($"Socket connected to {remote.RemoteEndPoint}"); + Logging.Debug($"Socket connected to {remote.DestEndPoint}"); var latency = DateTime.Now - _startConnectTime; IStrategy strategy = controller.GetCurrentStrategy(); @@ -554,7 +625,7 @@ namespace Shadowsocks.Controller } encryptor.Decrypt(remoteRecvBuffer, bytesRead, remoteSendBuffer, out bytesToSend); } - Logging.Debug(remote, bytesToSend, "TCP Relay", "@PipeRemoteReceiveCallback() (download)"); + Logging.Debug(remote.LocalEndPoint, remote.DestEndPoint, bytesToSend, "TCP Relay", "@PipeRemoteReceiveCallback() (download)"); connection.BeginSend(remoteSendBuffer, 0, bytesToSend, 0, new AsyncCallback(PipeConnectionSendCallback), null); IStrategy strategy = controller.GetCurrentStrategy(); @@ -606,7 +677,7 @@ namespace Shadowsocks.Controller } encryptor.Encrypt(connetionRecvBuffer, bytesRead, connetionSendBuffer, out bytesToSend); } - Logging.Debug(remote, bytesToSend, "TCP Relay", "@PipeConnectionReceiveCallback() (upload)"); + Logging.Debug(remote.LocalEndPoint, remote.DestEndPoint, bytesToSend, "TCP Relay", "@PipeConnectionReceiveCallback() (upload)"); tcprelay.UpdateOutboundCounter(server, bytesToSend); _startSendingTime = DateTime.Now; _bytesToSend = bytesToSend; diff --git a/shadowsocks-csharp/Controller/ShadowsocksController.cs b/shadowsocks-csharp/Controller/ShadowsocksController.cs index b4c80379..bbe880e3 100755 --- a/shadowsocks-csharp/Controller/ShadowsocksController.cs +++ b/shadowsocks-csharp/Controller/ShadowsocksController.cs @@ -394,7 +394,7 @@ namespace Shadowsocks.Controller polipoRunner.Start(_config); - TCPRelay tcpRelay = new TCPRelay(this); + TCPRelay tcpRelay = new TCPRelay(this, _config); UDPRelay udpRelay = new UDPRelay(this); List services = new List(); services.Add(tcpRelay); diff --git a/shadowsocks-csharp/Proxy/DirectConnect.cs b/shadowsocks-csharp/Proxy/DirectConnect.cs new file mode 100644 index 00000000..48af6ac7 --- /dev/null +++ b/shadowsocks-csharp/Proxy/DirectConnect.cs @@ -0,0 +1,98 @@ +using System; +using System.Net; +using System.Net.Sockets; +using System.Threading; + +namespace Shadowsocks.Proxy +{ + public class DirectConnect : IProxy + { + private class FakeAsyncResult : IAsyncResult + { + public FakeAsyncResult(object state) + { + AsyncState = state; + } + + public bool IsCompleted { get; } = true; + public WaitHandle AsyncWaitHandle { get; } = null; + public object AsyncState { get; } + public bool CompletedSynchronously { get; } = true; + } + + private Socket _remote; + + public EndPoint LocalEndPoint => _remote.LocalEndPoint; + + public EndPoint ProxyEndPoint { get; private set; } + + public EndPoint DestEndPoint { get; private set; } + + + public IAsyncResult BeginConnectProxy(EndPoint remoteEP, AsyncCallback callback, object state) + { + // do nothing + ProxyEndPoint = remoteEP; + + var r = new FakeAsyncResult(state); + callback?.Invoke(r); + + return r; + } + + public void EndConnectProxy(IAsyncResult asyncResult) + { + // do nothing + } + + public IAsyncResult BeginConnectDest(EndPoint remoteEP, AsyncCallback callback, object state) + { + if (_remote == null) + { + _remote = new Socket(remoteEP.AddressFamily, SocketType.Stream, ProtocolType.Tcp); + _remote.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true); + } + + DestEndPoint = remoteEP; + + return _remote.BeginConnect(remoteEP, callback, state); + } + + public void EndConnectDest(IAsyncResult asyncResult) + { + _remote.EndConnect(asyncResult); + } + + public IAsyncResult BeginSend(byte[] buffer, int offset, int size, SocketFlags socketFlags, AsyncCallback callback, + object state) + { + return _remote.BeginSend(buffer, offset, size, socketFlags, callback, state); + } + + public int EndSend(IAsyncResult asyncResult) + { + return _remote.EndSend(asyncResult); + } + + public IAsyncResult BeginReceive(byte[] buffer, int offset, int size, SocketFlags socketFlags, AsyncCallback callback, + object state) + { + return _remote.BeginReceive(buffer, offset, size, socketFlags, callback, state); + } + + public int EndReceive(IAsyncResult asyncResult) + { + return _remote.EndReceive(asyncResult); + } + + public void Shutdown(SocketShutdown how) + { + _remote?.Shutdown(how); + } + + public void Close() + { + _remote?.Close(); + } + } +} diff --git a/shadowsocks-csharp/Proxy/IProxy.cs b/shadowsocks-csharp/Proxy/IProxy.cs new file mode 100644 index 00000000..39a7c3e7 --- /dev/null +++ b/shadowsocks-csharp/Proxy/IProxy.cs @@ -0,0 +1,38 @@ +using System; +using System.Net; +using System.Net.Sockets; + +namespace Shadowsocks.Proxy +{ + + public interface IProxy + { + EndPoint LocalEndPoint { get; } + + EndPoint ProxyEndPoint { get; } + + EndPoint DestEndPoint { get; } + + IAsyncResult BeginConnectProxy(EndPoint remoteEP, AsyncCallback callback, object state); + + void EndConnectProxy(IAsyncResult asyncResult); + + IAsyncResult BeginConnectDest(EndPoint remoteEP, AsyncCallback callback, object state); + + void EndConnectDest(IAsyncResult asyncResult); + + IAsyncResult BeginSend(byte[] buffer, int offset, int size, SocketFlags socketFlags, AsyncCallback callback, + object state); + + int EndSend(IAsyncResult asyncResult); + + IAsyncResult BeginReceive(byte[] buffer, int offset, int size, SocketFlags socketFlags, AsyncCallback callback, + object state); + + int EndReceive(IAsyncResult asyncResult); + + void Shutdown(SocketShutdown how); + + void Close(); + } +} diff --git a/shadowsocks-csharp/shadowsocks-csharp.csproj b/shadowsocks-csharp/shadowsocks-csharp.csproj index d339b634..3b0adae2 100644 --- a/shadowsocks-csharp/shadowsocks-csharp.csproj +++ b/shadowsocks-csharp/shadowsocks-csharp.csproj @@ -170,6 +170,8 @@ + + From 9493f93c0f8dea6e392d4542d51154904b2f2456 Mon Sep 17 00:00:00 2001 From: noisyfox Date: Thu, 30 Jun 2016 00:09:20 +0800 Subject: [PATCH 3/5] Add Socks5 Proxy --- shadowsocks-csharp/Proxy/DirectConnect.cs | 16 +- shadowsocks-csharp/Proxy/IProxy.cs | 8 +- shadowsocks-csharp/Proxy/Socks5Proxy.cs | 312 +++++++++++++++++++ shadowsocks-csharp/shadowsocks-csharp.csproj | 1 + 4 files changed, 324 insertions(+), 13 deletions(-) create mode 100644 shadowsocks-csharp/Proxy/Socks5Proxy.cs diff --git a/shadowsocks-csharp/Proxy/DirectConnect.cs b/shadowsocks-csharp/Proxy/DirectConnect.cs index 48af6ac7..af8d70ae 100644 --- a/shadowsocks-csharp/Proxy/DirectConnect.cs +++ b/shadowsocks-csharp/Proxy/DirectConnect.cs @@ -29,15 +29,13 @@ namespace Shadowsocks.Proxy public EndPoint DestEndPoint { get; private set; } - public IAsyncResult BeginConnectProxy(EndPoint remoteEP, AsyncCallback callback, object state) + public void BeginConnectProxy(EndPoint remoteEP, AsyncCallback callback, object state) { // do nothing ProxyEndPoint = remoteEP; var r = new FakeAsyncResult(state); callback?.Invoke(r); - - return r; } public void EndConnectProxy(IAsyncResult asyncResult) @@ -45,7 +43,7 @@ namespace Shadowsocks.Proxy // do nothing } - public IAsyncResult BeginConnectDest(EndPoint remoteEP, AsyncCallback callback, object state) + public void BeginConnectDest(EndPoint remoteEP, AsyncCallback callback, object state) { if (_remote == null) { @@ -55,7 +53,7 @@ namespace Shadowsocks.Proxy DestEndPoint = remoteEP; - return _remote.BeginConnect(remoteEP, callback, state); + _remote.BeginConnect(remoteEP, callback, state); } public void EndConnectDest(IAsyncResult asyncResult) @@ -63,10 +61,10 @@ namespace Shadowsocks.Proxy _remote.EndConnect(asyncResult); } - public IAsyncResult BeginSend(byte[] buffer, int offset, int size, SocketFlags socketFlags, AsyncCallback callback, + public void BeginSend(byte[] buffer, int offset, int size, SocketFlags socketFlags, AsyncCallback callback, object state) { - return _remote.BeginSend(buffer, offset, size, socketFlags, callback, state); + _remote.BeginSend(buffer, offset, size, socketFlags, callback, state); } public int EndSend(IAsyncResult asyncResult) @@ -74,10 +72,10 @@ namespace Shadowsocks.Proxy return _remote.EndSend(asyncResult); } - public IAsyncResult BeginReceive(byte[] buffer, int offset, int size, SocketFlags socketFlags, AsyncCallback callback, + public void BeginReceive(byte[] buffer, int offset, int size, SocketFlags socketFlags, AsyncCallback callback, object state) { - return _remote.BeginReceive(buffer, offset, size, socketFlags, callback, state); + _remote.BeginReceive(buffer, offset, size, socketFlags, callback, state); } public int EndReceive(IAsyncResult asyncResult) diff --git a/shadowsocks-csharp/Proxy/IProxy.cs b/shadowsocks-csharp/Proxy/IProxy.cs index 39a7c3e7..4796c92f 100644 --- a/shadowsocks-csharp/Proxy/IProxy.cs +++ b/shadowsocks-csharp/Proxy/IProxy.cs @@ -13,20 +13,20 @@ namespace Shadowsocks.Proxy EndPoint DestEndPoint { get; } - IAsyncResult BeginConnectProxy(EndPoint remoteEP, AsyncCallback callback, object state); + void BeginConnectProxy(EndPoint remoteEP, AsyncCallback callback, object state); void EndConnectProxy(IAsyncResult asyncResult); - IAsyncResult BeginConnectDest(EndPoint remoteEP, AsyncCallback callback, object state); + void BeginConnectDest(EndPoint remoteEP, AsyncCallback callback, object state); void EndConnectDest(IAsyncResult asyncResult); - IAsyncResult BeginSend(byte[] buffer, int offset, int size, SocketFlags socketFlags, AsyncCallback callback, + void BeginSend(byte[] buffer, int offset, int size, SocketFlags socketFlags, AsyncCallback callback, object state); int EndSend(IAsyncResult asyncResult); - IAsyncResult BeginReceive(byte[] buffer, int offset, int size, SocketFlags socketFlags, AsyncCallback callback, + void BeginReceive(byte[] buffer, int offset, int size, SocketFlags socketFlags, AsyncCallback callback, object state); int EndReceive(IAsyncResult asyncResult); diff --git a/shadowsocks-csharp/Proxy/Socks5Proxy.cs b/shadowsocks-csharp/Proxy/Socks5Proxy.cs new file mode 100644 index 00000000..b66a18c4 --- /dev/null +++ b/shadowsocks-csharp/Proxy/Socks5Proxy.cs @@ -0,0 +1,312 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Net.Sockets; +using System.Text; +using System.Threading; +using Shadowsocks.Controller; + +namespace Shadowsocks.Proxy +{ + public class Socks5Proxy : IProxy + { + private class FakeAsyncResult : IAsyncResult + { + public readonly Socks5State innerState; + + private readonly IAsyncResult r; + + public FakeAsyncResult(IAsyncResult orig, Socks5State state) + { + r = orig; + innerState = state; + } + + public bool IsCompleted => r.IsCompleted; + public WaitHandle AsyncWaitHandle => r.AsyncWaitHandle; + public object AsyncState => innerState.AsyncState; + public bool CompletedSynchronously => r.CompletedSynchronously; + } + + private class Socks5State + { + public AsyncCallback Callback { get; set; } + + public object AsyncState { get; set; } + + public int BytesToRead; + + public Exception ex { get; set; } + } + + private Socket _remote; + + private const int Socks5PktMaxSize = 4 + 16 + 2; + private readonly byte[] _receiveBuffer = new byte[Socks5PktMaxSize]; + + public EndPoint LocalEndPoint => _remote.LocalEndPoint; + public EndPoint ProxyEndPoint { get; private set; } + public EndPoint DestEndPoint { get; private set; } + + public void BeginConnectProxy(EndPoint remoteEP, AsyncCallback callback, object state) + { + _remote = new Socket(remoteEP.AddressFamily, SocketType.Stream, ProtocolType.Tcp); + _remote.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true); + + var st = new Socks5State(); + st.Callback = callback; + st.AsyncState = state; + + ProxyEndPoint = remoteEP; + + _remote.BeginConnect(remoteEP, ConnectCallback, st); + } + + public void EndConnectProxy(IAsyncResult asyncResult) + { + var state = ((FakeAsyncResult)asyncResult).innerState; + + if (state.ex != null) + { + throw state.ex; + } + } + + public void BeginConnectDest(EndPoint remoteEP, AsyncCallback callback, object state) + { + var ep = remoteEP as IPEndPoint; + if (ep == null) + { + throw new Exception(I18N.GetString("Proxy request faild")); + } + + byte[] request = null; + byte atyp = 0; + switch (ep.AddressFamily) + { + case AddressFamily.InterNetwork: + request = new byte[4 + 4 + 2]; + atyp = 1; + break; + case AddressFamily.InterNetworkV6: + request = new byte[4 + 16 + 2]; + atyp = 4; + break; + } + if (request == null) + { + throw new Exception(I18N.GetString("Proxy request faild")); + } + + // 构造request包 + var addr = ep.Address.GetAddressBytes(); + request[0] = 5; + request[1] = 1; + request[2] = 0; + request[3] = atyp; + Array.Copy(addr, 0, request, 4, request.Length - 4 - 2); + request[request.Length - 2] = (byte) ((ep.Port >> 8) & 0xff); + request[request.Length - 1] = (byte) (ep.Port & 0xff); + + var st = new Socks5State(); + st.Callback = callback; + st.AsyncState = state; + + DestEndPoint = remoteEP; + + _remote.BeginSend(request, 0, request.Length, 0, Socks5RequestSendCallback, st); + + } + + public void EndConnectDest(IAsyncResult asyncResult) + { + var state = ((FakeAsyncResult)asyncResult).innerState; + + if (state.ex != null) + { + throw state.ex; + } + } + + public void BeginSend(byte[] buffer, int offset, int size, SocketFlags socketFlags, AsyncCallback callback, + object state) + { + _remote.BeginSend(buffer, offset, size, socketFlags, callback, state); + } + + public int EndSend(IAsyncResult asyncResult) + { + return _remote.EndSend(asyncResult); + } + + public void BeginReceive(byte[] buffer, int offset, int size, SocketFlags socketFlags, AsyncCallback callback, + object state) + { + _remote.BeginReceive(buffer, offset, size, socketFlags, callback, state); + } + + public int EndReceive(IAsyncResult asyncResult) + { + return _remote.EndReceive(asyncResult); + } + + public void Shutdown(SocketShutdown how) + { + _remote?.Shutdown(how); + } + + public void Close() + { + _remote?.Close(); + } + + + private void ConnectCallback(IAsyncResult ar) + { + var state = (Socks5State) ar.AsyncState; + try + { + _remote.EndConnect(ar); + + byte[] handshake = {5, 1, 0}; + _remote.BeginSend(handshake, 0, handshake.Length, 0, Socks5HandshakeSendCallback, state); + } + catch (Exception ex) + { + state.ex = ex; + state.Callback?.Invoke(new FakeAsyncResult(ar, state)); + } + } + + private void Socks5HandshakeSendCallback(IAsyncResult ar) + { + var state = (Socks5State)ar.AsyncState; + try + { + _remote.EndSend(ar); + + _remote.BeginReceive(_receiveBuffer, 0, 2, 0, Socks5HandshakeReceiveCallback, state); + } + catch (Exception ex) + { + state.ex = ex; + state.Callback?.Invoke(new FakeAsyncResult(ar, state)); + } + } + + private void Socks5HandshakeReceiveCallback(IAsyncResult ar) + { + Exception ex = null; + var state = (Socks5State)ar.AsyncState; + try + { + var bytesRead = _remote.EndReceive(ar); + if (bytesRead >= 2) + { + if (_receiveBuffer[0] != 5 || _receiveBuffer[1] != 0) + { + ex = new Exception(I18N.GetString("Proxy handshake faild")); + } + } + else + { + ex = new Exception(I18N.GetString("Proxy handshake faild")); + } + } + catch (Exception ex2) + { + ex = ex2; + } + state.ex = ex; + state.Callback?.Invoke(new FakeAsyncResult(ar, state)); + } + + + private void Socks5RequestSendCallback(IAsyncResult ar) + { + var state = (Socks5State)ar.AsyncState; + try + { + _remote.EndSend(ar); + + _remote.BeginReceive(_receiveBuffer, 0, 4, 0, Socks5ReplyReceiveCallback, state); + } + catch (Exception ex) + { + state.ex = ex; + state.Callback?.Invoke(new FakeAsyncResult(ar, state)); + } + } + + private void Socks5ReplyReceiveCallback(IAsyncResult ar) + { + var state = (Socks5State)ar.AsyncState; + try + { + var bytesRead = _remote.EndReceive(ar); + if (bytesRead >= 4) + { + if (_receiveBuffer[0] == 5 && _receiveBuffer[1] == 0) + { + // 跳过剩下的reply + switch (_receiveBuffer[3]) // atyp + { + case 1: + state.BytesToRead = 4 + 2; + _remote.BeginReceive(_receiveBuffer, 0, 4 + 2, 0, Socks5ReplyReceiveCallback2, state); + break; + case 4: + state.BytesToRead = 16 + 2; + _remote.BeginReceive(_receiveBuffer, 0, 16 + 2, 0, Socks5ReplyReceiveCallback2, state); + break; + default: + state.ex = new Exception(I18N.GetString("Proxy request faild")); + state.Callback?.Invoke(new FakeAsyncResult(ar, state)); + break; + } + } + else + { + state.ex = new Exception(I18N.GetString("Proxy request faild")); + state.Callback?.Invoke(new FakeAsyncResult(ar, state)); + } + } + else + { + state.ex = new Exception(I18N.GetString("Proxy request faild")); + state.Callback?.Invoke(new FakeAsyncResult(ar, state)); + } + } + catch (Exception ex) + { + state.ex = ex; + state.Callback?.Invoke(new FakeAsyncResult(ar, state)); + } + } + + + private void Socks5ReplyReceiveCallback2(IAsyncResult ar) + { + Exception ex = null; + var state = (Socks5State)ar.AsyncState; + try + { + var bytesRead = _remote.EndReceive(ar); + var bytesNeedSkip = state.BytesToRead; + + if (bytesRead < bytesNeedSkip) + { + ex = new Exception(I18N.GetString("Proxy request faild")); + } + } + catch (Exception ex2) + { + ex = ex2; + } + + state.ex = ex; + state.Callback?.Invoke(new FakeAsyncResult(ar, state)); + } + } +} diff --git a/shadowsocks-csharp/shadowsocks-csharp.csproj b/shadowsocks-csharp/shadowsocks-csharp.csproj index 3b0adae2..8b7dabd0 100644 --- a/shadowsocks-csharp/shadowsocks-csharp.csproj +++ b/shadowsocks-csharp/shadowsocks-csharp.csproj @@ -207,6 +207,7 @@ + From 4a1aa01a4fd59ab8ee34b8219d9459a52976fc7e Mon Sep 17 00:00:00 2001 From: noisyfox Date: Thu, 30 Jun 2016 00:09:45 +0800 Subject: [PATCH 4/5] Enable proxy switch --- .../Controller/Service/TCPRelay.cs | 33 +++++++++++++++---- 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/shadowsocks-csharp/Controller/Service/TCPRelay.cs b/shadowsocks-csharp/Controller/Service/TCPRelay.cs index 31def20c..d812f01e 100644 --- a/shadowsocks-csharp/Controller/Service/TCPRelay.cs +++ b/shadowsocks-csharp/Controller/Service/TCPRelay.cs @@ -41,7 +41,7 @@ namespace Shadowsocks.Controller return false; } socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true); - TCPHandler handler = new TCPHandler(this); + TCPHandler handler = new TCPHandler(this, _config); handler.connection = socket; handler.controller = _controller; handler.relay = this; @@ -98,6 +98,7 @@ namespace Shadowsocks.Controller public Socket connection; public ShadowsocksController controller; public TCPRelay relay; + public Configuration config; public DateTime lastActivity; @@ -140,9 +141,10 @@ namespace Shadowsocks.Controller private int _bytesToSend; private TCPRelay tcprelay; // TODO: tcprelay ?= relay - public TCPHandler(TCPRelay tcprelay) + public TCPHandler(TCPRelay tcprelay, Configuration config) { this.tcprelay = tcprelay; + this.config = config; } public void CreateRemote() @@ -423,21 +425,40 @@ namespace Shadowsocks.Controller IPHostEntry ipHostInfo = Dns.GetHostEntry(server.server); ipAddress = ipHostInfo.AddressList[0]; } - IPEndPoint remoteEP = new IPEndPoint(ipAddress, server.server_port); + IPEndPoint destEP = new IPEndPoint(ipAddress, server.server_port); + + // Setting up proxy + IPEndPoint proxyEP; + if (config.useProxy) + { + parsed = IPAddress.TryParse(config.proxyServer, out ipAddress); + if (!parsed) + { + IPHostEntry ipHostInfo = Dns.GetHostEntry(config.proxyServer); + ipAddress = ipHostInfo.AddressList[0]; + } + + remote = new Socks5Proxy(); + proxyEP = new IPEndPoint(ipAddress, config.proxyPort); + } + else + { + remote = new DirectConnect(); + proxyEP = destEP; + } - remote = new DirectConnect(); ProxyTimer proxyTimer = new ProxyTimer(3000); proxyTimer.AutoReset = false; proxyTimer.Elapsed += proxyConnectTimer_Elapsed; proxyTimer.Enabled = true; - proxyTimer.DestEndPoint = remoteEP; + proxyTimer.DestEndPoint = destEP; proxyTimer.Server = server; proxyConnected = false; // Connect to the proxy server. - remote.BeginConnectProxy(remoteEP, new AsyncCallback(ProxyConnectCallback), proxyTimer); + remote.BeginConnectProxy(proxyEP, new AsyncCallback(ProxyConnectCallback), proxyTimer); } catch (Exception e) { From e23641c522bed53598e867d4a6708e3f72621bd2 Mon Sep 17 00:00:00 2001 From: Noisyfox He Date: Mon, 8 Aug 2016 22:10:40 +1000 Subject: [PATCH 5/5] Improved debug info output by using isVerboseLogging --- shadowsocks-csharp/Controller/Service/TCPRelay.cs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/shadowsocks-csharp/Controller/Service/TCPRelay.cs b/shadowsocks-csharp/Controller/Service/TCPRelay.cs index ca0e5be2..300c65dd 100644 --- a/shadowsocks-csharp/Controller/Service/TCPRelay.cs +++ b/shadowsocks-csharp/Controller/Service/TCPRelay.cs @@ -445,7 +445,13 @@ namespace Shadowsocks.Controller _proxyConnected = true; - Logging.Debug($"Socket connected to proxy {remote.ProxyEndPoint}"); + if (_config.isVerboseLogging) + { + if (!(remote is DirectConnect)) + { + Logging.Info($"Socket connected to proxy {remote.ProxyEndPoint}"); + } + } _startConnectTime = DateTime.Now; ServerTimer connectTimer = new ServerTimer(3000); @@ -511,6 +517,11 @@ namespace Shadowsocks.Controller _destConnected = true; + if (_config.isVerboseLogging) + { + Logging.Info($"Socket connected to ss server {remote.DestEndPoint}"); + } + var latency = DateTime.Now - _startConnectTime; IStrategy strategy = controller.GetCurrentStrategy(); strategy?.UpdateLatency(server, latency);