Browse Source

Merge pull request #2419 from Yifei0727/master

Support local IPv6 listener

# Conflicts:
#	shadowsocks-csharp/Model/Configuration.cs
tags/4.1.7
celeron533 6 years ago
parent
commit
554203aa74
9 changed files with 62 additions and 28 deletions
  1. +12
    -8
      shadowsocks-csharp/Controller/Service/Listener.cs
  2. +6
    -4
      shadowsocks-csharp/Controller/Service/PACServer.cs
  3. +2
    -1
      shadowsocks-csharp/Controller/Service/PortForwarder.cs
  4. +8
    -4
      shadowsocks-csharp/Controller/Service/PrivoxyRunner.cs
  5. +16
    -3
      shadowsocks-csharp/Controller/Service/UDPRelay.cs
  6. +4
    -4
      shadowsocks-csharp/Controller/Service/UpdateChecker.cs
  7. +1
    -1
      shadowsocks-csharp/Controller/System/SystemProxy.cs
  8. +1
    -1
      shadowsocks-csharp/Data/privoxy_conf.txt
  9. +12
    -2
      shadowsocks-csharp/Model/Configuration.cs

+ 12
- 8
shadowsocks-csharp/Controller/Service/Listener.cs View File

@@ -27,9 +27,14 @@ namespace Shadowsocks.Controller
public class UDPState public class UDPState
{ {
public UDPState(Socket s)
{
socket = s;
remoteEndPoint = new IPEndPoint(s.AddressFamily == AddressFamily.InterNetworkV6 ? IPAddress.IPv6Any : IPAddress.Any, 0);
}
public Socket socket; public Socket socket;
public byte[] buffer = new byte[4096]; public byte[] buffer = new byte[4096];
public EndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0);
public EndPoint remoteEndPoint;
} }
Configuration _config; Configuration _config;
@@ -60,14 +65,14 @@ namespace Shadowsocks.Controller
try try
{ {
// Create a TCP/IP socket. // Create a TCP/IP socket.
_tcpSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_udpSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
_tcpSocket = new Socket(config.isIPv6Enabled ? AddressFamily.InterNetworkV6 : AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_udpSocket = new Socket(config.isIPv6Enabled ? AddressFamily.InterNetworkV6 : AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
_tcpSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); _tcpSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
_udpSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); _udpSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
IPEndPoint localEndPoint = null; IPEndPoint localEndPoint = null;
localEndPoint = _shareOverLAN localEndPoint = _shareOverLAN
? new IPEndPoint(IPAddress.Any, _config.localPort)
: new IPEndPoint(IPAddress.Loopback, _config.localPort);
? new IPEndPoint(config.isIPv6Enabled ? IPAddress.IPv6Any : IPAddress.Any, _config.localPort)
: new IPEndPoint(config.isIPv6Enabled ? IPAddress.IPv6Loopback : IPAddress.Loopback, _config.localPort);
// Bind the socket to the local endpoint and listen for incoming connections. // Bind the socket to the local endpoint and listen for incoming connections.
_tcpSocket.Bind(localEndPoint); _tcpSocket.Bind(localEndPoint);
@@ -81,8 +86,7 @@ namespace Shadowsocks.Controller
Logging.Info(Encryption.EncryptorFactory.DumpRegisteredEncryptor()); Logging.Info(Encryption.EncryptorFactory.DumpRegisteredEncryptor());
} }
_tcpSocket.BeginAccept(new AsyncCallback(AcceptCallback), _tcpSocket); _tcpSocket.BeginAccept(new AsyncCallback(AcceptCallback), _tcpSocket);
UDPState udpState = new UDPState();
udpState.socket = _udpSocket;
UDPState udpState = new UDPState(_udpSocket);
_udpSocket.BeginReceiveFrom(udpState.buffer, 0, udpState.buffer.Length, 0, ref udpState.remoteEndPoint, new AsyncCallback(RecvFromCallback), udpState); _udpSocket.BeginReceiveFrom(udpState.buffer, 0, udpState.buffer.Length, 0, ref udpState.remoteEndPoint, new AsyncCallback(RecvFromCallback), udpState);
} }
catch (SocketException) catch (SocketException)
@@ -105,7 +109,7 @@ namespace Shadowsocks.Controller
_udpSocket = null; _udpSocket = null;
} }
_services.ForEach(s=>s.Stop());
_services.ForEach(s => s.Stop());
} }
public void RecvFromCallback(IAsyncResult ar) public void RecvFromCallback(IAsyncResult ar)


+ 6
- 4
shadowsocks-csharp/Controller/Service/PACServer.cs View File

@@ -51,7 +51,7 @@ namespace Shadowsocks.Controller
PacSecret = ""; PacSecret = "";
} }
PacUrl = $"http://127.0.0.1:{config.localPort}/pac?t={GetTimestamp(DateTime.Now)}{PacSecret}";
PacUrl = $"http://{config.localHost}:{config.localPort}/pac?t={GetTimestamp(DateTime.Now)}{PacSecret}";
} }
@@ -101,7 +101,7 @@ namespace Shadowsocks.Controller
} }
if (!secretMatch) if (!secretMatch)
{ {
if(line.IndexOf(PacSecret, StringComparison.Ordinal) >= 0)
if (line.IndexOf(PacSecret, StringComparison.Ordinal) >= 0)
{ {
secretMatch = true; secretMatch = true;
} }
@@ -255,7 +255,7 @@ Connection: Close
if (UserRuleFileChanged != null) if (UserRuleFileChanged != null)
{ {
Logging.Info($"Detected: User Rule file '{e.Name}' was {e.ChangeType.ToString().ToLower()}."); Logging.Info($"Detected: User Rule file '{e.Name}' was {e.ChangeType.ToString().ToLower()}.");
Task.Factory.StartNew(()=>
Task.Factory.StartNew(() =>
{ {
((FileSystemWatcher)sender).EnableRaisingEvents = false; ((FileSystemWatcher)sender).EnableRaisingEvents = false;
System.Threading.Thread.Sleep(10); System.Threading.Thread.Sleep(10);
@@ -268,7 +268,9 @@ Connection: Close
private string GetPACAddress(IPEndPoint localEndPoint, bool useSocks) private string GetPACAddress(IPEndPoint localEndPoint, bool useSocks)
{ {
return $"{(useSocks ? "SOCKS5" : "PROXY")} {localEndPoint.Address}:{_config.localPort};";
return localEndPoint.AddressFamily == AddressFamily.InterNetworkV6
? $"{(useSocks ? "SOCKS5" : "PROXY")} [{localEndPoint.Address}]:{_config.localPort};"
: $"{(useSocks ? "SOCKS5" : "PROXY")} {localEndPoint.Address}:{_config.localPort};";
} }
} }
} }

+ 2
- 1
shadowsocks-csharp/Controller/Service/PortForwarder.cs View File

@@ -49,7 +49,8 @@ namespace Shadowsocks.Controller
_local = socket; _local = socket;
try try
{ {
EndPoint remoteEP = SocketUtil.GetEndPoint("127.0.0.1", targetPort);
// Local Port Forward use IP as is
EndPoint remoteEP = SocketUtil.GetEndPoint(_local.AddressFamily == AddressFamily.InterNetworkV6 ? "[::1]" : "127.0.0.1", targetPort);
// Connect to the remote endpoint. // Connect to the remote endpoint.
_remote = new WrappedSocket(); _remote = new WrappedSocket();


+ 8
- 4
shadowsocks-csharp/Controller/Service/PrivoxyRunner.cs View File

@@ -49,10 +49,14 @@ namespace Shadowsocks.Controller
KillProcess(p); KillProcess(p);
} }
string privoxyConfig = Resources.privoxy_conf; string privoxyConfig = Resources.privoxy_conf;
_runningPort = GetFreePort();
_runningPort = GetFreePort(configuration.isIPv6Enabled);
privoxyConfig = privoxyConfig.Replace("__SOCKS_PORT__", configuration.localPort.ToString()); privoxyConfig = privoxyConfig.Replace("__SOCKS_PORT__", configuration.localPort.ToString());
privoxyConfig = privoxyConfig.Replace("__PRIVOXY_BIND_PORT__", _runningPort.ToString()); privoxyConfig = privoxyConfig.Replace("__PRIVOXY_BIND_PORT__", _runningPort.ToString());
privoxyConfig = privoxyConfig.Replace("__PRIVOXY_BIND_IP__", configuration.shareOverLan ? "0.0.0.0" : "127.0.0.1");
privoxyConfig = configuration.isIPv6Enabled
? privoxyConfig.Replace("__PRIVOXY_BIND_IP__", configuration.shareOverLan ? "[::]" : "[::1]")
.Replace("__SOCKS_HOST__", "[::1]")
: privoxyConfig.Replace("__PRIVOXY_BIND_IP__", configuration.shareOverLan ? "0.0.0.0" : "127.0.0.1")
.Replace("__SOCKS_HOST__", "127.0.0.1");
FileManager.ByteArrayToFile(Utils.GetTempPath(_uniqueConfigFile), Encoding.UTF8.GetBytes(privoxyConfig)); FileManager.ByteArrayToFile(Utils.GetTempPath(_uniqueConfigFile), Encoding.UTF8.GetBytes(privoxyConfig));
_process = new Process _process = new Process
@@ -140,13 +144,13 @@ namespace Shadowsocks.Controller
} }
} }
private int GetFreePort()
private int GetFreePort(bool isIPv6 = false)
{ {
int defaultPort = 8123; int defaultPort = 8123;
try try
{ {
// TCP stack please do me a favor // TCP stack please do me a favor
TcpListener l = new TcpListener(IPAddress.Loopback, 0);
TcpListener l = new TcpListener(isIPv6 ? IPAddress.IPv6Loopback : IPAddress.Loopback, 0);
l.Start(); l.Start();
var port = ((IPEndPoint)l.LocalEndpoint).Port; var port = ((IPEndPoint)l.LocalEndpoint).Port;
l.Stop(); l.Stop();


+ 16
- 3
shadowsocks-csharp/Controller/Service/UDPRelay.cs View File

@@ -58,6 +58,19 @@ namespace Shadowsocks.Controller
private IPEndPoint _localEndPoint; private IPEndPoint _localEndPoint;
private IPEndPoint _remoteEndPoint; private IPEndPoint _remoteEndPoint;
private IPAddress GetIPAddress()
{
switch (_remote.AddressFamily)
{
case AddressFamily.InterNetwork:
return IPAddress.Any;
case AddressFamily.InterNetworkV6:
return IPAddress.IPv6Any;
default:
return IPAddress.Any;
}
}
public UDPHandler(Socket local, Server server, IPEndPoint localEndPoint) public UDPHandler(Socket local, Server server, IPEndPoint localEndPoint)
{ {
_local = local; _local = local;
@@ -74,7 +87,7 @@ namespace Shadowsocks.Controller
} }
_remoteEndPoint = new IPEndPoint(ipAddress, server.server_port); _remoteEndPoint = new IPEndPoint(ipAddress, server.server_port);
_remote = new Socket(_remoteEndPoint.AddressFamily, SocketType.Dgram, ProtocolType.Udp); _remote = new Socket(_remoteEndPoint.AddressFamily, SocketType.Dgram, ProtocolType.Udp);
_remote.Bind(new IPEndPoint(IPAddress.Any, 0));
_remote.Bind(new IPEndPoint(GetIPAddress(), 0));
} }
public void Send(byte[] data, int length) public void Send(byte[] data, int length)
@@ -91,7 +104,7 @@ namespace Shadowsocks.Controller
public void Receive() public void Receive()
{ {
EndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0);
EndPoint remoteEndPoint = new IPEndPoint(GetIPAddress(), 0);
Logging.Debug($"++++++Receive Server Port, size:" + _buffer.Length); Logging.Debug($"++++++Receive Server Port, size:" + _buffer.Length);
_remote?.BeginReceiveFrom(_buffer, 0, _buffer.Length, 0, ref remoteEndPoint, new AsyncCallback(RecvFromCallback), null); _remote?.BeginReceiveFrom(_buffer, 0, _buffer.Length, 0, ref remoteEndPoint, new AsyncCallback(RecvFromCallback), null);
} }
@@ -101,7 +114,7 @@ namespace Shadowsocks.Controller
try try
{ {
if (_remote == null) return; if (_remote == null) return;
EndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0);
EndPoint remoteEndPoint = new IPEndPoint(GetIPAddress(), 0);
int bytesRead = _remote.EndReceiveFrom(ar, ref remoteEndPoint); int bytesRead = _remote.EndReceiveFrom(ar, ref remoteEndPoint);
byte[] dataOut = new byte[bytesRead]; byte[] dataOut = new byte[bytesRead];


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

@@ -84,7 +84,7 @@ namespace Shadowsocks.Controller
{ {
foreach (JObject release in result) foreach (JObject release in result)
{ {
var isPreRelease = (bool) release["prerelease"];
var isPreRelease = (bool)release["prerelease"];
if (isPreRelease && !config.checkPreRelease) if (isPreRelease && !config.checkPreRelease)
{ {
continue; continue;
@@ -170,7 +170,7 @@ namespace Shadowsocks.Controller
{ {
WebClient http = new WebClient(); WebClient http = new WebClient();
http.Headers.Add("User-Agent", UserAgent); http.Headers.Add("User-Agent", UserAgent);
http.Proxy = new WebProxy(IPAddress.Loopback.ToString(), config.localPort);
http.Proxy = new WebProxy(config.localHost, config.localPort);
return http; return http;
} }
@@ -189,7 +189,7 @@ namespace Shadowsocks.Controller
public static Asset ParseAsset(JObject assertJObject) public static Asset ParseAsset(JObject assertJObject)
{ {
var name = (string) assertJObject["name"];
var name = (string)assertJObject["name"];
Match match = Regex.Match(name, @"^Shadowsocks-(?<version>\d+(?:\.\d+)*)(?:|-(?<suffix>.+))\.\w+$", Match match = Regex.Match(name, @"^Shadowsocks-(?<version>\d+(?:\.\d+)*)(?:|-(?<suffix>.+))\.\w+$",
RegexOptions.IgnoreCase); RegexOptions.IgnoreCase);
if (match.Success) if (match.Success)
@@ -198,7 +198,7 @@ namespace Shadowsocks.Controller
var asset = new Asset var asset = new Asset
{ {
browser_download_url = (string) assertJObject["browser_download_url"],
browser_download_url = (string)assertJObject["browser_download_url"],
name = name, name = name,
version = version version = version
}; };


+ 1
- 1
shadowsocks-csharp/Controller/System/SystemProxy.cs View File

@@ -28,7 +28,7 @@ namespace Shadowsocks.Controller
{ {
if (global) if (global)
{ {
Sysproxy.SetIEProxy(true, true, "127.0.0.1:" + config.localPort.ToString(), null);
Sysproxy.SetIEProxy(true, true, "localhost:" + config.localPort.ToString(), null);
} }
else else
{ {


+ 1
- 1
shadowsocks-csharp/Data/privoxy_conf.txt View File

@@ -3,6 +3,6 @@ toggle 0
logfile ss_privoxy.log logfile ss_privoxy.log
show-on-task-bar 0 show-on-task-bar 0
activity-animation 0 activity-animation 0
forward-socks5 / 127.0.0.1:__SOCKS_PORT__ .
forward-socks5 / __SOCKS_HOST__:__SOCKS_PORT__ .
max-client-connections 2048 max-client-connections 2048
hide-console hide-console

+ 12
- 2
shadowsocks-csharp/Model/Configuration.cs View File

@@ -20,6 +20,7 @@ namespace Shadowsocks.Model
public bool enabled; public bool enabled;
public bool shareOverLan; public bool shareOverLan;
public bool isDefault; public bool isDefault;
public bool isIPv6Enabled = false;
public int localPort; public int localPort;
public bool portableMode = true; public bool portableMode = true;
public string pacUrl; public string pacUrl;
@@ -34,7 +35,11 @@ namespace Shadowsocks.Model
public HotkeyConfig hotkey; public HotkeyConfig hotkey;
private static readonly string CONFIG_FILE = "gui-config.json"; private static readonly string CONFIG_FILE = "gui-config.json";
[JsonIgnore]
public string localHost => GetLocalHost();
private string GetLocalHost() {
return isIPv6Enabled ? "[::1]" : "127.0.0.1";
}
public Server GetCurrentServer() public Server GetCurrentServer()
{ {
if (index >= 0 && index < configs.Count) if (index >= 0 && index < configs.Count)
@@ -86,6 +91,10 @@ namespace Shadowsocks.Model
config.proxy = new ProxyConfig(); config.proxy = new ProxyConfig();
if (config.hotkey == null) if (config.hotkey == null)
config.hotkey = new HotkeyConfig(); config.hotkey = new HotkeyConfig();
if (!System.Net.Sockets.Socket.OSSupportsIPv6) {
config.isIPv6Enabled = false; // disable IPv6 if os not support
}
//TODO if remote host(server) do not support IPv6 (or DNS resolve AAAA TYPE record) disable IPv6?
config.proxy.CheckConfig(); config.proxy.CheckConfig();
@@ -192,7 +201,8 @@ namespace Shadowsocks.Model
public static void CheckTimeout(int timeout, int maxTimeout) public static void CheckTimeout(int timeout, int maxTimeout)
{ {
if (timeout <= 0 || timeout > maxTimeout) if (timeout <= 0 || timeout > maxTimeout)
throw new ArgumentException(I18N.GetString("Timeout is invalid, it should not exceed {0}", maxTimeout));
throw new ArgumentException(
I18N.GetString("Timeout is invalid, it should not exceed {0}", maxTimeout));
} }
public static void CheckProxyAuthUser(string user) public static void CheckProxyAuthUser(string user)


Loading…
Cancel
Save