At a glance

For users who have imported a subscription and can access websites but are seeing unexpected DNS test results. First, distinguish expected direct DNS lookups from unintended bypasses. Cross-check with system queries, core logs, and packet captures on the physical network adapter. Then assign separate roles to remote and direct DNS, and verify TUN coverage and FakeDNS domain restoration. The examples are core configuration snippets, not complete client configuration files.

1. What Is a DNS Leak? When DNS and Web Traffic Take Different Routes

DNS translates domain names into IP addresses. An established proxy connection does not mean the DNS lookup that came before it also used the proxy. For example, an app might ask your home router for a destination IP, then send the connection through a local proxy port. The webpage appears to use the proxy, but your local resolver may still see the domain you visited. A leak is a lookup that violates your intended routing policy—not simply any lookup handled by a local resolver.

App requests a domain lookup DNS rules are matched Query route is selected Destination address is returned Connection rules are matched

Using direct DNS for websites in mainland China that are meant to connect directly is usually reasonable. The issue this guide addresses is a domain that should use the proxy but whose DNS query goes to a resolver on the local network. VMess and VLESS handle proxy traffic; they do not automatically capture every DNS request made by the system. A subscription provides node settings, not necessarily a complete DNS policy for your device.

How it worksDNS paths that are easy to missWhat to check
System proxyApps that ignore the system proxy may still use system DNSDoes the app resolve domains locally or use its own DNS?
SOCKS proxyThe app sends only an IP address, not the domain nameIs the app configured to resolve domains through the proxy?
TUN routingTraffic may bypass the tunnel through excluded routes, IPv6, or built-in encrypted DNSAre the virtual adapter, DNS interception, and outbound rules all active?

2. How to Test for DNS Leaks: Establish a Baseline, Then Check the Physical Adapter

A browser-based test shows the recursive resolver's egress as seen by the test site; it may not be the server your client connects to directly. Public DNS services may use exits in different regions, and the city shown may come from an outdated geolocation database. So don't treat a mismatch between the resolver's city and your proxy node's city as conclusive evidence. Check which network adapter carries the query and whether that matches your rules.

53
Traditional DNS: UDP/TCP ports
443
Common port for DoH over HTTPS
853
Common port for DoT over TLS
  1. Record a baseline. Turn off TUN and the system proxy. Note your system DNS addresses, the browser's Secure DNS setting, and the resolvers listed by the test site. Don't visit sensitive sites during testing.
  2. Keep variables constant. Use the same node and routing rules for each test, and test the same page. Don't switch nodes or change browser DNS settings mid-test, or you won't know which change affected the result.
  3. Clear the cache. On Windows, run ipconfig /flushdns in a terminal, then close and reopen the browser. The core's DNS cache usually requires a core restart to clear.
  4. Check system lookups. Run the command below and note the default resolver and query result. This shows the system's DNS path; the browser may use a different one.
  5. Check the physical adapter. In your packet capture tool, select the Ethernet or Wi-Fi adapter that is connected to the internet. Check whether the query goes directly to a local resolver. Seeing DNS packets on a virtual adapter alone does not mean they have left your device.
ipconfig /all
ipconfig /flushdns
nslookup example.com

# Packet capture display filter: check traditional DNS and common DoT connections
udp.port == 53 || tcp.port == 53 || tcp.port == 853

example.com is a sample domain for demonstrating a query, not a DNS leak test service. For a real test, choose a domain your rules explicitly route through the proxy. Browser-based DoH uses HTTPS, so a port 53 filter won't identify it on its own. Check the browser's Secure DNS settings, connection destination, and client routing logs together.

Bottom line: Check whether the target domain bypasses the proxy, not how many resolvers appear

Choose a test domain that should clearly use the proxy. If a plaintext query for that domain still appears on the physical adapter going to a local resolver, check system DNS, app-level DNS, and TUN exclusions one by one. If multiple public resolver locations appear, first confirm whether they belong to the same DNS service.

3. Remote and Direct DNS in v2rayN: Configure Both the Resolver and Its Route

In v2rayN, open Settings → Parameters and check the active core and listener settings. Then go to Settings → DNS Settings and review the DNS configuration for that core. Menu locations and field names vary by version, so use the current interface and generated configuration as your reference. Pay particular attention to the difference between the core used for regular proxy connections and the one used by TUN. Don't paste a DNS JSON block into the configuration area for a different core.

Use remote DNS for domains that should connect through the proxy, and direct DNS for domains explicitly routed directly. Configuring a remote resolver is only the first step: if the connection to that resolver still goes direct, encrypted queries or not, DNS is not following the proxy route. DoH encrypts the connection to the resolver; it does not choose a proxy outbound for you.

Xray DNS snippet: match direct domains separately and use remote DNS for the rest

This example uses Xray configuration syntax. It requires geosite.dat to support the geosite:cn category. If the rule data is missing, fix the data file first or use an explicit list of domains instead. The example addresses illustrate the intended roles; verify that they are reachable on your network. disableFallbackIfMatch prevents a matched domain group from falling through to another resolver on failure, but it cannot control queries made independently by browsers or apps.

{
  "dns": {
    "queryStrategy": "UseIP",
    "disableFallbackIfMatch": true,
    "servers": [
      {
        "address": "223.5.5.5",
        "domains": ["geosite:cn"],
        "skipFallback": true
      },
      {
        "address": "https://1.1.1.1/dns-query"
      }
    ]
  }
}

Merge the following rules into your existing routing.rules; don't replace the entire routing configuration. This example assumes your configuration has outbounds named proxy and direct. If the client generates different tags, use the actual tags. The example selects an outbound by resolver IP, which can also affect other connections to those IPs. Review the impact against your existing rules before using it.

{
  "routing": {
    "rules": [
      {
        "type": "field",
        "ip": ["1.1.1.1/32"],
        "outboundTag": "proxy"
      },
      {
        "type": "field",
        "ip": ["223.5.5.5/32"],
        "outboundTag": "direct"
      }
    ]
  }
}

4. Prevent DNS Leaks in TUN Mode: Handle DNS and IPv6 After Capturing Traffic

TUN routes system traffic through a virtual network adapter, making it useful for apps that ignore the system proxy. But it is not a switch that forces every request through the proxy: routing rules still decide whether traffic goes direct or through the proxy. Whether DNS is intercepted and sent through a controlled resolution path also depends on the TUN configuration. Save your current settings, enable “Enable TUN” on the v2rayN main screen, grant the required system permissions, and check the startup log.

  1. Confirm the virtual adapter is up. If the core fails to start, fix the permission, driver, or configuration issue first. Don't try to hide a startup failure by changing DNS settings.
  2. Confirm DNS is being captured. Check that the TUN configuration includes applicable DNS hijacking or redirection rules, then verify with system lookups and a packet capture. Changing the adapter's DNS address alone won't control apps with hard-coded resolvers.
  3. Review routing exclusions. You can route local network traffic directly if needed, but make sure exclusions aren't also letting DNS requests that should use the proxy escape. Broad direct rules must not match the remote resolver's address first.
  4. Check IPv6 too. Capturing IPv4 traffic in TUN does not mean IPv6 is covered. Check the IPv6 default route and DNS servers. If you don't need IPv6, you can temporarily disable it to compare results after considering the impact—but disabling IPv6 is not a universal fix.
  5. Test reconnection and resume from sleep. Run another lookup after switching Wi-Fi networks or waking the device from sleep. The adapter's DNS, system routes, and virtual adapter state may have changed.

v2rayN's TUN implementation may use the sing-box core, whose DNS and FakeIP configuration differs from Xray FakeDNS. Configure it through the appropriate settings or in the format for that core. v2rayNG uses Xray, while v2flyNG uses V2Fly, but Android VPN capture, app exclusions, and DNS behavior still depend on the client configuration. Don't copy desktop JSON directly into Android client settings.

Bottom line: Verify traffic capture coverage before adding DNS features

First confirm that the target app's IPv4, IPv6, and DNS traffic all enter the expected handling path; only then consider FakeDNS. If the browser works but other apps still bypass the proxy, check app exclusions, hard-coded resolvers, and proxy-side DNS options instead of repeatedly switching nodes.

5. How to Configure FakeDNS: Restore the Domain on the Same Traffic Path

FakeDNS returns a mapped address from an address pool, not the website's real IP. When the app connects to that address, the core restores the original domain from the mapping, then applies domain-based routing and connects through the proxy. This can avoid looking up the real IP in advance, but FakeDNS is not encrypted DNS and does not, by itself, prevent leaks. Node bootstrap lookups, direct destinations, and DNS requests from uncontrolled apps still need separate handling.

Query the target domain Assign a mapped address App starts a connection Core restores the domain Proxy rules are matched

The following is an example snippet for an Xray core that supports this feature. 198.18.0.0/15 is a benchmarking address range commonly used for this type of mapping, not a real website address. Check for conflicts with your local network, other VPNs, or existing routes before using it. poolSize sets the mapping pool capacity; it does not indicate speed or concurrent connection capacity.

{
  "fakedns": [
    {
      "ipPool": "198.18.0.0/15",
      "poolSize": 65535
    }
  ],
  "dns": {
    "servers": ["fakedns"]
  }
}

The inbound that handles subsequent connections must also be able to restore FakeDNS domains. For example, configure the sniffing fields below on that inbound. Merge them into an existing inbound object; don't use them as a standalone inbound. This demonstrates mapping and restoration only—it does not include DNS traffic capture, node bootstrap lookups, or exceptions for direct domains.

{
  "sniffing": {
    "enabled": true,
    "destOverride": ["fakedns"],
    "metadataOnly": true
  }
}

6. Common DNS Errors: Identify Which Layer Failed First

The following are error snippets you may see in logs. Exact wording and prefixes vary by core version, and a single error only points you in a direction. For each test, change one setting at a time and note whether the error came from connecting to the node, the remote resolver, or the destination website.

Error: failed to lookup ip for domain

Cause and fix: The domain lookup did not return a usable address. First determine whether the failed domain is the node address or the destination, then check the relevant DNS resolver's reachability, domain-matching rules, and IPv4/IPv6 lookup settings.

Error: context deadline exceeded

Cause and fix: An operation did not complete before its deadline; this error is not specific to DNS. Check nearby log entries to see whether the failure occurred during a DNS query, then inspect the resolver's outbound route, connection timeouts, and possible bootstrap lookup loops.

Error: network is unreachable

Cause and fix: There is no available route to the destination on the current network. Check the IP address family shown in the error, TUN routes, and outbound interface. In particular, check whether DNS returned only an IPv6 address when the network has no IPv6 route.

Error: no such host

Cause and fix: The resolver path in use could not resolve the hostname. Check the spelling, system resolver, and node bootstrap path. Don't assume from this message alone that remote DNS is blocked.

7. Retesting FAQs: A Working Browser Doesn't Prove the Whole Device Is Covered

The test page still shows a local resolver. Does that always mean there's a leak?

Not necessarily. First check whether the test domain was meant to go direct under your rules, and review the browser's Secure DNS settings. If it should clearly use the proxy, look for a matching plaintext query on the physical adapter. Planned direct lookups for domains in mainland China are not the same issue.

Why does DNS still exit through my local network after I enable DoH?

DoH changes only how the query is sent. Check whether the HTTPS connection to the remote resolver uses the proxy outbound, whether the browser is creating it independently, and whether the query is bypassing the core's routing. Fix the outbound route first, then test again.

What should I do if subscription updates fail after enabling TUN?

Check bootstrap resolution for the subscription URL and node addresses. Temporarily restore the DNS and routing settings that worked before, confirm the update completes, then enable the new settings one at a time. Don't make subscription updates depend on a proxy connection that isn't established yet and requires the same DNS path to come up.

Some apps keep timing out after I enable FakeDNS. What should I check?

Restart the core, run ipconfig /flushdns, then restart the affected app. Check whether its connection to the mapped address reaches an inbound that can restore the domain. If it still isn't compatible, configure real DNS resolution for that app or domain, then verify its DNS route.

How can I check that the fix still works after switching networks?

Test on your current network, after switching networks, and after resuming from sleep. Each time, record the system DNS, TUN status, and lookup results for one proxy-routed domain and one direct domain; check IPv6 too. A single browser test proves only that one request path worked at that moment.

A complete validation should confirm the whole chain: proxy-routed domains use a controlled DNS path, connections to the remote resolver use the expected outbound, direct domains resolve according to policy, node addresses can be bootstrapped independently, and TUN and IPv6 coverage are understood. To review the basic setup, see the subscription import guide, DNS configuration guide, and TUN mode guide.