e3273c4c9c95a17746b5cae33d505851391c123c
[mono.git] / mcs / class / referencesource / System / net / System / Net / IPAddress.cs
1 //------------------------------------------------------------------------------
2 // <copyright file="IPAddress.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 //------------------------------------------------------------------------------
6
7 namespace System.Net {
8     using System.Net.Sockets;
9     using System.Globalization;
10     using System.Text;
11
12     /// <devdoc>
13     ///    <para>Provides an internet protocol (IP) address.</para>
14     /// </devdoc>
15     [Serializable]
16     public class IPAddress {
17
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;
22
23         internal const long LoopbackMask = 0x00000000000000FF;
24
25         //
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.
28         //
29         internal long m_Address;
30
31         [NonSerialized]
32         internal string m_ToString;
33
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);
37
38         /// <devdoc>
39         ///   <para>
40         ///     Default to IPv4 address
41         ///   </para>
42         /// </devdoc>
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;
47
48         internal const int IPv4AddressBytes =  4;
49         internal const int IPv6AddressBytes = 16;
50
51         internal const int NumberOfLabels = IPv6AddressBytes / 2;
52
53
54         /// <devdoc>
55         ///    <para>
56         ///       Initializes a new instance of the <see cref='System.Net.IPAddress'/>
57         ///       class with the specified
58         ///       address.
59         ///    </para>
60         /// </devdoc>
61         public IPAddress(long newAddress) {
62             if (newAddress<0 || newAddress>0x00000000FFFFFFFF) {
63                 throw new ArgumentOutOfRangeException("newAddress");
64             }
65             m_Address = newAddress;
66         }
67
68
69         /// <devdoc>
70         ///    <para>
71         ///       Constructor for an IPv6 Address with a specified Scope.
72         ///    </para>
73         /// </devdoc>
74         public IPAddress(byte[] address,long scopeid) {
75
76             if (address==null) {
77                 throw new ArgumentNullException("address");
78             }
79
80             if(address.Length != IPv6AddressBytes){
81                 throw new ArgumentException(SR.GetString(SR.dns_bad_ip_address), "address");
82             }
83
84             m_Family = AddressFamily.InterNetworkV6;
85
86             for (int i = 0; i < NumberOfLabels; i++) {
87                 m_Numbers[i] = (ushort)(address[i * 2] * 256 + address[i * 2 + 1]);
88             }
89
90             //
91             // Consider: Since scope is only valid for link-local and site-local
92             //           addresses we could implement some more robust checking here
93             //
94             if ( scopeid < 0 || scopeid > 0x00000000FFFFFFFF ) {
95                 throw new ArgumentOutOfRangeException("scopeid");
96             }
97
98             m_ScopeId = scopeid;
99         }
100         //
101         private IPAddress(ushort[] address, uint scopeid)
102         {
103             m_Family = AddressFamily.InterNetworkV6;
104             m_Numbers = address;
105             m_ScopeId = scopeid;
106         }
107
108
109         /// <devdoc>
110         ///    <para>
111         ///       Constructor for IPv4 and IPv6 Address.
112         ///    </para>
113         /// </devdoc>
114         public IPAddress(byte[] address){
115             if (address==null) {
116                 throw new ArgumentNullException("address");
117             }
118             if (address.Length != IPv4AddressBytes && address.Length != IPv6AddressBytes)
119             {
120                 throw new ArgumentException(SR.GetString(SR.dns_bad_ip_address), "address");
121             }
122
123             if (address.Length == IPv4AddressBytes)
124             {
125                 m_Family = AddressFamily.InterNetwork;
126                 m_Address = ((address[3] << 24 | address[2] <<16 | address[1] << 8| address[0]) & 0x0FFFFFFFF);
127             }
128             else {
129                 m_Family = AddressFamily.InterNetworkV6;
130
131                 for (int i = 0; i < NumberOfLabels; i++) {
132                     m_Numbers[i] = (ushort)(address[i * 2] * 256 + address[i * 2 + 1]);
133                 }
134             }
135         }
136
137         //
138         // we need this internally since we need to interface with winsock
139         // and winsock only understands Int32
140         //
141         internal IPAddress(int newAddress) {
142             m_Address = (long)newAddress & 0x00000000FFFFFFFF;
143         }
144
145
146
147         /// <devdoc>
148         /// <para>Converts an IP address string to an <see cref='System.Net.IPAddress'/>
149         /// instance.</para>
150         /// </devdoc>
151         public static bool TryParse(string ipString, out IPAddress address) {
152             address = InternalParse(ipString,true);
153             return (address != null);
154         } 
155         
156         public static IPAddress Parse(string ipString) {
157             return InternalParse(ipString,false);
158         }
159         
160         private static IPAddress InternalParse(string ipString, bool tryParse) {
161             if (ipString == null) {
162                 if (tryParse) {
163                     return null;
164                 }
165                 throw new ArgumentNullException("ipString");
166             }
167
168             //
169             // IPv6 Changes: Detect probable IPv6 addresses and use separate
170             //               parse method.
171             //
172             if (ipString.IndexOf(':') != -1 ) {
173
174 #if !FEATURE_PAL || MONO
175                 //
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.
181                 //
182                 // We need to make sure that Socket is initialized for this
183                 // call !
184                 //
185                 SocketException e = null;
186                 long   scope = 0;
187 #if !MONO
188                 if(Socket.OSSupportsIPv6)
189                 {
190                     byte[] bytes = new byte[IPv6AddressBytes];
191                     SocketAddress saddr = new SocketAddress(AddressFamily.InterNetworkV6, SocketAddress.IPv6AddressSize);
192
193                     SocketError errorCode =
194                         UnsafeNclNativeMethods.OSSOCK.WSAStringToAddress(
195                             ipString,
196                             AddressFamily.InterNetworkV6,
197                             IntPtr.Zero,
198                             saddr.m_Buffer,
199                             ref saddr.m_Size );
200
201                     if (errorCode ==SocketError.Success)
202                     {
203                         //
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.
206                         //
207                         for (int i=0; i < IPv6AddressBytes; i++)
208                         {
209                             bytes[i] = saddr[i + 8];
210                         }
211                         //
212                         // Scope
213                         //
214                         scope = (long)((saddr[27]<<24) + (saddr[26]<<16) + (saddr[25]<<8 ) + (saddr[24]));
215                         return new IPAddress(bytes,scope);
216                     }
217                     
218                     if(tryParse){
219                         return null;
220                     }
221                     
222                     e = new SocketException();
223                 }
224                 else
225 #endif
226                 {
227                     unsafe
228                     {
229                         int offset = 0;
230                         if (ipString[0] != '[')
231                             ipString = ipString + ']'; //for Uri parser to find the terminator.
232                         else
233                             offset = 1;
234
235                         int end = ipString.Length;
236                         fixed (char *name = ipString)
237                         {
238                             if (IPv6AddressHelper.IsValidStrict(name, offset, ref end) || (end != ipString.Length))
239                             {
240                                 ushort[] numbers = new ushort[NumberOfLabels];
241                                 string scopeId = null;
242                                 fixed (ushort *numbPtr = numbers)
243                                 {
244                                     IPv6AddressHelper.Parse(ipString, numbPtr, 0, ref scopeId);
245                                 }
246                                 //
247                                 // Scope
248                                 //
249                                 if (scopeId == null || scopeId.Length == 0)
250                                     return new IPAddress(numbers, 0);
251
252                                 uint result;
253                                 scopeId = scopeId.Substring(1);
254                                 if (UInt32.TryParse(scopeId, NumberStyles.None, null, out result))
255                                     return new IPAddress(numbers, result);
256 #if MONO
257                                 //
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
261                                 //
262                                 return new IPAddress(numbers, 0);
263 #endif
264                             }
265                         }
266                     }
267                     if(tryParse){
268                         return null;
269                     }
270                     e = new SocketException(SocketError.InvalidArgument);
271                 }
272
273                 throw new FormatException(SR.GetString(SR.dns_bad_ip_address), e);
274
275 #else // !FEATURE_PAL
276                 // IPv6 addresses not supported for FEATURE_PAL
277                 throw new SocketException(SocketError.OperationNotSupported);
278 #endif // !FEATURE_PAL
279             }
280             else
281             // The new IPv4 parser is better than the native one, it can parse 0xFFFFFFFF. (It's faster too).
282             {
283 #if !MONO
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                 ///////////////////////////
289 #endif
290                 int end = ipString.Length;
291                 long result;
292                 unsafe
293                 {
294                     fixed (char *name = ipString)
295                     {
296                         result = IPv4AddressHelper.ParseNonCanonical(name, 0, ref end, true);
297                     }
298                 }
299
300                 if (result == IPv4AddressHelper.Invalid || end != ipString.Length)
301                 {
302                     if (tryParse)
303                     {
304                         return null;
305                     }
306
307                     throw new FormatException(SR.GetString(SR.dns_bad_ip_address));
308                 }
309
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))));
313
314                 return new IPAddress(result);
315             }
316         } // Parse
317
318
319
320         /**
321          * @deprecated IPAddress.Address is address family dependant, use Equals method for comparison.
322          */
323         /// <devdoc>
324         ///     <para>
325         ///         Mark this as deprecated.
326         ///     </para>
327         /// </devdoc>
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 {
330             get {
331                 //
332                 // IPv6 Changes: Can't do this for IPv6, so throw an exception.
333                 //
334                 //
335                 if ( m_Family == AddressFamily.InterNetworkV6 ) {
336                     throw new SocketException(SocketError.OperationNotSupported);
337                 }
338                 else {
339                     return m_Address;
340                 }
341             }
342             set {
343                 //
344                 // IPv6 Changes: Can't do this for IPv6 addresses
345                 if ( m_Family == AddressFamily.InterNetworkV6 ) {
346                     throw new SocketException(SocketError.OperationNotSupported);
347                 }
348                 else {
349                     if (m_Address!=value) {
350                         m_ToString = null;
351                         m_Address = value;
352                     }
353                 }
354             }
355         }
356
357         /// <devdoc>
358         /// <para>
359         /// Provides a copy of the IPAddress internals as an array of bytes.
360         /// </para>
361         /// </devdoc>
362         public byte[] GetAddressBytes() {
363             byte[] bytes;
364             if (m_Family == AddressFamily.InterNetworkV6 ) {
365                 bytes = new byte[NumberOfLabels * 2];
366
367                 int j = 0;
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);
371                 }
372             }
373             else {
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);
379             }
380             return bytes;
381         }
382
383         public AddressFamily AddressFamily {
384             get {
385                 return m_Family;
386             }
387         }
388
389         /// <devdoc>
390         ///    <para>
391         ///        IPv6 Scope identifier. This is really a uint32, but that isn't CLS compliant
392         ///    </para>
393         /// </devdoc>
394         public long ScopeId {
395             get {
396                 //
397                 // Not valid for IPv4 addresses
398                 //
399                 if ( m_Family == AddressFamily.InterNetwork ) {
400                     throw new SocketException(SocketError.OperationNotSupported);
401                 }
402
403                 return m_ScopeId;
404             }
405             set {
406                 //
407                 // Not valid for IPv4 addresses
408                 //
409                 if ( m_Family == AddressFamily.InterNetwork ) {
410                     throw new SocketException(SocketError.OperationNotSupported);
411                 }
412
413                 //
414                 // Consider: Since scope is only valid for link-local and site-local
415                 //           addresses we could implement some more robust checking here
416                 //
417                 if ( value < 0 || value > 0x00000000FFFFFFFF) {
418                     throw new ArgumentOutOfRangeException("value");
419                 }
420                 if (m_ScopeId!=value) {
421                     m_Address = value;
422                     m_ScopeId = value;
423                 }
424             }
425         }
426
427         /// <devdoc>
428         ///    <para>
429         ///       Converts the Internet address to either standard dotted quad format
430         ///       or standard IPv6 representation.
431         ///    </para>
432         /// </devdoc>
433         public override string ToString() {
434             if (m_ToString==null) {
435                 //
436                 // IPv6 Changes: generate the IPV6 representation
437                 //
438                 if ( m_Family == AddressFamily.InterNetworkV6 ) {
439
440 #if !FEATURE_PAL
441                     int addressStringLength = 256;
442                     StringBuilder addressString = new StringBuilder(addressStringLength);
443
444                     if(Socket.OSSupportsIPv6)
445                     {
446                         SocketAddress saddr = new SocketAddress(AddressFamily.InterNetworkV6, SocketAddress.IPv6AddressSize);
447                         int j = 8;
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]);
451                         }
452                         if (m_ScopeId >0) {
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);
457                         }
458                         SocketError errorCode =
459                             UnsafeNclNativeMethods.OSSOCK.WSAAddressToString(
460                                 saddr.m_Buffer,
461                                 saddr.m_Size,
462                                 IntPtr.Zero,
463                                 addressString,
464                                 ref addressStringLength);
465                         if (errorCode!=SocketError.Success) {
466                             throw new SocketException();
467                         }
468                     }
469                     else
470                     {
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);
477
478                         if (m_ScopeId != 0)
479                         {
480                             addressString.Append('%').Append((uint)m_ScopeId);
481                         }
482                     }
483
484                     m_ToString = addressString.ToString();
485 #else // !FEATURE_PAL
486
487 #if MONO
488                     var v6 = new IPv6AddressFormatter (m_Numbers, ScopeId);
489                     m_ToString = v6.ToString ();
490 #else
491                     // IPv6 addresses not supported for FEATURE_PAL
492                     throw new SocketException(SocketError.OperationNotSupported);
493 #endif
494 #endif // !FEATURE_PAL
495                 }
496                 else {
497                     unsafe {
498                         const int MaxSize = 15;
499                         int offset = MaxSize;
500                         char* addressString = stackalloc char[MaxSize];
501                         int number = (int)((m_Address>>24)&0xFF);
502                         do {
503                             addressString[--offset] = (char)('0' + number%10);
504                             number = number/10;
505                         } while (number>0);
506                         addressString[--offset] = '.';
507                         number = (int)((m_Address>>16)&0xFF);
508                         do {
509                             addressString[--offset] = (char)('0' + number%10);
510                             number = number/10;
511                         } while (number>0);
512                         addressString[--offset] = '.';
513                         number = (int)((m_Address>>8)&0xFF);
514                         do {
515                             addressString[--offset] = (char)('0' + number%10);
516                             number = number/10;
517                         } while (number>0);
518                         addressString[--offset] = '.';
519                         number = (int)(m_Address&0xFF);
520                         do {
521                             addressString[--offset] = (char)('0' + number%10);
522                             number = number/10;
523                         } while (number>0);
524                         m_ToString = new string(addressString, offset, MaxSize-offset);
525                     }
526                 }
527             }
528             return m_ToString;
529         }
530
531         public static long HostToNetworkOrder(long host) {
532 #if BIGENDIAN
533             return host;
534 #else
535             return (((long)HostToNetworkOrder((int)host) & 0xFFFFFFFF) << 32)
536                     | ((long)HostToNetworkOrder((int)(host >> 32)) & 0xFFFFFFFF);
537 #endif
538         }
539         public static int HostToNetworkOrder(int host) {
540 #if BIGENDIAN
541             return host;
542 #else
543             return (((int)HostToNetworkOrder((short)host) & 0xFFFF) << 16)
544                     | ((int)HostToNetworkOrder((short)(host >> 16)) & 0xFFFF);
545 #endif
546         }
547         public static short HostToNetworkOrder(short host) {
548 #if BIGENDIAN
549             return host;
550 #else
551             return (short)((((int)host & 0xFF) << 8) | (int)((host >> 8) & 0xFF));
552 #endif
553         }
554         public static long NetworkToHostOrder(long network) {
555             return HostToNetworkOrder(network);
556         }
557         public static int NetworkToHostOrder(int network) {
558             return HostToNetworkOrder(network);
559         }
560         public static short NetworkToHostOrder(short network) {
561             return HostToNetworkOrder(network);
562         }
563
564         public static bool IsLoopback(IPAddress address) {
565             if (address == null) {
566                 throw new ArgumentNullException("address");
567             }
568             if ( address.m_Family == AddressFamily.InterNetworkV6 ) {
569                 //
570                 // Do Equals test for IPv6 addresses
571                 //
572                 return address.Equals(IPv6Loopback);
573             }
574             else {
575                 return ((address.m_Address & IPAddress.LoopbackMask) == (IPAddress.Loopback.m_Address & IPAddress.LoopbackMask));
576             }
577         }
578
579         internal bool IsBroadcast {
580             get {
581                 if ( m_Family == AddressFamily.InterNetworkV6 ) {
582                     //
583                     // No such thing as a broadcast address for IPv6
584                     //
585                     return false;
586                 }
587                 else {
588                     return m_Address==Broadcast.m_Address;
589                 }
590             }
591         }
592
593         /// <devdoc>
594         ///    <para>
595         ///       V.Next: Determines if an address is an IPv6 Multicast address
596         ///    </para>
597         /// </devdoc>
598         public bool IsIPv6Multicast{
599             get{
600                 return ( m_Family == AddressFamily.InterNetworkV6 ) &&
601                     ( ( this.m_Numbers[0] & 0xFF00 ) == 0xFF00 );
602             }
603
604         }
605
606         /// <devdoc>
607         ///    <para>
608         ///       V.Next: Determines if an address is an IPv6 Link Local address
609         ///    </para>
610         /// </devdoc>
611         public bool IsIPv6LinkLocal {
612             get{
613                 return ( m_Family == AddressFamily.InterNetworkV6 ) &&
614                    ( ( this.m_Numbers[0] & 0xFFC0 ) == 0xFE80 );
615             }
616         }
617
618         /// <devdoc>
619         ///    <para>
620         ///       V.Next: Determines if an address is an IPv6 Site Local address
621         ///    </para>
622         /// </devdoc>
623         public bool IsIPv6SiteLocal {
624             get{
625                 return ( m_Family == AddressFamily.InterNetworkV6 ) &&
626                    ( ( this.m_Numbers[0] & 0xFFC0 ) == 0xFEC0 );
627             }
628         }
629
630         public bool IsIPv6Teredo {
631             get {
632                 return ( m_Family == AddressFamily.InterNetworkV6 ) &&
633                        ( this.m_Numbers[0] == 0x2001 ) &&
634                        ( this.m_Numbers[1] == 0 );
635             }
636         }
637         
638         // 0:0:0:0:0:FFFF:x.x.x.x
639         public bool IsIPv4MappedToIPv6 {
640             get {
641                 if (AddressFamily != AddressFamily.InterNetworkV6) {
642                     return false;
643                 }
644                 for (int i = 0; i < 5; i++) {
645                     if (m_Numbers[i] != 0) {
646                         return false;
647                     }
648                 }
649                 return (m_Numbers[5] == 0xFFFF);
650             }
651         }
652
653         internal bool Equals(object comparandObj, bool compareScopeId) {
654             IPAddress comparand = comparandObj as IPAddress;
655
656             if (comparand == null) {
657                 return false;
658             }
659             //
660             // Compare families before address representations
661             //
662             if (m_Family != comparand.m_Family) {
663                 return false;
664             }
665             if ( m_Family == AddressFamily.InterNetworkV6 ) {
666                 //
667                 // For IPv6 addresses, we must compare the full 128bit
668                 // representation.
669                 //
670                 for ( int i = 0; i < NumberOfLabels; i++) {
671                     if (comparand.m_Numbers[i] != this.m_Numbers[i])
672                         return false;
673                 }
674                 //
675                 // In addition, the scope id's must match as well
676                 //
677                 if (comparand.m_ScopeId == this.m_ScopeId)
678                     return true;
679                 else
680                     return (compareScopeId? false : true);
681             }
682             else {
683                 //
684                 // For IPv4 addresses, compare the integer representation.
685                 //
686                 return comparand.m_Address == this.m_Address;
687             }
688         }
689
690         /// <devdoc>
691         ///    <para>
692         ///       Compares two IP addresses.
693         ///    </para>
694         /// </devdoc>
695         public override bool Equals(object comparand) {
696             return Equals(comparand, true);
697         }
698
699         public override int GetHashCode() {
700             //
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.
704             //
705             if ( m_Family == AddressFamily.InterNetworkV6 ) {
706                 if ( m_HashCode == 0 )
707                     m_HashCode = StringComparer.InvariantCultureIgnoreCase.GetHashCode(ToString());
708
709                 return m_HashCode;
710             }
711             else {
712                 //
713                 // For IPv4 addresses, we can simply use the integer
714                 // representation.
715                 //
716                 return unchecked((int)m_Address);
717             }
718         }
719
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()
722         {
723             switch (m_Family)
724             {
725                 case AddressFamily.InterNetwork:
726                     return new IPAddress(m_Address);
727
728                 case AddressFamily.InterNetworkV6:
729                     return new IPAddress(m_Numbers, (uint) m_ScopeId);
730             }
731
732             throw new InternalException();
733         }
734
735         // IPv4 192.168.1.1 maps as ::FFFF:192.168.1.1
736         public IPAddress MapToIPv6()
737         {
738             if (AddressFamily == AddressFamily.InterNetworkV6)
739             {
740                 return this;
741             }
742
743             ushort[] labels = new ushort[IPAddress.NumberOfLabels];
744             labels[5] = 0xFFFF;
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);
748         }
749
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()
754         {
755             if (AddressFamily == AddressFamily.InterNetwork)
756             {
757                 return this;
758             }
759
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);
765
766             return new IPAddress(address);
767         }
768     } // class IPAddress
769 } // namespace System.Net