6.6 KiB
Updates
- 1st July 2025: Renamed "HAIL_MARY" to "CLOUD_BRUTEFORCE_MITIGATION". Read Catechism of the Catholic Church before complaining.
- 19th June 2025: Updated the _AGENT to the latest Windows Firefox as some sites were rejecting download attempts based on an outdated user agent.
Fresh Installation Guide
Create a new user (we'll call ours "_pfbadhost"). The user should be created with a default shell of "nologin", home folder set to /var/empty/ with no password specified (disables password logins)
useradd -s /sbin/nologin -d /var/empty _pfbadhost
Download script from https://git.hiddenagenda.ltd.uk/jezcaudle/pfbadhost-fork/raw/branch/main/pf-badhost.sh
Install script with appropriate permissions
install -m 755 -o root -g bin pf-badhost.sh /usr/local/bin/pf-badhost
Create required files:
install -m 640 -o _pfbadhost -g wheel /dev/null /etc/pf-badhost.txt
install -d -m 755 -o root -g wheel /var/log/pf-badhost
install -m 640 -o _pfbadhost -g wheel /dev/null /var/log/pf-badhost/pf-badhost.log
install -m 640 -o _pfbadhost -g wheel /dev/null /var/log/pf-badhost/pf-badhost.log.0.gz
OPTIONAL: Install RipGrep and mawk for greatly improved performance. Note: RipGrep is not available on all CPU architectures, use 'ggrep' if affected.
pkg_add ripgrep mawk
Give user "_pfbadhost" strict doas permission for the exact commands the script needs run as superuser. NOTE: Unlike "sudo", ALL users must be explicitly granted permission to use doas, even the root user.
cat /etc/doas.conf
...
permit root
permit nopass _pfbadhost cmd /sbin/pfctl args -nf /etc/pf.conf
permit nopass _pfbadhost cmd /sbin/pfctl args -t pfbadhost -T replace -f /etc/pf-badhost.txt
# Optional rule for authlog scanning
permit nopass _pfbadhost cmd /usr/bin/zcat args -f /var/log/authlog /var/log/authlog.0.gz
...
Add the following lines to your pf.conf (Putting it higher-up/earlier in the ruleset is recommended):
...
table <pfbadhost> persist file "/etc/pf-badhost.txt"
block in quick on egress from <pfbadhost>
block out quick on egress to <pfbadhost>
...
To enable additional features such as IPv6, Subnet Aggregation, Geo-Blocking, Bogon Filtering or Authlog Scanning open "/usr/local/bin/pf-badhost" with your text editor of choice and find the "User Configuration Area" near the top of the file where you can enable features by setting their value to "1".
Most options can also be configured via command line flags. See man page for more details.
See the "Notes" section below for more info on installing optional utilities.
Run pfbadhost as user "_pfbadhost":
doas -u _pfbadhost pf-badhost
Reload your pf rule set:
pfctl -f /etc/pf.conf
For good measure, we'll run pf-badhost once more:
doas -u _pfbadhost pf-badhost
Edit _pfbadhost users crontab to run pf-badhost every night:
crontab -u _pfbadhost -e
...
~ 0~1 * * * -s pf-badhost
...
Yay! pf-badhost is now installed!
With the nightly cron job, the list will be regularly updated with the latest known bad hosts.
Please read the man page for information on how to configure pf-badhost. The manpage can be found here: https://git.sr.ht/~jezcaudle/pfbadhost-fork/tree/main/item/man.txt
Post Install Notes:
To add custom rules or enable features, or add alternate blocklists, see the "User Configuration Area" located at the top of the script. This area serves as a built in config file, so please feel free to edit it and experiment with all the features available within. Note: Most options can also be configured from the command line.
Regarding Cron Jobs - over the past year I've noticed a number of list host servers going down at midnight in populated timezones (ie West Coast, East Coast and Western Europe). To be respectful (and to avoid overloading list providers servers) we have cron jobs scheduled to run at a random time within a defined interval. With the new default cron job, pf-badhost will be run every night at some point between midnight and 2AM, and thus distributing the load of thousands of queries from numerous users over a 2 hour period rather than a matter of seconds.
Subnet aggregation is used to reduce the number of entries in a PF table by taking the individual IP addresses and translating them into CIDR notation such as 82.221.99.224/28
You can see what the limits are for various things in pf with the
pfctl -sm
states hard limit 100000
src-nodes hard limit 10000
frags hard limit 65536
tables hard limit 1000
table-entries hard limit 200000
pktdelay-pkts hard limit 10000
anchors hard limit 512
The script is able to detect which (if any) subnet aggregation utilities are installed and will try to "Do The Right Thing(tm)" and fallback to the best available option. If no subnet aggregation utility is found, the script will fallback to using a pure Perl IPv4 aggregator if Perl is installed.
Despite its name, "aggregate6" supports both IPv4 and IPv6 addresses and is written in Python, whereas the "aggregate" utility supports only IPv4 addresses and is written in C and uses significantly less memory but runs much slower. For greatly improved performance, aggregate6 can be run with Pypy. If both utilities are installed, the C based "aggregate" utility will be preferred for IPv4 aggregation, but the script will happily function if only one or the other is installed (or neither).
Note: Subnet aggregation can be enabled with the '-A' switch on the commandline.
-
"aggregate" can be installed via: # pkg_add aggregate
-
"aggregate6" can be installed via: # pkg_add aggregate6
-
For greatly improved aggregation performance, run aggregate6 with Pypy:
pkg_add pypy
pypy -m pip install wheel aggregate6
ln -s /usr/local/pypy/bin/aggregate6 /usr/local/bin/aggregate6
License
Copyright (c) 2018-2021 Jordan Geoghegan jordan@geoghegan.ca Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
In loving memory of Ron Sather
Copyright (c) Jez Caudle 2024 onwards with the same license as above.