Skip to content

Add configurable DNS query timeout#4079

Open
comebackto2021 wants to merge 59 commits into
SagerNet:testingfrom
comebackto2021:feat-configurable-dns-timeout
Open

Add configurable DNS query timeout#4079
comebackto2021 wants to merge 59 commits into
SagerNet:testingfrom
comebackto2021:feat-configurable-dns-timeout

Conversation

@comebackto2021
Copy link
Copy Markdown

Summary

Adds a timeout field to DNS configuration so the DNS exchange timeout can
be tuned per-deployment via JSON config. Previously hardcoded to
C.DNSTimeout = 10s in dns/client.go.

The Client.timeout field is already parameterized in code — NewClient()
accepts options.Timeout and falls back to C.DNSTimeout when zero. This
PR only wires up the JSON option and threads it through dns.NewRouter.

Motivation

On unstable mobile networks (carrier-grade NAT with aggressive timeouts,
DPI middleboxes on TCP/53), plain TCP DNS sockets can become "zombies"
after long idle periods — bytes are silently dropped while the kernel
still considers the socket valid. The full 10-second timeout is then
user-visible latency on the first query after inactivity.

Industry comparison for DNS exchange/per-attempt timeouts:

System Default
Microsoft Windows DNS client 1s first retry (5 attempts in 10s budget)
Microsoft Windows Server forwarder 3s
ThousandEyes DNS resolution test 3s measurement
Linux glibc RES_TIMEOUT 5s default, community recommends 1-3s
sing-box 10s, single attempt, not configurable

Operators deploying sing-box across many users on heterogeneous networks
have no way to tune this without forking and shipping custom libbox builds
to every client platform (Android AAR, Apple framework, Windows DLL).

Changes

  • option/dns.go: add Timeout badoption.Duration to DNSClientOptions
  • dns/router.go: pass it to dns.NewClient via existing ClientOptions.Timeout
  • docs/configuration/dns/index.md and index.zh.md: document the new field

Backward compatibility

Field is omitempty. When unset (time.Duration(0)), dns/client.go:80-82
falls back to C.DNSTimeout = 10s, preserving existing behavior. No
migration needed.

Example

{
  "dns": {
    "timeout": "3s",
    "servers": [...]
  }
}

Verification

  • go build ./... — passes
  • go vet ./option/... ./dns/... — clean
  • go test ./option/... ./dns/... — all green
  • Config validation: "timeout": "3s" accepted, invalid duration string rejected
    with clear error pointing to dns.timeout JSON path
  • Backward compatibility: configs without the field validate and run as before

@nekohasekai nekohasekai force-pushed the testing branch 6 times, most recently from 8f15b13 to 9ee56ae Compare May 3, 2026 01:08
@nekohasekai nekohasekai force-pushed the testing branch 6 times, most recently from 057f540 to 6b07a22 Compare May 15, 2026 05:29
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.

2 participants