Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to query the subnet mask(s) using Mono on Linux?

In my application (admin web interface written in MVC3) running on open-embedded Linux I have to list all the TCP/IP settings. This includes IP-Adresse, Gateway and the subnet mask.

The following code runs well under MS .Net but Mono 2.10 throws a NotImplemntedException for the "IPv4Mask" property:

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

Does anybody know how one can get the IPv4 subnet mask using Mono?

I found this question was asked already in 2009 but didn't find any answer to it.

like image 300
Marc Avatar asked Nov 14 '11 09:11

Marc


People also ask

How do I find my subnet mask in Linux?

In order to find the subnet mask for your host, use the “ifconfig” command with the interface name and pipe it with the “grep” command to isolate the “mask” string. In this case, you are presented with subnet masks for every network interface (loopback interface included).

How do I find gateway and netmask in Linux?

You can use ifconfig , it will show your inet address (IP) and mask. For the gateway, issue the ip route command and take note of the default route. Hope this can help you.


2 Answers

I took a look at some Mono sourcecode and extracted some code-snippets to build a helper that returns a the IPv4 subnet mask of the given network interface. The code is not an absolute beauty but it works.

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

Usage of the above helper is like this:

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

I didn't yet manage to fix this in the Mono sourcecode as one needs to change quite some files in Mono to get the above information from the place where it is queried (LinuxNetworkInterface) to the place where it is used (LinuxUnicastIPAddressInfo). But I will post my code to the Mono bug-report so maybe one of the Mono developers can take a look.

like image 85
Marc Avatar answered Sep 30 '22 15:09

Marc


Marc, just wanted to say THANK YOU VERY MUCH for this code. I was able to get it working in my application very easily and it works great on Ubuntu 10.10 on Mono 2.10.6. I wish I could upvote this more than once.

I build a special version of the app for Mono since the Win32 version uses System.Deployment which is not available on Mono; so for reference, here is the code I used:

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

Note: nic is just a NetworkInterface object and GetUnicastAddrFromNic() is a function I made that just looks at all the UnicastAddresses for the nic and returns the first one whose AddressFamily is InterNetwork.

Hopefully someone from the Mono team will apply your solution in an upcoming version.

like image 24
drew010 Avatar answered Sep 30 '22 14:09

drew010