一、整体架构
1.1 系统层次结构
┌─────────────────────────────────────────┐
│ Application Layer (Java/Kotlin) │
│ - ConnectivityService │
│ - NetworkPolicyManagerService │
└─────────────────┬───────────────────────┘
│ Binder/AIDL
┌─────────────────▼───────────────────────┐
│ Framework Layer (Java) │
│ - INetd Interface │
└─────────────────┬───────────────────────┘
│ Binder
┌─────────────────▼───────────────────────┐
│ netd Daemon (C++) │
│ ┌───────────────────────────────────┐ │
│ │ Controllers │ │
│ │ - BandwidthController │ │
│ │ - FirewallController │ │
│ │ - TetherController │ │
│ │ - IdletimerController │ │
│ │ - WakeupController │ │
│ │ - RouteController │ │
│ │ - StrictController │ │
│ └───────────────┬───────────────────┘ │
└───────────────────┼─────────────────────┘
│ iptables-restore
┌───────────────────▼─────────────────────┐
│ Linux Kernel Netfilter │
│ - iptables/ip6tables │
│ - Netfilter hooks │
│ - eBPF (Android T+) │
└──────────────────────────────────────────┘
1.2 iptables 五表五链
Android 使用的 5 个 iptables 表:
| 表名 | 功能 | 在 Android 中的用途 |
|---|---|---|
| filter | 包过滤 | 防火墙、流量统计、网络共享转发 |
| nat | 地址转换 | 热点 NAT、端口映射 |
| mangle | 包修改标记 | 路由标记、唤醒检测、空闲计时 |
| raw | 连接跟踪前处理 | 空闲计时、Tethering |
| security | SELinux 标记 | (较少使用) |
5 条内核原生链(Netfilter Hooks):
- PREROUTING - 路由决策前(raw, mangle, nat 表)
- INPUT - 进入本机的包(mangle, filter 表)
- FORWARD - 转发的包(mangle, filter 表)
- OUTPUT - 本机发出的包(raw, mangle, nat, filter 表)
- POSTROUTING - 路由决策后(mangle, nat 表)
二、Android 自定义链体系
2.1 链的创建顺序(关键!)
void Controllers::initChildChains() {
/*
* This is the only time we touch top-level chains in iptables; controllers
* should only mutate rules inside of their children chains, as created by
* the constants above.
*
* Modules should never ACCEPT packets (except in well-justified cases);
* they should instead defer to any remaining modules using RETURN, or
* otherwise DROP/REJECT.
*/
// Create chains for child modules.
createChildChains(V4V6, "filter", "INPUT", FILTER_INPUT, true);
createChildChains(V4V6, "filter", "FORWARD", FILTER_FORWARD, true);
createChildChains(V4V6, "raw", "PREROUTING", RAW_PREROUTING, true);
createChildChains(V4V6, "mangle", "FORWARD", MANGLE_FORWARD, true);
createChildChains(V4V6, "mangle", "INPUT", MANGLE_INPUT, true);
createChildChains(V4V6, "mangle", "OUTPUT", MANGLE_OUTPUT, true);
createChildChains(V4, "nat", "PREROUTING", NAT_PREROUTING, true);
createChildChains(V4, "nat", "POSTROUTING", NAT_POSTROUTING, true);
createChildChains(V4, "filter", "OUTPUT", FILTER_OUTPUT, false);
createChildChains(V6, "filter", "OUTPUT", FILTER_OUTPUT, false);
createChildChains(V4, "mangle", "POSTROUTING", MANGLE_POSTROUTING, false);
createChildChains(V6, "mangle", "POSTROUTING", MANGLE_POSTROUTING, false);
}
2.2 各表的子链映射
/**
* List of module chains to be created, along with explicit ordering. ORDERING
* IS CRITICAL, AND SHOULD BE TRIPLE-CHECKED WITH EACH CHANGE.
*/
static const std::vector<const char*> FILTER_INPUT = {
// Bandwidth should always be early in input chain, to make sure we
// correctly count incoming traffic against data plan.
BandwidthController::LOCAL_INPUT,
FirewallController::LOCAL_INPUT,
};
static const std::vector<const char*> FILTER_FORWARD = {
OEM_IPTABLES_FILTER_FORWARD,
FirewallController::LOCAL_FORWARD,
BandwidthController::LOCAL_FORWARD,
TetherController::LOCAL_FORWARD,
};
static const std::vector<const char*> FILTER_OUTPUT = {
OEM_IPTABLES_FILTER_OUTPUT,
FirewallController::LOCAL_OUTPUT,
StrictController::LOCAL_OUTPUT,
BandwidthController::LOCAL_OUTPUT,
};
static const std::vector<const char*> RAW_PREROUTING = {
IdletimerController::LOCAL_RAW_PREROUTING,
BandwidthController::LOCAL_RAW_PREROUTING,
TetherController::LOCAL_RAW_PREROUTING,
};
static const std::vector<const char*> MANGLE_POSTROUTING = {
OEM_IPTABLES_MANGLE_POSTROUTING,
BandwidthController::LOCAL_MANGLE_POSTROUTING,
IdletimerController::LOCAL_MANGLE_POSTROUTING,
};
static const std::vector<const char*> MANGLE_INPUT = {
CONNMARK_MANGLE_INPUT,
WakeupController::LOCAL_MANGLE_INPUT,
RouteController::LOCAL_MANGLE_INPUT,
};
static const std::vector<const char*> MANGLE_FORWARD = {
TetherController::LOCAL_MANGLE_FORWARD,
};
static const std::vector<const char*> MANGLE_OUTPUT = {
CONNMARK_MANGLE_OUTPUT,
};
static const std::vector<const char*> NAT_PREROUTING = {
OEM_IPTABLES_NAT_PREROUTING,
};
static const std::vector<const char*> NAT_POSTROUTING = {
TetherController::LOCAL_NAT_POSTROUTING,
};
链名常量总结:
| Controller | filter 表 | nat 表 | mangle 表 | raw 表 |
|---|---|---|---|---|
| BandwidthController | bw_INPUT bw_FORWARD bw_OUTPUT | - | bw_mangle_POSTROUTING | bw_raw_PREROUTING |
| FirewallController | fw_INPUT fw_FORWARD fw_OUTPUT | - | - | - |
| TetherController | tetherctrl_FORWARD | tetherctrl_nat_POSTROUTING | tetherctrl_mangle_FORWARD | tetherctrl_raw_PREROUTING |
| IdletimerController | - | - | idletimer_mangle_POSTROUTING | idletimer_raw_PREROUTING |
| WakeupController | - | - | wakeupctrl_mangle_INPUT | - |
| RouteController | - | - | routectrl_mangle_INPUT | - |
| StrictController | oem_out (OUTPUT) | - | - | - |
三、各 Controller 详细分析
3.1 BandwidthController - 流量控制
功能概述
- 数据配额管理(Data Saver)
- 按 UID/接口流量统计
- Penalty Box(黑名单)和 Happy Box(白名单)
- 全局流量警告
链结构
Filter 表:
bw_INPUT/bw_OUTPUT/bw_FORWARDbw_costly_shared- 共享配额链bw_costly_<iface>- 每接口独立配额链bw_penalty_box- 限制应用黑名单bw_happy_box- 允许应用白名单bw_data_saver- 数据节省模式bw_global_alert- 全局流量警告
Raw/Mangle 表:
bw_raw_PREROUTING- 入站流量统计(配合 xt_bpf)bw_mangle_POSTROUTING- 出站流量统计(配合 xt_bpf)
规则示例
# 1. 标记接口为计费接口
iptables -t filter -N bw_costly_rmnet0
iptables -t filter -I bw_INPUT -i rmnet0 -j bw_costly_rmnet0
iptables -t filter -I bw_OUTPUT -o rmnet0 -j bw_costly_rmnet0
# 2. 设置配额(500MB)
iptables -t filter -A bw_costly_rmnet0 -m quota ! --quota 524288000 \
-j REJECT --reject-with icmp-port-unreachable
# 3. 跳转到黑名单/白名单检查
iptables -t filter -A bw_costly_rmnet0 -j bw_penalty_box
iptables -t filter -A bw_penalty_box -j bw_happy_box
iptables -t filter -A bw_happy_box -j bw_data_saver
# 4. Penalty Box - 阻止特定应用
iptables -t filter -I bw_penalty_box -m owner --uid-owner 10086 \
-j REJECT --reject-with icmp-port-unreachable
# 5. Happy Box - 允许特定应用(系统应用、白名单)
iptables -t filter -I bw_happy_box -m owner --uid-owner 1000 -j RETURN
# 6. Data Saver - 省流量模式(全局开关)
# 启用时:拒绝所有(除了白名单)
iptables -t filter -R bw_data_saver 1 -j REJECT --reject-with icmp-port-unreachable
# 禁用时:放行
iptables -t filter -R bw_data_saver 1 -j RETURN
实际使用场景
- 移动数据限制:用户设置500MB月流量限制
- 后台数据限制:阻止特定应用后台联网
- Data Saver:省流量模式,仅允许白名单应用
- 流量统计:
NetworkStatsService读取 xt_qtaguid 统计
3.2 FirewallController - 防火墙
功能概述
- Allowlist/Denylist 两种模式
- 按 UID 或接口过滤
- 省电模式(Doze、Standby、PowerSave、Restricted、Low Power Standby)
- ICMPv6 必要连通性保证
链结构
Filter 表:
fw_INPUT/fw_OUTPUT/fw_FORWARD- 主防火墙链fw_dozable- Doze 模式链fw_standby- App Standby 模式链fw_powersave- 省电模式链fw_restricted- 受限网络模式链fw_low_power_standby- 低功耗待机模式链
模式说明
Denylist 模式(默认):
- 默认允许所有流量
- 仅阻止明确指定的 UID/接口
Allowlist 模式:
- 默认拒绝所有流量
- 仅允许明确指定的 UID/接口
int FirewallController::setFirewallType(FirewallType ftype) {
int res = 0;
if (mFirewallType != ftype) {
// flush any existing rules
resetFirewall();
if (ftype == ALLOWLIST) {
// create default rule to drop all traffic
std::string command =
"*filter\n"
"-A fw_INPUT -j DROP\n"
"-A fw_OUTPUT -j REJECT\n"
"-A fw_FORWARD -j REJECT\n"
"COMMIT\n";
res = execIptablesRestore(V4V6, command.c_str());
}
// Set this after calling disableFirewall(), since it defaults to ALLOWLIST there
mFirewallType = ftype;
}
return res ? -EREMOTEIO : 0;
}
ICMPv6 关键规则
// ICMPv6 types that are required for any form of IPv6 connectivity to work. Note that because the
// fw_dozable chain is called from both INPUT and OUTPUT, this includes both packets that we need
// to be able to send (e.g., RS, NS), and packets that we need to receive (e.g., RA, NA).
const char* FirewallController::ICMPV6_TYPES[] = {
"packet-too-big",
"router-solicitation",
"router-advertisement",
"neighbour-solicitation",
"neighbour-advertisement",
"redirect",
};
这些 ICMPv6 类型是 IPv6 基本连通性的必需,即使在防火墙严格模式下也必须放行。
规则示例
# Doze 模式 - 仅允许特定 UID
iptables -t filter -N fw_dozable
iptables -t filter -A fw_dozable -m owner --uid-owner 1000 -j RETURN # 系统服务
iptables -t filter -A fw_dozable -p icmpv6 --icmpv6-type router-solicitation -j RETURN
# ... 其他 ICMPv6 类型
iptables -t filter -A fw_dozable -j DROP
# Standby 模式 - 阻止空闲应用
iptables -t filter -N fw_standby
iptables -t filter -A fw_standby -m owner --uid-owner 10086 -j DROP # 空闲应用
iptables -t filter -A fw_standby -j RETURN
3.3 TetherController - 网络共享(重点:NAT 表)
功能概述
- Wi-Fi 热点
- USB 网络共享
- 蓝牙网络共享
- NAT 地址转换
- MSS Clamping(防止分片)
- 流量统计
链结构
NAT 表(⭐核心):
tetherctrl_nat_POSTROUTING- NAT 转换(MASQUERADE)
Filter 表:
tetherctrl_FORWARD- 转发控制tetherctrl_counters- 流量计数器
Mangle 表:
tetherctrl_mangle_FORWARD- MSS Clamping
Raw 表:
tetherctrl_raw_PREROUTING- 计数器(IPv6)
NAT 规则详解
int TetherController::enableNat(const char* intIface, const char* extIface) {
ALOGV("enableNat(intIface=<%s>, extIface=<%s>)",intIface, extIface);
if (!isIfaceName(intIface) || !isIfaceName(extIface)) {
return -ENODEV;
}
/* Bug: b/9565268. "enableNat wlan0 wlan0". For now we fail until java-land is fixed */
if (!strcmp(intIface, extIface)) {
ALOGE("Duplicate interface specified: %s %s", intIface, extIface);
return -EINVAL;
}
if (isForwardingPairEnabled(intIface, extIface)) {
return 0;
}
// add this if we are the first enabled nat for this upstream
if (!isAnyForwardingEnabledOnUpstream(extIface)) {
std::vector<std::string> v4Cmds = {
"*nat",
StringPrintf("-A %s -o %s -j MASQUERADE", LOCAL_NAT_POSTROUTING, extIface),
"COMMIT\n"
};
if (iptablesRestoreFunction(V4, Join(v4Cmds, '\n'), nullptr) || setupIPv6CountersChain() ||
setTetherGlobalAlertRule()) {
ALOGE("Error setting postroute rule: iface=%s", extIface);
if (!isAnyForwardingPairEnabled()) {
// unwind what's been done, but don't care about success - what more could we do?
setDefaults();
}
return -EREMOTEIO;
}
}
if (setForwardRules(true, intIface, extIface) != 0) {
ALOGE("Error setting forward rules");
if (!isAnyForwardingPairEnabled()) {
setDefaults();
}
return -ENODEV;
}
return 0;
}
实际规则示例
# 场景:手机通过 rmnet0(移动数据)上网,开启 Wi-Fi 热点(wlan0)
# 1. NAT 表 - MASQUERADE(地址伪装)
iptables -t nat -A tetherctrl_nat_POSTROUTING -o rmnet0 -j MASQUERADE
# 2. Filter 表 - 允许转发
iptables -t filter -A tetherctrl_FORWARD -i wlan0 -o rmnet0 -m state --state RELATED,ESTABLISHED -j RETURN
iptables -t filter -A tetherctrl_FORWARD -i wlan0 -o rmnet0 -j tetherctrl_counters
iptables -t filter -A tetherctrl_FORWARD -i rmnet0 -o wlan0 -m state --state RELATED,ESTABLISHED -j RETURN
iptables -t filter -A tetherctrl_FORWARD -i rmnet0 -o wlan0 -j tetherctrl_counters
# 3. Mangle 表 - MSS Clamping(解决 MTU 问题)
iptables -t mangle -A tetherctrl_mangle_FORWARD -p tcp --tcp-flags SYN SYN \
-j TCPMSS --clamp-mss-to-pmtu
# 4. 流量计数器
iptables -t filter -N tetherctrl_counters
工作原理:
- 客户端(192.168.43.100)通过热点访问互联网
- 数据包到达手机:
192.168.43.100:12345 → 8.8.8.8:53 - FORWARD 链处理:检查状态、计数
- POSTROUTING NAT:源地址改为手机公网 IP
10.0.0.1:54321 → 8.8.8.8:53
- 回复包到达:
8.8.8.8:53 → 10.0.0.1:54321 - PREROUTING NAT(conntrack 自动):目标地址改回
8.8.8.8:53 → 192.168.43.100:12345
3.4 IdletimerController - 网络空闲检测
功能概述
- 检测接口在指定时间内是否有数据传输
- 通过 IDLETIMER iptables 模块实现
- 超时后通过 netlink 通知用户空间
- 用于省电:关闭长时间无流量的网络连接
链结构
Raw 表:
idletimer_raw_PREROUTING- 入站流量监测
Mangle 表:
idletimer_mangle_POSTROUTING- 出站流量监测
规则示例
# 监测 rmnet0 接口,5秒无流量则触发通知
iptables -t raw -A idletimer_raw_PREROUTING -i rmnet0 \
-j IDLETIMER --timeout 5 --label rmnet0 --send_nl_msg
iptables -t mangle -A idletimer_mangle_POSTROUTING -o rmnet0 \
-j IDLETIMER --timeout 5 --label rmnet0 --send_nl_msg
工作流程:
- 接口有流量 → 计时器重置
- 5 秒无流量 → 内核发送 netlink 消息
- netd 接收通知 → 通知 ConnectivityService
- 系统决策:断开连接或保持
3.5 WakeupController - 唤醒包检测
功能概述
- 检测导致设备从休眠状态唤醒的网络包
- 使用 NFLOG 记录包内容
- 用于诊断电量消耗问题
链结构
Mangle 表:
wakeupctrl_mangle_INPUT- 入站唤醒包检测
规则示例
Status WakeupController::execIptables(const std::string& action, const std::string& ifName,
const std::string& prefix, uint32_t mark, uint32_t mask) {
// NFLOG messages to batch before releasing to userspace
constexpr int kBatch = 8;
const char kFormat[] =
"*mangle\n"
"%s %s -i %s -m mark --mark 0x%08x/0x%08x -m limit --limit 10/s"
" -j NFLOG --nflog-prefix %s --nflog-group %d --nflog-threshold %d\n"
"COMMIT\n";
const auto cmd = StringPrintf(kFormat,
action.c_str(), WakeupController::LOCAL_MANGLE_INPUT, ifName.c_str(), mark, mask,
prefix.c_str(), NetlinkManager::NFLOG_WAKEUP_GROUP, kBatch);
std::string out;
auto rv = mIptables->execute(V4V6, cmd, &out);
if (rv != 0) {
auto s = Status(rv, "Failed to execute iptables cmd: " + cmd + ", out: " + out);
ALOGE("%s", toString(s).c_str());
return s;
}
return netdutils::status::ok;
}
# 监测 rmnet0 上带有特定 mark 的唤醒包
iptables -t mangle -A wakeupctrl_mangle_INPUT -i rmnet0 \
-m mark --mark 0x00001000/0x0000f000 \
-m limit --limit 10/s \
-j NFLOG --nflog-prefix "WAKEUP:" --nflog-group 100 --nflog-threshold 8
3.6 RouteController - 路由标记
功能概述
- 为入站数据包打 fwmark(包含 netId、VPN 标记等)
- 确保回复包使用正确的网络接口
- 支持多网络并存
- VPN 路由策略
链结构
Mangle 表:
routectrl_mangle_INPUT- 入站包标记
Fwmark 结构
// Fwmark.h
struct Fwmark {
uint32_t netId : 16; // 网络 ID
uint32_t explicitlySelected : 1; // 应用显式选择
uint32_t protectedFromVpn : 1; // 绕过 VPN
uint32_t permission : 2; // 网络权限
uint32_t uidBillingDone : 1; // UID 计费完成
// ... 其他字段
};
规则示例
// An iptables rule to mark incoming packets on a network with the netId of the network.
//
// This is so that the kernel can:
// + Use the right fwmark for (and thus correctly route) replies (e.g.: TCP RST, ICMP errors, ping
// replies, SYN-ACKs, etc).
// + Mark sockets that accept connections from this interface so that the connection stays on the
// same interface.
int modifyIncomingPacketMark(unsigned netId, const char* interface, Permission permission,
bool add) {
Fwmark fwmark;
fwmark.netId = netId;
fwmark.explicitlySelected = true;
fwmark.protectedFromVpn = true;
fwmark.permission = permission;
const uint32_t mask = Fwmark::getUidBillingMask() | Fwmark::getIngressCpuWakeupMask();
std::string cmd = StringPrintf(
"%s %s -i %s -j MARK --set-mark 0x%x/0x%x", add ? "-A" : "-D",
RouteController::LOCAL_MANGLE_INPUT, interface, fwmark.intValue, ~mask);
if (RouteController::iptablesRestoreCommandFunction(V4V6, "mangle", cmd, nullptr) != 0) {
ALOGE("failed to change iptables rule that sets incoming packet mark");
return -EREMOTEIO;
}
return 0;
}
# 为从 wlan0 进入的包打上 netId=100 的标记
iptables -t mangle -A routectrl_mangle_INPUT -i wlan0 \
-j MARK --set-mark 0x00640003/0xffff00ff
3.7 StrictController - 明文检测
功能概述
- 检测明文 HTTP/FTP 流量
- 检测 TLS/DTLS 连接
- 用于 StrictMode 网络策略
链结构
Filter 表:
oem_out(LOCAL_OUTPUT) - 出站流量检测oem_clear_detect- 明文检测oem_clear_caught- 明文捕获oem_penalty_log- 日志记录
四、iptables 与 eBPF 的协同
从 Android T (13) 开始,部分功能逐步迁移到 eBPF,但仍保留 iptables 兼容层。
4.1 xt_bpf 模块
iptables 通过 xt_bpf 模块调用 eBPF 程序:
# 使用 eBPF 程序进行流量统计
iptables -t raw -A bw_raw_PREROUTING \
-m bpf --object-pinned /sys/fs/bpf/netd/xt_bpf_ingress_prog -j ACCEPT
4.2 流量统计迁移
传统方式 (xt_qtaguid):
iptables -t mangle -A bw_mangle_POSTROUTING -j owner
新方式 (eBPF + xt_bpf):
{
// Clat daemon does not generate new traffic, all its traffic is accounted for already
// on the v4-* interfaces (except for the 20 (or 28) extra bytes of IPv6 vs IPv4 overhead,
// but that can be corrected for later when merging v4-foo stats into interface foo's).
// CLAT sockets are created by system server and tagged as uid CLAT, see tagSocketAsClat()
uint32_t sock_uid = bpf_get_socket_uid(skb);
if (sock_uid == AID_SYSTEM) {
uint64_t cookie = bpf_get_socket_cookie(skb);
UidTagValue* utag = bpf_cookie_tag_map_lookup_elem(&cookie);
if (utag && utag->uid == AID_CLAT) return BPF_NOMATCH;
}
uint32_t key = skb->ifindex;
update_iface_stats_map(skb, &key, EGRESS, KVER_NONE);
return BPF_MATCH;
}
// WARNING: Android T's non-updatable netd depends on the name of this program.
DEFINE_XTBPF_PROG("skfilter/ingress/xtbpf", AID_ROOT, AID_NET_ADMIN, xt_bpf_ingress_prog)
(struct __sk_buff* skb) {
// Clat daemon traffic is not accounted by virtue of iptables raw prerouting drop rule
// (in clat_raw_PREROUTING chain), which triggers before this (in bw_raw_PREROUTING chain).
// It will be accounted for on the v4-* clat interface instead.
// Keep that in mind when moving this out of iptables xt_bpf and into tc ingress (or xdp).
uint32_t key = skb->ifindex;
update_iface_stats_map(skb, &key, INGRESS, KVER_NONE);
return BPF_MATCH;
}
优势:
- 性能更高(无需切换到用户空间)
- 更灵活(可动态更新)
- 更安全(JIT 验证)
五、规则管理机制
5.1 iptables-restore 批量更新
Android 不直接调用 iptables 命令,而是使用 iptables-restore 批量应用规则:
// 示例
std::string commands =
"*filter\n"
":bw_INPUT -\n"
":bw_OUTPUT -\n"
"-A bw_INPUT -i rmnet0 -j bw_costly_shared\n"
"-A bw_OUTPUT -o rmnet0 -j bw_costly_shared\n"
"COMMIT\n"
"*nat\n"
":tetherctrl_nat_POSTROUTING -\n"
"-A tetherctrl_nat_POSTROUTING -o wlan0 -j MASQUERADE\n"
"COMMIT\n";
execIptablesRestore(V4, commands);
优势:
- 原子性操作(要么全成功,要么全失败)
- 性能高(一次性加载多条规则)
- 减少内核锁竞争
5.2 初始化流程
void Controllers::initIptablesRules() {
Stopwatch s;
initChildChains();
gLog.info("Creating child chains: %" PRId64 "us", s.getTimeAndResetUs());
// Let each module setup their child chains
setupOemIptablesHook();
gLog.info("Setting up OEM hooks: %" PRId64 "us", s.getTimeAndResetUs());
/* When enabled, DROPs all packets except those matching rules. */
firewallCtrl.setupIptablesHooks();
gLog.info("Setting up FirewallController hooks: %" PRId64 "us", s.getTimeAndResetUs());
/* Does DROPs in FORWARD by default */
tetherCtrl.setupIptablesHooks();
gLog.info("Setting up TetherController hooks: %" PRId64 "us", s.getTimeAndResetUs());
/*
* Does REJECT in INPUT, OUTPUT. Does counting also.
* No DROP/REJECT allowed later in netfilter-flow hook order.
*/
bandwidthCtrl.setupIptablesHooks();
gLog.info("Setting up BandwidthController hooks: %" PRId64 "us", s.getTimeAndResetUs());
/*
* Counts in nat: PREROUTING, POSTROUTING.
* No DROP/REJECT allowed later in netfilter-flow hook order.
*/
idletimerCtrl.setupIptablesHooks();
gLog.info("Setting up IdletimerController hooks: %" PRId64 "us", s.getTimeAndResetUs());
/*
* Add rules for detecting IPv6/IPv4 TCP/UDP connections with TLS/DTLS header
*/
strictCtrl.setupIptablesHooks();
gLog.info("Setting up StrictController hooks: %" PRId64 "us", s.getTimeAndResetUs());
/*
* Add rules for storing netid in connmark.
*/
setupConnmarkIptablesHooks();
gLog.info("Setting up connmark hooks: %" PRId64 "us", s.getTimeAndResetUs());
}
六、实际应用案例
案例 1: 用户开启 Data Saver
流程:
用户操作 → Settings App
↓
NetworkPolicyManagerService
↓
ConnectivityService.setDataSaverEnabled(true)
↓
INetd.bandwidthEnableDataSaver(true)
↓
BandwidthController 修改 bw_data_saver 链
iptables 变化:
# 禁用前
iptables -t filter -L bw_data_saver -v
Chain bw_data_saver (1 references)
pkts bytes target prot opt in out source destination
0 0 RETURN all -- any any anywhere anywhere
# 启用后
Chain bw_data_saver (1 references)
pkts bytes target prot opt in out source destination
1234 567K REJECT all -- any any anywhere anywhere reject-with icmp-port-unreachable
结果:所有应用后台流量被阻止(除了白名单)
案例 2: 开启 Wi-Fi 热点
流程:
用户开启热点 → TetheringManager
↓
TetherController.enableNat("wlan0", "rmnet0")
↓
创建 NAT/FORWARD 规则
完整规则集:
# NAT 表
*nat
:tetherctrl_nat_POSTROUTING -
-A POSTROUTING -j tetherctrl_nat_POSTROUTING
-A tetherctrl_nat_POSTROUTING -o rmnet0 -j MASQUERADE
COMMIT
# Filter 表
*filter
:tetherctrl_FORWARD -
:tetherctrl_counters -
-A FORWARD -j tetherctrl_FORWARD
-A tetherctrl_FORWARD -j DROP # 默认拒绝
-A tetherctrl_FORWARD -i wlan0 -o rmnet0 -m state --state RELATED,ESTABLISHED -j RETURN
-A tetherctrl_FORWARD -i wlan0 -o rmnet0 -g tetherctrl_counters
-A tetherctrl_FORWARD -i rmnet0 -o wlan0 -m state --state RELATED,ESTABLISHED -j RETURN
-A tetherctrl_FORWARD -i rmnet0 -o wlan0 -g tetherctrl_counters
COMMIT
# Mangle 表
*mangle
:tetherctrl_mangle_FORWARD -
-A FORWARD -j tetherctrl_mangle_FORWARD
-A tetherctrl_mangle_FORWARD -p tcp --tcp-flags SYN SYN -j TCPMSS --clamp-mss-to-pmtu
COMMIT
案例 3: Doze 模式省电
流程:
设备进入 Doze → DeviceIdleController
↓
NetworkPolicyManagerService
↓
INetd.firewallSetUidRule(DOZABLE, uid, ALLOW)
↓
FirewallController 修改 fw_dozable 链
规则:
iptables -t filter -N fw_dozable
iptables -t filter -A INPUT -j fw_dozable
iptables -t filter -A OUTPUT -j fw_dozable
# 允许系统UID
iptables -t filter -A fw_dozable -m owner --uid-owner 0-9999 -j RETURN
# 允许白名单应用
iptables -t filter -A fw_dozable -m owner --uid-owner 10086 -j RETURN # 微信
# 允许必要的 ICMPv6
iptables -t filter -A fw_dozable -p icmpv6 --icmpv6-type router-solicitation -j RETURN
# ... 其他 ICMPv6 类型
# 默认拒绝
iptables -t filter -A fw_dozable -j DROP
七、总结表格
7.1 完整 Controller 功能矩阵
| Controller | Filter 表 | NAT 表 | Mangle 表 | Raw 表 | 主要功能 |
|---|---|---|---|---|---|
| BandwidthController | ✅ INPUT/OUTPUT/FORWARD • 流量配额 • Penalty/Happy Box • Data Saver | ❌ | ✅ POSTROUTING • 出站统计(xt_bpf) | ✅ PREROUTING • 入站统计(xt_bpf) | 流量控制、配额管理、统计 |
| FirewallController | ✅ INPUT/OUTPUT/FORWARD • Allowlist/Denylist • Doze/Standby/PowerSave • Restricted | ❌ | ❌ | ❌ | 防火墙、省电模式 |
| TetherController | ✅ FORWARD • 转发控制 • 流量计数 | ✅ POSTROUTING • MASQUERADE • NAT 转换 | ✅ FORWARD • MSS Clamping | ✅ PREROUTING • IPv6 计数 | 网络共享、热点 |
| IdletimerController | ❌ | ❌ | ✅ POSTROUTING • IDLETIMER 出站 | ✅ PREROUTING • IDLETIMER 入站 | 空闲检测、省电 |
| WakeupController | ❌ | ❌ | ✅ INPUT • NFLOG 唤醒包 | ❌ | 唤醒包诊断 |
| RouteController | ❌ | ❌ | ✅ INPUT • Fwmark 标记 • 多网络路由 | ❌ | 路由策略、多网络 |
| StrictController | ✅ OUTPUT • 明文检测 | ❌ | ❌ | ❌ | StrictMode 策略 |
7.2 关键配置参数
| 功能 | 配置路径 | 默认值 | 说明 |
|---|---|---|---|
| Data Saver | Settings → Network & internet → Data Saver | OFF | 省流量模式 |
| 流量警告 | CarrierConfigManager | 2GB | 流量警告阈值 |
| Doze 白名单 | Settings → Battery → Battery optimization | 系统应用 | 省电模式白名单 |
| 热点客户端数 | tether_offload_disabled | 8 | 最大连接数 |
八、调试命令
# 查看所有 iptables 规则
adb shell iptables -t filter -L -v -n
adb shell iptables -t nat -L -v -n
adb shell iptables -t mangle -L -v -n
adb shell iptables -t raw -L -v -n
# 查看特定链
adb shell iptables -t filter -L bw_INPUT -v -n --line-numbers
# 实时监控包计数
adb shell watch -n1 "iptables -t filter -L bw_costly_rmnet0 -v -n -x"
# 查看 NAT 连接跟踪
adb shell cat /proc/net/nf_conntrack | grep MASQUERADE
# 清空计数器
adb shell iptables -t filter -Z
# 查看 netd 日志
adb logcat -s NetdConnector:V Netd:V BandwidthController:V FirewallController:V
这份文档涵盖了 Android iptables 应用的所有核心方面,从架构设计到具体实现,从规则管理到实际案例,应该能满足您全面了解的需求。如需深入某个特定模块,请告诉我!