dns: Add timeout configuration

This commit is contained in:
世界 2026-04-28 14:29:52 +08:00
parent 60a5f874e2
commit 1bad8d87eb
No known key found for this signature in database
GPG key ID: CD109927C34A63C4
18 changed files with 141 additions and 10 deletions

View file

@ -38,6 +38,7 @@ type DNSQueryOptions struct {
DisableCache bool
DisableOptimisticCache bool
RewriteTTL *uint32
Timeout time.Duration
ClientSubnet netip.Prefix
}
@ -56,6 +57,7 @@ func DNSQueryOptionsFrom(ctx context.Context, options *option.DomainResolveOptio
DisableCache: options.DisableCache,
DisableOptimisticCache: options.DisableOptimisticCache,
RewriteTTL: options.RewriteTTL,
Timeout: time.Duration(options.Timeout),
ClientSubnet: options.ClientSubnet.Build(netip.Prefix{}),
}, nil
}

View file

@ -97,6 +97,7 @@ func NewWithOptions(options Options) (N.Dialer, error) {
dnsQueryOptions = adapter.DNSQueryOptions{
Transport: transport,
Strategy: strategy,
Timeout: time.Duration(dialOptions.DomainResolver.Timeout),
DisableCache: dialOptions.DomainResolver.DisableCache,
DisableOptimisticCache: dialOptions.DomainResolver.DisableOptimisticCache,
RewriteTTL: dialOptions.DomainResolver.RewriteTTL,

View file

@ -222,7 +222,7 @@ func (c *Client) Exchange(ctx context.Context, transport adapter.DNSTransport, m
return nil, ErrResponseRejectedCached
}
}
response, err := c.exchangeToTransport(ctx, transport, message)
response, err := c.exchangeToTransport(ctx, transport, message, options.Timeout)
if err != nil {
return nil, err
}
@ -497,7 +497,7 @@ func (c *Client) backgroundRefreshDNS(transport adapter.DNSTransport, question d
go func() {
defer c.backgroundRefresh.Delete(key)
ctx := contextWithTransportTag(c.ctx, transport.Tag())
response, err := c.exchangeToTransport(ctx, transport, message)
response, err := c.exchangeToTransport(ctx, transport, message, options.Timeout)
if err != nil {
if c.logger != nil {
c.logger.DebugContext(ctx, "optimistic refresh failed for ", FqdnToDomain(question.Name), ": ", err)
@ -552,8 +552,11 @@ func stripDNSPadding(response *dns.Msg) {
}
}
func (c *Client) exchangeToTransport(ctx context.Context, transport adapter.DNSTransport, message *dns.Msg) (*dns.Msg, error) {
ctx, cancel := context.WithTimeout(ctx, c.timeout)
func (c *Client) exchangeToTransport(ctx context.Context, transport adapter.DNSTransport, message *dns.Msg, timeout time.Duration) (*dns.Msg, error) {
if timeout == 0 {
timeout = c.timeout
}
ctx, cancel := context.WithTimeout(ctx, timeout)
defer cancel()
response, err := transport.Exchange(ctx, message)
if err == nil {

View file

@ -80,6 +80,7 @@ func NewRouter(ctx context.Context, logFactory log.Factory, options option.DNSOp
}
router.client = NewClient(ClientOptions{
Context: ctx,
Timeout: time.Duration(options.DNSClientOptions.Timeout),
DisableCache: options.DNSClientOptions.DisableCache,
DisableExpire: options.DNSClientOptions.DisableExpire,
OptimisticTimeout: optimisticTimeout,
@ -314,6 +315,9 @@ func (r *Router) matchDNS(ctx context.Context, rules []adapter.DNSRule, allowFak
if action.RewriteTTL != nil {
options.RewriteTTL = action.RewriteTTL
}
if action.Timeout > 0 {
options.Timeout = action.Timeout
}
if action.ClientSubnet.IsValid() {
options.ClientSubnet = action.ClientSubnet
}
@ -328,6 +332,9 @@ func (r *Router) matchDNS(ctx context.Context, rules []adapter.DNSRule, allowFak
if action.RewriteTTL != nil {
options.RewriteTTL = action.RewriteTTL
}
if action.Timeout > 0 {
options.Timeout = action.Timeout
}
if action.ClientSubnet.IsValid() {
options.ClientSubnet = action.ClientSubnet
}
@ -355,6 +362,9 @@ func (r *Router) applyDNSRouteOptions(options *adapter.DNSQueryOptions, routeOpt
if routeOptions.RewriteTTL != nil {
options.RewriteTTL = routeOptions.RewriteTTL
}
if routeOptions.Timeout > 0 {
options.Timeout = routeOptions.Timeout
}
if routeOptions.ClientSubnet.IsValid() {
options.ClientSubnet = routeOptions.ClientSubnet
}

View file

@ -5,7 +5,8 @@ icon: material/alert-decagram
!!! quote "Changes in sing-box 1.14.0"
:material-delete-clock: [independent_cache](#independent_cache)
:material-plus: [optimistic](#optimistic)
:material-plus: [optimistic](#optimistic)
:material-plus: [timeout](#timeout)
!!! quote "Changes in sing-box 1.12.0"
@ -31,6 +32,7 @@ icon: material/alert-decagram
"independent_cache": false,
"cache_capacity": 0,
"optimistic": false, // or {}
"timeout": "",
"reverse_mapping": false,
"client_subnet": "",
"fakeip": {}
@ -115,6 +117,16 @@ The maximum time an expired cache entry can be served optimistically.
`3d` is used by default.
#### timeout
!!! question "Since sing-box 1.14.0"
Default timeout for each DNS query.
`10s` is used by default.
Can be overridden by `rules.[].timeout` (DNS rule action) or `domain_resolver.timeout`.
#### reverse_mapping
Stores a reverse mapping of IP addresses after responding to a DNS query in order to provide domain names when routing.

View file

@ -5,7 +5,8 @@ icon: material/alert-decagram
!!! quote "sing-box 1.14.0 中的更改"
:material-delete-clock: [independent_cache](#independent_cache)
:material-plus: [optimistic](#optimistic)
:material-plus: [optimistic](#optimistic)
:material-plus: [timeout](#timeout)
!!! quote "sing-box 1.12.0 中的更改"
@ -31,6 +32,7 @@ icon: material/alert-decagram
"independent_cache": false,
"cache_capacity": 0,
"optimistic": false, // or {}
"timeout": "",
"reverse_mapping": false,
"client_subnet": "",
"fakeip": {}
@ -114,6 +116,16 @@ LRU 缓存容量。
默认使用 `3d`
#### timeout
!!! question "自 sing-box 1.14.0 起"
每次 DNS 查询的默认超时时间。
默认使用 `10s`
可被 `rules.[].timeout`DNS 规则动作)或 `domain_resolver.timeout` 覆盖。
#### reverse_mapping
在响应 DNS 查询后存储 IP 地址的反向映射以为路由目的提供域名。

View file

@ -7,7 +7,8 @@ icon: material/new-box
:material-delete-clock: [strategy](#strategy)
:material-plus: [evaluate](#evaluate)
:material-plus: [respond](#respond)
:material-plus: [disable_optimistic_cache](#disable_optimistic_cache)
:material-plus: [disable_optimistic_cache](#disable_optimistic_cache)
:material-plus: [timeout](#timeout)
!!! quote "Changes in sing-box 1.12.0"
@ -26,6 +27,7 @@ icon: material/new-box
"disable_cache": false,
"disable_optimistic_cache": false,
"rewrite_ttl": null,
"timeout": "",
"client_subnet": null
}
```
@ -64,6 +66,14 @@ Disable optimistic DNS caching in this query.
Rewrite TTL in DNS responses.
#### timeout
!!! question "Since sing-box 1.14.0"
Override the DNS query timeout for matched queries.
Will override `dns.timeout`.
#### client_subnet
Append a `edns0-subnet` OPT extra record with the specified IP prefix to every query by default.
@ -83,6 +93,7 @@ Will override `dns.client_subnet`.
"disable_cache": false,
"disable_optimistic_cache": false,
"rewrite_ttl": null,
"timeout": "",
"client_subnet": null
}
```
@ -116,6 +127,14 @@ Disable optimistic DNS caching in this query.
Rewrite TTL in DNS responses.
#### timeout
!!! question "Since sing-box 1.14.0"
Override the DNS query timeout for matched queries.
Will override `dns.timeout`.
#### client_subnet
Append a `edns0-subnet` OPT extra record with the specified IP prefix to every query by default.
@ -148,6 +167,7 @@ Only allowed after a preceding top-level `evaluate` rule. If the action is reach
"disable_cache": false,
"disable_optimistic_cache": false,
"rewrite_ttl": null,
"timeout": "",
"client_subnet": null
}
```

View file

@ -7,7 +7,8 @@ icon: material/new-box
:material-delete-clock: [strategy](#strategy)
:material-plus: [evaluate](#evaluate)
:material-plus: [respond](#respond)
:material-plus: [disable_optimistic_cache](#disable_optimistic_cache)
:material-plus: [disable_optimistic_cache](#disable_optimistic_cache)
:material-plus: [timeout](#timeout)
!!! quote "sing-box 1.12.0 中的更改"
@ -26,6 +27,7 @@ icon: material/new-box
"disable_cache": false,
"disable_optimistic_cache": false,
"rewrite_ttl": null,
"timeout": "",
"client_subnet": null
}
```
@ -64,6 +66,14 @@ icon: material/new-box
重写 DNS 回应中的 TTL。
#### timeout
!!! question "自 sing-box 1.14.0 起"
覆盖匹配查询的 DNS 查询超时时间。
将覆盖 `dns.timeout`
#### client_subnet
默认情况下,将带有指定 IP 前缀的 `edns0-subnet` OPT 附加记录附加到每个查询。
@ -83,6 +93,7 @@ icon: material/new-box
"disable_cache": false,
"disable_optimistic_cache": false,
"rewrite_ttl": null,
"timeout": "",
"client_subnet": null
}
```
@ -114,6 +125,14 @@ icon: material/new-box
重写 DNS 回应中的 TTL。
#### timeout
!!! question "自 sing-box 1.14.0 起"
覆盖匹配查询的 DNS 查询超时时间。
将覆盖 `dns.timeout`
#### client_subnet
默认情况下,将带有指定 IP 前缀的 `edns0-subnet` OPT 附加记录附加到每个查询。
@ -146,6 +165,7 @@ icon: material/new-box
"disable_cache": false,
"disable_optimistic_cache": false,
"rewrite_ttl": null,
"timeout": "",
"client_subnet": null
}
```

View file

@ -9,7 +9,8 @@ icon: material/new-box
!!! quote "Changes in sing-box 1.14.0"
:material-plus: [resolve.disable_optimistic_cache](#disable_optimistic_cache)
:material-plus: [resolve.disable_optimistic_cache](#disable_optimistic_cache)
:material-plus: [resolve.timeout](#timeout)
!!! quote "Changes in sing-box 1.12.0"
@ -285,6 +286,7 @@ Timeout for sniffing.
"disable_cache": false,
"disable_optimistic_cache": false,
"rewrite_ttl": null,
"timeout": "",
"client_subnet": null
}
```
@ -319,6 +321,14 @@ Disable optimistic DNS caching in this query.
Rewrite TTL in DNS responses.
#### timeout
!!! question "Since sing-box 1.14.0"
Override the DNS query timeout for this lookup.
Will override `dns.timeout`.
#### client_subnet
!!! question "Since sing-box 1.12.0"

View file

@ -9,7 +9,8 @@ icon: material/new-box
!!! quote "sing-box 1.14.0 中的更改"
:material-plus: [resolve.disable_optimistic_cache](#disable_optimistic_cache)
:material-plus: [resolve.disable_optimistic_cache](#disable_optimistic_cache)
:material-plus: [resolve.timeout](#timeout)
!!! quote "sing-box 1.12.0 中的更改"
@ -277,6 +278,7 @@ UDP 连接超时时间。
"disable_cache": false,
"disable_optimistic_cache": false,
"rewrite_ttl": null,
"timeout": "",
"client_subnet": null
}
```
@ -311,6 +313,14 @@ DNS 解析策略,可用值有:`prefer_ipv4`、`prefer_ipv6`、`ipv4_only`、
重写 DNS 回应中的 TTL。
#### timeout
!!! question "自 sing-box 1.14.0 起"
覆盖此查询的 DNS 查询超时时间。
将覆盖 `dns.timeout`
#### client_subnet
!!! question "自 sing-box 1.12.0 起"

View file

@ -2,6 +2,10 @@
icon: material/new-box
---
!!! quote "Changes in sing-box 1.14.0"
:material-alert: [domain_resolver](#domain_resolver)
!!! quote "Changes in sing-box 1.13.0"
:material-plus: [disable_tcp_keep_alive](#disable_tcp_keep_alive)

View file

@ -2,6 +2,10 @@
icon: material/new-box
---
!!! quote "sing-box 1.14.0 中的更改"
:material-alert: [domain_resolver](#domain_resolver)
!!! quote "sing-box 1.13.0 中的更改"
:material-plus: [disable_tcp_keep_alive](#disable_tcp_keep_alive)

View file

@ -48,6 +48,7 @@ func (o *DNSOptions) UnmarshalJSONContext(ctx context.Context, content []byte) e
type DNSClientOptions struct {
Strategy DomainStrategy `json:"strategy,omitempty"`
Timeout badoption.Duration `json:"timeout,omitempty"`
DisableCache bool `json:"disable_cache,omitempty"`
DisableExpire bool `json:"disable_expire,omitempty"`
IndependentCache bool `json:"independent_cache,omitempty"`

View file

@ -94,6 +94,7 @@ type DialerOptions struct {
type _DomainResolveOptions struct {
Server string `json:"server"`
Timeout badoption.Duration `json:"timeout,omitempty"`
Strategy DomainStrategy `json:"strategy,omitempty"`
DisableCache bool `json:"disable_cache,omitempty"`
DisableOptimisticCache bool `json:"disable_optimistic_cache,omitempty"`
@ -107,6 +108,7 @@ func (o DomainResolveOptions) MarshalJSON() ([]byte, error) {
if o.Server == "" {
return []byte("{}"), nil
} else if o.Strategy == DomainStrategy(C.DomainStrategyAsIS) &&
o.Timeout == 0 &&
!o.DisableCache &&
!o.DisableOptimisticCache &&
o.RewriteTTL == nil &&

View file

@ -202,6 +202,7 @@ func (r *RouteOptionsActionOptions) UnmarshalJSON(data []byte) error {
type DNSRouteActionOptions struct {
Server string `json:"server,omitempty"`
Timeout badoption.Duration `json:"timeout,omitempty"`
Strategy DomainStrategy `json:"strategy,omitempty"`
DisableCache bool `json:"disable_cache,omitempty"`
DisableOptimisticCache bool `json:"disable_optimistic_cache,omitempty"`
@ -211,6 +212,7 @@ type DNSRouteActionOptions struct {
type _DNSRouteOptionsActionOptions struct {
Strategy DomainStrategy `json:"strategy,omitempty"`
Timeout badoption.Duration `json:"timeout,omitempty"`
DisableCache bool `json:"disable_cache,omitempty"`
DisableOptimisticCache bool `json:"disable_optimistic_cache,omitempty"`
RewriteTTL *uint32 `json:"rewrite_ttl,omitempty"`
@ -324,6 +326,7 @@ type RouteActionSniff struct {
type RouteActionResolve struct {
Server string `json:"server,omitempty"`
Timeout badoption.Duration `json:"timeout,omitempty"`
Strategy DomainStrategy `json:"strategy,omitempty"`
DisableCache bool `json:"disable_cache,omitempty"`
DisableOptimisticCache bool `json:"disable_optimistic_cache,omitempty"`

View file

@ -79,6 +79,7 @@ func NewNetworkManager(ctx context.Context, logger logger.ContextLogger, options
DomainResolver: defaultDomainResolver.Server,
DomainResolveOptions: adapter.DNSQueryOptions{
Strategy: C.DomainStrategy(defaultDomainResolver.Strategy),
Timeout: time.Duration(defaultDomainResolver.Timeout),
DisableCache: defaultDomainResolver.DisableCache,
DisableOptimisticCache: defaultDomainResolver.DisableOptimisticCache,
RewriteTTL: defaultDomainResolver.RewriteTTL,

View file

@ -791,6 +791,7 @@ func (r *Router) actionResolve(ctx context.Context, metadata *adapter.InboundCon
DisableCache: action.DisableCache,
DisableOptimisticCache: action.DisableOptimisticCache,
RewriteTTL: action.RewriteTTL,
Timeout: action.Timeout,
ClientSubnet: action.ClientSubnet,
})
if err != nil {

View file

@ -108,6 +108,7 @@ func NewRuleAction(ctx context.Context, logger logger.ContextLogger, action opti
case C.RuleActionTypeResolve:
return &RuleActionResolve{
Server: action.ResolveOptions.Server,
Timeout: time.Duration(action.ResolveOptions.Timeout),
Strategy: C.DomainStrategy(action.ResolveOptions.Strategy),
DisableCache: action.ResolveOptions.DisableCache,
DisableOptimisticCache: action.ResolveOptions.DisableOptimisticCache,
@ -128,6 +129,7 @@ func NewDNSRuleAction(logger logger.ContextLogger, action option.DNSRuleAction)
Server: action.RouteOptions.Server,
RuleActionDNSRouteOptions: RuleActionDNSRouteOptions{
Strategy: C.DomainStrategy(action.RouteOptions.Strategy),
Timeout: time.Duration(action.RouteOptions.Timeout),
DisableCache: action.RouteOptions.DisableCache,
DisableOptimisticCache: action.RouteOptions.DisableOptimisticCache,
RewriteTTL: action.RouteOptions.RewriteTTL,
@ -139,6 +141,7 @@ func NewDNSRuleAction(logger logger.ContextLogger, action option.DNSRuleAction)
Server: action.RouteOptions.Server,
RuleActionDNSRouteOptions: RuleActionDNSRouteOptions{
Strategy: C.DomainStrategy(action.RouteOptions.Strategy),
Timeout: time.Duration(action.RouteOptions.Timeout),
DisableCache: action.RouteOptions.DisableCache,
DisableOptimisticCache: action.RouteOptions.DisableOptimisticCache,
RewriteTTL: action.RouteOptions.RewriteTTL,
@ -150,6 +153,7 @@ func NewDNSRuleAction(logger logger.ContextLogger, action option.DNSRuleAction)
case C.RuleActionTypeRouteOptions:
return &RuleActionDNSRouteOptions{
Strategy: C.DomainStrategy(action.RouteOptionsOptions.Strategy),
Timeout: time.Duration(action.RouteOptionsOptions.Timeout),
DisableCache: action.RouteOptionsOptions.DisableCache,
DisableOptimisticCache: action.RouteOptionsOptions.DisableOptimisticCache,
RewriteTTL: action.RouteOptionsOptions.RewriteTTL,
@ -320,6 +324,9 @@ func formatDNSRouteAction(action string, server string, options RuleActionDNSRou
if options.RewriteTTL != nil {
descriptions = append(descriptions, F.ToString("rewrite-ttl=", *options.RewriteTTL))
}
if options.Timeout > 0 {
descriptions = append(descriptions, F.ToString("timeout=", options.Timeout.String()))
}
if options.ClientSubnet.IsValid() {
descriptions = append(descriptions, F.ToString("client-subnet=", options.ClientSubnet))
}
@ -328,6 +335,7 @@ func formatDNSRouteAction(action string, server string, options RuleActionDNSRou
type RuleActionDNSRouteOptions struct {
Strategy C.DomainStrategy
Timeout time.Duration
DisableCache bool
DisableOptimisticCache bool
RewriteTTL *uint32
@ -349,6 +357,9 @@ func (r *RuleActionDNSRouteOptions) String() string {
if r.RewriteTTL != nil {
descriptions = append(descriptions, F.ToString("rewrite-ttl=", *r.RewriteTTL))
}
if r.Timeout > 0 {
descriptions = append(descriptions, F.ToString("timeout=", r.Timeout.String()))
}
if r.ClientSubnet.IsValid() {
descriptions = append(descriptions, F.ToString("client-subnet=", r.ClientSubnet))
}
@ -522,6 +533,7 @@ func (r *RuleActionSniff) String() string {
type RuleActionResolve struct {
Server string
Timeout time.Duration
Strategy C.DomainStrategy
DisableCache bool
DisableOptimisticCache bool
@ -550,6 +562,9 @@ func (r *RuleActionResolve) String() string {
if r.RewriteTTL != nil {
options = append(options, F.ToString("rewrite_ttl=", *r.RewriteTTL))
}
if r.Timeout > 0 {
options = append(options, F.ToString("timeout=", r.Timeout.String()))
}
if r.ClientSubnet.IsValid() {
options = append(options, F.ToString("client_subnet=", r.ClientSubnet))
}