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.
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).
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With