dns

Mullvad VPN, by default, hijacks DNS queries inside VPN tunnels and reroutes them to their own DNS servers. For most users, this is probably a good thing — your devices that try to ignore system DNS settings are still forced into using a more secure DNS. But, it can break things if you want to use unbound, for example.

To get around this, I’ll be using the Mullvad API directly to generate a certificate which does not do this.

See also

To summarize that article somewhat, drop the following in a Bash script and edit the <<INFO HERE>> points:

# 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}'

Using this with OpenWRT

If you want to use a certificate like this for a Whole-Network VPN routing setup, the OpenWRT Wireguard interface can be confusing (or at least was to me).

  1. In OpenWRT LuCI Network Interfaces, select Add New Interface…
  2. Give the interface a name, and select a protocol of Wireguard VPN
  3. In the interface General Settings, select the following:
    1. Disable this interface: unchecked
    2. Bring up on boot: checked
    3. Click Generate new key pair
      1. Note the Public Key. This is what goes in the <<YOUR WIREGUARD PUBLIC KEY>> in the Bash script.
  4. Run the bash script, and note the following from its output:
    1. name: note for future use
    2. ipv4_address: note for future use
    3. ipv6_address: note for future use
  5. Return to the Wireguard interface options in OpenWRT and continue configuring:
    1. Listen port: unset / random
    2. IP addresses:
      1. Add the ipv4_address value from the output of the API script
      2. Add the ipv6_address value from the output of the API script
  6. Go to the Advanced Settings tab on the interface and configure the following:
    1. Force Link: checked
    2. MTU: 1280
    3. Use custom DNS servers: IP address of the server with PiHole & Unbound
  7. Go to the Firewall Settings tab on the interface and select the appropriate firewall zone
  8. Go to https://mullvad.net/en/servers and find a server you want to use. Note the following:
    1. IPv4 address
    2. Public Key
  9. Go to the Peers tab on the interface, select Add Peer, and configure the following:
    1. Description: Name of the server from the list (us-chi-wg-312, for example. If you want to. I think it’s helpful, but it really doesn’t matter)
    2. Public key: the public key of the server you want to use
    3. Private key: blank
    4. Allowed IPs:
      1. Add 0.0.0.0/0
      2. Add ::0/0
    5. Route Allowed IPs: checked
    6. Endpoint Host: the IPv4 address of the server you want to use
    7. Endpoint Port: 51820

Viola — this tunnel should now be operational and you should be able to use your own DNS servers!

Appears as a leak

The Mullvad connection check will now indicate that you’re leaking DNS servers. This is expected behavior with this setup.

Preset multiple servers

You can repeat steps 8 and 9 multiple times with different servers to store a few presets of servers. This way, if one is slow or offline, you can just go switch right in your router and not have to figure this process out without internet.

Just make sure that all but one are Disabled at any given time!