diff --git a/shadowsocks-csharp/Controller/Service/PortForwarder.cs b/shadowsocks-csharp/Controller/Service/PortForwarder.cs index 4f78a24c..f76a1284 100644 --- a/shadowsocks-csharp/Controller/Service/PortForwarder.cs +++ b/shadowsocks-csharp/Controller/Service/PortForwarder.cs @@ -1,6 +1,7 @@ using System; using System.Net; using System.Net.Sockets; +using Shadowsocks.Util; namespace Shadowsocks.Controller { @@ -45,14 +46,9 @@ namespace Shadowsocks.Controller 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); + EndPoint remoteEP = SocketUtil.GetEndPoint("localhost", targetPort); - - _remote = new Socket(ipAddress.AddressFamily, - SocketType.Stream, ProtocolType.Tcp); + _remote = SocketUtil.CreateSocket(remoteEP); _remote.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true); // Connect to the remote endpoint. diff --git a/shadowsocks-csharp/Controller/Service/TCPRelay.cs b/shadowsocks-csharp/Controller/Service/TCPRelay.cs index 4bce227d..35f9f9a7 100644 --- a/shadowsocks-csharp/Controller/Service/TCPRelay.cs +++ b/shadowsocks-csharp/Controller/Service/TCPRelay.cs @@ -9,6 +9,7 @@ using Shadowsocks.Controller.Strategy; using Shadowsocks.Encryption; using Shadowsocks.Model; using Shadowsocks.Proxy; +using Shadowsocks.Util; namespace Shadowsocks.Controller { @@ -302,7 +303,6 @@ namespace Shadowsocks.Controller if (ar.AsyncState != null) { connection.EndSend(ar); - Logging.Debug(remote.LocalEndPoint, remote.DestEndPoint, RecvSize, "TCP Relay"); connection.BeginReceive(_connetionRecvBuffer, 0, RecvSize, SocketFlags.None, new AsyncCallback(ReadAll), null); } else @@ -310,7 +310,6 @@ namespace Shadowsocks.Controller int bytesRead = connection.EndReceive(ar); if (bytesRead > 0) { - Logging.Debug(remote.LocalEndPoint, remote.DestEndPoint, RecvSize, "TCP Relay"); connection.BeginReceive(_connetionRecvBuffer, 0, RecvSize, SocketFlags.None, new AsyncCallback(ReadAll), null); } else @@ -341,6 +340,7 @@ namespace Shadowsocks.Controller // inner class private class ProxyTimer : Timer { + public IProxy Proxy; public EndPoint DestEndPoint; public Server Server; @@ -361,34 +361,17 @@ namespace Shadowsocks.Controller { CreateRemote(); - // 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 destEP = new IPEndPoint(ipAddress, server.server_port); - // Setting up proxy - IPEndPoint proxyEP; + EndPoint proxyEP; if (_config.useProxy) { - parsed = IPAddress.TryParse(_config.proxyServer, out ipAddress); - if (!parsed) - { - IPHostEntry ipHostInfo = Dns.GetHostEntry(_config.proxyServer); - ipAddress = ipHostInfo.AddressList[0]; - } - remote = new Socks5Proxy(); - proxyEP = new IPEndPoint(ipAddress, _config.proxyPort); + proxyEP = SocketUtil.GetEndPoint(_config.proxyServer, _config.proxyPort); } else { remote = new DirectConnect(); - proxyEP = destEP; + proxyEP = null; } @@ -396,7 +379,9 @@ namespace Shadowsocks.Controller proxyTimer.AutoReset = false; proxyTimer.Elapsed += proxyConnectTimer_Elapsed; proxyTimer.Enabled = true; - proxyTimer.DestEndPoint = destEP; + + proxyTimer.Proxy = remote; + proxyTimer.DestEndPoint = SocketUtil.GetEndPoint(server.server, server.server_port); proxyTimer.Server = server; _proxyConnected = false; @@ -417,9 +402,9 @@ namespace Shadowsocks.Controller { return; } - var ep = ((ProxyTimer)sender).DestEndPoint; + var proxy = ((ProxyTimer)sender).Proxy; - Logging.Info($"Proxy {ep} timed out"); + Logging.Info($"Proxy {proxy.ProxyEndPoint} timed out"); remote?.Close(); RetryConnect(); } @@ -434,7 +419,7 @@ namespace Shadowsocks.Controller try { ProxyTimer timer = (ProxyTimer)ar.AsyncState; - var destEP = timer.DestEndPoint; + var destEndPoint = timer.DestEndPoint; server = timer.Server; timer.Elapsed -= proxyConnectTimer_Elapsed; timer.Enabled = false; @@ -462,7 +447,7 @@ namespace Shadowsocks.Controller _destConnected = false; // Connect to the remote endpoint. - remote.BeginConnectDest(destEP, new AsyncCallback(ConnectCallback), connectTimer); + remote.BeginConnectDest(destEndPoint, new AsyncCallback(ConnectCallback), connectTimer); } catch (ArgumentException) { diff --git a/shadowsocks-csharp/Controller/Service/UDPRelay.cs b/shadowsocks-csharp/Controller/Service/UDPRelay.cs index 5f0d2363..0a5a18ac 100644 --- a/shadowsocks-csharp/Controller/Service/UDPRelay.cs +++ b/shadowsocks-csharp/Controller/Service/UDPRelay.cs @@ -7,6 +7,7 @@ using System.Runtime.CompilerServices; using Shadowsocks.Controller.Strategy; using Shadowsocks.Encryption; using Shadowsocks.Model; +using Shadowsocks.Util; namespace Shadowsocks.Controller { @@ -56,7 +57,7 @@ namespace Shadowsocks.Controller private byte[] _buffer = new byte[1500]; private IPEndPoint _localEndPoint; - private IPEndPoint _remoteEndPoint; + private EndPoint _remoteEndPoint; public UDPHandler(Socket local, Server server, IPEndPoint localEndPoint) { @@ -64,16 +65,8 @@ namespace Shadowsocks.Controller _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); + _remoteEndPoint = SocketUtil.GetEndPoint(server.server, server.server_port); + _remote = SocketUtil.CreateSocket(_remoteEndPoint, ProtocolType.Udp); } public void Send(byte[] data, int length) diff --git a/shadowsocks-csharp/Data/cn.txt b/shadowsocks-csharp/Data/cn.txt index 5d48ef7d..c7ef11a5 100644 --- a/shadowsocks-csharp/Data/cn.txt +++ b/shadowsocks-csharp/Data/cn.txt @@ -113,4 +113,6 @@ Failed to update registry=无法修改注册表 System Proxy On: =系统代理已启用: Running: Port {0}=正在运行:端口 {0} Unexpected error, shadowsocks will exit. Please report to=非预期错误,Shadowsocks将退出。请提交此错误到 - \ No newline at end of file +Unsupported operating system, use Windows Vista at least.=不支持的操作系统版本,最低需求为Windows Vista。 +Proxy request failed=代理请求失败 +Proxy handshake failed=代理握手失败 diff --git a/shadowsocks-csharp/Program.cs b/shadowsocks-csharp/Program.cs index be7e2afe..ee5465dc 100755 --- a/shadowsocks-csharp/Program.cs +++ b/shadowsocks-csharp/Program.cs @@ -18,6 +18,14 @@ namespace Shadowsocks [STAThread] static void Main() { + // Check OS since we are using dual-mode socket + if (!Utils.IsWinVistaOrHigher()) + { + MessageBox.Show(I18N.GetString("Unsupported operating system, use Windows Vista at least."), + "Shadowsocks Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + return; + } + Utils.ReleaseMemory(true); using (Mutex mutex = new Mutex(false, "Global\\Shadowsocks_" + Application.StartupPath.GetHashCode())) { diff --git a/shadowsocks-csharp/Proxy/DirectConnect.cs b/shadowsocks-csharp/Proxy/DirectConnect.cs index 7de4e59f..487adc41 100644 --- a/shadowsocks-csharp/Proxy/DirectConnect.cs +++ b/shadowsocks-csharp/Proxy/DirectConnect.cs @@ -2,6 +2,7 @@ using System.Net; using System.Net.Sockets; using System.Threading; +using Shadowsocks.Util; namespace Shadowsocks.Proxy { @@ -20,19 +21,26 @@ namespace Shadowsocks.Proxy public bool CompletedSynchronously { get; } = true; } + private class FakeEndPoint : EndPoint + { + public override AddressFamily AddressFamily { get; } = AddressFamily.Unspecified; + + public override string ToString() + { + return "null proxy"; + } + } + private Socket _remote; public EndPoint LocalEndPoint => _remote.LocalEndPoint; - public EndPoint ProxyEndPoint { get; private set; } - + public EndPoint ProxyEndPoint { get; } = new FakeEndPoint(); public EndPoint DestEndPoint { get; private set; } - public void BeginConnectProxy(EndPoint remoteEP, AsyncCallback callback, object state) { // do nothing - ProxyEndPoint = remoteEP; var r = new FakeAsyncResult(state); callback?.Invoke(r); @@ -43,17 +51,16 @@ namespace Shadowsocks.Proxy // do nothing } - public void BeginConnectDest(EndPoint remoteEP, AsyncCallback callback, object state) + public void BeginConnectDest(EndPoint destEndPoint, AsyncCallback callback, object state) { + DestEndPoint = destEndPoint; + if (_remote == null) { - _remote = new Socket(remoteEP.AddressFamily, SocketType.Stream, ProtocolType.Tcp); + _remote = SocketUtil.CreateSocket(destEndPoint); _remote.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true); } - - DestEndPoint = remoteEP; - - _remote.BeginConnect(remoteEP, callback, state); + _remote.BeginConnect(destEndPoint, callback, state); } public void EndConnectDest(IAsyncResult asyncResult) diff --git a/shadowsocks-csharp/Proxy/IProxy.cs b/shadowsocks-csharp/Proxy/IProxy.cs index 4796c92f..cc76b543 100644 --- a/shadowsocks-csharp/Proxy/IProxy.cs +++ b/shadowsocks-csharp/Proxy/IProxy.cs @@ -17,7 +17,7 @@ namespace Shadowsocks.Proxy void EndConnectProxy(IAsyncResult asyncResult); - void BeginConnectDest(EndPoint remoteEP, AsyncCallback callback, object state); + void BeginConnectDest(EndPoint destEndPoint, AsyncCallback callback, object state); void EndConnectDest(IAsyncResult asyncResult); diff --git a/shadowsocks-csharp/Proxy/Socks5Proxy.cs b/shadowsocks-csharp/Proxy/Socks5Proxy.cs index 6e6c04a9..adb94402 100644 --- a/shadowsocks-csharp/Proxy/Socks5Proxy.cs +++ b/shadowsocks-csharp/Proxy/Socks5Proxy.cs @@ -6,6 +6,7 @@ using System.Net.Sockets; using System.Text; using System.Threading; using Shadowsocks.Controller; +using Shadowsocks.Util; namespace Shadowsocks.Proxy { @@ -51,7 +52,7 @@ namespace Shadowsocks.Proxy public void BeginConnectProxy(EndPoint remoteEP, AsyncCallback callback, object state) { - _remote = new Socket(remoteEP.AddressFamily, SocketType.Stream, ProtocolType.Tcp); + _remote = SocketUtil.CreateSocket(remoteEP); _remote.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true); var st = new Socks5State(); @@ -73,50 +74,62 @@ namespace Shadowsocks.Proxy } } - public void BeginConnectDest(EndPoint remoteEP, AsyncCallback callback, object state) + public void BeginConnectDest(EndPoint destEndPoint, AsyncCallback callback, object state) { - var ep = remoteEP as IPEndPoint; - if (ep == null) - { - throw new Exception(I18N.GetString("Proxy request faild")); - } + DestEndPoint = destEndPoint; byte[] request = null; byte atyp = 0; - switch (ep.AddressFamily) + int port; + + var dep = destEndPoint as DnsEndPoint; + if (dep != null) { - case AddressFamily.InterNetwork: - request = new byte[4 + 4 + 2]; - atyp = 1; - break; - case AddressFamily.InterNetworkV6: - request = new byte[4 + 16 + 2]; - atyp = 4; - break; + // is a domain name, we will leave it to server + + atyp = 3; // DOMAINNAME + var enc = Encoding.UTF8; + var hostByteCount = enc.GetByteCount(dep.Host); + + request = new byte[4 + 1/*length byte*/ + hostByteCount + 2]; + request[4] = (byte)hostByteCount; + enc.GetBytes(dep.Host, 0, dep.Host.Length, request, 5); + + port = dep.Port; } - if (request == null) + else { - throw new Exception(I18N.GetString("Proxy request faild")); + switch (DestEndPoint.AddressFamily) + { + case AddressFamily.InterNetwork: + request = new byte[4 + 4 + 2]; + atyp = 1; // IP V4 address + break; + case AddressFamily.InterNetworkV6: + request = new byte[4 + 16 + 2]; + atyp = 4; // IP V6 address + break; + default: + throw new Exception(I18N.GetString("Proxy request failed")); + } + port = ((IPEndPoint) DestEndPoint).Port; + var addr = ((IPEndPoint)DestEndPoint).Address.GetAddressBytes(); + Array.Copy(addr, 0, request, 4, request.Length - 4 - 2); } - // 构造request包 - var addr = ep.Address.GetAddressBytes(); + // 构造request包剩余部分 request[0] = 5; request[1] = 1; request[2] = 0; request[3] = atyp; - Array.Copy(addr, 0, request, 4, request.Length - 4 - 2); - request[request.Length - 2] = (byte) ((ep.Port >> 8) & 0xff); - request[request.Length - 1] = (byte) (ep.Port & 0xff); + request[request.Length - 2] = (byte) ((port >> 8) & 0xff); + request[request.Length - 1] = (byte) (port & 0xff); var st = new Socks5State(); st.Callback = callback; st.AsyncState = state; - DestEndPoint = remoteEP; - _remote?.BeginSend(request, 0, request.Length, 0, Socks5RequestSendCallback, st); - } public void EndConnectDest(IAsyncResult asyncResult) @@ -206,12 +219,12 @@ namespace Shadowsocks.Proxy { if (_receiveBuffer[0] != 5 || _receiveBuffer[1] != 0) { - ex = new Exception(I18N.GetString("Proxy handshake faild")); + ex = new Exception(I18N.GetString("Proxy handshake failed")); } } else { - ex = new Exception(I18N.GetString("Proxy handshake faild")); + ex = new Exception(I18N.GetString("Proxy handshake failed")); } } catch (Exception ex2) @@ -261,20 +274,20 @@ namespace Shadowsocks.Proxy _remote.BeginReceive(_receiveBuffer, 0, 16 + 2, 0, Socks5ReplyReceiveCallback2, state); break; default: - state.ex = new Exception(I18N.GetString("Proxy request faild")); + state.ex = new Exception(I18N.GetString("Proxy request failed")); state.Callback?.Invoke(new FakeAsyncResult(ar, state)); break; } } else { - state.ex = new Exception(I18N.GetString("Proxy request faild")); + state.ex = new Exception(I18N.GetString("Proxy request failed")); state.Callback?.Invoke(new FakeAsyncResult(ar, state)); } } else { - state.ex = new Exception(I18N.GetString("Proxy request faild")); + state.ex = new Exception(I18N.GetString("Proxy request failed")); state.Callback?.Invoke(new FakeAsyncResult(ar, state)); } } @@ -297,7 +310,7 @@ namespace Shadowsocks.Proxy if (bytesRead < bytesNeedSkip) { - ex = new Exception(I18N.GetString("Proxy request faild")); + ex = new Exception(I18N.GetString("Proxy request failed")); } } catch (Exception ex2) diff --git a/shadowsocks-csharp/Util/SocketUtil.cs b/shadowsocks-csharp/Util/SocketUtil.cs new file mode 100644 index 00000000..ad413d49 --- /dev/null +++ b/shadowsocks-csharp/Util/SocketUtil.cs @@ -0,0 +1,66 @@ +using System; +using System.Net; +using System.Net.Sockets; + +namespace Shadowsocks.Util +{ + public static class SocketUtil + { + private class DnsEndPoint2 : DnsEndPoint + { + public DnsEndPoint2(string host, int port) : base(host, port) + { + } + + public DnsEndPoint2(string host, int port, AddressFamily addressFamily) : base(host, port, addressFamily) + { + } + + public override string ToString() + { + return this.Host + ":" + this.Port; + } + } + + public static EndPoint GetEndPoint(string host, int port) + { + IPAddress ipAddress; + bool parsed = IPAddress.TryParse(host, out ipAddress); + if (parsed) + { + return new IPEndPoint(ipAddress, port); + } + + // maybe is a domain name + return new DnsEndPoint2(host, port); + } + + public static Socket CreateSocket(EndPoint endPoint, ProtocolType protocolType = ProtocolType.Tcp) + { + SocketType socketType; + switch (protocolType) + { + case ProtocolType.Tcp: + socketType = SocketType.Stream; + break; + case ProtocolType.Udp: + socketType = SocketType.Dgram; + break; + default: + throw new NotSupportedException("Protocol " + protocolType + " doesn't supported!"); + } + + if (endPoint is DnsEndPoint) + { + var socket = new Socket(AddressFamily.InterNetworkV6, socketType, protocolType); + socket.SetSocketOption(SocketOptionLevel.IPv6, (SocketOptionName)27, false); + + return socket; + } + else + { + return new Socket(endPoint.AddressFamily, socketType, protocolType); + } + } + } +} diff --git a/shadowsocks-csharp/Util/Util.cs b/shadowsocks-csharp/Util/Util.cs index 53077c87..fdb8482e 100755 --- a/shadowsocks-csharp/Util/Util.cs +++ b/shadowsocks-csharp/Util/Util.cs @@ -151,12 +151,16 @@ namespace Shadowsocks.Util // we are building x86 binary for both x86 and x64, which will // cause problem when opening registry key // detect operating system instead of CPU - RegistryKey userKey = RegistryKey.OpenBaseKey( RegistryHive.CurrentUser, - Environment.Is64BitOperatingSystem ? RegistryView.Registry64 : RegistryView.Registry32 ); - userKey = userKey.OpenSubKey( name, writable ); + RegistryKey userKey = RegistryKey.OpenRemoteBaseKey( RegistryHive.CurrentUser, "", + Environment.Is64BitOperatingSystem ? RegistryView.Registry64 : RegistryView.Registry32 ) + .OpenSubKey( name, writable ); return userKey; } + public static bool IsWinVistaOrHigher() { + return Environment.OSVersion.Version.Major > 5; + } + [DllImport("kernel32.dll")] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool SetProcessWorkingSetSize(IntPtr process, diff --git a/shadowsocks-csharp/shadowsocks-csharp.csproj b/shadowsocks-csharp/shadowsocks-csharp.csproj index c4c87271..10e2c7d2 100644 --- a/shadowsocks-csharp/shadowsocks-csharp.csproj +++ b/shadowsocks-csharp/shadowsocks-csharp.csproj @@ -176,6 +176,7 @@ + Form