Netfilter与FreeBSD的网络包过滤

在Linux中,使用Netflter来进行包过滤,所有的逻辑都要挂接在Netfilter的某个或者某些HOOK点上,并且实现成该HOOK点上的一个或者多个hook函数,这在Netfilter框架中是用nf_hook_ops结构体来表示的,整个Netfilter的框架如下图所示:

Netfilter与FreeBSD的网络包过滤

上图中有一部分被称为“过滤”模块,这在Netfilter中是通过filter表来实现的,filter表被划分为一条条的rule,被挂在FORWARD/INPUT/OUTPUT这三个HOOK点上,其nf_hook_ops结构体是:

static struct nf_hook_ops ipt_ops[] __read_mostly = {
    {
        .hook        = ipt_local_in_hook,
        .owner        = THIS_MODULE,
        .pf        = NFPROTO_IPV4,
        .hooknum    = NF_INET_LOCAL_IN,
        .priority    = NF_IP_PRI_FILTER,
    },
    {
        .hook        = ipt_hook,
        .owner        = THIS_MODULE,
        .pf        = NFPROTO_IPV4,
        .hooknum    = NF_INET_FORWARD,
        .priority    = NF_IP_PRI_FILTER,
    },
    {
        .hook        = ipt_local_out_hook,
        .owner        = THIS_MODULE,
        .pf        = NFPROTO_IPV4,
        .hooknum    = NF_INET_LOCAL_OUT,
        .priority    = NF_IP_PRI_FILTER,
    },
};

其hook函数内部调用ipt_do_table来实现rule的遍历匹配。

        前面几篇文章提到了FreeBSD的Netgraph,它相比Netfilter更加独立,因为它除了一个_p回调函数和标准协议栈相关之外,并不和协议栈有任何联系。事实上,你将会发现,在FreeBSD的包过滤模块中,Netgraph仅仅扮演了Netfilter的类似nf_hook_ops的概念,而不是Netfilter本身,那么FreeBSD中谁来扮演Netfilter呢?答案是:没有!你会发现,FreeBSD的协议栈都是通过单一的回调函数来被扩展的,包括包过滤也不例外的。回调函数可以最大限度的解除和标准协议栈的耦合。不像Netfilter,是Netfilter本身决定了各个hook函数按照什么顺序被调用,而Netfilter本身何时被调用是标准协议栈来决定的。从下图展示的FreeBSD的协议栈扩展框架可见一斑。

Netfilter与FreeBSD的网络包过滤

可以看出,Netgraph可以直接挂在标准协议栈上,还可以被挂在另外的扩展模块上,非常灵活(故而上图中部分连接线使用更加柔和的曲线来画出)。在代码实现上,FreeBSD几乎和Netfilter没有任何区别,我们看一下ip_input函数:

void ip_input(struct mbuf *m)
{
    ...
    if (!PFIL_HOOKED(&V_inet_pfil_hook))
        goto passin;
    odst = ip->ip_dst;
    if (pfil_run_hooks(&V_inet_pfil_hook, &m, ifp, PFIL_IN, NULL) != 0)
        return;
    if (m == NULL)                  /* consumed by filter */
        return;
    ...
}

pfil_run_hooks在这里接管了一切,其作用很类似Netfilter的NF_HOOK。差别仅仅在于由于Netfilter是内嵌进标准协议栈的,因此只要被Netfilter砍断的函数都主动的分为了两个阶段:XXX以及XXX_finish,而FreeBSD并没有这样。FreeBSD的pfil也有Netfilter的nf_hook_ops的对应概念:

struct packet_filter_hook {
    TAILQ_ENTRY(packet_filter_hook) pfil_link;
    int     (*pfil_func)(void *, struct mbuf **, struct ifnet *, int,
            struct inpcb *);
    void    *pfil_arg;
};

所谓的pfil_run_hooks函数其实就是遍历一个链表并调用每一个节点上的回调函数,该类链表在FreeBSD的协议栈中有好几个,非常类似于Netfilter的HOOK点的概念,不同的链表hook执行不是按照事先定义好优先级的方式进行的。

        说到这,可能有点晕了,ipfw,ipf,netgraph的关系到底是什么啊!实际上它们之间可以任意组合,这些模块之间以及它们和标准协议栈之间可以进行任意你喜欢的组合方式,协议栈只是在“某些固定”的地方设置了一些hook,不同于Netfilter,这些hook并没有规定你必须做什么和必须不能做什么,并且这些hook点之间是互相独立的,你可以直接使用netgraph,也可以将一张graph挂在一个filter上。正是这种灵活性使得FreeBSD成为了网络定制的首选。

原文链接: https://blog.csdn.net/dog250/article/details/7434756

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍;

也有高质量的技术群,里面有嵌入式、搜广推等BAT大佬

    Netfilter与FreeBSD的网络包过滤

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/409151

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年4月26日 上午11:14
下一篇 2023年4月26日 上午11:14

相关推荐