Unbound + WireGuard VPN with LAN DNS Access Issue

Hello everyone,

I’ve been using DietPi for a few weeks and I truly love it. I even donated to the project recently too. However, I’ve run into an issue that I can’t seem to resolve.


What I’m Trying to Achieve

  1. Unbound as LAN’s DNS Resolver
    All LAN devices (e.g., phones, laptops) should query Unbound on the DietPi system for DNS.

  2. Unbound’s Upstream Queries via VPN
    Unbound’s upstream queries (to root servers) should always go through the WireGuard VPN (Mullvad), ensuring privacy.

  3. Fallback Behavior

    • If the VPN goes down, LAN devices should still be able to query Unbound for cached results.
    • Unbound should not bypass the VPN for upstream queries under any condition.
  4. AdGuard as a Filter
    I’m using AdGuard Home as a filter between LAN devices and Unbound.


System Details

  • DietPi Version:
    G_DIETPI_VERSION_CORE=9, G_DIETPI_VERSION_SUB=8, G_DIETPI_VERSION_RC=0
  • Git Branch:
    master
  • Kernel:
    Linux DietPi 6.1.21-v7+ #1642 SMP Mon Apr 3 17:20:52 BST 2023 armv7l GNU/Linux
  • Distro:
    bookworm
  • Platform:
    RPi 2 Model B (armv7l)

What Works

  1. Unbound and WireGuard Together:

    • When I let WireGuard route all traffic for the DietPi system without adding iptables rules, everything works perfectly:
      • DietPi resolves DNS locally.
      • LAN devices can query Unbound via AdGuard and receive DNS responses.
  2. Unbound Without VPN:

    • Without WireGuard, LAN devices can query Unbound via AdGuard and get DNS responses without any issues.

What Doesn’t Work

When WireGuard is active and iptables rules are applied:

  1. LAN devices fail to get DNS responses from Unbound.
  2. AdGuard logs the DNS queries from LAN devices, but Unbound does not respond.
  3. LAN devices lose internet connectivity entirely when they rely on DietPi for DNS.

Configuration

WireGuard Configuration

/etc/wireguard/se-got-wg-002.conf:

[Interface]
PrivateKey = <Private Key>
Address = Mulvadip/32
DNS = 127.0.0.1
PostUp = ip rule add fwmark 0x1 lookup 100
PostUp = ip route add default dev %i table 100
PostUp = iptables -t mangle -A OUTPUT -m owner --uid-owner unbound -j MARK --set-mark 0x1
PostUp = iptables -A INPUT -s 192.168.0.0/16 -p tcp --dport 5335 -j ACCEPT
PostUp = iptables -A INPUT -s 192.168.0.0/16 -p udp --dport 5335 -j ACCEPT
PostDown = ip rule del fwmark 0x1 lookup 100
PostDown = ip route del default dev %i table 100
PostDown = iptables -t mangle -D OUTPUT -m owner --uid-owner unbound -j MARK --set-mark 0x1
PostDown = iptables -D INPUT -s 192.168.0.0/16 -p tcp --dport 5335 -j ACCEPT
PostDown = iptables -D INPUT -s 192.168.0.0/16 -p udp --dport 5335 -j ACCEPT

[Peer]
PublicKey = <Peer Public Key>
AllowedIPs = 0.0.0.0/0
Endpoint = <WireGuard Server IP>:51820

Unbound Configuration

/etc/unbound/unbound.conf.d/dietpi-unbound.conf:

server:
    interface: 127.0.0.1
    port: 5335
    access-control: 192.168.0.0/16 allow
    private-address: 192.168.0.0/16
    do-daemonize: no
    num-threads: 1

AdGuard Configuration

  • Upstream DNS: 127.0.0.1:5335
  • Private Reverse DNS Resolvers: 127.0.0.1:5335

Troubleshooting Steps Tried

  1. Removed All iptables Rules:

    • When WireGuard is disabled, DNS works for LAN devices.
    • When WireGuard is active without iptables rules, LAN devices still fail to get DNS responses.
  2. Modified iptables Rules:

    • Added specific rules to allow LAN traffic (192.168.0.0/16) to access Unbound on port 5335.
    • Unbound still doesn’t respond to LAN devices while routing its upstream traffic through WireGuard.
  3. Verified Mullvad VPN Config:

    • Created a new WireGuard key with DNS hijacking disabled using Mullvad’s API.
    • Tested the WireGuard connection with the new configuration and verified that Unbound uses the VPN for upstream queries.
  4. Checked Logs:

    • AdGuard logs show the queries from LAN devices, but there’s no resolution.
    • Unbound logs show no errors for local queries.
  5. Reset iptables Rules:

    • Reset all iptables rules (iptables -F) and ensured there are no other interfering rules.

Current Observations

  1. Without any iptables modifications, WireGuard works fine, and DietPi itself can resolve DNS queries.
  2. LAN devices cannot get DNS responses from Unbound as long as WireGuard is active, even with permissive iptables rules.
  3. It appears the iptables rules restricting Unbound’s upstream traffic to WireGuard might also prevent it from responding to LAN devices.

Logs and Outputs

iptables -L -v after resetting:

Chain INPUT (policy ACCEPT 113 packets, 8300 bytes)
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
Chain OUTPUT (policy ACCEPT 67 packets, 8480 bytes)

Unbound works locally:
Command: dig @127.0.0.1 -p 5335 example.com

;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 14006
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
example.com. IN A 93.184.215.14

AdGuard logs DNS queries from LAN devices, but Unbound does not respond.


Request for Help

I’m reaching out to see if anyone has successfully set up a similar configuration. Specifically:

  1. How can I allow LAN devices to query Unbound while ensuring Unbound’s upstream traffic is routed through WireGuard?
  2. Are there any additional iptables or routing rules I should use to fix this?

Thank you in advance for your advice and guidance.

Also if anyone encounters the same problem with Mullvad. this is how you can get a device that has DNS hijacking disabled

# Authenticate to Mullvad and store the returned access token
access_token=$( \
  curl -X 'POST' 'https://api.mullvad.net/auth/v1/token' \
    -H 'accept: application/json' -H 'content-type: application/json' \
    -d '{ "account_number": "YOUR MULLVAD ACCOUNT NUMBER" }' \
  | jq -r .access_token)

# Create a new Mullvad Device with DNS hijacking disabled
curl -X POST https://api.mullvad.net/accounts/v1/devices \
  -H "Authorization: Bearer $access_token" -H 'content-type: application/json' \
  -d '{"pubkey":"YOUR WIREGUARD PUBLIC KEY","hijack_dns":false}'