Esempio n. 1
0
        /// <summary>
        ///		根据服务器生成分享链接
        /// </summary>
        /// <param name="server">需要获取分享链接的服务器</param>
        /// <returns>解码后的字符串</returns>
        public static string GetShareLink(Server server)
        {
            var retLinkStr = "";

            switch (server.Type)
            {
            case "Socks5":
                // https://t.me/socks?server=1.1.1.1&port=443
                retLinkStr = string.Format("https://t.me/socks?server={0}&port={1}", server.Hostname, server.Port);

                break;

            case "SS":
                // ss://method:password@server:port#Remark
                retLinkStr = "ss://" + URLSafeBase64Encode(string.Format("{0}:{1}@{2}:{3}", server.EncryptMethod, server.Password, server.Hostname, server.Port)) + "#" + HttpUtility.UrlEncode(server.Remark);

                break;

            case "SSR":
                // https://github.com/shadowsocksr-backup/shadowsocks-rss/wiki/SSR-QRcode-scheme
                // ssr://base64(host:port:protocol:method:obfs:base64pass/?obfsparam=base64param&protoparam=base64param&remarks=base64remarks&group=base64group&udpport=0&uot=0)
                var paraStr = string.Format("/?obfsparam={0}&protoparam={1}&remarks={2}", URLSafeBase64Encode(server.OBFSParam), URLSafeBase64Encode(server.ProtocolParam), URLSafeBase64Encode(server.Remark));
                retLinkStr = "ssr://" + URLSafeBase64Encode(string.Format("{0}:{1}:{2}:{3}:{4}:{5}{6}", server.Hostname, server.Port, server.Protocol, server.EncryptMethod, server.OBFS, URLSafeBase64Encode(server.Password), paraStr));

                break;

            case "VMess":
                var vmessJson = JsonConvert.SerializeObject(new
                {
                    v    = "2",
                    ps   = server.Remark,
                    add  = server.Hostname,
                    port = server.Port,
                    id   = server.UserID,
                    aid  = server.AlterID,
                    net  = server.TransferProtocol,
                    type = server.FakeType,
                    host = server.Host,
                    path = server.Path,
                    tls  = server.TLSSecure ? "tls" : ""
                });
                retLinkStr = "vmess://" + URLSafeBase64Encode(vmessJson);

                break;

            default:
                return(null);
            }
            return(retLinkStr);
        }
Esempio n. 2
0
        /// <summary>
        /// SSR链接解析器
        /// Copy From https://github.com/HMBSbige/ShadowsocksR-Windows/blob/d9dc8d032a6e04c14b9dc6c8f673c9cc5aa9f607/shadowsocks-csharp/Model/Server.cs#L428
        /// Thx :D
        /// </summary>
        /// <param name="ssrUrl"></param>
        /// <returns></returns>
        public static Server SsrServerFromLink(string ssrUrl)
        {
            // ssr://host:port:protocol:method:obfs:base64pass/?obfsparam=base64&remarks=base64&group=base64&udpport=0&uot=1
            var ssr = Regex.Match(ssrUrl, "ssr://([A-Za-z0-9_-]+)", RegexOptions.IgnoreCase);

            if (!ssr.Success)
            {
                throw new FormatException();
            }

            var data        = URLSafeBase64Decode(ssr.Groups[1].Value);
            var params_dict = new Dictionary <string, string>();

            var param_start_pos = data.IndexOf("?", StringComparison.Ordinal);

            if (param_start_pos > 0)
            {
                params_dict = ParseParam(data.Substring(param_start_pos + 1));
                data        = data.Substring(0, param_start_pos);
            }
            if (data.IndexOf("/", StringComparison.Ordinal) >= 0)
            {
                data = data.Substring(0, data.LastIndexOf("/", StringComparison.Ordinal));
            }

            var UrlFinder = new Regex("^(.+):([^:]+):([^:]*):([^:]+):([^:]*):([^:]+)");
            var match     = UrlFinder.Match(data);

            if (match == null || !match.Success)
            {
                throw new FormatException();
            }

            var serverAddr  = match.Groups[1].Value;
            var Server_Port = ushort.Parse(match.Groups[2].Value);
            var Protocol    = match.Groups[3].Value.Length == 0 ? "origin" : match.Groups[3].Value;

            Protocol = Protocol.Replace("_compatible", "");
            var Method = match.Groups[4].Value;
            var obfs   = match.Groups[5].Value.Length == 0 ? "plain" : match.Groups[5].Value;

            obfs = obfs.Replace("_compatible", "");
            var Password      = URLSafeBase64Decode(match.Groups[6].Value);
            var ProtocolParam = "";
            var ObfsParam     = "";
            var Remarks       = "";
            var Group         = "";

            if (params_dict.ContainsKey("protoparam"))
            {
                ProtocolParam = URLSafeBase64Decode(params_dict["protoparam"]);
            }
            if (params_dict.ContainsKey("obfsparam"))
            {
                ObfsParam = URLSafeBase64Decode(params_dict["obfsparam"]);
            }
            if (params_dict.ContainsKey("remarks"))
            {
                Remarks = URLSafeBase64Decode(params_dict["remarks"]);
            }
            Group = params_dict.ContainsKey("group") ? URLSafeBase64Decode(params_dict["group"]) : string.Empty;

            /*if (params_dict.ContainsKey("uot"))
             * {
             *  UdpOverTcp = int.Parse(params_dict["uot"]) != 0;
             * }
             * if (params_dict.ContainsKey("udpport"))
             * {
             *  Server_Udp_Port = ushort.Parse(params_dict["udpport"]);
             * }*/
            var server = new Server();

            server.Type          = "SSR";
            server.Hostname      = serverAddr;
            server.Port          = Server_Port;
            server.Protocol      = Protocol;
            server.EncryptMethod = Method;
            server.OBFS          = obfs;
            server.Password      = Password;
            server.ProtocolParam = ProtocolParam;
            server.OBFSParam     = ObfsParam;
            server.Remark        = Remarks;
            server.Group         = Group;
            return(server);
        }
Esempio n. 3
0
        private static IEnumerable <Server> ParseLine(string text)
        {
            var list = new List <Server>();

            try
            {
                if (text.StartsWith("tg://socks?") || text.StartsWith("https://t.me/socks?"))
                {
                    var data = new Server();
                    data.Type = "Socks5";

                    var dict = new Dictionary <string, string>();
                    foreach (var str in text.Replace("tg://socks?", "").Replace("https://t.me/socks?", "").Split('&'))
                    {
                        var splited = str.Split('=');

                        dict.Add(splited[0], splited[1]);
                    }

                    if (!dict.ContainsKey("server") || !dict.ContainsKey("port"))
                    {
                        return(null);
                    }

                    data.Hostname = dict["server"];
                    data.Port     = int.Parse(dict["port"]);
                    if (dict.ContainsKey("user") && !string.IsNullOrWhiteSpace(dict["user"]))
                    {
                        data.Username = dict["user"];
                    }
                    if (dict.ContainsKey("pass") && !string.IsNullOrWhiteSpace(dict["pass"]))
                    {
                        data.Password = dict["pass"];
                    }

                    list.Add(data);
                }
                else if (text.StartsWith("ss://"))
                {
                    var data = new Server();
                    data.Type = "SS";

                    text = text.Replace("/?", "?");
                    try
                    {
                        if (text.Contains("#"))
                        {
                            data.Remark = HttpUtility.UrlDecode(text.Split('#')[1]);
                            text        = text.Split('#')[0];
                        }
                        if (text.Contains("?"))
                        {
                            var finder = new Regex(@"^(?<data>.+?)\?(.+)$");
                            var match  = finder.Match(text);

                            if (match.Success)
                            {
                                var plugins = HttpUtility.UrlDecode(HttpUtility.ParseQueryString(new Uri(text).Query).Get("plugin"));
                                if (plugins != null)
                                {
                                    var plugin     = plugins.Substring(0, plugins.IndexOf(";", StringComparison.Ordinal));
                                    var pluginopts = plugins.Substring(plugins.IndexOf(";", StringComparison.Ordinal) + 1);
                                    if (plugin == "obfs-local" || plugin == "simple-obfs")
                                    {
                                        plugin = "simple-obfs";
                                        if (!pluginopts.Contains("obfs="))
                                        {
                                            pluginopts = "obfs=http;obfs-host=" + pluginopts;
                                        }
                                    }
                                    else if (plugin == "simple-obfs-tls")
                                    {
                                        plugin = "simple-obfs";
                                        if (!pluginopts.Contains("obfs="))
                                        {
                                            pluginopts = "obfs=tls;obfs-host=" + pluginopts;
                                        }
                                    }

                                    data.Plugin       = plugin;
                                    data.PluginOption = pluginopts;
                                }

                                text = match.Groups["data"].Value;
                            }
                            else
                            {
                                throw new FormatException();
                            }
                        }
                        if (text.Contains("@"))
                        {
                            var finder = new Regex(@"^ss://(?<base64>.+?)@(?<server>.+):(?<port>\d+)");
                            var parser = new Regex(@"^(?<method>.+?):(?<password>.+)$");
                            var match  = finder.Match(text);
                            if (!match.Success)
                            {
                                throw new FormatException();
                            }

                            data.Hostname = match.Groups["server"].Value;
                            data.Port     = int.Parse(match.Groups["port"].Value);

                            var base64 = URLSafeBase64Decode(match.Groups["base64"].Value);
                            match = parser.Match(base64);
                            if (!match.Success)
                            {
                                throw new FormatException();
                            }

                            data.EncryptMethod = match.Groups["method"].Value;
                            data.Password      = match.Groups["password"].Value;
                        }
                        else
                        {
                            var parser = new Regex(@"^((?<method>.+?):(?<password>.+)@(?<server>.+):(?<port>\d+))");
                            var match  = parser.Match(URLSafeBase64Decode(text.Replace("ss://", "")));
                            if (!match.Success)
                            {
                                throw new FormatException();
                            }

                            data.Hostname      = match.Groups["server"].Value;
                            data.Port          = int.Parse(match.Groups["port"].Value);
                            data.EncryptMethod = match.Groups["method"].Value;
                            data.Password      = match.Groups["password"].Value;
                        }

                        if (!Global.EncryptMethods.SS.Contains(data.EncryptMethod))
                        {
                            Logging.Error($"不支持的 SS 加密方式:{data.EncryptMethod}");
                            return(null);
                        }

                        list.Add(data);
                    }
                    catch (FormatException)
                    {
                        return(null);
                    }
                }
                else if (text.StartsWith("ssd://"))
                {
                    var json = JsonConvert.DeserializeObject <Main>(URLSafeBase64Decode(text.Substring(6)));

                    foreach (var server in json.servers)
                    {
                        var data = new Server();
                        data.Type = "SS";

                        data.Remark        = server.remarks;
                        data.Hostname      = server.server;
                        data.Port          = server.port != 0 ? server.port : json.port;
                        data.Password      = server.password != null ? server.password : json.password;
                        data.EncryptMethod = server.encryption != null ? server.encryption : json.encryption;
                        data.Plugin        = string.IsNullOrEmpty(json.plugin) ? string.IsNullOrEmpty(server.plugin) ? null : server.plugin : json.plugin;
                        data.PluginOption  = string.IsNullOrEmpty(json.plugin_options) ? string.IsNullOrEmpty(server.plugin_options) ? null : server.plugin_options : json.plugin_options;

                        if (Global.EncryptMethods.SS.Contains(data.EncryptMethod))
                        {
                            list.Add(data);
                        }
                    }
                }
                else if (text.StartsWith("ssr://"))
                {
                    list.Add(SsrServerFromLink(text));
                }
                else if (text.StartsWith("vmess://"))
                {
                    var data = new Server();
                    data.Type = "VMess";

                    text = text.Substring(8);
                    var vmess = JsonConvert.DeserializeObject <VMess>(URLSafeBase64Decode(text));

                    data.Remark   = vmess.ps;
                    data.Hostname = vmess.add;
                    data.Port     = vmess.port;
                    data.UserID   = vmess.id;
                    data.AlterID  = vmess.aid;

                    data.TransferProtocol = vmess.net;
                    if (!Global.TransferProtocols.Contains(data.TransferProtocol))
                    {
                        Logging.Error($"不支持的 VMess 传输协议:{data.TransferProtocol}");
                        return(null);
                    }

                    data.FakeType = vmess.type;
                    if (data.FakeType.Length != 0 && !Global.FakeTypes.Contains(data.FakeType))
                    {
                        Logging.Error($"不支持的 VMess 伪装类型:{data.FakeType}");
                        return(null);
                    }

                    if (vmess.v == null || vmess.v == "1")
                    {
                        var info = vmess.host.Split(';');
                        if (info.Length == 2)
                        {
                            vmess.host = info[0];
                            vmess.path = info[1];
                        }
                    }
                    if (data.TransferProtocol == "quic")
                    {
                        if (!Global.EncryptMethods.VMessQUIC.Contains(vmess.host))
                        {
                            Logging.Error($"不支持的 VMess QUIC 加密方式:{vmess.host}");
                            return(null);
                        }

                        data.QUICSecure = vmess.host;
                        data.QUICSecret = vmess.path;
                    }
                    else
                    {
                        data.Host = vmess.host;
                        data.Path = vmess.path;
                    }
                    data.TLSSecure = vmess.tls == "tls";

                    if (vmess.mux == null)
                    {
                        data.UseMux = false;
                    }
                    else
                    {
                        if (vmess.mux.enabled is bool enabled)
                        {
                            data.UseMux = enabled;
                        }
                        else if (vmess.mux.enabled is string muxEnabled)
                        {
                            data.UseMux = muxEnabled == "true";  // 针对使用字符串当作布尔值的情况
                        }
                        else
                        {
                            data.UseMux = false;
                        }
                    }

                    data.EncryptMethod = "auto"; // V2Ray 加密方式不包括在链接中,主动添加一个

                    list.Add(data);
                }
                else if (text.StartsWith("Netch://"))
                {
                    text = text.Substring(8);
                    var NetchLink = JsonConvert.DeserializeObject <Server>(URLSafeBase64Decode(text));
                    if (!string.IsNullOrEmpty(NetchLink.Hostname) || NetchLink.Port > 65536 || NetchLink.Port > 0)
                    {
                        return(null);
                    }

                    switch (NetchLink.Type)
                    {
                    case "Socks5":
                        list.Add(NetchLink);
                        break;

                    case "SS":
                        if (!Global.EncryptMethods.SS.Contains(NetchLink.EncryptMethod))
                        {
                            Logging.Error($"不支持的 SS 加密方式:{NetchLink.EncryptMethod}");
                            return(null);
                        }
                        break;

                    case "SSR":
                        if (!Global.EncryptMethods.SSR.Contains(NetchLink.EncryptMethod))
                        {
                            Logging.Error($"不支持的 SSR 加密方式:{NetchLink.EncryptMethod}");
                            return(null);
                        }
                        if (!Global.Protocols.Contains(NetchLink.Protocol))
                        {
                            Logging.Error($"不支持的 SSR 协议:{NetchLink.Protocol}");
                            return(null);
                        }
                        if (!Global.OBFSs.Contains(NetchLink.OBFS))
                        {
                            Logging.Error($"不支持的 SSR 混淆:{NetchLink.OBFS}");
                            return(null);
                        }
                        break;

                    case "VMess":
                        if (!Global.TransferProtocols.Contains(NetchLink.TransferProtocol))
                        {
                            Logging.Error($"不支持的 VMess 传输协议:{NetchLink.TransferProtocol}");
                            return(null);
                        }
                        if (!Global.FakeTypes.Contains(NetchLink.FakeType))
                        {
                            Logging.Error($"不支持的 VMess 伪装类型:{NetchLink.FakeType}");
                            return(null);
                        }
                        if (NetchLink.TransferProtocol == "quic")
                        {
                            if (!Global.EncryptMethods.VMessQUIC.Contains(NetchLink.QUICSecure))
                            {
                                Logging.Error($"不支持的 VMess QUIC 加密方式:{NetchLink.QUICSecure}");
                                return(null);
                            }
                        }
                        break;

                    default:
                        return(null);
                    }
                    list.Add(NetchLink);
                }
                else if (text.StartsWith("trojan://"))
                {
                    var data = new Server();
                    data.Type = "Trojan";

                    text = text.Replace("/?", "?");
                    try
                    {
                        if (text.Contains("#"))
                        {
                            data.Remark = HttpUtility.UrlDecode(text.Split('#')[1]);
                            text        = text.Split('#')[0];
                        }
                        if (text.Contains("?"))
                        {
                            var reg      = new Regex(@"^(?<data>.+?)\?(.+)$");
                            var regmatch = reg.Match(text);

                            if (regmatch.Success)
                            {
                                var peer = HttpUtility.UrlDecode(HttpUtility.ParseQueryString(new Uri(text).Query).Get("peer"));

                                if (peer != null)
                                {
                                    data.Host = peer;
                                }

                                text = regmatch.Groups["data"].Value;
                            }
                            else
                            {
                                throw new FormatException();
                            }
                        }
                        var finder = new Regex(@"^trojan://(?<psk>.+?)@(?<server>.+):(?<port>\d+)");
                        var match  = finder.Match(text);
                        if (!match.Success)
                        {
                            throw new FormatException();
                        }

                        data.Password = match.Groups["psk"].Value;
                        data.Hostname = match.Groups["server"].Value;
                        data.Port     = int.Parse(match.Groups["port"].Value);

                        list.Add(data);
                    }
                    catch (FormatException)
                    {
                        return(null);
                    }
                }
            }
            catch (Exception e)
            {
                Logging.Error(e.ToString());
                return(null);
            }

            byte[] emoji_bytes = { 240, 159 };
            foreach (var node in list)
            {
                var remark      = Encoding.UTF8.GetBytes(node.Remark);
                var start_index = 0;
                while (remark.Length > start_index + 1 && remark[start_index] == emoji_bytes[0] && remark[start_index + 1] == emoji_bytes[1])
                {
                    start_index += 4;
                }
                node.Remark = Encoding.UTF8.GetString(remark.Skip(start_index).ToArray()).Trim();
            }

            return(list);
        }
Esempio n. 4
0
 public static string AutoResolveHostname(this Server server)
 {
     return(Global.Settings.ResolveServerHostname ? DNS.Lookup(server.Hostname).ToString() : server.Hostname);
 }