57、IP过滤与防火墙:Iptables深度解析

IP过滤与防火墙:Iptables深度解析

1. 规则匹配与分支处理

在规则匹配过程中,若分支链中没有规则匹配,我们需要返回到分支点所在的链,并从离开的位置开始扫描该链中的下一条规则。若分支未设置,则从 simplebranch 字段检查下一步操作:
- 若该字段设置为 FW_SKIP ,则跳过链中的下一条过滤规则。
- 若值设置为 FW_SKIP+1 ,则在第764行从当前链分支,即停止扫描当前列表,要么分支,要么停止进一步扫描。
- 对于其他值,只需检查是否需要退出进一步扫描。在第766行,清除当前链中CPU槽的回指信息。

2. ip_rule_match() 函数

规则匹配在 ip_rule_match() 函数中完成。 ip_fwkernel 对象是包含所有待匹配规则的规则结构。宏 FWINV 是处理反向规则的一种巧妙方式,反向规则表示除匹配项之外的任何内容。 ip_fwkernel 对象的 fw_invflag 字段为每个反向规则实体设置了一位。 FWINV 同时进行反向和简单匹配,匹配结果传递给宏,并与实体的反向位进行异或运算。若实体的该位反向标志被设置,则匹配结果取反;否则保持不变。若任何规则不匹配,则返回。

匹配过程如下:
1. 从第295行开始匹配源和目标IP/网络ID。若掩码全为1,则精确匹配IP地址;否则比较网络ID。
2. 仅当匹配设置了通配符标志 IP_FW_F_WILDIF 时,在第313行对使用该数据包的接口名称进行通配匹配。若未设置该标志,则在第322行对接口名称进行精确匹配。
3. 若规则设置为处理分片( IP_FW_F_FRAG 标志设置),且数据包未分片,则在第339行返回。
4. 若规则设置为测试SYN数据包( IP_FW_F_TCPSYN 标志设置),则仅在数据包未分片时进行测试(第344行)。
5. 若规则设置为过滤高层协议( fw_proto 设置),则需要将端口与为TCP/UDP设置的端口范围进行检查。 port_match() 仅在数据包未分片时匹配端口,因为只有第一个分片包含协议头,其余部分仅包含数据。否则,将协议端口与 ip_fwkernel 对象的 fw_dpts fw_spts 字段指定的端口范围进行匹配。

3. Iptables概述

Iptables的设计考虑了ipchains的许多缺点,以下是其相对于ipchains的优势:
1. 独立于兼容框架 :当前Iptables的设计独立于任何兼容框架,无需向兼容性框架注册。
2. 更好的内存管理 :Iptables的内存管理比ipchains好得多。
3. 高效的规则遍历 :过滤规则的遍历方式比ipchains更高效。
4. 更好的缓存局部性 :每个CPU的过滤表具有更好的缓存局部性,因此内存访问更快,处理速度也更快。

4. Iptables钩子的注册

Iptables直接注册其默认钩子,无需向兼容框架注册。默认情况下,它为本地交付、本地生成的流量和转发流量注册三个钩子。 ipt_ops 数组列出了这些钩子。 ipt_hook() 是本地交付和本地生成的传出流量的通用钩子回调例程,转发钩子的回调例程是 ipt_local_out_hook() 。这些例程中用于过滤流量的通用例程是 ipt_do_table()

iptables 模块初始化时,通过调用 nf_register_hook() 注册这些钩子。与Iptables关联的每个表都使用 ipt_register_table() 向Iptables框架注册。 ipt_tables 是所有向Iptables注册的表的列表头,这意味着不同的模块可以向Iptables框架注册其表,使得与Iptables兼容的所有模块的过滤表管理更加集中和简单。 packet_filter 是用于遍历过滤规则的主表。

5. Iptables过滤规则和目标组织
5.1 struct ipt_table

该结构体是表的头,用于保存指向表的指针并为表提供标识。它向Iptables框架注册并链接到 ipt_tables 中。
| 字段 | 描述 |
| ---- | ---- |
| list | 将表与 ipt_tables 列表链接 |
| name | 表的名称 |
| table | 指向保存表和钩子条目完整信息的对象的指针,表在 ipt_register_table() 中构建 |
| valid_hooks | 保存与表支持的钩子对应的位 |
| lock | 读写自旋锁,过滤时持有读锁,修改时持有写锁 |
| private | 指向 ipt_table_info 对象的指针,保存钩子条目表的完整信息 |
| me | 指向表所属模块的指针,否则为NULL |

5.2 struct ipt_table_info

该结构体保存表的完整信息。表附加到对象末尾,并为每个CPU复制一份以提高缓存局部性。它还包含用于遍历过滤链和操作跳转的指针。
| 字段 | 描述 |
| ---- | ---- |
| size | 表的大小,每个CPU的表副本大小相同 |
| number | 表中ipt规则条目的总数 |
| initial_entries | 表初始化时的条目总数 |
| hook_entry | 表中每个钩子条目的偏移量,在 translate_table() 中调用 check_entry_size_and_hooks() 初始化 |
| underflow | 每个钩子包含标准目标的基本入口点,若所有规则扫描完未找到目标,则返回该基本钩子入口点获取标准目标 |
| entries | 每个CPU表的基地址,新表注册时,在该对象末尾分配钩子条目表的空间。对于SMP机器,分配的总空间是表大小乘以CPU数量 |

表的复制过程如下:

graph TD;
    A[开始复制] --> B[获取表基地址 newinfo->entries];
    B --> C[遍历每个CPU];
    C --> D[计算当前CPU的表基地址偏移量];
    D --> E[将表从 newinfo->entries 复制到当前CPU的位置];
    E --> F{是否还有CPU};
    F -- 是 --> C;
    F -- 否 --> G[结束复制];
5.3 struct ipt_entry

该结构体是规则链的入口点,包含一系列 ipt_entry_match 类型的匹配规则对象,位于 ipt_entry 对象的末尾。若找到与 ipt_entry 对象规则匹配的数据包,则遍历附加到 ipt_entry 末尾的特定过滤规则。最后, ipt_entry 对象整体(包括所有过滤规则)的末尾有一个目标。
| 字段 | 描述 |
| ---- | ---- |
| ipt_ip | 包含我们感兴趣的数据包的所有通用信息,如接口、协议、标志等,类似于ipchains的 ip_fw 对象,通过 outiface_mask/iniface_mask 字段对接口通配符检查有更好的控制 |
| nfcache | 用于跟踪连接和分片数据包的缓存标志 |
| target_offset | 规则链的目标对象 ipt_entry_target 相对于 ipt_entry 对象起始位置的偏移量,由于 ipt_entry 对象大小未知,需要该偏移量来定位目标 |
| next_offset | 相对于当前条目的下一个表条目的偏移量,下一个规则链位于该位置,因为 ipt_entry 的长度可变 |
| comefrom | 保存分支点所在链的回指信息 |
| counters | 用于记录过滤的字节数和数据包数量 |
| elems | 匹配条目的特定规则链的头,可通过该字段添加 ipt_entry_match 类型的过滤规则 |

5.4 struct ipt_entry_match

该对象包含特定协议匹配的信息,分为三个部分:
1. 用户部分 :包含匹配名称(如 TCP UDP ICMP )和匹配大小的长度,匹配大小是定义该匹配名称的对象的大小,用户添加特定协议规则时需要该信息。
2. 内核部分 :包含与用户部分相同的匹配大小和指向对象的指针。 ipt_match 包含指向处理规则匹配和检查新规则有效性的回调例程的指针。每个匹配名称对应的 ipt_match 对象应向Iptables框架注册, ipt_match 维护一个列表,每个注册的条目都会链接到该列表中。
3. 数据部分 :包含用户指定的待匹配规则,附加到 ipt_entry_match 对象的末尾。例如,对于TCP,数据应指向 ipt_tcp 类型的对象;对于UDP和ICMP,匹配对象分别是 ipt_udp ipt_icmp

5.5 struct ipt_tcp

该对象包含TCP特定过滤的实体匹配信息。
| 字段 | 描述 |
| ---- | ---- |
| spts | 要与TCP头中的源端口匹配的源端口范围 |
| dpts | 要与TCP头中的目的端口匹配的目的端口范围 |
| option | 检查TCP头中是否存在任何TCP选项(如SACK、时间戳等) |
| flg_mask & flg_cmp | 与TCP头中的标志相关 |
| invflags | 用于反转搜索模式,更多细节可查看 tcp_match() |

5.6 struct ipt_entry_target

该结构体与 ipt_entry_match 类似,唯一的区别是它包含匹配规则目标的所有特定信息。

5.7 struct ipt_standard_target

该结构体用作搜索规则的标准目标,用于跳转到不同的规则链或在搜索结束时使用。若 verdict 字段为 IPT_RETURN ,则需要从内置链返回到标准目标;若 verdict 字段为正非零数,则表示需要分支到新的链进行下一轮过滤链筛选。

6. Iptables过滤规则和目标的组织架构

Iptables的过滤规则和目标组织通过一系列精心设计的数据结构来实现,这些结构相互协作,确保数据包能够按照预定规则进行高效过滤。下面我们详细介绍这些结构及其在过滤过程中的作用。

6.1 整体组织架构概述

Iptables的过滤规则和目标组织主要由 ipt_table ipt_table_info ipt_entry ipt_entry_match ipt_tcp ipt_entry_target ipt_standard_target 等结构体组成。这些结构体相互关联,形成了一个层次分明的架构,用于管理和执行过滤规则。

graph LR;
    A[ipt_table] --> B[ipt_table_info];
    B --> C[ipt_entry];
    C --> D[ipt_entry_match];
    C --> E[ipt_entry_target];
    D --> F[ipt_tcp];
    E --> G[ipt_standard_target];
6.2 各结构体的详细作用
  • ipt_table :作为表的头,它为表提供标识并链接到 ipt_tables 列表中。通过 name 字段可以唯一标识一个表, table 指针指向保存表和钩子条目完整信息的对象, valid_hooks 字段记录了该表支持的钩子。
  • ipt_table_info :保存表的完整信息,包括表的大小、规则条目总数、钩子条目的偏移量等。为了提高缓存局部性,表会为每个CPU复制一份,通过 entries 字段指向每个CPU表的基地址。
  • ipt_entry :规则链的入口点,包含了数据包的通用信息和一系列匹配规则。 ipt_ip 字段存储了数据包的关键信息, target_offset next_offset 字段用于定位目标和下一个规则条目。
  • ipt_entry_match :包含特定协议匹配的信息,分为用户部分、内核部分和数据部分。用户部分指定匹配名称和大小,内核部分包含回调例程指针,数据部分存储用户指定的规则。
  • ipt_tcp :专门用于TCP特定过滤的结构体,包含源端口范围、目的端口范围、TCP选项检查和标志相关信息。
  • ipt_entry_target :与 ipt_entry_match 类似,但包含匹配规则目标的特定信息。
  • ipt_standard_target :用作搜索规则的标准目标,通过 verdict 字段决定是返回还是分支到新的规则链。
7. 使用Iptables过滤数据包

Iptables通过三个基本的过滤钩子(用于传入、传出和转发数据包)来实现数据包过滤,这些钩子的回调例程内部都会调用 ipt_do_table() 函数来执行过滤逻辑。下面我们详细介绍 ipt_do_table() 函数的工作流程。

7.1 ipt_do_table() 函数的工作流程

ipt_do_table() 函数的主要任务是通过所有可能的规则对数据包进行过滤,一旦找到匹配的条目,可能会进行更具体的协议级过滤,最终确定过滤规则的目标。具体步骤如下:
1. 获取锁并定位表基地址 :在开始过滤过程之前,先获取表的读锁。由于每个CPU都有一份表的副本,需要通过 cpu_number_map() 函数获取当前CPU的编号,并使用 TABLE_OFFSET 宏计算当前CPU表的基地址。
2. 确定钩子入口点和标准目标偏移 :从 ipt_table_info 对象的 hook_entry 字段获取钩子在表中的入口点偏移,从 underflow 字段获取标准目标的偏移,并记录标准目标条目。
3. 循环过滤数据包 :在一个循环中不断尝试找到匹配的数据包,直到得到最终的裁决。
- 第一轮筛选 :使用 ip_packet_match() 函数进行第一轮筛选,检查数据包的IP地址、网络ID、接口、分片和高层协议等信息。若不匹配,则通过 next_offset 字段检查下一个规则链。
- 特定协议过滤 :若第一轮筛选匹配,则使用 IPT_MATCH_ITERATE 宏遍历 ipt_entry 对象末尾的特定过滤规则,这些规则是 ipt_entry_match 类型的对象,包含特定协议的匹配规则。
- 确定目标 :若所有过滤规则都匹配,则调用 ipt_get_target() 函数确定匹配条目的目标。目标可能是特定目标或标准目标。
- 处理裁决 :根据目标的 verdict 字段进行相应处理。
- 若 verdict 为负值,可能是最终裁决或 IPT_RETURN 。若是最终裁决,则直接返回;若是 IPT_RETURN ,则通过回指信息跳转到标准目标。
- 若 verdict 为正非零值,则可能需要从当前链分支到不同的入口点或下一个条目。

graph TD;
    A[开始过滤] --> B[获取表读锁];
    B --> C[定位当前CPU表基地址];
    C --> D[确定钩子入口点和标准目标偏移];
    D --> E[开始循环];
    E --> F[第一轮筛选: ip_packet_match()];
    F -- 不匹配 --> G[检查下一个规则链];
    G --> E;
    F -- 匹配 --> H[特定协议过滤: IPT_MATCH_ITERATE];
    H -- 不匹配 --> G;
    H -- 匹配 --> I[确定目标: ipt_get_target()];
    I --> J{目标是否为标准目标};
    J -- 是 --> K{verdict 是否为负值};
    K -- 是 --> L{是否为最终裁决};
    L -- 是 --> M[返回最终裁决];
    L -- 否 --> N[跳转到标准目标];
    N --> E;
    K -- 否 --> O{verdict 是否为正非零值};
    O -- 是 --> P[分支到新入口点或下一个条目];
    P --> E;
    J -- 否 --> Q[处理特定目标];
    Q --> E;
7.2 注意事项
  • 最后一个链条目应该包含一个通配符匹配,以确保任何未匹配的数据包都能通过,避免陷入无限循环。
  • 在处理 IPT_RETURN 时,需要正确维护回指信息,以便能够正确跳转到标准目标。
8. 总结

Iptables作为一种强大的IP过滤和防火墙工具,通过精心设计的数据结构和高效的过滤逻辑,为网络安全提供了有力的保障。其独立于兼容框架的设计、良好的内存管理、高效的规则遍历和优秀的缓存局部性,使其在性能和可维护性方面都具有显著优势。

在实际应用中,我们可以根据具体需求配置不同的过滤规则和目标,通过合理使用 ipt_do_table() 函数和相关结构体,实现对网络数据包的精确控制。同时,了解Iptables的内部工作原理,有助于我们更好地理解和优化网络安全策略,确保网络的稳定和安全。

希望通过本文的介绍,你对Iptables的规则匹配、数据结构和过滤逻辑有了更深入的理解,能够在实际工作中更加灵活地运用Iptables来保护网络安全。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值