1 //------------------------------------------------------------------------------
2 // <copyright file="IPAddress.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 //------------------------------------------------------------------------------
8 using System.Net.Sockets;
9 using System.Globalization;
13 /// <para>Provides an internet protocol (IP) address.</para>
16 public class IPAddress {
18 public static readonly IPAddress Any = new IPAddress(0x0000000000000000);
19 public static readonly IPAddress Loopback = new IPAddress(0x000000000100007F);
20 public static readonly IPAddress Broadcast = new IPAddress(0x00000000FFFFFFFF);
21 public static readonly IPAddress None = Broadcast;
23 internal const long LoopbackMask = 0x00000000000000FF;
26 // IPv6 Changes: make this internal so other NCL classes that understand about
27 // IPv4 and IPv4 can still access it rather than the obsolete property.
29 internal long m_Address;
32 internal string m_ToString;
34 public static readonly IPAddress IPv6Any = new IPAddress(new byte[]{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },0);
35 public static readonly IPAddress IPv6Loopback = new IPAddress(new byte[]{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 },0);
36 public static readonly IPAddress IPv6None = new IPAddress(new byte[]{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },0);
40 /// Default to IPv4 address
43 private AddressFamily m_Family = AddressFamily.InterNetwork;
44 private ushort[] m_Numbers = new ushort[NumberOfLabels];
45 private long m_ScopeId = 0; // really uint !
46 private int m_HashCode = 0;
48 internal const int IPv4AddressBytes = 4;
49 internal const int IPv6AddressBytes = 16;
51 internal const int NumberOfLabels = IPv6AddressBytes / 2;
56 /// Initializes a new instance of the <see cref='System.Net.IPAddress'/>
57 /// class with the specified
61 public IPAddress(long newAddress) {
62 if (newAddress<0 || newAddress>0x00000000FFFFFFFF) {
63 throw new ArgumentOutOfRangeException("newAddress");
65 m_Address = newAddress;
71 /// Constructor for an IPv6 Address with a specified Scope.
74 public IPAddress(byte[] address,long scopeid) {
77 throw new ArgumentNullException("address");
80 if(address.Length != IPv6AddressBytes){
81 throw new ArgumentException(SR.GetString(SR.dns_bad_ip_address), "address");
84 m_Family = AddressFamily.InterNetworkV6;
86 for (int i = 0; i < NumberOfLabels; i++) {
87 m_Numbers[i] = (ushort)(address[i * 2] * 256 + address[i * 2 + 1]);
91 // Consider: Since scope is only valid for link-local and site-local
92 // addresses we could implement some more robust checking here
94 if ( scopeid < 0 || scopeid > 0x00000000FFFFFFFF ) {
95 throw new ArgumentOutOfRangeException("scopeid");
101 private IPAddress(ushort[] address, uint scopeid)
103 m_Family = AddressFamily.InterNetworkV6;
111 /// Constructor for IPv4 and IPv6 Address.
114 public IPAddress(byte[] address){
116 throw new ArgumentNullException("address");
118 if (address.Length != IPv4AddressBytes && address.Length != IPv6AddressBytes)
120 throw new ArgumentException(SR.GetString(SR.dns_bad_ip_address), "address");
123 if (address.Length == IPv4AddressBytes)
125 m_Family = AddressFamily.InterNetwork;
126 m_Address = ((address[3] << 24 | address[2] <<16 | address[1] << 8| address[0]) & 0x0FFFFFFFF);
129 m_Family = AddressFamily.InterNetworkV6;
131 for (int i = 0; i < NumberOfLabels; i++) {
132 m_Numbers[i] = (ushort)(address[i * 2] * 256 + address[i * 2 + 1]);
138 // we need this internally since we need to interface with winsock
139 // and winsock only understands Int32
141 internal IPAddress(int newAddress) {
142 m_Address = (long)newAddress & 0x00000000FFFFFFFF;
148 /// <para>Converts an IP address string to an <see cref='System.Net.IPAddress'/>
151 public static bool TryParse(string ipString, out IPAddress address) {
152 address = InternalParse(ipString,true);
153 return (address != null);
156 public static IPAddress Parse(string ipString) {
157 return InternalParse(ipString,false);
160 private static IPAddress InternalParse(string ipString, bool tryParse) {
161 if (ipString == null) {
165 throw new ArgumentNullException("ipString");
169 // IPv6 Changes: Detect probable IPv6 addresses and use separate
172 if (ipString.IndexOf(':') != -1 ) {
174 #if !FEATURE_PAL || MONO
176 // If the address string contains the colon character
177 // then it can only be an IPv6 address. Use a separate
178 // parse method to unpick it all. Note: we don't support
179 // port specification at the end of address and so can
180 // make this decision.
182 // We need to make sure that Socket is initialized for this
185 SocketException e = null;
188 if(Socket.OSSupportsIPv6)
190 byte[] bytes = new byte[IPv6AddressBytes];
191 SocketAddress saddr = new SocketAddress(AddressFamily.InterNetworkV6, SocketAddress.IPv6AddressSize);
193 SocketError errorCode =
194 UnsafeNclNativeMethods.OSSOCK.WSAStringToAddress(
196 AddressFamily.InterNetworkV6,
201 if (errorCode ==SocketError.Success)
204 // We have to set up the address by hand now, to avoid initialization
205 // recursion problems that we get if we use IPEndPoint.Create.
207 for (int i=0; i < IPv6AddressBytes; i++)
209 bytes[i] = saddr[i + 8];
214 scope = (long)((saddr[27]<<24) + (saddr[26]<<16) + (saddr[25]<<8 ) + (saddr[24]));
215 return new IPAddress(bytes,scope);
222 e = new SocketException();
230 if (ipString[0] != '[')
231 ipString = ipString + ']'; //for Uri parser to find the terminator.
235 int end = ipString.Length;
236 fixed (char *name = ipString)
238 if (IPv6AddressHelper.IsValidStrict(name, offset, ref end) || (end != ipString.Length))
240 ushort[] numbers = new ushort[NumberOfLabels];
241 string scopeId = null;
242 fixed (ushort *numbPtr = numbers)
244 IPv6AddressHelper.Parse(ipString, numbPtr, 0, ref scopeId);
249 if (scopeId == null || scopeId.Length == 0)
250 return new IPAddress(numbers, 0);
253 scopeId = scopeId.Substring(1);
254 if (UInt32.TryParse(scopeId, NumberStyles.None, null, out result))
255 return new IPAddress(numbers, result);
258 // HACK: .NET does not support scopes with literals at all (API is long based)
259 // For backward Mono compatibility parsing IPv6 addresses like
260 // fe80::bae8:56ff:fe47:af7e%en0 will loose en0 information
262 return new IPAddress(numbers, 0);
270 e = new SocketException(SocketError.InvalidArgument);
273 throw new FormatException(SR.GetString(SR.dns_bad_ip_address), e);
275 #else // !FEATURE_PAL
276 // IPv6 addresses not supported for FEATURE_PAL
277 throw new SocketException(SocketError.OperationNotSupported);
278 #endif // !FEATURE_PAL
281 // The new IPv4 parser is better than the native one, it can parse 0xFFFFFFFF. (It's faster too).
284 // App-Compat: The .NET 4.0 parser used Winsock. When we removed this initialization in 4.5 it
285 // uncovered bugs in IIS's management APIs where they failed to initialize Winsock themselves.
286 // DDCC says we need to keep this for an in place release, but to remove it in the next SxS release.
287 Socket.InitializeSockets();
288 ///////////////////////////
290 int end = ipString.Length;
294 fixed (char *name = ipString)
296 result = IPv4AddressHelper.ParseNonCanonical(name, 0, ref end, true);
300 if (result == IPv4AddressHelper.Invalid || end != ipString.Length)
307 throw new FormatException(SR.GetString(SR.dns_bad_ip_address));
310 // IPv4AddressHelper always returns IP address in a format that we need to reverse.
311 result = (((result & 0x000000FF) << 24) | (((result & 0x0000FF00) << 8)
312 | (((result & 0x00FF0000) >> 8) | ((result & 0xFF000000) >> 24))));
314 return new IPAddress(result);
321 * @deprecated IPAddress.Address is address family dependant, use Equals method for comparison.
325 /// Mark this as deprecated.
328 [Obsolete("This property has been deprecated. It is address family dependent. Please use IPAddress.Equals method to perform comparisons. http://go.microsoft.com/fwlink/?linkid=14202")]
329 public long Address {
332 // IPv6 Changes: Can't do this for IPv6, so throw an exception.
335 if ( m_Family == AddressFamily.InterNetworkV6 ) {
336 throw new SocketException(SocketError.OperationNotSupported);
344 // IPv6 Changes: Can't do this for IPv6 addresses
345 if ( m_Family == AddressFamily.InterNetworkV6 ) {
346 throw new SocketException(SocketError.OperationNotSupported);
349 if (m_Address!=value) {
359 /// Provides a copy of the IPAddress internals as an array of bytes.
362 public byte[] GetAddressBytes() {
364 if (m_Family == AddressFamily.InterNetworkV6 ) {
365 bytes = new byte[NumberOfLabels * 2];
368 for ( int i = 0; i < NumberOfLabels; i++) {
369 bytes[j++] = (byte)((this.m_Numbers[i] >> 8) & 0xFF);
370 bytes[j++] = (byte)((this.m_Numbers[i] ) & 0xFF);
374 bytes = new byte[IPv4AddressBytes];
375 bytes[0] = (byte)(m_Address);
376 bytes[1] = (byte)(m_Address >> 8);
377 bytes[2] = (byte)(m_Address >> 16);
378 bytes[3] = (byte)(m_Address >> 24);
383 public AddressFamily AddressFamily {
391 /// IPv6 Scope identifier. This is really a uint32, but that isn't CLS compliant
394 public long ScopeId {
397 // Not valid for IPv4 addresses
399 if ( m_Family == AddressFamily.InterNetwork ) {
400 throw new SocketException(SocketError.OperationNotSupported);
407 // Not valid for IPv4 addresses
409 if ( m_Family == AddressFamily.InterNetwork ) {
410 throw new SocketException(SocketError.OperationNotSupported);
414 // Consider: Since scope is only valid for link-local and site-local
415 // addresses we could implement some more robust checking here
417 if ( value < 0 || value > 0x00000000FFFFFFFF) {
418 throw new ArgumentOutOfRangeException("value");
420 if (m_ScopeId!=value) {
429 /// Converts the Internet address to either standard dotted quad format
430 /// or standard IPv6 representation.
433 public override string ToString() {
434 if (m_ToString==null) {
436 // IPv6 Changes: generate the IPV6 representation
438 if ( m_Family == AddressFamily.InterNetworkV6 ) {
441 int addressStringLength = 256;
442 StringBuilder addressString = new StringBuilder(addressStringLength);
444 if(Socket.OSSupportsIPv6)
446 SocketAddress saddr = new SocketAddress(AddressFamily.InterNetworkV6, SocketAddress.IPv6AddressSize);
448 for ( int i = 0; i < NumberOfLabels; i++) {
449 saddr[j++] = (byte)(this.m_Numbers[i] >> 8);
450 saddr[j++] = (byte)(this.m_Numbers[i]);
453 saddr[24] = (byte)m_ScopeId;
454 saddr[25] = (byte)(m_ScopeId >> 8);
455 saddr[26] = (byte)(m_ScopeId >> 16);
456 saddr[27] = (byte)(m_ScopeId >> 24);
458 SocketError errorCode =
459 UnsafeNclNativeMethods.OSSOCK.WSAAddressToString(
464 ref addressStringLength);
465 if (errorCode!=SocketError.Success) {
466 throw new SocketException();
471 const string numberFormat = "{0:x4}:{1:x4}:{2:x4}:{3:x4}:{4:x4}:{5:x4}:{6}.{7}.{8}.{9}";
472 string address = String.Format(CultureInfo.InvariantCulture, numberFormat,
473 m_Numbers[0], m_Numbers[1], m_Numbers[2], m_Numbers[3], m_Numbers[4], m_Numbers[5],
474 ((m_Numbers[6] >> 8) & 0xFF), (m_Numbers[6] & 0xFF),
475 ((m_Numbers[7] >> 8) & 0xFF), (m_Numbers[7] & 0xFF));
476 addressString.Append(address);
480 addressString.Append('%').Append((uint)m_ScopeId);
484 m_ToString = addressString.ToString();
485 #else // !FEATURE_PAL
488 var v6 = new IPv6AddressFormatter (m_Numbers, ScopeId);
489 m_ToString = v6.ToString ();
491 // IPv6 addresses not supported for FEATURE_PAL
492 throw new SocketException(SocketError.OperationNotSupported);
494 #endif // !FEATURE_PAL
498 const int MaxSize = 15;
499 int offset = MaxSize;
500 char* addressString = stackalloc char[MaxSize];
501 int number = (int)((m_Address>>24)&0xFF);
503 addressString[--offset] = (char)('0' + number%10);
506 addressString[--offset] = '.';
507 number = (int)((m_Address>>16)&0xFF);
509 addressString[--offset] = (char)('0' + number%10);
512 addressString[--offset] = '.';
513 number = (int)((m_Address>>8)&0xFF);
515 addressString[--offset] = (char)('0' + number%10);
518 addressString[--offset] = '.';
519 number = (int)(m_Address&0xFF);
521 addressString[--offset] = (char)('0' + number%10);
524 m_ToString = new string(addressString, offset, MaxSize-offset);
531 public static long HostToNetworkOrder(long host) {
535 return (((long)HostToNetworkOrder((int)host) & 0xFFFFFFFF) << 32)
536 | ((long)HostToNetworkOrder((int)(host >> 32)) & 0xFFFFFFFF);
539 public static int HostToNetworkOrder(int host) {
543 return (((int)HostToNetworkOrder((short)host) & 0xFFFF) << 16)
544 | ((int)HostToNetworkOrder((short)(host >> 16)) & 0xFFFF);
547 public static short HostToNetworkOrder(short host) {
551 return (short)((((int)host & 0xFF) << 8) | (int)((host >> 8) & 0xFF));
554 public static long NetworkToHostOrder(long network) {
555 return HostToNetworkOrder(network);
557 public static int NetworkToHostOrder(int network) {
558 return HostToNetworkOrder(network);
560 public static short NetworkToHostOrder(short network) {
561 return HostToNetworkOrder(network);
564 public static bool IsLoopback(IPAddress address) {
565 if (address == null) {
566 throw new ArgumentNullException("address");
568 if ( address.m_Family == AddressFamily.InterNetworkV6 ) {
570 // Do Equals test for IPv6 addresses
572 return address.Equals(IPv6Loopback);
575 return ((address.m_Address & IPAddress.LoopbackMask) == (IPAddress.Loopback.m_Address & IPAddress.LoopbackMask));
579 internal bool IsBroadcast {
581 if ( m_Family == AddressFamily.InterNetworkV6 ) {
583 // No such thing as a broadcast address for IPv6
588 return m_Address==Broadcast.m_Address;
595 /// V.Next: Determines if an address is an IPv6 Multicast address
598 public bool IsIPv6Multicast{
600 return ( m_Family == AddressFamily.InterNetworkV6 ) &&
601 ( ( this.m_Numbers[0] & 0xFF00 ) == 0xFF00 );
608 /// V.Next: Determines if an address is an IPv6 Link Local address
611 public bool IsIPv6LinkLocal {
613 return ( m_Family == AddressFamily.InterNetworkV6 ) &&
614 ( ( this.m_Numbers[0] & 0xFFC0 ) == 0xFE80 );
620 /// V.Next: Determines if an address is an IPv6 Site Local address
623 public bool IsIPv6SiteLocal {
625 return ( m_Family == AddressFamily.InterNetworkV6 ) &&
626 ( ( this.m_Numbers[0] & 0xFFC0 ) == 0xFEC0 );
630 public bool IsIPv6Teredo {
632 return ( m_Family == AddressFamily.InterNetworkV6 ) &&
633 ( this.m_Numbers[0] == 0x2001 ) &&
634 ( this.m_Numbers[1] == 0 );
638 // 0:0:0:0:0:FFFF:x.x.x.x
639 public bool IsIPv4MappedToIPv6 {
641 if (AddressFamily != AddressFamily.InterNetworkV6) {
644 for (int i = 0; i < 5; i++) {
645 if (m_Numbers[i] != 0) {
649 return (m_Numbers[5] == 0xFFFF);
653 internal bool Equals(object comparandObj, bool compareScopeId) {
654 IPAddress comparand = comparandObj as IPAddress;
656 if (comparand == null) {
660 // Compare families before address representations
662 if (m_Family != comparand.m_Family) {
665 if ( m_Family == AddressFamily.InterNetworkV6 ) {
667 // For IPv6 addresses, we must compare the full 128bit
670 for ( int i = 0; i < NumberOfLabels; i++) {
671 if (comparand.m_Numbers[i] != this.m_Numbers[i])
675 // In addition, the scope id's must match as well
677 if (comparand.m_ScopeId == this.m_ScopeId)
680 return (compareScopeId? false : true);
684 // For IPv4 addresses, compare the integer representation.
686 return comparand.m_Address == this.m_Address;
692 /// Compares two IP addresses.
695 public override bool Equals(object comparand) {
696 return Equals(comparand, true);
699 public override int GetHashCode() {
701 // For IPv6 addresses, we cannot simply return the integer
702 // representation as the hashcode. Instead, we calculate
703 // the hashcode from the string representation of the address.
705 if ( m_Family == AddressFamily.InterNetworkV6 ) {
706 if ( m_HashCode == 0 )
707 m_HashCode = StringComparer.InvariantCultureIgnoreCase.GetHashCode(ToString());
713 // For IPv4 addresses, we can simply use the integer
716 return unchecked((int)m_Address);
720 // For security, we need to be able to take an IPAddress and make a copy that's immutable and not derived.
721 internal IPAddress Snapshot()
725 case AddressFamily.InterNetwork:
726 return new IPAddress(m_Address);
728 case AddressFamily.InterNetworkV6:
729 return new IPAddress(m_Numbers, (uint) m_ScopeId);
732 throw new InternalException();
735 // IPv4 192.168.1.1 maps as ::FFFF:192.168.1.1
736 public IPAddress MapToIPv6()
738 if (AddressFamily == AddressFamily.InterNetworkV6)
743 ushort[] labels = new ushort[IPAddress.NumberOfLabels];
745 labels[6] = (ushort)(((m_Address & 0x0000FF00) >> 8) | ((m_Address & 0x000000FF) << 8));
746 labels[7] = (ushort)(((m_Address & 0xFF000000) >> 24) | ((m_Address & 0x00FF0000) >> 8));
747 return new IPAddress(labels, 0);
750 // Takes the last 4 bytes of an IPv6 address and converts it to an IPv4 address.
751 // This does not restrict to address with the ::FFFF: prefix because other types of
752 // addresses display the tail segments as IPv4 like Terado.
753 public IPAddress MapToIPv4()
755 if (AddressFamily == AddressFamily.InterNetwork)
760 // Cast the ushort values to a uint and mask with unsigned literal before bit shifting.
761 // Otherwise, we can end up getting a negative value for any IPv4 address that ends with
762 // a byte higher than 127 due to sign extension of the most significant 1 bit.
763 long address = ((((uint)m_Numbers[6] & 0x0000FF00u) >> 8) | (((uint)m_Numbers[6] & 0x000000FFu) << 8)) |
764 (((((uint)m_Numbers[7] & 0x0000FF00u) >> 8) | (((uint)m_Numbers[7] & 0x000000FFu) << 8)) << 16);
766 return new IPAddress(address);
769 } // namespace System.Net