HOWTO - Redirect all DNS Requests to Opnsense

Started by Cypher100, July 26, 2018, 03:16:37 AM

Previous topic - Next topic
# My OPNsense + Proton VPN + Oracle Cloud Recursive DNS Journey (WireGuard + VLANs + DNS Hijacking)

Hi everyone,

I wanted to share a project I've been working on over the last few days with OPNsense. I still consider myself a beginner/newbie with OPNsense specifically, but I honestly had a lot of fun building and troubleshooting this environment over roughly 3 days.

The amount of flexibility OPNsense provides is honestly impressive.

My goal was to build a segmented home/lab network with:

* VLAN isolation
* forced DNS
* recursive DNS with filtering
* private DNS transport over WireGuard
* selective VPN routing
* RFC1918 local bypass
* cloud-hosted DNS
* clean routing logic

I also wanted to understand *why* things worked, not just copy/paste configs.

I'm posting this because I learned a lot during the process and maybe it helps someone else trying to build a similar architecture.

All sensitive information below is sanitized:

* no real public IPs
* no private keys
* no preshared keys
* no exact cloud identifiers

---

# Physical Infrastructure

Current hardware/network:

* OPNsense firewall/router
* 2x Layer-3 switches
* SFP56 fiber interconnects between switches
* dual fiber uplinks between switches
* multiple VLANs
* Oracle Cloud VM
* Proton VPN WireGuard tunnels

I will also add:

* a third access switch

because the current switches are 24-port models and I'm starting to run out of ports.

The switches are connected through:

* SFP56 fiber
* 2 physical links between them

The idea is eventually to continue expanding VLAN segmentation and lab environments.

---

# High-Level Goal

The final design became:



Clients
→ OPNsense
→ DNS hijacking / local forwarding
→ WireGuard tunnel
→ Oracle Cloud recursive DNS
```

while one VLAN uses Proton VPN for Internet egress:

```text id="xv7fzo"
VLAN100
→ Proton VPN
→ Internet
```

and all internal RFC1918 traffic stays local.

---

# Sanitized Topology Diagram



The diagram includes:

* VLAN layout
* WireGuard topology
* Proton VPN tunnels
* Oracle Cloud recursive DNS
* DNS flow
* PBR logic
* security controls
* validation tests

All IPs are sanitized intentionally.

---

# VLAN Layout

Current VLANs:

```text id="6b6rk4"
VLAN50  Users
VLAN60  IoT
VLAN70  General
VLAN80  Lab
VLAN90  Management
VLAN100  PowerUser
VLAN240  Infra
```

Each VLAN has:

* its own gateway
* firewall rules
* DNS handling
* routing policy

---

# DNS Architecture

Initially I was forwarding DNS from OPNsense to Oracle Cloud using the Oracle public IP.

That worked, but I quickly realized:

* source IP changes become annoying
* VPN exits complicate ACLs
* public DNS exposure is unnecessary

So I built a dedicated WireGuard tunnel between:

* OPNsense
* Oracle Cloud

Now DNS travels privately:

```text id="sv3m8j"
OPNsense
→ wg2
→ Oracle wg0
→ Unbound recursive DNS
```

This was validated using:

```bash id="6np8n5"
tcpdump -ni wg2 port 53
```

I could clearly see:

```text id="j6v1p8"
OPNsense-WG-IP → Oracle-WG-IP:53
```

which confirmed DNS was traversing the private tunnel.

---

# Important Discovery #1

## OPNsense Uses Round-Robin DNS Behavior

One thing I discovered:

If multiple DNS servers are configured under:

```text id="vppfjt"
System → Settings → General
```

OPNsense appears to use them in a round-robin-like manner.

That caused confusion during testing because:

* some queries used Oracle
* others used another resolver

For clean validation and predictable behavior:

* I ended up using only the Oracle WireGuard DNS server.

This made troubleshooting MUCH easier.

---

# Important Discovery #2

## WireGuard Instances Must Use Different Ports

Another thing that confused me initially:

Different WireGuard instances on OPNsense should use different listen ports.

Example:

```text id="o1pl5j"
wg0 → 51820
wg1 → 51830
wg2 → 51840
```

When multiple instances were using overlapping/default ports, behavior became inconsistent.

After assigning unique ports:

* everything stabilized immediately.

---

# Important Discovery #3

## WireGuard Key Logic

This was another major learning point for me.

The rule is simple:

```text id="9blz0y"
Your device keeps its own private key.
The peer gets your public key.
```

So on OPNsense:

```text id="0twd1z"
Instance:
- OPNsense private key

Peer:
- Oracle public key
```

On Oracle:

```text id="4ujpx3"
Interface:
- Oracle private key

Peer:
- OPNsense public key
```

The preshared key:

* must match on both sides
* but does NOT replace public/private key authentication.

At first I was confusing:

* public keys
* private keys
* preshared keys

especially because Proton VPN client configs look different from traditional WireGuard server configs.

---

# Important Discovery #4

## Cloud Firewalls + OS Firewalls Both Matter

This was another very important lesson.

When working with cloud VMs, you often have:

* cloud-level security rules
* operating system firewall rules

Both must allow the traffic.

In my case:

* Oracle Cloud security lists / NSGs had to allow:

  * WireGuard UDP port
  * DNS traffic
* Ubuntu itself also needed firewall rules

Even after Oracle Cloud allowed the traffic, DNS still failed until I allowed it locally on Ubuntu.

Example:

```bash id="0w7b1s"
sudo iptables -I INPUT 1 -i wg0 -p udp --dport 53 -j ACCEPT
sudo iptables -I INPUT 1 -i wg0 -p tcp --dport 53 -j ACCEPT
```

So the troubleshooting sequence became:

```text id="1rj4z9"
Cloud security rules
→ Linux firewall
→ Service binding/listening
→ routing
```

This was probably one of the biggest troubleshooting lessons from the whole project.

---

# Proton VPN Setup

I configured:

* Proton UAE
* Proton Switzerland

using WireGuard.

Important detail:

* I did NOT route the whole firewall through Proton.

Instead:

* only VLAN100 uses Proton through Policy-Based Routing.

This keeps:

* management stable
* OPNsense updates clean
* troubleshooting easier

while still allowing selected clients to use VPN egress.

---

# PBR (Policy-Based Routing)

The key logic:

```text id="z3b6q8"
Default VLANs
→ WAN

VLAN100
→ Proton VPN
```

For VLAN100 I added:

1. RFC1918 bypass rule
2. Proton gateway rule

in that order.

That means:

```text id="yp9u4r"
Internal traffic
→ local routing

Internet traffic
→ Proton VPN
```

This solved:

* local access issues
* inter-VLAN communication
* NAS/server access problems

while still tunneling Internet traffic.

---

# DNS Hijacking

All VLANs now use DNS hijacking rules.

If a client tries:

```text id="iq6jrf"
8.8.8.8
1.1.1.1
9.9.9.9
```

the request gets redirected back to OPNsense.

Then:

```text id="x0s2d2"
OPNsense
→ Oracle over WireGuard
```

This ensures:

* filtering
* DNSSEC
* logging consistency
* centralized control

---

# Oracle Cloud DNS Server

Oracle Cloud VM runs:

* Ubuntu
* WireGuard
* Unbound recursive DNS
* DNSSEC
* HaGeZi blocklists
* TIF threat feeds

Unbound receives DNS from OPNsense through WireGuard only.

I also modified iptables to:

* allow DNS from wg0
* allow WireGuard UDP
* restrict unnecessary exposure

---

# Validation Tests I Used

## Verify WG Route

```bash id="wsc9d3"
route -n get <oracle-wg-ip>
```

Expected:

```text id="20y5zy"
interface: wg2
```

---

## Verify DNS Through WG

```bash id="3h5m9r"
tcpdump -ni wg2 port 53
```

Then:

```bash id="otm32j"
dig google.com
```

Expected:

```text id="vw2m7i"
WG-IP → WG-IP:53
```

---

## Verify Proton Exit

From VLAN100:

```bash id="quvb8f"
curl ifconfig.me
```

Expected:

* Proton public IP

---

## Verify OPNsense Still Uses WAN

From OPNsense shell:

```bash id="wq1pp9"
curl ifconfig.me
```

Expected:

* ISP WAN IP

This was intentional.

I did NOT want the firewall itself depending on the VPN.

---

# Current Status

Everything is now operational:

* Proton VPN working
* Oracle WireGuard tunnel working
* DNS over WireGuard validated
* VLAN100 PBR validated
* DNS hijacking validated
* DNSSEC validated
* recursive DNS validated
* RFC1918 bypass working
* internal access preserved

---

# Next Improvements

Some of the next things I plan to implement:

* EAP-TLS certificate-based Wi-Fi authentication
* additional VLAN segmentation
* third access switch deployment
* improved monitoring
* maybe HA/failover later
* physical topology documentation
* additional DNS hardening
* more management isolation

I'm especially interested in moving toward:

* WPA-Enterprise
* EAP-TLS
* certificate-based authentication

instead of relying only on traditional PSKs.

---

# Final Thoughts

Honestly, I started this mostly wanting to "play" with OPNsense and learn more deeply how:

* routing
* WireGuard
* DNS
* VLANs
* firewall rules
* recursive DNS

all interact together.

It became a much bigger learning experience than expected.

I still consider myself a beginner with OPNsense specifically, but I'm really impressed with:

* flexibility
* visibility
* debugging capabilities
* policy routing
* WireGuard integration
* overall architecture possibilities

The troubleshooting tools alone:

* tcpdump
* route inspection
* firewall logs
* live states

made learning much easier.

Hopefully this helps someone trying something similar.

Here is an excerpt of my configurations, related to DNS and NTP redirection:

DNS and NTP redirection

Goals to solve with this solution:
- Provide local DNS services to clients.
- Redirect client attempts to circumvent local DNS, back to local DNS services
- Force clients to only use DNS UDP port 53 via their IPv4 address
- Block attempts to use port DNS over TLS port 853
- Block client access, to as great extent as possible, from accessing servers known to host DNS services via any protocol.

Pre-Requisites:

Firewall :: Categories (Optional step, including Categories used below)

Automatic: [ ] Unchecked

Name             # Color
0Frequent        0084ff
ASN              e7bc98
Danger           ff0000
Danger0          ff7f7f
Danger2          fa6400
Danger3          ffeb00
Danger4          ee00ee
Excep            808080
Firewall         ffffff
Host             84542a
Ingres           00ff00
Ingres0          80ff80
Ingres2          00bf00
Local            00ffff
Net              b37e52
Port             c990dd

Firewall :: Groups (Firewall Interface Groups)

Name        Members                           Description
    My Example:
LANs        <All Local except WANs>           
LANs        ex: OoB, LAN, GST, MGT, IoT, NVR  All Local networks, excluding virtual interfaces like OpenVPN, and WANs
    Policy Approach Example:
DNScli      LAN, GST, ...                     Interface networks you want to force local DNS

Firewall :: Aliases

Name:        danger_port
Type:        Port(s)
Categories:  Danger0, Port
Content:     853
Description: Block Dangerous Egress Ports
Notes:       This is part of a list of Ports I consider dangerous to access on the Internet.
             If you want more ports, or have your own, let's share

Name:        excep_local_nets_net
Type:        Network(s)
Categories:  Excep, Local
Content:     !10.0.0.0/8,!172.16.0.0/12,!192.168.0.0/16,!127.0.0.0/8,!::1/128,!127.0.0.1/32,!fc00::/7
Description: Local Default Networks Exclusion
Notes:       This list of networks are used to clean up external Block Lists.
             It is possible to receive a list with local CIDR blocks,
             and be remotely hosed from your own local networks.

Name:        danger_symm_url_aRaw
Type:        URL (IPs)
Categories:  Danger2
Content:     https://raw.githubusercontent.com/crypt0rr/public-doh-servers/refs/heads/main/ipv4.list
             https://raw.githubusercontent.com/crypt0rr/public-doh-servers/refs/heads/main/ipv6.list
             https://raw.githubusercontent.com/dibdot/DoH-IP-blocklists/refs/heads/master/doh-ipv4.txt
             https://raw.githubusercontent.com/dibdot/DoH-IP-blocklists/refs/heads/master/doh-ipv6.txt
             https://raw.githubusercontent.com/oneoffdallas/dohservers/refs/heads/master/iplist.txt
             https://raw.githubusercontent.com/oneoffdallas/dohservers/refs/heads/master/ipv6list.txt
Description: Block Symmetric URLs raw
Notes:       This is part of a list of URLs to Block lists of IP addresses.
             These IP addresses must not be accessed, and should not be accessing you.
             If you want more ports, or have your own, let's share

Name:        danger_symm_url_aGrp
Type:        Network group
Categories:  Danger2
Content:     excep_local_nets_net,danger_symm_url_aRaw
Description: Block Symmetric URL Group
Notes:       Fuses the two above lists to sanitize the input of the external block lists.
             The WANs rules to use this alias, are not discussed in this tutorial.

Name:        fw_port_svc_rdr
Type:        Port(s)
Categories:  Firewall, Port
Content:     53,123
Description: Firewall Redirect Egress Ports DNS NTP
Notes:       Confines a client from accessing a DNS or NTP server,
             A NAT rule will loop a request back to the Firewall or whatever destination you choose.

Firewall :: NAT :: Destination NAT

Description: Fwd DNS NTP to FW
Interface:   LANs, OpenVPN (Or other Interfaces, or Firewall Interface Groups you created)
Version:     IPv4          (Do NOT specify IPv6, that way it is easier to know who accesses services)
Protocol:    TCP/UDP
Source ::
  Invert Source:  [X]
  Source Address: This Firewall
  Source Port:    any
Destination ::
  Invert Source:  [X]
  Source Address: This Firewall
  Source Port:    [ fw_port_svc_rdr       v ]
  Pool Options:   Default
Options ::
  No RDR (NOT):   [ ]
  Log:            [ ]
  No XLMRPC Sync: [ ]
  NAT Reflection: [ Disable   v ]
  Set Tag:        [             ]
  Match Tag:      [             ]
  Firewall rule:  [ Manual    v ]

Description: Fwd NTP6 to FW
Interface:   LANs, OpenVPN (Or other Interfaces, or Firewall Interface Groups you created)
Version:     IPv6          (Do NOT specify IPv4, that is handled above)
Protocol:    TCP/UDP
Source ::
  Invert Source:  [X]
  Source Address: This Firewall
  Source Port:    any
Destination ::
  Invert Source:  [X]
  Source Address: This Firewall
  Source Port:    [ Single port or range  v ]
                  [ 123                     ]
  Pool Options:   Default
Options ::
  No RDR (NOT):   [ ]
  Log:            [ ]
  No XLMRPC Sync: [ ]
  NAT Reflection: [ Disable   v ]
  Set Tag:        [             ]
  Match Tag:      [             ]
  Firewall rule:  [ Manual    v ]


:::::: So far, this will cover redirecting services 53 and 123, now we block circumvention ::::::

Firewall :: Rules [New] or classic, same concept

Act Dis Ifaces Ver Proto Source           SPrt Destination           DstPort     Log Description          Categories
Prm [ ] *      4,6 Any    This Firewall   *     any                              [ ] FW Prm Anything      Ingres,Firewall
  Notes: Prevent your firewall from blocking access to external resources
Blk [ ] *      4,6 TC/UD  local_link      *     any                  53 (DNS)    [X] Blk Link Local DNS   Danger0,Local,Port
  Notes: Prevent link local addresses in both IPv4 and v6 from accessing DNS anonymously
Blk [ ] *      4,6 Any    local_link      *    !This Firewall                    [X] Blk Link Local Final Danger0,Local,Net
  Notes: Block remaining link local access that was not blocked from Default rules
Blk [ ] *       6  TC/UD  local_net_aGrp  *     any                  53 (DNS)    [X] Blk Local DNS6       Danger0,Local,Port
  Notes: Completely block clients with a Unicast IPv6 address, from accessing DNS anywhere.
         Clients can lookup AAAA records via v4 address.
Blk [ ] *      4,6 TC/UD  local_net_aGrp  *    !local_net_aGrp       danger_port [X] Blk Egr Danger Ports Danger0,Local,Port
  Notes: Block Dangerous ports, or at least port 853 for everyone except the firewall.
Prm [ ] *      4,6 Any    Excep network   *     excep_egr_url_aGrp               [X] Prm Egr Excep URL    Danger2,Excep
  Notes: The exception rule allows a trusted device to by-pass the block rule below, it is not discussed in this tutorial.
Blk [ ] *      4,6 Any    *               *     danger_symm_url_aGrp             [X] Blk Egr Danger URL   Danger2
  Notes: Block clients from accessing IP address lists known to serve DNS via any UDP, DNS over HTTPs, DNS over TLS, etc.


Please set a CRON rule to refresh your Aliases and DNS block lists.

Please feel free to ask questions
It is probably not fool-proof 100%,
I'm always open to improvement

Sources:
- This tutorial thread https://forum.opnsense.org/index.php?topic=9245.0
- https://github.com/dibdot/DoH-IP-blocklists
- https://github.com/oneoffdallas/dohservers/tree/master
- https://github.com/crypt0rr/public-doh-servers/tree/main