什么原因造成此情况?
$ sudo ip route show
192.168.100.0/24 dev usb0 scope link
$ sudo ip addr show usb0
85: usb0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state
UNKNOWN group default qlen 1000
link/ether 16:3d:0a:3f:3b:e6 brd ff:ff:ff:ff:ff:ff
inet 192.168.100.86/24 brd 192.168.100.255 scope global usb0
valid_lft forever preferred_lft forever
inet6 fe80::143d:aff:fe3f:3be6/64 scope link
valid_lft forever preferred_lft forever
$ sudo ip route get 192.168.100.2
RTNETLINK answers: Network is unreachable
这是在我的主机设备上,在 Linux 4.4 内核上运行 Android。我插入了我的 usb 小工具(Mendel Linux 设备)。usb0 接口出现了;我将其打开并在其上运行了 udhcpc。该小工具为我分配了 192.168.100.86/24,并通过 mDNS 将自身宣传为 192.168.100.2,因此我知道链接正在工作。我关闭了所有其他主机接口,以确保它们没有窃取路由。但是,如果我尝试 ping 它或 ssh 到它,我会得到“网络无法访问”的信息。
当我在另一台非 Android 主机上执行相同步骤时,它运行良好。我知道 Android 有一些奇怪的 iptables 规则(例如用于每个 uid 的数据使用情况跟踪),但我不认为这会影响路由表(并且刷新它们似乎没有帮助)。还有 SElinux,但我认为这只是文件系统的问题。还有什么其他晦涩难懂的(对我来说)Linux 功能可能会在这里阻碍我?
根据要求编辑以添加:
$ ip rule
0: from all lookup local
999: from all fwmark 0xa/0xffff lookup 2454
10000: from all fwmark 0xc0000/0xd0000 lookup 99
10500: from all iif lo oif ccmni1 uidrange 0-0 lookup 1003
13000: from all fwmark 0x10063/0x1ffff iif lo lookup 97
13000: from all fwmark 0xd006c/0xdffff iif lo lookup 1003
14000: from all fwmark 0xc0000/0xc0000 iif lo oif ccmni1 lookup 1003
15000: from all fwmark 0x0/0x10000 lookup 99
16000: from all fwmark 0x0/0x10000 lookup 98
17000: from all fwmark 0x0/0x10000 lookup 97
32000: from all unreachable
$ ip route show table local
broadcast 127.0.0.0 dev lo proto kernel scope link src 127.0.0.1
local 127.0.0.0/8 dev lo proto kernel scope host src 127.0.0.1
local 127.0.0.1 dev lo proto kernel scope host src 127.0.0.1
broadcast 127.255.255.255 dev lo proto kernel scope link src 127.0.0.1
broadcast 192.168.100.0 dev usb0 proto kernel scope link src 192.168.100.86
local 192.168.100.86 dev usb0 proto kernel scope host src 192.168.100.86
broadcast 192.168.100.255 dev usb0 proto kernel scope link src 192.168.100.86
$ ip route show table 2454
default dev ccmni1 proto static
$ ip route show table 99
$ ip route show table 1003
$ ip route show table 97
$ ip route show table 99
$ ip route show table 98
$
答案1
Android 使用大量的路由规则和表,可能每个应用程序一个。
从中可以看出,如果没有添加这样的规则及其对应的 fwmark,数据包将命中路由规则 32000:无法到达。
通过这种机制手动执行某些操作有点不可靠。特别是路由规则 10500 允许(仅)根使用传出接口ccmni1
,但oif
不是允许将数据包选择到此接口,而是允许来自套接字的数据包绑定到该接口(使用SO_BINDTODEVICE
)进行选择(oif
不是iif
用于路由数据包的直接等价物,也是iif lo
非路由数据包的特殊情况)。
许多规则收到防火墙标记可能由等效复杂设置iptables规则用于为每个应用程序(及其特定 UID)选择特定的路由规则。我猜想在安装应用程序时会有特定的 Android API 来注册此类规则。
如果你想允许 root 首先使用主路由表,从而避免无法到达命运,在多个可能的选择中:
ip rule add pref 998 uidrange 0-0 lookup main
或者如果你不关心任何用户,那么任何应用程序都可以使用usb0简单地:
ip rule add pref 998 lookup main
这可能无法与 Android 系统很好地集成,因为 Android 系统可能会在应用程序安装或启动时改变规则,而且人们无法知道剩下的是什么iptables/nftables(或者甚至沿着 SELinux, 碳等等)关于阻止访问。即使绑定到套接字也可能受到其他机制的限制(例如:CONFIG_ANDROID_PARANOID_NETWORK
)。