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来保护网络安全。
超级会员免费看
921

被折叠的 条评论
为什么被折叠?



