4_iptables_NAT与网络防火墙
1. 为什么需要 NAT?
NAT(Network Address Translation,网络地址转换)解决两个核心问题:
- IPv4 地址只有约 43 亿个,远不够每台设备独占一个。NAT 允许多台内网设备共用一个公网 IP 上网——类似一家 100 人的公司只需一个总机号(公网 IP),员工用各自的分机号(内网 IP)打外线,对方看到的来电显示始终是总机号。
- 除了地址复用,NAT 还提供天然的安全隔离:外部无法直接访问内网 IP。
理解了 NAT 的动机,接下来看它的两种核心工作模式:SNAT 和 DNAT。
2. SNAT 与 DNAT 的本质
NAT 只做一件事:改地址。改源地址就是 SNAT,改目标地址就是 DNAT。
%%{init: {'theme': 'base', 'themeVariables': { 'primaryColor': '#3B82F6', 'primaryTextColor': '#1E3A5F', 'primaryBorderColor': '#2563EB', 'lineColor': '#60A5FA', 'secondaryColor': '#10B981', 'tertiaryColor': '#F59E0B'}}}%%
flowchart LR
subgraph net_in ["内网"]
A["内网主机 10.0.0.5"]
end
subgraph gw ["网关"]
B["SNAT/DNAT 公网IP: 2.2.2.2"]
end
subgraph net_out ["外网"]
C["Web 服务器 8.8.8.8"]
end
A -- "① 源: 10.0.0.5 目标: 8.8.8.8" --> B
B -- "② 源: 2.2.2.2 目标: 8.8.8.8" --> C
C -- "③ 源: 8.8.8.8 目标: 2.2.2.2" --> B
B -- "④ 源: 8.8.8.8 目标: 10.0.0.5" --> A
classDef primary fill:#3B82F6,stroke:#2563EB,color:#fff
classDef success fill:#10B981,stroke:#059669,color:#fff
classDef warning fill:#F59E0B,stroke:#D97706,color:#fff
class A primary
class B warning
class C success整个过程是 SNAT(不是 DNAT),取决于前半段改的是什么。步骤 ② 改了源地址,所以是 SNAT。步骤 ④ 中目标地址被自动改回来,由 conntrack 完成,无需手动配规则。
| SNAT | DNAT | |
|---|---|---|
| 改什么 | 源地址 | 目标地址 |
| 在哪改 | POSTROUTING(出去前) | PREROUTING(进来后、路由前) |
| 典型场景 | 内网共享上网 | 外部访问内网服务(端口映射) |
| 反向自动 | 响应包的目标地址自动改回 | 响应包的源地址自动改回 |
下面分别展开这两种模式的配置方法。
3. SNAT——内网共享上网
3.1 基本配置
场景:内网网段 10.1.0.0/16 通过网关(公网 IP 2.2.2.2)上网。
1 | iptables -t nat -A POSTROUTING -s 10.1.0.0/16 -j SNAT --to-source 2.2.2.2 |
各参数含义:
| 参数 | 含义 |
|---|---|
-t nat | 操作 nat 表 |
-A POSTROUTING | 追加到 POSTROUTING 链 |
-s 10.1.0.0/16 | 匹配源地址为内网网段 |
-j SNAT --to-source 2.2.2.2 | 把源地址改为公网 IP |
3.2 为什么 SNAT 必须在 POSTROUTING?
类比:寄信时先写好收件人地址(路由判断),在投入邮筒前最后一刻才把寄件人地址从 “ 家庭地址 “ 改成 “ 公司地址 “。如果先改了寄件人地址再做路由判断,万一出错就改不回来了。
技术原因:POSTROUTING 是报文离开系统前的最后一关,此时路由已完成、出口网卡已确定——这是修改源地址的最佳时机。
知道了固定 IP 的 SNAT 怎么配,那动态 IP 场景怎么办?
4. MASQUERADE——动态 SNAT
SNAT 的 --to-source 需要写死公网 IP。如果使用拨号上网或 DHCP 动态分配 IP,每次 IP 变化都要修改规则。MASQUERADE 自动使用出口网卡当前 IP 作为源地址:
1 | # SNAT(写死 IP) |
类比:SNAT 相当于在发件人地址写 “ 北京市 XX 路 XX 号 “(固定地址);MASQUERADE 相当于写 “ 发件人:当前所在地 “(到哪用哪的地址)。
公网 IP 固定时,优先用 SNAT。MASQUERADE 每次都要查询网卡 IP,性能略低。
前面讲的都是 “ 内网出去 “ 的场景,反过来——外网怎么访问内网服务?这就是 DNAT 的工作。
5. DNAT——外网访问内网服务
5.1 场景
公司只有一个公网 IP 2.2.2.2,内网有两个服务需要从外网访问:
- Web 服务器
10.1.0.5:80 - 远程桌面
10.1.0.6:3389
5.2 配置
1 | # 公网 80 端口 → 内网 Web 服务器 |
各参数含义:
| 参数 | 含义 |
|---|---|
-t nat -I PREROUTING | 在 nat 表 PREROUTING 链插入规则 |
-d 2.2.2.2 | 匹配目标地址为公网 IP |
-p tcp --dport 80 | 匹配 TCP 目标端口 80 |
-j DNAT --to-destination 10.1.0.5:80 | 把目标地址改为内网 IP: 端口 |
5.3 为什么 DNAT 必须在 PREROUTING?
类比:收到一封寄给 “ 公司总机 “ 的信,必须在拆开之前就决定转给哪个部门。拆开后(路由判断完成),再想转发就来不及了。
技术原因:路由判断依据目标地址决定包的走向,DNAT 修改的正是目标地址。必须在路由前完成修改,否则路由会用错误的原始地址。
%%{init: {'theme': 'base', 'themeVariables': { 'primaryColor': '#3B82F6', 'primaryTextColor': '#1E3A5F', 'primaryBorderColor': '#2563EB', 'lineColor': '#60A5FA', 'secondaryColor': '#10B981', 'tertiaryColor': '#F59E0B'}}}%%
flowchart TD
A["数据包进入"] --> B["PREROUTING"]
B --> C{"DNAT 规则匹配?"}
C -->|"是"| D["修改目标地址"]
C -->|"否"| E["保持原地址"]
D --> F["路由判断"]
E --> F
F --> G{"目标是本机?"}
G -->|"是"| H["INPUT 链"]
G -->|"否"| I["FORWARD 链"]
H --> L["本地进程"]
I --> J["POSTROUTING"]
J --> K["数据包离开"]
classDef primary fill:#3B82F6,stroke:#2563EB,color:#fff
classDef success fill:#10B981,stroke:#059669,color:#fff
classDef warning fill:#F59E0B,stroke:#D97706,color:#fff
classDef danger fill:#EF4444,stroke:#DC2626,color:#fff
class A,K primary
class B,D warning
class F,G success
class H,I,L danger5.4 DNAT 何时需要搭配 SNAT?
配置了 DNAT 规则但不生效,最常见的原因是回包没有走网关,导致 conntrack 无法还原地址。
5.4.1 正常情况:回包经过网关
如果内网服务器的默认网关就是 NAT 网关本身(大多数内网部署都是如此),DNAT 单独就能工作:
%%{init: {'theme': 'base', 'themeVariables': {'actorBkg': '#3B82F6', 'actorTextColor': '#fff', 'actorBorder': '#2563EB', 'signalColor': '#1E3A5F', 'activationBkgColor': '#DBEAFE', 'activationBorderColor': '#3B82F6'}}}%%
sequenceDiagram
autonumber
participant Client as "客户端 1.1.1.1"
participant GW as "网关 2.2.2.2 / 10.1.0.1"
participant Web as "Web 10.1.0.5"
Client->>GW: "src: 1.1.1.1 dst: 2.2.2.2:80"
Note over GW: "DNAT: dst 改为 10.1.0.5:80"
GW->>Web: "src: 1.1.1.1 dst: 10.1.0.5:80"
Web->>GW: "src: 10.1.0.5 dst: 1.1.1.1"
Note over GW: "conntrack 匹配,自动还原: src 改为 2.2.2.2"
GW->>Client: "src: 2.2.2.2 dst: 1.1.1.1"回包经过网关,conntrack 自动将源地址还原为 2.2.2.2,客户端正常收到响应。
5.4.2 异常情况:回包绕过网关
当内网服务器的默认网关不是 NAT 网关时(例如多网关环境、服务器有独立出口),回包会走其他路径,绕过 NAT 网关:
%%{init: {'theme': 'base', 'themeVariables': {'actorBkg': '#3B82F6', 'actorTextColor': '#fff', 'actorBorder': '#2563EB', 'signalColor': '#1E3A5F', 'activationBkgColor': '#DBEAFE', 'activationBorderColor': '#3B82F6'}}}%%
sequenceDiagram
autonumber
participant Client as "客户端 1.1.1.1"
participant GW as "网关 2.2.2.2"
participant Web as "Web 10.1.0.5"
Client->>GW: "src: 1.1.1.1 dst: 2.2.2.2:80"
Note over GW: "DNAT: dst 改为 10.1.0.5:80"
GW->>Web: "src: 1.1.1.1 dst: 10.1.0.5:80"
Web-->>Client: "src: 10.1.0.5 dst: 1.1.1.1 (绕过网关)"
Note over Client: "期望来自 2.2.2.2 的回包,收到 10.1.0.5,丢弃"此时需要在网关上对 DNAT 流量做 SNAT,强制回包也经过网关:
1 | # DNAT 规则 |
关键点:SNAT 的 --to-source 使用的是网关的内网 IP(10.1.0.1),而非公网 IP。这样 Web 服务器看到的源地址是 10.1.0.1,回包自然发回网关,conntrack 再完成地址还原。
代价:配套 SNAT 后,内网服务器的访问日志中看到的客户端 IP 全部变成网关 IP
10.1.0.1,丢失了真实客户端 IP 信息。如果需要保留真实 IP,应优先调整内网服务器的默认网关指向 NAT 网关。
6. REDIRECT——本机端口映射
将访问本机某个端口的流量重定向到另一个端口:
1 | # 本机 80 端口 → 重定向到 8080 端口 |
典型场景:应用运行在 8080 端口,但希望用户通过 80 端口访问(非 root 用户无法直接监听 1024 以下端口)。
REDIRECT 也支持端口范围,例如 --to-ports 8080-8090,内核会在这个范围内轮询分配端口。
REDIRECT 只能在 PREROUTING 或 OUTPUT 链中使用,且仅限本机端口映射,不能跨主机。
NAT 解决了地址转换问题,但经过网关转发的流量如何做安全管控?这就需要 FORWARD 链。
7. 网络防火墙:FORWARD 链
7.1 角色区分
iptables 的两种防火墙角色:
| 角色 | 工作链 | 场景 |
|---|---|---|
| 主机防火墙 | INPUT / OUTPUT | 保护本机 |
| 网络防火墙 | FORWARD | 保护本机背后的网络 |
Linux 主机充当路由器/网关时,转发流量不经过 INPUT/OUTPUT 链,只经过 FORWARD 链。
%%{init: {'theme': 'base', 'themeVariables': { 'primaryColor': '#3B82F6', 'primaryTextColor': '#1E3A5F', 'primaryBorderColor': '#2563EB', 'lineColor': '#60A5FA', 'secondaryColor': '#10B981', 'tertiaryColor': '#F59E0B'}}}%%
flowchart LR
A["外网主机"] --> B["网关 FORWARD 链"]
B --> C["内网服务器"]
C --> B
B --> A
classDef primary fill:#3B82F6,stroke:#2563EB,color:#fff
classDef warning fill:#F59E0B,stroke:#D97706,color:#fff
classDef success fill:#10B981,stroke:#059669,color:#fff
class A primary
class B warning
class C success7.2 配置网络防火墙
前提:开启 IP 转发。
1 | # 临时开启 |
白名单策略配置(推荐):
1 | # 默认拒绝所有转发 |
-m conntrack --ctstate是-m state --state的新版语法,功能相同但更推荐。旧版本内核若不支持 conntrack,可回退到 state。
7.3 State 模块简化双向规则
FORWARD 规则的常见困扰是 “ 双向性 “——放行请求后,还要放行响应:
1 | # 不用 state 模块:每个服务都需要请求+响应两条规则 |
理解了各个组件的原理,接下来把它们组合起来,看一个完整的企业网关配置。
8. 综合实战:企业级网关配置
8.1 网络拓扑
1 | ┌─────────────┐ ┌──────────────────────┐ ┌──────────────┐ |
目标:① 内网上网(SNAT) ② 外网访问内网 Web(DNAT) ③ FORWARD 链安全过滤
8.2 完整配置脚本
1 |
|
8.3 规则持久化
iptables 规则存储在内存中,系统重启后会丢失。持久化方式:
1 | # 导出当前规则到文件 |
在 Debian/Ubuntu 上可安装 iptables-persistent 包实现开机自动加载:
1 | apt install iptables-persistent |
在 CentOS/RHEL 上使用 iptables-services:
1 | yum install iptables-services |
9. NAT 命令速查
1 | # ========== SNAT ========== |
下一篇:现代运维中的 iptables —— nftables 迁移指南、Docker/K8s 中的 iptables、生产最佳实践与常见故障排查。