分类: BSD
2008-04-03 17:11:05
options IPFIREWALL options IPFIREWALL_VERBOSE options “IPFIREWALL_VERBOSE_LIMIT=100” options IPFIREWALL_DEFAULT_TO_ACCEPT options IPDIVERT |
其中第一项设置IPFIREWALL是用于打开基本的包过滤支持的,只有使用它才能在内核中支持包过滤。IPFIREWALL_VERBOSE 和IPFIREWALL_VERBOSE_LIMIT设置记录过滤日志,及日志记录的限制。IPFIREWALL_DEFAULT_TO_ACCEPT是设置IPFIREWALL的缺省行为,在数据包不符合所有的过滤规则的情况下进行转发,显然这是一种宽松的限制,此时系统主要用于屏蔽特定地址和特定服务,而提供其他的缺省网络能力。如果没有定义这个选项,系统就只能允许符合已定义规则的数据包通过,而屏蔽其他任何数据包,这样在没有定义过滤规则的情况下,系统不能和其他计算机相互通信。最后一个选项IPDIVERT是用于定义IPFIREWALL与natd的接口。
当编译安装了内核之后,还需要设置内核具备数据包的转发能力。需要在rc.conf中设置gateway_enable 的值为YES,这样就能在系统启动时自动打开包转发能力。也可以直接执行下面命令来打开内核包转发能力。
# sysctl -w net.inet.ip.forwarding=1 |
IPFIREWALL的过滤规则是由ipfw命令来设置的,例如下面的规则允许所有127.0.0.1的数据传输。
# /sbin/ipfw add 1000 pass all from 127.0.0.1 to 127.0.0.1 |
ipfw命令中,首先指定对这个规则的处理方式,ipfw add为向内核中的过滤规则中添加,此外,ipfw delete用于删除一条规则,ipfw list用于显示当前定义的所有过滤规则,ipfw flush将清除所有的过滤规则,而ipfw file用于从文件file中读取定义的过滤规则。
此外,ipfw定义的规则都有自己的序号,其序号可以在处理方式之后指定,如ipfw delete 1000 就是删除第1000条过滤规则,内核中可以同时支持65535条过滤规则。有时可以不使用规则的序号,那么ipfw 就处理当前规则,而处理过一次规则之后,就立即将当前规则序号增加100,这样就对于添加过滤规则时十分方便,不必指定序号,ipfw add将每隔100添加一条过滤规则。
每个过滤规则中,要首先给出这条规则的处理指令,allow指令(或者使用同义词pass, permit,accept)为许可某类数据包通过;deny指令(或同义词drop)为不允许某类数据包通过,将该类数据包丢弃; reject指令与deny指令有所不同,但它不是简单的将数据包丢弃,而是在丢弃原有数据包的同时,回应ICMP host unreachable,通知发送计算机不能通过它与目的计算机进行通信,这样就免得发起连接请求的计算机一直发送连接请求,造成不必要的数据流量。使用count指令能对该类数据包进行简单记数,这个功能主要用于对网络使用进行记帐。log指令用于将连接发送到系统的日志记录中。
其中count和log指令与其他指令不同,其他指令都是对数据包进行处理的指令,因此每个数据包只要匹配这个指令,就立即将数据包或转发,或丢弃,不再进行其他处理,而count和log只是记录指令,只是将记录下这个数据包,而数据包本身还将继续受到其他过滤规则的处理。
过滤规则的第二部分是规定数据包的协议类型,指定规则是用于处理哪种数据包的,FreeBSD可以处理TCP,UCP,ICMP 类型的数据,以及在/etc/protocols文件中定义的其他数据包的类型,上例中使用all ,匹配所有类型的数据包。对于TCP或UDP,还可以在后面定义地址时指定应用的端口号(可以使用数字或/etc/services 中定义端口名字),进一步增加过滤能力。
过滤规则的第三部分是规定过滤规则适用的地址范围,这可以通过指定源和目的计算机的IP地址范围或数据包通过的网络界面来进行指定。
例如:屏蔽任何来自192.168.1.5的数据的指令为:
# ipfw add deny all from 192.168.1.5 |
而许可来自192.168.1.0网络上的远程登录的指令为:
# ipfw add allow tcp from 192.168.1.0/24 telnet |
应用过滤规则的顺序是按照过滤规则的序号,从小到大进行匹配,一旦一个数据包匹配一个过滤规则,就立即按照该规则转发或丢弃,不再需要继续考虑以下的规则(count和log规则除外)。因此在前面的例子中,192.168.1.5 就不能使用telnet连接,因为首先碰到的是不允许的规则,如果两个命令次序相反,则它就能够进行telnet连接。
最后一条过滤规则,第65535条规则,缺省被设为”deny all from any to any”时,为不允许对任何连接,此时在没有定义其他规则之前,不允许所有的网络连接。但是编译内核时使用IPFIREWALL_DEFAULT_TO_ACCEPT 选项,就能将这条规则改为”allow all from any to any”,允许转发不符合其他规则的所有数据。这两种不同的设置属于两种不同的考虑方式,一种适用于安全性要求较高的系统中,缺省情况不允许外界连接,另一种主要限制部分节点的访问,缺省情况允许任意网络连接,普通系统使用这样的设置更多些。
当启动了系统的包过滤能力之后,就需要在系统启动时将这些过滤规则自动载入内核,可以将这些添加过滤规则的指令写入启动文件rc.local或者其他启动文件中。但系统的启动文件中本来就具备载入这些过滤规则的相关启动文件 rc.firewall,这个文件中根据防火墙的基本要求,设置了常用的过滤规则,可以减轻防火墙管理员的设置工作。
为了让系统执行rc.firewall中的设置,需要在rc.conf中设置参数firewall为YES,以及设置firewall_type的值,这个参数值将传递给rc.firewall,使rc.firewall执行不同的设置。一般情况下可以将firewall_type设置为open,对网络访问不进行限制,而client主要用于计算机不对外提供网络服务,保护本计算机只用于访问外部系统而拒绝所有的访问请求,设置为simple则定义了简单的防火墙规则,可以使用这台计算机保护防火墙内部的计算机,这三个选项比较常用。下面为缺省rc.firewall 中的有关过滤规则的设置。
############ # Define the firewall type in /etc/rc.conf. Valid values are: # open - will allow anyone in # client - will try to protect just this machine # simple - will try to protect a whole network # closed - totally disables IP services except via lo0 interface # UNKNOWN - disables the loading of firewall rules. # filename - will load the rules in the given filename (full path required) # # For ``client'' and ``simple'' the entries below should be customized # appropriately. |
这里解释了rc.conf中对firewall参数的可能设置值,可以设置为不同的设置值,或者可以使用一个文件名作为firewall_type的值,指定一个包括了ipfw规则的文件,而设置使用者自己定制的过滤规则。
############ # Only in rare cases do you want to change these rules $fwcmd add 100 pass all from any to any via lo0 $fwcmd add 200 deny all from any to 127.0.0.0/8 |
这两个规则用于设置本地网络lo0的数据包能进行传输,但屏蔽所有从其他网络界面通向本地网络lo0的通信。这是最基本的设置,防止在路由或IP地址设置不正确的情况下,外部计算机访问127.0本地网络。
# Prototype setups. if [ "${firewall_type}" = "open" -o "${firewall_type}" = "OPEN" ]; then $fwcmd add 65000 pass all from any to any |
设置open为防火墙的类型时,即使没有设置IPFIREWALL_DEFAULT_TO_ACCEPT内核选项,也允许对数据包进行转发,因为这里设置的规则序号为65000,小于缺省的65535规则。
elif [ "${firewall_type}" = "client" ]; then ############ # This is a prototype setup that will protect your system somewhat against # people from outside your own network. ############ # set these to your network and netmask and ip net="192.168.4.0" mask="255.255.255.0" ip="192.168.4.17" |
当设置了client为防火墙的类型,那么就需要更改这里的IP地址和子网掩码的设置,使其符合自己计算机的实际情况。client类型主要用于单机系统,保护本机不受外部计算机侵袭的设置。它的保护与tcpwrapper类似,但比tcpwrapper更为基本和高效,但是它不能提供详细的连接记录日志。
# Allow any traffic to or from my own net. $fwcmd add pass all from ${ip} to ${net}:${mask} $fwcmd add pass all from ${net}:${mask} to ${ip} |
这两个规则用于许可计算机与本地网络的通信。
# Allow TCP through if setup succeeded $fwcmd add pass tcp from any to any established |
上面这两个规则允许连接已经设定成功的TCP连接的数据包能够保持连接,数据传输能够继续进行。 established参数就用于说明数据包为已经设置成功的TCP连接数据包。
# Allow setup of incoming email $fwcmd add pass tcp from any to ${ip} 25 setup |
允许外部计算机能向内地smtp端口发起连接请求,setup用于说明定义的数据包为请求连接的数据包。
# Allow setup of outgoing TCP connections only $fwcmd add pass tcp from ${ip} to any setup |
允许本地计算机能向外部网络发起连接请求。
# Disallow setup of all other TCP connections $fwcmd add deny tcp from any to any setup |
此后屏蔽所有其他种类的TCP连接请求数据包,因此如果要打开其他TCP连接请求,就需要在这个规则之前进行定义。
# Allow DNS queries out in the world $fwcmd add pass udp from any 53 to ${ip} $fwcmd add pass udp from ${ip} to any 53 # Allow NTP queries out in the world $fwcmd add pass udp from any 123 to ${ip} $fwcmd add pass udp from ${ip} to any 123 # Everything else is denied as default. |
此后定义对UDP数据包的过滤规则,只许可DNS和NTP协议通过,而屏蔽其他UDP数据包。
上面这些指令都是client类型的过滤规则,综合上面的指令,这就表示为屏蔽外部计算机向本地除smtp之外的TCP连接请求,而允许本地计算机向外发起连接请求,屏蔽除DNS和NTP之外的其他UDP数据包。这些过滤规则可以有效的保护一个不对外提供服务的客户系统。但是,如果要对外提供网络服务,就需要更改这里的设置,打开需要提供服务的端口,例如打开TCP端口22,以使得ssh客户能连接到系统中。
elif [ "${firewall_type}" = "simple" ]; then ############ # This is a prototype setup for a simple firewall. Configure this machine # as a named server and ntp server, and point all the machines on the inside # at this machine for those services. ############ # set these to your outside interface network and netmask and ip oif="ed0" onet="192.168.4.0" omask="255.255.255.0" oip="192.168.4.17" # set these to your inside interface network and netmask and ip iif="ed1" inet="192.168.3.0" imask="255.255.255.0" iip="192.168.3.17" |
防火墙类型simple用于设置一个简单的防火墙系统,用于保护内部网络中的计算机。由于防火墙系统需要连接多个网络界面,一个用于连接外部网络,而其他用于连接内部网络。这个简单的防火墙只针对两个网络界面进行了过滤规则的设置,内部网络的界面iif,外部网络的界面oif,因此它只适合只有两个网络界面的防火墙系统。
当真正要使用这个防火墙设置的时候,首先就要修改iif与oif的IP地址,网络掩码等相关设置,与本地系统实际使用的设置相同。
# Stop spoofing $fwcmd add deny all from ${inet}:${imask} to any in via ${oif} $fwcmd add deny all from ${onet}:${omask} to any in via ${iif} |
这两个过滤规则用于丢弃涉及IP地址欺骗的数据包,这包括来自于外部网络界面,但源地址为内部网络地址,或者来自于内部网络界面,但源地址为外部网络地址的数据包。由于这些数据包涉及IP地址欺骗,每个路由器都应该丢弃这样的数据包。
# Stop RFC1918 nets on the outside interface $fwcmd add deny all from 192.168.0.0:255.255.0.0 to any via ${oif} #$fwcmd add deny all from any to 192.168.0.0:255.255.0.0 via ${oif} $fwcmd add deny all from 172.16.0.0:255.240.0.0 to any via ${oif} $fwcmd add deny all from any to 172.16.0.0:255.240.0.0 via ${oif} $fwcmd add deny all from 10.0.0.0:255.0.0.0 to any via ${oif} $fwcmd add deny all from any to 10.0.0.0:255.0.0.0 via ${oif} |
RFC1918中定义了一些只用于内部网络的IP地址,这些地址不能用于Internet上的计算机,而只能用于内部网络中。这里禁止从外部网络界面上向内部地址进行数据传输,以防止外部网络向内部网络的地址进行连接,也是防火墙的重要功能之一。
注意,上例中与系统提供的缺省设置是不同的,将其中对应于实际使用的内部地址的一行加上了注释。这是因为该设置与natd相互冲突,使得natd发送的数据(具备内部网络地址)也被过滤。可以简单的注释对应本地网络地址的设置项,以使得它们能够相互协议,而将保护功能留给natd来完成。如果不使用natd,就不必使用上面的注释。
# Allow TCP through if setup succeeded $fwcmd add pass tcp from any to any established # Allow setup of incoming email $fwcmd add pass tcp from any to ${oip} 25 setup # Allow access to our DNS $fwcmd add pass tcp from any to ${oip} 53 setup # Allow access to our WWW $fwcmd add pass tcp from any to ${oip} 80 setup # Reject&Log all setup of incoming connections from the outside $fwcmd add deny log tcp from any to any in via ${oif} setup # Allow setup of any other TCP connection $fwcmd add pass tcp from any to any setup |
此后屏蔽除了email,www,dns之外的其他向内部网络的TCP连接请求,而只允许向外进行连接。当实际内部网络要向外提供服务时,再添加连接许可。
# Allow DNS queries out in the world $fwcmd add pass udp from any 53 to ${oip} $fwcmd add pass udp from ${oip} to any 53 # Allow NTP queries out in the world $fwcmd add pass udp from any 123 to ${oip} $fwcmd add pass udp from ${oip} to any 123 # Everything else is denied as default. |
然后定义UDP连接的限制,同样也只允许DNS和NTP数据包通过,这可以用于屏蔽类似BO之类的远程操纵程序。
elif [ "${firewall_type}" != "UNKNOWN" -a -r "${firewall_type}" ]; then $fwcmd ${firewall_type} fi |
如果使用者喜欢自己定制过滤规则,而不是在系统提供的规则基础上更改,那么可以将规则放入一个文件中,在rc.conf文件中设置firewall_enable=”YES”的基础上,将firewall_type的值改为放置ipfw规则的文件名。这样系统启动时就能够使用ipfw自动执行这些配置。但如果只是对过滤规则的少量更改,就可以直接修改rc.firewall文件。
natd与ipfw相互配合,能够实现网络地址翻译的能力。内核通过一个特定的divert类型的端口,将需要转换的数据包交给natd,而natd转换之后,再发送回内核,由内核再进行转发。它的好处不但是能提供防火墙能力,还能使得内部计算机能共享外部网络地址,这在IP地址空间比较紧张的当前是一个非常有用的技术。
当应用网络地址翻译时,可供选择的内部IP有:10.0.0.0到10.255.255.255,172.16.0.0到 172.31.255.255,192.168.0.0到192.168.255.255。这些地址由RFC1918中定义为内部地址,不会出现在Internet上。
FreeBSD下有几种软件能实现部分或全部NAT功能,功能最简单的是用户级ppp提供的alias功能,使用alias参数启动ppp将使ppp将所有来自其他网络介面的数据包中的源IP地址改变为tun0网络界面的IP ,转发到ppp连接上去。这种IP伪装的方式虽然功能简单,但对于拨号将内部网络和Internet连接的用户非常适合。
设置natd需要以下的步骤,首先设置好包过滤支持,包括内核中的IPFIREWALL和rc.conf中的 gateway_enable参数设置。它需要内核支持IPDIVERT选项,如果没有设置这个选项,就需要重新编译支持这些选项的内核;然后需要为natd指定一个divert端口,用于接收和发送从内核转发过来的包。这需要在/etc/services 中增加一个divert端口的设置:
natd 8668/divert |
然后需要将所有的数据包都发送给相应的divert端口natd,然后由监听这个端口的守护进程natd 接收并转换。
# /sbin/ipfw -f flush # /sbin/ipfw add divert natd all from any to any via fxp0 # /sbin/ipfw add pass all from any to any |
上面的命令中使用了一个新的ipfw指令divert,这个指令就对符合这个规则的数据包通过divert规定的端口natd进行地址转换。但是divert指令和log和count指令相似,它并没有终止过滤规则,而是继续进行数据包过滤,只是此后的过滤将是针对转换后的数据包进行的了。
执行了这些ipfw指令之后,而由于还没有启动natd守护进程,那么网络的正常连接都不再能进行了,发送到 divert的端口natd的数据包就被丢掉。直到启动natd进程,通过它进行处理之后,数据包才会正常发送。
最简单的启动natd的指令为:
# natd -interface fxp1 |
此时,natd将内部的向外连接中的内部地址转换为fxp1上的IP地址,而内部网络的计算机必须设置这个防火墙为它们的路由器,以便将数据包交给它进行转发。但由于整个网络对外只表现为一个地址,外部网络并不需要了解这台防火墙的路由能力。
如果要在系统启动时自动设置地址转换,就需要将这些ipfw/natd的过滤规则与系统启动文件结合在一起。缺省的启动文件已经支持了ipfw/natd,因而仅仅需要打开启动文件中相关设置就可以了。这不但需要在rc.conf 中设置gateway_enable,firewall_enable,还需要设置natd_enable为YE S,以使得自动启动natd守护进程,还需要指定natd使用的网络界面natd_interface的值,帮助将正确的数据包发送给natd,并使系统执行natd时使用正确的参数。而设置项natd_flags用来指定其他natd 需要的参数,例如用于指定natd设置文件等,简单情况下不需要使用这个设置项。
当打开natd_enable时,将在其他过滤规则之前添加这个过滤规则,但是其他规则同样也会生效,因为当数据包从natd发送回系统之后,系统再对其应用过滤规则。
不过,由于在natd转换IP地址之后还应用过滤规则,因此这些数据包还有可能被过滤。尤其在同时设置了 firewall_type为simple以执行rc.firewall中的防火墙过滤设置的时候,就需要注意其中与na td相冲突的设置。simple过滤规则中存在屏蔽外部计算机对RFC1918规定的IP地址进行访问的设置,然而n atd将正常通信的数据包中的地址转换为了内部IP地址,因而缺省设置将阻止这些数据包发送到内部计算机中。
为了和natd协作,必须修改其中过滤设置,以保证经natd转换过的数据包能发到内部计算机上。一般情况下,可以简单的rc.firewall将针对发送到本地网络的过滤规则设置注释掉就可以了,而从本地网络发送到外部网络的数据包在应用过滤规则之前,就已经进行完地址转换了,因此就不受规则影响。前一部分中介绍rc.firewall时,给出了进行注释的例子。另一种方法是调整过滤规则和顺序,将屏蔽这些内部地址的规则放置到divert指令之前。
使用-interface参数(或者使用其简写形式-n)启动的natd,可将所有内部网络向外的请求转换为该interface界面使用的IP地址,与外界进行通信。这种方式中,所有的连接中的内部地址不但转换的IP地址,同时也要转换端口地址,以避免地址冲突,并且外部网络只能连接到防火墙,而不能访问内部计算机上的服务。natd还有种种高级设置,使得系统能使用更复杂的地址转换功能。更复杂的情况是防火墙拥有一个合法子网,具有多个可利用的IP地址,此时防火墙对外表现为一个路由器,负责一个内部子网。
使用natd时,计算机至少必须拥有一个合法的外部地址,用于将内部地址转换为外部地址时使用,当使用 -interface时,这个值被设置为该网络界面绑订的IP地址,如果该网络界面上的IP地址可能改变(例如它被设置为d hcp客户端,或者是PPP连接),-dynamic参数能使natd跟踪该界面上的地址更改。如果不使用-interface 参数指定网络界面,就必须直接使用-alias_address指定natd使用的外部IP地址。alias_address 定义的地址可以是防火墙本身外部网络界面上拥有的合法IP地址之一,也可以是作为路由器的防火墙的内部网络所拥有的合法IP地址之一。
natd可以使用-redirect_address参数,设置静态IP地址转换,例如使用参数”-redirect_address iip oip”,将内部地址iip与外部地址oip进行映射,则所有发送给oip的连接将被转给内部的iip。
# natd -alias_address 202.102.245.60 -redirect_address 192.168.3.2 202.102.245.17 |
上面的命令将使得防火墙使用202.102.245.60作为内部计算机向外连接的缺省地址,而192.168.3.2 被映射为202.102.245.17,可以允许外部网络上的计算机对其进行访问。
此时外部网络应该将发送往这两个ip地址的数据都发送到这个防火墙上,一般情况下这个防火墙应对外表现为一个路由器,负责将包括这两个IP地址在内的网络连接到外部网络上,而外界网络上的路由器也具有达到它的正确路由。但也可以通过Proxy ARP或在防火墙外部网络界面上绑订多个ip地址的方法来实现。
为了让外部路由器了解这个防火墙负责的网络,除了在外部路由器上设置静态路由之外,还可以使用动态交换路由协议,将防火墙的路由数据与外部路由器动态交换。这就需要使用与外部路由器相同的路由交换协议,常用的内部路由交换协议有rip, rip 2,以及ospf,其中routed用于支持rip协议,而gated可以支持其他种类的协议。由于路由交换协议是整个网络统一规定的,因此必须根据统一使用。
另一个非常有用的参数是-redirect-port,它是用于将对某个IP地址固定端口的连接请求,转发至指定内部计算机中。这个参数非常灵活,针对tcp或udp进行设置。例如将对-alias_address定义地址的 http请求转发到内部地址192.168.3.3的另一个端口8080上。
# natd -alias_address 202.102.245.60 -redirect_port tcp 192.168.3.3:8080 80 |
当然也可以为其他地址,如202.102.245.17,设置映射。
# natd -alias_address 202.102.245.60 \ -redirect_port tcp 192.168.3.3:8080 202.102.245.17:80 |
进一步可以使用-redirect_port为特定的外部计算机的特定连接进行映射。
还可以使用-f或-config参数指定natd的配置文件,从文件中而非从命令行读取natd的设置,使得设置更为清晰明了。下面的设置文件例子中使用了另外几个很有用的参数。
alias_address 202.102.245.60 deny_incoming yes unregistered_only yes same_ports yes use_sockets yes |
deny_incoming用于拒绝向alias_address发起的所有连接请求,用来保护网络内部安全,这个参数可以和-redirect_port参数结合,控制提供的网络服务。
unregistered_only用于只对RFC1918定义的内部网址进行地址转换,防止出现错误设置影响正常的路由设置。
same_ports在网络转换时尽量选择与原有数据包相同的端口,这样来保证一些与端口相关的服务能够被尽可能满足,但这并不表示普通的地址转换会百分之百使用同样的端口,在将多个内部转换为一个外部地址时,总会有端口冲突发生的可能,真正要避免冲突,还必须使用-redirect_port直接指定。
use_sockets允许natd查看ftp、irc等连接的数据内部,以根据内容设置正确的端口,这将占用较多的系统资源,因此一般不要使用这个选项。然而和same_port协作使用,可以支持更复杂的客户程序。
其他还有一些设置选项,如log参数指定natd将日志记录到/var/log/alias.log文件中, dynamic参数用于和interface参数协作,跟踪网络界面的IP地址改变的信息,等等。
在设置文件中指定的参数,其形式与在命令行中使用的方式相似,不同之处在于有的参数在配置文件中需指定yes 或no,而在命令行中不需特别指定就意味着使用了yes属性。如直接使用-log而非-log yes。设置好这个设置文件之后,就可以启动natd了。
# natd -f filename |