2011-11-14 2 views
5

개방형 임베디드 리눅스에서 실행되는 내 응용 프로그램 (MVC3로 작성된 관리 웹 인터페이스)에서 모든 TCP/IP 설정을 나열해야합니다. 여기에는 IP 주소, 게이트웨이 및 서브넷 마스크가 포함됩니다.Linux에서 Mono를 사용하여 서브넷 마스크를 쿼리하는 방법은 무엇입니까?

다음 코드는 MS 닷넷에서 잘 실행되지만 모노 2.10이 "IPv4Mask" 속성에 대한 NotImplemntedException 던졌습니다 :

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

누구 하나 모노를 사용하여 IPv4의 서브넷 마스크를 얻을 수있는 방법을 알고 있나요을?

이 질문이 2009 년에 이미 제기되었지만 답변을 찾지 못했습니다.

+0

구현하도록 요청하거나 직접 구현하십시오. – leppie

+0

이미 Mono-List에 묻지 만 응답이 없습니다. 내가 직접 구현할 Linux 노하우가 없다고 생각하십시오. 어쩌면 다른 사람이 해결 방법을 알고있을 수도 있습니다. – Marc

+1

언제나'ifconfig'를 호출하고 수동으로 파싱 할 수 있습니다. – leppie

답변

5

나는 Mono 소스 코드를 살펴보고 주어진 네트워크 인터페이스의 IPv4 서브넷 마스크를 반환하는 도우미를 만들기 위해 일부 코드 조각을 추출했다. 코드는 절대적인 아름다움은 아니지만 작동합니다. 위의 도우미의

[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; 
    } 
} 

사용법은 다음과 같이이다 :

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

나는 아직 하나가 위의를 얻기 위해 모노에서 꽤 파일을 변경해야으로 모노 소스 코드에서이 문제를 해결하기 위해 관리하지 않았다 (LinuxNetworkInterface)에서 사용되는 곳까지의 정보 (LinuxUnicastIPAddressInfo). 하지만 Mono 버그보고에 코드를 게시하여 Mono 개발자 중 한 명이 볼 수 있습니다.

1

마크, 그냥 이 코드를 귀하에게 대단히 감사 말하고 싶었다. 내 응용 프로그램에서 매우 쉽게 작업 할 수 있었으며 Mono 2.10.6의 Ubuntu 10.10에서 훌륭하게 작동합니다. 나는 이것을 한 번 이상 upvote 할 수 있으면 좋겠다.

Mono에서 사용할 수없는 System.Deployment을 Win32 버전에서 사용하기 때문에 Mono 용 앱의 특별 버전을 빌드합니다. 그래서 참조를 위해, 여기 내가 사용하는 코드는 다음과 같습니다

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 

참고 : nic 그냥 NetworkInterface 객체이며 GetUnicastAddrFromNic() 난 그냥이 NIC에 대한 모든 UnicastAddresses에 보이는 것을 만든 기능이며, 그 AddressFamily 첫 번째를 반환 InterNetwork입니다.

Mono 팀의 누군가가 다음 버전에 솔루션을 적용 해 주시길 바랍니다.

+0

멋진 향상 - 감사합니다. 모노 : 모두에게 모노를 제출했지만 그 중에서 아무 것도 듣지 못했습니다. 그러나 실망스러운 일이 있습니다. – Marc

+1

네트워크 코드만큼 일반적인 것 같습니다. 최대한 빨리 포함 시키려하고 싶습니다만, M $로 유지하고 CLR로 작업 코드를 최신 상태로 유지하는 것만으로도 충분하다고 생각합니다. .. 적어도 이제는 Windows와 Windows에서 제대로 작동하는 .NET 양식과 Mono 렌더링 요소 간의 불일치 문제를 해결할 수 있습니다. ut가 Linux에서 잘못 표시됩니다. 다시 한번 감사드립니다. – drew010

관련 문제