next up previous contents
Next: 4 Firewalling tricks Up: The OpenBSD Packet Filter Previous: 2 Basic firewalling   Contents


3 Filtering Bridges

A bridge, or repeater, is a network device that connects two or more network segments together. It is commonly a simple box, which just repeats any incoming packets on the other network segment(s). However, an OpenBSD server can also be used for bridging, which makes it possible to use PF to filter traffic between the network segments.

This section explains how to set up a filtering bridge using OpenBSD PF. The network used in the examples is a university network, IPv4 network address, consisting of a large number of student workstations, a webserver on, and a shell server on

For security reasons, the university staff would like to separate the network segment the students connect to from the server network segment, and filter the traffic in between, with minimal changes to the network topology.

The decision is made to use an OpenBSD server, with the student network segment connected to interface xl0, and the server network segment connected to interface xl1.

3.1 Two directions

Packets traversing the bridge go through PF twice: they go in through one interface, and come out through the other. So our ruleset must allow both incoming and outgoing traffic, causing us to start with the following ruleset:

   pass in  on xl0 any
   pass out on xl0 any
   pass in  on xl1 any
   pass out on xl1 any

This will allow traffic received on both xl0 and xl1 to enter the bridge, and allow said traffic to be sent to the correct network segment.

3.2 Stateful filtering

The OpenBSD Packet Filter has this really nice feature called keeping state, described in section 2.3, which can be used in the example network to increase the security of the server network segment.

However, there's one thing we have to keep in mind when using stateful filtering: the entries in the state table are indexed by a key consisting of the source- and destination addresses and TCP ports, where the order of these two pairs is relevant. If an outgoing packet from A to B creates an entry in this state table, PF will pass outgoing packets from A to B, and incoming packets from B to A. It will still block outgoing packets from B to A, and incoming packets from A to B, which in the non-bridged case is perfectly clear and obvious.

However, when using state keeping on a bridge, the packet goes through PF twice; it is an incoming packet on one interface, and an outgoing packet on the other.

There are two solutions to this problem. One is to create two entries in the state table for each connection, using two rules with the keep state option. This, however, increases the load on the bridge server, and is not recommended, since the other option is fairly simple and elegant:

From the perspective of PF, packets go through the bridge twice. If you're looking at one interface, you'll see exactly the same traffic, only the direction is reversed. Therefore, we can ignore one interface and do all the filtering on the other.

We'd like to keep state on connections to both the webserver and the shell server, and since we trust the student network the least2, we'll filter on the xl0 interface, simply passing along all traffic on the xl1 interface:

   # some variables

   # allow all traffic traversing xl1
   pass  in  quick on xl1 all
   pass  out quick on xl1 all

   # block traffic on xl0 by default
   block in  on xl0 all
   block out on xl0 all

   # allow connections to the web- and shell server
   pass  in  quick on xl0 proto tcp from any to $web \
                       port = 80 flags S/SA keep state
   pass  in  quick on xl0 proto tcp from any to $shell \
                 port = { 22, 23 } flags S/SA keep state


... least2
A purely psychological reason

next up previous contents
Next: 4 Firewalling tricks Up: The OpenBSD Packet Filter Previous: 2 Basic firewalling   Contents
Wouter Coene 2002-04-05