📄 netfilter:linux 防火墙在内核中的实现.htm
字号:
<TD width="100%">
<TABLE cellSpacing=0 cellPadding=0 width=168 align=right border=0>
<TBODY>
<TR><!-- Sidebar Gutter-->
<TD width=8><IMG height=21 alt=""
src="netfilter:Linux 防火墙在内核中的实现.files/c.gif" width=5></TD>
<TD width=160><!-- Start TOC-->
<TABLE cellSpacing=0 cellPadding=0 width=160 border=0>
<TBODY>
<TR>
<TD width=160 bgColor=#000000 height=1><IMG height=1 alt=""
src="netfilter:Linux 防火墙在内核中的实现.files/c.gif" width=160></TD></TR>
<TR>
<TD align=middle
background="netfilter:Linux 防火墙在内核中的实现.files/bg-gold.gif"
height=5><B>内容:</B></TD></TR>
<TR>
<TD width=160 bgColor=#666666 height=1><IMG height=1 alt=""
src="netfilter:Linux 防火墙在内核中的实现.files/c.gif" width=160></TD></TR>
<TR>
<TD align=right>
<TABLE cellSpacing=0 cellPadding=3 width="98%" border=0>
<TBODY>
<TR>
<TD><A
href="http://www-900.ibm.com/developerWorks/cn/linux/network/l-netip/#1">netfilter
和 Linux 防火墙介绍</A></TD></TR>
<TR>
<TD><A
href="http://www-900.ibm.com/developerWorks/cn/linux/network/l-netip/#2">IPv4
代码中 netfilter 的接口</A></TD></TR>
<TR>
<TD><A
href="http://www-900.ibm.com/developerWorks/cn/linux/network/l-netip/#3">netfilter
的核心模块</A></TD></TR>
<TR>
<TD><A
href="http://www-900.ibm.com/developerWorks/cn/linux/network/l-netip/#4">小结</A></TD></TR>
<TR>
<TD><A
href="http://www-900.ibm.com/developerWorks/cn/linux/network/l-netip/#resources">参考资料</A></TD></TR>
<TR>
<TD><A
href="http://www-900.ibm.com/developerWorks/cn/linux/network/l-netip/#author1">关于作者</A></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE><!-- End TOC--><!-- Start Related Content Area--><!--<table border="0" cellpadding="0" cellspacing="0" width="160"><tr><td bgcolor="#000000" height="1" width="160"><img alt="" height="1" src="/developerWorks/cn/i/c.gif" width="160" /></td></tr><tr><td align="center" background="/developerWorks/cn/i/bg-gold.gif" height="5"><b>相关内容:</b></td></tr><tr><td bgcolor="#666666" height="1" width="160"><img alt="" height="1" src="/developerWorks/cn/i/c.gif" width="160" /></td></tr><tr><td align="right"><table border="0" cellpadding="3" cellspacing="0" width="98%"><tr><td><a href="#1">介绍</a></td></tr><tr><td><a href="#1">介绍</a></td></tr></table></td></tr></table>--><!-- End TOC--><!-- Start Related Content Area-->
<TABLE cellSpacing=0 cellPadding=0 width=160 border=0>
<TBODY>
<TR>
<TD width=160 bgColor=#000000 height=1><IMG height=1 alt=""
src="netfilter:Linux 防火墙在内核中的实现.files/c.gif" width=160></TD></TR>
<TR>
<TD align=middle
background="netfilter:Linux 防火墙在内核中的实现.files/bg-gold.gif"
height=5><A class=nav
href="http://www-900.ibm.com/developerWorks/cn/linux/index.shtml"><B>在
Linux 专区还有:</B></A></TD></TR>
<TR>
<TD width=160 bgColor=#666666 height=1><IMG height=1 alt=""
src="netfilter:Linux 防火墙在内核中的实现.files/c.gif" width=160></TD></TR>
<TR>
<TD align=right>
<TABLE cellSpacing=0 cellPadding=3 width="98%" border=0>
<TBODY>
<TR>
<TD><A
href="http://www-900.ibm.com/developerWorks/cn/cnedu.nsf/linux-onlinecourse-bytitle?OpenView&Count=500">教程</A></TD></TR>
<TR>
<TD><A
href="http://www-900.ibm.com/developerWorks/cn/cntools.nsf/dw/linux-codelib-byname?OpenDocument&Count=500">工具与产品</A></TD></TR>
<TR>
<TD><A
href="http://www-900.ibm.com/developerWorks/cn/cntools.nsf/dw/linux-projects-byname?OpenDocument&Count=500">代码与组件</A></TD></TR>
<TR>
<TD><A
href="http://www-900.ibm.com/developerWorks/cn/cnpapers.nsf/linux-papers-bynewest?OpenView&Count=500">文章</A></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE><!-- End Related dW Content Area-->
<TABLE cellSpacing=0 cellPadding=0 width=160 border=0>
<TBODY>
<TR>
<TD width=150 bgColor=#000000 colSpan=2 height=2><IMG height=2
alt="" src="netfilter:Linux 防火墙在内核中的实现.files/c.gif"
width=160></TD></TR>
<TR>
<TD width=150 bgColor=#ffffff colSpan=2 height=2><IMG height=2
alt="" src="netfilter:Linux 防火墙在内核中的实现.files/c.gif"
width=160></TD></TR></TBODY></TABLE><!-- END STANDARD SIDEBAR AREA--></TD></TR></TBODY></TABLE><!-- START SUBTITLE AND CONTENT-->
<P><A
href="http://www-900.ibm.com/developerWorks/cn/linux/network/l-netip/#author1">赵蔚</A>
(<A href="mailto:zhaoway@public1.ptt.js.cn">zhaoway@public1.ptt.js.cn</A>)
<BR>Linux/Free Software 独立技术顾问<BR>2002年11月15日</P>
<BLOCKQUOTE>本文介绍 Linux 的防火墙技术 netfilter/iptables 在 Linux
内核中的具体实现。</BLOCKQUOTE>
<P><A name=1><SPAN class=atitle2>netfilter 和 Linux 防火墙介绍</SPAN></A></P>
<P>Linux 的防火墙技术经历了若干代的沿革,一步步的发展而来。最开始的 ipfwadm 是 Alan Cox 在 Linux kernel
发展的初期,从 FreeBSD 的内核代码中移植过来的。后来经历了 ipchains,再经由 Paul Russell 在 Linux kernel
2.3 系列的开发过程中发展了 netfilter 这个架构。而用户空间的防火墙管理工具,也相应的发展为
iptables。netfilter/iptables 这个组合目前相当的令人满意。在经历了 Linux kernel 2.4 和 2.5
的发展以后,的确可以说,netfilter/iptables 经受住了大量用户广泛使用的考验。</P>
<P>本文并不打算介绍 Linux 防火墙在用户空间的管理程序 iptables 的使用。至于如何利用 netfilter/iptables
机制搭建一个可靠的 Internet 防火墙,这也不是本文感兴趣的话题。关于 iptables 的使用,读者朋友们可以参考 man iptables
的手册,也可以参考 netfilter 的核心开发者 Paul Russell 写的 Packet Filtering HOW-TO 和 NAT
HOW-TO。相关的链接,请参见文后所列的参考资料目录。读者朋友们在阅读本文之前,最好能够对 iptables 的使用有一定的了解。</P>
<P>本文介绍 netfilter 在 Linux kernel 中的实现。如果条件允许的话,我们可能在后续的文章中将要进一步说明如何编写自己的
kernel modules 并将其镶嵌在 netfilter 的架构中,以实现自己的定制防火墙功能。值得指出的是,在 netfilter
的网站上,可以看到 netfilter 的一个子项目 patch-o-matic,其中收录了大量的各种定制 kernel modules,这些
modules 给读者朋友们开发自己的 kernel modules,提供了非常多的、很好的例子。</P>
<P><A name=2><SPAN class=atitle2>IPv4 代码中 netfilter 的接口</SPAN></A></P>
<P>netfilter 在 Linux kernel 中的 IPv4、IPv6 和 DECnet
等网络协议栈中都有相应的实现。本文限于篇幅,将只介绍其中最让大多数读者朋友们感兴趣的 IPv4 协议栈上的 netfilter 的实现。</P>
<P>我们在编译 Linux kernel 的过程中一定会注意到,netfilter
是一个在编译过程中可选的部件。也就是说,用户在编译内核的过程中,可以按照自己的需要,决定是否要在自己的内核中编译进去 netfilter 的
kernel 支持。这就带给我们一个提示,实现 netfilter 的代码对于实现 IPv4
协议栈的代码的影响应该会是尽量的小,不那么引人注目才对。否则的话,IPv4 协议栈的代码维护工作就不得不和实现 netfilter
的代码的维护工作搅在一起,让人头疼了。</P>
<P>事实也的确如此,IPv4 协议栈为了实现对 netfilter 架构的支持,在 IP packet 在 IPv4
协议栈上的游历路线之中,仔细选择了五个参考点。在这五个参考点上,各引入了一行对 NF_HOOK() 宏函数的一个相应的调用。这五个参考点被分别命名为
PREROUTING,LOCAL-IN,FORWARD,LOCAL-OUT 和 POSTROUTING。关于这五个参考点的含义,在 iptables
的使用说明中有准确的叙述,相信读者朋友们都应该了解了。从如下的 grep 输出,我们可以看到 IPv4 协议栈实现代码对 NF_HOOK()
宏函数的调用:</P>
<P>
<TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#cccccc
border=1><TBODY>
<TR>
<TD><PRE><CODE>
zhaoway@qhq ~/linux-2.4.19/net/ipv4 $ grep -n NF_HOOK *.c
arp.c:591:NF_HOOK(NF_ARP, NF_ARP_OUT, skb, NULL, dev, dev_queue_xmit);
arp.c:871:return NF_HOOK(NF_ARP, NF_ARP_IN, skb, dev, NULL, arp_process);
igmp.c:187:/* Don't just hand NF_HOOK skb->dst->output, in case netfilter hook
igmp.c:252:return NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, rt->u.dst.dev,
ip_forward.c:145:return NF_HOOK(PF_INET, NF_IP_FORWARD, skb, skb->dev, dev2,
ip_gre.c:668:/* Need this wrapper because NF_HOOK takes the function address */
ip_input.c:302:return NF_HOOK(PF_INET, NF_IP_LOCAL_IN, skb, skb->dev, NULL,
ip_input.c:437:return NF_HOOK(PF_INET, NF_IP_PRE_ROUTING, skb, dev, NULL,
ip_output.c:111:/* Don't just hand NF_HOOK skb->dst->output, in case netfilter hook
ip_output.c:156:return NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, rt->u.dst.dev,
ip_output.c:191:return NF_HOOK(PF_INET, NF_IP_POST_ROUTING, skb, NULL, dev,
ip_output.c:233:NF_HOOK(PF_INET, NF_IP_POST_ROUTING, newskb, NULL,
ip_output.c:249:NF_HOOK(PF_INET, NF_IP_POST_ROUTING, newskb, NULL,
ip_output.c:400:return NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, rt->u.dst.dev,
ip_output.c:603:err = NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL,
ip_output.c:714:err = NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, rt->u.dst.dev,
ipip.c:516:/* Need this wrapper because NF_HOOK takes the function address */
ipmr.c:1211:NF_HOOK(PF_INET, NF_IP_FORWARD, skb2, skb->dev, dev,
zhaoway@qhq ~/linux-2.4.19/net/ipv4 $
</CODE></PRE></TD></TR></TBODY></TABLE></P>
<P>NF_HOOK() 这个宏函数,定义在 linux-2.4.19/include/linux/netfilter.h 里面。当 #ifdef
CONFIG_NETFILTER 被定义的时候,就转去调用 nf_hook_slow() 函数;如果 CONFIG_NETFILTER
没有被定义,则从 netfilter 模块转回到 IPv4 协议栈,继续往下处理。这样就给了用户在编译 kernel 的时候一个选项,可以通过定义
CONFIG_NETFILTER 与否来决定是否把 netfilter 支持代码编译进内核。从这个函数的名称,我们也可以猜到,可以把 IPv4
协议栈上的这五个参考点,形象的看成是五个钩子。IP packet 在 IPv4 协议栈上游历的时候,途经这五个钩子,就会被 netfilter
模块钓上来,审查一番,并据审查的结果,决定 packet 的下一步命运:是被原封不动的放回 IPv4
协议栈,继续游历;还是经过一些修改,再放回去;还是干脆丢弃掉算了?</P>
<P><A name=3><SPAN class=atitle2>netfilter 的核心模块</SPAN></A></P>
<P><SPAN class=atitle3>“鱼钩”和“垂钓点”</SPAN></P>
<P>IP packet 被 NF_HOOK() 从 IPv4 协议栈上钓出来以后,就进入
linux-2.4.19/net/core/netfilter.c 中的 nf_hook_slow() 函数进行处理。这个函数干的主要事情,就是根据
nf_hooks[] 数组,开始处理 packet。准确地说来,上一段讲到的 IPv4
协议栈上的五个参考点,并不是“钓鱼的钩子”,而是“允许垂钓的地点”。换句话说,IPv4
协议栈上定义了五个“允许垂钓点”。在每一个“垂钓点”,都可以让 netfilter 放置一个“鱼钩”,把经过的 packet 钓上来。那么
netfiler 的“鱼钩”都放在什么地方?就放在 nf_hooks[][] 数组里面。这个“鱼钩”用
linux-2.4.19/include/linux/netfilter.h 中定义的如下 struct 予以描述:</P>
<P>
<TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#cccccc
border=1><TBODY>
<TR>
<TD><PRE><CODE>
struct nf_hook_ops
{
struct list_head list;
nf_hookfn *hook;
int pf;
int hooknum;
int priority;
};
</CODE></PRE></TD></TR></TBODY></TABLE></P>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -