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;
+ }
+ }
}
|