June 26, 2012

A transparent firewall using OpenBSD

Filed under: UNIX/Linux/BSD — Tags: , — martin @ 1:46 pm

I wanted to enforce a different security policy for a given part of the home network, but without the introduction of separate subnets and static routes all over the place. So I started to experiment with a transparent firewall, on OpenBSD.

To accomplish this, what is needed first, is a bridge interface. A bridge interface is comprised of multiple (frequently 2) ethernet interfaces and transparently forwards traffic between the two interfaces. Very much like a 2-port ethernet switch would, or like a wireless bridge does.

If you have worked with bridges on Linux, configuration on OpenBSD works confusingly different than what you already know.

First, we have the configuration file /etc/hostname.bridge0, that specifies the interfaces that will be bridged:

# /etc/hostname.bridge0:
add vr0
add vr1
blocknonip vr1

If you are not concerned about non-IP traffic compromising the security of your bridging firewall, you may omit the option blocknonip here. The interface vr1 connects to the “restricted” part of the network here and for this example, I don’t want non-IP protocols such as NetBIOS to slip through.

Next, one of the two underlying interfaces is configured as if the bridge didn’t even exist. This will be the IP address of the bridge, here in /etc/hostname.vr0:

# /etc/hostname.vr0:
inet6 2001:db0:1:2::3 64

And the additional interface for the bridge is only brought “up” in /etc/hostname.vr1:

# /etc/hostname.vr1:

After a reboot, the bridge will be forwarding packets, without the need to enable IP forwarding and without enabling the firewall.

Now I can start adding firewall rules in /etc/pf.conf:

# /etc/pf.conf:

# The interface on the open network

# The interface on the restricted network

# I don't believe in dropping packets
set block-policy return

# Leave the loopback interface unfiltered
set skip on lo

# Pass out what's already inside the firewall
pass out on vr0 all
pass out on vr1 all

# Pass in everything coming from the open network
pass in on $PUBLIC_IF

# Reject everything coming from the restricted network
block in on $RESTRICT_IF

# Restricted network may talk to the world
pass in on $RESTRICT_IF inet
pass in on $RESTRICT_IF inet6

# But not to the open network
block in on $RESTRICT_IF from any to
block in on $RESTRICT_IF from any to 2001:db8:1:2::/64

# Allow access to the site's DNS server 
pass in on $RESTRICT_IF proto {tcp,udp} from any to port 53

# Allow access to this single SSH service
pass in on $RESTRICT_IF proto tcp from any to port 22
pass in on $RESTRICT_IF proto tcp from any to 2001:db8:1:2::b port 22

# Pass ICMP in all directions
pass proto {icmp, icmp6}

And that’s about it. What I have here is really just a rough example of what can be done. Bridging over 3 or more interfaces is possible, if you enjoy the complexity.

With basic firewalling out of the way, it is also possible to filter by MAC address. For this, we need to tag some traffic, e.g. a “trusted client”, directly on the bridge:

ifconfig bridge0 rule pass in on vr1 src 00:1c:c6:8b:ae:3b tag TRUSTEDCLIENT

(Append this, excluding the leading “ifconfig bridge0”, to /etc/hostname.bridge0 to make it permanent.)

In /etc/pf.conf, we can then filter by tag:

# Allow all traffic from trusted MAC addresses

Or, more specific:

pass in on $RESTRICT_IF proto tcp all port 22 tagged TRUSTEDCLIENT

Combining MAC filters with other filter criteria is of course possible. Please make up your own mind about whether and how you want to use this.

A final word on performance: With both interfaces working in promiscuous mode, stress on the firewall’s CPU can be expected to be rather high. This 100 Mbps bridge with a 500 MHz AMD Geode CPU will reach a CPU load of 70% while moving no more than 85 Mbps on a single TCP connection.

Leave a Comment »

No comments yet.

RSS feed for comments on this post. TrackBack URI

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Create a free website or blog at WordPress.com.

%d bloggers like this: