Skip to content
Snippets Groups Projects
scan_rr.go 40.7 KiB
Newer Older
  • Learn to ignore specific revisions
  • 	"bytes"
    
    	"encoding/base64"
    	"net"
    	"strconv"
    	"strings"
    )
    
    // A remainder of the rdata with embedded spaces, return the parsed string (sans the spaces)
    // or an error
    
    func endingToString(c *zlexer, errstr string) (string, *ParseError) {
    	var buffer bytes.Buffer
    
    	l, _ := c.Next() // zString
    
    	for l.value != zNewline && l.value != zEOF {
    		if l.err {
    
    			return buffer.String(), &ParseError{"", errstr, l}
    
    		}
    		switch l.value {
    		case zString:
    
    			buffer.WriteString(l.token)
    
    		case zBlank: // Ok
    		default:
    
    			return "", &ParseError{"", errstr, l}
    
    		l, _ = c.Next()
    
    
    	return buffer.String(), nil
    
    ale's avatar
    ale committed
    // 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 string) ([]string, *ParseError) {
    
    	// Get the remaining data until we see a zNewline
    
    	l, _ := c.Next()
    
    		return nil, &ParseError{"", errstr, l}
    
    ale's avatar
    ale committed
    	}
    
    	// Build the slice
    	s := make([]string, 0)
    	quote := false
    	empty := false
    	for l.value != zNewline && l.value != zEOF {
    		if l.err {
    
    			return nil, &ParseError{"", errstr, l}
    
    ale's avatar
    ale committed
    		}
    		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
    
    
    ale's avatar
    ale committed
    					p, i = p+255, i+255
    
    ale's avatar
    ale committed
    				s = append(s, sx...)
    				break
    			}
    
    ale's avatar
    ale committed
    			s = append(s, l.token)
    		case zBlank:
    			if quote {
    				// zBlank can only be seen in between txt parts.
    
    				return nil, &ParseError{"", errstr, l}
    
    ale's avatar
    ale committed
    		case zQuote:
    			if empty && quote {
    				s = append(s, "")
    
    ale's avatar
    ale committed
    			quote = !quote
    			empty = true
    		default:
    
    			return nil, &ParseError{"", errstr, l}
    
    		l, _ = c.Next()
    
    ale's avatar
    ale committed
    	}
    
    ale's avatar
    ale committed
    	if quote {
    
    		return nil, &ParseError{"", errstr, l}
    
    	return s, nil
    }
    
    func (rr *A) parse(c *zlexer, o string) *ParseError {
    
    	l, _ := c.Next()
    
    	rr.A = net.ParseIP(l.token)
    
    	// IPv4 addresses cannot include ":".
    	// We do this rather than use net.IP's To4() because
    	// To4() treats IPv4-mapped IPv6 addresses as being
    	// IPv4.
    	isIPv4 := !strings.Contains(l.token, ":")
    	if rr.A == nil || !isIPv4 || l.err {
    		return &ParseError{"", "bad A A", l}
    
    	return slurpRemainder(c)
    
    func (rr *AAAA) parse(c *zlexer, o string) *ParseError {
    
    	l, _ := c.Next()
    
    	rr.AAAA = net.ParseIP(l.token)
    
    	// IPv6 addresses must include ":", and IPv4
    	// addresses cannot include ":".
    	isIPv6 := strings.Contains(l.token, ":")
    	if rr.AAAA == nil || !isIPv6 || l.err {
    		return &ParseError{"", "bad AAAA AAAA", l}
    
    	return slurpRemainder(c)
    
    func (rr *NS) parse(c *zlexer, o string) *ParseError {
    
    	l, _ := c.Next()
    
    ale's avatar
    ale committed
    	name, nameOk := toAbsoluteName(l.token, o)
    	if l.err || !nameOk {
    
    		return &ParseError{"", "bad NS Ns", l}
    
    ale's avatar
    ale committed
    	rr.Ns = name
    
    	return slurpRemainder(c)
    
    func (rr *PTR) parse(c *zlexer, o string) *ParseError {
    
    	l, _ := c.Next()
    
    ale's avatar
    ale committed
    	name, nameOk := toAbsoluteName(l.token, o)
    	if l.err || !nameOk {
    
    		return &ParseError{"", "bad PTR Ptr", l}
    
    ale's avatar
    ale committed
    	rr.Ptr = name
    
    	return slurpRemainder(c)
    
    func (rr *NSAPPTR) parse(c *zlexer, o string) *ParseError {
    
    	l, _ := c.Next()
    
    ale's avatar
    ale committed
    	name, nameOk := toAbsoluteName(l.token, o)
    	if l.err || !nameOk {
    
    		return &ParseError{"", "bad NSAP-PTR Ptr", l}
    
    ale's avatar
    ale committed
    	rr.Ptr = name
    
    	return slurpRemainder(c)
    
    func (rr *RP) parse(c *zlexer, o string) *ParseError {
    
    	l, _ := c.Next()
    
    ale's avatar
    ale committed
    	mbox, mboxOk := toAbsoluteName(l.token, o)
    	if l.err || !mboxOk {
    
    		return &ParseError{"", "bad RP Mbox", l}
    
    ale's avatar
    ale committed
    	rr.Mbox = mbox
    
    
    	c.Next() // zBlank
    	l, _ = c.Next()
    
    ale's avatar
    ale committed
    
    	txt, txtOk := toAbsoluteName(l.token, o)
    	if l.err || !txtOk {
    
    		return &ParseError{"", "bad RP Txt", l}
    
    ale's avatar
    ale committed
    	rr.Txt = txt
    
    
    	return slurpRemainder(c)
    
    func (rr *MR) parse(c *zlexer, o string) *ParseError {
    
    	l, _ := c.Next()
    
    ale's avatar
    ale committed
    	name, nameOk := toAbsoluteName(l.token, o)
    	if l.err || !nameOk {
    
    		return &ParseError{"", "bad MR Mr", l}
    
    ale's avatar
    ale committed
    	rr.Mr = name
    
    	return slurpRemainder(c)
    
    func (rr *MB) parse(c *zlexer, o string) *ParseError {
    
    	l, _ := c.Next()
    
    ale's avatar
    ale committed
    	name, nameOk := toAbsoluteName(l.token, o)
    	if l.err || !nameOk {
    
    		return &ParseError{"", "bad MB Mb", l}
    
    ale's avatar
    ale committed
    	rr.Mb = name
    
    	return slurpRemainder(c)
    
    func (rr *MG) parse(c *zlexer, o string) *ParseError {
    
    	l, _ := c.Next()
    
    ale's avatar
    ale committed
    	name, nameOk := toAbsoluteName(l.token, o)
    	if l.err || !nameOk {
    
    		return &ParseError{"", "bad MG Mg", l}
    
    ale's avatar
    ale committed
    	rr.Mg = name
    
    	return slurpRemainder(c)
    
    func (rr *HINFO) parse(c *zlexer, o string) *ParseError {
    	chunks, e := endingToTxtSlice(c, "bad HINFO Fields")
    
    		return e
    
    	}
    
    	if ln := len(chunks); ln == 0 {
    
    		return 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 nil
    
    func (rr *MINFO) parse(c *zlexer, o string) *ParseError {
    
    	l, _ := c.Next()
    
    ale's avatar
    ale committed
    	rmail, rmailOk := toAbsoluteName(l.token, o)
    	if l.err || !rmailOk {
    
    		return &ParseError{"", "bad MINFO Rmail", l}
    
    ale's avatar
    ale committed
    	rr.Rmail = rmail
    
    
    	c.Next() // zBlank
    	l, _ = c.Next()
    
    ale's avatar
    ale committed
    
    	email, emailOk := toAbsoluteName(l.token, o)
    	if l.err || !emailOk {
    
    		return &ParseError{"", "bad MINFO Email", l}
    
    ale's avatar
    ale committed
    	rr.Email = email
    
    
    	return slurpRemainder(c)
    
    func (rr *MF) parse(c *zlexer, o string) *ParseError {
    
    	l, _ := c.Next()
    
    ale's avatar
    ale committed
    	name, nameOk := toAbsoluteName(l.token, o)
    	if l.err || !nameOk {
    
    		return &ParseError{"", "bad MF Mf", l}
    
    ale's avatar
    ale committed
    	rr.Mf = name
    
    	return slurpRemainder(c)
    
    func (rr *MD) parse(c *zlexer, o string) *ParseError {
    
    	l, _ := c.Next()
    
    ale's avatar
    ale committed
    	name, nameOk := toAbsoluteName(l.token, o)
    	if l.err || !nameOk {
    
    		return &ParseError{"", "bad MD Md", l}
    
    ale's avatar
    ale committed
    	rr.Md = name
    
    	return slurpRemainder(c)
    
    func (rr *MX) parse(c *zlexer, o string) *ParseError {
    
    	l, _ := c.Next()
    
    ale's avatar
    ale committed
    	i, e := strconv.ParseUint(l.token, 10, 16)
    
    	if e != nil || l.err {
    
    		return &ParseError{"", "bad MX Pref", l}
    
    	}
    	rr.Preference = uint16(i)
    
    ale's avatar
    ale committed
    
    
    	c.Next()        // zBlank
    	l, _ = c.Next() // zString
    
    ale's avatar
    ale committed
    
    	name, nameOk := toAbsoluteName(l.token, o)
    	if l.err || !nameOk {
    
    		return &ParseError{"", "bad MX Mx", l}
    
    ale's avatar
    ale committed
    	rr.Mx = name
    
    
    	return slurpRemainder(c)
    
    func (rr *RT) parse(c *zlexer, o string) *ParseError {
    
    	l, _ := c.Next()
    
    ale's avatar
    ale committed
    	i, e := strconv.ParseUint(l.token, 10, 16)
    
    		return &ParseError{"", "bad RT Preference", l}
    
    	}
    	rr.Preference = uint16(i)
    
    ale's avatar
    ale committed
    
    
    	c.Next()        // zBlank
    	l, _ = c.Next() // zString
    
    ale's avatar
    ale committed
    
    	name, nameOk := toAbsoluteName(l.token, o)
    	if l.err || !nameOk {
    
    		return &ParseError{"", "bad RT Host", l}
    
    ale's avatar
    ale committed
    	rr.Host = name
    
    
    	return slurpRemainder(c)
    
    func (rr *AFSDB) parse(c *zlexer, o string) *ParseError {
    
    	l, _ := c.Next()
    
    ale's avatar
    ale committed
    	i, e := strconv.ParseUint(l.token, 10, 16)
    
    	if e != nil || l.err {
    
    		return &ParseError{"", "bad AFSDB Subtype", l}
    
    	}
    	rr.Subtype = uint16(i)
    
    ale's avatar
    ale committed
    
    
    	c.Next()        // zBlank
    	l, _ = c.Next() // zString
    
    	rr.Hostname = l.token
    
    ale's avatar
    ale committed
    
    	name, nameOk := toAbsoluteName(l.token, o)
    	if l.err || !nameOk {
    
    		return &ParseError{"", "bad AFSDB Hostname", l}
    
    ale's avatar
    ale committed
    	rr.Hostname = name
    
    	return slurpRemainder(c)
    
    func (rr *X25) parse(c *zlexer, o string) *ParseError {
    
    	l, _ := c.Next()
    
    		return &ParseError{"", "bad X25 PSDNAddress", l}
    
    	}
    	rr.PSDNAddress = l.token
    
    	return slurpRemainder(c)
    
    func (rr *KX) parse(c *zlexer, o string) *ParseError {
    
    	l, _ := c.Next()
    
    ale's avatar
    ale committed
    	i, e := strconv.ParseUint(l.token, 10, 16)
    
    	if e != nil || l.err {
    
    		return &ParseError{"", "bad KX Pref", l}
    
    	}
    	rr.Preference = uint16(i)
    
    ale's avatar
    ale committed
    
    
    	c.Next()        // zBlank
    	l, _ = c.Next() // zString
    
    	rr.Exchanger = l.token
    
    ale's avatar
    ale committed
    
    	name, nameOk := toAbsoluteName(l.token, o)
    	if l.err || !nameOk {
    
    		return &ParseError{"", "bad KX Exchanger", l}
    
    ale's avatar
    ale committed
    	rr.Exchanger = name
    
    	return slurpRemainder(c)
    
    func (rr *CNAME) parse(c *zlexer, o string) *ParseError {
    
    	l, _ := c.Next()
    
    ale's avatar
    ale committed
    	name, nameOk := toAbsoluteName(l.token, o)
    	if l.err || !nameOk {
    
    		return &ParseError{"", "bad CNAME Target", l}
    
    ale's avatar
    ale committed
    	rr.Target = name
    
    	return slurpRemainder(c)
    
    func (rr *DNAME) parse(c *zlexer, o string) *ParseError {
    
    	l, _ := c.Next()
    
    ale's avatar
    ale committed
    	name, nameOk := toAbsoluteName(l.token, o)
    	if l.err || !nameOk {
    
    		return &ParseError{"", "bad DNAME Target", l}
    
    ale's avatar
    ale committed
    	rr.Target = name
    
    	return slurpRemainder(c)
    
    func (rr *SOA) parse(c *zlexer, o string) *ParseError {
    
    	l, _ := c.Next()
    
    ale's avatar
    ale committed
    	ns, nsOk := toAbsoluteName(l.token, o)
    	if l.err || !nsOk {
    
    		return &ParseError{"", "bad SOA Ns", l}
    
    ale's avatar
    ale committed
    	rr.Ns = ns
    
    	c.Next() // zBlank
    	l, _ = c.Next()
    
    ale's avatar
    ale committed
    
    	mbox, mboxOk := toAbsoluteName(l.token, o)
    	if l.err || !mboxOk {
    
    		return &ParseError{"", "bad SOA Mbox", l}
    
    ale's avatar
    ale committed
    	rr.Mbox = mbox
    
    
    	c.Next() // zBlank
    
    
    	var (
    		v  uint32
    		ok bool
    	)
    	for i := 0; i < 5; i++ {
    
    		l, _ = c.Next()
    
    			return &ParseError{"", "bad SOA zone parameter", l}
    
    		if j, err := strconv.ParseUint(l.token, 10, 32); err != nil {
    
    ale's avatar
    ale committed
    				// Serial must be a number
    
    				return &ParseError{"", "bad SOA zone parameter", l}
    
    ale's avatar
    ale committed
    			// We allow other fields to be unitful duration strings
    			if v, ok = stringToTTL(l.token); !ok {
    
    				return &ParseError{"", "bad SOA zone parameter", l}
    
    
    			}
    		} else {
    			v = uint32(j)
    		}
    		switch i {
    		case 0:
    			rr.Serial = v
    
    			c.Next() // zBlank
    
    			c.Next() // zBlank
    
    			c.Next() // zBlank
    
    			c.Next() // zBlank
    
    	return slurpRemainder(c)
    
    func (rr *SRV) parse(c *zlexer, o string) *ParseError {
    
    	l, _ := c.Next()
    
    ale's avatar
    ale committed
    	i, e := strconv.ParseUint(l.token, 10, 16)
    
    	if e != nil || l.err {
    
    		return &ParseError{"", "bad SRV Priority", l}
    
    	}
    	rr.Priority = uint16(i)
    
    ale's avatar
    ale committed
    
    
    	c.Next()        // zBlank
    	l, _ = c.Next() // zString
    
    	i, e1 := strconv.ParseUint(l.token, 10, 16)
    	if e1 != nil || l.err {
    		return &ParseError{"", "bad SRV Weight", l}
    
    	}
    	rr.Weight = uint16(i)
    
    ale's avatar
    ale committed
    
    
    	c.Next()        // zBlank
    	l, _ = c.Next() // zString
    
    	i, e2 := strconv.ParseUint(l.token, 10, 16)
    	if e2 != nil || l.err {
    		return &ParseError{"", "bad SRV Port", l}
    
    ale's avatar
    ale committed
    
    
    	c.Next()        // zBlank
    	l, _ = c.Next() // zString
    
    	rr.Target = l.token
    
    ale's avatar
    ale committed
    
    	name, nameOk := toAbsoluteName(l.token, o)
    	if l.err || !nameOk {
    
    		return &ParseError{"", "bad SRV Target", l}
    
    ale's avatar
    ale committed
    	rr.Target = name
    
    	return slurpRemainder(c)
    
    func (rr *NAPTR) parse(c *zlexer, o string) *ParseError {
    
    	l, _ := c.Next()
    
    ale's avatar
    ale committed
    	i, e := strconv.ParseUint(l.token, 10, 16)
    
    	if e != nil || l.err {
    
    		return &ParseError{"", "bad NAPTR Order", l}
    
    ale's avatar
    ale committed
    
    
    	c.Next()        // zBlank
    	l, _ = c.Next() // zString
    
    	i, e1 := strconv.ParseUint(l.token, 10, 16)
    	if e1 != nil || l.err {
    		return &ParseError{"", "bad NAPTR Preference", l}
    
    	}
    	rr.Preference = uint16(i)
    
    ale's avatar
    ale committed
    
    
    	c.Next()        // zBlank
    	l, _ = c.Next() // _QUOTE
    
    	if l.value != zQuote {
    
    		return &ParseError{"", "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 &ParseError{"", "bad NAPTR Flags", l}
    
    		}
    	} else if l.value == zQuote {
    		rr.Flags = ""
    	} else {
    
    		return &ParseError{"", "bad NAPTR Flags", l}
    
    	c.Next()        // zBlank
    	l, _ = c.Next() // _QUOTE
    
    	if l.value != zQuote {
    
    		return &ParseError{"", "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 &ParseError{"", "bad NAPTR Service", l}
    
    		}
    	} else if l.value == zQuote {
    		rr.Service = ""
    	} else {
    
    		return &ParseError{"", "bad NAPTR Service", l}
    
    	c.Next()        // zBlank
    	l, _ = c.Next() // _QUOTE
    
    	if l.value != zQuote {
    
    		return &ParseError{"", "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 &ParseError{"", "bad NAPTR Regexp", l}
    
    		}
    	} else if l.value == zQuote {
    		rr.Regexp = ""
    	} else {
    
    		return &ParseError{"", "bad NAPTR Regexp", l}
    
    ale's avatar
    ale committed
    
    
    	// After quote no space??
    
    	c.Next()        // zBlank
    	l, _ = c.Next() // zString
    
    	rr.Replacement = l.token
    
    ale's avatar
    ale committed
    
    	name, nameOk := toAbsoluteName(l.token, o)
    	if l.err || !nameOk {
    
    		return &ParseError{"", "bad NAPTR Replacement", l}
    
    ale's avatar
    ale committed
    	rr.Replacement = name
    
    	return slurpRemainder(c)
    
    func (rr *TALINK) parse(c *zlexer, o string) *ParseError {
    
    	l, _ := c.Next()
    
    ale's avatar
    ale committed
    	previousName, previousNameOk := toAbsoluteName(l.token, o)
    	if l.err || !previousNameOk {
    
    		return &ParseError{"", "bad TALINK PreviousName", l}
    
    ale's avatar
    ale committed
    	rr.PreviousName = previousName
    
    
    	c.Next() // zBlank
    	l, _ = c.Next()
    
    	rr.NextName = l.token
    
    ale's avatar
    ale committed
    
    	nextName, nextNameOk := toAbsoluteName(l.token, o)
    	if l.err || !nextNameOk {
    
    		return &ParseError{"", "bad TALINK NextName", l}
    
    ale's avatar
    ale committed
    	rr.NextName = nextName
    
    
    	return slurpRemainder(c)
    
    func (rr *LOC) parse(c *zlexer, o string) *ParseError {
    
    	// Non zero defaults for LOC record, see RFC 1876, Section 3.
    
    	rr.Size = 0x12     // 1e2 cm (1m)
    	rr.HorizPre = 0x16 // 1e6 cm (10000m)
    	rr.VertPre = 0x13  // 1e3 cm (10m)
    
    ale's avatar
    ale committed
    
    
    	l, _ := c.Next()
    
    ale's avatar
    ale committed
    	i, e := strconv.ParseUint(l.token, 10, 32)
    
    	if e != nil || l.err || i > 90 {
    		return &ParseError{"", "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
    	}
    
    	if i, err := strconv.ParseUint(l.token, 10, 32); err != nil || l.err || i > 59 {
    		return &ParseError{"", "bad LOC Latitude minutes", l}
    	} else {
    		rr.Latitude += 1000 * 60 * uint32(i)
    
    	c.Next() // zBlank
    	l, _ = c.Next()
    
    	if i, err := strconv.ParseFloat(l.token, 64); err != nil || l.err || i < 0 || i >= 60 {
    
    		return &ParseError{"", "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 &ParseError{"", "bad LOC Latitude North/South", l}
    
    	c.Next() // zBlank
    	l, _ = c.Next()
    
    	if i, err := strconv.ParseUint(l.token, 10, 32); err != nil || l.err || i > 180 {
    		return &ParseError{"", "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, err := strconv.ParseUint(l.token, 10, 32); err != nil || l.err || i > 59 {
    		return &ParseError{"", "bad LOC Longitude minutes", l}
    
    	} else {
    		rr.Longitude += 1000 * 60 * uint32(i)
    	}
    
    	c.Next() // zBlank
    	l, _ = c.Next()
    
    	if i, err := strconv.ParseFloat(l.token, 64); err != nil || l.err || i < 0 || i >= 60 {
    
    		return &ParseError{"", "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 &ParseError{"", "bad LOC Longitude East/West", l}
    
    	c.Next() // zBlank
    	l, _ = c.Next()
    
    	if l.token == "" || l.err {
    
    		return &ParseError{"", "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, err := strconv.ParseFloat(l.token, 64); err != nil {
    		return &ParseError{"", "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
    
    				exp, m, ok := stringToCm(l.token)
    
    					return &ParseError{"", "bad LOC Size", l}
    
    				rr.Size = exp&0x0f | m<<4&0xf0
    
    			case 1: // HorizPre
    
    				exp, m, ok := stringToCm(l.token)
    
    					return &ParseError{"", "bad LOC HorizPre", l}
    
    				rr.HorizPre = exp&0x0f | m<<4&0xf0
    
    				exp, m, ok := stringToCm(l.token)
    
    					return &ParseError{"", "bad LOC VertPre", l}
    
    				rr.VertPre = exp&0x0f | m<<4&0xf0
    
    			}
    			count++
    		case zBlank:
    			// Ok
    		default:
    
    			return &ParseError{"", "bad LOC Size, HorizPre or VertPre", l}
    
    		l, _ = c.Next()
    
    	return nil
    
    func (rr *HIP) parse(c *zlexer, o string) *ParseError {
    
    	// HitLength is not represented
    
    	l, _ := c.Next()
    
    ale's avatar
    ale committed
    	i, e := strconv.ParseUint(l.token, 10, 8)
    
    	if e != nil || l.err {
    
    		return &ParseError{"", "bad HIP PublicKeyAlgorithm", l}
    
    	}
    	rr.PublicKeyAlgorithm = uint8(i)
    
    ale's avatar
    ale committed
    
    
    	c.Next()        // zBlank
    	l, _ = c.Next() // zString
    
    	if l.token == "" || l.err {
    
    		return &ParseError{"", "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 l.token == "" || l.err {
    
    		return &ParseError{"", "bad HIP PublicKey", l}
    
    	}
    	rr.PublicKey = l.token // This cannot contain spaces
    
    	decodedPK, decodedPKerr := base64.StdEncoding.DecodeString(rr.PublicKey)
    	if decodedPKerr != nil {
    		return &ParseError{"", "bad HIP PublicKey", l}
    	}
    	rr.PublicKeyLength = uint16(len(decodedPK))
    
    
    	// RendezvousServers (if any)
    
    	l, _ = c.Next()
    
    	var xs []string
    	for l.value != zNewline && l.value != zEOF {
    		switch l.value {
    		case zString:
    
    ale's avatar
    ale committed
    			name, nameOk := toAbsoluteName(l.token, o)
    			if l.err || !nameOk {
    
    				return &ParseError{"", "bad HIP RendezvousServers", l}
    
    ale's avatar
    ale committed
    			xs = append(xs, name)
    
    		case zBlank:
    			// Ok
    		default:
    
    			return &ParseError{"", "bad HIP RendezvousServers", l}
    
    		l, _ = c.Next()
    
    	rr.RendezvousServers = xs
    
    	return nil
    
    func (rr *CERT) parse(c *zlexer, o string) *ParseError {
    
    	l, _ := c.Next()
    
    	if v, ok := StringToCertType[l.token]; ok {
    		rr.Type = v
    
    	} else if i, err := strconv.ParseUint(l.token, 10, 16); err != nil {
    		return &ParseError{"", "bad CERT Type", l}
    
    	} else {
    		rr.Type = uint16(i)
    	}
    
    	c.Next()        // zBlank
    	l, _ = c.Next() // zString
    
    ale's avatar
    ale committed
    	i, e := strconv.ParseUint(l.token, 10, 16)
    
    	if e != nil || l.err {
    
    		return &ParseError{"", "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, err := strconv.ParseUint(l.token, 10, 8); err != nil {
    		return &ParseError{"", "bad CERT Algorithm", l}
    
    	} else {
    		rr.Algorithm = uint8(i)
    	}
    
    	s, e1 := endingToString(c, "bad CERT Certificate")
    
    		return e1
    
    	return nil
    
    func (rr *OPENPGPKEY) parse(c *zlexer, o string) *ParseError {
    	s, e := endingToString(c, "bad OPENPGPKEY PublicKey")
    
    		return e
    
    	return nil
    
    func (rr *CSYNC) parse(c *zlexer, o string) *ParseError {
    
    	l, _ := c.Next()
    
    ale's avatar
    ale committed
    	j, e := strconv.ParseUint(l.token, 10, 32)
    	if e != nil {
    		// Serial must be a number
    
    		return &ParseError{"", "bad CSYNC serial", l}
    
    ale's avatar
    ale committed
    	}
    	rr.Serial = uint32(j)
    
    
    	c.Next() // zBlank
    
    ale's avatar
    ale committed
    
    
    	l, _ = c.Next()
    
    	j, e1 := strconv.ParseUint(l.token, 10, 16)
    	if e1 != nil {
    
    ale's avatar
    ale committed
    		// Serial must be a number
    
    		return &ParseError{"", "bad CSYNC flags", l}
    
    ale's avatar
    ale committed
    	}
    	rr.Flags = uint16(j)
    
    	rr.TypeBitMap = make([]uint16, 0)
    	var (
    		k  uint16
    		ok bool
    	)
    
    	l, _ = c.Next()
    
    ale's avatar
    ale committed
    	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 &ParseError{"", "bad CSYNC TypeBitMap", l}
    
    ale's avatar
    ale committed
    				}
    			}
    			rr.TypeBitMap = append(rr.TypeBitMap, k)
    		default:
    
    			return &ParseError{"", "bad CSYNC TypeBitMap", l}
    
    ale's avatar
    ale committed
    		}
    
    		l, _ = c.Next()
    
    ale's avatar
    ale committed
    	}
    
    	return nil
    
    ale's avatar
    ale committed
    }
    
    
    func (rr *ZONEMD) parse(c *zlexer, o string) *ParseError {
    	l, _ := c.Next()
    	i, e := strconv.ParseUint(l.token, 10, 32)
    	if e != nil || l.err {
    		return &ParseError{"", "bad ZONEMD Serial", l}
    	}
    	rr.Serial = uint32(i)
    
    	c.Next() // zBlank
    	l, _ = c.Next()
    	i, e1 := strconv.ParseUint(l.token, 10, 8)
    	if e1 != nil || l.err {
    		return &ParseError{"", "bad ZONEMD Scheme", l}
    	}
    	rr.Scheme = uint8(i)
    
    	c.Next() // zBlank
    	l, _ = c.Next()
    	i, err := strconv.ParseUint(l.token, 10, 8)
    	if err != nil || l.err {
    		return &ParseError{"", "bad ZONEMD Hash Algorithm", l}
    	}
    	rr.Hash = uint8(i)
    
    	s, e2 := endingToString(c, "bad ZONEMD Digest")
    	if e2 != nil {
    		return e2
    	}
    	rr.Digest = s
    	return nil
    }
    
    
    func (rr *SIG) parse(c *zlexer, o string) *ParseError { return rr.RRSIG.parse(c, o) }
    
    ale's avatar
    ale committed
    
    
    func (rr *RRSIG) parse(c *zlexer, o string) *ParseError {
    
    	l, _ := c.Next()
    	tokenUpper := strings.ToUpper(l.token)
    	if t, ok := StringToType[tokenUpper]; !ok {
    		if strings.HasPrefix(tokenUpper, "TYPE") {
    			t, ok = typeToInt(l.token)
    
    				return &ParseError{"", "bad RRSIG Typecovered", l}
    
    			}
    			rr.TypeCovered = t
    		} else {
    
    			return &ParseError{"", "bad RRSIG Typecovered", l}
    
    ale's avatar
    ale committed
    
    
    	c.Next() // zBlank
    	l, _ = c.Next()
    
    	i, e := strconv.ParseUint(l.token, 10, 8)
    	if e != nil || l.err {
    		return &ParseError{"", "bad RRSIG Algorithm", l}
    
    	}
    	rr.Algorithm = uint8(i)
    
    ale's avatar
    ale committed
    
    
    	c.Next() // zBlank
    	l, _ = c.Next()
    
    	i, e1 := strconv.ParseUint(l.token, 10, 8)
    	if e1 != nil || l.err {
    		return &ParseError{"", "bad RRSIG Labels", l}
    
    ale's avatar
    ale committed
    
    
    	c.Next() // zBlank
    	l, _ = c.Next()
    
    	i, e2 := strconv.ParseUint(l.token, 10, 32)
    	if e2 != nil || l.err {
    		return &ParseError{"", "bad RRSIG OrigTtl", l}
    
    	}
    	rr.OrigTtl = uint32(i)
    
    ale's avatar
    ale committed
    
    
    	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.ParseUint(l.token, 10, 32); err == nil {
    
    			rr.Expiration = uint32(i)
    		} else {
    
    			return &ParseError{"", "bad RRSIG Expiration", l}
    
    ale's avatar
    ale committed
    
    
    	c.Next() // zBlank
    	l, _ = c.Next()
    
    	if i, err := StringToTime(l.token); err != nil {
    
    		if i, err := strconv.ParseUint(l.token, 10, 32); err == nil {
    
    			rr.Inception = uint32(i)
    		} else {
    
    			return &ParseError{"", "bad RRSIG Inception", l}
    
    ale's avatar
    ale committed
    
    
    	c.Next() // zBlank
    	l, _ = c.Next()
    
    	i, e3 := strconv.ParseUint(l.token, 10, 16)
    	if e3 != nil || l.err {
    		return &ParseError{"", "bad RRSIG KeyTag", l}
    
    	}
    	rr.KeyTag = uint16(i)
    
    ale's avatar
    ale committed
    
    
    	c.Next() // zBlank
    	l, _ = c.Next()
    
    	rr.SignerName = l.token
    
    ale's avatar
    ale committed
    	name, nameOk := toAbsoluteName(l.token, o)
    	if l.err || !nameOk {
    
    		return &ParseError{"", "bad RRSIG SignerName", l}
    
    ale's avatar
    ale committed
    	rr.SignerName = name
    
    
    	s, e4 := endingToString(c, "bad RRSIG Signature")
    	if e4 != nil {
    		return e4
    
    ale's avatar
    ale committed
    
    
    	return nil
    
    func (rr *NSEC) parse(c *zlexer, o string) *ParseError {
    
    	l, _ := c.Next()
    
    ale's avatar
    ale committed
    	name, nameOk := toAbsoluteName(l.token, o)
    	if l.err || !nameOk {
    
    		return &ParseError{"", "bad NSEC NextDomain", l}
    
    ale's avatar
    ale committed
    	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 {