Forráskód Böngészése

Improve DNS caching

世界 2 éve
szülő
commit
6f1b258501

+ 2 - 1
common/dialer/conntrack/packet_conn.go

@@ -4,6 +4,7 @@ import (
 	"io"
 	"net"
 
+	"github.com/sagernet/sing/common/bufio"
 	"github.com/sagernet/sing/common/x/list"
 )
 
@@ -42,7 +43,7 @@ func (c *PacketConn) Close() error {
 }
 
 func (c *PacketConn) Upstream() any {
-	return c.PacketConn
+	return bufio.NewPacketConn(c.PacketConn)
 }
 
 func (c *PacketConn) ReaderReplaceable() bool {

+ 5 - 0
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.

+ 5 - 0
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 地址的反向映射以为路由目的提供域名。

+ 2 - 2
go.mod

@@ -24,8 +24,8 @@ require (
 	github.com/sagernet/gomobile v0.0.0-20230413023804-244d7ff07035
 	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 v0.2.5-0.20230501044132-8365dd48a17a
+	github.com/sagernet/sing-dns v0.1.5-0.20230426113254-25d948c44223
 	github.com/sagernet/sing-mux v0.0.0-20230517134606-1ebe6bb26646
 	github.com/sagernet/sing-shadowsocks v0.2.2-0.20230417102954-f77257340507
 	github.com/sagernet/sing-shadowtls v0.1.2-0.20230417103049-4f682e05f19b

+ 4 - 4
go.sum

@@ -111,10 +111,10 @@ github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 h1:5Th31OC6yj8byL
 github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691/go.mod h1:B8lp4WkQ1PwNnrVMM6KyuFR20pU8jYBD+A4EhJovEXU=
 github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY=
 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 v0.2.5-0.20230501044132-8365dd48a17a h1:s2kkd/eR3mWGkYioknxhgQzG8uft4VRx9skhqxxeyVQ=
+github.com/sagernet/sing v0.2.5-0.20230501044132-8365dd48a17a/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w=
+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-20230517134606-1ebe6bb26646 h1:X3ADfMqeGns1Q1FlXc9kaL9FwW1UM6D6tEQo8jFstpc=
 github.com/sagernet/sing-mux v0.0.0-20230517134606-1ebe6bb26646/go.mod h1:pF+RnLvCAOhECrvauy6LYOpBakJ/vuaF1Wm4lPsWryI=
 github.com/sagernet/sing-shadowsocks v0.2.2-0.20230417102954-f77257340507 h1:bAHZCdWqJkb8LEW98+YsMVDXGRMUVjka8IC+St6ot88=

+ 4 - 3
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 {

+ 3 - 3
outbound/dns.go

@@ -104,18 +104,18 @@ func (d *DNS) handleConnection(ctx context.Context, conn net.Conn, metadata adap
 func (d *DNS) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error {
 	var reader N.PacketReader = conn
 	var counters []N.CountFunc
-	var cachedBuffer []*N.PacketBuffer
+	var cachedPackets []*N.PacketBuffer
 	for {
 		reader, counters = N.UnwrapCountPacketReader(reader, counters)
 		if cachedReader, isCached := reader.(N.CachedPacketReader); isCached {
 			packet := cachedReader.ReadCachedPacket()
 			if packet != nil {
-				cachedBuffer = append([]*N.PacketBuffer{packet}, cachedBuffer...)
+				cachedPackets = append(cachedPackets, packet)
 				continue
 			}
 		}
 		if readWaiter, created := bufio.CreatePacketReadWaiter(reader); created {
-			return d.newPacketConnection(ctx, conn, readWaiter, counters, cachedBuffer, metadata)
+			return d.newPacketConnection(ctx, conn, readWaiter, counters, cachedPackets, metadata)
 		}
 		break
 	}

+ 6 - 1
route/router.go

@@ -111,7 +111,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 {

+ 24 - 16
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)