# 32.12.用 NTP 进行时钟同步

## 32.12.1. NTP 配置

在 FreeBSD 中，可以使用内置的 ntpd 来同步系统时钟。ntpd 通过 [rc.conf(5)](https://man.freebsd.org/cgi/man.cgi?query=rc.conf\&sektion=5\&format=html) 变量和 **/etc/ntp.conf** 配置文件进行配置，具体说明如下。

ntpd 与其网络对等方通过 UDP 数据包进行通信。在计算机与 NTP 对等方之间的任何防火墙必须配置为允许端口 123 上的 UDP 数据包进出。

### 32.12.1.1. **/etc/ntp.conf** 文件

ntpd 读取 **/etc/ntp.conf** 来确定要查询的 NTP 服务器。建议选择多个 NTP 服务器，以防其中一个服务器无法访问或其时钟不可靠。ntpd 会根据接收到的响应，优先选择可靠的服务器，而将不可靠的服务器排除。查询的服务器可以是本地网络中的服务器，ISP 提供的服务器，或者从 [公开可访问的 NTP 服务器列表](http://support.ntp.org/bin/view/Servers/WebHome) 中选择。选择公共 NTP 服务器时，应选择一个地理位置接近的服务器，并查看其使用政策。`pool` 配置关键字从服务器池中选择一个或多个服务器。可以参考 [公开的 NTP 服务器池列表](http://support.ntp.org/bin/view/Servers/NTPPoolServers)，按地理区域组织。此外，FreeBSD 提供了一个由项目支持的池，`0.freebsd.pool.ntp.org`。

**示例 3. 示例 `/etc/ntp.conf`**

这是一个简单的 **ntp.conf** 文件示例。可以安全地按原样使用；它包含了在公开可访问的网络连接上操作时推荐的 `restrict` 选项。

```ini
# 禁止 ntpq 控制/查询访问。仅允许根据此文件中的 pool 和 server 语句添加对等方。
restrict default limited kod nomodify notrap noquery nopeer
restrict source  limited kod nomodify notrap noquery

# 允许来自本地主机的查询和控制访问。
restrict 127.0.0.1
restrict ::1

# 添加特定的服务器。
server ntplocal.example.com iburst

# 添加 FreeBSD 池服务器，直到有 3 到 6 个有效的服务器。
tos minclock 3 maxclock 6
pool 0.freebsd.pool.ntp.org iburst

# 使用本地的闰秒文件。
leapfile "/var/db/ntpd.leap-seconds.list"
```

该文件的格式在 [ntp.conf(5)](https://man.freebsd.org/cgi/man.cgi?query=ntp.conf\&sektion=5\&format=html) 中有详细说明。以下是对示例中使用的关键字的简要概述。

默认情况下，NTP 服务器对任何网络主机都可访问。`restrict` 关键字控制哪些系统可以访问服务器。支持多个 `restrict` 条目，每个条目都会根据前面的声明细化访问限制。示例中的值授予本地系统完全的查询和控制访问权限，同时允许远程系统仅能够查询时间。有关更多详细信息，请参阅 [ntp.conf(5)](https://man.freebsd.org/cgi/man.cgi?query=ntp.conf\&sektion=5\&format=html) 中的 `Access Control Support` 子部分。

`server` 关键字指定一个服务器进行查询。该文件可以包含多个 `server` 关键字，每行列出一个服务器。`pool` 关键字指定一个服务器池。ntpd 会根据需要从该池中添加一个或多个服务器，以达到 `tos minclock` 值所指定的对等方数量。`iburst` 关键字指示 ntpd 在首次建立联系时与服务器进行八次快速数据包交换，以帮助快速同步系统时间。

`leapfile` 关键字指定一个文件的位置，该文件包含关于闰秒的信息。该文件会通过 [periodic(8)](https://man.freebsd.org/cgi/man.cgi?query=periodic\&sektion=8\&format=html) 自动更新。此关键字指定的文件位置必须与 **/etc/rc.conf** 中的 `ntp_db_leapfile` 变量所设置的路径匹配。

### 32.12.1.2. **/etc/rc.conf** 中的 NTP 条目

设置 `ntpd_enable=YES` 以在启动时启动 ntpd。将 `ntpd_enable=YES` 添加到 **/etc/rc.conf** 后，可以通过以下命令立即启动 ntpd，而无需重启系统：

```sh
# service ntpd start
```

只需设置 `ntpd_enable` 即可使用 ntpd。下面列出了一些可选的 **rc.conf** 变量，可以根据需要进行配置。

设置 `ntpd_sync_on_start=YES` 以允许 ntpd 在启动时一次性调整时钟的任何偏差。通常，如果时钟偏差超过 1000 秒，ntpd 会记录错误信息并退出。此选项在没有电池支持的实时时钟的系统中尤其有用。

设置 `ntpd_oomprotect=YES` 以保护 ntpd 守护进程不被系统因内存不足 (OOM) 情况下而终止。

设置 `ntpd_config=` 为备用 **ntp.conf** 文件的位置。

设置 `ntpd_flags=` 以包含其他 ntpd 所需的标志，但避免使用以下由 **/etc/rc.d/ntpd** 内部管理的标志：

* `-p`（pid 文件位置）
* `-c`（使用 `ntpd_config=` 代替）

### 32.12.1.3. ntpd 和非特权用户 `ntpd`

在 FreeBSD 上，ntpd 可以作为一个非特权用户启动并运行。这需要 [mac\_ntpd(4)](https://man.freebsd.org/cgi/man.cgi?query=mac_ntpd\&sektion=4\&format=html) 策略模块。**/etc/rc.d/ntpd** 启动脚本首先检查 NTP 配置。如果可能，它会加载 `mac_ntpd` 模块，然后以非特权用户 `ntpd`（用户 ID 123）启动 ntpd。为了避免文件和目录访问问题，当配置包含任何与文件相关的选项时，启动脚本不会自动以 `ntpd` 用户身份启动 ntpd。

在 `ntpd_flags` 中出现以下任何选项时，需要按照下面的描述手动配置以便作为 `ntpd` 用户运行：

* -f 或 --driftfile
* -i 或 --jaildir
* -k 或 --keyfile
* -l 或 --logfile
* -s 或 --statsdir

在 **ntp.conf** 中出现以下任何关键字时，需要按照下面的描述手动配置以便作为 `ntpd` 用户运行：

* crypto
* driftfile
* key
* logdir
* statsdir

要手动配置 ntpd 作为 `ntpd` 用户运行，必须：

* 确保 `ntpd` 用户对配置中指定的所有文件和目录具有访问权限。
* 安排加载或将 `mac_ntpd` 模块编译到内核中。有关详细信息，请参见 [mac\_ntpd(4)](https://man.freebsd.org/cgi/man.cgi?query=mac_ntpd\&sektion=4\&format=html)。
* 在 **/etc/rc.conf** 中设置 `ntpd_user="ntpd"`。

## 32.12.2. 使用 PPP 连接与 NTP

ntpd 不需要与互联网的永久连接即可正常运行。然而，如果 PPP 连接配置为按需拨号，则应防止 NTP 流量触发拨号或保持连接处于活动状态。可以通过在 **/etc/ppp/ppp.conf** 中配置 `filter` 指令来实现。例如：

```ini
set filter dial 0 deny udp src eq 123
# 防止 NTP 流量触发拨号
set filter dial 1 permit 0 0
set filter alive 0 deny udp src eq 123
# 防止传入的 NTP 流量保持连接打开
set filter alive 1 deny udp dst eq 123
# 防止传出的 NTP 流量保持连接打开
set filter alive 2 permit 0/0 0/0
```

更多细节，请参考 [ppp(8)](https://man.freebsd.org/cgi/man.cgi?query=ppp\&sektion=8\&format=html) 中的 `PACKET FILTERING` 部分以及 **/usr/share/examples/ppp/** 中的示例。

> **注意**
>
> 一些互联网接入提供商会阻止较低端口，从而导致 NTP 无法正常工作，因为回复无法到达机器。
