Newer
Older
"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
for l.value != zNewline && l.value != zEOF {
if l.err {
return buffer.String(), &ParseError{"", errstr, l}
}
switch l.value {
case zString:
case zBlank: // Ok
default:
// 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
}
// Build the slice
s := make([]string, 0)
quote := false
empty := false
for l.value != zNewline && l.value != zEOF {
if l.err {
}
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
s = append(s, l.token)
case zBlank:
if quote {
// zBlank can only be seen in between txt parts.
func (rr *A) parse(c *zlexer, o string) *ParseError {
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}
func (rr *AAAA) parse(c *zlexer, o string) *ParseError {
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}
func (rr *NS) parse(c *zlexer, o string) *ParseError {
name, nameOk := toAbsoluteName(l.token, o)
if l.err || !nameOk {
func (rr *PTR) parse(c *zlexer, o string) *ParseError {
name, nameOk := toAbsoluteName(l.token, o)
if l.err || !nameOk {
func (rr *NSAPPTR) parse(c *zlexer, o string) *ParseError {
name, nameOk := toAbsoluteName(l.token, o)
if l.err || !nameOk {
return &ParseError{"", "bad NSAP-PTR Ptr", l}
func (rr *RP) parse(c *zlexer, o string) *ParseError {
mbox, mboxOk := toAbsoluteName(l.token, o)
if l.err || !mboxOk {
txt, txtOk := toAbsoluteName(l.token, o)
if l.err || !txtOk {
func (rr *MR) parse(c *zlexer, o string) *ParseError {
name, nameOk := toAbsoluteName(l.token, o)
if l.err || !nameOk {
func (rr *MB) parse(c *zlexer, o string) *ParseError {
name, nameOk := toAbsoluteName(l.token, o)
if l.err || !nameOk {
func (rr *MG) parse(c *zlexer, o string) *ParseError {
name, nameOk := toAbsoluteName(l.token, o)
if l.err || !nameOk {
func (rr *HINFO) parse(c *zlexer, o string) *ParseError {
chunks, e := endingToTxtSlice(c, "bad HINFO Fields")
}
if ln := len(chunks); ln == 0 {
} 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:], " ")
func (rr *MINFO) parse(c *zlexer, o string) *ParseError {
rmail, rmailOk := toAbsoluteName(l.token, o)
if l.err || !rmailOk {
return &ParseError{"", "bad MINFO Rmail", l}
email, emailOk := toAbsoluteName(l.token, o)
if l.err || !emailOk {
return &ParseError{"", "bad MINFO Email", l}
func (rr *MF) parse(c *zlexer, o string) *ParseError {
name, nameOk := toAbsoluteName(l.token, o)
if l.err || !nameOk {
func (rr *MD) parse(c *zlexer, o string) *ParseError {
name, nameOk := toAbsoluteName(l.token, o)
if l.err || !nameOk {
func (rr *MX) parse(c *zlexer, o string) *ParseError {
}
rr.Preference = uint16(i)
c.Next() // zBlank
l, _ = c.Next() // zString
name, nameOk := toAbsoluteName(l.token, o)
if l.err || !nameOk {
func (rr *RT) parse(c *zlexer, o string) *ParseError {
return &ParseError{"", "bad RT Preference", l}
}
rr.Preference = uint16(i)
c.Next() // zBlank
l, _ = c.Next() // zString
name, nameOk := toAbsoluteName(l.token, o)
if l.err || !nameOk {
func (rr *AFSDB) parse(c *zlexer, o string) *ParseError {
return &ParseError{"", "bad AFSDB Subtype", l}
}
rr.Subtype = uint16(i)
c.Next() // zBlank
l, _ = c.Next() // zString
name, nameOk := toAbsoluteName(l.token, o)
if l.err || !nameOk {
return &ParseError{"", "bad AFSDB Hostname", l}
func (rr *X25) parse(c *zlexer, o string) *ParseError {
return &ParseError{"", "bad X25 PSDNAddress", l}
}
rr.PSDNAddress = l.token
func (rr *KX) parse(c *zlexer, o string) *ParseError {
}
rr.Preference = uint16(i)
c.Next() // zBlank
l, _ = c.Next() // zString
name, nameOk := toAbsoluteName(l.token, o)
if l.err || !nameOk {
return &ParseError{"", "bad KX Exchanger", l}
func (rr *CNAME) parse(c *zlexer, o string) *ParseError {
name, nameOk := toAbsoluteName(l.token, o)
if l.err || !nameOk {
return &ParseError{"", "bad CNAME Target", l}
func (rr *DNAME) parse(c *zlexer, o string) *ParseError {
name, nameOk := toAbsoluteName(l.token, o)
if l.err || !nameOk {
return &ParseError{"", "bad DNAME Target", l}
func (rr *SOA) parse(c *zlexer, o string) *ParseError {
ns, nsOk := toAbsoluteName(l.token, o)
if l.err || !nsOk {
mbox, mboxOk := toAbsoluteName(l.token, o)
if l.err || !mboxOk {
var (
v uint32
ok bool
)
for i := 0; i < 5; i++ {
return &ParseError{"", "bad SOA zone parameter", l}
if j, err := strconv.ParseUint(l.token, 10, 32); err != nil {
return &ParseError{"", "bad SOA zone parameter", l}
// 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
case 1:
rr.Refresh = v
case 2:
rr.Retry = v
case 3:
rr.Expire = v
case 4:
rr.Minttl = v
}
}
func (rr *SRV) parse(c *zlexer, o string) *ParseError {
return &ParseError{"", "bad SRV Priority", l}
}
rr.Priority = uint16(i)
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)
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}
}
rr.Port = uint16(i)
c.Next() // zBlank
l, _ = c.Next() // zString
name, nameOk := toAbsoluteName(l.token, o)
if l.err || !nameOk {
return &ParseError{"", "bad SRV Target", l}
func (rr *NAPTR) parse(c *zlexer, o string) *ParseError {
return &ParseError{"", "bad NAPTR Order", l}
}
rr.Order = uint16(i)
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)
c.Next() // zBlank
l, _ = c.Next() // _QUOTE
return &ParseError{"", "bad NAPTR Flags", l}
l, _ = c.Next() // Either String or Quote
if l.value == zString {
rr.Flags = l.token
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
return &ParseError{"", "bad NAPTR Service", l}
l, _ = c.Next() // Either String or Quote
if l.value == zString {
rr.Service = l.token
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
return &ParseError{"", "bad NAPTR Regexp", l}
l, _ = c.Next() // Either String or Quote
if l.value == zString {
rr.Regexp = l.token
return &ParseError{"", "bad NAPTR Regexp", l}
}
} else if l.value == zQuote {
rr.Regexp = ""
} else {
return &ParseError{"", "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 &ParseError{"", "bad NAPTR Replacement", l}
func (rr *TALINK) parse(c *zlexer, o string) *ParseError {
previousName, previousNameOk := toAbsoluteName(l.token, o)
if l.err || !previousNameOk {
return &ParseError{"", "bad TALINK PreviousName", l}
nextName, nextNameOk := toAbsoluteName(l.token, o)
if l.err || !nextNameOk {
return &ParseError{"", "bad TALINK NextName", l}
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)
if e != nil || l.err || i > 90 {
return &ParseError{"", "bad LOC Latitude", l}
}
rr.Latitude = 1000 * 60 * 60 * uint32(i)
// Either number, 'N' or 'S'
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)
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)
}
// Either number, 'N' or 'S'
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}
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)
}
// Either number, 'E' or 'W'
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)
}
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)
}
// Either number, 'E' or 'W'
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}
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
count := 0
for l.value != zNewline && l.value != zEOF {
switch l.value {
case zString:
switch count {
case 0: // Size
return &ParseError{"", "bad LOC HorizPre", l}
return &ParseError{"", "bad LOC VertPre", l}
}
count++
case zBlank:
// Ok
default:
return &ParseError{"", "bad LOC Size, HorizPre or VertPre", l}
func (rr *HIP) parse(c *zlexer, o string) *ParseError {
// HitLength is not represented
return &ParseError{"", "bad HIP PublicKeyAlgorithm", l}
}
rr.PublicKeyAlgorithm = uint8(i)
c.Next() // zBlank
l, _ = c.Next() // zString
}
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
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)
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 &ParseError{"", "bad HIP RendezvousServers", l}
case zBlank:
// Ok
default:
return &ParseError{"", "bad HIP RendezvousServers", l}
rr.RendezvousServers = xs
func (rr *CERT) parse(c *zlexer, o string) *ParseError {
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
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")
}
rr.Certificate = s
func (rr *OPENPGPKEY) parse(c *zlexer, o string) *ParseError {
s, e := endingToString(c, "bad OPENPGPKEY PublicKey")
func (rr *CSYNC) parse(c *zlexer, o string) *ParseError {
j, e := strconv.ParseUint(l.token, 10, 32)
if e != nil {
// Serial must be a number
return &ParseError{"", "bad CSYNC serial", l}
j, e1 := strconv.ParseUint(l.token, 10, 16)
if e1 != nil {
return &ParseError{"", "bad CSYNC flags", l}
}
rr.Flags = uint16(j)
rr.TypeBitMap = make([]uint16, 0)
var (
k uint16
ok bool
)
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}
}
}
rr.TypeBitMap = append(rr.TypeBitMap, k)
default:
return &ParseError{"", "bad CSYNC TypeBitMap", l}
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
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) }
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}
}
} else {
rr.TypeCovered = t
}
i, e := strconv.ParseUint(l.token, 10, 8)
if e != nil || l.err {
return &ParseError{"", "bad RRSIG Algorithm", l}
}
rr.Algorithm = uint8(i)
i, e1 := strconv.ParseUint(l.token, 10, 8)
if e1 != nil || l.err {
return &ParseError{"", "bad RRSIG Labels", l}
}
rr.Labels = uint8(i)
i, e2 := strconv.ParseUint(l.token, 10, 32)
if e2 != nil || l.err {
return &ParseError{"", "bad RRSIG OrigTtl", l}
}
rr.OrigTtl = uint32(i)
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}
}
} else {
rr.Expiration = i
}
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}
}
} else {
rr.Inception = i
}
i, e3 := strconv.ParseUint(l.token, 10, 16)
if e3 != nil || l.err {
return &ParseError{"", "bad RRSIG KeyTag", l}
}
rr.KeyTag = uint16(i)
name, nameOk := toAbsoluteName(l.token, o)
if l.err || !nameOk {
return &ParseError{"", "bad RRSIG SignerName", l}
s, e4 := endingToString(c, "bad RRSIG Signature")
if e4 != nil {
return e4
func (rr *NSEC) parse(c *zlexer, o string) *ParseError {
name, nameOk := toAbsoluteName(l.token, o)
if l.err || !nameOk {
return &ParseError{"", "bad NSEC NextDomain", l}
rr.TypeBitMap = make([]uint16, 0)
var (
k uint16
ok bool
)
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 {