From 524a80c35d2ae989abc2f94d5f034c5c0262162b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20V=C4=8Del=C3=A1k?= Date: Wed, 18 Mar 2020 11:21:59 +0100 Subject: [PATCH] CanonicalName function to return domain name in canonical form (#1073) * add Canonical function to get name in canonical form * replace strings.ToLower with Canonical * rename Canonical to CanonicalName * replace Fqdn with CanonicalName in ServeMux --- defaults.go | 6 ++++++ dnssec.go | 56 +++++++++++++++++++++++++------------------------- labels_test.go | 16 +++++++++++++++ serve_mux.go | 7 +++---- tsig.go | 8 ++++---- 5 files changed, 57 insertions(+), 36 deletions(-) diff --git a/defaults.go b/defaults.go index 8add6ab1..d874e300 100644 --- a/defaults.go +++ b/defaults.go @@ -317,6 +317,12 @@ func Fqdn(s string) string { return s + "." } +// CanonicalName returns the domain name in canonical form. A name in canonical +// form is lowercase and fully qualified. See Section 6.2 in RFC 4034. +func CanonicalName(s string) string { + return strings.ToLower(Fqdn(s)) +} + // Copied from the official Go code. // ReverseAddr returns the in-addr.arpa. or ip6.arpa. hostname of the IP diff --git a/dnssec.go b/dnssec.go index 12a693f9..68c0bd74 100644 --- a/dnssec.go +++ b/dnssec.go @@ -200,7 +200,7 @@ func (k *DNSKEY) ToDS(h uint8) *DS { wire = wire[:n] owner := make([]byte, 255) - off, err1 := PackDomainName(strings.ToLower(k.Hdr.Name), owner, 0, nil, false) + off, err1 := PackDomainName(CanonicalName(k.Hdr.Name), owner, 0, nil, false) if err1 != nil { return nil } @@ -285,7 +285,7 @@ func (rr *RRSIG) Sign(k crypto.Signer, rrset []RR) error { sigwire.Inception = rr.Inception sigwire.KeyTag = rr.KeyTag // For signing, lowercase this name - sigwire.SignerName = strings.ToLower(rr.SignerName) + sigwire.SignerName = CanonicalName(rr.SignerName) // Create the desired binary blob signdata := make([]byte, DefaultMsgSize) @@ -423,7 +423,7 @@ func (rr *RRSIG) Verify(k *DNSKEY, rrset []RR) error { sigwire.Expiration = rr.Expiration sigwire.Inception = rr.Inception sigwire.KeyTag = rr.KeyTag - sigwire.SignerName = strings.ToLower(rr.SignerName) + sigwire.SignerName = CanonicalName(rr.SignerName) // Create the desired binary blob signeddata := make([]byte, DefaultMsgSize) n, err := packSigWire(sigwire, signeddata) @@ -659,7 +659,7 @@ func rawSignatureData(rrset []RR, s *RRSIG) (buf []byte, err error) { h.Name = "*." + strings.Join(labels[len(labels)-int(s.Labels):], ".") + "." } // RFC 4034: 6.2. Canonical RR Form. (2) - domain name to lowercase - h.Name = strings.ToLower(h.Name) + h.Name = CanonicalName(h.Name) // 6.2. Canonical RR Form. (3) - domain rdata to lowercase. // NS, MD, MF, CNAME, SOA, MB, MG, MR, PTR, // HINFO, MINFO, MX, RP, AFSDB, RT, SIG, PX, NXT, NAPTR, KX, @@ -672,49 +672,49 @@ func rawSignatureData(rrset []RR, s *RRSIG) (buf []byte, err error) { // conversion. switch x := r1.(type) { case *NS: - x.Ns = strings.ToLower(x.Ns) + x.Ns = CanonicalName(x.Ns) case *MD: - x.Md = strings.ToLower(x.Md) + x.Md = CanonicalName(x.Md) case *MF: - x.Mf = strings.ToLower(x.Mf) + x.Mf = CanonicalName(x.Mf) case *CNAME: - x.Target = strings.ToLower(x.Target) + x.Target = CanonicalName(x.Target) case *SOA: - x.Ns = strings.ToLower(x.Ns) - x.Mbox = strings.ToLower(x.Mbox) + x.Ns = CanonicalName(x.Ns) + x.Mbox = CanonicalName(x.Mbox) case *MB: - x.Mb = strings.ToLower(x.Mb) + x.Mb = CanonicalName(x.Mb) case *MG: - x.Mg = strings.ToLower(x.Mg) + x.Mg = CanonicalName(x.Mg) case *MR: - x.Mr = strings.ToLower(x.Mr) + x.Mr = CanonicalName(x.Mr) case *PTR: - x.Ptr = strings.ToLower(x.Ptr) + x.Ptr = CanonicalName(x.Ptr) case *MINFO: - x.Rmail = strings.ToLower(x.Rmail) - x.Email = strings.ToLower(x.Email) + x.Rmail = CanonicalName(x.Rmail) + x.Email = CanonicalName(x.Email) case *MX: - x.Mx = strings.ToLower(x.Mx) + x.Mx = CanonicalName(x.Mx) case *RP: - x.Mbox = strings.ToLower(x.Mbox) - x.Txt = strings.ToLower(x.Txt) + x.Mbox = CanonicalName(x.Mbox) + x.Txt = CanonicalName(x.Txt) case *AFSDB: - x.Hostname = strings.ToLower(x.Hostname) + x.Hostname = CanonicalName(x.Hostname) case *RT: - x.Host = strings.ToLower(x.Host) + x.Host = CanonicalName(x.Host) case *SIG: - x.SignerName = strings.ToLower(x.SignerName) + x.SignerName = CanonicalName(x.SignerName) case *PX: - x.Map822 = strings.ToLower(x.Map822) - x.Mapx400 = strings.ToLower(x.Mapx400) + x.Map822 = CanonicalName(x.Map822) + x.Mapx400 = CanonicalName(x.Mapx400) case *NAPTR: - x.Replacement = strings.ToLower(x.Replacement) + x.Replacement = CanonicalName(x.Replacement) case *KX: - x.Exchanger = strings.ToLower(x.Exchanger) + x.Exchanger = CanonicalName(x.Exchanger) case *SRV: - x.Target = strings.ToLower(x.Target) + x.Target = CanonicalName(x.Target) case *DNAME: - x.Target = strings.ToLower(x.Target) + x.Target = CanonicalName(x.Target) } // 6.2. Canonical RR Form. (5) - origTTL wire := make([]byte, Len(r1)+1) // +1 to be safe(r) diff --git a/labels_test.go b/labels_test.go index ee7621b3..a355ce24 100644 --- a/labels_test.go +++ b/labels_test.go @@ -231,6 +231,22 @@ func TestIsFqdnEscaped(t *testing.T) { } } +func TestCanonicalName(t *testing.T) { + for s, expect := range map[string]string{ + "": ".", + ".": ".", + "tld": "tld.", + "tld.": "tld.", + "example.test": "example.test.", + "Lower.CASE.test.": "lower.case.test.", + "*.Test": "*.test.", + } { + if got := CanonicalName(s); got != expect { + t.Errorf("CanonicalName(%q) = %q, expected %q", s, got, expect) + } + } +} + func BenchmarkSplitLabels(b *testing.B) { for i := 0; i < b.N; i++ { Split("www.example.com.") diff --git a/serve_mux.go b/serve_mux.go index 69deb33e..aadb0bf0 100644 --- a/serve_mux.go +++ b/serve_mux.go @@ -1,7 +1,6 @@ package dns import ( - "strings" "sync" ) @@ -36,7 +35,7 @@ func (mux *ServeMux) match(q string, t uint16) Handler { return nil } - q = strings.ToLower(q) + q = CanonicalName(q) var handler Handler for off, end := 0, false; !end; off, end = NextLabel(q, off) { @@ -66,7 +65,7 @@ func (mux *ServeMux) Handle(pattern string, handler Handler) { if mux.z == nil { mux.z = make(map[string]Handler) } - mux.z[Fqdn(pattern)] = handler + mux.z[CanonicalName(pattern)] = handler mux.m.Unlock() } @@ -81,7 +80,7 @@ func (mux *ServeMux) HandleRemove(pattern string) { panic("dns: invalid pattern " + pattern) } mux.m.Lock() - delete(mux.z, Fqdn(pattern)) + delete(mux.z, CanonicalName(pattern)) mux.m.Unlock() } diff --git a/tsig.go b/tsig.go index 61efa248..9451f1a8 100644 --- a/tsig.go +++ b/tsig.go @@ -115,7 +115,7 @@ func TsigGenerate(m *Msg, secret, requestMAC string, timersOnly bool) ([]byte, s t := new(TSIG) var h hash.Hash - switch strings.ToLower(rr.Algorithm) { + switch CanonicalName(rr.Algorithm) { case HmacMD5: h = hmac.New(md5.New, rawsecret) case HmacSHA1: @@ -182,7 +182,7 @@ func TsigVerify(msg []byte, secret, requestMAC string, timersOnly bool) error { } var h hash.Hash - switch strings.ToLower(tsig.Algorithm) { + switch CanonicalName(tsig.Algorithm) { case HmacMD5: h = hmac.New(md5.New, rawsecret) case HmacSHA1: @@ -232,10 +232,10 @@ func tsigBuffer(msgbuf []byte, rr *TSIG, requestMAC string, timersOnly bool) []b tsigvar = tsigvar[:n] } else { tsig := new(tsigWireFmt) - tsig.Name = strings.ToLower(rr.Hdr.Name) + tsig.Name = CanonicalName(rr.Hdr.Name) tsig.Class = ClassANY tsig.Ttl = rr.Hdr.Ttl - tsig.Algorithm = strings.ToLower(rr.Algorithm) + tsig.Algorithm = CanonicalName(rr.Algorithm) tsig.TimeSigned = rr.TimeSigned tsig.Fudge = rr.Fudge tsig.Error = rr.Error