2 // System.Net.NetworkInformation.NetworkInterface
5 // Gonzalo Paniagua Javier (gonzalo@novell.com)
6 // Atsushi Enomoto (atsushi@ximian.com)
7 // Miguel de Icaza (miguel@novell.com)
8 // Eric Butler (eric@extremeboredom.net)
9 // Marek Habersack (mhabersack@novell.com)
10 // Marek Safar (marek.safar@gmail.com)
12 // Copyright (c) 2006-2008 Novell, Inc. (http://www.novell.com)
14 // Permission is hereby granted, free of charge, to any person obtaining
15 // a copy of this software and associated documentation files (the
16 // "Software"), to deal in the Software without restriction, including
17 // without limitation the rights to use, copy, modify, merge, publish,
18 // distribute, sublicense, and/or sell copies of the Software, and to
19 // permit persons to whom the Software is furnished to do so, subject to
20 // the following conditions:
22 // The above copyright notice and this permission notice shall be
23 // included in all copies or substantial portions of the Software.
25 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
29 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
30 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
31 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 using System.Collections.Generic;
35 using System.Collections;
37 using System.Net.Sockets;
38 using System.Runtime.InteropServices;
41 using System.Globalization;
43 namespace System.Net.NetworkInformation {
44 public abstract class NetworkInterface {
46 static readonly NetworkInterfaceFactory nif = NetworkInterfaceFactory.Create ();
48 protected NetworkInterface ()
52 public static NetworkInterface [] GetAllNetworkInterfaces ()
55 return nif.GetAllNetworkInterfaces ();
57 return new NetworkInterface [0];
61 [MonoTODO("Always returns true")]
62 public static bool GetIsNetworkAvailable ()
67 public static int LoopbackInterfaceIndex {
69 return nif.GetLoopbackInterfaceIndex ();
73 public abstract IPInterfaceProperties GetIPProperties ();
74 public abstract IPv4InterfaceStatistics GetIPv4Statistics ();
75 public abstract PhysicalAddress GetPhysicalAddress ();
76 public abstract bool Supports (NetworkInterfaceComponent networkInterfaceComponent);
78 public abstract string Description { get; }
79 public abstract string Id { get; }
80 public abstract bool IsReceiveOnly { get; }
81 public abstract string Name { get; }
82 public abstract NetworkInterfaceType NetworkInterfaceType { get; }
83 public abstract OperationalStatus OperationalStatus { get; }
84 public abstract long Speed { get; }
85 public abstract bool SupportsMulticast { get; }
88 abstract class NetworkInterfaceFactory
90 internal abstract class UnixNetworkInterfaceAPI : NetworkInterfaceFactory
93 public static extern int if_nametoindex(string ifname);
96 protected static extern int getifaddrs (out IntPtr ifap);
99 protected static extern void freeifaddrs (IntPtr ifap);
102 class MacOsNetworkInterfaceAPI : UnixNetworkInterfaceAPI
104 public override NetworkInterface [] GetAllNetworkInterfaces ()
106 const int AF_INET = 2;
107 const int AF_INET6 = 30;
108 const int AF_LINK = 18;
110 var interfaces = new Dictionary <string, MacOsNetworkInterface> ();
112 if (getifaddrs (out ifap) != 0)
113 throw new SystemException ("getifaddrs() failed");
117 while (next != IntPtr.Zero) {
118 MacOsStructs.ifaddrs addr = (MacOsStructs.ifaddrs) Marshal.PtrToStructure (next, typeof (MacOsStructs.ifaddrs));
119 IPAddress address = IPAddress.None;
120 string name = addr.ifa_name;
122 byte[] macAddress = null;
123 NetworkInterfaceType type = NetworkInterfaceType.Unknown;
125 if (addr.ifa_addr != IntPtr.Zero) {
127 MacOsStructs.sockaddr sockaddr = (MacOsStructs.sockaddr) Marshal.PtrToStructure (addr.ifa_addr, typeof (MacOsStructs.sockaddr));
129 if (sockaddr.sa_family == AF_INET6) {
130 MacOsStructs.sockaddr_in6 sockaddr6 = (MacOsStructs.sockaddr_in6) Marshal.PtrToStructure (addr.ifa_addr, typeof (MacOsStructs.sockaddr_in6));
131 address = new IPAddress (sockaddr6.sin6_addr.u6_addr8, sockaddr6.sin6_scope_id);
132 } else if (sockaddr.sa_family == AF_INET) {
133 MacOsStructs.sockaddr_in sockaddrin = (MacOsStructs.sockaddr_in) Marshal.PtrToStructure (addr.ifa_addr, typeof (MacOsStructs.sockaddr_in));
134 address = new IPAddress (sockaddrin.sin_addr);
135 } else if (sockaddr.sa_family == AF_LINK) {
136 MacOsStructs.sockaddr_dl sockaddrdl = new MacOsStructs.sockaddr_dl ();
137 sockaddrdl.Read (addr.ifa_addr);
139 macAddress = new byte [(int) sockaddrdl.sdl_alen];
140 // copy mac address from sdl_data field starting at last index pos of interface name into array macaddress, starting
142 Array.Copy (sockaddrdl.sdl_data, sockaddrdl.sdl_nlen, macAddress, 0, Math.Min (macAddress.Length, sockaddrdl.sdl_data.Length - sockaddrdl.sdl_nlen));
144 index = sockaddrdl.sdl_index;
146 int hwtype = (int) sockaddrdl.sdl_type;
147 if (Enum.IsDefined (typeof (MacOsArpHardware), hwtype)) {
148 switch ((MacOsArpHardware) hwtype) {
149 case MacOsArpHardware.ETHER:
150 type = NetworkInterfaceType.Ethernet;
153 case MacOsArpHardware.ATM:
154 type = NetworkInterfaceType.Atm;
157 case MacOsArpHardware.SLIP:
158 type = NetworkInterfaceType.Slip;
161 case MacOsArpHardware.PPP:
162 type = NetworkInterfaceType.Ppp;
165 case MacOsArpHardware.LOOPBACK:
166 type = NetworkInterfaceType.Loopback;
170 case MacOsArpHardware.FDDI:
171 type = NetworkInterfaceType.Fddi;
178 MacOsNetworkInterface iface = null;
180 // create interface if not already present
181 if (!interfaces.TryGetValue (name, out iface)) {
182 iface = new MacOsNetworkInterface (name, addr.ifa_flags);
183 interfaces.Add (name, iface);
186 // if a new address has been found, add it
187 if (!address.Equals (IPAddress.None))
188 iface.AddAddress (address);
190 // set link layer info, if iface has macaddress or is loopback device
191 if (macAddress != null || type == NetworkInterfaceType.Loopback)
192 iface.SetLinkLayerInfo (index, macAddress, type);
194 next = addr.ifa_next;
200 NetworkInterface [] result = new NetworkInterface [interfaces.Count];
202 foreach (NetworkInterface thisInterface in interfaces.Values) {
203 result [x] = thisInterface;
209 public override int GetLoopbackInterfaceIndex ()
211 return if_nametoindex ("lo0");
215 class LinuxNetworkInterfaceAPI : UnixNetworkInterfaceAPI
217 static void FreeInterfaceAddresses (IntPtr ifap)
220 AndroidPlatform.FreeInterfaceAddresses (ifap);
226 static int GetInterfaceAddresses (out IntPtr ifap)
229 return AndroidPlatform.GetInterfaceAddresses (out ifap);
231 return getifaddrs (out ifap);
235 public override NetworkInterface [] GetAllNetworkInterfaces ()
237 const int AF_INET = 2;
238 const int AF_INET6 = 10;
239 const int AF_PACKET = 17;
241 var interfaces = new Dictionary <string, LinuxNetworkInterface> ();
243 if (GetInterfaceAddresses (out ifap) != 0)
244 throw new SystemException ("getifaddrs() failed");
248 while (next != IntPtr.Zero) {
249 ifaddrs addr = (ifaddrs) Marshal.PtrToStructure (next, typeof (ifaddrs));
250 IPAddress address = IPAddress.None;
251 string name = addr.ifa_name;
253 byte[] macAddress = null;
254 NetworkInterfaceType type = NetworkInterfaceType.Unknown;
255 int nullNameCount = 0;
257 if (addr.ifa_addr != IntPtr.Zero) {
258 sockaddr_in sockaddr = (sockaddr_in) Marshal.PtrToStructure (addr.ifa_addr, typeof (sockaddr_in));
260 if (sockaddr.sin_family == AF_INET6) {
261 sockaddr_in6 sockaddr6 = (sockaddr_in6) Marshal.PtrToStructure (addr.ifa_addr, typeof (sockaddr_in6));
262 address = new IPAddress (sockaddr6.sin6_addr.u6_addr8, sockaddr6.sin6_scope_id);
263 } else if (sockaddr.sin_family == AF_INET) {
264 address = new IPAddress (sockaddr.sin_addr);
265 } else if (sockaddr.sin_family == AF_PACKET) {
266 sockaddr_ll sockaddrll = (sockaddr_ll) Marshal.PtrToStructure (addr.ifa_addr, typeof (sockaddr_ll));
267 if (((int)sockaddrll.sll_halen) > sockaddrll.sll_addr.Length){
268 Console.Error.WriteLine ("Got a bad hardware address length for an AF_PACKET {0} {1}",
269 sockaddrll.sll_halen, sockaddrll.sll_addr.Length);
270 next = addr.ifa_next;
274 macAddress = new byte [(int) sockaddrll.sll_halen];
275 Array.Copy (sockaddrll.sll_addr, 0, macAddress, 0, macAddress.Length);
276 index = sockaddrll.sll_ifindex;
278 int hwtype = (int)sockaddrll.sll_hatype;
279 if (Enum.IsDefined (typeof (LinuxArpHardware), hwtype)) {
280 switch ((LinuxArpHardware)hwtype) {
281 case LinuxArpHardware.EETHER:
282 goto case LinuxArpHardware.ETHER;
284 case LinuxArpHardware.ETHER:
285 type = NetworkInterfaceType.Ethernet;
288 case LinuxArpHardware.PRONET:
289 type = NetworkInterfaceType.TokenRing;
292 case LinuxArpHardware.ATM:
293 type = NetworkInterfaceType.Atm;
296 case LinuxArpHardware.SLIP:
297 case LinuxArpHardware.CSLIP:
298 case LinuxArpHardware.SLIP6:
299 case LinuxArpHardware.CSLIP6:
300 type = NetworkInterfaceType.Slip;
303 case LinuxArpHardware.PPP:
304 type = NetworkInterfaceType.Ppp;
307 case LinuxArpHardware.LOOPBACK:
308 type = NetworkInterfaceType.Loopback;
312 case LinuxArpHardware.FDDI:
313 type = NetworkInterfaceType.Fddi;
316 case LinuxArpHardware.SIT:
317 case LinuxArpHardware.IPDDP:
318 case LinuxArpHardware.IPGRE:
319 case LinuxArpHardware.IP6GRE:
320 case LinuxArpHardware.TUNNEL6:
321 case LinuxArpHardware.TUNNEL:
322 type = NetworkInterfaceType.Tunnel;
329 LinuxNetworkInterface iface = null;
331 if (String.IsNullOrEmpty (name))
332 name = "\0" + (++nullNameCount).ToString ();
334 if (!interfaces.TryGetValue (name, out iface)) {
335 iface = new LinuxNetworkInterface (name);
336 interfaces.Add (name, iface);
339 if (!address.Equals (IPAddress.None))
340 iface.AddAddress (address);
342 if (macAddress != null || type == NetworkInterfaceType.Loopback) {
343 if (type == NetworkInterfaceType.Ethernet) {
344 if (Directory.Exists(iface.IfacePath + "wireless")) {
345 type = NetworkInterfaceType.Wireless80211;
348 iface.SetLinkLayerInfo (index, macAddress, type);
351 next = addr.ifa_next;
354 FreeInterfaceAddresses (ifap);
357 NetworkInterface [] result = new NetworkInterface [interfaces.Count];
359 foreach (NetworkInterface thisInterface in interfaces.Values) {
360 result [x] = thisInterface;
366 public override int GetLoopbackInterfaceIndex ()
368 return if_nametoindex ("lo");
372 class Win32NetworkInterfaceAPI : NetworkInterfaceFactory
374 [DllImport ("iphlpapi.dll", SetLastError = true)]
375 static extern int GetAdaptersAddresses (uint family, uint flags, IntPtr reserved, byte [] info, ref int size);
377 unsafe static Win32_IP_ADAPTER_ADDRESSES [] GetAdaptersAddresses ()
379 byte [] bytes = null;
381 GetAdaptersAddresses (0, 0, IntPtr.Zero, bytes, ref len);
382 bytes = new byte [len];
383 int ret = GetAdaptersAddresses (0, 0, IntPtr.Zero, bytes, ref len);
385 throw new NetworkInformationException (ret);
387 List<Win32_IP_ADAPTER_ADDRESSES> l = new List<Win32_IP_ADAPTER_ADDRESSES> ();
388 fixed (byte* ptr = bytes) {
389 Win32_IP_ADAPTER_ADDRESSES info;
390 for (IntPtr p = (IntPtr) ptr; p != IntPtr.Zero; p = info.Next) {
391 info = new Win32_IP_ADAPTER_ADDRESSES ();
392 Marshal.PtrToStructure (p, info);
399 public override NetworkInterface [] GetAllNetworkInterfaces ()
401 // Win32_IP_ADAPTER_INFO [] ai = GetAdaptersInfo ();
402 Win32_IP_ADAPTER_ADDRESSES [] aa = GetAdaptersAddresses ();
403 NetworkInterface [] ret = new NetworkInterface [aa.Length];
404 for (int i = 0; i < ret.Length; i++)
405 ret [i] = new Win32NetworkInterface2 (aa [i]);
409 public override int GetLoopbackInterfaceIndex ()
411 throw new NotImplementedException ();
415 public abstract NetworkInterface [] GetAllNetworkInterfaces ();
416 public abstract int GetLoopbackInterfaceIndex ();
418 public static NetworkInterfaceFactory Create ()
421 return new MacOsNetworkInterfaceAPI ();
423 Version windowsVer51 = new Version (5, 1);
424 bool runningOnUnix = (Environment.OSVersion.Platform == PlatformID.Unix);
427 if (Platform.IsMacOS || Platform.IsFreeBSD)
428 return new MacOsNetworkInterfaceAPI ();
430 return new LinuxNetworkInterfaceAPI ();
433 if (Environment.OSVersion.Version >= windowsVer51)
434 return new Win32NetworkInterfaceAPI ();
436 throw new NotImplementedException ();
441 abstract class UnixNetworkInterface : NetworkInterface
444 protected IPv4InterfaceStatistics ipv4stats;
445 protected IPInterfaceProperties ipproperties;
449 protected List <IPAddress> addresses;
451 NetworkInterfaceType type;
453 internal UnixNetworkInterface (string name)
456 addresses = new List<IPAddress> ();
459 internal void AddAddress (IPAddress address)
461 addresses.Add (address);
464 internal void SetLinkLayerInfo (int index, byte[] macAddress, NetworkInterfaceType type)
466 //this.index = index;
467 this.macAddress = macAddress;
471 public override PhysicalAddress GetPhysicalAddress ()
473 if (macAddress != null)
474 return new PhysicalAddress (macAddress);
476 return PhysicalAddress.None;
479 public override bool Supports (NetworkInterfaceComponent networkInterfaceComponent)
481 bool wantIPv4 = networkInterfaceComponent == NetworkInterfaceComponent.IPv4;
482 bool wantIPv6 = wantIPv4 ? false : networkInterfaceComponent == NetworkInterfaceComponent.IPv6;
484 foreach (IPAddress address in addresses) {
485 if (wantIPv4 && address.AddressFamily == AddressFamily.InterNetwork)
487 else if (wantIPv6 && address.AddressFamily == AddressFamily.InterNetworkV6)
494 public override string Description {
498 public override string Id {
502 public override bool IsReceiveOnly {
503 get { return false; }
506 public override string Name {
510 public override NetworkInterfaceType NetworkInterfaceType {
514 [MonoTODO ("Parse dmesg?")]
515 public override long Speed {
522 internal int NameIndex {
524 return NetworkInterfaceFactory.UnixNetworkInterfaceAPI.if_nametoindex (Name);
530 // This class needs support from the libsupport.so library to fetch the
531 // data using arch-specific ioctls.
533 // For this to work, we have to create this on the factory above.
535 sealed class LinuxNetworkInterface : UnixNetworkInterface
537 //NetworkInterfaceType type;
539 string iface_operstate_path;
540 string iface_flags_path;
542 internal string IfacePath {
543 get { return iface_path; }
546 internal LinuxNetworkInterface (string name)
549 iface_path = "/sys/class/net/" + name + "/";
550 iface_operstate_path = iface_path + "operstate";
551 iface_flags_path = iface_path + "flags";
554 public override IPInterfaceProperties GetIPProperties ()
556 if (ipproperties == null)
557 ipproperties = new LinuxIPInterfaceProperties (this, addresses);
561 public override IPv4InterfaceStatistics GetIPv4Statistics ()
563 if (ipv4stats == null)
564 ipv4stats = new LinuxIPv4InterfaceStatistics (this);
568 public override OperationalStatus OperationalStatus {
570 if (!Directory.Exists (iface_path))
571 return OperationalStatus.Unknown;
574 string s = ReadLine (iface_operstate_path);
578 return OperationalStatus.Unknown;
581 return OperationalStatus.NotPresent;
584 return OperationalStatus.Down;
586 case "lowerlayerdown":
587 return OperationalStatus.LowerLayerDown;
590 return OperationalStatus.Testing;
593 return OperationalStatus.Dormant;
596 return OperationalStatus.Up;
600 return OperationalStatus.Unknown;
604 public override bool SupportsMulticast {
606 if (!Directory.Exists (iface_path))
610 string s = ReadLine (iface_flags_path);
611 if (s.Length > 2 && s [0] == '0' && s [1] == 'x')
614 ulong f = UInt64.Parse (s, NumberStyles.HexNumber);
616 // Hardcoded, only useful for Linux.
617 return ((f & 0x1000) == 0x1000);
624 internal static string ReadLine (string path)
626 using (FileStream fs = File.OpenRead (path)){
627 using (StreamReader sr = new StreamReader (fs)){
628 return sr.ReadLine ();
634 sealed class MacOsNetworkInterface : UnixNetworkInterface
636 private uint _ifa_flags;
638 internal MacOsNetworkInterface (string name, uint ifa_flags)
641 _ifa_flags = ifa_flags;
644 public override IPInterfaceProperties GetIPProperties ()
646 if (ipproperties == null)
647 ipproperties = new MacOsIPInterfaceProperties (this, addresses);
651 public override IPv4InterfaceStatistics GetIPv4Statistics ()
653 if (ipv4stats == null)
654 ipv4stats = new MacOsIPv4InterfaceStatistics (this);
658 public override OperationalStatus OperationalStatus {
660 if(((MacOsInterfaceFlags)_ifa_flags & MacOsInterfaceFlags.IFF_UP) == MacOsInterfaceFlags.IFF_UP){
661 return OperationalStatus.Up;
663 return OperationalStatus.Unknown;
667 public override bool SupportsMulticast {
669 return ((MacOsInterfaceFlags)_ifa_flags & MacOsInterfaceFlags.IFF_MULTICAST) == MacOsInterfaceFlags.IFF_MULTICAST;
674 class Win32NetworkInterface2 : NetworkInterface
676 [DllImport ("iphlpapi.dll", SetLastError = true)]
677 static extern int GetAdaptersInfo (byte [] info, ref int size);
679 [DllImport ("iphlpapi.dll", SetLastError = true)]
680 static extern int GetIfEntry (ref Win32_MIB_IFROW row);
682 public static Win32_IP_ADAPTER_INFO GetAdapterInfoByIndex (int index)
684 foreach (Win32_IP_ADAPTER_INFO info in GetAdaptersInfo ())
685 if (info.Index == index)
690 unsafe static Win32_IP_ADAPTER_INFO [] GetAdaptersInfo ()
692 byte [] bytes = null;
694 GetAdaptersInfo (bytes, ref len);
695 bytes = new byte [len];
696 int ret = GetAdaptersInfo (bytes, ref len);
699 throw new NetworkInformationException (ret);
701 List<Win32_IP_ADAPTER_INFO> l = new List<Win32_IP_ADAPTER_INFO> ();
702 fixed (byte* ptr = bytes) {
703 Win32_IP_ADAPTER_INFO info;
704 for (IntPtr p = (IntPtr) ptr; p != IntPtr.Zero; p = info.Next) {
705 info = new Win32_IP_ADAPTER_INFO ();
706 Marshal.PtrToStructure (p, info);
713 Win32_IP_ADAPTER_ADDRESSES addr;
714 Win32_MIB_IFROW mib4, mib6;
715 Win32IPv4InterfaceStatistics ip4stats;
716 IPInterfaceProperties ip_if_props;
718 internal Win32NetworkInterface2 (Win32_IP_ADAPTER_ADDRESSES addr)
721 mib4 = default (Win32_MIB_IFROW);
722 mib4.Index = addr.Alignment.IfIndex;
723 if (GetIfEntry (ref mib4) != 0)
724 mib4.Index = -1; // unavailable;
725 mib6 = default (Win32_MIB_IFROW);
726 mib6.Index = addr.Ipv6IfIndex;
727 if (GetIfEntry (ref mib6) != 0)
728 mib6.Index = -1; // unavailable;
729 ip4stats = new Win32IPv4InterfaceStatistics (mib4);
730 ip_if_props = new Win32IPInterfaceProperties2 (addr, mib4, mib6);
733 public override IPInterfaceProperties GetIPProperties ()
738 public override IPv4InterfaceStatistics GetIPv4Statistics ()
743 public override PhysicalAddress GetPhysicalAddress ()
745 byte [] bytes = new byte [addr.PhysicalAddressLength];
746 Array.Copy (addr.PhysicalAddress, 0, bytes, 0, bytes.Length);
747 return new PhysicalAddress (bytes);
750 public override bool Supports (NetworkInterfaceComponent networkInterfaceComponent)
752 switch (networkInterfaceComponent) {
753 case NetworkInterfaceComponent.IPv4:
754 return mib4.Index >= 0;
755 case NetworkInterfaceComponent.IPv6:
756 return mib6.Index >= 0;
761 public override string Description {
762 get { return addr.Description; }
764 public override string Id {
765 get { return addr.AdapterName; }
767 public override bool IsReceiveOnly {
768 get { return addr.IsReceiveOnly; }
770 public override string Name {
771 get { return addr.FriendlyName; }
773 public override NetworkInterfaceType NetworkInterfaceType {
774 get { return addr.IfType; }
776 public override OperationalStatus OperationalStatus {
777 get { return addr.OperStatus; }
779 public override long Speed {
780 get { return mib6.Index >= 0 ? mib6.Speed : mib4.Speed; }
782 public override bool SupportsMulticast {
783 get { return !addr.NoMulticast; }