Linux Firewall Configuration and Setup - iptables
Table of Contents
This is a collection of notes about modifying your iptables packet filter to add blocking of specific IPs and systems on the Tor network.
Basic Setup
The following is a basic firewall script that you can load with
iptables-restore <iptables
It allows access to
Port | Service | Notes |
---|---|---|
25 | SMTP | Incoming email |
110 | POP3 | POP3 service for email |
53 | DNS | Name server requests |
22 | SSH | Incoming SSH requests |
80 | HTTP | Webserver requests |
443 | HTTPS | Secure HTTP |
4000:5200 | BZFlag Servers | BZFlag server ports |
6000:6200 | BZFlag Servers | More server ports |
Anything else is logged and dropped at the firewall.
The logwatch
package makes nice daily summaries of the firewall logs.
Here is the iptables
file:
# Generated by iptables-save v1.3.6 on Mon Oct 20 14:37:02 2008 *filter :INPUT DROP [0:0] :FORWARD ACCEPT [0:0] :OUTPUT ACCEPT [8574312917:611260898475] -A INPUT -p tcp -m tcp --dport 25 -j ACCEPT -A INPUT -p tcp -m tcp --dport 110 -j ACCEPT -A INPUT -p udp -m udp --dport 53 -m state --state NEW -j ACCEPT -A INPUT -p tcp -m tcp --dport 53 -m state --state NEW -j ACCEPT -A INPUT -p icmp -j ACCEPT -A INPUT -i lo -j ACCEPT -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT -A INPUT -p tcp -m tcp --dport 22 -m state --state NEW -j ACCEPT -A INPUT -p tcp -m tcp --dport 80 -m state --state NEW -j ACCEPT -A INPUT -p tcp -m tcp --dport 443 -m state --state NEW -j ACCEPT -A INPUT -p tcp -m tcp --dport 4000:5200 -m state --state NEW -j ACCEPT -A INPUT -p udp -m udp --dport 4000:5200 -m state --state NEW -j ACCEPT -A INPUT -p tcp -m tcp --dport 6000:6200 -m state --state NEW -j ACCEPT -A INPUT -p udp -m udp --dport 6000:6200 -m state --state NEW -j ACCEPT -A INPUT -j LOG -A INPUT -j DROP -A OUTPUT -o lo -j ACCEPT COMMIT # Completed on Mon Oct 20 14:37:02 2008 # Generated by iptables-save v1.3.6 on Mon Oct 20 14:37:02 2008 *mangle :PREROUTING ACCEPT [2345559699:169138998026] :INPUT ACCEPT [2345528243:169135560350] :FORWARD ACCEPT [0:0] :OUTPUT ACCEPT [9525683538:678126408324] :POSTROUTING ACCEPT [9525683538:678126408324] COMMIT # Completed on Mon Oct 20 14:37:02 2008 # Generated by iptables-save v1.3.6 on Mon Oct 20 14:37:02 2008 *nat :PREROUTING ACCEPT [8235419:506261976] :POSTROUTING ACCEPT [1475984:91496805] :OUTPUT ACCEPT [1475984:91496805] COMMIT # Completed on Mon Oct 20 14:37:02 2008
Tie the rules to the network interface
In Debian you can automatically run scripts when interfaces are started and stopped.
We keep the firewall rules in /etc/iptables
and have the following lines in
/etc/network/interfaces
to save and restore the current set of rules across reboots.
/etc/network/interfaces
# The loopback network interface auto lo iface lo inet loopback # The primary network interface iface eth0 inet static address 1.2.3.4 netmask 255.255.255.255 gateway 1.2.3.1 # # iptables up /sbin/iptables-restore -c </etc/iptables down /sbin/iptables-save -c >/etc/iptables #
Custom Chains
Add custom chains to hold your custom firewall rules.
Here we use two new chains TOR_BLOCK
and BLOCK
to keep two
separate lists of IPs to be blocked at the firewall.
Adding Chains
Chains are where you keep your rules. You can add new chains with
iptables -N NEWCHAIN
Blocking Tor Systems
Here we use a new chain (TOR_BLOCK
) and a script to populate the chain.
This automatically keeps the list of IPs to block from the Tor network up
to date hourly.
Adding TOR_BLOCK chain to the INPUT chain
Create your new chain to hold Tor network node IPs to block with
iptables -N TOR_BLOCK
and tie this chain to your input rules with
iptables -I INPUT -j TOR_BLOCK
This jumps from the INPUT
chain to the TOR_BLOCK
chain and then
returns to the next rule in the INPUT
after hitting the RETURN
at
the end of the TOR_BLOCK
chain.
Populating the TOR_BLOCK chain
We will populate the TOR_BLOCK
chain automatically using the
torblock.fw
script below.
This will empty the TOR_BLOCK chain, add a RETURN to the end of the chain so we can process it like a subroutine and enter each listed Tor network IP into the list.
You can run the torblock.fw
script manually to wipe and populate the TOR_BLOCK
chain.
After you're happy with it I add a crontab
entry that updates the list once
an hour.
/usr/local/sbin/torblock.fw Script
#!/bin/bash # A simple bash script to block IP traffic from TOR exit nodes. # written by Andrew Vetlugin (antrew at gmail com) wget='/usr/bin/wget' iptables='/sbin/iptables' #url='https://torstat.xenobite.eu/export/tor_exitnodes.csv' url='http://torstatus.kgprog.com/ip_list_exit.php/Tor_ip_list_EXIT.csv' iptables_target='DROP' #iptables_target='REJECT' # Quick guide: # 1. add a separate chain for a list of TOR exit nodes # (this should be done by hand once) # iptables -N TOR_BLOCK # 2. add a rule to INPUT chain # Note: if you want to be able to connect to any TOR exit node yourself # (e.g., if $url is a exit node you should be able to fetch a list of exit # nodes from it) then you should add this rule AFTER accepting established # and related connections) # iptables -A INPUT -j TOR_BLOCK # 3. add this script to crontab (I think 10-20 minutes interval should be OK) # flush chain $iptables -F TOR_BLOCK # return to parent chain if the source is not TOR exit node $iptables -I TOR_BLOCK -j RETURN # add TOR exit nodes to TOR_BLOCK chain with $iptables_target rule for node in `$wget -q --no-check-certificate -O - $url | sort | uniq`; do $iptables -I TOR_BLOCK -s $node -j $iptables_target done
Crontab Entry
The following crontab
entry runs the torblock.fw
script. This
effectively erases all the Tor network nodes and re-populates the
TOR_BLOCK
list hourly.
00 * * * * root /usr/local/sbin/torblock.fw
Manual Blocking Chains
Now to deal with other problem systems we keep a separate BLOCK
list which we
can manually add, list, and remove entries from. The following scripts can
be provided to trusted users via sudo
so they can view and manipulate the
firewall rules.
Add BLOCK chain
Add the new chain to hold the IPs to block.
iptables -N BLOCK
Add a single rule to return from the end of the list to the calling chain.
iptables -I BLOCK -j RETURN
and tie this chain to to your input rules.
iptables -I INPUT -j BLOCK
This jumps from the INPUT
chain to the BLOCK
chain and then
returns to the next rule in the INPUT
chain after hitting the RETURN
at
the end of the BLOCK
chain.
Blocking IPs
Blocking IPs using the new BLOCK
chain is pretty simple.
usage: sudo block IP sudo block IP/nn sudo block IP 'comment goes here' sudo block IP/nn 'comment goes here' e.g. sudo block 1.2.3.4 # Adds 1.2.3.4 as the IP to block sudo block 1.2.3.4 'reason for block' # Adds 1.2.3.4 with a comment sudo block 1.2.3.4/24 'block subnet' # Blocks all ips matching 1.2.3.*
Comments are kept in the iptables
chain and are displayed by the blocklist
script below.
Block Script - /usr/local/sbin/block
#!/bin/sh INPUT="$(echo $1 | sed 's/[^.0-9/]//g')" COMMENT="$2" if [ "x$COMMENT" == "x" ] then iptables -I BLOCK -s $INPUT -j DROP else iptables -I BLOCK -s $INPUT -m comment --comment "$COMMENT" -j DROP fi /usr/local/sbin/blocklist
Unblocking IPs
To unblock an IP (removing it from the BLOCK
chain) just pass the IP
as parameter 1 and the comment (if any) exactly as it was entered when
blocking the IP.
usage: sudo unblock IP sudo unblock IP 'comment goes here'
Unblock Script - /usr/local/sbin/unblock
#!/bin/sh INPUT="$(echo $1 | sed 's/[^.0-9/]//g')" COMMENT="$2" if [ "x$COMMENT" == "x" ] then iptables -D BLOCK -s $INPUT -j DROP else iptables -D BLOCK -s $INPUT -m comment --comment "$COMMENT" -j DROP fi /usr/local/sbin/blocklist
Listing Blocked IPs
The following script simply displays the entries in the blocklist.
Usage: sudo blocklist
Block List script - /usr/local/sbin/blocklist
#!/bin/sh iptables -L BLOCK -n
Rate Limiting Connections
To effectively block script-kiddies that try dictionary attacks on the SSH server port I have the two following rules before the rule that accepts SSH connections
-A INPUT -p tcp -m tcp --dport 22 -m state --state NEW -m recent --set -A INPUT -p tcp -m tcp --dport 22 -m state --state NEW -m recent --update --seconds 60 --hitcount 4 -j DROP
This allows up to 3 connections from the same IP in a 60 second period. Any more than that are blocked (and not logged).
Waiting 60 seconds before retrying the connection attempt makes it work again.
Saving and Restoring tables
I save the current iptables
firewall rules with
/sbin/iptables-save -c >/etc/iptables
These can be restored with the following command
/sbin/iptables-restore -c </etc/iptables
These are normally added to my /etc/network/interfaces
file on Debian when the appropriate network
interface is brought up or down.
# Example /etc/network/interfaces entries # The primary network interface iface eth0 inet static address 1.2.3.4 netmask 255.255.255.0 gateway 1.2.3.1 up /sbin/iptables-restore -c </etc/iptables down /sbin/iptables-save -c >/etc/iptables