Merge pull request #5714 from alexischr/update_bockbuild
[mono.git] / mcs / class / System / System.Net.NetworkInformation / IPInterfaceProperties.cs
1 //
2 // System.Net.NetworkInformation.IPInterfaceProperties
3 //
4 // Authors:
5 //      Gonzalo Paniagua Javier (gonzalo@novell.com)
6 //      Atsushi Enomoto (atsushi@ximian.com)
7 //
8 // Copyright (c) 2006-2007 Novell, Inc. (http://www.novell.com)
9 //
10 // Permission is hereby granted, free of charge, to any person obtaining
11 // a copy of this software and associated documentation files (the
12 // "Software"), to deal in the Software without restriction, including
13 // without limitation the rights to use, copy, modify, merge, publish,
14 // distribute, sublicense, and/or sell copies of the Software, and to
15 // permit persons to whom the Software is furnished to do so, subject to
16 // the following conditions:
17 // 
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
20 // 
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 //
29 using System.Collections.Generic;
30 using System.Globalization;
31 using System.IO;
32 using System.Net.Sockets;
33 using System.Runtime.CompilerServices;
34 using System.Text.RegularExpressions;
35 using System.Runtime.InteropServices;
36
37 namespace System.Net.NetworkInformation {
38         abstract class UnixIPInterfaceProperties : IPInterfaceProperties
39         {
40                 protected IPv4InterfaceProperties ipv4iface_properties;
41                 protected UnixNetworkInterface iface;
42                 List <IPAddress> addresses;
43                 IPAddressCollection dns_servers;
44                 
45                 public UnixIPInterfaceProperties (UnixNetworkInterface iface, List <IPAddress> addresses)
46                 {
47                         this.iface = iface;
48                         this.addresses = addresses;
49                 }
50
51                 public override IPv6InterfaceProperties GetIPv6Properties ()
52                 {
53                         throw new NotImplementedException ();
54                 }
55 #if MONODROID
56                 [DllImport ("__Internal")]
57                 static extern int _monodroid_get_dns_servers (out IntPtr dns_servers_array);
58
59                 void GetDNSServersFromOS ()
60                 {
61                         IntPtr dsa;
62                         int len = _monodroid_get_dns_servers (out dsa);
63                         if (len <= 0)
64                                 return;
65
66                         var servers = new IntPtr [len];
67                         Marshal.Copy (dsa, servers, 0, len);
68
69                         dns_servers = new IPAddressCollection ();
70                         foreach (IntPtr s in servers) {
71                                 string server_ip = Marshal.PtrToStringAnsi (s);
72                                 Marshal.FreeHGlobal (s);
73
74                                 IPAddress addr;
75                                 if (!IPAddress.TryParse (server_ip, out addr))
76                                         continue;
77                                 dns_servers.InternalAdd (addr);
78                         }
79                         Marshal.FreeHGlobal (dsa);
80                 }
81 #else
82                 static Regex ns = new Regex (@"\s*nameserver\s+(?<address>.*)");
83                 static Regex search = new Regex (@"\s*search\s+(?<domain>.*)");
84
85                 string dns_suffix;
86                 DateTime last_parse;
87
88                 void ParseResolvConf ()
89                 {
90                         try {
91                                 DateTime wt = File.GetLastWriteTime ("/etc/resolv.conf");
92                                 if (wt <= last_parse)
93                                         return;
94
95                                 last_parse = wt;
96                                 dns_suffix = "";
97                                 dns_servers = new IPAddressCollection ();
98                                 using (StreamReader reader = new StreamReader ("/etc/resolv.conf")) {
99                                         string str;
100                                         string line;
101                                         while ((line = reader.ReadLine ()) != null) {
102                                                 line = line.Trim ();
103                                                 if (line.Length == 0 || line [0] == '#')
104                                                         continue;
105                                                 Match match = ns.Match (line);
106                                                 if (match.Success) {
107                                                         try {
108                                                                 str = match.Groups ["address"].Value;
109                                                                 str = str.Trim ();
110                                                                 dns_servers.InternalAdd (IPAddress.Parse (str));
111                                                         } catch {
112                                                         }
113                                                 } else {
114                                                         match = search.Match (line);
115                                                         if (match.Success) {
116                                                                 str = match.Groups ["domain"].Value;
117                                                                 string [] parts = str.Split (',');
118                                                                 dns_suffix = parts [0].Trim ();
119                                                         }
120                                                 }
121                                         }
122                                 }
123                         } catch {
124                         }
125                 }
126 #endif
127                 public override IPAddressInformationCollection AnycastAddresses {
128                         get {
129                                 var c = new IPAddressInformationCollection ();
130                                 foreach (IPAddress address in addresses) {
131                                         c.InternalAdd (new SystemIPAddressInformation (address, false, false));
132                                 }
133                                 return c;
134                         }
135                 }
136
137                 [MonoTODO ("Always returns an empty collection.")]
138                 public override IPAddressCollection DhcpServerAddresses {
139                         get {
140                                 // There are lots of different DHCP clients
141                                 // that all store their configuration differently.
142                                 // I'm not sure what to do here.
143                                 IPAddressCollection coll = new IPAddressCollection ();
144                                 return coll;
145                         }
146                 }
147
148                 public override IPAddressCollection DnsAddresses {
149                         get {
150 #if MONODROID
151                                 GetDNSServersFromOS ();
152 #else
153                                 ParseResolvConf ();
154 #endif
155                                 return dns_servers;
156                         }
157                 }
158
159                 public override string DnsSuffix {
160                         get {
161 #if MONODROID
162                                 return String.Empty;
163 #else
164                                 ParseResolvConf ();
165                                 return dns_suffix;
166 #endif
167                         }
168                 }
169
170                 [MonoTODO ("Always returns true")]
171                 public override bool IsDnsEnabled {
172                         get {
173                                 return true;
174                         }
175                 }
176
177                 [MonoTODO ("Always returns false")]
178                 public override bool IsDynamicDnsEnabled {
179                         get {
180                                 return false;
181                         }
182                 }
183
184                 public override MulticastIPAddressInformationCollection MulticastAddresses {
185                         get {
186                                 var multicastAddresses = new MulticastIPAddressInformationCollection ();
187                                 foreach (IPAddress address in addresses) {
188                                         byte[] addressBytes = address.GetAddressBytes ();
189                                         if (addressBytes[0] >= 224 && addressBytes[0] <= 239) {
190                                                 multicastAddresses.InternalAdd (new SystemMulticastIPAddressInformation (new SystemIPAddressInformation (address, true, false)));
191                                         }
192                                 }
193                                 return multicastAddresses;
194                         }
195                 }
196
197                 public override UnicastIPAddressInformationCollection UnicastAddresses {
198                         get {
199                                 var unicastAddresses = new UnicastIPAddressInformationCollection ();
200                                 foreach (IPAddress address in addresses) {
201                                         switch (address.AddressFamily) {
202                                                 case AddressFamily.InterNetwork:
203                                                         byte top = address.GetAddressBytes () [0];
204                                                         if (top >= 224 && top <= 239)
205                                                                 continue;
206                                                         unicastAddresses.InternalAdd (new LinuxUnicastIPAddressInformation (address));
207                                                         break;
208
209                                                 case AddressFamily.InterNetworkV6:
210                                                         if (address.IsIPv6Multicast)
211                                                                 continue;
212                                                         unicastAddresses.InternalAdd (new LinuxUnicastIPAddressInformation (address));
213                                                         break;
214                                         }
215                                 }
216                                 return unicastAddresses;
217                         }
218                 }
219
220                 [MonoTODO ("Always returns an empty collection.")]
221                 public override IPAddressCollection WinsServersAddresses {
222                         get {
223                                 // I do SUPPOSE we could scrape /etc/samba/smb.conf, but.. yeesh.
224                                 return new IPAddressCollection ();
225                         }
226                 }
227         }
228
229         class LinuxIPInterfaceProperties : UnixIPInterfaceProperties
230         {
231                 public LinuxIPInterfaceProperties (LinuxNetworkInterface iface, List <IPAddress> addresses)
232                         : base (iface, addresses)
233                 {
234                 }
235
236                 public override IPv4InterfaceProperties GetIPv4Properties ()
237                 {
238                         if (ipv4iface_properties == null)
239                                 ipv4iface_properties = new LinuxIPv4InterfaceProperties (iface as LinuxNetworkInterface);
240                         
241                         return ipv4iface_properties;
242                 }
243
244                 IPAddressCollection ParseRouteInfo (string iface)
245                 {
246                         var col = new IPAddressCollection ();
247                         try {
248                                 using (StreamReader reader = new StreamReader ("/proc/net/route")) {
249                                         string line;
250                                         reader.ReadLine (); // Ignore first line
251                                         while ((line = reader.ReadLine ()) != null) {
252                                                 line = line.Trim ();
253                                                 if (line.Length == 0)
254                                                         continue;
255
256                                                 string [] parts = line.Split ('\t');
257                                                 if (parts.Length < 3)
258                                                         continue;
259                                                 string gw_address = parts [2].Trim ();
260                                                 byte [] ipbytes = new byte [4];
261                                                 if (gw_address.Length == 8 && iface.Equals (parts [0], StringComparison.OrdinalIgnoreCase)) {
262                                                         for (int i = 0; i < 4; i++) {
263                                                                 if (!Byte.TryParse (gw_address.Substring (i * 2, 2), NumberStyles.HexNumber, null, out ipbytes [3 - i]))
264                                                                         continue;
265                                                         }
266                                                         IPAddress ip = new IPAddress (ipbytes);
267                                                         if (!ip.Equals (IPAddress.Any) && !col.Contains (ip))
268                                                                 col.InternalAdd (ip);
269                                                 }
270                                         }
271                                 }
272                         } catch {
273                         }
274
275                         return col;
276                 }
277
278                 public override GatewayIPAddressInformationCollection GatewayAddresses {
279                         get {
280                                 return SystemGatewayIPAddressInformation.ToGatewayIpAddressInformationCollection (ParseRouteInfo (this.iface.Name.ToString()));
281                         }
282                 }
283         }
284
285         class MacOsIPInterfaceProperties : UnixIPInterfaceProperties
286         {
287                 public MacOsIPInterfaceProperties (MacOsNetworkInterface iface, List <IPAddress> addresses)
288                         : base (iface, addresses)
289                 {
290                 }
291
292                 public override IPv4InterfaceProperties GetIPv4Properties ()
293                 {
294                         if (ipv4iface_properties == null)
295                                 ipv4iface_properties = new MacOsIPv4InterfaceProperties (iface as MacOsNetworkInterface);
296                         
297                         return ipv4iface_properties;
298                 }
299
300                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
301                 private extern static bool ParseRouteInfo_internal(string iface, out string[] gw_addr_list);
302
303                 public override GatewayIPAddressInformationCollection GatewayAddresses {
304                         get {
305                                 var gateways = new IPAddressCollection ();
306                                 string[] gw_addrlist;
307                                 if (!ParseRouteInfo_internal (this.iface.Name.ToString(), out gw_addrlist))
308                                         return new GatewayIPAddressInformationCollection ();
309
310                                 for(int i=0; i<gw_addrlist.Length; i++) {
311                                         try {
312                                                 IPAddress ip = IPAddress.Parse(gw_addrlist[i]);
313                                                 if (!ip.Equals (IPAddress.Any) && !gateways.Contains (ip))
314                                                         gateways.InternalAdd (ip);
315                                         } catch (ArgumentNullException) {
316                                                 /* Ignore this, as the
317                                                  * internal call might have
318                                                  * left some blank entries at
319                                                  * the end of the array
320                                                  */
321                                         }
322                                 }
323
324                                 return SystemGatewayIPAddressInformation.ToGatewayIpAddressInformationCollection (gateways);
325                         }
326                 }
327         }
328
329 #if WIN_PLATFORM
330         class Win32IPInterfaceProperties2 : IPInterfaceProperties
331         {
332                 readonly Win32_IP_ADAPTER_ADDRESSES addr;
333                 readonly Win32_MIB_IFROW mib4, mib6;
334
335                 public Win32IPInterfaceProperties2 (Win32_IP_ADAPTER_ADDRESSES addr, Win32_MIB_IFROW mib4, Win32_MIB_IFROW mib6)
336                 {
337                         this.addr = addr;
338                         this.mib4 = mib4;
339                         this.mib6 = mib6;
340                 }
341
342                 public override IPv4InterfaceProperties GetIPv4Properties ()
343                 {
344                         Win32_IP_ADAPTER_INFO v4info = Win32NetworkInterface2.GetAdapterInfoByIndex (mib4.Index);
345                         return new Win32IPv4InterfaceProperties (v4info, mib4);
346                 }
347
348                 public override IPv6InterfaceProperties GetIPv6Properties ()
349                 {
350                         Win32_IP_ADAPTER_INFO v6info = Win32NetworkInterface2.GetAdapterInfoByIndex (mib6.Index);
351                         return new Win32IPv6InterfaceProperties (mib6);
352                 }
353
354                 public override IPAddressInformationCollection AnycastAddresses {
355                         get { return Win32FromAnycast (addr.FirstAnycastAddress); }
356                 }
357
358                 static IPAddressInformationCollection Win32FromAnycast (IntPtr ptr)
359                 {
360                         var c = new IPAddressInformationCollection ();
361                         Win32_IP_ADAPTER_ANYCAST_ADDRESS a;
362                         for (IntPtr p = ptr; p != IntPtr.Zero; p = a.Next) {
363                                 a = (Win32_IP_ADAPTER_ANYCAST_ADDRESS) Marshal.PtrToStructure (p, typeof (Win32_IP_ADAPTER_ANYCAST_ADDRESS));
364                                 c.InternalAdd (new SystemIPAddressInformation (
365                                        a.Address.GetIPAddress (),
366                                        a.LengthFlags.IsDnsEligible,
367                                        a.LengthFlags.IsTransient));
368                         }
369                         return c;
370                 }
371
372                 public override IPAddressCollection DhcpServerAddresses {
373                         get {
374                                 Win32_IP_ADAPTER_INFO v4info = Win32NetworkInterface2.GetAdapterInfoByIndex (mib4.Index);
375                                 // FIXME: should ipv6 DhcpServer be considered?
376                                 try {
377                                         return new Win32IPAddressCollection (v4info.DhcpServer);
378                                 } catch (IndexOutOfRangeException) {
379                                         return Win32IPAddressCollection.Empty;
380                                 }
381                         }
382                 }
383
384                 public override IPAddressCollection DnsAddresses {
385                         get { return Win32IPAddressCollection.FromDnsServer (addr.FirstDnsServerAddress); }
386                 }
387
388                 public override string DnsSuffix {
389                         get { return addr.DnsSuffix; }
390                 }
391
392                 public override GatewayIPAddressInformationCollection GatewayAddresses {
393                         get {
394                                 var col = new GatewayIPAddressInformationCollection ();
395                                 try {
396                                         Win32_IP_ADAPTER_INFO v4info = Win32NetworkInterface2.GetAdapterInfoByIndex (mib4.Index);
397                                         // FIXME: should ipv6 DhcpServer be considered?
398
399                                         var a = v4info.GatewayList;
400                                         if (!String.IsNullOrEmpty (a.IpAddress)) {
401                                                 col.InternalAdd(new SystemGatewayIPAddressInformation(IPAddress.Parse (a.IpAddress)));
402                                                 AddSubsequently (a.Next, col);
403                                         }
404                                 } catch (IndexOutOfRangeException) {}
405                                 return col;
406                         }
407                 }
408
409                 static void AddSubsequently (IntPtr head, GatewayIPAddressInformationCollection col)
410                 {
411                         Win32_IP_ADDR_STRING a;
412                         for (IntPtr p = head; p != IntPtr.Zero; p = a.Next) {
413                                 a = (Win32_IP_ADDR_STRING) Marshal.PtrToStructure (p, typeof (Win32_IP_ADDR_STRING));
414                                 col.InternalAdd (new SystemGatewayIPAddressInformation (IPAddress.Parse (a.IpAddress)));
415                         }
416                 }
417
418                 public override bool IsDnsEnabled {
419                         get { return Win32NetworkInterface.FixedInfo.EnableDns != 0; }
420                 }
421
422                 public override bool IsDynamicDnsEnabled {
423                         get { return addr.DdnsEnabled; }
424                 }
425
426                 public override MulticastIPAddressInformationCollection MulticastAddresses {
427                         get { return Win32FromMulticast (addr.FirstMulticastAddress); }
428                 }
429
430                 static MulticastIPAddressInformationCollection Win32FromMulticast (IntPtr ptr)
431                 {
432                         var c = new MulticastIPAddressInformationCollection ();
433                         Win32_IP_ADAPTER_MULTICAST_ADDRESS a;
434                         for (IntPtr p = ptr; p != IntPtr.Zero; p = a.Next) {
435                                 a = (Win32_IP_ADAPTER_MULTICAST_ADDRESS) Marshal.PtrToStructure (p, typeof (Win32_IP_ADAPTER_MULTICAST_ADDRESS));
436                                 c.InternalAdd (new SystemMulticastIPAddressInformation (new SystemIPAddressInformation (
437                                        a.Address.GetIPAddress (),
438                                        a.LengthFlags.IsDnsEligible,
439                                        a.LengthFlags.IsTransient)));
440                         }
441                         return c;
442                 }
443
444                 public override UnicastIPAddressInformationCollection UnicastAddresses {
445                         get {
446                                 try {
447                                         Win32_IP_ADAPTER_INFO ai = Win32NetworkInterface2.GetAdapterInfoByIndex (mib4.Index);
448                                         // FIXME: should ipv6 DhcpServer be considered?
449                                         return Win32FromUnicast (addr.FirstUnicastAddress);
450                                 } catch (IndexOutOfRangeException) {
451                                         return new UnicastIPAddressInformationCollection ();
452                                 }
453                         }
454                 }
455
456                 static UnicastIPAddressInformationCollection Win32FromUnicast (IntPtr ptr)
457                 {
458                         UnicastIPAddressInformationCollection c = new UnicastIPAddressInformationCollection ();
459                         Win32_IP_ADAPTER_UNICAST_ADDRESS a;
460                         for (IntPtr p = ptr; p != IntPtr.Zero; p = a.Next) {
461                                 a = (Win32_IP_ADAPTER_UNICAST_ADDRESS) Marshal.PtrToStructure (p, typeof (Win32_IP_ADAPTER_UNICAST_ADDRESS));
462                                 c.InternalAdd (new Win32UnicastIPAddressInformation (a));
463                         }
464                         return c;
465                 }
466
467                 public override IPAddressCollection WinsServersAddresses {
468                         get {
469                                 try {
470                                         Win32_IP_ADAPTER_INFO v4info = Win32NetworkInterface2.GetAdapterInfoByIndex (mib4.Index);
471                                         // FIXME: should ipv6 DhcpServer be considered?
472                                         return new Win32IPAddressCollection (v4info.PrimaryWinsServer, v4info.SecondaryWinsServer);
473                                 } catch (IndexOutOfRangeException) {
474                                         return Win32IPAddressCollection.Empty;
475                                 }
476                         }
477                 }
478
479         }
480 #endif
481
482 }
483
484