How to Block IPs with a Blacklist Using PF Tables on OpenBSD
- Last updated: May 2, 2026
This How-To explains how to use OpenBSD Packet Filter (PF) to block IP addresses and CIDR ranges loaded from an external blocklist. The result is similar in spirit to PeerBlock on Windows: addresses listed in a file are loaded into a PF table and blocked by firewall rules.
Configuration
- OS: OpenBSD 7.8
- Firewall: Packet Filter (PF)
- Example protected host:
192.168.1.10 - Blocklist file:
/etc/blocklist
Commands
Download a black list
You can download blocklists from iBlocklist. For example, download the PrimaryThreats list here. Once downloaded, extract and format the file so it can be used with OpenBSD Packet Filter (PF).
- Get the list:
root# wget "URLtomyremotelist" -O list.zip
- Unzip the list:
root# unzip file.zip
- Format the list:
root# cut -d ":" -f2 list.txt | grep -E "[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}" > blocklist.tmp
root# sed -i 's/-/:/' blocklist.tmp
root# for i in $(cat blocklist.tmp); do echo "$i"; ipcalc -r "$i"| grep "/" >> blocklist; done
- Copy the blocklist file to
/etc/blocklist:
root# cp blocklist /etc/blocklist
Packet Filter configuration
Add a table and the matching rules to /etc/pf.conf. This example blocks traffic both from the blocklisted addresses to the protected host and from the protected host to the blocklisted addresses.
wan = "em0"
lan = "em1"
protected_host = "192.168.1.10"
# Increase the global number of addresses that can be stored in PF tables.
set limit table-entries 1000000
# Load the external blocklist into a persistent table.
table <blocklist> persist file "/etc/blocklist"
pass out on $wan
pass in quick on $lan inet proto tcp from $protected_host to any port { 80 443 }
block in quick log on $wan from <blocklist> to $protected_host
block out quick log on $wan from $protected_host to <blocklist>
Validate and reload PF
- Check the syntax before loading the ruleset:
root# pfctl -nf /etc/pf.conf
- Reload PF if the syntax check succeeds:
root# pfctl -f /etc/pf.conf
- Inspect the loaded table:
root# pfctl -t blocklist -T show | more
Update the blocklist without reloading all rules
After generating a new /etc/blocklist, you can replace only the table contents:
root# pfctl -t blocklist -T replace -f /etc/blocklist
Logging
The example rules use the log keyword, allowing you to monitor matching packets on the pflog0 interface using tcpdump:
-n: Do not resolve IP addresses to hostnames-e: Display link-layer headers-ttt: Show timestamps with date and time
root# tcpdump -n -e -ttt -i pflog0