-Use dual-mode socket & DnsEndPoint to handle all domain name connection. -Move all socket creation into one single function. So that we could treat domain name just like ipv4 & ipv6 address. This also solves the async domain solving problem because the os will hanlde it for us.tags/3.3
@@ -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. | |||
@@ -9,6 +9,7 @@ using Shadowsocks.Controller.Strategy; | |||
using Shadowsocks.Encryption; | |||
using Shadowsocks.Model; | |||
using Shadowsocks.Proxy; | |||
using Shadowsocks.Util; | |||
namespace Shadowsocks.Controller | |||
{ | |||
@@ -363,24 +364,11 @@ namespace Shadowsocks.Controller | |||
CreateRemote(); | |||
// Setting up proxy | |||
IPEndPoint proxyEP; | |||
EndPoint proxyEP; | |||
if (_config.useProxy) | |||
{ | |||
IPAddress ipAddress; | |||
bool parsed = IPAddress.TryParse(_config.proxyServer, out ipAddress); | |||
if (!parsed) | |||
{ | |||
/* | |||
* 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]; | |||
} | |||
remote = new Socks5Proxy(); | |||
proxyEP = new IPEndPoint(ipAddress, _config.proxyPort); | |||
proxyEP = SocketUtil.GetEndPoint(_config.proxyServer, _config.proxyPort); | |||
} | |||
else | |||
{ | |||
@@ -395,7 +383,7 @@ namespace Shadowsocks.Controller | |||
proxyTimer.Enabled = true; | |||
proxyTimer.Proxy = remote; | |||
proxyTimer.DestEndPoint = ProxyUtils.GetEndPoint(server.server, server.server_port); | |||
proxyTimer.DestEndPoint = SocketUtil.GetEndPoint(server.server, server.server_port); | |||
proxyTimer.Server = server; | |||
_proxyConnected = false; | |||
@@ -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) | |||
@@ -2,6 +2,7 @@ | |||
using System.Net; | |||
using System.Net.Sockets; | |||
using System.Threading; | |||
using Shadowsocks.Util; | |||
namespace Shadowsocks.Proxy | |||
{ | |||
@@ -52,39 +53,14 @@ namespace Shadowsocks.Proxy | |||
public void BeginConnectDest(EndPoint destEndPoint, AsyncCallback callback, object state) | |||
{ | |||
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) | |||
{ | |||
// need to resolve manually | |||
// TODO async resolving | |||
IPHostEntry ipHostInfo = Dns.GetHostEntry(dep.Host); | |||
IPAddress ipAddress = ipHostInfo.AddressList[0]; | |||
realEndPoint = new IPEndPoint(ipAddress, dep.Port); | |||
} | |||
DestEndPoint = destEndPoint; | |||
if (_remote == null) | |||
{ | |||
_remote = new Socket(realEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp); | |||
_remote = SocketUtil.CreateSocket(destEndPoint); | |||
_remote.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true); | |||
} | |||
_remote.BeginConnect(realEndPoint, callback, state); | |||
_remote.BeginConnect(destEndPoint, callback, state); | |||
} | |||
public void EndConnectDest(IAsyncResult asyncResult) | |||
@@ -35,20 +35,4 @@ 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); | |||
} | |||
} | |||
} |
@@ -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(); | |||
@@ -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); | |||
} | |||
} | |||
} | |||
} |
@@ -176,6 +176,7 @@ | |||
<Compile Include="Controller\Strategy\IStrategy.cs" /> | |||
<Compile Include="Proxy\Socks5Proxy.cs" /> | |||
<Compile Include="StringEx.cs" /> | |||
<Compile Include="Util\SocketUtil.cs" /> | |||
<Compile Include="Util\Util.cs" /> | |||
<Compile Include="View\ConfigForm.cs"> | |||
<SubType>Form</SubType> | |||