In the past I had used a Linksys broadband router that suited my purposes pretty well, but I had used all four of the ethernet ports on router's the built-in switch. Since I have begun playing around with different operating systems I have been adding a few more machines to my network, and really wanted to try a setting up a FreeBSD machine running Bind 9 to host DNS for my local network. To facilitate adding more machines to the network, I ordered an 8 port 3com OfficeConnect switch from ebay. This led me to ditch the old Linksys router and set up an OpenBSD router/firewall.
Why replace the Linksys router? It is true that I could have just uplinked the Linksys router to the new switch, but what fun would that be? I had gotten a couple of old laptops from work for free, so, working off of the advice of coworker/network guru/all around *nix master Steve Hosto, I set about learning how to set up an OpenBSD router/firewall on one of them.
Why OpenBSD? Well, OpenBSD is considered to be one of the most secure operating systems out of the box. It's also free, as are most of it's *BSD cousins. You can go to http://www.openbsd.org, find a mirror, and download it right now if you want to. The OpenBSD organization would appreciate it if you would buy the distribution CDs, as that is one of the ways they generate funds to keep the project going. However, if you are a poor IT worker with large mortgage and car payments like myself, you can just download the boot disk image and install from the FTP site.
One of the great things about most unix based operating systems is that you can install just what you need, and run it on very old hardware. According to the OpenBSD website, all you need for the Intel x86 platform is a 386 (with the math coprocessor) or better. We will want something a little faster than a 386 to run our router/firewall, but nothing too current. I would recommend the following hardware setup:
For my machine I used an old Gateway Solo laptop, with the following specs:
You may notice that the HD is only 722MB, while I recommended a 1GB or larger HD before. This just means I will have to clean up the logs more often.
One of the benefits of using a laptop is that it has it's own built-in battery backup in case the power fails. It also uses less power than the average desktop machine, keeping my electric bill low, and doesn't take up a whole lot of physical space. There are also downsides, such as if an internal component breaks there aren't really many options for fixing it, and upgrades may be impossible.
You should also note that I am using two 3com network cards. I would recommend that if at all possible, use two cards with different chipsets. This will come in handy later when we configure our firewall so we can determine which card is the internal interface and which is the external. In my case having one 10Mbit card and one 100Mbit card helped out, since I could determine which card was which by the speed.
I am going to recommend you read over the OpenBSD 3.6 Installation Guide on the OpenBSD website, as it will tell you pretty much everything you need to know to install the OS. A couple things to keep in mind while installing though:
If you are interested, here is how I set up my volumes.
# size mount point a: 59M / b: 50M swap d: 49.4M /tmp e: 234M /var g: 244M /usr h: 24.6M /home
Again, I would have liked to have had a larger /var volume, but with the 250MB /usr volume I am at 79% of capacity with the required software installed.
One nice thing about OpenBSD is that all of the software we need to run is installed by default. We just need to enable it for our router/firewall to be up and running.
The next step is to configure the network adapters and the PacketFilter (pf), the router/firewall component. First, run the command ifconfig -a to see what network adapters you have. This is what mine looks like:
# ifconfig -a
lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> mtu 33224 inet 127.0.0.1 netmask 0xff000000 inet6 ::1 prefixlen 128
inet6 fe80::1%lo0 prefixlen 64 scopeid 0x6 ep1: flags=8863<UP,BROADCAST,NOTRAILERS,RUNNING,SIMPLEX,MULTICAST> mtu 1500 address: 00:50:04:f2:5f:ea media: Ethernet autoselect (100baseTX full-duplex) status: active inet 192.168.0.1 netmask 0xffffff00 broadcast 192.168.0.255 inet6 fe80::250:4ff:fef2:5fea%ep1 prefixlen 64 scopeid 0x1 ep2: flags=8863<UP,BROADCAST,NOTRAILERS,RUNNING,SIMPLEX,MULTICAST> mtu 1500 address: 00:60:97:ec:f9:9b media: Ethernet 10baseT inet6 fe80::260:97ff:feec:f99b%ep2 prefixlen 64 scopeid 0x2 inet 12.203.118.99 netmask 0xffffff00 broadcast 255.255.255.255
Your output will look different than mine, but the basic layout should be the same. The three character codes listed on the far left are the names of your network cards. The first two characters are the driver name, and the number is an increment in case you have multiple cards using the same driver, as I do. Notice there are three adapters listed. The first, lo0, is the loopback device. You don't need to worry about this one. The next two devices however, are the network cards you have installed. This information is what we will use to configure PF.
In my case I know ep2 is my external interface because it is only a 10Mbit card. The other device, ep1, is my internal interface. If you look in the /etc directory you will find two files, named hostname.<drv>, where <drv> are the codes for the network cards you have installed. For your external interface, the hostname file should look like this:
# cat /etc/hostname.ep2 dhcp
The file for your external interface however, is a little bit more complicated.
# cat /etc/hostname.ep1 inet 192.168.0.1 255.255.255.0
The first part of this file says that this is an IPv4 address. The next part is the IP address of this machine on the internal network. I am using 192.168.0.1 for my router, so I entered that here. The last part is the subnet mask, which, if you are just using a range of 255 or less addresses, will be the same as mine.
Now that we have the network interfaces configured, there are a couple system files we need to change before we configure the firewall. First we will edit the /etc/sysctl.conf file to turn on forwarding. The following line should already exist in your sysctl.conf file, you most likely just need to uncomment it. Comments in this file are started with a # sign, so if this line is there, simply remove the # sign at the beginning of the line. If it is not there, add it.
# grep forwarding /etc/sysctl.conf net.inet.ip.forwarding=1
Next we will need to turn on PF in the rc.conf file. Find the line that says pf=NO, and change it to YES. This line is down a ways in the file, so you will probably have to scroll a bit to find it.
# grep pf /etc/rc.conf pf=YES
Our router is almost ready. The last thing we need to do is configure PF's configuration file, which is /etc/pf.conf. I could write out all the changes to make, but I think it is easier to simply give you an example file to work from. You will need to change the parts of the file that say ext_if = "ep2" and int_if = "ep1" to put in the names of your network interfaces.
# cat /etc/pf.conf
ext_if = "ep1"
int_if = "ep2"
table <RFC1918>> const {!192.168.0.0/24,0.0.0.0/8,1.0.0.0/8,2.0.0.0/8, \
5.0.0.0/8,7.0.0.0/8,10.0.0.0/8,23.0.0.0/8,27.0.0.0/8,31.0.0.0/8,36.0.0.0/8, \
37.0.0.0/8,39.0.0.0/8,41.0.0.0/8,42.0.0.0/8,49.0.0.0/8,50.0.0.0/8,58.0.0.0/8, \
59.0.0.0/8,73.0.0.0/8,74.0.0.0/8,75.0.0.0/8,76.0.0.0/8,77.0.0.0/8,78.0.0.0/8, \
79.0.0.0/8,89.0.0.0/8,90.0.0.0/8,91.0.0.0/8,92.0.0.0/8,93.0.0.0/8,94.0.0.0/8, \
95.0.0.0/8,96.0.0.0/8,97.0.0.0/8,98.0.0.0/8,99.0.0.0/8,100.0.0.0/8,101.0.0.0/8, \
102.0.0.0/8,103.0.0.0/8,104.0.0.0/8,105.0.0.0/8,106.0.0.0/8,107.0.0.0/8, \
108.0.0.0/8,109.0.0.0/8,110.0.0.0/8,111.0.0.0/8,112.0.0.0/8,113.0.0.0/8, \
114.0.0.0/8,115.0.0.0/8,116.0.0.0/8,117.0.0.0/8,118.0.0.0/8,119.0.0.0/8, \
120.0.0.0/8,121.0.0.0/8,122.0.0.0/8,123.0.0.0/8,124.0.0.0/8,125.0.0.0/8, \
126.0.0.0/8,127.0.0.0/8,169.254.0.0/16,172.16.0.0/12,173.0.0.0/8,174.0.0.0/8, \
175.0.0.0/8,176.0.0.0/8,177.0.0.0/8,178.0.0.0/8,179.0.0.0/8,180.0.0.0/8, \
181.0.0.0/8,182.0.0.0/8,183.0.0.0/8,184.0.0.0/8,185.0.0.0/8,186.0.0.0/8, \
187.0.0.0/8,189.0.0.0/8,190.0.0.0/8,192.0.2.0/24,192.168.0.0/16,197.0.0.0/8, \
198.18.0.0/15,223.0.0.0/8,224.0.0.0/3}
# Options
set timeout { interval 30, frag 10 }
set timeout { tcp.first 120, tcp.opening 30, tcp.established 3600 }
set timeout { tcp.closing 120, tcp.finwait 45, tcp.closed 90 }
set timeout { udp.first 60, udp.single 30, udp.multiple 60 }
set timeout { icmp.first 20, icmp.error 10 }
set timeout { other.first 60, other.single 30, other.multiple 60 }
set limit { states 20000, frags 5000 }
set loginterface $ext_if
set optimization normal
set block-policy drop
set require-order yes
# clean up fragmented packets
scrub on $ext_if all random-id min-ttl 255 max-mss 1492 fragment reassemble
# queueing
altq on $ext_if priq bandwidth 230Kb queue { q_pri, q_def }
queue q_pri priority 7
queue q_def priority 1 priq (default)
# NAT internal hosts
nat on $ext_if from 192.168.0.0/24 to any -> ($ext_if)
# loopback
antispoof log quick for lo0 inet
pass quick on lo0 all
# silently drop broadcasts cable modem noise
block in quick on $ext_if from any to 255.255.255.255
# Block bad tcp flags from malicious people and nmap scans
block in log quick on $ext_if proto tcp from any to any flags /S
block in log quick on $ext_if proto tcp from any to any flags /SFRA
block in log quick on $ext_if proto tcp from any to any flags /SFRAU
block in log quick on $ext_if proto tcp from any to any flags A/A
block in log quick on $ext_if proto tcp from any to any flags F/SFRA
block in log quick on $ext_if proto tcp from any to any flags U/SFRAU
block in log quick on $ext_if proto tcp from any to any flags SF/SF
block in log quick on $ext_if proto tcp from any to any flags SF/SFRA
block in log quick on $ext_if proto tcp from any to any flags SR/SR
block in log quick on $ext_if proto tcp from any to any flags FUP/FUP
block in log quick on $ext_if proto tcp from any to any flags FUP/SFRAUPEW
block in log quick on $ext_if proto tcp from any to any flags SFRAU/SFRAU
block in log quick on $ext_if proto tcp from any to any flags SFRAUP/SFRAUP
# Drop spoofed packets IP blocks
block in log quick on $ext_if from { <RFC1918> } to any
block out log quick on $ext_if from any to { <RFC1918> }
# block and log everything by default
block return log on $ext_if all
# block anything coming from source we have no back routes for
block in from no-route to any
# block and log outgoing packets that don't have our address as source,
# they are either spoofed or something is misconfigured NAT disabled,
# (for instance), we want to be nice and don't send out garbage.
block out log quick on $ext_if from ! $ext_if to any
# pass out all TCP connections and modulate state
pass out on $ext_if proto tcp from $ext_if to any flags S/SA modulate state queue (q_def, q_pri)
# pass out all UDP connections and keep state
pass out on $ext_if proto udp from $ext_if to any keep state
# pass out/in certain ICMP queries and keep state ping)
pass out on $ext_if inet proto icmp from $ext_if to any keep state
I originally got this file from pantz.org, and modified it to suit my purposes.
If you want to forward incomming traffic on a specific port you will need to add a rdr statement to /etc/pf.conf file. Here is an example of forwarding http traffic on the standard port 80 to a web server.
rdr on $ext_if proto tcp from any to $ext_if port 80 -> 192.168.0.10 port 80
You will want to change 192.168.0.10 to the address of your web server.
Now that these files are all in place, it is time to test the configuration. We will use pfctl to test the configuration.
# pfctl -nf /etc/pf.conf
If the above command executes without displaying any output, your configuration is syntactically correct. If you get any output, you have an error somewhere, and need to go back and find the problem.
Once you get it to work correctly, we need to tell pf to use the configuration file in the /etc directory.
# pfctl -f /etc/pf.conf
Now we are ready to reboot and test out our new router! Once the machine is rebooted, log in and try pinging a few sites. If all goes well, go to a machine inside your network and try accessing the internet. Don't forget you will need to configure the client machines to use your new router.
There is a lot more you can do with PF than what I have listed here. What we have gone over is just a basic setup to get you started. There is a wealth of information available on the net to help you configure OpenBSD and PF, and I strongly encourage you to search around and learn as much as you can. Also, I am still learning how all this works, so if you have any suggestions please feel free to send me an email.