dns/scan_rr.go
Tom Thorogood 17c1bc6792
Eliminate lexer goroutines (#792)
* Eliminate zlexer goroutine

This replaces the zlexer goroutine and channels with a zlexer struct
that maintains state and provides a channel-like API.

* Eliminate klexer goroutine

This replaces the klexer goroutine and channels with a klexer struct
that maintains state and provides a channel-like API.

* Merge scan into zlexer and klexer

This does result in tokenText existing twice, but it's pretty simple
and small so it's not that bad.

* Avoid using text/scanner.Position to track position

* Track escape within zlexer.Next

* Avoid zl.commt check on space and tab in zlexer

* Track stri within zlexer.Next

* Track comi within zlexer.Next

There is one special case at the start of a comment that needs to be
handled, otherwise this is as simple as stri was.

* Use a single token buffer in zlexer

This is safe as there is never both a non-empty string buffer and a
non-empty comment buffer.

* Don't hardcode length of zl.tok in zlexer

* Eliminate lex.length field

This is always set to len(l.token) and is only queried in a few places.

It was added in 47cc5b052df9b4e5d5a9900cfdd622607de10a6d without any
obvious need.

* Add whitespace to klexer.Next

* Track lex within klexer.Next

* Use a strings.Builder in klexer.Next

* Simplify : case in klexer.Next

* Add whitespace to zlexer.Next

* Change for loop style in zlexer.Next and klexer.Next

* Surface read errors in zlexer

* Surface read errors from klexer

* Remove debug line from parseKey

* Rename tokenText to readByte

* Make readByte return ok bool

Also change the for loop style to match the Next for loops.

* Make readByte errors sticky

klexer.Next calls readByte separately from within the loop. Without
readByte being sticky, an error that occurs during that readByte call
may be lost.

* Panic in testRR if the error is non-nil

* Add whitespace and unify field setting in zlexer.Next

* Remove eof fields from zlexer and klexer

With readByte having sticky errors, this no longer needed. zl.eof = true
was also in the wrong place and could mask an unbalanced brace error.

* Merge zl.tok blocks in zlexer.Next

* Split the tok buffer into separate string and comment buffers

The invariant of stri > 0 && comi > 0 never being true was broken when
x == '\n' && !zl.quote && zl.commt && zl.brace != 0 (the
"If not in a brace this ends the comment AND the RR" block).

Split the buffer back out into two separate buffers to avoid clobbering.

* Replace token slices with arrays in zlexer

* Add a NewRR benchmark

* Move token buffers into zlexer.Next

These don't need to be retained across Next calls and can be stack
allocated inside Next. This drastically reduces memory consumption as
they accounted for nearly half of all the memory used.

name      old alloc/op   new alloc/op   delta
NewRR-12    9.72kB ± 0%    4.98kB ± 0%  -48.72%  (p=0.000 n=10+10)

* Add a ReadRR benchmark

Unlike NewRR, this will use an io.Reader that does not implement any
methods aside from Read. In particular it does not implement
io.ByteReader.

* Avoid using a bufio.Reader for io.ByteReader readers

At the same time use a smaller buffer size of 1KiB rather than the
bufio.NewReader default of 4KiB.

name       old time/op    new time/op    delta
NewRR-12     11.0µs ± 3%     9.5µs ± 2%  -13.77%  (p=0.000 n=9+10)
ReadRR-12    11.2µs ±16%     9.8µs ± 1%  -13.03%  (p=0.000 n=10+10)

name       old alloc/op   new alloc/op   delta
NewRR-12     4.98kB ± 0%    0.81kB ± 0%  -83.79%  (p=0.000 n=10+10)
ReadRR-12    4.87kB ± 0%    1.82kB ± 0%  -62.73%  (p=0.000 n=10+10)

name       old allocs/op  new allocs/op  delta
NewRR-12       19.0 ± 0%      17.0 ± 0%  -10.53%  (p=0.000 n=10+10)
ReadRR-12      19.0 ± 0%      19.0 ± 0%     ~     (all equal)

ReadRR-12    11.2µs ±16%     9.8µs ± 1%  -13.03%  (p=0.000 n=10+10)

* Surface any remaining comment from zlexer.Next

* Improve comment handling in zlexer.Next

This both fixes a regression where comments could be lost under certain
circumstances and now emits comments that occur within braces.

* Remove outdated comment from zlexer.Next and klexer.Next

* Delay converting LF to space in braced comment

* Fixup TestParseZoneComments

* Remove tokenUpper field from lex

Not computing this for every token, and instead only
when needed is a substantial performance improvement.

name       old time/op    new time/op    delta
NewRR-12     9.56µs ± 0%    6.30µs ± 1%  -34.08%  (p=0.000 n=9+10)
ReadRR-12    9.93µs ± 1%    6.67µs ± 1%  -32.77%  (p=0.000 n=10+10)

name       old alloc/op   new alloc/op   delta
NewRR-12       824B ± 0%      808B ± 0%   -1.94%  (p=0.000 n=10+10)
ReadRR-12    1.83kB ± 0%    1.82kB ± 0%   -0.87%  (p=0.000 n=10+10)

name       old allocs/op  new allocs/op  delta
NewRR-12       17.0 ± 0%      17.0 ± 0%     ~     (all equal)
ReadRR-12      19.0 ± 0%      19.0 ± 0%     ~     (all equal)

* Update ParseZone documentation to match comment changes

The zlexer code was changed to return comments more often, so update the
ParseZone documentation to match.
2018-10-15 17:42:31 +10:30

2210 lines
50 KiB
Go

package dns
import (
"encoding/base64"
"net"
"strconv"
"strings"
)
type parserFunc struct {
// Func defines the function that parses the tokens and returns the RR
// or an error. The last string contains any comments in the line as
// they returned by the lexer as well.
Func func(h RR_Header, c *zlexer, origin string, file string) (RR, *ParseError, string)
// Signals if the RR ending is of variable length, like TXT or records
// that have Hexadecimal or Base64 as their last element in the Rdata. Records
// that have a fixed ending or for instance A, AAAA, SOA and etc.
Variable bool
}
// Parse the rdata of each rrtype.
// All data from the channel c is either zString or zBlank.
// After the rdata there may come a zBlank and then a zNewline
// or immediately a zNewline. If this is not the case we flag
// an *ParseError: garbage after rdata.
func setRR(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
parserfunc, ok := typeToparserFunc[h.Rrtype]
if ok {
r, e, cm := parserfunc.Func(h, c, o, f)
if parserfunc.Variable {
return r, e, cm
}
if e != nil {
return nil, e, ""
}
e, cm = slurpRemainder(c, f)
if e != nil {
return nil, e, ""
}
return r, nil, cm
}
// RFC3957 RR (Unknown RR handling)
return setRFC3597(h, c, o, f)
}
// A remainder of the rdata with embedded spaces, return the parsed string (sans the spaces)
// or an error
func endingToString(c *zlexer, errstr, f string) (string, *ParseError, string) {
s := ""
l, _ := c.Next() // zString
for l.value != zNewline && l.value != zEOF {
if l.err {
return s, &ParseError{f, errstr, l}, ""
}
switch l.value {
case zString:
s += l.token
case zBlank: // Ok
default:
return "", &ParseError{f, errstr, l}, ""
}
l, _ = c.Next()
}
return s, nil, l.comment
}
// A remainder of the rdata with embedded spaces, split on unquoted whitespace
// and return the parsed string slice or an error
func endingToTxtSlice(c *zlexer, errstr, f string) ([]string, *ParseError, string) {
// Get the remaining data until we see a zNewline
l, _ := c.Next()
if l.err {
return nil, &ParseError{f, errstr, l}, ""
}
// Build the slice
s := make([]string, 0)
quote := false
empty := false
for l.value != zNewline && l.value != zEOF {
if l.err {
return nil, &ParseError{f, errstr, l}, ""
}
switch l.value {
case zString:
empty = false
if len(l.token) > 255 {
// split up tokens that are larger than 255 into 255-chunks
sx := []string{}
p, i := 0, 255
for {
if i <= len(l.token) {
sx = append(sx, l.token[p:i])
} else {
sx = append(sx, l.token[p:])
break
}
p, i = p+255, i+255
}
s = append(s, sx...)
break
}
s = append(s, l.token)
case zBlank:
if quote {
// zBlank can only be seen in between txt parts.
return nil, &ParseError{f, errstr, l}, ""
}
case zQuote:
if empty && quote {
s = append(s, "")
}
quote = !quote
empty = true
default:
return nil, &ParseError{f, errstr, l}, ""
}
l, _ = c.Next()
}
if quote {
return nil, &ParseError{f, errstr, l}, ""
}
return s, nil, l.comment
}
func setA(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
rr := new(A)
rr.Hdr = h
l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return rr, nil, ""
}
rr.A = net.ParseIP(l.token)
if rr.A == nil || l.err {
return nil, &ParseError{f, "bad A A", l}, ""
}
return rr, nil, ""
}
func setAAAA(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
rr := new(AAAA)
rr.Hdr = h
l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return rr, nil, ""
}
rr.AAAA = net.ParseIP(l.token)
if rr.AAAA == nil || l.err {
return nil, &ParseError{f, "bad AAAA AAAA", l}, ""
}
return rr, nil, ""
}
func setNS(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
rr := new(NS)
rr.Hdr = h
l, _ := c.Next()
rr.Ns = l.token
if len(l.token) == 0 { // dynamic update rr.
return rr, nil, ""
}
name, nameOk := toAbsoluteName(l.token, o)
if l.err || !nameOk {
return nil, &ParseError{f, "bad NS Ns", l}, ""
}
rr.Ns = name
return rr, nil, ""
}
func setPTR(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
rr := new(PTR)
rr.Hdr = h
l, _ := c.Next()
rr.Ptr = l.token
if len(l.token) == 0 { // dynamic update rr.
return rr, nil, ""
}
name, nameOk := toAbsoluteName(l.token, o)
if l.err || !nameOk {
return nil, &ParseError{f, "bad PTR Ptr", l}, ""
}
rr.Ptr = name
return rr, nil, ""
}
func setNSAPPTR(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
rr := new(NSAPPTR)
rr.Hdr = h
l, _ := c.Next()
rr.Ptr = l.token
if len(l.token) == 0 { // dynamic update rr.
return rr, nil, ""
}
name, nameOk := toAbsoluteName(l.token, o)
if l.err || !nameOk {
return nil, &ParseError{f, "bad NSAP-PTR Ptr", l}, ""
}
rr.Ptr = name
return rr, nil, ""
}
func setRP(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
rr := new(RP)
rr.Hdr = h
l, _ := c.Next()
rr.Mbox = l.token
if len(l.token) == 0 { // dynamic update rr.
return rr, nil, ""
}
mbox, mboxOk := toAbsoluteName(l.token, o)
if l.err || !mboxOk {
return nil, &ParseError{f, "bad RP Mbox", l}, ""
}
rr.Mbox = mbox
c.Next() // zBlank
l, _ = c.Next()
rr.Txt = l.token
txt, txtOk := toAbsoluteName(l.token, o)
if l.err || !txtOk {
return nil, &ParseError{f, "bad RP Txt", l}, ""
}
rr.Txt = txt
return rr, nil, ""
}
func setMR(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
rr := new(MR)
rr.Hdr = h
l, _ := c.Next()
rr.Mr = l.token
if len(l.token) == 0 { // dynamic update rr.
return rr, nil, ""
}
name, nameOk := toAbsoluteName(l.token, o)
if l.err || !nameOk {
return nil, &ParseError{f, "bad MR Mr", l}, ""
}
rr.Mr = name
return rr, nil, ""
}
func setMB(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
rr := new(MB)
rr.Hdr = h
l, _ := c.Next()
rr.Mb = l.token
if len(l.token) == 0 { // dynamic update rr.
return rr, nil, ""
}
name, nameOk := toAbsoluteName(l.token, o)
if l.err || !nameOk {
return nil, &ParseError{f, "bad MB Mb", l}, ""
}
rr.Mb = name
return rr, nil, ""
}
func setMG(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
rr := new(MG)
rr.Hdr = h
l, _ := c.Next()
rr.Mg = l.token
if len(l.token) == 0 { // dynamic update rr.
return rr, nil, ""
}
name, nameOk := toAbsoluteName(l.token, o)
if l.err || !nameOk {
return nil, &ParseError{f, "bad MG Mg", l}, ""
}
rr.Mg = name
return rr, nil, ""
}
func setHINFO(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
rr := new(HINFO)
rr.Hdr = h
chunks, e, c1 := endingToTxtSlice(c, "bad HINFO Fields", f)
if e != nil {
return nil, e, c1
}
if ln := len(chunks); ln == 0 {
return rr, nil, ""
} else if ln == 1 {
// Can we split it?
if out := strings.Fields(chunks[0]); len(out) > 1 {
chunks = out
} else {
chunks = append(chunks, "")
}
}
rr.Cpu = chunks[0]
rr.Os = strings.Join(chunks[1:], " ")
return rr, nil, ""
}
func setMINFO(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
rr := new(MINFO)
rr.Hdr = h
l, _ := c.Next()
rr.Rmail = l.token
if len(l.token) == 0 { // dynamic update rr.
return rr, nil, ""
}
rmail, rmailOk := toAbsoluteName(l.token, o)
if l.err || !rmailOk {
return nil, &ParseError{f, "bad MINFO Rmail", l}, ""
}
rr.Rmail = rmail
c.Next() // zBlank
l, _ = c.Next()
rr.Email = l.token
email, emailOk := toAbsoluteName(l.token, o)
if l.err || !emailOk {
return nil, &ParseError{f, "bad MINFO Email", l}, ""
}
rr.Email = email
return rr, nil, ""
}
func setMF(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
rr := new(MF)
rr.Hdr = h
l, _ := c.Next()
rr.Mf = l.token
if len(l.token) == 0 { // dynamic update rr.
return rr, nil, ""
}
name, nameOk := toAbsoluteName(l.token, o)
if l.err || !nameOk {
return nil, &ParseError{f, "bad MF Mf", l}, ""
}
rr.Mf = name
return rr, nil, ""
}
func setMD(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
rr := new(MD)
rr.Hdr = h
l, _ := c.Next()
rr.Md = l.token
if len(l.token) == 0 { // dynamic update rr.
return rr, nil, ""
}
name, nameOk := toAbsoluteName(l.token, o)
if l.err || !nameOk {
return nil, &ParseError{f, "bad MD Md", l}, ""
}
rr.Md = name
return rr, nil, ""
}
func setMX(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
rr := new(MX)
rr.Hdr = h
l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return rr, nil, ""
}
i, e := strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err {
return nil, &ParseError{f, "bad MX Pref", l}, ""
}
rr.Preference = uint16(i)
c.Next() // zBlank
l, _ = c.Next() // zString
rr.Mx = l.token
name, nameOk := toAbsoluteName(l.token, o)
if l.err || !nameOk {
return nil, &ParseError{f, "bad MX Mx", l}, ""
}
rr.Mx = name
return rr, nil, ""
}
func setRT(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
rr := new(RT)
rr.Hdr = h
l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return rr, nil, ""
}
i, e := strconv.ParseUint(l.token, 10, 16)
if e != nil {
return nil, &ParseError{f, "bad RT Preference", l}, ""
}
rr.Preference = uint16(i)
c.Next() // zBlank
l, _ = c.Next() // zString
rr.Host = l.token
name, nameOk := toAbsoluteName(l.token, o)
if l.err || !nameOk {
return nil, &ParseError{f, "bad RT Host", l}, ""
}
rr.Host = name
return rr, nil, ""
}
func setAFSDB(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
rr := new(AFSDB)
rr.Hdr = h
l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return rr, nil, ""
}
i, e := strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err {
return nil, &ParseError{f, "bad AFSDB Subtype", l}, ""
}
rr.Subtype = uint16(i)
c.Next() // zBlank
l, _ = c.Next() // zString
rr.Hostname = l.token
name, nameOk := toAbsoluteName(l.token, o)
if l.err || !nameOk {
return nil, &ParseError{f, "bad AFSDB Hostname", l}, ""
}
rr.Hostname = name
return rr, nil, ""
}
func setX25(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
rr := new(X25)
rr.Hdr = h
l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return rr, nil, ""
}
if l.err {
return nil, &ParseError{f, "bad X25 PSDNAddress", l}, ""
}
rr.PSDNAddress = l.token
return rr, nil, ""
}
func setKX(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
rr := new(KX)
rr.Hdr = h
l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return rr, nil, ""
}
i, e := strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err {
return nil, &ParseError{f, "bad KX Pref", l}, ""
}
rr.Preference = uint16(i)
c.Next() // zBlank
l, _ = c.Next() // zString
rr.Exchanger = l.token
name, nameOk := toAbsoluteName(l.token, o)
if l.err || !nameOk {
return nil, &ParseError{f, "bad KX Exchanger", l}, ""
}
rr.Exchanger = name
return rr, nil, ""
}
func setCNAME(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
rr := new(CNAME)
rr.Hdr = h
l, _ := c.Next()
rr.Target = l.token
if len(l.token) == 0 { // dynamic update rr.
return rr, nil, ""
}
name, nameOk := toAbsoluteName(l.token, o)
if l.err || !nameOk {
return nil, &ParseError{f, "bad CNAME Target", l}, ""
}
rr.Target = name
return rr, nil, ""
}
func setDNAME(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
rr := new(DNAME)
rr.Hdr = h
l, _ := c.Next()
rr.Target = l.token
if len(l.token) == 0 { // dynamic update rr.
return rr, nil, ""
}
name, nameOk := toAbsoluteName(l.token, o)
if l.err || !nameOk {
return nil, &ParseError{f, "bad DNAME Target", l}, ""
}
rr.Target = name
return rr, nil, ""
}
func setSOA(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
rr := new(SOA)
rr.Hdr = h
l, _ := c.Next()
rr.Ns = l.token
if len(l.token) == 0 { // dynamic update rr.
return rr, nil, ""
}
ns, nsOk := toAbsoluteName(l.token, o)
if l.err || !nsOk {
return nil, &ParseError{f, "bad SOA Ns", l}, ""
}
rr.Ns = ns
c.Next() // zBlank
l, _ = c.Next()
rr.Mbox = l.token
mbox, mboxOk := toAbsoluteName(l.token, o)
if l.err || !mboxOk {
return nil, &ParseError{f, "bad SOA Mbox", l}, ""
}
rr.Mbox = mbox
c.Next() // zBlank
var (
v uint32
ok bool
)
for i := 0; i < 5; i++ {
l, _ = c.Next()
if l.err {
return nil, &ParseError{f, "bad SOA zone parameter", l}, ""
}
if j, e := strconv.ParseUint(l.token, 10, 32); e != nil {
if i == 0 {
// Serial must be a number
return nil, &ParseError{f, "bad SOA zone parameter", l}, ""
}
// We allow other fields to be unitful duration strings
if v, ok = stringToTTL(l.token); !ok {
return nil, &ParseError{f, "bad SOA zone parameter", l}, ""
}
} else {
v = uint32(j)
}
switch i {
case 0:
rr.Serial = v
c.Next() // zBlank
case 1:
rr.Refresh = v
c.Next() // zBlank
case 2:
rr.Retry = v
c.Next() // zBlank
case 3:
rr.Expire = v
c.Next() // zBlank
case 4:
rr.Minttl = v
}
}
return rr, nil, ""
}
func setSRV(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
rr := new(SRV)
rr.Hdr = h
l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return rr, nil, ""
}
i, e := strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err {
return nil, &ParseError{f, "bad SRV Priority", l}, ""
}
rr.Priority = uint16(i)
c.Next() // zBlank
l, _ = c.Next() // zString
i, e = strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err {
return nil, &ParseError{f, "bad SRV Weight", l}, ""
}
rr.Weight = uint16(i)
c.Next() // zBlank
l, _ = c.Next() // zString
i, e = strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err {
return nil, &ParseError{f, "bad SRV Port", l}, ""
}
rr.Port = uint16(i)
c.Next() // zBlank
l, _ = c.Next() // zString
rr.Target = l.token
name, nameOk := toAbsoluteName(l.token, o)
if l.err || !nameOk {
return nil, &ParseError{f, "bad SRV Target", l}, ""
}
rr.Target = name
return rr, nil, ""
}
func setNAPTR(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
rr := new(NAPTR)
rr.Hdr = h
l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return rr, nil, ""
}
i, e := strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err {
return nil, &ParseError{f, "bad NAPTR Order", l}, ""
}
rr.Order = uint16(i)
c.Next() // zBlank
l, _ = c.Next() // zString
i, e = strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err {
return nil, &ParseError{f, "bad NAPTR Preference", l}, ""
}
rr.Preference = uint16(i)
// Flags
c.Next() // zBlank
l, _ = c.Next() // _QUOTE
if l.value != zQuote {
return nil, &ParseError{f, "bad NAPTR Flags", l}, ""
}
l, _ = c.Next() // Either String or Quote
if l.value == zString {
rr.Flags = l.token
l, _ = c.Next() // _QUOTE
if l.value != zQuote {
return nil, &ParseError{f, "bad NAPTR Flags", l}, ""
}
} else if l.value == zQuote {
rr.Flags = ""
} else {
return nil, &ParseError{f, "bad NAPTR Flags", l}, ""
}
// Service
c.Next() // zBlank
l, _ = c.Next() // _QUOTE
if l.value != zQuote {
return nil, &ParseError{f, "bad NAPTR Service", l}, ""
}
l, _ = c.Next() // Either String or Quote
if l.value == zString {
rr.Service = l.token
l, _ = c.Next() // _QUOTE
if l.value != zQuote {
return nil, &ParseError{f, "bad NAPTR Service", l}, ""
}
} else if l.value == zQuote {
rr.Service = ""
} else {
return nil, &ParseError{f, "bad NAPTR Service", l}, ""
}
// Regexp
c.Next() // zBlank
l, _ = c.Next() // _QUOTE
if l.value != zQuote {
return nil, &ParseError{f, "bad NAPTR Regexp", l}, ""
}
l, _ = c.Next() // Either String or Quote
if l.value == zString {
rr.Regexp = l.token
l, _ = c.Next() // _QUOTE
if l.value != zQuote {
return nil, &ParseError{f, "bad NAPTR Regexp", l}, ""
}
} else if l.value == zQuote {
rr.Regexp = ""
} else {
return nil, &ParseError{f, "bad NAPTR Regexp", l}, ""
}
// After quote no space??
c.Next() // zBlank
l, _ = c.Next() // zString
rr.Replacement = l.token
name, nameOk := toAbsoluteName(l.token, o)
if l.err || !nameOk {
return nil, &ParseError{f, "bad NAPTR Replacement", l}, ""
}
rr.Replacement = name
return rr, nil, ""
}
func setTALINK(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
rr := new(TALINK)
rr.Hdr = h
l, _ := c.Next()
rr.PreviousName = l.token
if len(l.token) == 0 { // dynamic update rr.
return rr, nil, ""
}
previousName, previousNameOk := toAbsoluteName(l.token, o)
if l.err || !previousNameOk {
return nil, &ParseError{f, "bad TALINK PreviousName", l}, ""
}
rr.PreviousName = previousName
c.Next() // zBlank
l, _ = c.Next()
rr.NextName = l.token
nextName, nextNameOk := toAbsoluteName(l.token, o)
if l.err || !nextNameOk {
return nil, &ParseError{f, "bad TALINK NextName", l}, ""
}
rr.NextName = nextName
return rr, nil, ""
}
func setLOC(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
rr := new(LOC)
rr.Hdr = h
// Non zero defaults for LOC record, see RFC 1876, Section 3.
rr.HorizPre = 165 // 10000
rr.VertPre = 162 // 10
rr.Size = 18 // 1
ok := false
// North
l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return rr, nil, ""
}
i, e := strconv.ParseUint(l.token, 10, 32)
if e != nil || l.err {
return nil, &ParseError{f, "bad LOC Latitude", l}, ""
}
rr.Latitude = 1000 * 60 * 60 * uint32(i)
c.Next() // zBlank
// Either number, 'N' or 'S'
l, _ = c.Next()
if rr.Latitude, ok = locCheckNorth(l.token, rr.Latitude); ok {
goto East
}
i, e = strconv.ParseUint(l.token, 10, 32)
if e != nil || l.err {
return nil, &ParseError{f, "bad LOC Latitude minutes", l}, ""
}
rr.Latitude += 1000 * 60 * uint32(i)
c.Next() // zBlank
l, _ = c.Next()
if i, e := strconv.ParseFloat(l.token, 32); e != nil || l.err {
return nil, &ParseError{f, "bad LOC Latitude seconds", l}, ""
} else {
rr.Latitude += uint32(1000 * i)
}
c.Next() // zBlank
// Either number, 'N' or 'S'
l, _ = c.Next()
if rr.Latitude, ok = locCheckNorth(l.token, rr.Latitude); ok {
goto East
}
// If still alive, flag an error
return nil, &ParseError{f, "bad LOC Latitude North/South", l}, ""
East:
// East
c.Next() // zBlank
l, _ = c.Next()
if i, e := strconv.ParseUint(l.token, 10, 32); e != nil || l.err {
return nil, &ParseError{f, "bad LOC Longitude", l}, ""
} else {
rr.Longitude = 1000 * 60 * 60 * uint32(i)
}
c.Next() // zBlank
// Either number, 'E' or 'W'
l, _ = c.Next()
if rr.Longitude, ok = locCheckEast(l.token, rr.Longitude); ok {
goto Altitude
}
if i, e := strconv.ParseUint(l.token, 10, 32); e != nil || l.err {
return nil, &ParseError{f, "bad LOC Longitude minutes", l}, ""
} else {
rr.Longitude += 1000 * 60 * uint32(i)
}
c.Next() // zBlank
l, _ = c.Next()
if i, e := strconv.ParseFloat(l.token, 32); e != nil || l.err {
return nil, &ParseError{f, "bad LOC Longitude seconds", l}, ""
} else {
rr.Longitude += uint32(1000 * i)
}
c.Next() // zBlank
// Either number, 'E' or 'W'
l, _ = c.Next()
if rr.Longitude, ok = locCheckEast(l.token, rr.Longitude); ok {
goto Altitude
}
// If still alive, flag an error
return nil, &ParseError{f, "bad LOC Longitude East/West", l}, ""
Altitude:
c.Next() // zBlank
l, _ = c.Next()
if len(l.token) == 0 || l.err {
return nil, &ParseError{f, "bad LOC Altitude", l}, ""
}
if l.token[len(l.token)-1] == 'M' || l.token[len(l.token)-1] == 'm' {
l.token = l.token[0 : len(l.token)-1]
}
if i, e := strconv.ParseFloat(l.token, 32); e != nil {
return nil, &ParseError{f, "bad LOC Altitude", l}, ""
} else {
rr.Altitude = uint32(i*100.0 + 10000000.0 + 0.5)
}
// And now optionally the other values
l, _ = c.Next()
count := 0
for l.value != zNewline && l.value != zEOF {
switch l.value {
case zString:
switch count {
case 0: // Size
e, m, ok := stringToCm(l.token)
if !ok {
return nil, &ParseError{f, "bad LOC Size", l}, ""
}
rr.Size = e&0x0f | m<<4&0xf0
case 1: // HorizPre
e, m, ok := stringToCm(l.token)
if !ok {
return nil, &ParseError{f, "bad LOC HorizPre", l}, ""
}
rr.HorizPre = e&0x0f | m<<4&0xf0
case 2: // VertPre
e, m, ok := stringToCm(l.token)
if !ok {
return nil, &ParseError{f, "bad LOC VertPre", l}, ""
}
rr.VertPre = e&0x0f | m<<4&0xf0
}
count++
case zBlank:
// Ok
default:
return nil, &ParseError{f, "bad LOC Size, HorizPre or VertPre", l}, ""
}
l, _ = c.Next()
}
return rr, nil, ""
}
func setHIP(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
rr := new(HIP)
rr.Hdr = h
// HitLength is not represented
l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return rr, nil, l.comment
}
i, e := strconv.ParseUint(l.token, 10, 8)
if e != nil || l.err {
return nil, &ParseError{f, "bad HIP PublicKeyAlgorithm", l}, ""
}
rr.PublicKeyAlgorithm = uint8(i)
c.Next() // zBlank
l, _ = c.Next() // zString
if len(l.token) == 0 || l.err {
return nil, &ParseError{f, "bad HIP Hit", l}, ""
}
rr.Hit = l.token // This can not contain spaces, see RFC 5205 Section 6.
rr.HitLength = uint8(len(rr.Hit)) / 2
c.Next() // zBlank
l, _ = c.Next() // zString
if len(l.token) == 0 || l.err {
return nil, &ParseError{f, "bad HIP PublicKey", l}, ""
}
rr.PublicKey = l.token // This cannot contain spaces
rr.PublicKeyLength = uint16(base64.StdEncoding.DecodedLen(len(rr.PublicKey)))
// RendezvousServers (if any)
l, _ = c.Next()
var xs []string
for l.value != zNewline && l.value != zEOF {
switch l.value {
case zString:
name, nameOk := toAbsoluteName(l.token, o)
if l.err || !nameOk {
return nil, &ParseError{f, "bad HIP RendezvousServers", l}, ""
}
xs = append(xs, name)
case zBlank:
// Ok
default:
return nil, &ParseError{f, "bad HIP RendezvousServers", l}, ""
}
l, _ = c.Next()
}
rr.RendezvousServers = xs
return rr, nil, l.comment
}
func setCERT(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
rr := new(CERT)
rr.Hdr = h
l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return rr, nil, l.comment
}
if v, ok := StringToCertType[l.token]; ok {
rr.Type = v
} else if i, e := strconv.ParseUint(l.token, 10, 16); e != nil {
return nil, &ParseError{f, "bad CERT Type", l}, ""
} else {
rr.Type = uint16(i)
}
c.Next() // zBlank
l, _ = c.Next() // zString
i, e := strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err {
return nil, &ParseError{f, "bad CERT KeyTag", l}, ""
}
rr.KeyTag = uint16(i)
c.Next() // zBlank
l, _ = c.Next() // zString
if v, ok := StringToAlgorithm[l.token]; ok {
rr.Algorithm = v
} else if i, e := strconv.ParseUint(l.token, 10, 8); e != nil {
return nil, &ParseError{f, "bad CERT Algorithm", l}, ""
} else {
rr.Algorithm = uint8(i)
}
s, e1, c1 := endingToString(c, "bad CERT Certificate", f)
if e1 != nil {
return nil, e1, c1
}
rr.Certificate = s
return rr, nil, c1
}
func setOPENPGPKEY(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
rr := new(OPENPGPKEY)
rr.Hdr = h
s, e, c1 := endingToString(c, "bad OPENPGPKEY PublicKey", f)
if e != nil {
return nil, e, c1
}
rr.PublicKey = s
return rr, nil, c1
}
func setCSYNC(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
rr := new(CSYNC)
rr.Hdr = h
l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return rr, nil, l.comment
}
j, e := strconv.ParseUint(l.token, 10, 32)
if e != nil {
// Serial must be a number
return nil, &ParseError{f, "bad CSYNC serial", l}, ""
}
rr.Serial = uint32(j)
c.Next() // zBlank
l, _ = c.Next()
j, e = strconv.ParseUint(l.token, 10, 16)
if e != nil {
// Serial must be a number
return nil, &ParseError{f, "bad CSYNC flags", l}, ""
}
rr.Flags = uint16(j)
rr.TypeBitMap = make([]uint16, 0)
var (
k uint16
ok bool
)
l, _ = c.Next()
for l.value != zNewline && l.value != zEOF {
switch l.value {
case zBlank:
// Ok
case zString:
tokenUpper := strings.ToUpper(l.token)
if k, ok = StringToType[tokenUpper]; !ok {
if k, ok = typeToInt(l.token); !ok {
return nil, &ParseError{f, "bad CSYNC TypeBitMap", l}, ""
}
}
rr.TypeBitMap = append(rr.TypeBitMap, k)
default:
return nil, &ParseError{f, "bad CSYNC TypeBitMap", l}, ""
}
l, _ = c.Next()
}
return rr, nil, l.comment
}
func setSIG(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
r, e, s := setRRSIG(h, c, o, f)
if r != nil {
return &SIG{*r.(*RRSIG)}, e, s
}
return nil, e, s
}
func setRRSIG(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
rr := new(RRSIG)
rr.Hdr = h
l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return rr, nil, l.comment
}
tokenUpper := strings.ToUpper(l.token)
if t, ok := StringToType[tokenUpper]; !ok {
if strings.HasPrefix(tokenUpper, "TYPE") {
t, ok = typeToInt(l.token)
if !ok {
return nil, &ParseError{f, "bad RRSIG Typecovered", l}, ""
}
rr.TypeCovered = t
} else {
return nil, &ParseError{f, "bad RRSIG Typecovered", l}, ""
}
} else {
rr.TypeCovered = t
}
c.Next() // zBlank
l, _ = c.Next()
i, err := strconv.ParseUint(l.token, 10, 8)
if err != nil || l.err {
return nil, &ParseError{f, "bad RRSIG Algorithm", l}, ""
}
rr.Algorithm = uint8(i)
c.Next() // zBlank
l, _ = c.Next()
i, err = strconv.ParseUint(l.token, 10, 8)
if err != nil || l.err {
return nil, &ParseError{f, "bad RRSIG Labels", l}, ""
}
rr.Labels = uint8(i)
c.Next() // zBlank
l, _ = c.Next()
i, err = strconv.ParseUint(l.token, 10, 32)
if err != nil || l.err {
return nil, &ParseError{f, "bad RRSIG OrigTtl", l}, ""
}
rr.OrigTtl = uint32(i)
c.Next() // zBlank
l, _ = c.Next()
if i, err := StringToTime(l.token); err != nil {
// Try to see if all numeric and use it as epoch
if i, err := strconv.ParseInt(l.token, 10, 64); err == nil {
// TODO(miek): error out on > MAX_UINT32, same below
rr.Expiration = uint32(i)
} else {
return nil, &ParseError{f, "bad RRSIG Expiration", l}, ""
}
} else {
rr.Expiration = i
}
c.Next() // zBlank
l, _ = c.Next()
if i, err := StringToTime(l.token); err != nil {
if i, err := strconv.ParseInt(l.token, 10, 64); err == nil {
rr.Inception = uint32(i)
} else {
return nil, &ParseError{f, "bad RRSIG Inception", l}, ""
}
} else {
rr.Inception = i
}
c.Next() // zBlank
l, _ = c.Next()
i, err = strconv.ParseUint(l.token, 10, 16)
if err != nil || l.err {
return nil, &ParseError{f, "bad RRSIG KeyTag", l}, ""
}
rr.KeyTag = uint16(i)
c.Next() // zBlank
l, _ = c.Next()
rr.SignerName = l.token
name, nameOk := toAbsoluteName(l.token, o)
if l.err || !nameOk {
return nil, &ParseError{f, "bad RRSIG SignerName", l}, ""
}
rr.SignerName = name
s, e, c1 := endingToString(c, "bad RRSIG Signature", f)
if e != nil {
return nil, e, c1
}
rr.Signature = s
return rr, nil, c1
}
func setNSEC(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
rr := new(NSEC)
rr.Hdr = h
l, _ := c.Next()
rr.NextDomain = l.token
if len(l.token) == 0 { // dynamic update rr.
return rr, nil, l.comment
}
name, nameOk := toAbsoluteName(l.token, o)
if l.err || !nameOk {
return nil, &ParseError{f, "bad NSEC NextDomain", l}, ""
}
rr.NextDomain = name
rr.TypeBitMap = make([]uint16, 0)
var (
k uint16
ok bool
)
l, _ = c.Next()
for l.value != zNewline && l.value != zEOF {
switch l.value {
case zBlank:
// Ok
case zString:
tokenUpper := strings.ToUpper(l.token)
if k, ok = StringToType[tokenUpper]; !ok {
if k, ok = typeToInt(l.token); !ok {
return nil, &ParseError{f, "bad NSEC TypeBitMap", l}, ""
}
}
rr.TypeBitMap = append(rr.TypeBitMap, k)
default:
return nil, &ParseError{f, "bad NSEC TypeBitMap", l}, ""
}
l, _ = c.Next()
}
return rr, nil, l.comment
}
func setNSEC3(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
rr := new(NSEC3)
rr.Hdr = h
l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return rr, nil, l.comment
}
i, e := strconv.ParseUint(l.token, 10, 8)
if e != nil || l.err {
return nil, &ParseError{f, "bad NSEC3 Hash", l}, ""
}
rr.Hash = uint8(i)
c.Next() // zBlank
l, _ = c.Next()
i, e = strconv.ParseUint(l.token, 10, 8)
if e != nil || l.err {
return nil, &ParseError{f, "bad NSEC3 Flags", l}, ""
}
rr.Flags = uint8(i)
c.Next() // zBlank
l, _ = c.Next()
i, e = strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err {
return nil, &ParseError{f, "bad NSEC3 Iterations", l}, ""
}
rr.Iterations = uint16(i)
c.Next()
l, _ = c.Next()
if len(l.token) == 0 || l.err {
return nil, &ParseError{f, "bad NSEC3 Salt", l}, ""
}
if l.token != "-" {
rr.SaltLength = uint8(len(l.token)) / 2
rr.Salt = l.token
}
c.Next()
l, _ = c.Next()
if len(l.token) == 0 || l.err {
return nil, &ParseError{f, "bad NSEC3 NextDomain", l}, ""
}
rr.HashLength = 20 // Fix for NSEC3 (sha1 160 bits)
rr.NextDomain = l.token
rr.TypeBitMap = make([]uint16, 0)
var (
k uint16
ok bool
)
l, _ = c.Next()
for l.value != zNewline && l.value != zEOF {
switch l.value {
case zBlank:
// Ok
case zString:
tokenUpper := strings.ToUpper(l.token)
if k, ok = StringToType[tokenUpper]; !ok {
if k, ok = typeToInt(l.token); !ok {
return nil, &ParseError{f, "bad NSEC3 TypeBitMap", l}, ""
}
}
rr.TypeBitMap = append(rr.TypeBitMap, k)
default:
return nil, &ParseError{f, "bad NSEC3 TypeBitMap", l}, ""
}
l, _ = c.Next()
}
return rr, nil, l.comment
}
func setNSEC3PARAM(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
rr := new(NSEC3PARAM)
rr.Hdr = h
l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return rr, nil, ""
}
i, e := strconv.ParseUint(l.token, 10, 8)
if e != nil || l.err {
return nil, &ParseError{f, "bad NSEC3PARAM Hash", l}, ""
}
rr.Hash = uint8(i)
c.Next() // zBlank
l, _ = c.Next()
i, e = strconv.ParseUint(l.token, 10, 8)
if e != nil || l.err {
return nil, &ParseError{f, "bad NSEC3PARAM Flags", l}, ""
}
rr.Flags = uint8(i)
c.Next() // zBlank
l, _ = c.Next()
i, e = strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err {
return nil, &ParseError{f, "bad NSEC3PARAM Iterations", l}, ""
}
rr.Iterations = uint16(i)
c.Next()
l, _ = c.Next()
if l.token != "-" {
rr.SaltLength = uint8(len(l.token))
rr.Salt = l.token
}
return rr, nil, ""
}
func setEUI48(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
rr := new(EUI48)
rr.Hdr = h
l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return rr, nil, ""
}
if len(l.token) != 17 || l.err {
return nil, &ParseError{f, "bad EUI48 Address", l}, ""
}
addr := make([]byte, 12)
dash := 0
for i := 0; i < 10; i += 2 {
addr[i] = l.token[i+dash]
addr[i+1] = l.token[i+1+dash]
dash++
if l.token[i+1+dash] != '-' {
return nil, &ParseError{f, "bad EUI48 Address", l}, ""
}
}
addr[10] = l.token[15]
addr[11] = l.token[16]
i, e := strconv.ParseUint(string(addr), 16, 48)
if e != nil {
return nil, &ParseError{f, "bad EUI48 Address", l}, ""
}
rr.Address = i
return rr, nil, ""
}
func setEUI64(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
rr := new(EUI64)
rr.Hdr = h
l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return rr, nil, ""
}
if len(l.token) != 23 || l.err {
return nil, &ParseError{f, "bad EUI64 Address", l}, ""
}
addr := make([]byte, 16)
dash := 0
for i := 0; i < 14; i += 2 {
addr[i] = l.token[i+dash]
addr[i+1] = l.token[i+1+dash]
dash++
if l.token[i+1+dash] != '-' {
return nil, &ParseError{f, "bad EUI64 Address", l}, ""
}
}
addr[14] = l.token[21]
addr[15] = l.token[22]
i, e := strconv.ParseUint(string(addr), 16, 64)
if e != nil {
return nil, &ParseError{f, "bad EUI68 Address", l}, ""
}
rr.Address = uint64(i)
return rr, nil, ""
}
func setSSHFP(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
rr := new(SSHFP)
rr.Hdr = h
l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return rr, nil, ""
}
i, e := strconv.ParseUint(l.token, 10, 8)
if e != nil || l.err {
return nil, &ParseError{f, "bad SSHFP Algorithm", l}, ""
}
rr.Algorithm = uint8(i)
c.Next() // zBlank
l, _ = c.Next()
i, e = strconv.ParseUint(l.token, 10, 8)
if e != nil || l.err {
return nil, &ParseError{f, "bad SSHFP Type", l}, ""
}
rr.Type = uint8(i)
c.Next() // zBlank
s, e1, c1 := endingToString(c, "bad SSHFP Fingerprint", f)
if e1 != nil {
return nil, e1, c1
}
rr.FingerPrint = s
return rr, nil, ""
}
func setDNSKEYs(h RR_Header, c *zlexer, o, f, typ string) (RR, *ParseError, string) {
rr := new(DNSKEY)
rr.Hdr = h
l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return rr, nil, l.comment
}
i, e := strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err {
return nil, &ParseError{f, "bad " + typ + " Flags", l}, ""
}
rr.Flags = uint16(i)
c.Next() // zBlank
l, _ = c.Next() // zString
i, e = strconv.ParseUint(l.token, 10, 8)
if e != nil || l.err {
return nil, &ParseError{f, "bad " + typ + " Protocol", l}, ""
}
rr.Protocol = uint8(i)
c.Next() // zBlank
l, _ = c.Next() // zString
i, e = strconv.ParseUint(l.token, 10, 8)
if e != nil || l.err {
return nil, &ParseError{f, "bad " + typ + " Algorithm", l}, ""
}
rr.Algorithm = uint8(i)
s, e1, c1 := endingToString(c, "bad "+typ+" PublicKey", f)
if e1 != nil {
return nil, e1, c1
}
rr.PublicKey = s
return rr, nil, c1
}
func setKEY(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
r, e, s := setDNSKEYs(h, c, o, f, "KEY")
if r != nil {
return &KEY{*r.(*DNSKEY)}, e, s
}
return nil, e, s
}
func setDNSKEY(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
r, e, s := setDNSKEYs(h, c, o, f, "DNSKEY")
return r, e, s
}
func setCDNSKEY(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
r, e, s := setDNSKEYs(h, c, o, f, "CDNSKEY")
if r != nil {
return &CDNSKEY{*r.(*DNSKEY)}, e, s
}
return nil, e, s
}
func setRKEY(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
rr := new(RKEY)
rr.Hdr = h
l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return rr, nil, l.comment
}
i, e := strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err {
return nil, &ParseError{f, "bad RKEY Flags", l}, ""
}
rr.Flags = uint16(i)
c.Next() // zBlank
l, _ = c.Next() // zString
i, e = strconv.ParseUint(l.token, 10, 8)
if e != nil || l.err {
return nil, &ParseError{f, "bad RKEY Protocol", l}, ""
}
rr.Protocol = uint8(i)
c.Next() // zBlank
l, _ = c.Next() // zString
i, e = strconv.ParseUint(l.token, 10, 8)
if e != nil || l.err {
return nil, &ParseError{f, "bad RKEY Algorithm", l}, ""
}
rr.Algorithm = uint8(i)
s, e1, c1 := endingToString(c, "bad RKEY PublicKey", f)
if e1 != nil {
return nil, e1, c1
}
rr.PublicKey = s
return rr, nil, c1
}
func setEID(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
rr := new(EID)
rr.Hdr = h
s, e, c1 := endingToString(c, "bad EID Endpoint", f)
if e != nil {
return nil, e, c1
}
rr.Endpoint = s
return rr, nil, c1
}
func setNIMLOC(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
rr := new(NIMLOC)
rr.Hdr = h
s, e, c1 := endingToString(c, "bad NIMLOC Locator", f)
if e != nil {
return nil, e, c1
}
rr.Locator = s
return rr, nil, c1
}
func setGPOS(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
rr := new(GPOS)
rr.Hdr = h
l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return rr, nil, ""
}
_, e := strconv.ParseFloat(l.token, 64)
if e != nil || l.err {
return nil, &ParseError{f, "bad GPOS Longitude", l}, ""
}
rr.Longitude = l.token
c.Next() // zBlank
l, _ = c.Next()
_, e = strconv.ParseFloat(l.token, 64)
if e != nil || l.err {
return nil, &ParseError{f, "bad GPOS Latitude", l}, ""
}
rr.Latitude = l.token
c.Next() // zBlank
l, _ = c.Next()
_, e = strconv.ParseFloat(l.token, 64)
if e != nil || l.err {
return nil, &ParseError{f, "bad GPOS Altitude", l}, ""
}
rr.Altitude = l.token
return rr, nil, ""
}
func setDSs(h RR_Header, c *zlexer, o, f, typ string) (RR, *ParseError, string) {
rr := new(DS)
rr.Hdr = h
l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return rr, nil, l.comment
}
i, e := strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err {
return nil, &ParseError{f, "bad " + typ + " KeyTag", l}, ""
}
rr.KeyTag = uint16(i)
c.Next() // zBlank
l, _ = c.Next()
if i, e = strconv.ParseUint(l.token, 10, 8); e != nil {
tokenUpper := strings.ToUpper(l.token)
i, ok := StringToAlgorithm[tokenUpper]
if !ok || l.err {
return nil, &ParseError{f, "bad " + typ + " Algorithm", l}, ""
}
rr.Algorithm = i
} else {
rr.Algorithm = uint8(i)
}
c.Next() // zBlank
l, _ = c.Next()
i, e = strconv.ParseUint(l.token, 10, 8)
if e != nil || l.err {
return nil, &ParseError{f, "bad " + typ + " DigestType", l}, ""
}
rr.DigestType = uint8(i)
s, e1, c1 := endingToString(c, "bad "+typ+" Digest", f)
if e1 != nil {
return nil, e1, c1
}
rr.Digest = s
return rr, nil, c1
}
func setDS(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
r, e, s := setDSs(h, c, o, f, "DS")
return r, e, s
}
func setDLV(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
r, e, s := setDSs(h, c, o, f, "DLV")
if r != nil {
return &DLV{*r.(*DS)}, e, s
}
return nil, e, s
}
func setCDS(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
r, e, s := setDSs(h, c, o, f, "CDS")
if r != nil {
return &CDS{*r.(*DS)}, e, s
}
return nil, e, s
}
func setTA(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
rr := new(TA)
rr.Hdr = h
l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return rr, nil, l.comment
}
i, e := strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err {
return nil, &ParseError{f, "bad TA KeyTag", l}, ""
}
rr.KeyTag = uint16(i)
c.Next() // zBlank
l, _ = c.Next()
if i, e := strconv.ParseUint(l.token, 10, 8); e != nil {
tokenUpper := strings.ToUpper(l.token)
i, ok := StringToAlgorithm[tokenUpper]
if !ok || l.err {
return nil, &ParseError{f, "bad TA Algorithm", l}, ""
}
rr.Algorithm = i
} else {
rr.Algorithm = uint8(i)
}
c.Next() // zBlank
l, _ = c.Next()
i, e = strconv.ParseUint(l.token, 10, 8)
if e != nil || l.err {
return nil, &ParseError{f, "bad TA DigestType", l}, ""
}
rr.DigestType = uint8(i)
s, err, c1 := endingToString(c, "bad TA Digest", f)
if err != nil {
return nil, err, c1
}
rr.Digest = s
return rr, nil, c1
}
func setTLSA(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
rr := new(TLSA)
rr.Hdr = h
l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return rr, nil, l.comment
}
i, e := strconv.ParseUint(l.token, 10, 8)
if e != nil || l.err {
return nil, &ParseError{f, "bad TLSA Usage", l}, ""
}
rr.Usage = uint8(i)
c.Next() // zBlank
l, _ = c.Next()
i, e = strconv.ParseUint(l.token, 10, 8)
if e != nil || l.err {
return nil, &ParseError{f, "bad TLSA Selector", l}, ""
}
rr.Selector = uint8(i)
c.Next() // zBlank
l, _ = c.Next()
i, e = strconv.ParseUint(l.token, 10, 8)
if e != nil || l.err {
return nil, &ParseError{f, "bad TLSA MatchingType", l}, ""
}
rr.MatchingType = uint8(i)
// So this needs be e2 (i.e. different than e), because...??t
s, e2, c1 := endingToString(c, "bad TLSA Certificate", f)
if e2 != nil {
return nil, e2, c1
}
rr.Certificate = s
return rr, nil, c1
}
func setSMIMEA(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
rr := new(SMIMEA)
rr.Hdr = h
l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return rr, nil, l.comment
}
i, e := strconv.ParseUint(l.token, 10, 8)
if e != nil || l.err {
return nil, &ParseError{f, "bad SMIMEA Usage", l}, ""
}
rr.Usage = uint8(i)
c.Next() // zBlank
l, _ = c.Next()
i, e = strconv.ParseUint(l.token, 10, 8)
if e != nil || l.err {
return nil, &ParseError{f, "bad SMIMEA Selector", l}, ""
}
rr.Selector = uint8(i)
c.Next() // zBlank
l, _ = c.Next()
i, e = strconv.ParseUint(l.token, 10, 8)
if e != nil || l.err {
return nil, &ParseError{f, "bad SMIMEA MatchingType", l}, ""
}
rr.MatchingType = uint8(i)
// So this needs be e2 (i.e. different than e), because...??t
s, e2, c1 := endingToString(c, "bad SMIMEA Certificate", f)
if e2 != nil {
return nil, e2, c1
}
rr.Certificate = s
return rr, nil, c1
}
func setRFC3597(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
rr := new(RFC3597)
rr.Hdr = h
l, _ := c.Next()
if l.token != "\\#" {
return nil, &ParseError{f, "bad RFC3597 Rdata", l}, ""
}
c.Next() // zBlank
l, _ = c.Next()
rdlength, e := strconv.Atoi(l.token)
if e != nil || l.err {
return nil, &ParseError{f, "bad RFC3597 Rdata ", l}, ""
}
s, e1, c1 := endingToString(c, "bad RFC3597 Rdata", f)
if e1 != nil {
return nil, e1, c1
}
if rdlength*2 != len(s) {
return nil, &ParseError{f, "bad RFC3597 Rdata", l}, ""
}
rr.Rdata = s
return rr, nil, c1
}
func setSPF(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
rr := new(SPF)
rr.Hdr = h
s, e, c1 := endingToTxtSlice(c, "bad SPF Txt", f)
if e != nil {
return nil, e, ""
}
rr.Txt = s
return rr, nil, c1
}
func setAVC(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
rr := new(AVC)
rr.Hdr = h
s, e, c1 := endingToTxtSlice(c, "bad AVC Txt", f)
if e != nil {
return nil, e, ""
}
rr.Txt = s
return rr, nil, c1
}
func setTXT(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
rr := new(TXT)
rr.Hdr = h
// no zBlank reading here, because all this rdata is TXT
s, e, c1 := endingToTxtSlice(c, "bad TXT Txt", f)
if e != nil {
return nil, e, ""
}
rr.Txt = s
return rr, nil, c1
}
// identical to setTXT
func setNINFO(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
rr := new(NINFO)
rr.Hdr = h
s, e, c1 := endingToTxtSlice(c, "bad NINFO ZSData", f)
if e != nil {
return nil, e, ""
}
rr.ZSData = s
return rr, nil, c1
}
func setURI(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
rr := new(URI)
rr.Hdr = h
l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return rr, nil, ""
}
i, e := strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err {
return nil, &ParseError{f, "bad URI Priority", l}, ""
}
rr.Priority = uint16(i)
c.Next() // zBlank
l, _ = c.Next()
i, e = strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err {
return nil, &ParseError{f, "bad URI Weight", l}, ""
}
rr.Weight = uint16(i)
c.Next() // zBlank
s, err, c1 := endingToTxtSlice(c, "bad URI Target", f)
if err != nil {
return nil, err, ""
}
if len(s) != 1 {
return nil, &ParseError{f, "bad URI Target", l}, ""
}
rr.Target = s[0]
return rr, nil, c1
}
func setDHCID(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
// awesome record to parse!
rr := new(DHCID)
rr.Hdr = h
s, e, c1 := endingToString(c, "bad DHCID Digest", f)
if e != nil {
return nil, e, c1
}
rr.Digest = s
return rr, nil, c1
}
func setNID(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
rr := new(NID)
rr.Hdr = h
l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return rr, nil, ""
}
i, e := strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err {
return nil, &ParseError{f, "bad NID Preference", l}, ""
}
rr.Preference = uint16(i)
c.Next() // zBlank
l, _ = c.Next() // zString
u, err := stringToNodeID(l)
if err != nil || l.err {
return nil, err, ""
}
rr.NodeID = u
return rr, nil, ""
}
func setL32(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
rr := new(L32)
rr.Hdr = h
l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return rr, nil, ""
}
i, e := strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err {
return nil, &ParseError{f, "bad L32 Preference", l}, ""
}
rr.Preference = uint16(i)
c.Next() // zBlank
l, _ = c.Next() // zString
rr.Locator32 = net.ParseIP(l.token)
if rr.Locator32 == nil || l.err {
return nil, &ParseError{f, "bad L32 Locator", l}, ""
}
return rr, nil, ""
}
func setLP(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
rr := new(LP)
rr.Hdr = h
l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return rr, nil, ""
}
i, e := strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err {
return nil, &ParseError{f, "bad LP Preference", l}, ""
}
rr.Preference = uint16(i)
c.Next() // zBlank
l, _ = c.Next() // zString
rr.Fqdn = l.token
name, nameOk := toAbsoluteName(l.token, o)
if l.err || !nameOk {
return nil, &ParseError{f, "bad LP Fqdn", l}, ""
}
rr.Fqdn = name
return rr, nil, ""
}
func setL64(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
rr := new(L64)
rr.Hdr = h
l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return rr, nil, ""
}
i, e := strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err {
return nil, &ParseError{f, "bad L64 Preference", l}, ""
}
rr.Preference = uint16(i)
c.Next() // zBlank
l, _ = c.Next() // zString
u, err := stringToNodeID(l)
if err != nil || l.err {
return nil, err, ""
}
rr.Locator64 = u
return rr, nil, ""
}
func setUID(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
rr := new(UID)
rr.Hdr = h
l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return rr, nil, ""
}
i, e := strconv.ParseUint(l.token, 10, 32)
if e != nil || l.err {
return nil, &ParseError{f, "bad UID Uid", l}, ""
}
rr.Uid = uint32(i)
return rr, nil, ""
}
func setGID(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
rr := new(GID)
rr.Hdr = h
l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return rr, nil, ""
}
i, e := strconv.ParseUint(l.token, 10, 32)
if e != nil || l.err {
return nil, &ParseError{f, "bad GID Gid", l}, ""
}
rr.Gid = uint32(i)
return rr, nil, ""
}
func setUINFO(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
rr := new(UINFO)
rr.Hdr = h
s, e, c1 := endingToTxtSlice(c, "bad UINFO Uinfo", f)
if e != nil {
return nil, e, c1
}
if ln := len(s); ln == 0 {
return rr, nil, c1
}
rr.Uinfo = s[0] // silently discard anything after the first character-string
return rr, nil, c1
}
func setPX(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
rr := new(PX)
rr.Hdr = h
l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return rr, nil, ""
}
i, e := strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err {
return nil, &ParseError{f, "bad PX Preference", l}, ""
}
rr.Preference = uint16(i)
c.Next() // zBlank
l, _ = c.Next() // zString
rr.Map822 = l.token
map822, map822Ok := toAbsoluteName(l.token, o)
if l.err || !map822Ok {
return nil, &ParseError{f, "bad PX Map822", l}, ""
}
rr.Map822 = map822
c.Next() // zBlank
l, _ = c.Next() // zString
rr.Mapx400 = l.token
mapx400, mapx400Ok := toAbsoluteName(l.token, o)
if l.err || !mapx400Ok {
return nil, &ParseError{f, "bad PX Mapx400", l}, ""
}
rr.Mapx400 = mapx400
return rr, nil, ""
}
func setCAA(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
rr := new(CAA)
rr.Hdr = h
l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return rr, nil, l.comment
}
i, err := strconv.ParseUint(l.token, 10, 8)
if err != nil || l.err {
return nil, &ParseError{f, "bad CAA Flag", l}, ""
}
rr.Flag = uint8(i)
c.Next() // zBlank
l, _ = c.Next() // zString
if l.value != zString {
return nil, &ParseError{f, "bad CAA Tag", l}, ""
}
rr.Tag = l.token
c.Next() // zBlank
s, e, c1 := endingToTxtSlice(c, "bad CAA Value", f)
if e != nil {
return nil, e, ""
}
if len(s) != 1 {
return nil, &ParseError{f, "bad CAA Value", l}, ""
}
rr.Value = s[0]
return rr, nil, c1
}
func setTKEY(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
rr := new(TKEY)
rr.Hdr = h
l, _ := c.Next()
// Algorithm
if l.value != zString {
return nil, &ParseError{f, "bad TKEY algorithm", l}, ""
}
rr.Algorithm = l.token
c.Next() // zBlank
// Get the key length and key values
l, _ = c.Next()
i, err := strconv.ParseUint(l.token, 10, 8)
if err != nil || l.err {
return nil, &ParseError{f, "bad TKEY key length", l}, ""
}
rr.KeySize = uint16(i)
c.Next() // zBlank
l, _ = c.Next()
if l.value != zString {
return nil, &ParseError{f, "bad TKEY key", l}, ""
}
rr.Key = l.token
c.Next() // zBlank
// Get the otherdata length and string data
l, _ = c.Next()
i, err = strconv.ParseUint(l.token, 10, 8)
if err != nil || l.err {
return nil, &ParseError{f, "bad TKEY otherdata length", l}, ""
}
rr.OtherLen = uint16(i)
c.Next() // zBlank
l, _ = c.Next()
if l.value != zString {
return nil, &ParseError{f, "bad TKEY otherday", l}, ""
}
rr.OtherData = l.token
return rr, nil, ""
}
var typeToparserFunc = map[uint16]parserFunc{
TypeAAAA: {setAAAA, false},
TypeAFSDB: {setAFSDB, false},
TypeA: {setA, false},
TypeCAA: {setCAA, true},
TypeCDS: {setCDS, true},
TypeCDNSKEY: {setCDNSKEY, true},
TypeCERT: {setCERT, true},
TypeCNAME: {setCNAME, false},
TypeCSYNC: {setCSYNC, true},
TypeDHCID: {setDHCID, true},
TypeDLV: {setDLV, true},
TypeDNAME: {setDNAME, false},
TypeKEY: {setKEY, true},
TypeDNSKEY: {setDNSKEY, true},
TypeDS: {setDS, true},
TypeEID: {setEID, true},
TypeEUI48: {setEUI48, false},
TypeEUI64: {setEUI64, false},
TypeGID: {setGID, false},
TypeGPOS: {setGPOS, false},
TypeHINFO: {setHINFO, true},
TypeHIP: {setHIP, true},
TypeKX: {setKX, false},
TypeL32: {setL32, false},
TypeL64: {setL64, false},
TypeLOC: {setLOC, true},
TypeLP: {setLP, false},
TypeMB: {setMB, false},
TypeMD: {setMD, false},
TypeMF: {setMF, false},
TypeMG: {setMG, false},
TypeMINFO: {setMINFO, false},
TypeMR: {setMR, false},
TypeMX: {setMX, false},
TypeNAPTR: {setNAPTR, false},
TypeNID: {setNID, false},
TypeNIMLOC: {setNIMLOC, true},
TypeNINFO: {setNINFO, true},
TypeNSAPPTR: {setNSAPPTR, false},
TypeNSEC3PARAM: {setNSEC3PARAM, false},
TypeNSEC3: {setNSEC3, true},
TypeNSEC: {setNSEC, true},
TypeNS: {setNS, false},
TypeOPENPGPKEY: {setOPENPGPKEY, true},
TypePTR: {setPTR, false},
TypePX: {setPX, false},
TypeSIG: {setSIG, true},
TypeRKEY: {setRKEY, true},
TypeRP: {setRP, false},
TypeRRSIG: {setRRSIG, true},
TypeRT: {setRT, false},
TypeSMIMEA: {setSMIMEA, true},
TypeSOA: {setSOA, false},
TypeSPF: {setSPF, true},
TypeAVC: {setAVC, true},
TypeSRV: {setSRV, false},
TypeSSHFP: {setSSHFP, true},
TypeTALINK: {setTALINK, false},
TypeTA: {setTA, true},
TypeTLSA: {setTLSA, true},
TypeTXT: {setTXT, true},
TypeUID: {setUID, false},
TypeUINFO: {setUINFO, true},
TypeURI: {setURI, true},
TypeX25: {setX25, false},
TypeTKEY: {setTKEY, true},
}