From 93b8dec63e3854155ca2b49880ef709c01439710 Mon Sep 17 00:00:00 2001 From: Student Main Date: Sun, 19 Jul 2020 20:05:00 +0800 Subject: [PATCH 1/3] ctrl cv sswindows --- v2rayN/v2rayN/Handler/V2rayConfigHandler.cs | 153 +++++++++++++------- v2rayN/v2rayN/v2rayN.csproj | 1 + 2 files changed, 98 insertions(+), 56 deletions(-) diff --git a/v2rayN/v2rayN/Handler/V2rayConfigHandler.cs b/v2rayN/v2rayN/Handler/V2rayConfigHandler.cs index b3f25e06462..454229412f4 100644 --- a/v2rayN/v2rayN/Handler/V2rayConfigHandler.cs +++ b/v2rayN/v2rayN/Handler/V2rayConfigHandler.cs @@ -1,8 +1,12 @@ using System; using System.Collections.Generic; +using System.Collections.Specialized; using System.IO; using System.Linq; using System.Net; +using System.Text; +using System.Text.RegularExpressions; +using System.Web; using v2rayN.Base; using v2rayN.Mode; @@ -392,7 +396,7 @@ private static int outbound(Config config, ref V2rayConfig v2rayConfig) outbound.mux.enabled = false; outbound.mux.concurrency = -1; - + outbound.protocol = "shadowsocks"; outbound.settings.vnext = null; @@ -454,7 +458,7 @@ private static int boundStreamSettings(Config config, string iobound, ref Stream { //远程服务器底层传输配置 streamSettings.network = config.network(); - string host = config.requestHost(); + string host = config.requestHost(); //if tls if (config.streamSecurity() == Global.StreamSecurity) { @@ -1242,68 +1246,21 @@ public static VmessItem ImportFromClipboardConfig(string clipboardData, out stri { msg = UIRes.I18N("ConfigurationFormatIncorrect"); - vmessItem.configType = (int)EConfigType.Shadowsocks; - result = result.Substring(Global.ssProtocol.Length); - //remark - int indexRemark = result.IndexOf("#"); - if (indexRemark > 0) + vmessItem = ResolveSSLegacy(result); + if (vmessItem == null) { - try - { - vmessItem.remarks = WebUtility.UrlDecode(result.Substring(indexRemark + 1, result.Length - indexRemark - 1)); - } - catch { } - result = result.Substring(0, indexRemark); + vmessItem = ResolveSip002(result); } - //part decode - int indexS = result.IndexOf("@"); - if (indexS > 0) - { - result = Utils.Base64Decode(result.Substring(0, indexS)) + result.Substring(indexS, result.Length - indexS); - } - else - { - result = Utils.Base64Decode(result); - } - - //密码中可能包含“@”,所以从后往前搜索 - int indexAddressAndPort = result.LastIndexOf("@"); - if (indexAddressAndPort < 0) - { - return null; - } - string addressAndPort = result.Substring(indexAddressAndPort + 1); - string securityAndId = result.Substring(0, indexAddressAndPort); - - //IPv6地址中包含“:”,所以从后往前搜索 - int indexPort = addressAndPort.LastIndexOf(":"); - if (indexPort < 0) - { - return null; - } - - //加密方式中不包含“:”,所以从前往后搜索 - int indexId = securityAndId.IndexOf(":"); - if (indexId < 0) + if (vmessItem == null) { return null; } - - string address = addressAndPort.Substring(0, indexPort); - string port = addressAndPort.Substring(indexPort + 1); - string security = securityAndId.Substring(0, indexId); - string id = securityAndId.Substring(indexId + 1); - - //所有字段均不能为空 - if (address.Length == 0 || port.Length == 0 || security.Length == 0 || id.Length == 0) + if (vmessItem.address.Length == 0 || vmessItem.port == 0 || vmessItem.security.Length == 0 || vmessItem.id.Length == 0) { return null; } - vmessItem.address = address; - vmessItem.port = Utils.ToInt(port); - vmessItem.security = security; - vmessItem.id = id; + vmessItem.configType = (int)EConfigType.Shadowsocks; } else if (result.StartsWith(Global.socksProtocol)) { @@ -1428,6 +1385,90 @@ private static VmessItem ResolveVmess4Kitsunebi(string result) return vmessItem; } + private static VmessItem ResolveSip002(string result) + { + Uri parsedUrl; + try + { + parsedUrl = new Uri(result); + } + catch (UriFormatException) + { + return null; + } + VmessItem server = new VmessItem + { + remarks = parsedUrl.GetComponents(UriComponents.Fragment, UriFormat.Unescaped), + address = parsedUrl.IdnHost, + port = parsedUrl.Port, + }; + + // parse base64 UserInfo + string rawUserInfo = parsedUrl.GetComponents(UriComponents.UserInfo, UriFormat.Unescaped); + string base64 = rawUserInfo.Replace('-', '+').Replace('_', '/'); // Web-safe base64 to normal base64 + string userInfo; + try + { + userInfo = Encoding.UTF8.GetString(Convert.FromBase64String( + base64.PadRight(base64.Length + (4 - base64.Length % 4) % 4, '='))); + } + catch (FormatException) + { + return null; + } + string[] userInfoParts = userInfo.Split(new char[] { ':' }, 2); + if (userInfoParts.Length != 2) + { + return null; + } + server.security = userInfoParts[0]; + server.id = userInfoParts[1]; + + NameValueCollection queryParameters = HttpUtility.ParseQueryString(parsedUrl.Query); + string[] pluginParts = (queryParameters["plugin"] ?? "").Split(new[] { ';' }, 2); + if (pluginParts.Length > 0) + { + return null; + } + + return server; + } + + private static readonly Regex UrlFinder = new Regex(@"ss://(?[A-Za-z0-9+-/=_]+)(?:#(?\S+))?", RegexOptions.IgnoreCase); + private static readonly Regex DetailsParser = new Regex(@"^((?.+?):(?.*)@(?.+?):(?\d+?))$", RegexOptions.IgnoreCase); + + private static VmessItem ResolveSSLegacy(string result) + { + var match = UrlFinder.Match(result); + if (!match.Success) + return null; + + VmessItem server = new VmessItem(); + var base64 = match.Groups["base64"].Value.TrimEnd('/'); + var tag = match.Groups["tag"].Value; + if (!tag.IsNullOrEmpty()) + { + server.remarks = HttpUtility.UrlDecode(tag, Encoding.UTF8); + } + Match details; + try + { + details = DetailsParser.Match(Encoding.UTF8.GetString(Convert.FromBase64String( + base64.PadRight(base64.Length + (4 - base64.Length % 4) % 4, '=')))); + } + catch (FormatException) + { + return null; + } + if (!details.Success) + return null; + server.security = details.Groups["method"].Value; + server.id = details.Groups["password"].Value; + server.address = details.Groups["hostname"].Value; + server.port = int.Parse(details.Groups["port"].Value); + return server; + } + #endregion #region Gen speedtest config @@ -1449,7 +1490,7 @@ public static string GenerateClientSpeedtestConfigString(Config config, List + From e313e004eb8d815ee5a5322ba10df1afc0e91b2b Mon Sep 17 00:00:00 2001 From: Student Main Date: Sun, 19 Jul 2020 21:03:14 +0800 Subject: [PATCH 2/3] vmess --- v2rayN/v2rayN/Handler/V2rayConfigHandler.cs | 80 ++++++++++++++++++++- 1 file changed, 77 insertions(+), 3 deletions(-) diff --git a/v2rayN/v2rayN/Handler/V2rayConfigHandler.cs b/v2rayN/v2rayN/Handler/V2rayConfigHandler.cs index 454229412f4..1830e6afbbc 100644 --- a/v2rayN/v2rayN/Handler/V2rayConfigHandler.cs +++ b/v2rayN/v2rayN/Handler/V2rayConfigHandler.cs @@ -1199,7 +1199,7 @@ public static VmessItem ImportFromClipboardConfig(string clipboardData, out stri int indexSplit = result.IndexOf("?"); if (indexSplit > 0) { - vmessItem = ResolveVmess4Kitsunebi(result); + vmessItem = ResolveVmess4Vmess(result) ?? ResolveVmess4Kitsunebi(result); } else { @@ -1425,8 +1425,7 @@ private static VmessItem ResolveSip002(string result) server.id = userInfoParts[1]; NameValueCollection queryParameters = HttpUtility.ParseQueryString(parsedUrl.Query); - string[] pluginParts = (queryParameters["plugin"] ?? "").Split(new[] { ';' }, 2); - if (pluginParts.Length > 0) + if (queryParameters["plugin"] != null) { return null; } @@ -1469,6 +1468,81 @@ private static VmessItem ResolveSSLegacy(string result) return server; } + + private static VmessItem ResolveVmess4Vmess(string result) + { + VmessItem i = new VmessItem(); + + Uri u = new Uri(result); + + var uinfo = u.UserInfo; + var uinfo12 = uinfo.Split(':'); + if (uinfo12.Length != 2) return null; + var user = uinfo12[0]; + var pass = uinfo12[1]; + var passsp = pass.LastIndexOf('-'); + var id = pass.Substring(0, passsp); + var aid = pass.Substring(passsp + 1); + i.address = u.IdnHost; + i.port = u.Port; + i.id = id; + i.alterId = int.Parse(aid); + i.remarks = u.GetComponents(UriComponents.Fragment, UriFormat.Unescaped); + + + var query = u.Query; + + var q = HttpUtility.ParseQueryString(u.Query); + + if (user.EndsWith("+tls")) + { + user = user.Split('+')[0]; + i.streamSecurity = "tls"; + // TODO tlsServerName + } + i.network = user; + switch (user) + { + case "tcp": + string t1 = q["type"] ?? "none"; + i.headerType = t1; + // TODO t = http, parse http option + + + break; + case "kcp": + string t2 = q["type"] ?? "none"; + i.headerType = t2; + // TODO seed + break; + case "ws": + string p1 = q["path"] ?? "/"; + string h1 = q["host"] ?? ""; + i.requestHost = h1; + i.path = p1; + break; + + case "http": + i.network = "h2"; + string p2 = q["path"] ?? "/"; + string h2 = q["host"] ?? ""; + i.requestHost = h2; + i.path = p2; + break; + + case "quic": + string s = q["security"] ?? "none"; + string k = q["key"] ?? ""; + string t3 = q["type"] ?? "none"; + i.headerType = t3; + i.requestHost = s; + i.path = k; + break; + + } + + return i; + } #endregion #region Gen speedtest config From 4e8ea374d8024f8a7ef49af35100e2713aa68b73 Mon Sep 17 00:00:00 2001 From: Student Main Date: Thu, 23 Jul 2020 17:15:30 +0800 Subject: [PATCH 3/3] regex vmess url --- v2rayN/v2rayN/Handler/V2rayConfigHandler.cs | 67 ++++++++++++--------- 1 file changed, 40 insertions(+), 27 deletions(-) diff --git a/v2rayN/v2rayN/Handler/V2rayConfigHandler.cs b/v2rayN/v2rayN/Handler/V2rayConfigHandler.cs index 1830e6afbbc..127f2b7a991 100644 --- a/v2rayN/v2rayN/Handler/V2rayConfigHandler.cs +++ b/v2rayN/v2rayN/Handler/V2rayConfigHandler.cs @@ -1199,7 +1199,7 @@ public static VmessItem ImportFromClipboardConfig(string clipboardData, out stri int indexSplit = result.IndexOf("?"); if (indexSplit > 0) { - vmessItem = ResolveVmess4Vmess(result) ?? ResolveVmess4Kitsunebi(result); + vmessItem = ResolveStdVmess(result) ?? ResolveVmess4Kitsunebi(result); } else { @@ -1469,52 +1469,63 @@ private static VmessItem ResolveSSLegacy(string result) } - private static VmessItem ResolveVmess4Vmess(string result) + private static readonly Regex StdVmessUserInfo = new Regex( + @"^(?[a-z]+)(\+(?[a-z]+))?:(?[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})-(?[0-9]+)$"); + + private static VmessItem ResolveStdVmess(string result) { - VmessItem i = new VmessItem(); + VmessItem i = new VmessItem + { + configType = (int)EConfigType.Vmess, + security = "auto" + }; Uri u = new Uri(result); - var uinfo = u.UserInfo; - var uinfo12 = uinfo.Split(':'); - if (uinfo12.Length != 2) return null; - var user = uinfo12[0]; - var pass = uinfo12[1]; - var passsp = pass.LastIndexOf('-'); - var id = pass.Substring(0, passsp); - var aid = pass.Substring(passsp + 1); i.address = u.IdnHost; i.port = u.Port; - i.id = id; - i.alterId = int.Parse(aid); i.remarks = u.GetComponents(UriComponents.Fragment, UriFormat.Unescaped); + var q = HttpUtility.ParseQueryString(u.Query); + var m = StdVmessUserInfo.Match(u.UserInfo); + if (!m.Success) return null; - var query = u.Query; - - var q = HttpUtility.ParseQueryString(u.Query); + i.id = m.Groups["id"].Value; + if (!int.TryParse(m.Groups["alterId"].Value, out int aid)) + { + return null; + } + i.alterId = aid; - if (user.EndsWith("+tls")) + if (m.Groups["streamSecurity"].Success) { - user = user.Split('+')[0]; - i.streamSecurity = "tls"; - // TODO tlsServerName + i.streamSecurity = m.Groups["streamSecurity"].Value; } - i.network = user; - switch (user) + switch (i.streamSecurity) + { + case "tls": + // TODO tls config + break; + default: + if (!string.IsNullOrWhiteSpace(i.streamSecurity)) + return null; + break; + } + + i.network = m.Groups["network"].Value; + switch (i.network) { case "tcp": string t1 = q["type"] ?? "none"; i.headerType = t1; - // TODO t = http, parse http option - + // TODO http option break; case "kcp": - string t2 = q["type"] ?? "none"; - i.headerType = t2; - // TODO seed + i.headerType = q["type"] ?? "none"; + // TODO kcp seed break; + case "ws": string p1 = q["path"] ?? "/"; string h1 = q["host"] ?? ""; @@ -1539,6 +1550,8 @@ private static VmessItem ResolveVmess4Vmess(string result) i.path = k; break; + default: + return null; } return i;