Android 7系统网络(二)内核层—netfilter_iptables与路由策略
系列目录第一篇全景图与调用链路概览 |第二篇内核层—netfilter/iptables与路由策略| 第三篇Native层(上)—netd守护进程与CommandListener | 第四篇Native层(下)—netd Controller详解 | 第五篇Framework层(上)—ConnectivityService核心机制 | 第六篇Framework层(下)—NMS/NPMS/NSS三大服务 | 第七篇连接建立—WiFi/移动数据/以太网完整流程 | 第八篇应用API层—ConnectivityManager使用与实战调试一、为什么内核层是关键Android 的网络能力建立在 Linux 内核之上。理解下列内核机制才能弄懂 netd 和各种 Controller 到底在操作什么netfilter / iptables防火墙、NAT、数据包过滤——几乎所有网络安全和共享功能的基础路由表与策略路由多网络并存时每个网络需要独立的路由表fwmarkSocket 标记机制决定数据包走哪张路由表本章直接从内核视角拆解这些基础设施后续所有关于 netd Controller 的分析都将引用此处的概念。二、netfilter 框架2.1 五链四表netfilter 是 Linux 内核中的一个数据包过滤框架定义了五个钩子点Hook和四张表Table网络层数据包流向 入口 本机进程 出口 │ ▲ │ ▼ │ │ PREROUTING ──────────→ routing ──────────→ FORWARD ─┐ │ │ │ │ │ ▼ │ │ │ INPUT │ │ │ │ │ │ │ 本机进程接收 │ │ │ │ │ │ 本机进程发送 │ │ │ │ │ │ └────────────────── routing ◄────────────────┘ │ │ │ ▼ │ OUTPUT ──────────→ POSTROUTING │ ▼ 出口关键数据包在内核中沿着这五个钩子点依次穿行每个钩子点都可以挂载 iptables 规则链——Android 正是利用这些钩子点来实现防火墙、NAT 共享和 DNS 拦截。五个 Hook 点的含义Hook触发时机典型用途PREROUTING数据包进入网络栈后立刻触发DNAT目的地址转换、入口流量过滤INPUT数据包路由到本机后触发本机入站防火墙FORWARD数据包不是发给本机时触发路由器上的转发过滤网络共享的关键OUTPUT本机发出的数据包触发本机出站防火墙POSTROUTING数据包即将离开网络栈时触发SNAT源地址转换、MASQUERADE四张表的用途表名用途内建链filter过滤数据包允许/拒绝INPUT, FORWARD, OUTPUTnat网络地址转换PREROUTING, INPUT, OUTPUT, POSTROUTINGmangle修改数据包内容如 TTL、TOS全部五链raw设置连接跟踪豁免PREROUTING, OUTPUT2.2 Android 对 netfilter 的使用Android 大量使用 iptables 来实现各种网络功能。adb shell iptables -t nat -L -n查看一个典型设备上的规则会发现大量由 netd 自动生成的规则网络共享Tethering在 nat 表的 POSTROUTING 链中添加 MASQUERADE 规则实现类似路由器的 NAT防火墙在 filter 表的 OUTPUT 链中根据 UID 拒绝/允许出站流量uid_owner 匹配DNS 拦截将 DNS 请求UDP 53重定向到 netd 的 dnsproxyd socket三、Android 中的 iptables 命令详解3.1 nat_controller 的网络共享规则源码路径system/netd/server/TetherController.cpp当开启 WiFi 热点时netd 的 TetherController 会执行# 启用 IP 转发echo1/proc/sys/net/ipv4/ip_forward# 添加 NAT 规则MASQUERADEiptables-tnat-APOSTROUTING-ormnet_data0-jMASQUERADE# 添加 FORWARD 规则允许转发iptables-AFORWARD-iwlan0-ormnet_data0-jACCEPT iptables-AFORWARD-irmnet_data0-owlan0-mstate--stateESTABLISHED,RELATED-jACCEPT关键MASQUERADE 是一种特殊的 SNAT——自动替换源 IP 为出口接口的 IP是移动热点的核心技术。FORWARD 链的ESTABLISHED,RELATED规则确保只有已建立连接的返回流量能通过避免未授权的入站访问。3.2 firewall_controller 的 UID 过滤源码路径system/netd/server/FirewallController.cpp网络防火墙的核心是对每个 UID 的规则控制# 禁止 UID 10086 使用 WiFiiptables-AOUTPUT-owlan0-mowner --uid-owner10086-jREJECT# 禁止 UID 10086 使用移动数据iptables-AOUTPUT-ormnet_data0-mowner --uid-owner10086-jREJECT# 省电模式下禁止所有后台应用使用移动数据iptables-Abw_costly_rmnet_data0-mowner --uid-owner10086-jREJECT关键-m owner --uid-owner匹配器是 Android 内核中的扩展模块xt_owner根据发起 socket 的进程 UID 匹配数据包。这使得 Android 能以进程粒度控制网络访问而非传统 Linux 的 IP/端口粒度。-m owner --uid-owner匹配器是 Android 内核中的一个扩展模块xt_owner根据发起 socket 的进程 UID 匹配数据包。3.3 DNSPROXYLISTENER 的 DNS 重定向netd 中的 DnsProxyListener 通过 iptables 将所有的 DNS 请求重定向到 netd 的 DNS 代理端口源码路径system/netd/server/DnsProxyListener.cpp# 拦截 WiFi 上的 DNS 请求重定向到 netd 的 dnsproxyd socketiptables-tnat-AOUTPUT-pudp--dport53-jDNAT --to-destination127.0.0.1:53# 实际上 netd 在本地监听 UDP 53 端口通过 dnsproxyd socket关键DNS 拦截是 Android 网络管理的核心机制——通过将 UDP 53 端口的流量统一重定向到 netdAndroid 得以按网络接口WiFi/移动数据/VPN使用不同的上游 DNS 服务器并实现统一的 DNS 缓存。通过 DNS 拦截Android 能够统一管理 DNS 缓存根据不同网络接口使用不同的 DNS 服务器在 VPN 连接时使用 VPN 的 DNS四、路由表与策略路由4.1 传统路由表 vs Linux 策略路由传统路由表只有一个main所有数据包都用同一张表决定出口。但 Android 需要支持多网络并存所以使用了 Linux 的策略路由机制传统路由 数据包 → 查 main 路由表 → 走默认路由 → 一个网络出口 策略路由Android 数据包 → 根据 fwmark 查 rule → 转到 netId 对应的路由表 → 使用该网络的出口关键传统路由是一条路走到黑策略路由是看标记选路——fwmark 就是那个标记内核根据它决定查询哪张路由表从而让 WiFi 和移动数据的流量各走各的路。4.2 Android 的路由表组织源码路径system/netd/server/RouteController.cpp每个网络类型分配一个独立的 netId 和对应的路由表路由表 netId 网络类型 物理接口 ───────────────────────────────────────── 99 99 本地/回环 lo 100 100 WiFi wlan0 101 101 移动数据 rmnet_data0 102 102 VPN tun0 ...关键路由表编号与 netId 一一对应这个映射关系由RouteController在/data/misc/net/rt_tables文件中维护确保每个物理网络有独立的路由命名空间。每个路由表的内容大致如下以 WiFi 为例# 路由表 100 的内容iproute show table100# 直连路由本网段192.168.1.0/24 dev wlan0 proto kernel scopelinksrc192.168.1.100# 默认路由default via192.168.1.1 dev wlan0 proto static关键每张路由表至少包含两条路由——直连路由link scope负责本网段通信默认路由default负责所有其他流量。RouteController通过 netlink socket 直接向内核写入这些路由条目。4.3 fwmark 机制fwmarkFirewall Mark是 Linux 内核中为 Socket 打标记的机制。Android 利用它来选择路由表。源码路径system/netd/server/RouteController.cpp// RouteController 中的路由优先级定义constuint32_tRULE_PRIORITY_VPN_OVERRIDE_SYSTEM10000;constuint32_tRULE_PRIORITY_VPN_OVERRIDE_OIF10500;constuint32_tRULE_PRIORITY_VPN_OUTPUT_TO_LOCAL11000;constuint32_tRULE_PRIORITY_SECURE_VPN12000;constuint32_tRULE_PRIORITY_PROHIBIT_NON_VPN12500;关键优先级数值越小越优先匹配。VPN 相关规则10000-12500排在前面确保 VPN 流量优先于普通网络流量被路由PROHIBIT_NON_VPN12500则在安全 VPN 模式下主动丢弃未走 VPN 的数据包。策略路由规则通过ip rule命令配置# 查看当前策略路由规则iprule show# 典型输出# 0: from all lookup local → 本地表最高优先级# 10000: from all fwmark 0x3e8 lookup 1000 → 直连路由保护# 10500: from all fwmark 0x3e8/0xc0000 lookup 1000 → VPN 优先# 11000: from all fwmark 0x3e8/0xc0000 lookup local → VPN 到本地# 12000: from all fwmark 0x10064/0x1ffff lookup 100 → WiFi 网络netId100# 13000: from all fwmark 0x20065/0x1ffff lookup 101 → 移动数据netId101# ...关键每条策略路由规则由fwmark/掩码匹配条件决定——0x10064/0x1ffff中的0x10064提取出 netId100 和权限位0x1ffff掩码确保只匹配低 17 位从而精确区分不同网络的数据包。fwmark 的计算方式由Fwmark.h中的位域定义源码路径system/netd/include/Fwmark.hunionFwmark{uint32_tintValue;struct{unsignednetId:16;// 网络 ID低 16 位boolexplicitlySelected:1;// 是否显式选择boolprotectedFromVpn:1;// 是否受 VPN 保护Permission permission:2;// 权限位18-19 位};};关键Fwmark是一个 32 位 union——同一个intValue可以按位域拆解出 netId、选择标志、VPN 保护和权限四个字段内核的ip rule匹配时直接使用intValue与掩码做按位比较。fwmark netId | (explicitlySelected 16) | (protectedFromVpn 17) | (permission 18) 权限位 PERMISSION_NONE 0x0 // 普通应用 PERMISSION_NETWORK 0x1 // 特权网络应用 PERMISSION_SYSTEM 0x3 // 系统应用包含 NETWORK 权限关键权限位位于 fwmark 的高位18-19确保系统应用PERMISSION_SYSTEM 0x3的 fwmark 值始终大于普通应用配合策略路由的优先级匹配可以实现系统应用可绕过某些网络限制的效果。示例WiFi 的 netId100普通应用fwmark 0x00000064移动数据的 netId101系统应用fwmark 0x000C0065permission0x3 18每个 Socket 创建时可以通过setsockopt(SO_MARK)设置 fwmark或在 connect 前调用bindServiceInfo()Android 特有来绑定到特定网络。五、网络接口管理5.1 Linux 网络接口Android 设备上常见的网络接口接口名类型说明lo回环127.0.0.1wlan0WiFiIEEE 802.11 无线接口rmnet_data0移动数据蜂窝数据接口eth0以太网有线网口平板/车机常见p2p0WiFi P2PWiFi Direct 接口tun0VPNVPN 虚拟网络接口rndis0USB 共享USB RNDIS 网络共享接口5.2 接口生命周期一个网络接口从出现到就绪经历接口创建 → 接口 UP → 配置 IP → 添加路由 → 网络就绪关键接口创建和 UP 由内核驱动触发netd 被动接收 netlink 事件配置 IP 和添加路由由 Framework 主动下发命令网络就绪则由NetworkMonitor通过 ping 验证。这是一个内核通知 → 用户态配置 → 验证确认的协作流程。各阶段对应的事件和操作阶段触发netd 处理Controller接口创建内核驱动加载收到 RTM_NEWLINK 消息NetworkController接口 UP驱动启动收到链路状态变化NetworkController配置 IPDHCP / 静态配置Framework 下发命令NetworkController::setInterfaceConfig()添加路由Framework 下发写入对应路由表RouteController网络就绪路由 ping 通NetworkMonitor 验证—六、连接跟踪conntracknetfilter 的 conntrack 模块会跟踪所有活动连接。这在网络共享Tethering中至关重要——NAT 需要根据连接跟踪表来决定如何转换返回的数据包。# 查看当前连接跟踪表cat/proc/net/nf_conntrack# 典型条目# ipv4 2 tcp 6 431999 ESTABLISHED src192.168.43.5 dst142.250.80.4# sport45678 dport443 src10.0.0.1 dst192.168.43.5 sport443 dport45678关键conntrack 表中的每条记录都包含原始方向和回复方向两个四元组——内核正是利用这个双向映射在 NAT 场景下自动将返回数据包的目的地址从公网 IP 还原为内网 IP。连接跟踪也用于-m state匹配例如允许 ESTABLISHED 和 RELATED 的连接通过防火墙。七、小结本篇梳理了 Android 网络子系统在内核层的三个核心基础设施机制作用在 Android 中的关键使用场景netfilter/iptables数据包过滤与修改防火墙、NAT 共享、DNS 拦截策略路由 fwmark多网络出口选择多网络并存、VPN 路由连接跟踪连接状态维护NAT 转发、防火墙状态匹配下一篇将深入 Native 层拆解 netd 的启动流程和 CommandListener 架构——它是如何接收 Framework 层的命令并通过这些内核机制完成网络操作的。