• Netfilter 是如何工作的(一):HOOK点


    摘自https://segmentfault.com/a/1190000019449845

    写在前面

    本系列不是介绍How to配置iptables的文章。因为网络上已经有很多这类型的教程了,其中一些还不错(比如链接).

    本系列也不是一般意义上的Netfilter源码分析文章。因为大段粘贴代码也会让人心生畏惧和厌烦!

    本系列文章的目标是,用尽量少的文字和图片讲明白How Netfilter work

    Netfilter 的基本概念

    Netfilter是一套融入在Linux内核网络协议栈中的报文处理(过滤或者修改)框架。它在内核中报文的关键流动路径上定义了5HOOK点(下图蓝色方框),各个协议(如IPv4IPv6ARP)可以在这些HOOK点安装钩子函数,报文流经此地,内核会按照优先级调用这些钩子函数,这些钩子函数最终会决定报文是被NF_ACCEPT(放行)还是NF_DROP(丢弃)。

    forward-model

    图中红色虚线表示内核最常见的报文流经的路径:本机接收、转发、本机发送。
    5HOOK点分别是:路由前、本地上送、转发、本地发送、路由后1

    链(chain) & 表(table)

    初次接触iptables的同学可能会被四表五链这个名字吓到,特别是这个名字真的很容易令人困惑! 而当你了解了Netfilter的实现细节后,才会发现:噢,原来就是HOOK点,HOOK点就是,因为有5HOOK点,所以有五链

    那么,为什么要叫呢?

    因为一个HOOK点可以上可以安装多个钩子, 内核用“链条”将这些钩子串起来!

    图片描述
    相比之下,四表(table)就没那么神秘了: 起过滤作用的filter表、起NAT作用的nat表,用于修改报文的mangle表,用于取消连接跟踪的raw表。

    Netfilter设计多个表的目的,一方面是方便分类管理,另一方面,更重要的是为了限定各个钩子(或者说用户规则)执行的顺序!

    PREROUTING这个HOOK点为例,用户使用iptables设置的NAT规则和mangle会分别挂到nat hookmangle hookNAT表的优先级天生比mangle表低,因此报文一定会先执行mangle表的规则。

    图片描述

    这就是 四表五链 的概念。我个人认为的比重要多了. 因为就算Netfilter没有表的概念,那么通过小心翼翼地设置各个rule的顺序其实也可以达到相同的效果。但(也就是HOOK点)的作用是独一无二的。换个角度,用户在配置iptables规则时,更多的精力也是放在"应该在哪个HOOK点进行操作",至于用的是filter表、nat表还是其他表,其实都是顺理成章的事情。

    Hook

    HOOK 点的位置

    用户通过iptables配置的规则最终会记录在HOOK点。HOOK点定义在struct net结构中,即HOOK点是各个net namespace中独立的。所以,在使用容器的场景中,每个容器的防火墙规则是独立的。

    struct net {
        /* code omitted */
        struct netns_nf        nf;
        /* code omitted */
    }
    
    struct netns_nf {
        /* code omitted */
        struct list_head hooks[NFPROTO_NUMPROTO][NF_MAX_HOOKS];
    };

    从上面的定义可以看到,HOOK点是一个二维数组,每个元素都是一个链表头。它的第一个维度是协议类型,其中最常用的NFPROTO_IPV4,我们使用的iptables命令都是将这个钩子安装到这个协议的hook,而使用ip6tables就是将钩子安装到NFPROTO_IPV6hook;第二个维度是,对于IPV4来说,它的取值范围如下:

    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,
    }

    HOOK 点的元素

    hooks的每个元素都是链表头,链表上挂的元素类型是struct nf_hook_ops,这些元素有两个来源,一类来自于Netfilter初始化时各个表(如filter)的初始化,另一类来自于如连接跟踪这样的内部模块。下图展示了第一类来源的元素的挂接情况,它们按优先级排列(数字越小优先级越高),而.hook就是报文到达对应的路径时会执行的钩子函数。

    图片描述

    附:相关内核函数的例子

    iptable_filter_init 
      |--xt_hook_link
        |-- nf_register_hooks
           |-- nf_register_hook

    HOOK 点的调用

    Netfilter框架已经完全融入内核协议栈了,所以在协议栈代码中常常可以看到NF_HOOK宏的调用,这个宏的参数指定了HOOK点。

    以本机收到IPv4报文为例

    int ip_rcv(struct sk_buff* skb,...)
    {
       // code omitted
       return NF_HOOK(NFPROTO_IPV4, NF_INET_PRE_ROUTING, net, NULL, skb, dev, NULL, ip_rcv_finish); 
       // code omitted
    }

    它指定要遍历的钩子函数是net namespace为nethooks[NFPROTO_IPV4][NF_INET_PRE_ROUTING]链表上的元素,也就是上面图中的第一行的链表。如果三个钩子函数执行的结果(verdict)都是NF_ACCEPT,那么NF_HOOK指定的ip_rcv_finish就会被执行。

  • 相关阅读:
    Classview配置与访问
    MongoDB(NoSQL) 非关系型数据库
    服务器出现500错误的时候,让PHP显示错误信息
    Linux_目录介绍
    各类ip地址范围和私有地址范围
    Raid_磁盘冗余阵列
    Python_文件操作_读
    Git操作命令
    记录关于校园网登录不了腾讯的软件得问题解决
    关于科研方面分享的一些经验
  • 原文地址:https://www.cnblogs.com/LiuYanYGZ/p/12270062.html
Copyright © 2020-2023  润新知