我转一文章!!!!

注:任何转载或摘抄请保留作者信息和注明文章出处(中文FreeBSD用户组 cnfug.org)I

P Filter Based Firewalls HOWTO

xiaojl zhiyouxjl@sina.com

Brendan Conoboy
Erik Fichtner
$FreeBSD: src/share/examples/ipfilter/ipf-howto.txt,v 1.1.2.1 2002/04/27 20:04:18 darrenr Exp $

摘要:本文档向初学者介绍IP Filter防火墙软件,同时介绍一些设计防火墙的基本方法。

1.1声明

作者对因该文档所造成的破坏概不负责,该文档只是介绍基于ipfilter的防火墙。如果你觉得你采取的行动不太合适的话,你应该停止阅读该文档,请有资格的安全专家为你安装防火墙。

1.2 版权

除非其它情况,该文档版权属于每一个作者。部分或全部文档可以以各种介质复制和重新发布,只要你在所有的拷贝中保存版权声明。任何商业性质的发布应该通知文档的作者。
所有的翻译文档及其它衍生文档应该保留版权声明。

1.3 哪里可以获得重要文档

ipf官方网站:http://coombs.anu.edu.au/~avalon/ip-filter.html
文档的最新版本可以在这找到:http://www.obfuscation.org/ipf/

  1. 基本防火墙

这部分将使您对ipfilter的语法及防火墙原理有个总体的了解。这里讨论的防火墙特点都可以在任何好的防火墙软件中找到。这部分将使您更容易的阅读和理解后面的高级部分。必须提一下的是,这一部分不足以让你建立一个好的防火墙,如果您想建立一个有效率的安全系统您应该阅读高级部分。

2.1 文件的结构,顺序及优先级

ipf 有一个配置文件(或者说是一些一次运行的命令)。这个文件沿袭unix风格:每行一条规则,“#”表示注释,多余的空格将被忽略,我们鼓励保持规则文件的可读性。

2.2 基本的规则处理

每条规则从上到下顺序执行。这意味着如果你的配置文件是这样的:

block in all
pass in all

计算机将视它视为

block in all
pass in all

就是说,当有一个包进来,第一条规则起作用:

block in all

接下来ipf将包传给下一条规则,第二条规则将起作用:

pass in all

这个时候你也许会问ipf将执行第二条规则吗?如果你熟悉ipfwadm或者ipfw,你也许就不会问这个问题了。也许您将会对包的走向感到困惑,很多包过滤软件只要包符合一条规则,它将不会往下匹配,但是ipf不属于这种类型。
不像其它包过滤器,ipf会为每个包做一个标记,不管这个包通过与否。ipf将遍历整个规则集,除非你打断它的遍历,然后ipf根据最后一条规则决定是通过还是抛弃这个包。当一个包进入一个接口(如rl0,tun0),ipf就开始工作,他先检查这个包然后再检查第一条规则:

block in all

ipf说:“我现在应该阻止这个包”。它又看看第二条规则:

pass in all

“我现在应该通过这个包”。它又看看第三条规则,没有第三条规则,所以这个包根据最后一条规则,向前传递这个包。
现在应该指出的是,即使你的规则是这样的:

block in all
block in all
block in all
block in all
pass in all

这个包依然通过。规则没有累加作用的。最后一条匹配规则总是优先的。

2.3 控制规则的执行

如果你有使用其它包过滤器的经验,你也许会发现这种设计令人困惑,会觉得这样匹配速度会有些问题。想象一下如果你有100条规则,而最有用的是前10条,每个包都通过这100条规则是一种很可怕的开销。幸运的是,你可以加一个关键字到任意一条规则里面,只要匹配这条规则,这条规则将马上起作用,而不用跑到最后一条规则。这个关键字是quick。这是一个修改过的规则集,加入了quick:

block in quick all
pass in all

这种情况下,ipf检查第一条规则:

block in quick all

报匹配这条规则并且遍历结束.这个包就被抛弃,没有任何提示、记录。那么下一条规则呢?

pass in all

这条规则绝不会被检查,就像不在配置文件里面。all非常广泛而且quick马上起作用将使后面的规则不起作用。
在这里ipf就像它所配置的那样阻止包的通过,ipf也可以让一些包通过,我们可以稍微改一下规则组来实现。

2.4 基于ip地址的过滤

ipf可以在很多方面过滤数据包,我们最熟悉的一种是ip地址,有一些ip地址空间我们是绝对不会与之通信的,(假设)其中一块就是无路由网络,192.168.0.0/16(/16 是子网掩码,ipf也可以使用255.255.0.0)。如果你想阻止192.168.0.0/16,你可以这样:

block in quick from 192.168.0.0/16 to any
pass in all

现在我们有了一个较不严格的规则集,它确实能为我们做些事情。当一个来自1.2.3.4的包进来,查询第一条规则:

block in quick from 192.168.0.0/16 to any

这个包不是来自192.168..,所以不匹配。查询第二条规则:

pass in all

这个包匹配,这个包被传到它的目的地。
另一方面,假设我们有一个包来自192.168.1.2,第一条规则被执行:

block in quick from 192.168.0.0/16 to any

匹配,包被丢弃,结束(不执行下一条规则),因为第一条规则包含quick关键字。
现在你可以通过或者阻止相当广泛的地址的数据包,我们在上面的例子中阻止了进入我们防火墙的私有地址的数据包,让我们看看其它的规则:

block in quick from 192.168.0.0/16 to any
block in quick from 172.16.0.0/12 to any
block in quick from 10.0.0.0/8 to any
pass in all

前面的3块ip地址属于私有的ip地址空间。

2.5 控制接口

很多公司在它们连入外部网之前就有内部网了。事实上,防火墙的最早应用的地方就是在这里,连接外网和内往之间的机器就是路由器,它与其它机器的差别在于它拥有多个接口。所有你接收到的包以及所有你发出的包都经过网络接口。假设你有3个接口,lo0(loopback),xl0(3com ethernet),tun0(FreeBSD中ppp通常使用的接口),你不需要数据包进入你的tun0接口。

block in quick on tun0 all
pass in all

在这,关键字"on"说明数据是针对tun0接口的。当一个包进入tun0,第一条规则匹配并丢弃这个包,当一个数据包进入lo0或者xl0,第一条规则不匹配,第二条规则匹配,数据报通过。

2.6 联合ip地址和接口

一个防火墙匹配的规则标准(如ip,port,接口)越多,防火墙越严谨,也许你需要通过tun0传输数据,但是不想让来自192.168.0.0/16的数据包通过。以下规则是一个防火墙的开始:

block in quick on tun0 from 192.168.0.0/16 to any
pass in all

根据上面的规则,我们用tun0来阻止通过tun0接口的数据包,当一个来自192.168.0.0/16的数据包到达xl0,它将会通过。现在我们可以根据接口建立一个阻止或者允许大范围地址通过的防火墙:

block in quick on tun0 from 192.168.0.0/16 to any
block in quick on tun0 from 172.16.0.0/12 to any
block in quick on tun0 from 10.0.0.0/8 to any
block in quick on tun0 from 127.0.0.0/8 to any
block in quick on tun0 from 0.0.0.0/8 to any
block in quick on tun0 from 169.254.0.0/16 to any
block in quick on tun0 from 192.0.2.0/24 to any
block in quick on tun0 from 204.152.64.0/23 to any
block in quick on tun0 from 224.0.0.0/3 to any
pass in all

你已经了解前3块地址地址空间,第4块是回路地址(浪费了大块的A类网络地址),很多软件通过127.0.0.1与本机进行通信,所以应该阻止源地址是外部地址的数据包。第五块地址0.0.0.0/8,不应该出现在因特网上,大部分的ip堆栈把0.0.0.0/32当作默认网关,其它的0...*,不同的系统有不同的奇怪的处理方法。169.254.0.0/16由IANA分配给那些通过DHCP未能获得ip地址的机器作为自动获得的ip地址。特别是windows操作系统经常使用该ip地址段,当它们是通过DHCP获得ip地址,但是未能找到DHCP服务器。192.0.2.0/24是作者用来举例的ip地址段,同样它也是预留地址。20.20.20.4/24,204.152.64.0/23是sun公司预留的ip地址,是否阻止由你自己决定。224.0.0.0/3主要用于多播地址,几乎包括了D类,E类地址,其它的D类地址可以查找RFC1166。
包过滤有一个非常重要的原则,就是刚才提过的阻止私有地址的通过(除非你确信有跟私有地址进行通信),当你知道某种类型的数据的源地址,你应该建立只允许来自这个地址的数据通过。例如非路由地址,源地址是10.0.0.0/8的数据包是不应该到达tun0的,因为你没办法对这个数据包进行回复,这是一个非法的数据包,127.0.0.0/8也是这种类型。
很多软件根据数据包的原始地址进行认证,当你有一个内部网20.20.20.0/24,只有内部数据的交换,但是有数据包想要离开内部网,例如有个源地址是20.20.20.0/24想通过ppp拨号,这个时候你有理由抛弃它,这种类型的数据包是不应该到达它的目的地址的,你可以简单的用ipf来实现。规则是这样的:

block in quick on tun0 from 192.168.0.0/16 to any
block in quick on tun0 from 172.16.0.0/12 to any
block in quick on tun0 from 10.0.0.0/8 to any
block in quick on tun0 from 127.0.0.0/8 to any
block in quick on tun0 from 0.0.0.0/8 to any
block in quick on tun0 from 169.254.0.0/16 to any
block in quick on tun0 from 192.0.2.0/24 to any
block in quick on tun0 from 204.152.64.0/23 to any
block in quick on tun0 from 224.0.0.0/3 to any
block in quick on tun0 from 20.20.20.0/24 to any
pass in all

2.7 双向过滤,关键字“out”

到现在我们已经通过或者阻止进入防火墙的数据包,必须说明的是,进入的数据包到达的是防火墙的任意一个接口。相反,出去的数据包离开防火墙的任意一个接口(不管是本地产生的还是仅仅是通过防火墙的数据包),这就是说我们可以过滤进入防火墙的数据包也可以过滤离开防火墙的数据包。
现在我们知道可以像过滤进入的数据包那样过滤离开的数据包,我们可以想到的一个用处就是可以阻止伪装的数据包离开我们自己的网络。如果外部有些机器想通过ipf路由一个目的地址是192.168.0.0/16的数据包,我们干嘛不抛弃它呢,最坏的情况只是浪费一些带宽:

block out quick on tun0 from any to 192.168.0.0/16
block out quick on tun0 from any to 172.16.0.0/12
block out quick on tun0 from any to 10.0.0.0/8
block out quick on tun0 from any to 0.0.0.0/8
block out quick on tun0 from any to 127.0.0.0/8
block out quick on tun0 from any to 169.254.0.0/16
block out quick on tun0 from any to 192.0.2.0/24
block out quick on tun0 from any to 204.152.64.0/23
block out quick on tun0 from any to 224.0.0.0/3
block out quick on tun0 from !20.20.20.0/24 to any

最勉强的观点是这样做并不会提高你的安全性,但是它可以提高其它人的安全性,而且最好是这样做。另外一个观点是因为从你的站点没有人可以发送伪装的数据包,你被crackers攻击的目标就小了。你将会发现很多阻止数据包离开防火墙的用处。有件事你必须记在心上,那就是不管是进来的还是出去的数据包都是相对于你的防火墙的,而不是其它机器。

2.8 记录,关机字"log"

到现在所有的数据包都是悄悄的通过或者被阻止,通常你想知道你是否被攻击,但是我并不想记录所有的数据包,而且我想知道被我阻止的来自于20.20.20.0/24数据包的情况。为了达到这个目的,我加入关键字log

block in quick on tun0 from 192.168.0.0/16 to any
block in quick on tun0 from 172.16.0.0/12 to any
block in quick on tun0 from 10.0.0.0/8 to any
block in quick on tun0 from 127.0.0.0/8 to any
block in quick on tun0 from 0.0.0.0/8 to any
block in quick on tun0 from 169.254.0.0/16 to any
block in quick on tun0 from 192.0.2.0/24 to any
block in quick on tun0 from 204.152.64.0/23 to any
block in quick on tun0 from 224.0.0.0/3 to any
block in log quick on tun0 from 20.20.20.0/24 to any
pass in all

现在,我们的防火墙能够很好的阻止来自不明地址的数据包,但是我们还有很多事情要做,我们要做的第一件事情是我们要抛弃来自20.20.20.0/32和20.20.20.255/32的数据包,防止smurf攻击(关于smurf攻击请看相关资料):

block in quick on tun0 from 192.168.0.0/16 to any
block in quick on tun0 from 172.16.0.0/12 to any
block in quick on tun0 from 10.0.0.0/8 to any
block in quick on tun0 from 127.0.0.0/8 to any
block in quick on tun0 from 0.0.0.0/8 to any
block in quick on tun0 from 169.254.0.0/16 to any
block in quick on tun0 from 192.0.2.0/24 to any
block in quick on tun0 from 204.152.64.0/23 to any
block in quick on tun0 from 224.0.0.0/3 to any
block in log quick on tun0 from 20.20.20.0/24 to any
block in log quick on tun0 from any to 20.20.20.0/32
block in log quick on tun0 from any to 20.20.20.255/32
pass in all

2.9 基于接口的双向过滤

如果你想建立一个防火墙规则组,你应该考虑到每个方向每个接口。ipfilter默认的状态是通过所有的数据包,我们不应该依赖于默认规则,应该考虑每一个细节,每一个接口,直到所有的情况都包括进去。
首先我们从lo0开始,这个接口是用于本系统中程序之间的通信,让它自由通过:

pass out quick on lo0
pass in quick on lo0

接着是xl0,在后面我们将对它进行严格的限制,在这里我们假设我们的本地网可以信任,像lo0一样处理:

pass out quick on xl0
pass in quick on xl0

最后是tun0,在上面我们已经对tun0进行限制,合并如下:

block in quick on tun0 from 192.168.0.0/16 to any
block in quick on tun0 from 172.16.0.0/12 to any
block in quick on tun0 from 10.0.0.0/8 to any
block in quick on tun0 from 127.0.0.0/8 to any
block in quick on tun0 from 0.0.0.0/8 to any
block in quick on tun0 from 169.254.0.0/16 to any
block in quick on tun0 from 192.0.2.0/24 to any
block in quick on tun0 from 204.152.64.0/23 to any
block in quick on tun0 from 224.0.0.0/3 to any
block in log quick on tun0 from 20.20.20.0/24 to any
block in log quick on tun0 from any to 20.20.20.0/32
block in log quick on tun0 from any to 20.20.20.255/32
pass in all

这是一个很有效的过滤规则,防止20.20.20.0/24被伪装。下面的例子我们为了简便将只考虑一个方向,当你创建防火墙规则时应该考虑每个方向,每个接口。

2.10 控制协议;关键字"proto"

拒绝服务攻击跟缓冲溢出攻击一样猖獗,很多DOS攻击是利用了操作系统TCP/IP栈的失常,它通常是使用icmp包。我们为什么不阻止所有icmp的通过呢?

block in log quick on tun0 proto icmp from any to any

有多少icmp包从tun0进入将被记录并且抛弃。

2.11 用icmp-type关键字对icmp进行过滤

当然抛弃所有的icmp不是一个好主意,因为它在某些方面还是有用的。或许你想抛弃那些没用的icmp类型。如果你想要让ping和traceroute正常工作,你应该让icmp的types 0和11通过。严格来讲,这样做也不太好,权衡安全性和便利性,ipf可以这样做:

pass in quick on tun0 proto icmp from any to 20.20.20.0/24 icmp-type 0
pass in quick on tun0 proto icmp from any to 20.20.20.0/24 icmp-type 11

记得规则的顺序是很重要的。如果我们加入关键字"quick"我们必须在block之前pass,我们需要这样安排规则的顺序

pass in quick on tun0 proto icmp from any to 20.20.20.0/24 icmp-type 0
pass in quick on tun0 proto icmp from any to 20.20.20.0/24 icmp-type 11
block in log quick on tun0 proto icmp from any to any

把这三条规则加入上面的防止欺骗的规则中需要一些机巧。如果我们将这三条规则放在最前面会有些问题

pass in quick on tun0 proto icmp from any to 20.20.20.0/24 icmp-type 0
pass in quick on tun0 proto icmp from any to 20.20.20.0/24 icmp-type 11
block in log quick on tun0 proto icmp from any to any
block in quick on tun0 from 192.168.0.0/16 to any
block in quick on tun0 from 172.16.0.0/12 to any
block in quick on tun0 from 10.0.0.0/8 to any
block in quick on tun0 from 127.0.0.0/8 to any
block in quick on tun0 from 0.0.0.0/8 to any
block in quick on tun0 from 169.254.0.0/16 to any
block in quick on tun0 from 192.0.2.0/24 to any
block in quick on tun0 from 204.152.64.0/23 to any
block in quick on tun0 from 224.0.0.0/3 to any
block in log quick on tun0 from 20.20.20.0/24 to any
block in log quick on tun0 from any to 20.20.20.0/32
block in log quick on tun0 from any to 20.20.20.255/32
pass in all

这个问题是来自192.168.0.0/16的icmp type 0的数据包根据第一条规则将会通过,第四条规则将不会起作用。同样icmp也会通过并到达20.20.20.0/24,这样会向恶意的smurf攻击开了后门,而且最后两条规则也不起作用。为了避免这样的情况发生,我们将icmp规则放到防止欺骗的规则后面:

block in quick on tun0 from 192.168.0.0/16 to any
block in quick on tun0 from 172.16.0.0/12 to any
block in quick on tun0 from 10.0.0.0/8 to any
block in quick on tun0 from 127.0.0.0/8 to any
block in quick on tun0 from 0.0.0.0/8 to any
block in quick on tun0 from 169.254.0.0/16 to any
block in quick on tun0 from 192.0.2.0/24 to any
block in quick on tun0 from 204.152.64.0/23 to any
block in quick on tun0 from 224.0.0.0/3 to any
block in log quick on tun0 from 20.20.20.0/24 to any
block in log quick on tun0 from any to 20.20.20.0/32
block in log quick on tun0 from any to 20.20.20.255/32
pass in quick on tun0 proto icmp from any to 20.20.20.0/24 icmp-type 0
pass in quick on tun0 proto icmp from any to 20.20.20.0/24 icmp-type 11
block in log quick on tun0 proto icmp from any to any
pass in all

因为我们在icmp之前已经阻止了伪装的数据包,一个伪装的数据包将不会到达icmp规则。记住规则的顺序这一点很重要。

2.12 tcp,udp端口;关键字"port"

我们已经基于协议对数据包进行过滤,我们还可以基于协议的具体方面进行过滤。最有用的方面是端口号,rsh,rlogin,telnet服务通常是很有用的,但是由于网络嗅探和欺骗攻击,这些服务隐含这一些不安全的因素,一个很重要的妥协方法是只在内部网运行这些服务,阻止外网的访问。这很容易做到,因为rsh,rlogin,telnet使用专用的端口号(514,513,23)。容易建立规则:

block in log quick on tun0 proto tcp from any to 20.20.20.0/24 port = 513
block in log quick on tun0 proto tcp from any to 20.20.20.0/24 port = 514
block in log quick on tun0 proto tcp from any to 20.20.20.0/24 port = 23

这三条规则必须在pass in all之前,这样它们将跟外网隔开(为了简便省略防止欺骗的规则)

pass in quick on tun0 proto icmp from any to 20.20.20.0/24 icmp-type 0
pass in quick on tun0 proto icmp from any to 20.20.20.0/24 icmp-type 11
block in log quick on tun0 proto icmp from any to any
block in log quick on tun0 proto tcp from any to 20.20.20.0/24 port = 513
block in log quick on tun0 proto tcp from any to 20.20.20.0/24 port = 514
block in log quick on tun0 proto tcp from any to 20.20.20.0/24 port = 23
pass in all

你也许想阻止514/udp(syslog),111/tcp&111/udp(portmap),515/tcp(lpd),2049/tcp&udp(nfs),6000/tcp(X11)等等。你可以获得完整的系统正在侦听端口列表,netstat -a(或者lsof -i,如果你已经安装)。
如果要阻止udp,只要将tcp换成udp,下面是针对syslog的

block in log quick on tun0 proto udp from any to 20.20.20.0/24 port = 514

ipf对于同时处理tcp和udp有一个简单的方法,针对portmap:

block in log quick on tun0 proto tcp/udp from any to 20.20.20.0/24 port = 111

  1. 高级防火墙介绍

这部分文档跟前面的基础文档联系紧密,不仅包含着高级防火墙的观念,还包含着一些ipfilter特性,一旦你熟悉这部分,你将能够建立一个非常健壮的防火墙。

3.1 偏执狂:默认拒绝的规则

根据端口来阻止服务存在一个很大的问题:有时候端口是可以改变的,基于rpc的程序因为端口变化会变得很糟糕的,lockd,statd,甚至是nfsd侦听的端口不是2049。这种情况是很难预料的,更糟糕的是不大可能总是自适应这个变化。我们现在建立一个新的防火墙规则,我们将用的第一条规则是:

block in all

所有的数据报都无法通过。没有什么用处但是很安全。假设你的服务器只跑一个web服务,没有其它的。甚至没有dns查询,只开放80端口,我们可以加入另外一条规则来实现:

block in on tun0 all
pass in quick on tun0 proto tcp from any to 20.20.20.1/32 port = 80

第二条规则将使连接20.20.20.1端口80的数据包通过,其它的数据包则无法通过。作为基本的防火墙,这就够了。

3.2 状态规则

防火墙的作用是阻止从A到B的数据包,假设我们有这样一条规则:只要是到达端口23的数据包就可以通过。同样的只要一个数据包有FIN标志就可以通过,我们上面的防火墙并不知道TCP/UDP/ICMP会话的开始段,中间段,结束段。它只是针对所有包的规则。我们希望到达端口23的数据包没有被窃取、改动,就是说我们希望有一个方法将一个正常的TCP/UDP/ICMP数据包跟端口扫描或者是DOS攻击区分开来。这种方法就是所说的keeping state(保持连接状态)。
我们想要做到既方便又安全,很多人已经这么做了,像Ciscos有个established条款,这条款允许已经建立连接的tcp的数据包通过。ipfw也有established,ipfwadm有setup/established(译者注:用于建立连接的标志位/已建立连接的标志位),它们都有这个特点,但是它们的名字容易使人误导。当我们第一次看见的时候,我们会认为我们的包过滤器会追踪一个数据包想要做什么,过滤器会知道一个连接是否已经建立。事实上,它们都是根据数据包的部分例如TCP数据包的标志位来判断一个数据包想要做什么,但是udp/icmp没有用于判断的标志位,无法实现这个功能。如果是这样的话,任何人都可以伪造这些标志位,并使一个数据包通过防火墙。
IPF在这些问题上是怎么处理的呢?ipf不像其它的防火墙,它可以真正的追踪每个数据包并判断一个连接是否已经建立。而且ipf可以处理tcp,udp,icmp,不仅仅是tcp。Ipf称之为keep state(保持状态),规则的关键字就是keep state。
现在你已经知道防火墙检查每一个进入的数据包,同样检查每个离开的数据包。事实上,是状态表检查每个进入或者离开的数据包。状态表是整个防火墙规则中可以通过的TCP/UPD/ICMP会话(连接)表。这会不会是一个严重的安全漏洞呢,事实上这是防火墙中最好的。
所有的tcp/ip会话都有开始,中间及结束(尽管有时候这三个阶段都在同一个包里),只有结束阶段而没有中间阶段,或者只有中间阶段而没有开始阶段的会话(正常会话)是不可能的。这就是说,你所要做的就是过滤tcp/udp/icmp会话的开始阶段。如果一个会话的开始阶段允许通过,那么它的中间阶段和结束阶段也可以通过(除非ip栈溢出或者机器当机)。Keeping state允许你忽略中间阶段和结束阶段,而仅仅是集中在阻止或者通过一个新的会话。如果一个新的会话通过,那么它所有的后续数据包都被允许通过。这是一个跑ssh服务的例子(仅仅是ssh):

block out quick on tun0 all
pass in quick on tun0 proto tcp from any to 20.20.20.1/32 port = 22 keep state

你会注意到没有pass out规则。尽管如此,这个规则是完整的。这是keeping state的缘故。一旦一个含有SYN(连接的初始阶段)的数据包到达ssh服务器,会话状态被建立并保存(译者注:这样数据包就可以自由进出)。这是另外一个例子:

block in quick on tun0 all
pass out quick on tun0 proto tcp from 20.20.20.1/32 to any keep state

这种情况下,服务器不跑服务。事实上这不是一台服务器,而是客户机。而且这台客户机不想让未经过认证的包进入ip栈。然而客户机需要访问因特网,同时让回复的包通过。这个简单的规则为每个向外的tcp连接建立状态表。当这个状态表建立以后,这个tcp会话就会畅通无阻,而且没有防火墙规则集的检查(译者注:由状态表检查)。udp和icmp同样适用:

block in quick on tun0 all
pass out quick on tun0 proto tcp from 20.20.20.1/32 to any keep state
pass out quick on tun0 proto udp from 20.20.20.1/32 to any keep state
pass out quick on tun0 proto icmp from 20.20.20.1/32 to any keep state

这样就可以使用ping了,我们已经为tcp,udp,icmp建立连接状态(译者注:严格来讲udp,icmp会话没有建立连接状态,只是防火墙保存了连接状态)。现在我们可以向外连接了,攻击者却无法进入。这是非常方便的,因为我们不必跟踪机器在监听哪些端口,而仅仅是跟踪那些我们想让别人能够连接的端口。
state是非常方便的,但是需要一些机巧。在一些奇怪的令人迷惑的用法上,你有可能“搬石头砸自己的脚”。考虑一下下面的规则:

pass in quick on tun0 proto tcp from any to 20.20.20.1/32 port = 23
pass out quick on tun0 proto tcp from any to any keep state
block in quick all
block out quick all

这看起来像是一个好的防火墙规则,我们允许进入并通过防火墙连接23端口,而且允许所有对外的连接。无疑的,所有连接端口23的数据包都将得到回复,防火墙pass out规则将建立一条状态记录,所有的事情将会很完美,至少我们是这样想的。
不幸的是,60秒的空闲时间以后这条状态记录将会关闭(而不是5天),这是因为这条状态记录无法看到连接端口23的SYN数据包,它只看到SYN ACK(SYN的回复)。IPF很适合于跟踪从开始到结束的tcp连接,但是不擅长对连接的中间进行跟踪,所以应该像这样重写防火墙规则:

pass in quick on tun0 proto tcp from any to 20.20.20.1/32 port = 23 keep state
pass out quick on tun0 proto tcp from any to any keep state
block in quick all
block out quick all

新加上的那条规则将会对每个syn数据包建立状态记录,而且跟我们期望的一样工作得很好,一旦状态引擎发现了一个连接3次握手已经完成,这个连接就会被表记为4/4模式,这种模式意味着一个长时间数据交换的连接已经建立直到这个连接被拆除(ipfstat -s可以看到连接的模式)。

3.3 有状态的udp

udp是无状态协议,因此对它建立可靠的状态连接有很大的难度,尽管如此,ipf在这方面做得相当好。当机器A给B发送一个udp包,源端口是X,目的端口是Y,ipf将允许从机器Y到机器X源端口是Y,目的端口是X的回复包通过。这是一条短期的状态记录,仅仅是60秒。
这是一个例子,用nslookup查询www.3com.com的ip地址:

$nslookup 3com.com

一个DNS包产生:

17:54:25.499852 20.20.20.1.2111 > 198.41.0.5.53: 51979+

这个包从20.20.20.1端口2111到192.41.0.5端口53。一条60秒的状态记录被创建。在60秒的时间内从192.41.0.5端口53到20.20.20.1端口2111的包将通过,就像你所看到的:

17:54:25.501209 198.41.0.5.53 > 20.20.20.1.2111: 51979 q: 3com.com

回复包符合状态记录,允许通过,回复包通过之后这条状态记录被关闭,不在允许新的数据包进入,即使这个包来自同一个地方。

3.4 有状态的icmp

IPFilter像处理tcp,udp一样处理icmp状态,就像你理解的那样。ICMP主要有两种信息类型:请求和回复。 假设我们写了这样一条规则:

pass out on tun0 proto icmp from any to any icmp-type 8 keep state

允许向外发送回复请求(典型的ping),结果是类型为icmp-type 0的包回复并通过。这条状态记录是一种不完全的0/0(相比4/4)状态,它将在60秒的空闲时间后删除。这样当你为每个外出的icmp包保存状态,你将会得到每个icmp的回复。
然而,大部分icmp消息是由错误的udp(有时是tcp)包产生的,而且在3.4.X的ipfilter中错误的icmp消息(超时或端口不可达)会根据udp(有时是tcp)状态记录而通过防火墙。在旧的ipfilter中,如果你想让traceroute正常工作,你需要这样:

pass out on tun0 proto udp from any to any port 33434><33690 keep state
pass in on tun0 proto icmp from any to any icmp-type timex

而现在你只需要为udp保存状态就可以了:

pass out on tun0 proto udp from any to any port 33434><33690 keep state
block in quick on tun0 all
pass out quick on tun0 proto tcp from 20.20.20.1/32 to any keep state

为了防止第三方icmp消息通过一个活动的连接进入你的防火墙,防火墙不仅对进入的icmp消息进行源地址和目的地址的检查(有时包括端口,如果可用的话),还对icmp消息中的荷载(产生icmp消息的包的一部分)进行检查。

3.5 FIN扫描检测;关键字flags,keep frags

先回顾一下上面的4条规则

pass in quick on tun0 proto tcp from any to 20.20.20.1/32 port = 23 keep state
pass out quick on tun0 proto tcp from any to any keep state
block in quick all
block out quick all

这几条规则还不能令人满意,问题在于不仅允许SYN包到达23端口而且允许老的数据包通过。我们可以用关键字flags改变上面的规则:

pass in quick on tun0 proto tcp from any to 20.20.20.1/32 port = 23 flags S keep state
pass out quick on tun0 proto tcp from any to any flags S keep state
block in quick all
block out quick all

现在只有目的地址是20.20.20.1,目的端口23带有SYN标志的tcp包可以通过。SYN标志只存在于tcp会话的第一个数据包(称为tcp第一次握手),这也是我们所希望,这样做至少有两个好处:首先不是所有的包都可以进入防火墙并把你的状态表搞的乱七八糟。其次,FIN和XMAS扫描将会行不通,因为它们的标志位不是SYN。现在进入的数据包要么是SYN包要么是已经建立连接的数据包。如果其它的数据包进入,很可能是端口扫描或者伪造的数据包,但是也有可能是一个分片。IPF用关键字keep frags就可以处理分片。加上这个关键字,IPF将跟踪那些分片,允许我们需要的分片通过。我们重写一下规则,允许分片并记录伪装包:

pass in quick on tun0 proto tcp from any to 20.20.20.1/32 port = 23 flags S keep state keep frags
pass out quick on tun0 proto tcp from any to any keep state flags S keep frags
block in log quick all
block out log quick all

这几条规则将起作用,因为所有的包在block之前就已经通过了。但是无法发现SYN扫描,如果你感到不爽你可以记录所有的SYN包。

3.6 回应被阻止的数据包

现在被我们阻止的包都被丢弃,或者记录,我们没有发送任何回应包给源主机。有时侯这不是最好的办法,因为如果这样做就等于告诉一个攻击者我们有一个包过滤器。最好是我们能够误导使攻击者相信我们没有包过滤器,并且没有提供服务可供攻击。
当一个服务运行在unix系统上,它通常通过回复包让远程主机知道。在tcp中使通过RST包来回复。当阻止一个tcp通过时,实际上IPF返回一个RST给源主机(用关键字return-rst)。现在我们可以这样做

block return-rst in log proto tcp from any to 20.20.20.0/24 port = 23
block in log quick on tun0
pass in all

return-rst只适用于tcp,我们还想用于udp,icmp及其它协议(下面将介绍),现在远程主机将得到connection refused而不是connection timed out。
当有人给你的系统的一个udp端口发送数据包,防火墙也可能发送一条错误信息。只要你的规则是这样的:

block in log quick on tun0 proto udp from any to 20.20.20.0/24 port = 111

你可以用加入return-icmp关键字的规则来代替上面的规则来发送回复

block return-icmp(port-unr) in log quick on tun0 proto udp from any to 20.20.20.0/24 port = 111

根据tcp/ip的规范,当给服务器某个端口发送一个数据包,而服务器没有服务进程在监听这个端口时将发出port-unreachable。当然你可以用其它的icmp类型,但是port-unreachable可能是最好的。这也是默认的用来回复的icmp类型
然而当你用return-icmp的时候,你将会发现也不是很安全的,因为icmp包包含了防火墙的ip地址,而不是原始数据包的目的地址。这个问题已经在ipfilter3.3以后的版本中得到解决,一个新的关键字return-icmp-as-dest已经加入。这是新的规则:

block return-icmp-as-dest(port-unr) in log on tun0 proto udp from any to 20.20.20.0/24 port = 111

另外,你要慎用回复包,只有在你很清楚你要对什么数据进行回复的时候才能使用。例如:如果你给局域网的广播地址发送return-icmp,局域网将会在短时间内被淹没。

3.7 日志

如果你要使用日志设备dev/ipl,记得要加入关键字log.为了要看到日志信息,你必须运行ipmon(或者其它读取/dev/ipl的软件)。一般是使用ipmon -s向syslog写入信息。以ipfilter3.3为例,你甚至可以通过关键字log level控制syslog记录的行为:

block in log level auth.info quick on tun0 from 20.20.20.0/24 to any
block in log level auth.alert quick on tun0 proto tcp from any to 20.20.20.0/24 port = 21

另外你还可以对记录的信息进行裁剪,比如你对是否有人对你的telnet扫描感兴趣,但是对有人扫描你的telnet端口多少次并不感兴趣,你可以log first关键字来记录第一个包。
log的另外一个用处是跟踪你感兴趣的包,并且记录它的头部字段。Ipfilter使用关键字log body可以记录每个包的前128个字节。你应该限制使用body log,因为它会让你的日志变得冗长。

3.8 合并所有规则

现在我们有了一个非常严谨的防火墙了,但是它可以更严谨。先前我们去掉的防止欺骗的规则集实际上是很有用的。建议把它加上:

block in on tun0
block in quick on tun0 from 192.168.0.0/16 to any
block in quick on tun0 from 172.16.0.0/12 to any
block in quick on tun0 from 10.0.0.0/8 to any
block in quick on tun0 from 127.0.0.0/8 to any
block in quick on tun0 from 0.0.0.0/8 to any
block in quick on tun0 from 169.254.0.0/16 to any
block in quick on tun0 from 192.0.2.0/24 to any
block in quick on tun0 from 204.152.64.0/23 to any
block in quick on tun0 from 224.0.0.0/3 to any
block in log quick on tun0 from 20.20.20.0/24 to any
block in log quick on tun0 from any to 20.20.20.0/32
block in log quick on tun0 from any to 20.20.20.255/32
pass out quick on tun0 proto tcp/udp from 20.20.20.1/32 to any keep state
pass out quick on tun0 proto icmp from 20.20.20.1/32 to any keep state
pass in quick on tun0 proto tcp from any to 20.20.20.1/32 port = 80 flags S keep state

3.9 用规则组优化防火墙

让我们扩展一下我们的防火墙,使我们的防火墙更有用,作为例子我们将改变一下接口名字xl0,xl1,xl2。
xl0接外部网络20.20.20.0/26
xl1用于代理20.20.20.64/26
xl2连接受防火墙保护的网络20.20.20.128/25
我们先定义整个规则,你应该能清楚地理解它:

block in quick on xl0 from 192.168.0.0/16 to any
block in quick on xl0 from 172.16.0.0/12 to any
block in quick on xl0 from 10.0.0.0/8 to any
block in quick on xl0 from 127.0.0.0/8 to any
block in quick on xl0 from 0.0.0.0/8 to any
block in quick on xl0 from 169.254.0.0/16 to any
block in quick on xl0 from 192.0.2.0/24 to any
block in quick on xl0 from 204.152.64.0/23 to any
block in quick on xl0 from 224.0.0.0/3 to any
block in log quick on xl0 from 20.20.20.0/24 to any
block in log quick on xl0 from any to 20.20.20.0/32
block in log quick on xl0 from any to 20.20.20.63/32
block in log quick on xl0 from any to 20.20.20.64/32
block in log quick on xl0 from any to 20.20.20.127/32
block in log quick on xl0 from any to 20.20.20.128/32
block in log quick on xl0 from any to 20.20.20.255/32
pass out on xl0 all

pass out quick on xl1 proto tcp from any to 20.20.20.64/26 port = 80 flags S keep state
pass out quick on xl1 proto tcp from any to 20.20.20.64/26 port = 21 flags S keep state
pass out quick on xl1 proto tcp from any to 20.20.20.64/26 port = 20 flags S keep state
pass out quick on xl1 proto tcp from any to 20.20.20.65/32 port = 53 flags S keep state
pass out quick on xl1 proto udp from any to 20.20.20.65/32 port = 53 keep state
pass out quick on xl1 proto tcp from any to 20.20.20.66/32 port = 53 flags S keep state
pass out quick on xl1 proto udp from any to 20.20.20.66/32 port = 53 keep state
block out on xl1 all
pass in quick on xl1 proto tcp/udp from 20.20.20.64/26 to any keep state

block out on xl2 all
pass in quick on xl2 proto tcp/udp from 20.20.20.128/25 to any keep state

从这个例子中,我们可以看出我的规则集变得越来越臃肿了。如果我们加入跟多的规则时,情况会变得更严

我不喜欢用IP Filter带的防火墙。要用防火墙还是用ipfw好多了。
但是ipfw的地址转换效率比底。用做地址转换我还是用的ip filter
我在FreeBSD上都是用的ipfw+ipfilter!
在网吧用了8个月了。没点问题!
系统
FreeBSD 4.9 (ipfw+ipfilter)
Samba Server
RealServer 9.0
FtpServer (系统自带)
Apache1.3+cgi+php
Cs1.5 Server
VPN SERVER (pptp+l2tp)
速度快。又稳定!还可以将部分木马程序发邮件的端口关掉!什么冲击波震荡波都别想进来!

:laughing: :laughing:

效率好高.可惜资料比较少.

又是感觉太难了.好难学… :open_mouth: :open_mouth: