Signed-off-by: noisyfox <timemanager.rick@gmail.com>tags/3.3
@@ -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) | ||||
{ | { | ||||
@@ -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) | ||||
@@ -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); | |||||
} | |||||
} | |||||
} | } |
@@ -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) | ||||