Using PF to limit incoming connection attempts

A while back there was an SSH password guesser released and its use is on the increase - quite frequently I find my daily security logs spammed with 800+kb of "Invalid user fluffy from 1.2.3.4". Fortunately FreeBSD 6.0 has a version of PF which has table and overload support - this feature allows you to tell PF to limit the number of connection attempts from a given host and if it is exceeded the host will be placed into a table. The only downside is that there is no built-in method to expire the IPs after a certain time. To this end I wrote 2 scripts which are run daily by periodic and remove entries after a certain amount of time.

The first script is 900.expire-pf-tables which should be placed in /etc/periodic/daily. This script is run by periodic(8) every day must be enabled by entries in /etc/periodic.conf. The second is expire-table which should be placed in /usr/sbin.

Once you have copied the scripts into place you need to modify your PF rules to add the table and overload entries, eg

### Tables
table <abusive> persist
...
### Filter
block in quick from <abusive>
...
pass in on $ext_if proto tcp from any to ($ext_if) \
  port $tcp_services flags S/SA keep state \
  (max-src-conn-rate 10/10, overload <abusive> flush global)
...
Now reload the ruleset with /etc/rc.d/pf reload. Edit /etc/periodic.conf and add the following lines
expire_pf_tables_enable="YES"
expire_pf_list="abusive"
expire_pf_time_default="86400"
You will now see something like the following in your daily emails
Expiring PF tables
Expired 1, kept 7 IPs in abusive
done
If you want to check on the status of the table you can run pfctl -t abusive -T show -v.

Thanks to Benno Rice for goading me into writing a shell script version of expire-table :)


Daniel O'Connor
Last modified: Mon Mar 27 16:41:49 CST 2006