From f4ca3e7729f9e4dcac0a8c5bf8d69347822ce62d Mon Sep 17 00:00:00 2001 From: Kaguya Date: Tue, 15 Dec 2015 14:35:42 +0800 Subject: [PATCH 1/4] https://github.com/shadowsocks/shadowsocks-windows/issues/399 --- shadowsocks-csharp/Controller/Service/AvailabilityStatistics.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shadowsocks-csharp/Controller/Service/AvailabilityStatistics.cs b/shadowsocks-csharp/Controller/Service/AvailabilityStatistics.cs index 49820f6..aca7e02 100644 --- a/shadowsocks-csharp/Controller/Service/AvailabilityStatistics.cs +++ b/shadowsocks-csharp/Controller/Service/AvailabilityStatistics.cs @@ -123,7 +123,7 @@ namespace Shadowsocks.Controller { Logging.Debug("Ping " + server.FriendlyName()); if (server.server == "") return null; - var IP = Dns.GetHostAddresses(server.server).First(ip => ip.AddressFamily == AddressFamily.InterNetwork); + var IP = Dns.GetHostAddresses(server.server).First(ip => (ip.AddressFamily == AddressFamily.InterNetwork || ip.AddressFamily == AddressFamily.InterNetworkV6)); var ping = new Ping(); var ret = new List(); foreach ( From 0090f18fcc98a88c98c29ec8b37235d8a5863f84 Mon Sep 17 00:00:00 2001 From: Kaguya Date: Tue, 15 Dec 2015 14:39:52 +0800 Subject: [PATCH 2/4] Update README --- README.md | 131 +++++++++++++++++++++++++----------------------------- 1 file changed, 60 insertions(+), 71 deletions(-) diff --git a/README.md b/README.md index b4952dd..f142121 100644 --- a/README.md +++ b/README.md @@ -1,83 +1,72 @@ -Shadowsocks for Windows -======================= +### 带在线获取并同步最新Server参数的功能的一个版本 +* 现在由于干扰或一些别的原因,服务器配置会经常修改,而对于多人共享或者其他类似情境,发布和同步频繁修改的的配置就显得比较不便。我加了一个通过url较安全地获取配置的功能,即通过一个发布服务器,客户端可使用rsa加密通信从服务器获取最新的配置并与本地的配置同步,从而实现便捷获取最新配置. +* 其实在之前已经进行过约三个月的小范围测试,累计用户约1400人,效果还算不错,所以在考虑能否加入项目本体. +* 配置文件Server段结构如下 -[![Build Status]][Appveyor] + { + "server" : "127.0.0.1", + "server_port" : 2333, + "password" : "kaguya", + "method" : "aes-128-cfb", + "remarks" : "新测试1", + "auth" : false, + "provider" : "新服务器", + "fingerprint" : "90a409a19ba0db0f7cd0cff0dffbbcde" + }, + { + "server" : "127.0.0.1", + "server_port" : 8388, + "password" : "test", + "method" : "aes-256-cfb", + "remarks" : "comment", + "auth" : false, + "provider" : "local", + "fingerprint" : "" + } + 与原来相比,增加了provider和fingerprint两项 + + provider记录了配置的来源,如果是自行手工添加的则为local,若为在线获取的则为发布服务器指定的名称.用于在系统托盘菜单中显示用于指示配置来源. -[中文说明] + fingerprint记录了配置来源服务器的唯一的指纹,若是自行手工添加的则为空.此段用于标记来自同一发布服务器的一组配置的集合,当从同一发布服务器更新配置时,拥有与服务器相同指纹的配置可以被更新/覆盖. -#### Features + Server模型和配置文件的其他部分其他均与先前一致. + +* 工作原理 + * 客户端随机生成一对RSA密钥,并用明文发送公钥至发布服务器. + * 服务器接收并记录客户端公钥,将服务器的公钥、指纹、随机生成的验证字符串用客户端公钥加密以后发回. + * 客户端收到服务器公钥和指纹,如果存在对应的本地记录,则将收到的数据与本地记录进行比对,若不相符,判定为无效服务器;若无本地记录,则默认信任服务器有效性并将其加入本地记录.客户端把服务器发来的验证字符串原样返回,同时计算出一个随机字符串,将两者用服务器公钥加密后发往服务器. + * 服务器收到客户端请求,检查客户端返回的验证字符串并与服务器本地保存的字符串进行对比,若符合则信任客户端身份;否则判定为欺诈请求返回404错误.服务器根据预定策略将Shadowsocks配置和用户生成的验证字符串用客户端公钥加密后返回. + * 客户端收到数据,校验服务器返回的验证字符串,如果不符,则判定服务器身份不可信;如果相符,信任服务器身份并接受服务器返回的配置,反之则中止该次通信.至此,服务器和客户端完成双向的身份认证和数据的传输. + * 客户端将本地拥有与服务器相同指纹的配置置用获取的最新位置覆盖,完成配置的更新. -1. System proxy configuration -2. PAC mode and global mode -3. [GFWList] and user rules -4. Supports HTTP proxy -5. Supports server auto switching -6. Supports UDP relay (see Usage) +* 操作示例 + * 服务器配置的显示,如下图 + +![default](https://cloud.githubusercontent.com/assets/5331336/11752593/7788730c-a07b-11e5-9a45-b46757475679.png) -#### Download + * 在线获取/更新服务器的过程,如下图 +![add](https://cloud.githubusercontent.com/assets/5331336/11752616/8b8a28aa-a07b-11e5-9160-1baab4e17826.png) -Download the [latest release]. + 1.点击“导入”打开导入配置窗口 -#### Basic + 2.输入获得的url,点击“获取”,若无异常,列表框显示获得的配置,若出现异常,弹窗显示异常信息. -1. Find Shadowsocks icon in the notification tray -2. You can add multiple servers in servers menu -3. Select `Enable System Proxy` menu to enable system proxy. Please disable other -proxy addons in your browser, or set them to use system proxy -4. You can also configure your browser proxy manually if you don't want to enable -system proxy. Set Socks5 or HTTP proxy to 127.0.0.1:1080. You can change this -port in `Servers -> Edit Servers` + 3.选择不想添加的配置,点击“移除选定配置”,排除指定配置. -#### PAC + 4.点击“添加以上配置”,将列表中剩余的配置加入本地配置列表并覆盖同一来源的配置. -1. You can change PAC rules by editing the PAC file. When you save the PAC file -with any editor, Shadowsocks will notify browsers about the change automatically -2. You can also update PAC file from [GFWList] (maintained by 3rd party) -3. You can also use online PAC URL +* 安全性考虑 + * 这个功能采取“信任新服务器,在本地保存‘服务器-指纹’对作为服务器身份”的策略,当同一指纹在第一次通信安全可靠及服务器私钥未泄露的情况下,可以在后续的更新配置中排除中间人攻击的威胁. + -#### Server Auto Switching +* 更多 + * 配套的完整的发布服务器的实现在这里:(基于laravel,有部署脚本) + [https://github.com/SuperHentai/Shadowsocks-Config-Server](https://github.com/SuperHentai/Shadowsocks-Config-Server) + * 匆忙之中写完的说明,里面有比较详细的信息:[https://github.com/SuperHentai/Shadowsocks-Config-Server/blob/master/readme.md](https://github.com/SuperHentai/Shadowsocks-Config-Server/blob/master/readme.md) + [https://github.com/SuperHentai/Shadowsocks-Config-Server/wiki/%E8%AF%B4%E6%98%8E%E6%96%87%E6%A1%A3](https://github.com/SuperHentai/Shadowsocks-Config-Server/wiki/%E8%AF%B4%E6%98%8E%E6%96%87%E6%A1%A3) -1. Load balance: choosing server randomly -2. High availability: choosing the best server (low latency and packet loss) -3. Choose By Total Package Loss: ping and choose. Please also enable - `Availability Statistics` in the menu if you want to use this -4. Write your own strategy by implement IStrategy interface and send us a pull request! - -#### UDP - -For UDP, you need to use SocksCap or ProxyCap to force programs you want -to be proxied to tunnel over Shadowsocks - -#### Multiple Instances - -If you want to manage multiple servers using other tools like SwitchyOmega, -you can start multiple Shadowsocks instances. To avoid configuration conflicts, -copy Shadowsocks to a new directory and choose a different local port. - -Also, make sure to use `SOCKS5` proxy in SwitchyOmega, since we have only -one HTTP proxy instance. - -#### Server Configuration - -Please visit [Servers] for more information. - -#### Portable Mode - -If you want to put all temporary files into shadowsocks/temp folder instead of -system temp folder, create a `shadowsocks_portable_mode.txt` into shadowsocks folder. - -#### Develop - -Visual Studio 2015 is required. - -#### License - -GPLv3 - - -[Appveyor]: https://ci.appveyor.com/project/icylogic/shadowsocks-windows-l9mwe -[Build Status]: https://ci.appveyor.com/api/projects/status/ytllr9yjkbpc2tu2/branch/master -[latest release]: https://github.com/shadowsocks/shadowsocks-csharp/releases -[GFWList]: https://github.com/gfwlist/gfwlist -[Servers]: https://github.com/shadowsocks/shadowsocks/wiki/Ports-and-Clients#linux--server-side -[中文说明]: https://github.com/shadowsocks/shadowsocks-windows/wiki/Shadowsocks-Windows-%E4%BD%BF%E7%94%A8%E8%AF%B4%E6%98%8E + * 放出的测试程序[https://github.com/SuperHentai/shadowsocks-windows/releases/tag/test](https://github.com/SuperHentai/shadowsocks-windows/releases/tag/test) + * 已部署的测试发布服务器URL:http://test.unwall.org/ + * 发布服务器操作后台[http://test.unwall.org/panel](http://test.unwall.org/panel) + * 测试用户名:kaguya + * 测试密码:kaguya \ No newline at end of file From 0a458953421312c077ed3a4004efb5dff9081261 Mon Sep 17 00:00:00 2001 From: icylogic Date: Tue, 8 Dec 2015 22:53:29 +0800 Subject: [PATCH 3/4] fix #389: crash on empty statistic data. --- shadowsocks-csharp/View/StatisticsStrategyConfigurationForm.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/shadowsocks-csharp/View/StatisticsStrategyConfigurationForm.cs b/shadowsocks-csharp/View/StatisticsStrategyConfigurationForm.cs index 88e3230..028f109 100644 --- a/shadowsocks-csharp/View/StatisticsStrategyConfigurationForm.cs +++ b/shadowsocks-csharp/View/StatisticsStrategyConfigurationForm.cs @@ -85,6 +85,9 @@ namespace Shadowsocks.View { string serverName = _servers[serverSelector.SelectedIndex]; _dataTable.Rows.Clear(); + + //return directly when no data is usable + if (_controller.availabilityStatistics?.FilteredStatistics == null) return; List statistics; if (!_controller.availabilityStatistics.FilteredStatistics.TryGetValue(serverName, out statistics)) return; IEnumerable> dataGroups; From 49e8ccc1507cd66cad83fa5fdf97ec8737cdd0b1 Mon Sep 17 00:00:00 2001 From: Gang Zhuo Date: Wed, 16 Dec 2015 23:19:07 +0800 Subject: [PATCH 4/4] delay check for updates --- .../Controller/Service/UpdateChecker.cs | 38 ++++++++++++++++++- shadowsocks-csharp/View/MenuViewController.cs | 25 +++++++++--- 2 files changed, 56 insertions(+), 7 deletions(-) diff --git a/shadowsocks-csharp/Controller/Service/UpdateChecker.cs b/shadowsocks-csharp/Controller/Service/UpdateChecker.cs index 643c701..4596235 100644 --- a/shadowsocks-csharp/Controller/Service/UpdateChecker.cs +++ b/shadowsocks-csharp/Controller/Service/UpdateChecker.cs @@ -28,12 +28,41 @@ namespace Shadowsocks.Controller public const string Version = "2.5.8"; + private class CheckUpdateTimer : System.Timers.Timer + { + public Configuration config; + + public CheckUpdateTimer(int p) : base(p) + { + } + } + + public void CheckUpdate(Configuration config, int delay) + { + CheckUpdateTimer timer = new CheckUpdateTimer(delay); + timer.AutoReset = false; + timer.Elapsed += Timer_Elapsed; + timer.config = config; + timer.Enabled = true; + } + + private void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) + { + CheckUpdateTimer timer = (CheckUpdateTimer)sender; + Configuration config = timer.config; + timer.Elapsed -= Timer_Elapsed; + timer.Enabled = false; + timer.Dispose(); + CheckUpdate(config); + } + public void CheckUpdate(Configuration config) { this.config = config; try { + Logging.Debug("Checking updates..."); WebClient http = CreateWebClient(); http.DownloadStringCompleted += http_DownloadStringCompleted; http.DownloadStringAsync(new Uri(UpdateURL)); @@ -81,9 +110,13 @@ namespace Shadowsocks.Controller startDownload(); } - else if (CheckUpdateCompleted != null) + else { - CheckUpdateCompleted(this, new EventArgs()); + Logging.Debug("No update is available"); + if (CheckUpdateCompleted != null) + { + CheckUpdateCompleted(this, new EventArgs()); + } } } catch (Exception ex) @@ -117,6 +150,7 @@ namespace Shadowsocks.Controller Logging.LogUsefulException(e.Error); return; } + Logging.Debug($"New version {LatestVersionNumber} found: {LatestVersionLocalName}"); if (CheckUpdateCompleted != null) { CheckUpdateCompleted(this, new EventArgs()); diff --git a/shadowsocks-csharp/View/MenuViewController.cs b/shadowsocks-csharp/View/MenuViewController.cs index 4dfa1eb..dc22821 100755 --- a/shadowsocks-csharp/View/MenuViewController.cs +++ b/shadowsocks-csharp/View/MenuViewController.cs @@ -66,7 +66,9 @@ namespace Shadowsocks.View UpdateTrayIcon(); _notifyIcon.Visible = true; _notifyIcon.ContextMenu = contextMenu1; + _notifyIcon.BalloonTipClicked += notifyIcon1_BalloonTipClicked; _notifyIcon.MouseDoubleClick += notifyIcon1_DoubleClick; + _notifyIcon.BalloonTipClosed += _notifyIcon_BalloonTipClosed; this.updateChecker = new UpdateChecker(); updateChecker.CheckUpdateCompleted += updateChecker_CheckUpdateCompleted; @@ -78,7 +80,7 @@ namespace Shadowsocks.View if (config.autoCheckUpdate) { _isStartupChecking = true; - updateChecker.CheckUpdate(config); + updateChecker.CheckUpdate(config, 3000); } if (config.isDefault) @@ -256,7 +258,6 @@ namespace Shadowsocks.View if (updateChecker.NewVersionFound) { ShowBalloonTip(String.Format(I18N.GetString("Shadowsocks {0} Update Found"), updateChecker.LatestVersionNumber), I18N.GetString("Click here to update"), ToolTipIcon.Info, 5000); - _notifyIcon.BalloonTipClicked += notifyIcon1_BalloonTipClicked; _isFirstRun = false; } else if (!_isStartupChecking) @@ -269,9 +270,23 @@ namespace Shadowsocks.View void notifyIcon1_BalloonTipClicked(object sender, EventArgs e) { - _notifyIcon.BalloonTipClicked -= notifyIcon1_BalloonTipClicked; - string argument = "/select, \"" + updateChecker.LatestVersionLocalName + "\""; - System.Diagnostics.Process.Start("explorer.exe", argument); + if (updateChecker.NewVersionFound) + { + updateChecker.NewVersionFound = false; /* Reset the flag */ + if (System.IO.File.Exists(updateChecker.LatestVersionLocalName)) + { + string argument = "/select, \"" + updateChecker.LatestVersionLocalName + "\""; + System.Diagnostics.Process.Start("explorer.exe", argument); + } + } + } + + private void _notifyIcon_BalloonTipClosed(object sender, EventArgs e) + { + if (updateChecker.NewVersionFound) + { + updateChecker.NewVersionFound = false; /* Reset the flag */ + } }