diff --git a/defaults.go b/defaults.go index 186d179d..96423cad 100644 --- a/defaults.go +++ b/defaults.go @@ -197,26 +197,29 @@ func (dns *Msg) IsEdns0() (ok bool) { } // IsDomainName checks if s is a valid domainname, it returns -// the number of labels and true, when a domain name is valid. When false -// the returned labelcount isn't specified. -func IsDomainName(s string) (uint8, bool) { // copied from net package. +// the number of labels, total length and true, when a domain name is valid. +// When false the returned labelcount and length is 0 and 0. +func IsDomainName(s string) (uint8, uint8, bool) { // copied from net package. // See RFC 1035, RFC 3696. - if len(s) == 0 { - return 0, false + l := len(s) + if l == 0 || l > 255 { + return 0, 0, false } - if len(s) > 255 { // Not true...? - return 0, false - } - s = Fqdn(s) // simplify checking loop: make name end in dot + // Simplify checking loop: make the name end in a dot + // Don't call Fqdn() to save another len(s) + if s[l-1] != '.' { + s += "." + l++ + } last := byte('.') ok := false // ok once we've seen a letter partlen := 0 labels := uint8(0) - for i := 0; i < len(s); i++ { + for i := 0; i < l; i++ { c := s[i] switch { default: - return 0, false + return 0, uint8(l), false case 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || c == '_' || c == '*': ok = true partlen++ @@ -228,28 +231,27 @@ func IsDomainName(s string) (uint8, bool) { // copied from net package. case c == '-': // byte before dash cannot be dot if last == '.' { - return 0, false + return 0, uint8(l), false } partlen++ case c == '.': // byte before dot cannot be dot, dash if last == '.' || last == '-' { - return 0, false + return 0, uint8(l), false } if last == '\\' { // Ok, escaped dot. partlen++ break } if partlen > 63 || partlen == 0 { - return 0, false + return 0, uint8(l), false } partlen = 0 labels++ } last = c } - - return labels, ok + return labels, uint8(l), ok } // IsFqdn checks if a domain name is fully qualified diff --git a/dnssec.go b/dnssec.go index cf6e597d..f5de155b 100644 --- a/dnssec.go +++ b/dnssec.go @@ -201,7 +201,7 @@ func (s *RR_RRSIG) Sign(k PrivateKey, rrset []RR) error { s.OrigTtl = rrset[0].Header().Ttl s.TypeCovered = rrset[0].Header().Rrtype s.TypeCovered = rrset[0].Header().Rrtype - s.Labels, _ = IsDomainName(rrset[0].Header().Name) + s.Labels, _, _ = IsDomainName(rrset[0].Header().Name) // ... if strings.HasPrefix(rrset[0].Header().Name, "*") { s.Labels-- // wildcard, remove from label count diff --git a/examples/fp/data/q b/examples/fp/data/q index fc14f63d..d14cfe40 100644 --- a/examples/fp/data/q +++ b/examples/fp/data/q @@ -7,15 +7,14 @@ # explain .,CH,TXT,QUERY,NOERROR,qr,aa,tc,RD,ra,ad,cd,z,1,0,0,0,DO,65535,NSID # explain -.,IN,TXT,QUERY,NOERROR,qr,aa,tc,RD,ra,ad,cd,z,1,0,0,0,DO,128,NSID .,IN,TXT,QUERY,NOERROR,qr,aa,tc,RD,ra,ad,cd,z,1,0,0,0,DO,127,NSID # explain .,CH,TXT,UPDATE,NOERROR,qr,AA,tc,RD,ra,ad,cd,z,1,0,0,0,do,0,nsid .,CH,TXT,UPDATE,BADTRUNC,qr,AA,tc,RD,ra,ad,cd,z,1,0,0,0,do,0,nsid # explain .,IN,TXT,IQUERY,NOERROR,qr,AA,tc,RD,ra,ad,cd,z,1,0,0,0,do,0,nsid -.,IN,TXT,QUERY,NOERROR,qr,AA,tc,RD,ra,ad,cd,z,1,0,0,0,DO,128,nsid -.,IN,TXT,QUERY,NOERROR,qr,AA,tc,RD,ra,ad,cd,z,1,0,0,0,DO,128,nsid +.,IN,TXT,QUERY,NOERROR,qr,AA,tc,RD,ra,ad,cd,z,1,0,0,0,DO,768,nsid +.,IN,TXT,QUERY,NOERROR,qr,AA,tc,RD,ra,ad,cd,z,1,0,0,0,DO,801,nsid # explain .,IN,TXT,STATUS,NOERROR,qr,AA,tc,RD,ra,ad,cd,z,1,0,0,0,do,0,nsid # explain diff --git a/zscan.go b/zscan.go index dcf6ba42..e2d82321 100644 --- a/zscan.go +++ b/zscan.go @@ -161,11 +161,12 @@ func parseZone(r io.Reader, f string, t chan Token, include int) { st = _EXPECT_OWNER_DIR case _OWNER: h.Name = l.token - if _, ok := IsDomainName(l.token); !ok { + _, ld, ok := IsDomainName(l.token) + if !ok { t <- Token{Error: &ParseError{f, "bad owner name", l}} return } - if !IsFqdn(h.Name) { + if h.Name[ld-1] != '.' { h.Name += origin } st = _EXPECT_OWNER_BL @@ -378,8 +379,10 @@ func zlexer(s scanner.Scanner, c chan lex) { c <- l return } - switch x := s.TokenText(); x { - case " ", "\t": + // Each token we get is one byte, so we switch on that x[0]. This + // avoids a len(x) that Go otherwise will perform when comparing strings. + switch x := s.TokenText(); x[0] { + case ' ', '\t': escape = false if commt { break @@ -424,7 +427,7 @@ func zlexer(s scanner.Scanner, c chan lex) { } owner = false space = true - case ";": + case ';': if escape { escape = false str[stri] = ';' @@ -438,7 +441,7 @@ func zlexer(s scanner.Scanner, c chan lex) { break } commt = true - case "\n": + case '\n': // Hmmm, escape newline escape = false if commt { @@ -485,7 +488,7 @@ func zlexer(s scanner.Scanner, c chan lex) { commt = false rrtype = false owner = true - case "\\": + case '\\': if commt { break } @@ -498,7 +501,7 @@ func zlexer(s scanner.Scanner, c chan lex) { str[stri] = '\\' stri++ escape = true - case "\"": + case '"': if commt { break } @@ -510,7 +513,7 @@ func zlexer(s scanner.Scanner, c chan lex) { } // str += "\"" don't add quoted quotes quote = !quote - case "(": + case '(': if commt { break } @@ -521,7 +524,7 @@ func zlexer(s scanner.Scanner, c chan lex) { break } brace++ - case ")": + case ')': if commt { break } diff --git a/zscan_rr.go b/zscan_rr.go index d84d4aaa..15be50fb 100644 --- a/zscan_rr.go +++ b/zscan_rr.go @@ -123,10 +123,11 @@ func setNS(h RR_Header, c chan lex, o, f string) (RR, *ParseError) { l := <-c rr.Ns = l.token - if _, ok := IsDomainName(l.token); !ok { + _, ld, ok := IsDomainName(l.token) + if !ok { return nil, &ParseError{f, "bad NS Ns", l} } - if !IsFqdn(rr.Ns) { + if rr.Ns[ld-1]!= '.' { rr.Ns += o } return rr, nil @@ -145,10 +146,11 @@ func setMX(h RR_Header, c chan lex, o, f string) (RR, *ParseError) { <-c // _BLANK l = <-c // _STRING rr.Mx = l.token - if _, ok := IsDomainName(l.token); !ok { + _, ld, ok := IsDomainName(l.token) + if !ok { return nil, &ParseError{f, "bad MX Mx", l} } - if !IsFqdn(rr.Mx) { + if rr.Mx[ld-1] != '.' { rr.Mx += o } return rr, nil @@ -160,10 +162,11 @@ func setCNAME(h RR_Header, c chan lex, o, f string) (RR, *ParseError) { l := <-c rr.Cname = l.token - if _, ok := IsDomainName(l.token); !ok { + _, ld, ok := IsDomainName(l.token) + if !ok { return nil, &ParseError{f, "bad CNAME", l} } - if !IsFqdn(rr.Cname) { + if rr.Cname[ld-1] != '.' { rr.Cname += o } return rr, nil @@ -176,19 +179,21 @@ func setSOA(h RR_Header, c chan lex, o, f string) (RR, *ParseError) { l := <-c rr.Ns = l.token <-c // _BLANK - if _, ok := IsDomainName(l.token); !ok { + _, ld, ok := IsDomainName(l.token) + if !ok { return nil, &ParseError{f, "bad SOA mname", l} } - if !IsFqdn(rr.Ns) { + if rr.Ns[ld-1] != '.' { rr.Ns += o } l = <-c rr.Mbox = l.token - if _, ok := IsDomainName(l.token); !ok { + _, ld, ok = IsDomainName(l.token) + if !ok { return nil, &ParseError{f, "bad SOA rname", l} } - if !IsFqdn(rr.Mbox) { + if rr.Mbox[ld-1]!='.' { rr.Mbox += o } <-c // _BLANK @@ -274,10 +279,11 @@ func setRRSIG(h RR_Header, c chan lex, o, f string) (RR, *ParseError) { <-c // _BLANK l = <-c rr.SignerName = l.token - if _, ok := IsDomainName(l.token); !ok { + _, ld, ok := IsDomainName(l.token) + if !ok { return nil, &ParseError{f, "bad RRSIG signername", l} } - if !IsFqdn(rr.SignerName) { + if rr.SignerName[ld-1] != '.' { rr.SignerName += o } // Get the remaining data until we see a NEWLINE @@ -304,10 +310,11 @@ func setNSEC(h RR_Header, c chan lex, o, f string) (RR, *ParseError) { l := <-c rr.NextDomain = l.token - if _, ok := IsDomainName(l.token); !ok { + _, ld, ok := IsDomainName(l.token) + if !ok { return nil, &ParseError{f, "bad NSEC nextdomain", l} } - if !IsFqdn(rr.NextDomain) { + if rr.NextDomain[ld-1] != '.' { rr.NextDomain += o } @@ -364,10 +371,11 @@ func setNSEC3(h RR_Header, c chan lex, o, f string) (RR, *ParseError) { l = <-c rr.HashLength = uint8(len(l.token)) rr.NextDomain = l.token - if _, ok := IsDomainName(l.token); !ok { + _, ld, ok := IsDomainName(l.token) + if !ok { return nil, &ParseError{f, "bad NSEC nextdomain", l} } - if !IsFqdn(rr.NextDomain) { + if rr.NextDomain[ld-1] != '.' { rr.NextDomain += o }