V2Ray DNS Routing: Split DNS, DoH & DNS Pollution Protection

Learn how to configure DNS servers, domains, and expectIPs; route domains in mainland China and elsewhere to different resolvers; and reduce DNS pollution with routing rules.

At a glance

First identify which component resolves each domain. Then configure a dedicated resolver for domains in mainland China and an encrypted resolver for others, and use routing rules to choose the outbound path for DNS requests. This guide is for users who can already connect to a node and are ready to edit the core configuration. The examples are configuration snippets, not complete node files you can import as-is.

1. Check Whether DNS Requests Reach the Core

First, distinguish two things: DNS resolution translates domain names into IP addresses, while routing determines whether a connection goes direct or through a proxy. Editing only the dns section does not automatically send every app's DNS requests through V2Ray. Adding proxy rules alone also cannot guarantee that an app received the correct address in the first place.

App submits a domain Core evaluates rules Resolve an address if needed Select an outbound route

This is the typical path when an app passes a domain to the core. If the app resolves the name locally and submits only an IP address, the core receives something different. Browser Secure DNS, system DNS, and a client's built-in DNS can all be active at the same time. A single DNS field cannot tell you which resolver handled a request.

2. Understand servers, domains, and expectIPs

Group domains first, then assign a resolver to each group. servers is the list of DNS resolvers. An entry can be a simple address or an object with matching conditions. For separate resolution of domains in mainland China and elsewhere, object entries make the behavior easier to verify.

FieldPurposeNotes
serversLists available resolversDon't assume the first entry is always used. Match conditions and fallback settings affect resolver selection.
domainsSpecifies domains to prioritize for this resolvergeosite:cn requires the core to be able to read the corresponding domain data file.
expectIPsChecks whether returned addresses fall within the expected rangegeoip:cn filters by IP geolocation; it does not verify content safety or prove a domain is authentic.
skipFallbackControls whether this server handles fallback queries for unmatched domainsWhen set to true, it can still resolve queries matching its domains.
queryStrategySelects the address type to queryUseIPv4 queries IPv4 addresses only; it does not disable IPv6 across the system.
tagTags the source of built-in DNS queriesCan be matched by a routing rule's inboundTag, provided the query passes through core routing.

geosite contains domain classification data; geoip contains IP address classification data. They are not interchangeable. domains also supports matching a domain and its subdomains with entries such as domain:example.com. When troubleshooting one site, start with a specific domain rule. It's easier to isolate the issue than replacing an entire set of classification data.

Key point: Treat expectIPs as a filter, not a DNS pollution switch

Keep the geoip:cn restriction only when you specifically want that domain to return an IP address in mainland China. If the site uses an overseas CDN, check the rejected addresses and their actual locations before narrowing the rule. Don't treat every non-China address as polluted.

3. Configure a Mainland China Resolver and Encrypted DNS for Other Domains

Here is a basic, easy-to-check example: domains classified as mainland China use 223.5.5.5 first, while other domains use https://1.1.1.1/dns-query. The latter is DoH, which sends DNS queries over HTTPS. The example uses IPv4 to reduce dual-stack variables during initial troubleshooting; it does not mean IPv6 is inherently problematic.

{
  "dns": {
    "tag": "dns-query",
    "queryStrategy": "UseIPv4",
    "servers": [
      {
        "address": "223.5.5.5",
        "port": 53,
        "domains": [
          "geosite:cn"
        ],
        "expectIPs": [
          "geoip:cn"
        ],
        "skipFallback": true
      },
      {
        "address": "https://1.1.1.1/dns-query",
        "skipFallback": false
      }
    ]
  }
}
53
Example mainland China UDP DNS port
443
Default HTTPS port
2 resolver groups
Example resolver configuration

Here, skipFallback: true keeps the mainland China resolver out of ordinary fallback queries for unmatched domains. It does not mean that a query will never fall back if resolution through the mainland China resolver fails. If that resolver returns no result matching expectIPs, other applicable servers may still be tried when fallback is enabled. Fallback is not the same as strict isolation.

4. Use Routing Rules to Choose the DNS Outbound Path

First check your existing outbound tags. The snippet below assumes you already have a direct outbound tagged direct and a working proxy outbound tagged proxy. These are example names; DNS settings do not create them. If your tags differ, replace each with the actual name. Keep your existing VMess or VLESS node parameters unchanged.

{
  "routing": {
    "domainStrategy": "IPIfNonMatch",
    "rules": [
      {
        "type": "field",
        "inboundTag": ["dns-query"],
        "ip": ["223.5.5.5"],
        "port": "53",
        "outboundTag": "direct"
      },
      {
        "type": "field",
        "inboundTag": ["dns-query"],
        "outboundTag": "proxy"
      },
      {
        "type": "field",
        "domain": ["geosite:cn"],
        "outboundTag": "direct"
      },
      {
        "type": "field",
        "ip": ["geoip:private", "geoip:cn"],
        "outboundTag": "direct"
      }
    ]
  }
}

Rules are evaluated in order. The first rule sends only requests tagged dns-query and addressed to 223.5.5.5:53 through the direct outbound. The second sends other queries with the same tag through the proxy. If a broad proxy rule for DNS comes first, mainland China DNS requests will match it too, making the configured mainland China resolver take an unnecessarily indirect route.

  1. Put DNS-specific rules before broad rules. If the existing config includes rules for direct access on all ports, global proxying, or routing by inbound, check which rule matches first.
  2. Understand IPIfNonMatch. When a domain does not match an applicable rule, the core can use built-in DNS to resolve it and then try IP rules. This does not mean every domain must be resolved first.
  3. Keep your existing default outbound design. This snippet does not include a final catch-all rule. Traffic that matches no rule depends on the default outbound in your full config, so check outbound order when merging.
  4. Check how the proxy server hostname is resolved. If the proxy server address is a domain name, its only resolution path must not depend on a proxy connection that hasn't been established yet. Set up a reachable bootstrap resolver path specifically for that hostname if needed.

5. Verify DNS Routing with Logs and Test Requests

First verify which resolver handled the request and which outbound it used; then check whether the site loads. Running nslookup alone usually tests the resolver configured in the operating system, so it cannot prove that V2Ray's built-in DNS followed the rules. DNS leak test pages often show the recursive resolver's location, not your local proxy's outbound location.

  1. Temporarily enable more detailed logging. Set loglevel to debug in the existing log object, then restart the core. Set it back to warning when you're done to avoid logging large amounts of domain and connection details over time.
  2. Restart the test path. Restarting the core clears interference from its cache for this test. Close and reopen the test app, and clear its own DNS cache if needed. Refreshing a page alone may not trigger a new query.
  3. Test a domain that clearly matches the mainland China rule. Confirm that the corresponding DNS query appears in the logs, and check whether requests to 223.5.5.5:53 use direct. Cached requests, or requests routed directly by a domain rule, may not generate a new core DNS log entry.
  4. Test a domain not included in the mainland China group. Check that it uses the DoH resolver and that the connection uses proxy. Log formats vary by core, so cross-check the resolver address, destination domain, and outbound tag.
  5. Test app and local-resolution paths separately. On desktop, compare the two commands below, but first replace the port with the actual SOCKS listening port shown by your client.
curl --socks5-hostname 127.0.0.1:10808 -I https://example.com
curl --socks5 127.0.0.1:10808 -I https://example.com

The first command has the SOCKS proxy handle the destination domain. In the second, curl resolves the domain locally and submits the address. 10808 is just an example port; it may not match your listening port. Even if both commands succeed, that doesn't prove the core performed DNS resolution: the proxy outbound may pass the domain to the remote server. Confirm the path in the logs.

Troubleshooting: Find Where the Request Stops

If there is no query in the logs, check the cache and whether the app submitted a domain. If a query appears but times out, check the resolver's outbound route. If an address is returned but the connection fails, investigate routing, the node, and the destination service. Checking these three stages is more effective than repeatedly changing DNS addresses.

6. DNS Routing FAQs and Recovery Steps

All websites stopped working after I changed DNS. What should I check first?

Restore your backup first and confirm that the node still works, then check the core startup logs. Start with JSON syntax errors, failed classification data loads, and outbound tags that don't exist. Once the core starts, check whether DoH depends on a proxy server hostname that hasn't been resolved yet.

Some mainland China sites fail occasionally. Is expectIPs wrong?

First check whether geoip:cn is excluding the returned address. Temporarily remove this restriction for the specific domain or add a narrower rule, then restart and test again. If the site uses an overseas CDN, adjust its DNS policy rather than assuming the resolver is polluted.

Why does a DNS test still show my local ISP when I'm using DoH?

Check Secure DNS under your browser's settings, system DNS, and whether the app is bypassing the proxy. Then check whether the core actually received a query for that domain. DoH encrypts only the query sent to its specified resolver; it does not take over DNS for every app.

Why did my DNS settings change after updating the subscription?

First distinguish subscription node data from the core config generated by the client. Don't edit temporary JSON that gets recreated at every startup. Save DNS settings through the client's persistent settings or custom configuration entry point. After an update, inspect the active config and check dns and rule order.

Can querying IPv4 only cause problems for some apps?

It can affect destinations that rely on IPv6. First use UseIPv4 for basic validation, then switch to UseIP in a dual-stack environment and check IPv6 routing and outbound connectivity. Don't restore AAAA queries without also restoring the connection path for IPv6.

Keep a working copy of the config that starts, resolves domains, and connects. Change one variable at a time: try a different resolver first, then adjust domain groups, and finally tune fallback and address filtering. For more field details, see the site's configuration field reference and check each setting against your actual core version.

Download the client