编写netfilter模块 第三部分 Netfilter核心

第三部分

Netfilter核心

10 Netfilter钩子函数

网络代码中有若干调用是涉及到Netfilter的,并且所有的东西都和它绑定(也就是模块被加载)到netfilter框架中。最普遍的钩子组成部分是xtables(防火墙)、连接跟踪、IPv4的NAT引擎和IPVS的虚拟服务器。Ip6_input.c里面就调用了这个特定的钩子函数:

return NF_HOOK(NFPROTO_IPV6, NF_INET_PRE_ROUTING, skb,
dev, NULL, ip6_rcv_finish);

这里调用了所有的prerouting的钩子。NF_HOOK是一个大的宏,最后它将进入实际的函数nf_hook_slow,我将这些留给特殊的开发者,让你们自己重新编写查看这部分。(不用紧张,这里只是训练你。)

10.1 框架结构体

在struct nf_hook_ops中为每个钩子包含有vtable(虚函数表?)和元数据,例如名字和关联的协议。这个结构体的定义可以通过包含来获取。钩子是针对每个协议的;一个结构体只能注册一种协议,所以你需要注册多个钩子,那么就需要一个数组的nf_hook_ops实现。

struct nf_hook_ops {
unsigned int pf;
unsigned int priority;
unsigned int hooknum;
unsigned int (*hookfn)(unsigned int hooknum, struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *));
struct module *owner;
} 

10.2 初始化

结构体成员pf关系到这个钩子属于哪一个函数回调组。可能的值都列在netfilter.h中,最常见的值是NFPROTO_IPV6、NFPROTO_IPV4、NFPROTO_ARP和 NFPROTO_BRIDGE。在net/ipv4/目录中,你只能找到NFPROTO_IPV4,在net/ipv6/中,只能找到NFPROTO_IPV6。

成员priority则标示了这个钩子函数的调用顺序。一些标志性的静态变量定义在可以当做是偏移的基址,例如,语句NF_IP6_PRI_FILTER+1让这个钩子函数在跑完filter表后进行处理。这个值更多的取决于模块的作者根据期望的效果。

       因为有Xtables模块,这个注册结构体一定不能使const的,因为对应的区域可能会随着实现被修改。

static struct nf_hook_ops myhook_ops __read_mostly = {
.pf = PF_INET6,
.priority = 1,
.hooknum = NF_INET_LOCAL_OUT,
.hookfn = myhook_fn,
};
static int __init myhook_init(void)
{
return nf_register_hook(&myhook_ops);
}
static void __exit myhook_exit(void)
{
nf_unregister_hook(&myhook_ops);
}
module_init(myhook_init);
module_exit(myhook_exit);

这个钩子框架自己本身也不关注hooknum。一个钩子调用指定了一个特定的hooknum,hook模块可能会根据它来做一些事情。它通常是用于标示这个调用是从哪个位置来的:在前面(5.3节)提到Xtables、NAT和连接跟踪有五个静态变量,NF_INET_{PRE,POST}_ROUTING、NF_INET_LOCAL_{IN,OUT}和NF_INET_LOCAL_OUT。

 10.3 主要函数

static unsigned int myhook_fn(unsigned int hooknum, struct sk_buff *skb,
const struct net_device *in, const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
pr_info("Arr matey! - Captain Hook approves your packet!\n");
return NF_ACCEPT;
}

一个钩子函数的可能的返回值和target的返回值非常相似。不过没有XT_RETURN,因为没有可以跳转的链我们可以返回,所以这个返回值在这里是没有意义的。同样也没有XT_CONTINUE,在最好的情况下等于NF_ACCEPT,意味着这个钩子函数允许这个包通过。

其他值都意味这个包被消化了,在头文件linux/netfilter.h中定义。(所以所有的NF_*静态变量都可以被使用,参考5.4节)

       有很多的返回值定义都不是普遍被使用,更多的是被netfilter内部使用,例如

NF_QUEUE,被xt_NFQUEUE使用,用于将包中继到用户空间处理。

NF_STOLEN,相对于NF_DROP将数据包丢弃并且释放掉skb,NF_STOLEN只是表示这个钩子函数接管了这个skb数据包,netfilter只需要丢弃。Netfilter忘记了这个数据包,并不意味这这个数据包丢失了—这个钩子函数可能将会重新发送或者延长发送。

NF_REPEAT,这个数据包将会重新执行这个钩子函数。连接跟踪使用这个返回值用于简化代码路径。

NF_STOP,在功能上和NF_ACCEPT相同。

你可能感兴趣的:(源码分析)