用IPIW实现BSD防火墙(上)
时间:2007-02-17 来源:PHP爱好者
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 www.freebsd.org
ping: cannot resolve www.freebsd.org: Host name lookup failure
traceroute www.freebsd.org
traceroute: unknown host www.freebsd.org
lynx www.freebsd.org
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的文件。
php爱好者站 http://www.phpfans.net PHP|MySQL|javascript|ajax|html.