BSD DevCenter
oreilly.comSafari Books Online.Conferences.

advertisement


Securing Small Networks with OpenBSD NAT with pf

by Jacek Artymiak
03/06/2003

Catching Up with Changes in pf(4): Macros, Options, Scrubbing, and Network Address Translation

Despite what some doomsayers predicted when the OpenBSD project abandoned ipf (see the famous CVS log entry), the new pf(4) packet filter is doing its job very well and is steadily growing in functionality. A lot has changed since its official appearance in OpenBSD 3.0, and it is high time to have another look at what Daniel Hartmeier and others have been working on.

pf(4) has undergone numerous changes since I last wrote about it. It is now easier to use and has a greater range of available filtering options. If you have never used pf(4) before, you'll be delighted to know that it does packet filtering, network address translation (NAT), load balancing, protects against spam (coming in OpenBSD 3.3), and provides--after the merger with ALTQ--resource-sharing and quality of service control (QoS). In its current shape, pf(4) can be used to secure networks, connect multiple hosts to an external network through a single network interface, balance load between multiple servers, manage bandwidth, and keep logs of its activity. Because of this, pf(4) is quickly becoming an advanced tool for network management and security practitioners.

Related Reading

TCP/IP Network Administration
By Craig Hunt

This article assumes that you are using OpenBSD 3.2 with all of the latest security patches applied. (If you still don't know how to keep your system up to date, here are some hints to get you started.) The examples presented use the DMZ network configuration described earlier in this series. (Additional sources of information on DMZ design can be found in [Zwicky, Cooper, and Chapman 2000] and [Bishop 2003].) I will also answer some recent reader questions. Because there is so much new ground to cover, this article is split into four parts: (1) network address translation, (2) packet filtering (including transparent filtering), (3) ALTQ, and (4) load balancing and a preview of what's coming in OpenBSD 3.3. For the last installment you'll need to be running OpenBSD-current, as not all of the features I will be writing about are available in OpenBSD 3.2.

It also advisable (but by no means required) that you keep a copy of a good book on the workings of TCP/IP at hand while you are reading this. When I get stuck, I usually look things up in [Hunt 2002] or [Stevens 1994]. If these don't answer my questions, I dig through man pages and RFCs. (Browsing through their book catalog, I noticed that O'Reilly & Associates have a book on Internet protocols [Hall 2000], which could be helpful, but I have not read it. Another good book is [McKusick 1996], which focuses on the design of 4.4BSD and includes a lot of information about TCP/IP itself).

General Setup Tips

A firewall does not need expensive hardware to run, just a reasonably fast machine capable of running OpenBSD 3.2, with two or more network interfaces. (Depending on the internal network topology, it could even be just one interface; for example, the DMZ design described in one of my earlier articles uses three network interfaces on the firewall.) An old Pentium or Pentium II PC should be enough to cope with traffic up to 10Mbps even with packet logging enabled. As for the system memory, 32MB of RAM is quite enough although 64MB of RAM gives the operating system more breathing space. External storage is a more important consideration when the firewall is logging large amounts of traffic. This issue was discussed earlier, but I will return to it later in this series. Finally, on the hardware side, make sure that the firewall's network interfaces are capable of working at the speeds of their connected networks, i.e. a 100Mbps card connected to a network working at speeds up to 100Mbps, not a 10Mbps card when the network is working at 100Mbps. In most cases, a 10/100Mbps card solves this problem rather well, but if you want more information about Ethernet, read [Spurgeon 2000].

Remember not to run any network services and not to store any tools beyond what's needed to run the firewall and the intrusion detection software. The basic set of archives (base32 and etc32) should be enough in most cases. If you need the C/C++ compiler and other software development tools (comp32), run them on a workstation machine and transfer the binaries you create on it to the firewall via scp(1). Similarly, the game32, man32, misc32, xbase32, xfont32, xserv32, and xshare32 archives can be left uninstalled, as they only take up valuable storage space (not to mention the fact that, in case of a break-in, they can be used by the intruder for potential attacks).

/etc/rc.conf

Start the OpenBSD packet filter with pfctl(8), its control tool:

$ sudo pfctl -e -f /etc/pf.conf

To start pf(4) automatically on every system reboot, edit /etc/rc.conf, the "system daemon configuration database", with vi(1) or any other plain text editor:

$ sudo vi /etc/rc.conf

After you open /etc/rc.conf, change the following line:

pf=NO                   # Packet filter / NAT

to:

pf=YES                  # Packet filter / NAT

This file contains two more variables file related to pf(4). First is the rule file location variable:

pf_rules=/etc/pf.conf           # Packet filter rules file

Here you can change the location of the rule file from the default /etc/pf.conf to whatever you like, but it's probably best to leave it unchanged. Another variable of interest is:

pflogd_flags=                   # add more flags, ie. "-s 256"

This variable lists options for the pflogd(8) packet filter logging daemon. We'll look at it more closely a little later.

/etc/pf.conf

pf(4) stores its filtering rules in /etc/pf.conf, a plain ASCII file that you can edit with vi(1) or other plain text editor. Every rule is a single, continuous line that begins with a special keyword. Keywords define a macro, set some global variable, or describe an action to take for packets that match a rule. These keywords are

  • set
  • scrub
  • rdr
  • nat
  • binat
  • block
  • pass

Note that /etc/pf.conf contains all rules for both NAT and filtering. (They were previously stored in two separate files.) The rule file is divided into five sections: macro definitions, options, scrub, NAT, and filter. Any of these sections may be missing, but the order of sections must be maintained, as in the following:

#################################################################
# macro definitions

#################################################################
# options: "set"

#################################################################
# scrub rules: "scrub"

#################################################################
# NAT rules: "rdr", "nat", "binat"

#################################################################
# filtering rules: "antispoof", "block", "pass"

When you think about it, this grouping is quite practical: later sections rely on the previous ones, so it is natural to use the order that simplifies the work of the firewall administrator. The order of the rules inside each section is a different story. It depends on your packet filtering policy and will be the subject of interest throughout this series.

Basic pfctl(8) Operations

Here are a few basic pfctl(8) operations that you should memorize, as you'll use them often while designing your own rules:

  • enable pf(4):

    $ sudo pfctl -e
  • enable pf(4) and load rule file:

    $ sudo pfctl -e -f /etc/pf.conf
  • only load pf(4) rule file (no need to disable the packet filter):

    $ sudo pfctl -f /etc/pf.conf
  • parse rules, but do not load them:

    $ sudo pfctl -n -f /etc/pf.conf
  • disable pf(4):

    $ sudo pfctl -d

Macro Definitions

NAT and filter rules can quickly become complex, so it is very convenient to define macros to use in place of real names of network interfaces, addresses, protocols, ports, and other repetitive information found in filter rules. Life is much simpler with macros; they make it easier to adapt existing rule sets to changes in hardware configuration. For example, the only necessary change after modifying the external interface on the firewall machine is to edit the macro definition. Macro names must start with a letter from the a-zA-Z range of the lower part of the ascii(7) set and may contain letters from the same range, digits, and underscores. The string that the macro expands to must be enclosed in a pair of double quotes ("). Macros are not expanded recursively for simplicity and security. When you're referring to a macro, precede its name with a dollar sign ($), as in:

#################################################################
# macro definitions

ext_if  = "ne1"
dmz1_if = "ne2"
dmz2_if = "ne3"

#################################################################
# options: "set"

#################################################################
# scrub rules: "scrub"

scrub in on $ext_if all
scrub in on $dmz1_if all
scrub in on $dmz2_if all

Pages: 1, 2, 3, 4

Next Pagearrow





Sponsored by: