1. How to identify a DNS leak: Start by deciding which queries should use the proxy
Your public IP may show the proxy while DNS queries still go through your local network. That’s because web traffic and DNS lookups take separate routes. A system proxy typically affects only apps that honor proxy settings; it doesn’t automatically capture system queries sent over UDP port 53. Browsers may also use their own encrypted DNS.
Here, a “leak” means a domain lookup that should go through the proxy is unexpectedly sent to a resolver over a direct local connection. If your configuration intentionally uses local DNS for domains in mainland China, that direct connection is expected. Seeing two resolvers on a test page does not, by itself, mean your configuration has failed.
| What you see | What it tells you | What to check next |
|---|---|---|
| The web exit IP belongs to the proxy node | This web connection used the proxy | Check the DNS path next |
| The test shows your local ISP’s resolver | A local recursive lookup may be occurring | Review routing rules and packet captures |
| The test shows a public DNS provider | That provider took part in the recursive lookup | The provider’s name alone can’t show whether the query used the proxy |
The query returns 198.18.x.x | The query may have been mapped to a fake IP | Still check the upstream lookup and connection route |
2. How to test for DNS leaks: establish a baseline, compare, and capture packets
Keep the test conditions consistent
- Note the client name, client version, and core version. The configuration below is for mihomo; the original Clash and older cores may not support every field.
- Note the proxy mode, selected node, TUN status, and browser Secure DNS setting. Don’t change nodes and DNS resolvers at the same time during testing.
- On the same network, turn off the proxy and run a DNS leak test. Record the resolver name and IP, along with your public IP. This is your direct-connection baseline.
- Turn on the proxy and run a fresh test. If possible, use a test that generates a random subdomain to reduce the impact of cached results.
- Next, enable TUN and repeat the same test. If the results change only when TUN is on, check whether system DNS queries were bypassing the core.
Clear the cache and check the local listener
On Windows, run the commands below in a terminal. The first clears the system DNS cache; the second queries the local DNS listener port used in this guide. Browsers also maintain their own caches and connection pools, so fully quit and reopen the browser before testing. Refreshing a page may not trigger a new lookup.
ipconfig /flushdns
nslookup example.com 127.0.0.1
The example below listens on 127.0.0.1:1053, while nslookup queries port 53 by default. It will work only if port 53 is forwarded locally. To query port 1053, use a tool that supports specifying a port, such as dig if it’s installed:
dig @127.0.0.1 -p 1053 example.com A
dig @127.0.0.1 -p 1053 example.com AAAA
A fake IP in the response means this query reached the core’s DNS resolver. It doesn’t prove that every app uses this entry point. Also check the client’s connection log for the rule and outbound policy applied to the target domain.
Use a packet capture to verify the local path
Capture traffic on the physical network adapter in use and filter for udp.port == 53 || tcp.port == 53. Then run the test again. If you see the randomly generated test domain sent directly to your router or ISP’s DNS, and that doesn’t match your intended direct-connection policy, you have clear evidence of a bypass. Packet captures may contain private information such as domain names; redact them before sharing.
DoH often uses TCP 443 or QUIC 443, while DoT typically uses TCP 853. No traffic on port 53 doesn’t rule out a DNS bypass. For encrypted queries, also check the resolver’s IP, the process making the request, and the client’s connection logs.
3. What fake-ip, DNS policies, and TUN hijacking each do
| Mechanism | What it does | Limitations |
|---|---|---|
fake-ip | Assigns fake IPs to domains so the core can recover the domain and match it against rules | Doesn’t automatically capture DoH built into apps |
nameserver-policy | Selects a resolver based on the domain | Choosing a resolver doesn’t determine which proxy route its traffic uses |
respect-rules | Routes upstream DNS connections according to routing rules | If a rule selects DIRECT, the upstream connection still goes direct |
TUN dns-hijack | Sends matching DNS traffic passing through TUN to the core | Can’t decrypt and rewrite DNS inside arbitrary HTTPS traffic |
198.18.0.0/16 is a commonly used fake-ip range. It belongs to a reserved address block for benchmarking, not the proxy node’s real public IP range. When an app connects to one of these fake IPs, the core uses its mapping to recover the domain, then applies routing rules to handle the connection.
So fake-ip is a domain-mapping mechanism, not a switch that routes all DNS through the proxy. A reliable setup needs all three points checked: where the app sends its query, which resolver the core selects, and how the connection to that resolver is routed.
4. mihomo DNS configuration: start with a verifiable baseline
Back up your current configuration first. You can merge the snippet below into a mihomo configuration that supports these fields, keeping your existing nodes, proxy groups, and rules. Don’t import it as a complete subscription file. Keep only one dns: section with this name, and use spaces for YAML indentation.
dns:
enable: true
listen: 127.0.0.1:1053
ipv6: false
enhanced-mode: fake-ip
fake-ip-range: 198.18.0.1/16
fake-ip-filter:
- "*.lan"
- "*.local"
respect-rules: true
default-nameserver:
- 223.5.5.5
proxy-server-nameserver:
- https://223.5.5.5/dns-query
nameserver:
- https://1.1.1.1/dns-query
Check each setting; don’t rely solely on a successful configuration load
- Bind
listento the local loopback address so the DNS service isn’t exposed to your LAN. System network settings usually can’t specify DNS port 1053; you’ll need TUN hijacking or local port forwarding to use it. ipv6: falsecontrols how the core handles AAAA queries. It doesn’t disable IPv6 in the operating system or stop apps from obtaining IPv6 addresses by other means.default-nameserverresolves the hostnames of DNS services. This example retains a plaintext bootstrap resolver, so it doesn’t encrypt every query. Using a DoH URL with an IP address can reduce the need for bootstrap lookups.proxy-server-nameserverresolves proxy server hostnames and helps avoid a circular dependency where you need the proxy to resolve the proxy’s address. This example uses a separate DoH provider; test that it’s reachable on your network.respect-rules: truerequires a working proxy server DNS configuration. Also check that connections to1.1.1.1:443match the intended proxy policy. If your existing rules send them direct, those queries still won’t use the proxy.
After applying the configuration, check the validation results and then review the runtime logs. If you see an unknown field, confirm which core is actually loaded rather than adding more fields to an older core. Client UI settings may override DNS settings from a subscription, and subscription updates may overwrite manual edits. Use the client’s persistent override feature and verify the final active configuration.
5. nameserver-policy: use a dedicated resolver for local domains
Corporate intranet domains, home NAS devices, and router admin domains often resolve only through local DNS. Sending them all to a public resolver usually makes them unresolvable, not more secure. The example below routes specific domains to a dedicated resolver. Use it only if your router is actually at 192.168.1.1 and resolves these domains.
nameserver-policy:
"+.lan":
- 192.168.1.1
"+.home.arpa":
- 192.168.1.1
Add this under your existing dns: section, at the same indentation level as nameserver. The two-space indentation matters. +.lan matches the domain and its subdomains; home.arpa is reserved for home networks. Don’t send an entire public domain suffix to a local resolver just to restore access to one intranet service.
If an app needs the real LAN address, also add the relevant domain to your existing fake-ip-filter, for example "*.home.arpa". A filter entry changes how fake IPs are returned; it doesn’t select a resolver or automatically force a direct route. Make sure your LAN subnets have the right direct-connection rules too.
Test a local service first, then a public domain. A local-domain lookup going directly to the router is expected under this policy; don’t confuse it with an unintended bypass for public domains.
6. TUN DNS hijacking: capture system queries and apps that ignore system proxy settings
With only the system proxy enabled, some apps may still send DNS queries on their own. Desktop mihomo clients can use TUN to capture more traffic; this usually requires service mode or administrator privileges. Here’s a basic snippet to use with the DNS configuration above:
tun:
enable: true
stack: system
auto-route: true
auto-detect-interface: true
dns-hijack:
- any:53
- tcp://any:53
any:53 matches UDP DNS passing through TUN; the second entry handles TCP DNS. The key requirement is that the traffic actually enters TUN. Other VPNs, bridged virtual machines, container networking, IPv6 routes, and app exclusion lists can all create a separate path. Some platforms also limit interception of local-network DNS, so verify the actual traffic with a packet capture.
Test browser Secure DNS separately
In Chrome, check the current setting under Settings → Privacy and security → Security → Use secure DNS; the wording may vary slightly between versions. For troubleshooting, first turn it off so the browser uses system DNS, then test TUN. Turn it back on afterward and check whether connections to the browser’s resolver still match the intended proxy rules.
This isn’t a recommendation to leave encrypted DNS disabled. The goal is to isolate variables: an app’s built-in DoH is a regular encrypted network connection and won’t be automatically replaced by port 53 hijacking. Check Android Private DNS separately too. It’s usually under Settings → Network & internet → Private DNS, though device manufacturers may move the setting.
7. Common issues and final verification checklist
Printers or NAS devices stop working after enabling fake-ip
First check which resolver handles your LAN domains, then add a precise nameserver-policy and any necessary fake-ip filters. mDNS uses UDP 5353 and is different from ordinary unicast DNS; hijacking port 53 alone won’t fix every .local discovery issue.
Proxy node hostname lookup times out after enabling respect-rules
Check connectivity to proxy-server-nameserver, and make sure reaching that resolver doesn’t depend on a proxy that hasn’t been resolved yet. If needed, restore your backup and first re-establish an independent DNS path for proxy hostnames, then tighten DNS outbound rules gradually. Don’t assume the proxy node itself is down.
The test results don’t change
Troubleshoot in this order: active configuration → DNS cache → browser DoH → TUN routing → rule matches. If the test domain never appears in the logs, check the entry point first. If there’s a query but its outbound route is DIRECT, check the rules. If the route is correct and only the geolocation differs, check the resolver’s anycast and forwarding behavior.
- Public test domain: a fresh query reaches the core, and the resolver connection uses the intended outbound route.
- Local physical adapter: no plaintext test-domain queries that violate the routing policy.
- Browser and system: test Secure DNS on and off separately; don’t rely on a single test page.
- LAN services: routers, NAS devices, and printers remain reachable, with clear exceptions for domains expected to connect directly.
- Persistence: retest after restarting the client and updating the subscription to confirm overrides remain active.
Success doesn’t mean “the test page shows only one resolver.” Every type of query should have an explainable entry point, resolver, and outbound route. Make the path visible first, then remove unnecessary exceptions. The easier your configuration is to verify, the easier it will be to diagnose the next network change.