Moving From Sophos UTM 9 to pfSense
Table of Contents
Yeah I figure why not, at the same time that I’m replacing another key piece of network infrastructure, I might as well just replace the (second) most important piece, right? So cue the music, because…
Now, this is a story, all about how my life network got flipped, turned upside down, and I’d like to take a minute, just sit right there, I’ll tell you how I became the prince of a town called Bel Air the owner of a… just… just cut the music. Let’s begin.
So, the basics… I upgraded the box that sits between my network and the rest of the internet. (Technically, my network and the rest of the house, but…) In terms of core features, it’s the network router and gateway, and in terms of other features… it’s a firewall. The software package I was using was the UTM 9 (Unified Threat Management) by Sophos, and, if you’re familiar with that name, then you already know it does a lot.
Sophos UTM 9
Note: the successor to this is called Sophos XG, which… I’ve never touched, I just didn’t upgrade.
UTM 9, besides being a pretty standard firewall / NAT device, also did a lot more like application traffic shaping, what’s effectively Snort traffic monitoring, HTTP download virus scanning, URL blocking, email download scanning, email DKIM signing, email spam detection… a lot of things. UTM could even do things like webserver protection, act as an AP controller, so much fun stuff.
It ran mainly off a system called confd
, a central (to the device, in this case) configuration management engine, wrapped up in a nice (and slow) graphical web interface.
To the best of my knowledge, the real backend of the firewall / NAT section is iptables
, which, let’s just say I’m glad it’s much simpler to use graphically.
A home use (non-commercial) version is available for free, licensed for 50 LAN-side IP addresses. This also comes with software and virus database updates.
And one final thing to note that will be important later: the UTM installer checks how many NICs (translated: Ethernet ports) your device has, and it will refuse to run unless there’s at least two, one for the WAN (internet / ISP / “everyone else”) side, and one for the {« abbr LAN “Local Area Network” >}} (own network) side.
pfSense
pfSense is a network firewall application built on FreeBSD.
It doesn’t have all the features of a full UTM, but in some ways it’s a little better.
Besides being FOSS, it’s also based not on iptables
for filtering and routing, but pf
(packet filter) instead, hence the name, pfSense.
Kinda not true, and I’ve switched to OPNsense because of the actions of Netgate, the company that owns and produces pfSense.
See, the free version, called “Community Edition” now, is taking a back seat to “pfSense+,” which is the version that used to be shipped on their own hardware appliances, and is now just straight up being sold.
Naturally, a lot of people are assuming, especially given the recent and past actions of Netgate, that they’re going to start leaving pfSense CE behind to get people to pay up for plus. Also, as much as they claim it’s ‘open source,’ well, those claims don’t really tend to hold up that well when you start to look deeper.
Netgate is really showing terms of being a paranoid company, about to be dethroned by competitors, and has taken some rather fun measures to stop that, including a smear campaign against OPNsense itself, buying the domain A word about pfSense and FOSS
opnsense.com
(THe actual project lives at opnsense.ORG
and running derogatory and misleading content, possibly to confuse people, but we won’t know.
This culminated in a complaint to the World Intellectual Property Organization, and the domain being taken down.
I… really do not feel comfortable supporting a company that does that
Instead of relying on one central configuration manager to keep all the services in check, pfSense makes edits directly, many of them requiring an explicit ‘save’ or ‘apply’ to take effect.
pfSense has a built in package manager to allow installing additional features that have been created by the community, like a .ovpn
(OpenVPN client config profile) file exporter or a Zabbix monitoring agent, but by default you’ve still got quite a few things to play with: IPsec and OpenVPN VPNs, CARP for pfSense high availability, various methods of traffic shaping… and as a router, it’s got decent DHCP and DNS capabilities, with… some quirks.
I’m obviously not going to give you a full, detailed walkthrough, but as a general comparison, the UI looks much cleaner, less cluttered, and feels more responsive, in my opinion, and it’s a very capable system indeed.
pf
Whereas iptables
is a core part of linux at this point, with a list of “chains” of rules that are evaluated top to bottom, and the first one to match within a chain will send the rule to any other specified chain, or specify a final action instead like ACCEPT
or DROP
, pf
uses a rules file, like this:
pass in quick on $IPsec inet from any to any tracker 1597637882 keep state label "VPN"
pass in quick on $OpenVPN inet from any to any tracker 1597540135 keep state label "VPN"
block in quick on $WAN reply-to ( re0 192.168.1.1 ) inet proto tcp from any to any port 23 tracker 1597471764 flags S/SA label "No telnet"
pass in quick on $WAN reply-to ( re0 192.168.1.1 ) inet proto tcp from any to 192.168.5.73 port $Syncthing tracker 1597548003 flags S/SA keep state label "NAT Syncthing"
pass in quick on $WAN reply-to ( re0 192.168.1.1 ) inet proto tcp from any to $BorderProxy port $Jellyfin tracker 1597548009 flags S/SA keep state label "NAT Media server access"
pass in quick on $WAN reply-to ( re0 192.168.1.1 ) inet proto tcp from any to $BorderProxy port $Matrix tracker 1597548015 flags S/SA keep state label "NAT Allow Synapse to fedrerate with Matrix"
pass in quick on $WAN reply-to ( re0 192.168.1.1 ) inet proto tcp from any to $BorderProxy port $NewsTransfer tracker 1597548030 flags S/SA keep state label "NAT Allow NNTP access to blog articles"
pass in quick on $WAN reply-to ( re0 192.168.1.1 ) inet proto tcp from any to $BorderProxy port $Web tracker 1597548036 flags S/SA keep state label "NAT Web access to services"
pass in quick on $WAN reply-to ( re0 192.168.1.1 ) inet proto tcp from any to 192.168.5.20 port 22 tracker 1597548044 flags S/SA keep state label "NAT Allow SSH for Git repos"
pass in quick on $WAN reply-to ( re0 192.168.1.1 ) inet proto tcp from any to 192.168.5.21 port $SSHAlt tracker 1597548050 flags S/SA keep state label "NAT Allow SSH for other VCS repos"
If you read it left to right it actually just spells out what to do:
pass
: Pass (allow)in
: Incoming trafficon $WAN
: On the WAN interfacereply-to ( re0 192.168.1.1 )
: (send all replies to192.168.1.1
NOT the original source)inet
: That’s IPv4 traffic, not IPv6proto tcp
: Using TCPfrom any
: Coming from anywhereto $BorderProxy
: Going to$BorderProxy
(user alias,192.168.5.200
)port $Jellyfin
: Destined for port$Jellyfin
(user alias,8096
)flags S/SA
: Inspect theSYN
andACK
flags, and only match traffic with theSYN
flag set and theACK
flag unsetkeep state
: When matched, add a state entry to allow further communications through
While cool, it’s also a headache to understand.
Like for example, notice how all the rules say quick
?
pf
evaluates top to bottom, but the last rule that was matched will decide the outcome, not the first.
The quick
keyword causes rule evaluation to end right there, meaning that by putting quick
on every rule, it’s effectively a first match wins again.
The user interface here automatically sets quick
since it presents the rules table in a top-to-bottom, first match wins order.
This firewall just by itself is very powerful, with the ability to match many protocols (not just TCP / UDP), inspect arbitrary flag combinations, state tracking, and a rule can even, as a bonus action, set what processing queue to filter matched traffic into (for traffic shaping).
DHCP Quirks
Both UTM and pfSense offer DHCP to their LAN side, presented in a nice DHCP lease table. In Sophos UTM, from here you can press “Make static” and it’ll bring up the network host creation dialog with the host MAC, current IP, and hostname all pre-filled. You can assign any valid IP address to this, then save it. Next time it tries to renew it’s lease, it’ll be sent the static reservation data.
pfSense can do the same thing, except it only fills in the MAC address, you have to specify the IP, hostname (useful for (r)DNS), additional DNS servers (overrides global setting), and other pieces.
You also *cannot assign a static reservation within the DHCP range.
It just straight-up won’t let you.
For example, if my DHCP range is set for 192.168.5.20
–192.168.5.200
, then adding a static for 192.168.5.53
will just give me an error.
For the technical reasons, the DHCP service doesn’t take static reservations out of the DHCP pool, meaning that if it allows this to happen, it can actually double-book an address, giving the same IP to two different hosts, which is uh… kinda a big deal.
With pfSense, you’ll want to set the DHCP range to be a sort of “guest” address range, and make reservations for permanent clients that reside outside of that range.
For me, that means 100
–199
is the DHCP range, if a host is not in that range, I’ve made it static.
Two Interfaces, One NIC
And now for something that pfSense can do that UTM can’t: Run with one physical NIC. This is because the installer lets you configure the default LAN and WAN interfaces not just as a particular network card, but also a VLAN tag, if it needs one. I’ve already see this in practice, for example, default, untagged packets are the LAN side, and VLAN 10 tagged packets are the WAN side. It’ll take this and… just work, assuming the switch(es) that are handling the VLANs are handling it correctly. Meaning if you want to be budget, just about any device can become a network router and firewall if you have a VLAN-capable switch.