+++
title = 'Using PeerBlock lists on Linux'
date = 2012-10-18T16:49:00Z
+++

On Windows, [PeerBlock](http://www.peerblock.com/) is a firewall of sorts that blocks inbound and outbound communication with hosts based on their inclusion in one of several lists. It is commonly used to block parties that participate in anti-peer-to-peer activities (i.e. suing people for sharing content, even legitimately), advertisements, malware, etc. It blocks more traffic than one might expect, too.

Unfortunately, there isn't a really good alternative for Linux. The original [PeerGuardian](http://sourceforge.net/projects/peerguardian/) for Linux appears to have been revived, but when I tired to use it, it didn't work and was incredibly unstable. The documentation was also pretty terrible. There are a few others, such as *moblock* and *iplist* that appear to have been dead for quite some time. Some other solutions exist, such as simple scripts that convert block lists into iptables rules, but depending on the size of the list, these would consume so many system resources it would be impossible to use the computer.

Fortunately, the Linux kernel itself actually includes all the capabilities necessary to implement a large blacklist as part of the netfilter framework. We'll use the kernel packet filter and a relatively new feature called "IP sets" to create a high-performance index of the block lists.

For this to work, you'll need to make sure your kernel supports iptables and IP sets:

    CONFIG_IP_NF_IPTABLES=y
    CONFIG_NETFILTER_XT_SET=y
    CONFIG_IP_SET=y
    CONFIG_IP_SET_HASH_NET=y

You could also compile these features as modules and insert them at runtime:

    for mod in ip_tables ip_set xt_set ip_set_hash; do modprobe $mod; done

You will also need the `iptables` and `ipset` utilities, as well as several standard command line tools like `curl`, `cut`, `gawk`, `grep`, and `gunzip`.

Next, you'll need to create an IP set to hold the data from a blocklist. For modern kernels, the `hash:net` type works the best:

    ipset create LEVEL1 hash:net maxelem 262144

The identifier `LEVEL1` is the name of the set, which will be used later in the firewall rule. Notice the `maxelem` property which sets the maximum number of elements in the set. The default is 65536. You'll need to increase it if you want to use a large block list. This example is for the [Bluetack Level 1](http://www.iblocklist.com/list.php?list=bt_level1) list, which lists over 250,000 address ranges (totaling over 800 million addresses).

Now that we've got the set created, it's time to populate it. Again, I'm using the Bluetack Level 1 list, but you can use any list you want. You can get several lists from [I-BlockList](http://www.iblocklist.com/). The `p2p` format lists are free, so that's what I'll use in this example.

    curl -L "http://list.iblocklist.com/?list=bt_level1&amp;fileformat=p2p&amp;archiveformat=gz" |
        gunzip |
        cut -d: -f2 |
        grep -E "^[-0-9.]+$" |
        gawk '{print "add LEVEL1 "$1}' |
        ipset restore -exist

You can now view (some of) the contents of your IP set to make sure it worked:

    ipset list LEVEL1 | head

You should see something like this:

    Name: LEVEL1
    Type: hash:net
    Header: family inet hashsize 131072 maxelem 262144 
    Size in memory: 5868152
    References: 0
    Members:
    213.17.157.224/28
    61.95.132.192/27
    184.73.76.96/30
    81.58.24.80/29

Now it's time to tell the firewall to block hosts on these networks. To do that, we'll use two iptables rules:

    iptables -I INPUT -m set --match-set LEVEL1 src -j DROP
    iptables -I OUTPUT -m set --match-set LEVEL1 dst -j DROP

Now you have a kernel-level firewall configuration doing exactly what PeerBlock does.

Make sure you save your iptables configuration using your distribution's recommended method. On Gentoo, it's as simple as `rc-service iptables save`.

You'll probably want to have your block list updated automatically. To do that, create a new IP set with a different name (such as `LEVEL1-updated`) and populate it with the same pipeline as before. Then, use the `ipset swap LEVEL1 LEVEL1-updated` command to replace the original set with the updated set. Then delete the temporary set with `ipset destroy LEVEL1-updated`.