Contents: Packet Filters, Firewalls and Router ACLsParticular Examples


About this document

8. Pinprick Firewalls

A default-deny stance on in-bound traffic makes a good firewall; a default-deny stance on out-bound traffic in addition to this makes a better one. Firewalls in which not a single packet is allowed in or out of a machine unless it matches a tightly-specified rule are called pinprick (or pinhole) firewalls.

8.1. Example

This example is implemented using IPTables. Points to note --- the machine running this firewall is:

  1. running an HTTP server for which access is granted to all;
  2. running an SSH server for which access is granted to a strictly limited list of hosts;
  3. mounting a disk via NFS from 130.88.254.254;
  4. using FTP to get patches from a remote, anonymous site;
  5. blocking most out-bound new connections from clients on the machine --- only DNS lookups and SSH connections (at least, those that look like SSH connections) are allowed.
#!/bin/sh

# -- where's the iptables binary?
IPT="/sbin/iptables"


# ------------------------------------------------------------------------------------------
# -- to start with, clean out the bath :
# ------------------------------------------------------------------------------------------

for i in filter nat mangle
do
    $IPT -t $i -F
    $IPT -t $i -X
done


# ------------------------------------------------------------------------------------------
# -- create our tables :
# ------------------------------------------------------------------------------------------

    # ...we use separate tables for different things, since it's faster...

$IPT -N TCP_IN
$IPT -N TCP_OUT
$IPT -N UDP_IN
$IPT -N UDP_OUT


# ------------------------------------------------------------------------------------------
# -- me/local :
# ------------------------------------------------------------------------------------------

    # ...allow me to talk to myself on both loopback and external-facing devices...

$IPT -t filter -A INPUT  -s 127.0.0.1 -j ACCEPT
$IPT -t filter -A OUTPUT -s 127.0.0.1 -j ACCEPT

$IPT -t filter -A INPUT   -i lo  -p tcp  -s 130.88.253.254  -j ACCEPT
$IPT -t filter -A OUTPUT  -o lo  -p tcp  -s 130.88.253.254  -j ACCEPT


# ------------------------------------------------------------------------------------------
# -- remote debug :
# ------------------------------------------------------------------------------------------

    # ...occasionally we are crazy enough to modify the IPTables rules remotely, so offer
    #    a safety net:  allow in a hardened machine to sort it out :

$IPT -t filter -A INPUT  -s 130.88.253.255 -j ACCEPT
$IPT -t filter -A OUTPUT -d 130.88.253.255 -j ACCEPT


# ------------------------------------------------------------------------------------------
# -- handle TCP and UDP :
# ------------------------------------------------------------------------------------------

    # ...TCP and UDP traffic, in-bound and out-bound, is handled by the
    #    appropriate table, so we jump to it...

$IPT -t filter -A INPUT  -p tcp -i eth0 -d 130.88.253.254  -j TCP_IN
$IPT -t filter -A OUTPUT -p tcp -o eth0 -s 130.88.253.254  -j TCP_OUT

$IPT -t filter -A INPUT  -p udp -i eth0  -d 130.88.253.254  -j UDP_IN
$IPT -t filter -A OUTPUT -p udp -o eth0  -s 130.88.253.254  -j UDP_OUT


# ------------------------------------------------------------------------------------------
# -- handle ICMP :
# ------------------------------------------------------------------------------------------

    # ...we don't like it...

$IPT -t filter -A INPUT -p icmp -j DROP


# ------------------------------------------------------------------------------------------
# -- default drops  :
# ------------------------------------------------------------------------------------------

    # ...frankly, anything that gets this far is something we are not interested in,
    #    and which is going to the bin...
    #    
    #     -- e.g., windoze broadcast/netbios-type crap is going straight down the hole
    #     -- other stuff we log, before dropping, just to see what it is...

$IPT -t filter -A INPUT -p udp  --sport 137 --dport 137  -j DROP
$IPT -t filter -A INPUT -p udp  --sport 138 --dport 138  -j DROP

$IPT -t filter -A INPUT  -j LOG --log-prefix " **INPUT DROP** "
$IPT -t filter -A INPUT  -j DROP
$IPT -t filter -A OUTPUT -j LOG --log-prefix " **OUTPUT DROP** "
$IPT -t filter -A OUTPUT -j DROP


# ------------------------------------------------------------------------------------------
# -- the policies which override everything else :
# ------------------------------------------------------------------------------------------

$IPT -t filter -P INPUT DROP
$IPT -t filter -P OUTPUT DROP
$IPT -t filter -P FORWARD DROP


# ------------------------------------------------------------------------------------------
# -- THE END.  (End of "main";  following are the "subroutines/functions".)
# ------------------------------------------------------------------------------------------


# ------------------------------------------------------------------------------------------
# -- CHAIN TCP_IN :  new inward TCP connections :
# ------------------------------------------------------------------------------------------

# -- bad stuff :
#
$IPT -t filter -A TCP_IN -p tcp ! --syn -m state --state NEW -j LOG --log-prefix " **NEW NOT SYN** "
$IPT -t filter -A TCP_IN -p tcp ! --syn -m state --state NEW -j DROP


# -- incoming packets related to connections we initiated out-bound :
#
$IPT -t filter -A TCP_IN -p tcp  --dport 1024:  -m state --state ESTABLISHED,RELATED  -j ACCEPT


# -- allow new connections to our http-server plus traffic on established connections from all hosts :
#
$IPT -t filter -A TCP_IN -p tcp  --sport 1024: --dport 80  -m state --state NEW,ESTABLISHED  -j ACCEPT


# -- ssh connections to our daemon from selected hosts only :
#
$IPT -t filter -A TCP_IN -p tcp  -s 130.88.254.254 --sport 1024: --dport 22  -m state --state NEW -j LOG --log-level warn
$IPT -t filter -A TCP_IN -p tcp  -s 130.88.254.254 --sport 1024: --dport 22  -m state --state NEW,ESTABLISHED -j ACCEPT  


# -- nfs (mount a remote disk from 254.254) :
#
$IPT -t filter -A TCP_IN -p tcp  -s 130.88.254.254  --sport  111                -m state --state NEW,ESTABLISHED -j ACCEPT  
$IPT -t filter -A TCP_IN -p tcp  -s 130.88.254.254  --sport 2049 --dport 1024:  -m state --state NEW,ESTABLISHED -j ACCEPT  


# -- est/rel ftp (for apt-get) :
#
#     ...need to deal with initial connection out to 21, passive FTP (high to high, 
#        originating from client/us) and active FTP (originates from server on 20 
#        to client/us on high)...
#
#     ...addresses reflect contencts of /etc/apt/sources.list...
#
$IPT -t filter -A TCP_IN -p tcp  -s 195.224.53.39 --sport 21                   -m state --state ESTABLISHED          -j ACCEPT
$IPT -t filter -A TCP_IN -p tcp  -s 195.224.53.39 --sport 20                   -m state --state ESTABLISHED,RELATED  -j ACCEPT
$IPT -t filter -A TCP_IN -p tcp  -s 195.224.53.39 --sport 1024: --dport 1024:  -m state --state ESTABLISHED          -j ACCEPT


# -- every other tcp connection can go in the bin :
#
#     ...alternatively: $IPT -t filter -A TCP_IN -m state --state NEW -j DROP...
#
$IPT -t filter -A TCP_IN -m state --state NEW -j REJECT --reject-with icmp-port-unreachable


# -- drop any other tcp packet :
#
$IPT -t filter -A TCP_IN -p tcp -j LOG --log-prefix " **TCP_IN DROP** "
$IPT -t filter -A TCP_IN -p tcp -j DROP 



# ------------------------------------------------------------------------------------------
# -- CHAIN TCP_OUT :  outward TCP :
# ------------------------------------------------------------------------------------------

# ...output is default-deny too...
#
#    allow connections from all local high-numbered ports to all remote --- so that any TCP 
#    client on our machine can get new connections out :
#
#        $IPT -t filter -A TCP_OUT -p tcp --sport 1024:65535 -j ACCEPT
#
#    NO!  The above rule is common, but lazy/sloppy.
#    YES: allow strictly limited TCP client access out :
#
$IPT -t filter -A TCP_OUT -p tcp  --sport 1024: --dport   22  -m state --state NEW,ESTABLISHED  -j ACCEPT
$IPT -t filter -A TCP_OUT -p tcp  --sport 1024: --dport 2222  -m state --state NEW,ESTABLISHED  -j ACCEPT


# -- allow established outward http to any host :
#
$IPT -t filter -A TCP_OUT -p tcp  --sport 80 --dport 1024:  -m state --state ESTABLISHED  -j ACCEPT


# -- allow established outward traffic to vips from our sshd :
#
$IPT -t filter -A TCP_OUT -p tcp  --sport 22 -d 130.88.254.254    -m state --state ESTABLISHED  -j ACCEPT 


# -- nfs (mount a remote disk from 254.254) :
#
$IPT -t filter -A TCP_OUT -p tcp  -d 130.88.254.254               --dport  111  -m state --state NEW,ESTABLISHED -j ACCEPT  
$IPT -t filter -A TCP_OUT -p tcp  -d 130.88.254.254 --sport 1024: --dport 2049  -m state --state NEW,ESTABLISHED -j ACCEPT  


# -- allow ftp so apt-get can do its stuff :
#
#     ...need to deal with initial connection out to 21, passive FTP (high to high, 
#        originating from client/us) and active FTP (originates from server on 20 
#        to client/us on high)...
#
#     ...addresses reflect contencts of /etc/apt/sources.list...
#
$IPT -t filter -A TCP_OUT -p tcp  -d 195.224.53.39 --dport 21                   -m state --state NEW,ESTABLISHED     -j ACCEPT
$IPT -t filter -A TCP_OUT -p tcp  -d 195.224.53.39 --dport 20                   -m state --state ESTABLISHED         -j ACCEPT
$IPT -t filter -A TCP_OUT -p tcp  -d 195.224.53.39 --sport 1024: --dport 1024:  -m state --state ESTABLISHED,RELATED -j ACCEPT


# -- default deny :
# 
$IPT -t filter -A TCP_OUT -p tcp -j LOG --log-prefix " **TCP_OUT DROP** "
$IPT -t filter -A TCP_OUT -p tcp -j DROP



# ------------------------------------------------------------------------------------------
# -- CHAIN UDP_IN :  new inward UDP connections :
# ------------------------------------------------------------------------------------------

$IPT -t filter -A UDP_IN -p udp  -m state --state ESTABLISHED,RELATED  -j ACCEPT


# -- nfs (mount a remote disk from 254.254) :
#
$IPT -t filter -A UDP_IN -p udp  -s 130.88.254.254 --sport  111                -m state --state NEW,ESTABLISHED -j ACCEPT  
$IPT -t filter -A UDP_IN -p udp  -s 130.88.254.254 --sport 2049 --dport 1024:                                   -j ACCEPT


# -- default deny :
#
$IPT -t filter -A UDP_IN -p udp  -j DROP


# ------------------------------------------------------------------------------------------
# -- CHAIN UDP_OUT :  new outward UDP connections :
# ------------------------------------------------------------------------------------------

# -- DNS lookups (we must have these!) :
#
$IPT -t filter -A UDP_OUT -p udp --sport 1024: --dport  53 -j ACCEPT 


# -- nfs (mount a remote disk from 254.254) :
#
$IPT -t filter -A UDP_OUT -p udp  -d 130.88.254.254  --dport  111   -j ACCEPT
$IPT -t filter -A UDP_OUT -p udp  -d 130.88.254.254  --dport 1024:  -j ACCEPT


# -- remote syslog logs (syslogs are copied to a secure remote server) :
#
$IPT -t filter -A UDP_OUT -p udp -d 130.88.254.253 --sport 514 -j ACCEPT 


# -- default deny :
#
$IPT -t filter -A UDP_OUT -p udp -j DROP


# ------------------------------------------------------------------------------------------
# ------------------------------------------------------------------------------------------


...previousup (conts)next...