# 30.2.配置 PPP

FreeBSD 提供对拨号 PPP 连接的内建支持，可以通过 [ppp(8)](https://man.freebsd.org/cgi/man.cgi?query=ppp\&sektion=8\&format=html) 管理。默认的 FreeBSD 内核已支持 **tun**，用于与调制解调器硬件交互。配置工作主要通过编辑至少一个配置文件完成，并已提供包含示例的配置文件。最后，使用 `ppp` 命令来启动和管理连接。

要使用 PPP 连接，必须具备以下内容：

* 与互联网服务提供商（ISP）签订的拨号账号；
* 一台拨号调制解调器；
* ISP 的拨号号码；
* ISP 分配的登录用户名与密码；
* 一个或多个 DNS 服务器的 IP 地址。通常，ISP 会提供这些地址；如果未提供，FreeBSD 可配置为使用 DNS 协商。

如果缺少上述信息，请联系 ISP。

以下信息可能由 ISP 提供，但并非必需：

* 默认网关的 IP 地址。如果未知，ISP 会在连接过程中自动提供正确的值。在配置 FreeBSD 的 PPP 时，这个地址称为 `HISADDR`；
* 子网掩码。如果 ISP 未提供，将在 [ppp(8)](https://man.freebsd.org/cgi/man.cgi?query=ppp\&sektion=8\&format=html) 配置文件中使用 `255.255.255.255`。\*\
  如果 ISP 分配了静态 IP 地址和主机名，应在配置文件中填写；否则，这些信息将在连接过程中自动提供。

本节接下来将演示如何为常见的 PPP 连接场景配置 FreeBSD。所需的配置文件是 **/etc/ppp/ppp.conf**，此外 **/usr/share/examples/ppp/** 中还提供了附加的文件与示例。

> **注意**
>
> 在本节中，许多文件示例显示了行号。这些行号用于方便讨论而添加，不应出现在实际文件中。
>
> 当编辑配置文件时，缩进非常重要。以 `:` 结尾的行必须置于第一列开头，其他行则需如示例中所示，使用空格或 Tab 进行缩进。

## 30.2.1. 基本配置

为了配置 PPP 连接，首先使用 ISP 的拨入信息编辑 **/etc/ppp/ppp.conf**。该文件说明如下：

```ini
1     default:
2       set log Phase Chat LCP IPCP CCP tun command
3       ident user-ppp VERSION
4       set device /dev/cuau0
5       set speed 115200
6       set dial "ABORT BUSY ABORT NO\\sCARRIER TIMEOUT 5 \
7                 \"\" AT OK-AT-OK ATE1Q0 OK \\dATDT\\T TIMEOUT 40 CONNECT"
8       set timeout 180
9       enable dns
10
11    provider:
12      set phone "(123) 456 7890"
13      set authname foo
14      set authkey bar
15      set timeout 300
16      set ifaddr x.x.x.x/0 y.y.y.y/0 255.255.255.255 0.0.0.0
17      add default HISADDR
```

**第 1 行**：标识 `default` 条目。执行 `ppp` 时，会自动运行本条目中的命令（第 2 至 9 行）。

**第 2 行**：启用详细日志参数，用于测试连接。待配置正常工作，可简化为：

```sh
set log phase tun
```

**第 3 行**：向连接另一端的 PPP 软件显示 \[ppp(8)] 的版本号。

**第 4 行**：指定连接调制解调器的设备，**COM1** 为 **/dev/cuau0**，**COM2** 为 **/dev/cuau1**。

**第 5 行**：设置连接速率。如果旧调制解调器无法使用 `115200`，可尝试 `38400`。

**第 6 与 7 行**：拨号字符串，使用 expect-send 语法书写。详情请参阅 [chat(8)](https://man.freebsd.org/cgi/man.cgi?query=chat\&sektion=8\&format=html)。

注意此命令因可读性原因换行。**ppp.conf** 中的任何命令都可以在行末加 `\` 来换行。

**第 8 行**：设置链路空闲超时（秒）。

**第 9 行**：指示对端确认 DNS 设置。如果本地网络已有 DNS 服务器，应将本行注释掉（加 `#`），或直接删除。

**第 10 行**：空行，仅用于可读性，\[ppp(8)] 会忽略空行。

**第 11 行**：标识名为 `provider` 的条目。可将其改为 ISP 名称，以便用 `load <ISP>` 启动连接。

**第 12 行**：填写 ISP 的电话号码。可使用冒号（`:`）或竖线（`|`）分隔多个号码。冒号用于轮换拨号，竖线用于总是优先拨打第一个号码，仅当失败才尝试其他号码。所有号码必须用引号包裹，以避免拨号失败。

**第 13 与 14 行**：填写 ISP 的用户名与密码。

**第 15 行**：设置连接的默认空闲超时（秒）。此例中，连接在 300 秒无活动后自动断开。若希望连接永不超时，可将其设为 0。

**第 16 行**：设置接口地址。具体值取决于 ISP 是否提供静态 IP 地址，或是通过连接动态协商。

如果 ISP 分配了静态 IP 和默认网关地址，则用该静态 IP 替换 *x.x.x.x*，用网关地址替换 *y.y.y.y*；若 ISP 仅提供静态 IP 而无网关地址，则将 *y.y.y.y* 改为 `10.0.0.2/0`。

如果每次连接时 IP 地址会变化，则改为以下内容，使用 IP 配置协议（IPCP）动态协商：

```sh
set ifaddr 10.0.0.1/0 10.0.0.2/0 255.255.255.255 0.0.0.0
```

**第 17 行**：保持不变，用于将默认路由添加到网关地址。`HISADDR` 将自动替换为第 16 行指定的网关地址。必须放在第 16 行之后。

如果以手动或自动方式运行 \[ppp(8)]，可能还需要创建 **/etc/ppp/ppp.linkup** 文件，内容如下。若以 `-auto` 模式运行 `ppp`，该文件是必需的。它在连接建立之后使用，此时 IP 地址已分配，可以添加路由表项。创建此文件时，*provider* 必须与 **ppp.conf** 第 11 行中所用值一致。

```ini
provider:
      add default HISADDR
```

如果在静态 IP 配置中默认网关地址是“猜测”出来的，也需要此文件。在这种情况下，应从 **ppp.conf** 中删除第 17 行，并创建包含上述两行的 **/etc/ppp/ppp.linkup**。该文件的更多示例可见于 **/usr/share/examples/ppp/**。

默认情况下，`ppp` 必须以 `root` 身份运行。若要更改此行为，应将希望运行 `ppp` 的用户账户添加到 **/etc/group** 中的 `network` 组。

然后使用 `allow` 语句授予该用户访问 **/etc/ppp/ppp.conf** 某些条目的权限。例如，要让 `fred` 和 `mary` 仅能使用 `provider:` 条目，在该部分添加：

```ini
allow users fred mary
```

若希望允许这些用户访问所有条目，则应将该语句放入 `default` 部分。

## 30.2.2. 高级配置

PPP 可以配置为按需提供 DNS 和 NetBIOS 名称服务器地址。

要在 PPP 1.x 版本中启用这些扩展功能，可以在 **/etc/ppp/ppp.conf** 的相关段落中添加以下几行：

```ini
enable msext
set ns 203.14.100.1 203.14.100.2
set nbns 203.14.100.5
```

对于 PPP 2 及更高版本：

```ini
accept dns
set dns 203.14.100.1 203.14.100.2
set nbns 203.14.100.5
```

这会告知客户端主、备名称服务器地址和一个 NetBIOS 名称服务器主机。

在 2 及以上版本中，如果省略 `set dns` 行，则 PPP 会使用 **/etc/resolv.conf** 中的值。

### 30.2.2.1. PAP 与 CHAP 认证

有些 ISP 设置其系统以使用 PAP 或 CHAP 认证机制完成连接的认证部分。如果是这种情况，ISP 在连接时不会提供 `login:` 提示符，而是会直接开始 PPP 会话。

PAP 的安全性低于 CHAP，但安全性通常不是关键问题，因为尽管 PAP 使用明文传输密码，但是在串行线路上传输。攻击者“窃听”的可能性非常小。

需要进行如下更改：

```ini
13      set authname MyUserName
14      set authkey MyPassword
15      set login
```

**第 13 行** ：此行指定 PAP/CHAP 用户名。请将 *MyUserName* 替换为正确的用户名。

**第 14 行**：此行指定 PAP/CHAP 密码。请将 *MyPassword* 替换为正确的密码。你可能还希望添加一行，例如：

```ini
16      accept PAP
```

或

```ini
16      accept CHAP
```

以明确表达使用的认证类型，但默认情况下 PAP 与 CHAP 都是被接受的。

**第 15 行**：当使用 PAP 或 CHAP 时，ISP 通常不需要登录服务器，因此请禁用 "set login" 字符串。

### 30.2.2.2. 使用 PPP 的网络地址转换功能

PPP 具有使用内部 NAT 的能力，而无需依赖内核的 divert 支持。可以通过在 **/etc/ppp/ppp.conf** 中加入以下行启用此功能：

```ini
nat enable yes
```

或者，也可以通过命令行选项 `-nat` 启用 NAT。此外，**/etc/rc.conf** 中有一个名为 `ppp_nat` 的选项，默认是启用的。

在使用此功能时，可以加入如下选项以启用对外连接的端口转发（位于 **/etc/ppp/ppp.conf**）：

```ini
nat port tcp 10.0.0.2:ftp ftp
nat port tcp 10.0.0.2:http http
```

或完全禁止外部连接：

```ini
nat deny_incoming yes
```

## 30.2.3. 最终系统配置

虽然 `ppp` 已经完成配置，但仍需对 **/etc/rc.conf** 进行一些编辑。

从该文件的顶部开始，确保设置了 `hostname=` 行：

```ini
hostname="foo.example.com"
```

如果 ISP 提供了静态 IP 地址和主机名，请使用此主机名作为系统名称。

查找 `network_interfaces` 变量。若要将系统配置为按需拨号连接 ISP，请确保将 **tun0** 设备添加到列表中；否则请将其移除。

```ini
network_interfaces="lo0 tun0"
ifconfig_tun0=
```

> **注意**
>
> `ifconfig_tun0` 变量应为空，并应创建一个名为 **/etc/start\_if.tun0** 的文件。该文件应包含以下一行：
>
> ```sh
> ppp -auto mysystem
> ```
>
> 该脚本将在网络配置时执行，以自动模式启动 ppp 守护进程。如果此主机作为网关使用，建议加入 `-alias`。详情请参考手册页。

确保在 **/etc/rc.conf** 中使用以下行将路由器程序设置为 `NO`：

```ini
router_enable="NO"
```

这一点很重要，因为不能启动 `routed` 守护进程，否则 `routed` 会删除由 `ppp` 创建的默认路由表项。

建议确保 `sendmail_flags` 行中不包含 `-q` 选项，否则 `sendmail` 会定期进行网络查询，可能会触发系统拨号。你可以尝试：

```sh
sendmail_flags="-bd"
```

这样做的缺点是，每当 PPP 链路建立时，`sendmail` 会被迫重新检查邮件队列。要实现自动化，可以在 **ppp.linkup** 中包含 `!bg`：

```ini
1     provider:
2       delete ALL
3       add 0 0 HISADDR
4       !bg sendmail -bd -q30m
```

另一种方法是设置 “dfilter” 来阻止 SMTP 流量。详见示例文件。

## 30.2.4. 使用 `ppp`

剩下的就是重启系统。重启后，可以键入：

```sh
# ppp
```

然后输入 `dial provider` 来启动 PPP 会话，或者，如果想让 `ppp` 在有出站流量时自动建立连接，并且 **start\_if.tun0** 不存在，可输入：

```sh
# ppp -auto provider
```

可以在 `ppp` 在后台运行时与其通信，但前提是设置了合适的诊断端口。要做到这一点，在配置中添加以下行：

```sh
set server /var/run/ppp-tun%d DiagnosticPassword 0177
```

这会让 PPP 监听指定的 UNIX® 域套接字，在允许访问之前，要求客户端提供指定的密码。名称中的 `%d` 会被使用中的 **tun** 设备号所替代。

待套接字建立完成，[pppctl(8)](https://man.freebsd.org/cgi/man.cgi?query=pppctl\&sektion=8\&format=html) 程序就可以在需要操作正在运行的程序的脚本中使用。

## 30.2.5. 配置拨入服务

[“拨入服务”](https://docs.freebsd.org/en/books/handbook/serialcomms/#dialup) 提供了启用拨号服务的良好说明，使用的是 [getty(8)](https://man.freebsd.org/cgi/man.cgi?query=getty\&sektion=8\&format=html)。

除了 `getty`，还有一个更智能的替代方案：[comms/mgetty+sendfax](https://cgit.freebsd.org/ports/tree/comms/mgetty+sendfax/) 这个 Ports，它是专为拨号线路设计的 `getty` 改进版本。

使用 `mgetty` 的优点在于它能主动与调制解调器“对话”，意味着如果在 **/etc/ttys** 中关闭了端口，那么调制解调器将不会接听电话。

从 0.99beta 版本起，`mgetty` 还支持自动检测 PPP 流，这样客户端就可以无需脚本地访问服务器。

关于 `mgetty` 的更多信息，请参阅：<http://mgetty.greenie.net/doc/mgetty_toc.html>。

默认情况下，[comms/mgetty+sendfax](https://cgit.freebsd.org/ports/tree/comms/mgetty+sendfax/) Ports 启用了 `AUTO_PPP` 选项，使 `mgetty` 能够检测 PPP 连接的 LCP 阶段，并自动启动一个 ppp shell。然而由于此过程中不会经过常规的登录/密码步骤，因此需要通过 PAP 或 CHAP 方式对用户进行认证。

本节假设用户已经成功编译并安装了 [comms/mgetty+sendfax](https://cgit.freebsd.org/ports/tree/comms/mgetty+sendfax/) Ports。

确保 **/usr/local/etc/mgetty+sendfax/login.config** 中包含以下内容：

```sh
/AutoPPP/ -     - /etc/ppp/ppp-pap-dialup
```

这会告诉 `mgetty`：当检测到 PPP 连接时，运行 **ppp-pap-dialup**。

创建一个名为 **/etc/ppp/ppp-pap-dialup** 的可执行文件，内容如下：

```sh
#!/bin/sh
exec /usr/sbin/ppp -direct pap$IDENT
```

对于每个在 **/etc/ttys** 中启用的拨号线路，应在 **/etc/ppp/ppp.conf** 中创建相应条目。它们可以与我们之前创建的定义共存。

```ini
pap:
  enable pap
  set ifaddr 203.14.100.1 203.14.100.20-203.14.100.40
  enable proxy
```

通过这种方式登录的每个用户都需要在 **/etc/ppp/ppp.secret** 中拥有用户名/密码。或者也可以添加以下选项，以通过 **/etc/passwd** 使用 PAP 认证用户：

```ini
enable passwdauth
```

要为某些用户分配静态 IP 地址，请在 **/etc/ppp/ppp.secret** 中将该地址作为第三个参数指定。示例请参考 **/usr/share/examples/ppp/ppp.secret.sample**。
