Compare commits

..
72 Commits
Author SHA1 Message Date
celeron533 1a56ea23ec Update CHANGES and bump version 2018-05-10 23:29:06 +08:00
Allen Zhu 1c2e135d8e Merge pull request #1818 from celeron533/CLI
Add plugin CLI arguments support
2018-04-26 20:01:14 +08:00
celeron533 9439fc617a Config form UI updates
* Add tooltips
* Translations
2018-04-17 21:24:19 +08:00
celeron533 b7e30318cd Add plugin CLI arguments support 2018-04-17 20:41:57 +08:00
celeron533 2227595998 Update README.md
- Add section "Open Source Components / Libraries"
- Other minor changes
2018-04-12 23:42:51 +08:00
Allen Zhu 7fb75f27b1 Merge pull request #1769 from studentmain/master
[Fix] QRCodeSplashForm.cs无法在窗体设计工具中打开
2018-03-29 19:53:25 +08:00
Allen Zhu 78e46188f6 Merge pull request #1782 from tltltltl/patch-1
Update zh_TW.txt
2018-03-29 19:32:44 +08:00
tltltltl 58f2c3937b Update zh_TW.txt
change some translations
2018-03-29 18:53:07 +08:00
Zch 81dcad5df5 fix #1768
Move PerPixelAlphaForm's code into QRCodeSplashForm to avoid 2 derived class of Form in same file.

Before: QRCodeSplashForm -> PerPixelAlphaForm -> Form
After: QRCodeSplashForm -> Form
2018-03-24 21:32:48 +08:00
celeron533 5a78ee9212 Add square bracket for SIP002 IPv6 (RFC3986) 2018-03-23 22:39:06 +08:00
Max Lv 4431610205 Merge pull request #1762 from celeron533/Server_IPV6_URL
Server address should not be encoded
2018-03-22 22:07:23 +08:00
celeron533 257448a80a Misc 2018-03-20 21:03:20 +08:00
celeron533 c9ead3eee9 Server address should not be encoded 2018-03-20 13:30:44 +08:00
wzxjohn 226ad0cf50 Fix wrong splash on multi display (#1729)
Because the splash is already on the target display, the target rect doesn't need to calculate with the screen position.
2018-03-18 21:23:43 -05:00
Chen Shaoju 5138e43aff "Allow Clients from LAN" Description & Translation optimization (#1753)
"Allow Clients from LAN" --> "Allow other Devices to connect"
2018-03-16 21:15:15 -05:00
celeron533 25c1d02395 Update CHANGES and bump version 2018-03-14 22:32:31 +08:00
celeron533 897934c233 Add comments in app.config 2018-03-11 21:46:01 +08:00
Allen Zhu fdbd3a975b Merge pull request #1732 from wongsyrone/patch-1
add official way to dump network tracing info
2018-03-11 08:34:45 -05:00
Syrone Wong 7fd9ce2bc3 add official way to dump network tracing info
just uncomment the specific node in app.config, no need to recompile
to take effect. It will be shipped as Shadowsocks.exe.config after built.

This is for debugging only.
2018-03-11 16:05:37 +08:00
Allen Zhu c168af6975 Merge pull request #1725 from celeron533/master
add xchacha20-ietf-poly1305
2018-03-07 06:27:57 -06:00
Syrone Wong 3329291ab9 add xchacha20-ietf-poly1305
- update mbedtls to 2.7.0, use new md5 api
- update libsodium to 1.0.16
- static link to openssl 1.1.0g, check libsscrypto repo for detail
2018-03-03 22:22:01 +08:00
celeron533 1e04279d37 Update issue template 2018-03-03 20:37:18 +08:00
celeron533 20fa87ba89 Fix proxy bypass list #1674 2018-02-22 10:29:46 +08:00
celeron533 5db7c79407 Minor changes on Forward Proxy 2018-02-20 18:27:26 +08:00
HYec 85bd65e021 Only start the current server's plugin 2018-02-20 12:32:01 +08:00
HYec 7197e46b53 Close sockets before stop plugins 2018-02-20 12:31:53 +08:00
Allen Zhu b2c0bba953 Merge pull request #1682 from chenshaoju/patch-1
Add new requirement
2018-02-17 09:06:05 -06:00
Chen Shaoju d266ea2e39 fix 2018-02-17 11:28:01 +08:00
Chen Shaoju a5b11aee34 Add new requirements 2018-02-17 11:21:16 +08:00
celeron533 e2b9822224 Update CHANGES and bump version 2018-02-16 10:15:53 +08:00
Allen Zhu a12a70ccf0 Merge pull request #1671 from wongsyrone/master
Add OpenSSL 1.1.0g support due to hardware acceleration
2018-02-15 10:05:42 -06:00
Syrone Wong b2645f9f0a Fix bf-cfb name
Don't use Cname
2018-02-15 21:29:40 +08:00
Syrone Wong 4d4f1753c7 Add OpenSSL 1.1.0g support due to hardware acceleration
Note: If you want to compile it by yourself, please make sure
do NOT use `no-asm` configure option, since the main point of
this commit is to utilize assembly in openssl

Add OpenSSL test
2018-02-10 08:27:32 +08:00
celeron533 502397b5f9 Update nuget packages 2018-01-29 22:29:49 +08:00
celeron533 f042e91305 Minor changes
SIP003 server port validation
Year 2018
2018-01-29 21:23:41 +08:00
Allen Zhu d1219bbfca Merge pull request #1618 from hyec/master
Close sockets before stop plugins

Do not activate all servers' plugins at the same time
2018-01-27 09:35:19 -06:00
HYec 7564e79ede Only start the current server's plugin 2018-01-09 23:08:50 +08:00
HYec 511feb2e31 Close sockets before stop plugins 2018-01-06 22:06:15 +08:00
celeron533 647f986003 Avoid raise FileSystemWatcher event twice
When saving user-rule.txt file, some text editors can raise FileSystemWatcher event twice.
The 1st time is blank content, then the 2nd time is the modified content.
2017-12-20 22:48:52 +08:00
celeron533 8cd64d4022 Reuse the PAC file merge procedure 2017-12-20 21:49:05 +08:00
Allen Zhu 7021edd61f Merge pull request #1564 from jinliming2/user-rule
Put user rules at the begin of the PAC file.
2017-12-20 06:32:43 -06:00
Allen Zhu f7cd2390b2 Merge pull request #1568 from wongsyrone/patch-1
Close connection if received zero bytes
2017-12-15 06:22:19 -06:00
Syrone Wong 218925e191 Close connection if received zero bytes
This might fix 500 Privoxy Internal Error: no-server-data
2017-12-14 09:54:31 +08:00
Liming Jin dc718a583b Put user rules at the begin of the PAC file.
Fix: #1468
Enhance: 46d40fec67
2017-12-10 17:25:07 +08:00
celeron533 0c877a76c6 Update CHANGES and bump version 2017-12-09 12:24:23 +08:00
celeron533 c24714e168 Simplify SystemEvents_PowerModeChanged() 2017-12-03 21:11:41 +08:00
celeron533 46d40fec67 Add the UserRule at the beginning of PAC file 2017-11-19 13:57:27 +08:00
Allen Zhu aacc4edf69 Merge pull request #1438 from SharerMax/master
Add option to show password
2017-11-18 22:22:57 -06:00
SharerMax acc192df34 Remove useless code 2017-10-11 01:04:55 +08:00
SharerMax eae0b1cfac Add option to show password 2017-10-11 01:00:24 +08:00
Allen Zhu 63980b3a12 Merge pull request #1406 from celeron533/SIP002_Refine
Sip002 refine
2017-10-05 05:43:12 -05:00
celeron533 a4c4967f5f Rename GetQRCode() to GetServerURL() 2017-09-25 20:24:15 +08:00
celeron533 55c19187c7 Refine URL parser
- Bring back the legacy parser
- Refine SIP002 logic
2017-09-25 20:24:15 +08:00
celeron533 7c73aaa1cf Append more test cases for ParseShadowsocksUrlTest 2017-09-10 10:55:45 +08:00
celeron533 77a93a9140 Fix the issue "unable to add server from URL"
Base64 code ended with '=' cause the Uri invalid to parse.
Simplified the logic.
2017-09-10 00:54:39 +08:00
celeron533 08f06f7177 Update CHANGES and bump version 2017-09-09 20:24:50 +08:00
celeron533 cb3afafd54 Update readme.md 2017-09-08 21:54:38 +08:00
celeron533 05df449826 Add notification message 2017-09-05 22:31:54 +08:00
celeron533 d0e692a491 Translation for SIP003 2017-08-31 20:28:45 +08:00
Allen Zhu b0a2c2735b Merge pull request #1336 from rwasef1830/use_job_for_sip003_plugin
Use job objects with SIP003 plugin to avoid lingering processes if app is killed
2017-08-31 19:58:07 +08:00
Raif Atef f239244af2 Early start SIP003 plugins when reloading servers to avoid delay on first packet. 2017-08-27 09:11:41 +02:00
Raif Atef a316b95f45 Logging for SIP003 start failure. 2017-08-26 21:22:53 +02:00
Raif Atef cf5de91acb Use job objects with SIP003 plugin to avoid lingering processes if app is killed. 2017-08-23 12:36:32 +02:00
Allen Zhu 71120e5c3e Merge pull request #1298 from rwasef1830/sip003
SIP002 and SIP003 support.
2017-08-21 20:25:34 +08:00
Raif Atef caa96ad334 Fix port range check and move Sip003Plugin. 2017-08-17 11:11:06 +02:00
Raif Atef f04b497d79 SIP002 and SIP003 support 2017-08-14 11:48:41 +02:00
celeron533 ed31a3cab0 Update CHANGES and bump version 2017-08-09 19:20:50 +08:00
celeron533 081bbaf011 Fix #1301. Configuration is not fully initialized and cause NullReferenceException crash 2017-08-06 22:48:02 +08:00
celeron533 0251130fa5 Socket.ConnectAsync() does not call SocketAsyncEventArgs.Completed when operation completed synchronously.
#1273
2017-08-06 17:17:32 +08:00
Jacob Zuo f0b196c8c3 Fix "4.0.4 launch exception" error (PR #1232) 2017-08-06 12:06:29 +08:00
celeron533 057b148092 Merge pull request #1227 from gitzhuoer/patch-2
Add .NET Framework 4.6.2 requirement
2017-07-10 19:47:42 +08:00
Zhuoer Dong 101c33d0f1 Update README.md 2017-07-10 19:41:48 +08:00
45 changed files with 2047 additions and 596 deletions
+9 -8
View File
@@ -1,19 +1,20 @@
Please read Wiki carefully, especially https://github.com/shadowsocks/shadowsocks-windows/wiki/Troubleshooting.
Please answer these questions before submitting your issue. Thanks!
Please read Wiki carefully, especially / 提问前请先阅读wiki https://github.com/shadowsocks/shadowsocks-windows/wiki/Troubleshooting.
Or search from issue board / 或在issue board中搜索 https://github.com/shadowsocks/shadowsocks-windows/issues?utf8=%E2%9C%93&q=is%3Aissue
Please answer these questions before submitting your issue. Thanks! / 请按照以下格式描述你的问题
### Version(release version or AppVeyor link)
### Version(release version or AppVeyor link) / 版本(正式版或基于AppVeyor的链接)
### Environment(Operating system, .NET Framework, etc)
### Environment(Operating system, .NET Framework, etc) / 操作环境(操作系统,.NET Framework等)
### Steps you have tried
### Steps you have tried / 操作步骤
### What did you expect to see?
### What did you expect to see? / 期望的结果
### What did you see instead?
### What did you see instead? / 实际结果
### Config and error log in detail (with all sensitive info masked)
### Config and error log in detail (with all sensitive info masked) / 配置文件和日志文件(请隐去敏感信息)
+33
View File
@@ -1,3 +1,36 @@
4.0.10 2018-05-10
- Add square bracket for SIP002 IPv6 (RFC3986)
- Add plugin CLI arguments support
- Bug fix: Server address should not be encoded (#1758)
- Bug fix: Wrong splash on multi display (#1729)
- Fix PerPixelAlphaForm's issue in disigner
- Other minor bug fixes and improvements
4.0.9 2018-03-14
- Fix port occupied issue
- Add xchacha20-ietf-poly1305
- Update cryptographic libraries
- Bug fixes and improvements
4.0.8 2018-02-16
- Add OpenSSL 1.1.0g support #1671
- Update nuget packages
- Bug fixes and improvements
4.0.7 2017-12-09
- Fix QR code and ss:// protocol import issue
- Add an option to show password
- User rules have higher priority in PAC file
- Bug fixes and improvements
4.0.6 2017-09-09
- SIP002 support
- SIP003 support
4.0.5 2017-08-09
- Fix crash when user-wininet.json fail to parse. (#1178)
- Bug fixes and improvements.
4.0.4 2017-06-01
- Save user wininet settings as user-wininet.json
- Improve performance of aes-256-gcm
+15
View File
@@ -0,0 +1,15 @@
OpenSSL library guide for VS2017
# Read NOTES.WIN and NOTES.PERL
# use Visual Studio native tools command prompt
# use activeperl, install NASM assembler
ppm install dmake
# Win32 x86
set PATH=D:\NASM-32;%PATH%
perl Configure VC-WIN32 --release --prefix=C:\Users\home\Downloads\openssl-1.1.0g\x86-build --openssldir=C:\Users\home\Downloads\openssl-1.1.0g\x86-install
nmake
nmake test
# to rebuild
nmake distclean
+46 -13
View File
@@ -13,10 +13,15 @@ Shadowsocks for Windows
4. Supports HTTP proxy
5. Supports server auto switching
6. Supports UDP relay (see Usage)
7. Supports plugins
#### Download
Download the [latest release].
Download the latest release from [release page].
#### Requirements
Microsoft [.NET Framework 4.6.2] or higher, Microsoft [Visual C++ 2015 Redistributable] (x86) .
#### Basic
@@ -54,11 +59,17 @@ 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.
#### Plugins
If you would like to connect to server via a plugin, please set the plugin's
path (relative or absolute) on Edit Servers form.
_Note_: Forward Proxy will not be used while a plugin is enabled.
#### Global hotkeys
Hotkeys are NOT registered automatically. You should re-register all hotkeys after
restarting Shadowsocks. If you are using multiple instances of Shadowsocks,
you must set different key combination for other instances.
you must set different key combination for each instance.
##### How to input?
@@ -89,20 +100,42 @@ if you want to deactivate all, please clear all textboxes.
Please visit [Servers] for more information.
#### Develop
#### Development
[Visual Studio 2015] & [.NET Framework 4.6.2 Developer Pack] are required.
1. [Visual Studio 2015] & [.NET Framework 4.6.2 Developer Pack] are required.
2. It is recommended to share your idea on the Issue Board before you start to work,
especially for feature development.
#### License
GPLv3
[GPLv3]
#### Open Source Components / Libraries
```
Caseless.Fody (MIT) https://github.com/Fody/Caseless
Costura.Fody (MIT) https://github.com/Fody/Costura
Fody (MIT) https://github.com/Fody/Fody
GlobalHotKey (GPLv3) https://github.com/kirmir/GlobalHotKey
Newtonsoft.Json (MIT) https://www.newtonsoft.com/json
StringEx.CS () https://github.com/LazyMode/StringEx
ZXing.Net (Apache 2.0) https://github.com/micjahn/ZXing.Net
libsscrypto (GPLv2) https://github.com/shadowsocks/libsscrypto
Privoxy (GPLv2) https://www.privoxy.org
Sysproxy () https://github.com/Noisyfox/sysproxy
```
[Appveyor]: https://ci.appveyor.com/project/wongsyrone/shadowsocks-windows-yqdou
[Build Status]: https://ci.appveyor.com/api/projects/status/yieb7lo96irmuc28/branch/master?svg=true
[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
[Visual Studio 2015]: https://www.visualstudio.com/downloads/
[.NET Framework 4.6.2 Developer Pack]: https://www.microsoft.com/download/details.aspx?id=53321
[Appveyor]: https://ci.appveyor.com/project/celeron533/shadowsocks-windows
[Build Status]: https://ci.appveyor.com/api/projects/status/tfw57q6eecippsl5/branch/master?svg=true
[release page]: 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
[Visual Studio 2015]: https://www.visualstudio.com/downloads/
[.NET Framework 4.6.2]: https://www.microsoft.com/en-US/download/details.aspx?id=53344
[.NET Framework 4.6.2 Developer Pack]: https://www.microsoft.com/download/details.aspx?id=53321
[Visual C++ 2015 Redistributable]: https://www.microsoft.com/en-us/download/details.aspx?id=53840
[GPLv3]: https://github.com/shadowsocks/shadowsocks-windows/blob/master/LICENSE.txt
@@ -36,52 +36,52 @@ namespace Shadowsocks.Controller
try
{
File.WriteAllText(Utils.GetTempPath("gfwlist.txt"), e.Result, Encoding.UTF8);
List<string> lines = ParseResult(e.Result);
if (File.Exists(PACServer.USER_RULE_FILE))
{
string local = FileManager.NonExclusiveReadAllText(PACServer.USER_RULE_FILE, Encoding.UTF8);
using (var sr = new StringReader(local))
{
foreach (var rule in sr.NonWhiteSpaceLines())
{
if (rule.BeginWithAny(IgnoredLineBegins))
continue;
lines.Add(rule);
}
}
}
string abpContent;
if (File.Exists(PACServer.USER_ABP_FILE))
{
abpContent = FileManager.NonExclusiveReadAllText(PACServer.USER_ABP_FILE, Encoding.UTF8);
}
else
{
abpContent = Utils.UnGzip(Resources.abp_js);
}
abpContent = abpContent.Replace("__RULES__", JsonConvert.SerializeObject(lines, Formatting.Indented));
if (File.Exists(PACServer.PAC_FILE))
{
string original = FileManager.NonExclusiveReadAllText(PACServer.PAC_FILE, Encoding.UTF8);
if (original == abpContent)
{
UpdateCompleted(this, new ResultEventArgs(false));
return;
}
}
File.WriteAllText(PACServer.PAC_FILE, abpContent, Encoding.UTF8);
if (UpdateCompleted != null)
{
UpdateCompleted(this, new ResultEventArgs(true));
}
bool pacFileChanged = MergeAndWritePACFile(e.Result);
UpdateCompleted?.Invoke(this, new ResultEventArgs(pacFileChanged));
}
catch (Exception ex)
{
if (Error != null)
Error?.Invoke(this, new ErrorEventArgs(ex));
}
}
public static bool MergeAndWritePACFile(string gfwListResult)
{
List<string> lines = new List<string>();
if (File.Exists(PACServer.USER_RULE_FILE))
{
string local = FileManager.NonExclusiveReadAllText(PACServer.USER_RULE_FILE, Encoding.UTF8);
using (var sr = new StringReader(local))
{
Error(this, new ErrorEventArgs(ex));
foreach (var rule in sr.NonWhiteSpaceLines())
{
if (rule.BeginWithAny(IgnoredLineBegins))
continue;
lines.Add(rule);
}
}
}
lines.AddRange(ParseResult(gfwListResult));
string abpContent;
if (File.Exists(PACServer.USER_ABP_FILE))
{
abpContent = FileManager.NonExclusiveReadAllText(PACServer.USER_ABP_FILE, Encoding.UTF8);
}
else
{
abpContent = Utils.UnGzip(Resources.abp_js);
}
abpContent = abpContent.Replace("__RULES__", JsonConvert.SerializeObject(lines, Formatting.Indented));
if (File.Exists(PACServer.PAC_FILE))
{
string original = FileManager.NonExclusiveReadAllText(PACServer.PAC_FILE, Encoding.UTF8);
if (original == abpContent)
{
return false;
}
}
File.WriteAllText(PACServer.PAC_FILE, abpContent, Encoding.UTF8);
return true;
}
public void UpdatePACFromGFWList(Configuration config)
@@ -85,6 +85,7 @@ namespace Shadowsocks.Controller
// Start an asynchronous socket to listen for connections.
Logging.Info("Shadowsocks started");
Logging.Info(Encryption.EncryptorFactory.DumpRegisteredEncryptor());
_tcpSocket.BeginAccept(new AsyncCallback(AcceptCallback), _tcpSocket);
UDPState udpState = new UDPState();
udpState.socket = _udpSocket;
@@ -202,6 +203,7 @@ namespace Shadowsocks.Controller
try
{
int bytesRead = conn.EndReceive(ar);
if (bytesRead <= 0) goto Shutdown;
foreach (IService service in _services)
{
if (service.Handle(buf, bytesRead, conn, null))
@@ -209,6 +211,7 @@ namespace Shadowsocks.Controller
return;
}
}
Shutdown:
// no service found for this
if (conn.ProtocolType == ProtocolType.Tcp)
{
@@ -9,6 +9,7 @@ using Shadowsocks.Encryption;
using Shadowsocks.Model;
using Shadowsocks.Properties;
using Shadowsocks.Util;
using System.Threading.Tasks;
namespace Shadowsocks.Controller
{
@@ -241,42 +242,34 @@ Connection: Close
#region FileSystemWatcher.OnChanged()
// FileSystemWatcher Changed event is raised twice
// http://stackoverflow.com/questions/1764809/filesystemwatcher-changed-event-is-raised-twice
private static Hashtable fileChangedTime = new Hashtable();
// Add a short delay to avoid raise event twice in a short period
private void PACFileWatcher_Changed(object sender, FileSystemEventArgs e)
{
string path = e.FullPath.ToString();
string currentLastWriteTime = File.GetLastWriteTime(e.FullPath).ToString(CultureInfo.InvariantCulture);
// if there is no path info stored yet or stored path has different time of write then the one now is inspected
if (!fileChangedTime.ContainsKey(path) || fileChangedTime[path].ToString() != currentLastWriteTime)
if (PACFileChanged != null)
{
if (PACFileChanged != null)
Logging.Info($"Detected: PAC file '{e.Name}' was {e.ChangeType.ToString().ToLower()}.");
Task.Factory.StartNew(() =>
{
Logging.Info($"Detected: PAC file '{e.Name}' was {e.ChangeType.ToString().ToLower()}.");
((FileSystemWatcher)sender).EnableRaisingEvents = false;
System.Threading.Thread.Sleep(10);
PACFileChanged(this, new EventArgs());
}
// lastly we update the last write time in the hashtable
fileChangedTime[path] = currentLastWriteTime;
((FileSystemWatcher)sender).EnableRaisingEvents = true;
});
}
}
private void UserRuleFileWatcher_Changed(object sender, FileSystemEventArgs e)
{
string path = e.FullPath.ToString();
string currentLastWriteTime = File.GetLastWriteTime(e.FullPath).ToString(CultureInfo.InvariantCulture);
// if there is no path info stored yet or stored path has different time of write then the one now is inspected
if (!fileChangedTime.ContainsKey(path) || fileChangedTime[path].ToString() != currentLastWriteTime)
if (UserRuleFileChanged != null)
{
if (UserRuleFileChanged != null)
Logging.Info($"Detected: User Rule file '{e.Name}' was {e.ChangeType.ToString().ToLower()}.");
Task.Factory.StartNew(()=>
{
Logging.Info($"Detected: User Rule file '{e.Name}' was {e.ChangeType.ToString().ToLower()}.");
((FileSystemWatcher)sender).EnableRaisingEvents = false;
System.Threading.Thread.Sleep(10);
UserRuleFileChanged(this, new EventArgs());
}
// lastly we update the last write time in the hashtable
fileChangedTime[path] = currentLastWriteTime;
((FileSystemWatcher)sender).EnableRaisingEvents = true;
});
}
}
#endregion
@@ -0,0 +1,141 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Reflection;
using Shadowsocks.Model;
using Shadowsocks.Util.ProcessManagement;
namespace Shadowsocks.Controller.Service
{
// https://github.com/shadowsocks/shadowsocks-org/wiki/Plugin
public sealed class Sip003Plugin : IDisposable
{
public IPEndPoint LocalEndPoint { get; private set; }
public int ProcessId => _started ? _pluginProcess.Id : 0;
private readonly object _startProcessLock = new object();
private readonly Job _pluginJob;
private readonly Process _pluginProcess;
private bool _started;
private bool _disposed;
public static Sip003Plugin CreateIfConfigured(Server server)
{
if (server == null)
{
throw new ArgumentNullException(nameof(server));
}
if (string.IsNullOrWhiteSpace(server.plugin))
{
return null;
}
return new Sip003Plugin(server.plugin, server.plugin_opts, server.plugin_args, server.server, server.server_port);
}
private Sip003Plugin(string plugin, string pluginOpts, string pluginArgs, string serverAddress, int serverPort)
{
if (plugin == null) throw new ArgumentNullException(nameof(plugin));
if (string.IsNullOrWhiteSpace(serverAddress))
{
throw new ArgumentException("Value cannot be null or whitespace.", nameof(serverAddress));
}
if (serverPort <= 0 || serverPort > 65535)
{
throw new ArgumentOutOfRangeException("serverPort");
}
var appPath = Path.GetDirectoryName(new Uri(Assembly.GetExecutingAssembly().GetName().CodeBase).LocalPath);
_pluginProcess = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = plugin,
Arguments = pluginArgs,
UseShellExecute = false,
CreateNoWindow = true,
ErrorDialog = false,
WindowStyle = ProcessWindowStyle.Hidden,
WorkingDirectory = appPath ?? Environment.CurrentDirectory,
Environment =
{
["SS_REMOTE_HOST"] = serverAddress,
["SS_REMOTE_PORT"] = serverPort.ToString(),
["SS_PLUGIN_OPTIONS"] = pluginOpts
}
}
};
_pluginJob = new Job();
}
public bool StartIfNeeded()
{
if (_disposed)
{
throw new ObjectDisposedException(GetType().FullName);
}
lock (_startProcessLock)
{
if (_started && !_pluginProcess.HasExited)
{
return false;
}
var localPort = GetNextFreeTcpPort();
LocalEndPoint = new IPEndPoint(IPAddress.Loopback, localPort);
_pluginProcess.StartInfo.Environment["SS_LOCAL_HOST"] = LocalEndPoint.Address.ToString();
_pluginProcess.StartInfo.Environment["SS_LOCAL_PORT"] = LocalEndPoint.Port.ToString();
_pluginProcess.Start();
_pluginJob.AddProcess(_pluginProcess.Handle);
_started = true;
}
return true;
}
static int GetNextFreeTcpPort()
{
var l = new TcpListener(IPAddress.Loopback, 0);
l.Start();
int port = ((IPEndPoint)l.LocalEndpoint).Port;
l.Stop();
return port;
}
public void Dispose()
{
if (_disposed)
{
return;
}
try
{
if (!_pluginProcess.HasExited)
{
_pluginProcess.Kill();
_pluginProcess.WaitForExit();
}
}
catch (Exception) { }
finally
{
try
{
_pluginProcess.Dispose();
_pluginJob.Dispose();
}
catch (Exception) { }
_disposed = true;
}
}
}
}
@@ -570,7 +570,15 @@ namespace Shadowsocks.Controller
// Setting up proxy
IProxy remote;
EndPoint proxyEP = null;
if (_config.proxy.useProxy)
EndPoint serverEP = SocketUtil.GetEndPoint(_server.server, _server.server_port);
EndPoint pluginEP = _controller.GetPluginLocalEndPointIfConfigured(_server);
if (pluginEP != null)
{
serverEP = pluginEP;
remote = new DirectConnect();
}
else if (_config.proxy.useProxy)
{
switch (_config.proxy.proxyType)
{
@@ -607,7 +615,7 @@ namespace Shadowsocks.Controller
proxyTimer.Enabled = true;
proxyTimer.Session = session;
proxyTimer.DestEndPoint = SocketUtil.GetEndPoint(_server.server, _server.server_port);
proxyTimer.DestEndPoint = serverEP;
proxyTimer.Server = _server;
_proxyConnected = false;
@@ -24,7 +24,7 @@ namespace Shadowsocks.Controller
public string LatestVersionLocalName;
public event EventHandler CheckUpdateCompleted;
public const string Version = "4.0.4";
public const string Version = "4.0.10";
private class CheckUpdateTimer : System.Timers.Timer
{
@@ -1,4 +1,5 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Net;
@@ -14,6 +15,8 @@ using Shadowsocks.Model;
using Shadowsocks.Properties;
using Shadowsocks.Util;
using System.Linq;
using Shadowsocks.Controller.Service;
using Shadowsocks.Proxy;
namespace Shadowsocks.Controller
{
@@ -33,6 +36,8 @@ namespace Shadowsocks.Controller
private StrategyManager _strategyManager;
private PrivoxyRunner privoxyRunner;
private GFWListUpdater gfwListUpdater;
private readonly ConcurrentDictionary<Server, Sip003Plugin> _pluginsByServer;
public AvailabilityStatistics availabilityStatistics = AvailabilityStatistics.Instance;
public StatisticsStrategyConfiguration StatisticsConfiguration { get; private set; }
@@ -79,6 +84,7 @@ namespace Shadowsocks.Controller
_config = Configuration.Load();
StatisticsConfiguration = StatisticsStrategyConfiguration.Load();
_strategyManager = new StrategyManager(this);
_pluginsByServer = new ConcurrentDictionary<Server, Sip003Plugin>();
StartReleasingMemory();
StartTrafficStatistics(61);
}
@@ -144,6 +150,31 @@ namespace Shadowsocks.Controller
return GetCurrentServer();
}
public EndPoint GetPluginLocalEndPointIfConfigured(Server server)
{
var plugin = _pluginsByServer.GetOrAdd(server, Sip003Plugin.CreateIfConfigured);
if (plugin == null)
{
return null;
}
try
{
if (plugin.StartIfNeeded())
{
Logging.Info(
$"Started SIP003 plugin for {server.Identifier()} on {plugin.LocalEndPoint} - PID: {plugin.ProcessId}");
}
}
catch (Exception ex)
{
Logging.Error("Failed to start SIP003 plugin: " + ex.Message);
throw;
}
return plugin.LocalEndPoint;
}
public void SaveServers(List<Server> servers, int localPort)
{
_config.configs = servers;
@@ -209,19 +240,9 @@ namespace Shadowsocks.Controller
}
}
public void DisableProxy()
public void SaveProxy(ProxyConfig proxyConfig)
{
_config.proxy.useProxy = false;
SaveConfig(_config);
}
public void EnableProxy(int type, string proxy, int port, int timeout)
{
_config.proxy.useProxy = true;
_config.proxy.proxyType = type;
_config.proxy.proxyServer = proxy;
_config.proxy.proxyPort = port;
_config.proxy.proxyTimeout = timeout;
_config.proxy = proxyConfig;
SaveConfig(_config);
}
@@ -259,6 +280,7 @@ namespace Shadowsocks.Controller
{
_listener.Stop();
}
StopPlugins();
if (privoxyRunner != null)
{
privoxyRunner.Stop();
@@ -270,6 +292,15 @@ namespace Shadowsocks.Controller
Encryption.RNG.Close();
}
private void StopPlugins()
{
foreach (var serverAndPlugin in _pluginsByServer)
{
serverAndPlugin.Value?.Dispose();
}
_pluginsByServer.Clear();
}
public void TouchPACFile()
{
string pacFilename = _pacServer.TouchPACFile();
@@ -288,22 +319,50 @@ namespace Shadowsocks.Controller
}
}
public string GetQRCodeForCurrentServer()
public string GetServerURLForCurrentServer()
{
Server server = GetCurrentServer();
return GetQRCode(server);
return GetServerURL(server);
}
public static string GetQRCode(Server server)
public static string GetServerURL(Server server)
{
string tag = string.Empty;
string parts = $"{server.method}:{server.password}@{server.server}:{server.server_port}";
string base64 = Convert.ToBase64String(Encoding.UTF8.GetBytes(parts));
if(!server.remarks.IsNullOrEmpty())
string url = string.Empty;
if (string.IsNullOrWhiteSpace(server.plugin))
{
// For backwards compatiblity, if no plugin, use old url format
string parts = $"{server.method}:{server.password}@{server.server}:{server.server_port}";
string base64 = Convert.ToBase64String(Encoding.UTF8.GetBytes(parts));
url = base64;
}
else
{
// SIP002
string parts = $"{server.method}:{server.password}";
string base64 = Convert.ToBase64String(Encoding.UTF8.GetBytes(parts));
string websafeBase64 = base64.Replace('+', '-').Replace('/', '_').TrimEnd('=');
string pluginPart = server.plugin;
if (!string.IsNullOrWhiteSpace(server.plugin_opts))
{
pluginPart += ";" + server.plugin_opts;
}
url = string.Format(
"{0}@{1}:{2}/?plugin={3}",
websafeBase64,
server.FormatHostName(server.server),
server.server_port,
HttpUtility.UrlEncode(pluginPart, Encoding.UTF8));
}
if (!server.remarks.IsNullOrEmpty())
{
tag = $"#{HttpUtility.UrlEncode(server.remarks, Encoding.UTF8)}";
}
return $"ss://{base64}{tag}";
return $"ss://{url}{tag}";
}
public void UpdatePACFromGFWList()
@@ -450,6 +509,9 @@ namespace Shadowsocks.Controller
{
_listener.Stop();
}
StopPlugins();
// don't put PrivoxyRunner.Start() before pacServer.Stop()
// or bind will fail when switching bind address from 0.0.0.0 to 127.0.0.1
// though UseShellExecute is set to true now
@@ -463,6 +525,7 @@ namespace Shadowsocks.Controller
strategy.ReloadServers();
}
StartPlugin();
privoxyRunner.Start(_config);
TCPRelay tcpRelay = new TCPRelay(this, _config);
@@ -500,6 +563,12 @@ namespace Shadowsocks.Controller
Utils.ReleaseMemory(true);
}
private void StartPlugin()
{
var server = _config.GetCurrentServer();
GetPluginLocalEndPointIfConfigured(server);
}
protected void SaveConfig(Configuration newConfig)
{
Configuration.Save(newConfig);
@@ -531,45 +600,14 @@ namespace Shadowsocks.Controller
private static readonly IEnumerable<char> IgnoredLineBegins = new[] { '!', '[' };
private void pacServer_UserRuleFileChanged(object sender, EventArgs e)
{
// TODO: this is a dirty hack. (from code GListUpdater.http_DownloadStringCompleted())
if (!File.Exists(Utils.GetTempPath("gfwlist.txt")))
{
UpdatePACFromGFWList();
return;
}
List<string> lines = GFWListUpdater.ParseResult(FileManager.NonExclusiveReadAllText(Utils.GetTempPath("gfwlist.txt")));
if (File.Exists(PACServer.USER_RULE_FILE))
{
string local = FileManager.NonExclusiveReadAllText(PACServer.USER_RULE_FILE, Encoding.UTF8);
using (var sr = new StringReader(local))
{
foreach (var rule in sr.NonWhiteSpaceLines())
{
if (rule.BeginWithAny(IgnoredLineBegins))
continue;
lines.Add(rule);
}
}
}
string abpContent;
if (File.Exists(PACServer.USER_ABP_FILE))
{
abpContent = FileManager.NonExclusiveReadAllText(PACServer.USER_ABP_FILE, Encoding.UTF8);
}
else
{
abpContent = Utils.UnGzip(Resources.abp_js);
GFWListUpdater.MergeAndWritePACFile(FileManager.NonExclusiveReadAllText(Utils.GetTempPath("gfwlist.txt")));
}
abpContent = abpContent.Replace("__RULES__", JsonConvert.SerializeObject(lines, Formatting.Indented));
if (File.Exists(PACServer.PAC_FILE))
{
string original = FileManager.NonExclusiveReadAllText(PACServer.PAC_FILE, Encoding.UTF8);
if (original == abpContent)
{
return;
}
}
File.WriteAllText(PACServer.PAC_FILE, abpContent, Encoding.UTF8);
}
public void CopyPacUrl()
+6 -1
View File
@@ -13,7 +13,7 @@ Edit Servers...=サーバーの編集...
Statistics Config...=統計情報の設定...
Start on Boot=システムと同時に起動
Forward Proxy...=フォワードプロキシの設定...
Allow Clients from LAN=LAN からのアクセスを許可
Allow other Devices to connect=他のデバイスからの接続を許可する
Local PAC=ローカル PAC
Online PAC=オンライン PAC
Edit Local PAC File...=ローカル PAC ファイルの編集...
@@ -49,7 +49,11 @@ Server=サーバー
Server Addr=サーバーアドレス
Server Port=サーバーポート
Password=パスワード
Show Password=パスワードを表示する
Encryption=暗号化
Plugin Program=プラグインプログラム
Plugin Options=プラグインのオプション
Plugin Arguments=プラグインの引数
Proxy Port=プロキシポート
Remarks=付記
Timeout(Sec)=タイムアウト (秒)
@@ -66,6 +70,7 @@ Use Proxy=プロキシを利用する
Proxy Type=プロキシの種類
Proxy Addr=プロキシアドレス
Proxy Port=プロキシポート
If server has a plugin, proxy will not be used=サーバーにプラグインがある場合、プロキシは利用されません
# Log Form
Binary file not shown.
+6 -1
View File
@@ -13,7 +13,7 @@ Edit Servers...=编辑服务器...
Statistics Config...=统计配置...
Start on Boot=开机启动
Forward Proxy...=正向代理设置...
Allow Clients from LAN=允许来自局域网的连接
Allow other Devices to connect=允许其他设备连入
Local PAC=使用本地 PAC
Online PAC=使用在线 PAC
Edit Local PAC File...=编辑本地 PAC 文件...
@@ -49,7 +49,11 @@ Server=服务器
Server Addr=服务器地址
Server Port=服务器端口
Password=密码
Show Password=显示密码
Encryption=加密
Plugin Program=插件程序
Plugin Options=插件选项
Plugin Arguments=插件参数
Proxy Port=代理端口
Remarks=备注
Timeout(Sec)=超时(秒)
@@ -66,6 +70,7 @@ Use Proxy=使用代理
Proxy Type=代理类型
Proxy Addr=代理地址
Proxy Port=代理端口
If server has a plugin, proxy will not be used=若服务器含有插件,代理将不被使用
# Log Form
+6 -1
View File
@@ -13,7 +13,7 @@ Edit Servers...=編輯伺服器...
Statistics Config...=統計設定檔...
Start on Boot=開機啟動
Forward Proxy...=正向 Proxy 設定...
Allow Clients from LAN=允許來自區域網路的連線
Allow other Devices to connect=允許其他裝置連入
Local PAC=使用本機 PAC
Online PAC=使用線上 PAC
Edit Local PAC File...=編輯本機 PAC 檔案...
@@ -49,7 +49,11 @@ Server=伺服器
Server Addr=伺服器位址
Server Port=伺服器連接埠
Password=密碼
Show Password=顯示密碼
Encryption=加密
Plugin Program=外掛程式
Plugin Options=外掛程式選項
Plugin Arguments=外掛程式參數
Proxy Port=Proxy 連接埠
Remarks=註解
Timeout(Sec)=逾時 (秒)
@@ -66,6 +70,7 @@ Use Proxy=使用 Proxy
Proxy Type=Proxy 類型
Proxy Addr=Proxy 位址
Proxy Port=Proxy 連接埠
If server has a plugin, proxy will not be used=若伺服器含有外掛程式,Proxy 將不被使用
# Log Form
@@ -127,9 +127,9 @@ namespace Shadowsocks.Encryption.AEAD
public static void randBytes(byte[] buf, int length) { RNG.GetBytes(buf, length); }
public abstract int cipherEncrypt(byte[] plaintext, uint plen, byte[] ciphertext, ref uint clen);
public abstract void cipherEncrypt(byte[] plaintext, uint plen, byte[] ciphertext, ref uint clen);
public abstract int cipherDecrypt(byte[] ciphertext, uint clen, byte[] plaintext, ref uint plen);
public abstract void cipherDecrypt(byte[] ciphertext, uint clen, byte[] plaintext, ref uint plen);
#region TCP
@@ -19,7 +19,7 @@ namespace Shadowsocks.Encryption.AEAD
{
}
private static Dictionary<string, EncryptorInfo> _ciphers = new Dictionary<string, EncryptorInfo>
private static readonly Dictionary<string, EncryptorInfo> _ciphers = new Dictionary<string, EncryptorInfo>
{
{"aes-128-gcm", new EncryptorInfo("AES-128-GCM", 16, 16, 12, 16, CIPHER_AES)},
{"aes-192-gcm", new EncryptorInfo("AES-192-GCM", 24, 24, 12, 16, CIPHER_AES)},
@@ -48,6 +48,7 @@ namespace Shadowsocks.Encryption.AEAD
{
_decryptCtx = ctx;
}
MbedTLS.cipher_init(ctx);
if (MbedTLS.cipher_setup(ctx, MbedTLS.cipher_info_from_string(_innerLibName)) != 0)
throw new System.Exception("Cannot initialize mbed TLS cipher context");
@@ -67,7 +68,7 @@ namespace Shadowsocks.Encryption.AEAD
if (ret != 0) throw new System.Exception("failed to finish preparation");
}
public override int cipherEncrypt(byte[] plaintext, uint plen, byte[] ciphertext, ref uint clen)
public override void cipherEncrypt(byte[] plaintext, uint plen, byte[] ciphertext, ref uint clen)
{
// buf: all plaintext
// outbuf: ciphertext + tag
@@ -87,18 +88,18 @@ namespace Shadowsocks.Encryption.AEAD
/* cipher */
ciphertext, ref olen,
tagbuf, (uint) tagLen);
if (ret != 0) throw new CryptoErrorException();
if (ret != 0) throw new CryptoErrorException(String.Format("ret is {0}", ret));
Debug.Assert(olen == plen);
// attach tag to ciphertext
Array.Copy(tagbuf, 0, ciphertext, (int) plen, tagLen);
clen = olen + (uint) tagLen;
return ret;
break;
default:
throw new System.Exception("not implemented");
}
}
public override int cipherDecrypt(byte[] ciphertext, uint clen, byte[] plaintext, ref uint plen)
public override void cipherDecrypt(byte[] ciphertext, uint clen, byte[] plaintext, ref uint plen)
{
// buf: ciphertext + tag
// outbuf: plaintext
@@ -116,10 +117,10 @@ namespace Shadowsocks.Encryption.AEAD
ciphertext, (uint) (clen - tagLen),
plaintext, ref olen,
tagbuf, (uint) tagLen);
if (ret != 0) throw new CryptoErrorException();
if (ret != 0) throw new CryptoErrorException(String.Format("ret is {0}", ret));
Debug.Assert(olen == clen - tagLen);
plen = olen;
return ret;
break;
default:
throw new System.Exception("not implemented");
}
@@ -163,6 +164,7 @@ namespace Shadowsocks.Encryption.AEAD
Marshal.FreeHGlobal(_encryptCtx);
_encryptCtx = IntPtr.Zero;
}
if (_decryptCtx != IntPtr.Zero)
{
MbedTLS.cipher_free(_decryptCtx);
@@ -0,0 +1,192 @@
using System;
using System.Collections.Generic;
using Shadowsocks.Encryption.Exception;
namespace Shadowsocks.Encryption.AEAD
{
public class AEADOpenSSLEncryptor
: AEADEncryptor, IDisposable
{
const int CIPHER_AES = 1;
const int CIPHER_CHACHA20IETFPOLY1305 = 2;
private byte[] _opensslEncSubkey;
private byte[] _opensslDecSubkey;
private IntPtr _encryptCtx = IntPtr.Zero;
private IntPtr _decryptCtx = IntPtr.Zero;
private IntPtr _cipherInfoPtr = IntPtr.Zero;
public AEADOpenSSLEncryptor(string method, string password)
: base(method, password)
{
_opensslEncSubkey = new byte[keyLen];
_opensslDecSubkey = new byte[keyLen];
}
private static readonly Dictionary<string, EncryptorInfo> _ciphers = new Dictionary<string, EncryptorInfo>
{
{"aes-128-gcm", new EncryptorInfo("aes-128-gcm", 16, 16, 12, 16, CIPHER_AES)},
{"aes-192-gcm", new EncryptorInfo("aes-192-gcm", 24, 24, 12, 16, CIPHER_AES)},
{"aes-256-gcm", new EncryptorInfo("aes-256-gcm", 32, 32, 12, 16, CIPHER_AES)},
{"chacha20-ietf-poly1305", new EncryptorInfo("chacha20-poly1305", 32, 32, 12, 16, CIPHER_CHACHA20IETFPOLY1305)}
};
public static List<string> SupportedCiphers()
{
return new List<string>(_ciphers.Keys);
}
protected override Dictionary<string, EncryptorInfo> getCiphers()
{
return _ciphers;
}
public override void InitCipher(byte[] salt, bool isEncrypt, bool isUdp)
{
base.InitCipher(salt, isEncrypt, isUdp);
_cipherInfoPtr = OpenSSL.GetCipherInfo(_innerLibName);
if (_cipherInfoPtr == IntPtr.Zero) throw new System.Exception("openssl: cipher not found");
IntPtr ctx = OpenSSL.EVP_CIPHER_CTX_new();
if (ctx == IntPtr.Zero) throw new System.Exception("openssl: fail to create ctx");
if (isEncrypt)
{
_encryptCtx = ctx;
}
else
{
_decryptCtx = ctx;
}
DeriveSessionKey(isEncrypt ? _encryptSalt : _decryptSalt, _Masterkey,
isEncrypt ? _opensslEncSubkey : _opensslDecSubkey);
var ret = OpenSSL.EVP_CipherInit_ex(ctx, _cipherInfoPtr, IntPtr.Zero, null, null,
isEncrypt ? OpenSSL.OPENSSL_ENCRYPT : OpenSSL.OPENSSL_DECRYPT);
if (ret != 1) throw new System.Exception("openssl: fail to init ctx");
ret = OpenSSL.EVP_CIPHER_CTX_set_key_length(ctx, keyLen);
if (ret != 1) throw new System.Exception("openssl: fail to set key length");
ret = OpenSSL.EVP_CIPHER_CTX_ctrl(ctx, OpenSSL.EVP_CTRL_AEAD_SET_IVLEN,
nonceLen, IntPtr.Zero);
if (ret != 1) throw new System.Exception("openssl: fail to set AEAD nonce length");
ret = OpenSSL.EVP_CipherInit_ex(ctx, IntPtr.Zero, IntPtr.Zero,
isEncrypt ? _opensslEncSubkey : _opensslDecSubkey,
null,
isEncrypt ? OpenSSL.OPENSSL_ENCRYPT : OpenSSL.OPENSSL_DECRYPT);
if (ret != 1) throw new System.Exception("openssl: cannot set key");
OpenSSL.EVP_CIPHER_CTX_set_padding(ctx, 0);
}
public override void cipherEncrypt(byte[] plaintext, uint plen, byte[] ciphertext, ref uint clen)
{
OpenSSL.SetCtxNonce(_encryptCtx, _encNonce, true);
// buf: all plaintext
// outbuf: ciphertext + tag
int ret;
int tmpLen = 0;
clen = 0;
var tagBuf = new byte[tagLen];
ret = OpenSSL.EVP_CipherUpdate(_encryptCtx, ciphertext, out tmpLen,
plaintext, (int) plen);
if (ret != 1) throw new CryptoErrorException("openssl: fail to encrypt AEAD");
clen += (uint) tmpLen;
// For AEAD cipher, it should not output anything
ret = OpenSSL.EVP_CipherFinal_ex(_encryptCtx, ciphertext, ref tmpLen);
if (ret != 1) throw new CryptoErrorException("openssl: fail to finalize AEAD");
if (tmpLen > 0)
{
throw new System.Exception("openssl: fail to finish AEAD");
}
OpenSSL.AEADGetTag(_encryptCtx, tagBuf, tagLen);
Array.Copy(tagBuf, 0, ciphertext, clen, tagLen);
clen += (uint) tagLen;
}
public override void cipherDecrypt(byte[] ciphertext, uint clen, byte[] plaintext, ref uint plen)
{
OpenSSL.SetCtxNonce(_decryptCtx, _decNonce, false);
// buf: ciphertext + tag
// outbuf: plaintext
int ret;
int tmpLen = 0;
plen = 0;
// split tag
byte[] tagbuf = new byte[tagLen];
Array.Copy(ciphertext, (int) (clen - tagLen), tagbuf, 0, tagLen);
OpenSSL.AEADSetTag(_decryptCtx, tagbuf, tagLen);
ret = OpenSSL.EVP_CipherUpdate(_decryptCtx,
plaintext, out tmpLen, ciphertext, (int) (clen - tagLen));
if (ret != 1) throw new CryptoErrorException("openssl: fail to decrypt AEAD");
plen += (uint) tmpLen;
// For AEAD cipher, it should not output anything
ret = OpenSSL.EVP_CipherFinal_ex(_decryptCtx, plaintext, ref tmpLen);
if (ret <= 0)
{
// If this is not successful authenticated
throw new CryptoErrorException(String.Format("ret is {0}", ret));
}
if (tmpLen > 0)
{
throw new System.Exception("openssl: fail to finish AEAD");
}
}
#region IDisposable
private bool _disposed;
// instance based lock
private readonly object _lock = new object();
public override void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
~AEADOpenSSLEncryptor()
{
Dispose(false);
}
protected virtual void Dispose(bool disposing)
{
lock (_lock)
{
if (_disposed) return;
_disposed = true;
}
if (disposing)
{
// free managed objects
}
// free unmanaged objects
if (_encryptCtx != IntPtr.Zero)
{
OpenSSL.EVP_CIPHER_CTX_free(_encryptCtx);
_encryptCtx = IntPtr.Zero;
}
if (_decryptCtx != IntPtr.Zero)
{
OpenSSL.EVP_CIPHER_CTX_free(_decryptCtx);
_decryptCtx = IntPtr.Zero;
}
}
#endregion
}
}
@@ -10,7 +10,8 @@ namespace Shadowsocks.Encryption.AEAD
: AEADEncryptor, IDisposable
{
private const int CIPHER_CHACHA20IETFPOLY1305 = 1;
private const int CIPHER_AES256GCM = 2;
private const int CIPHER_XCHACHA20IETFPOLY1305 = 2;
private const int CIPHER_AES256GCM = 3;
private byte[] _sodiumEncSubkey;
private byte[] _sodiumDecSubkey;
@@ -22,9 +23,10 @@ namespace Shadowsocks.Encryption.AEAD
_sodiumDecSubkey = new byte[keyLen];
}
private static Dictionary<string, EncryptorInfo> _ciphers = new Dictionary<string, EncryptorInfo>
private static readonly Dictionary<string, EncryptorInfo> _ciphers = new Dictionary<string, EncryptorInfo>
{
{"chacha20-ietf-poly1305", new EncryptorInfo(32, 32, 12, 16, CIPHER_CHACHA20IETFPOLY1305)},
{"xchacha20-ietf-poly1305", new EncryptorInfo(32, 32, 24, 16, CIPHER_XCHACHA20IETFPOLY1305)},
{"aes-256-gcm", new EncryptorInfo(32, 32, 12, 16, CIPHER_AES256GCM)},
};
@@ -46,7 +48,7 @@ namespace Shadowsocks.Encryption.AEAD
}
public override int cipherEncrypt(byte[] plaintext, uint plen, byte[] ciphertext, ref uint clen)
public override void cipherEncrypt(byte[] plaintext, uint plen, byte[] ciphertext, ref uint clen)
{
Debug.Assert(_sodiumEncSubkey != null);
// buf: all plaintext
@@ -65,6 +67,13 @@ namespace Shadowsocks.Encryption.AEAD
null, _encNonce,
_sodiumEncSubkey);
break;
case CIPHER_XCHACHA20IETFPOLY1305:
ret = Sodium.crypto_aead_xchacha20poly1305_ietf_encrypt(ciphertext, ref encClen,
plaintext, (ulong)plen,
null, 0,
null, _encNonce,
_sodiumEncSubkey);
break;
case CIPHER_AES256GCM:
ret = Sodium.crypto_aead_aes256gcm_encrypt(ciphertext, ref encClen,
plaintext, (ulong)plen,
@@ -75,13 +84,12 @@ namespace Shadowsocks.Encryption.AEAD
default:
throw new System.Exception("not implemented");
}
if (ret != 0) throw new CryptoErrorException();
if (ret != 0) throw new CryptoErrorException(String.Format("ret is {0}", ret));
Logging.Dump("after cipherEncrypt: cipher", ciphertext, (int) encClen);
clen = (uint) encClen;
return ret;
}
public override int cipherDecrypt(byte[] ciphertext, uint clen, byte[] plaintext, ref uint plen)
public override void cipherDecrypt(byte[] ciphertext, uint clen, byte[] plaintext, ref uint plen)
{
Debug.Assert(_sodiumDecSubkey != null);
// buf: ciphertext + tag
@@ -100,6 +108,13 @@ namespace Shadowsocks.Encryption.AEAD
null, 0,
_decNonce, _sodiumDecSubkey);
break;
case CIPHER_XCHACHA20IETFPOLY1305:
ret = Sodium.crypto_aead_xchacha20poly1305_ietf_decrypt(plaintext, ref decPlen,
null,
ciphertext, (ulong)clen,
null, 0,
_decNonce, _sodiumDecSubkey);
break;
case CIPHER_AES256GCM:
ret = Sodium.crypto_aead_aes256gcm_decrypt(plaintext, ref decPlen,
null,
@@ -111,10 +126,9 @@ namespace Shadowsocks.Encryption.AEAD
throw new System.Exception("not implemented");
}
if (ret != 0) throw new CryptoErrorException();
if (ret != 0) throw new CryptoErrorException(String.Format("ret is {0}", ret));
Logging.Dump("after cipherDecrypt: plain", plaintext, (int) decPlen);
plen = (uint) decPlen;
return ret;
}
public override void Dispose()
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
using Shadowsocks.Encryption.AEAD;
using Shadowsocks.Encryption.Stream;
@@ -26,21 +27,42 @@ namespace Shadowsocks.Encryption
AEADSodiumEncryptorSupportedCiphers.Remove("aes-256-gcm");
}
foreach (string method in StreamMbedTLSEncryptor.SupportedCiphers())
// XXX: sequence matters, OpenSSL > Sodium > MbedTLS
foreach (string method in StreamOpenSSLEncryptor.SupportedCiphers())
{
_registeredEncryptors.Add(method, typeof(StreamMbedTLSEncryptor));
if (!_registeredEncryptors.ContainsKey(method))
_registeredEncryptors.Add(method, typeof(StreamOpenSSLEncryptor));
}
foreach (string method in StreamSodiumEncryptor.SupportedCiphers())
{
_registeredEncryptors.Add(method, typeof(StreamSodiumEncryptor));
if (!_registeredEncryptors.ContainsKey(method))
_registeredEncryptors.Add(method, typeof(StreamSodiumEncryptor));
}
foreach (string method in AEADMbedTLSEncryptorSupportedCiphers)
foreach (string method in StreamMbedTLSEncryptor.SupportedCiphers())
{
_registeredEncryptors.Add(method, typeof(AEADMbedTLSEncryptor));
if (!_registeredEncryptors.ContainsKey(method))
_registeredEncryptors.Add(method, typeof(StreamMbedTLSEncryptor));
}
foreach (string method in AEADOpenSSLEncryptor.SupportedCiphers())
{
if (!_registeredEncryptors.ContainsKey(method))
_registeredEncryptors.Add(method, typeof(AEADOpenSSLEncryptor));
}
foreach (string method in AEADSodiumEncryptorSupportedCiphers)
{
_registeredEncryptors.Add(method, typeof(AEADSodiumEncryptor));
if (!_registeredEncryptors.ContainsKey(method))
_registeredEncryptors.Add(method, typeof(AEADSodiumEncryptor));
}
foreach (string method in AEADMbedTLSEncryptorSupportedCiphers)
{
if (!_registeredEncryptors.ContainsKey(method))
_registeredEncryptors.Add(method, typeof(AEADMbedTLSEncryptor));
}
}
@@ -50,12 +72,29 @@ namespace Shadowsocks.Encryption
{
method = "aes-256-cfb";
}
method = method.ToLowerInvariant();
Type t = _registeredEncryptors[method];
ConstructorInfo c = t.GetConstructor(ConstructorTypes);
if (c == null) throw new System.Exception("Invalid ctor");
IEncryptor result = (IEncryptor) c.Invoke(new object[] {method, password});
return result;
}
public static string DumpRegisteredEncryptor()
{
var sb = new StringBuilder();
sb.Append(Environment.NewLine);
sb.AppendLine("=========================");
sb.AppendLine("Registered Encryptor Info");
foreach (var encryptor in _registeredEncryptors)
{
sb.AppendLine(String.Format("{0}=>{1}", encryptor.Key, encryptor.Value.Name));
}
sb.AppendLine("=========================");
return sb.ToString();
}
}
}
+3 -2
View File
@@ -34,7 +34,8 @@ namespace Shadowsocks.Encryption
public static byte[] MD5(byte[] input)
{
byte[] output = new byte[16];
md5(input, (uint) input.Length, output);
if (md5_ret(input, (uint) input.Length, output) != 0)
throw new System.Exception("mbedtls: MD5 failure");
return output;
}
@@ -42,7 +43,7 @@ namespace Shadowsocks.Encryption
private static extern IntPtr LoadLibrary(string path);
[DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
public static extern void md5(byte[] input, uint ilen, byte[] output);
public static extern int md5_ret(byte[] input, uint ilen, byte[] output);
/// <summary>
/// Get cipher ctx size for unmanaged memory allocation
+161
View File
@@ -0,0 +1,161 @@
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Security;
using System.Text;
using Shadowsocks.Controller;
using Shadowsocks.Encryption.Exception;
using Shadowsocks.Properties;
using Shadowsocks.Util;
namespace Shadowsocks.Encryption
{
// XXX: only for OpenSSL 1.1.0 and higher
public static class OpenSSL
{
private const string DLLNAME = "libsscrypto.dll";
public const int OPENSSL_ENCRYPT = 1;
public const int OPENSSL_DECRYPT = 0;
public const int EVP_CTRL_AEAD_SET_IVLEN = 0x9;
public const int EVP_CTRL_AEAD_GET_TAG = 0x10;
public const int EVP_CTRL_AEAD_SET_TAG = 0x11;
static OpenSSL()
{
string dllPath = Utils.GetTempPath(DLLNAME);
try
{
FileManager.UncompressFile(dllPath, Resources.libsscrypto_dll);
}
catch (IOException)
{
}
catch (System.Exception e)
{
Logging.LogUsefulException(e);
}
LoadLibrary(dllPath);
}
public static IntPtr GetCipherInfo(string cipherName)
{
var name = Encoding.ASCII.GetBytes(cipherName);
Array.Resize(ref name, name.Length + 1);
return EVP_get_cipherbyname(name);
}
/// <summary>
/// Need init cipher context after EVP_CipherFinal_ex to reuse context
/// </summary>
/// <param name="ctx"></param>
/// <param name="cipherType"></param>
/// <param name="nonce"></param>
public static void SetCtxNonce(IntPtr ctx, byte[] nonce, bool isEncrypt)
{
var ret = EVP_CipherInit_ex(ctx, IntPtr.Zero,
IntPtr.Zero, null,
nonce,
isEncrypt ? OPENSSL_ENCRYPT : OPENSSL_DECRYPT);
if (ret != 1) throw new System.Exception("openssl: fail to set AEAD nonce");
}
public static void AEADGetTag(IntPtr ctx, byte[] tagbuf, int taglen)
{
IntPtr tagBufIntPtr = IntPtr.Zero;
try
{
tagBufIntPtr = Marshal.AllocHGlobal(taglen);
var ret = EVP_CIPHER_CTX_ctrl(ctx,
EVP_CTRL_AEAD_GET_TAG, taglen, tagBufIntPtr);
if (ret != 1) throw new CryptoErrorException("openssl: fail to get AEAD tag");
// take tag from unmanaged memory
Marshal.Copy(tagBufIntPtr, tagbuf, 0, taglen);
}
finally
{
if (tagBufIntPtr != IntPtr.Zero)
{
Marshal.FreeHGlobal(tagBufIntPtr);
}
}
}
public static void AEADSetTag(IntPtr ctx, byte[] tagbuf, int taglen)
{
IntPtr tagBufIntPtr = IntPtr.Zero;
try
{
// allocate unmanaged memory for tag
tagBufIntPtr = Marshal.AllocHGlobal(taglen);
// copy tag to unmanaged memory
Marshal.Copy(tagbuf, 0, tagBufIntPtr, taglen);
var ret = EVP_CIPHER_CTX_ctrl(ctx,
EVP_CTRL_AEAD_SET_TAG, taglen, tagBufIntPtr);
if (ret != 1) throw new CryptoErrorException("openssl: fail to set AEAD tag");
}
finally
{
if (tagBufIntPtr != IntPtr.Zero)
{
Marshal.FreeHGlobal(tagBufIntPtr);
}
}
}
[DllImport("Kernel32.dll")]
private static extern IntPtr LoadLibrary(string path);
[SuppressUnmanagedCodeSecurity]
[DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr EVP_CIPHER_CTX_new();
[SuppressUnmanagedCodeSecurity]
[DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
public static extern void EVP_CIPHER_CTX_free(IntPtr ctx);
[SuppressUnmanagedCodeSecurity]
[DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
public static extern int EVP_CIPHER_CTX_reset(IntPtr ctx);
[SuppressUnmanagedCodeSecurity]
[DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
public static extern int EVP_CipherInit_ex(IntPtr ctx, IntPtr type,
IntPtr impl, byte[] key, byte[] iv, int enc);
[SuppressUnmanagedCodeSecurity]
[DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
public static extern int EVP_CipherUpdate(IntPtr ctx, byte[] outb,
out int outl, byte[] inb, int inl);
[SuppressUnmanagedCodeSecurity]
[DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
public static extern int EVP_CipherFinal_ex(IntPtr ctx, byte[] outm, ref int outl);
[SuppressUnmanagedCodeSecurity]
[DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
public static extern int EVP_CIPHER_CTX_set_padding(IntPtr x, int padding);
[SuppressUnmanagedCodeSecurity]
[DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
public static extern int EVP_CIPHER_CTX_set_key_length(IntPtr x, int keylen);
[SuppressUnmanagedCodeSecurity]
[DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
public static extern int EVP_CIPHER_CTX_ctrl(IntPtr ctx, int type, int arg, IntPtr ptr);
/// <summary>
/// simulate NUL-terminated string
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
[SuppressUnmanagedCodeSecurity]
[DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr EVP_get_cipherbyname(byte[] name);
}
}
+8
View File
@@ -73,6 +73,14 @@ namespace Shadowsocks.Encryption
public static extern int crypto_aead_chacha20poly1305_ietf_decrypt(byte[] m, ref ulong mlen_p,
byte[] nsec, byte[] c, ulong clen, byte[] ad, ulong adlen, byte[] npub, byte[] k);
[DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
public static extern int crypto_aead_xchacha20poly1305_ietf_encrypt(byte[] c, ref ulong clen_p, byte[] m, ulong mlen,
byte[] ad, ulong adlen, byte[] nsec, byte[] npub, byte[] k);
[DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
public static extern int crypto_aead_xchacha20poly1305_ietf_decrypt(byte[] m, ref ulong mlen_p, byte[] nsec, byte[] c,
ulong clen, byte[] ad, ulong adlen, byte[] npub, byte[] k);
[DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
public static extern int crypto_aead_aes256gcm_encrypt(byte[] c, ref ulong clen_p, byte[] m, ulong mlen,
byte[] ad, ulong adlen, byte[] nsec, byte[] npub, byte[] k);
@@ -0,0 +1,160 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using Shadowsocks.Encryption.Exception;
namespace Shadowsocks.Encryption.Stream
{
public class StreamOpenSSLEncryptor
: StreamEncryptor, IDisposable
{
const int CIPHER_RC4 = 1;
const int CIPHER_AES = 2;
const int CIPHER_CAMELLIA = 3;
const int CIPHER_BLOWFISH = 4;
const int CIPHER_CHACHA20_IETF = 5;
private IntPtr _encryptCtx = IntPtr.Zero;
private IntPtr _decryptCtx = IntPtr.Zero;
public StreamOpenSSLEncryptor(string method, string password)
: base(method, password)
{
}
// XXX: name=RC4,blkSz=1,keyLen=16,ivLen=0, do NOT pass IV to it
private static readonly Dictionary<string, EncryptorInfo> _ciphers = new Dictionary<string, EncryptorInfo>
{
{ "aes-128-cfb", new EncryptorInfo("AES-128-CFB", 16, 16, CIPHER_AES) },
{ "aes-192-cfb", new EncryptorInfo("AES-192-CFB", 24, 16, CIPHER_AES) },
{ "aes-256-cfb", new EncryptorInfo("AES-256-CFB", 32, 16, CIPHER_AES) },
{ "aes-128-ctr", new EncryptorInfo("aes-128-ctr", 16, 16, CIPHER_AES) },
{ "aes-192-ctr", new EncryptorInfo("aes-192-ctr", 24, 16, CIPHER_AES) },
{ "aes-256-ctr", new EncryptorInfo("aes-256-ctr", 32, 16, CIPHER_AES) },
{ "bf-cfb", new EncryptorInfo("bf-cfb", 16, 8, CIPHER_BLOWFISH) },
{ "camellia-128-cfb", new EncryptorInfo("CAMELLIA-128-CFB", 16, 16, CIPHER_CAMELLIA) },
{ "camellia-192-cfb", new EncryptorInfo("CAMELLIA-192-CFB", 24, 16, CIPHER_CAMELLIA) },
{ "camellia-256-cfb", new EncryptorInfo("CAMELLIA-256-CFB", 32, 16, CIPHER_CAMELLIA) },
{ "rc4-md5", new EncryptorInfo("RC4", 16, 16, CIPHER_RC4) },
// it's using ivLen=16, not compatible
//{ "chacha20-ietf", new EncryptorInfo("chacha20", 32, 12, CIPHER_CHACHA20_IETF) }
};
public static List<string> SupportedCiphers()
{
return new List<string>(_ciphers.Keys);
}
protected override Dictionary<string, EncryptorInfo> getCiphers()
{
return _ciphers;
}
protected override void initCipher(byte[] iv, bool isEncrypt)
{
base.initCipher(iv, isEncrypt);
IntPtr cipherInfo = OpenSSL.GetCipherInfo(_innerLibName);
if (cipherInfo == IntPtr.Zero) throw new System.Exception("openssl: cipher not found");
IntPtr ctx = OpenSSL.EVP_CIPHER_CTX_new();
if (ctx == IntPtr.Zero) throw new System.Exception("fail to create ctx");
if (isEncrypt)
{
_encryptCtx = ctx;
}
else
{
_decryptCtx = ctx;
}
byte[] realkey;
if (_method == "rc4-md5")
{
byte[] temp = new byte[keyLen + ivLen];
realkey = new byte[keyLen];
Array.Copy(_key, 0, temp, 0, keyLen);
Array.Copy(iv, 0, temp, keyLen, ivLen);
realkey = MbedTLS.MD5(temp);
}
else
{
realkey = _key;
}
var ret = OpenSSL.EVP_CipherInit_ex(ctx, cipherInfo, IntPtr.Zero, null,null,
isEncrypt ? OpenSSL.OPENSSL_ENCRYPT : OpenSSL.OPENSSL_DECRYPT);
if (ret != 1) throw new System.Exception("openssl: fail to set key length");
ret = OpenSSL.EVP_CIPHER_CTX_set_key_length(ctx, keyLen);
if (ret != 1) throw new System.Exception("openssl: fail to set key length");
ret = OpenSSL.EVP_CipherInit_ex(ctx, IntPtr.Zero, IntPtr.Zero, realkey,
_method == "rc4-md5" ? null : iv,
isEncrypt ? OpenSSL.OPENSSL_ENCRYPT : OpenSSL.OPENSSL_DECRYPT);
if (ret != 1) throw new System.Exception("openssl: cannot set key and iv");
OpenSSL.EVP_CIPHER_CTX_set_padding(ctx, 0);
}
protected override void cipherUpdate(bool isEncrypt, int length, byte[] buf, byte[] outbuf)
{
// C# could be multi-threaded
if (_disposed)
{
throw new ObjectDisposedException(this.ToString());
}
int outlen = 0;
var ret = OpenSSL.EVP_CipherUpdate(isEncrypt ? _encryptCtx : _decryptCtx,
outbuf, out outlen, buf, length);
if (ret != 1)
throw new CryptoErrorException(String.Format("ret is {0}", ret));
Debug.Assert(outlen == length);
}
#region IDisposable
private bool _disposed;
// instance based lock
private readonly object _lock = new object();
public override void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
~StreamOpenSSLEncryptor()
{
Dispose(false);
}
protected virtual void Dispose(bool disposing)
{
lock (_lock)
{
if (_disposed) return;
_disposed = true;
}
if (disposing)
{
// free managed objects
}
// free unmanaged objects
if (_encryptCtx != IntPtr.Zero)
{
OpenSSL.EVP_CIPHER_CTX_free(_encryptCtx);
_encryptCtx = IntPtr.Zero;
}
if (_decryptCtx != IntPtr.Zero)
{
OpenSSL.EVP_CIPHER_CTX_free(_decryptCtx);
_decryptCtx = IntPtr.Zero;
}
}
#endregion
}
}
@@ -27,7 +27,7 @@ namespace Shadowsocks.Encryption.Stream
_decryptBuf = new byte[MAX_INPUT_SIZE + SODIUM_BLOCK_SIZE];
}
private static Dictionary<string, EncryptorInfo> _ciphers = new Dictionary<string, EncryptorInfo> {
private static readonly Dictionary<string, EncryptorInfo> _ciphers = new Dictionary<string, EncryptorInfo> {
{ "salsa20", new EncryptorInfo(32, 8, CIPHER_SALSA20) },
{ "chacha20", new EncryptorInfo(32, 8, CIPHER_CHACHA20) },
{ "chacha20-ietf", new EncryptorInfo(32, 12, CIPHER_CHACHA20_IETF) }
+4 -1
View File
@@ -89,7 +89,10 @@ namespace Shadowsocks.Model
configs = new List<Server>()
{
GetDefaultServer()
}
},
logViewer = new LogViewerConfig(),
proxy = new ProxyConfig(),
hotkey = new HotkeyConfig()
};
}
}
+123 -35
View File
@@ -1,18 +1,21 @@
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
using Shadowsocks.Controller;
using System.Text.RegularExpressions;
namespace Shadowsocks.Model
{
[Serializable]
public class Server
{
#region ParseLegacyURL
public static readonly Regex
UrlFinder = new Regex(@"ss://(?<base64>[A-Za-z0-9+-/=_]+)(?:#(?<tag>\S+))?", RegexOptions.IgnoreCase),
DetailsParser = new Regex(@"^((?<method>.+?):(?<password>.*)@(?<hostname>.+?):(?<port>\d+?))$", RegexOptions.IgnoreCase);
#endregion ParseLegacyURL
private const int DefaultServerTimeoutSec = 5;
public const int MaxServerTimeoutSec = 20;
@@ -21,6 +24,9 @@ namespace Shadowsocks.Model
public int server_port;
public string password;
public string method;
public string plugin;
public string plugin_opts;
public string plugin_args;
public string remarks;
public int timeout;
@@ -41,59 +47,141 @@ namespace Shadowsocks.Model
{
return I18N.GetString("New server");
}
string serverStr;
// CheckHostName() won't do a real DNS lookup
var hostType = Uri.CheckHostName(server);
switch (hostType)
{
case UriHostNameType.IPv6:
serverStr = $"[{server}]:{server_port}";
break;
default:
// IPv4 and domain name
serverStr = $"{server}:{server_port}";
break;
}
string serverStr = $"{FormatHostName(server)}:{server_port}";
return remarks.IsNullOrEmpty()
? serverStr
: $"{remarks} ({serverStr})";
}
public string FormatHostName(string hostName)
{
// CheckHostName() won't do a real DNS lookup
switch (Uri.CheckHostName(hostName))
{
case UriHostNameType.IPv6: // Add square bracket when IPv6 (RFC3986)
return $"[{hostName}]";
default: // IPv4 or domain name
return hostName;
}
}
public Server()
{
server = "";
server_port = 8388;
method = "aes-256-cfb";
plugin = "";
plugin_opts = "";
plugin_args = "";
password = "";
remarks = "";
timeout = DefaultServerTimeoutSec;
}
private static Server ParseLegacyURL(string ssURL)
{
var match = UrlFinder.Match(ssURL);
if (!match.Success)
return null;
Server server = new Server();
var base64 = match.Groups["base64"].Value.TrimEnd('/');
var tag = match.Groups["tag"].Value;
if (!tag.IsNullOrEmpty())
{
server.remarks = HttpUtility.UrlDecode(tag, Encoding.UTF8);
}
Match details = null;
try
{
details = DetailsParser.Match(Encoding.UTF8.GetString(Convert.FromBase64String(
base64.PadRight(base64.Length + (4 - base64.Length % 4) % 4, '='))));
}
catch (FormatException)
{
return null;
}
if (!details.Success)
return null;
server.method = details.Groups["method"].Value;
server.password = details.Groups["password"].Value;
server.server = details.Groups["hostname"].Value;
server.server_port = int.Parse(details.Groups["port"].Value);
return server;
}
public static List<Server> GetServers(string ssURL)
{
var matches = UrlFinder.Matches(ssURL);
if (matches.Count <= 0) return null;
List<Server> servers = new List<Server>();
foreach (Match match in matches)
{
Server tmp = new Server();
var base64 = match.Groups["base64"].Value;
var tag = match.Groups["tag"].Value;
if (!tag.IsNullOrEmpty())
{
tmp.remarks = HttpUtility.UrlDecode(tag, Encoding.UTF8);
}
Match details = DetailsParser.Match(Encoding.UTF8.GetString(Convert.FromBase64String(
base64.PadRight(base64.Length + (4 - base64.Length % 4) % 4, '='))));
if (!details.Success)
continue;
tmp.method = details.Groups["method"].Value;
tmp.password = details.Groups["password"].Value;
tmp.server = details.Groups["hostname"].Value;
tmp.server_port = int.Parse(details.Groups["port"].Value);
var serverUrls = ssURL.Split('\r', '\n');
servers.Add(tmp);
List<Server> servers = new List<Server>();
foreach (string serverUrl in serverUrls)
{
string _serverUrl = serverUrl.Trim();
if (!_serverUrl.BeginWith("ss://", StringComparison.InvariantCultureIgnoreCase))
{
continue;
}
Server legacyServer = ParseLegacyURL(serverUrl);
if (legacyServer != null) //legacy
{
servers.Add(legacyServer);
}
else //SIP002
{
Uri parsedUrl;
try
{
parsedUrl = new Uri(serverUrl);
}
catch (UriFormatException)
{
continue;
}
Server server = new Server
{
remarks = parsedUrl.GetComponents(UriComponents.Fragment, UriFormat.Unescaped),
server = parsedUrl.IdnHost,
server_port = parsedUrl.Port,
};
// parse base64 UserInfo
string rawUserInfo = parsedUrl.GetComponents(UriComponents.UserInfo, UriFormat.Unescaped);
string base64 = rawUserInfo.Replace('-', '+').Replace('_', '/'); // Web-safe base64 to normal base64
string userInfo = "";
try
{
userInfo = Encoding.UTF8.GetString(Convert.FromBase64String(
base64.PadRight(base64.Length + (4 - base64.Length % 4) % 4, '=')));
}
catch (FormatException)
{
continue;
}
string[] userInfoParts = userInfo.Split(new char[] { ':' }, 2);
if (userInfoParts.Length != 2)
{
continue;
}
server.method = userInfoParts[0];
server.password = userInfoParts[1];
NameValueCollection queryParameters = HttpUtility.ParseQueryString(parsedUrl.Query);
string[] pluginParts = HttpUtility.UrlDecode(queryParameters["plugin"] ?? "").Split(new[] { ';' }, 2);
if (pluginParts.Length > 0)
{
server.plugin = pluginParts[0] ?? "";
}
if (pluginParts.Length > 1)
{
server.plugin_opts = pluginParts[1] ?? "";
}
servers.Add(server);
}
}
return servers;
}
+13 -35
View File
@@ -122,11 +122,19 @@ namespace Shadowsocks
Logging.Info("os wake up");
if (MainController != null)
{
System.Timers.Timer timer = new System.Timers.Timer(10 * 1000);
timer.Elapsed += Timer_Elapsed;
timer.AutoReset = false;
timer.Enabled = true;
timer.Start();
System.Threading.Tasks.Task.Factory.StartNew(() =>
{
Thread.Sleep(10 * 1000);
try
{
MainController.Start();
Logging.Info("controller started");
}
catch (Exception ex)
{
Logging.LogUsefulException(ex);
}
});
}
break;
case PowerModes.Suspend:
@@ -140,36 +148,6 @@ namespace Shadowsocks
}
}
private static void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
try
{
if (MainController != null)
{
MainController.Start();
Logging.Info("controller started");
}
}
catch (Exception ex)
{
Logging.LogUsefulException(ex);
}
finally
{
try
{
System.Timers.Timer timer = (System.Timers.Timer)sender;
timer.Enabled = false;
timer.Stop();
timer.Dispose();
}
catch (Exception ex)
{
Logging.LogUsefulException(ex);
}
}
}
private static void Application_ApplicationExit(object sender, EventArgs e)
{
// detach static event handlers
@@ -11,7 +11,7 @@ using System.Runtime.InteropServices;
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Shadowsocks")]
[assembly: AssemblyCopyright("clowwindy & community 2017")]
[assembly: AssemblyCopyright("clowwindy & community 2018")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
+44 -44
View File
@@ -1,10 +1,10 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
// 此代码由工具生成。
// 运行时版本:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// 对此文件的更改可能会导致不正确的行为,并且如果
// 重新生成代码,这些更改将会丢失。
// </auto-generated>
//------------------------------------------------------------------------------
@@ -13,13 +13,13 @@ namespace Shadowsocks.Properties {
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// 一个强类型的资源类,用于查找本地化的字符串等。
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
// 此类是由 StronglyTypedResourceBuilder
// 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
// 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen
// (以 /str 作为命令选项),或重新生成 VS 项目。
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
@@ -33,7 +33,7 @@ namespace Shadowsocks.Properties {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// 返回此类使用的缓存的 ResourceManager 实例。
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
@@ -47,8 +47,8 @@ namespace Shadowsocks.Properties {
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// 使用此强类型资源类,为所有资源查找
/// 重写当前线程的 CurrentUICulture 属性。
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
@@ -61,7 +61,7 @@ namespace Shadowsocks.Properties {
}
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// 查找 System.Byte[] 类型的本地化资源。
/// </summary>
internal static byte[] abp_js {
get {
@@ -71,28 +71,28 @@ namespace Shadowsocks.Properties {
}
/// <summary>
/// Looks up a localized string similar to # translation for Japanese
/// 查找类似 # translation for Japanese
///
///Shadowsocks=Shadowsocks
///
///# Menu items
///
///Enable System Proxy=システムの代理を有効にする
///Enable System Proxy=システム プロキシを有効にする
///Mode=モード
///PAC=PAC
///Global=全般
///Servers=サーバ
///Edit Servers...=サーバーを編集する...
///Servers=サーバー
///Edit Servers...=サーバーの編集...
///Statistics Config...=統計情報の設定...
///Start on Boot=システムと同時に起動
///Forward Proxy...=代理を転送する...
///Allow Clients from LAN=LANからのクライアントを許可する
///Forward Proxy...=フォワードプロキシの設定...
///Allow Clients from LAN=LAN からのアクセスを許可
///Local PAC=ローカル PAC
///Online PAC=オンライン PAC
///Edit Local PAC File...=ローカル PAC ファイルを編集する...
///Update Local PAC from GFWList=GFWList から、ローカル PACを更新する
///Edit User Rule for GFWList...=利用者規則を編集する...
///Secure Local [rest of string was truncated]&quot;;.
///Edit Local PAC File...=ローカル PAC ファイルの編集...
///Update Local PAC from GFWList=GFWList からローカル PAC を更新
///Edit User Rule for GFWList...=ユーザールールの編集...
///Secure Local [字符串的其余部分被截断]&quot;; 的本地化字符串。
/// </summary>
internal static string ja {
get {
@@ -101,7 +101,7 @@ namespace Shadowsocks.Properties {
}
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// 查找 System.Byte[] 类型的本地化资源。
/// </summary>
internal static byte[] libsscrypto_dll {
get {
@@ -111,7 +111,7 @@ namespace Shadowsocks.Properties {
}
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// 查找 System.Byte[] 类型的本地化资源。
/// </summary>
internal static byte[] mgwz_dll {
get {
@@ -121,14 +121,14 @@ namespace Shadowsocks.Properties {
}
/// <summary>
/// Looks up a localized string similar to listen-address __PRIVOXY_BIND_IP__:__PRIVOXY_BIND_PORT__
/// 查找类似 listen-address __PRIVOXY_BIND_IP__:__PRIVOXY_BIND_PORT__
///toggle 0
///logfile ss_privoxy.log
///show-on-task-bar 0
///activity-animation 0
///forward-socks5 / 127.0.0.1:__SOCKS_PORT__ .
///hide-console
///.
/// 的本地化字符串。
/// </summary>
internal static string privoxy_conf {
get {
@@ -137,7 +137,7 @@ namespace Shadowsocks.Properties {
}
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// 查找 System.Byte[] 类型的本地化资源。
/// </summary>
internal static byte[] privoxy_exe {
get {
@@ -147,7 +147,7 @@ namespace Shadowsocks.Properties {
}
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// 查找 System.Byte[] 类型的本地化资源。
/// </summary>
internal static byte[] proxy_pac_txt {
get {
@@ -157,7 +157,7 @@ namespace Shadowsocks.Properties {
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// 查找 System.Drawing.Bitmap 类型的本地化资源。
/// </summary>
internal static System.Drawing.Bitmap ss16 {
get {
@@ -167,7 +167,7 @@ namespace Shadowsocks.Properties {
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// 查找 System.Drawing.Bitmap 类型的本地化资源。
/// </summary>
internal static System.Drawing.Bitmap ss20 {
get {
@@ -177,7 +177,7 @@ namespace Shadowsocks.Properties {
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// 查找 System.Drawing.Bitmap 类型的本地化资源。
/// </summary>
internal static System.Drawing.Bitmap ss24 {
get {
@@ -187,7 +187,7 @@ namespace Shadowsocks.Properties {
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// 查找 System.Drawing.Bitmap 类型的本地化资源。
/// </summary>
internal static System.Drawing.Bitmap ssIn24 {
get {
@@ -197,7 +197,7 @@ namespace Shadowsocks.Properties {
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// 查找 System.Drawing.Bitmap 类型的本地化资源。
/// </summary>
internal static System.Drawing.Bitmap ssOut24 {
get {
@@ -207,7 +207,7 @@ namespace Shadowsocks.Properties {
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// 查找 System.Drawing.Bitmap 类型的本地化资源。
/// </summary>
internal static System.Drawing.Bitmap ssw128 {
get {
@@ -217,7 +217,7 @@ namespace Shadowsocks.Properties {
}
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// 查找 System.Byte[] 类型的本地化资源。
/// </summary>
internal static byte[] sysproxy_exe {
get {
@@ -227,7 +227,7 @@ namespace Shadowsocks.Properties {
}
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// 查找 System.Byte[] 类型的本地化资源。
/// </summary>
internal static byte[] sysproxy64_exe {
get {
@@ -237,9 +237,9 @@ namespace Shadowsocks.Properties {
}
/// <summary>
/// Looks up a localized string similar to ! Put user rules line by line in this file.
/// 查找类似 ! Put user rules line by line in this file.
///! See https://adblockplus.org/en/filter-cheatsheet
///.
/// 的本地化字符串。
/// </summary>
internal static string user_rule {
get {
@@ -248,7 +248,7 @@ namespace Shadowsocks.Properties {
}
/// <summary>
/// Looks up a localized string similar to # translation for Simplified Chinese
/// 查找类似 # translation for Simplified Chinese
///
///Shadowsocks=Shadowsocks
///
@@ -270,7 +270,7 @@ namespace Shadowsocks.Properties {
///Update Local PAC from GFWList=从 GFWList 更新本地 PAC
///Edit User Rule for GFWList...=编辑 GFWList 的用户规则...
///Secure Local PAC=保护本地 PAC
///Cop [rest of string was truncated]&quot;;.
///Cop [字符串的其余部分被截断]&quot;; 的本地化字符串。
/// </summary>
internal static string zh_CN {
get {
@@ -279,7 +279,7 @@ namespace Shadowsocks.Properties {
}
/// <summary>
/// Looks up a localized string similar to # translation for Traditional Chinese
/// 查找类似 # translation for Traditional Chinese
///
///Shadowsocks=Shadowsocks
///
@@ -300,7 +300,7 @@ namespace Shadowsocks.Properties {
///Edit Local PAC File...=編輯本機 PAC 檔案...
///Update Local PAC from GFWList=從 GFWList 更新本機 PAC
///Edit User Rule for GFWList...=編輯 GFWList 的使用者規則...
///Secure Local PAC=安全本機 [rest of string was truncated]&quot;;.
///Secure Local PAC=安全本機 [字符串的其余部分被截断]&quot;; 的本地化字符串。
/// </summary>
internal static string zh_TW {
get {
+1 -1
View File
@@ -125,7 +125,7 @@
<value>..\Data\ja.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>
<data name="libsscrypto_dll" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\data\libsscrypto.dll.gz;System.Byte[], mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
<value>..\Data\libsscrypto.dll.gz;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="mgwz_dll" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\data\mgwz.dll.gz;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
@@ -42,7 +42,10 @@ namespace Shadowsocks.Util.Sockets
arg.Completed += OnTcpConnectCompleted;
arg.UserToken = new TcpUserToken(callback, state);
Socket.ConnectAsync(SocketType.Stream, ProtocolType.Tcp, arg);
if(!Socket.ConnectAsync(SocketType.Stream, ProtocolType.Tcp, arg))
{
OnTcpConnectCompleted(this, arg);
}
}
private class FakeAsyncResult : IAsyncResult
@@ -48,18 +48,19 @@ namespace Shadowsocks.Util.SystemProxy
public static void SetIEProxy(bool enable, bool global, string proxyServer, string pacURL)
{
Read();
if (!_userSettings.UserSettingsRecorded)
{
// record user settings
ExecSysproxy("query");
ParseQueryStr(_queryStr);
}
string arguments;
string arguments;
if (enable)
{
arguments = global
? $"global {proxyServer} <local>;localhost;127.*;10.*;172.16.*;172.17.*;172.18.*;172.19.*;172.20.*;172.21.*;172.22.*;172.23.*;172.24.*;172.25.*;172.26.*;172.27.*;172.28.*;172.29.*;172.30.*;172.31.*;172.32.*;192.168.*"
? $"global {proxyServer} <local>;localhost;127.*;10.*;172.16.*;172.17.*;172.18.*;172.19.*;172.20.*;172.21.*;172.22.*;172.23.*;172.24.*;172.25.*;172.26.*;172.27.*;172.28.*;172.29.*;172.30.*;172.31.*;192.168.*"
: $"pac {pacURL}";
}
else
@@ -138,8 +139,10 @@ namespace Shadowsocks.Util.SystemProxy
try {
string configContent = File.ReadAllText(_userWininetConfigFile);
_userSettings = JsonConvert.DeserializeObject<SysproxyConfig>(configContent);
} catch (FileNotFoundException) {
_userSettings = new SysproxyConfig();
} catch(Exception) {
// Suppress all exceptions. finally block will initialize new user config settings.
} finally {
if (_userSettings == null) _userSettings = new SysproxyConfig();
}
}
+161 -54
View File
@@ -28,9 +28,11 @@
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
this.PluginOptionsLabel = new System.Windows.Forms.Label();
this.PluginTextBox = new System.Windows.Forms.TextBox();
this.RemarksTextBox = new System.Windows.Forms.TextBox();
this.RemarksLabel = new System.Windows.Forms.Label();
this.IPLabel = new System.Windows.Forms.Label();
this.ServerPortLabel = new System.Windows.Forms.Label();
this.PasswordLabel = new System.Windows.Forms.Label();
@@ -41,6 +43,12 @@
this.EncryptionSelect = new System.Windows.Forms.ComboBox();
this.TimeoutLabel = new System.Windows.Forms.Label();
this.TimeoutTextBox = new System.Windows.Forms.TextBox();
this.PluginLabel = new System.Windows.Forms.Label();
this.PluginOptionsTextBox = new System.Windows.Forms.TextBox();
this.ShowPasswdCheckBox = new System.Windows.Forms.CheckBox();
this.RemarksLabel = new System.Windows.Forms.Label();
this.PluginArgumentsTextBox = new System.Windows.Forms.TextBox();
this.PluginArgumentsLabel = new System.Windows.Forms.Label();
this.panel2 = new System.Windows.Forms.Panel();
this.OKButton = new System.Windows.Forms.Button();
this.MyCancelButton = new System.Windows.Forms.Button();
@@ -58,6 +66,7 @@
this.tableLayoutPanel3 = new System.Windows.Forms.TableLayoutPanel();
this.tableLayoutPanel4 = new System.Windows.Forms.TableLayoutPanel();
this.DuplicateButton = new System.Windows.Forms.Button();
this.toolTip1 = new System.Windows.Forms.ToolTip(this.components);
this.tableLayoutPanel1.SuspendLayout();
this.ServerGroupBox.SuspendLayout();
this.tableLayoutPanel2.SuspendLayout();
@@ -74,23 +83,30 @@
this.tableLayoutPanel1.ColumnCount = 2;
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel1.Controls.Add(this.RemarksTextBox, 1, 5);
this.tableLayoutPanel1.Controls.Add(this.RemarksLabel, 0, 5);
this.tableLayoutPanel1.Controls.Add(this.PluginOptionsLabel, 0, 6);
this.tableLayoutPanel1.Controls.Add(this.PluginTextBox, 1, 5);
this.tableLayoutPanel1.Controls.Add(this.RemarksTextBox, 1, 9);
this.tableLayoutPanel1.Controls.Add(this.IPLabel, 0, 0);
this.tableLayoutPanel1.Controls.Add(this.ServerPortLabel, 0, 1);
this.tableLayoutPanel1.Controls.Add(this.PasswordLabel, 0, 2);
this.tableLayoutPanel1.Controls.Add(this.IPTextBox, 1, 0);
this.tableLayoutPanel1.Controls.Add(this.ServerPortTextBox, 1, 1);
this.tableLayoutPanel1.Controls.Add(this.PasswordTextBox, 1, 2);
this.tableLayoutPanel1.Controls.Add(this.EncryptionLabel, 0, 3);
this.tableLayoutPanel1.Controls.Add(this.EncryptionSelect, 1, 3);
this.tableLayoutPanel1.Controls.Add(this.TimeoutLabel, 0, 6);
this.tableLayoutPanel1.Controls.Add(this.TimeoutTextBox, 1, 6);
this.tableLayoutPanel1.Controls.Add(this.EncryptionLabel, 0, 4);
this.tableLayoutPanel1.Controls.Add(this.EncryptionSelect, 1, 4);
this.tableLayoutPanel1.Controls.Add(this.TimeoutLabel, 0, 10);
this.tableLayoutPanel1.Controls.Add(this.TimeoutTextBox, 1, 10);
this.tableLayoutPanel1.Controls.Add(this.PluginLabel, 0, 5);
this.tableLayoutPanel1.Controls.Add(this.PluginOptionsTextBox, 1, 6);
this.tableLayoutPanel1.Controls.Add(this.ShowPasswdCheckBox, 1, 3);
this.tableLayoutPanel1.Controls.Add(this.PluginArgumentsTextBox, 1, 7);
this.tableLayoutPanel1.Controls.Add(this.PluginArgumentsLabel, 0, 7);
this.tableLayoutPanel1.Controls.Add(this.RemarksLabel, 0, 9);
this.tableLayoutPanel1.Location = new System.Drawing.Point(8, 21);
this.tableLayoutPanel1.Margin = new System.Windows.Forms.Padding(0);
this.tableLayoutPanel1.Name = "tableLayoutPanel1";
this.tableLayoutPanel1.Padding = new System.Windows.Forms.Padding(3);
this.tableLayoutPanel1.RowCount = 7;
this.tableLayoutPanel1.RowCount = 11;
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());
@@ -98,34 +114,49 @@
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(255, 167);
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.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel1.Size = new System.Drawing.Size(279, 270);
this.tableLayoutPanel1.TabIndex = 0;
//
// PluginOptionsLabel
//
this.PluginOptionsLabel.Anchor = System.Windows.Forms.AnchorStyles.Right;
this.PluginOptionsLabel.AutoSize = true;
this.PluginOptionsLabel.Location = new System.Drawing.Point(18, 166);
this.PluginOptionsLabel.Name = "PluginOptionsLabel";
this.PluginOptionsLabel.Size = new System.Drawing.Size(89, 12);
this.PluginOptionsLabel.TabIndex = 6;
this.PluginOptionsLabel.Text = "Plugin Options";
this.toolTip1.SetToolTip(this.PluginOptionsLabel, "Environment variables");
//
// PluginTextBox
//
this.PluginTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right)));
this.PluginTextBox.Location = new System.Drawing.Point(113, 135);
this.PluginTextBox.MaxLength = 256;
this.PluginTextBox.Name = "PluginTextBox";
this.PluginTextBox.Size = new System.Drawing.Size(160, 21);
this.PluginTextBox.TabIndex = 5;
this.PluginTextBox.WordWrap = false;
//
// RemarksTextBox
//
this.RemarksTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right)));
this.RemarksTextBox.Location = new System.Drawing.Point(89, 113);
this.RemarksTextBox.Location = new System.Drawing.Point(113, 216);
this.RemarksTextBox.MaxLength = 32;
this.RemarksTextBox.Name = "RemarksTextBox";
this.RemarksTextBox.Size = new System.Drawing.Size(160, 21);
this.RemarksTextBox.TabIndex = 4;
this.RemarksTextBox.TabIndex = 8;
this.RemarksTextBox.WordWrap = false;
//
// RemarksLabel
//
this.RemarksLabel.Anchor = System.Windows.Forms.AnchorStyles.Right;
this.RemarksLabel.AutoSize = true;
this.RemarksLabel.Location = new System.Drawing.Point(36, 117);
this.RemarksLabel.Name = "RemarksLabel";
this.RemarksLabel.Size = new System.Drawing.Size(47, 12);
this.RemarksLabel.TabIndex = 9;
this.RemarksLabel.Text = "Remarks";
//
// IPLabel
//
this.IPLabel.Anchor = System.Windows.Forms.AnchorStyles.Right;
this.IPLabel.AutoSize = true;
this.IPLabel.Location = new System.Drawing.Point(24, 10);
this.IPLabel.Location = new System.Drawing.Point(48, 10);
this.IPLabel.Name = "IPLabel";
this.IPLabel.Size = new System.Drawing.Size(59, 12);
this.IPLabel.TabIndex = 0;
@@ -135,7 +166,7 @@
//
this.ServerPortLabel.Anchor = System.Windows.Forms.AnchorStyles.Right;
this.ServerPortLabel.AutoSize = true;
this.ServerPortLabel.Location = new System.Drawing.Point(12, 37);
this.ServerPortLabel.Location = new System.Drawing.Point(36, 37);
this.ServerPortLabel.Name = "ServerPortLabel";
this.ServerPortLabel.Size = new System.Drawing.Size(71, 12);
this.ServerPortLabel.TabIndex = 1;
@@ -145,16 +176,17 @@
//
this.PasswordLabel.Anchor = System.Windows.Forms.AnchorStyles.Right;
this.PasswordLabel.AutoSize = true;
this.PasswordLabel.Location = new System.Drawing.Point(30, 64);
this.PasswordLabel.Location = new System.Drawing.Point(54, 64);
this.PasswordLabel.Name = "PasswordLabel";
this.PasswordLabel.Size = new System.Drawing.Size(53, 12);
this.PasswordLabel.TabIndex = 2;
this.PasswordLabel.Text = "Password";
this.PasswordLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
//
// IPTextBox
//
this.IPTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right)));
this.IPTextBox.Location = new System.Drawing.Point(89, 6);
this.IPTextBox.Location = new System.Drawing.Point(113, 6);
this.IPTextBox.MaxLength = 512;
this.IPTextBox.Name = "IPTextBox";
this.IPTextBox.Size = new System.Drawing.Size(160, 21);
@@ -164,7 +196,7 @@
// ServerPortTextBox
//
this.ServerPortTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right)));
this.ServerPortTextBox.Location = new System.Drawing.Point(89, 33);
this.ServerPortTextBox.Location = new System.Drawing.Point(113, 33);
this.ServerPortTextBox.MaxLength = 10;
this.ServerPortTextBox.Name = "ServerPortTextBox";
this.ServerPortTextBox.Size = new System.Drawing.Size(160, 21);
@@ -174,7 +206,7 @@
// PasswordTextBox
//
this.PasswordTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right)));
this.PasswordTextBox.Location = new System.Drawing.Point(89, 60);
this.PasswordTextBox.Location = new System.Drawing.Point(113, 60);
this.PasswordTextBox.MaxLength = 256;
this.PasswordTextBox.Name = "PasswordTextBox";
this.PasswordTextBox.Size = new System.Drawing.Size(160, 21);
@@ -186,10 +218,10 @@
//
this.EncryptionLabel.Anchor = System.Windows.Forms.AnchorStyles.Right;
this.EncryptionLabel.AutoSize = true;
this.EncryptionLabel.Location = new System.Drawing.Point(18, 91);
this.EncryptionLabel.Location = new System.Drawing.Point(42, 113);
this.EncryptionLabel.Name = "EncryptionLabel";
this.EncryptionLabel.Size = new System.Drawing.Size(65, 12);
this.EncryptionLabel.TabIndex = 8;
this.EncryptionLabel.TabIndex = 4;
this.EncryptionLabel.Text = "Encryption";
//
// EncryptionSelect
@@ -218,31 +250,98 @@
"aes-128-gcm",
"aes-192-gcm",
"aes-256-gcm",
"chacha20-ietf-poly1305"});
this.EncryptionSelect.Location = new System.Drawing.Point(89, 87);
"chacha20-ietf-poly1305",
"xchacha20-ietf-poly1305"});
this.EncryptionSelect.Location = new System.Drawing.Point(113, 109);
this.EncryptionSelect.Name = "EncryptionSelect";
this.EncryptionSelect.Size = new System.Drawing.Size(160, 20);
this.EncryptionSelect.TabIndex = 3;
this.EncryptionSelect.TabIndex = 4;
//
// TimeoutLabel
//
this.TimeoutLabel.Anchor = System.Windows.Forms.AnchorStyles.Right;
this.TimeoutLabel.AutoSize = true;
this.TimeoutLabel.Location = new System.Drawing.Point(6, 144);
this.TimeoutLabel.Location = new System.Drawing.Point(30, 247);
this.TimeoutLabel.Name = "TimeoutLabel";
this.TimeoutLabel.RightToLeft = System.Windows.Forms.RightToLeft.No;
this.TimeoutLabel.Size = new System.Drawing.Size(77, 12);
this.TimeoutLabel.TabIndex = 10;
this.TimeoutLabel.TabIndex = 9;
this.TimeoutLabel.Text = "Timeout(Sec)";
//
// TimeoutTextBox
//
this.TimeoutTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right)));
this.TimeoutTextBox.Location = new System.Drawing.Point(89, 140);
this.TimeoutTextBox.Location = new System.Drawing.Point(113, 243);
this.TimeoutTextBox.MaxLength = 5;
this.TimeoutTextBox.Name = "TimeoutTextBox";
this.TimeoutTextBox.Size = new System.Drawing.Size(160, 21);
this.TimeoutTextBox.TabIndex = 11;
this.TimeoutTextBox.TabIndex = 9;
//
// PluginLabel
//
this.PluginLabel.Anchor = System.Windows.Forms.AnchorStyles.Right;
this.PluginLabel.AutoSize = true;
this.PluginLabel.Location = new System.Drawing.Point(18, 139);
this.PluginLabel.Name = "PluginLabel";
this.PluginLabel.Size = new System.Drawing.Size(89, 12);
this.PluginLabel.TabIndex = 5;
this.PluginLabel.Text = "Plugin Program";
//
// PluginOptionsTextBox
//
this.PluginOptionsTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right)));
this.PluginOptionsTextBox.Location = new System.Drawing.Point(113, 162);
this.PluginOptionsTextBox.MaxLength = 256;
this.PluginOptionsTextBox.Name = "PluginOptionsTextBox";
this.PluginOptionsTextBox.Size = new System.Drawing.Size(160, 21);
this.PluginOptionsTextBox.TabIndex = 6;
this.PluginOptionsTextBox.WordWrap = false;
//
// ShowPasswdCheckBox
//
this.ShowPasswdCheckBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)));
this.ShowPasswdCheckBox.AutoSize = true;
this.ShowPasswdCheckBox.Location = new System.Drawing.Point(113, 87);
this.ShowPasswdCheckBox.Name = "ShowPasswdCheckBox";
this.ShowPasswdCheckBox.Size = new System.Drawing.Size(102, 16);
this.ShowPasswdCheckBox.TabIndex = 3;
this.ShowPasswdCheckBox.Text = "Show Password";
this.ShowPasswdCheckBox.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
this.ShowPasswdCheckBox.UseVisualStyleBackColor = true;
this.ShowPasswdCheckBox.CheckedChanged += new System.EventHandler(this.ShowPasswdCheckBox_CheckedChanged);
//
// RemarksLabel
//
this.RemarksLabel.Anchor = System.Windows.Forms.AnchorStyles.Right;
this.RemarksLabel.AutoSize = true;
this.RemarksLabel.Location = new System.Drawing.Point(60, 220);
this.RemarksLabel.Name = "RemarksLabel";
this.RemarksLabel.Size = new System.Drawing.Size(47, 12);
this.RemarksLabel.TabIndex = 8;
this.RemarksLabel.Text = "Remarks";
//
// PluginArgumentsTextBox
//
this.PluginArgumentsTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right)));
this.PluginArgumentsTextBox.Location = new System.Drawing.Point(113, 189);
this.PluginArgumentsTextBox.MaxLength = 512;
this.PluginArgumentsTextBox.Name = "PluginArgumentsTextBox";
this.PluginArgumentsTextBox.Size = new System.Drawing.Size(160, 21);
this.PluginArgumentsTextBox.TabIndex = 7;
this.PluginArgumentsTextBox.WordWrap = false;
//
// PluginArgumentsLabel
//
this.PluginArgumentsLabel.Anchor = System.Windows.Forms.AnchorStyles.Right;
this.PluginArgumentsLabel.AutoSize = true;
this.PluginArgumentsLabel.Location = new System.Drawing.Point(6, 193);
this.PluginArgumentsLabel.Name = "PluginArgumentsLabel";
this.PluginArgumentsLabel.Size = new System.Drawing.Size(101, 12);
this.PluginArgumentsLabel.TabIndex = 7;
this.PluginArgumentsLabel.Text = "Plugin Arguments";
this.toolTip1.SetToolTip(this.PluginArgumentsLabel, "Not SIP003 standard. Used as CLI arguments.\r\nMandatory:\r\n%SS_LOCAL_HOST%, %SS_LOC" +
"SL_PORT%, %SS_REMOTE_HOST%, %SS_REMOTE_PORT%\r\nOptional:\r\n%SS_PLUGIN_OPTIONS%");
//
// panel2
//
@@ -262,7 +361,7 @@
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.TabIndex = 17;
this.OKButton.Text = "OK";
this.OKButton.UseVisualStyleBackColor = true;
this.OKButton.Click += new System.EventHandler(this.OKButton_Click);
@@ -275,7 +374,7 @@
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.TabIndex = 18;
this.MyCancelButton.Text = "Cancel";
this.MyCancelButton.UseVisualStyleBackColor = true;
this.MyCancelButton.Click += new System.EventHandler(this.CancelButton_Click);
@@ -287,7 +386,7 @@
this.DeleteButton.Margin = new System.Windows.Forms.Padding(3, 6, 0, 3);
this.DeleteButton.Name = "DeleteButton";
this.DeleteButton.Size = new System.Drawing.Size(80, 23);
this.DeleteButton.TabIndex = 9;
this.DeleteButton.TabIndex = 13;
this.DeleteButton.Text = "&Delete";
this.DeleteButton.UseVisualStyleBackColor = true;
this.DeleteButton.Click += new System.EventHandler(this.DeleteButton_Click);
@@ -299,7 +398,7 @@
this.AddButton.Margin = new System.Windows.Forms.Padding(0, 6, 3, 3);
this.AddButton.Name = "AddButton";
this.AddButton.Size = new System.Drawing.Size(80, 23);
this.AddButton.TabIndex = 8;
this.AddButton.TabIndex = 12;
this.AddButton.Text = "&Add";
this.AddButton.UseVisualStyleBackColor = true;
this.AddButton.Click += new System.EventHandler(this.AddButton_Click);
@@ -312,7 +411,7 @@
this.ServerGroupBox.Location = new System.Drawing.Point(178, 0);
this.ServerGroupBox.Margin = new System.Windows.Forms.Padding(12, 0, 0, 0);
this.ServerGroupBox.Name = "ServerGroupBox";
this.ServerGroupBox.Size = new System.Drawing.Size(266, 205);
this.ServerGroupBox.Size = new System.Drawing.Size(290, 308);
this.ServerGroupBox.TabIndex = 0;
this.ServerGroupBox.TabStop = false;
this.ServerGroupBox.Text = "Server";
@@ -326,7 +425,7 @@
this.ServersListBox.Margin = new System.Windows.Forms.Padding(0);
this.ServersListBox.Name = "ServersListBox";
this.ServersListBox.Size = new System.Drawing.Size(166, 148);
this.ServersListBox.TabIndex = 7;
this.ServersListBox.TabIndex = 11;
this.ServersListBox.SelectedIndexChanged += new System.EventHandler(this.ServersListBox_SelectedIndexChanged);
//
// tableLayoutPanel2
@@ -349,7 +448,7 @@
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel2.Size = new System.Drawing.Size(444, 301);
this.tableLayoutPanel2.Size = new System.Drawing.Size(468, 404);
this.tableLayoutPanel2.TabIndex = 7;
//
// tableLayoutPanel6
@@ -362,7 +461,7 @@
this.tableLayoutPanel6.Controls.Add(this.MoveDownButton, 1, 0);
this.tableLayoutPanel6.Controls.Add(this.MoveUpButton, 0, 0);
this.tableLayoutPanel6.Dock = System.Windows.Forms.DockStyle.Top;
this.tableLayoutPanel6.Location = new System.Drawing.Point(0, 269);
this.tableLayoutPanel6.Location = new System.Drawing.Point(0, 372);
this.tableLayoutPanel6.Margin = new System.Windows.Forms.Padding(0);
this.tableLayoutPanel6.Name = "tableLayoutPanel6";
this.tableLayoutPanel6.RowCount = 1;
@@ -377,7 +476,7 @@
this.MoveDownButton.Margin = new System.Windows.Forms.Padding(3, 6, 0, 3);
this.MoveDownButton.Name = "MoveDownButton";
this.MoveDownButton.Size = new System.Drawing.Size(80, 23);
this.MoveDownButton.TabIndex = 11;
this.MoveDownButton.TabIndex = 16;
this.MoveDownButton.Text = "Move D&own";
this.MoveDownButton.UseVisualStyleBackColor = true;
this.MoveDownButton.Click += new System.EventHandler(this.MoveDownButton_Click);
@@ -389,7 +488,7 @@
this.MoveUpButton.Margin = new System.Windows.Forms.Padding(0, 6, 3, 3);
this.MoveUpButton.Name = "MoveUpButton";
this.MoveUpButton.Size = new System.Drawing.Size(80, 23);
this.MoveUpButton.TabIndex = 10;
this.MoveUpButton.TabIndex = 15;
this.MoveUpButton.Text = "Move &Up";
this.MoveUpButton.UseVisualStyleBackColor = true;
this.MoveUpButton.Click += new System.EventHandler(this.MoveUpButton_Click);
@@ -405,7 +504,7 @@
this.tableLayoutPanel5.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel5.Controls.Add(this.ProxyPortTextBox, 1, 0);
this.tableLayoutPanel5.Controls.Add(this.ProxyPortLabel, 0, 0);
this.tableLayoutPanel5.Location = new System.Drawing.Point(248, 205);
this.tableLayoutPanel5.Location = new System.Drawing.Point(272, 308);
this.tableLayoutPanel5.Margin = new System.Windows.Forms.Padding(0);
this.tableLayoutPanel5.Name = "tableLayoutPanel5";
this.tableLayoutPanel5.Padding = new System.Windows.Forms.Padding(3);
@@ -425,7 +524,7 @@
this.ProxyPortTextBox.MaxLength = 10;
this.ProxyPortTextBox.Name = "ProxyPortTextBox";
this.ProxyPortTextBox.Size = new System.Drawing.Size(113, 21);
this.ProxyPortTextBox.TabIndex = 6;
this.ProxyPortTextBox.TabIndex = 10;
this.ProxyPortTextBox.WordWrap = false;
//
// ProxyPortLabel
@@ -435,7 +534,7 @@
this.ProxyPortLabel.Location = new System.Drawing.Point(6, 26);
this.ProxyPortLabel.Name = "ProxyPortLabel";
this.ProxyPortLabel.Size = new System.Drawing.Size(65, 12);
this.ProxyPortLabel.TabIndex = 3;
this.ProxyPortLabel.TabIndex = 10;
this.ProxyPortLabel.Text = "Proxy Port";
//
// tableLayoutPanel3
@@ -449,7 +548,7 @@
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(285, 272);
this.tableLayoutPanel3.Location = new System.Drawing.Point(309, 375);
this.tableLayoutPanel3.Margin = new System.Windows.Forms.Padding(3, 3, 0, 3);
this.tableLayoutPanel3.Name = "tableLayoutPanel3";
this.tableLayoutPanel3.RowCount = 1;
@@ -468,7 +567,7 @@
this.tableLayoutPanel4.Controls.Add(this.DeleteButton, 1, 0);
this.tableLayoutPanel4.Controls.Add(this.AddButton, 0, 0);
this.tableLayoutPanel4.Dock = System.Windows.Forms.DockStyle.Top;
this.tableLayoutPanel4.Location = new System.Drawing.Point(0, 205);
this.tableLayoutPanel4.Location = new System.Drawing.Point(0, 308);
this.tableLayoutPanel4.Margin = new System.Windows.Forms.Padding(0);
this.tableLayoutPanel4.Name = "tableLayoutPanel4";
this.tableLayoutPanel4.RowCount = 2;
@@ -484,7 +583,7 @@
this.DuplicateButton.Margin = new System.Windows.Forms.Padding(0, 6, 3, 3);
this.DuplicateButton.Name = "DuplicateButton";
this.DuplicateButton.Size = new System.Drawing.Size(80, 23);
this.DuplicateButton.TabIndex = 10;
this.DuplicateButton.TabIndex = 14;
this.DuplicateButton.Text = "Dupli&cate";
this.DuplicateButton.UseVisualStyleBackColor = true;
this.DuplicateButton.Click += new System.EventHandler(this.DuplicateButton_Click);
@@ -497,7 +596,7 @@
this.AutoSize = true;
this.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
this.CancelButton = this.MyCancelButton;
this.ClientSize = new System.Drawing.Size(574, 367);
this.ClientSize = new System.Drawing.Size(574, 438);
this.Controls.Add(this.tableLayoutPanel2);
this.Controls.Add(this.panel2);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
@@ -535,7 +634,6 @@
private System.Windows.Forms.Label PasswordLabel;
private System.Windows.Forms.TextBox IPTextBox;
private System.Windows.Forms.TextBox ServerPortTextBox;
private System.Windows.Forms.TextBox PasswordTextBox;
private System.Windows.Forms.Label EncryptionLabel;
private System.Windows.Forms.ComboBox EncryptionSelect;
private System.Windows.Forms.Panel panel2;
@@ -559,6 +657,15 @@
private System.Windows.Forms.Button DuplicateButton;
private System.Windows.Forms.Label TimeoutLabel;
private System.Windows.Forms.TextBox TimeoutTextBox;
private System.Windows.Forms.Label PluginOptionsLabel;
private System.Windows.Forms.TextBox PluginTextBox;
private System.Windows.Forms.Label PluginLabel;
private System.Windows.Forms.TextBox PluginOptionsTextBox;
private System.Windows.Forms.CheckBox ShowPasswdCheckBox;
private System.Windows.Forms.TextBox PasswordTextBox;
private System.Windows.Forms.TextBox PluginArgumentsTextBox;
private System.Windows.Forms.Label PluginArgumentsLabel;
private System.Windows.Forms.ToolTip toolTip1;
}
}
+15
View File
@@ -46,7 +46,11 @@ namespace Shadowsocks.View
IPLabel.Text = I18N.GetString("Server Addr");
ServerPortLabel.Text = I18N.GetString("Server Port");
PasswordLabel.Text = I18N.GetString("Password");
ShowPasswdCheckBox.Text = I18N.GetString("Show Password");
EncryptionLabel.Text = I18N.GetString("Encryption");
PluginLabel.Text = I18N.GetString("Plugin Program");
PluginOptionsLabel.Text = I18N.GetString("Plugin Options");
PluginArgumentsLabel.Text = I18N.GetString("Plugin Arguments");
ProxyPortLabel.Text = I18N.GetString("Proxy Port");
RemarksLabel.Text = I18N.GetString("Remarks");
TimeoutLabel.Text = I18N.GetString("Timeout(Sec)");
@@ -94,6 +98,9 @@ namespace Shadowsocks.View
}
server.password = PasswordTextBox.Text;
server.method = EncryptionSelect.Text;
server.plugin = PluginTextBox.Text;
server.plugin_opts = PluginOptionsTextBox.Text;
server.plugin_args = PluginArgumentsTextBox.Text;
server.remarks = RemarksTextBox.Text;
if (!int.TryParse(TimeoutTextBox.Text, out server.timeout))
{
@@ -127,6 +134,9 @@ namespace Shadowsocks.View
PasswordTextBox.Text = server.password;
ProxyPortTextBox.Text = _modifiedConfiguration.localPort.ToString();
EncryptionSelect.Text = server.method ?? "aes-256-cfb";
PluginTextBox.Text = server.plugin;
PluginOptionsTextBox.Text = server.plugin_opts;
PluginArgumentsTextBox.Text = server.plugin_args;
RemarksTextBox.Text = server.remarks;
TimeoutTextBox.Text = server.timeout.ToString();
}
@@ -352,5 +362,10 @@ namespace Shadowsocks.View
MoveConfigItem(+1); // +1 means move forward
}
}
private void ShowPasswdCheckBox_CheckedChanged(object sender, EventArgs e)
{
this.PasswordTextBox.UseSystemPasswordChar = !this.ShowPasswdCheckBox.Checked;
}
}
}
+135
View File
@@ -117,4 +117,139 @@
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="tableLayoutPanel1.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="PluginOptionsLabel.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="toolTip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
<metadata name="PluginTextBox.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="RemarksTextBox.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="IPLabel.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="ServerPortLabel.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="PasswordLabel.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="IPTextBox.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="ServerPortTextBox.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="PasswordTextBox.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="EncryptionLabel.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="EncryptionSelect.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="TimeoutLabel.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="TimeoutTextBox.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="PluginLabel.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="PluginOptionsTextBox.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="ShowPasswdCheckBox.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="PluginArgumentsTextBox.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="PluginArgumentsLabel.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="toolTip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
<metadata name="RemarksLabel.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="panel2.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="OKButton.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="MyCancelButton.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="DeleteButton.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="AddButton.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="ServerGroupBox.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="ServersListBox.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="tableLayoutPanel2.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="tableLayoutPanel6.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="MoveDownButton.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="MoveUpButton.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="tableLayoutPanel5.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="ProxyPortTextBox.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="ProxyPortLabel.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="tableLayoutPanel3.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="tableLayoutPanel4.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="DuplicateButton.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="MoveDownButton.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="MoveUpButton.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="ProxyPortTextBox.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="ProxyPortLabel.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="DuplicateButton.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="$this.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
</root>
@@ -187,6 +187,10 @@ namespace Shadowsocks.View
I18N.GetString("System Proxy On: ") + (global ? I18N.GetString("Global") : I18N.GetString("PAC")) :
String.Format(I18N.GetString("Running: Port {0}"), config.localPort)) // this feedback is very important because they need to know Shadowsocks is running
+ "\n" + serverInfo;
if (text.Length > 127)
{
text = text.Substring(0, 126 - 3) + "...";
}
ViewUtils.SetNotifyIconText(_notifyIcon, text);
}
@@ -286,7 +290,7 @@ namespace Shadowsocks.View
this.proxyItem = CreateMenuItem("Forward 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)),
this.ShareOverLANItem = CreateMenuItem("Allow other Devices to connect", new EventHandler(this.ShareOverLANItem_Click)),
new MenuItem("-"),
this.hotKeyItem = CreateMenuItem("Edit Hotkeys...", new EventHandler(this.hotKeyItem_Click)),
CreateMenuGroup("Help", new MenuItem[] {
@@ -659,7 +663,7 @@ namespace Shadowsocks.View
private void QRCodeItem_Click(object sender, EventArgs e)
{
QRCodeForm qrCodeForm = new QRCodeForm(controller.GetQRCodeForCurrentServer());
QRCodeForm qrCodeForm = new QRCodeForm(controller.GetServerURLForCurrentServer());
//qrCodeForm.Icon = this.Icon;
// TODO
qrCodeForm.Show();
@@ -707,7 +711,7 @@ namespace Shadowsocks.View
{
splash.FormClosed += splash_FormClosed;
}
else if (result.Text.StartsWith("http://") || result.Text.StartsWith("https://"))
else if (result.Text.ToLower().StartsWith("http://") || result.Text.ToLower().StartsWith("https://"))
{
_urlToOpen = result.Text;
splash.FormClosed += openURLFromQRCode;
@@ -738,7 +742,7 @@ namespace Shadowsocks.View
splash.Location = new Point(screen.Bounds.X, screen.Bounds.Y);
// we need a panel because a window has a minimal size
// TODO: test on high DPI
splash.TargetRect = new Rectangle((int)minX + screen.Bounds.X, (int)minY + screen.Bounds.Y, (int)maxX - (int)minX, (int)maxY - (int)minY);
splash.TargetRect = new Rectangle((int)minX, (int)minY, (int)maxX - (int)minX, (int)maxY - (int)minY);
splash.Size = new Size(fullImage.Width, fullImage.Height);
splash.Show();
return;
+79 -112
View File
@@ -28,70 +28,27 @@
/// </summary>
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.ProxyPortLabel = new System.Windows.Forms.Label();
this.ProxyPortTextBox = new System.Windows.Forms.TextBox();
this.tableLayoutPanel4 = new System.Windows.Forms.TableLayoutPanel();
this.ProxyTypeLabel = new System.Windows.Forms.Label();
this.ProxyTypeComboBox = new System.Windows.Forms.ComboBox();
this.ProxyTimeoutTextBox = new System.Windows.Forms.TextBox();
this.ProxyTimeoutLabel = new System.Windows.Forms.Label();
this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
this.ProxyNotificationLabel = new System.Windows.Forms.Label();
this.flowLayoutPanel1 = new System.Windows.Forms.FlowLayoutPanel();
this.tableLayoutPanel1.SuspendLayout();
this.tableLayoutPanel3.SuspendLayout();
this.tableLayoutPanel2.SuspendLayout();
this.tableLayoutPanel4.SuspendLayout();
this.flowLayoutPanel1.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, 3);
this.tableLayoutPanel1.Controls.Add(this.UseProxyCheckBox, 0, 0);
this.tableLayoutPanel1.Controls.Add(this.tableLayoutPanel2, 0, 2);
this.tableLayoutPanel1.Controls.Add(this.tableLayoutPanel4, 0, 1);
this.tableLayoutPanel1.Location = new System.Drawing.Point(15, 15);
this.tableLayoutPanel1.Name = "tableLayoutPanel1";
this.tableLayoutPanel1.RowCount = 4;
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.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel1.Size = new System.Drawing.Size(395, 123);
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, 94);
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";
@@ -104,7 +61,6 @@
// 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";
@@ -117,6 +73,7 @@
// UseProxyCheckBox
//
this.UseProxyCheckBox.AutoSize = true;
this.tableLayoutPanel1.SetColumnSpan(this.UseProxyCheckBox, 2);
this.UseProxyCheckBox.Location = new System.Drawing.Point(3, 3);
this.UseProxyCheckBox.Name = "UseProxyCheckBox";
this.UseProxyCheckBox.Size = new System.Drawing.Size(78, 16);
@@ -125,31 +82,11 @@
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.ProxyPortLabel, 2, 0);
this.tableLayoutPanel2.Controls.Add(this.ProxyPortTextBox, 3, 0);
this.tableLayoutPanel2.Location = new System.Drawing.Point(3, 61);
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.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 27F));
this.tableLayoutPanel2.Size = new System.Drawing.Size(389, 27);
this.tableLayoutPanel2.TabIndex = 1;
//
// ProxyAddrLabel
//
this.ProxyAddrLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right)));
this.ProxyAddrLabel.AutoSize = true;
this.ProxyAddrLabel.Location = new System.Drawing.Point(3, 7);
this.ProxyAddrLabel.Location = new System.Drawing.Point(3, 71);
this.ProxyAddrLabel.Name = "ProxyAddrLabel";
this.ProxyAddrLabel.Size = new System.Drawing.Size(65, 12);
this.ProxyAddrLabel.TabIndex = 0;
@@ -158,10 +95,10 @@
// ProxyServerTextBox
//
this.ProxyServerTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right)));
this.ProxyServerTextBox.Location = new System.Drawing.Point(74, 3);
this.ProxyServerTextBox.Location = new System.Drawing.Point(74, 67);
this.ProxyServerTextBox.MaxLength = 512;
this.ProxyServerTextBox.Name = "ProxyServerTextBox";
this.ProxyServerTextBox.Size = new System.Drawing.Size(135, 21);
this.ProxyServerTextBox.Size = new System.Drawing.Size(142, 21);
this.ProxyServerTextBox.TabIndex = 1;
this.ProxyServerTextBox.WordWrap = false;
//
@@ -169,46 +106,27 @@
//
this.ProxyPortLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right)));
this.ProxyPortLabel.AutoSize = true;
this.ProxyPortLabel.Location = new System.Drawing.Point(215, 7);
this.ProxyPortLabel.Location = new System.Drawing.Point(222, 71);
this.ProxyPortLabel.Name = "ProxyPortLabel";
this.ProxyPortLabel.Size = new System.Drawing.Size(65, 12);
this.ProxyPortLabel.Size = new System.Drawing.Size(77, 12);
this.ProxyPortLabel.TabIndex = 2;
this.ProxyPortLabel.Text = "Proxy Port";
//
// ProxyPortTextBox
//
this.ProxyPortTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right)));
this.ProxyPortTextBox.Location = new System.Drawing.Point(286, 3);
this.ProxyPortTextBox.Location = new System.Drawing.Point(305, 67);
this.ProxyPortTextBox.MaxLength = 10;
this.ProxyPortTextBox.Name = "ProxyPortTextBox";
this.ProxyPortTextBox.Size = new System.Drawing.Size(100, 21);
this.ProxyPortTextBox.Size = new System.Drawing.Size(58, 21);
this.ProxyPortTextBox.TabIndex = 3;
this.ProxyPortTextBox.WordWrap = false;
//
// tableLayoutPanel4
//
this.tableLayoutPanel4.AutoSize = true;
this.tableLayoutPanel4.ColumnCount = 4;
this.tableLayoutPanel4.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel4.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel4.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel4.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel4.Controls.Add(this.ProxyTypeLabel, 0, 0);
this.tableLayoutPanel4.Controls.Add(this.ProxyTypeComboBox, 1, 0);
this.tableLayoutPanel4.Controls.Add(this.ProxyTimeoutTextBox, 3, 0);
this.tableLayoutPanel4.Controls.Add(this.ProxyTimeoutLabel, 2, 0);
this.tableLayoutPanel4.Location = new System.Drawing.Point(3, 25);
this.tableLayoutPanel4.Name = "tableLayoutPanel4";
this.tableLayoutPanel4.RowCount = 1;
this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel4.Size = new System.Drawing.Size(387, 30);
this.tableLayoutPanel4.TabIndex = 10;
//
// ProxyTypeLabel
//
this.ProxyTypeLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right)));
this.ProxyTypeLabel.AutoSize = true;
this.ProxyTypeLabel.Location = new System.Drawing.Point(3, 9);
this.ProxyTypeLabel.Location = new System.Drawing.Point(3, 40);
this.ProxyTypeLabel.Name = "ProxyTypeLabel";
this.ProxyTypeLabel.Size = new System.Drawing.Size(65, 12);
this.ProxyTypeLabel.TabIndex = 1;
@@ -222,30 +140,86 @@
this.ProxyTypeComboBox.Items.AddRange(new object[] {
"SOCKS5",
"HTTP"});
this.ProxyTypeComboBox.Location = new System.Drawing.Point(74, 5);
this.ProxyTypeComboBox.Location = new System.Drawing.Point(74, 36);
this.ProxyTypeComboBox.Margin = new System.Windows.Forms.Padding(3, 5, 3, 5);
this.ProxyTypeComboBox.Name = "ProxyTypeComboBox";
this.ProxyTypeComboBox.Size = new System.Drawing.Size(121, 20);
this.ProxyTypeComboBox.Size = new System.Drawing.Size(142, 20);
this.ProxyTypeComboBox.TabIndex = 2;
//
// ProxyTimeoutTextBox
//
this.ProxyTimeoutTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right)));
this.ProxyTimeoutTextBox.Location = new System.Drawing.Point(284, 4);
this.ProxyTimeoutTextBox.Location = new System.Drawing.Point(305, 36);
this.ProxyTimeoutTextBox.Name = "ProxyTimeoutTextBox";
this.ProxyTimeoutTextBox.Size = new System.Drawing.Size(100, 21);
this.ProxyTimeoutTextBox.Size = new System.Drawing.Size(58, 21);
this.ProxyTimeoutTextBox.TabIndex = 3;
//
// ProxyTimeoutLabel
//
this.ProxyTimeoutLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right)));
this.ProxyTimeoutLabel.AutoSize = true;
this.ProxyTimeoutLabel.Location = new System.Drawing.Point(201, 9);
this.ProxyTimeoutLabel.Location = new System.Drawing.Point(222, 40);
this.ProxyTimeoutLabel.Name = "ProxyTimeoutLabel";
this.ProxyTimeoutLabel.Size = new System.Drawing.Size(77, 12);
this.ProxyTimeoutLabel.TabIndex = 4;
this.ProxyTimeoutLabel.Text = "Timeout(Sec)";
//
// tableLayoutPanel1
//
this.tableLayoutPanel1.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
this.tableLayoutPanel1.ColumnCount = 4;
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 70F));
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 30F));
this.tableLayoutPanel1.Controls.Add(this.UseProxyCheckBox, 0, 0);
this.tableLayoutPanel1.Controls.Add(this.ProxyTypeLabel, 0, 1);
this.tableLayoutPanel1.Controls.Add(this.ProxyPortTextBox, 3, 2);
this.tableLayoutPanel1.Controls.Add(this.ProxyTypeComboBox, 1, 1);
this.tableLayoutPanel1.Controls.Add(this.ProxyTimeoutLabel, 2, 1);
this.tableLayoutPanel1.Controls.Add(this.ProxyPortLabel, 2, 2);
this.tableLayoutPanel1.Controls.Add(this.ProxyTimeoutTextBox, 3, 1);
this.tableLayoutPanel1.Controls.Add(this.ProxyServerTextBox, 1, 2);
this.tableLayoutPanel1.Controls.Add(this.ProxyAddrLabel, 0, 2);
this.tableLayoutPanel1.Controls.Add(this.ProxyNotificationLabel, 0, 3);
this.tableLayoutPanel1.Controls.Add(this.flowLayoutPanel1, 0, 4);
this.tableLayoutPanel1.Location = new System.Drawing.Point(15, 15);
this.tableLayoutPanel1.Name = "tableLayoutPanel1";
this.tableLayoutPanel1.RowCount = 5;
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 21.95122F));
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 21.95122F));
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 21.95122F));
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 34.14634F));
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel1.Size = new System.Drawing.Size(366, 177);
this.tableLayoutPanel1.TabIndex = 14;
//
// ProxyNotificationLabel
//
this.ProxyNotificationLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right)));
this.ProxyNotificationLabel.AutoSize = true;
this.tableLayoutPanel1.SetColumnSpan(this.ProxyNotificationLabel, 4);
this.ProxyNotificationLabel.ForeColor = System.Drawing.Color.Red;
this.ProxyNotificationLabel.Location = new System.Drawing.Point(3, 111);
this.ProxyNotificationLabel.Name = "ProxyNotificationLabel";
this.ProxyNotificationLabel.Size = new System.Drawing.Size(360, 12);
this.ProxyNotificationLabel.TabIndex = 5;
this.ProxyNotificationLabel.Text = "If server has a plugin, proxy will not be used";
//
// flowLayoutPanel1
//
this.flowLayoutPanel1.AutoSize = true;
this.flowLayoutPanel1.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
this.tableLayoutPanel1.SetColumnSpan(this.flowLayoutPanel1, 4);
this.flowLayoutPanel1.Controls.Add(this.MyCancelButton);
this.flowLayoutPanel1.Controls.Add(this.OKButton);
this.flowLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Right;
this.flowLayoutPanel1.FlowDirection = System.Windows.Forms.FlowDirection.RightToLeft;
this.flowLayoutPanel1.Location = new System.Drawing.Point(204, 145);
this.flowLayoutPanel1.Name = "flowLayoutPanel1";
this.flowLayoutPanel1.Size = new System.Drawing.Size(159, 29);
this.flowLayoutPanel1.TabIndex = 6;
//
// ProxyForm
//
this.AcceptButton = this.OKButton;
@@ -254,7 +228,7 @@
this.AutoSize = true;
this.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
this.CancelButton = this.MyCancelButton;
this.ClientSize = new System.Drawing.Size(441, 165);
this.ClientSize = new System.Drawing.Size(448, 231);
this.Controls.Add(this.tableLayoutPanel1);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
this.MaximizeBox = false;
@@ -266,32 +240,25 @@
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.tableLayoutPanel4.ResumeLayout(false);
this.tableLayoutPanel4.PerformLayout();
this.flowLayoutPanel1.ResumeLayout(false);
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 ProxyPortLabel;
private System.Windows.Forms.TextBox ProxyPortTextBox;
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel3;
private System.Windows.Forms.Button MyCancelButton;
private System.Windows.Forms.Button OKButton;
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel4;
private System.Windows.Forms.Label ProxyTypeLabel;
private System.Windows.Forms.ComboBox ProxyTypeComboBox;
private System.Windows.Forms.TextBox ProxyTimeoutTextBox;
private System.Windows.Forms.Label ProxyTimeoutLabel;
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
private System.Windows.Forms.Label ProxyNotificationLabel;
private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel1;
}
}
+25 -30
View File
@@ -12,7 +12,7 @@ namespace Shadowsocks.View
private ShadowsocksController controller;
// this is a copy of configuration that we are working on
private ProxyConfig _modifiedConfiguration;
private ProxyConfig _modifiedProxyConfig;
public ProxyForm(ShadowsocksController controller)
{
@@ -36,6 +36,7 @@ namespace Shadowsocks.View
ProxyAddrLabel.Text = I18N.GetString("Proxy Addr");
ProxyPortLabel.Text = I18N.GetString("Proxy Port");
ProxyTimeoutLabel.Text = I18N.GetString("Timeout(Sec)");
ProxyNotificationLabel.Text = I18N.GetString("If server has a plugin, proxy will not be used");
OKButton.Text = I18N.GetString("OK");
MyCancelButton.Text = I18N.GetString("Cancel");
this.Text = I18N.GetString("Edit Proxy");
@@ -48,53 +49,47 @@ namespace Shadowsocks.View
private void LoadCurrentConfiguration()
{
_modifiedConfiguration = controller.GetConfigurationCopy().proxy;
UseProxyCheckBox.Checked = _modifiedConfiguration.useProxy;
ProxyServerTextBox.Text = _modifiedConfiguration.proxyServer;
ProxyPortTextBox.Text = _modifiedConfiguration.proxyPort.ToString();
ProxyTimeoutTextBox.Text = _modifiedConfiguration.proxyTimeout.ToString();
ProxyTypeComboBox.SelectedIndex = _modifiedConfiguration.proxyType;
_modifiedProxyConfig = controller.GetConfigurationCopy().proxy;
UseProxyCheckBox.Checked = _modifiedProxyConfig.useProxy;
ProxyServerTextBox.Text = _modifiedProxyConfig.proxyServer;
ProxyPortTextBox.Text = _modifiedProxyConfig.proxyPort.ToString();
ProxyTimeoutTextBox.Text = _modifiedProxyConfig.proxyTimeout.ToString();
ProxyTypeComboBox.SelectedIndex = _modifiedProxyConfig.proxyType;
}
private void OKButton_Click(object sender, EventArgs e)
{
if (UseProxyCheckBox.Checked)
if (_modifiedProxyConfig.useProxy=UseProxyCheckBox.Checked)
{
int port;
int timeout;
if (!int.TryParse(ProxyPortTextBox.Text, out port))
if (!int.TryParse(ProxyPortTextBox.Text, out _modifiedProxyConfig.proxyPort))
{
MessageBox.Show(I18N.GetString("Illegal port number format"));
return;
}
if (!int.TryParse(ProxyTimeoutTextBox.Text, out timeout))
if (!int.TryParse(ProxyTimeoutTextBox.Text, out _modifiedProxyConfig.proxyTimeout))
{
MessageBox.Show(I18N.GetString("Illegal timeout format"));
return;
}
var type = ProxyTypeComboBox.SelectedIndex;
var proxy = ProxyServerTextBox.Text;
_modifiedProxyConfig.proxyType = ProxyTypeComboBox.SelectedIndex;
try
{
Configuration.CheckServer(proxy);
Configuration.CheckPort(port);
Configuration.CheckTimeout(timeout, ProxyConfig.MaxProxyTimeoutSec);
Configuration.CheckServer(_modifiedProxyConfig.proxyServer = ProxyServerTextBox.Text);
Configuration.CheckPort(_modifiedProxyConfig.proxyPort);
Configuration.CheckTimeout(_modifiedProxyConfig.proxyTimeout, ProxyConfig.MaxProxyTimeoutSec);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
return;
}
}
controller.EnableProxy(type, proxy, port, timeout);
}
else
{
controller.DisableProxy();
}
controller.SaveProxy(_modifiedProxyConfig);
this.Close();
}
@@ -118,17 +113,17 @@ namespace Shadowsocks.View
{
if (UseProxyCheckBox.Checked)
{
ProxyServerTextBox.Enabled = true;
ProxyPortTextBox.Enabled = true;
ProxyTimeoutTextBox.Enabled = true;
ProxyServerTextBox.Enabled =
ProxyPortTextBox.Enabled =
ProxyTimeoutTextBox.Enabled =
ProxyTypeComboBox.Enabled = true;
}
else
{
ProxyServerTextBox.Enabled = false;
ProxyPortTextBox.Enabled = false;
ProxyTimeoutTextBox.Enabled = false;
ProxyTypeComboBox.Enabled = false;
ProxyServerTextBox.Enabled =
ProxyPortTextBox.Enabled =
ProxyTimeoutTextBox.Enabled =
ProxyTypeComboBox.Enabled = false;
}
}
}
+1 -1
View File
@@ -67,7 +67,7 @@ namespace Shadowsocks.View
var servers = Configuration.Load();
var serverDatas = servers.configs.Select(
server =>
new KeyValuePair<string, string>(ShadowsocksController.GetQRCode(server), server.FriendlyName())
new KeyValuePair<string, string>(ShadowsocksController.GetServerURL(server), server.FriendlyName())
).ToList();
listBox1.DataSource = serverDatas;
+65 -84
View File
@@ -12,12 +12,13 @@ using System.Diagnostics;
namespace Shadowsocks.View
{
public class QRCodeSplashForm : PerPixelAlphaForm
public class QRCodeSplashForm : Form
{
public Rectangle TargetRect;
public QRCodeSplashForm()
{
FormBorderStyle = FormBorderStyle.None;
this.Load += QRCodeSplashForm_Load;
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None;
this.BackColor = System.Drawing.Color.White;
@@ -69,16 +70,6 @@ namespace Shadowsocks.View
brush = new SolidBrush(Color.FromArgb(30, Color.Red));
}
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.ExStyle |= 0x00080000; // This form has to have the WS_EX_LAYERED extended style
return cp;
}
}
void timer_Tick(object sender, EventArgs e)
{
double percent = (double)sw.ElapsedMilliseconds / 1000.0 / (double)ANIMATION_TIME;
@@ -148,6 +139,69 @@ namespace Shadowsocks.View
flashStep++;
}
}
// PerPixelAlphaForm.cs
// http://www.codeproject.com/Articles/1822/Per-Pixel-Alpha-Blend-in-C
// Rui Lopes
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.ExStyle |= 0x00080000; // This form has to have the WS_EX_LAYERED extended style
return cp;
}
}
public void SetBitmap(Bitmap bitmap)
{
SetBitmap(bitmap, 255);
}
/// <para>Changes the current bitmap with a custom opacity level. Here is where all happens!</para>
public void SetBitmap(Bitmap bitmap, byte opacity)
{
if (bitmap.PixelFormat != PixelFormat.Format32bppArgb)
throw new ApplicationException("The bitmap must be 32ppp with alpha-channel.");
// The idea of this is very simple,
// 1. Create a compatible DC with screen;
// 2. Select the bitmap with 32bpp with alpha-channel in the compatible DC;
// 3. Call the UpdateLayeredWindow.
IntPtr screenDc = Win32.GetDC(IntPtr.Zero);
IntPtr memDc = Win32.CreateCompatibleDC(screenDc);
IntPtr hBitmap = IntPtr.Zero;
IntPtr oldBitmap = IntPtr.Zero;
try
{
hBitmap = bitmap.GetHbitmap(Color.FromArgb(0)); // grab a GDI handle from this GDI+ bitmap
oldBitmap = Win32.SelectObject(memDc, hBitmap);
Win32.Size size = new Win32.Size(bitmap.Width, bitmap.Height);
Win32.Point pointSource = new Win32.Point(0, 0);
Win32.Point topPos = new Win32.Point(Left, Top);
Win32.BLENDFUNCTION blend = new Win32.BLENDFUNCTION();
blend.BlendOp = Win32.AC_SRC_OVER;
blend.BlendFlags = 0;
blend.SourceConstantAlpha = opacity;
blend.AlphaFormat = Win32.AC_SRC_ALPHA;
Win32.UpdateLayeredWindow(Handle, screenDc, ref topPos, ref size, memDc, ref pointSource, 0, ref blend, Win32.ULW_ALPHA);
}
finally
{
Win32.ReleaseDC(IntPtr.Zero, screenDc);
if (hBitmap != IntPtr.Zero)
{
Win32.SelectObject(memDc, oldBitmap);
//Windows.DeleteObject(hBitmap); // The documentation says that we have to use the Windows.DeleteObject... but since there is no such method I use the normal DeleteObject from Win32 GDI and it's working fine without any resource leak.
Win32.DeleteObject(hBitmap);
}
Win32.DeleteDC(memDc);
}
}
}
@@ -224,77 +278,4 @@ namespace Shadowsocks.View
[DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)]
public static extern int DeleteObject(IntPtr hObject);
}
public class PerPixelAlphaForm : Form
{
// http://www.codeproject.com/Articles/1822/Per-Pixel-Alpha-Blend-in-C
// Rui Lopes
public PerPixelAlphaForm()
{
// This form should not have a border or else Windows will clip it.
FormBorderStyle = FormBorderStyle.None;
}
public void SetBitmap(Bitmap bitmap)
{
SetBitmap(bitmap, 255);
}
/// <para>Changes the current bitmap with a custom opacity level. Here is where all happens!</para>
public void SetBitmap(Bitmap bitmap, byte opacity)
{
if (bitmap.PixelFormat != PixelFormat.Format32bppArgb)
throw new ApplicationException("The bitmap must be 32ppp with alpha-channel.");
// The idea of this is very simple,
// 1. Create a compatible DC with screen;
// 2. Select the bitmap with 32bpp with alpha-channel in the compatible DC;
// 3. Call the UpdateLayeredWindow.
IntPtr screenDc = Win32.GetDC(IntPtr.Zero);
IntPtr memDc = Win32.CreateCompatibleDC(screenDc);
IntPtr hBitmap = IntPtr.Zero;
IntPtr oldBitmap = IntPtr.Zero;
try
{
hBitmap = bitmap.GetHbitmap(Color.FromArgb(0)); // grab a GDI handle from this GDI+ bitmap
oldBitmap = Win32.SelectObject(memDc, hBitmap);
Win32.Size size = new Win32.Size(bitmap.Width, bitmap.Height);
Win32.Point pointSource = new Win32.Point(0, 0);
Win32.Point topPos = new Win32.Point(Left, Top);
Win32.BLENDFUNCTION blend = new Win32.BLENDFUNCTION();
blend.BlendOp = Win32.AC_SRC_OVER;
blend.BlendFlags = 0;
blend.SourceConstantAlpha = opacity;
blend.AlphaFormat = Win32.AC_SRC_ALPHA;
Win32.UpdateLayeredWindow(Handle, screenDc, ref topPos, ref size, memDc, ref pointSource, 0, ref blend, Win32.ULW_ALPHA);
}
finally
{
Win32.ReleaseDC(IntPtr.Zero, screenDc);
if (hBitmap != IntPtr.Zero)
{
Win32.SelectObject(memDc, oldBitmap);
//Windows.DeleteObject(hBitmap); // The documentation says that we have to use the Windows.DeleteObject... but since there is no such method I use the normal DeleteObject from Win32 GDI and it's working fine without any resource leak.
Win32.DeleteObject(hBitmap);
}
Win32.DeleteDC(memDc);
}
}
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.ExStyle |= 0x00080000; // This form has to have the WS_EX_LAYERED extended style
return cp;
}
}
}
}
+45
View File
@@ -39,4 +39,49 @@
</setting>
</Shadowsocks.Properties.Settings>
</userSettings>
<!-- Uncomment to dump network tracing info
<system.diagnostics>
<sources>
<source name="System.Net" tracemode="includehex" maxdatasize="1024">
<listeners>
<add name="System.Net"/>
</listeners>
</source>
<source name="System.Net.Cache">
<listeners>
<add name="System.Net"/>
</listeners>
</source>
<source name="System.Net.Http">
<listeners>
<add name="System.Net"/>
</listeners>
</source>
<source name="System.Net.Sockets">
<listeners>
<add name="System.Net"/>
</listeners>
</source>
<source name="System.Net.WebSockets">
<listeners>
<add name="System.Net"/>
</listeners>
</source>
</sources>
<switches>
<add name="System.Net" value="Verbose"/>
<add name="System.Net.Cache" value="Verbose"/>
<add name="System.Net.Http" value="Verbose"/>
<add name="System.Net.Sockets" value="Verbose"/>
<add name="System.Net.WebSockets" value="Verbose"/>
</switches>
<sharedListeners>
<add name="System.Net"
type="System.Diagnostics.TextWriterTraceListener"
initializeData="network-tracing.log"
/>
</sharedListeners>
<trace autoflush="true"/>
</system.diagnostics>
-->
</configuration>
+5 -5
View File
@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Caseless.Fody" version="1.5.0" targetFramework="net462" developmentDependency="true" />
<package id="Costura.Fody" version="1.4.1" targetFramework="net462" developmentDependency="true" />
<package id="Fody" version="2.0.9" targetFramework="net462" developmentDependency="true" />
<package id="Caseless.Fody" version="1.7.3" targetFramework="net462" developmentDependency="true" />
<package id="Costura.Fody" version="1.6.2" targetFramework="net462" developmentDependency="true" />
<package id="Fody" version="2.3.23" targetFramework="net462" developmentDependency="true" />
<package id="GlobalHotKey" version="1.1.0" targetFramework="net462" />
<package id="Newtonsoft.Json" version="10.0.2" targetFramework="net462" />
<package id="Newtonsoft.Json" version="10.0.3" targetFramework="net462" />
<package id="StringEx.CS" version="0.3.1" targetFramework="net462" developmentDependency="true" />
<package id="ZXing.Net" version="0.15.0" targetFramework="net462" />
<package id="ZXing.Net" version="0.16.2" targetFramework="net462" />
</packages>
+23 -10
View File
@@ -23,6 +23,8 @@
<OldToolsVersion>3.5</OldToolsVersion>
<TargetFrameworkProfile>
</TargetFrameworkProfile>
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
<PublishUrl>publish\</PublishUrl>
<Install>true</Install>
<InstallFrom>Disk</InstallFrom>
@@ -37,8 +39,6 @@
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
<UseApplicationTrust>false</UseApplicationTrust>
<BootstrapperEnabled>true</BootstrapperEnabled>
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
<DebugSymbols>true</DebugSymbols>
@@ -66,6 +66,13 @@
<ApplicationManifest>app.manifest</ApplicationManifest>
</PropertyGroup>
<ItemGroup>
<Reference Include="Caseless, Version=0.0.0.0, Culture=neutral, PublicKeyToken=409b3227471b0f0d, processorArchitecture=MSIL">
<HintPath>3rd\Caseless.Fody.1.7.3\lib\net452\Caseless.dll</HintPath>
</Reference>
<Reference Include="Costura, Version=1.6.2.0, Culture=neutral, PublicKeyToken=9919ef960d84173d, processorArchitecture=MSIL">
<HintPath>3rd\Costura.Fody.1.6.2\lib\dotnet\Costura.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="GlobalHotKey, Version=1.1.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>3rd\GlobalHotKey.1.1.0\lib\GlobalHotKey.dll</HintPath>
<Private>True</Private>
@@ -73,7 +80,7 @@
<Reference Include="Microsoft.CSharp" />
<Reference Include="Microsoft.VisualBasic" />
<Reference Include="Newtonsoft.Json, Version=10.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>3rd\Newtonsoft.Json.10.0.2\lib\net45\Newtonsoft.Json.dll</HintPath>
<HintPath>3rd\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Data" />
@@ -85,17 +92,18 @@
<Reference Include="System.Windows.Forms.DataVisualization" />
<Reference Include="System.XML" />
<Reference Include="WindowsBase" />
<Reference Include="zxing, Version=0.15.0.0, Culture=neutral, PublicKeyToken=4e88037ac681fe60, processorArchitecture=MSIL">
<HintPath>3rd\ZXing.Net.0.15.0\lib\net461\zxing.dll</HintPath>
<Reference Include="zxing, Version=0.16.2.0, Culture=neutral, PublicKeyToken=4e88037ac681fe60, processorArchitecture=MSIL">
<HintPath>3rd\ZXing.Net.0.16.2\lib\net461\zxing.dll</HintPath>
</Reference>
<Reference Include="zxing.presentation, Version=0.15.0.0, Culture=neutral, PublicKeyToken=4e88037ac681fe60, processorArchitecture=MSIL">
<HintPath>3rd\ZXing.Net.0.15.0\lib\net461\zxing.presentation.dll</HintPath>
<Reference Include="zxing.presentation, Version=0.16.2.0, Culture=neutral, PublicKeyToken=4e88037ac681fe60, processorArchitecture=MSIL">
<HintPath>3rd\ZXing.Net.0.16.2\lib\net461\zxing.presentation.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="Controller\System\Hotkeys\HotkeyCallbacks.cs" />
<Compile Include="Encryption\AEAD\AEADEncryptor.cs" />
<Compile Include="Encryption\AEAD\AEADMbedTLSEncryptor.cs" />
<Compile Include="Encryption\AEAD\AEADOpenSSLEncryptor.cs" />
<Compile Include="Encryption\AEAD\AEADSodiumEncryptor.cs" />
<Compile Include="Encryption\CircularBuffer\ByteCircularBuffer.cs" />
<Compile Include="Encryption\EncryptorBase.cs" />
@@ -103,10 +111,12 @@
<Compile Include="Encryption\Exception\CryptoException.cs" />
<Compile Include="Encryption\IEncryptor.cs" />
<Compile Include="Encryption\MbedTLS.cs" />
<Compile Include="Encryption\OpenSSL.cs" />
<Compile Include="Encryption\RNG.cs" />
<Compile Include="Encryption\Sodium.cs" />
<Compile Include="Encryption\Stream\StreamEncryptor.cs" />
<Compile Include="Encryption\Stream\StreamMbedTLSEncryptor.cs" />
<Compile Include="Encryption\Stream\StreamOpenSSLEncryptor.cs" />
<Compile Include="Encryption\Stream\StreamSodiumEncryptor.cs" />
<Compile Include="Model\HotKeyConfig.cs" />
<Compile Include="Model\ProxyConfig.cs" />
@@ -145,6 +155,7 @@
<Compile Include="Controller\Strategy\BalancingStrategy.cs" />
<Compile Include="Controller\Strategy\StrategyManager.cs" />
<Compile Include="Controller\Strategy\IStrategy.cs" />
<Compile Include="Controller\Service\Sip003Plugin.cs" />
<Compile Include="Proxy\Socks5Proxy.cs" />
<Compile Include="Settings.cs" />
<Compile Include="StringEx.cs" />
@@ -341,13 +352,15 @@ foreach (var item in filesToCleanup)
<Target Name="CleanReferenceCopyLocalPaths" AfterTargets="AfterBuild;NonWinFodyTarget">
<CosturaCleanup Config="FodyWeavers.xml" Files="@(ReferenceCopyLocalPaths->'$(OutDir)%(DestinationSubDirectory)%(Filename)%(Extension)')" />
</Target>
<Import Project="3rd\Fody.2.0.9\build\netstandard1.4\Fody.targets" Condition="Exists('3rd\Fody.2.0.9\build\netstandard1.4\Fody.targets')" />
<Import Project="3rd\Fody.2.3.23\build\Fody.targets" Condition="Exists('3rd\Fody.2.3.23\build\Fody.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>此项目引用这台计算机上缺少的 NuGet 程序包。使用 NuGet 程序包还原可下载这些程序包。有关详细信息,请参阅 http://go.microsoft.com/fwlink/?LinkID=322105。缺少的文件是 {0}。</ErrorText>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('3rd\Fody.2.0.9\build\netstandard1.4\Fody.targets')" Text="$([System.String]::Format('$(ErrorText)', '3rd\Fody.2.0.9\build\netstandard1.4\Fody.targets'))" />
<Error Condition="!Exists('3rd\Fody.2.3.23\build\Fody.targets')" Text="$([System.String]::Format('$(ErrorText)', '3rd\Fody.2.3.23\build\Fody.targets'))" />
<Error Condition="!Exists('3rd\Costura.Fody.1.6.2\build\dotnet\Costura.Fody.targets')" Text="$([System.String]::Format('$(ErrorText)', '3rd\Costura.Fody.1.6.2\build\dotnet\Costura.Fody.targets'))" />
</Target>
<Import Project="3rd\Costura.Fody.1.6.2\build\dotnet\Costura.Fody.targets" Condition="Exists('3rd\Costura.Fody.1.6.2\build\dotnet\Costura.Fody.targets')" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
+264 -7
View File
@@ -8,6 +8,7 @@ using System.Threading;
using System.Collections.Generic;
using Shadowsocks.Controller.Hotkeys;
using Shadowsocks.Encryption.Stream;
using Shadowsocks.Model;
namespace test
{
@@ -26,12 +27,13 @@ namespace test
Assert.IsTrue(UpdateChecker.Asset.CompareVersion("1.3.2", "1.3.1") > 0);
}
[ TestMethod ]
public void TestHotKey2Str() {
Assert.AreEqual( "Ctrl+A", HotKeys.HotKey2Str( Key.A, ModifierKeys.Control ) );
Assert.AreEqual( "Ctrl+Alt+D2", HotKeys.HotKey2Str( Key.D2, (ModifierKeys.Alt | ModifierKeys.Control) ) );
Assert.AreEqual("Ctrl+Alt+Shift+NumPad7", HotKeys.HotKey2Str(Key.NumPad7, (ModifierKeys.Alt|ModifierKeys.Control|ModifierKeys.Shift)));
Assert.AreEqual( "Ctrl+Alt+Shift+F6", HotKeys.HotKey2Str( Key.F6, (ModifierKeys.Alt|ModifierKeys.Control|ModifierKeys.Shift)));
[TestMethod]
public void TestHotKey2Str()
{
Assert.AreEqual("Ctrl+A", HotKeys.HotKey2Str(Key.A, ModifierKeys.Control));
Assert.AreEqual("Ctrl+Alt+D2", HotKeys.HotKey2Str(Key.D2, (ModifierKeys.Alt | ModifierKeys.Control)));
Assert.AreEqual("Ctrl+Alt+Shift+NumPad7", HotKeys.HotKey2Str(Key.NumPad7, (ModifierKeys.Alt | ModifierKeys.Control | ModifierKeys.Shift)));
Assert.AreEqual("Ctrl+Alt+Shift+F6", HotKeys.HotKey2Str(Key.F6, (ModifierKeys.Alt | ModifierKeys.Control | ModifierKeys.Shift)));
Assert.AreNotEqual("Ctrl+Shift+Alt+F6", HotKeys.HotKey2Str(Key.F6, (ModifierKeys.Alt | ModifierKeys.Control | ModifierKeys.Shift)));
}
@@ -41,7 +43,7 @@ namespace test
Assert.IsTrue(HotKeys.Str2HotKey("Ctrl+A").Equals(new HotKey(Key.A, ModifierKeys.Control)));
Assert.IsTrue(HotKeys.Str2HotKey("Ctrl+Alt+A").Equals(new HotKey(Key.A, (ModifierKeys.Control | ModifierKeys.Alt))));
Assert.IsTrue(HotKeys.Str2HotKey("Ctrl+Shift+A").Equals(new HotKey(Key.A, (ModifierKeys.Control | ModifierKeys.Shift))));
Assert.IsTrue(HotKeys.Str2HotKey("Ctrl+Alt+Shift+A").Equals(new HotKey(Key.A, (ModifierKeys.Control | ModifierKeys.Alt| ModifierKeys.Shift))));
Assert.IsTrue(HotKeys.Str2HotKey("Ctrl+Alt+Shift+A").Equals(new HotKey(Key.A, (ModifierKeys.Control | ModifierKeys.Alt | ModifierKeys.Shift))));
HotKey testKey0 = HotKeys.Str2HotKey("Ctrl+Alt+Shift+A");
Assert.IsTrue(testKey0 != null && testKey0.Equals(new HotKey(Key.A, (ModifierKeys.Control | ModifierKeys.Alt | ModifierKeys.Shift))));
HotKey testKey1 = HotKeys.Str2HotKey("Ctrl+Alt+Shift+F2");
@@ -224,5 +226,260 @@ namespace test
throw;
}
}
[TestMethod]
public void TestOpenSSLEncryption()
{
// run it once before the multi-threading test to initialize global tables
RunSingleOpenSSLEncryptionThread();
List<Thread> threads = new List<Thread>();
for (int i = 0; i < 10; i++)
{
Thread t = new Thread(new ThreadStart(RunSingleOpenSSLEncryptionThread));
threads.Add(t);
t.Start();
}
foreach (Thread t in threads)
{
t.Join();
}
RNG.Close();
Assert.IsFalse(encryptionFailed);
}
private void RunSingleOpenSSLEncryptionThread()
{
try
{
for (int i = 0; i < 100; i++)
{
var random = new Random();
IEncryptor encryptor;
IEncryptor decryptor;
encryptor = new StreamOpenSSLEncryptor("aes-256-cfb", "barfoo!");
decryptor = new StreamOpenSSLEncryptor("aes-256-cfb", "barfoo!");
RunEncryptionRound(encryptor, decryptor);
}
}
catch
{
encryptionFailed = true;
throw;
}
}
[TestMethod]
public void ParseAndGenerateShadowsocksUrl()
{
var server = new Server
{
server = "192.168.100.1",
server_port = 8888,
password = "test",
method = "bf-cfb"
};
var serverCanonUrl = "ss://YmYtY2ZiOnRlc3RAMTkyLjE2OC4xMDAuMTo4ODg4";
var server2 = new Server
{
server = "192.168.1.1",
server_port = 8388,
password = "test",
method = "bf-cfb"
};
var server2CanonUrl = "ss://YmYtY2ZiOnRlc3RAMTkyLjE2OC4xLjE6ODM4OA==";
var serverWithRemark = new Server
{
server = server.server,
server_port = server.server_port,
password = server.password,
method = server.method,
remarks = "example-server"
};
var serverWithRemarkCanonUrl = "ss://YmYtY2ZiOnRlc3RAMTkyLjE2OC4xMDAuMTo4ODg4#example-server";
var server2WithRemark = new Server
{
server = server2.server,
server_port = server2.server_port,
password = server2.password,
method = server2.method,
remarks = "example-server"
};
var server2WithRemarkCanonUrl = "ss://YmYtY2ZiOnRlc3RAMTkyLjE2OC4xLjE6ODM4OA==#example-server";
var serverWithPlugin = new Server
{
server = server.server,
server_port = server.server_port,
password = server.password,
method = server.method,
plugin = "obfs-local",
plugin_opts = "obfs=http;obfs-host=google.com"
};
var serverWithPluginCanonUrl =
"ss://YmYtY2ZiOnRlc3Q@192.168.100.1:8888/?plugin=obfs-local%3bobfs%3dhttp%3bobfs-host%3dgoogle.com";
var server2WithPlugin = new Server
{
server = server2.server,
server_port = server2.server_port,
password = server2.password,
method = server2.method,
plugin = "obfs-local",
plugin_opts = "obfs=http;obfs-host=google.com"
};
var server2WithPluginCanonUrl =
"ss://YmYtY2ZiOnRlc3Q@192.168.1.1:8388/?plugin=obfs-local%3bobfs%3dhttp%3bobfs-host%3dgoogle.com";
var serverWithPluginAndRemark = new Server
{
server = server.server,
server_port = server.server_port,
password = server.password,
method = server.method,
plugin = serverWithPlugin.plugin,
plugin_opts = serverWithPlugin.plugin_opts,
remarks = serverWithRemark.remarks
};
var serverWithPluginAndRemarkCanonUrl =
"ss://YmYtY2ZiOnRlc3Q@192.168.100.1:8888/?plugin=obfs-local%3bobfs%3dhttp%3bobfs-host%3dgoogle.com#example-server";
var server2WithPluginAndRemark = new Server
{
server = server2.server,
server_port = server2.server_port,
password = server2.password,
method = server2.method,
plugin = server2WithPlugin.plugin,
plugin_opts = server2WithPlugin.plugin_opts,
remarks = server2WithRemark.remarks
};
var server2WithPluginAndRemarkCanonUrl =
"ss://YmYtY2ZiOnRlc3Q@192.168.1.1:8388/?plugin=obfs-local%3bobfs%3dhttp%3bobfs-host%3dgoogle.com#example-server";
RunParseShadowsocksUrlTest(
string.Join(
"\r\n",
serverCanonUrl,
"\r\n",
"ss://YmYtY2ZiOnRlc3RAMTkyLjE2OC4xMDAuMTo4ODg4/",
serverWithRemarkCanonUrl,
"ss://YmYtY2ZiOnRlc3RAMTkyLjE2OC4xMDAuMTo4ODg4/#example-server"),
new[]
{
server,
server,
serverWithRemark,
serverWithRemark
});
RunParseShadowsocksUrlTest(
string.Join(
"\r\n",
server2CanonUrl,
"\r\n",
"ss://YmYtY2ZiOnRlc3RAMTkyLjE2OC4xLjE6ODM4OA==/",
server2WithRemarkCanonUrl,
"ss://YmYtY2ZiOnRlc3RAMTkyLjE2OC4xLjE6ODM4OA==/#example-server"),
new[]
{
server2,
server2,
server2WithRemark,
server2WithRemark
});
RunParseShadowsocksUrlTest(
string.Join(
"\r\n",
"ss://YmYtY2ZiOnRlc3Q@192.168.100.1:8888",
"\r\n",
"ss://YmYtY2ZiOnRlc3Q@192.168.100.1:8888/",
"ss://YmYtY2ZiOnRlc3Q@192.168.100.1:8888#example-server",
"ss://YmYtY2ZiOnRlc3Q@192.168.100.1:8888/#example-server",
serverWithPluginCanonUrl,
serverWithPluginAndRemarkCanonUrl,
"ss://YmYtY2ZiOnRlc3Q@192.168.100.1:8888/?plugin=obfs-local%3bobfs%3dhttp%3bobfs-host%3dgoogle.com&unsupported=1#example-server"),
new[]
{
server,
server,
serverWithRemark,
serverWithRemark,
serverWithPlugin,
serverWithPluginAndRemark,
serverWithPluginAndRemark
});
RunParseShadowsocksUrlTest(
string.Join(
"\r\n",
"ss://YmYtY2ZiOnRlc3Q@192.168.1.1:8388",
"\r\n",
"ss://YmYtY2ZiOnRlc3Q@192.168.1.1:8388/",
"ss://YmYtY2ZiOnRlc3Q@192.168.1.1:8388#example-server",
"ss://YmYtY2ZiOnRlc3Q@192.168.1.1:8388/#example-server",
server2WithPluginCanonUrl,
server2WithPluginAndRemarkCanonUrl,
"ss://YmYtY2ZiOnRlc3Q@192.168.1.1:8388/?plugin=obfs-local%3bobfs%3dhttp%3bobfs-host%3dgoogle.com&unsupported=1#example-server"),
new[]
{
server2,
server2,
server2WithRemark,
server2WithRemark,
server2WithPlugin,
server2WithPluginAndRemark,
server2WithPluginAndRemark
});
var generateUrlCases = new Dictionary<string, Server>
{
[serverCanonUrl] = server,
[serverWithRemarkCanonUrl] = serverWithRemark,
[serverWithPluginCanonUrl] = serverWithPlugin,
[serverWithPluginAndRemarkCanonUrl] = serverWithPluginAndRemark
};
RunGenerateShadowsocksUrlTest(generateUrlCases);
}
private static void RunParseShadowsocksUrlTest(string testCase, IReadOnlyList<Server> expected)
{
var actual = Server.GetServers(testCase);
if (actual.Count != expected.Count)
{
Assert.Fail("Wrong number of configs. Expected: {0}. Actual: {1}", expected.Count, actual.Count);
}
for (int i = 0; i < expected.Count; i++)
{
var expectedServer = expected[i];
var actualServer = actual[i];
Assert.AreEqual(expectedServer.server, actualServer.server);
Assert.AreEqual(expectedServer.server_port, actualServer.server_port);
Assert.AreEqual(expectedServer.password, actualServer.password);
Assert.AreEqual(expectedServer.method, actualServer.method);
Assert.AreEqual(expectedServer.plugin, actualServer.plugin);
Assert.AreEqual(expectedServer.plugin_opts, actualServer.plugin_opts);
Assert.AreEqual(expectedServer.remarks, actualServer.remarks);
Assert.AreEqual(expectedServer.timeout, actualServer.timeout);
}
}
private static void RunGenerateShadowsocksUrlTest(IReadOnlyDictionary<string, Server> testCases)
{
foreach (var testCase in testCases)
{
string expected = testCase.Key;
Server config = testCase.Value;
var actual = ShadowsocksController.GetServerURL(config);
Assert.AreEqual(expected, actual);
}
}
}
}