I want to be able to discover Android devices on my network and possibly retrieve some device information about them. This is very easy with Apple devices since they run Bonjour services. However, I can't seem to find any similar service running on Android.
This must work without modifying the Android device, installing some service, or opening some port. It's meant to work with vanilla Android devices in the way that Bonjour helps you find vanilla Apple devices. Even being able to just verify that the device is running Android would be sufficient.
Chosen Answer: Although it's not the top rated answer (yet), please take a look at the response by Luis. As he mentions, you can use a DNS lookup (using your local DNS server) to discover Android devices. I have found this to have a 100% success rate, as Android forces devices to use a hostname of android-_____. This is apparently difficult to change on the phone, even if it is rooted. So I think this is a pretty accurate method. Thanks, Luis!
Example: $ nslookup 192.168.1.104 192.168.1.1 Server: 192.168.1.1 Address: 192.168.1.1#53 104.1.168.192.in-addr.arpa name = android-711c129e251f14cf.\001.
Sample Code: If you wanted to implement this in Java (e.g., to run on Android), you can't easily use getHostName() because it uses the external DNS servers. You want to use the local DNS server on your router, for example. Luis mentions below that you could modify the DNS servers of the Wifi connection, but that could possibly break other things. Instead, I've found the dnsjava
library to be extremely helpful to send targeted DNS requests. Here is some sample code using the library:
String ipAddress = "104.1.168.192"; String dnsblDomain = "in-addr.arpa"; Record[] records; Lookup lookup = new Lookup(ipAddress + "." + dnsblDomain, Type.PTR); SimpleResolver resolver = new SimpleResolver(); resolver.setAddress(InetAddress.getByName("192.168.1.1")); lookup.setResolver(resolver); records = lookup.run(); if(lookup.getResult() == Lookup.SUCCESSFUL) { for (int i = 0; i < records.length; i++) { if(records[i] instanceof PTRRecord) { PTRRecord ptr = (PTRRecord) records[i]; System.out.println("DNS Record: " + records[0].rdataToString()); } } } else { System.out.println("Failed lookup"); } } catch(Exception e) { System.out.println("Exception: " + e); }
This gives me the output:
DNS Record: android-711c129e251f14cf.\001.
Bingo.
Review devicesGo to your Google Account. On the left navigation panel, select Security . On the Your devices panel, select Manage all devices. You'll see devices where you're currently signed in to your Google Account or have been in the last few weeks.
Signs That Someone Has Remote Access to Your PhoneThe battery drains quickly even when not in use. Higher data usage than usual. Noises in the background when you're on a phone call. You receive unusual messages, emails, or notifications.
There is an very simple approach that gave me positive results in few different devices.
When a device connects to your router it receives an IP (i.e. DHCP) and registers a name in DNS. The name that is registered seems to be always in the form android_nnnnnnnn
.
Of course, you can name any computer with the same approach and trick the check, resulting in false positives ...
Also, I can't ensure that all device suppliers are following the same approach, but I've found it to work correctly in a few devices from different brands (including different SDK levels) that I've tested.
--EDITED--
How to do it
It depends on where you would be running the code to discover the Android devices. Assuming that you would be running the code in an Android device:
First discover devices responding to ping
in your network. You can use the code in my answer to this post: execComd() to run a ping command.
Get the name of responding devices using the code:
InetAddress inetAddress = InetAddress.getByName(string_with_ip_addr);
String name = inetAddress.getCanonicalHostName();
--EDIT 2--
Proof of concept
The method below is just a proof of concept for what I've wrote above.
I'm using isReachable()
method to generate the ICMP request, which is said to only work with rooted devices in many posts, which is the case for the device used for testing it. However, I didn't give root permissions for the application running this code, so I believe it couldn't set the SIUD bit, which is the reason why some claim that this method fails. I would like to do it here from the perspective of someone testing it on a non-rooted device.
To call use:
ArrayList<String> hosts = scanSubNet("192.168.1.");
It returns in hosts
, a list of names for devices responding to ping request.
private ArrayList<String> scanSubNet(String subnet){ ArrayList<String> hosts = new ArrayList<String>(); InetAddress inetAddress = null; for(int i=1; i<10; i++){ Log.d(TAG, "Trying: " + subnet + String.valueOf(i)); try { inetAddress = InetAddress.getByName(subnet + String.valueOf(i)); if(inetAddress.isReachable(1000)){ hosts.add(inetAddress.getHostName()); Log.d(TAG, inetAddress.getHostName()); } } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } return hosts; }
Regards.
Android is not going to be as easy as iOS. There is no Bonjour equivalent.
Android 4.0, Ice Cream Sandwich, introduced Wi-Fi Direct Peer to Peer networking. At first I hoped it might be able to be scanned in the the way your thinking, but it helps Android devices communicate without an access point, so they're not really "on your network". Besides, ICS runs on only a fraction of Android devices.
Rather than an active netscan approach, you're left with a passive monitoring approach. If your network is secure, sniffing the encrypted packet is possible, but inconvenient. You'll have to
If you want to see this in action, Wireshark supports WPA decryption.
Once you're able to view the Wi-Fi traffic, you will notice Android devices tend to communicate with certain Google servers and their HTTP connections have User Agent strings that can be identified. This is the basis for a workable passive solution.
Tenable Network Security offer products that seem to take this type of approach.
@Michelle Cannon mentioned Libelium's Meshlium Xtreme whose approach will not get you all the way there (not without good up to date MAC address range tables). But it could be part of reaching a lesser goal. You can:
This may be workable if your willing to detect devices that are probably Android.
@Michelle Cannon suggested DHCP fingerprinting. I wasn't sure at first but I have to thank him for suggesting what's looking like the best bet for simple passive scanning. As a cautionary tail, I'd like to explain why I was late to the party.
In a lot of ways, it's good that Android uses the Linux kernel. But it's not good if you want to discover Android devices on your network. Android's TCP/IP stack is Linux's therefor Android devices will look like Linux devices or so I thought at first. But then I realized Linux has a lot of build configuration parameters so there could be something distinctive about Android when seen on a network, but what?
DHCP fingerprinting uses a the exact DHCP options requested by the device plus timing. For this to work you generally need an up to date fingerprint database to match against. At first it looked like fingerbank was crowed sourcing this data, but then I noticed their files hadn't been updated for almost a year. With all the different Android device types, I don't think it's practical to keep updated fingerprints for a single project.
But then I looked at the actual DHCP signatures for Android and I noticed this:
Android 1.0: dhcpvendorcode=dhcpcd 4.0.0-beta9 Android 1.5-2.1: dhcpvendorcode=dhcpcd 4.0.1 Android 2.2: dhcpvendorcode=dhcpcd 4.0.15 Android 3.0: dhcpvendorcode=dhcpcd-5.2.10
Linux normally uses dhclient as their DHCP client, but Android is using dhcpcd. Android has a strong preference for using software licensed with the BSD style where possible and dhcpcd uses a BSD license. It would seem dhcpvendorcode could be used as a strong indicator that a mobile device is running Android.
A client uses DHCP to get an IP address when joining a network so it's starting without an IP address. It gets around this problem by using UDP broadcasts for the initial exchange. On Wi-Fi, even with WPA, broadcast traffic is not encrypted. So you can just listen on UDP port 67 for client to server traffic and 68 for the reverse. You don't even need to put your network interface into promiscuous mode. You can easily monitor this traffic using a protocol analyzer like Wireshark.
I preferred to write code to monitor the traffic and decided to use Python. I selected pydhcplib to handle the details of DHCP. My experience with this library was not smooth. I needed to manually download and place IN.py and TYPES.py support files. And their packet to string conversion was leaving the dhcpvendorcode blank. It did parse the DHCP packets correctly, so I just wrote my own print code.
Here's code that monitors DHCP traffic from client to server:
#!/usr/bin/python from pydhcplib.dhcp_packet import * from pydhcplib.dhcp_network import * from pydhcplib.dhcp_constants import * netopt = { 'client_listen_port':"68", 'server_listen_port':"67", 'listen_address':"0.0.0.0" } class Server(DhcpServer): def __init__(self, options): DhcpServer.__init__( self,options["listen_address"], options["client_listen_port"], options["server_listen_port"]) def PrintOptions(self, packet, options=['vendor_class', 'host_name', 'chaddr']): # uncomment next line to print full details # print packet.str() for option in options: # chaddr is not really and option, it's in the fixed header if option == 'chaddr': begin = DhcpFields[option][0] end = begin+6 opdata = packet.packet_data[begin:end] hex = ['0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'] print option+':', ':'.join([(hex[i/16]+hex[i%16]) for i in opdata]) else: opdata = packet.options_data.get(option) if opdata: print option+':', ''.join([chr(i) for i in opdata if i != 0]) print def HandleDhcpDiscover(self, packet): print "DHCP DISCOVER" self.PrintOptions(packet) def HandleDhcpRequest(self, packet): print "DHCP REQUEST" self.PrintOptions(packet) ## def HandleDhcpDecline(self, packet): ## self.PrintOptions(packet) ## def HandleDhcpRelease(self, packet): ## self.PrintOptions(packet) ## def HandleDhcpInform(self, packet): ## self.PrintOptions(packet) server = Server(netopt) while True : server.GetNextDhcpPacket()
This code is based on pydhcplib's server example because it listens for client requests, like a server.
When my Nexus 7 Android 4.2 tablet connects, this interesting information is captured (redacted):
DHCP REQUEST vendor_class: dhcpcd-5.5.6 host_name: android-5c1b97cdffffffff chaddr: 10:bf:48:ff:ff:ff DHCP DISCOVER vendor_class: dhcpcd-5.5.6 host_name: android-5c1b97cdffffffff chaddr: 10:bf:48:ff:ff:ff
The host name seems to have a fixed format and is easily parsed. If you need the IP address you can monitor the server to client traffic. Note: only the initial exchange, when an new client first shows up without an IP address, is broadcast. Future lease extensions, etc., are not broadcast.
@Luis posted a great solution that demonstrates how simpler is better. Even after seeing Android's DHCP client was setting host_name to android-5c1b97cdffffffff, I didn't think to ask the router for it's list of names using reverse DNS lookups. The router adds the host_name to it's DNS server so you can still access the device if its IP address changes.
The host_name is expected to remain listed in the DNS for the duration of the DHCP lease. You could check if the device is still present by pinging it.
One drawback to depending on host_name is there are ways this could be changed. It's easy for the device manufacturer or carrier to change the host_name (though after searching, I've been unable to find any evidence they ever have). There are apps to change host name, but they require root so that's, at most, an edge case.
Finally there's an open Android Issue 6111: Allow a hostname to be specified that currently has 629 stars. It would not be surprising to see configurable host_name in Android Settings at some point in the future, maybe soon. So if you start depending on host_name to identify Android devices, realize it could be yanked out from under you.
If you're doing live tracking, another potential problem with Reverse DNS Lookup is you have to decide how frequently to scan. (Of course this is not an issue if you're just taking a one-time snapshot.) Frequent scanning consumes network resources, infrequent leaves you with stale data. Here's how adding DHCP monitoring can help:
While it's not easy (nor 100% accurate), there are several techniques that make it possible to discover Android devices on your network.
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