欢迎光临散文网 会员登陆 & 注册

数据包如何游走于 Iptables 规则之间?

2023-08-17 15:11 作者:补给站Linux内核  | 我要投稿

在前文《Linux 路由三大件》中,我们提到了 iptables 可以修改数据包的特征从而影响其路由。这个功能无论是传统场景下的 防火墙,还是云原生场景下的 服务路由(k8s service)、网络策略(calico network policy) 等都有依赖。

虽然业界在积极地推进 ipvs、ebpf 等更新、更高效的技术落地,但是出于各种各样的原因(技术、成本、管理等),iptables 仍然有着非常广泛的使用 ,所以我们有必要了解 iptables 的方方面面。今天我们就来了解其中的重要一环:调试和追踪 iptables。更具体一点:一个数据包是怎么在 iptables 的各个 chain/table/rule 中游走的。

注:不了解 iptables 的同学可以先看看这篇 wiki https://wiki.archlinux.org/title/Iptables

trace

我们知道,iptables 的 rule 最后是一个 target,这个 target 可以设置为 TRACE。这样,匹配这个 rule 的包经过的所有 chain/table/rule 都会被记录下来。

这个 rule 本身只能被放在 raw 表里,可以存在于 PREROUTING 和 OUTPUT 两个 chain 中。其匹配规则和其他一般的 rule 没有什么差别。

实践

我们采用一个 docker 场景来进行实践,如下图:

亦即宿主机的 10000 端口映射给了容器的 80 端口。图中有两种测试场景,分别是:

  1. 本节点访问容器 IP

  2. 跨节点访问宿主机 IP

为了让分析更直观/简单,我们用 telnet 测试即可(curl 会产生很多后续 http 包,不够简洁)。

OK,开始我们的测试!

首先在宿主机上开启 iptables log

然后增加 trace 配置

查看结果可以用这个命令:cat /var/log/messages | grep "TRACE:"

本节点访问:telnet 172.19.0.9 80,结果:

跨节点访问:telnet 192.168.64.4 10000,结果:


【文章福利】小编推荐自己的Linux内核技术交流群:【749907784】整理了一些个人觉得比较好的学习书籍、视频资料共享在群文件里面,有需要的可以自行添加哦!!!(含视频教程、电子书、实战项目及代码)   



对比这张图

以及宿主机节点上具体的规则(删除了 docker0 相关)

*raw
:PREROUTING ACCEPT [312:33617]
:OUTPUT ACCEPT [335:24610]
-A PREROUTING -d 192.168.64.4/32 -p tcp -m tcp --dport 10000 -j TRACE
-A OUTPUT -d 172.19.0.0/16 -p tcp -m tcp --dport 80 -j TRACE
COMMIT

*nat
:PREROUTING ACCEPT [4:903]
:INPUT ACCEPT [4:903]
:OUTPUT ACCEPT [222:16027]
:POSTROUTING ACCEPT [224:16155]
:DOCKER - [0:0]
-A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER
-A OUTPUT ! -d 127.0.0.0/8 -m addrtype --dst-type LOCAL -j DOCKER
-A POSTROUTING -s 172.19.0.0/16 ! -o br-00ea7870520a -j MASQUERADE
-A POSTROUTING -s 172.19.0.9/32 -d 172.19.0.9/32 -p tcp -m tcp --dport 80 -j MASQUERADE
-A DOCKER -i br-00ea7870520a -j RETURN

分析内容可以知:

  1. 两个测试都是 TCP 三步握手的第一、三步的两个包,从包的 SEQ 字段可以验证,也可以用 iptables rule 的 pkts 字段的差异来进行验证

  1. 对于 TCP 链接,只有第一个包才会经过 nat,后续包属于 RELATED,ESTABLISHED,直接放过,不需要重新 nat

  2. 对于跨节点访问,第一个包首先来到 PREROUTING 链, 命中了 docker 添加的 DNAT 规则:nat:DOCKERrule 3),效果就是第三行到第四行 DST 从 192.168.64.4 变成了 172.19.0.9

DNAT 后走到了 Forward 链, DOCKER-USER 和 DOCKER-ISOLATION-STAGE-1 都 return 了。最后通过 filter:FORWARD:rule:8 来到 filter:DOCKER 上,accept 将包送到了 docker bridge: br-00ea7870520a 上,从而送进了容器 172.19.0.9。当然,第二个包依然属于 RELATED,ESTABLISHED,所以在 filter:FORWARD:rule:7 上直接 ACCEPT,不需要再走 filter:DOCKER 了。

补充

最后补充一下,对于较新的内核,iptables 是 nf_tables 而不是 iptables-legacy 的场景下:

用 nft monitor trace # xtables-monitor --trace 命令来观察结果(这个方式比 messages 更友好:每个包都有一个单独的 id,更直观),当然,trace 方式也有差别,此处不展开,感兴趣读者可以自行到参考链接中进行研究。

原文作者:九零后程序员




数据包如何游走于 Iptables 规则之间?的评论 (共 条)

分享到微博请遵守国家法律