diff --git a/v2rayN/ServiceLib.Tests/Fmt/WireguardFmtTests.cs b/v2rayN/ServiceLib.Tests/Fmt/WireguardFmtTests.cs new file mode 100644 index 00000000..e9b5014d --- /dev/null +++ b/v2rayN/ServiceLib.Tests/Fmt/WireguardFmtTests.cs @@ -0,0 +1,46 @@ +using AwesomeAssertions; +using ServiceLib.Handler.Fmt; +using Xunit; + +namespace ServiceLib.Tests.Fmt; + +public class WireguardFmtTests +{ + [Fact] + public void ResolveConfig_ShouldParsePeersAndIgnoreInlineComments() + { + var config = """ + [Interface] + PrivateKey = interface-private-key + Address = 10.0.0.2/32, fd00::2/128 ; inline comment + MTU = 1420 + + [Peer] + PublicKey = peer-public-key + PresharedKey = peer-preshared-key + Reserved = 1, 2, 3 # inline comment + Endpoint = [2001:db8::1]:51820 # inline comment + + [Peer] + PublicKey = peer-public-key-2 + Endpoint = example.com:12345 + """; + + var resolved = WireguardFmt.ResolveConfig(config); + + resolved.Should().NotBeNull(); + resolved.Should().HaveCount(2); + + var first = resolved![0]; + first.Address.Should().Be("2001:db8::1"); + first.Port.Should().Be(51820); + first.Password.Should().Be("interface-private-key"); + first.GetProtocolExtra().WgReserved.Should().Be("1, 2, 3"); + first.GetProtocolExtra().WgInterfaceAddress.Should().Be("10.0.0.2/32, fd00::2/128"); + first.GetProtocolExtra().WgMtu.Should().Be(1420); + + var second = resolved[1]; + second.Address.Should().Be("example.com"); + second.Port.Should().Be(12345); + } +} \ No newline at end of file diff --git a/v2rayN/ServiceLib/Handler/ConfigHandler.cs b/v2rayN/ServiceLib/Handler/ConfigHandler.cs index d25141f8..61511219 100644 --- a/v2rayN/ServiceLib/Handler/ConfigHandler.cs +++ b/v2rayN/ServiceLib/Handler/ConfigHandler.cs @@ -790,12 +790,17 @@ public static class ConfigHandler profileItem.Address = profileItem.Address.TrimEx(); profileItem.Password = profileItem.Password.TrimEx(); + var wgReserved = profileItem.GetProtocolExtra().WgReserved?.TrimEx(); + if (!wgReserved.IsNullOrEmpty()) + { + wgReserved = wgReserved.Replace(", ", ","); + } profileItem.SetProtocolExtra(profileItem.GetProtocolExtra() with { WgPublicKey = profileItem.GetProtocolExtra().WgPublicKey?.TrimEx(), WgPresharedKey = profileItem.GetProtocolExtra().WgPresharedKey?.TrimEx(), WgInterfaceAddress = profileItem.GetProtocolExtra().WgInterfaceAddress?.TrimEx(), - WgReserved = profileItem.GetProtocolExtra().WgReserved?.TrimEx(), + WgReserved = wgReserved, WgMtu = profileItem.GetProtocolExtra().WgMtu is null or <= 0 ? Global.TunMtus.First() : profileItem.GetProtocolExtra().WgMtu, }); diff --git a/v2rayN/ServiceLib/Handler/Fmt/WireguardFmt.cs b/v2rayN/ServiceLib/Handler/Fmt/WireguardFmt.cs index a9d47991..b0de1068 100644 --- a/v2rayN/ServiceLib/Handler/Fmt/WireguardFmt.cs +++ b/v2rayN/ServiceLib/Handler/Fmt/WireguardFmt.cs @@ -76,7 +76,6 @@ public class WireguardFmt : BaseFmt 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; @@ -117,17 +116,7 @@ public class WireguardFmt : BaseFmt 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; - } - } + var commentPos = value.IndexOfAny(['#', ';']); if (commentPos >= 0) { value = value[..commentPos].TrimEnd(); @@ -155,20 +144,17 @@ public class WireguardFmt : BaseFmt continue; } - var endpointParts = endpoint.Split(':'); - var peerAddress = endpointParts[0].Trim(); - if (peerAddress.StartsWith('[')) // IPv6 address + if (!TryParseEndpoint(endpoint, out var peerAddress, out var peerPort)) { - peerAddress = peerAddress.Trim('[', ']'); + continue; } - 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(), + WgReserved = (peerDic.TryGetValue("Reserved", out var reserved) ? reserved : string.Empty).NullIfEmpty(), WgMtu = wgMtu > 0 ? wgMtu : null, }; @@ -188,4 +174,58 @@ public class WireguardFmt : BaseFmt return resultList; } + + private static bool TryParseEndpoint(string endpoint, out string address, out int port) + { + address = string.Empty; + port = 2408; + + var trimmedEndpoint = endpoint.Trim(); + if (trimmedEndpoint.IsNullOrEmpty()) + { + return false; + } + + if (trimmedEndpoint[0] == '[') + { + var closeIndex = trimmedEndpoint.IndexOf(']'); + if (closeIndex <= 1) + { + return false; + } + + address = trimmedEndpoint[1..closeIndex].Trim(); + var portIndex = closeIndex + 1; + if (portIndex < trimmedEndpoint.Length && trimmedEndpoint[portIndex] == ':' && + int.TryParse(trimmedEndpoint[(portIndex + 1)..].Trim(), out var bracketedPort) && bracketedPort is > 0 and <= 65535) + { + port = bracketedPort; + } + + return address.IsNotEmpty(); + } + + var lastColonIndex = trimmedEndpoint.LastIndexOf(':'); + if (lastColonIndex <= 0) + { + address = trimmedEndpoint; + return true; + } + + address = trimmedEndpoint[..lastColonIndex].Trim(); + var portText = trimmedEndpoint[(lastColonIndex + 1)..].Trim(); + if (address.IsNullOrEmpty()) + { + return false; + } + + if (int.TryParse(portText, out var parsedPortValue) && parsedPortValue is > 0 and <= 65535) + { + port = parsedPortValue; + return true; + } + + address = trimmedEndpoint; + return true; + } }