Most people meet the dns: block the way you meet a fuse box: only when something has gone dark. The rules looked right, the node was reachable, the group was selected — and yet one site went out the wrong path, or a printer on the desk stopped answering, or the whole thing worked perfectly for a week and then broke the moment a laptop moved to a different network.
Almost every one of those stories is a name resolution story. Routing decisions are made about destinations, and for the overwhelming majority of traffic the destination starts life as a hostname rather than an address. Whoever turns that hostname into an address, and at what moment, sets the boundaries on what the rule engine is even capable of deciding.
This piece stays inside that one layer: what the resolver is for, what the two enhanced modes do to a packet, which hostnames must be kept out of the synthetic path, and how to tell quickly whether you are debugging DNS or routing.
Why a Routing Engine Wants Its Own Resolver
It looks like duplication. The operating system already has a resolver, the router hands one out over DHCP, the ISP runs one behind that. The reason for a fourth is that the engine needs to be in the conversation before the connection exists, not after. Three things follow:
- It needs the hostname. A rule like
DOMAIN-SUFFIX,example.comcan only fire if the engine knows the request was for that name. If the application resolved it privately, that information is already gone. - It needs control over where lookups travel. Sending every query to whatever the local network suggests means the answers, and the record of what you asked for, follow a path you did not choose.
- It needs consistency across interfaces. Laptops change networks. A resolver owned by the engine rather than by the current Wi-Fi keeps behaviour stable when the DHCP lease changes underneath it.
So the client runs a small resolver on a local port, and either the system is pointed at it or a virtual adapter captures port 53 traffic and feeds it there.
The Order of Operations Nobody Draws
Here is an ordinary browser request written out, because the ordering is the whole point:
- The application wants
images.example.com, and has no socket yet — a socket needs an address. - It asks a resolver for one.
- It receives an address and opens a connection to it.
- The engine sees that connection and evaluates its rules against whatever metadata came with it.
Step four is where the interesting configuration lives, but step two is where the hostname either survives or evaporates. If the resolver in step two is not the engine’s — or is the engine’s but works in a mode that discards the association — then by step four there is nothing left but an address, and only address-shaped rules can match it.
That is the sentence worth keeping: resolution happens before routing, so the resolver decides which rules are still eligible. Everything below is a consequence.
fake-ip: Answer With a Placeholder, Keep the Name
Under enhanced-mode: fake-ip the engine does something that feels like cheating and is in fact the cleanest option available. Asked for images.example.com, it performs no upstream lookup at all: it invents an address from a reserved pool, records the pairing, and answers immediately.
The application is satisfied and opens a connection. That connection arrives at the engine, which looks the address up in its table, recovers the hostname, and evaluates the rules with it intact. Only once a policy has been chosen does a real lookup happen — locally for direct traffic, at the remote end for proxied traffic.
The reserved range
The pool is set by fake-ip-range, conventionally 198.18.0.1/16. That block is reserved for network benchmarking and is not routable publicly, which is exactly the property you want: if one of these addresses escapes the table and reaches a real interface, it dies quietly instead of connecting to a stranger. Change it only if the range collides with a network you genuinely use, and then only for another non-routable block.
The table, and what it costs
The mapping lives in memory as a bounded, self-evicting table: allocate, hand out, reclaim once the entry goes cold. Two consequences matter. These addresses are meaningless outside the machine holding the table, so forwarding one elsewhere produces nothing. And a stale entry cached somewhere else can point at a pairing that no longer exists — which is why mode changes and cache flushes belong together.
This matters most under a virtual adapter. TUN mode captures traffic from applications that never consulted a proxy setting and resolve names on their own terms; placeholder answers are what keep the hostname attached to those connections. Without them a carefully written domain rule list becomes decorative, and everything falls through to address matching and the final catch-all.
redir-host: Resolve First, Match on the Result
The older mode does the obvious thing: a query arrives, the engine forwards it upstream, gets a real address, returns it. When the connection appears, some capture paths still carry the hostname the engine just resolved, so domain rules can work — but the guarantee is weaker and depends on how the traffic was intercepted.
The bigger cost is that the lookup happens before any policy decision. Every name is resolved by whichever upstream the configuration names, including names you meant to hand to a remote endpoint — a round trip in front of every new host, down a path you did not choose.
redir-host still has uses — some transparent-proxy arrangements on routers expect real addresses downstream — but as a desktop default it has largely been retired.
fake-ipredir-hostReply to the applicationSynthetic address from the reserved poolThe real address, resolved upstreamWhen the real lookup happensAfter a policy is chosenBefore any rule is evaluatedDomain rules under TUNReliable — name recovered from the tableFragile, capture-dependentAdded latency on first contactNone at the DNS stepOne resolution round tripWho resolves proxied namesThe remote endYour configured upstreamMain hazardHosts that need a genuine addressLookups leaving by the wrong path
fake-ip-filter: The Names That Must Stay Real
Placeholder answers work because nothing outside the engine needs to interpret them. Wherever that assumption fails, the hostname belongs in fake-ip-filter, an exclusion list of names resolved genuinely instead. Four categories cover nearly all of it:
- Local devices and internal suffixes.
*.lan,*.local,*.home.arpa, plus whatever your router appends to DHCP hostnames — a NAS, a printer, a hypervisor console, anything you reach by name on the same network. - Captive portals. Hotel and airport networks intercept a specific probe hostname and judge your connectivity by what comes back. A synthetic answer convinces the portal you are already online, so the login page never appears and the network stays half-open.
- Time synchronisation. NTP pool hostnames. Clock drift breaks certificate validation, and a certificate error is a spectacularly misleading symptom to debug.
- Anything that resolves a name and then passes the address on. Peer discovery, some game matchmaking, smart-home controllers that look up a hub and hand the result to another device. Whenever an address travels somewhere the table cannot follow, the placeholder has to go.
Sensible clients ship a starting list, and if you run a Windows, macOS or Linux clash desktop client you will usually find those defaults already present in a generated profile — worth reading once, because it tells you what the maintainers have already been bitten by. Add your own local suffixes on top; nobody can guess what your router calls itself.
nameserver, fallback, and Splitting the Resolvers
Three keys carry the upstream configuration, and they do different jobs.
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” – “*.home.arpa” – “+.pool.ntp.org” – “captive.apple.com” – “connectivitycheck.gstatic.com” default-nameserver: – 223.5.5.5 – 1.1.1.1 nameserver: – 223.5.5.5 – 119.29.29.29 fallback: – https://dns.google/dns-query – tls://1.1.1.1:853 fallback-filter: geoip: true geoip-code: CN ipcidr: – 240.0.0.0/4 nameserver-policy: “+.internal.example.com”: 10.0.0.53 “*.lan”: 192.168.1.1default-nameserver solves a bootstrap problem: encrypted upstreams are written as hostnames, and something has to resolve those. Plain-IP servers only.
nameserver is the primary set used for general queries. fallback is a second set consulted in parallel, typically over DoH or DoT, whose answers win when fallback-filter judges the primary result untrustworthy — for instance whenever the primary returns an address outside a given region or inside a suspicious range.
nameserver-policy is the precise tool and deserves more use than it gets. It pins patterns to specific resolvers — corporate zones to the corporate resolver, local suffixes to the router — without disturbing anything else. It is also how split routing stays coherent: if a domain’s traffic goes direct, its lookup belongs to a resolver on the same side of the split, or you get an answer optimised for a location your packets never visit.
Where Lookups Leak
A leak here means something narrower than the marketing usage: a query that left by a path contradicting the policy chosen for its traffic. Three mechanisms cause nearly all of them.
- An address rule evaluated too early. If the engine reaches a rule that tests an address and none is known yet, it obtains one so it can answer the question — pulling a resolution forward on a connection that a domain rule further down would have handled without one. The
no-resolveoption suppresses exactly this, and belongs on every address rule sitting above your domain block. - Traffic that never reached the engine. Under a plain system proxy, anything that ignores proxy settings resolves names on its own — one of the clearer arguments for a virtual adapter over a listener-only setup.
- An upstream reachable by the wrong route. If a fallback resolver was meant to be contacted through a proxy but the engine can reach it directly, it will.
The way to actually see this rather than theorise about it is the connections view. Watching the list while you load a single site shows resolutions appearing next to the requests that caused them, and a client such as clash-vergerev.co displays the matched rule for each entry — which turns “something is leaking” into “line 14 is missing an option” in about a minute.
Applications That Ignore Your Resolver Entirely
Some software does not ask. It has its own opinion about DNS and acts on it.
- Browsers with secure DNS enabled. Chrome and Firefox can speak DoH directly to a provider of their own choosing. Under a plain proxy this defeats fake-ip for browser traffic entirely; under a virtual adapter the queries at least travel through your routing, but are still answered by someone else’s server.
- Hardcoded addresses. Plenty of appliances, smart TVs and IoT devices contain a literal
8.8.8.8and no way to change it. - Container runtimes and virtual machines with their own resolver stacks and their own idea of the host network.
You notice it the same way each time: the engine’s log shows no query for a hostname that traffic is clearly reaching, so the name was either resolved elsewhere or served from a cache. The fixes are limited but real — turn off secure DNS in the browser, redirect outbound port 53 for hardcoded offenders, or accept the exception and route those connections by address.
Caches, and the Evening They Cost
There are at least three caches between an application and an answer: the engine’s, the operating system’s, and often the application’s. Changing enhanced-mode invalidates assumptions in all three at once, and the stale entries left behind produce symptoms that look exactly like configuration errors but are not.
Flush the system cache after any mode change. On Windows, ipconfig /flushdns. On macOS, sudo dscacheutil -flushcache; sudo killall -HUP mDNSResponder. On Linux it depends on the resolver in use — resolvectl flush-caches for systemd-resolved. Then restart the browser, which keeps its own and will not let go of it otherwise.
Telling a DNS Problem From a Routing Problem
The two produce similar complaints and want opposite fixes. This sequence separates them in a couple of minutes.
- Try the address directly. If connecting by IP works and by name does not, it is resolution. If both fail identically, it is routing or the node.
- Ask the engine’s resolver by hand.
dig @127.0.0.1 -p 1053 example.com. An answer in the fake-ip range means the synthetic path works. A real address means the name matched a filter entry, intended or otherwise. No answer means the resolver is not listening where you think. - Compare against a known upstream.
dig @1.1.1.1 example.com. If the answers agree but behaviour differs, the problem is downstream of resolution. - Check whether a query happened. Raise the log level and reload the page. Nothing logged means something resolved the name without you.
- Read the matched rule. A connection showing a bare address where you expected a hostname means the name was lost before the engine saw it: filter entry, external resolver or stale cache.
A rough heuristic: intermittent failures that clear on retry are usually resolution timeouts, consistent failures for one service are usually a rule, and everything breaking at once is usually the node or the adapter.
Questions That Come Up
Do I need fake-ip if I only use a system proxy?
Less urgently. With a listener-based setup, well-behaved applications hand the hostname to the proxy in the request itself, so domain rules already have what they need. fake-ip becomes important the moment traffic is captured at the adapter level, where no such handoff exists.
Is 198.18.0.1/16 safe to use?
Yes, in the sense that matters: reserved for benchmarking, allocated to nobody, never routed publicly. Change it only if it overlaps a network you genuinely use — some lab and carrier setups do — and replace it with another non-routable block.
My internal company hostnames stopped resolving. Why?
Two fixes, and you usually need both. Add the internal suffix to fake-ip-filter so it resolves genuinely, then pin it in nameserver-policy to the resolver that knows the zone. Public resolvers have never heard of your intranet.
Should IPv6 be enabled in the DNS block?
Leave it off unless you have a reason. Enabling it returns AAAA records that dual-stack applications will prefer, doubling the paths you have to reason about while many nodes handle v6 inconsistently.
Where This Leaves You
The DNS block looks like plumbing and behaves like policy. It decides whether a hostname is still attached to a connection when the rule list runs, which upstream sees each query, and which names skip the synthetic path entirely. Three keys carry most of that weight: enhanced-mode, fake-ip-filter and nameserver-policy.
If you are starting from a working profile, resist rewriting the block. Set fake-ip, add your local suffixes to the filter, pin any zone that needs a resolver which knows it, put no-resolve on the address rules sitting above your domain rules, and flush the caches. That covers the failures people actually hit. And when something does break later, ask the resolver question first — one dig command, ten seconds, and you know whether the next hour belongs in the dns: block or somewhere else entirely.
