深入理解 netfilter 和 iptables!( 二 )


深入理解 netfilter 和 iptables!

文章插图
netfilter-hooks-stack
NF_INET_PRE_ROUTING: 这个 hook 在 IPv4 协议栈的 ip_rcv 函数或 IPv6 协议栈的 ipv6_rcv 函数中执行 。所有接收数据包到达的第一个 hook 触发点(实际上新版本 Linux 增加了 INGRESS hook 作为最早触发点),在进行路由判断之前执行 。
NF_INET_LOCAL_IN: 这个 hook 在 IPv4 协议栈的 ip_local_deliver 函数或 IPv6 协议栈的 ip6_input 函数中执行 。经过路由判断后,所有目标地址是本机的接收数据包到达此 hook 触发点 。
NF_INET_FORWARD: 这个 hook 在 IPv4 协议栈的 ip_forward 函数或 IPv6 协议栈的 ip6_forward 函数中执行 。经过路由判断后,所有目标地址不是本机的接收数据包到达此 hook 触发点 。
NF_INET_LOCAL_OUT: 这个 hook 在 IPv4 协议栈的 __ip_local_out 函数或 IPv6 协议栈的 __ip6_local_out 函数中执行 。所有本机产生的准备发出的数据包,在进入网络栈后首先到达此 hook 触发点 。
NF_INET_POST_ROUTING: 这个 hook 在 IPv4 协议栈的 ip_output 函数或 IPv6 协议栈的 ip6_finish_output2 函数中执行 。本机产生的准备发出的数据包或者转发的数据包,在经过路由判断之后,将到达此 hook 触发点 。
NF_HOOK 宏和 netfilter 向量
所有的触发点位置统一调用 NF_HOOK 这个宏来触发 hook:
static inline int NF_HOOK(uint8_t pf, unsigned int hook, struct sk_buff *skb, struct net_device * in, struct net_device *out, int (*okfn)(struct sk_buff *)) { returnNF_HOOK_THRESH(pf, hook, skb, in, out, okfn, INT_MIN); }
NF-HOOK 接收的参数如下:
pf: 数据包的协议族,对 IPv4 来说是 NFPROTO_IPV4。
hook: 上图中所示的 netfilter hook 枚举对象,如 NF_INET_PRE_ROUTING 或 NF_INET_LOCAL_OUT 。
skb: SKB 对象,表示正在被处理的数据包 。
in: 数据包的输入网络设备 。
out: 数据包的输出网络设备 。
okfn: 一个指向函数的指针,该函数将在该 hook 即将终止时调用,通常传入数据包处理路径上的下一个处理函数 。
NF-HOOK 的返回值是以下具有特定含义的 netfilter 向量之一:
NF_ACCEPT: 在处理路径上正常继续(实际上是在 NF-HOOK 中最后执行传入的 okfn ) 。
NF_DROP: 丢弃数据包,终止处理 。
NF_STOLEN: 数据包已转交,终止处理 。
NF_QUEUE: 将数据包入队后供其他处理 。
NF_REPEAT: 重新调用当前 hook 。
回归到源码,IPv4 内核网络栈会在以下代码模块中调用 NF_HOOK :
深入理解 netfilter 和 iptables!

文章插图
NF_HOOK
实际调用方式以 `net/ipv4/ip_forward.c`[1] 对数据包进行转发的源码为例,在 ip_forward 函数结尾部分的第 115 行以 NF_INET_FORWARDhook 作为入参调用了 NF_HOOK 宏,并将网络栈接下来的处理函数 ip_forward_finish 作为 okfn 参数传入 :
int ip_forward(struct sk_buff *skb) { .....(省略部分代码) if(rt-rt_flagsRTCF_DOREDIRECT!opt-srr!skb_sec_path(skb)) ip_rt_send_redirect(skb); skb-priority = rt_tos2priority(iph-tos); returnNF_HOOK(NFPROTO_IPV4, NF_INET_FORWARD, skb, skb-dev, rt-dst.dev, ip_forward_finish); .....(省略部分代码) }
回调函数与优先级
netfilter 的另一组成部分是 hook 的回调函数 。内核网络栈既使用 hook 来代表特定触发位置,也使用 hook (的整数值)作为数据索引来访问触发点对应的回调函数 。
内核的其他模块可以通过 netfilter 提供的 api 向指定的 hook 注册回调函数,同一 hook 可以注册多个回调函数,通过注册时指定的 priority参数可指定回调函数在执行时的优先级 。
注册 hook 的回调函数时,首先需要定义一个 nf_hook_ops 结构(或由多个该结构组成的数组),其定义如下:


以上关于本文的内容,仅作参考!温馨提示:如遇专业性较强的问题(如:疾病、健康、理财等),还请咨询专业人士给予相关指导!

「辽宁龙网」www.liaoninglong.com小编还为您精选了以下内容,希望对您有所帮助: