From a8f0f58ed5d851a0c1be1ed4047f9dee520420b9 Mon Sep 17 00:00:00 2001 From: database64128 Date: Sat, 6 Mar 2021 21:47:04 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=8E=92=20CLI:=20legacy=20backend?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Shadowsocks.CLI/Backend.cs | 10 +++ Shadowsocks.CLI/Client/Legacy.cs | 57 +++++++++++++++++ Shadowsocks.CLI/Client/Pipelines.cs | 29 +++++++++ Shadowsocks.CLI/Program.cs | 88 +++++++++++++++++++++----- Shadowsocks.CLI/Shadowsocks.CLI.csproj | 1 + Shadowsocks.Net/TCPRelay.cs | 4 +- Shadowsocks.Net/UDPRelay.cs | 2 +- 7 files changed, 172 insertions(+), 19 deletions(-) create mode 100644 Shadowsocks.CLI/Backend.cs create mode 100644 Shadowsocks.CLI/Client/Legacy.cs create mode 100644 Shadowsocks.CLI/Client/Pipelines.cs diff --git a/Shadowsocks.CLI/Backend.cs b/Shadowsocks.CLI/Backend.cs new file mode 100644 index 00000000..dc25eae9 --- /dev/null +++ b/Shadowsocks.CLI/Backend.cs @@ -0,0 +1,10 @@ +namespace Shadowsocks.CLI +{ + public enum Backend + { + SsRust, + V2Ray, + Legacy, + Pipelines, + } +} diff --git a/Shadowsocks.CLI/Client/Legacy.cs b/Shadowsocks.CLI/Client/Legacy.cs new file mode 100644 index 00000000..86f463c9 --- /dev/null +++ b/Shadowsocks.CLI/Client/Legacy.cs @@ -0,0 +1,57 @@ +using Shadowsocks.Models; +using Shadowsocks.Net; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Net; +using System.Text; +using System.Threading.Tasks; + +namespace Shadowsocks.CLI.Client +{ + public class Legacy + { + private TCPListener? _tcpListener; + private UDPListener? _udpListener; + + public void Start(string listenSocks, string serverAddress, int serverPort, string method, string password, string? plugin, string? pluginOpts, string? pluginArgs) + { + var localEP = IPEndPoint.Parse(listenSocks); + var server = new Server() + { + Host = serverAddress, + Port = serverPort, + Method = method, + Password = password, + Plugin = plugin, + PluginOpts = pluginOpts, + }; + if (!string.IsNullOrEmpty(plugin) && !string.IsNullOrEmpty(pluginArgs)) + { + var processStartInfo = new ProcessStartInfo(plugin, pluginArgs); + server.PluginArgs = processStartInfo.ArgumentList.ToList(); + } + + var tcpRelay = new TCPRelay(server); + _tcpListener = new TCPListener(localEP, new List() + { + tcpRelay, + }); + _tcpListener.Start(); + + var udpRelay = new UDPRelay(server); + _udpListener = new UDPListener(localEP, new List() + { + udpRelay, + }); + _udpListener.Start(); + } + + public void Stop() + { + _tcpListener?.Stop(); + _udpListener?.Stop(); + } + } +} diff --git a/Shadowsocks.CLI/Client/Pipelines.cs b/Shadowsocks.CLI/Client/Pipelines.cs new file mode 100644 index 00000000..c0a69720 --- /dev/null +++ b/Shadowsocks.CLI/Client/Pipelines.cs @@ -0,0 +1,29 @@ +using Shadowsocks.Protocol; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Text; +using System.Threading.Tasks; + +namespace Shadowsocks.CLI.Client +{ + public class Pipelines + { + private TcpPipeListener? _tcpPipeListener; + + public Task Start(string listenSocks, string serverAddress, int serverPort, string method, string? password, string? key, string? plugin, string? pluginOpts, string? pluginArgs) + { + // TODO + var localEP = IPEndPoint.Parse(listenSocks); + var remoteEp = new DnsEndPoint(serverAddress, serverPort); + byte[]? mainKey = null; + if (!string.IsNullOrEmpty(key)) + mainKey = Encoding.UTF8.GetBytes(key); + _tcpPipeListener = new(localEP); + return _tcpPipeListener.Start(localEP, remoteEp, method, password, mainKey); + } + + public void Stop() => _tcpPipeListener?.Stop(); + } +} diff --git a/Shadowsocks.CLI/Program.cs b/Shadowsocks.CLI/Program.cs index f36383d9..fac9d985 100644 --- a/Shadowsocks.CLI/Program.cs +++ b/Shadowsocks.CLI/Program.cs @@ -1,8 +1,11 @@ -using Shadowsocks.Protocol; +using Shadowsocks.Models; +using Splat; using System; using System.Collections.Generic; using System.CommandLine; using System.CommandLine.Invocation; +using System.Diagnostics; +using System.Linq; using System.Net; using System.Text; using System.Threading; @@ -16,28 +19,81 @@ namespace Shadowsocks.CLI { var clientCommand = new Command("client", "Shadowsocks client."); clientCommand.AddAlias("c"); - clientCommand.AddOption(new Option("--listen", "The address and port to listen on for both SOCKS5 and HTTP proxy.")); - clientCommand.AddOption(new Option("--listen-socks", "The address and port to listen on for SOCKS5 proxy.")); - clientCommand.AddOption(new Option("--listen-http", "The address and port to listen on for HTTP proxy.")); + clientCommand.AddOption(new Option("--backend", "Shadowsocks backend to use. Available backends: shadowsocks-rust, v2ray, legacy, pipelines.")); + clientCommand.AddOption(new Option("--listen", "Address and port to listen on for both SOCKS5 and HTTP proxy.")); + clientCommand.AddOption(new Option("--listen-socks", "Address and port to listen on for SOCKS5 proxy.")); + clientCommand.AddOption(new Option("--listen-http", "Address and port to listen on for HTTP proxy.")); clientCommand.AddOption(new Option("--server-address", "Address of the remote Shadowsocks server to connect to.")); clientCommand.AddOption(new Option("--server-port", "Port of the remote Shadowsocks server to connect to.")); - clientCommand.AddOption(new Option("--method", "Encryption method to use for the remote Shadowsocks server.")); - clientCommand.AddOption(new Option("--password", "Password to use for the remote Shadowsocks server.")); - clientCommand.AddOption(new Option("--key", "Encryption key (NOT password!) to use for the remote Shadowsocks server.")); + clientCommand.AddOption(new Option("--method", "Encryption method to use for remote Shadowsocks server.")); + clientCommand.AddOption(new Option("--password", "Password to use for remote Shadowsocks server.")); + clientCommand.AddOption(new Option("--key", "Encryption key (NOT password!) to use for remote Shadowsocks server.")); clientCommand.AddOption(new Option("--plugin", "Plugin binary path.")); clientCommand.AddOption(new Option("--plugin-opts", "Plugin options.")); clientCommand.AddOption(new Option("--plugin-args", "Plugin startup arguments.")); clientCommand.Handler = CommandHandler.Create( - async (string? listen, string? listenSocks, string? listenHttp, string serverAddress, int serverPort, string method, string? password, string? key, string? plugin, string? pluginOpts, string? pluginArgs) => + async (Backend backend, string? listen, string? listenSocks, string? listenHttp, string serverAddress, int serverPort, string method, string? password, string? key, string? plugin, string? pluginOpts, string? pluginArgs, CancellationToken cancellationToken) => { - // TODO - var localEP = IPEndPoint.Parse(listenSocks); - var remoteEp = new DnsEndPoint(serverAddress, serverPort); - byte[]? mainKey = null; - if (!string.IsNullOrEmpty(key)) - mainKey = Encoding.UTF8.GetBytes(key); - var tcpPipeListener = new TcpPipeListener(localEP); - tcpPipeListener.Start(localEP, remoteEp, method, password, mainKey).Wait(); + Locator.CurrentMutable.RegisterConstant(new()); + if (string.IsNullOrEmpty(listenSocks)) + { + LogHost.Default.Error("You must specify SOCKS5 listen address and port."); + return; + } + + Client.Legacy? legacyClient = null; + Client.Pipelines? pipelinesClient = null; + + switch (backend) + { + case Backend.SsRust: + LogHost.Default.Error("Not implemented."); + break; + case Backend.V2Ray: + LogHost.Default.Error("Not implemented."); + break; + case Backend.Legacy: + if (!string.IsNullOrEmpty(password)) + { + legacyClient = new(); + legacyClient.Start(listenSocks, serverAddress, serverPort, method, password, plugin, pluginOpts, pluginArgs); + } + else + LogHost.Default.Error("The legacy backend requires password."); + break; + case Backend.Pipelines: + pipelinesClient = new(); + await pipelinesClient.Start(listenSocks, serverAddress, serverPort, method, password, key, plugin, pluginOpts, pluginArgs); + break; + default: + LogHost.Default.Error("Not implemented."); + break; + } + + while (!cancellationToken.IsCancellationRequested) + { + await Task.Delay(TimeSpan.FromHours(1.00), cancellationToken); + Console.WriteLine("An hour has passed."); + } + + switch (backend) + { + case Backend.SsRust: + LogHost.Default.Error("Not implemented."); + break; + case Backend.V2Ray: + LogHost.Default.Error("Not implemented."); + break; + case Backend.Legacy: + legacyClient?.Stop(); + break; + case Backend.Pipelines: + pipelinesClient?.Stop(); + break; + default: + LogHost.Default.Error("Not implemented."); + break; + } }); var serverCommand = new Command("server", "Shadowsocks server."); diff --git a/Shadowsocks.CLI/Shadowsocks.CLI.csproj b/Shadowsocks.CLI/Shadowsocks.CLI.csproj index 75f859d9..d6a93bdd 100644 --- a/Shadowsocks.CLI/Shadowsocks.CLI.csproj +++ b/Shadowsocks.CLI/Shadowsocks.CLI.csproj @@ -34,6 +34,7 @@ + diff --git a/Shadowsocks.Net/TCPRelay.cs b/Shadowsocks.Net/TCPRelay.cs index 91589765..698c69ad 100644 --- a/Shadowsocks.Net/TCPRelay.cs +++ b/Shadowsocks.Net/TCPRelay.cs @@ -16,7 +16,7 @@ using Shadowsocks.Models; namespace Shadowsocks.Net { - class TCPRelay : StreamService, IEnableLogger + public class TCPRelay : StreamService, IEnableLogger { public event EventHandler OnConnected; public event EventHandler OnInbound; @@ -182,7 +182,7 @@ namespace Shadowsocks.Net } } - internal class TCPHandler : IEnableLogger + public class TCPHandler : IEnableLogger { public event EventHandler OnConnected; public event EventHandler OnInbound; diff --git a/Shadowsocks.Net/UDPRelay.cs b/Shadowsocks.Net/UDPRelay.cs index 352b57f4..77ffabf3 100644 --- a/Shadowsocks.Net/UDPRelay.cs +++ b/Shadowsocks.Net/UDPRelay.cs @@ -12,7 +12,7 @@ using System.Threading.Tasks; namespace Shadowsocks.Net { - class UDPRelay : DatagramService + public class UDPRelay : DatagramService { Server _server; // TODO: choose a smart number