2011-11-14 10 views
5

En mi aplicación (interfaz web de administración escrita en MVC3) que se ejecuta en Linux abierto incrustado, tengo que enumerar todas las configuraciones de TCP/IP. Esto incluye IP-Adresse, Gateway y la máscara de subred.¿Cómo consultar las máscaras de subred usando Mono en Linux?

El siguiente código funciona bien bajo MS .Net pero Mono 2.10 lanza una NotImplemntedException para la propiedad "IPv4Mask":

var ipProperties = networkIntf.GetIPProperties(); 
var unicastIpInfo = ipProperties.UnicastAddresses.FirstOrDefault(); 
var subnetMask = unicastAddress != null ? unicastAddress.IPv4Mask.ToString() : ""; 

¿Alguien sabe cómo se puede obtener la máscara de subred IPv4 usando Mono?

Encontré que esta pregunta ya se hizo en 2009, pero no encontré ninguna respuesta.

+0

O pídales que lo implementen o impleméntelo usted mismo. – leppie

+0

Preguntado ya en la Mono-List pero no obtuvo ninguna respuesta. Creo que no tengo los conocimientos de Linux para implementarlo yo mismo. Entonces, tal vez alguien más sepa una solución alternativa. – Marc

+1

Siempre puede llamar a 'ifconfig' y analizarlo manualmente. – leppie

Respuesta

5

Eché un vistazo a algún código fuente Mono y extraje algunos fragmentos de código para crear un helper que devuelva una máscara de subred IPv4 de la interfaz de red dada. El código no es una belleza absoluta, pero funciona.

[StructLayout(LayoutKind.Explicit)] 
struct ifa_ifu 
{ 
    [FieldOffset(0)] 
    public IntPtr ifu_broadaddr; 

    [FieldOffset(0)] 
    public IntPtr ifu_dstaddr; 
} 

[StructLayout(LayoutKind.Sequential)] 
struct ifaddrs 
{ 
    public IntPtr ifa_next; 
    public string ifa_name; 
    public uint ifa_flags; 
    public IntPtr ifa_addr; 
    public IntPtr ifa_netmask; 
    public ifa_ifu ifa_ifu; 
    public IntPtr ifa_data; 
} 

[StructLayout(LayoutKind.Sequential)] 
struct sockaddr_in 
{ 
    public ushort sin_family; 
    public ushort sin_port; 
    public uint sin_addr; 
} 

[StructLayout(LayoutKind.Sequential)] 
struct sockaddr_in6 
{ 
    public ushort sin6_family; /* AF_INET6 */ 
    public ushort sin6_port;  /* Transport layer port # */ 
    public uint sin6_flowinfo; /* IPv6 flow information */ 
    public in6_addr sin6_addr;  /* IPv6 address */ 
    public uint sin6_scope_id; /* scope id (new in RFC2553) */ 
} 

[StructLayout(LayoutKind.Sequential)] 
struct in6_addr 
{ 
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] 
    public byte[] u6_addr8; 
} 

[StructLayout(LayoutKind.Sequential)] 
struct sockaddr_ll 
{ 
    public ushort sll_family; 
    public ushort sll_protocol; 
    public int sll_ifindex; 
    public ushort sll_hatype; 
    public byte sll_pkttype; 
    public byte sll_halen; 

    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] 
    public byte[] sll_addr; 
} 

internal class IPInfoTools 
{ 
    const int AF_INET = 2; 
    const int AF_INET6 = 10; 
    const int AF_PACKET = 17; 

    [DllImport("libc")] 
    static extern int getifaddrs (out IntPtr ifap); 

    [DllImport ("libc")] 
    static extern void freeifaddrs (IntPtr ifap); 

    internal static string GetIPv4Mask(string networkInterfaceName) 
    { 
     IntPtr ifap; 
     if (getifaddrs(out ifap) != 0) 
     { 
      throw new SystemException("getifaddrs() failed"); 
     } 

     try 
     { 
      var next = ifap; 
      while (next != IntPtr.Zero) 
      { 
       var addr = (ifaddrs)Marshal.PtrToStructure(next, typeof(ifaddrs)); 
       var name = addr.ifa_name; 

       if (addr.ifa_addr != IntPtr.Zero) 
       { 
        var sockaddr = (sockaddr_in)Marshal.PtrToStructure(addr.ifa_addr, typeof(sockaddr_in)); 
        switch (sockaddr.sin_family) 
        { 
         case AF_INET6: 
          //sockaddr_in6 sockaddr6 = (sockaddr_in6)Marshal.PtrToStructure(addr.ifa_addr, typeof(sockaddr_in6)); 
          break; 
         case AF_INET: 
          if (name == networkInterfaceName) 
          { 
           var netmask = (sockaddr_in)Marshal.PtrToStructure(addr.ifa_netmask, typeof(sockaddr_in)); 
           var ipAddr = new IPAddress(netmask.sin_addr); // IPAddress to format into default string notation 
           return ipAddr.ToString(); 
          } 
          break; 
         case AF_PACKET: 
          { 
           var sockaddrll = (sockaddr_ll)Marshal.PtrToStructure(addr.ifa_addr, typeof(sockaddr_ll)); 
           if (sockaddrll.sll_halen > sockaddrll.sll_addr.Length) 
           { 
            Console.Error.WriteLine("Got a bad hardware address length for an AF_PACKET {0} {1}", 
                  sockaddrll.sll_halen, sockaddrll.sll_addr.Length); 
            next = addr.ifa_next; 
            continue; 
           } 
          } 
          break; 
        } 
       } 

       next = addr.ifa_next; 
      } 
     } 
     finally 
     { 
      freeifaddrs(ifap); 
     } 

     return null; 
    } 
} 

Uso del ayudante de arriba es como esto:

String subnetMask = IPInfoTools.GetIPv4Mask("etc0"); 

aún no tenía arreglo para solucionar este problema en el código fuente mono como uno tiene que cambiar bastantes archivos en mono para conseguir lo anterior información del lugar donde se consulta (LinuxNetworkInterface) al lugar donde se utiliza (LinuxUnicastIPAddressInfo). Pero publicaré mi código en el informe de errores de Mono para que tal vez uno de los desarrolladores de Mono pueda echarle un vistazo.

1

Marc, solo quería decir MUCHAS GRACIAS para este código. Pude hacerlo funcionar en mi aplicación muy fácilmente y funciona muy bien en Ubuntu 10.10 en Mono 2.10.6. Desearía poder votar esto más de una vez.

Creo una versión especial de la aplicación para Mono ya que la versión de Win32 usa System.Deployment que no está disponible en Mono; por lo que para referencia, aquí está el código que utilicé:

UnicastIPAddressInformation addr = GetUnicastAddrFromNic(nic.GetIPProperties().UnicastAddresses); 

#if BUILD4MONO 
string mask = null; 
try { 
    mask = IPInfoTools.GetIPv4Mask(nic.Name); // Marc's function - nic.Name is eth0 or wlan1 etc. 
} catch (Exception ex) { // getifaddrs failed 
    Console.WriteLine("GetIPRangeInfoFromNetworkInterface failed: {0}", ex.Message); 
} 

if (mask == null || IPAddress.TryParse(mask, out rangeInfo.SubnetMask) == false) { 
    rangeInfo.SubnetMask = IPAddress.Parse("255.255.255.0"); // default to this 
} 
#else 
rangeInfo.SubnetMask = addr.IPv4Mask; // Win32 
#endif 

Nota: nic es sólo un objeto NetworkInterface y GetUnicastAddrFromNic() es una función que hice que sólo se ve en todos los UnicastAddresses para el NIC y devuelve el primero cuya AddressFamily es InterNetwork.

Esperemos que alguien del equipo Mono aplique su solución en una próxima versión.

+0

Bonita mejora - ¡gracias! Mono: Envié todo a Mono pero no escuché nada de ellos. Es algo decepcionante, pero bueno ... – Marc

+1

Sí, por algo tan común como el código de red. Me gustaría verlo incluido lo antes posible, pero supongo que es bastante difícil mantenerse al día con M $ y mantener su código de trabajo actualizado con el CLR. Al menos ahora puedo pasar a corregir las incoherencias entre los elementos de representación de .NET y Mono en mi formulario que funcionan bien en Windows b ut muestra incorrectamente en Linux. Gracias de nuevo. – drew010

Cuestiones relacionadas