diff --git a/v2rayN/ServiceLib/Handler/ConfigHandler.cs b/v2rayN/ServiceLib/Handler/ConfigHandler.cs index 6fa8e65b..d25141f8 100644 --- a/v2rayN/ServiceLib/Handler/ConfigHandler.cs +++ b/v2rayN/ServiceLib/Handler/ConfigHandler.cs @@ -1639,30 +1639,18 @@ public static class ConfigHandler ProfileItem? profileItem = null; //Is sing-box configuration - if (profileItem is null) - { - profileItem = SingboxFmt.ResolveFull(strData, subRemarks); - } + profileItem ??= SingboxFmt.ResolveFull(strData, subRemarks); //Is v2ray configuration - if (profileItem is null) - { - profileItem = V2rayFmt.ResolveFull(strData, subRemarks); - } + profileItem ??= V2rayFmt.ResolveFull(strData, subRemarks); //Is Html Page if (profileItem is null && HtmlPageFmt.IsHtmlPage(strData)) { return -1; } //Is Clash configuration - if (profileItem is null) - { - profileItem = ClashFmt.ResolveFull(strData, subRemarks); - } + profileItem ??= ClashFmt.ResolveFull(strData, subRemarks); //Is hysteria configuration - if (profileItem is null) - { - profileItem = Hysteria2Fmt.ResolveFull2(strData, subRemarks); - } + profileItem ??= Hysteria2Fmt.ResolveFull2(strData, subRemarks); if (profileItem is null || profileItem.Address.IsNullOrEmpty()) { return -1; @@ -1727,6 +1715,40 @@ public static class ConfigHandler return -1; } + private static async Task AddBatchServers4Wireguard(Config config, string strData, string subid, bool isSub) + { + if (strData.IsNullOrEmpty()) + { + return -1; + } + if (!(strData.Contains("[Interface]", StringComparison.OrdinalIgnoreCase) + && strData.Contains("[Peer]", StringComparison.OrdinalIgnoreCase))) + { + return -1; + } + if (isSub && subid.IsNotEmpty()) + { + await RemoveServersViaSubid(config, subid, isSub); + } + var lstSsServer = WireguardFmt.ResolveConfig(strData); + if (lstSsServer?.Count > 0) + { + var counter = 0; + foreach (var ssItem in lstSsServer) + { + ssItem.Subid = subid; + ssItem.IsSub = isSub; + if (await AddWireguardServer(config, ssItem) == 0) + { + counter++; + } + } + await SaveConfig(config); + return counter; + } + return -1; + } + /// /// Main entry point for adding batch servers from various formats /// Tries different parsing methods to import as many servers as possible @@ -1769,6 +1791,12 @@ public static class ConfigHandler counter = await AddBatchServers4SsSIP008(config, strData, subid, isSub); } + //maybe wireguard config + if (counter < 1) + { + counter = await AddBatchServers4Wireguard(config, strData, subid, isSub); + } + //maybe other sub if (counter < 1) { diff --git a/v2rayN/ServiceLib/Handler/Fmt/WireguardFmt.cs b/v2rayN/ServiceLib/Handler/Fmt/WireguardFmt.cs index e13dcbb7..a9d47991 100644 --- a/v2rayN/ServiceLib/Handler/Fmt/WireguardFmt.cs +++ b/v2rayN/ServiceLib/Handler/Fmt/WireguardFmt.cs @@ -30,7 +30,7 @@ public class WireguardFmt : BaseFmt WgPresharedKey = GetQueryDecoded(query, "presharedkey"), WgReserved = GetQueryDecoded(query, "reserved"), WgInterfaceAddress = GetQueryDecoded(query, "address"), - WgMtu = int.TryParse(GetQueryDecoded(query, "mtu"), out var mtuVal) ? mtuVal : 1280, + WgMtu = int.TryParse(GetQueryDecoded(query, "mtu"), out var mtuVal) ? mtuVal : null, }); return item; @@ -67,7 +67,125 @@ public class WireguardFmt : BaseFmt { dicQuery.Add("address", Utils.UrlEncode(protoExtra.WgInterfaceAddress)); } - dicQuery.Add("mtu", Utils.UrlEncode(protoExtra.WgMtu > 0 ? protoExtra.WgMtu.ToString() : "1280")); + if (protoExtra.WgMtu > 0) + { + dicQuery.Add("mtu", protoExtra.WgMtu.ToString()); + } return ToUri(EConfigType.WireGuard, item.Address, item.Port, item.Password, dicQuery, remark); } + + public static List? ResolveConfig(string strData) + { + //var dic = new Dictionary(StringComparer.OrdinalIgnoreCase); + var interfaceDic = new Dictionary(StringComparer.OrdinalIgnoreCase); + var peerDicList = new List>(); + var currentDicRef = interfaceDic; + using (var reader = new StringReader(strData)) + { + while (reader.ReadLine() is { } line) + { + if (line.IsNullOrEmpty()) + { + continue; + } + + var trimmedLine = line.Trim(); + + if (trimmedLine.Equals("[Interface]", StringComparison.OrdinalIgnoreCase)) + { + currentDicRef = interfaceDic; + continue; + } + if (trimmedLine.Equals("[Peer]", StringComparison.OrdinalIgnoreCase)) + { + var peerDic = new Dictionary(StringComparer.OrdinalIgnoreCase); + peerDicList.Add(peerDic); + currentDicRef = peerDic; + continue; + } + + if (trimmedLine.StartsWith('[') || trimmedLine.StartsWith('#') || trimmedLine.StartsWith(';')) + { + continue; + } + + var idx = line.IndexOf('='); + if (idx <= 0) + { + continue; + } + + var key = line[..idx].Trim(); + var value = line[(idx + 1)..].Trim(); + // Remove inline comments starting with # or ; + var commentPos = -1; + var commentChars = new[] { '#', ';' }; + foreach (var cc in commentChars) + { + var p = value.IndexOf(cc); + if (p >= 0 && (commentPos < 0 || p < commentPos)) + { + commentPos = p; + } + } + if (commentPos >= 0) + { + value = value[..commentPos].TrimEnd(); + } + + currentDicRef[key] = value; + } + } + + if (!interfaceDic.TryGetValue("PrivateKey", out var privateKey) || privateKey.IsNullOrEmpty()) + { + return null; + } + + var wgMtu = interfaceDic.TryGetValue("MTU", out var mtuStr) && int.TryParse(mtuStr, out var mtuVal) ? mtuVal : 0; + var wgInterfaceAddress = interfaceDic.TryGetValue("Address", out var interfaceAddress) ? interfaceAddress : string.Empty; + + var index = 0; + var resultList = new List(); + + foreach (var peerDic in peerDicList) + { + if (!peerDic.TryGetValue("Endpoint", out var endpoint) || endpoint.IsNullOrEmpty()) + { + continue; + } + + var endpointParts = endpoint.Split(':'); + var peerAddress = endpointParts[0].Trim(); + if (peerAddress.StartsWith('[')) // IPv6 address + { + peerAddress = peerAddress.Trim('[', ']'); + } + var peerPort = endpointParts.Length > 1 && int.TryParse(endpointParts[1].Trim(), out var portVal) && portVal is > 0 and <= 65535 ? portVal : 2408; + + var protoExtra = new ProtocolExtraItem + { + WgPublicKey = (peerDic.TryGetValue("PublicKey", out var publicKey) ? publicKey : string.Empty).NullIfEmpty(), + WgPresharedKey = (peerDic.TryGetValue("PresharedKey", out var presharedKey) ? presharedKey : string.Empty).NullIfEmpty(), + WgInterfaceAddress = wgInterfaceAddress, + WgReserved = (peerDic.TryGetValue("Reserved", out var reserved) ? reserved : string.Empty).Replace(", ", ",").NullIfEmpty(), + WgMtu = wgMtu > 0 ? wgMtu : null, + }; + + var item = new ProfileItem + { + Remarks = $"{nameof(EConfigType.WireGuard)} Peer {index + 1}", + ConfigType = EConfigType.WireGuard, + Address = peerAddress, + Port = peerPort, + Password = privateKey, + }; + item.SetProtocolExtra(protoExtra); + resultList.Add(item); + + index += 1; + } + + return resultList; + } }