DNS Leak Detection and Configuration

Learn how to detect DNS leaks in Clash, configure nameserver, fallback, and nameserver-policy, and apply a ready-to-use setup to control DNS routing.

Define What Counts as a DNS Leak

A Clash DNS leak usually means a domain query that should go to a specified resolver or through a proxy has bypassed the expected route and reached your local network, ISP, or another DNS service. Define the expected behavior first. For example, domains used in mainland China may resolve directly, while other domains should use a specified DoH service through the proxy. Without that boundary, seeing a country or provider name on a DNS test page is not enough to conclude that a leak occurred.

A single visit can involve three separate paths: which resolver the app sends its query to, which upstream Clash uses, and whether the connection to that upstream is direct or proxied. nameserver-policy selects an upstream by domain; it does not take over traffic or make the DNS connection use a proxy.

What You SeeWhat It Tells YouWhat to Check Next
The test page shows a public DNS providerThe test query reached that provider's recursive resolverWhether the connection to that resolver used the proxy
The physical network adapter shows UDP 53 queries to the routerUnencrypted DNS queries are being sent locallyWhether the domain or startup lookup is allowed to go direct
The returned address is in 198.18.0.0/16Fake-IP mapping may be in useWhich upstream and outbound route handled the actual query
The browser works, but other apps cannot resolve domainsDifferent apps may use different DNS entry pointsSystem DNS, browser Secure DNS, and TUN interception coverage

Set Up a Reproducible DNS Test

1. Record a Baseline, Then Enable the Proxy

  1. Disable other VPNs, proxies, and network acceleration tools, then note the DNS addresses assigned to your network adapter. On Windows, run ipconfig /all; on macOS, run scutil --dns; on Linux with systemd-resolved, run resolvectl status.
  2. Note whether Secure DNS is enabled in your browser. Run one test using system DNS, then test browser DoH separately so the two paths are not confused.
  3. Run a DNS test with Clash disabled and note the provider, resolver addresses, and time. Enable Clash and repeat the test on the same network with the same browser.
  4. Also open the client logs or connection list. During the test, check the domain, destination address, matched rule, and outbound policy. The test page offers clues; local logs help explain the actual route.

Public DNS providers may use anycast, and the recursive resolver's location may differ from the proxy exit location. Multiple resolver addresses on a test page could indicate multiple upstreams or a pool of nodes belonging to one service. Do not treat the number or location of addresses as a direct measure of leaks.

2. Test Clash's DNS Listener Separately

The configuration below listens on 127.0.0.1:1053. This address is accessible only from the local machine, and 1053 is a DNS port, not an HTTP proxy port. If an app still sends queries to port 53 on the router, enabling this listener will not redirect them automatically.

# macOS / Linux; dig must be installed
dig @127.0.0.1 -p 1053 example.com A
dig @127.0.0.1 -p 1053 example.com AAAA

# Windows
nslookup -port=1053 example.com 127.0.0.1

If the command returns a result, the local machine can reach Clash's DNS endpoint; this does not prove that system DNS has been intercepted. If it times out, first check that the configuration loaded, the core is running, and port 1053 is available. Do not immediately switch proxy nodes.

3. Check for Unencrypted Queries on the Physical Adapter

On a device where you have permission, use a packet capture tool with the filter udp.port == 53 || tcp.port == 53. On Linux, you can also run the command below. The any interface includes virtual interfaces, so distinguish the physical adapter from the TUN interface when reviewing results.

sudo tcpdump -ni any '(udp port 53 or tcp port 53)'

If you see queries going to a local DNS server, check whether the domain is allowed to resolve directly. Seeing no traffic on port 53 does not prove that all DNS is proxied: DoH typically uses HTTPS on port 443, while DoT typically uses TCP port 853. Neither is covered by this filter.

How nameserver and DNS Bootstrapping Work

dns.enable enables the core DNS service; listen sets the listening address; and nameserver provides upstreams for regular queries. An upstream can be a standard DNS address or an encrypted DNS URL supported by the core. Replacing standard DNS with DoH protects traffic between the client and the DoH service, but the resolver can still see the queries.

  • default-nameserver: Primarily resolves the hostnames of DNS upstreams, solving the startup problem of needing to resolve the resolver's address first. It is not the default group for all regular domain queries.
  • proxy-server-nameserver: In mihomo, provides a dedicated resolver for proxy server hostnames, so a node does not need to be connected before it can resolve its own address.
  • nameserver: Handles regular queries not covered by a specific policy.
  • nameserver-policy: Routes specified domains or supported domain sets to particular resolvers.

The example below uses DoH URLs with IP addresses for bootstrapping. Your network must be able to reach these addresses, and the core must pass TLS verification. If your network blocks a service, choose a reachable, trusted resolver and reassess which queries should go direct. Do not work around the problem by disabling certificate verification.

Ready-to-Use mihomo DNS Configuration

This is a snippet to merge into an existing configuration; it does not include proxies or subscriptions. The example sends regular domains to Cloudflare DoH and domains ending in .cn to Alibaba DoH, with rules to control the outbound route for DNS service connections. The .cn suffix identifies a domain ending, not every website in mainland China.

Before applying this, confirm that your existing configuration has a policy group named exactly PROXY and that a working node is selected. If your group has a different name, replace PROXY in the rules. Insert the rules below near the top of your existing rules list, keeping your existing service rules and final fallback. Do not create a second YAML key with the same name.

dns:
  enable: true
  listen: 127.0.0.1:1053
  ipv6: false
  enhanced-mode: fake-ip
  fake-ip-range: 198.18.0.1/16
  respect-rules: true
  default-nameserver:
    - https://1.1.1.1/dns-query
  proxy-server-nameserver:
    - https://1.1.1.1/dns-query
  nameserver:
    - https://cloudflare-dns.com/dns-query
  nameserver-policy:
    "+.cn":
      - https://dns.alidns.com/dns-query

# Merge near the top of the existing rules; do not overwrite the rules below.
rules:
  - DOMAIN,cloudflare-dns.com,PROXY
  - DOMAIN,dns.alidns.com,DIRECT
  - IP-CIDR,1.1.1.1/32,DIRECT,no-resolve

respect-rules: true makes connections to regular DNS upstreams follow routing rules. The example explicitly routes Cloudflare DoH through PROXY and sends Alibaba DoH direct; IP rules keep the bootstrap addresses on a direct route. The dedicated resolver for proxy node hostnames remains a startup dependency, so this configuration does not send every DNS query through the proxy.

ipv6: false here limits AAAA responses from the core DNS service. It does not disable IPv6 in the operating system or prevent IPv6 traffic leaks. If you need IPv6, test IPv6 routing, TUN interception, and upstream support separately before enabling it.

nameserver-policy Matching and Scope

In mihomo's domain matching syntax, "+.example.com" can match both the domain and its subdomains. Quote policy keys that contain special characters, and use two-space indentation. A policy value can be a list of resolvers; do not assume that multiple resolvers in a list are used in a strict primary-and-backup order.

dns:
  nameserver-policy:
    "+.example.com":
      - https://cloudflare-dns.com/dns-query
    "+.cn":
      - https://dns.alidns.com/dns-query

This snippet only demonstrates the policy syntax. Merge it into the dns section above rather than creating a duplicate key. example.com is a sample domain for testing matches; replace it with domains relevant to your use case. Avoid guessing precedence with overlapping, overly broad policies. Keep each scope clear, and test the root domain and its subdomains separately.

Handle Corporate Internal Domains Separately

Company internal domains can usually be resolved only by the office network's DNS. Map the actual internal suffix to an internal DNS server and ensure that the server's address has a direct route. If using Fake-IP, also assess whether to add the domain to fake-ip-filter based on app requirements. Do not send internal domains to public resolvers or mistake a failure from public DNS for a proxy node failure.

Adding a domain to fake-ip-filter only changes whether the response contains a real or mapped address. It does not select an upstream or force a direct connection. Resolver selection, Fake-IP exceptions, and connection routing are separate configuration layers and should be tested independently.

fallback Is Not a DNS Leak Prevention Switch

fallback provides another set of upstream resolvers, while fallback-filter helps determine which results to use. It is not safe to assume that a fallback resolver is queried only after the primary DNS fails completely: queries may run in parallel, depending on the core and filter conditions. If the upstreams belong to different trust boundaries, the queries may be sent to both.

The snippet below demonstrates a separate setup for filtering anomalous address results. Add it to the existing dns section; do not replace the entire configuration. When using Quad9, also check the outbound policy for its connections. Declaring an HTTPS URL does not automatically route it through a proxy.

  fallback:
    - https://dns.quad9.net/dns-query
  fallback-filter:
    geoip: false
    ipcidr:
      - 0.0.0.0/32
      - 127.0.0.0/8

This disables GeoIP-based filtering and demonstrates filtering only a specified range of anomalous addresses. It is not a complete method for detecting DNS poisoning. Some security filtering services intentionally return empty addresses, and some test domains may legitimately resolve to loopback addresses. Add conditions only when needed; more filters do not necessarily mean greater reliability.

What System Proxy, TUN, and Browser DoH Can Miss

A System Proxy Does Not Intercept All DNS

An HTTP proxy can resolve the requested hostname on the proxy server, but apps that do not use the system proxy may still query the system resolver. Whether a SOCKS app sends the hostname to the proxy depends on its remote DNS setting. A working website after enabling the system proxy does not mean command-line tools, games, and background services use the same DNS route.

TUN DNS Hijacking Has Protocol Limits

To intercept apps that ignore the system proxy, enable TUN on a supported platform. The snippet below is a common mihomo configuration. Auto-routing usually requires appropriate system permissions, and interception of DNS queries to local network targets also depends on platform routing and client implementation.

tun:
  enable: true
  stack: mixed
  auto-route: true
  auto-detect-interface: true
  dns-hijack:
    - any:53
    - tcp://any:53

These hijack settings target traditional DNS on UDP/TCP port 53. They do not decrypt browser DoH or turn every port 443 connection into a core DNS query. Browser DoH remains a separate connection: TUN may route it through a proxy, but its DNS queries are not handled by nameserver-policy.

Test Browser and System Caches Separately

In desktop Chrome, check Settings → Privacy and security → Security for Use secure DNS; labels may vary by version. To test the Clash core's DNS, temporarily disable custom Secure DNS first. If you keep browser DoH enabled, check the outbound policy for that DoH service separately.

On Windows, run ipconfig /flushdns to clear the system cache. On Linux with systemd-resolved, run resolvectl flush-caches. Browser and core caches may still be present, so restart the relevant processes before testing again. Do not use a quick response from a cached result as proof that the upstream has changed.

Run a Final Test Based on the Symptoms

SymptomCheck FirstHow to Verify
Queries to port 1053 time outDNS listener, configuration errors, or port conflictCheck startup logs and query the local listener directly
Only the browser shows a different resolverBrowser DoH or browser proxy settingsSwitch to system DNS and repeat the same test
Router DNS queries continue after enabling TUNDestination routing, platform interception limits, or another virtual adapterCapture traffic on the physical adapter and identify the process making the query
DNS stops working after switching nodesNode hostname resolution or an upstream routing loopCheck whether the dedicated node resolver can connect independently
Settings disappear after a subscription updateThe edited remote configuration was replacedUse a persistent override and check the final active configuration

Repeat the checks in the same order: confirm the local listener on port 1053 works; confirm that the system or TUN sends the target query to the core; confirm that the policy selects the expected upstream; then confirm that the upstream connection uses the correct outbound route. Record the test time, queried domain, resolver, and policy. Only when all four results match is the query route behaving as expected. A single screenshot from a DNS test page cannot represent every app, network, or IPv6 scenario.

Download Clash Clients