Dave Cater

Linux firewall

 
Home Page
Career outline
Java
Linux
Linux references
Linux Mandrake
Linux Red Hat
Linux kernel upgrade
Linux Internet connection
Linux firewall
Linux projects
Security
Perl
System management
Testing
Musical notes
This article describes how to create a Linux firewall from scratch using IP packet filtering built into the kernel.

For other notes on design and testing of firewalls in general, refer to Security - firewalls.

There are several IP packet filtering methods for Linux - ipfw, ipchains and iptables. I used ipchains(8) originally, as it was available for my version of Linux (kernel version 2.2). Subsequently I rewrote the firewall using iptables after I had upgraded to kernel version 2.4. Also ipchains is similar to, but newer than, ipfw.

I started by following various articles on ipchains which covered the basics of the input, output and forwarding chains. Each chain is a series of rules you create to determine what happens to packets received by a network interface (input) sent out from a network interface (output) or forwarded from one network interface to another (eg. from an external dial-up connection using ppp0 to an internal LAN using eth0). Packets which do not match any rule in the chain are handled according to a policy (in my case, simply rejected).

I was optimistic that a firewall could be written by a few simple commands to set the policy to reject input packets and allow only those associated with local connections from the loopback device (lo) and the PPP device (ppp0).

I dialed my ISP, then phoned a friend supplying the IP address dynamically allocated (shown in /var/log/messages) with an invitation to try to break into my Apache WWW server. Within a few seconds he managed to connect. Time to try again.

With quite a lot of suggestions from my friend and further study of ipchains, we put together a firewall which worked as follows:

  • Flush the input, output and forwarding chains.
  • The policy for the input, output and forwarding chains is set to DENY.
  • Add rules to allow ICMP and traceroute packets.
  • Add rules to input and output chains to accept packets from/to the loopback device (lo).
  • A port range for ephemeral ports is explicitly created.
  • Add rule to output chain to allow UDP packets from the ppp+ device with source port in the ephemeral port range. Add rule to input chain to allow UDP packets to the ppp+ device with destination port in the ephemeral port range. As local servers do not listen on ephemeral ports (only on "well-known" ports) this prevents external UDP packets being sent to local servers (ppp+ means ppp0, ppp1, etc).
  • Similarly add rules to allow TCP packets from/to the ppp+ device. A neat trick here is to exclude "SYN" packets on input using the "! -y" command. This prevents reply packets from attempting malicious connections.
  • Add rules to log packets which don't match any previous rule as they are potentially malicious. The log file is /var/log/messages
  • It is easy to add rules to allow input/output packets for a specific well-known destination port (eg. port 80 to allow external connections to a WWW server).
  • A cautionary note: the above rules do not prevent a malicious local process (a trojan) from making connections to the Internet. Even if we restrict connections to well-known ports, a trojan could still connect to a malicious server.
  • Finally the required commands are put in a script rc.fwsetup which is placed in /etc/rc.d (for Mandrake/Red Hat Linux) and sourced on system startup. The script includes comment lines which are understood by chkconfig(8) so running chkconfig creates all required lines in the /etc directories for each run level where we want the firewall to be running.