Is it possible to set the IP address of an interface in Android within an application?
I can query the available interfaces and their current addresses using java.net.NetworkInterface, but this doesn't provide a facility to change these. Did I just miss something somewhere, or is it not allowed?
I was hoping to be able to make my application either change or add an alias to one or more of the existing interfaces at runtime on an "off the shelf" device. (2.1/2.2). Ideally I'd like to do this for both IPv4 and IPv6 addresses.
Settings.System includes several flags you can use for this:
WIFI_USE_STATIC_IP
WIFI_STATIC_IP
WIFI_STATIC_NETMASK
WIFI_STATIC_GATEWAY
WIFI_STATIC_DNS1 and WIFI_STATIC_DNS2
You'll also need the android.permission.WRITE_SETTINGS permission declared for your application.
Then in your activity:
final ContentResolver cr = getContentResolver();
Settings.System.putInt(cr, Settings.System.WIFI_USE_STATIC_IP, 1);
Settings.System.putString(cr, Settings.System.WIFI_STATIC_IP, "you.re.ip.addr");
// call putString() for each value to set for your interface
If you want to change the IP address of the carrier's 3G/4G,etc interface, I do not believe this is possible - as it is connected to the carrier and uses their DHCP/security for enabling you to connect and use their services (sort of like changing the external IP of your cable modem without the consent of your ISP).
Related
as far as I understood Android uses the NetworkScore class to select between available networks. Every available network is assigned with various flags and the Connectivity module in AOSP uses the policy logic for network selection found in the NetworkRanker class to determine from those flags, which network to choose.
I also got that it is not possible to directly select the network operator from API (for security reasons).
Would it be possible to change those flags programmatically (after set by NetworkScore) to "force" a certain network to be selected by the system?
Would it be possible to change the policy logic in the NetworkRanker class to block Network operators of a certain country?
I'm working on android 9 and I want to give preference to WiFi over Ethernet.
I tried giving wifi higher priority than ethernet in my config.xml file as shown below but still my ethernet has higher priorty.
<string-array translatable="false" name="networkAttributes">
<item>"wifi,1,1,2,6000,true"</item>
<item>"ethernet,9,9,0,6000,true"</item>
</string-array>
I searched online and I found that default network preference can be given in ConnectivityManager.java. But it shows deprecated in API28.
#Deprecated
public static final int DEFAULT_NETWORK_PREFERENCE = TYPE_WIFI;
Also, getNetworkInfo and startUsingNetworkFeature is deprecated as well.
#Deprecated
#RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
public NetworkInfo getNetworkInfo(int networkType) {
#Deprecated
public int startUsingNetworkFeature(int networkType, String feature) {
How do i give WIFI higher priority than ethernet on android 9?
You have two options on how you can handle this.
Option 1: Update AOSP source code
In Android 9, ConnectivityService will use a static network score to determine which priority to use various network transport types (ethernet vs Wi-Fi vs cellular, etc).
Ethernet has a network score of 70 (link) while Wi-Fi has a network score of 60 (link).
In your case, if I wanted to prioritize Wi-Fi over Ethernet, you can change the score to reflect the new priority (e.g. change Wi-Fi to 71 in the Wi-Fi link above or similarly, lower ethernet's score to say 59 in its factory).
Example with Wi-Fi:
private static final int SCORE_FILTER = 71;
Option 2: Use Resource Overlay
There is a resource overlay that can be used to manually configure the network capabilities on Ethernet networks named config_ethernet_interfaces (link).
<!-- Configuration of Ethernet interfaces in the following format:
<interface name|mac address>;[Network Capabilities];[IP config];[Override Transport]
Where
[Network Capabilities] Optional. A comma seprated list of network capabilities.
Values must be from NetworkCapabilities#NET_CAPABILITY_* constants.
The NOT_ROAMING, NOT_CONGESTED and NOT_SUSPENDED capabilities are always
added automatically because this configuration provides no way to update
them dynamically.
[IP config] Optional. If empty or not specified - DHCP will be used, otherwise
use the following format to specify static IP configuration:
ip=<ip-address/mask> gateway=<ip-address> dns=<comma-sep-ip-addresses>
domains=<comma-sep-domains>
[Override Transport] Optional. An override network transport type to allow
the propagation of an interface type on the other end of a local Ethernet
interface. Value must be from NetworkCapabilities#TRANSPORT_* constants. If
left out, this will default to TRANSPORT_ETHERNET.
-->
<string-array translatable="false" name="config_ethernet_interfaces">
<!--
<item>eth1;12,13,14,15;ip=192.168.0.10/24 gateway=192.168.0.1 dns=4.4.4.4,8.8.8.8</item>
<item>eth2;;ip=192.168.0.11/24</item>
<item>eth3;12,13,14,15;ip=192.168.0.12/24;1</item>
-->
</string-array>
This is indexed on ethernet interface name so you'll need to have the same ethernet name in all cases, e.g. eth0 for most people. You could update the above config to play around with the capabilities. In your case, you could just omit the NOT_RESTRICTED capability (link) in which case Ethernet would never be used as the default network only leaving Wi-Fi to be prioritized higher.
<!-- Restricting eth0 -->
<string-array translatable="false" name="config_ethernet_interfaces">
<item>eth0;11,12,14;;</item>
</string-array>
In fact, the Android Cuttlefish target (link) does this today for similar reasons. Note, the above config would mark eth0 as restricted so it probably wouldn't get an IP or be used at all (except by potentially apps with restricted network access). You can always play around with these capabilities if you want a different behavior.
I ran into an issue where my Android app cannot make outgoing connections using the TcpClient class (question located here). While debugging and conducting further research, I found that my Android device (API level 22) is receiving a subnet mask of 0.0.0.0 when it connects to my WiFi network. My DHCP server is configured to use 255.255.255.0, so I believe this discrepancy could be the root of my other problem. This is my code:
//Connect to the WiFi network
int id = WiFiManager.AddNetwork(new WifiConfiguration()
{
Ssid = $"\"{ssid}\"",
PreSharedKey = $"\"{password}\""
});
WiFiManager.EnableNetwork(id, true);
WiFiManager.Reconnect();
//Retrieve subnet mask (for debugging)
int subnet_mask = WiFiManager.DhcpInfo.Netmask;
subnet_mask returns 0, and the formatted version of the DhcpInfo class shows:
{ipaddr 10.0.0.15 gateway 10.0.0.0 netmask 0.0.0.0 dns1 10.0.0.0 dns2 0.0.0.0 DHCP server
10.0.0.0 lease 43200 seconds}
With this being the situation, is there any way I can manually change the subnet mask (or "netmask") within the Android API? I have tried using a static IP configuration as shown here, but use of those settings was deprecated in API level 17. I have also tried setting the DhcpInfo.Netmask property manually, but it takes an int. I calculated one based on this answer, but it was too large and became a uint. Lastly, I looked through a variety of classes, including Android.Net.Wifi.WifiManager, to see if there was a way to change the netmask. I didn't find anything, but I might have just been looking in the wrong places.
Any help is greatly appreciated!
Update:
For security reasons, it seems like this is not possible with the standard Android API. However, is the Android NDK able to change the subnet mask? I understand it provides lower-level access to the device, and I do not need to put this app on the app store (it is for my use only).
For security reasons, Android OS may not allow you to do this.
I know as a user I would not want an app to change my network configuration.
It seems this may have been able to be done in the past: https://stackoverflow.com/a/7142316/2913599
but that API is obsolete/deprecated in API level 17: https://developer.android.com/reference/android/provider/Settings.System.html#WIFI_STATIC_DNS1
Docs say to use WifiManager instead, but that API does not allow changing the ip, dns, gateway, again for security reasons.
If you need to get these settings changed, perhaps you can provide an instruction page for the user so they can change them themselves.
Is it possible to set the IP address of an interface in Android within an application?
I can query the available interfaces and their current addresses using java.net.NetworkInterface, but this doesn't provide a facility to change these. Did I just miss something somewhere, or is it not allowed?
I was hoping to be able to make my application either change or add an alias to one or more of the existing interfaces at runtime on an "off the shelf" device. (2.1/2.2). Ideally I'd like to do this for both IPv4 and IPv6 addresses.
Settings.System includes several flags you can use for this:
WIFI_USE_STATIC_IP
WIFI_STATIC_IP
WIFI_STATIC_NETMASK
WIFI_STATIC_GATEWAY
WIFI_STATIC_DNS1 and WIFI_STATIC_DNS2
You'll also need the android.permission.WRITE_SETTINGS permission declared for your application.
Then in your activity:
final ContentResolver cr = getContentResolver();
Settings.System.putInt(cr, Settings.System.WIFI_USE_STATIC_IP, 1);
Settings.System.putString(cr, Settings.System.WIFI_STATIC_IP, "you.re.ip.addr");
// call putString() for each value to set for your interface
If you want to change the IP address of the carrier's 3G/4G,etc interface, I do not believe this is possible - as it is connected to the carrier and uses their DHCP/security for enabling you to connect and use their services (sort of like changing the external IP of your cable modem without the consent of your ISP).
How do I get the MAC-Address of the network interface of an android device which doesn't have a Wifi-Interface (e.g. the android emulator)? WifiInfo obtained via the WifiManager returns null.
EDIT
To be more clear: I have to communicate with an existing network protocol (not designed by me) on the local network where I have to send the mac address of the communicating interface within the payload during a registration phase.
I'm going to take a leap and assume that you want this MAC address in order to establish a unique identifier for the device. Mac Addresses are not the way to do this.
There's an Android Developer Blog post titled "Identifying App Installations" which covers the topic of generating unique ID's fairly well, including the popular methods, and the pros/cons. It's definitely worth a read. Quite relevant to this post is the following quote:
It may be possible to retrieve a Mac address from a device’s WiFi or Bluetooth hardware. We do not recommend using this as a unique identifier. To start with, not all devices have WiFi. Also, if the WiFi is not turned on, the hardware may not report the Mac address.
The options available to you instead include TelephonyManager.getDeviceId(), android.os.Build.SERIAL, and Settings.Secure.ANDROID_ID, all of which are covered in more detail in the linked post.
Read /sys/class/net/[something]/address as a text file
But it's unlikely to be useful in the way you think.
See this post where I have submitted Utils.java example to provide pure-java implementations.
Utils.getMACAddress("wlan0");
Utils.getMACAddress("eth0");
Utils.getIPAddress(true); // IPv4
Utils.getIPAddress(false); // IPv6
What is the network interface you want the MAC address of? If there's no wifi, you certainly can't get the wifi device's MAC address. It represents the physical hardware and if that's not present, it simply doesn't exist.
To get wifi MAC of android device using adb:
adb shell getprop ril.wifi_macaddr
Use the following code in Java to get it programmatically:
Process p = Runtime.getRuntime.exec("adb", "shell", "getprop", "ril.wifi_macaddr")
BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream());
String macAddress = br.readLine();