> For the complete documentation index, see [llms.txt](https://book.bsdcn.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://book.bsdcn.org/handbook/di-34-zhang-fang-huo-qiang/34.6.-blocklistd.md).

# 34.6.blocklistd

blocklistd 是守护进程，监听套接字，等待接收来自其他守护进程关于连接尝试失败或成功的通知。它最广泛用于阻止对开放端口的过多连接尝试。典型的例子是互联网上运行的 SSH 服务器会收到大量来自机器人或脚本的请求，这些机器人或脚本试图猜测密码以获取访问权限。

使用 blocklistd，守护进程可通知防火墙创建过滤规则，在多次尝试后阻止来自单一来源的过多连接尝试。blocklistd 最初在 NetBSD 上开发，并随其版本 7 发布，最初名为 blacklistd。FreeBSD 11 从 NetBSD 引入了 blocklistd。

本章介绍如何设置和配置 blocklistd，并提供使用示例。读者应熟悉规则等基本防火墙概念。有关详细信息，请参阅防火墙相关章节。

示例中使用 PF，但 FreeBSD 上可用的其他防火墙也应该能与 blocklistd 一起工作。

## 34.6.1. 启用 blocklistd

blocklistd 的主要配置存储在 [blocklistd.conf(5)](https://man.freebsd.org/cgi/man.cgi?query=blocklistd.conf\&sektion=5\&format=html) 中。还提供了各种命令行选项来更改 blocklistd 的运行时行为。跨重启保留的持久配置应存储在 **/etc/blocklistd.conf** 中。要在系统引导时启用该守护进程，请将 `blocklistd_enable` 行添加到 **/etc/rc.conf** 中，如下所示：

```sh
# sysrc blocklistd_enable=yes
```

要手动启动服务，请运行以下命令：

```sh
# service blocklistd start
```

## 34.6.2. 创建 blocklistd 规则集

blocklistd 的规则在 [blocklistd.conf(5)](https://man.freebsd.org/cgi/man.cgi?query=blocklistd.conf\&sektion=5\&format=html) 中配置，每行包含一个条目。每个规则包含由空格或制表符分隔的元组。规则可以属于 `local` 或 `remote`，分别适用于运行 blocklistd 的机器或外部源。

### 34.6.2.1. 本地规则

本地规则的示例 blocklistd.conf 条目如下所示：

```sh
[local]
ssh             stream  *       *               *       3       24h
```

所有跟随 `[local]` 部分的规则都被视为本地规则（这是默认设置），适用于本地机器。遇到 `[remote]` 部分时，后续规则将作为远程机器规则处理。

七个由制表符或空格分隔的字段定义规则。前四个字段标识应列入黑名单的流量。接下来的三个字段定义 blocklistd 的行为。通配符由星号 (`*`) 表示，匹配该字段中的任何内容。第一个字段定义位置。本地规则中，这些是网络端口。位置字段的语法如下：

```sh
[address|interface][/mask][:port]
```

地址可以以数字格式指定为 IPv4，或者用方括号表示 IPv6。也可以使用像 `em0` 这样的接口名称。

第二个字段定义了套接字类型。TCP 套接字为 `stream` 类型，而 UDP 则用 `dgram` 表示。上面的示例使用的是 TCP，因为 SSH 使用的是该协议。

第三个字段可在 blocklistd 规则中使用协议。可使用的协议包括：`tcp`、`udp`、`tcp6`、`udp6` 或数字。像上面的示例一样，通常使用通配符匹配所有协议，除非有特别的理由需要通过特定协议区分流量。

在第四个字段中，定义了报告事件的守护进程的有效用户或所有者。这里可以使用用户名或 UID，也可以使用通配符（参见上面的示例规则）。

第五个字段声明了数据包过滤规则的名称，这标志着规则的行为部分。默认情况下，blocklistd 将所有阻塞规则放置在 `pf.conf` 中的名为 `blocklistd` 的锚点下，如下所示：

```sh
anchor "blocklistd/*" in on $ext_if
block in
pass out
```

对于单独的黑名单，可在该字段中使用锚点名称。其他情况下，使用通配符就足够了。名称以连字符（`-`）开头时，意味着应使用带有默认规则名称的锚点。下面是修改后的示例，使用了连字符：

```sh
ssh             stream  *       *               -ssh       3       24h
```

在此规则下，任何新的黑名单规则将添加到名为 `blocklistd-ssh` 的锚点中。

要在单次规则违反时阻止整个子网，可在规则名称中使用 `/`。这会使名称的剩余部分解释为应用于规则中指定地址的掩码。例如，此规则将阻止与 `/24` 相邻的每个地址：

```sh
22              stream  tcp       *               */24    3       24h
```

> **注意**
>
> 这里需要指定正确的协议。IPv4 和 IPv6 对 `/24` 的处理不同，因此在此规则的第三个字段中不能使用 `*`。

此规则定义，如果该网络中的任何主机表现不当，整个网络中的其他主机也将被阻止。

第六个字段，称为 `nfail`，设置需要多少次登录失败才能将远程 IP 列入黑名单。在此位置使用通配符时，意味着永远不会发生阻止。在上面的示例规则中，定义了三次登录失败的限制，即在单个连接上三次尝试登录 SSH 后，该 IP 会被阻止。

最后一个字段指定了主机被列入黑名单的时间。默认单位为秒，但也可以指定如 `m`、`h` 和 `d` 等后缀，分别表示分钟、小时和天。

完整的示例规则意味着在三次尝试 SSH 认证后，将为该主机创建新的 PF 阻止规则。规则匹配按顺序执行，首先检查本地规则，最具体的规则优先。匹配后，将应用 `remote` 规则，并通过匹配的 `remote` 规则更改规则中的名称、`nfail` 和持续时间字段。

### 34.6.2.2. 远程规则

远程规则用于指定 blocklistd 如何根据当前评估的远程主机改变其行为。远程规则中的每个字段与本地规则相同。唯一的区别在于 blocklistd 使用它们的方式。为说明这一点，使用以下示例规则：

```sh
[remote]
203.0.113.128/25 *      *       *               =/25    =       48h
```

地址字段可以是 IP 地址（无论是 v4 还是 v6）、端口或两者的组合。这样能为特定的远程地址范围设置特殊规则，就像此示例一样。套接字类型、协议和所有者字段的解释与本地规则相同。

不过，名称字段是不同的：远程规则中的等号（`=`）告诉 blocklistd 使用匹配的本地规则中的值。这意味着防火墙规则条目会被采用，并且会添加 `/25` 前缀（即子网掩码为 **255.255.255.128**）。来自该地址范围的连接被列入黑名单时，整个子网都会受到影响。这里也可以使用 PF 锚点名称，在这种情况下，blocklistd 会将此地址块的规则添加到该名称的锚点中。使用通配符时，将使用默认表。

可以为地址在 `nfail` 列中定义自定义的失败次数。此字段对特定规则的例外情况很有用，例如，可能让某人对登录尝试有更宽松的限制或更多的容忍度。使用星号（`*`）时，将禁用阻止功能。

与来自本地网络（例如办公室）的登录尝试相比，远程规则允许对登录尝试实施更严格的限制。

## 34.6.3. blocklistd 客户端配置

在 FreeBSD 中，有一些软件包可以利用 blocklistd 的功能。最突出的两个是 [ftpd(8)](https://man.freebsd.org/cgi/man.cgi?query=ftpd\&sektion=8\&format=html) 和 [sshd(8)](https://man.freebsd.org/cgi/man.cgi?query=sshd\&sektion=8\&format=html)，它们可以阻止过多的连接尝试。要在 SSH 守护进程中启用 blocklistd，请在 **/etc/ssh/sshd\_config** 中添加以下行：

```sh
UseBlocklist yes
```

然后重新启动 sshd 使更改生效。

对于 [ftpd(8)](https://man.freebsd.org/cgi/man.cgi?query=ftpd\&sektion=8\&format=html)，可以使用 `-B` 来启用黑名单功能，这可以在 **/etc/inetd.conf** 中设置，或者作为标志在 **/etc/rc.conf** 中设置，如下所示：

```sh
ftpd_flags="-B"
```

这就是让这些程序与 blocklistd 通信所需的所有设置。

## 34.6.4. Blocklistd 管理

blocklistd 提供了名为 [blocklistctl(8)](https://man.freebsd.org/cgi/man.cgi?query=blocklistctl\&sektion=8\&format=html) 的管理工具。它显示通过 [blocklistd.conf(5)](https://man.freebsd.org/cgi/man.cgi?query=blocklistd.conf\&sektion=5\&format=html) 中定义的规则列入黑名单的地址和网络。要查看当前被阻止的主机列表，可使用 `dump` 命令并结合 `-b` 参数，如下所示：

```sh
# blocklistctl dump -b
rulename                address/ma:port id      nfail   last access
blocklistd        213.0.123.128/25:22   OK      6/3     2019/06/08 14:30:19
```

此示例显示了来自地址范围 **213.0.123.128/25** 的端口 22 上发生的连接尝试，其中有 6 次尝试，超过了允许的 3 次。列出的尝试次数超过了允许的次数，因为 SSH 让客户端能在单个 TCP 连接上尝试多次登录。当前的连接不会被 blocklistd 停止。最后一次连接尝试的时间显示在 `last access` 列中。

要查看此主机剩余的封锁时间，可以在之前的命令中添加 `-r` 参数：

```sh
# blocklistctl dump -br
rulename                address/ma:port id      nfail   remaining time
blocklistd        213.0.123.128/25:22   OK      6/3     36s
```

在此示例中，距离该主机解除封锁还有 36 秒。

## 34.6.5. 从黑名单中移除主机

有时需要在剩余时间到期之前将某个主机从黑名单中移除。不幸的是，blocklistd 并未提供直接执行此操作的功能。然而，可使用 pfctl 从 PF 表中移除该地址。对于每个被阻止的端口，**/etc/pf.conf** 中的 blocklistd 锚点内都会定义子锚点。例如，如果有子锚点用于阻止端口 22，它会被命名为 `blocklistd/22`。该子锚点内部有表格，包含被阻止的地址。此表格的名称为 `port` 后跟端口号。在此示例中，其名称为 `port22`。有了这些信息后，就可使用 [pfctl(8)](https://man.freebsd.org/cgi/man.cgi?query=pfctl\&sektion=8\&format=html) 显示列出的所有地址，如下所示：

```sh
# pfctl -a blocklistd/22 -t port22 -T show
...
213.0.123.128/25
...
```

从列表中识别出需要解除封锁的地址后，使用以下命令将其从列表中移除：

```sh
# pfctl -a blocklistd/22 -t port22 -T delete 213.0.123.128/25
```

该地址现在已从 PF 中移除，但仍会出现在 blocklistctl 列表中，因为 blocklistd 并不知道 PF 中的更改。blocklistd 数据库中的该条目最终会过期，并从输出中移除。如果该主机再次匹配 blocklistd 中的某条封锁规则，则该条目将再次添加。


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## 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, and the optional `goal` query parameter:

```
GET https://book.bsdcn.org/handbook/di-34-zhang-fang-huo-qiang/34.6.-blocklistd.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

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.
