Merge pull request #3938 from ntherning/UnicastIPAddressInformation.IPv4Mask-from...
authorNiklas Therning <niklas@therning.org>
Sat, 12 Nov 2016 07:41:55 +0000 (08:41 +0100)
committerGitHub <noreply@github.com>
Sat, 12 Nov 2016 07:41:55 +0000 (08:41 +0100)
Change UnicastIPAddressInformation.IPv4Mask to work as in refsource on Windows

mcs/class/System/System.Net.NetworkInformation/IPInterfaceProperties.cs
mcs/class/System/System.Net.NetworkInformation/UnicastIPAddressInformation.cs

index 9a8560a92b58275149f51640218549c4c1a15652..af9fbec33bef62230039b5cefe5983203eb9ca64 100644 (file)
@@ -406,17 +406,17 @@ namespace System.Net.NetworkInformation {
                        get {
                                Win32_IP_ADAPTER_INFO ai = Win32NetworkInterface2.GetAdapterInfoByIndex (mib4.Index);
                                // FIXME: should ipv6 DhcpServer be considered?
-                               return ai != null ? Win32FromUnicast ((int) ai.Index, addr.FirstUnicastAddress) : new UnicastIPAddressInformationCollection ();
+                               return ai != null ? Win32FromUnicast (addr.FirstUnicastAddress) : new UnicastIPAddressInformationCollection ();
                        }
                }
 
-               static UnicastIPAddressInformationCollection Win32FromUnicast (int ifIndex, IntPtr ptr)
+               static UnicastIPAddressInformationCollection Win32FromUnicast (IntPtr ptr)
                {
                        UnicastIPAddressInformationCollection c = new UnicastIPAddressInformationCollection ();
                        Win32_IP_ADAPTER_UNICAST_ADDRESS a;
                        for (IntPtr p = ptr; p != IntPtr.Zero; p = a.Next) {
                                a = (Win32_IP_ADAPTER_UNICAST_ADDRESS) Marshal.PtrToStructure (p, typeof (Win32_IP_ADAPTER_UNICAST_ADDRESS));
-                               c.InternalAdd (new Win32UnicastIPAddressInformation (ifIndex, a));
+                               c.InternalAdd (new Win32UnicastIPAddressInformation (a));
                        }
                        return c;
                }
index 439cab07cf091c553d92b9ba5565fdd1d81bb0dc..17710c420fd9c5188fef8dfcef54222bf74c250c 100644 (file)
 using System;
 using System.Runtime.InteropServices;
 using System.Net.Sockets;
+using System.Diagnostics.Contracts;
 
 namespace System.Net.NetworkInformation {
 #if !MOBILE
        class Win32UnicastIPAddressInformation : UnicastIPAddressInformation 
        {
-               int if_index;
                Win32_IP_ADAPTER_UNICAST_ADDRESS info;
+               IPAddress ipv4Mask;
 
-               public Win32UnicastIPAddressInformation (int ifIndex, Win32_IP_ADAPTER_UNICAST_ADDRESS info)
+               public Win32UnicastIPAddressInformation (Win32_IP_ADAPTER_UNICAST_ADDRESS info)
                {
-                       this.if_index = ifIndex;
                        this.info = info;
+                       IPAddress ipAddress = info.Address.GetIPAddress ();
+                       // IPv6 returns 0.0.0.0 for consistancy with XP
+                       if (ipAddress.AddressFamily == AddressFamily.InterNetwork) {
+                               ipv4Mask = PrefixLengthToSubnetMask (info.OnLinkPrefixLength, ipAddress.AddressFamily);
+                       }
                }
 
                public override IPAddress Address {
@@ -74,27 +79,15 @@ namespace System.Net.NetworkInformation {
                        get { return info.DadState; }
                }
 
-               public override IPAddress IPv4Mask {
+               public override IPAddress IPv4Mask{
                        get {
-                               Win32_IP_ADAPTER_INFO ai = Win32NetworkInterface2.GetAdapterInfoByIndex (if_index);
-                               if (ai == null)
-                                       throw new Exception ("huh? " + if_index);
-                               if (this.Address == null)
-                                       return null;
-                               string expected = this.Address.ToString ();
-                               unsafe {
-                                       Win32_IP_ADDR_STRING p = ai.IpAddressList;
-                                       while (true) {
-                                               if (p.IpAddress == expected)
-                                                       return IPAddress.Parse (p.IpMask);
-                                               if (p.Next == IntPtr.Zero)
-                                                       break;
-                                               p = (Win32_IP_ADDR_STRING) Marshal.PtrToStructure (p.Next, typeof (Win32_IP_ADDR_STRING));
-                                       }
-
-                                       // Or whatever it should be...
-                                       return null;
+                               // The IPv6 equivilant was never available on XP, and we've kept this behavior for legacy reasons.
+                               // For IPv6 use PrefixLength instead.
+                               if (Address.AddressFamily != AddressFamily.InterNetwork) {
+                                       return IPAddress.Any;
                                }
+
+                               return ipv4Mask;
                        }
                }
 
@@ -105,6 +98,28 @@ namespace System.Net.NetworkInformation {
                public override SuffixOrigin SuffixOrigin {
                        get { return info.SuffixOrigin; }
                }
+
+               // Convert a CIDR prefix length to a subnet mask "255.255.255.0" format
+               private static IPAddress PrefixLengthToSubnetMask (byte prefixLength, AddressFamily family) {
+                       Contract.Requires ((0 <= prefixLength) && (prefixLength <= 126));
+                       Contract.Requires ((family == AddressFamily.InterNetwork) || (family == AddressFamily.InterNetworkV6));
+
+                       byte[] addressBytes;
+                       if (family == AddressFamily.InterNetwork) {
+                               addressBytes = new byte [4];
+                       } else { // v6
+                               addressBytes = new byte [16];
+                       }
+
+                       Contract.Assert (prefixLength < (addressBytes.Length * 8));
+
+                       // Enable bits one at a time from left/high to right/low
+                       for (int bit = 0; bit < prefixLength; bit++) {
+                               addressBytes [bit / 8] |= (byte) (0x80 >> (bit % 8));
+                       }
+
+                       return new IPAddress (addressBytes);
+               }
        }
 #endif