Repository: miekg/dns
Pull request #1590 (2024-08-06 08:19:54)

Annotate unpack* function errors with where the error happened.
Here's a first stab at the code for #1576 

This commit adds annotations to the error message when an error occurs during unpacking of a DNS message, the annotation will give detiail on where in the DNS message the unpacking error occured at. This helps to improve the debugability of such errors.


miekg: this looks good, however a whole bunch of
~~~
= RUN   TestTsigErrorResponse
    tsig_test.go:69: question.Qclass: %!w(<nil>)
--- FAIL: TestTsigErrorResponse (0.00s)
=== RUN   TestTsigBadTimeResponse
    tsig_test.go:98: question.Qclass: %!w(<nil>)
--- FAIL: TestTsigBadTimeResponse (0.00s)
=== RUN   TestTsigErrors
    tsig_test.go:140: expected an error 'dns: bad time' but got 'question.Qclass: %!w(<nil>)'
--- FAIL: TestTsigErrors (0.00s)
~~~
is popping up in the tests....
EricIO: > this looks good, however a whole bunch of
> 
> ```
> = RUN   TestTsigErrorResponse
>     tsig_test.go:69: question.Qclass: %!w(<nil>)
> --- FAIL: TestTsigErrorResponse (0.00s)
> === RUN   TestTsigBadTimeResponse
>     tsig_test.go:98: question.Qclass: %!w(<nil>)
> --- FAIL: TestTsigBadTimeResponse (0.00s)
> === RUN   TestTsigErrors
>     tsig_test.go:140: expected an error 'dns: bad time' but got 'question.Qclass: %!w(<nil>)'
> --- FAIL: TestTsigErrors (0.00s)
> ```
> 
> is popping up in the tests....

Oops sorry forgot to add my latest changes...

Patch:
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index 202ae236..4be16cd4 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -4,3 +4,7 @@ updates:
     directory: "/"
     schedule:
       interval: "monthly"
+    groups:
+      all:
+        patterns:
+          - "*"
diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml
index c0674c78..56a62f2b 100644
--- a/.github/workflows/go.yml
+++ b/.github/workflows/go.yml
@@ -7,7 +7,7 @@ jobs:
     runs-on: ubuntu-latest
     strategy:
       matrix:
-        go: [ 1.22.x, 1.23.x ]
+        go: [ 1.22.x, 1.23.x, 1.24.x ]
     steps:
 
     - name: Set up Go
diff --git a/README.md b/README.md
index 8d5a2a47..54471f5c 100644
--- a/README.md
+++ b/README.md
@@ -85,7 +85,8 @@ 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
+* https://framagit.org/bortzmeyer/check-soa
 
 Send pull request if you want to be listed here.
 
@@ -184,6 +185,7 @@ Example programs can be found in the `github.com/miekg/exdns` repository.
 * 7871 - EDNS0 Client Subnet
 * 7873 - Domain Name System (DNS) Cookies
 * 8080 - EdDSA for DNSSEC
+* 8490 - DNS Stateful Operations
 * 8499 - DNS Terminology
 * 8659 - DNS Certification Authority Authorization (CAA) Resource Record
 * 8777 - DNS Reverse IP Automatic Multicast Tunneling (AMT) Discovery
@@ -192,6 +194,9 @@ 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
+* 9606 - DNS Resolver Information
+* Draft - Compact Denial of Existence in DNSSEC
 
 ## Loosely Based Upon
 
diff --git a/dnssec.go b/dnssec.go
index 1be87eae..ffdafceb 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/edns.go b/edns.go
index c1bbdaae..91793b90 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.
@@ -58,7 +59,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 +67,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"`
@@ -76,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:; "
 	}
@@ -144,8 +148,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)
@@ -198,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.
@@ -236,8 +258,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 +297,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 +421,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 +452,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 +491,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 +537,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 +561,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 +585,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 +610,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 +690,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 +861,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} }
diff --git a/go.mod b/go.mod
index cb9c336d..ec0932a9 100644
--- a/go.mod
+++ b/go.mod
@@ -1,12 +1,14 @@
 module github.com/miekg/dns
 
-go 1.19
+go 1.23.0
+
+toolchain go1.24.2
 
 require (
-	golang.org/x/net v0.27.0
-	golang.org/x/sync v0.7.0
-	golang.org/x/sys v0.22.0
-	golang.org/x/tools v0.22.0
+	golang.org/x/net v0.40.0
+	golang.org/x/sync v0.14.0
+	golang.org/x/sys v0.33.0
+	golang.org/x/tools v0.33.0
 )
 
-require golang.org/x/mod v0.18.0 // indirect
+require golang.org/x/mod v0.24.0 // indirect
diff --git a/go.sum b/go.sum
index c835f72e..d9d371e9 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.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.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=
+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.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU=
+golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
+golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=
+golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=
+golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ=
+golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
+golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
+golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
+golang.org/x/tools v0.33.0 h1:4qz2S3zmRxbGIhDIAgjxvFutSvH5EfnsYrRBj0UI0bc=
+golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI=
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 8cebb2f1..9e4010bd 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 41326f20..35dfc949 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/msg.go b/msg.go
index 5fa7f9e8..b85c1078 100644
--- a/msg.go
+++ b/msg.go
@@ -136,18 +136,19 @@ var OpcodeToString = map[int]string{
 
 // RcodeToString maps Rcodes to strings.
 var RcodeToString = map[int]string{
-	RcodeSuccess:        "NOERROR",
-	RcodeFormatError:    "FORMERR",
-	RcodeServerFailure:  "SERVFAIL",
-	RcodeNameError:      "NXDOMAIN",
-	RcodeNotImplemented: "NOTIMP",
-	RcodeRefused:        "REFUSED",
-	RcodeYXDomain:       "YXDOMAIN", // See RFC 2136
-	RcodeYXRrset:        "YXRRSET",
-	RcodeNXRrset:        "NXRRSET",
-	RcodeNotAuth:        "NOTAUTH",
-	RcodeNotZone:        "NOTZONE",
-	RcodeBadSig:         "BADSIG", // Also known as RcodeBadVers, see RFC 6891
+	RcodeSuccess:                    "NOERROR",
+	RcodeFormatError:                "FORMERR",
+	RcodeServerFailure:              "SERVFAIL",
+	RcodeNameError:                  "NXDOMAIN",
+	RcodeNotImplemented:             "NOTIMP",
+	RcodeRefused:                    "REFUSED",
+	RcodeYXDomain:                   "YXDOMAIN", // See RFC 2136
+	RcodeYXRrset:                    "YXRRSET",
+	RcodeNXRrset:                    "NXRRSET",
+	RcodeNotAuth:                    "NOTAUTH",
+	RcodeNotZone:                    "NOTZONE",
+	RcodeStatefulTypeNotImplemented: "DSOTYPENI",
+	RcodeBadSig:                     "BADSIG", // Also known as RcodeBadVers, see RFC 6891
 	//	RcodeBadVers:        "BADVERS",
 	RcodeBadKey:    "BADKEY",
 	RcodeBadTime:   "BADTIME",
@@ -871,10 +872,9 @@ func (dns *Msg) unpack(dh Header, msg []byte, off int) (err error) {
 	// TODO(miek) make this an error?
 	// use PackOpt to let people tell how detailed the error reporting should be?
 	// if off != len(msg) {
-	// 	// println("dns: extra bytes in dns packet", off, "<", len(msg))
+	//	// println("dns: extra bytes in dns packet", off, "<", len(msg))
 	// }
 	return err
-
 }
 
 // Unpack unpacks a binary message to a Msg structure.
@@ -1123,23 +1123,28 @@ func unpackQuestion(msg []byte, off int) (Question, int, error) {
 	)
 	q.Name, off, err = UnpackDomainName(msg, off)
 	if err != nil {
-		return q, off, err
+		return q, off, fmt.Errorf("question.Name: %w", err)
 	}
 	if off == len(msg) {
 		return q, off, nil
 	}
 	q.Qtype, off, err = unpackUint16(msg, off)
 	if err != nil {
-		return q, off, err
+		return q, off, fmt.Errorf("question.Qtype: %w", err)
 	}
 	if off == len(msg) {
 		return q, off, nil
 	}
 	q.Qclass, off, err = unpackUint16(msg, off)
+	if err != nil {
+		return q, off, fmt.Errorf("question.Qclass: %w", err)
+	}
+
 	if off == len(msg) {
 		return q, off, nil
 	}
-	return q, off, err
+
+	return q, off, nil
 }
 
 func (dh *Header) pack(msg []byte, off int, compression compressionMap, compress bool) (int, error) {
@@ -1177,27 +1182,27 @@ func unpackMsgHdr(msg []byte, off int) (Header, int, error) {
 	)
 	dh.Id, off, err = unpackUint16(msg, off)
 	if err != nil {
-		return dh, off, err
+		return dh, off, fmt.Errorf("header.Id: %w", err)
 	}
 	dh.Bits, off, err = unpackUint16(msg, off)
 	if err != nil {
-		return dh, off, err
+		return dh, off, fmt.Errorf("header.Bits: %w", err)
 	}
 	dh.Qdcount, off, err = unpackUint16(msg, off)
 	if err != nil {
-		return dh, off, err
+		return dh, off, fmt.Errorf("header.Qdcount: %w", err)
 	}
 	dh.Ancount, off, err = unpackUint16(msg, off)
 	if err != nil {
-		return dh, off, err
+		return dh, off, fmt.Errorf("header.Ancount: %w", err)
 	}
 	dh.Nscount, off, err = unpackUint16(msg, off)
 	if err != nil {
-		return dh, off, err
+		return dh, off, fmt.Errorf("header.Nscount: %w", err)
 	}
 	dh.Arcount, off, err = unpackUint16(msg, off)
 	if err != nil {
-		return dh, off, err
+		return dh, off, fmt.Errorf("header.Arcount: %w", err)
 	}
 	return dh, off, nil
 }
diff --git a/msg_generate.go b/msg_generate.go
index e3614193..b98fe9e7 100644
--- a/msg_generate.go
+++ b/msg_generate.go
@@ -24,6 +24,7 @@ var packageHdr = `
 
 package dns
 
+import "fmt"
 `
 
 // getTypeStruct will take a type and the package scope, and return the
@@ -208,10 +209,15 @@ _ = rdStart
 		for i := 1; i < st.NumFields(); i++ {
 			o := func(s string) {
 				fmt.Fprintf(b, s, st.Field(i).Name())
-				fmt.Fprint(b, `if err != nil {
-return off, err
+
+				err_name := name
+				if name != st.Field(i).Name() {
+					err_name += "." + st.Field(i).Name()
+				}
+				fmt.Fprintf(b, `if err != nil {
+return off, fmt.Errorf("%s: %%w", err)
 }
-`)
+`, err_name)
 			}
 
 			// size-* are special, because they reference a struct member we should use for the length.
diff --git a/reverse.go b/reverse.go
index 28151af8..6f5b3ea7 100644
--- a/reverse.go
+++ b/reverse.go
@@ -23,9 +23,12 @@ var StringToAlgorithm = reverseInt8(AlgorithmToString)
 // StringToHash is a map of names to hash IDs.
 var StringToHash = reverseInt8(HashToString)
 
-// StringToCertType is the reverseof CertTypeToString.
+// StringToCertType is the reverse of CertTypeToString.
 var StringToCertType = reverseInt16(CertTypeToString)
 
+// StringToStatefulType is the reverse of StatefulTypeToString.
+var StringToStatefulType = reverseInt16(StatefulTypeToString)
+
 // Reverse a map
 func reverseInt8(m map[uint8]string) map[string]uint8 {
 	n := make(map[string]uint8, len(m))
diff --git a/scan.go b/scan.go
index e26e8027..31957b2e 100644
--- a/scan.go
+++ b/scan.go
@@ -108,6 +108,8 @@ type ttlState struct {
 // origin for resolving relative domain names defaults to the DNS root (.).
 // Full zone file syntax is supported, including directives like $TTL and $ORIGIN.
 // All fields of the returned RR are set from the read data, except RR.Header().Rdlength which is set to 0.
+// Is you need a partial resource record with no rdata - for instance - for dynamic updates, see the [ANY]
+// documentation.
 func NewRR(s string) (RR, error) {
 	if len(s) > 0 && s[len(s)-1] != '\n' { // We need a closing newline
 		return ReadRR(strings.NewReader(s+"\n"), "")
@@ -1316,6 +1318,13 @@ func toAbsoluteName(name, origin string) (absolute string, ok bool) {
 		return origin, true
 	}
 
+	// this can happen when we have a comment after a RR that has a domain, '...   MX 20 ; this is wrong'.
+	// technically a newline can be in a domain name, but this is clearly an error and the newline only shows
+	// because of the scanning and the comment.
+	if name == "\n" {
+		return "", false
+	}
+
 	// require a valid domain name
 	_, ok = IsDomainName(name)
 	if !ok || name == "" {
diff --git a/scan_rr.go b/scan_rr.go
index c1a76995..ac885f66 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/server.go b/server.go
index 81580d1e..839fc544 100644
--- a/server.go
+++ b/server.go
@@ -44,6 +44,8 @@ type ResponseWriter interface {
 	LocalAddr() net.Addr
 	// RemoteAddr returns the net.Addr of the client that sent the current request.
 	RemoteAddr() net.Addr
+	// Network returns the value of the Net field of the Server (e.g., "tcp", "tcp-tls").
+	Network() string
 	// WriteMsg writes a reply back to the client.
 	WriteMsg(*Msg) error
 	// Write writes a raw buffer back to the client.
@@ -77,6 +79,7 @@ type response struct {
 	udpSession     *SessionUDP    // oob data to get egress interface right
 	pcSession      net.Addr       // address to use when writing to a generic net.PacketConn
 	writer         Writer         // writer to output the raw DNS bits
+	network        string         // corresponding Server.Net value
 }
 
 // handleRefused returns a HandlerFunc that returns REFUSED for every request it gets.
@@ -226,6 +229,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
@@ -556,7 +560,7 @@ func (srv *Server) serveUDP(l net.PacketConn) error {
 
 // Serve a new TCP connection.
 func (srv *Server) serveTCPConn(wg *sync.WaitGroup, rw net.Conn) {
-	w := &response{tsigProvider: srv.tsigProvider(), tcp: rw}
+	w := &response{tsigProvider: srv.tsigProvider(), tcp: rw, network: srv.Net}
 	if srv.DecorateWriter != nil {
 		w.writer = srv.DecorateWriter(w)
 	} else {
@@ -611,7 +615,7 @@ func (srv *Server) serveTCPConn(wg *sync.WaitGroup, rw net.Conn) {
 
 // Serve a new UDP request.
 func (srv *Server) serveUDPPacket(wg *sync.WaitGroup, m []byte, u net.PacketConn, udpSession *SessionUDP, pcSession net.Addr) {
-	w := &response{tsigProvider: srv.tsigProvider(), udp: u, udpSession: udpSession, pcSession: pcSession}
+	w := &response{tsigProvider: srv.tsigProvider(), udp: u, udpSession: udpSession, pcSession: pcSession, network: srv.Net}
 	if srv.DecorateWriter != nil {
 		w.writer = srv.DecorateWriter(w)
 	} else {
@@ -817,6 +821,9 @@ func (w *response) RemoteAddr() net.Addr {
 	}
 }
 
+// Network implements the ResponseWriter.Network method.
+func (w *response) Network() string { return w.network }
+
 // TsigStatus implements the ResponseWriter.TsigStatus method.
 func (w *response) TsigStatus() error { return w.tsigStatus }
 
diff --git a/sig0.go b/sig0.go
index 2c4b1035..057bb578 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
diff --git a/svcb.go b/svcb.go
index 310c7d11..d1baeea9 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
 }
diff --git a/types.go b/types.go
index 7a34c14c..f5067cd4 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
@@ -125,33 +126,35 @@ const (
 	ClassANY    = 255
 
 	// Message Response Codes, see https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml
-	RcodeSuccess        = 0  // NoError   - No Error                          [DNS]
-	RcodeFormatError    = 1  // FormErr   - Format Error                      [DNS]
-	RcodeServerFailure  = 2  // ServFail  - Server Failure                    [DNS]
-	RcodeNameError      = 3  // NXDomain  - Non-Existent Domain               [DNS]
-	RcodeNotImplemented = 4  // NotImp    - Not Implemented                   [DNS]
-	RcodeRefused        = 5  // Refused   - Query Refused                     [DNS]
-	RcodeYXDomain       = 6  // YXDomain  - Name Exists when it should not    [DNS Update]
-	RcodeYXRrset        = 7  // YXRRSet   - RR Set Exists when it should not  [DNS Update]
-	RcodeNXRrset        = 8  // NXRRSet   - RR Set that should exist does not [DNS Update]
-	RcodeNotAuth        = 9  // NotAuth   - Server Not Authoritative for zone [DNS Update]
-	RcodeNotZone        = 10 // NotZone   - Name not contained in zone        [DNS Update/TSIG]
-	RcodeBadSig         = 16 // BADSIG    - TSIG Signature Failure            [TSIG]  https://www.rfc-editor.org/rfc/rfc6895.html#section-2.3
-	RcodeBadVers        = 16 // BADVERS   - Bad OPT Version                   [EDNS0] https://www.rfc-editor.org/rfc/rfc6895.html#section-2.3
-	RcodeBadKey         = 17 // BADKEY    - Key not recognized                [TSIG]
-	RcodeBadTime        = 18 // BADTIME   - Signature out of time window      [TSIG]
-	RcodeBadMode        = 19 // BADMODE   - Bad TKEY Mode                     [TKEY]
-	RcodeBadName        = 20 // BADNAME   - Duplicate key name                [TKEY]
-	RcodeBadAlg         = 21 // BADALG    - Algorithm not supported           [TKEY]
-	RcodeBadTrunc       = 22 // BADTRUNC  - Bad Truncation                    [TSIG]
-	RcodeBadCookie      = 23 // BADCOOKIE - Bad/missing Server Cookie         [DNS Cookies]
+	RcodeSuccess                    = 0  // NoError   - No Error                          [DNS]
+	RcodeFormatError                = 1  // FormErr   - Format Error                      [DNS]
+	RcodeServerFailure              = 2  // ServFail  - Server Failure                    [DNS]
+	RcodeNameError                  = 3  // NXDomain  - Non-Existent Domain               [DNS]
+	RcodeNotImplemented             = 4  // NotImp    - Not Implemented                   [DNS]
+	RcodeRefused                    = 5  // Refused   - Query Refused                     [DNS]
+	RcodeYXDomain                   = 6  // YXDomain  - Name Exists when it should not    [DNS Update]
+	RcodeYXRrset                    = 7  // YXRRSet   - RR Set Exists when it should not  [DNS Update]
+	RcodeNXRrset                    = 8  // NXRRSet   - RR Set that should exist does not [DNS Update]
+	RcodeNotAuth                    = 9  // NotAuth   - Server Not Authoritative for zone [DNS Update]
+	RcodeNotZone                    = 10 // NotZone   - Name not contained in zone        [DNS Update/TSIG]
+	RcodeStatefulTypeNotImplemented = 11 // DSOTypeNI - DSO-TYPE not implemented          [DNS Stateful Operations] https://www.rfc-editor.org/rfc/rfc8490.html#section-10.2
+	RcodeBadSig                     = 16 // BADSIG    - TSIG Signature Failure            [TSIG]  https://www.rfc-editor.org/rfc/rfc6895.html#section-2.3
+	RcodeBadVers                    = 16 // BADVERS   - Bad OPT Version                   [EDNS0] https://www.rfc-editor.org/rfc/rfc6895.html#section-2.3
+	RcodeBadKey                     = 17 // BADKEY    - Key not recognized                [TSIG]
+	RcodeBadTime                    = 18 // BADTIME   - Signature out of time window      [TSIG]
+	RcodeBadMode                    = 19 // BADMODE   - Bad TKEY Mode                     [TKEY]
+	RcodeBadName                    = 20 // BADNAME   - Duplicate key name                [TKEY]
+	RcodeBadAlg                     = 21 // BADALG    - Algorithm not supported           [TKEY]
+	RcodeBadTrunc                   = 22 // BADTRUNC  - Bad Truncation                    [TSIG]
+	RcodeBadCookie                  = 23 // BADCOOKIE - Bad/missing Server Cookie         [DNS Cookies]
 
 	// Message Opcodes. There is no 3.
-	OpcodeQuery  = 0
-	OpcodeIQuery = 1
-	OpcodeStatus = 2
-	OpcodeNotify = 4
-	OpcodeUpdate = 5
+	OpcodeQuery    = 0
+	OpcodeIQuery   = 1
+	OpcodeStatus   = 2
+	OpcodeNotify   = 4
+	OpcodeUpdate   = 5
+	OpcodeStateful = 6
 )
 
 // Used in ZONEMD https://tools.ietf.org/html/rfc8976
@@ -178,6 +181,19 @@ const (
 	AMTRELAYHost = IPSECGatewayHost
 )
 
+// Stateful types as defined in RFC 8490.
+const (
+	StatefulTypeKeepAlive uint16 = iota + 1
+	StatefulTypeRetryDelay
+	StatefulTypeEncryptionPadding
+)
+
+var StatefulTypeToString = map[uint16]string{
+	StatefulTypeKeepAlive:         "KeepAlive",
+	StatefulTypeRetryDelay:        "RetryDelay",
+	StatefulTypeEncryptionPadding: "EncryptionPadding",
+}
+
 // Header is the wire format for the DNS packet header.
 type Header struct {
 	Id                                 uint16
@@ -267,11 +283,20 @@ func (q *Question) String() (s string) {
 	return s
 }
 
-// ANY is a wild card record. See RFC 1035, Section 3.2.3. ANY
-// is named "*" there.
+// ANY is a wild card record. See RFC 1035, Section 3.2.3. ANY is named "*" there.
+// The ANY records can be (ab)used to create resource records without any rdata, that
+// can be used in dynamic update requests. Basic use pattern:
+//
+//	a := &ANY{RR_Header{
+//		Name:   "example.org.",
+//		Rrtype: TypeA,
+//		Class:  ClassINET,
+//	}}
+//
+// Results in an A record without rdata.
 type ANY struct {
 	Hdr RR_Header
-	// Does not have any rdata
+	// Does not have any rdata.
 }
 
 func (rr *ANY) String() string { return rr.Hdr.String() }
@@ -876,7 +901,7 @@ func (rr *LOC) String() string {
 	lon = lon % LOC_HOURS
 	s += fmt.Sprintf("%02d %02d %0.3f %s ", h, m, float64(lon)/1000, ew)
 
-	var alt = float64(rr.Altitude) / 100
+	alt := float64(rr.Altitude) / 100
 	alt -= LOC_ALTITUDEBASE
 	if rr.Altitude%100 != 0 {
 		s += fmt.Sprintf("%.2fm ", alt)
@@ -1508,6 +1533,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/udp.go b/udp.go
index c018ad43..d2267185 100644
--- a/udp.go
+++ b/udp.go
@@ -1,5 +1,5 @@
-//go:build !windows
-// +build !windows
+//go:build !windows && !darwin
+// +build !windows,!darwin
 
 package dns
 
diff --git a/udp_windows.go b/udp_no_control.go
similarity index 85%
rename from udp_windows.go
rename to udp_no_control.go
index a259b67e..ca3d4a63 100644
--- a/udp_windows.go
+++ b/udp_no_control.go
@@ -1,9 +1,11 @@
-//go:build windows
-// +build windows
+//go:build windows || darwin
+// +build windows darwin
 
 // TODO(tmthrgd): Remove this Windows-specific code if go.dev/issue/7175 and
 //   go.dev/issue/7174 are ever fixed.
 
+// NOTICE(stek29): darwin supports PKTINFO in sendmsg, but it unbinds sockets, see https://github.com/miekg/dns/issues/724
+
 package dns
 
 import "net"
diff --git a/update.go b/update.go
index 16f9ee85..2fef1461 100644
--- a/update.go
+++ b/update.go
@@ -2,6 +2,7 @@ package dns
 
 // NameUsed sets the RRs in the prereq section to
 // "Name is in use" RRs. RFC 2136 section 2.4.4.
+// See [ANY] on how to make RRs without rdata.
 func (u *Msg) NameUsed(rr []RR) {
 	if u.Answer == nil {
 		u.Answer = make([]RR, 0, len(rr))
@@ -41,6 +42,7 @@ func (u *Msg) Used(rr []RR) {
 
 // RRsetUsed sets the RRs in the prereq section to
 // "RRset exists (value independent -- no rdata)" RRs. RFC 2136 section 2.4.1.
+// See [ANY] on how to make RRs without rdata.
 func (u *Msg) RRsetUsed(rr []RR) {
 	if u.Answer == nil {
 		u.Answer = make([]RR, 0, len(rr))
@@ -53,6 +55,7 @@ func (u *Msg) RRsetUsed(rr []RR) {
 
 // RRsetNotUsed sets the RRs in the prereq section to
 // "RRset does not exist" RRs. RFC 2136 section 2.4.3.
+// See [ANY] on how to make RRs without rdata.
 func (u *Msg) RRsetNotUsed(rr []RR) {
 	if u.Answer == nil {
 		u.Answer = make([]RR, 0, len(rr))
@@ -64,6 +67,7 @@ func (u *Msg) RRsetNotUsed(rr []RR) {
 }
 
 // Insert creates a dynamic update packet that adds an complete RRset, see RFC 2136 section 2.5.1.
+// See [ANY] on how to make RRs without rdata.
 func (u *Msg) Insert(rr []RR) {
 	if len(u.Question) == 0 {
 		panic("dns: empty question section")
@@ -78,6 +82,7 @@ func (u *Msg) Insert(rr []RR) {
 }
 
 // RemoveRRset creates a dynamic update packet that deletes an RRset, see RFC 2136 section 2.5.2.
+// See [ANY] on how to make RRs without rdata.
 func (u *Msg) RemoveRRset(rr []RR) {
 	if u.Ns == nil {
 		u.Ns = make([]RR, 0, len(rr))
@@ -89,6 +94,7 @@ func (u *Msg) RemoveRRset(rr []RR) {
 }
 
 // RemoveName creates a dynamic update packet that deletes all RRsets of a name, see RFC 2136 section 2.5.3
+// See [ANY] on how to make RRs without rdata.
 func (u *Msg) RemoveName(rr []RR) {
 	if u.Ns == nil {
 		u.Ns = make([]RR, 0, len(rr))
@@ -99,6 +105,7 @@ func (u *Msg) RemoveName(rr []RR) {
 }
 
 // Remove creates a dynamic update packet deletes RR from a RRSset, see RFC 2136 section 2.5.4
+// See [ANY] on how to make RRs without rdata.
 func (u *Msg) Remove(rr []RR) {
 	if u.Ns == nil {
 		u.Ns = make([]RR, 0, len(rr))
diff --git a/version.go b/version.go
index 00c8629f..936dc212 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, 66}
 
 // v holds the version of this library.
 type v struct {
diff --git a/xfr.go b/xfr.go
index 5cfbb516..97a64247 100644
--- a/xfr.go
+++ b/xfr.go
@@ -251,10 +251,13 @@ func (t *Transfer) ReadMsg() (*Msg, error) {
 	if err := m.Unpack(p); err != nil {
 		return nil, err
 	}
-	if ts, tp := m.IsTsig(), t.tsigProvider(); ts != nil && tp != nil {
+
+	if tp := t.tsigProvider(); tp != nil {
 		// Need to work on the original message p, as that was used to calculate the tsig.
 		err = TsigVerifyWithProvider(p, tp, t.tsigRequestMAC, t.tsigTimersOnly)
-		t.tsigRequestMAC = ts.MAC
+		if ts := m.IsTsig(); ts != nil {
+			t.tsigRequestMAC = ts.MAC
+		}
 	}
 	return m, err
 }
diff --git a/zduplicate.go b/zduplicate.go
index 330c0539..ebd9e029 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 5a6cf4c6..8143ddc1 100644
--- a/zmsg.go
+++ b/zmsg.go
@@ -2,6 +2,8 @@
 
 package dns
 
+import "fmt"
+
 // pack*() functions
 
 func (rr *A) pack(msg []byte, off int, compression compressionMap, compress bool) (off1 int, err error) {
@@ -762,6 +764,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 {
@@ -1214,7 +1224,7 @@ func (rr *A) unpack(msg []byte, off int) (off1 int, err error) {
 
 	rr.A, off, err = unpackDataA(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("A: %w", err)
 	}
 	return off, nil
 }
@@ -1225,7 +1235,7 @@ func (rr *AAAA) unpack(msg []byte, off int) (off1 int, err error) {
 
 	rr.AAAA, off, err = unpackDataAAAA(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("AAAA: %w", err)
 	}
 	return off, nil
 }
@@ -1236,14 +1246,14 @@ func (rr *AFSDB) unpack(msg []byte, off int) (off1 int, err error) {
 
 	rr.Subtype, off, err = unpackUint16(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("AFSDB.Subtype: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Hostname, off, err = UnpackDomainName(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("AFSDB.Hostname: %w", err)
 	}
 	return off, nil
 }
@@ -1254,14 +1264,14 @@ func (rr *AMTRELAY) unpack(msg []byte, off int) (off1 int, err error) {
 
 	rr.Precedence, off, err = unpackUint8(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("AMTRELAY.Precedence: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.GatewayType, off, err = unpackUint8(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("AMTRELAY.GatewayType: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
@@ -1271,7 +1281,7 @@ func (rr *AMTRELAY) unpack(msg []byte, off int) (off1 int, err error) {
 	}
 	rr.GatewayAddr, rr.GatewayHost, off, err = unpackIPSECGateway(msg, off, rr.GatewayType)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("AMTRELAY.GatewayHost: %w", err)
 	}
 	return off, nil
 }
@@ -1289,7 +1299,7 @@ func (rr *APL) unpack(msg []byte, off int) (off1 int, err error) {
 
 	rr.Prefixes, off, err = unpackDataApl(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("APL.Prefixes: %w", err)
 	}
 	return off, nil
 }
@@ -1300,7 +1310,7 @@ func (rr *AVC) unpack(msg []byte, off int) (off1 int, err error) {
 
 	rr.Txt, off, err = unpackStringTxt(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("AVC.Txt: %w", err)
 	}
 	return off, nil
 }
@@ -1311,21 +1321,21 @@ func (rr *CAA) unpack(msg []byte, off int) (off1 int, err error) {
 
 	rr.Flag, off, err = unpackUint8(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("CAA.Flag: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Tag, off, err = unpackString(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("CAA.Tag: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Value, off, err = unpackStringOctet(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("CAA.Value: %w", err)
 	}
 	return off, nil
 }
@@ -1336,28 +1346,28 @@ func (rr *CDNSKEY) unpack(msg []byte, off int) (off1 int, err error) {
 
 	rr.Flags, off, err = unpackUint16(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("CDNSKEY.Flags: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Protocol, off, err = unpackUint8(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("CDNSKEY.Protocol: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Algorithm, off, err = unpackUint8(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("CDNSKEY.Algorithm: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.PublicKey, off, err = unpackStringBase64(msg, off, rdStart+int(rr.Hdr.Rdlength))
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("CDNSKEY.PublicKey: %w", err)
 	}
 	return off, nil
 }
@@ -1368,28 +1378,28 @@ func (rr *CDS) unpack(msg []byte, off int) (off1 int, err error) {
 
 	rr.KeyTag, off, err = unpackUint16(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("CDS.KeyTag: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Algorithm, off, err = unpackUint8(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("CDS.Algorithm: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.DigestType, off, err = unpackUint8(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("CDS.DigestType: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Digest, off, err = unpackStringHex(msg, off, rdStart+int(rr.Hdr.Rdlength))
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("CDS.Digest: %w", err)
 	}
 	return off, nil
 }
@@ -1400,28 +1410,28 @@ func (rr *CERT) unpack(msg []byte, off int) (off1 int, err error) {
 
 	rr.Type, off, err = unpackUint16(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("CERT.Type: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.KeyTag, off, err = unpackUint16(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("CERT.KeyTag: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Algorithm, off, err = unpackUint8(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("CERT.Algorithm: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Certificate, off, err = unpackStringBase64(msg, off, rdStart+int(rr.Hdr.Rdlength))
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("CERT.Certificate: %w", err)
 	}
 	return off, nil
 }
@@ -1432,7 +1442,7 @@ func (rr *CNAME) unpack(msg []byte, off int) (off1 int, err error) {
 
 	rr.Target, off, err = UnpackDomainName(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("CNAME.Target: %w", err)
 	}
 	return off, nil
 }
@@ -1443,21 +1453,21 @@ func (rr *CSYNC) unpack(msg []byte, off int) (off1 int, err error) {
 
 	rr.Serial, off, err = unpackUint32(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("CSYNC.Serial: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Flags, off, err = unpackUint16(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("CSYNC.Flags: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.TypeBitMap, off, err = unpackDataNsec(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("CSYNC.TypeBitMap: %w", err)
 	}
 	return off, nil
 }
@@ -1468,7 +1478,7 @@ func (rr *DHCID) unpack(msg []byte, off int) (off1 int, err error) {
 
 	rr.Digest, off, err = unpackStringBase64(msg, off, rdStart+int(rr.Hdr.Rdlength))
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("DHCID.Digest: %w", err)
 	}
 	return off, nil
 }
@@ -1479,28 +1489,28 @@ func (rr *DLV) unpack(msg []byte, off int) (off1 int, err error) {
 
 	rr.KeyTag, off, err = unpackUint16(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("DLV.KeyTag: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Algorithm, off, err = unpackUint8(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("DLV.Algorithm: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.DigestType, off, err = unpackUint8(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("DLV.DigestType: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Digest, off, err = unpackStringHex(msg, off, rdStart+int(rr.Hdr.Rdlength))
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("DLV.Digest: %w", err)
 	}
 	return off, nil
 }
@@ -1511,7 +1521,7 @@ func (rr *DNAME) unpack(msg []byte, off int) (off1 int, err error) {
 
 	rr.Target, off, err = UnpackDomainName(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("DNAME.Target: %w", err)
 	}
 	return off, nil
 }
@@ -1522,28 +1532,28 @@ func (rr *DNSKEY) unpack(msg []byte, off int) (off1 int, err error) {
 
 	rr.Flags, off, err = unpackUint16(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("DNSKEY.Flags: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Protocol, off, err = unpackUint8(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("DNSKEY.Protocol: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Algorithm, off, err = unpackUint8(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("DNSKEY.Algorithm: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.PublicKey, off, err = unpackStringBase64(msg, off, rdStart+int(rr.Hdr.Rdlength))
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("DNSKEY.PublicKey: %w", err)
 	}
 	return off, nil
 }
@@ -1554,28 +1564,28 @@ func (rr *DS) unpack(msg []byte, off int) (off1 int, err error) {
 
 	rr.KeyTag, off, err = unpackUint16(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("DS.KeyTag: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Algorithm, off, err = unpackUint8(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("DS.Algorithm: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.DigestType, off, err = unpackUint8(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("DS.DigestType: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Digest, off, err = unpackStringHex(msg, off, rdStart+int(rr.Hdr.Rdlength))
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("DS.Digest: %w", err)
 	}
 	return off, nil
 }
@@ -1586,7 +1596,7 @@ func (rr *EID) unpack(msg []byte, off int) (off1 int, err error) {
 
 	rr.Endpoint, off, err = unpackStringHex(msg, off, rdStart+int(rr.Hdr.Rdlength))
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("EID.Endpoint: %w", err)
 	}
 	return off, nil
 }
@@ -1597,7 +1607,7 @@ func (rr *EUI48) unpack(msg []byte, off int) (off1 int, err error) {
 
 	rr.Address, off, err = unpackUint48(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("EUI48.Address: %w", err)
 	}
 	return off, nil
 }
@@ -1608,7 +1618,7 @@ func (rr *EUI64) unpack(msg []byte, off int) (off1 int, err error) {
 
 	rr.Address, off, err = unpackUint64(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("EUI64.Address: %w", err)
 	}
 	return off, nil
 }
@@ -1619,7 +1629,7 @@ func (rr *GID) unpack(msg []byte, off int) (off1 int, err error) {
 
 	rr.Gid, off, err = unpackUint32(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("GID.Gid: %w", err)
 	}
 	return off, nil
 }
@@ -1630,21 +1640,21 @@ func (rr *GPOS) unpack(msg []byte, off int) (off1 int, err error) {
 
 	rr.Longitude, off, err = unpackString(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("GPOS.Longitude: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Latitude, off, err = unpackString(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("GPOS.Latitude: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Altitude, off, err = unpackString(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("GPOS.Altitude: %w", err)
 	}
 	return off, nil
 }
@@ -1655,14 +1665,14 @@ func (rr *HINFO) unpack(msg []byte, off int) (off1 int, err error) {
 
 	rr.Cpu, off, err = unpackString(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("HINFO.Cpu: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Os, off, err = unpackString(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("HINFO.Os: %w", err)
 	}
 	return off, nil
 }
@@ -1673,21 +1683,21 @@ func (rr *HIP) unpack(msg []byte, off int) (off1 int, err error) {
 
 	rr.HitLength, off, err = unpackUint8(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("HIP.HitLength: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.PublicKeyAlgorithm, off, err = unpackUint8(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("HIP.PublicKeyAlgorithm: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.PublicKeyLength, off, err = unpackUint16(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("HIP.PublicKeyLength: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
@@ -1702,7 +1712,7 @@ func (rr *HIP) unpack(msg []byte, off int) (off1 int, err error) {
 	}
 	rr.RendezvousServers, off, err = unpackDataDomainNames(msg, off, rdStart+int(rr.Hdr.Rdlength))
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("HIP.RendezvousServers: %w", err)
 	}
 	return off, nil
 }
@@ -1713,21 +1723,21 @@ func (rr *HTTPS) unpack(msg []byte, off int) (off1 int, err error) {
 
 	rr.Priority, off, err = unpackUint16(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("HTTPS.Priority: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Target, off, err = UnpackDomainName(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("HTTPS.Target: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Value, off, err = unpackDataSVCB(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("HTTPS.Value: %w", err)
 	}
 	return off, nil
 }
@@ -1738,21 +1748,21 @@ func (rr *IPSECKEY) unpack(msg []byte, off int) (off1 int, err error) {
 
 	rr.Precedence, off, err = unpackUint8(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("IPSECKEY.Precedence: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.GatewayType, off, err = unpackUint8(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("IPSECKEY.GatewayType: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Algorithm, off, err = unpackUint8(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("IPSECKEY.Algorithm: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
@@ -1762,14 +1772,14 @@ func (rr *IPSECKEY) unpack(msg []byte, off int) (off1 int, err error) {
 	}
 	rr.GatewayAddr, rr.GatewayHost, off, err = unpackIPSECGateway(msg, off, rr.GatewayType)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("IPSECKEY.GatewayHost: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.PublicKey, off, err = unpackStringBase64(msg, off, rdStart+int(rr.Hdr.Rdlength))
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("IPSECKEY.PublicKey: %w", err)
 	}
 	return off, nil
 }
@@ -1780,14 +1790,14 @@ func (rr *ISDN) unpack(msg []byte, off int) (off1 int, err error) {
 
 	rr.Address, off, err = unpackString(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("ISDN.Address: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.SubAddress, off, err = unpackString(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("ISDN.SubAddress: %w", err)
 	}
 	return off, nil
 }
@@ -1798,28 +1808,28 @@ func (rr *KEY) unpack(msg []byte, off int) (off1 int, err error) {
 
 	rr.Flags, off, err = unpackUint16(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("KEY.Flags: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Protocol, off, err = unpackUint8(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("KEY.Protocol: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Algorithm, off, err = unpackUint8(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("KEY.Algorithm: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.PublicKey, off, err = unpackStringBase64(msg, off, rdStart+int(rr.Hdr.Rdlength))
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("KEY.PublicKey: %w", err)
 	}
 	return off, nil
 }
@@ -1830,14 +1840,14 @@ func (rr *KX) unpack(msg []byte, off int) (off1 int, err error) {
 
 	rr.Preference, off, err = unpackUint16(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("KX.Preference: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Exchanger, off, err = UnpackDomainName(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("KX.Exchanger: %w", err)
 	}
 	return off, nil
 }
@@ -1848,14 +1858,14 @@ func (rr *L32) unpack(msg []byte, off int) (off1 int, err error) {
 
 	rr.Preference, off, err = unpackUint16(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("L32.Preference: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Locator32, off, err = unpackDataA(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("L32.Locator32: %w", err)
 	}
 	return off, nil
 }
@@ -1866,14 +1876,14 @@ func (rr *L64) unpack(msg []byte, off int) (off1 int, err error) {
 
 	rr.Preference, off, err = unpackUint16(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("L64.Preference: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Locator64, off, err = unpackUint64(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("L64.Locator64: %w", err)
 	}
 	return off, nil
 }
@@ -1884,49 +1894,49 @@ func (rr *LOC) unpack(msg []byte, off int) (off1 int, err error) {
 
 	rr.Version, off, err = unpackUint8(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("LOC.Version: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Size, off, err = unpackUint8(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("LOC.Size: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.HorizPre, off, err = unpackUint8(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("LOC.HorizPre: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.VertPre, off, err = unpackUint8(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("LOC.VertPre: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Latitude, off, err = unpackUint32(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("LOC.Latitude: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Longitude, off, err = unpackUint32(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("LOC.Longitude: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Altitude, off, err = unpackUint32(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("LOC.Altitude: %w", err)
 	}
 	return off, nil
 }
@@ -1937,14 +1947,14 @@ func (rr *LP) unpack(msg []byte, off int) (off1 int, err error) {
 
 	rr.Preference, off, err = unpackUint16(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("LP.Preference: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Fqdn, off, err = UnpackDomainName(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("LP.Fqdn: %w", err)
 	}
 	return off, nil
 }
@@ -1955,7 +1965,7 @@ func (rr *MB) unpack(msg []byte, off int) (off1 int, err error) {
 
 	rr.Mb, off, err = UnpackDomainName(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("MB.Mb: %w", err)
 	}
 	return off, nil
 }
@@ -1966,7 +1976,7 @@ func (rr *MD) unpack(msg []byte, off int) (off1 int, err error) {
 
 	rr.Md, off, err = UnpackDomainName(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("MD.Md: %w", err)
 	}
 	return off, nil
 }
@@ -1977,7 +1987,7 @@ func (rr *MF) unpack(msg []byte, off int) (off1 int, err error) {
 
 	rr.Mf, off, err = UnpackDomainName(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("MF.Mf: %w", err)
 	}
 	return off, nil
 }
@@ -1988,7 +1998,7 @@ func (rr *MG) unpack(msg []byte, off int) (off1 int, err error) {
 
 	rr.Mg, off, err = UnpackDomainName(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("MG.Mg: %w", err)
 	}
 	return off, nil
 }
@@ -1999,14 +2009,14 @@ func (rr *MINFO) unpack(msg []byte, off int) (off1 int, err error) {
 
 	rr.Rmail, off, err = UnpackDomainName(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("MINFO.Rmail: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Email, off, err = UnpackDomainName(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("MINFO.Email: %w", err)
 	}
 	return off, nil
 }
@@ -2017,7 +2027,7 @@ func (rr *MR) unpack(msg []byte, off int) (off1 int, err error) {
 
 	rr.Mr, off, err = UnpackDomainName(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("MR.Mr: %w", err)
 	}
 	return off, nil
 }
@@ -2028,14 +2038,14 @@ func (rr *MX) unpack(msg []byte, off int) (off1 int, err error) {
 
 	rr.Preference, off, err = unpackUint16(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("MX.Preference: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Mx, off, err = UnpackDomainName(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("MX.Mx: %w", err)
 	}
 	return off, nil
 }
@@ -2046,42 +2056,42 @@ func (rr *NAPTR) unpack(msg []byte, off int) (off1 int, err error) {
 
 	rr.Order, off, err = unpackUint16(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("NAPTR.Order: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Preference, off, err = unpackUint16(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("NAPTR.Preference: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Flags, off, err = unpackString(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("NAPTR.Flags: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Service, off, err = unpackString(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("NAPTR.Service: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Regexp, off, err = unpackString(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("NAPTR.Regexp: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Replacement, off, err = UnpackDomainName(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("NAPTR.Replacement: %w", err)
 	}
 	return off, nil
 }
@@ -2092,14 +2102,14 @@ func (rr *NID) unpack(msg []byte, off int) (off1 int, err error) {
 
 	rr.Preference, off, err = unpackUint16(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("NID.Preference: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.NodeID, off, err = unpackUint64(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("NID.NodeID: %w", err)
 	}
 	return off, nil
 }
@@ -2110,7 +2120,7 @@ func (rr *NIMLOC) unpack(msg []byte, off int) (off1 int, err error) {
 
 	rr.Locator, off, err = unpackStringHex(msg, off, rdStart+int(rr.Hdr.Rdlength))
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("NIMLOC.Locator: %w", err)
 	}
 	return off, nil
 }
@@ -2121,7 +2131,7 @@ func (rr *NINFO) unpack(msg []byte, off int) (off1 int, err error) {
 
 	rr.ZSData, off, err = unpackStringTxt(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("NINFO.ZSData: %w", err)
 	}
 	return off, nil
 }
@@ -2132,7 +2142,7 @@ func (rr *NS) unpack(msg []byte, off int) (off1 int, err error) {
 
 	rr.Ns, off, err = UnpackDomainName(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("NS.Ns: %w", err)
 	}
 	return off, nil
 }
@@ -2143,7 +2153,7 @@ func (rr *NSAPPTR) unpack(msg []byte, off int) (off1 int, err error) {
 
 	rr.Ptr, off, err = UnpackDomainName(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("NSAPPTR.Ptr: %w", err)
 	}
 	return off, nil
 }
@@ -2154,14 +2164,14 @@ func (rr *NSEC) unpack(msg []byte, off int) (off1 int, err error) {
 
 	rr.NextDomain, off, err = UnpackDomainName(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("NSEC.NextDomain: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.TypeBitMap, off, err = unpackDataNsec(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("NSEC.TypeBitMap: %w", err)
 	}
 	return off, nil
 }
@@ -2172,28 +2182,28 @@ func (rr *NSEC3) unpack(msg []byte, off int) (off1 int, err error) {
 
 	rr.Hash, off, err = unpackUint8(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("NSEC3.Hash: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Flags, off, err = unpackUint8(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("NSEC3.Flags: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Iterations, off, err = unpackUint16(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("NSEC3.Iterations: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.SaltLength, off, err = unpackUint8(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("NSEC3.SaltLength: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
@@ -2204,7 +2214,7 @@ func (rr *NSEC3) unpack(msg []byte, off int) (off1 int, err error) {
 	}
 	rr.HashLength, off, err = unpackUint8(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("NSEC3.HashLength: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
@@ -2215,7 +2225,7 @@ func (rr *NSEC3) unpack(msg []byte, off int) (off1 int, err error) {
 	}
 	rr.TypeBitMap, off, err = unpackDataNsec(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("NSEC3.TypeBitMap: %w", err)
 	}
 	return off, nil
 }
@@ -2226,28 +2236,28 @@ func (rr *NSEC3PARAM) unpack(msg []byte, off int) (off1 int, err error) {
 
 	rr.Hash, off, err = unpackUint8(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("NSEC3PARAM.Hash: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Flags, off, err = unpackUint8(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("NSEC3PARAM.Flags: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Iterations, off, err = unpackUint16(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("NSEC3PARAM.Iterations: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.SaltLength, off, err = unpackUint8(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("NSEC3PARAM.SaltLength: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
@@ -2265,7 +2275,7 @@ func (rr *NULL) unpack(msg []byte, off int) (off1 int, err error) {
 
 	rr.Data, off, err = unpackStringAny(msg, off, rdStart+int(rr.Hdr.Rdlength))
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("NULL.Data: %w", err)
 	}
 	return off, nil
 }
@@ -2283,14 +2293,14 @@ func (rr *NXT) unpack(msg []byte, off int) (off1 int, err error) {
 
 	rr.NextDomain, off, err = UnpackDomainName(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("NXT.NextDomain: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.TypeBitMap, off, err = unpackDataNsec(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("NXT.TypeBitMap: %w", err)
 	}
 	return off, nil
 }
@@ -2301,7 +2311,7 @@ func (rr *OPENPGPKEY) unpack(msg []byte, off int) (off1 int, err error) {
 
 	rr.PublicKey, off, err = unpackStringBase64(msg, off, rdStart+int(rr.Hdr.Rdlength))
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("OPENPGPKEY.PublicKey: %w", err)
 	}
 	return off, nil
 }
@@ -2312,7 +2322,7 @@ func (rr *OPT) unpack(msg []byte, off int) (off1 int, err error) {
 
 	rr.Option, off, err = unpackDataOpt(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("OPT.Option: %w", err)
 	}
 	return off, nil
 }
@@ -2323,7 +2333,7 @@ func (rr *PTR) unpack(msg []byte, off int) (off1 int, err error) {
 
 	rr.Ptr, off, err = UnpackDomainName(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("PTR.Ptr: %w", err)
 	}
 	return off, nil
 }
@@ -2334,19 +2344,30 @@ func (rr *PX) unpack(msg []byte, off int) (off1 int, err error) {
 
 	rr.Preference, off, err = unpackUint16(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("PX.Preference: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Map822, off, err = UnpackDomainName(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("PX.Map822: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Mapx400, off, err = UnpackDomainName(msg, off)
+	if err != nil {
+		return off, fmt.Errorf("PX.Mapx400: %w", err)
+	}
+	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
 	}
@@ -2359,7 +2380,7 @@ func (rr *RFC3597) unpack(msg []byte, off int) (off1 int, err error) {
 
 	rr.Rdata, off, err = unpackStringHex(msg, off, rdStart+int(rr.Hdr.Rdlength))
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("RFC3597.Rdata: %w", err)
 	}
 	return off, nil
 }
@@ -2370,28 +2391,28 @@ func (rr *RKEY) unpack(msg []byte, off int) (off1 int, err error) {
 
 	rr.Flags, off, err = unpackUint16(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("RKEY.Flags: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Protocol, off, err = unpackUint8(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("RKEY.Protocol: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Algorithm, off, err = unpackUint8(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("RKEY.Algorithm: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.PublicKey, off, err = unpackStringBase64(msg, off, rdStart+int(rr.Hdr.Rdlength))
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("RKEY.PublicKey: %w", err)
 	}
 	return off, nil
 }
@@ -2402,14 +2423,14 @@ func (rr *RP) unpack(msg []byte, off int) (off1 int, err error) {
 
 	rr.Mbox, off, err = UnpackDomainName(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("RP.Mbox: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Txt, off, err = UnpackDomainName(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("RP.Txt: %w", err)
 	}
 	return off, nil
 }
@@ -2420,63 +2441,63 @@ func (rr *RRSIG) unpack(msg []byte, off int) (off1 int, err error) {
 
 	rr.TypeCovered, off, err = unpackUint16(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("RRSIG.TypeCovered: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Algorithm, off, err = unpackUint8(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("RRSIG.Algorithm: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Labels, off, err = unpackUint8(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("RRSIG.Labels: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.OrigTtl, off, err = unpackUint32(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("RRSIG.OrigTtl: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Expiration, off, err = unpackUint32(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("RRSIG.Expiration: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Inception, off, err = unpackUint32(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("RRSIG.Inception: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.KeyTag, off, err = unpackUint16(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("RRSIG.KeyTag: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.SignerName, off, err = UnpackDomainName(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("RRSIG.SignerName: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Signature, off, err = unpackStringBase64(msg, off, rdStart+int(rr.Hdr.Rdlength))
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("RRSIG.Signature: %w", err)
 	}
 	return off, nil
 }
@@ -2487,14 +2508,14 @@ func (rr *RT) unpack(msg []byte, off int) (off1 int, err error) {
 
 	rr.Preference, off, err = unpackUint16(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("RT.Preference: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Host, off, err = UnpackDomainName(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("RT.Host: %w", err)
 	}
 	return off, nil
 }
@@ -2505,63 +2526,63 @@ func (rr *SIG) unpack(msg []byte, off int) (off1 int, err error) {
 
 	rr.TypeCovered, off, err = unpackUint16(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("SIG.TypeCovered: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Algorithm, off, err = unpackUint8(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("SIG.Algorithm: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Labels, off, err = unpackUint8(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("SIG.Labels: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.OrigTtl, off, err = unpackUint32(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("SIG.OrigTtl: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Expiration, off, err = unpackUint32(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("SIG.Expiration: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Inception, off, err = unpackUint32(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("SIG.Inception: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.KeyTag, off, err = unpackUint16(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("SIG.KeyTag: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.SignerName, off, err = UnpackDomainName(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("SIG.SignerName: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Signature, off, err = unpackStringBase64(msg, off, rdStart+int(rr.Hdr.Rdlength))
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("SIG.Signature: %w", err)
 	}
 	return off, nil
 }
@@ -2572,28 +2593,28 @@ func (rr *SMIMEA) unpack(msg []byte, off int) (off1 int, err error) {
 
 	rr.Usage, off, err = unpackUint8(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("SMIMEA.Usage: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Selector, off, err = unpackUint8(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("SMIMEA.Selector: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.MatchingType, off, err = unpackUint8(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("SMIMEA.MatchingType: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Certificate, off, err = unpackStringHex(msg, off, rdStart+int(rr.Hdr.Rdlength))
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("SMIMEA.Certificate: %w", err)
 	}
 	return off, nil
 }
@@ -2604,49 +2625,49 @@ func (rr *SOA) unpack(msg []byte, off int) (off1 int, err error) {
 
 	rr.Ns, off, err = UnpackDomainName(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("SOA.Ns: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Mbox, off, err = UnpackDomainName(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("SOA.Mbox: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Serial, off, err = unpackUint32(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("SOA.Serial: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Refresh, off, err = unpackUint32(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("SOA.Refresh: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Retry, off, err = unpackUint32(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("SOA.Retry: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Expire, off, err = unpackUint32(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("SOA.Expire: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Minttl, off, err = unpackUint32(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("SOA.Minttl: %w", err)
 	}
 	return off, nil
 }
@@ -2657,7 +2678,7 @@ func (rr *SPF) unpack(msg []byte, off int) (off1 int, err error) {
 
 	rr.Txt, off, err = unpackStringTxt(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("SPF.Txt: %w", err)
 	}
 	return off, nil
 }
@@ -2668,28 +2689,28 @@ func (rr *SRV) unpack(msg []byte, off int) (off1 int, err error) {
 
 	rr.Priority, off, err = unpackUint16(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("SRV.Priority: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Weight, off, err = unpackUint16(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("SRV.Weight: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Port, off, err = unpackUint16(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("SRV.Port: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Target, off, err = UnpackDomainName(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("SRV.Target: %w", err)
 	}
 	return off, nil
 }
@@ -2700,21 +2721,21 @@ func (rr *SSHFP) unpack(msg []byte, off int) (off1 int, err error) {
 
 	rr.Algorithm, off, err = unpackUint8(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("SSHFP.Algorithm: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Type, off, err = unpackUint8(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("SSHFP.Type: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.FingerPrint, off, err = unpackStringHex(msg, off, rdStart+int(rr.Hdr.Rdlength))
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("SSHFP.FingerPrint: %w", err)
 	}
 	return off, nil
 }
@@ -2725,21 +2746,21 @@ func (rr *SVCB) unpack(msg []byte, off int) (off1 int, err error) {
 
 	rr.Priority, off, err = unpackUint16(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("SVCB.Priority: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Target, off, err = UnpackDomainName(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("SVCB.Target: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Value, off, err = unpackDataSVCB(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("SVCB.Value: %w", err)
 	}
 	return off, nil
 }
@@ -2750,28 +2771,28 @@ func (rr *TA) unpack(msg []byte, off int) (off1 int, err error) {
 
 	rr.KeyTag, off, err = unpackUint16(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("TA.KeyTag: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Algorithm, off, err = unpackUint8(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("TA.Algorithm: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.DigestType, off, err = unpackUint8(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("TA.DigestType: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Digest, off, err = unpackStringHex(msg, off, rdStart+int(rr.Hdr.Rdlength))
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("TA.Digest: %w", err)
 	}
 	return off, nil
 }
@@ -2782,14 +2803,14 @@ func (rr *TALINK) unpack(msg []byte, off int) (off1 int, err error) {
 
 	rr.PreviousName, off, err = UnpackDomainName(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("TALINK.PreviousName: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.NextName, off, err = UnpackDomainName(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("TALINK.NextName: %w", err)
 	}
 	return off, nil
 }
@@ -2800,42 +2821,42 @@ func (rr *TKEY) unpack(msg []byte, off int) (off1 int, err error) {
 
 	rr.Algorithm, off, err = UnpackDomainName(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("TKEY.Algorithm: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Inception, off, err = unpackUint32(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("TKEY.Inception: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Expiration, off, err = unpackUint32(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("TKEY.Expiration: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Mode, off, err = unpackUint16(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("TKEY.Mode: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Error, off, err = unpackUint16(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("TKEY.Error: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.KeySize, off, err = unpackUint16(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("TKEY.KeySize: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
@@ -2846,7 +2867,7 @@ func (rr *TKEY) unpack(msg []byte, off int) (off1 int, err error) {
 	}
 	rr.OtherLen, off, err = unpackUint16(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("TKEY.OtherLen: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
@@ -2864,28 +2885,28 @@ func (rr *TLSA) unpack(msg []byte, off int) (off1 int, err error) {
 
 	rr.Usage, off, err = unpackUint8(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("TLSA.Usage: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Selector, off, err = unpackUint8(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("TLSA.Selector: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.MatchingType, off, err = unpackUint8(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("TLSA.MatchingType: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Certificate, off, err = unpackStringHex(msg, off, rdStart+int(rr.Hdr.Rdlength))
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("TLSA.Certificate: %w", err)
 	}
 	return off, nil
 }
@@ -2896,28 +2917,28 @@ func (rr *TSIG) unpack(msg []byte, off int) (off1 int, err error) {
 
 	rr.Algorithm, off, err = UnpackDomainName(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("TSIG.Algorithm: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.TimeSigned, off, err = unpackUint48(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("TSIG.TimeSigned: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Fudge, off, err = unpackUint16(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("TSIG.Fudge: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.MACSize, off, err = unpackUint16(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("TSIG.MACSize: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
@@ -2928,21 +2949,21 @@ func (rr *TSIG) unpack(msg []byte, off int) (off1 int, err error) {
 	}
 	rr.OrigId, off, err = unpackUint16(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("TSIG.OrigId: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Error, off, err = unpackUint16(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("TSIG.Error: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.OtherLen, off, err = unpackUint16(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("TSIG.OtherLen: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
@@ -2960,7 +2981,7 @@ func (rr *TXT) unpack(msg []byte, off int) (off1 int, err error) {
 
 	rr.Txt, off, err = unpackStringTxt(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("TXT.Txt: %w", err)
 	}
 	return off, nil
 }
@@ -2971,7 +2992,7 @@ func (rr *UID) unpack(msg []byte, off int) (off1 int, err error) {
 
 	rr.Uid, off, err = unpackUint32(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("UID.Uid: %w", err)
 	}
 	return off, nil
 }
@@ -2982,7 +3003,7 @@ func (rr *UINFO) unpack(msg []byte, off int) (off1 int, err error) {
 
 	rr.Uinfo, off, err = unpackString(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("UINFO.Uinfo: %w", err)
 	}
 	return off, nil
 }
@@ -2993,21 +3014,21 @@ func (rr *URI) unpack(msg []byte, off int) (off1 int, err error) {
 
 	rr.Priority, off, err = unpackUint16(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("URI.Priority: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Weight, off, err = unpackUint16(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("URI.Weight: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Target, off, err = unpackStringOctet(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("URI.Target: %w", err)
 	}
 	return off, nil
 }
@@ -3018,7 +3039,7 @@ func (rr *X25) unpack(msg []byte, off int) (off1 int, err error) {
 
 	rr.PSDNAddress, off, err = unpackString(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("X25.PSDNAddress: %w", err)
 	}
 	return off, nil
 }
@@ -3029,28 +3050,28 @@ func (rr *ZONEMD) unpack(msg []byte, off int) (off1 int, err error) {
 
 	rr.Serial, off, err = unpackUint32(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("ZONEMD.Serial: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Scheme, off, err = unpackUint8(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("ZONEMD.Scheme: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Hash, off, err = unpackUint8(msg, off)
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("ZONEMD.Hash: %w", err)
 	}
 	if off == len(msg) {
 		return off, nil
 	}
 	rr.Digest, off, err = unpackStringHex(msg, off, rdStart+int(rr.Hdr.Rdlength))
 	if err != nil {
-		return off, err
+		return off, fmt.Errorf("ZONEMD.Digest: %w", err)
 	}
 	return off, nil
 }
diff --git a/ztypes.go b/ztypes.go
index 11f13ecf..cea79ae7 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}
 }


Test patch:
diff --git a/dnssec_test.go b/dnssec_test.go
index 1511278c..4f04e85f 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/edns_test.go b/edns_test.go
index b7c15f7e..b9853dd2 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())
diff --git a/scan_test.go b/scan_test.go
index c4f7e7f4..e46b3684 100644
--- a/scan_test.go
+++ b/scan_test.go
@@ -226,6 +226,22 @@ func TestZoneParserAddressAAAA(t *testing.T) {
 	}
 }
 
+func TestZoneParserTargetBad(t *testing.T) {
+	records := []string{
+		"bad.example.org. CNAME ; bad cname",
+		"bad.example.org. HTTPS 10 ; bad https",
+		"bad.example.org. MX 10 ; bad mx",
+		"bad.example.org. SRV 1 0 80 ; bad srv",
+	}
+
+	for _, record := range records {
+		const expect = "bad "
+		if got, err := NewRR(record); err == nil || !strings.Contains(err.Error(), expect) {
+			t.Errorf("NewRR(%v) = %v, want err to contain %q", record, got, expect)
+		}
+	}
+}
+
 func TestZoneParserAddressBad(t *testing.T) {
 	records := []string{
 		"1.bad.example.org. 600 IN A ::1",
diff --git a/server_test.go b/server_test.go
index 4fc2af32..a9e2339b 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)
 	}
diff --git a/xfr_test.go b/xfr_test.go
index 04801a2e..c580ceef 100644
--- a/xfr_test.go
+++ b/xfr_test.go
@@ -2,6 +2,7 @@ package dns
 
 import (
 	"crypto/tls"
+	"errors"
 	"testing"
 	"time"
 )
@@ -221,6 +222,29 @@ func axfrTestingSuiteWithCustomTsig(t *testing.T, addrstr string, provider TsigP
 	}
 }
 
+func axfrTestingSuiteWithMsgNotSigned(t *testing.T, addrstr string, provider TsigProvider) {
+	tr := new(Transfer)
+	m := new(Msg)
+	var err error
+	tr.Conn, err = Dial("tcp", addrstr)
+	if err != nil {
+		t.Fatal("failed to dial", err)
+	}
+	tr.TsigProvider = provider
+	m.SetAxfr("miek.nl.")
+
+	c, err := tr.In(m, addrstr)
+	if err != nil {
+		t.Fatal("failed to zone transfer in", err)
+	}
+
+	for msg := range c {
+		if !errors.Is(msg.Error, ErrNoSig) {
+			t.Fatal("expecting ErrNoSig error")
+		}
+	}
+}
+
 func TestCustomTsigProvider(t *testing.T) {
 	HandleFunc("miek.nl.", SingleEnvelopeXfrServer)
 	defer HandleRemove("miek.nl.")
@@ -235,3 +259,16 @@ func TestCustomTsigProvider(t *testing.T) {
 
 	axfrTestingSuiteWithCustomTsig(t, addrstr, tsigSecretProvider(tsigSecret))
 }
+
+func TestTSIGNotSigned(t *testing.T) {
+	HandleFunc("miek.nl.", SingleEnvelopeXfrServer)
+	defer HandleRemove("miek.nl.")
+
+	s, addrstr, _, err := RunLocalTCPServer(":0")
+	if err != nil {
+		t.Fatalf("unable to run test server: %s", err)
+	}
+	defer s.Shutdown()
+
+	axfrTestingSuiteWithMsgNotSigned(t, addrstr, tsigSecretProvider(tsigSecret))
+}