My previous article demonstrated how even novice BSD users can quickly create a working firewall to protect their own systems. Today I want to start with that base firewall and explore how to fine-tune rules, configure NAT so other PCs can share an Internet connection, and review firewall logs.
The rulebase created in the last article allows your computer to access the internet, and allows fwbuilder to use SSH on the localhost to install firewall policies. This means you should be able to do most internet-related activities including web browsing, sending email, using
pkg_add to install software, using
portupgrade to keep your software up-to-date, and using most of the common internet applications such as Gaim for chat, Skype for free telephone calls, XMMS to listen to music, and RSS feeders to keep abreast of the latest news.
Occasionally, you'll run across an application your firewall blocks. The reason is that the application needs to make a connection to you in order to send packets. Some internet games do this; a Google search should tell you which ports you need to open on your firewall. Simply make a TCP or UDP object which contains the required port(s) and insert a rule that allows that service from any source.
Some other services, besides internet games, may not work as you expect. As an example, I use /usr/ports/mail/fetchmail to download email from my ISP's POP3 server. After installing my firewall, I was surprised to discover that I could send email but not receive it.
fetchmail had no problem connecting to the ISP to download the email; the problem was that
fetchmail expected to contact
sendmail before it delivered that email into my inbox. The problem disappeared after I installed that package and added this rule:
Source Destination Service Action Options Comment Any test:lo0:ip smtp Accept used by fetchmail
I created that smtp object by starting
fwbuilder, right-clicking the TCP object in the Services tree, and choosing New TCP Service from the menu. I gave it the name smtp and a Destination Port Range Start of 25. Notice that the destination is the loopback address, which only local mail delivery uses. Even if you don't use
fetchmail, you should still add this rule so that your periodic scripts can successfully send mail to the superuser account.
You may be surprised to learn that
ping won't work until you add another firewall rule. This is because
ping uses two types of ICMP packets: one goes out from your machine (an echo request), but you'll never know your request made it to the destination unless your firewall allows an echo reply packet to come in. The current firewall rules only allow your packets to go out.
To fix this, start by creating two ICMP objects. Right-click ICMP and select New ICMP Service from the menu. Name the first object Echo Request, and enter an ICMP Type of 8 and an ICMP Code of 0. When you make the second ICMP object, name it Echo Reply and enter an ICMP type of 0 and an ICMP Code of 0.
Note: if you're curious, the types and codes for ICMP packets are available from the IANA.
Next, decide if you just want the firewall to be able to ping out or if you also wish to allow others to ping your firewall. This rule will allow all pings:
Source Destination Service Action Options Comment Any Any echo request Accept Allow all pings echo reply
Note: technically, you don't need to add the
echo request service, as the existing firewall rules already allow your outbound packets. I've included it because it makes more sense to me when I view the rule.
If you want to be more restrictive and only allow your firewall to
ping out and not allow others to
ping your firewall, modify the rule so it looks like:
Source Destination Service Action Options Comment Any firewall echo reply Accept Allow sites I've pinged to reply back
Again, you don't have to allow your echo requests out, as they already fall under the rule that allows you to access the internet. It is up to you whether to include that service in this rule.
Before creating the rules you need within
fwbuilder to share your internet connection, make sure that your network is properly set up. The computer running
fwbuilder needs to have a NIC, which it uses to communicate with the other computers in your home network. This NIC is separate from the hardware you use to communicate with your ISP; that might also be a NIC (in the case of a cable or DSL connection) or it might be a modem (in the case of a dial-up PPP connection). Make sure the NIC you use to communicate with your other computers is plugged into the same hub or switch as your other computers.
You also need to decide on an addressing scheme to use on your home computers. The easiest method is to choose one of the addresses from the private address ranges. These addresses always start with either 10, 172.16 up to 172.31, or 192.168.
In my example, a FreeBSD system running
fwbuilder will share its internet connection with a Windows XP system. I've assigned the address 10.0.0.1 to the FreeBSD system and 10.0.0.2 to the XP system. Starting on the XP system:
On the FreeBSD system, become the superuser and type
ifconfig to determine the name of the NIC you will use to communicate with the XP system. If you have multiple NICs and are currently connected to the internet, choose the NIC that currently doesn't have an IP address. In my example,
rl0 connected to the XP system and
xl0 connected to the ISP:
# ifconfig rl0: flags=8802<BROADCAST,SIMPLEX,MULTICAST> mtu 1500 options=8<VLAN_MTU> ether 00:11:d8:ea:16:d7 media: Ethernet autoselect (10baseT/UTP) status: active xl0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500 options=9<RXCSUM,VLAN_MTU> inet 22.214.171.124 netmask 0xffffff00 broadcast 126.96.36.199 ether 00:04:75:ee:e0:21 media: Ethernet autoselect (100baseTX <full-duplex>) status: active lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> mtu 16384 inet 127.0.0.1 netmask 0xff000000
Assigning the IP address is simple. (Replace
rl0 with the FreeBSD name of your NIC):
# ifconfig rl0 10.0.0.1
Double-check that the connection is good with a
# ping 10.0.0.2 (press ctrl c to end)
Now that your computers are ready, it's time to add object(s) to your firewall to represent the computer(s) on your home network, recheck your rules to ensure all computers are allowed internet access, and then add a NAT rule to enable the actual connection sharing.
There are several ways to represent the computers on your network: you can create host objects for each computer, or you can create a network object to represent all of the computers on your home network. Because I have only one other computer, I've chosen to add a host object to represent my XP computer.
Right-click Hosts and select New Host from the menu. Give the host a descriptive name; I called mine XP. When asked to configure the interfaces manually, add the IP address and subnet mask for the computer; you can leave the rest of the parameters empty. Just make sure that you have added the address. In my case, I entered 10.0.0.2 and 255.0.0.0 with a label of my_network.
Next, review your current firewall rules and ask yourself, should only the firewall computer be able to do this or should all my computers? For example, I should add the XP computer as a Source for the rule that allows access to the internet, but I should leave the firewall loopback as the only Destination for the SSH rule that allows me to install a firewall policy. My complete rulebase resembles Figure 1.
Figure 1. My complete rulebase (Click for full-size image)
Creating the NAT rule is easy. In the right frame, click on the NAT tab. Your firewall rules should disappear (don't worry, they are still available from the Policy tab). You should see an empty frame, as you haven't created any NAT rules yet. Right-click and choose Insert Rule. Notice that NAT rules have different fields than regular firewall rules:
Original Src default value of Any Original Dst default value of Any Original Svr default value of Any Translated Src default value of Original Translated Dst default value of Original Translated Svr default value of Original Comment empty by default
This is what you want to happen: when your other computer needs to access the internet, it should go through the firewall and then out its other interface to the ISP. Create a rule that does that by changing two of the default values:
Original Src host object Translated Src external interface of firewall
In my case, I called my host object XP and my external firewall interface ISP, so my rule looks like Figure 2.
Figure 2. My NAT rule (Click for full-size image)
Don't forget to install your policy when you finish creating your NAT rule. Then try to access a website from your other computer. Assuming you remembered to add that host to your internet access rule, everything should just work.
Hint: if you'd like to see your NAT rules using
pfctl -s rules as the superuser. To see your NAT translations or your current NAT connections, type
pfctl -s state.
There are several things you need to do if you'd like to view your firewall logs. First, make sure that you've chosen the Logging On Action in at least one of your firewall rules.
Hint: choose wisely when deciding which rules to log; if you log everything, you will have to wade through very large logfiles! If you only want to log when you think there is a problem--for example, one of your applications doesn't seem to work through the firewall--enable logging temporarily for your internet access rule until you've figured out the problem.
Next, make sure that you have
# kldstat | grep pflog 7 1 0xc52d4000 2000 pflog.ko
If you see this,
pflog is good to go. If you only get your prompt back, load the module:
# kldload pflog
... and add these lines to /etc/rc.conf to reload the module at boot time:
pflog_enable="YES" pflog_logfile="/var/log/pflog" pflog_flags=""
If that logfile doesn't already exist, create it:
# touch /var/log/pflog
You should now be able to start
# /etc/rc.d/pflog start Starting pflog. # /etc/rc.d/pflog status pflog is running as pid 95363.
The logfile that this creates is not a text file, meaning you can't read it directly or use a utility such as
tail -f to watch the log.
# tcpdump -n -e -ttt -r /var/log/pflog
To view the file as it grows, use:
# tcpdump -n -e -ttt -i pflog0
Admittedly, those are some pretty long commands just to view a log. This is an excellent time to create some key bindings. These bindings work from a terminal, so I run them from
Alt-F2 instead of the GUI. The first command will bind
Ctrl-L to the command that reads the logfile, and the second command will bind
Ctrl-g to the command that watches the log as it grows:
# bindkey -s "^L" "tcpdump -n -e -ttt -r /var/log/pflog" # bindkey -s "^g" "tcpdump pn -e -ttt -i pflog0"
I find that pressing
Ctrl-g is much quicker. If you prefer to have your bindings work in your GUI, install and configure
Hint: BSD Hacks has more directions for creating shell, terminal, and GUI bindings.
Even with key bindings,
tcpdump can still be a little inconvenient; it displays your log entries in pure text. There currently aren't any GUI
pflog entry readers, but you can hack an HTML equivalent that will allow you to view your logs in a browser. Start by installing the
# cd /usr/ports/sysutils/pflogx # make install
Note that I've chosen to install the port, not the binary package, and that I didn't use the
clean target to
make. This is because I want to use an .xls file that doesn't come with the package.
make clean will delete it. Also, during the install, you'll see a menu asking if you want to use Expat; selecting this option will give you the ability to merge logfiles.
Once installed, check out the installed .xsl files:
# ls pflogx/work/xsl export_csv.xsl export_xhtml.xsl last_date.xsl export_html.xsl first_date.xsl
The /usr/local/share/doc/pflogx/README holds directions for using
pflogx and descriptions of each .xsl file.
Here is an example to get you started. Using the logfile as input (
-i), create an XML file as output (
# pflogx -i /var/log/pflog -o ~/log.xml
Copy export_html.xsl to your home directory:
# cp /usr/ports/sysutils/pflogx/work/pflogx/xsl/export_html.xsl ~
Open ~/log.xml in your favourite text editor. The first line should say:
<?xml version="1.0" encoding="UTF-8"?>
Right after that line, add:
<?xml-stylesheet type="text/xsl" href="export_html.xsl"?>
After you save your change, type the full path to log.xml into your browser. You should see something like Figure 3.
Figure 3. An HTML firewall log report (Click for full-size image)
I've barely scratched the surface of
pf's features. More advanced users can explore how to integrate these features into fwbuilder. Here is some reading material to get you started:
If you right-click your firewall object and choose Edit, then Firewall Settings, you'll find many interesting tunables. If you wish to implement some
pf features not currently supported by
fwbuilder, such as
carp, experiment with adding the required lines to the Prolog/Epilog tab.
Dru Lavigne is a network and systems administrator, IT instructor, author and international speaker. She has over a decade of experience administering and teaching Netware, Microsoft, Cisco, Checkpoint, SCO, Solaris, Linux, and BSD systems. A prolific author, she pens the popular FreeBSD Basics column for O'Reilly and is author of BSD Hacks and The Best of FreeBSD Basics.
Return to the BSD DevCenter.
Copyright © 2009 O'Reilly Media, Inc.