Digital Elephant

Firewall Configuration Example (ipchains)

This example configuration controls access to a private (masqueraded) network. It permits access to a variety of services on the boundary machine, a scheme that is frowned on by some security gurus, but which is a comfortable tradeoff between an unprotected network and an expensive multi-box firewall protection system.

The actual configuration file, without all the explanatory material in it can be retrieved here.

1. Set up defaults

The first thing we do is set up default policies, in case forwarding is still on when this script starts. In that case, when we flush the chains controlling access, each one falls back to denying everything, so that unexpected intrusions do not have a small window of opportunity to get through the barrier. Once the chain definitions are done, these default policies do not get used, because the last entry in each chain is a catch-all rule that creates a syslog entry, and then discards the packet.

/sbin/ipchains -P input DENY
/sbin/ipchains -P output DENY
/sbin/ipchains -P forward DENY

2. Clean house

Next, delete any named chains that we left over from any previous firewall configuration. This step allows us to run the script at any time, without having to reboot (while we are testing this stuff, for example). The permanent chains (input, output and forward) cannot be deleted, so we just flush the contents. Our script will try to create the named chains, so we need to delete them (silently), since there isn't an easy way to do a conditional create step.

/sbin/ipchains -F input
/sbin/ipchains -F output
/sbin/ipchains -F forward
/sbin/ipchains -F wellk
/sbin/ipchains -F udpsocks
/sbin/ipchains -X wellk
/sbin/ipchains -X udpsocks

3. Define standard-service ports

Now that the housekeeping is done, we can begin to create actual firewall filtering rules. Our first step is to specify the standard TCP service ports that we want to open so that external customers can make contact with them.

/sbin/ipchains -N wellk
/sbin/ipchains -A wellk -p tcp --dport www -j ACCEPT
/sbin/ipchains -A wellk -p tcp --dport smtp -j ACCEPT
/sbin/ipchains -A wellk -p tcp --dport domain -j ACCEPT
/sbin/ipchains -A wellk -p tcp --dport auth -j ACCEPT
/sbin/ipchains -A wellk -p tcp --dport nntp -j ACCEPT
/sbin/ipchains -A wellk -p tcp --dport ntp -j ACCEPT
/sbin/ipchains -A wellk -p tcp --dport https -j ACCEPT

Similarly, we create a list of the standard UDP service ports that we will accept.

/sbin/ipchains -N udpsocks
/sbin/ipchains -A udpsocks -p udp --dport ntp -j ACCEPT
/sbin/ipchains -A udpsocks -p udp --dport domain -j ACCEPT

4. Rules for each interface

After these preliminary definitions, we can begin to deal with the rules that affect each actual interface on our boundary machine. Unfortunately, there are not two, but three: loopback is the internal "interface" that is used by many programs to launch IP traffic, so that they don't have to deal with finding the actual interface corresponding to the IP address of their target, but can leave that to the normal packet dispatch code. For this interface, we just permit everything.

/sbin/ipchains -A input -i lo -j ACCEPT
/sbin/ipchains -A output -i lo -j ACCEPT 

For the interface to our private network, we allow all traffic. This is not always a good idea, but I trust my users implicitly. If you do not, you can put restrictions on what uses they make of the Internet here.

/sbin/ipchains -A input -i eth0 -j ACCEPT
/sbin/ipchains -A output -i eth0 -j ACCEPT

This is the interface to the Internet. Our basic strategy is to control which packets are accepted on this interface, and then use other control mechanisms to deal with what can go out. The first line allows TCP traffic on unprivileged ports to flow without further checking. This is not as secure as we might be, but the general rule is that such traffic will have to be accepted by a process either on the firewall or at a client machine on the trusted side of the firewall. The next two lines check for valid TCP and UDP requests. There is a special check to allow DNS traffic to pass through the firewall, even if the destination port is not the DNS standard port. Then we allow ICMP traffic. Finally, if the packet is not acceptable, we log the event, and drop the packet on the floor.

/sbin/ipchains -A input -i eth1 -p tcp --dport 1024:65535 -j ACCEPT
/sbin/ipchains -A input -i eth1 -p tcp -j wellk
/sbin/ipchains -A input -i eth1 -p udp --sport domain --dport 1024:65535 -j ACCEPT
/sbin/ipchains -A input -i eth1 -p udp -j udpsocks
/sbin/ipchains -A input -p icmp -j ACCEPT
/sbin/ipchains -A input -l -j DENY

Output filtering is pretty simple. If the source address for a packet matches the IP address of the interface, we allow it out. All legal traffic should look like this. Anything that doesn't match is probably the result of hackery, so we log it, and trash the packet instead of allowing it out onto the Internet.

/sbin/ipchains -A output -i eth1 -s {your_external_IP} -j ACCEPT
/sbin/ipchains -A output -l -j DENY

5. Masquerade Internal Traffic

When a packet is forwarded from the private network side, it cannot be transmitted directly onto the Internet, because its source address is one of the special ones for Private Networks. Any router in the Internet that is worth its salt will refuse to forward such a packet. Therefore, there is special processing code in the kernel that alters the packet header so that it appears to be originating on the firewall machine. At the same time, this code alters the source port number, as a way to identify the expected reply. When the target host sends a reply packet back (addressed to the firewall), that packet will contain this port number as the destination port. This allows the kernel forwarding code to identify the return packet as one for which it should undo the masquerading it has done, by recovering the original source IP address and port, and inserting them into the reply packet as destination address and port. Such demasqueraded packets bypass the normal input and forwarding rules, and are sent more or less directly out onto the private network side.

/sbin/ipchains -A forward -s 192.168.1.0/24 -d 0/0 -j MASQ

Last updated November 7, 2006 Webmaster