################################################################### # pf-badhost 0.4 FreeBSD Installation Instructions # Copyright 2020 Jordan Geoghegan ################################################################### ################################################################### # Fresh Installation Guide ################################################################### 1) Create a new user (we'll call ours "_pfbadhost") The user should be created with default shell of "nologin" and an empty password (disables password logins). # pw useradd _pfbadhost -s /sbin/nologin 2) Download script: $ fetch https://geoghegan.ca/pub/pf-badhost/0.4/pf-badhost.sh 3) Install script with appropriate permissions # install -m 755 -o root -g bin pf-badhost.sh /usr/local/bin/pf-badhost.sh 4) Create /etc/pf-badhost.txt: # install -m 640 -o _pfbadhost -g wheel /dev/null /etc/pf-badhost.txt 5) Install 'doas' utility # pkg install doas 6) 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 /usr/local/etc/doas.conf permit root permit nopass _pfbadhost cmd pfctl args -nf /etc/pf.conf permit nopass _pfbadhost cmd pfctl args -t pfbadhost -T replace -f /etc/pf-badhost.txt # Optional rule for authlog scanning permit nopass _pfbadhost cmd bzcat args -f /var/log/auth.log /var/log/auth.log.0.bz2 7) Add the following lines to your pf.conf: (Putting it higher-up/earlier in the ruleset is recommended) ... table persist file "/etc/pf-badhost.txt" block in quick on egress from block out quick on egress to ... 8.a) Add line to /boot/loader.conf to allow for larger pfctl transaction size: # cat /boot/loader.conf net.pf.request_maxcount=400000 8.b) Reboot your machine for the change to take affect (for some reason FreeBSD does not allow this setting to be adjusted on the fly) 9) To enable additional options such as IPv6, subnet aggregation, geoblocking, bogon filtering or authlog scanning open '/usr/local/bin/pf-badhost.sh with your text editor of choice and scroll down to around line 400 to the "User Configuration Area". From there, you can enable options by setting their value to "1" See the 'Notes' section below for more info on installing optional utilities. 10) Run the pfbadhost.sh script as user "_pfbadhost" using the '-freebsd' argument # doas -u _pfbadhost sh /usr/local/bin/pf-badhost.sh -freebsd 11) Reload your pf rule set: # pfctl -f /etc/pf.conf 12) For good measure, we'll run the pf-badhost.sh script once more # doas -u _pfbadhost sh /usr/local/bin/pf-badhost.sh -freebsd 13) Edit _pfbadhost crontab to run pf-badhost.sh every night at midnight # crontab -u _pfbadhost -e @midnight /bin/sh /usr/local/bin/pf-badhost.sh -freebsd Yay! pf-badhost is now installed! With the nightly cron job, the list will be be regularly updated with the latest known bad hosts. ################################################################### # Post Install Notes: ################################################################### Note: For info on enabling PF on FreeBSD see: https://www.freebsd.org/doc/handbook/firewalls-pf.html 1) To add custom rules or enable or add alternate blocklists, add them to the appropriate section of the script The user configuration area starts at around line 400 The script is well commented so it should be pretty straightforward. 2) 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, wheras the 'aggregate' utility supports only IPv4 addresses and is written in C and uses less memory and runs slightly faster. 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). * 'aggregate' can be installed via: # pkg install aggregate * 'aggregate6' can be installed via: # pip install aggregate6 3) If you are trying to run pf-badhost on a LAN or are using NAT etc, you will want to negate your subnet range from the filter: Just uncomment the 'echo' lines and modify to suit your needs Feel free to add as many custom rules as you like! # vi /usr/local/bin/pf-badhost.sh # User Defined Rules: (add or negate addresses from block list) # echo "!169.254.169.254" >> "$userlist" echo "!2001:19f0:ffff::1" >> "$userlist" echo "!192.0.2.0/24 >> "$userlist" Conversely, you can add a pass quick rule to your pf.conf appearing BEFORE the pf-badhost rules allowing traffic to and from your local subnet so that you can still access your gateway and any DNS servers. Something like this should do: # vi /etc/pf.conf pass in quick on egress from 192.0.2.0/24 pass out quick on egress to 192.0.2.0/24 table persist file "/etc/pf-badhost.txt" block in quick on egress from block out quick on egress to