原文地址:http://blog.chinaunix.net/uid-22227409-id-2656911.html
Linux-Netfilter机制学习(一)
基于Linux2.6.30内核源代码
钩子函数的注册管理
主要说明Netfilter钩子函数的挂载点,hook函数的保存机制,注册方式;
1) hook的存储机制
钩子函数由一个全局二维链表数组nf_hooks保存
struct list_head nf_hooks[NFPROTO_NUMPROTO][NF_MAX_HOOKS] __read_mostly;
首先按照其协议族进行归类存储(第一维代表的意义),主要协议族包括IPV4、IPV6等协议在内;在每个协议族中,根据钩子点顺序排列,Linux系统定义的最大挂载钩子函数的地点为8个,实际常用的为5各,分别是NF_IP_PRE_ROUTING, NF_IP_LOCAL_IN, NF_IP_FORWARD, NF_IP_LOCAL_OUT, NF_IP_POST_ROUTING;在每个钩子点内保存的则是按照钩子函数优先级保存的钩子节点结构nf_hook_ops,在nf_hook_ops中实际存放了钩子函数的内容。
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;
};
在相应的钩子点调用钩子函数时,则根据协议族和钩子点找到相应的链表入口,然后依次调用该链中的每一个钩子函数对数据包进行操作
2) hook的管理机制
内核在启动的时候通过netfilter_init函数完成钩子函数的初始化工作;如果需要在相应的钩子点挂载钩子函数,则需要首先定义一个nf_hook_ops结构,在其中实现所需的钩子函数,再调用nf_register_hook将该钩子函数注册到上述的全局二维链表中。
下面先来看一下netfilter_init初始化函数:
void __init netfilter_init(void)
{
int i, h;
/*首先完成全局二维链表的初始化工作*/
for (i = 0; i < ARRAY_SIZE(nf_hooks); i++) {
for (h = 0; h < NF_MAX_HOOKS; h++)
INIT_LIST_HEAD(&nf_hooks[i][h]);
}
#ifdef CONFIG_PROC_FS
/*在proc文件系统内注册相应的文件选项*/
proc_net_netfilter = proc_mkdir("netfilter", init_net.proc_net);
if (!proc_net_netfilter)