linux 内核 hook函数介绍

在编写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_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 );

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值