blocklistd
Table of Contents
blocklistd 是一个守护进程:它通过套接字监听,接收其他守护进程发送的连接成功或失败通知,主要用于封锁发起过多连接尝试的来源地址
典型场景是互联网上的 SSH 服务常收到大量来自机器人或脚本的请求,这些请求试图通过密码猜测获取访问权限
使用 blocklistd 后,守护进程可通知防火墙,在单个来源地址尝试多次后创建过滤规则,以封锁过多的连接尝试。
blocklistd 最初在 NetBSD 上开发,并于 NetBSD 7 发布,最初名为 blacklistd NetBSD 于 2020 年将其更名为 blocklistd,FreeBSD 于 2025 年跟进更名 自 FreeBSD 11 起从 NetBSD 引入,在 FreeBSD 11–14 中命令和服务名仍为 blacklistd,配置文件为 /etc/blacklistd.conf FreeBSD 15 起改为 blocklistd,配置文件对应为 /etc/blocklistd.conf 本节以 FreeBSD 15 的 blocklistd 为准,使用旧版本的读者需将文中命令和路径中的 blocklistd 替换为 blacklistd
启用 blocklistd
要在系统启动时启用该守护进程,执行以下命令:
$ service blocklistd enable
要手动启动服务,运行以下命令:
$ service blocklistd start
创建 blocklistd 规则集
blocklistd 规则集位于 /etc/blocklistd.conf 文件,每行填写一条规则
- 每条规则由空格或制表符分隔的七个字段组成
- 规则分为 local 和 remote,分别应用于 blocklistd 所在的本机和外部来源
本地规则
默认配置文件 /etc/blocklistd.conf 内容如下:
# Blocklist rule # adr/mask:port type proto owner name nfail duration [local] ssh stream * * * 3 24h ftp stream * * * 3 24h smtp stream * * * 3 24h submission stream * * * 3 24h #6161 stream tcp6 christos * 2 10m * * * * * 3 60 # adr/mask:port type proto owner name nfail duration [remote] #129.168.0.0/16 * * * = * * #[2001:db8::]/32:ssh * * * = * * #6161 = = = =/24 = = #* stream tcp * = = =
文件 /etc/blocklistd.conf 中的默认本地规则如下所示:
[local] ssh stream * * * 3 24h ftp stream * * * 3 24h smtp stream * * * 3 24h submission stream * * * 3 24h #6161 stream tcp6 christos * 2 10m * * * * * 3 60
- [local] 段后的所有规则均视为本地规则(此为默认设置),适用于本机
- [remote] 段后,后续规则将作为远程规则处理
- 通配符由星号 (*) 表示,匹配该字段中的任意内容
七个字段共同定义一条规则,字段之间以制表符或空格分隔:
- adr/mask:port、type、proto、owner:前四个字段用于标识需列入封禁列表的流量
adr/mask:port 字段:定义地址。在本地规则中,该字段是网络端口
adr/mask:port 地址字段的语法: [地址|接口][/掩码][:端口] adr/mask:port 地址字段可按数字格式指定为 IPv4 或 IPv6(以方括号表示),也可使用接口名称,如 em0
- type 字段:定义套接字类型
- TCP 套接字为 stream 类型
UDP 则用 dgram 表示
因为 SSH 基于 TCP 协议,上例使用的是 stream
proto 字段:定义协议
可用协议包括 tcp、udp、tcp6、udp6 或数值形式的协议号 除非有必要按特定协议区分流量,否则通常如示例所示使用通配符来匹配所有协议
owner 字段:定义报告事件的守护进程的有效用户或属主
守护进程报告事件时,以此字段标识其身份 这里可以使用用户名或 UID,也可以使用通配符
- name、nfail、duration:后三个字段定义 blocklistd 的行为
name 字段:定义数据包过滤规则名称,标志着规则行为部分的开始
如果需要单独的封锁列表,可以在此字段中使用锚点名称 在其他情况下,使用通配符即可
名称以连字符 _-_开头时,表示应使用带有默认规则名称的锚点。修改后的示例如下:
ssh stream * * -ssh 3 24h 在此规则下,新的封禁规则将添加到锚点 blocklistd-ssh 中
如果因某 IP 违反某条规则而需封锁整个子网,可以在规则名称中使用 / 这样名称中 / 后面的部分会当作掩码,应用到规则中指定的地址
例如,以下这条规则会封锁与指定地址相邻的所有 /24 网段的地址 22 stream tcp * */24 3 24h 这里需指定正确的协议。IPv4 和 IPv6 对 /24 的处理不同,因此在此规则的第三个字段中不能使用 * 如果该网络中任何主机出现违规行为,则整个网络中的其他主机均将受到封禁
nfail 字段:设置需多少次登录失败方可将远程 IP 列入封禁列表。如果在此位置使用通配符,则永不触发封禁
在上例中,定义了 3 次登录失败的限制,即在 SSH 上登录失败 3 次后,该 IP 被封禁
- duration 字段:指定主机列入封禁列表的时间
- 默认单位为秒,亦可指定 m、h、d 等后缀,分别表示分钟、小时和天
完整的示例规则 ssh stream * * * 3 24h 表示:SSH 验证失败三次后,该主机将生成一条新的 PF 封锁规则 规则匹配时,首先按顺序检查 local 规则,从最具体(匹配条件最严格、范围最小的规则)到最不具体(匹配条件宽泛、范围大的规则) 匹配成功后,会应用 remote 规则,并由匹配的 remote 规则修改字段 name、nfail 和 duration
远程规则
remote 规则用于指定 blocklistd 如何根据当前评估的远程主机调整其行为。remote 规则中的每个字段与 local 规则相同,唯一的区别在于 blocklistd 使用这些字段的方式不同。以下用示例规则说明:
# adr/mask:port type proto owner name nfail duration [remote] #129.168.0.0/16 * * * = * * #[2001:db8::]/32:ssh * * * = * * #6161 = = = =/24 = = #* stream tcp * = = =
地址字段可为 IP 地址(IPv4 或 IPv6)、端口,或二者兼有
这样可以为特定的远程地址范围设置特殊规则(如本例所示)
- 套接字类型、协议和属主字段的解释与 local 规则完全相同
- name 字段有所不同:在 remote 规则中,等号 = 表示 blocklistd 沿用匹配的 local 规则中 name 字段的值
- 如果 name 字段写为 =/XX 的格式(如 =/24),则在沿用 name 值的同时,将 /XX 作为掩码前缀应用于地址(即封禁整个 /XX 子网)
若仅使用 = 而不带 / 部分,则不会修改掩码
此处也可使用 PF 锚点名称,此时 blocklistd 会将该地址块的规则添加到该锚点下 若使用通配符,则使用默认表格
nfail 列可为某个地址定义自定义失败次数
这在设置特定规则的例外时很有用,例如给予某些用户较宽松的登录尝试机会
- 第六个字段使用星号时,封禁功能即告禁用
第六个字段使用星号时,封禁功能即告禁用
配置 blocklistd 客户端
在 FreeBSD 中,有一些软件包可以利用 blocklistd 的功能 最常用的是 ftpd(8) 和 sshd(8),可阻止过多的连接尝试
要为 SSH 守护进程启用 blocklistd,在 /etc/ssh/sshd_config 文件中添加以下行:
UseBlocklist yes
随后重新启动 sshd 使更改生效
对于 ftp/freebsd-ftpd,可通过 -B 参数启用 blocklist 功能。既可以在 /etc/inetd.conf 中设置该参数,也可以像下面这样作为标志写入 /etc/rc.conf :
ftpd_flags="-B"
启用 PF 防火墙
blocklistd 只是一个监控的守护进程,本身并无封禁能力,需依赖防火墙才能封禁 可以参考其他章节安装并启用 PF 防火墙 示例中使用了 PF,但 FreeBSD 上其他可用防火墙也可与 blocklistd 配合使用
blocklistd 会将所有封禁规则放入 /etc/pf.conf 文件中的 PF 锚点 blocklistd 下。 因此,需要将以下内容写入 PF 防火墙配置文件 /etc/pf.conf 中:
ext_if="em0" # 需替换为实际的网卡接口 table <blocklistd> persist anchor "blocklistd/*" block drop in log quick on $ext_if from <blocklistd> to any pass out all
随后启用 PF 防火墙
管理 blocklistd
blocklistd 提供了管理工具 blocklistctl(8) ,用于查看 blocklistd.conf(5) 中定义的规则封禁的地址和网络。
要查看当前封禁的主机列表,可使用以下命令:
$ blocklistctl dump -b rulename address/ma:port id nfail last access blocklistd 192.168.179.32/32:22 OK 3/3 2026/04/16 12:33:43
此示例显示,从地址范围 192.168.179.32/32 发起的端口 22 登录尝试已达到 3 次上限 由于 SSH 允许客户端在单条 TCP 连接上进行多次登录尝试,实际尝试次数可能略超配置的 nfail 值 输出中的“last access”列显示了最后一次连接尝试的时间
要查看该主机在封锁列表上剩余的时间,可在之前的命令中添加 -r 参数
$ blocklistctl dump -br rulename address/ma:port id nfail remaining time blocklistd 192.168.179.32/32:22 OK 3/3 2m13
在此示例中,距离该主机解除封锁还有 2 分 13 秒
测试时可先将配置文件 /etc/blocklistd.conf 保存到其他位置,再新建空的配置文件,写入 * * * * * 3 180(对任意端口的任意连接,超过三次即封禁 180 秒) 另外,blocklistd 不会中断当前正在进行的连接,因此测试前需断开相关连接。 切勿在生产环境执行此测试!
从 blocklistd 中移除主机
有时需在剩余时间重置前将主机从封锁列表中移出,但 blocklistd 本身并未提供此功能
不过,可以使用 pfctl 命令从 PF 表中移除该地址。每个封禁端口在 /etc/pf.conf 的 blocklistd 锚点下都有一个子锚点
例如,用于封锁端口 22 的子锚点是 blocklistd/22 该子锚点内有一个包含所有封禁地址的表,表名为 port 加上端口号,在此例中为 port22
有了这些信息,就可以使用 pfctl(8) 来显示列出的所有地址:
$ pfctl -a blocklistd/22 -t port22 -T show 192.168.179.1
从列表中识别出需解除封禁的地址后,使用以下命令将其从列表中移除:
$ pfctl -a blocklistd/22 -t port22 -T delete 192.168.179.1
blocklistd 无法感知 PF 中的更改,即使已从 PF 中移除该地址,该地址仍会出现在 blocklistctl 列表中 blocklistd 数据库中的该条目最终会过期,并从输出中移除
如果该主机再次匹配 blocklistd 中的某条封禁规则,则此主机的对应条目将再次被添加
| Previous: Fail2Ban | Home: 防火墙 |