多年来,我们在办公室使用的都是普通的ADSL——下载速度快,上传速度慢,延迟高——这样的链路费用是1美元/GB。我们在性能和可靠性方面有很多问题,经过几年的努力,我们决定获得第二个上游链路-SHDSL 5M/5M对称链路-低延迟,在7x24保持一致的速率。
然而,SHDS链路是昂贵的!虽然国内流量是免费的,但国际流量是5美元/GB。与国内和国际相同价格的1美元/GB的ADSL链路相比(表1)。
表1: ADSL链路 vs SHDSL链路
ADSL链路 | SHDSL链路 | |
速率 | 7Mbps下行/1Mbps上行 | 5Mbps下行/5Mbps上行 |
国内流量价格 | 1美元/GB | 免费 |
国际流量价格 | 1美元/GB | 5美元/GB |
两者都有明显的优缺点,这让我想到,如果我们把ADSL链路用于国际流量,而把SHDSL链路用于国内流量,那么不就能达到最优性价比了吗。如图2:
我们还将SHDSL链路用于DMZ区,显然,我们希望所有进出DMZ区的流量都通过SHDSL链路,不管它是国内的还是国际的。如图3:
为了实现我的计划,公司的核心路由器需要一些方法来决定从办公室内网到外网的流量是国际的还是国内的,并相应地通过ADSL链路或SHDSL链路转发它。路由器使用路由表来决定它们所转发的数据包的命运和路径。一个地址为192.168.130.100的办公室工作站的简单路由表看起来像这样:
[workstation] ~ # ip route show
192.168.130.0/24 dev eth0 proto kernel scope link src 192.168.130.100
default via 192.168.130.1 dev eth0
意思是说,到192.168.130.0/24范围内所有其他地址的所有流量都将直接发送到连接到接口eth0的本地网段。所有其他流量遵循“默认”路由,并移交给IP为192.168.130.1的路由器来处理它。让我们假设我们正在向谷歌的公共DNS服务器8.8.4.4发送一个包。对于初学者,我们尝试“ping 8.8.4.4”,并通过tcpdump观察工作站的eth0接口上的流量:
[workstation] ~ # tcpdump -i eth0 -n -s0 -e
listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes
[1] 17:53:59.615650 00:16:17:ec:5c:6c > ff:ff:ff:ff:ff:ff, ethertype ARP (0x0806), length 42:
Request who-has 192.168.130.1 tell 192.168.130.100, length 28
[2] 17:53:59.615775 00:14:c2:5b:4f:2c > 00:16:17:ec:5c:6c, ethertype ARP (0x0806), length 60:
Reply 192.168.130.1 is-at 00:14:c2:5b:4f:2c, length 46
[3] 17:53:59.615796 00:16:17:ec:5c:6c > 00:14:c2:5b:4f:2c, ethertype IPv4 (0x0800), length 98:
192.168.130.100 > 8.8.4.4: ICMP echo request, id 3082, seq 1, length 64
我的工作站查了路由表的目的IP地址8.8.4.4,意识到它应该把包发送到默认路由器192.168.130.1。为此,它需要路由器的底层以太网地址(也称为MAC地址),而上面tcpdump输出中的第一个包(标记为[1])正是这样做的——通过向网段上的所有节点“广播”请求来请求IP地址192.168.130.1的MAC地址。第二个包,标记为[2],是一个应答- IP地址192.168.130.1在MAC地址00:14:c2:5b:4f:2c。最后,PING包可以被发送,目的地为IP地址8.8.4.4到路由器的MAC地址00:14:c2:5b:4f:2c(标记为[3])。
很好,现在我们可以假设我们的路由器收到了数据包,并将它进一步转发到目的地。让我们看看路由器上发生了什么。
我们的路由器已经配置了ADSL链路和SHDSL链路,但默认情况下,所有流量都是通过ADSL链路转发的。ADSL链路的IP地址为192.168.128.254。目前,SHDSL链路203.0.113.36/30处于空闲状态。下面是路由表:
[router] ~ # ip route show
[1] 203.0.113.36/30 dev vlan-shdsl proto kernel scope link src 203.0.113.38
[2] 192.168.128.0/24 dev vlan-adsl proto kernel scope link src 192.168.128.1
[3] 192.168.130.0/24 dev vlan-office proto kernel scope link src 192.168.130.1
[4] default via 192.168.128.254 dev vlan-adsl
第一行[1]是SHDSL链路——我们的路由器在该链路上配置的IP地址是203.0.113.38。第二行[2]是ADSL链路,第三行[3]是我的办公内网工作站所在的网段,最后第四行[4]是默认路由。所有数据包不匹配任何本地子网在线路1,2或3的数据包被发送到ADSL链路的下一跳地址192.168.128.254,然后将他们转发给ISP 2。这也是8.8.4.4数据包的命运。我们通过调用ip route get来快速验证将会发生什么:
[router] ~ # ip route get 8.8.4.4 from 192.168.130.100 iif vlan-office
8.8.4.4 from 192.168.130.100 via 192.168.128.254 dev vlan-adsl
如你所见,它将被通过192.168.128.254转发,这是ADSL链路。检查从我的工作站到任何给定目标地址的完整网络路径的简单方法是traceroute命令。它显示了到达目的地的所有路由器:
[workstation] ~ $ /usr/sbin/traceroute 8.8.4.4
traceroute to 8.8.4.4 (8.8.4.4), 30 hops max, 40 byte packets using UDP
1 gw-vlan-office.e-it.co.nz (192.168.130.1) 0.156 ms 0.126 ms 0.124 ms
2 gw-vlan-adsl.e-it.co.nz (192.168.128.254) 0.853 ms 0.831 ms 0.830 ms
3 core-adsl.isp2 (218.101.x.y) 11.765 ms 19.173 ms 19.066 ms
4 core-xyz.isp2 (203.98.x.y) 16.052 ms 15.515 ms 17.153 ms
[... some more hops ...]
13 64.233.x.y (64.233.x.y) 193.826 ms 194.230 ms 194.412 ms
14 * * *
15 google-public-dns-b.google.com (8.8.4.4) 196.086 ms 195.909 ms 195.816 ms
如你所见,第一个跳是我们的路由器192.168.130.1。第二跳是ADSL链路192.168.128.254。第三跳是ISP2的核心路由器之一,以此为例,在数据包最终到达目的地8.8.4.4(即google-publicdns -b.google.com)之前,它还要经过11个路由器。
国内流量 vs 国际流量
谷歌的公共DNS服务器B显然是一个离岸国际目的地。然而,新西兰有一个根DNS服务器,即IP地址为192.5.5.241的f.root-servers.net。目前,到f.root-servers.net的traceroute仍然显示ADSL链路路径:
[workstation] ~ $ /usr/sbin/traceroute f.root-servers.net
traceroute to f.root-servers.net (192.5.5.241), 30 hops max, 40 byte packets using UDP
1 gw-vlan-office.e-it.co.nz (192.168.130.1) 0.175 ms 0.126 ms 0.125 ms
2 gw-vlan-adsl.e-it.co.nz (192.168.128.254) 0.861 ms 0.840 ms 0.825 ms
3 core-adsl.isp2 (218.101.x.y) 22.456 ms 22.298 ms 23.501 ms
4 isp2.ape.net.nz (192.203.154.x) 21.035 ms 20.928 ms 21.268 ms
5 isc2.ape.net.nz (192.203.154.y) 20.689 ms 21.724 ms 24.187 ms
6 f.root-servers.net (192.5.5.241) 26.680 ms 26.059 ms 25.427 ms
这显然是国际流量,按照我们的计划应该通过SHDSL链路出去。我们可以手动完成,并在核心路由器上设置合适的路由:
[router] ~ # ip route add 192.5.5.241 via 203.0.113.37 dev vlan-shdsl
关于NAT我们需要知道:我们还需要将办公室地址范围192.168.130.0/24转换(或“伪装”或NAT)到我们的SHDSL链路公共IP地址203.0.113.38。如果我们不这样做,数据包的源IP地址将是192.168.130.100,并且回包将永远无法找到他们回到我的工作站的方式,因为这个地址范围在公共互联网中是不可路由的。讨论防火墙和NAT超出了本文的范围,但为了让您了解,这里有一个最简单的命令:
[router] ~ # iptables -t nat -A POSTROUTING -s 192.168.128.0/20 -o vlan-shdsl -j SNAT --to 203.0.113.38
所有源地址来自192.168.128.0/20范围的数据包通过接口vlan-shdsl将源重写为203.0.113.38。
现在,让我们检查新的网络路径:
[workstation] ~ $ /usr/sbin/traceroute f.root-servers.net
traceroute to f.root-servers.net (192.5.5.241), 30 hops max, 40 byte packets using UDP
1 gw-vlan-office.e-it.co.nz (192.168.130.1) 0.190 ms 0.129 ms 0.125 ms
2 rt-shdsl.isp1 (203.0.113.37) 2.676 ms 2.599 ms 2.632 ms
3 rt3.isp1 (121.98.ab.cd) 2.715 ms 2.680 ms 2.591 ms
4 isc2.ape.net.nz (192.203.154.z) 2.919 ms 3.033 ms 3.088 ms
5 f.root-servers.net (192.5.5.241) 3.007 ms 2.670 ms 2.864 ms
现在好多了。第一跳保持不变,那是我的工作站的路由器,但第二跳不再是ADSL链路。相反,它是SHDSL ISP1链路的核心路由器。它也清楚地显示了延迟的改善,从26ms的ADSL链路到3ms的SHDSL链路。
让我们再次删除手动配置的路由,以避免任何混乱的路由,并查询路由表:
[router] ~ # ip route get 192.5.5.241 from 192.168.130.100 iif vlan-office
192.5.5.241 from 192.168.130.100 via 203.0.113.37 dev vlan-shdsl # SHDSL链路
[router] ~ # ip route delete 192.5.5.241 via 203.0.113.37 dev vlan-shdsl
[router] ~ # ip route get 192.5.5.241 from 192.168.130.100 iif vlan-office
192.5.5.241 from 192.168.130.100 via 192.168.128.254 dev vlan-adsl # ADSL链路
所以我们现在只需要一个所有国家IP地址的列表,把它们放到路由表中,然后就完成了。但是如何做?手动配置吗?即使在新西兰这样的小国家,也有数百个本地IP地址和前缀,而且列表是动态的,每天都在变化。没有办法手动管理这样的列表。我们需要一个更好的方式。
GET IT,使用BGP!
BGP是当今Internet的路由协议。这个星球上的每一个ISP都会告诉其他所有ISP它的网络中有哪些IP地址,以及其他哪些IP地址可以通过这个ISP的网络到达。交换这种信息的协议称为BGP (Border Gateway protocol)。
我不打算深入讨论BGP的细节。我们只需要知道我们的ISP1可以使用BGP向我们发送所有国家前缀的列表。我们不再手动输入它们,而是侦听“BGP消息”并从它更新我们的路由表。这部分需要与互联网供应商协调,所以我要求我们的ISP1请给我们分配一个私有的ASN,并发送给我们一个带国家前缀的BGP。BGP通常在由ASN (Autonomous System Number)标识的自治系统之间运行。任何足够大的组织都可以申请和支付自己的官方ASN,但就我们的目的而言,从ISP分配的私人范围内使用ASN就足够了。表2显示了我从他们那里收到的信息。
表2:
ISP | Company | |
ASN | 177XY | 6452X |
Router IP | 203.0.113.37 | 203.0.113.38 |
Prefixes advertised | all national ones | none |
现在我们在链路的两边都有路由器的IP地址,有ASN和他们将发送给我们的前缀的确认(“所有国家的”)。这就是我们需要的全部信息。
许多BGP软件可用于Linux。我选择了Bird(当时最新的版本是1.3.4),并从RPM安装了它。
Bird的配置很简单。配置文件位于/etc/bird/bird.conf,如下所示:
log syslog all;
protocol kernel {
import none;
export all;
}
protocol device {
scan time 10;
}
protocol bgp {
description "ISP1 National Routes";
local as 64526;
neighbor 203.0.113.37 as 17746;
source address 203.0.113.38;
import all; # Accept all prefixes from our neighbor
export none; # Don't send the neighbor any prefixes
}
本质上,Bird进程与BGP邻居对话,并将所有发布的前缀引入到它的内部路由列表中。它还与内核进行对话,并将它所知道的所有路由(即通过BGP学习到的所有路由)“导出到内核”。这样,它就从BGP提供内核路由表。
引入BGP路由后,目前内核路由表有4000多条记录:
[router] ~ # ip route show
[1] 203.0.113.36/30 dev vlan-shdsl proto kernel scope link src 203.0.113.38
[2] 192.168.128.0/24 dev vlan-adsl proto kernel scope link src 192.168.128.1
[3] 192.168.130.0/24 dev vlan-office proto kernel scope link src 192.168.130.1
[4] default via 192.168.128.254 dev vlan-adsl
[5] 14.1.32.0/19 via 203.0.113.37 dev vlan-shdsl proto bird
[6] 27.252.0.0/16 via 203.0.113.37 dev vlan-shdsl proto bird
[7] 58.28.0.0/16 via 203.0.113.37 dev vlan-shdsl proto bird
....
[4509] 203.97.0.0/17 via 203.0.113.37 dev vlan-shdsl proto bird
[4510] 222.153.128.0/18 via 203.0.113.37 dev vlan-shdsl proto bird
[4511] 222.155.96.0/19 via 203.0.113.37 dev vlan-shdsl proto bird
从[1]到[4]的行与前面看到的相同—所有直接连接的子网和默认路由。[5] ~[4511]是通过BGP接收的路由。
现在,让我们来查询新填充的路由,以找到我们最喜欢的f.root-servers.net的路径:
[router] ~ # ip route get 192.5.5.241 from 192.168.130.100 iif vlan-office
192.5.5.241 from 192.168.130.100 via 203.0.113.37 dev vlan-shdsl # SHDSL链路
太好了,这正是我们想要的!从工作站到国内和国际目的地运行一对traceroute,验证新路径是否按预期使用。
希望本文对您有所帮助,非常感谢!