# 33.6.Blacklistd

## 33.6.1. 启用 Blacklistd

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

```sh
# sysrc blacklistd_enable=yes
```

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

```sh
# service blacklistd start
```

## 33.6.2. 创建 Blacklistd 规则集

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

### 33.6.2.1. 本地规则

本地规则的一个示例 blacklistd.conf 条目如下所示：

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

### 33.6.2.2. 远程规则

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

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

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

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

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

远程规则允许比来自本地网络（例如办公室）尝试登录时更加严格地执行限制。

## 33.6.3. Blacklistd 客户端配置

在 FreeBSD 中，有一些软件包可以利用 blacklistd 的功能。最突出的两个是 [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 守护进程中启用 blacklistd，请在 **/etc/ssh/sshd\_config** 中添加以下行：

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

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

## 33.6.4. Blacklistd 管理

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

```sh
# blacklistctl dump -b
      address/ma:port id      nfail   last access
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 连接上尝试多次登录。当前的连接不会被 blacklistd 停止。最后一次连接尝试的时间显示在 `last access` 列中。

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

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

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

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

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

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

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

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

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


---

# 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-33-zhang-fang-huo-qiang/33.6.-blacklistd.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.
