├── .gitattributes ├── Shadowsocks.PAC ├── Resources │ ├── dlc.dat │ └── user-rule.txt ├── Shadowsocks.PAC.csproj └── PACSettings.cs ├── Shadowsocks.WPF ├── shadowsocks.ico ├── Resources │ ├── ss128.pdn │ ├── ss32.pdn │ ├── ss32Fill.png │ ├── ss32In.png │ ├── ss32Out.png │ ├── ssw128.png │ ├── privoxy.exe.gz │ ├── ss32Outline.png │ ├── RobotoMono │ │ ├── RobotoMono-Bold.ttf │ │ ├── RobotoMono-Italic.ttf │ │ ├── RobotoMono-Light.ttf │ │ ├── RobotoMono-Medium.ttf │ │ ├── RobotoMono-Thin.ttf │ │ ├── RobotoMono-Regular.ttf │ │ ├── RobotoMono-SemiBold.ttf │ │ ├── RobotoMono-BoldItalic.ttf │ │ ├── RobotoMono-ExtraLight.ttf │ │ ├── RobotoMono-LightItalic.ttf │ │ ├── RobotoMono-ThinItalic.ttf │ │ ├── RobotoMono-MediumItalic.ttf │ │ ├── RobotoMono-ExtraLightItalic.ttf │ │ └── RobotoMono-SemiBoldItalic.ttf │ └── privoxy_conf.txt ├── FodyWeavers.xml ├── Properties │ └── PublishProfiles │ │ ├── win-x64.pubxml.user │ │ ├── win-x86.pubxml.user │ │ ├── FolderProfile.pubxml │ │ ├── win-arm.pubxml │ │ ├── win-x64.pubxml │ │ └── win-x86.pubxml ├── ViewModels │ ├── RoutingViewModel.cs │ ├── ServersViewModel.cs │ ├── DashboardViewModel.cs │ ├── SettingsViewModel.cs │ ├── MainWindowViewModel.cs │ ├── VersionUpdatePromptViewModel.cs │ └── ServerSharingViewModel.cs ├── App.xaml.cs ├── Localization │ └── LocalizationProvider.cs ├── Models │ ├── Group.cs │ ├── Server.cs │ ├── AppSettings.cs │ └── Settings.cs ├── AssemblyInfo.cs ├── Views │ ├── RoutingView.xaml.cs │ ├── ServersView.xaml.cs │ ├── SettingsView.xaml.cs │ ├── DashboardView.xaml.cs │ ├── MainWindow.xaml.cs │ ├── VersionUpdatePromptView.xaml.cs │ ├── ServerSharingView.xaml.cs │ ├── ServersView.xaml │ ├── DashboardView.xaml │ ├── OnlineConfigView.xaml.cs │ ├── ServerSharingView.xaml │ ├── VersionUpdatePromptView.xaml │ ├── OnlineConfigView.xaml │ └── ForwardProxyView.xaml.cs ├── App.xaml ├── FodyWeavers.xsd ├── Services │ ├── OnlineConfigService.cs │ └── SystemProxy │ │ └── RAS.cs ├── Utils │ ├── FileManager.cs │ ├── SystemProxy.cs │ └── IPCService.cs └── App.manifest ├── Shadowsocks.Interop ├── V2Ray │ ├── StatsObject.cs │ ├── Protocols │ │ ├── UserObject.cs │ │ ├── VMess │ │ │ ├── DetourObject.cs │ │ │ ├── InboundConfigurationObject.cs │ │ │ ├── OutboundConfigurationObject.cs │ │ │ ├── UserObject.cs │ │ │ └── ServerObject.cs │ │ ├── AccountObject.cs │ │ ├── Trojan │ │ │ ├── ClientObject.cs │ │ │ ├── InboundConfigurationObject.cs │ │ │ ├── FallbackObject.cs │ │ │ ├── OutboundConfigurationObject.cs │ │ │ └── ServerObject.cs │ │ ├── Freedom │ │ │ └── OutboundConfigurationObject.cs │ │ ├── Socks │ │ │ ├── InboundConfigurationObject.cs │ │ │ ├── OutboundConfigurationObject.cs │ │ │ └── ServerObject.cs │ │ └── Shadowsocks │ │ │ ├── OutboundConfigurationObject.cs │ │ │ ├── InboundConfigurationObject.cs │ │ │ └── ServerObject.cs │ ├── Transport │ │ ├── HttpObject.cs │ │ ├── SockoptObject.cs │ │ ├── TlsObject.cs │ │ ├── Header │ │ │ ├── HttpHeaderObject.cs │ │ │ ├── HeaderObject.cs │ │ │ └── Http │ │ │ │ ├── HttpResponseObject.cs │ │ │ │ └── HttpRequestObject.cs │ │ ├── TcpObject.cs │ │ ├── DomainSocketObject.cs │ │ ├── CertificateObject.cs │ │ ├── WebSocketObject.cs │ │ ├── QuicObject.cs │ │ ├── KcpObject.cs │ │ └── StreamSettingsObject.cs │ ├── FakeDnsObject.cs │ ├── ReverseObject.cs │ ├── TransportObject.cs │ ├── Reverse │ │ ├── PortalObject.cs │ │ └── BridgeObject.cs │ ├── PolicyObject.cs │ ├── Policy │ │ ├── SystemPolicyObject.cs │ │ └── LevelPolicyObject.cs │ ├── Routing │ │ ├── BalancerObject.cs │ │ └── RuleObject.cs │ ├── Outbound │ │ ├── MuxObject.cs │ │ └── ProxySettingsObject.cs │ ├── LogObject.cs │ ├── ApiObject.cs │ ├── Inbound │ │ ├── AllocateObject.cs │ │ └── SniffingObject.cs │ ├── Config.cs │ ├── Dns │ │ └── ServerObject.cs │ ├── InboundObject.cs │ ├── DnsObject.cs │ ├── RoutingObject.cs │ └── OutboundObject.cs ├── Shadowsocks.Interop.csproj ├── Settings │ └── InteropSettings.cs └── Utils │ └── JsonHelper.cs ├── Shadowsocks.WPF.Tests ├── DataUsageTests.cs └── Shadowsocks.WPF.Tests.csproj ├── Shadowsocks.CLI ├── Backend.cs ├── Client │ ├── Pipelines.cs │ └── Legacy.cs └── Shadowsocks.CLI.csproj ├── Shadowsocks ├── Shadowsocks.csproj ├── Models │ ├── IGroup.cs │ ├── Group.cs │ ├── IServer.cs │ └── JsonSnakeCaseNamingPolicy.cs └── Utilities │ └── Base64Url.cs ├── Shadowsocks.Protocol ├── IStreamClient.cs ├── IStreamService.cs ├── Shadowsocks.Protocol.csproj ├── Shadowsocks │ ├── Crypto │ │ ├── AeadAesGcmCrypto.cs │ │ ├── AeadChaCha20Poly1305Crypto.cs │ │ ├── AeadXChaCha20Poly1305Crypto.cs │ │ ├── CryptoParameter.cs │ │ ├── UnsafeNoneCrypto.cs │ │ ├── AeadCrypto.cs │ │ ├── CryptoProvider.cs │ │ └── CryptoUtils.cs │ ├── ICrypto.cs │ ├── PayloadProtocolClient.cs │ ├── SaltMessage.cs │ ├── ShadowsocksClient.cs │ ├── AeadBlockMessage.cs │ └── UnsafeClient.cs ├── Direct │ └── PortForwardService.cs ├── TcpPipeClient.cs ├── DuplexPipe.cs ├── IProtocolMessage.cs ├── PipePair.cs ├── Socks5 │ ├── Socks5UserPasswordResponseMessage.cs │ ├── Socks5MethodSelectionMessage.cs │ ├── Socks5VersionIdentifierMessage.cs │ ├── Socks5UserPasswordRequestMessage.cs │ ├── Socks5UdpMessage.cs │ ├── Socks5Client.cs │ └── Socks5RequestReplyMessage.cs ├── Util.cs └── TcpPipeListener.cs ├── Shadowsocks.Protobuf ├── Shadowsocks.Protobuf.csproj └── geosite.proto ├── Shadowsocks.Net ├── Crypto │ ├── CryptoUtils.cs │ ├── ICrypto.cs │ ├── Exception │ │ └── CryptoException.cs │ ├── TCPInfo.cs │ ├── RNG.cs │ ├── Stream │ │ ├── StreamPlainNativeCrypto.cs │ │ └── StreamCryptoBaseCrypto.cs │ ├── CryptoBase.cs │ ├── AEAD │ │ └── AEADCryptoBaseCrypto.cs │ └── CipherInfo.cs ├── Shadowsocks.Net.csproj ├── Proxy │ ├── IProxy.cs │ └── DirectConnect.cs ├── Settings │ ├── ForwardProxySettings.cs │ └── NetSettings.cs └── SystemProxy │ └── ProxyException.cs ├── nuget.config ├── CONTRIBUTING.md ├── .github ├── ISSUE_TEMPLATE │ ├── feature_request.md │ ├── bug_report_zh.md │ └── bug_report_en.md └── PULL_REQUEST_TEMPLATE.md └── Shadowsocks.Tests └── Shadowsocks.Tests.csproj /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | 3 | # geosite database 4 | *.dat binary -------------------------------------------------------------------------------- /Shadowsocks.PAC/Resources/dlc.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ybNero/shadowsocks-windows/main/Shadowsocks.PAC/Resources/dlc.dat -------------------------------------------------------------------------------- /Shadowsocks.WPF/shadowsocks.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ybNero/shadowsocks-windows/main/Shadowsocks.WPF/shadowsocks.ico -------------------------------------------------------------------------------- /Shadowsocks.WPF/Resources/ss128.pdn: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ybNero/shadowsocks-windows/main/Shadowsocks.WPF/Resources/ss128.pdn -------------------------------------------------------------------------------- /Shadowsocks.WPF/Resources/ss32.pdn: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ybNero/shadowsocks-windows/main/Shadowsocks.WPF/Resources/ss32.pdn -------------------------------------------------------------------------------- /Shadowsocks.WPF/Resources/ss32Fill.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ybNero/shadowsocks-windows/main/Shadowsocks.WPF/Resources/ss32Fill.png -------------------------------------------------------------------------------- /Shadowsocks.WPF/Resources/ss32In.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ybNero/shadowsocks-windows/main/Shadowsocks.WPF/Resources/ss32In.png -------------------------------------------------------------------------------- /Shadowsocks.WPF/Resources/ss32Out.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ybNero/shadowsocks-windows/main/Shadowsocks.WPF/Resources/ss32Out.png -------------------------------------------------------------------------------- /Shadowsocks.WPF/Resources/ssw128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ybNero/shadowsocks-windows/main/Shadowsocks.WPF/Resources/ssw128.png -------------------------------------------------------------------------------- /Shadowsocks.PAC/Resources/user-rule.txt: -------------------------------------------------------------------------------- 1 | ! Put user rules line by line in this file. 2 | ! See https://adblockplus.org/en/filter-cheatsheet 3 | -------------------------------------------------------------------------------- /Shadowsocks.WPF/Resources/privoxy.exe.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ybNero/shadowsocks-windows/main/Shadowsocks.WPF/Resources/privoxy.exe.gz -------------------------------------------------------------------------------- /Shadowsocks.Interop/V2Ray/StatsObject.cs: -------------------------------------------------------------------------------- 1 | namespace Shadowsocks.Interop.V2Ray 2 | { 3 | public class StatsObject 4 | { 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Shadowsocks.WPF/Resources/ss32Outline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ybNero/shadowsocks-windows/main/Shadowsocks.WPF/Resources/ss32Outline.png -------------------------------------------------------------------------------- /Shadowsocks.WPF/FodyWeavers.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /Shadowsocks.WPF/Resources/RobotoMono/RobotoMono-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ybNero/shadowsocks-windows/main/Shadowsocks.WPF/Resources/RobotoMono/RobotoMono-Bold.ttf -------------------------------------------------------------------------------- /Shadowsocks.WPF/Resources/RobotoMono/RobotoMono-Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ybNero/shadowsocks-windows/main/Shadowsocks.WPF/Resources/RobotoMono/RobotoMono-Italic.ttf -------------------------------------------------------------------------------- /Shadowsocks.WPF/Resources/RobotoMono/RobotoMono-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ybNero/shadowsocks-windows/main/Shadowsocks.WPF/Resources/RobotoMono/RobotoMono-Light.ttf -------------------------------------------------------------------------------- /Shadowsocks.WPF/Resources/RobotoMono/RobotoMono-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ybNero/shadowsocks-windows/main/Shadowsocks.WPF/Resources/RobotoMono/RobotoMono-Medium.ttf -------------------------------------------------------------------------------- /Shadowsocks.WPF/Resources/RobotoMono/RobotoMono-Thin.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ybNero/shadowsocks-windows/main/Shadowsocks.WPF/Resources/RobotoMono/RobotoMono-Thin.ttf -------------------------------------------------------------------------------- /Shadowsocks.WPF/Resources/RobotoMono/RobotoMono-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ybNero/shadowsocks-windows/main/Shadowsocks.WPF/Resources/RobotoMono/RobotoMono-Regular.ttf -------------------------------------------------------------------------------- /Shadowsocks.WPF/Resources/RobotoMono/RobotoMono-SemiBold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ybNero/shadowsocks-windows/main/Shadowsocks.WPF/Resources/RobotoMono/RobotoMono-SemiBold.ttf -------------------------------------------------------------------------------- /Shadowsocks.WPF/Resources/RobotoMono/RobotoMono-BoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ybNero/shadowsocks-windows/main/Shadowsocks.WPF/Resources/RobotoMono/RobotoMono-BoldItalic.ttf -------------------------------------------------------------------------------- /Shadowsocks.WPF/Resources/RobotoMono/RobotoMono-ExtraLight.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ybNero/shadowsocks-windows/main/Shadowsocks.WPF/Resources/RobotoMono/RobotoMono-ExtraLight.ttf -------------------------------------------------------------------------------- /Shadowsocks.WPF/Resources/RobotoMono/RobotoMono-LightItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ybNero/shadowsocks-windows/main/Shadowsocks.WPF/Resources/RobotoMono/RobotoMono-LightItalic.ttf -------------------------------------------------------------------------------- /Shadowsocks.WPF/Resources/RobotoMono/RobotoMono-ThinItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ybNero/shadowsocks-windows/main/Shadowsocks.WPF/Resources/RobotoMono/RobotoMono-ThinItalic.ttf -------------------------------------------------------------------------------- /Shadowsocks.WPF.Tests/DataUsageTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Xunit; 3 | 4 | namespace Shadowsocks.WPF.Tests 5 | { 6 | public class DataUsageTests 7 | { 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Shadowsocks.WPF/Resources/RobotoMono/RobotoMono-MediumItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ybNero/shadowsocks-windows/main/Shadowsocks.WPF/Resources/RobotoMono/RobotoMono-MediumItalic.ttf -------------------------------------------------------------------------------- /Shadowsocks.WPF/Resources/RobotoMono/RobotoMono-ExtraLightItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ybNero/shadowsocks-windows/main/Shadowsocks.WPF/Resources/RobotoMono/RobotoMono-ExtraLightItalic.ttf -------------------------------------------------------------------------------- /Shadowsocks.WPF/Resources/RobotoMono/RobotoMono-SemiBoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ybNero/shadowsocks-windows/main/Shadowsocks.WPF/Resources/RobotoMono/RobotoMono-SemiBoldItalic.ttf -------------------------------------------------------------------------------- /Shadowsocks.CLI/Backend.cs: -------------------------------------------------------------------------------- 1 | namespace Shadowsocks.CLI 2 | { 3 | public enum Backend 4 | { 5 | SsRust, 6 | V2Ray, 7 | Legacy, 8 | Pipelines, 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Shadowsocks.Interop/V2Ray/Protocols/UserObject.cs: -------------------------------------------------------------------------------- 1 | namespace Shadowsocks.Interop.V2Ray.Protocols 2 | { 3 | public class UserObject : AccountObject 4 | { 5 | public int Level { get; set; } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /Shadowsocks/Shadowsocks.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net5.0 5 | enable 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Shadowsocks.WPF/Properties/PublishProfiles/win-x64.pubxml.user: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /Shadowsocks.WPF/Properties/PublishProfiles/win-x86.pubxml.user: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /Shadowsocks.WPF/Resources/privoxy_conf.txt: -------------------------------------------------------------------------------- 1 | listen-address __PRIVOXY_BIND_IP__:__PRIVOXY_BIND_PORT__ 2 | toggle 0 3 | logfile ss_privoxy.log 4 | show-on-task-bar 0 5 | activity-animation 0 6 | forward-socks5 / __SOCKS_HOST__:__SOCKS_PORT__ . 7 | max-client-connections 2048 8 | hide-console 9 | -------------------------------------------------------------------------------- /Shadowsocks.Protocol/IStreamClient.cs: -------------------------------------------------------------------------------- 1 | using System.IO.Pipelines; 2 | using System.Net; 3 | using System.Threading.Tasks; 4 | 5 | namespace Shadowsocks.Protocol 6 | { 7 | interface IStreamClient 8 | { 9 | Task Connect(EndPoint destination, IDuplexPipe client, IDuplexPipe server); 10 | } 11 | } -------------------------------------------------------------------------------- /Shadowsocks.Interop/V2Ray/Protocols/VMess/DetourObject.cs: -------------------------------------------------------------------------------- 1 | namespace Shadowsocks.Interop.V2Ray.Protocols.VMess 2 | { 3 | public class DetourObject 4 | { 5 | public string To { get; set; } 6 | 7 | public DetourObject() 8 | { 9 | To = ""; 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Shadowsocks.Protobuf/Shadowsocks.Protobuf.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net5.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /Shadowsocks.Protocol/IStreamService.cs: -------------------------------------------------------------------------------- 1 | using System.IO.Pipelines; 2 | using System.Threading.Tasks; 3 | 4 | namespace Shadowsocks.Protocol 5 | { 6 | public interface IStreamService 7 | { 8 | Task IsMyClient(IDuplexPipe pipe); 9 | Task Handle(IDuplexPipe pipe); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Shadowsocks.Interop/Shadowsocks.Interop.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net5.0 5 | enable 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /Shadowsocks.WPF/ViewModels/RoutingViewModel.cs: -------------------------------------------------------------------------------- 1 | using ReactiveUI; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | 6 | namespace Shadowsocks.WPF.ViewModels 7 | { 8 | public class RoutingViewModel : ReactiveObject 9 | { 10 | public RoutingViewModel() 11 | { 12 | 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Shadowsocks.WPF/ViewModels/ServersViewModel.cs: -------------------------------------------------------------------------------- 1 | using ReactiveUI; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | 6 | namespace Shadowsocks.WPF.ViewModels 7 | { 8 | public class ServersViewModel : ReactiveObject 9 | { 10 | public ServersViewModel() 11 | { 12 | 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Shadowsocks.WPF/ViewModels/DashboardViewModel.cs: -------------------------------------------------------------------------------- 1 | using ReactiveUI; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | 6 | namespace Shadowsocks.WPF.ViewModels 7 | { 8 | public class DashboardViewModel : ReactiveObject 9 | { 10 | public DashboardViewModel() 11 | { 12 | 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Shadowsocks.WPF/ViewModels/SettingsViewModel.cs: -------------------------------------------------------------------------------- 1 | using ReactiveUI; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | 6 | namespace Shadowsocks.WPF.ViewModels 7 | { 8 | public class SettingsViewModel : ReactiveObject 9 | { 10 | public SettingsViewModel() 11 | { 12 | 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Shadowsocks.Interop/V2Ray/Protocols/AccountObject.cs: -------------------------------------------------------------------------------- 1 | namespace Shadowsocks.Interop.V2Ray.Protocols 2 | { 3 | public class AccountObject 4 | { 5 | public string User { get; set; } 6 | public string Pass { get; set; } 7 | 8 | public AccountObject() 9 | { 10 | User = ""; 11 | Pass = ""; 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Shadowsocks.Net/Crypto/CryptoUtils.cs: -------------------------------------------------------------------------------- 1 | using CryptoBase.Digests.MD5; 2 | 3 | namespace Shadowsocks.Net.Crypto 4 | { 5 | public static class CryptoUtils 6 | { 7 | public static byte[] MD5(byte[] b) 8 | { 9 | var hash = new byte[CryptoBase.MD5Length]; 10 | MD5Utils.Default(b, hash); 11 | return hash; 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Shadowsocks.Interop/V2Ray/Protocols/Trojan/ClientObject.cs: -------------------------------------------------------------------------------- 1 | namespace Shadowsocks.Interop.V2Ray.Protocols.Trojan 2 | { 3 | public class ClientObject 4 | { 5 | public string Password { get; set; } 6 | public string? Email { get; set; } 7 | public int? Level { get; set; } 8 | 9 | public ClientObject() 10 | { 11 | Password = ""; 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Shadowsocks.Interop/V2Ray/Transport/HttpObject.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Shadowsocks.Interop.V2Ray.Transport 4 | { 5 | public class HttpObject 6 | { 7 | public List Host { get; set; } 8 | public string Path { get; set; } 9 | 10 | public HttpObject() 11 | { 12 | Host = new(); 13 | Path = "/"; 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Shadowsocks.Protocol/Shadowsocks.Protocol.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net5.0 5 | enable 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /Shadowsocks.Interop/V2Ray/Transport/SockoptObject.cs: -------------------------------------------------------------------------------- 1 | namespace Shadowsocks.Interop.V2Ray.Transport 2 | { 3 | public class SockoptObject 4 | { 5 | public int Mark { get; set; } 6 | public bool TcpFastOpen { get; set; } 7 | public string? Tproxy { get; set; } 8 | 9 | public static SockoptObject DefaultLinux => new() 10 | { 11 | Tproxy = "off", 12 | }; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Shadowsocks.Protocol/Shadowsocks/Crypto/AeadAesGcmCrypto.cs: -------------------------------------------------------------------------------- 1 | using CryptoBase; 2 | 3 | namespace Shadowsocks.Protocol.Shadowsocks.Crypto 4 | { 5 | public class AeadAesGcmCrypto : AeadCrypto 6 | { 7 | public AeadAesGcmCrypto(CryptoParameter parameter) : base(parameter) 8 | { 9 | } 10 | 11 | public override void Init(byte[] key, byte[] iv) => crypto = AEADCryptoCreate.AesGcm(key); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Shadowsocks.Protocol/Direct/PortForwardService.cs: -------------------------------------------------------------------------------- 1 | using System.IO.Pipelines; 2 | using System.Threading.Tasks; 3 | 4 | namespace Shadowsocks.Protocol.Direct 5 | { 6 | public class PortForwardService : IStreamService 7 | { 8 | public async Task Handle(IDuplexPipe pipe) => await Task.FromResult(null); 9 | 10 | public Task IsMyClient(IDuplexPipe pipe) => Task.FromResult(true); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Shadowsocks.Net/Crypto/ICrypto.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Shadowsocks.Net.Crypto 4 | { 5 | public interface ICrypto : IDisposable 6 | { 7 | int Encrypt(ReadOnlySpan plain, Span cipher); 8 | int Decrypt(Span plain, ReadOnlySpan cipher); 9 | int EncryptUDP(ReadOnlySpan plain, Span cipher); 10 | int DecryptUDP(Span plain, ReadOnlySpan cipher); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /nuget.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /Shadowsocks.Protocol/Shadowsocks/ICrypto.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Shadowsocks.Protocol.Shadowsocks 4 | { 5 | // stream cipher simply ignore nonce 6 | public interface ICrypto : IDisposable 7 | { 8 | void Init(byte[] key, byte[] iv); 9 | int Encrypt(ReadOnlySpan nonce, ReadOnlySpan plain, Span cipher); 10 | int Decrypt(ReadOnlySpan nonce, Span plain, ReadOnlySpan cipher); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Shadowsocks.Interop/V2Ray/FakeDnsObject.cs: -------------------------------------------------------------------------------- 1 | namespace Shadowsocks.Interop.V2Ray 2 | { 3 | public class FakeDnsObject 4 | { 5 | /// 6 | /// Gets or sets the IP pool CIDR. 7 | /// 8 | public string IpPool { get; set; } = "198.18.0.0/15"; 9 | 10 | /// 11 | /// Gets or sets the IP pool size. 12 | /// 13 | public long PoolSize { get; set; } = 65535L; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Shadowsocks.Net/Shadowsocks.Net.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net5.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /Shadowsocks.Protocol/Shadowsocks/Crypto/AeadChaCha20Poly1305Crypto.cs: -------------------------------------------------------------------------------- 1 | using CryptoBase; 2 | 3 | namespace Shadowsocks.Protocol.Shadowsocks.Crypto 4 | { 5 | public class AeadChaCha20Poly1305Crypto : AeadCrypto 6 | { 7 | public AeadChaCha20Poly1305Crypto(CryptoParameter parameter) : base(parameter) 8 | { 9 | } 10 | 11 | public override void Init(byte[] key, byte[] iv) => crypto = AEADCryptoCreate.ChaCha20Poly1305(key); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Shadowsocks.Protocol/Shadowsocks/Crypto/AeadXChaCha20Poly1305Crypto.cs: -------------------------------------------------------------------------------- 1 | using CryptoBase; 2 | 3 | namespace Shadowsocks.Protocol.Shadowsocks.Crypto 4 | { 5 | public class AeadXChaCha20Poly1305Crypto : AeadCrypto 6 | { 7 | public AeadXChaCha20Poly1305Crypto(CryptoParameter parameter) : base(parameter) 8 | { 9 | } 10 | 11 | public override void Init(byte[] key, byte[] iv) => crypto = AEADCryptoCreate.XChaCha20Poly1305(key); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Shadowsocks.Interop/V2Ray/Transport/TlsObject.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Shadowsocks.Interop.V2Ray.Transport 4 | { 5 | public class TlsObject 6 | { 7 | public string? ServerName { get; set; } 8 | public bool AllowInsecure { get; set; } 9 | public List? Alpn { get; set; } 10 | public List? Certificates { get; set; } 11 | public bool DisableSystemRoot { get; set; } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Shadowsocks.Interop/V2Ray/Protocols/Freedom/OutboundConfigurationObject.cs: -------------------------------------------------------------------------------- 1 | namespace Shadowsocks.Interop.V2Ray.Protocols.Freedom 2 | { 3 | public class OutboundConfigurationObject 4 | { 5 | public string DomainStrategy { get; set; } 6 | public string? Redirect { get; set; } 7 | public int? UserLevel { get; set; } 8 | 9 | public OutboundConfigurationObject() 10 | { 11 | DomainStrategy = "AsIs"; 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Shadowsocks.WPF/App.xaml.cs: -------------------------------------------------------------------------------- 1 | using ReactiveUI; 2 | 3 | using Splat; 4 | 5 | using System.Reflection; 6 | using System.Windows; 7 | 8 | namespace Shadowsocks.WPF 9 | { 10 | /// 11 | /// Interaction logic for App.xaml 12 | /// 13 | public partial class App : Application 14 | { 15 | public App() 16 | { 17 | Locator.CurrentMutable.RegisterViewsForViewModels(Assembly.GetCallingAssembly()); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Shadowsocks.Interop/V2Ray/ReverseObject.cs: -------------------------------------------------------------------------------- 1 | using Shadowsocks.Interop.V2Ray.Reverse; 2 | using System.Collections.Generic; 3 | 4 | namespace Shadowsocks.Interop.V2Ray 5 | { 6 | public class ReverseObject 7 | { 8 | public List Bridges { get; set; } 9 | public List Portals { get; set; } 10 | 11 | public ReverseObject() 12 | { 13 | Bridges = new(); 14 | Portals = new(); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Shadowsocks/Models/IGroup.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Shadowsocks.Models 4 | { 5 | public interface IGroup 6 | { 7 | /// 8 | /// Gets or sets the SIP008 configuration version. 9 | /// 10 | public int Version { get; set; } 11 | 12 | /// 13 | /// Gets or sets the list of servers in the group. 14 | /// 15 | public List Servers { get; set; } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Shadowsocks.Net/Crypto/Exception/CryptoException.cs: -------------------------------------------------------------------------------- 1 | namespace Shadowsocks.Net.Crypto.Exception 2 | { 3 | public class CryptoErrorException : System.Exception 4 | { 5 | public CryptoErrorException() 6 | { 7 | } 8 | 9 | public CryptoErrorException(string msg) : base(msg) 10 | { 11 | } 12 | 13 | public CryptoErrorException(string message, System.Exception innerException) : base(message, innerException) 14 | { 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Shadowsocks.WPF/Localization/LocalizationProvider.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using WPFLocalizeExtension.Extensions; 3 | 4 | namespace Shadowsocks.WPF.Localization 5 | { 6 | public class LocalizationProvider 7 | { 8 | private static readonly string CallingAssemblyName = Assembly.GetCallingAssembly().GetName().Name ?? "Shadowsocks.WPF"; 9 | 10 | public static T GetLocalizedValue(string key) => LocExtension.GetLocalizedValue($"{CallingAssemblyName}:Strings:{key}"); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Shadowsocks.Interop/V2Ray/Protocols/Trojan/InboundConfigurationObject.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Shadowsocks.Interop.V2Ray.Protocols.Trojan 4 | { 5 | public class InboundConfigurationObject 6 | { 7 | public List Clients { get; set; } 8 | public List Fallbacks { get; set; } 9 | 10 | public InboundConfigurationObject() 11 | { 12 | Clients = new(); 13 | Fallbacks = new(); 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Shadowsocks.Interop/V2Ray/Protocols/VMess/InboundConfigurationObject.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Shadowsocks.Interop.V2Ray.Protocols.VMess 4 | { 5 | public class InboundConfigurationObject 6 | { 7 | public List Clients { get; set; } 8 | public UserObject? Default { get; set; } 9 | public DetourObject? Detour { get; set; } 10 | 11 | public InboundConfigurationObject() 12 | { 13 | Clients = new(); 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Shadowsocks.WPF/Properties/PublishProfiles/FolderProfile.pubxml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | Release 8 | Any CPU 9 | bin\Release\net5.0-windows10.0.19041.0\publish\ 10 | FileSystem 11 | 12 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | How to Contribute 2 | ================= 3 | 4 | Pull Requests 5 | ------------- 6 | 7 | 1. Pull requests are welcome. 8 | 2. Make sure to pass the unit tests. Write unit tests for new modules if 9 | needed. 10 | 3. Search before sending new pull request. 11 | 12 | Issues 13 | ------ 14 | 15 | 1. **DO NOT post question about connection problem in issue tracker**, read [Troubleshooting]. 16 | 2. Search before sending new issue. 17 | 18 | [Troubleshooting]: https://github.com/shadowsocks/shadowsocks-windows/wiki/Troubleshooting 19 | -------------------------------------------------------------------------------- /Shadowsocks.Interop/Settings/InteropSettings.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Shadowsocks.Interop.Settings 8 | { 9 | public class InteropSettings 10 | { 11 | public string SsRustPath { get; set; } 12 | public string V2RayCorePath { get; set; } 13 | 14 | public InteropSettings() 15 | { 16 | SsRustPath = ""; 17 | V2RayCorePath = ""; 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Shadowsocks.Protocol/TcpPipeClient.cs: -------------------------------------------------------------------------------- 1 | using Pipelines.Sockets.Unofficial; 2 | using System.IO.Pipelines; 3 | using System.Net; 4 | using System.Threading.Tasks; 5 | 6 | namespace Shadowsocks.Protocol 7 | { 8 | public class TcpPipeClient : IStreamClient 9 | { 10 | public async Task Connect(EndPoint destination, IDuplexPipe client, IDuplexPipe server) 11 | { 12 | var sc = await SocketConnection.ConnectAsync(destination); 13 | await DuplexPipe.CopyDuplexPipe(client, sc); 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Shadowsocks.WPF/Models/Group.cs: -------------------------------------------------------------------------------- 1 | namespace Shadowsocks.WPF.Models 2 | { 3 | public class Group : Shadowsocks.Models.Group 4 | { 5 | /// 6 | /// Gets or sets the URL of SIP008 online configuration delivery source. 7 | /// 8 | public string OnlineConfigSource { get; set; } 9 | 10 | public Group() : this(string.Empty) 11 | { } 12 | 13 | public Group(string name) : base(name) 14 | { 15 | OnlineConfigSource = ""; 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Shadowsocks.Interop/V2Ray/TransportObject.cs: -------------------------------------------------------------------------------- 1 | using Shadowsocks.Interop.V2Ray.Transport; 2 | 3 | namespace Shadowsocks.Interop.V2Ray 4 | { 5 | public class TransportObject 6 | { 7 | public TcpObject? TcpSettings { get; set; } 8 | public KcpObject? KcpSettings { get; set; } 9 | public WebSocketObject? WsSettings { get; set; } 10 | public HttpObject? HttpSettings { get; set; } 11 | public QuicObject? QuicSettings { get; set; } 12 | public DomainSocketObject? DsSettings { get; set; } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Shadowsocks.Interop/V2Ray/Transport/Header/HttpHeaderObject.cs: -------------------------------------------------------------------------------- 1 | using Shadowsocks.Interop.V2Ray.Transport.Header.Http; 2 | 3 | namespace Shadowsocks.Interop.V2Ray.Transport.Header 4 | { 5 | public class HttpHeaderObject : HeaderObject 6 | { 7 | public HttpRequestObject request { get; set; } 8 | 9 | public HttpResponseObject response { get; set; } 10 | 11 | public HttpHeaderObject() 12 | { 13 | Type = "http"; 14 | request = new(); 15 | response = new(); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Shadowsocks.Protocol/DuplexPipe.cs: -------------------------------------------------------------------------------- 1 | using System.IO.Pipelines; 2 | using System.Threading.Tasks; 3 | 4 | namespace Shadowsocks.Protocol 5 | { 6 | class DuplexPipe : IDuplexPipe 7 | { 8 | public PipeReader Input { get; set; } 9 | public PipeWriter Output { get; set; } 10 | 11 | public static Task CopyDuplexPipe(IDuplexPipe p1, IDuplexPipe p2) 12 | { 13 | var t1 = p1.Input.CopyToAsync(p2.Output); 14 | var t2 = p2.Input.CopyToAsync(p1.Output); 15 | 16 | return Task.WhenAll(t1, t2); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Shadowsocks.Interop/V2Ray/Reverse/PortalObject.cs: -------------------------------------------------------------------------------- 1 | namespace Shadowsocks.Interop.V2Ray.Reverse 2 | { 3 | public class PortalObject 4 | { 5 | /// 6 | /// Gets or sets the outbound tag for the portal. 7 | /// 8 | public string Tag { get; set; } 9 | 10 | /// 11 | /// Gets or sets the domain name for the portal. 12 | /// 13 | public string Domain { get; set; } 14 | 15 | public PortalObject() 16 | { 17 | Tag = ""; 18 | Domain = ""; 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Shadowsocks.Interop/V2Ray/Reverse/BridgeObject.cs: -------------------------------------------------------------------------------- 1 | namespace Shadowsocks.Interop.V2Ray.Reverse 2 | { 3 | public class BridgeObject 4 | { 5 | /// 6 | /// Gets or sets the inbound tag for the bridge. 7 | /// 8 | public string Tag { get; set; } 9 | 10 | /// 11 | /// Gets or sets the domain name for the bridge. 12 | /// Can be omitted. 13 | /// 14 | public string? Domain { get; set; } 15 | 16 | public BridgeObject() 17 | { 18 | Tag = ""; 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Shadowsocks.Interop/V2Ray/Transport/Header/HeaderObject.cs: -------------------------------------------------------------------------------- 1 | namespace Shadowsocks.Interop.V2Ray.Transport.Header 2 | { 3 | public class HeaderObject 4 | { 5 | /// 6 | /// Gets or sets the header type. 7 | /// Defaults to none. 8 | /// Available values: 9 | /// none 10 | /// srtp 11 | /// utp 12 | /// wechat-video 13 | /// dtls 14 | /// wireguard 15 | /// 16 | public string Type { get; set; } 17 | 18 | public HeaderObject() 19 | { 20 | Type = "none"; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Shadowsocks.Interop/V2Ray/Protocols/Trojan/FallbackObject.cs: -------------------------------------------------------------------------------- 1 | namespace Shadowsocks.Interop.V2Ray.Protocols.Trojan 2 | { 3 | public class FallbackObject 4 | { 5 | public string? Alpn { get; set; } 6 | public string? Path { get; set; } 7 | public object Dest { get; set; } 8 | public int? Xver { get; set; } 9 | 10 | public FallbackObject() 11 | { 12 | Dest = 0; 13 | } 14 | 15 | public static FallbackObject Default => new() 16 | { 17 | Alpn = "", 18 | Path = "", 19 | Xver = 0, 20 | }; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Shadowsocks.WPF/Models/Server.cs: -------------------------------------------------------------------------------- 1 | namespace Shadowsocks.WPF.Models 2 | { 3 | public class Server : Shadowsocks.Models.Server 4 | { 5 | /// 6 | /// Gets or sets the amount of data ingress in bytes. 7 | /// 8 | public ulong BytesIngress { get; set; } 9 | 10 | /// 11 | /// Gets or sets the amount of data egress in bytes. 12 | /// 13 | public ulong BytesEgress { get; set; } 14 | 15 | public Server() 16 | { 17 | BytesIngress = 0UL; 18 | BytesEgress = 0UL; 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Shadowsocks.Interop/V2Ray/PolicyObject.cs: -------------------------------------------------------------------------------- 1 | using Shadowsocks.Interop.V2Ray.Policy; 2 | using System.Collections.Generic; 3 | 4 | namespace Shadowsocks.Interop.V2Ray 5 | { 6 | public class PolicyObject 7 | { 8 | public Dictionary? Levels { get; set; } 9 | public SystemPolicyObject? System { get; set; } 10 | 11 | /// 12 | /// Gets the default policy object. 13 | /// 14 | public static PolicyObject Default => new() 15 | { 16 | Levels = new(), 17 | System = SystemPolicyObject.Default, 18 | }; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Shadowsocks.Interop/V2Ray/Protocols/VMess/OutboundConfigurationObject.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Shadowsocks.Interop.V2Ray.Protocols.VMess 4 | { 5 | public class OutboundConfigurationObject 6 | { 7 | public List Vnext { get; set; } 8 | 9 | public OutboundConfigurationObject() 10 | { 11 | Vnext = new(); 12 | } 13 | 14 | public OutboundConfigurationObject(string address, int port, string id) 15 | { 16 | Vnext = new() 17 | { 18 | new(address, port, id), 19 | }; 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Shadowsocks.WPF/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | 3 | [assembly: ThemeInfo( 4 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located 5 | //(used if a resource is not found in the page, 6 | // or application resource dictionaries) 7 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located 8 | //(used if a resource is not found in the page, 9 | // app, or any theme specific resource dictionaries) 10 | )] 11 | -------------------------------------------------------------------------------- /Shadowsocks.Interop/V2Ray/Protocols/Socks/InboundConfigurationObject.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Shadowsocks.Interop.V2Ray.Protocols.Socks 4 | { 5 | public class InboundConfigurationObject 6 | { 7 | public string? Auth { get; set; } 8 | public List? Accounts { get; set; } 9 | public bool? Udp { get; set; } 10 | public string? Ip { get; set; } 11 | public int? UserLevel { get; set; } 12 | 13 | public static InboundConfigurationObject Default => new() 14 | { 15 | Udp = true, 16 | Ip = "127.0.0.1", 17 | }; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Shadowsocks.Interop/V2Ray/Protocols/VMess/UserObject.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Shadowsocks.Interop.V2Ray.Protocols.VMess 4 | { 5 | /// 6 | /// The user object for VMess AEAD. 7 | /// 8 | public class UserObject 9 | { 10 | public string Id { get; set; } 11 | public string? Email { get; set; } 12 | public int Level { get; set; } 13 | 14 | public UserObject(string id = "") 15 | { 16 | Id = id; 17 | } 18 | 19 | public static UserObject Default => new() 20 | { 21 | Id = Guid.NewGuid().ToString(), 22 | }; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Shadowsocks.Interop/V2Ray/Protocols/Trojan/OutboundConfigurationObject.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Shadowsocks.Interop.V2Ray.Protocols.Trojan 4 | { 5 | public class OutboundConfigurationObject 6 | { 7 | public List Servers { get; set; } 8 | 9 | public OutboundConfigurationObject() 10 | { 11 | Servers = new(); 12 | } 13 | 14 | public OutboundConfigurationObject(string address, int port, string password) 15 | { 16 | Servers = new() 17 | { 18 | new(address, port, password), 19 | }; 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Shadowsocks.Protocol/IProtocolMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Shadowsocks.Protocol 4 | { 5 | public interface IProtocolMessage : IEquatable 6 | { 7 | public int Serialize(Memory buffer); 8 | /// 9 | /// 10 | /// 11 | /// 12 | /// Tuple represent load state, 13 | /// when success, length is how many byte has been taken 14 | /// when fail, length is how many byte required, 0 is parse error 15 | /// 16 | public (bool success, int length) TryLoad(ReadOnlyMemory buffer); 17 | } 18 | } -------------------------------------------------------------------------------- /Shadowsocks.Interop/V2Ray/Policy/SystemPolicyObject.cs: -------------------------------------------------------------------------------- 1 | namespace Shadowsocks.Interop.V2Ray.Policy 2 | { 3 | public class SystemPolicyObject 4 | { 5 | public bool StatsInboundUplink { get; set; } 6 | public bool StatsInboundDownlink { get; set; } 7 | public bool StatsOutboundUplink { get; set; } 8 | public bool StatsOutboundDownlink { get; set; } 9 | 10 | public static SystemPolicyObject Default => new() 11 | { 12 | StatsInboundUplink = true, 13 | StatsInboundDownlink = true, 14 | StatsOutboundUplink = true, 15 | StatsOutboundDownlink = true, 16 | }; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Shadowsocks.Interop/V2Ray/Protocols/Shadowsocks/OutboundConfigurationObject.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Shadowsocks.Interop.V2Ray.Protocols.Shadowsocks 4 | { 5 | public class OutboundConfigurationObject 6 | { 7 | public List Servers { get; set; } 8 | 9 | public OutboundConfigurationObject() 10 | { 11 | Servers = new(); 12 | } 13 | 14 | public OutboundConfigurationObject(string address, int port, string method, string password) 15 | { 16 | Servers = new() 17 | { 18 | new(address, port, method, password), 19 | }; 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Shadowsocks.WPF/Models/AppSettings.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace Shadowsocks.WPF.Models 6 | { 7 | public class AppSettings 8 | { 9 | public bool StartOnBoot { get; set; } 10 | public bool AssociateSsLinks { get; set; } 11 | public bool VersionUpdateCheckForPrerelease { get; set; } 12 | public string SkippedUpdateVersion { get; set; } 13 | 14 | public AppSettings() 15 | { 16 | StartOnBoot = false; 17 | AssociateSsLinks = false; 18 | VersionUpdateCheckForPrerelease = false; 19 | SkippedUpdateVersion = ""; 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. -------------------------------------------------------------------------------- /Shadowsocks.Interop/V2Ray/Routing/BalancerObject.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Shadowsocks.Interop.V2Ray.Routing 4 | { 5 | public class BalancerObject 6 | { 7 | /// 8 | /// Gets or sets the outbound tag for the load balancer. 9 | /// 10 | public string Tag { get; set; } 11 | 12 | /// 13 | /// Gets or sets a list of outbound tags 14 | /// to include in the load balancer. 15 | /// 16 | public List Selector { get; set; } 17 | 18 | public BalancerObject() 19 | { 20 | Tag = ""; 21 | Selector = new(); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Shadowsocks.Interop/V2Ray/Protocols/Socks/OutboundConfigurationObject.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Net; 3 | 4 | namespace Shadowsocks.Interop.V2Ray.Protocols.Socks 5 | { 6 | public class OutboundConfigurationObject 7 | { 8 | public List Servers { get; set; } 9 | 10 | public OutboundConfigurationObject() 11 | { 12 | Servers = new(); 13 | } 14 | 15 | public OutboundConfigurationObject(DnsEndPoint socksEndPoint, string username = "", string password = "") 16 | { 17 | Servers = new() 18 | { 19 | new(socksEndPoint, username, password), 20 | }; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Shadowsocks.Protocol/Shadowsocks/Crypto/CryptoParameter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Shadowsocks.Protocol.Shadowsocks.Crypto 4 | { 5 | public struct CryptoParameter 6 | { 7 | public Type Crypto; 8 | public int KeySize; // key size = salt size 9 | public int NonceSize; // reused as iv size 10 | public int TagSize; 11 | 12 | public ICrypto GetCrypto() 13 | { 14 | var ctor = Crypto.GetConstructor(new[] { typeof(CryptoParameter) }) ?? 15 | throw new TypeLoadException("can't load constructor"); 16 | return (ICrypto)ctor.Invoke(new object[] { this }); 17 | } 18 | 19 | public bool IsAead => TagSize > 0; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Shadowsocks.Protocol/Shadowsocks/PayloadProtocolClient.cs: -------------------------------------------------------------------------------- 1 | using Shadowsocks.Protocol.Socks5; 2 | using System.IO.Pipelines; 3 | using System.Net; 4 | using System.Threading.Tasks; 5 | 6 | namespace Shadowsocks.Protocol.Shadowsocks 7 | { 8 | // shadowsocks payload protocol client 9 | class PayloadProtocolClient : IStreamClient 10 | { 11 | public async Task Connect(EndPoint destination, IDuplexPipe client, IDuplexPipe server) 12 | { 13 | var addrMem = server.Output.GetMemory(512); 14 | 15 | var addrLen = Socks5Message.SerializeAddress(addrMem, destination); 16 | server.Output.Advance(addrLen); 17 | 18 | await DuplexPipe.CopyDuplexPipe(client, server); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Shadowsocks.WPF/ViewModels/MainWindowViewModel.cs: -------------------------------------------------------------------------------- 1 | using ReactiveUI; 2 | using ReactiveUI.Fody.Helpers; 3 | using Shadowsocks.WPF.Views; 4 | 5 | namespace Shadowsocks.WPF.ViewModels 6 | { 7 | public class MainWindowViewModel : ReactiveObject 8 | { 9 | public MainWindowViewModel() 10 | { 11 | GetDashboardView = new(); 12 | GetServersView = new(); 13 | GetRoutingView = new(); 14 | GetSettingsView = new(); 15 | } 16 | 17 | public DashboardView GetDashboardView { get; } 18 | 19 | public ServersView GetServersView { get; } 20 | 21 | public RoutingView GetRoutingView { get; } 22 | 23 | public SettingsView GetSettingsView { get; } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Shadowsocks.Interop/V2Ray/Protocols/Shadowsocks/InboundConfigurationObject.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text.Json.Serialization; 3 | 4 | namespace Shadowsocks.Interop.V2Ray.Protocols.Shadowsocks 5 | { 6 | public class InboundConfigurationObject 7 | { 8 | public string? Email { get; set; } 9 | 10 | public string Method { get; set; } 11 | 12 | public string Password { get; set; } 13 | 14 | public int? Level { get; set; } 15 | 16 | public string Network { get; set; } 17 | 18 | public InboundConfigurationObject() 19 | { 20 | Method = "chacha20-ietf-poly1305"; 21 | Password = Guid.NewGuid().ToString(); 22 | Network = "tcp,udp"; 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Shadowsocks.Interop/V2Ray/Protocols/Trojan/ServerObject.cs: -------------------------------------------------------------------------------- 1 | namespace Shadowsocks.Interop.V2Ray.Protocols.Trojan 2 | { 3 | public class ServerObject 4 | { 5 | public string Address { get; set; } 6 | public int Port { get; set; } 7 | public string Password { get; set; } 8 | public string? Email { get; set; } 9 | public int? Level { get; set; } 10 | 11 | public ServerObject() 12 | { 13 | Address = ""; 14 | Port = 0; 15 | Password = ""; 16 | } 17 | 18 | public ServerObject(string address, int port, string password) 19 | { 20 | Address = address; 21 | Port = port; 22 | Password = password; 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report_zh.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug报告 (中文) 3 | about: 反馈Bug 4 | title: '' 5 | labels: bug report 6 | assignees: '' 7 | 8 | --- 9 | 10 | 17 | 18 | ### 简要描述问题 19 | 20 | ### 环境 21 | 22 | - Shadowsocks客户端版本: 23 | - 操作系统版本: 24 | - .NET版本: 25 | 26 | ### 操作步骤 27 | 28 | 29 | ### 期望的结果 30 | 31 | 32 | ### 实际结果 33 | 34 | 35 | ### 配置文件和日志文件(请隐去敏感信息) 36 | 37 | ``` 38 | 在此粘贴日志 39 | ``` 40 | -------------------------------------------------------------------------------- /Shadowsocks.Interop/V2Ray/Protocols/VMess/ServerObject.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Shadowsocks.Interop.V2Ray.Protocols.VMess 4 | { 5 | public class ServerObject 6 | { 7 | public string Address { get; set; } 8 | public int Port { get; set; } 9 | public List Users { get; set; } 10 | 11 | public ServerObject() 12 | { 13 | Address = ""; 14 | Port = 0; 15 | Users = new(); 16 | } 17 | 18 | public ServerObject(string address, int port, string id) 19 | { 20 | Address = address; 21 | Port = port; 22 | Users = new() 23 | { 24 | new(id), 25 | }; 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Shadowsocks.Interop/V2Ray/Outbound/MuxObject.cs: -------------------------------------------------------------------------------- 1 | namespace Shadowsocks.Interop.V2Ray.Outbound 2 | { 3 | public class MuxObject 4 | { 5 | /// 6 | /// Gets or sets whether to enable mux. 7 | /// Defaults to false (disabled). 8 | /// 9 | public bool Enabled { get; set; } 10 | 11 | /// 12 | /// Gets or sets the concurrency for a single TCP connection when using mux. 13 | /// Defaults to 8. 14 | /// Range: [1, 1024]. 15 | /// Set to -1 to disable the mux module. 16 | /// 17 | public int Concurrency { get; set; } 18 | 19 | public MuxObject() 20 | { 21 | Enabled = false; 22 | Concurrency = 8; 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Shadowsocks.Net/Crypto/TCPInfo.cs: -------------------------------------------------------------------------------- 1 | using Shadowsocks.Net.Crypto.AEAD; 2 | 3 | namespace Shadowsocks.Net.Crypto 4 | { 5 | public static class TCPParameter 6 | { 7 | // each recv size. 8 | public const int RecvSize = 2048; 9 | 10 | // overhead of one chunk, reserved for AEAD ciphers 11 | // /* two tags */ 12 | public const int ChunkOverheadSize = 16 * 2 + AEADCrypto.ChunkLengthBytes; 13 | 14 | // max chunk size 15 | public const uint MaxChunkSize = AEADCrypto.ChunkLengthMask + AEADCrypto.ChunkLengthBytes + 16 * 2; 16 | 17 | // In general, the ciphertext length, we should take overhead into account 18 | public const int BufferSize = RecvSize + (int)MaxChunkSize + 32 /* max salt len */; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Shadowsocks.Interop/V2Ray/Transport/TcpObject.cs: -------------------------------------------------------------------------------- 1 | using Shadowsocks.Interop.V2Ray.Transport.Header; 2 | 3 | namespace Shadowsocks.Interop.V2Ray.Transport 4 | { 5 | public class TcpObject 6 | { 7 | /// 8 | /// Gets or sets whether to use PROXY protocol. 9 | /// 10 | public bool AcceptProxyProtocol { get; set; } 11 | 12 | /// 13 | /// Gets or sets the header options. 14 | /// 15 | public object Header { get; set; } 16 | 17 | public TcpObject() 18 | { 19 | AcceptProxyProtocol = false; 20 | Header = new HeaderObject(); 21 | } 22 | 23 | public static TcpObject DefaultHttp => new() 24 | { 25 | Header = new HttpHeaderObject(), 26 | }; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Shadowsocks.WPF/Properties/PublishProfiles/win-arm.pubxml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | Release 8 | Any CPU 9 | bin\Release\net5.0-windows10.0.19041.0\win-arm\publish\ 10 | FileSystem 11 | net5.0-windows 12 | win-arm 13 | true 14 | True 15 | False 16 | True 17 | 18 | -------------------------------------------------------------------------------- /Shadowsocks.WPF/Properties/PublishProfiles/win-x64.pubxml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | Release 8 | Any CPU 9 | bin\Release\net5.0-windows10.0.19041.0\win-x64\publish\ 10 | FileSystem 11 | net5.0-windows 12 | win-x64 13 | true 14 | True 15 | False 16 | True 17 | 18 | -------------------------------------------------------------------------------- /Shadowsocks.WPF/Properties/PublishProfiles/win-x86.pubxml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | Release 8 | Any CPU 9 | bin\Release\net5.0-windows10.0.19041.0\win-x86\publish\ 10 | FileSystem 11 | net5.0-windows 12 | win-x86 13 | true 14 | True 15 | False 16 | True 17 | 18 | -------------------------------------------------------------------------------- /Shadowsocks.WPF/Models/Settings.cs: -------------------------------------------------------------------------------- 1 | using Shadowsocks.Interop.Settings; 2 | using Shadowsocks.Net.Settings; 3 | using Shadowsocks.PAC; 4 | using System.Collections.Generic; 5 | 6 | namespace Shadowsocks.WPF.Models 7 | { 8 | public class Settings 9 | { 10 | public AppSettings App { get; set; } 11 | 12 | public InteropSettings Interop { get; set; } 13 | 14 | public NetSettings Net { get; set; } 15 | 16 | public PACSettings PAC { get; set; } 17 | 18 | public List Groups { get; set; } 19 | 20 | public Settings() 21 | { 22 | App = new AppSettings(); 23 | Interop = new InteropSettings(); 24 | Net = new NetSettings(); 25 | PAC = new PACSettings(); 26 | Groups = new List(); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Shadowsocks.Interop/V2Ray/Policy/LevelPolicyObject.cs: -------------------------------------------------------------------------------- 1 | namespace Shadowsocks.Interop.V2Ray.Policy 2 | { 3 | public class LevelPolicyObject 4 | { 5 | public int? Handshake { get; set; } 6 | public int? ConnIdle { get; set; } 7 | public int? UplinkOnly { get; set; } 8 | public int? DownlinkOnly { get; set; } 9 | public bool? StatsUserUplink { get; set; } 10 | public bool? StatsUserDownlink { get; set; } 11 | public int? BufferSize { get; set; } 12 | 13 | public static LevelPolicyObject Default => new() 14 | { 15 | Handshake = 4, 16 | ConnIdle = 300, 17 | UplinkOnly = 2, 18 | DownlinkOnly = 5, 19 | StatsUserUplink = false, 20 | StatsUserDownlink = false, 21 | BufferSize = 512, 22 | }; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Shadowsocks.Protocol/Shadowsocks/Crypto/UnsafeNoneCrypto.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Shadowsocks.Protocol.Shadowsocks.Crypto 4 | { 5 | class UnsafeNoneCrypto : ICrypto 6 | { 7 | public UnsafeNoneCrypto(CryptoParameter parameter) 8 | { 9 | } 10 | 11 | public int Decrypt(ReadOnlySpan nonce, Span plain, ReadOnlySpan cipher) 12 | { 13 | cipher.CopyTo(plain); 14 | return plain.Length; 15 | } 16 | 17 | public int Encrypt(ReadOnlySpan nonce, ReadOnlySpan plain, Span cipher) 18 | { 19 | plain.CopyTo(cipher); 20 | return plain.Length; 21 | } 22 | 23 | public void Init(byte[] key, byte[] iv) 24 | { 25 | } 26 | 27 | public void Dispose() 28 | { 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Shadowsocks.WPF/Views/RoutingView.xaml.cs: -------------------------------------------------------------------------------- 1 | using ReactiveUI; 2 | using Shadowsocks.WPF.ViewModels; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Text; 6 | using System.Windows; 7 | using System.Windows.Controls; 8 | using System.Windows.Data; 9 | using System.Windows.Documents; 10 | using System.Windows.Input; 11 | using System.Windows.Media; 12 | using System.Windows.Media.Imaging; 13 | using System.Windows.Navigation; 14 | using System.Windows.Shapes; 15 | 16 | namespace Shadowsocks.WPF.Views 17 | { 18 | /// 19 | /// Interaction logic for RoutingView.xaml 20 | /// 21 | public partial class RoutingView 22 | { 23 | public RoutingView() 24 | { 25 | InitializeComponent(); 26 | this.WhenActivated(disposables => 27 | { 28 | 29 | }); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Shadowsocks.WPF/Views/ServersView.xaml.cs: -------------------------------------------------------------------------------- 1 | using ReactiveUI; 2 | using Shadowsocks.WPF.ViewModels; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Text; 6 | using System.Windows; 7 | using System.Windows.Controls; 8 | using System.Windows.Data; 9 | using System.Windows.Documents; 10 | using System.Windows.Input; 11 | using System.Windows.Media; 12 | using System.Windows.Media.Imaging; 13 | using System.Windows.Navigation; 14 | using System.Windows.Shapes; 15 | 16 | namespace Shadowsocks.WPF.Views 17 | { 18 | /// 19 | /// Interaction logic for ServersView.xaml 20 | /// 21 | public partial class ServersView 22 | { 23 | public ServersView() 24 | { 25 | InitializeComponent(); 26 | this.WhenActivated(disposables => 27 | { 28 | 29 | }); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Shadowsocks.WPF/Views/SettingsView.xaml.cs: -------------------------------------------------------------------------------- 1 | using ReactiveUI; 2 | using Shadowsocks.WPF.ViewModels; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Text; 6 | using System.Windows; 7 | using System.Windows.Controls; 8 | using System.Windows.Data; 9 | using System.Windows.Documents; 10 | using System.Windows.Input; 11 | using System.Windows.Media; 12 | using System.Windows.Media.Imaging; 13 | using System.Windows.Navigation; 14 | using System.Windows.Shapes; 15 | 16 | namespace Shadowsocks.WPF.Views 17 | { 18 | /// 19 | /// Interaction logic for SettingsView.xaml 20 | /// 21 | public partial class SettingsView 22 | { 23 | public SettingsView() 24 | { 25 | InitializeComponent(); 26 | this.WhenActivated(disposables => 27 | { 28 | 29 | }); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Shadowsocks.WPF/Views/DashboardView.xaml.cs: -------------------------------------------------------------------------------- 1 | using ReactiveUI; 2 | using Shadowsocks.WPF.ViewModels; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Text; 6 | using System.Windows; 7 | using System.Windows.Controls; 8 | using System.Windows.Data; 9 | using System.Windows.Documents; 10 | using System.Windows.Input; 11 | using System.Windows.Media; 12 | using System.Windows.Media.Imaging; 13 | using System.Windows.Navigation; 14 | using System.Windows.Shapes; 15 | 16 | namespace Shadowsocks.WPF.Views 17 | { 18 | /// 19 | /// Interaction logic for DashboardView.xaml 20 | /// 21 | public partial class DashboardView 22 | { 23 | public DashboardView() 24 | { 25 | InitializeComponent(); 26 | this.WhenActivated(disposables => 27 | { 28 | 29 | }); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Shadowsocks/Utilities/Base64Url.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text; 3 | 4 | namespace Shadowsocks.Utilities 5 | { 6 | public static class Base64Url 7 | { 8 | public static string Encode(string data) => Encode(Encoding.UTF8.GetBytes(data)); 9 | 10 | public static string Encode(byte[] bytes) => Convert.ToBase64String(bytes).TrimEnd('=').Replace('+', '-').Replace('/', '_'); 11 | 12 | public static string DecodeToString(string base64url) => Encoding.UTF8.GetString(DecodeToBytes(base64url)); 13 | 14 | public static byte[] DecodeToBytes(string base64url) 15 | { 16 | var base64string = base64url.Replace('_', '/').Replace('-', '+'); 17 | base64string = base64string.PadRight(base64string.Length + (4 - base64string.Length % 4) % 4, '='); 18 | return Convert.FromBase64String(base64string); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Shadowsocks.Interop/V2Ray/Transport/DomainSocketObject.cs: -------------------------------------------------------------------------------- 1 | namespace Shadowsocks.Interop.V2Ray.Transport 2 | { 3 | public class DomainSocketObject 4 | { 5 | /// 6 | /// Gets or sets the path to the unix domain socket file. 7 | /// 8 | public string Path { get; set; } 9 | 10 | /// 11 | /// Gets or sets whether the domain socket is abstract. 12 | /// Defaults to false. 13 | /// 14 | public bool Abstract { get; set; } 15 | 16 | /// 17 | /// Gets or sets whether padding is used. 18 | /// Defaults to false. 19 | /// 20 | public bool Padding { get; set; } 21 | 22 | public DomainSocketObject() 23 | { 24 | Path = ""; 25 | Abstract = false; 26 | Padding = false; 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Shadowsocks.Net/Proxy/IProxy.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | using System.Net.Sockets; 4 | using System.Threading; 5 | using System.Threading.Tasks; 6 | 7 | namespace Shadowsocks.Net.Proxy 8 | { 9 | public interface IProxy 10 | { 11 | EndPoint LocalEndPoint { get; } 12 | 13 | EndPoint ProxyEndPoint { get; } 14 | 15 | EndPoint DestEndPoint { get; } 16 | 17 | Task ConnectProxyAsync(EndPoint remoteEP, NetworkCredential auth = null, CancellationToken token = default); 18 | 19 | Task ConnectRemoteAsync(EndPoint destEndPoint, CancellationToken token = default); 20 | 21 | Task SendAsync(ReadOnlyMemory buffer, CancellationToken token = default); 22 | 23 | Task ReceiveAsync(Memory buffer, CancellationToken token = default); 24 | 25 | void Shutdown(SocketShutdown how); 26 | 27 | void Close(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Shadowsocks.Interop/V2Ray/Transport/CertificateObject.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Shadowsocks.Interop.V2Ray.Transport 4 | { 5 | public class CertificateObject 6 | { 7 | public string Usage { get; set; } 8 | public string? CertificateFile { get; set; } 9 | public string? KeyFile { get; set; } 10 | public List? Certificate { get; set; } 11 | public List? Key { get; set; } 12 | 13 | public CertificateObject() 14 | { 15 | Usage = "encipherment"; 16 | } 17 | 18 | public static CertificateObject DefaultFromFile => new() 19 | { 20 | CertificateFile = "", 21 | KeyFile = "", 22 | }; 23 | 24 | public static CertificateObject DefaultEmbedded => new() 25 | { 26 | Certificate = new(), 27 | Key = new(), 28 | }; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Shadowsocks.Net/Settings/ForwardProxySettings.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Shadowsocks.Net.Settings 8 | { 9 | public class ForwardProxySettings 10 | { 11 | public bool NoProxy { get; set; } 12 | public bool UseSocks5Proxy { get; set; } 13 | public bool UseHttpProxy { get; set; } 14 | public string Address { get; set; } 15 | public int Port { get; set; } 16 | public string Username { get; set; } 17 | public string Password { get; set; } 18 | 19 | public ForwardProxySettings() 20 | { 21 | NoProxy = true; 22 | UseSocks5Proxy = false; 23 | UseHttpProxy = false; 24 | Address = ""; 25 | Port = 1088; 26 | Username = ""; 27 | Password = ""; 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Shadowsocks.WPF/App.xaml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /Shadowsocks.Interop/V2Ray/Transport/WebSocketObject.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Shadowsocks.Interop.V2Ray.Transport 4 | { 5 | public class WebSocketObject 6 | { 7 | /// 8 | /// Gets or sets whether to use PROXY protocol. 9 | /// 10 | public bool AcceptProxyProtocol { get; set; } 11 | 12 | /// 13 | /// Gets or sets the HTTP query path. 14 | /// Defaults to "/". 15 | /// 16 | public string Path { get; set; } 17 | 18 | /// 19 | /// Gets or sets HTTP header key-value pairs. 20 | /// Defaults to empty. 21 | /// 22 | public Dictionary Headers { get; set; } 23 | 24 | public WebSocketObject() 25 | { 26 | AcceptProxyProtocol = false; 27 | Path = "/"; 28 | Headers = new(); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Shadowsocks.Interop/V2Ray/Transport/QuicObject.cs: -------------------------------------------------------------------------------- 1 | using Shadowsocks.Interop.V2Ray.Transport.Header; 2 | 3 | namespace Shadowsocks.Interop.V2Ray.Transport 4 | { 5 | public class QuicObject 6 | { 7 | /// 8 | /// Gets or sets the encryption method. 9 | /// Defaults to "none" (no encryption). 10 | /// Available values: "none" | "aes-128-gcm" | "chacha20-poly1305" 11 | /// 12 | public string Security { get; set; } 13 | 14 | /// 15 | /// Gets or sets the encryption key. 16 | /// 17 | public string Key { get; set; } 18 | 19 | /// 20 | /// Gets or sets the header options. 21 | /// 22 | public HeaderObject Header { get; set; } 23 | 24 | public QuicObject() 25 | { 26 | Security = "none"; 27 | Key = ""; 28 | Header = new(); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Shadowsocks.Protocol/PipePair.cs: -------------------------------------------------------------------------------- 1 | using System.IO.Pipelines; 2 | 3 | namespace Shadowsocks.Protocol 4 | { 5 | internal class PipePair 6 | { 7 | 8 | /* 9 | * 10 | * --> c ---w[ uplink ]r--> s 11 | * <-- c <--r[ downlink ]w--- s 12 | * down up down 13 | */ 14 | 15 | private readonly Pipe uplink = new Pipe(); 16 | private readonly Pipe downlink = new Pipe(); 17 | public DuplexPipe UpSide { get; private set; } 18 | public DuplexPipe DownSide { get; private set; } 19 | public PipePair() 20 | { 21 | UpSide = new DuplexPipe 22 | { 23 | Input = downlink.Reader, 24 | Output = uplink.Writer, 25 | }; 26 | DownSide = new DuplexPipe 27 | { 28 | Input = uplink.Reader, 29 | Output = downlink.Writer, 30 | }; 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Shadowsocks.Interop/V2Ray/Outbound/ProxySettingsObject.cs: -------------------------------------------------------------------------------- 1 | namespace Shadowsocks.Interop.V2Ray.Outbound 2 | { 3 | public class ProxySettingsObject 4 | { 5 | /// 6 | /// Gets or sets the tag of the outbound 7 | /// used as the proxy. 8 | /// 9 | public string Tag { get; set; } 10 | 11 | /// 12 | /// Gets or sets whether to keep the protocol 13 | /// itself's transport layer intact. 14 | /// Defaults to false, or only proxy internal TCP traffic. 15 | /// Set to true to proxy the protocol. 16 | /// The tag will act as a forward proxy. 17 | /// 18 | public bool TransportLayer { get; set; } 19 | 20 | public ProxySettingsObject() 21 | { 22 | Tag = ""; 23 | } 24 | 25 | public static ProxySettingsObject Default => new() 26 | { 27 | TransportLayer = true, 28 | }; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Shadowsocks.Interop/V2Ray/Protocols/Shadowsocks/ServerObject.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json.Serialization; 2 | 3 | namespace Shadowsocks.Interop.V2Ray.Protocols.Shadowsocks 4 | { 5 | public class ServerObject 6 | { 7 | public string? Email { get; set; } 8 | 9 | public string Address { get; set; } 10 | 11 | public int Port { get; set; } 12 | 13 | public string Method { get; set; } 14 | 15 | public string Password { get; set; } 16 | 17 | public int? Level { get; set; } 18 | 19 | public ServerObject() 20 | { 21 | Address = ""; 22 | Port = 8388; 23 | Method = "chacha20-ietf-poly1305"; 24 | Password = ""; 25 | } 26 | 27 | public ServerObject(string address, int port, string method, string password) 28 | { 29 | Address = address; 30 | Port = port; 31 | Method = method; 32 | Password = password; 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Shadowsocks.Interop/V2Ray/LogObject.cs: -------------------------------------------------------------------------------- 1 | namespace Shadowsocks.Interop.V2Ray 2 | { 3 | public class LogObject 4 | { 5 | /// 6 | /// Gets or sets the path to the access log file. 7 | /// Defaults to empty, which prints to stdout. 8 | /// 9 | public string Access { get; set; } 10 | 11 | /// 12 | /// Gets or sets the path to the error log file. 13 | /// Defaults to empty, which prints to stdout. 14 | /// 15 | public string Error { get; set; } 16 | 17 | /// 18 | /// Gets or sets the log level. 19 | /// Defaults to warning. 20 | /// Available values: "debug" | "info" | "warning" | "error" | "none" 21 | /// 22 | public string Loglevel { get; set; } 23 | 24 | public LogObject() 25 | { 26 | Access = ""; 27 | Error = ""; 28 | Loglevel = "warning"; 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Shadowsocks.Interop/V2Ray/Transport/KcpObject.cs: -------------------------------------------------------------------------------- 1 | using Shadowsocks.Interop.V2Ray.Transport.Header; 2 | 3 | namespace Shadowsocks.Interop.V2Ray.Transport 4 | { 5 | public class KcpObject 6 | { 7 | public int Mtu { get; set; } 8 | public int Tti { get; set; } 9 | public int UplinkCapacity { get; set; } 10 | public int DownlinkCapacity { get; set; } 11 | public bool Congestion { get; set; } 12 | public int ReadBufferSize { get; set; } 13 | public int WriteBufferSize { get; set; } 14 | public HeaderObject Header { get; set; } 15 | public string Seed { get; set; } 16 | 17 | public KcpObject() 18 | { 19 | Mtu = 1350; 20 | Tti = 50; 21 | UplinkCapacity = 5; 22 | DownlinkCapacity = 20; 23 | Congestion = false; 24 | ReadBufferSize = 2; 25 | WriteBufferSize = 2; 26 | Header = new(); 27 | Seed = ""; 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Shadowsocks.Protobuf/geosite.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | // DomainObject for routing decision. 4 | message DomainObject { 5 | // Type of domain value. 6 | enum Type { 7 | // The value is used as is. 8 | Plain = 0; 9 | // The value is used as a regular expression. 10 | Regex = 1; 11 | // The value is a root domain. 12 | Domain = 2; 13 | // The value is a domain. 14 | Full = 3; 15 | } 16 | 17 | // DomainObject matching type. 18 | Type type = 1; 19 | 20 | // DomainObject value. 21 | string value = 2; 22 | 23 | message Attribute { 24 | string key = 1; 25 | 26 | oneof typed_value { 27 | bool bool_value = 2; 28 | int64 int_value = 3; 29 | } 30 | } 31 | 32 | // Attributes of this domain. May be used for filtering. 33 | repeated Attribute attribute = 3; 34 | } 35 | 36 | message Geosite { 37 | string group_name = 1; 38 | repeated DomainObject domains = 2; 39 | } 40 | 41 | message GeositeList{ 42 | repeated Geosite entries = 1; 43 | } 44 | -------------------------------------------------------------------------------- /Shadowsocks.Net/Settings/NetSettings.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace Shadowsocks.Net.Settings 6 | { 7 | public class NetSettings 8 | { 9 | public bool EnableSocks5 { get; set; } 10 | public bool EnableHttp { get; set; } 11 | public string Socks5ListeningAddress { get; set; } 12 | public string HttpListeningAddress { get; set; } 13 | public int Socks5ListeningPort { get; set; } 14 | public int HttpListeningPort { get; set; } 15 | 16 | public ForwardProxySettings ForwardProxy { get; set; } 17 | 18 | public NetSettings() 19 | { 20 | EnableSocks5 = true; 21 | EnableHttp = true; 22 | Socks5ListeningAddress = "::1"; 23 | HttpListeningAddress = "::1"; 24 | Socks5ListeningPort = 1080; 25 | HttpListeningPort = 1080; 26 | 27 | ForwardProxy = new ForwardProxySettings(); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Shadowsocks.Interop/V2Ray/ApiObject.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Shadowsocks.Interop.V2Ray 4 | { 5 | public class ApiObject 6 | { 7 | /// 8 | /// Gets or sets the outbound tag for the API. 9 | /// 10 | public string Tag { get; set; } 11 | 12 | /// 13 | /// Gets or sets the list of API services to enable. 14 | /// 15 | public List Services { get; set; } 16 | 17 | public ApiObject() 18 | { 19 | Tag = ""; 20 | Services = new(); 21 | } 22 | 23 | /// 24 | /// Gets the default API object. 25 | /// 26 | public static ApiObject Default => new() 27 | { 28 | Tag = "api", 29 | Services = new() 30 | { 31 | "HandlerService", 32 | "LoggerService", 33 | "StatsService", 34 | }, 35 | }; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## Please follow the guide below 2 | 3 | - You will be asked some questions, please read them **carefully** and answer honestly 4 | - Put an `x` into all the boxes [ ] relevant to your *pull request* (like that [x]) 5 | - Use *Preview* tab to see how your *pull request* will actually look like 6 | 7 | - [ ] [Searched](https://github.com/shadowsocks/shadowsocks-windows/search?q=is%3Apr&type=Issues) for similar pull requests 8 | - [ ] Compiled the code with Visual Studio 9 | - [ ] Require translation update 10 | - [ ] Require document update (readme.md, wikipage, etc) 11 | 12 | ### What is the purpose of your *pull request*? 13 | - [ ] Bug fix 14 | - [ ] Improvement 15 | - [ ] New feature 16 | 17 | --- 18 | 19 | ### Description of your *pull request* and other information 20 | 21 | Explanation of your *pull request* in arbitrary form goes here. Please make sure the description explains the purpose and effect of your *pull request* and is worded well enough to be understood. Provide as much context and examples as possible. -------------------------------------------------------------------------------- /Shadowsocks.Interop/V2Ray/Transport/StreamSettingsObject.cs: -------------------------------------------------------------------------------- 1 | namespace Shadowsocks.Interop.V2Ray.Transport 2 | { 3 | public class StreamSettingsObject : TransportObject 4 | { 5 | /// 6 | /// Gets or sets the transport protocol type. 7 | /// Defaults to "tcp". 8 | /// Available values: "tcp" | "kcp" | "ws" | "http" | "domainsocket" | "quic" 9 | /// 10 | public string? Network { get; set; } 11 | 12 | /// 13 | /// Gets or sets the transport encryption type. 14 | /// Defaults to "none" (no encryption). 15 | /// Available values: "none" | "tls" 16 | /// 17 | public string? Security { get; set; } 18 | 19 | public TlsObject? TlsSettings { get; set; } 20 | public SockoptObject? Sockopt { get; set; } 21 | 22 | public static StreamSettingsObject DefaultWsTls => new() 23 | { 24 | Network = "ws", 25 | Security = "tls", 26 | TlsSettings = new(), 27 | }; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Shadowsocks.Tests/Shadowsocks.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net5.0 5 | 6 | false 7 | 8 | enable 9 | 10 | 11 | 12 | 13 | 14 | 15 | runtime; build; native; contentfiles; analyzers; buildtransitive 16 | all 17 | 18 | 19 | runtime; build; native; contentfiles; analyzers; buildtransitive 20 | all 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /Shadowsocks.Interop/V2Ray/Inbound/AllocateObject.cs: -------------------------------------------------------------------------------- 1 | namespace Shadowsocks.Interop.V2Ray.Inbound 2 | { 3 | public class AllocateObject 4 | { 5 | /// 6 | /// Gets or sets the port allocation strategy. 7 | /// Defaults to "always". 8 | /// Available values: "always" | "random" 9 | /// 10 | public string Strategy { get; set; } 11 | 12 | /// 13 | /// Gets or sets the random port refreshing interval in minutes. 14 | /// Defaults to 5 minutes. 15 | /// 16 | public int? Refresh { get; set; } 17 | 18 | /// 19 | /// Gets or sets the number of random ports. 20 | /// Defaults to 3. 21 | /// 22 | public int? Concurrency { get; set; } 23 | 24 | public AllocateObject() 25 | { 26 | Strategy = "always"; 27 | } 28 | 29 | public static AllocateObject Default => new() 30 | { 31 | Refresh = 5, 32 | Concurrency = 3, 33 | }; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Shadowsocks.WPF.Tests/Shadowsocks.WPF.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net5.0-windows10.0.19041.0 5 | 6 | false 7 | 8 | enable 9 | 10 | 11 | 12 | 13 | 14 | 15 | runtime; build; native; contentfiles; analyzers; buildtransitive 16 | all 17 | 18 | 19 | runtime; build; native; contentfiles; analyzers; buildtransitive 20 | all 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /Shadowsocks.CLI/Client/Pipelines.cs: -------------------------------------------------------------------------------- 1 | using Shadowsocks.Protocol; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Net; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace Shadowsocks.CLI.Client 10 | { 11 | public class Pipelines 12 | { 13 | private TcpPipeListener? _tcpPipeListener; 14 | 15 | public Task Start(string listenSocks, string serverAddress, int serverPort, string method, string? password, string? key, string? plugin, string? pluginOpts, string? pluginArgs) 16 | { 17 | // TODO 18 | var localEP = IPEndPoint.Parse(listenSocks); 19 | var remoteEp = new DnsEndPoint(serverAddress, serverPort); 20 | byte[]? mainKey = null; 21 | if (!string.IsNullOrEmpty(key)) 22 | mainKey = Encoding.UTF8.GetBytes(key); 23 | _tcpPipeListener = new(localEP); 24 | return _tcpPipeListener.Start(localEP, remoteEp, method, password, mainKey); 25 | } 26 | 27 | public void Stop() => _tcpPipeListener?.Stop(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report_en.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report (English) 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | 17 | 18 | ### Describe the bug 19 | 20 | ### Environment 21 | 22 | - Shadowsocks client version: 23 | - OS version: 24 | - .NET version: 25 | 26 | ### Steps you have tried 27 | 28 | 29 | ### What did you expect to see? 30 | 31 | 32 | ### What did you see instead? 33 | 34 | 35 | ### Config and error log in detail (with all sensitive info masked) 36 | 37 | ``` 38 | PASTE LOG HERE 39 | ``` 40 | -------------------------------------------------------------------------------- /Shadowsocks.Interop/V2Ray/Config.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Shadowsocks.Interop.V2Ray 4 | { 5 | public class Config 6 | { 7 | public LogObject? Log { get; set; } 8 | public ApiObject? Api { get; set; } 9 | public DnsObject? Dns { get; set; } 10 | public RoutingObject? Routing { get; set; } 11 | public PolicyObject? Policy { get; set; } 12 | public List? Inbounds { get; set; } 13 | public List? Outbounds { get; set; } 14 | public TransportObject? Transport { get; set; } 15 | public StatsObject? Stats { get; set; } 16 | public ReverseObject? Reverse { get; set; } 17 | 18 | /// 19 | /// Gets the default configuration. 20 | /// 21 | public static Config Default => new() 22 | { 23 | Log = new(), 24 | Api = ApiObject.Default, 25 | Dns = new(), 26 | Routing = new(), 27 | Policy = PolicyObject.Default, 28 | Inbounds = new(), 29 | Outbounds = new(), 30 | Stats = new(), 31 | }; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Shadowsocks.Protocol/Shadowsocks/SaltMessage.cs: -------------------------------------------------------------------------------- 1 | using Shadowsocks.Protocol.Shadowsocks.Crypto; 2 | using System; 3 | using System.Diagnostics.CodeAnalysis; 4 | using System.Security.Cryptography; 5 | 6 | namespace Shadowsocks.Protocol.Shadowsocks 7 | { 8 | public class SaltMessage : IProtocolMessage 9 | { 10 | private readonly int length; 11 | public Memory Salt { get; private set; } 12 | 13 | public SaltMessage(int length, bool roll = false) 14 | { 15 | this.length = length; 16 | if (roll) 17 | { 18 | Salt = new byte[length]; 19 | RandomNumberGenerator.Fill(Salt.Span); 20 | } 21 | } 22 | 23 | public bool Equals([AllowNull] IProtocolMessage other) => throw new NotImplementedException(); 24 | 25 | public int Serialize(Memory buffer) 26 | { 27 | Salt.CopyTo(buffer); 28 | return length; 29 | } 30 | 31 | public (bool success, int length) TryLoad(ReadOnlyMemory buffer) 32 | { 33 | if (buffer.Length < length) return (false, length); 34 | buffer.Slice(0, length).CopyTo(Salt); 35 | return (true, length); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Shadowsocks.Interop/V2Ray/Protocols/Socks/ServerObject.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Net; 3 | 4 | namespace Shadowsocks.Interop.V2Ray.Protocols.Socks 5 | { 6 | public class ServerObject 7 | { 8 | public string Address { get; set; } 9 | public int Port { get; set; } 10 | public List? Users { get; set; } 11 | 12 | public ServerObject() 13 | { 14 | Address = ""; 15 | Port = 0; 16 | } 17 | 18 | public ServerObject(DnsEndPoint socksEndPoint, string? username = null, string? password = null) 19 | { 20 | Address = socksEndPoint.Host; 21 | Port = socksEndPoint.Port; 22 | Users = new(); 23 | var hasCredential = !string.IsNullOrEmpty(username) && !string.IsNullOrEmpty(password); 24 | if (hasCredential) 25 | { 26 | var user = new UserObject() 27 | { 28 | User = username!, // null check already performed at line 23. 29 | Pass = password!, 30 | }; 31 | Users = new() 32 | { 33 | user, 34 | }; 35 | } 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Shadowsocks.Protocol/Socks5/Socks5UserPasswordResponseMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Shadowsocks.Protocol.Socks5 4 | { 5 | public class Socks5UserPasswordResponseMessage : Socks5Message 6 | { 7 | // 1 success 8 | 9 | public bool Success; 10 | 11 | public override int Serialize(Memory buffer) 12 | { 13 | if (buffer.Length < 2) throw Util.BufferTooSmall(2, buffer.Length, nameof(buffer)); 14 | 15 | buffer.Span[0] = 1; 16 | buffer.Span[1] = (byte) (Success ? 0 : 1); 17 | return 2; 18 | } 19 | 20 | public override (bool success, int length) TryLoad(ReadOnlyMemory buffer) 21 | { 22 | if (buffer.Length < 2) return (false, 2); 23 | if (buffer.Span[0] != 1) return (false, 0); 24 | 25 | Success = buffer.Span[1] == 0; 26 | return (true, 2); 27 | } 28 | 29 | public override bool Equals(IProtocolMessage other) 30 | { 31 | if (other is null) return false; 32 | if (ReferenceEquals(this, other)) return true; 33 | if (other.GetType() != GetType()) return false; 34 | return Success == ((Socks5UserPasswordResponseMessage)other).Success; 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /Shadowsocks.Protocol/Socks5/Socks5MethodSelectionMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Shadowsocks.Protocol.Socks5 4 | { 5 | public class Socks5MethodSelectionMessage : Socks5Message 6 | { 7 | // 5 auth 8 | public byte SelectedAuth; 9 | 10 | public override int Serialize(Memory buffer) 11 | { 12 | if (buffer.Length < 2) throw Util.BufferTooSmall(2, buffer.Length, nameof(buffer)); 13 | 14 | buffer.Span[0] = 5; 15 | buffer.Span[1] = SelectedAuth; 16 | return 2; 17 | } 18 | 19 | public override (bool success, int length) TryLoad(ReadOnlyMemory buffer) 20 | { 21 | // need 3 byte 22 | if (buffer.Length < 2) return (false, 2); 23 | if (buffer.Span[0] != 5) return (false, 0); 24 | 25 | SelectedAuth = buffer.Span[1]; 26 | return (true, 2); 27 | } 28 | 29 | public override bool Equals(IProtocolMessage other) 30 | { 31 | if (other is null) return false; 32 | if (ReferenceEquals(this, other)) return true; 33 | if (other.GetType() != GetType()) return false; 34 | return SelectedAuth == ((Socks5MethodSelectionMessage) other).SelectedAuth; 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /Shadowsocks.Interop/V2Ray/Routing/RuleObject.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Text.Json.Serialization; 3 | 4 | namespace Shadowsocks.Interop.V2Ray.Routing 5 | { 6 | public class RuleObject 7 | { 8 | [JsonIgnore(Condition = JsonIgnoreCondition.Never)] 9 | public string Type { get; set; } 10 | public List? Domain { get; set; } 11 | public List? Ip { get; set; } 12 | public object? Port { get; set; } 13 | public object? SourcePort { get; set; } 14 | public string? Network { get; set; } 15 | public List? Source { get; set; } 16 | public List? User { get; set; } 17 | public List? InboundTag { get; set; } 18 | public List? Protocol { get; set; } 19 | public string? Attrs { get; set; } 20 | public string? OutboundTag { get; set; } 21 | public string? BalancerTag { get; set; } 22 | 23 | public RuleObject() 24 | { 25 | Type = "field"; 26 | } 27 | 28 | public static RuleObject DefaultOutbound => new() 29 | { 30 | OutboundTag = "", 31 | }; 32 | 33 | public static RuleObject DefaultBalancer => new() 34 | { 35 | BalancerTag = "", 36 | }; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Shadowsocks.WPF/FodyWeavers.xsd: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. 12 | 13 | 14 | 15 | 16 | A comma-separated list of error codes that can be safely ignored in assembly verification. 17 | 18 | 19 | 20 | 21 | 'false' to turn off automatic generation of the XML Schema file. 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /Shadowsocks.Interop/V2Ray/Dns/ServerObject.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Shadowsocks.Interop.V2Ray.Dns 4 | { 5 | public class ServerObject 6 | { 7 | /// 8 | /// Gets or sets the DNS server address. 9 | /// Supports UDP and DoH. 10 | /// 11 | public string Address { get; set; } 12 | 13 | /// 14 | /// Gets or sets the DNS server port. 15 | /// Defaults to 53. 16 | /// 17 | public int Port { get; set; } 18 | 19 | /// 20 | /// Gets or sets the client IP 21 | /// to include in DNS queries. 22 | /// 23 | public string? ClientIp { get; set; } 24 | 25 | /// 26 | /// Gets or sets the list of domains 27 | /// that prefers this DNS server. 28 | /// 29 | public List Domains { get; set; } 30 | 31 | /// 32 | /// Gets or sets the ranges of IP addresses 33 | /// this DNS server is expected to return. 34 | /// 35 | public List ExpectIPs { get; set; } 36 | 37 | public ServerObject() 38 | { 39 | Address = ""; 40 | Port = 53; 41 | Domains = new(); 42 | ExpectIPs = new(); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Shadowsocks.PAC/Shadowsocks.PAC.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net5.0 5 | enable 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | True 29 | True 30 | Resources.resx 31 | 32 | 33 | 34 | 35 | 36 | ResXFileCodeGenerator 37 | Resources.Designer.cs 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /Shadowsocks.Interop/V2Ray/Transport/Header/Http/HttpResponseObject.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Shadowsocks.Interop.V2Ray.Transport.Header.Http 4 | { 5 | public class HttpResponseObject 6 | { 7 | public string Version { get; set; } 8 | public string Status { get; set; } 9 | public string Reason { get; set; } 10 | public Dictionary> Headers { get; set; } 11 | 12 | public HttpResponseObject() 13 | { 14 | Version = "1.1"; 15 | Status = "200"; 16 | Reason = "OK"; 17 | Headers = new() 18 | { 19 | ["Content-Type"] = new() 20 | { 21 | "application/octet-stream", 22 | "video/mpeg", 23 | }, 24 | ["Transfer-Encoding"] = new() 25 | { 26 | "chunked", 27 | }, 28 | ["Connection"] = new() 29 | { 30 | "keep-alive", 31 | }, 32 | ["Pragma"] = new() 33 | { 34 | "no-cache", 35 | }, 36 | ["Cache-Control"] = new() 37 | { 38 | "private", 39 | "no-cache", 40 | }, 41 | }; 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Shadowsocks.Net/Crypto/RNG.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Security.Cryptography; 3 | 4 | namespace Shadowsocks.Net.Crypto 5 | { 6 | public static class RNG 7 | { 8 | private static RNGCryptoServiceProvider _rng = new RNGCryptoServiceProvider(); 9 | 10 | public static void Reload() 11 | { 12 | _rng.Dispose(); 13 | _rng = new RNGCryptoServiceProvider(); 14 | } 15 | 16 | public static void GetSpan(Span span) 17 | { 18 | _rng.GetBytes(span); 19 | } 20 | 21 | public static Span GetSpan(int length) 22 | { 23 | Span span = new byte[length]; 24 | _rng.GetBytes(span); 25 | return span; 26 | } 27 | 28 | public static byte[] GetBytes(int length) 29 | { 30 | byte[] buf = new byte[length]; 31 | _rng.GetBytes(buf); 32 | return buf; 33 | } 34 | 35 | public static void GetBytes(byte[] buf, int len) 36 | { 37 | try 38 | { 39 | _rng.GetBytes(buf, 0, len); 40 | } 41 | catch 42 | { 43 | // the backup way 44 | byte[] tmp = new byte[len]; 45 | _rng.GetBytes(tmp); 46 | Buffer.BlockCopy(tmp, 0, buf, 0, len); 47 | } 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Shadowsocks.Interop/V2Ray/InboundObject.cs: -------------------------------------------------------------------------------- 1 | using Shadowsocks.Interop.V2Ray.Inbound; 2 | using Shadowsocks.Interop.V2Ray.Transport; 3 | 4 | namespace Shadowsocks.Interop.V2Ray 5 | { 6 | public class InboundObject 7 | { 8 | public string Tag { get; set; } 9 | public string? Listen { get; set; } 10 | public object? Port { get; set; } 11 | public string Protocol { get; set; } 12 | public object? Settings { get; set; } 13 | public StreamSettingsObject? StreamSettings { get; set; } 14 | public SniffingObject? Sniffing { get; set; } 15 | public AllocateObject? Allocate { get; set; } 16 | 17 | public InboundObject() 18 | { 19 | Tag = ""; 20 | Protocol = ""; 21 | } 22 | 23 | public static InboundObject DefaultLocalSocks => new() 24 | { 25 | Tag = "socks-in", 26 | Listen = "127.0.0.1", 27 | Port = 1080, 28 | Protocol = "socks", 29 | Settings = Protocols.Socks.InboundConfigurationObject.Default, 30 | Sniffing = SniffingObject.Default, 31 | }; 32 | 33 | public static InboundObject DefaultLocalHttp => new() 34 | { 35 | Tag = "http-in", 36 | Listen = "127.0.0.1", 37 | Port = 8080, 38 | Protocol = "http", 39 | Sniffing = SniffingObject.Default, 40 | }; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Shadowsocks.Protocol/Shadowsocks/Crypto/AeadCrypto.cs: -------------------------------------------------------------------------------- 1 | using CryptoBase.Abstractions.SymmetricCryptos; 2 | using System; 3 | 4 | namespace Shadowsocks.Protocol.Shadowsocks.Crypto 5 | { 6 | public abstract class AeadCrypto : ICrypto 7 | { 8 | protected IAEADCrypto? crypto; 9 | 10 | private readonly CryptoParameter _parameter; 11 | 12 | protected AeadCrypto(CryptoParameter parameter) 13 | { 14 | _parameter = parameter; 15 | } 16 | 17 | public abstract void Init(byte[] key, byte[] iv); 18 | 19 | public int Decrypt(ReadOnlySpan nonce, Span plain, ReadOnlySpan cipher) 20 | { 21 | crypto!.Decrypt( 22 | nonce, 23 | cipher[..^_parameter.TagSize], 24 | cipher[^_parameter.TagSize..], 25 | plain[..(cipher.Length - _parameter.TagSize)]); 26 | return cipher.Length - _parameter.TagSize; 27 | } 28 | 29 | public int Encrypt(ReadOnlySpan nonce, ReadOnlySpan plain, Span cipher) 30 | { 31 | crypto!.Encrypt( 32 | nonce, 33 | plain, 34 | cipher.Slice(0, plain.Length), 35 | cipher.Slice(plain.Length, _parameter.TagSize)); 36 | return plain.Length + _parameter.TagSize; 37 | } 38 | 39 | public void Dispose() => crypto?.Dispose(); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Shadowsocks.WPF/Views/MainWindow.xaml.cs: -------------------------------------------------------------------------------- 1 | using ReactiveUI; 2 | using Shadowsocks.WPF.ViewModels; 3 | using System.Reactive.Disposables; 4 | 5 | namespace Shadowsocks.WPF.Views 6 | { 7 | /// 8 | /// Interaction logic for MainWindow.xaml 9 | /// 10 | public partial class MainWindow 11 | { 12 | public MainWindow() 13 | { 14 | InitializeComponent(); 15 | ViewModel = new MainWindowViewModel(); 16 | this.WhenActivated(disposables => 17 | { 18 | this.OneWayBind(ViewModel, 19 | viewModel => viewModel.GetDashboardView, 20 | view => view.dashboardTabItem.Content) 21 | .DisposeWith(disposables); 22 | this.OneWayBind(ViewModel, 23 | viewModel => viewModel.GetServersView, 24 | view => view.serversTabItem.Content) 25 | .DisposeWith(disposables); 26 | this.OneWayBind(ViewModel, 27 | viewModel => viewModel.GetRoutingView, 28 | view => view.routingTabItem.Content) 29 | .DisposeWith(disposables); 30 | this.OneWayBind(ViewModel, 31 | viewModel => viewModel.GetSettingsView, 32 | view => view.settingsTabItem.Content) 33 | .DisposeWith(disposables); 34 | }); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Shadowsocks.Interop/V2Ray/DnsObject.cs: -------------------------------------------------------------------------------- 1 | using Shadowsocks.Interop.V2Ray.Dns; 2 | using System.Collections.Generic; 3 | 4 | namespace Shadowsocks.Interop.V2Ray 5 | { 6 | public class DnsObject 7 | { 8 | /// 9 | /// Gets or sets the dictionary storing hosts. 10 | /// The key is the hostname. 11 | /// The value can either be a hostname or an IP address. 12 | /// 13 | public Dictionary Hosts { get; set; } 14 | 15 | /// 16 | /// Gets or sets the list of DNS servers. 17 | /// A DNS server can either be a or a string. 18 | /// 19 | public List Servers { get; set; } 20 | 21 | /// 22 | /// Gets or sets the client IP used when sending requests to DNS server. 23 | /// 24 | public string? ClientIp { get; set; } 25 | 26 | /// 27 | /// Gets or sets whether to disable internal DNS cache. 28 | /// Defaults to false, or DNS cache is enabled. 29 | /// 30 | public bool DisableCache { get; set; } 31 | 32 | /// 33 | /// Gets or sets the inbound tag for DNS traffic. 34 | /// 35 | public string? Tag { get; set; } 36 | 37 | public DnsObject() 38 | { 39 | Hosts = new(); 40 | Servers = new(); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Shadowsocks.Net/Crypto/Stream/StreamPlainNativeCrypto.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace Shadowsocks.Net.Crypto.Stream 5 | { 6 | public class StreamPlainNativeCrypto : StreamCrypto 7 | { 8 | 9 | public StreamPlainNativeCrypto(string method, string password) : base(method, password) 10 | { 11 | } 12 | 13 | protected override int CipherDecrypt(Span plain, ReadOnlySpan cipher) 14 | { 15 | cipher.CopyTo(plain); 16 | return cipher.Length; 17 | } 18 | 19 | protected override int CipherEncrypt(ReadOnlySpan plain, Span cipher) 20 | { 21 | plain.CopyTo(cipher); 22 | return plain.Length; 23 | } 24 | 25 | #region Cipher Info 26 | private static readonly Dictionary _ciphers = new Dictionary 27 | { 28 | {"plain", new CipherInfo("plain", 0, 0, CipherFamily.Plain) }, 29 | {"none", new CipherInfo("none", 0, 0, CipherFamily.Plain) }, 30 | }; 31 | 32 | public static Dictionary SupportedCiphers() 33 | { 34 | return _ciphers; 35 | } 36 | 37 | protected override Dictionary GetCiphers() 38 | { 39 | return _ciphers; 40 | } 41 | #endregion 42 | 43 | public override void Dispose() { } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Shadowsocks.Protocol/Shadowsocks/ShadowsocksClient.cs: -------------------------------------------------------------------------------- 1 | using Shadowsocks.Protocol.Shadowsocks.Crypto; 2 | using System.IO.Pipelines; 3 | using System.Net; 4 | using System.Threading.Tasks; 5 | 6 | namespace Shadowsocks.Protocol.Shadowsocks 7 | { 8 | internal class ShadowsocksClient : IStreamClient 9 | { 10 | private readonly IStreamClient shadow; 11 | private readonly PayloadProtocolClient socks = new PayloadProtocolClient(); 12 | private readonly PipePair p = new PipePair(); 13 | 14 | public ShadowsocksClient(string method, string password) 15 | { 16 | var param = CryptoProvider.GetCrypto(method); 17 | if (param.IsAead) 18 | { 19 | shadow = new AeadClient(param, password); 20 | } 21 | else 22 | { 23 | shadow = new UnsafeClient(param, password); 24 | } 25 | } 26 | 27 | public ShadowsocksClient(string method, byte[] key) 28 | { 29 | var param = CryptoProvider.GetCrypto(method); 30 | shadow = new AeadClient(param, key); 31 | } 32 | 33 | public Task Connect(EndPoint destination, IDuplexPipe client, IDuplexPipe server) 34 | { 35 | var tShadow = shadow.Connect(null, p.UpSide, server); 36 | var tSocks = socks.Connect(destination, client, p.UpSide); 37 | 38 | return Task.WhenAll(tShadow, tSocks); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Shadowsocks.WPF/Views/VersionUpdatePromptView.xaml.cs: -------------------------------------------------------------------------------- 1 | using ReactiveUI; 2 | using Shadowsocks.WPF.ViewModels; 3 | using System.Reactive.Disposables; 4 | using System.Text.Json; 5 | 6 | namespace Shadowsocks.WPF.Views 7 | { 8 | /// 9 | /// Interaction logic for VersionUpdatePromptView.xaml 10 | /// 11 | public partial class VersionUpdatePromptView 12 | { 13 | public VersionUpdatePromptView() 14 | { 15 | InitializeComponent(); 16 | DataContext = ViewModel; // for compatibility with MdXaml 17 | this.WhenActivated(disposables => 18 | { 19 | /*this.OneWayBind(ViewModel, 20 | viewModel => viewModel.ReleaseNotes, 21 | view => releaseNotesMarkdownScrollViewer.Markdown) 22 | .DisposeWith(disposables);*/ 23 | 24 | this.BindCommand(ViewModel!, 25 | viewModel => viewModel.Update, 26 | view => view.updateButton) 27 | .DisposeWith(disposables); 28 | this.BindCommand(ViewModel!, 29 | viewModel => viewModel.SkipVersion, 30 | view => view.skipVersionButton) 31 | .DisposeWith(disposables); 32 | this.BindCommand(ViewModel!, 33 | viewModel => viewModel.NotNow, 34 | view => view.notNowButton) 35 | .DisposeWith(disposables); 36 | }); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Shadowsocks/Models/Group.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text.Json.Serialization; 4 | 5 | namespace Shadowsocks.Models 6 | { 7 | public class Group : IGroup 8 | { 9 | /// 10 | /// Gets or sets the group name. 11 | /// 12 | public string Name { get; set; } 13 | 14 | /// 15 | /// Gets or sets the UUID of the group. 16 | /// 17 | public Guid Id { get; set; } 18 | 19 | /// 20 | public int Version { get; set; } 21 | 22 | /// 23 | public List Servers { get; set; } 24 | 25 | /// 26 | /// Gets or sets the data usage in bytes. 27 | /// The value is fetched from SIP008 provider. 28 | /// 29 | [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] 30 | public ulong BytesUsed { get; set; } 31 | 32 | /// 33 | /// Gets or sets the data remaining to be used in bytes. 34 | /// The value is fetched from SIP008 provider. 35 | /// 36 | [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] 37 | public ulong BytesRemaining { get; set; } 38 | 39 | public Group(string name = "") 40 | { 41 | Name = name; 42 | Id = Guid.NewGuid(); 43 | Version = 1; 44 | BytesUsed = 0UL; 45 | BytesRemaining = 0UL; 46 | Servers = new List(); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Shadowsocks/Models/IServer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text.Json.Serialization; 3 | 4 | namespace Shadowsocks.Models 5 | { 6 | public interface IServer : IEquatable 7 | { 8 | /// 9 | /// Gets or sets the server address. 10 | /// 11 | [JsonPropertyName("server")] 12 | public string Host { get; set; } 13 | 14 | /// 15 | /// Gets or sets the server port. 16 | /// 17 | [JsonPropertyName("server_port")] 18 | public int Port { get; set; } 19 | 20 | /// 21 | /// Gets or sets the password for the server. 22 | /// 23 | public string Password { get; set; } 24 | 25 | /// 26 | /// Gets or sets the method used for the server. 27 | /// 28 | public string Method { get; set; } 29 | 30 | /// 31 | /// Gets or sets the plugin executable filename. 32 | /// 33 | [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] 34 | public string? Plugin { get; set; } 35 | 36 | /// 37 | /// Gets or sets the plugin options passed as environment variables. 38 | /// 39 | [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] 40 | public string? PluginOpts { get; set; } 41 | 42 | /// 43 | /// Gets or sets the server name. 44 | /// 45 | [JsonPropertyName("remarks")] 46 | public string Name { get; set; } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Shadowsocks.Protocol/Socks5/Socks5VersionIdentifierMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Shadowsocks.Protocol.Socks5 4 | { 5 | public class Socks5VersionIdentifierMessage : Socks5Message 6 | { 7 | // 5 lAuth [Auth] 8 | 9 | public Memory Auth; 10 | 11 | public override int Serialize(Memory buffer) 12 | { 13 | var required = Auth.Length + 2; 14 | if (buffer.Length < required) throw Util.BufferTooSmall(required, buffer.Length, nameof(buffer)); 15 | 16 | buffer.Span[0] = 5; 17 | buffer.Span[1] = (byte) Auth.Length; 18 | Auth.CopyTo(buffer.Slice(2)); 19 | return Auth.Length + 2; 20 | } 21 | 22 | public override (bool success, int length) TryLoad(ReadOnlyMemory buffer) 23 | { 24 | // need 3 byte 25 | if (buffer.Length < 3) return (false, 3); 26 | if (buffer.Span[0] != 5) return (false, 0); 27 | if (buffer.Span[1] == 0) return (false, 0); 28 | if (buffer.Length < buffer.Span[1] + 2) return (false, buffer.Span[1] + 2); 29 | 30 | Auth = Util.GetArray(buffer[2..(2 + buffer.Span[1])]); 31 | return (true, buffer.Span[1] + 2); 32 | } 33 | 34 | public override bool Equals(IProtocolMessage other) 35 | { 36 | if (other is null) return false; 37 | if (ReferenceEquals(this, other)) return true; 38 | if (other.GetType() != GetType()) return false; 39 | return Auth.SequenceEqual(((Socks5VersionIdentifierMessage) other).Auth); 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /Shadowsocks.WPF/Services/OnlineConfigService.cs: -------------------------------------------------------------------------------- 1 | using Shadowsocks.WPF.Models; 2 | using Splat; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Net.Http; 7 | using System.Net.Http.Json; 8 | using System.Text; 9 | using System.Text.Json; 10 | using System.Threading.Tasks; 11 | 12 | namespace Shadowsocks.WPF.Services 13 | { 14 | /// 15 | /// The service for updating a group from an SIP008 online configuration source. 16 | /// 17 | public class OnlineConfigService 18 | { 19 | private Group _group; 20 | private HttpClient _httpClient; 21 | 22 | public OnlineConfigService(Group group) 23 | { 24 | _group = group; 25 | _httpClient = Locator.Current.GetService(); 26 | } 27 | 28 | /// 29 | /// Updates the group from the configured online configuration source. 30 | /// 31 | /// 32 | public async Task Update() 33 | { 34 | // Download 35 | var downloadedGroup = await _httpClient.GetFromJsonAsync(_group.OnlineConfigSource); 36 | if (downloadedGroup == null) 37 | throw new Exception("An error occurred."); 38 | // Merge downloaded group into existing group 39 | _group.Version = downloadedGroup.Version; 40 | _group.BytesUsed = downloadedGroup.BytesUsed; 41 | _group.BytesRemaining = downloadedGroup.BytesRemaining; 42 | _group.Servers = downloadedGroup.Servers; // TODO: preserve per-server statistics 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Shadowsocks.Net/Crypto/CryptoBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Shadowsocks.Net.Crypto 4 | { 5 | public abstract class CryptoBase : ICrypto 6 | { 7 | private static int _currentId = 0; 8 | 9 | public const int MaxInputSize = 32768; 10 | 11 | public const int MAX_DOMAIN_LEN = 255; 12 | public const int ADDR_PORT_LEN = 2; 13 | public const int ADDR_ATYP_LEN = 1; 14 | 15 | public const int ATYP_IPv4 = 0x01; 16 | public const int ATYP_DOMAIN = 0x03; 17 | public const int ATYP_IPv6 = 0x04; 18 | 19 | public const int MD5Length = 16; 20 | 21 | // for debugging only, give it a number to trace data stream 22 | public readonly int instanceId; 23 | 24 | protected CryptoBase(string method, string password) 25 | { 26 | instanceId = _currentId; 27 | _currentId++; 28 | 29 | Method = method; 30 | Password = password; 31 | } 32 | 33 | protected string Method; 34 | protected string Password; 35 | 36 | public override string ToString() 37 | { 38 | return $"{instanceId}({Method},{Password})"; 39 | } 40 | 41 | public abstract int Encrypt(ReadOnlySpan plain, Span cipher); 42 | public abstract int Decrypt(Span plain, ReadOnlySpan cipher); 43 | public abstract int EncryptUDP(ReadOnlySpan plain, Span cipher); 44 | public abstract int DecryptUDP(Span plain, ReadOnlySpan cipher); 45 | 46 | public int AddressBufferLength { get; set; } = -1; 47 | 48 | public abstract void Dispose(); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Shadowsocks.Net/SystemProxy/ProxyException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.Serialization; 3 | 4 | namespace Shadowsocks.Net.SystemProxy 5 | { 6 | public enum ProxyExceptionType 7 | { 8 | Unspecific, 9 | FailToRun, 10 | QueryReturnEmpty, 11 | SysproxyExitError, 12 | QueryReturnMalformed 13 | } 14 | 15 | public class ProxyException : Exception 16 | { 17 | // provide more specific information about exception 18 | public ProxyExceptionType Type { get; } 19 | 20 | public ProxyException() 21 | { 22 | } 23 | 24 | public ProxyException(string message) : base(message) 25 | { 26 | } 27 | 28 | public ProxyException(string message, Exception innerException) : base(message, innerException) 29 | { 30 | } 31 | 32 | protected ProxyException(SerializationInfo info, StreamingContext context) : base(info, context) 33 | { 34 | } 35 | public ProxyException(ProxyExceptionType type) 36 | { 37 | this.Type = type; 38 | } 39 | 40 | public ProxyException(ProxyExceptionType type, string message) : base(message) 41 | { 42 | this.Type = type; 43 | } 44 | 45 | public ProxyException(ProxyExceptionType type, string message, Exception innerException) : base(message, innerException) 46 | { 47 | this.Type = type; 48 | } 49 | 50 | protected ProxyException(ProxyExceptionType type, SerializationInfo info, StreamingContext context) : base(info, context) 51 | { 52 | this.Type = type; 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Shadowsocks.CLI/Shadowsocks.CLI.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net5.0 6 | enable 7 | sscli 8 | Shadowsocks.CLI 9 | Clowwindy & The Community 10 | Shadowsocks CLI 11 | CLI for Shadowsocks server and client implementation in C#. 12 | © 2021 Clowwindy & The Community 13 | LICENSE.txt 14 | https://github.com/shadowsocks/shadowsocks-windows 15 | https://github.com/shadowsocks/shadowsocks-windows 16 | Public 17 | ssw128.png 18 | 19 | 20 | 21 | 22 | True 23 | 24 | 25 | 26 | True 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /Shadowsocks.Interop/V2Ray/Transport/Header/Http/HttpRequestObject.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Shadowsocks.Interop.V2Ray.Transport.Header.Http 4 | { 5 | public class HttpRequestObject 6 | { 7 | public string Version { get; set; } 8 | public string Method { get; set; } 9 | public List Path { get; set; } 10 | public Dictionary> Headers { get; set; } 11 | 12 | public HttpRequestObject() 13 | { 14 | Version = "1.1"; 15 | Method = "GET"; 16 | Path = new() 17 | { 18 | "/", 19 | }; 20 | Headers = new() 21 | { 22 | ["Host"] = new() 23 | { 24 | "www.baidu.com", 25 | "www.bing.com", 26 | }, 27 | ["User-Agent"] = new() 28 | { 29 | "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36", 30 | "Mozilla/5.0 (iPhone; CPU iPhone OS 10_0_2 like Mac OS X) AppleWebKit/601.1 (KHTML, like Gecko) CriOS/53.0.2785.109 Mobile/14A456 Safari/601.1.46", 31 | }, 32 | ["Accept-Encoding"] = new() 33 | { 34 | "gzip, deflate", 35 | }, 36 | ["Connection"] = new() 37 | { 38 | "keep-alive", 39 | }, 40 | ["Pragma"] = new() 41 | { 42 | "no-cache", 43 | }, 44 | }; 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Shadowsocks.WPF/ViewModels/VersionUpdatePromptViewModel.cs: -------------------------------------------------------------------------------- 1 | using ReactiveUI; 2 | using Shadowsocks.WPF.Services; 3 | using Splat; 4 | using System.Reactive; 5 | using System.Text.Json; 6 | 7 | namespace Shadowsocks.WPF.ViewModels 8 | { 9 | public class VersionUpdatePromptViewModel : ReactiveObject 10 | { 11 | public VersionUpdatePromptViewModel(JsonElement releaseObject) 12 | { 13 | _updateChecker = Locator.Current.GetService(); 14 | _releaseObject = releaseObject; 15 | var releaseTagName = _releaseObject.GetProperty("tag_name").GetString(); 16 | var releaseNotes = _releaseObject.GetProperty("body").GetString(); 17 | var releaseIsPrerelease = _releaseObject.GetProperty("prerelease").GetBoolean(); 18 | ReleaseNotes = string.Concat( 19 | $"# {(releaseIsPrerelease ? "⚠ Pre-release" : "ℹ Release")} {releaseTagName ?? "Failed to get tag name"}\r\n", 20 | releaseNotes ?? "Failed to get release notes"); 21 | 22 | Update = ReactiveCommand.CreateFromTask(_updateChecker.DoUpdate); 23 | SkipVersion = ReactiveCommand.Create(_updateChecker.SkipUpdate); 24 | NotNow = ReactiveCommand.Create(_updateChecker.CloseVersionUpdatePromptWindow); 25 | } 26 | 27 | private readonly UpdateChecker _updateChecker; 28 | private readonly JsonElement _releaseObject; 29 | 30 | public string ReleaseNotes { get; } 31 | 32 | public ReactiveCommand Update { get; } 33 | 34 | public ReactiveCommand SkipVersion { get; } 35 | 36 | public ReactiveCommand NotNow { get; } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Shadowsocks.Interop/V2Ray/RoutingObject.cs: -------------------------------------------------------------------------------- 1 | using Shadowsocks.Interop.V2Ray.Routing; 2 | using System.Collections.Generic; 3 | 4 | namespace Shadowsocks.Interop.V2Ray 5 | { 6 | public class RoutingObject 7 | { 8 | /// 9 | /// Gets or sets the domain strategy used for routing. 10 | /// Default value: AsIs. 11 | /// Available values: "AsIs" | "IPIfNonMatch" | "IPOnDemand" 12 | /// 13 | public string DomainStrategy { get; set; } 14 | 15 | /// 16 | /// Gets or sets the domain matcher used for routing. 17 | /// Default value: "linear". 18 | /// Available values: "linear" | "mph" 19 | /// 20 | public string DomainMatcher { get; set; } 21 | 22 | /// 23 | /// Gets or sets the list of routing rules. 24 | /// 25 | public List Rules { get; set; } 26 | 27 | /// 28 | /// Gets or sets the list of load balancers. 29 | /// 30 | public List? Balancers { get; set; } 31 | 32 | public RoutingObject() 33 | { 34 | DomainStrategy = "AsIs"; 35 | DomainMatcher = "linear"; 36 | Rules = new(); 37 | } 38 | 39 | public static RoutingObject Default => new() 40 | { 41 | DomainStrategy = "IPOnDemand", 42 | DomainMatcher = "mph", 43 | }; 44 | 45 | public static RoutingObject DefaultBalancers => new() 46 | { 47 | DomainStrategy = "IPOnDemand", 48 | DomainMatcher = "mph", 49 | Balancers = new(), 50 | }; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Shadowsocks.Interop/V2Ray/Inbound/SniffingObject.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Shadowsocks.Interop.V2Ray.Inbound 4 | { 5 | public class SniffingObject 6 | { 7 | /// 8 | /// Gets or sets whether to enable sniffing. 9 | /// Defaults to true (enabled). 10 | /// 11 | public bool Enabled { get; set; } 12 | 13 | /// 14 | /// Gets or sets the list of protocols that destination override is enabled. 15 | /// 16 | public List DestOverride { get; set; } 17 | 18 | /// 19 | /// Gets or sets whether the target address is sniffed 20 | /// solely based on metadata. 21 | /// Defaults to false. 22 | /// Change to true to use FakeDNS. 23 | /// 24 | public bool MetadataOnly { get; set; } 25 | 26 | public SniffingObject() 27 | { 28 | Enabled = true; 29 | DestOverride = new() 30 | { 31 | "http", 32 | "tls", 33 | }; 34 | } 35 | 36 | public static SniffingObject Default => new() 37 | { 38 | Enabled = false, 39 | DestOverride = new() 40 | { 41 | "http", 42 | "tls", 43 | }, 44 | }; 45 | 46 | public static SniffingObject DefaultFakeDns => new() 47 | { 48 | Enabled = true, 49 | DestOverride = new() 50 | { 51 | "http", 52 | "tls", 53 | "fakedns", 54 | }, 55 | MetadataOnly = true, 56 | }; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /Shadowsocks.Protocol/Util.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using System.Runtime.InteropServices; 4 | using System.Text; 5 | 6 | namespace Shadowsocks.Protocol 7 | { 8 | internal static class Util 9 | { 10 | private static readonly IdnMapping _idnMapping = new IdnMapping(); 11 | 12 | public static string RestoreHostName(string punycode) => Encoding.UTF8.GetByteCount(punycode) != punycode.Length 13 | ? punycode.ToLowerInvariant() 14 | : _idnMapping.GetUnicode(punycode).ToLowerInvariant(); 15 | 16 | public static string EncodeHostName(string unicode) => Encoding.UTF8.GetByteCount(unicode) != unicode.Length 17 | ? _idnMapping.GetAscii(unicode).ToLowerInvariant() 18 | : unicode.ToLowerInvariant(); 19 | 20 | public static ArraySegment GetArray(ReadOnlyMemory m) 21 | { 22 | if (!MemoryMarshal.TryGetArray(m, out var arr)) 23 | { 24 | throw new InvalidOperationException("Can't get base array"); 25 | } 26 | return arr; 27 | } 28 | 29 | public static ArgumentException BufferTooSmall(int expected, int actual, string name) => new ArgumentException($"Require {expected} byte buffer, received {actual} byte", name); 30 | 31 | public static bool SequenceEqual(this Memory m1, ReadOnlyMemory m2) => m1.Span.SequenceEqual(m2.Span); 32 | 33 | public static void SodiumIncrement(this Span salt) 34 | { 35 | for (var i = 0; i < salt.Length; ++i) 36 | { 37 | if (++salt[i] != 0) 38 | { 39 | break; 40 | } 41 | } 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Shadowsocks.Interop/Utils/JsonHelper.cs: -------------------------------------------------------------------------------- 1 | using Shadowsocks.Models; 2 | using System.Text.Encodings.Web; 3 | using System.Text.Json; 4 | using System.Text.Json.Serialization; 5 | 6 | namespace Shadowsocks.Interop.Utils 7 | { 8 | public static class JsonHelper 9 | { 10 | public static readonly JsonSerializerOptions camelCaseJsonSerializerOptions = new JsonSerializerOptions() 11 | { 12 | DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault, 13 | Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, 14 | PropertyNamingPolicy = JsonNamingPolicy.CamelCase, 15 | WriteIndented = true, 16 | }; 17 | 18 | public static readonly JsonSerializerOptions snakeCaseJsonSerializerOptions = new JsonSerializerOptions() 19 | { 20 | DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault, 21 | Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, 22 | PropertyNamingPolicy = new JsonSnakeCaseNamingPolicy(), 23 | WriteIndented = true, 24 | }; 25 | 26 | public static readonly JsonSerializerOptions camelCaseJsonDeserializerOptions = new JsonSerializerOptions() 27 | { 28 | AllowTrailingCommas = true, 29 | PropertyNamingPolicy = JsonNamingPolicy.CamelCase, 30 | ReadCommentHandling = JsonCommentHandling.Skip, 31 | WriteIndented = true, 32 | }; 33 | 34 | public static readonly JsonSerializerOptions snakeCaseJsonDeserializerOptions = new JsonSerializerOptions() 35 | { 36 | AllowTrailingCommas = true, 37 | PropertyNamingPolicy = new JsonSnakeCaseNamingPolicy(), 38 | ReadCommentHandling = JsonCommentHandling.Skip, 39 | WriteIndented = true, 40 | }; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Shadowsocks.Protocol/Shadowsocks/Crypto/CryptoProvider.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace Shadowsocks.Protocol.Shadowsocks.Crypto 5 | { 6 | static class CryptoProvider 7 | { 8 | static Dictionary parameters = new Dictionary 9 | { 10 | ["xchacha20-ietf-poly1305"] = new CryptoParameter { KeySize = 32, NonceSize = 24, TagSize = 16, Crypto = typeof(AeadXChaCha20Poly1305Crypto) }, 11 | ["chacha20-ietf-poly1305"] = new CryptoParameter { KeySize = 32, NonceSize = 12, TagSize = 16, Crypto = typeof(AeadChaCha20Poly1305Crypto) }, 12 | ["aes-256-gcm"] = new CryptoParameter { KeySize = 32, NonceSize = 12, TagSize = 16, Crypto = typeof(AeadAesGcmCrypto) }, 13 | ["aes-192-gcm"] = new CryptoParameter { KeySize = 24, NonceSize = 12, TagSize = 16, Crypto = typeof(AeadAesGcmCrypto) }, 14 | ["aes-128-gcm"] = new CryptoParameter { KeySize = 16, NonceSize = 12, TagSize = 16, Crypto = typeof(AeadAesGcmCrypto) }, 15 | ["none"] = new CryptoParameter { KeySize = 0, NonceSize = 0, TagSize = 0, Crypto = typeof(UnsafeNoneCrypto) } 16 | }; 17 | 18 | public static CryptoParameter GetCrypto(string method) 19 | { 20 | if (string.IsNullOrEmpty(method)) 21 | { 22 | // todo 23 | //method = IoCManager.Container.Resolve().GetDefaultMethod(); 24 | } 25 | 26 | method = method.ToLowerInvariant(); 27 | var ok = parameters.TryGetValue(method, out var t); 28 | if (!ok) 29 | { 30 | //t = parameters[DefaultCipher]; 31 | throw new NotImplementedException(); 32 | } 33 | return t; 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Shadowsocks.WPF/Views/ServerSharingView.xaml.cs: -------------------------------------------------------------------------------- 1 | using ReactiveUI; 2 | using Shadowsocks.WPF.ViewModels; 3 | using System.Reactive.Disposables; 4 | using System.Windows.Input; 5 | 6 | namespace Shadowsocks.WPF.Views 7 | { 8 | /// 9 | /// Interaction logic for ServerSharingView.xaml 10 | /// 11 | public partial class ServerSharingView 12 | { 13 | public ServerSharingView() 14 | { 15 | InitializeComponent(); 16 | this.WhenActivated(disposables => 17 | { 18 | this.OneWayBind(ViewModel, 19 | viewModel => viewModel.SelectedServerUrlImage, 20 | view => view.qrCodeImage.Source) 21 | .DisposeWith(disposables); 22 | this.OneWayBind(ViewModel, 23 | viewModel => viewModel.Servers, 24 | view => view.serversListBox.ItemsSource) 25 | .DisposeWith(disposables); 26 | this.Bind(ViewModel, 27 | viewModel => viewModel.SelectedServer, 28 | view => view.serversListBox.SelectedItem) 29 | .DisposeWith(disposables); 30 | this.OneWayBind(ViewModel, 31 | viewModel => viewModel.SelectedServerUrl, 32 | view => view.urlTextBox.Text) 33 | .DisposeWith(disposables); 34 | 35 | this.BindCommand(ViewModel!, 36 | viewModel => viewModel.CopyLink, 37 | view => view.copyLinkButton) 38 | .DisposeWith(disposables); 39 | }); 40 | } 41 | 42 | private void urlTextBox_PreviewMouseDoubleClick(object sender, MouseButtonEventArgs e) 43 | { 44 | urlTextBox.SelectAll(); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Shadowsocks.WPF/Views/ServersView.xaml: -------------------------------------------------------------------------------- 1 | 18 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 34 | Servers 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /Shadowsocks.WPF/Views/DashboardView.xaml: -------------------------------------------------------------------------------- 1 | 18 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 34 | Dashboard 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /Shadowsocks.Protocol/Shadowsocks/Crypto/CryptoUtils.cs: -------------------------------------------------------------------------------- 1 | using CryptoBase.Digests.MD5; 2 | using System; 3 | using System.Buffers; 4 | using System.Text; 5 | 6 | namespace Shadowsocks.Protocol.Shadowsocks.Crypto 7 | { 8 | public static class CryptoUtils 9 | { 10 | public static byte[] SSKDF(string password, int keylen) 11 | { 12 | const int md5Length = 16; 13 | var pwMaxSize = Encoding.UTF8.GetMaxByteCount(password.Length); 14 | var key = new byte[keylen]; 15 | 16 | var pwBuffer = ArrayPool.Shared.Rent(pwMaxSize); 17 | var resultBuffer = ArrayPool.Shared.Rent(pwMaxSize + md5Length); 18 | try 19 | { 20 | var pwLength = Encoding.UTF8.GetBytes(password, pwBuffer); 21 | var pw = pwBuffer.AsSpan(0, pwLength); 22 | Span md5Sum = stackalloc byte[md5Length]; 23 | var result = resultBuffer.AsSpan(0, pwLength + md5Length); 24 | var i = 0; 25 | while (i < keylen) 26 | { 27 | if (i == 0) 28 | { 29 | MD5Utils.Default(pw, md5Sum); 30 | } 31 | else 32 | { 33 | md5Sum.CopyTo(result); 34 | pw.CopyTo(result.Slice(md5Length)); 35 | MD5Utils.Default(result, md5Sum); 36 | } 37 | 38 | var length = Math.Min(16, keylen - i); 39 | md5Sum.Slice(0, length).CopyTo(key.AsSpan(i, length)); 40 | 41 | i += md5Length; 42 | } 43 | return key; 44 | } 45 | finally 46 | { 47 | ArrayPool.Shared.Return(pwBuffer); 48 | ArrayPool.Shared.Return(resultBuffer); 49 | } 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Shadowsocks.CLI/Client/Legacy.cs: -------------------------------------------------------------------------------- 1 | using Shadowsocks.Models; 2 | using Shadowsocks.Net; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Diagnostics; 6 | using System.Linq; 7 | using System.Net; 8 | using System.Text; 9 | using System.Threading.Tasks; 10 | 11 | namespace Shadowsocks.CLI.Client 12 | { 13 | public class Legacy 14 | { 15 | private TCPListener? _tcpListener; 16 | private UDPListener? _udpListener; 17 | 18 | public void Start(string listenSocks, string serverAddress, int serverPort, string method, string password, string? plugin, string? pluginOpts, string? pluginArgs) 19 | { 20 | var localEP = IPEndPoint.Parse(listenSocks); 21 | var server = new Server() 22 | { 23 | Host = serverAddress, 24 | Port = serverPort, 25 | Method = method, 26 | Password = password, 27 | Plugin = plugin, 28 | PluginOpts = pluginOpts, 29 | }; 30 | if (!string.IsNullOrEmpty(plugin) && !string.IsNullOrEmpty(pluginArgs)) 31 | { 32 | var processStartInfo = new ProcessStartInfo(plugin, pluginArgs); 33 | server.PluginArgs = processStartInfo.ArgumentList.ToList(); 34 | } 35 | 36 | var tcpRelay = new TCPRelay(server); 37 | _tcpListener = new TCPListener(localEP, new List() 38 | { 39 | tcpRelay, 40 | }); 41 | _tcpListener.Start(); 42 | 43 | var udpRelay = new UDPRelay(server); 44 | _udpListener = new UDPListener(localEP, new List() 45 | { 46 | udpRelay, 47 | }); 48 | _udpListener.Start(); 49 | } 50 | 51 | public void Stop() 52 | { 53 | _tcpListener?.Stop(); 54 | _udpListener?.Stop(); 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Shadowsocks.Protocol/Socks5/Socks5UserPasswordRequestMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Shadowsocks.Protocol.Socks5 4 | { 5 | public class Socks5UserPasswordRequestMessage : Socks5Message 6 | { 7 | // 1 lUser [User] lPassword [Password] 8 | 9 | public Memory User; 10 | public Memory Password; 11 | 12 | public override int Serialize(Memory buffer) 13 | { 14 | var required = User.Length + Password.Length + 3; 15 | if (buffer.Length < required) throw Util.BufferTooSmall(required, buffer.Length, nameof(buffer)); 16 | buffer.Span[0] = 1; 17 | buffer.Span[1] = (byte) User.Length; 18 | User.CopyTo(buffer.Slice(2)); 19 | buffer.Span[User.Length + 2] = (byte) Password.Length; 20 | Password.CopyTo(buffer.Slice(User.Length + 3)); 21 | return required; 22 | } 23 | 24 | public override (bool success, int length) TryLoad(ReadOnlyMemory buffer) 25 | { 26 | if (buffer.Length < 2) return (false, 2); 27 | if (buffer.Span[0] != 1) return (false, 0); 28 | int userLength = buffer.Span[1]; 29 | if (buffer.Length < userLength + 3) return (false, userLength + 3); 30 | int passLength = buffer.Span[userLength + 2]; 31 | if (buffer.Length < userLength + passLength + 3) return (false, userLength + passLength + 3); 32 | 33 | User = Util.GetArray(buffer[2..(2 + userLength)]); 34 | Password = Util.GetArray(buffer[(3 + userLength)..(3 + userLength + passLength)]); 35 | return (true, userLength + passLength + 3); 36 | } 37 | 38 | public override bool Equals(IProtocolMessage other) 39 | { 40 | if (other is null) return false; 41 | if (ReferenceEquals(this, other)) return true; 42 | if (other.GetType() != GetType()) return false; 43 | var msg = (Socks5UserPasswordRequestMessage) other; 44 | return User.SequenceEqual(msg.User) && Password.SequenceEqual(msg.Password); 45 | } 46 | } 47 | } -------------------------------------------------------------------------------- /Shadowsocks.Protocol/Socks5/Socks5UdpMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.Net; 4 | 5 | namespace Shadowsocks.Protocol.Socks5 6 | { 7 | public class Socks5UdpMessage : Socks5Message 8 | { 9 | public byte Fragment; 10 | public EndPoint EndPoint = new IPEndPoint(IPAddress.Any, 0); 11 | 12 | public override int Serialize(Memory buffer) 13 | { 14 | var addrLen = NeededBytes(EndPoint); 15 | if (buffer.Length < addrLen + 3) throw Util.BufferTooSmall(addrLen + 3, buffer.Length, nameof(buffer)); 16 | buffer.Span[0] = 0; 17 | buffer.Span[1] = 0; 18 | buffer.Span[2] = Fragment; 19 | 20 | return SerializeAddress(buffer[3..], EndPoint) + 3; 21 | } 22 | 23 | public override (bool success, int length) TryLoad(ReadOnlyMemory buffer) 24 | { 25 | if (buffer.Length < 4) return (false, 4); 26 | if (buffer.Span[0] != 0 || buffer.Span[1] != 0) return (false, 0); 27 | if (buffer.Span[3] == 3 && buffer.Length < 5) return (false, 5); 28 | var req = buffer.Span[3] switch 29 | { 30 | AddressIPv4 => 10, 31 | AddressDomain => buffer.Span[4] + 7, 32 | AddressIPv6 => 22, 33 | _ => 0, 34 | }; 35 | if (req == 0) return (false, 0); 36 | if (buffer.Length < req) return (false, req); 37 | 38 | (var state, var len) = TryParseAddress(buffer[3..], out var ep); 39 | Debug.Assert(state); 40 | Debug.Assert(len == req - 3); 41 | 42 | Fragment = buffer.Span[2]; 43 | EndPoint = ep; 44 | return (true, req); 45 | } 46 | 47 | public override bool Equals(IProtocolMessage other) 48 | { 49 | if (other is null) return false; 50 | if (ReferenceEquals(this, other)) return true; 51 | if (other.GetType() != GetType()) return false; 52 | var msg = (Socks5UdpMessage) other; 53 | return Fragment == msg.Fragment && Equals(EndPoint, msg.EndPoint); 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /Shadowsocks.WPF/Utils/FileManager.cs: -------------------------------------------------------------------------------- 1 | using Splat; 2 | using System; 3 | using System.IO; 4 | using System.IO.Compression; 5 | using System.Text; 6 | 7 | namespace Shadowsocks.WPF.Utils 8 | { 9 | public static class FileManager 10 | { 11 | public static bool ByteArrayToFile(string fileName, byte[] content) 12 | { 13 | try 14 | { 15 | using (var fs = new FileStream(fileName, FileMode.Create, FileAccess.Write)) 16 | fs.Write(content, 0, content.Length); 17 | return true; 18 | } 19 | catch (Exception ex) 20 | { 21 | LogHost.Default.Error(ex, ""); 22 | } 23 | return false; 24 | } 25 | 26 | public static void UncompressFile(string fileName, byte[] content) 27 | { 28 | // Because the uncompressed size of the file is unknown, 29 | // we are using an arbitrary buffer size. 30 | byte[] buffer = new byte[4096]; 31 | int n; 32 | 33 | using(var fs = File.Create(fileName)) 34 | using (var input = new GZipStream(new MemoryStream(content), 35 | CompressionMode.Decompress, false)) 36 | { 37 | while ((n = input.Read(buffer, 0, buffer.Length)) > 0) 38 | { 39 | fs.Write(buffer, 0, n); 40 | } 41 | } 42 | } 43 | 44 | public static string NonExclusiveReadAllText(string path) 45 | { 46 | return NonExclusiveReadAllText(path, Encoding.Default); 47 | } 48 | 49 | public static string NonExclusiveReadAllText(string path, Encoding encoding) 50 | { 51 | try 52 | { 53 | using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) 54 | using (var sr = new StreamReader(fs, encoding)) 55 | { 56 | return sr.ReadToEnd(); 57 | } 58 | } 59 | catch (Exception ex) 60 | { 61 | LogHost.Default.Error(ex, ""); 62 | throw; 63 | } 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /Shadowsocks.WPF/Views/OnlineConfigView.xaml.cs: -------------------------------------------------------------------------------- 1 | using ReactiveUI; 2 | using Shadowsocks.WPF.ViewModels; 3 | using System.Reactive.Disposables; 4 | 5 | namespace Shadowsocks.WPF.Views 6 | { 7 | /// 8 | /// Interaction logic for OnlineConfigView.xaml 9 | /// 10 | public partial class OnlineConfigView 11 | { 12 | public OnlineConfigView() 13 | { 14 | InitializeComponent(); 15 | ViewModel = new OnlineConfigViewModel(); 16 | this.WhenActivated(disposables => 17 | { 18 | this.OneWayBind(ViewModel, 19 | viewModel => viewModel.Sources, 20 | view => view.sourcesListBox.ItemsSource) 21 | .DisposeWith(disposables); 22 | this.Bind(ViewModel, 23 | viewModel => viewModel.SelectedSource, 24 | view => view.sourcesListBox.SelectedItem) 25 | .DisposeWith(disposables); 26 | this.Bind(ViewModel, 27 | viewModel => viewModel.Address, 28 | view => view.urlTextBox.Text) 29 | .DisposeWith(disposables); 30 | 31 | this.BindCommand(ViewModel, 32 | viewModel => viewModel.Update, 33 | view => view.updateButton) 34 | .DisposeWith(disposables); 35 | this.BindCommand(ViewModel, 36 | viewModel => viewModel.UpdateAll, 37 | view => view.updateAllButton) 38 | .DisposeWith(disposables); 39 | this.BindCommand(ViewModel, 40 | viewModel => viewModel.CopyLink, 41 | view => view.copyLinkButton) 42 | .DisposeWith(disposables); 43 | this.BindCommand(ViewModel, 44 | viewModel => viewModel.Remove, 45 | view => view.removeButton) 46 | .DisposeWith(disposables); 47 | this.BindCommand(ViewModel, 48 | viewModel => viewModel.Add, 49 | view => view.addButton) 50 | .DisposeWith(disposables); 51 | }); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /Shadowsocks.Net/Proxy/DirectConnect.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | using System.Net.Sockets; 4 | using System.Threading; 5 | using System.Threading.Tasks; 6 | 7 | namespace Shadowsocks.Net.Proxy 8 | { 9 | public class DirectConnect : IProxy 10 | { 11 | private class FakeAsyncResult : IAsyncResult 12 | { 13 | public FakeAsyncResult(object state) 14 | { 15 | AsyncState = state; 16 | } 17 | 18 | public bool IsCompleted { get; } = true; 19 | public WaitHandle AsyncWaitHandle { get; } = null; 20 | public object AsyncState { get; } 21 | public bool CompletedSynchronously { get; } = true; 22 | } 23 | 24 | private class FakeEndPoint : EndPoint 25 | { 26 | public override AddressFamily AddressFamily { get; } = AddressFamily.Unspecified; 27 | 28 | public override string ToString() 29 | { 30 | return "null proxy"; 31 | } 32 | } 33 | 34 | private readonly Socket _remote = new Socket(SocketType.Stream, ProtocolType.Tcp); 35 | 36 | public EndPoint LocalEndPoint => _remote.LocalEndPoint; 37 | 38 | public EndPoint ProxyEndPoint { get; } = new FakeEndPoint(); 39 | public EndPoint DestEndPoint { get; private set; } 40 | 41 | public void Shutdown(SocketShutdown how) 42 | { 43 | _remote.Shutdown(how); 44 | } 45 | 46 | public void Close() 47 | { 48 | _remote.Dispose(); 49 | } 50 | 51 | public Task ConnectProxyAsync(EndPoint remoteEP, NetworkCredential auth = null, CancellationToken token = default) 52 | { 53 | return Task.CompletedTask; 54 | } 55 | 56 | public async Task ConnectRemoteAsync(EndPoint destEndPoint, CancellationToken token = default) 57 | { 58 | DestEndPoint = destEndPoint; 59 | await _remote.ConnectAsync(destEndPoint); 60 | } 61 | 62 | public async Task SendAsync(ReadOnlyMemory buffer, CancellationToken token = default) 63 | { 64 | return await _remote.SendAsync(buffer, SocketFlags.None, token); 65 | } 66 | 67 | public async Task ReceiveAsync(Memory buffer, CancellationToken token = default) 68 | { 69 | return await _remote.ReceiveAsync(buffer, SocketFlags.None, token); 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /Shadowsocks.WPF/Views/ServerSharingView.xaml: -------------------------------------------------------------------------------- 1 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 29 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 41 | 42 | 43 | 44 | 45 | 50 |