Programmatically Getting the Gateway and Subnet Mask Details

Programmatically getting the gateway and subnet mask details

I have found a class called DhcpInfo within the android.net package. It has some public variables that stores the values of current Network parameters. But the problem is they return the value in integer converted from 8Bit shifted binary.

Sample Image Describing thee Scenario:

Sample Image

****Here is a sample code:**

**java file:****

package com.schogini.dhcp;

import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.widget.TextView;
import android.net.*;
import android.net.wifi.WifiManager;

public class dhcpInfo extends Activity {
public String s_dns1 ;
public String s_dns2;
public String s_gateway;
public String s_ipAddress;
public String s_leaseDuration;
public String s_netmask;
public String s_serverAddress;
TextView info;
DhcpInfo d;
WifiManager wifii;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
wifii= (WifiManager) getSystemService(Context.WIFI_SERVICE);
d=wifii.getDhcpInfo();

s_dns1="DNS 1: "+String.valueOf(d.dns1);
s_dns2="DNS 2: "+String.valueOf(d.dns2);
s_gateway="Default Gateway: "+String.valueOf(d.gateway);
s_ipAddress="IP Address: "+String.valueOf(d.ipAddress);
s_leaseDuration="Lease Time: "+String.valueOf(d.leaseDuration);
s_netmask="Subnet Mask: "+String.valueOf(d.netmask);
s_serverAddress="Server IP: "+String.valueOf(d.serverAddress);

//dispaly them
info= (TextView) findViewById(R.id.infolbl);
info.setText("Network Info\n"+s_dns1+"\n"+s_dns2+"\n"+s_gateway+"\n"+s_ipAddress+"\n"+s_leaseDuration+"\n"+s_netmask+"\n"+s_serverAddress);
}
}

xml Coding:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.schogini.dhcp"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk android:minSdkVersion="4" />

<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".dhcpInfo"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
</manifest>

I tried converting the integer value to its equivalent but i couldn't. If you do so you can post back.. Bye..

UPDATE: Some how managed to convert the IP to v4 Format from the integer form
Conversion to IPv4 Format:

public String intToIp(int i) {

return ((i >> 24 ) & 0xFF ) + "." +
((i >> 16 ) & 0xFF) + "." +
((i >> 8 ) & 0xFF) + "." +
( i & 0xFF) ;
}

IMAGE Courtesy: http://www.bennadel.com/blog/1830-Converting-IP-Addresses-To-And-From-Integer-Values-With-ColdFusion.htm

get subnet mask and gateway from IP address

You cannot calculate your subnet mask or gateway from just an IP address.

You can calculate the range that a potential gateway could be in given an IP address and a netmask. But, the range is basically ((My LAN segment Size) - MyIP). Generally this will be around 253 IP addresses unless you're on a large network.

Given a gateway and a netmask you can calculate a range of potential IP addresses you can configure yourself to use - but if you're manually configuring then you have the chance of clobbering an existing IP address. (This is why DHCP is good)

Given a gateway and an IP address you can calculate enough of your netmask that you can get your traffic to be routed - but depending on the subnet configuration you may not be able to talk to other machines that are on the same LAN segment. An example of this would be if your gateway is 10.1.3.254 and you configure your netmask as 255.255.255.0. The gateway (and the LAN) could actually be masked as 255.255.254.0 (basically, 2 class Cs worth of addresses in a contiguous segment).. So, you'd be able to get to the internet, but you might not be able to talk with 'local machines'.

In summation these are the possible outcomes:

  • mask + gateway = guessable but non-definitive IP address
  • mask + ip = guessable but non-definitive range of IP addresses you might find a
    gateway
  • ip + gateway = guessable but potentially misconfigured
    netmask

How to collect network information programmatically

I just editted code from selected answer in below question to get needed network information. It's not seems smart but worked for my case.

How to configue a static IP address, netmask, gateway programmatically on Android 3.x or 4.x

How can I programmatically find the IP address/netmask/gateway configured for a specific network device in Linux?

There sure is using a struct of ifreq and ioctl() calls you can grab all interface information:

Man page is here Ifreq manpage

/* local interface info */
typedef struct{
char *iface;
struct ether_addr hwa;
struct in_addr ipa;
struct in_addr bcast;
struct in_addr nmask;
u_short mtu;
} ifcfg_t;
/*
* Grabs local network interface information and stores in a ifcfg_t
* defined in network.h, returns 0 on success -1 on failure
*/
int get_local_info(int rsock, ifcfg_t *ifcfg)
{
struct ifreq ifr;

memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, ifcfg->iface, IF_NAMESIZE);
if((ioctl(rsock, SIOCGIFHWADDR, &ifr)) == -1){
perror("ioctl():");
return -1;
}
memcpy(&(ifcfg->hwa), &ifr.ifr_hwaddr.sa_data, 6);

memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, ifcfg->iface, IF_NAMESIZE);
if((ioctl(rsock, SIOCGIFADDR, &ifr)) == -1){
perror("ioctl():");
return -1;
}
memcpy(&ifcfg->ipa, &(*(struct sockaddr_in *)&ifr.ifr_addr).sin_addr, 4);

memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, ifcfg->iface, IF_NAMESIZE);
if((ioctl(rsock, SIOCGIFBRDADDR, &ifr)) == -1){
perror("ioctl():");
return -1;
}
memcpy(&ifcfg->bcast, &(*(struct sockaddr_in *)&ifr.ifr_broadaddr).sin_addr, 4);

memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, ifcfg->iface, IF_NAMESIZE);
if((ioctl(rsock, SIOCGIFNETMASK, &ifr)) == -1){
perror("ioctl():");
return -1;
}
memcpy(&ifcfg->nmask.s_addr, &(*(struct sockaddr_in *)&ifr.ifr_netmask).sin_addr, 4);

memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, ifcfg->iface, IF_NAMESIZE);
if((ioctl(rsock, SIOCGIFMTU, &ifr)) == -1){
perror("ioctl():");
return -1;
}
ifcfg->mtu = ifr.ifr_mtu;

return 0;
}

Quick edit, this function requires that the interface has been assigned before it is called, like so:

strcpy(if_cfg->iface, iface)

Ensuring you have allocated the memory first, then call like so

if((get_local_info(sock, if_cfg)) != 0){
printf("Unable to get network device info\n");
return -1;
}

Get the Default Gateway

It will probably be the first valid and enabled gateway address of the first enabled network interface:

public static IPAddress GetDefaultGateway()
{
return NetworkInterface
.GetAllNetworkInterfaces()
.Where(n => n.OperationalStatus == OperationalStatus.Up)
.Where(n => n.NetworkInterfaceType != NetworkInterfaceType.Loopback)
.SelectMany(n => n.GetIPProperties()?.GatewayAddresses)
.Select(g => g?.Address)
.Where(a => a != null)
// .Where(a => a.AddressFamily == AddressFamily.InterNetwork)
// .Where(a => Array.FindIndex(a.GetAddressBytes(), b => b != 0) >= 0)
.FirstOrDefault();
}

I've also added some further commented checks which have been pointed out as useful by other people here. You can check the AddressFamily one to distinguish between IPv4 and IPv6. The latter one can be used to filter out 0.0.0.0 addresses.

The above solution will give you a valid/connected interface, and is good enough for 99% of situations. That said, if you have multiple valid interfaces that traffic can be routed through, and you need to be 100% accurate, the way to do this uses GetBestInterface to find an interface for routing to a specific IP address. This additionally handles the case where you might have a specific address range routed through a different adapter (e.g. 10.*.*.* going through a VPN, everything else going to your router)

[DllImport("iphlpapi.dll", CharSet = CharSet.Auto)]
private static extern int GetBestInterface(UInt32 destAddr, out UInt32 bestIfIndex);

public static IPAddress GetGatewayForDestination(IPAddress destinationAddress)
{
UInt32 destaddr = BitConverter.ToUInt32(destinationAddress.GetAddressBytes(), 0);

uint interfaceIndex;
int result = GetBestInterface(destaddr, out interfaceIndex);
if (result != 0)
throw new Win32Exception(result);

foreach (var ni in NetworkInterface.GetAllNetworkInterfaces())
{
var niprops = ni.GetIPProperties();
if (niprops == null)
continue;

var gateway = niprops.GatewayAddresses?.FirstOrDefault()?.Address;
if (gateway == null)
continue;

if (ni.Supports(NetworkInterfaceComponent.IPv4))
{
var v4props = niprops.GetIPv4Properties();
if (v4props == null)
continue;

if (v4props.Index == interfaceIndex)
return gateway;
}

if (ni.Supports(NetworkInterfaceComponent.IPv6))
{
var v6props = niprops.GetIPv6Properties();
if (v6props == null)
continue;

if (v6props.Index == interfaceIndex)
return gateway;
}
}

return null;
}

These two examples could be wrapped up into a helper class and used in the appropriate cases: that you do, or do not have a destination address in mind already.

Find netMask on Android device

It's an android bug.

According to the bug report, you can either use the following workaround (copied from the report):

WifiManager wifiManager = (WifiManager) getActivity().getSystemService(Context.WIFI_SERVICE);
DhcpInfo dhcpInfo = wifiManager.getDhcpInfo();
try {
InetAddress inetAddress = InetAddress.getByAddress(extractBytes(dhcpInfo.ipAddress));
NetworkInterface networkInterface = NetworkInterface.getByInetAddress(inetAddress);
for (InterfaceAddress address : networkInterface.getInterfaceAddresses()) {
//short netPrefix = address.getNetworkPrefixLength();
Log.d(TAG, address.toString());
}
} catch (IOException e) {
Log.e(TAG, e.getMessage());
}

... or stop using this API altogether and use the LinkProperties API instead.

How to configure a static IP address, netmask, gateway programmatically on Android 3.x or 4.x

I realise that there is no API on 3.x or 4.x for those setting per SSID. Therefore, I checked out the source code and found out that the configuration of each SSID is stored in android.net.wifi.WifiConfiguration which is gotten from android.net.wifi.WifiManager.

In the below code, IpAssignment is an Enum, either STAIC, DHCP or NONE.
And linkProperties is the object store IP address, gateway, DNS, etc...

linkAddress is IP address and its netmask as prefixLength (how many bit 1 in netmask).

mRoutes is ArrayList of RouteInfo that can indicate gateway.

mDnses is ArrayList of InetAddress for DNS.

Firstly, get the current configuration using WifiConfiguration SSID

WifiConfiguration wifiConf = null;
WifiManager wifiManager = (WifiManager)getSystemService(Context.WIFI_SERVICE);
WifiInfo connectionInfo = wifiManager.getConnectionInfo();
List<WifiConfiguration> configuredNetworks = wifiManager.getConfiguredNetworks();
for (WifiConfiguration conf : configuredNetworks){
if (conf.networkId == connectionInfo.getNetworkId()){
wifiConf = conf;
break;
}
}

As the IpAssignment and linkProperties are hidden, the object can be gotten from reflection.

The following method can set the declared IP address setting on SSID WifiConfiguration:

    public static void setIpAssignment(String assign , WifiConfiguration wifiConf)
throws SecurityException, IllegalArgumentException, NoSuchFieldException, IllegalAccessException{
setEnumField(wifiConf, assign, "ipAssignment");
}

public static void setIpAddress(InetAddress addr, int prefixLength, WifiConfiguration wifiConf)
throws SecurityException, IllegalArgumentException, NoSuchFieldException, IllegalAccessException,
NoSuchMethodException, ClassNotFoundException, InstantiationException, InvocationTargetException{
Object linkProperties = getField(wifiConf, "linkProperties");
if(linkProperties == null)return;
Class laClass = Class.forName("android.net.LinkAddress");
Constructor laConstructor = laClass.getConstructor(new Class[]{InetAddress.class, int.class});
Object linkAddress = laConstructor.newInstance(addr, prefixLength);

ArrayList mLinkAddresses = (ArrayList)getDeclaredField(linkProperties, "mLinkAddresses");
mLinkAddresses.clear();
mLinkAddresses.add(linkAddress);
}

public static void setGateway(InetAddress gateway, WifiConfiguration wifiConf)
throws SecurityException, IllegalArgumentException, NoSuchFieldException, IllegalAccessException,
ClassNotFoundException, NoSuchMethodException, InstantiationException, InvocationTargetException{
Object linkProperties = getField(wifiConf, "linkProperties");
if(linkProperties == null)return;
Class routeInfoClass = Class.forName("android.net.RouteInfo");
Constructor routeInfoConstructor = routeInfoClass.getConstructor(new Class[]{InetAddress.class});
Object routeInfo = routeInfoConstructor.newInstance(gateway);

ArrayList mRoutes = (ArrayList)getDeclaredField(linkProperties, "mRoutes");
mRoutes.clear();
mRoutes.add(routeInfo);
}

public static void setDNS(InetAddress dns, WifiConfiguration wifiConf)
throws SecurityException, IllegalArgumentException, NoSuchFieldException, IllegalAccessException{
Object linkProperties = getField(wifiConf, "linkProperties");
if(linkProperties == null)return;

ArrayList<InetAddress> mDnses = (ArrayList<InetAddress>)getDeclaredField(linkProperties, "mDnses");
mDnses.clear(); //or add a new dns address , here I just want to replace DNS1
mDnses.add(dns);
}

public static Object getField(Object obj, String name)
throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException{
Field f = obj.getClass().getField(name);
Object out = f.get(obj);
return out;
}

public static Object getDeclaredField(Object obj, String name)
throws SecurityException, NoSuchFieldException,
IllegalArgumentException, IllegalAccessException {
Field f = obj.getClass().getDeclaredField(name);
f.setAccessible(true);
Object out = f.get(obj);
return out;
}

private static void setEnumField(Object obj, String value, String name)
throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException{
Field f = obj.getClass().getField(name);
f.set(obj, Enum.valueOf((Class<Enum>) f.getType(), value));
}

After that, I can set setting and update WifiConfiguration for this SSID.

    try{
setIpAssignment("STATIC", wifiConf); //or "DHCP" for dynamic setting
setIpAddress(InetAddress.getByName("192.168.0.100"), 24, wifiConf);
setGateway(InetAddress.getByName("4.4.4.4"), wifiConf);
setDNS(InetAddress.getByName("4.4.4.4"), wifiConf);
wifiManager.updateNetwork(wifiConf); //apply the setting
wifiManager.saveConfiguration(); //Save it
}catch(Exception e){
e.printStackTrace();
}

Edit:
Sorry for I don't check for Android 3.x device that have silmilar UI with Android 4.x.
In Android 3.x, the gateway is storted in mGateways of linkProperties.
mGateways is Arraylist of type InetAddress. Therefore, following should work in Android 3.x.

public static void setGateway(InetAddress gateway, WifiConfiguration wifiConf)
throws SecurityException, IllegalArgumentException, NoSuchFieldException, IllegalAccessException,
ClassNotFoundException, NoSuchMethodException, InstantiationException, InvocationTargetException{
Object linkProperties = getField(wifiConf, "linkProperties");
if(linkProperties == null)return;
ArrayList mGateways = (ArrayList)getDeclaredField(linkProperties, "mGateways");
mGateways.clear();
mGateways.add(gateway);
}

Edit2: The methods setIpAddress, setGateway, setDNS should be inputted as InetAddress type.



Related Topics



Leave a reply



Submit