|
Linux 防火墙在内核中的实现
|
|
来源: 作者:赵蔚 发布时间:2007-05-22
|
|
struct nf_hook_ops { struct list_head list; nf_hookfn *hook; int pf; int hooknum; int priority; };
我们看到,“鱼钩”的本质,是一个 nf_hookfn 函数。这个函数将对被钓上来的 IP packet 进行初步的处理。那么,这些“鱼钩”是由谁来放置到 nf_hooks[][] 数组里面的呢?答案是,各个 table。熟悉 iptables 管理工具的读者朋友们应该了解,一个 table 就是一组类似的防火墙 rules 的集合。iptables 里面默认定义了三个 table:filter,mangle,和 nat。举 filter table 为例,它是在 linux-2.4.19/net/ipv4/netfilter/iptable_filter.c 中实现的一个 kernel module。在这个 module 的初始化过程中,它会调用 nf_register_hook() 向 netfilter 的核心代码注册一组“鱼钩”。这个注册过程,实际上,也就是把“鱼钩”放到“垂钓点”的过程。“垂钓点”的具体位置,由 nf_hooks[][] 数组的下标具体说明。
ipt_do_table()
我们具体看到 linux-2.4.19/net/ipv4/netfilter/iptable_filter.c 也就是 filter table 的实现代码,就发现 filter table 中的“鱼钩”上的 nf_hookfn 函数,主要是在调用 ipt_do_table() 函数。这是一个定义在 linux-2.4.19/net/ipv4/netfilter/ip_tables.c 中的函数。前面提到过,一个 table 就是一组防火墙 rules 的集合。显然,ipt_do_table() 函数将要做的事情,就是按照 table 中存储的一条又一条的 rules 来处理被“钓”上来的 IP packet。
table 里面存放了这个 table 中所有的防火墙 rules。但是并不是所有的 rules 都要拿过来,按照它审查一下这个 packet。事实上,这个 packet 是从哪个“鱼钩”上被钓上来的,就只有和那个“鱼钩”相关的 rules 才被拿过来,用来审查这个 packet。这个机制,就为每个 table 实现了多个 chain,而每个 chain 上又有多个 rules。而且,我们立刻看到,一个 chain 是和 IPv4 协议栈上的一个“垂钓点”相对应的。熟悉 iptables 用户空间管理工具的使用的读者朋友们应该立刻就会注意到这一点了。
在 linux-2.4.19/include/linux/netfilter_ipv4/ip_tables.h 中定义了 table 中的 rule 的存放格式,如下:
/* This structure defines each of the firewall rules. Consists of 3 parts which are 1) general IP header stuff 2) match specific stuff 3) the target to perform if the rule matches */ struct ipt_entry { struct ipt_ip ip; /* Mark with fields that we care about. */ unsigned int nfcache; /* Size of ipt_entry + matches */ u_int16_t target_offset; /* Size of ipt_entry + matches + target */ u_int16_t next_offset; /* Back pointer */ unsigned int comefrom; /* Packet and byte counters. */ struct ipt_counters counters; /* The matches (if any), then the target. */ unsigned char elems[0]; };
一个 entry 就是一个 rule。一个 entry 主要由两部分组成。一部分,是一系列的 matches;另一部分,是一个 target。这若干个 match 所要回答的问题,是相关的 packet 和本条 rule 是否匹配。而这个 target 所要回答的问题,是一旦 packet 匹配上以后,该拿这个 packet 怎么办?也就是要由 target 来决定这个匹配的 packet 今后的命运了。开头的 struct ipt_ip 的定义如下:
struct ipt_ip { /* Source and destination IP addr */ struct in_addr src, dst; /* Mask for src and dest IP addr */ struct in_addr smsk, dmsk; char iniface[IFNAMSIZ], outiface[IFNAMSIZ]; unsigned char iniface_mask[IFNAMSIZ], outiface_mask[IFNAMSIZ]; /* Protocol, 0 = ANY */ u_int16_t proto; /* Flags word */ u_int8_t flags; /* Inverse flags */ u_int8_t invflags; };
我们立刻可以看出来,在 struct ipt_ip 里面记录了关于这个 rule 所要匹配(match)的 packet 的一些特征。
match 和 target
netfilter 核心部分提供了一个分析、处置 packet 的架构,但是核心部分代码并不具体的去分析、处置 packet。这个具体的分析、处置的任务被交给其它的 module 来完成。核心部分代码可以根据 table 中记录的 rules 信息,来把 packet 交给能够处理相应的 rules 的 module 代码。那么,核心代码如何了解哪一个 module 可以处理哪一类的 rules 的呢?这要由各个相应的 modules 起动的时候,主动去向核心代码注册,ipt_register_target() 或者是 ipt_register_match()。这个注册过程,主要就是通知核心代码,本 module 有一个 target() 函数,可以决定 packet 的命运;或者是,本 module 有一个 match() 函数,可以判定一个 packet 是否符合 rules 的匹配要求。
这就提示我们,如果要写自己的防火墙模块,镶嵌在 netfilter 的架构中的话,我们主要要做的任务,就是向 netfilter 核心注册 ipt_register_target() 或者 ipt_register_match()。
iptables 管理工具
最后,要说明的是 iptables,这个位于用户空间的管理工具。前面我们看到了,netfilter 在内核空间的代码根据 table 中的 rules,完成对 packet 的分析和处置。但是这些 table 中的具体的防火墙 rules,还是必须由系统管理员亲自编写。kernel 中的 netfilter 只是提供了一个机制,它并不知道该怎样利用这个机制,写出合适的 rules,来实现一个网络防火墙。那么,系统管理员编写的 rules,怎样进入位于 kernel 空间中的 netfilter 维护的 table 中去呢?
这个任务是由 iptables 这个工具来完成的。它经过 getsockopt() 以及 setsockopt() 两个系统调用,进入 kernel 空间。这两个调用是 BSD Socket 接口的一部分。这里面的问题是 IPv4 在接到关于某个 sock 的不认识的 opt 的时候,应该怎么处理?netfilter 要求它在 linux-2.4.19/net/ipv4/ip_sockglue.c 文件中处理 getsockopt() 和 setsockopt() 系统调用的 ip_sockopt() 函数中适当的地方调用 nf_sockopt()。这样,用户空间就可以和 netfilter 核心部分进行交流,可以维护 table 中的防火墙 rules 了。
共3页: 上一页 [1] 2 [3] 下一页
|
| |
|
|
如果您对本文有任何疑问或者建议,请到论坛讨论区发表您的意见: >> 论坛入口 |
[ 收藏]
[ 推荐]
[ 评论(0条)]
[返回顶部] [打印本页]
[关闭窗口] |
|
|
|