一文吃透 iptables-nfqueue
文章目录
iptables
常用,iptables-nfqueue
少用。因需要深度理解 iptables-nfqueue
,所以顺手撸了一遍 iptables-nfqueue
的源代码。
iptables-nfqueue
,aka NFQUEUE,是将网络包发送到用户程序去做接收/丢弃决定的 iptables
特性。NFQUEUE 需要用户程序监听 NFQUEUE 队列,并对接收到的网络包响应对应的判决结果。
NFQUEUE 的使用
例子参考:使用 Go 对接 iptables NFQUEUE 的例子
使用的 iptables
规则如下:
|
|
--queue-num
指当前规则将对应的网络包放到 1 号队列--queue-bypass
指当没有用户程序监听当前队列时,默认放行网络包,而不是丢包
NFQUEUE 的使用注意事项
队列容量
NFQUEUE 是有容量限制的,默认是 1024;用户程序可以在监听队列的时候设置容量大小。如果队列满了,iptables
默认会丢包;在内核 3.6 之后,可以使用 --fail-open
选项将这默认丢包改为默认接收。
如何知道队列满了后发生丢包呢?
有两种方式:
- 每次丢包都会打印一条系统日志
cat /proc/net/netfilter/nfnetlink_queue
里有丢包统计
无法通过程序的方式实时感知到队列满了、或者丢包了。
复制到用户程序的网络包的大小
将网络包复制到用户程序的时候,对网络包的大小是有限制的,默认是 65531;用户程序可以在监听队列的时候设置复制网络包的最大值。
如果只需要根据 IP 和端口进行判决,则可以将这个限制设置为 40(三层和四层的头部总大小),避免不必要的网络包内容复制。
没有响应判决结果
如果没有对网络包响应其判决结果,则该网络包会永远阻塞在 iptables
,iptables
不会自动丢弃这样的网络包。
NFQUEUE 的工作机制
NFQUEUE 的工作机制可分上下两场:
- 上半场:
- 接收
-j NFQUEUE
发送过来的网络包 - 入队
- 通过
nfnetlink
将网络包发给用户程序
- 接收
- 下半场:
- 接收用户程序通过
nfnetlink
发送过来的判决结果 - 出队
- 处理判决结果
- 继续
iptables
后续的处理
- 接收用户程序通过
上半场的函数调用栈如下:
|
|
下半场的函数调用栈如下:
|
|
NFQUEUE 的源码分析
NFQUEU 的源代码分为 nf_queue
和 nfnetlink_queue
两部分。nf_queue
是 iptables
的一部分,nfnetlink_queue
是netfilter
的一个子模块。
nfnetlink_queue
nfnetlink_queue
是 nf_queue
跟用户程序之间的桥梁,是基于 nfnetlink
的专门用于 NFQUEUE 的通信机制;而 nfnetlink
是一套基于 netlink 的专门用于 netfilter
的通信机制。
nfnetlink_queue
初始化
|
|
用户程序绑定 NFQUEUE
内核的 nfnetlink_queue
已初始化完毕,当用户程序需要监听 NFQUEUE 队列,会执行哪些代码呢?
|
|
NFQUEUE 上半场
用户程序运行起来后,网络包是怎么从 iptables
到达用户程序的?
下面从 PREROUTING 链为 iptables
入口,到 iptables-nfqueue
,再到 nfnetlink_queue
发送 netlink
消息给用户程序。
|
|
NFQUEUE 下半场
用户程序响应回来的判决是怎么生效的呢?
由 nfnetlink_queue
初始化 知道,用户回复判决会调用函数 nfqnl_recv_verdict
,就接着该函数进行分析吧。
|
|
NFQUEUE 的统计信息
每个 NFQUEUE 的统计信息保存在 struct nfqnl_instance
中,并且每个一行地打印到 /proc/net/netfilter/nfnetlink_queue
中。
|
|
统计信息是如何打印到 /proc/net/netfilter/nfnetlink_queue
的?
|
|
纵观 NFQUEUE 的源代码,NFQUEUE 并没有直接提供 API 去获取丢包事件。
总结
NFQUEUE 因为需要将网络包发送给用户程序,所以它的性能并不高;但相比于堆叠 iptables 规则,NFQUEUE 的处理方式更加灵活。而对于 XDP
、xt_bpf
等拥有同等灵活性的新技术而言,NFQUEUE 的适用范围更广、能够适配很多老旧系统。
文章作者 Leon Hwang
上次更新 2021-12-09