################################################################### # pf-badhost 0.4 MacOS 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). NOTE: Make sure you set the 'UniqueID' and 'PrimaryGroupID' to an unused value! # dscl . -create /Users/_pfbadhost # dscl . -create /Users/_pfbadhost UserShell /sbin/nologin # dscl . -create /Users/_pfbadhost RealName “_pfbadhost" # dscl . -create /Users/_pfbadhost UniqueID 1011 # dscl . -create /Users/_pfbadhost PrimaryGroupID 1011 1.b) You may need to give the user admin privledges, but you shouldn't need to # dscl . -append /Groups/admin GroupMembership _pfbadhost 2) Download script: $ curl 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) Give '_pfbadhost' user permission to use sudo without a password Run 'sudo visudo' and then add the following line near the end of the file: _pfbadhost ALL = (ALL) NOPASSWD: ALL 6) 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 ... 5) 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. 8) Run the pfbadhost.sh script as user "_pfbadhost" using the '-macos' argument # sudo -u _pfbadhost sh /usr/local/bin/pf-badhost.sh -macos 9) Reload your pf rule set: # pfctl -f /etc/pf.conf 10) For good measure, we'll run the pf-badhost.sh script once more # sudo -u _pfbadhost sh /usr/local/bin/pf-badhost.sh -macos 11) 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 -macos 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: ################################################################### 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) NOTE: The default grep on MacOS sometimes segfaults on the IPv6 regex! It is STRONGLY recommended to use RipGrep or GNU grep instead * To convert the script to use RipGrep, run "brew install ripgrep" and run this command as root: # sed -i -e 's/grep -E/rg/g' /usr/local/bin/pf-badhost.sh * To convert the script to use GNU grep, run "brew install ggrep" and run this command as root: # sed -i -e 's/grep -E/ggrep -E/g' /usr/local/bin/pf-badhost.sh 2.b) NOTE: authlog analysis is not supported on MacOS 3) 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: # brew install aggregate * 'aggregate6' can be installed via: # pip install aggregate6 4) 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