DæmonNews: News and views for the BSD community

July 2002 BSD Newsletter Get BSD Contact Us Search BSD FAQ New to BSD?
Search


Get BSD Stuff

HOWTO: Transparent Packet Filtering with OpenBSD

Nate Underwood <articles@natey.com>

Introduction

In today's world of broadband Internet technologies such as cable and DSL, IP addresses are often assigned in limited quantity by an ISP. Many of us would like a robust firewall to protect our network, but would rather not waste precious IP addresses. In this article we are going to build a robust, stateful packet filter that uses no IP addresses. Thankfully, OpenBSD provides built-in support for this "invisible firewall" via the bridge interface and the new packet filter, pf.

The Scenario

Let's assume that we currently have cable internet access from an ISP that has provided us with a small number of IP addresses. Because we need all of the addresses for a few workstations and servers, our network is unprotected at this point, with CAT5 cabling running directly from our cable modem to the hub where the workstations and server are connected.

The following diagram (thanks Marek!) shows the inclusion of a regular PC running OpenBSD (our "invisible firewall") that has been inserted inline between the cable modem and the hub.

The finished network topology will look like the diagram below.

Transparent Packet Filtering Topology diagram

Requirements

The minimum requirements for the OpenBSD machine are as follows:

Because our device will not have any interfaces with IP addresses, administration will need to be performed via console, either with a monitor connected to a video card or via serial.

This article assumes that the user is familiar with installing OpenBSD. Please see the OpenBSD website for questions regarding installation or upgrading. A default OpenBSD 3.0 or higher install with the GENERIC kernel will support the bridge/pf configuration.

Bridge Configuration

Once the OpenBSD installation is finished, remove any IP address information that you may have configured during the install. OpenBSD's bridging support is highly evolved: while the bridge operates solely at Layer 2, Layers 3 and 4 can still be filtered and manipulated while in transit through the bridge interfaces by pf.

For more specific information on OpenBSD bridging, please see the man page for bridge.

Setting up the bridge

First, we need to enable ip forwarding between the two network interfaces. Edit /etc/sysctl.conf and uncomment the line that reads: net.inet.ip.forwarding=1

Assuming the 2 bridge interfaces are fxp0 and fxp1 (if your interface names are different, change the interface names accordingly), create the following files with these parameters:

	# ifconfig fxp0 delete
	# echo 'up' > /etc/hostname.fxp0
	
	# ifconfig fxp1 delete
	# echo 'up' > /etc/hostname.fxp1
	
	# echo 'add fxp0 add fxp1 up' > /etc/bridgename.bridge0
Reboot and verify that the bridge is up by running ifconfig -a. You should see output that includes this entry:
	bridge0: flags=41 <UP,RUNNING> mtu 1500
Your bridge is now up and running and we can begin to configure the ruleset for pf.

pf Configuration

pf (Packet Filter) is the packet filtering system in OpenBSD 3.0 and later. Its syntax and functionality are very similar to ipf in both FreeBSD, NetBSD, and earlier versions of OpenBSD. If you are familiar with ipf ruleset syntax, pf syntax should be readable.

Enable pf filtering

In /etc/rc.conf, pf is disabled by default. Use pf=YES to enable. (pf will not actually be enabled until you reboot the machine once again.)

Building the ruleset

Because this is a home network, our ruleset will reflect functionality for a mixed Unix and Windows environment.

Our example filtering requirements:

The default rules in /etc/pf.conf are to allow everything to pass through the filter. We want to narrow this down a bit as seen in the following example /etc/pf.conf. This example assumes your two network interfaces are named fxp0 and fxp1.
	#########################################################################
	# OpenBSD bridged packet filter /etc/pf.conf example
	#
	# Some changes will likely be required for your specific setup!
	
	#### Interface aliases
	# Interface aliases should be created for ease of administration.
	
	ext_if = "fxp0"		# Untrusted (from cable modem) side
	int_if = "fxp1"		# Trusted (to hub/switch) side
	
	#### External Bridge interface rules (allow all in - filter on internal)
	# In bridge mode, we only filter on one interface.
	
	pass in quick on $ext_if all
	pass out quick on $ext_if all
	
	#### Internal Bridge interface rules (main ruleset)
	# Rule order does not matter
	
	# Block (Deny) and LOG everything IN by default
	block in log on $int_if all
	
	### IN RULES
	
	# Allowed incoming tcp services (ssh, https)
	pass in on $int_if proto tcp from any to any port \
	        { ssh, https } \
	        keep state
	
	# Allow http traffic to our webserver
	pass in on $int_if proto tcp from any to 1.2.3.4 port = http keep state
	
	# Allow MS RDP (TCP 3389) from work to win2k server
	pass in on $int_if proto tcp from 2.2.3.4 to 1.2.3.5 port = 3389 keep state
	
	# Allow Certain UDP services IN (DNS, NTP)
	pass in on $int_if proto udp from any to any port \
		{ domain, ntp } \
		keep state
	
	# Allow ICMP (ping) IN
	# pass out/in certain ICMP queries and keep state (ping)
	pass in on $int_if inet proto icmp all icmp-type 8 code 0 keep state
	
	### END of IN RULES
	
	### OUT RULES
	
	# Allow ICMP (ping) OUT
	pass out on $int_if inet proto icmp all icmp-type 8 code 0 keep state
	
	# Pass (Allow) all UDP/TCP OUT and keep state
	pass out on $int_if proto udp all keep state
	pass out on $int_if proto tcp all modulate state 
	
	### END of OUT RULES
	########################################################################
More information and ruleset examples can be found in the pf.conf man page.

Loading and viewing the ruleset

The pfctl command controls the loading and viewing of the rules, as well as a number of other rule-related items (e.g., viewing state tables).

The example /etc/pf.conf is loaded like this:

	# pfctl -R /etc/pf.conf
To view the loaded rules:
	# pfctl -s rules

Logging and Testing

Because we added a log parameter to the block rule in the above example, we can use tcpdump to view traffic on the pf log interface (pflog0) in real time to see the traffic that is being dropped.

To view pf logged traffic in real time:

	# tcpdump -i pflog0
Real-time logging will be shown, which can be extremely helpful in ruleset configuration or any problems that may occur.

One other helpful troubleshooting test that you can run with tcpdump will read the pf logfile (/var/log/pflog) and show you accepted and rejected packets along with a matching rule number.

	# tcpdump -n -e -ttt -r /var/log/pflog
These methods will prove invaluable as you develop more complex rulesets and enable more sophisticated logging.

Thoughts and Conclusion

That's it. We now have an "invisible firewall" capable of stateful packet inspection and advanced capabilities without using any of our precious IP addresses. From a security standpoint this is nearly the perfect firewall solution because of its stealth. It cannot be compromised over the network, cannot be portscanned and doesn't waste IP space. To someone on the outside of your network, denied packets simply mysteriously "disappear" for no apparent reason.

There are many other uses for this kind of invisible or stealth packet filtering, from segmenting flat corporate networks to building a portable invisible traffic monitoring device. You might even add another NIC to it and create an addressed interface that plugs into a secure management VLAN for ease of administration... the possibilities are vast.

I hope this article has been helpful, and I hope that you will find a myriad of ways to incorporate this solution into your particular networking environment.



Author maintains all copyrights on this article.
Images and layout Copyright © 1998-2003 Dæmon News. All Rights Reserved.