Multi-WAN DNS in pfSense

Update: I later figured out there are many other places pfSense restarts Unbound, so this is simply not worth the effort. I reversed the changes & moved Unbound to another box and using just DNS forwarder on pfSense — which is used by the Unbound server.

Having multiple broadband connections at home, I have a pfSense which takes care of load balancing and firewalling. pfSense is pretty good in almost everything, except one thing that was annoying me a lot — That it restarted the DNS Resolver (Unbound) every time either of my WAN connections restarted (one of my ISPs restarts the connection periodically), and the traffic originating from the box itself cannot be load balanced across multiple connections due to a limitation in FreeBSD’s implementation of pf itself – it is unable to set the correct source address.

It’s quite annoying that – even when you use the forwarding mode of Unbound, your DNS still goes through a single WAN interface. Moreover, Unbound doesn’t seem to do parallel querying across DNS servers. So if you have listed multiple DNS servers as forwarders it will try them one by one as they fail. Suppose, the WAN interface from which DNS traffic is outgoing is running at full capacity – a download or somebody is streaming a video, then your browsing becomes slow as well – but the browsing itself may go through another WAN connection. Notably, for having a stable multi-WAN setup in pfSense – you have to use forwarding mode. The gateway switching for the box itself doesn’t work reliably in my experience, due to which I’ve had to face “host not found” error messages even when one of the connections was up.

Solution: Use both DNS Forwarder (DNSMasq) and DNS Resolver together. Why not just forwarder? Because Unbound is a better DNS server – in terms of performance and security. And DNSMasq has an excellent feature that’s probably not available in any DNS Forwarder or Resolver – the ability to send parallel queries to the upstream servers. It’s called the all-servers option and what it does is – when it receives a query for domain X, it will send the query to all the servers and return the first response it receives – so you get the response extremely fast.

Basically, run the forwarder on a different port, listening on local host and let it do the actual forwarding to your DNS servers instead of Unbound directly talking to your upstream DNS servers. You may argue that the performance benefits of using Unbound may get negated by using the DNS Forwarder as upstream to Unbound – probably yes, but probaby no too – because of the parallel query part. Moreover, DNSMasq is exclusively used for relaying queries between Unbound and upstream servers – nothing else, not even caching. So that should possibly remove any bottlenecks in their. Personally I’ve used DNSMasq as the only server in the past and it was pretty fast in terms of user experience – I haven’t compared benchmarks and I’m not interested in doing that either.

So go to Services => DNS Forwarder in pfSense and configure it with following settings:

Capture

Then in the custom options box, put the following:

no-negcache
cache-size=0
resolv-file=/var/run/resolv.conf

You may be wondering why I’ve specified a different resolv.conf file here, it’s to prevent DNSMasq from using Unbound as a DNS server. That can be achieved by tweaking the “Disable DNS Forwarder” flag in System => General setup, but that would mean the box’s DNS will become slower. I want to use Unbound for the pfSense box too, but DNSMasq should not use Unbound.

Then in DNS Resolver settings:

Disable Forwarding Mode – Otherwise pfSense will put in the configured upstream DNS  servers in Unbound’s configuration.

In custom options box:

server:
  do-not-query-localhost: no
forward-zone:
  name: "."
  forward-addr: 127.0.0.1@5353

Further, to prevent Unbound from restarting whenever your WAN connection is restarted –

  • SSH to your pfSense box
  • Open /etc/rc.newwanip in your favorite editor, go to line 228 which calls a function services_unbound_configure(). Comment the line.
  • Then open /etc/inc/system.inc, go to line 175 which opens /etc/resolv.conf for writing and replace it with:
$fd = fopen("/var/run/resolv.conf", "w");

Then in System => General setup, tick the box which says “Do not use the DNS Forwarder/DNS Resolver as a DNS server for the firewall”. Now, pfSense will write the real resolv.conf based on your configured DNS servers or whatever your ISP supplies (configurable in General Setup) to /var/run/resolv.conf and in /etc/resolv.conf just put one line:

nameserver 127.0.0.1

This will ensure that the pfSense uses Unbound as it’s resolver, so immune to WAN failures.

So now, the DNS works something like this:

Client => Unbound => DNSMasq => Upstream DNS Server

Here, client can be any client on the LAN or pfSense itself. And because of the all-servers feature of DNSMasq, both WAN connections will get used for DNS traffic and choking of one line will not cripple DNS.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

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

Facebook photo

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

Connecting to %s

%d bloggers like this: