Linux 内核源码分析---netfilter 框架

iptables是用户用来管理和配置防火墙规则的一种策略,但是实际解析规则并按照规则实施产生作用的是Netfilter。

iptables 与协议栈内有包过滤功能的 hook 交互来完成工作,这些内核 hook 构成了 netfilter 框架。每个进入网络系统的包(接收和发送)在经过协议栈的时候都会触发这些 hook,程序可以通过注册 hook 函数的方式在一些关键路径上处理网络流量。iptables相关的内核模块在这些hook注册了处理函数,因此可以通过iptables规则来使得网络流量符合防火墙规则。

Netfilter 是 Linux 内核中的一个框架,它为以定制处理器形式实施的各种网络相关操作提供了灵活性。Netfilter提供数据包过滤、网络地址翻译和端口翻译的各种选项。

netfilter 挂钩及挂载点

netfilter 子系统主要功能:
数据包选择(iptables);
数据包过滤;
网络地址转换(NAT);
数据包操纵;
连接跟踪;
网络统计信息。

netfilter提供了 5 个hook点,但要注意ipv6和ipv4中挂接点名称相同,数据包经过协议栈时会触发内核模块注册在这里的处理函数。触发哪个 hook 取决于包的方向(接收还是接收)、包的目的地址、以及包在上一个 hook 点是被丢弃还 accept 等等。

在这里插入图片描述

下面几个hook是内核协议栈已经定义好的:
在这里插入图片描述

从上图可以看出,路由判定是数据流向的关键点。

  • 第一个路由判定通过查找输入数据包 IP头部 的目的 IP地址 是否为本机的 IP地址,如果是本机的 IP地址,说明数据是发送给本机的。否则说明数据包是发送给其他主机,经过本机只是进行中转。
  • 第二个路由判定根据输出数据包 IP头部 的目的 IP地址 从路由表中查找对应的路由信息,然后根据路由信息获取下一跳主机(或网关)的 IP地址,然后进行数据传输。

数据包流向从图中可以看到,三个方向的数据包需要经过的钩子节点不完全相同:
发往本地:NF_INET_PRE_ROUTING–>NF_INET_LOCAL_IN
转发:NF_INET_PRE_ROUTING–>NF_INET_FORWARD–>NF_INET_POST_ROUTING
本地发出:NF_INET_LOCAL_OUT–>NF_INET_POST_ROUTING

  • NF_IP_PRE_ROUTING:只要数据包从设备(如网卡)那里进入到协议栈,就会触发该钩子。当我们需要修改数据包的 “Destination IP” 时,会使用到它,即钩子主要用于目标网络地址转换(DNAT,Destination NAT);
  • NF_IP_LOCAL_IN:接收到的包经过路由判断,如果目的是本机,将触发此hook;
  • NF_IP_FORWARD:接收到的包经过路由判断,如果目的是其他机器,将触发此hook;
  • NF_IP_LOCAL_OUT:本机产生的准备发送的包,在进入协议栈后立即触发此hook;
  • NF_IP_POST_ROUTING:本机产生的准备发送的包或者转发的包,在经过路由的判断之后,数据出协议栈之前无论这个数据是转发的,还是经过本机进程处理过的,都会触发该钩子。

触发调用某个挂载点上(链)的所有钩子函数,需要使用 NF_HOOK 宏来实现。当数据包在内核网络栈中传输时,会在某些地方调用NF_HOOK宏:
在这里插入图片描述

  • pf:协议簇,对于IPV4(NFPROTO IPV4);对于IPv6(NFPROTO IPV6);
  • hook:表示有5个挂接点之一;
  • skb:表示要处理的数据包的SKB对象;
  • indev:输入网络设备;
  • outdev:输出网络设备
  • okfn:函数指针,指向钩子回调方法执行完毕后将调用的方法,它接受一个参数SKB;

netfilter 回调函数返回值:
在这里插入图片描述

Netfilter 允许在同一个钩子处,注册多个回调函数。
因此向钩子注册回调函数必须明确优先级,以便按照明确的优先顺序触发回调函数。因为回调函数有多个,如果把这些回调函数串起来,就构成了一条链,我们将其称为回调链(Chained Callbacks)。这个设计影响了围绕 Netfilter 构建的上层应用基本都带有“链”的概念。

注册一个 hook 函数是围绕nf_hook_ops数据结构的一个非常简单的操作,nf_hook_ops数据结构的定义如下:
在这里插入图片描述
list :用于维护 Netfilter hook 的列表,并且不是用户在注册 hook 时需要关心的重点。
hook:是一个指向nf_hookfn类型的函数的指针,该函数是这个 hook 被调用时执行的函数。nf_hookfn 同样在 linux/netfilter.h 中定义。
pf:用于指定协议族。有效的协议族在linux/socket.h中列出,但对于IPv4我们希望使用协议族 PF_INET。
hooknum:用于指定安装的这个函数对应的具体的 hook 类型,其值为NF_IP_PRE_ROUTING等。
priority:用于指定在执行的顺序中,这个 hook 函数应当在被放在什么地方。对于IPv4,可用的值在linux/netfilter_ipv4.hnf_ip_hook_priorities 枚举中定义。

注册钩子函数Register the hooks

在这里插入图片描述
钩子的优先级,每个协议系列的所有有效标识符都在头文件中定义。

enum nf_ip_hook_priorities {
        NF_IP_PRI_FIRST = INT_MIN,
        NF_IP_PRI_CONNTRACK_DEFRAG = -400,
        NF_IP_PRI_RAW = -300,
        NF_IP_PRI_SELINUX_FIRST = -225,
        NF_IP_PRI_CONNTRACK = -200,
        NF_IP_PRI_MANGLE = -150,
        NF_IP_PRI_NAT_DST = -100,
        NF_IP_PRI_FILTER = 0,
        NF_IP_PRI_SECURITY = 50,
        NF_IP_PRI_NAT_SRC = 100,
        NF_IP_PRI_SELINUX_LAST = 225,
        NF_IP_PRI_CONNTRACK_CONFIRM = INT_MAX,
        NF_IP_PRI_LAST = INT_MAX,
};
enum {
        NFPROTO_UNSPEC =  0,
        NFPROTO_IPV4   =  2,
        NFPROTO_ARP    =  3,
        NFPROTO_BRIDGE =  7,
        NFPROTO_IPV6   = 10,
        NFPROTO_DECNET = 12,
        NFPROTO_NUMPROTO,
};

Netfilter报过滤技术:
基于接口进行过滤:使用相应的net_device数据结构的name这个成员,可以根据数据包的源接口和目的接口来选择是否丢弃它。如果想丢弃所有到达接口 eth0 的数据包,需要做的仅仅是将 in->name 的值与”eth0”做比较,如果名字匹配,那么hook函数简单的返回NF_DROP即可,数据包会被自动销毁。
基于地址进行过滤:基于数据包的源或目的IP地址进行过滤也同样可以实现, 获取一个数据包的IP头通过使用sk_buff数据结构中的网络层包头来完成。这个头位于一个联合中,可以通过sk_buff->nh.iph这样的方式来访问。如果数据包的源地址与我们设定的丢弃数据包的地址匹配,那么该数据包将被丢弃。
基于TCP端口进行过滤:获取一个 TCP 头的指针是一件简单的事情,而可以分配一个tcphdr数据结构(在linux/tcp.h中定义)的指针,并将它指向我们的数据包中 IP 头之后的数据。

深入高可用架构原理与实践
深入理解netfilter的核心原理与实现
走进Linux内核之Netfilter框架

  • 14
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

飞大圣

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值