From 60089295f7760d1af87adcb6e0487567e551887d Mon Sep 17 00:00:00 2001 From: Johan Brandhorst-Satzkorn Date: Wed, 21 Aug 2024 04:00:37 -0700 Subject: [PATCH 01/19] 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 81580d1e5..b04d370f6 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 02/19] 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 c1bbdaae2..0447fd826 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 03/19] 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 cb9c336d1..e339698a3 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 c835f72e0..eb350ad14 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= From cbe4275da1c1c2dfcbaf7c37224cbb9a1e49e706 Mon Sep 17 00:00:00 2001 From: Erik Geiser <70747329+rtpt-erikgeiser@users.noreply.github.com> Date: Fri, 24 Jan 2025 11:27:49 +0100 Subject: [PATCH 04/19] Allow SO_REUSEADDR and SO_REUSEPORT to be set simultaneously (#1623) --- ...euseport.go => listen_no_socket_options.go | 22 ++++- ...n_reuseport.go => listen_socket_options.go | 31 ++++++ server_test.go | 96 ++++++++++++++++++- 3 files changed, 144 insertions(+), 5 deletions(-) rename listen_no_reuseport.go => listen_no_socket_options.go (61%) rename listen_reuseport.go => listen_socket_options.go (66%) diff --git a/listen_no_reuseport.go b/listen_no_socket_options.go similarity index 61% rename from listen_no_reuseport.go rename to listen_no_socket_options.go index 8cebb2f17..9e4010bdc 100644 --- a/listen_no_reuseport.go +++ b/listen_no_socket_options.go @@ -3,9 +3,15 @@ package dns -import "net" +import ( + "fmt" + "net" +) -const supportsReusePort = false +const ( + supportsReusePort = false + supportsReuseAddr = false +) func listenTCP(network, addr string, reuseport, reuseaddr bool) (net.Listener, error) { if reuseport || reuseaddr { @@ -15,8 +21,6 @@ func listenTCP(network, addr string, reuseport, reuseaddr bool) (net.Listener, e return net.Listen(network, addr) } -const supportsReuseAddr = false - func listenUDP(network, addr string, reuseport, reuseaddr bool) (net.PacketConn, error) { if reuseport || reuseaddr { // TODO(tmthrgd): return an error? @@ -24,3 +28,13 @@ func listenUDP(network, addr string, reuseport, reuseaddr bool) (net.PacketConn, return net.ListenPacket(network, addr) } + +// this is just for test compatibility +func checkReuseport(fd uintptr) (bool, error) { + return false, fmt.Errorf("not supported") +} + +// this is just for test compatibility +func checkReuseaddr(fd uintptr) (bool, error) { + return false, fmt.Errorf("not supported") +} diff --git a/listen_reuseport.go b/listen_socket_options.go similarity index 66% rename from listen_reuseport.go rename to listen_socket_options.go index 41326f20b..35dfc9498 100644 --- a/listen_reuseport.go +++ b/listen_socket_options.go @@ -39,10 +39,40 @@ func reuseaddrControl(network, address string, c syscall.RawConn) error { return opErr } +func reuseaddrandportControl(network, address string, c syscall.RawConn) error { + err := reuseaddrControl(network, address, c) + if err != nil { + return err + } + + return reuseportControl(network, address, c) +} + +// this is just for test compatibility +func checkReuseport(fd uintptr) (bool, error) { + v, err := unix.GetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_REUSEPORT) + if err != nil { + return false, err + } + + return v == 1, nil +} + +// this is just for test compatibility +func checkReuseaddr(fd uintptr) (bool, error) { + v, err := unix.GetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_REUSEADDR) + if err != nil { + return false, err + } + + return v == 1, nil +} + func listenTCP(network, addr string, reuseport, reuseaddr bool) (net.Listener, error) { var lc net.ListenConfig switch { case reuseaddr && reuseport: + lc.Control = reuseaddrandportControl case reuseport: lc.Control = reuseportControl case reuseaddr: @@ -56,6 +86,7 @@ func listenUDP(network, addr string, reuseport, reuseaddr bool) (net.PacketConn, var lc net.ListenConfig switch { case reuseaddr && reuseport: + lc.Control = reuseaddrandportControl case reuseport: lc.Control = reuseportControl case reuseaddr: diff --git a/server_test.go b/server_test.go index 4fc2af329..a9e2339b4 100644 --- a/server_test.go +++ b/server_test.go @@ -996,6 +996,101 @@ func TestServerStartStopRace(t *testing.T) { wg.Wait() } +func TestSocketOptions(t *testing.T) { + if !supportsReuseAddr || !supportsReusePort { + t.Skip("reuseaddr or reuseport is not supported") + } + + testSocketOptions := func(t *testing.T, reuseAddr bool, reusePort bool) { + wait := make(chan struct{}) + + srv := &Server{ + Net: "udp", + Addr: ":0", + ReuseAddr: reuseAddr, + ReusePort: reusePort, + } + + srv.NotifyStartedFunc = func() { + defer close(wait) + + conn, ok := srv.PacketConn.(*net.UDPConn) + if !ok { + t.Errorf("unexpected conn type: %T", srv.PacketConn) + return + } + + syscallConn, err := conn.SyscallConn() + if err != nil { + t.Errorf("cannot cast UDP conn to syscall conn: %v", err) + return + + } + + err = syscallConn.Control(func(fd uintptr) { + actualReusePort, err := checkReuseport(fd) + if err != nil { + t.Errorf("cannot get SO_REUSEPORT socket option: %v", err) + return + } + + if actualReusePort != reusePort { + t.Errorf("SO_REUSEPORT is %v instead of %v", actualReusePort, reusePort) + } + + actualReuseAddr, err := checkReuseaddr(fd) + if err != nil { + t.Errorf("cannot get SO_REUSEADDR socket option: %v", err) + return + } + + if actualReuseAddr != reuseAddr { + t.Errorf("SO_REUSEADDR is %v instead of %v", actualReuseAddr, reusePort) + } + }) + if err != nil { + t.Errorf("cannot check socket options: %v", err) + } + } + + fin := make(chan error, 1) + go func() { + fin <- srv.ListenAndServe() + }() + + select { + case <-wait: + err := srv.Shutdown() + if err != nil { + t.Fatalf("cannot shutdown server: %v", err) + } + + err = <-fin + if err != nil { + t.Fatalf("listen adn serve: %v", err) + } + case err := <-fin: + t.Fatalf("listen adn serve: %v", err) + } + } + + t.Run("no socket options", func(t *testing.T) { + testSocketOptions(t, false, false) + }) + + t.Run("SO_REUSEPORT", func(t *testing.T) { + testSocketOptions(t, false, true) + }) + + t.Run("SO_REUSEADDR", func(t *testing.T) { + testSocketOptions(t, true, false) + }) + + t.Run("SO_REUSEADDR and SO_REUSEPORT", func(t *testing.T) { + testSocketOptions(t, true, true) + }) +} + func TestServerReuseport(t *testing.T) { if !supportsReusePort { t.Skip("reuseport is not supported") @@ -1329,7 +1424,6 @@ func TestResponseWriteSinglePacket(t *testing.T) { m.SetQuestion("miek.nl.", TypeTXT) m.Response = true err := rw.WriteMsg(m) - if err != nil { t.Fatalf("failed to write: %v", err) } From 8a00a2f968962669182eca425f8ab26830f1aa18 Mon Sep 17 00:00:00 2001 From: Phillip Stephens Date: Fri, 24 Jan 2025 02:28:10 -0800 Subject: [PATCH 05/19] add zdns as a user of miekg/dns (#1608) --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 8d5a2a478..9831c37ba 100644 --- a/README.md +++ b/README.md @@ -85,6 +85,7 @@ A not-so-up-to-date-list-that-may-be-actually-current: * https://github.com/wintbiit/NineDNS * https://linuxcontainers.org/incus/ * https://ifconfig.es +* https://github.com/zmap/zdns Send pull request if you want to be listed here. From ca39c8b728b2f1ea8cd18c82dc6805c0377feac1 Mon Sep 17 00:00:00 2001 From: Raymond Nook <59678453+developStorm@users.noreply.github.com> Date: Fri, 24 Jan 2025 02:33:32 -0800 Subject: [PATCH 06/19] fix: input validation for RRSIG.Verify() (#1618) * fix: input validation for RRSIG.verify() * fix: use labels.go/equal instead of strings.EqualFold for domain comparison --- dnssec.go | 42 +++++++++++++------ dnssec_test.go | 111 +++++++++++++++++++++++++++++++++++++++++++++++++ sig0.go | 3 +- 3 files changed, 141 insertions(+), 15 deletions(-) diff --git a/dnssec.go b/dnssec.go index 1be87eae6..ffdafcebd 100644 --- a/dnssec.go +++ b/dnssec.go @@ -250,14 +250,6 @@ func (d *DS) ToCDS() *CDS { // zero, it is used as-is, otherwise the TTL of the RRset is used as the // OrigTTL. func (rr *RRSIG) Sign(k crypto.Signer, rrset []RR) error { - if k == nil { - return ErrPrivKey - } - // s.Inception and s.Expiration may be 0 (rollover etc.), the rest must be set - if rr.KeyTag == 0 || len(rr.SignerName) == 0 || rr.Algorithm == 0 { - return ErrKey - } - h0 := rrset[0].Header() rr.Hdr.Rrtype = TypeRRSIG rr.Hdr.Name = h0.Name @@ -272,6 +264,18 @@ func (rr *RRSIG) Sign(k crypto.Signer, rrset []RR) error { rr.Labels-- // wildcard, remove from label count } + return rr.signAsIs(k, rrset) +} + +func (rr *RRSIG) signAsIs(k crypto.Signer, rrset []RR) error { + if k == nil { + return ErrPrivKey + } + // s.Inception and s.Expiration may be 0 (rollover etc.), the rest must be set + if rr.KeyTag == 0 || len(rr.SignerName) == 0 || rr.Algorithm == 0 { + return ErrKey + } + sigwire := new(rrsigWireFmt) sigwire.TypeCovered = rr.TypeCovered sigwire.Algorithm = rr.Algorithm @@ -370,9 +374,12 @@ func (rr *RRSIG) Verify(k *DNSKEY, rrset []RR) error { if rr.Algorithm != k.Algorithm { return ErrKey } - if !strings.EqualFold(rr.SignerName, k.Hdr.Name) { + + signerName := CanonicalName(rr.SignerName) + if !equal(signerName, k.Hdr.Name) { return ErrKey } + if k.Protocol != 3 { return ErrKey } @@ -384,9 +391,18 @@ func (rr *RRSIG) Verify(k *DNSKEY, rrset []RR) error { } // IsRRset checked that we have at least one RR and that the RRs in - // the set have consistent type, class, and name. Also check that type and - // class matches the RRSIG record. - if h0 := rrset[0].Header(); h0.Class != rr.Hdr.Class || h0.Rrtype != rr.TypeCovered { + // the set have consistent type, class, and name. Also check that type, + // class and name matches the RRSIG record. + // Also checks RFC 4035 5.3.1 the number of labels in the RRset owner + // name MUST be greater than or equal to the value in the RRSIG RR's Labels field. + // RFC 4035 5.3.1 Signer's Name MUST be the name of the zone that [contains the RRset]. + // Since we don't have SOA info, checking suffix may be the best we can do...? + if h0 := rrset[0].Header(); h0.Class != rr.Hdr.Class || + h0.Rrtype != rr.TypeCovered || + uint8(CountLabel(h0.Name)) < rr.Labels || + !equal(h0.Name, rr.Hdr.Name) || + !strings.HasSuffix(CanonicalName(h0.Name), signerName) { + return ErrRRset } @@ -400,7 +416,7 @@ func (rr *RRSIG) Verify(k *DNSKEY, rrset []RR) error { sigwire.Expiration = rr.Expiration sigwire.Inception = rr.Inception sigwire.KeyTag = rr.KeyTag - sigwire.SignerName = CanonicalName(rr.SignerName) + sigwire.SignerName = signerName // Create the desired binary blob signeddata := make([]byte, DefaultMsgSize) n, err := packSigWire(sigwire, signeddata) diff --git a/dnssec_test.go b/dnssec_test.go index 1511278c0..4f04e85f6 100644 --- a/dnssec_test.go +++ b/dnssec_test.go @@ -155,6 +155,117 @@ func TestSignVerify(t *testing.T) { } } +// Test if RRSIG.Verify() conforms to RFC 4035 Section 5.3.1 +func TestShouldNotVerifyInvalidSig(t *testing.T) { + // The RRSIG RR and the RRset MUST have the same owner name + rrNameMismatch := getSoa() + rrNameMismatch.Hdr.Name = "example.com." + + // ... and the same class + rrClassMismatch := getSoa() + rrClassMismatch.Hdr.Class = ClassCHAOS + + // The RRSIG RR's Type Covered field MUST equal the RRset's type. + rrTypeMismatch := getSoa() + rrTypeMismatch.Hdr.Rrtype = TypeA + + // The number of labels in the RRset owner name MUST be greater than + // or equal to the value in the RRSIG RR's Labels field. + rrLabelLessThan := getSoa() + rrLabelLessThan.Hdr.Name = "nl." + + // Time checks are done in ValidityPeriod + + // With this key + key := new(DNSKEY) + key.Hdr.Rrtype = TypeDNSKEY + key.Hdr.Name = "miek.nl." + key.Hdr.Class = ClassINET + key.Hdr.Ttl = 14400 + key.Flags = 256 + key.Protocol = 3 + key.Algorithm = RSASHA256 + privkey, _ := key.Generate(512) + + normalSoa := getSoa() + + // Fill in the normal values of the Sig, before signing + sig := new(RRSIG) + sig.Hdr = RR_Header{"miek.nl.", TypeRRSIG, ClassINET, 14400, 0} + sig.TypeCovered = TypeSOA + sig.Labels = uint8(CountLabel(normalSoa.Hdr.Name)) + sig.OrigTtl = normalSoa.Hdr.Ttl + sig.Expiration = 1296534305 // date -u '+%s' -d"2011-02-01 04:25:05" + sig.Inception = 1293942305 // date -u '+%s' -d"2011-01-02 04:25:05" + sig.KeyTag = key.KeyTag() // Get the keyfrom the Key + sig.SignerName = key.Hdr.Name + sig.Algorithm = RSASHA256 + + for i, rr := range []RR{rrNameMismatch, rrClassMismatch, rrTypeMismatch, rrLabelLessThan} { + if i != 0 { // Just for the rrNameMismatch case, we need the name to mismatch + sig := sig.copy().(*RRSIG) + sig.SignerName = rr.Header().Name + sig.Hdr.Name = rr.Header().Name + key := key.copy().(*DNSKEY) + key.Hdr.Name = rr.Header().Name + } + + if err := sig.signAsIs(privkey.(*rsa.PrivateKey), []RR{rr}); err != nil { + t.Error("failure to sign the record:", err) + continue + } + + if err := sig.Verify(key, []RR{rr}); err == nil { + t.Error("should not validate: ", rr) + continue + } else { + t.Logf("expected failure: %v for RR name %s, class %d, type %d, rrsig labels %d", err, rr.Header().Name, rr.Header().Class, rr.Header().Rrtype, CountLabel(rr.Header().Name)) + } + } + + // The RRSIG RR's Signer's Name field MUST be the name of the zone that contains the RRset. + // The RRSIG RR's Signer's Name, Algorithm, and Key Tag fields MUST match the owner name, + // algorithm, and key tag for some DNSKEY RR in the zone's apex DNSKEY RRset. + sigMismatchName := sig.copy().(*RRSIG) + sigMismatchName.SignerName = "example.com." + soaMismatchName := getSoa() + soaMismatchName.Hdr.Name = "example.com." + keyMismatchName := key.copy().(*DNSKEY) + keyMismatchName.Hdr.Name = "example.com." + if err := sigMismatchName.signAsIs(privkey.(*rsa.PrivateKey), []RR{soaMismatchName}); err != nil { + t.Error("failure to sign the record:", err) + } else if err := sigMismatchName.Verify(keyMismatchName, []RR{soaMismatchName}); err == nil { + t.Error("should not validate: ", soaMismatchName, ", RRSIG's signer's name does not match the owner name") + } else { + t.Logf("expected failure: %v for signer %s and owner %s", err, sigMismatchName.SignerName, sigMismatchName.Hdr.Name) + } + + sigMismatchAlgo := sig.copy().(*RRSIG) + sigMismatchAlgo.Algorithm = RSASHA1 + sigMismatchKeyTag := sig.copy().(*RRSIG) + sigMismatchKeyTag.KeyTag = 12345 + for _, sigMismatch := range []*RRSIG{sigMismatchAlgo, sigMismatchKeyTag} { + if err := sigMismatch.Sign(privkey.(*rsa.PrivateKey), []RR{normalSoa}); err != nil { + t.Error("failure to sign the record:", err) + } else if err := sigMismatch.Verify(key, []RR{normalSoa}); err == nil { + t.Error("should not validate: ", normalSoa) + } else { + t.Logf("expected failure: %v for signer %s algo %d keytag %d", err, sigMismatch.SignerName, sigMismatch.Algorithm, sigMismatch.KeyTag) + } + } + + // The matching DNSKEY RR MUST have the Zone Flag bit (DNSKEY RDATA Flag bit 7) set. + keyZoneBitWrong := key.copy().(*DNSKEY) + keyZoneBitWrong.Flags = key.Flags &^ ZONE + if err := sig.Sign(privkey.(*rsa.PrivateKey), []RR{normalSoa}); err != nil { + t.Error("failure to sign the record:", err) + } else if err := sig.Verify(keyZoneBitWrong, []RR{normalSoa}); err == nil { + t.Error("should not validate: ", normalSoa) + } else { + t.Logf("expected failure: %v for key flags %d", err, keyZoneBitWrong.Flags) + } +} + func Test65534(t *testing.T) { t6 := new(RFC3597) t6.Hdr = RR_Header{"miek.nl.", 65534, ClassINET, 14400, 0} diff --git a/sig0.go b/sig0.go index 2c4b10352..057bb5787 100644 --- a/sig0.go +++ b/sig0.go @@ -7,7 +7,6 @@ import ( "crypto/rsa" "encoding/binary" "math/big" - "strings" "time" ) @@ -151,7 +150,7 @@ func (rr *SIG) Verify(k *KEY, buf []byte) error { } // If key has come from the DNS name compression might // have mangled the case of the name - if !strings.EqualFold(signername, k.Header().Name) { + if !equal(signername, k.Header().Name) { return &Error{err: "signer name doesn't match key name"} } sigend := offset From fb0c220a7f9050cdfd3e04f79babd61d82e1d30f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 24 Jan 2025 11:34:03 +0100 Subject: [PATCH 07/19] Bump golang.org/x/net from 0.28.0 to 0.31.0 (#1622) Bumps [golang.org/x/net](https://github.com/golang/net) from 0.28.0 to 0.31.0. - [Commits](https://github.com/golang/net/compare/v0.28.0...v0.31.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 e339698a3..c43d1ddb6 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.28.0 + golang.org/x/net v0.31.0 golang.org/x/sync v0.7.0 - golang.org/x/sys v0.23.0 + golang.org/x/sys v0.27.0 golang.org/x/tools v0.22.0 ) diff --git a/go.sum b/go.sum index eb350ad14..6b5c4724c 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.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= -golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= +golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo= +golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM= 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.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM= -golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s= +golang.org/x/sys v0.27.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 c705e5aa58725bec0e408a4df2554f220e076d32 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 24 Jan 2025 11:34:30 +0100 Subject: [PATCH 08/19] Bump golang.org/x/sys from 0.23.0 to 0.27.0 (#1619) Bumps [golang.org/x/sys](https://github.com/golang/sys) from 0.23.0 to 0.27.0. - [Commits](https://github.com/golang/sys/compare/v0.23.0...v0.27.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 97c29ffb8fbdcc2ee5c9bd842f441a18eab0dc90 Mon Sep 17 00:00:00 2001 From: Miek Gieben Date: Fri, 24 Jan 2025 12:05:25 +0100 Subject: [PATCH 09/19] Release 1.1.63 --- version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.go b/version.go index 00c8629f2..e290e3dff 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, 62} +var Version = v{1, 1, 63} // v holds the version of this library. type v struct { From b5cf0597b81507af20690ae58c042c01c535983d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 22 Feb 2025 12:51:33 +0100 Subject: [PATCH 10/19] Bump golang.org/x/sys from 0.27.0 to 0.29.0 (#1632) Bumps [golang.org/x/sys](https://github.com/golang/sys) from 0.27.0 to 0.29.0. - [Commits](https://github.com/golang/sys/compare/v0.27.0...v0.29.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 c43d1ddb6..efdea89d3 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.19 require ( golang.org/x/net v0.31.0 golang.org/x/sync v0.7.0 - golang.org/x/sys v0.27.0 + golang.org/x/sys v0.29.0 golang.org/x/tools v0.22.0 ) diff --git a/go.sum b/go.sum index 6b5c4724c..02703e542 100644 --- a/go.sum +++ b/go.sum @@ -4,7 +4,7 @@ golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo= golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM= 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.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s= -golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= +golang.org/x/sys v0.29.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 b911878db335d03de066372fa9e3992acf8d39a0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 22 Feb 2025 12:51:47 +0100 Subject: [PATCH 11/19] Bump golang.org/x/net from 0.31.0 to 0.34.0 (#1631) Bumps [golang.org/x/net](https://github.com/golang/net) from 0.31.0 to 0.34.0. - [Commits](https://github.com/golang/net/compare/v0.31.0...v0.34.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 efdea89d3..2138fc404 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.31.0 + golang.org/x/net v0.34.0 golang.org/x/sync v0.7.0 golang.org/x/sys v0.29.0 golang.org/x/tools v0.22.0 diff --git a/go.sum b/go.sum index 02703e542..38e4f7732 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,7 @@ 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.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo= -golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM= +golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0= +golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k= 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.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= From 72fe95ac977d221183a6d2503010e2520b6e2c37 Mon Sep 17 00:00:00 2001 From: Miek Gieben Date: Sat, 22 Feb 2025 13:01:06 +0100 Subject: [PATCH 12/19] SVCB is no RFC 9460. (#1636) Closes #1628 Signed-off-by: Miek Gieben --- README.md | 1 + svcb.go | 12 ++---------- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 9831c37ba..65d6d79af 100644 --- a/README.md +++ b/README.md @@ -193,6 +193,7 @@ Example programs can be found in the `github.com/miekg/exdns` repository. * 9460 - Service Binding and Parameter Specification via the DNS * 9461 - Service Binding Mapping for DNS Servers * 9462 - Discovery of Designated Resolvers +* 9460 - SVCB and HTTPS Records ## Loosely Based Upon diff --git a/svcb.go b/svcb.go index 310c7d11f..d1baeea99 100644 --- a/svcb.go +++ b/svcb.go @@ -214,11 +214,7 @@ func makeSVCBKeyValue(key SVCBKey) SVCBKeyValue { } } -// SVCB RR. See RFC xxxx (https://tools.ietf.org/html/draft-ietf-dnsop-svcb-https-08). -// -// NOTE: The HTTPS/SVCB RFCs are in the draft stage. -// The API, including constants and types related to SVCBKeyValues, may -// change in future versions in accordance with the latest drafts. +// SVCB RR. See RFC 9460. type SVCB struct { Hdr RR_Header Priority uint16 // If zero, Value must be empty or discarded by the user of this library @@ -226,12 +222,8 @@ type SVCB struct { Value []SVCBKeyValue `dns:"pairs"` } -// HTTPS RR. Everything valid for SVCB applies to HTTPS as well. +// HTTPS RR. See RFC 9460. Everything valid for SVCB applies to HTTPS as well. // Except that the HTTPS record is intended for use with the HTTP and HTTPS protocols. -// -// NOTE: The HTTPS/SVCB RFCs are in the draft stage. -// The API, including constants and types related to SVCBKeyValues, may -// change in future versions in accordance with the latest drafts. type HTTPS struct { SVCB } From 75e8f27ccd1a3643011fdbfa70a721a4b6e137d1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 Feb 2025 15:14:14 +0100 Subject: [PATCH 13/19] Bump golang.org/x/sync from 0.7.0 to 0.11.0 (#1635) Bumps [golang.org/x/sync](https://github.com/golang/sync) from 0.7.0 to 0.11.0. - [Commits](https://github.com/golang/sync/compare/v0.7.0...v0.11.0) --- updated-dependencies: - dependency-name: golang.org/x/sync 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 2138fc404..d0c4749a1 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.19 require ( golang.org/x/net v0.34.0 - golang.org/x/sync v0.7.0 + golang.org/x/sync v0.11.0 golang.org/x/sys v0.29.0 golang.org/x/tools v0.22.0 ) diff --git a/go.sum b/go.sum index 38e4f7732..73820a66b 100644 --- a/go.sum +++ b/go.sum @@ -2,8 +2,8 @@ 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.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0= golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k= -golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= -golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= +golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA= From 37f4827e1cff5d0ed21d2bf9df4e140dfe4b4937 Mon Sep 17 00:00:00 2001 From: Miek Gieben Date: Mon, 24 Feb 2025 15:20:36 +0100 Subject: [PATCH 14/19] Try to group the dependabot prs Signed-off-by: Miek Gieben --- .github/dependabot.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 202ae2366..4be16cd42 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -4,3 +4,7 @@ updates: directory: "/" schedule: interval: "monthly" + groups: + all: + patterns: + - "*" From 1c19e4901474ca38eae989a814ba67bce3e55eae Mon Sep 17 00:00:00 2001 From: Miek Gieben Date: Mon, 24 Feb 2025 15:21:19 +0100 Subject: [PATCH 15/19] Manually run a go get -u Signed-off-by: Miek Gieben --- go.mod | 12 +++++++----- go.sum | 18 ++++++++++-------- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/go.mod b/go.mod index d0c4749a1..9f2b8a475 100644 --- a/go.mod +++ b/go.mod @@ -1,12 +1,14 @@ module github.com/miekg/dns -go 1.19 +go 1.22.0 + +toolchain go1.24.0 require ( - golang.org/x/net v0.34.0 + golang.org/x/net v0.35.0 golang.org/x/sync v0.11.0 - golang.org/x/sys v0.29.0 - golang.org/x/tools v0.22.0 + golang.org/x/sys v0.30.0 + golang.org/x/tools v0.30.0 ) -require golang.org/x/mod v0.18.0 // indirect +require golang.org/x/mod v0.23.0 // indirect diff --git a/go.sum b/go.sum index 73820a66b..ea241f1ee 100644 --- a/go.sum +++ b/go.sum @@ -1,10 +1,12 @@ -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.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0= -golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +golang.org/x/mod v0.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM= +golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= +golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= +golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= -golang.org/x/sys v0.29.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= +golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= +golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/tools v0.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY= +golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY= From 6425a084b83b879c1b5ab26a81398b4e223827b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Bortzmeyer?= Date: Mon, 10 Mar 2025 19:52:10 +0100 Subject: [PATCH 16/19] Add the check-soa program, which uses the library (#1638) Co-authored-by: Stephane Bortzmeyer --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 65d6d79af..8c957f6a7 100644 --- a/README.md +++ b/README.md @@ -86,7 +86,7 @@ A not-so-up-to-date-list-that-may-be-actually-current: * https://linuxcontainers.org/incus/ * https://ifconfig.es * https://github.com/zmap/zdns - +* https://framagit.org/bortzmeyer/check-soa Send pull request if you want to be listed here. From 8d0c4128deeb82bf7b296852e35bd6e198a82a40 Mon Sep 17 00:00:00 2001 From: Christian Elmerot Date: Wed, 12 Mar 2025 19:03:33 +0100 Subject: [PATCH 17/19] Add support for Compact Answers OK flag in EDNS (#1639) Compact Answers OK flag is a signal that a queryer or server understand and can validate Compact Denial of Existance answers allowing RCODE NXDOMAIN restoration with single NSEC/NSEC3. Flag is allocated by IANA: https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-13 Compact Denial of Existance: https://www.iana.org/go/draft-ietf-dnsop-compact-denial-of-existence-07 Co-authored-by: Christian Elmerot --- README.md | 1 + edns.go | 35 ++++++++++++++++++++++++++++++----- edns_test.go | 38 ++++++++++++++++++++++++++++++++++++-- 3 files changed, 67 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 8c957f6a7..5fbfb17e3 100644 --- a/README.md +++ b/README.md @@ -194,6 +194,7 @@ Example programs can be found in the `github.com/miekg/exdns` repository. * 9461 - Service Binding Mapping for DNS Servers * 9462 - Discovery of Designated Resolvers * 9460 - SVCB and HTTPS Records +* Draft - Compact Denial of Existence in DNSSEC ## Loosely Based Upon diff --git a/edns.go b/edns.go index 0447fd826..91793b906 100644 --- a/edns.go +++ b/edns.go @@ -27,6 +27,7 @@ const ( EDNS0LOCALSTART = 0xFDE9 // Beginning of range reserved for local/experimental use (See RFC 6891) EDNS0LOCALEND = 0xFFFE // End of range reserved for local/experimental use (See RFC 6891) _DO = 1 << 15 // DNSSEC OK + _CO = 1 << 14 // Compact Answers OK ) // makeDataOpt is used to unpack the EDNS0 option(s) from a message. @@ -75,7 +76,11 @@ type OPT struct { func (rr *OPT) String() string { s := "\n;; OPT PSEUDOSECTION:\n; EDNS: version " + strconv.Itoa(int(rr.Version())) + "; " if rr.Do() { - s += "flags: do; " + if rr.Co() { + s += "flags: do, co; " + } else { + s += "flags: do; " + } } else { s += "flags:; " } @@ -195,14 +200,34 @@ func (rr *OPT) SetDo(do ...bool) { } } -// Z returns the Z part of the OPT RR as a uint16 with only the 15 least significant bits used. +// Co returns the value of the CO (Compact Answers OK) bit. +func (rr *OPT) Co() bool { + return rr.Hdr.Ttl&_CO == _CO +} + +// SetCo sets the CO (Compact Answers OK) bit. +// If we pass an argument, set the CO bit to that value. +// It is possible to pass 2 or more arguments, but they will be ignored. +func (rr *OPT) SetCo(co ...bool) { + if len(co) == 1 { + if co[0] { + rr.Hdr.Ttl |= _CO + } else { + rr.Hdr.Ttl &^= _CO + } + } else { + rr.Hdr.Ttl |= _CO + } +} + +// Z returns the Z part of the OPT RR as a uint16 with only the 14 least significant bits used. func (rr *OPT) Z() uint16 { - return uint16(rr.Hdr.Ttl & 0x7FFF) + return uint16(rr.Hdr.Ttl & 0x3FFF) } -// SetZ sets the Z part of the OPT RR, note only the 15 least significant bits of z are used. +// SetZ sets the Z part of the OPT RR, note only the 14 least significant bits of z are used. func (rr *OPT) SetZ(z uint16) { - rr.Hdr.Ttl = rr.Hdr.Ttl&^0x7FFF | uint32(z&0x7FFF) + rr.Hdr.Ttl = rr.Hdr.Ttl&^0x3FFF | uint32(z&0x3FFF) } // EDNS0 defines an EDNS0 Option. An OPT RR can have multiple options appended to it. diff --git a/edns_test.go b/edns_test.go index b7c15f7e4..b9853dd2d 100644 --- a/edns_test.go +++ b/edns_test.go @@ -56,6 +56,39 @@ func TestOPTTtl(t *testing.T) { t.Errorf("DO bit should be non-zero") } + // CO (Compact ANswers OK) flag tests follow the same pattern as DO tests + // verify that invoking SetCo() sets CO=1 + e.SetCo() + if !e.Co() { + t.Errorf("CO bit should be non-zero") + } + + // verify that using SetCo(true) works when CO=1 + e.SetCo(true) + if !e.Co() { + t.Errorf("CO bit should still be non-zero") + } + // verify that we can use SetCo(false) to set CO=0 + e.SetCo(false) + if e.Co() { + t.Errorf("CO bit should be zero") + } + // verify that if we call SetCo(false) when CO=0 that it is unchanged + e.SetCo(false) + if e.Co() { + t.Errorf("CO bit should still be zero") + } + // verify that using SetCo(true) works for CO=0 + e.SetCo(true) + if !e.Co() { + t.Errorf("CO bit should be non-zero") + } + // verify that using SetCo() works for CO=1 + e.SetCo() + if !e.Co() { + t.Errorf("CO bit should be non-zero") + } + if e.Version() != 0 { t.Errorf("version should be non-zero") } @@ -141,6 +174,7 @@ func TestZ(t *testing.T) { e.Hdr.Rrtype = TypeOPT e.SetVersion(8) e.SetDo() + e.SetCo() if e.Z() != 0 { t.Errorf("expected Z of 0, got %d", e.Z()) } @@ -149,8 +183,8 @@ func TestZ(t *testing.T) { t.Errorf("expected Z of 5, got %d", e.Z()) } e.SetZ(0xFFFF) - if e.Z() != 0x7FFF { - t.Errorf("expected Z of 0x7FFFF, got %d", e.Z()) + if e.Z() != 0x3FFF { + t.Errorf("expected Z of 0x3FFFF, got %d", e.Z()) } if e.Version() != 8 { t.Errorf("expected version to still be 8, got %d", e.Version()) From d9125187847d4a06f89b09aad13478b4ed599761 Mon Sep 17 00:00:00 2001 From: frcroth Date: Tue, 18 Mar 2025 12:55:06 +0100 Subject: [PATCH 18/19] Add RESINFO rr (#1641) * Add RESINFO rr * Update scan_rr.go --------- Co-authored-by: Miek Gieben --- README.md | 1 + scan_rr.go | 10 ++++++++++ types.go | 10 ++++++++++ zduplicate.go | 17 +++++++++++++++++ zmsg.go | 19 +++++++++++++++++++ ztypes.go | 15 +++++++++++++++ 6 files changed, 72 insertions(+) diff --git a/README.md b/README.md index 5fbfb17e3..0e42858ae 100644 --- a/README.md +++ b/README.md @@ -194,6 +194,7 @@ Example programs can be found in the `github.com/miekg/exdns` repository. * 9461 - Service Binding Mapping for DNS Servers * 9462 - Discovery of Designated Resolvers * 9460 - SVCB and HTTPS Records +* 9606 - DNS Resolver Information * Draft - Compact Denial of Existence in DNSSEC ## Loosely Based Upon diff --git a/scan_rr.go b/scan_rr.go index c1a76995e..ac885f66f 100644 --- a/scan_rr.go +++ b/scan_rr.go @@ -1620,6 +1620,16 @@ func (rr *NINFO) parse(c *zlexer, o string) *ParseError { return nil } +// Uses the same format as TXT +func (rr *RESINFO) parse(c *zlexer, o string) *ParseError { + s, e := endingToTxtSlice(c, "bad RESINFO Resinfo") + if e != nil { + return e + } + rr.Txt = s + return nil +} + func (rr *URI) parse(c *zlexer, o string) *ParseError { l, _ := c.Next() i, e := strconv.ParseUint(l.token, 10, 16) diff --git a/types.go b/types.go index 7a34c14ca..7e945b516 100644 --- a/types.go +++ b/types.go @@ -101,6 +101,7 @@ const ( TypeCAA uint16 = 257 TypeAVC uint16 = 258 TypeAMTRELAY uint16 = 260 + TypeRESINFO uint16 = 261 TypeTKEY uint16 = 249 TypeTSIG uint16 = 250 @@ -1508,6 +1509,15 @@ func (rr *ZONEMD) String() string { " " + rr.Digest } +// RESINFO RR. See RFC 9606. + +type RESINFO struct { + Hdr RR_Header + Txt []string `dns:"txt"` +} + +func (rr *RESINFO) String() string { return rr.Hdr.String() + sprintTxt(rr.Txt) } + // APL RR. See RFC 3123. type APL struct { Hdr RR_Header diff --git a/zduplicate.go b/zduplicate.go index 330c05395..ebd9e0297 100644 --- a/zduplicate.go +++ b/zduplicate.go @@ -957,6 +957,23 @@ func (r1 *PX) isDuplicate(_r2 RR) bool { return true } +func (r1 *RESINFO) isDuplicate(_r2 RR) bool { + r2, ok := _r2.(*RESINFO) + if !ok { + return false + } + _ = r2 + if len(r1.Txt) != len(r2.Txt) { + return false + } + for i := 0; i < len(r1.Txt); i++ { + if r1.Txt[i] != r2.Txt[i] { + return false + } + } + return true +} + func (r1 *RFC3597) isDuplicate(_r2 RR) bool { r2, ok := _r2.(*RFC3597) if !ok { diff --git a/zmsg.go b/zmsg.go index 5a6cf4c6a..cc09810fb 100644 --- a/zmsg.go +++ b/zmsg.go @@ -762,6 +762,14 @@ func (rr *PX) pack(msg []byte, off int, compression compressionMap, compress boo return off, nil } +func (rr *RESINFO) pack(msg []byte, off int, compression compressionMap, compress bool) (off1 int, err error) { + off, err = packStringTxt(rr.Txt, msg, off) + if err != nil { + return off, err + } + return off, nil +} + func (rr *RFC3597) pack(msg []byte, off int, compression compressionMap, compress bool) (off1 int, err error) { off, err = packStringHex(rr.Rdata, msg, off) if err != nil { @@ -2353,6 +2361,17 @@ func (rr *PX) unpack(msg []byte, off int) (off1 int, err error) { return off, nil } +func (rr *RESINFO) unpack(msg []byte, off int) (off1 int, err error) { + rdStart := off + _ = rdStart + + rr.Txt, off, err = unpackStringTxt(msg, off) + if err != nil { + return off, err + } + return off, nil +} + func (rr *RFC3597) unpack(msg []byte, off int) (off1 int, err error) { rdStart := off _ = rdStart diff --git a/ztypes.go b/ztypes.go index 11f13ecf9..cea79ae77 100644 --- a/ztypes.go +++ b/ztypes.go @@ -66,6 +66,7 @@ var TypeToRR = map[uint16]func() RR{ TypeOPT: func() RR { return new(OPT) }, TypePTR: func() RR { return new(PTR) }, TypePX: func() RR { return new(PX) }, + TypeRESINFO: func() RR { return new(RESINFO) }, TypeRKEY: func() RR { return new(RKEY) }, TypeRP: func() RR { return new(RP) }, TypeRRSIG: func() RR { return new(RRSIG) }, @@ -154,6 +155,7 @@ var TypeToString = map[uint16]string{ TypeOPT: "OPT", TypePTR: "PTR", TypePX: "PX", + TypeRESINFO: "RESINFO", TypeRKEY: "RKEY", TypeRP: "RP", TypeRRSIG: "RRSIG", @@ -238,6 +240,7 @@ func (rr *OPENPGPKEY) Header() *RR_Header { return &rr.Hdr } func (rr *OPT) Header() *RR_Header { return &rr.Hdr } func (rr *PTR) Header() *RR_Header { return &rr.Hdr } func (rr *PX) Header() *RR_Header { return &rr.Hdr } +func (rr *RESINFO) Header() *RR_Header { return &rr.Hdr } func (rr *RFC3597) Header() *RR_Header { return &rr.Hdr } func (rr *RKEY) Header() *RR_Header { return &rr.Hdr } func (rr *RP) Header() *RR_Header { return &rr.Hdr } @@ -622,6 +625,14 @@ func (rr *PX) len(off int, compression map[string]struct{}) int { return l } +func (rr *RESINFO) len(off int, compression map[string]struct{}) int { + l := rr.Hdr.len(off, compression) + for _, x := range rr.Txt { + l += len(x) + 1 + } + return l +} + func (rr *RFC3597) len(off int, compression map[string]struct{}) int { l := rr.Hdr.len(off, compression) l += len(rr.Rdata) / 2 @@ -1148,6 +1159,10 @@ func (rr *PX) copy() RR { } } +func (rr *RESINFO) copy() RR { + return &RESINFO{rr.Hdr, cloneSlice(rr.Txt)} +} + func (rr *RFC3597) copy() RR { return &RFC3597{rr.Hdr, rr.Rdata} } From f83d075be8ee87f121b90348792df9c744357d17 Mon Sep 17 00:00:00 2001 From: Miek Gieben Date: Tue, 18 Mar 2025 16:56:14 +0100 Subject: [PATCH 19/19] Release 1.1.64 --- version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.go b/version.go index e290e3dff..384c3eb13 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, 63} +var Version = v{1, 1, 64} // v holds the version of this library. type v struct {