Up one level
How I set up a small Router/Gateway/Firewall in Linux using DNSMASQ (instead of DHCPD+DNS/BIND) (Debian)
Spencer Stirling

I recently had the pleasure of trying to figure out how to set up a router with a firewall (aka Network Address Translation (NAT) aka IP Masquerading) for a small network. Figuring all of this stuff out took me a whole day, and I have no wish to repeat it (since it's actually not hard - but I've had huge pitfalls with the DNS stuff - e.g. resolving names on my local network).

Note that for determining services that are listening on your computer at any given time, the command "netstat -luntp" can be very useful. You can also do a portscan (from a remote host) with "nmap -sV [remotehost]" to see how your firewall is REALLY looking to an outsider.

Note: these firewall scripts only keep traffic where it belongs. It does NOT limit bandwidth (e.g. won't protect you from a Denial of Service DoS flood attack). For that you should look at combining "iptables" with the iproute2 software (Debian package "iproute"). Just as iptables replaced the older ipchains firewall, the iproute2 commands "tc" and "ip" replace the older "route" and "ifconfig" commands (which are now, for backward compatibility, just scripts that call iproute2). Consult the Linux Advanced Routing and Traffic Control Howto for the ultimate guide. This will tell you how to "shape" (limit and prioritize outgoing traffic) and "police" (limit and prioritize incoming traffic). The package "wondershaper" does a few of these things automatically.

The package "fail2ban" (useful for SSH Security and (with some configuration) avoiding webserver and email server attacks) will kill many types of unwanted traffic by scanning the logs and banning unwanted IPs. Also have a look at (D)DoS-Deflate for preventing those DoS attacks.

Before we begin, I should point out that if you merely have a regular computer with one interface and you just want some simple firewalling rules then you might want to use a graphical firewall frontend like "guarddog+guidedog" or "firestarter". Under the hood they all use IPTABLES. In my experience if you are going to be doing ANYTHING more than the simplest standalone firewalling then you should just learn IPTABLES - at least you'll then know what the machine is doing. Here is a script that brings up some firewalling rules on a machine with only one network interface.

THIS SCRIPT IS FOR A STANDALONE COMPUTER (i.e. not a router for other computers) WITH ONLY 1 NETWORK INTERFACE. PLEASE SKIP BELOW IF YOU WANT TO KNOW ABOUT THE FIREWALLED ROUTER. I USE THIS FIREWALL SCRIPT FOR SOME SERVERS THAT SIT BEHIND DSL/CABLE ROUTERS, BUT IT WORKS EVEN FOR WORKSTATION (NOT SERVER) COMPUTERS.

#!/bin/sh

#  SAMPLE IPTABLES  FIREWALL  script
#  I'm assuming that the interface is "up"
#  YOU CAN SPECIFY THE INTERFACE AS AN ARGUMENT ON THE COMMANDLINE
#    i.e. "firewall.sh ath0"

echo -e "\n\nSETTING UP IPTABLES FIREWALL..."


# SET THE INTERFACE DESIGNATION AND ADDRESS AND NETWORK ADDRESS
# FOR THE NIC CONNECTED TO EXTERNAL NETWORK
#   The default value below is for "eth0".  This value 
#   You can use the ifconfig command to list the interfaces
#   on your system.
EXTIF="eth0"
#check for a commandline argument
if [ "$1" != "" ]
then
  EXTIF="$1"
fi
EXTIP="`/sbin/ifconfig $EXTIF | grep 'inet addr' \
      | awk '{print $2}' | sed -e 's/.*://'`"


UNIVERSE="0.0.0.0/0"

# Clear any existing rules and setting default policy to DROP
iptables -P INPUT DROP
iptables -F INPUT 
iptables -P OUTPUT DROP
iptables -F OUTPUT 
iptables -P FORWARD DROP
iptables -F FORWARD 
iptables -F -t nat

# Flush the user chain.. if it exists
if [ "`iptables -L | grep drop-and-log-it`" ]; then
   iptables -F drop-and-log-it
fi

# Delete all User-specified chains
iptables -X

# Reset all IPTABLES counters
iptables -Z

# Creating a DROP chain
iptables -N drop-and-log-it
iptables -A drop-and-log-it -j LOG --log-level info 
iptables -A drop-and-log-it -j REJECT

echo -e "     - Loading INPUT rulesets"

#######################################################################
# INPUT: Incoming traffic from various interfaces.  All rulesets are 
#        already flushed and set to a default policy of DROP. 
#

# loopback interfaces are valid.
iptables -A INPUT -i lo -j ACCEPT

# THIS WOULD ALLOW EVERYTHING TO GET IN - FOR TESTING ONLY
#iptables -A INPUT -i $EXTIF -s $UNIVERSE -d $EXTIP -j ACCEPT

# This is necessary for basic network functionality
iptables -A INPUT -i $EXTIF -p icmp -s $UNIVERSE -d $EXTIP -j ACCEPT

# THIS ALLOWS ALREADY-ESTABLISHED TRAFFIC IN
# Allow any related traffic coming back to the MASQ server in
iptables -A INPUT -i $EXTIF -s $UNIVERSE -d $EXTIP \
  -m state --state ESTABLISHED,RELATED -j ACCEPT

######################################################################## 
# HERE ARE THE INCOMING SERVICES THAT ARE ALLOWED.  YOU MAY ADD
# MORE IF YOU NEED TO OPEN UP A PORT FOR A SPECIFIC REASON,
# BUT YOU SHOULD REALIZE THAT ANY SERVICE LISTED HERE ALLOWS
# SOMEBODY TO GET INTO YOUR MACHINE!!!
#######################################################################

# ping/echo
iptables -A INPUT -i $EXTIF -p tcp -s $UNIVERSE -d $EXTIP \
   --dport 7 -j ACCEPT
iptables -A INPUT -i $EXTIF -p udp -s $UNIVERSE -d $EXTIP \
   --dport 7 -j ACCEPT

# GOOD IF YOU ARE RUNNING A WEB SERVER
#iptables -A INPUT -i $EXTIF -p tcp -s $UNIVERSE -d $EXTIP \
#  --dport 80 -j ACCEPT
#iptables -A INPUT -i $EXTIF -p udp -s $UNIVERSE -d $EXTIP \
#  --dport 80 -j ACCEPT

# GOOD IF YOU ARE RUNNING AN FTP SERVER
#iptables -A INPUT -i $EXTIF -p tcp -s $UNIVERSE -d $EXTIP \
#  --dport 20:21 -j ACCEPT
#iptables -A INPUT -i $EXTIF -p udp -s $UNIVERSE -d $EXTIP \
#  --dport 21 -j ACCEPT

# NFS (Network File System) server
# YOU NEED RPC PORTMAPPER (portmap), rpc.statd???, nlockmgr???, 
# rpc.mountd??? (these last 3 have changing port numbers!!!)
# NFS is a COMPLETE MESS!!!  Firewall+NFS = oil+water
#iptables -A INPUT -i $EXTIF -p tcp -s $UNIVERSE -d $EXTIP \
#  --dport 2049 -j ACCEPT
#iptables -A INPUT -i $EXTIF -p udp -s $UNIVERSE -d $EXTIP \
#  --dport 2049 -j ACCEPT

# RPC Portmapper (portmap)
#iptables -A INPUT -i $EXTIF -p tcp -s $UNIVERSE -d $EXTIP \
#  --dport 111 -j ACCEPT
#iptables -A INPUT -i $EXTIF -p udp -s $UNIVERSE -d $EXTIP \
#  --dport 111 -j ACCEPT

# NETBIOS (SMB=samba Windows networking)
#iptables -A INPUT -i $EXTIF -p tcp -s $UNIVERSE -d $EXTIP \
#  --dport 137:139 -j ACCEPT
#iptables -A INPUT -i $EXTIF -p udp -s $UNIVERSE -d $EXTIP \
#  --dport 137:139 -j ACCEPT
#iptables -A INPUT -i $EXTIF -p tcp -s $UNIVERSE -d $EXTIP \
#  --dport 445 -j ACCEPT
#iptables -A INPUT -i $EXTIF -p udp -s $UNIVERSE -d $EXTIP \
#  --dport 445 -j ACCEPT

# GOOD IF YOU ARE RUNNING AN SSL WEB SERVER
#iptables -A INPUT -i $EXTIF -p tcp -s $UNIVERSE -d $EXTIP \
#  --dport 443 -j ACCEPT
#iptables -A INPUT -i $EXTIF -p udp -s $UNIVERSE -d $EXTIP \
#  --dport 443 -j ACCEPT

# rsync
#iptables -A INPUT -i $EXTIF -p tcp -s $UNIVERSE -d $EXTIP \
#  --dport 873 -j ACCEPT
#iptables -A INPUT -i $EXTIF -p udp -s $UNIVERSE -d $EXTIP \
#  --dport 873 -j ACCEPT

# ident/auth (YOU PROBABLY DON'T NEED THIS
# YOU NEED BOTH INCOMING AND OUTGOING
#iptables -A INPUT -i $EXTIF -p tcp -s $UNIVERSE -d $EXTIP \
#  --dport 113 -j ACCEPT
#iptables -A INPUT -i $EXTIF -p udp -s $UNIVERSE -d $EXTIP \
#  --dport 113 -j ACCEPT

# incoming ssh connections
iptables -A INPUT -i $EXTIF -p tcp -s $UNIVERSE -d $EXTIP \
   --dport 22 -j ACCEPT

# incoming SSH connections (with restrictions)
### restricts to 3 "burst", then once per minute
#iptables -A INPUT -m tcp -p tcp --dport 22 -m state --state \
#  ESTABLISHED,RELATED -j ACCEPT
### uncomment the next line to put no restrictions on IP range 10.1.0.0/24
# iptables -A INPUT -m tcp -p tcp -s 10.1.0.0/24 --dport 22 -j ACCEPT
#iptables -A INPUT -m tcp -p tcp --dport 22 -m state --state NEW -m limit \
#  --limit 1/min --limit-burst 3 -j ACCEPT
#iptables -A INPUT -m tcp -p tcp --dport 22 -j DROP

# ntp (NETWORK TIME PROTOCOL)
#iptables -A INPUT -i $EXTIF -p tcp -s $UNIVERSE -d $EXTIP \
#   --dport 123 -j ACCEPT
#iptables -A INPUT -i $EXTIF -p udp -s $UNIVERSE -d $EXTIP \
#   --dport 123 -j ACCEPT

# eDonkey2000
# NEED BOTH INCOMING AND OUTGOING
#iptables -A INPUT -i $EXTIF -p tcp -s $UNIVERSE -d $EXTIP \
#   --dport 4661:4662 -j ACCEPT
#iptables -A INPUT -i $EXTIF -p udp -s $UNIVERSE -d $EXTIP \
#   --dport 4665:4666 -j ACCEPT

# OverNET
# NEED BOTH INCOMING AND OUTGOING
#iptables -A INPUT -i $EXTIF -p tcp -s $UNIVERSE -d $EXTIP \
#   --dport 4953 -j ACCEPT
#iptables -A INPUT -i $EXTIF -p udp -s $UNIVERSE -d $EXTIP \
#   --dport 4953 -j ACCEPT

# BitTorrent
# NEED BOTH INCOMING AND OUTGOING
#iptables -A INPUT -i $EXTIF -p tcp -s $UNIVERSE -d $EXTIP \
#   --dport 6881:6889 -j ACCEPT
#iptables -A INPUT -i $EXTIF -p tcp -s $UNIVERSE -d $EXTIP \
#   --dport 6969 -j ACCEPT

# Windows Media Player
# NEED BOTH INCOMING AND OUTGOING
#iptables -A INPUT -i $EXTIF -p tcp -s $UNIVERSE -d $EXTIP \
#   --dport 1755 -j ACCEPT
#iptables -A INPUT -i $EXTIF -p tcp -s $UNIVERSE -d $EXTIP \
#   --dport 1755 -j ACCEPT

# RealPlayer Audio
# NEED BOTH INCOMING AND OUTGOING
#iptables -A INPUT -i $EXTIF -p tcp -s $UNIVERSE -d $EXTIP \
#   --dport 554 -j ACCEPT
#iptables -A INPUT -i $EXTIF -p tcp -s $UNIVERSE -d $EXTIP \
#   --dport 7070 -j ACCEPT
#iptables -A INPUT -i $EXTIF -p tcp -s $UNIVERSE -d $EXTIP \
#   --dport 6970:7170 -j ACCEPT


# ADD MORE INCOMING SERVICES HERE

# Catch all rule, all other incoming is denied and logged. 
iptables -A INPUT -s $UNIVERSE -d $UNIVERSE -j drop-and-log-it


echo -e "     - Loading OUTPUT rulesets"

#######################################################################
# OUTPUT: Outgoing traffic from various interfaces.  All rulesets are 
#         already flushed and set to a default policy of DROP. 
#

# loopback interface is valid.
iptables -A OUTPUT -o lo -j ACCEPT

# THIS ALLOWS ANYTHING OUT
# IF YOU ARE PARANOID THEN YOU CAN COMMENT THIS OUT
# AND MANUALLY SELECT FROM THE LIST BELOW
iptables -A OUTPUT -o $EXTIF -s $EXTIP -d $UNIVERSE -j ACCEPT

# This is necessary for basic network functionality
iptables -A OUTPUT -o $EXTIF -p icmp -s $EXTIP -d $UNIVERSE -j ACCEPT

######################################################################## 
# HERE ARE THE OUTGOING SERVICES THAT ARE ALLOWED.  YOU MAY ADD
# MORE IF YOU NEED TO OPEN UP A PORT FOR A SPECIFIC REASON
#######################################################################

# ALLOW ALREADY ESTABLISHED CONNECTIONS OUT
iptables -A OUTPUT -o $EXTIF -s $EXTIP -d $UNIVERSE \
  -m state --state ESTABLISHED,RELATED -j ACCEPT

# IN CASE YOU WANT TO REDIRECT WEB TRAFFIC TO A PROXY
# Here the Squid server operates as user "proxy" on port 3128
# and the Dansguardian server operates as user "dansguardian" on port 8080
#### OPEN UP DANSGUARDIAN PORT
#iptables -A OUTPUT -p tcp --dport 8080 -j ACCEPT
#### ALLOW SQUID TO SEND TRAFFIC TO THE INTERNET
#iptables -t nat -A OUTPUT -p tcp \
#   --dport 80 -m owner --uid-owner proxy -j ACCEPT
#### LET DANSGUARDIAN TALK TO SQUID 
#iptables -t nat -A OUTPUT -p tcp \
#   --dport 3128 -m owner --uid-owner dansguardian -j ACCEPT
#### CHANGE "EXEMPT_USER" TO MATCH ANY EXEMPT USERS (E.G. PARENT)
#iptables -t nat -A OUTPUT -p tcp \
#   --dport 80 -m owner --uid-owner EXEMPT_USER -j ACCEPT
#### REDIRECT PORT 80 TO DANSGUARDIAN
#iptables -t nat -A OUTPUT -p tcp \
#   --dport 80 -j REDIRECT --to-ports 8080
#### DON'T LET ANYBODY ELSE BYPASS DANSGUARDIAN AND TALK DIRECTLY TO SQUID
#iptables -t nat -A OUTPUT -p tcp \
#   --dport 3128 -j REDIRECT --to-ports 8080

# ALLOW ARBITRARY OUTGOING CONNECTIONS TO "HIGH" PORT NUMBERS
iptables -A OUTPUT -o $EXTIF -p tcp -s $EXTIP -d $UNIVERSE \
   --dport 1024:65535 -j ACCEPT

# DNS requests
iptables -A OUTPUT -o $EXTIF -p tcp -s $EXTIP -d $UNIVERSE \
   --dport 53 -j ACCEPT
iptables -A OUTPUT -o $EXTIF -p udp -s $EXTIP -d $UNIVERSE \
   --dport 53 -j ACCEPT

# ping/echo
iptables -A OUTPUT -o $EXTIF -p tcp -s $EXTIP -d $UNIVERSE \
   --dport 7 -j ACCEPT
iptables -A OUTPUT -o $EXTIF -p udp -s $EXTIP -d $UNIVERSE \
   --dport 7 -j ACCEPT

# http
iptables -A OUTPUT -o $EXTIF -p tcp -s $EXTIP -d $UNIVERSE \
   --dport 80 -j ACCEPT
iptables -A OUTPUT -o $EXTIF -p udp -s $EXTIP -d $UNIVERSE \
   --dport 80 -j ACCEPT

# https
iptables -A OUTPUT -o $EXTIF -p tcp -s $EXTIP -d $UNIVERSE \
   --dport 443 -j ACCEPT
iptables -A OUTPUT -o $EXTIF -p udp -s $EXTIP -d $UNIVERSE \
   --dport 443 -j ACCEPT

# ftp
iptables -A OUTPUT -o $EXTIF -p tcp -s $EXTIP -d $UNIVERSE \
   --dport 20:21 -j ACCEPT
iptables -A OUTPUT -o $EXTIF -p udp -s $EXTIP -d $UNIVERSE \
   --dport 21 -j ACCEPT

# NFS (Network File System)
# You need RPC Portmapper (portmap) and the services
# rpc.statd???, nlockmgr???, rpc.mountd??? (the last 3
# have changing port numbers!!!).  NFS is a COMPLETE mess!
# NFS+Firewall = hell
#iptables -A OUTPUT -o $EXTIF -p tcp -s $EXTIP -d $UNIVERSE \
#   --dport 2049 -j ACCEPT
#iptables -A OUTPUT -o $EXTIF -p udp -s $EXTIP -d $UNIVERSE \
#   --dport 2049 -j ACCEPT

# RPC Portmapper (portmap)
#iptables -A OUTPUT -o $EXTIF -p tcp -s $EXTIP -d $UNIVERSE \
#   --dport 111 -j ACCEPT
#iptables -A OUTPUT -o $EXTIF -p udp -s $EXTIP -d $UNIVERSE \
#   --dport 111 -j ACCEPT

# NETBIOS ports (SMB=samba Windows networking)
#iptables -A OUTPUT -o $EXTIF -p tcp -s $EXTIP -d $UNIVERSE \
#   --dport 137:139 -j ACCEPT
#iptables -A OUTPUT -o $EXTIF -p udp -s $EXTIP -d $UNIVERSE \
#   --dport 137:139 -j ACCEPT
#iptables -A OUTPUT -o $EXTIF -p tcp -s $EXTIP -d $UNIVERSE \
#   --dport 445 -j ACCEPT
#iptables -A OUTPUT -o $EXTIF -p udp -s $EXTIP -d $UNIVERSE \
#   --dport 445 -j ACCEPT

# outgoing ssh
iptables -A OUTPUT -o $EXTIF -p tcp -s $EXTIP -d $UNIVERSE \
   --dport 22 -j ACCEPT

# ident/auth (you probably need this)
# YOU WILL NEED INCOMING udp as well (see above)
iptables -A OUTPUT -o $EXTIF -p tcp -s $EXTIP -d $UNIVERSE \
   --dport 113 -j ACCEPT
iptables -A OUTPUT -o $EXTIF -p udp -s $EXTIP -d $UNIVERSE \
   --dport 113 -j ACCEPT

# ntp (Network Time Protocol)
# YOU WILL NEED THE INCOMING udp 123 at LEAST as well (see above)
#iptables -A OUTPUT -o $EXTIF -p tcp -s $EXTIP -d $UNIVERSE \
#   --dport 123 -j ACCEPT
#iptables -A OUTPUT -o $EXTIF -p udp -s $EXTIP -d $UNIVERSE \
#   --dport 123 -j ACCEPT

# rsync
#iptables -A OUTPUT -o $EXTIF -p tcp -s $EXTIP -d $UNIVERSE \
#   --dport 873 -j ACCEPT
#iptables -A OUTPUT -o $EXTIF -p udp -s $EXTIP -d $UNIVERSE \
#   --dport 873 -j ACCEPT

# AOL instant messenger
#iptables -A OUTPUT -o $EXTIF -p tcp -s $EXTIP -d $UNIVERSE \
#   --dport 5190:5193 -j ACCEPT
#iptables -A OUTPUT -o $EXTIF -p udp -s $EXTIP -d $UNIVERSE \
#   --dport 5190:5193 -j ACCEPT

# eDonkey2000
# UDP protocol NEEDS BOTH INCOMING AND OUTGOING
#iptables -A OUTPUT -o $EXTIF -p tcp -s $EXTIP -d $UNIVERSE \
#   --dport 4661:4662 -j ACCEPT
#iptables -A OUTPUT -o $EXTIF -p udp -s $EXTIP -d $UNIVERSE \
#   --dport 4665:4666 -j ACCEPT

# OverNET
# UDP NEEDS BOTH INCOMING AND OUTGOING
#iptables -A OUTPUT -o $EXTIF -p tcp -s $EXTIP -d $UNIVERSE \
#   --dport 4953 -j ACCEPT
#iptables -A OUTPUT -o $EXTIF -p udp -s $EXTIP -d $UNIVERSE \
#   --dport 4953 -j ACCEPT

# BitTorrent
#iptables -A OUTPUT -o $EXTIF -p tcp -s $EXTIP -d $UNIVERSE \
#   --dport  6881:6889 -j ACCEPT
#iptables -A OUTPUT -o $EXTIF -p tcp -s $EXTIP -d $UNIVERSE \
#   --dport 6969 -j ACCEPT

# Windows Media Player
# UDP NEEDS BOTH INCOMING AND OUTGOING
#iptables -A OUTPUT -o $EXTIF -p tcp -s $EXTIP -d $UNIVERSE \
#   --dport  1755 -j ACCEPT
#iptables -A OUTPUT -o $EXTIF -p tcp -s $EXTIP -d $UNIVERSE \
#   --dport 1755 -j ACCEPT

# RealPlayer Audio
# NEED BOTH INCOMING AND OUTGOING
#iptables -A OUTPUT -o $EXTIF -p tcp -s $EXTIP -d $UNIVERSE \
#   --dport  554 -j ACCEPT
#iptables -A OUTPUT -o $EXTIF -p tcp -s $EXTIP -d $UNIVERSE \
#   --dport  7070 -j ACCEPT
#iptables -A OUTPUT -o $EXTIF -p tcp -s $EXTIP -d $UNIVERSE \
#   --dport 6970:7170 -j ACCEPT


# ADD MORE OUTGOING SERVICES HERE

# Catch all rule, all other outgoing is denied and logged. 
iptables -A OUTPUT -s $UNIVERSE -d $UNIVERSE -j drop-and-log-it

Router and Firewall

The rest of this document will deal with a machine with TWO INTERFACES meant to glue together separate networks. Please note that I only used the firewall for a day, so I cannot comment on its reliability or speed (DNSMASQ seemed pretty slow in name resolution, actually).

Here is the setup: I have a Debian box that has two network cards - one an "external" card linking to the outside world, and another an "internal" card linking to my LAN. I wanted to set this box to be a DHCP server (automatically assign IP addresses to computers added on the LAN), and I wanted this machine to act as a simple DNS - e.g. manage names on the LAN and forward name lookups to the internet if not found on the LAN. Finally, I wanted to (obviously) forward traffic between the two cards so that the LAN can see the internet.

The "industrial-grade" way of handling this is to use the "dhcpd" server and the big DNS utility "bind". I didn't want to go this route since it seems like overkill, although it would've been a good learning experience (I have other things to learn right now). The alternative is to use a neat little utility called "dnsmasq" - this simple little utility does *almost* everything that I want, so that's the choice (I'm still unhappy with the name resolution for computers on the LAN, but I can live with it).

Getting the kernel to use multiple ethernet cards
It was already difficult enough to figure out that the kernel doesn't automatically sense every ethernet card in the box. You need to TELL the kernel to use all of the cards explicitly. In my case, when running "lspci" I found the lines

Ethernet controller: Realtek Semiconductor Co., Ltd. RTL-8169 Gigabit Ethernet (rev 10)
Ethernet controller: VIA Technologies, Inc. VT6102 [Rhine-II] (rev 74)

After poking around in /lib/modules I found that the appropriate drivers were "r8169" and "via_rhine" - so I put both of those entries in /etc/modules (this file just forces the kernel to load these modules explicitly). I have no idea how to control which becomes eth0 and which becomes eth1 (I tried adding aliases - that didn't work). Anyway, I found that my via_rhine became eth1 and my r8169 became eth0 (and it was consistent reboot after reboot after reboot) so I just learned to live with it (if anybody can tell me how to force the eth0/eth1 naming then I'd be much obliged). If the drivers are compiled in the kernel then you need to pass a kernel argument when booting from grub or lilo such as "ether=0,0,eth0 ether=0,0,eth1". I'm using modules so I can't speak from experience.

Now my eth0 will be my INTERNAL card and my eth1 will be my EXTERNAL card. How you connect your EXTERNAL card to the internet will vary widely - many will probably use ADSL with PPPoE or something similar. In my case I actually can push out to my ISP a DHCP request - so my firewall becomes a DHCP *client* on the EXTERNAL interface (like the way your computer normally gets on a network). This has nothing to do with the fact that I am trying to set up a DHCP *server* on my INTERNAL network. To get both interfaces up I have the following lines in /etc/network/interfaces (yours will probably be similar)

auto lo eth0 eth1

iface lo inet loopback

mapping eth1
		script grep
		map eth1
		
allow-hotplug eth1
iface eth1 inet dhcp		


This just tells my "eth1" (EXTERNAL card) to get its IP address from my ISP using a DHCP client request. Your script will probably be something similar - this isn't important (I just wrote it down for comparison). Note that I added the "eth0" in the "auto" line in anticipation of the following lines also added to bring up the INTERNAL interface:

iface eth0 inet static
		address 192.168.0.254
		netmask 255.255.255.0		


This statically sets my INTERNAL card to the address 192.168.0.254 (obviously I have chosen the 192.168.0.XXX subnet for my LAN - make sure that your EXTERNAL IP address and your INTERNAL LAN addresses don't conflict, i.e. if you get an EXTERNAL IP of 192.168.0.13 from your ISP then this subnet choice would be disastrous). A reboot will probably be necessary for the changes to occur (by the way, this is also how you would set up a static IP address even for a regular machine if you so desired. The only thing to add after the netmask line is a "gateway XXX.XXX.XXX.XXX" line to specify the gateway where traffic to/from the outside world should be routed).

If you want to play around and check thinks out manually then use "ifconfig". For example just typing "ifconfig" will list all interfaces that are UP - useful for debugging. You can manually assign eth0 to 192.168.0.254 by typing "ifconfig eth0 192.168.0.254 up", for example.

Setting up DNSMASQ as a DHCP and DNS service
Now you can install "dnsmasq" through apt-get if you like Debian. The relevant configuration file is located in "/etc/dnsmasq.conf". It's pretty self-explanatory, but I'll mention the relevant entries here (I assume that my domain is called "localdomain" - bad idea, I know).

# set up the local domain
local=/localdomain/
domain=localdomain

# limit DHCP requests to this INTERNAL interface
interface=eth1

# nice so that you don't have to use fully qualified names - tacks
# on that localdomain for you
expand-hosts

# set the DHCP ranges to assign
dhcp-range=192.168.0.50,192.168.0.150,12h

# MANUALLY set hostnames on the network using the hardware MAC address
# for each host
# if you don't care about referring to a computer by name then this isn't
# necessary
dhcp-host=00:20:E0:6B:C4:EA,charlene,192.168.0.50
dhcp-host=00:40:E7:6B:C4:EA,greasyspoon,192.168.0.51


Now you should add each host in "/etc/hosts" by name as well

192.168.0.50	charlene
192.168.0.51	greasyspoon


This allows the firewall to ALSO refer to these computers by name. Note that I have not found a way to just have the DHCP server grab the hostname and automatically update its DNS information on the fly - it's all manual here. This has cost me a lot of time and patience - maybe "dhcpd" and "bind" can do it. (Please note that "dhcpd" and "dhcpcd" are TWO DIFFERENT PACKAGES - one is the DHCP server, another is just a client).

Gluing the two interfaces together
Now it's time to actually forward TCP/IP traffic (you already forwarded DNS name resolution, but no actual traffic can get through yet). This is done using an IPTABLES set of rules. To learn about the "iptables" command you should consult this website... it's quite instructive.

Here's a script that just acts as a pass-through - you should only use it for testing purposes since there are NO firewalling rules whatsoever here.

#!/bin/sh

# Just a straight-through gluing script - for testing ONLY
# Here I'll assume the the interfaces are already "up"
# this merely adds FORWARDING rules

echo -e "\n\nSETTING UP IPTABLES FORWARDER..."


# SET THE INTERFACE DESIGNATION FOR THE NIC CONNECTED TO YOUR INTERNAL NETWORK
INTIF="eth0"


# SET THE INTERFACE DESIGNATION FOR YOUR "EXTERNAL" (INTERNET) CONNECTION
EXTIF="eth1"

echo 1 > /proc/sys/net/ipv4/ip_forward

# Clearing any existing rules and setting default policy
iptables -P INPUT ACCEPT
iptables -F INPUT 
iptables -P OUTPUT ACCEPT
iptables -F OUTPUT 
iptables -P FORWARD DROP
iptables -F FORWARD 
iptables -t nat -F

# FWD: Allow all connections OUT and only existing and related ones IN
iptables -A FORWARD -i $EXTIF -o $INTIF -m state \
  --state ESTABLISHED,RELATED -j ACCEPT
iptables -A FORWARD -i $INTIF -o $EXTIF -j ACCEPT

# Enabling SNAT (MASQUERADE) functionality on $EXTIF
iptables -t nat -A POSTROUTING -o $EXTIF -j MASQUERADE

echo -e "       Proxy server rule loading complete\n\n"

Really you will need to add some IPTABLES firewall rules to keep the bad guys out. For something a little more sturdy you could start with this: Note the built-in support for transparent web proxying and web filtering! Give it a try - you'll love it.

#!/bin/sh

#  SAMPLE IPTABLES  FIREWALL  script
#  Again, I'm assuming that both interfaces are "up"

echo -e "\n\nSETTING UP IPTABLES FIREWALL..."


# SET THE INTERFACE DESIGNATION AND ADDRESS AND NETWORK ADDRESS
# FOR THE NIC CONNECTED TO YOUR _INTERNAL_ NETWORK
# Enter the designation for the Internal Interface's
INTIF="eth1"
# Enter the NETWORK address the Internal Interface is on
INTNET="192.168.200.0/24"
# Enter the IP address of the Internal Interface
INTIP="192.168.200.254"



# SET THE INTERFACE DESIGNATION FOR YOUR "EXTERNAL" (INTERNET) CONNECTION
EXTIF="eth0"
EXTIP="`/sbin/ifconfig $EXTIF | grep 'inet addr' \
  | awk '{print $2}' | sed -e 's/.*://'`"


UNIVERSE="0.0.0.0/0"

echo 1 > /proc/sys/net/ipv4/ip_forward

# Clear any existing rules and setting default policy to DROP
iptables -P INPUT DROP
iptables -F INPUT 
iptables -P OUTPUT DROP
iptables -F OUTPUT 
iptables -P FORWARD DROP
iptables -F FORWARD 
iptables -F -t nat

# Flush the user chain.. if it exists
if [ "`iptables -L | grep drop-and-log-it`" ]; then
   iptables -F drop-and-log-it
fi

# Delete all User-specified chains
iptables -X

# Reset all IPTABLES counters
iptables -Z

# Creating a DROP chain
iptables -N drop-and-log-it
iptables -A drop-and-log-it -j LOG --log-level info 
iptables -A drop-and-log-it -j REJECT

echo -e "     - Loading INPUT rulesets"

#######################################################################
# INPUT: Incoming traffic from various interfaces.  All rulesets are 
#        already flushed and set to a default policy of DROP. 
#

# TRUST ANYTHING COMING IN ON LOOPBACK
iptables -A INPUT -i lo -j ACCEPT

# remote interface, claiming to be local machines, IP spoofing, get lost
iptables -A INPUT -i $EXTIF -s $INTNET -d $UNIVERSE -j drop-and-log-it

# these are necessary for basic networking functionality
iptables -A INPUT -i $INTIF -p icmp -s $INTNET -d $UNIVERSE -j ACCEPT
iptables -A INPUT -i $EXTIF -p icmp -s $UNIVERSE -d $EXTIP -j ACCEPT

 
# THIS ALLOWS ANY TRAFFIC TO COME IN ON THE INTERNAL
# CARD - THIS IS PROBABLY TOO LENIENT.  THE RULES BELOW
# ARE MORE SELECTIVE 
#iptables -A INPUT -i $INTIF -s $INTNET -d $UNIVERSE -j ACCEPT

#############################################################
# HERE ARE RULES FOR WHICH TRAFFIC ORIGINATING ON THE LOCAL
# NETWORK IS ALLOWED TO ACCESS THE FIREWALL ITSELF - 
# THIS HAS NOTHING TO DO WITH WHAT IS FORWARDED THROUGH!!!
#############################################################

# Allow any related traffic coming back to the MASQ server in
iptables -A INPUT -i $INTIF -s $INTNET -d $INTIP -m state \
  --state ESTABLISHED,RELATED -j ACCEPT

# ping/echo
iptables -A INPUT -i $INTIF -p tcp -s $INTNET -d $UNIVERSE --dport 7 -j ACCEPT
iptables -A INPUT -i $INTIF -p udp -s $INTNET -d $UNIVERSE --dport 7 -j ACCEPT

# DNS requests
iptables -A INPUT -i $INTIF -p tcp -s $INTNET -d $UNIVERSE --dport 53 -j ACCEPT
iptables -A INPUT -i $INTIF -p udp -s $INTNET -d $UNIVERSE --dport 53 -j ACCEPT

# ident/auth
#iptables -A INPUT -i $INTIF -p tcp -s $INTNET -d $UNIVERSE \
#  --dport 113 -j ACCEPT
#iptables -A INPUT -i $INTIF -p udp -s $INTNET -d $UNIVERSE \
#  --dport 113 -j ACCEPT

# ssh
#iptables -A INPUT -i $INTIF -p tcp -s $INTNET -d $UNIVERSE \
#  --dport 22 -j ACCEPT
  
# UNCOMMENT THIS STANZA FOR WEB CACHE/PROXY SUPPORT
# USING A DANSGUARDIAN/SQUID SETUP
#iptables -A INPUT -i $INTIF -p tcp --dport 8080 -j ACCEPT
# Redirect port 80 to Dansguardian (port 8080)
#iptables -t nat -A PREROUTING -i $INTIF -p tcp \
#   --dport 80 -j REDIRECT --to-ports 8080

 
# THIS ALLOWS ANYTHING TO COME IN ON THE EXTERNAL INTERFACE.
# THIS IS OBVIOUSLY UNACCEPTABLE.  UNCOMMENT ONLY FOR TESTING
# PURPOSES
#iptables -A INPUT -i $EXTIF -s $UNIVERSE -d $EXTIP -j ACCEPT

#############################################################
# HERE ARE RULES FOR WHICH *INBOUND* TRAFFIC IS ALLOWED
# ON THE EXTERNAL INTERFACE - THIS IS THE CRITICAL PART!!!
# ANY SERVICE SPECIFIED HERE MUST BE EITHER PROVIDED BY 
# THE FIREWALL ITSELF, OR THE PORT MUST BE FORWARDED TO
# SOME SPECIFIC MACHINE ON THE INTERNAL LAN
# SEE BOTTOM OF SCRIPT FOR PORT FORWARDING EXAMPLE
#############################################################

# Allow any related traffic coming back to the MASQ server in
iptables -A INPUT -i $EXTIF -s $UNIVERSE -d $EXTIP -m state \
  --state ESTABLISHED,RELATED -j ACCEPT

# ping/echo
iptables -A INPUT -i $EXTIF -p tcp -s $UNIVERSE \
  -d $EXTIP --dport 7 -j ACCEPT
iptables -A INPUT -i $EXTIF -p udp -s $UNIVERSE \
  -d $EXTIP --dport 7 -j ACCEPT

# ident/auth
#iptables -A INPUT -i $EXTIF -p tcp -s $UNIVERSE \
#  -d $EXTIP --dport 113 -j ACCEPT
#iptables -A INPUT -i $EXTIF -p udp -s $UNIVERSE \
#  -d $EXTIP --dport 113 -j ACCEPT

# ssh (no restrictions)
iptables -A INPUT -i $EXTIF -p tcp -s $UNIVERSE \
  -d $EXTIP --dport 22 -j ACCEPT
  
# SSH (restricted) to 3 burst attempts, then once per minute
#iptables -A INPUT -i $EXTIF -m tcp -p tcp --dport 22 -m state --state \
#  ESTABLISHED,RELATED -j ACCEPT
#iptables -A INPUT -i $EXTIF -m tcp -p tcp --dport 22 -m state --state \
#  NEW -m limit --limit 1/min --limit-burst 3 -j ACCEPT
#iptables -A INPUT -i $EXTIF -m tcp -p tcp --dport 22 -j DROP

# http
#iptables -A INPUT -i $EXTIF -p tcp -s $UNIVERSE \
#  -d $EXTIP --dport 80 -j ACCEPT
#iptables -A INPUT -i $EXTIF -p udp -s $UNIVERSE \
#  -d $EXTIP --dport 80 -j ACCEPT

####################################################
# SEE SCRIPT AT BEGINNING OF THIS WEBPAGE TO
# LOCATE MORE SERVICES THAT YOU MIGHT WANT

# ADD YOUR OWN RULES
#####################################################

# Catch all rule, all other incoming is denied and logged. 
iptables -A INPUT -s $UNIVERSE -d $UNIVERSE -j drop-and-log-it


echo -e "     - Loading OUTPUT rulesets"

#######################################################################
# OUTPUT: Outgoing traffic from various interfaces.  All rulesets are 
#         already flushed and set to a default policy of DROP. 
#

# YOU WILL PROBABLY NOT NEED TO MODIFY THE OUTGOING RULES
# UNLESS YOU REALLY WANT A BOMBPROOF FIREWALL

# outgoing to local net on remote interface, stuffed routing, deny
iptables -A OUTPUT -o $EXTIF -s $UNIVERSE -d $INTNET -j drop-and-log-it

# loopback is valid
iptables -A OUTPUT -o lo -j ACCEPT

# local interface, any source going to local net is valid
iptables -A OUTPUT -o $INTIF -d $INTNET -j ACCEPT

# anything else outgoing on remote interface is valid
iptables -A OUTPUT -o $EXTIF -j ACCEPT

# Catch all rule, all other outgoing is denied and logged. 
iptables -A OUTPUT -s $UNIVERSE -d $UNIVERSE -j drop-and-log-it


echo -e "     - Loading FORWARD rulesets"

#######################################################################
# FORWARD: Enable Forwarding and thus IPMASQ

################################################################
# ADD PORT FORWARDING RULES HERE
# ANY ENTRY HERE MUST HAVE A CORRESPONDING ENTRY IN THE
# "INPUT ON THE EXTERNAL INTERFACE" SECTION - SEE ABOVE
################################################################

# EXAMPLE FORWARD PORT 80 TO COMPUTER ON LAN WITH IP 192.168.200.5
# THIS comes in two sections.  Forward what comes in on the outside,
# and make a special exception to forward whatever originated
# on INTERNAL network BACK inside
#iptables -t nat -A PREROUTING -i $EXTIF -p tcp --dport 80 \
#  -j DNAT --to-destination 192.168.200.5
#iptables -A FORWARD -i $EXTIF -p tcp --dport 80 -j ACCEPT
#iptables -t nat -A PREROUTING -i $INTIF -p tcp -d $EXTIP --dport 80 \
#  -j DNAT --to-destination 192.168.200.5
#iptables -A FORWARD -i $INTIF -p tcp -d $EXTIP --dport 80 -j ACCEPT

#########################################################
# ADD YOUR RULES HERE FOR TRAFFIC THAT WILL BE
# FORWARDED FROM THE INTERNAL INTERFACE TO THE
# EXTERNAL INTERFACE - this is not as critical as
# the INCOMING filter above, but still worthwhile
#########################################################

# Enable (MASQUERADE) functionality on $EXTIF
iptables -t nat -A POSTROUTING -o $EXTIF -j MASQUERADE
iptables -t nat -A POSTROUTING -o $INTIF -j MASQUERADE

# this allows everything from inside to outside
# MAYBE too lenient, but maybe not.  If you are
# PARANOID THEN COMMENT THIS OUT and consider
# the rules below!!!
iptables -A FORWARD -i $INTIF -o $EXTIF -j ACCEPT

# allow any previously established traffic through
iptables -A FORWARD -i $EXTIF -o $INTIF -m state \
  --state ESTABLISHED,RELATED -j ACCEPT

# ICMP protocol necessary for ping, etc
iptables -A FORWARD -i $INTIF -p icmp -j ACCEPT

# high port numbers allowed out
iptables -A FORWARD -i $INTIF -p tcp --dport 1024:65535 -j ACCEPT
iptables -A FORWARD -i $INTIF -p udp --dport 1024:65535 -j ACCEPT

# ping/echo
iptables -A FORWARD -i $INTIF -p tcp --dport 7 -j ACCEPT
iptables -A FORWARD -i $INTIF -p udp --dport 7 -j ACCEPT

# DNS
iptables -A FORWARD -i $INTIF -p tcp --dport 53 -j ACCEPT
iptables -A FORWARD -i $INTIF -p udp --dport 53 -j ACCEPT

# ident/auth
iptables -A FORWARD -i $INTIF -p tcp --dport 113 -j ACCEPT
iptables -A FORWARD -i $INTIF -p udp --dport 113 -j ACCEPT

# ssh
iptables -A FORWARD -i $INTIF -p tcp --dport 22 -j ACCEPT
iptables -A FORWARD -i $INTIF -p udp --dport 22 -j ACCEPT

# http
iptables -A FORWARD -i $INTIF -p tcp --dport 80 -j ACCEPT
iptables -A FORWARD -i $INTIF -p udp --dport 80 -j ACCEPT

# https
iptables -A FORWARD -i $INTIF -p tcp --dport 443 -j ACCEPT
iptables -A FORWARD -i $INTIF -p udp --dport 443 -j ACCEPT

# ftp
iptables -A FORWARD -i $INTIF -p tcp --dport 20:21 -j ACCEPT
iptables -A FORWARD -i $INTIF -p udp --dport 21 -j ACCEPT

# Catch all rule, all other forwarding is denied and logged. 
iptables -A FORWARD -j drop-and-log-it


echo -e "    Firewall server rule loading complete\n\n"

I think that it is interesting to talk about Web proxies like Squid. A "proxy" can allow you to cache Web data (speeds up the internet) and, more importantly, control Web access on your LAN. For example, by using a Squid add-on such as SquidGuard or Dansguardian (recommended) you can even FILTER WEB CONTENT. Please see my Dansguardian/Squid HOWTO for more information.

This page has been visited   times since December 25, 2005