diff --git a/adapter/router.go b/adapter/router.go index b26a62d2..91c45674 100644 --- a/adapter/router.go +++ b/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) diff --git a/common/sniff/dns.go b/common/sniff/dns.go index 7ff541d1..9b2ad91f 100644 --- a/common/sniff/dns.go +++ b/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 } diff --git a/common/tls/acme.go b/common/tls/acme.go index eb6eac39..2b8608c6 100644 --- a/common/tls/acme.go +++ b/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" ) diff --git a/common/tls/ech_client.go b/common/tls/ech_client.go index e3d1bb5d..c6238f91 100644 --- a/common/tls/ech_client.go +++ b/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 { diff --git a/docs/contributing/sub-projects.md b/docs/contributing/sub-projects.md index c10306fe..3f62a52c 100644 --- a/docs/contributing/sub-projects.md +++ b/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) diff --git a/go.mod b/go.mod index 29aaec5a..c017e8a8 100644 --- a/go.mod +++ b/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 diff --git a/go.sum b/go.sum index 34340bc5..9224a3c4 100644 --- a/go.sum +++ b/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= diff --git a/outbound/dns.go b/outbound/dns.go index 81133e42..fa25ac1c 100644 --- a/outbound/dns.go +++ b/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 diff --git a/route/router_dns.go b/route/router_dns.go index a1bab409..47635a10 100644 --- a/route/router_dns.go +++ b/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:] +func fqdnToDomain(fqdn string) string { + if mDNS.IsFqdn(fqdn) { + return fqdn[:len(fqdn)-1] } - var qClass string - qClass = question.Class.String() - if len(qClass) > 5 { - qClass = qClass[5:] - } - 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 }