Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • ale/autoradio
1 result
Show changes
Showing
with 1154 additions and 1131 deletions
...@@ -3,7 +3,6 @@ package dns ...@@ -3,7 +3,6 @@ package dns
import ( import (
"bufio" "bufio"
"crypto" "crypto"
"crypto/dsa"
"crypto/ecdsa" "crypto/ecdsa"
"crypto/rsa" "crypto/rsa"
"io" "io"
...@@ -44,26 +43,7 @@ func (k *DNSKEY) ReadPrivateKey(q io.Reader, file string) (crypto.PrivateKey, er ...@@ -44,26 +43,7 @@ func (k *DNSKEY) ReadPrivateKey(q io.Reader, file string) (crypto.PrivateKey, er
return nil, ErrPrivKey return nil, ErrPrivKey
} }
switch uint8(algo) { switch uint8(algo) {
case DSA: case RSASHA1, RSASHA1NSEC3SHA1, RSASHA256, RSASHA512:
priv, err := readPrivateKeyDSA(m)
if err != nil {
return nil, err
}
pub := k.publicKeyDSA()
if pub == nil {
return nil, ErrKey
}
priv.PublicKey = *pub
return priv, nil
case RSAMD5:
fallthrough
case RSASHA1:
fallthrough
case RSASHA1NSEC3SHA1:
fallthrough
case RSASHA256:
fallthrough
case RSASHA512:
priv, err := readPrivateKeyRSA(m) priv, err := readPrivateKeyRSA(m)
if err != nil { if err != nil {
return nil, err return nil, err
...@@ -74,11 +54,7 @@ func (k *DNSKEY) ReadPrivateKey(q io.Reader, file string) (crypto.PrivateKey, er ...@@ -74,11 +54,7 @@ func (k *DNSKEY) ReadPrivateKey(q io.Reader, file string) (crypto.PrivateKey, er
} }
priv.PublicKey = *pub priv.PublicKey = *pub
return priv, nil return priv, nil
case ECCGOST: case ECDSAP256SHA256, ECDSAP384SHA384:
return nil, ErrPrivKey
case ECDSAP256SHA256:
fallthrough
case ECDSAP384SHA384:
priv, err := readPrivateKeyECDSA(m) priv, err := readPrivateKeyECDSA(m)
if err != nil { if err != nil {
return nil, err return nil, err
...@@ -92,7 +68,7 @@ func (k *DNSKEY) ReadPrivateKey(q io.Reader, file string) (crypto.PrivateKey, er ...@@ -92,7 +68,7 @@ func (k *DNSKEY) ReadPrivateKey(q io.Reader, file string) (crypto.PrivateKey, er
case ED25519: case ED25519:
return readPrivateKeyED25519(m) return readPrivateKeyED25519(m)
default: default:
return nil, ErrPrivKey return nil, ErrAlg
} }
} }
...@@ -129,24 +105,6 @@ func readPrivateKeyRSA(m map[string]string) (*rsa.PrivateKey, error) { ...@@ -129,24 +105,6 @@ func readPrivateKeyRSA(m map[string]string) (*rsa.PrivateKey, error) {
return p, nil return p, nil
} }
func readPrivateKeyDSA(m map[string]string) (*dsa.PrivateKey, error) {
p := new(dsa.PrivateKey)
p.X = new(big.Int)
for k, v := range m {
switch k {
case "private_value(x)":
v1, err := fromBase64([]byte(v))
if err != nil {
return nil, err
}
p.X.SetBytes(v1)
case "created", "publish", "activate":
/* not used in Go (yet) */
}
}
return p, nil
}
func readPrivateKeyECDSA(m map[string]string) (*ecdsa.PrivateKey, error) { func readPrivateKeyECDSA(m map[string]string) (*ecdsa.PrivateKey, error) {
p := new(ecdsa.PrivateKey) p := new(ecdsa.PrivateKey)
p.D = new(big.Int) p.D = new(big.Int)
......
...@@ -2,7 +2,6 @@ package dns ...@@ -2,7 +2,6 @@ package dns
import ( import (
"crypto" "crypto"
"crypto/dsa"
"crypto/ecdsa" "crypto/ecdsa"
"crypto/rsa" "crypto/rsa"
"math/big" "math/big"
...@@ -17,8 +16,8 @@ var bigIntOne = big.NewInt(1) ...@@ -17,8 +16,8 @@ var bigIntOne = big.NewInt(1)
// PrivateKeyString converts a PrivateKey to a string. This string has the same // PrivateKeyString converts a PrivateKey to a string. This string has the same
// format as the private-key-file of BIND9 (Private-key-format: v1.3). // format as the private-key-file of BIND9 (Private-key-format: v1.3).
// It needs some info from the key (the algorithm), so its a method of the DNSKEY // It needs some info from the key (the algorithm), so its a method of the DNSKEY.
// It supports rsa.PrivateKey, ecdsa.PrivateKey and dsa.PrivateKey // It supports *rsa.PrivateKey, *ecdsa.PrivateKey and ed25519.PrivateKey.
func (r *DNSKEY) PrivateKeyString(p crypto.PrivateKey) string { func (r *DNSKEY) PrivateKeyString(p crypto.PrivateKey) string {
algorithm := strconv.Itoa(int(r.Algorithm)) algorithm := strconv.Itoa(int(r.Algorithm))
algorithm += " (" + AlgorithmToString[r.Algorithm] + ")" algorithm += " (" + AlgorithmToString[r.Algorithm] + ")"
...@@ -67,21 +66,6 @@ func (r *DNSKEY) PrivateKeyString(p crypto.PrivateKey) string { ...@@ -67,21 +66,6 @@ func (r *DNSKEY) PrivateKeyString(p crypto.PrivateKey) string {
"Algorithm: " + algorithm + "\n" + "Algorithm: " + algorithm + "\n" +
"PrivateKey: " + private + "\n" "PrivateKey: " + private + "\n"
case *dsa.PrivateKey:
T := divRoundUp(divRoundUp(p.PublicKey.Parameters.G.BitLen(), 8)-64, 8)
prime := toBase64(intToBytes(p.PublicKey.Parameters.P, 64+T*8))
subprime := toBase64(intToBytes(p.PublicKey.Parameters.Q, 20))
base := toBase64(intToBytes(p.PublicKey.Parameters.G, 64+T*8))
priv := toBase64(intToBytes(p.X, 20))
pub := toBase64(intToBytes(p.PublicKey.Y, 64+T*8))
return format +
"Algorithm: " + algorithm + "\n" +
"Prime(p): " + prime + "\n" +
"Subprime(q): " + subprime + "\n" +
"Base(g): " + base + "\n" +
"Private_value(x): " + priv + "\n" +
"Public_value(y): " + pub + "\n"
case ed25519.PrivateKey: case ed25519.PrivateKey:
private := toBase64(p.Seed()) private := toBase64(p.Seed())
return format + return format +
......
...@@ -83,7 +83,7 @@ with: ...@@ -83,7 +83,7 @@ with:
in, err := dns.Exchange(m1, "127.0.0.1:53") in, err := dns.Exchange(m1, "127.0.0.1:53")
When this functions returns you will get dns message. A dns message consists When this functions returns you will get DNS message. A DNS message consists
out of four sections. out of four sections.
The question section: in.Question, the answer section: in.Answer, The question section: in.Question, the answer section: in.Answer,
the authority section: in.Ns and the additional section: in.Extra. the authority section: in.Ns and the additional section: in.Extra.
...@@ -209,7 +209,7 @@ Basic use pattern validating and replying to a message that has TSIG set. ...@@ -209,7 +209,7 @@ Basic use pattern validating and replying to a message that has TSIG set.
// *Msg r has an TSIG record and it was validated // *Msg r has an TSIG record and it was validated
m.SetTsig("axfr.", dns.HmacMD5, 300, time.Now().Unix()) m.SetTsig("axfr.", dns.HmacMD5, 300, time.Now().Unix())
} else { } else {
// *Msg r has an TSIG records and it was not valided // *Msg r has an TSIG records and it was not validated
} }
} }
w.WriteMsg(m) w.WriteMsg(m)
...@@ -221,7 +221,7 @@ RFC 6895 sets aside a range of type codes for private use. This range is 65,280 ...@@ -221,7 +221,7 @@ RFC 6895 sets aside a range of type codes for private use. This range is 65,280
- 65,534 (0xFF00 - 0xFFFE). When experimenting with new Resource Records these - 65,534 (0xFF00 - 0xFFFE). When experimenting with new Resource Records these
can be used, before requesting an official type code from IANA. can be used, before requesting an official type code from IANA.
See https://miek.nl/2014/September/21/idn-and-private-rr-in-go-dns/ for more See https://miek.nl/2014/september/21/idn-and-private-rr-in-go-dns/ for more
information. information.
EDNS0 EDNS0
...@@ -238,9 +238,8 @@ Basic use pattern for creating an (empty) OPT RR: ...@@ -238,9 +238,8 @@ Basic use pattern for creating an (empty) OPT RR:
The rdata of an OPT RR consists out of a slice of EDNS0 (RFC 6891) interfaces. The rdata of an OPT RR consists out of a slice of EDNS0 (RFC 6891) interfaces.
Currently only a few have been standardized: EDNS0_NSID (RFC 5001) and Currently only a few have been standardized: EDNS0_NSID (RFC 5001) and
EDNS0_SUBNET (draft-vandergaast-edns-client-subnet-02). Note that these options EDNS0_SUBNET (RFC 7871). Note that these options may be combined in an OPT RR.
may be combined in an OPT RR. Basic use pattern for a server to check if (and Basic use pattern for a server to check if (and which) options are set:
which) options are set:
// o is a dns.OPT // o is a dns.OPT
for _, s := range o.Option { for _, s := range o.Option {
...@@ -261,7 +260,7 @@ From RFC 2931: ...@@ -261,7 +260,7 @@ From RFC 2931:
on requests and responses, and protection of the overall integrity of a response. on requests and responses, and protection of the overall integrity of a response.
It works like TSIG, except that SIG(0) uses public key cryptography, instead of It works like TSIG, except that SIG(0) uses public key cryptography, instead of
the shared secret approach in TSIG. Supported algorithms: DSA, ECDSAP256SHA256, the shared secret approach in TSIG. Supported algorithms: ECDSAP256SHA256,
ECDSAP384SHA384, RSASHA1, RSASHA256 and RSASHA512. ECDSAP384SHA384, RSASHA1, RSASHA256 and RSASHA512.
Signing subsequent messages in multi-message sessions is not implemented. Signing subsequent messages in multi-message sessions is not implemented.
......
...@@ -3,9 +3,8 @@ package dns ...@@ -3,9 +3,8 @@ package dns
//go:generate go run duplicate_generate.go //go:generate go run duplicate_generate.go
// IsDuplicate checks of r1 and r2 are duplicates of each other, excluding the TTL. // IsDuplicate checks of r1 and r2 are duplicates of each other, excluding the TTL.
// So this means the header data is equal *and* the RDATA is the same. Return true // So this means the header data is equal *and* the RDATA is the same. Returns true
// is so, otherwise false. // if so, otherwise false. It's a protocol violation to have identical RRs in a message.
// It's is a protocol violation to have identical RRs in a message.
func IsDuplicate(r1, r2 RR) bool { func IsDuplicate(r1, r2 RR) bool {
// Check whether the record header is identical. // Check whether the record header is identical.
if !r1.Header().isDuplicate(r2.Header()) { if !r1.Header().isDuplicate(r2.Header()) {
......
...@@ -88,7 +88,7 @@ func (rr *OPT) len(off int, compression map[string]struct{}) int { ...@@ -88,7 +88,7 @@ func (rr *OPT) len(off int, compression map[string]struct{}) int {
return l return l
} }
func (rr *OPT) parse(c *zlexer, origin, file string) *ParseError { func (rr *OPT) parse(c *zlexer, origin string) *ParseError {
panic("dns: internal error: parse should never be called on OPT") panic("dns: internal error: parse should never be called on OPT")
} }
...@@ -360,7 +360,7 @@ func (e *EDNS0_COOKIE) copy() EDNS0 { return &EDNS0_COOKIE{e.Code, e.C ...@@ -360,7 +360,7 @@ func (e *EDNS0_COOKIE) copy() EDNS0 { return &EDNS0_COOKIE{e.Code, e.C
// The EDNS0_UL (Update Lease) (draft RFC) option is used to tell the server to set // The EDNS0_UL (Update Lease) (draft RFC) option is used to tell the server to set
// an expiration on an update RR. This is helpful for clients that cannot clean // an expiration on an update RR. This is helpful for clients that cannot clean
// up after themselves. This is a draft RFC and more information can be found at // up after themselves. This is a draft RFC and more information can be found at
// http://files.dns-sd.org/draft-sekar-dns-ul.txt // https://tools.ietf.org/html/draft-sekar-dns-ul-02
// //
// o := new(dns.OPT) // o := new(dns.OPT)
// o.Hdr.Name = "." // o.Hdr.Name = "."
...@@ -370,24 +370,36 @@ func (e *EDNS0_COOKIE) copy() EDNS0 { return &EDNS0_COOKIE{e.Code, e.C ...@@ -370,24 +370,36 @@ func (e *EDNS0_COOKIE) copy() EDNS0 { return &EDNS0_COOKIE{e.Code, e.C
// e.Lease = 120 // in seconds // e.Lease = 120 // in seconds
// o.Option = append(o.Option, e) // o.Option = append(o.Option, e)
type EDNS0_UL struct { type EDNS0_UL struct {
Code uint16 // Always EDNS0UL Code uint16 // Always EDNS0UL
Lease uint32 Lease uint32
KeyLease uint32
} }
// Option implements the EDNS0 interface. // Option implements the EDNS0 interface.
func (e *EDNS0_UL) Option() uint16 { return EDNS0UL } func (e *EDNS0_UL) Option() uint16 { return EDNS0UL }
func (e *EDNS0_UL) String() string { return strconv.FormatUint(uint64(e.Lease), 10) } func (e *EDNS0_UL) String() string { return fmt.Sprintf("%d %d", e.Lease, e.KeyLease) }
func (e *EDNS0_UL) copy() EDNS0 { return &EDNS0_UL{e.Code, e.Lease} } func (e *EDNS0_UL) copy() EDNS0 { return &EDNS0_UL{e.Code, e.Lease, e.KeyLease} }
// Copied: http://golang.org/src/pkg/net/dnsmsg.go // Copied: http://golang.org/src/pkg/net/dnsmsg.go
func (e *EDNS0_UL) pack() ([]byte, error) { func (e *EDNS0_UL) pack() ([]byte, error) {
b := make([]byte, 4) var b []byte
if e.KeyLease == 0 {
b = make([]byte, 4)
} else {
b = make([]byte, 8)
binary.BigEndian.PutUint32(b[4:], e.KeyLease)
}
binary.BigEndian.PutUint32(b, e.Lease) binary.BigEndian.PutUint32(b, e.Lease)
return b, nil return b, nil
} }
func (e *EDNS0_UL) unpack(b []byte) error { func (e *EDNS0_UL) unpack(b []byte) error {
if len(b) < 4 { switch len(b) {
case 4:
e.KeyLease = 0
case 8:
e.KeyLease = binary.BigEndian.Uint32(b[4:])
default:
return ErrBuf return ErrBuf
} }
e.Lease = binary.BigEndian.Uint32(b) e.Lease = binary.BigEndian.Uint32(b)
...@@ -531,6 +543,10 @@ func (e *EDNS0_EXPIRE) pack() ([]byte, error) { ...@@ -531,6 +543,10 @@ func (e *EDNS0_EXPIRE) pack() ([]byte, error) {
} }
func (e *EDNS0_EXPIRE) unpack(b []byte) error { func (e *EDNS0_EXPIRE) unpack(b []byte) error {
if len(b) == 0 {
// zero-length EXPIRE query, see RFC 7314 Section 2
return nil
}
if len(b) < 4 { if len(b) < 4 {
return ErrBuf return ErrBuf
} }
......
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
package dns package dns
import "strings"
func Fuzz(data []byte) int { func Fuzz(data []byte) int {
msg := new(Msg) msg := new(Msg)
...@@ -16,7 +18,14 @@ func Fuzz(data []byte) int { ...@@ -16,7 +18,14 @@ func Fuzz(data []byte) int {
} }
func FuzzNewRR(data []byte) int { func FuzzNewRR(data []byte) int {
if _, err := NewRR(string(data)); err != nil { str := string(data)
// Do not fuzz lines that include the $INCLUDE keyword and hint the fuzzer
// at avoiding them.
// See GH#1025 for context.
if strings.Contains(strings.ToUpper(str), "$INCLUDE") {
return -1
}
if _, err := NewRR(str); err != nil {
return 0 return 0
} }
return 1 return 1
......
...@@ -20,13 +20,13 @@ import ( ...@@ -20,13 +20,13 @@ import (
// of $ after that are interpreted. // of $ after that are interpreted.
func (zp *ZoneParser) generate(l lex) (RR, bool) { func (zp *ZoneParser) generate(l lex) (RR, bool) {
token := l.token token := l.token
step := 1 step := int64(1)
if i := strings.IndexByte(token, '/'); i >= 0 { if i := strings.IndexByte(token, '/'); i >= 0 {
if i+1 == len(token) { if i+1 == len(token) {
return zp.setParseError("bad step in $GENERATE range", l) return zp.setParseError("bad step in $GENERATE range", l)
} }
s, err := strconv.Atoi(token[i+1:]) s, err := strconv.ParseInt(token[i+1:], 10, 64)
if err != nil || s <= 0 { if err != nil || s <= 0 {
return zp.setParseError("bad step in $GENERATE range", l) return zp.setParseError("bad step in $GENERATE range", l)
} }
...@@ -40,20 +40,24 @@ func (zp *ZoneParser) generate(l lex) (RR, bool) { ...@@ -40,20 +40,24 @@ func (zp *ZoneParser) generate(l lex) (RR, bool) {
return zp.setParseError("bad start-stop in $GENERATE range", l) return zp.setParseError("bad start-stop in $GENERATE range", l)
} }
start, err := strconv.Atoi(sx[0]) start, err := strconv.ParseInt(sx[0], 10, 64)
if err != nil { if err != nil {
return zp.setParseError("bad start in $GENERATE range", l) return zp.setParseError("bad start in $GENERATE range", l)
} }
end, err := strconv.Atoi(sx[1]) end, err := strconv.ParseInt(sx[1], 10, 64)
if err != nil { if err != nil {
return zp.setParseError("bad stop in $GENERATE range", l) return zp.setParseError("bad stop in $GENERATE range", l)
} }
if end < 0 || start < 0 || end < start { if end < 0 || start < 0 || end < start || (end-start)/step > 65535 {
return zp.setParseError("bad range in $GENERATE range", l) return zp.setParseError("bad range in $GENERATE range", l)
} }
zp.c.Next() // _BLANK // _BLANK
l, ok := zp.c.Next()
if !ok || l.value != zBlank {
return zp.setParseError("garbage after $GENERATE range", l)
}
// Create a complete new string, which we then parse again. // Create a complete new string, which we then parse again.
var s string var s string
...@@ -71,16 +75,17 @@ func (zp *ZoneParser) generate(l lex) (RR, bool) { ...@@ -71,16 +75,17 @@ func (zp *ZoneParser) generate(l lex) (RR, bool) {
r := &generateReader{ r := &generateReader{
s: s, s: s,
cur: start, cur: int(start),
start: start, start: int(start),
end: end, end: int(end),
step: step, step: int(step),
file: zp.file, file: zp.file,
lex: &l, lex: &l,
} }
zp.sub = NewZoneParser(r, zp.origin, zp.file) zp.sub = NewZoneParser(r, zp.origin, zp.file)
zp.sub.includeDepth, zp.sub.includeAllowed = zp.includeDepth, zp.includeAllowed zp.sub.includeDepth, zp.sub.includeAllowed = zp.includeDepth, zp.includeAllowed
zp.sub.generateDisallowed = true
zp.sub.SetDefaultTTL(defaultTtl) zp.sub.SetDefaultTTL(defaultTtl)
return zp.subNext() return zp.subNext()
} }
...@@ -183,7 +188,7 @@ func (r *generateReader) ReadByte() (byte, error) { ...@@ -183,7 +188,7 @@ func (r *generateReader) ReadByte() (byte, error) {
if errMsg != "" { if errMsg != "" {
return 0, r.parseError(errMsg, si+3+sep) return 0, r.parseError(errMsg, si+3+sep)
} }
if r.start+offset < 0 || r.end+offset > 1<<31-1 { if r.start+offset < 0 || int64(r.end) + int64(offset) > 1<<31-1 {
return 0, r.parseError("bad offset in $GENERATE", si+3+sep) return 0, r.parseError("bad offset in $GENERATE", si+3+sep)
} }
...@@ -224,19 +229,19 @@ func modToPrintf(s string) (string, int, string) { ...@@ -224,19 +229,19 @@ func modToPrintf(s string) (string, int, string) {
return "", 0, "bad base in $GENERATE" return "", 0, "bad base in $GENERATE"
} }
offset, err := strconv.Atoi(offStr) offset, err := strconv.ParseInt(offStr, 10, 64)
if err != nil { if err != nil {
return "", 0, "bad offset in $GENERATE" return "", 0, "bad offset in $GENERATE"
} }
width, err := strconv.Atoi(widthStr) width, err := strconv.ParseInt(widthStr, 10, 64)
if err != nil || width < 0 || width > 255 { if err != nil || width < 0 || width > 255 {
return "", 0, "bad width in $GENERATE" return "", 0, "bad width in $GENERATE"
} }
if width == 0 { if width == 0 {
return "%" + base, offset, "" return "%" + base, int(offset), ""
} }
return "%0" + widthStr + base, offset, "" return "%0" + widthStr + base, int(offset), ""
} }
module github.com/miekg/dns
go 1.12
require (
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550
golang.org/x/net v0.0.0-20190923162816-aa69164e4478
golang.org/x/sync v0.0.0-20190423024810-112230192c58
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe
golang.org/x/tools v0.0.0-20191216052735-49a3e744a425 // indirect
)
golang.org/x/crypto v0.0.0-20181001203147-e3636079e1a4 h1:Vk3wNqEZwyGyei9yq5ekj7frek2u7HUfffJ1/opblzc=
golang.org/x/crypto v0.0.0-20181001203147-e3636079e1a4/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190829043050-9756ffdc2472 h1:Gv7RPwsi3eZ2Fgewe3CBsuOebPwO27PoXzRpJPsvSSM=
golang.org/x/crypto v0.0.0-20190829043050-9756ffdc2472/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392 h1:ACG4HJsFiNMf47Y4PeRoebLNy/2lXT9EtprMuTFWt1M=
golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/net v0.0.0-20180926154720-4dfa2610cdf3 h1:dgd4x4kJt7G4k4m93AYLzM8Ni6h2qLTfh9n9vXJT3/0=
golang.org/x/net v0.0.0-20180926154720-4dfa2610cdf3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190923162816-aa69164e4478 h1:l5EDrHhldLYb3ZRHDUhXF7Om7MvYXnkV9/iQNo1lX6g=
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180928133829-e4b3c5e90611 h1:O33LKL7WyJgjN9CvxfTIomjIClbd/Kq86/iipowHQU0=
golang.org/x/sys v0.0.0-20180928133829-e4b3c5e90611/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd h1:DBH9mDw0zluJT/R+nGuV3jWFWLFaHyYZWD4tOT+cjn0=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe h1:6fAMxZRR6sl1Uq8U61gxU+kPTs2tR8uOySCbBP7BN/M=
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191216052735-49a3e744a425 h1:VvQyQJN0tSuecqgcIxMWnnfG5kSmgy9KZR9sW3W5QeA=
golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
...@@ -83,7 +83,7 @@ func CompareDomainName(s1, s2 string) (n int) { ...@@ -83,7 +83,7 @@ func CompareDomainName(s1, s2 string) (n int) {
return return
} }
// CountLabel counts the the number of labels in the string s. // CountLabel counts the number of labels in the string s.
// s must be a syntactically valid domain name. // s must be a syntactically valid domain name.
func CountLabel(s string) (labels int) { func CountLabel(s string) (labels int) {
if s == "." { if s == "." {
...@@ -126,20 +126,23 @@ func Split(s string) []int { ...@@ -126,20 +126,23 @@ func Split(s string) []int {
// The bool end is true when the end of the string has been reached. // The bool end is true when the end of the string has been reached.
// Also see PrevLabel. // Also see PrevLabel.
func NextLabel(s string, offset int) (i int, end bool) { func NextLabel(s string, offset int) (i int, end bool) {
quote := false if s == "" {
return 0, true
}
for i = offset; i < len(s)-1; i++ { for i = offset; i < len(s)-1; i++ {
switch s[i] { if s[i] != '.' {
case '\\': continue
quote = !quote }
default: j := i - 1
quote = false for j >= 0 && s[j] == '\\' {
case '.': j--
if quote { }
quote = !quote
continue if (j-i)%2 == 0 {
} continue
return i + 1, false
} }
return i + 1, false
} }
return i + 1, true return i + 1, true
} }
...@@ -149,17 +152,38 @@ func NextLabel(s string, offset int) (i int, end bool) { ...@@ -149,17 +152,38 @@ func NextLabel(s string, offset int) (i int, end bool) {
// The bool start is true when the start of the string has been overshot. // The bool start is true when the start of the string has been overshot.
// Also see NextLabel. // Also see NextLabel.
func PrevLabel(s string, n int) (i int, start bool) { func PrevLabel(s string, n int) (i int, start bool) {
if s == "" {
return 0, true
}
if n == 0 { if n == 0 {
return len(s), false return len(s), false
} }
lab := Split(s)
if lab == nil { l := len(s) - 1
return 0, true if s[l] == '.' {
l--
} }
if n > len(lab) {
return 0, true for ; l >= 0 && n > 0; l-- {
if s[l] != '.' {
continue
}
j := l - 1
for j >= 0 && s[j] == '\\' {
j--
}
if (j-l)%2 == 0 {
continue
}
n--
if n == 0 {
return l + 1, false
}
} }
return lab[len(lab)-n], false
return 0, n > 1
} }
// equal compares a and b while ignoring case. It returns true when equal otherwise false. // equal compares a and b while ignoring case. It returns true when equal otherwise false.
......
...@@ -11,14 +11,12 @@ package dns ...@@ -11,14 +11,12 @@ package dns
//go:generate go run msg_generate.go //go:generate go run msg_generate.go
import ( import (
crand "crypto/rand" "crypto/rand"
"encoding/binary" "encoding/binary"
"fmt" "fmt"
"math/big" "math/big"
"math/rand"
"strconv" "strconv"
"strings" "strings"
"sync"
) )
const ( const (
...@@ -73,53 +71,23 @@ var ( ...@@ -73,53 +71,23 @@ var (
ErrTime error = &Error{err: "bad time"} // ErrTime indicates a timing error in TSIG authentication. ErrTime error = &Error{err: "bad time"} // ErrTime indicates a timing error in TSIG authentication.
) )
// Id by default, returns a 16 bits random number to be used as a // Id by default returns a 16-bit random number to be used as a message id. The
// message id. The random provided should be good enough. This being a // number is drawn from a cryptographically secure random number generator.
// variable the function can be reassigned to a custom function. // This being a variable the function can be reassigned to a custom function.
// For instance, to make it return a static value: // For instance, to make it return a static value for testing:
// //
// dns.Id = func() uint16 { return 3 } // dns.Id = func() uint16 { return 3 }
var Id = id var Id = id
var (
idLock sync.Mutex
idRand *rand.Rand
)
// id returns a 16 bits random number to be used as a // id returns a 16 bits random number to be used as a
// message id. The random provided should be good enough. // message id. The random provided should be good enough.
func id() uint16 { func id() uint16 {
idLock.Lock() var output uint16
err := binary.Read(rand.Reader, binary.BigEndian, &output)
if idRand == nil { if err != nil {
// This (partially) works around panic("dns: reading random id failed: " + err.Error())
// https://github.com/golang/go/issues/11833 by only
// seeding idRand upon the first call to id.
var seed int64
var buf [8]byte
if _, err := crand.Read(buf[:]); err == nil {
seed = int64(binary.LittleEndian.Uint64(buf[:]))
} else {
seed = rand.Int63()
}
idRand = rand.New(rand.NewSource(seed))
} }
return output
// The call to idRand.Uint32 must be within the
// mutex lock because *rand.Rand is not safe for
// concurrent use.
//
// There is no added performance overhead to calling
// idRand.Uint32 inside a mutex lock over just
// calling rand.Uint32 as the global math/rand rng
// is internally protected by a sync.Mutex.
id := uint16(idRand.Uint32())
idLock.Unlock()
return id
} }
// MsgHdr is a a manually-unpacked version of (id, bits). // MsgHdr is a a manually-unpacked version of (id, bits).
...@@ -430,17 +398,12 @@ Loop: ...@@ -430,17 +398,12 @@ Loop:
return "", lenmsg, ErrLongDomain return "", lenmsg, ErrLongDomain
} }
for _, b := range msg[off : off+c] { for _, b := range msg[off : off+c] {
switch b { if isDomainNameLabelSpecial(b) {
case '.', '(', ')', ';', ' ', '@':
fallthrough
case '"', '\\':
s = append(s, '\\', b) s = append(s, '\\', b)
default: } else if b < ' ' || b > '~' {
if b < ' ' || b > '~' { // unprintable, use \DDD s = append(s, escapeByte(b)...)
s = append(s, escapeByte(b)...) } else {
} else { s = append(s, b)
s = append(s, b)
}
} }
} }
s = append(s, '.') s = append(s, '.')
...@@ -693,7 +656,6 @@ func unpackRRslice(l int, msg []byte, off int) (dst1 []RR, off1 int, err error) ...@@ -693,7 +656,6 @@ func unpackRRslice(l int, msg []byte, off int) (dst1 []RR, off1 int, err error)
} }
// If offset does not increase anymore, l is a lie // If offset does not increase anymore, l is a lie
if off1 == off { if off1 == off {
l = i
break break
} }
dst = append(dst, r) dst = append(dst, r)
......
...@@ -6,6 +6,7 @@ import ( ...@@ -6,6 +6,7 @@ import (
"encoding/binary" "encoding/binary"
"encoding/hex" "encoding/hex"
"net" "net"
"sort"
"strings" "strings"
) )
...@@ -265,24 +266,36 @@ func unpackString(msg []byte, off int) (string, int, error) { ...@@ -265,24 +266,36 @@ func unpackString(msg []byte, off int) (string, int, error) {
return "", off, &Error{err: "overflow unpacking txt"} return "", off, &Error{err: "overflow unpacking txt"}
} }
l := int(msg[off]) l := int(msg[off])
if off+l+1 > len(msg) { off++
if off+l > len(msg) {
return "", off, &Error{err: "overflow unpacking txt"} return "", off, &Error{err: "overflow unpacking txt"}
} }
var s strings.Builder var s strings.Builder
s.Grow(l) consumed := 0
for _, b := range msg[off+1 : off+1+l] { for i, b := range msg[off : off+l] {
switch { switch {
case b == '"' || b == '\\': case b == '"' || b == '\\':
if consumed == 0 {
s.Grow(l * 2)
}
s.Write(msg[off+consumed : off+i])
s.WriteByte('\\') s.WriteByte('\\')
s.WriteByte(b) s.WriteByte(b)
consumed = i + 1
case b < ' ' || b > '~': // unprintable case b < ' ' || b > '~': // unprintable
if consumed == 0 {
s.Grow(l * 2)
}
s.Write(msg[off+consumed : off+i])
s.WriteString(escapeByte(b)) s.WriteString(escapeByte(b))
default: consumed = i + 1
s.WriteByte(b)
} }
} }
off += 1 + l if consumed == 0 { // no escaping needed
return s.String(), off, nil return string(msg[off : off+l]), off + l, nil
}
s.Write(msg[off+consumed : off+l])
return s.String(), off + l, nil
} }
func packString(s string, msg []byte, off int) (int, error) { func packString(s string, msg []byte, off int) (int, error) {
...@@ -411,100 +424,60 @@ Option: ...@@ -411,100 +424,60 @@ Option:
if off+int(optlen) > len(msg) { if off+int(optlen) > len(msg) {
return nil, len(msg), &Error{err: "overflow unpacking opt"} return nil, len(msg), &Error{err: "overflow unpacking opt"}
} }
e := makeDataOpt(code)
if err := e.unpack(msg[off : off+int(optlen)]); err != nil {
return nil, len(msg), err
}
edns = append(edns, e)
off += int(optlen)
if off < len(msg) {
goto Option
}
return edns, off, nil
}
func makeDataOpt(code uint16) EDNS0 {
switch code { switch code {
case EDNS0NSID: case EDNS0NSID:
e := new(EDNS0_NSID) return new(EDNS0_NSID)
if err := e.unpack(msg[off : off+int(optlen)]); err != nil {
return nil, len(msg), err
}
edns = append(edns, e)
off += int(optlen)
case EDNS0SUBNET: case EDNS0SUBNET:
e := new(EDNS0_SUBNET) return new(EDNS0_SUBNET)
if err := e.unpack(msg[off : off+int(optlen)]); err != nil {
return nil, len(msg), err
}
edns = append(edns, e)
off += int(optlen)
case EDNS0COOKIE: case EDNS0COOKIE:
e := new(EDNS0_COOKIE) return new(EDNS0_COOKIE)
if err := e.unpack(msg[off : off+int(optlen)]); err != nil { case EDNS0EXPIRE:
return nil, len(msg), err return new(EDNS0_EXPIRE)
}
edns = append(edns, e)
off += int(optlen)
case EDNS0UL: case EDNS0UL:
e := new(EDNS0_UL) return new(EDNS0_UL)
if err := e.unpack(msg[off : off+int(optlen)]); err != nil {
return nil, len(msg), err
}
edns = append(edns, e)
off += int(optlen)
case EDNS0LLQ: case EDNS0LLQ:
e := new(EDNS0_LLQ) return new(EDNS0_LLQ)
if err := e.unpack(msg[off : off+int(optlen)]); err != nil {
return nil, len(msg), err
}
edns = append(edns, e)
off += int(optlen)
case EDNS0DAU: case EDNS0DAU:
e := new(EDNS0_DAU) return new(EDNS0_DAU)
if err := e.unpack(msg[off : off+int(optlen)]); err != nil {
return nil, len(msg), err
}
edns = append(edns, e)
off += int(optlen)
case EDNS0DHU: case EDNS0DHU:
e := new(EDNS0_DHU) return new(EDNS0_DHU)
if err := e.unpack(msg[off : off+int(optlen)]); err != nil {
return nil, len(msg), err
}
edns = append(edns, e)
off += int(optlen)
case EDNS0N3U: case EDNS0N3U:
e := new(EDNS0_N3U) return new(EDNS0_N3U)
if err := e.unpack(msg[off : off+int(optlen)]); err != nil {
return nil, len(msg), err
}
edns = append(edns, e)
off += int(optlen)
case EDNS0PADDING: case EDNS0PADDING:
e := new(EDNS0_PADDING) return new(EDNS0_PADDING)
if err := e.unpack(msg[off : off+int(optlen)]); err != nil {
return nil, len(msg), err
}
edns = append(edns, e)
off += int(optlen)
default: default:
e := new(EDNS0_LOCAL) e := new(EDNS0_LOCAL)
e.Code = code e.Code = code
if err := e.unpack(msg[off : off+int(optlen)]); err != nil { return e
return nil, len(msg), err
}
edns = append(edns, e)
off += int(optlen)
} }
if off < len(msg) {
goto Option
}
return edns, off, nil
} }
func packDataOpt(options []EDNS0, msg []byte, off int) (int, error) { func packDataOpt(options []EDNS0, msg []byte, off int) (int, error) {
for _, el := range options { for _, el := range options {
b, err := el.pack() b, err := el.pack()
if err != nil || off+3 > len(msg) { if err != nil || off+4 > len(msg) {
return len(msg), &Error{err: "overflow packing opt"} return len(msg), &Error{err: "overflow packing opt"}
} }
binary.BigEndian.PutUint16(msg[off:], el.Option()) // Option code binary.BigEndian.PutUint16(msg[off:], el.Option()) // Option code
binary.BigEndian.PutUint16(msg[off+2:], uint16(len(b))) // Length binary.BigEndian.PutUint16(msg[off+2:], uint16(len(b))) // Length
off += 4 off += 4
if off+len(b) > len(msg) { if off+len(b) > len(msg) {
copy(msg[off:], b) return len(msg), &Error{err: "overflow packing opt"}
off = len(msg)
continue
} }
// Actual data // Actual data
copy(msg[off:off+len(b)], b) copy(msg[off:off+len(b)], b)
...@@ -587,6 +560,29 @@ func unpackDataNsec(msg []byte, off int) ([]uint16, int, error) { ...@@ -587,6 +560,29 @@ func unpackDataNsec(msg []byte, off int) ([]uint16, int, error) {
return nsec, off, nil return nsec, off, nil
} }
// typeBitMapLen is a helper function which computes the "maximum" length of
// a the NSEC Type BitMap field.
func typeBitMapLen(bitmap []uint16) int {
var l int
var lastwindow, lastlength uint16
for _, t := range bitmap {
window := t / 256
length := (t-window*256)/8 + 1
if window > lastwindow && lastlength != 0 { // New window, jump to the new offset
l += int(lastlength) + 2
lastlength = 0
}
if window < lastwindow || length < lastlength {
// packDataNsec would return Error{err: "nsec bits out of order"} here, but
// when computing the length, we want do be liberal.
continue
}
lastwindow, lastlength = window, length
}
l += int(lastlength) + 2
return l
}
func packDataNsec(bitmap []uint16, msg []byte, off int) (int, error) { func packDataNsec(bitmap []uint16, msg []byte, off int) (int, error) {
if len(bitmap) == 0 { if len(bitmap) == 0 {
return off, nil return off, nil
...@@ -617,6 +613,65 @@ func packDataNsec(bitmap []uint16, msg []byte, off int) (int, error) { ...@@ -617,6 +613,65 @@ func packDataNsec(bitmap []uint16, msg []byte, off int) (int, error) {
return off, nil return off, nil
} }
func unpackDataSVCB(msg []byte, off int) ([]SVCBKeyValue, int, error) {
var xs []SVCBKeyValue
var code uint16
var length uint16
var err error
for off < len(msg) {
code, off, err = unpackUint16(msg, off)
if err != nil {
return nil, len(msg), &Error{err: "overflow unpacking SVCB"}
}
length, off, err = unpackUint16(msg, off)
if err != nil || off+int(length) > len(msg) {
return nil, len(msg), &Error{err: "overflow unpacking SVCB"}
}
e := makeSVCBKeyValue(SVCBKey(code))
if e == nil {
return nil, len(msg), &Error{err: "bad SVCB key"}
}
if err := e.unpack(msg[off : off+int(length)]); err != nil {
return nil, len(msg), err
}
if len(xs) > 0 && e.Key() <= xs[len(xs)-1].Key() {
return nil, len(msg), &Error{err: "SVCB keys not in strictly increasing order"}
}
xs = append(xs, e)
off += int(length)
}
return xs, off, nil
}
func packDataSVCB(pairs []SVCBKeyValue, msg []byte, off int) (int, error) {
pairs = append([]SVCBKeyValue(nil), pairs...)
sort.Slice(pairs, func(i, j int) bool {
return pairs[i].Key() < pairs[j].Key()
})
prev := svcb_RESERVED
for _, el := range pairs {
if el.Key() == prev {
return len(msg), &Error{err: "repeated SVCB keys are not allowed"}
}
prev = el.Key()
packed, err := el.pack()
if err != nil {
return len(msg), err
}
off, err = packUint16(uint16(el.Key()), msg, off)
if err != nil {
return len(msg), &Error{err: "overflow packing SVCB"}
}
off, err = packUint16(uint16(len(packed)), msg, off)
if err != nil || off+len(packed) > len(msg) {
return len(msg), &Error{err: "overflow packing SVCB"}
}
copy(msg[off:off+len(packed)], packed)
off += len(packed)
}
return off, nil
}
func unpackDataDomainNames(msg []byte, off, end int) ([]string, int, error) { func unpackDataDomainNames(msg []byte, off, end int) ([]string, int, error) {
var ( var (
servers []string servers []string
...@@ -646,3 +701,133 @@ func packDataDomainNames(names []string, msg []byte, off int, compression compre ...@@ -646,3 +701,133 @@ func packDataDomainNames(names []string, msg []byte, off int, compression compre
} }
return off, nil return off, nil
} }
func packDataApl(data []APLPrefix, msg []byte, off int) (int, error) {
var err error
for i := range data {
off, err = packDataAplPrefix(&data[i], msg, off)
if err != nil {
return len(msg), err
}
}
return off, nil
}
func packDataAplPrefix(p *APLPrefix, msg []byte, off int) (int, error) {
if len(p.Network.IP) != len(p.Network.Mask) {
return len(msg), &Error{err: "address and mask lengths don't match"}
}
var err error
prefix, _ := p.Network.Mask.Size()
addr := p.Network.IP.Mask(p.Network.Mask)[:(prefix+7)/8]
switch len(p.Network.IP) {
case net.IPv4len:
off, err = packUint16(1, msg, off)
case net.IPv6len:
off, err = packUint16(2, msg, off)
default:
err = &Error{err: "unrecognized address family"}
}
if err != nil {
return len(msg), err
}
off, err = packUint8(uint8(prefix), msg, off)
if err != nil {
return len(msg), err
}
var n uint8
if p.Negation {
n = 0x80
}
// trim trailing zero bytes as specified in RFC3123 Sections 4.1 and 4.2.
i := len(addr) - 1
for ; i >= 0 && addr[i] == 0; i-- {
}
addr = addr[:i+1]
adflen := uint8(len(addr)) & 0x7f
off, err = packUint8(n|adflen, msg, off)
if err != nil {
return len(msg), err
}
if off+len(addr) > len(msg) {
return len(msg), &Error{err: "overflow packing APL prefix"}
}
off += copy(msg[off:], addr)
return off, nil
}
func unpackDataApl(msg []byte, off int) ([]APLPrefix, int, error) {
var result []APLPrefix
for off < len(msg) {
prefix, end, err := unpackDataAplPrefix(msg, off)
if err != nil {
return nil, len(msg), err
}
off = end
result = append(result, prefix)
}
return result, off, nil
}
func unpackDataAplPrefix(msg []byte, off int) (APLPrefix, int, error) {
family, off, err := unpackUint16(msg, off)
if err != nil {
return APLPrefix{}, len(msg), &Error{err: "overflow unpacking APL prefix"}
}
prefix, off, err := unpackUint8(msg, off)
if err != nil {
return APLPrefix{}, len(msg), &Error{err: "overflow unpacking APL prefix"}
}
nlen, off, err := unpackUint8(msg, off)
if err != nil {
return APLPrefix{}, len(msg), &Error{err: "overflow unpacking APL prefix"}
}
var ip []byte
switch family {
case 1:
ip = make([]byte, net.IPv4len)
case 2:
ip = make([]byte, net.IPv6len)
default:
return APLPrefix{}, len(msg), &Error{err: "unrecognized APL address family"}
}
if int(prefix) > 8*len(ip) {
return APLPrefix{}, len(msg), &Error{err: "APL prefix too long"}
}
afdlen := int(nlen & 0x7f)
if afdlen > len(ip) {
return APLPrefix{}, len(msg), &Error{err: "APL length too long"}
}
if off+afdlen > len(msg) {
return APLPrefix{}, len(msg), &Error{err: "overflow unpacking APL address"}
}
off += copy(ip, msg[off:off+afdlen])
if afdlen > 0 {
last := ip[afdlen-1]
if last == 0 {
return APLPrefix{}, len(msg), &Error{err: "extra APL address bits"}
}
}
ipnet := net.IPNet{
IP: ip,
Mask: net.CIDRMask(int(prefix), 8*len(ip)),
}
network := ipnet.IP.Mask(ipnet.Mask)
if !network.Equal(ipnet.IP) {
return APLPrefix{}, len(msg), &Error{err: "invalid APL address length"}
}
return APLPrefix{
Negation: (nlen & 0x80) != 0,
Network: ipnet,
}, off, nil
}
...@@ -4,12 +4,18 @@ package dns ...@@ -4,12 +4,18 @@ package dns
// size by removing records that exceed the requested size. // size by removing records that exceed the requested size.
// //
// It will first check if the reply fits without compression and then with // It will first check if the reply fits without compression and then with
// compression. If it won't fit with compression, Scrub then walks the // compression. If it won't fit with compression, Truncate then walks the
// record adding as many records as possible without exceeding the // record adding as many records as possible without exceeding the
// requested buffer size. // requested buffer size.
// //
// The TC bit will be set if any answer records were excluded from the // The TC bit will be set if any records were excluded from the message.
// message. This indicates to that the client should retry over TCP. // If the TC bit is already set on the message it will be retained.
// TC indicates that the client should retry over TCP.
//
// According to RFC 2181, the TC bit should only be set if not all of the
// "required" RRs can be included in the response. Unfortunately, we have
// no way of knowing which RRs are required so we set the TC bit if any RR
// had to be omitted from the response.
// //
// The appropriate buffer size can be retrieved from the requests OPT // The appropriate buffer size can be retrieved from the requests OPT
// record, if present, and is transport specific otherwise. dns.MinMsgSize // record, if present, and is transport specific otherwise. dns.MinMsgSize
...@@ -23,11 +29,11 @@ func (dns *Msg) Truncate(size int) { ...@@ -23,11 +29,11 @@ func (dns *Msg) Truncate(size int) {
} }
// RFC 6891 mandates that the payload size in an OPT record // RFC 6891 mandates that the payload size in an OPT record
// less than 512 bytes must be treated as equal to 512 bytes. // less than 512 (MinMsgSize) bytes must be treated as equal to 512 bytes.
// //
// For ease of use, we impose that restriction here. // For ease of use, we impose that restriction here.
if size < 512 { if size < MinMsgSize {
size = 512 size = MinMsgSize
} }
l := msgLenWithCompressionMap(dns, nil) // uncompressed length l := msgLenWithCompressionMap(dns, nil) // uncompressed length
...@@ -68,12 +74,12 @@ func (dns *Msg) Truncate(size int) { ...@@ -68,12 +74,12 @@ func (dns *Msg) Truncate(size int) {
var numExtra int var numExtra int
if l < size { if l < size {
l, numExtra = truncateLoop(dns.Extra, size, l, compression) _, numExtra = truncateLoop(dns.Extra, size, l, compression)
} }
// According to RFC 2181, the TC bit should only be set if not all // See the function documentation for when we set this.
// of the answer RRs can be included in the response. dns.Truncated = dns.Truncated || len(dns.Answer) > numAnswer ||
dns.Truncated = len(dns.Answer) > numAnswer len(dns.Ns) > numNS || len(dns.Extra) > numExtra
dns.Answer = dns.Answer[:numAnswer] dns.Answer = dns.Answer[:numAnswer]
dns.Ns = dns.Ns[:numNS] dns.Ns = dns.Ns[:numNS]
......
...@@ -43,7 +43,7 @@ func HashName(label string, ha uint8, iter uint16, salt string) string { ...@@ -43,7 +43,7 @@ func HashName(label string, ha uint8, iter uint16, salt string) string {
return toBase32(nsec3) return toBase32(nsec3)
} }
// Cover returns true if a name is covered by the NSEC3 record // Cover returns true if a name is covered by the NSEC3 record.
func (rr *NSEC3) Cover(name string) bool { func (rr *NSEC3) Cover(name string) bool {
nameHash := HashName(name, rr.Hash, rr.Iterations, rr.Salt) nameHash := HashName(name, rr.Hash, rr.Iterations, rr.Salt)
owner := strings.ToUpper(rr.Hdr.Name) owner := strings.ToUpper(rr.Hdr.Name)
......
package dns package dns
import ( import "strings"
"fmt"
"strings"
)
// PrivateRdata is an interface used for implementing "Private Use" RR types, see // PrivateRdata is an interface used for implementing "Private Use" RR types, see
// RFC 6895. This allows one to experiment with new RR types, without requesting an // RFC 6895. This allows one to experiment with new RR types, without requesting an
...@@ -16,9 +13,8 @@ type PrivateRdata interface { ...@@ -16,9 +13,8 @@ type PrivateRdata interface {
// Pack is used when packing a private RR into a buffer. // Pack is used when packing a private RR into a buffer.
Pack([]byte) (int, error) Pack([]byte) (int, error)
// Unpack is used when unpacking a private RR from a buffer. // Unpack is used when unpacking a private RR from a buffer.
// TODO(miek): diff. signature than Pack, see edns0.go for instance.
Unpack([]byte) (int, error) Unpack([]byte) (int, error)
// Copy copies the Rdata. // Copy copies the Rdata into the PrivateRdata argument.
Copy(PrivateRdata) error Copy(PrivateRdata) error
// Len returns the length in octets of the Rdata. // Len returns the length in octets of the Rdata.
Len() int Len() int
...@@ -29,22 +25,8 @@ type PrivateRdata interface { ...@@ -29,22 +25,8 @@ type PrivateRdata interface {
type PrivateRR struct { type PrivateRR struct {
Hdr RR_Header Hdr RR_Header
Data PrivateRdata Data PrivateRdata
}
func mkPrivateRR(rrtype uint16) *PrivateRR {
// Panics if RR is not an instance of PrivateRR.
rrfunc, ok := TypeToRR[rrtype]
if !ok {
panic(fmt.Sprintf("dns: invalid operation with Private RR type %d", rrtype))
}
anyrr := rrfunc()
rr, ok := anyrr.(*PrivateRR)
if !ok {
panic(fmt.Sprintf("dns: RR is not a PrivateRR, TypeToRR[%d] generator returned %T", rrtype, anyrr))
}
return rr generator func() PrivateRdata // for copy
} }
// Header return the RR header of r. // Header return the RR header of r.
...@@ -61,13 +43,12 @@ func (r *PrivateRR) len(off int, compression map[string]struct{}) int { ...@@ -61,13 +43,12 @@ func (r *PrivateRR) len(off int, compression map[string]struct{}) int {
func (r *PrivateRR) copy() RR { func (r *PrivateRR) copy() RR {
// make new RR like this: // make new RR like this:
rr := mkPrivateRR(r.Hdr.Rrtype) rr := &PrivateRR{r.Hdr, r.generator(), r.generator}
rr.Hdr = r.Hdr
err := r.Data.Copy(rr.Data) if err := r.Data.Copy(rr.Data); err != nil {
if err != nil { panic("dns: got value that could not be used to copy Private rdata: " + err.Error())
panic("dns: got value that could not be used to copy Private rdata")
} }
return rr return rr
} }
...@@ -86,7 +67,7 @@ func (r *PrivateRR) unpack(msg []byte, off int) (int, error) { ...@@ -86,7 +67,7 @@ func (r *PrivateRR) unpack(msg []byte, off int) (int, error) {
return off, err return off, err
} }
func (r *PrivateRR) parse(c *zlexer, origin, file string) *ParseError { func (r *PrivateRR) parse(c *zlexer, origin string) *ParseError {
var l lex var l lex
text := make([]string, 0, 2) // could be 0..N elements, median is probably 1 text := make([]string, 0, 2) // could be 0..N elements, median is probably 1
Fetch: Fetch:
...@@ -103,7 +84,7 @@ Fetch: ...@@ -103,7 +84,7 @@ Fetch:
err := r.Data.Parse(text) err := r.Data.Parse(text)
if err != nil { if err != nil {
return &ParseError{file, err.Error(), l} return &ParseError{"", err.Error(), l}
} }
return nil return nil
...@@ -116,7 +97,7 @@ func (r1 *PrivateRR) isDuplicate(r2 RR) bool { return false } ...@@ -116,7 +97,7 @@ func (r1 *PrivateRR) isDuplicate(r2 RR) bool { return false }
func PrivateHandle(rtypestr string, rtype uint16, generator func() PrivateRdata) { func PrivateHandle(rtypestr string, rtype uint16, generator func() PrivateRdata) {
rtypestr = strings.ToUpper(rtypestr) rtypestr = strings.ToUpper(rtypestr)
TypeToRR[rtype] = func() RR { return &PrivateRR{RR_Header{}, generator()} } TypeToRR[rtype] = func() RR { return &PrivateRR{RR_Header{}, generator(), generator} }
TypeToString[rtype] = rtypestr TypeToString[rtype] = rtypestr
StringToType[rtypestr] = rtype StringToType[rtypestr] = rtype
} }
......
...@@ -87,31 +87,18 @@ type lex struct { ...@@ -87,31 +87,18 @@ type lex struct {
column int // column in the file column int // column in the file
} }
// Token holds the token that are returned when a zone file is parsed.
type Token struct {
// The scanned resource record when error is not nil.
RR
// When an error occurred, this has the error specifics.
Error *ParseError
// A potential comment positioned after the RR and on the same line.
Comment string
}
// ttlState describes the state necessary to fill in an omitted RR TTL // ttlState describes the state necessary to fill in an omitted RR TTL
type ttlState struct { type ttlState struct {
ttl uint32 // ttl is the current default TTL ttl uint32 // ttl is the current default TTL
isByDirective bool // isByDirective indicates whether ttl was set by a $TTL directive isByDirective bool // isByDirective indicates whether ttl was set by a $TTL directive
} }
// NewRR reads the RR contained in the string s. Only the first RR is // NewRR reads the RR contained in the string s. Only the first RR is returned.
// returned. If s contains no records, NewRR will return nil with no // If s contains no records, NewRR will return nil with no error.
// error.
//
// The class defaults to IN and TTL defaults to 3600. The full zone
// file syntax like $TTL, $ORIGIN, etc. is supported.
// //
// All fields of the returned RR are set, except RR.Header().Rdlength // The class defaults to IN and TTL defaults to 3600. The full zone file syntax
// which is set to 0. // like $TTL, $ORIGIN, etc. is supported. All fields of the returned RR are
// set, except RR.Header().Rdlength which is set to 0.
func NewRR(s string) (RR, error) { func NewRR(s string) (RR, error) {
if len(s) > 0 && s[len(s)-1] != '\n' { // We need a closing newline if len(s) > 0 && s[len(s)-1] != '\n' { // We need a closing newline
return ReadRR(strings.NewReader(s+"\n"), "") return ReadRR(strings.NewReader(s+"\n"), "")
...@@ -133,69 +120,6 @@ func ReadRR(r io.Reader, file string) (RR, error) { ...@@ -133,69 +120,6 @@ func ReadRR(r io.Reader, file string) (RR, error) {
return rr, zp.Err() return rr, zp.Err()
} }
// ParseZone reads a RFC 1035 style zonefile from r. It returns
// *Tokens on the returned channel, each consisting of either a
// parsed RR and optional comment or a nil RR and an error. The
// channel is closed by ParseZone when the end of r is reached.
//
// The string file is used in error reporting and to resolve relative
// $INCLUDE directives. The string origin is used as the initial
// origin, as if the file would start with an $ORIGIN directive.
//
// The directives $INCLUDE, $ORIGIN, $TTL and $GENERATE are all
// supported.
//
// Basic usage pattern when reading from a string (z) containing the
// zone data:
//
// for x := range dns.ParseZone(strings.NewReader(z), "", "") {
// if x.Error != nil {
// // log.Println(x.Error)
// } else {
// // Do something with x.RR
// }
// }
//
// Comments specified after an RR (and on the same line!) are
// returned too:
//
// foo. IN A 10.0.0.1 ; this is a comment
//
// The text "; this is comment" is returned in Token.Comment.
// Comments inside the RR are returned concatenated along with the
// RR. Comments on a line by themselves are discarded.
//
// To prevent memory leaks it is important to always fully drain the
// returned channel. If an error occurs, it will always be the last
// Token sent on the channel.
//
// Deprecated: New users should prefer the ZoneParser API.
func ParseZone(r io.Reader, origin, file string) chan *Token {
t := make(chan *Token, 10000)
go parseZone(r, origin, file, t)
return t
}
func parseZone(r io.Reader, origin, file string, t chan *Token) {
defer close(t)
zp := NewZoneParser(r, origin, file)
zp.SetIncludeAllowed(true)
for rr, ok := zp.Next(); ok; rr, ok = zp.Next() {
t <- &Token{RR: rr, Comment: zp.Comment()}
}
if err := zp.Err(); err != nil {
pe, ok := err.(*ParseError)
if !ok {
pe = &ParseError{file: file, err: err.Error()}
}
t <- &Token{Error: pe}
}
}
// ZoneParser is a parser for an RFC 1035 style zonefile. // ZoneParser is a parser for an RFC 1035 style zonefile.
// //
// Each parsed RR in the zone is returned sequentially from Next. An // Each parsed RR in the zone is returned sequentially from Next. An
...@@ -203,6 +127,7 @@ func parseZone(r io.Reader, origin, file string, t chan *Token) { ...@@ -203,6 +127,7 @@ func parseZone(r io.Reader, origin, file string, t chan *Token) {
// //
// The directives $INCLUDE, $ORIGIN, $TTL and $GENERATE are all // The directives $INCLUDE, $ORIGIN, $TTL and $GENERATE are all
// supported. Although $INCLUDE is disabled by default. // supported. Although $INCLUDE is disabled by default.
// Note that $GENERATE's range support up to a maximum of 65535 steps.
// //
// Basic usage pattern when reading from a string (z) containing the // Basic usage pattern when reading from a string (z) containing the
// zone data: // zone data:
...@@ -245,7 +170,8 @@ type ZoneParser struct { ...@@ -245,7 +170,8 @@ type ZoneParser struct {
includeDepth uint8 includeDepth uint8
includeAllowed bool includeAllowed bool
generateDisallowed bool
} }
// NewZoneParser returns an RFC 1035 style zonefile parser that reads // NewZoneParser returns an RFC 1035 style zonefile parser that reads
...@@ -503,9 +429,8 @@ func (zp *ZoneParser) Next() (RR, bool) { ...@@ -503,9 +429,8 @@ func (zp *ZoneParser) Next() (RR, bool) {
return zp.setParseError("expecting $TTL value, not this...", l) return zp.setParseError("expecting $TTL value, not this...", l)
} }
if e := slurpRemainder(zp.c, zp.file); e != nil { if err := slurpRemainder(zp.c); err != nil {
zp.parseErr = e return zp.setParseError(err.err, err.lex)
return nil, false
} }
ttl, ok := stringToTTL(l.token) ttl, ok := stringToTTL(l.token)
...@@ -527,9 +452,8 @@ func (zp *ZoneParser) Next() (RR, bool) { ...@@ -527,9 +452,8 @@ func (zp *ZoneParser) Next() (RR, bool) {
return zp.setParseError("expecting $ORIGIN value, not this...", l) return zp.setParseError("expecting $ORIGIN value, not this...", l)
} }
if e := slurpRemainder(zp.c, zp.file); e != nil { if err := slurpRemainder(zp.c); err != nil {
zp.parseErr = e return zp.setParseError(err.err, err.lex)
return nil, false
} }
name, ok := toAbsoluteName(l.token, zp.origin) name, ok := toAbsoluteName(l.token, zp.origin)
...@@ -547,6 +471,9 @@ func (zp *ZoneParser) Next() (RR, bool) { ...@@ -547,6 +471,9 @@ func (zp *ZoneParser) Next() (RR, bool) {
st = zExpectDirGenerate st = zExpectDirGenerate
case zExpectDirGenerate: case zExpectDirGenerate:
if zp.generateDisallowed {
return zp.setParseError("nested $GENERATE directive not allowed", l)
}
if l.value != zString { if l.value != zString {
return zp.setParseError("expecting $GENERATE value, not this...", l) return zp.setParseError("expecting $GENERATE value, not this...", l)
} }
...@@ -650,19 +577,44 @@ func (zp *ZoneParser) Next() (RR, bool) { ...@@ -650,19 +577,44 @@ func (zp *ZoneParser) Next() (RR, bool) {
st = zExpectRdata st = zExpectRdata
case zExpectRdata: case zExpectRdata:
r, e := setRR(*h, zp.c, zp.origin, zp.file) var rr RR
if e != nil { if newFn, ok := TypeToRR[h.Rrtype]; ok && canParseAsRR(h.Rrtype) {
// If e.lex is nil than we have encounter a unknown RR type rr = newFn()
// in that case we substitute our current lex token *rr.Header() = *h
if e.lex.token == "" && e.lex.value == 0 { } else {
e.lex = l // Uh, dirty rr = &RFC3597{Hdr: *h}
}
_, isPrivate := rr.(*PrivateRR)
if !isPrivate && zp.c.Peek().token == "" {
// This is a dynamic update rr.
// TODO(tmthrgd): Previously slurpRemainder was only called
// for certain RR types, which may have been important.
if err := slurpRemainder(zp.c); err != nil {
return zp.setParseError(err.err, err.lex)
}
return rr, true
} else if l.value == zNewline {
return zp.setParseError("unexpected newline", l)
}
if err := rr.parse(zp.c, zp.origin); err != nil {
// err is a concrete *ParseError without the file field set.
// The setParseError call below will construct a new
// *ParseError with file set to zp.file.
// If err.lex is nil than we have encounter an unknown RR type
// in that case we substitute our current lex token.
if err.lex == (lex{}) {
return zp.setParseError(err.err, l)
} }
zp.parseErr = e return zp.setParseError(err.err, err.lex)
return nil, false
} }
return r, true return rr, true
} }
} }
...@@ -671,6 +623,18 @@ func (zp *ZoneParser) Next() (RR, bool) { ...@@ -671,6 +623,18 @@ func (zp *ZoneParser) Next() (RR, bool) {
return nil, false return nil, false
} }
// canParseAsRR returns true if the record type can be parsed as a
// concrete RR. It blacklists certain record types that must be parsed
// according to RFC 3597 because they lack a presentation format.
func canParseAsRR(rrtype uint16) bool {
switch rrtype {
case TypeANY, TypeNULL, TypeOPT, TypeTSIG:
return false
default:
return true
}
}
type zlexer struct { type zlexer struct {
br io.ByteReader br io.ByteReader
...@@ -682,7 +646,8 @@ type zlexer struct { ...@@ -682,7 +646,8 @@ type zlexer struct {
comBuf string comBuf string
comment string comment string
l lex l lex
cachedL *lex
brace int brace int
quote bool quote bool
...@@ -748,13 +713,37 @@ func (zl *zlexer) readByte() (byte, bool) { ...@@ -748,13 +713,37 @@ func (zl *zlexer) readByte() (byte, bool) {
return c, true return c, true
} }
func (zl *zlexer) Peek() lex {
if zl.nextL {
return zl.l
}
l, ok := zl.Next()
if !ok {
return l
}
if zl.nextL {
// Cache l. Next returns zl.cachedL then zl.l.
zl.cachedL = &l
} else {
// In this case l == zl.l, so we just tell Next to return zl.l.
zl.nextL = true
}
return l
}
func (zl *zlexer) Next() (lex, bool) { func (zl *zlexer) Next() (lex, bool) {
l := &zl.l l := &zl.l
if zl.nextL { switch {
case zl.cachedL != nil:
l, zl.cachedL = zl.cachedL, nil
return *l, true
case zl.nextL:
zl.nextL = false zl.nextL = false
return *l, true return *l, true
} case l.err:
if l.err {
// Parsing errors should be sticky. // Parsing errors should be sticky.
return lex{value: zEOF}, false return lex{value: zEOF}, false
} }
...@@ -908,6 +897,11 @@ func (zl *zlexer) Next() (lex, bool) { ...@@ -908,6 +897,11 @@ func (zl *zlexer) Next() (lex, bool) {
// was inside braces and we delayed adding it until now. // was inside braces and we delayed adding it until now.
com[comi] = ' ' // convert newline to space com[comi] = ' ' // convert newline to space
comi++ comi++
if comi >= len(com) {
l.token = "comment length insufficient for parsing"
l.err = true
return *l, true
}
} }
com[comi] = ';' com[comi] = ';'
...@@ -1216,11 +1210,29 @@ func stringToCm(token string) (e, m uint8, ok bool) { ...@@ -1216,11 +1210,29 @@ func stringToCm(token string) (e, m uint8, ok bool) {
if cmeters, err = strconv.Atoi(s[1]); err != nil { if cmeters, err = strconv.Atoi(s[1]); err != nil {
return return
} }
// There's no point in having more than 2 digits in this part, and would rather make the implementation complicated ('123' should be treated as '12').
// So we simply reject it.
// We also make sure the first character is a digit to reject '+-' signs.
if len(s[1]) > 2 || s[1][0] < '0' || s[1][0] > '9' {
return
}
if len(s[1]) == 1 {
// 'nn.1' must be treated as 'nn-meters and 10cm, not 1cm.
cmeters *= 10
}
if len(s[0]) == 0 {
// This will allow omitting the 'meter' part, like .01 (meaning 0.01m = 1cm).
break
}
fallthrough fallthrough
case 1: case 1:
if meters, err = strconv.Atoi(s[0]); err != nil { if meters, err = strconv.Atoi(s[0]); err != nil {
return return
} }
// RFC1876 states the max value is 90000000.00. The latter two conditions enforce it.
if s[0][0] < '0' || s[0][0] > '9' || meters > 90000000 || (meters == 90000000 && cmeters != 0) {
return
}
case 0: case 0:
// huh? // huh?
return 0, 0, false return 0, 0, false
...@@ -1233,13 +1245,10 @@ func stringToCm(token string) (e, m uint8, ok bool) { ...@@ -1233,13 +1245,10 @@ func stringToCm(token string) (e, m uint8, ok bool) {
e = 0 e = 0
val = cmeters val = cmeters
} }
for val > 10 { for val >= 10 {
e++ e++
val /= 10 val /= 10
} }
if e > 9 {
ok = false
}
m = uint8(val) m = uint8(val)
return return
} }
...@@ -1281,6 +1290,9 @@ func appendOrigin(name, origin string) string { ...@@ -1281,6 +1290,9 @@ func appendOrigin(name, origin string) string {
// LOC record helper function // LOC record helper function
func locCheckNorth(token string, latitude uint32) (uint32, bool) { func locCheckNorth(token string, latitude uint32) (uint32, bool) {
if latitude > 90 * 1000 * 60 * 60 {
return latitude, false
}
switch token { switch token {
case "n", "N": case "n", "N":
return LOC_EQUATOR + latitude, true return LOC_EQUATOR + latitude, true
...@@ -1292,6 +1304,9 @@ func locCheckNorth(token string, latitude uint32) (uint32, bool) { ...@@ -1292,6 +1304,9 @@ func locCheckNorth(token string, latitude uint32) (uint32, bool) {
// LOC record helper function // LOC record helper function
func locCheckEast(token string, longitude uint32) (uint32, bool) { func locCheckEast(token string, longitude uint32) (uint32, bool) {
if longitude > 180 * 1000 * 60 * 60 {
return longitude, false
}
switch token { switch token {
case "e", "E": case "e", "E":
return LOC_EQUATOR + longitude, true return LOC_EQUATOR + longitude, true
...@@ -1302,18 +1317,18 @@ func locCheckEast(token string, longitude uint32) (uint32, bool) { ...@@ -1302,18 +1317,18 @@ func locCheckEast(token string, longitude uint32) (uint32, bool) {
} }
// "Eat" the rest of the "line" // "Eat" the rest of the "line"
func slurpRemainder(c *zlexer, f string) *ParseError { func slurpRemainder(c *zlexer) *ParseError {
l, _ := c.Next() l, _ := c.Next()
switch l.value { switch l.value {
case zBlank: case zBlank:
l, _ = c.Next() l, _ = c.Next()
if l.value != zNewline && l.value != zEOF { if l.value != zNewline && l.value != zEOF {
return &ParseError{f, "garbage after rdata", l} return &ParseError{"", "garbage after rdata", l}
} }
case zNewline: case zNewline:
case zEOF: case zEOF:
default: default:
return &ParseError{f, "garbage after rdata", l} return &ParseError{"", "garbage after rdata", l}
} }
return nil return nil
} }
......
package dns package dns
import ( import (
"bytes"
"encoding/base64" "encoding/base64"
"net" "net"
"strconv" "strconv"
"strings" "strings"
) )
// 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) {
var rr RR
if newFn, ok := TypeToRR[h.Rrtype]; ok && canParseAsRR(h.Rrtype) {
rr = newFn()
*rr.Header() = h
} else {
rr = &RFC3597{Hdr: h}
}
err := rr.parse(c, o, f)
if err != nil {
return nil, err
}
return rr, nil
}
// canParseAsRR returns true if the record type can be parsed as a
// concrete RR. It blacklists certain record types that must be parsed
// according to RFC 3597 because they lack a presentation format.
func canParseAsRR(rrtype uint16) bool {
switch rrtype {
case TypeANY, TypeNULL, TypeOPT, TypeTSIG:
return false
default:
return true
}
}
// A remainder of the rdata with embedded spaces, return the parsed string (sans the spaces) // A remainder of the rdata with embedded spaces, return the parsed string (sans the spaces)
// or an error // or an error
func endingToString(c *zlexer, errstr, f string) (string, *ParseError) { func endingToString(c *zlexer, errstr string) (string, *ParseError) {
var s string var buffer bytes.Buffer
l, _ := c.Next() // zString l, _ := c.Next() // zString
for l.value != zNewline && l.value != zEOF { for l.value != zNewline && l.value != zEOF {
if l.err { if l.err {
return s, &ParseError{f, errstr, l} return buffer.String(), &ParseError{"", errstr, l}
} }
switch l.value { switch l.value {
case zString: case zString:
s += l.token buffer.WriteString(l.token)
case zBlank: // Ok case zBlank: // Ok
default: default:
return "", &ParseError{f, errstr, l} return "", &ParseError{"", errstr, l}
} }
l, _ = c.Next() l, _ = c.Next()
} }
return s, nil return buffer.String(), nil
} }
// A remainder of the rdata with embedded spaces, split on unquoted whitespace // A remainder of the rdata with embedded spaces, split on unquoted whitespace
// and return the parsed string slice or an error // and return the parsed string slice or an error
func endingToTxtSlice(c *zlexer, errstr, f string) ([]string, *ParseError) { func endingToTxtSlice(c *zlexer, errstr string) ([]string, *ParseError) {
// Get the remaining data until we see a zNewline // Get the remaining data until we see a zNewline
l, _ := c.Next() l, _ := c.Next()
if l.err { if l.err {
return nil, &ParseError{f, errstr, l} return nil, &ParseError{"", errstr, l}
} }
// Build the slice // Build the slice
...@@ -78,7 +45,7 @@ func endingToTxtSlice(c *zlexer, errstr, f string) ([]string, *ParseError) { ...@@ -78,7 +45,7 @@ func endingToTxtSlice(c *zlexer, errstr, f string) ([]string, *ParseError) {
empty := false empty := false
for l.value != zNewline && l.value != zEOF { for l.value != zNewline && l.value != zEOF {
if l.err { if l.err {
return nil, &ParseError{f, errstr, l} return nil, &ParseError{"", errstr, l}
} }
switch l.value { switch l.value {
case zString: case zString:
...@@ -105,7 +72,7 @@ func endingToTxtSlice(c *zlexer, errstr, f string) ([]string, *ParseError) { ...@@ -105,7 +72,7 @@ func endingToTxtSlice(c *zlexer, errstr, f string) ([]string, *ParseError) {
case zBlank: case zBlank:
if quote { if quote {
// zBlank can only be seen in between txt parts. // zBlank can only be seen in between txt parts.
return nil, &ParseError{f, errstr, l} return nil, &ParseError{"", errstr, l}
} }
case zQuote: case zQuote:
if empty && quote { if empty && quote {
...@@ -114,24 +81,20 @@ func endingToTxtSlice(c *zlexer, errstr, f string) ([]string, *ParseError) { ...@@ -114,24 +81,20 @@ func endingToTxtSlice(c *zlexer, errstr, f string) ([]string, *ParseError) {
quote = !quote quote = !quote
empty = true empty = true
default: default:
return nil, &ParseError{f, errstr, l} return nil, &ParseError{"", errstr, l}
} }
l, _ = c.Next() l, _ = c.Next()
} }
if quote { if quote {
return nil, &ParseError{f, errstr, l} return nil, &ParseError{"", errstr, l}
} }
return s, nil return s, nil
} }
func (rr *A) parse(c *zlexer, o, f string) *ParseError { func (rr *A) parse(c *zlexer, o string) *ParseError {
l, _ := c.Next() l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return slurpRemainder(c, f)
}
rr.A = net.ParseIP(l.token) rr.A = net.ParseIP(l.token)
// IPv4 addresses cannot include ":". // IPv4 addresses cannot include ":".
// We do this rather than use net.IP's To4() because // We do this rather than use net.IP's To4() because
...@@ -139,82 +102,58 @@ func (rr *A) parse(c *zlexer, o, f string) *ParseError { ...@@ -139,82 +102,58 @@ func (rr *A) parse(c *zlexer, o, f string) *ParseError {
// IPv4. // IPv4.
isIPv4 := !strings.Contains(l.token, ":") isIPv4 := !strings.Contains(l.token, ":")
if rr.A == nil || !isIPv4 || l.err { if rr.A == nil || !isIPv4 || l.err {
return &ParseError{f, "bad A A", l} return &ParseError{"", "bad A A", l}
} }
return slurpRemainder(c, f) return slurpRemainder(c)
} }
func (rr *AAAA) parse(c *zlexer, o, f string) *ParseError { func (rr *AAAA) parse(c *zlexer, o string) *ParseError {
l, _ := c.Next() l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return slurpRemainder(c, f)
}
rr.AAAA = net.ParseIP(l.token) rr.AAAA = net.ParseIP(l.token)
// IPv6 addresses must include ":", and IPv4 // IPv6 addresses must include ":", and IPv4
// addresses cannot include ":". // addresses cannot include ":".
isIPv6 := strings.Contains(l.token, ":") isIPv6 := strings.Contains(l.token, ":")
if rr.AAAA == nil || !isIPv6 || l.err { if rr.AAAA == nil || !isIPv6 || l.err {
return &ParseError{f, "bad AAAA AAAA", l} return &ParseError{"", "bad AAAA AAAA", l}
} }
return slurpRemainder(c, f) return slurpRemainder(c)
} }
func (rr *NS) parse(c *zlexer, o, f string) *ParseError { func (rr *NS) parse(c *zlexer, o string) *ParseError {
l, _ := c.Next() l, _ := c.Next()
rr.Ns = l.token
if len(l.token) == 0 { // dynamic update rr.
return slurpRemainder(c, f)
}
name, nameOk := toAbsoluteName(l.token, o) name, nameOk := toAbsoluteName(l.token, o)
if l.err || !nameOk { if l.err || !nameOk {
return &ParseError{f, "bad NS Ns", l} return &ParseError{"", "bad NS Ns", l}
} }
rr.Ns = name rr.Ns = name
return slurpRemainder(c, f) return slurpRemainder(c)
} }
func (rr *PTR) parse(c *zlexer, o, f string) *ParseError { func (rr *PTR) parse(c *zlexer, o string) *ParseError {
l, _ := c.Next() l, _ := c.Next()
rr.Ptr = l.token
if len(l.token) == 0 { // dynamic update rr.
return slurpRemainder(c, f)
}
name, nameOk := toAbsoluteName(l.token, o) name, nameOk := toAbsoluteName(l.token, o)
if l.err || !nameOk { if l.err || !nameOk {
return &ParseError{f, "bad PTR Ptr", l} return &ParseError{"", "bad PTR Ptr", l}
} }
rr.Ptr = name rr.Ptr = name
return slurpRemainder(c, f) return slurpRemainder(c)
} }
func (rr *NSAPPTR) parse(c *zlexer, o, f string) *ParseError { func (rr *NSAPPTR) parse(c *zlexer, o string) *ParseError {
l, _ := c.Next() l, _ := c.Next()
rr.Ptr = l.token
if len(l.token) == 0 { // dynamic update rr.
return slurpRemainder(c, f)
}
name, nameOk := toAbsoluteName(l.token, o) name, nameOk := toAbsoluteName(l.token, o)
if l.err || !nameOk { if l.err || !nameOk {
return &ParseError{f, "bad NSAP-PTR Ptr", l} return &ParseError{"", "bad NSAP-PTR Ptr", l}
} }
rr.Ptr = name rr.Ptr = name
return slurpRemainder(c, f) return slurpRemainder(c)
} }
func (rr *RP) parse(c *zlexer, o, f string) *ParseError { func (rr *RP) parse(c *zlexer, o string) *ParseError {
l, _ := c.Next() l, _ := c.Next()
rr.Mbox = l.token
if len(l.token) == 0 { // dynamic update rr.
return slurpRemainder(c, f)
}
mbox, mboxOk := toAbsoluteName(l.token, o) mbox, mboxOk := toAbsoluteName(l.token, o)
if l.err || !mboxOk { if l.err || !mboxOk {
return &ParseError{f, "bad RP Mbox", l} return &ParseError{"", "bad RP Mbox", l}
} }
rr.Mbox = mbox rr.Mbox = mbox
...@@ -224,60 +163,45 @@ func (rr *RP) parse(c *zlexer, o, f string) *ParseError { ...@@ -224,60 +163,45 @@ func (rr *RP) parse(c *zlexer, o, f string) *ParseError {
txt, txtOk := toAbsoluteName(l.token, o) txt, txtOk := toAbsoluteName(l.token, o)
if l.err || !txtOk { if l.err || !txtOk {
return &ParseError{f, "bad RP Txt", l} return &ParseError{"", "bad RP Txt", l}
} }
rr.Txt = txt rr.Txt = txt
return slurpRemainder(c, f) return slurpRemainder(c)
} }
func (rr *MR) parse(c *zlexer, o, f string) *ParseError { func (rr *MR) parse(c *zlexer, o string) *ParseError {
l, _ := c.Next() l, _ := c.Next()
rr.Mr = l.token
if len(l.token) == 0 { // dynamic update rr.
return slurpRemainder(c, f)
}
name, nameOk := toAbsoluteName(l.token, o) name, nameOk := toAbsoluteName(l.token, o)
if l.err || !nameOk { if l.err || !nameOk {
return &ParseError{f, "bad MR Mr", l} return &ParseError{"", "bad MR Mr", l}
} }
rr.Mr = name rr.Mr = name
return slurpRemainder(c, f) return slurpRemainder(c)
} }
func (rr *MB) parse(c *zlexer, o, f string) *ParseError { func (rr *MB) parse(c *zlexer, o string) *ParseError {
l, _ := c.Next() l, _ := c.Next()
rr.Mb = l.token
if len(l.token) == 0 { // dynamic update rr.
return slurpRemainder(c, f)
}
name, nameOk := toAbsoluteName(l.token, o) name, nameOk := toAbsoluteName(l.token, o)
if l.err || !nameOk { if l.err || !nameOk {
return &ParseError{f, "bad MB Mb", l} return &ParseError{"", "bad MB Mb", l}
} }
rr.Mb = name rr.Mb = name
return slurpRemainder(c, f) return slurpRemainder(c)
} }
func (rr *MG) parse(c *zlexer, o, f string) *ParseError { func (rr *MG) parse(c *zlexer, o string) *ParseError {
l, _ := c.Next() l, _ := c.Next()
rr.Mg = l.token
if len(l.token) == 0 { // dynamic update rr.
return slurpRemainder(c, f)
}
name, nameOk := toAbsoluteName(l.token, o) name, nameOk := toAbsoluteName(l.token, o)
if l.err || !nameOk { if l.err || !nameOk {
return &ParseError{f, "bad MG Mg", l} return &ParseError{"", "bad MG Mg", l}
} }
rr.Mg = name rr.Mg = name
return slurpRemainder(c, f) return slurpRemainder(c)
} }
func (rr *HINFO) parse(c *zlexer, o, f string) *ParseError { func (rr *HINFO) parse(c *zlexer, o string) *ParseError {
chunks, e := endingToTxtSlice(c, "bad HINFO Fields", f) chunks, e := endingToTxtSlice(c, "bad HINFO Fields")
if e != nil { if e != nil {
return e return e
} }
...@@ -299,16 +223,11 @@ func (rr *HINFO) parse(c *zlexer, o, f string) *ParseError { ...@@ -299,16 +223,11 @@ func (rr *HINFO) parse(c *zlexer, o, f string) *ParseError {
return nil return nil
} }
func (rr *MINFO) parse(c *zlexer, o, f string) *ParseError { func (rr *MINFO) parse(c *zlexer, o string) *ParseError {
l, _ := c.Next() l, _ := c.Next()
rr.Rmail = l.token
if len(l.token) == 0 { // dynamic update rr.
return slurpRemainder(c, f)
}
rmail, rmailOk := toAbsoluteName(l.token, o) rmail, rmailOk := toAbsoluteName(l.token, o)
if l.err || !rmailOk { if l.err || !rmailOk {
return &ParseError{f, "bad MINFO Rmail", l} return &ParseError{"", "bad MINFO Rmail", l}
} }
rr.Rmail = rmail rr.Rmail = rmail
...@@ -318,52 +237,38 @@ func (rr *MINFO) parse(c *zlexer, o, f string) *ParseError { ...@@ -318,52 +237,38 @@ func (rr *MINFO) parse(c *zlexer, o, f string) *ParseError {
email, emailOk := toAbsoluteName(l.token, o) email, emailOk := toAbsoluteName(l.token, o)
if l.err || !emailOk { if l.err || !emailOk {
return &ParseError{f, "bad MINFO Email", l} return &ParseError{"", "bad MINFO Email", l}
} }
rr.Email = email rr.Email = email
return slurpRemainder(c, f) return slurpRemainder(c)
} }
func (rr *MF) parse(c *zlexer, o, f string) *ParseError { func (rr *MF) parse(c *zlexer, o string) *ParseError {
l, _ := c.Next() l, _ := c.Next()
rr.Mf = l.token
if len(l.token) == 0 { // dynamic update rr.
return slurpRemainder(c, f)
}
name, nameOk := toAbsoluteName(l.token, o) name, nameOk := toAbsoluteName(l.token, o)
if l.err || !nameOk { if l.err || !nameOk {
return &ParseError{f, "bad MF Mf", l} return &ParseError{"", "bad MF Mf", l}
} }
rr.Mf = name rr.Mf = name
return slurpRemainder(c, f) return slurpRemainder(c)
} }
func (rr *MD) parse(c *zlexer, o, f string) *ParseError { func (rr *MD) parse(c *zlexer, o string) *ParseError {
l, _ := c.Next() l, _ := c.Next()
rr.Md = l.token
if len(l.token) == 0 { // dynamic update rr.
return slurpRemainder(c, f)
}
name, nameOk := toAbsoluteName(l.token, o) name, nameOk := toAbsoluteName(l.token, o)
if l.err || !nameOk { if l.err || !nameOk {
return &ParseError{f, "bad MD Md", l} return &ParseError{"", "bad MD Md", l}
} }
rr.Md = name rr.Md = name
return slurpRemainder(c, f) return slurpRemainder(c)
} }
func (rr *MX) parse(c *zlexer, o, f string) *ParseError { func (rr *MX) parse(c *zlexer, o string) *ParseError {
l, _ := c.Next() l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return slurpRemainder(c, f)
}
i, e := strconv.ParseUint(l.token, 10, 16) i, e := strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err { if e != nil || l.err {
return &ParseError{f, "bad MX Pref", l} return &ParseError{"", "bad MX Pref", l}
} }
rr.Preference = uint16(i) rr.Preference = uint16(i)
...@@ -373,22 +278,18 @@ func (rr *MX) parse(c *zlexer, o, f string) *ParseError { ...@@ -373,22 +278,18 @@ func (rr *MX) parse(c *zlexer, o, f string) *ParseError {
name, nameOk := toAbsoluteName(l.token, o) name, nameOk := toAbsoluteName(l.token, o)
if l.err || !nameOk { if l.err || !nameOk {
return &ParseError{f, "bad MX Mx", l} return &ParseError{"", "bad MX Mx", l}
} }
rr.Mx = name rr.Mx = name
return slurpRemainder(c, f) return slurpRemainder(c)
} }
func (rr *RT) parse(c *zlexer, o, f string) *ParseError { func (rr *RT) parse(c *zlexer, o string) *ParseError {
l, _ := c.Next() l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return slurpRemainder(c, f)
}
i, e := strconv.ParseUint(l.token, 10, 16) i, e := strconv.ParseUint(l.token, 10, 16)
if e != nil { if e != nil {
return &ParseError{f, "bad RT Preference", l} return &ParseError{"", "bad RT Preference", l}
} }
rr.Preference = uint16(i) rr.Preference = uint16(i)
...@@ -398,22 +299,18 @@ func (rr *RT) parse(c *zlexer, o, f string) *ParseError { ...@@ -398,22 +299,18 @@ func (rr *RT) parse(c *zlexer, o, f string) *ParseError {
name, nameOk := toAbsoluteName(l.token, o) name, nameOk := toAbsoluteName(l.token, o)
if l.err || !nameOk { if l.err || !nameOk {
return &ParseError{f, "bad RT Host", l} return &ParseError{"", "bad RT Host", l}
} }
rr.Host = name rr.Host = name
return slurpRemainder(c, f) return slurpRemainder(c)
} }
func (rr *AFSDB) parse(c *zlexer, o, f string) *ParseError { func (rr *AFSDB) parse(c *zlexer, o string) *ParseError {
l, _ := c.Next() l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return slurpRemainder(c, f)
}
i, e := strconv.ParseUint(l.token, 10, 16) i, e := strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err { if e != nil || l.err {
return &ParseError{f, "bad AFSDB Subtype", l} return &ParseError{"", "bad AFSDB Subtype", l}
} }
rr.Subtype = uint16(i) rr.Subtype = uint16(i)
...@@ -423,34 +320,26 @@ func (rr *AFSDB) parse(c *zlexer, o, f string) *ParseError { ...@@ -423,34 +320,26 @@ func (rr *AFSDB) parse(c *zlexer, o, f string) *ParseError {
name, nameOk := toAbsoluteName(l.token, o) name, nameOk := toAbsoluteName(l.token, o)
if l.err || !nameOk { if l.err || !nameOk {
return &ParseError{f, "bad AFSDB Hostname", l} return &ParseError{"", "bad AFSDB Hostname", l}
} }
rr.Hostname = name rr.Hostname = name
return slurpRemainder(c, f) return slurpRemainder(c)
} }
func (rr *X25) parse(c *zlexer, o, f string) *ParseError { func (rr *X25) parse(c *zlexer, o string) *ParseError {
l, _ := c.Next() l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return slurpRemainder(c, f)
}
if l.err { if l.err {
return &ParseError{f, "bad X25 PSDNAddress", l} return &ParseError{"", "bad X25 PSDNAddress", l}
} }
rr.PSDNAddress = l.token rr.PSDNAddress = l.token
return slurpRemainder(c, f) return slurpRemainder(c)
} }
func (rr *KX) parse(c *zlexer, o, f string) *ParseError { func (rr *KX) parse(c *zlexer, o string) *ParseError {
l, _ := c.Next() l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return slurpRemainder(c, f)
}
i, e := strconv.ParseUint(l.token, 10, 16) i, e := strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err { if e != nil || l.err {
return &ParseError{f, "bad KX Pref", l} return &ParseError{"", "bad KX Pref", l}
} }
rr.Preference = uint16(i) rr.Preference = uint16(i)
...@@ -460,52 +349,37 @@ func (rr *KX) parse(c *zlexer, o, f string) *ParseError { ...@@ -460,52 +349,37 @@ func (rr *KX) parse(c *zlexer, o, f string) *ParseError {
name, nameOk := toAbsoluteName(l.token, o) name, nameOk := toAbsoluteName(l.token, o)
if l.err || !nameOk { if l.err || !nameOk {
return &ParseError{f, "bad KX Exchanger", l} return &ParseError{"", "bad KX Exchanger", l}
} }
rr.Exchanger = name rr.Exchanger = name
return slurpRemainder(c, f) return slurpRemainder(c)
} }
func (rr *CNAME) parse(c *zlexer, o, f string) *ParseError { func (rr *CNAME) parse(c *zlexer, o string) *ParseError {
l, _ := c.Next() l, _ := c.Next()
rr.Target = l.token
if len(l.token) == 0 { // dynamic update rr.
return slurpRemainder(c, f)
}
name, nameOk := toAbsoluteName(l.token, o) name, nameOk := toAbsoluteName(l.token, o)
if l.err || !nameOk { if l.err || !nameOk {
return &ParseError{f, "bad CNAME Target", l} return &ParseError{"", "bad CNAME Target", l}
} }
rr.Target = name rr.Target = name
return slurpRemainder(c, f) return slurpRemainder(c)
} }
func (rr *DNAME) parse(c *zlexer, o, f string) *ParseError { func (rr *DNAME) parse(c *zlexer, o string) *ParseError {
l, _ := c.Next() l, _ := c.Next()
rr.Target = l.token
if len(l.token) == 0 { // dynamic update rr.
return slurpRemainder(c, f)
}
name, nameOk := toAbsoluteName(l.token, o) name, nameOk := toAbsoluteName(l.token, o)
if l.err || !nameOk { if l.err || !nameOk {
return &ParseError{f, "bad DNAME Target", l} return &ParseError{"", "bad DNAME Target", l}
} }
rr.Target = name rr.Target = name
return slurpRemainder(c, f) return slurpRemainder(c)
} }
func (rr *SOA) parse(c *zlexer, o, f string) *ParseError { func (rr *SOA) parse(c *zlexer, o string) *ParseError {
l, _ := c.Next() l, _ := c.Next()
rr.Ns = l.token
if len(l.token) == 0 { // dynamic update rr.
return slurpRemainder(c, f)
}
ns, nsOk := toAbsoluteName(l.token, o) ns, nsOk := toAbsoluteName(l.token, o)
if l.err || !nsOk { if l.err || !nsOk {
return &ParseError{f, "bad SOA Ns", l} return &ParseError{"", "bad SOA Ns", l}
} }
rr.Ns = ns rr.Ns = ns
...@@ -515,7 +389,7 @@ func (rr *SOA) parse(c *zlexer, o, f string) *ParseError { ...@@ -515,7 +389,7 @@ func (rr *SOA) parse(c *zlexer, o, f string) *ParseError {
mbox, mboxOk := toAbsoluteName(l.token, o) mbox, mboxOk := toAbsoluteName(l.token, o)
if l.err || !mboxOk { if l.err || !mboxOk {
return &ParseError{f, "bad SOA Mbox", l} return &ParseError{"", "bad SOA Mbox", l}
} }
rr.Mbox = mbox rr.Mbox = mbox
...@@ -528,16 +402,16 @@ func (rr *SOA) parse(c *zlexer, o, f string) *ParseError { ...@@ -528,16 +402,16 @@ func (rr *SOA) parse(c *zlexer, o, f string) *ParseError {
for i := 0; i < 5; i++ { for i := 0; i < 5; i++ {
l, _ = c.Next() l, _ = c.Next()
if l.err { if l.err {
return &ParseError{f, "bad SOA zone parameter", l} return &ParseError{"", "bad SOA zone parameter", l}
} }
if j, e := strconv.ParseUint(l.token, 10, 32); e != nil { if j, err := strconv.ParseUint(l.token, 10, 32); err != nil {
if i == 0 { if i == 0 {
// Serial must be a number // Serial must be a number
return &ParseError{f, "bad SOA zone parameter", l} return &ParseError{"", "bad SOA zone parameter", l}
} }
// We allow other fields to be unitful duration strings // We allow other fields to be unitful duration strings
if v, ok = stringToTTL(l.token); !ok { if v, ok = stringToTTL(l.token); !ok {
return &ParseError{f, "bad SOA zone parameter", l} return &ParseError{"", "bad SOA zone parameter", l}
} }
} else { } else {
...@@ -560,34 +434,30 @@ func (rr *SOA) parse(c *zlexer, o, f string) *ParseError { ...@@ -560,34 +434,30 @@ func (rr *SOA) parse(c *zlexer, o, f string) *ParseError {
rr.Minttl = v rr.Minttl = v
} }
} }
return slurpRemainder(c, f) return slurpRemainder(c)
} }
func (rr *SRV) parse(c *zlexer, o, f string) *ParseError { func (rr *SRV) parse(c *zlexer, o string) *ParseError {
l, _ := c.Next() l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return slurpRemainder(c, f)
}
i, e := strconv.ParseUint(l.token, 10, 16) i, e := strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err { if e != nil || l.err {
return &ParseError{f, "bad SRV Priority", l} return &ParseError{"", "bad SRV Priority", l}
} }
rr.Priority = uint16(i) rr.Priority = uint16(i)
c.Next() // zBlank c.Next() // zBlank
l, _ = c.Next() // zString l, _ = c.Next() // zString
i, e = strconv.ParseUint(l.token, 10, 16) i, e1 := strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err { if e1 != nil || l.err {
return &ParseError{f, "bad SRV Weight", l} return &ParseError{"", "bad SRV Weight", l}
} }
rr.Weight = uint16(i) rr.Weight = uint16(i)
c.Next() // zBlank c.Next() // zBlank
l, _ = c.Next() // zString l, _ = c.Next() // zString
i, e = strconv.ParseUint(l.token, 10, 16) i, e2 := strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err { if e2 != nil || l.err {
return &ParseError{f, "bad SRV Port", l} return &ParseError{"", "bad SRV Port", l}
} }
rr.Port = uint16(i) rr.Port = uint16(i)
...@@ -597,29 +467,25 @@ func (rr *SRV) parse(c *zlexer, o, f string) *ParseError { ...@@ -597,29 +467,25 @@ func (rr *SRV) parse(c *zlexer, o, f string) *ParseError {
name, nameOk := toAbsoluteName(l.token, o) name, nameOk := toAbsoluteName(l.token, o)
if l.err || !nameOk { if l.err || !nameOk {
return &ParseError{f, "bad SRV Target", l} return &ParseError{"", "bad SRV Target", l}
} }
rr.Target = name rr.Target = name
return slurpRemainder(c, f) return slurpRemainder(c)
} }
func (rr *NAPTR) parse(c *zlexer, o, f string) *ParseError { func (rr *NAPTR) parse(c *zlexer, o string) *ParseError {
l, _ := c.Next() l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return slurpRemainder(c, f)
}
i, e := strconv.ParseUint(l.token, 10, 16) i, e := strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err { if e != nil || l.err {
return &ParseError{f, "bad NAPTR Order", l} return &ParseError{"", "bad NAPTR Order", l}
} }
rr.Order = uint16(i) rr.Order = uint16(i)
c.Next() // zBlank c.Next() // zBlank
l, _ = c.Next() // zString l, _ = c.Next() // zString
i, e = strconv.ParseUint(l.token, 10, 16) i, e1 := strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err { if e1 != nil || l.err {
return &ParseError{f, "bad NAPTR Preference", l} return &ParseError{"", "bad NAPTR Preference", l}
} }
rr.Preference = uint16(i) rr.Preference = uint16(i)
...@@ -627,57 +493,57 @@ func (rr *NAPTR) parse(c *zlexer, o, f string) *ParseError { ...@@ -627,57 +493,57 @@ func (rr *NAPTR) parse(c *zlexer, o, f string) *ParseError {
c.Next() // zBlank c.Next() // zBlank
l, _ = c.Next() // _QUOTE l, _ = c.Next() // _QUOTE
if l.value != zQuote { if l.value != zQuote {
return &ParseError{f, "bad NAPTR Flags", l} return &ParseError{"", "bad NAPTR Flags", l}
} }
l, _ = c.Next() // Either String or Quote l, _ = c.Next() // Either String or Quote
if l.value == zString { if l.value == zString {
rr.Flags = l.token rr.Flags = l.token
l, _ = c.Next() // _QUOTE l, _ = c.Next() // _QUOTE
if l.value != zQuote { if l.value != zQuote {
return &ParseError{f, "bad NAPTR Flags", l} return &ParseError{"", "bad NAPTR Flags", l}
} }
} else if l.value == zQuote { } else if l.value == zQuote {
rr.Flags = "" rr.Flags = ""
} else { } else {
return &ParseError{f, "bad NAPTR Flags", l} return &ParseError{"", "bad NAPTR Flags", l}
} }
// Service // Service
c.Next() // zBlank c.Next() // zBlank
l, _ = c.Next() // _QUOTE l, _ = c.Next() // _QUOTE
if l.value != zQuote { if l.value != zQuote {
return &ParseError{f, "bad NAPTR Service", l} return &ParseError{"", "bad NAPTR Service", l}
} }
l, _ = c.Next() // Either String or Quote l, _ = c.Next() // Either String or Quote
if l.value == zString { if l.value == zString {
rr.Service = l.token rr.Service = l.token
l, _ = c.Next() // _QUOTE l, _ = c.Next() // _QUOTE
if l.value != zQuote { if l.value != zQuote {
return &ParseError{f, "bad NAPTR Service", l} return &ParseError{"", "bad NAPTR Service", l}
} }
} else if l.value == zQuote { } else if l.value == zQuote {
rr.Service = "" rr.Service = ""
} else { } else {
return &ParseError{f, "bad NAPTR Service", l} return &ParseError{"", "bad NAPTR Service", l}
} }
// Regexp // Regexp
c.Next() // zBlank c.Next() // zBlank
l, _ = c.Next() // _QUOTE l, _ = c.Next() // _QUOTE
if l.value != zQuote { if l.value != zQuote {
return &ParseError{f, "bad NAPTR Regexp", l} return &ParseError{"", "bad NAPTR Regexp", l}
} }
l, _ = c.Next() // Either String or Quote l, _ = c.Next() // Either String or Quote
if l.value == zString { if l.value == zString {
rr.Regexp = l.token rr.Regexp = l.token
l, _ = c.Next() // _QUOTE l, _ = c.Next() // _QUOTE
if l.value != zQuote { if l.value != zQuote {
return &ParseError{f, "bad NAPTR Regexp", l} return &ParseError{"", "bad NAPTR Regexp", l}
} }
} else if l.value == zQuote { } else if l.value == zQuote {
rr.Regexp = "" rr.Regexp = ""
} else { } else {
return &ParseError{f, "bad NAPTR Regexp", l} return &ParseError{"", "bad NAPTR Regexp", l}
} }
// After quote no space?? // After quote no space??
...@@ -687,22 +553,17 @@ func (rr *NAPTR) parse(c *zlexer, o, f string) *ParseError { ...@@ -687,22 +553,17 @@ func (rr *NAPTR) parse(c *zlexer, o, f string) *ParseError {
name, nameOk := toAbsoluteName(l.token, o) name, nameOk := toAbsoluteName(l.token, o)
if l.err || !nameOk { if l.err || !nameOk {
return &ParseError{f, "bad NAPTR Replacement", l} return &ParseError{"", "bad NAPTR Replacement", l}
} }
rr.Replacement = name rr.Replacement = name
return slurpRemainder(c, f) return slurpRemainder(c)
} }
func (rr *TALINK) parse(c *zlexer, o, f string) *ParseError { func (rr *TALINK) parse(c *zlexer, o string) *ParseError {
l, _ := c.Next() l, _ := c.Next()
rr.PreviousName = l.token
if len(l.token) == 0 { // dynamic update rr.
return slurpRemainder(c, f)
}
previousName, previousNameOk := toAbsoluteName(l.token, o) previousName, previousNameOk := toAbsoluteName(l.token, o)
if l.err || !previousNameOk { if l.err || !previousNameOk {
return &ParseError{f, "bad TALINK PreviousName", l} return &ParseError{"", "bad TALINK PreviousName", l}
} }
rr.PreviousName = previousName rr.PreviousName = previousName
...@@ -712,28 +573,25 @@ func (rr *TALINK) parse(c *zlexer, o, f string) *ParseError { ...@@ -712,28 +573,25 @@ func (rr *TALINK) parse(c *zlexer, o, f string) *ParseError {
nextName, nextNameOk := toAbsoluteName(l.token, o) nextName, nextNameOk := toAbsoluteName(l.token, o)
if l.err || !nextNameOk { if l.err || !nextNameOk {
return &ParseError{f, "bad TALINK NextName", l} return &ParseError{"", "bad TALINK NextName", l}
} }
rr.NextName = nextName rr.NextName = nextName
return slurpRemainder(c, f) return slurpRemainder(c)
} }
func (rr *LOC) parse(c *zlexer, o, f string) *ParseError { func (rr *LOC) parse(c *zlexer, o string) *ParseError {
// Non zero defaults for LOC record, see RFC 1876, Section 3. // Non zero defaults for LOC record, see RFC 1876, Section 3.
rr.HorizPre = 165 // 10000 rr.Size = 0x12 // 1e2 cm (1m)
rr.VertPre = 162 // 10 rr.HorizPre = 0x16 // 1e6 cm (10000m)
rr.Size = 18 // 1 rr.VertPre = 0x13 // 1e3 cm (10m)
ok := false ok := false
// North // North
l, _ := c.Next() l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return nil
}
i, e := strconv.ParseUint(l.token, 10, 32) i, e := strconv.ParseUint(l.token, 10, 32)
if e != nil || l.err { if e != nil || l.err || i > 90 {
return &ParseError{f, "bad LOC Latitude", l} return &ParseError{"", "bad LOC Latitude", l}
} }
rr.Latitude = 1000 * 60 * 60 * uint32(i) rr.Latitude = 1000 * 60 * 60 * uint32(i)
...@@ -743,16 +601,16 @@ func (rr *LOC) parse(c *zlexer, o, f string) *ParseError { ...@@ -743,16 +601,16 @@ func (rr *LOC) parse(c *zlexer, o, f string) *ParseError {
if rr.Latitude, ok = locCheckNorth(l.token, rr.Latitude); ok { if rr.Latitude, ok = locCheckNorth(l.token, rr.Latitude); ok {
goto East goto East
} }
i, e = strconv.ParseUint(l.token, 10, 32) if i, err := strconv.ParseUint(l.token, 10, 32); err != nil || l.err || i > 59 {
if e != nil || l.err { return &ParseError{"", "bad LOC Latitude minutes", l}
return &ParseError{f, "bad LOC Latitude minutes", l} } else {
rr.Latitude += 1000 * 60 * uint32(i)
} }
rr.Latitude += 1000 * 60 * uint32(i)
c.Next() // zBlank c.Next() // zBlank
l, _ = c.Next() l, _ = c.Next()
if i, e := strconv.ParseFloat(l.token, 32); e != nil || l.err { if i, err := strconv.ParseFloat(l.token, 32); err != nil || l.err || i < 0 || i >= 60 {
return &ParseError{f, "bad LOC Latitude seconds", l} return &ParseError{"", "bad LOC Latitude seconds", l}
} else { } else {
rr.Latitude += uint32(1000 * i) rr.Latitude += uint32(1000 * i)
} }
...@@ -763,14 +621,14 @@ func (rr *LOC) parse(c *zlexer, o, f string) *ParseError { ...@@ -763,14 +621,14 @@ func (rr *LOC) parse(c *zlexer, o, f string) *ParseError {
goto East goto East
} }
// If still alive, flag an error // If still alive, flag an error
return &ParseError{f, "bad LOC Latitude North/South", l} return &ParseError{"", "bad LOC Latitude North/South", l}
East: East:
// East // East
c.Next() // zBlank c.Next() // zBlank
l, _ = c.Next() l, _ = c.Next()
if i, e := strconv.ParseUint(l.token, 10, 32); e != nil || l.err { if i, err := strconv.ParseUint(l.token, 10, 32); err != nil || l.err || i > 180 {
return &ParseError{f, "bad LOC Longitude", l} return &ParseError{"", "bad LOC Longitude", l}
} else { } else {
rr.Longitude = 1000 * 60 * 60 * uint32(i) rr.Longitude = 1000 * 60 * 60 * uint32(i)
} }
...@@ -780,15 +638,15 @@ East: ...@@ -780,15 +638,15 @@ East:
if rr.Longitude, ok = locCheckEast(l.token, rr.Longitude); ok { if rr.Longitude, ok = locCheckEast(l.token, rr.Longitude); ok {
goto Altitude goto Altitude
} }
if i, e := strconv.ParseUint(l.token, 10, 32); e != nil || l.err { if i, err := strconv.ParseUint(l.token, 10, 32); err != nil || l.err || i > 59 {
return &ParseError{f, "bad LOC Longitude minutes", l} return &ParseError{"", "bad LOC Longitude minutes", l}
} else { } else {
rr.Longitude += 1000 * 60 * uint32(i) rr.Longitude += 1000 * 60 * uint32(i)
} }
c.Next() // zBlank c.Next() // zBlank
l, _ = c.Next() l, _ = c.Next()
if i, e := strconv.ParseFloat(l.token, 32); e != nil || l.err { if i, err := strconv.ParseFloat(l.token, 32); err != nil || l.err || i < 0 || i >= 60 {
return &ParseError{f, "bad LOC Longitude seconds", l} return &ParseError{"", "bad LOC Longitude seconds", l}
} else { } else {
rr.Longitude += uint32(1000 * i) rr.Longitude += uint32(1000 * i)
} }
...@@ -799,19 +657,19 @@ East: ...@@ -799,19 +657,19 @@ East:
goto Altitude goto Altitude
} }
// If still alive, flag an error // If still alive, flag an error
return &ParseError{f, "bad LOC Longitude East/West", l} return &ParseError{"", "bad LOC Longitude East/West", l}
Altitude: Altitude:
c.Next() // zBlank c.Next() // zBlank
l, _ = c.Next() l, _ = c.Next()
if len(l.token) == 0 || l.err { if len(l.token) == 0 || l.err {
return &ParseError{f, "bad LOC Altitude", l} return &ParseError{"", "bad LOC Altitude", l}
} }
if l.token[len(l.token)-1] == 'M' || l.token[len(l.token)-1] == 'm' { if l.token[len(l.token)-1] == 'M' || l.token[len(l.token)-1] == 'm' {
l.token = l.token[0 : len(l.token)-1] l.token = l.token[0 : len(l.token)-1]
} }
if i, e := strconv.ParseFloat(l.token, 32); e != nil { if i, err := strconv.ParseFloat(l.token, 64); err != nil {
return &ParseError{f, "bad LOC Altitude", l} return &ParseError{"", "bad LOC Altitude", l}
} else { } else {
rr.Altitude = uint32(i*100.0 + 10000000.0 + 0.5) rr.Altitude = uint32(i*100.0 + 10000000.0 + 0.5)
} }
...@@ -824,52 +682,48 @@ Altitude: ...@@ -824,52 +682,48 @@ Altitude:
case zString: case zString:
switch count { switch count {
case 0: // Size case 0: // Size
e, m, ok := stringToCm(l.token) exp, m, ok := stringToCm(l.token)
if !ok { if !ok {
return &ParseError{f, "bad LOC Size", l} return &ParseError{"", "bad LOC Size", l}
} }
rr.Size = e&0x0f | m<<4&0xf0 rr.Size = exp&0x0f | m<<4&0xf0
case 1: // HorizPre case 1: // HorizPre
e, m, ok := stringToCm(l.token) exp, m, ok := stringToCm(l.token)
if !ok { if !ok {
return &ParseError{f, "bad LOC HorizPre", l} return &ParseError{"", "bad LOC HorizPre", l}
} }
rr.HorizPre = e&0x0f | m<<4&0xf0 rr.HorizPre = exp&0x0f | m<<4&0xf0
case 2: // VertPre case 2: // VertPre
e, m, ok := stringToCm(l.token) exp, m, ok := stringToCm(l.token)
if !ok { if !ok {
return &ParseError{f, "bad LOC VertPre", l} return &ParseError{"", "bad LOC VertPre", l}
} }
rr.VertPre = e&0x0f | m<<4&0xf0 rr.VertPre = exp&0x0f | m<<4&0xf0
} }
count++ count++
case zBlank: case zBlank:
// Ok // Ok
default: default:
return &ParseError{f, "bad LOC Size, HorizPre or VertPre", l} return &ParseError{"", "bad LOC Size, HorizPre or VertPre", l}
} }
l, _ = c.Next() l, _ = c.Next()
} }
return nil return nil
} }
func (rr *HIP) parse(c *zlexer, o, f string) *ParseError { func (rr *HIP) parse(c *zlexer, o string) *ParseError {
// HitLength is not represented // HitLength is not represented
l, _ := c.Next() l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return nil
}
i, e := strconv.ParseUint(l.token, 10, 8) i, e := strconv.ParseUint(l.token, 10, 8)
if e != nil || l.err { if e != nil || l.err {
return &ParseError{f, "bad HIP PublicKeyAlgorithm", l} return &ParseError{"", "bad HIP PublicKeyAlgorithm", l}
} }
rr.PublicKeyAlgorithm = uint8(i) rr.PublicKeyAlgorithm = uint8(i)
c.Next() // zBlank c.Next() // zBlank
l, _ = c.Next() // zString l, _ = c.Next() // zString
if len(l.token) == 0 || l.err { if len(l.token) == 0 || l.err {
return &ParseError{f, "bad HIP Hit", l} return &ParseError{"", "bad HIP Hit", l}
} }
rr.Hit = l.token // This can not contain spaces, see RFC 5205 Section 6. rr.Hit = l.token // This can not contain spaces, see RFC 5205 Section 6.
rr.HitLength = uint8(len(rr.Hit)) / 2 rr.HitLength = uint8(len(rr.Hit)) / 2
...@@ -877,7 +731,7 @@ func (rr *HIP) parse(c *zlexer, o, f string) *ParseError { ...@@ -877,7 +731,7 @@ func (rr *HIP) parse(c *zlexer, o, f string) *ParseError {
c.Next() // zBlank c.Next() // zBlank
l, _ = c.Next() // zString l, _ = c.Next() // zString
if len(l.token) == 0 || l.err { if len(l.token) == 0 || l.err {
return &ParseError{f, "bad HIP PublicKey", l} return &ParseError{"", "bad HIP PublicKey", l}
} }
rr.PublicKey = l.token // This cannot contain spaces rr.PublicKey = l.token // This cannot contain spaces
rr.PublicKeyLength = uint16(base64.StdEncoding.DecodedLen(len(rr.PublicKey))) rr.PublicKeyLength = uint16(base64.StdEncoding.DecodedLen(len(rr.PublicKey)))
...@@ -890,13 +744,13 @@ func (rr *HIP) parse(c *zlexer, o, f string) *ParseError { ...@@ -890,13 +744,13 @@ func (rr *HIP) parse(c *zlexer, o, f string) *ParseError {
case zString: case zString:
name, nameOk := toAbsoluteName(l.token, o) name, nameOk := toAbsoluteName(l.token, o)
if l.err || !nameOk { if l.err || !nameOk {
return &ParseError{f, "bad HIP RendezvousServers", l} return &ParseError{"", "bad HIP RendezvousServers", l}
} }
xs = append(xs, name) xs = append(xs, name)
case zBlank: case zBlank:
// Ok // Ok
default: default:
return &ParseError{f, "bad HIP RendezvousServers", l} return &ParseError{"", "bad HIP RendezvousServers", l}
} }
l, _ = c.Next() l, _ = c.Next()
} }
...@@ -905,16 +759,12 @@ func (rr *HIP) parse(c *zlexer, o, f string) *ParseError { ...@@ -905,16 +759,12 @@ func (rr *HIP) parse(c *zlexer, o, f string) *ParseError {
return nil return nil
} }
func (rr *CERT) parse(c *zlexer, o, f string) *ParseError { func (rr *CERT) parse(c *zlexer, o string) *ParseError {
l, _ := c.Next() l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return nil
}
if v, ok := StringToCertType[l.token]; ok { if v, ok := StringToCertType[l.token]; ok {
rr.Type = v rr.Type = v
} else if i, e := strconv.ParseUint(l.token, 10, 16); e != nil { } else if i, err := strconv.ParseUint(l.token, 10, 16); err != nil {
return &ParseError{f, "bad CERT Type", l} return &ParseError{"", "bad CERT Type", l}
} else { } else {
rr.Type = uint16(i) rr.Type = uint16(i)
} }
...@@ -922,19 +772,19 @@ func (rr *CERT) parse(c *zlexer, o, f string) *ParseError { ...@@ -922,19 +772,19 @@ func (rr *CERT) parse(c *zlexer, o, f string) *ParseError {
l, _ = c.Next() // zString l, _ = c.Next() // zString
i, e := strconv.ParseUint(l.token, 10, 16) i, e := strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err { if e != nil || l.err {
return &ParseError{f, "bad CERT KeyTag", l} return &ParseError{"", "bad CERT KeyTag", l}
} }
rr.KeyTag = uint16(i) rr.KeyTag = uint16(i)
c.Next() // zBlank c.Next() // zBlank
l, _ = c.Next() // zString l, _ = c.Next() // zString
if v, ok := StringToAlgorithm[l.token]; ok { if v, ok := StringToAlgorithm[l.token]; ok {
rr.Algorithm = v rr.Algorithm = v
} else if i, e := strconv.ParseUint(l.token, 10, 8); e != nil { } else if i, err := strconv.ParseUint(l.token, 10, 8); err != nil {
return &ParseError{f, "bad CERT Algorithm", l} return &ParseError{"", "bad CERT Algorithm", l}
} else { } else {
rr.Algorithm = uint8(i) rr.Algorithm = uint8(i)
} }
s, e1 := endingToString(c, "bad CERT Certificate", f) s, e1 := endingToString(c, "bad CERT Certificate")
if e1 != nil { if e1 != nil {
return e1 return e1
} }
...@@ -942,8 +792,8 @@ func (rr *CERT) parse(c *zlexer, o, f string) *ParseError { ...@@ -942,8 +792,8 @@ func (rr *CERT) parse(c *zlexer, o, f string) *ParseError {
return nil return nil
} }
func (rr *OPENPGPKEY) parse(c *zlexer, o, f string) *ParseError { func (rr *OPENPGPKEY) parse(c *zlexer, o string) *ParseError {
s, e := endingToString(c, "bad OPENPGPKEY PublicKey", f) s, e := endingToString(c, "bad OPENPGPKEY PublicKey")
if e != nil { if e != nil {
return e return e
} }
...@@ -951,25 +801,22 @@ func (rr *OPENPGPKEY) parse(c *zlexer, o, f string) *ParseError { ...@@ -951,25 +801,22 @@ func (rr *OPENPGPKEY) parse(c *zlexer, o, f string) *ParseError {
return nil return nil
} }
func (rr *CSYNC) parse(c *zlexer, o, f string) *ParseError { func (rr *CSYNC) parse(c *zlexer, o string) *ParseError {
l, _ := c.Next() l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return nil
}
j, e := strconv.ParseUint(l.token, 10, 32) j, e := strconv.ParseUint(l.token, 10, 32)
if e != nil { if e != nil {
// Serial must be a number // Serial must be a number
return &ParseError{f, "bad CSYNC serial", l} return &ParseError{"", "bad CSYNC serial", l}
} }
rr.Serial = uint32(j) rr.Serial = uint32(j)
c.Next() // zBlank c.Next() // zBlank
l, _ = c.Next() l, _ = c.Next()
j, e = strconv.ParseUint(l.token, 10, 16) j, e1 := strconv.ParseUint(l.token, 10, 16)
if e != nil { if e1 != nil {
// Serial must be a number // Serial must be a number
return &ParseError{f, "bad CSYNC flags", l} return &ParseError{"", "bad CSYNC flags", l}
} }
rr.Flags = uint16(j) rr.Flags = uint16(j)
...@@ -987,38 +834,32 @@ func (rr *CSYNC) parse(c *zlexer, o, f string) *ParseError { ...@@ -987,38 +834,32 @@ func (rr *CSYNC) parse(c *zlexer, o, f string) *ParseError {
tokenUpper := strings.ToUpper(l.token) tokenUpper := strings.ToUpper(l.token)
if k, ok = StringToType[tokenUpper]; !ok { if k, ok = StringToType[tokenUpper]; !ok {
if k, ok = typeToInt(l.token); !ok { if k, ok = typeToInt(l.token); !ok {
return &ParseError{f, "bad CSYNC TypeBitMap", l} return &ParseError{"", "bad CSYNC TypeBitMap", l}
} }
} }
rr.TypeBitMap = append(rr.TypeBitMap, k) rr.TypeBitMap = append(rr.TypeBitMap, k)
default: default:
return &ParseError{f, "bad CSYNC TypeBitMap", l} return &ParseError{"", "bad CSYNC TypeBitMap", l}
} }
l, _ = c.Next() l, _ = c.Next()
} }
return nil return nil
} }
func (rr *SIG) parse(c *zlexer, o, f string) *ParseError { func (rr *SIG) parse(c *zlexer, o string) *ParseError { return rr.RRSIG.parse(c, o) }
return rr.RRSIG.parse(c, o, f)
}
func (rr *RRSIG) parse(c *zlexer, o, f string) *ParseError { func (rr *RRSIG) parse(c *zlexer, o string) *ParseError {
l, _ := c.Next() l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return nil
}
tokenUpper := strings.ToUpper(l.token) tokenUpper := strings.ToUpper(l.token)
if t, ok := StringToType[tokenUpper]; !ok { if t, ok := StringToType[tokenUpper]; !ok {
if strings.HasPrefix(tokenUpper, "TYPE") { if strings.HasPrefix(tokenUpper, "TYPE") {
t, ok = typeToInt(l.token) t, ok = typeToInt(l.token)
if !ok { if !ok {
return &ParseError{f, "bad RRSIG Typecovered", l} return &ParseError{"", "bad RRSIG Typecovered", l}
} }
rr.TypeCovered = t rr.TypeCovered = t
} else { } else {
return &ParseError{f, "bad RRSIG Typecovered", l} return &ParseError{"", "bad RRSIG Typecovered", l}
} }
} else { } else {
rr.TypeCovered = t rr.TypeCovered = t
...@@ -1026,25 +867,25 @@ func (rr *RRSIG) parse(c *zlexer, o, f string) *ParseError { ...@@ -1026,25 +867,25 @@ func (rr *RRSIG) parse(c *zlexer, o, f string) *ParseError {
c.Next() // zBlank c.Next() // zBlank
l, _ = c.Next() l, _ = c.Next()
i, err := strconv.ParseUint(l.token, 10, 8) i, e := strconv.ParseUint(l.token, 10, 8)
if err != nil || l.err { if e != nil || l.err {
return &ParseError{f, "bad RRSIG Algorithm", l} return &ParseError{"", "bad RRSIG Algorithm", l}
} }
rr.Algorithm = uint8(i) rr.Algorithm = uint8(i)
c.Next() // zBlank c.Next() // zBlank
l, _ = c.Next() l, _ = c.Next()
i, err = strconv.ParseUint(l.token, 10, 8) i, e1 := strconv.ParseUint(l.token, 10, 8)
if err != nil || l.err { if e1 != nil || l.err {
return &ParseError{f, "bad RRSIG Labels", l} return &ParseError{"", "bad RRSIG Labels", l}
} }
rr.Labels = uint8(i) rr.Labels = uint8(i)
c.Next() // zBlank c.Next() // zBlank
l, _ = c.Next() l, _ = c.Next()
i, err = strconv.ParseUint(l.token, 10, 32) i, e2 := strconv.ParseUint(l.token, 10, 32)
if err != nil || l.err { if e2 != nil || l.err {
return &ParseError{f, "bad RRSIG OrigTtl", l} return &ParseError{"", "bad RRSIG OrigTtl", l}
} }
rr.OrigTtl = uint32(i) rr.OrigTtl = uint32(i)
...@@ -1052,11 +893,10 @@ func (rr *RRSIG) parse(c *zlexer, o, f string) *ParseError { ...@@ -1052,11 +893,10 @@ func (rr *RRSIG) parse(c *zlexer, o, f string) *ParseError {
l, _ = c.Next() l, _ = c.Next()
if i, err := StringToTime(l.token); err != nil { if i, err := StringToTime(l.token); err != nil {
// Try to see if all numeric and use it as epoch // Try to see if all numeric and use it as epoch
if i, err := strconv.ParseInt(l.token, 10, 64); err == nil { if i, err := strconv.ParseUint(l.token, 10, 32); err == nil {
// TODO(miek): error out on > MAX_UINT32, same below
rr.Expiration = uint32(i) rr.Expiration = uint32(i)
} else { } else {
return &ParseError{f, "bad RRSIG Expiration", l} return &ParseError{"", "bad RRSIG Expiration", l}
} }
} else { } else {
rr.Expiration = i rr.Expiration = i
...@@ -1065,10 +905,10 @@ func (rr *RRSIG) parse(c *zlexer, o, f string) *ParseError { ...@@ -1065,10 +905,10 @@ func (rr *RRSIG) parse(c *zlexer, o, f string) *ParseError {
c.Next() // zBlank c.Next() // zBlank
l, _ = c.Next() l, _ = c.Next()
if i, err := StringToTime(l.token); err != nil { if i, err := StringToTime(l.token); err != nil {
if i, err := strconv.ParseInt(l.token, 10, 64); err == nil { if i, err := strconv.ParseUint(l.token, 10, 32); err == nil {
rr.Inception = uint32(i) rr.Inception = uint32(i)
} else { } else {
return &ParseError{f, "bad RRSIG Inception", l} return &ParseError{"", "bad RRSIG Inception", l}
} }
} else { } else {
rr.Inception = i rr.Inception = i
...@@ -1076,9 +916,9 @@ func (rr *RRSIG) parse(c *zlexer, o, f string) *ParseError { ...@@ -1076,9 +916,9 @@ func (rr *RRSIG) parse(c *zlexer, o, f string) *ParseError {
c.Next() // zBlank c.Next() // zBlank
l, _ = c.Next() l, _ = c.Next()
i, err = strconv.ParseUint(l.token, 10, 16) i, e3 := strconv.ParseUint(l.token, 10, 16)
if err != nil || l.err { if e3 != nil || l.err {
return &ParseError{f, "bad RRSIG KeyTag", l} return &ParseError{"", "bad RRSIG KeyTag", l}
} }
rr.KeyTag = uint16(i) rr.KeyTag = uint16(i)
...@@ -1087,29 +927,24 @@ func (rr *RRSIG) parse(c *zlexer, o, f string) *ParseError { ...@@ -1087,29 +927,24 @@ func (rr *RRSIG) parse(c *zlexer, o, f string) *ParseError {
rr.SignerName = l.token rr.SignerName = l.token
name, nameOk := toAbsoluteName(l.token, o) name, nameOk := toAbsoluteName(l.token, o)
if l.err || !nameOk { if l.err || !nameOk {
return &ParseError{f, "bad RRSIG SignerName", l} return &ParseError{"", "bad RRSIG SignerName", l}
} }
rr.SignerName = name rr.SignerName = name
s, e := endingToString(c, "bad RRSIG Signature", f) s, e4 := endingToString(c, "bad RRSIG Signature")
if e != nil { if e4 != nil {
return e return e4
} }
rr.Signature = s rr.Signature = s
return nil return nil
} }
func (rr *NSEC) parse(c *zlexer, o, f string) *ParseError { func (rr *NSEC) parse(c *zlexer, o string) *ParseError {
l, _ := c.Next() l, _ := c.Next()
rr.NextDomain = l.token
if len(l.token) == 0 { // dynamic update rr.
return nil
}
name, nameOk := toAbsoluteName(l.token, o) name, nameOk := toAbsoluteName(l.token, o)
if l.err || !nameOk { if l.err || !nameOk {
return &ParseError{f, "bad NSEC NextDomain", l} return &ParseError{"", "bad NSEC NextDomain", l}
} }
rr.NextDomain = name rr.NextDomain = name
...@@ -1127,47 +962,43 @@ func (rr *NSEC) parse(c *zlexer, o, f string) *ParseError { ...@@ -1127,47 +962,43 @@ func (rr *NSEC) parse(c *zlexer, o, f string) *ParseError {
tokenUpper := strings.ToUpper(l.token) tokenUpper := strings.ToUpper(l.token)
if k, ok = StringToType[tokenUpper]; !ok { if k, ok = StringToType[tokenUpper]; !ok {
if k, ok = typeToInt(l.token); !ok { if k, ok = typeToInt(l.token); !ok {
return &ParseError{f, "bad NSEC TypeBitMap", l} return &ParseError{"", "bad NSEC TypeBitMap", l}
} }
} }
rr.TypeBitMap = append(rr.TypeBitMap, k) rr.TypeBitMap = append(rr.TypeBitMap, k)
default: default:
return &ParseError{f, "bad NSEC TypeBitMap", l} return &ParseError{"", "bad NSEC TypeBitMap", l}
} }
l, _ = c.Next() l, _ = c.Next()
} }
return nil return nil
} }
func (rr *NSEC3) parse(c *zlexer, o, f string) *ParseError { func (rr *NSEC3) parse(c *zlexer, o string) *ParseError {
l, _ := c.Next() l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return nil
}
i, e := strconv.ParseUint(l.token, 10, 8) i, e := strconv.ParseUint(l.token, 10, 8)
if e != nil || l.err { if e != nil || l.err {
return &ParseError{f, "bad NSEC3 Hash", l} return &ParseError{"", "bad NSEC3 Hash", l}
} }
rr.Hash = uint8(i) rr.Hash = uint8(i)
c.Next() // zBlank c.Next() // zBlank
l, _ = c.Next() l, _ = c.Next()
i, e = strconv.ParseUint(l.token, 10, 8) i, e1 := strconv.ParseUint(l.token, 10, 8)
if e != nil || l.err { if e1 != nil || l.err {
return &ParseError{f, "bad NSEC3 Flags", l} return &ParseError{"", "bad NSEC3 Flags", l}
} }
rr.Flags = uint8(i) rr.Flags = uint8(i)
c.Next() // zBlank c.Next() // zBlank
l, _ = c.Next() l, _ = c.Next()
i, e = strconv.ParseUint(l.token, 10, 16) i, e2 := strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err { if e2 != nil || l.err {
return &ParseError{f, "bad NSEC3 Iterations", l} return &ParseError{"", "bad NSEC3 Iterations", l}
} }
rr.Iterations = uint16(i) rr.Iterations = uint16(i)
c.Next() c.Next()
l, _ = c.Next() l, _ = c.Next()
if len(l.token) == 0 || l.err { if len(l.token) == 0 || l.err {
return &ParseError{f, "bad NSEC3 Salt", l} return &ParseError{"", "bad NSEC3 Salt", l}
} }
if l.token != "-" { if l.token != "-" {
rr.SaltLength = uint8(len(l.token)) / 2 rr.SaltLength = uint8(len(l.token)) / 2
...@@ -1177,7 +1008,7 @@ func (rr *NSEC3) parse(c *zlexer, o, f string) *ParseError { ...@@ -1177,7 +1008,7 @@ func (rr *NSEC3) parse(c *zlexer, o, f string) *ParseError {
c.Next() c.Next()
l, _ = c.Next() l, _ = c.Next()
if len(l.token) == 0 || l.err { if len(l.token) == 0 || l.err {
return &ParseError{f, "bad NSEC3 NextDomain", l} return &ParseError{"", "bad NSEC3 NextDomain", l}
} }
rr.HashLength = 20 // Fix for NSEC3 (sha1 160 bits) rr.HashLength = 20 // Fix for NSEC3 (sha1 160 bits)
rr.NextDomain = l.token rr.NextDomain = l.token
...@@ -1196,60 +1027,52 @@ func (rr *NSEC3) parse(c *zlexer, o, f string) *ParseError { ...@@ -1196,60 +1027,52 @@ func (rr *NSEC3) parse(c *zlexer, o, f string) *ParseError {
tokenUpper := strings.ToUpper(l.token) tokenUpper := strings.ToUpper(l.token)
if k, ok = StringToType[tokenUpper]; !ok { if k, ok = StringToType[tokenUpper]; !ok {
if k, ok = typeToInt(l.token); !ok { if k, ok = typeToInt(l.token); !ok {
return &ParseError{f, "bad NSEC3 TypeBitMap", l} return &ParseError{"", "bad NSEC3 TypeBitMap", l}
} }
} }
rr.TypeBitMap = append(rr.TypeBitMap, k) rr.TypeBitMap = append(rr.TypeBitMap, k)
default: default:
return &ParseError{f, "bad NSEC3 TypeBitMap", l} return &ParseError{"", "bad NSEC3 TypeBitMap", l}
} }
l, _ = c.Next() l, _ = c.Next()
} }
return nil return nil
} }
func (rr *NSEC3PARAM) parse(c *zlexer, o, f string) *ParseError { func (rr *NSEC3PARAM) parse(c *zlexer, o string) *ParseError {
l, _ := c.Next() l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return slurpRemainder(c, f)
}
i, e := strconv.ParseUint(l.token, 10, 8) i, e := strconv.ParseUint(l.token, 10, 8)
if e != nil || l.err { if e != nil || l.err {
return &ParseError{f, "bad NSEC3PARAM Hash", l} return &ParseError{"", "bad NSEC3PARAM Hash", l}
} }
rr.Hash = uint8(i) rr.Hash = uint8(i)
c.Next() // zBlank c.Next() // zBlank
l, _ = c.Next() l, _ = c.Next()
i, e = strconv.ParseUint(l.token, 10, 8) i, e1 := strconv.ParseUint(l.token, 10, 8)
if e != nil || l.err { if e1 != nil || l.err {
return &ParseError{f, "bad NSEC3PARAM Flags", l} return &ParseError{"", "bad NSEC3PARAM Flags", l}
} }
rr.Flags = uint8(i) rr.Flags = uint8(i)
c.Next() // zBlank c.Next() // zBlank
l, _ = c.Next() l, _ = c.Next()
i, e = strconv.ParseUint(l.token, 10, 16) i, e2 := strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err { if e2 != nil || l.err {
return &ParseError{f, "bad NSEC3PARAM Iterations", l} return &ParseError{"", "bad NSEC3PARAM Iterations", l}
} }
rr.Iterations = uint16(i) rr.Iterations = uint16(i)
c.Next() c.Next()
l, _ = c.Next() l, _ = c.Next()
if l.token != "-" { if l.token != "-" {
rr.SaltLength = uint8(len(l.token)) rr.SaltLength = uint8(len(l.token) / 2)
rr.Salt = l.token rr.Salt = l.token
} }
return slurpRemainder(c, f) return slurpRemainder(c)
} }
func (rr *EUI48) parse(c *zlexer, o, f string) *ParseError { func (rr *EUI48) parse(c *zlexer, o string) *ParseError {
l, _ := c.Next() l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return slurpRemainder(c, f)
}
if len(l.token) != 17 || l.err { if len(l.token) != 17 || l.err {
return &ParseError{f, "bad EUI48 Address", l} return &ParseError{"", "bad EUI48 Address", l}
} }
addr := make([]byte, 12) addr := make([]byte, 12)
dash := 0 dash := 0
...@@ -1258,7 +1081,7 @@ func (rr *EUI48) parse(c *zlexer, o, f string) *ParseError { ...@@ -1258,7 +1081,7 @@ func (rr *EUI48) parse(c *zlexer, o, f string) *ParseError {
addr[i+1] = l.token[i+1+dash] addr[i+1] = l.token[i+1+dash]
dash++ dash++
if l.token[i+1+dash] != '-' { if l.token[i+1+dash] != '-' {
return &ParseError{f, "bad EUI48 Address", l} return &ParseError{"", "bad EUI48 Address", l}
} }
} }
addr[10] = l.token[15] addr[10] = l.token[15]
...@@ -1266,20 +1089,16 @@ func (rr *EUI48) parse(c *zlexer, o, f string) *ParseError { ...@@ -1266,20 +1089,16 @@ func (rr *EUI48) parse(c *zlexer, o, f string) *ParseError {
i, e := strconv.ParseUint(string(addr), 16, 48) i, e := strconv.ParseUint(string(addr), 16, 48)
if e != nil { if e != nil {
return &ParseError{f, "bad EUI48 Address", l} return &ParseError{"", "bad EUI48 Address", l}
} }
rr.Address = i rr.Address = i
return slurpRemainder(c, f) return slurpRemainder(c)
} }
func (rr *EUI64) parse(c *zlexer, o, f string) *ParseError { func (rr *EUI64) parse(c *zlexer, o string) *ParseError {
l, _ := c.Next() l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return slurpRemainder(c, f)
}
if len(l.token) != 23 || l.err { if len(l.token) != 23 || l.err {
return &ParseError{f, "bad EUI64 Address", l} return &ParseError{"", "bad EUI64 Address", l}
} }
addr := make([]byte, 16) addr := make([]byte, 16)
dash := 0 dash := 0
...@@ -1288,7 +1107,7 @@ func (rr *EUI64) parse(c *zlexer, o, f string) *ParseError { ...@@ -1288,7 +1107,7 @@ func (rr *EUI64) parse(c *zlexer, o, f string) *ParseError {
addr[i+1] = l.token[i+1+dash] addr[i+1] = l.token[i+1+dash]
dash++ dash++
if l.token[i+1+dash] != '-' { if l.token[i+1+dash] != '-' {
return &ParseError{f, "bad EUI64 Address", l} return &ParseError{"", "bad EUI64 Address", l}
} }
} }
addr[14] = l.token[21] addr[14] = l.token[21]
...@@ -1296,119 +1115,102 @@ func (rr *EUI64) parse(c *zlexer, o, f string) *ParseError { ...@@ -1296,119 +1115,102 @@ func (rr *EUI64) parse(c *zlexer, o, f string) *ParseError {
i, e := strconv.ParseUint(string(addr), 16, 64) i, e := strconv.ParseUint(string(addr), 16, 64)
if e != nil { if e != nil {
return &ParseError{f, "bad EUI68 Address", l} return &ParseError{"", "bad EUI68 Address", l}
} }
rr.Address = i rr.Address = i
return slurpRemainder(c, f) return slurpRemainder(c)
} }
func (rr *SSHFP) parse(c *zlexer, o, f string) *ParseError { func (rr *SSHFP) parse(c *zlexer, o string) *ParseError {
l, _ := c.Next() l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return nil
}
i, e := strconv.ParseUint(l.token, 10, 8) i, e := strconv.ParseUint(l.token, 10, 8)
if e != nil || l.err { if e != nil || l.err {
return &ParseError{f, "bad SSHFP Algorithm", l} return &ParseError{"", "bad SSHFP Algorithm", l}
} }
rr.Algorithm = uint8(i) rr.Algorithm = uint8(i)
c.Next() // zBlank c.Next() // zBlank
l, _ = c.Next() l, _ = c.Next()
i, e = strconv.ParseUint(l.token, 10, 8) i, e1 := strconv.ParseUint(l.token, 10, 8)
if e != nil || l.err { if e1 != nil || l.err {
return &ParseError{f, "bad SSHFP Type", l} return &ParseError{"", "bad SSHFP Type", l}
} }
rr.Type = uint8(i) rr.Type = uint8(i)
c.Next() // zBlank c.Next() // zBlank
s, e1 := endingToString(c, "bad SSHFP Fingerprint", f) s, e2 := endingToString(c, "bad SSHFP Fingerprint")
if e1 != nil { if e2 != nil {
return e1 return e2
} }
rr.FingerPrint = s rr.FingerPrint = s
return nil return nil
} }
func (rr *DNSKEY) parseDNSKEY(c *zlexer, o, f, typ string) *ParseError { func (rr *DNSKEY) parseDNSKEY(c *zlexer, o, typ string) *ParseError {
l, _ := c.Next() l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return nil
}
i, e := strconv.ParseUint(l.token, 10, 16) i, e := strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err { if e != nil || l.err {
return &ParseError{f, "bad " + typ + " Flags", l} return &ParseError{"", "bad " + typ + " Flags", l}
} }
rr.Flags = uint16(i) rr.Flags = uint16(i)
c.Next() // zBlank c.Next() // zBlank
l, _ = c.Next() // zString l, _ = c.Next() // zString
i, e = strconv.ParseUint(l.token, 10, 8) i, e1 := strconv.ParseUint(l.token, 10, 8)
if e != nil || l.err { if e1 != nil || l.err {
return &ParseError{f, "bad " + typ + " Protocol", l} return &ParseError{"", "bad " + typ + " Protocol", l}
} }
rr.Protocol = uint8(i) rr.Protocol = uint8(i)
c.Next() // zBlank c.Next() // zBlank
l, _ = c.Next() // zString l, _ = c.Next() // zString
i, e = strconv.ParseUint(l.token, 10, 8) i, e2 := strconv.ParseUint(l.token, 10, 8)
if e != nil || l.err { if e2 != nil || l.err {
return &ParseError{f, "bad " + typ + " Algorithm", l} return &ParseError{"", "bad " + typ + " Algorithm", l}
} }
rr.Algorithm = uint8(i) rr.Algorithm = uint8(i)
s, e1 := endingToString(c, "bad "+typ+" PublicKey", f) s, e3 := endingToString(c, "bad "+typ+" PublicKey")
if e1 != nil { if e3 != nil {
return e1 return e3
} }
rr.PublicKey = s rr.PublicKey = s
return nil return nil
} }
func (rr *DNSKEY) parse(c *zlexer, o, f string) *ParseError { func (rr *DNSKEY) parse(c *zlexer, o string) *ParseError { return rr.parseDNSKEY(c, o, "DNSKEY") }
return rr.parseDNSKEY(c, o, f, "DNSKEY") func (rr *KEY) parse(c *zlexer, o string) *ParseError { return rr.parseDNSKEY(c, o, "KEY") }
} func (rr *CDNSKEY) parse(c *zlexer, o string) *ParseError { return rr.parseDNSKEY(c, o, "CDNSKEY") }
func (rr *DS) parse(c *zlexer, o string) *ParseError { return rr.parseDS(c, o, "DS") }
func (rr *KEY) parse(c *zlexer, o, f string) *ParseError { func (rr *DLV) parse(c *zlexer, o string) *ParseError { return rr.parseDS(c, o, "DLV") }
return rr.parseDNSKEY(c, o, f, "KEY") func (rr *CDS) parse(c *zlexer, o string) *ParseError { return rr.parseDS(c, o, "CDS") }
}
func (rr *CDNSKEY) parse(c *zlexer, o, f string) *ParseError {
return rr.parseDNSKEY(c, o, f, "CDNSKEY")
}
func (rr *RKEY) parse(c *zlexer, o, f string) *ParseError { func (rr *RKEY) parse(c *zlexer, o string) *ParseError {
l, _ := c.Next() l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return nil
}
i, e := strconv.ParseUint(l.token, 10, 16) i, e := strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err { if e != nil || l.err {
return &ParseError{f, "bad RKEY Flags", l} return &ParseError{"", "bad RKEY Flags", l}
} }
rr.Flags = uint16(i) rr.Flags = uint16(i)
c.Next() // zBlank c.Next() // zBlank
l, _ = c.Next() // zString l, _ = c.Next() // zString
i, e = strconv.ParseUint(l.token, 10, 8) i, e1 := strconv.ParseUint(l.token, 10, 8)
if e != nil || l.err { if e1 != nil || l.err {
return &ParseError{f, "bad RKEY Protocol", l} return &ParseError{"", "bad RKEY Protocol", l}
} }
rr.Protocol = uint8(i) rr.Protocol = uint8(i)
c.Next() // zBlank c.Next() // zBlank
l, _ = c.Next() // zString l, _ = c.Next() // zString
i, e = strconv.ParseUint(l.token, 10, 8) i, e2 := strconv.ParseUint(l.token, 10, 8)
if e != nil || l.err { if e2 != nil || l.err {
return &ParseError{f, "bad RKEY Algorithm", l} return &ParseError{"", "bad RKEY Algorithm", l}
} }
rr.Algorithm = uint8(i) rr.Algorithm = uint8(i)
s, e1 := endingToString(c, "bad RKEY PublicKey", f) s, e3 := endingToString(c, "bad RKEY PublicKey")
if e1 != nil { if e3 != nil {
return e1 return e3
} }
rr.PublicKey = s rr.PublicKey = s
return nil return nil
} }
func (rr *EID) parse(c *zlexer, o, f string) *ParseError { func (rr *EID) parse(c *zlexer, o string) *ParseError {
s, e := endingToString(c, "bad EID Endpoint", f) s, e := endingToString(c, "bad EID Endpoint")
if e != nil { if e != nil {
return e return e
} }
...@@ -1416,8 +1218,8 @@ func (rr *EID) parse(c *zlexer, o, f string) *ParseError { ...@@ -1416,8 +1218,8 @@ func (rr *EID) parse(c *zlexer, o, f string) *ParseError {
return nil return nil
} }
func (rr *NIMLOC) parse(c *zlexer, o, f string) *ParseError { func (rr *NIMLOC) parse(c *zlexer, o string) *ParseError {
s, e := endingToString(c, "bad NIMLOC Locator", f) s, e := endingToString(c, "bad NIMLOC Locator")
if e != nil { if e != nil {
return e return e
} }
...@@ -1425,52 +1227,44 @@ func (rr *NIMLOC) parse(c *zlexer, o, f string) *ParseError { ...@@ -1425,52 +1227,44 @@ func (rr *NIMLOC) parse(c *zlexer, o, f string) *ParseError {
return nil return nil
} }
func (rr *GPOS) parse(c *zlexer, o, f string) *ParseError { func (rr *GPOS) parse(c *zlexer, o string) *ParseError {
l, _ := c.Next() l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return slurpRemainder(c, f)
}
_, e := strconv.ParseFloat(l.token, 64) _, e := strconv.ParseFloat(l.token, 64)
if e != nil || l.err { if e != nil || l.err {
return &ParseError{f, "bad GPOS Longitude", l} return &ParseError{"", "bad GPOS Longitude", l}
} }
rr.Longitude = l.token rr.Longitude = l.token
c.Next() // zBlank c.Next() // zBlank
l, _ = c.Next() l, _ = c.Next()
_, e = strconv.ParseFloat(l.token, 64) _, e1 := strconv.ParseFloat(l.token, 64)
if e != nil || l.err { if e1 != nil || l.err {
return &ParseError{f, "bad GPOS Latitude", l} return &ParseError{"", "bad GPOS Latitude", l}
} }
rr.Latitude = l.token rr.Latitude = l.token
c.Next() // zBlank c.Next() // zBlank
l, _ = c.Next() l, _ = c.Next()
_, e = strconv.ParseFloat(l.token, 64) _, e2 := strconv.ParseFloat(l.token, 64)
if e != nil || l.err { if e2 != nil || l.err {
return &ParseError{f, "bad GPOS Altitude", l} return &ParseError{"", "bad GPOS Altitude", l}
} }
rr.Altitude = l.token rr.Altitude = l.token
return slurpRemainder(c, f) return slurpRemainder(c)
} }
func (rr *DS) parseDS(c *zlexer, o, f, typ string) *ParseError { func (rr *DS) parseDS(c *zlexer, o, typ string) *ParseError {
l, _ := c.Next() l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return nil
}
i, e := strconv.ParseUint(l.token, 10, 16) i, e := strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err { if e != nil || l.err {
return &ParseError{f, "bad " + typ + " KeyTag", l} return &ParseError{"", "bad " + typ + " KeyTag", l}
} }
rr.KeyTag = uint16(i) rr.KeyTag = uint16(i)
c.Next() // zBlank c.Next() // zBlank
l, _ = c.Next() l, _ = c.Next()
if i, e = strconv.ParseUint(l.token, 10, 8); e != nil { if i, err := strconv.ParseUint(l.token, 10, 8); err != nil {
tokenUpper := strings.ToUpper(l.token) tokenUpper := strings.ToUpper(l.token)
i, ok := StringToAlgorithm[tokenUpper] i, ok := StringToAlgorithm[tokenUpper]
if !ok || l.err { if !ok || l.err {
return &ParseError{f, "bad " + typ + " Algorithm", l} return &ParseError{"", "bad " + typ + " Algorithm", l}
} }
rr.Algorithm = i rr.Algorithm = i
} else { } else {
...@@ -1478,49 +1272,33 @@ func (rr *DS) parseDS(c *zlexer, o, f, typ string) *ParseError { ...@@ -1478,49 +1272,33 @@ func (rr *DS) parseDS(c *zlexer, o, f, typ string) *ParseError {
} }
c.Next() // zBlank c.Next() // zBlank
l, _ = c.Next() l, _ = c.Next()
i, e = strconv.ParseUint(l.token, 10, 8) i, e1 := strconv.ParseUint(l.token, 10, 8)
if e != nil || l.err { if e1 != nil || l.err {
return &ParseError{f, "bad " + typ + " DigestType", l} return &ParseError{"", "bad " + typ + " DigestType", l}
} }
rr.DigestType = uint8(i) rr.DigestType = uint8(i)
s, e1 := endingToString(c, "bad "+typ+" Digest", f) s, e2 := endingToString(c, "bad "+typ+" Digest")
if e1 != nil { if e2 != nil {
return e1 return e2
} }
rr.Digest = s rr.Digest = s
return nil return nil
} }
func (rr *DS) parse(c *zlexer, o, f string) *ParseError { func (rr *TA) parse(c *zlexer, o string) *ParseError {
return rr.parseDS(c, o, f, "DS")
}
func (rr *DLV) parse(c *zlexer, o, f string) *ParseError {
return rr.parseDS(c, o, f, "DLV")
}
func (rr *CDS) parse(c *zlexer, o, f string) *ParseError {
return rr.parseDS(c, o, f, "CDS")
}
func (rr *TA) parse(c *zlexer, o, f string) *ParseError {
l, _ := c.Next() l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return nil
}
i, e := strconv.ParseUint(l.token, 10, 16) i, e := strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err { if e != nil || l.err {
return &ParseError{f, "bad TA KeyTag", l} return &ParseError{"", "bad TA KeyTag", l}
} }
rr.KeyTag = uint16(i) rr.KeyTag = uint16(i)
c.Next() // zBlank c.Next() // zBlank
l, _ = c.Next() l, _ = c.Next()
if i, e := strconv.ParseUint(l.token, 10, 8); e != nil { if i, err := strconv.ParseUint(l.token, 10, 8); err != nil {
tokenUpper := strings.ToUpper(l.token) tokenUpper := strings.ToUpper(l.token)
i, ok := StringToAlgorithm[tokenUpper] i, ok := StringToAlgorithm[tokenUpper]
if !ok || l.err { if !ok || l.err {
return &ParseError{f, "bad TA Algorithm", l} return &ParseError{"", "bad TA Algorithm", l}
} }
rr.Algorithm = i rr.Algorithm = i
} else { } else {
...@@ -1528,113 +1306,105 @@ func (rr *TA) parse(c *zlexer, o, f string) *ParseError { ...@@ -1528,113 +1306,105 @@ func (rr *TA) parse(c *zlexer, o, f string) *ParseError {
} }
c.Next() // zBlank c.Next() // zBlank
l, _ = c.Next() l, _ = c.Next()
i, e = strconv.ParseUint(l.token, 10, 8) i, e1 := strconv.ParseUint(l.token, 10, 8)
if e != nil || l.err { if e1 != nil || l.err {
return &ParseError{f, "bad TA DigestType", l} return &ParseError{"", "bad TA DigestType", l}
} }
rr.DigestType = uint8(i) rr.DigestType = uint8(i)
s, err := endingToString(c, "bad TA Digest", f) s, e2 := endingToString(c, "bad TA Digest")
if err != nil { if e2 != nil {
return err return e2
} }
rr.Digest = s rr.Digest = s
return nil return nil
} }
func (rr *TLSA) parse(c *zlexer, o, f string) *ParseError { func (rr *TLSA) parse(c *zlexer, o string) *ParseError {
l, _ := c.Next() l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return nil
}
i, e := strconv.ParseUint(l.token, 10, 8) i, e := strconv.ParseUint(l.token, 10, 8)
if e != nil || l.err { if e != nil || l.err {
return &ParseError{f, "bad TLSA Usage", l} return &ParseError{"", "bad TLSA Usage", l}
} }
rr.Usage = uint8(i) rr.Usage = uint8(i)
c.Next() // zBlank c.Next() // zBlank
l, _ = c.Next() l, _ = c.Next()
i, e = strconv.ParseUint(l.token, 10, 8) i, e1 := strconv.ParseUint(l.token, 10, 8)
if e != nil || l.err { if e1 != nil || l.err {
return &ParseError{f, "bad TLSA Selector", l} return &ParseError{"", "bad TLSA Selector", l}
} }
rr.Selector = uint8(i) rr.Selector = uint8(i)
c.Next() // zBlank c.Next() // zBlank
l, _ = c.Next() l, _ = c.Next()
i, e = strconv.ParseUint(l.token, 10, 8) i, e2 := strconv.ParseUint(l.token, 10, 8)
if e != nil || l.err { if e2 != nil || l.err {
return &ParseError{f, "bad TLSA MatchingType", l} return &ParseError{"", "bad TLSA MatchingType", l}
} }
rr.MatchingType = uint8(i) rr.MatchingType = uint8(i)
// So this needs be e2 (i.e. different than e), because...??t // So this needs be e2 (i.e. different than e), because...??t
s, e2 := endingToString(c, "bad TLSA Certificate", f) s, e3 := endingToString(c, "bad TLSA Certificate")
if e2 != nil { if e3 != nil {
return e2 return e3
} }
rr.Certificate = s rr.Certificate = s
return nil return nil
} }
func (rr *SMIMEA) parse(c *zlexer, o, f string) *ParseError { func (rr *SMIMEA) parse(c *zlexer, o string) *ParseError {
l, _ := c.Next() l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return nil
}
i, e := strconv.ParseUint(l.token, 10, 8) i, e := strconv.ParseUint(l.token, 10, 8)
if e != nil || l.err { if e != nil || l.err {
return &ParseError{f, "bad SMIMEA Usage", l} return &ParseError{"", "bad SMIMEA Usage", l}
} }
rr.Usage = uint8(i) rr.Usage = uint8(i)
c.Next() // zBlank c.Next() // zBlank
l, _ = c.Next() l, _ = c.Next()
i, e = strconv.ParseUint(l.token, 10, 8) i, e1 := strconv.ParseUint(l.token, 10, 8)
if e != nil || l.err { if e1 != nil || l.err {
return &ParseError{f, "bad SMIMEA Selector", l} return &ParseError{"", "bad SMIMEA Selector", l}
} }
rr.Selector = uint8(i) rr.Selector = uint8(i)
c.Next() // zBlank c.Next() // zBlank
l, _ = c.Next() l, _ = c.Next()
i, e = strconv.ParseUint(l.token, 10, 8) i, e2 := strconv.ParseUint(l.token, 10, 8)
if e != nil || l.err { if e2 != nil || l.err {
return &ParseError{f, "bad SMIMEA MatchingType", l} return &ParseError{"", "bad SMIMEA MatchingType", l}
} }
rr.MatchingType = uint8(i) rr.MatchingType = uint8(i)
// So this needs be e2 (i.e. different than e), because...??t // So this needs be e2 (i.e. different than e), because...??t
s, e2 := endingToString(c, "bad SMIMEA Certificate", f) s, e3 := endingToString(c, "bad SMIMEA Certificate")
if e2 != nil { if e3 != nil {
return e2 return e3
} }
rr.Certificate = s rr.Certificate = s
return nil return nil
} }
func (rr *RFC3597) parse(c *zlexer, o, f string) *ParseError { func (rr *RFC3597) parse(c *zlexer, o string) *ParseError {
l, _ := c.Next() l, _ := c.Next()
if l.token != "\\#" { if l.token != "\\#" {
return &ParseError{f, "bad RFC3597 Rdata", l} return &ParseError{"", "bad RFC3597 Rdata", l}
} }
c.Next() // zBlank c.Next() // zBlank
l, _ = c.Next() l, _ = c.Next()
rdlength, e := strconv.Atoi(l.token) rdlength, e := strconv.Atoi(l.token)
if e != nil || l.err { if e != nil || l.err {
return &ParseError{f, "bad RFC3597 Rdata ", l} return &ParseError{"", "bad RFC3597 Rdata ", l}
} }
s, e1 := endingToString(c, "bad RFC3597 Rdata", f) s, e1 := endingToString(c, "bad RFC3597 Rdata")
if e1 != nil { if e1 != nil {
return e1 return e1
} }
if rdlength*2 != len(s) { if rdlength*2 != len(s) {
return &ParseError{f, "bad RFC3597 Rdata", l} return &ParseError{"", "bad RFC3597 Rdata", l}
} }
rr.Rdata = s rr.Rdata = s
return nil return nil
} }
func (rr *SPF) parse(c *zlexer, o, f string) *ParseError { func (rr *SPF) parse(c *zlexer, o string) *ParseError {
s, e := endingToTxtSlice(c, "bad SPF Txt", f) s, e := endingToTxtSlice(c, "bad SPF Txt")
if e != nil { if e != nil {
return e return e
} }
...@@ -1642,8 +1412,8 @@ func (rr *SPF) parse(c *zlexer, o, f string) *ParseError { ...@@ -1642,8 +1412,8 @@ func (rr *SPF) parse(c *zlexer, o, f string) *ParseError {
return nil return nil
} }
func (rr *AVC) parse(c *zlexer, o, f string) *ParseError { func (rr *AVC) parse(c *zlexer, o string) *ParseError {
s, e := endingToTxtSlice(c, "bad AVC Txt", f) s, e := endingToTxtSlice(c, "bad AVC Txt")
if e != nil { if e != nil {
return e return e
} }
...@@ -1651,9 +1421,9 @@ func (rr *AVC) parse(c *zlexer, o, f string) *ParseError { ...@@ -1651,9 +1421,9 @@ func (rr *AVC) parse(c *zlexer, o, f string) *ParseError {
return nil return nil
} }
func (rr *TXT) parse(c *zlexer, o, f string) *ParseError { func (rr *TXT) parse(c *zlexer, o string) *ParseError {
// no zBlank reading here, because all this rdata is TXT // no zBlank reading here, because all this rdata is TXT
s, e := endingToTxtSlice(c, "bad TXT Txt", f) s, e := endingToTxtSlice(c, "bad TXT Txt")
if e != nil { if e != nil {
return e return e
} }
...@@ -1662,8 +1432,8 @@ func (rr *TXT) parse(c *zlexer, o, f string) *ParseError { ...@@ -1662,8 +1432,8 @@ func (rr *TXT) parse(c *zlexer, o, f string) *ParseError {
} }
// identical to setTXT // identical to setTXT
func (rr *NINFO) parse(c *zlexer, o, f string) *ParseError { func (rr *NINFO) parse(c *zlexer, o string) *ParseError {
s, e := endingToTxtSlice(c, "bad NINFO ZSData", f) s, e := endingToTxtSlice(c, "bad NINFO ZSData")
if e != nil { if e != nil {
return e return e
} }
...@@ -1671,40 +1441,36 @@ func (rr *NINFO) parse(c *zlexer, o, f string) *ParseError { ...@@ -1671,40 +1441,36 @@ func (rr *NINFO) parse(c *zlexer, o, f string) *ParseError {
return nil return nil
} }
func (rr *URI) parse(c *zlexer, o, f string) *ParseError { func (rr *URI) parse(c *zlexer, o string) *ParseError {
l, _ := c.Next() l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return nil
}
i, e := strconv.ParseUint(l.token, 10, 16) i, e := strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err { if e != nil || l.err {
return &ParseError{f, "bad URI Priority", l} return &ParseError{"", "bad URI Priority", l}
} }
rr.Priority = uint16(i) rr.Priority = uint16(i)
c.Next() // zBlank c.Next() // zBlank
l, _ = c.Next() l, _ = c.Next()
i, e = strconv.ParseUint(l.token, 10, 16) i, e1 := strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err { if e1 != nil || l.err {
return &ParseError{f, "bad URI Weight", l} return &ParseError{"", "bad URI Weight", l}
} }
rr.Weight = uint16(i) rr.Weight = uint16(i)
c.Next() // zBlank c.Next() // zBlank
s, err := endingToTxtSlice(c, "bad URI Target", f) s, e2 := endingToTxtSlice(c, "bad URI Target")
if err != nil { if e2 != nil {
return err return e2
} }
if len(s) != 1 { if len(s) != 1 {
return &ParseError{f, "bad URI Target", l} return &ParseError{"", "bad URI Target", l}
} }
rr.Target = s[0] rr.Target = s[0]
return nil return nil
} }
func (rr *DHCID) parse(c *zlexer, o, f string) *ParseError { func (rr *DHCID) parse(c *zlexer, o string) *ParseError {
// awesome record to parse! // awesome record to parse!
s, e := endingToString(c, "bad DHCID Digest", f) s, e := endingToString(c, "bad DHCID Digest")
if e != nil { if e != nil {
return e return e
} }
...@@ -1712,56 +1478,44 @@ func (rr *DHCID) parse(c *zlexer, o, f string) *ParseError { ...@@ -1712,56 +1478,44 @@ func (rr *DHCID) parse(c *zlexer, o, f string) *ParseError {
return nil return nil
} }
func (rr *NID) parse(c *zlexer, o, f string) *ParseError { func (rr *NID) parse(c *zlexer, o string) *ParseError {
l, _ := c.Next() l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return slurpRemainder(c, f)
}
i, e := strconv.ParseUint(l.token, 10, 16) i, e := strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err { if e != nil || l.err {
return &ParseError{f, "bad NID Preference", l} return &ParseError{"", "bad NID Preference", l}
} }
rr.Preference = uint16(i) rr.Preference = uint16(i)
c.Next() // zBlank c.Next() // zBlank
l, _ = c.Next() // zString l, _ = c.Next() // zString
u, err := stringToNodeID(l) u, e1 := stringToNodeID(l)
if err != nil || l.err { if e1 != nil || l.err {
return err return e1
} }
rr.NodeID = u rr.NodeID = u
return slurpRemainder(c, f) return slurpRemainder(c)
} }
func (rr *L32) parse(c *zlexer, o, f string) *ParseError { func (rr *L32) parse(c *zlexer, o string) *ParseError {
l, _ := c.Next() l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return slurpRemainder(c, f)
}
i, e := strconv.ParseUint(l.token, 10, 16) i, e := strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err { if e != nil || l.err {
return &ParseError{f, "bad L32 Preference", l} return &ParseError{"", "bad L32 Preference", l}
} }
rr.Preference = uint16(i) rr.Preference = uint16(i)
c.Next() // zBlank c.Next() // zBlank
l, _ = c.Next() // zString l, _ = c.Next() // zString
rr.Locator32 = net.ParseIP(l.token) rr.Locator32 = net.ParseIP(l.token)
if rr.Locator32 == nil || l.err { if rr.Locator32 == nil || l.err {
return &ParseError{f, "bad L32 Locator", l} return &ParseError{"", "bad L32 Locator", l}
} }
return slurpRemainder(c, f) return slurpRemainder(c)
} }
func (rr *LP) parse(c *zlexer, o, f string) *ParseError { func (rr *LP) parse(c *zlexer, o string) *ParseError {
l, _ := c.Next() l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return slurpRemainder(c, f)
}
i, e := strconv.ParseUint(l.token, 10, 16) i, e := strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err { if e != nil || l.err {
return &ParseError{f, "bad LP Preference", l} return &ParseError{"", "bad LP Preference", l}
} }
rr.Preference = uint16(i) rr.Preference = uint16(i)
...@@ -1770,64 +1524,51 @@ func (rr *LP) parse(c *zlexer, o, f string) *ParseError { ...@@ -1770,64 +1524,51 @@ func (rr *LP) parse(c *zlexer, o, f string) *ParseError {
rr.Fqdn = l.token rr.Fqdn = l.token
name, nameOk := toAbsoluteName(l.token, o) name, nameOk := toAbsoluteName(l.token, o)
if l.err || !nameOk { if l.err || !nameOk {
return &ParseError{f, "bad LP Fqdn", l} return &ParseError{"", "bad LP Fqdn", l}
} }
rr.Fqdn = name rr.Fqdn = name
return slurpRemainder(c)
return slurpRemainder(c, f)
} }
func (rr *L64) parse(c *zlexer, o, f string) *ParseError { func (rr *L64) parse(c *zlexer, o string) *ParseError {
l, _ := c.Next() l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return slurpRemainder(c, f)
}
i, e := strconv.ParseUint(l.token, 10, 16) i, e := strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err { if e != nil || l.err {
return &ParseError{f, "bad L64 Preference", l} return &ParseError{"", "bad L64 Preference", l}
} }
rr.Preference = uint16(i) rr.Preference = uint16(i)
c.Next() // zBlank c.Next() // zBlank
l, _ = c.Next() // zString l, _ = c.Next() // zString
u, err := stringToNodeID(l) u, e1 := stringToNodeID(l)
if err != nil || l.err { if e1 != nil || l.err {
return err return e1
} }
rr.Locator64 = u rr.Locator64 = u
return slurpRemainder(c, f) return slurpRemainder(c)
} }
func (rr *UID) parse(c *zlexer, o, f string) *ParseError { func (rr *UID) parse(c *zlexer, o string) *ParseError {
l, _ := c.Next() l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return slurpRemainder(c, f)
}
i, e := strconv.ParseUint(l.token, 10, 32) i, e := strconv.ParseUint(l.token, 10, 32)
if e != nil || l.err { if e != nil || l.err {
return &ParseError{f, "bad UID Uid", l} return &ParseError{"", "bad UID Uid", l}
} }
rr.Uid = uint32(i) rr.Uid = uint32(i)
return slurpRemainder(c, f) return slurpRemainder(c)
} }
func (rr *GID) parse(c *zlexer, o, f string) *ParseError { func (rr *GID) parse(c *zlexer, o string) *ParseError {
l, _ := c.Next() l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return slurpRemainder(c, f)
}
i, e := strconv.ParseUint(l.token, 10, 32) i, e := strconv.ParseUint(l.token, 10, 32)
if e != nil || l.err { if e != nil || l.err {
return &ParseError{f, "bad GID Gid", l} return &ParseError{"", "bad GID Gid", l}
} }
rr.Gid = uint32(i) rr.Gid = uint32(i)
return slurpRemainder(c, f) return slurpRemainder(c)
} }
func (rr *UINFO) parse(c *zlexer, o, f string) *ParseError { func (rr *UINFO) parse(c *zlexer, o string) *ParseError {
s, e := endingToTxtSlice(c, "bad UINFO Uinfo", f) s, e := endingToTxtSlice(c, "bad UINFO Uinfo")
if e != nil { if e != nil {
return e return e
} }
...@@ -1838,15 +1579,11 @@ func (rr *UINFO) parse(c *zlexer, o, f string) *ParseError { ...@@ -1838,15 +1579,11 @@ func (rr *UINFO) parse(c *zlexer, o, f string) *ParseError {
return nil return nil
} }
func (rr *PX) parse(c *zlexer, o, f string) *ParseError { func (rr *PX) parse(c *zlexer, o string) *ParseError {
l, _ := c.Next() l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return slurpRemainder(c, f)
}
i, e := strconv.ParseUint(l.token, 10, 16) i, e := strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err { if e != nil || l.err {
return &ParseError{f, "bad PX Preference", l} return &ParseError{"", "bad PX Preference", l}
} }
rr.Preference = uint16(i) rr.Preference = uint16(i)
...@@ -1855,7 +1592,7 @@ func (rr *PX) parse(c *zlexer, o, f string) *ParseError { ...@@ -1855,7 +1592,7 @@ func (rr *PX) parse(c *zlexer, o, f string) *ParseError {
rr.Map822 = l.token rr.Map822 = l.token
map822, map822Ok := toAbsoluteName(l.token, o) map822, map822Ok := toAbsoluteName(l.token, o)
if l.err || !map822Ok { if l.err || !map822Ok {
return &ParseError{f, "bad PX Map822", l} return &ParseError{"", "bad PX Map822", l}
} }
rr.Map822 = map822 rr.Map822 = map822
...@@ -1864,82 +1601,142 @@ func (rr *PX) parse(c *zlexer, o, f string) *ParseError { ...@@ -1864,82 +1601,142 @@ func (rr *PX) parse(c *zlexer, o, f string) *ParseError {
rr.Mapx400 = l.token rr.Mapx400 = l.token
mapx400, mapx400Ok := toAbsoluteName(l.token, o) mapx400, mapx400Ok := toAbsoluteName(l.token, o)
if l.err || !mapx400Ok { if l.err || !mapx400Ok {
return &ParseError{f, "bad PX Mapx400", l} return &ParseError{"", "bad PX Mapx400", l}
} }
rr.Mapx400 = mapx400 rr.Mapx400 = mapx400
return slurpRemainder(c)
return slurpRemainder(c, f)
} }
func (rr *CAA) parse(c *zlexer, o, f string) *ParseError { func (rr *CAA) parse(c *zlexer, o string) *ParseError {
l, _ := c.Next() l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr. i, e := strconv.ParseUint(l.token, 10, 8)
return nil if e != nil || l.err {
} return &ParseError{"", "bad CAA Flag", l}
i, err := strconv.ParseUint(l.token, 10, 8)
if err != nil || l.err {
return &ParseError{f, "bad CAA Flag", l}
} }
rr.Flag = uint8(i) rr.Flag = uint8(i)
c.Next() // zBlank c.Next() // zBlank
l, _ = c.Next() // zString l, _ = c.Next() // zString
if l.value != zString { if l.value != zString {
return &ParseError{f, "bad CAA Tag", l} return &ParseError{"", "bad CAA Tag", l}
} }
rr.Tag = l.token rr.Tag = l.token
c.Next() // zBlank c.Next() // zBlank
s, e := endingToTxtSlice(c, "bad CAA Value", f) s, e1 := endingToTxtSlice(c, "bad CAA Value")
if e != nil { if e1 != nil {
return e return e1
} }
if len(s) != 1 { if len(s) != 1 {
return &ParseError{f, "bad CAA Value", l} return &ParseError{"", "bad CAA Value", l}
} }
rr.Value = s[0] rr.Value = s[0]
return nil return nil
} }
func (rr *TKEY) parse(c *zlexer, o, f string) *ParseError { func (rr *TKEY) parse(c *zlexer, o string) *ParseError {
l, _ := c.Next() l, _ := c.Next()
// Algorithm // Algorithm
if l.value != zString { if l.value != zString {
return &ParseError{f, "bad TKEY algorithm", l} return &ParseError{"", "bad TKEY algorithm", l}
} }
rr.Algorithm = l.token rr.Algorithm = l.token
c.Next() // zBlank c.Next() // zBlank
// Get the key length and key values // Get the key length and key values
l, _ = c.Next() l, _ = c.Next()
i, err := strconv.ParseUint(l.token, 10, 8) i, e := strconv.ParseUint(l.token, 10, 8)
if err != nil || l.err { if e != nil || l.err {
return &ParseError{f, "bad TKEY key length", l} return &ParseError{"", "bad TKEY key length", l}
} }
rr.KeySize = uint16(i) rr.KeySize = uint16(i)
c.Next() // zBlank c.Next() // zBlank
l, _ = c.Next() l, _ = c.Next()
if l.value != zString { if l.value != zString {
return &ParseError{f, "bad TKEY key", l} return &ParseError{"", "bad TKEY key", l}
} }
rr.Key = l.token rr.Key = l.token
c.Next() // zBlank c.Next() // zBlank
// Get the otherdata length and string data // Get the otherdata length and string data
l, _ = c.Next() l, _ = c.Next()
i, err = strconv.ParseUint(l.token, 10, 8) i, e1 := strconv.ParseUint(l.token, 10, 8)
if err != nil || l.err { if e1 != nil || l.err {
return &ParseError{f, "bad TKEY otherdata length", l} return &ParseError{"", "bad TKEY otherdata length", l}
} }
rr.OtherLen = uint16(i) rr.OtherLen = uint16(i)
c.Next() // zBlank c.Next() // zBlank
l, _ = c.Next() l, _ = c.Next()
if l.value != zString { if l.value != zString {
return &ParseError{f, "bad TKEY otherday", l} return &ParseError{"", "bad TKEY otherday", l}
} }
rr.OtherData = l.token rr.OtherData = l.token
return nil
}
func (rr *APL) parse(c *zlexer, o string) *ParseError {
var prefixes []APLPrefix
for {
l, _ := c.Next()
if l.value == zNewline || l.value == zEOF {
break
}
if l.value == zBlank && prefixes != nil {
continue
}
if l.value != zString {
return &ParseError{"", "unexpected APL field", l}
}
// Expected format: [!]afi:address/prefix
colon := strings.IndexByte(l.token, ':')
if colon == -1 {
return &ParseError{"", "missing colon in APL field", l}
}
family, cidr := l.token[:colon], l.token[colon+1:]
var negation bool
if family != "" && family[0] == '!' {
negation = true
family = family[1:]
}
afi, e := strconv.ParseUint(family, 10, 16)
if e != nil {
return &ParseError{"", "failed to parse APL family: " + e.Error(), l}
}
var addrLen int
switch afi {
case 1:
addrLen = net.IPv4len
case 2:
addrLen = net.IPv6len
default:
return &ParseError{"", "unrecognized APL family", l}
}
ip, subnet, e1 := net.ParseCIDR(cidr)
if e1 != nil {
return &ParseError{"", "failed to parse APL address: " + e1.Error(), l}
}
if !ip.Equal(subnet.IP) {
return &ParseError{"", "extra bits in APL address", l}
}
if len(subnet.IP) != addrLen {
return &ParseError{"", "address mismatch with the APL family", l}
}
prefixes = append(prefixes, APLPrefix{
Negation: negation,
Network: *subnet,
})
}
rr.Prefixes = prefixes
return nil return nil
} }
package dns package dns
import ( import (
"strings"
"sync" "sync"
) )
...@@ -36,33 +35,9 @@ func (mux *ServeMux) match(q string, t uint16) Handler { ...@@ -36,33 +35,9 @@ func (mux *ServeMux) match(q string, t uint16) Handler {
return nil return nil
} }
var handler Handler q = CanonicalName(q)
// TODO(tmthrgd): Once https://go-review.googlesource.com/c/go/+/137575
// lands in a go release, replace the following with strings.ToLower.
var sb strings.Builder
for i := 0; i < len(q); i++ {
c := q[i]
if !(c >= 'A' && c <= 'Z') {
continue
}
sb.Grow(len(q))
sb.WriteString(q[:i])
for ; i < len(q); i++ {
c := q[i]
if c >= 'A' && c <= 'Z' {
c += 'a' - 'A'
}
sb.WriteByte(c)
}
q = sb.String()
break
}
var handler Handler
for off, end := 0, false; !end; off, end = NextLabel(q, off) { for off, end := 0, false; !end; off, end = NextLabel(q, off) {
if h, ok := mux.z[q[off:]]; ok { if h, ok := mux.z[q[off:]]; ok {
if t != TypeDS { if t != TypeDS {
...@@ -90,7 +65,7 @@ func (mux *ServeMux) Handle(pattern string, handler Handler) { ...@@ -90,7 +65,7 @@ func (mux *ServeMux) Handle(pattern string, handler Handler) {
if mux.z == nil { if mux.z == nil {
mux.z = make(map[string]Handler) mux.z = make(map[string]Handler)
} }
mux.z[Fqdn(pattern)] = handler mux.z[CanonicalName(pattern)] = handler
mux.m.Unlock() mux.m.Unlock()
} }
...@@ -105,7 +80,7 @@ func (mux *ServeMux) HandleRemove(pattern string) { ...@@ -105,7 +80,7 @@ func (mux *ServeMux) HandleRemove(pattern string) {
panic("dns: invalid pattern " + pattern) panic("dns: invalid pattern " + pattern)
} }
mux.m.Lock() mux.m.Lock()
delete(mux.z, Fqdn(pattern)) delete(mux.z, CanonicalName(pattern))
mux.m.Unlock() mux.m.Unlock()
} }
...@@ -116,7 +91,7 @@ func (mux *ServeMux) HandleRemove(pattern string) { ...@@ -116,7 +91,7 @@ func (mux *ServeMux) HandleRemove(pattern string) {
// are redirected to the parent zone (if that is also registered), // are redirected to the parent zone (if that is also registered),
// otherwise the child gets the query. // otherwise the child gets the query.
// //
// If no handler is found, or there is no question, a standard SERVFAIL // If no handler is found, or there is no question, a standard REFUSED
// message is returned // message is returned
func (mux *ServeMux) ServeDNS(w ResponseWriter, req *Msg) { func (mux *ServeMux) ServeDNS(w ResponseWriter, req *Msg) {
var h Handler var h Handler
...@@ -127,7 +102,7 @@ func (mux *ServeMux) ServeDNS(w ResponseWriter, req *Msg) { ...@@ -127,7 +102,7 @@ func (mux *ServeMux) ServeDNS(w ResponseWriter, req *Msg) {
if h != nil { if h != nil {
h.ServeDNS(w, req) h.ServeDNS(w, req)
} else { } else {
HandleFailed(w, req) handleRefused(w, req)
} }
} }
......
...@@ -72,13 +72,22 @@ type response struct { ...@@ -72,13 +72,22 @@ type response struct {
tsigStatus error tsigStatus error
tsigRequestMAC string tsigRequestMAC string
tsigSecret map[string]string // the tsig secrets tsigSecret map[string]string // the tsig secrets
udp *net.UDPConn // i/o connection if UDP was used udp net.PacketConn // i/o connection if UDP was used
tcp net.Conn // i/o connection if TCP was used tcp net.Conn // i/o connection if TCP was used
udpSession *SessionUDP // oob data to get egress interface right udpSession *SessionUDP // oob data to get egress interface right
pcSession net.Addr // address to use when writing to a generic net.PacketConn
writer Writer // writer to output the raw DNS bits writer Writer // writer to output the raw DNS bits
} }
// handleRefused returns a HandlerFunc that returns REFUSED for every request it gets.
func handleRefused(w ResponseWriter, r *Msg) {
m := new(Msg)
m.SetRcode(r, RcodeRefused)
w.WriteMsg(m)
}
// HandleFailed returns a HandlerFunc that returns SERVFAIL for every request it gets. // HandleFailed returns a HandlerFunc that returns SERVFAIL for every request it gets.
// Deprecated: This function is going away.
func HandleFailed(w ResponseWriter, r *Msg) { func HandleFailed(w ResponseWriter, r *Msg) {
m := new(Msg) m := new(Msg)
m.SetRcode(r, RcodeServerFailure) m.SetRcode(r, RcodeServerFailure)
...@@ -139,12 +148,24 @@ type Reader interface { ...@@ -139,12 +148,24 @@ type Reader interface {
ReadUDP(conn *net.UDPConn, timeout time.Duration) ([]byte, *SessionUDP, error) ReadUDP(conn *net.UDPConn, timeout time.Duration) ([]byte, *SessionUDP, error)
} }
// defaultReader is an adapter for the Server struct that implements the Reader interface // PacketConnReader is an optional interface that Readers can implement to support using generic net.PacketConns.
// using the readTCP and readUDP func of the embedded Server. type PacketConnReader interface {
Reader
// ReadPacketConn reads a raw message from a generic net.PacketConn UDP connection. Implementations may
// alter connection properties, for example the read-deadline.
ReadPacketConn(conn net.PacketConn, timeout time.Duration) ([]byte, net.Addr, error)
}
// defaultReader is an adapter for the Server struct that implements the Reader and
// PacketConnReader interfaces using the readTCP, readUDP and readPacketConn funcs
// of the embedded Server.
type defaultReader struct { type defaultReader struct {
*Server *Server
} }
var _ PacketConnReader = defaultReader{}
func (dr defaultReader) ReadTCP(conn net.Conn, timeout time.Duration) ([]byte, error) { func (dr defaultReader) ReadTCP(conn net.Conn, timeout time.Duration) ([]byte, error) {
return dr.readTCP(conn, timeout) return dr.readTCP(conn, timeout)
} }
...@@ -153,8 +174,14 @@ func (dr defaultReader) ReadUDP(conn *net.UDPConn, timeout time.Duration) ([]byt ...@@ -153,8 +174,14 @@ func (dr defaultReader) ReadUDP(conn *net.UDPConn, timeout time.Duration) ([]byt
return dr.readUDP(conn, timeout) return dr.readUDP(conn, timeout)
} }
func (dr defaultReader) ReadPacketConn(conn net.PacketConn, timeout time.Duration) ([]byte, net.Addr, error) {
return dr.readPacketConn(conn, timeout)
}
// DecorateReader is a decorator hook for extending or supplanting the functionality of a Reader. // DecorateReader is a decorator hook for extending or supplanting the functionality of a Reader.
// Implementations should never return a nil Reader. // Implementations should never return a nil Reader.
// Readers should also implement the optional PacketConnReader interface.
// PacketConnReader is required to use a generic net.PacketConn.
type DecorateReader func(Reader) Reader type DecorateReader func(Reader) Reader
// DecorateWriter is a decorator hook for extending or supplanting the functionality of a Writer. // DecorateWriter is a decorator hook for extending or supplanting the functionality of a Writer.
...@@ -317,24 +344,22 @@ func (srv *Server) ActivateAndServe() error { ...@@ -317,24 +344,22 @@ func (srv *Server) ActivateAndServe() error {
srv.init() srv.init()
pConn := srv.PacketConn if srv.PacketConn != nil {
l := srv.Listener
if pConn != nil {
// Check PacketConn interface's type is valid and value // Check PacketConn interface's type is valid and value
// is not nil // is not nil
if t, ok := pConn.(*net.UDPConn); ok && t != nil { if t, ok := srv.PacketConn.(*net.UDPConn); ok && t != nil {
if e := setUDPSocketOptions(t); e != nil { if e := setUDPSocketOptions(t); e != nil {
return e return e
} }
srv.started = true
unlock()
return srv.serveUDP(t)
} }
srv.started = true
unlock()
return srv.serveUDP(srv.PacketConn)
} }
if l != nil { if srv.Listener != nil {
srv.started = true srv.started = true
unlock() unlock()
return srv.serveTCP(l) return srv.serveTCP(srv.Listener)
} }
return &Error{err: "bad listeners"} return &Error{err: "bad listeners"}
} }
...@@ -438,18 +463,24 @@ func (srv *Server) serveTCP(l net.Listener) error { ...@@ -438,18 +463,24 @@ func (srv *Server) serveTCP(l net.Listener) error {
} }
// serveUDP starts a UDP listener for the server. // serveUDP starts a UDP listener for the server.
func (srv *Server) serveUDP(l *net.UDPConn) error { func (srv *Server) serveUDP(l net.PacketConn) error {
defer l.Close() defer l.Close()
if srv.NotifyStartedFunc != nil {
srv.NotifyStartedFunc()
}
reader := Reader(defaultReader{srv}) reader := Reader(defaultReader{srv})
if srv.DecorateReader != nil { if srv.DecorateReader != nil {
reader = srv.DecorateReader(reader) reader = srv.DecorateReader(reader)
} }
lUDP, isUDP := l.(*net.UDPConn)
readerPC, canPacketConn := reader.(PacketConnReader)
if !isUDP && !canPacketConn {
return &Error{err: "PacketConnReader was not implemented on Reader returned from DecorateReader but is required for net.PacketConn"}
}
if srv.NotifyStartedFunc != nil {
srv.NotifyStartedFunc()
}
var wg sync.WaitGroup var wg sync.WaitGroup
defer func() { defer func() {
wg.Wait() wg.Wait()
...@@ -459,7 +490,17 @@ func (srv *Server) serveUDP(l *net.UDPConn) error { ...@@ -459,7 +490,17 @@ func (srv *Server) serveUDP(l *net.UDPConn) error {
rtimeout := srv.getReadTimeout() rtimeout := srv.getReadTimeout()
// deadline is not used here // deadline is not used here
for srv.isStarted() { for srv.isStarted() {
m, s, err := reader.ReadUDP(l, rtimeout) var (
m []byte
sPC net.Addr
sUDP *SessionUDP
err error
)
if isUDP {
m, sUDP, err = reader.ReadUDP(lUDP, rtimeout)
} else {
m, sPC, err = readerPC.ReadPacketConn(l, rtimeout)
}
if err != nil { if err != nil {
if !srv.isStarted() { if !srv.isStarted() {
return nil return nil
...@@ -476,7 +517,7 @@ func (srv *Server) serveUDP(l *net.UDPConn) error { ...@@ -476,7 +517,7 @@ func (srv *Server) serveUDP(l *net.UDPConn) error {
continue continue
} }
wg.Add(1) wg.Add(1)
go srv.serveUDPPacket(&wg, m, l, s) go srv.serveUDPPacket(&wg, m, l, sUDP, sPC)
} }
return nil return nil
...@@ -538,8 +579,8 @@ func (srv *Server) serveTCPConn(wg *sync.WaitGroup, rw net.Conn) { ...@@ -538,8 +579,8 @@ func (srv *Server) serveTCPConn(wg *sync.WaitGroup, rw net.Conn) {
} }
// Serve a new UDP request. // Serve a new UDP request.
func (srv *Server) serveUDPPacket(wg *sync.WaitGroup, m []byte, u *net.UDPConn, s *SessionUDP) { func (srv *Server) serveUDPPacket(wg *sync.WaitGroup, m []byte, u net.PacketConn, udpSession *SessionUDP, pcSession net.Addr) {
w := &response{tsigSecret: srv.TsigSecret, udp: u, udpSession: s} w := &response{tsigSecret: srv.TsigSecret, udp: u, udpSession: udpSession, pcSession: pcSession}
if srv.DecorateWriter != nil { if srv.DecorateWriter != nil {
w.writer = srv.DecorateWriter(w) w.writer = srv.DecorateWriter(w)
} else { } else {
...@@ -560,26 +601,32 @@ func (srv *Server) serveDNS(m []byte, w *response) { ...@@ -560,26 +601,32 @@ func (srv *Server) serveDNS(m []byte, w *response) {
req := new(Msg) req := new(Msg)
req.setHdr(dh) req.setHdr(dh)
switch srv.MsgAcceptFunc(dh) { switch action := srv.MsgAcceptFunc(dh); action {
case MsgAccept: case MsgAccept:
if req.unpack(dh, m, off) == nil { if req.unpack(dh, m, off) == nil {
break break
} }
fallthrough fallthrough
case MsgReject: case MsgReject, MsgRejectNotImplemented:
opcode := req.Opcode
req.SetRcodeFormatError(req) req.SetRcodeFormatError(req)
req.Zero = false
if action == MsgRejectNotImplemented {
req.Opcode = opcode
req.Rcode = RcodeNotImplemented
}
// Are we allowed to delete any OPT records here? // Are we allowed to delete any OPT records here?
req.Ns, req.Answer, req.Extra = nil, nil, nil req.Ns, req.Answer, req.Extra = nil, nil, nil
w.WriteMsg(req) w.WriteMsg(req)
fallthrough
case MsgIgnore:
if w.udp != nil && cap(m) == srv.UDPSize { if w.udp != nil && cap(m) == srv.UDPSize {
srv.udpPool.Put(m[:srv.UDPSize]) srv.udpPool.Put(m[:srv.UDPSize])
} }
return
case MsgIgnore:
return return
} }
...@@ -645,6 +692,24 @@ func (srv *Server) readUDP(conn *net.UDPConn, timeout time.Duration) ([]byte, *S ...@@ -645,6 +692,24 @@ func (srv *Server) readUDP(conn *net.UDPConn, timeout time.Duration) ([]byte, *S
return m, s, nil return m, s, nil
} }
func (srv *Server) readPacketConn(conn net.PacketConn, timeout time.Duration) ([]byte, net.Addr, error) {
srv.lock.RLock()
if srv.started {
// See the comment in readTCP above.
conn.SetReadDeadline(time.Now().Add(timeout))
}
srv.lock.RUnlock()
m := srv.udpPool.Get().([]byte)
n, addr, err := conn.ReadFrom(m)
if err != nil {
srv.udpPool.Put(m)
return nil, nil, err
}
m = m[:n]
return m, addr, nil
}
// WriteMsg implements the ResponseWriter.WriteMsg method. // WriteMsg implements the ResponseWriter.WriteMsg method.
func (w *response) WriteMsg(m *Msg) (err error) { func (w *response) WriteMsg(m *Msg) (err error) {
if w.closed { if w.closed {
...@@ -678,7 +743,10 @@ func (w *response) Write(m []byte) (int, error) { ...@@ -678,7 +743,10 @@ func (w *response) Write(m []byte) (int, error) {
switch { switch {
case w.udp != nil: case w.udp != nil:
return WriteToSessionUDP(w.udp, m, w.udpSession) if u, ok := w.udp.(*net.UDPConn); ok {
return WriteToSessionUDP(u, m, w.udpSession)
}
return w.udp.WriteTo(m, w.pcSession)
case w.tcp != nil: case w.tcp != nil:
if len(m) > MaxMsgSize { if len(m) > MaxMsgSize {
return 0, &Error{err: "message too large"} return 0, &Error{err: "message too large"}
...@@ -711,10 +779,12 @@ func (w *response) RemoteAddr() net.Addr { ...@@ -711,10 +779,12 @@ func (w *response) RemoteAddr() net.Addr {
switch { switch {
case w.udpSession != nil: case w.udpSession != nil:
return w.udpSession.RemoteAddr() return w.udpSession.RemoteAddr()
case w.pcSession != nil:
return w.pcSession
case w.tcp != nil: case w.tcp != nil:
return w.tcp.RemoteAddr() return w.tcp.RemoteAddr()
default: default:
panic("dns: internal error: udpSession and tcp both nil") panic("dns: internal error: udpSession, pcSession and tcp are all nil")
} }
} }
......
...@@ -2,7 +2,6 @@ package dns ...@@ -2,7 +2,6 @@ package dns
import ( import (
"crypto" "crypto"
"crypto/dsa"
"crypto/ecdsa" "crypto/ecdsa"
"crypto/rsa" "crypto/rsa"
"encoding/binary" "encoding/binary"
...@@ -85,7 +84,7 @@ func (rr *SIG) Verify(k *KEY, buf []byte) error { ...@@ -85,7 +84,7 @@ func (rr *SIG) Verify(k *KEY, buf []byte) error {
var hash crypto.Hash var hash crypto.Hash
switch rr.Algorithm { switch rr.Algorithm {
case DSA, RSASHA1: case RSASHA1:
hash = crypto.SHA1 hash = crypto.SHA1
case RSASHA256, ECDSAP256SHA256: case RSASHA256, ECDSAP256SHA256:
hash = crypto.SHA256 hash = crypto.SHA256
...@@ -178,17 +177,6 @@ func (rr *SIG) Verify(k *KEY, buf []byte) error { ...@@ -178,17 +177,6 @@ func (rr *SIG) Verify(k *KEY, buf []byte) error {
hashed := hasher.Sum(nil) hashed := hasher.Sum(nil)
sig := buf[sigend:] sig := buf[sigend:]
switch k.Algorithm { switch k.Algorithm {
case DSA:
pk := k.publicKeyDSA()
sig = sig[1:]
r := new(big.Int).SetBytes(sig[:len(sig)/2])
s := new(big.Int).SetBytes(sig[len(sig)/2:])
if pk != nil {
if dsa.Verify(pk, hashed, r, s) {
return nil
}
return ErrSig
}
case RSASHA1, RSASHA256, RSASHA512: case RSASHA1, RSASHA256, RSASHA512:
pk := k.publicKeyRSA() pk := k.publicKeyRSA()
if pk != nil { if pk != nil {
......