Ejemplo n.º 1
0
        public Server ParseShadowsocksServer(YamlMappingNode proxy)
        {
            string portString = Yaml.GetStringOrDefaultFromYamlChildrenNode(proxy, "port", "0");
            int    port;

            if (!int.TryParse(portString, out port))
            {
                this.logger.LogError($"Invalid port: {port}.");
                return(null);
            }

            var server = new ShadowsocksServer()
            {
                Port     = port,
                Name     = Yaml.GetStringOrDefaultFromYamlChildrenNode(proxy, "name"),
                Host     = Yaml.GetStringOrDefaultFromYamlChildrenNode(proxy, "server"),
                Password = Yaml.GetStringOrDefaultFromYamlChildrenNode(proxy, "password"),
                Method   = Yaml.GetStringOrDefaultFromYamlChildrenNode(proxy, "cipher"),
                UDPRelay = Yaml.GetTruthFromYamlChildrenNode(proxy, "udp"),
            };

            YamlNode pluginOptionsNode;

            // refer to offical clash to parse plugin options
            // https://github.com/Dreamacro/clash/blob/34338e7107c1868124f8aab2446f6b71c9b0640f/adapters/outbound/shadowsocks.go#L135
            if (proxy.Children.TryGetValue("plugin-opts", out pluginOptionsNode) && pluginOptionsNode.NodeType == YamlNodeType.Mapping)
            {
                switch (Yaml.GetStringOrDefaultFromYamlChildrenNode(proxy, "plugin").ToLower())
                {
                case "obfs":
                    var simpleObfsModeString = Yaml.GetStringOrDefaultFromYamlChildrenNode(pluginOptionsNode, "mode");
                    var simpleObfsOptions    = new SimpleObfsPluginOptions();

                    if (SimpleObfsPluginOptions.TryParseMode(simpleObfsModeString, out SimpleObfsPluginMode simpleObfsMode))
                    {
                        simpleObfsOptions.Mode = simpleObfsMode;
                    }
                    else if (!string.IsNullOrWhiteSpace(simpleObfsModeString))
                    {
                        this.logger.LogError($"Unsupported simple-obfs mode: {simpleObfsModeString}. This server will be ignored.");
                        return(null);
                    }
                    simpleObfsOptions.Host = Yaml.GetStringOrDefaultFromYamlChildrenNode(pluginOptionsNode, "host");

                    server.PluginOptions = simpleObfsOptions;
                    break;

                case "v2ray-plugin":
                    // also refer to official v2ray-plugin to parse v2ray-plugin options
                    // https://github.com/shadowsocks/v2ray-plugin/blob/c7017f45bb1e12cf1e4b739bcb8f42f3eb8b22cd/main.go#L126
                    var v2rayModeString = Yaml.GetStringOrDefaultFromYamlChildrenNode(pluginOptionsNode, "mode");
                    var options         = new V2RayPluginOptions();
                    server.PluginOptions = options;

                    if (V2RayPluginOptions.TryParseMode(v2rayModeString, out V2RayPluginMode v2rayMode))
                    {
                        options.Mode = v2rayMode;
                    }
                    else
                    {
                        this.logger.LogError($"Unsupported v2ray-plugin mode: {v2rayModeString}. This server will be ignored.");
                        return(null);
                    }

                    options.Host                 = Yaml.GetStringOrDefaultFromYamlChildrenNode(pluginOptionsNode, "host");
                    options.Path                 = Yaml.GetStringOrDefaultFromYamlChildrenNode(pluginOptionsNode, "path");
                    options.EnableTLS            = Yaml.GetTruthFromYamlChildrenNode(pluginOptionsNode, "tls");
                    options.SkipCertVerification = Yaml.GetTruthFromYamlChildrenNode(pluginOptionsNode, "skip-cert-verify");
                    options.Headers              = new Dictionary <string, string>();

                    YamlNode headersNode;
                    if (!(pluginOptionsNode as YamlMappingNode).Children.TryGetValue("headers", out headersNode))
                    {
                        break;
                    }
                    if (headersNode.NodeType != YamlNodeType.Mapping)
                    {
                        break;
                    }

                    foreach (var header in (headersNode as YamlMappingNode))
                    {
                        if (header.Value.NodeType != YamlNodeType.Scalar)
                        {
                            continue;
                        }
                        options.Headers.Add((header.Key as YamlScalarNode).Value, (header.Value as YamlScalarNode).Value);
                    }
                    break;
                }
            }

            if (server.PluginOptions == null)
            {
                var simpleObfsModeString = Yaml.GetStringOrDefaultFromYamlChildrenNode(proxy, "obfs");

                if (SimpleObfsPluginOptions.TryParseMode(simpleObfsModeString, out SimpleObfsPluginMode simpleObfsMode))
                {
                    server.PluginOptions = new SimpleObfsPluginOptions()
                    {
                        Mode = simpleObfsMode,
                        Host = Yaml.GetStringOrDefaultFromYamlChildrenNode(proxy, "obfs-host")
                    };
                }
                else if (!string.IsNullOrWhiteSpace(simpleObfsModeString))
                {
                    this.logger.LogError($"Unsupported simple-obfs mode: {simpleObfsModeString}");
                    return(null);
                }
            }

            return(server);
        }
Ejemplo n.º 2
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);
        }
Ejemplo n.º 3
0
        public static Server ParseShadowsocksServer(YamlMappingNode proxy)
        {
            int port;

            if (!Int32.TryParse(Yaml.GetStringOrDefaultFromYamlChildrenNode(proxy, "port", "0"), out port))
            {
                return(null);
            }

            var server = new ShadowsocksServer()
            {
                Port     = port,
                Name     = Yaml.GetStringOrDefaultFromYamlChildrenNode(proxy, "name"),
                Host     = Yaml.GetStringOrDefaultFromYamlChildrenNode(proxy, "server"),
                Password = Yaml.GetStringOrDefaultFromYamlChildrenNode(proxy, "password"),
                Method   = Yaml.GetStringOrDefaultFromYamlChildrenNode(proxy, "cipher"),
                UDPRelay = Yaml.GetTruthFromYamlChildrenNode(proxy, "udp"),
            };

            YamlNode pluginOptionsNode;

            // refer to offical clash to parse plugin options
            // https://github.com/Dreamacro/clash/blob/34338e7107c1868124f8aab2446f6b71c9b0640f/adapters/outbound/shadowsocks.go#L135
            if (proxy.Children.TryGetValue("plugin-opts", out pluginOptionsNode) && pluginOptionsNode.NodeType == YamlNodeType.Mapping)
            {
                switch (Yaml.GetStringOrDefaultFromYamlChildrenNode(proxy, "plugin"))
                {
                case "obfs":
                    server.PluginType    = PluginType.SimpleObfs;
                    server.PluginOptions = new SimpleObfsPluginOptions()
                    {
                        Mode = Yaml.GetStringOrDefaultFromYamlChildrenNode(pluginOptionsNode, "mode"),
                        Host = Yaml.GetStringOrDefaultFromYamlChildrenNode(pluginOptionsNode, "host"),
                    };
                    break;

                case "v2ray-plugin":
                    // also refer to official v2ray-plugin to parse v2ray-plugin options
                    // https://github.com/shadowsocks/v2ray-plugin/blob/c7017f45bb1e12cf1e4b739bcb8f42f3eb8b22cd/main.go#L126
                    var options = new V2RayPluginOptions();
                    server.PluginType    = PluginType.V2Ray;
                    server.PluginOptions = options;

                    options.Host                 = Yaml.GetStringOrDefaultFromYamlChildrenNode(pluginOptionsNode, "host");
                    options.Mode                 = Yaml.GetStringOrDefaultFromYamlChildrenNode(pluginOptionsNode, "mode");
                    options.Path                 = Yaml.GetStringOrDefaultFromYamlChildrenNode(pluginOptionsNode, "path");
                    options.EnableTLS            = Yaml.GetTruthFromYamlChildrenNode(pluginOptionsNode, "tls");
                    options.SkipCertVerification = Yaml.GetTruthFromYamlChildrenNode(pluginOptionsNode, "skip-cert-verify");
                    options.Headers              = new Dictionary <string, string>();

                    YamlNode headersNode;
                    if (!(pluginOptionsNode as YamlMappingNode).Children.TryGetValue("headers", out headersNode))
                    {
                        break;
                    }
                    if (headersNode.NodeType != YamlNodeType.Mapping)
                    {
                        break;
                    }

                    foreach (var header in (headersNode as YamlMappingNode))
                    {
                        if (header.Value.NodeType != YamlNodeType.Scalar)
                        {
                            continue;
                        }
                        options.Headers.Add((header.Key as YamlScalarNode).Value, (header.Value as YamlScalarNode).Value);
                    }
                    break;
                }
            }


            if (server.PluginType == PluginType.None)
            {
                var obfs     = Yaml.GetStringOrDefaultFromYamlChildrenNode(proxy, "obfs");
                var obfsHost = Yaml.GetStringOrDefaultFromYamlChildrenNode(proxy, "obfs-host");

                if (!String.IsNullOrEmpty(obfs))
                {
                    server.PluginType    = PluginType.SimpleObfs;
                    server.PluginOptions = new SimpleObfsPluginOptions()
                    {
                        Mode = obfs,
                        Host = obfsHost
                    };
                }
            }

            return(server);
        }