From 47cc5b052df9b4e5d5a9900cfdd622607de10a6d Mon Sep 17 00:00:00 2001 From: Miek Gieben Date: Tue, 10 Sep 2013 13:13:10 +0000 Subject: [PATCH] Work on making IsDomainName better --- defaults.go | 92 +++++++++++++++----------------------------- dnssec.go | 3 +- zscan.go | 33 ++++++++++------ zscan_rr.go | 109 ++++++++++++++++++++++++++-------------------------- 4 files changed, 107 insertions(+), 130 deletions(-) diff --git a/defaults.go b/defaults.go index 0b772505..0736e4b5 100644 --- a/defaults.go +++ b/defaults.go @@ -156,76 +156,44 @@ func (dns *Msg) IsEdns0() *OPT { } // IsDomainName checks if s is a valid domainname, it returns -// the number of labels, total length and true, when a domain name is valid. -// Note that unfully qualified domain name is considered valid, in this case the +// the number of labels and true, when a domain name is valid. +// Note that non fully qualified domain name is considered valid, in this case the // last label is counted in the number of labels. -// When false is returned the labelcount and length are not defined. -func IsDomainName(s string) (uint8, uint8, bool) { // copied from net package. - // See RFC 1035, RFC 3696. - l := len(s) - if l == 0 || l > 255 { - return 0, 0, false +// When false is returned the number of labels is not defined. +func IsDomainName(s string) (int, bool) { + // use PackDomainName + if buf == nil { + buf = make([]byte, 256) } - // Preloop check for root label - if s == "." { - return 0, 1, true + lenmsg, err := PackDomainName(s, buf, 0, nil, false) + if err != nil { + return 0, false } - - last := byte('.') - ok := false // Ok once we've seen a letter or digit. - partlen := 0 - labels := uint8(0) - var c byte - for i := 0; i < l; i++ { - c = s[i] - switch { - default: - // anything escaped is legal - if last != '\\' { - return 0, uint8(l), false - } - partlen++ - case 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || c == '_' || c == '*' || c == '/': - ok = true - partlen++ - case c == '\\': // OK. - case c == '@': - if last != '\\' { - return 0, uint8(l), false - } - partlen++ - case '0' <= c && c <= '9': - ok = true - partlen++ - case c == '-': - if last == '.' { - return 0, uint8(l), false - } - partlen++ - case c == '.': - // byte before dot cannot be dot - if last == '.' { - return 0, uint8(l), false - } - if last == '\\' { // Ok, escaped dot. - partlen++ - c = 'A' // Make current value not scary. + // There are no compression pointers, because the map was nil, so + // walk the binary name and count the length bits - this is the number + // of labels. + off := 0 + labels := 0 +Loop: + for { + if off >= lenmsg { + return labels, false + } + c := int(buf[off]) + switch c & 0xC0 { + case 0x00: + if c == 0x00 { + // end of name break } - if partlen > 63 || partlen == 0 { - return 0, uint8(l), false + if off+c > lenmsg { + return labels, false } - partlen = 0 labels++ + off += c } - last = c } - // If last isn't a dot, the name was unqualified, but we still want to count - // the last label. - if last == '.' { - return labels, uint8(l), ok - } - return labels + 1, uint8(l), ok + return labels, true } // IsSubDomain checks if child is indeed a child of the parent. Both child and @@ -253,7 +221,7 @@ func Fqdn(s string) string { return s + "." } -// Copied from the official Go code +// Copied from the official Go code. // ReverseAddr returns the in-addr.arpa. or ip6.arpa. hostname of the IP // address addr suitable for rDNS (PTR) record lookup or an error if it fails diff --git a/dnssec.go b/dnssec.go index cde778a7..af28ea17 100644 --- a/dnssec.go +++ b/dnssec.go @@ -222,7 +222,8 @@ func (rr *RRSIG) Sign(k PrivateKey, rrset []RR) error { rr.OrigTtl = rrset[0].Header().Ttl rr.TypeCovered = rrset[0].Header().Rrtype rr.TypeCovered = rrset[0].Header().Rrtype - rr.Labels, _, _ = IsDomainName(rrset[0].Header().Name) + x := CountLabel(rrset[0].Header().Name) + rr.Labels = uint8(x) if strings.HasPrefix(rrset[0].Header().Name, "*") { rr.Labels-- // wildcard, remove from label count diff --git a/zscan.go b/zscan.go index 6a6bdbc4..102bcefc 100644 --- a/zscan.go +++ b/zscan.go @@ -88,6 +88,7 @@ func (e *ParseError) Error() (s string) { type lex struct { token string // text of the token + length int // lenght of the token err bool // when true, token text has lexer error value uint8 // value: _STRING, _BLANK, etc. line int // line in the file @@ -179,11 +180,11 @@ func parseZone(r io.Reader, origin, f string, t chan Token, include int) { if origin == "" { origin = "." } - if _, _, ok := IsDomainName(origin); !ok { + origin = Fqdn(origin) + if _, ok := IsDomainName(origin); !ok { t <- Token{Error: &ParseError{f, "bad initial origin name", lex{}}} return } - origin = Fqdn(origin) st := _EXPECT_OWNER_DIR // initial state var h RR_Header @@ -212,14 +213,14 @@ func parseZone(r io.Reader, origin, f string, t chan Token, include int) { st = _EXPECT_OWNER_BL break } - _, ld, ok := IsDomainName(l.token) + if h.Name[l.length-1] != '.' { + h.Name = appendOrigin(h.Name, origin) + } + _, ok := IsDomainName(l.token) if !ok { t <- Token{Error: &ParseError{f, "bad owner name", l}} return } - if h.Name[ld-1] != '.' { - h.Name = appendOrigin(h.Name, origin) - } prevName = h.Name st = _EXPECT_OWNER_BL case _DIRTTL: @@ -273,12 +274,12 @@ func parseZone(r io.Reader, origin, f string, t chan Token, include int) { case _BLANK: l := <-c if l.value == _STRING { - if _, _, ok := IsDomainName(l.token); !ok { + if _, ok := IsDomainName(l.token); !ok { t <- Token{Error: &ParseError{f, "bad origin name", l}} return } // a new origin is specified. - if !IsFqdn(l.token) { + if l.token[l.length-1] != '.' { if origin != "." { // Prevent .. endings neworigin = l.token + "." + origin } else { @@ -342,11 +343,11 @@ func parseZone(r io.Reader, origin, f string, t chan Token, include int) { if e, _ := slurpRemainder(c, f); e != nil { t <- Token{Error: e} } - if _, _, ok := IsDomainName(l.token); !ok { + if _, ok := IsDomainName(l.token); !ok { t <- Token{Error: &ParseError{f, "bad origin name", l}} return } - if !IsFqdn(l.token) { + if l.token[l.length-1] != '.' { if origin != "." { // Prevent .. endings origin = l.token + "." + origin } else { @@ -527,6 +528,7 @@ func zlexer(s *scan, c chan lex) { // If we have a string and its the first, make it an owner l.value = _OWNER l.token = string(str[:stri]) + l.length = stri // escape $... start with a \ not a $, so this will work switch l.token { case "$TTL": @@ -543,7 +545,7 @@ func zlexer(s *scan, c chan lex) { } else { l.value = _STRING l.token = string(str[:stri]) - + l.length = stri if !rrtype { if t, ok := StringToType[l.token]; ok { l.value = _RRTYPE @@ -589,6 +591,7 @@ func zlexer(s *scan, c chan lex) { if !space && !commt { l.value = _BLANK l.token = " " + l.length = 1 debug.Printf("[5 %+v]", l.token) c <- l } @@ -610,6 +613,7 @@ func zlexer(s *scan, c chan lex) { if stri > 0 { l.value = _STRING l.token = string(str[:stri]) + l.length = stri debug.Printf("[4 %+v]", l.token) c <- l stri = 0 @@ -640,6 +644,7 @@ func zlexer(s *scan, c chan lex) { owner = true l.value = _NEWLINE l.token = "\n" + l.length = 1 l.comment = string(com[:comi]) debug.Printf("[3 %+v %+v]", l.token, l.comment) c <- l @@ -657,6 +662,7 @@ func zlexer(s *scan, c chan lex) { if stri != 0 { l.value = _STRING l.token = string(str[:stri]) + l.length = stri if !rrtype { if t, ok := StringToType[strings.ToUpper(l.token)]; ok { l.value = _RRTYPE @@ -669,6 +675,7 @@ func zlexer(s *scan, c chan lex) { } l.value = _NEWLINE l.token = "\n" + l.length = 1 debug.Printf("[1 %+v]", l.token) c <- l stri = 0 @@ -710,12 +717,14 @@ func zlexer(s *scan, c chan lex) { if stri != 0 { l.value = _STRING l.token = string(str[:stri]) + l.length = stri debug.Printf("[%+v]", l.token) c <- l stri = 0 } l.value = _QUOTE l.token = "\"" + l.length = 1 c <- l quote = !quote case '(', ')': @@ -761,10 +770,10 @@ func zlexer(s *scan, c chan lex) { } x, err = s.tokenText() } - // Hmm. if stri > 0 { // Send remainder l.token = string(str[:stri]) + l.length = stri l.value = _STRING debug.Printf("[%+v]", l.token) c <- l diff --git a/zscan_rr.go b/zscan_rr.go index db4068b5..4fd9b3ef 100644 --- a/zscan_rr.go +++ b/zscan_rr.go @@ -271,11 +271,11 @@ func setNS(h RR_Header, c chan lex, o, f string) (RR, *ParseError) { rr.Ns = o return rr, nil } - _, ld, ok := IsDomainName(l.token) + _, ok := IsDomainName(l.token) if !ok { return nil, &ParseError{f, "bad NS Ns", l} } - if rr.Ns[ld-1] != '.' { + if rr.Ns[l.length-1] != '.' { rr.Ns = appendOrigin(rr.Ns, o) } return rr, nil @@ -291,11 +291,11 @@ func setPTR(h RR_Header, c chan lex, o, f string) (RR, *ParseError) { rr.Ptr = o return rr, nil } - _, ld, ok := IsDomainName(l.token) + _, ok := IsDomainName(l.token) if !ok { return nil, &ParseError{f, "bad PTR Ptr", l} } - if rr.Ptr[ld-1] != '.' { + if rr.Ptr[l.length-1] != '.' { rr.Ptr = appendOrigin(rr.Ptr, o) } return rr, nil @@ -310,11 +310,11 @@ func setRP(h RR_Header, c chan lex, o, f string) (RR, *ParseError) { if l.token == "@" { rr.Mbox = o } else { - _, ld, ok := IsDomainName(l.token) + _, ok := IsDomainName(l.token) if !ok { return nil, &ParseError{f, "bad RP Mbox", l} } - if rr.Mbox[ld-1] != '.' { + if rr.Mbox[l.length-1] != '.' { rr.Mbox = appendOrigin(rr.Mbox, o) } } @@ -325,14 +325,13 @@ func setRP(h RR_Header, c chan lex, o, f string) (RR, *ParseError) { rr.Txt = o return rr, nil } - _, ld, ok := IsDomainName(l.token) + _, ok := IsDomainName(l.token) if !ok { return nil, &ParseError{f, "bad RP Txt", l} } - if rr.Txt[ld-1] != '.' { + if rr.Txt[l.length-1] != '.' { rr.Txt = appendOrigin(rr.Txt, o) } - return rr, nil } @@ -346,11 +345,11 @@ func setMR(h RR_Header, c chan lex, o, f string) (RR, *ParseError) { rr.Mr = o return rr, nil } - _, ld, ok := IsDomainName(l.token) + _, ok := IsDomainName(l.token) if !ok { return nil, &ParseError{f, "bad MR Mr", l} } - if rr.Mr[ld-1] != '.' { + if rr.Mr[l.length-1] != '.' { rr.Mr = appendOrigin(rr.Mr, o) } return rr, nil @@ -366,11 +365,11 @@ func setMB(h RR_Header, c chan lex, o, f string) (RR, *ParseError) { rr.Mb = o return rr, nil } - _, ld, ok := IsDomainName(l.token) + _, ok := IsDomainName(l.token) if !ok { return nil, &ParseError{f, "bad MB Mb", l} } - if rr.Mb[ld-1] != '.' { + if rr.Mb[l.length-1] != '.' { rr.Mb = appendOrigin(rr.Mb, o) } return rr, nil @@ -386,11 +385,11 @@ func setMG(h RR_Header, c chan lex, o, f string) (RR, *ParseError) { rr.Mg = o return rr, nil } - _, ld, ok := IsDomainName(l.token) + _, ok := IsDomainName(l.token) if !ok { return nil, &ParseError{f, "bad MG Mg", l} } - if rr.Mg[ld-1] != '.' { + if rr.Mg[l.length-1] != '.' { rr.Mg = appendOrigin(rr.Mg, o) } return rr, nil @@ -418,11 +417,11 @@ func setMINFO(h RR_Header, c chan lex, o, f string) (RR, *ParseError) { if l.token == "@" { rr.Rmail = o } else { - _, ld, ok := IsDomainName(l.token) + _, ok := IsDomainName(l.token) if !ok { return nil, &ParseError{f, "bad MINFO Rmail", l} } - if rr.Rmail[ld-1] != '.' { + if rr.Rmail[l.length-1] != '.' { rr.Rmail = appendOrigin(rr.Rmail, o) } } @@ -433,11 +432,11 @@ func setMINFO(h RR_Header, c chan lex, o, f string) (RR, *ParseError) { rr.Email = o return rr, nil } - _, ld, ok := IsDomainName(l.token) + _, ok := IsDomainName(l.token) if !ok { return nil, &ParseError{f, "bad MINFO Email", l} } - if rr.Email[ld-1] != '.' { + if rr.Email[l.length-1] != '.' { rr.Email = appendOrigin(rr.Email, o) } return rr, nil @@ -453,11 +452,11 @@ func setMF(h RR_Header, c chan lex, o, f string) (RR, *ParseError) { rr.Mf = o return rr, nil } - _, ld, ok := IsDomainName(l.token) + _, ok := IsDomainName(l.token) if !ok { return nil, &ParseError{f, "bad MF Mf", l} } - if rr.Mf[ld-1] != '.' { + if rr.Mf[l.length-1] != '.' { rr.Mf = appendOrigin(rr.Mf, o) } return rr, nil @@ -473,11 +472,11 @@ func setMD(h RR_Header, c chan lex, o, f string) (RR, *ParseError) { rr.Md = o return rr, nil } - _, ld, ok := IsDomainName(l.token) + _, ok := IsDomainName(l.token) if !ok { return nil, &ParseError{f, "bad MD Md", l} } - if rr.Md[ld-1] != '.' { + if rr.Md[l.length-1] != '.' { rr.Md = appendOrigin(rr.Md, o) } return rr, nil @@ -500,11 +499,11 @@ func setMX(h RR_Header, c chan lex, o, f string) (RR, *ParseError) { rr.Mx = o return rr, nil } - _, ld, ok := IsDomainName(l.token) + _, ok := IsDomainName(l.token) if !ok { return nil, &ParseError{f, "bad MX Mx", l} } - if rr.Mx[ld-1] != '.' { + if rr.Mx[l.length-1] != '.' { rr.Mx = appendOrigin(rr.Mx, o) } return rr, nil @@ -527,11 +526,11 @@ func setRT(h RR_Header, c chan lex, o, f string) (RR, *ParseError) { rr.Host = o return rr, nil } - _, ld, ok := IsDomainName(l.token) + _, ok := IsDomainName(l.token) if !ok { return nil, &ParseError{f, "bad RT Host", l} } - if rr.Host[ld-1] != '.' { + if rr.Host[l.length-1] != '.' { rr.Host = appendOrigin(rr.Host, o) } return rr, nil @@ -554,11 +553,11 @@ func setAFSDB(h RR_Header, c chan lex, o, f string) (RR, *ParseError) { rr.Hostname = o return rr, nil } - _, ld, ok := IsDomainName(l.token) + _, ok := IsDomainName(l.token) if !ok { return nil, &ParseError{f, "bad AFSDB Hostname", l} } - if rr.Hostname[ld-1] != '.' { + if rr.Hostname[l.length-1] != '.' { rr.Hostname = appendOrigin(rr.Hostname, o) } return rr, nil @@ -590,11 +589,11 @@ func setKX(h RR_Header, c chan lex, o, f string) (RR, *ParseError) { rr.Exchanger = o return rr, nil } - _, ld, ok := IsDomainName(l.token) + _, ok := IsDomainName(l.token) if !ok { return nil, &ParseError{f, "bad KX Exchanger", l} } - if rr.Exchanger[ld-1] != '.' { + if rr.Exchanger[l.length-1] != '.' { rr.Exchanger = appendOrigin(rr.Exchanger, o) } return rr, nil @@ -610,11 +609,11 @@ func setCNAME(h RR_Header, c chan lex, o, f string) (RR, *ParseError) { rr.Target = o return rr, nil } - _, ld, ok := IsDomainName(l.token) + _, ok := IsDomainName(l.token) if !ok { return nil, &ParseError{f, "bad CNAME Target", l} } - if rr.Target[ld-1] != '.' { + if rr.Target[l.length-1] != '.' { rr.Target = appendOrigin(rr.Target, o) } return rr, nil @@ -630,11 +629,11 @@ func setDNAME(h RR_Header, c chan lex, o, f string) (RR, *ParseError) { rr.Target = o return rr, nil } - _, ld, ok := IsDomainName(l.token) + _, ok := IsDomainName(l.token) if !ok { return nil, &ParseError{f, "bad CNAME Target", l} } - if rr.Target[ld-1] != '.' { + if rr.Target[l.length-1] != '.' { rr.Target = appendOrigin(rr.Target, o) } return rr, nil @@ -650,11 +649,11 @@ func setSOA(h RR_Header, c chan lex, o, f string) (RR, *ParseError) { if l.token == "@" { rr.Ns = o } else { - _, ld, ok := IsDomainName(l.token) + _, ok := IsDomainName(l.token) if !ok { return nil, &ParseError{f, "bad SOA Ns", l} } - if rr.Ns[ld-1] != '.' { + if rr.Ns[l.length-1] != '.' { rr.Ns = appendOrigin(rr.Ns, o) } } @@ -664,11 +663,11 @@ func setSOA(h RR_Header, c chan lex, o, f string) (RR, *ParseError) { if l.token == "@" { rr.Mbox = o } else { - _, ld, ok := IsDomainName(l.token) + _, ok := IsDomainName(l.token) if !ok { return nil, &ParseError{f, "bad SOA Mbox", l} } - if rr.Mbox[ld-1] != '.' { + if rr.Mbox[l.length-1] != '.' { rr.Mbox = appendOrigin(rr.Mbox, o) } } @@ -743,11 +742,11 @@ func setSRV(h RR_Header, c chan lex, o, f string) (RR, *ParseError) { rr.Target = o return rr, nil } - _, ld, ok := IsDomainName(l.token) + _, ok := IsDomainName(l.token) if !ok { return nil, &ParseError{f, "bad SRV Target", l} } - if rr.Target[ld-1] != '.' { + if rr.Target[l.length-1] != '.' { rr.Target = appendOrigin(rr.Target, o) } return rr, nil @@ -834,11 +833,11 @@ func setNAPTR(h RR_Header, c chan lex, o, f string) (RR, *ParseError) { rr.Replacement = o return rr, nil } - _, ld, ok := IsDomainName(l.token) + _, ok := IsDomainName(l.token) if !ok { return nil, &ParseError{f, "bad NAPTR Replacement", l} } - if rr.Replacement[ld-1] != '.' { + if rr.Replacement[l.length-1] != '.' { rr.Replacement = appendOrigin(rr.Replacement, o) } return rr, nil @@ -853,11 +852,11 @@ func setTALINK(h RR_Header, c chan lex, o, f string) (RR, *ParseError) { if l.token == "@" { rr.PreviousName = o } else { - _, ld, ok := IsDomainName(l.token) + _, ok := IsDomainName(l.token) if !ok { return nil, &ParseError{f, "bad TALINK PreviousName", l} } - if rr.PreviousName[ld-1] != '.' { + if rr.PreviousName[l.length-1] != '.' { rr.PreviousName = appendOrigin(rr.PreviousName, o) } } @@ -868,11 +867,11 @@ func setTALINK(h RR_Header, c chan lex, o, f string) (RR, *ParseError) { rr.NextName = o return rr, nil } - _, ld, ok := IsDomainName(l.token) + _, ok := IsDomainName(l.token) if !ok { return nil, &ParseError{f, "bad TALINK NextName", l} } - if rr.NextName[ld-1] != '.' { + if rr.NextName[l.length-1] != '.' { rr.NextName = appendOrigin(rr.NextName, o) } return rr, nil @@ -1036,11 +1035,11 @@ func setHIP(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { xs = append(xs, o) continue } - _, ld, ok := IsDomainName(l.token) + _, ok := IsDomainName(l.token) if !ok { return nil, &ParseError{f, "bad HIP RendezvousServers", l}, "" } - if l.token[ld-1] != '.' { + if l.token[l.length-1] != '.' { l.token = appendOrigin(l.token, o) } xs = append(xs, l.token) @@ -1144,11 +1143,11 @@ func setRRSIG(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { if l.token == "@" { rr.SignerName = o } else { - _, ld, ok := IsDomainName(l.token) + _, ok := IsDomainName(l.token) if !ok { return nil, &ParseError{f, "bad RRSIG SignerName", l}, "" } - if rr.SignerName[ld-1] != '.' { + if rr.SignerName[l.length-1] != '.' { rr.SignerName = appendOrigin(rr.SignerName, o) } } @@ -1169,11 +1168,11 @@ func setNSEC(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { if l.token == "@" { rr.NextDomain = o } else { - _, ld, ok := IsDomainName(l.token) + _, ok := IsDomainName(l.token) if !ok { return nil, &ParseError{f, "bad NSEC NextDomain", l}, "" } - if rr.NextDomain[ld-1] != '.' { + if rr.NextDomain[l.length-1] != '.' { rr.NextDomain = appendOrigin(rr.NextDomain, o) } } @@ -1861,11 +1860,11 @@ func setLP(h RR_Header, c chan lex, o, f string) (RR, *ParseError) { rr.Fqdn = o return rr, nil } - _, ld, ok := IsDomainName(l.token) + _, ok := IsDomainName(l.token) if !ok { return nil, &ParseError{f, "bad LP Fqdn", l} } - if rr.Fqdn[ld-1] != '.' { + if rr.Fqdn[l.length-1] != '.' { rr.Fqdn = appendOrigin(rr.Fqdn, o) } return rr, nil