蒋胜凡广博天下客 2019-11-17
每一条iptables
配置的规则(rule
)都包含了匹配条件(match
)部分和动作(target
)。当报文途径HOOK
点时,Netfilter
会逐个遍历挂在该钩子点上的表的rule
,若报文满足rule
的匹配条件,内核就会执行动作(target
)。
上面是一条普通iptables
规则,如果报文匹配前面的条件,就会执行最后的-j DROP
,它就是这条规则的动作(target
)
动作又可分为普通target和扩展target两类,其中普通动作是指ACCEPT
(允许报文通过)、DROP
(拒绝报文通过)这类简单明了的行为,而扩展target
是指包含了其他操作的动作,比如REJECT
动作会产生ICMP
差错信息、LOG
动作记录日志、SNAT
和DNAT
用于进行地址转换。
本文不涉及 How to
配置这些动作的规则,也不涉及这些动作各自的作用是什么,对此有兴趣的读者可以参考链接
Netfilter
使用xt_standard_target
表示一个动作:
该结构由两部分组成,其中verdict
是动作的编码, 取值有NF_DROP
、NF_ACCEPT
、NF_QUEUE
等等。对于普通动作来说,有verdict
就够了,但对于扩展动作来说,还需要有地方存储额外的信息(eg. 如何进行NAT
),这里的target
就是存储这些额外信息的地方。与本系列上一篇中说的xt_entry_match
一样,xt_entry_target
结构同样是一个union
。它们的设计思路是一样的:内核代码和iptables
用户态代码定义这样一个同样的数据类型,用户态使用的是user
部分,设置要使用的扩展动作的name
(普通动作的name
为""),内核收到该结构后,根据name
查询到注册过的动作,将该信息挂到xt_entry_target
的target
指针上。而data
字段表示的柔性数组区域就是各种扩展模块各显神通的地方了,对NAT
来说,这里存储转换后的地址。
我们需要将target
预先注册到Netfilter
框架中,才能在之后的配置中使用这个target
。就拿本文最初的那条规则来说,需要一个隐含的前提就是SNAT
这个xt_target
事先被注册到Netfilter
框架了。这部分工作在xt_nat.c
定义的内核模块中完成:
除了SNAT
, 通过xt_register_target
接口,其他各个模块都可以注册自己的动作。根据名字进行区分,所有的target
会挂到xf
链表上。
每个target
上有三个函数指针,其中
target
:这个函数将决定skb
的后续处理结果,如果为NULL
,那么这条规则的动作就是普通target
,处理结果从外面的verdict
就可以得出。如果不为NULL
,那么就执行这个函数,这个函数返回NF_DROP
, NF_ACCEPT
, NF_STOLEN
这类动作checkentry
:这个函数在用户配置规则时被调用,如果返回0,表示配置失败。destroy
:这个函数再使用该target
的规则被删除时调用。当用户通过iptables
下发一条规则时,Netfilter
会从xf
链表上查找是否已有这样的target
当数据包经过HOOK
点,如果某条rule
的匹配条件与报文一致,就会执行该rule
包含的动作。