Merge branch 'reader'
This commit is contained in:
commit
9e02a40cc8
|
@ -27,8 +27,7 @@ If you like this, you may also be interested in:
|
|||
* Reply speed around ~ 50K qps (faster hardware results in more qps);
|
||||
* Parsing RRs with ~ 100K RR/s, that's 5M records in about 50 seconds;
|
||||
* Server side programming (mimicking the net/http package);
|
||||
* Client side programming with asynchronous calls;
|
||||
* Asynchronous queries/replies for client and server;
|
||||
* Client side programming;
|
||||
* DNSSEC: signing, validating and key generation for DSA, RSA and ECDSA;
|
||||
* EDNS0, NSID;
|
||||
* AXFR/IXFR;
|
||||
|
|
44
client.go
44
client.go
|
@ -9,8 +9,8 @@ import (
|
|||
)
|
||||
|
||||
// Order of events:
|
||||
// *client -> *reply -> Exchange*() -> dial()/send()->write()/receive()->read()
|
||||
|
||||
// *client -> *reply -> Exchange() -> dial()/send()->write()/receive()->read()
|
||||
// Do I want make this an interface thingy?
|
||||
type reply struct {
|
||||
client *Client
|
||||
addr string
|
||||
|
@ -29,50 +29,18 @@ type Client struct {
|
|||
Net string // if "tcp" a TCP query will be initiated, otherwise an UDP one (default is "" for UDP)
|
||||
Attempts int // number of attempts, if not set defaults to 1
|
||||
Retry bool // retry with TCP
|
||||
ReadTimeout time.Duration // the net.Conn.SetReadTimeout value for new connections (ns), defauls to 2 * 1e9
|
||||
WriteTimeout time.Duration // the net.Conn.SetWriteTimeout value for new connections (ns), defauls to 2 * 1e9
|
||||
ReadTimeout time.Duration // the net.Conn.SetReadTimeout value for new connections (ns), defaults to 2 * 1e9
|
||||
WriteTimeout time.Duration // the net.Conn.SetWriteTimeout value for new connections (ns), defaults to 2 * 1e9
|
||||
TsigSecret map[string]string // secret(s) for Tsig map[<zonename>]<base64 secret>, zonename must be fully qualified
|
||||
}
|
||||
|
||||
// Do performs an asynchronous query. The msg *Msg is the question to ask, the
|
||||
// string addr is the address of the nameserver, the parameter data is used
|
||||
// in the callback function. The call backback function is called with the
|
||||
// original query, the answer returned from the nameserver an optional error and
|
||||
// data.
|
||||
func (c *Client) Do(msg *Msg, addr string, data interface{}, callback func(*Msg, *Msg, error, interface{})) {
|
||||
go func() {
|
||||
r, err := c.Exchange(msg, addr)
|
||||
callback(msg, r, err, data)
|
||||
}()
|
||||
}
|
||||
|
||||
// DoRtt is equivalent to Do, except that is calls ExchangeRtt.
|
||||
func (c *Client) DoRtt(msg *Msg, addr string, data interface{}, callback func(*Msg, *Msg, time.Duration, error, interface{})) {
|
||||
go func() {
|
||||
r, rtt, err := c.ExchangeRtt(msg, addr)
|
||||
callback(msg, r, rtt, err, data)
|
||||
}()
|
||||
}
|
||||
|
||||
// Exchange performs an synchronous query. It sends the message m to the address
|
||||
// contained in a and waits for an reply. Basic use pattern with a *Client:
|
||||
//
|
||||
// c := new(dns.Client)
|
||||
// in, err := c.Exchange(message, "127.0.0.1:53")
|
||||
//
|
||||
// See Client.ExchangeRtt(...) to get the round trip time.
|
||||
func (c *Client) Exchange(m *Msg, a string) (r *Msg, err error) {
|
||||
r, _, err = c.ExchangeRtt(m, a)
|
||||
return
|
||||
}
|
||||
|
||||
// ExchangeRtt performs an synchronous query. It sends the message m to the address
|
||||
// contained in a and waits for an reply. Basic use pattern with a *Client:
|
||||
//
|
||||
// c := new(dns.Client)
|
||||
// in, rtt, err := c.ExchangeRtt(message, "127.0.0.1:53")
|
||||
// in, rtt, err := c.Exchange(message, "127.0.0.1:53")
|
||||
//
|
||||
func (c *Client) ExchangeRtt(m *Msg, a string) (r *Msg, rtt time.Duration, err error) {
|
||||
func (c *Client) Exchange(m *Msg, a string) (r *Msg, rtt time.Duration, err error) {
|
||||
w := new(reply)
|
||||
w.client = c
|
||||
w.addr = a
|
||||
|
|
|
@ -10,7 +10,7 @@ func TestClientSync(t *testing.T) {
|
|||
m.SetQuestion("miek.nl.", TypeSOA)
|
||||
|
||||
c := new(Client)
|
||||
r, _ := c.Exchange(m, "85.223.71.124:53")
|
||||
r, _, _ := c.Exchange(m, "37.251.95.53:53")
|
||||
|
||||
if r != nil && r.Rcode != RcodeSuccess {
|
||||
t.Log("Failed to get an valid answer")
|
||||
|
@ -19,20 +19,6 @@ func TestClientSync(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestClientASync(t *testing.T) {
|
||||
m := new(Msg)
|
||||
m.SetQuestion("miek.nl.", TypeSOA)
|
||||
|
||||
c := new(Client)
|
||||
c.Do(m, "85.223.71.124:53", nil, func(m, r *Msg, e error, d interface{}) {
|
||||
if r != nil && r.Rcode != RcodeSuccess {
|
||||
t.Log("Failed to get an valid answer")
|
||||
t.Fail()
|
||||
t.Logf("%v\n", r)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestClientEDNS0(t *testing.T) {
|
||||
m := new(Msg)
|
||||
m.SetQuestion("miek.nl.", TypeDNSKEY)
|
||||
|
@ -42,7 +28,7 @@ func TestClientEDNS0(t *testing.T) {
|
|||
//edns.SetNsid("") // Empty to request it
|
||||
|
||||
c := new(Client)
|
||||
r, _ := c.Exchange(m, "85.223.71.124:53")
|
||||
r, _, _ := c.Exchange(m, "37.251.95.53:53")
|
||||
|
||||
if r != nil && r.Rcode != RcodeSuccess {
|
||||
t.Log("Failed to get an valid answer")
|
||||
|
@ -60,7 +46,7 @@ func TestClientTsigAXFR(t *testing.T) {
|
|||
c.TsigSecret = map[string]string{"axfr.": "so6ZGir4GPAqINNh9U5c3A=="}
|
||||
c.Net = "tcp"
|
||||
|
||||
if a, err := c.XfrReceive(m, "85.223.71.124:53"); err != nil {
|
||||
if a, err := c.XfrReceive(m, "37.251.95.53:53"); err != nil {
|
||||
t.Log("Failed to setup axfr: " + err.Error())
|
||||
t.Fail()
|
||||
return
|
||||
|
@ -85,7 +71,7 @@ func TestClientAXFRMultipleMessages(t *testing.T) {
|
|||
c := new(Client)
|
||||
c.Net = "tcp"
|
||||
|
||||
if a, err := c.XfrReceive(m, "85.223.71.124:53"); err != nil {
|
||||
if a, err := c.XfrReceive(m, "37.251.95.53:53"); err != nil {
|
||||
t.Log("Failed to setup axfr" + err.Error())
|
||||
t.Fail()
|
||||
return
|
||||
|
|
|
@ -155,6 +155,7 @@ func (dns *Msg) IsEdns0() *RR_OPT {
|
|||
// IsDomainName checks if s is a valid domainname, it returns
|
||||
// the number of labels, total length and true, when a domain name is valid.
|
||||
// When false is returned the labelcount and length are not defined.
|
||||
// TODO(mg): checks for \DDD
|
||||
func IsDomainName(s string) (uint8, uint8, bool) { // copied from net package.
|
||||
// See RFC 1035, RFC 3696.
|
||||
l := len(s)
|
||||
|
@ -189,6 +190,11 @@ func IsDomainName(s string) (uint8, uint8, bool) { // copied from net package.
|
|||
partlen++
|
||||
case c == '\\':
|
||||
// Ok
|
||||
// case c == '@':
|
||||
// if last != '\\' {
|
||||
// return 0, uint8(l - longer), false
|
||||
// }
|
||||
// partlen++
|
||||
case '0' <= c && c <= '9':
|
||||
ok = true
|
||||
partlen++
|
||||
|
|
5
dns.go
5
dns.go
|
@ -59,10 +59,9 @@
|
|||
// server configured on 127.0.0.1 and port 53:
|
||||
//
|
||||
// c := new(Client)
|
||||
// in, err := c.Exchange(m1, "127.0.0.1:53")
|
||||
// in, rtt, err := c.Exchange(m1, "127.0.0.1:53")
|
||||
//
|
||||
// An asynchronous query is also possible, see client.Do or client.DoRtt, when
|
||||
// you are interested in the round trip time of the exchange.
|
||||
// For asynchronous queries it is easy to wrap Exchange().
|
||||
//
|
||||
// From a birds eye view a dns message consists out of four sections.
|
||||
// The question section: in.Question, the answer section: in.Answer,
|
||||
|
|
|
@ -13,6 +13,8 @@
|
|||
// m.SetEdns0(4096, true)
|
||||
//
|
||||
// Signature generation, signature verification and key generation are all supported.
|
||||
// Writing a DNSSEC validating resolver is hard, if you need something like that you
|
||||
// might want to use the unbound wrapper found at github.com/miekg/unbound .
|
||||
package dns
|
||||
|
||||
import (
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
package dns
|
||||
|
||||
// Find better solution
|
||||
|
|
|
@ -26,57 +26,59 @@ func main() {
|
|||
}
|
||||
for _, a := range addr {
|
||||
m.Question[0] = dns.Question{"version.bind.", dns.TypeTXT, dns.ClassCHAOS}
|
||||
in, rtt, _ := c.ExchangeRtt(m, a)
|
||||
in, rtt, _ := c.Exchange(m, a)
|
||||
if in != nil && len(in.Answer) > 0 {
|
||||
fmt.Printf("(time %.3d µs) %v\n", rtt/1e3, in.Answer[0])
|
||||
}
|
||||
m.Question[0] = dns.Question{"hostname.bind.", dns.TypeTXT, dns.ClassCHAOS}
|
||||
in, rtt, _ = c.ExchangeRtt(m, a)
|
||||
in, rtt, _ = c.Exchange(m, a)
|
||||
if in != nil && len(in.Answer) > 0 {
|
||||
fmt.Printf("(time %.3d µs) %v\n", rtt/1e3, in.Answer[0])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func qhandler(m, r *dns.Msg, e error, data interface{}) {
|
||||
ips := make([]string, 0)
|
||||
if r != nil && r.Rcode == dns.RcodeSuccess {
|
||||
for _, aa := range r.Answer {
|
||||
switch aa.(type) {
|
||||
case *dns.RR_A:
|
||||
ips = append(ips, aa.(*dns.RR_A).A.String()+":53")
|
||||
case *dns.RR_AAAA:
|
||||
ips = append(ips, "["+aa.(*dns.RR_AAAA).AAAA.String()+"]:53")
|
||||
}
|
||||
}
|
||||
data.(chan []string) <- ips
|
||||
return
|
||||
}
|
||||
data.(chan []string) <- nil
|
||||
}
|
||||
|
||||
func addresses(conf *dns.ClientConfig, c *dns.Client, name string) []string {
|
||||
func addresses(conf *dns.ClientConfig, c *dns.Client, name string) (ips []string) {
|
||||
m4 := new(dns.Msg)
|
||||
m4.SetQuestion(dns.Fqdn(os.Args[1]), dns.TypeA)
|
||||
m6 := new(dns.Msg)
|
||||
m6.SetQuestion(dns.Fqdn(os.Args[1]), dns.TypeAAAA)
|
||||
c4 := c.Do(m4, conf.Servers[0]+":"+conf.Port)
|
||||
c6 := c.Do(m6, conf.Servers[0]+":"+conf.Port)
|
||||
|
||||
addr := make(chan []string)
|
||||
defer close(addr)
|
||||
c.Do(m4, conf.Servers[0]+":"+conf.Port, addr, qhandler)
|
||||
c.Do(m6, conf.Servers[0]+":"+conf.Port, addr, qhandler)
|
||||
|
||||
var ips []string
|
||||
i := 2 // two outstanding queries
|
||||
forever:
|
||||
for {
|
||||
select {
|
||||
case ip := <-addr:
|
||||
ips = append(ips, ip...)
|
||||
case ip4 := <-c4:
|
||||
if ip4.Reply != nil && ip4.Reply.Rcode == dns.RcodeSuccess {
|
||||
for _, a := range ip4.Reply.Answer {
|
||||
switch a.(type) {
|
||||
case *dns.RR_A:
|
||||
ips = append(ips, a.(*dns.RR_A).A.String()+":53")
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
i--
|
||||
if i == 0 {
|
||||
break forever
|
||||
}
|
||||
case ip6 := <-c6:
|
||||
if ip6.Reply != nil && ip6.Reply.Rcode == dns.RcodeSuccess {
|
||||
for _, a := range ip6.Reply.Answer {
|
||||
switch a.(type) {
|
||||
case *dns.RR_AAAA:
|
||||
ips = append(ips, a.(*dns.RR_AAAA).AAAA.String()+":53")
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
i--
|
||||
if i == 0 {
|
||||
break forever
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return ips
|
||||
|
|
|
@ -24,7 +24,7 @@ func localQuery(qname string, qtype uint16) (*dns.Msg, error) {
|
|||
localm.SetQuestion(qname, qtype)
|
||||
for i := range conf.Servers {
|
||||
server := conf.Servers[i]
|
||||
r, err := localc.Exchange(localm, server+":"+conf.Port)
|
||||
r, _, err := localc.Exchange(localm, server+":"+conf.Port)
|
||||
if r == nil || r.Rcode == dns.RcodeNameError || r.Rcode == dns.RcodeSuccess {
|
||||
return r, err
|
||||
}
|
||||
|
@ -114,7 +114,7 @@ func main() {
|
|||
} else {
|
||||
nsAddressPort = ip + ":53"
|
||||
}
|
||||
soa, err := c.Exchange(m, nsAddressPort)
|
||||
soa, _, err := c.Exchange(m, nsAddressPort)
|
||||
// TODO: retry if timeout? Otherwise, one lost UDP packet and it is the end
|
||||
if soa == nil {
|
||||
success = false
|
||||
|
|
44
ex/q/q.go
44
ex/q/q.go
|
@ -190,7 +190,8 @@ Flags:
|
|||
m.Extra = append(m.Extra, o)
|
||||
}
|
||||
|
||||
for i, v := range qname {
|
||||
ch := make(chan *dns.Exchange)
|
||||
for _, v := range qname {
|
||||
m.Question[0] = dns.Question{dns.Fqdn(v), qtype, qclass}
|
||||
m.Id = dns.Id()
|
||||
if *query {
|
||||
|
@ -217,12 +218,26 @@ Flags:
|
|||
continue
|
||||
}
|
||||
|
||||
c.DoRtt(m, nameserver, nil, func(m, r *dns.Msg, rtt time.Duration, e error, data interface{}) {
|
||||
defer func() {
|
||||
if i == len(qname)-1 {
|
||||
os.Exit(0)
|
||||
}
|
||||
}()
|
||||
c.Do(m, nameserver, ch)
|
||||
}
|
||||
|
||||
// HUH?
|
||||
if qtype != dns.TypeAXFR && qtype != dns.TypeIXFR {
|
||||
// xfr didn't start any goroutines
|
||||
select {}
|
||||
}
|
||||
|
||||
i := 0
|
||||
for {
|
||||
select {
|
||||
case ex := <-ch:
|
||||
if i == len(qname)-1 {
|
||||
os.Exit(0)
|
||||
}
|
||||
i++
|
||||
r := ex.Reply
|
||||
rtt := ex.Rtt
|
||||
e := ex.Error
|
||||
Redo:
|
||||
if e != nil {
|
||||
fmt.Printf(";; %s\n", e.Error())
|
||||
|
@ -241,19 +256,19 @@ Flags:
|
|||
o.Hdr.Rrtype = dns.TypeOPT
|
||||
o.SetUDPSize(dns.DefaultMsgSize)
|
||||
m.Extra = append(m.Extra, o)
|
||||
r, rtt, e = c.ExchangeRtt(m, nameserver)
|
||||
r, rtt, e = c.Exchange(m, nameserver)
|
||||
*dnssec = true
|
||||
goto Redo
|
||||
} else {
|
||||
// First EDNS, then TCP
|
||||
fmt.Printf(";; Truncated, trying TCP\n")
|
||||
c.Net = "tcp"
|
||||
r, rtt, e = c.ExchangeRtt(m, nameserver)
|
||||
r, rtt, e = c.Exchange(m, nameserver)
|
||||
goto Redo
|
||||
}
|
||||
}
|
||||
}
|
||||
if r.MsgHdr.Truncated && !*fallback {
|
||||
if ex.Reply.MsgHdr.Truncated && !*fallback {
|
||||
fmt.Printf(";; Truncated\n")
|
||||
}
|
||||
if *check {
|
||||
|
@ -266,13 +281,8 @@ Flags:
|
|||
|
||||
fmt.Printf("%v", r)
|
||||
fmt.Printf("\n;; query time: %.3d µs, server: %s(%s), size: %d bytes\n", rtt/1e3, nameserver, c.Net, r.Size)
|
||||
})
|
||||
}
|
||||
}
|
||||
if qtype != dns.TypeAXFR && qtype != dns.TypeIXFR {
|
||||
// xfr don't start any goroutines
|
||||
select {}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func tsigKeyParse(s string) (algo, name, secret string, ok bool) {
|
||||
|
@ -385,7 +395,7 @@ func getKey(name string, keytag uint16, server string, tcp bool) *dns.RR_DNSKEY
|
|||
m := new(dns.Msg)
|
||||
m.SetQuestion(name, dns.TypeDNSKEY)
|
||||
m.SetEdns0(4096, true)
|
||||
r, err := c.Exchange(m, server)
|
||||
r, _, err := c.Exchange(m, server)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -125,7 +125,7 @@ func handleReflect(w dns.ResponseWriter, r *dns.Msg) {
|
|||
if *printf {
|
||||
fmt.Printf("%v\n", m.String())
|
||||
}
|
||||
w.Write(m)
|
||||
w.WriteMsg(m)
|
||||
}
|
||||
|
||||
func serve(net, name, secret string) {
|
||||
|
|
|
@ -11,7 +11,7 @@ func ExampleRR_MX() {
|
|||
m := new(Msg)
|
||||
m.SetQuestion("miek.nl.", TypeMX)
|
||||
m.RecursionDesired = true
|
||||
r, err := c.Exchange(m, config.Servers[0]+":"+config.Port)
|
||||
r, _, err := c.Exchange(m, config.Servers[0]+":"+config.Port)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -36,7 +36,7 @@ func ExampleToDs(zone string) {
|
|||
}
|
||||
m.SetQuestion(Fqdn(zone), TypeDNSKEY)
|
||||
m.SetEdns0(4096, true)
|
||||
r, err := c.Exchange(m, config.Servers[0]+":"+config.Port)
|
||||
r, _, err := c.Exchange(m, config.Servers[0]+":"+config.Port)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
|
9
msg.go
9
msg.go
|
@ -99,11 +99,16 @@ var Rr_str = map[uint16]string{
|
|||
TypeMX: "MX",
|
||||
TypeWKS: "WKS",
|
||||
TypeNS: "NS",
|
||||
TypeNULL: "NULL",
|
||||
TypeAFSDB: "AFSDB",
|
||||
TypeX25: "X25",
|
||||
TypeISDN: "ISDN",
|
||||
TypePTR: "PTR",
|
||||
TypeRT: "RT",
|
||||
TypeSOA: "SOA",
|
||||
TypeTXT: "TXT",
|
||||
TypeSRV: "SRV",
|
||||
TypeATMA: "ATMA",
|
||||
TypeNAPTR: "NAPTR",
|
||||
TypeKX: "KX",
|
||||
TypeCERT: "CERT",
|
||||
|
@ -115,6 +120,10 @@ var Rr_str = map[uint16]string{
|
|||
TypeDS: "DS",
|
||||
TypeDHCID: "DHCID",
|
||||
TypeHIP: "HIP",
|
||||
TypeNINFO: "NINFO",
|
||||
TypeRKEY: "RKEY",
|
||||
TypeCDS: "CDS",
|
||||
TypeCAA: "CAA",
|
||||
TypeIPSECKEY: "IPSECKEY",
|
||||
TypeSSHFP: "SSHFP",
|
||||
TypeRRSIG: "RRSIG",
|
||||
|
|
141
nsecx.go
141
nsecx.go
|
@ -13,22 +13,6 @@ const (
|
|||
_NSEC3_NODATA
|
||||
)
|
||||
|
||||
// A Denialer is a record that performs denial
|
||||
// of existence in DNSSEC. Currently there are
|
||||
// two types NSEC and NSEC3.
|
||||
type Denialer interface {
|
||||
// HashNames hashes the owner and next domain name according
|
||||
// to the hashing set in the record. For NSEC it is the identity function.
|
||||
// The string domain is appended to the ownername in case of NSEC3
|
||||
HashNames(domain string)
|
||||
// Match checks if domain matches the (hashed) owner of name of the record.
|
||||
Match(domain string) bool
|
||||
// Cover checks if domain is covered by the NSEC(3) record
|
||||
Cover(domain string) bool
|
||||
// MatchType checks if the type is present in the bitmap
|
||||
MatchType(rrtype uint16) bool
|
||||
}
|
||||
|
||||
type saltWireFmt struct {
|
||||
Salt string `dns:"size-hex"`
|
||||
}
|
||||
|
@ -135,128 +119,3 @@ func (rr *RR_NSEC3) Cover(domain string) bool {
|
|||
func (rr *RR_NSEC) Cover(domain string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// NsecVerify verifies an denial of existence response with NSECs
|
||||
// NsecVerify returns nil when the NSECs in the message contain
|
||||
// the correct proof. This function does not validates the NSECs.
|
||||
func (m *Msg) NsecVerify(q Question) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Nsec3Verify verifies an denial of existence response with NSEC3s.
|
||||
// This function does not validate the NSEC3s.
|
||||
func (m *Msg) Nsec3Verify(q Question) (int, error) {
|
||||
var (
|
||||
nsec3 []*RR_NSEC3
|
||||
ncdenied = false // next closer denied
|
||||
sodenied = false // source of synthesis denied
|
||||
ce = "" // closest encloser
|
||||
nc = "" // next closer
|
||||
so = "" // source of synthesis
|
||||
)
|
||||
if len(m.Answer) > 0 && len(m.Ns) > 0 {
|
||||
// Wildcard expansion
|
||||
// Closest encloser inferred from SIG in authority and qname
|
||||
// println("EXPANDED WILDCARD PROOF or DNAME CNAME")
|
||||
// println("NODATA")
|
||||
// I need to check the type bitmap
|
||||
// wildcard bit not set?
|
||||
// MM: No need to check the wildcard bit here:
|
||||
// This response has only 1 NSEC4 and it does not match
|
||||
// the closest encloser (it covers next closer).
|
||||
}
|
||||
if len(m.Answer) == 0 && len(m.Ns) > 0 {
|
||||
// Maybe an NXDOMAIN or NODATA, we only know when we check
|
||||
for _, n := range m.Ns {
|
||||
if n.Header().Rrtype == TypeNSEC3 {
|
||||
nsec3 = append(nsec3, n.(*RR_NSEC3))
|
||||
}
|
||||
}
|
||||
if len(nsec3) == 0 {
|
||||
return 0, ErrDenialNsec3
|
||||
}
|
||||
|
||||
lastchopped := ""
|
||||
labels := SplitLabels(q.Name)
|
||||
|
||||
// Find the closest encloser and create the next closer
|
||||
for _, nsec := range nsec3 {
|
||||
candidate := ""
|
||||
for i := len(labels) - 1; i >= 0; i-- {
|
||||
candidate = labels[i] + "." + candidate
|
||||
if nsec.Match(candidate) {
|
||||
ce = candidate
|
||||
}
|
||||
lastchopped = labels[i]
|
||||
}
|
||||
}
|
||||
if ce == "" { // what about root label?
|
||||
return 0, ErrDenialCe
|
||||
}
|
||||
nc = lastchopped + "." + ce
|
||||
so = "*." + ce
|
||||
// Check if the next closer is covered and thus denied
|
||||
for _, nsec := range nsec3 {
|
||||
if nsec.Cover(nc) {
|
||||
ncdenied = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !ncdenied {
|
||||
if m.Rcode == RcodeNameError {
|
||||
// For NXDOMAIN this is a problem
|
||||
return 0, ErrDenialNc // add next closer name here
|
||||
}
|
||||
goto NoData
|
||||
}
|
||||
|
||||
// Check if the source of synthesis is covered and thus also denied
|
||||
for _, nsec := range nsec3 {
|
||||
if nsec.Cover(so) {
|
||||
sodenied = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !sodenied {
|
||||
return 0, ErrDenialSo
|
||||
}
|
||||
// The message headers claims something different!
|
||||
if m.Rcode != RcodeNameError {
|
||||
return 0, ErrDenialHdr
|
||||
}
|
||||
|
||||
return _NSEC3_NXDOMAIN, nil
|
||||
}
|
||||
return 0, nil
|
||||
NoData:
|
||||
// For NODATA we need to to check if the matching nsec3 has to correct type bit map
|
||||
// And we need to check that the wildcard does NOT exist
|
||||
for _, nsec := range nsec3 {
|
||||
if nsec.Cover(so) {
|
||||
sodenied = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if sodenied {
|
||||
// Whoa, the closest encloser is denied, but there does exist
|
||||
// a wildcard a that level. That's not good
|
||||
return 0, ErrDenialWc
|
||||
}
|
||||
|
||||
// The closest encloser MUST be the query name
|
||||
for _, nsec := range nsec3 {
|
||||
if nsec.Match(nc) {
|
||||
// This nsec3 must NOT have the type bitmap set of the qtype. If it does have it, return an error
|
||||
for _, t := range nsec.TypeBitMap {
|
||||
if t == q.Qtype {
|
||||
return 0, ErrDenialBit
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if m.Rcode == RcodeNameError {
|
||||
return 0, ErrDenialHdr
|
||||
}
|
||||
return _NSEC3_NODATA, nil
|
||||
}
|
||||
|
|
52
server.go
52
server.go
|
@ -21,10 +21,10 @@ type Handler interface {
|
|||
type ResponseWriter interface {
|
||||
// RemoteAddr returns the net.Addr of the client that sent the current request.
|
||||
RemoteAddr() net.Addr
|
||||
// Write writes a reply back to the client.
|
||||
Write(*Msg) error
|
||||
// WriteBuf writes a raw buffer back to the client.
|
||||
WriteBuf([]byte) error
|
||||
// WriteMsg writes a reply back to the client.
|
||||
WriteMsg(*Msg) error
|
||||
// Write writes a raw buffer back to the client.
|
||||
Write([]byte) (int, error)
|
||||
// Close closes the connection.
|
||||
Close() error
|
||||
// TsigStatus returns the status of the Tsig.
|
||||
|
@ -86,7 +86,7 @@ func HandleFailed(w ResponseWriter, r *Msg) {
|
|||
m := new(Msg)
|
||||
m.SetRcode(r, RcodeServerFailure)
|
||||
// does not matter if this write fails
|
||||
w.Write(m)
|
||||
w.WriteMsg(m)
|
||||
}
|
||||
|
||||
// AuthorHandler returns a HandlerFunc that returns the authors
|
||||
|
@ -118,7 +118,7 @@ func HandleAuthors(w ResponseWriter, r *Msg) {
|
|||
h := RR_Header{r.Question[0].Name, TypeTXT, ClassCHAOS, 0, 0}
|
||||
m.Answer = append(m.Answer, &RR_TXT{h, []string{author}})
|
||||
}
|
||||
w.Write(m)
|
||||
w.WriteMsg(m)
|
||||
}
|
||||
|
||||
// VersionHandler returns a HandlerFunc that returns the version
|
||||
|
@ -148,7 +148,7 @@ func HandleVersion(w ResponseWriter, r *Msg) {
|
|||
m.SetReply(r)
|
||||
h := RR_Header{r.Question[0].Name, TypeTXT, ClassCHAOS, 0, 0}
|
||||
m.Answer = append(m.Answer, &RR_TXT{h, []string{Version}})
|
||||
w.Write(m)
|
||||
w.WriteMsg(m)
|
||||
}
|
||||
|
||||
func authorHandler() Handler { return HandlerFunc(HandleAuthors) }
|
||||
|
@ -375,7 +375,7 @@ func serve(a net.Addr, h Handler, m []byte, u *net.UDPConn, t *net.TCPConn, tsig
|
|||
// Send a format error back
|
||||
x := new(Msg)
|
||||
x.SetRcodeFormatError(req)
|
||||
w.Write(x)
|
||||
w.WriteMsg(x)
|
||||
break
|
||||
}
|
||||
|
||||
|
@ -404,8 +404,8 @@ func serve(a net.Addr, h Handler, m []byte, u *net.UDPConn, t *net.TCPConn, tsig
|
|||
return
|
||||
}
|
||||
|
||||
// Write implements the ResponseWriter.Write method.
|
||||
func (w *response) Write(m *Msg) (err error) {
|
||||
// WriteMsg implements the ResponseWriter.WriteMsg method.
|
||||
func (w *response) WriteMsg(m *Msg) (err error) {
|
||||
var data []byte
|
||||
if w.tsigSecret != nil { // if no secrets, dont check for the tsig (which is a longer check)
|
||||
if t := m.IsTsig(); t != nil {
|
||||
|
@ -413,46 +413,48 @@ func (w *response) Write(m *Msg) (err error) {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return w.WriteBuf(data)
|
||||
_, err = w.Write(data)
|
||||
return err
|
||||
}
|
||||
}
|
||||
data, err = m.Pack()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return w.WriteBuf(data)
|
||||
_, err = w.Write(data)
|
||||
return err
|
||||
}
|
||||
|
||||
// WriteBuf implements the ResponseWriter.WriteBuf method.
|
||||
func (w *response) WriteBuf(m []byte) error {
|
||||
// Write implements the ResponseWriter.Write method.
|
||||
func (w *response) Write(m []byte) (int, error) {
|
||||
switch {
|
||||
case w._UDP != nil:
|
||||
_, err := w._UDP.WriteTo(m, w.remoteAddr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
n, err := w._UDP.WriteTo(m, w.remoteAddr)
|
||||
return n, err
|
||||
case w._TCP != nil:
|
||||
lm := len(m)
|
||||
if len(m) > MaxMsgSize {
|
||||
return &Error{Err: "message too large"}
|
||||
return 0, &Error{Err: "message too large"}
|
||||
}
|
||||
l := make([]byte, 2)
|
||||
l[0], l[1] = packUint16(uint16(len(m)))
|
||||
l[0], l[1] = packUint16(uint16(lm))
|
||||
m = append(l, m...)
|
||||
n, err := w._TCP.Write(m)
|
||||
if err != nil {
|
||||
return err
|
||||
return n, err
|
||||
}
|
||||
i := n
|
||||
if i < len(m) {
|
||||
j, err := w._TCP.Write(m[i:len(m)])
|
||||
if i < lm {
|
||||
j, err := w._TCP.Write(m[i:lm])
|
||||
if err != nil {
|
||||
return err
|
||||
return i, err
|
||||
}
|
||||
i += j
|
||||
}
|
||||
n = i
|
||||
return i, nil
|
||||
}
|
||||
return nil
|
||||
panic("not reached")
|
||||
}
|
||||
|
||||
// RemoteAddr implements the ResponseWriter.RemoteAddr method.
|
||||
|
|
|
@ -11,7 +11,7 @@ func HelloServer(w ResponseWriter, req *Msg) {
|
|||
|
||||
m.Extra = make([]RR, 1)
|
||||
m.Extra[0] = &RR_TXT{Hdr: RR_Header{Name: m.Question[0].Name, Rrtype: TypeTXT, Class: ClassINET, Ttl: 0}, Txt: []string{"Hello world"}}
|
||||
w.Write(m)
|
||||
w.WriteMsg(m)
|
||||
}
|
||||
|
||||
func AnotherHelloServer(w ResponseWriter, req *Msg) {
|
||||
|
@ -20,7 +20,7 @@ func AnotherHelloServer(w ResponseWriter, req *Msg) {
|
|||
|
||||
m.Extra = make([]RR, 1)
|
||||
m.Extra[0] = &RR_TXT{Hdr: RR_Header{Name: m.Question[0].Name, Rrtype: TypeTXT, Class: ClassINET, Ttl: 0}, Txt: []string{"Hello example"}}
|
||||
w.Write(m)
|
||||
w.WriteMsg(m)
|
||||
}
|
||||
|
||||
func TestServing(t *testing.T) {
|
||||
|
@ -38,14 +38,14 @@ func TestServing(t *testing.T) {
|
|||
m := new(Msg)
|
||||
|
||||
m.SetQuestion("miek.nl.", TypeTXT)
|
||||
r, _ := c.Exchange(m, "127.0.0.1:8053")
|
||||
r, _, _ := c.Exchange(m, "127.0.0.1:8053")
|
||||
txt := r.Extra[0].(*RR_TXT).Txt[0]
|
||||
if txt != "Hello world" {
|
||||
t.Log("Unexpected result for miek.nl", txt, "!= Hello world")
|
||||
t.Fail()
|
||||
}
|
||||
m.SetQuestion("example.com.", TypeTXT)
|
||||
r, _ = c.Exchange(m, "127.0.0.1:8053")
|
||||
r, _, _ = c.Exchange(m, "127.0.0.1:8053")
|
||||
txt = r.Extra[0].(*RR_TXT).Txt[0]
|
||||
if txt != "Hello example" {
|
||||
t.Log("Unexpected result for example.com", txt, "!= Hello example")
|
||||
|
|
132
types.go
132
types.go
|
@ -37,6 +37,8 @@ const (
|
|||
TypeTXT uint16 = 16
|
||||
TypeRP uint16 = 17
|
||||
TypeAFSDB uint16 = 18
|
||||
TypeX25 uint16 = 19
|
||||
TypeISDN uint16 = 20
|
||||
TypeRT uint16 = 21
|
||||
TypeSIG uint16 = 24
|
||||
TypeKEY uint16 = 25
|
||||
|
@ -44,6 +46,7 @@ const (
|
|||
TypeLOC uint16 = 29
|
||||
TypeNXT uint16 = 30
|
||||
TypeSRV uint16 = 33
|
||||
TypeATMA uint16 = 34
|
||||
TypeNAPTR uint16 = 35
|
||||
TypeKX uint16 = 36
|
||||
TypeCERT uint16 = 37
|
||||
|
@ -60,7 +63,10 @@ const (
|
|||
TypeNSEC3PARAM uint16 = 51
|
||||
TypeTLSA uint16 = 52
|
||||
TypeHIP uint16 = 55
|
||||
TypeNINFO uint16 = 56
|
||||
TypeRKEY uint16 = 57
|
||||
TypeTALINK uint16 = 58
|
||||
TypeCDS uint16 = 59
|
||||
TypeSPF uint16 = 99
|
||||
TypeNID uint16 = 104
|
||||
TypeL32 uint16 = 105
|
||||
|
@ -77,6 +83,7 @@ const (
|
|||
TypeANY uint16 = 255
|
||||
|
||||
TypeURI uint16 = 256
|
||||
TypeCAA uint16 = 257
|
||||
TypeTA uint16 = 32768
|
||||
TypeDLV uint16 = 32769
|
||||
|
||||
|
@ -369,9 +376,9 @@ func (rr *RR_MD) Copy() RR {
|
|||
}
|
||||
|
||||
type RR_MX struct {
|
||||
Hdr RR_Header
|
||||
Hdr RR_Header
|
||||
Preference uint16
|
||||
Mx string `dns:"cdomain-name"`
|
||||
Mx string `dns:"cdomain-name"`
|
||||
}
|
||||
|
||||
func (rr *RR_MX) Header() *RR_Header {
|
||||
|
@ -414,6 +421,27 @@ func (rr *RR_AFSDB) Copy() RR {
|
|||
return &RR_AFSDB{*rr.Hdr.CopyHeader(), rr.Subtype, rr.Hostname}
|
||||
}
|
||||
|
||||
type RR_X25 struct {
|
||||
Hdr RR_Header
|
||||
PSDNAddress string
|
||||
}
|
||||
|
||||
func (rr *RR_X25) Header() *RR_Header {
|
||||
return &rr.Hdr
|
||||
}
|
||||
|
||||
func (rr *RR_X25) String() string {
|
||||
return rr.Hdr.String() + rr.PSDNAddress
|
||||
}
|
||||
|
||||
func (rr *RR_X25) Len() int {
|
||||
return rr.Hdr.Len() + len(rr.PSDNAddress)
|
||||
}
|
||||
|
||||
func (rr *RR_X25) Copy() RR {
|
||||
return &RR_X25{*rr.Hdr.CopyHeader(), rr.PSDNAddress}
|
||||
}
|
||||
|
||||
type RR_RT struct {
|
||||
Hdr RR_Header
|
||||
Preference uint16
|
||||
|
@ -634,7 +662,7 @@ func (rr *RR_SRV) Copy() RR {
|
|||
type RR_NAPTR struct {
|
||||
Hdr RR_Header
|
||||
Order uint16
|
||||
Preference uint16
|
||||
Preference uint16
|
||||
Flags string
|
||||
Service string
|
||||
Regexp string
|
||||
|
@ -923,6 +951,33 @@ func (rr *RR_DS) Copy() RR {
|
|||
return &RR_DS{*rr.Hdr.CopyHeader(), rr.KeyTag, rr.Algorithm, rr.DigestType, rr.Digest}
|
||||
}
|
||||
|
||||
type RR_CDS struct {
|
||||
Hdr RR_Header
|
||||
KeyTag uint16
|
||||
Algorithm uint8
|
||||
DigestType uint8
|
||||
Digest string `dns:"hex"`
|
||||
}
|
||||
|
||||
func (rr *RR_CDS) Header() *RR_Header {
|
||||
return &rr.Hdr
|
||||
}
|
||||
|
||||
func (rr *RR_CDS) String() string {
|
||||
return rr.Hdr.String() + strconv.Itoa(int(rr.KeyTag)) +
|
||||
" " + strconv.Itoa(int(rr.Algorithm)) +
|
||||
" " + strconv.Itoa(int(rr.DigestType)) +
|
||||
" " + strings.ToUpper(rr.Digest)
|
||||
}
|
||||
|
||||
func (rr *RR_CDS) Len() int {
|
||||
return rr.Hdr.Len() + 4 + len(rr.Digest)/2
|
||||
}
|
||||
|
||||
func (rr *RR_CDS) Copy() RR {
|
||||
return &RR_CDS{*rr.Hdr.CopyHeader(), rr.KeyTag, rr.Algorithm, rr.DigestType, rr.Digest}
|
||||
}
|
||||
|
||||
type RR_DLV struct {
|
||||
Hdr RR_Header
|
||||
KeyTag uint16
|
||||
|
@ -951,9 +1006,9 @@ func (rr *RR_DLV) Copy() RR {
|
|||
}
|
||||
|
||||
type RR_KX struct {
|
||||
Hdr RR_Header
|
||||
Preference uint16
|
||||
Exchanger string `dns:"domain-name"`
|
||||
Hdr RR_Header
|
||||
Preference uint16
|
||||
Exchanger string `dns:"domain-name"`
|
||||
}
|
||||
|
||||
func (rr *RR_KX) Header() *RR_Header {
|
||||
|
@ -1106,6 +1161,34 @@ func (rr *RR_DNSKEY) Copy() RR {
|
|||
return &RR_DNSKEY{*rr.Hdr.CopyHeader(), rr.Flags, rr.Protocol, rr.Algorithm, rr.PublicKey}
|
||||
}
|
||||
|
||||
type RR_RKEY struct {
|
||||
Hdr RR_Header
|
||||
Flags uint16
|
||||
Protocol uint8
|
||||
Algorithm uint8
|
||||
PublicKey string `dns:"base64"`
|
||||
}
|
||||
|
||||
func (rr *RR_RKEY) Header() *RR_Header {
|
||||
return &rr.Hdr
|
||||
}
|
||||
|
||||
func (rr *RR_RKEY) String() string {
|
||||
return rr.Hdr.String() + strconv.Itoa(int(rr.Flags)) +
|
||||
" " + strconv.Itoa(int(rr.Protocol)) +
|
||||
" " + strconv.Itoa(int(rr.Algorithm)) +
|
||||
" " + rr.PublicKey
|
||||
}
|
||||
|
||||
func (rr *RR_RKEY) Len() int {
|
||||
return rr.Hdr.Len() + 4 +
|
||||
base64.StdEncoding.DecodedLen(len(rr.PublicKey))
|
||||
}
|
||||
|
||||
func (rr *RR_RKEY) Copy() RR {
|
||||
return &RR_RKEY{*rr.Hdr.CopyHeader(), rr.Flags, rr.Protocol, rr.Algorithm, rr.PublicKey}
|
||||
}
|
||||
|
||||
type RR_NSEC3 struct {
|
||||
Hdr RR_Header
|
||||
Hash uint8
|
||||
|
@ -1347,6 +1430,39 @@ func (rr *RR_HIP) Copy() RR {
|
|||
return &RR_HIP{*rr.Hdr.CopyHeader(), rr.HitLength, rr.PublicKeyAlgorithm, rr.PublicKeyLength, rr.Hit, rr.PublicKey, rr.RendezvousServers}
|
||||
}
|
||||
|
||||
type RR_NINFO struct {
|
||||
Hdr RR_Header
|
||||
ZSData []string `dns:"txt"`
|
||||
}
|
||||
|
||||
func (rr *RR_NINFO) Header() *RR_Header {
|
||||
return &rr.Hdr
|
||||
}
|
||||
|
||||
func (rr *RR_NINFO) String() string {
|
||||
s := rr.Hdr.String()
|
||||
for i, s1 := range rr.ZSData {
|
||||
if i > 0 {
|
||||
s += " " + strconv.QuoteToASCII(s1)
|
||||
} else {
|
||||
s += strconv.QuoteToASCII(s1)
|
||||
}
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func (rr *RR_NINFO) Len() int {
|
||||
l := rr.Hdr.Len()
|
||||
for _, t := range rr.ZSData {
|
||||
l += len(t)
|
||||
}
|
||||
return l
|
||||
}
|
||||
|
||||
func (rr *RR_NINFO) Copy() RR {
|
||||
return &RR_NINFO{*rr.Hdr.CopyHeader(), rr.ZSData}
|
||||
}
|
||||
|
||||
type RR_WKS struct {
|
||||
Hdr RR_Header
|
||||
Address net.IP `dns:"a"`
|
||||
|
@ -1536,8 +1652,11 @@ var rr_mk = map[uint16]func() RR{
|
|||
TypeMINFO: func() RR { return new(RR_MINFO) },
|
||||
TypeRP: func() RR { return new(RR_RP) },
|
||||
TypeAFSDB: func() RR { return new(RR_AFSDB) },
|
||||
TypeX25: func() RR { return new(RR_X25) },
|
||||
TypeMR: func() RR { return new(RR_MR) },
|
||||
TypeMX: func() RR { return new(RR_MX) },
|
||||
TypeRKEY: func() RR { return new(RR_RKEY) },
|
||||
TypeNINFO: func() RR { return new(RR_NINFO) },
|
||||
TypeNS: func() RR { return new(RR_NS) },
|
||||
TypePTR: func() RR { return new(RR_PTR) },
|
||||
TypeSOA: func() RR { return new(RR_SOA) },
|
||||
|
@ -1552,6 +1671,7 @@ var rr_mk = map[uint16]func() RR{
|
|||
TypeLOC: func() RR { return new(RR_LOC) },
|
||||
TypeOPT: func() RR { return new(RR_OPT) },
|
||||
TypeDS: func() RR { return new(RR_DS) },
|
||||
TypeCDS: func() RR { return new(RR_CDS) },
|
||||
TypeCERT: func() RR { return new(RR_CERT) },
|
||||
TypeKX: func() RR { return new(RR_KX) },
|
||||
TypeSPF: func() RR { return new(RR_SPF) },
|
||||
|
|
2
xfr.go
2
xfr.go
|
@ -183,7 +183,7 @@ func axfrSend(w ResponseWriter, req *Msg, c chan *XfrToken, e *error) {
|
|||
for x := range c {
|
||||
// assume it fits
|
||||
rep.Answer = append(rep.Answer, x.RR...)
|
||||
if err := w.Write(rep); e != nil {
|
||||
if err := w.WriteMsg(rep); e != nil {
|
||||
*e = err
|
||||
return
|
||||
}
|
||||
|
|
146
zscan_rr.go
146
zscan_rr.go
|
@ -46,6 +46,9 @@ func setRR(h RR_Header, c chan lex, o, f string) (RR, *ParseError) {
|
|||
case TypeAFSDB:
|
||||
r, e = setAFSDB(h, c, o, f)
|
||||
goto Slurp
|
||||
case TypeX25:
|
||||
r, e = setX25(h,c, f)
|
||||
goto Slurp
|
||||
case TypeMX:
|
||||
r, e = setMX(h, c, o, f)
|
||||
goto Slurp
|
||||
|
@ -95,6 +98,8 @@ func setRR(h RR_Header, c chan lex, o, f string) (RR, *ParseError) {
|
|||
// newline. Thus there is no need to slurp the remainder, because there is none.
|
||||
case TypeDNSKEY:
|
||||
return setDNSKEY(h, c, f)
|
||||
case TypeRKEY:
|
||||
return setRKEY(h, c, f)
|
||||
case TypeRRSIG:
|
||||
return setRRSIG(h, c, o, f)
|
||||
case TypeNSEC:
|
||||
|
@ -107,6 +112,8 @@ func setRR(h RR_Header, c chan lex, o, f string) (RR, *ParseError) {
|
|||
return setWKS(h, c, f)
|
||||
case TypeDS:
|
||||
return setDS(h, c, f)
|
||||
case TypeCDS:
|
||||
return setCDS(h, c, f)
|
||||
case TypeDLV:
|
||||
return setDLV(h, c, f)
|
||||
case TypeTA:
|
||||
|
@ -115,6 +122,8 @@ func setRR(h RR_Header, c chan lex, o, f string) (RR, *ParseError) {
|
|||
return setTLSA(h, c, f)
|
||||
case TypeTXT:
|
||||
return setTXT(h, c, f)
|
||||
case TypeNINFO:
|
||||
return setNINFO(h, c, f)
|
||||
case TypeHIP:
|
||||
return setHIP(h, c, o, f)
|
||||
case TypeSPF:
|
||||
|
@ -465,6 +474,15 @@ func setAFSDB(h RR_Header, c chan lex, o, f string) (RR, *ParseError) {
|
|||
return rr, nil
|
||||
}
|
||||
|
||||
func setX25(h RR_Header, c chan lex, f string) (RR, *ParseError) {
|
||||
rr := new(RR_X25)
|
||||
rr.Hdr = h
|
||||
|
||||
l := <-c
|
||||
rr.PSDNAddress = l.token
|
||||
return rr, nil
|
||||
}
|
||||
|
||||
func setKX(h RR_Header, c chan lex, o, f string) (RR, *ParseError) {
|
||||
rr := new(RR_KX)
|
||||
rr.Hdr = h
|
||||
|
@ -1328,6 +1346,47 @@ func setDNSKEY(h RR_Header, c chan lex, f string) (RR, *ParseError) {
|
|||
return rr, nil
|
||||
}
|
||||
|
||||
func setRKEY(h RR_Header, c chan lex, f string) (RR, *ParseError) {
|
||||
rr := new(RR_RKEY)
|
||||
rr.Hdr = h
|
||||
|
||||
l := <-c
|
||||
if i, e := strconv.Atoi(l.token); e != nil {
|
||||
return nil, &ParseError{f, "bad RKEY Flags", l}
|
||||
} else {
|
||||
rr.Flags = uint16(i)
|
||||
}
|
||||
<-c // _BLANK
|
||||
l = <-c // _STRING
|
||||
if i, e := strconv.Atoi(l.token); e != nil {
|
||||
return nil, &ParseError{f, "bad RKEY Protocol", l}
|
||||
} else {
|
||||
rr.Protocol = uint8(i)
|
||||
}
|
||||
<-c // _BLANK
|
||||
l = <-c // _STRING
|
||||
if i, e := strconv.Atoi(l.token); e != nil {
|
||||
return nil, &ParseError{f, "bad RKEY Algorithm", l}
|
||||
} else {
|
||||
rr.Algorithm = uint8(i)
|
||||
}
|
||||
l = <-c
|
||||
var s string
|
||||
for l.value != _NEWLINE && l.value != _EOF {
|
||||
switch l.value {
|
||||
case _STRING:
|
||||
s += l.token
|
||||
case _BLANK:
|
||||
// Ok
|
||||
default:
|
||||
return nil, &ParseError{f, "bad RKEY PublicKey", l}
|
||||
}
|
||||
l = <-c
|
||||
}
|
||||
rr.PublicKey = s
|
||||
return rr, nil
|
||||
}
|
||||
|
||||
func setDS(h RR_Header, c chan lex, f string) (RR, *ParseError) {
|
||||
rr := new(RR_DS)
|
||||
rr.Hdr = h
|
||||
|
@ -1373,6 +1432,51 @@ func setDS(h RR_Header, c chan lex, f string) (RR, *ParseError) {
|
|||
return rr, nil
|
||||
}
|
||||
|
||||
func setCDS(h RR_Header, c chan lex, f string) (RR, *ParseError) {
|
||||
rr := new(RR_CDS)
|
||||
rr.Hdr = h
|
||||
l := <-c
|
||||
if i, e := strconv.Atoi(l.token); e != nil {
|
||||
return nil, &ParseError{f, "bad CDS KeyTag", l}
|
||||
} else {
|
||||
rr.KeyTag = uint16(i)
|
||||
}
|
||||
<-c // _BLANK
|
||||
l = <-c
|
||||
if i, e := strconv.Atoi(l.token); e != nil {
|
||||
if i, ok := Str_alg[strings.ToUpper(l.token)]; !ok {
|
||||
return nil, &ParseError{f, "bad CDS Algorithm", l}
|
||||
} else {
|
||||
rr.Algorithm = i
|
||||
}
|
||||
} else {
|
||||
rr.Algorithm = uint8(i)
|
||||
}
|
||||
<-c // _BLANK
|
||||
l = <-c
|
||||
if i, e := strconv.Atoi(l.token); e != nil {
|
||||
return nil, &ParseError{f, "bad CDS DigestType", l}
|
||||
} else {
|
||||
rr.DigestType = uint8(i)
|
||||
}
|
||||
// There can be spaces here...
|
||||
l = <-c
|
||||
s := ""
|
||||
for l.value != _NEWLINE && l.value != _EOF {
|
||||
switch l.value {
|
||||
case _STRING:
|
||||
s += l.token
|
||||
case _BLANK:
|
||||
// Ok
|
||||
default:
|
||||
return nil, &ParseError{f, "bad CDS Digest", l}
|
||||
}
|
||||
l = <-c
|
||||
}
|
||||
rr.Digest = s
|
||||
return rr, nil
|
||||
}
|
||||
|
||||
func setDLV(h RR_Header, c chan lex, f string) (RR, *ParseError) {
|
||||
rr := new(RR_DLV)
|
||||
rr.Hdr = h
|
||||
|
@ -1620,6 +1724,48 @@ func setTXT(h RR_Header, c chan lex, f string) (RR, *ParseError) {
|
|||
return rr, nil
|
||||
}
|
||||
|
||||
// identical to setTXT
|
||||
func setNINFO(h RR_Header, c chan lex, f string) (RR, *ParseError) {
|
||||
rr := new(RR_NINFO)
|
||||
rr.Hdr = h
|
||||
|
||||
// Get the remaining data until we see a NEWLINE
|
||||
quote := false
|
||||
l := <-c
|
||||
var s []string
|
||||
switch l.value == _QUOTE {
|
||||
case true: // A number of quoted string
|
||||
s = make([]string, 0)
|
||||
for l.value != _NEWLINE && l.value != _EOF {
|
||||
switch l.value {
|
||||
case _STRING:
|
||||
s = append(s, l.token)
|
||||
case _BLANK:
|
||||
if quote {
|
||||
// _BLANK can only be seen in between txt parts.
|
||||
return nil, &ParseError{f, "bad NINFO ZSData", l}
|
||||
}
|
||||
case _QUOTE:
|
||||
quote = !quote
|
||||
default:
|
||||
return nil, &ParseError{f, "bad NINFO ZSData", l}
|
||||
}
|
||||
l = <-c
|
||||
}
|
||||
if quote {
|
||||
return nil, &ParseError{f, "bad NINFO ZSData", l}
|
||||
}
|
||||
case false: // Unquoted text record
|
||||
s = make([]string, 1)
|
||||
for l.value != _NEWLINE && l.value != _EOF {
|
||||
s[0] += l.token
|
||||
l = <-c
|
||||
}
|
||||
}
|
||||
rr.ZSData = s
|
||||
return rr, nil
|
||||
}
|
||||
|
||||
func setURI(h RR_Header, c chan lex, f string) (RR, *ParseError) {
|
||||
rr := new(RR_URI)
|
||||
rr.Hdr = h
|
||||
|
|
Loading…
Reference in New Issue