netfilter/iptables (二) Netfilter hook 数据结构

一、Netfilter简介

       Netfilter是Linux 2.4.x引入的一个子系统,它作为一个通用的、抽象的框架,提供一整套的hook函数的管理机制,使得诸如数据包过滤、网络地址转换(NAT)和基于协议类型的连接跟踪成为了可能。Netfilter在内核中位置如下图所示:

      

       这幅图,很直观的反应了用户空间的iptables和内核空间的基于Netfilter的ip_tables模块之间的关系和其通讯方式,以及Netfilter在这其中所扮演的角色。

       Netfilter在netfilter_ipv4.h中将那五个关键点“12345”上来。重新命名,如下图所示。

      

对于收到的每个数据包,都是从 PRE_ROUTING 进来,经过路由判决,如果是发送给本机的数据包就经过 LOCAL_IN ,然后往协议栈的上层继续传递,否则,如果该数据包的目的地不是本机,那么就经过 FORWARD,然后顺着 POST_ROUTING 将该包转发出去;

对于发送的每个数据包,首先也有一个路由判决,以确定该包是从哪个接口出去,然后经过 LOCAL_OUT,最后也是顺着 POST_ROUTING 将该包发送出去。

Netfilter 的架构就是在整个网络流程的上面这些位置放置一些检测点(HOOK,或者说回调函数),而在每个检测点上登记(callback)了一些处理函数进行处理(如包过滤、NAT等,甚至可以是用户自定义的功能)。
这些hook点就是 netfilter hook,在这里,数据包可以被分析并且选择是保留还是放弃。

Netfilter 中定义了五个关于ipv4的hook类型(这里我们只讨论ipv4,对于ipv6也是可以对应的的 hook类型,这些符号声明在 linux/netfilter_ipv4.h中。
PS:大家需要知道的是,在高版本中,内核已经做出了修改,下面的ipv4符号均修改为NF_INET形式。所以大家编程的时候要把IP换为INET

  1. NF_IP_PRE_ROUTING
    刚刚通过数据链路层解包(从上一篇博文我们了解到netfilter是在网络层作用),进入网络层的数据包通过此点(刚刚进行完版本号,校验
    和等检测),目的地址转换在此点进行;
  2. NF_IP_LOCAL_IN
    经路由查找后,送往本机的通过此检查点,INPUT包过滤在此点进行;
  3. NF_IP_FORWARD
    目的地是其他主机的数据包,要转发的包通过此检测点,FORWARD包过滤在此点进行 ;
  4. NF_IP_LOCAL_OUT
    本机进程发出的包通过此检测点,OUTPUT包过滤在此点进行;
  5. NF_IP_POST_ROUTING
    所有马上便要通过网络设备出去的包通过此检测点,内置的源地址转换功能(包括地址伪装)在此点进行 ;

 二、钩子函数返回值

       在每个关键点上,有很多已经按照优先级预先注册了的回调函数(这些函数称为“钩子函数”)埋伏在这些关键点,形成了一条链。对于每个到来的数据包会依次被那些回调函数“调戏”一番再视情况是将其放行,丢弃还是怎么滴。但是无论如何,这些回调函数最后必须向Netfilter报告一下该数据包的死活情况,因为毕竟每个数据包都是Netfilter从人家协议栈那儿借调过来给兄弟们Happy的,别个再怎么滴也总得“活要见人,死要见尸”吧。每个钩子函数最后必须向Netfilter框架返回下列几个值其中之一:

NF_ACCEPT 继续正常传输数据报。这个返回值告诉Netfilter:到目前为止,该数据包还是被接受的并且该数据包应当被递交到网络协议栈的下一个阶段。

NF_DROP 丢弃该数据报,不再传输。

NF_STOLEN 模块接管该数据报,告诉Netfilter“忘掉”该数据报。该回调函数将从此开始对数据包的处理,并且Netfilter应当放弃对该数据包做任何的处理。但是,这并不意味着该数据包的资源已经被释放。这个数据包以及它独自的sk_buff数据结构仍然有效,只是回调函数从Netfilter 获取了该数据包的所有权。

NF_QUEUE 对该数据报进行排队(通常用于将数据报给用户空间的进程进行处理)

NF_REPEAT 再次调用该回调函数,应当谨慎使用这个值,以免造成死循环。

上面提到的五个关键点后面我们就叫它们为hook点,每个hook点所注册的那些回调函数都将其称为hook函数。

三、hook

       Linux 2.6版内核的Netfilter目前支持IPv4、IPv6以及DECnet等协议栈,这里我们主要研究IPv4协议。关于协议类型,hook点,hook函数,优先级,通过下面这个图给大家做个详细展示:

        \

        hook函数就保存在上面的二维数组中,通过协议类型和hook类型定位,并且每个hook函数具备对应的优先级, 

四、注册和注销Netfilter hook

          注册一个 hook 函数是围绕 nf_hook_ops 数据结构的一个非常简单的操作。
  linux/netfilter.h(linux4.1)

struct nf_hook_ops {
	struct list_head list;             //维护Netfilter hook的列表

	/* User fills in from here down. */
	nf_hookfn	*hook;             //该函数是这个hook被调用时执行的函数
	struct module	*owner;            //模块的所有者
	void		*priv;
	u_int8_t	pf;                //用于指定协议族
	unsigned int	hooknum;           //就是前面说到的五个值,钩子函数在哪个位置
	/* Hooks are ordered in ascending priority. */
	int		priority;          //钩子函数优先级
};
int nf_register_hook(struct nf_hook_ops *reg);   //注册
void nf_unregister_hook(struct nf_hook_ops *reg);//注销

转自:https://blog.csdn.net/wenqian1991/article/details/50364227

猜你喜欢

转载自blog.csdn.net/m0_37806112/article/details/82943664
今日推荐