> 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/ask/flat/chapter-31-firewalls/di-31.6-jie-blocklistd.md).

# 31.6 blocklistd

blocklistd is a daemon: it listens on a socket, receiving notifications from other daemons about connection successes or failures, primarily used to block source addresses that initiate too many connection attempts. A typical scenario is that SSH services on the Internet often receive a large number of requests from bots or scripts attempting to gain access through password guessing. With blocklistd, the daemon can notify the firewall to create filtering rules after a single source address attempts too many connections, thereby blocking excessive connection attempts.

blocklistd was originally developed on NetBSD and released with NetBSD 7, initially named blacklistd. NetBSD renamed it to blocklistd in 2020, and FreeBSD followed suit in 2025. It was introduced from NetBSD starting with FreeBSD 11, where the command and service name remained `blacklistd` in FreeBSD 11–14, with the configuration file at **/etc/blacklistd.conf**; starting from FreeBSD 15, it was changed to `blocklistd`, with the corresponding configuration file at **/etc/blocklistd.conf**. This section is based on FreeBSD 15's `blocklistd`; readers using older versions should replace `blocklistd` in the commands and paths with `blacklistd`.

This section introduces the usage and examples of blocklistd. Readers should be familiar with basic firewall concepts.

## Enabling blocklistd

To enable the daemon at system startup, execute the following command:

```sh
# service blocklistd enable
```

To manually start the service, run the following command:

```sh
# service blocklistd start
```

## Creating a blocklistd Rule Set

The blocklistd rule set is located in the **/etc/blocklistd.conf** file, with one rule per line. Each rule consists of seven fields separated by spaces or tabs. Rules are divided into `local` and `remote`, applied to the local machine where blocklistd is running and to external sources, respectively.

### Local Rules

The default configuration file **/etc/blocklistd.conf** contains the following:

```ini
# 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	*		=	=	=
```

The default local rules in the file **/etc/blocklistd.conf** are shown below:

```ini
[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
```

All rules after the `[local]` section are treated as local rules (this is the default setting) and apply to the local machine. When the `[remote]` section is encountered, subsequent rules are treated as remote rules. Wildcards are represented by an asterisk (`*`), matching any content in that field.

The seven fields together define a rule, with fields separated by tabs or spaces:

* `adr/mask:port`, `type`, `proto`, `owner`: The first four fields identify the traffic to be placed on the block list.
  * `adr/mask:port` field: Defines the address. In local rules, this field is the network port.

    The syntax for the `adr/mask:port` address field:

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

    The `adr/mask:port` address field can be specified numerically as IPv4 or IPv6 (indicated by square brackets), or using an interface name such as `em0`.
  * `type` field: Defines the socket type. TCP sockets are of `stream` type, while UDP is represented by `dgram`. Since SSH is based on the TCP protocol, the example above uses `stream`.
  * `proto` field: Defines the protocol. Available protocols include `tcp`, `udp`, `tcp6`, `udp6`, or a numeric protocol number. Unless it is necessary to distinguish traffic by specific protocol, wildcards are typically used as shown in the example to match all protocols.
  * `owner` field: Defines the effective user or owner of the daemon reporting the event. When a daemon reports an event, this field identifies it. A username or UID can be used here, or a wildcard.
* `name`, `nfail`, `duration`: The last three fields define blocklistd's behavior.
  * `name` field: Defines the packet filter rule name, marking the beginning of the rule's behavioral portion. If a separate block list is needed, an anchor name can be used in this field. Otherwise, a wildcard is sufficient. When the name begins with a hyphen (`-`), it indicates that an anchor with the default rule name should be used. The modified example is as follows:

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

    **Under this rule**, new ban rules will be added to the anchor `blocklistd-ssh`.

    If an entire subnet needs to be blocked because a particular IP violated a rule, a **/** can be used in the rule name. The part after the **/** in the name will be treated as a mask, applied to the address specified in the rule. For example, the following rule will block all addresses in the **/24** network segment adjacent to the specified address.

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

    > **Note**
    >
    > The correct protocol must be specified here. IPv4 and IPv6 handle **/24** differently, so `*` cannot be used in the third field of this rule.

    This rule defines that if any host in this network violates the rule, all other hosts in the network will also be blocked.
  * `nfail` field: Sets how many login failures are required before a remote IP is placed on the block list. If a wildcard is used in this position, blocking is never triggered. In the example above, a limit of 3 login failures is defined, meaning that after 3 failed SSH login attempts, the IP is blocked.
* `duration` field: Specifies how long a host remains on the block list. The default unit is seconds, but suffixes such as `m`, `h`, and `d` can be specified to indicate minutes, hours, and days, respectively.

The complete example rule `ssh stream * * * 3 24h` means: after three SSH authentication failures, a new PF blocking rule will be generated for that host. When a rule matches, `local` rules are checked in order from the most specific (rules with the strictest matching conditions and smallest scope) to the least specific (rules with broad matching conditions and large scope). After a successful match, `remote` rules are applied, and the matching `remote` rule modifies the `name`, `nfail`, and `duration` fields.

### Remote Rules

`remote` rules specify how blocklistd adjusts its behavior based on the remote host currently being evaluated. Each field in a `remote` rule is the same as in a `local` rule; the only difference is how blocklistd uses these fields. The following explains using example rules:

```ini
# adr/mask:port	type	proto	owner		name	nfail	duration
[remote]
#129.168.0.0/16	*	*	*		=	*	*
#[2001:db8::]/32:ssh	*	*	*		=	*	*
#6161		=	=	=		=/24	=	=
#*		stream	tcp	*		=	=	=
```

The address field can be an IP address (IPv4 or IPv6), a port, or both. This allows setting special rules for specific remote address ranges (as shown in this example). The socket type, protocol, and owner fields are interpreted exactly the same as in `local` rules.

The name field differs: in `remote` rules, an equals sign (`=`) indicates that blocklistd uses the value of the name field from the matching `local` rule. If the name field is written in the format `=/XX` (such as `=/24`), the name value is inherited while applying `/XX` as a mask prefix to the address (i.e., blocking the entire `/XX` subnet). If only `=` is used without the `/` portion, the mask is not modified. A PF anchor name can also be used here, in which case blocklistd adds rules for that address block under the anchor. If a wildcard is used, the default table is used.

The `nfail` column can define a custom failure count for a specific address. This is useful when setting exceptions for specific rules, such as giving certain users more lenient login attempt opportunities. When the sixth field uses an asterisk, the blocking feature is disabled.

`remote` rules can impose stricter restrictions compared to login attempts from the local network (such as an office).

## Configuring blocklistd Clients

In FreeBSD, several packages can take advantage of blocklistd's functionality. The most commonly used are ftpd(8) and sshd(8), which can block excessive connection attempts.

To enable blocklistd for the SSH daemon, add the following line to the **/etc/ssh/sshd\_config** file:

```ini
UseBlocklist yes
```

Then restart `sshd` for the changes to take effect.

For the Port ftp/freebsd-ftpd, blocklist functionality can be enabled via the `-B` parameter. This can be set either in **/etc/inetd.conf** or written as a flag in **/etc/rc.conf** as follows:

```ini
ftpd_flags="-B"
```

The above is all the configuration needed for these programs to communicate with blocklistd.

## Enabling the PF Firewall

blocklistd is only a monitoring daemon and has no blocking capability on its own; it relies on a firewall to enforce blocks. Refer to other sections for installing and enabling the PF firewall. The example uses PF, but other available firewalls on FreeBSD can also work with blocklistd.

blocklistd places all blocking rules under the PF anchor `blocklistd` in the **/etc/pf.conf** file. Therefore, the following content needs to be written into the PF firewall configuration file **/etc/pf.conf**:

```ini
ext_if="em0"        # Must be replaced with the actual network interface
table <blocklistd> persist
anchor "blocklistd/*"
block drop in log quick on $ext_if from <blocklistd> to any
pass out all
```

Then enable the PF firewall.

## Managing blocklistd

blocklistd provides the management tool blocklistctl(8) for viewing addresses and networks blocked by the rules defined in blocklistd.conf(5).

To view the current list of blocked hosts, use the following command:

```sh
# 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
```

This example shows that login attempts from the address range **192.168.179.32/32** on port `22` have reached the limit of 3. Since SSH allows clients to make multiple login attempts on a single TCP connection, the actual number of attempts may slightly exceed the configured `nfail` value. The "last access" column in the output shows the time of the last connection attempt.

> **Tip**
>
> For testing, first save the configuration file **/etc/blocklistd.conf** to another location, then create a new empty configuration file with the content `* * * * * 3 180` (block any connection on any port after three attempts for 180 seconds). Also, **blocklistd does not interrupt currently active connections, so relevant connections must be disconnected before testing.** Do not perform this test in a production environment!

To view the remaining time a host has on the block list, add the `-r` parameter to the previous command.

```sh
# blocklistctl dump -br
rulename			  address/ma:port id      nfail   remaining time
blocklistd		192.168.179.32/32:22  OK      3/3     2m13
```

In this example, there are 2 minutes and 13 seconds remaining before the host is unblocked.

## Removing a Host from blocklistd

Sometimes it is necessary to remove a host from the block list before the remaining time expires. However, blocklistd itself does not provide this functionality.

However, the pfctl command can be used to remove the address from the PF table. Each blocked port has a sub-anchor under the blocklistd anchor in **/etc/pf.conf**. For example, the sub-anchor for blocking port 22 is **blocklistd/22**. Within this sub-anchor, there is a table containing all blocked addresses, with the table name being "port" followed by the port number, which in this case is `port22`.

With this information, pfctl(8) can be used to display all listed addresses:

```sh
# pfctl -a blocklistd/22 -t port22 -T show
192.168.179.1
```

After identifying the address to be unbanned from the list, use the following command to remove it:

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

blocklistd is not aware of changes in PF, so even after the address has been removed from PF, it will still appear in the blocklistctl output. The entry in the blocklistd database will eventually expire and be removed from the output.

If that host matches a blocking rule in blocklistd again, the corresponding entry for that host will be added once more.


---

# 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:

```
GET https://book.bsdcn.org/ask/flat/chapter-31-firewalls/di-31.6-jie-blocklistd.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.
