本内容覆盖了 NAT 的基本概念、Android 实现方式、连接跟踪机制(conntrack)及具体的示例流程。
Android 网络栈中的 NAT 实现原理与 Netfilter 钩子机制
🧭 前言
NAT(Network Address Translation)是现代网络中最常见的技术之一,广泛用于家庭、企业和云服务网络场景中。在 Linux 中,NAT 是通过 Netfilter 框架实现的,它结合了多层钩子点(hooks)与连接跟踪(conntrack)系统,实现了完整、灵活且强大的网络地址转换功能。
本篇文章将从 NAT 的核心原理出发,结合 Linux 内核的钩子机制(PREROUTING、POSTROUTING 等),并配合具体示例深入剖析 Linux 是如何完成 NAT 操作的。
📌 第一部分:NAT 基本概念简述
🔶 什么是 NAT?
NAT 是一种 IP 层的地址转换技术,它的主要作用是在网络边界上修改 IP 数据包中的源地址或目标地址。常见有两种形式:
- SNAT(Source NAT) :修改源地址,常用于“内网设备访问外网”场景。
- DNAT(Destination NAT) :修改目标地址,常用于“外网访问内网服务”场景。
🔷 NAT 的典型应用
| 场景 | 使用 NAT 类型 | 示例说明 |
|---|---|---|
| 内网电脑访问外网网站 | SNAT | 192.168.1.100 → 203.0.113.5 |
| 外网访问家庭摄像头 | DNAT | 203.0.113.5:8080 → 192.168.1.100:80 |
| 负载均衡流量转发(LVS) | DNAT/SNAT | 网关代理连接并重定向流量 |
NAT的目标是什么
无论是家用路由器、企业防火墙还是 Linux 系统,NAT 的核心目标都是:
- SNAT(Source NAT) :修改源 IP,用于内网机器访问外网时,伪装为网关的公网 IP。
- DNAT(Destination NAT) :修改目标 IP,用于外网访问内网服务时,转发到真实内网主机。
- 连接跟踪(conntrack) :对 NAT 后的连接进行状态跟踪,确保响应包能够正确返回。
这些 NAT 类型在路由器和 Linux 中都有体现,属于 “网络层的地址转换” 。
NAT工作在哪一层
因为NAT会修改IP头、TCP头、UDP头、ICMP头等,所以NAT工作在传输层和网络层
🔍 第二部分:Linux 中 NAT 的实现基础 - Netfilter 框架
Linux 实现 NAT 是基于 Netfilter 框架完成的。Netfilter 提供了一套钩子点机制,让内核模块(如 iptables/nftables)可以在数据包处理路径的多个阶段挂接逻辑。
📌 Netfilter 的五个主要钩子点(hooks)
| 钩子链名称 | 处理阶段 | 常见用途 |
|---|---|---|
PREROUTING | 数据包刚进入网卡 | 主要用于 DNAT |
INPUT | 数据包即将进入本机 | 本地服务的接收处理 |
FORWARD | 数据包被转发(非本机) | 路由转发控制 |
POSTROUTING | 数据包将离开发送出网卡前 | 主要用于 SNAT |
OUTPUT | 本地进程发出的包 | 本地 NAT 也可能在此 |
🧠 NAT 是工作在 PREROUTING 和 POSTROUTING 上的逻辑(DNAT 和 SNAT) 。
🧠 第三部分:连接跟踪(conntrack)系统
🔸 conntrack 简介
NAT 的核心难点在于:如果修改了地址,响应包还能回来吗?
Linux 使用 conntrack 模块解决这一问题。它会为每条连接维护状态记录和 NAT 映射。
比如:
tcp 6 431999 ESTABLISHED src=192.168.1.100 dst=8.8.8.8 sport=54321 dport=443 [UNREPLIED]
conntrack 在第一次请求时建立记录,并在后续包中引用这条记录,完成 NAT 转换的对称性。
🔧 第四部分:NAT 数据包流程示例(家庭网络)
我们用一个家庭路由器为例,演示内网主机访问公网、外网主机回包的整个 NAT 过程。
✅ 情景:内网主机访问外网网站(SNAT)
前提:
- 内网主机:
192.168.1.100 - 路由器公网地址:
203.0.113.5 - 外网服务器:
8.8.8.8
流程如下:
- 内网主机发送请求:
src=192.168.1.100:54321 → dst=8.8.8.8:443
- 包进入 Netfilter PREROUTING → 被允许通过 → 路由决定出接口为 eth0
- 到达 POSTROUTING:执行 SNAT(MASQUERADE)
src=203.0.113.5:40000 → dst=8.8.8.8:443
- conntrack 创建映射:记录 src 原地址
- 包被发送到 eth0 出口,发往公网
🔁 外网回包过程(DNAT via conntrack)
- 外网服务器回应包:
src=8.8.8.8:443 → dst=203.0.113.5:40000
- 包进入 PREROUTING
- conntrack 识别该连接,执行 DNAT:
dst 修改为:192.168.1.100:54321
- 包进入 FORWARD 链,路由表找到目标为内网主机
- 最终送达主机
📘 附:iptables NAT 规则示例
# 1. 启用 IP 转发
echo 1 > /proc/sys/net/ipv4/ip_forward
# 2. 配置 SNAT(公网固定 IP)
iptables -t nat -A POSTROUTING -o eth0 -j SNAT --to-source 203.0.113.5
# 3. 或配置 MASQUERADE(动态 IP 场景)
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
# 4. 配置 DNAT(端口转发)
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 8080 -j DNAT --to-destination 192.168.1.100:80
🧩 小结
| 模块 | 功能 |
|---|---|
| Netfilter | 提供钩子点供模块在各阶段处理网络包 |
| NAT 表 | 定义 SNAT、DNAT 行为 |
| conntrack | 跟踪连接状态和 NAT 映射关系 |
| iptables | 用户态配置接口,用于管理 Netfilter 规则 |