From 1c125733b2100bd841c1eb0cc3ca37618dad5ce0 Mon Sep 17 00:00:00 2001 From: Qstick Date: Wed, 7 Dec 2022 21:16:40 -0600 Subject: [PATCH] New: Improve IPAddress.IsLocal method Co-Authored-By: ta264 --- .../Extensions/IpAddressExtensions.cs | 46 +++++++++++++------ 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/src/NzbDrone.Common/Extensions/IpAddressExtensions.cs b/src/NzbDrone.Common/Extensions/IpAddressExtensions.cs index 4a7cc9a44..7feb431c4 100644 --- a/src/NzbDrone.Common/Extensions/IpAddressExtensions.cs +++ b/src/NzbDrone.Common/Extensions/IpAddressExtensions.cs @@ -7,34 +7,50 @@ namespace NzbDrone.Common.Extensions { public static bool IsLocalAddress(this IPAddress ipAddress) { - if (ipAddress.IsIPv6LinkLocal) + // Map back to IPv4 if mapped to IPv6, for example "::ffff:1.2.3.4" to "1.2.3.4". + if (ipAddress.IsIPv4MappedToIPv6) { - return true; + ipAddress = ipAddress.MapToIPv4(); } + // Checks loopback ranges for both IPv4 and IPv6. if (IPAddress.IsLoopback(ipAddress)) { return true; } + // IPv4 if (ipAddress.AddressFamily == AddressFamily.InterNetwork) { - byte[] bytes = ipAddress.GetAddressBytes(); - switch (bytes[0]) - { - case 10: - case 127: - return true; - case 172: - return bytes[1] < 32 && bytes[1] >= 16; - case 192: - return bytes[1] == 168; - default: - return false; - } + return IsLocalIPv4(ipAddress.GetAddressBytes()); + } + + // IPv6 + if (ipAddress.AddressFamily == AddressFamily.InterNetworkV6) + { + return ipAddress.IsIPv6LinkLocal || + ipAddress.IsIPv6UniqueLocal || + ipAddress.IsIPv6SiteLocal; } return false; } + + private static bool IsLocalIPv4(byte[] ipv4Bytes) + { + // Link local (no IP assigned by DHCP): 169.254.0.0 to 169.254.255.255 (169.254.0.0/16) + bool IsLinkLocal() => ipv4Bytes[0] == 169 && ipv4Bytes[1] == 254; + + // Class A private range: 10.0.0.0 – 10.255.255.255 (10.0.0.0/8) + bool IsClassA() => ipv4Bytes[0] == 10; + + // Class B private range: 172.16.0.0 – 172.31.255.255 (172.16.0.0/12) + bool IsClassB() => ipv4Bytes[0] == 172 && ipv4Bytes[1] >= 16 && ipv4Bytes[1] <= 31; + + // Class C private range: 192.168.0.0 – 192.168.255.255 (192.168.0.0/16) + bool IsClassC() => ipv4Bytes[0] == 192 && ipv4Bytes[1] == 168; + + return IsLinkLocal() || IsClassA() || IsClassC() || IsClassB(); + } } }