Browse Source

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.
tags/3.3
noisyfox 8 years ago
parent
commit
53ce1948e4
8 changed files with 84 additions and 79 deletions
  1. +3
    -7
      shadowsocks-csharp/Controller/Service/PortForwarder.cs
  2. +4
    -16
      shadowsocks-csharp/Controller/Service/TCPRelay.cs
  3. +4
    -11
      shadowsocks-csharp/Controller/Service/UDPRelay.cs
  4. +4
    -28
      shadowsocks-csharp/Proxy/DirectConnect.cs
  5. +0
    -16
      shadowsocks-csharp/Proxy/IProxy.cs
  6. +2
    -1
      shadowsocks-csharp/Proxy/Socks5Proxy.cs
  7. +66
    -0
      shadowsocks-csharp/Util/SocketUtil.cs
  8. +1
    -0
      shadowsocks-csharp/shadowsocks-csharp.csproj

+ 3
- 7
shadowsocks-csharp/Controller/Service/PortForwarder.cs View File

@@ -1,6 +1,7 @@
using System; using System;
using System.Net; using System.Net;
using System.Net.Sockets; using System.Net.Sockets;
using Shadowsocks.Util;
namespace Shadowsocks.Controller namespace Shadowsocks.Controller
{ {
@@ -45,14 +46,9 @@ namespace Shadowsocks.Controller
this._local = socket; this._local = socket;
try 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); _remote.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true);
// Connect to the remote endpoint. // Connect to the remote endpoint.


+ 4
- 16
shadowsocks-csharp/Controller/Service/TCPRelay.cs View File

@@ -9,6 +9,7 @@ using Shadowsocks.Controller.Strategy;
using Shadowsocks.Encryption; using Shadowsocks.Encryption;
using Shadowsocks.Model; using Shadowsocks.Model;
using Shadowsocks.Proxy; using Shadowsocks.Proxy;
using Shadowsocks.Util;
namespace Shadowsocks.Controller namespace Shadowsocks.Controller
{ {
@@ -363,24 +364,11 @@ namespace Shadowsocks.Controller
CreateRemote(); CreateRemote();
// Setting up proxy // Setting up proxy
IPEndPoint proxyEP;
EndPoint proxyEP;
if (_config.useProxy) 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(); remote = new Socks5Proxy();
proxyEP = new IPEndPoint(ipAddress, _config.proxyPort);
proxyEP = SocketUtil.GetEndPoint(_config.proxyServer, _config.proxyPort);
} }
else else
{ {
@@ -395,7 +383,7 @@ namespace Shadowsocks.Controller
proxyTimer.Enabled = true; proxyTimer.Enabled = true;
proxyTimer.Proxy = remote; proxyTimer.Proxy = remote;
proxyTimer.DestEndPoint = ProxyUtils.GetEndPoint(server.server, server.server_port);
proxyTimer.DestEndPoint = SocketUtil.GetEndPoint(server.server, server.server_port);
proxyTimer.Server = server; proxyTimer.Server = server;
_proxyConnected = false; _proxyConnected = false;


+ 4
- 11
shadowsocks-csharp/Controller/Service/UDPRelay.cs View File

@@ -7,6 +7,7 @@ using System.Runtime.CompilerServices;
using Shadowsocks.Controller.Strategy; using Shadowsocks.Controller.Strategy;
using Shadowsocks.Encryption; using Shadowsocks.Encryption;
using Shadowsocks.Model; using Shadowsocks.Model;
using Shadowsocks.Util;
namespace Shadowsocks.Controller namespace Shadowsocks.Controller
{ {
@@ -56,7 +57,7 @@ namespace Shadowsocks.Controller
private byte[] _buffer = new byte[1500]; private byte[] _buffer = new byte[1500];
private IPEndPoint _localEndPoint; private IPEndPoint _localEndPoint;
private IPEndPoint _remoteEndPoint;
private EndPoint _remoteEndPoint;
public UDPHandler(Socket local, Server server, IPEndPoint localEndPoint) public UDPHandler(Socket local, Server server, IPEndPoint localEndPoint)
{ {
@@ -64,16 +65,8 @@ namespace Shadowsocks.Controller
_server = server; _server = server;
_localEndPoint = localEndPoint; _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) public void Send(byte[] data, int length)


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

@@ -2,6 +2,7 @@
using System.Net; using System.Net;
using System.Net.Sockets; using System.Net.Sockets;
using System.Threading; using System.Threading;
using Shadowsocks.Util;


namespace Shadowsocks.Proxy namespace Shadowsocks.Proxy
{ {
@@ -52,39 +53,14 @@ namespace Shadowsocks.Proxy


public void BeginConnectDest(EndPoint destEndPoint, AsyncCallback callback, object state) 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) if (_remote == null)
{ {
_remote = new Socket(realEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
_remote = SocketUtil.CreateSocket(destEndPoint);
_remote.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true); _remote.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true);
} }
_remote.BeginConnect(realEndPoint, callback, state);
_remote.BeginConnect(destEndPoint, callback, state);
} }


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


+ 0
- 16
shadowsocks-csharp/Proxy/IProxy.cs View File

@@ -35,20 +35,4 @@ 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);
}
}
} }

+ 2
- 1
shadowsocks-csharp/Proxy/Socks5Proxy.cs View File

@@ -6,6 +6,7 @@ using System.Net.Sockets;
using System.Text; using System.Text;
using System.Threading; using System.Threading;
using Shadowsocks.Controller; using Shadowsocks.Controller;
using Shadowsocks.Util;


namespace Shadowsocks.Proxy namespace Shadowsocks.Proxy
{ {
@@ -51,7 +52,7 @@ namespace Shadowsocks.Proxy


public void BeginConnectProxy(EndPoint remoteEP, AsyncCallback callback, object state) 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); _remote.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true);


var st = new Socks5State(); var st = new Socks5State();


+ 66
- 0
shadowsocks-csharp/Util/SocketUtil.cs View File

@@ -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);
}
}
}
}

+ 1
- 0
shadowsocks-csharp/shadowsocks-csharp.csproj View File

@@ -176,6 +176,7 @@
<Compile Include="Controller\Strategy\IStrategy.cs" /> <Compile Include="Controller\Strategy\IStrategy.cs" />
<Compile Include="Proxy\Socks5Proxy.cs" /> <Compile Include="Proxy\Socks5Proxy.cs" />
<Compile Include="StringEx.cs" /> <Compile Include="StringEx.cs" />
<Compile Include="Util\SocketUtil.cs" />
<Compile Include="Util\Util.cs" /> <Compile Include="Util\Util.cs" />
<Compile Include="View\ConfigForm.cs"> <Compile Include="View\ConfigForm.cs">
<SubType>Form</SubType> <SubType>Form</SubType>


Loading…
Cancel
Save