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 }