1 Why DNS leaks undermine your proxy
Most users picture a VPN or proxy as a single pipe that “encrypts the internet.” In practice, name resolution is a separate channel. When an application calls getaddrinfo, the operating system may forward that query to whatever resolver is configured in Wi-Fi settings, DHCP, or corporate policy. If that resolver belongs to your access provider, they can log the hostname even when the subsequent HTTPS session exits through a remote node. That mismatch—encrypted transport, cleartext or provider-visible DNS—is what people mean by a DNS leak.
Rule-based clients such as Clash Verge Rev or headless Mihomo add another twist. Your rules section decides whether traffic uses DIRECT or a proxy group, but the decision often depends on the domain or IP seen at connection time. If DNS resolution happened outside the core, the IP you connect to might not be the one your rules assumed, leading to false routing, broken split tunneling, or the appearance of leaks on audit sites. Fixing DNS inside the Meta core aligns resolver output with policy and closes the obvious side channel.
The following sections stay implementation-focused. We assume you already run a Clash-compatible profile on Mihomo and simply need resolver hygiene. Where desktop behavior matters—especially TUN—we point you to the companion tunnel guide so you can combine transparent routing with the DNS block shown later.
2 How Mihomo handles DNS alongside rules
Mihomo exposes a dedicated dns object in YAML. When dns.enable is true, the core can accept DNS queries on a local listener (for example 0.0.0.0:1053) and answer them using the same outbound selection logic you rely on for TCP and UDP. That design matters because it lets you send DNS to remote, encrypted resolvers through the proxy when needed, while still allowing domestic or LAN lookups to stay direct per your rules.
The Meta core also understands multiple upstream types: classic UDP/TCP DNS, DNS-over-TLS (DoT), DNS-over-HTTPS (DoH), and even DHCP-derived nameservers if you wire them explicitly. Each upstream can be tagged and referenced inside nameserver-policy, which is how you steer sensitive zones—think +.google.com or an internal suffix—toward resolvers you trust for that namespace. Without this layer, every query would hit the same resolver chain, which is either brittle or slow.
Finally, integration with mode: rule means DNS is not an afterthought. When enhanced modes are enabled, the core can synthesize answers locally for matched domains, deferring real resolution until a connection attempt actually needs it. That behavior is the foundation of FakeIP, covered in its own section once we nail encrypted transport basics.
3 DoH, DoT, and why default-nameserver matters
DNS-over-HTTPS and DNS-over-TLS wrap queries inside TLS, which hides QNAME data from casual on-path observers and stops UDP-only interference on hostile networks. In Mihomo you declare them as strings, for example https://1.1.1.1/dns-query or tls://dns.quad9.net:853. These URLs look simple, but they introduce a bootstrap problem: before the core can speak TLS to Cloudflare, it must resolve 1.1.1.1 (already an IP, so no issue) or the hostname embedded in a provider URL. If you only list encrypted upstreams that depend on a domain, the core needs a plain resolver to unlock them.
That is what default-nameserver is for. Populate it with fast, reachable UDP or TCP servers—often your ISP’s resolver in low-latency scenarios or a neutral anycast pair if you prefer. Keep this list short and reliable; its sole job is to unblock resolution of the DoH/DoT endpoints themselves. Skipping it is a common reason encrypted DNS silently fails and applications fall back to system resolvers, recreating the leak you were trying to stop.
Practical ordering
A sane pattern is: default-nameserver with two plaintext resolvers, nameserver with your preferred DoH/DoT endpoints, and fallback with alternates that should engage when primary answers look poisoned or geographically wrong. Mihomo evaluates groups asynchronously and can apply filters so fallback triggers only when needed, which keeps latency down for day-to-day browsing while retaining a safety net.
4 FakeIP: keep local apps from bypassing the core
enhanced-mode: fake-ip (or legacy alias fake-ip) changes how responses look to applications on your machine. Instead of returning the real remote address immediately, Mihomo hands back an address from fake-ip-range, typically a private-looking segment such as 198.18.0.1/16 reserved for documentation-like use inside the tunnel. The first time a socket connects to that placeholder, the core performs the true resolution and associates the mapping in memory. From the application’s perspective, resolution was instant; from the network’s perspective, no external DNS query left the host for that name during the initial lookup phase.
FakeIP shines when combined with TUN or strict system proxy adoption because it minimizes accidental “split brain” between the resolver your OS likes and the resolver your rules expect. It also reduces telemetry noise: many binaries phone home with short-lived domains; FakeIP lets the core log and classify those flows consistently. The trade-off is complexity—you must exclude names that genuinely need real IPs locally, which leads directly to fake-ip-filter.
Curating fake-ip-filter
Some targets should never receive synthetic addresses. Local discovery suffixes (*.lan, *.local), captive portal hosts, and certain STUN-heavy VoIP domains often belong in fake-ip-filter so they resolve to routable LAN or WAN addresses. Community rule lists sometimes ship recommended filter sets; treat them as hints and trim to your network. Over-filtering erodes FakeIP benefits, while under-filtering breaks printers, Chromecast-style devices, or intranet portals.
5 fallback, fallback-filter, and geoip awareness
Censorship and cache poisoning turn DNS into a game of redundancy. Mihomo’s fallback group exists so secondary resolvers can answer when primaries return suspect results. Pair it with fallback-filter to define what “suspect” means: geographic hints via geoip: true and geoip-code, IP CIDR blocks that should never appear for public names, or domain-name regex lists. A typical profile sets geoip-code to the country you consider “on-net” for direct routing, so answers that geolocate elsewhere trigger fallback verification.
This layer interacts with DoH because encrypted upstreams may still return manipulated answers if the path to them is controlled. Combining multiple independent providers—say a large anycast operator plus a privacy-oriented resolver—raises the bar. Remember that each additional hop adds latency; tune concurrency and timeout values if you run on satellite or high-loss links.
6 TUN mode, dns-hijack, and the operating system
System proxy mode helps browsers, but many binaries ignore it. TUN virtual interfaces push IP packets through Mihomo before they leave the box, which is the reliable way to catch stray DNS to UDP 53 or TCP 443 DoH from stubborn apps—provided you enable hijack rules. In YAML, a tun section may include dns-hijack entries such as any:53 so plaintext resolver attempts get redirected into the core listener. Exact keys evolve between releases, so confirm against your Mihomo version changelog, but the principle stays constant: without hijack, some stacks will still talk to 8.8.8.8 around your rules.
Desktop clients like Clash Verge Rev expose toggles for TUN, auto route, and DNS helper features; the YAML mirrors those capabilities. If you are wiring a server instead, see our Linux systemd deployment guide for a minimal service layout, then layer the DNS block from this article on top. For a full walkthrough of developer-centric TUN adoption—terminals, Git, Docker—read the Clash Verge Rev TUN mode tutorial; it pairs naturally with the resolver settings here.
7 Production-minded YAML template
The snippet below is not a complete profile—it omits proxies and rules you already maintain—but it is a drop-in dns section plus a tun sketch for transparent mode. Adjust listeners if port 1053 conflicts with systemd-resolved or Windows services; changing to 127.0.0.1:1053 is fine for single-user machines. Swap resolvers to match your compliance requirements.
dns:
enable: true
listen: 0.0.0.0:1053
ipv6: false
enhanced-mode: fake-ip
fake-ip-range: 198.18.0.1/16
fake-ip-filter:
- '*.lan'
- '*.local'
- '*.localhost'
- '+.msftconnecttest.com'
- '+.msftncsi.com'
default-nameserver:
- 223.5.5.5
- 119.29.29.29
nameserver:
- https://1.1.1.1/dns-query
- https://dns.google/dns-query
nameserver-policy:
'geosite:cn':
- https://dns.alidns.com/dns-query
- 223.5.5.5
fallback:
- tls://dns.quad9.net:853
- https://8.8.8.8/dns-query
fallback-filter:
geoip: true
geoip-code: CN
ipcidr:
- 240.0.0.0/4
domain:
- '+.google.com'
- '+.github.com'
tun:
enable: true
stack: system
auto-route: true
strict-route: false
dns-hijack:
- any:53
Notes: nameserver-policy referencing geosite:cn assumes you load GeoSite data; if your build lacks it, replace with explicit suffixes. strict-route changes how default routes interact with local subnets—enable only when you understand split tunnel impacts. Always reconcile ipv6: false with your global ipv6 flag; inconsistent IPv6 routing is another stealth leak class where AAAA records bypass your tunnel.
8 Verify you actually fixed the leak
After applying config, restart the core and clear stale DNS caches on the OS where possible. On Windows, ipconfig /flushdns remains relevant; on macOS, sudo dscacheutil -flushcache; sudo killall -HUP mDNSResponder still helps during testing. Then run browser-based leak tests as a smoke signal, but prefer targeted checks: from a shell that inherits proxy environment variables, run curl -v https://www.example.com and confirm Mihomo logs show the query hitting your local DNS listener rather than external UDP 53. For TUN, packet captures on the physical interface should no longer show plaintext DNS once hijack is active.
Interpret third-party leak sites cautiously—they often geolocate resolver IPs without understanding split routing. Your goal is consistency: the resolver IP reported during tests should match the outbound path you intended (for example your proxy exit or trusted DoH provider), not a surprise ISP anycast node. Keep logs at info or debug briefly while validating, then return to warning to avoid disk churn.
9 Common pitfalls and honest limits
- Corporate SSL inspection: Managed devices with custom roots can intercept DoH, defeating confidentiality. Policy beats technology here.
- Browser secure DNS: Chrome and Edge can ignore OS resolvers when their internal DoH toggle is on, creating parallel resolution paths. Align browser settings with your tunnel strategy.
- IPv6 router advertisements: If IPv6 is up but not steered through TUN, some stacks prefer AAAA and leak metadata via alternate paths. Either route IPv6 fully or disable it consistently.
- Game consoles and IoT: Devices with hard-coded resolvers may need LAN-level blocking or accept residual plaintext. Document exceptions instead of pretending FakeIP magically fixes hardware you cannot configure.
10 Wrap-up
DNS leak prevention on Mihomo is less about ticking a single checkbox and more about engineering consistency: encrypted upstreams with a bootstrap plan, FakeIP to keep local consumers aligned with the core, fallback filters for poisoned answers, and—when you need whole-machine coverage—TUN hijack so nothing sneaks resolver traffic out the side. Taken together, those layers match how modern Clash.Meta clients expect profiles to behave in 2026.
Maintained desktop builds bundle the same core with UI affordances for importing subscriptions, toggling TUN, and watching live connections, which beats hand-editing YAML every time you need to test a resolver change. Compared with one-off scripts, they give you shared vocabulary across Windows, macOS, and Linux—especially when you bounce between a GUI on your laptop and a systemd service on a VPS.
If you want that workflow without stitching tools together manually, grab an up-to-date client from our downloads page and paste the DNS block here into your active profile. A few restarts and a careful leak test usually beat hours of guessing which resolver path an app picked.