Determining Android VPN Interface/IP? - java

I'm trying to determine the name of a PPTP VPN interface in android so I can list it as a bind-able interface in my application. Since there is no VPN API to do that in Android -- I figured I could use straight Java to find it.
When I do your standard Java to get the list of interfaces, ie.
ArrayList<NetworkInterface> allInterfaces = Collections.list(NetworkInterface.getNetworkInterfaces());
I see a few interesting things:
When phone is on 802.11X Wifi
tiwlan0 (the wifi interface)
ppp0 (the VPN)
When the phone is on Verizon Only
ppp0 (the VPN, usually)
ppp1 (the VZ network, usually)
So - I need a way to eliminate the VZ interface. You can get NetworkInfo objects from the Android API like this:
ConnectivityManager conMan = (ConnectivityManager)this.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo[] infoList = conMan.getAllNetworkInfo();
There are a few problems with that method:
The VPN doesn't show up
The names/fields in the network info objects don't correspond to anything in the Java NetworkInterface object
The way I see it there's a few ways to eliminate the VZ interface from the all interfaces list:
Do it by name (ie. if Android gave me a list that had "ppp1" in it I could eliminate ppp1, since the Android list does not ever contain the VPN)
Do it by IP (ie. if I could figure out the VZ IP address, I could eliminate the interface with that IP using Java's NetworkInterface object.)
Unfortunately, it doesn't look like either of those options are possible since the names don't match up and I can't figure out how to get the VZ IP from the Android OS.
So -- has anyone else tried something similar? Is there some way to ask the android OS what interfaces have IP addresses?
Thanks in advance -- all help is appreciated.
Dan
PS. I'm trying to avoid forcing the user to input a valid IP range (or specific IP) to bind to.

EDIT: One possible option here is to do a JNI system calll with the android native kit. Read the directory listing of /dev/ and grep for ppp*. Assume the earliest one is the 3G/4g connection and the latter one is the VPN.

Found out this is not possible using the current API (10). Bug Report/Feature Request:
http://code.google.com/p/android/issues/detail?id=15082

Related

How do I get client's ip address with cidr

I tried getting Public IP address from HttpServletRequest object using
httpServletRequest.getRemoteAddress();
which returns simple public ip address e.g. 123.21.21.12 but what I need is 132.21.21.12/8.
I have checked this How to get client's IP address using javascript only? but all of these provide simple ip addresses not with CIDR bits.
Thank you.
As others stated in the comments to your question, there is no way to extract subnet mask information just from the IP address alone, and there is no reliable way to get this information from the server. Firstly, you are communicating with a single IP address and not the whole subnet, so the correct CIDR is, as others said, /32. Secondly, network mask is network layer information and the way IP routing works doesn't require any other information to be provided other than a destination IP address.
It is important to know what exactly are trying to accomplish and are using this information for. Do you need this just to fulfill some format requirements or you really need the subnet mask. Anyway, if we're talking about ordinary web client/server I could see two different scenarios:
1) You need exact information about client network configuration
Even if you would be able to programmatically obtain such data, I'm not sure how useful it would be. Because of the shortage of IPv4 addresses and the way ISPs allocate addresses to customers most of the clients are behind their home router which does NAT or in some cases behind carrier grade NAT. Having bunch of clients that all have the same 192.168.1.2/24 address would be a bit pointless.
2) You need the public information (used for global routing) to group customers or something related to that.
This means getting the public IP address (the one you get with httpServletRequest.getRemoteAddress();). There's no way to obtain the exact subnet with 100% accuracy but you can get the route object from a RIR (Regional Internet Registry) database that delegated the scope that IP belongs to. LIRs (organizations that got the address block) have the obligation to update this database with various information and one of those is creating these route objects. For that you can use Whois protocol which is really simple and easily implemented. Basically you just need to open TCP connection to a port 43, send a command that contain the IP address you need the info on and parse the output.
For your example (123.21.21.12) the route object would look like:
~ # whois -T route 123.21.21.12
% [whois.apnic.net]
% Whois data copyright terms http://www.apnic.net/db/dbcopyright.html
% Information related to '123.21.16.0/20AS45899'
route: 123.21.16.0/20
descr: VietNam Post and Telecom Corporation (VNPT)
descr: VNPT-AS-AP
country: VN
origin: AS45899
remarks: mailto: noc#vnn.vn
notify: hm-changed#vnnic.net.vn
mnt-by: MAINT-VN-VNPT
changed: hm-changed#vnnic.net.vn 20100810
source: APNIC
% This query was served by the APNIC Whois Service version 1.69.1-APNICv1r0 (UNDEFINED)
We can see that that IP address belongs to a AS45899 (VNPT) and that the route object is 123.21.16.0/20, which gives you the CIDR you wanted.
And if we query that IP address from a router that has a full BGP table:
# show bgp ipv4 unicast 123.21.21.12
BGP routing table entry for 123.21.16.0/20, version 71369881
Paths: (3 available, best #1, table default)
we do see that indeed the Whois database is updated and that IP belongs to 123.21.16.0/20 route.
Keep in mind that this /20 could be aggregated route, but that's the best you can get. That's the routing information that's globally available and used by routers around the world to route traffic. How that /20 prefix is used inside the ISP network is up to their internal organization and policies and you can't check that. You also shouldn't get routes smaller than /24 this way.

Java Sockets and multiple outgoing interfaces on Linux

There are quite a couple of related questions (e.g. Java Socket specify a certain network interface for outgoing connections ) however I couldn't find a satisfying i.e. practical solution to my problem:
On my target (Linux) platform there are multiple network interfaces (eth0...ethN) from which a Server S is reachable. The default route is normally via eth0, however I'm trying to connect S via e.g. eth4 using
new java.net.Socket(IP_of_S, targetport, IP_of_eth4, srcport)
or
sock.bind( eth4_SocketAddress );
sock.connect( S_SocketAddress );
In this example case the IP of eth4 is assigned correctly but traffic is still going out trough the interface of the default route. I've learned this is due to the the "weak end system model" RFC 1122. However I'm wondering whether there's still a Java-based solution to achieving my original goal or whether I have to trigger external iptables or route calls from my program.
(BTW: The outgoing interface needs to be chosen dynamically at runtime, i.e. my program closes the connection and tries to reconnect using a different outbound interface quite frequently.)
As far as I know, you cannot choose the outgoing interface without some routing table setup.
In my opinion, the best solution is to set up a bunch of source-specific routes, routes that match on the source address of a packet, and bind to a given source address in order to select the route (as you already do). There are two ways of achieving that:
use ip rule and multiple routing tables — this is described in http://lartc.org/howto/lartc.rpdb.html ;
use ip route add ... from .... As far as I know, this only works for IPv6, but avoids the complexity of multiple routing tables.
You'll find some background about source-specific routing in https://arxiv.org/pdf/1403.0445v4.pdf (disclaimer, I'm a co-author).

32 - How to overcome the Wi-Fi Direct 32 limit on credentials in Android?

See->
https://android.googlesource.com/platform/frameworks/base/+/b267554/wifi/java/android/net/wifi/p2p/WifiP2pGroupList.java#34
private static final int CREDENTIAL_MAX_NUM = 32;
Which is essentially limiting the number of devices I can have connected in a single Wi-Fi Direct 'cloud' per se.
This Question spawns from the answer and comments at https://stackoverflow.com/a/26242221/1815624
This Question is not a question of "How to" connect multiple device such as found at WiFi Direct for multiple devices
CREDENTIAL_MAX_NUM is a limit on the number of WifiP2pGroup objects that the the WififP2pGroupList will store. It is not a limit on the number of devices that can be a member a single Wi-Fi Direct group - this is theoretically bounded by the IP address range of the group. It is a bound on the number of persistent groups that can be stored in and utilised by the device.
WifiP2pGroupList is instantiated by the Wi-Fi P2P service and is populated by the wpa_supplicant, so changing the value of CREDENTIAL_MAX_NUM by reflection is not a solution, as the bound may be inherited from the supplicant and the P2P service resides in the system server process.
The list object can be acquired by reflection (to do this requires the use of a dynamic proxy class to implement the hidden method WifiP2pManager.PersistentGroupInfoListener and then passing this to the system service via IPC), but it's use is limited - for all groups it will not contain credentials, so caching for future use is not possible. Modification of the list will be restricted to whatever is provided by methods that are exposed by the WifiP2pManager.
So to summarise, modification of the CREDENTIAL_MAX_NUM is not possible and even if it was, an upper bound may exist in the wpa_supplicant.

How Java WebStart application Obtain the MAC address for accessing my webpage

I am writing a java webstart application to deploy from website so users can click and run my software. I need to have a kind of unique machine identification to avoid abusing the accessing of the files. I would like to use the client's MAC address as a unique key so that the server can ensure that no client downloads too much.
Of course, a user may have multiple network cards, so how can my Java application determine the MAC address of the network card that the user is using to access my web site?
..machine identification..
Why not instead do a kind of 'session identification'? As each app. loads (you might want to implement the SingleInstanceService to enforce one app. per PC.) have it contact the server to establish an unique session. Use that to identify it for each request.
To thwart the user from 'using up' their allowance and stopping/restarting the app. (within a time limit), store some details using the PersistenceService.
You can use java.net.NetworkInterface.getNetworkInterfaces to obtain the network interfaces, and call getHardwareAddress() on them to get the MAC address.
You may want to filter out loopback with if.isLoopBack() (where "if" is the interface object). Also filter out any interface where if.getHardwareAddress() returns null. Then pick out one. You could sort them by name, if.getName(), and take the first one. For your purposes it doesn't really matter if it is the actual interface used to download your files or not, just that you can identify the computer somehow. Finally if.getHardwareAddress() gives you an array of bytes with the MAC address. If you'd rather have a String, format each byte with "%02x".format(byte) and join them with a ":" as separator.
As suggested in another answer it may be better to use PersistenceService.
Using the MAC address can however be useful if you want to persist different data for the same user on different computers in the case where the user has the same files/homedirs on each computer. You can use the MAC address as part of the URL you pass to PersistenceService#create() and get(). Useful if you want per-computer data rather than per-user data.
Short example Scala-code:
def computerID: String = {
try { // mac address of first network interface
return java.net.NetworkInterface.getNetworkInterfaces
.filter(!_.isLoopback)
.filter(_.getHardwareAddress != null)
.toList.sortBy(_.getName).head
.getHardwareAddress.map("%02x".format(_)).mkString(":")
} catch {
case _ => return "0" // no mac address available? use default "0"
}
}

Network Interface - VB.Net/Java

I have this snippet in Java:
final InetAddress address = InetAddress.getLocalHost();
final NetworkInterface ni = NetworkInterface.getByInetAddress(address);
key = new String(ni.getHardwareAddress());
"key", on my PC returns:
▲╔UiÎ
What would be the equivalent to get the same output in VB.Net? I have tried getting 'MAC Address' and 'Physical Address' but they do not compare to the output in Java at all?
I can't help you with the VB, but maybe I can clear a few things up.
In my experience, InetAddress.getLocalHost() is useless. It gives different results depending on the OS, on the Java version, on the brand of router you're connecting to, on the phase of the moon, etc. Stay away from it. If you want the loopback IP address, just hard-code it: 127.0.0.1. If you want the addresses of the network interfaces on your machine, call NetworkInterface.getInterfaces() and iterate through them.
The MAC address is the unique ID of an ethernet interface. Normally, you don't have to worry about it at all, unless you're doing something weird with the network hardware. It's got nothing to do with IP addresses.
Lastly: if you're looking to determine the IP address that others can use to connect to you, just be aware that it's not so simple. A computer may have multiple network interfaces - how do you know which one to pick? And if you're behind a router (as most machines are these days) then the computer is assigned a "local" address, which is completely useless to anyone outside the local network.

Categories

Resources