From 7050011802e21e5ffd7966b91549e551b4ababb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Wed, 26 Apr 2023 04:53:25 +0800 Subject: [PATCH] Improve DNS caching --- docs/configuration/dns/index.md | 5 ++++ docs/configuration/dns/index.zh.md | 5 ++++ go.mod | 2 +- go.sum | 4 +-- option/dns.go | 7 +++--- route/router.go | 7 +++++- route/router_dns.go | 40 ++++++++++++++++++------------ 7 files changed, 47 insertions(+), 23 deletions(-) diff --git a/docs/configuration/dns/index.md b/docs/configuration/dns/index.md index 40b26473..5f8b2547 100644 --- a/docs/configuration/dns/index.md +++ b/docs/configuration/dns/index.md @@ -11,6 +11,7 @@ "strategy": "", "disable_cache": false, "disable_expire": false, + "independent_cache": false, "reverse_mapping": false, "fakeip": {} } @@ -48,6 +49,10 @@ Disable dns cache. Disable dns cache expire. +#### independent_cache + +Make each DNS server's cache independent for special purposes. If enabled, will slightly degrade performance. + #### reverse_mapping Stores a reverse mapping of IP addresses after responding to a DNS query in order to provide domain names when routing. diff --git a/docs/configuration/dns/index.zh.md b/docs/configuration/dns/index.zh.md index 034d8dd3..b84f9528 100644 --- a/docs/configuration/dns/index.zh.md +++ b/docs/configuration/dns/index.zh.md @@ -11,6 +11,7 @@ "strategy": "", "disable_cache": false, "disable_expire": false, + "independent_cache": false, "reverse_mapping": false, "fakeip": {} } @@ -47,6 +48,10 @@ 禁用 DNS 缓存过期。 +#### independent_cache + +使每个 DNS 服务器的缓存独立,以满足特殊目的。如果启用,将轻微降低性能。 + #### reverse_mapping 在响应 DNS 查询后存储 IP 地址的反向映射以为路由目的提供域名。 diff --git a/go.mod b/go.mod index 51006355..a867a726 100644 --- a/go.mod +++ b/go.mod @@ -25,7 +25,7 @@ require ( github.com/sagernet/quic-go v0.0.0-20230202071646-a8c8afb18b32 github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 github.com/sagernet/sing v0.2.5-0.20230425122720-bf0aaacc6754 - github.com/sagernet/sing-dns v0.1.5-0.20230415085626-111ecf799dfc + github.com/sagernet/sing-dns v0.1.5-0.20230426113254-25d948c44223 github.com/sagernet/sing-mux v0.0.0-20230425130511-b0a6ffd8406f github.com/sagernet/sing-shadowsocks v0.2.2-0.20230417102954-f77257340507 github.com/sagernet/sing-shadowtls v0.1.2-0.20230417103049-4f682e05f19b diff --git a/go.sum b/go.sum index 6573d88d..440adcb3 100644 --- a/go.sum +++ b/go.sum @@ -113,8 +113,8 @@ github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2 github.com/sagernet/sing v0.1.8/go.mod h1:jt1w2u7lJQFFSGLiRrRIs5YWmx4kAPfWuOejuDW9qMk= github.com/sagernet/sing v0.2.5-0.20230425122720-bf0aaacc6754 h1:y89Ntm1rrZPQVb1f+TKd4DH6NwX5XCyMIwoseTQd/5U= github.com/sagernet/sing v0.2.5-0.20230425122720-bf0aaacc6754/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w= -github.com/sagernet/sing-dns v0.1.5-0.20230415085626-111ecf799dfc h1:hmbuqKv48SAjiKPoqtJGvS5pEHVPZjTHq9CPwQY2cZ4= -github.com/sagernet/sing-dns v0.1.5-0.20230415085626-111ecf799dfc/go.mod h1:ZKuuqgsHRxDahYrzgSgy4vIAGGuKPlIf4hLcNzYzLkY= +github.com/sagernet/sing-dns v0.1.5-0.20230426113254-25d948c44223 h1:L4eMuM07iSHY3UCknFnuFuHoe5clZuF2Xnf2wwA6Lwc= +github.com/sagernet/sing-dns v0.1.5-0.20230426113254-25d948c44223/go.mod h1:ZKuuqgsHRxDahYrzgSgy4vIAGGuKPlIf4hLcNzYzLkY= github.com/sagernet/sing-mux v0.0.0-20230425130511-b0a6ffd8406f h1:iEpOTgBTjt0vZJVXMTqYq13XyIu/337TWbq6WZ3CMWc= github.com/sagernet/sing-mux v0.0.0-20230425130511-b0a6ffd8406f/go.mod h1:pF+RnLvCAOhECrvauy6LYOpBakJ/vuaF1Wm4lPsWryI= github.com/sagernet/sing-shadowsocks v0.2.2-0.20230417102954-f77257340507 h1:bAHZCdWqJkb8LEW98+YsMVDXGRMUVjka8IC+St6ot88= diff --git a/option/dns.go b/option/dns.go index d700252c..1e73fb5f 100644 --- a/option/dns.go +++ b/option/dns.go @@ -20,9 +20,10 @@ type DNSServerOptions struct { } type DNSClientOptions struct { - Strategy DomainStrategy `json:"strategy,omitempty"` - DisableCache bool `json:"disable_cache,omitempty"` - DisableExpire bool `json:"disable_expire,omitempty"` + Strategy DomainStrategy `json:"strategy,omitempty"` + DisableCache bool `json:"disable_cache,omitempty"` + DisableExpire bool `json:"disable_expire,omitempty"` + IndependentCache bool `json:"independent_cache,omitempty"` } type DNSFakeIPOptions struct { diff --git a/route/router.go b/route/router.go index e95e7d47..4202b796 100644 --- a/route/router.go +++ b/route/router.go @@ -113,7 +113,12 @@ func NewRouter( defaultMark: options.DefaultMark, platformInterface: platformInterface, } - router.dnsClient = dns.NewClient(dnsOptions.DNSClientOptions.DisableCache, dnsOptions.DNSClientOptions.DisableExpire, router.dnsLogger) + router.dnsClient = dns.NewClient(dns.ClientOptions{ + DisableCache: dnsOptions.DNSClientOptions.DisableCache, + DisableExpire: dnsOptions.DNSClientOptions.DisableExpire, + IndependentCache: dnsOptions.DNSClientOptions.IndependentCache, + Logger: router.dnsLogger, + }) for i, ruleOptions := range options.Rules { routeRule, err := NewRule(router, router.logger, ruleOptions) if err != nil { diff --git a/route/router_dns.go b/route/router_dns.go index d343fb8b..0b693371 100644 --- a/route/router_dns.go +++ b/route/router_dns.go @@ -73,23 +73,31 @@ func (r *Router) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, er if len(message.Question) > 0 { r.dnsLogger.DebugContext(ctx, "exchange ", formatQuestion(message.Question[0].String())) } - ctx, metadata := adapter.AppendContext(ctx) - if len(message.Question) > 0 { - metadata.QueryType = message.Question[0].Qtype - switch metadata.QueryType { - case mDNS.TypeA: - metadata.IPVersion = 4 - case mDNS.TypeAAAA: - metadata.IPVersion = 6 + var ( + response *mDNS.Msg + cached bool + err error + ) + response, cached = r.dnsClient.ExchangeCache(ctx, message) + if !cached { + ctx, metadata := adapter.AppendContext(ctx) + if len(message.Question) > 0 { + metadata.QueryType = message.Question[0].Qtype + switch metadata.QueryType { + case mDNS.TypeA: + metadata.IPVersion = 4 + case mDNS.TypeAAAA: + metadata.IPVersion = 6 + } + metadata.Domain = fqdnToDomain(message.Question[0].Name) + } + ctx, transport, strategy := r.matchDNS(ctx) + ctx, cancel := context.WithTimeout(ctx, C.DNSTimeout) + defer cancel() + response, err = r.dnsClient.Exchange(ctx, transport, message, strategy) + if err != nil && len(message.Question) > 0 { + r.dnsLogger.ErrorContext(ctx, E.Cause(err, "exchange failed for ", formatQuestion(message.Question[0].String()))) } - metadata.Domain = fqdnToDomain(message.Question[0].Name) - } - ctx, transport, strategy := r.matchDNS(ctx) - ctx, cancel := context.WithTimeout(ctx, C.DNSTimeout) - defer cancel() - response, err := r.dnsClient.Exchange(ctx, transport, message, strategy) - if err != nil && len(message.Question) > 0 { - r.dnsLogger.ErrorContext(ctx, E.Cause(err, "exchange failed for ", formatQuestion(message.Question[0].String()))) } if len(message.Question) > 0 && response != nil { LogDNSAnswers(r.dnsLogger, ctx, message.Question[0].Name, response.Answer)