Fix origin handling and fix lines which start with ownernames

Zonefile handling is more robust and more up to the specs.
Also added a new zone file which has some nice properties
which trigger corner cases.
This commit is contained in:
Miek Gieben 2012-02-15 08:47:31 +01:00
parent cb1d41c607
commit 697d67ea96
3 changed files with 162 additions and 102 deletions

30
t/name.txt Normal file
View File

@ -0,0 +1,30 @@
$ORIGIN .
$TTL 3600 ; 1 hour
name IN SOA a6.nstld.com. hostmaster.nic.name. (
203362132 ; serial
300 ; refresh (5 minutes)
300 ; retry (5 minutes)
1209600 ; expire (2 weeks)
300 ; minimum (5 minutes)
)
$TTL 10800 ; 3 hours
NS g6.nstld.com.
NS h6.nstld.com.
NS j6.nstld.com.
NS k6.nstld.com.
NS l6.nstld.com.
NS a6.nstld.com.
NS c6.nstld.com.
NS d6.nstld.com.
NS f6.nstld.com.
NS m6.nstld.com.
$ORIGIN name.
0-0onlus NS ns7.ehiweb.it.
NS ns8.ehiweb.it.
0-g MX 10 mx01.nic
MX 10 mx02.nic
MX 10 mx03.nic
MX 10 mx04.nic
$ORIGIN 0-g.name
moutamassey NS ns01.yahoodomains.jp.
NS ns02.yahoodomains.jp.

203
zscan.go
View File

@ -132,7 +132,8 @@ func parseZone(r io.Reader, origin, f string, t chan Token, include int) {
s.Whitespace = 0 s.Whitespace = 0
// Start the lexer // Start the lexer
go zlexer(s, c) go zlexer(s, c)
// 5 possible beginnings of a line, _ is a space // 6 possible beginnings of a line, _ is a space
// 0. _ _RRTYPE -> all omitted until the rrtype
// 1. _OWNER _ _RRTYPE -> class/ttl omitted // 1. _OWNER _ _RRTYPE -> class/ttl omitted
// 2. _OWNER _ _STRING _ _RRTYPE -> class omitted // 2. _OWNER _ _STRING _ _RRTYPE -> class omitted
// 3. _OWNER _ _STRING _ _CLASS _ _RRTYPE -> ttl/class // 3. _OWNER _ _STRING _ _CLASS _ _RRTYPE -> ttl/class
@ -141,17 +142,18 @@ func parseZone(r io.Reader, origin, f string, t chan Token, include int) {
// After detecting these, we know the _RRTYPE so we can jump to functions // After detecting these, we know the _RRTYPE so we can jump to functions
// handling the rdata for each of these types. // handling the rdata for each of these types.
if origin == "" { if origin == "" {
origin = "." origin = "."
} }
if _, _, ok := IsDomainName(origin); !ok { if _, _, ok := IsDomainName(origin); !ok {
t <- Token{Error: &ParseError{f, "bad origin name", lex{}}} t <- Token{Error: &ParseError{f, "bad origin name", lex{}}}
return return
} }
st := _EXPECT_OWNER_DIR st := _EXPECT_OWNER_DIR
var h RR_Header var h RR_Header
var ok bool var ok bool
var defttl uint32 = DefaultTtl var defttl uint32 = DefaultTtl
var prevName string
for l := range c { for l := range c {
if _DEBUG { if _DEBUG {
fmt.Printf("[%v]\n", l) fmt.Printf("[%v]\n", l)
@ -172,19 +174,21 @@ func parseZone(r io.Reader, origin, f string, t chan Token, include int) {
st = _EXPECT_OWNER_DIR st = _EXPECT_OWNER_DIR
case _OWNER: case _OWNER:
h.Name = l.token h.Name = l.token
if l.token == "@" { if l.token == "@" {
h.Name = origin h.Name = origin
st = _EXPECT_OWNER_BL prevName = h.Name
break st = _EXPECT_OWNER_BL
} break
}
_, ld, ok := IsDomainName(l.token) _, ld, ok := IsDomainName(l.token)
if !ok { if !ok {
t <- Token{Error: &ParseError{f, "bad owner name", l}} t <- Token{Error: &ParseError{f, "bad owner name", l}}
return return
} }
if h.Name[ld-1] != '.' { if h.Name[ld-1] != '.' {
h.Name += origin h.Name = appendOrigin(h.Name, origin)
} }
prevName = h.Name
st = _EXPECT_OWNER_BL st = _EXPECT_OWNER_BL
case _DIRTTL: case _DIRTTL:
st = _EXPECT_DIRTTL_BL st = _EXPECT_DIRTTL_BL
@ -192,8 +196,23 @@ func parseZone(r io.Reader, origin, f string, t chan Token, include int) {
st = _EXPECT_DIRORIGIN_BL st = _EXPECT_DIRORIGIN_BL
case _DIRINCLUDE: case _DIRINCLUDE:
st = _EXPECT_DIRINCLUDE_BL st = _EXPECT_DIRINCLUDE_BL
case _RRTYPE:
// Everthing has been omitted
h.Name = prevName
h.Rrtype, ok = Str_rr[strings.ToUpper(l.token)]
if !ok {
if h.Rrtype, ok = typeToInt(l.token); !ok {
t <- Token{Error: &ParseError{f, "Unknown RR type", l}}
return
}
}
st = _EXPECT_RDATA
case _BLANK:
// Discard, can happen when there is nothing on the
// line except the RR type
default: default:
t <- Token{Error: &ParseError{f, "Error at the start", l}} println(l.value)
t <- Token{Error: &ParseError{f, "Error at beginning", l}}
return return
} }
case _EXPECT_DIRINCLUDE_BL: case _EXPECT_DIRINCLUDE_BL:
@ -235,8 +254,10 @@ func parseZone(r io.Reader, origin, f string, t chan Token, include int) {
} }
if e := slurpRemainder(c, f); e != nil { if e := slurpRemainder(c, f); e != nil {
t <- Token{Error: e} t <- Token{Error: e}
return
} }
if ttl, ok := stringToTtl(l, f, t); !ok { if ttl, ok := stringToTtl(l, f, t); !ok {
t <- Token{Error: &ParseError{f, "Expecting $TTL value, not this...", l}}
return return
} else { } else {
defttl = ttl defttl = ttl
@ -257,9 +278,13 @@ func parseZone(r io.Reader, origin, f string, t chan Token, include int) {
t <- Token{Error: e} t <- Token{Error: e}
} }
if !IsFqdn(l.token) { if !IsFqdn(l.token) {
origin = l.token + "." + origin // Append old origin if the new one isn't a fqdn if origin != "." { // Prevent .. endings
origin = l.token + "." + origin
} else {
origin = l.token + origin
}
} else { } else {
origin = "." + l.token origin = l.token
} }
st = _EXPECT_OWNER_DIR st = _EXPECT_OWNER_DIR
case _EXPECT_OWNER_BL: case _EXPECT_OWNER_BL:
@ -272,12 +297,12 @@ func parseZone(r io.Reader, origin, f string, t chan Token, include int) {
switch l.value { switch l.value {
case _RRTYPE: case _RRTYPE:
h.Rrtype, ok = Str_rr[strings.ToUpper(l.token)] h.Rrtype, ok = Str_rr[strings.ToUpper(l.token)]
if !ok { if !ok {
if h.Rrtype, ok = typeToInt(l.token); !ok { if h.Rrtype, ok = typeToInt(l.token); !ok {
t <- Token{Error: &ParseError{f, "Unknown RR type", l}} t <- Token{Error: &ParseError{f, "Unknown RR type", l}}
return return
} }
} }
st = _EXPECT_RDATA st = _EXPECT_RDATA
case _CLASS: case _CLASS:
h.Class, ok = Str_class[strings.ToUpper(l.token)] h.Class, ok = Str_class[strings.ToUpper(l.token)]
@ -325,12 +350,12 @@ func parseZone(r io.Reader, origin, f string, t chan Token, include int) {
st = _EXPECT_RRTYPE_BL st = _EXPECT_RRTYPE_BL
case _RRTYPE: case _RRTYPE:
h.Rrtype, ok = Str_rr[strings.ToUpper(l.token)] h.Rrtype, ok = Str_rr[strings.ToUpper(l.token)]
if !ok { if !ok {
if h.Rrtype, ok = typeToInt(l.token); !ok { if h.Rrtype, ok = typeToInt(l.token); !ok {
t <- Token{Error: &ParseError{f, "Unknown RR type", l}} t <- Token{Error: &ParseError{f, "Unknown RR type", l}}
return return
} }
} }
st = _EXPECT_RDATA st = _EXPECT_RDATA
} }
case _EXPECT_ANY_NOCLASS: case _EXPECT_ANY_NOCLASS:
@ -345,12 +370,12 @@ func parseZone(r io.Reader, origin, f string, t chan Token, include int) {
st = _EXPECT_RRTYPE_BL st = _EXPECT_RRTYPE_BL
case _RRTYPE: case _RRTYPE:
h.Rrtype, ok = Str_rr[strings.ToUpper(l.token)] h.Rrtype, ok = Str_rr[strings.ToUpper(l.token)]
if !ok { if !ok {
if h.Rrtype, ok = typeToInt(l.token); !ok { if h.Rrtype, ok = typeToInt(l.token); !ok {
t <- Token{Error: &ParseError{f, "Unknown RR type", l}} t <- Token{Error: &ParseError{f, "Unknown RR type", l}}
return return
} }
} }
st = _EXPECT_RDATA st = _EXPECT_RDATA
default: default:
t <- Token{Error: &ParseError{f, "Expecting RR type or TTL, not this...", l}} t <- Token{Error: &ParseError{f, "Expecting RR type or TTL, not this...", l}}
@ -368,12 +393,12 @@ func parseZone(r io.Reader, origin, f string, t chan Token, include int) {
return return
} }
h.Rrtype, ok = Str_rr[strings.ToUpper(l.token)] h.Rrtype, ok = Str_rr[strings.ToUpper(l.token)]
if !ok { if !ok {
if h.Rrtype, ok = typeToInt(l.token); !ok { if h.Rrtype, ok = typeToInt(l.token); !ok {
t <- Token{Error: &ParseError{f, "Unknown RR type", l}} t <- Token{Error: &ParseError{f, "Unknown RR type", l}}
return return
} }
} }
st = _EXPECT_RDATA st = _EXPECT_RDATA
case _EXPECT_RDATA: case _EXPECT_RDATA:
// I could save my token here...? l // I could save my token here...? l
@ -410,7 +435,11 @@ func (l lex) String() string {
case _CLASS: case _CLASS:
return "C:" + l.token + "$" return "C:" + l.token + "$"
case _DIRTTL: case _DIRTTL:
return "T:" + l.token + "$" return "$T:" + l.token + "$"
case _DIRORIGIN:
return "$O:" + l.token + "$"
case _DIRINCLUDE:
return "$I:" + l.token + "$"
} }
return "**" return "**"
} }
@ -477,11 +506,11 @@ func zlexer(s scanner.Scanner, c chan lex) {
l.value = _RRTYPE l.value = _RRTYPE
rrtype = true rrtype = true
} else { } else {
if strings.HasPrefix(strings.ToUpper(l.token), "TYPE") { if strings.HasPrefix(strings.ToUpper(l.token), "TYPE") {
l.value = _RRTYPE l.value = _RRTYPE
rrtype = true rrtype = true
} }
} }
if _, ok := Str_class[strings.ToUpper(l.token)]; ok { if _, ok := Str_class[strings.ToUpper(l.token)]; ok {
l.value = _CLASS l.value = _CLASS
} else { } else {
@ -521,9 +550,9 @@ func zlexer(s scanner.Scanner, c chan lex) {
stri = 0 stri = 0
} }
commt = true commt = true
case '\r': case '\r':
// discard // discard
// this means it can also not be used as rdata // this means it can also not be used as rdata
case '\n': case '\n':
// hmmm, escape newline // hmmm, escape newline
if quote { if quote {
@ -629,17 +658,17 @@ func zlexer(s scanner.Scanner, c chan lex) {
escape = false escape = false
break break
} }
switch x[0] { switch x[0] {
case ')': case ')':
brace-- brace--
if brace < 0 { if brace < 0 {
l.err = "extra closing brace" l.err = "extra closing brace"
c <- l c <- l
return return
} }
case '(': case '(':
brace++ brace++
} }
default: default:
if commt { if commt {
break break
@ -679,32 +708,40 @@ func typeToInt(token string) (uint16, bool) {
} }
func stringToTtl(l lex, f string, t chan Token) (uint32, bool) { func stringToTtl(l lex, f string, t chan Token) (uint32, bool) {
s := uint32(0) s := uint32(0)
i := uint32(0) i := uint32(0)
for _, c := range l.token { for _, c := range l.token {
switch c { switch c {
case 's', 'S': case 's', 'S':
s += i s += i
i = 0 i = 0
case 'm', 'M': case 'm', 'M':
s += i * 60 s += i * 60
i = 0 i = 0
case 'h', 'H': case 'h', 'H':
s += i * 60 * 60 s += i * 60 * 60
i = 0 i = 0
case 'd', 'D': case 'd', 'D':
s += i * 60 * 60 * 24 s += i * 60 * 60 * 24
i = 0 i = 0
case 'w', 'W': case 'w', 'W':
s += i * 60 * 60 * 24 * 7 s += i * 60 * 60 * 24 * 7
i = 0 i = 0
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
i *= 10 i *= 10
i += uint32(c) - '0' i += uint32(c) - '0'
default: default:
t <- Token{Error: &ParseError{f, "Not a TTL", l}} t <- Token{Error: &ParseError{f, "Not a TTL", l}}
return 0, false return 0, false
} }
} }
return s+i, true return s + i, true
}
func appendOrigin(name, origin string) string {
if origin == "." {
return name + origin
}
return name + "." + origin
} }

View File

@ -1,13 +1,12 @@
package dns package dns
import ( import (
"fmt"
"net" "net"
"strconv" "strconv"
"strings" "strings"
) )
// TODO: SPF, TKEY, Unknown RRs, RR_URI, DHCID, TLSA // TODO: SPF, TKEY, RR_URI, DHCID, TLSA
// Parse the rdata of each rrtype. // Parse the rdata of each rrtype.
// All data from the channel c is either _STRING or _BLANK. // All data from the channel c is either _STRING or _BLANK.
@ -85,15 +84,9 @@ Slurp:
func slurpRemainder(c chan lex, f string) *ParseError { func slurpRemainder(c chan lex, f string) *ParseError {
l := <-c l := <-c
if _DEBUG {
fmt.Printf("%v\n", l)
}
switch l.value { switch l.value {
case _BLANK: case _BLANK:
l = <-c l = <-c
if _DEBUG {
fmt.Printf("%v\n", l)
}
if l.value != _NEWLINE && l.value != _EOF { if l.value != _NEWLINE && l.value != _EOF {
return &ParseError{f, "garbage after rdata", l} return &ParseError{f, "garbage after rdata", l}
} }
@ -143,7 +136,7 @@ func setNS(h RR_Header, c chan lex, o, f string) (RR, *ParseError) {
return nil, &ParseError{f, "bad NS Ns", l} return nil, &ParseError{f, "bad NS Ns", l}
} }
if rr.Ns[ld-1] != '.' { if rr.Ns[ld-1] != '.' {
rr.Ns += o rr.Ns = appendOrigin(rr.Ns, o)
} }
return rr, nil return rr, nil
} }
@ -159,7 +152,7 @@ func setPTR(h RR_Header, c chan lex, o, f string) (RR, *ParseError) {
return nil, &ParseError{f, "bad PTR Ptr", l} return nil, &ParseError{f, "bad PTR Ptr", l}
} }
if rr.Ptr[ld-1] != '.' { if rr.Ptr[ld-1] != '.' {
rr.Ptr += o rr.Ptr = appendOrigin(rr.Ptr, o)
} }
return rr, nil return rr, nil
} }
@ -182,7 +175,7 @@ func setMX(h RR_Header, c chan lex, o, f string) (RR, *ParseError) {
return nil, &ParseError{f, "bad MX Mx", l} return nil, &ParseError{f, "bad MX Mx", l}
} }
if rr.Mx[ld-1] != '.' { if rr.Mx[ld-1] != '.' {
rr.Mx += o rr.Mx = appendOrigin(rr.Mx, o)
} }
return rr, nil return rr, nil
} }
@ -198,7 +191,7 @@ func setCNAME(h RR_Header, c chan lex, o, f string) (RR, *ParseError) {
return nil, &ParseError{f, "bad CNAME Cname", l} return nil, &ParseError{f, "bad CNAME Cname", l}
} }
if rr.Cname[ld-1] != '.' { if rr.Cname[ld-1] != '.' {
rr.Cname += o rr.Cname = appendOrigin(rr.Cname, o)
} }
return rr, nil return rr, nil
} }
@ -214,7 +207,7 @@ func setDNAME(h RR_Header, c chan lex, o, f string) (RR, *ParseError) {
return nil, &ParseError{f, "bad CNAME Target", l} return nil, &ParseError{f, "bad CNAME Target", l}
} }
if rr.Target[ld-1] != '.' { if rr.Target[ld-1] != '.' {
rr.Target += o rr.Target = appendOrigin(rr.Target, o)
} }
return rr, nil return rr, nil
} }
@ -231,7 +224,7 @@ func setSOA(h RR_Header, c chan lex, o, f string) (RR, *ParseError) {
return nil, &ParseError{f, "bad SOA Ns", l} return nil, &ParseError{f, "bad SOA Ns", l}
} }
if rr.Ns[ld-1] != '.' { if rr.Ns[ld-1] != '.' {
rr.Ns += o rr.Ns = appendOrigin(rr.Ns, o)
} }
l = <-c l = <-c
@ -241,7 +234,7 @@ func setSOA(h RR_Header, c chan lex, o, f string) (RR, *ParseError) {
return nil, &ParseError{f, "bad SOA Mbox", l} return nil, &ParseError{f, "bad SOA Mbox", l}
} }
if rr.Mbox[ld-1] != '.' { if rr.Mbox[ld-1] != '.' {
rr.Mbox += o rr.Mbox = appendOrigin(rr.Mbox, o)
} }
<-c // _BLANK <-c // _BLANK
@ -304,7 +297,7 @@ func setSRV(h RR_Header, c chan lex, o, f string) (RR, *ParseError) {
return nil, &ParseError{f, "bad SRV Target", l} return nil, &ParseError{f, "bad SRV Target", l}
} }
if rr.Target[ld-1] != '.' { if rr.Target[ld-1] != '.' {
rr.Target += o rr.Target = appendOrigin(rr.Target, o)
} }
return rr, nil return rr, nil
} }
@ -391,7 +384,7 @@ func setNAPTR(h RR_Header, c chan lex, o, f string) (RR, *ParseError) {
return nil, &ParseError{f, "bad NAPTR Replacement", l} return nil, &ParseError{f, "bad NAPTR Replacement", l}
} }
if rr.Replacement[ld-1] != '.' { if rr.Replacement[ld-1] != '.' {
rr.Replacement += o rr.Replacement = appendOrigin(rr.Replacement, o)
} }
return rr, nil return rr, nil
} }
@ -498,7 +491,7 @@ func setRRSIG(h RR_Header, c chan lex, o, f string) (RR, *ParseError) {
return nil, &ParseError{f, "bad RRSIG SignerName", l} return nil, &ParseError{f, "bad RRSIG SignerName", l}
} }
if rr.SignerName[ld-1] != '.' { if rr.SignerName[ld-1] != '.' {
rr.SignerName += o rr.SignerName = appendOrigin(rr.SignerName, o)
} }
// Get the remaining data until we see a NEWLINE // Get the remaining data until we see a NEWLINE
l = <-c l = <-c
@ -529,7 +522,7 @@ func setNSEC(h RR_Header, c chan lex, o, f string) (RR, *ParseError) {
return nil, &ParseError{f, "bad NSEC NextDomain", l} return nil, &ParseError{f, "bad NSEC NextDomain", l}
} }
if rr.NextDomain[ld-1] != '.' { if rr.NextDomain[ld-1] != '.' {
rr.NextDomain += o rr.NextDomain = appendOrigin(rr.NextDomain, o)
} }
rr.TypeBitMap = make([]uint16, 0) rr.TypeBitMap = make([]uint16, 0)