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