Netfilter 是 Linux网络内核协议栈提供了报文过滤(防火墙)框架,HOOK机制是Netfilter的核心。
一、如何在协议栈中调用钩子函数
在协议栈中相应位置嵌入Netfilter的函数NF_HOOK,来拦截报文送到Netfilter中进行处理。
协议栈中的五条内置链
我们知道Linux网络内核内置了5条链PREROUTING、INPUT、FORWARD、OUTPUT、POSTROUTING, 其实就是在内核的五个位置嵌入了NF_HOOK函数,然后通过NF_HOOK
进入Netfilter框架处理。我们以PREROUTING为例,看下插入NF_HOOK的五个位置。
网卡驱动接收到报文,经过二层处理后,会调用net_receive_skb
传递给具体的协议处理函数, 对于IPv4来说,这里的协议处理函数指的就是ip_rcv
了。而我们PREROUTING链的NF_HOOK函数正是在ip_rcv
中嵌入的。
/*
* Main IP Receive routine.
* 主要功能:对IP头部合法性进行严格检查,然后把具体功能交给ip_rcv_finish。
*/
int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)
{
......
/* 进入Netfilter处理,处理完后如果报文还要继续往下传递,则进入ip_rcv_finish函数处理 */
return NF_HOOK(PF_INET, NF_INET_PRE_ROUTING, skb, dev, NULL,
ip_rcv_finish);
......
}
其他几条链的嵌入位置分别如下:
+ PREROUTING: ip_rcv
+ INPUT:ip_local_deliver
+ FORWARDip_forward
+ OUTPUT:raw_send_hdrinc
+ POSTROUTING:ip_mc_output
和ip_mc_output
二、NF_HOOK 钩子函数
(一)、nf_hook 钩子函数的存储
钩子函数存储在全局二维数组nf_hooks
中。
struct list_head nf_hooks[NFPROTO_NUMPROTO][NF_MAX_HOOKS] __read_mostly;
从nf_hooks的定义我们可以看出,该结构体每一个成员都是一个struct list_head
对象。
NFPROTO_NUMPROTO有一下取值
enum {
NFPROTO_UNSPEC = 0,
NFPROTO_IPV4 = 2,
NFPROTO_ARP = 3