为了让一台主机在网能找到另一台主机, 就必须要有一种机制来描述如何从一台主机连至另一台上。这个就叫做 路由选择(routing)。 一个“路由”是一对预先定义的地址: “目的地(destination)”和“网关(gateway)”。 这对地址表明如果您想要试着到达这个目的地(destination), 那么就通过这个网关(gateway)进行通信。 目的地有三种类型: 单个主机(individual hosts), 子网(subnets)和“默认(default)”。 如果没有其它路由应用,就使用“默认路由(default route)”。 关于默认路由我们以后为讨论多一点。有三种类型的网关: 单个主机,接口(也叫“连接(links)”)和以太网硬件地址(MAC addresses)。
为了说明路由选择的各个部分,我们使用以用下面这个例子。 以下是命令 netstat 的输出:
% netstat -r Routing tables Destination Gateway Flags Refs Use Netif Expire default outside-gw UGSc 37 418 ppp0 localhost localhost UH 0 181 lo0 test0 0:e0:b5:36:cf:4f UHLW 5 63288 ed0 77 10.20.30.255 link#1 UHLW 1 2421 example.com link#1 UC 0 0 host1 0:e0:a8:37:8:1e UHLW 3 4601 lo0 host2 0:e0:a8:37:8:1e UHLW 0 5 lo0 => host2.example.com link#1 UC 0 0 224 link#1 UC 0 0
头两行指定默认路由 (我们会在下一节说明) 和本地(localhost)路由。
这张路由表里指定用于localhost的接口 (Netif 列)是lo0, 也就是众所周知的“回环设备(loopback device)”。 这就使得所有以此为“目的地”的通信留在了内部, 而不是通过LAN发送出去,因为它会在开始的地方就结束返回。
接着出现的是以 0:e0: 开头的地址。这些是以太网硬件地址,也称为 MAC 地址。 FreeBSD 会自动识别在同一个以太网中的任何主机(如 test0),并为这个主机新增一个路由, 以并通过那个以太网接口——ed0 直接到达它(译者注:那台主机。与这类路由表相关的也有一个超时项 (Expire列),当我们在指定时间内没有收到从那个主机发来的信息, 这项就派上用场了。这种情况下,到这个主机的路由就会被自动删除。 这些主机被使用一种叫做RIP(路由信息协议--Routing Information Protocol)的机制所识别,这种机制利用基于“最短路径选择 (shortest path determination)”的办法计算出到本地主机的路由。
FreeBSD 也会为本地子网添加子网路由(10.20.30.255 是子网 10.20.30 的广播地址,而 example.com 是这个子网相联的域名)。 名称 link#1 代表主机上的第一块以太网卡。 您会发现,对于它们没有指定另外的接口。
这两个组(本地网络主机和本地子网)的路由是由守护进程 routed 自动配置的。如果它没有运行, 那就只有被静态定义 (例如,明确输入的) 的路由才存在了。
host1 行代表我们的主机,它通过以太网地址来识别。 因为我们是发送端,FreeBSD知道使用回还接口 (lo0) 而不是通过以太网接口来进行发送。
两个 host2 是我们使用 ifconfig(8) 别名 (请看关于以太网的那部分就会知道我们为什么这么做) 时产生的一个实例。在 lo0 接口之后的 => 符号表明我们不仅使用了回环 (因为这个地址也涉及了本地主机),而且明确指出它是个别名。 这类路由只有在支持别名的主机上才能显现出来。 所有本地网上的其它的主机对于这类路由只会简单拥有 link#1。
最后一行 (目标子网224) 用于处理多播——它会覆盖到其它的区域。
最后,每个路由的不同属性可以在 Flags 列中看到。下边是个关于这些标志和它们的含义的一个简表:
当本地系统需要与远程主机建立连接时, 它会检查路由表以决定是否有已知的路径存在。 如果远程主机属于一个我们已知如何到达 (克隆的路由) 的子网内,那么系统会检查看沿着那个接口是否能够连接。
如果所有已知路径都失败,系统还有最后一个选择: “默认”路由。这个路由是特殊类型的网关路由 (通常只有一个存在于系统里),并且总是在标志栏使用一个 c来进行标识。对于本地区域网络里的主机, 这个网关被设置到任何与外界有直接连接的机子里 (无论是通过 PPP、DSL、cable modem、T1 或其它的网络接口连接)。
如果您正为某台本身就做为网关连接外界的机子配置默认路由的话, 那么该默认路由应该是您的“互联网服务商 (ISP)”那方的网关机子。
让我们来看一个关于默认路由的例子。这是个很普遍的配置:
主机 Local1 和 Local2 在您那边。Local1 通过 PPP 拨号连接到了 ISP。这个 PPP 服务器通过一个局域网连接到另一台网关机子——它又通过一个外部接口连接到 ISP 提供的互联网上。
您的每一台机子的默认路由应该是:
一个常见的问题是“我们为什么 (或怎样) 能 T1-GW 设置成为 Local1 默认网关,而不是它所连接 ISP 服务器?”
记住,因为 PPP 接口使用的一个地址是在 ISP 的局域网里的,用于您那边的连接,对于 ISP 的局域网里的其它机子,其路由会自动产生。 因此,您就已经知道了如何到达机子 T1-GW, 那么也就没必要中那一步了——发送通信给 ISP 服务器。
通常使用地址 X.X.X.1 做为一个局域网的网关。 因此 (使用相同的例子),如果您本地的 C 类地址空间是 10.20.30,而您的 ISP 使用的是 10.9.9, 那么默认路由表将是:
Host | Default Route |
---|---|
Local2 (10.20.30.2) | Local1 (10.20.30.1) |
Local1 (10.20.30.1, 10.9.9.30) | T1-GW (10.9.9.1) |
您可以很轻易地通过 /etc/rc.conf 文件设定默认路由。在我们的实例里,在主机 Local2 里,我们在文件 /etc/rc.conf 里增加了下边内容:
defaultrouter="10.20.30.1"
也可以直接在命令行使用 route(8) 命令:
# route add default 10.20.30.1
想要了解更多关于手工处理网络路由表的信息,参考 route(8) 手册页。
还有一种其它的类型的配置是我们要提及的, 这就是一个主机处于两个不同的网络。技术上,任何做为网关 (上边的实例中,使用了 PPP 连接) 的机子就算作是重宿主机。 但这个词实际上仅用来指那种处于两个局域网这中的机子。
有一种情形,一台机子有两个网卡, 对于各个子网都有各自的一个地址。另一种情况, 这台机子仅有一张网卡,但使用 ifconfig(8) 做了别名。如果有两个独立的以太网在使用的情形就使用前者, 如果只有一个物理网段,但逻辑上分成了两个独立的子网, 就使用后者。
每种情况都要设置路由表以便两子网都知道这台主机是到其它子网的网关——入站路由 (inbound route)。将一台主机配置成两个子网间的路由器, 这种配置经常在我们需要实现单向或双向的包过滤或防火墙时被用到。
如果想让主机在两个接口间转发数据包,您需要激活 FreBSD 的这项功能。至于怎么做,请看下一部分了解更多。
网络路由器只是一个将数据包从一个接口转发到另一个接口的系统。 互联网标准和良好的工程实践阻止了 FreeBSD 计划在 FreeBSD 中把它置成默认地。您在可以在 rc.conf(5) 中改变下列变量的值为 YES,使用这个功能生效:
gateway_enable=YES # Set to YES if this host will be a gateway
这个选项会把sysctl(8) 变量——net.inet.ip.forwarding 设置成 1。如果您要临时地停止路由, 您可以把它重为 0。
新的路由器需要有路由才知道将数据传向何处。 如果网络够简单,您可以使用静态路由。FreeBSD 也自带一个标准的BSD路由选择守护进程 routed(8), 称之为 RIP ( version 1和 version 2) 和 IRDP。对 BGP v4,OSPF v2 和其它复杂路由选择协议的支持可以从 net/zebra 包中得到。 像 GateD® 一样的商业产品也提供了更复杂的网络路由解决方案。
即使 FreeBSD 按照这种方法进行了配置, 它也并不完全符合 Internet 标准对路由器的要求。 但对于一般应用已经足够了。
假设如下这样一个网络:
在这里,RouterA 是我们的 FreeBSD 机子,它充当连接到互联网其它部分的路由器的角色。 默认路由设置为10.0.0.1, 它就允许与外界连接。我们假定已经正确配置了 RouterB,并且知道如何连接到想去的任何地方。 (在这个图里很简单。只须在 RouterB 上增加默认路由,使用 192.168.1.1 做为网关。)
如果我们查看一下RouterA的路由表, 我们就会看到如下一些内容:
% netstat -nr Routing tables Internet: Destination Gateway Flags Refs Use Netif Expire default 10.0.0.1 UGS 0 49378 xl0 127.0.0.1 127.0.0.1 UH 0 6 lo0 10.0.0/24 link#1 UC 0 0 xl0 192.168.1/24 link#2 UC 0 0 xl1
使用当前的路由表,RouterA 是不能到达我们的内网——Internal Net 2 的。它没有到 192.168.2.0/24 的路由。 一种可以接受的方法是手工增加这条路由。以下的命令会把 Internal Net 2 网络加入到 RouterA 的路由表中,使用192.168.1.2 做为下一个跳跃:
# route add -net 192.168.2.0/24 192.168.1.2
现在 RouterA 就可以到达 192.168.2.0/24 网络上的任何主机了。
上面的实例对于运行着的系统来说配置静态路由是相当不错了。 只是,有一个问题——如果您重启您的 FreeBSD 机子,路由信息就会消失。 处理附加的静态路由的方法是把它放到您的 /etc/rc.conf 文件里去。
# Add Internal Net 2 as a static route static_routes="internalnet2" route_internalnet2="-net 192.168.2.0/24 192.168.1.2"
配置变量 static_routes 是一串以空格格开的字符串。每一串表示一个路由名字。 在上面的例子中我们中有一个串在 static_routes 里。这个字符串中 internalnet2。 然后我们新增一个配置变量 route_internalnet2, 这里我们把所有传给 route(8)命令的参数拿了过来。 在上面的实例中的我使用的命令是:
# route add -net 192.168.2.0/24 192.168.1.2
因此,我们需要的是 "-net 192.168.2.0/24 192.168.1.2"。
前边已经说了,我们可以有不只一个字符串的 static_routes 里边。 下面我们就建立多个静态路由。下面几行显示了一个为 192.168.0.0/24 和 192.168.1.0/24 网络在一个假想的路由器上增加静态路由的例子:
static_routes="net1 net2" route_net1="-net 192.168.0.0/24 192.168.0.1" route_net2="-net 192.168.1.0/24 192.168.1.1"
我们已经讨论了如何定义通向外界的路由, 但未谈及外界是如何找到我们的。
我们已经知道可以设置路由表, 这样任何指向特定地址空间 (在我们的例子中是一个 C 类子网) 的数据都会被送往网络上特定的主机, 然后由这台主机向地址空间内部转发数据。
当您得到一个分配给您的网络的地址空间时, ISP(网络服务商)会设置它们的路由表, 这样指向您子网的数据就会通过 PPP 连接下传到您的网络。 但是其它跨越国界的网络是如何知道将数据传给您的 ISP 的呢?
有一个系统(很像分布式 DNS 信息系统), 它一直跟踪被分配的地址空间, 并说明它们连接到互联网骨干(Internet backbone)的点。 “骨干(Backbone)” 指的是负责全世界和跨国的传输的主要干线。 每一台骨干主机(backbone machine)有一份主要表集的拷贝, 它将发送给特定网络的数据导向相应的骨干载体上(backbone carrier), 从结点往下遍历服务提供商链,直到数据到达您的网络。
服务提供商的任务是向骨干网络广播他们就是到到达您的网点的连接结点 (以及进入的路径)。这就是路由传播。
有时候,路由传播会有一个问题,一些网络无法与您连接。 或许能帮您找出路由是在哪里中断的最有用的命令就是 traceroute(8)了。当您无法与远程主机连接时, 这个命令一样有用(例如 ping(8) 失败)。
traceroute(8) 命令将以您想连接的主机的名字作为参数执行。 不管是到达了目标,还是因为没有连接而终止, 它都会显示所经过的所有网关主机。
想了解更多的信息,查看 traceroute(8) 的手册。
FreeBSD 一开始就支持多播应用软件和多播路由选择。 多播程序并不要求FreeBSD的任何特殊的配置, 就可以工作得很好。多播路由需要支持被编译入内核:
options MROUTING
另外,多播路由守护进程——mrouted(8) 必须通过 /etc/mrouted.conf 配置来开启通道和 DVMRP。 更多关于多播路由配置的信息可以在 mrouted(8) 的手册里找到。