Android 系统中 iptables 应用全面分析

3 阅读15分钟

一、整体架构

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
securitySELinux 标记(较少使用)

5 条内核原生链(Netfilter Hooks):

  1. PREROUTING - 路由决策前(raw, mangle, nat 表)
  2. INPUT - 进入本机的包(mangle, filter 表)
  3. FORWARD - 转发的包(mangle, filter 表)
  4. OUTPUT - 本机发出的包(raw, mangle, nat, filter 表)
  5. 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,
};

链名常量总结

Controllerfilter 表nat 表mangle 表raw 表
BandwidthControllerbw_INPUT
bw_FORWARD
bw_OUTPUT
-bw_mangle_POSTROUTINGbw_raw_PREROUTING
FirewallControllerfw_INPUT
fw_FORWARD
fw_OUTPUT
---
TetherControllertetherctrl_FORWARDtetherctrl_nat_POSTROUTINGtetherctrl_mangle_FORWARDtetherctrl_raw_PREROUTING
IdletimerController--idletimer_mangle_POSTROUTINGidletimer_raw_PREROUTING
WakeupController--wakeupctrl_mangle_INPUT-
RouteController--routectrl_mangle_INPUT-
StrictControlleroem_out (OUTPUT)---

三、各 Controller 详细分析

3.1 BandwidthController - 流量控制

功能概述

  • 数据配额管理(Data Saver)
  • 按 UID/接口流量统计
  • Penalty Box(黑名单)和 Happy Box(白名单)
  • 全局流量警告

链结构

Filter 表:

  • bw_INPUT / bw_OUTPUT / bw_FORWARD
  • bw_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

实际使用场景

  1. 移动数据限制:用户设置500MB月流量限制
  2. 后台数据限制:阻止特定应用后台联网
  3. Data Saver:省流量模式,仅允许白名单应用
  4. 流量统计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

工作原理

  1. 客户端(192.168.43.100)通过热点访问互联网
  2. 数据包到达手机:192.168.43.100:12345 → 8.8.8.8:53
  3. FORWARD 链处理:检查状态、计数
  4. POSTROUTING NAT:源地址改为手机公网 IP
    • 10.0.0.1:54321 → 8.8.8.8:53
  5. 回复包到达:8.8.8.8:53 → 10.0.0.1:54321
  6. 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

工作流程

  1. 接口有流量 → 计时器重置
  2. 5 秒无流量 → 内核发送 netlink 消息
  3. netd 接收通知 → 通知 ConnectivityService
  4. 系统决策:断开连接或保持

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 功能矩阵

ControllerFilter 表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 SaverSettings → Network & internet → Data SaverOFF省流量模式
流量警告CarrierConfigManager2GB流量警告阈值
Doze 白名单Settings → Battery → Battery optimization系统应用省电模式白名单
热点客户端数tether_offload_disabled8最大连接数

八、调试命令

# 查看所有 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 应用的所有核心方面,从架构设计到具体实现,从规则管理到实际案例,应该能满足您全面了解的需求。如需深入某个特定模块,请告诉我!