Network Management in Android: Routing
I plan on diving deep into Android in future blog posts but for now I thought I might share something that was really confusing to me in hope to prevent the confusion to others. The confusion was not actually Android exclusive, I just stumpled upon it while working with Android and it was a great reminder that routing is a lot more complicated than I usually think of it.
Anyway, if you have an Android machine (in my case a container), you can run
ip-route(8)
and see that there is probably only one route and it’s not the
default gateway. This is because, at least in my Android container, Android
doesn’t use the main table for routing configuration. Linux routing actually
have multiple routing tables which the kernel looks at for each packet. We can
see the rules that decide which table to look at through ip-rule(8)
. The rule
list in my Android container looks like so:
0: from all lookup local
10000: from all fwmark 0xc0000/0xd0000 lookup legacy_system
11000: from all iif lo oif eth0 uidrange 0-0 lookup eth0
16000: from all fwmark 0x10063/0x1ffff iif lo lookup local_network
16000: from all fwmark 0x10064/0x1ffff iif lo lookup eth0
17000: from all iif lo oif eth0 lookup eth0
18000: from all fwmark 0x0/0x10000 lookup legacy_system
19000: from all fwmark 0x0/0x10000 lookup legacy_network
20000: from all fwmark 0x0/0x10000 lookup local_network
23000: from all fwmark 0x64/0x1ffff iif lo lookup eth0
31000: from all fwmark 0x0/0xffff iif lo lookup eth0
32000: from all unreachable
This is x4 more rules than what I have on my Fedora Silverblue machine:
0: from all lookup local
32766: from all lookup main
32767: from all lookup default
I actually don’t know why the big difference but the important difference is
that Android doesn’t even look at the main table as part of its rules. When you
want to look at the routing rules you probably want to look at all of them
together. Luckily the ip
command accept all
as a pseudo table that prints
the routing rules from all tables. For example, in my container I get this:
c340878bf6f5:/ # ip route show table all
172.17.0.0/16 dev eth0 table eth0_local proto static scope link
224.0.0.0/24 dev eth0 table eth0_local proto static scope link
default via 172.17.0.1 dev eth0 table eth0 proto static
172.17.0.0/16 dev eth0 table eth0 proto static scope link
172.17.0.0/16 dev eth0 proto kernel scope link src 172.17.0.2
local 127.0.0.0/8 dev lo table local proto kernel scope host src 127.0.0.1
local 127.0.0.1 dev lo table local proto kernel scope host src 127.0.0.1
broadcast 127.255.255.255 dev lo table local proto kernel scope link src 127.0.0.1
local 172.17.0.2 dev eth0 table local proto kernel scope host src 172.17.0.2
broadcast 172.17.255.255 dev eth0 table local proto kernel scope link src 172.17.0.2
fe80::/64 dev eth0 table eth0_local proto static metric 1024 pref medium
fe80::/64 dev eth0 table eth0 proto static metric 1024 pref medium
fe80::/64 dev eth0 proto kernel metric 256 pref medium
local fe80::3fcd:8604:cea7:9ecd dev eth0 table local proto kernel metric 0 pref medium
multicast ff00::/8 dev eth0 table local proto kernel metric 256 pref medium
I can also use this output to extract all the tables which have routing rules,
unlike ip-rule(8)
output which shows several empty routing tables. The command
I came up with which is probably not the shortest is this:
c340878bf6f5:/ # ip route show table all | grep -o "table [a-zA-Z_0-9]*" | cut -d' ' -f2 | sort | uniq
eth0
eth0_local
local
That’s it, I didn’t realise how I can ping something without having a default gateway and this was the answer.