This post is a fairly comprehensive reference to Advanced Policy Firewall (apf-firewall), a user-friendly interface of iptables. We will also cover BFD (bfd), a script that automates IP blocking using APF.

Technical Context: Ubuntu 14.04, APF v9.7, BFD v1.5-2

Installation

$ apt-get install apf-firewall

$ wget http://rfxnetworks.com/downloads/bfd-current.tar.gz
$ tar xfz bfd-current.tar.gz
$ cd bfd-1.5-2
$ ./install.sh

Basic Usage

apf -s - Start
apf -f - Stop
apf -r - Restart
apf -e - Refresh APF rules
apf -a <IP> - manually allow IP
apf -d <IP> - manually block IP
apf -u <IP> - manually unblock IP (works for BFD too)

What -a actually does is add the IP entry to the allow_hosts.rules file. -d does the same thing for deny_hosts.rules. -u removes the IP entry from either allow_hosts.rules or deny_hosts.rules, if it exists. All three commands will call apf -e as well.

APF supports CIDR notation for specifying rules for IP blocks, as well as fully qualified domain names (FQDR)1.

There are basically three ways to use APF:

  1. Restrict on a per-IP basis
  2. Restrict on a per-port basis
  3. Restrict on a IP-port combination basis

Restrict on a per-IP basis

The most straightforward to do this is, as mentioned earlier, by using -a, -d and -u. Of course, you can edit allow_hosts.rules or deny_hosts.rules directly as well (specify each IP address on a new line).

Restrict on a per-port basis

By default, APF blocks a number of known malicious ports (see the main config file for an exhaustive list). To allow all incoming or outgoing connections on a per-port basis, we can edit the IG_TCP_CPORTS or EG_TCP_CPORTS setting respectively in APF’s main config file /etc/apf-firewall/conf.apf:

# incoming connections
IG_TCP_CPORTS="22,80,443"
IG_UDP_CPORTS=""

# outgoing connections
EG_TCP_CPORTS="21,25,80,443,43"
EG_UDP_CPORTS="20,21,53"

Notably, these settings are overriden by rules in allow_hosts.rules and deny_hosts.rules.

Restrict on a IP-port combination basis

The allow_hosts.rules and deny_hosts.rules is very well commented regarding the syntax for specifying granular restrictions, so I’ll cover them only briefly here:

# Syntax:
# proto:flow:[s/d]=port:[s/d]=ip(/mask)
# s – source , d – destination , flow – packet flow in/out

For example:

tcp:in:d=22:s=192.168.2.1

in allow_hosts.rules will allow incoming connections from 192.168.2.1 to port 22.

Multiple IPs to the same port need to be specified on separate lines:

tcp:in:d=22:s=192.168.2.1
tcp:in:d=22:s=192.168.31.4
...

APF Configuration

Some other noteworthy APF configuration settings in /etc/apf-firewall/conf.apf that you should change:

Development Mode

DEVEL_MODE="1"

When set to "1", APF will deactivate itself after every 5 minutes. This prevents you from setting stupid rules and cutting yourself out from a remote machine.

Remember to set this to "0" once APF is determined to be functioning as desired.

Monokernel

SET_MONOKERN="0"

It might be an issue in situations where iptables is installed into the kernel rather than as a package. In those cases, you’ll see something like:

Unable to load iptables module (ip_tables), aborting.

or

$ apf -s
apf(17079): {glob} activating firewall
apf(17120): {glob} kernel version not equal to 2.4.x or 2.6.x, aborting.

Setting it to SET_MONOKERN="1" will fix the problem.

Ban Duration

RAB_TIMER="300"

I recommend setting this a lot higher than the default of 300 seconds. 21600 (6 hours), maybe?

Reactive Address Blocking

RAB="0"

Set this to “1” to activate APF’s reactive address blocking.

Subscriptions

APF can subscribe to known lists of bad IP addresses. The below is an abridged portion of the config file that deals with this:

##
# [Remote Rule Imports]
##
# Project Honey Pot is the first and only distributed system for identifying
# spammers and the spambots they use to scrape addresses from your website.
# This aggregate list combines Harvesters, Spammers and SMTP Dictionary attacks
# from the PHP IP Data at:  http://www.projecthoneypot.org/list_of_ips.php
DLIST_PHP="0"

DLIST_PHP_URL="rfxn.com/downloads/php_list"
DLIST_PHP_URL_PROT="http"

# The Spamhaus Don't Route Or Peer List (DROP) is an advisory "drop all
# traffic" list, consisting of stolen 'zombie' netblocks and netblocks
# controlled entirely by professional spammers. For more information please
# see http://www.spamhaus.org/drop/.
DLIST_SPAMHAUS="0"

DLIST_SPAMHAUS_URL="www.spamhaus.org/drop/drop.lasso"
DLIST_SPAMHAUS_URL_PROT="http"

# DShield collects data about malicious activity from across the Internet.
# This data is cataloged, summarized and can be used to discover trends in
# activity, confirm widespread attacks, or assist in preparing better firewall
# rules. This is a list of top networks that have exhibited suspicious activity.
DLIST_DSHIELD="0"

DLIST_DSHIELD_URL="feeds.dshield.org/top10-2.txt"
DLIST_DSHIELD_URL_PROT="http"

BFD Configuration

BFD barely has any configuration (which is A Good Thing™). The below is pretty much it:

$ vim /usr/local/bfd/conf.bfd

You can set the threshold for the number of attempts before an IP address is blocked:

TRIG="15"

The default number of 15 is quite generous - I’d lower it to at most 5 or 6.

BFD also has email alerts:

EMAIL_ALERTS="1"
EMAIL_ADDRESS="wow@example.com"

We can add whitelisted IP addresses in:

$ vim /usr/local/bfd/ignore.hosts

IP addresses whitelisted by BFD are still subjected to APF’s rules - they do not have any influence on each other.

Finally, and most importantly, BFD is started with:

$ bfs -s

which will also start a cron job2 that goes through your access log files every 3 minutes and tells APF to ban any IP addresses that goes beyond the specified threshold in TRIG.

BFD Logs

BFD logs to /var/log/bfd_log.

Footnotes
  1. I won’t be demonstrating this here, but this should apply to virtually any setting where an IP address is otherwise expected.

  2. You can verify this by checking /etc/cron.d/bfd.