A Router Firewall

History

My first firewall seemed to work well but it did not. The reason for this was that I did not understand the concept of the iptables completely. I had opened the OUTPUT chain completely and inserted a lot of INPUT rules. For the FORWARD I had very few lines. For the POSTROUTING I used SNAT.

When I activated this firewall for the first time I was unable to go to the outside world. In the SYSLOG I found out that it was blocked in the FORWARD chain. The solution was simple: Open the ports in the FORWARD chain. But I was puzzeled. I decided to ask some questions to Henk van de Kamer. He is a Dutch guy who writes about his work with computers (Het Lab). His answers made me change (and as a result simplify) my firewall.

Firewall

On the INPUT, OUTPUT, and FORWARD chains I accept all traffic that is already in an 'active' state. I also allow some ICMP protocol traffics.

INPUT

The INPUT chain handles the traffic that comes into the firewall (=the router). Since I only need to access the firewall from my LAN and DMZ I only need to check these interfaces. On the firewall there is only SSH and HTTP available so only traffic to those ports is accepted.

OUTPUT

The OUTPUT chain handles the traffic that goes out of the firewall. I need to be able to mount a directory through shfs (port 22), upgrade the software (port 80), synchronise the internal clock (port 123), and log to an external SYSLOG server (port 514) I open only those ports.

FORWARD

The FORWARD chain handles all traffic that passes the firewall. I will open it port by port. The SYSLOG is a great help for this. At this moment I have only the ports 53 (DNS), 80 (HTTP), and 123 (NTP) open between the DMZ and the outside world. At this moment my LAN is protected by another firewall. Once my DMZ is operational this will change.

PREROUTING

The PREROUTING chain changes packet envelopes. I use it to re-route the HTTP and HTTPS traffic to the Squid server and to re-route the HTTP traffic to the intranet server to the 8080 port.

POSTROUTING

The POSTROUTING chain changes packet envelopes. I use it to 'MASQUERADE' the internal IP-addresses. For the outside world all packets come from the same IP-address. If you want/need to use multiple IP-addresses then you must use SNAT instead of MASQUERADE.

The Script

#!/bin/sh
. /etc/functions.sh

### Activate the LOG option for iptables.
insmod ipt_LOG
insmod ipt_REDIRECT

### Get the broadcast.
getBC() {
  IP=`echo $1  | sed -re 's/.[0-9]*$/.255/'`
  echo $IP
}

### Find the IP Address for a server.
getIP() {
  IP=`ping -c 1 $1 2>&1 | grep -E '^PING' | sed -re 's/^[^(]*.([^)]*).*/\1/'`
  if [ -z "$IP" ]; then IP="127.0.0.1"; fi
  echo $IP
}

### Get the net.
getNW() {
  IP=`echo $1  | sed -re 's:.[0-9]*$:.0/24:'`
  echo $IP
}

### Find the interface per sub-domain.
DMZ=$(nvram get dmz_ifname)
DMZ_IP=$(nvram get dmz_ipaddr)
FREE=$(nvram get free_ifname)
FREE_IP=$(nvram get free_ipaddr)
LAN=$(nvram get lan_ifname)
LAN_IP=$(nvram get lan_ipaddr)
VOIP=$(nvram get voip_ifname)
VOIP_IP=$(nvram get voip_ipaddr)
WAN=$(nvram get wan_ifname)
WAN_IP=$(nvram get wan_ipaddr)

### Preset servers
DNS=`getIP dns.debooy.eu`
MODEM=`getIP modem.debooy.eu`
TOMCAT=`getIP intra.debooy.eu`
PROXY=`getIP proxy.debooy.eu`
SAMBA=`getIP samba.debooy.eu`
TELCEN=`getIP aput.debooy.eu`

### Broadcasts
DMZ_BC=`getBC $DMZ_IP`
FREE_BC=`getBC $FREE_IP`
GEN_BC=255.255.255.255
LAN_BC=`getBC $LAN_IP`
VOIP_BC=`getBC $VOIP_IP`
WAN_BC=`getBC $WAN_IP`

### Networks
DMZ_NW=`getNW $DMZ_IP`
FREE_NW=`getNW $FREE_IP`
GEN_NW=0/0
LAN_NW=`getNW $LAN_IP`
VOIP_NW=`getNW $VOIP_IP`
WAN_NW=`getNW $WAN_IP`

### Allow forwarding of packets.
echo 1 > /proc/sys/net/ipv4/ip_forward

iptables --flush
iptables --table filter --flush
iptables --table nat    --flush
iptables --delete-chain
iptables --table nat    --delete-chain

### Allow self access by loopback interface
iptables -A INPUT   -i lo -j ACCEPT
iptables -A FORWARD -i lo -j ACCEPT

### Create separate chains
iptables -N allowed
iptables -N bad_tcp_packets
iptables -N blacklist
iptables -N icmp_packets
iptables -N whitelist
iptables -N ${DMZ}_FW
iptables -N ${DMZ}_IN
iptables -N ${DMZ}_OU
iptables -N ${FREE}_IN
iptables -N ${LAN}_FW
iptables -N ${LAN}_IN
iptables -N ${LAN}_OU
iptables -N ${VOIP}_IN
iptables -N ${WAN}_IN

### allowed chain
iptables -A allowed -p tcp --syn                                -j ACCEPT
iptables -A allowed -p tcp -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A allowed -p tcp                                      -j DROP

### bad_tcp_packets chain
iptables -A bad_tcp_packets -p tcp --tcp-flags SYN,ACK SYN,ACK     -m state --state NEW -j REJECT --reject-with tcp-reset
iptables -A bad_tcp_packets -p tcp ! --syn                         -m state --state NEW -j LOG    --log-prefix "FIREWALL:NEW!SYN - "
iptables -A bad_tcp_packets -p tcp ! --syn                         -m state --state NEW -j DROP

### ICMP rules
iptables -A icmp_packets -p icmp --fragment                -j LOG    --log-prefix "FIREWALL:ICMP!FR - "
iptables -A icmp_packets -p icmp --fragment                -j DROP
iptables -A icmp_packets -p icmp -s $GEN_NW --icmp-type 0  -j ACCEPT
iptables -A icmp_packets -p icmp -s $GEN_NW --icmp-type 8  -j ACCEPT
iptables -A icmp_packets -p icmp -s $GEN_NW --icmp-type 11 -j ACCEPT

### Blacklist
if [ -f /etc/iptables/blacklist ]; then
  for HOST in `cat /etc/iptables/blacklist`
  do
    iptables -A blacklist -s $HOST -j DROP
  done
fi

### Whitelist
if [ -f /etc/iptables/whitelist ]; then
  for HOST in `cat /etc/iptables/whitelist`
  do
    iptables -A whitelist -s $HOST -j ACCEPT
  done
fi

### DMZ FW rules
iptables -A ${DMZ}_FW -p tcp            --dport 22          -j ACCEPT
iptables -A ${DMZ}_FW -p udp            --dport 22          -j ACCEPT
iptables -A ${DMZ}_FW -p tcp            --dport 25          -j ACCEPT
iptables -A ${DMZ}_FW -p udp            --dport 53          -j ACCEPT
iptables -A ${DMZ}_FW -p udp --dport 67:68 --sport 67:68    -j ACCEPT
iptables -A ${DMZ}_FW -p tcp            --dport 80          -j ACCEPT
iptables -A ${DMZ}_FW -p udp            --dport 123         -j ACCEPT
iptables -A ${DMZ}_FW -p tcp            --dport 139         -j ACCEPT
iptables -A ${DMZ}_FW -p tcp            --dport 445         -j ACCEPT
iptables -A ${DMZ}_FW -p tcp            --dport 8080        -j ACCEPT
iptables -A ${DMZ}_FW -p tcp -d $MODEM  --dport 23          -j ACCEPT
iptables -A ${DMZ}_FW -p tcp -d $TELCEN --dport 23          -j ACCEPT

### DMZ IN rules
iptables -A ${DMZ}_IN -p all -d $DMZ_IP                     -j ACCEPT
iptables -A ${DMZ}_IN -p tcp            --dport 22          -j ACCEPT
iptables -A ${DMZ}_IN -p udp            --dport 22          -j ACCEPT
iptables -A ${DMZ}_IN -p udp            --dport 53          -j ACCEPT
iptables -A ${DMZ}_IN -p udp --dport 67:68 --sport 67:68    -j ACCEPT
iptables -A ${DMZ}_IN -p udp -d $DMZ_BC --dport 135:139     -j DROP
iptables -A ${DMZ}_IN -p udp -d $GEN_BC --dport 135:139     -j DROP
iptables -A ${DMZ}_IN -p tcp            --dport 137:139     -j ACCEPT
iptables -A ${DMZ}_IN -p udp            --dport 137:139     -j ACCEPT

### DMZ OU rules
iptables -A ${DMZ}_OU -p udp            --dport 53          -j ACCEPT
iptables -A ${DMZ}_OU -p udp            --dport 123         -j ACCEPT
iptables -A ${DMZ}_OU -p udp            --dport 514         -j ACCEPT

### FREE IN rules
iptables -A ${FREE}_IN -p all -d $FREE_IP                   -j ACCEPT
iptables -A ${FREE}_IN -p tcp --dport 22                    -j ACCEPT
iptables -A ${FREE}_IN -p udp --dport 22                    -j ACCEPT
iptables -A ${FREE}_IN -p udp --dport 67:68 --sport 67:68   -j ACCEPT

### LAN FW rules
iptables -A ${LAN}_FW -p tcp            --dport 21          -j ACCEPT
iptables -A ${LAN}_FW -p tcp            --dport 22          -j ACCEPT
iptables -A ${LAN}_FW -p udp            --dport 22          -j ACCEPT
iptables -A ${LAN}_FW -p tcp            --dport 25          -j ACCEPT
iptables -A ${LAN}_FW -p udp            --dport 53          -j ACCEPT
iptables -A ${LAN}_FW -p udp --dport 67:68 --sport 67:68    -j ACCEPT
iptables -A ${LAN}_FW -p tcp            --dport 110         -j ACCEPT
iptables -A ${LAN}_FW -p udp            --dport 123         -j ACCEPT
iptables -A ${LAN}_FW -p tcp            --dport 389         -j ACCEPT
iptables -A ${LAN}_FW -p udp            --dport 389         -j ACCEPT
iptables -A ${LAN}_FW -p tcp            --dport 443         -j ACCEPT
iptables -A ${LAN}_FW -p udp            --dport 500         -j ACCEPT
iptables -A ${LAN}_FW -p tcp            --dport 554         -j ACCEPT
iptables -A ${LAN}_FW -p tcp            --dport 3128        -j ACCEPT
iptables -A ${LAN}_FW -p tcp            --dport 3306        -j ACCEPT
iptables -A ${LAN}_FW -p udp            --dport 4500        -j ACCEPT
iptables -A ${LAN}_FW -p tcp            --dport 8085        -j ACCEPT
iptables -A ${LAN}_FW -p tcp -d $MODEM  --dport 23          -j ACCEPT
iptables -A ${LAN}_FW -p tcp -d $MODEM  --dport 80          -j ACCEPT
## Facebook spelletjes
iptables -A ${LAN}_FW -p tcp -o ${WAN}  --dport 843         -j ACCEPT
iptables -A ${LAN}_FW -p tcp -o ${WAN}  --dport 8080        -j ACCEPT
iptables -A ${LAN}_FW -p tcp -o ${WAN}  --dport 9339        -j ACCEPT
## Samba
iptables -A ${LAN}_FW -p tcp            --dport 135         -j ACCEPT
iptables -A ${LAN}_FW -p udp            --dport 137         -j ACCEPT
iptables -A ${LAN}_FW -p udp            --dport 138         -j ACCEPT
iptables -A ${LAN}_FW -p tcp            --dport 139         -j ACCEPT
iptables -A ${LAN}_FW -p tcp            --dport 445         -j ACCEPT
## NFS
iptables -A ${LAN}_FW -p tcp            --dport 111         -j ACCEPT
iptables -A ${LAN}_FW -p udp            --dport 111         -j ACCEPT
iptables -A ${LAN}_FW -p tcp            --dport 2049        -j ACCEPT
iptables -A ${LAN}_FW -p udp            --dport 2049        -j ACCEPT
iptables -A ${LAN}_FW -p tcp            --dport 32765:32769 -j ACCEPT
iptables -A ${LAN}_FW -p udp            --dport 32765:32769 -j ACCEPT

### LAN IN rules
iptables -A ${LAN}_IN -p all -d $LAN_IP                     -j ACCEPT
iptables -A ${LAN}_IN -p tcp            --dport 22          -j ACCEPT
iptables -A ${LAN}_IN -p udp            --dport 22          -j ACCEPT
iptables -A ${LAN}_IN -p tcp            --dport 42          -j ACCEPT
iptables -A ${LAN}_IN -p udp --dport 67:68 --sport 67:68    -j ACCEPT
iptables -A ${LAN}_IN -p tcp            --dport 80          -j ACCEPT
iptables -A ${LAN}_IN -p udp -d $LAN_BC --dport 135:139     -j DROP
iptables -A ${LAN}_IN -p udp -d $GEN_BC --dport 135:139     -j DROP
iptables -A ${LAN}_IN -p tcp            --dport 137:139     -j ACCEPT
iptables -A ${LAN}_IN -p udp            --dport 137:139     -j ACCEPT
iptables -A ${LAN}_IN -p udp -s $LAN_IP --dport 514         -j ACCEPT

### LAN OU rules
iptables -A ${LAN}_OU -p udp            --dport 514         -j ACCEPT

### VOIP FW rules
iptables -A ${VOIP}_FW -p udp           --dport 53          -j ACCEPT
iptables -A ${VOIP}_FW -p udp --dport 67:68 --sport 67:68   -j ACCEPT
iptables -A ${VOIP}_FW -p udp           --dport 123         -j ACCEPT
iptables -A ${VOIP}_FW -p udp           --dport 5060        -j ACCEPT

### VOIP IN rules
iptables -A ${VOIP}_IN -p all -d $VOIP_IP                   -j ACCEPT
iptables -A ${VOIP}_IN -p tcp            --dport 22         -j ACCEPT
iptables -A ${VOIP}_IN -p udp            --dport 22         -j ACCEPT
iptables -A ${VOIP}_IN -p udp --dport 67:68 --sport 67:68   -j ACCEPT

### FORWARD rules
iptables -A FORWARD                                         -j blacklist
iptables -A FORWARD                                         -j whitelist
iptables -A FORWARD -p tcp                                  -j bad_tcp_packets
iptables -A FORWARD -p icmp                                 -j icmp_packets
iptables -A FORWARD -m state --state ESTABLISHED,RELATED    -j ACCEPT
# Where does it come from?
iptables -A FORWARD -p all  -i $DMZ                         -j ${DMZ}_FW
iptables -A FORWARD -p all  -i $LAN                         -j ${LAN}_FW
iptables -A FORWARD -p all  -i $VOIP                        -j ${VOIP}_FW
iptables -A FORWARD -p all  -i $WAN                         -j ${WAN}_FW

### INPUT rules
iptables -A INPUT                                           -j blacklist
iptables -A INPUT                                           -j whitelist
iptables -A INPUT -p tcp                                    -j bad_tcp_packets
iptables -A INPUT -p icmp                                   -j icmp_packets
iptables -A INPUT -m state --state ESTABLISHED,RELATED      -j ACCEPT
# Where does it come from?
iptables -A INPUT -p all  -i $DMZ                           -j ${DMZ}_IN
iptables -A INPUT -p all  -i $FREE                          -j ${FREE}_IN
iptables -A INPUT -p all  -i $LAN                           -j ${LAN}_IN
iptables -A INPUT -p all  -i $VOIP                          -j ${VOIP}_IN
iptables -A INPUT -p all  -i $WAN                           -j ${WAN}_IN

### From Localhost interface to Localhost IP's
iptables -A INPUT -p all -i lo -s $DMZ_IP                   -j ACCEPT
iptables -A INPUT -p all -i lo -s $FREE_IP                  -j ACCEPT
iptables -A INPUT -p all -i lo -s $LAN_IP                   -j ACCEPT
iptables -A INPUT -p all -i lo -s $VOIP_IP                  -j ACCEPT
iptables -A INPUT -p all -i lo -s $WAN_IP                   -j ACCEPT

### OUTPUT rules
iptables -A OUTPUT                                          -j blacklist
iptables -A OUTPUT                                          -j whitelist
iptables -A OUTPUT -p tcp                                   -j bad_tcp_packets
iptables -A OUTPUT -p icmp                                  -j icmp_packets
iptables -A OUTPUT -m state --state ESTABLISHED,RELATED     -j ACCEPT
# Where does it come from?
iptables -A OUTPUT -p all  -o $DMZ                          -j ${DMZ}_OU
iptables -A OUTPUT -p all  -o $LAN                          -j ${LAN}_OU

### PREROUTING rules
iptables -t nat -A PREROUTING -i $LAN   -p tcp -d $LAN_IP --dport 80   -j ACCEPT
iptables -t nat -A PREROUTING -i $LAN   -p tcp -d $MODEM  --dport 80   -j ACCEPT
iptables -t nat -A PREROUTING -i $LAN   -p tcp            --dport 80   -j DNAT --to $PROXY:3128

### POSTROUTING rules
## Enable simple IP Forwarding and Network Address Translation
#iptables -t nat -A POSTROUTING -o $WAN -j LOG --log-prefix "FIREWALL:P.ROUTE - "
iptables -t nat -A POSTROUTING -o $WAN -s $DMZ_NW  -j MASQUERADE
iptables -t nat -A POSTROUTING -o $WAN -s $FREE_NW -j MASQUERADE
iptables -t nat -A POSTROUTING -o $WAN -s $LAN_NW  -j MASQUERADE
iptables -t nat -A POSTROUTING -o $WAN -s $VOIP_NW -j MASQUERADE
iptables -t nat -A POSTROUTING -o $WAN -s $WIFI_NW -j MASQUERADE

### Log the packages that passed
iptables -A INPUT   -j LOG --log-prefix "FIREWALL:INPUT   - "
iptables -A FORWARD -j LOG --log-prefix "FIREWALL:FORWARD - "
iptables -A OUTPUT  -j LOG --log-prefix "FIREWALL:OUTPUT  - "

### Block all the rest
iptables -P INPUT   DROP
iptables -P FORWARD DROP
iptables -P OUTPUT  ACCEPT