Exemplo n.º 1
0
        public string EncodeProxyList(Server[] servers, out Server[] encodedServers)
        {
            var encodedServersList = new List <Server>();
            var serverLines        = servers
                                     .Select(server =>
            {
                string serverLine = server switch
                {
                    ShadowsocksServer ssServer => this.EncodeShadowsocksServer(ssServer),
                    ShadowsocksRServer ssrServer => this.EncodeShadowsocksRServer(ssrServer),
                    _ => null,
                };
                if (!string.IsNullOrWhiteSpace(serverLine))
                {
                    encodedServersList.Add(server);
                }
                else
                {
                    this.logger.LogInformation($"Server {server} is ignored.");
                }
                return(serverLine);
            })
                                     .Where(line => !string.IsNullOrWhiteSpace(line))
                                     .ToArray();

            encodedServers = encodedServersList.ToArray();
            return(string.Join('\n', serverLines));
        }
Exemplo n.º 2
0
        public string Encode(EncodeOptions options, Server[] servers, out Server[] encodedServers)
        {
            var encodedServerList = new List <Server>();
            var sb = new StringBuilder();

            sb.AppendLine($"REMARKS={options.ProfileName}");
            sb.AppendLine("");

            foreach (var server in servers)
            {
                var serverLine = server switch
                {
                    ShadowsocksServer ss => EncodeShadowsocksServer(ss),
                    ShadowsocksRServer ssr => EncodeShadowsocksRServer(ssr),
                    _ => null,
                };

                if (string.IsNullOrWhiteSpace(serverLine))
                {
                    this.logger.LogInformation($"Server {server} is ignored.");
                }
                else
                {
                    encodedServerList.Add(server);
                    sb.AppendLine(serverLine);
                }
            }

            encodedServers = encodedServerList.ToArray();
            return(Convert.ToBase64String(Encoding.ASCII.GetBytes(sb.ToString())));
        }
Exemplo n.º 3
0
        private string EncodeShadowsocksRServer(ShadowsocksRServer server, string groupName = null)
        {
            // base64(host:port:protocol:method:obfs:base64pass/?group=base64group)
            var serverInfo = $"{server.Host}:{server.Port}:{server.Protocol}:{server.Method}:{server.Obfuscation}";

            var otherInfos = new List <string>()
            {
                "remarks=" + WebSafeBase64Encode(Encoding.UTF8.GetBytes(server.Name))
            };

            if (!string.IsNullOrEmpty(server.ObfuscationParameter))
            {
                otherInfos.Add("obfsparam=" + WebSafeBase64Encode(Encoding.UTF8.GetBytes(server.ObfuscationParameter)));
            }
            if (!string.IsNullOrEmpty(server.ProtocolParameter))
            {
                otherInfos.Add("protoparam=" + WebSafeBase64Encode(Encoding.UTF8.GetBytes(server.ProtocolParameter)));
            }
            if (server.UDPPort > 0)
            {
                otherInfos.Add($"udpport={server.UDPPort}");
            }
            if (server.UDPOverTCP)
            {
                otherInfos.Add("uot=1");
            }
            if (!string.IsNullOrEmpty(groupName))
            {
                otherInfos.Add("group=" + WebSafeBase64Encode(Encoding.UTF8.GetBytes(groupName)));
            }

            return("ssr://" + WebSafeBase64Encode(Encoding.UTF8.GetBytes(serverInfo + "/?" + string.Join("&", otherInfos))));
        }
Exemplo n.º 4
0
        public string EncodeShadowsocksRServer(ShadowsocksRServer server)
        {
            var properties = new List <string>();

            properties.Add($"shadowsocks={server.Host}:{server.Port}");
            properties.Add($"method={server.Method}");
            properties.Add($"password={server.Password}");
            properties.Add($"ssr-protocol={server.Protocol}");
            properties.Add($"ssr-protocol-param={server.ProtocolParameter}");
            properties.Add($"obfs={server.Obfuscation}");
            properties.Add($"obfs-host={server.ObfuscationParameter}");
            properties.Add($"tag={server.Name}");
            return(string.Join(", ", properties));
        }
Exemplo n.º 5
0
        /// <summary>
        /// Follow scheme https://github.com/shadowsocksr-backup/shadowsocks-rss/wiki/SSR-QRcode-scheme
        /// to parse a given shadowsocksR server uri.
        /// </summary>
        ShadowsocksRServer ParseShadowsocksRURI(string ssrURI)
        {
            ssrURI = ssrURI.Substring("ssr://".Length);
            var splitted = Encoding.UTF8.GetString(WebSafeBase64Decode(HttpUtility.UrlDecode(ssrURI))).Split("/?");

            // host:port:protocol:method:obfs:base64pass
            var serverInfo = splitted[0].Split(":", 6);
            var server     = new ShadowsocksRServer()
            {
                Host        = serverInfo[0],
                Port        = Convert.ToInt32(serverInfo.ElementAtOrDefault(1) ?? "0"),
                Protocol    = serverInfo.ElementAtOrDefault(2),
                Method      = serverInfo.ElementAtOrDefault(3),
                Obfuscation = serverInfo.ElementAtOrDefault(4),
                Password    = Encoding.ASCII.GetString(Convert.FromBase64String(serverInfo.ElementAtOrDefault(5) ?? "")),
            };

            // /?obfsparam=base64param&protoparam=base64param&remarks=base64remarks&group=base64group&udpport=0&uot=0
            var otherInfos = splitted.ElementAtOrDefault(1);

            if (!string.IsNullOrEmpty(otherInfos))
            {
                var qs = HttpUtility.ParseQueryString(otherInfos);
                server.ProtocolParameter = qs["protoparam"] != null?Encoding.UTF8.GetString(WebSafeBase64Decode(qs["protoparam"])) : null;

                server.ObfuscationParameter = qs["obfsparam"] != null?Encoding.UTF8.GetString(WebSafeBase64Decode(qs["obfsparam"])) : null;

                server.Name = qs["remarks"] != null?Encoding.UTF8.GetString(WebSafeBase64Decode(qs["remarks"])) : null;

                server.UDPOverTCP = qs["uot"] != null && qs["uot"] != "0";
                int UDPPort;
                if (Int32.TryParse(qs["udpport"], out UDPPort))
                {
                    server.UDPPort = UDPPort;
                }
            }

            return(server);
        }
Exemplo n.º 6
0
        /// <summary>
        /// Parse QuantumultX shadowsocks proxy setting
        /// Sample:
        ///   shadowsocks=example.com:80, method=chacha20, password=pwd, obfs=http, obfs-host=bing.com, obfs-uri=/resource/file, fast-open=false, udp-relay=false, server_check_url=http://www.apple.com/generate_204, tag=ss-01
        ///   shadowsocks=example.com:443, method=chacha20, password=pwd, ssr-protocol=auth_chain_b, ssr-protocol-param=def, obfs=tls1.2_ticket_fastauth, obfs-host=bing.com, tag=ssr
        /// </summary>
        /// <param name="line">A string starts with `shadowsocks=`</param>
        /// <returns>Could be an instance of <see cref="ShadowsocksRServer"> or <see cref="ShadowsocksServer"></returns>
        public Server ParseShadowsocksLine(string line)
        {
            var properties = new Dictionary <string, string>();

            foreach (var kvPair in line.Split(","))
            {
                var parts = kvPair.Split("=", 2);
                if (parts.Length != 2)
                {
                    this.logger.LogWarning($"[{{ComponentName}}] Invaild shadowsocks setting: {line}", this.GetType());
                    return(null);
                }

                properties.TryAdd(parts[0].Trim().ToLower(), parts[1].Trim());
            }

            var host     = default(string);
            var port     = default(int);
            var method   = properties.GetValueOrDefault("method");
            var password = properties.GetValueOrDefault("password");

            if (!Misc.SplitHostAndPort(properties.GetValueOrDefault("shadowsocks"), out host, out port))
            {
                this.logger.LogWarning($"[{{ComponentName}}] Host and port are invalid and this proxy setting is ignored. Invaild shadowsocks setting : {line}", this.GetType());
                return(null);
            }

            if (string.IsNullOrEmpty(method))
            {
                this.logger.LogWarning($"[{{ComponentName}}] Encryption method is missing and this proxy setting is ignored. Invaild shadowsocks setting : {line}", this.GetType());
                return(null);
            }

            if (string.IsNullOrEmpty(password))
            {
                this.logger.LogWarning($"[{{ComponentName}}] Password is missing and this proxy setting is ignored. Invaild shadowsocks setting : {line}", this.GetType());
                return(null);
            }

            Server server;

            if (this.IsShadowsocksRServer(properties))
            {
                var ssrServer = new ShadowsocksRServer
                {
                    Method = method,
                };

                ssrServer.Obfuscation          = properties.GetValueOrDefault("obfs");
                ssrServer.ObfuscationParameter = properties.GetValueOrDefault("obfs-host");
                ssrServer.Protocol             = properties.GetValueOrDefault("ssr-protocol");
                ssrServer.ProtocolParameter    = properties.GetValueOrDefault("ssr-protocol-param");
                // QuantumultX doesn't support following parameter yet
                //   * UDP Port
                //   * UDP over TCP

                server = ssrServer;
            }
            else
            {
                var ssServer = new ShadowsocksServer
                {
                    Method = method,
                };

                if (bool.TryParse(properties.GetValueOrDefault("udp-relay", "false"), out bool udpRelay))
                {
                    ssServer.UDPRelay = udpRelay;
                }

                if (bool.TryParse(properties.GetValueOrDefault("fast-open", "false"), out bool fastOpen))
                {
                    ssServer.FastOpen = fastOpen;
                }

                var obfs = properties.GetValueOrDefault("obfs", "").ToLower();
                switch (obfs)
                {
                case "tls":
                case "http":
                {
                    if (!SimpleObfsPluginOptions.TryParseMode(obfs, out SimpleObfsPluginMode mode))
                    {
                        this.logger.LogWarning($"[{{ComponentName}}] Simple-obfs mode `{obfs}` is not supported and this proxy setting is ignored. Invaild shadowsocks setting : {line}", this.GetType());
                        return(null);
                    }

                    var options = new SimpleObfsPluginOptions()
                    {
                        Host = properties.GetValueOrDefault("obfs-host"),
                        Mode = mode,
                    };

                    if (obfs != "tls")
                    {
                        options.Uri = properties.GetValueOrDefault("obfs-uri");
                    }

                    ssServer.PluginOptions = options;
                }
                break;

                case "wss":
                case "ws":
                {
                    if (!V2RayPluginOptions.TryParseMode(obfs, out V2RayPluginMode mode))
                    {
                        this.logger.LogWarning($"[{{ComponentName}}] Simple-obfs mode `{obfs}` is not supported and this proxy setting is ignored. Invaild shadowsocks setting : {line}", this.GetType());
                        return(null);
                    }

                    var options = new V2RayPluginOptions()
                    {
                        Mode      = mode,
                        Host      = properties.GetValueOrDefault("obfs-host"),
                        Path      = properties.GetValueOrDefault("obfs-uri"),
                        EnableTLS = obfs == "wss",
                    };

                    ssServer.PluginOptions = options;
                }
                break;

                default:
                    this.logger.LogWarning($"[{{ComponentName}}] Obfuscation `{obfs}` is not supported and this proxy setting is ignored. Invaild shadowsocks setting : {line}", this.GetType());
                    return(null);
                }

                server = ssServer;
            }

            server.Host = host;
            server.Port = port;
            server.Name = properties.GetValueOrDefault("tag", $"{server.Host}:{server.Port}");

            return(server);
        }