Jelajahi Sumber

Refactor to miekg/dns

世界 3 tahun lalu
induk
melakukan
007a278ac8
9 mengubah file dengan 55 tambahan dan 119 penghapusan
  1. 2 2
      adapter/router.go
  2. 4 12
      common/sniff/dns.go
  3. 1 1
      common/tls/acme.go
  4. 9 19
      common/tls/ech_client.go
  5. 0 11
      docs/contributing/sub-projects.md
  6. 2 2
      go.mod
  7. 4 4
      go.sum
  8. 5 5
      outbound/dns.go
  9. 28 63
      route/router_dns.go

+ 2 - 2
adapter/router.go

@@ -11,7 +11,7 @@ import (
 	"github.com/sagernet/sing/common/control"
 	N "github.com/sagernet/sing/common/network"
 
-	"golang.org/x/net/dns/dnsmessage"
+	mdns "github.com/miekg/dns"
 )
 
 type Router interface {
@@ -27,7 +27,7 @@ type Router interface {
 	GeoIPReader() *geoip.Reader
 	LoadGeosite(code string) (Rule, error)
 
-	Exchange(ctx context.Context, message *dnsmessage.Message) (*dnsmessage.Message, error)
+	Exchange(ctx context.Context, message *mdns.Msg) (*mdns.Msg, error)
 	Lookup(ctx context.Context, domain string, strategy dns.DomainStrategy) ([]netip.Addr, error)
 	LookupDefault(ctx context.Context, domain string) ([]netip.Addr, error)
 

+ 4 - 12
common/sniff/dns.go

@@ -13,7 +13,7 @@ import (
 	"github.com/sagernet/sing/common/buf"
 	"github.com/sagernet/sing/common/task"
 
-	"golang.org/x/net/dns/dnsmessage"
+	mDNS "github.com/miekg/dns"
 )
 
 func StreamDomainNameQuery(readCtx context.Context, reader io.Reader) (*adapter.InboundContext, error) {
@@ -44,18 +44,10 @@ func StreamDomainNameQuery(readCtx context.Context, reader io.Reader) (*adapter.
 }
 
 func DomainNameQuery(ctx context.Context, packet []byte) (*adapter.InboundContext, error) {
-	var parser dnsmessage.Parser
-	_, err := parser.Start(packet)
+	var msg mDNS.Msg
+	err := msg.Unpack(packet)
 	if err != nil {
 		return nil, err
 	}
-	question, err := parser.Question()
-	if err != nil {
-		return nil, os.ErrInvalid
-	}
-	domain := question.Name.String()
-	if question.Class == dnsmessage.ClassINET && IsDomainName(domain) {
-		return &adapter.InboundContext{Protocol: C.ProtocolDNS /*, Domain: domain*/}, nil
-	}
-	return nil, os.ErrInvalid
+	return &adapter.InboundContext{Protocol: C.ProtocolDNS}, nil
 }

+ 1 - 1
common/tls/acme.go

@@ -7,11 +7,11 @@ import (
 	"crypto/tls"
 	"strings"
 
-	"github.com/sagernet/certmagic"
 	"github.com/sagernet/sing-box/adapter"
 	"github.com/sagernet/sing-box/option"
 	E "github.com/sagernet/sing/common/exceptions"
 
+	"github.com/caddyserver/certmagic"
 	"github.com/mholt/acmez/acme"
 )
 

+ 9 - 19
common/tls/ech_client.go

@@ -18,7 +18,6 @@ import (
 	E "github.com/sagernet/sing/common/exceptions"
 
 	mDNS "github.com/miekg/dns"
-	"golang.org/x/net/dns/dnsmessage"
 )
 
 type echClientConfig struct {
@@ -170,15 +169,15 @@ const typeHTTPS = 65
 
 func fetchECHClientConfig(router adapter.Router) func(ctx context.Context, serverName string) ([]cftls.ECHConfig, error) {
 	return func(ctx context.Context, serverName string) ([]cftls.ECHConfig, error) {
-		message := &dnsmessage.Message{
-			Header: dnsmessage.Header{
+		message := &mDNS.Msg{
+			MsgHdr: mDNS.MsgHdr{
 				RecursionDesired: true,
 			},
-			Questions: []dnsmessage.Question{
+			Question: []mDNS.Question{
 				{
-					Name:  dnsmessage.MustNewName(serverName + "."),
-					Type:  typeHTTPS,
-					Class: dnsmessage.ClassINET,
+					Name:   serverName + ".",
+					Qtype:  mDNS.TypeHTTPS,
+					Qclass: mDNS.ClassINET,
 				},
 			},
 		}
@@ -186,19 +185,10 @@ func fetchECHClientConfig(router adapter.Router) func(ctx context.Context, serve
 		if err != nil {
 			return nil, err
 		}
-		if response.RCode != dnsmessage.RCodeSuccess {
-			return nil, dns.RCodeError(response.RCode)
+		if response.Rcode != mDNS.RcodeSuccess {
+			return nil, dns.RCodeError(response.Rcode)
 		}
-		content, err := response.Pack()
-		if err != nil {
-			return nil, err
-		}
-		var mMsg mDNS.Msg
-		err = mMsg.Unpack(content)
-		if err != nil {
-			return nil, err
-		}
-		for _, rr := range mMsg.Answer {
+		for _, rr := range response.Answer {
 			switch resource := rr.(type) {
 			case *mDNS.HTTPS:
 				for _, value := range resource.Value {

+ 0 - 11
docs/contributing/sub-projects.md

@@ -53,17 +53,6 @@ we need to do this.
 
 The library needs to be updated with the upstream.
 
-#### certmagic
-
-Link: [GitHub repository](https://github.com/SagerNet/certmagic)
-
-Fork of `caddyserver/certmagic`
-
-Since upstream uses `miekg/dns` and we use `x/net/dnsmessage`, we need to replace its DNS part with our own
-implementation.
-
-The library needs to be updated with the upstream.
-
 #### smux
 
 Link: [GitHub repository](https://github.com/SagerNet/smux)

+ 2 - 2
go.mod

@@ -4,6 +4,7 @@ go 1.18
 
 require (
 	berty.tech/go-libtor v1.0.385
+	github.com/caddyserver/certmagic v0.17.1
 	github.com/cloudflare/circl v1.2.1-0.20220831060716-4cf0150356fc
 	github.com/cretz/bine v0.2.0
 	github.com/database64128/tfo-go v1.1.2
@@ -20,11 +21,10 @@ require (
 	github.com/oschwald/maxminddb-golang v1.10.0
 	github.com/pires/go-proxyproto v0.6.2
 	github.com/refraction-networking/utls v1.1.2
-	github.com/sagernet/certmagic v0.0.0-20220819042630-4a57f8b6853a
 	github.com/sagernet/quic-go v0.0.0-20220818150011-de611ab3e2bb
 	github.com/sagernet/shadowsocksr v0.0.0-20220912092645-c9ab93f81bb0
 	github.com/sagernet/sing v0.0.0-20220913004915-27ddefbb8921
-	github.com/sagernet/sing-dns v0.0.0-20220822023312-3e086b06d666
+	github.com/sagernet/sing-dns v0.0.0-20220913080251-628caf4acef7
 	github.com/sagernet/sing-shadowsocks v0.0.0-20220819002358-7461bb09a8f6
 	github.com/sagernet/sing-tun v0.0.0-20220911034209-c7dd5d457e24
 	github.com/sagernet/sing-vmess v0.0.0-20220913015714-c4ab86d40e12

+ 4 - 4
go.sum

@@ -10,6 +10,8 @@ github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHG
 github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
 github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
 github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
+github.com/caddyserver/certmagic v0.17.1 h1:VrWANhQAj3brK7jAUKyN6XBHg56WsyorI/84Ilq1tCQ=
+github.com/caddyserver/certmagic v0.17.1/go.mod h1:pSS2aZcdKlrTZrb2DKuRafckx20o5Fz1EdDKEB8KOQM=
 github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
 github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
 github.com/cloudflare/circl v1.2.1-0.20220831060716-4cf0150356fc h1:307gdRLiZ08dwOIKwc5lAQ19DRFaQQvdhHalyB4Asx8=
@@ -133,8 +135,6 @@ github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6L
 github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
 github.com/sagernet/abx-go v0.0.0-20220819185957-dba1257d738e h1:5CFRo8FJbCuf5s/eTBdZpmMbn8Fe2eSMLNAYfKanA34=
 github.com/sagernet/abx-go v0.0.0-20220819185957-dba1257d738e/go.mod h1:qbt0dWObotCfcjAJJ9AxtFPNSDUfZF+6dCpgKEOBn/g=
-github.com/sagernet/certmagic v0.0.0-20220819042630-4a57f8b6853a h1:SE3Xn4GOQ+kxbgGa2Xp0H2CCsx1o2pVTt0f+hmfuHH4=
-github.com/sagernet/certmagic v0.0.0-20220819042630-4a57f8b6853a/go.mod h1:Q+ZXyesnkjV5B70B1ixk65ecKrlJ2jz0atv3fPKsVVo=
 github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 h1:5+m7c6AkmAylhauulqN/c5dnh8/KssrE9c93TQrXldA=
 github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61/go.mod h1:QUQ4RRHD6hGGHdFMEtR8T2P6GS6R3D/CXKdaYHKKXms=
 github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6EslacyapiRz7LLSJyr4RajF/BhMVyE=
@@ -147,8 +147,8 @@ github.com/sagernet/sing v0.0.0-20220812082120-05f9836bff8f/go.mod h1:QVsS5L/ZA2
 github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY=
 github.com/sagernet/sing v0.0.0-20220913004915-27ddefbb8921 h1:xUHzlIbdlPV/fkToIO9futp9lmKIY+72ezk/whQ8XsI=
 github.com/sagernet/sing v0.0.0-20220913004915-27ddefbb8921/go.mod h1:kZvzh1VDa/Dg/Bt5WaYKU0jl5ept8KKDpl3Ay4gRtRQ=
-github.com/sagernet/sing-dns v0.0.0-20220822023312-3e086b06d666 h1:XUTocA/Ek0dFxUX+xJCWMPPFZCn2GC/uLrBjTSr1vHY=
-github.com/sagernet/sing-dns v0.0.0-20220822023312-3e086b06d666/go.mod h1:eDyH7AJmqBGjZQdQmpZIzlbTREudZuWDExMuGKgjRVM=
+github.com/sagernet/sing-dns v0.0.0-20220913080251-628caf4acef7 h1:hGmqtoGifhIy/XFczifR4coknjBIE8f1Suyd1SJc2F4=
+github.com/sagernet/sing-dns v0.0.0-20220913080251-628caf4acef7/go.mod h1:NxH8BRDCYo28ZoojuNdRZEt9zbYgyAvC7WxEEkaUBCM=
 github.com/sagernet/sing-shadowsocks v0.0.0-20220819002358-7461bb09a8f6 h1:JJfDeYYhWunvtxsU/mOVNTmFQmnzGx9dY034qG6G3g4=
 github.com/sagernet/sing-shadowsocks v0.0.0-20220819002358-7461bb09a8f6/go.mod h1:EX3RbZvrwAkPI2nuGa78T2iQXmrkT+/VQtskjou42xM=
 github.com/sagernet/sing-tun v0.0.0-20220911034209-c7dd5d457e24 h1:LsmPeFvj4GhiV5Y7Rm8I845XysdxVN4MQmfZ36P5bmw=

+ 5 - 5
outbound/dns.go

@@ -16,7 +16,7 @@ import (
 	N "github.com/sagernet/sing/common/network"
 	"github.com/sagernet/sing/common/task"
 
-	"golang.org/x/net/dns/dnsmessage"
+	mDNS "github.com/miekg/dns"
 )
 
 var _ adapter.Outbound = (*DNS)(nil)
@@ -72,7 +72,7 @@ func (d *DNS) handleConnection(ctx context.Context, conn net.Conn, metadata adap
 	if err != nil {
 		return err
 	}
-	var message dnsmessage.Message
+	var message mDNS.Msg
 	err = message.Unpack(buffer.Bytes())
 	if err != nil {
 		return err
@@ -88,7 +88,7 @@ func (d *DNS) handleConnection(ctx context.Context, conn net.Conn, metadata adap
 		responseBuffer := common.Dup(_responseBuffer)
 		defer responseBuffer.Release()
 		responseBuffer.Resize(2, 0)
-		n, err := response.AppendPack(responseBuffer.Index(0))
+		n, err := response.PackBuffer(responseBuffer.FreeBytes())
 		if err != nil {
 			return err
 		}
@@ -117,7 +117,7 @@ func (d *DNS) NewPacketConnection(ctx context.Context, conn N.PacketConn, metada
 			if err != nil {
 				return err
 			}
-			var message dnsmessage.Message
+			var message mDNS.Msg
 			err = message.Unpack(buffer.Bytes())
 			if err != nil {
 				return err
@@ -131,7 +131,7 @@ func (d *DNS) NewPacketConnection(ctx context.Context, conn N.PacketConn, metada
 				}
 				timeout.Update()
 				responseBuffer := buf.NewPacket()
-				n, err := response.AppendPack(responseBuffer.Index(0))
+				n, err := response.PackBuffer(responseBuffer.FreeBytes())
 				if err != nil {
 					responseBuffer.Release()
 					return err

+ 28 - 63
route/router_dns.go

@@ -12,7 +12,7 @@ import (
 	E "github.com/sagernet/sing/common/exceptions"
 	F "github.com/sagernet/sing/common/format"
 
-	"golang.org/x/net/dns/dnsmessage"
+	mDNS "github.com/miekg/dns"
 )
 
 func (r *Router) matchDNS(ctx context.Context) (context.Context, dns.Transport, dns.DomainStrategy) {
@@ -40,29 +40,29 @@ func (r *Router) matchDNS(ctx context.Context) (context.Context, dns.Transport,
 	return ctx, r.defaultTransport, r.defaultDomainStrategy
 }
 
-func (r *Router) Exchange(ctx context.Context, message *dnsmessage.Message) (*dnsmessage.Message, error) {
-	if len(message.Questions) > 0 {
-		r.dnsLogger.DebugContext(ctx, "exchange ", formatDNSQuestion(message.Questions[0]))
+func (r *Router) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, error) {
+	if len(message.Question) > 0 {
+		r.dnsLogger.DebugContext(ctx, "exchange ", formatQuestion(message.Question[0].String()))
 	}
 	ctx, metadata := adapter.AppendContext(ctx)
-	if len(message.Questions) > 0 {
-		switch message.Questions[0].Type {
-		case dnsmessage.TypeA:
+	if len(message.Question) > 0 {
+		switch message.Question[0].Qtype {
+		case mDNS.TypeA:
 			metadata.IPVersion = 4
-		case dnsmessage.TypeAAAA:
+		case mDNS.TypeAAAA:
 			metadata.IPVersion = 6
 		}
-		metadata.Domain = string(message.Questions[0].Name.Data[:message.Questions[0].Name.Length-1])
+		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.Questions) > 0 {
-		r.dnsLogger.ErrorContext(ctx, E.Cause(err, "exchange failed for ", message.Questions[0].Name.String()))
+	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.Questions) > 0 && response != nil {
-		LogDNSAnswers(r.dnsLogger, ctx, message.Questions[0].Name.String(), response.Answers)
+	if len(message.Question) > 0 && response != nil {
+		LogDNSAnswers(r.dnsLogger, ctx, message.Question[0].Name, response.Answer)
 	}
 	return response, err
 }
@@ -93,61 +93,26 @@ func (r *Router) LookupDefault(ctx context.Context, domain string) ([]netip.Addr
 	return r.Lookup(ctx, domain, dns.DomainStrategyAsIS)
 }
 
-func LogDNSAnswers(logger log.ContextLogger, ctx context.Context, domain string, answers []dnsmessage.Resource) {
-	for _, rawAnswer := range answers {
-		var content string
-		switch answer := rawAnswer.Body.(type) {
-		case *dnsmessage.AResource:
-			content = netip.AddrFrom4(answer.A).String()
-		case *dnsmessage.NSResource:
-			content = answer.NS.String()
-		case *dnsmessage.CNAMEResource:
-			content = answer.CNAME.String()
-		case *dnsmessage.SOAResource:
-			content = answer.MBox.String()
-		case *dnsmessage.PTRResource:
-			content = answer.PTR.String()
-		case *dnsmessage.MXResource:
-			content = answer.MX.String()
-		case *dnsmessage.TXTResource:
-			content = strings.Join(answer.TXT, " ")
-		case *dnsmessage.AAAAResource:
-			content = netip.AddrFrom16(answer.AAAA).String()
-		case *dnsmessage.SRVResource:
-			content = answer.Target.String()
-		case *dnsmessage.UnknownResource:
-			content = answer.Type.String()
-		default:
-			continue
-		}
-		rType := formatDNSType(rawAnswer.Header.Type)
-		if rType == "" {
-			logger.InfoContext(ctx, "exchanged ", domain, " ", rType)
-		} else {
-			logger.InfoContext(ctx, "exchanged ", domain, " ", rType, " ", content)
-		}
+func LogDNSAnswers(logger log.ContextLogger, ctx context.Context, domain string, answers []mDNS.RR) {
+	for _, answer := range answers {
+		logger.InfoContext(ctx, "exchanged ", domain, " ", mDNS.Type(answer.Header().Rrtype).String(), " ", formatQuestion(answer.String()))
 	}
 }
 
-func formatDNSQuestion(question dnsmessage.Question) string {
-	var qType string
-	qType = question.Type.String()
-	if len(qType) > 4 {
-		qType = qType[4:]
-	}
-	var qClass string
-	qClass = question.Class.String()
-	if len(qClass) > 5 {
-		qClass = qClass[5:]
+func fqdnToDomain(fqdn string) string {
+	if mDNS.IsFqdn(fqdn) {
+		return fqdn[:len(fqdn)-1]
 	}
-	return string(question.Name.Data[:question.Name.Length-1]) + " " + qType + " " + qClass
+	return fqdn
 }
 
-func formatDNSType(qType dnsmessage.Type) string {
-	qTypeName := qType.String()
-	if len(qTypeName) > 4 {
-		return qTypeName[4:]
-	} else {
-		return F.ToString("unknown (type ", qTypeName, ")")
+func formatQuestion(string string) string {
+	if strings.HasPrefix(string, ";") {
+		string = string[1:]
+	}
+	string = strings.ReplaceAll(string, "\t", " ")
+	for strings.Contains(string, "  ") {
+		string = strings.ReplaceAll(string, "  ", " ")
 	}
+	return string
 }