Merge pull request #3142 from henricm/fix-for-win-mono_string_to_utf8
[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                 string dns_suffix;
45                 DateTime last_parse;
46                 
47                 public UnixIPInterfaceProperties (UnixNetworkInterface iface, List <IPAddress> addresses)
48                 {
49                         this.iface = iface;
50                         this.addresses = addresses;
51                 }
52
53                 public override IPv6InterfaceProperties GetIPv6Properties ()
54                 {
55                         throw new NotImplementedException ();
56                 }
57
58                 static Regex ns = new Regex (@"\s*nameserver\s+(?<address>.*)");
59                 static Regex search = new Regex (@"\s*search\s+(?<domain>.*)");
60                 void ParseResolvConf ()
61                 {
62                         try {
63                                 DateTime wt = File.GetLastWriteTime ("/etc/resolv.conf");
64                                 if (wt <= last_parse)
65                                         return;
66
67                                 last_parse = wt;
68                                 dns_suffix = "";
69                                 dns_servers = new IPAddressCollection ();
70                                 using (StreamReader reader = new StreamReader ("/etc/resolv.conf")) {
71                                         string str;
72                                         string line;
73                                         while ((line = reader.ReadLine ()) != null) {
74                                                 line = line.Trim ();
75                                                 if (line.Length == 0 || line [0] == '#')
76                                                         continue;
77                                                 Match match = ns.Match (line);
78                                                 if (match.Success) {
79                                                         try {
80                                                                 str = match.Groups ["address"].Value;
81                                                                 str = str.Trim ();
82                                                                 dns_servers.InternalAdd (IPAddress.Parse (str));
83                                                         } catch {
84                                                         }
85                                                 } else {
86                                                         match = search.Match (line);
87                                                         if (match.Success) {
88                                                                 str = match.Groups ["domain"].Value;
89                                                                 string [] parts = str.Split (',');
90                                                                 dns_suffix = parts [0].Trim ();
91                                                         }
92                                                 }
93                                         }
94                                 }
95                         } catch {
96                         }
97                 }
98
99                 public override IPAddressInformationCollection AnycastAddresses {
100                         get {
101                                 var c = new IPAddressInformationCollection ();
102                                 foreach (IPAddress address in addresses) {
103                                         c.InternalAdd (new SystemIPAddressInformation (address, false, false));
104                                 }
105                                 return c;
106                         }
107                 }
108
109                 [MonoTODO ("Always returns an empty collection.")]
110                 public override IPAddressCollection DhcpServerAddresses {
111                         get {
112                                 // There are lots of different DHCP clients
113                                 // that all store their configuration differently.
114                                 // I'm not sure what to do here.
115                                 IPAddressCollection coll = new IPAddressCollection ();
116                                 return coll;
117                         }
118                 }
119
120                 public override IPAddressCollection DnsAddresses {
121                         get {
122                                 ParseResolvConf ();
123                                 return dns_servers;
124                         }
125                 }
126
127                 public override string DnsSuffix {
128                         get {
129                                 ParseResolvConf ();
130                                 return dns_suffix;
131                         }
132                 }
133
134                 [MonoTODO ("Always returns true")]
135                 public override bool IsDnsEnabled {
136                         get {
137                                 return true;
138                         }
139                 }
140
141                 [MonoTODO ("Always returns false")]
142                 public override bool IsDynamicDnsEnabled {
143                         get {
144                                 return false;
145                         }
146                 }
147
148                 public override MulticastIPAddressInformationCollection MulticastAddresses {
149                         get {
150                                 var multicastAddresses = new MulticastIPAddressInformationCollection ();
151                                 foreach (IPAddress address in addresses) {
152                                         byte[] addressBytes = address.GetAddressBytes ();
153                                         if (addressBytes[0] >= 224 && addressBytes[0] <= 239) {
154                                                 multicastAddresses.InternalAdd (new SystemMulticastIPAddressInformation (new SystemIPAddressInformation (address, true, false)));
155                                         }
156                                 }
157                                 return multicastAddresses;
158                         }
159                 }
160
161                 public override UnicastIPAddressInformationCollection UnicastAddresses {
162                         get {
163                                 var unicastAddresses = new UnicastIPAddressInformationCollection ();
164                                 foreach (IPAddress address in addresses) {
165                                         switch (address.AddressFamily) {
166                                                 case AddressFamily.InterNetwork:
167                                                         byte top = address.GetAddressBytes () [0];
168                                                         if (top >= 224 && top <= 239)
169                                                                 continue;
170                                                         unicastAddresses.InternalAdd (new LinuxUnicastIPAddressInformation (address));
171                                                         break;
172
173                                                 case AddressFamily.InterNetworkV6:
174                                                         if (address.IsIPv6Multicast)
175                                                                 continue;
176                                                         unicastAddresses.InternalAdd (new LinuxUnicastIPAddressInformation (address));
177                                                         break;
178                                         }
179                                 }
180                                 return unicastAddresses;
181                         }
182                 }
183
184                 [MonoTODO ("Always returns an empty collection.")]
185                 public override IPAddressCollection WinsServersAddresses {
186                         get {
187                                 // I do SUPPOSE we could scrape /etc/samba/smb.conf, but.. yeesh.
188                                 return new IPAddressCollection ();
189                         }
190                 }
191         }
192
193         class LinuxIPInterfaceProperties : UnixIPInterfaceProperties
194         {
195                 public LinuxIPInterfaceProperties (LinuxNetworkInterface iface, List <IPAddress> addresses)
196                         : base (iface, addresses)
197                 {
198                 }
199
200                 public override IPv4InterfaceProperties GetIPv4Properties ()
201                 {
202                         if (ipv4iface_properties == null)
203                                 ipv4iface_properties = new LinuxIPv4InterfaceProperties (iface as LinuxNetworkInterface);
204                         
205                         return ipv4iface_properties;
206                 }
207
208                 IPAddressCollection ParseRouteInfo (string iface)
209                 {
210                         var col = new IPAddressCollection ();
211                         try {
212                                 using (StreamReader reader = new StreamReader ("/proc/net/route")) {
213                                         string line;
214                                         reader.ReadLine (); // Ignore first line
215                                         while ((line = reader.ReadLine ()) != null) {
216                                                 line = line.Trim ();
217                                                 if (line.Length == 0)
218                                                         continue;
219
220                                                 string [] parts = line.Split ('\t');
221                                                 if (parts.Length < 3)
222                                                         continue;
223                                                 string gw_address = parts [2].Trim ();
224                                                 byte [] ipbytes = new byte [4];
225                                                 if (gw_address.Length == 8 && iface.Equals (parts [0], StringComparison.OrdinalIgnoreCase)) {
226                                                         for (int i = 0; i < 4; i++) {
227                                                                 if (!Byte.TryParse (gw_address.Substring (i * 2, 2), NumberStyles.HexNumber, null, out ipbytes [3 - i]))
228                                                                         continue;
229                                                         }
230                                                         IPAddress ip = new IPAddress (ipbytes);
231                                                         if (!ip.Equals (IPAddress.Any) && !col.Contains (ip))
232                                                                 col.InternalAdd (ip);
233                                                 }
234                                         }
235                                 }
236                         } catch {
237                         }
238
239                         return col;
240                 }
241
242                 public override GatewayIPAddressInformationCollection GatewayAddresses {
243                         get {
244                                 return SystemGatewayIPAddressInformation.ToGatewayIpAddressInformationCollection (ParseRouteInfo (this.iface.Name.ToString()));
245                         }
246                 }
247         }
248
249         class MacOsIPInterfaceProperties : UnixIPInterfaceProperties
250         {
251                 public MacOsIPInterfaceProperties (MacOsNetworkInterface iface, List <IPAddress> addresses)
252                         : base (iface, addresses)
253                 {
254                 }
255
256                 public override IPv4InterfaceProperties GetIPv4Properties ()
257                 {
258                         if (ipv4iface_properties == null)
259                                 ipv4iface_properties = new MacOsIPv4InterfaceProperties (iface as MacOsNetworkInterface);
260                         
261                         return ipv4iface_properties;
262                 }
263
264                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
265                 private extern static bool ParseRouteInfo_internal(string iface, out string[] gw_addr_list);
266
267                 public override GatewayIPAddressInformationCollection GatewayAddresses {
268                         get {
269                                 var gateways = new IPAddressCollection ();
270                                 string[] gw_addrlist;
271                                 if (!ParseRouteInfo_internal (this.iface.Name.ToString(), out gw_addrlist))
272                                         return new GatewayIPAddressInformationCollection ();
273
274                                 for(int i=0; i<gw_addrlist.Length; i++) {
275                                         try {
276                                                 IPAddress ip = IPAddress.Parse(gw_addrlist[i]);
277                                                 if (!ip.Equals (IPAddress.Any) && !gateways.Contains (ip))
278                                                         gateways.InternalAdd (ip);
279                                         } catch (ArgumentNullException) {
280                                                 /* Ignore this, as the
281                                                  * internal call might have
282                                                  * left some blank entries at
283                                                  * the end of the array
284                                                  */
285                                         }
286                                 }
287
288                                 return SystemGatewayIPAddressInformation.ToGatewayIpAddressInformationCollection (gateways);
289                         }
290                 }
291         }
292
293 #if !MOBILE
294         class Win32IPInterfaceProperties2 : IPInterfaceProperties
295         {
296                 readonly Win32_IP_ADAPTER_ADDRESSES addr;
297                 readonly Win32_MIB_IFROW mib4, mib6;
298
299                 public Win32IPInterfaceProperties2 (Win32_IP_ADAPTER_ADDRESSES addr, Win32_MIB_IFROW mib4, Win32_MIB_IFROW mib6)
300                 {
301                         this.addr = addr;
302                         this.mib4 = mib4;
303                         this.mib6 = mib6;
304                 }
305
306                 public override IPv4InterfaceProperties GetIPv4Properties ()
307                 {
308                         Win32_IP_ADAPTER_INFO v4info = Win32NetworkInterface2.GetAdapterInfoByIndex (mib4.Index);
309                         return v4info != null ? new Win32IPv4InterfaceProperties (v4info, mib4) : null;
310                 }
311
312                 public override IPv6InterfaceProperties GetIPv6Properties ()
313                 {
314                         Win32_IP_ADAPTER_INFO v6info = Win32NetworkInterface2.GetAdapterInfoByIndex (mib6.Index);
315                         return v6info != null ? new Win32IPv6InterfaceProperties (mib6) : null;
316                 }
317
318                 public override IPAddressInformationCollection AnycastAddresses {
319                         get { return Win32FromAnycast (addr.FirstAnycastAddress); }
320                 }
321
322                 static IPAddressInformationCollection Win32FromAnycast (IntPtr ptr)
323                 {
324                         var c = new IPAddressInformationCollection ();
325                         Win32_IP_ADAPTER_ANYCAST_ADDRESS a;
326                         for (IntPtr p = ptr; p != IntPtr.Zero; p = a.Next) {
327                                 a = (Win32_IP_ADAPTER_ANYCAST_ADDRESS) Marshal.PtrToStructure (p, typeof (Win32_IP_ADAPTER_ANYCAST_ADDRESS));
328                                 c.InternalAdd (new SystemIPAddressInformation (
329                                        a.Address.GetIPAddress (),
330                                        a.LengthFlags.IsDnsEligible,
331                                        a.LengthFlags.IsTransient));
332                         }
333                         return c;
334                 }
335
336                 public override IPAddressCollection DhcpServerAddresses {
337                         get {
338                                 Win32_IP_ADAPTER_INFO v4info = Win32NetworkInterface2.GetAdapterInfoByIndex (mib4.Index);
339                                 // FIXME: should ipv6 DhcpServer be considered?
340                                 return v4info != null ? new Win32IPAddressCollection (v4info.DhcpServer) : Win32IPAddressCollection.Empty;
341                         }
342                 }
343
344                 public override IPAddressCollection DnsAddresses {
345                         get { return Win32IPAddressCollection.FromDnsServer (addr.FirstDnsServerAddress); }
346                 }
347
348                 public override string DnsSuffix {
349                         get { return addr.DnsSuffix; }
350                 }
351
352                 public override GatewayIPAddressInformationCollection GatewayAddresses {
353                         get {
354                                 Win32_IP_ADAPTER_INFO v4info = Win32NetworkInterface2.GetAdapterInfoByIndex (mib4.Index);
355                                 // FIXME: should ipv6 DhcpServer be considered?
356
357                                 var col = new GatewayIPAddressInformationCollection ();
358                                 if (v4info != null) {
359                                         var a = v4info.GatewayList;
360                                         if (!String.IsNullOrEmpty (a.IpAddress)) {
361                                                 col.InternalAdd(new SystemGatewayIPAddressInformation(IPAddress.Parse (a.IpAddress)));
362                                                 AddSubsequently (a.Next, col);
363                                         }
364                                 }
365
366                                 return col;
367                         }
368                 }
369
370                 static void AddSubsequently (IntPtr head, GatewayIPAddressInformationCollection col)
371                 {
372                         Win32_IP_ADDR_STRING a;
373                         for (IntPtr p = head; p != IntPtr.Zero; p = a.Next) {
374                                 a = (Win32_IP_ADDR_STRING) Marshal.PtrToStructure (p, typeof (Win32_IP_ADDR_STRING));
375                                 col.InternalAdd (new SystemGatewayIPAddressInformation (IPAddress.Parse (a.IpAddress)));
376                         }
377                 }
378
379                 public override bool IsDnsEnabled {
380                         get { return Win32_FIXED_INFO.Instance.EnableDns != 0; }
381                 }
382
383                 public override bool IsDynamicDnsEnabled {
384                         get { return addr.DdnsEnabled; }
385                 }
386
387                 public override MulticastIPAddressInformationCollection MulticastAddresses {
388                         get { return Win32FromMulticast (addr.FirstMulticastAddress); }
389                 }
390
391                 static MulticastIPAddressInformationCollection Win32FromMulticast (IntPtr ptr)
392                 {
393                         var c = new MulticastIPAddressInformationCollection ();
394                         Win32_IP_ADAPTER_MULTICAST_ADDRESS a;
395                         for (IntPtr p = ptr; p != IntPtr.Zero; p = a.Next) {
396                                 a = (Win32_IP_ADAPTER_MULTICAST_ADDRESS) Marshal.PtrToStructure (p, typeof (Win32_IP_ADAPTER_MULTICAST_ADDRESS));
397                                 c.InternalAdd (new SystemMulticastIPAddressInformation (new SystemIPAddressInformation (
398                                        a.Address.GetIPAddress (),
399                                        a.LengthFlags.IsDnsEligible,
400                                        a.LengthFlags.IsTransient)));
401                         }
402                         return c;
403                 }
404
405                 public override UnicastIPAddressInformationCollection UnicastAddresses {
406                         get {
407                                 Win32_IP_ADAPTER_INFO ai = Win32NetworkInterface2.GetAdapterInfoByIndex (mib4.Index);
408                                 // FIXME: should ipv6 DhcpServer be considered?
409                                 return ai != null ? Win32FromUnicast ((int) ai.Index, addr.FirstUnicastAddress) : new UnicastIPAddressInformationCollection ();
410                         }
411                 }
412
413                 static UnicastIPAddressInformationCollection Win32FromUnicast (int ifIndex, IntPtr ptr)
414                 {
415                         UnicastIPAddressInformationCollection c = new UnicastIPAddressInformationCollection ();
416                         Win32_IP_ADAPTER_UNICAST_ADDRESS a;
417                         for (IntPtr p = ptr; p != IntPtr.Zero; p = a.Next) {
418                                 a = (Win32_IP_ADAPTER_UNICAST_ADDRESS) Marshal.PtrToStructure (p, typeof (Win32_IP_ADAPTER_UNICAST_ADDRESS));
419                                 c.Add (new Win32UnicastIPAddressInformation (ifIndex, a));
420                         }
421                         return c;
422                 }
423
424                 public override IPAddressCollection WinsServersAddresses {
425                         get {
426                                 Win32_IP_ADAPTER_INFO v4info = Win32NetworkInterface2.GetAdapterInfoByIndex (mib4.Index);
427                                 // FIXME: should ipv6 DhcpServer be considered?
428                                 return v4info != null ? new Win32IPAddressCollection (v4info.PrimaryWinsServer, v4info.SecondaryWinsServer) : Win32IPAddressCollection.Empty;
429                         }
430                 }
431
432         }
433 #endif
434
435 }
436
437