Skip to content

feat(xdns): add resolver-based DNS tunneling with multi-resolver fan-out; fix sendLoop starvation#5871

Closed
nnemirovsky wants to merge 2 commits intoXTLS:mainfrom
nnemirovsky:xdns-resolver-multiplexing
Closed

feat(xdns): add resolver-based DNS tunneling with multi-resolver fan-out; fix sendLoop starvation#5871
nnemirovsky wants to merge 2 commits intoXTLS:mainfrom
nnemirovsky:xdns-resolver-multiplexing

Conversation

@nnemirovsky
Copy link
Copy Markdown

Summary

Two related changes to XDNS finalmask:

1. Resolver-based DNS tunneling (new feature)

Add optional resolvers config field. When set, the client sends DNS queries through public resolvers (1.1.1.1, 8.8.8.8, etc.) instead of connecting directly to the server on port 53.

  • Each resolver gets its own UDP socket and receive goroutine for parallel I/O
  • Round-robin distribution across resolvers
  • Fully backward compatible: omitting resolvers preserves current direct-connection behavior
  • Server needs no changes (already acts as authoritative DNS, uses embedded clientID for demux)

Config example:

"finalmask": {
  "udp": [{
    "type": "xdns",
    "settings": {
      "domain": "t.example.com",
      "resolvers": ["1.1.1.1", "8.8.8.8", "9.9.9.9"]
    }
  }]
}

Why: Direct connection to server:53 is easily blocked by IP. Routing through public DNS resolvers makes traffic look like normal DNS queries and enables multi-resolver multiplexing for better throughput.

2. Fix sendLoop starvation under mKCP load (bug fix)

The XDNS server sendLoop failed to deliver downstream data when mKCP generated retransmission floods. HTTPS connections through the tunnel would time out because:

  • The nextRec = <-c.ch case in the inner select caused the sendLoop to abandon responses whenever a new query arrived, resulting in empty responses under load
  • The 1-second maxResponseDelay was too slow, causing the sendLoop to fall behind
  • The write queue (capacity 512) overflowed and silently dropped data
  • The mKCP 30s connection timeout was too short for DNS tunnel latency

Changes:

  • Remove query preemption from sendLoop inner select
  • Drain excess records before processing to skip stale queries
  • Reduce response wait from 1s to 50ms
  • Increase server write queue from 512 to 4096
  • Increase mKCP connection timeout from 30s to 120s

Test plan

  • Unit tests for resolver address parsing (TestParseResolverAddr)
  • Integration test with mock resolver (TestResolverModeRoundTrip)
  • End-to-end round-trip test (TestDirectModeRoundTrip)
  • Verified HTTPS works through XDNS tunnel on localhost (both direct and resolver mode)

Add optional `resolvers` config field to XDNS finalmask. When set,
the client sends DNS queries through public DNS resolvers instead of
connecting directly to the server on port 53.

- One UDP socket per resolver with independent receive goroutines
- Round-robin query distribution across resolvers
- Backward compatible: omitting resolvers preserves direct mode
- Server unchanged (uses embedded clientID for demux)
- Unit tests for resolver parsing and mock resolver round-trip
- Remove nextRec query preemption from sendLoop inner select
- Drain excess records before processing to skip stale queries
- Reduce response wait from 1s to 50ms for faster turnaround
- Increase server write queue from 512 to 4096
- Increase mKCP connection timeout from 30s to 120s
@RPRX
Copy link
Copy Markdown
Member

RPRX commented Mar 31, 2026

这个不是本来就是在 outbound address 填 1.1.1.1 这类 public DNS 地址吗?

@LjhAUMEM

@nnemirovsky nnemirovsky force-pushed the xdns-resolver-multiplexing branch from e06f0d7 to c9faf7b Compare March 31, 2026 08:58
@nnemirovsky
Copy link
Copy Markdown
Author

nnemirovsky commented Mar 31, 2026

@RPRX, you're right that setting a public DNS address like 1.1.1.1 in the outbound address would route queries through a resolver. The DNS delegation (NS record) handles forwarding to the authoritative server automatically.

The resolvers field adds multi-resolver fan-out within a single mKCP session. Each resolver gets its own UDP socket and receive goroutine. Queries are distributed round-robin across all configured resolvers simultaneously. This increases throughput because each resolver is an independent bandwidth channel.

This can't be achieved with multiple vnext entries because Xray picks one address per connection. A single mKCP session would use only one resolver for its entire lifetime.

The sendLoop fix in the second commit is independent and addresses a real bug where downstream data delivery stalls under mKCP retransmission load.

@RPRX
Copy link
Copy Markdown
Member

RPRX commented Mar 31, 2026

大概懂了你是想实现 #4846 (comment) 这种多路径加速,这对于 XDNS 来说确实挺有用,而且还是 mKCP,这下成 mekya 了

有没有兴趣顺便实现 #4846 (comment)

@Fangliding
Copy link
Copy Markdown
Member

image 纯AI迷惑改动。。

@Fangliding Fangliding closed this Mar 31, 2026
@RPRX
Copy link
Copy Markdown
Member

RPRX commented Mar 31, 2026

我发现这些 AI PR 虽然无法被直接合并但有时候想法是有可取之处的,@LjhAUMEM 你看下吧

@nnemirovsky
Copy link
Copy Markdown
Author

@RPRX @Fangliding @LjhAUMEM, check this out please #5872. I cleaned up some AI artifacts and fixed what @RPRX asked for

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants