Chinaunix首页 | 论坛 | 博客
  • 博客访问: 53704
  • 博文数量: 24
  • 博客积分: 975
  • 博客等级: 准尉
  • 技术积分: 250
  • 用 户 组: 普通用户
  • 注册时间: 2005-08-18 21:58
文章分类

全部博文(24)

文章存档

2011年(1)

2005年(23)

我的朋友
最近访客

分类: BSD

2005-10-17 20:21:20

使用ipfw配置系统的防火墙

(一)
FreeBSD操作系统本身带有二种内置的IP信息包检查机制:ipfw和ipfilter。在创建决定允许哪些信息包进入系统、哪些信息包会被拒之系统门外的规则集方面,二种机制各有自己独特的语法。在这里,我们将讨论如何使用ipfw配置系统的防火墙。

在能够使用ipfw防火墙机制之前,我们需要在FreeBSD的内核配置文件中添加一些选项,并重新编译内核。如果不太清楚如何编译FreeBSD的内核,请参阅相关的手册。

可供ipfw使用的选项有好几个,我们首先从讨论LINT开始。在这里,我通过使用“/”符号进行搜索,以便能够快速地发现恰当的小节:

cd /usr/src/sys/i386/conf
more LINT
/IPFIREWALL
# IPFIREWALL和ipfw软件,这二者就可以支持IP防火墙的构建。IPFIREWALL_VERBOSE向
# 系统的注册程序发送注册信息包,IPFIREWALL_VERBOSE_LIMIT限制一台机器注册的次
# 数。注意:如果没有在启动时添加任何允许IP访问的规则,IPFIREWALL的缺省配置是
# 禁止任何IP数据包进出系统的,这时你甚至不能访问网络中的其他机器。建议首次使
# 用这一功能时在/etc/rc.conf中设置firewall_type=open,然后在对内核进行测试后
# 再在/etc/rc.firewall仔细地调整防火墙的设置。IPFIREWALL_DEFAULT_TO_ACCEPT使
# 得缺省的规则允许所有形式的访问。在使用这一变量时应该非常小心,如果黑客能够
# 突破防火墙,就能任意访问你的系统。

要启用ipfw,必须设置IPFIREWALL选项,它将通知操作系统的内核检查每个IP数据包,将它们与规则集进行比较,通过添加 IPFIREWALL_VERBOSE选项包括注册支持是一个好主意,还应该通过添加IPFIREWALL_VERBOSE_LIMIT选项来限制内核注 册的数据包的数量。

除非在规则集中进行了特别的说明,缺省情况下ipfw将阻塞所有的IP数据包。由于缺省设置可以仔细地控制哪些数据包会被接受,因此我非常喜欢它。我不喜 欢内核会接受自己都不清楚内容的数据包,如果需要的数据没有被系统接受,会得到系统的提示,并修改规则集使系统可以接受它们。这时,如果有没有预料到的数 据包通过系统也不会知道。因此,我不会通过包括IPFIREWALL_DEFAULT_TO_ACCEPT选项来绕过缺省的设置。

# IPDIVERT启用由ipfw divert使用的转向IP套接字。这一选项需要与natd联合使用。由
# 于在本例中建立的防火墙仅用于保护一台机器,因此不需要这个选项。
# IPSTEALTH启动支持秘密转发的代码,这一选项在使防火墙不被traceroute和类似工具发现时很有用。

这是一个非常有趣的选项,因此我将在防火墙中包含这一选项,并在对防火墙进行测试时看看它的工作原理。

# 接受过滤器中的静态连接
# options ACCEPT_FILTER_DATA
# options ACCEPT_FILTER_HTTP

在这台计算机上运行的不是互联网服务器,因此无需在编译时包括这二个选项。

# 下面的选项和系统级变量控制系统如何处理适当的TCP数据包。
#
# TCP_DROP_SYNFIN可以支持包含有SYN+FIN的TCP数据包,它使nmap不能识别TCP/IP栈,# 但可以破坏对RFC1644扩展的支持,建议不要在互联网服务器中使用。
#
# TCP_RESTRICT_RST支持阻止TCP RST栈的泄出,对于需要大量SYN的系统或者不希望被简单地扫描到端口的系统非常有用。

我将在防火墙中包括这些选项,在测试防火墙时,仔细看看它们有什么作用。

# ICMP_BANDLIM根据带宽限制产生icmp错误。一般情况下我们需要这个选项,它有助于
# 你的系统免受D.O.S.攻击。
#
options ICMP_BANDLIM

FreeBSD内核缺省支持这一选项。

# DUMMYNET启动“dummynet”带宽限制软件。还需要有IPFIREWALL选项的支持
# BRIDGE启动以太网卡之间的桥接功能

在本例中我不会选这二个选项,因为在独立的计算机系统上无需对流量进行控制。

在重新编译FreeBSD内核之前,我将在内核配置文件中添加下面的内容:

#以缺省的、拒绝所有数据包方式启动IPFW
options IPFIREWALL
options IPFIREWALL_VERBOSE
options IPFIREWALL_VERBOSE_LIMIT=10

#隐藏防火墙
options IPSTEALTH

#使不被nmap发现,如果是互联网服务器则去掉该选项。
options TCP_DROP_SYNFIN

#防止端口扫描
options TCP_RESTRICT_RST

在重新编译内核时,我将再次仔细审查在/etc/rc.conf中添加的选项。下面是手册中有关各个选项的说明:

man rc.conf
/firewall

firewall_enable
(布尔型)如果不想在系统启动时加载防火墙规则集,将其值设置为NO;否则,将其设置为YES。如果它被设置为YES,而内核在编译时没有使用IPFIREWALL选项,ipfw内核模块将自动被加载。
firewall_script
(字符串型)如果要运行一段防火墙脚本程序,而不是/etc/rc.firewall,将这一变量设置为脚本程序的路径全名。
firewall_type
(字符串型)从/etc/rc.firewall或包含规则集的文件中的防火墙类型中指定防火墙类型。/etc/rc.firewall中可选的防火墙类 型为:open-不限制IP访问;closed-禁止除通过lo0进行的之外的所有IP服务;client-对工作站的基本保护;simple-对LAN 的基本保护。如果给的是一个指定的文件名,则必须使用全路径名。

由于我希望系统启动时加载防火墙规则,因此将把firewall_enable变量的值设置为YES。由于要使用自己的规则集,需要指定使用firewall_type创建的文件的全路径名。

firewall_quiet
(布尔型)如果设置为YES,则系统在启动时,不会在控制台上显示ipfw规则。

由于会显示加载的各条规则,将这个变量设置为YES是一个好主意。如果相关规则中出现了错误,则在这个错误之后的所有规则都不会被加载。如果在启动时看着 屏幕,就会在成功加载的最后一条规则之后看到一个ipfw语法消息。这样就可以在规则集中发现出现的错误,然后重新启动机器,使所有的规则都能够被成功地 加载。

firewall_logging
(布尔型)设置为YES会启动ipfw事件日志功能,与IPFIREWALL_VERBOSE内核选项的功能相同。
tcp_extensions
(布尔型)缺省状态下被设置为NO。设置为YES可以启动由RFC 1323定义的一些TCP选项。如果连接有随机的问题出现,将其重新设置为NO,看是否能够解决问题,因为一些软、硬件问题都与这个选项有关。
log_in_vain
(布尔型)缺省状态下设置为NO。设置为YES将把对端口的连接尝试记入日志中。
tcp_keepalive
(布尔型)缺省状态下设置为YES。设置为NO会禁止对空闲的TCP连接的探查。
tcp_drop_synfin
(布尔型)缺省状态下设置为NO。设置为YES会使内核忽略有SYN和FIN标志的TCP帧。 虽然这样会提供操作系统的指纹,但会使一些正常的应用软件出毛病。只有在编译内核时使用了TCP_DROP_SYNFIN选项,该选项才有效。

由于在内核中添加了TCP_DROP_SYNFIN选项,我将这一变量的值设置为YES。如果在计算机上运行互联网服务器软件,应该去掉这一选项。

tcp_restrict_rst
(布尔型)缺省状态下设置为NO。设置为YES将使内核在响应无效的TCP数据包时不能输出TCP RST帧。只有在编译内核时使用了TCP_RESTRICT_RST选项,这一选项才有效。
icmp_drop_redirect
(布尔型)缺省状态下设置为NO。设置为YES将使内核忽略ICMP REDIRECT信息包。
icmp_log_redirect
(布尔型)缺省状态下设置为NO。设置为YES将使内核在日志中记录ICMP REDIRECT信息包。由于日志是没有什么限制的,因此只有在对网络维护时才会使用这一选项。

最终,我在系统中的/etc/rc.conf文件中加入了下面的内容:

#用于支持ipfw的选项
firewall_enable="YES"
firewall_script="/etc/rc.firewall"
firewall_type="/etc/ipfw.rules"
firewall_quiet="NO" #对现有的规则满意后将其值改为YES
firewall_logging_enable="YES"
#附加的防火墙选项
log_in_vain="YES"
tcp_drop_synfin="YES" #如果要创建互联网服务器,将其值改为NO。
tcp_restrict_rst="YES"
icmp_drop_redirect="YES"

在重新启动机器运行新的内核之前,有一点需要注意。如果LINT文件显示出“YOU WILL LOCK YOURSELF OUT”(你将封锁自己),说明新的规则已经起作用了。在重新创建允许所需的IP数据包进入系统之前,所有的IP数据包都不能进入或传出计算机。如果想从 互联网上收发电子邮件和下载资料,就需要在重新启动系统之前完成这些工作。

创建一个好的规则集是一件技术性很强固的工作。如果是第一次创建防火墙,需要有大量的时间进行练习,就会发现ipfw所使用的逻辑与你认为的逻辑不完全相同。

此外,防火墙并非是安装后就一劳永逸了,需要花些时间对它进行优化,在它不能完成你预期的任务时多想想这是为什么。一旦用有防火墙的新内核启动机器后,你可能希望完成下面的三项工作。

▲系统地在规则集中添加新的规则,测试每条规则的作用,确保只有你需要的数据包才能够出入你的系统。

▲决定你要将哪些IP数据包记入日志并查看日志文件,随着不断发现你禁止或允许的一些数据包出入系统,会不断地修改规则。

▲一旦对防火墙允许或不允许通过哪些数据包满意了,就需要测试防火墙的性能是否能够令人满意。

好了,下面我要重新启动机器加载新的内核。在启动时盯着屏幕,在NIC加载后会看到下面的信息:

Flushed all rules.
00100 allow ip from any to any via lo0
00200 deny ip from any to any to 127.0.0.0/8
Firewall rules loaded, starting divert daemons:.
Additional routing options: tcp extensions=NO ignore ICMP redirect=YES TCP keepalive=YES restrict TCP reset=YES drop SYN+FIN packets=YES.

Additional TCP options: log_in_vain=YES.

你可能会有疑惑,没有创建包含规则集的文件,怎么会显示头三行信息呢?在编辑/etc/rc.conf时,我在其中添加了下面一行的内容:

firewall_script="/etc/rc.firewall"

在启动时系统会读取/etc/rc.firewall文件,该文件包含下面的内容:

############
# Flush out the list before we begin.
#
${fwcmd} -f flush

############
# 只有在极少数的情况下才需要改变这些规则
#
${fwcmd} add 100 pass all from any to any via lo0
${fwcmd} add 200 deny all from any to 127.0.0.0/8

由于规则100和规则200在启动时会用到,因此在创建规则时应该从规则300开始。在创建规则之前,我会用下面的方法分二次检查ipfw是否缺省地禁止所有的信息包出入我的计算机系统。可以通过运行ipfw show命令来进行检查:

ipfw show
ipfw: socket: Operation not permitted

似乎只有超级用户才有查看防火墙规则的权限,因此我将再次以超级用户再身份次进行检查:

su
Password:
ipfw show
00100 0 0 allow ip from any to any via lo0
00200 0 0 deny ip from any to 127.0.0.0/8
65535 115 14092 deny ip from any to any

确实已经禁止所有的信息包出入计算机系统,我再来试着使用一下网络连接。

ping
ping: cannot resolve Host name lookup failure

traceroute
traceroute: unknown host

lynx
Alert!: Unable to access document.

好了,名字解析也无效,我们再试试ping吧:

ping 24.141.116.1
PING 24.141.116.1 (24.141.116.1): 56 data bytes
ping: sendto: Permission denied
ping: sendto: Permission denied
^C
--- 24.141.116.1 ping statistics ---
2 packets transmitted, 0 packets received, 100% packet loss

由于我是以超级用户的身份运行最后一个ping的,因此ipfw确实已经禁止所有信息包的出入,我已经完全不能使用网络连接了。现在我们来创建一个允许收发我需要的IP信息包的规则集。

有二种方式可以创建被ipfw读取的规则:

如果已经在使用ipfw,不用重启动机器就能使规则生效。但是,如果重新启动机器后,添加的规则就会丢了。

你还可以在让ipfw读取的文件中添加一条规则,这样只有机器重新启动后,新添加的规则才能生效。

由于这台机器只有我一个人使用,因此,我将把规则直接加进文件中并重启机器。我已经在/etc/rc.conf中添加了下面的一行内容:

firewall_type="/etc/ipfw.rules"

因此,我将创建一个名字为/etc/ipfw.rules的文件.


(二)
我们已经通过安装带缺省的禁止所有数据包出入的策略的ipfw,使所有的IP信息包都不能出入我的计算机系统,下面,我们再创建一个能被ipfw读取的规则集,使所需要的信息包能够出入计算机系统。

由于在创建规则集方面没有所谓“最合适”的方法,因此我不能说明如何在规则集中添加“万能”的规则,而只能说明一下在创建规则集时需要遵循的原则。在这里,我假设你已经掌握了ipfw的语法,能够理解我创建的规则。如果对这些知识不大理解,请参阅相关的资料。

在创建规则集时需要注意的是,规则是按给定数字行号的顺序被系统读取的,直到信息包符合一条规则,ipfw才会停止读取规则,也就是说,如果规则400和 规则800都适用于一个信息包,系统总是会用到规则400而不会读取规则800。因此,在添加新的规则之前,需要仔细地审查原来的规则,确保新的规则不会 被原来的规则所覆盖。

此外,规则对所有的连接-也就是在ifconfig -a的输出中所列出的所有连接都是适用的。如果在象我这样只有一个连接的计算机上自然不会有什么问题,但如果在有多个连接的计算机上,就会有所不同。例 如,你的机器上可能有二个连接,一个是互联网连接,一个是内部局域网连接,每个不同的连接需要不同的安全规则,这一点可以通过在ipfw的规则中指定连接 的名字来实现。

我的机器是一台运行FreeBSD 4.2、配置有互联网连接的单台计算机。由于这是我在家里使用的计算机,因此可以对向互联网上发送的信息包的类型不作任何限制,而只需要它能够接收是对我发出的信息包有效响应的信息包。

要完成这一任务最好的方法之一是利用ipfw的动态功能。如果你对这一概念还不太熟悉,下面我将对它作一番详尽的解释。

如果使用“动态”的规则,当我向互联网上发送一个信息包时,ipfw将在其状态表中添加一个记录,其中包括有发送的信息包的目标计算机的IP地址和使用的 目标计算机的端口。当有信息包从互联网上返回时,如果其IP地址、端口号与在状态表中记录得不一致,计算机就不会接收这一信息包。动态规则只适用于TCP 信息包,而不适用于UDP信息包,原因是UDP不创建一个虚拟的连接,它被称作是“无状态”协议,也就不能使用“状态表”。

ipfw手册中的例子部分给出了三条用来创建这个动态信息包过滤装置的规则。由于我决定在/etc/ipfw.rules中创建自己的规则,因此,需要以超级用户的身份创建包含下面内容的文件:

# 只允许向外发送信息包
add 00300 check-state
add 00301 deny tcp from any to any in established
add 00302 allow tcp from any to any out setup keep-state

由于规则100和规则200是预先包含在/etc/rc.firewall中的,因此,我自己添加的规则将从行号300开始。我将给相关的规则以300、 301、302等行号,等规则越来越多或创建不相关的规则时,我就会把行号跳到400。不过,从理论上说你可以任意给规则指定行号,只要该行号没有在该规 则集文件中出现过就行。

你可能已经注意到规则集出现了几个在ipfw手册中定义的关健字:

check-state:检查信息包是否与动态规则集匹配。如果匹配则搜索中止,否则继续搜索下一条规则。
keep-state:根据匹配情况,防火墙将创建一条动态规则,其功能是在源、目的IP地址/端口之间使用同一协议的流量,这一规则是具有一定的生命周期的(由一系列sysctl(变量控制),每当发现匹配协议时其生命周期都会刷新。
established:只适用于TCP信息包,与有RST或ACK位的信息包进行匹配。
setup:只适用于TCP信息包,与有SYN位但不具有ACK位的信息包进行匹配。

换句话说,当有信息包到达网络连接后,ipfw将首先检查它是否在状态表中,如果在状态表中,则允许它进入系统(行号为300的规则执行这一检查工作)。 如果它不在状态表中,而且设置了RST或ACK位,ipfw将不允许它进入系统,因为它不是我创建的连接的有效响应(规则301完成这一工作)。只有当 ACK标志没有设置,(这意味着它要初始化连接)并且这一信息包是由系统向外发送的时,才允许它向外发送;如果有信息包符合这一规则,则它被加入状态表 中。

我们来看看添加上这些规则后对系统有什么影响。对规则集进行检查没有错误后,保存文件,然后输入下面的命令:

killall init

敲Enter键,然后输入:

exit

然后仔细观察启动信息,确保规则在加载时没有出现出错信息。如果在规则加载过程中出现了错误信息,那么可能是系统的安全级别被设置为3或更高了,必须首先在/etc/rc.conf文件中找到下面的这行内容,将kern_securelevel改为较小的值:

kern_securelevel="3"

然后重新执行killall init命令。

重新登录后,我将尝试能否向外发送IP数据包并收到相应的应答数据包:

ping
ping: cannot resolve Host name lookup failure

lynx
Alert!. Unable to access document.

也许是我的系统上没有安装DNA域名解析功能的缘故,我再使用IP地址试一下:

lynx 216.136.204.21

这次我发现自己在的主页上了。

阅读(876) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~