UP | HOME

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: 防火墙