Engineering

How we test for DNS leaks

Every proxy client says it doesn’t leak DNS. Almost none of them publish how they checked. Here is our method, the control test that proves the check can actually detect a leak, and the per-protocol results — so you can reproduce it rather than take our word for it.

36 / 36protocol & transport combinations verified clean
0DNS packets observed leaving the physical interface
2directions the check is control-tested in

Why a leak test is easy to get wrong

The usual approach is to visit a DNS-leak website and read the answer off the page. That tells you which resolver answered a query. It does not tell you whether a query escaped your device. Those are different questions, and only the second one matters.

So we don’t ask a website. We watch the wire. While traffic is flowing, we run a packet capture on the physical network interface — the Wi-Fi or Ethernet adapter, not the tunnel — and count DNS packets. If a lookup leaves the device unencrypted, it has to cross that interface, and it gets caught.

The trap that invalidates most leak tests: “we saw zero DNS packets” is exactly what a broken capture reports too. A test that can only ever return “clean” is not a test. Handling this is the part that makes the result mean something — see the liveness check below.

The method

  1. Real Chrome, never curl A protocol result only counts if it was produced by real Google Chrome loading pages concurrently and fully. This is a hard rule for us, and it exists because we got burned: an entire class of gRPC deadlock connects fine, returns the correct egress IP and passes a DNS check under curl, while moving zero bytes in an actual browser. A curl pass isn’t weak evidence — it’s no evidence. We deleted our own curl-based runners so the mistake can’t be repeated.
  2. Concurrent tabs, fully loaded Six tabs at once, each asserted to complete loading — including a heavy real-world news page with many third-party origins, ads and images. Multiple origins in parallel is what actually stresses a proxy’s connection handling.
  3. Sustained media playback Seventy seconds of continuous video in a foreground tab. Page loads are bursty; streaming is not. Sustained throughput surfaces stalls that a page load hides.
  4. A soak that reuses the same browser Twelve iterations, four seconds apart, in the same browser session. Browser reuse is where the interesting bugs live — connection pooling, session state, and multiplexed transports that work once and wedge on the fifth attempt.
  5. Packet capture the whole time tcpdump on the physical interface, filtering DNS ports and traffic to the proxy server, for both IPv4 and IPv6.
  6. Then the verdict — with a liveness check We require proxy-server packets to be present. The tunnel’s own encrypted traffic crosses the physical interface constantly, so if we can see it, the capture is provably live. Only then does a DNS count of zero mean anything. If we see no proxy traffic either, the run is reported INCONCLUSIVE — never as a pass.
  7. Cooldown, then the next protocol Each combination is torn down and disconnected before the next begins, so no result can be contaminated by the previous tunnel.

The control test

A leak detector that has never detected a leak is indistinguishable from a detector that is simply broken. So we verify ours in both directions:

ConditionDNS packets on the physical interfaceMeaning
VPN down29 captured — router and ISP resolvers, IPv4 and IPv6The check demonstrably detects real leaks
VPN up0, with proxy traffic presentNothing escaped, and the capture was live

That first row is the one to insist on — from us or from anyone else publishing a leak claim. Without it, “no leaks detected” is unfalsifiable.

What a pass requires

A combination is only recorded as PASS when every one of these holds. A protocol that moves traffic but leaks DNS is recorded as a failure, not a partial success — the entire point of the product is that neither the payload nor the lookup escapes.

Tabs

All six concurrent tabs fully loaded.

Soak

At least 10 of 12 reuse iterations succeeded.

Media

Sustained playback held for the full duration.

DNS

Verdict CLEAN — zero packets, capture proven live.

Results — Rocket Proxy 2.0

Run sequentially against live servers on 3 August 2026. Every combination below returned PASS with a CLEAN DNS verdict.

VMess WS
VMess TCP
VMess + gRPC
VMess Mux.Cool TCP
VLESS Reality
VLESS WS
VLESS + gRPC
VLESS + xHTTP
VLESS + xHTTP H3
VLESS + mKCP
VLESS HTTPUpgrade
Trojan TLS
Trojan WS
Trojan + gRPC
Shadowsocks 2022
Shadowsocks Legacy
ShadowsocksR
SS + ShadowTLS v3
SS + SimpleObfs (HTTP)
SS + SimpleObfs (TLS)
SS + v2ray-plugin (WS)
SS + Cloak
SS + kcptun
Hysteria 1
Hysteria 2
TUIC v5
Juicity
Snell v4
Brook
Mieru
WireGuard
AmneziaWG
OpenConnect
gost relay+tls
HTTP proxy
SOCKS5 proxy

Check it yourself

You don’t need our harness. On a Mac, connect the tunnel, then watch your physical interface directly. Replace en0 with your active adapter.

# 1. Find the physical interface (the one that is NOT a utun)
route -n get default | grep interface

# 2. Watch it for DNS while the tunnel is UP. Then browse for a minute.
sudo tcpdump -i en0 -n 'udp port 53 or tcp port 53 or port 5353'

# Expected with Rocket Proxy connected: nothing.
# Now the control — disconnect and run it again. You should see queries
# immediately. If you don't, your capture is wrong, not your VPN.
Honest limits. These results are from macOS, over the app’s real network path, against our own test servers. They show that the client does not leak lookups. They are not a claim about your operating system’s behaviour outside the app, your browser’s secure DNS settings, or your proxy server’s own logging — the server you connect to can always see the lookups you send it. Choose it accordingly. Numbers here are from a single sequential run, not an average of many.

Related: import a Clash or Stash config · free macOS download