VPN enthusiasts increasingly rely on complex stacks—local DNS resolvers, browser DoH clients, mobile per‑app VPN APIs, and containerized apps. Those layers make leaks (DNS, WebRTC, IPv6, or app-level routing bypasses) more likely and harder to find. This guide shows how to methodically test for leaks across platforms in 2026 and outlines concrete, reversible fixes: resolver configuration, firewall rules, interface‑binding, application settings and monitoring. Expect reproducible commands, packet capture tips and a short automation checklist you can use when verifying a provider or hardening your personal endpoints.
Overview: leak types and why they matter
Before diving into commands, label the problems you’ll detect and fix:
- DNS leaks — system or application queries bypass the VPN, spilling which domains you resolve to your ISP or a third party.
- WebRTC leaks — browser real‑time APIs reveal local/IPv6 addresses to STUN servers even with a VPN active.
- IPv6 leaks — IPv6 traffic routes outside the VPN because the tunnel or provider lacks IPv6 support or routing rules.
- Application-level leaks — apps that bind to a physical interface or use platform APIs that ignore the VPN (common in containerized apps, background services, or old games).
Preparation: tools and basic checks
Install these tools on the device you’ll test from:
- curl, dig (bind9‑utils), tcpdump or Wireshark
- dnscrypt-proxy or cloudflared (local DoH/DoT proxy)
- nftables/iptables (Linux) or pfctl (macOS) or Windows PowerShell / Windows Defender Firewall
- Browser with customizable settings (Firefox recommended for fine-grained DNS/WebRTC controls)
Have two browser tabs ready: an IP/DNS leak test (ipleak.net, browserleaks.com) and a STUN/WebRTC test (browserleaks.com/webrtc). Use a separate device or VM as a control point when possible.
Step 1 — Baseline tests (web and CLI)
-
Open a browser and run these web tests:
- https://ipleak.net — checks IP, DNS, WebRTC, and WebGL fingerprinting.
- https://browserleaks.com/webrtc — shows what STUN reports as local and public addresses.
-
From a shell, check the visible public IP and DNS resolution path:
curl -s https://ifconfig.co && echo dig +short txt ch txt whoami.akamai.net @ns1-1.akamaitech.net
(ifconfig.co returns your public IP; use a known DNS provider to check if your queries go to the expected resolver.)
-
Capture DNS and STUN traffic to confirm what actually leaves the device:
sudo tcpdump -i any 'udp port 53 or tcp port 853 or udp port 3478 or port 443'
Look for cleartext UDP port 53 (classic DNS) or STUN UDP packets to port 3478/19302 that include private addresses.
Step 2 — Platform-specific diagnostics and fixes
Linux (desktop and servers)
Common leak vectors: systemd-resolved split DNS, user-level DoH clients, containers bound to host network.
- Inspect resolver and routes:
resolvectl status ip -4 addr show ip -6 addr show ip route show ip -6 route show
- Force DNS through VPN: run a local DNS proxy bound to 127.0.0.1 (dnscrypt-proxy or cloudflared), point /etc/resolv.conf to 127.0.0.1, and ensure the proxy forwards to DoH/DoT servers over the VPN interface.
- Block non‑VPN outbound traffic using nftables (example):
sudo tee /etc/nftables.conf <<'EOF'
table inet filter {
chain output {
type filter hook output priority 0; policy drop;
iif "lo" accept
oifname "tun0" accept
ct state established,related accept
}
}
EOF
sudo nft -f /etc/nftables.conf
Replace "tun0" with your tunnel interface (wg0, utun, etc.). Test from an SSH session first—use console access or a rescue mechanism to avoid locking yourself out.
macOS (desktop)
macOS leaks often come from per-app network stack behavior and mDNS/Bonjour traffic. Tools: scutil, pfctl, and Network preferences.
- Check service order and DNS servers:
scutil --dns networksetup -getdnsservers Wi-Fi
- Prefer VPN DNS: set the VPN network service to be first in the priority order (System Settings → Network → Manage Service Order) or configure the VPN client to push DNS servers.
- Use pf to block interfaces other than the tunnel (example):
echo "block out on en0 all pass out on utun0 all" | sudo pfctl -f - && sudo pfctl -e
Adjust interface names for your system. Again, test carefully to avoid losing remote access.
Windows (desktop)
Windows issues include the resolver (Windows DNS client), browser DoH overrides, and apps using Winsock that may bypass VPNs.
- Check DNS client settings with PowerShell:
Get-DnsClientServerAddress -AddressFamily IPv4
- Use "Block connections without VPN" (Android term) equivalent: create outbound firewall rules to allow traffic only via the VPN interface. Example PowerShell to block non-VPN outbound traffic (conceptual — test before applying):
# Identify VPN interface index
Get-NetAdapter | Where-Object {$_.InterfaceDescription -like "*VPN*"} | Format-Table -Auto
# Create a firewall rule to block outbound traffic on non-VPN adapters
New-NetFirewallRule -DisplayName "Block-NonVPN-Outbound" -Direction Outbound -Action Block -Profile Any -InterfaceAlias "Wi-Fi"
Instead of a blanket block, create allow rules for the VPN adapter and block the others. For stubborn leaks, install a local DNS proxy and configure it in the matching VPN profile.
iOS (iPhone/iPad)
iOS offers an "Always-On" VPN with "Block connections" when the VPN is down in MDM-managed profiles. For consumer devices:
- Enable the VPN client's "Always-on" or "Connect on demand" and any "Block local network" setting.
- Check per-app VPN configuration if using an MDM: verify app lists and that non-enrolled apps don't bypass the tunnel.
- Test with STUN pages in Safari and use a second device on the same network as a control.
Android
Android's "Block connections without VPN" option (Settings → Network & internet → VPN → gear icon) prevents apps from sending traffic when VPN is disconnected. VpnService-based apps should honor this, but OEM Wi‑Fi assistants or battery savers might bypass it.
- Enable "Always-on" and "Block connections without VPN" for your VPN profile.
- Audit apps using "Data Saver" and background restrictions—some apps open their own sockets that may behave differently.
Step 3 — Browser and WebRTC specific fixes
WebRTC leaks are browser-level. To stop them:
- Firefox: set
media.peerconnection.enabledto false in about:config (or use uBlock/Firefox privacy settings that block IP leaks) and configure DNS over HTTPS withnetwork.trr.mode. - Chrome/Chromium: use an extension that disables WebRTC IP leaks (verify extension source) or launch Chrome with
--disable-webrtcoptions where applicable; Chrome lacks a first-class toggle. - Always test after changes at browserleaks.com/webrtc and clear browser caches between tests.
Step 4 — DNS over HTTPS/TLS/QUIC and how to verify
DoH/DoT/DoQ can protect DNS from on‑path observers, but if a local resolver forwards over UDP 53 you still leak. Verify with packet capture:
sudo tcpdump -i any 'udp port 53' -n sudo tcpdump -i any 'tcp port 853' -n # DoT sudo tcpdump -i any 'port 443 and (host 1.1.1.1 or host 9.9.9.9)' -n
If you see UDP 53 leaving the physical interface while VPN is on, your system is still using the ISP resolver. Route DNS via an in‑VPN proxy and pin the proxy to 127.0.0.1 in the OS resolver configuration.
Step 5 — Containers and background services
Containers (Docker, Podman) sometimes bind to the host network. Verify container network mode:
docker inspect --format='{{.HostConfig.NetworkMode}}' mycontainer
If a container uses host networking, it will bypass the host VPN. Run containers in bridge mode and configure their DNS to point at your local proxy. For system services, use process-specific firewall rules where available (Windows) or drop privileges from the default network namespaces (Linux: use network namespaces or systemd-networkd to isolate services).
Automation: repeatable tests and monitoring
Create a small checklist script you can run after connecting the VPN:
- curl to check public IPv4/v6 via the tunnel:
curl -s --interface tun0 https://ifconfig.co
- dig @127.0.0.1 example.com +short
- run STUN request via a STUN client or curl to browserleaks endpoints (or open a headless browser and screenshot the page).
- tcpdump short capture to ensure no UDP/53 leaves the physical interface.
Schedule the script with a local cron/task scheduler or incorporate it into your VPN client’s post-up hook.
When disabling IPv6 is the right move
If your VPN provider does not support IPv6 or you cannot reliably route IPv6 through the tunnel, the safest option is to disable IPv6 at the OS level until support is available. Commands:
- Linux (temporary):
sudo sysctl -w net.ipv6.conf.all.disable_ipv6=1
- macOS: disable via Network settings per interface or remove IPv6 configuration.
- Windows: disable IPv6 in adapter properties (or use PowerShell for registry changes).
Disabling IPv6 can break some modern services—test connectivity before committing.
Checklist before concluding a session
- Run web and CLI leak checks (ipleak.net, browserleaks, curl).
- Confirm no UDP/53 packets traverse the physical adapter while VPN active.
- Confirm WebRTC shows only VPN-assigned addresses or is disabled.
- Confirm containers and local services are using the VPN or isolated networks.
- Have a rollback plan: store original firewall/resolver configs and an out‑of‑band access method.
Conclusion and practical recommendations
In 2026, the surface area for VPN leaks is larger than ever: OS resolvers, DoH clients, browser APIs, IPv6 and containerized workloads all create risk. A methodical approach—baseline web/CLI tests, packet captures, and platform‑specific firewall or proxy fixes—lets you find and eliminate leaks without guesswork. Favor local DNS proxies (dnscrypt-proxy, cloudflared) bound to loopback, per-device firewall policies that force traffic over the tunnel, and browser settings that disable WebRTC leaks. Automate a short post‑connect test script and include it in your verification routine when changing VPN providers or updating system software.
If you’d like, I can produce a downloadable post‑connect test script for Linux, macOS and Windows that implements the commands and checks in this guide.