一 概述
中篇已经提到了钩子函数的注册,也知道最终数据进来是通过钩子函数处理,来实现防火墙的功能的。那么netfilter 内核是在什么时候调用钩子函数?钩子函数又是怎么实现防火墙对应的功能的?(本章主要讲钩子函数实现的过滤功能)
二 调用钩子函数
中篇知道钩子函数最终会注册挂载到 struct net 结构体下的struct netns_nf nf 结构体中,但是钩子函数又是在什么时候调用的呢?
前篇在讲解五链表提到一张图,如下图
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190701204220238.png)
其实钩子函数就是在设置的这五个关卡上调用的,而每个关卡(hook)上,调用钩子函数都是调用了netfilter.h中的一个内联函数,NF_HOOK() 函数 或者NF_HOOK_COND()函数,这两函数唯一区别,就是调用NF_HOOK_COND的条件是:如果协议栈当前所处理的数据包skb中没有重新路由的标记,数据包才会进入Netfilter框架。即cond = 1 时进入钩子,否则直接调用okfn函数走协议栈去处理。
static inline int
NF_HOOK_COND(uint8_t pf, unsigned int hook, struct net *net, struct sock *sk,
struct sk_buff *skb, struct net_device *in, struct net_device *out,
int (*okfn)(struct net *, struct sock *, struct sk_buff *),
bool cond)
{
int ret;
if (!cond ||
((ret = nf_hook(pf, hook, net, sk, skb, in, out, okfn)) == 1))
ret = okfn(net, sk, skb);
return ret;
}
static inline int
NF_HOOK(uint8_t pf, unsigned int hook, struct net *net, struct sock *sk, struct sk_buff *skb,
struct net_device *in, struct net_device *out,
int (*okfn)(struct net *, struct sock *, struct sk_buff *))
{
int ret = nf_hook(pf, hook, net, sk, skb, in, out, okfn);
if (ret == 1)
ret = okfn(net, sk, skb);
return ret;
}
NF_HOOK各个参数的解释说明:
- pf:协议族名,Netfilter架构同样可以用于IP层之外,因此这个变量还可以有诸如PF_INET6,PF_DECnet等名字。
- hook:HOOK点的名字,这里指我们讨论的五条链
- net :钩子函数,全部规则都会挂载到struct net 这个结构体上
- sk :套接字结构体
- skb:协议栈的结构体
- in:数据包进来的设备,以struct net_device结构表示;
- out :数据包出去的设备,以struct net_device结构表示;
- okfn :是个函数指针
nf_hook函数
static inline int nf_hook(u_int8_t pf, unsigned int hook, struct net *net,
struct sock *sk, struct sk_buff *skb,
struct net_device *indev, struct net_device *outdev,
int (*okfn)(struct net *, struct sock *, struct sk_buff *))
{
struct nf_hook_entries *hook_head = NULL;
int ret = 1;
#ifdef HAVE_JUMP_LABEL
if (__builtin_constant_p(pf) &&
__builtin_constant_p(hook) &