# 34.2.网关和路由

*路由* 是使系统能够找到通往另一个系统的网络路径的机制。*路由* 是一对定义的地址，分别表示“目标”和“网关”。路由表明，当尝试连接到指定的目标时，应该通过指定的网关发送数据包。有三种目标类型：单个主机、子网和“默认”。“默认路由”在没有其他路由适用时使用。网关也有三种类型：单个主机、接口（也叫做链路）和以太网硬件（MAC）地址。已知的路由会存储在路由表中。

本节提供了路由基础的概述。然后展示了如何将 FreeBSD 系统配置为路由器，并提供了一些故障排除技巧。

## 34.2.1. 路由基础

要查看 FreeBSD 系统的路由表，可以使用 [netstat(1)](https://man.freebsd.org/cgi/man.cgi?query=netstat\&sektion=1\&format=html)：

```sh
% netstat -r
Routing tables

Internet:
Destination      Gateway            Flags     Refs     Use     Netif Expire
default          outside-gw         UGS        37      418       em0
localhost        localhost          UH          0      181       lo0
test0            0:e0:b5:36:cf:4f   UHLW        5    63288       re0     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
```

这个例子中的条目如下：

**default** 路由表中的第一个条目指定了 `default` 路由。当本地系统需要连接到远程主机时，它会检查路由表以确定是否有已知的路径。如果远程主机匹配表中的某个条目，系统将检查是否可以通过该条目中指定的接口连接。

如果目标不匹配任何条目，或者所有已知路径失败，系统将使用默认路由的条目。对于本地局域网上的主机，默认路由中的 `Gateway` 字段设置为具有直接互联网连接的系统。在读取此条目时，确保 `Flags` 列指示网关是可用的（`UG`）。

对于作为外部世界网关的机器，默认路由将是连接到互联网服务提供商（ISP）的网关机器。

**localhost** 第二个路由是 `localhost` 路由。`Netif` 列中为 `localhost` 指定的接口是 **lo0**，也称为回环设备。这表明所有发送到此目标的流量应保持在内部，而不是通过网络发送。

**MAC 地址** 以 `0:e0:` 开头的地址是 MAC 地址。FreeBSD 会自动识别本地以太网中的任何主机（例如示例中的 `test0`），并为该主机在以太网接口 **re0** 上添加一条路由。这种类型的路由有一个超时，如 `Expire` 列所示，如果主机在特定时间内没有响应，该路由将自动删除。这些主机是通过路由信息协议（RIP）识别的，RIP 根据最短路径确定到本地主机的路由。

**子网** FreeBSD 会自动为本地子网添加子网路由。在这个例子中，`10.20.30.255` 是 `10.20.30` 子网的广播地址，`example.com` 是与该子网关联的域名。`link#1` 表示机器的第一个以太网卡。

本地网络主机和本地子网的路由是由一个名为 [routed(8)](https://man.freebsd.org/cgi/man.cgi?query=routed\&sektion=8\&format=html) 的守护进程自动配置的。如果它未运行，则只有管理员静态定义的路由存在。

**主机** `host1` 行通过以太网地址引用主机。由于它是发送主机，FreeBSD 知道要使用回环接口 (**lo0**)，而不是以太网接口。

两条 `host2` 行代表使用 [ifconfig(8)](https://man.freebsd.org/cgi/man.cgi?query=ifconfig\&sektion=8\&format=html) 创建的别名。**lo0** 接口后的 `⇒` 符号表示除了回环地址外，还设置了一个别名。此类路由仅出现在支持别名的主机上，本地网络上的所有其他主机将对这些路由显示 `link#1` 行。

**224** 最后一行（目标子网 `224`）处理多播。

可以在 `Flags` 列中查看每个路由的各种属性。[常见的路由表标志](https://docs.freebsd.org/en/books/handbook/advanced-networking/#routeflags) 总结了这些标志及其含义。

**表 1. 常见的路由表标志**

| 标志 | 目的                                 |
| -- | ---------------------------------- |
| U  | 路由是活动的（启用）。                        |
| H  | 路由目标是单个主机。                         |
| G  | 将此目的地的任何流量转发到此网关，由网关决定如何进一步转发。     |
| S  | 该路由是静态配置的。                         |
| C  | 基于此路由克隆一个新路由，用于机器的连接。此类路由通常用于本地网络。 |
| W  | 该路由是根据本地网络（克隆）路由自动配置的。             |
| L  | 路由涉及到以太网（链路）硬件的引用。                 |

在 FreeBSD 系统中，可以通过在 **/etc/rc.conf** 中指定默认网关的 IP 地址来定义默认路由：

```sh
defaultrouter="10.20.30.1"
```

也可以使用 `route` 手动添加路由：

```sh
# route add default 10.20.30.1
```

请注意，手动添加的路由在重启后不会保留。有关手动操作网络路由表的更多信息，请参阅 [route(8)](https://man.freebsd.org/cgi/man.cgi?query=route\&sektion=8\&format=html)。

## 34.2.2. 配置带静态路由的路由器

如果 FreeBSD 系统是双网卡系统，它可以配置为网络的默认网关或路由器。双网卡系统是指至少连接到两个不同网络的主机。通常，每个网络连接到一个独立的网络接口，尽管可以使用 IP 别名将多个地址绑定到一个物理接口，并使每个地址处于不同的子网。

为了让系统在接口之间转发数据包，FreeBSD 必须被配置为路由器。互联网标准和良好的工程实践不允许 FreeBSD 项目默认启用此功能，但可以通过在 **/etc/rc.conf** 中添加以下行来配置在启动时启用此功能：

```sh
gateway_enable="YES"          # 如果此主机是网关，则设置为 YES
```

要立即启用路由，请将 [sysctl(8)](https://man.freebsd.org/cgi/man.cgi?query=sysctl\&sektion=8\&format=html) 变量 `net.inet.ip.forwarding` 设置为 `1`。要停止路由，请将此变量重置为 `0`。

路由器的路由表需要添加额外的路由，以便它知道如何到达其他网络。路由可以通过静态路由手动添加，也可以通过路由协议自动学习。静态路由适用于小型网络，本节将介绍如何为小型网络添加静态路由条目。

> **注意**
>
> 对于大型网络，静态路由很快变得不可扩展。FreeBSD 提供了标准的 BSD 路由守护进程 [routed(8)](https://man.freebsd.org/cgi/man.cgi?query=routed\&sektion=8\&format=html)，它提供了 RIP 协议（版本 1 和 2）和 IRDP 协议的支持。通过安装包或 Port [net/quagga](https://cgit.freebsd.org/ports/tree/net/quagga/)，可以支持 BGP 和 OSPF 路由协议。

考虑以下网络配置：

![静态路由](https://docs.freebsd.org/images/books/handbook/advanced-networking/static-routes.png)

在此示例中，`RouterA` 是一台 FreeBSD 机器，充当通向外部互联网的路由器。它的默认路由设置为 `10.0.0.1`，允许它与外部世界连接。`RouterB` 已配置使用 `192.168.1.1` 作为其默认网关。

在添加任何静态路由之前，`RouterA` 的路由表如下所示：

```sh
% 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.0/24        link#1             UC          0        0    xl0
192.168.1.0/24     link#2             UC          0        0    xl1
```

当前的路由表中，`RouterA` 没有到 `192.168.2.0/24` 网络的路由。以下命令将 `Internal Net 2` 网络添加到 `RouterA` 的路由表，并使用 `192.168.1.2` 作为下一跳：

```sh
# route add -net 192.168.2.0/24 192.168.1.2
```

现在，`RouterA` 可以访问 `192.168.2.0/24` 网络上的任何主机。但是，如果 FreeBSD 系统重新启动，路由信息将不会保留。如果需要使静态路由持久化，可以将其添加到 **/etc/rc.conf** 中：

```sh
# 将 Internal Net 2 添加为持久静态路由
static_routes="internalnet2"
route_internalnet2="-net 192.168.2.0/24 192.168.1.2"
```

`static_routes` 配置变量是一个由空格分隔的字符串列表，每个字符串引用一个路由名称。变量 `route_internalnet2` 包含该路由名称的静态路由。

使用多个字符串在 `static_routes` 中创建多个静态路由。以下示例显示了如何为 `192.168.0.0/24` 和 `192.168.1.0/24` 网络添加静态路由：

```sh
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"
```

## 34.2.3. 故障排除

当一个地址空间被分配给一个网络时，服务提供商会配置他们的路由表，以确保所有流量都被发送到该站点的链接。但是，外部站点如何知道将其数据包发送到网络的 ISP 呢？

有一个系统跟踪所有分配的地址空间，并定义它们与互联网主干网（或承载互联网流量的主干线路）连接的节点。每台主干机器都保存一份主路由表，该表将特定网络的流量指向一个特定的主干承运商，从那里通过一系列服务提供商直到到达特定网络。

服务提供商的任务是向主干站点通告他们是连接点，因此也是流量的进入路径。这个过程被称为路由传播。

有时，路由传播会出现问题，导致某些站点无法连接。最有用的命令之一用于查找路由问题的断点是 `traceroute`，尤其是在 `ping` 失败时非常有用。

使用 `traceroute` 时，需要提供远程主机的地址。输出将显示路径上的网关主机，最终要么到达目标主机，要么因连接问题而终止。有关更多信息，请参阅 [traceroute(8)](https://man.freebsd.org/cgi/man.cgi?query=traceroute\&sektion=8\&format=html)。

## 34.2.4. 多播考虑事项

FreeBSD 本身支持多播应用和多播路由。多播应用在 FreeBSD 上运行时无需进行特殊配置。要支持多播路由，必须将以下选项编译到自定义内核中：

```ini
options MROUTING
```

多播路由守护进程 `mrouted` 可以通过 [net/mrouted](https://cgit.freebsd.org/ports/tree/net/mrouted/) 软件包和 Ports 进行安装。该守护进程实现了 DVMRP 多播路由协议，并通过编辑 **/usr/local/etc/mrouted.conf** 来配置隧道和 DVMRP。安装 `mrouted` 时，还会安装 `map-mbone` 和 `mrinfo`，以及它们相关的 man 页面。请参考这些文档以获得配置示例。

> **注意**
>
> DVMRP 已经在许多多播安装中被 PIM 协议取代。有关更多信息，请参阅 [pim(4)](https://man.freebsd.org/cgi/man.cgi?query=pim\&sektion=4\&format=html)。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://book.bsdcn.org/hanbook/di-34-zhang-gao-ji-wang-luo/34.2.-wang-guan-he-lu-you.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
