linux 内核 hook函数介绍

匿名 (未验证) 提交于 2019-12-02 21:56:30

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

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

其中的成员信息为:

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

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

 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

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

 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_ops  int	 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 ); 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!