iptables Tips & Tricks [closed]

I'm sure Linux sysadmins are quite familiar with iptables, the userland interface to the netfilter packet-filtering framework.

Now, this "Question" is meant to be a Community Wiki for collecting together various bits-n-pieces of iptables wisdom. Nothing is too common or too obscure. Post anything you know that would help others make the most of iptables.


Solution 1:

Using whitelist and blacklist with iptables

#!/bin/bash

WHITELIST=/whitelist.txt
BLACKLIST=/blacklist.txt

#THIS WILL CLEAR ALL EXISTING RULES!
echo 'Clearing all rules'
iptables -F

#
## Whitelist
#

for x in `grep -v ^# $WHITELIST | awk '{print $1}'`; do
        echo "Permitting $x..."
        $IPTABLES -A INPUT -t filter -s $x -j ACCEPT
done

#
## Blacklist
#

for x in `grep -v ^# $BLACKLIST | awk '{print $1}'`; do
        echo "Denying $x..."
        $IPTABLES -A INPUT -t filter -s $x -j DROP
done

Script to open ports

#!/bin/bash
ALLOWEDTCP="80 3128 3784"
ALLOWEDUDP="3128 3784"

#
## Permitted Ports
#

for port in $ALLOWEDTCP; do
       echo "Accepting port TCP $port..."
       $IPTABLES -A INPUT -t filter -p tcp --dport $port -j ACCEPT
done

for port in $ALLOWEDUDP; do
        echo "Accepting port UDP $port..."
        $IPTABLES -A INPUT -t filter -p udp --dport $port -j ACCEPT
done

Blocking portscan

# Attempt to block portscans
# Anyone who tried to portscan us is locked out for an entire day.
iptables -A INPUT   -m recent --name portscan --rcheck --seconds 86400 -j DROP
iptables -A FORWARD -m recent --name portscan --rcheck --seconds 86400 -j DROP

# Once the day has passed, remove them from the portscan list
iptables -A INPUT   -m recent --name portscan --remove
iptables -A FORWARD -m recent --name portscan --remove

# These rules add scanners to the portscan list, and log the attempt.
iptables -A INPUT   -p tcp -m tcp --dport 139 -m recent --name portscan --set -j LOG --log-prefix "Portscan:"
iptables -A INPUT   -p tcp -m tcp --dport 139 -m recent --name portscan --set -j DROP

iptables -A FORWARD -p tcp -m tcp --dport 139 -m recent --name portscan --set -j LOG --log-prefix "Portscan:"
iptables -A FORWARD -p tcp -m tcp --dport 139 -m recent --name portscan --set -j DROP

Spoofed/Invalid packets

# Reject spoofed packets
# These adresses are mostly used for LAN's, so if these would come to a WAN-only server, drop them.
iptables -A INPUT -s 10.0.0.0/8 -j DROP
iptables -A INPUT -s 169.254.0.0/16 -j DROP
iptables -A INPUT -s 172.16.0.0/12 -j DROP
iptables -A INPUT -s 127.0.0.0/8 -j DROP

#Multicast-adresses.
iptables -A INPUT -s 224.0.0.0/4 -j DROP
iptables -A INPUT -d 224.0.0.0/4 -j DROP
iptables -A INPUT -s 240.0.0.0/5 -j DROP
iptables -A INPUT -d 240.0.0.0/5 -j DROP
iptables -A INPUT -s 0.0.0.0/8 -j DROP
iptables -A INPUT -d 0.0.0.0/8 -j DROP
iptables -A INPUT -d 239.255.255.0/24 -j DROP
iptables -A INPUT -d 255.255.255.255 -j DROP

# Drop all invalid packets
iptables -A INPUT -m state --state INVALID -j DROP
iptables -A FORWARD -m state --state INVALID -j DROP
iptables -A OUTPUT -m state --state INVALID -j DROP

Block Smurf attacks

# Stop smurf attacks
iptables -A INPUT -p icmp -m icmp --icmp-type address-mask-request -j DROP
iptables -A INPUT -p icmp -m icmp --icmp-type timestamp-request -j DROP
iptables -A INPUT -p icmp -m icmp -j DROP

# Drop excessive RST packets to avoid smurf attacks
iptables -A INPUT -p tcp -m tcp --tcp-flags RST RST -m limit --limit 2/second --limit-burst 2 -j ACCEPT

Block ICMP (aka ping)

# Don't allow pings through
iptables -A INPUT -p icmp -m icmp --icmp-type 8 -j DROP

Solution 2:

Optimize netfilter's Performance Using ipset

If you write a lot of similar rules based on mere IP, port, or both, consider using ipset to optimize netfilter's performance.

For example:

iptables -s 192.168.1.11 -j ACCEPT
iptables -s 192.168.1.27 -j ACCEPT
iptables -s 192.168.1.44 -j ACCEPT
... hundreds of similar rules ...
iptables -s 192.168.251.177 -j ACCEPT

This means that a packet with the source address of 192.168.251.177 must first traverse hundreds of rules before it can get its verdict of ACCEPT.

Of course, experienced sysadmins will split the rules by subnet. But that still means hundreds of rules.

ipset to the rescue!

First, define an IP Set of ipmap type:

ipset -N Allowed_Hosts ipmap --network 192.168.0.0/16

Then, populate it with the addresses:

for ip in $LIST_OF_ALLOWED_IP; do ipset -A Allowed_Hosts $ip; done

Finally, replace the hundreds of iptables rules above with one rule:

iptables -m set --match-set Allowed_Hosts src -j ACCEPT

When a packet arrives, netfilter will perform a very quick bitmap search for the packet's source (src) IP against the Allowed_Hosts IP Set. All packets coming from 192.168.0.0/16 will experience one rule. And do believe me that searching a bitmap is at least two order of magnitudes faster than performing hundreds of iptables rule-checking.

ipset is not limited to IP addresses. It can also match based on ports, IP-port tuple, network/subnet addresses, IP-MAC tuple, and so on and so forth. And it can match those criteria as source or destination or a mix of both (in the case of tuples).

And finally, with ipset you can automatically put IP addresses in blacklists/whitelists. These blacklists/whitelists can also 'age', thus automatically deleting the IP address after a configurable amount of time has passed.

Please refer to ipset's man page for more details.

VERY IMPORTANT NOTE:

Some Linux distros may not have 'out-of-the-box' support for ipset (e.g. Ubuntu 10.04 had this issue). On these systems one method is to install ipset from source code.

Instead, download ipset's source from its website: http://ipset.netfilter.org/install.html

Alternatively, if you use xtables-addons, ipset is included in its source: http://xtables-addons.sourceforge.net/

Solution 3:

Add comments to your rules:

-m comment --comment "Comments help to read output of iptables -nvL"

Solution 4:

Block Well-Known TCP Attacks

Add the following rules, preferably in -t raw -A PREROUTING

-p tcp --tcp-flags FIN,SYN FIN,SYN -j DROP
-p tcp --tcp-flags SYN,RST SYN,RST -j DROP
-p tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG FIN,PSH,URG -j DROP
-p tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG FIN -j DROP
-p tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG NONE -j DROP
-p tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG FIN,SYN,RST,PSH,ACK,URG -j DROP

The attacks being blocked are, respectively:

  • SYN-FIN attack
  • SYN-RST attack
  • X-Mas attack
  • nmap FIN scan
  • NULLflags attack
  • ALLflags attack

(feel free to edit the names of the attacks above)