Netfilter 挂钩注册到网络子系统

Netfilter hook registration with networking sub system

在探索 netfilter 功能时,我尝试编写一个简单的 netfilter 模块并注册了一个钩子,如下所示:

    dhcp_nfho.owner             = THIS_MODULE;
    dhcp_nfho.hook              = dhcp_hook_function;
    dhcp_nfho.hooknum           = NF_INET_POST_ROUTING;
    dhcp_nfho.priority          = NF_IP_PRI_FIRST;
    dhcp_nfho.pf            = PF_INET; // not on bridge interface
    nf_register_hook(&dhcp_nfho);

我在LXR页面查看了nf_register_hook的代码:(3.13版本)

int nf_register_hook(struct nf_hook_ops *reg)
 69 {
 70         struct nf_hook_ops *elem;
 71         int err;
 72 
 73         err = mutex_lock_interruptible(&nf_hook_mutex);
 74         if (err < 0)
 75                 return err;
 76         list_for_each_entry(elem, &nf_hooks[reg->pf][reg->hooknum], list) {
 77                 if (reg->priority < elem->priority)
 78                         break;
 79         }
 80         list_add_rcu(&reg->list, elem->list.prev);
 81         mutex_unlock(&nf_hook_mutex);
 82 #if defined(CONFIG_JUMP_LABEL)
 83         static_key_slow_inc(&nf_hooks_needed[reg->pf][reg->hooknum]);
 84 #endif
 85         return 0;
 86 }

这个二维链表是什么nf_hooks[PF][hooknum]。看起来每个协议系列都有一个 PRE/INPUT/FORWARD/OUTPUT/POST 钩子列表?

netfilter 子系统如何使用这个二维数组?

netfilter 子系统代码是否与网络驱动程序代码交互? (因为挂钩是在 Soft-irq 中处理的,网络驱动程序也使用 soft-irq 来处理数据包)?

我在哪里可以找到驱动程序接收数据包后调用 Netfilter Hooks 的代码?

你是对的。对于每个协议族,确实有一个钩子列表,实际上是由 PF 自己设置的(例如 NFPROTO_BRIDGE 有一个 BROUTE 钩子列表,但是 IPv4 和 IPv6 都没有)。

当数据包进入逻辑网络接口(以太网桥、以太网接口等)时,它将在堆栈中传递。如果它是一个 IPv4 数据包,它最终会调用 ip_rcv() 。这将在继续进行正确的数据包路由之前调用 NF_INET_PRE_ROUTING 挂钩。同样,ip_output 在实际发送数据包之前调用 NF_INET_POST_ROUTING 挂钩。

将 Netfilter 挂钩放入主要网络代码中允许网络接口驱动程序本身对整个过程一无所知。

要更好地了解这一切的流程,请查看 http://lxr.free-electrons.com/source/net/ipv4/ip_input.c and http://lxr.free-electrons.com/source/net/ipv4/ip_output.c。你会看到 NF_HOOK 和 NF_HOOK_COND 宏在数据包转换到不同层等时被调用