Chapter 4. Firewalling

When designing a network, it’s often desirable to define policies governing how and where certain vital network services can be accessed. The firewall is a key technology that is instrumental in enforcing these policies and can allow network administrators to delineate trust relationships between networks and hosts with a fine grain of detail.

By instituting a firewall, you can prevent unauthorized access to services at the network level before an attacker is given the chance to attempt to exploit them. You can use a firewall not only to limit what information flows into a network, but also to prevent the egress of information. Doing so aids in preventing worm propagation and helps stop important confidential information from leaving an enterprise. Additionally, firewall logs can be excellent tools to help you understand where the threats to your network originate.

A variety of firewalls are available today. In addition to the many firewall appliances that are available, Linux, BSD, and Windows all include some form of firewalling support. This chapter shows how to set up firewalls with Linux, FreeBSD, OpenBSD, and Windows, as well as how to test your firewall rulesets. You’ll also see how to perform MAC address filtering and how to create a gateway that will authenticate machines based on login credentials. Finally, you’ll learn a few additional tricks to keep certain types of traffic from exiting your network.

Protect your network with Linux’s powerful firewalling features.

Linux has long had the capability for filtering packets, and it has come a long way since the early days in terms of both power and flexibility. The first generation of packet-filtering code, called ipfw (for “IP firewall”), provided basic filtering capability. Since it was somewhat inflexible and inefficient for complex configurations, ipfw is rarely used now. The second generation of IP filtering was called IP chains. It improved greatly on ipfw and is still in common use. The latest generation of filtering, called Netfilter, is manipulated with the iptables command and used exclusively with the 2.4.x and later series of kernels. Although Netfilter is the kernel component and iptables is the user-space configuration tool, these terms are often used interchangeably.

An important concept in Netfilter is the chain , which consists of a list of rules that are applied to packets as they enter, leave, or traverse the system. The kernel defines three chains by default, but new chains of rules can be specified and linked to the predefined chains. The INPUT chain applies to packets that are received by and destined for the local system, and the OUTPUT chain applies to packets that are transmitted by the local system. Finally, the FORWARD chain applies whenever a packet will be routed from one network interface to another through the system. It is used whenever the system is acting as a router or gateway, and it applies to packets that are neither originating from nor destined for the local system.

The iptables command makes changes to the Netfilter chains and rulesets. Using iptables, you can create new chains, delete chains, list the rules in a chain, flush chains (i.e., remove all rules from a chain), and set the default action for a chain. iptables also allows you to insert, append, delete, and replace rules in a chain.

Now, let’s construct some rules to allow this traffic through. First, make a rule to allow traffic on TCP port 80—the standard port for web servers—to pass to the web server unfettered by the firewall:

# iptables -A FORWARD -m state --state NEW -p tcp \ 
               -d 192.168.1.20 --dport 80 -j ACCEPT
            

And now for the mail server, which uses TCP port 25 for SMTP:

# iptables -A FORWARD -m state --state NEW -p tcp \ 
               -d 192.168.1.21 --dport 25 -j ACCEPT
            

You might also want to allow remote POP3, IMAP, and IMAP+SSL access:

Finally, allow DNS access via port 53:

# iptables -A FORWARD -m state --state NEW -p tcp \
               -d 192.168.1.21 --dport 53 -j ACCEPT
            

Unlike the other services, DNS can use both TCP and UDP port 53. Using a default deny policy makes it slightly more difficult to use UDP for DNS. This is because the policy relies on the use of state-tracking rules, and since UDP is a stateless protocol, there is no way to track it. In this case, you can configure the DNS server either to use only TCP, or to use a UDP source port of 53 for any response that it sends back to clients that were using UDP to query the name server.

If the DNS server is configured to respond to clients using UDP port 53, you can allow this traffic through with the following two rules:

# iptables -A FORWARD -p udp -d 192.168.1.18 --dport 53 -j ACCEPT
# iptables -A FORWARD -p udp -s 192.168.1.18 --sport 53 -j ACCEPT
            

The first rule allows traffic destined for the DNS server into your network, and the second rule allows responses from the DNS server to leave the network.

In these examples, the order in which the rules were entered does not really matter. Since you’re operating with a default DENY policy, all your rules have an ACCEPT target. However, if you had specified targets of DROP or REJECT as arguments to the -j option, you would have had to take a little extra care to ensure that the order of those rules would result in the desired effect. Remember that the first rule that matches a packet is always triggered as the rule chains are traversed, so rule order can sometimes be critically important.

It should also be noted that rule order can have a performance impact in some circumstances. For example, the rule shown earlier that matches ESTABLISHED and RELATED states should be specified before any of the other rules, since that particular rule will be matched far more often than any of the rules that will match only on new connections. Putting that rule first will prevent any packets that are already associated with a connection from having to traverse the rest of the rule chain before finding a match.

To complete the firewall configuration, you’ll want to enable packet forwarding. Run this command:

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

This tells the kernel to forward packets between interfaces whenever appropriate. To have this done automatically at boot time, add the following line to /etc/sysctl.conf :

net.ipv4.ip_forward=1

If your system doesn’t support /etc/sysctl.conf, you can put the preceding echo command in one of your startup rc scripts, such as /etc/rc.local.

Another useful kernel parameter is rp_filter, which helps prevent IP spoofing. Running the following command enables source address verification by checking that the IP address for any given packet has arrived on the expected network interface:

# echo 1 > /proc/sys/net/ipv4/conf/default/rp_filter
            

You can also enable source address verification by editing /etc/sysctl.conf on systems that support it, or else putting the changes in your rc.local. To enable rp_filter in your sysctl.conf, add the following line:

net.ipv4.conf.all.rp_filter=1

To save all of the rules, either write them to a shell script or use your Linux distribution’s particular way of saving them. Do this in Red Hat by running the following command:

# /sbin/service iptables save
            

This saves all currently active filter rules to /etc/sysconfig/iptables. To achieve the same effect under Debian, edit /etc/default/iptables and set enable_iptables_initd=true.

After doing this, run the following command:

# /etc/init.d/iptables save_active
            

When the machine reboots, your iptables configuration will automatically be restored.