From e526f1179fb15bdccdecfe458d2dac41d22c4a62 Mon Sep 17 00:00:00 2001 From: Peter Dettman Date: Fri, 3 Feb 2023 17:43:19 +0700 Subject: Update IPAddress from bc-java --- crypto/src/util/net/IPAddress.cs | 315 +++++++++++++++++++++------------------ 1 file changed, 171 insertions(+), 144 deletions(-) diff --git a/crypto/src/util/net/IPAddress.cs b/crypto/src/util/net/IPAddress.cs index 69e8e4680..62b0ed09a 100644 --- a/crypto/src/util/net/IPAddress.cs +++ b/crypto/src/util/net/IPAddress.cs @@ -1,11 +1,7 @@ -using System; -using System.Globalization; - -using Org.BouncyCastle.Math; - namespace Org.BouncyCastle.Utilities.Net { - public class IPAddress + // TODO Make static in next API revision + public class IPAddress { /** * Validate the given IPv4 or IPv6 address. @@ -14,8 +10,7 @@ namespace Org.BouncyCastle.Utilities.Net * * @return true if a valid address, false otherwise */ - public static bool IsValid( - string address) + public static bool IsValid(string address) { return IsValidIPv4(address) || IsValidIPv6(address); } @@ -27,8 +22,7 @@ namespace Org.BouncyCastle.Utilities.Net * * @return true if a valid address with netmask, false otherwise */ - public static bool IsValidWithNetMask( - string address) + public static bool IsValidWithNetMask(string address) { return IsValidIPv4WithNetmask(address) || IsValidIPv6WithNetmask(address); } @@ -40,80 +34,36 @@ namespace Org.BouncyCastle.Utilities.Net * * @return true if a valid IPv4 address, false otherwise */ - public static bool IsValidIPv4( - string address) - { - try - { - return unsafeIsValidIPv4(address); - } - catch (FormatException) {} - catch (OverflowException) {} - return false; - } - - private static bool unsafeIsValidIPv4( - string address) + public static bool IsValidIPv4(string address) { - if (address.Length == 0) - return false; + int length = address.Length; + if (length < 7 || length > 15) + return false; - int octets = 0; - string temp = address + "."; + int pos = 0; + for (int octetIndex = 0; octetIndex < 3; ++octetIndex) + { + int end = Platform.IndexOf(address, '.', pos); - int pos; - int start = 0; - while (start < temp.Length - && (pos = temp.IndexOf('.', start)) > start) - { - if (octets == 4) - return false; + if (!IsParseableIPv4Octet(address, pos, end)) + return false; - string octetStr = temp.Substring(start, pos - start); - int octet = int.Parse(octetStr); + pos = end + 1; + } - if (octet < 0 || octet > 255) - return false; - - start = pos + 1; - octets++; - } - - return octets == 4; + return IsParseableIPv4Octet(address, pos, length); } - public static bool IsValidIPv4WithNetmask( - string address) + public static bool IsValidIPv4WithNetmask(string address) { - int index = address.IndexOf('/'); - string mask = address.Substring(index + 1); + int index = Platform.IndexOf(address, '/'); + if (index < 1) + return false; - return (index > 0) && IsValidIPv4(address.Substring(0, index)) - && (IsValidIPv4(mask) || IsMaskValue(mask, 32)); - } + string before = address.Substring(0, index); + string after = address.Substring(index + 1); - public static bool IsValidIPv6WithNetmask( - string address) - { - int index = address.IndexOf('/'); - string mask = address.Substring(index + 1); - - return (index > 0) && (IsValidIPv6(address.Substring(0, index)) - && (IsValidIPv6(mask) || IsMaskValue(mask, 128))); - } - - private static bool IsMaskValue( - string component, - int size) - { - int val = int.Parse(component); - try - { - return val >= 0 && val <= size; - } - catch (FormatException) {} - catch (OverflowException) {} - return false; + return IsValidIPv4(before) && (IsValidIPv4(after) || IsParseableIPv4Mask(after)); } /** @@ -123,75 +73,152 @@ namespace Org.BouncyCastle.Utilities.Net * * @return true if a valid IPv4 address, false otherwise */ - public static bool IsValidIPv6( - string address) + public static bool IsValidIPv6(string address) { - try - { - return unsafeIsValidIPv6(address); - } - catch (FormatException) {} - catch (OverflowException) {} - return false; - } - - private static bool unsafeIsValidIPv6( - string address) - { - if (address.Length == 0) - { - return false; - } - - int octets = 0; - - string temp = address + ":"; - bool doubleColonFound = false; - int pos; - int start = 0; - while (start < temp.Length - && (pos = temp.IndexOf(':', start)) >= start) - { - if (octets == 8) - { - return false; - } - - if (start != pos) - { - string value = temp.Substring(start, pos - start); - - if (pos == (temp.Length - 1) && value.IndexOf('.') > 0) - { - if (!IsValidIPv4(value)) - { - return false; - } - - octets++; // add an extra one as address covers 2 words. - } - else - { - string octetStr = temp.Substring(start, pos - start); - int octet = int.Parse(octetStr, NumberStyles.AllowHexSpecifier); - - if (octet < 0 || octet > 0xffff) - return false; - } - } - else - { - if (pos != 1 && pos != temp.Length - 1 && doubleColonFound) - { - return false; - } - doubleColonFound = true; - } - start = pos + 1; - octets++; - } - - return octets == 8 || doubleColonFound; - } - } + if (address.Length == 0) + return false; + + if (address[0] != ':' && GetDigitHexadecimal(address, 0) < 0) + return false; + + int segmentCount = 0; + string temp = address + ":"; + bool doubleColonFound = false; + + int pos = 0, end; + while (pos < temp.Length && (end = Platform.IndexOf(temp, ':', pos)) >= pos) + { + if (segmentCount == 8) + return false; + + if (pos != end) + { + string value = temp.Substring(pos, end - pos); + + if (end == temp.Length - 1 && Platform.IndexOf(value, '.') > 0) + { + // add an extra one as address covers 2 words. + if (++segmentCount == 8) + return false; + + if (!IsValidIPv4(value)) + return false; + } + else if (!IsParseableIPv6Segment(temp, pos, end)) + { + return false; + } + } + else + { + if (end != 1 && end != temp.Length - 1 && doubleColonFound) + return false; + + doubleColonFound = true; + } + + pos = end + 1; + ++segmentCount; + } + + return segmentCount == 8 || doubleColonFound; + } + + public static bool IsValidIPv6WithNetmask(string address) + { + int index = Platform.IndexOf(address, '/'); + if (index < 1) + return false; + + string before = address.Substring(0, index); + string after = address.Substring(index + 1); + + return IsValidIPv6(before) && (IsValidIPv6(after) || IsParseableIPv6Mask(after)); + } + + private static bool IsParseableIPv4Mask(string s) + { + return IsParseableDecimal(s, 0, s.Length, 2, false, 0, 32); + } + + private static bool IsParseableIPv4Octet(string s, int pos, int end) + { + return IsParseableDecimal(s, pos, end, 3, true, 0, 255); + } + + private static bool IsParseableIPv6Mask(string s) + { + return IsParseableDecimal(s, 0, s.Length, 3, false, 1, 128); + } + + private static bool IsParseableIPv6Segment(string s, int pos, int end) + { + return IsParseableHexadecimal(s, pos, end, 4, true, 0x0000, 0xFFFF); + } + + private static bool IsParseableDecimal(string s, int pos, int end, int maxLength, bool allowLeadingZero, + int minValue, int maxValue) + { + int length = end - pos; + if (length < 1 | length > maxLength) + return false; + + bool checkLeadingZero = length > 1 & !allowLeadingZero; + if (checkLeadingZero && s[pos] == '0') + return false; + + int value = 0; + while (pos < end) + { + int d = GetDigitDecimal(s, pos++); + if (d < 0) + return false; + + value *= 10; + value += d; + } + + return value >= minValue & value <= maxValue; + } + + private static bool IsParseableHexadecimal(string s, int pos, int end, int maxLength, bool allowLeadingZero, + int minValue, int maxValue) + { + int length = end - pos; + if (length < 1 | length > maxLength) + return false; + + bool checkLeadingZero = length > 1 & !allowLeadingZero; + if (checkLeadingZero && s[pos] == '0') + return false; + + int value = 0; + while (pos < end) + { + int d = GetDigitHexadecimal(s, pos++); + if (d < 0) + return false; + + value *= 16; + value += d; + } + + return value >= minValue & value <= maxValue; + } + + private static int GetDigitDecimal(string s, int pos) + { + char c = s[pos]; + uint d = (uint)(c - '0'); + return d <= 9 ? (int)d : -1; + } + + private static int GetDigitHexadecimal(string s, int pos) + { + char c = s[pos]; + uint d = (uint)c | 0x20U; + d -= (d >= (uint)'a') ? ((uint)'a' - 10) : (uint)'0'; + return d <= 16 ? (int)d : -1; + } + } } -- cgit 1.4.1