summary refs log tree commit diff
path: root/crypto/src/util/net/IPAddress.cs
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/src/util/net/IPAddress.cs')
-rw-r--r--crypto/src/util/net/IPAddress.cs315
1 files 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;
+        }
+    }
 }