From 76926c794793141df4c94023715fd2de0cef7c4e Mon Sep 17 00:00:00 2001 From: Janik Rabe Date: Thu, 13 Jun 2024 15:13:25 +0100 Subject: [PATCH 01/21] Fix possible out-of-bounds read in endingToTxtSlice (#1557) * Update escapedStringOffset to improve readability This function was, admittedly, a little difficult to follow. This new version is slightly more verbose, but, in my opinion, easier to understand. * Fix possible out-of-bounds read in endingToTxtSlice caused by escapedStringOffset If the input had a trailing backslash (normally the start of an escape sequence) with nothing following it, `escapedStringOffset` would return the length of the input, plus one (!), as the result index, causing an out-of-bounds read and panic in `endingToTxtSlice`. Consistent with, e.g., commit 2230854ba97edcf29ac55a1f274e49cec11bf9bb, I've decided to make this an error since it definitely indicates that the string isn't valid. Credit to OSS-Fuzz -- thank you! --- scan_rr.go | 38 ++++++++++++++++++++++++-------------- scan_test.go | 34 +++++++++++++++++++++++----------- 2 files changed, 47 insertions(+), 25 deletions(-) diff --git a/scan_rr.go b/scan_rr.go index 7d1ade7d87..c1a76995e7 100644 --- a/scan_rr.go +++ b/scan_rr.go @@ -55,7 +55,10 @@ func endingToTxtSlice(c *zlexer, errstr string) ([]string, *ParseError) { sx := []string{} p := 0 for { - i := escapedStringOffset(l.token[p:], 255) + i, ok := escapedStringOffset(l.token[p:], 255) + if !ok { + return nil, &ParseError{err: errstr, lex: l} + } if i != -1 && p+i != len(l.token) { sx = append(sx, l.token[p:p+i]) } else { @@ -1919,29 +1922,36 @@ func (rr *APL) parse(c *zlexer, o string) *ParseError { // escapedStringOffset finds the offset within a string (which may contain escape // sequences) that corresponds to a certain byte offset. If the input offset is -// out of bounds, -1 is returned. -func escapedStringOffset(s string, byteOffset int) int { - if byteOffset == 0 { - return 0 +// out of bounds, -1 is returned (which is *not* considered an error). +func escapedStringOffset(s string, desiredByteOffset int) (int, bool) { + if desiredByteOffset == 0 { + return 0, true } - offset := 0 - for i := 0; i < len(s); i++ { - offset += 1 + currentByteOffset, i := 0, 0 + + for i < len(s) { + currentByteOffset += 1 // Skip escape sequences if s[i] != '\\' { - // Not an escape sequence; nothing to do. + // Single plain byte, not an escape sequence. + i++ } else if isDDD(s[i+1:]) { - i += 3 + // Skip backslash and DDD. + i += 4 + } else if len(s[i+1:]) < 1 { + // No character following the backslash; that's an error. + return 0, false } else { - i++ + // Skip backslash and following byte. + i += 2 } - if offset >= byteOffset { - return i + 1 + if currentByteOffset >= desiredByteOffset { + return i, true } } - return -1 + return -1, true } diff --git a/scan_test.go b/scan_test.go index 580236ea26..c4f7e7f4a9 100644 --- a/scan_test.go +++ b/scan_test.go @@ -433,25 +433,37 @@ func TestEscapedStringOffset(t *testing.T) { input string inputOffset int expectedOffset int + expectedOK bool }{ - {"simple string with no escape sequences", 20, 20}, - {"simple string with no escape sequences", 500, -1}, - {`\;\088\\\;\120\\`, 0, 0}, - {`\;\088\\\;\120\\`, 1, 2}, - {`\;\088\\\;\120\\`, 2, 6}, - {`\;\088\\\;\120\\`, 3, 8}, - {`\;\088\\\;\120\\`, 4, 10}, - {`\;\088\\\;\120\\`, 5, 14}, - {`\;\088\\\;\120\\`, 6, 16}, - {`\;\088\\\;\120\\`, 7, -1}, + {"simple string with no escape sequences", 20, 20, true}, + {"simple string with no escape sequences", 500, -1, true}, + {`\;\088\\\;\120\\`, 0, 0, true}, + {`\;\088\\\;\120\\`, 1, 2, true}, + {`\;\088\\\;\120\\`, 2, 6, true}, + {`\;\088\\\;\120\\`, 3, 8, true}, + {`\;\088\\\;\120\\`, 4, 10, true}, + {`\;\088\\\;\120\\`, 5, 14, true}, + {`\;\088\\\;\120\\`, 6, 16, true}, + {`\;\088\\\;\120\\`, 7, -1, true}, + {`\`, 3, 0, false}, + {`a\`, 3, 0, false}, + {`aa\`, 3, 0, false}, + {`aaa\`, 3, 3, true}, + {`aaaa\`, 3, 3, true}, } for i, test := range cases { - outputOffset := escapedStringOffset(test.input, test.inputOffset) + outputOffset, outputOK := escapedStringOffset(test.input, test.inputOffset) if outputOffset != test.expectedOffset { t.Errorf( "Test %d (input %#q offset %d) returned offset %d but expected %d", i, test.input, test.inputOffset, outputOffset, test.expectedOffset, ) } + if outputOK != test.expectedOK { + t.Errorf( + "Test %d (input %#q offset %d) returned ok=%t but expected %t", + i, test.input, test.inputOffset, outputOK, test.expectedOK, + ) + } } } From d945412a3e7121bc05216de12eb0b0253097ac84 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 13 Jun 2024 16:13:45 +0200 Subject: [PATCH 02/21] Bump golang.org/x/sys from 0.18.0 to 0.20.0 (#1571) Bumps [golang.org/x/sys](https://github.com/golang/sys) from 0.18.0 to 0.20.0. - [Commits](https://github.com/golang/sys/compare/v0.18.0...v0.20.0) --- updated-dependencies: - dependency-name: golang.org/x/sys dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index bd18820871..ff57fb19dd 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.19 require ( golang.org/x/net v0.22.0 golang.org/x/sync v0.6.0 - golang.org/x/sys v0.18.0 + golang.org/x/sys v0.20.0 golang.org/x/tools v0.19.0 ) diff --git a/go.sum b/go.sum index d0f87415b3..42edcddc31 100644 --- a/go.sum +++ b/go.sum @@ -4,7 +4,7 @@ golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc= golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= -golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= +golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/tools v0.19.0 h1:tfGCXNR1OsFG+sVdLAitlpjAvD/I6dHDKnYrpEZUHkw= golang.org/x/tools v0.19.0/go.mod h1:qoJWxmGSIBmAeriMx19ogtrEPrGtDbPK634QFIcLAhc= From f89100d6fe33f08260d2d81cd349f8438c98f834 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 13 Jun 2024 16:14:01 +0200 Subject: [PATCH 03/21] Bump golang.org/x/net from 0.22.0 to 0.25.0 (#1569) Bumps [golang.org/x/net](https://github.com/golang/net) from 0.22.0 to 0.25.0. - [Commits](https://github.com/golang/net/compare/v0.22.0...v0.25.0) --- updated-dependencies: - dependency-name: golang.org/x/net dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index ff57fb19dd..03daf6c2d6 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/miekg/dns go 1.19 require ( - golang.org/x/net v0.22.0 + golang.org/x/net v0.25.0 golang.org/x/sync v0.6.0 golang.org/x/sys v0.20.0 golang.org/x/tools v0.19.0 diff --git a/go.sum b/go.sum index 42edcddc31..fb66113951 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,7 @@ golang.org/x/mod v0.16.0 h1:QX4fJ0Rr5cPQCF7O9lh9Se4pmwfwskqZfq5moyldzic= golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc= -golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= +golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= From 32f0e182ee52639f1d47f5e15601f54cd1a6062d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 13 Jun 2024 16:24:45 +0200 Subject: [PATCH 04/21] Bump golang.org/x/tools from 0.19.0 to 0.22.0 (#1574) Bumps [golang.org/x/tools](https://github.com/golang/tools) from 0.19.0 to 0.22.0. - [Release notes](https://github.com/golang/tools/releases) - [Commits](https://github.com/golang/tools/compare/v0.19.0...v0.22.0) --- updated-dependencies: - dependency-name: golang.org/x/tools dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 10 +++++----- go.sum | 20 ++++++++++---------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/go.mod b/go.mod index 03daf6c2d6..2f8e569b86 100644 --- a/go.mod +++ b/go.mod @@ -3,10 +3,10 @@ module github.com/miekg/dns go 1.19 require ( - golang.org/x/net v0.25.0 - golang.org/x/sync v0.6.0 - golang.org/x/sys v0.20.0 - golang.org/x/tools v0.19.0 + golang.org/x/net v0.26.0 + golang.org/x/sync v0.7.0 + golang.org/x/sys v0.21.0 + golang.org/x/tools v0.22.0 ) -require golang.org/x/mod v0.16.0 // indirect +require golang.org/x/mod v0.18.0 // indirect diff --git a/go.sum b/go.sum index fb66113951..1e3f4ba0b8 100644 --- a/go.sum +++ b/go.sum @@ -1,10 +1,10 @@ -golang.org/x/mod v0.16.0 h1:QX4fJ0Rr5cPQCF7O9lh9Se4pmwfwskqZfq5moyldzic= -golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= -golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= -golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= -golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= -golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/tools v0.19.0 h1:tfGCXNR1OsFG+sVdLAitlpjAvD/I6dHDKnYrpEZUHkw= -golang.org/x/tools v0.19.0/go.mod h1:qoJWxmGSIBmAeriMx19ogtrEPrGtDbPK634QFIcLAhc= +golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0= +golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= +golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= +golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= +golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA= +golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c= From 2b89f28521aa2b38fb2e781d3dec7990ac2acae2 Mon Sep 17 00:00:00 2001 From: Patrik Lundin Date: Thu, 13 Jun 2024 16:31:48 +0200 Subject: [PATCH 05/21] (*Transfer) Out: Increment WaitGroup in example (#1572) --- xfr.go | 1 + 1 file changed, 1 insertion(+) diff --git a/xfr.go b/xfr.go index 2187c456db..5cfbb516af 100644 --- a/xfr.go +++ b/xfr.go @@ -209,6 +209,7 @@ func (t *Transfer) inIxfr(q *Msg, c chan *Envelope) { // ch := make(chan *dns.Envelope) // tr := new(dns.Transfer) // var wg sync.WaitGroup +// wg.Add(1) // go func() { // tr.Out(w, r, ch) // wg.Done() From eada9c9b7c799c43ddb3f9793cbe55ce7fe62a0d Mon Sep 17 00:00:00 2001 From: "Benjamin M. Schwartz" Date: Thu, 13 Jun 2024 11:15:27 -0400 Subject: [PATCH 06/21] Add a hook to catch invalid messages (#1568) * Add a hook to catch invalid messages Currently there are hooks for reading messages off the wire (DecorateReader), checking if they comply with policy (MsgAcceptFunc), and generating responses (Handler). However, there is no hook that notifies the server when a message is dropped or rejected due to a syntax error. That makes it hard to monitor these packets without repeating the parsing process. This PR adds a hook for notifications about invalid packets. * s/InvalidMsg/MsgInvalid/g --- acceptfunc_test.go | 85 ++++++++++++++++++++++++++++++++++++++++++++++ server.go | 19 ++++++++++- 2 files changed, 103 insertions(+), 1 deletion(-) diff --git a/acceptfunc_test.go b/acceptfunc_test.go index d40d4e4cd5..868154d403 100644 --- a/acceptfunc_test.go +++ b/acceptfunc_test.go @@ -1,6 +1,8 @@ package dns import ( + "encoding/binary" + "net" "testing" ) @@ -33,3 +35,86 @@ func handleNotify(w ResponseWriter, req *Msg) { m.SetReply(req) w.WriteMsg(m) } + +func TestInvalidMsg(t *testing.T) { + HandleFunc("example.org.", func(ResponseWriter, *Msg) { + t.Fatal("the handler must not be called in any of these tests") + }) + s, addrstr, _, err := RunLocalTCPServer(":0") + if err != nil { + t.Fatalf("unable to run test server: %v", err) + } + defer s.Shutdown() + + s.MsgAcceptFunc = func(dh Header) MsgAcceptAction { + switch dh.Id { + case 0x0001: + return MsgAccept + case 0x0002: + return MsgReject + case 0x0003: + return MsgIgnore + case 0x0004: + return MsgRejectNotImplemented + default: + t.Errorf("unexpected ID %x", dh.Id) + return -1 + } + } + + invalidErrors := make(chan error) + s.MsgInvalidFunc = func(m []byte, err error) { + invalidErrors <- err + } + + c, err := net.Dial("tcp", addrstr) + if err != nil { + t.Fatalf("cannot connect to test server: %v", err) + } + + write := func(m []byte) { + var length [2]byte + binary.BigEndian.PutUint16(length[:], uint16(len(m))) + _, err := c.Write(length[:]) + if err != nil { + t.Fatalf("length write failed: %v", err) + } + _, err = c.Write(m) + if err != nil { + t.Fatalf("content write failed: %v", err) + } + } + + /* Message is too short, so there is no header to accept or reject. */ + + tooShortMessage := make([]byte, 11) + tooShortMessage[1] = 0x3 // ID = 3, would be ignored if it were parsable. + + write(tooShortMessage) + // Expect an error to be reported. + <-invalidErrors + + /* Message is accepted but is actually invalid. */ + + badMessage := make([]byte, 13) + badMessage[1] = 0x1 // ID = 1, Accept. + badMessage[5] = 1 // QDCOUNT = 1 + badMessage[12] = 99 // Bad question section. Invalid! + + write(badMessage) + // Expect an error to be reported. + <-invalidErrors + + /* Message is rejected before it can be determined to be invalid. */ + + close(invalidErrors) // A call to InvalidMsgFunc would panic due to the closed chan. + + badMessage[1] = 0x2 // ID = 2, Reject + write(badMessage) + + badMessage[1] = 0x3 // ID = 3, Ignore + write(badMessage) + + badMessage[1] = 0x4 // ID = 4, RejectNotImplemented + write(badMessage) +} diff --git a/server.go b/server.go index 0207d6da22..2f7655645b 100644 --- a/server.go +++ b/server.go @@ -188,6 +188,14 @@ type DecorateReader func(Reader) Reader // Implementations should never return a nil Writer. type DecorateWriter func(Writer) Writer +// InvalidMsgFunc is a listener hook for observing incoming messages that were discarded +// because they could not be parsed. +// Every message that is read by a Reader will eventually be provided to the Handler, +// rejected (or ignored) by the MsgAcceptFunc, or passed to this function. +type InvalidMsgFunc func(m []byte, err error) + +func DefaultMsgInvalidFunc(m []byte, err error) {} + // A Server defines parameters for running an DNS server. type Server struct { // Address to listen on, ":dns" if empty. @@ -233,6 +241,8 @@ type Server struct { // AcceptMsgFunc will check the incoming message and will reject it early in the process. // By default DefaultMsgAcceptFunc will be used. MsgAcceptFunc MsgAcceptFunc + // MsgInvalidFunc is optional, will be called if a message is received but cannot be parsed. + MsgInvalidFunc InvalidMsgFunc // Shutdown handling lock sync.RWMutex @@ -277,6 +287,9 @@ func (srv *Server) init() { if srv.MsgAcceptFunc == nil { srv.MsgAcceptFunc = DefaultMsgAcceptFunc } + if srv.MsgInvalidFunc == nil { + srv.MsgInvalidFunc = DefaultMsgInvalidFunc + } if srv.Handler == nil { srv.Handler = DefaultServeMux } @@ -531,6 +544,7 @@ func (srv *Server) serveUDP(l net.PacketConn) error { if cap(m) == srv.UDPSize { srv.udpPool.Put(m[:srv.UDPSize]) } + srv.MsgInvalidFunc(m, ErrShortRead) continue } wg.Add(1) @@ -611,6 +625,7 @@ func (srv *Server) serveUDPPacket(wg *sync.WaitGroup, m []byte, u net.PacketConn func (srv *Server) serveDNS(m []byte, w *response) { dh, off, err := unpackMsgHdr(m, 0) if err != nil { + srv.MsgInvalidFunc(m, err) // Let client hang, they are sending crap; any reply can be used to amplify. return } @@ -620,10 +635,12 @@ func (srv *Server) serveDNS(m []byte, w *response) { switch action := srv.MsgAcceptFunc(dh); action { case MsgAccept: - if req.unpack(dh, m, off) == nil { + err := req.unpack(dh, m, off) + if err == nil { break } + srv.MsgInvalidFunc(m, err) fallthrough case MsgReject, MsgRejectNotImplemented: opcode := req.Opcode From c3301c36d8292d5be7dd35215878c9b521c26fde Mon Sep 17 00:00:00 2001 From: Miek Gieben Date: Thu, 13 Jun 2024 17:17:07 +0200 Subject: [PATCH 07/21] These two too Signed-off-by: Miek Gieben --- server.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/server.go b/server.go index 2f7655645b..81580d1e5f 100644 --- a/server.go +++ b/server.go @@ -188,11 +188,11 @@ type DecorateReader func(Reader) Reader // Implementations should never return a nil Writer. type DecorateWriter func(Writer) Writer -// InvalidMsgFunc is a listener hook for observing incoming messages that were discarded +// MsgInvalidFunc is a listener hook for observing incoming messages that were discarded // because they could not be parsed. // Every message that is read by a Reader will eventually be provided to the Handler, // rejected (or ignored) by the MsgAcceptFunc, or passed to this function. -type InvalidMsgFunc func(m []byte, err error) +type MsgInvalidFunc func(m []byte, err error) func DefaultMsgInvalidFunc(m []byte, err error) {} @@ -242,7 +242,7 @@ type Server struct { // By default DefaultMsgAcceptFunc will be used. MsgAcceptFunc MsgAcceptFunc // MsgInvalidFunc is optional, will be called if a message is received but cannot be parsed. - MsgInvalidFunc InvalidMsgFunc + MsgInvalidFunc MsgInvalidFunc // Shutdown handling lock sync.RWMutex From a1ef7a631234c33b61d8cec0349582645be72b5d Mon Sep 17 00:00:00 2001 From: Steffen Sassalla <32709406+steffsas@users.noreply.github.com> Date: Thu, 13 Jun 2024 17:49:04 +0200 Subject: [PATCH 08/21] Add RFC 9540 oblivious services via service binding records (#1567) --- parse_test.go | 11 +++++++++++ svcb.go | 50 ++++++++++++++++++++++++++++++++++++++++++++++---- svcb_test.go | 5 +++++ 3 files changed, 62 insertions(+), 4 deletions(-) diff --git a/parse_test.go b/parse_test.go index da94cc38e4..f0d68a44ec 100644 --- a/parse_test.go +++ b/parse_test.go @@ -1609,7 +1609,18 @@ func TestParseSVCB(t *testing.T) { // From draft-ietf-add-ddr-06 `_dns.example.net. SVCB 1 example.net. alpn=h2 dohpath=/dns-query{?dns}`: `_dns.example.net. 3600 IN SVCB 1 example.net. alpn="h2" dohpath="/dns-query{?dns}"`, `_dns.example.net. SVCB 1 example.net. alpn=h2 dohpath=/dns\045query{\?dns}`: `_dns.example.net. 3600 IN SVCB 1 example.net. alpn="h2" dohpath="/dns-query{?dns}"`, + // From RFC9461 Section 7 (https://datatracker.ietf.org/doc/html/rfc9461#section-7) + `_dns.simple.example. 7200 IN SVCB 1 simple.example. alpn=dot`: `_dns.simple.example. 7200 IN SVCB 1 simple.example. alpn="dot"`, + `_dns.doh.example. 7200 IN SVCB 1 doh.example. alpn=h2 dohpath=/dns-query{?dns}`: `_dns.doh.example. 7200 IN SVCB 1 doh.example. alpn="h2" dohpath="/dns-query{?dns}"`, + `_dns.resolver.example. 7200 IN SVCB 1 resolver.example. alpn=dot,doq,h2,h3 dohpath=/q{?dns}`: `_dns.resolver.example. 7200 IN SVCB 1 resolver.example. alpn="dot,doq,h2,h3" dohpath="/q{?dns}"`, + `_dns.resolver.example. 7200 IN SVCB 2 resolver.example. alpn=dot port=8530`: `_dns.resolver.example. 7200 IN SVCB 2 resolver.example. alpn="dot" port="8530"`, + // From RFC 9540 Section 4.2.1 (https://www.rfc-editor.org/rfc/rfc9540.html#name-the-ohttp-svcparamkey) + `_dns.resolver.arpa 7200 IN SVCB 1 doh.example.net alpn=h2 dohpath=/dns-query{?dns} ohttp`: `_dns.resolver.arpa. 7200 IN SVCB 1 doh.example.net. alpn="h2" dohpath="/dns-query{?dns}" ohttp=""`, + // From RFC 9540 Section 4.1 (HTTPS RR) (https://www.rfc-editor.org/rfc/rfc9540.html#name-use-in-https-service-rrs) + `svc.example.com. 7200 IN HTTPS 1 . alpn=h2 ohttp`: `svc.example.com. 7200 IN HTTPS 1 . alpn="h2" ohttp=""`, + `svc.example.com. 7200 IN HTTPS 1 . mandatory=ohttp ohttp`: `svc.example.com. 7200 IN HTTPS 1 . mandatory="ohttp" ohttp=""`, } + for s, o := range svcbs { rr, err := NewRR(s) if err != nil { diff --git a/svcb.go b/svcb.go index c1a740b684..310c7d11f5 100644 --- a/svcb.go +++ b/svcb.go @@ -14,7 +14,7 @@ import ( // SVCBKey is the type of the keys used in the SVCB RR. type SVCBKey uint16 -// Keys defined in draft-ietf-dnsop-svcb-https-08 Section 14.3.2. +// Keys defined in rfc9460 const ( SVCB_MANDATORY SVCBKey = iota SVCB_ALPN @@ -23,7 +23,8 @@ const ( SVCB_IPV4HINT SVCB_ECHCONFIG SVCB_IPV6HINT - SVCB_DOHPATH // draft-ietf-add-svcb-dns-02 Section 9 + SVCB_DOHPATH // rfc9461 Section 5 + SVCB_OHTTP // rfc9540 Section 8 svcb_RESERVED SVCBKey = 65535 ) @@ -37,6 +38,7 @@ var svcbKeyToStringMap = map[SVCBKey]string{ SVCB_ECHCONFIG: "ech", SVCB_IPV6HINT: "ipv6hint", SVCB_DOHPATH: "dohpath", + SVCB_OHTTP: "ohttp", } var svcbStringToKeyMap = reverseSVCBKeyMap(svcbKeyToStringMap) @@ -201,6 +203,8 @@ func makeSVCBKeyValue(key SVCBKey) SVCBKeyValue { return new(SVCBIPv6Hint) case SVCB_DOHPATH: return new(SVCBDoHPath) + case SVCB_OHTTP: + return new(SVCBOhttp) case svcb_RESERVED: return nil default: @@ -771,8 +775,8 @@ func (s *SVCBIPv6Hint) copy() SVCBKeyValue { // SVCBDoHPath pair is used to indicate the URI template that the // clients may use to construct a DNS over HTTPS URI. // -// See RFC xxxx (https://datatracker.ietf.org/doc/html/draft-ietf-add-svcb-dns-02) -// and RFC yyyy (https://datatracker.ietf.org/doc/html/draft-ietf-add-ddr-06). +// See RFC 9461 (https://datatracker.ietf.org/doc/html/rfc9461) +// and RFC 9462 (https://datatracker.ietf.org/doc/html/rfc9462). // // A basic example of using the dohpath option together with the alpn // option to indicate support for DNS over HTTPS on a certain path: @@ -816,6 +820,44 @@ func (s *SVCBDoHPath) copy() SVCBKeyValue { } } +// The "ohttp" SvcParamKey is used to indicate that a service described in a SVCB RR +// can be accessed as a target using an associated gateway. +// Both the presentation and wire-format values for the "ohttp" parameter MUST be empty. +// +// See RFC 9460 (https://datatracker.ietf.org/doc/html/rfc9460/) +// and RFC 9230 (https://datatracker.ietf.org/doc/html/rfc9230/) +// +// A basic example of using the dohpath option together with the alpn +// option to indicate support for DNS over HTTPS on a certain path: +// +// s := new(dns.SVCB) +// s.Hdr = dns.RR_Header{Name: ".", Rrtype: dns.TypeSVCB, Class: dns.ClassINET} +// e := new(dns.SVCBAlpn) +// e.Alpn = []string{"h2", "h3"} +// p := new(dns.SVCBOhttp) +// s.Value = append(s.Value, e, p) +type SVCBOhttp struct{} + +func (*SVCBOhttp) Key() SVCBKey { return SVCB_OHTTP } +func (*SVCBOhttp) copy() SVCBKeyValue { return &SVCBOhttp{} } +func (*SVCBOhttp) pack() ([]byte, error) { return []byte{}, nil } +func (*SVCBOhttp) String() string { return "" } +func (*SVCBOhttp) len() int { return 0 } + +func (*SVCBOhttp) unpack(b []byte) error { + if len(b) != 0 { + return errors.New("dns: svcbotthp: svcbotthp must have no value") + } + return nil +} + +func (*SVCBOhttp) parse(b string) error { + if b != "" { + return errors.New("dns: svcbotthp: svcbotthp must have no value") + } + return nil +} + // SVCBLocal pair is intended for experimental/private use. The key is recommended // to be in the range [SVCB_PRIVATE_LOWER, SVCB_PRIVATE_UPPER]. // Basic use pattern for creating a keyNNNNN option: diff --git a/svcb_test.go b/svcb_test.go index 63a40102c7..a96a344b6d 100644 --- a/svcb_test.go +++ b/svcb_test.go @@ -24,6 +24,7 @@ func TestSVCB(t *testing.T) { {`key65002`, ``}, {`key65003`, `=\"\"`}, {`key65004`, `\254\ \ \030\000`}, + {`ohttp`, ``}, } for _, o := range svcbs { @@ -86,6 +87,10 @@ func TestDecodeBadSVCB(t *testing.T) { key: SVCB_IPV6HINT, data: []byte{0, 0, 0}, }, + { + key: SVCB_OHTTP, + data: []byte{0}, + }, } for _, o := range svcbs { err := makeSVCBKeyValue(SVCBKey(o.key)).unpack(o.data) From e5a40bc574c835a67a0e1953186b8a5230ccd2dc Mon Sep 17 00:00:00 2001 From: Miek Gieben Date: Thu, 13 Jun 2024 17:51:48 +0200 Subject: [PATCH 09/21] update list of RFCs Signed-off-by: Miek Gieben --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 58275db3b8..10ddda1427 100644 --- a/README.md +++ b/README.md @@ -188,6 +188,9 @@ Example programs can be found in the `github.com/miekg/exdns` repository. * 8777 - DNS Reverse IP Automatic Multicast Tunneling (AMT) Discovery * 8914 - Extended DNS Errors * 8976 - Message Digest for DNS Zones (ZONEMD RR) +* 9460 - Service Binding and Parameter Specification via the DNS +* 9461 - Service Binding Mapping for DNS Servers +* 9462 - Discovery of Designated Resolvers ## Loosely Based Upon From 870b1c1f9bd1c61a5026cfa06376d5799aa537af Mon Sep 17 00:00:00 2001 From: Infinoid Date: Fri, 21 Jun 2024 15:43:02 -0400 Subject: [PATCH 10/21] add rfc3596 to the list (#1577) --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 10ddda1427..8d5a2a4789 100644 --- a/README.md +++ b/README.md @@ -148,6 +148,7 @@ Example programs can be found in the `github.com/miekg/exdns` repository. * 3225 - DO bit (DNSSEC OK) * 340{1,2,3} - NAPTR record * 3445 - Limiting the scope of (DNS)KEY +* 3596 - AAAA record * 3597 - Unknown RRs * 4025 - A Method for Storing IPsec Keying Material in DNS * 403{3,4,5} - DNSSEC + validation functions From d6940bfa7d6753a10ea5d156fdf86313a0ea215c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 3 Aug 2024 07:58:29 +0200 Subject: [PATCH 11/21] Bump golang.org/x/net from 0.26.0 to 0.27.0 (#1587) Bumps [golang.org/x/net](https://github.com/golang/net) from 0.26.0 to 0.27.0. - [Commits](https://github.com/golang/net/compare/v0.26.0...v0.27.0) --- updated-dependencies: - dependency-name: golang.org/x/net dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 2f8e569b86..cb9c336d15 100644 --- a/go.mod +++ b/go.mod @@ -3,9 +3,9 @@ module github.com/miekg/dns go 1.19 require ( - golang.org/x/net v0.26.0 + golang.org/x/net v0.27.0 golang.org/x/sync v0.7.0 - golang.org/x/sys v0.21.0 + golang.org/x/sys v0.22.0 golang.org/x/tools v0.22.0 ) diff --git a/go.sum b/go.sum index 1e3f4ba0b8..c835f72e01 100644 --- a/go.sum +++ b/go.sum @@ -1,10 +1,10 @@ golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0= golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= -golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= +golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys= +golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= -golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= +golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA= golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c= From 347f2504712befdf64aadb6888a544e2730f38c4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 3 Aug 2024 07:58:40 +0200 Subject: [PATCH 12/21] Bump golang.org/x/sys from 0.21.0 to 0.22.0 (#1588) Bumps [golang.org/x/sys](https://github.com/golang/sys) from 0.21.0 to 0.22.0. - [Commits](https://github.com/golang/sys/compare/v0.21.0...v0.22.0) --- updated-dependencies: - dependency-name: golang.org/x/sys dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> From 8d05ff70486b1e06ff544998e29c75687f9b7ad7 Mon Sep 17 00:00:00 2001 From: Christian Elmerot Date: Sat, 3 Aug 2024 07:59:34 +0200 Subject: [PATCH 13/21] Add support for missing Extended DNS Error Codes (EDE) (#1585) Extended DNS Error (EDE) codes were missing for code points 25-30. These are documented in: https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#extended-dns-error-codes Co-authored-by: Christian Elmerot --- edns.go | 62 ++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 37 insertions(+), 25 deletions(-) diff --git a/edns.go b/edns.go index 1b58e8f0aa..c1bbdaae2e 100644 --- a/edns.go +++ b/edns.go @@ -756,36 +756,48 @@ const ( ExtendedErrorCodeNoReachableAuthority ExtendedErrorCodeNetworkError ExtendedErrorCodeInvalidData + ExtendedErrorCodeSignatureExpiredBeforeValid + ExtendedErrorCodeTooEarly + ExtendedErrorCodeUnsupportedNSEC3IterValue + ExtendedErrorCodeUnableToConformToPolicy + ExtendedErrorCodeSynthesized + ExtendedErrorCodeInvalidQueryType ) // ExtendedErrorCodeToString maps extended error info codes to a human readable // description. var ExtendedErrorCodeToString = map[uint16]string{ - ExtendedErrorCodeOther: "Other", - ExtendedErrorCodeUnsupportedDNSKEYAlgorithm: "Unsupported DNSKEY Algorithm", - ExtendedErrorCodeUnsupportedDSDigestType: "Unsupported DS Digest Type", - ExtendedErrorCodeStaleAnswer: "Stale Answer", - ExtendedErrorCodeForgedAnswer: "Forged Answer", - ExtendedErrorCodeDNSSECIndeterminate: "DNSSEC Indeterminate", - ExtendedErrorCodeDNSBogus: "DNSSEC Bogus", - ExtendedErrorCodeSignatureExpired: "Signature Expired", - ExtendedErrorCodeSignatureNotYetValid: "Signature Not Yet Valid", - ExtendedErrorCodeDNSKEYMissing: "DNSKEY Missing", - ExtendedErrorCodeRRSIGsMissing: "RRSIGs Missing", - ExtendedErrorCodeNoZoneKeyBitSet: "No Zone Key Bit Set", - ExtendedErrorCodeNSECMissing: "NSEC Missing", - ExtendedErrorCodeCachedError: "Cached Error", - ExtendedErrorCodeNotReady: "Not Ready", - ExtendedErrorCodeBlocked: "Blocked", - ExtendedErrorCodeCensored: "Censored", - ExtendedErrorCodeFiltered: "Filtered", - ExtendedErrorCodeProhibited: "Prohibited", - ExtendedErrorCodeStaleNXDOMAINAnswer: "Stale NXDOMAIN Answer", - ExtendedErrorCodeNotAuthoritative: "Not Authoritative", - ExtendedErrorCodeNotSupported: "Not Supported", - ExtendedErrorCodeNoReachableAuthority: "No Reachable Authority", - ExtendedErrorCodeNetworkError: "Network Error", - ExtendedErrorCodeInvalidData: "Invalid Data", + ExtendedErrorCodeOther: "Other", + ExtendedErrorCodeUnsupportedDNSKEYAlgorithm: "Unsupported DNSKEY Algorithm", + ExtendedErrorCodeUnsupportedDSDigestType: "Unsupported DS Digest Type", + ExtendedErrorCodeStaleAnswer: "Stale Answer", + ExtendedErrorCodeForgedAnswer: "Forged Answer", + ExtendedErrorCodeDNSSECIndeterminate: "DNSSEC Indeterminate", + ExtendedErrorCodeDNSBogus: "DNSSEC Bogus", + ExtendedErrorCodeSignatureExpired: "Signature Expired", + ExtendedErrorCodeSignatureNotYetValid: "Signature Not Yet Valid", + ExtendedErrorCodeDNSKEYMissing: "DNSKEY Missing", + ExtendedErrorCodeRRSIGsMissing: "RRSIGs Missing", + ExtendedErrorCodeNoZoneKeyBitSet: "No Zone Key Bit Set", + ExtendedErrorCodeNSECMissing: "NSEC Missing", + ExtendedErrorCodeCachedError: "Cached Error", + ExtendedErrorCodeNotReady: "Not Ready", + ExtendedErrorCodeBlocked: "Blocked", + ExtendedErrorCodeCensored: "Censored", + ExtendedErrorCodeFiltered: "Filtered", + ExtendedErrorCodeProhibited: "Prohibited", + ExtendedErrorCodeStaleNXDOMAINAnswer: "Stale NXDOMAIN Answer", + ExtendedErrorCodeNotAuthoritative: "Not Authoritative", + ExtendedErrorCodeNotSupported: "Not Supported", + ExtendedErrorCodeNoReachableAuthority: "No Reachable Authority", + ExtendedErrorCodeNetworkError: "Network Error", + ExtendedErrorCodeInvalidData: "Invalid Data", + ExtendedErrorCodeSignatureExpiredBeforeValid: "Signature Expired Before Valid", + ExtendedErrorCodeTooEarly: "Too Early", + ExtendedErrorCodeUnsupportedNSEC3IterValue: "Unsupported NSEC3 Iterations Value", + ExtendedErrorCodeUnableToConformToPolicy: "Unable To Conform To Policy", + ExtendedErrorCodeSynthesized: "Synthesized", + ExtendedErrorCodeInvalidQueryType: "Invalid Query Type", } // StringToExtendedErrorCode is a map from human readable descriptions to From ee99288e87b1b72608caafbaac5d57eb3608ae76 Mon Sep 17 00:00:00 2001 From: Christian Elmerot Date: Sat, 3 Aug 2024 08:00:16 +0200 Subject: [PATCH 14/21] Add support for NXNAME type (#1584) IANA har allocated the NXNAME meta type to indicate an NSEC/NSEC3 record signals that the name does not exist (corresponds to NXDOMAIN). NXNAME is a meta type only for use with NSEC/NSEC3 bitmaps and use is defined in https://datatracker.ietf.org/doc/draft-ietf-dnsop-compact-denial-of-existence/ Co-authored-by: Christian Elmerot --- types.go | 14 ++++++++++++++ zduplicate.go | 9 +++++++++ zmsg.go | 11 +++++++++++ ztypes.go | 12 ++++++++++++ 4 files changed, 46 insertions(+) diff --git a/types.go b/types.go index 8e3129cbd2..7a34c14ca0 100644 --- a/types.go +++ b/types.go @@ -96,6 +96,7 @@ const ( TypeLP uint16 = 107 TypeEUI48 uint16 = 108 TypeEUI64 uint16 = 109 + TypeNXNAME uint16 = 128 TypeURI uint16 = 256 TypeCAA uint16 = 257 TypeAVC uint16 = 258 @@ -294,6 +295,19 @@ func (*NULL) parse(c *zlexer, origin string) *ParseError { return &ParseError{err: "NULL records do not have a presentation format"} } +// NXNAME is a meta record. See https://www.iana.org/go/draft-ietf-dnsop-compact-denial-of-existence-04 +// Reference: https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml +type NXNAME struct { + Hdr RR_Header + // Does not have any rdata +} + +func (rr *NXNAME) String() string { return rr.Hdr.String() } + +func (*NXNAME) parse(c *zlexer, origin string) *ParseError { + return &ParseError{err: "NXNAME records do not have a presentation format"} +} + // CNAME RR. See RFC 1034. type CNAME struct { Hdr RR_Header diff --git a/zduplicate.go b/zduplicate.go index 03029fb3eb..330c05395f 100644 --- a/zduplicate.go +++ b/zduplicate.go @@ -886,6 +886,15 @@ func (r1 *NULL) isDuplicate(_r2 RR) bool { return true } +func (r1 *NXNAME) isDuplicate(_r2 RR) bool { + r2, ok := _r2.(*NXNAME) + if !ok { + return false + } + _ = r2 + return true +} + func (r1 *NXT) isDuplicate(_r2 RR) bool { r2, ok := _r2.(*NXT) if !ok { diff --git a/zmsg.go b/zmsg.go index 39b3bc8102..5a6cf4c6ad 100644 --- a/zmsg.go +++ b/zmsg.go @@ -706,6 +706,10 @@ func (rr *NULL) pack(msg []byte, off int, compression compressionMap, compress b return off, nil } +func (rr *NXNAME) pack(msg []byte, off int, compression compressionMap, compress bool) (off1 int, err error) { + return off, nil +} + func (rr *NXT) pack(msg []byte, off int, compression compressionMap, compress bool) (off1 int, err error) { off, err = packDomainName(rr.NextDomain, msg, off, compression, false) if err != nil { @@ -2266,6 +2270,13 @@ func (rr *NULL) unpack(msg []byte, off int) (off1 int, err error) { return off, nil } +func (rr *NXNAME) unpack(msg []byte, off int) (off1 int, err error) { + rdStart := off + _ = rdStart + + return off, nil +} + func (rr *NXT) unpack(msg []byte, off int) (off1 int, err error) { rdStart := off _ = rdStart diff --git a/ztypes.go b/ztypes.go index 2c70fc44d6..11f13ecf9c 100644 --- a/ztypes.go +++ b/ztypes.go @@ -60,6 +60,7 @@ var TypeToRR = map[uint16]func() RR{ TypeNSEC3: func() RR { return new(NSEC3) }, TypeNSEC3PARAM: func() RR { return new(NSEC3PARAM) }, TypeNULL: func() RR { return new(NULL) }, + TypeNXNAME: func() RR { return new(NXNAME) }, TypeNXT: func() RR { return new(NXT) }, TypeOPENPGPKEY: func() RR { return new(OPENPGPKEY) }, TypeOPT: func() RR { return new(OPT) }, @@ -146,6 +147,7 @@ var TypeToString = map[uint16]string{ TypeNSEC3: "NSEC3", TypeNSEC3PARAM: "NSEC3PARAM", TypeNULL: "NULL", + TypeNXNAME: "NXNAME", TypeNXT: "NXT", TypeNone: "None", TypeOPENPGPKEY: "OPENPGPKEY", @@ -230,6 +232,7 @@ func (rr *NSEC) Header() *RR_Header { return &rr.Hdr } func (rr *NSEC3) Header() *RR_Header { return &rr.Hdr } func (rr *NSEC3PARAM) Header() *RR_Header { return &rr.Hdr } func (rr *NULL) Header() *RR_Header { return &rr.Hdr } +func (rr *NXNAME) Header() *RR_Header { return &rr.Hdr } func (rr *NXT) Header() *RR_Header { return &rr.Hdr } func (rr *OPENPGPKEY) Header() *RR_Header { return &rr.Hdr } func (rr *OPT) Header() *RR_Header { return &rr.Hdr } @@ -594,6 +597,11 @@ func (rr *NULL) len(off int, compression map[string]struct{}) int { return l } +func (rr *NXNAME) len(off int, compression map[string]struct{}) int { + l := rr.Hdr.len(off, compression) + return l +} + func (rr *OPENPGPKEY) len(off int, compression map[string]struct{}) int { l := rr.Hdr.len(off, compression) l += base64.StdEncoding.DecodedLen(len(rr.PublicKey)) @@ -1107,6 +1115,10 @@ func (rr *NULL) copy() RR { return &NULL{rr.Hdr, rr.Data} } +func (rr *NXNAME) copy() RR { + return &NXNAME{rr.Hdr} +} + func (rr *NXT) copy() RR { return &NXT{*rr.NSEC.copy().(*NSEC)} } From ef7392e4ff2ef86bea51ee4f32fc60eaf1c2a88a Mon Sep 17 00:00:00 2001 From: Miek Gieben Date: Sat, 3 Aug 2024 08:07:18 +0200 Subject: [PATCH 15/21] Remove use of deprecated net.Error.Temporary (#1589) net.Error.Temporary has been deprecated since Go 1.18. There has been some discussion around what to use in server accept loops instead [1], but the suggestion seems to be that it may be a mistake to have any sort of retries in place [2]. This PR removes it, which may expose some users to errors that were previously swallowed and retried, but at the expense of leaking file descriptors and the like. 1: https://groups.google.com/g/golang-nuts/c/-JcZzOkyqYI/m/xwaZzjCgAwAJ?pli=1 2: https://groups.google.com/g/golang-nuts/c/-JcZzOkyqYI/m/vNNiVn_LAwAJ Co-authored-by: Johan Brandhorst-Satzkorn --- server.go | 6 ------ 1 file changed, 6 deletions(-) diff --git a/server.go b/server.go index 81580d1e5f..7a67cf3b4e 100644 --- a/server.go +++ b/server.go @@ -476,9 +476,6 @@ func (srv *Server) serveTCP(l net.Listener) error { if !srv.isStarted() { return nil } - if neterr, ok := err.(net.Error); ok && neterr.Temporary() { - continue - } return err } srv.lock.Lock() @@ -535,9 +532,6 @@ func (srv *Server) serveUDP(l net.PacketConn) error { if !srv.isStarted() { return nil } - if netErr, ok := err.(net.Error); ok && netErr.Temporary() { - continue - } return err } if len(m) < headerSize { From 39938e9c416f02cefdae627be8ffa4238447c3bd Mon Sep 17 00:00:00 2001 From: Miek Gieben Date: Tue, 13 Aug 2024 20:39:49 +0200 Subject: [PATCH 16/21] Revert "Remove use of deprecated net.Error.Temporary (#1589)" (#1594) This reverts commit ef7392e4ff2ef86bea51ee4f32fc60eaf1c2a88a. See: https://github.com/miekg/dns/pull/1589#issuecomment-2276738695 breaks udp serving --- server.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/server.go b/server.go index 7a67cf3b4e..81580d1e5f 100644 --- a/server.go +++ b/server.go @@ -476,6 +476,9 @@ func (srv *Server) serveTCP(l net.Listener) error { if !srv.isStarted() { return nil } + if neterr, ok := err.(net.Error); ok && neterr.Temporary() { + continue + } return err } srv.lock.Lock() @@ -532,6 +535,9 @@ func (srv *Server) serveUDP(l net.PacketConn) error { if !srv.isStarted() { return nil } + if netErr, ok := err.(net.Error); ok && netErr.Temporary() { + continue + } return err } if len(m) < headerSize { From 34b3cbb0035de80981215f89ca671853afeccbf9 Mon Sep 17 00:00:00 2001 From: Miek Gieben Date: Tue, 13 Aug 2024 20:51:26 +0200 Subject: [PATCH 17/21] Go 1.23 was released couple of hours ago Signed-off-by: Miek Gieben --- .github/workflows/go.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index fe3228ea96..c0674c784b 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -7,7 +7,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - go: [ 1.20.x, 1.21.x ] + go: [ 1.22.x, 1.23.x ] steps: - name: Set up Go From 07a2352e44fe1aaa3bae7b0b4cbcb3a0f6d1a4a6 Mon Sep 17 00:00:00 2001 From: Miek Gieben Date: Tue, 13 Aug 2024 20:55:19 +0200 Subject: [PATCH 18/21] Release 1.1.62 --- version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.go b/version.go index dc34e5902b..00c8629f27 100644 --- a/version.go +++ b/version.go @@ -3,7 +3,7 @@ package dns import "fmt" // Version is current version of this library. -var Version = v{1, 1, 58} +var Version = v{1, 1, 62} // v holds the version of this library. type v struct { From 60089295f7760d1af87adcb6e0487567e551887d Mon Sep 17 00:00:00 2001 From: Johan Brandhorst-Satzkorn Date: Wed, 21 Aug 2024 04:00:37 -0700 Subject: [PATCH 19/21] add decorate reader warning (#1596) The bytes read from the reader are returned to a pool and must not be changed by the decorated reader. --- server.go | 1 + 1 file changed, 1 insertion(+) diff --git a/server.go b/server.go index 81580d1e5f..b04d370f68 100644 --- a/server.go +++ b/server.go @@ -226,6 +226,7 @@ type Server struct { // If NotifyStartedFunc is set it is called once the server has started listening. NotifyStartedFunc func() // DecorateReader is optional, allows customization of the process that reads raw DNS messages. + // The decorated reader must not mutate the data read from the conn. DecorateReader DecorateReader // DecorateWriter is optional, allows customization of the process that writes raw DNS messages. DecorateWriter DecorateWriter From 794abd7eb88a961442bfe6af3501b306d2f8d53d Mon Sep 17 00:00:00 2001 From: Miek Gieben Date: Wed, 21 Aug 2024 13:01:04 +0200 Subject: [PATCH 20/21] edns0 cleanups (#1595) Mostly trickered by: ~~~ - return &EDNS0_ESU{Code: EDNS0ESU} + return new(EDNS0_ESU) ~~~ dont see why this 'case' needs to be different than all the others. Some various textual changes for the test. Signed-off-by: Miek Gieben --- edns.go | 36 ++++++++++++++++-------------------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/edns.go b/edns.go index c1bbdaae2e..0447fd826a 100644 --- a/edns.go +++ b/edns.go @@ -58,7 +58,7 @@ func makeDataOpt(code uint16) EDNS0 { case EDNS0EDE: return new(EDNS0_EDE) case EDNS0ESU: - return &EDNS0_ESU{Code: EDNS0ESU} + return new(EDNS0_ESU) default: e := new(EDNS0_LOCAL) e.Code = code @@ -66,8 +66,7 @@ func makeDataOpt(code uint16) EDNS0 { } } -// OPT is the EDNS0 RR appended to messages to convey extra (meta) information. -// See RFC 6891. +// OPT is the EDNS0 RR appended to messages to convey extra (meta) information. See RFC 6891. type OPT struct { Hdr RR_Header Option []EDNS0 `dns:"opt"` @@ -144,8 +143,6 @@ func (*OPT) parse(c *zlexer, origin string) *ParseError { func (rr *OPT) isDuplicate(r2 RR) bool { return false } -// return the old value -> delete SetVersion? - // Version returns the EDNS version used. Only zero is defined. func (rr *OPT) Version() uint8 { return uint8(rr.Hdr.Ttl & 0x00FF0000 >> 16) @@ -236,8 +233,8 @@ type EDNS0 interface { // e.Nsid = "AA" // o.Option = append(o.Option, e) type EDNS0_NSID struct { - Code uint16 // Always EDNS0NSID - Nsid string // This string needs to be hex encoded + Code uint16 // always EDNS0NSID + Nsid string // string needs to be hex encoded } func (e *EDNS0_NSID) pack() ([]byte, error) { @@ -275,7 +272,7 @@ func (e *EDNS0_NSID) copy() EDNS0 { return &EDNS0_NSID{e.Code, e.Nsid} // When packing it will apply SourceNetmask. If you need more advanced logic, // patches welcome and good luck. type EDNS0_SUBNET struct { - Code uint16 // Always EDNS0SUBNET + Code uint16 // always EDNS0SUBNET Family uint16 // 1 for IP, 2 for IP6 SourceNetmask uint8 SourceScope uint8 @@ -399,8 +396,8 @@ func (e *EDNS0_SUBNET) copy() EDNS0 { // // There is no guarantee that the Cookie string has a specific length. type EDNS0_COOKIE struct { - Code uint16 // Always EDNS0COOKIE - Cookie string // Hex-encoded cookie data + Code uint16 // always EDNS0COOKIE + Cookie string // hex encoded cookie data } func (e *EDNS0_COOKIE) pack() ([]byte, error) { @@ -430,7 +427,7 @@ func (e *EDNS0_COOKIE) copy() EDNS0 { return &EDNS0_COOKIE{e.Code, e.C // e.Lease = 120 // in seconds // o.Option = append(o.Option, e) type EDNS0_UL struct { - Code uint16 // Always EDNS0UL + Code uint16 // always EDNS0UL Lease uint32 KeyLease uint32 } @@ -469,7 +466,7 @@ func (e *EDNS0_UL) unpack(b []byte) error { // EDNS0_LLQ stands for Long Lived Queries: http://tools.ietf.org/html/draft-sekar-dns-llq-01 // Implemented for completeness, as the EDNS0 type code is assigned. type EDNS0_LLQ struct { - Code uint16 // Always EDNS0LLQ + Code uint16 // always EDNS0LLQ Version uint16 Opcode uint16 Error uint16 @@ -515,7 +512,7 @@ func (e *EDNS0_LLQ) copy() EDNS0 { // EDNS0_DAU implements the EDNS0 "DNSSEC Algorithm Understood" option. See RFC 6975. type EDNS0_DAU struct { - Code uint16 // Always EDNS0DAU + Code uint16 // always EDNS0DAU AlgCode []uint8 } @@ -539,7 +536,7 @@ func (e *EDNS0_DAU) copy() EDNS0 { return &EDNS0_DAU{e.Code, e.AlgCode} } // EDNS0_DHU implements the EDNS0 "DS Hash Understood" option. See RFC 6975. type EDNS0_DHU struct { - Code uint16 // Always EDNS0DHU + Code uint16 // always EDNS0DHU AlgCode []uint8 } @@ -563,7 +560,7 @@ func (e *EDNS0_DHU) copy() EDNS0 { return &EDNS0_DHU{e.Code, e.AlgCode} } // EDNS0_N3U implements the EDNS0 "NSEC3 Hash Understood" option. See RFC 6975. type EDNS0_N3U struct { - Code uint16 // Always EDNS0N3U + Code uint16 // always EDNS0N3U AlgCode []uint8 } @@ -588,7 +585,7 @@ func (e *EDNS0_N3U) copy() EDNS0 { return &EDNS0_N3U{e.Code, e.AlgCode} } // EDNS0_EXPIRE implements the EDNS0 option as described in RFC 7314. type EDNS0_EXPIRE struct { - Code uint16 // Always EDNS0EXPIRE + Code uint16 // always EDNS0EXPIRE Expire uint32 Empty bool // Empty is used to signal an empty Expire option in a backwards compatible way, it's not used on the wire. } @@ -668,7 +665,7 @@ func (e *EDNS0_LOCAL) unpack(b []byte) error { // EDNS0_TCP_KEEPALIVE is an EDNS0 option that instructs the server to keep // the TCP connection alive. See RFC 7828. type EDNS0_TCP_KEEPALIVE struct { - Code uint16 // Always EDNSTCPKEEPALIVE + Code uint16 // always EDNSTCPKEEPALIVE // Timeout is an idle timeout value for the TCP connection, specified in // units of 100 milliseconds, encoded in network byte order. If set to 0, @@ -839,13 +836,12 @@ func (e *EDNS0_EDE) unpack(b []byte) error { return nil } -// The EDNS0_ESU option for ENUM Source-URI Extension +// The EDNS0_ESU option for ENUM Source-URI Extension. type EDNS0_ESU struct { - Code uint16 + Code uint16 // always EDNS0ESU Uri string } -// Option implements the EDNS0 interface. func (e *EDNS0_ESU) Option() uint16 { return EDNS0ESU } func (e *EDNS0_ESU) String() string { return e.Uri } func (e *EDNS0_ESU) copy() EDNS0 { return &EDNS0_ESU{e.Code, e.Uri} } From b77d1ed8e9282cadf21c4124f53a660fed55c8ca Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 Sep 2024 17:16:11 +0200 Subject: [PATCH 21/21] Bump golang.org/x/net from 0.27.0 to 0.28.0 (#1600) Bumps [golang.org/x/net](https://github.com/golang/net) from 0.27.0 to 0.28.0. - [Commits](https://github.com/golang/net/compare/v0.27.0...v0.28.0) --- updated-dependencies: - dependency-name: golang.org/x/net dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index cb9c336d15..e339698a3c 100644 --- a/go.mod +++ b/go.mod @@ -3,9 +3,9 @@ module github.com/miekg/dns go 1.19 require ( - golang.org/x/net v0.27.0 + golang.org/x/net v0.28.0 golang.org/x/sync v0.7.0 - golang.org/x/sys v0.22.0 + golang.org/x/sys v0.23.0 golang.org/x/tools v0.22.0 ) diff --git a/go.sum b/go.sum index c835f72e01..eb350ad145 100644 --- a/go.sum +++ b/go.sum @@ -1,10 +1,10 @@ golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0= golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys= -golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= +golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= +golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= -golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM= +golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA= golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c=