I've long been a fan of FreeBSD (although I also use a Mac, Linux, and Windows machine -- right tool for the job, and all that), and one of the things I like best about the various BSDs is the ease with which you can set up a stateful packet-filtering firewall. To put it simply, pf rocks.
Setting it up for the first time, though, can be a bit of a chore. If you are interested in giving pf a look, here's how you do it on FreeBSD.
Recompile your kernel
For the sake of argument, let's assume that we are going to be setting up a machine called "zeus" as a gateway server with a few simple services running on it. We first need to compile the pf stuff into the kernel, and then install our new kernel. First, get to the right directory:
[tcs@zeus] ~> su -
Password:
1:28PM up 60 days, 3:54, 1 user, load averages: 0.03, 0.01, 0.00
[root@zeus] ~# cd /usr/src/sys/i386/conf/
Now, copy the file GENERIC to some new file (I'm calling my zeus):
[root@zeus] ~# cp GENERIC ZEUS
Edit the file ZEUS and add the following lines just below "options ADAPTIVE_GIANT":
#PF Support
device pf #PF OpenBSD packet-filter firewall
device pflog #logging support interface for PF
device pfsync #synchronization interface for PF
#ALTQ Support
options ALTQ
options ALTQ_CBQ # Class Bases Queueing
options ALTQ_RED # Random Early Drop
options ALTQ_RIO # RED In/Out
options ALTQ_HFSC # Hierarchical Packet Scheduler
options ALTQ_CDNR # Traffic conditioner
options ALTQ_PRIQ # Priority Queueing
Now, we need to compile and install the kernel. Go to the /usr/src directory and execute this command:
make buildkernel KERNCONF=ZEUS
Wait (quite a while). When it's done, type this:
make installkernel KERNCONF=ZEUS
Wait a bit longer. Reboot. If it comes up, congrats -- you have a new kernel.
Enable PF in rc.conf
We need to tell the OS that we want to use pf. Enter the following in /etc/rc.conf
pf_enable="YES"
pf_rules="/etc/pf.conf" # rules definition file for pf
pf_flags="" # additional flags for pfctl startup
pflog_enable="YES" # start pflogd(8)
pflog_logfile="/var/log/pflog" # where pflogd should store the logfile
pflog_flags="" # additional flags for pflogd startup
Set up the firewall: pf.conf
The default rules for pf.conf are very, very detailed. We are going to ignore them, and make our own. First, back up the /etc/pf.conf file that is (probably) there by default:
cd /etc
mv pf.conf pf.conf.dist
Now, edit a new file called pf.conf and enter the file below (each service is mentioned in the comments preceding it):
# define our interfaces. Find yours by typing ifconfig as root
lo="lo0"
ext_if="fxp1" #your external nic
ext_gw="19x.xx.xx.254" #change this to the ip of your gateway router
int_if="fxp0" #your internal nic
oip1="19x.xxx.xxx.222" #change this to your external ip address
#clean everything up (reset to defaults)
scrub in
# nat for internal clients
nat on $int_if from 192.168.0.0/24 to any -> ($int_if)
# Pass/block rules
block in
pass quick on { $lo $int_if } all
# we shouldn't have to do this, but seem to have to on freebsd
pass out on $lo all
# allow ssh to local machine
pass in on $ext_if proto tcp to ($ext_if) port ssh keep state
Save, and you are ready to give things a try!
Helpful hints:
To enable the firewall rules:
pfctl -f /etc/pf.conf
To enable pf:
pfctl -e
To disable pf:
pfctl -d