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
import (
"bufio"
"crypto"
"crypto/dsa"
"crypto/ecdsa"
"crypto/rsa"
"io"
......@@ -44,26 +43,7 @@ func (k *DNSKEY) ReadPrivateKey(q io.Reader, file string) (crypto.PrivateKey, er
return nil, ErrPrivKey
}
switch uint8(algo) {
case DSA:
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:
case RSASHA1, RSASHA1NSEC3SHA1, RSASHA256, RSASHA512:
priv, err := readPrivateKeyRSA(m)
if err != nil {
return nil, err
......@@ -74,11 +54,7 @@ func (k *DNSKEY) ReadPrivateKey(q io.Reader, file string) (crypto.PrivateKey, er
}
priv.PublicKey = *pub
return priv, nil
case ECCGOST:
return nil, ErrPrivKey
case ECDSAP256SHA256:
fallthrough
case ECDSAP384SHA384:
case ECDSAP256SHA256, ECDSAP384SHA384:
priv, err := readPrivateKeyECDSA(m)
if err != nil {
return nil, err
......@@ -92,7 +68,7 @@ func (k *DNSKEY) ReadPrivateKey(q io.Reader, file string) (crypto.PrivateKey, er
case ED25519:
return readPrivateKeyED25519(m)
default:
return nil, ErrPrivKey
return nil, ErrAlg
}
}
......@@ -129,24 +105,6 @@ func readPrivateKeyRSA(m map[string]string) (*rsa.PrivateKey, error) {
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) {
p := new(ecdsa.PrivateKey)
p.D = new(big.Int)
......
......@@ -2,7 +2,6 @@ package dns
import (
"crypto"
"crypto/dsa"
"crypto/ecdsa"
"crypto/rsa"
"math/big"
......@@ -17,8 +16,8 @@ var bigIntOne = big.NewInt(1)
// 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).
// 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 needs some info from the key (the algorithm), so its a method of the DNSKEY.
// It supports *rsa.PrivateKey, *ecdsa.PrivateKey and ed25519.PrivateKey.
func (r *DNSKEY) PrivateKeyString(p crypto.PrivateKey) string {
algorithm := strconv.Itoa(int(r.Algorithm))
algorithm += " (" + AlgorithmToString[r.Algorithm] + ")"
......@@ -67,21 +66,6 @@ func (r *DNSKEY) PrivateKeyString(p crypto.PrivateKey) string {
"Algorithm: " + algorithm + "\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:
private := toBase64(p.Seed())
return format +
......
......@@ -83,7 +83,7 @@ with:
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.
The question section: in.Question, the answer section: in.Answer,
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.
// *Msg r has an TSIG record and it was validated
m.SetTsig("axfr.", dns.HmacMD5, 300, time.Now().Unix())
} 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)
......@@ -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
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.
EDNS0
......@@ -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.
Currently only a few have been standardized: EDNS0_NSID (RFC 5001) and
EDNS0_SUBNET (draft-vandergaast-edns-client-subnet-02). Note that these options
may be combined in an OPT RR. Basic use pattern for a server to check if (and
which) options are set:
EDNS0_SUBNET (RFC 7871). Note that these options may be combined in an OPT RR.
Basic use pattern for a server to check if (and which) options are set:
// o is a dns.OPT
for _, s := range o.Option {
......@@ -261,7 +260,7 @@ From RFC 2931:
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
the shared secret approach in TSIG. Supported algorithms: DSA, ECDSAP256SHA256,
the shared secret approach in TSIG. Supported algorithms: ECDSAP256SHA256,
ECDSAP384SHA384, RSASHA1, RSASHA256 and RSASHA512.
Signing subsequent messages in multi-message sessions is not implemented.
......
......@@ -3,9 +3,8 @@ package dns
//go:generate go run duplicate_generate.go
// 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
// is so, otherwise false.
// It's is a protocol violation to have identical RRs in a message.
// So this means the header data is equal *and* the RDATA is the same. Returns true
// if so, otherwise false. It's a protocol violation to have identical RRs in a message.
func IsDuplicate(r1, r2 RR) bool {
// Check whether the record header is identical.
if !r1.Header().isDuplicate(r2.Header()) {
......
......@@ -88,7 +88,7 @@ func (rr *OPT) len(off int, compression map[string]struct{}) int {
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")
}
......@@ -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
// 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
// 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.Hdr.Name = "."
......@@ -370,24 +370,36 @@ func (e *EDNS0_COOKIE) copy() EDNS0 { return &EDNS0_COOKIE{e.Code, e.C
// e.Lease = 120 // in seconds
// o.Option = append(o.Option, e)
type EDNS0_UL struct {
Code uint16 // Always EDNS0UL
Lease uint32
Code uint16 // Always EDNS0UL
Lease uint32
KeyLease uint32
}
// Option implements the EDNS0 interface.
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) copy() EDNS0 { return &EDNS0_UL{e.Code, e.Lease} }
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, e.KeyLease} }
// Copied: http://golang.org/src/pkg/net/dnsmsg.go
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)
return b, nil
}
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
}
e.Lease = binary.BigEndian.Uint32(b)
......@@ -531,6 +543,10 @@ func (e *EDNS0_EXPIRE) pack() ([]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 {
return ErrBuf
}
......
......@@ -2,6 +2,8 @@
package dns
import "strings"
func Fuzz(data []byte) int {
msg := new(Msg)
......@@ -16,7 +18,14 @@ func Fuzz(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 1
......
......@@ -20,13 +20,13 @@ import (
// of $ after that are interpreted.
func (zp *ZoneParser) generate(l lex) (RR, bool) {
token := l.token
step := 1
step := int64(1)
if i := strings.IndexByte(token, '/'); i >= 0 {
if i+1 == len(token) {
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 {
return zp.setParseError("bad step in $GENERATE range", l)
}
......@@ -40,20 +40,24 @@ func (zp *ZoneParser) generate(l lex) (RR, bool) {
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 {
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 {
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)
}
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.
var s string
......@@ -71,16 +75,17 @@ func (zp *ZoneParser) generate(l lex) (RR, bool) {
r := &generateReader{
s: s,
cur: start,
start: start,
end: end,
step: step,
cur: int(start),
start: int(start),
end: int(end),
step: int(step),
file: zp.file,
lex: &l,
}
zp.sub = NewZoneParser(r, zp.origin, zp.file)
zp.sub.includeDepth, zp.sub.includeAllowed = zp.includeDepth, zp.includeAllowed
zp.sub.generateDisallowed = true
zp.sub.SetDefaultTTL(defaultTtl)
return zp.subNext()
}
......@@ -183,7 +188,7 @@ func (r *generateReader) ReadByte() (byte, error) {
if errMsg != "" {
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)
}
......@@ -224,19 +229,19 @@ func modToPrintf(s string) (string, int, string) {
return "", 0, "bad base in $GENERATE"
}
offset, err := strconv.Atoi(offStr)
offset, err := strconv.ParseInt(offStr, 10, 64)
if err != nil {
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 {
return "", 0, "bad width in $GENERATE"
}
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) {
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.
func CountLabel(s string) (labels int) {
if s == "." {
......@@ -126,20 +126,23 @@ func Split(s string) []int {
// The bool end is true when the end of the string has been reached.
// Also see PrevLabel.
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++ {
switch s[i] {
case '\\':
quote = !quote
default:
quote = false
case '.':
if quote {
quote = !quote
continue
}
return i + 1, false
if s[i] != '.' {
continue
}
j := i - 1
for j >= 0 && s[j] == '\\' {
j--
}
if (j-i)%2 == 0 {
continue
}
return i + 1, false
}
return i + 1, true
}
......@@ -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.
// Also see NextLabel.
func PrevLabel(s string, n int) (i int, start bool) {
if s == "" {
return 0, true
}
if n == 0 {
return len(s), false
}
lab := Split(s)
if lab == nil {
return 0, true
l := len(s) - 1
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.
......
......@@ -11,14 +11,12 @@ package dns
//go:generate go run msg_generate.go
import (
crand "crypto/rand"
"crypto/rand"
"encoding/binary"
"fmt"
"math/big"
"math/rand"
"strconv"
"strings"
"sync"
)
const (
......@@ -73,53 +71,23 @@ var (
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
// message id. The random provided should be good enough. This being a
// variable the function can be reassigned to a custom function.
// For instance, to make it return a static value:
// Id by default returns a 16-bit random number to be used as a message id. The
// number is drawn from a cryptographically secure random number generator.
// This being a variable the function can be reassigned to a custom function.
// For instance, to make it return a static value for testing:
//
// dns.Id = func() uint16 { return 3 }
var Id = id
var (
idLock sync.Mutex
idRand *rand.Rand
)
// id returns a 16 bits random number to be used as a
// message id. The random provided should be good enough.
func id() uint16 {
idLock.Lock()
if idRand == nil {
// This (partially) works around
// 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))
var output uint16
err := binary.Read(rand.Reader, binary.BigEndian, &output)
if err != nil {
panic("dns: reading random id failed: " + err.Error())
}
// 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
return output
}
// MsgHdr is a a manually-unpacked version of (id, bits).
......@@ -430,17 +398,12 @@ Loop:
return "", lenmsg, ErrLongDomain
}
for _, b := range msg[off : off+c] {
switch b {
case '.', '(', ')', ';', ' ', '@':
fallthrough
case '"', '\\':
if isDomainNameLabelSpecial(b) {
s = append(s, '\\', b)
default:
if b < ' ' || b > '~' { // unprintable, use \DDD
s = append(s, escapeByte(b)...)
} else {
s = append(s, b)
}
} else if b < ' ' || b > '~' {
s = append(s, escapeByte(b)...)
} else {
s = append(s, b)
}
}
s = append(s, '.')
......@@ -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 off1 == off {
l = i
break
}
dst = append(dst, r)
......
......@@ -6,6 +6,7 @@ import (
"encoding/binary"
"encoding/hex"
"net"
"sort"
"strings"
)
......@@ -265,24 +266,36 @@ func unpackString(msg []byte, off int) (string, int, error) {
return "", off, &Error{err: "overflow unpacking txt"}
}
l := int(msg[off])
if off+l+1 > len(msg) {
off++
if off+l > len(msg) {
return "", off, &Error{err: "overflow unpacking txt"}
}
var s strings.Builder
s.Grow(l)
for _, b := range msg[off+1 : off+1+l] {
consumed := 0
for i, b := range msg[off : off+l] {
switch {
case b == '"' || b == '\\':
if consumed == 0 {
s.Grow(l * 2)
}
s.Write(msg[off+consumed : off+i])
s.WriteByte('\\')
s.WriteByte(b)
consumed = i + 1
case b < ' ' || b > '~': // unprintable
if consumed == 0 {
s.Grow(l * 2)
}
s.Write(msg[off+consumed : off+i])
s.WriteString(escapeByte(b))
default:
s.WriteByte(b)
consumed = i + 1
}
}
off += 1 + l
return s.String(), off, nil
if consumed == 0 { // no escaping needed
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) {
......@@ -411,100 +424,60 @@ Option:
if off+int(optlen) > len(msg) {
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 {
case EDNS0NSID:
e := 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)
return new(EDNS0_NSID)
case EDNS0SUBNET:
e := 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)
return new(EDNS0_SUBNET)
case EDNS0COOKIE:
e := new(EDNS0_COOKIE)
if err := e.unpack(msg[off : off+int(optlen)]); err != nil {
return nil, len(msg), err
}
edns = append(edns, e)
off += int(optlen)
return new(EDNS0_COOKIE)
case EDNS0EXPIRE:
return new(EDNS0_EXPIRE)
case EDNS0UL:
e := 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)
return new(EDNS0_UL)
case EDNS0LLQ:
e := 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)
return new(EDNS0_LLQ)
case EDNS0DAU:
e := 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)
return new(EDNS0_DAU)
case EDNS0DHU:
e := 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)
return new(EDNS0_DHU)
case EDNS0N3U:
e := 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)
return new(EDNS0_N3U)
case EDNS0PADDING:
e := 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)
return new(EDNS0_PADDING)
default:
e := new(EDNS0_LOCAL)
e.Code = code
if err := e.unpack(msg[off : off+int(optlen)]); err != nil {
return nil, len(msg), err
}
edns = append(edns, e)
off += int(optlen)
return e
}
if off < len(msg) {
goto Option
}
return edns, off, nil
}
func packDataOpt(options []EDNS0, msg []byte, off int) (int, error) {
for _, el := range options {
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"}
}
binary.BigEndian.PutUint16(msg[off:], el.Option()) // Option code
binary.BigEndian.PutUint16(msg[off+2:], uint16(len(b))) // Length
off += 4
if off+len(b) > len(msg) {
copy(msg[off:], b)
off = len(msg)
continue
return len(msg), &Error{err: "overflow packing opt"}
}
// Actual data
copy(msg[off:off+len(b)], b)
......@@ -587,6 +560,29 @@ func unpackDataNsec(msg []byte, off int) ([]uint16, int, error) {
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) {
if len(bitmap) == 0 {
return off, nil
......@@ -617,6 +613,65 @@ func packDataNsec(bitmap []uint16, msg []byte, off int) (int, error) {
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) {
var (
servers []string
......@@ -646,3 +701,133 @@ func packDataDomainNames(names []string, msg []byte, off int, compression compre
}
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
// size by removing records that exceed the requested size.
//
// 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
// requested buffer size.
//
// The TC bit will be set if any answer records were excluded from the
// message. This indicates to that the client should retry over TCP.
// The TC bit will be set if any records were excluded from the message.
// 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
// record, if present, and is transport specific otherwise. dns.MinMsgSize
......@@ -23,11 +29,11 @@ func (dns *Msg) Truncate(size int) {
}
// 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.
if size < 512 {
size = 512
if size < MinMsgSize {
size = MinMsgSize
}
l := msgLenWithCompressionMap(dns, nil) // uncompressed length
......@@ -68,12 +74,12 @@ func (dns *Msg) Truncate(size int) {
var numExtra int
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
// of the answer RRs can be included in the response.
dns.Truncated = len(dns.Answer) > numAnswer
// See the function documentation for when we set this.
dns.Truncated = dns.Truncated || len(dns.Answer) > numAnswer ||
len(dns.Ns) > numNS || len(dns.Extra) > numExtra
dns.Answer = dns.Answer[:numAnswer]
dns.Ns = dns.Ns[:numNS]
......
......@@ -43,7 +43,7 @@ func HashName(label string, ha uint8, iter uint16, salt string) string {
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 {
nameHash := HashName(name, rr.Hash, rr.Iterations, rr.Salt)
owner := strings.ToUpper(rr.Hdr.Name)
......
package dns
import (
"fmt"
"strings"
)
import "strings"
// 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
......@@ -16,9 +13,8 @@ type PrivateRdata interface {
// Pack is used when packing a private RR into a buffer.
Pack([]byte) (int, error)
// 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)
// Copy copies the Rdata.
// Copy copies the Rdata into the PrivateRdata argument.
Copy(PrivateRdata) error
// Len returns the length in octets of the Rdata.
Len() int
......@@ -29,22 +25,8 @@ type PrivateRdata interface {
type PrivateRR struct {
Hdr RR_Header
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.
......@@ -61,13 +43,12 @@ func (r *PrivateRR) len(off int, compression map[string]struct{}) int {
func (r *PrivateRR) copy() RR {
// make new RR like this:
rr := mkPrivateRR(r.Hdr.Rrtype)
rr.Hdr = r.Hdr
rr := &PrivateRR{r.Hdr, r.generator(), r.generator}
err := r.Data.Copy(rr.Data)
if err != nil {
panic("dns: got value that could not be used to copy Private rdata")
if err := r.Data.Copy(rr.Data); err != nil {
panic("dns: got value that could not be used to copy Private rdata: " + err.Error())
}
return rr
}
......@@ -86,7 +67,7 @@ func (r *PrivateRR) unpack(msg []byte, off int) (int, error) {
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
text := make([]string, 0, 2) // could be 0..N elements, median is probably 1
Fetch:
......@@ -103,7 +84,7 @@ Fetch:
err := r.Data.Parse(text)
if err != nil {
return &ParseError{file, err.Error(), l}
return &ParseError{"", err.Error(), l}
}
return nil
......@@ -116,7 +97,7 @@ func (r1 *PrivateRR) isDuplicate(r2 RR) bool { return false }
func PrivateHandle(rtypestr string, rtype uint16, generator func() PrivateRdata) {
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
StringToType[rtypestr] = rtype
}
......
......@@ -87,31 +87,18 @@ type lex struct {
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
type ttlState struct {
ttl uint32 // ttl is the current default TTL
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
// returned. If s contains no records, NewRR will return nil with no
// error.
//
// The class defaults to IN and TTL defaults to 3600. The full zone
// file syntax like $TTL, $ORIGIN, etc. is supported.
// NewRR reads the RR contained in the string s. Only the first RR is returned.
// If s contains no records, NewRR will return nil with no error.
//
// All fields of the returned RR are set, except RR.Header().Rdlength
// which is set to 0.
// The class defaults to IN and TTL defaults to 3600. The full zone file syntax
// like $TTL, $ORIGIN, etc. is supported. All fields of the returned RR are
// set, except RR.Header().Rdlength which is set to 0.
func NewRR(s string) (RR, error) {
if len(s) > 0 && s[len(s)-1] != '\n' { // We need a closing newline
return ReadRR(strings.NewReader(s+"\n"), "")
......@@ -133,69 +120,6 @@ func ReadRR(r io.Reader, file string) (RR, error) {
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.
//
// 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) {
//
// The directives $INCLUDE, $ORIGIN, $TTL and $GENERATE are all
// 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
// zone data:
......@@ -245,7 +170,8 @@ type ZoneParser struct {
includeDepth uint8
includeAllowed bool
includeAllowed bool
generateDisallowed bool
}
// NewZoneParser returns an RFC 1035 style zonefile parser that reads
......@@ -503,9 +429,8 @@ func (zp *ZoneParser) Next() (RR, bool) {
return zp.setParseError("expecting $TTL value, not this...", l)
}
if e := slurpRemainder(zp.c, zp.file); e != nil {
zp.parseErr = e
return nil, false
if err := slurpRemainder(zp.c); err != nil {
return zp.setParseError(err.err, err.lex)
}
ttl, ok := stringToTTL(l.token)
......@@ -527,9 +452,8 @@ func (zp *ZoneParser) Next() (RR, bool) {
return zp.setParseError("expecting $ORIGIN value, not this...", l)
}
if e := slurpRemainder(zp.c, zp.file); e != nil {
zp.parseErr = e
return nil, false
if err := slurpRemainder(zp.c); err != nil {
return zp.setParseError(err.err, err.lex)
}
name, ok := toAbsoluteName(l.token, zp.origin)
......@@ -547,6 +471,9 @@ func (zp *ZoneParser) Next() (RR, bool) {
st = zExpectDirGenerate
case zExpectDirGenerate:
if zp.generateDisallowed {
return zp.setParseError("nested $GENERATE directive not allowed", l)
}
if l.value != zString {
return zp.setParseError("expecting $GENERATE value, not this...", l)
}
......@@ -650,19 +577,44 @@ func (zp *ZoneParser) Next() (RR, bool) {
st = zExpectRdata
case zExpectRdata:
r, e := setRR(*h, zp.c, zp.origin, zp.file)
if e != nil {
// If e.lex is nil than we have encounter a unknown RR type
// in that case we substitute our current lex token
if e.lex.token == "" && e.lex.value == 0 {
e.lex = l // Uh, dirty
var rr RR
if newFn, ok := TypeToRR[h.Rrtype]; ok && canParseAsRR(h.Rrtype) {
rr = newFn()
*rr.Header() = *h
} else {
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 nil, false
return zp.setParseError(err.err, err.lex)
}
return r, true
return rr, true
}
}
......@@ -671,6 +623,18 @@ func (zp *ZoneParser) Next() (RR, bool) {
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 {
br io.ByteReader
......@@ -682,7 +646,8 @@ type zlexer struct {
comBuf string
comment string
l lex
l lex
cachedL *lex
brace int
quote bool
......@@ -748,13 +713,37 @@ func (zl *zlexer) readByte() (byte, bool) {
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) {
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
return *l, true
}
if l.err {
case l.err:
// Parsing errors should be sticky.
return lex{value: zEOF}, false
}
......@@ -908,6 +897,11 @@ func (zl *zlexer) Next() (lex, bool) {
// was inside braces and we delayed adding it until now.
com[comi] = ' ' // convert newline to space
comi++
if comi >= len(com) {
l.token = "comment length insufficient for parsing"
l.err = true
return *l, true
}
}
com[comi] = ';'
......@@ -1216,11 +1210,29 @@ func stringToCm(token string) (e, m uint8, ok bool) {
if cmeters, err = strconv.Atoi(s[1]); err != nil {
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
case 1:
if meters, err = strconv.Atoi(s[0]); err != nil {
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:
// huh?
return 0, 0, false
......@@ -1233,13 +1245,10 @@ func stringToCm(token string) (e, m uint8, ok bool) {
e = 0
val = cmeters
}
for val > 10 {
for val >= 10 {
e++
val /= 10
}
if e > 9 {
ok = false
}
m = uint8(val)
return
}
......@@ -1281,6 +1290,9 @@ func appendOrigin(name, origin string) string {
// LOC record helper function
func locCheckNorth(token string, latitude uint32) (uint32, bool) {
if latitude > 90 * 1000 * 60 * 60 {
return latitude, false
}
switch token {
case "n", "N":
return LOC_EQUATOR + latitude, true
......@@ -1292,6 +1304,9 @@ func locCheckNorth(token string, latitude uint32) (uint32, bool) {
// LOC record helper function
func locCheckEast(token string, longitude uint32) (uint32, bool) {
if longitude > 180 * 1000 * 60 * 60 {
return longitude, false
}
switch token {
case "e", "E":
return LOC_EQUATOR + longitude, true
......@@ -1302,18 +1317,18 @@ func locCheckEast(token string, longitude uint32) (uint32, bool) {
}
// "Eat" the rest of the "line"
func slurpRemainder(c *zlexer, f string) *ParseError {
func slurpRemainder(c *zlexer) *ParseError {
l, _ := c.Next()
switch l.value {
case zBlank:
l, _ = c.Next()
if l.value != zNewline && l.value != zEOF {
return &ParseError{f, "garbage after rdata", l}
return &ParseError{"", "garbage after rdata", l}
}
case zNewline:
case zEOF:
default:
return &ParseError{f, "garbage after rdata", l}
return &ParseError{"", "garbage after rdata", l}
}
return nil
}
......
package dns
import (
"bytes"
"encoding/base64"
"net"
"strconv"
"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)
// or an error
func endingToString(c *zlexer, errstr, f string) (string, *ParseError) {
var s string
func endingToString(c *zlexer, errstr string) (string, *ParseError) {
var buffer bytes.Buffer
l, _ := c.Next() // zString
for l.value != zNewline && l.value != zEOF {
if l.err {
return s, &ParseError{f, errstr, l}
return buffer.String(), &ParseError{"", errstr, l}
}
switch l.value {
case zString:
s += l.token
buffer.WriteString(l.token)
case zBlank: // Ok
default:
return "", &ParseError{f, errstr, l}
return "", &ParseError{"", errstr, l}
}
l, _ = c.Next()
}
return s, nil
return buffer.String(), nil
}
// A remainder of the rdata with embedded spaces, split on unquoted whitespace
// and return the parsed string slice or an error
func endingToTxtSlice(c *zlexer, errstr, f string) ([]string, *ParseError) {
func endingToTxtSlice(c *zlexer, errstr string) ([]string, *ParseError) {
// Get the remaining data until we see a zNewline
l, _ := c.Next()
if l.err {
return nil, &ParseError{f, errstr, l}
return nil, &ParseError{"", errstr, l}
}
// Build the slice
......@@ -78,7 +45,7 @@ func endingToTxtSlice(c *zlexer, errstr, f string) ([]string, *ParseError) {
empty := false
for l.value != zNewline && l.value != zEOF {
if l.err {
return nil, &ParseError{f, errstr, l}
return nil, &ParseError{"", errstr, l}
}
switch l.value {
case zString:
......@@ -105,7 +72,7 @@ func endingToTxtSlice(c *zlexer, errstr, f string) ([]string, *ParseError) {
case zBlank:
if quote {
// zBlank can only be seen in between txt parts.
return nil, &ParseError{f, errstr, l}
return nil, &ParseError{"", errstr, l}
}
case zQuote:
if empty && quote {
......@@ -114,24 +81,20 @@ func endingToTxtSlice(c *zlexer, errstr, f string) ([]string, *ParseError) {
quote = !quote
empty = true
default:
return nil, &ParseError{f, errstr, l}
return nil, &ParseError{"", errstr, l}
}
l, _ = c.Next()
}
if quote {
return nil, &ParseError{f, errstr, l}
return nil, &ParseError{"", errstr, l}
}
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()
if len(l.token) == 0 { // dynamic update rr.
return slurpRemainder(c, f)
}
rr.A = net.ParseIP(l.token)
// IPv4 addresses cannot include ":".
// 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 {
// IPv4.
isIPv4 := !strings.Contains(l.token, ":")
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()
if len(l.token) == 0 { // dynamic update rr.
return slurpRemainder(c, f)
}
rr.AAAA = net.ParseIP(l.token)
// IPv6 addresses must include ":", and IPv4
// addresses cannot include ":".
isIPv6 := strings.Contains(l.token, ":")
if rr.AAAA == nil || !isIPv6 || l.err {
return &ParseError{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()
rr.Ns = l.token
if len(l.token) == 0 { // dynamic update rr.
return slurpRemainder(c, f)
}
name, nameOk := toAbsoluteName(l.token, o)
if l.err || !nameOk {
return &ParseError{f, "bad NS Ns", l}
return &ParseError{"", "bad NS Ns", l}
}
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()
rr.Ptr = l.token
if len(l.token) == 0 { // dynamic update rr.
return slurpRemainder(c, f)
}
name, nameOk := toAbsoluteName(l.token, o)
if l.err || !nameOk {
return &ParseError{f, "bad PTR Ptr", l}
return &ParseError{"", "bad PTR Ptr", l}
}
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()
rr.Ptr = l.token
if len(l.token) == 0 { // dynamic update rr.
return slurpRemainder(c, f)
}
name, nameOk := toAbsoluteName(l.token, o)
if l.err || !nameOk {
return &ParseError{f, "bad NSAP-PTR Ptr", l}
return &ParseError{"", "bad NSAP-PTR Ptr", l}
}
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()
rr.Mbox = l.token
if len(l.token) == 0 { // dynamic update rr.
return slurpRemainder(c, f)
}
mbox, mboxOk := toAbsoluteName(l.token, o)
if l.err || !mboxOk {
return &ParseError{f, "bad RP Mbox", l}
return &ParseError{"", "bad RP Mbox", l}
}
rr.Mbox = mbox
......@@ -224,60 +163,45 @@ func (rr *RP) parse(c *zlexer, o, f string) *ParseError {
txt, txtOk := toAbsoluteName(l.token, o)
if l.err || !txtOk {
return &ParseError{f, "bad RP Txt", l}
return &ParseError{"", "bad RP Txt", l}
}
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()
rr.Mr = l.token
if len(l.token) == 0 { // dynamic update rr.
return slurpRemainder(c, f)
}
name, nameOk := toAbsoluteName(l.token, o)
if l.err || !nameOk {
return &ParseError{f, "bad MR Mr", l}
return &ParseError{"", "bad MR Mr", l}
}
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()
rr.Mb = l.token
if len(l.token) == 0 { // dynamic update rr.
return slurpRemainder(c, f)
}
name, nameOk := toAbsoluteName(l.token, o)
if l.err || !nameOk {
return &ParseError{f, "bad MB Mb", l}
return &ParseError{"", "bad MB Mb", l}
}
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()
rr.Mg = l.token
if len(l.token) == 0 { // dynamic update rr.
return slurpRemainder(c, f)
}
name, nameOk := toAbsoluteName(l.token, o)
if l.err || !nameOk {
return &ParseError{f, "bad MG Mg", l}
return &ParseError{"", "bad MG Mg", l}
}
rr.Mg = name
return slurpRemainder(c, f)
return slurpRemainder(c)
}
func (rr *HINFO) parse(c *zlexer, o, f string) *ParseError {
chunks, e := endingToTxtSlice(c, "bad HINFO Fields", f)
func (rr *HINFO) parse(c *zlexer, o string) *ParseError {
chunks, e := endingToTxtSlice(c, "bad HINFO Fields")
if e != nil {
return e
}
......@@ -299,16 +223,11 @@ func (rr *HINFO) parse(c *zlexer, o, f string) *ParseError {
return nil
}
func (rr *MINFO) parse(c *zlexer, o, f string) *ParseError {
func (rr *MINFO) parse(c *zlexer, o string) *ParseError {
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)
if l.err || !rmailOk {
return &ParseError{f, "bad MINFO Rmail", l}
return &ParseError{"", "bad MINFO Rmail", l}
}
rr.Rmail = rmail
......@@ -318,52 +237,38 @@ func (rr *MINFO) parse(c *zlexer, o, f string) *ParseError {
email, emailOk := toAbsoluteName(l.token, o)
if l.err || !emailOk {
return &ParseError{f, "bad MINFO Email", l}
return &ParseError{"", "bad MINFO Email", l}
}
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()
rr.Mf = l.token
if len(l.token) == 0 { // dynamic update rr.
return slurpRemainder(c, f)
}
name, nameOk := toAbsoluteName(l.token, o)
if l.err || !nameOk {
return &ParseError{f, "bad MF Mf", l}
return &ParseError{"", "bad MF Mf", l}
}
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()
rr.Md = l.token
if len(l.token) == 0 { // dynamic update rr.
return slurpRemainder(c, f)
}
name, nameOk := toAbsoluteName(l.token, o)
if l.err || !nameOk {
return &ParseError{f, "bad MD Md", l}
return &ParseError{"", "bad MD Md", l}
}
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()
if len(l.token) == 0 { // dynamic update rr.
return slurpRemainder(c, f)
}
i, e := strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err {
return &ParseError{f, "bad MX Pref", l}
return &ParseError{"", "bad MX Pref", l}
}
rr.Preference = uint16(i)
......@@ -373,22 +278,18 @@ func (rr *MX) parse(c *zlexer, o, f string) *ParseError {
name, nameOk := toAbsoluteName(l.token, o)
if l.err || !nameOk {
return &ParseError{f, "bad MX Mx", l}
return &ParseError{"", "bad MX Mx", l}
}
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()
if len(l.token) == 0 { // dynamic update rr.
return slurpRemainder(c, f)
}
i, e := strconv.ParseUint(l.token, 10, 16)
if e != nil {
return &ParseError{f, "bad RT Preference", l}
return &ParseError{"", "bad RT Preference", l}
}
rr.Preference = uint16(i)
......@@ -398,22 +299,18 @@ func (rr *RT) parse(c *zlexer, o, f string) *ParseError {
name, nameOk := toAbsoluteName(l.token, o)
if l.err || !nameOk {
return &ParseError{f, "bad RT Host", l}
return &ParseError{"", "bad RT Host", l}
}
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()
if len(l.token) == 0 { // dynamic update rr.
return slurpRemainder(c, f)
}
i, e := strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err {
return &ParseError{f, "bad AFSDB Subtype", l}
return &ParseError{"", "bad AFSDB Subtype", l}
}
rr.Subtype = uint16(i)
......@@ -423,34 +320,26 @@ func (rr *AFSDB) parse(c *zlexer, o, f string) *ParseError {
name, nameOk := toAbsoluteName(l.token, o)
if l.err || !nameOk {
return &ParseError{f, "bad AFSDB Hostname", l}
return &ParseError{"", "bad AFSDB Hostname", l}
}
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()
if len(l.token) == 0 { // dynamic update rr.
return slurpRemainder(c, f)
}
if l.err {
return &ParseError{f, "bad X25 PSDNAddress", l}
return &ParseError{"", "bad X25 PSDNAddress", l}
}
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()
if len(l.token) == 0 { // dynamic update rr.
return slurpRemainder(c, f)
}
i, e := strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err {
return &ParseError{f, "bad KX Pref", l}
return &ParseError{"", "bad KX Pref", l}
}
rr.Preference = uint16(i)
......@@ -460,52 +349,37 @@ func (rr *KX) parse(c *zlexer, o, f string) *ParseError {
name, nameOk := toAbsoluteName(l.token, o)
if l.err || !nameOk {
return &ParseError{f, "bad KX Exchanger", l}
return &ParseError{"", "bad KX Exchanger", l}
}
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()
rr.Target = l.token
if len(l.token) == 0 { // dynamic update rr.
return slurpRemainder(c, f)
}
name, nameOk := toAbsoluteName(l.token, o)
if l.err || !nameOk {
return &ParseError{f, "bad CNAME Target", l}
return &ParseError{"", "bad CNAME Target", l}
}
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()
rr.Target = l.token
if len(l.token) == 0 { // dynamic update rr.
return slurpRemainder(c, f)
}
name, nameOk := toAbsoluteName(l.token, o)
if l.err || !nameOk {
return &ParseError{f, "bad DNAME Target", l}
return &ParseError{"", "bad DNAME Target", l}
}
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()
rr.Ns = l.token
if len(l.token) == 0 { // dynamic update rr.
return slurpRemainder(c, f)
}
ns, nsOk := toAbsoluteName(l.token, o)
if l.err || !nsOk {
return &ParseError{f, "bad SOA Ns", l}
return &ParseError{"", "bad SOA Ns", l}
}
rr.Ns = ns
......@@ -515,7 +389,7 @@ func (rr *SOA) parse(c *zlexer, o, f string) *ParseError {
mbox, mboxOk := toAbsoluteName(l.token, o)
if l.err || !mboxOk {
return &ParseError{f, "bad SOA Mbox", l}
return &ParseError{"", "bad SOA Mbox", l}
}
rr.Mbox = mbox
......@@ -528,16 +402,16 @@ func (rr *SOA) parse(c *zlexer, o, f string) *ParseError {
for i := 0; i < 5; i++ {
l, _ = c.Next()
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 {
// 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
if v, ok = stringToTTL(l.token); !ok {
return &ParseError{f, "bad SOA zone parameter", l}
return &ParseError{"", "bad SOA zone parameter", l}
}
} else {
......@@ -560,34 +434,30 @@ func (rr *SOA) parse(c *zlexer, o, f string) *ParseError {
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()
if len(l.token) == 0 { // dynamic update rr.
return slurpRemainder(c, f)
}
i, e := strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err {
return &ParseError{f, "bad SRV Priority", l}
return &ParseError{"", "bad SRV Priority", l}
}
rr.Priority = uint16(i)
c.Next() // zBlank
l, _ = c.Next() // zString
i, e = strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err {
return &ParseError{f, "bad SRV Weight", l}
i, e1 := strconv.ParseUint(l.token, 10, 16)
if e1 != nil || l.err {
return &ParseError{"", "bad SRV Weight", l}
}
rr.Weight = uint16(i)
c.Next() // zBlank
l, _ = c.Next() // zString
i, e = strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err {
return &ParseError{f, "bad SRV Port", l}
i, e2 := strconv.ParseUint(l.token, 10, 16)
if e2 != nil || l.err {
return &ParseError{"", "bad SRV Port", l}
}
rr.Port = uint16(i)
......@@ -597,29 +467,25 @@ func (rr *SRV) parse(c *zlexer, o, f string) *ParseError {
name, nameOk := toAbsoluteName(l.token, o)
if l.err || !nameOk {
return &ParseError{f, "bad SRV Target", l}
return &ParseError{"", "bad SRV Target", l}
}
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()
if len(l.token) == 0 { // dynamic update rr.
return slurpRemainder(c, f)
}
i, e := strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err {
return &ParseError{f, "bad NAPTR Order", l}
return &ParseError{"", "bad NAPTR Order", l}
}
rr.Order = uint16(i)
c.Next() // zBlank
l, _ = c.Next() // zString
i, e = strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err {
return &ParseError{f, "bad NAPTR Preference", l}
i, e1 := strconv.ParseUint(l.token, 10, 16)
if e1 != nil || l.err {
return &ParseError{"", "bad NAPTR Preference", l}
}
rr.Preference = uint16(i)
......@@ -627,57 +493,57 @@ func (rr *NAPTR) parse(c *zlexer, o, f string) *ParseError {
c.Next() // zBlank
l, _ = c.Next() // _QUOTE
if l.value != zQuote {
return &ParseError{f, "bad NAPTR Flags", l}
return &ParseError{"", "bad NAPTR Flags", l}
}
l, _ = c.Next() // Either String or Quote
if l.value == zString {
rr.Flags = l.token
l, _ = c.Next() // _QUOTE
if l.value != zQuote {
return &ParseError{f, "bad NAPTR Flags", l}
return &ParseError{"", "bad NAPTR Flags", l}
}
} else if l.value == zQuote {
rr.Flags = ""
} else {
return &ParseError{f, "bad NAPTR Flags", l}
return &ParseError{"", "bad NAPTR Flags", l}
}
// Service
c.Next() // zBlank
l, _ = c.Next() // _QUOTE
if l.value != zQuote {
return &ParseError{f, "bad NAPTR Service", l}
return &ParseError{"", "bad NAPTR Service", l}
}
l, _ = c.Next() // Either String or Quote
if l.value == zString {
rr.Service = l.token
l, _ = c.Next() // _QUOTE
if l.value != zQuote {
return &ParseError{f, "bad NAPTR Service", l}
return &ParseError{"", "bad NAPTR Service", l}
}
} else if l.value == zQuote {
rr.Service = ""
} else {
return &ParseError{f, "bad NAPTR Service", l}
return &ParseError{"", "bad NAPTR Service", l}
}
// Regexp
c.Next() // zBlank
l, _ = c.Next() // _QUOTE
if l.value != zQuote {
return &ParseError{f, "bad NAPTR Regexp", l}
return &ParseError{"", "bad NAPTR Regexp", l}
}
l, _ = c.Next() // Either String or Quote
if l.value == zString {
rr.Regexp = l.token
l, _ = c.Next() // _QUOTE
if l.value != zQuote {
return &ParseError{f, "bad NAPTR Regexp", l}
return &ParseError{"", "bad NAPTR Regexp", l}
}
} else if l.value == zQuote {
rr.Regexp = ""
} else {
return &ParseError{f, "bad NAPTR Regexp", l}
return &ParseError{"", "bad NAPTR Regexp", l}
}
// After quote no space??
......@@ -687,22 +553,17 @@ func (rr *NAPTR) parse(c *zlexer, o, f string) *ParseError {
name, nameOk := toAbsoluteName(l.token, o)
if l.err || !nameOk {
return &ParseError{f, "bad NAPTR Replacement", l}
return &ParseError{"", "bad NAPTR Replacement", l}
}
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()
rr.PreviousName = l.token
if len(l.token) == 0 { // dynamic update rr.
return slurpRemainder(c, f)
}
previousName, previousNameOk := toAbsoluteName(l.token, o)
if l.err || !previousNameOk {
return &ParseError{f, "bad TALINK PreviousName", l}
return &ParseError{"", "bad TALINK PreviousName", l}
}
rr.PreviousName = previousName
......@@ -712,28 +573,25 @@ func (rr *TALINK) parse(c *zlexer, o, f string) *ParseError {
nextName, nextNameOk := toAbsoluteName(l.token, o)
if l.err || !nextNameOk {
return &ParseError{f, "bad TALINK NextName", l}
return &ParseError{"", "bad TALINK NextName", l}
}
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.
rr.HorizPre = 165 // 10000
rr.VertPre = 162 // 10
rr.Size = 18 // 1
rr.Size = 0x12 // 1e2 cm (1m)
rr.HorizPre = 0x16 // 1e6 cm (10000m)
rr.VertPre = 0x13 // 1e3 cm (10m)
ok := false
// North
l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return nil
}
i, e := strconv.ParseUint(l.token, 10, 32)
if e != nil || l.err {
return &ParseError{f, "bad LOC Latitude", l}
if e != nil || l.err || i > 90 {
return &ParseError{"", "bad LOC Latitude", l}
}
rr.Latitude = 1000 * 60 * 60 * uint32(i)
......@@ -743,16 +601,16 @@ func (rr *LOC) parse(c *zlexer, o, f string) *ParseError {
if rr.Latitude, ok = locCheckNorth(l.token, rr.Latitude); ok {
goto East
}
i, e = strconv.ParseUint(l.token, 10, 32)
if e != nil || l.err {
return &ParseError{f, "bad LOC Latitude minutes", l}
if i, err := strconv.ParseUint(l.token, 10, 32); err != nil || l.err || i > 59 {
return &ParseError{"", "bad LOC Latitude minutes", l}
} else {
rr.Latitude += 1000 * 60 * uint32(i)
}
rr.Latitude += 1000 * 60 * uint32(i)
c.Next() // zBlank
l, _ = c.Next()
if i, e := strconv.ParseFloat(l.token, 32); e != nil || l.err {
return &ParseError{f, "bad LOC Latitude seconds", l}
if i, err := strconv.ParseFloat(l.token, 32); err != nil || l.err || i < 0 || i >= 60 {
return &ParseError{"", "bad LOC Latitude seconds", l}
} else {
rr.Latitude += uint32(1000 * i)
}
......@@ -763,14 +621,14 @@ func (rr *LOC) parse(c *zlexer, o, f string) *ParseError {
goto East
}
// 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
c.Next() // zBlank
l, _ = c.Next()
if i, e := strconv.ParseUint(l.token, 10, 32); e != nil || l.err {
return &ParseError{f, "bad LOC Longitude", l}
if i, err := strconv.ParseUint(l.token, 10, 32); err != nil || l.err || i > 180 {
return &ParseError{"", "bad LOC Longitude", l}
} else {
rr.Longitude = 1000 * 60 * 60 * uint32(i)
}
......@@ -780,15 +638,15 @@ East:
if rr.Longitude, ok = locCheckEast(l.token, rr.Longitude); ok {
goto Altitude
}
if i, e := strconv.ParseUint(l.token, 10, 32); e != nil || l.err {
return &ParseError{f, "bad LOC Longitude minutes", l}
if i, err := strconv.ParseUint(l.token, 10, 32); err != nil || l.err || i > 59 {
return &ParseError{"", "bad LOC Longitude minutes", l}
} else {
rr.Longitude += 1000 * 60 * uint32(i)
}
c.Next() // zBlank
l, _ = c.Next()
if i, e := strconv.ParseFloat(l.token, 32); e != nil || l.err {
return &ParseError{f, "bad LOC Longitude seconds", l}
if i, err := strconv.ParseFloat(l.token, 32); err != nil || l.err || i < 0 || i >= 60 {
return &ParseError{"", "bad LOC Longitude seconds", l}
} else {
rr.Longitude += uint32(1000 * i)
}
......@@ -799,19 +657,19 @@ East:
goto Altitude
}
// If still alive, flag an error
return &ParseError{f, "bad LOC Longitude East/West", l}
return &ParseError{"", "bad LOC Longitude East/West", l}
Altitude:
c.Next() // zBlank
l, _ = c.Next()
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' {
l.token = l.token[0 : len(l.token)-1]
}
if i, e := strconv.ParseFloat(l.token, 32); e != nil {
return &ParseError{f, "bad LOC Altitude", l}
if i, err := strconv.ParseFloat(l.token, 64); err != nil {
return &ParseError{"", "bad LOC Altitude", l}
} else {
rr.Altitude = uint32(i*100.0 + 10000000.0 + 0.5)
}
......@@ -824,52 +682,48 @@ Altitude:
case zString:
switch count {
case 0: // Size
e, m, ok := stringToCm(l.token)
exp, m, ok := stringToCm(l.token)
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
e, m, ok := stringToCm(l.token)
exp, m, ok := stringToCm(l.token)
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
e, m, ok := stringToCm(l.token)
exp, m, ok := stringToCm(l.token)
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++
case zBlank:
// Ok
default:
return &ParseError{f, "bad LOC Size, HorizPre or VertPre", l}
return &ParseError{"", "bad LOC Size, HorizPre or VertPre", l}
}
l, _ = c.Next()
}
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
l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return nil
}
i, e := strconv.ParseUint(l.token, 10, 8)
if e != nil || l.err {
return &ParseError{f, "bad HIP PublicKeyAlgorithm", l}
return &ParseError{"", "bad HIP PublicKeyAlgorithm", l}
}
rr.PublicKeyAlgorithm = uint8(i)
c.Next() // zBlank
l, _ = c.Next() // zString
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.HitLength = uint8(len(rr.Hit)) / 2
......@@ -877,7 +731,7 @@ func (rr *HIP) parse(c *zlexer, o, f string) *ParseError {
c.Next() // zBlank
l, _ = c.Next() // zString
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.PublicKeyLength = uint16(base64.StdEncoding.DecodedLen(len(rr.PublicKey)))
......@@ -890,13 +744,13 @@ func (rr *HIP) parse(c *zlexer, o, f string) *ParseError {
case zString:
name, nameOk := toAbsoluteName(l.token, o)
if l.err || !nameOk {
return &ParseError{f, "bad HIP RendezvousServers", l}
return &ParseError{"", "bad HIP RendezvousServers", l}
}
xs = append(xs, name)
case zBlank:
// Ok
default:
return &ParseError{f, "bad HIP RendezvousServers", l}
return &ParseError{"", "bad HIP RendezvousServers", l}
}
l, _ = c.Next()
}
......@@ -905,16 +759,12 @@ func (rr *HIP) parse(c *zlexer, o, f string) *ParseError {
return nil
}
func (rr *CERT) parse(c *zlexer, o, f string) *ParseError {
func (rr *CERT) parse(c *zlexer, o string) *ParseError {
l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return nil
}
if v, ok := StringToCertType[l.token]; ok {
rr.Type = v
} else if i, e := strconv.ParseUint(l.token, 10, 16); e != nil {
return &ParseError{f, "bad CERT Type", l}
} else if i, err := strconv.ParseUint(l.token, 10, 16); err != nil {
return &ParseError{"", "bad CERT Type", l}
} else {
rr.Type = uint16(i)
}
......@@ -922,19 +772,19 @@ func (rr *CERT) parse(c *zlexer, o, f string) *ParseError {
l, _ = c.Next() // zString
i, e := strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err {
return &ParseError{f, "bad CERT KeyTag", l}
return &ParseError{"", "bad CERT KeyTag", l}
}
rr.KeyTag = uint16(i)
c.Next() // zBlank
l, _ = c.Next() // zString
if v, ok := StringToAlgorithm[l.token]; ok {
rr.Algorithm = v
} else if i, e := strconv.ParseUint(l.token, 10, 8); e != nil {
return &ParseError{f, "bad CERT Algorithm", l}
} else if i, err := strconv.ParseUint(l.token, 10, 8); err != nil {
return &ParseError{"", "bad CERT Algorithm", l}
} else {
rr.Algorithm = uint8(i)
}
s, e1 := endingToString(c, "bad CERT Certificate", f)
s, e1 := endingToString(c, "bad CERT Certificate")
if e1 != nil {
return e1
}
......@@ -942,8 +792,8 @@ func (rr *CERT) parse(c *zlexer, o, f string) *ParseError {
return nil
}
func (rr *OPENPGPKEY) parse(c *zlexer, o, f string) *ParseError {
s, e := endingToString(c, "bad OPENPGPKEY PublicKey", f)
func (rr *OPENPGPKEY) parse(c *zlexer, o string) *ParseError {
s, e := endingToString(c, "bad OPENPGPKEY PublicKey")
if e != nil {
return e
}
......@@ -951,25 +801,22 @@ func (rr *OPENPGPKEY) parse(c *zlexer, o, f string) *ParseError {
return nil
}
func (rr *CSYNC) parse(c *zlexer, o, f string) *ParseError {
func (rr *CSYNC) parse(c *zlexer, o string) *ParseError {
l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return nil
}
j, e := strconv.ParseUint(l.token, 10, 32)
if e != nil {
// Serial must be a number
return &ParseError{f, "bad CSYNC serial", l}
return &ParseError{"", "bad CSYNC serial", l}
}
rr.Serial = uint32(j)
c.Next() // zBlank
l, _ = c.Next()
j, e = strconv.ParseUint(l.token, 10, 16)
if e != nil {
j, e1 := strconv.ParseUint(l.token, 10, 16)
if e1 != nil {
// Serial must be a number
return &ParseError{f, "bad CSYNC flags", l}
return &ParseError{"", "bad CSYNC flags", l}
}
rr.Flags = uint16(j)
......@@ -987,38 +834,32 @@ func (rr *CSYNC) parse(c *zlexer, o, f string) *ParseError {
tokenUpper := strings.ToUpper(l.token)
if k, ok = StringToType[tokenUpper]; !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)
default:
return &ParseError{f, "bad CSYNC TypeBitMap", l}
return &ParseError{"", "bad CSYNC TypeBitMap", l}
}
l, _ = c.Next()
}
return nil
}
func (rr *SIG) parse(c *zlexer, o, f string) *ParseError {
return rr.RRSIG.parse(c, o, f)
}
func (rr *SIG) parse(c *zlexer, o string) *ParseError { return rr.RRSIG.parse(c, o) }
func (rr *RRSIG) parse(c *zlexer, o, f string) *ParseError {
func (rr *RRSIG) parse(c *zlexer, o string) *ParseError {
l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return nil
}
tokenUpper := strings.ToUpper(l.token)
if t, ok := StringToType[tokenUpper]; !ok {
if strings.HasPrefix(tokenUpper, "TYPE") {
t, ok = typeToInt(l.token)
if !ok {
return &ParseError{f, "bad RRSIG Typecovered", l}
return &ParseError{"", "bad RRSIG Typecovered", l}
}
rr.TypeCovered = t
} else {
return &ParseError{f, "bad RRSIG Typecovered", l}
return &ParseError{"", "bad RRSIG Typecovered", l}
}
} else {
rr.TypeCovered = t
......@@ -1026,25 +867,25 @@ func (rr *RRSIG) parse(c *zlexer, o, f string) *ParseError {
c.Next() // zBlank
l, _ = c.Next()
i, err := strconv.ParseUint(l.token, 10, 8)
if err != nil || l.err {
return &ParseError{f, "bad RRSIG Algorithm", l}
i, e := strconv.ParseUint(l.token, 10, 8)
if e != nil || l.err {
return &ParseError{"", "bad RRSIG Algorithm", l}
}
rr.Algorithm = uint8(i)
c.Next() // zBlank
l, _ = c.Next()
i, err = strconv.ParseUint(l.token, 10, 8)
if err != nil || l.err {
return &ParseError{f, "bad RRSIG Labels", l}
i, e1 := strconv.ParseUint(l.token, 10, 8)
if e1 != nil || l.err {
return &ParseError{"", "bad RRSIG Labels", l}
}
rr.Labels = uint8(i)
c.Next() // zBlank
l, _ = c.Next()
i, err = strconv.ParseUint(l.token, 10, 32)
if err != nil || l.err {
return &ParseError{f, "bad RRSIG OrigTtl", l}
i, e2 := strconv.ParseUint(l.token, 10, 32)
if e2 != nil || l.err {
return &ParseError{"", "bad RRSIG OrigTtl", l}
}
rr.OrigTtl = uint32(i)
......@@ -1052,11 +893,10 @@ func (rr *RRSIG) parse(c *zlexer, o, f string) *ParseError {
l, _ = c.Next()
if i, err := StringToTime(l.token); err != nil {
// Try to see if all numeric and use it as epoch
if i, err := strconv.ParseInt(l.token, 10, 64); err == nil {
// TODO(miek): error out on > MAX_UINT32, same below
if i, err := strconv.ParseUint(l.token, 10, 32); err == nil {
rr.Expiration = uint32(i)
} else {
return &ParseError{f, "bad RRSIG Expiration", l}
return &ParseError{"", "bad RRSIG Expiration", l}
}
} else {
rr.Expiration = i
......@@ -1065,10 +905,10 @@ func (rr *RRSIG) parse(c *zlexer, o, f string) *ParseError {
c.Next() // zBlank
l, _ = c.Next()
if i, err := StringToTime(l.token); err != nil {
if i, err := strconv.ParseInt(l.token, 10, 64); err == nil {
if i, err := strconv.ParseUint(l.token, 10, 32); err == nil {
rr.Inception = uint32(i)
} else {
return &ParseError{f, "bad RRSIG Inception", l}
return &ParseError{"", "bad RRSIG Inception", l}
}
} else {
rr.Inception = i
......@@ -1076,9 +916,9 @@ func (rr *RRSIG) parse(c *zlexer, o, f string) *ParseError {
c.Next() // zBlank
l, _ = c.Next()
i, err = strconv.ParseUint(l.token, 10, 16)
if err != nil || l.err {
return &ParseError{f, "bad RRSIG KeyTag", l}
i, e3 := strconv.ParseUint(l.token, 10, 16)
if e3 != nil || l.err {
return &ParseError{"", "bad RRSIG KeyTag", l}
}
rr.KeyTag = uint16(i)
......@@ -1087,29 +927,24 @@ func (rr *RRSIG) parse(c *zlexer, o, f string) *ParseError {
rr.SignerName = l.token
name, nameOk := toAbsoluteName(l.token, o)
if l.err || !nameOk {
return &ParseError{f, "bad RRSIG SignerName", l}
return &ParseError{"", "bad RRSIG SignerName", l}
}
rr.SignerName = name
s, e := endingToString(c, "bad RRSIG Signature", f)
if e != nil {
return e
s, e4 := endingToString(c, "bad RRSIG Signature")
if e4 != nil {
return e4
}
rr.Signature = s
return nil
}
func (rr *NSEC) parse(c *zlexer, o, f string) *ParseError {
func (rr *NSEC) parse(c *zlexer, o string) *ParseError {
l, _ := c.Next()
rr.NextDomain = l.token
if len(l.token) == 0 { // dynamic update rr.
return nil
}
name, nameOk := toAbsoluteName(l.token, o)
if l.err || !nameOk {
return &ParseError{f, "bad NSEC NextDomain", l}
return &ParseError{"", "bad NSEC NextDomain", l}
}
rr.NextDomain = name
......@@ -1127,47 +962,43 @@ func (rr *NSEC) parse(c *zlexer, o, f string) *ParseError {
tokenUpper := strings.ToUpper(l.token)
if k, ok = StringToType[tokenUpper]; !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)
default:
return &ParseError{f, "bad NSEC TypeBitMap", l}
return &ParseError{"", "bad NSEC TypeBitMap", l}
}
l, _ = c.Next()
}
return nil
}
func (rr *NSEC3) parse(c *zlexer, o, f string) *ParseError {
func (rr *NSEC3) parse(c *zlexer, o string) *ParseError {
l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return nil
}
i, e := strconv.ParseUint(l.token, 10, 8)
if e != nil || l.err {
return &ParseError{f, "bad NSEC3 Hash", l}
return &ParseError{"", "bad NSEC3 Hash", l}
}
rr.Hash = uint8(i)
c.Next() // zBlank
l, _ = c.Next()
i, e = strconv.ParseUint(l.token, 10, 8)
if e != nil || l.err {
return &ParseError{f, "bad NSEC3 Flags", l}
i, e1 := strconv.ParseUint(l.token, 10, 8)
if e1 != nil || l.err {
return &ParseError{"", "bad NSEC3 Flags", l}
}
rr.Flags = uint8(i)
c.Next() // zBlank
l, _ = c.Next()
i, e = strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err {
return &ParseError{f, "bad NSEC3 Iterations", l}
i, e2 := strconv.ParseUint(l.token, 10, 16)
if e2 != nil || l.err {
return &ParseError{"", "bad NSEC3 Iterations", l}
}
rr.Iterations = uint16(i)
c.Next()
l, _ = c.Next()
if len(l.token) == 0 || l.err {
return &ParseError{f, "bad NSEC3 Salt", l}
return &ParseError{"", "bad NSEC3 Salt", l}
}
if l.token != "-" {
rr.SaltLength = uint8(len(l.token)) / 2
......@@ -1177,7 +1008,7 @@ func (rr *NSEC3) parse(c *zlexer, o, f string) *ParseError {
c.Next()
l, _ = c.Next()
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.NextDomain = l.token
......@@ -1196,60 +1027,52 @@ func (rr *NSEC3) parse(c *zlexer, o, f string) *ParseError {
tokenUpper := strings.ToUpper(l.token)
if k, ok = StringToType[tokenUpper]; !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)
default:
return &ParseError{f, "bad NSEC3 TypeBitMap", l}
return &ParseError{"", "bad NSEC3 TypeBitMap", l}
}
l, _ = c.Next()
}
return nil
}
func (rr *NSEC3PARAM) parse(c *zlexer, o, f string) *ParseError {
func (rr *NSEC3PARAM) parse(c *zlexer, o string) *ParseError {
l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return slurpRemainder(c, f)
}
i, e := strconv.ParseUint(l.token, 10, 8)
if e != nil || l.err {
return &ParseError{f, "bad NSEC3PARAM Hash", l}
return &ParseError{"", "bad NSEC3PARAM Hash", l}
}
rr.Hash = uint8(i)
c.Next() // zBlank
l, _ = c.Next()
i, e = strconv.ParseUint(l.token, 10, 8)
if e != nil || l.err {
return &ParseError{f, "bad NSEC3PARAM Flags", l}
i, e1 := strconv.ParseUint(l.token, 10, 8)
if e1 != nil || l.err {
return &ParseError{"", "bad NSEC3PARAM Flags", l}
}
rr.Flags = uint8(i)
c.Next() // zBlank
l, _ = c.Next()
i, e = strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err {
return &ParseError{f, "bad NSEC3PARAM Iterations", l}
i, e2 := strconv.ParseUint(l.token, 10, 16)
if e2 != nil || l.err {
return &ParseError{"", "bad NSEC3PARAM Iterations", l}
}
rr.Iterations = uint16(i)
c.Next()
l, _ = c.Next()
if l.token != "-" {
rr.SaltLength = uint8(len(l.token))
rr.SaltLength = uint8(len(l.token) / 2)
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()
if len(l.token) == 0 { // dynamic update rr.
return slurpRemainder(c, f)
}
if len(l.token) != 17 || l.err {
return &ParseError{f, "bad EUI48 Address", l}
return &ParseError{"", "bad EUI48 Address", l}
}
addr := make([]byte, 12)
dash := 0
......@@ -1258,7 +1081,7 @@ func (rr *EUI48) parse(c *zlexer, o, f string) *ParseError {
addr[i+1] = l.token[i+1+dash]
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]
......@@ -1266,20 +1089,16 @@ func (rr *EUI48) parse(c *zlexer, o, f string) *ParseError {
i, e := strconv.ParseUint(string(addr), 16, 48)
if e != nil {
return &ParseError{f, "bad EUI48 Address", l}
return &ParseError{"", "bad EUI48 Address", l}
}
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()
if len(l.token) == 0 { // dynamic update rr.
return slurpRemainder(c, f)
}
if len(l.token) != 23 || l.err {
return &ParseError{f, "bad EUI64 Address", l}
return &ParseError{"", "bad EUI64 Address", l}
}
addr := make([]byte, 16)
dash := 0
......@@ -1288,7 +1107,7 @@ func (rr *EUI64) parse(c *zlexer, o, f string) *ParseError {
addr[i+1] = l.token[i+1+dash]
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]
......@@ -1296,119 +1115,102 @@ func (rr *EUI64) parse(c *zlexer, o, f string) *ParseError {
i, e := strconv.ParseUint(string(addr), 16, 64)
if e != nil {
return &ParseError{f, "bad EUI68 Address", l}
return &ParseError{"", "bad EUI68 Address", l}
}
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()
if len(l.token) == 0 { // dynamic update rr.
return nil
}
i, e := strconv.ParseUint(l.token, 10, 8)
if e != nil || l.err {
return &ParseError{f, "bad SSHFP Algorithm", l}
return &ParseError{"", "bad SSHFP Algorithm", l}
}
rr.Algorithm = uint8(i)
c.Next() // zBlank
l, _ = c.Next()
i, e = strconv.ParseUint(l.token, 10, 8)
if e != nil || l.err {
return &ParseError{f, "bad SSHFP Type", l}
i, e1 := strconv.ParseUint(l.token, 10, 8)
if e1 != nil || l.err {
return &ParseError{"", "bad SSHFP Type", l}
}
rr.Type = uint8(i)
c.Next() // zBlank
s, e1 := endingToString(c, "bad SSHFP Fingerprint", f)
if e1 != nil {
return e1
s, e2 := endingToString(c, "bad SSHFP Fingerprint")
if e2 != nil {
return e2
}
rr.FingerPrint = s
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()
if len(l.token) == 0 { // dynamic update rr.
return nil
}
i, e := strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err {
return &ParseError{f, "bad " + typ + " Flags", l}
return &ParseError{"", "bad " + typ + " Flags", l}
}
rr.Flags = uint16(i)
c.Next() // zBlank
l, _ = c.Next() // zString
i, e = strconv.ParseUint(l.token, 10, 8)
if e != nil || l.err {
return &ParseError{f, "bad " + typ + " Protocol", l}
i, e1 := strconv.ParseUint(l.token, 10, 8)
if e1 != nil || l.err {
return &ParseError{"", "bad " + typ + " Protocol", l}
}
rr.Protocol = uint8(i)
c.Next() // zBlank
l, _ = c.Next() // zString
i, e = strconv.ParseUint(l.token, 10, 8)
if e != nil || l.err {
return &ParseError{f, "bad " + typ + " Algorithm", l}
i, e2 := strconv.ParseUint(l.token, 10, 8)
if e2 != nil || l.err {
return &ParseError{"", "bad " + typ + " Algorithm", l}
}
rr.Algorithm = uint8(i)
s, e1 := endingToString(c, "bad "+typ+" PublicKey", f)
if e1 != nil {
return e1
s, e3 := endingToString(c, "bad "+typ+" PublicKey")
if e3 != nil {
return e3
}
rr.PublicKey = s
return nil
}
func (rr *DNSKEY) parse(c *zlexer, o, f string) *ParseError {
return rr.parseDNSKEY(c, o, f, "DNSKEY")
}
func (rr *KEY) parse(c *zlexer, o, f string) *ParseError {
return rr.parseDNSKEY(c, o, f, "KEY")
}
func (rr *CDNSKEY) parse(c *zlexer, o, f string) *ParseError {
return rr.parseDNSKEY(c, o, f, "CDNSKEY")
}
func (rr *DNSKEY) parse(c *zlexer, o string) *ParseError { return rr.parseDNSKEY(c, o, "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 *DLV) parse(c *zlexer, o string) *ParseError { return rr.parseDS(c, o, "DLV") }
func (rr *CDS) parse(c *zlexer, o string) *ParseError { return rr.parseDS(c, o, "CDS") }
func (rr *RKEY) parse(c *zlexer, o, f string) *ParseError {
func (rr *RKEY) parse(c *zlexer, o string) *ParseError {
l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return nil
}
i, e := strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err {
return &ParseError{f, "bad RKEY Flags", l}
return &ParseError{"", "bad RKEY Flags", l}
}
rr.Flags = uint16(i)
c.Next() // zBlank
l, _ = c.Next() // zString
i, e = strconv.ParseUint(l.token, 10, 8)
if e != nil || l.err {
return &ParseError{f, "bad RKEY Protocol", l}
i, e1 := strconv.ParseUint(l.token, 10, 8)
if e1 != nil || l.err {
return &ParseError{"", "bad RKEY Protocol", l}
}
rr.Protocol = uint8(i)
c.Next() // zBlank
l, _ = c.Next() // zString
i, e = strconv.ParseUint(l.token, 10, 8)
if e != nil || l.err {
return &ParseError{f, "bad RKEY Algorithm", l}
i, e2 := strconv.ParseUint(l.token, 10, 8)
if e2 != nil || l.err {
return &ParseError{"", "bad RKEY Algorithm", l}
}
rr.Algorithm = uint8(i)
s, e1 := endingToString(c, "bad RKEY PublicKey", f)
if e1 != nil {
return e1
s, e3 := endingToString(c, "bad RKEY PublicKey")
if e3 != nil {
return e3
}
rr.PublicKey = s
return nil
}
func (rr *EID) parse(c *zlexer, o, f string) *ParseError {
s, e := endingToString(c, "bad EID Endpoint", f)
func (rr *EID) parse(c *zlexer, o string) *ParseError {
s, e := endingToString(c, "bad EID Endpoint")
if e != nil {
return e
}
......@@ -1416,8 +1218,8 @@ func (rr *EID) parse(c *zlexer, o, f string) *ParseError {
return nil
}
func (rr *NIMLOC) parse(c *zlexer, o, f string) *ParseError {
s, e := endingToString(c, "bad NIMLOC Locator", f)
func (rr *NIMLOC) parse(c *zlexer, o string) *ParseError {
s, e := endingToString(c, "bad NIMLOC Locator")
if e != nil {
return e
}
......@@ -1425,52 +1227,44 @@ func (rr *NIMLOC) parse(c *zlexer, o, f string) *ParseError {
return nil
}
func (rr *GPOS) parse(c *zlexer, o, f string) *ParseError {
func (rr *GPOS) parse(c *zlexer, o string) *ParseError {
l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return slurpRemainder(c, f)
}
_, e := strconv.ParseFloat(l.token, 64)
if e != nil || l.err {
return &ParseError{f, "bad GPOS Longitude", l}
return &ParseError{"", "bad GPOS Longitude", l}
}
rr.Longitude = l.token
c.Next() // zBlank
l, _ = c.Next()
_, e = strconv.ParseFloat(l.token, 64)
if e != nil || l.err {
return &ParseError{f, "bad GPOS Latitude", l}
_, e1 := strconv.ParseFloat(l.token, 64)
if e1 != nil || l.err {
return &ParseError{"", "bad GPOS Latitude", l}
}
rr.Latitude = l.token
c.Next() // zBlank
l, _ = c.Next()
_, e = strconv.ParseFloat(l.token, 64)
if e != nil || l.err {
return &ParseError{f, "bad GPOS Altitude", l}
_, e2 := strconv.ParseFloat(l.token, 64)
if e2 != nil || l.err {
return &ParseError{"", "bad GPOS Altitude", l}
}
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()
if len(l.token) == 0 { // dynamic update rr.
return nil
}
i, e := strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err {
return &ParseError{f, "bad " + typ + " KeyTag", l}
return &ParseError{"", "bad " + typ + " KeyTag", l}
}
rr.KeyTag = uint16(i)
c.Next() // zBlank
l, _ = c.Next()
if i, e = strconv.ParseUint(l.token, 10, 8); e != nil {
if i, err := strconv.ParseUint(l.token, 10, 8); err != nil {
tokenUpper := strings.ToUpper(l.token)
i, ok := StringToAlgorithm[tokenUpper]
if !ok || l.err {
return &ParseError{f, "bad " + typ + " Algorithm", l}
return &ParseError{"", "bad " + typ + " Algorithm", l}
}
rr.Algorithm = i
} else {
......@@ -1478,49 +1272,33 @@ func (rr *DS) parseDS(c *zlexer, o, f, typ string) *ParseError {
}
c.Next() // zBlank
l, _ = c.Next()
i, e = strconv.ParseUint(l.token, 10, 8)
if e != nil || l.err {
return &ParseError{f, "bad " + typ + " DigestType", l}
i, e1 := strconv.ParseUint(l.token, 10, 8)
if e1 != nil || l.err {
return &ParseError{"", "bad " + typ + " DigestType", l}
}
rr.DigestType = uint8(i)
s, e1 := endingToString(c, "bad "+typ+" Digest", f)
if e1 != nil {
return e1
s, e2 := endingToString(c, "bad "+typ+" Digest")
if e2 != nil {
return e2
}
rr.Digest = s
return nil
}
func (rr *DS) parse(c *zlexer, o, f 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 {
func (rr *TA) parse(c *zlexer, o string) *ParseError {
l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return nil
}
i, e := strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err {
return &ParseError{f, "bad TA KeyTag", l}
return &ParseError{"", "bad TA KeyTag", l}
}
rr.KeyTag = uint16(i)
c.Next() // zBlank
l, _ = c.Next()
if i, e := strconv.ParseUint(l.token, 10, 8); e != nil {
if i, err := strconv.ParseUint(l.token, 10, 8); err != nil {
tokenUpper := strings.ToUpper(l.token)
i, ok := StringToAlgorithm[tokenUpper]
if !ok || l.err {
return &ParseError{f, "bad TA Algorithm", l}
return &ParseError{"", "bad TA Algorithm", l}
}
rr.Algorithm = i
} else {
......@@ -1528,113 +1306,105 @@ func (rr *TA) parse(c *zlexer, o, f string) *ParseError {
}
c.Next() // zBlank
l, _ = c.Next()
i, e = strconv.ParseUint(l.token, 10, 8)
if e != nil || l.err {
return &ParseError{f, "bad TA DigestType", l}
i, e1 := strconv.ParseUint(l.token, 10, 8)
if e1 != nil || l.err {
return &ParseError{"", "bad TA DigestType", l}
}
rr.DigestType = uint8(i)
s, err := endingToString(c, "bad TA Digest", f)
if err != nil {
return err
s, e2 := endingToString(c, "bad TA Digest")
if e2 != nil {
return e2
}
rr.Digest = s
return nil
}
func (rr *TLSA) parse(c *zlexer, o, f string) *ParseError {
func (rr *TLSA) parse(c *zlexer, o string) *ParseError {
l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return nil
}
i, e := strconv.ParseUint(l.token, 10, 8)
if e != nil || l.err {
return &ParseError{f, "bad TLSA Usage", l}
return &ParseError{"", "bad TLSA Usage", l}
}
rr.Usage = uint8(i)
c.Next() // zBlank
l, _ = c.Next()
i, e = strconv.ParseUint(l.token, 10, 8)
if e != nil || l.err {
return &ParseError{f, "bad TLSA Selector", l}
i, e1 := strconv.ParseUint(l.token, 10, 8)
if e1 != nil || l.err {
return &ParseError{"", "bad TLSA Selector", l}
}
rr.Selector = uint8(i)
c.Next() // zBlank
l, _ = c.Next()
i, e = strconv.ParseUint(l.token, 10, 8)
if e != nil || l.err {
return &ParseError{f, "bad TLSA MatchingType", l}
i, e2 := strconv.ParseUint(l.token, 10, 8)
if e2 != nil || l.err {
return &ParseError{"", "bad TLSA MatchingType", l}
}
rr.MatchingType = uint8(i)
// So this needs be e2 (i.e. different than e), because...??t
s, e2 := endingToString(c, "bad TLSA Certificate", f)
if e2 != nil {
return e2
s, e3 := endingToString(c, "bad TLSA Certificate")
if e3 != nil {
return e3
}
rr.Certificate = s
return nil
}
func (rr *SMIMEA) parse(c *zlexer, o, f string) *ParseError {
func (rr *SMIMEA) parse(c *zlexer, o string) *ParseError {
l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return nil
}
i, e := strconv.ParseUint(l.token, 10, 8)
if e != nil || l.err {
return &ParseError{f, "bad SMIMEA Usage", l}
return &ParseError{"", "bad SMIMEA Usage", l}
}
rr.Usage = uint8(i)
c.Next() // zBlank
l, _ = c.Next()
i, e = strconv.ParseUint(l.token, 10, 8)
if e != nil || l.err {
return &ParseError{f, "bad SMIMEA Selector", l}
i, e1 := strconv.ParseUint(l.token, 10, 8)
if e1 != nil || l.err {
return &ParseError{"", "bad SMIMEA Selector", l}
}
rr.Selector = uint8(i)
c.Next() // zBlank
l, _ = c.Next()
i, e = strconv.ParseUint(l.token, 10, 8)
if e != nil || l.err {
return &ParseError{f, "bad SMIMEA MatchingType", l}
i, e2 := strconv.ParseUint(l.token, 10, 8)
if e2 != nil || l.err {
return &ParseError{"", "bad SMIMEA MatchingType", l}
}
rr.MatchingType = uint8(i)
// So this needs be e2 (i.e. different than e), because...??t
s, e2 := endingToString(c, "bad SMIMEA Certificate", f)
if e2 != nil {
return e2
s, e3 := endingToString(c, "bad SMIMEA Certificate")
if e3 != nil {
return e3
}
rr.Certificate = s
return nil
}
func (rr *RFC3597) parse(c *zlexer, o, f string) *ParseError {
func (rr *RFC3597) parse(c *zlexer, o string) *ParseError {
l, _ := c.Next()
if l.token != "\\#" {
return &ParseError{f, "bad RFC3597 Rdata", l}
return &ParseError{"", "bad RFC3597 Rdata", l}
}
c.Next() // zBlank
l, _ = c.Next()
rdlength, e := strconv.Atoi(l.token)
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 {
return e1
}
if rdlength*2 != len(s) {
return &ParseError{f, "bad RFC3597 Rdata", l}
return &ParseError{"", "bad RFC3597 Rdata", l}
}
rr.Rdata = s
return nil
}
func (rr *SPF) parse(c *zlexer, o, f string) *ParseError {
s, e := endingToTxtSlice(c, "bad SPF Txt", f)
func (rr *SPF) parse(c *zlexer, o string) *ParseError {
s, e := endingToTxtSlice(c, "bad SPF Txt")
if e != nil {
return e
}
......@@ -1642,8 +1412,8 @@ func (rr *SPF) parse(c *zlexer, o, f string) *ParseError {
return nil
}
func (rr *AVC) parse(c *zlexer, o, f string) *ParseError {
s, e := endingToTxtSlice(c, "bad AVC Txt", f)
func (rr *AVC) parse(c *zlexer, o string) *ParseError {
s, e := endingToTxtSlice(c, "bad AVC Txt")
if e != nil {
return e
}
......@@ -1651,9 +1421,9 @@ func (rr *AVC) parse(c *zlexer, o, f string) *ParseError {
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
s, e := endingToTxtSlice(c, "bad TXT Txt", f)
s, e := endingToTxtSlice(c, "bad TXT Txt")
if e != nil {
return e
}
......@@ -1662,8 +1432,8 @@ func (rr *TXT) parse(c *zlexer, o, f string) *ParseError {
}
// identical to setTXT
func (rr *NINFO) parse(c *zlexer, o, f string) *ParseError {
s, e := endingToTxtSlice(c, "bad NINFO ZSData", f)
func (rr *NINFO) parse(c *zlexer, o string) *ParseError {
s, e := endingToTxtSlice(c, "bad NINFO ZSData")
if e != nil {
return e
}
......@@ -1671,40 +1441,36 @@ func (rr *NINFO) parse(c *zlexer, o, f string) *ParseError {
return nil
}
func (rr *URI) parse(c *zlexer, o, f string) *ParseError {
func (rr *URI) parse(c *zlexer, o string) *ParseError {
l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return nil
}
i, e := strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err {
return &ParseError{f, "bad URI Priority", l}
return &ParseError{"", "bad URI Priority", l}
}
rr.Priority = uint16(i)
c.Next() // zBlank
l, _ = c.Next()
i, e = strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err {
return &ParseError{f, "bad URI Weight", l}
i, e1 := strconv.ParseUint(l.token, 10, 16)
if e1 != nil || l.err {
return &ParseError{"", "bad URI Weight", l}
}
rr.Weight = uint16(i)
c.Next() // zBlank
s, err := endingToTxtSlice(c, "bad URI Target", f)
if err != nil {
return err
s, e2 := endingToTxtSlice(c, "bad URI Target")
if e2 != nil {
return e2
}
if len(s) != 1 {
return &ParseError{f, "bad URI Target", l}
return &ParseError{"", "bad URI Target", l}
}
rr.Target = s[0]
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!
s, e := endingToString(c, "bad DHCID Digest", f)
s, e := endingToString(c, "bad DHCID Digest")
if e != nil {
return e
}
......@@ -1712,56 +1478,44 @@ func (rr *DHCID) parse(c *zlexer, o, f string) *ParseError {
return nil
}
func (rr *NID) parse(c *zlexer, o, f string) *ParseError {
func (rr *NID) parse(c *zlexer, o string) *ParseError {
l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return slurpRemainder(c, f)
}
i, e := strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err {
return &ParseError{f, "bad NID Preference", l}
return &ParseError{"", "bad NID Preference", l}
}
rr.Preference = uint16(i)
c.Next() // zBlank
l, _ = c.Next() // zString
u, err := stringToNodeID(l)
if err != nil || l.err {
return err
u, e1 := stringToNodeID(l)
if e1 != nil || l.err {
return e1
}
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()
if len(l.token) == 0 { // dynamic update rr.
return slurpRemainder(c, f)
}
i, e := strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err {
return &ParseError{f, "bad L32 Preference", l}
return &ParseError{"", "bad L32 Preference", l}
}
rr.Preference = uint16(i)
c.Next() // zBlank
l, _ = c.Next() // zString
rr.Locator32 = net.ParseIP(l.token)
if rr.Locator32 == nil || l.err {
return &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()
if len(l.token) == 0 { // dynamic update rr.
return slurpRemainder(c, f)
}
i, e := strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err {
return &ParseError{f, "bad LP Preference", l}
return &ParseError{"", "bad LP Preference", l}
}
rr.Preference = uint16(i)
......@@ -1770,64 +1524,51 @@ func (rr *LP) parse(c *zlexer, o, f string) *ParseError {
rr.Fqdn = l.token
name, nameOk := toAbsoluteName(l.token, o)
if l.err || !nameOk {
return &ParseError{f, "bad LP Fqdn", l}
return &ParseError{"", "bad LP Fqdn", l}
}
rr.Fqdn = name
return slurpRemainder(c, f)
return slurpRemainder(c)
}
func (rr *L64) parse(c *zlexer, o, f string) *ParseError {
func (rr *L64) parse(c *zlexer, o string) *ParseError {
l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return slurpRemainder(c, f)
}
i, e := strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err {
return &ParseError{f, "bad L64 Preference", l}
return &ParseError{"", "bad L64 Preference", l}
}
rr.Preference = uint16(i)
c.Next() // zBlank
l, _ = c.Next() // zString
u, err := stringToNodeID(l)
if err != nil || l.err {
return err
u, e1 := stringToNodeID(l)
if e1 != nil || l.err {
return e1
}
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()
if len(l.token) == 0 { // dynamic update rr.
return slurpRemainder(c, f)
}
i, e := strconv.ParseUint(l.token, 10, 32)
if e != nil || l.err {
return &ParseError{f, "bad UID Uid", l}
return &ParseError{"", "bad UID Uid", l}
}
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()
if len(l.token) == 0 { // dynamic update rr.
return slurpRemainder(c, f)
}
i, e := strconv.ParseUint(l.token, 10, 32)
if e != nil || l.err {
return &ParseError{f, "bad GID Gid", l}
return &ParseError{"", "bad GID Gid", l}
}
rr.Gid = uint32(i)
return slurpRemainder(c, f)
return slurpRemainder(c)
}
func (rr *UINFO) parse(c *zlexer, o, f string) *ParseError {
s, e := endingToTxtSlice(c, "bad UINFO Uinfo", f)
func (rr *UINFO) parse(c *zlexer, o string) *ParseError {
s, e := endingToTxtSlice(c, "bad UINFO Uinfo")
if e != nil {
return e
}
......@@ -1838,15 +1579,11 @@ func (rr *UINFO) parse(c *zlexer, o, f string) *ParseError {
return nil
}
func (rr *PX) parse(c *zlexer, o, f string) *ParseError {
func (rr *PX) parse(c *zlexer, o string) *ParseError {
l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return slurpRemainder(c, f)
}
i, e := strconv.ParseUint(l.token, 10, 16)
if e != nil || l.err {
return &ParseError{f, "bad PX Preference", l}
return &ParseError{"", "bad PX Preference", l}
}
rr.Preference = uint16(i)
......@@ -1855,7 +1592,7 @@ func (rr *PX) parse(c *zlexer, o, f string) *ParseError {
rr.Map822 = l.token
map822, map822Ok := toAbsoluteName(l.token, o)
if l.err || !map822Ok {
return &ParseError{f, "bad PX Map822", l}
return &ParseError{"", "bad PX Map822", l}
}
rr.Map822 = map822
......@@ -1864,82 +1601,142 @@ func (rr *PX) parse(c *zlexer, o, f string) *ParseError {
rr.Mapx400 = l.token
mapx400, mapx400Ok := toAbsoluteName(l.token, o)
if l.err || !mapx400Ok {
return &ParseError{f, "bad PX Mapx400", l}
return &ParseError{"", "bad PX Mapx400", l}
}
rr.Mapx400 = mapx400
return slurpRemainder(c, f)
return slurpRemainder(c)
}
func (rr *CAA) parse(c *zlexer, o, f string) *ParseError {
func (rr *CAA) parse(c *zlexer, o string) *ParseError {
l, _ := c.Next()
if len(l.token) == 0 { // dynamic update rr.
return nil
}
i, err := strconv.ParseUint(l.token, 10, 8)
if err != nil || l.err {
return &ParseError{f, "bad CAA Flag", l}
i, e := strconv.ParseUint(l.token, 10, 8)
if e != nil || l.err {
return &ParseError{"", "bad CAA Flag", l}
}
rr.Flag = uint8(i)
c.Next() // zBlank
l, _ = c.Next() // zString
if l.value != zString {
return &ParseError{f, "bad CAA Tag", l}
return &ParseError{"", "bad CAA Tag", l}
}
rr.Tag = l.token
c.Next() // zBlank
s, e := endingToTxtSlice(c, "bad CAA Value", f)
if e != nil {
return e
s, e1 := endingToTxtSlice(c, "bad CAA Value")
if e1 != nil {
return e1
}
if len(s) != 1 {
return &ParseError{f, "bad CAA Value", l}
return &ParseError{"", "bad CAA Value", l}
}
rr.Value = s[0]
return nil
}
func (rr *TKEY) parse(c *zlexer, o, f string) *ParseError {
func (rr *TKEY) parse(c *zlexer, o string) *ParseError {
l, _ := c.Next()
// Algorithm
if l.value != zString {
return &ParseError{f, "bad TKEY algorithm", l}
return &ParseError{"", "bad TKEY algorithm", l}
}
rr.Algorithm = l.token
c.Next() // zBlank
// Get the key length and key values
l, _ = c.Next()
i, err := strconv.ParseUint(l.token, 10, 8)
if err != nil || l.err {
return &ParseError{f, "bad TKEY key length", l}
i, e := strconv.ParseUint(l.token, 10, 8)
if e != nil || l.err {
return &ParseError{"", "bad TKEY key length", l}
}
rr.KeySize = uint16(i)
c.Next() // zBlank
l, _ = c.Next()
if l.value != zString {
return &ParseError{f, "bad TKEY key", l}
return &ParseError{"", "bad TKEY key", l}
}
rr.Key = l.token
c.Next() // zBlank
// Get the otherdata length and string data
l, _ = c.Next()
i, err = strconv.ParseUint(l.token, 10, 8)
if err != nil || l.err {
return &ParseError{f, "bad TKEY otherdata length", l}
i, e1 := strconv.ParseUint(l.token, 10, 8)
if e1 != nil || l.err {
return &ParseError{"", "bad TKEY otherdata length", l}
}
rr.OtherLen = uint16(i)
c.Next() // zBlank
l, _ = c.Next()
if l.value != zString {
return &ParseError{f, "bad TKEY otherday", l}
return &ParseError{"", "bad TKEY otherday", l}
}
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
}
package dns
import (
"strings"
"sync"
)
......@@ -36,33 +35,9 @@ func (mux *ServeMux) match(q string, t uint16) Handler {
return nil
}
var handler Handler
// 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
}
q = CanonicalName(q)
var handler Handler
for off, end := 0, false; !end; off, end = NextLabel(q, off) {
if h, ok := mux.z[q[off:]]; ok {
if t != TypeDS {
......@@ -90,7 +65,7 @@ func (mux *ServeMux) Handle(pattern string, handler Handler) {
if mux.z == nil {
mux.z = make(map[string]Handler)
}
mux.z[Fqdn(pattern)] = handler
mux.z[CanonicalName(pattern)] = handler
mux.m.Unlock()
}
......@@ -105,7 +80,7 @@ func (mux *ServeMux) HandleRemove(pattern string) {
panic("dns: invalid pattern " + pattern)
}
mux.m.Lock()
delete(mux.z, Fqdn(pattern))
delete(mux.z, CanonicalName(pattern))
mux.m.Unlock()
}
......@@ -116,7 +91,7 @@ func (mux *ServeMux) HandleRemove(pattern string) {
// are redirected to the parent zone (if that is also registered),
// 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
func (mux *ServeMux) ServeDNS(w ResponseWriter, req *Msg) {
var h Handler
......@@ -127,7 +102,7 @@ func (mux *ServeMux) ServeDNS(w ResponseWriter, req *Msg) {
if h != nil {
h.ServeDNS(w, req)
} else {
HandleFailed(w, req)
handleRefused(w, req)
}
}
......
......@@ -72,13 +72,22 @@ type response struct {
tsigStatus error
tsigRequestMAC string
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
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
}
// 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.
// Deprecated: This function is going away.
func HandleFailed(w ResponseWriter, r *Msg) {
m := new(Msg)
m.SetRcode(r, RcodeServerFailure)
......@@ -139,12 +148,24 @@ type Reader interface {
ReadUDP(conn *net.UDPConn, timeout time.Duration) ([]byte, *SessionUDP, error)
}
// defaultReader is an adapter for the Server struct that implements the Reader interface
// using the readTCP and readUDP func of the embedded Server.
// PacketConnReader is an optional interface that Readers can implement to support using generic net.PacketConns.
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 {
*Server
}
var _ PacketConnReader = defaultReader{}
func (dr defaultReader) ReadTCP(conn net.Conn, timeout time.Duration) ([]byte, error) {
return dr.readTCP(conn, timeout)
}
......@@ -153,8 +174,14 @@ func (dr defaultReader) ReadUDP(conn *net.UDPConn, timeout time.Duration) ([]byt
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.
// 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
// DecorateWriter is a decorator hook for extending or supplanting the functionality of a Writer.
......@@ -317,24 +344,22 @@ func (srv *Server) ActivateAndServe() error {
srv.init()
pConn := srv.PacketConn
l := srv.Listener
if pConn != nil {
if srv.PacketConn != nil {
// Check PacketConn interface's type is valid and value
// 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 {
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
unlock()
return srv.serveTCP(l)
return srv.serveTCP(srv.Listener)
}
return &Error{err: "bad listeners"}
}
......@@ -438,18 +463,24 @@ func (srv *Server) serveTCP(l net.Listener) error {
}
// 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()
if srv.NotifyStartedFunc != nil {
srv.NotifyStartedFunc()
}
reader := Reader(defaultReader{srv})
if srv.DecorateReader != nil {
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
defer func() {
wg.Wait()
......@@ -459,7 +490,17 @@ func (srv *Server) serveUDP(l *net.UDPConn) error {
rtimeout := srv.getReadTimeout()
// deadline is not used here
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 !srv.isStarted() {
return nil
......@@ -476,7 +517,7 @@ func (srv *Server) serveUDP(l *net.UDPConn) error {
continue
}
wg.Add(1)
go srv.serveUDPPacket(&wg, m, l, s)
go srv.serveUDPPacket(&wg, m, l, sUDP, sPC)
}
return nil
......@@ -538,8 +579,8 @@ func (srv *Server) serveTCPConn(wg *sync.WaitGroup, rw net.Conn) {
}
// Serve a new UDP request.
func (srv *Server) serveUDPPacket(wg *sync.WaitGroup, m []byte, u *net.UDPConn, s *SessionUDP) {
w := &response{tsigSecret: srv.TsigSecret, udp: u, udpSession: s}
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: udpSession, pcSession: pcSession}
if srv.DecorateWriter != nil {
w.writer = srv.DecorateWriter(w)
} else {
......@@ -560,26 +601,32 @@ func (srv *Server) serveDNS(m []byte, w *response) {
req := new(Msg)
req.setHdr(dh)
switch srv.MsgAcceptFunc(dh) {
switch action := srv.MsgAcceptFunc(dh); action {
case MsgAccept:
if req.unpack(dh, m, off) == nil {
break
}
fallthrough
case MsgReject:
case MsgReject, MsgRejectNotImplemented:
opcode := req.Opcode
req.SetRcodeFormatError(req)
req.Zero = false
if action == MsgRejectNotImplemented {
req.Opcode = opcode
req.Rcode = RcodeNotImplemented
}
// Are we allowed to delete any OPT records here?
req.Ns, req.Answer, req.Extra = nil, nil, nil
w.WriteMsg(req)
fallthrough
case MsgIgnore:
if w.udp != nil && cap(m) == srv.UDPSize {
srv.udpPool.Put(m[:srv.UDPSize])
}
return
case MsgIgnore:
return
}
......@@ -645,6 +692,24 @@ func (srv *Server) readUDP(conn *net.UDPConn, timeout time.Duration) ([]byte, *S
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.
func (w *response) WriteMsg(m *Msg) (err error) {
if w.closed {
......@@ -678,7 +743,10 @@ func (w *response) Write(m []byte) (int, error) {
switch {
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:
if len(m) > MaxMsgSize {
return 0, &Error{err: "message too large"}
......@@ -711,10 +779,12 @@ func (w *response) RemoteAddr() net.Addr {
switch {
case w.udpSession != nil:
return w.udpSession.RemoteAddr()
case w.pcSession != nil:
return w.pcSession
case w.tcp != nil:
return w.tcp.RemoteAddr()
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
import (
"crypto"
"crypto/dsa"
"crypto/ecdsa"
"crypto/rsa"
"encoding/binary"
......@@ -85,7 +84,7 @@ func (rr *SIG) Verify(k *KEY, buf []byte) error {
var hash crypto.Hash
switch rr.Algorithm {
case DSA, RSASHA1:
case RSASHA1:
hash = crypto.SHA1
case RSASHA256, ECDSAP256SHA256:
hash = crypto.SHA256
......@@ -178,17 +177,6 @@ func (rr *SIG) Verify(k *KEY, buf []byte) error {
hashed := hasher.Sum(nil)
sig := buf[sigend:]
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:
pk := k.publicKeyRSA()
if pk != nil {
......