diff --git a/CHANGES b/CHANGES index 0fc9e1f9..64f5ee1c 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,6 @@ +2.2.1 2015-01-18 +- Fix QR Code compatibility + 2.2 2015-01-14 - Support updating PAC from GFWList - Support adding server by scanning QR Code diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ace27628..c88855b2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -20,6 +20,8 @@ a pull request, or ask some of your friends to do so. 3. We don't answer questions of any other types here. Since very few people are watching the issue tracker here, you'll probably get no help from here. Read [Troubleshooting] and get help from forums or [mailing lists]. +4. Issues in languages other than English will be Google translated into English +later. [Troubleshooting]: https://github.com/clowwindy/shadowsocks/wiki/Troubleshooting diff --git a/README.md b/README.md index 7b05714a..6d1c41ad 100644 --- a/README.md +++ b/README.md @@ -23,11 +23,10 @@ For >= Windows 8, download Shadowsocks-win-dotnet4.0-x.x.x.zip, unless you have 1. Find Shadowsocks icon in notification tray 2. You can add multiple servers in servers menu -3. Select Enable menu to enable system proxy -4. Leave Enable menu unchecked, Shadowsocks will still provide an HTTP proxy at 127.0.0.1:8123 -5. After you saved PAC file with any editor, Shadowsocks will notify browsers +3. Select Enable System Proxy menu to enable system proxy +4. After you saved PAC file with any editor, Shadowsocks will notify browsers about the change automatically -6. Please disable other proxy addons in your browser, or set them to use +5. Please disable other proxy addons in your browser, or set them to use system proxy ### Develop diff --git a/shadowsocks-csharp/Controller/GfwListUpdater.cs b/shadowsocks-csharp/Controller/GfwListUpdater.cs index 7abe9445..77be9c03 100644 --- a/shadowsocks-csharp/Controller/GfwListUpdater.cs +++ b/shadowsocks-csharp/Controller/GfwListUpdater.cs @@ -6,6 +6,7 @@ using System.IO; using Shadowsocks.Properties; using SimpleJson; using Shadowsocks.Util; +using Shadowsocks.Model; namespace Shadowsocks.Controller { @@ -42,10 +43,10 @@ namespace Shadowsocks.Controller } } - public void UpdatePACFromGFWList() + public void UpdatePACFromGFWList(Configuration config) { WebClient http = new WebClient(); - http.Proxy = new WebProxy(IPAddress.Loopback.ToString(), 8123); + http.Proxy = new WebProxy(IPAddress.Loopback.ToString(), config.localPort); http.DownloadStringCompleted += http_DownloadStringCompleted; http.DownloadStringAsync(new Uri(GFWLIST_URL)); } diff --git a/shadowsocks-csharp/Controller/Listener.cs b/shadowsocks-csharp/Controller/Listener.cs new file mode 100755 index 00000000..923bc0e7 --- /dev/null +++ b/shadowsocks-csharp/Controller/Listener.cs @@ -0,0 +1,143 @@ +using Shadowsocks.Model; +using System; +using System.Collections.Generic; +using System.Net; +using System.Net.Sockets; +using System.Text; + +namespace Shadowsocks.Controller +{ + public class Listener + { + public interface Service + { + bool Handle(byte[] firstPacket, int length, Socket socket); + } + + Configuration _config; + bool _shareOverLAN; + Socket _socket; + IList _services; + + public Listener(IList services) + { + this._services = services; + } + + public void Start(Configuration config) + { + this._config = config; + this._shareOverLAN = config.shareOverLan; + try + { + // Create a TCP/IP socket. + _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + _socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); + IPEndPoint localEndPoint = null; + if (_shareOverLAN) + { + localEndPoint = new IPEndPoint(IPAddress.Any, _config.localPort); + } + else + { + localEndPoint = new IPEndPoint(IPAddress.Loopback, _config.localPort); + } + + // Bind the socket to the local endpoint and listen for incoming connections. + _socket.Bind(localEndPoint); + _socket.Listen(1024); + + + // Start an asynchronous socket to listen for connections. + Console.WriteLine("Shadowsocks started"); + _socket.BeginAccept( + new AsyncCallback(AcceptCallback), + _socket); + } + catch (SocketException) + { + _socket.Close(); + throw; + } + } + + public void Stop() + { + if (_socket != null) + { + _socket.Close(); + _socket = null; + } + } + + public void AcceptCallback(IAsyncResult ar) + { + Socket listener = (Socket)ar.AsyncState; + try + { + Socket conn = listener.EndAccept(ar); + + byte[] buf = new byte[4096]; + object[] state = new object[] { + conn, + buf + }; + + conn.BeginReceive(buf, 0, buf.Length, 0, + new AsyncCallback(ReceiveCallback), state); + } + catch (ObjectDisposedException) + { + } + catch (Exception e) + { + Console.WriteLine(e); + } + finally + { + try + { + listener.BeginAccept( + new AsyncCallback(AcceptCallback), + listener); + } + catch (ObjectDisposedException) + { + // do nothing + } + catch (Exception e) + { + Logging.LogUsefulException(e); + } + } + } + + + private void ReceiveCallback(IAsyncResult ar) + { + object[] state = (object[])ar.AsyncState; + + Socket conn = (Socket)state[0]; + byte[] buf = (byte[])state[1]; + try + { + int bytesRead = conn.EndReceive(ar); + foreach (Service service in _services) + { + if (service.Handle(buf, bytesRead, conn)) + { + return; + } + } + // no service found for this + // shouldn't happen + conn.Close(); + } + catch (Exception e) + { + Console.WriteLine(e); + conn.Close(); + } + } + } +} diff --git a/shadowsocks-csharp/Controller/Local.cs b/shadowsocks-csharp/Controller/Local.cs index cd6d2f96..5489ea52 100755 --- a/shadowsocks-csharp/Controller/Local.cs +++ b/shadowsocks-csharp/Controller/Local.cs @@ -9,105 +9,43 @@ using Shadowsocks.Model; namespace Shadowsocks.Controller { - class Local + class Local : Listener.Service { - private Server _server; - private bool _shareOverLAN; - //private Encryptor encryptor; - Socket _listener; + private Configuration _config; public Local(Configuration config) { - this._server = config.GetCurrentServer(); - _shareOverLAN = config.shareOverLan; - //this.encryptor = new Encryptor(config.method, config.password); + this._config = config; } - public void Start() + public bool Handle(byte[] firstPacket, int length, Socket socket) { - try + if (length < 2 || firstPacket[0] != 5) { - // Create a TCP/IP socket. - _listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); - _listener.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); - IPEndPoint localEndPoint = null; - if (_shareOverLAN) - { - localEndPoint = new IPEndPoint(IPAddress.Any, _server.local_port); - } - else - { - localEndPoint = new IPEndPoint(IPAddress.Loopback, _server.local_port); - } - - // Bind the socket to the local endpoint and listen for incoming connections. - _listener.Bind(localEndPoint); - _listener.Listen(100); - - - // Start an asynchronous socket to listen for connections. - Console.WriteLine("Shadowsocks started"); - _listener.BeginAccept( - new AsyncCallback(AcceptCallback), - _listener); - } - catch(SocketException) - { - _listener.Close(); - throw; + return false; } + socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true); + Handler handler = new Handler(); + handler.connection = socket; + Server server = _config.GetCurrentServer(); + handler.encryptor = EncryptorFactory.GetEncryptor(server.method, server.password); + handler.server = server; + handler.Start(firstPacket, length); + return true; } - - public void Stop() - { - _listener.Close(); - } - - - public void AcceptCallback(IAsyncResult ar) - { - Socket listener = (Socket)ar.AsyncState; - try - { - Socket conn = listener.EndAccept(ar); - conn.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true); - - Handler handler = new Handler(); - handler.connection = conn; - handler.encryptor = EncryptorFactory.GetEncryptor(_server.method, _server.password); - handler.config = _server; - - handler.Start(); - } - catch - { - //Console.WriteLine(e.Message); - } - finally - { - try - { - listener.BeginAccept( - new AsyncCallback(AcceptCallback), - listener); - } - catch - { - //Console.WriteLine(e.Message); - } - } - } - } class Handler { //public Encryptor encryptor; public IEncryptor encryptor; - public Server config; + public Server server; // Client socket. public Socket remote; public Socket connection; + + private byte[] _firstPacket; + private int _firstPacketLength; // Size of receive buffer. public const int RecvSize = 16384; public const int BufferSize = RecvSize + 32; @@ -128,19 +66,21 @@ namespace Shadowsocks.Controller private object encryptionLock = new object(); private object decryptionLock = new object(); - public void Start() + public void Start(byte[] firstPacket, int length) { + this._firstPacket = firstPacket; + this._firstPacketLength = length; try { // TODO async resolving IPAddress ipAddress; - bool parsed = IPAddress.TryParse(config.server, out ipAddress); + bool parsed = IPAddress.TryParse(server.server, out ipAddress); if (!parsed) { - IPHostEntry ipHostInfo = Dns.GetHostEntry(config.server); + IPHostEntry ipHostInfo = Dns.GetHostEntry(server.server); ipAddress = ipHostInfo.AddressList[0]; } - IPEndPoint remoteEP = new IPEndPoint(ipAddress, config.server_port); + IPEndPoint remoteEP = new IPEndPoint(ipAddress, server.server_port); remote = new Socket(ipAddress.AddressFamily, @@ -240,33 +180,15 @@ namespace Shadowsocks.Controller } try { - connection.BeginReceive(connetionRecvBuffer, 0, 256, 0, - new AsyncCallback(HandshakeReceiveCallback), null); - } - catch (Exception e) - { - Logging.LogUsefulException(e); - this.Close(); - } - } - - private void HandshakeReceiveCallback(IAsyncResult ar) - { - if (closed) - { - return; - } - try - { - int bytesRead = connection.EndReceive(ar); + int bytesRead = _firstPacketLength; if (bytesRead > 1) { byte[] response = { 5, 0 }; - if (connetionRecvBuffer[0] != 5) + if (_firstPacket[0] != 5) { // reject socks 4 - response = new byte[]{ 0, 91 }; + response = new byte[] { 0, 91 }; Console.WriteLine("socks 5 protocol error"); } connection.BeginSend(response, 0, response.Length, 0, new AsyncCallback(HandshakeSendCallback), null); diff --git a/shadowsocks-csharp/Controller/PACServer.cs b/shadowsocks-csharp/Controller/PACServer.cs index b2456e18..b0ccf4d3 100755 --- a/shadowsocks-csharp/Controller/PACServer.cs +++ b/shadowsocks-csharp/Controller/PACServer.cs @@ -12,59 +12,73 @@ using System.Text; namespace Shadowsocks.Controller { - class PACServer + class PACServer : Listener.Service { - private static int PORT = 8093; public static string PAC_FILE = "pac.txt"; - private static Configuration config; - Socket _listener; FileSystemWatcher watcher; + private Configuration _config; public event EventHandler PACFileChanged; - public void Start(Configuration configuration) + public PACServer() + { + this.WatchPacFile(); + } + + public void UpdateConfiguration(Configuration config) + { + this._config = config; + } + + public bool Handle(byte[] firstPacket, int length, Socket socket) { try { - config = configuration; - // Create a TCP/IP socket. - _listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); - _listener.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); - IPEndPoint localEndPoint = null; - if (configuration.shareOverLan) + string request = Encoding.UTF8.GetString(firstPacket, 0, length); + string[] lines = request.Split('\r', '\n'); + bool hostMatch = false, pathMatch = false, useSocks = false; + foreach (string line in lines) { - localEndPoint = new IPEndPoint(IPAddress.Any, PORT); + string[] kv = line.Split(new char[]{':'}, 2); + if (kv.Length == 2) + { + if (kv[0] == "Host") + { + if (kv[1].Trim() == ((IPEndPoint)socket.LocalEndPoint).ToString()) + { + hostMatch = true; + } + } + else if (kv[0] == "User-Agent") + { + if (kv[1].IndexOf("Chrome") >= 0) + { + useSocks = true; + } + } + } + else if (kv.Length == 1) + { + if (line.IndexOf("pac") >= 0) + { + pathMatch = true; + } + } } - else + if (hostMatch && pathMatch) { - localEndPoint = new IPEndPoint(IPAddress.Loopback, PORT); + SendResponse(firstPacket, length, socket, useSocks); + return true; } - - // Bind the socket to the local endpoint and listen for incoming connections. - _listener.Bind(localEndPoint); - _listener.Listen(100); - _listener.BeginAccept( - new AsyncCallback(AcceptCallback), - _listener); - - WatchPacFile(); + return false; } - catch (SocketException) + catch (ArgumentException) { - _listener.Close(); - throw; + return false; } } - public void Stop() - { - if (_listener != null) - { - _listener.Close(); - _listener = null; - } - } public string TouchPACFile() { @@ -79,50 +93,6 @@ namespace Shadowsocks.Controller } } - // we don't even use it - static byte[] requestBuf = new byte[2048]; - - public void AcceptCallback(IAsyncResult ar) - { - Socket listener = (Socket)ar.AsyncState; - try - { - Socket conn = listener.EndAccept(ar); - - object[] state = new object[] { - conn, - requestBuf - }; - - conn.BeginReceive(requestBuf, 0, requestBuf.Length, 0, - new AsyncCallback(ReceiveCallback), state); - } - catch (ObjectDisposedException) - { - } - catch (Exception e) - { - Console.WriteLine(e); - } - finally - { - try - { - listener.BeginAccept( - new AsyncCallback(AcceptCallback), - listener); - } - catch (ObjectDisposedException) - { - // do nothing - } - catch (Exception e) - { - Logging.LogUsefulException(e); - } - } - } - private string GetPACContent() { if (File.Exists(PAC_FILE)) @@ -135,46 +105,33 @@ namespace Shadowsocks.Controller } } - private void ReceiveCallback(IAsyncResult ar) + public void SendResponse(byte[] firstPacket, int length, Socket socket, bool useSocks) { - object[] state = (object[])ar.AsyncState; - - Socket conn = (Socket)state[0]; - byte[] requestBuf = (byte[])state[1]; try { - int bytesRead = conn.EndReceive(ar); - string pac = GetPACContent(); - IPEndPoint localEndPoint = (IPEndPoint)conn.LocalEndPoint; + IPEndPoint localEndPoint = (IPEndPoint)socket.LocalEndPoint; - string proxy = GetPACAddress(requestBuf, localEndPoint); + string proxy = GetPACAddress(firstPacket, length, localEndPoint, useSocks); pac = pac.Replace("__PROXY__", proxy); - if (bytesRead > 0) - { - string text = String.Format(@"HTTP/1.1 200 OK + string text = String.Format(@"HTTP/1.1 200 OK Server: Shadowsocks Content-Type: application/x-ns-proxy-autoconfig Content-Length: {0} Connection: Close ", System.Text.Encoding.UTF8.GetBytes(pac).Length) + pac; - byte[] response = System.Text.Encoding.UTF8.GetBytes(text); - conn.BeginSend(response, 0, response.Length, 0, new AsyncCallback(SendCallback), conn); - Util.Utils.ReleaseMemory(); - } - else - { - conn.Close(); - } + byte[] response = System.Text.Encoding.UTF8.GetBytes(text); + socket.BeginSend(response, 0, response.Length, 0, new AsyncCallback(SendCallback), socket); + Util.Utils.ReleaseMemory(); } catch (Exception e) { Console.WriteLine(e); - conn.Close(); + socket.Close(); } } @@ -213,9 +170,8 @@ Connection: Close } } - private string GetPACAddress(byte[] requestBuf, IPEndPoint localEndPoint) + private string GetPACAddress(byte[] requestBuf, int length, IPEndPoint localEndPoint, bool useSocks) { - string proxy = "PROXY " + localEndPoint.Address + ":8123;"; //try //{ // string requestString = Encoding.UTF8.GetString(requestBuf); @@ -229,7 +185,7 @@ Connection: Close //{ // Console.WriteLine(e); //} - return proxy; + return (useSocks ? "SOCKS5 " : "PROXY ") + localEndPoint.Address + ":" + this._config.localPort + ";"; } } } diff --git a/shadowsocks-csharp/Controller/PolipoRunner.cs b/shadowsocks-csharp/Controller/PolipoRunner.cs index 42bf3bfa..ae0b46f1 100755 --- a/shadowsocks-csharp/Controller/PolipoRunner.cs +++ b/shadowsocks-csharp/Controller/PolipoRunner.cs @@ -6,6 +6,8 @@ using System.Diagnostics; using System.IO; using System.IO.Compression; using System.Text; +using System.Net.NetworkInformation; +using System.Net; namespace Shadowsocks.Controller { @@ -13,6 +15,7 @@ namespace Shadowsocks.Controller { private Process _process; private static string temppath; + private int _runningPort; static PolipoRunner() { @@ -27,6 +30,14 @@ namespace Shadowsocks.Controller } } + public int RunningPort + { + get + { + return _runningPort; + } + } + public void Start(Configuration configuration) { Server server = configuration.GetCurrentServer(); @@ -45,8 +56,10 @@ namespace Shadowsocks.Controller Console.WriteLine(e.ToString()); } } - string polipoConfig = Resources.polipo_config; - polipoConfig = polipoConfig.Replace("__SOCKS_PORT__", server.local_port.ToString()); + string polipoConfig = Resources.polipo_config; + _runningPort = this.GetFreePort(); + polipoConfig = polipoConfig.Replace("__SOCKS_PORT__", configuration.localPort.ToString()); + polipoConfig = polipoConfig.Replace("__POLIPO_BIND_PORT__", _runningPort.ToString()); polipoConfig = polipoConfig.Replace("__POLIPO_BIND_IP__", configuration.shareOverLan ? "0.0.0.0" : "127.0.0.1"); FileManager.ByteArrayToFile(temppath + "/polipo.conf", System.Text.Encoding.UTF8.GetBytes(polipoConfig)); @@ -79,5 +92,35 @@ namespace Shadowsocks.Controller _process = null; } } + + private int GetFreePort() + { + int defaultPort = 8123; + try + { + IPGlobalProperties properties = IPGlobalProperties.GetIPGlobalProperties(); + IPEndPoint[] tcpEndPoints = properties.GetActiveTcpListeners(); + + List usedPorts = new List(); + foreach (IPEndPoint endPoint in IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpListeners()) + { + usedPorts.Add(endPoint.Port); + } + for (int port = defaultPort; port <= 65535; port++) + { + if (!usedPorts.Contains(port)) + { + return port; + } + } + } + catch (Exception e) + { + // in case access denied + Logging.LogUsefulException(e); + return defaultPort; + } + throw new Exception("No free port found."); + } } } diff --git a/shadowsocks-csharp/Controller/PortForwarder.cs b/shadowsocks-csharp/Controller/PortForwarder.cs new file mode 100755 index 00000000..1057143f --- /dev/null +++ b/shadowsocks-csharp/Controller/PortForwarder.cs @@ -0,0 +1,264 @@ +using System; +using System.Collections.Generic; +using System.Net; +using System.Net.Sockets; +using System.Text; + +namespace Shadowsocks.Controller +{ + class PortForwarder : Listener.Service + { + int _targetPort; + + public PortForwarder(int targetPort) + { + this._targetPort = targetPort; + } + + public bool Handle(byte[] firstPacket, int length, Socket socket) + { + new Handler().Start(firstPacket, length, socket, this._targetPort); + return true; + } + + class Handler + { + private byte[] _firstPacket; + private int _firstPacketLength; + private Socket _local; + private Socket _remote; + private bool _closed = false; + private bool _localShutdown = false; + private bool _remoteShutdown = false; + public const int RecvSize = 16384; + // remote receive buffer + private byte[] remoteRecvBuffer = new byte[RecvSize]; + // connection receive buffer + private byte[] connetionRecvBuffer = new byte[RecvSize]; + + public void Start(byte[] firstPacket, int length, Socket socket, int targetPort) + { + this._firstPacket = firstPacket; + this._firstPacketLength = length; + this._local = socket; + try + { + // TODO async resolving + IPAddress ipAddress; + bool parsed = IPAddress.TryParse("127.0.0.1", out ipAddress); + IPEndPoint remoteEP = new IPEndPoint(ipAddress, targetPort); + + + _remote = new Socket(ipAddress.AddressFamily, + SocketType.Stream, ProtocolType.Tcp); + _remote.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true); + + // Connect to the remote endpoint. + _remote.BeginConnect(remoteEP, + new AsyncCallback(ConnectCallback), null); + } + catch (Exception e) + { + Logging.LogUsefulException(e); + this.Close(); + } + } + + private void ConnectCallback(IAsyncResult ar) + { + if (_closed) + { + return; + } + try + { + _remote.EndConnect(ar); + HandshakeReceive(); + } + catch (Exception e) + { + Logging.LogUsefulException(e); + this.Close(); + } + } + + private void HandshakeReceive() + { + if (_closed) + { + return; + } + try + { + _remote.BeginSend(_firstPacket, 0, _firstPacketLength, 0, new AsyncCallback(StartPipe), null); + } + catch (Exception e) + { + Logging.LogUsefulException(e); + this.Close(); + } + } + + + private void StartPipe(IAsyncResult ar) + { + if (_closed) + { + return; + } + try + { + _remote.EndSend(ar); + _remote.BeginReceive(remoteRecvBuffer, 0, RecvSize, 0, + new AsyncCallback(PipeRemoteReceiveCallback), null); + _local.BeginReceive(connetionRecvBuffer, 0, RecvSize, 0, + new AsyncCallback(PipeConnectionReceiveCallback), null); + } + catch (Exception e) + { + Logging.LogUsefulException(e); + this.Close(); + } + } + + private void PipeRemoteReceiveCallback(IAsyncResult ar) + { + if (_closed) + { + return; + } + try + { + int bytesRead = _remote.EndReceive(ar); + + if (bytesRead > 0) + { + _local.BeginSend(remoteRecvBuffer, 0, bytesRead, 0, new AsyncCallback(PipeConnectionSendCallback), null); + } + else + { + //Console.WriteLine("bytesRead: " + bytesRead.ToString()); + _local.Shutdown(SocketShutdown.Send); + _localShutdown = true; + CheckClose(); + } + } + catch (Exception e) + { + Logging.LogUsefulException(e); + this.Close(); + } + } + + private void PipeConnectionReceiveCallback(IAsyncResult ar) + { + if (_closed) + { + return; + } + try + { + int bytesRead = _local.EndReceive(ar); + + if (bytesRead > 0) + { + _remote.BeginSend(connetionRecvBuffer, 0, bytesRead, 0, new AsyncCallback(PipeRemoteSendCallback), null); + } + else + { + _remote.Shutdown(SocketShutdown.Send); + _remoteShutdown = true; + CheckClose(); + } + } + catch (Exception e) + { + Logging.LogUsefulException(e); + this.Close(); + } + } + + private void PipeRemoteSendCallback(IAsyncResult ar) + { + if (_closed) + { + return; + } + try + { + _remote.EndSend(ar); + _local.BeginReceive(this.connetionRecvBuffer, 0, RecvSize, 0, + new AsyncCallback(PipeConnectionReceiveCallback), null); + } + catch (Exception e) + { + Logging.LogUsefulException(e); + this.Close(); + } + } + + private void PipeConnectionSendCallback(IAsyncResult ar) + { + if (_closed) + { + return; + } + try + { + _local.EndSend(ar); + _remote.BeginReceive(this.remoteRecvBuffer, 0, RecvSize, 0, + new AsyncCallback(PipeRemoteReceiveCallback), null); + } + catch (Exception e) + { + Logging.LogUsefulException(e); + this.Close(); + } + } + + private void CheckClose() + { + if (_localShutdown && _remoteShutdown) + { + this.Close(); + } + } + + public void Close() + { + lock (this) + { + if (_closed) + { + return; + } + _closed = true; + } + if (_local != null) + { + try + { + _local.Shutdown(SocketShutdown.Both); + _local.Close(); + } + catch (Exception e) + { + Logging.LogUsefulException(e); + } + } + if (_remote != null) + { + try + { + _remote.Shutdown(SocketShutdown.Both); + _remote.Close(); + } + catch (SocketException e) + { + Logging.LogUsefulException(e); + } + } + } + } + } +} diff --git a/shadowsocks-csharp/Controller/ShadowsocksController.cs b/shadowsocks-csharp/Controller/ShadowsocksController.cs index 113242a7..4e343c96 100755 --- a/shadowsocks-csharp/Controller/ShadowsocksController.cs +++ b/shadowsocks-csharp/Controller/ShadowsocksController.cs @@ -17,8 +17,8 @@ namespace Shadowsocks.Controller private Thread _ramThread; - private Local local; - private PACServer pacServer; + private Listener _listener; + private PACServer _pacServer; private Configuration _config; private PolipoRunner polipoRunner; private GFWListUpdater gfwListUpdater; @@ -74,9 +74,10 @@ namespace Shadowsocks.Controller return Configuration.Load(); } - public void SaveServers(List servers) + public void SaveServers(List servers, int localPort) { _config.configs = servers; + _config.localPort = localPort; SaveConfig(_config); } @@ -142,9 +143,9 @@ namespace Shadowsocks.Controller return; } stopped = true; - if (local != null) + if (_listener != null) { - local.Stop(); + _listener.Stop(); } if (polipoRunner != null) { @@ -152,13 +153,13 @@ namespace Shadowsocks.Controller } if (_config.enabled) { - SystemProxy.Disable(); + SystemProxy.Update(_config, true); } } public void TouchPACFile() { - string pacFilename = pacServer.TouchPACFile(); + string pacFilename = _pacServer.TouchPACFile(); if (PACFileReadyToOpen != null) { PACFileReadyToOpen(this, new PathEventArgs() { Path = pacFilename }); @@ -177,7 +178,7 @@ namespace Shadowsocks.Controller { if (gfwListUpdater != null) { - gfwListUpdater.UpdatePACFromGFWList(); + gfwListUpdater.UpdatePACFromGFWList(_config); } } @@ -190,11 +191,12 @@ namespace Shadowsocks.Controller { polipoRunner = new PolipoRunner(); } - if (pacServer == null) + if (_pacServer == null) { - pacServer = new PACServer(); - pacServer.PACFileChanged += pacServer_PACFileChanged; + _pacServer = new PACServer(); + _pacServer.PACFileChanged += pacServer_PACFileChanged; } + _pacServer.UpdateConfiguration(_config); if (gfwListUpdater == null) { gfwListUpdater = new GFWListUpdater(); @@ -202,11 +204,9 @@ namespace Shadowsocks.Controller gfwListUpdater.Error += pacServer_PACUpdateError; } - pacServer.Stop(); - - if (local != null) + if (_listener != null) { - local.Stop(); + _listener.Stop(); } // don't put polipoRunner.Start() before pacServer.Stop() @@ -218,9 +218,13 @@ namespace Shadowsocks.Controller { polipoRunner.Start(_config); - local = new Local(_config); - local.Start(); - pacServer.Start(_config); + Local local = new Local(_config); + List services = new List(); + services.Add(local); + services.Add(_pacServer); + services.Add(new PortForwarder(polipoRunner.RunningPort)); + _listener = new Listener(services); + _listener.Start(_config); } catch (Exception e) { @@ -259,7 +263,7 @@ namespace Shadowsocks.Controller { if (_config.enabled) { - SystemProxy.Enable(_config.global); + SystemProxy.Update(_config, false); _systemProxyIsDirty = true; } else @@ -267,7 +271,7 @@ namespace Shadowsocks.Controller // only switch it off if we have switched it on if (_systemProxyIsDirty) { - SystemProxy.Disable(); + SystemProxy.Update(_config, false); _systemProxyIsDirty = false; } } diff --git a/shadowsocks-csharp/Controller/SystemProxy.cs b/shadowsocks-csharp/Controller/SystemProxy.cs index c8cc6f8d..dfbc4bc1 100755 --- a/shadowsocks-csharp/Controller/SystemProxy.cs +++ b/shadowsocks-csharp/Controller/SystemProxy.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Runtime.InteropServices; using System.Text; using System.IO; +using Shadowsocks.Model; namespace Shadowsocks.Controller { @@ -25,24 +26,39 @@ namespace Shadowsocks.Controller _refreshReturn = InternetSetOption(IntPtr.Zero, INTERNET_OPTION_REFRESH, IntPtr.Zero, 0); } - public static void Enable(bool global) + public static void Update(Configuration config, bool forceDisable) { + bool global = config.global; + bool enabled = config.enabled; + if (forceDisable) + { + enabled = false; + } try { RegistryKey registry = Registry.CurrentUser.OpenSubKey("Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", true); - if (global) + if (enabled) { - registry.SetValue("ProxyEnable", 1); - registry.SetValue("ProxyServer", "127.0.0.1:8123"); - registry.SetValue("AutoConfigURL", ""); + if (global) + { + registry.SetValue("ProxyEnable", 1); + registry.SetValue("ProxyServer", "127.0.0.1:" + config.localPort.ToString()); + registry.SetValue("AutoConfigURL", ""); + } + else + { + registry.SetValue("ProxyEnable", 0); + registry.SetValue("ProxyServer", ""); + registry.SetValue("AutoConfigURL", "http://127.0.0.1:" + config.localPort.ToString() + "/pac?t=" + GetTimestamp(DateTime.Now)); + } } else { registry.SetValue("ProxyEnable", 0); registry.SetValue("ProxyServer", ""); - registry.SetValue("AutoConfigURL", "http://127.0.0.1:8093/pac?t=" + GetTimestamp(DateTime.Now)); + registry.SetValue("AutoConfigURL", ""); } SystemProxy.NotifyIE(); //Must Notify IE first, or the connections do not chanage @@ -56,27 +72,6 @@ namespace Shadowsocks.Controller } } - public static void Disable() - { - try - { - RegistryKey registry = - Registry.CurrentUser.OpenSubKey("Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", - true); - registry.SetValue("ProxyEnable", 0); - registry.SetValue("ProxyServer", ""); - registry.SetValue("AutoConfigURL", ""); - SystemProxy.NotifyIE(); - CopyProxySettingFromLan(); - } - catch (Exception e) - { - Logging.LogUsefulException(e); - // TODO this should be moved into views - MessageBox.Show(I18N.GetString("Failed to update registry")); - } - } - private static void CopyProxySettingFromLan() { RegistryKey registry = diff --git a/shadowsocks-csharp/Controller/UpdateChecker.cs b/shadowsocks-csharp/Controller/UpdateChecker.cs index 3fe76f98..00aab2a0 100755 --- a/shadowsocks-csharp/Controller/UpdateChecker.cs +++ b/shadowsocks-csharp/Controller/UpdateChecker.cs @@ -1,4 +1,5 @@ -using System; +using Shadowsocks.Model; +using System; using System.Collections; using System.Collections.Generic; using System.Net; @@ -17,13 +18,13 @@ namespace Shadowsocks.Controller public string LatestVersionURL; public event EventHandler NewVersionFound; - public const string Version = "2.2"; + public const string Version = "2.3"; - public void CheckUpdate() + public void CheckUpdate(Configuration config) { // TODO test failures WebClient http = new WebClient(); - http.Proxy = new WebProxy(IPAddress.Loopback.ToString(), 8123); + http.Proxy = new WebProxy(IPAddress.Loopback.ToString(), config.localPort); http.DownloadStringCompleted += http_DownloadStringCompleted; http.DownloadStringAsync(new Uri(UpdateURL)); } @@ -74,6 +75,10 @@ namespace Shadowsocks.Controller private bool IsNewVersion(string url) { + if (url.IndexOf("prerelease") >= 0) + { + return false; + } // check dotnet 4.0 AssemblyName[] references = Assembly.GetExecutingAssembly().GetReferencedAssemblies(); Version dotNetVersion = Environment.Version; diff --git a/shadowsocks-csharp/Data/abp.js.gz b/shadowsocks-csharp/Data/abp.js.gz index e049c0a4..0577c7f5 100755 Binary files a/shadowsocks-csharp/Data/abp.js.gz and b/shadowsocks-csharp/Data/abp.js.gz differ diff --git a/shadowsocks-csharp/Data/cn.txt b/shadowsocks-csharp/Data/cn.txt index ed6dfbd8..34db8f0f 100644 --- a/shadowsocks-csharp/Data/cn.txt +++ b/shadowsocks-csharp/Data/cn.txt @@ -1,5 +1,5 @@ Shadowsocks=Shadowsocks -Enable=启用代理 +Enable System Proxy=启用系统代理 Mode=代理模式 PAC=PAC 模式 Global=全局模式 diff --git a/shadowsocks-csharp/Data/polipo_config.txt b/shadowsocks-csharp/Data/polipo_config.txt index 5a18557f..fabeab66 100755 --- a/shadowsocks-csharp/Data/polipo_config.txt +++ b/shadowsocks-csharp/Data/polipo_config.txt @@ -1,4 +1,5 @@ -proxyAddress = "__POLIPO_BIND_IP__" +proxyAddress = "__POLIPO_BIND_IP__" +proxyPort = 8123 socksParentProxy = "127.0.0.1:__SOCKS_PORT__" socksProxyType = socks5 diff --git a/shadowsocks-csharp/Model/Configuration.cs b/shadowsocks-csharp/Model/Configuration.cs index 4b6e0ecb..56c91759 100755 --- a/shadowsocks-csharp/Model/Configuration.cs +++ b/shadowsocks-csharp/Model/Configuration.cs @@ -16,6 +16,7 @@ namespace Shadowsocks.Model public bool enabled; public bool shareOverLan; public bool isDefault; + public int localPort; private static string CONFIG_FILE = "gui-config.json"; @@ -33,7 +34,6 @@ namespace Shadowsocks.Model public static void CheckServer(Server server) { - CheckPort(server.local_port); CheckPort(server.server_port); CheckPassword(server.password); CheckServer(server.server); @@ -46,6 +46,10 @@ namespace Shadowsocks.Model string configContent = File.ReadAllText(CONFIG_FILE); Configuration config = SimpleJson.SimpleJson.DeserializeObject(configContent, new JsonSerializerStrategy()); config.isDefault = false; + if (config.localPort == 0) + { + config.localPort = 1080; + } return config; } catch (Exception e) @@ -58,6 +62,7 @@ namespace Shadowsocks.Model { index = 0, isDefault = true, + localPort = 1080, configs = new List() { GetDefaultServer() @@ -105,7 +110,7 @@ namespace Shadowsocks.Model } } - private static void CheckPort(int port) + public static void CheckPort(int port) { if (port <= 0 || port > 65535) { diff --git a/shadowsocks-csharp/Model/Server.cs b/shadowsocks-csharp/Model/Server.cs index b4486db9..4acc3a0e 100755 --- a/shadowsocks-csharp/Model/Server.cs +++ b/shadowsocks-csharp/Model/Server.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Text; using System.IO; @@ -14,7 +14,6 @@ namespace Shadowsocks.Model { public string server; public int server_port; - public int local_port; public string password; public string method; public string remarks; @@ -39,7 +38,6 @@ namespace Shadowsocks.Model { this.server = ""; this.server_port = 8388; - this.local_port = 1080; this.method = "aes-256-cfb"; this.password = ""; this.remarks = ""; @@ -50,7 +48,8 @@ namespace Shadowsocks.Model string[] r1 = Regex.Split(ssURL, "ss://", RegexOptions.IgnoreCase); string base64 = r1[1].ToString(); byte[] bytes = null; - for (var i = 0; i < 3; i++) { + for (var i = 0; i < 3; i++) + { try { bytes = System.Convert.FromBase64String(base64); @@ -64,11 +63,25 @@ namespace Shadowsocks.Model { throw new FormatException(); } - string[] parts = Encoding.UTF8.GetString(bytes).Split(new char[2] { ':', '@' }); - this.method = parts[0].ToString(); - this.password = parts[1].ToString(); - this.server = parts[2].ToString(); - this.server_port = int.Parse(parts[3].ToString()); + try + { + string data = Encoding.UTF8.GetString(bytes); + int indexLastAt = data.LastIndexOf('@'); + + string afterAt = data.Substring(indexLastAt + 1); + int indexLastColon = afterAt.LastIndexOf(':'); + this.server_port = int.Parse(afterAt.Substring(indexLastColon + 1)); + this.server = afterAt.Substring(0, indexLastColon); + + string beforeAt = data.Substring(0, indexLastAt); + string[] parts = beforeAt.Split(new[] { ':' }); + this.method = parts[0]; + this.password = parts[1]; + } + catch (IndexOutOfRangeException) + { + throw new FormatException(); + } } } } diff --git a/shadowsocks-csharp/View/ConfigForm.Designer.cs b/shadowsocks-csharp/View/ConfigForm.Designer.cs index 57e1441b..83dae64a 100755 --- a/shadowsocks-csharp/View/ConfigForm.Designer.cs +++ b/shadowsocks-csharp/View/ConfigForm.Designer.cs @@ -33,8 +33,6 @@ this.RemarksLabel = new System.Windows.Forms.Label(); this.IPLabel = new System.Windows.Forms.Label(); this.ServerPortLabel = new System.Windows.Forms.Label(); - this.ProxyPortTextBox = new System.Windows.Forms.TextBox(); - this.ProxyPortLabel = new System.Windows.Forms.Label(); this.PasswordLabel = new System.Windows.Forms.Label(); this.IPTextBox = new System.Windows.Forms.TextBox(); this.ServerPortTextBox = new System.Windows.Forms.TextBox(); @@ -49,11 +47,15 @@ this.ServerGroupBox = new System.Windows.Forms.GroupBox(); this.ServersListBox = new System.Windows.Forms.ListBox(); this.tableLayoutPanel2 = new System.Windows.Forms.TableLayoutPanel(); + this.tableLayoutPanel5 = new System.Windows.Forms.TableLayoutPanel(); + this.ProxyPortTextBox = new System.Windows.Forms.TextBox(); + this.ProxyPortLabel = new System.Windows.Forms.Label(); this.tableLayoutPanel3 = new System.Windows.Forms.TableLayoutPanel(); this.tableLayoutPanel4 = new System.Windows.Forms.TableLayoutPanel(); this.tableLayoutPanel1.SuspendLayout(); this.ServerGroupBox.SuspendLayout(); this.tableLayoutPanel2.SuspendLayout(); + this.tableLayoutPanel5.SuspendLayout(); this.tableLayoutPanel3.SuspendLayout(); this.tableLayoutPanel4.SuspendLayout(); this.SuspendLayout(); @@ -69,8 +71,6 @@ this.tableLayoutPanel1.Controls.Add(this.RemarksLabel, 0, 5); this.tableLayoutPanel1.Controls.Add(this.IPLabel, 0, 0); this.tableLayoutPanel1.Controls.Add(this.ServerPortLabel, 0, 1); - this.tableLayoutPanel1.Controls.Add(this.ProxyPortTextBox, 1, 4); - this.tableLayoutPanel1.Controls.Add(this.ProxyPortLabel, 0, 4); this.tableLayoutPanel1.Controls.Add(this.PasswordLabel, 0, 2); this.tableLayoutPanel1.Controls.Add(this.IPTextBox, 1, 0); this.tableLayoutPanel1.Controls.Add(this.ServerPortTextBox, 1, 1); @@ -88,13 +88,13 @@ 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(238, 163); + this.tableLayoutPanel1.Size = new System.Drawing.Size(238, 137); this.tableLayoutPanel1.TabIndex = 0; // // 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(72, 137); + this.RemarksTextBox.Location = new System.Drawing.Point(72, 111); this.RemarksTextBox.MaxLength = 32; this.RemarksTextBox.Name = "RemarksTextBox"; this.RemarksTextBox.Size = new System.Drawing.Size(160, 20); @@ -105,7 +105,7 @@ // this.RemarksLabel.Anchor = System.Windows.Forms.AnchorStyles.Right; this.RemarksLabel.AutoSize = true; - this.RemarksLabel.Location = new System.Drawing.Point(17, 140); + this.RemarksLabel.Location = new System.Drawing.Point(17, 114); this.RemarksLabel.Name = "RemarksLabel"; this.RemarksLabel.Size = new System.Drawing.Size(49, 13); this.RemarksLabel.TabIndex = 9; @@ -131,26 +131,6 @@ this.ServerPortLabel.TabIndex = 1; this.ServerPortLabel.Text = "Server 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(72, 111); - this.ProxyPortTextBox.MaxLength = 10; - this.ProxyPortTextBox.Name = "ProxyPortTextBox"; - this.ProxyPortTextBox.Size = new System.Drawing.Size(160, 20); - this.ProxyPortTextBox.TabIndex = 4; - this.ProxyPortTextBox.WordWrap = false; - // - // ProxyPortLabel - // - this.ProxyPortLabel.Anchor = System.Windows.Forms.AnchorStyles.Right; - this.ProxyPortLabel.AutoSize = true; - this.ProxyPortLabel.Location = new System.Drawing.Point(11, 114); - this.ProxyPortLabel.Name = "ProxyPortLabel"; - this.ProxyPortLabel.Size = new System.Drawing.Size(55, 13); - this.ProxyPortLabel.TabIndex = 3; - this.ProxyPortLabel.Text = "Proxy Port"; - // // PasswordLabel // this.PasswordLabel.Anchor = System.Windows.Forms.AnchorStyles.Right; @@ -292,7 +272,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(249, 200); + this.ServerGroupBox.Size = new System.Drawing.Size(249, 174); this.ServerGroupBox.TabIndex = 6; this.ServerGroupBox.TabStop = false; this.ServerGroupBox.Text = "Server"; @@ -315,6 +295,7 @@ this.tableLayoutPanel2.ColumnCount = 2; this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel2.Controls.Add(this.tableLayoutPanel5, 1, 1); this.tableLayoutPanel2.Controls.Add(this.tableLayoutPanel3, 1, 2); this.tableLayoutPanel2.Controls.Add(this.ServersListBox, 0, 0); this.tableLayoutPanel2.Controls.Add(this.ServerGroupBox, 1, 0); @@ -326,9 +307,53 @@ 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(427, 264); + this.tableLayoutPanel2.Size = new System.Drawing.Size(427, 238); this.tableLayoutPanel2.TabIndex = 7; // + // tableLayoutPanel5 + // + this.tableLayoutPanel5.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Right))); + this.tableLayoutPanel5.AutoSize = true; + this.tableLayoutPanel5.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this.tableLayoutPanel5.ColumnCount = 2; + this.tableLayoutPanel5.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + 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(241, 174); + this.tableLayoutPanel5.Margin = new System.Windows.Forms.Padding(0); + this.tableLayoutPanel5.Name = "tableLayoutPanel5"; + this.tableLayoutPanel5.Padding = new System.Windows.Forms.Padding(3); + this.tableLayoutPanel5.RowCount = 1; + this.tableLayoutPanel5.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel5.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 26F)); + this.tableLayoutPanel5.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 26F)); + this.tableLayoutPanel5.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 26F)); + this.tableLayoutPanel5.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 26F)); + this.tableLayoutPanel5.Size = new System.Drawing.Size(186, 32); + this.tableLayoutPanel5.TabIndex = 9; + // + // ProxyPortTextBox + // + this.ProxyPortTextBox.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.ProxyPortTextBox.Location = new System.Drawing.Point(67, 6); + this.ProxyPortTextBox.MaxLength = 10; + this.ProxyPortTextBox.Name = "ProxyPortTextBox"; + this.ProxyPortTextBox.Size = new System.Drawing.Size(113, 20); + this.ProxyPortTextBox.TabIndex = 4; + this.ProxyPortTextBox.WordWrap = false; + // + // ProxyPortLabel + // + this.ProxyPortLabel.Anchor = System.Windows.Forms.AnchorStyles.Right; + this.ProxyPortLabel.AutoSize = true; + this.ProxyPortLabel.Location = new System.Drawing.Point(6, 9); + this.ProxyPortLabel.Name = "ProxyPortLabel"; + this.ProxyPortLabel.Size = new System.Drawing.Size(55, 13); + this.ProxyPortLabel.TabIndex = 3; + this.ProxyPortLabel.Text = "Proxy Port"; + // // tableLayoutPanel3 // this.tableLayoutPanel3.AutoSize = true; @@ -340,7 +365,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(268, 235); + this.tableLayoutPanel3.Location = new System.Drawing.Point(268, 209); this.tableLayoutPanel3.Margin = new System.Windows.Forms.Padding(3, 3, 0, 3); this.tableLayoutPanel3.Name = "tableLayoutPanel3"; this.tableLayoutPanel3.RowCount = 1; @@ -358,7 +383,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, 200); + this.tableLayoutPanel4.Location = new System.Drawing.Point(0, 174); this.tableLayoutPanel4.Margin = new System.Windows.Forms.Padding(0); this.tableLayoutPanel4.Name = "tableLayoutPanel4"; this.tableLayoutPanel4.RowCount = 1; @@ -393,6 +418,8 @@ this.ServerGroupBox.PerformLayout(); this.tableLayoutPanel2.ResumeLayout(false); this.tableLayoutPanel2.PerformLayout(); + this.tableLayoutPanel5.ResumeLayout(false); + this.tableLayoutPanel5.PerformLayout(); this.tableLayoutPanel3.ResumeLayout(false); this.tableLayoutPanel4.ResumeLayout(false); this.ResumeLayout(false); @@ -406,11 +433,9 @@ private System.Windows.Forms.Label IPLabel; private System.Windows.Forms.Label ServerPortLabel; private System.Windows.Forms.Label PasswordLabel; - private System.Windows.Forms.Label ProxyPortLabel; private System.Windows.Forms.TextBox IPTextBox; private System.Windows.Forms.TextBox ServerPortTextBox; private System.Windows.Forms.TextBox PasswordTextBox; - private System.Windows.Forms.TextBox ProxyPortTextBox; private System.Windows.Forms.Label EncryptionLabel; private System.Windows.Forms.ComboBox EncryptionSelect; private System.Windows.Forms.Panel panel2; @@ -425,6 +450,9 @@ private System.Windows.Forms.TableLayoutPanel tableLayoutPanel2; private System.Windows.Forms.TableLayoutPanel tableLayoutPanel3; private System.Windows.Forms.TableLayoutPanel tableLayoutPanel4; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel5; + private System.Windows.Forms.TextBox ProxyPortTextBox; + private System.Windows.Forms.Label ProxyPortLabel; } } diff --git a/shadowsocks-csharp/View/ConfigForm.cs b/shadowsocks-csharp/View/ConfigForm.cs index ecc9bf1f..574fafd5 100755 --- a/shadowsocks-csharp/View/ConfigForm.cs +++ b/shadowsocks-csharp/View/ConfigForm.cs @@ -79,12 +79,14 @@ namespace Shadowsocks.View server = IPTextBox.Text, server_port = int.Parse(ServerPortTextBox.Text), password = PasswordTextBox.Text, - local_port = int.Parse(ProxyPortTextBox.Text), method = EncryptionSelect.Text, remarks = RemarksTextBox.Text }; + int localPort = int.Parse(ProxyPortTextBox.Text); Configuration.CheckServer(server); + Configuration.CheckPort(localPort); _modifiedConfiguration.configs[_oldSelectedIndex] = server; + _modifiedConfiguration.localPort = localPort; return true; } @@ -108,7 +110,7 @@ namespace Shadowsocks.View IPTextBox.Text = server.server; ServerPortTextBox.Text = server.server_port.ToString(); PasswordTextBox.Text = server.password; - ProxyPortTextBox.Text = server.local_port.ToString(); + ProxyPortTextBox.Text = _modifiedConfiguration.localPort.ToString(); EncryptionSelect.Text = server.method ?? "aes-256-cfb"; RemarksTextBox.Text = server.remarks; ServerGroupBox.Visible = true; @@ -202,7 +204,7 @@ namespace Shadowsocks.View MessageBox.Show(I18N.GetString("Please add at least one server")); return; } - controller.SaveServers(_modifiedConfiguration.configs); + controller.SaveServers(_modifiedConfiguration.configs, _modifiedConfiguration.localPort); this.Close(); } diff --git a/shadowsocks-csharp/View/MenuViewController.cs b/shadowsocks-csharp/View/MenuViewController.cs index 9fe27bec..6d00bd07 100755 --- a/shadowsocks-csharp/View/MenuViewController.cs +++ b/shadowsocks-csharp/View/MenuViewController.cs @@ -63,7 +63,7 @@ namespace Shadowsocks.View LoadCurrentConfiguration(); - updateChecker.CheckUpdate(); + updateChecker.CheckUpdate(controller.GetConfiguration()); if (controller.GetConfiguration().isDefault) { @@ -131,7 +131,7 @@ namespace Shadowsocks.View private void LoadMenu() { this.contextMenu1 = new ContextMenu(new MenuItem[] { - this.enableItem = CreateMenuItem("Enable", new EventHandler(this.EnableItem_Click)), + this.enableItem = CreateMenuItem("Enable System Proxy", new EventHandler(this.EnableItem_Click)), CreateMenuGroup("Mode", new MenuItem[] { this.PACModeItem = CreateMenuItem("PAC", new EventHandler(this.PACModeItem_Click)), this.globalModeItem = CreateMenuItem("Global", new EventHandler(this.GlobalModeItem_Click)) diff --git a/shadowsocks-csharp/shadowsocks-csharp.csproj b/shadowsocks-csharp/shadowsocks-csharp.csproj index 61820eaa..3d51fabb 100755 --- a/shadowsocks-csharp/shadowsocks-csharp.csproj +++ b/shadowsocks-csharp/shadowsocks-csharp.csproj @@ -127,7 +127,9 @@ + +