aaronjwood/PortAuthority

ip neighbor command throws exception on android 11

5hahryar opened this issue · 14 comments

Hello, I encountered a strange issue. I tried running the app on android 11 it worked fine, then I updated the compile and target SDK versions from 29 to 30 and then after a rebuild I restarted the app. After this change a few exceptions happened, but the main one that I'm concerned with is about running "ip neighbor" command to access the MAC address.
Running this command exits with this error: "Cannot bind netlink socket permission denied"
Now I'm wondering if this is related to the new restrictions on android or it can be fixed in some way?
Side question: Getting the MAC address of devices on network, is it not possible anymore on android? If that is the case, then how fing is doing it?

Sounds like the same issue as #129

To your question, they have tightened things a lot in the newer versions of Android. Here is just one example https://issuetracker.google.com/issues/130103885?pli=1

That is true, but like i mentioned Fing is doing fine and they recently published a new version that supports android 11, 12. So do you have any idea on how they are implementing this? like using NDK or something?

@5hahryar I just verified this, and Fing is effectively using the NDK to implement their "Native ARP" (if you decompile their APK you'll see it implemented in libengine.so).

I don't know what would be simplest method to achieve API 30 compatibility : maybe using the NDK to build a modified ip binary only implementing the neighbor parameter, so the change to the rest of the code stays as minimal as possible?

@BayLee4 I tried running a sample code on a raspberry pi 4. It compiled and worked successfully but I had to use sudo.
I tried running the same code on an android device (SDK 31) inside an app called "Cxxdroid". It compiled but failed with this error: socket() failed : Permission denied.
I'm not sure if that's because I'm using a third party app to execute the code, or it's a restriction from android on raw sockets or something?
The code it self seems to be ok since it ran fine on raspbianOS.

@5hahryar Yes, we need a code that can run without root permission (so without having to run as sudo on Linux).
This is why I was suggesting using a modified ip, in fact we would only need to port the print_neigh function

@BayLee4 I have no experience in C, is there any documentation that can help?

@5hahryar None that I can think of unfortunately, but I just finished to make a stripped down version of the ip command only keeping the neigh part, could you please test it on your Raspberry Pi? I tested it on a x86_64 virtual machine, so I do not know if it works well on arm64.

Here is the repo, once cloned and in the directory just do make and see if there are errors (there should have only one warning). If there is no error, please run ./ip and compare the output with the ip neigh command, the two outputs should be the same.

(If either make or ip neigh isn't recognized, you can install them by running : sudo apt-get install iproute2 build-essential)

@BayLee4 Thank you, I executed your code and it looks like it is working perfectly.
Here is the output:
pi@raspberrypi:~/Desktop/ip/ip_neigh-main $ ./ip 192.168.1.1 dev eth0 lladdr e4:**:**:**:**:9c STALE 192.168.1.163 dev eth0 lladdr a4:**:**:**:**:07 REACHABLE

pi@raspberrypi:~/Desktop/ip/ip_neigh-main $ ip neigh 192.168.1.1 dev eth0 lladdr e4:**:**:**:**:9c REACHABLE 192.168.1.163 dev eth0 lladdr a4:**:**:**:**:07 DELAY

@5hahryar Nice! Hopefully it will also work on Android with additional work, I never used the NDK though, did you?

For the record the following code needs an alternative :

	if (bind(rth->fd, (struct sockaddr *)&rth->local,
		 sizeof(rth->local)) < 0) {
		perror("Cannot bind netlink socket");
		return -1;
	}
	addr_len = sizeof(rth->local);

As this is what isn't working currently (API 30 not allowing to bind on NETLINK_ROUTE sockets).
See : arvidn/libtorrent#6251

@BayLee4 I also haven't used NDK but I'll try it on an empty project to figure it out.

@5hahryar Ok, I pushed a fix today in the ip_neigh repo for working around the API 30 limitation, so hopefully it will work as is once built with the NDK.

@BayLee4 I created a repository and added all your C files. It fails to build the project with this error: undefined reference to 'rtnl_dump_filter_nc'
If you have any ideas please open an issue on my repo. we can come back here when we have a working solution.

@5hahryar Sure, better not to flood this issue anymore. I'll open an issue in your repository.

Regarding the undefined reference issue, this is because you only added the ipneigh.c source file (where all .c files should be added) in your CMakeLists.txt. But this is not the only issue, you're mixing C and C++ files, and native-lib.cpp doesn't call anything related to ip_neigh.

Furthermore I believe it would be simpler to compile ip_neigh as an executable, then call it directly and parsing what's written into stdout (not to change anything in the current code). Plus, dealing with string buffers is a bit painful in C, so I really recommend going this way even if it may not be the most elegant method.