极客油画

iptables 的“调试”本质上就是利用日志(LOG)规则来追踪数据包的命中路径。由于 iptables 本身没有单步调试器,最实用的方法就是在关键链上插入临时的 LOG 规则,像“埋点”一样观察数据包的去向。

一、核心调试手段:LOG 规则

LOG 规则是 iptables 调试的“瑞士军刀”,它不会阻断流量,只是将数据包信息打印到系统日志。

1. 基本用法

1
2
# 在 INPUT 链的首部插入日志规则
iptables -I INPUT -p tcp --dport 80 -j LOG --log-prefix "DEBUG-HTTP: " --log-level 4

关键参数解读:

  • -I INPUT:在 INPUT 链头部插入(确保最先命中,避免被后续规则拦截而无法记录)。
  • --log-prefix "DEBUG: ":日志前缀,方便在 /var/log/syslogjournalctl 中快速筛选。
  • --log-level 4:日志级别(4=warning,避免产生过多 debug 级别日志)。

2. 查看日志

添加规则后,触发流量(如访问网页),然后查看日志:

1
2
3
4
5
6
7
8
# 查看内核日志(通用)
tail -f /var/log/kern.log

# 使用 systemd 的系统
journalctl -f

# 筛选特定前缀
grep "DEBUG-HTTP" /var/log/syslog

日志会记录源/目标 IP、端口、协议等详细信息,帮你确认数据包是否到达了预期位置。

二、实战:追踪数据包路径的“三板斧”

一个高效的调试策略是在关键链的头部插入 LOG,还原数据包的生命周期。

场景:调试被拒绝的 SSH 连接

1
2
3
4
5
6
7
8
# 1. 在 INPUT 链头部打点
iptables -I INPUT -p tcp --dport 22 -j LOG --log-prefix "INPUT-SSH: "

# 2. 在 FORWARD 链头部打点(如果涉及转发)
iptables -I FORWARD -p tcp --dport 22 -j LOG --log-prefix "FORWARD-SSH: "

# 3. 查看规则当前生效顺序(确认 LOG 规则在顶部)
iptables -L INPUT -n --line-numbers

分析逻辑:

  1. 如果能看到 INPUT-SSH 日志,说明包到达了 INPUT 链。
  2. 如果没看到日志但连接被拒,说明包可能被更早的链(如 PREROUTING)或其他规则丢弃。
  3. 如果看到日志但连接失败,检查日志后的第一条规则(通常是 DROP/REJECT)。

三、进阶排查工具

1. 规则列表检查

1
2
3
4
5
6
7
8
# 显示规则编号(关键!用于精准删除)
iptables -L -n --line-numbers

# 显示详细规则(包括包/字节计数器)
iptables -L -v -n

# 查看 NAT 表(解决端口转发问题)
iptables -t nat -L -n -v

2. 包计数器分析

每条规则前的 pktsbytes 计数器是天然的性能分析器。

1
2
3
4
Chain INPUT (policy DROP 0 packets, 0 bytes)
num   pkts bytes target     prot opt in     out     source               destination
1        0     0 DROP       tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:22
2       10  1200 LOG        tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:22 LOG flags 0 level 4 prefix "DEBUG-SSH: "

解读:如果 DROP 规则的 pkts 为 0,但 LOG 规则的 pkts 在增长,说明 LOG 规则位置不对(在 DROP 之后),数据包先被丢弃了,根本走不到 LOG 规则。

3. 使用 TRACE 目标(高级)

对于更复杂的内核级调试,可以启用 TRACE(需内核支持):

1
2
modprobe ipt_LOG
iptables -t raw -I PREROUTING -p tcp --dport 80 -j TRACE

TRACE 会生成详细的内核日志,展示数据包经过的每一个钩子点,但日志量极大,仅建议在复杂网络问题中使用。

四、调试流程清单

  1. 明确问题:是“完全不通”还是“特定端口不通”?
  2. 插入 LOG:在怀疑的链(INPUT/OUTPUT/FORWARD)头部插入 LOG 规则。
  3. 触发流量:执行一次访问或 ping。
  4. 检查日志:查看 kern.logjournalctl
  5. 分析路径
    • 有日志:说明包到达了该链,检查后续规则。
    • 无日志:说明包在到达该链前已被丢弃,检查 PREROUTING 或物理链路。
  6. 清理现场:调试完成后务必删除临时规则。
    1
    2
    
    # 根据规则编号删除
    iptables -D INPUT 1
    

五、常见“坑”与解决

  • 日志太多刷屏:使用 --log-level 4 或限制源 IP(-s 192.168.1.100)。
  • 规则顺序错乱:iptables 规则是顺序执行的,第一条匹配的规则生效。使用 -I(插入)而非 -A(追加)来确保 LOG 规则在顶部。
  • 表选择错误:NAT 规则在 nat 表,过滤规则在 filter 表,确认你查看的是正确的表。

六、清理临时规则

调试结束后,务必清理临时规则,避免日志爆炸或规则混乱:

1
2
3
4
5
# 查看编号
iptables -L INPUT --line-numbers

# 精准删除(假设 LOG 规则是第 1 条)
iptables -D INPUT 1

对于复杂的防火墙配置,建议使用 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表的POSTROUTINGSNAT
2. 默认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 」,也可搜索「 极客油画 」找到我。


上一篇 « 下一篇 »

赞赏支持

请我吃鸡腿 =^_^=

i ysf

云闪付

i wechat

微信

推荐阅读

Big Image