From ef357bbbcf96fb289ed056c2d760d8a141c27a3b Mon Sep 17 00:00:00 2001 From: clowwindy Date: Sat, 11 Jul 2015 13:19:16 +0800 Subject: [PATCH 01/11] handshake before connecting to server --- shadowsocks-csharp/Controller/Local.cs | 114 ++++++++++++++++++--------------- 1 file changed, 61 insertions(+), 53 deletions(-) diff --git a/shadowsocks-csharp/Controller/Local.cs b/shadowsocks-csharp/Controller/Local.cs index 5489ea52..b0000eb3 100755 --- a/shadowsocks-csharp/Controller/Local.cs +++ b/shadowsocks-csharp/Controller/Local.cs @@ -44,6 +44,7 @@ namespace Shadowsocks.Controller public Socket remote; public Socket connection; + private byte command; private byte[] _firstPacket; private int _firstPacketLength; // Size of receive buffer. @@ -70,32 +71,7 @@ namespace Shadowsocks.Controller { this._firstPacket = firstPacket; this._firstPacketLength = length; - try - { - // TODO async resolving - IPAddress ipAddress; - bool parsed = IPAddress.TryParse(server.server, out ipAddress); - if (!parsed) - { - IPHostEntry ipHostInfo = Dns.GetHostEntry(server.server); - ipAddress = ipHostInfo.AddressList[0]; - } - IPEndPoint remoteEP = new IPEndPoint(ipAddress, server.server_port); - - - 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(); - } + this.HandshakeReceive(); } private void CheckClose() @@ -149,28 +125,6 @@ namespace Shadowsocks.Controller } } - private void ConnectCallback(IAsyncResult ar) - { - if (closed) - { - return; - } - try - { - // Complete the connection. - remote.EndConnect(ar); - - //Console.WriteLine("Socket connected to {0}", - // remote.RemoteEndPoint.ToString()); - - HandshakeReceive(); - } - catch (Exception e) - { - Logging.LogUsefulException(e); - this.Close(); - } - } private void HandshakeReceive() { @@ -241,11 +195,12 @@ namespace Shadowsocks.Controller try { int bytesRead = connection.EndReceive(ar); - - if (bytesRead > 0) + + if (bytesRead >= 3) { + command = connetionRecvBuffer[1]; byte[] response = { 5, 0, 0, 1, 0, 0, 0, 0, 0, 0 }; - connection.BeginSend(response, 0, response.Length, 0, new AsyncCallback(StartPipe), null); + connection.BeginSend(response, 0, response.Length, 0, new AsyncCallback(StartConnect), null); } else { @@ -260,8 +215,62 @@ namespace Shadowsocks.Controller } } + private void StartConnect(IAsyncResult ar) + { + try + { + connection.EndSend(ar); + + // TODO async resolving + IPAddress ipAddress; + bool parsed = IPAddress.TryParse(server.server, out ipAddress); + if (!parsed) + { + IPHostEntry ipHostInfo = Dns.GetHostEntry(server.server); + ipAddress = ipHostInfo.AddressList[0]; + } + IPEndPoint remoteEP = new IPEndPoint(ipAddress, server.server_port); + + + 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 + { + // Complete the connection. + remote.EndConnect(ar); + + //Console.WriteLine("Socket connected to {0}", + // remote.RemoteEndPoint.ToString()); + + StartPipe(); + } + catch (Exception e) + { + Logging.LogUsefulException(e); + this.Close(); + } + } - private void StartPipe(IAsyncResult ar) + private void StartPipe() { if (closed) { @@ -269,7 +278,6 @@ namespace Shadowsocks.Controller } try { - connection.EndReceive(ar); remote.BeginReceive(remoteRecvBuffer, 0, RecvSize, 0, new AsyncCallback(PipeRemoteReceiveCallback), null); connection.BeginReceive(connetionRecvBuffer, 0, RecvSize, 0, From f5500c40808bbba0d3c0c68273e25a6f3fc9d74f Mon Sep 17 00:00:00 2001 From: clowwindy Date: Sat, 11 Jul 2015 15:41:47 +0800 Subject: [PATCH 02/11] support UDP assoc in UDP relay --- shadowsocks-csharp/Controller/Local.cs | 68 +++++++++++++++++++++++++++++++++- 1 file changed, 66 insertions(+), 2 deletions(-) diff --git a/shadowsocks-csharp/Controller/Local.cs b/shadowsocks-csharp/Controller/Local.cs index b0000eb3..0c62b5f8 100755 --- a/shadowsocks-csharp/Controller/Local.cs +++ b/shadowsocks-csharp/Controller/Local.cs @@ -199,8 +199,15 @@ namespace Shadowsocks.Controller if (bytesRead >= 3) { command = connetionRecvBuffer[1]; - byte[] response = { 5, 0, 0, 1, 0, 0, 0, 0, 0, 0 }; - connection.BeginSend(response, 0, response.Length, 0, new AsyncCallback(StartConnect), null); + if (command == 1) + { + byte[] response = { 5, 0, 0, 1, 0, 0, 0, 0, 0, 0 }; + connection.BeginSend(response, 0, response.Length, 0, new AsyncCallback(StartConnect), null); + } + else if (command == 3) + { + HandleUDPAssociate(); + } } else { @@ -215,6 +222,63 @@ namespace Shadowsocks.Controller } } + private void HandleUDPAssociate() + { + IPEndPoint endPoint = (IPEndPoint)connection.LocalEndPoint; + byte[] address = endPoint.Address.GetAddressBytes(); + int port = endPoint.Port; + byte[] response = new byte[4 + address.Length + 2]; + response[0] = 5; + if (endPoint.AddressFamily == AddressFamily.InterNetwork) + { + response[3] = 1; + } + else if (endPoint.AddressFamily == AddressFamily.InterNetworkV6) + { + response[3] = 4; + } + address.CopyTo(response, 4); + response[response.Length - 2] = (byte)(port & 0xFF); + response[response.Length - 1] = (byte)((port >> 8) & 0xFF); + connection.BeginSend(response, 0, response.Length, 0, new AsyncCallback(ReadAll), true); + } + + private void ReadAll(IAsyncResult ar) + { + + if (closed) + { + return; + } + try + { + if (ar.AsyncState != null) + { + connection.EndSend(ar); + connection.BeginReceive(connetionRecvBuffer, 0, RecvSize, 0, + new AsyncCallback(ReadAll), null); + } + else + { + int bytesRead = connection.EndReceive(ar); + if (bytesRead > 0) + { + connection.BeginReceive(connetionRecvBuffer, 0, RecvSize, 0, + new AsyncCallback(ReadAll), null); + } + else + { + this.Close(); + } + } + } + catch (Exception e) + { + Logging.LogUsefulException(e); + this.Close(); + } + } + private void StartConnect(IAsyncResult ar) { try From 680d465393e2f0c49344ddbcc945f0721c36f05c Mon Sep 17 00:00:00 2001 From: clowwindy Date: Sat, 11 Jul 2015 17:15:04 +0800 Subject: [PATCH 03/11] add UDPRelay --- shadowsocks-csharp/Controller/Listener.cs | 85 +++++++++++++--- shadowsocks-csharp/Controller/PACServer.cs | 6 +- shadowsocks-csharp/Controller/PortForwarder.cs | 6 +- .../Controller/ShadowsocksController.cs | 6 +- .../Controller/{Local.cs => TCPRelay.cs} | 14 ++- shadowsocks-csharp/Controller/UDPRelay.cs | 113 +++++++++++++++++++++ shadowsocks-csharp/shadowsocks-csharp.csproj | 3 +- 7 files changed, 208 insertions(+), 25 deletions(-) rename shadowsocks-csharp/Controller/{Local.cs => TCPRelay.cs} (94%) create mode 100644 shadowsocks-csharp/Controller/UDPRelay.cs diff --git a/shadowsocks-csharp/Controller/Listener.cs b/shadowsocks-csharp/Controller/Listener.cs index 9943e536..1cf7cb97 100755 --- a/shadowsocks-csharp/Controller/Listener.cs +++ b/shadowsocks-csharp/Controller/Listener.cs @@ -12,12 +12,19 @@ namespace Shadowsocks.Controller { public interface Service { - bool Handle(byte[] firstPacket, int length, Socket socket); + bool Handle(byte[] firstPacket, int length, Socket socket, object state); + } + + public class UDPState + { + public byte[] buffer = new byte[4096]; + public EndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0); } Configuration _config; bool _shareOverLAN; - Socket _socket; + Socket _tcpSocket; + Socket _udpSocket; IList _services; public Listener(IList services) @@ -51,8 +58,10 @@ namespace Shadowsocks.Controller try { // Create a TCP/IP socket. - _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); - _socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); + _tcpSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + _udpSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); + _tcpSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); + _udpSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); IPEndPoint localEndPoint = null; if (_shareOverLAN) { @@ -64,29 +73,73 @@ namespace Shadowsocks.Controller } // Bind the socket to the local endpoint and listen for incoming connections. - _socket.Bind(localEndPoint); - _socket.Listen(1024); + _tcpSocket.Bind(localEndPoint); + _udpSocket.Bind(localEndPoint); + _tcpSocket.Listen(1024); // Start an asynchronous socket to listen for connections. Console.WriteLine("Shadowsocks started"); - _socket.BeginAccept( + _tcpSocket.BeginAccept( new AsyncCallback(AcceptCallback), - _socket); + _tcpSocket); + UDPState udpState = new UDPState(); + _udpSocket.BeginReceiveFrom(udpState.buffer, 0, udpState.buffer.Length, 0, ref udpState.remoteEndPoint, new AsyncCallback(RecvFromCallback), udpState); } catch (SocketException) { - _socket.Close(); + _tcpSocket.Close(); throw; } } public void Stop() { - if (_socket != null) + if (_tcpSocket != null) + { + _tcpSocket.Close(); + _tcpSocket = null; + } + if (_udpSocket != null) + { + _udpSocket.Close(); + _udpSocket = null; + } + } + + public void RecvFromCallback(IAsyncResult ar) + { + UDPState state = (UDPState)ar.AsyncState; + try + { + int bytesRead = _udpSocket.EndReceiveFrom(ar, ref state.remoteEndPoint); + foreach (Service service in _services) + { + if (service.Handle(state.buffer, bytesRead, _udpSocket, state)) + { + break; + } + } + } + catch (ObjectDisposedException) { - _socket.Close(); - _socket = null; + } + catch (Exception e) + { + } + finally + { + try + { + _udpSocket.BeginReceiveFrom(state.buffer, 0, state.buffer.Length, 0, ref state.remoteEndPoint, new AsyncCallback(RecvFromCallback), state); + } + catch (ObjectDisposedException) + { + // do nothing + } + catch (Exception e) + { + } } } @@ -144,14 +197,16 @@ namespace Shadowsocks.Controller int bytesRead = conn.EndReceive(ar); foreach (Service service in _services) { - if (service.Handle(buf, bytesRead, conn)) + if (service.Handle(buf, bytesRead, conn, null)) { return; } } // no service found for this - // shouldn't happen - conn.Close(); + if (conn.ProtocolType == ProtocolType.Tcp) + { + conn.Close(); + } } catch (Exception e) { diff --git a/shadowsocks-csharp/Controller/PACServer.cs b/shadowsocks-csharp/Controller/PACServer.cs index e193d9b4..038ead8c 100755 --- a/shadowsocks-csharp/Controller/PACServer.cs +++ b/shadowsocks-csharp/Controller/PACServer.cs @@ -33,8 +33,12 @@ namespace Shadowsocks.Controller this._config = config; } - public bool Handle(byte[] firstPacket, int length, Socket socket) + public bool Handle(byte[] firstPacket, int length, Socket socket, object state) { + if (socket.ProtocolType != ProtocolType.Tcp) + { + return false; + } try { string request = Encoding.UTF8.GetString(firstPacket, 0, length); diff --git a/shadowsocks-csharp/Controller/PortForwarder.cs b/shadowsocks-csharp/Controller/PortForwarder.cs index 1057143f..e0b05aea 100755 --- a/shadowsocks-csharp/Controller/PortForwarder.cs +++ b/shadowsocks-csharp/Controller/PortForwarder.cs @@ -15,8 +15,12 @@ namespace Shadowsocks.Controller this._targetPort = targetPort; } - public bool Handle(byte[] firstPacket, int length, Socket socket) + public bool Handle(byte[] firstPacket, int length, Socket socket, object state) { + if (socket.ProtocolType != ProtocolType.Tcp) + { + return false; + } new Handler().Start(firstPacket, length, socket, this._targetPort); return true; } diff --git a/shadowsocks-csharp/Controller/ShadowsocksController.cs b/shadowsocks-csharp/Controller/ShadowsocksController.cs index 734f27d1..0eb57c94 100755 --- a/shadowsocks-csharp/Controller/ShadowsocksController.cs +++ b/shadowsocks-csharp/Controller/ShadowsocksController.cs @@ -250,9 +250,11 @@ namespace Shadowsocks.Controller { polipoRunner.Start(_config); - Local local = new Local(_config); + TCPRelay tcpRelay = new TCPRelay(_config); + UDPRelay udpRelay = new UDPRelay(_config); List services = new List(); - services.Add(local); + services.Add(tcpRelay); + services.Add(udpRelay); services.Add(_pacServer); services.Add(new PortForwarder(polipoRunner.RunningPort)); _listener = new Listener(services); diff --git a/shadowsocks-csharp/Controller/Local.cs b/shadowsocks-csharp/Controller/TCPRelay.cs similarity index 94% rename from shadowsocks-csharp/Controller/Local.cs rename to shadowsocks-csharp/Controller/TCPRelay.cs index 0c62b5f8..610d28b7 100755 --- a/shadowsocks-csharp/Controller/Local.cs +++ b/shadowsocks-csharp/Controller/TCPRelay.cs @@ -9,16 +9,20 @@ using Shadowsocks.Model; namespace Shadowsocks.Controller { - class Local : Listener.Service + class TCPRelay : Listener.Service { private Configuration _config; - public Local(Configuration config) + public TCPRelay(Configuration config) { this._config = config; } - public bool Handle(byte[] firstPacket, int length, Socket socket) + public bool Handle(byte[] firstPacket, int length, Socket socket, object state) { + if (socket.ProtocolType != ProtocolType.Tcp) + { + return false; + } if (length < 2 || firstPacket[0] != 5) { return false; @@ -238,8 +242,8 @@ namespace Shadowsocks.Controller response[3] = 4; } address.CopyTo(response, 4); - response[response.Length - 2] = (byte)(port & 0xFF); - response[response.Length - 1] = (byte)((port >> 8) & 0xFF); + response[response.Length - 1] = (byte)(port & 0xFF); + response[response.Length - 2] = (byte)((port >> 8) & 0xFF); connection.BeginSend(response, 0, response.Length, 0, new AsyncCallback(ReadAll), true); } diff --git a/shadowsocks-csharp/Controller/UDPRelay.cs b/shadowsocks-csharp/Controller/UDPRelay.cs new file mode 100644 index 00000000..afa25aa2 --- /dev/null +++ b/shadowsocks-csharp/Controller/UDPRelay.cs @@ -0,0 +1,113 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Shadowsocks.Encryption; +using Shadowsocks.Model; +using System.Net.Sockets; +using System.Net; + +namespace Shadowsocks.Controller +{ + class UDPRelay : Listener.Service + { + private Configuration _config; + public UDPRelay(Configuration config) + { + this._config = config; + } + + public bool Handle(byte[] firstPacket, int length, Socket socket, object state) + { + if (socket.ProtocolType != ProtocolType.Udp) + { + return false; + } + if (length < 4) + { + return false; + } + Listener.UDPState udpState = (Listener.UDPState)state; + // TODO add cache + UDPHandler handler = new UDPHandler(socket, _config.GetCurrentServer(), (IPEndPoint)udpState.remoteEndPoint); + handler.Send(firstPacket, length); + handler.Receive(); + return true; + } + + class UDPHandler + { + private Socket _local; + private Socket _remote; + + private Server _server; + private byte[] _buffer = new byte[1500]; + + private IPEndPoint _localEndPoint; + private IPEndPoint _remoteEndPoint; + + public UDPHandler(Socket local, Server server, IPEndPoint localEndPoint) + { + // TODO add timeout + _local = local; + _server = server; + _localEndPoint = localEndPoint; + + // TODO async resolving + IPAddress ipAddress; + bool parsed = IPAddress.TryParse(server.server, out ipAddress); + if (!parsed) + { + IPHostEntry ipHostInfo = Dns.GetHostEntry(server.server); + ipAddress = ipHostInfo.AddressList[0]; + } + _remoteEndPoint = new IPEndPoint(ipAddress, server.server_port); + _remote = new Socket(_remoteEndPoint.AddressFamily, SocketType.Dgram, ProtocolType.Udp); + + } + public void Send(byte[] data, int length) + { + IEncryptor encryptor = EncryptorFactory.GetEncryptor(_server.method, _server.password); + byte[] dataIn = new byte[length - 3]; + Array.Copy(data, 3, dataIn, 0, length - 3); + byte[] dataOut = new byte[length - 3 + 16]; + int outlen; + encryptor.Encrypt(dataIn, dataIn.Length, dataOut, out outlen); + _remote.SendTo(dataOut, _remoteEndPoint); + } + public void Receive() + { + EndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0); + _remote.BeginReceiveFrom(_buffer, 0, _buffer.Length, 0, ref remoteEndPoint, new AsyncCallback(RecvFromCallback), null); + } + public void RecvFromCallback(IAsyncResult ar) + { + try + { + EndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0); + int bytesRead = _remote.EndReceiveFrom(ar, ref remoteEndPoint); + + byte[] dataOut = new byte[bytesRead]; + int outlen; + + IEncryptor encryptor = EncryptorFactory.GetEncryptor(_server.method, _server.password); + encryptor.Decrypt(_buffer, bytesRead, dataOut, out outlen); + + byte[] sendBuf = new byte[outlen + 3]; + Array.Copy(dataOut, 0, sendBuf, 3, outlen); + + _local.SendTo(sendBuf, outlen + 3, 0, _localEndPoint); + Receive(); + } + catch (ObjectDisposedException) + { + } + catch (Exception e) + { + } + finally + { + } + } + } + } +} diff --git a/shadowsocks-csharp/shadowsocks-csharp.csproj b/shadowsocks-csharp/shadowsocks-csharp.csproj index aa2c9000..fc87e606 100755 --- a/shadowsocks-csharp/shadowsocks-csharp.csproj +++ b/shadowsocks-csharp/shadowsocks-csharp.csproj @@ -131,6 +131,7 @@ + @@ -156,7 +157,7 @@ ConfigForm.cs - + From 09def2fc27f8df175a63ea6b0ee4fe6f7cbec37f Mon Sep 17 00:00:00 2001 From: clowwindy Date: Sat, 11 Jul 2015 18:32:32 +0800 Subject: [PATCH 04/11] add LRUCache for UDPRelay --- shadowsocks-csharp/Controller/Listener.cs | 2 +- shadowsocks-csharp/Controller/UDPRelay.cs | 94 +++++++++++++++++++++++++++++-- 2 files changed, 91 insertions(+), 5 deletions(-) diff --git a/shadowsocks-csharp/Controller/Listener.cs b/shadowsocks-csharp/Controller/Listener.cs index 1cf7cb97..a1f316b8 100755 --- a/shadowsocks-csharp/Controller/Listener.cs +++ b/shadowsocks-csharp/Controller/Listener.cs @@ -18,7 +18,7 @@ namespace Shadowsocks.Controller public class UDPState { public byte[] buffer = new byte[4096]; - public EndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0); + public EndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 1); } Configuration _config; diff --git a/shadowsocks-csharp/Controller/UDPRelay.cs b/shadowsocks-csharp/Controller/UDPRelay.cs index afa25aa2..bad2e41b 100644 --- a/shadowsocks-csharp/Controller/UDPRelay.cs +++ b/shadowsocks-csharp/Controller/UDPRelay.cs @@ -5,15 +5,18 @@ using Shadowsocks.Encryption; using Shadowsocks.Model; using System.Net.Sockets; using System.Net; +using System.Runtime.CompilerServices; namespace Shadowsocks.Controller { class UDPRelay : Listener.Service { private Configuration _config; + private LRUCache _cache; public UDPRelay(Configuration config) { this._config = config; + this._cache = new LRUCache(512); // todo: choose a smart number } public bool Handle(byte[] firstPacket, int length, Socket socket, object state) @@ -27,14 +30,19 @@ namespace Shadowsocks.Controller return false; } Listener.UDPState udpState = (Listener.UDPState)state; - // TODO add cache - UDPHandler handler = new UDPHandler(socket, _config.GetCurrentServer(), (IPEndPoint)udpState.remoteEndPoint); + IPEndPoint remoteEndPoint = (IPEndPoint)udpState.remoteEndPoint; + UDPHandler handler = _cache.get(remoteEndPoint); + if (handler == null) + { + handler = new UDPHandler(socket, _config.GetCurrentServer(), remoteEndPoint); + _cache.add(remoteEndPoint, handler); + } handler.Send(firstPacket, length); handler.Receive(); return true; } - class UDPHandler + public class UDPHandler { private Socket _local; private Socket _remote; @@ -47,7 +55,6 @@ namespace Shadowsocks.Controller public UDPHandler(Socket local, Server server, IPEndPoint localEndPoint) { - // TODO add timeout _local = local; _server = server; _localEndPoint = localEndPoint; @@ -108,6 +115,85 @@ namespace Shadowsocks.Controller { } } + public void Close() + { + try + { + _remote.Close(); + } + catch (ObjectDisposedException) + { + } + catch (Exception e) + { + } + finally + { + } + } + } + } + // cc by-sa 3.0 http://stackoverflow.com/a/3719378/1124054 + class LRUCache where V : UDPRelay.UDPHandler + { + private int capacity; + private Dictionary>> cacheMap = new Dictionary>>(); + private LinkedList> lruList = new LinkedList>(); + + public LRUCache(int capacity) + { + this.capacity = capacity; + } + + [MethodImpl(MethodImplOptions.Synchronized)] + public V get(K key) + { + LinkedListNode> node; + if (cacheMap.TryGetValue(key, out node)) + { + V value = node.Value.value; + lruList.Remove(node); + lruList.AddLast(node); + return value; + } + return default(V); + } + + [MethodImpl(MethodImplOptions.Synchronized)] + public void add(K key, V val) + { + if (cacheMap.Count >= capacity) + { + RemoveFirst(); + } + + LRUCacheItem cacheItem = new LRUCacheItem(key, val); + LinkedListNode> node = new LinkedListNode>(cacheItem); + lruList.AddLast(node); + cacheMap.Add(key, node); } + + private void RemoveFirst() + { + // Remove from LRUPriority + LinkedListNode> node = lruList.First; + lruList.RemoveFirst(); + + // Remove from cache + cacheMap.Remove(node.Value.key); + node.Value.value.Close(); + } + } + + class LRUCacheItem + { + public LRUCacheItem(K k, V v) + { + key = k; + value = v; + } + public K key; + public V value; } + } From f9f49552aeb0403c69cb6deb8cd9d3dc6a5a98aa Mon Sep 17 00:00:00 2001 From: clowwindy Date: Sat, 11 Jul 2015 18:38:45 +0800 Subject: [PATCH 05/11] add port check for 8123 --- shadowsocks-csharp/Data/cn.txt | 1 + shadowsocks-csharp/Model/Configuration.cs | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/shadowsocks-csharp/Data/cn.txt b/shadowsocks-csharp/Data/cn.txt index e092575c..3f4a3ac2 100644 --- a/shadowsocks-csharp/Data/cn.txt +++ b/shadowsocks-csharp/Data/cn.txt @@ -58,6 +58,7 @@ Please add at least one server=请添加至少一个服务器 Server IP can not be blank=服务器 IP 不能为空 Password can not be blank=密码不能为空 Port out of range=端口超出范围 +Port can't be 8123=端口不能为 8123 Shadowsocks {0} Update Found=Shadowsocks {0} 更新 Click here to download=点击这里下载 Shadowsocks is here=Shadowsocks 在这里 diff --git a/shadowsocks-csharp/Model/Configuration.cs b/shadowsocks-csharp/Model/Configuration.cs index b78358e8..294dd9b2 100755 --- a/shadowsocks-csharp/Model/Configuration.cs +++ b/shadowsocks-csharp/Model/Configuration.cs @@ -118,6 +118,10 @@ namespace Shadowsocks.Model { throw new ArgumentException(I18N.GetString("Port out of range")); } + if (port == 8123) + { + throw new ArgumentException(I18N.GetString("Port can't be 8123")); + } } private static void CheckPassword(string password) From 5906ddbc4b827a3c0fac915f2967269f1bb940ce Mon Sep 17 00:00:00 2001 From: clowwindy Date: Sat, 11 Jul 2015 18:50:10 +0800 Subject: [PATCH 06/11] fix warnings --- shadowsocks-csharp/Controller/Listener.cs | 4 ++-- shadowsocks-csharp/Controller/UDPRelay.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/shadowsocks-csharp/Controller/Listener.cs b/shadowsocks-csharp/Controller/Listener.cs index a1f316b8..b21e4f89 100755 --- a/shadowsocks-csharp/Controller/Listener.cs +++ b/shadowsocks-csharp/Controller/Listener.cs @@ -124,7 +124,7 @@ namespace Shadowsocks.Controller catch (ObjectDisposedException) { } - catch (Exception e) + catch (Exception) { } finally @@ -137,7 +137,7 @@ namespace Shadowsocks.Controller { // do nothing } - catch (Exception e) + catch (Exception) { } } diff --git a/shadowsocks-csharp/Controller/UDPRelay.cs b/shadowsocks-csharp/Controller/UDPRelay.cs index bad2e41b..beee8d85 100644 --- a/shadowsocks-csharp/Controller/UDPRelay.cs +++ b/shadowsocks-csharp/Controller/UDPRelay.cs @@ -108,7 +108,7 @@ namespace Shadowsocks.Controller catch (ObjectDisposedException) { } - catch (Exception e) + catch (Exception) { } finally @@ -124,7 +124,7 @@ namespace Shadowsocks.Controller catch (ObjectDisposedException) { } - catch (Exception e) + catch (Exception) { } finally From 21fda9e81bbb25a08fef96adbf837259850b041a Mon Sep 17 00:00:00 2001 From: clowwindy Date: Sat, 11 Jul 2015 19:31:43 +0800 Subject: [PATCH 07/11] use GitHub releases instead of SourceForge --- shadowsocks-csharp/Controller/UpdateChecker.cs | 27 ++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/shadowsocks-csharp/Controller/UpdateChecker.cs b/shadowsocks-csharp/Controller/UpdateChecker.cs index 55b27ee1..8d0f283e 100755 --- a/shadowsocks-csharp/Controller/UpdateChecker.cs +++ b/shadowsocks-csharp/Controller/UpdateChecker.cs @@ -6,13 +6,13 @@ using System.Net; using System.Reflection; using System.Text; using System.Text.RegularExpressions; -using System.Xml; +using SimpleJson; namespace Shadowsocks.Controller { public class UpdateChecker { - private const string UpdateURL = "https://sourceforge.net/api/file/index/project-id/1817190/path/dist/mtime/desc/limit/10/rss"; + private const string UpdateURL = "https://api.github.com/repos/shadowsocks/shadowsocks-csharp/releases"; public string LatestVersionNumber; public string LatestVersionURL; @@ -24,6 +24,7 @@ namespace Shadowsocks.Controller { // TODO test failures WebClient http = new WebClient(); + http.Headers.Add("User-Agent", "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.3319.102 Safari/537.36"); http.Proxy = new WebProxy(IPAddress.Loopback.ToString(), config.localPort); http.DownloadStringCompleted += http_DownloadStringCompleted; http.DownloadStringAsync(new Uri(UpdateURL)); @@ -119,23 +120,25 @@ namespace Shadowsocks.Controller { string response = e.Result; - XmlDocument xmlDoc = new XmlDocument(); - xmlDoc.LoadXml(response); - XmlNodeList elements = xmlDoc.GetElementsByTagName("media:content"); + JsonArray result = (JsonArray)SimpleJson.SimpleJson.DeserializeObject(e.Result); + List versions = new List(); - foreach (XmlNode el in elements) + foreach (JsonObject release in result) { - foreach (XmlAttribute attr in el.Attributes) + if ((bool)release["prerelease"]) + { + continue; + } + foreach (JsonObject asset in (JsonArray)release["assets"]) { - if (attr.Name == "url") + string url = (string)asset["browser_download_url"]; + if (IsNewVersion(url)) { - if (IsNewVersion(attr.Value)) - { - versions.Add(attr.Value); - } + versions.Add(url); } } } + if (versions.Count == 0) { return; From 544c9dc766760337285984467172e6d6b827a9fb Mon Sep 17 00:00:00 2001 From: clowwindy Date: Sat, 11 Jul 2015 19:35:02 +0800 Subject: [PATCH 08/11] update generated code --- .../Properties/Resources.Designer.cs | 25 ++++++++++------------ 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/shadowsocks-csharp/Properties/Resources.Designer.cs b/shadowsocks-csharp/Properties/Resources.Designer.cs index a5d9c107..0cc09108 100755 --- a/shadowsocks-csharp/Properties/Resources.Designer.cs +++ b/shadowsocks-csharp/Properties/Resources.Designer.cs @@ -71,7 +71,12 @@ namespace Shadowsocks.Properties { } /// - /// Looks up a localized string similar to Shadowsocks=Shadowsocks + /// Looks up a localized string similar to # translation for Simplified Chinese + /// + ///Shadowsocks=Shadowsocks + /// + ///# Menu items + /// ///Enable System Proxy=启用系统代理 ///Mode=系统代理模式 ///PAC=PAC 模式 @@ -80,24 +85,16 @@ namespace Shadowsocks.Properties { ///Edit Servers...=编辑服务器... ///Start on Boot=开机启动 ///Allow Clients from LAN=允许来自局域网的连接 - ///Edit PAC File...=编辑 PAC 文件... + ///Local PAC=使用本地 PAC + ///Online PAC=使用在线 PAC + ///Edit Local PAC File...=编辑本地 PAC 文件... + ///Update Local PAC from GFWList=从 GFWList 更新本地 PAC ///Edit User Rule for GFWList...=编辑 GFWList 的用户规则... ///Show QRCode...=显示二维码... ///Scan QRCode from Screen...=扫描屏幕上的二维码... ///Show Logs...=显示日志... ///About...=关于... - ///Quit=退出 - ///Edit Servers=编辑服务器 - ///&Add=添加(&A) - ///&Delete=删除(&D) - ///Server=服务器 - ///Server IP=服务器 IP - ///Server Port=服务器端口 - ///Password=密码 - ///Encryption=加密 - ///Proxy Port=代理端口 - ///Remarks=备注 - ///OK= [rest of string was truncated]";. + ///Quit=退出 [rest of string was truncated]";. /// internal static string cn { get { From ccce252d6225256bf0d0cc3f25c553f6c73b2b4c Mon Sep 17 00:00:00 2001 From: clowwindy Date: Sat, 11 Jul 2015 19:36:09 +0800 Subject: [PATCH 09/11] bump --- shadowsocks-csharp/Controller/UpdateChecker.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shadowsocks-csharp/Controller/UpdateChecker.cs b/shadowsocks-csharp/Controller/UpdateChecker.cs index 8d0f283e..03a17079 100755 --- a/shadowsocks-csharp/Controller/UpdateChecker.cs +++ b/shadowsocks-csharp/Controller/UpdateChecker.cs @@ -18,7 +18,7 @@ namespace Shadowsocks.Controller public string LatestVersionURL; public event EventHandler NewVersionFound; - public const string Version = "2.3.1"; + public const string Version = "2.4"; public void CheckUpdate(Configuration config) { From c673f18f8084cc57f4cc1241eaae263889ee7782 Mon Sep 17 00:00:00 2001 From: clowwindy Date: Sat, 11 Jul 2015 19:47:26 +0800 Subject: [PATCH 10/11] update CHANGES --- CHANGES | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CHANGES b/CHANGES index 6e8b7840..75df2d38 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,12 @@ +2.4 2015-07-11 +- Support UDP relay +- Support online PAC +- Migrate update checker to GitHub releases +- Other fixes + +2.3.1 2015-03-06 +- Support user rule + 2.3 2015-01-25 - Use the same port for every profile - Use the same port for HTTP/Socks5/PAC From f6cbf7b73a92c160f253692010b422283cf283ab Mon Sep 17 00:00:00 2001 From: clowwindy Date: Sat, 11 Jul 2015 19:58:43 +0800 Subject: [PATCH 11/11] Update README.md --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 60816ebc..d688c427 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,7 @@ Shadowsocks for Windows 3. PAC mode and global mode 4. GFWList and user rules 5. Supports HTTP proxy +6. Supports UDP relay (see Usage) #### Download @@ -33,6 +34,8 @@ with any editor, Shadowsocks will notify browsers about the change automatically 6. You can also update the PAC file from GFWList. Note your modifications to the PAC file will be lost. However you can put your rules in the user rule file for GFWList. Don't forget to update from GFWList again after you've edited the user rule +7. For UDP, you need to use SocksCap or ProxyCap to force programs you want +to proxy to tunnel over Shadowsocks ### Develop