Browse Source

Improve host address handling using DnsEndPoint

Signed-off-by: noisyfox <timemanager.rick@gmail.com>
tags/3.3
noisyfox 8 years ago
parent
commit
ad15c7e64b
4 changed files with 81 additions and 59 deletions
  1. +11
    -12
      shadowsocks-csharp/Controller/Service/TCPRelay.cs
  2. +28
    -16
      shadowsocks-csharp/Proxy/DirectConnect.cs
  3. +18
    -4
      shadowsocks-csharp/Proxy/IProxy.cs
  4. +24
    -27
      shadowsocks-csharp/Proxy/Socks5Proxy.cs

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

@@ -302,8 +302,7 @@ namespace Shadowsocks.Controller
if (ar.AsyncState != null) if (ar.AsyncState != null)
{ {
connection.EndSend(ar); connection.EndSend(ar);
// TODO: need fix
//Logging.Debug(remote.LocalEndPoint, remote.DestEndPoint, RecvSize, "TCP Relay");
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
@@ -311,8 +310,7 @@ namespace Shadowsocks.Controller
int bytesRead = connection.EndReceive(ar); int bytesRead = connection.EndReceive(ar);
if (bytesRead > 0) if (bytesRead > 0)
{ {
// TODO: need fix
//Logging.Debug(remote.LocalEndPoint, remote.DestEndPoint, RecvSize, "TCP Relay");
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
@@ -344,8 +342,7 @@ namespace Shadowsocks.Controller
private class ProxyTimer : Timer private class ProxyTimer : Timer
{ {
public IProxy Proxy; public IProxy Proxy;
public string DestHost;
public int DestPort;
public EndPoint DestEndPoint;
public Server Server; public Server Server;
public ProxyTimer(int p) : base(p) public ProxyTimer(int p) : base(p)
@@ -373,7 +370,11 @@ namespace Shadowsocks.Controller
bool parsed = IPAddress.TryParse(_config.proxyServer, out ipAddress); bool parsed = IPAddress.TryParse(_config.proxyServer, out ipAddress);
if (!parsed) if (!parsed)
{ {
// TODO really necessary to resolve a proxy's address? Maybe from local hosts?
/*
* TODO really necessary to resolve a proxy's address? Maybe from local hosts?
* also we may simplify it by using dual-mode socket with
* the approach described in DirectConnect.BeginConnectDest
*/
IPHostEntry ipHostInfo = Dns.GetHostEntry(_config.proxyServer); IPHostEntry ipHostInfo = Dns.GetHostEntry(_config.proxyServer);
ipAddress = ipHostInfo.AddressList[0]; ipAddress = ipHostInfo.AddressList[0];
} }
@@ -394,8 +395,7 @@ namespace Shadowsocks.Controller
proxyTimer.Enabled = true; proxyTimer.Enabled = true;
proxyTimer.Proxy = remote; proxyTimer.Proxy = remote;
proxyTimer.DestHost = server.server;
proxyTimer.DestPort = server.server_port;
proxyTimer.DestEndPoint = ProxyUtils.GetEndPoint(server.server, server.server_port);
proxyTimer.Server = server; proxyTimer.Server = server;
_proxyConnected = false; _proxyConnected = false;
@@ -433,8 +433,7 @@ namespace Shadowsocks.Controller
try try
{ {
ProxyTimer timer = (ProxyTimer)ar.AsyncState; ProxyTimer timer = (ProxyTimer)ar.AsyncState;
var destHost = timer.DestHost;
var destPort = timer.DestPort;
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 +461,7 @@ namespace Shadowsocks.Controller
_destConnected = false; _destConnected = false;
// Connect to the remote endpoint. // Connect to the remote endpoint.
remote.BeginConnectDest(destHost, destPort, new AsyncCallback(ConnectCallback), connectTimer);
remote.BeginConnectDest(destEndPoint, new AsyncCallback(ConnectCallback), connectTimer);
} }
catch (ArgumentException) catch (ArgumentException)
{ {


+ 28
- 16
shadowsocks-csharp/Proxy/DirectConnect.cs View File

@@ -35,9 +35,7 @@ namespace Shadowsocks.Proxy
public EndPoint LocalEndPoint => _remote.LocalEndPoint; public EndPoint LocalEndPoint => _remote.LocalEndPoint;


public EndPoint ProxyEndPoint { get; } = new FakeEndPoint(); public EndPoint ProxyEndPoint { get; } = new FakeEndPoint();
public string DestHost { get; private set; }
public int DestPort { 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)
{ {
@@ -52,27 +50,41 @@ namespace Shadowsocks.Proxy
// do nothing // do nothing
} }


public void BeginConnectDest(string host, int port, AsyncCallback callback, object state)
public void BeginConnectDest(EndPoint destEndPoint, AsyncCallback callback, object state)
{ {
// TODO async resolving
IPAddress ipAddress;
bool parsed = IPAddress.TryParse(host, out ipAddress);
if (!parsed)
EndPoint realEndPoint = DestEndPoint = destEndPoint;

/*
* On windows vista or later, dual-mode socket is supported, so that
* we don't need to resolve a DnsEndPoint manually.
* We could just create a dual-mode socket and pass the DnsEndPoint
* directly to it's BeginConnect and the system will handle it correctlly
* so that we won't worry about async resolving any more.
*
* see: https://blogs.msdn.microsoft.com/webdev/2013/01/08/dual-mode-sockets-never-create-an-ipv4-socket-again/
*
* But it seems that we can't use this feature because DnsEndPoint
* doesn't have a specific AddressFamily before it has been
* resolved (we don't know whether it's ipv4 or ipv6) and we don't have
* a dual-mode socket to use on windows xp :(
*/
var dep = realEndPoint as DnsEndPoint;
if (dep != null)
{ {
IPHostEntry ipHostInfo = Dns.GetHostEntry(host);
ipAddress = ipHostInfo.AddressList[0];
}
IPEndPoint remoteEP = new IPEndPoint(ipAddress, port);
// need to resolve manually
// TODO async resolving
IPHostEntry ipHostInfo = Dns.GetHostEntry(dep.Host);
IPAddress ipAddress = ipHostInfo.AddressList[0];


DestHost = host;
DestPort = port;
realEndPoint = new IPEndPoint(ipAddress, dep.Port);
}


if (_remote == null) if (_remote == null)
{ {
_remote = new Socket(remoteEP.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
_remote = new Socket(realEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
_remote.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true); _remote.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true);
} }
_remote.BeginConnect(remoteEP, callback, state);
_remote.BeginConnect(realEndPoint, callback, state);
} }


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


+ 18
- 4
shadowsocks-csharp/Proxy/IProxy.cs View File

@@ -11,15 +11,13 @@ namespace Shadowsocks.Proxy


EndPoint ProxyEndPoint { get; } EndPoint ProxyEndPoint { get; }


string DestHost { get; }

int DestPort { get; }
EndPoint DestEndPoint { get; }


void BeginConnectProxy(EndPoint remoteEP, AsyncCallback callback, object state); void BeginConnectProxy(EndPoint remoteEP, AsyncCallback callback, object state);


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


void BeginConnectDest(string host, int port, AsyncCallback callback, object state);
void BeginConnectDest(EndPoint destEndPoint, AsyncCallback callback, object state);


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


@@ -37,4 +35,20 @@ namespace Shadowsocks.Proxy


void Close(); void Close();
} }

public static class ProxyUtils
{
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 DnsEndPoint(host, port);
}
}
} }

+ 24
- 27
shadowsocks-csharp/Proxy/Socks5Proxy.cs View File

@@ -47,8 +47,7 @@ namespace Shadowsocks.Proxy


public EndPoint LocalEndPoint => _remote.LocalEndPoint; public EndPoint LocalEndPoint => _remote.LocalEndPoint;
public EndPoint ProxyEndPoint { get; private set; } public EndPoint ProxyEndPoint { get; private set; }
public string DestHost { get; private set; }
public int DestPort { 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)
{ {
@@ -74,20 +73,32 @@ namespace Shadowsocks.Proxy
} }
} }


public void BeginConnectDest(string host, int port, AsyncCallback callback, object state)
public void BeginConnectDest(EndPoint destEndPoint, AsyncCallback callback, object state)
{ {
DestHost = host;
DestPort = port;
DestEndPoint = destEndPoint;


byte[] request = null; byte[] request = null;
byte atyp = 0; byte atyp = 0;
IPAddress ipAddress;
bool parsed = IPAddress.TryParse(host, out ipAddress);
if (parsed)
int port;

var dep = destEndPoint as DnsEndPoint;
if (dep != null)
{
// 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;
}
else
{ {
IPEndPoint ep = new IPEndPoint(ipAddress, port);
switch (ep.AddressFamily)
switch (DestEndPoint.AddressFamily)
{ {
case AddressFamily.InterNetwork: case AddressFamily.InterNetwork:
request = new byte[4 + 4 + 2]; request = new byte[4 + 4 + 2];
@@ -100,23 +111,10 @@ namespace Shadowsocks.Proxy
default: default:
throw new Exception(I18N.GetString("Proxy request failed")); throw new Exception(I18N.GetString("Proxy request failed"));
} }
var addr = ep.Address.GetAddressBytes();
port = ((IPEndPoint) DestEndPoint).Port;
var addr = ((IPEndPoint)DestEndPoint).Address.GetAddressBytes();
Array.Copy(addr, 0, request, 4, request.Length - 4 - 2); Array.Copy(addr, 0, request, 4, request.Length - 4 - 2);
} }
else
{
// maybe is a domain name, we will leave it to server
// need ValidateTcpPort? porttest > 1 && porttest < 65535?

atyp = 3; // DOMAINNAME
var enc = Encoding.UTF8;
var hostByteCount = enc.GetByteCount(host);
request = new byte[4 + 1/*length byte*/ + hostByteCount + 2];
request[4] = (byte)hostByteCount;
enc.GetBytes(host, 0, host.Length, request, 5);
}


// 构造request包剩余部分 // 构造request包剩余部分
request[0] = 5; request[0] = 5;
@@ -131,7 +129,6 @@ namespace Shadowsocks.Proxy
st.AsyncState = state; st.AsyncState = state;


_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)


Loading…
Cancel
Save