PF-BADHOST(8) System Manager's Manual PF-BADHOST(8) NAME pf-badhost - fetch, validate and parse blocklist data for pf SYNOPSIS pf-badhost [-4 | -6 | -B] [-ADVbnx] [-C config-file] [-H maxauthtries [-E extract-tool -J log-file -K log-file]] [-P maxprocs] [-R retrylimit] [-T allow|block|block-exit] [-U useragent] [-W output-file] [-a asn] [-c ip-address] [-f blocklist-file] [-g cctld] [-i ip-file] [-j asn-file] [-l url-file] [-m asn-url-file] [-o long-option] [-r rule] [-s cctld-file] [-t asn-url] [-u url] [-w rule-file] [file ...] pf-badhost -h | -v DESCRIPTION pf-badhost fetches, validates and parses IP, ASN, and geo-location data into a format suitable for ingestion by the pf(4) firewall. By default the generated blocklist is output to the file /etc/pf-badhost.txt and loaded into a pf(4) table named pfbadhost. pf-badhost expects to be run as an unprivileged user named _pfbadhost. This user must have permission to use pfctl(8) granted to it via either doas(1) or sudo(1). Blocklists may be generated and exported to stdout without any special permissions. Comments can be included in the various files passed to pf-badhost by starting the line with a hash mark (`#') or semi-colon (`;') and will continue to the end of the line. The options are as follows: -4 Generate an IPv4-only blocklist. This is the default behavior. -6 Generate an IPv6-only blocklist. -A Enable IP subnet aggregation. This option will format blocklist data into the smallest possible representation using CIDR notation. It is strongly recommended to enable this option when performing Geoblocking, ASN or bogon filtering. -B Generate a mixed IPv4 and IPv6 blocklist. -C config-file Specify path to a configuration file. To avoid having your config file potentially nullify or clobber conflicting command- line arguments, specify this flag first. -D Disable UID checking. Normally pf-badhost expects to be run as the unpriviliged user _pfbadhost and this option disables that check. -E extract-tool Specify sshd(8) authlog decompression tool. Typically either zcat(1) or bzcat(1) is used. -H maxauthtries Enable sshd(8) authentication log analysis. This will search the system logs for sshd(8) bruteforcers and add any IP addresses to the blocklist which have failed int or more login attempts. When enabled, the systems default authentication logs will be used. Alternate log files may be specified with the -J and -K options. -J log-file Specify path to an sshd(8) authentication log to be searched for bruteforcers. This file may optionally be compressed. -K log-file Specify path to a secondary sshd(8) authentication log to be searched for bruteforcers. This file may optionally be compressed. -P maxproc Set the maximum number of processes to run in parallel. Default is 3. 0 may be specified to disable parallelism. -R retrylimit Set the maximum number of URL fetch attempts. Default is 5. The behavior of this option varies based upon specified URL fetch utility. 0 may be specified to disable re-attempts. -T arg Enable Tor filtering. Valid arguments are: allow Whitelist all Tor relays and exit nodes. block Block all Tor relays and exit nodes. block-exit Block all Tor exit nodes. -U useragent Define a custom HTTP user agent. -V Disables printing of all non-fatal error messages. -W output-file Specify path to a file to output the generated blocklist to. -a asn Specify a single ASN to block. This option is case insensitive and can be specified multiple times. -b Enable bogon filtering. -c ip-address Check if specified IP address exists within the PF firewall table. This option accepts a single IPv4 or IPv6 address. This option is case insensitive and can be specified multiple times. -f blocklist-file Specify path to a file containing IP blocklist data. -g cctld Specify a two letter ISO 3166 country code to block. This option is case insensitive and can be specified multiple times. -h Print the help message and exit. -i ip-file Specify path to a file containing a list of one or more IPv4 and/or IPv6 addresses to check if they exist within the PF table. See -c. -j asn-file Specify path to a file containing a list of one or more ASNs to block. ASNs must be formatted one per line. -l url-file Specify path to a file containing a list of one or more IP blocklist URLs to fetch. URLs must be formatted one per line. Supports HTTP(S) and FTP URLs. Support for additional URL schemas is dependent upon the URL fetch utility used. This option may be specified multiple times. -m asn-url-file Specify path to a file containing a list of one or more ASN blocklist URLs to fetch. URLs must be formatted one per line. Supports HTTP(S) and FTP URLs. Support for additional URL schemas is dependent upon the URL fetch utility used. This option may be specified multiple times. -n Check that the configuration is valid and exit. -o long-option In addition to short command line options, some options are supported in long form. This option may be specified multiple times. custom-filter | no-custom-filter Enable/disable the use of the CUSTOM_FILTER function from an external configuration file specified with the -C option. Disabled by default. export-raw Export raw blocklist data with no embedded statistics, dates, or comments etc. Use of this option implies -x. ipv4-reserved | no-ipv4-reserved Enable/disable whitelisting IPv4 addresses from the IANA IPv4 Special-Purpose Address Registry. Enabled by default. ipv6-reserved | no-ipv6-reserved Enable/disable whitelisting IPv6 addresses from the IANA IPv6 Special-Purpose Address Registry. Enabled by default. log | no-log Enable/disable logging of all informational and warning messages. Enabled by default. mirror | no-mirror Enable/disable the use of RIR GitHub mirror. Enabling this option can greatly improve geoblocking dataset fetch times, especially on low-bandwidth connections. Disabled by default. ssh-nopass Enable alternate regex for SSH authlog analysis with password authentication disabled. See -H description. Use of this option with SSH password authentication enabled will likely result in incorrect accounting of bruteforcer attempts. strict | no-strict Enable/disable aborting when a blocklist fails to download. Enabled by default. uid-check | no-uid-check Enable/disable the forced use of the _pfbadhost user. See -D description. Enabled by default. verbose | no-verbose Enabled/disable printing of all informational and non-fatal errors messages. Enabled by default. The following options are useful for debugging, statistics and firewall table manipulation. These options are mutually exclusive and the last specified option will take precedence. flush-table Flush pf firewall table. This option will flush the address table, disabling all pf- badhost related filtering. print-debug Print utility debugging information and statistics. show-stats Print all pf-badhost filtering statistics. show-stats-address Print per-address filtering statistics. show-stats-global Print global filtering statistics. The following URL fetch utilities are supported and unless overridden by specifying one of the options below, will be used in the following order of preference if found on the system: aria2c, wget, curl, fetch, ftp. aria2c Use aria2c. curl Use curl. fetch Use the FreeBSD fetch(1) utility. ftp Use the OpenBSD ftp(1) utility. wget Use wget. The following grep(1) utilities are supported and unless overridden by specifying one of the options below, will be used in the following order of preference if found on the system: ripgrep, ugrep, ggrep, grep. ggrep Use GNU grep. grep Use the systems default grep(1). rg Use ripgrep. ugrep Use ugrep. The following awk(1) utilities are supported and unless overridden by specifying one of the options below, will be used in the following order of preference if found on the system: mawk, gawk, goawk, awk. awk Use the systems default awk(1). gawk Use GNU awk. goawk Use GoAWK. mawk Use mawk. -r rule Specify a custom rule to add to the blocklist. A valid rule consists of an IP address or CIDR range optionally prefaced with an exclamation mark (`!') for whitelisting. This option may be specified multiple times. -s cctld-file Specify path to a file containing one or more two letter ISO 3166 country codes to block. Country codes must be formatted one per line and are case insensitive. -t asn-url Specify a single URL to fetch ASN blocklist data from. Supports HTTP(S) and FTP URLs. Support for additional URL schemas is dependent upon the URL fetch utility used. This option may be specified multiple times. -u url Specify a single URL to fetch IP blocklist data from. Supports HTTP(S) and FTP URLs. Support for additional URL schemas is dependent upon the URL fetch utility used. This option may be specified multiple times. -v Print version information and exit. -w rule-file Specify path to a file containing a list of one or more custom rules. A valid rule consists of an IP address or CIDR range optionally prefaced with an exclamation mark (`!') for whitelisting. Rules must be formatted one per line. This option may be specified multiple times. -x Print the generated blocklist to stdout instead of adding to pf(4). Use of this option implies -D and -o no-log. EXIT STATUS The pf-badhost utility exits 0 on success, and >0 if an error occurs. EXAMPLES Fetch IP blocklist data from URL list and print to stdout: $ pf-badhost -Bxl /etc/pf-badhost/urls Verify configuration file validity: $ pf-badhost -C /etc/pf-badhost.conf -n Block bogons and specify custom rule to whitelist local subnet: $ pf-badhost -br '!192.0.2.0/24' Block an aggregated list of all IP addresses registered to Australia: $ pf-badhost -ABg AU Block an aggregated list of all IPv4 addresses announced from Apple's ASN: $ pf-badhost -4Aa AS714 Enforce sanctions by blocking a list of country codes from a file: $ pf-badhost -s /etc/pf-badhost/axis-of-evil Add any IP address with 25 or more failed sshd(8) logins to blocklist: $ pf-badhost -H 25 Enabled sshd(8) authentication log analysis with custom paths: $ pf-badhost -H 25 -J /tmp/authlog SEE ALSO pf(4), pf.conf(5), pfctl(8) STANDARDS pf-badhost does not strictly conform to the POSIX shell specification and instead aims for ksh(1) compatibility. AUTHORS Jordan Geoghegan CAVEATS The IPv6 address parser may fail to match against IPv6 addresses terminated with a carriage return (0x0d). This is due to a limitation in both BSD and GNU grep(1) but can be mitigated by using ripgrep or ugrep. The IPv6 address parser requires addresses to be formatted one per line. This is in contrast to the IPv4 address parser which supports arbitrary input formatting (text, JSON, XML, HTML, etc). On platforms that use FreeGrep (OpenBSD, MacOS) performance may be very slow and may even (on MacOS) segfault on the IPv6 regex. It is strongly recommended to replace the use of FreeGrep with ripgrep or ugrep. If the pfbadhost table exceeds the default pf(4) table size limit of 100,000 entries then the limit will need to be raised. Users with large blocklists are additionally encouraged to enable subnet aggregation. The pf(4) table size limit can be raised by adding the following line to pf.conf(5). set limit table-entries 500000 OpenBSD 7.0 October 28, 2021 OpenBSD 7.0