Why firewall your laptop? There are several reasons, not least of which is to prevent unauthorised access to your computer. You probably also don't want packets being sent accidentally from your computer out across the Internet; not only does this give away information about your setup, potentially making it easier to crack, it can also interfere with the operation of other people's computers and incur the wrath of your ISP.

Read on...

Linux has built-in support for firewalling in it's kernel routing code. In this article we'll be covering the use of a tool called ipchains in setting up a basic firewall suitable for a laptop or single workstation.

First of all, you need to make sure that your kernel has been compiled with the correct options. If you're using a stock LinuxPPC or YellowDog kernel, you should have no problems. If you roll your own, make sure that IP networking is enabled along with IP forwarding.

The ipchains tool is included on the LinuxPPC distribution CD; you can also download it from ; just click on the 'Index by Name' link, 'packages beginning with I' and then select ipchains.

Once you have the package installed, you need to set up the firewall rules. First, a brief introduction into the way Linux firewalling code works. As packets are received on the various interfaces, they are compared against the rules that you specify. These rules are organised by default into three groups and analysed sequentially; this is why the groups are called 'chains'. The 3 default chains, in the order they are traversed, are input, forward and output. You can specify other chains; that's more advanced than necessary here however.

Each rule can be as general or as specific as necessary. For example a rule could say 'any packet from the 10.0.0.0 network must be dropped'; another could say 'any TCP packet from 192.168.0.2 port 8080 to 192.168.0.3 port 80 must be accepted'. For each packet, each chain is traversed until the first matching rule is found. This is important; a packet may never leave the input chain, so allowing it in the output chain will have no effect. Also, denying or rejecting a packet near the start of the chain means that a rule which will accept the packet should be placed before the rule that denies it. Confused? I'm not surprised!

The basic firewall I'm showing here will allow a minimum of traffic in and out, and restricts FTP access to passive-mode FTP. Most internet protocols are included here; specific ones such as game protocols are not, due to a) the large number of differing protocols used and b) the difficulty in securing a lot of these protocols. This firewall will allow DNS, web, secure web, SSH, telnet, SMTP, POP3 and IMAP connections outwards; no inward connections can be made. All but web, ssl, ssh and telnet must be made to specific servers only. If, for example, you need to access two POP3 servers, just duplicate the rules for the POP3 server and add another 'export' entry for the server; e.g.

export imapIP2="your.2nd.IMAP.server"

Let's get down to the script for this basic firewall, which I've broken into parts to ease readability. I usually call this script /etc/ppp/ip-up.local, which is executed by /etc/ppp/ip-up when the internet connection has been started.

#!/bin/sh
# Set up some constants to help readability and alteration
export extIP="your.external.IP.address"
export extIF="eth0" # or ppp0 for dialup IP
export anyIP="0.0.0.0/0"
export dnsIP="your.isps.dns.here"
export pop3IP="your.isps.POP3.server"
export imapIP="your.isps.IMAP.server"
export smtpIP="your.isps.SMTP.server"
export unpriv="1024:65535"

This code allows alterations to the network, for example the IP address your ISP is using for it's DN server, to be easily altered. The addresses should either be specified using dotted-decimal (e.g. 1.2.3.4) notation, or by using a domain name (e.g. pop3.iinet.net.au). Note that unless you have an entry in your /etc/hosts file for it, using a domain name for the DN server is a really bad idea!

Also, if you are using PPP, which you probably will be if you're using a laptop, you can automate filling in the interface name and IP. The script /etc/ppp/ip-up is executed with various options, and you can modify it to pass these to /etc/ppp/ip-up.local . The positional parameters in question are $1 for extIF and $4 for the local IP. The line in /etc/ppp/ip-up would be:

. /etc/ppp/ip-up.local $1 $4

and in the above script use the following export commands:

export extIP=$2
export extIF=$1

Do note though that the scripts provided with your distro may vary.

# Flush rules and establish deny-all policy
ipchains -F
ipchains -P input -j DENY
ipchains -P output -j DENY
ipchains -P forward -j DENY

# Enable loopback
ipchains -A input -i lo -s 127.0.0.0/8 -j ALLOW
ipchains -A output -i lo -s 127.0.0.0/8 -j ALLOW

To start with, we want to drop all packets that aren't explicitly accepted by the firewall rules below. Why? Mostly because the other type of firewall, an accept-everything router, is very hard to secure. It's easier to close everything off and then start allowing the services we know we want.

# Drop a couple of obvious spoofs.
ipchains -A input -i ! lo -s 127.0.0.0/8 -j DENY
ipchains -A input -i ! lo -d 127.0.0.0/8 -j DENY
ipchains -A input -i extIF -d ! extIP -j DENY
# The following 3 rules are for the 'private' IP ranges - no ISP should use them.
# However if you find you are allocated an address in one of these ranges, comment out
# the appropriate rule.
ipchains -A input -i extIF -s 10.0.0.0/8 -j DENY -l
ipchains -A input -i extIF -s 172.16.0.0/12 -j DENY -l
ipchains -A input -i extIF -s 192.168.0.0/16 -j DENY -l

The only place you'll see legitimate packets to or from 127.0.0.0/8 (the internal loopback address) is on the loopback interface. Loopback is used internally by services such as X-Window, it allows the same code to be used for processes running on local and remote machines.

# Protect the priviliged ports on the external interface and enable logging for them
ipchains -A input -i extIF -d extIP 0:1023 -j DENY -l

# Explicitly deny access to the X-Window ports on the external interface
ipchains -A input -i extIF -d extIP 6000:6100 -j DENY -l
ipchains -A output -i extIF -s extIP 6000:6100 -j REJECT -l

By using -l we get a log of attempted connections inwards, along with a log of attempts to send packets outwards from these ports. Using REJECT on the second X-Window line means that local processes will be notified of failures and will not hang waiting for replies which will never come.

# Allow DNS lookups as a client
ipchains -A input -i extIF -p udp -s dnsIP dns -d extIP unpriv -j ACCEPT
ipchains -A output -i extIF -p udp -s extIP unpriv -d dnsIP dns -j ACCEPT

DNS lookup replies can be spoofed which is why we are only allowing access to our (hopefully) trustworthy ISP's DN server.

# HTTP (Web)
ipchains -A input -y -i extIF -p tcp -s anyIP http -d extIP unpriv -j ACCEPT
ipchains -A output -i extIF -p tcp -s extIP unpriv -d anyIP http -j ACCEPT

# SSL (Secure web)
ipchains -A input -y -i extIF -p tcp -s anyIP ssl -d extIP unpriv -j ACCEPT
ipchains -A output -i extIF -p tcp -s extIP unpriv -d anyIP ssl -j ACCEPT<

# Telnet
ipchains -A input -y -i extIF -p tcp -s anyIP telnet -d extIP unpriv -j ACCEPT
ipchains -A output -i extIF -p tcp -s extIP unpriv -d anyIP telnet -j ACCEPT

# SSH (Secure SHell)
ipchains -A input -y -i extIF -p tcp -s anyIP ssh -d extIP unpriv -j ACCEPT
ipchains -A output -i extIF -p tcp -s extIP unpriv -d anyIP ssh -j ACCEPT

# POP3
ipchains -A input -y -i extIF -p tcp -s pop3IP pop3 -d extIP unpriv -j ACCEPT
ipchains -A output -i extIF -p tcp -s extIP unpriv -d pop3IP pop3 -j ACCEPT

# IMAP
ipchains -A input -y -i extIF -p tcp -s imapIP imap -d extIP unpriv -j ACCEPT
ipchains -A output -i extIF -p tcp -s extIP unpriv -d imapIP imap -j ACCEPT

# SMTP
ipchains -A input -y -i extIF -p tcp -s smtpIP smtp -d extIP unpriv -j ACCEPT
ipchains -A output -i extIF -p tcp -s extIP unpriv -d smtpIP smtp -j ACCEPT

# FTP control connection
ipchains -A input -y -i extIF -p tcp -s anyIP ftp -d extIP unpriv -j ACCEPT
ipchains -A output -i extIF -p tcp -s extIP unpriv -d anyIP ftp -j ACCEPT

# FTP data connection. A real mess, 'cos there are two types, active and passive.
# Allowing active outwards can really open your box up so I'll go for the most secure here;
# passive outwards.
ipchains -A input -y -i extIF -p tcp -s anyIP ftp-data -d extIP unpriv -j ACCEPT
ipchains -A output -i extIF -p tcp -s extIP unpriv -d anyIP ftp-data -j ACCEPT

All these protocols use the same basic rules, the only differences being the port number allowed and whether a specific peer IP is used. Explicitly specifying that the local connection must be from an unprivileged port is probably a bit of overkill, but it does no harm so there's no reason not to.

Before you activate this firewall however, enter the following script and have a console ready (I usually put it in /etc/ppp/killfw.sh) in case there is an error and you can't use X-Window. This script flushes the chains and resets the policies to their defaults.

#!/bin/sh
ipchains -F
ipchains -P input -j ACCEPT
ipchains -P output -j ACCEPT
ipchains -P forward -j FORWARD

(Remember to chmod both of the scripts with 0755 and chown root:root!) Well, there you have it, a basic firewall. Remember though that this is no substitute for being careful; for example using Telnet (or POP3/IMAP for that matter) to connect to another host is not a good idea as your password (along with everything else) is sent in the clear. If you can, use SSH and/or one of the password-encryption schemes available under POP3/IMAP. Even better yet, find out if your ISP allows tunnelling over SSH; this way all the traffic (your emails included) will be encrypted.

If you have an interest in other configurations, please . Also please write and let me know how you get on with these instructions, what needs to be altered or clarified, and whether you found this useful!