本篇主要从三层协议栈调用函数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. 微信小程序手动实现select下拉框选择

    在小程序中没有像h5中的下拉 标签的 picker又满足部了,那就自己动手写 <view class='list-msg'> <view class='list-msg1'> ...

  2. bash shell脚本之使用expr运算

    bash shell中的数学运算 cat test7: #!/bin/bash # An example of using the expr command var1= var2= var3=`exp ...

  3. 9.Spring整合Hibernate_2_声明式的事务管理(Xml的方式)

    使用xml的方式进行声明式的事务管理 推荐使用xml的方式,因为可以同时为多个方法进行声明 <!-- 开启Spring中的事务管理(声明式的事务管理) xml--> <!-- 不管是 ...

  4. 修正Calendar的Bug

    procedure TAndroidNativeCalendarListener.onSelectedDayChange(view: JCalendarView; year, month, dayOf ...

  5. JavaMaven【八、pom.xml】

    简介: 重点学习: 1.dependency-scope 依赖范围 compile 编译 默认,对编译.测试.运行都有效 provided 编译和测试时有效 runtime 测试和运行时有效 test ...

  6. web开发:Bootstrap应用及内存管理

    一.栅格系统 二.移动端适配 三.栅格系统案例 四.表格 五.表单 六.循环应用 一.栅格系统 <!DOCTYPE html> <html> <head> < ...

  7. 2.03_Python网络爬虫Http和Https

    一:HTTP和HTTPS HTTP协议(HyperText Transfer Protocol,超文本传输协议):是一种发布和接收 HTML页面的方法,以明文的形式传输,效率高,但是不安全 HTTPS ...

  8. linux——常用命令

    学习linux命令地址: 学习命令地址,可参考http://linux.51yip.com/ 在文件中搜索指定字符串 grep -i "requirepass" redis.con ...

  9. shell 入门及常用命令

    1.shell 是什么 shell是指一种程序, 它是和linux沟通的桥梁, 这个应用程序提供了一个界面,用户通过这个界面访问操作系统内核的服务, Ken Thompson 的 sh 是第一种 Un ...

  10. 关于Java的Object.clone()方法与对象的深浅拷贝

    文章同步更新在个人博客:关于Java的Object.clone()方法与对象的深浅拷贝 引言 在某些场景中,我们需要获取到一个对象的拷贝用于某些处理.这时候就可以用到Java中的Object.clon ...