882 lines
31 KiB
C#
882 lines
31 KiB
C#
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Microsoft Research Singularity / NetStack
|
||
|
//
|
||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||
|
//
|
||
|
// File: IPv6.cs
|
||
|
//
|
||
|
|
||
|
using System;
|
||
|
using System.Text;
|
||
|
|
||
|
namespace System.Net.IP
|
||
|
{
|
||
|
/// <summary>
|
||
|
/// IPv6 Address Structure.
|
||
|
/// </summary>
|
||
|
[ CLSCompliant(false) ]
|
||
|
public struct IPv6 : IComparable
|
||
|
{
|
||
|
private uint u0, u1, u2, u3;
|
||
|
|
||
|
/// <summary>
|
||
|
/// The number of bytes in an IPv6 address.
|
||
|
/// </summary>
|
||
|
public const int Length = 16;
|
||
|
|
||
|
/// <summary>
|
||
|
/// The number of bits in an IPv6 address.
|
||
|
/// </summary>
|
||
|
public const int BitCount = 128;
|
||
|
|
||
|
/// <summary>
|
||
|
/// Constructor.
|
||
|
/// </summary>
|
||
|
/// <param name="q0">The most significant 32-bits in
|
||
|
/// host order.</param>
|
||
|
/// <param name="q1">The next significant 32-bits in
|
||
|
/// host order.</param>
|
||
|
/// <param name="q2">The next significant 32-bits in
|
||
|
/// host order.</param>
|
||
|
/// <param name="q3">The least significant 32-bits in
|
||
|
/// host order.</param>
|
||
|
public IPv6(uint q0, uint q1, uint q2, uint q3)
|
||
|
{
|
||
|
u0 = q0;
|
||
|
u1 = q1;
|
||
|
u2 = q2;
|
||
|
u3 = q3;
|
||
|
}
|
||
|
|
||
|
#if HAVE_SYSTEM_NET_IPADDRESS
|
||
|
/// <summary>
|
||
|
/// Constructor
|
||
|
/// </summary>
|
||
|
/// <param name="ipa">An instance of the
|
||
|
/// System.Net.IPAddress class.</param>
|
||
|
/// <exception cref="ArgumentNullException">Thrown when
|
||
|
/// argument is null.</exception>
|
||
|
/// <exception cref="ArgumentException">Thrown when
|
||
|
/// AddressFamily of <c>ipa</c>is other than
|
||
|
/// InterNetwork6</exception>
|
||
|
public IPv6(IPAddress ipa)
|
||
|
{
|
||
|
if (ipa == null)
|
||
|
{
|
||
|
throw new ArgumentNullException();
|
||
|
}
|
||
|
|
||
|
byte [] data = ipa.GetAddressBytes();
|
||
|
if (data.Length != Length)
|
||
|
{
|
||
|
throw new ArgumentException();
|
||
|
}
|
||
|
u0 = (uint)((data[0] << 24) | (data[1] << 16) |
|
||
|
(data[2] << 8) | (data[3]));
|
||
|
u1 = (uint)((data[4] << 24) | (data[5] << 16) |
|
||
|
(data[6] << 8) | (data[7]));
|
||
|
u2 = (uint)((data[8] << 24) | (data[9] << 16) |
|
||
|
(data[10] << 8) | (data[11]));
|
||
|
u3 = (uint)((data[12] << 24) | (data[13] << 16) |
|
||
|
(data[14] << 8) | (data[15]));
|
||
|
}
|
||
|
#endif // HAVE_SYSTEM_NET_IPADDRESS
|
||
|
|
||
|
/// <summary>
|
||
|
/// Provide a copy of the <c>IPv6</c> address as an array of bytes.
|
||
|
/// </summary>
|
||
|
/// <returns>Array of bytes, ordered MSB to LSB.</returns>
|
||
|
public byte[] GetAddressBytes()
|
||
|
{
|
||
|
return new byte[Length] {
|
||
|
(byte)(u0 >> 24), (byte)(u0 >> 16),
|
||
|
(byte)(u0 >> 8), (byte)(u0),
|
||
|
(byte)(u1 >> 24), (byte)(u1 >> 16),
|
||
|
(byte)(u1 >> 8), (byte)(u1),
|
||
|
(byte)(u2 >> 24), (byte)(u2 >> 16),
|
||
|
(byte)(u2 >> 8), (byte)(u2),
|
||
|
(byte)(u3 >> 24), (byte)(u3 >> 16),
|
||
|
(byte)(u3 >> 8), (byte)(u3)
|
||
|
};
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Create an IPv6 address representing a netmask.
|
||
|
/// </summary>
|
||
|
/// <param name="maskLength"></param>
|
||
|
/// <returns>An IPv6 instance.</returns>
|
||
|
/// <exception cref="ArgumentException">Thrown if maskLength is
|
||
|
/// outside of the range [0,128].</exception>
|
||
|
public static IPv6 NetMask(int maskLength)
|
||
|
{
|
||
|
if ((maskLength > BitCount) || (maskLength < 0))
|
||
|
{
|
||
|
throw new
|
||
|
ArgumentException("Mask length greater than possible.");
|
||
|
}
|
||
|
return IPv6.AllOnes << (BitCount - maskLength);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Create an IPv6 address representing an IPv4 node that is only
|
||
|
/// IPv4 capable.
|
||
|
/// </summary>
|
||
|
public static IPv6 CreateIPv4OnlyNodeAddress(IPv4 a)
|
||
|
{
|
||
|
return new IPv6(0, 0, 0xffff, (uint)a);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Create an IPv6 address representing an IPv4 node is IPv4
|
||
|
/// and IPv6 capable.
|
||
|
/// </summary>
|
||
|
public static IPv6 CreateIPv4NodeAddress(IPv4 a)
|
||
|
{
|
||
|
return new IPv6(0, 0, 0x0, (uint)a);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Create an IPv6 address from bytes in an array. The bytes
|
||
|
/// are assumed to be in the order of MSB to LSB.
|
||
|
/// </summary>
|
||
|
/// <param name="data">Byte array to read address from.</param>
|
||
|
/// <param name="offset">Offset in bytes of starting point.</param>
|
||
|
/// <exception cref="ArgumentNullException">Thrown if the array
|
||
|
/// is null.</exception>
|
||
|
/// <exception cref="ArgumentException">Thrown if there are less
|
||
|
/// than 16 bytes from the offset to the end of the array.</exception>
|
||
|
public static IPv6 ParseBytes(byte [] data, int offset)
|
||
|
{
|
||
|
if (data == null)
|
||
|
{
|
||
|
throw new ArgumentNullException();
|
||
|
}
|
||
|
if (data.Length - offset < Length)
|
||
|
{
|
||
|
throw new ArgumentException("Byte array length not 16.");
|
||
|
}
|
||
|
return new IPv6((uint)((data[offset + 0] << 24) |
|
||
|
(data[offset + 1] << 16) |
|
||
|
(data[offset + 2] << 8) |
|
||
|
(data[offset + 3])),
|
||
|
(uint)((data[offset + 4] << 24) |
|
||
|
(data[offset + 5] << 16) |
|
||
|
(data[offset + 6] << 8) |
|
||
|
(data[offset + 7])),
|
||
|
(uint)((data[offset + 8] << 24) |
|
||
|
(data[offset + 9] << 16) |
|
||
|
(data[offset + 10] << 8) |
|
||
|
(data[offset + 11])),
|
||
|
(uint)((data[offset + 12] << 24) |
|
||
|
(data[offset + 13] << 16) |
|
||
|
(data[offset + 14] << 8) |
|
||
|
(data[offset + 15]))
|
||
|
);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Create an IPv6 address from bytes in an array.
|
||
|
/// </summary>
|
||
|
/// <exception cref="ArgumentNullException">Thrown if the array
|
||
|
/// is null.</exception>
|
||
|
/// <exception cref="ArgumentException">Thrown if there are less
|
||
|
/// than 16 bytes in the array.</exception>
|
||
|
public static IPv6 ParseBytes(byte [] data)
|
||
|
{
|
||
|
return ParseBytes(data, 0);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Converts characters in a range to parts of an IPv6 address.
|
||
|
/// <param name="ipString">Input string.</param>
|
||
|
/// <param name="start">Start position in <c>ipString</c></param>
|
||
|
/// <param name="end">End position in <c>ipString</c></param>
|
||
|
/// <param name="maxValues">The maximum number of 16bit address
|
||
|
/// components to accept.</param>
|
||
|
/// <param name="values">Array to receive 16bit address components.
|
||
|
/// </param>
|
||
|
/// </summary>
|
||
|
private static int Parse(string! ipString, int start, int end,
|
||
|
int maxValues, ref ushort[]! values)
|
||
|
{
|
||
|
const string hex = "00112233445566778899aAbBcCdDeEfF";
|
||
|
|
||
|
int valueIndex = 0;
|
||
|
int digits = 0;
|
||
|
|
||
|
for (int i = start; i < end; i++)
|
||
|
{
|
||
|
int n = hex.IndexOf(ipString[i]);
|
||
|
digits ++;
|
||
|
if (n >= 0)
|
||
|
{
|
||
|
if (valueIndex == maxValues || digits > 4)
|
||
|
{
|
||
|
// About to access value beyond specified range
|
||
|
throw new FormatException();
|
||
|
}
|
||
|
uint v = values[valueIndex];
|
||
|
v = v * 16 + (uint)(n / 2);
|
||
|
if (v > 0xffffu)
|
||
|
{
|
||
|
throw new FormatException();
|
||
|
}
|
||
|
values[valueIndex] = (ushort)v;
|
||
|
}
|
||
|
else if (ipString[i] == ':')
|
||
|
{
|
||
|
// Reached Separator or end
|
||
|
valueIndex++;
|
||
|
digits = 0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Invalid Character
|
||
|
throw new FormatException();
|
||
|
}
|
||
|
}
|
||
|
return valueIndex + 1;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Converts an IP address string into an IPv6 instance. This string
|
||
|
/// must be a pure IPv6 representation -- IPv4 representations are not
|
||
|
/// supported.
|
||
|
/// </summary>
|
||
|
/// <exception cref="ArgumentNullException">Thrown if
|
||
|
/// <c>ipString</c> is null.</exception>
|
||
|
/// <exception cref="FormatException">Thrown if
|
||
|
/// <c>ipString</c> is invalid.</exception>
|
||
|
public static IPv6 Parse(string ipString)
|
||
|
{
|
||
|
if (ipString == null)
|
||
|
throw new ArgumentNullException();
|
||
|
|
||
|
int zeroSep = ipString.IndexOf("::");
|
||
|
|
||
|
ushort[]! lhs = new ushort [8];
|
||
|
int nlhs;
|
||
|
|
||
|
if (zeroSep >= 0)
|
||
|
{
|
||
|
nlhs = Parse(ipString, 0, zeroSep, 8, ref lhs);
|
||
|
ushort[]! rhs = new ushort [8];
|
||
|
int nrhs = Parse(ipString, zeroSep + 2, ipString.Length,
|
||
|
8 - nlhs, ref rhs);
|
||
|
if (nrhs + nlhs > 8)
|
||
|
{
|
||
|
throw new FormatException("Too many address components");
|
||
|
}
|
||
|
for (int i = 0; i < nrhs; i++)
|
||
|
{
|
||
|
lhs[8 - nrhs + i] = rhs[i];
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
nlhs = Parse(ipString, 0, ipString.Length, 8, ref lhs);
|
||
|
}
|
||
|
|
||
|
return new IPv6( ((uint)lhs[0] << 16) | ((uint)lhs[1]),
|
||
|
((uint)lhs[2] << 16) | ((uint)lhs[3]),
|
||
|
((uint)lhs[4] << 16) | ((uint)lhs[5]),
|
||
|
((uint)lhs[6] << 16) | ((uint)lhs[7])
|
||
|
);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Converts an IP address string into an IPv6 instance.
|
||
|
/// </summary>
|
||
|
/// <exception cref="ArgumentNullException">Thrown if
|
||
|
/// <c>ipString</c> is null.</exception>
|
||
|
/// <returns> <c>true</c> on success, <c>false</c> on failure.</returns>
|
||
|
public static bool Parse(string ipString, out IPv6 address)
|
||
|
{
|
||
|
try
|
||
|
{
|
||
|
address = Parse(ipString);
|
||
|
}
|
||
|
catch (FormatException)
|
||
|
{
|
||
|
address = IPv6.Zero;
|
||
|
return false;
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Writes network-order byte representation of IPv6 address
|
||
|
/// into buffer at a specified offset.
|
||
|
/// </summary>
|
||
|
/// <exception cref="ArgumentNullException">Thrown if <c>buffer</c>
|
||
|
/// argument is null. </exception>
|
||
|
/// <exception cref="ArgumentException">Thrown if there is
|
||
|
/// insufficient space between <c>outputOffset</c> and the end of
|
||
|
/// <c>buffer</c> to write out the IP address.</exception>
|
||
|
public int CopyOut(byte[] buffer, int outputOffset)
|
||
|
{
|
||
|
if (buffer == null)
|
||
|
{
|
||
|
throw new ArgumentNullException();
|
||
|
}
|
||
|
if (buffer.Length - outputOffset < Length)
|
||
|
{
|
||
|
throw new ArgumentException("Byte array too short.");
|
||
|
}
|
||
|
buffer[outputOffset + 0] = (byte)(u0 >> 24);
|
||
|
buffer[outputOffset + 1] = (byte)(u0 >> 16);
|
||
|
buffer[outputOffset + 2] = (byte)(u0 >> 8);
|
||
|
buffer[outputOffset + 3] = (byte)(u0);
|
||
|
|
||
|
buffer[outputOffset + 4] = (byte)(u1 >> 24);
|
||
|
buffer[outputOffset + 5] = (byte)(u1 >> 16);
|
||
|
buffer[outputOffset + 6] = (byte)(u1 >> 8);
|
||
|
buffer[outputOffset + 7] = (byte)(u1);
|
||
|
|
||
|
buffer[outputOffset + 8] = (byte)(u2 >> 24);
|
||
|
buffer[outputOffset + 9] = (byte)(u2 >> 16);
|
||
|
buffer[outputOffset + 10] = (byte)(u2 >> 8);
|
||
|
buffer[outputOffset + 11] = (byte)(u2);
|
||
|
|
||
|
buffer[outputOffset + 12] = (byte)(u3 >> 24);
|
||
|
buffer[outputOffset + 13] = (byte)(u3 >> 16);
|
||
|
buffer[outputOffset + 14] = (byte)(u3 >> 8);
|
||
|
buffer[outputOffset + 15] = (byte)(u3);
|
||
|
|
||
|
return Length;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// The less-than operator for two IPv6 addresses.
|
||
|
/// </summary>
|
||
|
/// <param name="lhs"></param>
|
||
|
/// <param name="rhs"></param>
|
||
|
/// <returns>True if the 128-bit number representing the <c>lhs</c>
|
||
|
/// is less than <c>rhs</c>.</returns>
|
||
|
public static bool operator < (IPv6 lhs, IPv6 rhs)
|
||
|
{
|
||
|
if (lhs.u0 != rhs.u0)
|
||
|
return lhs.u0 < rhs.u0;
|
||
|
if (lhs.u1 != rhs.u1)
|
||
|
return lhs.u1 < rhs.u1;
|
||
|
if (lhs.u2 != rhs.u2)
|
||
|
return lhs.u2 < rhs.u2;
|
||
|
return lhs.u3 < rhs.u3;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// The less-than-or-equal-to operator for two IPv6 addresses.
|
||
|
/// </summary>
|
||
|
/// <param name="lhs"></param>
|
||
|
/// <param name="rhs"></param>
|
||
|
/// <returns>True if the 128-bit number representing the <c>lhs</c>
|
||
|
/// is less than or equal to <c>rhs</c>.</returns>
|
||
|
public static bool operator <= (IPv6 lhs, IPv6 rhs)
|
||
|
{
|
||
|
if (rhs.u0 > lhs.u0 || rhs.u1 > lhs.u1 || rhs.u2 > lhs.u2)
|
||
|
return false;
|
||
|
|
||
|
return lhs.u3 <= rhs.u3;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// The greater-than operator for two IPv6 addresses.
|
||
|
/// </summary>
|
||
|
/// <param name="lhs"></param>
|
||
|
/// <param name="rhs"></param>
|
||
|
/// <returns>True if the 128-bit number representing the <c>lhs</c>
|
||
|
/// is greater than <c>rhs</c>.</returns>
|
||
|
public static bool operator > (IPv6 lhs, IPv6 rhs)
|
||
|
{
|
||
|
if (lhs.u0 != rhs.u0)
|
||
|
return lhs.u0 > rhs.u0;
|
||
|
if (lhs.u1 != rhs.u1)
|
||
|
return lhs.u1 > rhs.u1;
|
||
|
if (lhs.u2 != rhs.u2)
|
||
|
return lhs.u2 > rhs.u2;
|
||
|
return lhs.u3 > rhs.u3;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// The greater-than-or-equal-to operator for two IPv6 addresses.
|
||
|
/// </summary>
|
||
|
/// <param name="lhs"></param>
|
||
|
/// <param name="rhs"></param>
|
||
|
/// <returns>True if the 128-bit number representing the <c>lhs</c>
|
||
|
/// is greater than or equal to <c>rhs</c>.</returns>
|
||
|
public static bool operator >= (IPv6 lhs, IPv6 rhs)
|
||
|
{
|
||
|
if (lhs.u0 < rhs.u0 || lhs.u1 < rhs.u1 || lhs.u2 < rhs.u2)
|
||
|
return false;
|
||
|
|
||
|
return lhs.u3 >= rhs.u3;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Equals operator.
|
||
|
/// </summary>
|
||
|
/// <param name="lhs"></param>
|
||
|
/// <param name="rhs"></param>
|
||
|
/// <returns>True if the addresses represented by <c>lhs</c> and
|
||
|
/// <c>rhs</c> are the same.</returns>
|
||
|
public static bool operator == (IPv6 lhs, IPv6 rhs)
|
||
|
{
|
||
|
return ((lhs.u0 == rhs.u0) && (lhs.u1 == rhs.u1) &&
|
||
|
(lhs.u2 == rhs.u2) && (lhs.u3 == rhs.u3));
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Not-equals operator.
|
||
|
/// </summary>
|
||
|
/// <param name="lhs"></param>
|
||
|
/// <param name="rhs"></param>
|
||
|
/// <returns>True if the addresses represented by <c>lhs</c> and
|
||
|
/// <c>rhs</c> are different.</returns>
|
||
|
public static bool operator != (IPv6 lhs, IPv6 rhs)
|
||
|
{
|
||
|
return ((lhs.u0 != rhs.u0) || (lhs.u1 != rhs.u1) ||
|
||
|
(lhs.u2 != rhs.u2) || (lhs.u3 != rhs.u3));
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Bit-wise AND operator.
|
||
|
/// </summary>
|
||
|
/// <param name="lhs"></param>
|
||
|
/// <param name="rhs"></param>
|
||
|
/// <returns>An IPv6 instance.</returns>
|
||
|
public static IPv6 operator & (IPv6 lhs, IPv6 rhs)
|
||
|
{
|
||
|
return new IPv6(lhs.u0 & rhs.u0, lhs.u1 & rhs.u1,
|
||
|
lhs.u2 & rhs.u2, lhs.u3 & rhs.u3);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Bit-wise OR operator.
|
||
|
/// </summary>
|
||
|
/// <param name="lhs"></param>
|
||
|
/// <param name="rhs"></param>
|
||
|
/// <returns>An IPv6 instance.</returns>
|
||
|
public static IPv6 operator | (IPv6 lhs, IPv6 rhs)
|
||
|
{
|
||
|
return new IPv6(lhs.u0 | rhs.u0, lhs.u1 | rhs.u1,
|
||
|
lhs.u2 | rhs.u2, lhs.u3 | rhs.u3);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Bit-wise XOR operator.
|
||
|
/// </summary>
|
||
|
/// <param name="lhs"></param>
|
||
|
/// <param name="rhs"></param>
|
||
|
/// <returns>An IPv6 instance.</returns>
|
||
|
public static IPv6 operator ^ (IPv6 lhs, IPv6 rhs)
|
||
|
{
|
||
|
return new IPv6(lhs.u0 ^ rhs.u0, lhs.u1 ^ rhs.u1,
|
||
|
lhs.u2 ^ rhs.u2, lhs.u3 ^ rhs.u3);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Bit-wise NOT operator.
|
||
|
/// </summary>
|
||
|
/// <param name="ipv6"></param>
|
||
|
/// <returns>An IPv6 instance.</returns>
|
||
|
public static IPv6 operator ~ (IPv6 ipv6)
|
||
|
{
|
||
|
return new IPv6(~ipv6.u0, ~ipv6.u1, ~ipv6.u2, ~ipv6.u3);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Increment IPv6 address.
|
||
|
/// </summary>
|
||
|
/// <param name="ipv6"></param>
|
||
|
/// <returns>An IPv6 instance.</returns>
|
||
|
public static IPv6 operator ++ (IPv6 ipv6)
|
||
|
{
|
||
|
uint u3 = ipv6.u3 + 1;
|
||
|
if (u3 > ipv6.u3)
|
||
|
return new IPv6(ipv6.u0, ipv6.u1, ipv6.u2, u3);
|
||
|
uint u2 = ipv6.u2 + 1;
|
||
|
if (u2 > ipv6.u2)
|
||
|
return new IPv6(ipv6.u0, ipv6.u1, u2, u3);
|
||
|
uint u1 = ipv6.u1 + 1;
|
||
|
if (u1 > ipv6.u1)
|
||
|
return new IPv6(ipv6.u0, u1, u2, u3);
|
||
|
uint u0 = ipv6.u0 + 1;
|
||
|
return new IPv6(u0, u1, u2, u3);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Decrement IPv6 address.
|
||
|
/// </summary>
|
||
|
/// <param name="ipv6"></param>
|
||
|
/// <returns>An IPv6 instance.</returns>
|
||
|
public static IPv6 operator -- (IPv6 ipv6)
|
||
|
{
|
||
|
uint u3 = ipv6.u3 - 1;
|
||
|
if (u3 < ipv6.u3)
|
||
|
return new IPv6(ipv6.u0, ipv6.u1, ipv6.u2, u3);
|
||
|
uint u2 = ipv6.u2 - 1;
|
||
|
if (u2 < ipv6.u2)
|
||
|
return new IPv6(ipv6.u0, ipv6.u1, u2, u3);
|
||
|
uint u1 = ipv6.u1 - 1;
|
||
|
if (u1 < ipv6.u1)
|
||
|
return new IPv6(ipv6.u0, u1, u2, u3);
|
||
|
uint u0 = ipv6.u0 - 1;
|
||
|
return new IPv6(u0, u1, u2, u3);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Right-shift operator.
|
||
|
/// </summary>
|
||
|
/// <param name="addr">Address to be shifted.</param>
|
||
|
/// <param name="n">Number of bits to shift-by.</param>
|
||
|
/// <returns>An IPv6 address.</returns>
|
||
|
public static IPv6 operator >> (IPv6 addr, int n)
|
||
|
{
|
||
|
switch (n >> 5)
|
||
|
{
|
||
|
case 3:
|
||
|
addr.u3 = addr.u0;
|
||
|
addr.u0 = addr.u1 = addr.u2 = 0;
|
||
|
break;
|
||
|
case 2:
|
||
|
addr.u3 = addr.u1;
|
||
|
addr.u2 = addr.u0;
|
||
|
addr.u0 = addr.u1 = 0;
|
||
|
break;
|
||
|
case 1:
|
||
|
addr.u3 = addr.u2;
|
||
|
addr.u2 = addr.u1;
|
||
|
addr.u1 = addr.u0;
|
||
|
addr.u0 = 0;
|
||
|
break;
|
||
|
case 0:
|
||
|
break;
|
||
|
default:
|
||
|
if (n < 0)
|
||
|
return addr << (-n);
|
||
|
return Zero;
|
||
|
}
|
||
|
|
||
|
n = n & 0x1f;
|
||
|
if (n != 0)
|
||
|
{
|
||
|
int m = 32 - n;
|
||
|
addr.u3 = (addr.u3 >> n) | (addr.u2 << m);
|
||
|
addr.u2 = (addr.u2 >> n) | (addr.u1 << m);
|
||
|
addr.u1 = (addr.u1 >> n) | (addr.u0 << m);
|
||
|
addr.u0 = (addr.u0 >> n);
|
||
|
}
|
||
|
return new IPv6(addr.u0, addr.u1, addr.u2, addr.u3);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Left-shift operator.
|
||
|
/// </summary>
|
||
|
/// <param name="addr">Address to be shifted.</param>
|
||
|
/// <param name="n">Number of bits to shift-by.</param>
|
||
|
/// <returns>An IPv6 address.</returns>
|
||
|
public static IPv6 operator << (IPv6 addr, int n)
|
||
|
{
|
||
|
switch (n >> 5)
|
||
|
{
|
||
|
case 3:
|
||
|
addr.u0 = addr.u3;
|
||
|
addr.u1 = addr.u2 = addr.u3 = 0;
|
||
|
break;
|
||
|
case 2:
|
||
|
addr.u0 = addr.u2;
|
||
|
addr.u1 = addr.u3;
|
||
|
addr.u2 = addr.u3 = 0;
|
||
|
break;
|
||
|
case 1:
|
||
|
addr.u0 = addr.u1;
|
||
|
addr.u1 = addr.u2;
|
||
|
addr.u2 = addr.u3;
|
||
|
addr.u3 = 0;
|
||
|
break;
|
||
|
case 0:
|
||
|
break;
|
||
|
default:
|
||
|
if (n < 0)
|
||
|
return addr >> (-n);
|
||
|
return Zero;
|
||
|
}
|
||
|
n = n & 0x1f;
|
||
|
if (n != 0)
|
||
|
{
|
||
|
int m = 32 - n;
|
||
|
addr.u0 = (addr.u0 << n) | (addr.u1 >> m);
|
||
|
addr.u1 = (addr.u1 << n) | (addr.u2 >> m);
|
||
|
addr.u2 = (addr.u2 << n) | (addr.u3 >> m);
|
||
|
addr.u3 = (addr.u3 << n);
|
||
|
}
|
||
|
return new IPv6(addr.u0, addr.u1, addr.u2, addr.u3);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Get a single bit from an IPv6 address.
|
||
|
/// </summary>
|
||
|
/// <param name="bitIndex">Index of bit (ordered from msb-to-lsb)
|
||
|
/// </param>
|
||
|
/// <returns>Returns <c>true</c> if bit is set, false if
|
||
|
/// bit is unset or <paramref name="bitIndex" /> is out
|
||
|
/// of range.
|
||
|
/// </returns>
|
||
|
public bool GetBit(int bitIndex)
|
||
|
{
|
||
|
if (bitIndex < 0 || bitIndex >= BitCount)
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
int dwordIndex = bitIndex / 32;
|
||
|
uint mask = 1u << (31 - (bitIndex & 31));
|
||
|
|
||
|
switch (dwordIndex)
|
||
|
{
|
||
|
case 0:
|
||
|
return (u0 & mask) == mask;
|
||
|
case 1:
|
||
|
return (u1 & mask) == mask;
|
||
|
case 2:
|
||
|
return (u2 & mask) == mask;
|
||
|
}
|
||
|
return (u3 & mask) == mask;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Get the mask length from an IPv6 address representing a netmask.
|
||
|
/// </summary>
|
||
|
/// <param name="netmask"></param>
|
||
|
public static int GetMaskLength(IPv6 netmask)
|
||
|
{
|
||
|
int i = 0;
|
||
|
while (netmask.GetBit(i) == true)
|
||
|
{
|
||
|
i++;
|
||
|
}
|
||
|
return i;
|
||
|
}
|
||
|
|
||
|
#if HAVE_SYSTEM_NET_IPADDRESS
|
||
|
/// <summary>
|
||
|
/// Cast <c>IPv6</c> instance into a <c>System.Net.IPAddress</c>
|
||
|
/// </summary>
|
||
|
/// <param name="ipv6"></param>
|
||
|
/// <returns>An <c>IPAddress</c> instance.</returns>
|
||
|
public static explicit operator IPAddress(IPv6 ipv6)
|
||
|
{
|
||
|
return new IPAddress(ipv6.GetAddressBytes());
|
||
|
}
|
||
|
#endif // HAVE_SYSTEM_NET_IPADDRESS
|
||
|
|
||
|
/// <summary>
|
||
|
/// Determines whether two Object instances are equal.
|
||
|
/// </summary>
|
||
|
/// <param name="o">Object to be compared to.</param>
|
||
|
/// <returns>True if <c>o</c> is an IPv6 address and numerically
|
||
|
/// the same as instance.</returns>
|
||
|
public override bool Equals(object o)
|
||
|
{
|
||
|
if (o is IPv6)
|
||
|
{
|
||
|
IPv6 ipo = (IPv6)o;
|
||
|
return this == ipo;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Compute numeric hash of IPv6 instance. Value is
|
||
|
/// suitable for use in hashing algorithms and data
|
||
|
/// structures like a hash table.
|
||
|
/// </summary>
|
||
|
public override int GetHashCode()
|
||
|
{
|
||
|
return (int)(u0 ^ u1 ^ u2 ^ u3);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Determine if IPv6 address represents an IPv4 capable node.
|
||
|
/// </summary>
|
||
|
public bool RepresentsIPv4Address()
|
||
|
{
|
||
|
// RFC1884 Section 2.4.4
|
||
|
return (u0 == 0) && (u1 == 0) && ((u2 >> 16) == 0) &&
|
||
|
((u2 & 0xffff) == 0xffff ||
|
||
|
((u2 & 0xffff) == 0) && (u3 != 0));
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Determine if IPv6 address represents IPv4 only capable node.
|
||
|
/// </summary>
|
||
|
public bool RepresentsIPv4OnlyAddress()
|
||
|
{
|
||
|
// RFC1884 Section 2.4.4
|
||
|
return (u0 == 0) && (u1 == 0) && ((u2 >> 16) == 0) &&
|
||
|
((u2 & 0xffff) == 0xffff);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Determine if IPv6 address represents a link-local address.
|
||
|
/// </summary>
|
||
|
public bool IsLinkLocalAddress()
|
||
|
{
|
||
|
return (u0 & 0xffc00000) == 0xfe800000; // RFC1884 Section 2.3
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Determine if IPv6 address represents a site-local address.
|
||
|
/// </summary>
|
||
|
public bool IsSiteLocalAddress()
|
||
|
{
|
||
|
return (u0 & 0xffc00000) == 0xfec00000; // RFC1884 Section 2.3
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Indicates whether instance represents a native IPv6
|
||
|
/// loopback address.
|
||
|
/// </summary>
|
||
|
/// <returns>True if instance represents a loopback
|
||
|
/// address.</returns>
|
||
|
public bool IsLoopback()
|
||
|
{
|
||
|
return (this == IPv6.Loopback);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Determine if IPv6 address represents a native IPv6
|
||
|
/// multicast address.
|
||
|
/// </summary>
|
||
|
public bool IsMulticast()
|
||
|
{
|
||
|
return ((u0 & 0xff000000) == 0xff000000);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Extract embedded IPv4 address.
|
||
|
/// </summary>
|
||
|
/// <returns>Returns IPv4 address on success and <c>IPv4.Any</c>
|
||
|
/// if address does not represent an IPv4 address.</returns>
|
||
|
public IPv4 GetIPv4Address()
|
||
|
{
|
||
|
if (u0 == 0 && u1 == 0 && (u2 == 0 || u2 == 0xffff))
|
||
|
{
|
||
|
return new IPv4(u3);
|
||
|
}
|
||
|
return IPv4.Any;
|
||
|
}
|
||
|
|
||
|
private string! NativeStringRepresentation()
|
||
|
{
|
||
|
// Copy address into array of ushorts to make it easy to find
|
||
|
// region a region of zeroes per RFC 1884. We only find the
|
||
|
// first region rather than attempt to find the longest.
|
||
|
ushort [] words = new ushort [8] {
|
||
|
(ushort)(u0 >> 16), (ushort)(u0 & 0xffffU),
|
||
|
(ushort)(u1 >> 16), (ushort)(u1 & 0xffffU),
|
||
|
(ushort)(u2 >> 16), (ushort)(u2 & 0xffffU),
|
||
|
(ushort)(u3 >> 16), (ushort)(u3 & 0xffffU)
|
||
|
};
|
||
|
|
||
|
// Find start of the zero block
|
||
|
int zStart;
|
||
|
for (zStart = 0; zStart < words.Length; zStart++)
|
||
|
{
|
||
|
if (words[zStart] == 0)
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// Find the end of the zero block
|
||
|
int zEnd;
|
||
|
for (zEnd = zStart + 1; zEnd < words.Length; zEnd++)
|
||
|
{
|
||
|
if (words[zEnd] != 0)
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// Max size is 8 * 4 hexdigits + 7 * 1 digit separator
|
||
|
StringBuilder sb = new StringBuilder(null, 8 * 4 + 7 * 1);
|
||
|
for (int i = 0; i < zStart; i++)
|
||
|
{
|
||
|
if (i > 0)
|
||
|
sb.AppendFormat(":{0:x}", words[i]);
|
||
|
else
|
||
|
sb.AppendFormat("{0:x}", words[i]);
|
||
|
}
|
||
|
|
||
|
if (zStart == words.Length)
|
||
|
return sb.ToString();
|
||
|
|
||
|
sb.Append("::");
|
||
|
for (int i = zEnd; i < words.Length; i++)
|
||
|
{
|
||
|
if (i > zEnd)
|
||
|
sb.AppendFormat(":{0:x}", words[i]);
|
||
|
else
|
||
|
sb.AppendFormat("{0:x}", words[i]);
|
||
|
}
|
||
|
|
||
|
return sb.ToString();
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Returns a string representing IPv6 instance.
|
||
|
/// </summary>
|
||
|
public override string! ToString()
|
||
|
{
|
||
|
#if NOTYET
|
||
|
if (RepresentsIPv4OnlyAddress() == true)
|
||
|
{
|
||
|
return String.Format("::ffff:{0}.{1}.{2}.{3}", u3 >> 24,
|
||
|
(u3 >> 16) & 0xff, (u3 >> 8) & 0xff,
|
||
|
u3 & 0xff);
|
||
|
}
|
||
|
else if (RepresentsIPv4Address() == true)
|
||
|
{
|
||
|
return String.Format("::{0}.{1}.{2}.{3}", u3 >> 24,
|
||
|
(u3 >> 16) & 0xff, (u3 >> 8) & 0xff,
|
||
|
u3 & 0xff);
|
||
|
}
|
||
|
#endif // NOTYET
|
||
|
return NativeStringRepresentation();
|
||
|
}
|
||
|
|
||
|
public int CompareTo(object other)
|
||
|
{
|
||
|
if (other == null)
|
||
|
return 1;
|
||
|
if (other is IPv6)
|
||
|
{
|
||
|
IPv6 value = (IPv6) other;
|
||
|
if (this < value) return -1;
|
||
|
if (this > value) return +1;
|
||
|
return 0;
|
||
|
}
|
||
|
throw new ArgumentException ("Arg_MustBeIPv6");
|
||
|
}
|
||
|
|
||
|
|
||
|
/// <summary>
|
||
|
/// IPv6 address representing unspecified address.
|
||
|
/// </summary>
|
||
|
public static readonly IPv6 Any = new IPv6(0U, 0U, 0U, 0U);
|
||
|
|
||
|
/// <summary>
|
||
|
/// IPv6 address with all bits set to zero.
|
||
|
/// </summary>
|
||
|
public static readonly IPv6 Zero = new IPv6(0U, 0U, 0U, 0U);
|
||
|
|
||
|
/// <summary>
|
||
|
/// IPv6 loopback address.
|
||
|
/// </summary>
|
||
|
public static readonly IPv6 Loopback = new IPv6(0U, 0U, 0U, 1U);
|
||
|
|
||
|
/// <summary>
|
||
|
/// IPv6 address with all bits set to one.
|
||
|
/// </summary>
|
||
|
public static readonly IPv6 AllOnes = new IPv6(~0U, ~0U, ~0U, ~0U);
|
||
|
}
|
||
|
} // namespace System.Net.IP
|