Fix client side TSIG
Redesign of TSIG. Validation is on the TOOD - this can be done in the same way as in the server.
This commit is contained in:
parent
172c89675c
commit
3232814d1b
|
@ -6,15 +6,13 @@ need to be fixed.
|
||||||
* Speed, we can always go faster. A simple reflect server now hits 35/45K qps
|
* Speed, we can always go faster. A simple reflect server now hits 35/45K qps
|
||||||
* go test; only works correct on my machine
|
* go test; only works correct on my machine
|
||||||
* Add handy zone data structure (r/b tree)? Or not...
|
* Add handy zone data structure (r/b tree)? Or not...
|
||||||
* Use the Exchange structure to deal with errors when resolving, esp. Timeout
|
|
||||||
* Add tsig check in 'q'?
|
|
||||||
* Tsig is handled in the library, api for querying tsig status
|
|
||||||
* Query source address?
|
* Query source address?
|
||||||
|
|
||||||
* NSECx bitmap length
|
* NSECx bitmap length
|
||||||
array of 256 block lens set to 0. scan RRs, save highest RR / 8 in
|
array of 256 block lens set to 0. scan RRs, save highest RR / 8 in
|
||||||
each block. len is 2 * # non-0 blocks + sum block len
|
each block. len is 2 * # non-0 blocks + sum block len
|
||||||
|
We now allocate 32 bytes for each nsec3 seen
|
||||||
|
|
||||||
## Examples to add
|
## Examples to add
|
||||||
|
|
||||||
* Nameserver, with a small zone, 1 KSK and online signing;
|
* Nameserver, with a small zone, 1 KSK and online signing;
|
||||||
|
|
26
client.go
26
client.go
|
@ -39,7 +39,7 @@ type reply struct {
|
||||||
conn net.Conn
|
conn net.Conn
|
||||||
tsigRequestMAC string
|
tsigRequestMAC string
|
||||||
tsigTimersOnly bool
|
tsigTimersOnly bool
|
||||||
tsigStatus int
|
tsigStatus int
|
||||||
}
|
}
|
||||||
|
|
||||||
// A Request is a incoming message from a Client.
|
// A Request is a incoming message from a Client.
|
||||||
|
@ -150,6 +150,7 @@ func NewClient() *Client {
|
||||||
c.QueryChan = DefaultQueryChan
|
c.QueryChan = DefaultQueryChan
|
||||||
c.ReadTimeout = 2 * 1e9
|
c.ReadTimeout = 2 * 1e9
|
||||||
c.WriteTimeout = 2 * 1e9
|
c.WriteTimeout = 2 * 1e9
|
||||||
|
c.TsigSecret = make(map[string]string)
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -382,25 +383,18 @@ func (w *reply) readClient(p []byte) (n int, err error) {
|
||||||
// signature is calculated.
|
// signature is calculated.
|
||||||
func (w *reply) Send(m *Msg) error {
|
func (w *reply) Send(m *Msg) error {
|
||||||
if m.IsTsig() {
|
if m.IsTsig() {
|
||||||
secret := m.Extra[len(m.Extra)-1].(*RR_TSIG).Hdr.Name
|
name := m.Extra[len(m.Extra)-1].(*RR_TSIG).Hdr.Name
|
||||||
_, ok := w.Client().TsigSecret[secret]
|
if _, ok := w.Client().TsigSecret[name]; !ok {
|
||||||
if !ok {
|
|
||||||
return ErrSecret
|
return ErrSecret
|
||||||
}
|
}
|
||||||
// TODO(mg): compression makes this fail
|
out, mac, err := TsigGenerate(m, w.Client().TsigSecret[name], w.tsigRequestMAC, w.tsigTimersOnly)
|
||||||
if err := TsigGenerate(m, w.Client().TsigSecret[secret], w.tsigRequestMAC, w.tsigTimersOnly); err != nil {
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
w.tsigRequestMAC = mac
|
||||||
|
if _, err = w.writeClient(out); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
w.tsigRequestMAC = m.Extra[len(m.Extra)-1].(*RR_TSIG).MAC // Save the requestMAC for the next packet
|
|
||||||
}
|
|
||||||
out, ok := m.Pack()
|
|
||||||
if !ok {
|
|
||||||
return ErrPack
|
|
||||||
}
|
|
||||||
// Tsig calculation should happen here
|
|
||||||
_, err := w.writeClient(out)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
35
ex/q/q.go
35
ex/q/q.go
|
@ -7,6 +7,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
var dnskey *dns.RR_DNSKEY
|
var dnskey *dns.RR_DNSKEY
|
||||||
|
@ -32,7 +33,7 @@ func main() {
|
||||||
short := flag.Bool("short", false, "abbreviate long DNSSEC records")
|
short := flag.Bool("short", false, "abbreviate long DNSSEC records")
|
||||||
check := flag.Bool("check", false, "check internal DNSSEC consistency")
|
check := flag.Bool("check", false, "check internal DNSSEC consistency")
|
||||||
anchor := flag.String("anchor", "", "use the DNSKEY in this file for interal DNSSEC consistency")
|
anchor := flag.String("anchor", "", "use the DNSKEY in this file for interal DNSSEC consistency")
|
||||||
//tsig := flag.String("tsig", "", "request tsig with key: [hmac:]name:key")
|
tsig := flag.String("tsig", "", "request tsig with key: [hmac:]name:key")
|
||||||
port := flag.Int("port", 53, "port number to use")
|
port := flag.Int("port", 53, "port number to use")
|
||||||
aa := flag.Bool("aa", false, "set AA flag in query")
|
aa := flag.Bool("aa", false, "set AA flag in query")
|
||||||
ad := flag.Bool("ad", false, "set AD flag in query")
|
ad := flag.Bool("ad", false, "set AD flag in query")
|
||||||
|
@ -127,9 +128,7 @@ Flags:
|
||||||
nameserver = string([]byte(nameserver)[1:]) // chop off @
|
nameserver = string([]byte(nameserver)[1:]) // chop off @
|
||||||
nameserver += ":" + strconv.Itoa(*port)
|
nameserver += ":" + strconv.Itoa(*port)
|
||||||
|
|
||||||
// ipv6 todo
|
// We use the async query handling, just to show how it is to be used.
|
||||||
// We use the async query handling, just to show how
|
|
||||||
// it is to be used.
|
|
||||||
dns.HandleQueryFunc(".", q)
|
dns.HandleQueryFunc(".", q)
|
||||||
dns.ListenAndQuery(nil, nil)
|
dns.ListenAndQuery(nil, nil)
|
||||||
c := dns.NewClient()
|
c := dns.NewClient()
|
||||||
|
@ -163,6 +162,16 @@ Flags:
|
||||||
if *query {
|
if *query {
|
||||||
fmt.Printf("%s\n", m.String())
|
fmt.Printf("%s\n", m.String())
|
||||||
}
|
}
|
||||||
|
// Add tsig
|
||||||
|
if *tsig != "" {
|
||||||
|
if algo, name, secret, ok := tsigKeyParse(*tsig); ok {
|
||||||
|
m.SetTsig(name, algo, 300, uint64(time.Now().Unix()))
|
||||||
|
c.TsigSecret[name] = secret;
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(os.Stderr, "TSIG key error\n")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
c.Do(m, nameserver)
|
c.Do(m, nameserver)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -219,6 +228,24 @@ forever:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func tsigKeyParse(s string) (algo, name, secret string, ok bool) {
|
||||||
|
s1 := strings.SplitN(s, ":", 3)
|
||||||
|
switch len(s1) {
|
||||||
|
case 2:
|
||||||
|
return "hmac-md5.sig-alg.reg.int.", s1[0], s1[1], true
|
||||||
|
case 3:
|
||||||
|
switch s1[0] {
|
||||||
|
case "hmac-md5":
|
||||||
|
return "hmac-md5.sig-alg.reg.int.", s1[0], s1[1], true
|
||||||
|
case "hmac-sha1":
|
||||||
|
return "hmac-sha1.", s1[1], s1[2], true
|
||||||
|
case "hmac-sha256":
|
||||||
|
return "hmac-sha256.", s1[1], s1[2], true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func sectionCheck(set []dns.RR, server string, tcp bool) {
|
func sectionCheck(set []dns.RR, server string, tcp bool) {
|
||||||
var key *dns.RR_DNSKEY
|
var key *dns.RR_DNSKEY
|
||||||
for _, rr := range set {
|
for _, rr := range set {
|
||||||
|
|
2
msg.go
2
msg.go
|
@ -42,7 +42,7 @@ var (
|
||||||
ErrTime error = &Error{Err: "dns: bad time"}
|
ErrTime error = &Error{Err: "dns: bad time"}
|
||||||
ErrNoSig error = &Error{Err: "dns: no signature found"}
|
ErrNoSig error = &Error{Err: "dns: no signature found"}
|
||||||
ErrSig error = &Error{Err: "dns: bad signature"}
|
ErrSig error = &Error{Err: "dns: bad signature"}
|
||||||
ErrSecret error = &Error{Err: "dns: no secret defined"}
|
ErrSecret error = &Error{Err: "dns: no secrets defined"}
|
||||||
ErrSigGen error = &Error{Err: "dns: bad signature generation"}
|
ErrSigGen error = &Error{Err: "dns: bad signature generation"}
|
||||||
ErrAuth error = &Error{Err: "dns: bad authentication"}
|
ErrAuth error = &Error{Err: "dns: bad authentication"}
|
||||||
ErrXfrSoa error = &Error{Err: "dns: no SOA seen"}
|
ErrXfrSoa error = &Error{Err: "dns: no SOA seen"}
|
||||||
|
|
|
@ -189,10 +189,10 @@ func TestParseDirectiveMisc(t *testing.T) {
|
||||||
// Another one hear, geared to NSECx
|
// Another one hear, geared to NSECx
|
||||||
func TestParseNSEC(t *testing.T) {
|
func TestParseNSEC(t *testing.T) {
|
||||||
nsectests := map[string]string{
|
nsectests := map[string]string{
|
||||||
"nl. IN NSEC3PARAM 1 0 5 30923C44C6CBBB8F": "nl.\t3600\tIN\tNSEC3PARAM\t1 0 5 30923C44C6CBBB8F",
|
"nl. IN NSEC3PARAM 1 0 5 30923C44C6CBBB8F": "nl.\t3600\tIN\tNSEC3PARAM\t1 0 5 30923C44C6CBBB8F",
|
||||||
"p2209hipbpnm681knjnu0m1febshlv4e.nl. IN NSEC3 1 1 5 30923C44C6CBBB8F P90DG1KE8QEAN0B01613LHQDG0SOJ0TA NS SOA TXT RRSIG DNSKEY NSEC3PARAM": "p2209hipbpnm681knjnu0m1febshlv4e.nl.\t3600\tIN\tNSEC3\t1 1 5 30923C44C6CBBB8F P90DG1KE8QEAN0B01613LHQDG0SOJ0TA NS SOA TXT RRSIG DNSKEY NSEC3PARAM",
|
"p2209hipbpnm681knjnu0m1febshlv4e.nl. IN NSEC3 1 1 5 30923C44C6CBBB8F P90DG1KE8QEAN0B01613LHQDG0SOJ0TA NS SOA TXT RRSIG DNSKEY NSEC3PARAM": "p2209hipbpnm681knjnu0m1febshlv4e.nl.\t3600\tIN\tNSEC3\t1 1 5 30923C44C6CBBB8F P90DG1KE8QEAN0B01613LHQDG0SOJ0TA NS SOA TXT RRSIG DNSKEY NSEC3PARAM",
|
||||||
"localhost.dnssex.nl. IN NSEC www.dnssex.nl. A RRSIG NSEC": "localhost.dnssex.nl.\t3600\tIN\tNSEC\twww.dnssex.nl. A RRSIG NSEC",
|
"localhost.dnssex.nl. IN NSEC www.dnssex.nl. A RRSIG NSEC": "localhost.dnssex.nl.\t3600\tIN\tNSEC\twww.dnssex.nl. A RRSIG NSEC",
|
||||||
"localhost.dnssex.nl. IN NSEC www.dnssex.nl. A RRSIG NSEC TYPE65534": "localhost.dnssex.nl.\t3600\tIN\tNSEC\twww.dnssex.nl. A RRSIG NSEC TYPE65534",
|
"localhost.dnssex.nl. IN NSEC www.dnssex.nl. A RRSIG NSEC TYPE65534": "localhost.dnssex.nl.\t3600\tIN\tNSEC\twww.dnssex.nl. A RRSIG NSEC TYPE65534",
|
||||||
}
|
}
|
||||||
for i, o := range nsectests {
|
for i, o := range nsectests {
|
||||||
rr, e := NewRR(i)
|
rr, e := NewRR(i)
|
||||||
|
|
40
rawmsg.go
40
rawmsg.go
|
@ -4,24 +4,39 @@
|
||||||
|
|
||||||
package dns
|
package dns
|
||||||
|
|
||||||
// RawSetId sets the message ID in buf. The offset 'off' must
|
// RawSetId sets the message ID in buf.
|
||||||
// be positioned at the beginning of the message.
|
func RawSetId(msg []byte, i uint16) {
|
||||||
func RawSetId(msg []byte, off int, id uint16) bool {
|
msg[0], msg[1] = packUint16(i)
|
||||||
msg[off], msg[off+1] = packUint16(id)
|
}
|
||||||
return true
|
|
||||||
|
// RawSetQuestionLen sets the len of the question section.
|
||||||
|
func RawSetQuestionLen(msg []byte, i uint16) {
|
||||||
|
msg[4], msg[5] = packUint16(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RawSetAnswerLen sets the len of the question section.
|
||||||
|
func RawSetAnswerLen(msg []byte, i uint16) {
|
||||||
|
msg[6], msg[7] = packUint16(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RawSetsNsLen sets the len of the question section.
|
||||||
|
func RawSetNsLen(msg []byte, i uint16) {
|
||||||
|
msg[8], msg[9] = packUint16(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RawSetExtraLen sets the len of the question section.
|
||||||
|
func RawSetExtraLen(msg []byte, i uint16) {
|
||||||
|
msg[10], msg[11] = packUint16(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RawSetRdlength sets the rdlength in the header of
|
// RawSetRdlength sets the rdlength in the header of
|
||||||
// the RR. The offset 'off' must be positioned at the
|
// the RR. The offset 'off' must be positioned at the
|
||||||
// start of the header of the RR, 'end' must be the
|
// start of the header of the RR, 'end' must be the
|
||||||
// end of the RR.
|
// end of the RR. There is no check if we overrun the buffer.
|
||||||
func RawSetRdlength(msg []byte, off, end int) bool {
|
func RawSetRdlength(msg []byte, off, end int) {
|
||||||
// We are at the start of the header, walk the domainname (might be compressed)
|
// We are at the start of the header, walk the domainname (might be compressed)
|
||||||
Loop:
|
Loop:
|
||||||
for {
|
for {
|
||||||
if off > len(msg) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
c := int(msg[off])
|
c := int(msg[off])
|
||||||
off++
|
off++
|
||||||
switch c & 0xC0 {
|
switch c & 0xC0 {
|
||||||
|
@ -40,11 +55,8 @@ Loop:
|
||||||
// The domainname has been seen, we at the start of the fixed part in the header.
|
// The domainname has been seen, we at the start of the fixed part in the header.
|
||||||
// Type is 2 bytes, class is 2 bytes, ttl 4 and then 2 bytes for the length.
|
// Type is 2 bytes, class is 2 bytes, ttl 4 and then 2 bytes for the length.
|
||||||
off += 2 + 2 + 4
|
off += 2 + 2 + 4
|
||||||
if off+1 > len(msg) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
//off+1 is the end of the header, 'end' is the end of the rr
|
//off+1 is the end of the header, 'end' is the end of the rr
|
||||||
//so 'end' - 'off+2' is the lenght of the rdata
|
//so 'end' - 'off+2' is the lenght of the rdata
|
||||||
msg[off], msg[off+1] = packUint16(uint16(end - (off + 2)))
|
msg[off], msg[off+1] = packUint16(uint16(end - (off + 2)))
|
||||||
return true
|
return
|
||||||
}
|
}
|
||||||
|
|
48
tsig.go
48
tsig.go
|
@ -82,34 +82,33 @@ type timerWireFmt struct {
|
||||||
Fudge uint16
|
Fudge uint16
|
||||||
}
|
}
|
||||||
|
|
||||||
// TsigGenerate adds an TSIG RR to a message. The message should contain
|
// TsigGenerate fills out the TSIG record attached to the message.
|
||||||
// a "stub" TsigRR with the algorithm, key name (owner name of the RR),
|
// The message should contain
|
||||||
// time fudge (defaults to 300 seconds) and the current time
|
// a "stub" TSIG RR with the algorithm, key name (owner name of the RR),
|
||||||
// The TSIG MAC is saved in that Tsig RR.
|
// time fudge (defaults to 300 seconds) and the current time
|
||||||
// When TsigGenerate is called for the
|
// The TSIG MAC is saved in that Tsig RR.
|
||||||
// first time requestMAC is set to the empty string.
|
// When TsigGenerate is called for the first time requestMAC is set to the empty string and
|
||||||
// If something goes wrong an error is returned, otherwise it is nil.
|
// timersOnly is false.
|
||||||
// TODO this needs to work on []byte, not *Msg, to take
|
// If something goes wrong an error is returned, otherwise it is nil.
|
||||||
// compression into account
|
func TsigGenerate(m *Msg, secret, requestMAC string, timersOnly bool) ([]byte, string, error) {
|
||||||
// This
|
|
||||||
func TsigGenerate(m *Msg, secret, requestMAC string, timersOnly bool) error {
|
|
||||||
if !m.IsTsig() {
|
if !m.IsTsig() {
|
||||||
// panic? panic?
|
|
||||||
panic("TSIG not last RR in additional")
|
panic("TSIG not last RR in additional")
|
||||||
}
|
}
|
||||||
// If we barf here, the caller is to blame
|
// If we barf here, the caller is to blame
|
||||||
rawsecret, err := packBase64([]byte(secret))
|
rawsecret, err := packBase64([]byte(secret))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
rr := m.Extra[len(m.Extra)-1].(*RR_TSIG)
|
rr := m.Extra[len(m.Extra)-1].(*RR_TSIG)
|
||||||
m.Extra = m.Extra[0 : len(m.Extra)-1] // kill the TSIG from the msg
|
m.Extra = m.Extra[0 : len(m.Extra)-1] // kill the TSIG from the msg
|
||||||
mbuf, _ := m.Pack()
|
mbuf, ok := m.Pack()
|
||||||
|
if !ok {
|
||||||
|
return nil, "", ErrPack
|
||||||
|
}
|
||||||
buf := tsigBuffer(mbuf, rr, requestMAC, timersOnly)
|
buf := tsigBuffer(mbuf, rr, requestMAC, timersOnly)
|
||||||
|
|
||||||
t := new(RR_TSIG)
|
t := new(RR_TSIG)
|
||||||
|
|
||||||
var h hash.Hash
|
var h hash.Hash
|
||||||
switch rr.Algorithm {
|
switch rr.Algorithm {
|
||||||
case HmacMD5:
|
case HmacMD5:
|
||||||
|
@ -119,10 +118,10 @@ func TsigGenerate(m *Msg, secret, requestMAC string, timersOnly bool) error {
|
||||||
case HmacSHA256:
|
case HmacSHA256:
|
||||||
h = hmac.New(sha256.New, []byte(rawsecret))
|
h = hmac.New(sha256.New, []byte(rawsecret))
|
||||||
default:
|
default:
|
||||||
return ErrKeyAlg
|
return nil, "", ErrKeyAlg
|
||||||
}
|
}
|
||||||
|
io.WriteString(h, string(buf))
|
||||||
t.MAC = hex.EncodeToString(h.Sum(buf))
|
t.MAC = hex.EncodeToString(h.Sum(nil))
|
||||||
t.MACSize = uint16(len(t.MAC) / 2) // Size is half!
|
t.MACSize = uint16(len(t.MAC) / 2) // Size is half!
|
||||||
|
|
||||||
t.Hdr = RR_Header{Name: rr.Hdr.Name, Rrtype: TypeTSIG, Class: ClassANY, Ttl: 0}
|
t.Hdr = RR_Header{Name: rr.Hdr.Name, Rrtype: TypeTSIG, Class: ClassANY, Ttl: 0}
|
||||||
|
@ -130,9 +129,16 @@ func TsigGenerate(m *Msg, secret, requestMAC string, timersOnly bool) error {
|
||||||
t.TimeSigned = rr.TimeSigned
|
t.TimeSigned = rr.TimeSigned
|
||||||
t.Algorithm = rr.Algorithm
|
t.Algorithm = rr.Algorithm
|
||||||
t.OrigId = m.MsgHdr.Id
|
t.OrigId = m.MsgHdr.Id
|
||||||
|
|
||||||
m.Extra = append(m.Extra, t)
|
tbuf := make([]byte, t.Len())
|
||||||
return nil
|
if off, ok := packRR(t, tbuf, 0, nil, false); ok {
|
||||||
|
tbuf = tbuf[:off] // reset to actual size used
|
||||||
|
} else {
|
||||||
|
return nil, "", ErrPack
|
||||||
|
}
|
||||||
|
mbuf = append(mbuf, tbuf...)
|
||||||
|
RawSetExtraLen(mbuf, uint16(len(m.Extra)+1))
|
||||||
|
return mbuf, t.MAC, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// TsigVerify verifies the TSIG on a message.
|
// TsigVerify verifies the TSIG on a message.
|
||||||
|
|
4
types.go
4
types.go
|
@ -178,7 +178,7 @@ func (rr *RR_ANY) Len() int {
|
||||||
}
|
}
|
||||||
|
|
||||||
type RR_CNAME struct {
|
type RR_CNAME struct {
|
||||||
Hdr RR_Header
|
Hdr RR_Header
|
||||||
Target string "cdomain-name"
|
Target string "cdomain-name"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1096,7 +1096,7 @@ func dateToTime(s string) (uint32, error) {
|
||||||
// need for RFC1982 calculations as this date is 48 bits
|
// need for RFC1982 calculations as this date is 48 bits
|
||||||
func tsigTimeToDate(t uint64) string {
|
func tsigTimeToDate(t uint64) string {
|
||||||
// only use the lower 48 bits, TODO(mg), check for 48 bit size
|
// only use the lower 48 bits, TODO(mg), check for 48 bit size
|
||||||
return ""
|
return "TODO"
|
||||||
/*
|
/*
|
||||||
ti := time.Unix(int64(t), 0).Unix()
|
ti := time.Unix(int64(t), 0).Unix()
|
||||||
return ti.Format("20060102150405")
|
return ti.Format("20060102150405")
|
||||||
|
|
|
@ -666,7 +666,7 @@ func setNSEC3(h RR_Header, c chan lex, o, f string) (RR, *ParseError) {
|
||||||
|
|
||||||
rr.TypeBitMap = make([]uint16, 0)
|
rr.TypeBitMap = make([]uint16, 0)
|
||||||
var (
|
var (
|
||||||
k uint16
|
k uint16
|
||||||
ok bool
|
ok bool
|
||||||
)
|
)
|
||||||
l = <-c
|
l = <-c
|
||||||
|
@ -676,7 +676,7 @@ func setNSEC3(h RR_Header, c chan lex, o, f string) (RR, *ParseError) {
|
||||||
// Ok
|
// Ok
|
||||||
case _STRING:
|
case _STRING:
|
||||||
if k, ok = Str_rr[strings.ToUpper(l.token)]; !ok {
|
if k, ok = Str_rr[strings.ToUpper(l.token)]; !ok {
|
||||||
if k, ok = typeToInt(l.token); ! ok {
|
if k, ok = typeToInt(l.token); !ok {
|
||||||
return nil, &ParseError{f, "bad NSEC3 TypeBitMap", l}
|
return nil, &ParseError{f, "bad NSEC3 TypeBitMap", l}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue