本篇主要从三层协议栈调用函数NF_HOOK说起,不断深入,分析某个钩子点中所有钩子函数的调用流程,但是本文不包含规则介绍和核心的规则匹配流程,后续文章将继续分析;

NF_HOOK函数先调用了nf_hook继续执行调用钩子函数处理,处理之后,如果接受,则调用输入的回调函数okfn,继续数据包的下一步处理;

 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 == )
ret = okfn(net, sk, skb);
return ret;
}

NF_HOOK_COND增加了一个输入掉价cond,当不满足条件的时候,直接调用okfn,满足条件的时候,才会继续调用nf_hook进行后续的钩子函数调用流程,如果nf_hook返回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)) == ))
ret = okfn(net, sk, skb);
return ret;
}

nf_hook函数首先找到钩子点函数入口,如果有钩子函数,则进一步初始化nf_hook_state结构,然后调用nf_hook_slow进入钩子函数调用流程;

 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_entry *hook_head;
int ret = ; #ifdef HAVE_JUMP_LABEL
if (__builtin_constant_p(pf) &&
__builtin_constant_p(hook) &&
!static_key_false(&nf_hooks_needed[pf][hook]))
return ;
#endif rcu_read_lock();
/* 找到钩子点 */
hook_head = rcu_dereference(net->nf.hooks[pf][hook]);
if (hook_head) {
struct nf_hook_state state; /* 初始化nf_hook_state结构 */
nf_hook_state_init(&state, hook, pf, indev, outdev,
sk, net, okfn); /* 执行钩子函数 */
ret = nf_hook_slow(skb, &state, hook_head);
}
rcu_read_unlock(); return ret;
}

在分析nf_hook_slow之前,我们先看下该函数中涉及到的钩子函数执行结果的返回值字段的含义;

 /* Responses from hook functions. */
#define NF_DROP 0 /* 丢包,不再传输 */
#define NF_ACCEPT 1 /* 接受数据包,继续正常传输 */
#define NF_STOLEN 2 /* 数据包已经被接管,回调函数处理该包,NF不再处理 */
#define NF_QUEUE 3 /* 将数据包交给用户空间的进程处理 */
#define NF_REPEAT 4 /* 再次调用钩子函数 */
#define NF_STOP 5 /* Deprecated, for userspace nf_queue compatibility. */
#define NF_MAX_VERDICT NF_STOP

nf_hook_slow会遍历当前钩子点上的钩子函数,通过函数nf_hook_entry_hookfn调用钩子函数,并根据返回值判断如何进行下一步处理;

 int nf_hook_slow(struct sk_buff *skb, struct nf_hook_state *state,
struct nf_hook_entry *entry)
{
unsigned int verdict;
int ret; do {
/* 调用钩子函数 */
verdict = nf_hook_entry_hookfn(entry, skb, state);
switch (verdict & NF_VERDICT_MASK) {
case NF_ACCEPT:
/* 获取下一个钩子函数 */
entry = rcu_dereference(entry->next);
break;
case NF_DROP:
/* 丢包 */
kfree_skb(skb);
ret = NF_DROP_GETERR(verdict);
if (ret == )
ret = -EPERM;
return ret;
case NF_QUEUE:
/* 通过netfilter_queue交给应用层nf_queue处理 */
ret = nf_queue(skb, state, &entry, verdict);
if (ret == && entry)
continue;
return ret;
default:
/* Implicit handling for NF_STOLEN, as well as any other
* non conventional verdicts.
*/
return ;
} /* 继续执行下一个钩子函数 */
} while (entry); return ;
}

nf_hook_entry_hookfn函数调用当前钩子函数结构entry中的钩子函数hook,返回执行结果;

 static inline int
nf_hook_entry_hookfn(const struct nf_hook_entry *entry, struct sk_buff *skb,
struct nf_hook_state *state)
{
return entry->hook(entry->priv, skb, state);
}

我们暂且看一下filter表的钩子函数,可见,其核心流程为ipt_do_table,也就是进入filter表的规则匹配流程,ipt_do_table函数后续文章我们单独分析;

 static unsigned int
iptable_filter_hook(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state)
{
/* LOCAL_OUT && (数据长度不足ip头 || 实际ip头部长度不足最小ip头),在使用raw socket */
if (state->hook == NF_INET_LOCAL_OUT &&
(skb->len < sizeof(struct iphdr) ||
ip_hdrlen(skb) < sizeof(struct iphdr)))
/* root is playing with raw sockets. */
return NF_ACCEPT; /* 核心规则匹配流程 */
return ipt_do_table(skb, state, state->net->ipv4.iptable_filter);
}

Netfilter 之 钩子函数调用的更多相关文章

  1. netfilter的钩子——数据包在内核态得捕获、修改和转发

    转发:http://blog.csdn.net/stonesharp/article/details/27091391 数据包在内核态得捕获.修改和转发(基于 netfilter)    忙活了好几天 ...

  2. Linux Netfilter注册钩子点

    注册钩子点首先要包含响应的头文件,因为这应该已经属于对kernel的编程了. #include <linux/module.h> #include <linux/kernel.h&g ...

  3. Netfilter 之 钩子函数与钩子点关系图

    概述 通过钩子点和优先级的代码追溯,得到如下对应关系图,图中横坐标为钩子点,纵坐标为优先级,每个钩子点上的钩子函数按照优先级排布: 详细分析 5个钩子点如下所示,在这个五个钩子点上的钩子函数按照上面的 ...

  4. Netfilter 之 钩子函数注册

    通过注册流程代码的分析,能够明确钩子函数的注册流程,理解存储钩子函数的数据结构,如下图(点击图片可查看原图): 废话不多说,开始分析: nf_hook_ops是注册的钩子函数的核心结构,字段含义如下所 ...

  5. Netfilter的使用和实现

    本文主要内容:Netfilter的原理和实现浅析,以及示例模块. 内核版本:2.6.37 Author:zhangskd @ csdn blog 概述 Netfilter为多种网络协议(IPv4.IP ...

  6. Linux内核project导论——网络:Netfilter概览

    简单介绍 最早的内核包过滤机制是ipfwadm.后来是ipchains.再后来就是iptables/netfilter了. 再往后,也就是如今是nftables. 只是nftables与iptable ...

  7. Netfilter/iptables防火墙

    http://os.51cto.com/art/201107/273443.htm [51CTO独家特稿]Linux系统管理员们都接触过Netfilter/iptables,这是Linux系统自带的免 ...

  8. c#调用钩子

    1 概述 在c++中有钩子程序,但是在C#还没有对其进行封装,所以需要自己根据实际情况调用钩子.钩子在我的理解下是,通过初始化钩子与系统中消息映射建立某种关系,当点击鼠标或者键盘,就会通过钩子中的回调 ...

  9. Pytest权威教程19-编写钩子(Hooks)方法函数

    目录 编写钩子(Hooks)函数 钩子函数验证和执行 firstresult: 遇到第一个有效(非None)结果返回 hookwrapper:在其他钩子函数周围执行 钩子(Hooks)函数排序/调用示 ...

随机推荐

  1. SpringBoot-JPA入门

    SpringBoot-JPA入门 JPA就是Spring集成了hibernate感觉. 注解,方法仓库(顾名思义的方法,封装好了,还有自定义的方法). 案例: spring: datasource: ...

  2. 有趣的"=="与"==="

    console.log([]==![]);//true //"=="会进行类型转换,转换成统一类型进行比较 // !符号优于==,[]boolean值为TRUE,所以![]就是FA ...

  3. 捕捉Promise reject 错误

    var sleep = function (time) { return new Promise(function (resolve, reject) { setTimeout(function () ...

  4. pip install win32api报错解决方法

    在安装pywinauto模块,导入模块后,提示缺少:win32api 但是在使用pip install安装win32api后,居然报错 错误信息如下: Could not find a version ...

  5. VirtualBox虚拟CentOS7共享文件夹

    在VirtualBox的centos虚拟机光盘设置为安装增强工具包VBoxGuestAdditions.iso 进入centos, cd /media mkdir cdrom mount -t iso ...

  6. [Abp vNext微服务实践] - 租户登录

    简介 Abp vNext微服务授权验证基于ids4,实现租户登录需要在授权服务中获取token,和之前的介绍的登录方式一样,只是多了tenant参数.本篇将介绍在Abp vNext授权服务中启用多租户 ...

  7. C#信号量(Semaphore,SemaphoreSlim)

    Object->MarshalByRefObject->WaitHandle->Semaphore 1.作用: 多线程环境下,可以控制线程的并发数量来限制对资源的访问 2.举例: S ...

  8. Debian常见命令总结

    dpkg学习: (1)dpkg是一个较底层的安装工具,处理.deb文件,软件包依赖性需要更高层的前端工具是apt:    dpkg本身是不能解决依赖的.    dpkg是dpkg-deb的前端,如果d ...

  9. Java8-Stream-No.06

    import java.io.IOException; import java.math.BigDecimal; import java.util.Arrays; import java.util.s ...

  10. 区间第K小——可持久化线段树模板

    概念 可持久化线段树又叫主席树,之所以叫主席树是因为这东西是fotile主席创建出来的. 可持久化数据结构思想,就是保留整个操作的历史,即,对一个线段树进行操作之后,保留访问操作前的线段树的能力. 最 ...