在编写linux内核中的网络模块时,用到了钩子函数也就是hook函数。现在来看看linux是如何实现hook函数的。

先介绍一个结构体:

struct nf_hook_ops,这个结构体是实现钩子函数必须要用到的结构体,所在文件:linux/netfilter.h 定义为:

typedef unsigned int nf_hookfn(unsigned int hooknum,struct sk_buff *skb,const struct net_device *in,const struct net_device *out,int (*okfn)(struct sk_buff *));struct nf_hook_ops {struct list_head list;/* User fills in from here down. */nf_hookfn *hook;struct module *owner;u_int8_t pf;unsigned int hooknum;/* Hooks are ordered in ascending priority. */int priority;
};

其中的成员信息为:

hook  :是一个函数指针,可以将自定义的函数赋值给它,来实现当有数据包到达是调用你自定义的函数。自定义函数的返回值为:

/* 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

owner:是模块的所有者,一般owner = THIS_MODULE ;

pf   :是protocol flags,其取值范围为:

enum {NFPROTO_UNSPEC =  0,NFPROTO_IPV4   =  2,NFPROTO_ARP    =  3,NFPROTO_BRIDGE =  7,NFPROTO_IPV6   = 10,NFPROTO_DECNET = 12,NFPROTO_NUMPROTO,
};

hooknum :中存放的是用户自定义的钩子函数的调用时机,其取值为:

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
};

其中的每个值的含义为:

priority : 为所定义的钩子函数的优先级,其取值为份两种:分别为IPV4 和 IPV6;

priority 的IPV4取值为:

enum nf_ip_hook_priorities {NF_IP_PRI_FIRST = INT_MIN,NF_IP_PRI_CONNTRACK_DEFRAG = -400,NF_IP_PRI_RAW = -300,NF_IP_PRI_SELINUX_FIRST = -225,NF_IP_PRI_CONNTRACK = -200,NF_IP_PRI_MANGLE = -150,NF_IP_PRI_NAT_DST = -100,NF_IP_PRI_FILTER = 0,NF_IP_PRI_SECURITY = 50,NF_IP_PRI_NAT_SRC = 100,NF_IP_PRI_SELINUX_LAST = 225,NF_IP_PRI_CONNTRACK_CONFIRM = INT_MAX,NF_IP_PRI_LAST = INT_MAX,
};

所在文件:linux\netfilter_ipv4.h

priority 的IPV6取值为:

enum nf_ip6_hook_priorities {NF_IP6_PRI_FIRST = INT_MIN,NF_IP6_PRI_CONNTRACK_DEFRAG = -400,NF_IP6_PRI_RAW = -300,NF_IP6_PRI_SELINUX_FIRST = -225,NF_IP6_PRI_CONNTRACK = -200,NF_IP6_PRI_MANGLE = -150,NF_IP6_PRI_NAT_DST = -100,NF_IP6_PRI_FILTER = 0,NF_IP6_PRI_SECURITY = 50,NF_IP6_PRI_NAT_SRC = 100,NF_IP6_PRI_SELINUX_LAST = 225,NF_IP6_PRI_LAST = INT_MAX,
};

以上是对struct nf_hook_ops结构体中的每个字段的详解;

具体实例

struct nf_hook_ops my_hook = {.hook   = myfunction,.owner    = THIS_MODULE,.pf          = NFPROTO_IPV4,.hooknum  = NET_INET_FORWARD,.priority = NF_IP4_PRI_FIRST
};unsigned int myfunction( unsigend int hooknum, struct sk_buff *skb,const struct net_device *in,const struct net_device *out,int (*okfn)(struct sk_buff *))
{}

如上面的代码一样,当定义一个struct nf_hook_ops结构体,并且对其完成了初始化以后,需要将这个结构体进行注册,之后这个结构体以及其中的自定义函数才会其作用。

注册一个struct nf_hook_ops需要用到的函数为:

int  nf_register_hook(struct nf_hook_ops *reg)

其实这个 int nf_register_hook()函数在内核中的实现也没有多么的复杂,

来看看它是如何实现的:

struct list_head nf_hooks[NFPROTO_NUMPROTO][NF_MAX_HOOKS] __read_mostly;
EXPORT_SYMBOL(nf_hooks);
static DEFINE_MUTEX(nf_hook_mutex);int nf_register_hook(struct nf_hook_ops *reg)
{struct nf_hook_ops *elem;int err;err = mutex_lock_interruptible(&nf_hook_mutex);if (err < 0)return err;list_for_each_entry(elem, &nf_hooks[reg->pf][reg->hooknum], list) {if (reg->priority < elem->priority)break;}list_add_rcu(&reg->list, elem->list.prev);mutex_unlock(&nf_hook_mutex);return 0;
}
EXPORT_SYMBOL(nf_register_hook);

所在文件:net\netfilter\core.c

当不再需要使用这个struct nf_hook_ops时,需要注销这个结构体,其可用的函数为:

void nf_unregister_hook(struct nf_hook_ops *reg)
{mutex_lock(&nf_hook_mutex);list_del_rcu(&reg->list);mutex_unlock(&nf_hook_mutex);synchronize_net();
}
EXPORT_SYMBOL(nf_unregister_hook);

当一次需要注册多个struct nf_hook_ops结构体,如:

struct nf_hook_ops myhooks[n]时,使用:

int nf_register_hooks(struct nf_hook_ops *reg, unsigned int n)
{unsigned int i;int err = 0;for (i = 0; i < n; i++) {err = nf_register_hook(&reg[i]);if (err)goto err;}return err;err:if (i > 0)nf_unregister_hooks(reg, i);return err;
}
EXPORT_SYMBOL(nf_register_hooks);

同样,当一次需要注销多个struct nf_hook_ops结构体是,使用:

void nf_unregister_hooks(struct nf_hook_ops *reg, unsigned int n)
{while (n-- > 0)nf_unregister_hook(&reg[n]);
}
EXPORT_SYMBOL(nf_unregister_hooks);

总结:

struct nf_hook_opsint     nf_register_hook( struct nf_hook_ops *reg );void nf_unregister_hook( struct nf_hook_ops *reg );int  nf_register_hooks( struct nf_hook_ops *regs, unsigend int n );void nf_unregister_hooks( struct nf_hook_ops *regs, unsigned int n );

linux 内核 hook函数介绍相关推荐

  1. Linux内核Hook系统调用execve

    资源下载地址:linux内核hook系统调用execve函数-Linux文档类资源-CSDN下载 (已在内核为 4.19.0-amd64-desktop版本uos编译通过,并成功达到目的) 在Linu ...

  2. Linux内核scatterlist API介绍 DMA SG搬移

    Linux内核scatterlist API介绍 1. 前言 我们在那些需要和用户空间交互大量数据的子系统(例如MMC[1].Video.Audio等)中,经常看到scatterlist的影子.对我们 ...

  3. Linux进程调用execve,linux内核系统调用函数do_execve()解析实例源码

    linux内核系统调用函数do_execve()解析,彻底解析内核调用用户空间代码入口函数do_execve() sys_execve() –> do_execve() /usr/src/lin ...

  4. Linux内核系统架构介绍

    28年前(1991年8月26日)Linus公开Linux的代码,开启了一个伟大的时代.这篇文章从进程调度,内存管理,设备驱动,文件系统,网络等方面讲解Linux内核系统架构.Linux的系统架构是一个 ...

  5. linux 内核 空指针,Linux 内核IS_ERR函数

    本文介绍Linux 4.4内核IS_ERR()函数. 文件:include/linux/err.h,定义如下: #define MAX_ERRNO 4095 ## 对于64位系统,判断x是否在0xff ...

  6. linux内核hook技术之指令覆盖与注入

    前言 说到hook,传统意义上,大家都会觉得跟注入和劫持挂钩.在linux内核中,也可以通过指令覆盖和注入的方式进行hook,来完成自己的业务逻辑,实现自己的功能需求. 一部分人喜欢称这种hook技术 ...

  7. linux内核current宏介绍

    1.概述 本文主要介绍linux current宏在arm和arm64上的实现 内核版本:Linux 5.3 2.current在arm和arm64上的实现 在linux 内核中,有一个current ...

  8. linux内核时间函数us,Linux上系统时间函数、DST等相关有关问题总结

    http://www.reader8.cn/jiaocheng/20120910/1995886.html 2012 Linux下系统时间函数.DST等相关问题总结1. 内核中时间的基本类型:在Lin ...

  9. linux内核常用函数或宏

    1. simple_strtoul 用于将字符串转换为无符号长整数,第3个参数10意味着转换方式是10进制. ival = simple_strtoul(buffer, NULL, 10); 2. 大 ...

最新文章

  1. 洛谷 P3182 [HAOI2016]放棋子(错排问题)
  2. java main 方法不能执行,AndroidStudio无法执行Java的main函数
  3. xampp中apache不能启动解决方法 (share)
  4. 互联网支付系统概要设计
  5. log4j2.xml 文件
  6. python调用c函数传字符串参数_Python使用ctypes模块调用DLL函数之传递数值、指针与字符串参数...
  7. 1997年投稿,2021年发表!收到录用信那一刻,我即将退休……
  8. 华为已经没落的一个手机系列 无人问津甚至有点多余
  9. Jmeter如何将上一个请求的结果作为下一个请求的参数——使用正则表达式提取器转载...
  10. Git教程——查看修改日志 (log diff)
  11. “带锁的门”问题,并有c语言和python代码运行效率对比
  12. LintCode_408 二进制求和
  13. Python计算贝塔系数和夏普比率
  14. 上传图片 可限制大小和文件类型
  15. 台式计算机报废如何进行处置,设备报废处置请示.doc
  16. StringUtil方法全集
  17. Sigil制作epub,正则表达式的使用
  18. @Validated和@Valid校验参数、级联属性、List
  19. Adobe application manager丢失或损坏解决方法
  20. CUMT2021一道SSRF

热门文章

  1. KVM 虚拟化架构和实现原理
  2. MDK 工程宏定义的应用
  3. MySQL主从库--同步异常
  4. React-Native 之 GD (二)自定义共用导航栏样式
  5. 39[dropbox etc]
  6. 网站的高性能架构---存储性能优化
  7. 多线程导出大规模excel文件
  8. 【OpenCV学习】内存分配讨论两例
  9. 拖拽使用 .bat 批处理
  10. 关于nginx rewrtie的四种flag