Browse Source

Merge PR #660 from @Noisyfox

Resolving domain name through socks5 proxy
and
dual-mode socket
tags/3.3
Syrone Wong 9 years ago
parent
commit
64e21e031d
11 changed files with 167 additions and 92 deletions
  1. +3
    -7
      shadowsocks-csharp/Controller/Service/PortForwarder.cs
  2. +12
    -27
      shadowsocks-csharp/Controller/Service/TCPRelay.cs
  3. +4
    -11
      shadowsocks-csharp/Controller/Service/UDPRelay.cs
  4. +3
    -1
      shadowsocks-csharp/Data/cn.txt
  5. +8
    -0
      shadowsocks-csharp/Program.cs
  6. +17
    -10
      shadowsocks-csharp/Proxy/DirectConnect.cs
  7. +1
    -1
      shadowsocks-csharp/Proxy/IProxy.cs
  8. +45
    -32
      shadowsocks-csharp/Proxy/Socks5Proxy.cs
  9. +66
    -0
      shadowsocks-csharp/Util/SocketUtil.cs
  10. +7
    -3
      shadowsocks-csharp/Util/Util.cs
  11. +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.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.


+ 12
- 27
shadowsocks-csharp/Controller/Service/TCPRelay.cs View File

@@ -9,6 +9,7 @@ using Shadowsocks.Controller.Strategy;
using Shadowsocks.Encryption;
using Shadowsocks.Model;
using Shadowsocks.Proxy;
using Shadowsocks.Util;
namespace Shadowsocks.Controller
{
@@ -302,7 +303,6 @@ namespace Shadowsocks.Controller
if (ar.AsyncState != null)
{
connection.EndSend(ar);
Logging.Debug(remote.LocalEndPoint, remote.DestEndPoint, RecvSize, "TCP Relay");
connection.BeginReceive(_connetionRecvBuffer, 0, RecvSize, SocketFlags.None, new AsyncCallback(ReadAll), null);
}
else
@@ -310,7 +310,6 @@ namespace Shadowsocks.Controller
int bytesRead = connection.EndReceive(ar);
if (bytesRead > 0)
{
Logging.Debug(remote.LocalEndPoint, remote.DestEndPoint, RecvSize, "TCP Relay");
connection.BeginReceive(_connetionRecvBuffer, 0, RecvSize, SocketFlags.None, new AsyncCallback(ReadAll), null);
}
else
@@ -341,6 +340,7 @@ namespace Shadowsocks.Controller
// inner class
private class ProxyTimer : Timer
{
public IProxy Proxy;
public EndPoint DestEndPoint;
public Server Server;
@@ -361,34 +361,17 @@ namespace Shadowsocks.Controller
{
CreateRemote();
// 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];
}
IPEndPoint destEP = new IPEndPoint(ipAddress, server.server_port);
// Setting up proxy
IPEndPoint proxyEP;
EndPoint proxyEP;
if (_config.useProxy)
{
parsed = IPAddress.TryParse(_config.proxyServer, out ipAddress);
if (!parsed)
{
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
{
remote = new DirectConnect();
proxyEP = destEP;
proxyEP = null;
}
@@ -396,7 +379,9 @@ namespace Shadowsocks.Controller
proxyTimer.AutoReset = false;
proxyTimer.Elapsed += proxyConnectTimer_Elapsed;
proxyTimer.Enabled = true;
proxyTimer.DestEndPoint = destEP;
proxyTimer.Proxy = remote;
proxyTimer.DestEndPoint = SocketUtil.GetEndPoint(server.server, server.server_port);
proxyTimer.Server = server;
_proxyConnected = false;
@@ -417,9 +402,9 @@ namespace Shadowsocks.Controller
{
return;
}
var ep = ((ProxyTimer)sender).DestEndPoint;
var proxy = ((ProxyTimer)sender).Proxy;
Logging.Info($"Proxy {ep} timed out");
Logging.Info($"Proxy {proxy.ProxyEndPoint} timed out");
remote?.Close();
RetryConnect();
}
@@ -434,7 +419,7 @@ namespace Shadowsocks.Controller
try
{
ProxyTimer timer = (ProxyTimer)ar.AsyncState;
var destEP = timer.DestEndPoint;
var destEndPoint = timer.DestEndPoint;
server = timer.Server;
timer.Elapsed -= proxyConnectTimer_Elapsed;
timer.Enabled = false;
@@ -462,7 +447,7 @@ namespace Shadowsocks.Controller
_destConnected = false;
// Connect to the remote endpoint.
remote.BeginConnectDest(destEP, new AsyncCallback(ConnectCallback), connectTimer);
remote.BeginConnectDest(destEndPoint, new AsyncCallback(ConnectCallback), connectTimer);
}
catch (ArgumentException)
{


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

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


+ 3
- 1
shadowsocks-csharp/Data/cn.txt View File

@@ -113,4 +113,6 @@ Failed to update registry=无法修改注册表
System Proxy On: =系统代理已启用:
Running: Port {0}=正在运行:端口 {0}
Unexpected error, shadowsocks will exit. Please report to=非预期错误,Shadowsocks将退出。请提交此错误到
Unsupported operating system, use Windows Vista at least.=不支持的操作系统版本,最低需求为Windows Vista。
Proxy request failed=代理请求失败
Proxy handshake failed=代理握手失败

+ 8
- 0
shadowsocks-csharp/Program.cs View File

@@ -18,6 +18,14 @@ namespace Shadowsocks
[STAThread]
static void Main()
{
// Check OS since we are using dual-mode socket
if (!Utils.IsWinVistaOrHigher())
{
MessageBox.Show(I18N.GetString("Unsupported operating system, use Windows Vista at least."),
"Shadowsocks Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
Utils.ReleaseMemory(true);
using (Mutex mutex = new Mutex(false, "Global\\Shadowsocks_" + Application.StartupPath.GetHashCode()))
{


+ 17
- 10
shadowsocks-csharp/Proxy/DirectConnect.cs View File

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

namespace Shadowsocks.Proxy
{
@@ -20,19 +21,26 @@ namespace Shadowsocks.Proxy
public bool CompletedSynchronously { get; } = true;
}

private class FakeEndPoint : EndPoint
{
public override AddressFamily AddressFamily { get; } = AddressFamily.Unspecified;

public override string ToString()
{
return "null proxy";
}
}

private Socket _remote;

public EndPoint LocalEndPoint => _remote.LocalEndPoint;

public EndPoint ProxyEndPoint { get; private set; }

public EndPoint ProxyEndPoint { get; } = new FakeEndPoint();
public EndPoint DestEndPoint { get; private set; }


public void BeginConnectProxy(EndPoint remoteEP, AsyncCallback callback, object state)
{
// do nothing
ProxyEndPoint = remoteEP;

var r = new FakeAsyncResult(state);
callback?.Invoke(r);
@@ -43,17 +51,16 @@ namespace Shadowsocks.Proxy
// do nothing
}

public void BeginConnectDest(EndPoint remoteEP, AsyncCallback callback, object state)
public void BeginConnectDest(EndPoint destEndPoint, AsyncCallback callback, object state)
{
DestEndPoint = destEndPoint;

if (_remote == null)
{
_remote = new Socket(remoteEP.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
_remote = SocketUtil.CreateSocket(destEndPoint);
_remote.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true);
}

DestEndPoint = remoteEP;

_remote.BeginConnect(remoteEP, callback, state);
_remote.BeginConnect(destEndPoint, callback, state);
}

public void EndConnectDest(IAsyncResult asyncResult)


+ 1
- 1
shadowsocks-csharp/Proxy/IProxy.cs View File

@@ -17,7 +17,7 @@ namespace Shadowsocks.Proxy

void EndConnectProxy(IAsyncResult asyncResult);

void BeginConnectDest(EndPoint remoteEP, AsyncCallback callback, object state);
void BeginConnectDest(EndPoint destEndPoint, AsyncCallback callback, object state);

void EndConnectDest(IAsyncResult asyncResult);



+ 45
- 32
shadowsocks-csharp/Proxy/Socks5Proxy.cs View File

@@ -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();
@@ -73,50 +74,62 @@ namespace Shadowsocks.Proxy
}
}

public void BeginConnectDest(EndPoint remoteEP, AsyncCallback callback, object state)
public void BeginConnectDest(EndPoint destEndPoint, AsyncCallback callback, object state)
{
var ep = remoteEP as IPEndPoint;
if (ep == null)
{
throw new Exception(I18N.GetString("Proxy request faild"));
}
DestEndPoint = destEndPoint;

byte[] request = null;
byte atyp = 0;
switch (ep.AddressFamily)
int port;

var dep = destEndPoint as DnsEndPoint;
if (dep != null)
{
case AddressFamily.InterNetwork:
request = new byte[4 + 4 + 2];
atyp = 1;
break;
case AddressFamily.InterNetworkV6:
request = new byte[4 + 16 + 2];
atyp = 4;
break;
// 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;
}
if (request == null)
else
{
throw new Exception(I18N.GetString("Proxy request faild"));
switch (DestEndPoint.AddressFamily)
{
case AddressFamily.InterNetwork:
request = new byte[4 + 4 + 2];
atyp = 1; // IP V4 address
break;
case AddressFamily.InterNetworkV6:
request = new byte[4 + 16 + 2];
atyp = 4; // IP V6 address
break;
default:
throw new Exception(I18N.GetString("Proxy request failed"));
}
port = ((IPEndPoint) DestEndPoint).Port;
var addr = ((IPEndPoint)DestEndPoint).Address.GetAddressBytes();
Array.Copy(addr, 0, request, 4, request.Length - 4 - 2);
}

// 构造request包
var addr = ep.Address.GetAddressBytes();
// 构造request包剩余部分
request[0] = 5;
request[1] = 1;
request[2] = 0;
request[3] = atyp;
Array.Copy(addr, 0, request, 4, request.Length - 4 - 2);
request[request.Length - 2] = (byte) ((ep.Port >> 8) & 0xff);
request[request.Length - 1] = (byte) (ep.Port & 0xff);
request[request.Length - 2] = (byte) ((port >> 8) & 0xff);
request[request.Length - 1] = (byte) (port & 0xff);

var st = new Socks5State();
st.Callback = callback;
st.AsyncState = state;

DestEndPoint = remoteEP;

_remote?.BeginSend(request, 0, request.Length, 0, Socks5RequestSendCallback, st);

}

public void EndConnectDest(IAsyncResult asyncResult)
@@ -206,12 +219,12 @@ namespace Shadowsocks.Proxy
{
if (_receiveBuffer[0] != 5 || _receiveBuffer[1] != 0)
{
ex = new Exception(I18N.GetString("Proxy handshake faild"));
ex = new Exception(I18N.GetString("Proxy handshake failed"));
}
}
else
{
ex = new Exception(I18N.GetString("Proxy handshake faild"));
ex = new Exception(I18N.GetString("Proxy handshake failed"));
}
}
catch (Exception ex2)
@@ -261,20 +274,20 @@ namespace Shadowsocks.Proxy
_remote.BeginReceive(_receiveBuffer, 0, 16 + 2, 0, Socks5ReplyReceiveCallback2, state);
break;
default:
state.ex = new Exception(I18N.GetString("Proxy request faild"));
state.ex = new Exception(I18N.GetString("Proxy request failed"));
state.Callback?.Invoke(new FakeAsyncResult(ar, state));
break;
}
}
else
{
state.ex = new Exception(I18N.GetString("Proxy request faild"));
state.ex = new Exception(I18N.GetString("Proxy request failed"));
state.Callback?.Invoke(new FakeAsyncResult(ar, state));
}
}
else
{
state.ex = new Exception(I18N.GetString("Proxy request faild"));
state.ex = new Exception(I18N.GetString("Proxy request failed"));
state.Callback?.Invoke(new FakeAsyncResult(ar, state));
}
}
@@ -297,7 +310,7 @@ namespace Shadowsocks.Proxy

if (bytesRead < bytesNeedSkip)
{
ex = new Exception(I18N.GetString("Proxy request faild"));
ex = new Exception(I18N.GetString("Proxy request failed"));
}
}
catch (Exception ex2)


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

+ 7
- 3
shadowsocks-csharp/Util/Util.cs View File

@@ -151,12 +151,16 @@ namespace Shadowsocks.Util
// we are building x86 binary for both x86 and x64, which will
// cause problem when opening registry key
// detect operating system instead of CPU
RegistryKey userKey = RegistryKey.OpenBaseKey( RegistryHive.CurrentUser,
Environment.Is64BitOperatingSystem ? RegistryView.Registry64 : RegistryView.Registry32 );
userKey = userKey.OpenSubKey( name, writable );
RegistryKey userKey = RegistryKey.OpenRemoteBaseKey( RegistryHive.CurrentUser, "",
Environment.Is64BitOperatingSystem ? RegistryView.Registry64 : RegistryView.Registry32 )
.OpenSubKey( name, writable );
return userKey;
}
public static bool IsWinVistaOrHigher() {
return Environment.OSVersion.Version.Major > 5;
}
[DllImport("kernel32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool SetProcessWorkingSetSize(IntPtr process,


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

@@ -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>


Loading…
Cancel
Save