Merge PR #660 from @Noisyfox
Resolving domain name through socks5 proxy and dual-mode socket
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
|
||||
{
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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=代理握手失败
|
||||
|
||||
@@ -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()))
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
|
||||
@@ -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