// out that in ms.net there's an internal class called\r
// IPv6Address in namespace System.\r
//\r
-
-//
-// Permission is hereby granted, free of charge, to any person obtaining
-// a copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to
-// permit persons to whom the Software is furnished to do so, subject to
-// the following conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-//
+\r
+//\r
+// Permission is hereby granted, free of charge, to any person obtaining\r
+// a copy of this software and associated documentation files (the\r
+// "Software"), to deal in the Software without restriction, including\r
+// without limitation the rights to use, copy, modify, merge, publish,\r
+// distribute, sublicense, and/or sell copies of the Software, and to\r
+// permit persons to whom the Software is furnished to do so, subject to\r
+// the following conditions:\r
+// \r
+// The above copyright notice and this permission notice shall be\r
+// included in all copies or substantial portions of the Software.\r
+// \r
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\r
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\r
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\r
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
+//\r
\r
\r
using System;\r
+using System.Globalization;\r
using System.Net.Sockets;\r
using System.Runtime.InteropServices;\r
using System.Text;\r
if (prefixLength < 0 || prefixLength > 128)\r
throw new ArgumentException ("prefixLength");\r
this.prefixLength = prefixLength;\r
- } \r
+ }\r
\r
public IPv6Address (ushort [] addr, int prefixLength, int scopeId) : this (addr, prefixLength)\r
{\r
- this.scopeId = scopeId;\r
- } \r
- \r
+ this.scopeId = scopeId;\r
+ }\r
+\r
public static IPv6Address Parse (string ipString)\r
{\r
if (ipString == null)\r
throw new ArgumentNullException ("ipString");\r
\r
+ IPv6Address result;\r
+ if (TryParse (ipString, out result))\r
+ return result;\r
+ throw new FormatException ("Not a valid IPv6 address");\r
+ }\r
+\r
+ static int Fill (ushort [] addr, string ipString)\r
+ {\r
+ int p = 0;\r
+ int slot = 0;\r
+\r
+ if (ipString.Length == 0)\r
+ return 0;\r
+ \r
+ // Catch double uses of ::\r
+ if (ipString.IndexOf ("::", StringComparison.Ordinal) != -1)\r
+ return -1;\r
+\r
+ for (int i = 0; i < ipString.Length; i++){\r
+ char c = ipString [i];\r
+ int n;\r
+\r
+ if (c == ':'){\r
+ // Trailing : is not allowed.\r
+ if (i == ipString.Length-1)\r
+ return -1;\r
+ \r
+ if (slot == 8)\r
+ return -1;\r
+ \r
+ addr [slot++] = (ushort) p;\r
+ p = 0;\r
+ continue;\r
+ } if ('0' <= c && c <= '9')\r
+ n = (int) (c - '0');\r
+ else if ('a' <= c && c <= 'f')\r
+ n = (int) (c - 'a' + 10);\r
+ else if ('A' <= c && c <= 'F')\r
+ n = (int) (c - 'A' + 10);\r
+ else \r
+ return -1;\r
+ p = (p << 4) + n;\r
+ if (p > UInt16.MaxValue)\r
+ return -1;\r
+ }\r
+\r
+ if (slot == 8)\r
+ return -1;\r
+ \r
+ addr [slot++] = (ushort) p;\r
+\r
+ return slot;\r
+ }\r
+\r
+ static bool TryParse (string prefix, out int res)\r
+ {\r
+ return Int32.TryParse (prefix, NumberStyles.Integer, CultureInfo.InvariantCulture, out res);\r
+ }\r
+ \r
+ public static bool TryParse (string ipString, out IPv6Address result)\r
+ {\r
+ result = null;\r
+ if (ipString == null)\r
+ return false;\r
+\r
if (ipString.Length > 2 && \r
ipString [0] == '[' && \r
ipString [ipString.Length - 1] == ']')\r
- ipString = ipString.Substring (1, ipString.Length - 2); \r
+ ipString = ipString.Substring (1, ipString.Length - 2);\r
\r
if (ipString.Length < 2)\r
- throw new FormatException ("Not a valid IPv6 address");\r
+ return false;\r
\r
int prefixLen = 0;\r
int scopeId = 0;\r
int pos = ipString.LastIndexOf ('/');\r
if (pos != -1) {\r
string prefix = ipString.Substring (pos + 1);\r
- try {\r
- prefixLen = Int32.Parse (prefix);\r
- } catch (Exception) {\r
+ if (!TryParse (prefix , out prefixLen))\r
prefixLen = -1;\r
- }\r
if (prefixLen < 0 || prefixLen > 128)\r
- throw new FormatException ("Not a valid prefix length");\r
+ return false;\r
ipString = ipString.Substring (0, pos);\r
} else {\r
pos = ipString.LastIndexOf ('%');\r
if (pos != -1) {\r
string prefix = ipString.Substring (pos + 1);\r
- try {\r
- scopeId = Int32.Parse (prefix);\r
- } \r
- catch (Exception) {\r
+ if (!TryParse (prefix, out scopeId))\r
scopeId = 0;\r
- }\r
ipString = ipString.Substring (0, pos);\r
} \r
}\r
- \r
- ushort [] addr = new ushort [8]; \r
- \r
+\r
+ //\r
+ // At this point the prefix/suffixes have been removed\r
+ // and we only have to deal with the ipv4 or ipv6 addressed\r
+ //\r
+ ushort [] addr = new ushort [8];\r
+\r
+ //\r
+ // Is there an ipv4 address at the end?\r
+ //\r
bool ipv4 = false;\r
- int pos2 = ipString.LastIndexOf (":");\r
+ int pos2 = ipString.LastIndexOf (':');\r
if (pos2 == -1)\r
- throw new FormatException ("Not a valid IPv6 address");\r
+ return false;\r
+\r
+ int slots = 0;\r
if (pos2 < (ipString.Length - 1)) {\r
string ipv4Str = ipString.Substring (pos2 + 1);\r
if (ipv4Str.IndexOf ('.') != -1) {\r
- try {\r
- long a = IPAddress.Parse (ipv4Str).InternalIPv4Address;\r
- addr [6] = (ushort) (((int) (a & 0xff) << 8) + ((int) ((a >> 8) & 0xff)));\r
- addr [7] = (ushort) (((int) ((a >> 16) & 0xff) << 8) + ((int) ((a >> 24) & 0xff)));\r
- if (ipString [pos2 - 1] == ':') \r
- ipString = ipString.Substring (0, pos2 + 1);\r
- else\r
- ipString = ipString.Substring (0, pos2);\r
- ipv4 = true;\r
- } catch (Exception) {\r
- throw new FormatException ("Not a valid IPv6 address"); \r
- }\r
+ IPAddress ip;\r
+ \r
+ if (!IPAddress.TryParse (ipv4Str, out ip))\r
+ return false;\r
+ \r
+ long a = ip.InternalIPv4Address;\r
+ addr [6] = (ushort) (((int) (a & 0xff) << 8) + ((int) ((a >> 8) & 0xff)));\r
+ addr [7] = (ushort) (((int) ((a >> 16) & 0xff) << 8) + ((int) ((a >> 24) & 0xff)));\r
+ if (pos2 > 0 && ipString [pos2 - 1] == ':') \r
+ ipString = ipString.Substring (0, pos2 + 1);\r
+ else\r
+ ipString = ipString.Substring (0, pos2);\r
+ ipv4 = true;\r
+ slots = 2;\r
}\r
} \r
- \r
- int origLen = ipString.Length;\r
- if (origLen < 2)\r
- throw new FormatException ("Not a valid IPv6 address"); \r
- ipString = ipString.Replace ("::", ":!:");\r
- int len = ipString.Length;\r
- if ((len - origLen) > 1) \r
- throw new FormatException ("Not a valid IPv6 address");\r
- \r
- if (ipString [1] == '!') \r
- ipString = ipString.Remove (0, 1);\r
- if (ipString [len - 2] == '!')\r
- ipString = ipString.Remove (len - 1, 1);\r
- if ((ipString.Length > 2) && \r
- ((ipString [0] == ':') || (ipString [ipString.Length - 1] == ':'))) \r
- throw new FormatException ("Not a valid IPv6 address");\r
- \r
- string [] pieces = ipString.Split (new char [] {':'});\r
- len = pieces.Length;\r
- if (len > (ipv4 ? 6 : 8)) \r
- throw new FormatException ("Not a valid IPv6 address");\r
- int piecedouble = -1;\r
- bool ipv6 = false;
- for (int i = 0; i < len; i++) {\r
- string piece = pieces [i];\r
- if (piece == "!")\r
- piecedouble = i;\r
- else {\r
- int plen = piece.Length;\r
- if (plen > 4)\r
- throw new FormatException ("Not a valid IPv6 address");\r
- int p = 0;\r
- for (int j = 0; j < plen; j++) \r
- try {\r
- p = (p << 4) + Uri.FromHex (piece [j]);\r
- } catch (ArgumentException) {\r
- throw new FormatException ("Not a valid IPv6 address");\r
- }\r
- addr [i] = (ushort) p;
- if (p != 0 || (i == 5 && p != 0xffff))
- ipv6 = true;
+\r
+ //\r
+ // Only an ipv6 block remains, either:\r
+ // "hexnumbers::hexnumbers", "hexnumbers::" or "hexnumbers"\r
+ //\r
+ int c = ipString.IndexOf ("::", StringComparison.Ordinal);\r
+ if (c != -1){\r
+ int right_slots = Fill (addr, ipString.Substring (c+2));\r
+ if (right_slots == -1){\r
+ return false;\r
}\r
- }\r
\r
- //expand the :: token\r
- if (piecedouble != -1) {\r
- int totallen = (ipv4 ? 5 : 7);\r
- int i = totallen;\r
- for (i = totallen; i >= (totallen - (len - piecedouble - 1)); i--) {\r
- addr [i] = addr [(len - 1) + i - totallen];\r
+ if (right_slots + slots > 8){\r
+ return false;\r
+ }\r
+\r
+ int d = 8-slots-right_slots;\r
+ for (int i = right_slots; i > 0; i--){\r
+ addr [i+d-1] = addr [i-1];\r
+ addr [i-1] = 0;\r
}\r
- for (; i >= piecedouble; i--) {\r
- addr [i] = 0;\r
+ \r
+ int left_slots = Fill (addr, ipString.Substring (0, c));\r
+ if (left_slots == -1)\r
+ return false;\r
+\r
+ if (left_slots + right_slots + slots > 7)\r
+ return false;\r
+ } else {\r
+ if (Fill (addr, ipString) != 8-slots)\r
+ return false;\r
+ }\r
+\r
+ // Now check the results in the ipv6-address range only\r
+ bool ipv6 = false;\r
+ for (int i = 0; i < slots; i++){\r
+ if (addr [i] != 0 || i == 5 && addr [i] != 0xffff)\r
+ ipv6 = true;\r
+ }\r
+ \r
+ // check IPv4 validity\r
+ if (ipv4 && !ipv6) {\r
+ for (int i = 0; i < 5; i++) {\r
+ if (addr [i] != 0)\r
+ return false;\r
}\r
- } else if (len != (ipv4 ? 6 : 8)) \r
- throw new FormatException ("Not a valid IPv6 address");\r
-\r
- // check IPv4 validity
- if (ipv4 && !ipv6) {
- for (int i = 0; i < 5; i++) {
- if (addr [i] != 0)
- throw new FormatException ("Not a valid IPv6 address");
- }
-
- if (addr [5] != 0 && addr [5] != 0xffff)
- throw new FormatException ("Not a valid IPv6 address");
- }
-
- return new IPv6Address (addr, prefixLen, scopeId);
- }
-
+\r
+ if (addr [5] != 0 && addr [5] != 0xffff)\r
+ return false;\r
+ }\r
+\r
+ result = new IPv6Address (addr, prefixLen, scopeId);\r
+ return true;\r
+ }\r
+\r
public ushort [] Address {\r
get { return address; }\r
}\r
public AddressFamily AddressFamily {\r
get { return AddressFamily.InterNetworkV6; }\r
}\r
-
- public static bool IsLoopback (IPv6Address addr)
- {
- if (addr.address [7] != 1)
- return false;
-
- int x = addr.address [6] >> 8;
- if (x != 0x7f && x != 0)
- return false;
-
- for (int i = 0; i < 4; i++) {
- if (addr.address [i] != 0)
- return false;
- }
-
- if (addr.address [5] != 0 && addr.address [5] != 0xffff)
- return false;
-
- return true;
- }
-
- private static ushort SwapUShort (ushort number)
- {
- return (ushort) ( ((number >> 8) & 0xFF) + ((number << 8) & 0xFF00) );
- }
-
- // Convert the address into a format expected by the IPAddress (long) ctor
- private int AsIPv4Int ()
- {
- return (SwapUShort (address [7]) << 16) + SwapUShort (address [6]);
- }
-
+\r
+ public static bool IsLoopback (IPv6Address addr)\r
+ {\r
+ if (addr.address [7] != 1)\r
+ return false;\r
+\r
+ int x = addr.address [6] >> 8;\r
+ if (x != 0x7f && x != 0)\r
+ return false;\r
+\r
+ for (int i = 0; i < 4; i++) {\r
+ if (addr.address [i] != 0)\r
+ return false;\r
+ }\r
+\r
+ if (addr.address [5] != 0 && addr.address [5] != 0xffff)\r
+ return false;\r
+\r
+ return true;\r
+ }\r
+\r
+ private static ushort SwapUShort (ushort number)\r
+ {\r
+ return (ushort) ( ((number >> 8) & 0xFF) + ((number << 8) & 0xFF00) );\r
+ }\r
+\r
+ // Convert the address into a format expected by the IPAddress (long) ctor\r
+ private int AsIPv4Int ()\r
+ {\r
+ return (SwapUShort (address [7]) << 16) + SwapUShort (address [6]);\r
+ } \r
+\r
public bool IsIPv4Compatible ()\r
{\r
for (int i = 0; i < 6; i++) \r
if (address [i] != 0)\r
return false;\r
- return (AsIPv4Int () > 1);
+ return (AsIPv4Int () > 1);\r
}\r
\r
public bool IsIPv4Mapped ()\r
if(IsIPv4Mapped())\r
s.Append("ffff:");\r
\r
- s.Append(new IPAddress( AsIPv4Int ()).ToString ());
+ s.Append(new IPAddress( AsIPv4Int ()).ToString ());\r
\r
return s.ToString ();\r
}\r
if (i < 7) s.Append (':');\r
}\r
}\r
+ if (scopeId != 0)\r
+ s.Append ('%').Append (scopeId);\r
return s.ToString ();\r
}\r
-
- public string ToString (bool fullLength)
- {
- if (!fullLength)
- return ToString ();
-
- StringBuilder sb = new StringBuilder ();
- for (int i=0; i < address.Length - 1; i++) {
+\r
+ public string ToString (bool fullLength)\r
+ {\r
+ if (!fullLength)\r
+ return ToString ();\r
+\r
+ StringBuilder sb = new StringBuilder ();\r
+ for (int i=0; i < address.Length - 1; i++) {\r
sb.AppendFormat ("{0:X4}:", address [i]);\r
- }
+ }\r
sb.AppendFormat ("{0:X4}", address [address.Length - 1]);\r
- return sb.ToString ();
+ return sb.ToString ();\r
}\r
\r
/// <returns>\r
for (int i = 0; i < 8; i++) \r
if (this.address [i] != ipv6.address [i])\r
return false;\r
- return true; \r
- } \r
+ return true;\r
+ }\r
\r
System.Net.IPAddress ipv4 = other as System.Net.IPAddress;\r
if (ipv4 != null) {\r
for (int i = 0; i < 5; i++) \r
if (address [i] != 0)\r
- return false; \r
+ return false;\r
\r
if (address [5] != 0 && address [5] != 0xffff)\r
return false;\r
long a = ipv4.InternalIPv4Address;\r
if (address [6] != (ushort) (((int) (a & 0xff) << 8) + ((int) ((a >> 8) & 0xff))) ||\r
address [7] != (ushort) (((int) ((a >> 16) & 0xff) << 8) + ((int) ((a >> 24) & 0xff))))\r
- return false;\r
- \r
+ return false;\r
+\r
return true;\r
}\r
\r