相应的RPDB大致如下, 这里要说明的是21300: from all lookup main这个查找main路由表的规则是需要自己添加的, Android原生代码已经把main表的查找规则剔除了, 对于同时有对个网卡共存的情况, main表是必须的, 否则基于eth0网口的局域网就无法正常ping通.
0: from all lookup local 10000: from all fwmark 0xc0000/0xd0000 lookup legacy_system 10500: from all iif lo oif dummy0 uidrange 0-0 lookup dummy0 10500: from all iif lo oif eth0 uidrange 0-0 lookup eth0 10500: from all iif lo oif usb0 uidrange 0-0 lookup usb0 13000: from all fwmark 0x10063/0x1ffff iif lo lookup local_network 13000: from all fwmark 0x10064/0x1ffff iif lo lookup eth0 13000: from all fwmark 0x10065/0x1ffff iif lo lookup usb0 14000: from all iif lo oif dummy0 lookup dummy0 14000: from all iif lo oif eth0 lookup eth0 14000: from all iif lo oif usb0 lookup usb0 15000: from all fwmark 0x0/0x10000 lookup legacy_system 16000: from all fwmark 0x0/0x10000 lookup legacy_network 17000: from all fwmark 0x0/0x10000 lookup local_network 19000: from all fwmark 0x64/0x1ffff iif lo lookup eth0 19000: from all fwmark 0x65/0x1ffff iif lo lookup usb0 21300: from all lookup main 22000: from all fwmark 0x0/0xffff iif lo lookup usb0 32000: from all unreachable
// This structure is modified only at startup (when libc.so is loaded) and never // afterwards, so it's okay that it's read later at runtime without a lock. __LIBC_HIDDEN__ NetdClientDispatch __netdClientDispatch __attribute__((aligned(32))) = { __accept4, __connect, __socket, fallBackNetIdForResolv, };
staticvoidnetdClientInitImpl(){ void* netdClientHandle = dlopen("libnetd_client.so", RTLD_NOW); if (netdClientHandle == NULL) { // If the library is not available, it's not an error. We'll just use // default implementations of functions that it would've overridden. return; } netdClientInitFunction(netdClientHandle, "netdClientInitAccept4", &__netdClientDispatch.accept4); netdClientInitFunction(netdClientHandle, "netdClientInitConnect", &__netdClientDispatch.connect); netdClientInitFunction(netdClientHandle, "netdClientInitNetIdForResolv", &__netdClientDispatch.netIdForResolv); netdClientInitFunction(netdClientHandle, "netdClientInitSocket", &__netdClientDispatch.socket); }
// NetdClient.cpp intnetdClientConnect(int sockfd, const sockaddr* addr, socklen_t addrlen){ constbool shouldSetFwmark = (sockfd >= 0) && addr && FwmarkClient::shouldSetFwmark(addr->sa_family); if (shouldSetFwmark) { FwmarkCommand command = {FwmarkCommand::ON_CONNECT, 0, 0, 0}; if (int error = FwmarkClient().send(&command, sockfd, nullptr)) { errno = -error; return-1; } } // Latency measurement does not include time of sending commands to Fwmark Stopwatch s; constint ret = libcConnect(sockfd, addr, addrlen); // Save errno so it isn't clobbered by sending ON_CONNECT_COMPLETE constint connectErrno = errno; constunsigned latencyMs = lround(s.timeTaken()); // Send an ON_CONNECT_COMPLETE command that includes sockaddr and connect latency for reporting if (shouldSetFwmark && FwmarkClient::shouldReportConnectComplete(addr->sa_family)) { FwmarkConnectInfo connectInfo(ret == 0 ? 0 : connectErrno, latencyMs, addr); // TODO: get the netId from the socket mark once we have continuous benchmark runs FwmarkCommand command = {FwmarkCommand::ON_CONNECT_COMPLETE, /* netId (ignored) */0, /* uid (filled in by the server) */0, 0}; // Ignore return value since it's only used for logging FwmarkClient().send(&command, sockfd, &connectInfo); } errno = connectErrno; return ret; }
switch (command.cmdId) { case FwmarkCommand::ON_ACCEPT: { // Called after a socket accept(). The kernel would've marked the NetId and necessary // permissions bits, so we just add the rest of the user's permissions here. permission = static_cast<Permission>(permission | fwmark.permission); break; }
case FwmarkCommand::ON_CONNECT: { // Called before a socket connect() happens. Set an appropriate NetId into the fwmark so // that the socket routes consistently over that network. Do this even if the socket // already has a NetId, so that calling connect() multiple times still works. // // But if the explicit bit was set, the existing NetId was explicitly preferred (and not // a case of connect() being called multiple times). Don't reset the NetId in that case. .... // 这里explicitlySelected为false, 因此实际会选择默认网络的netId if (!fwmark.explicitlySelected) { if (!fwmark.protectedFromVpn) { fwmark.netId = mNetworkController->getNetworkForConnect(client->getUid()); } elseif (!mNetworkController->isVirtualNetwork(fwmark.netId)) { fwmark.netId = mNetworkController->getDefaultNetwork(); } } break; } ....
WARN_UNUSED_RESULT intRouteController::modifyPhysicalNetwork(unsigned netId, constchar* interface, Permission permission, bool add){ //if network id has register interface, other interface route add to the table with interface registered by netid .... if (int ret = modifyIncomingPacketMark(netId, interface, permission, add)) { return ret; } if (int ret = modifyExplicitNetworkRule(netId, table, permission, INVALID_UID, INVALID_UID, add)) { return ret; } if (int ret = modifyOutputInterfaceRules(interface, table, permission, INVALID_UID, INVALID_UID, add)) { return ret; }
// Only set implicit rules for networks that don't require permissions. // // This is so that if the default network ceases to be the default network and then switches // from requiring no permissions to requiring permissions, we ensure that apps only use the // network if they explicitly select it. This is consistent with destroySocketsLackingPermission ... if (permission == PERMISSION_NONE) { returnmodifyImplicitNetworkRule(netId, table, add); } return0; }
这个函数会设置一个值为默认网络netId的fwmark, 也就是我们最开始看到的那条优先级为19000的规则, 并通过类型为NETLINK_ROUTE的netlink向内核配置该规则, 内核就会根据这条规则来匹配上对应的TCP包, 因而就会出现我们最开始的那个问题:使用TCP连接会提示No Route to Host, 那为何ping不存在这个问题了?