Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/master' into phillip/sync-miekg-2
Browse files Browse the repository at this point in the history
  • Loading branch information
phillip-stephens committed Feb 11, 2025
2 parents a7b8ec7 + 97c29ff commit 172bb3a
Show file tree
Hide file tree
Showing 10 changed files with 293 additions and 27 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ A not-so-up-to-date-list-that-may-be-actually-current:
* https://github.com/wintbiit/NineDNS
* https://linuxcontainers.org/incus/
* https://ifconfig.es
* https://github.com/zmap/zdns


Send pull request if you want to be listed here.
Expand Down
42 changes: 29 additions & 13 deletions dnssec.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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
}
Expand All @@ -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
}

Expand All @@ -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)
Expand Down
111 changes: 111 additions & 0 deletions dnssec_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand Down
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ go 1.19

require (
github.com/miekg/dns v1.1.62
golang.org/x/net v0.28.0
golang.org/x/net v0.31.0
golang.org/x/sync v0.7.0
golang.org/x/sys v0.23.0
golang.org/x/sys v0.27.0
golang.org/x/tools v0.22.0
)

Expand Down
8 changes: 4 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0=
golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo=
golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM=
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM=
golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s=
golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA=
golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c=
22 changes: 18 additions & 4 deletions listen_no_reuseport.go → listen_no_socket_options.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -15,12 +21,20 @@ 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?
}

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")
}
31 changes: 31 additions & 0 deletions listen_reuseport.go → listen_socket_options.go
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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:
Expand Down
Loading

0 comments on commit 172bb3a

Please sign in to comment.