“All hosts must take responsibility for their own security.”

—Simson Garfinkel and Gene Spafford (O’Reilly),

Practical UNIX and Internet Security

I’m sure you’ll agree that there are many subjects that need to be covered in the security field! In this Daily Drill Down, I’m going to help you build your own firewall on UNIX-clone systems like Linux or FreeBSD using their preinstalled software. Why did I choose these two systems? One might say, “Hey! He is a FreeBSD bigot!” No, no, I am not a FreeBSD or Linux bigot. As for my own preferences, I prefer the Solaris operating system to either of these two. First of all, FreeBSD is a freely distributed open source system, as is Linux. Second, these systems are very easy to use to build a software firewall. They are good examples because the most popular firewall software is available to them and is distributed for free with open sources.

Linux preinstalled firewall software
Let’s start with the Linux operating system and its preinstalled software for building a firewall. I’m going to use a Network Address Translation (NAT) technology for blocking access to an internal network DMZ (the so-called demilitarized zone). For this example, I will use a Red Hat Linux distribution with the 2.0.38 kernel. (I’d like to warn you that you shouldn’t download and install the latest kernel distribution just because it’s the latest. There have been a number of times when the latest kernel wasn’t as stable as the previous release. I’d suggest that you not ever experiment on a working system with the Linux kernel distributions.)

You need to build your kernel distribution with the IP Forwarding, IP Masquerading, IP Firewalling, IP Transparent Proxying, and IP Routing functions. If you have problems building and compiling your customized kernel, you should refer to a Linux manual (there are many of them on the Net), because I assume here that you are somewhat experienced with the Linux system and its kernel structure. As far as the internal network is concerned (called the DMZ network later in this Daily Drill Down), you’ll have to change the network I’m using in this example (, which is a part of private class network, according to RFC1918) to the one you’re creating. You can use a network block that you’ve obtained from your local Internet service provider (ISP) with real IP addresses. That’s a good idea because it will greatly decrease the number of address collisions you experience on the Net.

Once you’ve built and installed your new kernel with the firewall options enabled, it’s time to set up a configuration script, which will start our firewall. Create (if it does not exist) and edit the file /etc/rc.d/init.d/firewall as shown here:
# flushing out all rulesets
# this is meaningless on the startup, but a good idea when restarting the firewall services
ipfwadm -F –f
ipfwadm -I –f
ipfwadm -O –f

# denying all connections, using the default rule
ipfwadm -F -p deny

       # allowing all connections from the DMZ network interface
ipfwadm -F -a accept -m -P all -S

       # allowing all incoming connections
ipfwadm -I -p accept
Okay, now it’s time to take care of the tcpwrappers package that’s included in the Red Hat Linux distribution. To begin with, let’s enable SSH connections to our firewall from the DMZ network to allow you to configure it in case of an emergency. Edit the /etc/hosts.allow file as shown here:
ALL: 10.0.0.
22: ALL

Now it’s time to close all other connections for our DMZ network by editing the /etc/hosts.deny system file:

We’ve now finished a simple firewall setup on our Linux system. Of course, I haven’t covered the subject of monitoring our firewall, but that is the topic of my next Daily Drill Down. There are many monitoring tools around, such as Big Brother and NetSaint. Some system administrators may want to write their own monitoring tools. This is not a question of firewall security. We have reached our target: We built a firewall that routes our internal network and denies others access to break into our network, which might contain classified information.

FreeBSD preinstalled firewall application
Now let’s try to build a somewhat different firewall (more complex and unified) using the preinstalled tools of the FreeBSD operating system. What elements should we build into our firewall? We must:

  • Block all incoming connections to ports 135-139 to our internal network because these ports are used by NetBIOS services (broadcasts, resources sharing, etc.), and they should not be available through the external network connection.
  • Allow our local network to access FTP and HTTP services on the external network.
  • Make our firewall invulnerable to SYN Flood and ICMP Flood attacks.
  • Limit connections to the corporate HTTP server.
  • Enable a backup connection to the firewall from the operator’s workstation to allow him to access the firewall and make changes to it.

To make all of these wishes come true, I’m going to use the FreeBSD operating system—to be exact, a distribution snapshot from the FreeBSD 4.0-STABLE branch. I’m also going to use the ipfw package as the firewall software. This package has been distributed with FreeBSD for a very long time, and it has been extensively tested by hundreds of FreeBSD users.

The network scheme looks pretty straightforward. The firewall has two network cards: The fxp0 interface card has the IP address and is used for a direct connection to our Internet router, and the fxp1 interface card has the IP address and is used for a connection to our new DMZ network with 18 IP addresses inside (subnetwork with network mask Since all these IP addresses belong to the private network class, according to RFC1918, you may have to change them to real ones to make this scheme work. I would like to remind you once again that all IP addresses used in this Daily Drill Down are for demonstration purposes only! Okay, let’s get started.

The kernel
To make the ipfw package work, we must enable this service in the kernel. Edit your kernel configuration file in the /usr/src/sys/i386/conf directory and add these options:
options IPFIREWALL     # this enables IP filtering services
options IPFIREWALL_VERBOSE  # this enables services for logging
                      # by rulesets of the passing through
                      # IP packets
# limits the number of packets
# that will be passed for logging
# to syslog to avoid allowing it
# to be flooded
options TCP_DROP_SYNFIN  # drops down all TCP packets with SYN
# and FIN flags set

As with the Linux system, I expect you to have some experience with the FreeBSD operating system in order to build and install a new kernel. If you don’t, I suggest that you to refer to the master Web site of FreeBSD, which contains numerous resources on this topic.
By default, using this kernel configuration, the newly installed kernel firewall will be set to not pass any connections. If you’d like to open all connections by default and close only the unnecessary ones, you may add the next option to your kernel configuration:

Which variant is best for you I can’t say for sure. I wrote a Daily Drill Down called “Tripped traps tricked by tricky tips: Security tricks” devoted to this problem; give it a read and you’ll be able to decide which variant to choose for your firewall.

Configuring the firewall
Now, after building and installing the new kernel, it’s time to start configuring the firewall itself. First, we have to edit the /etc/rc.conf file, as shown here. I’ll explain the code as we go along:

This blocks out the RFC1323 extensions to the TCP protocol, which are dangerous and vulnerable to several kinds of attacks.

This forces our router to drop TCP packets with the SYN and FIN flags set.

This drops and logs all ICMP REDIRECTs that are being done through our system.

This last command enables firewall rulesets, so now we have to write them. To do this, we must edit the /etc/rc.firewall configuration file:

These are predefined variables that will be used later in this startup script.
${fwcmd} add pass all from any to any via lo0

This enables all local traffic.
${fwcmd} add pass all from any to any via fxp1

This enables all traffic, limiting it to the DMZ network.
${fwcmd} add deny icmp from any to any frag

This blocks fragmented packets.
${fwcmd} add pass icmp from any to any

Here we pass all other ICMP packets.
${fwcmd} add pass tcp from any to any 25 out
${fwcmd} add pass tcp from any 25 to any out
${fwcmd} add pass tcp from any to any 443 out
${fwcmd} add pass tcp from any 443 to any out

Then we enable SMTP and HTTPS protocols.
${fwcmd} add deny tcp from any to 80 in via fxp0

We block access to our private (corporate) HTTP server, which has IP address
${fwcmd} add pass tcp from any to any 80 out via fxp1
${fwcmd} add pass tcp from any 80 to any out via fxp1

Then we pass traffic to the HTTP protocol in the DMZ network.
I’d like to dwell a bit on the order of these rulesets. Since we have to block some HTTP traffic, we must put the blocking rulesets before the allowing rulesets to give them the highest priority.${fwcmd} add allow all from any to any via fxp1

Next we allow any traffic within our DMZ network.
${fwcmd} add pass udp from any to any 53
${fwcmd} add pass udp from any 53 to any
${fwcmd} add pass tcp from any to any 119
${fwcmd} add pass tcp from any 119 to any
${fwcmd} add pass tcp from any to any 110
${fwcmd} add pass tcp from any 110 to any
${fwcmd} add pass tcp form any 21 to any
${fwcmd} add pass tcp from any to any 21
${fwcmd} add pass tcp from any 20 to any
${fwcmd} add pass tcp from any to any 20

Then we allow DNS, NNTP, POP3, FTP, and FTP-DATA protocols.
${fwcmd} add pass tcp from 22 to
${fwcmd} add pass tcp from to 22

Finally, we allow SSH connections from the operator’s backup host, whose IP address is

Well, that’s it. After the system reboots, the firewall will load these rulesets at system startup. You can manually configure the firewall using the ipfw binary, which is usually placed at the /usr/sbin directory. For example, to view all rulesets that were loaded by the firewall, you should type /usr/sbin/ipfw show at the shell prompt.

IP Filter
Recent releases of FreeBSD have included an IP Filter package along with ipfw. IP Filter is a pretty young firewall software package, but it is very configurable and includes a lot of functions that are missing from the ipfw package. For this simple reason, a number of network administrators upgraded their firewall to this software before it was thoroughly tested. Now they have a lot of extra features to play with, but at a price. For example, they have the ability to block the new Denial of Service attacks of BSD-clone systems—no other firewall software was able to do this. Now, however, many system administrators are having headaches because of weaknesses that exist in the IP Filter package in all versions up to and including 3.3.15 and 3.4.3. These weaknesses allow an attacker to penetrate the firewall when a common, yet admittedly flawed, configuration is used. Since many system administrators never rewrote the default configuration but just added their own options, they made their systems vulnerable. Of course, the patch for all versions was released very quickly and was incorporated into new releases of this package, but it left a very bad feeling in those who had many sleepless nights downgrading their systems to ipfw or even restoring from backups after successful attacks.

I’m not going to call the ipfw package the best firewall software. IP Filter does have a lot of necessary and very useful features; I’m only trying to make you aware of the fact that even firewall software may have holes, deficiencies, and bugs.

Just setting up a stand-alone firewall isn’t enough to make your network secure. Too often, system administrators do a great job writing very complex rulesets for their firewalls to secure their hosts and networks from external attackers, but they forget about local users. When dealing with data privacy, you must view your own users as potential enemies and attackers. It’s sad but true. That’s why even an excellent ruleset on your firewall won’t save it from being cracked because of the firewall’s local environment weaknesses. I’ll give you some hints on securing the networking environment for your firewall. What’s the most popular way that local intruders use to pass through a firewall? It’s MAC address spoofing. To avoid this problem, we can create our own fixed table of MAC addresses by editing the /etc/ethers file. Its format is pretty simple; here’s an example:
smirnoff 00:20:af:4a:3e:e3
blade 00:20:fg:3a:3e:21
timmons 00:20:fg:3a:3e:21
parker 00:20:fg:3a:3e:21

To learn the Ethernet address of the host, you should type arp -a. Typing arp -f /etc/ethers will load all Ethernet addresses from the /etc/ethers file and freeze the ARP table. You can automate this process by using the arpwatch program that comes in the ports collection of FreeBSD. This program monitors the ARP table and, when the ARP table changes, sends a message to the system administrator and freezes the table.

One of the reasons why people seem to be fond of firewalls and other network-based security measures is that they assume that they can allow host security to lapse if they secure the perimeter of their network. They are somewhat correct but at the same time greatly mistaken. Network security is mostly host security. If host administrators assume that the firewall will protect their hosts from access violations, sooner or later they’re in for a nasty surprise. No stand-alone technology can protect hosts from all access violations, so only the most complex of network- and host-based security systems, including both firewalling and monitoring programs, can ensure the safety of your hosts. At the heart of all these technologies is the need for smart planning of the security system as a whole. A bunch of security systems that aren’t integrated with one another are no more helpful than the Do Not Enter! sign on an open door.

In this Daily Drill Down, I pointed out that a well-designed network security scheme should consider all possible security breakdowns and holes and all aspects of those holes before it’s too late. I also showed you how to build your own firewall on UNIX-clone systems such as Linux or FreeBSD using their preinstalled software. While you may not think that there is anything of value on your network or even on a stand-alone system, someone else will. When you find out how valuable it was, you may have already lost the data as well as your job. So be smart and take care.
The authors and editors have taken care in preparation of the content contained herein but make no expressed or implied warranty of any kind and assume no responsibility for errors or omissions. No liability is assumed for any damages. Always have a verified backup before making any changes.