gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

scan.go (30040B)


      1 package dns
      2 
      3 import (
      4 	"bufio"
      5 	"fmt"
      6 	"io"
      7 	"os"
      8 	"path/filepath"
      9 	"strconv"
     10 	"strings"
     11 )
     12 
     13 const maxTok = 512 // Token buffer start size, and growth size amount.
     14 
     15 // The maximum depth of $INCLUDE directives supported by the
     16 // ZoneParser API.
     17 const maxIncludeDepth = 7
     18 
     19 // Tokenize a RFC 1035 zone file. The tokenizer will normalize it:
     20 // * Add ownernames if they are left blank;
     21 // * Suppress sequences of spaces;
     22 // * Make each RR fit on one line (_NEWLINE is send as last)
     23 // * Handle comments: ;
     24 // * Handle braces - anywhere.
     25 const (
     26 	// Zonefile
     27 	zEOF = iota
     28 	zString
     29 	zBlank
     30 	zQuote
     31 	zNewline
     32 	zRrtpe
     33 	zOwner
     34 	zClass
     35 	zDirOrigin   // $ORIGIN
     36 	zDirTTL      // $TTL
     37 	zDirInclude  // $INCLUDE
     38 	zDirGenerate // $GENERATE
     39 
     40 	// Privatekey file
     41 	zValue
     42 	zKey
     43 
     44 	zExpectOwnerDir      // Ownername
     45 	zExpectOwnerBl       // Whitespace after the ownername
     46 	zExpectAny           // Expect rrtype, ttl or class
     47 	zExpectAnyNoClass    // Expect rrtype or ttl
     48 	zExpectAnyNoClassBl  // The whitespace after _EXPECT_ANY_NOCLASS
     49 	zExpectAnyNoTTL      // Expect rrtype or class
     50 	zExpectAnyNoTTLBl    // Whitespace after _EXPECT_ANY_NOTTL
     51 	zExpectRrtype        // Expect rrtype
     52 	zExpectRrtypeBl      // Whitespace BEFORE rrtype
     53 	zExpectRdata         // The first element of the rdata
     54 	zExpectDirTTLBl      // Space after directive $TTL
     55 	zExpectDirTTL        // Directive $TTL
     56 	zExpectDirOriginBl   // Space after directive $ORIGIN
     57 	zExpectDirOrigin     // Directive $ORIGIN
     58 	zExpectDirIncludeBl  // Space after directive $INCLUDE
     59 	zExpectDirInclude    // Directive $INCLUDE
     60 	zExpectDirGenerate   // Directive $GENERATE
     61 	zExpectDirGenerateBl // Space after directive $GENERATE
     62 )
     63 
     64 // ParseError is a parsing error. It contains the parse error and the location in the io.Reader
     65 // where the error occurred.
     66 type ParseError struct {
     67 	file string
     68 	err  string
     69 	lex  lex
     70 }
     71 
     72 func (e *ParseError) Error() (s string) {
     73 	if e.file != "" {
     74 		s = e.file + ": "
     75 	}
     76 	s += "dns: " + e.err + ": " + strconv.QuoteToASCII(e.lex.token) + " at line: " +
     77 		strconv.Itoa(e.lex.line) + ":" + strconv.Itoa(e.lex.column)
     78 	return
     79 }
     80 
     81 type lex struct {
     82 	token  string // text of the token
     83 	err    bool   // when true, token text has lexer error
     84 	value  uint8  // value: zString, _BLANK, etc.
     85 	torc   uint16 // type or class as parsed in the lexer, we only need to look this up in the grammar
     86 	line   int    // line in the file
     87 	column int    // column in the file
     88 }
     89 
     90 // ttlState describes the state necessary to fill in an omitted RR TTL
     91 type ttlState struct {
     92 	ttl           uint32 // ttl is the current default TTL
     93 	isByDirective bool   // isByDirective indicates whether ttl was set by a $TTL directive
     94 }
     95 
     96 // NewRR reads the RR contained in the string s. Only the first RR is returned.
     97 // If s contains no records, NewRR will return nil with no error.
     98 //
     99 // The class defaults to IN and TTL defaults to 3600. The full zone file syntax
    100 // like $TTL, $ORIGIN, etc. is supported. All fields of the returned RR are
    101 // set, except RR.Header().Rdlength which is set to 0.
    102 func NewRR(s string) (RR, error) {
    103 	if len(s) > 0 && s[len(s)-1] != '\n' { // We need a closing newline
    104 		return ReadRR(strings.NewReader(s+"\n"), "")
    105 	}
    106 	return ReadRR(strings.NewReader(s), "")
    107 }
    108 
    109 // ReadRR reads the RR contained in r.
    110 //
    111 // The string file is used in error reporting and to resolve relative
    112 // $INCLUDE directives.
    113 //
    114 // See NewRR for more documentation.
    115 func ReadRR(r io.Reader, file string) (RR, error) {
    116 	zp := NewZoneParser(r, ".", file)
    117 	zp.SetDefaultTTL(defaultTtl)
    118 	zp.SetIncludeAllowed(true)
    119 	rr, _ := zp.Next()
    120 	return rr, zp.Err()
    121 }
    122 
    123 // ZoneParser is a parser for an RFC 1035 style zonefile.
    124 //
    125 // Each parsed RR in the zone is returned sequentially from Next. An
    126 // optional comment can be retrieved with Comment.
    127 //
    128 // The directives $INCLUDE, $ORIGIN, $TTL and $GENERATE are all
    129 // supported. Although $INCLUDE is disabled by default.
    130 // Note that $GENERATE's range support up to a maximum of 65535 steps.
    131 //
    132 // Basic usage pattern when reading from a string (z) containing the
    133 // zone data:
    134 //
    135 //	zp := NewZoneParser(strings.NewReader(z), "", "")
    136 //
    137 //	for rr, ok := zp.Next(); ok; rr, ok = zp.Next() {
    138 //		// Do something with rr
    139 //	}
    140 //
    141 //	if err := zp.Err(); err != nil {
    142 //		// log.Println(err)
    143 //	}
    144 //
    145 // Comments specified after an RR (and on the same line!) are
    146 // returned too:
    147 //
    148 //	foo. IN A 10.0.0.1 ; this is a comment
    149 //
    150 // The text "; this is comment" is returned from Comment. Comments inside
    151 // the RR are returned concatenated along with the RR. Comments on a line
    152 // by themselves are discarded.
    153 //
    154 // Callers should not assume all returned data in an Resource Record is
    155 // syntactically correct, e.g. illegal base64 in RRSIGs will be returned as-is.
    156 type ZoneParser struct {
    157 	c *zlexer
    158 
    159 	parseErr *ParseError
    160 
    161 	origin string
    162 	file   string
    163 
    164 	defttl *ttlState
    165 
    166 	h RR_Header
    167 
    168 	// sub is used to parse $INCLUDE files and $GENERATE directives.
    169 	// Next, by calling subNext, forwards the resulting RRs from this
    170 	// sub parser to the calling code.
    171 	sub    *ZoneParser
    172 	osFile *os.File
    173 
    174 	includeDepth uint8
    175 
    176 	includeAllowed     bool
    177 	generateDisallowed bool
    178 }
    179 
    180 // NewZoneParser returns an RFC 1035 style zonefile parser that reads
    181 // from r.
    182 //
    183 // The string file is used in error reporting and to resolve relative
    184 // $INCLUDE directives. The string origin is used as the initial
    185 // origin, as if the file would start with an $ORIGIN directive.
    186 func NewZoneParser(r io.Reader, origin, file string) *ZoneParser {
    187 	var pe *ParseError
    188 	if origin != "" {
    189 		origin = Fqdn(origin)
    190 		if _, ok := IsDomainName(origin); !ok {
    191 			pe = &ParseError{file, "bad initial origin name", lex{}}
    192 		}
    193 	}
    194 
    195 	return &ZoneParser{
    196 		c: newZLexer(r),
    197 
    198 		parseErr: pe,
    199 
    200 		origin: origin,
    201 		file:   file,
    202 	}
    203 }
    204 
    205 // SetDefaultTTL sets the parsers default TTL to ttl.
    206 func (zp *ZoneParser) SetDefaultTTL(ttl uint32) {
    207 	zp.defttl = &ttlState{ttl, false}
    208 }
    209 
    210 // SetIncludeAllowed controls whether $INCLUDE directives are
    211 // allowed. $INCLUDE directives are not supported by default.
    212 //
    213 // The $INCLUDE directive will open and read from a user controlled
    214 // file on the system. Even if the file is not a valid zonefile, the
    215 // contents of the file may be revealed in error messages, such as:
    216 //
    217 //	/etc/passwd: dns: not a TTL: "root:x:0:0:root:/root:/bin/bash" at line: 1:31
    218 //	/etc/shadow: dns: not a TTL: "root:$6$<redacted>::0:99999:7:::" at line: 1:125
    219 func (zp *ZoneParser) SetIncludeAllowed(v bool) {
    220 	zp.includeAllowed = v
    221 }
    222 
    223 // Err returns the first non-EOF error that was encountered by the
    224 // ZoneParser.
    225 func (zp *ZoneParser) Err() error {
    226 	if zp.parseErr != nil {
    227 		return zp.parseErr
    228 	}
    229 
    230 	if zp.sub != nil {
    231 		if err := zp.sub.Err(); err != nil {
    232 			return err
    233 		}
    234 	}
    235 
    236 	return zp.c.Err()
    237 }
    238 
    239 func (zp *ZoneParser) setParseError(err string, l lex) (RR, bool) {
    240 	zp.parseErr = &ParseError{zp.file, err, l}
    241 	return nil, false
    242 }
    243 
    244 // Comment returns an optional text comment that occurred alongside
    245 // the RR.
    246 func (zp *ZoneParser) Comment() string {
    247 	if zp.parseErr != nil {
    248 		return ""
    249 	}
    250 
    251 	if zp.sub != nil {
    252 		return zp.sub.Comment()
    253 	}
    254 
    255 	return zp.c.Comment()
    256 }
    257 
    258 func (zp *ZoneParser) subNext() (RR, bool) {
    259 	if rr, ok := zp.sub.Next(); ok {
    260 		return rr, true
    261 	}
    262 
    263 	if zp.sub.osFile != nil {
    264 		zp.sub.osFile.Close()
    265 		zp.sub.osFile = nil
    266 	}
    267 
    268 	if zp.sub.Err() != nil {
    269 		// We have errors to surface.
    270 		return nil, false
    271 	}
    272 
    273 	zp.sub = nil
    274 	return zp.Next()
    275 }
    276 
    277 // Next advances the parser to the next RR in the zonefile and
    278 // returns the (RR, true). It will return (nil, false) when the
    279 // parsing stops, either by reaching the end of the input or an
    280 // error. After Next returns (nil, false), the Err method will return
    281 // any error that occurred during parsing.
    282 func (zp *ZoneParser) Next() (RR, bool) {
    283 	if zp.parseErr != nil {
    284 		return nil, false
    285 	}
    286 	if zp.sub != nil {
    287 		return zp.subNext()
    288 	}
    289 
    290 	// 6 possible beginnings of a line (_ is a space):
    291 	//
    292 	//   0. zRRTYPE                              -> all omitted until the rrtype
    293 	//   1. zOwner _ zRrtype                     -> class/ttl omitted
    294 	//   2. zOwner _ zString _ zRrtype           -> class omitted
    295 	//   3. zOwner _ zString _ zClass  _ zRrtype -> ttl/class
    296 	//   4. zOwner _ zClass  _ zRrtype           -> ttl omitted
    297 	//   5. zOwner _ zClass  _ zString _ zRrtype -> class/ttl (reversed)
    298 	//
    299 	// After detecting these, we know the zRrtype so we can jump to functions
    300 	// handling the rdata for each of these types.
    301 
    302 	st := zExpectOwnerDir // initial state
    303 	h := &zp.h
    304 
    305 	for l, ok := zp.c.Next(); ok; l, ok = zp.c.Next() {
    306 		// zlexer spotted an error already
    307 		if l.err {
    308 			return zp.setParseError(l.token, l)
    309 		}
    310 
    311 		switch st {
    312 		case zExpectOwnerDir:
    313 			// We can also expect a directive, like $TTL or $ORIGIN
    314 			if zp.defttl != nil {
    315 				h.Ttl = zp.defttl.ttl
    316 			}
    317 
    318 			h.Class = ClassINET
    319 
    320 			switch l.value {
    321 			case zNewline:
    322 				st = zExpectOwnerDir
    323 			case zOwner:
    324 				name, ok := toAbsoluteName(l.token, zp.origin)
    325 				if !ok {
    326 					return zp.setParseError("bad owner name", l)
    327 				}
    328 
    329 				h.Name = name
    330 
    331 				st = zExpectOwnerBl
    332 			case zDirTTL:
    333 				st = zExpectDirTTLBl
    334 			case zDirOrigin:
    335 				st = zExpectDirOriginBl
    336 			case zDirInclude:
    337 				st = zExpectDirIncludeBl
    338 			case zDirGenerate:
    339 				st = zExpectDirGenerateBl
    340 			case zRrtpe:
    341 				h.Rrtype = l.torc
    342 
    343 				st = zExpectRdata
    344 			case zClass:
    345 				h.Class = l.torc
    346 
    347 				st = zExpectAnyNoClassBl
    348 			case zBlank:
    349 				// Discard, can happen when there is nothing on the
    350 				// line except the RR type
    351 			case zString:
    352 				ttl, ok := stringToTTL(l.token)
    353 				if !ok {
    354 					return zp.setParseError("not a TTL", l)
    355 				}
    356 
    357 				h.Ttl = ttl
    358 
    359 				if zp.defttl == nil || !zp.defttl.isByDirective {
    360 					zp.defttl = &ttlState{ttl, false}
    361 				}
    362 
    363 				st = zExpectAnyNoTTLBl
    364 			default:
    365 				return zp.setParseError("syntax error at beginning", l)
    366 			}
    367 		case zExpectDirIncludeBl:
    368 			if l.value != zBlank {
    369 				return zp.setParseError("no blank after $INCLUDE-directive", l)
    370 			}
    371 
    372 			st = zExpectDirInclude
    373 		case zExpectDirInclude:
    374 			if l.value != zString {
    375 				return zp.setParseError("expecting $INCLUDE value, not this...", l)
    376 			}
    377 
    378 			neworigin := zp.origin // There may be optionally a new origin set after the filename, if not use current one
    379 			switch l, _ := zp.c.Next(); l.value {
    380 			case zBlank:
    381 				l, _ := zp.c.Next()
    382 				if l.value == zString {
    383 					name, ok := toAbsoluteName(l.token, zp.origin)
    384 					if !ok {
    385 						return zp.setParseError("bad origin name", l)
    386 					}
    387 
    388 					neworigin = name
    389 				}
    390 			case zNewline, zEOF:
    391 				// Ok
    392 			default:
    393 				return zp.setParseError("garbage after $INCLUDE", l)
    394 			}
    395 
    396 			if !zp.includeAllowed {
    397 				return zp.setParseError("$INCLUDE directive not allowed", l)
    398 			}
    399 			if zp.includeDepth >= maxIncludeDepth {
    400 				return zp.setParseError("too deeply nested $INCLUDE", l)
    401 			}
    402 
    403 			// Start with the new file
    404 			includePath := l.token
    405 			if !filepath.IsAbs(includePath) {
    406 				includePath = filepath.Join(filepath.Dir(zp.file), includePath)
    407 			}
    408 
    409 			r1, e1 := os.Open(includePath)
    410 			if e1 != nil {
    411 				var as string
    412 				if !filepath.IsAbs(l.token) {
    413 					as = fmt.Sprintf(" as `%s'", includePath)
    414 				}
    415 
    416 				msg := fmt.Sprintf("failed to open `%s'%s: %v", l.token, as, e1)
    417 				return zp.setParseError(msg, l)
    418 			}
    419 
    420 			zp.sub = NewZoneParser(r1, neworigin, includePath)
    421 			zp.sub.defttl, zp.sub.includeDepth, zp.sub.osFile = zp.defttl, zp.includeDepth+1, r1
    422 			zp.sub.SetIncludeAllowed(true)
    423 			return zp.subNext()
    424 		case zExpectDirTTLBl:
    425 			if l.value != zBlank {
    426 				return zp.setParseError("no blank after $TTL-directive", l)
    427 			}
    428 
    429 			st = zExpectDirTTL
    430 		case zExpectDirTTL:
    431 			if l.value != zString {
    432 				return zp.setParseError("expecting $TTL value, not this...", l)
    433 			}
    434 
    435 			if err := slurpRemainder(zp.c); err != nil {
    436 				return zp.setParseError(err.err, err.lex)
    437 			}
    438 
    439 			ttl, ok := stringToTTL(l.token)
    440 			if !ok {
    441 				return zp.setParseError("expecting $TTL value, not this...", l)
    442 			}
    443 
    444 			zp.defttl = &ttlState{ttl, true}
    445 
    446 			st = zExpectOwnerDir
    447 		case zExpectDirOriginBl:
    448 			if l.value != zBlank {
    449 				return zp.setParseError("no blank after $ORIGIN-directive", l)
    450 			}
    451 
    452 			st = zExpectDirOrigin
    453 		case zExpectDirOrigin:
    454 			if l.value != zString {
    455 				return zp.setParseError("expecting $ORIGIN value, not this...", l)
    456 			}
    457 
    458 			if err := slurpRemainder(zp.c); err != nil {
    459 				return zp.setParseError(err.err, err.lex)
    460 			}
    461 
    462 			name, ok := toAbsoluteName(l.token, zp.origin)
    463 			if !ok {
    464 				return zp.setParseError("bad origin name", l)
    465 			}
    466 
    467 			zp.origin = name
    468 
    469 			st = zExpectOwnerDir
    470 		case zExpectDirGenerateBl:
    471 			if l.value != zBlank {
    472 				return zp.setParseError("no blank after $GENERATE-directive", l)
    473 			}
    474 
    475 			st = zExpectDirGenerate
    476 		case zExpectDirGenerate:
    477 			if zp.generateDisallowed {
    478 				return zp.setParseError("nested $GENERATE directive not allowed", l)
    479 			}
    480 			if l.value != zString {
    481 				return zp.setParseError("expecting $GENERATE value, not this...", l)
    482 			}
    483 
    484 			return zp.generate(l)
    485 		case zExpectOwnerBl:
    486 			if l.value != zBlank {
    487 				return zp.setParseError("no blank after owner", l)
    488 			}
    489 
    490 			st = zExpectAny
    491 		case zExpectAny:
    492 			switch l.value {
    493 			case zRrtpe:
    494 				if zp.defttl == nil {
    495 					return zp.setParseError("missing TTL with no previous value", l)
    496 				}
    497 
    498 				h.Rrtype = l.torc
    499 
    500 				st = zExpectRdata
    501 			case zClass:
    502 				h.Class = l.torc
    503 
    504 				st = zExpectAnyNoClassBl
    505 			case zString:
    506 				ttl, ok := stringToTTL(l.token)
    507 				if !ok {
    508 					return zp.setParseError("not a TTL", l)
    509 				}
    510 
    511 				h.Ttl = ttl
    512 
    513 				if zp.defttl == nil || !zp.defttl.isByDirective {
    514 					zp.defttl = &ttlState{ttl, false}
    515 				}
    516 
    517 				st = zExpectAnyNoTTLBl
    518 			default:
    519 				return zp.setParseError("expecting RR type, TTL or class, not this...", l)
    520 			}
    521 		case zExpectAnyNoClassBl:
    522 			if l.value != zBlank {
    523 				return zp.setParseError("no blank before class", l)
    524 			}
    525 
    526 			st = zExpectAnyNoClass
    527 		case zExpectAnyNoTTLBl:
    528 			if l.value != zBlank {
    529 				return zp.setParseError("no blank before TTL", l)
    530 			}
    531 
    532 			st = zExpectAnyNoTTL
    533 		case zExpectAnyNoTTL:
    534 			switch l.value {
    535 			case zClass:
    536 				h.Class = l.torc
    537 
    538 				st = zExpectRrtypeBl
    539 			case zRrtpe:
    540 				h.Rrtype = l.torc
    541 
    542 				st = zExpectRdata
    543 			default:
    544 				return zp.setParseError("expecting RR type or class, not this...", l)
    545 			}
    546 		case zExpectAnyNoClass:
    547 			switch l.value {
    548 			case zString:
    549 				ttl, ok := stringToTTL(l.token)
    550 				if !ok {
    551 					return zp.setParseError("not a TTL", l)
    552 				}
    553 
    554 				h.Ttl = ttl
    555 
    556 				if zp.defttl == nil || !zp.defttl.isByDirective {
    557 					zp.defttl = &ttlState{ttl, false}
    558 				}
    559 
    560 				st = zExpectRrtypeBl
    561 			case zRrtpe:
    562 				h.Rrtype = l.torc
    563 
    564 				st = zExpectRdata
    565 			default:
    566 				return zp.setParseError("expecting RR type or TTL, not this...", l)
    567 			}
    568 		case zExpectRrtypeBl:
    569 			if l.value != zBlank {
    570 				return zp.setParseError("no blank before RR type", l)
    571 			}
    572 
    573 			st = zExpectRrtype
    574 		case zExpectRrtype:
    575 			if l.value != zRrtpe {
    576 				return zp.setParseError("unknown RR type", l)
    577 			}
    578 
    579 			h.Rrtype = l.torc
    580 
    581 			st = zExpectRdata
    582 		case zExpectRdata:
    583 			var (
    584 				rr             RR
    585 				parseAsRFC3597 bool
    586 			)
    587 			if newFn, ok := TypeToRR[h.Rrtype]; ok {
    588 				rr = newFn()
    589 				*rr.Header() = *h
    590 
    591 				// We may be parsing a known RR type using the RFC3597 format.
    592 				// If so, we handle that here in a generic way.
    593 				//
    594 				// This is also true for PrivateRR types which will have the
    595 				// RFC3597 parsing done for them and the Unpack method called
    596 				// to populate the RR instead of simply deferring to Parse.
    597 				if zp.c.Peek().token == "\\#" {
    598 					parseAsRFC3597 = true
    599 				}
    600 			} else {
    601 				rr = &RFC3597{Hdr: *h}
    602 			}
    603 
    604 			_, isPrivate := rr.(*PrivateRR)
    605 			if !isPrivate && zp.c.Peek().token == "" {
    606 				// This is a dynamic update rr.
    607 
    608 				// TODO(tmthrgd): Previously slurpRemainder was only called
    609 				// for certain RR types, which may have been important.
    610 				if err := slurpRemainder(zp.c); err != nil {
    611 					return zp.setParseError(err.err, err.lex)
    612 				}
    613 
    614 				return rr, true
    615 			} else if l.value == zNewline {
    616 				return zp.setParseError("unexpected newline", l)
    617 			}
    618 
    619 			parseAsRR := rr
    620 			if parseAsRFC3597 {
    621 				parseAsRR = &RFC3597{Hdr: *h}
    622 			}
    623 
    624 			if err := parseAsRR.parse(zp.c, zp.origin); err != nil {
    625 				// err is a concrete *ParseError without the file field set.
    626 				// The setParseError call below will construct a new
    627 				// *ParseError with file set to zp.file.
    628 
    629 				// err.lex may be nil in which case we substitute our current
    630 				// lex token.
    631 				if err.lex == (lex{}) {
    632 					return zp.setParseError(err.err, l)
    633 				}
    634 
    635 				return zp.setParseError(err.err, err.lex)
    636 			}
    637 
    638 			if parseAsRFC3597 {
    639 				err := parseAsRR.(*RFC3597).fromRFC3597(rr)
    640 				if err != nil {
    641 					return zp.setParseError(err.Error(), l)
    642 				}
    643 			}
    644 
    645 			return rr, true
    646 		}
    647 	}
    648 
    649 	// If we get here, we and the h.Rrtype is still zero, we haven't parsed anything, this
    650 	// is not an error, because an empty zone file is still a zone file.
    651 	return nil, false
    652 }
    653 
    654 type zlexer struct {
    655 	br io.ByteReader
    656 
    657 	readErr error
    658 
    659 	line   int
    660 	column int
    661 
    662 	comBuf  string
    663 	comment string
    664 
    665 	l       lex
    666 	cachedL *lex
    667 
    668 	brace  int
    669 	quote  bool
    670 	space  bool
    671 	commt  bool
    672 	rrtype bool
    673 	owner  bool
    674 
    675 	nextL bool
    676 
    677 	eol bool // end-of-line
    678 }
    679 
    680 func newZLexer(r io.Reader) *zlexer {
    681 	br, ok := r.(io.ByteReader)
    682 	if !ok {
    683 		br = bufio.NewReaderSize(r, 1024)
    684 	}
    685 
    686 	return &zlexer{
    687 		br: br,
    688 
    689 		line: 1,
    690 
    691 		owner: true,
    692 	}
    693 }
    694 
    695 func (zl *zlexer) Err() error {
    696 	if zl.readErr == io.EOF {
    697 		return nil
    698 	}
    699 
    700 	return zl.readErr
    701 }
    702 
    703 // readByte returns the next byte from the input
    704 func (zl *zlexer) readByte() (byte, bool) {
    705 	if zl.readErr != nil {
    706 		return 0, false
    707 	}
    708 
    709 	c, err := zl.br.ReadByte()
    710 	if err != nil {
    711 		zl.readErr = err
    712 		return 0, false
    713 	}
    714 
    715 	// delay the newline handling until the next token is delivered,
    716 	// fixes off-by-one errors when reporting a parse error.
    717 	if zl.eol {
    718 		zl.line++
    719 		zl.column = 0
    720 		zl.eol = false
    721 	}
    722 
    723 	if c == '\n' {
    724 		zl.eol = true
    725 	} else {
    726 		zl.column++
    727 	}
    728 
    729 	return c, true
    730 }
    731 
    732 func (zl *zlexer) Peek() lex {
    733 	if zl.nextL {
    734 		return zl.l
    735 	}
    736 
    737 	l, ok := zl.Next()
    738 	if !ok {
    739 		return l
    740 	}
    741 
    742 	if zl.nextL {
    743 		// Cache l. Next returns zl.cachedL then zl.l.
    744 		zl.cachedL = &l
    745 	} else {
    746 		// In this case l == zl.l, so we just tell Next to return zl.l.
    747 		zl.nextL = true
    748 	}
    749 
    750 	return l
    751 }
    752 
    753 func (zl *zlexer) Next() (lex, bool) {
    754 	l := &zl.l
    755 	switch {
    756 	case zl.cachedL != nil:
    757 		l, zl.cachedL = zl.cachedL, nil
    758 		return *l, true
    759 	case zl.nextL:
    760 		zl.nextL = false
    761 		return *l, true
    762 	case l.err:
    763 		// Parsing errors should be sticky.
    764 		return lex{value: zEOF}, false
    765 	}
    766 
    767 	var (
    768 		str = make([]byte, maxTok) // Hold string text
    769 		com = make([]byte, maxTok) // Hold comment text
    770 
    771 		stri int // Offset in str (0 means empty)
    772 		comi int // Offset in com (0 means empty)
    773 
    774 		escape bool
    775 	)
    776 
    777 	if zl.comBuf != "" {
    778 		comi = copy(com[:], zl.comBuf)
    779 		zl.comBuf = ""
    780 	}
    781 
    782 	zl.comment = ""
    783 
    784 	for x, ok := zl.readByte(); ok; x, ok = zl.readByte() {
    785 		l.line, l.column = zl.line, zl.column
    786 
    787 		if stri >= len(str) {
    788 			// if buffer length is insufficient, increase it.
    789 			str = append(str[:], make([]byte, maxTok)...)
    790 		}
    791 		if comi >= len(com) {
    792 			// if buffer length is insufficient, increase it.
    793 			com = append(com[:], make([]byte, maxTok)...)
    794 		}
    795 
    796 		switch x {
    797 		case ' ', '\t':
    798 			if escape || zl.quote {
    799 				// Inside quotes or escaped this is legal.
    800 				str[stri] = x
    801 				stri++
    802 
    803 				escape = false
    804 				break
    805 			}
    806 
    807 			if zl.commt {
    808 				com[comi] = x
    809 				comi++
    810 				break
    811 			}
    812 
    813 			var retL lex
    814 			if stri == 0 {
    815 				// Space directly in the beginning, handled in the grammar
    816 			} else if zl.owner {
    817 				// If we have a string and it's the first, make it an owner
    818 				l.value = zOwner
    819 				l.token = string(str[:stri])
    820 
    821 				// escape $... start with a \ not a $, so this will work
    822 				switch strings.ToUpper(l.token) {
    823 				case "$TTL":
    824 					l.value = zDirTTL
    825 				case "$ORIGIN":
    826 					l.value = zDirOrigin
    827 				case "$INCLUDE":
    828 					l.value = zDirInclude
    829 				case "$GENERATE":
    830 					l.value = zDirGenerate
    831 				}
    832 
    833 				retL = *l
    834 			} else {
    835 				l.value = zString
    836 				l.token = string(str[:stri])
    837 
    838 				if !zl.rrtype {
    839 					tokenUpper := strings.ToUpper(l.token)
    840 					if t, ok := StringToType[tokenUpper]; ok {
    841 						l.value = zRrtpe
    842 						l.torc = t
    843 
    844 						zl.rrtype = true
    845 					} else if strings.HasPrefix(tokenUpper, "TYPE") {
    846 						t, ok := typeToInt(l.token)
    847 						if !ok {
    848 							l.token = "unknown RR type"
    849 							l.err = true
    850 							return *l, true
    851 						}
    852 
    853 						l.value = zRrtpe
    854 						l.torc = t
    855 
    856 						zl.rrtype = true
    857 					}
    858 
    859 					if t, ok := StringToClass[tokenUpper]; ok {
    860 						l.value = zClass
    861 						l.torc = t
    862 					} else if strings.HasPrefix(tokenUpper, "CLASS") {
    863 						t, ok := classToInt(l.token)
    864 						if !ok {
    865 							l.token = "unknown class"
    866 							l.err = true
    867 							return *l, true
    868 						}
    869 
    870 						l.value = zClass
    871 						l.torc = t
    872 					}
    873 				}
    874 
    875 				retL = *l
    876 			}
    877 
    878 			zl.owner = false
    879 
    880 			if !zl.space {
    881 				zl.space = true
    882 
    883 				l.value = zBlank
    884 				l.token = " "
    885 
    886 				if retL == (lex{}) {
    887 					return *l, true
    888 				}
    889 
    890 				zl.nextL = true
    891 			}
    892 
    893 			if retL != (lex{}) {
    894 				return retL, true
    895 			}
    896 		case ';':
    897 			if escape || zl.quote {
    898 				// Inside quotes or escaped this is legal.
    899 				str[stri] = x
    900 				stri++
    901 
    902 				escape = false
    903 				break
    904 			}
    905 
    906 			zl.commt = true
    907 			zl.comBuf = ""
    908 
    909 			if comi > 1 {
    910 				// A newline was previously seen inside a comment that
    911 				// was inside braces and we delayed adding it until now.
    912 				com[comi] = ' ' // convert newline to space
    913 				comi++
    914 				if comi >= len(com) {
    915 					l.token = "comment length insufficient for parsing"
    916 					l.err = true
    917 					return *l, true
    918 				}
    919 			}
    920 
    921 			com[comi] = ';'
    922 			comi++
    923 
    924 			if stri > 0 {
    925 				zl.comBuf = string(com[:comi])
    926 
    927 				l.value = zString
    928 				l.token = string(str[:stri])
    929 				return *l, true
    930 			}
    931 		case '\r':
    932 			escape = false
    933 
    934 			if zl.quote {
    935 				str[stri] = x
    936 				stri++
    937 			}
    938 
    939 			// discard if outside of quotes
    940 		case '\n':
    941 			escape = false
    942 
    943 			// Escaped newline
    944 			if zl.quote {
    945 				str[stri] = x
    946 				stri++
    947 				break
    948 			}
    949 
    950 			if zl.commt {
    951 				// Reset a comment
    952 				zl.commt = false
    953 				zl.rrtype = false
    954 
    955 				// If not in a brace this ends the comment AND the RR
    956 				if zl.brace == 0 {
    957 					zl.owner = true
    958 
    959 					l.value = zNewline
    960 					l.token = "\n"
    961 					zl.comment = string(com[:comi])
    962 					return *l, true
    963 				}
    964 
    965 				zl.comBuf = string(com[:comi])
    966 				break
    967 			}
    968 
    969 			if zl.brace == 0 {
    970 				// If there is previous text, we should output it here
    971 				var retL lex
    972 				if stri != 0 {
    973 					l.value = zString
    974 					l.token = string(str[:stri])
    975 
    976 					if !zl.rrtype {
    977 						tokenUpper := strings.ToUpper(l.token)
    978 						if t, ok := StringToType[tokenUpper]; ok {
    979 							zl.rrtype = true
    980 
    981 							l.value = zRrtpe
    982 							l.torc = t
    983 						}
    984 					}
    985 
    986 					retL = *l
    987 				}
    988 
    989 				l.value = zNewline
    990 				l.token = "\n"
    991 
    992 				zl.comment = zl.comBuf
    993 				zl.comBuf = ""
    994 				zl.rrtype = false
    995 				zl.owner = true
    996 
    997 				if retL != (lex{}) {
    998 					zl.nextL = true
    999 					return retL, true
   1000 				}
   1001 
   1002 				return *l, true
   1003 			}
   1004 		case '\\':
   1005 			// comments do not get escaped chars, everything is copied
   1006 			if zl.commt {
   1007 				com[comi] = x
   1008 				comi++
   1009 				break
   1010 			}
   1011 
   1012 			// something already escaped must be in string
   1013 			if escape {
   1014 				str[stri] = x
   1015 				stri++
   1016 
   1017 				escape = false
   1018 				break
   1019 			}
   1020 
   1021 			// something escaped outside of string gets added to string
   1022 			str[stri] = x
   1023 			stri++
   1024 
   1025 			escape = true
   1026 		case '"':
   1027 			if zl.commt {
   1028 				com[comi] = x
   1029 				comi++
   1030 				break
   1031 			}
   1032 
   1033 			if escape {
   1034 				str[stri] = x
   1035 				stri++
   1036 
   1037 				escape = false
   1038 				break
   1039 			}
   1040 
   1041 			zl.space = false
   1042 
   1043 			// send previous gathered text and the quote
   1044 			var retL lex
   1045 			if stri != 0 {
   1046 				l.value = zString
   1047 				l.token = string(str[:stri])
   1048 
   1049 				retL = *l
   1050 			}
   1051 
   1052 			// send quote itself as separate token
   1053 			l.value = zQuote
   1054 			l.token = "\""
   1055 
   1056 			zl.quote = !zl.quote
   1057 
   1058 			if retL != (lex{}) {
   1059 				zl.nextL = true
   1060 				return retL, true
   1061 			}
   1062 
   1063 			return *l, true
   1064 		case '(', ')':
   1065 			if zl.commt {
   1066 				com[comi] = x
   1067 				comi++
   1068 				break
   1069 			}
   1070 
   1071 			if escape || zl.quote {
   1072 				// Inside quotes or escaped this is legal.
   1073 				str[stri] = x
   1074 				stri++
   1075 
   1076 				escape = false
   1077 				break
   1078 			}
   1079 
   1080 			switch x {
   1081 			case ')':
   1082 				zl.brace--
   1083 
   1084 				if zl.brace < 0 {
   1085 					l.token = "extra closing brace"
   1086 					l.err = true
   1087 					return *l, true
   1088 				}
   1089 			case '(':
   1090 				zl.brace++
   1091 			}
   1092 		default:
   1093 			escape = false
   1094 
   1095 			if zl.commt {
   1096 				com[comi] = x
   1097 				comi++
   1098 				break
   1099 			}
   1100 
   1101 			str[stri] = x
   1102 			stri++
   1103 
   1104 			zl.space = false
   1105 		}
   1106 	}
   1107 
   1108 	if zl.readErr != nil && zl.readErr != io.EOF {
   1109 		// Don't return any tokens after a read error occurs.
   1110 		return lex{value: zEOF}, false
   1111 	}
   1112 
   1113 	var retL lex
   1114 	if stri > 0 {
   1115 		// Send remainder of str
   1116 		l.value = zString
   1117 		l.token = string(str[:stri])
   1118 		retL = *l
   1119 
   1120 		if comi <= 0 {
   1121 			return retL, true
   1122 		}
   1123 	}
   1124 
   1125 	if comi > 0 {
   1126 		// Send remainder of com
   1127 		l.value = zNewline
   1128 		l.token = "\n"
   1129 		zl.comment = string(com[:comi])
   1130 
   1131 		if retL != (lex{}) {
   1132 			zl.nextL = true
   1133 			return retL, true
   1134 		}
   1135 
   1136 		return *l, true
   1137 	}
   1138 
   1139 	if zl.brace != 0 {
   1140 		l.token = "unbalanced brace"
   1141 		l.err = true
   1142 		return *l, true
   1143 	}
   1144 
   1145 	return lex{value: zEOF}, false
   1146 }
   1147 
   1148 func (zl *zlexer) Comment() string {
   1149 	if zl.l.err {
   1150 		return ""
   1151 	}
   1152 
   1153 	return zl.comment
   1154 }
   1155 
   1156 // Extract the class number from CLASSxx
   1157 func classToInt(token string) (uint16, bool) {
   1158 	offset := 5
   1159 	if len(token) < offset+1 {
   1160 		return 0, false
   1161 	}
   1162 	class, err := strconv.ParseUint(token[offset:], 10, 16)
   1163 	if err != nil {
   1164 		return 0, false
   1165 	}
   1166 	return uint16(class), true
   1167 }
   1168 
   1169 // Extract the rr number from TYPExxx
   1170 func typeToInt(token string) (uint16, bool) {
   1171 	offset := 4
   1172 	if len(token) < offset+1 {
   1173 		return 0, false
   1174 	}
   1175 	typ, err := strconv.ParseUint(token[offset:], 10, 16)
   1176 	if err != nil {
   1177 		return 0, false
   1178 	}
   1179 	return uint16(typ), true
   1180 }
   1181 
   1182 // stringToTTL parses things like 2w, 2m, etc, and returns the time in seconds.
   1183 func stringToTTL(token string) (uint32, bool) {
   1184 	var s, i uint32
   1185 	for _, c := range token {
   1186 		switch c {
   1187 		case 's', 'S':
   1188 			s += i
   1189 			i = 0
   1190 		case 'm', 'M':
   1191 			s += i * 60
   1192 			i = 0
   1193 		case 'h', 'H':
   1194 			s += i * 60 * 60
   1195 			i = 0
   1196 		case 'd', 'D':
   1197 			s += i * 60 * 60 * 24
   1198 			i = 0
   1199 		case 'w', 'W':
   1200 			s += i * 60 * 60 * 24 * 7
   1201 			i = 0
   1202 		case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
   1203 			i *= 10
   1204 			i += uint32(c) - '0'
   1205 		default:
   1206 			return 0, false
   1207 		}
   1208 	}
   1209 	return s + i, true
   1210 }
   1211 
   1212 // Parse LOC records' <digits>[.<digits>][mM] into a
   1213 // mantissa exponent format. Token should contain the entire
   1214 // string (i.e. no spaces allowed)
   1215 func stringToCm(token string) (e, m uint8, ok bool) {
   1216 	if token[len(token)-1] == 'M' || token[len(token)-1] == 'm' {
   1217 		token = token[0 : len(token)-1]
   1218 	}
   1219 	s := strings.SplitN(token, ".", 2)
   1220 	var meters, cmeters, val int
   1221 	var err error
   1222 	switch len(s) {
   1223 	case 2:
   1224 		if cmeters, err = strconv.Atoi(s[1]); err != nil {
   1225 			return
   1226 		}
   1227 		// There's no point in having more than 2 digits in this part, and would rather make the implementation complicated ('123' should be treated as '12').
   1228 		// So we simply reject it.
   1229 		// We also make sure the first character is a digit to reject '+-' signs.
   1230 		if len(s[1]) > 2 || s[1][0] < '0' || s[1][0] > '9' {
   1231 			return
   1232 		}
   1233 		if len(s[1]) == 1 {
   1234 			// 'nn.1' must be treated as 'nn-meters and 10cm, not 1cm.
   1235 			cmeters *= 10
   1236 		}
   1237 		if s[0] == "" {
   1238 			// This will allow omitting the 'meter' part, like .01 (meaning 0.01m = 1cm).
   1239 			break
   1240 		}
   1241 		fallthrough
   1242 	case 1:
   1243 		if meters, err = strconv.Atoi(s[0]); err != nil {
   1244 			return
   1245 		}
   1246 		// RFC1876 states the max value is 90000000.00.  The latter two conditions enforce it.
   1247 		if s[0][0] < '0' || s[0][0] > '9' || meters > 90000000 || (meters == 90000000 && cmeters != 0) {
   1248 			return
   1249 		}
   1250 	case 0:
   1251 		// huh?
   1252 		return 0, 0, false
   1253 	}
   1254 	ok = true
   1255 	if meters > 0 {
   1256 		e = 2
   1257 		val = meters
   1258 	} else {
   1259 		e = 0
   1260 		val = cmeters
   1261 	}
   1262 	for val >= 10 {
   1263 		e++
   1264 		val /= 10
   1265 	}
   1266 	m = uint8(val)
   1267 	return
   1268 }
   1269 
   1270 func toAbsoluteName(name, origin string) (absolute string, ok bool) {
   1271 	// check for an explicit origin reference
   1272 	if name == "@" {
   1273 		// require a nonempty origin
   1274 		if origin == "" {
   1275 			return "", false
   1276 		}
   1277 		return origin, true
   1278 	}
   1279 
   1280 	// require a valid domain name
   1281 	_, ok = IsDomainName(name)
   1282 	if !ok || name == "" {
   1283 		return "", false
   1284 	}
   1285 
   1286 	// check if name is already absolute
   1287 	if IsFqdn(name) {
   1288 		return name, true
   1289 	}
   1290 
   1291 	// require a nonempty origin
   1292 	if origin == "" {
   1293 		return "", false
   1294 	}
   1295 	return appendOrigin(name, origin), true
   1296 }
   1297 
   1298 func appendOrigin(name, origin string) string {
   1299 	if origin == "." {
   1300 		return name + origin
   1301 	}
   1302 	return name + "." + origin
   1303 }
   1304 
   1305 // LOC record helper function
   1306 func locCheckNorth(token string, latitude uint32) (uint32, bool) {
   1307 	if latitude > 90*1000*60*60 {
   1308 		return latitude, false
   1309 	}
   1310 	switch token {
   1311 	case "n", "N":
   1312 		return LOC_EQUATOR + latitude, true
   1313 	case "s", "S":
   1314 		return LOC_EQUATOR - latitude, true
   1315 	}
   1316 	return latitude, false
   1317 }
   1318 
   1319 // LOC record helper function
   1320 func locCheckEast(token string, longitude uint32) (uint32, bool) {
   1321 	if longitude > 180*1000*60*60 {
   1322 		return longitude, false
   1323 	}
   1324 	switch token {
   1325 	case "e", "E":
   1326 		return LOC_EQUATOR + longitude, true
   1327 	case "w", "W":
   1328 		return LOC_EQUATOR - longitude, true
   1329 	}
   1330 	return longitude, false
   1331 }
   1332 
   1333 // "Eat" the rest of the "line"
   1334 func slurpRemainder(c *zlexer) *ParseError {
   1335 	l, _ := c.Next()
   1336 	switch l.value {
   1337 	case zBlank:
   1338 		l, _ = c.Next()
   1339 		if l.value != zNewline && l.value != zEOF {
   1340 			return &ParseError{"", "garbage after rdata", l}
   1341 		}
   1342 	case zNewline:
   1343 	case zEOF:
   1344 	default:
   1345 		return &ParseError{"", "garbage after rdata", l}
   1346 	}
   1347 	return nil
   1348 }
   1349 
   1350 // Parse a 64 bit-like ipv6 address: "0014:4fff:ff20:ee64"
   1351 // Used for NID and L64 record.
   1352 func stringToNodeID(l lex) (uint64, *ParseError) {
   1353 	if len(l.token) < 19 {
   1354 		return 0, &ParseError{l.token, "bad NID/L64 NodeID/Locator64", l}
   1355 	}
   1356 	// There must be three colons at fixes positions, if not its a parse error
   1357 	if l.token[4] != ':' && l.token[9] != ':' && l.token[14] != ':' {
   1358 		return 0, &ParseError{l.token, "bad NID/L64 NodeID/Locator64", l}
   1359 	}
   1360 	s := l.token[0:4] + l.token[5:9] + l.token[10:14] + l.token[15:19]
   1361 	u, err := strconv.ParseUint(s, 16, 64)
   1362 	if err != nil {
   1363 		return 0, &ParseError{l.token, "bad NID/L64 NodeID/Locator64", l}
   1364 	}
   1365 	return u, nil
   1366 }