上一篇讲了iptables防火墙对于单个主机的应用,现在来学习一下将iptables防火墙作为网关防火墙使用。这时iptables防火墙不仅仅是保护一台主机了,而是保护整个网络,充当网关这样的角色。责任相当更加重大,同时需求也提升了很多。
linux防火墙的NAT功能
    有关NAT地址转换的知识在这里就不多说了,我们知道这个一般都是在路由器上实现的,而linux主机同样可以实现这个功能。iptables防火墙中有3张内置的表:filter、nat和mangle,其中的nat表实现了地址转换的功能。nat表包含PREROUTING、OUTPUT和POSTROUTING 3条链,里面包含的规则指出了如何对数据包的地址进行转换。
1、SNAT
    源NAT的规则在POSTROUTING链中定义。这些规则的处理是在路由完成后进行的,可以使用"-j SNAT"目标动作对匹配的数据包进行源地址转换。如果希望内网10.10.1.0/24出去的数据包其源IP地址都转换外网接口eth0的固定公网IP地址218.75.26.35,采用"-j POSTOUTING”目标动作,则需要执行以下iptables命令:
iptables -t nat -A POSTROUTING -s 10.10.1.0/24 -o eth0 -j SNAT --to-source 218.75.26.35
以上命令中,"-t nat"指定使用的是nat表,"-A POSTROUTING"表示在POSTROUTING链中添加规则,"--to-source 218.75.26.35"表示把数据包的源IP地址转换为218.75.26.35,而根据-s选项的内容,匹配的数据包其源IP地址应该是属于10.10.1.0/24子网的。还有,"-o eth0"指定了只有从eth0接口出去的数据包才做源NAT转换,转换后的公网地址直接是eth0的公网IP地址。
**************************************************************************************
除了转换为eth0的公网地址外,也可以使用其他地址,例如,218.75.26.34。此时,需要为eth0创建一个子接口,并把IP地址设置为218.75.26.34,使用的命令如下所示:
ifconfig eth0:1 218.75.26.34 netmask 255.255.255.240
以上命令使eth0接口拥有两个公网IP。也可以使用某一IP地址范围作为转换后的公网地址,此时要创建多个子接口,并对应每一个公网地址。而"--to-source"选项后的参数应该以"a.b.c.x-a.b.c.y"的形式出现。**************************************************************************************
前面介绍的是数据包转换后的公网IP是固定的情况。如果公网IP地址是从ISP服务商那里通过ADSL拨号动态获得的,则每一次拨号所得到的地址是不同的,并且网络接口也是在拨号后才产生的。在这种情况下,前面命令中的"--to-source"选项将无法使用。为了解决这个问题,iptables提供了另一种称为IP伪装的源NAT,其实现方法是采用"-j MASQUERADE"目标动作,具体命令如下所示。
iptables -t nat -A POSTROUTING -s 10.10.1.0/24 -o ppp0 -j MASQUERADE
以上命令中,MASQUERADE意为伪装,ppp0是拨号成功后产生的虚拟接口,其IP地址是从ISP服务商那里获得的公网IP。"-j MASQUERADE"表示把数据包的源IP地址改为ppp0接口的IP地址。
2、DNAT
    目的NAT改变的是数据包的目的IP地址,当来自Internet的数据包访问NAT服务器网络接口的公网IP时,NAT服务器会把这些数据包的目的地址转换为某一对应的内网IP,再路由给内网计算机。这样,使用内网IP地址的服务器也可以为Internet上的计算机提供网络服务了。如果大家学习过硬件防火墙的话,会知道有一个DMZ区域,可以将内部对外的服务器放在这个区域映射出去。同理,iptables防火墙也可以实现同样的功能。"-j DNAT"指定了目标动作是DNAT,表示要对数据包的目的IP进行修改,它的子选项"--to 10.10.2.3"表示修改后的IP地址是10.10.2.3。于是,目的IP修改后,接下来将由路由模块把数据包路由给10.10.2.3服务器。假设IP为10.10.2.3的计算机需要为Internet提供网络服务,此时,可以规定一个公网IP地址,使其与10.10.2.3建立映射关系,采用"-j PREROUTING”目标动作。假设使用的公网IP是218.75.26.34,则配置目的NAT的命令如下:
iptables -t nat -A PREROUTING -i eth0 -d 218.75.26.34/32 -j DNAT --to 10.10.2.3
    以上是在PREROUTING链中添加规则,这条链位于路由模块的前面,因此是在路由前改变了数据包的目的IP,这将对路由的结果造成影响。由于网络接口eth0与Internet连接,因此,"-i eth0"保证了数据包是来自Internet的数据包。"-d 218.75.26.34/32"表示数据包的目的地是到218.75.26.34主机,而这个IP应该是eth0某个子接口的地址,这样才能由NAT服务器接收数据包,否则,数据包将会因为无人接收而丢弃。
    以上是让一个公网IP完全映射到内网的某个IP上,此时同10.10.2.3主机直接位于Internet,并且使用218.75.26.34地址是没有区别的。因此这种方式虽然达到了地址转换的目的,但实际上并没有带来多大好处,因为使用NAT的主要目的是为了能够共用公网IP地址,以节省日益紧张的IP地址资源。为了达到共用IP地址的目的,可以使用端口映射。端口映射是把一个公网IP地址的某一端口映射到内网某一IP地址的某一端口上去。它使用起来非常灵活,两个映射的端口其端口号可以不一样,而且同一个公网IP的不同端口可以映射到不同的内网IP地址上去。例如,主机10.10.2.3只为外网提供Web服务,因此,只需要开放80端口,而主机10.10.2.9为外网提供了FTP服务,因此需要开放21号端口。在这种情况下,完全可以把公网IP地址218.75.26.34的80号和21号端口分别映射到10.10.2.3和10.10.2.9的80号和21号端口,以便两台内网服务器可以共用一个公网IP。具体命令如下所示。
iptables -t nat -A PREROUTING -i eth0 -d 218.75.26.34/32 -p tcp --dport 80 -j DNAT --to 10.10.2.3:80 
iptables -t nat -A PREROUTING -i eth0 -d 218.75.26.34/32 -p tcp --dport 21 -j DNAT --to 10.10.2.9:21
    以上命令中,目的地址是218.75.26.34的TCP数据包。当目的端口是80时,将转发给10.10.2.3主机的80端口;当目的端口是21时,将转发给10.10.2.9主机的21号端口。当然,两个映射的端口完全可以不一样。例如,如果还有一台主机10.10.2.8也通过80端口提供Web服务,并且映射的IP地址也是218.75.26.34,此时需要把218.75.26.34的另一个端口,如8080,映射到10.10.2.8的80端口,命令如下:
iptables -t nat -A PREROUTING -i eth0 -d 218.75.26.34/32 -p tcp --dport 8080 -j DNAT --to 10.10.2.8:80 
注意:上面介绍的只是有关iptables中的DNAT配置,在实际应用中,还需要其他一些配置的配合才能真正成功。例如,filter表的3个链应该允许相应的数据包通过,应该为每一个外网IP创建eth0接口的子接口等。 
此外,对于FTP服务来说,由于21号端口只是建立控制连接时用到的端口,真正传输数据时要使用其他端口。而且在被动方式下,客户端向FTP服务器发起连接的端口号是随机的,因此,无法通过开放固定的端口来满足要求。为了解决这个问题,可以在Linux系统中载入以下两个模块:modprobeip_conntrack_ftp和modprobeip_nat_ftp。这两个模块可以监控FTP控制流,以便能事先知道将要建立的FTP数据连接所使用的端口,从而可以允许相应的数据包通过,即使防火墙没有开放这个端口。
实验案例
如图,RHEL-A是企业内网的一台服务器,RHEL-B是外网一台主机,RHEL-C是企业出口网关,Router代表运营商路由器。企业内部使用私有地址,网关处需要进行NAT转换才可以访问,RHEL-C的eth0接口只有一个公网IP。要求RHEL-A能够访问外网的RHEL-B,RHEL-B在浏览器上输入RHEL-C的外网IP时可直接访问RHEL-A的80端口(前提保证RHEL-A的http服务开启)。
RHEL5.7下iptabels防火墙配置(下)_第1张图片
首先在RHEL-C上开启路由功能
echo 1 >  /proc/sys/net/ipv4/ip_forward
1、在RHEL-C上做SNAT进行源地址转换
iptables -t nat -A POSTROUTING -s 192.168.10.0/24 -o eth1 -j SNAT --to-source 198.2.3.2
2、在RHEL-C上配置默认路由
route add -net 0.0.0.0 netmask 0.0.0.0 gw 198.2.3.1
3、在RHEL-B上配置默认路由
route add –net 0.0.0.0 netmask 0.0.0.0 gw 203.2.3.1
查看RHEL-C的nat规则表:
RHEL5.7下iptabels防火墙配置(下)_第2张图片
此时如果没有其他问题的话,RHEL-A是可以Ping通外网以及RHEL-B的。现在开通RHEL-B的vsftpd服务,用RHEL-A去访问
RHEL5.7下iptabels防火墙配置(下)_第3张图片
访问没有问题,在RHEL-B上查看进程连接
netstat–na | more
可以发现有下面这么一条记录:
p_w_picpath
说明RHEL-A是通过网关RHEL-C的外网IP 198.2.3.2对RHEL-B的21端口进行访问的,SNAT配置成功!
4、在RHEL-C上做DNAT,将RHEL-A的80端口映射出去
iptables -t nat -A PREROUTING -i eth1 -d 198.2.3.2/32 -p tcp --dport 80 -j DNAT --to 192.168.10.1:80
这时用RHEL-B的firefox浏览器访问http://198.2.3.2,如果成功显示RHEL-A的web页面,那么内部服务器映射外网是成功的,DNAT配置成功!
RHEL5.7下iptabels防火墙配置(下)_第4张图片