Unified ipv4, ipv6 and domain connections.
-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.
This commit is contained in:
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user