Browse Source

Merge PR #660 from @Noisyfox

Resolving domain name through socks5 proxy
and
dual-mode socket
tags/3.3
Syrone Wong 9 years ago
parent
commit
64e21e031d
11 changed files with 167 additions and 92 deletions
  1. +3
    -7
      shadowsocks-csharp/Controller/Service/PortForwarder.cs
  2. +12
    -27
      shadowsocks-csharp/Controller/Service/TCPRelay.cs
  3. +4
    -11
      shadowsocks-csharp/Controller/Service/UDPRelay.cs
  4. +3
    -1
      shadowsocks-csharp/Data/cn.txt
  5. +8
    -0
      shadowsocks-csharp/Program.cs
  6. +17
    -10
      shadowsocks-csharp/Proxy/DirectConnect.cs
  7. +1
    -1
      shadowsocks-csharp/Proxy/IProxy.cs
  8. +45
    -32
      shadowsocks-csharp/Proxy/Socks5Proxy.cs
  9. +66
    -0
      shadowsocks-csharp/Util/SocketUtil.cs
  10. +7
    -3
      shadowsocks-csharp/Util/Util.cs
  11. +1
    -0
      shadowsocks-csharp/shadowsocks-csharp.csproj

+ 3
- 7
shadowsocks-csharp/Controller/Service/PortForwarder.cs View File

@@ -1,6 +1,7 @@
using System; using System;
using System.Net; using System.Net;
using System.Net.Sockets; using System.Net.Sockets;
using Shadowsocks.Util;
namespace Shadowsocks.Controller namespace Shadowsocks.Controller
{ {
@@ -45,14 +46,9 @@ namespace Shadowsocks.Controller
this._local = socket; this._local = socket;
try 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); _remote.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true);
// Connect to the remote endpoint. // Connect to the remote endpoint.


+ 12
- 27
shadowsocks-csharp/Controller/Service/TCPRelay.cs View File

@@ -9,6 +9,7 @@ using Shadowsocks.Controller.Strategy;
using Shadowsocks.Encryption; using Shadowsocks.Encryption;
using Shadowsocks.Model; using Shadowsocks.Model;
using Shadowsocks.Proxy; using Shadowsocks.Proxy;
using Shadowsocks.Util;
namespace Shadowsocks.Controller namespace Shadowsocks.Controller
{ {
@@ -302,7 +303,6 @@ namespace Shadowsocks.Controller
if (ar.AsyncState != null) if (ar.AsyncState != null)
{ {
connection.EndSend(ar); connection.EndSend(ar);
Logging.Debug(remote.LocalEndPoint, remote.DestEndPoint, RecvSize, "TCP Relay");
connection.BeginReceive(_connetionRecvBuffer, 0, RecvSize, SocketFlags.None, new AsyncCallback(ReadAll), null); connection.BeginReceive(_connetionRecvBuffer, 0, RecvSize, SocketFlags.None, new AsyncCallback(ReadAll), null);
} }
else else
@@ -310,7 +310,6 @@ namespace Shadowsocks.Controller
int bytesRead = connection.EndReceive(ar); int bytesRead = connection.EndReceive(ar);
if (bytesRead > 0) if (bytesRead > 0)
{ {
Logging.Debug(remote.LocalEndPoint, remote.DestEndPoint, RecvSize, "TCP Relay");
connection.BeginReceive(_connetionRecvBuffer, 0, RecvSize, SocketFlags.None, new AsyncCallback(ReadAll), null); connection.BeginReceive(_connetionRecvBuffer, 0, RecvSize, SocketFlags.None, new AsyncCallback(ReadAll), null);
} }
else else
@@ -341,6 +340,7 @@ namespace Shadowsocks.Controller
// inner class // inner class
private class ProxyTimer : Timer private class ProxyTimer : Timer
{ {
public IProxy Proxy;
public EndPoint DestEndPoint; public EndPoint DestEndPoint;
public Server Server; public Server Server;
@@ -361,34 +361,17 @@ namespace Shadowsocks.Controller
{ {
CreateRemote(); 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 // Setting up proxy
IPEndPoint proxyEP;
EndPoint proxyEP;
if (_config.useProxy) 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(); remote = new Socks5Proxy();
proxyEP = new IPEndPoint(ipAddress, _config.proxyPort);
proxyEP = SocketUtil.GetEndPoint(_config.proxyServer, _config.proxyPort);
} }
else else
{ {
remote = new DirectConnect(); remote = new DirectConnect();
proxyEP = destEP;
proxyEP = null;
} }
@@ -396,7 +379,9 @@ namespace Shadowsocks.Controller
proxyTimer.AutoReset = false; proxyTimer.AutoReset = false;
proxyTimer.Elapsed += proxyConnectTimer_Elapsed; proxyTimer.Elapsed += proxyConnectTimer_Elapsed;
proxyTimer.Enabled = true; proxyTimer.Enabled = true;
proxyTimer.DestEndPoint = destEP;
proxyTimer.Proxy = remote;
proxyTimer.DestEndPoint = SocketUtil.GetEndPoint(server.server, server.server_port);
proxyTimer.Server = server; proxyTimer.Server = server;
_proxyConnected = false; _proxyConnected = false;
@@ -417,9 +402,9 @@ namespace Shadowsocks.Controller
{ {
return; 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(); remote?.Close();
RetryConnect(); RetryConnect();
} }
@@ -434,7 +419,7 @@ namespace Shadowsocks.Controller
try try
{ {
ProxyTimer timer = (ProxyTimer)ar.AsyncState; ProxyTimer timer = (ProxyTimer)ar.AsyncState;
var destEP = timer.DestEndPoint;
var destEndPoint = timer.DestEndPoint;
server = timer.Server; server = timer.Server;
timer.Elapsed -= proxyConnectTimer_Elapsed; timer.Elapsed -= proxyConnectTimer_Elapsed;
timer.Enabled = false; timer.Enabled = false;
@@ -462,7 +447,7 @@ namespace Shadowsocks.Controller
_destConnected = false; _destConnected = false;
// Connect to the remote endpoint. // Connect to the remote endpoint.
remote.BeginConnectDest(destEP, new AsyncCallback(ConnectCallback), connectTimer);
remote.BeginConnectDest(destEndPoint, new AsyncCallback(ConnectCallback), connectTimer);
} }
catch (ArgumentException) catch (ArgumentException)
{ {


+ 4
- 11
shadowsocks-csharp/Controller/Service/UDPRelay.cs View File

@@ -7,6 +7,7 @@ using System.Runtime.CompilerServices;
using Shadowsocks.Controller.Strategy; using Shadowsocks.Controller.Strategy;
using Shadowsocks.Encryption; using Shadowsocks.Encryption;
using Shadowsocks.Model; using Shadowsocks.Model;
using Shadowsocks.Util;
namespace Shadowsocks.Controller namespace Shadowsocks.Controller
{ {
@@ -56,7 +57,7 @@ namespace Shadowsocks.Controller
private byte[] _buffer = new byte[1500]; private byte[] _buffer = new byte[1500];
private IPEndPoint _localEndPoint; private IPEndPoint _localEndPoint;
private IPEndPoint _remoteEndPoint;
private EndPoint _remoteEndPoint;
public UDPHandler(Socket local, Server server, IPEndPoint localEndPoint) public UDPHandler(Socket local, Server server, IPEndPoint localEndPoint)
{ {
@@ -64,16 +65,8 @@ namespace Shadowsocks.Controller
_server = server; _server = server;
_localEndPoint = localEndPoint; _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) public void Send(byte[] data, int length)


+ 3
- 1
shadowsocks-csharp/Data/cn.txt View File

@@ -113,4 +113,6 @@ Failed to update registry=无法修改注册表
System Proxy On: =系统代理已启用: System Proxy On: =系统代理已启用:
Running: Port {0}=正在运行:端口 {0} Running: Port {0}=正在运行:端口 {0}
Unexpected error, shadowsocks will exit. Please report to=非预期错误,Shadowsocks将退出。请提交此错误到 Unexpected error, shadowsocks will exit. Please report to=非预期错误,Shadowsocks将退出。请提交此错误到
Unsupported operating system, use Windows Vista at least.=不支持的操作系统版本,最低需求为Windows Vista。
Proxy request failed=代理请求失败
Proxy handshake failed=代理握手失败

+ 8
- 0
shadowsocks-csharp/Program.cs View File

@@ -18,6 +18,14 @@ namespace Shadowsocks
[STAThread] [STAThread]
static void Main() 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); Utils.ReleaseMemory(true);
using (Mutex mutex = new Mutex(false, "Global\\Shadowsocks_" + Application.StartupPath.GetHashCode())) using (Mutex mutex = new Mutex(false, "Global\\Shadowsocks_" + Application.StartupPath.GetHashCode()))
{ {


+ 17
- 10
shadowsocks-csharp/Proxy/DirectConnect.cs View File

@@ -2,6 +2,7 @@
using System.Net; using System.Net;
using System.Net.Sockets; using System.Net.Sockets;
using System.Threading; using System.Threading;
using Shadowsocks.Util;


namespace Shadowsocks.Proxy namespace Shadowsocks.Proxy
{ {
@@ -20,19 +21,26 @@ namespace Shadowsocks.Proxy
public bool CompletedSynchronously { get; } = true; 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; private Socket _remote;


public EndPoint LocalEndPoint => _remote.LocalEndPoint; public EndPoint LocalEndPoint => _remote.LocalEndPoint;


public EndPoint ProxyEndPoint { get; private set; }

public EndPoint ProxyEndPoint { get; } = new FakeEndPoint();
public EndPoint DestEndPoint { get; private set; } public EndPoint DestEndPoint { get; private set; }



public void BeginConnectProxy(EndPoint remoteEP, AsyncCallback callback, object state) public void BeginConnectProxy(EndPoint remoteEP, AsyncCallback callback, object state)
{ {
// do nothing // do nothing
ProxyEndPoint = remoteEP;


var r = new FakeAsyncResult(state); var r = new FakeAsyncResult(state);
callback?.Invoke(r); callback?.Invoke(r);
@@ -43,17 +51,16 @@ namespace Shadowsocks.Proxy
// do nothing // 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) if (_remote == null)
{ {
_remote = new Socket(remoteEP.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
_remote = SocketUtil.CreateSocket(destEndPoint);
_remote.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true); _remote.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true);
} }

DestEndPoint = remoteEP;

_remote.BeginConnect(remoteEP, callback, state);
_remote.BeginConnect(destEndPoint, callback, state);
} }


public void EndConnectDest(IAsyncResult asyncResult) public void EndConnectDest(IAsyncResult asyncResult)


+ 1
- 1
shadowsocks-csharp/Proxy/IProxy.cs View File

@@ -17,7 +17,7 @@ namespace Shadowsocks.Proxy


void EndConnectProxy(IAsyncResult asyncResult); void EndConnectProxy(IAsyncResult asyncResult);


void BeginConnectDest(EndPoint remoteEP, AsyncCallback callback, object state);
void BeginConnectDest(EndPoint destEndPoint, AsyncCallback callback, object state);


void EndConnectDest(IAsyncResult asyncResult); void EndConnectDest(IAsyncResult asyncResult);




+ 45
- 32
shadowsocks-csharp/Proxy/Socks5Proxy.cs View File

@@ -6,6 +6,7 @@ using System.Net.Sockets;
using System.Text; using System.Text;
using System.Threading; using System.Threading;
using Shadowsocks.Controller; using Shadowsocks.Controller;
using Shadowsocks.Util;


namespace Shadowsocks.Proxy namespace Shadowsocks.Proxy
{ {
@@ -51,7 +52,7 @@ namespace Shadowsocks.Proxy


public void BeginConnectProxy(EndPoint remoteEP, AsyncCallback callback, object state) 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); _remote.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true);


var st = new Socks5State(); 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[] request = null;
byte atyp = 0; 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[0] = 5;
request[1] = 1; request[1] = 1;
request[2] = 0; request[2] = 0;
request[3] = atyp; 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(); var st = new Socks5State();
st.Callback = callback; st.Callback = callback;
st.AsyncState = state; st.AsyncState = state;


DestEndPoint = remoteEP;

_remote?.BeginSend(request, 0, request.Length, 0, Socks5RequestSendCallback, st); _remote?.BeginSend(request, 0, request.Length, 0, Socks5RequestSendCallback, st);

} }


public void EndConnectDest(IAsyncResult asyncResult) public void EndConnectDest(IAsyncResult asyncResult)
@@ -206,12 +219,12 @@ namespace Shadowsocks.Proxy
{ {
if (_receiveBuffer[0] != 5 || _receiveBuffer[1] != 0) if (_receiveBuffer[0] != 5 || _receiveBuffer[1] != 0)
{ {
ex = new Exception(I18N.GetString("Proxy handshake faild"));
ex = new Exception(I18N.GetString("Proxy handshake failed"));
} }
} }
else else
{ {
ex = new Exception(I18N.GetString("Proxy handshake faild"));
ex = new Exception(I18N.GetString("Proxy handshake failed"));
} }
} }
catch (Exception ex2) catch (Exception ex2)
@@ -261,20 +274,20 @@ namespace Shadowsocks.Proxy
_remote.BeginReceive(_receiveBuffer, 0, 16 + 2, 0, Socks5ReplyReceiveCallback2, state); _remote.BeginReceive(_receiveBuffer, 0, 16 + 2, 0, Socks5ReplyReceiveCallback2, state);
break; break;
default: 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)); state.Callback?.Invoke(new FakeAsyncResult(ar, state));
break; break;
} }
} }
else 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)); state.Callback?.Invoke(new FakeAsyncResult(ar, state));
} }
} }
else 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)); state.Callback?.Invoke(new FakeAsyncResult(ar, state));
} }
} }
@@ -297,7 +310,7 @@ namespace Shadowsocks.Proxy


if (bytesRead < bytesNeedSkip) if (bytesRead < bytesNeedSkip)
{ {
ex = new Exception(I18N.GetString("Proxy request faild"));
ex = new Exception(I18N.GetString("Proxy request failed"));
} }
} }
catch (Exception ex2) catch (Exception ex2)


+ 66
- 0
shadowsocks-csharp/Util/SocketUtil.cs View File

@@ -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);
}
}
}
}

+ 7
- 3
shadowsocks-csharp/Util/Util.cs View File

@@ -151,12 +151,16 @@ namespace Shadowsocks.Util
// we are building x86 binary for both x86 and x64, which will // we are building x86 binary for both x86 and x64, which will
// cause problem when opening registry key // cause problem when opening registry key
// detect operating system instead of CPU // 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; return userKey;
} }
public static bool IsWinVistaOrHigher() {
return Environment.OSVersion.Version.Major > 5;
}
[DllImport("kernel32.dll")] [DllImport("kernel32.dll")]
[return: MarshalAs(UnmanagedType.Bool)] [return: MarshalAs(UnmanagedType.Bool)]
private static extern bool SetProcessWorkingSetSize(IntPtr process, private static extern bool SetProcessWorkingSetSize(IntPtr process,


+ 1
- 0
shadowsocks-csharp/shadowsocks-csharp.csproj View File

@@ -176,6 +176,7 @@
<Compile Include="Controller\Strategy\IStrategy.cs" /> <Compile Include="Controller\Strategy\IStrategy.cs" />
<Compile Include="Proxy\Socks5Proxy.cs" /> <Compile Include="Proxy\Socks5Proxy.cs" />
<Compile Include="StringEx.cs" /> <Compile Include="StringEx.cs" />
<Compile Include="Util\SocketUtil.cs" />
<Compile Include="Util\Util.cs" /> <Compile Include="Util\Util.cs" />
<Compile Include="View\ConfigForm.cs"> <Compile Include="View\ConfigForm.cs">
<SubType>Form</SubType> <SubType>Form</SubType>


Loading…
Cancel
Save