随着ISP开始向用户提供高速的Internet连接,普通小型企业及计算机用户要建立自己的Web服务器、FTP服务器或者Mail服务器,就变得非常的容易。但是,如果ISP出现错误的话,我们将怎么办呢?一个最常用的解决方法就是进行另外一个ISP的冗余连接。本文将介绍使用一个Linux主机来完成Internet冗余连接,主要有以下内容:
1.配置主机,使其可以处理多个ISP的流入信息。
2.网络流出连接的负载平衡。
3.配置各种服务以实现冗余。
4.使用ipchains或者iptables配置防火墙。
图1描述了小型企业或家庭计算机网络的结构。在图中,Linux是作为Internet和内部局域网两个部分之间的防火墙。在本例中,网卡eth1使用的DSL,网卡eht2使用的是线缆modem。Linux主机通过和两个ISP的连接实现负载平衡,这种方法不仅仅适用于高速网络连接。同样的技术也可以用于在两个拨号连接间实现负载平衡。
图1 实现Internet冗余连接的Linux主机
在图1中测试用的主机使用的是CPU为Intel Celeron 533MHz的计算机,操作系统使用的是Red Hat 6.2,内核为2.2.18。本文所述方法在内核为 2.4.13的Red Hat 7.2中也测试通过。不过,读者在实际应用中,不一定非得使用533MHz的CPU,事实上,在本例中,用一台老的配置有32M内存的Pentium 100机器作为防火墙也完全可以。此外,本文中一些例子虽然是针对Red Hat的,不过,只需稍加修改,就可用于其它Linux发行版。
在本文中,我没有提供网卡配置、Linux内核编译以及DNS配置等内容。因为这方面的信息在网上或者书店里都有大量的资料。此外,读者也可以到http://www.linuxdoc.org去查找一些相关的资料。
配置内核
Linux内核2.2以及更高版本支持高级路由技术,它可以在一个Linux主机中实现负载平衡和多个缺省的路由。为了支持多个Internet连接,在编译时必需加入下面几个内核网络选项:
CONFIG_IP_ADVANCED_ROUTER=y
CONFIG_IP_MULTIPLE_TABLES=y
CONFIG_IP_ROUTE_MULTIPATH=y
如果要想使用新内核中的高级路由功能,那么就必需要安装ip路由工具包(在Red Hat 7.1以上版本中均带有该工具包),如果没有该工具包,可以从以下地址下载:
ftp://ftp.inr.ac.ru/ip-routing/
ip路由工具包提供了两个专门的命令:ip和tc用于实现高级的路由功能,有关ip命令的文文件可查看以下地址:
http://snafu.freedom.org/linux2.2/docs/ip-cref/ip-cref.html
源IP路由
缺省情况下,TCP/IP数据包是通过检测目的IP地址,然后在路由表中查找一个到达目的地的路径。路由表可以通过netstat –r command命令来查看。如果发现了一个路径,数据包就会被送到网卡,否则,数据包就会被送到缺省的网关。对于大多数直接连入Internet的主机来说,缺省网关一般是某一个ISP。在本例中,这就意味着所有向外的Internet连接都通过DSL接口。这不是一个冗余Internet连接所希望发生的。很显然,当你在系统中加入一个线缆Modem后,你并不希望由DSL连接来响应你的线缆Modem连接。
要解决这个问题,我们使用ip命令建立一个多路由表。而路由表的选择是基于流出数据包的IP地址的。这可以通过以下的命令来实现:
# Setup source IP routing rules for DSL
ip rule add from 63.89.102.157 lookup 1
ip route add 10.0.0.0/24 via 10.0.0.1 table 1
ip route add 0/0 via 63.89.102.1 table 1
# Setup source IP routing rules for cable modem
ip rule add from 65.3.17.133 lookup 2
ip route add 10.0.0.0/24 via 10.0.0.1 table 2
ip route add 0/0 via 65.3.17.1 table 2
如果一个流出的数据包的源IP地址为63.89.102.157 (DSL),那么就在路由表1中选择,它有两条路径:
> ip route list table 1
10.0.0.0/24 via 10.0.0.1 dev eth0
default via 63.89.102.1 dev eth1
第一行把本地数据流路由到内部网,第二行则捕获所有剩下的数据包并通过DSL接口将其送到ISP。线缆Modem的路由表2使用的也是同样的方法。
负载平衡
在内部网中实现流出负载平衡,使用的是CONFIG_IP_ROUTE_MULTIPATH内核选项,它可以让系统有多个默认的网关。可以使用以下命令从/etc/sysconfig/network文件中删除默认网关,然后再使用高级路由功能设置缺省网关:
# ip route add default equalize
nexthop via 63.89.102.1 dev eth1
nexthop via 65.3.17.1 dev eth2
要查看高级路由表,使用以下命令:
> ip route list
255.255.255.255 dev eth0 scope link
255.255.255.255 dev eth2 scope link
255.255.255.255 dev eth1 scope link
10.0.0.1 dev eth0 scope link
63.89.102.157 dev eth1 scope link
65.3.17.133 dev eth2 scope link
10.0.0.0/24 dev eth0 proto kernel scope link src 10.0.0.1
63.89.102.0/24 dev eth1 proto kernel scope link src 63.89.102.157
65.3.17.0/24 dev eth2 proto kernel scope link src 65.3.17.133
127.0.0.0/8 dev lo scope link
default equalize
nexthop via 63.89.102.1 dev eth1 weight 1
nexthop via 65.3.17.1 dev eth2 weight 1
CONFIG_IP_ROUTE_MULTIPATH内核选项将把所有这些路径(缺省路由)等同看待,然后再根据/usr/src/linux/Documentation/Configure.help来选择其特定的方式。Ip route命令的equalize选项,会让Linux内核基于IP地址平衡外部连接。对于一个特定的IP地址,内核会选择一个接口用于传输流出的数据包,然后内核会为该IP地址在路由缓冲中建一个记录。这样,其它到达的有相同IP地址的数据包就会使用同一个接口,直到该记录从路由缓冲中删除。我们可以使用ip route list cache命令来查看路由缓冲。
配置服务
各种不同的服务(DNS、SMTP、HTTP、LDAP、SSH等) 可以通过DNS循环来实现。减少每一个DNS记录里的TTL(存活时间),让远程系统只能缓冲IP信息30分钟。这样流入的信息就会分散在两个IP地址上。对于流入的SMTP连接,在DNS中添加了两个MX记录,这样如果一个接口关闭了,电子邮件将从另外一个接口传送。
你可以使用如下所示的dig命令来检查你的DNS配置:
> dig alphapager.org any
; <<>> DiG 8.2 <<>> alphapager.org any
;; res options: init recurs defnam dnsrch
;; got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 4
;; flags: qr rd ra; QUERY: 1, ANSWER: 9, AUTHORITY: 0, ADDITIONAL: 5
;; QUERY SECTION:
;; alphapager.org, type = ANY, class = IN
;; ANSWER SECTION:
alphapager.org. 30M IN A 63.89.102.157
alphapager.org. 30M IN A 65.3.17.133
alphapager.org. 30M IN NS ns.alphapager.org.
alphapager.org. 30M IN NS ns.herdejurgen.com.
alphapager.org. 30M IN SOA proxy.alphapager.org. \
root.proxy.alphapager.org. (
2001031000 ; serial
3H ; refresh
1H ; retry
1W ; expiry
30M ) ; minimum
alphapager.org. 30M IN MX 10 ns.herdejurgen.com.
alphapager.org. 30M IN MX 10 ns.alphapager.org.
;; ADDITIONAL SECTION:
ns.alphapager.org. 30M IN A 63.89.102.157
ns.herdejurgen.com. 30M IN A 65.3.17.133
;; Total query time: 98 msec
;; FROM: pandora to SERVER: default -- 192.168.100.1
;; WHEN: Sat Mar 10 22:15:22 2001
;; MSG SIZE sent: 32 rcvd: 326
所有的DNS记录(除了ns.alphapager.org和ns.herdejurgen.com)现在都被解析成了两个IP地址。比如:
> nslookup seann.herdejurgen.com
Server: proxy-in.alphapager.org
Address: 10.0.0.1
Name: seann.herdejurgen.com
Addresses: 65.3.17.133, 63.89.102.157
对于Apache,可以更改httpd.conf中的以下行来实现多个名字的虚拟主机:
NameVirtualHost 63.89.102.157:80
NameVirtualHost 65.3.17.133:80
Inbound LDAP and SSH traffic are distributed using round-robin DNS and require no special configuration.
启动脚本
为了支持我们的网络配置,必须对启动脚本进行一些更改。这里更改的脚本是指Red Hat的,不过我们很容易将其推广到其它的Linux发行套件。系统启动以后,ip rule命令只能被执行一次。我们可以把以下的行添加到/etc/rc.d/init.d/network脚本中来实现这一目的:
# Add non interface-specific static-rules
if [ -f /etc/sysconfig/static-rules ]; then
sh /etc/sysconfig/static-rules
fi
/etc/sysconfig/static-rules文件内容:
# Setup source IP routing rules
ip rule add from 63.89.102.157 lookup 1
ip rule add from 65.3.17.133 lookup 2
# Setup load balancing
ip route add default equalize
nexthop via 63.89.102.1 dev eth1
nexthop via 65.3.17.1 dev eth2
每一次对某个接口执行ifup后,都必须要执行ip route命令。我们可以在/etc/sysconfig/network-scripts/ifup-routes中添加以下行来实现该目的:
# Add any advanced routes
grep "^advanced " /etc/sysconfig/static-routes |
while read ignore dev args; do
if [ " $dev" = " $1" ]; then
/sbin/ip route add $args
fi
done
/etc/sysconfig/static-routes文件内容:
advanced eth0 10.0.0.0/24 via 10.0.0.1 table 1
advanced eth0 10.0.0.0/24 via 10.0.0.1 table 2
advanced eth1 0/0 via 63.89.102.1 table 1
advanced eth2 0/0 via 65.3.17.1 table 2
防火墙
我们都知道,出于安全性的考虑,只要主机连接在Internet上,就应该有一个防火墙阻止恶意的信息访问主机。设置防火墙时,首先决定哪一些服务可以通过Internet访问,然后关闭所有其它的服务。当然并不是说运行了防火墙就万事大吉了,事实上,任何一个你允许通过防火墙来访问的服务都可能有自己安全上的漏洞,所以你必须经常注意更新你的应用程序,以使其具有最新的补丁。
大部分防火墙只支持外部网和内部网有单一的连接。因此,要支持多个外部网接口,就必须要自己写一些防火墙脚本。第一个用于编写脚本的工具是基于数据包的ipchains,它随Linux 2.2内核一起发行。第二个工具是基于数据包的iptables,它随2.4版的内核一起发行。
Iptables是ipchains的下一代,因其支持连接跟踪,所以功能更加强大。Iptables的可扩展性也非常不错,我们可以在不更改基本的源代码的前提下为它增加一些新功能(比如字符串匹配)。Ipchains和iptables都会把信息通过一系列的规则链,以决定是否接受或者拒绝接受该数据包。
Iptables 中使用了三个规则(或者称“链”)表(filter、nat和mangle)来过滤数据包。在ipchains中,三个对应的规则分别为INPUT、FORWARD和OUTPUT。INPUT分析刚到达网络接口的数据包,FORWARD分析经过伪装的数据包。而OUTPUT分析即将流出网络接口的数据包。图2描述的是ipchains防火墙中数据包通过不同的规则链的过程。
图2 ipchains数据包的传输过程
在iptables的nat表中,增加了两个规则,它们是PREROUTING和POSTROUTING。这些规则用于实现伪装以及网络地址翻译。所有流入或者流出的数据包都必须通过这些规则链。在iptables中INPUT和OUTPUT规则链用于处理去往防火墙的数据包,而FORWARD规则链则只用于处理数据包伪装。图3描述了数据包在iptables防火墙的不同规则链的过程。
图3 iptables数据包的传输过程
在iptables中,magle表使用PREROUTING和OUPUT链来让用户修改数据包中的IP标识,比如TTL或者TOS(服务类型)。
防火墙内核配置
要想建立起一个基于Linux 2.2内核的ipchains防火墙,必须在内核配置文件中配置以下的功能:
CONFIG_IP_FIREWALL=y
CONFIG_IP_MASQUERADE=y
CONFIG_IP_MASQUERADE_ICMP=y
CONFIG_IP_ROUTE_TOS=y
CONFIG_SYN_COOKIES=y
而要建立一个基于Linux 2.4内核的iptables防火墙,就必须在内核配置文件中配置以下功能:
CONFIG_IP_NF_IPTABLES=y
CONFIG_IP_NF_CONNTRACK=y
CONFIG_IP_NF_MATCH_LIMIT=m
CONFIG_IP_NF_MATCH_PSD=m
CONFIG_IP_NF_MATCH_STATE=m
CONFIG_IP_NF_MATCH_IPLIMIT=m
CONFIG_IP_NF_MATCH_STRING=m
CONFIG_IP_NF_FILTER=m
CONFIG_IP_NF_TARGET_REJECT=m
CONFIG_IP_NF_NAT=m
CONFIG_IP_NF_TARGET_MASQUERADE=m
CONFIG_IP_NF_TARGET_REDIRECT=m
CONFIG_IP_NF_MANGLE=m
CONFIG_IP_NF_TARGET_TOS=m
CONFIG_IP_NF_TARGET_LOG=m
CONFIG_IP_ROUTE_TOS=y
CONFIG_SYN_COOKIES=y
现在,这些核心功能中的一部分在主流Linux 2.4内核的版本中还不可用,不过它们可能作为补丁被添加进去。要把这些功能添加到内核中,必须安装Linux 内核2.4.13版本和iptables1.2.4版本,可以在以下网址获得源程序:
http://www.kernel.org/pub/linux/kernel/v2.4/linux-2.4.13.tar.gz
http://netfilter.filewatcher.org/iptables-1.2.4.tar.bz2
按以下步骤把iptables补丁加到内核中:
1、在/usr/src/linux目录下安装Linux 2.4.13,并运行它。
2、把iptables-1.2.4.tar.bz2解压到它自己的目录中。
3、iptables-1.2.4# make patch-o-matic
选择“yes”到以下补丁:
string
psd (port scan detection)
iplimit
因为并不是每个补丁都兼容,因此只选择需要的补丁即可。
4、iptables-1.2.4#开始安装
5、/usr/src/linux# make oldconfig
在CONFIG_IP_NF_MATCH选项时回答“m”。
6、重新编译内核并重启。
防火墙脚本
配置防火墙脚本的基本流程是依次设置INPUT、FORWARD和OUTPUT规则。Iptables防火墙脚本还要设置PREROUTING和POSTROUTING规则。各脚本都有注释,描述什么信息被接收或者拒绝。REJECT会忽略数据包并且给发送者返回一个ICMP信息,告诉他信息已经丢失。而DENY(ipchains)或者DROP(iptables)则在丢弃数据包后,不做任何回复。在有人探测主机的特定端口时,该功能可以让系统仿佛不存在,从而有效地保护系统。在本文的防火墙脚本中,设计成不给远程系统作响应。
要在Red Hat 7.1上配置防火墙脚本,先把脚本放在/etc/init.d/firewall中,然后执行以下命令:
# chkconfig firewall on
要为你的系统配置防火脚本,还必须编辑以下两行,以定义内部网和外部网的接口:
INT_IFACE="eth0"
EXT_IFACES="eth1 eth2"
INPUT规则链在防火墙上为服务开了一个口,所以对于特定的系统,你必须编辑服务列表 。在ipchains防火墙中,流入连接可以使用以下的行:
# ACCEPT TCP connections for various
# services found in /etc/services
for service in ftp ssh smtp domain
http auth ldap https; do
ipchains -A INPUT -i $EXT_IFACE -p tcp
-d $IP $service -j ACCEPT
done
防火墙脚本在不同的服务间循环,这在主机上是允许的。在本例中,这些服务是FTP、SSH、Sendmail、DNS、HTTP、ident、LDAP和HTTPS。这些基于TCP协议的名字和端口号可以在/etc/services文件中找到。
通过以下规则,在ipchains防火墙脚本中,INPUT链还可以接收任何源自本地的连接:
# ACCEPT non-SYN TCP packets on
# unprivileged ports (returns)
ipchains -A INPUT -i $EXT_IFACE -p tcp
! -y -d $IP 1024: -j ACCEPT
# ACCEPT all UDP packets on unprivileged ports
ipchains -A INPUT -i $EXT_IFACE -p udp -d $IP 1024:
-j ACCEPT
ipchains不支持连接跟踪,而iptables一个很大的改进即是支持这一功能。这就意味着数据包只有和一个活动的连接相符,才能被接收。在iptables防火墙脚本中使用以下规则来处理:
# ACCEPT return TCP/UDP traffic (stateful firewall)
iptables -t filter -A INPUT -m state
--state ESTABLISHED -i $EXT_IFACE
-p tcp -d $IP --dport 1024: -j ACCEPT
iptables -t filter -A INPUT -m state
--state ESTABLISHED -i $EXT_IFACE
-p udp -d $IP --dport 1024: -j ACCEPT
因为UDP是一个无状态协议,iptables连接跟踪维护一个状态表,并且只对源自内部网的信息作出响应。
Iptables防火墙脚本接受向内的连接并且根据下面所列的规则在连接跟踪数据库中加入一个新的连接:
# ACCEPT inbound TCP connections for various
# services found in /etc/services
for service in ftp ssh smtp domain
http auth ldap https; do
iptables -t filter INPUT -m state
--state NEW,ESTABLISHED -i $EXT_IFACE
-p tcp -d $IP --dport $service -j ACCEPT
done
我们可以通过查看/proc/net/ip_conntrack文件来查看连接跟踪。
以下iptables规则允许在TCP端口20上有主动模式的FTP连接请求:
# ACCEPT active FTP data connections on firewall
iptables -t filter -A INPUT -m state --state RELATED
-i $EXT_IFACE -p tcp -d $IP --dport 1024:
--sport ftp-data -j ACCEPT
在网络内部的连接,FORWARD规则会通过NAT把连接进行伪装。使用NAT,大部分协议都可以正常工作,只有很少一部分需要一个重写IP地址的模块。对于主动模式的FTP连接,需要一个辅助程序来通过防火墙。你可以使用modprobe命令加载ip_masq_ftp(ipchains)或者ip_nat-ftp(iptables)模块,以实现对主动FTP连接的伪装。这样,处于主动的FTP连接的远程机器,为了传输数据,会要求连接本地机。这时,ip_masq_ftp模块会重新修改FTP连接中的数据包,使得内部机器看起来就像是直接连接在Internet上一样。对于被动模式的FTP连接,可以使用TCP端口21来传输数据,以避开这个问题。值得注意的是,因为FTP的密码在网络上是以文本的形式传输的,所以并不安全。要建一个安全的FTP站点,可以使用sftp,它在通信时使用的是安全的套接字。Sftp随着OpenSSH客户端工具起发行。
对于各种应用程序的伪装模块,可以在/lib/modules/'uname -r'/ipv4 (ipchains) 或者/lib/modules/'uname -r'/ kernel/net/ipv4/netfilter/ (iptables)目录中找到。
FORWARD使用以下的iptables规则来伪装通过防火墙的数据包:
# ACCEPT new outbound traffic (stateful firewall)
iptables -t filter -A FORWARD -m state —state NEW,ESTABLISHED
-i $INT_IFACE -s $INT_NET -j ACCEPT
# ACCEPT return traffic (stateful firewall)
iptables -t filter -A FORWARD -m state —state NEW,ESTABLISHED,RELATED \
-i $EXT_IFACE -s ! $INT_NET -j ACCEPT
# Pass Internet traffic to internal network unmodified
iptables -t nat -A POSTROUTING -o $INT_IFACE -j ACCEPT
# Masquerading outbound connections from internal network
iptables -t nat -A POSTROUTING -o $EXT_IFACE -j MASQUERADE
OUTPU规则中还可以通过配置TOS(服务类型)标识来实现信息传输的先后次序。很多IPS都容易忽略TOS标识。事实上,由于CONFIG_IP_ROUTE_TOS内核选项判断信息流顺序时正是基于这一标识,所以这一标识非常有用。这就意味着,当一个交互式的应用程序(比如SSH)运行时,你可以让高带宽的应用程序(比如FTP)以最大的吞吐量运行,也不会使交互延迟。也就是说,可以让FTP不影响SSH连接的性能。
TOS标识在iptables防火墙mangle表中的PREROUTING和OUTPUT规则中设置。以下规则会让SSH数据包的延迟最小:
iptables -t mangle -A PREROUTING -j TOS
--set-tos Minimize-Delay -p tcp --dport ssh
iptables -t mangle -A OUTPUT -j TOS
--set-tos Minimize-Delay -p tcp --sport ssh
OUTPUT规则还可以限制系统对各种ICMP信息的响应。使用以下的配置,我们可以允许ICMP响应ping和traceroute,而不响应时间戳:
# ACCEPT various ICMP messages
for message in echo-reply destination-unreachable
source-quench redirect echo-request
time-exceeded parameter-problem; do
ipchains -A OUTPUT -p icmp -s 0/0 $message -j ACCEPT
done
防火墙的维护
要检查防火墙规则的效率,可以使用以下命令来执行防火墙脚本:
# ./firewall status
该命令输出的结果中,如果前两列是零,那么就意味着没有与规则相符的数据包。DENY和DROP规则的零意味着没有人试图得用特定的规则对你进行攻击。ACCEPT规则的零意味着没有接受符合该规则的信息。
如果想查找防火墙规则的错误,那么务必要要在ipchains命令后加上-l选项,这样就可把REJECT和DENY规则的信息写入/var/log/messages文件。Iptables防火墙脚本会创建一个特别的规则链DROPLOG,它将会记录被拒绝的数据包。做为管理员,应该经常查看这些信息,以发现潜在的攻击者。
结束语
以上说了那么多,你是不是有点犯晕,没关系,如果你在实际中,亲身实践一遍,你可能会说,不过如此。 (伊利贵)