From 7353236eb549ac2f4d2783e64bf9e60e3bb8b512 Mon Sep 17 00:00:00 2001 From: trudy Date: Fri, 17 Sep 2021 19:09:23 -0700 Subject: [PATCH 01/12] fox IsInRange --- CHANGELOG.md | 5 ++++- VpnHood.Client.Device/IpRange.cs | 25 +++++++++++++++++++------ VpnHood.Server.App.Net/appsettings.json | 8 ++------ VpnHood.ZTest/Tests/IpNetworkTest.cs | 7 +++++++ 4 files changed, 32 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c1796dd45..fdf5835bc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,7 @@ -# v2.0.271 +# Upcoming +* Fix: Issue in PacketCaptureIncludeIpRanges + +# v2.0.271 ### Client * Feature: Server Redirection * Feature: Server Maintenance mode detection diff --git a/VpnHood.Client.Device/IpRange.cs b/VpnHood.Client.Device/IpRange.cs index 928942ad5..b8817b720 100644 --- a/VpnHood.Client.Device/IpRange.cs +++ b/VpnHood.Client.Device/IpRange.cs @@ -61,7 +61,7 @@ public static IpRange[] Invert(IEnumerable ipRanges) // invert of nothing is all thing! if (ipRangesSorted.Length == 0) - return new[] {Parse("0.0.0.0-255.255.255.255")}; + return new[] { Parse("0.0.0.0-255.255.255.255") }; // extract List res = new(); @@ -107,24 +107,37 @@ public override int GetHashCode() private static IPAddress IpAddressFromLong(long ipAddress) { - return new IPAddress((uint) IPAddress.NetworkToHostOrder((int) ipAddress)); + return new IPAddress((uint)IPAddress.NetworkToHostOrder((int)ipAddress)); } private static long IpAddressToLong(IPAddress ipAddress) { var bytes = ipAddress.GetAddressBytes(); - return ((long) bytes[0] << 24) | ((long) bytes[1] << 16) | ((long) bytes[2] << 8) | bytes[3]; + return ((long)bytes[0] << 24) | ((long)bytes[1] << 16) | ((long)bytes[2] << 8) | bytes[3]; } public bool IsInRange(IPAddress ipAddress) { - var ipAddressLong = IpAddressToLong(ipAddress); - return ipAddressLong < FirstIpAddressLong || ipAddressLong > LastIpAddressLong; + return + CompareIpAddress(ipAddress, FirstIpAddress) >= 0 && + CompareIpAddress(ipAddress, LastIpAddress) <= 0; } public static int CompareIpAddress(IPAddress ipAddress1, IPAddress ipAddress2) { - return (int) (IpAddressToLong(ipAddress1) - IpAddressToLong(ipAddress2)); + if (ipAddress1.AddressFamily != ipAddress2.AddressFamily) + throw new InvalidOperationException("could not compare IPAddresses with different AddressFamily!"); + + var bytes1 = ipAddress1.GetAddressBytes(); + var bytes2 = ipAddress2.GetAddressBytes(); + + for (var i = 0; i < bytes1.Length; i++) + { + if (bytes1[i] < bytes2[i]) return -1; + if (bytes1[i] > bytes2[i]) return +1; + } + + return 0; } /// diff --git a/VpnHood.Server.App.Net/appsettings.json b/VpnHood.Server.App.Net/appsettings.json index bcc6a6d44..1e1eaa0dc 100644 --- a/VpnHood.Server.App.Net/appsettings.json +++ b/VpnHood.Server.App.Net/appsettings.json @@ -1,8 +1,4 @@ { - "RestBaseUrl": "https://localhost:5001/api/access/", - "RestAuthorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJWcG5TZXJ2ZXIiLCJyb2xlcyI6IlZwblNlcnZlciIsInByb2plY3RfaWQiOiI4RDBCNDRCMS04MDhBLTRBMzgtQUU0NS1CNDZBRjk4NUYyODAiLCJleHAiOjE5NDU4MzkyMzIsImlzcyI6ImF1dGgudnBuaG9vZC5jb20iLCJhdWQiOiJhY2Nlc3MudnBuaG9vZC5jb20ifQ.p9y3LIIjRu7SlEOk9AFcVIbC9G23dxSAjS3MGZnMS1o", - "EndPoint": "0.0.0.0:9443", - "IsDiagnoseMode": false, - "OrgStreamReadBufferSize": 40960, - "TunnelStreamReadBufferSize": 20480 + "EndPoint": "0.0.0.0:443", + "IsDiagnoseMode": false } \ No newline at end of file diff --git a/VpnHood.ZTest/Tests/IpNetworkTest.cs b/VpnHood.ZTest/Tests/IpNetworkTest.cs index 56eccbe63..d3e896552 100644 --- a/VpnHood.ZTest/Tests/IpNetworkTest.cs +++ b/VpnHood.ZTest/Tests/IpNetworkTest.cs @@ -60,6 +60,13 @@ public void IpNetwork_Unit() [TestMethod] public void IpRange_IsInRange() { + // simple + var range = new IpRange(IPAddress.Parse("1.1.1.1"), IPAddress.Parse("1.1.1.10")); + Assert.IsTrue(range.IsInRange(IPAddress.Parse("1.1.1.5"))); + Assert.IsFalse(range.IsInRange(IPAddress.Parse("1.1.1.12"))); + + + // array var ipRanges = new[] { IpRange.Parse("9.9.9.9 - 9.9.9.9"), From cece3482ec8e3ce6a96130b4243b85c116747a2a Mon Sep 17 00:00:00 2001 From: trudy Date: Sat, 18 Sep 2021 00:24:34 -0700 Subject: [PATCH 02/12] Add IPv6 support to IpRange --- CHANGELOG.md | 1 - VpnHood.Client.Device/IPAddressUtil.cs | 131 +++++++++++++++++++++ VpnHood.Client.Device/IpAddressComparer.cs | 11 ++ VpnHood.Client.Device/IpRange.cs | 96 +++++++-------- VpnHood.Client/VpnHoodClient.cs | 2 +- VpnHood.ZTest/Tests/IpNetworkTest.cs | 10 +- 6 files changed, 190 insertions(+), 61 deletions(-) create mode 100644 VpnHood.Client.Device/IPAddressUtil.cs create mode 100644 VpnHood.Client.Device/IpAddressComparer.cs diff --git a/CHANGELOG.md b/CHANGELOG.md index fdf5835bc..e03a7f30f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,4 @@ # Upcoming -* Fix: Issue in PacketCaptureIncludeIpRanges # v2.0.271 ### Client diff --git a/VpnHood.Client.Device/IPAddressUtil.cs b/VpnHood.Client.Device/IPAddressUtil.cs new file mode 100644 index 000000000..c963141bb --- /dev/null +++ b/VpnHood.Client.Device/IPAddressUtil.cs @@ -0,0 +1,131 @@ +using System; +using System.Net; +using System.Net.Sockets; + +namespace VpnHood.Client.Device +{ + public static class IPAddressUtil + { + private static bool IsSupported(AddressFamily addressFamily) + { + return addressFamily + is AddressFamily.InterNetworkV6 + or AddressFamily.InterNetwork; + } + + private static void Verify(AddressFamily addressFamily) + { + if (!IsSupported(addressFamily)) + throw new NotSupportedException($"{addressFamily} is not supported!"); + } + + private static void Verify(IPAddress ipAddress) + { + Verify(ipAddress.AddressFamily); + } + + public static int Compare(IPAddress ipAddress1, IPAddress ipAddress2) + { + Verify(ipAddress1); + Verify(ipAddress2); + + if (ipAddress1.AddressFamily == AddressFamily.InterNetwork && + ipAddress2.AddressFamily == AddressFamily.InterNetworkV6) + return -1; + + if (ipAddress1.AddressFamily == AddressFamily.InterNetworkV6 && + ipAddress2.AddressFamily == AddressFamily.InterNetwork) + return +1; + + var bytes1 = ipAddress1.GetAddressBytes(); + var bytes2 = ipAddress2.GetAddressBytes(); + + for (var i = 0; i < bytes1.Length; i++) + { + if (bytes1[i] < bytes2[i]) return -1; + if (bytes1[i] > bytes2[i]) return +1; + } + + return 0; + } + + public static IPAddress FromLong(long ipAddress) + { + return new IPAddress((uint)IPAddress.NetworkToHostOrder((int)ipAddress)); + } + + public static IPAddress Increment(IPAddress ipAddress) + { + Verify(ipAddress); + + var bytes = ipAddress.GetAddressBytes(); + + for (var k = bytes.Length - 1; k >= 0; k--) + { + if (bytes[k] == byte.MaxValue) + { + bytes[k] = byte.MinValue; + continue; + } + + bytes[k]++; + + return new IPAddress(bytes); + } + + // Un-increment-able, return the original address. + return ipAddress; + } + + public static IPAddress Decrement(IPAddress ipAddress) + { + Verify(ipAddress); + + var bytes = ipAddress.GetAddressBytes(); + + for (var k = bytes.Length - 1; k >= 0; k--) + { + if (bytes[k] == byte.MinValue) + { + bytes[k] = byte.MaxValue; + continue; + } + + bytes[k]--; + + return new IPAddress(bytes); + } + + // Un-decrement-able, return the original address. + return ipAddress; + } + + public static IPAddress MaxIPv6Value { get; } = IPAddress.Parse("FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF"); + public static IPAddress MinIPv6Value { get; } = IPAddress.Parse("::"); + public static IPAddress MaxIPv4Value { get; } = IPAddress.Parse("255.255.255.255"); + public static IPAddress MinIPv4Value { get; } = IPAddress.Parse("0.0.0.0"); + + public static bool IsMaxValue(IPAddress ipAddress) + { + Verify(ipAddress); + return ipAddress.AddressFamily switch + { + AddressFamily.InterNetworkV6 => ipAddress.Equals(MaxIPv6Value), + AddressFamily.InterNetwork => ipAddress.Equals(MaxIPv4Value), + _ => throw new NotSupportedException($"{ipAddress.AddressFamily} is not supported!") + }; + } + + public static bool IsMinValue(IPAddress ipAddress) + { + Verify(ipAddress); + return ipAddress.AddressFamily switch + { + AddressFamily.InterNetworkV6 => ipAddress.Equals(MinIPv6Value), + AddressFamily.InterNetwork => ipAddress.Equals(MinIPv4Value), + _ => throw new NotSupportedException($"{ipAddress.AddressFamily} is not supported!") + }; + } + + } +} \ No newline at end of file diff --git a/VpnHood.Client.Device/IpAddressComparer.cs b/VpnHood.Client.Device/IpAddressComparer.cs new file mode 100644 index 000000000..db56d107c --- /dev/null +++ b/VpnHood.Client.Device/IpAddressComparer.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; +using System.Net; + +namespace VpnHood.Client.Device +{ + public class IpAddressComparer : IComparer + { + public int Compare(IPAddress x, IPAddress y) + => IPAddressUtil.Compare(x, y); + } +} \ No newline at end of file diff --git a/VpnHood.Client.Device/IpRange.cs b/VpnHood.Client.Device/IpRange.cs index b8817b720..acc54c7eb 100644 --- a/VpnHood.Client.Device/IpRange.cs +++ b/VpnHood.Client.Device/IpRange.cs @@ -2,6 +2,8 @@ using System.Collections.Generic; using System.Linq; using System.Net; +using System.Net.Sockets; +using System.Numerics; using System.Text.Json.Serialization; namespace VpnHood.Client.Device @@ -9,72 +11,84 @@ namespace VpnHood.Client.Device [JsonConverter(typeof(IpRangeConverter))] public class IpRange { - public IpRange(IPAddress ipAddress) : this(ipAddress, ipAddress) + public IpRange(IPAddress ipAddress) + : this(ipAddress, ipAddress) { } public IpRange(IPAddress firstIpAddress, IPAddress lastIpAddress) { - FirstIpAddressLong = IpAddressToLong(firstIpAddress); - LastIpAddressLong = IpAddressToLong(lastIpAddress); + if (firstIpAddress.AddressFamily != lastIpAddress.AddressFamily) + throw new InvalidOperationException("Both ipAddress must have a same address family!"); + + FirstIpAddress = firstIpAddress; + LastIpAddress = lastIpAddress; } public IpRange(long firstIpAddress, long lastIpAddress) { - FirstIpAddressLong = firstIpAddress; - LastIpAddressLong = lastIpAddress; + FirstIpAddress = IPAddressUtil.FromLong(firstIpAddress); + LastIpAddress = IPAddressUtil.FromLong(lastIpAddress); } - public long FirstIpAddressLong { get; } - public long LastIpAddressLong { get; } - public IPAddress FirstIpAddress => IpAddressFromLong(FirstIpAddressLong); - public IPAddress LastIpAddress => IpAddressFromLong(LastIpAddressLong); - public long Total => LastIpAddressLong - FirstIpAddressLong + 1; + public IPAddress FirstIpAddress { get; } + public IPAddress LastIpAddress { get; } + public BigInteger Total => new BigInteger(LastIpAddress.GetAddressBytes(), true, true) - new BigInteger(FirstIpAddress.GetAddressBytes(), true, true) + 1; public static IpRange[] Sort(IEnumerable ipRanges) { - return Unify(ipRanges.OrderBy(x => x.FirstIpAddressLong)); + var sortedRanges = ipRanges.OrderBy(x => x.FirstIpAddress, new IpAddressComparer()); + return Unify(sortedRanges); } private static IpRange[] Unify(IEnumerable sortedIpRanges) { List res = new(); foreach (var ipRange in sortedIpRanges) - if (res.Count > 0 && ipRange.FirstIpAddressLong <= res[^1].LastIpAddressLong) + { + if (res.Count > 0 && + ipRange.FirstIpAddress.AddressFamily == res[^1].LastIpAddress.AddressFamily && + IPAddressUtil.Compare(ipRange.FirstIpAddress, res[^1].LastIpAddress) <= 0) { - if (ipRange.LastIpAddressLong > res[^1].LastIpAddressLong) + if (IPAddressUtil.Compare(ipRange.LastIpAddress, res[^1].LastIpAddress) > 0) res[^1] = new IpRange(res[^1].FirstIpAddress, ipRange.LastIpAddress); } else { res.Add(ipRange); } + } return res.ToArray(); } - public static IpRange[] Invert(IEnumerable ipRanges) + public static IpRange[] Invert(IEnumerable ipRanges, bool includeIPv6 = false) { // sort var ipRangesSorted = Sort(ipRanges); - // invert of nothing is all thing! - if (ipRangesSorted.Length == 0) - return new[] { Parse("0.0.0.0-255.255.255.255") }; - // extract List res = new(); for (var i = 0; i < ipRangesSorted.Length; i++) { var ipRange = ipRangesSorted[i]; - if (i == 0 && ipRange.FirstIpAddressLong != 0) res.Add(new IpRange(0, ipRange.FirstIpAddressLong - 1)); + var minIpValue = ipRange.FirstIpAddress.AddressFamily == AddressFamily.InterNetworkV6 ? IPAddressUtil.MinIPv6Value : IPAddressUtil.MinIPv4Value; + var maxIpValue = ipRange.FirstIpAddress.AddressFamily == AddressFamily.InterNetworkV6 ? IPAddressUtil.MaxIPv6Value : IPAddressUtil.MaxIPv4Value; + + if (i == 0 && !IPAddressUtil.IsMinValue(ipRange.FirstIpAddress)) res.Add(new IpRange(minIpValue, IPAddressUtil.Decrement(ipRange.FirstIpAddress))); if (i > 0) - res.Add(new IpRange(ipRangesSorted[i - 1].LastIpAddressLong + 1, ipRange.FirstIpAddressLong - 1)); - if (i == ipRangesSorted.Length - 1 && ipRange.LastIpAddressLong != 0xFFFFFFFF) - res.Add(new IpRange(ipRange.LastIpAddressLong + 1, 0xFFFFFFFF)); + res.Add(new IpRange(IPAddressUtil.Increment(ipRangesSorted[i - 1].LastIpAddress), IPAddressUtil.Decrement(ipRange.FirstIpAddress))); + if (i == ipRangesSorted.Length - 1 && !IPAddressUtil.IsMaxValue(ipRange.LastIpAddress)) + res.Add(new IpRange(IPAddressUtil.Increment(ipRange.LastIpAddress), maxIpValue)); } + // invert of nothing is all thing! + if (ipRangesSorted.All(x => x.FirstIpAddress.AddressFamily != AddressFamily.InterNetwork)) + res.Insert(0, new IpRange(IPAddressUtil.MinIPv4Value, IPAddressUtil.MaxIPv4Value)); + if (includeIPv6 && ipRangesSorted.All(x => x.FirstIpAddress.AddressFamily != AddressFamily.InterNetworkV6)) + res.Add(new IpRange(IPAddressUtil.MinIPv6Value, IPAddressUtil.MaxIPv6Value)); + return res.ToArray(); } @@ -105,39 +119,11 @@ public override int GetHashCode() return HashCode.Combine(FirstIpAddress, LastIpAddress); } - private static IPAddress IpAddressFromLong(long ipAddress) - { - return new IPAddress((uint)IPAddress.NetworkToHostOrder((int)ipAddress)); - } - - private static long IpAddressToLong(IPAddress ipAddress) - { - var bytes = ipAddress.GetAddressBytes(); - return ((long)bytes[0] << 24) | ((long)bytes[1] << 16) | ((long)bytes[2] << 8) | bytes[3]; - } - public bool IsInRange(IPAddress ipAddress) { return - CompareIpAddress(ipAddress, FirstIpAddress) >= 0 && - CompareIpAddress(ipAddress, LastIpAddress) <= 0; - } - - public static int CompareIpAddress(IPAddress ipAddress1, IPAddress ipAddress2) - { - if (ipAddress1.AddressFamily != ipAddress2.AddressFamily) - throw new InvalidOperationException("could not compare IPAddresses with different AddressFamily!"); - - var bytes1 = ipAddress1.GetAddressBytes(); - var bytes2 = ipAddress2.GetAddressBytes(); - - for (var i = 0; i < bytes1.Length; i++) - { - if (bytes1[i] < bytes2[i]) return -1; - if (bytes1[i] > bytes2[i]) return +1; - } - - return 0; + IPAddressUtil.Compare(ipAddress, FirstIpAddress) >= 0 && + IPAddressUtil.Compare(ipAddress, LastIpAddress) <= 0; } /// @@ -152,14 +138,12 @@ public static bool IsInRangeFast(IpRange[] sortedIpRanges, IPAddress ipAddress) new IpRangeSearchComparer()); return res >= 0 && res < sortedIpRanges.Length; } - private class IpRangeSearchComparer : IComparer { public int Compare(IpRange x, IpRange y) { - if (x.FirstIpAddressLong <= y.FirstIpAddressLong && - x.LastIpAddressLong >= y.LastIpAddressLong) return 0; - if (x.FirstIpAddressLong < y.FirstIpAddressLong) return -1; + if (IPAddressUtil.Compare(x.FirstIpAddress, y.FirstIpAddress) <= 0 && IPAddressUtil.Compare(x.LastIpAddress, y.LastIpAddress) >= 0) return 0; + if (IPAddressUtil.Compare(x.FirstIpAddress, y.FirstIpAddress) < 0) return -1; return +1; } } diff --git a/VpnHood.Client/VpnHoodClient.cs b/VpnHood.Client/VpnHoodClient.cs index 85bfc6c3c..af178393a 100644 --- a/VpnHood.Client/VpnHoodClient.cs +++ b/VpnHood.Client/VpnHoodClient.cs @@ -223,7 +223,7 @@ private void ConfigPacketFilter(IPEndPoint hostEndPoint) List includeNetworks = new(); if (PacketCaptureIncludeIpRanges?.Length > 0) { - if (!PacketCaptureIncludeIpRanges.Any(x => x.IsInRange(hostEndPoint.Address))) + if (PacketCaptureIncludeIpRanges.Any(x => x.IsInRange(hostEndPoint.Address))) throw new InvalidOperationException( $"ServerIp can not be part of {nameof(PacketCaptureIncludeIpRanges)}! ServerIp: {hostEndPoint.Address}"); includeNetworks.AddRange(IpNetwork.FromIpRange(PacketCaptureIncludeIpRanges)); diff --git a/VpnHood.ZTest/Tests/IpNetworkTest.cs b/VpnHood.ZTest/Tests/IpNetworkTest.cs index d3e896552..66345bcb4 100644 --- a/VpnHood.ZTest/Tests/IpNetworkTest.cs +++ b/VpnHood.ZTest/Tests/IpNetworkTest.cs @@ -71,9 +71,11 @@ public void IpRange_IsInRange() { IpRange.Parse("9.9.9.9 - 9.9.9.9"), IpRange.Parse("8.8.8.8"), - IpRange.Parse("3.3.3.3-4.4.4.4"), - IpRange.Parse("3.3.3.3-4.4.3.4"), - IpRange.Parse("3.3.3.3-4.4.2.4"), + IpRange.Parse("3.3.3.3 - 4.4.4.4"), + IpRange.Parse("3.3.3.3 - 4.4.3.4"), + IpRange.Parse("3.3.3.3 - 4.4.2.4"), + IpRange.Parse("FF:: - FF::FF"), + IpRange.Parse("EF:: - FF::FF"), IpRange.Parse("5.5.5.5-5.5.5.10") }; @@ -83,6 +85,8 @@ public void IpRange_IsInRange() Assert.IsTrue(IpRange.IsInRangeFast(ipRanges, IPAddress.Parse("9.9.9.9"))); Assert.IsFalse(IpRange.IsInRangeFast(ipRanges, IPAddress.Parse("4.4.4.5"))); Assert.IsTrue(IpRange.IsInRangeFast(ipRanges, IPAddress.Parse("4.4.4.3"))); + Assert.IsTrue(IpRange.IsInRangeFast(ipRanges, IPAddress.Parse("FF::F0"))); + Assert.IsFalse(IpRange.IsInRangeFast(ipRanges, IPAddress.Parse("AF::F0"))); } } } \ No newline at end of file From 3265d19d8e702aab0acd04cc57dd2dab30d7f029 Mon Sep 17 00:00:00 2001 From: trudy Date: Sun, 19 Sep 2021 03:06:22 -0700 Subject: [PATCH 03/12] add ip6 support to IpNetwork --- VpnHood.Client.Device/IPAddressUtil.cs | 34 +++++++-- VpnHood.Client.Device/IPNetwork.cs | 102 ++++++++++++------------- VpnHood.ZTest/Tests/IpNetworkTest.cs | 21 ++++- 3 files changed, 93 insertions(+), 64 deletions(-) diff --git a/VpnHood.Client.Device/IPAddressUtil.cs b/VpnHood.Client.Device/IPAddressUtil.cs index c963141bb..fd2b043d2 100644 --- a/VpnHood.Client.Device/IPAddressUtil.cs +++ b/VpnHood.Client.Device/IPAddressUtil.cs @@ -1,25 +1,26 @@ using System; using System.Net; using System.Net.Sockets; +using System.Numerics; namespace VpnHood.Client.Device { public static class IPAddressUtil { - private static bool IsSupported(AddressFamily addressFamily) + public static bool IsSupported(AddressFamily addressFamily) { return addressFamily is AddressFamily.InterNetworkV6 or AddressFamily.InterNetwork; } - private static void Verify(AddressFamily addressFamily) + public static void Verify(AddressFamily addressFamily) { if (!IsSupported(addressFamily)) throw new NotSupportedException($"{addressFamily} is not supported!"); } - private static void Verify(IPAddress ipAddress) + public static void Verify(IPAddress ipAddress) { Verify(ipAddress.AddressFamily); } @@ -48,12 +49,36 @@ public static int Compare(IPAddress ipAddress1, IPAddress ipAddress2) return 0; } - + + public static long ToLong(IPAddress ipAddress) + { + if (ipAddress.AddressFamily != AddressFamily.InterNetwork) + throw new InvalidOperationException($"Only {AddressFamily.InterNetwork} family can be converted into long!"); + + var bytes = ipAddress.GetAddressBytes(); + return ((long)bytes[0] << 24) | ((long)bytes[1] << 16) | ((long)bytes[2] << 8) | bytes[3]; + } + public static IPAddress FromLong(long ipAddress) { return new IPAddress((uint)IPAddress.NetworkToHostOrder((int)ipAddress)); } + public static BigInteger ToBigInteger(IPAddress value) + { + return new BigInteger(value.GetAddressBytes(), true, true); + } + + public static IPAddress FromBigInteger(BigInteger value, AddressFamily addressFamily) + { + Verify(addressFamily); + + var bytes = new byte[addressFamily == AddressFamily.InterNetworkV6 ? 16 : 4]; + value.TryWriteBytes(bytes, out _, true); + Array.Reverse(bytes); + return new IPAddress(bytes); + } + public static IPAddress Increment(IPAddress ipAddress) { Verify(ipAddress); @@ -126,6 +151,5 @@ public static bool IsMinValue(IPAddress ipAddress) _ => throw new NotSupportedException($"{ipAddress.AddressFamily} is not supported!") }; } - } } \ No newline at end of file diff --git a/VpnHood.Client.Device/IPNetwork.cs b/VpnHood.Client.Device/IPNetwork.cs index 0539cbaa0..38cf68ddd 100644 --- a/VpnHood.Client.Device/IPNetwork.cs +++ b/VpnHood.Client.Device/IPNetwork.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Net; using System.Net.Sockets; +using System.Numerics; using System.Text.Json.Serialization; namespace VpnHood.Client.Device @@ -10,27 +11,29 @@ namespace VpnHood.Client.Device [JsonConverter(typeof(IpNetworkConverter))] public class IpNetwork { - private readonly long _firstIpAddressLong; - private readonly long _lastIpAddressLong; + private readonly BigInteger _firstIpAddressValue; + private readonly BigInteger _lastIpAddressValue; public IpNetwork(IPAddress prefix, int prefixLength = 32) { - if (prefix.AddressFamily != AddressFamily.InterNetwork) - throw new NotSupportedException("IPv6 is not supported"); + IPAddressUtil.Verify(prefix); Prefix = prefix; PrefixLength = prefixLength; - - var mask = (uint) ~(0xFFFFFFFFL >> prefixLength); - _firstIpAddressLong = IpAddressToLong(Prefix) & mask; - _lastIpAddressLong = _firstIpAddressLong | ~mask; + var bits = prefix.AddressFamily == AddressFamily.InterNetworkV6 ? 128 : 32; + var mask = ((new BigInteger(1) << prefixLength) - 1) << (bits - prefixLength); + var maskNot = (new BigInteger(1) << bits - prefixLength) - 1; + _firstIpAddressValue = IPAddressUtil.ToBigInteger(Prefix) & mask ; + _lastIpAddressValue = _firstIpAddressValue | maskNot; + FirstIpAddress = IPAddressUtil.FromBigInteger(_firstIpAddressValue, prefix.AddressFamily); + LastIpAddress = IPAddressUtil.FromBigInteger(_lastIpAddressValue, prefix.AddressFamily); } public IPAddress Prefix { get; } public int PrefixLength { get; } - public IPAddress FirstIpAddress => IpAddressFromLong(_firstIpAddressLong); - public IPAddress LastIpAddress => IpAddressFromLong(_lastIpAddressLong); - public long Total => _lastIpAddressLong - _firstIpAddressLong + 1; + public IPAddress FirstIpAddress { get; } + public IPAddress LastIpAddress { get; } + public BigInteger Total => _lastIpAddressValue - _firstIpAddressValue + 1; public static IpNetwork[] LocalNetworks { get; } = { @@ -40,63 +43,52 @@ public IpNetwork(IPAddress prefix, int prefixLength = 32) Parse("169.254.0.0/16") }; - public static IpNetwork[] FromIpRange(IpRange ipRange) + public static IEnumerable FromIpRange(IpRange ipRange) { return FromIpRange(ipRange.FirstIpAddress, ipRange.LastIpAddress); } - public static IpNetwork[] FromIpRange(IPAddress firstIpAddress, IPAddress lastIpAddress) + public static IEnumerable FromIpRange(IPAddress firstIpAddress, IPAddress lastIpAddress) { - return FromIpRange(IpAddressToLong(firstIpAddress), IpAddressToLong(lastIpAddress)); - } + if (firstIpAddress.AddressFamily != lastIpAddress.AddressFamily) + throw new ArgumentException("AddressFamilies don't match!"); - public static IpNetwork[] FromIpRange(long firstIpAddressLong, long lastIpAddressLong) - { - var result = new List(); - while (lastIpAddressLong >= firstIpAddressLong) - { - byte maxSize = 32; - while (maxSize > 0) - { - var mask = Mask(maxSize - 1); - var maskBase = firstIpAddressLong & mask; + var addressFamily = firstIpAddress.AddressFamily; + var bits = addressFamily == AddressFamily.InterNetworkV6 ? 128 : 32; + var first = IPAddressUtil.ToBigInteger(firstIpAddress); + var last = IPAddressUtil.ToBigInteger(lastIpAddress); - if (maskBase != firstIpAddressLong) - break; - maxSize--; + if (first > last) yield break; + last++; + // mask == 1 << len + BigInteger mask = 1; + int len = 0; + while (first + mask <= last) + { + if ((first & mask) != 0) + { + yield return new IpNetwork(IPAddressUtil.FromBigInteger(first, addressFamily), bits - len); + first += mask; + } + mask <<= 1; + len++; + } + while (first < last) + { + mask >>= 1; + len--; + if ((last & mask) != 0) + { + yield return new IpNetwork(IPAddressUtil.FromBigInteger(first, addressFamily), bits - len); + first += mask; } - - var x = Math.Log(lastIpAddressLong - firstIpAddressLong + 1) / Math.Log(2); - var maxDiff = (byte) (32 - Math.Floor(x)); - if (maxSize < maxDiff) maxSize = maxDiff; - var ipAddress = IpAddressFromLong(firstIpAddressLong); - result.Add(new IpNetwork(ipAddress, maxSize)); - firstIpAddressLong += (long) Math.Pow(2, 32 - maxSize); } - - return result.ToArray(); - } - - private static long Mask(int s) - { - return (long) (Math.Pow(2, 32) - Math.Pow(2, 32 - s)); - } - - public static long IpAddressToLong(IPAddress ipAddress) - { - var bytes = ipAddress.GetAddressBytes(); - return ((long) bytes[0] << 24) | ((long) bytes[1] << 16) | ((long) bytes[2] << 8) | bytes[3]; - } - - public static IPAddress IpAddressFromLong(long ipAddress) - { - return new IPAddress((uint) IPAddress.NetworkToHostOrder((int) ipAddress)); } public IpNetwork[] Invert() { - return Invert(new[] {this}); + return Invert(new[] { this }); } public static IpNetwork Parse(string value) @@ -114,7 +106,7 @@ public static IpNetwork Parse(string value) public static IOrderedEnumerable Sort(IEnumerable ipNetworks) { - return ipNetworks.OrderBy(x => x._firstIpAddressLong); + return ipNetworks.OrderBy(x => x._firstIpAddressValue); } public static IpNetwork[] Invert(IEnumerable ipNetworks) diff --git a/VpnHood.ZTest/Tests/IpNetworkTest.cs b/VpnHood.ZTest/Tests/IpNetworkTest.cs index 66345bcb4..1c097ee30 100644 --- a/VpnHood.ZTest/Tests/IpNetworkTest.cs +++ b/VpnHood.ZTest/Tests/IpNetworkTest.cs @@ -12,6 +12,8 @@ public class IpNetworkTest [TestMethod] public void Invert_Unify_Convert() { + //todo ip6 test + var ipRangesSorted = new[] { IpRange.Parse("127.0.0.0 - 127.255.255.255"), @@ -39,8 +41,7 @@ public void Invert_Unify_Convert() CollectionAssert.AreEqual(ipRangesSorted, IpRange.Sort(ipRanges)); // check network - CollectionAssert.AreEqual(IpNetwork.FromIpRange(expected), - IpNetwork.Invert(IpNetwork.FromIpRange(ipRanges))); + CollectionAssert.AreEqual(IpNetwork.FromIpRange(expected), IpNetwork.Invert(IpNetwork.FromIpRange(ipRanges))); CollectionAssert.AreEqual(ipRangesSorted, IpNetwork.ToIpRange(IpNetwork.FromIpRange(ipRanges))); } @@ -50,11 +51,12 @@ public void IpNetwork_Unit() var ipNetwork = IpNetwork.Parse("192.168.23.23/32"); var inverted = ipNetwork.Invert(); Assert.AreEqual(32, inverted.Length); - CollectionAssert.AreEqual(new[] {ipNetwork}, IpNetwork.Invert(inverted)); + CollectionAssert.AreEqual(new[] { ipNetwork }, IpNetwork.Invert(inverted)); + //todo ip6 test ipNetwork = IpNetwork.Parse("0.0.0.0/0"); Assert.AreEqual(0, ipNetwork.Invert().Length); - CollectionAssert.AreEqual(new[] {IpNetwork.Parse("0.0.0.0/0")}, IpNetwork.Invert(Array.Empty())); + CollectionAssert.AreEqual(new[] { IpNetwork.Parse("0.0.0.0/0") }, IpNetwork.Invert(Array.Empty())); } [TestMethod] @@ -88,5 +90,16 @@ public void IpRange_IsInRange() Assert.IsTrue(IpRange.IsInRangeFast(ipRanges, IPAddress.Parse("FF::F0"))); Assert.IsFalse(IpRange.IsInRangeFast(ipRanges, IPAddress.Parse("AF::F0"))); } + + [TestMethod] + public void Foo() + { + var ipNetwork = new IpNetwork(IPAddress.Parse("192.167.0.1"), 8); + Console.WriteLine(ipNetwork); + Console.WriteLine(ipNetwork.FirstIpAddress); + Console.WriteLine(ipNetwork.LastIpAddress); + + var a1 = IpNetwork.FromIpRange(IPAddress.Parse("0.0.0.0"), IPAddress.Parse("255.255.255.255")); + } } } \ No newline at end of file From 7415139a1f7da6c0e65edf882dc35124cef86821 Mon Sep 17 00:00:00 2001 From: trudy Date: Sun, 19 Sep 2021 23:09:52 -0700 Subject: [PATCH 04/12] Fix ip networks --- CHANGELOG.md | 1 + VpnHood.Client.Device/IPNetwork.cs | 13 +++--- VpnHood.Client.Device/IpRange.cs | 61 ++++++++++++++++++++-------- VpnHood.ZTest/Tests/IpNetworkTest.cs | 37 ++++++++--------- 4 files changed, 70 insertions(+), 42 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e03a7f30f..957c72563 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,5 @@ # Upcoming +* Fix: IpFilter miss some IPs of countries # v2.0.271 ### Client diff --git a/VpnHood.Client.Device/IPNetwork.cs b/VpnHood.Client.Device/IPNetwork.cs index 38cf68ddd..e6085bf8a 100644 --- a/VpnHood.Client.Device/IPNetwork.cs +++ b/VpnHood.Client.Device/IPNetwork.cs @@ -13,7 +13,6 @@ public class IpNetwork { private readonly BigInteger _firstIpAddressValue; private readonly BigInteger _lastIpAddressValue; - public IpNetwork(IPAddress prefix, int prefixLength = 32) { IPAddressUtil.Verify(prefix); @@ -31,6 +30,7 @@ public IpNetwork(IPAddress prefix, int prefixLength = 32) public IPAddress Prefix { get; } public int PrefixLength { get; } + public AddressFamily AddressFamily => Prefix.AddressFamily; public IPAddress FirstIpAddress { get; } public IPAddress LastIpAddress { get; } public BigInteger Total => _lastIpAddressValue - _firstIpAddressValue + 1; @@ -43,7 +43,10 @@ public IpNetwork(IPAddress prefix, int prefixLength = 32) Parse("169.254.0.0/16") }; - public static IEnumerable FromIpRange(IpRange ipRange) + public static IpNetwork AllV4 { get; } = Parse("0.0.0.0/0"); + public static IpNetwork AllV6 { get; } = Parse("::/0"); + + public static IEnumerable FromIpRange(IpRange ipRange) { return FromIpRange(ipRange.FirstIpAddress, ipRange.LastIpAddress); } @@ -88,7 +91,7 @@ public static IEnumerable FromIpRange(IPAddress firstIpAddress, IPAdd public IpNetwork[] Invert() { - return Invert(new[] { this }); + return Invert(new[] { this }, AddressFamily==AddressFamily.InterNetwork, AddressFamily == AddressFamily.InterNetworkV6); } public static IpNetwork Parse(string value) @@ -109,9 +112,9 @@ public static IOrderedEnumerable Sort(IEnumerable ipNetwor return ipNetworks.OrderBy(x => x._firstIpAddressValue); } - public static IpNetwork[] Invert(IEnumerable ipNetworks) + public static IpNetwork[] Invert(IEnumerable ipNetworks, bool includeIPv4 = true, bool includeIPv6 = true) { - return FromIpRange(IpRange.Invert(ToIpRange(ipNetworks))); + return FromIpRange(IpRange.Invert(ToIpRange(ipNetworks), includeIPv4, includeIPv6)); } public IpRange ToIpRange() diff --git a/VpnHood.Client.Device/IpRange.cs b/VpnHood.Client.Device/IpRange.cs index acc54c7eb..d26276d55 100644 --- a/VpnHood.Client.Device/IpRange.cs +++ b/VpnHood.Client.Device/IpRange.cs @@ -16,21 +16,24 @@ public IpRange(IPAddress ipAddress) { } + public IpRange(long firstIpAddress, long lastIpAddress) + : this(IPAddressUtil.FromLong(firstIpAddress), IPAddressUtil.FromLong(lastIpAddress)) + { + } + public IpRange(IPAddress firstIpAddress, IPAddress lastIpAddress) { if (firstIpAddress.AddressFamily != lastIpAddress.AddressFamily) throw new InvalidOperationException("Both ipAddress must have a same address family!"); + if (IPAddressUtil.Compare(firstIpAddress, lastIpAddress) > 0) + throw new InvalidOperationException($"{nameof(lastIpAddress)} must be equal or greater than {nameof(firstIpAddress)}"); + FirstIpAddress = firstIpAddress; LastIpAddress = lastIpAddress; } - public IpRange(long firstIpAddress, long lastIpAddress) - { - FirstIpAddress = IPAddressUtil.FromLong(firstIpAddress); - LastIpAddress = IPAddressUtil.FromLong(lastIpAddress); - } - + public AddressFamily AddressFamily => FirstIpAddress.AddressFamily; public IPAddress FirstIpAddress { get; } public IPAddress LastIpAddress { get; } public BigInteger Total => new BigInteger(LastIpAddress.GetAddressBytes(), true, true) - new BigInteger(FirstIpAddress.GetAddressBytes(), true, true) + 1; @@ -47,8 +50,8 @@ private static IpRange[] Unify(IEnumerable sortedIpRanges) foreach (var ipRange in sortedIpRanges) { if (res.Count > 0 && - ipRange.FirstIpAddress.AddressFamily == res[^1].LastIpAddress.AddressFamily && - IPAddressUtil.Compare(ipRange.FirstIpAddress, res[^1].LastIpAddress) <= 0) + ipRange.AddressFamily == res[^1].AddressFamily && + IPAddressUtil.Compare(IPAddressUtil.Decrement(ipRange.FirstIpAddress), res[^1].LastIpAddress) <= 0) { if (IPAddressUtil.Compare(ipRange.LastIpAddress, res[^1].LastIpAddress) > 0) res[^1] = new IpRange(res[^1].FirstIpAddress, ipRange.LastIpAddress); @@ -62,8 +65,35 @@ private static IpRange[] Unify(IEnumerable sortedIpRanges) return res.ToArray(); } + public static IpRange[] Invert(IpRange[] ipRanges, bool includeIPv4 = true, bool includeIPv6 = true) + { + List list = new(); + + // IP4 + if (includeIPv4) + { + var ipRanges2 = ipRanges.Where(x => x.AddressFamily == AddressFamily.InterNetwork).ToArray(); + if (ipRanges2.Any()) + list.AddRange(InvertInternal(ipRanges2)); + else + list.Add(new IpRange(IPAddressUtil.MinIPv4Value, IPAddressUtil.MaxIPv4Value)); + } + + // IP6 + if (includeIPv6) + { + var ipRanges2 = ipRanges.Where(x => x.AddressFamily == AddressFamily.InterNetworkV6).ToArray(); + if (ipRanges2.Any()) + list.AddRange(InvertInternal(ipRanges2)); + else + list.Add(new IpRange(IPAddressUtil.MinIPv6Value, IPAddressUtil.MaxIPv6Value)); + } + + return list.ToArray(); + } + - public static IpRange[] Invert(IEnumerable ipRanges, bool includeIPv6 = false) + private static IpRange[] InvertInternal(IEnumerable ipRanges) { // sort var ipRangesSorted = Sort(ipRanges); @@ -73,22 +103,17 @@ public static IpRange[] Invert(IEnumerable ipRanges, bool includeIPv6 = for (var i = 0; i < ipRangesSorted.Length; i++) { var ipRange = ipRangesSorted[i]; - var minIpValue = ipRange.FirstIpAddress.AddressFamily == AddressFamily.InterNetworkV6 ? IPAddressUtil.MinIPv6Value : IPAddressUtil.MinIPv4Value; - var maxIpValue = ipRange.FirstIpAddress.AddressFamily == AddressFamily.InterNetworkV6 ? IPAddressUtil.MaxIPv6Value : IPAddressUtil.MaxIPv4Value; + var minIpValue = ipRange.AddressFamily == AddressFamily.InterNetworkV6 ? IPAddressUtil.MinIPv6Value : IPAddressUtil.MinIPv4Value; + var maxIpValue = ipRange.AddressFamily == AddressFamily.InterNetworkV6 ? IPAddressUtil.MaxIPv6Value : IPAddressUtil.MaxIPv4Value; - if (i == 0 && !IPAddressUtil.IsMinValue(ipRange.FirstIpAddress)) res.Add(new IpRange(minIpValue, IPAddressUtil.Decrement(ipRange.FirstIpAddress))); + if (i == 0 && !IPAddressUtil.IsMinValue(ipRange.FirstIpAddress)) + res.Add(new IpRange(minIpValue, IPAddressUtil.Decrement(ipRange.FirstIpAddress))); if (i > 0) res.Add(new IpRange(IPAddressUtil.Increment(ipRangesSorted[i - 1].LastIpAddress), IPAddressUtil.Decrement(ipRange.FirstIpAddress))); if (i == ipRangesSorted.Length - 1 && !IPAddressUtil.IsMaxValue(ipRange.LastIpAddress)) res.Add(new IpRange(IPAddressUtil.Increment(ipRange.LastIpAddress), maxIpValue)); } - // invert of nothing is all thing! - if (ipRangesSorted.All(x => x.FirstIpAddress.AddressFamily != AddressFamily.InterNetwork)) - res.Insert(0, new IpRange(IPAddressUtil.MinIPv4Value, IPAddressUtil.MaxIPv4Value)); - if (includeIPv6 && ipRangesSorted.All(x => x.FirstIpAddress.AddressFamily != AddressFamily.InterNetworkV6)) - res.Add(new IpRange(IPAddressUtil.MinIPv6Value, IPAddressUtil.MaxIPv6Value)); - return res.ToArray(); } diff --git a/VpnHood.ZTest/Tests/IpNetworkTest.cs b/VpnHood.ZTest/Tests/IpNetworkTest.cs index 1c097ee30..cd0a761b7 100644 --- a/VpnHood.ZTest/Tests/IpNetworkTest.cs +++ b/VpnHood.ZTest/Tests/IpNetworkTest.cs @@ -17,28 +17,34 @@ public void Invert_Unify_Convert() var ipRangesSorted = new[] { IpRange.Parse("127.0.0.0 - 127.255.255.255"), - IpRange.Parse("192.168.0.0 - 192.168.255.255") + IpRange.Parse("192.168.0.0 - 192.168.255.255"), + IpRange.Parse("9A::0000 - AA::FFFF") }; - var ipRanges = new[] { + IpRange.Parse("AA::0000 - AA::FCFC"), IpRange.Parse("192.168.0.0 - 192.168.255.140"), + IpRange.Parse("9A::0000 - AA::AABB"), + IpRange.Parse("AA::0000 - AA::FFF0"), + IpRange.Parse("AA::FFF1 - AA::FFFF"), IpRange.Parse("192.168.10.0 - 192.168.255.255"), IpRange.Parse("127.0.0.0 - 127.255.255.255"), IpRange.Parse("127.0.0.0 - 127.255.255.254") //extra }; + CollectionAssert.AreEqual(ipRangesSorted, IpRange.Sort(ipRanges)); var inverted = IpRange.Invert(ipRanges); var expected = new[] { IpRange.Parse("0.0.0.0 - 126.255.255.255"), IpRange.Parse("128.0.0.0 - 192.167.255.255"), - IpRange.Parse("192.169.0.0 - 255.255.255.255") + IpRange.Parse("192.169.0.0 - 255.255.255.255"), + IpRange.Parse(":: - 99:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF"), + IpRange.Parse("AA::01:0000 - FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF"), }; CollectionAssert.AreEqual(expected, inverted); - CollectionAssert.AreEqual(ipRangesSorted, IpRange.Sort(ipRanges)); // check network CollectionAssert.AreEqual(IpNetwork.FromIpRange(expected), IpNetwork.Invert(IpNetwork.FromIpRange(ipRanges))); @@ -51,12 +57,15 @@ public void IpNetwork_Unit() var ipNetwork = IpNetwork.Parse("192.168.23.23/32"); var inverted = ipNetwork.Invert(); Assert.AreEqual(32, inverted.Length); - CollectionAssert.AreEqual(new[] { ipNetwork }, IpNetwork.Invert(inverted)); + CollectionAssert.AreEqual(new[] { ipNetwork }, IpNetwork.Invert(inverted, true, false)); - //todo ip6 test - ipNetwork = IpNetwork.Parse("0.0.0.0/0"); + ipNetwork = IpNetwork.AllV4; + Assert.AreEqual(0, ipNetwork.Invert().Length); + + ipNetwork = IpNetwork.AllV6; Assert.AreEqual(0, ipNetwork.Invert().Length); - CollectionAssert.AreEqual(new[] { IpNetwork.Parse("0.0.0.0/0") }, IpNetwork.Invert(Array.Empty())); + + CollectionAssert.AreEqual(new[] { IpNetwork.AllV4, IpNetwork.AllV6 }, IpNetwork.Invert(Array.Empty())); } [TestMethod] @@ -91,15 +100,5 @@ public void IpRange_IsInRange() Assert.IsFalse(IpRange.IsInRangeFast(ipRanges, IPAddress.Parse("AF::F0"))); } - [TestMethod] - public void Foo() - { - var ipNetwork = new IpNetwork(IPAddress.Parse("192.167.0.1"), 8); - Console.WriteLine(ipNetwork); - Console.WriteLine(ipNetwork.FirstIpAddress); - Console.WriteLine(ipNetwork.LastIpAddress); - - var a1 = IpNetwork.FromIpRange(IPAddress.Parse("0.0.0.0"), IPAddress.Parse("255.255.255.255")); - } - } + } } \ No newline at end of file From 08aa8a4283024c7150d869e8e6cadf87b709be80 Mon Sep 17 00:00:00 2001 From: trudy Date: Sun, 19 Sep 2021 23:32:15 -0700 Subject: [PATCH 05/12] add remarks --- VpnHood.Client.Device/IPNetwork.cs | 12 +++++++++--- VpnHood.Client/VpnHoodClient.cs | 2 +- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/VpnHood.Client.Device/IPNetwork.cs b/VpnHood.Client.Device/IPNetwork.cs index e6085bf8a..2c41162d3 100644 --- a/VpnHood.Client.Device/IPNetwork.cs +++ b/VpnHood.Client.Device/IPNetwork.cs @@ -22,7 +22,7 @@ public IpNetwork(IPAddress prefix, int prefixLength = 32) var bits = prefix.AddressFamily == AddressFamily.InterNetworkV6 ? 128 : 32; var mask = ((new BigInteger(1) << prefixLength) - 1) << (bits - prefixLength); var maskNot = (new BigInteger(1) << bits - prefixLength) - 1; - _firstIpAddressValue = IPAddressUtil.ToBigInteger(Prefix) & mask ; + _firstIpAddressValue = IPAddressUtil.ToBigInteger(Prefix) & mask; _lastIpAddressValue = _firstIpAddressValue | maskNot; FirstIpAddress = IPAddressUtil.FromBigInteger(_firstIpAddressValue, prefix.AddressFamily); LastIpAddress = IPAddressUtil.FromBigInteger(_lastIpAddressValue, prefix.AddressFamily); @@ -43,10 +43,16 @@ public IpNetwork(IPAddress prefix, int prefixLength = 32) Parse("169.254.0.0/16") }; + public static IpNetwork[] LocalNetworksV6 { get; } = + { + Parse("fc00::/7"), + Parse("fe80::/10") + }; + public static IpNetwork AllV4 { get; } = Parse("0.0.0.0/0"); public static IpNetwork AllV6 { get; } = Parse("::/0"); - public static IEnumerable FromIpRange(IpRange ipRange) + public static IEnumerable FromIpRange(IpRange ipRange) { return FromIpRange(ipRange.FirstIpAddress, ipRange.LastIpAddress); } @@ -91,7 +97,7 @@ public static IEnumerable FromIpRange(IPAddress firstIpAddress, IPAdd public IpNetwork[] Invert() { - return Invert(new[] { this }, AddressFamily==AddressFamily.InterNetwork, AddressFamily == AddressFamily.InterNetworkV6); + return Invert(new[] { this }, AddressFamily == AddressFamily.InterNetwork, AddressFamily == AddressFamily.InterNetworkV6); } public static IpNetwork Parse(string value) diff --git a/VpnHood.Client/VpnHoodClient.cs b/VpnHood.Client/VpnHoodClient.cs index af178393a..59823e8af 100644 --- a/VpnHood.Client/VpnHoodClient.cs +++ b/VpnHood.Client/VpnHoodClient.cs @@ -296,7 +296,7 @@ private void PacketCapture_OnPacketReceivedFromInbound(object sender, Device.Pac foreach (var ipPacket in e.IpPackets) { if (_cancellationTokenSource.IsCancellationRequested) return; - if (ipPacket.Version != IPVersion.IPv4) + if (ipPacket.Version != IPVersion.IPv4) // actively drop IPv6 at this version continue; var isInRange = IsInIpRange(ipPacket.DestinationAddress); From 4ece2169a050379e4aa23bd611e8fc5f97b41866 Mon Sep 17 00:00:00 2001 From: trudy Date: Mon, 20 Sep 2021 12:02:02 -0700 Subject: [PATCH 06/12] more ip6 --- .../AppVpnService.cs | 2 +- .../WinDivertPacketCapture.cs | 12 +++++++--- VpnHood.Client/TcpProxyHost.cs | 21 +++++++--------- VpnHood.Client/VpnHoodClient.cs | 6 ++--- VpnHood.ZTest/Tests/IpNetworkTest.cs | 2 -- VpnHood.ZTest/Tests/NatTest.cs | 24 +++++++++++-------- 6 files changed, 36 insertions(+), 31 deletions(-) diff --git a/VpnHood.Client.Device.Android/AppVpnService.cs b/VpnHood.Client.Device.Android/AppVpnService.cs index b810d03bc..b36794879 100644 --- a/VpnHood.Client.Device.Android/AppVpnService.cs +++ b/VpnHood.Client.Device.Android/AppVpnService.cs @@ -210,7 +210,7 @@ private Task ReadingPacketTask() var buf = new byte[short.MaxValue]; while (_inStream.Read(buf) > 0) { - var ipPacket = Packet.ParsePacket(LinkLayers.Raw, buf)?.Extract(); + var ipPacket = Packet.ParsePacket(LinkLayers.Raw, buf)?.Extract(); if (ipPacket != null) ProcessPacket(ipPacket); } diff --git a/VpnHood.Client.Device.WinDivert/WinDivertPacketCapture.cs b/VpnHood.Client.Device.WinDivert/WinDivertPacketCapture.cs index 37c5f30f5..71b101246 100644 --- a/VpnHood.Client.Device.WinDivert/WinDivertPacketCapture.cs +++ b/VpnHood.Client.Device.WinDivert/WinDivertPacketCapture.cs @@ -85,6 +85,11 @@ public IpNetwork[]? IncludeNetworks } } + private string Ip(IpRange ipRange) + { + return ipRange.AddressFamily==AddressFamily.InterNetworkV6 ? "ipv6" : "ip"; + } + public void StartCapture() { if (Started) @@ -96,14 +101,15 @@ public void StartCapture() { var ipRanges = IpNetwork.ToIpRange(IncludeNetworks); var phrases = ipRanges.Select(x => x.FirstIpAddress.Equals(x.LastIpAddress) - ? $"ip.DstAddr=={x.FirstIpAddress}" - : $"(ip.DstAddr>={x.FirstIpAddress} and ip.DstAddr<={x.LastIpAddress})"); + ? $"{Ip(x)}.DstAddr=={x.FirstIpAddress}" + : $"({Ip(x)}.DstAddr>={x.FirstIpAddress} and {Ip(x)}.DstAddr<={x.LastIpAddress})"); var phrase = string.Join(" or ", phrases); phraseX += $" and ({phrase})"; } // add outbound; filter loopback - var filter = $"ip and outbound and !loopback and (udp.DstPort==53 or ({phraseX}))"; + var filter = $"(ip or ipv6) and outbound and !loopback and (udp.DstPort==53 or ({phraseX}))"; + filter = filter.Replace("ipv6.DstAddr>=::", "(ipv6.DstAddr==:: or ipv6.DstAddr>::)"); try { Device.Filter = filter; diff --git a/VpnHood.Client/TcpProxyHost.cs b/VpnHood.Client/TcpProxyHost.cs index 135cd06df..e62db20af 100644 --- a/VpnHood.Client/TcpProxyHost.cs +++ b/VpnHood.Client/TcpProxyHost.cs @@ -55,15 +55,12 @@ public async Task StartListening() VhLogger.Instance.LogInformation( $"Start listening on {VhLogger.Format(_tcpListener.LocalEndpoint)}..."); _tcpListener.Start(); - _localEndpoint = (IPEndPoint) _tcpListener.LocalEndpoint; //it is slow; make sure to cache it + _localEndpoint = (IPEndPoint)_tcpListener.LocalEndpoint; //it is slow; make sure to cache it - await using (cancellationToken.Register(() => _tcpListener.Stop())) + while (!cancellationToken.IsCancellationRequested) { - while (!cancellationToken.IsCancellationRequested) - { - var tcpClient = await _tcpListener.AcceptTcpClientAsync(); - _ = ProcessClient(tcpClient, cancellationToken); - } + var tcpClient = await Util.RunTask(_tcpListener.AcceptTcpClientAsync(), 0, cancellationToken); + _ = ProcessClient(tcpClient, cancellationToken); } } catch (Exception ex) @@ -83,7 +80,7 @@ public IPPacket[] ProcessOutgoingPacket(IPPacket[] ipPackets) if (_localEndpoint == null) throw new InvalidOperationException( $"{nameof(_localEndpoint)} has not been initialized! Did you call {nameof(StartListening)}!"); - + _ipPackets.Clear(); // prevent reallocation in this intensive method var ret = _ipPackets; @@ -101,7 +98,7 @@ public IPPacket[] ProcessOutgoingPacket(IPPacket[] ipPackets) if (Equals(ipPacket.DestinationAddress, _loopbackAddress)) { // redirect to inbound - var natItem = (NatItemEx?) Client.Nat.Resolve(ipPacket.Protocol, tcpPacket.DestinationPort); + var natItem = (NatItemEx?)Client.Nat.Resolve(ipPacket.Protocol, tcpPacket.DestinationPort); if (natItem != null) { ipPacket.SourceAddress = natItem.DestinationAddress; @@ -130,7 +127,7 @@ public IPPacket[] ProcessOutgoingPacket(IPPacket[] ipPackets) tcpPacket.SourcePort = natItem.NatId; // 1 ipPacket.DestinationAddress = ipPacket.SourceAddress; // 2 ipPacket.SourceAddress = _loopbackAddress; //3 - tcpPacket.DestinationPort = (ushort) _localEndpoint.Port; //4 + tcpPacket.DestinationPort = (ushort)_localEndpoint.Port; //4 } else { @@ -165,8 +162,8 @@ private async Task ProcessClient(TcpClient tcpOrgClient, CancellationToken cance Util.TcpClient_SetKeepAlive(tcpOrgClient, true); // get original remote from NAT - var orgRemoteEndPoint = (IPEndPoint) tcpOrgClient.Client.RemoteEndPoint; - var natItem = (NatItemEx?) Client.Nat.Resolve(ProtocolType.Tcp, (ushort) orgRemoteEndPoint.Port); + var orgRemoteEndPoint = (IPEndPoint)tcpOrgClient.Client.RemoteEndPoint; + var natItem = (NatItemEx?)Client.Nat.Resolve(ProtocolType.Tcp, (ushort)orgRemoteEndPoint.Port); if (natItem == null) throw new Exception( $"Could not resolve original remote from NAT! RemoteEndPoint: {VhLogger.Format(tcpOrgClient.Client.RemoteEndPoint)}"); diff --git a/VpnHood.Client/VpnHoodClient.cs b/VpnHood.Client/VpnHoodClient.cs index 59823e8af..d7bd6812c 100644 --- a/VpnHood.Client/VpnHoodClient.cs +++ b/VpnHood.Client/VpnHoodClient.cs @@ -242,7 +242,7 @@ private void ConfigPacketFilter(IPEndPoint hostEndPoint) // convert excludeNetworks into includeNetworks if (excludeNetworks.Count > 0) - includeNetworks.AddRange(IpNetwork.Invert(excludeNetworks)); + includeNetworks.AddRange(IpNetwork.Invert(excludeNetworks, true, true)); } // finalize @@ -296,8 +296,8 @@ private void PacketCapture_OnPacketReceivedFromInbound(object sender, Device.Pac foreach (var ipPacket in e.IpPackets) { if (_cancellationTokenSource.IsCancellationRequested) return; - if (ipPacket.Version != IPVersion.IPv4) // actively drop IPv6 at this version - continue; + if (ipPacket.Version == IPVersion.IPv6) + continue; // actively drop IPv6 packets var isInRange = IsInIpRange(ipPacket.DestinationAddress); diff --git a/VpnHood.ZTest/Tests/IpNetworkTest.cs b/VpnHood.ZTest/Tests/IpNetworkTest.cs index cd0a761b7..9279f981e 100644 --- a/VpnHood.ZTest/Tests/IpNetworkTest.cs +++ b/VpnHood.ZTest/Tests/IpNetworkTest.cs @@ -12,8 +12,6 @@ public class IpNetworkTest [TestMethod] public void Invert_Unify_Convert() { - //todo ip6 test - var ipRangesSorted = new[] { IpRange.Parse("127.0.0.0 - 127.255.255.255"), diff --git a/VpnHood.ZTest/Tests/NatTest.cs b/VpnHood.ZTest/Tests/NatTest.cs index a10d40011..2d22888e0 100644 --- a/VpnHood.ZTest/Tests/NatTest.cs +++ b/VpnHood.ZTest/Tests/NatTest.cs @@ -36,21 +36,23 @@ public void Nat_NatItem_Test() Assert.AreEqual(ipPacket.SourceAddress, natItem.SourceAddress); Assert.AreEqual(tcpPacket.SourcePort, natItem.SourcePort); - var newIpPacket = new IPv4Packet(ipPacket.BytesSegment); + var newIpPacket = Packet.ParsePacket(LinkLayers.Raw, ipPacket.BytesSegment.Bytes).Extract(); Assert.AreEqual(id, nat.GetOrAdd(newIpPacket).NatId, "Same NatId is expected for a same packet!"); - newIpPacket = new IPv4Packet(ipPacket.BytesSegment) {SourceAddress = IPAddress.Parse("10.2.1.1")}; + newIpPacket = Packet.ParsePacket(LinkLayers.Raw, ipPacket.BytesSegment.Bytes).Extract(); + newIpPacket.SourceAddress = IPAddress.Parse("10.2.1.1"); Assert.AreNotEqual(id, nat.GetOrAdd(newIpPacket).NatId, "Different NatId is expected for a new source!"); - newIpPacket = new IPv4Packet(ipPacket.BytesSegment); + newIpPacket = Packet.ParsePacket(LinkLayers.Raw, ipPacket.BytesSegment.Bytes).Extract(); PacketUtil.ExtractTcp(newIpPacket).SourcePort = (ushort) (tcpPacket.SourcePort + 1); Assert.AreNotEqual(id, nat.GetOrAdd(newIpPacket).NatId, "Different NatId is expected for a new SourcePort!"); - newIpPacket = new IPv4Packet(ipPacket.BytesSegment) {DestinationAddress = IPAddress.Parse("10.2.1.1")}; + newIpPacket = Packet.ParsePacket(LinkLayers.Raw, ipPacket.BytesSegment.Bytes).Extract(); + newIpPacket.DestinationAddress = IPAddress.Parse("10.2.1.1"); Assert.AreEqual(id, nat.GetOrAdd(newIpPacket).NatId, "Same NatId is expected for a new destination!"); - newIpPacket = new IPv4Packet(ipPacket.BytesSegment); + newIpPacket = Packet.ParsePacket(LinkLayers.Raw, ipPacket.BytesSegment.Bytes).Extract(); PacketUtil.ExtractTcp(newIpPacket).DestinationPort = (ushort) (tcpPacket.DestinationPort + 1); Assert.AreEqual(id, nat.GetOrAdd(newIpPacket).NatId, "Sme NatId is expected for a new destinationPort!"); } @@ -73,22 +75,24 @@ public void Nat_NatItemEx_Test() Assert.AreEqual(tcpPacket.SourcePort, natItem.SourcePort); Assert.AreEqual(tcpPacket.DestinationPort, natItem.DestinationPort); - var newIpPacket = new IPv4Packet(ipPacket.BytesSegment); + var newIpPacket = Packet.ParsePacket(LinkLayers.Raw, ipPacket.BytesSegment.Bytes).Extract(); Assert.AreEqual(id, nat.GetOrAdd(newIpPacket).NatId, "Same NatId is expected for a same packet!"); - newIpPacket = new IPv4Packet(ipPacket.BytesSegment) {SourceAddress = IPAddress.Parse("10.2.1.1")}; + newIpPacket = Packet.ParsePacket(LinkLayers.Raw, ipPacket.BytesSegment.Bytes).Extract(); + newIpPacket.SourceAddress = IPAddress.Parse("10.2.1.1"); Assert.AreNotEqual(id, nat.GetOrAdd(newIpPacket).NatId, "Different NatId is expected for a new source!"); - newIpPacket = new IPv4Packet(ipPacket.BytesSegment); + newIpPacket = Packet.ParsePacket(LinkLayers.Raw, ipPacket.BytesSegment.Bytes).Extract(); PacketUtil.ExtractTcp(newIpPacket).DestinationPort = (ushort) (tcpPacket.SourcePort + 1); Assert.AreNotEqual(id, nat.GetOrAdd(newIpPacket).NatId, "Different NatId is expected for a new SourcePort!"); - newIpPacket = new IPv4Packet(ipPacket.BytesSegment) {DestinationAddress = IPAddress.Parse("10.2.1.1")}; + newIpPacket = Packet.ParsePacket(LinkLayers.Raw, ipPacket.BytesSegment.Bytes).Extract(); + newIpPacket.DestinationAddress = IPAddress.Parse("10.2.1.1"); Assert.AreNotEqual(id, nat.GetOrAdd(newIpPacket).NatId, "Different NatId is expected for a new destination!"); - newIpPacket = new IPv4Packet(ipPacket.BytesSegment); + newIpPacket = Packet.ParsePacket(LinkLayers.Raw, ipPacket.BytesSegment.Bytes).Extract(); PacketUtil.ExtractTcp(newIpPacket).SourcePort = (ushort) (tcpPacket.DestinationPort + 1); Assert.AreNotEqual(id, nat.GetOrAdd(newIpPacket).NatId, "Different NatId is expected for a new destinationPort!"); From 73578d5426fffc99c2a901c7d71500f10b289d4e Mon Sep 17 00:00:00 2001 From: trudy Date: Mon, 20 Sep 2021 12:31:48 -0700 Subject: [PATCH 07/12] more ip6 --- VpnHood.Tunneling/StreamPacketReader.cs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/VpnHood.Tunneling/StreamPacketReader.cs b/VpnHood.Tunneling/StreamPacketReader.cs index 8aeb0477f..38cd607ca 100644 --- a/VpnHood.Tunneling/StreamPacketReader.cs +++ b/VpnHood.Tunneling/StreamPacketReader.cs @@ -38,8 +38,11 @@ public StreamPacketReader(Stream stream) var bufferIndex = 0; while (_bufferCount - bufferIndex >= 4) { - var packetLength = IPAddress.NetworkToHostOrder(BitConverter.ToInt16(_buffer, bufferIndex + 2)); - if (packetLength < IPv4Packet.HeaderMinimumLength) + var version = _buffer[bufferIndex] >> 4; + var packetLength = version == 4 + ? IPAddress.NetworkToHostOrder(BitConverter.ToInt16(_buffer, bufferIndex + 2)) + : 40; + if (packetLength < 20) //v4 throw new Exception($"A packet with invalid length has been received! Length: {packetLength}"); // read all packets @@ -48,8 +51,7 @@ public StreamPacketReader(Stream stream) var packetBuffer = _buffer[bufferIndex..(bufferIndex + packetLength)]; //we shouldn't use shared memory for packet - var segment = new ByteArraySegment(packetBuffer); - var ipPacket = new IPv4Packet(segment); + var ipPacket = Packet.ParsePacket(LinkLayers.Raw, packetBuffer).Extract(); _ipPackets.Add(ipPacket); bufferIndex += packetLength; From 086e77fbe7137319b38ea3180738ec9bc55682cb Mon Sep 17 00:00:00 2001 From: trudy Date: Mon, 20 Sep 2021 13:16:23 -0700 Subject: [PATCH 08/12] more ip6 --- VpnHood.Tunneling/PacketUtil.cs | 42 ++++++++++++++++++------- VpnHood.Tunneling/PingProxy.cs | 2 +- VpnHood.Tunneling/StreamPacketReader.cs | 10 ++---- 3 files changed, 34 insertions(+), 20 deletions(-) diff --git a/VpnHood.Tunneling/PacketUtil.cs b/VpnHood.Tunneling/PacketUtil.cs index 9dbd76ff2..2d2b7a13d 100644 --- a/VpnHood.Tunneling/PacketUtil.cs +++ b/VpnHood.Tunneling/PacketUtil.cs @@ -45,6 +45,10 @@ public static void UpdateIpPacket(IPPacket ipPacket, bool throwIfNotSupported = ipV4Packet.UpdateIPChecksum(); ipPacket.UpdateCalculatedValues(); } + else if (ipPacket is IPv6Packet) + { + ipPacket.UpdateCalculatedValues(); + } else { if (throwIfNotSupported) @@ -77,7 +81,6 @@ public static IPPacket CreateTcpResetReply(IPPacket ipPacket, bool updatePacket resetTcpPacket.SequenceNumber = tcpPacketOrg.AcknowledgmentNumber; } - IPv4Packet resetIpPacket = new(ipPacket.DestinationAddress, ipPacket.SourceAddress) { Protocol = ProtocolType.Tcp, @@ -121,7 +124,7 @@ public static IPPacket CreateUnreachableReply(IPPacket ipPacket, IcmpV4TypeCode Sequence = sequence }; icmpV4Packet.Checksum = - (ushort) ChecksumUtils.OnesComplementSum(icmpV4Packet.Bytes, 0, icmpV4Packet.Bytes.Length); + (ushort)ChecksumUtils.OnesComplementSum(icmpV4Packet.Bytes, 0, icmpV4Packet.Bytes.Length); icmpV4Packet.UpdateCalculatedValues(); var newIpPacket = new IPv4Packet(ipPacket.DestinationAddress, ipPacket.SourceAddress) @@ -129,8 +132,7 @@ public static IPPacket CreateUnreachableReply(IPPacket ipPacket, IcmpV4TypeCode PayloadPacket = icmpV4Packet, FragmentFlags = 0 }; - newIpPacket.UpdateIPChecksum(); - newIpPacket.UpdateCalculatedValues(); + UpdateIpPacket(newIpPacket); return newIpPacket; } @@ -141,20 +143,38 @@ public static void UpdateIcmpChecksum(IcmpV4Packet icmpPacket) icmpPacket.Checksum = 0; var buf = icmpPacket.Bytes; icmpPacket.Checksum = - buf != null ? (ushort) ChecksumUtils.OnesComplementSum(buf, 0, buf.Length) : (ushort) 0; + buf != null ? (ushort)ChecksumUtils.OnesComplementSum(buf, 0, buf.Length) : (ushort)0; + } + + public static ushort ReadPacketLength(byte[] buffer, int bufferIndex) + { + var version = buffer[bufferIndex] >> 4; + + // v4 + if (version == 4) + { + var ret = (ushort)IPAddress.NetworkToHostOrder(BitConverter.ToInt16(buffer, bufferIndex + 2)); + if (ret < 20) + throw new Exception($"A packet with invalid length has been received! Length: {ret}"); + return ret; + } + + // v6 + if (version == 6) + return 40; + + // unknown + throw new Exception("Unknown packet version!"); } public static IPPacket ReadNextPacket(byte[] buffer, ref int bufferIndex) { if (buffer is null) throw new ArgumentNullException(nameof(buffer)); - var packetLength = IPAddress.NetworkToHostOrder(BitConverter.ToInt16(buffer, bufferIndex + 2)); - if (packetLength < IPv4Packet.HeaderMinimumLength) - throw new Exception($"A packet with invalid length has been received! Length: {packetLength}"); - - var segment = new ByteArraySegment(buffer, bufferIndex, packetLength); + var packetLength = ReadPacketLength(buffer, bufferIndex); + var packet = Packet.ParsePacket(LinkLayers.Raw, buffer[bufferIndex..(bufferIndex + packetLength)]).Extract(); bufferIndex += packetLength; - return new IPv4Packet(segment); + return packet; } public static void LogPackets(IEnumerable ipPackets, string operation) diff --git a/VpnHood.Tunneling/PingProxy.cs b/VpnHood.Tunneling/PingProxy.cs index b521da663..226bd09df 100644 --- a/VpnHood.Tunneling/PingProxy.cs +++ b/VpnHood.Tunneling/PingProxy.cs @@ -44,7 +44,7 @@ private void Ping_PingCompleted(object sender, PingCompletedEventArgs e) } var pingReply = e.Reply ?? throw new Exception("Ping Reply is null!."); - var ipPacket = (IPv4Packet) e.UserState ?? throw new Exception("UserState is null!"); + var ipPacket = (IPPacket) e.UserState ?? throw new Exception("UserState is null!"); if (pingReply.Status != IPStatus.Success) { if (VhLogger.IsDiagnoseMode) diff --git a/VpnHood.Tunneling/StreamPacketReader.cs b/VpnHood.Tunneling/StreamPacketReader.cs index 38cd607ca..c3ccb9f49 100644 --- a/VpnHood.Tunneling/StreamPacketReader.cs +++ b/VpnHood.Tunneling/StreamPacketReader.cs @@ -38,19 +38,13 @@ public StreamPacketReader(Stream stream) var bufferIndex = 0; while (_bufferCount - bufferIndex >= 4) { - var version = _buffer[bufferIndex] >> 4; - var packetLength = version == 4 - ? IPAddress.NetworkToHostOrder(BitConverter.ToInt16(_buffer, bufferIndex + 2)) - : 40; - if (packetLength < 20) //v4 - throw new Exception($"A packet with invalid length has been received! Length: {packetLength}"); + var packetLength = PacketUtil.ReadPacketLength(_buffer, bufferIndex); // read all packets if (_bufferCount - bufferIndex < packetLength) break; - var packetBuffer = - _buffer[bufferIndex..(bufferIndex + packetLength)]; //we shouldn't use shared memory for packet + var packetBuffer = _buffer[bufferIndex..(bufferIndex + packetLength)]; //we shouldn't use shared memory for packet var ipPacket = Packet.ParsePacket(LinkLayers.Raw, packetBuffer).Extract(); _ipPackets.Add(ipPacket); From d60473b004bd43a6f93095f932ded1ce5585790f Mon Sep 17 00:00:00 2001 From: trudy Date: Tue, 21 Sep 2021 09:20:11 -0700 Subject: [PATCH 09/12] more ipv6 friendly --- VpnHood.Tunneling/PacketUtil.cs | 55 +++++++++++++++++++++++++++------ VpnHood.Tunneling/PingProxy.cs | 3 +- VpnHood.Tunneling/Tunnel.cs | 12 +++---- VpnHood.Tunneling/UdpProxy.cs | 7 ++--- VpnHood.ZTest/Tests/NatTest.cs | 6 ++-- 5 files changed, 56 insertions(+), 27 deletions(-) diff --git a/VpnHood.Tunneling/PacketUtil.cs b/VpnHood.Tunneling/PacketUtil.cs index 2d2b7a13d..26f2789e0 100644 --- a/VpnHood.Tunneling/PacketUtil.cs +++ b/VpnHood.Tunneling/PacketUtil.cs @@ -2,10 +2,12 @@ using System.Collections.Generic; using System.IO; using System.Net; +using System.Net.Sockets; using Microsoft.Extensions.Logging; using PacketDotNet; using PacketDotNet.Utils; using VpnHood.Common.Logging; +using ProtocolType = PacketDotNet.ProtocolType; namespace VpnHood.Tunneling { @@ -81,17 +83,28 @@ public static IPPacket CreateTcpResetReply(IPPacket ipPacket, bool updatePacket resetTcpPacket.SequenceNumber = tcpPacketOrg.AcknowledgmentNumber; } - IPv4Packet resetIpPacket = new(ipPacket.DestinationAddress, ipPacket.SourceAddress) - { - Protocol = ProtocolType.Tcp, - PayloadPacket = resetTcpPacket - }; + var resetIpPacket = CreateIpPacket(ipPacket.DestinationAddress, ipPacket.SourceAddress); + resetIpPacket.Protocol = ProtocolType.Tcp; + resetIpPacket.PayloadPacket = resetTcpPacket; if (updatePacket) UpdateIpPacket(resetIpPacket); return resetIpPacket; } + public static IPPacket CreateIpPacket(IPAddress sourceAddress, IPAddress destinationAddress) + { + if (sourceAddress.AddressFamily != destinationAddress.AddressFamily) + throw new InvalidOperationException($"{nameof(sourceAddress)} and {nameof(destinationAddress)} address family must be same!"); + + return sourceAddress.AddressFamily switch + { + AddressFamily.InterNetwork => new IPv4Packet(sourceAddress, destinationAddress), + AddressFamily.InterNetworkV6 => new IPv6Packet(sourceAddress, destinationAddress), + _ => throw new NotSupportedException($"{sourceAddress.AddressFamily} is not supported!") + }; + } + public static IcmpV4Packet ExtractIcmp(IPPacket ipPacket) { return ipPacket.Extract() ?? @@ -110,6 +123,29 @@ public static TcpPacket ExtractTcp(IPPacket ipPacket) throw new InvalidDataException($"Invalid {ipPacket.Protocol} packet!"); } + public static IPPacket CreateUnreachableReplyV6(IPPacket ipPacket, IcmpV4TypeCode typeCode, ushort mtu = 0) + { + if (ipPacket is null) throw new ArgumentNullException(nameof(ipPacket)); + + var icmpDataLen = Math.Min(ipPacket.TotalLength, 20 + 8); + var byteArraySegment = new ByteArraySegment(new byte[16 + icmpDataLen]); + var icmpPacket = new IcmpV6Packet(byteArraySegment, ipPacket) + { + Type = IcmpV6Type.PacketTooBig, + + Code = 0 + }; + + icmpPacket.UpdateCalculatedValues(); + + var newIpPacket = new IPv6Packet(ipPacket.DestinationAddress, ipPacket.SourceAddress) + { + PayloadPacket = icmpPacket + }; + UpdateIpPacket(newIpPacket); + throw new NotImplementedException("Not implemented!"); + } + public static IPPacket CreateUnreachableReply(IPPacket ipPacket, IcmpV4TypeCode typeCode, ushort sequence = 0) { if (ipPacket is null) throw new ArgumentNullException(nameof(ipPacket)); @@ -117,19 +153,18 @@ public static IPPacket CreateUnreachableReply(IPPacket ipPacket, IcmpV4TypeCode // packet is too big var icmpDataLen = Math.Min(ipPacket.TotalLength, 20 + 8); var byteArraySegment = new ByteArraySegment(new byte[16 + icmpDataLen]); - var icmpV4Packet = new IcmpV4Packet(byteArraySegment, ipPacket) + var icmpPacket = new IcmpV4Packet(byteArraySegment, ipPacket) { TypeCode = typeCode, PayloadData = ipPacket.Bytes[..icmpDataLen], Sequence = sequence }; - icmpV4Packet.Checksum = - (ushort)ChecksumUtils.OnesComplementSum(icmpV4Packet.Bytes, 0, icmpV4Packet.Bytes.Length); - icmpV4Packet.UpdateCalculatedValues(); + icmpPacket.Checksum = (ushort)ChecksumUtils.OnesComplementSum(icmpPacket.Bytes, 0, icmpPacket.Bytes.Length); + icmpPacket.UpdateCalculatedValues(); var newIpPacket = new IPv4Packet(ipPacket.DestinationAddress, ipPacket.SourceAddress) { - PayloadPacket = icmpV4Packet, + PayloadPacket = icmpPacket, FragmentFlags = 0 }; UpdateIpPacket(newIpPacket); diff --git a/VpnHood.Tunneling/PingProxy.cs b/VpnHood.Tunneling/PingProxy.cs index 226bd09df..7a75a29d4 100644 --- a/VpnHood.Tunneling/PingProxy.cs +++ b/VpnHood.Tunneling/PingProxy.cs @@ -80,8 +80,7 @@ public void Send(IPPacket ipPacket) // We should not use Task due its stack usage, this method is called by many session each many times! var icmpPacket = PacketUtil.ExtractIcmp(ipPacket); - var noFragment = ipPacket is IPv4Packet ipV4Packet && (ipV4Packet.FragmentFlags & 0x2) != 0 || - ipPacket is IPv6Packet; + var noFragment = ipPacket is IPv4Packet ipV4Packet && (ipV4Packet.FragmentFlags & 0x2) != 0 || ipPacket is IPv6Packet; var pingOptions = new PingOptions(ipPacket.TimeToLive - 1, noFragment); _ping.SendAsync(ipPacket.DestinationAddress, _timeout, icmpPacket.Data, pingOptions, ipPacket); diff --git a/VpnHood.Tunneling/Tunnel.cs b/VpnHood.Tunneling/Tunnel.cs index 6bef073b8..dadae03fa 100644 --- a/VpnHood.Tunneling/Tunnel.cs +++ b/VpnHood.Tunneling/Tunnel.cs @@ -328,8 +328,7 @@ private async Task SendPacketTask(IDatagramChannel channel) // drop packet if it is larger than _mtuWithFragment if (packetSize > _mtuWithFragment) { - VhLogger.Instance.LogWarning( - $"Packet dropped! There is no channel to support this fragmented packet. Fragmented MTU: {_mtuWithFragment}, PacketLength: {ipPacket.TotalLength}, Packet: {ipPacket}"); + VhLogger.Instance.LogWarning($"Packet dropped! There is no channel to support this fragmented packet. Fragmented MTU: {_mtuWithFragment}, PacketLength: {ipPacket.TotalLength}, Packet: {ipPacket}"); _packetQueue.TryDequeue(out ipPacket); continue; } @@ -337,13 +336,10 @@ private async Task SendPacketTask(IDatagramChannel channel) // drop packet if it is larger than _mtuNoFragment if (packetSize > _mtuNoFragment && ipPacket is IPv4Packet {FragmentFlags: 2}) { - VhLogger.Instance.LogWarning( - $"Packet dropped! There is no channel to support this non fragmented packet. NoFragmented MTU: {_mtuNoFragment}, PacketLength: {ipPacket.TotalLength}, Packet: {ipPacket}"); + VhLogger.Instance.LogWarning($"Packet dropped! There is no channel to support this non fragmented packet. NoFragmented MTU: {_mtuNoFragment}, PacketLength: {ipPacket.TotalLength}, Packet: {ipPacket}"); _packetQueue.TryDequeue(out ipPacket); - var replyPacket = PacketUtil.CreateUnreachableReply(ipPacket, - IcmpV4TypeCode.UnreachableFragmentationNeeded, (ushort) _mtuNoFragment); - OnPacketReceived?.Invoke(this, - new ChannelPacketReceivedEventArgs(new[] {replyPacket}, channel)); + var replyPacket = PacketUtil.CreateUnreachableReply(ipPacket, IcmpV4TypeCode.UnreachableFragmentationNeeded, (ushort) _mtuNoFragment); + OnPacketReceived?.Invoke(this, new ChannelPacketReceivedEventArgs(new[] {replyPacket}, channel)); continue; } diff --git a/VpnHood.Tunneling/UdpProxy.cs b/VpnHood.Tunneling/UdpProxy.cs index 06b44579f..57f9bf5c1 100644 --- a/VpnHood.Tunneling/UdpProxy.cs +++ b/VpnHood.Tunneling/UdpProxy.cs @@ -48,8 +48,7 @@ public void Dispose() private async Task ReceiveUdpTask() { - var udpClient = _udpClient; - var localEndPoint = (IPEndPoint)udpClient.Client.LocalEndPoint; + var localEndPoint = (IPEndPoint)_udpClient.Client.LocalEndPoint; using var _ = VhLogger.Instance.BeginScope($"UdpProxy LocalEp: {localEndPoint}"); VhLogger.Instance.Log(LogLevel.Information, GeneralEventId.Udp, "Start listening..."); @@ -58,10 +57,10 @@ private async Task ReceiveUdpTask() try { //receiving packet - var udpResult = await udpClient.ReceiveAsync(); + var udpResult = await _udpClient.ReceiveAsync(); // forward packet - var ipPacket = new IPv4Packet(udpResult.RemoteEndPoint.Address, _sourceEndPoint.Address); + var ipPacket = PacketUtil.CreateIpPacket(udpResult.RemoteEndPoint.Address, _sourceEndPoint.Address); var udpPacket = new UdpPacket((ushort)udpResult.RemoteEndPoint.Port, (ushort)_sourceEndPoint.Port) { PayloadData = udpResult.Buffer diff --git a/VpnHood.ZTest/Tests/NatTest.cs b/VpnHood.ZTest/Tests/NatTest.cs index 2d22888e0..aedd8366a 100644 --- a/VpnHood.ZTest/Tests/NatTest.cs +++ b/VpnHood.ZTest/Tests/NatTest.cs @@ -23,7 +23,7 @@ public static void AssemblyCleanup() [TestMethod] public void Nat_NatItem_Test() { - var ipPacket = new IPv4Packet(IPAddress.Parse("10.1.1.1"), IPAddress.Parse("10.1.1.2")); + var ipPacket = PacketUtil.CreateIpPacket(IPAddress.Parse("10.1.1.1"), IPAddress.Parse("10.1.1.2")); var tcpPacket = new TcpPacket(100, 100); ipPacket.PayloadPacket = tcpPacket; @@ -60,7 +60,7 @@ public void Nat_NatItem_Test() [TestMethod] public void Nat_NatItemEx_Test() { - var ipPacket = new IPv4Packet(IPAddress.Parse("10.1.1.1"), IPAddress.Parse("10.1.1.2")); + var ipPacket = PacketUtil.CreateIpPacket(IPAddress.Parse("10.1.1.1"), IPAddress.Parse("10.1.1.2")); var tcpPacket = new TcpPacket(100, 100); ipPacket.PayloadPacket = tcpPacket; @@ -101,7 +101,7 @@ public void Nat_NatItemEx_Test() [TestMethod] public void Nat_OverFlow_Test() { - var ipPacket = new IPv4Packet(IPAddress.Parse("10.1.1.1"), IPAddress.Parse("10.1.1.2")); + var ipPacket = PacketUtil.CreateIpPacket(IPAddress.Parse("10.1.1.1"), IPAddress.Parse("10.1.1.2")); var tcpPacket = new TcpPacket(100, 100); ipPacket.PayloadPacket = tcpPacket; From 06b154c81920dd8b623c7a1d6226608954e11f50 Mon Sep 17 00:00:00 2001 From: trudy Date: Tue, 21 Sep 2021 16:05:40 -0700 Subject: [PATCH 10/12] fix android 5.1 --- CHANGELOG.md | 3 ++ VpnHood.Client.App.Android/AndroidApp.cs | 8 +++- VpnHood.Client.App.Android/MainActivity.cs | 25 +++++++++--- .../mipmap-ldpi/ic_launcher_foreground.png | Bin 0 -> 2817 bytes .../mipmap-ldpi/ic_launcher_round.png | Bin 0 -> 3229 bytes .../Resources/mipmap-ldpi/ic_notification.png | Bin 0 -> 1750 bytes .../VpnHood.Client.App.Android.csproj | 12 +++++- VpnHood.Client.App/ClientProfileStore.cs | 30 +++++++------- VpnHood.Client.App/VpnHoodApp.cs | 4 +- .../AppVpnService.cs | 34 ++++++++++------ VpnHood.Client.Device/IPNetwork.cs | 37 ++++++++++++++++++ VpnHood.Client/Diagnosing/DiagnoseUtil.cs | 2 +- VpnHood.Client/TcpProxyHost.cs | 5 +-- VpnHood.Client/VpnHoodClient.cs | 20 +++++----- VpnHood.Common/Util.cs | 9 +++-- VpnHood.Server/TcpHost.cs | 6 +-- VpnHood.Tunneling/PacketUtil.cs | 37 +++++++++--------- VpnHood.ZTest/Tests/ClientAppTest.cs | 4 +- 18 files changed, 157 insertions(+), 79 deletions(-) create mode 100644 VpnHood.Client.App.Android/Resources/mipmap-ldpi/ic_launcher_foreground.png create mode 100644 VpnHood.Client.App.Android/Resources/mipmap-ldpi/ic_launcher_round.png create mode 100644 VpnHood.Client.App.Android/Resources/mipmap-ldpi/ic_notification.png diff --git a/CHANGELOG.md b/CHANGELOG.md index 957c72563..b14270632 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ # Upcoming +* Fix: Android: Closing VpnService +* Fix: Android: Crash in android 5.1 * Fix: IpFilter miss some IPs of countries +* Improve: Connect speed # v2.0.271 ### Client diff --git a/VpnHood.Client.App.Android/AndroidApp.cs b/VpnHood.Client.App.Android/AndroidApp.cs index b981420ab..385b51b8f 100644 --- a/VpnHood.Client.App.Android/AndroidApp.cs +++ b/VpnHood.Client.App.Android/AndroidApp.cs @@ -34,10 +34,10 @@ public AndroidApp(IntPtr javaReference, JniHandleOwnership transfer) } - private readonly object stateLock = new(); + private readonly object _stateLock = new(); private void UpdateNotification() { - lock (stateLock) + lock (_stateLock) { if (_notifyBuilder == null) return; // _notifyBuilder has not been initialized yet @@ -143,6 +143,10 @@ private void InitNotification() #pragma warning restore CS0618 // Type or member is obsolete } + // for android 5.1 (no subtext will be shown if we don't call SetContentText) + if (Build.VERSION.SdkInt < BuildVersionCodes.N) + _notifyBuilder.SetContentText(Resources?.GetString(Resource.String.app_name) ?? "VpnHood!"); + _notifyBuilder.SetVisibility(NotificationVisibility.Secret); //VPN icon is already showed by the system _notifyBuilder.SetContentIntent(pendingOpenIntent); _notifyBuilder.AddAction(new Notification.Action(0, Resources?.GetText(Resource.String.disconnect) ?? "Disconnect", CreatePendingIntent("disconnect"))); diff --git a/VpnHood.Client.App.Android/MainActivity.cs b/VpnHood.Client.App.Android/MainActivity.cs index 81866b6c4..9a4d3ef58 100644 --- a/VpnHood.Client.App.Android/MainActivity.cs +++ b/VpnHood.Client.App.Android/MainActivity.cs @@ -29,11 +29,22 @@ public class MainActivity : Activity private const int RequestVpnPermission = 10; private VpnHoodAppUi? _appUi; - private AndroidDevice Device => (AndroidDevice?) AndroidApp.Current?.Device ?? - throw new InvalidOperationException($"{nameof(Device)} is not initialized!"); + private AndroidDevice Device => + (AndroidDevice?)AndroidApp.Current?.Device ?? throw new InvalidOperationException($"{nameof(Device)} is not initialized!"); public WebView? WebView { get; private set; } - public Color BackgroundColor => Resources?.GetColor(Resource.Color.colorBackground, null) ?? Color.DarkBlue; + public Color BackgroundColor + { + get + { + if (Build.VERSION.SdkInt >= BuildVersionCodes.M) + return Resources?.GetColor(Resource.Color.colorBackground, Theme) ?? Color.DarkBlue; + +#pragma warning disable 618 + return Resources?.GetColor(Resource.Color.colorBackground) ?? Color.DarkBlue; +#pragma warning restore 618 + } + } protected override void OnCreate(Bundle? savedInstanceState) { @@ -44,10 +55,12 @@ protected override void OnCreate(Bundle? savedInstanceState) // manage VpnPermission Device.OnRequestVpnPermission += Device_OnRequestVpnPermission; + + //var item = VpnHoodApp.Instance.ClientProfileStore.ClientProfileItems[0]; //todo + //VpnHoodApp.Instance.Connect(item.Id); //todo // Initialize UI - var zipStream = Resources?.Assets?.Open("SPA.zip") ?? - throw new Exception("Could not load SPA.zip resource!"); + var zipStream = Resources?.Assets?.Open("SPA.zip") ?? throw new Exception("Could not load SPA.zip resource!"); _appUi = VpnHoodAppUi.Init(zipStream); InitWebUi(); } @@ -90,7 +103,7 @@ private void InitSplashScreen() imageView.SetImageResource(Resource.Mipmap.ic_launcher_round); imageView.LayoutParameters = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MatchParent, ViewGroup.LayoutParams.MatchParent); imageView.SetScaleType(ImageView.ScaleType.CenterInside); - //imageView.SetBackgroundColor(Color); + imageView.SetBackgroundColor(BackgroundColor); SetContentView(imageView); } diff --git a/VpnHood.Client.App.Android/Resources/mipmap-ldpi/ic_launcher_foreground.png b/VpnHood.Client.App.Android/Resources/mipmap-ldpi/ic_launcher_foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..9fb99a04b4f0876cef9069bdfa169b93a6e170b0 GIT binary patch literal 2817 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 TKh(Q>00000NkvXXu0mjfU71gC literal 0 HcmV?d00001 diff --git a/VpnHood.Client.App.Android/Resources/mipmap-ldpi/ic_launcher_round.png b/VpnHood.Client.App.Android/Resources/mipmap-ldpi/ic_launcher_round.png new file mode 100644 index 0000000000000000000000000000000000000000..34d0c41130f5266eeb6bd8128884658f02b7a658 GIT binary patch literal 3229 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 P00000NkvXXu0mjfJHSJi literal 0 HcmV?d00001 diff --git a/VpnHood.Client.App.Android/Resources/mipmap-ldpi/ic_notification.png b/VpnHood.Client.App.Android/Resources/mipmap-ldpi/ic_notification.png new file mode 100644 index 0000000000000000000000000000000000000000..c52e0e94384c9b51e86b52942165a82867a468c6 GIT binary patch literal 1750 zcmV;{1}XW8P)U0={&x!x!uqE-tY6g?;pxtZ_oGL&vl*Gd7R5}p6B%}z;FCnU=H8 z7iY}{0A;FtS7G1%RDZLEWwrsdmfisP8?ZcZ25@g_J*(cBO#ll6-vdhlrvXO-i!`Rb z88{YrcQ!+6wgAMcn*sj-)-A;iqnu#~eE=K^+*)BaaY#)H!2SN2sD}WTmeuuy9%-NU z-Fd)C^`*evKh`q|fL8g7fuk!y!#aHm`JGnRW48c%1K*T4#sV=efGDpr|1L$eu!;?l z`CWPHAz&Bai*Z2=Ijn2RmL_imb_b%+Ou`_09s_m&zHGvAu$-9!aJ^R6+W!Lf8B_Tv z7!daZJ2fGwX9qnq1rVyd061EGgdwVc|QyKN4^P2;YH1s!g|8$CIZLO}6{tVnXwAc+%AWhk_!1KT#inrTlO$t<&iugX?brtW1 zM$1~E(a(Slfp>-^^$-9Fojb}pZ9!5YmFQEn`(6e6fVJ-wZ^2?v#lXwpyPoHrwgU20Hpm@DV4NI zi$Xc@-0C>LZCv0Q+k~@AF|8-)zt+3fTPu}ewrz~#dW|E++R?r?RVYmbAl6UlMCn*a z8oj85yVir#7pcHsfGbPeQ-HIYN}XI$Nx|I){HgIo&azT(GnE%c0f_Pzm%DoeUk)7B zG;VE-DpRFY?uzP6w;r+9a|F8>@Hnth&sm0~6~A|m=mU^2v6p`VShJa=6!IdlNgbT# ztgqcrjxv_4n0HNIGDfl0ishDQT5V;>Mz-f)^-Xkr0Kz)L|4Rd});O4?aw$+m`c#J$nN_bSR0tvBx}Mg;W0!}*Y@oT0E?I&PS+bRI9EHW{-5z$ z0Qt8usP$K9xl8)* z;)NU(*KGkfA*DHUkpk8O{@2i(-&>ufH)mRTJdf_T_3%l9mIm*-YBjPpd!Mb=A_cMa zLS$#wb_BgEUg!dlWjs8+xYl>En*uVQ78rY=#G`vWShw2?sZ<&|Eov)nv9j$*vCH|p z0=M^^p;z`TeUjAo06S-G*uaCO&es9sI`=hNZhPQ?&UImuPC>Q_R?u{shTx7(T*unp z(0My&f8!%4*~S6pzRpme3T?PpOk)W3{kn>)1#ZDuLhIR!I7s9&N`(v?!^ar!CTPn- zhLVk$w+sJmteic`fyIGM0h#VC;FTtMyVol5w5^OSO&b+Q)g9ErEdX!S44+)e8a@^+ z!^$`m#Hd5Mbu0?E@B7~Q{V3`+6b-laf#(_zsh4@WRXh+OCgti)0&8I}pDf|_KR#~m z8@R&~N!(F%nmA70^j&7Plb$qtM1`qmr{gt@tjzP0L{>jh_B}3^J-msK>!-5X2oZx{ zw^de>I2BlH#BOQ)>Hx4v?NPC55?$ety6G@kv*rIpX2#bw%ui4{Gr?xZey<{MTKU`JW zVgFZ80QlJs;VRTs%G(GpV^08Wk!WmXjtz$w#w@VmBrl?qo#G~C5EX0bPtZe@Uhj|UtQj= z>lQiPHA6fR enable - 9.0 + 9.0 true @@ -102,7 +102,9 @@ - + + + {18d028c5-3056-457f-9286-f469bee59bbe} @@ -259,5 +261,11 @@ MSBuild:UpdateGeneratedFiles + + + + + + \ No newline at end of file diff --git a/VpnHood.Client.App/ClientProfileStore.cs b/VpnHood.Client.App/ClientProfileStore.cs index 7e1e0b9c4..0039a260a 100644 --- a/VpnHood.Client.App/ClientProfileStore.cs +++ b/VpnHood.Client.App/ClientProfileStore.cs @@ -50,12 +50,12 @@ public ClientProfileItem[] ClientProfileItems } } - public Token GetToken(Guid tokenId, bool autoUpdate = false) + public Token GetToken(Guid tokenId) { - return GetToken(tokenId, false, autoUpdate); + return GetToken(tokenId, false); } - internal Token GetToken(Guid tokenId, bool withSecret, bool autoUpdate) + internal Token GetToken(Guid tokenId, bool withSecret) { var token = _tokens.FirstOrDefault(x => x.TokenId == tokenId); if (token == null) throw new KeyNotFoundException($"{nameof(tokenId)} does not exists. TokenId {tokenId}"); @@ -63,31 +63,33 @@ internal Token GetToken(Guid tokenId, bool withSecret, bool autoUpdate) // clone token token = (Token) token.Clone(); - // update token - if (token.Url != null && autoUpdate) - token = UpdateTokenFromUrl(token).Result; - if (!withSecret) token.Secret = Array.Empty(); return token; } - private async Task UpdateTokenFromUrl(Token token) + public async Task UpdateTokenFromUrl(Token token) { + if (string.IsNullOrEmpty(token.Url)) + return token; + // update token VhLogger.Instance.LogInformation($"Trying to get new token from token url, Url: {token.Url}"); try { using var client = new HttpClient(); - var accessKey = await client.GetStringAsync(token.Url); - AddAccessKey(accessKey); //update store - token = Token.FromAccessKey(accessKey); - VhLogger.Instance.LogInformation( - $"Updated TokenId: {VhLogger.FormatId(token.TokenId)}, SupportId: {VhLogger.FormatId(token.SupportId)}"); + var accessKey = await Util.RunTask(client.GetStringAsync(token.Url), TimeSpan.FromSeconds(20)); + var newToken = Token.FromAccessKey(accessKey); + if (newToken.TokenId != token.TokenId) + throw new InvalidOperationException($"Could not updated Token because {nameof(token.TokenId)} has been changed! TokenId: {VhLogger.FormatId(token.TokenId)}"); + + //update store + AddAccessKey(accessKey); + VhLogger.Instance.LogInformation($"Updated TokenId: {VhLogger.FormatId(token.TokenId)}, SupportId: {VhLogger.FormatId(token.SupportId)}"); } catch (Exception ex) { - VhLogger.Instance.LogInformation($"Could not update token from token url, Error: {ex.Message}"); + VhLogger.Instance.LogError($"Could not update token from token url, Error: {ex.Message}"); } return token; diff --git a/VpnHood.Client.App/VpnHoodApp.cs b/VpnHood.Client.App/VpnHoodApp.cs index fc336ac1c..c6990a200 100644 --- a/VpnHood.Client.App/VpnHoodApp.cs +++ b/VpnHood.Client.App/VpnHoodApp.cs @@ -340,7 +340,9 @@ private async Task ConnectInternal(IPacketCapture packetCapture, Guid tokenId, s VhLogger.Instance.LogInformation($"UserAgent: {userAgent}"); // get token - var token = ClientProfileStore.GetToken(tokenId, true, true); + var token = ClientProfileStore.GetToken(tokenId, true); + _ = ClientProfileStore.UpdateTokenFromUrl(token); + VhLogger.Instance.LogInformation($"TokenId: {VhLogger.FormatId(token.TokenId)}, SupportId: {VhLogger.FormatId(token.SupportId)}"); // Create Client diff --git a/VpnHood.Client.Device.Android/AppVpnService.cs b/VpnHood.Client.Device.Android/AppVpnService.cs index b36794879..0427c040d 100644 --- a/VpnHood.Client.Device.Android/AppVpnService.cs +++ b/VpnHood.Client.Device.Android/AppVpnService.cs @@ -15,15 +15,16 @@ using PacketDotNet; using VpnHood.Common; using VpnHood.Common.Logging; +using Exception = System.Exception; namespace VpnHood.Client.Device.Android { [Service(Label = VpnServiceName, Permission = Manifest.Permission.BindVpnService)] - [IntentFilter(new[] {"android.net.VpnService"})] + [IntentFilter(new[] { "android.net.VpnService" })] internal class AppVpnService : VpnService, IPacketCapture { public const string VpnServiceName = "VpnHood"; - private IPAddress[]? _dnsServers = {IPAddress.Parse("8.8.8.8"), IPAddress.Parse("8.8.4.4")}; + private IPAddress[]? _dnsServers = { IPAddress.Parse("8.8.8.8"), IPAddress.Parse("8.8.4.4") }; private FileInputStream? _inStream; // Packets to be sent are queued in this input stream. private ParcelFileDescriptor? _mInterface; private int _mtu; @@ -68,10 +69,11 @@ public void StartCapture() var builder = new Builder(this) .SetBlocking(true) .SetSession(VpnServiceName) - .AddAddress("192.168.0.100", 24); + .AddAddress("192.168.0.100", 24) + .AddAddress("fe80::64", 120); // dnsServers - if (DnsServers is {Length: > 0}) + if (DnsServers is { Length: > 0 }) foreach (var dnsServer in DnsServers) builder.AddDnsServer(dnsServer.ToString()); else @@ -234,7 +236,7 @@ protected virtual void ProcessPacket(IPPacket ipPacket) { try { - OnPacketReceivedFromInbound?.Invoke(this, new PacketReceivedEventArgs(new[] {ipPacket}, this)); + OnPacketReceivedFromInbound?.Invoke(this, new PacketReceivedEventArgs(new[] { ipPacket }, this)); } catch (Exception ex) { @@ -257,13 +259,23 @@ private void Close() return; VhLogger.Instance.LogTrace("Closing VpnService..."); - StopSelf(); - _inStream?.Dispose(); - _outStream?.Dispose(); - _mInterface?.Close(); //required to close the vpn. dispose is not enough - _mInterface?.Dispose(); - _mInterface = null; + try + { + _inStream?.Dispose(); + _outStream?.Dispose(); + _mInterface?.Close(); //required to close the vpn. dispose is not enough + _mInterface?.Dispose(); + _mInterface = null; + + } + catch (Exception ex) + { + VhLogger.Instance.LogError(ex, "Error while closing the VpnService!"); + } + + // it must be after _mInterface.Close + StopSelf(); } #region Application Filter diff --git a/VpnHood.Client.Device/IPNetwork.cs b/VpnHood.Client.Device/IPNetwork.cs index 2c41162d3..f005a8447 100644 --- a/VpnHood.Client.Device/IPNetwork.cs +++ b/VpnHood.Client.Device/IPNetwork.cs @@ -51,12 +51,49 @@ public IpNetwork(IPAddress prefix, int prefixLength = 32) public static IpNetwork AllV4 { get; } = Parse("0.0.0.0/0"); public static IpNetwork AllV6 { get; } = Parse("::/0"); + public static IpNetwork AllGlobalUnicastV6 { get; } = Parse("2000::/3"); public static IEnumerable FromIpRange(IpRange ipRange) { return FromIpRange(ipRange.FirstIpAddress, ipRange.LastIpAddress); } + private static long Mask(int s) + { + return (long)(Math.Pow(2, 32) - Math.Pow(2, 32 - s)); + } + + public static IpNetwork[] FromIpRangeOld(IPAddress firstIpAddress, IPAddress lastIpAddress) + { + var firstIpAddressLong = IPAddressUtil.ToLong(firstIpAddress); + var lastIpAddressLong = IPAddressUtil.ToLong(lastIpAddress); + + var result = new List(); + while (lastIpAddressLong >= firstIpAddressLong) + { + byte maxSize = 32; + while (maxSize > 0) + { + var mask = Mask(maxSize - 1); + var maskBase = firstIpAddressLong & mask; + + if (maskBase != firstIpAddressLong) + break; + + maxSize--; + } + + var x = Math.Log(lastIpAddressLong - firstIpAddressLong + 1) / Math.Log(2); + var maxDiff = (byte)(32 - Math.Floor(x)); + if (maxSize < maxDiff) maxSize = maxDiff; + var ipAddress = IPAddressUtil.FromLong(firstIpAddressLong); + result.Add(new IpNetwork(ipAddress, maxSize)); + firstIpAddressLong += (long)Math.Pow(2, 32 - maxSize); + } + + return result.ToArray(); + } + public static IEnumerable FromIpRange(IPAddress firstIpAddress, IPAddress lastIpAddress) { if (firstIpAddress.AddressFamily != lastIpAddress.AddressFamily) diff --git a/VpnHood.Client/Diagnosing/DiagnoseUtil.cs b/VpnHood.Client/Diagnosing/DiagnoseUtil.cs index 272f487d3..f32e7bfff 100644 --- a/VpnHood.Client/Diagnosing/DiagnoseUtil.cs +++ b/VpnHood.Client/Diagnosing/DiagnoseUtil.cs @@ -167,7 +167,7 @@ public static async Task GetHostEntry(string host, IPEndPoint dnsEn udpClient.Client.SendTimeout = timeout; udpClient.Client.ReceiveTimeout = timeout; await udpClient.SendAsync(buffer, buffer.Length, dnsEndPoint); - var receiveTask = await Util.RunTask(udpClient.ReceiveAsync(), timeout); + var receiveTask = await Util.RunTask(udpClient.ReceiveAsync(), TimeSpan.FromMilliseconds(timeout)); buffer = receiveTask.Buffer; //The response message has the same header and question structure, so we move index to the answer part directly. diff --git a/VpnHood.Client/TcpProxyHost.cs b/VpnHood.Client/TcpProxyHost.cs index e62db20af..07955af6a 100644 --- a/VpnHood.Client/TcpProxyHost.cs +++ b/VpnHood.Client/TcpProxyHost.cs @@ -52,14 +52,13 @@ public async Task StartListening() try { - VhLogger.Instance.LogInformation( - $"Start listening on {VhLogger.Format(_tcpListener.LocalEndpoint)}..."); + VhLogger.Instance.LogInformation($"Start listening on {VhLogger.Format(_tcpListener.LocalEndpoint)}..."); _tcpListener.Start(); _localEndpoint = (IPEndPoint)_tcpListener.LocalEndpoint; //it is slow; make sure to cache it while (!cancellationToken.IsCancellationRequested) { - var tcpClient = await Util.RunTask(_tcpListener.AcceptTcpClientAsync(), 0, cancellationToken); + var tcpClient = await Util.RunTask(_tcpListener.AcceptTcpClientAsync(), default, cancellationToken); _ = ProcessClient(tcpClient, cancellationToken); } } diff --git a/VpnHood.Client/VpnHoodClient.cs b/VpnHood.Client/VpnHoodClient.cs index d7bd6812c..5d8bd5957 100644 --- a/VpnHood.Client/VpnHoodClient.cs +++ b/VpnHood.Client/VpnHoodClient.cs @@ -171,8 +171,7 @@ public async Task Connect() // report config ThreadPool.GetMinThreads(out var workerThreads, out var completionPortThreads); - VhLogger.Instance.LogInformation( - $"MinWorkerThreads: {workerThreads}, CompletionPortThreads: {completionPortThreads}"); + VhLogger.Instance.LogInformation($"MinWorkerThreads: {workerThreads}, CompletionPortThreads: {completionPortThreads}"); // Replace dot in version to prevent anonymous make treat it as ip. VhLogger.Instance.LogInformation($"Client is connecting. Version: {Version}"); @@ -224,8 +223,7 @@ private void ConfigPacketFilter(IPEndPoint hostEndPoint) if (PacketCaptureIncludeIpRanges?.Length > 0) { if (PacketCaptureIncludeIpRanges.Any(x => x.IsInRange(hostEndPoint.Address))) - throw new InvalidOperationException( - $"ServerIp can not be part of {nameof(PacketCaptureIncludeIpRanges)}! ServerIp: {hostEndPoint.Address}"); + throw new InvalidOperationException($"ServerIp can not be part of {nameof(PacketCaptureIncludeIpRanges)}! ServerIp: {hostEndPoint.Address}"); includeNetworks.AddRange(IpNetwork.FromIpRange(PacketCaptureIncludeIpRanges)); } else @@ -242,16 +240,18 @@ private void ConfigPacketFilter(IPEndPoint hostEndPoint) // convert excludeNetworks into includeNetworks if (excludeNetworks.Count > 0) - includeNetworks.AddRange(IpNetwork.Invert(excludeNetworks, true, true)); + includeNetworks.AddRange(IpNetwork.Invert(excludeNetworks, true, false)); } - // finalize + // block IP6 + includeNetworks.Add(ExcludeLocalNetwork ? IpNetwork.AllGlobalUnicastV6 : IpNetwork.AllV6); + + // make sure ProxyLoopback exists in include includeNetworks.Add(includeNetworks.Count == 0 - ? IpNetwork.Parse("0.0.0.0/0") + ? IpNetwork.AllV4 : new IpNetwork(TcpProxyLoopbackAddress)); - VhLogger.Instance.LogInformation( - $"PacketCapture Include Networks: {string.Join(", ", includeNetworks.Select(x => x.ToString()))}"); + VhLogger.Instance.LogInformation($"PacketCapture Include Networks: {string.Join(", ", includeNetworks.Select(x => x.ToString()))}"); _packetCapture.IncludeNetworks = includeNetworks.ToArray(); } @@ -525,7 +525,7 @@ internal async Task GetSslConnectionToServer(EventId eventId, // Client.Timeout does not affect in ConnectAsync VhLogger.Instance.LogTrace(eventId, $"Connecting to Server: {VhLogger.Format(HostEndPoint)}..."); - await Util.RunTask(tcpClient.ConnectAsync(HostEndPoint.Address, HostEndPoint.Port), (int)Timeout.TotalMilliseconds, cancellationToken); + await Util.RunTask(tcpClient.ConnectAsync(HostEndPoint.Address, HostEndPoint.Port), Timeout, cancellationToken); // start TLS var stream = new SslStream(tcpClient.GetStream(), true, UserCertificateValidationCallback); diff --git a/VpnHood.Common/Util.cs b/VpnHood.Common/Util.cs index 3522d5956..c45d3437d 100644 --- a/VpnHood.Common/Util.cs +++ b/VpnHood.Common/Util.cs @@ -105,16 +105,17 @@ public static void DirectoryCopy(string sourcePath, string destinationPath, bool } } - public static async Task RunTask(Task task, int timeout = 0, CancellationToken cancellationToken = default) + public static async Task RunTask(Task task, TimeSpan timeout = default, CancellationToken cancellationToken = default) { await RunTask((Task)task, timeout, cancellationToken); return await task; } - public static async Task RunTask(Task task, int timeout = 0, CancellationToken cancellationToken = default) + public static async Task RunTask(Task task, TimeSpan timeout = default, CancellationToken cancellationToken = default) { - if (timeout == 0) timeout = -1; - + if (timeout == TimeSpan.Zero) + timeout = TimeSpan.FromMilliseconds(-1); + var timeoutTask = Task.Delay(timeout, cancellationToken); await Task.WhenAny(task, timeoutTask); diff --git a/VpnHood.Server/TcpHost.cs b/VpnHood.Server/TcpHost.cs index b67f6ea80..acf7f28f5 100644 --- a/VpnHood.Server/TcpHost.cs +++ b/VpnHood.Server/TcpHost.cs @@ -19,7 +19,7 @@ namespace VpnHood.Server internal class TcpHost : IDisposable { private const int ServerProtocolVersion = 2; - private const int RemoteHostTimeout = 60000; + private readonly TimeSpan _remoteHostTimeout = TimeSpan.FromSeconds(60); private readonly CancellationTokenSource _cancellationTokenSource = new(); private readonly SessionManager _sessionManager; private readonly SocketFactory _socketFactory; @@ -83,7 +83,7 @@ private async Task ListenThread() tcpClient.NoDelay = true; // create cancellation token - using var timeoutCt = new CancellationTokenSource(RemoteHostTimeout); + using var timeoutCt = new CancellationTokenSource(_remoteHostTimeout); using var cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(timeoutCt.Token, _cancellationTokenSource.Token); @@ -310,7 +310,7 @@ private async Task ProcessTcpProxyChannel(TcpClientStream tcpClientStream, Cance isRequestedEpException = true; await Util.RunTask(tcpClient2.ConnectAsync(request.DestinationEndPoint.Address, request.DestinationEndPoint.Port), - RemoteHostTimeout, cancellationToken); + _remoteHostTimeout, cancellationToken); isRequestedEpException = false; // send response diff --git a/VpnHood.Tunneling/PacketUtil.cs b/VpnHood.Tunneling/PacketUtil.cs index 26f2789e0..847bc0c24 100644 --- a/VpnHood.Tunneling/PacketUtil.cs +++ b/VpnHood.Tunneling/PacketUtil.cs @@ -123,26 +123,25 @@ public static TcpPacket ExtractTcp(IPPacket ipPacket) throw new InvalidDataException($"Invalid {ipPacket.Protocol} packet!"); } - public static IPPacket CreateUnreachableReplyV6(IPPacket ipPacket, IcmpV4TypeCode typeCode, ushort mtu = 0) + public static IPPacket CreateUnreachableReplyV6(IPPacket ipPacket) { - if (ipPacket is null) throw new ArgumentNullException(nameof(ipPacket)); - - var icmpDataLen = Math.Min(ipPacket.TotalLength, 20 + 8); - var byteArraySegment = new ByteArraySegment(new byte[16 + icmpDataLen]); - var icmpPacket = new IcmpV6Packet(byteArraySegment, ipPacket) - { - Type = IcmpV6Type.PacketTooBig, - - Code = 0 - }; - - icmpPacket.UpdateCalculatedValues(); - - var newIpPacket = new IPv6Packet(ipPacket.DestinationAddress, ipPacket.SourceAddress) - { - PayloadPacket = icmpPacket - }; - UpdateIpPacket(newIpPacket); + //if (ipPacket is null) throw new ArgumentNullException(nameof(ipPacket)); + + //var icmpDataLen = Math.Min(ipPacket.TotalLength, 20 + 8); + //var byteArraySegment = new ByteArraySegment(new byte[16 + icmpDataLen]); + //var icmpPacket = new IcmpV6Packet(byteArraySegment, ipPacket) + //{ + // Type = IcmpV6Type.PacketTooBig, + // Code = 0 + //}; + + //icmpPacket.UpdateCalculatedValues(); + + //var newIpPacket = new IPv6Packet(ipPacket.DestinationAddress, ipPacket.SourceAddress) + //{ + // PayloadPacket = icmpPacket + //}; + //UpdateIpPacket(newIpPacket); throw new NotImplementedException("Not implemented!"); } diff --git a/VpnHood.ZTest/Tests/ClientAppTest.cs b/VpnHood.ZTest/Tests/ClientAppTest.cs index 55e7f3a54..2d5c52df0 100644 --- a/VpnHood.ZTest/Tests/ClientAppTest.cs +++ b/VpnHood.ZTest/Tests/ClientAppTest.cs @@ -474,12 +474,10 @@ public void Get_token_from_tokenLink() }); webServer.Start(); - // remove token1 from server - fileAccessServer.AccessItem_Delete(token1.TokenId).Wait(); - // connect using var app = TestHelper.CreateClientApp(); var clientProfile = app.ClientProfileStore.AddAccessKey(token1.ToAccessKey()); + app.ClientProfileStore.UpdateTokenFromUrl(token1).Wait(); var _ = app.Connect(clientProfile.ClientProfileId); TestHelper.WaitForClientState(app, AppConnectionState.Connected); Assert.AreEqual(AppConnectionState.Connected, app.State.ConnectionState); From 64630dcf746776f87d282508d00ea79709d5ac75 Mon Sep 17 00:00:00 2001 From: trudy Date: Wed, 22 Sep 2021 00:24:58 -0700 Subject: [PATCH 11/12] more ip6 friendly --- .../VpnHood.Client.App.Win.csproj | 2 +- .../VpnHood.Client.Device.WinDivert.csproj | 2 +- .../WinDivertPacketCapture.cs | 2 +- VpnHood.Client/VpnHoodClient.cs | 6 +- VpnHood.Tunneling/PacketUtil.cs | 92 +++++++++++++------ VpnHood.Tunneling/Tunnel.cs | 2 +- VpnHood.Tunneling/UdpProxy.cs | 2 +- VpnHood.ZTest/Tests/ClientServerTest.cs | 26 +++++- 8 files changed, 96 insertions(+), 38 deletions(-) diff --git a/VpnHood.Client.App.Win/VpnHood.Client.App.Win.csproj b/VpnHood.Client.App.Win/VpnHood.Client.App.Win.csproj index b9bdc11cd..c807a0c1d 100644 --- a/VpnHood.Client.App.Win/VpnHood.Client.App.Win.csproj +++ b/VpnHood.Client.App.Win/VpnHood.Client.App.Win.csproj @@ -58,7 +58,7 @@ - + diff --git a/VpnHood.Client.Device.WinDivert/VpnHood.Client.Device.WinDivert.csproj b/VpnHood.Client.Device.WinDivert/VpnHood.Client.Device.WinDivert.csproj index 5d6dcc28d..66d1ea02d 100644 --- a/VpnHood.Client.Device.WinDivert/VpnHood.Client.Device.WinDivert.csproj +++ b/VpnHood.Client.Device.WinDivert/VpnHood.Client.Device.WinDivert.csproj @@ -29,7 +29,7 @@ - + diff --git a/VpnHood.Client.Device.WinDivert/WinDivertPacketCapture.cs b/VpnHood.Client.Device.WinDivert/WinDivertPacketCapture.cs index 71b101246..11bc10a75 100644 --- a/VpnHood.Client.Device.WinDivert/WinDivertPacketCapture.cs +++ b/VpnHood.Client.Device.WinDivert/WinDivertPacketCapture.cs @@ -109,7 +109,7 @@ public void StartCapture() // add outbound; filter loopback var filter = $"(ip or ipv6) and outbound and !loopback and (udp.DstPort==53 or ({phraseX}))"; - filter = filter.Replace("ipv6.DstAddr>=::", "(ipv6.DstAddr==:: or ipv6.DstAddr>::)"); + filter = filter.Replace("ipv6.DstAddr>=::", "ipv6"); // WinDivert bug try { Device.Filter = filter; diff --git a/VpnHood.Client/VpnHoodClient.cs b/VpnHood.Client/VpnHoodClient.cs index 5d8bd5957..26d5e9e01 100644 --- a/VpnHood.Client/VpnHoodClient.cs +++ b/VpnHood.Client/VpnHoodClient.cs @@ -297,7 +297,10 @@ private void PacketCapture_OnPacketReceivedFromInbound(object sender, Device.Pac { if (_cancellationTokenSource.IsCancellationRequested) return; if (ipPacket.Version == IPVersion.IPv6) + { + _packetCapture.SendPacketToInbound(PacketUtil.CreateUnreachableReply(ipPacket)); continue; // actively drop IPv6 packets + } var isInRange = IsInIpRange(ipPacket.DestinationAddress); @@ -339,8 +342,7 @@ private void PacketCapture_OnPacketReceivedFromInbound(object sender, Device.Pac if (passthruPackets.Count > 0) _packetCapture.SendPacketToOutbound(passthruPackets.ToArray()); if (proxyPackets.Count > 0) _clientProxyManager.SendPacket(proxyPackets); if (tunnelPackets.Count > 0) Tunnel.SendPacket(tunnelPackets.ToArray()); - if (tcpHostPackets.Count > 0) - _packetCapture.SendPacketToInbound(_tcpProxyHost.ProcessOutgoingPacket(tcpHostPackets.ToArray())); + if (tcpHostPackets.Count > 0) _packetCapture.SendPacketToInbound(_tcpProxyHost.ProcessOutgoingPacket(tcpHostPackets.ToArray())); } } catch (Exception ex) diff --git a/VpnHood.Tunneling/PacketUtil.cs b/VpnHood.Tunneling/PacketUtil.cs index 847bc0c24..325903764 100644 --- a/VpnHood.Tunneling/PacketUtil.cs +++ b/VpnHood.Tunneling/PacketUtil.cs @@ -21,19 +21,20 @@ public static void UpdateIpPacket(IPPacket ipPacket, bool throwIfNotSupported = { var tcpPacket = ExtractTcp(ipPacket); tcpPacket.UpdateTcpChecksum(); - tcpPacket.UpdateCalculatedValues(); } else if (ipPacket.Protocol == ProtocolType.Udp) { var udpPacket = ExtractUdp(ipPacket); udpPacket.UpdateUdpChecksum(); - udpPacket.UpdateCalculatedValues(); } else if (ipPacket.Protocol == ProtocolType.Icmp) { var icmpPacket = ExtractIcmp(ipPacket); UpdateIcmpChecksum(icmpPacket); - icmpPacket.UpdateCalculatedValues(); + } + else if (ipPacket.Protocol == ProtocolType.IcmpV6) + { + // nothing need to do due to packet.UpdateCalculatedValues } else { @@ -123,49 +124,81 @@ public static TcpPacket ExtractTcp(IPPacket ipPacket) throw new InvalidDataException($"Invalid {ipPacket.Protocol} packet!"); } - public static IPPacket CreateUnreachableReplyV6(IPPacket ipPacket) + public static IPPacket CreateUnreachableReply(IPPacket ipPacket) + { + if (ipPacket.Version == IPVersion.IPv6) + return CreateUnreachableReplyV6(ipPacket, IcmpV6Type.DestinationUnreachable, 0, 0); + else + return CreateUnreachableReplyV4(ipPacket, IcmpV4TypeCode.UnreachableHost, 0); + } + + public static IPPacket CreateUnreachablePortReply(IPPacket ipPacket) { - //if (ipPacket is null) throw new ArgumentNullException(nameof(ipPacket)); - - //var icmpDataLen = Math.Min(ipPacket.TotalLength, 20 + 8); - //var byteArraySegment = new ByteArraySegment(new byte[16 + icmpDataLen]); - //var icmpPacket = new IcmpV6Packet(byteArraySegment, ipPacket) - //{ - // Type = IcmpV6Type.PacketTooBig, - // Code = 0 - //}; - - //icmpPacket.UpdateCalculatedValues(); - - //var newIpPacket = new IPv6Packet(ipPacket.DestinationAddress, ipPacket.SourceAddress) - //{ - // PayloadPacket = icmpPacket - //}; - //UpdateIpPacket(newIpPacket); - throw new NotImplementedException("Not implemented!"); + if (ipPacket.Version == IPVersion.IPv6) + return CreateUnreachableReplyV6(ipPacket, IcmpV6Type.DestinationUnreachable, 4, 0); + else + return CreateUnreachableReplyV4(ipPacket, IcmpV4TypeCode.UnreachablePort, 0); + } + + public static IPPacket CreatePacketTooBigReply(IPPacket ipPacket, ushort mtu) + { + if (ipPacket.Version == IPVersion.IPv6) + return CreateUnreachableReplyV6(ipPacket, IcmpV6Type.PacketTooBig, 0, mtu); + else + return CreateUnreachableReplyV4(ipPacket, IcmpV4TypeCode.UnreachableFragmentationNeeded, mtu); } - public static IPPacket CreateUnreachableReply(IPPacket ipPacket, IcmpV4TypeCode typeCode, ushort sequence = 0) + private static IPPacket CreateUnreachableReplyV6(IPPacket ipPacket, IcmpV6Type icmpV6Type, byte code, int reserved) + { + if (ipPacket is null) + throw new ArgumentNullException(nameof(ipPacket)); + + const int headerSize = 8; + var icmpDataLen = Math.Min(ipPacket.TotalLength, 1300); + var buffer = new byte[headerSize + icmpDataLen]; + Array.Copy(BitConverter.GetBytes(reserved), 0, buffer, 4, 4); + Array.Copy(ipPacket.Bytes, 0, buffer, headerSize, icmpDataLen); + var icmpPacket = new IcmpV6Packet(new ByteArraySegment(new byte[headerSize])) //todo: PacketDotNet bug + { + Type = icmpV6Type, + Code = code, + PayloadData = buffer[headerSize..] + }; + + var newIpPacket = new IPv6Packet(ipPacket.DestinationAddress, ipPacket.SourceAddress) + { + PayloadPacket = icmpPacket + }; + newIpPacket.PayloadLength = (ushort)icmpPacket.TotalPacketLength; + UpdateIpPacket(newIpPacket); + + //var restorePacketV6 = Packet.ParsePacket(LinkLayers.Raw, newIpPacket.Bytes).Extract(); + //var restoreIcmpV6 = restorePacketV6.Extract(); + return newIpPacket; + } + + private static IPPacket CreateUnreachableReplyV4(IPPacket ipPacket, IcmpV4TypeCode typeCode, ushort sequence) { if (ipPacket is null) throw new ArgumentNullException(nameof(ipPacket)); // packet is too big + const int headerSize = 8; var icmpDataLen = Math.Min(ipPacket.TotalLength, 20 + 8); - var byteArraySegment = new ByteArraySegment(new byte[16 + icmpDataLen]); - var icmpPacket = new IcmpV4Packet(byteArraySegment, ipPacket) + var buffer = new byte[headerSize + icmpDataLen]; + Array.Copy(ipPacket.Bytes, 0, buffer, headerSize, icmpDataLen); + var icmpPacket = new IcmpV4Packet(new ByteArraySegment(buffer)) { TypeCode = typeCode, - PayloadData = ipPacket.Bytes[..icmpDataLen], Sequence = sequence }; icmpPacket.Checksum = (ushort)ChecksumUtils.OnesComplementSum(icmpPacket.Bytes, 0, icmpPacket.Bytes.Length); - icmpPacket.UpdateCalculatedValues(); var newIpPacket = new IPv4Packet(ipPacket.DestinationAddress, ipPacket.SourceAddress) { PayloadPacket = icmpPacket, FragmentFlags = 0 }; + UpdateIpPacket(newIpPacket); return newIpPacket; } @@ -176,8 +209,9 @@ public static void UpdateIcmpChecksum(IcmpV4Packet icmpPacket) icmpPacket.Checksum = 0; var buf = icmpPacket.Bytes; - icmpPacket.Checksum = - buf != null ? (ushort)ChecksumUtils.OnesComplementSum(buf, 0, buf.Length) : (ushort)0; + icmpPacket.Checksum = buf != null + ? (ushort)ChecksumUtils.OnesComplementSum(buf, 0, buf.Length) + : (ushort)0; } public static ushort ReadPacketLength(byte[] buffer, int bufferIndex) diff --git a/VpnHood.Tunneling/Tunnel.cs b/VpnHood.Tunneling/Tunnel.cs index dadae03fa..3f86a5bdb 100644 --- a/VpnHood.Tunneling/Tunnel.cs +++ b/VpnHood.Tunneling/Tunnel.cs @@ -338,7 +338,7 @@ private async Task SendPacketTask(IDatagramChannel channel) { VhLogger.Instance.LogWarning($"Packet dropped! There is no channel to support this non fragmented packet. NoFragmented MTU: {_mtuNoFragment}, PacketLength: {ipPacket.TotalLength}, Packet: {ipPacket}"); _packetQueue.TryDequeue(out ipPacket); - var replyPacket = PacketUtil.CreateUnreachableReply(ipPacket, IcmpV4TypeCode.UnreachableFragmentationNeeded, (ushort) _mtuNoFragment); + var replyPacket = PacketUtil.CreatePacketTooBigReply(ipPacket, (ushort)_mtuNoFragment); OnPacketReceived?.Invoke(this, new ChannelPacketReceivedEventArgs(new[] {replyPacket}, channel)); continue; } diff --git a/VpnHood.Tunneling/UdpProxy.cs b/VpnHood.Tunneling/UdpProxy.cs index 57f9bf5c1..5910ebbcd 100644 --- a/VpnHood.Tunneling/UdpProxy.cs +++ b/VpnHood.Tunneling/UdpProxy.cs @@ -76,7 +76,7 @@ private async Task ReceiveUdpTask() if (_sameHost && _lastPacket != null) { var replyPacket = - PacketUtil.CreateUnreachableReply(_lastPacket, IcmpV4TypeCode.UnreachablePort); + PacketUtil.CreateUnreachablePortReply(_lastPacket); OnPacketReceived?.Invoke(this, new PacketReceivedEventArgs(replyPacket)); if (VhLogger.IsDiagnoseMode && !IsDisposed) VhLogger.Instance.Log(LogLevel.Information, GeneralEventId.Udp, diff --git a/VpnHood.ZTest/Tests/ClientServerTest.cs b/VpnHood.ZTest/Tests/ClientServerTest.cs index fbb45258b..56611a2c4 100644 --- a/VpnHood.ZTest/Tests/ClientServerTest.cs +++ b/VpnHood.ZTest/Tests/ClientServerTest.cs @@ -6,10 +6,13 @@ using System.Net.Sockets; using System.Threading; using Microsoft.VisualStudio.TestTools.UnitTesting; +using PacketDotNet; +using PacketDotNet.Utils; using VpnHood.Client; using VpnHood.Common.Messaging; using VpnHood.Server; using VpnHood.Server.AccessServers; +using VpnHood.Tunneling; namespace VpnHood.Test.Tests { @@ -250,9 +253,9 @@ public void Client_must_dispose_after_server_stopped() TestHelper.Test_Https(); server.Dispose(); - try { TestHelper.Test_Https(); } catch { /* ignored */ } + try { TestHelper.Test_Https(); } catch { /* ignored */ } Thread.Sleep(1000); - try { TestHelper.Test_Https(); } catch { /* ignored */ } + try { TestHelper.Test_Https(); } catch { /* ignored */ } TestHelper.WaitForClientState(client, ClientState.Disposed); } @@ -467,6 +470,25 @@ public void Subscribe_Maintenance_Server() TestHelper.WaitForClientState(client2, ClientState.Connected); } + [TestMethod] + public void Foo() + { + var buffer = new byte[100]; + var packetv6 = new IPv6Packet(IPAddress.IPv6Loopback, IPAddress.IPv6Loopback) + { Protocol = PacketDotNet.ProtocolType.Gre }; + packetv6.PayloadData = buffer; + packetv6.PayloadLength = (ushort)buffer.Length; + packetv6.UpdateCalculatedValues(); + + var packet4 = new IPv4Packet(IPAddress.Loopback, IPAddress.Loopback) + { Protocol = PacketDotNet.ProtocolType.Gre }; + packet4.PayloadData = buffer; + packet4.UpdateCalculatedValues(); + + PacketUtil.CreateUnreachableReply(packetv6); + PacketUtil.CreateUnreachableReply(packet4); + } + #if DEBUG [TestMethod] public void Disconnect_for_unsupported_client() From 14ed49a65f0b5f8fdcf198ab4dbc03d9b22d2428 Mon Sep 17 00:00:00 2001 From: trudy Date: Wed, 22 Sep 2021 16:28:59 -0700 Subject: [PATCH 12/12] Publish v2.0.272 --- CHANGELOG.md | 8 +++++--- Pub/Version.json | Bin 224 -> 224 bytes .../VpnHood.App.Launcher.csproj | 6 +++--- .../Properties/AndroidManifest.xml | 2 +- .../VpnHood.Client.App.UI.csproj | 6 +++--- .../VpnHood.Client.App.Win.Setup.aip | 6 +++--- .../VpnHood.Client.App.Win.csproj | 6 +++--- VpnHood.Client.App/VpnHood.Client.App.csproj | 6 +++--- .../VpnHood.Client.Device.WinDivert.csproj | 6 +++--- .../VpnHood.Client.Device.csproj | 6 +++--- VpnHood.Client/Note/Flow.txt | 16 ---------------- VpnHood.Client/VpnHood.Client.csproj | 6 +++--- VpnHood.Client/VpnHoodClient.cs | 2 +- VpnHood.Common/VpnHood.Common.csproj | 6 +++--- .../VpnHood.Server.Access.csproj | 6 +++--- .../VpnHood.Server.App.Net.csproj | 6 +++--- VpnHood.Server/VpnHood.Server.csproj | 6 +++--- VpnHood.Tunneling/VpnHood.Tunneling.csproj | 6 +++--- 18 files changed, 46 insertions(+), 60 deletions(-) delete mode 100644 VpnHood.Client/Note/Flow.txt diff --git a/CHANGELOG.md b/CHANGELOG.md index b14270632..35ac3435e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,9 @@ -# Upcoming -* Fix: Android: Closing VpnService +# v2.0.272 +* Feature: Block all IPv6 Global Unicast to prevent leak +* Fix: Android: Vpn Connection keeps open after disconnecting * Fix: Android: Crash in android 5.1 * Fix: IpFilter miss some IPs of countries -* Improve: Connect speed +* Update: Improve the speed of establishing the connection # v2.0.271 ### Client @@ -273,3 +274,4 @@ + diff --git a/Pub/Version.json b/Pub/Version.json index d250d87c1c0585c0e640b74712554b3ff85ccb65..42ed19c5f32bc71e94c2e6410cb0e816a98a02fc 100644 GIT binary patch delta 64 zcmaFB_<(Uj0i)5xLTeKv1|xLTeKP26KiG216jUVlW1iCJYt~dO%TAAkT=wfWZ>Tk77__;AP-q Hs0EV%n7Ijz diff --git a/VpnHood.App.Launcher/VpnHood.App.Launcher.csproj b/VpnHood.App.Launcher/VpnHood.App.Launcher.csproj index 81f6a4e01..80e60e219 100644 --- a/VpnHood.App.Launcher/VpnHood.App.Launcher.csproj +++ b/VpnHood.App.Launcher/VpnHood.App.Launcher.csproj @@ -14,9 +14,9 @@ VpnHood.png VpnHood.App.Launcher Resources\VpnHood.ico - 2.0.271 - 2.0.271 - 2.0.271 + 2.0.272 + 2.0.272 + 2.0.272 9.0 enable diff --git a/VpnHood.Client.App.Android/Properties/AndroidManifest.xml b/VpnHood.Client.App.Android/Properties/AndroidManifest.xml index fc6150378..b2f1656bd 100644 --- a/VpnHood.Client.App.Android/Properties/AndroidManifest.xml +++ b/VpnHood.Client.App.Android/Properties/AndroidManifest.xml @@ -1,5 +1,5 @@  - + diff --git a/VpnHood.Client.App.UI/VpnHood.Client.App.UI.csproj b/VpnHood.Client.App.UI/VpnHood.Client.App.UI.csproj index 5302d0a05..8f8e25de9 100644 --- a/VpnHood.Client.App.UI/VpnHood.Client.App.UI.csproj +++ b/VpnHood.Client.App.UI/VpnHood.Client.App.UI.csproj @@ -12,9 +12,9 @@ VpnHood.png Readymade Vpn App skeleton for VpnHood clients. You just need to add build a UI on it. VpnHood.Client.App.UI - 2.0.271 - 2.0.271 - 2.0.271 + 2.0.272 + 2.0.272 + 2.0.272 enable 9.0 diff --git a/VpnHood.Client.App.Win.Setup/VpnHood.Client.App.Win.Setup.aip b/VpnHood.Client.App.Win.Setup/VpnHood.Client.App.Win.Setup.aip index ac4334a2c..792048533 100644 --- a/VpnHood.Client.App.Win.Setup/VpnHood.Client.App.Win.Setup.aip +++ b/VpnHood.Client.App.Win.Setup/VpnHood.Client.App.Win.Setup.aip @@ -1,5 +1,5 @@ - + @@ -22,10 +22,10 @@ - + - + diff --git a/VpnHood.Client.App.Win/VpnHood.Client.App.Win.csproj b/VpnHood.Client.App.Win/VpnHood.Client.App.Win.csproj index c807a0c1d..a26264628 100644 --- a/VpnHood.Client.App.Win/VpnHood.Client.App.Win.csproj +++ b/VpnHood.Client.App.Win/VpnHood.Client.App.Win.csproj @@ -16,9 +16,9 @@ app.manifest VpnHood.Client.App.Win - 2.0.271 - 2.0.271 - 2.0.271 + 2.0.272 + 2.0.272 + 2.0.272 enable 9.0 false diff --git a/VpnHood.Client.App/VpnHood.Client.App.csproj b/VpnHood.Client.App/VpnHood.Client.App.csproj index 604a48d4b..3736d71b4 100644 --- a/VpnHood.Client.App/VpnHood.Client.App.csproj +++ b/VpnHood.Client.App/VpnHood.Client.App.csproj @@ -11,9 +11,9 @@ https://github.com/vpnhood/vpnhood Readymade Vpn App skeleton for VpnHood clients. You just need to create a UI on it. VpnHood.Client.App - 2.0.271 - 2.0.271 - 2.0.271 + 2.0.272 + 2.0.272 + 2.0.272 enable 9.0 diff --git a/VpnHood.Client.Device.WinDivert/VpnHood.Client.Device.WinDivert.csproj b/VpnHood.Client.Device.WinDivert/VpnHood.Client.Device.WinDivert.csproj index 66d1ea02d..10f975872 100644 --- a/VpnHood.Client.Device.WinDivert/VpnHood.Client.Device.WinDivert.csproj +++ b/VpnHood.Client.Device.WinDivert/VpnHood.Client.Device.WinDivert.csproj @@ -9,11 +9,11 @@ https://github.com/vpnhood/vpnhood VpnHood.png VpnHood client device provider for Windows using WinDivert. - 2.0.271 + 2.0.272 VpnHood.Client.Device.WinDivert 1.1.226 - 2.0.271 - 2.0.271 + 2.0.272 + 2.0.272 enable 9.0 diff --git a/VpnHood.Client.Device/VpnHood.Client.Device.csproj b/VpnHood.Client.Device/VpnHood.Client.Device.csproj index ab5c11679..a170e4a49 100644 --- a/VpnHood.Client.Device/VpnHood.Client.Device.csproj +++ b/VpnHood.Client.Device/VpnHood.Client.Device.csproj @@ -14,9 +14,9 @@ VpnHood.Client.Device VpnHood.Client.Device - 2.0.271 - 2.0.271 - 2.0.271 + 2.0.272 + 2.0.272 + 2.0.272 enable 9.0 diff --git a/VpnHood.Client/Note/Flow.txt b/VpnHood.Client/Note/Flow.txt deleted file mode 100644 index 995c3e8a7..000000000 --- a/VpnHood.Client/Note/Flow.txt +++ /dev/null @@ -1,16 +0,0 @@ -How a user knows that he has been disconnected by another session? - -* Server keeps sessions alive for SessionTimeout -* Server keep disposed sessions info for SessionTimeout -* Any other session with same clientId will be closed on new session creation -* Any connections with closed session id is replied by an error message that indicates he was disconnected by another session -* Server doesn't return any error message if sessionId is not detected! no fingerprint to prevent server query - -Normal Connection -* Try to connect -* if failed run pre-connection test to check network - -Diagnose Connection -* dianose all tests and provide best message -* Keep connection alive if client connected - diff --git a/VpnHood.Client/VpnHood.Client.csproj b/VpnHood.Client/VpnHood.Client.csproj index 903d53fbb..05dd1ce36 100644 --- a/VpnHood.Client/VpnHood.Client.csproj +++ b/VpnHood.Client/VpnHood.Client.csproj @@ -13,9 +13,9 @@ 2020 VpnHood VpnHood.Client VPN VpnClient Proxy - 2.0.271 - 2.0.271 - 2.0.271 + 2.0.272 + 2.0.272 + 2.0.272 enable 9.0 diff --git a/VpnHood.Client/VpnHoodClient.cs b/VpnHood.Client/VpnHoodClient.cs index 26d5e9e01..4d6907f11 100644 --- a/VpnHood.Client/VpnHoodClient.cs +++ b/VpnHood.Client/VpnHoodClient.cs @@ -759,7 +759,7 @@ private void Dispose(Exception ex) Dispose(); } - private readonly object _disposingLock = new (); + private readonly object _disposingLock = new(); public void Dispose() { lock (_disposingLock) diff --git a/VpnHood.Common/VpnHood.Common.csproj b/VpnHood.Common/VpnHood.Common.csproj index 7ed087f6b..260729647 100644 --- a/VpnHood.Common/VpnHood.Common.csproj +++ b/VpnHood.Common/VpnHood.Common.csproj @@ -12,9 +12,9 @@ VpnHood.Common VpnHood.png VpnHood Common Library is shared among all other VpnHood modules. - 2.0.271 - 2.0.271 - 2.0.271 + 2.0.272 + 2.0.272 + 2.0.272 enable 9.0 diff --git a/VpnHood.Server.Access/VpnHood.Server.Access.csproj b/VpnHood.Server.Access/VpnHood.Server.Access.csproj index 21c618599..5eae78c1c 100644 --- a/VpnHood.Server.Access/VpnHood.Server.Access.csproj +++ b/VpnHood.Server.Access/VpnHood.Server.Access.csproj @@ -12,9 +12,9 @@ VpnHood.Server.Access VpnHood.png Stores, and retrieves end users' access and usage. Provides required interfaces and classes to use or create an access server and accounting. - 2.0.271 - 2.0.271 - 2.0.271 + 2.0.272 + 2.0.272 + 2.0.272 enable 9.0 diff --git a/VpnHood.Server.App.Net/VpnHood.Server.App.Net.csproj b/VpnHood.Server.App.Net/VpnHood.Server.App.Net.csproj index c01583a98..d0f9a995c 100644 --- a/VpnHood.Server.App.Net/VpnHood.Server.App.Net.csproj +++ b/VpnHood.Server.App.Net/VpnHood.Server.App.Net.csproj @@ -13,9 +13,9 @@ https://github.com/vpnhood/vpnhood LGPL-2.1-only VpnHood.png - 2.0.271 - 2.0.271 - 2.0.271 + 2.0.272 + 2.0.272 + 2.0.272 enable 9.0 diff --git a/VpnHood.Server/VpnHood.Server.csproj b/VpnHood.Server/VpnHood.Server.csproj index de8a7ab3a..3f2282046 100644 --- a/VpnHood.Server/VpnHood.Server.csproj +++ b/VpnHood.Server/VpnHood.Server.csproj @@ -13,9 +13,9 @@ VpnHood.png The core of VpnHood server. It can listen and accept connections from VpnHood clients. VpnHood.Server - 2.0.271 - 2.0.271 - 2.0.271 + 2.0.272 + 2.0.272 + 2.0.272 enable 9.0 diff --git a/VpnHood.Tunneling/VpnHood.Tunneling.csproj b/VpnHood.Tunneling/VpnHood.Tunneling.csproj index 772090b99..77281784d 100644 --- a/VpnHood.Tunneling/VpnHood.Tunneling.csproj +++ b/VpnHood.Tunneling/VpnHood.Tunneling.csproj @@ -15,9 +15,9 @@ VpnHood.png VpnHood.Tunneling Provides tunnelling classes and protocols shared between VpnHood.Client and VpnHood.Server. - 2.0.271 - 2.0.271 - 2.0.271 + 2.0.272 + 2.0.272 + 2.0.272 enable 9.0