DNS Interception in OPNsense

The Why

If you have any experience with information technology, as a system administrator or security analyst, for example, then you know how important it is to not just secure your DNS servers, but to log all DNS queries made from inside your network by any client device on the network. Not logging DNS is just not good policy. But in addition to logging DNS, you might want to have a tighter control on where DNS queries are allowed to go on your network.

This post describes how I have DNS interception setup on my network. It’s quite simple: my OPNsense firewall acts as a DHCP server for my LAN, and also as the DNS resolver for the LAN. However, I sometimes have devices on my LAN that I cannot necessarily control as strictly as I like, and you never know what kind of malicious activity might occur if the phone, tablet or laptop of a friend or family member, perhaps already infected, makes its way into your network. All devices pulling addresses via DHCP get the firewall as their DNS server, but what about devices or software that have hardcoded DNS?

As part of the security policy for my home network, I want to force all DNS queries to go to my UTM/firewall, no matter which appliance or software I may be using (e.g. Sophos UTM, OPNsense, pfsense, etc) and no matter what DNS server the request is intended for (Google, Quad9, etc).

The How

I setup NAT and firewall rules to transparently proxy DNS queries that are outbound but not destined for the firewall’s LAN address. This should catch any stray queries made for software that I cannot configure directly (applications that use hardcoded DNS servers, malware, etc).

Let’s set the NAT in Firewall: NAT: Port Forward:

  1. Interface: LAN
  2. Protocol: TCP/UDP
  3. Source: any (if you have a complex network topology you may need to set this to something different)
  4. Destination/Invert: checked
  5. Destination: LAN address
  6. Destination port range: DNS
  7. Redirect target IP: Single host or Network (set it to or the LAN address of the firewall)
  8. Redirect target port: DNS
  9. Description: Type something meaningful here to remind yourself about what it’s for, such as “DNS Proxy” or “DNS Redirect”
  10. NAT reflection: Disable
  11. Filter rule association: None (I prefer to set my own rules, not have them auto-generated)
  12. Save and apply

Note: Keep in mind that in most firewall products, NAT typically happens before routing, and NAT changes a packet’s header, so if you don’t understand what the above does, think of it this way: “For any packet coming from our local LAN, ingressing the LAN interface of the firewall, destined for a DNS server that is not our firewall’s LAN address, alter the packet’s header so that the destination is now the firewall’s LAN address.”

Now let’s set the firewall rule in Firewall: Rules: LAN:

  1. Action: Pass
  2. Interface: LAN
  3. Protocol: TCP/UDP
  4. Source: LAN net (if you have a complex network topology you may need to set this to something different)
  5. Destination: Single host or Network (set it to or the LAN address of the firewall, same as what you did for the NAT above)
  6. Destination port range: DNS
  7. Description: use the same descriptive text you did in the NAT above
  8. Save and apply

The firewall rule is needed to allow the redirected packet to pass through the firewall, like any other rule.

That’s really it. You can run tcpdump to watch the DNS traffic on the firewall in a SSH session, and view the translated/redirected DNS connections in Firewall: Diagnostics: States Dump (use a filter expression of “:53”).

Note: if you run DNS on non-standard ports, you will need to alter the settings to accommodate that. Also, this isn’t going to catch DNS traffic that is encrypted and running on other ports, like 853 for DNS-over-TLS, or if there’s some malicious software running on a system that is attempting to evade a firewall/IDS/IPS.