📄 netfilter:linux 防火墙在内核中的实现.htm
字号:
<P>我们看到,“鱼钩”的本质,是一个 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[][]
数组的下标具体说明。</P>
<P><SPAN class=atitle3>ipt_do_table()</SPAN></P>
<P>我们具体看到 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。</P>
<P>table 里面存放了这个 table 中所有的防火墙 rules。但是并不是所有的 rules 都要拿过来,按照它审查一下这个
packet。事实上,这个 packet 是从哪个“鱼钩”上被钓上来的,就只有和那个“鱼钩”相关的 rules 才被拿过来,用来审查这个
packet。这个机制,就为每个 table 实现了多个 chain,而每个 chain 上又有多个 rules。而且,我们立刻看到,一个
chain 是和 IPv4 协议栈上的一个“垂钓点”相对应的。熟悉 iptables
用户空间管理工具的使用的读者朋友们应该立刻就会注意到这一点了。</P>
<P>在 linux-2.4.19/include/linux/netfilter_ipv4/ip_tables.h 中定义了 table 中的
rule 的存放格式,如下:</P>
<P>
<TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#cccccc
border=1><TBODY>
<TR>
<TD><PRE><CODE>
/* 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];
};
</CODE></PRE></TD></TR></TBODY></TABLE></P>
<P>一个 entry 就是一个 rule。一个 entry 主要由两部分组成。一部分,是一系列的 matches;另一部分,是一个
target。这若干个 match 所要回答的问题,是相关的 packet 和本条 rule 是否匹配。而这个 target 所要回答的问题,是一旦
packet 匹配上以后,该拿这个 packet 怎么办?也就是要由 target 来决定这个匹配的 packet 今后的命运了。开头的
struct ipt_ip 的定义如下:</P>
<P>
<TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#cccccc
border=1><TBODY>
<TR>
<TD><PRE><CODE>
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;
};
</CODE></PRE></TD></TR></TBODY></TABLE></P>
<P>我们立刻可以看出来,在 struct ipt_ip 里面记录了关于这个 rule 所要匹配(match)的 packet 的一些特征。</P>
<P><SPAN class=atitle3>match 和 target</SPAN></P>
<P>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 的匹配要求。</P>
<P>这就提示我们,如果要写自己的防火墙模块,镶嵌在 netfilter 的架构中的话,我们主要要做的任务,就是向 netfilter 核心注册
ipt_register_target() 或者 ipt_register_match()。</P>
<P><SPAN class=atitle3>iptables 管理工具</SPAN></P>
<P>最后,要说明的是 iptables,这个位于用户空间的管理工具。前面我们看到了,netfilter 在内核空间的代码根据 table 中的
rules,完成对 packet 的分析和处置。但是这些 table 中的具体的防火墙 rules,还是必须由系统管理员亲自编写。kernel 中的
netfilter 只是提供了一个机制,它并不知道该怎样利用这个机制,写出合适的 rules,来实现一个网络防火墙。那么,系统管理员编写的
rules,怎样进入位于 kernel 空间中的 netfilter 维护的 table 中去呢?</P>
<P>这个任务是由 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 了。</P>
<P><A name=4><SPAN class=atitle2>小结</SPAN></A></P>
<P>netfilter 对于 IPv4 的修改非常小,一是在若干个地方调用了 NF_HOOK(),二是在 ip_sockopt() 中调用了
nf_sockopt()。netfilter 的核心部分代码只是维护 table,解释 table 的任务在于其它的 kernel
module。netfilter 会把从 hook “钓”起来的 packet 以及 table 里面的相关内容发给注册了的 module,决定
packet 的命运。 </P>
<P><A name=resources><SPAN class=atitle2>参考资料</SPAN></A></P>
<P>1 netfilter/iptables 主站点在 <A
href="http://www.netfilter.org/">http://www.netfilter.org/</A> 或者 <A
href="http://www.iptables.org/">http://www.iptables.org/</A> 在这个站点上,可以找到
netfilter 核心开发者 Paul Russell 写的 Linux Packet Filtering HOW-TO,Linux NAT
HOW-TO 等关于怎样部署 Linux netfilter 防火墙的技术文章。</P>
<P>2 Linux 内核源代码的在线交叉索引在 <A
href="http://lxr.linux.no/">http://lxr.linux.no/</A> 这个站点可以帮助读者朋友们更加方便的阅读
Linux kernel 的源程序。</P>
<P><A name=author1><SPAN class=atitle2>关于作者</SPAN></A></P>
<P>赵蔚,住在南京市的 Linux/Free Software 独立技术顾问。在 IBM developerWorks
发表过多篇中文文章。关于他在网络上发表的技术文章的一份清单,可以在 <A
href="http://www.advogato.org/person/zhaoway/">http://www.advogato.org/person/zhaoway/</A>
找到。他经常光顾南京大学小百合 BBS 上的 LinuxUnix 版。南大小百合的网址在 <A
href="http://bbs.nju.edu.cn/">http://bbs.nju.edu.cn/</A> 赵蔚在南大小百合上面的 ID 是
iloveqhq 欢迎读者朋友们和他讨论 Linux/Free Software 相关的各种技术问题。</P><!-- END PAPER BODY--></TD>
<TD width=10><IMG height=1 alt=""
src="netfilter:Linux 防火墙在内核中的实现.files/c.gif" width=10
border=0></TD></TR></TBODY></TABLE><BR clear=all><IMG height=10 alt=""
src="netfilter:Linux 防火墙在内核中的实现.files/c.gif" width=100 border=0><BR>
<TABLE cellSpacing=0 cellPadding=0 width="100%" border=0>
<TBODY>
<TR vAlign=top>
<TD align=right width="100%"><A
href="http://www-900.ibm.com/developerWorks/cn/linux/network/l-netip/#top">到页首</A></TD>
<TD width=5><IMG height=1 alt=""
src="netfilter:Linux 防火墙在内核中的实现.files/c.gif" width=5 border=0></TD></TR>
<TR vAlign=top>
<TD bgColor=#000000 colSpan=2><IMG height=1 alt=""
src="netfilter:Linux 防火墙在内核中的实现.files/c.gif" width=100 border=0></TD></TR>
<TR vAlign=top>
<TD bgColor=#ffffff colSpan=2><IMG height=8 alt=""
src="netfilter:Linux 防火墙在内核中的实现.files/c.gif" width=100
border=0></TD></TR></TBODY></TABLE>
<TABLE cellSpacing=0 cellPadding=10 width="100%" border=0>
<TBODY>
<TR vAlign=top>
<TD>
<FORM name=getURL
action=/developerWorks/cn/cnratings.nsf/RateArticle?CreateDocument
method=post><INPUT type=hidden value="netfilter:Linux 防火墙在内核中的实现"
name=ArticleTitle> <INPUT type=hidden name=url>
<SCRIPT language=javascript>getURL();</SCRIPT>
<INPUT type=hidden value=linux name=Zone> <INPUT type=hidden
value=/developerWorks/cn/thankyou/feedback-linux.html name=RedirectURL> <A
name=rating><B>您对这篇文章的看法如何?</B></A>
<TABLE cellSpacing=0 cellPadding=0 width=600 border=0>
<TBODY>
<TR>
<TD colSpan=5><IMG height=8 alt=""
src="netfilter:Linux 防火墙在内核中的实现.files/c.gif" width=100
border=0></TD></TR>
<TR vAlign=top>
<TD width="16%"><INPUT type=radio value=5 name=Rating>真棒!(5)</TD>
<TD width="20%"><INPUT type=radio value=4 name=Rating>好材料 (4)</TD>
<TD width="24%"><INPUT type=radio value=3 name=Rating>一般;尚可 (3)</TD>
<TD width="22%"><INPUT type=radio value=2 name=Rating>需提高 (2)</TD>
<TD width="18%"><INPUT type=radio value=1 name=Rating>太差!
(1)</TD></TR></TBODY></TABLE><BR><B>建议?</B><BR><TEXTAREA name=Comments rows=5 wrap=virtual cols=60></TEXTAREA><BR><BR><INPUT type=submit value=提交反馈意见></FORM></TD></TR>
<TR vAlign=top>
<TD bgColor=#ffffff><IMG height=8 alt=""
src="netfilter:Linux 防火墙在内核中的实现.files/c.gif" width=100
border=0></TD></TR></TBODY></TABLE>
<TABLE cellSpacing=0 cellPadding=0 width="100%" border=0>
<TBODY>
<TR>
<TD align=right>(c) Copyright IBM Corp. 2001, (c) Copyright IBM China
2001, All Right Reserved</TD></TR>
<TR vAlign=top>
<TD class=bbg height=21> <A class=mainlink
href="http://www-900.ibm.com/developerWorks/cn/cgi-bin/click.cgi?url=www-900.ibm.com/cn/ibm/index.shtml&origin=dwhead">关于
IBM</A><SPAN class=divider> | </SPAN><A
class=mainlink
href="http://www-900.ibm.com/developerWorks/cn/cgi-bin/click.cgi?url=www-900.ibm.com/cn/ibm/privacy/index.shtml&origin=dwhead">隐私条约</A><SPAN
class=divider> | </SPAN><A class=mainlink
href="http://www-900.ibm.com/developerWorks/cn/cgi-bin/click.cgi?url=www-900.ibm.com/cn/ibm/legal/index.shtml&origin=dwhead">使用条款</A><SPAN
class=divider> | </SPAN><A class=mainlink
href="http://www-900.ibm.com/developerWorks/cn/cgi-bin/click.cgi?url=www-900.ibm.com/cn/ibm/contact/index.shtml&origin=dwhead">联系
IBM</A></TD></TR></TBODY></TABLE>
<SCRIPT language=JavaScript1.2 src="netfilter:Linux 防火墙在内核中的实现.files/stats.js"
type=text/javascript></SCRIPT>
<NOSCRIPT><IMG height=1 alt=""
src="C:\Documents and Settings\hlm\My Documents\文档\防火墙技术\netfilter:Linux 防火墙在内核中的实现.files\c(1).gif"
width=1 border=0></NOSCRIPT> </A></BODY></HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -