Got a spare box sitting under your desk? Stick two NICs in it, install Debian minimal, and you have a firewall that will outperform most consumer routers. I did this with an old Pentium III and two 100Mbit Ethernet cards I had lying about. Total cost: nothing.
Hardware and OS setup
You need two network interfaces. eth0 faces the internet (or your ISP modem), eth1 faces your LAN. Install Debian net-install, skip the desktop environment, just get a base system with SSH. You want as few services running as possible - this box is a firewall, not a web server.
First, enable IP forwarding. Edit /etc/sysctl.conf:
net.ipv4.ip_forward = 1
Apply it:
# sysctl -p
The iptables script
I keep my rules in /etc/firewall.sh and call it from /etc/rc.local. Here is the full script:
#!/bin/bash
IPT="/sbin/iptables"
WAN="eth0"
LAN="eth1"
LAN_NET="192.168.1.0/24"
# Flush existing rules
$IPT -F
$IPT -t nat -F
$IPT -t mangle -F
$IPT -X
# Default policies - drop everything
$IPT -P INPUT DROP
$IPT -P FORWARD DROP
$IPT -P OUTPUT ACCEPT
# Loopback
$IPT -A INPUT -i lo -j ACCEPT
$IPT -A OUTPUT -o lo -j ACCEPT
# Allow established and related connections
$IPT -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
$IPT -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT
# Allow all traffic from LAN
$IPT -A INPUT -i $LAN -s $LAN_NET -j ACCEPT
$IPT -A FORWARD -i $LAN -s $LAN_NET -j ACCEPT
# NAT - masquerade outbound traffic
$IPT -t nat -A POSTROUTING -o $WAN -j MASQUERADE
# Port forwarding - SSH to internal box
$IPT -t nat -A PREROUTING -i $WAN -p tcp --dport 2222 \
-j DNAT --to-destination 192.168.1.10:22
$IPT -A FORWARD -i $WAN -p tcp --dport 22 -d 192.168.1.10 \
-m state --state NEW -j ACCEPT
# Port forwarding - HTTP to internal web server
$IPT -t nat -A PREROUTING -i $WAN -p tcp --dport 80 \
-j DNAT --to-destination 192.168.1.20:80
$IPT -A FORWARD -i $WAN -p tcp --dport 80 -d 192.168.1.20 \
-m state --state NEW -j ACCEPT
# Allow SSH to the firewall itself (from LAN only)
$IPT -A INPUT -i $LAN -p tcp --dport 22 -j ACCEPT
# Drop invalid packets
$IPT -A INPUT -m state --state INVALID -j DROP
$IPT -A FORWARD -m state --state INVALID -j DROP
# Log dropped packets (limit to avoid flooding syslog)
$IPT -A INPUT -j LOG --log-prefix "FW_INPUT_DROP: " --log-level 4 \
-m limit --limit 5/min
$IPT -A FORWARD -j LOG --log-prefix "FW_FORWARD_DROP: " --log-level 4 \
-m limit --limit 5/min
echo "Firewall rules loaded."
Make it executable and run it:
# chmod +x /etc/firewall.sh
# /etc/firewall.sh
Firewall rules loaded.
What this gives you
Default policy is DROP on INPUT and FORWARD. Nothing gets through unless you explicitly allow it. Outbound traffic from the LAN is masqueraded behind the WAN IP. Two port forwards are set up - SSH on port 2222 goes to an internal box, and HTTP goes to a web server on the LAN.
The logging rules at the end are useful for seeing what is being blocked. Check /var/log/messages or /var/log/syslog depending on your setup. The rate limit prevents log flooding if someone runs a port scan against you.
DHCP for the LAN
You will want to run a DHCP server on the LAN side. Install dhcp3-server and configure /etc/dhcp3/dhcpd.conf:
subnet 192.168.1.0 netmask 255.255.255.0 {
range 192.168.1.100 192.168.1.200;
option routers 192.168.1.1;
option domain-name-servers 208.67.222.222, 208.67.220.220;
default-lease-time 86400;
}
I am using OpenDNS here. You could run your own caching resolver with dnsmasq but that is a topic for another post.
Testing
From an external machine (or ask a mate), run nmap against your WAN IP:
$ nmap -sS -Pn 82.x.x.x
Starting Nmap 4.11 ( http://www.insecure.org/nmap/ )
Interesting ports on 82.x.x.x:
Not shown: 1677 filtered ports
PORT STATE SERVICE
80/tcp open http
2222/tcp open unknown
Only the forwarded ports should show up. Everything else should be filtered (not closed - filtered means the packets are being silently dropped, which is what we want).
Persistence
Add /etc/firewall.sh to /etc/rc.local so the rules survive a reboot. Alternatively, install iptables-persistent and use iptables-save / iptables-restore, but I prefer the script approach because it is easier to read and modify.
Total setup time was about 45 minutes including the Debian install. The Pentium III barely breaks a sweat routing traffic - CPU usage sits at 1-2% even when saturating the 100Mbit link. For a home network with a handful of machines, this is more than adequate.
Next up I will look at adding Snort to this setup for basic intrusion detection.