Improve host address handling using DnsEndPoint
Signed-off-by: noisyfox <timemanager.rick@gmail.com>
This commit is contained in:
@@ -302,8 +302,7 @@ namespace Shadowsocks.Controller
|
||||
if (ar.AsyncState != null)
|
||||
{
|
||||
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);
|
||||
}
|
||||
else
|
||||
@@ -311,8 +310,7 @@ namespace Shadowsocks.Controller
|
||||
int bytesRead = connection.EndReceive(ar);
|
||||
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);
|
||||
}
|
||||
else
|
||||
@@ -344,8 +342,7 @@ namespace Shadowsocks.Controller
|
||||
private class ProxyTimer : Timer
|
||||
{
|
||||
public IProxy Proxy;
|
||||
public string DestHost;
|
||||
public int DestPort;
|
||||
public EndPoint DestEndPoint;
|
||||
public Server Server;
|
||||
|
||||
public ProxyTimer(int p) : base(p)
|
||||
@@ -373,7 +370,11 @@ namespace Shadowsocks.Controller
|
||||
bool parsed = IPAddress.TryParse(_config.proxyServer, out ipAddress);
|
||||
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);
|
||||
ipAddress = ipHostInfo.AddressList[0];
|
||||
}
|
||||
@@ -394,8 +395,7 @@ namespace Shadowsocks.Controller
|
||||
proxyTimer.Enabled = true;
|
||||
|
||||
proxyTimer.Proxy = remote;
|
||||
proxyTimer.DestHost = server.server;
|
||||
proxyTimer.DestPort = server.server_port;
|
||||
proxyTimer.DestEndPoint = ProxyUtils.GetEndPoint(server.server, server.server_port);
|
||||
proxyTimer.Server = server;
|
||||
|
||||
_proxyConnected = false;
|
||||
@@ -433,8 +433,7 @@ namespace Shadowsocks.Controller
|
||||
try
|
||||
{
|
||||
ProxyTimer timer = (ProxyTimer)ar.AsyncState;
|
||||
var destHost = timer.DestHost;
|
||||
var destPort = timer.DestPort;
|
||||
var destEndPoint = timer.DestEndPoint;
|
||||
server = timer.Server;
|
||||
timer.Elapsed -= proxyConnectTimer_Elapsed;
|
||||
timer.Enabled = false;
|
||||
@@ -462,7 +461,7 @@ namespace Shadowsocks.Controller
|
||||
|
||||
_destConnected = false;
|
||||
// Connect to the remote endpoint.
|
||||
remote.BeginConnectDest(destHost, destPort, new AsyncCallback(ConnectCallback), connectTimer);
|
||||
remote.BeginConnectDest(destEndPoint, new AsyncCallback(ConnectCallback), connectTimer);
|
||||
}
|
||||
catch (ArgumentException)
|
||||
{
|
||||
|
||||
@@ -35,9 +35,7 @@ namespace Shadowsocks.Proxy
|
||||
public EndPoint LocalEndPoint => _remote.LocalEndPoint;
|
||||
|
||||
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)
|
||||
{
|
||||
@@ -52,27 +50,41 @@ namespace Shadowsocks.Proxy
|
||||
// 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)
|
||||
{
|
||||
IPHostEntry ipHostInfo = Dns.GetHostEntry(host);
|
||||
ipAddress = ipHostInfo.AddressList[0];
|
||||
}
|
||||
IPEndPoint remoteEP = new IPEndPoint(ipAddress, port);
|
||||
EndPoint realEndPoint = DestEndPoint = destEndPoint;
|
||||
|
||||
DestHost = host;
|
||||
DestPort = port;
|
||||
/*
|
||||
* 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)
|
||||
{
|
||||
// need to resolve manually
|
||||
// TODO async resolving
|
||||
IPHostEntry ipHostInfo = Dns.GetHostEntry(dep.Host);
|
||||
IPAddress ipAddress = ipHostInfo.AddressList[0];
|
||||
|
||||
realEndPoint = new IPEndPoint(ipAddress, dep.Port);
|
||||
}
|
||||
|
||||
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.BeginConnect(remoteEP, callback, state);
|
||||
_remote.BeginConnect(realEndPoint, callback, state);
|
||||
}
|
||||
|
||||
public void EndConnectDest(IAsyncResult asyncResult)
|
||||
|
||||
@@ -11,15 +11,13 @@ namespace Shadowsocks.Proxy
|
||||
|
||||
EndPoint ProxyEndPoint { get; }
|
||||
|
||||
string DestHost { get; }
|
||||
|
||||
int DestPort { get; }
|
||||
EndPoint DestEndPoint { get; }
|
||||
|
||||
void BeginConnectProxy(EndPoint remoteEP, AsyncCallback callback, object state);
|
||||
|
||||
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);
|
||||
|
||||
@@ -37,4 +35,20 @@ namespace Shadowsocks.Proxy
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,8 +47,7 @@ namespace Shadowsocks.Proxy
|
||||
|
||||
public EndPoint LocalEndPoint => _remote.LocalEndPoint;
|
||||
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)
|
||||
{
|
||||
@@ -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 atyp = 0;
|
||||
|
||||
IPAddress ipAddress;
|
||||
bool parsed = IPAddress.TryParse(host, out ipAddress);
|
||||
if (parsed)
|
||||
int port;
|
||||
|
||||
var dep = destEndPoint as DnsEndPoint;
|
||||
if (dep != null)
|
||||
{
|
||||
IPEndPoint ep = new IPEndPoint(ipAddress, port);
|
||||
switch (ep.AddressFamily)
|
||||
// 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
|
||||
{
|
||||
switch (DestEndPoint.AddressFamily)
|
||||
{
|
||||
case AddressFamily.InterNetwork:
|
||||
request = new byte[4 + 4 + 2];
|
||||
@@ -100,23 +111,10 @@ namespace Shadowsocks.Proxy
|
||||
default:
|
||||
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);
|
||||
}
|
||||
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[0] = 5;
|
||||
@@ -131,7 +129,6 @@ namespace Shadowsocks.Proxy
|
||||
st.AsyncState = state;
|
||||
|
||||
_remote?.BeginSend(request, 0, request.Length, 0, Socks5RequestSendCallback, st);
|
||||
|
||||
}
|
||||
|
||||
public void EndConnectDest(IAsyncResult asyncResult)
|
||||
|
||||
Reference in New Issue
Block a user