iptables 的“调试”本质上就是利用日志(LOG)规则来追踪数据包的命中路径。由于 iptables 本身没有单步调试器,最实用的方法就是在关键链上插入临时的 LOG 规则,像“埋点”一样观察数据包的去向。
一、核心调试手段:LOG 规则
LOG 规则是 iptables 调试的“瑞士军刀”,它不会阻断流量,只是将数据包信息打印到系统日志。
1. 基本用法
关键参数解读:
-I INPUT:在 INPUT 链头部插入(确保最先命中,避免被后续规则拦截而无法记录)。--log-prefix "DEBUG: ":日志前缀,方便在/var/log/syslog或journalctl中快速筛选。--log-level 4:日志级别(4=warning,避免产生过多 debug 级别日志)。
2. 查看日志
添加规则后,触发流量(如访问网页),然后查看日志:
日志会记录源/目标 IP、端口、协议等详细信息,帮你确认数据包是否到达了预期位置。
二、实战:追踪数据包路径的“三板斧”
一个高效的调试策略是在关键链的头部插入 LOG,还原数据包的生命周期。
场景:调试被拒绝的 SSH 连接
分析逻辑:
- 如果能看到
INPUT-SSH日志,说明包到达了 INPUT 链。 - 如果没看到日志但连接被拒,说明包可能被更早的链(如 PREROUTING)或其他规则丢弃。
- 如果看到日志但连接失败,检查日志后的第一条规则(通常是 DROP/REJECT)。
三、进阶排查工具
1. 规则列表检查
2. 包计数器分析
每条规则前的 pkts 和 bytes 计数器是天然的性能分析器。
解读:如果 DROP 规则的 pkts 为 0,但 LOG 规则的 pkts 在增长,说明 LOG 规则位置不对(在 DROP 之后),数据包先被丢弃了,根本走不到 LOG 规则。
3. 使用 TRACE 目标(高级)
对于更复杂的内核级调试,可以启用 TRACE(需内核支持):
TRACE 会生成详细的内核日志,展示数据包经过的每一个钩子点,但日志量极大,仅建议在复杂网络问题中使用。
四、调试流程清单
- 明确问题:是“完全不通”还是“特定端口不通”?
- 插入 LOG:在怀疑的链(INPUT/OUTPUT/FORWARD)头部插入 LOG 规则。
- 触发流量:执行一次访问或 ping。
- 检查日志:查看
kern.log或journalctl。 - 分析路径:
- 有日志:说明包到达了该链,检查后续规则。
- 无日志:说明包在到达该链前已被丢弃,检查 PREROUTING 或物理链路。
- 清理现场:调试完成后务必删除临时规则。
五、常见“坑”与解决
- 日志太多刷屏:使用
--log-level 4或限制源 IP(-s 192.168.1.100)。 - 规则顺序错乱:iptables 规则是顺序执行的,第一条匹配的规则生效。使用
-I(插入)而非-A(追加)来确保 LOG 规则在顶部。 - 表选择错误:NAT 规则在
nat表,过滤规则在filter表,确认你查看的是正确的表。
六、清理临时规则
调试结束后,务必清理临时规则,避免日志爆炸或规则混乱:
对于复杂的防火墙配置,建议使用 iptables-save > backup.rules 进行备份,以便随时回滚。
七、容器brige模式的几个问题
容器网络命名空间隔离了“网络设备”和“端口号”,但默认没有隔离“iptables 规则视图”,这个时候把容器当作普通进程来处理更合理。
容器与容器的通信,本质上就本机进程与进程的通信,他们遵循宿主机两个进程通信时使用的同一套iptables规则。
一个容器ping另一个容器,它经过了哪些iptables表和链呢?
一个容器ping宿主机,它经过了哪些iptables表和链呢?
一个容器ping外网ip,它经过了哪些iptables表和链呢?
宿主机ping容器,它经过了哪些iptables表和链呢?
| 场景 | 源地址 → 目标地址 | 出站路径 | 入站路径 | 关键点说明 |
|---|---|---|---|---|
| 容器ping另一个容器 | 容器A → 容器B | 1. 容器A内部出站 - PREROUTING - OUTPUT 2. 通过docker0网桥转发 - FORWARD 3. 容器B内部入站 - PREROUTING - INPUT |
主要在FORWARD链处理转发 |
1. 同主机容器间通信走网桥转发 2. 经过 filter表的FORWARD链3. 如果配置了网络策略,可能被拦截 |
| 容器ping宿主机 | 容器 → 宿主机IP | 1. 容器内部出站 - PREROUTING - OUTPUT 2. 通过docker0到宿主机 - PREROUTING - INPUT |
宿主机INPUT链接收 |
1. 容器访问宿主机被视为外部访问 2. 需在宿主机 INPUT链允许3. 默认Docker允许(ACCEPT规则) |
| 容器ping外网 | 容器 → 外网IP | 1. 容器内部出站 - PREROUTING - OUTPUT 2. 宿主机NAT转换 - PREROUTING (nat) - POSTROUTING (nat) 3. 通过宿主机网卡出站 - FORWARD - OUTPUT 4. 返回路径反向处理 |
1. 源地址SNAT 2. 目的地址DNAT(如有) |
1. 必须经过nat表的POSTROUTING做SNAT2. 默认Docker已配置MASQUERADE 3. 返回流量经过 PREROUTING的DNAT |
| 宿主机ping容器 | 宿主机 → 容器IP | 1. 宿主机出站 - OUTPUT - POSTROUTING 2. 通过docker0到容器 - PREROUTING - INPUT |
容器内部INPUT链 |
1. 宿主机访问容器走本地路由 2. 通常不经过FORWARD链 3. 直接在宿主机OUTPUT链处理 |
网桥不是路由器,为何能转发呢?
- 网桥能转发,靠的是“认 MAC 地址”。它通过自学习建立一张“MAC-端口”映射表,然后像交通指挥一样,把数据帧精准地送到对应的端口。
- 在纯二层的容器间通信中(同一网桥下),数据包根本不经过 iptables 的 FORWARD链。它是直接通过网桥的 MAC 表转发的。iptables 是三层(IP层)的防火墙,管不到二层的帧交换。
- 网桥只能连接同一个 IP 子网(如 172.17.0.0/16)内的设备。如果你想让网桥连接不同网段,必须借助路由器(三层设备)进行路由。
既然网桥,数据包根本不经过 iptables 的 FORWARD链, 那为何禁用iptables的FORWARD链,容器之前无法ping通呢?
- 网桥把包转发出去了。
- 内核的 bridge-nf模块介入,检查 iptables FORWARD链。
- 发现策略是 DROP,于是内核在最后一刻把包丢弃了。
- 通过 sysctl -w net.bridge.bridge-nf-call-iptables=0关闭这个检查,即使 FORWARD 是 DROP,容器间也能通
本文发表于 0001-01-01,最后修改于 0001-01-01。
本站永久域名「 jiavvc.top 」,也可搜索「 极客油画 」找到我。

