How to set up a DMZ with a Linux router

To explain how to set up a DMZ with a a Linux router I will use the firewall in my own Raspberry Pi router as an example.

You want to route an incoming connection to a computer in the LAN. Let’s assume the connection is SSH, that is, of protocol TCP and port 22 type.

The first step is to re-route the incoming connection to the LAN IP. Let’s assume the LAN computer has IP 192.168.0.15. The re-routing in done in the NAT table and PREROUTING chain.

Add to the NAT chain,

# DMZ
$IPTABLES -t nat -A PREROUTING -p TCP -i $INET_IFACE -d $INET_IP --dport 22 -j DNAT --to-destination 192.168.0.15

In this pre-routing rule, any connection arriving at the external network interface $INET_IFACE with IP $INET_IP, and protocol TCP and port 22, is routed to IP 192.168.0.15.

This alone will not do the trick, because the connection needs to be forwarded to the LAN network interface.

Add to the LAN network interface’s FORWARD chain, before all external requests to the LAN are blocked,

# DMZ
$IPTABLES -A FORWARD -i $INET_IFACE -o $IFACE -p TCP -m state --state NEW --dport 22 -j ACCEPT

This rule forwards any connection of protocol TCP to port 22 arriving at the external interface $INET_IFACE to the LAN network interface $IFACE.

The full syntax of the firewall piece that goes in file /etc/network/if-up.d/firewall is shown next, and the added rules are highlighted in blue,

#!/bin/sh

# Author: Ricardo Yanez ricardo.yanez@calel.org

IPTABLES="/sbin/iptables"

# external interface
INET_IFACE="enxb827eb28828c"

# WLAN interface
WLAN_IFACE="wlan0"

WLAN_IP="192.168.0.1"
WLAN_IP_RANGE="192.168.0.0/24"

if [ "$IFACE" = "$INET_IFACE" ]; then

 # "block-spoof" chain
 $IPTABLES -N block-spoof
 $IPTABLES -A block-spoof -i $IFACE -s 10.0.0.0/8 -j DROP
 $IPTABLES -A block-spoof -i $IFACE -s 172.16.0.0/12 -j DROP
 $IPTABLES -A block-spoof -i $IFACE -s 192.168.0.0/16 -j DROP

 # "allowed-icmp-packets" chain
 $IPTABLES -N allowed-icmp-packets
 $IPTABLES -A allowed-icmp-packets -p ICMP --icmp-type 8 -m limit --limit 1/second --limit-burst 3 -j ACCEPT
 $IPTABLES -A allowed-icmp-packets -p ICMP -j DROP

 # "allowed-udp-packets" chain
 $IPTABLES -N allowed-udp-packets
 $IPTABLES -A allowed-udp-packets -p UDP -m state --state NEW --dport 53 -j ACCEPT
 $IPTABLES -A allowed-udp-packets -p UDP -m state --state NEW --dport 123 -j ACCEPT
 $IPTABLES -A allowed-udp-packets -p UDP -m state --state NEW -j DROP

 # "allowed-tcp-packets" chain
 $IPTABLES -N allowed-tcp-packets
 $IPTABLES -A allowed-tcp-packets -p TCP -m state --state NEW --dport 53 -j ACCEPT

 ###############################################
 ############### INPUT chain ###################
 ###############################################

 # established, related
 $IPTABLES -A INPUT -i $IFACE -m state --state ESTABLISHED,RELATED -j ACCEPT

 $IPTABLES -A INPUT -i $IFACE -j block-spoof
 $IPTABLES -A INPUT -i $IFACE -j blocked-packets
 $IPTABLES -A INPUT -i $IFACE -p ICMP -j allowed-icmp-packets
 $IPTABLES -A INPUT -i $IFACE -p UDP -j allowed-udp-packets
 $IPTABLES -A INPUT -i $IFACE -p TCP -j allowed-tcp-packets

 # log discarded INPUT chain packets
 $IPTABLES -A INPUT -i $IFACE -j LOG --log-level debug --log-prefix "iptables DROP INPUT: "

 ###############################################
 ############## FORWARD chain ##################
 ###############################################

 # log discarded FORWARD chain packets
 $IPTABLES -A FORWARD -i $IFACE -j LOG --log-level debug --log-prefix "iptables DROP FORWARD: "

 ###############################################
 ############## OUTPUT chain ###################
 ###############################################

 # established, related
 $IPTABLES -A OUTPUT -o $IFACE -m state --state ESTABLISHED,RELATED -j ACCEPT

 # ICMP packets
 $IPTABLES -A OUTPUT -o $IFACE -p ICMP --icmp-type 8 -j ACCEPT

 # UDP packets
 $IPTABLES -A OUTPUT -o $IFACE -p UDP -m state --state NEW --dport 53 -j ACCEPT    # dns
 $IPTABLES -A OUTPUT -o $IFACE -p UDP -m state --state NEW --dport 67 -j ACCEPT    # bootps
 $IPTABLES -A OUTPUT -o $IFACE -p UDP -m state --state NEW --dport 123 -j ACCEPT   # ntp

 # TCP packets
 $IPTABLES -A OUTPUT -o $IFACE -p TCP -m state --state NEW --dport 43 -j ACCEPT    # whois
 $IPTABLES -A OUTPUT -o $IFACE -p TCP -m state --state NEW --dport 53 -j ACCEPT    # dns
 $IPTABLES -A OUTPUT -o $IFACE -p TCP -m state --state NEW --dport 67 -j ACCEPT    # bootps
 $IPTABLES -A OUTPUT -o $IFACE -p TCP -m state --state NEW --dport 80 -j ACCEPT    # http
 $IPTABLES -A OUTPUT -o $IFACE -p TCP -m state --state NEW --dport 443 -j ACCEPT   # https

 # log rest of OUTPUT chain packets
 $IPTABLES -A OUTPUT -o $IFACE -m state --state NEW -j LOG --log-level debug --log-prefix "iptables NEW OUTPUT: "
fi

if [ "$IFACE" = "$WLAN_IFACE" ]; then

 ###############################################
 ############### INPUT chain ###################
 ###############################################

 # established, related
 $IPTABLES -A INPUT -i $IFACE -s $WLAN_IP_RANGE -m state --state ESTABLISHED,RELATED -j ACCEPT

 # ICMP packets
 $IPTABLES -A INPUT -i $IFACE -s $WLAN_IP_RANGE -p ICMP --icmp-type 8 -m limit --limit 1/second --limit-burst 3 -j ACCEPT
   $IPTABLES -A INPUT -i $IFACE -s $WLAN_IP_RANGE -p ICMP -j DROP

 # UDP packets
 $IPTABLES -A INPUT -i $IFACE -s $WLAN_IP_RANGE -p UDP -m state --state NEW --dport 53 -j ACCEPT    # dns
 $IPTABLES -A INPUT -i $IFACE -s $WLAN_IP_RANGE -p UDP -m state --state NEW --dport 67 -j ACCEPT    # bootsp
 $IPTABLES -A INPUT -i $IFACE -s $WLAN_IP_RANGE -p UDP -m state --state NEW --dport 123 -j ACCEPT   # ntp

 # TCP packets
 $IPTABLES -A INPUT -i $IFACE -s $WLAN_IP_RANGE -p TCP -m state --state NEW --dport 22 -j ACCEPT    # ssh
 $IPTABLES -A INPUT -i $IFACE -s $WLAN_IP_RANGE -p TCP -m state --state NEW --dport 53 -j ACCEPT    # dns
 $IPTABLES -A INPUT -i $IFACE -s $WLAN_IP_RANGE -p TCP -m state --state NEW --dport 80 -j ACCEPT    # http

 # log rest of LAN INPUT chain packets
 $IPTABLES -A INPUT -i $IFACE -m state --state NEW -j LOG --log-level debug --log-prefix "iptables LAN NEW INPUT: "

 ###############################################
 ############## FORWARD chain ##################
 ###############################################

 # established, related
 $IPTABLES -A FORWARD -i $INET_IFACE -o $IFACE -m state --state ESTABLISHED,RELATED -j ACCEPT
 $IPTABLES -A FORWARD -i $IFACE -o $INET_IFACE -m state --state ESTABLISHED,RELATED -j ACCEPT

 # DMZ
 $IPTABLES -A FORWARD -i $INET_IFACE -o $IFACE -p TCP -m state --state NEW --dport 22 -j ACCEPT

 # block external FORWARD requests to LAN  $IPTABLES -A FORWARD -i $INET_IFACE -o $IFACE -m state --state NEW -j DROP

 # ICMP packets
 $IPTABLES -A FORWARD -i $IFACE -o $INET_IFACE -p ICMP --icmp-type 8 -m limit --limit 1/second --limit-burst 3 -j ACCEPT
 $IPTABLES -A FORWARD -i $IFACE -o $INET_IFACE -p ICMP -j DROP

 # UDP packets
 $IPTABLES -A FORWARD -i $IFACE -o $INET_IFACE -p UDP -m state --state NEW --dport 53 -j ACCEPT    # dns
 $IPTABLES -A FORWARD -i $IFACE -o $INET_IFACE -p UDP -m state --state NEW --dport 80 -j ACCEPT    # http
 $IPTABLES -A FORWARD -i $IFACE -o $INET_IFACE -p UDP -m state --state NEW --dport 123 -j ACCEPT   # ntp
 $IPTABLES -A FORWARD -i $IFACE -o $INET_IFACE -p UDP -m state --state NEW --dport 443 -j ACCEPT   # https
 $IPTABLES -A FORWARD -i $IFACE -o $INET_IFACE -p UDP -m state --state NEW --dport 5353 -j ACCEPT  # Multicast DNS

 # TCP packets
 $IPTABLES -A FORWARD -i $IFACE -o $INET_IFACE -p TCP -m state --state NEW --dport 22 -j ACCEPT    # ssh
 $IPTABLES -A FORWARD -i $IFACE -o $INET_IFACE -p TCP -m state --state NEW --dport 43 -j ACCEPT    # whois
 $IPTABLES -A FORWARD -i $IFACE -o $INET_IFACE -p TCP -m state --state NEW --dport 53 -j ACCEPT    # dns
 $IPTABLES -A FORWARD -i $IFACE -o $INET_IFACE -p TCP -m state --state NEW --dport 80 -j ACCEPT    # http
 $IPTABLES -A FORWARD -i $IFACE -o $INET_IFACE -p TCP -m state --state NEW --dport 443 -j ACCEPT   # https
 $IPTABLES -A FORWARD -i $IFACE -o $INET_IFACE -p TCP -m state --state NEW --dport 465 -j ACCEPT   # smtps
 $IPTABLES -A FORWARD -i $IFACE -o $INET_IFACE -p TCP -m state --state NEW --dport 993 -j ACCEPT   # imaps

 # log rest of LAN FORWARD chain packets
 $IPTABLES -A FORWARD -i $IFACE -o $INET_IFACE -m state --state NEW -j LOG --log-level debug --log-prefix "iptables LAN NEW FORWARD: "

 ###############################################
 ############## OUTPUT chain ###################
 ###############################################

 # established, related
 $IPTABLES -A OUTPUT -o $IFACE -m state --state ESTABLISHED,RELATED -j ACCEPT

 # ICMP packets
 $IPTABLES -A OUTPUT -o $IFACE -p ICMP --icmp-type 8 -m limit --limit 1/second --limit-burst 3 -j ACCEPT
 $IPTABLES -A OUTPUT -o $IFACE -p ICMP -j DROP

 # log rest of LAN OUTPUT chain packets
 $IPTABLES -A OUTPUT -o $IFACE -m state --state NEW -j LOG --log-level debug --log-prefix "iptables LAN NEW OUTPUT: "

 ###############################################
 ############## NAT chain ######################
 ###############################################

 $IPTABLES -t nat -F POSTROUTING
 $IPTABLES -t nat -F PREROUTING

 # DMZ
 $IPTABLES -t nat -A PREROUTING -p TCP -i $INET_IFACE -d $INET_IP --dport 22 -j DNAT --to-destination 192.168.0.15

 # IP masquerade
 INET_IP=ifconfig $INET_IFACE | grep -Eo 'inet (addr:)?([0-9]*\.){3}[0-9]*' | grep -Eo '([0-9]*\.){3}[0-9]*'
 $IPTABLES -t nat -A POSTROUTING -s $WLAN_IP_RANGE -o $INET_IFACE -j SNAT --to-source $INET_IP
fi

Needless to say, the LAN computer that receives all SSH connections from the exterior needs to be protected. I use a hit counter to limit the allowed number of connections from an IP,

$IPTABLES -A INPUT -i $IFACE -p TCP -m state --state NEW --dport 22 -m recent --set
$IPTABLES -A INPUT -i $IFACE -p TCP -m state --state NEW --dport 22 -m recent --update --seconds 120 --hitcount 2 -j DROP
$IPTABLES -A INPUT -i $IFACE -p TCP -m state --state NEW --dport 22 -j LOG --log-level debug --log-prefix "iptables ssh: "
$IPTABLES -A INPUT -i $IFACE -p TCP -m state --state NEW --dport 22 -j ACCEPT

These rules will set a counter of maximum 2 connections every 120 seconds for any IP attempting to connect with SSH. This effectively reduces the chance of hacking to practically zero.

Leave a Reply

Your email address will not be published. Required fields are marked *