2011-12-14 19:26:31 +11:00
|
|
|
package dns
|
2011-12-14 19:00:39 +11:00
|
|
|
|
|
|
|
import (
|
2017-12-07 09:03:54 +11:00
|
|
|
"fmt"
|
2011-12-14 19:26:31 +11:00
|
|
|
"io"
|
2012-01-22 09:36:54 +11:00
|
|
|
"os"
|
2017-12-07 09:03:54 +11:00
|
|
|
"path/filepath"
|
2011-12-14 19:00:39 +11:00
|
|
|
"strconv"
|
|
|
|
"strings"
|
|
|
|
)
|
|
|
|
|
2012-12-02 18:31:56 +11:00
|
|
|
const maxTok = 2048 // Largest token we can return.
|
2013-12-05 20:54:46 +11:00
|
|
|
const maxUint16 = 1<<16 - 1
|
2011-12-16 20:30:42 +11:00
|
|
|
|
2011-12-14 19:00:39 +11:00
|
|
|
// Tokinize a RFC 1035 zone file. The tokenizer will normalize it:
|
2011-12-15 22:27:05 +11:00
|
|
|
// * Add ownernames if they are left blank;
|
2011-12-14 19:00:39 +11:00
|
|
|
// * Suppress sequences of spaces;
|
2012-12-02 18:31:56 +11:00
|
|
|
// * Make each RR fit on one line (_NEWLINE is send as last)
|
2011-12-14 19:00:39 +11:00
|
|
|
// * Handle comments: ;
|
2012-12-02 18:31:56 +11:00
|
|
|
// * Handle braces - anywhere.
|
2011-12-14 19:00:39 +11:00
|
|
|
const (
|
2011-12-16 08:40:07 +11:00
|
|
|
// Zonefile
|
2015-02-19 21:45:59 +11:00
|
|
|
zEOF = iota
|
|
|
|
zString
|
|
|
|
zBlank
|
|
|
|
zQuote
|
|
|
|
zNewline
|
|
|
|
zRrtpe
|
|
|
|
zOwner
|
|
|
|
zClass
|
|
|
|
zDirOrigin // $ORIGIN
|
2017-11-04 03:15:35 +11:00
|
|
|
zDirTTL // $TTL
|
2015-02-19 21:45:59 +11:00
|
|
|
zDirInclude // $INCLUDE
|
|
|
|
zDirGenerate // $GENERATE
|
2011-12-14 19:00:39 +11:00
|
|
|
|
2011-12-16 08:40:07 +11:00
|
|
|
// Privatekey file
|
2015-02-19 21:45:59 +11:00
|
|
|
zValue
|
|
|
|
zKey
|
2011-12-15 23:03:51 +11:00
|
|
|
|
2015-02-19 21:59:15 +11:00
|
|
|
zExpectOwnerDir // Ownername
|
|
|
|
zExpectOwnerBl // Whitespace after the ownername
|
|
|
|
zExpectAny // Expect rrtype, ttl or class
|
|
|
|
zExpectAnyNoClass // Expect rrtype or ttl
|
|
|
|
zExpectAnyNoClassBl // The whitespace after _EXPECT_ANY_NOCLASS
|
2017-11-04 03:15:35 +11:00
|
|
|
zExpectAnyNoTTL // Expect rrtype or class
|
|
|
|
zExpectAnyNoTTLBl // Whitespace after _EXPECT_ANY_NOTTL
|
2015-02-19 21:59:15 +11:00
|
|
|
zExpectRrtype // Expect rrtype
|
|
|
|
zExpectRrtypeBl // Whitespace BEFORE rrtype
|
|
|
|
zExpectRdata // The first element of the rdata
|
2017-11-04 03:15:35 +11:00
|
|
|
zExpectDirTTLBl // Space after directive $TTL
|
|
|
|
zExpectDirTTL // Directive $TTL
|
2015-02-19 21:59:15 +11:00
|
|
|
zExpectDirOriginBl // Space after directive $ORIGIN
|
|
|
|
zExpectDirOrigin // Directive $ORIGIN
|
|
|
|
zExpectDirIncludeBl // Space after directive $INCLUDE
|
|
|
|
zExpectDirInclude // Directive $INCLUDE
|
|
|
|
zExpectDirGenerate // Directive $GENERATE
|
|
|
|
zExpectDirGenerateBl // Space after directive $GENERATE
|
2011-12-14 19:00:39 +11:00
|
|
|
)
|
|
|
|
|
2012-05-08 22:17:17 +10:00
|
|
|
// ParseError is a parsing error. It contains the parse error and the location in the io.Reader
|
2016-01-04 14:16:50 +11:00
|
|
|
// where the error occurred.
|
2011-12-14 21:30:29 +11:00
|
|
|
type ParseError struct {
|
2012-01-22 09:36:54 +11:00
|
|
|
file string
|
|
|
|
err string
|
|
|
|
lex lex
|
2011-12-14 21:30:29 +11:00
|
|
|
}
|
|
|
|
|
2012-01-22 09:36:54 +11:00
|
|
|
func (e *ParseError) Error() (s string) {
|
|
|
|
if e.file != "" {
|
|
|
|
s = e.file + ": "
|
|
|
|
}
|
2012-03-04 03:40:30 +11:00
|
|
|
s += "dns: " + e.err + ": " + strconv.QuoteToASCII(e.lex.token) + " at line: " +
|
2012-11-22 08:21:40 +11:00
|
|
|
strconv.Itoa(e.lex.line) + ":" + strconv.Itoa(e.lex.column)
|
2012-01-22 09:36:54 +11:00
|
|
|
return
|
2011-12-14 21:30:29 +11:00
|
|
|
}
|
|
|
|
|
2011-12-17 05:34:30 +11:00
|
|
|
type lex struct {
|
2014-08-28 22:00:15 +10:00
|
|
|
token string // text of the token
|
|
|
|
tokenUpper string // uppercase text of the token
|
2016-01-04 14:16:50 +11:00
|
|
|
length int // length of the token
|
2014-08-28 22:00:15 +10:00
|
|
|
err bool // when true, token text has lexer error
|
2015-02-21 08:16:49 +11:00
|
|
|
value uint8 // value: zString, _BLANK, etc.
|
2014-08-28 22:00:15 +10:00
|
|
|
line int // line in the file
|
|
|
|
column int // column in the file
|
|
|
|
torc uint16 // type or class as parsed in the lexer, we only need to look this up in the grammar
|
|
|
|
comment string // any comment text seen
|
2011-12-14 19:00:39 +11:00
|
|
|
}
|
|
|
|
|
2015-02-19 20:58:33 +11:00
|
|
|
// Token holds the token that are returned when a zone file is parsed.
|
2011-12-16 20:06:28 +11:00
|
|
|
type Token struct {
|
2015-02-19 20:58:33 +11:00
|
|
|
// The scanned resource record when error is not nil.
|
|
|
|
RR
|
2016-01-04 14:16:50 +11:00
|
|
|
// When an error occurred, this has the error specifics.
|
2015-02-19 20:58:33 +11:00
|
|
|
Error *ParseError
|
|
|
|
// A potential comment positioned after the RR and on the same line.
|
|
|
|
Comment string
|
2011-12-16 20:06:28 +11:00
|
|
|
}
|
|
|
|
|
2017-09-27 01:15:37 +10:00
|
|
|
// ttlState describes the state necessary to fill in an omitted RR TTL
|
|
|
|
type ttlState struct {
|
|
|
|
ttl uint32 // ttl is the current default TTL
|
|
|
|
isByDirective bool // isByDirective indicates whether ttl was set by a $TTL directive
|
|
|
|
}
|
|
|
|
|
2015-01-11 17:33:47 +11:00
|
|
|
// NewRR reads the RR contained in the string s. Only the first RR is
|
|
|
|
// returned. If s contains no RR, return nil with no error. The class
|
|
|
|
// defaults to IN and TTL defaults to 3600. The full zone file syntax
|
|
|
|
// like $TTL, $ORIGIN, etc. is supported. All fields of the returned
|
|
|
|
// RR are set, except RR.Header().Rdlength which is set to 0.
|
2011-12-16 03:37:07 +11:00
|
|
|
func NewRR(s string) (RR, error) {
|
2015-01-11 17:33:47 +11:00
|
|
|
if len(s) > 0 && s[len(s)-1] != '\n' { // We need a closing newline
|
2012-01-28 09:59:21 +11:00
|
|
|
return ReadRR(strings.NewReader(s+"\n"), "")
|
2011-12-16 20:06:28 +11:00
|
|
|
}
|
2012-01-28 09:59:21 +11:00
|
|
|
return ReadRR(strings.NewReader(s), "")
|
2012-01-23 06:20:30 +11:00
|
|
|
}
|
|
|
|
|
2014-04-24 19:55:55 +10:00
|
|
|
// ReadRR reads the RR contained in q.
|
2014-04-21 18:10:39 +10:00
|
|
|
// See NewRR for more documentation.
|
2012-01-23 06:20:30 +11:00
|
|
|
func ReadRR(q io.Reader, filename string) (RR, error) {
|
2017-09-27 01:15:37 +10:00
|
|
|
defttl := &ttlState{defaultTtl, false}
|
2017-11-17 21:48:42 +11:00
|
|
|
r := <-parseZoneHelper(q, ".", filename, defttl, 1)
|
2015-01-11 17:33:47 +11:00
|
|
|
if r == nil {
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
2012-01-28 09:59:21 +11:00
|
|
|
if r.Error != nil {
|
|
|
|
return nil, r.Error
|
|
|
|
}
|
|
|
|
return r.RR, nil
|
2011-12-14 21:30:29 +11:00
|
|
|
}
|
|
|
|
|
2015-08-08 05:58:26 +10:00
|
|
|
// ParseZone reads a RFC 1035 style zonefile from r. It returns *Tokens on the
|
2017-09-27 01:15:37 +10:00
|
|
|
// returned channel, each consisting of either a parsed RR and optional comment
|
|
|
|
// or a nil RR and an error. The string file is only used
|
2012-02-15 22:50:23 +11:00
|
|
|
// in error reporting. The string origin is used as the initial origin, as
|
2017-09-27 01:15:37 +10:00
|
|
|
// if the file would start with an $ORIGIN directive.
|
2012-05-21 01:39:06 +10:00
|
|
|
// The directives $INCLUDE, $ORIGIN, $TTL and $GENERATE are supported.
|
2012-02-14 03:52:53 +11:00
|
|
|
// The channel t is closed by ParseZone when the end of r is reached.
|
2012-05-03 17:05:30 +10:00
|
|
|
//
|
2013-05-06 04:30:44 +10:00
|
|
|
// Basic usage pattern when reading from a string (z) containing the
|
2012-05-03 17:05:30 +10:00
|
|
|
// zone data:
|
|
|
|
//
|
2012-05-21 04:46:25 +10:00
|
|
|
// for x := range dns.ParseZone(strings.NewReader(z), "", "") {
|
2012-05-03 17:05:30 +10:00
|
|
|
// if x.Error != nil {
|
2015-10-05 21:09:22 +11:00
|
|
|
// // log.Println(x.Error)
|
|
|
|
// } else {
|
|
|
|
// // Do something with x.RR
|
|
|
|
// }
|
2013-03-04 22:16:20 +11:00
|
|
|
// }
|
|
|
|
//
|
2013-03-05 03:21:34 +11:00
|
|
|
// Comments specified after an RR (and on the same line!) are returned too:
|
2013-05-06 04:30:44 +10:00
|
|
|
//
|
2013-03-04 22:16:20 +11:00
|
|
|
// foo. IN A 10.0.0.1 ; this is a comment
|
|
|
|
//
|
2015-08-08 05:58:26 +10:00
|
|
|
// The text "; this is comment" is returned in Token.Comment. Comments inside the
|
2013-03-05 03:21:34 +11:00
|
|
|
// RR are discarded. Comments on a line by themselves are discarded too.
|
2013-11-10 06:34:46 +11:00
|
|
|
func ParseZone(r io.Reader, origin, file string) chan *Token {
|
2017-11-17 21:48:42 +11:00
|
|
|
return parseZoneHelper(r, origin, file, nil, 10000)
|
2012-07-04 04:06:02 +10:00
|
|
|
}
|
|
|
|
|
2017-11-17 21:48:42 +11:00
|
|
|
func parseZoneHelper(r io.Reader, origin, file string, defttl *ttlState, chansize int) chan *Token {
|
2013-11-10 06:34:46 +11:00
|
|
|
t := make(chan *Token, chansize)
|
2017-11-17 21:48:42 +11:00
|
|
|
go parseZone(r, origin, file, defttl, t, 0)
|
2012-01-09 00:06:58 +11:00
|
|
|
return t
|
2011-12-20 05:20:55 +11:00
|
|
|
}
|
|
|
|
|
2017-11-17 21:48:42 +11:00
|
|
|
func parseZone(r io.Reader, origin, f string, defttl *ttlState, t chan *Token, include int) {
|
2012-01-22 09:36:54 +11:00
|
|
|
defer func() {
|
|
|
|
if include == 0 {
|
|
|
|
close(t)
|
|
|
|
}
|
|
|
|
}()
|
2017-11-17 21:47:28 +11:00
|
|
|
s, cancel := scanInit(r)
|
2015-03-19 20:18:25 +11:00
|
|
|
c := make(chan lex)
|
2011-12-14 21:30:29 +11:00
|
|
|
// Start the lexer
|
2012-01-05 23:24:35 +11:00
|
|
|
go zlexer(s, c)
|
2017-11-17 21:47:28 +11:00
|
|
|
|
|
|
|
defer func() {
|
|
|
|
cancel()
|
|
|
|
// zlexer can send up to three tokens, the next one and possibly 2 remainders.
|
|
|
|
// Do a non-blocking read.
|
|
|
|
_, ok := <-c
|
|
|
|
_, ok = <-c
|
|
|
|
_, ok = <-c
|
|
|
|
if !ok {
|
|
|
|
// too bad
|
|
|
|
}
|
|
|
|
}()
|
2012-02-15 18:47:31 +11:00
|
|
|
// 6 possible beginnings of a line, _ is a space
|
2015-02-21 08:16:49 +11:00
|
|
|
// 0. zRRTYPE -> all omitted until the rrtype
|
|
|
|
// 1. zOwner _ zRrtype -> class/ttl omitted
|
|
|
|
// 2. zOwner _ zString _ zRrtype -> class omitted
|
|
|
|
// 3. zOwner _ zString _ zClass _ zRrtype -> ttl/class
|
|
|
|
// 4. zOwner _ zClass _ zRrtype -> ttl omitted
|
|
|
|
// 5. zOwner _ zClass _ zString _ zRrtype -> class/ttl (reversed)
|
|
|
|
// After detecting these, we know the zRrtype so we can jump to functions
|
2011-12-14 19:00:39 +11:00
|
|
|
// handling the rdata for each of these types.
|
2012-02-14 23:46:40 +11:00
|
|
|
|
2017-09-27 01:15:37 +10:00
|
|
|
if origin != "" {
|
|
|
|
origin = Fqdn(origin)
|
|
|
|
if _, ok := IsDomainName(origin); !ok {
|
|
|
|
t <- &Token{Error: &ParseError{f, "bad initial origin name", lex{}}}
|
|
|
|
return
|
|
|
|
}
|
2012-02-15 18:47:31 +11:00
|
|
|
}
|
2012-07-17 03:46:16 +10:00
|
|
|
|
2015-02-19 21:59:15 +11:00
|
|
|
st := zExpectOwnerDir // initial state
|
2011-12-14 19:26:31 +11:00
|
|
|
var h RR_Header
|
2012-02-15 18:47:31 +11:00
|
|
|
var prevName string
|
2011-12-14 19:00:39 +11:00
|
|
|
for l := range c {
|
2011-12-17 21:28:54 +11:00
|
|
|
// Lexer spotted an error already
|
2012-02-24 06:13:37 +11:00
|
|
|
if l.err == true {
|
2013-11-10 06:34:46 +11:00
|
|
|
t <- &Token{Error: &ParseError{f, l.token, l}}
|
2011-12-17 21:28:54 +11:00
|
|
|
return
|
|
|
|
|
|
|
|
}
|
2011-12-14 19:00:39 +11:00
|
|
|
switch st {
|
2015-02-19 21:59:15 +11:00
|
|
|
case zExpectOwnerDir:
|
2011-12-19 03:58:06 +11:00
|
|
|
// We can also expect a directive, like $TTL or $ORIGIN
|
2017-09-27 01:15:37 +10:00
|
|
|
if defttl != nil {
|
|
|
|
h.Ttl = defttl.ttl
|
|
|
|
}
|
2011-12-16 20:06:28 +11:00
|
|
|
h.Class = ClassINET
|
2011-12-14 19:00:39 +11:00
|
|
|
switch l.value {
|
2015-02-19 21:45:59 +11:00
|
|
|
case zNewline:
|
2015-02-19 21:59:15 +11:00
|
|
|
st = zExpectOwnerDir
|
2015-02-19 21:45:59 +11:00
|
|
|
case zOwner:
|
2011-12-14 19:00:39 +11:00
|
|
|
h.Name = l.token
|
2017-09-27 01:15:37 +10:00
|
|
|
name, ok := toAbsoluteName(l.token, origin)
|
2012-02-05 21:33:55 +11:00
|
|
|
if !ok {
|
2013-11-10 06:34:46 +11:00
|
|
|
t <- &Token{Error: &ParseError{f, "bad owner name", l}}
|
2012-01-13 08:49:26 +11:00
|
|
|
return
|
|
|
|
}
|
2017-09-27 01:15:37 +10:00
|
|
|
h.Name = name
|
2012-02-15 18:47:31 +11:00
|
|
|
prevName = h.Name
|
2015-02-19 21:59:15 +11:00
|
|
|
st = zExpectOwnerBl
|
2017-11-04 03:15:35 +11:00
|
|
|
case zDirTTL:
|
|
|
|
st = zExpectDirTTLBl
|
2015-02-19 21:45:59 +11:00
|
|
|
case zDirOrigin:
|
2015-02-19 21:59:15 +11:00
|
|
|
st = zExpectDirOriginBl
|
2015-02-19 21:45:59 +11:00
|
|
|
case zDirInclude:
|
2015-02-19 21:59:15 +11:00
|
|
|
st = zExpectDirIncludeBl
|
2015-02-19 21:45:59 +11:00
|
|
|
case zDirGenerate:
|
2015-02-19 21:59:15 +11:00
|
|
|
st = zExpectDirGenerateBl
|
2015-02-19 21:45:59 +11:00
|
|
|
case zRrtpe:
|
2012-02-15 18:47:31 +11:00
|
|
|
h.Name = prevName
|
2012-02-28 07:12:04 +11:00
|
|
|
h.Rrtype = l.torc
|
2015-02-19 21:59:15 +11:00
|
|
|
st = zExpectRdata
|
2015-02-19 21:45:59 +11:00
|
|
|
case zClass:
|
2012-02-28 04:48:53 +11:00
|
|
|
h.Name = prevName
|
2012-02-28 07:12:04 +11:00
|
|
|
h.Class = l.torc
|
2015-02-19 21:59:15 +11:00
|
|
|
st = zExpectAnyNoClassBl
|
2015-02-19 21:45:59 +11:00
|
|
|
case zBlank:
|
2012-02-15 18:47:31 +11:00
|
|
|
// Discard, can happen when there is nothing on the
|
|
|
|
// line except the RR type
|
2015-02-19 21:45:59 +11:00
|
|
|
case zString:
|
2017-11-04 03:15:35 +11:00
|
|
|
ttl, ok := stringToTTL(l.token)
|
2015-02-19 22:36:40 +11:00
|
|
|
if !ok {
|
2013-11-10 06:34:46 +11:00
|
|
|
t <- &Token{Error: &ParseError{f, "not a TTL", l}}
|
2012-02-28 04:48:53 +11:00
|
|
|
return
|
|
|
|
}
|
2015-02-19 22:36:40 +11:00
|
|
|
h.Ttl = ttl
|
2017-09-27 01:15:37 +10:00
|
|
|
if defttl == nil || !defttl.isByDirective {
|
|
|
|
defttl = &ttlState{ttl, false}
|
|
|
|
}
|
2017-11-04 03:15:35 +11:00
|
|
|
st = zExpectAnyNoTTLBl
|
2012-02-28 07:12:04 +11:00
|
|
|
|
2011-12-14 19:00:39 +11:00
|
|
|
default:
|
2013-11-10 06:34:46 +11:00
|
|
|
t <- &Token{Error: &ParseError{f, "syntax error at beginning", l}}
|
2012-01-22 09:36:54 +11:00
|
|
|
return
|
|
|
|
}
|
2015-02-19 21:59:15 +11:00
|
|
|
case zExpectDirIncludeBl:
|
2015-02-19 21:45:59 +11:00
|
|
|
if l.value != zBlank {
|
2013-11-10 06:34:46 +11:00
|
|
|
t <- &Token{Error: &ParseError{f, "no blank after $INCLUDE-directive", l}}
|
2011-12-16 20:06:28 +11:00
|
|
|
return
|
2011-12-14 19:00:39 +11:00
|
|
|
}
|
2015-02-19 21:59:15 +11:00
|
|
|
st = zExpectDirInclude
|
|
|
|
case zExpectDirInclude:
|
2015-02-19 21:45:59 +11:00
|
|
|
if l.value != zString {
|
2013-11-10 06:34:46 +11:00
|
|
|
t <- &Token{Error: &ParseError{f, "expecting $INCLUDE value, not this...", l}}
|
2012-01-22 09:36:54 +11:00
|
|
|
return
|
|
|
|
}
|
2012-12-13 20:08:35 +11:00
|
|
|
neworigin := origin // There may be optionally a new origin set after the filename, if not use current one
|
2017-08-09 08:19:10 +10:00
|
|
|
switch l := <-c; l.value {
|
2015-02-19 21:45:59 +11:00
|
|
|
case zBlank:
|
2012-12-13 20:08:35 +11:00
|
|
|
l := <-c
|
2015-02-19 21:45:59 +11:00
|
|
|
if l.value == zString {
|
2017-09-27 01:15:37 +10:00
|
|
|
name, ok := toAbsoluteName(l.token, origin)
|
|
|
|
if !ok {
|
2013-11-10 06:34:46 +11:00
|
|
|
t <- &Token{Error: &ParseError{f, "bad origin name", l}}
|
2012-12-13 20:14:22 +11:00
|
|
|
return
|
|
|
|
}
|
2017-09-27 01:15:37 +10:00
|
|
|
neworigin = name
|
2012-12-13 20:08:35 +11:00
|
|
|
}
|
2015-02-19 21:45:59 +11:00
|
|
|
case zNewline, zEOF:
|
2012-12-13 20:08:35 +11:00
|
|
|
// Ok
|
|
|
|
default:
|
2013-11-10 06:34:46 +11:00
|
|
|
t <- &Token{Error: &ParseError{f, "garbage after $INCLUDE", l}}
|
2012-12-13 20:08:35 +11:00
|
|
|
return
|
2012-02-14 07:12:14 +11:00
|
|
|
}
|
2012-01-22 09:36:54 +11:00
|
|
|
// Start with the new file
|
2017-12-07 09:03:54 +11:00
|
|
|
includePath := l.token
|
|
|
|
if !filepath.IsAbs(includePath) {
|
|
|
|
includePath = filepath.Join(filepath.Dir(f), includePath)
|
|
|
|
}
|
2017-12-08 04:12:20 +11:00
|
|
|
r1, e1 := os.Open(includePath)
|
2012-01-22 09:42:33 +11:00
|
|
|
if e1 != nil {
|
2017-12-07 09:03:54 +11:00
|
|
|
msg := fmt.Sprintf("failed to open `%s'", l.token)
|
|
|
|
if !filepath.IsAbs(l.token) {
|
|
|
|
msg += fmt.Sprintf(" as `%s'", includePath)
|
|
|
|
}
|
|
|
|
t <- &Token{Error: &ParseError{f, msg, l}}
|
2012-01-22 09:42:33 +11:00
|
|
|
return
|
|
|
|
}
|
2012-01-28 09:59:21 +11:00
|
|
|
if include+1 > 7 {
|
2013-11-10 06:34:46 +11:00
|
|
|
t <- &Token{Error: &ParseError{f, "too deeply nested $INCLUDE", l}}
|
2012-01-28 09:59:21 +11:00
|
|
|
return
|
|
|
|
}
|
2017-12-07 09:03:54 +11:00
|
|
|
parseZone(r1, neworigin, includePath, defttl, t, include+1)
|
2015-02-19 21:59:15 +11:00
|
|
|
st = zExpectOwnerDir
|
2017-11-04 03:15:35 +11:00
|
|
|
case zExpectDirTTLBl:
|
2015-02-19 21:45:59 +11:00
|
|
|
if l.value != zBlank {
|
2013-11-10 06:34:46 +11:00
|
|
|
t <- &Token{Error: &ParseError{f, "no blank after $TTL-directive", l}}
|
2011-12-19 03:58:06 +11:00
|
|
|
return
|
|
|
|
}
|
2017-11-04 03:15:35 +11:00
|
|
|
st = zExpectDirTTL
|
|
|
|
case zExpectDirTTL:
|
2015-02-19 21:45:59 +11:00
|
|
|
if l.value != zString {
|
2013-11-10 06:34:46 +11:00
|
|
|
t <- &Token{Error: &ParseError{f, "expecting $TTL value, not this...", l}}
|
2011-12-19 03:58:06 +11:00
|
|
|
return
|
|
|
|
}
|
2013-03-04 21:24:08 +11:00
|
|
|
if e, _ := slurpRemainder(c, f); e != nil {
|
2013-11-10 06:34:46 +11:00
|
|
|
t <- &Token{Error: e}
|
2012-02-15 18:47:31 +11:00
|
|
|
return
|
2012-02-14 07:12:14 +11:00
|
|
|
}
|
2017-11-04 03:15:35 +11:00
|
|
|
ttl, ok := stringToTTL(l.token)
|
2015-02-19 22:36:40 +11:00
|
|
|
if !ok {
|
2013-11-10 06:34:46 +11:00
|
|
|
t <- &Token{Error: &ParseError{f, "expecting $TTL value, not this...", l}}
|
2011-12-19 03:58:06 +11:00
|
|
|
return
|
|
|
|
}
|
2017-09-27 01:15:37 +10:00
|
|
|
defttl = &ttlState{ttl, true}
|
2015-02-19 21:59:15 +11:00
|
|
|
st = zExpectOwnerDir
|
|
|
|
case zExpectDirOriginBl:
|
2015-02-19 21:45:59 +11:00
|
|
|
if l.value != zBlank {
|
2013-11-10 06:34:46 +11:00
|
|
|
t <- &Token{Error: &ParseError{f, "no blank after $ORIGIN-directive", l}}
|
2012-01-13 08:49:26 +11:00
|
|
|
return
|
|
|
|
}
|
2015-02-19 21:59:15 +11:00
|
|
|
st = zExpectDirOrigin
|
|
|
|
case zExpectDirOrigin:
|
2015-02-19 21:45:59 +11:00
|
|
|
if l.value != zString {
|
2013-11-10 06:34:46 +11:00
|
|
|
t <- &Token{Error: &ParseError{f, "expecting $ORIGIN value, not this...", l}}
|
2012-01-13 08:49:26 +11:00
|
|
|
return
|
|
|
|
}
|
2013-03-04 21:24:08 +11:00
|
|
|
if e, _ := slurpRemainder(c, f); e != nil {
|
2013-11-10 06:34:46 +11:00
|
|
|
t <- &Token{Error: e}
|
2012-02-14 07:12:14 +11:00
|
|
|
}
|
2017-09-27 01:15:37 +10:00
|
|
|
name, ok := toAbsoluteName(l.token, origin)
|
|
|
|
if !ok {
|
2013-11-10 06:34:46 +11:00
|
|
|
t <- &Token{Error: &ParseError{f, "bad origin name", l}}
|
2012-12-13 20:14:22 +11:00
|
|
|
return
|
|
|
|
}
|
2017-09-27 01:15:37 +10:00
|
|
|
origin = name
|
2015-02-19 21:59:15 +11:00
|
|
|
st = zExpectOwnerDir
|
|
|
|
case zExpectDirGenerateBl:
|
2015-02-19 21:45:59 +11:00
|
|
|
if l.value != zBlank {
|
2013-11-10 06:34:46 +11:00
|
|
|
t <- &Token{Error: &ParseError{f, "no blank after $GENERATE-directive", l}}
|
2012-05-20 23:28:27 +10:00
|
|
|
return
|
|
|
|
}
|
2015-02-19 21:59:15 +11:00
|
|
|
st = zExpectDirGenerate
|
|
|
|
case zExpectDirGenerate:
|
2015-02-19 21:45:59 +11:00
|
|
|
if l.value != zString {
|
2013-11-10 06:34:46 +11:00
|
|
|
t <- &Token{Error: &ParseError{f, "expecting $GENERATE value, not this...", l}}
|
2012-05-20 23:28:27 +10:00
|
|
|
return
|
|
|
|
}
|
2016-06-09 16:00:08 +10:00
|
|
|
if errMsg := generate(l, c, t, origin); errMsg != "" {
|
|
|
|
t <- &Token{Error: &ParseError{f, errMsg, l}}
|
2012-05-20 23:28:27 +10:00
|
|
|
return
|
|
|
|
}
|
2015-02-19 21:59:15 +11:00
|
|
|
st = zExpectOwnerDir
|
|
|
|
case zExpectOwnerBl:
|
2015-02-19 21:45:59 +11:00
|
|
|
if l.value != zBlank {
|
2013-11-10 06:34:46 +11:00
|
|
|
t <- &Token{Error: &ParseError{f, "no blank after owner", l}}
|
2011-12-16 20:06:28 +11:00
|
|
|
return
|
2011-12-14 19:00:39 +11:00
|
|
|
}
|
2015-02-19 21:59:15 +11:00
|
|
|
st = zExpectAny
|
|
|
|
case zExpectAny:
|
2011-12-14 19:00:39 +11:00
|
|
|
switch l.value {
|
2015-02-19 21:45:59 +11:00
|
|
|
case zRrtpe:
|
2017-09-27 01:15:37 +10:00
|
|
|
if defttl == nil {
|
|
|
|
t <- &Token{Error: &ParseError{f, "missing TTL with no previous value", l}}
|
|
|
|
return
|
|
|
|
}
|
2012-02-28 07:12:04 +11:00
|
|
|
h.Rrtype = l.torc
|
2015-02-19 21:59:15 +11:00
|
|
|
st = zExpectRdata
|
2015-02-19 21:45:59 +11:00
|
|
|
case zClass:
|
2012-02-28 07:12:04 +11:00
|
|
|
h.Class = l.torc
|
2015-02-19 21:59:15 +11:00
|
|
|
st = zExpectAnyNoClassBl
|
2015-02-19 21:45:59 +11:00
|
|
|
case zString:
|
2017-11-04 03:15:35 +11:00
|
|
|
ttl, ok := stringToTTL(l.token)
|
2015-02-19 22:36:40 +11:00
|
|
|
if !ok {
|
2013-11-10 06:34:46 +11:00
|
|
|
t <- &Token{Error: &ParseError{f, "not a TTL", l}}
|
2011-12-16 20:06:28 +11:00
|
|
|
return
|
2011-12-14 19:00:39 +11:00
|
|
|
}
|
2015-02-19 22:36:40 +11:00
|
|
|
h.Ttl = ttl
|
2017-09-27 01:15:37 +10:00
|
|
|
if defttl == nil || !defttl.isByDirective {
|
|
|
|
defttl = &ttlState{ttl, false}
|
|
|
|
}
|
2017-11-04 03:15:35 +11:00
|
|
|
st = zExpectAnyNoTTLBl
|
2011-12-14 19:00:39 +11:00
|
|
|
default:
|
2013-11-10 06:34:46 +11:00
|
|
|
t <- &Token{Error: &ParseError{f, "expecting RR type, TTL or class, not this...", l}}
|
2011-12-16 20:06:28 +11:00
|
|
|
return
|
2011-12-14 19:00:39 +11:00
|
|
|
}
|
2015-02-19 21:59:15 +11:00
|
|
|
case zExpectAnyNoClassBl:
|
2015-02-19 21:45:59 +11:00
|
|
|
if l.value != zBlank {
|
2013-11-10 06:34:46 +11:00
|
|
|
t <- &Token{Error: &ParseError{f, "no blank before class", l}}
|
2011-12-16 20:06:28 +11:00
|
|
|
return
|
2011-12-14 19:00:39 +11:00
|
|
|
}
|
2015-02-19 21:59:15 +11:00
|
|
|
st = zExpectAnyNoClass
|
2017-11-04 03:15:35 +11:00
|
|
|
case zExpectAnyNoTTLBl:
|
2015-02-19 21:45:59 +11:00
|
|
|
if l.value != zBlank {
|
2013-11-10 06:34:46 +11:00
|
|
|
t <- &Token{Error: &ParseError{f, "no blank before TTL", l}}
|
2011-12-16 20:06:28 +11:00
|
|
|
return
|
2011-12-14 19:00:39 +11:00
|
|
|
}
|
2017-11-04 03:15:35 +11:00
|
|
|
st = zExpectAnyNoTTL
|
|
|
|
case zExpectAnyNoTTL:
|
2011-12-14 19:00:39 +11:00
|
|
|
switch l.value {
|
2015-02-19 21:45:59 +11:00
|
|
|
case zClass:
|
2012-02-28 07:12:04 +11:00
|
|
|
h.Class = l.torc
|
2015-02-19 21:59:15 +11:00
|
|
|
st = zExpectRrtypeBl
|
2015-02-19 21:45:59 +11:00
|
|
|
case zRrtpe:
|
2012-02-28 07:12:04 +11:00
|
|
|
h.Rrtype = l.torc
|
2015-02-19 21:59:15 +11:00
|
|
|
st = zExpectRdata
|
2012-03-04 20:41:16 +11:00
|
|
|
default:
|
2013-11-10 06:34:46 +11:00
|
|
|
t <- &Token{Error: &ParseError{f, "expecting RR type or class, not this...", l}}
|
2012-03-04 03:40:30 +11:00
|
|
|
return
|
2011-12-14 19:00:39 +11:00
|
|
|
}
|
2015-02-19 21:59:15 +11:00
|
|
|
case zExpectAnyNoClass:
|
2011-12-14 19:00:39 +11:00
|
|
|
switch l.value {
|
2015-02-19 21:45:59 +11:00
|
|
|
case zString:
|
2017-11-04 03:15:35 +11:00
|
|
|
ttl, ok := stringToTTL(l.token)
|
2015-02-19 22:36:40 +11:00
|
|
|
if !ok {
|
2013-11-10 06:34:46 +11:00
|
|
|
t <- &Token{Error: &ParseError{f, "not a TTL", l}}
|
2011-12-16 20:06:28 +11:00
|
|
|
return
|
2011-12-14 19:00:39 +11:00
|
|
|
}
|
2015-02-19 22:36:40 +11:00
|
|
|
h.Ttl = ttl
|
2017-09-27 01:15:37 +10:00
|
|
|
if defttl == nil || !defttl.isByDirective {
|
|
|
|
defttl = &ttlState{ttl, false}
|
|
|
|
}
|
2015-02-19 21:59:15 +11:00
|
|
|
st = zExpectRrtypeBl
|
2015-02-19 21:45:59 +11:00
|
|
|
case zRrtpe:
|
2012-02-28 07:12:04 +11:00
|
|
|
h.Rrtype = l.torc
|
2015-02-19 21:59:15 +11:00
|
|
|
st = zExpectRdata
|
2011-12-14 19:00:39 +11:00
|
|
|
default:
|
2013-11-10 06:34:46 +11:00
|
|
|
t <- &Token{Error: &ParseError{f, "expecting RR type or TTL, not this...", l}}
|
2011-12-16 20:06:28 +11:00
|
|
|
return
|
2011-12-14 19:00:39 +11:00
|
|
|
}
|
2015-02-19 21:59:15 +11:00
|
|
|
case zExpectRrtypeBl:
|
2015-02-19 21:45:59 +11:00
|
|
|
if l.value != zBlank {
|
2013-11-10 06:34:46 +11:00
|
|
|
t <- &Token{Error: &ParseError{f, "no blank before RR type", l}}
|
2011-12-16 20:06:28 +11:00
|
|
|
return
|
2011-12-14 19:00:39 +11:00
|
|
|
}
|
2015-02-19 21:59:15 +11:00
|
|
|
st = zExpectRrtype
|
|
|
|
case zExpectRrtype:
|
2015-02-19 21:45:59 +11:00
|
|
|
if l.value != zRrtpe {
|
2013-11-10 06:34:46 +11:00
|
|
|
t <- &Token{Error: &ParseError{f, "unknown RR type", l}}
|
2011-12-16 20:06:28 +11:00
|
|
|
return
|
2011-12-14 19:00:39 +11:00
|
|
|
}
|
2012-02-28 07:12:04 +11:00
|
|
|
h.Rrtype = l.torc
|
2015-02-19 21:59:15 +11:00
|
|
|
st = zExpectRdata
|
|
|
|
case zExpectRdata:
|
2013-03-04 22:16:20 +11:00
|
|
|
r, e, c1 := setRR(h, c, origin, f)
|
2011-12-14 21:30:29 +11:00
|
|
|
if e != nil {
|
2011-12-17 05:34:30 +11:00
|
|
|
// If e.lex is nil than we have encounter a unknown RR type
|
|
|
|
// in that case we substitute our current lex token
|
2011-12-17 00:48:30 +11:00
|
|
|
if e.lex.token == "" && e.lex.value == 0 {
|
|
|
|
e.lex = l // Uh, dirty
|
|
|
|
}
|
2013-11-10 06:34:46 +11:00
|
|
|
t <- &Token{Error: e}
|
2011-12-16 20:06:28 +11:00
|
|
|
return
|
2011-12-14 19:00:39 +11:00
|
|
|
}
|
2013-11-10 06:34:46 +11:00
|
|
|
t <- &Token{RR: r, Comment: c1}
|
2015-02-19 21:59:15 +11:00
|
|
|
st = zExpectOwnerDir
|
2011-12-14 19:00:39 +11:00
|
|
|
}
|
|
|
|
}
|
2012-05-20 23:31:35 +10:00
|
|
|
// If we get here, we and the h.Rrtype is still zero, we haven't parsed anything, this
|
|
|
|
// is not an error, because an empty zone file is still a zone file.
|
2011-12-14 19:00:39 +11:00
|
|
|
}
|
|
|
|
|
2011-12-15 23:03:51 +11:00
|
|
|
// zlexer scans the sourcefile and returns tokens on the channel c.
|
2012-02-22 08:41:00 +11:00
|
|
|
func zlexer(s *scan, c chan lex) {
|
2011-12-17 05:34:30 +11:00
|
|
|
var l lex
|
2012-01-28 09:59:21 +11:00
|
|
|
str := make([]byte, maxTok) // Should be enough for any token
|
2012-01-28 10:35:37 +11:00
|
|
|
stri := 0 // Offset in str (0 means empty)
|
2013-03-04 19:40:45 +11:00
|
|
|
com := make([]byte, maxTok) // Hold comment text
|
|
|
|
comi := 0
|
2011-12-14 19:00:39 +11:00
|
|
|
quote := false
|
2011-12-19 05:59:01 +11:00
|
|
|
escape := false
|
2011-12-14 19:00:39 +11:00
|
|
|
space := false
|
|
|
|
commt := false
|
|
|
|
rrtype := false
|
|
|
|
owner := true
|
|
|
|
brace := 0
|
2012-02-22 08:41:00 +11:00
|
|
|
x, err := s.tokenText()
|
2012-01-05 23:24:35 +11:00
|
|
|
defer close(c)
|
2012-02-22 08:41:00 +11:00
|
|
|
for err == nil {
|
|
|
|
l.column = s.position.Column
|
|
|
|
l.line = s.position.Line
|
2015-05-07 19:56:48 +10:00
|
|
|
if stri >= maxTok {
|
2014-08-28 07:09:21 +10:00
|
|
|
l.token = "token length insufficient for parsing"
|
2012-02-24 06:13:37 +11:00
|
|
|
l.err = true
|
2012-01-28 10:35:37 +11:00
|
|
|
c <- l
|
|
|
|
return
|
|
|
|
}
|
2015-05-07 19:56:48 +10:00
|
|
|
if comi >= maxTok {
|
2014-08-28 07:09:21 +10:00
|
|
|
l.token = "comment length insufficient for parsing"
|
2013-03-04 19:58:09 +11:00
|
|
|
l.err = true
|
|
|
|
c <- l
|
|
|
|
return
|
|
|
|
}
|
2012-02-22 08:41:00 +11:00
|
|
|
|
|
|
|
switch x {
|
2012-01-31 07:26:29 +11:00
|
|
|
case ' ', '\t':
|
2013-12-03 20:12:21 +11:00
|
|
|
if escape {
|
|
|
|
escape = false
|
|
|
|
str[stri] = x
|
|
|
|
stri++
|
|
|
|
break
|
|
|
|
}
|
2012-02-13 05:06:32 +11:00
|
|
|
if quote {
|
|
|
|
// Inside quotes this is legal
|
2012-02-22 08:41:00 +11:00
|
|
|
str[stri] = x
|
2012-02-13 05:06:32 +11:00
|
|
|
stri++
|
|
|
|
break
|
|
|
|
}
|
2011-12-14 19:00:39 +11:00
|
|
|
if commt {
|
2013-03-04 19:58:09 +11:00
|
|
|
com[comi] = x
|
|
|
|
comi++
|
2011-12-14 19:00:39 +11:00
|
|
|
break
|
|
|
|
}
|
2012-01-28 09:59:21 +11:00
|
|
|
if stri == 0 {
|
2012-11-22 21:54:46 +11:00
|
|
|
// Space directly in the beginning, handled in the grammar
|
2011-12-14 19:00:39 +11:00
|
|
|
} else if owner {
|
2011-12-14 19:26:31 +11:00
|
|
|
// If we have a string and its the first, make it an owner
|
2015-02-19 21:45:59 +11:00
|
|
|
l.value = zOwner
|
2012-01-28 09:59:21 +11:00
|
|
|
l.token = string(str[:stri])
|
2014-08-28 22:17:40 +10:00
|
|
|
l.tokenUpper = strings.ToUpper(l.token)
|
2013-09-10 23:13:10 +10:00
|
|
|
l.length = stri
|
2012-01-09 00:06:58 +11:00
|
|
|
// escape $... start with a \ not a $, so this will work
|
2014-08-28 22:17:40 +10:00
|
|
|
switch l.tokenUpper {
|
2012-01-22 09:42:33 +11:00
|
|
|
case "$TTL":
|
2017-11-04 03:15:35 +11:00
|
|
|
l.value = zDirTTL
|
2012-01-22 09:42:33 +11:00
|
|
|
case "$ORIGIN":
|
2015-02-19 21:45:59 +11:00
|
|
|
l.value = zDirOrigin
|
2012-01-22 09:42:33 +11:00
|
|
|
case "$INCLUDE":
|
2015-02-19 21:45:59 +11:00
|
|
|
l.value = zDirInclude
|
2012-05-20 23:28:27 +10:00
|
|
|
case "$GENERATE":
|
2015-02-19 21:45:59 +11:00
|
|
|
l.value = zDirGenerate
|
2012-01-22 09:42:33 +11:00
|
|
|
}
|
2011-12-14 19:00:39 +11:00
|
|
|
c <- l
|
|
|
|
} else {
|
2015-02-19 21:45:59 +11:00
|
|
|
l.value = zString
|
2012-01-28 09:59:21 +11:00
|
|
|
l.token = string(str[:stri])
|
2014-08-28 22:00:15 +10:00
|
|
|
l.tokenUpper = strings.ToUpper(l.token)
|
2013-09-10 23:13:10 +10:00
|
|
|
l.length = stri
|
2011-12-14 19:26:31 +11:00
|
|
|
if !rrtype {
|
2014-08-28 22:00:15 +10:00
|
|
|
if t, ok := StringToType[l.tokenUpper]; ok {
|
2015-02-19 21:45:59 +11:00
|
|
|
l.value = zRrtpe
|
2012-02-28 07:12:04 +11:00
|
|
|
l.torc = t
|
2011-12-17 21:28:54 +11:00
|
|
|
rrtype = true
|
2012-02-14 07:12:14 +11:00
|
|
|
} else {
|
2014-08-28 22:00:15 +10:00
|
|
|
if strings.HasPrefix(l.tokenUpper, "TYPE") {
|
2015-02-19 22:36:40 +11:00
|
|
|
t, ok := typeToInt(l.token)
|
|
|
|
if !ok {
|
2012-02-28 07:12:04 +11:00
|
|
|
l.token = "unknown RR type"
|
|
|
|
l.err = true
|
|
|
|
c <- l
|
|
|
|
return
|
|
|
|
}
|
2015-02-19 22:36:40 +11:00
|
|
|
l.value = zRrtpe
|
2018-01-08 04:57:04 +11:00
|
|
|
rrtype = true
|
|