企业🤖AI智能体构建引擎,智能编排和调试,一键部署,支持知识库和私有化部署方案 广告
[TOC] ### **简介** Netfilter是linux内核中的数据包过滤框架(也可以说它是内核的一个子系统)。它提供了一种钩子机制,可以让其他内核模块比如conntrack、nat等向它的钩子点注册回调函数。 简单来说:Netfilter是一个框架,不是模块,它提供钩子点;conntrack、nat是内核模块,实现具体的数据包过滤与管理功能。内核模块是可以卸载的,但框架只有在编译内核的时候选择编译或者不编译,不能够卸载。我们编译Linux内核时,如果选择了Netfilter子系统,那么这些钩子点就已经在Linux内核网络中。 ### **支持多种协议族** Netfilter是一种通用的数据包处理框架,所谓通用是指它支持多种协议族。在4.4的内核版本中, Netfilter支持的协议族如下: > include/uapi/linux/netfilter.h ``` enum { NFPROTO_UNSPEC = 0, NFPROTO_INET = 1, NFPROTO_IPV4 = 2, NFPROTO_ARP = 3, NFPROTO_NETDEV = 5, NFPROTO_BRIDGE = 7, NFPROTO_IPV6 = 10, NFPROTO_DECNET = 12, NFPROTO_NUMPROTO, }; ``` 我们可以通俗地理解为,Netfilter框架可以处理不同协议的包,比如IPv4、IPv6等。不过,上面的名字不一定表示协议的名字,比如BRIDGE就不是协议的名字,它表示Netfilter可以处理二层的数据帧。 ### **钩子点与钩子函数** Netfilter提供钩子点,其他内核模块可以向钩子点注册钩子函数。Netfilter定义一个全局二维数组,用来存储所有协议族的钩子点与钩子函数。在4.4的内核中,该数组的定义如下: > net/netfilter/core.c ``` struct static_key nf_hooks_needed[NFPROTO_NUMPROTO][NF_MAX_HOOKS]; ``` `NF_MAX_HOOKS`的值为8,说明有些协议族会有八个钩子点。 在iptables中,有五条链,它们的名字分别是`PREROUTING`、`POSTROUTING`、`INPUT`、`OUTPUT`、`FORWARD`。钩子点其实是没有名字的,比如`nf_hooks_needed[NFPROTO_IPV4][0]`就表示IPv4协议的第0个钩子点。不过,第0个钩子点的钩子函数是根据`PREROUTING`链中的规则对数据包进行处理的。所以为了把钩子点和链对应起来,内核中给`nf_hooks_needed[NFPROTO_IPV4][x]`中的第二个下标`x`命名了一系列常量,如下: > include/uapi/linux/netfilter_ipv4.h ``` /* only for userspace compatibility */ #ifndef __KERNEL__ ... /* IP Hooks */ /* After promisc drops, checksum checks. */ #define NF_IP_PRE_ROUTING 0 /* If the packet is destined for this box. */ #define NF_IP_LOCAL_IN 1 /* If the packet is destined for another interface. */ #define NF_IP_FORWARD 2 /* Packets coming from a local process. */ #define NF_IP_LOCAL_OUT 3 /* Packets about to hit the wire. */ #define NF_IP_POST_ROUTING 4 #define NF_IP_NUMHOOKS 5 ... #endif /* ! __KERNEL__ */ ``` 上面我们可以看出,对于IPv4协议,给钩子点的命名分别为`NF_IP_PRE_ROUTING`、`NF_IP_POST_ROUTING`等。 不过,从上面的注释可以看到,上面的钩子名的常量定义其实不是在内核空间的,是给用户空间所使用的。什么意思呢?就是说,如果用户要进行内核编程,那么用到的常量就是`NF_IP_PRE_ROUTING`。在内核中,使用到的钩子名的常量不是这样叫的。那是怎么的呢? 其实,在内核空间中,由于IPv4和IPv6的钩子点个数一样多,都是5个,所以内核对于这两个协议,统一了钩子点的常量定义,如下: > include/uapi/linux/netfilter.h ``` enum nf_inet_hooks { NF_INET_PRE_ROUTING, NF_INET_LOCAL_IN, NF_INET_FORWARD, NF_INET_LOCAL_OUT, NF_INET_POST_ROUTING, NF_INET_NUMHOOKS }; ``` 所以在我们后面的章节中,我们对钩子点的叫法分别为`NF_INET_xxxx`。 虽然,IPv4与IPv6协议的钩子点命名统一了,但是二者的钩子函数是不一样的。也就是说,IPv4的钩子点的函数是注册在`nf_hooks_needed[NFPROTO_IPV4][x]`中的,IPv6的钩子点的函数是注册在`nf_hooks_needed[NFPROTO_IPV6][x]`中的。而不是两种协议的钩子函数都注册在`nf_hooks_needed[NFPROTO_INET][x]`中。 conntrack、nat等模块可以向上面的五个钩子点注册钩子函数,对数据包进行处理。钩子函数的返回值如下: > include/uapi/linux/netfilter.h ``` /* Responses from hook functions. */ #define NF_DROP 0 #define NF_ACCEPT 1 #define NF_STOLEN 2 #define NF_QUEUE 3 #define NF_REPEAT 4 #define NF_STOP 5 #define NF_MAX_VERDICT NF_STOP ``` 上面返回值的含义可以参考[这里](http://www.hyuuhit.com/2018/07/15/netfilter/) ### **参考** * https://blog.csdn.net/jasonchen_gbd/article/details/44873089 * https://blog.csdn.net/wenqian1991/article/details/50365689 * http://www.hyuuhit.com/2018/07/15/netfilter/ * http://wiki.dreamrunner.org/public_html/Linux/Networks/netfilter.html