Add github.com/miekg/dns to vendor
authorAnton Tolchanov <me@knyar.net>
Mon, 27 Jun 2016 20:25:19 +0000 (23:25 +0300)
committerAnton Tolchanov <me@knyar.net>
Mon, 27 Jun 2016 20:26:48 +0000 (23:26 +0300)
46 files changed:
vendor/github.com/miekg/dns/AUTHORS [new file with mode: 0644]
vendor/github.com/miekg/dns/CONTRIBUTORS [new file with mode: 0644]
vendor/github.com/miekg/dns/COPYRIGHT [new file with mode: 0644]
vendor/github.com/miekg/dns/LICENSE [new file with mode: 0644]
vendor/github.com/miekg/dns/README.md [new file with mode: 0644]
vendor/github.com/miekg/dns/client.go [new file with mode: 0644]
vendor/github.com/miekg/dns/clientconfig.go [new file with mode: 0644]
vendor/github.com/miekg/dns/defaults.go [new file with mode: 0644]
vendor/github.com/miekg/dns/dns.go [new file with mode: 0644]
vendor/github.com/miekg/dns/dnssec.go [new file with mode: 0644]
vendor/github.com/miekg/dns/dnssec_keygen.go [new file with mode: 0644]
vendor/github.com/miekg/dns/dnssec_keyscan.go [new file with mode: 0644]
vendor/github.com/miekg/dns/dnssec_privkey.go [new file with mode: 0644]
vendor/github.com/miekg/dns/doc.go [new file with mode: 0644]
vendor/github.com/miekg/dns/edns.go [new file with mode: 0644]
vendor/github.com/miekg/dns/format.go [new file with mode: 0644]
vendor/github.com/miekg/dns/generate.go [new file with mode: 0644]
vendor/github.com/miekg/dns/labels.go [new file with mode: 0644]
vendor/github.com/miekg/dns/msg.go [new file with mode: 0644]
vendor/github.com/miekg/dns/msg_generate.go [new file with mode: 0644]
vendor/github.com/miekg/dns/msg_helpers.go [new file with mode: 0644]
vendor/github.com/miekg/dns/nsecx.go [new file with mode: 0644]
vendor/github.com/miekg/dns/privaterr.go [new file with mode: 0644]
vendor/github.com/miekg/dns/rawmsg.go [new file with mode: 0644]
vendor/github.com/miekg/dns/reverse.go [new file with mode: 0644]
vendor/github.com/miekg/dns/sanitize.go [new file with mode: 0644]
vendor/github.com/miekg/dns/scan.go [new file with mode: 0644]
vendor/github.com/miekg/dns/scan_rr.go [new file with mode: 0644]
vendor/github.com/miekg/dns/scanner.go [new file with mode: 0644]
vendor/github.com/miekg/dns/server.go [new file with mode: 0644]
vendor/github.com/miekg/dns/sig0.go [new file with mode: 0644]
vendor/github.com/miekg/dns/singleinflight.go [new file with mode: 0644]
vendor/github.com/miekg/dns/tlsa.go [new file with mode: 0644]
vendor/github.com/miekg/dns/tsig.go [new file with mode: 0644]
vendor/github.com/miekg/dns/types.go [new file with mode: 0644]
vendor/github.com/miekg/dns/types_generate.go [new file with mode: 0644]
vendor/github.com/miekg/dns/udp.go [new file with mode: 0644]
vendor/github.com/miekg/dns/udp_linux.go [new file with mode: 0644]
vendor/github.com/miekg/dns/udp_other.go [new file with mode: 0644]
vendor/github.com/miekg/dns/udp_plan9.go [new file with mode: 0644]
vendor/github.com/miekg/dns/udp_windows.go [new file with mode: 0644]
vendor/github.com/miekg/dns/update.go [new file with mode: 0644]
vendor/github.com/miekg/dns/xfr.go [new file with mode: 0644]
vendor/github.com/miekg/dns/zmsg.go [new file with mode: 0644]
vendor/github.com/miekg/dns/ztypes.go [new file with mode: 0644]
vendor/vendor.json

diff --git a/vendor/github.com/miekg/dns/AUTHORS b/vendor/github.com/miekg/dns/AUTHORS
new file mode 100644 (file)
index 0000000..1965683
--- /dev/null
@@ -0,0 +1 @@
+Miek Gieben <miek@miek.nl>
diff --git a/vendor/github.com/miekg/dns/CONTRIBUTORS b/vendor/github.com/miekg/dns/CONTRIBUTORS
new file mode 100644 (file)
index 0000000..f77e8a8
--- /dev/null
@@ -0,0 +1,9 @@
+Alex A. Skinner
+Andrew Tunnell-Jones
+Ask Bjørn Hansen
+Dave Cheney
+Dusty Wilson
+Marek Majkowski
+Peter van Dijk
+Omri Bahumi
+Alex Sergeyev
diff --git a/vendor/github.com/miekg/dns/COPYRIGHT b/vendor/github.com/miekg/dns/COPYRIGHT
new file mode 100644 (file)
index 0000000..35702b1
--- /dev/null
@@ -0,0 +1,9 @@
+Copyright 2009 The Go Authors. All rights reserved. Use of this source code
+is governed by a BSD-style license that can be found in the LICENSE file.
+Extensions of the original work are copyright (c) 2011 Miek Gieben
+
+Copyright 2011 Miek Gieben. All rights reserved. Use of this source code is
+governed by a BSD-style license that can be found in the LICENSE file.
+
+Copyright 2014 CloudFlare. All rights reserved. Use of this source code is
+governed by a BSD-style license that can be found in the LICENSE file.
diff --git a/vendor/github.com/miekg/dns/LICENSE b/vendor/github.com/miekg/dns/LICENSE
new file mode 100644 (file)
index 0000000..5763fa7
--- /dev/null
@@ -0,0 +1,32 @@
+Extensions of the original work are copyright (c) 2011 Miek Gieben
+
+As this is fork of the official Go code the same license applies:
+
+Copyright (c) 2009 The Go Authors. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+   * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+   * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+   * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
diff --git a/vendor/github.com/miekg/dns/README.md b/vendor/github.com/miekg/dns/README.md
new file mode 100644 (file)
index 0000000..83b4183
--- /dev/null
@@ -0,0 +1,151 @@
+[![Build Status](https://travis-ci.org/miekg/dns.svg?branch=master)](https://travis-ci.org/miekg/dns)
+
+# Alternative (more granular) approach to a DNS library
+
+> Less is more.
+
+Complete and usable DNS library. All widely used Resource Records are
+supported, including the DNSSEC types. It follows a lean and mean philosophy.
+If there is stuff you should know as a DNS programmer there isn't a convenience
+function for it. Server side and client side programming is supported, i.e. you
+can build servers and resolvers with it.
+
+We try to keep the "master" branch as sane as possible and at the bleeding edge
+of standards, avoiding breaking changes wherever reasonable. We support the last
+two versions of Go, currently: 1.5 and 1.6.
+
+# Goals
+
+* KISS;
+* Fast;
+* Small API, if its easy to code in Go, don't make a function for it.
+
+# Users
+
+A not-so-up-to-date-list-that-may-be-actually-current:
+
+* https://cloudflare.com
+* https://github.com/abh/geodns
+* http://www.statdns.com/
+* http://www.dnsinspect.com/
+* https://github.com/chuangbo/jianbing-dictionary-dns
+* http://www.dns-lg.com/
+* https://github.com/fcambus/rrda
+* https://github.com/kenshinx/godns
+* https://github.com/skynetservices/skydns
+* https://github.com/hashicorp/consul
+* https://github.com/DevelopersPL/godnsagent
+* https://github.com/duedil-ltd/discodns
+* https://github.com/StalkR/dns-reverse-proxy
+* https://github.com/tianon/rawdns
+* https://mesosphere.github.io/mesos-dns/
+* https://pulse.turbobytes.com/
+* https://play.google.com/store/apps/details?id=com.turbobytes.dig
+* https://github.com/fcambus/statzone
+* https://github.com/benschw/dns-clb-go
+* https://github.com/corny/dnscheck for http://public-dns.info/
+* https://namesmith.io
+* https://github.com/miekg/unbound
+* https://github.com/miekg/exdns
+* https://dnslookup.org
+* https://github.com/looterz/grimd
+* https://github.com/phamhongviet/serf-dns
+
+Send pull request if you want to be listed here.
+
+# Features
+
+* UDP/TCP queries, IPv4 and IPv6;
+* RFC 1035 zone file parsing ($INCLUDE, $ORIGIN, $TTL and $GENERATE (for all record types) are supported;
+* Fast:
+    * Reply speed around ~ 80K qps (faster hardware results in more qps);
+    * Parsing RRs ~ 100K RR/s, that's 5M records in about 50 seconds;
+* Server side programming (mimicking the net/http package);
+* Client side programming;
+* DNSSEC: signing, validating and key generation for DSA, RSA and ECDSA;
+* EDNS0, NSID, Cookies;
+* AXFR/IXFR;
+* TSIG, SIG(0);
+* DNS over TLS: optional encrypted connection between client and server;
+* DNS name compression;
+* Depends only on the standard library.
+
+Have fun!
+
+Miek Gieben  -  2010-2012  -  <miek@miek.nl>
+
+# Building
+
+Building is done with the `go` tool. If you have setup your GOPATH
+correctly, the following should work:
+
+    go get github.com/miekg/dns
+    go build github.com/miekg/dns
+
+## Examples
+
+A short "how to use the API" is at the beginning of doc.go (this also will show
+when you call `godoc github.com/miekg/dns`).
+
+Example programs can be found in the `github.com/miekg/exdns` repository.
+
+## Supported RFCs
+
+*all of them*
+
+* 103{4,5} - DNS standard
+* 1348 - NSAP record (removed the record)
+* 1982 - Serial Arithmetic
+* 1876 - LOC record
+* 1995 - IXFR
+* 1996 - DNS notify
+* 2136 - DNS Update (dynamic updates)
+* 2181 - RRset definition - there is no RRset type though, just []RR
+* 2537 - RSAMD5 DNS keys
+* 2065 - DNSSEC (updated in later RFCs)
+* 2671 - EDNS record
+* 2782 - SRV record
+* 2845 - TSIG record
+* 2915 - NAPTR record
+* 2929 - DNS IANA Considerations
+* 3110 - RSASHA1 DNS keys
+* 3225 - DO bit (DNSSEC OK)
+* 340{1,2,3} - NAPTR record
+* 3445 - Limiting the scope of (DNS)KEY
+* 3597 - Unknown RRs
+* 403{3,4,5} - DNSSEC + validation functions
+* 4255 - SSHFP record
+* 4343 - Case insensitivity
+* 4408 - SPF record
+* 4509 - SHA256 Hash in DS
+* 4592 - Wildcards in the DNS
+* 4635 - HMAC SHA TSIG
+* 4701 - DHCID
+* 4892 - id.server
+* 5001 - NSID
+* 5155 - NSEC3 record
+* 5205 - HIP record
+* 5702 - SHA2 in the DNS
+* 5936 - AXFR
+* 5966 - TCP implementation recommendations
+* 6605 - ECDSA
+* 6725 - IANA Registry Update
+* 6742 - ILNP DNS
+* 6840 - Clarifications and Implementation Notes for DNS Security
+* 6844 - CAA record
+* 6891 - EDNS0 update
+* 6895 - DNS IANA considerations
+* 6975 - Algorithm Understanding in DNSSEC
+* 7043 - EUI48/EUI64 records
+* 7314 - DNS (EDNS) EXPIRE Option
+* 7553 - URI record
+* 7858 - DNS over TLS: Initiation and Performance Considerations (draft)
+* 7873 - Domain Name System (DNS) Cookies (draft-ietf-dnsop-cookies)
+* xxxx - EDNS0 DNS Update Lease (draft)
+
+## Loosely based upon
+
+* `ldns`
+* `NSD`
+* `Net::DNS`
+* `GRONG`
diff --git a/vendor/github.com/miekg/dns/client.go b/vendor/github.com/miekg/dns/client.go
new file mode 100644 (file)
index 0000000..1302e4e
--- /dev/null
@@ -0,0 +1,455 @@
+package dns
+
+// A client implementation.
+
+import (
+       "bytes"
+       "crypto/tls"
+       "encoding/binary"
+       "io"
+       "net"
+       "time"
+)
+
+const dnsTimeout time.Duration = 2 * time.Second
+const tcpIdleTimeout time.Duration = 8 * time.Second
+
+// A Conn represents a connection to a DNS server.
+type Conn struct {
+       net.Conn                         // a net.Conn holding the connection
+       UDPSize        uint16            // minimum receive buffer for UDP messages
+       TsigSecret     map[string]string // secret(s) for Tsig map[<zonename>]<base64 secret>, zonename must be fully qualified
+       rtt            time.Duration
+       t              time.Time
+       tsigRequestMAC string
+}
+
+// A Client defines parameters for a DNS client.
+type Client struct {
+       Net            string            // if "tcp" or "tcp-tls" (DNS over TLS) a TCP query will be initiated, otherwise an UDP one (default is "" for UDP)
+       UDPSize        uint16            // minimum receive buffer for UDP messages
+       TLSConfig      *tls.Config       // TLS connection configuration
+       Timeout        time.Duration     // a cumulative timeout for dial, write and read, defaults to 0 (disabled) - overrides DialTimeout, ReadTimeout and WriteTimeout when non-zero
+       DialTimeout    time.Duration     // net.DialTimeout, defaults to 2 seconds - overridden by Timeout when that value is non-zero
+       ReadTimeout    time.Duration     // net.Conn.SetReadTimeout value for connections, defaults to 2 seconds - overridden by Timeout when that value is non-zero
+       WriteTimeout   time.Duration     // net.Conn.SetWriteTimeout value for connections, defaults to 2 seconds - overridden by Timeout when that value is non-zero
+       TsigSecret     map[string]string // secret(s) for Tsig map[<zonename>]<base64 secret>, zonename must be fully qualified
+       SingleInflight bool              // if true suppress multiple outstanding queries for the same Qname, Qtype and Qclass
+       group          singleflight
+}
+
+// Exchange performs a synchronous UDP query. It sends the message m to the address
+// contained in a and waits for an reply. Exchange does not retry a failed query, nor
+// will it fall back to TCP in case of truncation.
+// See client.Exchange for more information on setting larger buffer sizes.
+func Exchange(m *Msg, a string) (r *Msg, err error) {
+       var co *Conn
+       co, err = DialTimeout("udp", a, dnsTimeout)
+       if err != nil {
+               return nil, err
+       }
+
+       defer co.Close()
+
+       opt := m.IsEdns0()
+       // If EDNS0 is used use that for size.
+       if opt != nil && opt.UDPSize() >= MinMsgSize {
+               co.UDPSize = opt.UDPSize()
+       }
+
+       co.SetWriteDeadline(time.Now().Add(dnsTimeout))
+       if err = co.WriteMsg(m); err != nil {
+               return nil, err
+       }
+
+       co.SetReadDeadline(time.Now().Add(dnsTimeout))
+       r, err = co.ReadMsg()
+       if err == nil && r.Id != m.Id {
+               err = ErrId
+       }
+       return r, err
+}
+
+// ExchangeConn performs a synchronous query. It sends the message m via the connection
+// c and waits for a reply. The connection c is not closed by ExchangeConn.
+// This function is going away, but can easily be mimicked:
+//
+//     co := &dns.Conn{Conn: c} // c is your net.Conn
+//     co.WriteMsg(m)
+//     in, _  := co.ReadMsg()
+//     co.Close()
+//
+func ExchangeConn(c net.Conn, m *Msg) (r *Msg, err error) {
+       println("dns: this function is deprecated")
+       co := new(Conn)
+       co.Conn = c
+       if err = co.WriteMsg(m); err != nil {
+               return nil, err
+       }
+       r, err = co.ReadMsg()
+       if err == nil && r.Id != m.Id {
+               err = ErrId
+       }
+       return r, err
+}
+
+// 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 *dns.Client:
+//
+//     c := new(dns.Client)
+//     in, rtt, err := c.Exchange(message, "127.0.0.1:53")
+//
+// Exchange does not retry a failed query, nor will it fall back to TCP in
+// case of truncation.
+// It is up to the caller to create a message that allows for larger responses to be
+// returned. Specifically this means adding an EDNS0 OPT RR that will advertise a larger
+// buffer, see SetEdns0. Messsages without an OPT RR will fallback to the historic limit
+// of 512 bytes.
+func (c *Client) Exchange(m *Msg, a string) (r *Msg, rtt time.Duration, err error) {
+       if !c.SingleInflight {
+               return c.exchange(m, a)
+       }
+       // This adds a bunch of garbage, TODO(miek).
+       t := "nop"
+       if t1, ok := TypeToString[m.Question[0].Qtype]; ok {
+               t = t1
+       }
+       cl := "nop"
+       if cl1, ok := ClassToString[m.Question[0].Qclass]; ok {
+               cl = cl1
+       }
+       r, rtt, err, shared := c.group.Do(m.Question[0].Name+t+cl, func() (*Msg, time.Duration, error) {
+               return c.exchange(m, a)
+       })
+       if err != nil {
+               return r, rtt, err
+       }
+       if shared {
+               return r.Copy(), rtt, nil
+       }
+       return r, rtt, nil
+}
+
+func (c *Client) dialTimeout() time.Duration {
+       if c.Timeout != 0 {
+               return c.Timeout
+       }
+       if c.DialTimeout != 0 {
+               return c.DialTimeout
+       }
+       return dnsTimeout
+}
+
+func (c *Client) readTimeout() time.Duration {
+       if c.ReadTimeout != 0 {
+               return c.ReadTimeout
+       }
+       return dnsTimeout
+}
+
+func (c *Client) writeTimeout() time.Duration {
+       if c.WriteTimeout != 0 {
+               return c.WriteTimeout
+       }
+       return dnsTimeout
+}
+
+func (c *Client) exchange(m *Msg, a string) (r *Msg, rtt time.Duration, err error) {
+       var co *Conn
+       network := "udp"
+       tls := false
+
+       switch c.Net {
+       case "tcp-tls":
+               network = "tcp"
+               tls = true
+       case "tcp4-tls":
+               network = "tcp4"
+               tls = true
+       case "tcp6-tls":
+               network = "tcp6"
+               tls = true
+       default:
+               if c.Net != "" {
+                       network = c.Net
+               }
+       }
+
+       var deadline time.Time
+       if c.Timeout != 0 {
+               deadline = time.Now().Add(c.Timeout)
+       }
+
+       if tls {
+               co, err = DialTimeoutWithTLS(network, a, c.TLSConfig, c.dialTimeout())
+       } else {
+               co, err = DialTimeout(network, a, c.dialTimeout())
+       }
+
+       if err != nil {
+               return nil, 0, err
+       }
+       defer co.Close()
+
+       opt := m.IsEdns0()
+       // If EDNS0 is used use that for size.
+       if opt != nil && opt.UDPSize() >= MinMsgSize {
+               co.UDPSize = opt.UDPSize()
+       }
+       // Otherwise use the client's configured UDP size.
+       if opt == nil && c.UDPSize >= MinMsgSize {
+               co.UDPSize = c.UDPSize
+       }
+
+       co.TsigSecret = c.TsigSecret
+       co.SetWriteDeadline(deadlineOrTimeout(deadline, c.writeTimeout()))
+       if err = co.WriteMsg(m); err != nil {
+               return nil, 0, err
+       }
+
+       co.SetReadDeadline(deadlineOrTimeout(deadline, c.readTimeout()))
+       r, err = co.ReadMsg()
+       if err == nil && r.Id != m.Id {
+               err = ErrId
+       }
+       return r, co.rtt, err
+}
+
+// ReadMsg reads a message from the connection co.
+// If the received message contains a TSIG record the transaction
+// signature is verified.
+func (co *Conn) ReadMsg() (*Msg, error) {
+       p, err := co.ReadMsgHeader(nil)
+       if err != nil {
+               return nil, err
+       }
+
+       m := new(Msg)
+       if err := m.Unpack(p); err != nil {
+               // If ErrTruncated was returned, we still want to allow the user to use
+               // the message, but naively they can just check err if they don't want
+               // to use a truncated message
+               if err == ErrTruncated {
+                       return m, err
+               }
+               return nil, err
+       }
+       if t := m.IsTsig(); t != nil {
+               if _, ok := co.TsigSecret[t.Hdr.Name]; !ok {
+                       return m, ErrSecret
+               }
+               // Need to work on the original message p, as that was used to calculate the tsig.
+               err = TsigVerify(p, co.TsigSecret[t.Hdr.Name], co.tsigRequestMAC, false)
+       }
+       return m, err
+}
+
+// ReadMsgHeader reads a DNS message, parses and populates hdr (when hdr is not nil).
+// Returns message as a byte slice to be parsed with Msg.Unpack later on.
+// Note that error handling on the message body is not possible as only the header is parsed.
+func (co *Conn) ReadMsgHeader(hdr *Header) ([]byte, error) {
+       var (
+               p   []byte
+               n   int
+               err error
+       )
+
+       switch t := co.Conn.(type) {
+       case *net.TCPConn, *tls.Conn:
+               r := t.(io.Reader)
+
+               // First two bytes specify the length of the entire message.
+               l, err := tcpMsgLen(r)
+               if err != nil {
+                       return nil, err
+               }
+               p = make([]byte, l)
+               n, err = tcpRead(r, p)
+               co.rtt = time.Since(co.t)
+       default:
+               if co.UDPSize > MinMsgSize {
+                       p = make([]byte, co.UDPSize)
+               } else {
+                       p = make([]byte, MinMsgSize)
+               }
+               n, err = co.Read(p)
+               co.rtt = time.Since(co.t)
+       }
+
+       if err != nil {
+               return nil, err
+       } else if n < headerSize {
+               return nil, ErrShortRead
+       }
+
+       p = p[:n]
+       if hdr != nil {
+               dh, _, err := unpackMsgHdr(p, 0)
+               if err != nil {
+                       return nil, err
+               }
+               *hdr = dh
+       }
+       return p, err
+}
+
+// tcpMsgLen is a helper func to read first two bytes of stream as uint16 packet length.
+func tcpMsgLen(t io.Reader) (int, error) {
+       p := []byte{0, 0}
+       n, err := t.Read(p)
+       if err != nil {
+               return 0, err
+       }
+       if n != 2 {
+               return 0, ErrShortRead
+       }
+       l := binary.BigEndian.Uint16(p)
+       if l == 0 {
+               return 0, ErrShortRead
+       }
+       return int(l), nil
+}
+
+// tcpRead calls TCPConn.Read enough times to fill allocated buffer.
+func tcpRead(t io.Reader, p []byte) (int, error) {
+       n, err := t.Read(p)
+       if err != nil {
+               return n, err
+       }
+       for n < len(p) {
+               j, err := t.Read(p[n:])
+               if err != nil {
+                       return n, err
+               }
+               n += j
+       }
+       return n, err
+}
+
+// Read implements the net.Conn read method.
+func (co *Conn) Read(p []byte) (n int, err error) {
+       if co.Conn == nil {
+               return 0, ErrConnEmpty
+       }
+       if len(p) < 2 {
+               return 0, io.ErrShortBuffer
+       }
+       switch t := co.Conn.(type) {
+       case *net.TCPConn, *tls.Conn:
+               r := t.(io.Reader)
+
+               l, err := tcpMsgLen(r)
+               if err != nil {
+                       return 0, err
+               }
+               if l > len(p) {
+                       return int(l), io.ErrShortBuffer
+               }
+               return tcpRead(r, p[:l])
+       }
+       // UDP connection
+       n, err = co.Conn.Read(p)
+       if err != nil {
+               return n, err
+       }
+       return n, err
+}
+
+// WriteMsg sends a message through the connection co.
+// If the message m contains a TSIG record the transaction
+// signature is calculated.
+func (co *Conn) WriteMsg(m *Msg) (err error) {
+       var out []byte
+       if t := m.IsTsig(); t != nil {
+               mac := ""
+               if _, ok := co.TsigSecret[t.Hdr.Name]; !ok {
+                       return ErrSecret
+               }
+               out, mac, err = TsigGenerate(m, co.TsigSecret[t.Hdr.Name], co.tsigRequestMAC, false)
+               // Set for the next read, although only used in zone transfers
+               co.tsigRequestMAC = mac
+       } else {
+               out, err = m.Pack()
+       }
+       if err != nil {
+               return err
+       }
+       co.t = time.Now()
+       if _, err = co.Write(out); err != nil {
+               return err
+       }
+       return nil
+}
+
+// Write implements the net.Conn Write method.
+func (co *Conn) Write(p []byte) (n int, err error) {
+       switch t := co.Conn.(type) {
+       case *net.TCPConn, *tls.Conn:
+               w := t.(io.Writer)
+
+               lp := len(p)
+               if lp < 2 {
+                       return 0, io.ErrShortBuffer
+               }
+               if lp > MaxMsgSize {
+                       return 0, &Error{err: "message too large"}
+               }
+               l := make([]byte, 2, lp+2)
+               binary.BigEndian.PutUint16(l, uint16(lp))
+               p = append(l, p...)
+               n, err := io.Copy(w, bytes.NewReader(p))
+               return int(n), err
+       }
+       n, err = co.Conn.(*net.UDPConn).Write(p)
+       return n, err
+}
+
+// Dial connects to the address on the named network.
+func Dial(network, address string) (conn *Conn, err error) {
+       conn = new(Conn)
+       conn.Conn, err = net.Dial(network, address)
+       if err != nil {
+               return nil, err
+       }
+       return conn, nil
+}
+
+// DialTimeout acts like Dial but takes a timeout.
+func DialTimeout(network, address string, timeout time.Duration) (conn *Conn, err error) {
+       conn = new(Conn)
+       conn.Conn, err = net.DialTimeout(network, address, timeout)
+       if err != nil {
+               return nil, err
+       }
+       return conn, nil
+}
+
+// DialWithTLS connects to the address on the named network with TLS.
+func DialWithTLS(network, address string, tlsConfig *tls.Config) (conn *Conn, err error) {
+       conn = new(Conn)
+       conn.Conn, err = tls.Dial(network, address, tlsConfig)
+       if err != nil {
+               return nil, err
+       }
+       return conn, nil
+}
+
+// DialTimeoutWithTLS acts like DialWithTLS but takes a timeout.
+func DialTimeoutWithTLS(network, address string, tlsConfig *tls.Config, timeout time.Duration) (conn *Conn, err error) {
+       var dialer net.Dialer
+       dialer.Timeout = timeout
+
+       conn = new(Conn)
+       conn.Conn, err = tls.DialWithDialer(&dialer, network, address, tlsConfig)
+       if err != nil {
+               return nil, err
+       }
+       return conn, nil
+}
+
+func deadlineOrTimeout(deadline time.Time, timeout time.Duration) time.Time {
+       if deadline.IsZero() {
+               return time.Now().Add(timeout)
+       }
+       return deadline
+}
diff --git a/vendor/github.com/miekg/dns/clientconfig.go b/vendor/github.com/miekg/dns/clientconfig.go
new file mode 100644 (file)
index 0000000..cfa9ad0
--- /dev/null
@@ -0,0 +1,99 @@
+package dns
+
+import (
+       "bufio"
+       "os"
+       "strconv"
+       "strings"
+)
+
+// ClientConfig wraps the contents of the /etc/resolv.conf file.
+type ClientConfig struct {
+       Servers  []string // servers to use
+       Search   []string // suffixes to append to local name
+       Port     string   // what port to use
+       Ndots    int      // number of dots in name to trigger absolute lookup
+       Timeout  int      // seconds before giving up on packet
+       Attempts int      // lost packets before giving up on server, not used in the package dns
+}
+
+// ClientConfigFromFile parses a resolv.conf(5) like file and returns
+// a *ClientConfig.
+func ClientConfigFromFile(resolvconf string) (*ClientConfig, error) {
+       file, err := os.Open(resolvconf)
+       if err != nil {
+               return nil, err
+       }
+       defer file.Close()
+       c := new(ClientConfig)
+       scanner := bufio.NewScanner(file)
+       c.Servers = make([]string, 0)
+       c.Search = make([]string, 0)
+       c.Port = "53"
+       c.Ndots = 1
+       c.Timeout = 5
+       c.Attempts = 2
+
+       for scanner.Scan() {
+               if err := scanner.Err(); err != nil {
+                       return nil, err
+               }
+               line := scanner.Text()
+               f := strings.Fields(line)
+               if len(f) < 1 {
+                       continue
+               }
+               switch f[0] {
+               case "nameserver": // add one name server
+                       if len(f) > 1 {
+                               // One more check: make sure server name is
+                               // just an IP address.  Otherwise we need DNS
+                               // to look it up.
+                               name := f[1]
+                               c.Servers = append(c.Servers, name)
+                       }
+
+               case "domain": // set search path to just this domain
+                       if len(f) > 1 {
+                               c.Search = make([]string, 1)
+                               c.Search[0] = f[1]
+                       } else {
+                               c.Search = make([]string, 0)
+                       }
+
+               case "search": // set search path to given servers
+                       c.Search = make([]string, len(f)-1)
+                       for i := 0; i < len(c.Search); i++ {
+                               c.Search[i] = f[i+1]
+                       }
+
+               case "options": // magic options
+                       for i := 1; i < len(f); i++ {
+                               s := f[i]
+                               switch {
+                               case len(s) >= 6 && s[:6] == "ndots:":
+                                       n, _ := strconv.Atoi(s[6:])
+                                       if n < 1 {
+                                               n = 1
+                                       }
+                                       c.Ndots = n
+                               case len(s) >= 8 && s[:8] == "timeout:":
+                                       n, _ := strconv.Atoi(s[8:])
+                                       if n < 1 {
+                                               n = 1
+                                       }
+                                       c.Timeout = n
+                               case len(s) >= 8 && s[:9] == "attempts:":
+                                       n, _ := strconv.Atoi(s[9:])
+                                       if n < 1 {
+                                               n = 1
+                                       }
+                                       c.Attempts = n
+                               case s == "rotate":
+                                       /* not imp */
+                               }
+                       }
+               }
+       }
+       return c, nil
+}
diff --git a/vendor/github.com/miekg/dns/defaults.go b/vendor/github.com/miekg/dns/defaults.go
new file mode 100644 (file)
index 0000000..cf45616
--- /dev/null
@@ -0,0 +1,282 @@
+package dns
+
+import (
+       "errors"
+       "net"
+       "strconv"
+)
+
+const hexDigit = "0123456789abcdef"
+
+// Everything is assumed in ClassINET.
+
+// SetReply creates a reply message from a request message.
+func (dns *Msg) SetReply(request *Msg) *Msg {
+       dns.Id = request.Id
+       dns.RecursionDesired = request.RecursionDesired // Copy rd bit
+       dns.Response = true
+       dns.Opcode = OpcodeQuery
+       dns.Rcode = RcodeSuccess
+       if len(request.Question) > 0 {
+               dns.Question = make([]Question, 1)
+               dns.Question[0] = request.Question[0]
+       }
+       return dns
+}
+
+// SetQuestion creates a question message, it sets the Question
+// section, generates an Id and sets the RecursionDesired (RD)
+// bit to true.
+func (dns *Msg) SetQuestion(z string, t uint16) *Msg {
+       dns.Id = Id()
+       dns.RecursionDesired = true
+       dns.Question = make([]Question, 1)
+       dns.Question[0] = Question{z, t, ClassINET}
+       return dns
+}
+
+// SetNotify creates a notify message, it sets the Question
+// section, generates an Id and sets the Authoritative (AA)
+// bit to true.
+func (dns *Msg) SetNotify(z string) *Msg {
+       dns.Opcode = OpcodeNotify
+       dns.Authoritative = true
+       dns.Id = Id()
+       dns.Question = make([]Question, 1)
+       dns.Question[0] = Question{z, TypeSOA, ClassINET}
+       return dns
+}
+
+// SetRcode creates an error message suitable for the request.
+func (dns *Msg) SetRcode(request *Msg, rcode int) *Msg {
+       dns.SetReply(request)
+       dns.Rcode = rcode
+       return dns
+}
+
+// SetRcodeFormatError creates a message with FormError set.
+func (dns *Msg) SetRcodeFormatError(request *Msg) *Msg {
+       dns.Rcode = RcodeFormatError
+       dns.Opcode = OpcodeQuery
+       dns.Response = true
+       dns.Authoritative = false
+       dns.Id = request.Id
+       return dns
+}
+
+// SetUpdate makes the message a dynamic update message. It
+// sets the ZONE section to: z, TypeSOA, ClassINET.
+func (dns *Msg) SetUpdate(z string) *Msg {
+       dns.Id = Id()
+       dns.Response = false
+       dns.Opcode = OpcodeUpdate
+       dns.Compress = false // BIND9 cannot handle compression
+       dns.Question = make([]Question, 1)
+       dns.Question[0] = Question{z, TypeSOA, ClassINET}
+       return dns
+}
+
+// SetIxfr creates message for requesting an IXFR.
+func (dns *Msg) SetIxfr(z string, serial uint32, ns, mbox string) *Msg {
+       dns.Id = Id()
+       dns.Question = make([]Question, 1)
+       dns.Ns = make([]RR, 1)
+       s := new(SOA)
+       s.Hdr = RR_Header{z, TypeSOA, ClassINET, defaultTtl, 0}
+       s.Serial = serial
+       s.Ns = ns
+       s.Mbox = mbox
+       dns.Question[0] = Question{z, TypeIXFR, ClassINET}
+       dns.Ns[0] = s
+       return dns
+}
+
+// SetAxfr creates message for requesting an AXFR.
+func (dns *Msg) SetAxfr(z string) *Msg {
+       dns.Id = Id()
+       dns.Question = make([]Question, 1)
+       dns.Question[0] = Question{z, TypeAXFR, ClassINET}
+       return dns
+}
+
+// SetTsig appends a TSIG RR to the message.
+// This is only a skeleton TSIG RR that is added as the last RR in the
+// additional section. The Tsig is calculated when the message is being send.
+func (dns *Msg) SetTsig(z, algo string, fudge, timesigned int64) *Msg {
+       t := new(TSIG)
+       t.Hdr = RR_Header{z, TypeTSIG, ClassANY, 0, 0}
+       t.Algorithm = algo
+       t.Fudge = 300
+       t.TimeSigned = uint64(timesigned)
+       t.OrigId = dns.Id
+       dns.Extra = append(dns.Extra, t)
+       return dns
+}
+
+// SetEdns0 appends a EDNS0 OPT RR to the message.
+// TSIG should always the last RR in a message.
+func (dns *Msg) SetEdns0(udpsize uint16, do bool) *Msg {
+       e := new(OPT)
+       e.Hdr.Name = "."
+       e.Hdr.Rrtype = TypeOPT
+       e.SetUDPSize(udpsize)
+       if do {
+               e.SetDo()
+       }
+       dns.Extra = append(dns.Extra, e)
+       return dns
+}
+
+// IsTsig checks if the message has a TSIG record as the last record
+// in the additional section. It returns the TSIG record found or nil.
+func (dns *Msg) IsTsig() *TSIG {
+       if len(dns.Extra) > 0 {
+               if dns.Extra[len(dns.Extra)-1].Header().Rrtype == TypeTSIG {
+                       return dns.Extra[len(dns.Extra)-1].(*TSIG)
+               }
+       }
+       return nil
+}
+
+// IsEdns0 checks if the message has a EDNS0 (OPT) record, any EDNS0
+// record in the additional section will do. It returns the OPT record
+// found or nil.
+func (dns *Msg) IsEdns0() *OPT {
+       // EDNS0 is at the end of the additional section, start there.
+       // We might want to change this to *only* look at the last two
+       // records. So we see TSIG and/or OPT - this a slightly bigger
+       // change though.
+       for i := len(dns.Extra) - 1; i >= 0; i-- {
+               if dns.Extra[i].Header().Rrtype == TypeOPT {
+                       return dns.Extra[i].(*OPT)
+               }
+       }
+       return nil
+}
+
+// IsDomainName checks if s is a valid domain name, it returns the number of
+// labels and true, when a domain name is valid.  Note that non fully qualified
+// domain name is considered valid, in this case the last label is counted in
+// the number of labels.  When false is returned the number of labels is not
+// defined.  Also note that this function is extremely liberal; almost any
+// string is a valid domain name as the DNS is 8 bit protocol. It checks if each
+// label fits in 63 characters, but there is no length check for the entire
+// string s. I.e.  a domain name longer than 255 characters is considered valid.
+func IsDomainName(s string) (labels int, ok bool) {
+       _, labels, err := packDomainName(s, nil, 0, nil, false)
+       return labels, err == nil
+}
+
+// IsSubDomain checks if child is indeed a child of the parent. If child and parent
+// are the same domain true is returned as well.
+func IsSubDomain(parent, child string) bool {
+       // Entire child is contained in parent
+       return CompareDomainName(parent, child) == CountLabel(parent)
+}
+
+// IsMsg sanity checks buf and returns an error if it isn't a valid DNS packet.
+// The checking is performed on the binary payload.
+func IsMsg(buf []byte) error {
+       // Header
+       if len(buf) < 12 {
+               return errors.New("dns: bad message header")
+       }
+       // Header: Opcode
+       // TODO(miek): more checks here, e.g. check all header bits.
+       return nil
+}
+
+// IsFqdn checks if a domain name is fully qualified.
+func IsFqdn(s string) bool {
+       l := len(s)
+       if l == 0 {
+               return false
+       }
+       return s[l-1] == '.'
+}
+
+// IsRRset checks if a set of RRs is a valid RRset as defined by RFC 2181.
+// This means the RRs need to have the same type, name, and class. Returns true
+// if the RR set is valid, otherwise false.
+func IsRRset(rrset []RR) bool {
+       if len(rrset) == 0 {
+               return false
+       }
+       if len(rrset) == 1 {
+               return true
+       }
+       rrHeader := rrset[0].Header()
+       rrType := rrHeader.Rrtype
+       rrClass := rrHeader.Class
+       rrName := rrHeader.Name
+
+       for _, rr := range rrset[1:] {
+               curRRHeader := rr.Header()
+               if curRRHeader.Rrtype != rrType || curRRHeader.Class != rrClass || curRRHeader.Name != rrName {
+                       // Mismatch between the records, so this is not a valid rrset for
+                       //signing/verifying
+                       return false
+               }
+       }
+
+       return true
+}
+
+// Fqdn return the fully qualified domain name from s.
+// If s is already fully qualified, it behaves as the identity function.
+func Fqdn(s string) string {
+       if IsFqdn(s) {
+               return s
+       }
+       return s + "."
+}
+
+// Copied from the official Go code.
+
+// ReverseAddr returns the in-addr.arpa. or ip6.arpa. hostname of the IP
+// address suitable for reverse DNS (PTR) record lookups or an error if it fails
+// to parse the IP address.
+func ReverseAddr(addr string) (arpa string, err error) {
+       ip := net.ParseIP(addr)
+       if ip == nil {
+               return "", &Error{err: "unrecognized address: " + addr}
+       }
+       if ip.To4() != nil {
+               return strconv.Itoa(int(ip[15])) + "." + strconv.Itoa(int(ip[14])) + "." + strconv.Itoa(int(ip[13])) + "." +
+                       strconv.Itoa(int(ip[12])) + ".in-addr.arpa.", nil
+       }
+       // Must be IPv6
+       buf := make([]byte, 0, len(ip)*4+len("ip6.arpa."))
+       // Add it, in reverse, to the buffer
+       for i := len(ip) - 1; i >= 0; i-- {
+               v := ip[i]
+               buf = append(buf, hexDigit[v&0xF])
+               buf = append(buf, '.')
+               buf = append(buf, hexDigit[v>>4])
+               buf = append(buf, '.')
+       }
+       // Append "ip6.arpa." and return (buf already has the final .)
+       buf = append(buf, "ip6.arpa."...)
+       return string(buf), nil
+}
+
+// String returns the string representation for the type t.
+func (t Type) String() string {
+       if t1, ok := TypeToString[uint16(t)]; ok {
+               return t1
+       }
+       return "TYPE" + strconv.Itoa(int(t))
+}
+
+// String returns the string representation for the class c.
+func (c Class) String() string {
+       if c1, ok := ClassToString[uint16(c)]; ok {
+               return c1
+       }
+       return "CLASS" + strconv.Itoa(int(c))
+}
+
+// String returns the string representation for the name n.
+func (n Name) String() string {
+       return sprintName(string(n))
+}
diff --git a/vendor/github.com/miekg/dns/dns.go b/vendor/github.com/miekg/dns/dns.go
new file mode 100644 (file)
index 0000000..b329228
--- /dev/null
@@ -0,0 +1,104 @@
+package dns
+
+import "strconv"
+
+const (
+       year68     = 1 << 31 // For RFC1982 (Serial Arithmetic) calculations in 32 bits.
+       defaultTtl = 3600    // Default internal TTL.
+
+       DefaultMsgSize = 4096  // DefaultMsgSize is the standard default for messages larger than 512 bytes.
+       MinMsgSize     = 512   // MinMsgSize is the minimal size of a DNS packet.
+       MaxMsgSize     = 65535 // MaxMsgSize is the largest possible DNS packet.
+)
+
+// Error represents a DNS error.
+type Error struct{ err string }
+
+func (e *Error) Error() string {
+       if e == nil {
+               return "dns: <nil>"
+       }
+       return "dns: " + e.err
+}
+
+// An RR represents a resource record.
+type RR interface {
+       // Header returns the header of an resource record. The header contains
+       // everything up to the rdata.
+       Header() *RR_Header
+       // String returns the text representation of the resource record.
+       String() string
+
+       // copy returns a copy of the RR
+       copy() RR
+       // len returns the length (in octets) of the uncompressed RR in wire format.
+       len() int
+       // pack packs an RR into wire format.
+       pack([]byte, int, map[string]int, bool) (int, error)
+}
+
+// RR_Header is the header all DNS resource records share.
+type RR_Header struct {
+       Name     string `dns:"cdomain-name"`
+       Rrtype   uint16
+       Class    uint16
+       Ttl      uint32
+       Rdlength uint16 // Length of data after header.
+}
+
+// Header returns itself. This is here to make RR_Header implements the RR interface.
+func (h *RR_Header) Header() *RR_Header { return h }
+
+// Just to implement the RR interface.
+func (h *RR_Header) copy() RR { return nil }
+
+func (h *RR_Header) copyHeader() *RR_Header {
+       r := new(RR_Header)
+       r.Name = h.Name
+       r.Rrtype = h.Rrtype
+       r.Class = h.Class
+       r.Ttl = h.Ttl
+       r.Rdlength = h.Rdlength
+       return r
+}
+
+func (h *RR_Header) String() string {
+       var s string
+
+       if h.Rrtype == TypeOPT {
+               s = ";"
+               // and maybe other things
+       }
+
+       s += sprintName(h.Name) + "\t"
+       s += strconv.FormatInt(int64(h.Ttl), 10) + "\t"
+       s += Class(h.Class).String() + "\t"
+       s += Type(h.Rrtype).String() + "\t"
+       return s
+}
+
+func (h *RR_Header) len() int {
+       l := len(h.Name) + 1
+       l += 10 // rrtype(2) + class(2) + ttl(4) + rdlength(2)
+       return l
+}
+
+// ToRFC3597 converts a known RR to the unknown RR representation from RFC 3597.
+func (rr *RFC3597) ToRFC3597(r RR) error {
+       buf := make([]byte, r.len()*2)
+       off, err := PackRR(r, buf, 0, nil, false)
+       if err != nil {
+               return err
+       }
+       buf = buf[:off]
+       if int(r.Header().Rdlength) > off {
+               return ErrBuf
+       }
+
+       rfc3597, _, err := unpackRFC3597(*r.Header(), buf, off-int(r.Header().Rdlength))
+       if err != nil {
+               return err
+       }
+       *rr = *rfc3597.(*RFC3597)
+       return nil
+}
diff --git a/vendor/github.com/miekg/dns/dnssec.go b/vendor/github.com/miekg/dns/dnssec.go
new file mode 100644 (file)
index 0000000..f5f3fbd
--- /dev/null
@@ -0,0 +1,721 @@
+package dns
+
+import (
+       "bytes"
+       "crypto"
+       "crypto/dsa"
+       "crypto/ecdsa"
+       "crypto/elliptic"
+       _ "crypto/md5"
+       "crypto/rand"
+       "crypto/rsa"
+       _ "crypto/sha1"
+       _ "crypto/sha256"
+       _ "crypto/sha512"
+       "encoding/asn1"
+       "encoding/binary"
+       "encoding/hex"
+       "math/big"
+       "sort"
+       "strings"
+       "time"
+)
+
+// DNSSEC encryption algorithm codes.
+const (
+       _ uint8 = iota
+       RSAMD5
+       DH
+       DSA
+       _ // Skip 4, RFC 6725, section 2.1
+       RSASHA1
+       DSANSEC3SHA1
+       RSASHA1NSEC3SHA1
+       RSASHA256
+       _ // Skip 9, RFC 6725, section 2.1
+       RSASHA512
+       _ // Skip 11, RFC 6725, section 2.1
+       ECCGOST
+       ECDSAP256SHA256
+       ECDSAP384SHA384
+       INDIRECT   uint8 = 252
+       PRIVATEDNS uint8 = 253 // Private (experimental keys)
+       PRIVATEOID uint8 = 254
+)
+
+// Map for algorithm names.
+var AlgorithmToString = map[uint8]string{
+       RSAMD5:           "RSAMD5",
+       DH:               "DH",
+       DSA:              "DSA",
+       RSASHA1:          "RSASHA1",
+       DSANSEC3SHA1:     "DSA-NSEC3-SHA1",
+       RSASHA1NSEC3SHA1: "RSASHA1-NSEC3-SHA1",
+       RSASHA256:        "RSASHA256",
+       RSASHA512:        "RSASHA512",
+       ECCGOST:          "ECC-GOST",
+       ECDSAP256SHA256:  "ECDSAP256SHA256",
+       ECDSAP384SHA384:  "ECDSAP384SHA384",
+       INDIRECT:         "INDIRECT",
+       PRIVATEDNS:       "PRIVATEDNS",
+       PRIVATEOID:       "PRIVATEOID",
+}
+
+// Map of algorithm strings.
+var StringToAlgorithm = reverseInt8(AlgorithmToString)
+
+// Map of algorithm crypto hashes.
+var AlgorithmToHash = map[uint8]crypto.Hash{
+       RSAMD5:           crypto.MD5, // Deprecated in RFC 6725
+       RSASHA1:          crypto.SHA1,
+       RSASHA1NSEC3SHA1: crypto.SHA1,
+       RSASHA256:        crypto.SHA256,
+       ECDSAP256SHA256:  crypto.SHA256,
+       ECDSAP384SHA384:  crypto.SHA384,
+       RSASHA512:        crypto.SHA512,
+}
+
+// DNSSEC hashing algorithm codes.
+const (
+       _      uint8 = iota
+       SHA1         // RFC 4034
+       SHA256       // RFC 4509
+       GOST94       // RFC 5933
+       SHA384       // Experimental
+       SHA512       // Experimental
+)
+
+// Map for hash names.
+var HashToString = map[uint8]string{
+       SHA1:   "SHA1",
+       SHA256: "SHA256",
+       GOST94: "GOST94",
+       SHA384: "SHA384",
+       SHA512: "SHA512",
+}
+
+// Map of hash strings.
+var StringToHash = reverseInt8(HashToString)
+
+// DNSKEY flag values.
+const (
+       SEP    = 1
+       REVOKE = 1 << 7
+       ZONE   = 1 << 8
+)
+
+// The RRSIG needs to be converted to wireformat with some of the rdata (the signature) missing.
+type rrsigWireFmt struct {
+       TypeCovered uint16
+       Algorithm   uint8
+       Labels      uint8
+       OrigTtl     uint32
+       Expiration  uint32
+       Inception   uint32
+       KeyTag      uint16
+       SignerName  string `dns:"domain-name"`
+       /* No Signature */
+}
+
+// Used for converting DNSKEY's rdata to wirefmt.
+type dnskeyWireFmt struct {
+       Flags     uint16
+       Protocol  uint8
+       Algorithm uint8
+       PublicKey string `dns:"base64"`
+       /* Nothing is left out */
+}
+
+func divRoundUp(a, b int) int {
+       return (a + b - 1) / b
+}
+
+// KeyTag calculates the keytag (or key-id) of the DNSKEY.
+func (k *DNSKEY) KeyTag() uint16 {
+       if k == nil {
+               return 0
+       }
+       var keytag int
+       switch k.Algorithm {
+       case RSAMD5:
+               // Look at the bottom two bytes of the modules, which the last
+               // item in the pubkey. We could do this faster by looking directly
+               // at the base64 values. But I'm lazy.
+               modulus, _ := fromBase64([]byte(k.PublicKey))
+               if len(modulus) > 1 {
+                       x := binary.BigEndian.Uint16(modulus[len(modulus)-2:])
+                       keytag = int(x)
+               }
+       default:
+               keywire := new(dnskeyWireFmt)
+               keywire.Flags = k.Flags
+               keywire.Protocol = k.Protocol
+               keywire.Algorithm = k.Algorithm
+               keywire.PublicKey = k.PublicKey
+               wire := make([]byte, DefaultMsgSize)
+               n, err := packKeyWire(keywire, wire)
+               if err != nil {
+                       return 0
+               }
+               wire = wire[:n]
+               for i, v := range wire {
+                       if i&1 != 0 {
+                               keytag += int(v) // must be larger than uint32
+                       } else {
+                               keytag += int(v) << 8
+                       }
+               }
+               keytag += (keytag >> 16) & 0xFFFF
+               keytag &= 0xFFFF
+       }
+       return uint16(keytag)
+}
+
+// ToDS converts a DNSKEY record to a DS record.
+func (k *DNSKEY) ToDS(h uint8) *DS {
+       if k == nil {
+               return nil
+       }
+       ds := new(DS)
+       ds.Hdr.Name = k.Hdr.Name
+       ds.Hdr.Class = k.Hdr.Class
+       ds.Hdr.Rrtype = TypeDS
+       ds.Hdr.Ttl = k.Hdr.Ttl
+       ds.Algorithm = k.Algorithm
+       ds.DigestType = h
+       ds.KeyTag = k.KeyTag()
+
+       keywire := new(dnskeyWireFmt)
+       keywire.Flags = k.Flags
+       keywire.Protocol = k.Protocol
+       keywire.Algorithm = k.Algorithm
+       keywire.PublicKey = k.PublicKey
+       wire := make([]byte, DefaultMsgSize)
+       n, err := packKeyWire(keywire, wire)
+       if err != nil {
+               return nil
+       }
+       wire = wire[:n]
+
+       owner := make([]byte, 255)
+       off, err1 := PackDomainName(strings.ToLower(k.Hdr.Name), owner, 0, nil, false)
+       if err1 != nil {
+               return nil
+       }
+       owner = owner[:off]
+       // RFC4034:
+       // digest = digest_algorithm( DNSKEY owner name | DNSKEY RDATA);
+       // "|" denotes concatenation
+       // DNSKEY RDATA = Flags | Protocol | Algorithm | Public Key.
+
+       // digest buffer
+       digest := append(owner, wire...) // another copy
+
+       var hash crypto.Hash
+       switch h {
+       case SHA1:
+               hash = crypto.SHA1
+       case SHA256:
+               hash = crypto.SHA256
+       case SHA384:
+               hash = crypto.SHA384
+       case SHA512:
+               hash = crypto.SHA512
+       default:
+               return nil
+       }
+
+       s := hash.New()
+       s.Write(digest)
+       ds.Digest = hex.EncodeToString(s.Sum(nil))
+       return ds
+}
+
+// ToCDNSKEY converts a DNSKEY record to a CDNSKEY record.
+func (k *DNSKEY) ToCDNSKEY() *CDNSKEY {
+       c := &CDNSKEY{DNSKEY: *k}
+       c.Hdr = *k.Hdr.copyHeader()
+       c.Hdr.Rrtype = TypeCDNSKEY
+       return c
+}
+
+// ToCDS converts a DS record to a CDS record.
+func (d *DS) ToCDS() *CDS {
+       c := &CDS{DS: *d}
+       c.Hdr = *d.Hdr.copyHeader()
+       c.Hdr.Rrtype = TypeCDS
+       return c
+}
+
+// Sign signs an RRSet. The signature needs to be filled in with the values:
+// Inception, Expiration, KeyTag, SignerName and Algorithm.  The rest is copied
+// from the RRset. Sign returns a non-nill error when the signing went OK.
+// There is no check if RRSet is a proper (RFC 2181) RRSet.  If OrigTTL is non
+// zero, it is used as-is, otherwise the TTL of the RRset is used as the
+// OrigTTL.
+func (rr *RRSIG) Sign(k crypto.Signer, rrset []RR) error {
+       if k == nil {
+               return ErrPrivKey
+       }
+       // s.Inception and s.Expiration may be 0 (rollover etc.), the rest must be set
+       if rr.KeyTag == 0 || len(rr.SignerName) == 0 || rr.Algorithm == 0 {
+               return ErrKey
+       }
+
+       rr.Hdr.Rrtype = TypeRRSIG
+       rr.Hdr.Name = rrset[0].Header().Name
+       rr.Hdr.Class = rrset[0].Header().Class
+       if rr.OrigTtl == 0 { // If set don't override
+               rr.OrigTtl = rrset[0].Header().Ttl
+       }
+       rr.TypeCovered = rrset[0].Header().Rrtype
+       rr.Labels = uint8(CountLabel(rrset[0].Header().Name))
+
+       if strings.HasPrefix(rrset[0].Header().Name, "*") {
+               rr.Labels-- // wildcard, remove from label count
+       }
+
+       sigwire := new(rrsigWireFmt)
+       sigwire.TypeCovered = rr.TypeCovered
+       sigwire.Algorithm = rr.Algorithm
+       sigwire.Labels = rr.Labels
+       sigwire.OrigTtl = rr.OrigTtl
+       sigwire.Expiration = rr.Expiration
+       sigwire.Inception = rr.Inception
+       sigwire.KeyTag = rr.KeyTag
+       // For signing, lowercase this name
+       sigwire.SignerName = strings.ToLower(rr.SignerName)
+
+       // Create the desired binary blob
+       signdata := make([]byte, DefaultMsgSize)
+       n, err := packSigWire(sigwire, signdata)
+       if err != nil {
+               return err
+       }
+       signdata = signdata[:n]
+       wire, err := rawSignatureData(rrset, rr)
+       if err != nil {
+               return err
+       }
+       signdata = append(signdata, wire...)
+
+       hash, ok := AlgorithmToHash[rr.Algorithm]
+       if !ok {
+               return ErrAlg
+       }
+
+       h := hash.New()
+       h.Write(signdata)
+
+       signature, err := sign(k, h.Sum(nil), hash, rr.Algorithm)
+       if err != nil {
+               return err
+       }
+
+       rr.Signature = toBase64(signature)
+
+       return nil
+}
+
+func sign(k crypto.Signer, hashed []byte, hash crypto.Hash, alg uint8) ([]byte, error) {
+       signature, err := k.Sign(rand.Reader, hashed, hash)
+       if err != nil {
+               return nil, err
+       }
+
+       switch alg {
+       case RSASHA1, RSASHA1NSEC3SHA1, RSASHA256, RSASHA512:
+               return signature, nil
+
+       case ECDSAP256SHA256, ECDSAP384SHA384:
+               ecdsaSignature := &struct {
+                       R, S *big.Int
+               }{}
+               if _, err := asn1.Unmarshal(signature, ecdsaSignature); err != nil {
+                       return nil, err
+               }
+
+               var intlen int
+               switch alg {
+               case ECDSAP256SHA256:
+                       intlen = 32
+               case ECDSAP384SHA384:
+                       intlen = 48
+               }
+
+               signature := intToBytes(ecdsaSignature.R, intlen)
+               signature = append(signature, intToBytes(ecdsaSignature.S, intlen)...)
+               return signature, nil
+
+       // There is no defined interface for what a DSA backed crypto.Signer returns
+       case DSA, DSANSEC3SHA1:
+               //      t := divRoundUp(divRoundUp(p.PublicKey.Y.BitLen(), 8)-64, 8)
+               //      signature := []byte{byte(t)}
+               //      signature = append(signature, intToBytes(r1, 20)...)
+               //      signature = append(signature, intToBytes(s1, 20)...)
+               //      rr.Signature = signature
+       }
+
+       return nil, ErrAlg
+}
+
+// Verify validates an RRSet with the signature and key. This is only the
+// cryptographic test, the signature validity period must be checked separately.
+// This function copies the rdata of some RRs (to lowercase domain names) for the validation to work.
+func (rr *RRSIG) Verify(k *DNSKEY, rrset []RR) error {
+       // First the easy checks
+       if !IsRRset(rrset) {
+               return ErrRRset
+       }
+       if rr.KeyTag != k.KeyTag() {
+               return ErrKey
+       }
+       if rr.Hdr.Class != k.Hdr.Class {
+               return ErrKey
+       }
+       if rr.Algorithm != k.Algorithm {
+               return ErrKey
+       }
+       if strings.ToLower(rr.SignerName) != strings.ToLower(k.Hdr.Name) {
+               return ErrKey
+       }
+       if k.Protocol != 3 {
+               return ErrKey
+       }
+
+       // IsRRset checked that we have at least one RR and that the RRs in
+       // the set have consistent type, class, and name. Also check that type and
+       // class matches the RRSIG record.
+       if rrset[0].Header().Class != rr.Hdr.Class {
+               return ErrRRset
+       }
+       if rrset[0].Header().Rrtype != rr.TypeCovered {
+               return ErrRRset
+       }
+
+       // RFC 4035 5.3.2.  Reconstructing the Signed Data
+       // Copy the sig, except the rrsig data
+       sigwire := new(rrsigWireFmt)
+       sigwire.TypeCovered = rr.TypeCovered
+       sigwire.Algorithm = rr.Algorithm
+       sigwire.Labels = rr.Labels
+       sigwire.OrigTtl = rr.OrigTtl
+       sigwire.Expiration = rr.Expiration
+       sigwire.Inception = rr.Inception
+       sigwire.KeyTag = rr.KeyTag
+       sigwire.SignerName = strings.ToLower(rr.SignerName)
+       // Create the desired binary blob
+       signeddata := make([]byte, DefaultMsgSize)
+       n, err := packSigWire(sigwire, signeddata)
+       if err != nil {
+               return err
+       }
+       signeddata = signeddata[:n]
+       wire, err := rawSignatureData(rrset, rr)
+       if err != nil {
+               return err
+       }
+       signeddata = append(signeddata, wire...)
+
+       sigbuf := rr.sigBuf()           // Get the binary signature data
+       if rr.Algorithm == PRIVATEDNS { // PRIVATEOID
+               // TODO(miek)
+               // remove the domain name and assume its ours?
+       }
+
+       hash, ok := AlgorithmToHash[rr.Algorithm]
+       if !ok {
+               return ErrAlg
+       }
+
+       switch rr.Algorithm {
+       case RSASHA1, RSASHA1NSEC3SHA1, RSASHA256, RSASHA512, RSAMD5:
+               // TODO(mg): this can be done quicker, ie. cache the pubkey data somewhere??
+               pubkey := k.publicKeyRSA() // Get the key
+               if pubkey == nil {
+                       return ErrKey
+               }
+
+               h := hash.New()
+               h.Write(signeddata)
+               return rsa.VerifyPKCS1v15(pubkey, hash, h.Sum(nil), sigbuf)
+
+       case ECDSAP256SHA256, ECDSAP384SHA384:
+               pubkey := k.publicKeyECDSA()
+               if pubkey == nil {
+                       return ErrKey
+               }
+
+               // Split sigbuf into the r and s coordinates
+               r := new(big.Int).SetBytes(sigbuf[:len(sigbuf)/2])
+               s := new(big.Int).SetBytes(sigbuf[len(sigbuf)/2:])
+
+               h := hash.New()
+               h.Write(signeddata)
+               if ecdsa.Verify(pubkey, h.Sum(nil), r, s) {
+                       return nil
+               }
+               return ErrSig
+
+       default:
+               return ErrAlg
+       }
+}
+
+// ValidityPeriod uses RFC1982 serial arithmetic to calculate
+// if a signature period is valid. If t is the zero time, the
+// current time is taken other t is. Returns true if the signature
+// is valid at the given time, otherwise returns false.
+func (rr *RRSIG) ValidityPeriod(t time.Time) bool {
+       var utc int64
+       if t.IsZero() {
+               utc = time.Now().UTC().Unix()
+       } else {
+               utc = t.UTC().Unix()
+       }
+       modi := (int64(rr.Inception) - utc) / year68
+       mode := (int64(rr.Expiration) - utc) / year68
+       ti := int64(rr.Inception) + (modi * year68)
+       te := int64(rr.Expiration) + (mode * year68)
+       return ti <= utc && utc <= te
+}
+
+// Return the signatures base64 encodedig sigdata as a byte slice.
+func (rr *RRSIG) sigBuf() []byte {
+       sigbuf, err := fromBase64([]byte(rr.Signature))
+       if err != nil {
+               return nil
+       }
+       return sigbuf
+}
+
+// publicKeyRSA returns the RSA public key from a DNSKEY record.
+func (k *DNSKEY) publicKeyRSA() *rsa.PublicKey {
+       keybuf, err := fromBase64([]byte(k.PublicKey))
+       if err != nil {
+               return nil
+       }
+
+       // RFC 2537/3110, section 2. RSA Public KEY Resource Records
+       // Length is in the 0th byte, unless its zero, then it
+       // it in bytes 1 and 2 and its a 16 bit number
+       explen := uint16(keybuf[0])
+       keyoff := 1
+       if explen == 0 {
+               explen = uint16(keybuf[1])<<8 | uint16(keybuf[2])
+               keyoff = 3
+       }
+       pubkey := new(rsa.PublicKey)
+
+       pubkey.N = big.NewInt(0)
+       shift := uint64((explen - 1) * 8)
+       expo := uint64(0)
+       for i := int(explen - 1); i > 0; i-- {
+               expo += uint64(keybuf[keyoff+i]) << shift
+               shift -= 8
+       }
+       // Remainder
+       expo += uint64(keybuf[keyoff])
+       if expo > 2<<31 {
+               // Larger expo than supported.
+               // println("dns: F5 primes (or larger) are not supported")
+               return nil
+       }
+       pubkey.E = int(expo)
+
+       pubkey.N.SetBytes(keybuf[keyoff+int(explen):])
+       return pubkey
+}
+
+// publicKeyECDSA returns the Curve public key from the DNSKEY record.
+func (k *DNSKEY) publicKeyECDSA() *ecdsa.PublicKey {
+       keybuf, err := fromBase64([]byte(k.PublicKey))
+       if err != nil {
+               return nil
+       }
+       pubkey := new(ecdsa.PublicKey)
+       switch k.Algorithm {
+       case ECDSAP256SHA256:
+               pubkey.Curve = elliptic.P256()
+               if len(keybuf) != 64 {
+                       // wrongly encoded key
+                       return nil
+               }
+       case ECDSAP384SHA384:
+               pubkey.Curve = elliptic.P384()
+               if len(keybuf) != 96 {
+                       // Wrongly encoded key
+                       return nil
+               }
+       }
+       pubkey.X = big.NewInt(0)
+       pubkey.X.SetBytes(keybuf[:len(keybuf)/2])
+       pubkey.Y = big.NewInt(0)
+       pubkey.Y.SetBytes(keybuf[len(keybuf)/2:])
+       return pubkey
+}
+
+func (k *DNSKEY) publicKeyDSA() *dsa.PublicKey {
+       keybuf, err := fromBase64([]byte(k.PublicKey))
+       if err != nil {
+               return nil
+       }
+       if len(keybuf) < 22 {
+               return nil
+       }
+       t, keybuf := int(keybuf[0]), keybuf[1:]
+       size := 64 + t*8
+       q, keybuf := keybuf[:20], keybuf[20:]
+       if len(keybuf) != 3*size {
+               return nil
+       }
+       p, keybuf := keybuf[:size], keybuf[size:]
+       g, y := keybuf[:size], keybuf[size:]
+       pubkey := new(dsa.PublicKey)
+       pubkey.Parameters.Q = big.NewInt(0).SetBytes(q)
+       pubkey.Parameters.P = big.NewInt(0).SetBytes(p)
+       pubkey.Parameters.G = big.NewInt(0).SetBytes(g)
+       pubkey.Y = big.NewInt(0).SetBytes(y)
+       return pubkey
+}
+
+type wireSlice [][]byte
+
+func (p wireSlice) Len() int      { return len(p) }
+func (p wireSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
+func (p wireSlice) Less(i, j int) bool {
+       _, ioff, _ := UnpackDomainName(p[i], 0)
+       _, joff, _ := UnpackDomainName(p[j], 0)
+       return bytes.Compare(p[i][ioff+10:], p[j][joff+10:]) < 0
+}
+
+// Return the raw signature data.
+func rawSignatureData(rrset []RR, s *RRSIG) (buf []byte, err error) {
+       wires := make(wireSlice, len(rrset))
+       for i, r := range rrset {
+               r1 := r.copy()
+               r1.Header().Ttl = s.OrigTtl
+               labels := SplitDomainName(r1.Header().Name)
+               // 6.2. Canonical RR Form. (4) - wildcards
+               if len(labels) > int(s.Labels) {
+                       // Wildcard
+                       r1.Header().Name = "*." + strings.Join(labels[len(labels)-int(s.Labels):], ".") + "."
+               }
+               // RFC 4034: 6.2.  Canonical RR Form. (2) - domain name to lowercase
+               r1.Header().Name = strings.ToLower(r1.Header().Name)
+               // 6.2. Canonical RR Form. (3) - domain rdata to lowercase.
+               //   NS, MD, MF, CNAME, SOA, MB, MG, MR, PTR,
+               //   HINFO, MINFO, MX, RP, AFSDB, RT, SIG, PX, NXT, NAPTR, KX,
+               //   SRV, DNAME, A6
+               //
+               // RFC 6840 - Clarifications and Implementation Notes for DNS Security (DNSSEC):
+               //      Section 6.2 of [RFC4034] also erroneously lists HINFO as a record
+               //      that needs conversion to lowercase, and twice at that.  Since HINFO
+               //      records contain no domain names, they are not subject to case
+               //      conversion.
+               switch x := r1.(type) {
+               case *NS:
+                       x.Ns = strings.ToLower(x.Ns)
+               case *CNAME:
+                       x.Target = strings.ToLower(x.Target)
+               case *SOA:
+                       x.Ns = strings.ToLower(x.Ns)
+                       x.Mbox = strings.ToLower(x.Mbox)
+               case *MB:
+                       x.Mb = strings.ToLower(x.Mb)
+               case *MG:
+                       x.Mg = strings.ToLower(x.Mg)
+               case *MR:
+                       x.Mr = strings.ToLower(x.Mr)
+               case *PTR:
+                       x.Ptr = strings.ToLower(x.Ptr)
+               case *MINFO:
+                       x.Rmail = strings.ToLower(x.Rmail)
+                       x.Email = strings.ToLower(x.Email)
+               case *MX:
+                       x.Mx = strings.ToLower(x.Mx)
+               case *NAPTR:
+                       x.Replacement = strings.ToLower(x.Replacement)
+               case *KX:
+                       x.Exchanger = strings.ToLower(x.Exchanger)
+               case *SRV:
+                       x.Target = strings.ToLower(x.Target)
+               case *DNAME:
+                       x.Target = strings.ToLower(x.Target)
+               }
+               // 6.2. Canonical RR Form. (5) - origTTL
+               wire := make([]byte, r1.len()+1) // +1 to be safe(r)
+               off, err1 := PackRR(r1, wire, 0, nil, false)
+               if err1 != nil {
+                       return nil, err1
+               }
+               wire = wire[:off]
+               wires[i] = wire
+       }
+       sort.Sort(wires)
+       for i, wire := range wires {
+               if i > 0 && bytes.Equal(wire, wires[i-1]) {
+                       continue
+               }
+               buf = append(buf, wire...)
+       }
+       return buf, nil
+}
+
+func packSigWire(sw *rrsigWireFmt, msg []byte) (int, error) {
+       // copied from zmsg.go RRSIG packing
+       off, err := packUint16(sw.TypeCovered, msg, 0)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint8(sw.Algorithm, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint8(sw.Labels, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint32(sw.OrigTtl, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint32(sw.Expiration, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint32(sw.Inception, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint16(sw.KeyTag, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = PackDomainName(sw.SignerName, msg, off, nil, false)
+       if err != nil {
+               return off, err
+       }
+       return off, nil
+}
+
+func packKeyWire(dw *dnskeyWireFmt, msg []byte) (int, error) {
+       // copied from zmsg.go DNSKEY packing
+       off, err := packUint16(dw.Flags, msg, 0)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint8(dw.Protocol, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint8(dw.Algorithm, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packStringBase64(dw.PublicKey, msg, off)
+       if err != nil {
+               return off, err
+       }
+       return off, nil
+}
diff --git a/vendor/github.com/miekg/dns/dnssec_keygen.go b/vendor/github.com/miekg/dns/dnssec_keygen.go
new file mode 100644 (file)
index 0000000..229a079
--- /dev/null
@@ -0,0 +1,156 @@
+package dns
+
+import (
+       "crypto"
+       "crypto/dsa"
+       "crypto/ecdsa"
+       "crypto/elliptic"
+       "crypto/rand"
+       "crypto/rsa"
+       "math/big"
+)
+
+// Generate generates a DNSKEY of the given bit size.
+// The public part is put inside the DNSKEY record.
+// The Algorithm in the key must be set as this will define
+// what kind of DNSKEY will be generated.
+// The ECDSA algorithms imply a fixed keysize, in that case
+// bits should be set to the size of the algorithm.
+func (k *DNSKEY) Generate(bits int) (crypto.PrivateKey, error) {
+       switch k.Algorithm {
+       case DSA, DSANSEC3SHA1:
+               if bits != 1024 {
+                       return nil, ErrKeySize
+               }
+       case RSAMD5, RSASHA1, RSASHA256, RSASHA1NSEC3SHA1:
+               if bits < 512 || bits > 4096 {
+                       return nil, ErrKeySize
+               }
+       case RSASHA512:
+               if bits < 1024 || bits > 4096 {
+                       return nil, ErrKeySize
+               }
+       case ECDSAP256SHA256:
+               if bits != 256 {
+                       return nil, ErrKeySize
+               }
+       case ECDSAP384SHA384:
+               if bits != 384 {
+                       return nil, ErrKeySize
+               }
+       }
+
+       switch k.Algorithm {
+       case DSA, DSANSEC3SHA1:
+               params := new(dsa.Parameters)
+               if err := dsa.GenerateParameters(params, rand.Reader, dsa.L1024N160); err != nil {
+                       return nil, err
+               }
+               priv := new(dsa.PrivateKey)
+               priv.PublicKey.Parameters = *params
+               err := dsa.GenerateKey(priv, rand.Reader)
+               if err != nil {
+                       return nil, err
+               }
+               k.setPublicKeyDSA(params.Q, params.P, params.G, priv.PublicKey.Y)
+               return priv, nil
+       case RSAMD5, RSASHA1, RSASHA256, RSASHA512, RSASHA1NSEC3SHA1:
+               priv, err := rsa.GenerateKey(rand.Reader, bits)
+               if err != nil {
+                       return nil, err
+               }
+               k.setPublicKeyRSA(priv.PublicKey.E, priv.PublicKey.N)
+               return priv, nil
+       case ECDSAP256SHA256, ECDSAP384SHA384:
+               var c elliptic.Curve
+               switch k.Algorithm {
+               case ECDSAP256SHA256:
+                       c = elliptic.P256()
+               case ECDSAP384SHA384:
+                       c = elliptic.P384()
+               }
+               priv, err := ecdsa.GenerateKey(c, rand.Reader)
+               if err != nil {
+                       return nil, err
+               }
+               k.setPublicKeyECDSA(priv.PublicKey.X, priv.PublicKey.Y)
+               return priv, nil
+       default:
+               return nil, ErrAlg
+       }
+}
+
+// Set the public key (the value E and N)
+func (k *DNSKEY) setPublicKeyRSA(_E int, _N *big.Int) bool {
+       if _E == 0 || _N == nil {
+               return false
+       }
+       buf := exponentToBuf(_E)
+       buf = append(buf, _N.Bytes()...)
+       k.PublicKey = toBase64(buf)
+       return true
+}
+
+// Set the public key for Elliptic Curves
+func (k *DNSKEY) setPublicKeyECDSA(_X, _Y *big.Int) bool {
+       if _X == nil || _Y == nil {
+               return false
+       }
+       var intlen int
+       switch k.Algorithm {
+       case ECDSAP256SHA256:
+               intlen = 32
+       case ECDSAP384SHA384:
+               intlen = 48
+       }
+       k.PublicKey = toBase64(curveToBuf(_X, _Y, intlen))
+       return true
+}
+
+// Set the public key for DSA
+func (k *DNSKEY) setPublicKeyDSA(_Q, _P, _G, _Y *big.Int) bool {
+       if _Q == nil || _P == nil || _G == nil || _Y == nil {
+               return false
+       }
+       buf := dsaToBuf(_Q, _P, _G, _Y)
+       k.PublicKey = toBase64(buf)
+       return true
+}
+
+// Set the public key (the values E and N) for RSA
+// RFC 3110: Section 2. RSA Public KEY Resource Records
+func exponentToBuf(_E int) []byte {
+       var buf []byte
+       i := big.NewInt(int64(_E))
+       if len(i.Bytes()) < 256 {
+               buf = make([]byte, 1)
+               buf[0] = uint8(len(i.Bytes()))
+       } else {
+               buf = make([]byte, 3)
+               buf[0] = 0
+               buf[1] = uint8(len(i.Bytes()) >> 8)
+               buf[2] = uint8(len(i.Bytes()))
+       }
+       buf = append(buf, i.Bytes()...)
+       return buf
+}
+
+// Set the public key for X and Y for Curve. The two
+// values are just concatenated.
+func curveToBuf(_X, _Y *big.Int, intlen int) []byte {
+       buf := intToBytes(_X, intlen)
+       buf = append(buf, intToBytes(_Y, intlen)...)
+       return buf
+}
+
+// Set the public key for X and Y for Curve. The two
+// values are just concatenated.
+func dsaToBuf(_Q, _P, _G, _Y *big.Int) []byte {
+       t := divRoundUp(divRoundUp(_G.BitLen(), 8)-64, 8)
+       buf := []byte{byte(t)}
+       buf = append(buf, intToBytes(_Q, 20)...)
+       buf = append(buf, intToBytes(_P, 64+t*8)...)
+       buf = append(buf, intToBytes(_G, 64+t*8)...)
+       buf = append(buf, intToBytes(_Y, 64+t*8)...)
+       return buf
+}
diff --git a/vendor/github.com/miekg/dns/dnssec_keyscan.go b/vendor/github.com/miekg/dns/dnssec_keyscan.go
new file mode 100644 (file)
index 0000000..c0b54dc
--- /dev/null
@@ -0,0 +1,249 @@
+package dns
+
+import (
+       "crypto"
+       "crypto/dsa"
+       "crypto/ecdsa"
+       "crypto/rsa"
+       "io"
+       "math/big"
+       "strconv"
+       "strings"
+)
+
+// NewPrivateKey returns a PrivateKey by parsing the string s.
+// s should be in the same form of the BIND private key files.
+func (k *DNSKEY) NewPrivateKey(s string) (crypto.PrivateKey, error) {
+       if s[len(s)-1] != '\n' { // We need a closing newline
+               return k.ReadPrivateKey(strings.NewReader(s+"\n"), "")
+       }
+       return k.ReadPrivateKey(strings.NewReader(s), "")
+}
+
+// ReadPrivateKey reads a private key from the io.Reader q. The string file is
+// only used in error reporting.
+// The public key must be known, because some cryptographic algorithms embed
+// the public inside the privatekey.
+func (k *DNSKEY) ReadPrivateKey(q io.Reader, file string) (crypto.PrivateKey, error) {
+       m, err := parseKey(q, file)
+       if m == nil {
+               return nil, err
+       }
+       if _, ok := m["private-key-format"]; !ok {
+               return nil, ErrPrivKey
+       }
+       if m["private-key-format"] != "v1.2" && m["private-key-format"] != "v1.3" {
+               return nil, ErrPrivKey
+       }
+       // TODO(mg): check if the pubkey matches the private key
+       algo, err := strconv.Atoi(strings.SplitN(m["algorithm"], " ", 2)[0])
+       if err != nil {
+               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:
+               priv, err := readPrivateKeyRSA(m)
+               if err != nil {
+                       return nil, err
+               }
+               pub := k.publicKeyRSA()
+               if pub == nil {
+                       return nil, ErrKey
+               }
+               priv.PublicKey = *pub
+               return priv, nil
+       case ECCGOST:
+               return nil, ErrPrivKey
+       case ECDSAP256SHA256:
+               fallthrough
+       case ECDSAP384SHA384:
+               priv, err := readPrivateKeyECDSA(m)
+               if err != nil {
+                       return nil, err
+               }
+               pub := k.publicKeyECDSA()
+               if pub == nil {
+                       return nil, ErrKey
+               }
+               priv.PublicKey = *pub
+               return priv, nil
+       default:
+               return nil, ErrPrivKey
+       }
+}
+
+// Read a private key (file) string and create a public key. Return the private key.
+func readPrivateKeyRSA(m map[string]string) (*rsa.PrivateKey, error) {
+       p := new(rsa.PrivateKey)
+       p.Primes = []*big.Int{nil, nil}
+       for k, v := range m {
+               switch k {
+               case "modulus", "publicexponent", "privateexponent", "prime1", "prime2":
+                       v1, err := fromBase64([]byte(v))
+                       if err != nil {
+                               return nil, err
+                       }
+                       switch k {
+                       case "modulus":
+                               p.PublicKey.N = big.NewInt(0)
+                               p.PublicKey.N.SetBytes(v1)
+                       case "publicexponent":
+                               i := big.NewInt(0)
+                               i.SetBytes(v1)
+                               p.PublicKey.E = int(i.Int64()) // int64 should be large enough
+                       case "privateexponent":
+                               p.D = big.NewInt(0)
+                               p.D.SetBytes(v1)
+                       case "prime1":
+                               p.Primes[0] = big.NewInt(0)
+                               p.Primes[0].SetBytes(v1)
+                       case "prime2":
+                               p.Primes[1] = big.NewInt(0)
+                               p.Primes[1].SetBytes(v1)
+                       }
+               case "exponent1", "exponent2", "coefficient":
+                       // not used in Go (yet)
+               case "created", "publish", "activate":
+                       // not used in Go (yet)
+               }
+       }
+       return p, nil
+}
+
+func readPrivateKeyDSA(m map[string]string) (*dsa.PrivateKey, error) {
+       p := new(dsa.PrivateKey)
+       p.X = big.NewInt(0)
+       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 = big.NewInt(0)
+       // TODO: validate that the required flags are present
+       for k, v := range m {
+               switch k {
+               case "privatekey":
+                       v1, err := fromBase64([]byte(v))
+                       if err != nil {
+                               return nil, err
+                       }
+                       p.D.SetBytes(v1)
+               case "created", "publish", "activate":
+                       /* not used in Go (yet) */
+               }
+       }
+       return p, nil
+}
+
+// parseKey reads a private key from r. It returns a map[string]string,
+// with the key-value pairs, or an error when the file is not correct.
+func parseKey(r io.Reader, file string) (map[string]string, error) {
+       s := scanInit(r)
+       m := make(map[string]string)
+       c := make(chan lex)
+       k := ""
+       // Start the lexer
+       go klexer(s, c)
+       for l := range c {
+               // It should alternate
+               switch l.value {
+               case zKey:
+                       k = l.token
+               case zValue:
+                       if k == "" {
+                               return nil, &ParseError{file, "no private key seen", l}
+                       }
+                       //println("Setting", strings.ToLower(k), "to", l.token, "b")
+                       m[strings.ToLower(k)] = l.token
+                       k = ""
+               }
+       }
+       return m, nil
+}
+
+// klexer scans the sourcefile and returns tokens on the channel c.
+func klexer(s *scan, c chan lex) {
+       var l lex
+       str := "" // Hold the current read text
+       commt := false
+       key := true
+       x, err := s.tokenText()
+       defer close(c)
+       for err == nil {
+               l.column = s.position.Column
+               l.line = s.position.Line
+               switch x {
+               case ':':
+                       if commt {
+                               break
+                       }
+                       l.token = str
+                       if key {
+                               l.value = zKey
+                               c <- l
+                               // Next token is a space, eat it
+                               s.tokenText()
+                               key = false
+                               str = ""
+                       } else {
+                               l.value = zValue
+                       }
+               case ';':
+                       commt = true
+               case '\n':
+                       if commt {
+                               // Reset a comment
+                               commt = false
+                       }
+                       l.value = zValue
+                       l.token = str
+                       c <- l
+                       str = ""
+                       commt = false
+                       key = true
+               default:
+                       if commt {
+                               break
+                       }
+                       str += string(x)
+               }
+               x, err = s.tokenText()
+       }
+       if len(str) > 0 {
+               // Send remainder
+               l.token = str
+               l.value = zValue
+               c <- l
+       }
+}
diff --git a/vendor/github.com/miekg/dns/dnssec_privkey.go b/vendor/github.com/miekg/dns/dnssec_privkey.go
new file mode 100644 (file)
index 0000000..56f3ea9
--- /dev/null
@@ -0,0 +1,85 @@
+package dns
+
+import (
+       "crypto"
+       "crypto/dsa"
+       "crypto/ecdsa"
+       "crypto/rsa"
+       "math/big"
+       "strconv"
+)
+
+const format = "Private-key-format: v1.3\n"
+
+// 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
+func (r *DNSKEY) PrivateKeyString(p crypto.PrivateKey) string {
+       algorithm := strconv.Itoa(int(r.Algorithm))
+       algorithm += " (" + AlgorithmToString[r.Algorithm] + ")"
+
+       switch p := p.(type) {
+       case *rsa.PrivateKey:
+               modulus := toBase64(p.PublicKey.N.Bytes())
+               e := big.NewInt(int64(p.PublicKey.E))
+               publicExponent := toBase64(e.Bytes())
+               privateExponent := toBase64(p.D.Bytes())
+               prime1 := toBase64(p.Primes[0].Bytes())
+               prime2 := toBase64(p.Primes[1].Bytes())
+               // Calculate Exponent1/2 and Coefficient as per: http://en.wikipedia.org/wiki/RSA#Using_the_Chinese_remainder_algorithm
+               // and from: http://code.google.com/p/go/issues/detail?id=987
+               one := big.NewInt(1)
+               p1 := big.NewInt(0).Sub(p.Primes[0], one)
+               q1 := big.NewInt(0).Sub(p.Primes[1], one)
+               exp1 := big.NewInt(0).Mod(p.D, p1)
+               exp2 := big.NewInt(0).Mod(p.D, q1)
+               coeff := big.NewInt(0).ModInverse(p.Primes[1], p.Primes[0])
+
+               exponent1 := toBase64(exp1.Bytes())
+               exponent2 := toBase64(exp2.Bytes())
+               coefficient := toBase64(coeff.Bytes())
+
+               return format +
+                       "Algorithm: " + algorithm + "\n" +
+                       "Modulus: " + modulus + "\n" +
+                       "PublicExponent: " + publicExponent + "\n" +
+                       "PrivateExponent: " + privateExponent + "\n" +
+                       "Prime1: " + prime1 + "\n" +
+                       "Prime2: " + prime2 + "\n" +
+                       "Exponent1: " + exponent1 + "\n" +
+                       "Exponent2: " + exponent2 + "\n" +
+                       "Coefficient: " + coefficient + "\n"
+
+       case *ecdsa.PrivateKey:
+               var intlen int
+               switch r.Algorithm {
+               case ECDSAP256SHA256:
+                       intlen = 32
+               case ECDSAP384SHA384:
+                       intlen = 48
+               }
+               private := toBase64(intToBytes(p.D, intlen))
+               return format +
+                       "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"
+
+       default:
+               return ""
+       }
+}
diff --git a/vendor/github.com/miekg/dns/doc.go b/vendor/github.com/miekg/dns/doc.go
new file mode 100644 (file)
index 0000000..f3555e4
--- /dev/null
@@ -0,0 +1,251 @@
+/*
+Package dns implements a full featured interface to the Domain Name System.
+Server- and client-side programming is supported.
+The package allows complete control over what is send out to the DNS. The package
+API follows the less-is-more principle, by presenting a small, clean interface.
+
+The package dns supports (asynchronous) querying/replying, incoming/outgoing zone transfers,
+TSIG, EDNS0, dynamic updates, notifies and DNSSEC validation/signing.
+Note that domain names MUST be fully qualified, before sending them, unqualified
+names in a message will result in a packing failure.
+
+Resource records are native types. They are not stored in wire format.
+Basic usage pattern for creating a new resource record:
+
+     r := new(dns.MX)
+     r.Hdr = dns.RR_Header{Name: "miek.nl.", Rrtype: dns.TypeMX,
+       Class: dns.ClassINET, Ttl: 3600}
+     r.Preference = 10
+     r.Mx = "mx.miek.nl."
+
+Or directly from a string:
+
+     mx, err := dns.NewRR("miek.nl. 3600 IN MX 10 mx.miek.nl.")
+
+Or when the default TTL (3600) and class (IN) suit you:
+
+     mx, err := dns.NewRR("miek.nl. MX 10 mx.miek.nl.")
+
+Or even:
+
+     mx, err := dns.NewRR("$ORIGIN nl.\nmiek 1H IN MX 10 mx.miek")
+
+In the DNS messages are exchanged, these messages contain resource
+records (sets).  Use pattern for creating a message:
+
+     m := new(dns.Msg)
+     m.SetQuestion("miek.nl.", dns.TypeMX)
+
+Or when not certain if the domain name is fully qualified:
+
+       m.SetQuestion(dns.Fqdn("miek.nl"), dns.TypeMX)
+
+The message m is now a message with the question section set to ask
+the MX records for the miek.nl. zone.
+
+The following is slightly more verbose, but more flexible:
+
+     m1 := new(dns.Msg)
+     m1.Id = dns.Id()
+     m1.RecursionDesired = true
+     m1.Question = make([]dns.Question, 1)
+     m1.Question[0] = dns.Question{"miek.nl.", dns.TypeMX, dns.ClassINET}
+
+After creating a message it can be send.
+Basic use pattern for synchronous querying the DNS at a
+server configured on 127.0.0.1 and port 53:
+
+     c := new(dns.Client)
+     in, rtt, err := c.Exchange(m1, "127.0.0.1:53")
+
+Suppressing multiple outstanding queries (with the same question, type and
+class) is as easy as setting:
+
+       c.SingleInflight = true
+
+If these "advanced" features are not needed, a simple UDP query can be send,
+with:
+
+       in, err := dns.Exchange(m1, "127.0.0.1:53")
+
+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.
+
+Each of these sections (except the Question section) contain a []RR. Basic
+use pattern for accessing the rdata of a TXT RR as the first RR in
+the Answer section:
+
+       if t, ok := in.Answer[0].(*dns.TXT); ok {
+               // do something with t.Txt
+       }
+
+Domain Name and TXT Character String Representations
+
+Both domain names and TXT character strings are converted to presentation
+form both when unpacked and when converted to strings.
+
+For TXT character strings, tabs, carriage returns and line feeds will be
+converted to \t, \r and \n respectively. Back slashes and quotations marks
+will be escaped. Bytes below 32 and above 127 will be converted to \DDD
+form.
+
+For domain names, in addition to the above rules brackets, periods,
+spaces, semicolons and the at symbol are escaped.
+
+DNSSEC
+
+DNSSEC (DNS Security Extension) adds a layer of security to the DNS. It
+uses public key cryptography to sign resource records. The
+public keys are stored in DNSKEY records and the signatures in RRSIG records.
+
+Requesting DNSSEC information for a zone is done by adding the DO (DNSSEC OK) bit
+to a request.
+
+     m := new(dns.Msg)
+     m.SetEdns0(4096, true)
+
+Signature generation, signature verification and key generation are all supported.
+
+DYNAMIC UPDATES
+
+Dynamic updates reuses the DNS message format, but renames three of
+the sections. Question is Zone, Answer is Prerequisite, Authority is
+Update, only the Additional is not renamed. See RFC 2136 for the gory details.
+
+You can set a rather complex set of rules for the existence of absence of
+certain resource records or names in a zone to specify if resource records
+should be added or removed. The table from RFC 2136 supplemented with the Go
+DNS function shows which functions exist to specify the prerequisites.
+
+ 3.2.4 - Table Of Metavalues Used In Prerequisite Section
+
+  CLASS    TYPE     RDATA    Meaning                    Function
+  --------------------------------------------------------------
+  ANY      ANY      empty    Name is in use             dns.NameUsed
+  ANY      rrset    empty    RRset exists (value indep) dns.RRsetUsed
+  NONE     ANY      empty    Name is not in use         dns.NameNotUsed
+  NONE     rrset    empty    RRset does not exist       dns.RRsetNotUsed
+  zone     rrset    rr       RRset exists (value dep)   dns.Used
+
+The prerequisite section can also be left empty.
+If you have decided on the prerequisites you can tell what RRs should
+be added or deleted. The next table shows the options you have and
+what functions to call.
+
+ 3.4.2.6 - Table Of Metavalues Used In Update Section
+
+  CLASS    TYPE     RDATA    Meaning                     Function
+  ---------------------------------------------------------------
+  ANY      ANY      empty    Delete all RRsets from name dns.RemoveName
+  ANY      rrset    empty    Delete an RRset             dns.RemoveRRset
+  NONE     rrset    rr       Delete an RR from RRset     dns.Remove
+  zone     rrset    rr       Add to an RRset             dns.Insert
+
+TRANSACTION SIGNATURE
+
+An TSIG or transaction signature adds a HMAC TSIG record to each message sent.
+The supported algorithms include: HmacMD5, HmacSHA1, HmacSHA256 and HmacSHA512.
+
+Basic use pattern when querying with a TSIG name "axfr." (note that these key names
+must be fully qualified - as they are domain names) and the base64 secret
+"so6ZGir4GPAqINNh9U5c3A==":
+
+       c := new(dns.Client)
+       c.TsigSecret = map[string]string{"axfr.": "so6ZGir4GPAqINNh9U5c3A=="}
+       m := new(dns.Msg)
+       m.SetQuestion("miek.nl.", dns.TypeMX)
+       m.SetTsig("axfr.", dns.HmacMD5, 300, time.Now().Unix())
+       ...
+       // When sending the TSIG RR is calculated and filled in before sending
+
+When requesting an zone transfer (almost all TSIG usage is when requesting zone transfers), with
+TSIG, this is the basic use pattern. In this example we request an AXFR for
+miek.nl. with TSIG key named "axfr." and secret "so6ZGir4GPAqINNh9U5c3A=="
+and using the server 176.58.119.54:
+
+       t := new(dns.Transfer)
+       m := new(dns.Msg)
+       t.TsigSecret = map[string]string{"axfr.": "so6ZGir4GPAqINNh9U5c3A=="}
+       m.SetAxfr("miek.nl.")
+       m.SetTsig("axfr.", dns.HmacMD5, 300, time.Now().Unix())
+       c, err := t.In(m, "176.58.119.54:53")
+       for r := range c { ... }
+
+You can now read the records from the transfer as they come in. Each envelope is checked with TSIG.
+If something is not correct an error is returned.
+
+Basic use pattern validating and replying to a message that has TSIG set.
+
+       server := &dns.Server{Addr: ":53", Net: "udp"}
+       server.TsigSecret = map[string]string{"axfr.": "so6ZGir4GPAqINNh9U5c3A=="}
+       go server.ListenAndServe()
+       dns.HandleFunc(".", handleRequest)
+
+       func handleRequest(w dns.ResponseWriter, r *dns.Msg) {
+               m := new(dns.Msg)
+               m.SetReply(r)
+               if r.IsTsig() != nil {
+                       if w.TsigStatus() == nil {
+                               // *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
+                       }
+               }
+               w.WriteMsg(m)
+       }
+
+PRIVATE RRS
+
+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 http://miek.nl/posts/2014/Sep/21/Private%20RRs%20and%20IDN%20in%20Go%20DNS/ for more
+information.
+
+EDNS0
+
+EDNS0 is an extension mechanism for the DNS defined in RFC 2671 and updated
+by RFC 6891. It defines an new RR type, the OPT RR, which is then completely
+abused.
+Basic use pattern for creating an (empty) OPT RR:
+
+       o := new(dns.OPT)
+       o.Hdr.Name = "." // MUST be the root zone, per definition.
+       o.Hdr.Rrtype = dns.TypeOPT
+
+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:
+
+       // o is a dns.OPT
+       for _, s := range o.Option {
+               switch e := s.(type) {
+               case *dns.EDNS0_NSID:
+                       // do stuff with e.Nsid
+               case *dns.EDNS0_SUBNET:
+                       // access e.Family, e.Address, etc.
+               }
+       }
+
+SIG(0)
+
+From RFC 2931:
+
+    SIG(0) provides protection for DNS transactions and requests ....
+    ... protection for glue records, DNS requests, protection for message headers
+    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, ECDSAP384SHA384, RSASHA1, RSASHA256 and
+RSASHA512.
+
+Signing subsequent messages in multi-message sessions is not implemented.
+*/
+package dns
diff --git a/vendor/github.com/miekg/dns/edns.go b/vendor/github.com/miekg/dns/edns.go
new file mode 100644 (file)
index 0000000..7a58aa9
--- /dev/null
@@ -0,0 +1,532 @@
+package dns
+
+import (
+       "encoding/binary"
+       "encoding/hex"
+       "errors"
+       "net"
+       "strconv"
+)
+
+// EDNS0 Option codes.
+const (
+       EDNS0LLQ         = 0x1     // long lived queries: http://tools.ietf.org/html/draft-sekar-dns-llq-01
+       EDNS0UL          = 0x2     // update lease draft: http://files.dns-sd.org/draft-sekar-dns-ul.txt
+       EDNS0NSID        = 0x3     // nsid (RFC5001)
+       EDNS0DAU         = 0x5     // DNSSEC Algorithm Understood
+       EDNS0DHU         = 0x6     // DS Hash Understood
+       EDNS0N3U         = 0x7     // NSEC3 Hash Understood
+       EDNS0SUBNET      = 0x8     // client-subnet (RFC6891)
+       EDNS0EXPIRE      = 0x9     // EDNS0 expire
+       EDNS0COOKIE      = 0xa     // EDNS0 Cookie
+       EDNS0SUBNETDRAFT = 0x50fa  // Don't use! Use EDNS0SUBNET
+       EDNS0LOCALSTART  = 0xFDE9  // Beginning of range reserved for local/experimental use (RFC6891)
+       EDNS0LOCALEND    = 0xFFFE  // End of range reserved for local/experimental use (RFC6891)
+       _DO              = 1 << 15 // dnssec ok
+)
+
+// OPT is the EDNS0 RR appended to messages to convey extra (meta) information.
+// See RFC 6891.
+type OPT struct {
+       Hdr    RR_Header
+       Option []EDNS0 `dns:"opt"`
+}
+
+func (rr *OPT) String() string {
+       s := "\n;; OPT PSEUDOSECTION:\n; EDNS: version " + strconv.Itoa(int(rr.Version())) + "; "
+       if rr.Do() {
+               s += "flags: do; "
+       } else {
+               s += "flags: ; "
+       }
+       s += "udp: " + strconv.Itoa(int(rr.UDPSize()))
+
+       for _, o := range rr.Option {
+               switch o.(type) {
+               case *EDNS0_NSID:
+                       s += "\n; NSID: " + o.String()
+                       h, e := o.pack()
+                       var r string
+                       if e == nil {
+                               for _, c := range h {
+                                       r += "(" + string(c) + ")"
+                               }
+                               s += "  " + r
+                       }
+               case *EDNS0_SUBNET:
+                       s += "\n; SUBNET: " + o.String()
+                       if o.(*EDNS0_SUBNET).DraftOption {
+                               s += " (draft)"
+                       }
+               case *EDNS0_COOKIE:
+                       s += "\n; COOKIE: " + o.String()
+               case *EDNS0_UL:
+                       s += "\n; UPDATE LEASE: " + o.String()
+               case *EDNS0_LLQ:
+                       s += "\n; LONG LIVED QUERIES: " + o.String()
+               case *EDNS0_DAU:
+                       s += "\n; DNSSEC ALGORITHM UNDERSTOOD: " + o.String()
+               case *EDNS0_DHU:
+                       s += "\n; DS HASH UNDERSTOOD: " + o.String()
+               case *EDNS0_N3U:
+                       s += "\n; NSEC3 HASH UNDERSTOOD: " + o.String()
+               case *EDNS0_LOCAL:
+                       s += "\n; LOCAL OPT: " + o.String()
+               }
+       }
+       return s
+}
+
+func (rr *OPT) len() int {
+       l := rr.Hdr.len()
+       for i := 0; i < len(rr.Option); i++ {
+               l += 4 // Account for 2-byte option code and 2-byte option length.
+               lo, _ := rr.Option[i].pack()
+               l += len(lo)
+       }
+       return l
+}
+
+// return the old value -> delete SetVersion?
+
+// Version returns the EDNS version used. Only zero is defined.
+func (rr *OPT) Version() uint8 {
+       return uint8((rr.Hdr.Ttl & 0x00FF0000) >> 16)
+}
+
+// SetVersion sets the version of EDNS. This is usually zero.
+func (rr *OPT) SetVersion(v uint8) {
+       rr.Hdr.Ttl = rr.Hdr.Ttl&0xFF00FFFF | (uint32(v) << 16)
+}
+
+// ExtendedRcode returns the EDNS extended RCODE field (the upper 8 bits of the TTL).
+func (rr *OPT) ExtendedRcode() int {
+       return int((rr.Hdr.Ttl&0xFF000000)>>24) + 15
+}
+
+// SetExtendedRcode sets the EDNS extended RCODE field.
+func (rr *OPT) SetExtendedRcode(v uint8) {
+       if v < RcodeBadVers { // Smaller than 16.. Use the 4 bits you have!
+               return
+       }
+       rr.Hdr.Ttl = rr.Hdr.Ttl&0x00FFFFFF | (uint32(v-15) << 24)
+}
+
+// UDPSize returns the UDP buffer size.
+func (rr *OPT) UDPSize() uint16 {
+       return rr.Hdr.Class
+}
+
+// SetUDPSize sets the UDP buffer size.
+func (rr *OPT) SetUDPSize(size uint16) {
+       rr.Hdr.Class = size
+}
+
+// Do returns the value of the DO (DNSSEC OK) bit.
+func (rr *OPT) Do() bool {
+       return rr.Hdr.Ttl&_DO == _DO
+}
+
+// SetDo sets the DO (DNSSEC OK) bit.
+func (rr *OPT) SetDo() {
+       rr.Hdr.Ttl |= _DO
+}
+
+// EDNS0 defines an EDNS0 Option. An OPT RR can have multiple options appended to it.
+type EDNS0 interface {
+       // Option returns the option code for the option.
+       Option() uint16
+       // pack returns the bytes of the option data.
+       pack() ([]byte, error)
+       // unpack sets the data as found in the buffer. Is also sets
+       // the length of the slice as the length of the option data.
+       unpack([]byte) error
+       // String returns the string representation of the option.
+       String() string
+}
+
+// The nsid EDNS0 option is used to retrieve a nameserver
+// identifier. When sending a request Nsid must be set to the empty string
+// The identifier is an opaque string encoded as hex.
+// Basic use pattern for creating an nsid option:
+//
+//     o := new(dns.OPT)
+//     o.Hdr.Name = "."
+//     o.Hdr.Rrtype = dns.TypeOPT
+//     e := new(dns.EDNS0_NSID)
+//     e.Code = dns.EDNS0NSID
+//     e.Nsid = "AA"
+//     o.Option = append(o.Option, e)
+type EDNS0_NSID struct {
+       Code uint16 // Always EDNS0NSID
+       Nsid string // This string needs to be hex encoded
+}
+
+func (e *EDNS0_NSID) pack() ([]byte, error) {
+       h, err := hex.DecodeString(e.Nsid)
+       if err != nil {
+               return nil, err
+       }
+       return h, nil
+}
+
+func (e *EDNS0_NSID) Option() uint16        { return EDNS0NSID }
+func (e *EDNS0_NSID) unpack(b []byte) error { e.Nsid = hex.EncodeToString(b); return nil }
+func (e *EDNS0_NSID) String() string        { return string(e.Nsid) }
+
+// EDNS0_SUBNET is the subnet option that is used to give the remote nameserver
+// an idea of where the client lives. It can then give back a different
+// answer depending on the location or network topology.
+// Basic use pattern for creating an subnet option:
+//
+//     o := new(dns.OPT)
+//     o.Hdr.Name = "."
+//     o.Hdr.Rrtype = dns.TypeOPT
+//     e := new(dns.EDNS0_SUBNET)
+//     e.Code = dns.EDNS0SUBNET
+//     e.Family = 1    // 1 for IPv4 source address, 2 for IPv6
+//     e.NetMask = 32  // 32 for IPV4, 128 for IPv6
+//     e.SourceScope = 0
+//     e.Address = net.ParseIP("127.0.0.1").To4()      // for IPv4
+//     // e.Address = net.ParseIP("2001:7b8:32a::2")   // for IPV6
+//     o.Option = append(o.Option, e)
+//
+// Note: the spec (draft-ietf-dnsop-edns-client-subnet-00) has some insane logic
+// for which netmask applies to the address. This code will parse all the
+// available bits when unpacking (up to optlen). When packing it will apply
+// SourceNetmask. If you need more advanced logic, patches welcome and good luck.
+type EDNS0_SUBNET struct {
+       Code          uint16 // Always EDNS0SUBNET
+       Family        uint16 // 1 for IP, 2 for IP6
+       SourceNetmask uint8
+       SourceScope   uint8
+       Address       net.IP
+       DraftOption   bool // Set to true if using the old (0x50fa) option code
+}
+
+func (e *EDNS0_SUBNET) Option() uint16 {
+       if e.DraftOption {
+               return EDNS0SUBNETDRAFT
+       }
+       return EDNS0SUBNET
+}
+
+func (e *EDNS0_SUBNET) pack() ([]byte, error) {
+       b := make([]byte, 4)
+       binary.BigEndian.PutUint16(b[0:], e.Family)
+       b[2] = e.SourceNetmask
+       b[3] = e.SourceScope
+       switch e.Family {
+       case 1:
+               if e.SourceNetmask > net.IPv4len*8 {
+                       return nil, errors.New("dns: bad netmask")
+               }
+               if len(e.Address.To4()) != net.IPv4len {
+                       return nil, errors.New("dns: bad address")
+               }
+               ip := e.Address.To4().Mask(net.CIDRMask(int(e.SourceNetmask), net.IPv4len*8))
+               needLength := (e.SourceNetmask + 8 - 1) / 8 // division rounding up
+               b = append(b, ip[:needLength]...)
+       case 2:
+               if e.SourceNetmask > net.IPv6len*8 {
+                       return nil, errors.New("dns: bad netmask")
+               }
+               if len(e.Address) != net.IPv6len {
+                       return nil, errors.New("dns: bad address")
+               }
+               ip := e.Address.Mask(net.CIDRMask(int(e.SourceNetmask), net.IPv6len*8))
+               needLength := (e.SourceNetmask + 8 - 1) / 8 // division rounding up
+               b = append(b, ip[:needLength]...)
+       default:
+               return nil, errors.New("dns: bad address family")
+       }
+       return b, nil
+}
+
+func (e *EDNS0_SUBNET) unpack(b []byte) error {
+       if len(b) < 4 {
+               return ErrBuf
+       }
+       e.Family = binary.BigEndian.Uint16(b)
+       e.SourceNetmask = b[2]
+       e.SourceScope = b[3]
+       switch e.Family {
+       case 1:
+               if e.SourceNetmask > net.IPv4len*8 || e.SourceScope > net.IPv4len*8 {
+                       return errors.New("dns: bad netmask")
+               }
+               addr := make([]byte, net.IPv4len)
+               for i := 0; i < net.IPv4len && 4+i < len(b); i++ {
+                       addr[i] = b[4+i]
+               }
+               e.Address = net.IPv4(addr[0], addr[1], addr[2], addr[3])
+       case 2:
+               if e.SourceNetmask > net.IPv6len*8 || e.SourceScope > net.IPv6len*8 {
+                       return errors.New("dns: bad netmask")
+               }
+               addr := make([]byte, net.IPv6len)
+               for i := 0; i < net.IPv6len && 4+i < len(b); i++ {
+                       addr[i] = b[4+i]
+               }
+               e.Address = net.IP{addr[0], addr[1], addr[2], addr[3], addr[4],
+                       addr[5], addr[6], addr[7], addr[8], addr[9], addr[10],
+                       addr[11], addr[12], addr[13], addr[14], addr[15]}
+       default:
+               return errors.New("dns: bad address family")
+       }
+       return nil
+}
+
+func (e *EDNS0_SUBNET) String() (s string) {
+       if e.Address == nil {
+               s = "<nil>"
+       } else if e.Address.To4() != nil {
+               s = e.Address.String()
+       } else {
+               s = "[" + e.Address.String() + "]"
+       }
+       s += "/" + strconv.Itoa(int(e.SourceNetmask)) + "/" + strconv.Itoa(int(e.SourceScope))
+       return
+}
+
+// The Cookie EDNS0 option
+//
+//     o := new(dns.OPT)
+//     o.Hdr.Name = "."
+//     o.Hdr.Rrtype = dns.TypeOPT
+//     e := new(dns.EDNS0_COOKIE)
+//     e.Code = dns.EDNS0COOKIE
+//     e.Cookie = "24a5ac.."
+//     o.Option = append(o.Option, e)
+//
+// The Cookie field consists out of a client cookie (RFC 7873 Section 4), that is
+// always 8 bytes. It may then optionally be followed by the server cookie. The server
+// cookie is of variable length, 8 to a maximum of 32 bytes. In other words:
+//
+//     cCookie := o.Cookie[:16]
+//     sCookie := o.Cookie[16:]
+//
+// There is no guarantee that the Cookie string has a specific length.
+type EDNS0_COOKIE struct {
+       Code   uint16 // Always EDNS0COOKIE
+       Cookie string // Hex-encoded cookie data
+}
+
+func (e *EDNS0_COOKIE) pack() ([]byte, error) {
+       h, err := hex.DecodeString(e.Cookie)
+       if err != nil {
+               return nil, err
+       }
+       return h, nil
+}
+
+func (e *EDNS0_COOKIE) Option() uint16        { return EDNS0COOKIE }
+func (e *EDNS0_COOKIE) unpack(b []byte) error { e.Cookie = hex.EncodeToString(b); return nil }
+func (e *EDNS0_COOKIE) String() string        { return e.Cookie }
+
+// 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
+//
+//     o := new(dns.OPT)
+//     o.Hdr.Name = "."
+//     o.Hdr.Rrtype = dns.TypeOPT
+//     e := new(dns.EDNS0_UL)
+//     e.Code = dns.EDNS0UL
+//     e.Lease = 120 // in seconds
+//     o.Option = append(o.Option, e)
+type EDNS0_UL struct {
+       Code  uint16 // Always EDNS0UL
+       Lease uint32
+}
+
+func (e *EDNS0_UL) Option() uint16 { return EDNS0UL }
+func (e *EDNS0_UL) String() string { return strconv.FormatUint(uint64(e.Lease), 10) }
+
+// Copied: http://golang.org/src/pkg/net/dnsmsg.go
+func (e *EDNS0_UL) pack() ([]byte, error) {
+       b := make([]byte, 4)
+       binary.BigEndian.PutUint32(b, e.Lease)
+       return b, nil
+}
+
+func (e *EDNS0_UL) unpack(b []byte) error {
+       if len(b) < 4 {
+               return ErrBuf
+       }
+       e.Lease = binary.BigEndian.Uint32(b)
+       return nil
+}
+
+// EDNS0_LLQ stands for Long Lived Queries: http://tools.ietf.org/html/draft-sekar-dns-llq-01
+// Implemented for completeness, as the EDNS0 type code is assigned.
+type EDNS0_LLQ struct {
+       Code      uint16 // Always EDNS0LLQ
+       Version   uint16
+       Opcode    uint16
+       Error     uint16
+       Id        uint64
+       LeaseLife uint32
+}
+
+func (e *EDNS0_LLQ) Option() uint16 { return EDNS0LLQ }
+
+func (e *EDNS0_LLQ) pack() ([]byte, error) {
+       b := make([]byte, 18)
+       binary.BigEndian.PutUint16(b[0:], e.Version)
+       binary.BigEndian.PutUint16(b[2:], e.Opcode)
+       binary.BigEndian.PutUint16(b[4:], e.Error)
+       binary.BigEndian.PutUint64(b[6:], e.Id)
+       binary.BigEndian.PutUint32(b[14:], e.LeaseLife)
+       return b, nil
+}
+
+func (e *EDNS0_LLQ) unpack(b []byte) error {
+       if len(b) < 18 {
+               return ErrBuf
+       }
+       e.Version = binary.BigEndian.Uint16(b[0:])
+       e.Opcode = binary.BigEndian.Uint16(b[2:])
+       e.Error = binary.BigEndian.Uint16(b[4:])
+       e.Id = binary.BigEndian.Uint64(b[6:])
+       e.LeaseLife = binary.BigEndian.Uint32(b[14:])
+       return nil
+}
+
+func (e *EDNS0_LLQ) String() string {
+       s := strconv.FormatUint(uint64(e.Version), 10) + " " + strconv.FormatUint(uint64(e.Opcode), 10) +
+               " " + strconv.FormatUint(uint64(e.Error), 10) + " " + strconv.FormatUint(uint64(e.Id), 10) +
+               " " + strconv.FormatUint(uint64(e.LeaseLife), 10)
+       return s
+}
+
+type EDNS0_DAU struct {
+       Code    uint16 // Always EDNS0DAU
+       AlgCode []uint8
+}
+
+func (e *EDNS0_DAU) Option() uint16        { return EDNS0DAU }
+func (e *EDNS0_DAU) pack() ([]byte, error) { return e.AlgCode, nil }
+func (e *EDNS0_DAU) unpack(b []byte) error { e.AlgCode = b; return nil }
+
+func (e *EDNS0_DAU) String() string {
+       s := ""
+       for i := 0; i < len(e.AlgCode); i++ {
+               if a, ok := AlgorithmToString[e.AlgCode[i]]; ok {
+                       s += " " + a
+               } else {
+                       s += " " + strconv.Itoa(int(e.AlgCode[i]))
+               }
+       }
+       return s
+}
+
+type EDNS0_DHU struct {
+       Code    uint16 // Always EDNS0DHU
+       AlgCode []uint8
+}
+
+func (e *EDNS0_DHU) Option() uint16        { return EDNS0DHU }
+func (e *EDNS0_DHU) pack() ([]byte, error) { return e.AlgCode, nil }
+func (e *EDNS0_DHU) unpack(b []byte) error { e.AlgCode = b; return nil }
+
+func (e *EDNS0_DHU) String() string {
+       s := ""
+       for i := 0; i < len(e.AlgCode); i++ {
+               if a, ok := HashToString[e.AlgCode[i]]; ok {
+                       s += " " + a
+               } else {
+                       s += " " + strconv.Itoa(int(e.AlgCode[i]))
+               }
+       }
+       return s
+}
+
+type EDNS0_N3U struct {
+       Code    uint16 // Always EDNS0N3U
+       AlgCode []uint8
+}
+
+func (e *EDNS0_N3U) Option() uint16        { return EDNS0N3U }
+func (e *EDNS0_N3U) pack() ([]byte, error) { return e.AlgCode, nil }
+func (e *EDNS0_N3U) unpack(b []byte) error { e.AlgCode = b; return nil }
+
+func (e *EDNS0_N3U) String() string {
+       // Re-use the hash map
+       s := ""
+       for i := 0; i < len(e.AlgCode); i++ {
+               if a, ok := HashToString[e.AlgCode[i]]; ok {
+                       s += " " + a
+               } else {
+                       s += " " + strconv.Itoa(int(e.AlgCode[i]))
+               }
+       }
+       return s
+}
+
+type EDNS0_EXPIRE struct {
+       Code   uint16 // Always EDNS0EXPIRE
+       Expire uint32
+}
+
+func (e *EDNS0_EXPIRE) Option() uint16 { return EDNS0EXPIRE }
+func (e *EDNS0_EXPIRE) String() string { return strconv.FormatUint(uint64(e.Expire), 10) }
+
+func (e *EDNS0_EXPIRE) pack() ([]byte, error) {
+       b := make([]byte, 4)
+       b[0] = byte(e.Expire >> 24)
+       b[1] = byte(e.Expire >> 16)
+       b[2] = byte(e.Expire >> 8)
+       b[3] = byte(e.Expire)
+       return b, nil
+}
+
+func (e *EDNS0_EXPIRE) unpack(b []byte) error {
+       if len(b) < 4 {
+               return ErrBuf
+       }
+       e.Expire = binary.BigEndian.Uint32(b)
+       return nil
+}
+
+// The EDNS0_LOCAL option is used for local/experimental purposes. The option
+// code is recommended to be within the range [EDNS0LOCALSTART, EDNS0LOCALEND]
+// (RFC6891), although any unassigned code can actually be used.  The content of
+// the option is made available in Data, unaltered.
+// Basic use pattern for creating a local option:
+//
+//     o := new(dns.OPT)
+//     o.Hdr.Name = "."
+//     o.Hdr.Rrtype = dns.TypeOPT
+//     e := new(dns.EDNS0_LOCAL)
+//     e.Code = dns.EDNS0LOCALSTART
+//     e.Data = []byte{72, 82, 74}
+//     o.Option = append(o.Option, e)
+type EDNS0_LOCAL struct {
+       Code uint16
+       Data []byte
+}
+
+func (e *EDNS0_LOCAL) Option() uint16 { return e.Code }
+func (e *EDNS0_LOCAL) String() string {
+       return strconv.FormatInt(int64(e.Code), 10) + ":0x" + hex.EncodeToString(e.Data)
+}
+
+func (e *EDNS0_LOCAL) pack() ([]byte, error) {
+       b := make([]byte, len(e.Data))
+       copied := copy(b, e.Data)
+       if copied != len(e.Data) {
+               return nil, ErrBuf
+       }
+       return b, nil
+}
+
+func (e *EDNS0_LOCAL) unpack(b []byte) error {
+       e.Data = make([]byte, len(b))
+       copied := copy(e.Data, b)
+       if copied != len(b) {
+               return ErrBuf
+       }
+       return nil
+}
diff --git a/vendor/github.com/miekg/dns/format.go b/vendor/github.com/miekg/dns/format.go
new file mode 100644 (file)
index 0000000..3f5303c
--- /dev/null
@@ -0,0 +1,87 @@
+package dns
+
+import (
+       "net"
+       "reflect"
+       "strconv"
+)
+
+// NumField returns the number of rdata fields r has.
+func NumField(r RR) int {
+       return reflect.ValueOf(r).Elem().NumField() - 1 // Remove RR_Header
+}
+
+// Field returns the rdata field i as a string. Fields are indexed starting from 1.
+// RR types that holds slice data, for instance the NSEC type bitmap will return a single
+// string where the types are concatenated using a space.
+// Accessing non existing fields will cause a panic.
+func Field(r RR, i int) string {
+       if i == 0 {
+               return ""
+       }
+       d := reflect.ValueOf(r).Elem().Field(i)
+       switch k := d.Kind(); k {
+       case reflect.String:
+               return d.String()
+       case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+               return strconv.FormatInt(d.Int(), 10)
+       case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+               return strconv.FormatUint(d.Uint(), 10)
+       case reflect.Slice:
+               switch reflect.ValueOf(r).Elem().Type().Field(i).Tag {
+               case `dns:"a"`:
+                       // TODO(miek): Hmm store this as 16 bytes
+                       if d.Len() < net.IPv6len {
+                               return net.IPv4(byte(d.Index(0).Uint()),
+                                       byte(d.Index(1).Uint()),
+                                       byte(d.Index(2).Uint()),
+                                       byte(d.Index(3).Uint())).String()
+                       }
+                       return net.IPv4(byte(d.Index(12).Uint()),
+                               byte(d.Index(13).Uint()),
+                               byte(d.Index(14).Uint()),
+                               byte(d.Index(15).Uint())).String()
+               case `dns:"aaaa"`:
+                       return net.IP{
+                               byte(d.Index(0).Uint()),
+                               byte(d.Index(1).Uint()),
+                               byte(d.Index(2).Uint()),
+                               byte(d.Index(3).Uint()),
+                               byte(d.Index(4).Uint()),
+                               byte(d.Index(5).Uint()),
+                               byte(d.Index(6).Uint()),
+                               byte(d.Index(7).Uint()),
+                               byte(d.Index(8).Uint()),
+                               byte(d.Index(9).Uint()),
+                               byte(d.Index(10).Uint()),
+                               byte(d.Index(11).Uint()),
+                               byte(d.Index(12).Uint()),
+                               byte(d.Index(13).Uint()),
+                               byte(d.Index(14).Uint()),
+                               byte(d.Index(15).Uint()),
+                       }.String()
+               case `dns:"nsec"`:
+                       if d.Len() == 0 {
+                               return ""
+                       }
+                       s := Type(d.Index(0).Uint()).String()
+                       for i := 1; i < d.Len(); i++ {
+                               s += " " + Type(d.Index(i).Uint()).String()
+                       }
+                       return s
+               default:
+                       // if it does not have a tag its a string slice
+                       fallthrough
+               case `dns:"txt"`:
+                       if d.Len() == 0 {
+                               return ""
+                       }
+                       s := d.Index(0).String()
+                       for i := 1; i < d.Len(); i++ {
+                               s += " " + d.Index(i).String()
+                       }
+                       return s
+               }
+       }
+       return ""
+}
diff --git a/vendor/github.com/miekg/dns/generate.go b/vendor/github.com/miekg/dns/generate.go
new file mode 100644 (file)
index 0000000..e4481a4
--- /dev/null
@@ -0,0 +1,159 @@
+package dns
+
+import (
+       "bytes"
+       "errors"
+       "fmt"
+       "strconv"
+       "strings"
+)
+
+// Parse the $GENERATE statement as used in BIND9 zones.
+// See http://www.zytrax.com/books/dns/ch8/generate.html for instance.
+// We are called after '$GENERATE '. After which we expect:
+// * the range (12-24/2)
+// * lhs (ownername)
+// * [[ttl][class]]
+// * type
+// * rhs (rdata)
+// But we are lazy here, only the range is parsed *all* occurrences
+// of $ after that are interpreted.
+// Any error are returned as a string value, the empty string signals
+// "no error".
+func generate(l lex, c chan lex, t chan *Token, o string) string {
+       step := 1
+       if i := strings.IndexAny(l.token, "/"); i != -1 {
+               if i+1 == len(l.token) {
+                       return "bad step in $GENERATE range"
+               }
+               if s, err := strconv.Atoi(l.token[i+1:]); err == nil {
+                       if s < 0 {
+                               return "bad step in $GENERATE range"
+                       }
+                       step = s
+               } else {
+                       return "bad step in $GENERATE range"
+               }
+               l.token = l.token[:i]
+       }
+       sx := strings.SplitN(l.token, "-", 2)
+       if len(sx) != 2 {
+               return "bad start-stop in $GENERATE range"
+       }
+       start, err := strconv.Atoi(sx[0])
+       if err != nil {
+               return "bad start in $GENERATE range"
+       }
+       end, err := strconv.Atoi(sx[1])
+       if err != nil {
+               return "bad stop in $GENERATE range"
+       }
+       if end < 0 || start < 0 || end < start {
+               return "bad range in $GENERATE range"
+       }
+
+       <-c // _BLANK
+       // Create a complete new string, which we then parse again.
+       s := ""
+BuildRR:
+       l = <-c
+       if l.value != zNewline && l.value != zEOF {
+               s += l.token
+               goto BuildRR
+       }
+       for i := start; i <= end; i += step {
+               var (
+                       escape bool
+                       dom    bytes.Buffer
+                       mod    string
+                       err    error
+                       offset int
+               )
+
+               for j := 0; j < len(s); j++ { // No 'range' because we need to jump around
+                       switch s[j] {
+                       case '\\':
+                               if escape {
+                                       dom.WriteByte('\\')
+                                       escape = false
+                                       continue
+                               }
+                               escape = true
+                       case '$':
+                               mod = "%d"
+                               offset = 0
+                               if escape {
+                                       dom.WriteByte('$')
+                                       escape = false
+                                       continue
+                               }
+                               escape = false
+                               if j+1 >= len(s) { // End of the string
+                                       dom.WriteString(fmt.Sprintf(mod, i+offset))
+                                       continue
+                               } else {
+                                       if s[j+1] == '$' {
+                                               dom.WriteByte('$')
+                                               j++
+                                               continue
+                                       }
+                               }
+                               // Search for { and }
+                               if s[j+1] == '{' { // Modifier block
+                                       sep := strings.Index(s[j+2:], "}")
+                                       if sep == -1 {
+                                               return "bad modifier in $GENERATE"
+                                       }
+                                       mod, offset, err = modToPrintf(s[j+2 : j+2+sep])
+                                       if err != nil {
+                                               return err.Error()
+                                       }
+                                       j += 2 + sep // Jump to it
+                               }
+                               dom.WriteString(fmt.Sprintf(mod, i+offset))
+                       default:
+                               if escape { // Pretty useless here
+                                       escape = false
+                                       continue
+                               }
+                               dom.WriteByte(s[j])
+                       }
+               }
+               // Re-parse the RR and send it on the current channel t
+               rx, err := NewRR("$ORIGIN " + o + "\n" + dom.String())
+               if err != nil {
+                       return err.Error()
+               }
+               t <- &Token{RR: rx}
+               // Its more efficient to first built the rrlist and then parse it in
+               // one go! But is this a problem?
+       }
+       return ""
+}
+
+// Convert a $GENERATE modifier 0,0,d to something Printf can deal with.
+func modToPrintf(s string) (string, int, error) {
+       xs := strings.SplitN(s, ",", 3)
+       if len(xs) != 3 {
+               return "", 0, errors.New("bad modifier in $GENERATE")
+       }
+       // xs[0] is offset, xs[1] is width, xs[2] is base
+       if xs[2] != "o" && xs[2] != "d" && xs[2] != "x" && xs[2] != "X" {
+               return "", 0, errors.New("bad base in $GENERATE")
+       }
+       offset, err := strconv.Atoi(xs[0])
+       if err != nil || offset > 255 {
+               return "", 0, errors.New("bad offset in $GENERATE")
+       }
+       width, err := strconv.Atoi(xs[1])
+       if err != nil || width > 255 {
+               return "", offset, errors.New("bad width in $GENERATE")
+       }
+       switch {
+       case width < 0:
+               return "", offset, errors.New("bad width in $GENERATE")
+       case width == 0:
+               return "%" + xs[1] + xs[2], offset, nil
+       }
+       return "%0" + xs[1] + xs[2], offset, nil
+}
diff --git a/vendor/github.com/miekg/dns/labels.go b/vendor/github.com/miekg/dns/labels.go
new file mode 100644 (file)
index 0000000..fca5c7d
--- /dev/null
@@ -0,0 +1,168 @@
+package dns
+
+// Holds a bunch of helper functions for dealing with labels.
+
+// SplitDomainName splits a name string into it's labels.
+// www.miek.nl. returns []string{"www", "miek", "nl"}
+// .www.miek.nl. returns []string{"", "www", "miek", "nl"},
+// The root label (.) returns nil. Note that using
+// strings.Split(s) will work in most cases, but does not handle
+// escaped dots (\.) for instance.
+// s must be a syntactically valid domain name, see IsDomainName.
+func SplitDomainName(s string) (labels []string) {
+       if len(s) == 0 {
+               return nil
+       }
+       fqdnEnd := 0 // offset of the final '.' or the length of the name
+       idx := Split(s)
+       begin := 0
+       if s[len(s)-1] == '.' {
+               fqdnEnd = len(s) - 1
+       } else {
+               fqdnEnd = len(s)
+       }
+
+       switch len(idx) {
+       case 0:
+               return nil
+       case 1:
+               // no-op
+       default:
+               end := 0
+               for i := 1; i < len(idx); i++ {
+                       end = idx[i]
+                       labels = append(labels, s[begin:end-1])
+                       begin = end
+               }
+       }
+
+       labels = append(labels, s[begin:fqdnEnd])
+       return labels
+}
+
+// CompareDomainName compares the names s1 and s2 and
+// returns how many labels they have in common starting from the *right*.
+// The comparison stops at the first inequality. The names are not downcased
+// before the comparison.
+//
+// www.miek.nl. and miek.nl. have two labels in common: miek and nl
+// www.miek.nl. and www.bla.nl. have one label in common: nl
+//
+// s1 and s2 must be syntactically valid domain names.
+func CompareDomainName(s1, s2 string) (n int) {
+       s1 = Fqdn(s1)
+       s2 = Fqdn(s2)
+       l1 := Split(s1)
+       l2 := Split(s2)
+
+       // the first check: root label
+       if l1 == nil || l2 == nil {
+               return
+       }
+
+       j1 := len(l1) - 1 // end
+       i1 := len(l1) - 2 // start
+       j2 := len(l2) - 1
+       i2 := len(l2) - 2
+       // the second check can be done here: last/only label
+       // before we fall through into the for-loop below
+       if s1[l1[j1]:] == s2[l2[j2]:] {
+               n++
+       } else {
+               return
+       }
+       for {
+               if i1 < 0 || i2 < 0 {
+                       break
+               }
+               if s1[l1[i1]:l1[j1]] == s2[l2[i2]:l2[j2]] {
+                       n++
+               } else {
+                       break
+               }
+               j1--
+               i1--
+               j2--
+               i2--
+       }
+       return
+}
+
+// CountLabel counts the the number of labels in the string s.
+// s must be a syntactically valid domain name.
+func CountLabel(s string) (labels int) {
+       if s == "." {
+               return
+       }
+       off := 0
+       end := false
+       for {
+               off, end = NextLabel(s, off)
+               labels++
+               if end {
+                       return
+               }
+       }
+}
+
+// Split splits a name s into its label indexes.
+// www.miek.nl. returns []int{0, 4, 9}, www.miek.nl also returns []int{0, 4, 9}.
+// The root name (.) returns nil. Also see SplitDomainName.
+// s must be a syntactically valid domain name.
+func Split(s string) []int {
+       if s == "." {
+               return nil
+       }
+       idx := make([]int, 1, 3)
+       off := 0
+       end := false
+
+       for {
+               off, end = NextLabel(s, off)
+               if end {
+                       return idx
+               }
+               idx = append(idx, off)
+       }
+}
+
+// NextLabel returns the index of the start of the next label in the
+// string s starting at offset.
+// 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
+       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
+               }
+       }
+       return i + 1, true
+}
+
+// PrevLabel returns the index of the label when starting from the right and
+// jumping n labels to the left.
+// 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 n == 0 {
+               return len(s), false
+       }
+       lab := Split(s)
+       if lab == nil {
+               return 0, true
+       }
+       if n > len(lab) {
+               return 0, true
+       }
+       return lab[len(lab)-n], false
+}
diff --git a/vendor/github.com/miekg/dns/msg.go b/vendor/github.com/miekg/dns/msg.go
new file mode 100644 (file)
index 0000000..ec2f7ab
--- /dev/null
@@ -0,0 +1,1231 @@
+// DNS packet assembly, see RFC 1035. Converting from - Unpack() -
+// and to - Pack() - wire format.
+// All the packers and unpackers take a (msg []byte, off int)
+// and return (off1 int, ok bool).  If they return ok==false, they
+// also return off1==len(msg), so that the next unpacker will
+// also fail.  This lets us avoid checks of ok until the end of a
+// packing sequence.
+
+package dns
+
+//go:generate go run msg_generate.go
+
+import (
+       crand "crypto/rand"
+       "encoding/binary"
+       "math/big"
+       "math/rand"
+       "strconv"
+)
+
+func init() {
+       // Initialize default math/rand source using crypto/rand to provide better
+       // security without the performance trade-off.
+       buf := make([]byte, 8)
+       _, err := crand.Read(buf)
+       if err != nil {
+               // Failed to read from cryptographic source, fallback to default initial
+               // seed (1) by returning early
+               return
+       }
+       seed := binary.BigEndian.Uint64(buf)
+       rand.Seed(int64(seed))
+}
+
+const maxCompressionOffset = 2 << 13 // We have 14 bits for the compression pointer
+
+var (
+       ErrAlg           error = &Error{err: "bad algorithm"}                  // ErrAlg indicates an error with the (DNSSEC) algorithm.
+       ErrAuth          error = &Error{err: "bad authentication"}             // ErrAuth indicates an error in the TSIG authentication.
+       ErrBuf           error = &Error{err: "buffer size too small"}          // ErrBuf indicates that the buffer used it too small for the message.
+       ErrConnEmpty     error = &Error{err: "conn has no connection"}         // ErrConnEmpty indicates a connection is being uses before it is initialized.
+       ErrExtendedRcode error = &Error{err: "bad extended rcode"}             // ErrExtendedRcode ...
+       ErrFqdn          error = &Error{err: "domain must be fully qualified"} // ErrFqdn indicates that a domain name does not have a closing dot.
+       ErrId            error = &Error{err: "id mismatch"}                    // ErrId indicates there is a mismatch with the message's ID.
+       ErrKeyAlg        error = &Error{err: "bad key algorithm"}              // ErrKeyAlg indicates that the algorithm in the key is not valid.
+       ErrKey           error = &Error{err: "bad key"}
+       ErrKeySize       error = &Error{err: "bad key size"}
+       ErrNoSig         error = &Error{err: "no signature found"}
+       ErrPrivKey       error = &Error{err: "bad private key"}
+       ErrRcode         error = &Error{err: "bad rcode"}
+       ErrRdata         error = &Error{err: "bad rdata"}
+       ErrRRset         error = &Error{err: "bad rrset"}
+       ErrSecret        error = &Error{err: "no secrets defined"}
+       ErrShortRead     error = &Error{err: "short read"}
+       ErrSig           error = &Error{err: "bad signature"}                      // ErrSig indicates that a signature can not be cryptographically validated.
+       ErrSoa           error = &Error{err: "no SOA"}                             // ErrSOA indicates that no SOA RR was seen when doing zone transfers.
+       ErrTime          error = &Error{err: "bad time"}                           // ErrTime indicates a timing error in TSIG authentication.
+       ErrTruncated     error = &Error{err: "failed to unpack truncated message"} // ErrTruncated indicates that we failed to unpack a truncated message. We unpacked as much as we had so Msg can still be used, if desired.
+)
+
+// 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:
+//
+//     dns.Id = func() uint16 { return 3 }
+var Id func() uint16 = id
+
+// id returns a 16 bits random number to be used as a
+// message id. The random provided should be good enough.
+func id() uint16 {
+       id32 := rand.Uint32()
+       return uint16(id32)
+}
+
+// MsgHdr is a a manually-unpacked version of (id, bits).
+type MsgHdr struct {
+       Id                 uint16
+       Response           bool
+       Opcode             int
+       Authoritative      bool
+       Truncated          bool
+       RecursionDesired   bool
+       RecursionAvailable bool
+       Zero               bool
+       AuthenticatedData  bool
+       CheckingDisabled   bool
+       Rcode              int
+}
+
+// Msg contains the layout of a DNS message.
+type Msg struct {
+       MsgHdr
+       Compress bool       `json:"-"` // If true, the message will be compressed when converted to wire format.
+       Question []Question // Holds the RR(s) of the question section.
+       Answer   []RR       // Holds the RR(s) of the answer section.
+       Ns       []RR       // Holds the RR(s) of the authority section.
+       Extra    []RR       // Holds the RR(s) of the additional section.
+}
+
+// ClassToString is a maps Classes to strings for each CLASS wire type.
+var ClassToString = map[uint16]string{
+       ClassINET:   "IN",
+       ClassCSNET:  "CS",
+       ClassCHAOS:  "CH",
+       ClassHESIOD: "HS",
+       ClassNONE:   "NONE",
+       ClassANY:    "ANY",
+}
+
+// OpcodeToString maps Opcodes to strings.
+var OpcodeToString = map[int]string{
+       OpcodeQuery:  "QUERY",
+       OpcodeIQuery: "IQUERY",
+       OpcodeStatus: "STATUS",
+       OpcodeNotify: "NOTIFY",
+       OpcodeUpdate: "UPDATE",
+}
+
+// RcodeToString maps Rcodes to strings.
+var RcodeToString = map[int]string{
+       RcodeSuccess:        "NOERROR",
+       RcodeFormatError:    "FORMERR",
+       RcodeServerFailure:  "SERVFAIL",
+       RcodeNameError:      "NXDOMAIN",
+       RcodeNotImplemented: "NOTIMPL",
+       RcodeRefused:        "REFUSED",
+       RcodeYXDomain:       "YXDOMAIN", // See RFC 2136
+       RcodeYXRrset:        "YXRRSET",
+       RcodeNXRrset:        "NXRRSET",
+       RcodeNotAuth:        "NOTAUTH",
+       RcodeNotZone:        "NOTZONE",
+       RcodeBadSig:         "BADSIG", // Also known as RcodeBadVers, see RFC 6891
+       //      RcodeBadVers:        "BADVERS",
+       RcodeBadKey:    "BADKEY",
+       RcodeBadTime:   "BADTIME",
+       RcodeBadMode:   "BADMODE",
+       RcodeBadName:   "BADNAME",
+       RcodeBadAlg:    "BADALG",
+       RcodeBadTrunc:  "BADTRUNC",
+       RcodeBadCookie: "BADCOOKIE",
+}
+
+// Domain names are a sequence of counted strings
+// split at the dots. They end with a zero-length string.
+
+// PackDomainName packs a domain name s into msg[off:].
+// If compression is wanted compress must be true and the compression
+// map needs to hold a mapping between domain names and offsets
+// pointing into msg.
+func PackDomainName(s string, msg []byte, off int, compression map[string]int, compress bool) (off1 int, err error) {
+       off1, _, err = packDomainName(s, msg, off, compression, compress)
+       return
+}
+
+func packDomainName(s string, msg []byte, off int, compression map[string]int, compress bool) (off1 int, labels int, err error) {
+       // special case if msg == nil
+       lenmsg := 256
+       if msg != nil {
+               lenmsg = len(msg)
+       }
+       ls := len(s)
+       if ls == 0 { // Ok, for instance when dealing with update RR without any rdata.
+               return off, 0, nil
+       }
+       // If not fully qualified, error out, but only if msg == nil #ugly
+       switch {
+       case msg == nil:
+               if s[ls-1] != '.' {
+                       s += "."
+                       ls++
+               }
+       case msg != nil:
+               if s[ls-1] != '.' {
+                       return lenmsg, 0, ErrFqdn
+               }
+       }
+       // Each dot ends a segment of the name.
+       // We trade each dot byte for a length byte.
+       // Except for escaped dots (\.), which are normal dots.
+       // There is also a trailing zero.
+
+       // Compression
+       nameoffset := -1
+       pointer := -1
+       // Emit sequence of counted strings, chopping at dots.
+       begin := 0
+       bs := []byte(s)
+       roBs, bsFresh, escapedDot := s, true, false
+       for i := 0; i < ls; i++ {
+               if bs[i] == '\\' {
+                       for j := i; j < ls-1; j++ {
+                               bs[j] = bs[j+1]
+                       }
+                       ls--
+                       if off+1 > lenmsg {
+                               return lenmsg, labels, ErrBuf
+                       }
+                       // check for \DDD
+                       if i+2 < ls && isDigit(bs[i]) && isDigit(bs[i+1]) && isDigit(bs[i+2]) {
+                               bs[i] = dddToByte(bs[i:])
+                               for j := i + 1; j < ls-2; j++ {
+                                       bs[j] = bs[j+2]
+                               }
+                               ls -= 2
+                       } else if bs[i] == 't' {
+                               bs[i] = '\t'
+                       } else if bs[i] == 'r' {
+                               bs[i] = '\r'
+                       } else if bs[i] == 'n' {
+                               bs[i] = '\n'
+                       }
+                       escapedDot = bs[i] == '.'
+                       bsFresh = false
+                       continue
+               }
+
+               if bs[i] == '.' {
+                       if i > 0 && bs[i-1] == '.' && !escapedDot {
+                               // two dots back to back is not legal
+                               return lenmsg, labels, ErrRdata
+                       }
+                       if i-begin >= 1<<6 { // top two bits of length must be clear
+                               return lenmsg, labels, ErrRdata
+                       }
+                       // off can already (we're in a loop) be bigger than len(msg)
+                       // this happens when a name isn't fully qualified
+                       if off+1 > lenmsg {
+                               return lenmsg, labels, ErrBuf
+                       }
+                       if msg != nil {
+                               msg[off] = byte(i - begin)
+                       }
+                       offset := off
+                       off++
+                       for j := begin; j < i; j++ {
+                               if off+1 > lenmsg {
+                                       return lenmsg, labels, ErrBuf
+                               }
+                               if msg != nil {
+                                       msg[off] = bs[j]
+                               }
+                               off++
+                       }
+                       if compress && !bsFresh {
+                               roBs = string(bs)
+                               bsFresh = true
+                       }
+                       // Don't try to compress '.'
+                       if compress && roBs[begin:] != "." {
+                               if p, ok := compression[roBs[begin:]]; !ok {
+                                       // Only offsets smaller than this can be used.
+                                       if offset < maxCompressionOffset {
+                                               compression[roBs[begin:]] = offset
+                                       }
+                               } else {
+                                       // The first hit is the longest matching dname
+                                       // keep the pointer offset we get back and store
+                                       // the offset of the current name, because that's
+                                       // where we need to insert the pointer later
+
+                                       // If compress is true, we're allowed to compress this dname
+                                       if pointer == -1 && compress {
+                                               pointer = p         // Where to point to
+                                               nameoffset = offset // Where to point from
+                                               break
+                                       }
+                               }
+                       }
+                       labels++
+                       begin = i + 1
+               }
+               escapedDot = false
+       }
+       // Root label is special
+       if len(bs) == 1 && bs[0] == '.' {
+               return off, labels, nil
+       }
+       // If we did compression and we find something add the pointer here
+       if pointer != -1 {
+               // We have two bytes (14 bits) to put the pointer in
+               // if msg == nil, we will never do compression
+               binary.BigEndian.PutUint16(msg[nameoffset:], uint16(pointer^0xC000))
+               off = nameoffset + 1
+               goto End
+       }
+       if msg != nil && off < len(msg) {
+               msg[off] = 0
+       }
+End:
+       off++
+       return off, labels, nil
+}
+
+// Unpack a domain name.
+// In addition to the simple sequences of counted strings above,
+// domain names are allowed to refer to strings elsewhere in the
+// packet, to avoid repeating common suffixes when returning
+// many entries in a single domain.  The pointers are marked
+// by a length byte with the top two bits set.  Ignoring those
+// two bits, that byte and the next give a 14 bit offset from msg[0]
+// where we should pick up the trail.
+// Note that if we jump elsewhere in the packet,
+// we return off1 == the offset after the first pointer we found,
+// which is where the next record will start.
+// In theory, the pointers are only allowed to jump backward.
+// We let them jump anywhere and stop jumping after a while.
+
+// UnpackDomainName unpacks a domain name into a string.
+func UnpackDomainName(msg []byte, off int) (string, int, error) {
+       s := make([]byte, 0, 64)
+       off1 := 0
+       lenmsg := len(msg)
+       ptr := 0 // number of pointers followed
+Loop:
+       for {
+               if off >= lenmsg {
+                       return "", lenmsg, ErrBuf
+               }
+               c := int(msg[off])
+               off++
+               switch c & 0xC0 {
+               case 0x00:
+                       if c == 0x00 {
+                               // end of name
+                               break Loop
+                       }
+                       // literal string
+                       if off+c > lenmsg {
+                               return "", lenmsg, ErrBuf
+                       }
+                       for j := off; j < off+c; j++ {
+                               switch b := msg[j]; b {
+                               case '.', '(', ')', ';', ' ', '@':
+                                       fallthrough
+                               case '"', '\\':
+                                       s = append(s, '\\', b)
+                               case '\t':
+                                       s = append(s, '\\', 't')
+                               case '\r':
+                                       s = append(s, '\\', 'r')
+                               default:
+                                       if b < 32 || b >= 127 { // unprintable use \DDD
+                                               var buf [3]byte
+                                               bufs := strconv.AppendInt(buf[:0], int64(b), 10)
+                                               s = append(s, '\\')
+                                               for i := 0; i < 3-len(bufs); i++ {
+                                                       s = append(s, '0')
+                                               }
+                                               for _, r := range bufs {
+                                                       s = append(s, r)
+                                               }
+                                       } else {
+                                               s = append(s, b)
+                                       }
+                               }
+                       }
+                       s = append(s, '.')
+                       off += c
+               case 0xC0:
+                       // pointer to somewhere else in msg.
+                       // remember location after first ptr,
+                       // since that's how many bytes we consumed.
+                       // also, don't follow too many pointers --
+                       // maybe there's a loop.
+                       if off >= lenmsg {
+                               return "", lenmsg, ErrBuf
+                       }
+                       c1 := msg[off]
+                       off++
+                       if ptr == 0 {
+                               off1 = off
+                       }
+                       if ptr++; ptr > 10 {
+                               return "", lenmsg, &Error{err: "too many compression pointers"}
+                       }
+                       off = (c^0xC0)<<8 | int(c1)
+               default:
+                       // 0x80 and 0x40 are reserved
+                       return "", lenmsg, ErrRdata
+               }
+       }
+       if ptr == 0 {
+               off1 = off
+       }
+       if len(s) == 0 {
+               s = []byte(".")
+       }
+       return string(s), off1, nil
+}
+
+func packTxt(txt []string, msg []byte, offset int, tmp []byte) (int, error) {
+       if len(txt) == 0 {
+               if offset >= len(msg) {
+                       return offset, ErrBuf
+               }
+               msg[offset] = 0
+               return offset, nil
+       }
+       var err error
+       for i := range txt {
+               if len(txt[i]) > len(tmp) {
+                       return offset, ErrBuf
+               }
+               offset, err = packTxtString(txt[i], msg, offset, tmp)
+               if err != nil {
+                       return offset, err
+               }
+       }
+       return offset, nil
+}
+
+func packTxtString(s string, msg []byte, offset int, tmp []byte) (int, error) {
+       lenByteOffset := offset
+       if offset >= len(msg) || len(s) > len(tmp) {
+               return offset, ErrBuf
+       }
+       offset++
+       bs := tmp[:len(s)]
+       copy(bs, s)
+       for i := 0; i < len(bs); i++ {
+               if len(msg) <= offset {
+                       return offset, ErrBuf
+               }
+               if bs[i] == '\\' {
+                       i++
+                       if i == len(bs) {
+                               break
+                       }
+                       // check for \DDD
+                       if i+2 < len(bs) && isDigit(bs[i]) && isDigit(bs[i+1]) && isDigit(bs[i+2]) {
+                               msg[offset] = dddToByte(bs[i:])
+                               i += 2
+                       } else if bs[i] == 't' {
+                               msg[offset] = '\t'
+                       } else if bs[i] == 'r' {
+                               msg[offset] = '\r'
+                       } else if bs[i] == 'n' {
+                               msg[offset] = '\n'
+                       } else {
+                               msg[offset] = bs[i]
+                       }
+               } else {
+                       msg[offset] = bs[i]
+               }
+               offset++
+       }
+       l := offset - lenByteOffset - 1
+       if l > 255 {
+               return offset, &Error{err: "string exceeded 255 bytes in txt"}
+       }
+       msg[lenByteOffset] = byte(l)
+       return offset, nil
+}
+
+func packOctetString(s string, msg []byte, offset int, tmp []byte) (int, error) {
+       if offset >= len(msg) || len(s) > len(tmp) {
+               return offset, ErrBuf
+       }
+       bs := tmp[:len(s)]
+       copy(bs, s)
+       for i := 0; i < len(bs); i++ {
+               if len(msg) <= offset {
+                       return offset, ErrBuf
+               }
+               if bs[i] == '\\' {
+                       i++
+                       if i == len(bs) {
+                               break
+                       }
+                       // check for \DDD
+                       if i+2 < len(bs) && isDigit(bs[i]) && isDigit(bs[i+1]) && isDigit(bs[i+2]) {
+                               msg[offset] = dddToByte(bs[i:])
+                               i += 2
+                       } else {
+                               msg[offset] = bs[i]
+                       }
+               } else {
+                       msg[offset] = bs[i]
+               }
+               offset++
+       }
+       return offset, nil
+}
+
+func unpackTxt(msg []byte, off0 int) (ss []string, off int, err error) {
+       off = off0
+       var s string
+       for off < len(msg) && err == nil {
+               s, off, err = unpackTxtString(msg, off)
+               if err == nil {
+                       ss = append(ss, s)
+               }
+       }
+       return
+}
+
+func unpackTxtString(msg []byte, offset int) (string, int, error) {
+       if offset+1 > len(msg) {
+               return "", offset, &Error{err: "overflow unpacking txt"}
+       }
+       l := int(msg[offset])
+       if offset+l+1 > len(msg) {
+               return "", offset, &Error{err: "overflow unpacking txt"}
+       }
+       s := make([]byte, 0, l)
+       for _, b := range msg[offset+1 : offset+1+l] {
+               switch b {
+               case '"', '\\':
+                       s = append(s, '\\', b)
+               case '\t':
+                       s = append(s, `\t`...)
+               case '\r':
+                       s = append(s, `\r`...)
+               case '\n':
+                       s = append(s, `\n`...)
+               default:
+                       if b < 32 || b > 127 { // unprintable
+                               var buf [3]byte
+                               bufs := strconv.AppendInt(buf[:0], int64(b), 10)
+                               s = append(s, '\\')
+                               for i := 0; i < 3-len(bufs); i++ {
+                                       s = append(s, '0')
+                               }
+                               for _, r := range bufs {
+                                       s = append(s, r)
+                               }
+                       } else {
+                               s = append(s, b)
+                       }
+               }
+       }
+       offset += 1 + l
+       return string(s), offset, nil
+}
+
+// Helpers for dealing with escaped bytes
+func isDigit(b byte) bool { return b >= '0' && b <= '9' }
+
+func dddToByte(s []byte) byte {
+       return byte((s[0]-'0')*100 + (s[1]-'0')*10 + (s[2] - '0'))
+}
+
+// Helper function for packing and unpacking
+func intToBytes(i *big.Int, length int) []byte {
+       buf := i.Bytes()
+       if len(buf) < length {
+               b := make([]byte, length)
+               copy(b[length-len(buf):], buf)
+               return b
+       }
+       return buf
+}
+
+// PackRR packs a resource record rr into msg[off:].
+// See PackDomainName for documentation about the compression.
+func PackRR(rr RR, msg []byte, off int, compression map[string]int, compress bool) (off1 int, err error) {
+       if rr == nil {
+               return len(msg), &Error{err: "nil rr"}
+       }
+
+       off1, err = rr.pack(msg, off, compression, compress)
+       if err != nil {
+               return len(msg), err
+       }
+       // TODO(miek): Not sure if this is needed? If removed we can remove rawmsg.go as well.
+       if rawSetRdlength(msg, off, off1) {
+               return off1, nil
+       }
+       return off, ErrRdata
+}
+
+// UnpackRR unpacks msg[off:] into an RR.
+func UnpackRR(msg []byte, off int) (rr RR, off1 int, err error) {
+       h, off, msg, err := unpackHeader(msg, off)
+       if err != nil {
+               return nil, len(msg), err
+       }
+       end := off + int(h.Rdlength)
+
+       if fn, known := typeToUnpack[h.Rrtype]; !known {
+               rr, off, err = unpackRFC3597(h, msg, off)
+       } else {
+               rr, off, err = fn(h, msg, off)
+       }
+       if off != end {
+               return &h, end, &Error{err: "bad rdlength"}
+       }
+       return rr, off, err
+}
+
+// unpackRRslice unpacks msg[off:] into an []RR.
+// If we cannot unpack the whole array, then it will return nil
+func unpackRRslice(l int, msg []byte, off int) (dst1 []RR, off1 int, err error) {
+       var r RR
+       // Optimistically make dst be the length that was sent
+       dst := make([]RR, 0, l)
+       for i := 0; i < l; i++ {
+               off1 := off
+               r, off, err = UnpackRR(msg, off)
+               if err != nil {
+                       off = len(msg)
+                       break
+               }
+               // If offset does not increase anymore, l is a lie
+               if off1 == off {
+                       l = i
+                       break
+               }
+               dst = append(dst, r)
+       }
+       if err != nil && off == len(msg) {
+               dst = nil
+       }
+       return dst, off, err
+}
+
+// Convert a MsgHdr to a string, with dig-like headers:
+//
+//;; opcode: QUERY, status: NOERROR, id: 48404
+//
+//;; flags: qr aa rd ra;
+func (h *MsgHdr) String() string {
+       if h == nil {
+               return "<nil> MsgHdr"
+       }
+
+       s := ";; opcode: " + OpcodeToString[h.Opcode]
+       s += ", status: " + RcodeToString[h.Rcode]
+       s += ", id: " + strconv.Itoa(int(h.Id)) + "\n"
+
+       s += ";; flags:"
+       if h.Response {
+               s += " qr"
+       }
+       if h.Authoritative {
+               s += " aa"
+       }
+       if h.Truncated {
+               s += " tc"
+       }
+       if h.RecursionDesired {
+               s += " rd"
+       }
+       if h.RecursionAvailable {
+               s += " ra"
+       }
+       if h.Zero { // Hmm
+               s += " z"
+       }
+       if h.AuthenticatedData {
+               s += " ad"
+       }
+       if h.CheckingDisabled {
+               s += " cd"
+       }
+
+       s += ";"
+       return s
+}
+
+// Pack packs a Msg: it is converted to to wire format.
+// If the dns.Compress is true the message will be in compressed wire format.
+func (dns *Msg) Pack() (msg []byte, err error) {
+       return dns.PackBuffer(nil)
+}
+
+// PackBuffer packs a Msg, using the given buffer buf. If buf is too small
+// a new buffer is allocated.
+func (dns *Msg) PackBuffer(buf []byte) (msg []byte, err error) {
+       // We use a similar function in tsig.go's stripTsig.
+       var (
+               dh          Header
+               compression map[string]int
+       )
+
+       if dns.Compress {
+               compression = make(map[string]int) // Compression pointer mappings
+       }
+
+       if dns.Rcode < 0 || dns.Rcode > 0xFFF {
+               return nil, ErrRcode
+       }
+       if dns.Rcode > 0xF {
+               // Regular RCODE field is 4 bits
+               opt := dns.IsEdns0()
+               if opt == nil {
+                       return nil, ErrExtendedRcode
+               }
+               opt.SetExtendedRcode(uint8(dns.Rcode >> 4))
+               dns.Rcode &= 0xF
+       }
+
+       // Convert convenient Msg into wire-like Header.
+       dh.Id = dns.Id
+       dh.Bits = uint16(dns.Opcode)<<11 | uint16(dns.Rcode)
+       if dns.Response {
+               dh.Bits |= _QR
+       }
+       if dns.Authoritative {
+               dh.Bits |= _AA
+       }
+       if dns.Truncated {
+               dh.Bits |= _TC
+       }
+       if dns.RecursionDesired {
+               dh.Bits |= _RD
+       }
+       if dns.RecursionAvailable {
+               dh.Bits |= _RA
+       }
+       if dns.Zero {
+               dh.Bits |= _Z
+       }
+       if dns.AuthenticatedData {
+               dh.Bits |= _AD
+       }
+       if dns.CheckingDisabled {
+               dh.Bits |= _CD
+       }
+
+       // Prepare variable sized arrays.
+       question := dns.Question
+       answer := dns.Answer
+       ns := dns.Ns
+       extra := dns.Extra
+
+       dh.Qdcount = uint16(len(question))
+       dh.Ancount = uint16(len(answer))
+       dh.Nscount = uint16(len(ns))
+       dh.Arcount = uint16(len(extra))
+
+       // We need the uncompressed length here, because we first pack it and then compress it.
+       msg = buf
+       compress := dns.Compress
+       dns.Compress = false
+       if packLen := dns.Len() + 1; len(msg) < packLen {
+               msg = make([]byte, packLen)
+       }
+       dns.Compress = compress
+
+       // Pack it in: header and then the pieces.
+       off := 0
+       off, err = dh.pack(msg, off, compression, dns.Compress)
+       if err != nil {
+               return nil, err
+       }
+       for i := 0; i < len(question); i++ {
+               off, err = question[i].pack(msg, off, compression, dns.Compress)
+               if err != nil {
+                       return nil, err
+               }
+       }
+       for i := 0; i < len(answer); i++ {
+               off, err = PackRR(answer[i], msg, off, compression, dns.Compress)
+               if err != nil {
+                       return nil, err
+               }
+       }
+       for i := 0; i < len(ns); i++ {
+               off, err = PackRR(ns[i], msg, off, compression, dns.Compress)
+               if err != nil {
+                       return nil, err
+               }
+       }
+       for i := 0; i < len(extra); i++ {
+               off, err = PackRR(extra[i], msg, off, compression, dns.Compress)
+               if err != nil {
+                       return nil, err
+               }
+       }
+       return msg[:off], nil
+}
+
+// Unpack unpacks a binary message to a Msg structure.
+func (dns *Msg) Unpack(msg []byte) (err error) {
+       var (
+               dh  Header
+               off int
+       )
+       if dh, off, err = unpackMsgHdr(msg, off); err != nil {
+               return err
+       }
+       if off == len(msg) {
+               return ErrTruncated
+       }
+
+       dns.Id = dh.Id
+       dns.Response = (dh.Bits & _QR) != 0
+       dns.Opcode = int(dh.Bits>>11) & 0xF
+       dns.Authoritative = (dh.Bits & _AA) != 0
+       dns.Truncated = (dh.Bits & _TC) != 0
+       dns.RecursionDesired = (dh.Bits & _RD) != 0
+       dns.RecursionAvailable = (dh.Bits & _RA) != 0
+       dns.Zero = (dh.Bits & _Z) != 0
+       dns.AuthenticatedData = (dh.Bits & _AD) != 0
+       dns.CheckingDisabled = (dh.Bits & _CD) != 0
+       dns.Rcode = int(dh.Bits & 0xF)
+
+       // Optimistically use the count given to us in the header
+       dns.Question = make([]Question, 0, int(dh.Qdcount))
+
+       for i := 0; i < int(dh.Qdcount); i++ {
+               off1 := off
+               var q Question
+               q, off, err = unpackQuestion(msg, off)
+               if err != nil {
+                       // Even if Truncated is set, we only will set ErrTruncated if we
+                       // actually got the questions
+                       return err
+               }
+               if off1 == off { // Offset does not increase anymore, dh.Qdcount is a lie!
+                       dh.Qdcount = uint16(i)
+                       break
+               }
+               dns.Question = append(dns.Question, q)
+       }
+
+       dns.Answer, off, err = unpackRRslice(int(dh.Ancount), msg, off)
+       // The header counts might have been wrong so we need to update it
+       dh.Ancount = uint16(len(dns.Answer))
+       if err == nil {
+               dns.Ns, off, err = unpackRRslice(int(dh.Nscount), msg, off)
+       }
+       // The header counts might have been wrong so we need to update it
+       dh.Nscount = uint16(len(dns.Ns))
+       if err == nil {
+               dns.Extra, off, err = unpackRRslice(int(dh.Arcount), msg, off)
+       }
+       // The header counts might have been wrong so we need to update it
+       dh.Arcount = uint16(len(dns.Extra))
+
+       if off != len(msg) {
+               // TODO(miek) make this an error?
+               // use PackOpt to let people tell how detailed the error reporting should be?
+               // println("dns: extra bytes in dns packet", off, "<", len(msg))
+       } else if dns.Truncated {
+               // Whether we ran into a an error or not, we want to return that it
+               // was truncated
+               err = ErrTruncated
+       }
+       return err
+}
+
+// Convert a complete message to a string with dig-like output.
+func (dns *Msg) String() string {
+       if dns == nil {
+               return "<nil> MsgHdr"
+       }
+       s := dns.MsgHdr.String() + " "
+       s += "QUERY: " + strconv.Itoa(len(dns.Question)) + ", "
+       s += "ANSWER: " + strconv.Itoa(len(dns.Answer)) + ", "
+       s += "AUTHORITY: " + strconv.Itoa(len(dns.Ns)) + ", "
+       s += "ADDITIONAL: " + strconv.Itoa(len(dns.Extra)) + "\n"
+       if len(dns.Question) > 0 {
+               s += "\n;; QUESTION SECTION:\n"
+               for i := 0; i < len(dns.Question); i++ {
+                       s += dns.Question[i].String() + "\n"
+               }
+       }
+       if len(dns.Answer) > 0 {
+               s += "\n;; ANSWER SECTION:\n"
+               for i := 0; i < len(dns.Answer); i++ {
+                       if dns.Answer[i] != nil {
+                               s += dns.Answer[i].String() + "\n"
+                       }
+               }
+       }
+       if len(dns.Ns) > 0 {
+               s += "\n;; AUTHORITY SECTION:\n"
+               for i := 0; i < len(dns.Ns); i++ {
+                       if dns.Ns[i] != nil {
+                               s += dns.Ns[i].String() + "\n"
+                       }
+               }
+       }
+       if len(dns.Extra) > 0 {
+               s += "\n;; ADDITIONAL SECTION:\n"
+               for i := 0; i < len(dns.Extra); i++ {
+                       if dns.Extra[i] != nil {
+                               s += dns.Extra[i].String() + "\n"
+                       }
+               }
+       }
+       return s
+}
+
+// Len returns the message length when in (un)compressed wire format.
+// If dns.Compress is true compression it is taken into account. Len()
+// is provided to be a faster way to get the size of the resulting packet,
+// than packing it, measuring the size and discarding the buffer.
+func (dns *Msg) Len() int {
+       // We always return one more than needed.
+       l := 12 // Message header is always 12 bytes
+       var compression map[string]int
+       if dns.Compress {
+               compression = make(map[string]int)
+       }
+       for i := 0; i < len(dns.Question); i++ {
+               l += dns.Question[i].len()
+               if dns.Compress {
+                       compressionLenHelper(compression, dns.Question[i].Name)
+               }
+       }
+       for i := 0; i < len(dns.Answer); i++ {
+               if dns.Answer[i] == nil {
+                       continue
+               }
+               l += dns.Answer[i].len()
+               if dns.Compress {
+                       k, ok := compressionLenSearch(compression, dns.Answer[i].Header().Name)
+                       if ok {
+                               l += 1 - k
+                       }
+                       compressionLenHelper(compression, dns.Answer[i].Header().Name)
+                       k, ok = compressionLenSearchType(compression, dns.Answer[i])
+                       if ok {
+                               l += 1 - k
+                       }
+                       compressionLenHelperType(compression, dns.Answer[i])
+               }
+       }
+       for i := 0; i < len(dns.Ns); i++ {
+               if dns.Ns[i] == nil {
+                       continue
+               }
+               l += dns.Ns[i].len()
+               if dns.Compress {
+                       k, ok := compressionLenSearch(compression, dns.Ns[i].Header().Name)
+                       if ok {
+                               l += 1 - k
+                       }
+                       compressionLenHelper(compression, dns.Ns[i].Header().Name)
+                       k, ok = compressionLenSearchType(compression, dns.Ns[i])
+                       if ok {
+                               l += 1 - k
+                       }
+                       compressionLenHelperType(compression, dns.Ns[i])
+               }
+       }
+       for i := 0; i < len(dns.Extra); i++ {
+               if dns.Extra[i] == nil {
+                       continue
+               }
+               l += dns.Extra[i].len()
+               if dns.Compress {
+                       k, ok := compressionLenSearch(compression, dns.Extra[i].Header().Name)
+                       if ok {
+                               l += 1 - k
+                       }
+                       compressionLenHelper(compression, dns.Extra[i].Header().Name)
+                       k, ok = compressionLenSearchType(compression, dns.Extra[i])
+                       if ok {
+                               l += 1 - k
+                       }
+                       compressionLenHelperType(compression, dns.Extra[i])
+               }
+       }
+       return l
+}
+
+// Put the parts of the name in the compression map.
+func compressionLenHelper(c map[string]int, s string) {
+       pref := ""
+       lbs := Split(s)
+       for j := len(lbs) - 1; j >= 0; j-- {
+               pref = s[lbs[j]:]
+               if _, ok := c[pref]; !ok {
+                       c[pref] = len(pref)
+               }
+       }
+}
+
+// Look for each part in the compression map and returns its length,
+// keep on searching so we get the longest match.
+func compressionLenSearch(c map[string]int, s string) (int, bool) {
+       off := 0
+       end := false
+       if s == "" { // don't bork on bogus data
+               return 0, false
+       }
+       for {
+               if _, ok := c[s[off:]]; ok {
+                       return len(s[off:]), true
+               }
+               if end {
+                       break
+               }
+               off, end = NextLabel(s, off)
+       }
+       return 0, false
+}
+
+// TODO(miek): should add all types, because the all can be *used* for compression. Autogenerate from msg_generate and put in zmsg.go
+func compressionLenHelperType(c map[string]int, r RR) {
+       switch x := r.(type) {
+       case *NS:
+               compressionLenHelper(c, x.Ns)
+       case *MX:
+               compressionLenHelper(c, x.Mx)
+       case *CNAME:
+               compressionLenHelper(c, x.Target)
+       case *PTR:
+               compressionLenHelper(c, x.Ptr)
+       case *SOA:
+               compressionLenHelper(c, x.Ns)
+               compressionLenHelper(c, x.Mbox)
+       case *MB:
+               compressionLenHelper(c, x.Mb)
+       case *MG:
+               compressionLenHelper(c, x.Mg)
+       case *MR:
+               compressionLenHelper(c, x.Mr)
+       case *MF:
+               compressionLenHelper(c, x.Mf)
+       case *MD:
+               compressionLenHelper(c, x.Md)
+       case *RT:
+               compressionLenHelper(c, x.Host)
+       case *RP:
+               compressionLenHelper(c, x.Mbox)
+               compressionLenHelper(c, x.Txt)
+       case *MINFO:
+               compressionLenHelper(c, x.Rmail)
+               compressionLenHelper(c, x.Email)
+       case *AFSDB:
+               compressionLenHelper(c, x.Hostname)
+       case *SRV:
+               compressionLenHelper(c, x.Target)
+       case *NAPTR:
+               compressionLenHelper(c, x.Replacement)
+       case *RRSIG:
+               compressionLenHelper(c, x.SignerName)
+       case *NSEC:
+               compressionLenHelper(c, x.NextDomain)
+               // HIP?
+       }
+}
+
+// Only search on compressing these types.
+func compressionLenSearchType(c map[string]int, r RR) (int, bool) {
+       switch x := r.(type) {
+       case *NS:
+               return compressionLenSearch(c, x.Ns)
+       case *MX:
+               return compressionLenSearch(c, x.Mx)
+       case *CNAME:
+               return compressionLenSearch(c, x.Target)
+       case *DNAME:
+               return compressionLenSearch(c, x.Target)
+       case *PTR:
+               return compressionLenSearch(c, x.Ptr)
+       case *SOA:
+               k, ok := compressionLenSearch(c, x.Ns)
+               k1, ok1 := compressionLenSearch(c, x.Mbox)
+               if !ok && !ok1 {
+                       return 0, false
+               }
+               return k + k1, true
+       case *MB:
+               return compressionLenSearch(c, x.Mb)
+       case *MG:
+               return compressionLenSearch(c, x.Mg)
+       case *MR:
+               return compressionLenSearch(c, x.Mr)
+       case *MF:
+               return compressionLenSearch(c, x.Mf)
+       case *MD:
+               return compressionLenSearch(c, x.Md)
+       case *RT:
+               return compressionLenSearch(c, x.Host)
+       case *MINFO:
+               k, ok := compressionLenSearch(c, x.Rmail)
+               k1, ok1 := compressionLenSearch(c, x.Email)
+               if !ok && !ok1 {
+                       return 0, false
+               }
+               return k + k1, true
+       case *AFSDB:
+               return compressionLenSearch(c, x.Hostname)
+       }
+       return 0, false
+}
+
+// Copy returns a new RR which is a deep-copy of r.
+func Copy(r RR) RR { r1 := r.copy(); return r1 }
+
+// Len returns the length (in octets) of the uncompressed RR in wire format.
+func Len(r RR) int { return r.len() }
+
+// Copy returns a new *Msg which is a deep-copy of dns.
+func (dns *Msg) Copy() *Msg { return dns.CopyTo(new(Msg)) }
+
+// CopyTo copies the contents to the provided message using a deep-copy and returns the copy.
+func (dns *Msg) CopyTo(r1 *Msg) *Msg {
+       r1.MsgHdr = dns.MsgHdr
+       r1.Compress = dns.Compress
+
+       if len(dns.Question) > 0 {
+               r1.Question = make([]Question, len(dns.Question))
+               copy(r1.Question, dns.Question) // TODO(miek): Question is an immutable value, ok to do a shallow-copy
+       }
+
+       rrArr := make([]RR, len(dns.Answer)+len(dns.Ns)+len(dns.Extra))
+       var rri int
+
+       if len(dns.Answer) > 0 {
+               rrbegin := rri
+               for i := 0; i < len(dns.Answer); i++ {
+                       rrArr[rri] = dns.Answer[i].copy()
+                       rri++
+               }
+               r1.Answer = rrArr[rrbegin:rri:rri]
+       }
+
+       if len(dns.Ns) > 0 {
+               rrbegin := rri
+               for i := 0; i < len(dns.Ns); i++ {
+                       rrArr[rri] = dns.Ns[i].copy()
+                       rri++
+               }
+               r1.Ns = rrArr[rrbegin:rri:rri]
+       }
+
+       if len(dns.Extra) > 0 {
+               rrbegin := rri
+               for i := 0; i < len(dns.Extra); i++ {
+                       rrArr[rri] = dns.Extra[i].copy()
+                       rri++
+               }
+               r1.Extra = rrArr[rrbegin:rri:rri]
+       }
+
+       return r1
+}
+
+func (q *Question) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
+       off, err := PackDomainName(q.Name, msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint16(q.Qtype, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint16(q.Qclass, msg, off)
+       if err != nil {
+               return off, err
+       }
+       return off, nil
+}
+
+func unpackQuestion(msg []byte, off int) (Question, int, error) {
+       var (
+               q   Question
+               err error
+       )
+       q.Name, off, err = UnpackDomainName(msg, off)
+       if err != nil {
+               return q, off, err
+       }
+       if off == len(msg) {
+               return q, off, nil
+       }
+       q.Qtype, off, err = unpackUint16(msg, off)
+       if err != nil {
+               return q, off, err
+       }
+       if off == len(msg) {
+               return q, off, nil
+       }
+       q.Qclass, off, err = unpackUint16(msg, off)
+       if off == len(msg) {
+               return q, off, nil
+       }
+       return q, off, err
+}
+
+func (dh *Header) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
+       off, err := packUint16(dh.Id, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint16(dh.Bits, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint16(dh.Qdcount, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint16(dh.Ancount, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint16(dh.Nscount, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint16(dh.Arcount, msg, off)
+       return off, err
+}
+
+func unpackMsgHdr(msg []byte, off int) (Header, int, error) {
+       var (
+               dh  Header
+               err error
+       )
+       dh.Id, off, err = unpackUint16(msg, off)
+       if err != nil {
+               return dh, off, err
+       }
+       dh.Bits, off, err = unpackUint16(msg, off)
+       if err != nil {
+               return dh, off, err
+       }
+       dh.Qdcount, off, err = unpackUint16(msg, off)
+       if err != nil {
+               return dh, off, err
+       }
+       dh.Ancount, off, err = unpackUint16(msg, off)
+       if err != nil {
+               return dh, off, err
+       }
+       dh.Nscount, off, err = unpackUint16(msg, off)
+       if err != nil {
+               return dh, off, err
+       }
+       dh.Arcount, off, err = unpackUint16(msg, off)
+       return dh, off, err
+}
diff --git a/vendor/github.com/miekg/dns/msg_generate.go b/vendor/github.com/miekg/dns/msg_generate.go
new file mode 100644 (file)
index 0000000..166b3af
--- /dev/null
@@ -0,0 +1,337 @@
+//+build ignore
+
+// msg_generate.go is meant to run with go generate. It will use
+// go/{importer,types} to track down all the RR struct types. Then for each type
+// it will generate pack/unpack methods based on the struct tags. The generated source is
+// written to zmsg.go, and is meant to be checked into git.
+package main
+
+import (
+       "bytes"
+       "fmt"
+       "go/format"
+       "go/importer"
+       "go/types"
+       "log"
+       "os"
+       "strings"
+)
+
+var packageHdr = `
+// *** DO NOT MODIFY ***
+// AUTOGENERATED BY go generate from msg_generate.go
+
+package dns
+
+`
+
+// getTypeStruct will take a type and the package scope, and return the
+// (innermost) struct if the type is considered a RR type (currently defined as
+// those structs beginning with a RR_Header, could be redefined as implementing
+// the RR interface). The bool return value indicates if embedded structs were
+// resolved.
+func getTypeStruct(t types.Type, scope *types.Scope) (*types.Struct, bool) {
+       st, ok := t.Underlying().(*types.Struct)
+       if !ok {
+               return nil, false
+       }
+       if st.Field(0).Type() == scope.Lookup("RR_Header").Type() {
+               return st, false
+       }
+       if st.Field(0).Anonymous() {
+               st, _ := getTypeStruct(st.Field(0).Type(), scope)
+               return st, true
+       }
+       return nil, false
+}
+
+func main() {
+       // Import and type-check the package
+       pkg, err := importer.Default().Import("github.com/miekg/dns")
+       fatalIfErr(err)
+       scope := pkg.Scope()
+
+       // Collect actual types (*X)
+       var namedTypes []string
+       for _, name := range scope.Names() {
+               o := scope.Lookup(name)
+               if o == nil || !o.Exported() {
+                       continue
+               }
+               if st, _ := getTypeStruct(o.Type(), scope); st == nil {
+                       continue
+               }
+               if name == "PrivateRR" {
+                       continue
+               }
+
+               // Check if corresponding TypeX exists
+               if scope.Lookup("Type"+o.Name()) == nil && o.Name() != "RFC3597" {
+                       log.Fatalf("Constant Type%s does not exist.", o.Name())
+               }
+
+               namedTypes = append(namedTypes, o.Name())
+       }
+
+       b := &bytes.Buffer{}
+       b.WriteString(packageHdr)
+
+       fmt.Fprint(b, "// pack*() functions\n\n")
+       for _, name := range namedTypes {
+               o := scope.Lookup(name)
+               st, _ := getTypeStruct(o.Type(), scope)
+
+               fmt.Fprintf(b, "func (rr *%s) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {\n", name)
+               fmt.Fprint(b, `off, err := rr.Hdr.pack(msg, off, compression, compress)
+if err != nil {
+       return off, err
+}
+headerEnd := off
+`)
+               for i := 1; i < st.NumFields(); i++ {
+                       o := func(s string) {
+                               fmt.Fprintf(b, s, st.Field(i).Name())
+                               fmt.Fprint(b, `if err != nil {
+return off, err
+}
+`)
+                       }
+
+                       if _, ok := st.Field(i).Type().(*types.Slice); ok {
+                               switch st.Tag(i) {
+                               case `dns:"-"`: // ignored
+                               case `dns:"txt"`:
+                                       o("off, err = packStringTxt(rr.%s, msg, off)\n")
+                               case `dns:"opt"`:
+                                       o("off, err = packDataOpt(rr.%s, msg, off)\n")
+                               case `dns:"nsec"`:
+                                       o("off, err = packDataNsec(rr.%s, msg, off)\n")
+                               case `dns:"domain-name"`:
+                                       o("off, err = packDataDomainNames(rr.%s, msg, off, compression, compress)\n")
+                               default:
+                                       log.Fatalln(name, st.Field(i).Name(), st.Tag(i))
+                               }
+                               continue
+                       }
+
+                       switch {
+                       case st.Tag(i) == `dns:"-"`: // ignored
+                       case st.Tag(i) == `dns:"cdomain-name"`:
+                               fallthrough
+                       case st.Tag(i) == `dns:"domain-name"`:
+                               o("off, err = PackDomainName(rr.%s, msg, off, compression, compress)\n")
+                       case st.Tag(i) == `dns:"a"`:
+                               o("off, err = packDataA(rr.%s, msg, off)\n")
+                       case st.Tag(i) == `dns:"aaaa"`:
+                               o("off, err = packDataAAAA(rr.%s, msg, off)\n")
+                       case st.Tag(i) == `dns:"uint48"`:
+                               o("off, err = packUint48(rr.%s, msg, off)\n")
+                       case st.Tag(i) == `dns:"txt"`:
+                               o("off, err = packString(rr.%s, msg, off)\n")
+
+                       case strings.HasPrefix(st.Tag(i), `dns:"size-base32`): // size-base32 can be packed just like base32
+                               fallthrough
+                       case st.Tag(i) == `dns:"base32"`:
+                               o("off, err = packStringBase32(rr.%s, msg, off)\n")
+
+                       case strings.HasPrefix(st.Tag(i), `dns:"size-base64`): // size-base64 can be packed just like base64
+                               fallthrough
+                       case st.Tag(i) == `dns:"base64"`:
+                               o("off, err = packStringBase64(rr.%s, msg, off)\n")
+
+                       case strings.HasPrefix(st.Tag(i), `dns:"size-hex`): // size-hex can be packed just like hex
+                               fallthrough
+                       case st.Tag(i) == `dns:"hex"`:
+                               o("off, err = packStringHex(rr.%s, msg, off)\n")
+
+                       case st.Tag(i) == `dns:"octet"`:
+                               o("off, err = packStringOctet(rr.%s, msg, off)\n")
+                       case st.Tag(i) == "":
+                               switch st.Field(i).Type().(*types.Basic).Kind() {
+                               case types.Uint8:
+                                       o("off, err = packUint8(rr.%s, msg, off)\n")
+                               case types.Uint16:
+                                       o("off, err = packUint16(rr.%s, msg, off)\n")
+                               case types.Uint32:
+                                       o("off, err = packUint32(rr.%s, msg, off)\n")
+                               case types.Uint64:
+                                       o("off, err = packUint64(rr.%s, msg, off)\n")
+                               case types.String:
+                                       o("off, err = packString(rr.%s, msg, off)\n")
+                               default:
+                                       log.Fatalln(name, st.Field(i).Name())
+                               }
+                       default:
+                               log.Fatalln(name, st.Field(i).Name(), st.Tag(i))
+                       }
+               }
+               // We have packed everything, only now we know the rdlength of this RR
+               fmt.Fprintln(b, "rr.Header().Rdlength = uint16(off- headerEnd)")
+               fmt.Fprintln(b, "return off, nil }\n")
+       }
+
+       fmt.Fprint(b, "// unpack*() functions\n\n")
+       for _, name := range namedTypes {
+               o := scope.Lookup(name)
+               st, _ := getTypeStruct(o.Type(), scope)
+
+               fmt.Fprintf(b, "func unpack%s(h RR_Header, msg []byte, off int) (RR, int, error) {\n", name)
+               fmt.Fprintf(b, "rr := new(%s)\n", name)
+               fmt.Fprint(b, "rr.Hdr = h\n")
+               fmt.Fprint(b, `if noRdata(h) {
+return rr, off, nil
+       }
+var err error
+rdStart := off
+_ = rdStart
+
+`)
+               for i := 1; i < st.NumFields(); i++ {
+                       o := func(s string) {
+                               fmt.Fprintf(b, s, st.Field(i).Name())
+                               fmt.Fprint(b, `if err != nil {
+return rr, off, err
+}
+`)
+                       }
+
+                       // size-* are special, because they reference a struct member we should use for the length.
+                       if strings.HasPrefix(st.Tag(i), `dns:"size-`) {
+                               structMember := structMember(st.Tag(i))
+                               structTag := structTag(st.Tag(i))
+                               switch structTag {
+                               case "hex":
+                                       fmt.Fprintf(b, "rr.%s, off, err = unpackStringHex(msg, off, off + int(rr.%s))\n", st.Field(i).Name(), structMember)
+                               case "base32":
+                                       fmt.Fprintf(b, "rr.%s, off, err = unpackStringBase32(msg, off, off + int(rr.%s))\n", st.Field(i).Name(), structMember)
+                               case "base64":
+                                       fmt.Fprintf(b, "rr.%s, off, err = unpackStringBase64(msg, off, off + int(rr.%s))\n", st.Field(i).Name(), structMember)
+                               default:
+                                       log.Fatalln(name, st.Field(i).Name(), st.Tag(i))
+                               }
+                               fmt.Fprint(b, `if err != nil {
+return rr, off, err
+}
+`)
+                               continue
+                       }
+
+                       if _, ok := st.Field(i).Type().(*types.Slice); ok {
+                               switch st.Tag(i) {
+                               case `dns:"-"`: // ignored
+                               case `dns:"txt"`:
+                                       o("rr.%s, off, err = unpackStringTxt(msg, off)\n")
+                               case `dns:"opt"`:
+                                       o("rr.%s, off, err = unpackDataOpt(msg, off)\n")
+                               case `dns:"nsec"`:
+                                       o("rr.%s, off, err = unpackDataNsec(msg, off)\n")
+                               case `dns:"domain-name"`:
+                                       o("rr.%s, off, err = unpackDataDomainNames(msg, off, rdStart + int(rr.Hdr.Rdlength))\n")
+                               default:
+                                       log.Fatalln(name, st.Field(i).Name(), st.Tag(i))
+                               }
+                               continue
+                       }
+
+                       switch st.Tag(i) {
+                       case `dns:"-"`: // ignored
+                       case `dns:"cdomain-name"`:
+                               fallthrough
+                       case `dns:"domain-name"`:
+                               o("rr.%s, off, err = UnpackDomainName(msg, off)\n")
+                       case `dns:"a"`:
+                               o("rr.%s, off, err = unpackDataA(msg, off)\n")
+                       case `dns:"aaaa"`:
+                               o("rr.%s, off, err = unpackDataAAAA(msg, off)\n")
+                       case `dns:"uint48"`:
+                               o("rr.%s, off, err = unpackUint48(msg, off)\n")
+                       case `dns:"txt"`:
+                               o("rr.%s, off, err = unpackString(msg, off)\n")
+                       case `dns:"base32"`:
+                               o("rr.%s, off, err = unpackStringBase32(msg, off, rdStart + int(rr.Hdr.Rdlength))\n")
+                       case `dns:"base64"`:
+                               o("rr.%s, off, err = unpackStringBase64(msg, off, rdStart + int(rr.Hdr.Rdlength))\n")
+                       case `dns:"hex"`:
+                               o("rr.%s, off, err = unpackStringHex(msg, off, rdStart + int(rr.Hdr.Rdlength))\n")
+                       case `dns:"octet"`:
+                               o("rr.%s, off, err = unpackStringOctet(msg, off)\n")
+                       case "":
+                               switch st.Field(i).Type().(*types.Basic).Kind() {
+                               case types.Uint8:
+                                       o("rr.%s, off, err = unpackUint8(msg, off)\n")
+                               case types.Uint16:
+                                       o("rr.%s, off, err = unpackUint16(msg, off)\n")
+                               case types.Uint32:
+                                       o("rr.%s, off, err = unpackUint32(msg, off)\n")
+                               case types.Uint64:
+                                       o("rr.%s, off, err = unpackUint64(msg, off)\n")
+                               case types.String:
+                                       o("rr.%s, off, err = unpackString(msg, off)\n")
+                               default:
+                                       log.Fatalln(name, st.Field(i).Name())
+                               }
+                       default:
+                               log.Fatalln(name, st.Field(i).Name(), st.Tag(i))
+                       }
+                       // If we've hit len(msg) we return without error.
+                       if i < st.NumFields()-1 {
+                               fmt.Fprintf(b, `if off == len(msg) {
+return rr, off, nil
+       }
+`)
+                       }
+               }
+               fmt.Fprintf(b, "return rr, off, err }\n\n")
+       }
+       // Generate typeToUnpack map
+       fmt.Fprintln(b, "var typeToUnpack = map[uint16]func(RR_Header, []byte, int) (RR, int, error){")
+       for _, name := range namedTypes {
+               if name == "RFC3597" {
+                       continue
+               }
+               fmt.Fprintf(b, "Type%s: unpack%s,\n", name, name)
+       }
+       fmt.Fprintln(b, "}\n")
+
+       // gofmt
+       res, err := format.Source(b.Bytes())
+       if err != nil {
+               b.WriteTo(os.Stderr)
+               log.Fatal(err)
+       }
+
+       // write result
+       f, err := os.Create("zmsg.go")
+       fatalIfErr(err)
+       defer f.Close()
+       f.Write(res)
+}
+
+// structMember will take a tag like dns:"size-base32:SaltLength" and return the last part of this string.
+func structMember(s string) string {
+       fields := strings.Split(s, ":")
+       if len(fields) == 0 {
+               return ""
+       }
+       f := fields[len(fields)-1]
+       // f should have a closing "
+       if len(f) > 1 {
+               return f[:len(f)-1]
+       }
+       return f
+}
+
+// structTag will take a tag like dns:"size-base32:SaltLength" and return base32.
+func structTag(s string) string {
+       fields := strings.Split(s, ":")
+       if len(fields) < 2 {
+               return ""
+       }
+       return fields[1][len("\"size-"):]
+}
+
+func fatalIfErr(err error) {
+       if err != nil {
+               log.Fatal(err)
+       }
+}
diff --git a/vendor/github.com/miekg/dns/msg_helpers.go b/vendor/github.com/miekg/dns/msg_helpers.go
new file mode 100644 (file)
index 0000000..e7a9500
--- /dev/null
@@ -0,0 +1,630 @@
+package dns
+
+import (
+       "encoding/base32"
+       "encoding/base64"
+       "encoding/binary"
+       "encoding/hex"
+       "net"
+       "strconv"
+)
+
+// helper functions called from the generated zmsg.go
+
+// These function are named after the tag to help pack/unpack, if there is no tag it is the name
+// of the type they pack/unpack (string, int, etc). We prefix all with unpackData or packData, so packDataA or
+// packDataDomainName.
+
+func unpackDataA(msg []byte, off int) (net.IP, int, error) {
+       if off+net.IPv4len > len(msg) {
+               return nil, len(msg), &Error{err: "overflow unpacking a"}
+       }
+       a := append(make(net.IP, 0, net.IPv4len), msg[off:off+net.IPv4len]...)
+       off += net.IPv4len
+       return a, off, nil
+}
+
+func packDataA(a net.IP, msg []byte, off int) (int, error) {
+       // It must be a slice of 4, even if it is 16, we encode only the first 4
+       if off+net.IPv4len > len(msg) {
+               return len(msg), &Error{err: "overflow packing a"}
+       }
+       switch len(a) {
+       case net.IPv4len, net.IPv6len:
+               copy(msg[off:], a.To4())
+               off += net.IPv4len
+       case 0:
+               // Allowed, for dynamic updates.
+       default:
+               return len(msg), &Error{err: "overflow packing a"}
+       }
+       return off, nil
+}
+
+func unpackDataAAAA(msg []byte, off int) (net.IP, int, error) {
+       if off+net.IPv6len > len(msg) {
+               return nil, len(msg), &Error{err: "overflow unpacking aaaa"}
+       }
+       aaaa := append(make(net.IP, 0, net.IPv6len), msg[off:off+net.IPv6len]...)
+       off += net.IPv6len
+       return aaaa, off, nil
+}
+
+func packDataAAAA(aaaa net.IP, msg []byte, off int) (int, error) {
+       if off+net.IPv6len > len(msg) {
+               return len(msg), &Error{err: "overflow packing aaaa"}
+       }
+
+       switch len(aaaa) {
+       case net.IPv6len:
+               copy(msg[off:], aaaa)
+               off += net.IPv6len
+       case 0:
+               // Allowed, dynamic updates.
+       default:
+               return len(msg), &Error{err: "overflow packing aaaa"}
+       }
+       return off, nil
+}
+
+// unpackHeader unpacks an RR header, returning the offset to the end of the header and a
+// re-sliced msg according to the expected length of the RR.
+func unpackHeader(msg []byte, off int) (rr RR_Header, off1 int, truncmsg []byte, err error) {
+       hdr := RR_Header{}
+       if off == len(msg) {
+               return hdr, off, msg, nil
+       }
+
+       hdr.Name, off, err = UnpackDomainName(msg, off)
+       if err != nil {
+               return hdr, len(msg), msg, err
+       }
+       hdr.Rrtype, off, err = unpackUint16(msg, off)
+       if err != nil {
+               return hdr, len(msg), msg, err
+       }
+       hdr.Class, off, err = unpackUint16(msg, off)
+       if err != nil {
+               return hdr, len(msg), msg, err
+       }
+       hdr.Ttl, off, err = unpackUint32(msg, off)
+       if err != nil {
+               return hdr, len(msg), msg, err
+       }
+       hdr.Rdlength, off, err = unpackUint16(msg, off)
+       if err != nil {
+               return hdr, len(msg), msg, err
+       }
+       msg, err = truncateMsgFromRdlength(msg, off, hdr.Rdlength)
+       return hdr, off, msg, nil
+}
+
+// pack packs an RR header, returning the offset to the end of the header.
+// See PackDomainName for documentation about the compression.
+func (hdr RR_Header) pack(msg []byte, off int, compression map[string]int, compress bool) (off1 int, err error) {
+       if off == len(msg) {
+               return off, nil
+       }
+
+       off, err = PackDomainName(hdr.Name, msg, off, compression, compress)
+       if err != nil {
+               return len(msg), err
+       }
+       off, err = packUint16(hdr.Rrtype, msg, off)
+       if err != nil {
+               return len(msg), err
+       }
+       off, err = packUint16(hdr.Class, msg, off)
+       if err != nil {
+               return len(msg), err
+       }
+       off, err = packUint32(hdr.Ttl, msg, off)
+       if err != nil {
+               return len(msg), err
+       }
+       off, err = packUint16(hdr.Rdlength, msg, off)
+       if err != nil {
+               return len(msg), err
+       }
+       return off, nil
+}
+
+// helper helper functions.
+
+// truncateMsgFromRdLength truncates msg to match the expected length of the RR.
+// Returns an error if msg is smaller than the expected size.
+func truncateMsgFromRdlength(msg []byte, off int, rdlength uint16) (truncmsg []byte, err error) {
+       lenrd := off + int(rdlength)
+       if lenrd > len(msg) {
+               return msg, &Error{err: "overflowing header size"}
+       }
+       return msg[:lenrd], nil
+}
+
+func fromBase32(s []byte) (buf []byte, err error) {
+       buflen := base32.HexEncoding.DecodedLen(len(s))
+       buf = make([]byte, buflen)
+       n, err := base32.HexEncoding.Decode(buf, s)
+       buf = buf[:n]
+       return
+}
+
+func toBase32(b []byte) string { return base32.HexEncoding.EncodeToString(b) }
+
+func fromBase64(s []byte) (buf []byte, err error) {
+       buflen := base64.StdEncoding.DecodedLen(len(s))
+       buf = make([]byte, buflen)
+       n, err := base64.StdEncoding.Decode(buf, s)
+       buf = buf[:n]
+       return
+}
+
+func toBase64(b []byte) string { return base64.StdEncoding.EncodeToString(b) }
+
+// dynamicUpdate returns true if the Rdlength is zero.
+func noRdata(h RR_Header) bool { return h.Rdlength == 0 }
+
+func unpackUint8(msg []byte, off int) (i uint8, off1 int, err error) {
+       if off+1 > len(msg) {
+               return 0, len(msg), &Error{err: "overflow unpacking uint8"}
+       }
+       return uint8(msg[off]), off + 1, nil
+}
+
+func packUint8(i uint8, msg []byte, off int) (off1 int, err error) {
+       if off+1 > len(msg) {
+               return len(msg), &Error{err: "overflow packing uint8"}
+       }
+       msg[off] = byte(i)
+       return off + 1, nil
+}
+
+func unpackUint16(msg []byte, off int) (i uint16, off1 int, err error) {
+       if off+2 > len(msg) {
+               return 0, len(msg), &Error{err: "overflow unpacking uint16"}
+       }
+       return binary.BigEndian.Uint16(msg[off:]), off + 2, nil
+}
+
+func packUint16(i uint16, msg []byte, off int) (off1 int, err error) {
+       if off+2 > len(msg) {
+               return len(msg), &Error{err: "overflow packing uint16"}
+       }
+       binary.BigEndian.PutUint16(msg[off:], i)
+       return off + 2, nil
+}
+
+func unpackUint32(msg []byte, off int) (i uint32, off1 int, err error) {
+       if off+4 > len(msg) {
+               return 0, len(msg), &Error{err: "overflow unpacking uint32"}
+       }
+       return binary.BigEndian.Uint32(msg[off:]), off + 4, nil
+}
+
+func packUint32(i uint32, msg []byte, off int) (off1 int, err error) {
+       if off+4 > len(msg) {
+               return len(msg), &Error{err: "overflow packing uint32"}
+       }
+       binary.BigEndian.PutUint32(msg[off:], i)
+       return off + 4, nil
+}
+
+func unpackUint48(msg []byte, off int) (i uint64, off1 int, err error) {
+       if off+6 > len(msg) {
+               return 0, len(msg), &Error{err: "overflow unpacking uint64 as uint48"}
+       }
+       // Used in TSIG where the last 48 bits are occupied, so for now, assume a uint48 (6 bytes)
+       i = (uint64(uint64(msg[off])<<40 | uint64(msg[off+1])<<32 | uint64(msg[off+2])<<24 | uint64(msg[off+3])<<16 |
+               uint64(msg[off+4])<<8 | uint64(msg[off+5])))
+       off += 6
+       return i, off, nil
+}
+
+func packUint48(i uint64, msg []byte, off int) (off1 int, err error) {
+       if off+6 > len(msg) {
+               return len(msg), &Error{err: "overflow packing uint64 as uint48"}
+       }
+       msg[off] = byte(i >> 40)
+       msg[off+1] = byte(i >> 32)
+       msg[off+2] = byte(i >> 24)
+       msg[off+3] = byte(i >> 16)
+       msg[off+4] = byte(i >> 8)
+       msg[off+5] = byte(i)
+       off += 6
+       return off, nil
+}
+
+func unpackUint64(msg []byte, off int) (i uint64, off1 int, err error) {
+       if off+8 > len(msg) {
+               return 0, len(msg), &Error{err: "overflow unpacking uint64"}
+       }
+       return binary.BigEndian.Uint64(msg[off:]), off + 8, nil
+}
+
+func packUint64(i uint64, msg []byte, off int) (off1 int, err error) {
+       if off+8 > len(msg) {
+               return len(msg), &Error{err: "overflow packing uint64"}
+       }
+       binary.BigEndian.PutUint64(msg[off:], i)
+       off += 8
+       return off, nil
+}
+
+func unpackString(msg []byte, off int) (string, int, error) {
+       if off+1 > len(msg) {
+               return "", off, &Error{err: "overflow unpacking txt"}
+       }
+       l := int(msg[off])
+       if off+l+1 > len(msg) {
+               return "", off, &Error{err: "overflow unpacking txt"}
+       }
+       s := make([]byte, 0, l)
+       for _, b := range msg[off+1 : off+1+l] {
+               switch b {
+               case '"', '\\':
+                       s = append(s, '\\', b)
+               case '\t', '\r', '\n':
+                       s = append(s, b)
+               default:
+                       if b < 32 || b > 127 { // unprintable
+                               var buf [3]byte
+                               bufs := strconv.AppendInt(buf[:0], int64(b), 10)
+                               s = append(s, '\\')
+                               for i := 0; i < 3-len(bufs); i++ {
+                                       s = append(s, '0')
+                               }
+                               for _, r := range bufs {
+                                       s = append(s, r)
+                               }
+                       } else {
+                               s = append(s, b)
+                       }
+               }
+       }
+       off += 1 + l
+       return string(s), off, nil
+}
+
+func packString(s string, msg []byte, off int) (int, error) {
+       txtTmp := make([]byte, 256*4+1)
+       off, err := packTxtString(s, msg, off, txtTmp)
+       if err != nil {
+               return len(msg), err
+       }
+       return off, nil
+}
+
+func unpackStringBase32(msg []byte, off, end int) (string, int, error) {
+       if end > len(msg) {
+               return "", len(msg), &Error{err: "overflow unpacking base32"}
+       }
+       s := toBase32(msg[off:end])
+       return s, end, nil
+}
+
+func packStringBase32(s string, msg []byte, off int) (int, error) {
+       b32, err := fromBase32([]byte(s))
+       if err != nil {
+               return len(msg), err
+       }
+       if off+len(b32) > len(msg) {
+               return len(msg), &Error{err: "overflow packing base32"}
+       }
+       copy(msg[off:off+len(b32)], b32)
+       off += len(b32)
+       return off, nil
+}
+
+func unpackStringBase64(msg []byte, off, end int) (string, int, error) {
+       // Rest of the RR is base64 encoded value, so we don't need an explicit length
+       // to be set. Thus far all RR's that have base64 encoded fields have those as their
+       // last one. What we do need is the end of the RR!
+       if end > len(msg) {
+               return "", len(msg), &Error{err: "overflow unpacking base64"}
+       }
+       s := toBase64(msg[off:end])
+       return s, end, nil
+}
+
+func packStringBase64(s string, msg []byte, off int) (int, error) {
+       b64, err := fromBase64([]byte(s))
+       if err != nil {
+               return len(msg), err
+       }
+       if off+len(b64) > len(msg) {
+               return len(msg), &Error{err: "overflow packing base64"}
+       }
+       copy(msg[off:off+len(b64)], b64)
+       off += len(b64)
+       return off, nil
+}
+
+func unpackStringHex(msg []byte, off, end int) (string, int, error) {
+       // Rest of the RR is hex encoded value, so we don't need an explicit length
+       // to be set. NSEC and TSIG have hex fields with a length field.
+       // What we do need is the end of the RR!
+       if end > len(msg) {
+               return "", len(msg), &Error{err: "overflow unpacking hex"}
+       }
+
+       s := hex.EncodeToString(msg[off:end])
+       return s, end, nil
+}
+
+func packStringHex(s string, msg []byte, off int) (int, error) {
+       h, err := hex.DecodeString(s)
+       if err != nil {
+               return len(msg), err
+       }
+       if off+(len(h)) > len(msg) {
+               return len(msg), &Error{err: "overflow packing hex"}
+       }
+       copy(msg[off:off+len(h)], h)
+       off += len(h)
+       return off, nil
+}
+
+func unpackStringTxt(msg []byte, off int) ([]string, int, error) {
+       txt, off, err := unpackTxt(msg, off)
+       if err != nil {
+               return nil, len(msg), err
+       }
+       return txt, off, nil
+}
+
+func packStringTxt(s []string, msg []byte, off int) (int, error) {
+       txtTmp := make([]byte, 256*4+1) // If the whole string consists out of \DDD we need this many.
+       off, err := packTxt(s, msg, off, txtTmp)
+       if err != nil {
+               return len(msg), err
+       }
+       return off, nil
+}
+
+func unpackDataOpt(msg []byte, off int) ([]EDNS0, int, error) {
+       var edns []EDNS0
+Option:
+       code := uint16(0)
+       if off+4 > len(msg) {
+               return nil, len(msg), &Error{err: "overflow unpacking opt"}
+       }
+       code = binary.BigEndian.Uint16(msg[off:])
+       off += 2
+       optlen := binary.BigEndian.Uint16(msg[off:])
+       off += 2
+       if off+int(optlen) > len(msg) {
+               return nil, len(msg), &Error{err: "overflow unpacking opt"}
+       }
+       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)
+       case EDNS0SUBNET, EDNS0SUBNETDRAFT:
+               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)
+               if code == EDNS0SUBNETDRAFT {
+                       e.DraftOption = true
+               }
+       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)
+       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)
+       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)
+       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)
+       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)
+       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)
+       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)
+       }
+
+       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) {
+                       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
+               }
+               // Actual data
+               copy(msg[off:off+len(b)], b)
+               off += len(b)
+       }
+       return off, nil
+}
+
+func unpackStringOctet(msg []byte, off int) (string, int, error) {
+       s := string(msg[off:])
+       return s, len(msg), nil
+}
+
+func packStringOctet(s string, msg []byte, off int) (int, error) {
+       txtTmp := make([]byte, 256*4+1)
+       off, err := packOctetString(s, msg, off, txtTmp)
+       if err != nil {
+               return len(msg), err
+       }
+       return off, nil
+}
+
+func unpackDataNsec(msg []byte, off int) ([]uint16, int, error) {
+       var nsec []uint16
+       length, window, lastwindow := 0, 0, -1
+       for off < len(msg) {
+               if off+2 > len(msg) {
+                       return nsec, len(msg), &Error{err: "overflow unpacking nsecx"}
+               }
+               window = int(msg[off])
+               length = int(msg[off+1])
+               off += 2
+               if window <= lastwindow {
+                       // RFC 4034: Blocks are present in the NSEC RR RDATA in
+                       // increasing numerical order.
+                       return nsec, len(msg), &Error{err: "out of order NSEC block"}
+               }
+               if length == 0 {
+                       // RFC 4034: Blocks with no types present MUST NOT be included.
+                       return nsec, len(msg), &Error{err: "empty NSEC block"}
+               }
+               if length > 32 {
+                       return nsec, len(msg), &Error{err: "NSEC block too long"}
+               }
+               if off+length > len(msg) {
+                       return nsec, len(msg), &Error{err: "overflowing NSEC block"}
+               }
+
+               // Walk the bytes in the window and extract the type bits
+               for j := 0; j < length; j++ {
+                       b := msg[off+j]
+                       // Check the bits one by one, and set the type
+                       if b&0x80 == 0x80 {
+                               nsec = append(nsec, uint16(window*256+j*8+0))
+                       }
+                       if b&0x40 == 0x40 {
+                               nsec = append(nsec, uint16(window*256+j*8+1))
+                       }
+                       if b&0x20 == 0x20 {
+                               nsec = append(nsec, uint16(window*256+j*8+2))
+                       }
+                       if b&0x10 == 0x10 {
+                               nsec = append(nsec, uint16(window*256+j*8+3))
+                       }
+                       if b&0x8 == 0x8 {
+                               nsec = append(nsec, uint16(window*256+j*8+4))
+                       }
+                       if b&0x4 == 0x4 {
+                               nsec = append(nsec, uint16(window*256+j*8+5))
+                       }
+                       if b&0x2 == 0x2 {
+                               nsec = append(nsec, uint16(window*256+j*8+6))
+                       }
+                       if b&0x1 == 0x1 {
+                               nsec = append(nsec, uint16(window*256+j*8+7))
+                       }
+               }
+               off += length
+               lastwindow = window
+       }
+       return nsec, off, nil
+}
+
+func packDataNsec(bitmap []uint16, msg []byte, off int) (int, error) {
+       if len(bitmap) == 0 {
+               return off, nil
+       }
+       var lastwindow, lastlength uint16
+       for j := 0; j < len(bitmap); j++ {
+               t := bitmap[j]
+               window := t / 256
+               length := (t-window*256)/8 + 1
+               if window > lastwindow && lastlength != 0 { // New window, jump to the new offset
+                       off += int(lastlength) + 2
+                       lastlength = 0
+               }
+               if window < lastwindow || length < lastlength {
+                       return len(msg), &Error{err: "nsec bits out of order"}
+               }
+               if off+2+int(length) > len(msg) {
+                       return len(msg), &Error{err: "overflow packing nsec"}
+               }
+               // Setting the window #
+               msg[off] = byte(window)
+               // Setting the octets length
+               msg[off+1] = byte(length)
+               // Setting the bit value for the type in the right octet
+               msg[off+1+int(length)] |= byte(1 << (7 - (t % 8)))
+               lastwindow, lastlength = window, length
+       }
+       off += int(lastlength) + 2
+       return off, nil
+}
+
+func unpackDataDomainNames(msg []byte, off, end int) ([]string, int, error) {
+       var (
+               servers []string
+               s       string
+               err     error
+       )
+       if end > len(msg) {
+               return nil, len(msg), &Error{err: "overflow unpacking domain names"}
+       }
+       for off < end {
+               s, off, err = UnpackDomainName(msg, off)
+               if err != nil {
+                       return servers, len(msg), err
+               }
+               servers = append(servers, s)
+       }
+       return servers, off, nil
+}
+
+func packDataDomainNames(names []string, msg []byte, off int, compression map[string]int, compress bool) (int, error) {
+       var err error
+       for j := 0; j < len(names); j++ {
+               off, err = PackDomainName(names[j], msg, off, compression, false && compress)
+               if err != nil {
+                       return len(msg), err
+               }
+       }
+       return off, nil
+}
diff --git a/vendor/github.com/miekg/dns/nsecx.go b/vendor/github.com/miekg/dns/nsecx.go
new file mode 100644 (file)
index 0000000..6f10f3e
--- /dev/null
@@ -0,0 +1,119 @@
+package dns
+
+import (
+       "crypto/sha1"
+       "hash"
+       "io"
+       "strings"
+)
+
+type saltWireFmt struct {
+       Salt string `dns:"size-hex"`
+}
+
+// HashName hashes a string (label) according to RFC 5155. It returns the hashed string in uppercase.
+func HashName(label string, ha uint8, iter uint16, salt string) string {
+       saltwire := new(saltWireFmt)
+       saltwire.Salt = salt
+       wire := make([]byte, DefaultMsgSize)
+       n, err := packSaltWire(saltwire, wire)
+       if err != nil {
+               return ""
+       }
+       wire = wire[:n]
+       name := make([]byte, 255)
+       off, err := PackDomainName(strings.ToLower(label), name, 0, nil, false)
+       if err != nil {
+               return ""
+       }
+       name = name[:off]
+       var s hash.Hash
+       switch ha {
+       case SHA1:
+               s = sha1.New()
+       default:
+               return ""
+       }
+
+       // k = 0
+       name = append(name, wire...)
+       io.WriteString(s, string(name))
+       nsec3 := s.Sum(nil)
+       // k > 0
+       for k := uint16(0); k < iter; k++ {
+               s.Reset()
+               nsec3 = append(nsec3, wire...)
+               io.WriteString(s, string(nsec3))
+               nsec3 = s.Sum(nil)
+       }
+       return toBase32(nsec3)
+}
+
+// Denialer is an interface that should be implemented by types that are used to denial
+// answers in DNSSEC.
+type Denialer interface {
+       // Cover will check if the (unhashed) name is being covered by this NSEC or NSEC3.
+       Cover(name string) bool
+       // Match will check if the ownername matches the (unhashed) name for this NSEC3 or NSEC3.
+       Match(name string) bool
+}
+
+// Cover implements the Denialer interface.
+func (rr *NSEC) Cover(name string) bool {
+       return true
+}
+
+// Match implements the Denialer interface.
+func (rr *NSEC) Match(name string) bool {
+       return true
+}
+
+// Cover implements the Denialer interface.
+func (rr *NSEC3) Cover(name string) bool {
+       // FIXME(miek): check if the zones match
+       // FIXME(miek): check if we're not dealing with parent nsec3
+       hname := HashName(name, rr.Hash, rr.Iterations, rr.Salt)
+       labels := Split(rr.Hdr.Name)
+       if len(labels) < 2 {
+               return false
+       }
+       hash := strings.ToUpper(rr.Hdr.Name[labels[0] : labels[1]-1]) // -1 to remove the dot
+       if hash == rr.NextDomain {
+               return false // empty interval
+       }
+       if hash > rr.NextDomain { // last name, points to apex
+               // hname > hash
+               // hname > rr.NextDomain
+               // TODO(miek)
+       }
+       if hname <= hash {
+               return false
+       }
+       if hname >= rr.NextDomain {
+               return false
+       }
+       return true
+}
+
+// Match implements the Denialer interface.
+func (rr *NSEC3) Match(name string) bool {
+       // FIXME(miek): Check if we are in the same zone
+       hname := HashName(name, rr.Hash, rr.Iterations, rr.Salt)
+       labels := Split(rr.Hdr.Name)
+       if len(labels) < 2 {
+               return false
+       }
+       hash := strings.ToUpper(rr.Hdr.Name[labels[0] : labels[1]-1]) // -1 to remove the .
+       if hash == hname {
+               return true
+       }
+       return false
+}
+
+func packSaltWire(sw *saltWireFmt, msg []byte) (int, error) {
+       off, err := packStringHex(sw.Salt, msg, 0)
+       if err != nil {
+               return off, err
+       }
+       return off, nil
+}
diff --git a/vendor/github.com/miekg/dns/privaterr.go b/vendor/github.com/miekg/dns/privaterr.go
new file mode 100644 (file)
index 0000000..6b08e6e
--- /dev/null
@@ -0,0 +1,149 @@
+package dns
+
+import (
+       "fmt"
+       "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
+// official type code. Also see dns.PrivateHandle and dns.PrivateHandleRemove.
+type PrivateRdata interface {
+       // String returns the text presentaton of the Rdata of the Private RR.
+       String() string
+       // Parse parses the Rdata of the private RR.
+       Parse([]string) error
+       // 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(PrivateRdata) error
+       // Len returns the length in octets of the Rdata.
+       Len() int
+}
+
+// PrivateRR represents an RR that uses a PrivateRdata user-defined type.
+// It mocks normal RRs and implements dns.RR 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()
+       switch rr := anyrr.(type) {
+       case *PrivateRR:
+               return rr
+       }
+       panic(fmt.Sprintf("dns: RR is not a PrivateRR, TypeToRR[%d] generator returned %T", rrtype, anyrr))
+}
+
+// Header return the RR header of r.
+func (r *PrivateRR) Header() *RR_Header { return &r.Hdr }
+
+func (r *PrivateRR) String() string { return r.Hdr.String() + r.Data.String() }
+
+// Private len and copy parts to satisfy RR interface.
+func (r *PrivateRR) len() int { return r.Hdr.len() + r.Data.Len() }
+func (r *PrivateRR) copy() RR {
+       // make new RR like this:
+       rr := mkPrivateRR(r.Hdr.Rrtype)
+       newh := r.Hdr.copyHeader()
+       rr.Hdr = *newh
+
+       err := r.Data.Copy(rr.Data)
+       if err != nil {
+               panic("dns: got value that could not be used to copy Private rdata")
+       }
+       return rr
+}
+func (r *PrivateRR) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
+       off, err := r.Hdr.pack(msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       headerEnd := off
+       n, err := r.Data.Pack(msg[off:])
+       if err != nil {
+               return len(msg), err
+       }
+       off += n
+       r.Header().Rdlength = uint16(off - headerEnd)
+       return off, nil
+}
+
+// PrivateHandle registers a private resource record type. It requires
+// string and numeric representation of private RR type and generator function as argument.
+func PrivateHandle(rtypestr string, rtype uint16, generator func() PrivateRdata) {
+       rtypestr = strings.ToUpper(rtypestr)
+
+       TypeToRR[rtype] = func() RR { return &PrivateRR{RR_Header{}, generator()} }
+       TypeToString[rtype] = rtypestr
+       StringToType[rtypestr] = rtype
+
+       typeToUnpack[rtype] = func(h RR_Header, msg []byte, off int) (RR, int, error) {
+               if noRdata(h) {
+                       return &h, off, nil
+               }
+               var err error
+
+               rr := mkPrivateRR(h.Rrtype)
+               rr.Hdr = h
+
+               off1, err := rr.Data.Unpack(msg[off:])
+               off += off1
+               if err != nil {
+                       return rr, off, err
+               }
+               return rr, off, err
+       }
+
+       setPrivateRR := func(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
+               rr := mkPrivateRR(h.Rrtype)
+               rr.Hdr = h
+
+               var l lex
+               text := make([]string, 0, 2) // could be 0..N elements, median is probably 1
+       Fetch:
+               for {
+                       // TODO(miek): we could also be returning _QUOTE, this might or might not
+                       // be an issue (basically parsing TXT becomes hard)
+                       switch l = <-c; l.value {
+                       case zNewline, zEOF:
+                               break Fetch
+                       case zString:
+                               text = append(text, l.token)
+                       }
+               }
+
+               err := rr.Data.Parse(text)
+               if err != nil {
+                       return nil, &ParseError{f, err.Error(), l}, ""
+               }
+
+               return rr, nil, ""
+       }
+
+       typeToparserFunc[rtype] = parserFunc{setPrivateRR, true}
+}
+
+// PrivateHandleRemove removes defenitions required to support private RR type.
+func PrivateHandleRemove(rtype uint16) {
+       rtypestr, ok := TypeToString[rtype]
+       if ok {
+               delete(TypeToRR, rtype)
+               delete(TypeToString, rtype)
+               delete(typeToparserFunc, rtype)
+               delete(StringToType, rtypestr)
+               delete(typeToUnpack, rtype)
+       }
+       return
+}
diff --git a/vendor/github.com/miekg/dns/rawmsg.go b/vendor/github.com/miekg/dns/rawmsg.go
new file mode 100644 (file)
index 0000000..6e21fba
--- /dev/null
@@ -0,0 +1,49 @@
+package dns
+
+import "encoding/binary"
+
+// rawSetRdlength sets the rdlength in the header of
+// the RR. The offset 'off' must be positioned at the
+// start of the header of the RR, 'end' must be the
+// end of the RR.
+func rawSetRdlength(msg []byte, off, end int) bool {
+       l := len(msg)
+Loop:
+       for {
+               if off+1 > l {
+                       return false
+               }
+               c := int(msg[off])
+               off++
+               switch c & 0xC0 {
+               case 0x00:
+                       if c == 0x00 {
+                               // End of the domainname
+                               break Loop
+                       }
+                       if off+c > l {
+                               return false
+                       }
+                       off += c
+
+               case 0xC0:
+                       // pointer, next byte included, ends domainname
+                       off++
+                       break Loop
+               }
+       }
+       // 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.
+       off += 2 + 2 + 4
+       if off+2 > l {
+               return false
+       }
+       //off+1 is the end of the header, 'end' is the end of the rr
+       //so 'end' - 'off+2' is the length of the rdata
+       rdatalen := end - (off + 2)
+       if rdatalen > 0xFFFF {
+               return false
+       }
+       binary.BigEndian.PutUint16(msg[off:], uint16(rdatalen))
+       return true
+}
diff --git a/vendor/github.com/miekg/dns/reverse.go b/vendor/github.com/miekg/dns/reverse.go
new file mode 100644 (file)
index 0000000..099dac9
--- /dev/null
@@ -0,0 +1,38 @@
+package dns
+
+// StringToType is the reverse of TypeToString, needed for string parsing.
+var StringToType = reverseInt16(TypeToString)
+
+// StringToClass is the reverse of ClassToString, needed for string parsing.
+var StringToClass = reverseInt16(ClassToString)
+
+// Map of opcodes strings.
+var StringToOpcode = reverseInt(OpcodeToString)
+
+// Map of rcodes strings.
+var StringToRcode = reverseInt(RcodeToString)
+
+// Reverse a map
+func reverseInt8(m map[uint8]string) map[string]uint8 {
+       n := make(map[string]uint8, len(m))
+       for u, s := range m {
+               n[s] = u
+       }
+       return n
+}
+
+func reverseInt16(m map[uint16]string) map[string]uint16 {
+       n := make(map[string]uint16, len(m))
+       for u, s := range m {
+               n[s] = u
+       }
+       return n
+}
+
+func reverseInt(m map[int]string) map[string]int {
+       n := make(map[string]int, len(m))
+       for u, s := range m {
+               n[s] = u
+       }
+       return n
+}
diff --git a/vendor/github.com/miekg/dns/sanitize.go b/vendor/github.com/miekg/dns/sanitize.go
new file mode 100644 (file)
index 0000000..b489f3f
--- /dev/null
@@ -0,0 +1,84 @@
+package dns
+
+// Dedup removes identical RRs from rrs. It preserves the original ordering.
+// The lowest TTL of any duplicates is used in the remaining one. Dedup modifies
+// rrs.
+// m is used to store the RRs temporay. If it is nil a new map will be allocated.
+func Dedup(rrs []RR, m map[string]RR) []RR {
+       if m == nil {
+               m = make(map[string]RR)
+       }
+       // Save the keys, so we don't have to call normalizedString twice.
+       keys := make([]*string, 0, len(rrs))
+
+       for _, r := range rrs {
+               key := normalizedString(r)
+               keys = append(keys, &key)
+               if _, ok := m[key]; ok {
+                       // Shortest TTL wins.
+                       if m[key].Header().Ttl > r.Header().Ttl {
+                               m[key].Header().Ttl = r.Header().Ttl
+                       }
+                       continue
+               }
+
+               m[key] = r
+       }
+       // If the length of the result map equals the amount of RRs we got,
+       // it means they were all different. We can then just return the original rrset.
+       if len(m) == len(rrs) {
+               return rrs
+       }
+
+       j := 0
+       for i, r := range rrs {
+               // If keys[i] lives in the map, we should copy and remove it.
+               if _, ok := m[*keys[i]]; ok {
+                       delete(m, *keys[i])
+                       rrs[j] = r
+                       j++
+               }
+
+               if len(m) == 0 {
+                       break
+               }
+       }
+
+       return rrs[:j]
+}
+
+// normalizedString returns a normalized string from r. The TTL
+// is removed and the domain name is lowercased. We go from this:
+// DomainName<TAB>TTL<TAB>CLASS<TAB>TYPE<TAB>RDATA to:
+// lowercasename<TAB>CLASS<TAB>TYPE...
+func normalizedString(r RR) string {
+       // A string Go DNS makes has: domainname<TAB>TTL<TAB>...
+       b := []byte(r.String())
+
+       // find the first non-escaped tab, then another, so we capture where the TTL lives.
+       esc := false
+       ttlStart, ttlEnd := 0, 0
+       for i := 0; i < len(b) && ttlEnd == 0; i++ {
+               switch {
+               case b[i] == '\\':
+                       esc = !esc
+               case b[i] == '\t' && !esc:
+                       if ttlStart == 0 {
+                               ttlStart = i
+                               continue
+                       }
+                       if ttlEnd == 0 {
+                               ttlEnd = i
+                       }
+               case b[i] >= 'A' && b[i] <= 'Z' && !esc:
+                       b[i] += 32
+               default:
+                       esc = false
+               }
+       }
+
+       // remove TTL.
+       copy(b[ttlStart:], b[ttlEnd:])
+       cut := ttlEnd - ttlStart
+       return string(b[:len(b)-cut])
+}
diff --git a/vendor/github.com/miekg/dns/scan.go b/vendor/github.com/miekg/dns/scan.go
new file mode 100644 (file)
index 0000000..0e83797
--- /dev/null
@@ -0,0 +1,974 @@
+package dns
+
+import (
+       "io"
+       "log"
+       "os"
+       "strconv"
+       "strings"
+)
+
+type debugging bool
+
+const debug debugging = false
+
+func (d debugging) Printf(format string, args ...interface{}) {
+       if d {
+               log.Printf(format, args...)
+       }
+}
+
+const maxTok = 2048 // Largest token we can return.
+const maxUint16 = 1<<16 - 1
+
+// Tokinize a RFC 1035 zone file. The tokenizer will normalize it:
+// * Add ownernames if they are left blank;
+// * Suppress sequences of spaces;
+// * Make each RR fit on one line (_NEWLINE is send as last)
+// * Handle comments: ;
+// * Handle braces - anywhere.
+const (
+       // Zonefile
+       zEOF = iota
+       zString
+       zBlank
+       zQuote
+       zNewline
+       zRrtpe
+       zOwner
+       zClass
+       zDirOrigin   // $ORIGIN
+       zDirTtl      // $TTL
+       zDirInclude  // $INCLUDE
+       zDirGenerate // $GENERATE
+
+       // Privatekey file
+       zValue
+       zKey
+
+       zExpectOwnerDir      // Ownername
+       zExpectOwnerBl       // Whitespace after the ownername
+       zExpectAny           // Expect rrtype, ttl or class
+       zExpectAnyNoClass    // Expect rrtype or ttl
+       zExpectAnyNoClassBl  // The whitespace after _EXPECT_ANY_NOCLASS
+       zExpectAnyNoTtl      // Expect rrtype or class
+       zExpectAnyNoTtlBl    // Whitespace after _EXPECT_ANY_NOTTL
+       zExpectRrtype        // Expect rrtype
+       zExpectRrtypeBl      // Whitespace BEFORE rrtype
+       zExpectRdata         // The first element of the rdata
+       zExpectDirTtlBl      // Space after directive $TTL
+       zExpectDirTtl        // Directive $TTL
+       zExpectDirOriginBl   // Space after directive $ORIGIN
+       zExpectDirOrigin     // Directive $ORIGIN
+       zExpectDirIncludeBl  // Space after directive $INCLUDE
+       zExpectDirInclude    // Directive $INCLUDE
+       zExpectDirGenerate   // Directive $GENERATE
+       zExpectDirGenerateBl // Space after directive $GENERATE
+)
+
+// ParseError is a parsing error. It contains the parse error and the location in the io.Reader
+// where the error occurred.
+type ParseError struct {
+       file string
+       err  string
+       lex  lex
+}
+
+func (e *ParseError) Error() (s string) {
+       if e.file != "" {
+               s = e.file + ": "
+       }
+       s += "dns: " + e.err + ": " + strconv.QuoteToASCII(e.lex.token) + " at line: " +
+               strconv.Itoa(e.lex.line) + ":" + strconv.Itoa(e.lex.column)
+       return
+}
+
+type lex struct {
+       token      string // text of the token
+       tokenUpper string // uppercase text of the token
+       length     int    // length of the token
+       err        bool   // when true, token text has lexer error
+       value      uint8  // value: zString, _BLANK, etc.
+       line       int    // line in the file
+       column     int    // column in the file
+       torc       uint16 // type or class as parsed in the lexer, we only need to look this up in the grammar
+       comment    string // any comment text seen
+}
+
+// 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
+}
+
+// NewRR reads the RR contained in the string s. Only the first RR is
+// returned. If s contains no RR, 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. 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"), "")
+       }
+       return ReadRR(strings.NewReader(s), "")
+}
+
+// ReadRR reads the RR contained in q.
+// See NewRR for more documentation.
+func ReadRR(q io.Reader, filename string) (RR, error) {
+       r := <-parseZoneHelper(q, ".", filename, 1)
+       if r == nil {
+               return nil, nil
+       }
+
+       if r.Error != nil {
+               return nil, r.Error
+       }
+       return r.RR, nil
+}
+
+// ParseZone reads a RFC 1035 style zonefile from r. It returns *Tokens on the
+// returned channel, which consist out the parsed RR, a potential comment or an error.
+// If there is an error the RR is nil. The string file is only used
+// in error reporting. The string origin is used as the initial origin, as
+// if the file would start with: $ORIGIN origin .
+// The directives $INCLUDE, $ORIGIN, $TTL and $GENERATE are supported.
+// The channel t is closed by ParseZone when the end of r is reached.
+//
+// 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 discarded. Comments on a line by themselves are discarded too.
+func ParseZone(r io.Reader, origin, file string) chan *Token {
+       return parseZoneHelper(r, origin, file, 10000)
+}
+
+func parseZoneHelper(r io.Reader, origin, file string, chansize int) chan *Token {
+       t := make(chan *Token, chansize)
+       go parseZone(r, origin, file, t, 0)
+       return t
+}
+
+func parseZone(r io.Reader, origin, f string, t chan *Token, include int) {
+       defer func() {
+               if include == 0 {
+                       close(t)
+               }
+       }()
+       s := scanInit(r)
+       c := make(chan lex)
+       // Start the lexer
+       go zlexer(s, c)
+       // 6 possible beginnings of a line, _ is a space
+       // 0. zRRTYPE                              -> all omitted until the rrtype
+       // 1. zOwner _ zRrtype                     -> class/ttl omitted
+       // 2. zOwner _ zString _ zRrtype           -> class omitted
+       // 3. zOwner _ zString _ zClass  _ zRrtype -> ttl/class
+       // 4. zOwner _ zClass  _ zRrtype           -> ttl omitted
+       // 5. zOwner _ zClass  _ zString _ zRrtype -> class/ttl (reversed)
+       // After detecting these, we know the zRrtype so we can jump to functions
+       // handling the rdata for each of these types.
+
+       if origin == "" {
+               origin = "."
+       }
+       origin = Fqdn(origin)
+       if _, ok := IsDomainName(origin); !ok {
+               t <- &Token{Error: &ParseError{f, "bad initial origin name", lex{}}}
+               return
+       }
+
+       st := zExpectOwnerDir // initial state
+       var h RR_Header
+       var defttl uint32 = defaultTtl
+       var prevName string
+       for l := range c {
+               // Lexer spotted an error already
+               if l.err == true {
+                       t <- &Token{Error: &ParseError{f, l.token, l}}
+                       return
+
+               }
+               switch st {
+               case zExpectOwnerDir:
+                       // We can also expect a directive, like $TTL or $ORIGIN
+                       h.Ttl = defttl
+                       h.Class = ClassINET
+                       switch l.value {
+                       case zNewline:
+                               st = zExpectOwnerDir
+                       case zOwner:
+                               h.Name = l.token
+                               if l.token[0] == '@' {
+                                       h.Name = origin
+                                       prevName = h.Name
+                                       st = zExpectOwnerBl
+                                       break
+                               }
+                               if h.Name[l.length-1] != '.' {
+                                       h.Name = appendOrigin(h.Name, origin)
+                               }
+                               _, ok := IsDomainName(l.token)
+                               if !ok {
+                                       t <- &Token{Error: &ParseError{f, "bad owner name", l}}
+                                       return
+                               }
+                               prevName = h.Name
+                               st = zExpectOwnerBl
+                       case zDirTtl:
+                               st = zExpectDirTtlBl
+                       case zDirOrigin:
+                               st = zExpectDirOriginBl
+                       case zDirInclude:
+                               st = zExpectDirIncludeBl
+                       case zDirGenerate:
+                               st = zExpectDirGenerateBl
+                       case zRrtpe:
+                               h.Name = prevName
+                               h.Rrtype = l.torc
+                               st = zExpectRdata
+                       case zClass:
+                               h.Name = prevName
+                               h.Class = l.torc
+                               st = zExpectAnyNoClassBl
+                       case zBlank:
+                               // Discard, can happen when there is nothing on the
+                               // line except the RR type
+                       case zString:
+                               ttl, ok := stringToTtl(l.token)
+                               if !ok {
+                                       t <- &Token{Error: &ParseError{f, "not a TTL", l}}
+                                       return
+                               }
+                               h.Ttl = ttl
+                               // Don't about the defttl, we should take the $TTL value
+                               // defttl = ttl
+                               st = zExpectAnyNoTtlBl
+
+                       default:
+                               t <- &Token{Error: &ParseError{f, "syntax error at beginning", l}}
+                               return
+                       }
+               case zExpectDirIncludeBl:
+                       if l.value != zBlank {
+                               t <- &Token{Error: &ParseError{f, "no blank after $INCLUDE-directive", l}}
+                               return
+                       }
+                       st = zExpectDirInclude
+               case zExpectDirInclude:
+                       if l.value != zString {
+                               t <- &Token{Error: &ParseError{f, "expecting $INCLUDE value, not this...", l}}
+                               return
+                       }
+                       neworigin := origin // There may be optionally a new origin set after the filename, if not use current one
+                       l := <-c
+                       switch l.value {
+                       case zBlank:
+                               l := <-c
+                               if l.value == zString {
+                                       if _, ok := IsDomainName(l.token); !ok || l.length == 0 || l.err {
+                                               t <- &Token{Error: &ParseError{f, "bad origin name", l}}
+                                               return
+                                       }
+                                       // a new origin is specified.
+                                       if l.token[l.length-1] != '.' {
+                                               if origin != "." { // Prevent .. endings
+                                                       neworigin = l.token + "." + origin
+                                               } else {
+                                                       neworigin = l.token + origin
+                                               }
+                                       } else {
+                                               neworigin = l.token
+                                       }
+                               }
+                       case zNewline, zEOF:
+                               // Ok
+                       default:
+                               t <- &Token{Error: &ParseError{f, "garbage after $INCLUDE", l}}
+                               return
+                       }
+                       // Start with the new file
+                       r1, e1 := os.Open(l.token)
+                       if e1 != nil {
+                               t <- &Token{Error: &ParseError{f, "failed to open `" + l.token + "'", l}}
+                               return
+                       }
+                       if include+1 > 7 {
+                               t <- &Token{Error: &ParseError{f, "too deeply nested $INCLUDE", l}}
+                               return
+                       }
+                       parseZone(r1, l.token, neworigin, t, include+1)
+                       st = zExpectOwnerDir
+               case zExpectDirTtlBl:
+                       if l.value != zBlank {
+                               t <- &Token{Error: &ParseError{f, "no blank after $TTL-directive", l}}
+                               return
+                       }
+                       st = zExpectDirTtl
+               case zExpectDirTtl:
+                       if l.value != zString {
+                               t <- &Token{Error: &ParseError{f, "expecting $TTL value, not this...", l}}
+                               return
+                       }
+                       if e, _ := slurpRemainder(c, f); e != nil {
+                               t <- &Token{Error: e}
+                               return
+                       }
+                       ttl, ok := stringToTtl(l.token)
+                       if !ok {
+                               t <- &Token{Error: &ParseError{f, "expecting $TTL value, not this...", l}}
+                               return
+                       }
+                       defttl = ttl
+                       st = zExpectOwnerDir
+               case zExpectDirOriginBl:
+                       if l.value != zBlank {
+                               t <- &Token{Error: &ParseError{f, "no blank after $ORIGIN-directive", l}}
+                               return
+                       }
+                       st = zExpectDirOrigin
+               case zExpectDirOrigin:
+                       if l.value != zString {
+                               t <- &Token{Error: &ParseError{f, "expecting $ORIGIN value, not this...", l}}
+                               return
+                       }
+                       if e, _ := slurpRemainder(c, f); e != nil {
+                               t <- &Token{Error: e}
+                       }
+                       if _, ok := IsDomainName(l.token); !ok {
+                               t <- &Token{Error: &ParseError{f, "bad origin name", l}}
+                               return
+                       }
+                       if l.token[l.length-1] != '.' {
+                               if origin != "." { // Prevent .. endings
+                                       origin = l.token + "." + origin
+                               } else {
+                                       origin = l.token + origin
+                               }
+                       } else {
+                               origin = l.token
+                       }
+                       st = zExpectOwnerDir
+               case zExpectDirGenerateBl:
+                       if l.value != zBlank {
+                               t <- &Token{Error: &ParseError{f, "no blank after $GENERATE-directive", l}}
+                               return
+                       }
+                       st = zExpectDirGenerate
+               case zExpectDirGenerate:
+                       if l.value != zString {
+                               t <- &Token{Error: &ParseError{f, "expecting $GENERATE value, not this...", l}}
+                               return
+                       }
+                       if errMsg := generate(l, c, t, origin); errMsg != "" {
+                               t <- &Token{Error: &ParseError{f, errMsg, l}}
+                               return
+                       }
+                       st = zExpectOwnerDir
+               case zExpectOwnerBl:
+                       if l.value != zBlank {
+                               t <- &Token{Error: &ParseError{f, "no blank after owner", l}}
+                               return
+                       }
+                       st = zExpectAny
+               case zExpectAny:
+                       switch l.value {
+                       case zRrtpe:
+                               h.Rrtype = l.torc
+                               st = zExpectRdata
+                       case zClass:
+                               h.Class = l.torc
+                               st = zExpectAnyNoClassBl
+                       case zString:
+                               ttl, ok := stringToTtl(l.token)
+                               if !ok {
+                                       t <- &Token{Error: &ParseError{f, "not a TTL", l}}
+                                       return
+                               }
+                               h.Ttl = ttl
+                               // defttl = ttl // don't set the defttl here
+                               st = zExpectAnyNoTtlBl
+                       default:
+                               t <- &Token{Error: &ParseError{f, "expecting RR type, TTL or class, not this...", l}}
+                               return
+                       }
+               case zExpectAnyNoClassBl:
+                       if l.value != zBlank {
+                               t <- &Token{Error: &ParseError{f, "no blank before class", l}}
+                               return
+                       }
+                       st = zExpectAnyNoClass
+               case zExpectAnyNoTtlBl:
+                       if l.value != zBlank {
+                               t <- &Token{Error: &ParseError{f, "no blank before TTL", l}}
+                               return
+                       }
+                       st = zExpectAnyNoTtl
+               case zExpectAnyNoTtl:
+                       switch l.value {
+                       case zClass:
+                               h.Class = l.torc
+                               st = zExpectRrtypeBl
+                       case zRrtpe:
+                               h.Rrtype = l.torc
+                               st = zExpectRdata
+                       default:
+                               t <- &Token{Error: &ParseError{f, "expecting RR type or class, not this...", l}}
+                               return
+                       }
+               case zExpectAnyNoClass:
+                       switch l.value {
+                       case zString:
+                               ttl, ok := stringToTtl(l.token)
+                               if !ok {
+                                       t <- &Token{Error: &ParseError{f, "not a TTL", l}}
+                                       return
+                               }
+                               h.Ttl = ttl
+                               // defttl = ttl // don't set the def ttl anymore
+                               st = zExpectRrtypeBl
+                       case zRrtpe:
+                               h.Rrtype = l.torc
+                               st = zExpectRdata
+                       default:
+                               t <- &Token{Error: &ParseError{f, "expecting RR type or TTL, not this...", l}}
+                               return
+                       }
+               case zExpectRrtypeBl:
+                       if l.value != zBlank {
+                               t <- &Token{Error: &ParseError{f, "no blank before RR type", l}}
+                               return
+                       }
+                       st = zExpectRrtype
+               case zExpectRrtype:
+                       if l.value != zRrtpe {
+                               t <- &Token{Error: &ParseError{f, "unknown RR type", l}}
+                               return
+                       }
+                       h.Rrtype = l.torc
+                       st = zExpectRdata
+               case zExpectRdata:
+                       r, e, c1 := setRR(h, c, origin, f)
+                       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
+                               }
+                               t <- &Token{Error: e}
+                               return
+                       }
+                       t <- &Token{RR: r, Comment: c1}
+                       st = zExpectOwnerDir
+               }
+       }
+       // If we get here, we and the h.Rrtype is still zero, we haven't parsed anything, this
+       // is not an error, because an empty zone file is still a zone file.
+}
+
+// zlexer scans the sourcefile and returns tokens on the channel c.
+func zlexer(s *scan, c chan lex) {
+       var l lex
+       str := make([]byte, maxTok) // Should be enough for any token
+       stri := 0                   // Offset in str (0 means empty)
+       com := make([]byte, maxTok) // Hold comment text
+       comi := 0
+       quote := false
+       escape := false
+       space := false
+       commt := false
+       rrtype := false
+       owner := true
+       brace := 0
+       x, err := s.tokenText()
+       defer close(c)
+       for err == nil {
+               l.column = s.position.Column
+               l.line = s.position.Line
+               if stri >= maxTok {
+                       l.token = "token length insufficient for parsing"
+                       l.err = true
+                       debug.Printf("[%+v]", l.token)
+                       c <- l
+                       return
+               }
+               if comi >= maxTok {
+                       l.token = "comment length insufficient for parsing"
+                       l.err = true
+                       debug.Printf("[%+v]", l.token)
+                       c <- l
+                       return
+               }
+
+               switch x {
+               case ' ', '\t':
+                       if escape {
+                               escape = false
+                               str[stri] = x
+                               stri++
+                               break
+                       }
+                       if quote {
+                               // Inside quotes this is legal
+                               str[stri] = x
+                               stri++
+                               break
+                       }
+                       if commt {
+                               com[comi] = x
+                               comi++
+                               break
+                       }
+                       if stri == 0 {
+                               // Space directly in the beginning, handled in the grammar
+                       } else if owner {
+                               // If we have a string and its the first, make it an owner
+                               l.value = zOwner
+                               l.token = string(str[:stri])
+                               l.tokenUpper = strings.ToUpper(l.token)
+                               l.length = stri
+                               // escape $... start with a \ not a $, so this will work
+                               switch l.tokenUpper {
+                               case "$TTL":
+                                       l.value = zDirTtl
+                               case "$ORIGIN":
+                                       l.value = zDirOrigin
+                               case "$INCLUDE":
+                                       l.value = zDirInclude
+                               case "$GENERATE":
+                                       l.value = zDirGenerate
+                               }
+                               debug.Printf("[7 %+v]", l.token)
+                               c <- l
+                       } else {
+                               l.value = zString
+                               l.token = string(str[:stri])
+                               l.tokenUpper = strings.ToUpper(l.token)
+                               l.length = stri
+                               if !rrtype {
+                                       if t, ok := StringToType[l.tokenUpper]; ok {
+                                               l.value = zRrtpe
+                                               l.torc = t
+                                               rrtype = true
+                                       } else {
+                                               if strings.HasPrefix(l.tokenUpper, "TYPE") {
+                                                       t, ok := typeToInt(l.token)
+                                                       if !ok {
+                                                               l.token = "unknown RR type"
+                                                               l.err = true
+                                                               c <- l
+                                                               return
+                                                       }
+                                                       l.value = zRrtpe
+                                                       l.torc = t
+                                               }
+                                       }
+                                       if t, ok := StringToClass[l.tokenUpper]; ok {
+                                               l.value = zClass
+                                               l.torc = t
+                                       } else {
+                                               if strings.HasPrefix(l.tokenUpper, "CLASS") {
+                                                       t, ok := classToInt(l.token)
+                                                       if !ok {
+                                                               l.token = "unknown class"
+                                                               l.err = true
+                                                               c <- l
+                                                               return
+                                                       }
+                                                       l.value = zClass
+                                                       l.torc = t
+                                               }
+                                       }
+                               }
+                               debug.Printf("[6 %+v]", l.token)
+                               c <- l
+                       }
+                       stri = 0
+                       // I reverse space stuff here
+                       if !space && !commt {
+                               l.value = zBlank
+                               l.token = " "
+                               l.length = 1
+                               debug.Printf("[5 %+v]", l.token)
+                               c <- l
+                       }
+                       owner = false
+                       space = true
+               case ';':
+                       if escape {
+                               escape = false
+                               str[stri] = x
+                               stri++
+                               break
+                       }
+                       if quote {
+                               // Inside quotes this is legal
+                               str[stri] = x
+                               stri++
+                               break
+                       }
+                       if stri > 0 {
+                               l.value = zString
+                               l.token = string(str[:stri])
+                               l.length = stri
+                               debug.Printf("[4 %+v]", l.token)
+                               c <- l
+                               stri = 0
+                       }
+                       commt = true
+                       com[comi] = ';'
+                       comi++
+               case '\r':
+                       escape = false
+                       if quote {
+                               str[stri] = x
+                               stri++
+                               break
+                       }
+                       // discard if outside of quotes
+               case '\n':
+                       escape = false
+                       // Escaped newline
+                       if quote {
+                               str[stri] = x
+                               stri++
+                               break
+                       }
+                       // inside quotes this is legal
+                       if commt {
+                               // Reset a comment
+                               commt = false
+                               rrtype = false
+                               stri = 0
+                               // If not in a brace this ends the comment AND the RR
+                               if brace == 0 {
+                                       owner = true
+                                       owner = true
+                                       l.value = zNewline
+                                       l.token = "\n"
+                                       l.length = 1
+                                       l.comment = string(com[:comi])
+                                       debug.Printf("[3 %+v %+v]", l.token, l.comment)
+                                       c <- l
+                                       l.comment = ""
+                                       comi = 0
+                                       break
+                               }
+                               com[comi] = ' ' // convert newline to space
+                               comi++
+                               break
+                       }
+
+                       if brace == 0 {
+                               // If there is previous text, we should output it here
+                               if stri != 0 {
+                                       l.value = zString
+                                       l.token = string(str[:stri])
+                                       l.tokenUpper = strings.ToUpper(l.token)
+
+                                       l.length = stri
+                                       if !rrtype {
+                                               if t, ok := StringToType[l.tokenUpper]; ok {
+                                                       l.value = zRrtpe
+                                                       l.torc = t
+                                                       rrtype = true
+                                               }
+                                       }
+                                       debug.Printf("[2 %+v]", l.token)
+                                       c <- l
+                               }
+                               l.value = zNewline
+                               l.token = "\n"
+                               l.length = 1
+                               debug.Printf("[1 %+v]", l.token)
+                               c <- l
+                               stri = 0
+                               commt = false
+                               rrtype = false
+                               owner = true
+                               comi = 0
+                       }
+               case '\\':
+                       // comments do not get escaped chars, everything is copied
+                       if commt {
+                               com[comi] = x
+                               comi++
+                               break
+                       }
+                       // something already escaped must be in string
+                       if escape {
+                               str[stri] = x
+                               stri++
+                               escape = false
+                               break
+                       }
+                       // something escaped outside of string gets added to string
+                       str[stri] = x
+                       stri++
+                       escape = true
+               case '"':
+                       if commt {
+                               com[comi] = x
+                               comi++
+                               break
+                       }
+                       if escape {
+                               str[stri] = x
+                               stri++
+                               escape = false
+                               break
+                       }
+                       space = false
+                       // send previous gathered text and the quote
+                       if stri != 0 {
+                               l.value = zString
+                               l.token = string(str[:stri])
+                               l.length = stri
+
+                               debug.Printf("[%+v]", l.token)
+                               c <- l
+                               stri = 0
+                       }
+
+                       // send quote itself as separate token
+                       l.value = zQuote
+                       l.token = "\""
+                       l.length = 1
+                       c <- l
+                       quote = !quote
+               case '(', ')':
+                       if commt {
+                               com[comi] = x
+                               comi++
+                               break
+                       }
+                       if escape {
+                               str[stri] = x
+                               stri++
+                               escape = false
+                               break
+                       }
+                       if quote {
+                               str[stri] = x
+                               stri++
+                               break
+                       }
+                       switch x {
+                       case ')':
+                               brace--
+                               if brace < 0 {
+                                       l.token = "extra closing brace"
+                                       l.err = true
+                                       debug.Printf("[%+v]", l.token)
+                                       c <- l
+                                       return
+                               }
+                       case '(':
+                               brace++
+                       }
+               default:
+                       escape = false
+                       if commt {
+                               com[comi] = x
+                               comi++
+                               break
+                       }
+                       str[stri] = x
+                       stri++
+                       space = false
+               }
+               x, err = s.tokenText()
+       }
+       if stri > 0 {
+               // Send remainder
+               l.token = string(str[:stri])
+               l.length = stri
+               l.value = zString
+               debug.Printf("[%+v]", l.token)
+               c <- l
+       }
+}
+
+// Extract the class number from CLASSxx
+func classToInt(token string) (uint16, bool) {
+       offset := 5
+       if len(token) < offset+1 {
+               return 0, false
+       }
+       class, ok := strconv.Atoi(token[offset:])
+       if ok != nil || class > maxUint16 {
+               return 0, false
+       }
+       return uint16(class), true
+}
+
+// Extract the rr number from TYPExxx
+func typeToInt(token string) (uint16, bool) {
+       offset := 4
+       if len(token) < offset+1 {
+               return 0, false
+       }
+       typ, ok := strconv.Atoi(token[offset:])
+       if ok != nil || typ > maxUint16 {
+               return 0, false
+       }
+       return uint16(typ), true
+}
+
+// Parse things like 2w, 2m, etc, Return the time in seconds.
+func stringToTtl(token string) (uint32, bool) {
+       s := uint32(0)
+       i := uint32(0)
+       for _, c := range token {
+               switch c {
+               case 's', 'S':
+                       s += i
+                       i = 0
+               case 'm', 'M':
+                       s += i * 60
+                       i = 0
+               case 'h', 'H':
+                       s += i * 60 * 60
+                       i = 0
+               case 'd', 'D':
+                       s += i * 60 * 60 * 24
+                       i = 0
+               case 'w', 'W':
+                       s += i * 60 * 60 * 24 * 7
+                       i = 0
+               case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
+                       i *= 10
+                       i += uint32(c) - '0'
+               default:
+                       return 0, false
+               }
+       }
+       return s + i, true
+}
+
+// Parse LOC records' <digits>[.<digits>][mM] into a
+// mantissa exponent format. Token should contain the entire
+// string (i.e. no spaces allowed)
+func stringToCm(token string) (e, m uint8, ok bool) {
+       if token[len(token)-1] == 'M' || token[len(token)-1] == 'm' {
+               token = token[0 : len(token)-1]
+       }
+       s := strings.SplitN(token, ".", 2)
+       var meters, cmeters, val int
+       var err error
+       switch len(s) {
+       case 2:
+               if cmeters, err = strconv.Atoi(s[1]); err != nil {
+                       return
+               }
+               fallthrough
+       case 1:
+               if meters, err = strconv.Atoi(s[0]); err != nil {
+                       return
+               }
+       case 0:
+               // huh?
+               return 0, 0, false
+       }
+       ok = true
+       if meters > 0 {
+               e = 2
+               val = meters
+       } else {
+               e = 0
+               val = cmeters
+       }
+       for val > 10 {
+               e++
+               val /= 10
+       }
+       if e > 9 {
+               ok = false
+       }
+       m = uint8(val)
+       return
+}
+
+func appendOrigin(name, origin string) string {
+       if origin == "." {
+               return name + origin
+       }
+       return name + "." + origin
+}
+
+// LOC record helper function
+func locCheckNorth(token string, latitude uint32) (uint32, bool) {
+       switch token {
+       case "n", "N":
+               return LOC_EQUATOR + latitude, true
+       case "s", "S":
+               return LOC_EQUATOR - latitude, true
+       }
+       return latitude, false
+}
+
+// LOC record helper function
+func locCheckEast(token string, longitude uint32) (uint32, bool) {
+       switch token {
+       case "e", "E":
+               return LOC_EQUATOR + longitude, true
+       case "w", "W":
+               return LOC_EQUATOR - longitude, true
+       }
+       return longitude, false
+}
+
+// "Eat" the rest of the "line". Return potential comments
+func slurpRemainder(c chan lex, f string) (*ParseError, string) {
+       l := <-c
+       com := ""
+       switch l.value {
+       case zBlank:
+               l = <-c
+               com = l.comment
+               if l.value != zNewline && l.value != zEOF {
+                       return &ParseError{f, "garbage after rdata", l}, ""
+               }
+       case zNewline:
+               com = l.comment
+       case zEOF:
+       default:
+               return &ParseError{f, "garbage after rdata", l}, ""
+       }
+       return nil, com
+}
+
+// Parse a 64 bit-like ipv6 address: "0014:4fff:ff20:ee64"
+// Used for NID and L64 record.
+func stringToNodeID(l lex) (uint64, *ParseError) {
+       if len(l.token) < 19 {
+               return 0, &ParseError{l.token, "bad NID/L64 NodeID/Locator64", l}
+       }
+       // There must be three colons at fixes postitions, if not its a parse error
+       if l.token[4] != ':' && l.token[9] != ':' && l.token[14] != ':' {
+               return 0, &ParseError{l.token, "bad NID/L64 NodeID/Locator64", l}
+       }
+       s := l.token[0:4] + l.token[5:9] + l.token[10:14] + l.token[15:19]
+       u, err := strconv.ParseUint(s, 16, 64)
+       if err != nil {
+               return 0, &ParseError{l.token, "bad NID/L64 NodeID/Locator64", l}
+       }
+       return u, nil
+}
diff --git a/vendor/github.com/miekg/dns/scan_rr.go b/vendor/github.com/miekg/dns/scan_rr.go
new file mode 100644 (file)
index 0000000..e521dc0
--- /dev/null
@@ -0,0 +1,2143 @@
+package dns
+
+import (
+       "encoding/base64"
+       "net"
+       "strconv"
+       "strings"
+)
+
+type parserFunc struct {
+       // Func defines the function that parses the tokens and returns the RR
+       // or an error. The last string contains any comments in the line as
+       // they returned by the lexer as well.
+       Func func(h RR_Header, c chan lex, origin string, file string) (RR, *ParseError, string)
+       // Signals if the RR ending is of variable length, like TXT or records
+       // that have Hexadecimal or Base64 as their last element in the Rdata. Records
+       // that have a fixed ending or for instance A, AAAA, SOA and etc.
+       Variable bool
+}
+
+// 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 chan lex, o, f string) (RR, *ParseError, string) {
+       parserfunc, ok := typeToparserFunc[h.Rrtype]
+       if ok {
+               r, e, cm := parserfunc.Func(h, c, o, f)
+               if parserfunc.Variable {
+                       return r, e, cm
+               }
+               if e != nil {
+                       return nil, e, ""
+               }
+               e, cm = slurpRemainder(c, f)
+               if e != nil {
+                       return nil, e, ""
+               }
+               return r, nil, cm
+       }
+       // RFC3957 RR (Unknown RR handling)
+       return setRFC3597(h, c, o, f)
+}
+
+// A remainder of the rdata with embedded spaces, return the parsed string (sans the spaces)
+// or an error
+func endingToString(c chan lex, errstr, f string) (string, *ParseError, string) {
+       s := ""
+       l := <-c // zString
+       for l.value != zNewline && l.value != zEOF {
+               if l.err {
+                       return s, &ParseError{f, errstr, l}, ""
+               }
+               switch l.value {
+               case zString:
+                       s += l.token
+               case zBlank: // Ok
+               default:
+                       return "", &ParseError{f, errstr, l}, ""
+               }
+               l = <-c
+       }
+       return s, nil, l.comment
+}
+
+// A remainder of the rdata with embedded spaces, return the parsed string slice (sans the spaces)
+// or an error
+func endingToTxtSlice(c chan lex, errstr, f string) ([]string, *ParseError, string) {
+       // Get the remaining data until we see a zNewline
+       quote := false
+       l := <-c
+       var s []string
+       if l.err {
+               return s, &ParseError{f, errstr, l}, ""
+       }
+       switch l.value == zQuote {
+       case true: // A number of quoted string
+               s = make([]string, 0)
+               empty := true
+               for l.value != zNewline && l.value != zEOF {
+                       if l.err {
+                               return nil, &ParseError{f, errstr, l}, ""
+                       }
+                       switch l.value {
+                       case zString:
+                               empty = false
+                               if len(l.token) > 255 {
+                                       // split up tokens that are larger than 255 into 255-chunks
+                                       sx := []string{}
+                                       p, i := 0, 255
+                                       for {
+                                               if i <= len(l.token) {
+                                                       sx = append(sx, l.token[p:i])
+                                               } else {
+                                                       sx = append(sx, l.token[p:])
+                                                       break
+
+                                               }
+                                               p, i = p+255, i+255
+                                       }
+                                       s = append(s, sx...)
+                                       break
+                               }
+
+                               s = append(s, l.token)
+                       case zBlank:
+                               if quote {
+                                       // zBlank can only be seen in between txt parts.
+                                       return nil, &ParseError{f, errstr, l}, ""
+                               }
+                       case zQuote:
+                               if empty && quote {
+                                       s = append(s, "")
+                               }
+                               quote = !quote
+                               empty = true
+                       default:
+                               return nil, &ParseError{f, errstr, l}, ""
+                       }
+                       l = <-c
+               }
+               if quote {
+                       return nil, &ParseError{f, errstr, l}, ""
+               }
+       case false: // Unquoted text record
+               s = make([]string, 1)
+               for l.value != zNewline && l.value != zEOF {
+                       if l.err {
+                               return s, &ParseError{f, errstr, l}, ""
+                       }
+                       s[0] += l.token
+                       l = <-c
+               }
+       }
+       return s, nil, l.comment
+}
+
+func setA(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
+       rr := new(A)
+       rr.Hdr = h
+
+       l := <-c
+       if l.length == 0 { // Dynamic updates.
+               return rr, nil, ""
+       }
+       rr.A = net.ParseIP(l.token)
+       if rr.A == nil || l.err {
+               return nil, &ParseError{f, "bad A A", l}, ""
+       }
+       return rr, nil, ""
+}
+
+func setAAAA(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
+       rr := new(AAAA)
+       rr.Hdr = h
+
+       l := <-c
+       if l.length == 0 {
+               return rr, nil, ""
+       }
+       rr.AAAA = net.ParseIP(l.token)
+       if rr.AAAA == nil || l.err {
+               return nil, &ParseError{f, "bad AAAA AAAA", l}, ""
+       }
+       return rr, nil, ""
+}
+
+func setNS(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
+       rr := new(NS)
+       rr.Hdr = h
+
+       l := <-c
+       rr.Ns = l.token
+       if l.length == 0 {
+               return rr, nil, ""
+       }
+       if l.token == "@" {
+               rr.Ns = o
+               return rr, nil, ""
+       }
+       _, ok := IsDomainName(l.token)
+       if !ok || l.length == 0 || l.err {
+               return nil, &ParseError{f, "bad NS Ns", l}, ""
+       }
+       if rr.Ns[l.length-1] != '.' {
+               rr.Ns = appendOrigin(rr.Ns, o)
+       }
+       return rr, nil, ""
+}
+
+func setPTR(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
+       rr := new(PTR)
+       rr.Hdr = h
+
+       l := <-c
+       rr.Ptr = l.token
+       if l.length == 0 { // dynamic update rr.
+               return rr, nil, ""
+       }
+       if l.token == "@" {
+               rr.Ptr = o
+               return rr, nil, ""
+       }
+       _, ok := IsDomainName(l.token)
+       if !ok || l.length == 0 || l.err {
+               return nil, &ParseError{f, "bad PTR Ptr", l}, ""
+       }
+       if rr.Ptr[l.length-1] != '.' {
+               rr.Ptr = appendOrigin(rr.Ptr, o)
+       }
+       return rr, nil, ""
+}
+
+func setNSAPPTR(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
+       rr := new(NSAPPTR)
+       rr.Hdr = h
+
+       l := <-c
+       rr.Ptr = l.token
+       if l.length == 0 {
+               return rr, nil, ""
+       }
+       if l.token == "@" {
+               rr.Ptr = o
+               return rr, nil, ""
+       }
+       _, ok := IsDomainName(l.token)
+       if !ok || l.length == 0 || l.err {
+               return nil, &ParseError{f, "bad NSAP-PTR Ptr", l}, ""
+       }
+       if rr.Ptr[l.length-1] != '.' {
+               rr.Ptr = appendOrigin(rr.Ptr, o)
+       }
+       return rr, nil, ""
+}
+
+func setRP(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
+       rr := new(RP)
+       rr.Hdr = h
+
+       l := <-c
+       rr.Mbox = l.token
+       if l.length == 0 {
+               return rr, nil, ""
+       }
+       if l.token == "@" {
+               rr.Mbox = o
+       } else {
+               _, ok := IsDomainName(l.token)
+               if !ok || l.length == 0 || l.err {
+                       return nil, &ParseError{f, "bad RP Mbox", l}, ""
+               }
+               if rr.Mbox[l.length-1] != '.' {
+                       rr.Mbox = appendOrigin(rr.Mbox, o)
+               }
+       }
+       <-c // zBlank
+       l = <-c
+       rr.Txt = l.token
+       if l.token == "@" {
+               rr.Txt = o
+               return rr, nil, ""
+       }
+       _, ok := IsDomainName(l.token)
+       if !ok || l.length == 0 || l.err {
+               return nil, &ParseError{f, "bad RP Txt", l}, ""
+       }
+       if rr.Txt[l.length-1] != '.' {
+               rr.Txt = appendOrigin(rr.Txt, o)
+       }
+       return rr, nil, ""
+}
+
+func setMR(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
+       rr := new(MR)
+       rr.Hdr = h
+
+       l := <-c
+       rr.Mr = l.token
+       if l.length == 0 {
+               return rr, nil, ""
+       }
+       if l.token == "@" {
+               rr.Mr = o
+               return rr, nil, ""
+       }
+       _, ok := IsDomainName(l.token)
+       if !ok || l.length == 0 || l.err {
+               return nil, &ParseError{f, "bad MR Mr", l}, ""
+       }
+       if rr.Mr[l.length-1] != '.' {
+               rr.Mr = appendOrigin(rr.Mr, o)
+       }
+       return rr, nil, ""
+}
+
+func setMB(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
+       rr := new(MB)
+       rr.Hdr = h
+
+       l := <-c
+       rr.Mb = l.token
+       if l.length == 0 {
+               return rr, nil, ""
+       }
+       if l.token == "@" {
+               rr.Mb = o
+               return rr, nil, ""
+       }
+       _, ok := IsDomainName(l.token)
+       if !ok || l.length == 0 || l.err {
+               return nil, &ParseError{f, "bad MB Mb", l}, ""
+       }
+       if rr.Mb[l.length-1] != '.' {
+               rr.Mb = appendOrigin(rr.Mb, o)
+       }
+       return rr, nil, ""
+}
+
+func setMG(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
+       rr := new(MG)
+       rr.Hdr = h
+
+       l := <-c
+       rr.Mg = l.token
+       if l.length == 0 {
+               return rr, nil, ""
+       }
+       if l.token == "@" {
+               rr.Mg = o
+               return rr, nil, ""
+       }
+       _, ok := IsDomainName(l.token)
+       if !ok || l.length == 0 || l.err {
+               return nil, &ParseError{f, "bad MG Mg", l}, ""
+       }
+       if rr.Mg[l.length-1] != '.' {
+               rr.Mg = appendOrigin(rr.Mg, o)
+       }
+       return rr, nil, ""
+}
+
+func setHINFO(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
+       rr := new(HINFO)
+       rr.Hdr = h
+
+       chunks, e, c1 := endingToTxtSlice(c, "bad HINFO Fields", f)
+       if e != nil {
+               return nil, e, c1
+       }
+
+       if ln := len(chunks); ln == 0 {
+               return rr, nil, ""
+       } else if ln == 1 {
+               // Can we split it?
+               if out := strings.Fields(chunks[0]); len(out) > 1 {
+                       chunks = out
+               } else {
+                       chunks = append(chunks, "")
+               }
+       }
+
+       rr.Cpu = chunks[0]
+       rr.Os = strings.Join(chunks[1:], " ")
+
+       return rr, nil, ""
+}
+
+func setMINFO(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
+       rr := new(MINFO)
+       rr.Hdr = h
+
+       l := <-c
+       rr.Rmail = l.token
+       if l.length == 0 {
+               return rr, nil, ""
+       }
+       if l.token == "@" {
+               rr.Rmail = o
+       } else {
+               _, ok := IsDomainName(l.token)
+               if !ok || l.length == 0 || l.err {
+                       return nil, &ParseError{f, "bad MINFO Rmail", l}, ""
+               }
+               if rr.Rmail[l.length-1] != '.' {
+                       rr.Rmail = appendOrigin(rr.Rmail, o)
+               }
+       }
+       <-c // zBlank
+       l = <-c
+       rr.Email = l.token
+       if l.token == "@" {
+               rr.Email = o
+               return rr, nil, ""
+       }
+       _, ok := IsDomainName(l.token)
+       if !ok || l.length == 0 || l.err {
+               return nil, &ParseError{f, "bad MINFO Email", l}, ""
+       }
+       if rr.Email[l.length-1] != '.' {
+               rr.Email = appendOrigin(rr.Email, o)
+       }
+       return rr, nil, ""
+}
+
+func setMF(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
+       rr := new(MF)
+       rr.Hdr = h
+
+       l := <-c
+       rr.Mf = l.token
+       if l.length == 0 {
+               return rr, nil, ""
+       }
+       if l.token == "@" {
+               rr.Mf = o
+               return rr, nil, ""
+       }
+       _, ok := IsDomainName(l.token)
+       if !ok || l.length == 0 || l.err {
+               return nil, &ParseError{f, "bad MF Mf", l}, ""
+       }
+       if rr.Mf[l.length-1] != '.' {
+               rr.Mf = appendOrigin(rr.Mf, o)
+       }
+       return rr, nil, ""
+}
+
+func setMD(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
+       rr := new(MD)
+       rr.Hdr = h
+
+       l := <-c
+       rr.Md = l.token
+       if l.length == 0 {
+               return rr, nil, ""
+       }
+       if l.token == "@" {
+               rr.Md = o
+               return rr, nil, ""
+       }
+       _, ok := IsDomainName(l.token)
+       if !ok || l.length == 0 || l.err {
+               return nil, &ParseError{f, "bad MD Md", l}, ""
+       }
+       if rr.Md[l.length-1] != '.' {
+               rr.Md = appendOrigin(rr.Md, o)
+       }
+       return rr, nil, ""
+}
+
+func setMX(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
+       rr := new(MX)
+       rr.Hdr = h
+
+       l := <-c
+       if l.length == 0 {
+               return rr, nil, ""
+       }
+       i, e := strconv.Atoi(l.token)
+       if e != nil || l.err {
+               return nil, &ParseError{f, "bad MX Pref", l}, ""
+       }
+       rr.Preference = uint16(i)
+       <-c     // zBlank
+       l = <-c // zString
+       rr.Mx = l.token
+       if l.token == "@" {
+               rr.Mx = o
+               return rr, nil, ""
+       }
+       _, ok := IsDomainName(l.token)
+       if !ok || l.length == 0 || l.err {
+               return nil, &ParseError{f, "bad MX Mx", l}, ""
+       }
+       if rr.Mx[l.length-1] != '.' {
+               rr.Mx = appendOrigin(rr.Mx, o)
+       }
+       return rr, nil, ""
+}
+
+func setRT(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
+       rr := new(RT)
+       rr.Hdr = h
+       l := <-c
+       if l.length == 0 {
+               return rr, nil, ""
+       }
+       i, e := strconv.Atoi(l.token)
+       if e != nil {
+               return nil, &ParseError{f, "bad RT Preference", l}, ""
+       }
+       rr.Preference = uint16(i)
+       <-c     // zBlank
+       l = <-c // zString
+       rr.Host = l.token
+       if l.token == "@" {
+               rr.Host = o
+               return rr, nil, ""
+       }
+       _, ok := IsDomainName(l.token)
+       if !ok || l.length == 0 || l.err {
+               return nil, &ParseError{f, "bad RT Host", l}, ""
+       }
+       if rr.Host[l.length-1] != '.' {
+               rr.Host = appendOrigin(rr.Host, o)
+       }
+       return rr, nil, ""
+}
+
+func setAFSDB(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
+       rr := new(AFSDB)
+       rr.Hdr = h
+
+       l := <-c
+       if l.length == 0 {
+               return rr, nil, ""
+       }
+       i, e := strconv.Atoi(l.token)
+       if e != nil || l.err {
+               return nil, &ParseError{f, "bad AFSDB Subtype", l}, ""
+       }
+       rr.Subtype = uint16(i)
+       <-c     // zBlank
+       l = <-c // zString
+       rr.Hostname = l.token
+       if l.token == "@" {
+               rr.Hostname = o
+               return rr, nil, ""
+       }
+       _, ok := IsDomainName(l.token)
+       if !ok || l.length == 0 || l.err {
+               return nil, &ParseError{f, "bad AFSDB Hostname", l}, ""
+       }
+       if rr.Hostname[l.length-1] != '.' {
+               rr.Hostname = appendOrigin(rr.Hostname, o)
+       }
+       return rr, nil, ""
+}
+
+func setX25(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
+       rr := new(X25)
+       rr.Hdr = h
+
+       l := <-c
+       if l.length == 0 {
+               return rr, nil, ""
+       }
+       if l.err {
+               return nil, &ParseError{f, "bad X25 PSDNAddress", l}, ""
+       }
+       rr.PSDNAddress = l.token
+       return rr, nil, ""
+}
+
+func setKX(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
+       rr := new(KX)
+       rr.Hdr = h
+
+       l := <-c
+       if l.length == 0 {
+               return rr, nil, ""
+       }
+       i, e := strconv.Atoi(l.token)
+       if e != nil || l.err {
+               return nil, &ParseError{f, "bad KX Pref", l}, ""
+       }
+       rr.Preference = uint16(i)
+       <-c     // zBlank
+       l = <-c // zString
+       rr.Exchanger = l.token
+       if l.token == "@" {
+               rr.Exchanger = o
+               return rr, nil, ""
+       }
+       _, ok := IsDomainName(l.token)
+       if !ok || l.length == 0 || l.err {
+               return nil, &ParseError{f, "bad KX Exchanger", l}, ""
+       }
+       if rr.Exchanger[l.length-1] != '.' {
+               rr.Exchanger = appendOrigin(rr.Exchanger, o)
+       }
+       return rr, nil, ""
+}
+
+func setCNAME(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
+       rr := new(CNAME)
+       rr.Hdr = h
+
+       l := <-c
+       rr.Target = l.token
+       if l.length == 0 {
+               return rr, nil, ""
+       }
+       if l.token == "@" {
+               rr.Target = o
+               return rr, nil, ""
+       }
+       _, ok := IsDomainName(l.token)
+       if !ok || l.length == 0 || l.err {
+               return nil, &ParseError{f, "bad CNAME Target", l}, ""
+       }
+       if rr.Target[l.length-1] != '.' {
+               rr.Target = appendOrigin(rr.Target, o)
+       }
+       return rr, nil, ""
+}
+
+func setDNAME(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
+       rr := new(DNAME)
+       rr.Hdr = h
+
+       l := <-c
+       rr.Target = l.token
+       if l.length == 0 {
+               return rr, nil, ""
+       }
+       if l.token == "@" {
+               rr.Target = o
+               return rr, nil, ""
+       }
+       _, ok := IsDomainName(l.token)
+       if !ok || l.length == 0 || l.err {
+               return nil, &ParseError{f, "bad CNAME Target", l}, ""
+       }
+       if rr.Target[l.length-1] != '.' {
+               rr.Target = appendOrigin(rr.Target, o)
+       }
+       return rr, nil, ""
+}
+
+func setSOA(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
+       rr := new(SOA)
+       rr.Hdr = h
+
+       l := <-c
+       rr.Ns = l.token
+       if l.length == 0 {
+               return rr, nil, ""
+       }
+       <-c // zBlank
+       if l.token == "@" {
+               rr.Ns = o
+       } else {
+               _, ok := IsDomainName(l.token)
+               if !ok || l.length == 0 || l.err {
+                       return nil, &ParseError{f, "bad SOA Ns", l}, ""
+               }
+               if rr.Ns[l.length-1] != '.' {
+                       rr.Ns = appendOrigin(rr.Ns, o)
+               }
+       }
+
+       l = <-c
+       rr.Mbox = l.token
+       if l.token == "@" {
+               rr.Mbox = o
+       } else {
+               _, ok := IsDomainName(l.token)
+               if !ok || l.length == 0 || l.err {
+                       return nil, &ParseError{f, "bad SOA Mbox", l}, ""
+               }
+               if rr.Mbox[l.length-1] != '.' {
+                       rr.Mbox = appendOrigin(rr.Mbox, o)
+               }
+       }
+       <-c // zBlank
+
+       var (
+               v  uint32
+               ok bool
+       )
+       for i := 0; i < 5; i++ {
+               l = <-c
+               if l.err {
+                       return nil, &ParseError{f, "bad SOA zone parameter", l}, ""
+               }
+               if j, e := strconv.Atoi(l.token); e != nil {
+                       if i == 0 {
+                               // Serial should be a number
+                               return nil, &ParseError{f, "bad SOA zone parameter", l}, ""
+                       }
+                       if v, ok = stringToTtl(l.token); !ok {
+                               return nil, &ParseError{f, "bad SOA zone parameter", l}, ""
+
+                       }
+               } else {
+                       v = uint32(j)
+               }
+               switch i {
+               case 0:
+                       rr.Serial = v
+                       <-c // zBlank
+               case 1:
+                       rr.Refresh = v
+                       <-c // zBlank
+               case 2:
+                       rr.Retry = v
+                       <-c // zBlank
+               case 3:
+                       rr.Expire = v
+                       <-c // zBlank
+               case 4:
+                       rr.Minttl = v
+               }
+       }
+       return rr, nil, ""
+}
+
+func setSRV(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
+       rr := new(SRV)
+       rr.Hdr = h
+
+       l := <-c
+       if l.length == 0 {
+               return rr, nil, ""
+       }
+       i, e := strconv.Atoi(l.token)
+       if e != nil || l.err {
+               return nil, &ParseError{f, "bad SRV Priority", l}, ""
+       }
+       rr.Priority = uint16(i)
+       <-c     // zBlank
+       l = <-c // zString
+       i, e = strconv.Atoi(l.token)
+       if e != nil || l.err {
+               return nil, &ParseError{f, "bad SRV Weight", l}, ""
+       }
+       rr.Weight = uint16(i)
+       <-c     // zBlank
+       l = <-c // zString
+       i, e = strconv.Atoi(l.token)
+       if e != nil || l.err {
+               return nil, &ParseError{f, "bad SRV Port", l}, ""
+       }
+       rr.Port = uint16(i)
+       <-c     // zBlank
+       l = <-c // zString
+       rr.Target = l.token
+       if l.token == "@" {
+               rr.Target = o
+               return rr, nil, ""
+       }
+       _, ok := IsDomainName(l.token)
+       if !ok || l.length == 0 || l.err {
+               return nil, &ParseError{f, "bad SRV Target", l}, ""
+       }
+       if rr.Target[l.length-1] != '.' {
+               rr.Target = appendOrigin(rr.Target, o)
+       }
+       return rr, nil, ""
+}
+
+func setNAPTR(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
+       rr := new(NAPTR)
+       rr.Hdr = h
+
+       l := <-c
+       if l.length == 0 {
+               return rr, nil, ""
+       }
+       i, e := strconv.Atoi(l.token)
+       if e != nil || l.err {
+               return nil, &ParseError{f, "bad NAPTR Order", l}, ""
+       }
+       rr.Order = uint16(i)
+       <-c     // zBlank
+       l = <-c // zString
+       i, e = strconv.Atoi(l.token)
+       if e != nil || l.err {
+               return nil, &ParseError{f, "bad NAPTR Preference", l}, ""
+       }
+       rr.Preference = uint16(i)
+       // Flags
+       <-c     // zBlank
+       l = <-c // _QUOTE
+       if l.value != zQuote {
+               return nil, &ParseError{f, "bad NAPTR Flags", l}, ""
+       }
+       l = <-c // Either String or Quote
+       if l.value == zString {
+               rr.Flags = l.token
+               l = <-c // _QUOTE
+               if l.value != zQuote {
+                       return nil, &ParseError{f, "bad NAPTR Flags", l}, ""
+               }
+       } else if l.value == zQuote {
+               rr.Flags = ""
+       } else {
+               return nil, &ParseError{f, "bad NAPTR Flags", l}, ""
+       }
+
+       // Service
+       <-c     // zBlank
+       l = <-c // _QUOTE
+       if l.value != zQuote {
+               return nil, &ParseError{f, "bad NAPTR Service", l}, ""
+       }
+       l = <-c // Either String or Quote
+       if l.value == zString {
+               rr.Service = l.token
+               l = <-c // _QUOTE
+               if l.value != zQuote {
+                       return nil, &ParseError{f, "bad NAPTR Service", l}, ""
+               }
+       } else if l.value == zQuote {
+               rr.Service = ""
+       } else {
+               return nil, &ParseError{f, "bad NAPTR Service", l}, ""
+       }
+
+       // Regexp
+       <-c     // zBlank
+       l = <-c // _QUOTE
+       if l.value != zQuote {
+               return nil, &ParseError{f, "bad NAPTR Regexp", l}, ""
+       }
+       l = <-c // Either String or Quote
+       if l.value == zString {
+               rr.Regexp = l.token
+               l = <-c // _QUOTE
+               if l.value != zQuote {
+                       return nil, &ParseError{f, "bad NAPTR Regexp", l}, ""
+               }
+       } else if l.value == zQuote {
+               rr.Regexp = ""
+       } else {
+               return nil, &ParseError{f, "bad NAPTR Regexp", l}, ""
+       }
+       // After quote no space??
+       <-c     // zBlank
+       l = <-c // zString
+       rr.Replacement = l.token
+       if l.token == "@" {
+               rr.Replacement = o
+               return rr, nil, ""
+       }
+       _, ok := IsDomainName(l.token)
+       if !ok || l.length == 0 || l.err {
+               return nil, &ParseError{f, "bad NAPTR Replacement", l}, ""
+       }
+       if rr.Replacement[l.length-1] != '.' {
+               rr.Replacement = appendOrigin(rr.Replacement, o)
+       }
+       return rr, nil, ""
+}
+
+func setTALINK(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
+       rr := new(TALINK)
+       rr.Hdr = h
+
+       l := <-c
+       rr.PreviousName = l.token
+       if l.length == 0 {
+               return rr, nil, ""
+       }
+       if l.token == "@" {
+               rr.PreviousName = o
+       } else {
+               _, ok := IsDomainName(l.token)
+               if !ok || l.length == 0 || l.err {
+                       return nil, &ParseError{f, "bad TALINK PreviousName", l}, ""
+               }
+               if rr.PreviousName[l.length-1] != '.' {
+                       rr.PreviousName = appendOrigin(rr.PreviousName, o)
+               }
+       }
+       <-c // zBlank
+       l = <-c
+       rr.NextName = l.token
+       if l.token == "@" {
+               rr.NextName = o
+               return rr, nil, ""
+       }
+       _, ok := IsDomainName(l.token)
+       if !ok || l.length == 0 || l.err {
+               return nil, &ParseError{f, "bad TALINK NextName", l}, ""
+       }
+       if rr.NextName[l.length-1] != '.' {
+               rr.NextName = appendOrigin(rr.NextName, o)
+       }
+       return rr, nil, ""
+}
+
+func setLOC(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
+       rr := new(LOC)
+       rr.Hdr = h
+       // Non zero defaults for LOC record, see RFC 1876, Section 3.
+       rr.HorizPre = 165 // 10000
+       rr.VertPre = 162  // 10
+       rr.Size = 18      // 1
+       ok := false
+       // North
+       l := <-c
+       if l.length == 0 {
+               return rr, nil, ""
+       }
+       i, e := strconv.Atoi(l.token)
+       if e != nil || l.err {
+               return nil, &ParseError{f, "bad LOC Latitude", l}, ""
+       }
+       rr.Latitude = 1000 * 60 * 60 * uint32(i)
+
+       <-c // zBlank
+       // Either number, 'N' or 'S'
+       l = <-c
+       if rr.Latitude, ok = locCheckNorth(l.token, rr.Latitude); ok {
+               goto East
+       }
+       i, e = strconv.Atoi(l.token)
+       if e != nil || l.err {
+               return nil, &ParseError{f, "bad LOC Latitude minutes", l}, ""
+       }
+       rr.Latitude += 1000 * 60 * uint32(i)
+
+       <-c // zBlank
+       l = <-c
+       if i, e := strconv.ParseFloat(l.token, 32); e != nil || l.err {
+               return nil, &ParseError{f, "bad LOC Latitude seconds", l}, ""
+       } else {
+               rr.Latitude += uint32(1000 * i)
+       }
+       <-c // zBlank
+       // Either number, 'N' or 'S'
+       l = <-c
+       if rr.Latitude, ok = locCheckNorth(l.token, rr.Latitude); ok {
+               goto East
+       }
+       // If still alive, flag an error
+       return nil, &ParseError{f, "bad LOC Latitude North/South", l}, ""
+
+East:
+       // East
+       <-c // zBlank
+       l = <-c
+       if i, e := strconv.Atoi(l.token); e != nil || l.err {
+               return nil, &ParseError{f, "bad LOC Longitude", l}, ""
+       } else {
+               rr.Longitude = 1000 * 60 * 60 * uint32(i)
+       }
+       <-c // zBlank
+       // Either number, 'E' or 'W'
+       l = <-c
+       if rr.Longitude, ok = locCheckEast(l.token, rr.Longitude); ok {
+               goto Altitude
+       }
+       if i, e := strconv.Atoi(l.token); e != nil || l.err {
+               return nil, &ParseError{f, "bad LOC Longitude minutes", l}, ""
+       } else {
+               rr.Longitude += 1000 * 60 * uint32(i)
+       }
+       <-c // zBlank
+       l = <-c
+       if i, e := strconv.ParseFloat(l.token, 32); e != nil || l.err {
+               return nil, &ParseError{f, "bad LOC Longitude seconds", l}, ""
+       } else {
+               rr.Longitude += uint32(1000 * i)
+       }
+       <-c // zBlank
+       // Either number, 'E' or 'W'
+       l = <-c
+       if rr.Longitude, ok = locCheckEast(l.token, rr.Longitude); ok {
+               goto Altitude
+       }
+       // If still alive, flag an error
+       return nil, &ParseError{f, "bad LOC Longitude East/West", l}, ""
+
+Altitude:
+       <-c // zBlank
+       l = <-c
+       if l.length == 0 || l.err {
+               return nil, &ParseError{f, "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 nil, &ParseError{f, "bad LOC Altitude", l}, ""
+       } else {
+               rr.Altitude = uint32(i*100.0 + 10000000.0 + 0.5)
+       }
+
+       // And now optionally the other values
+       l = <-c
+       count := 0
+       for l.value != zNewline && l.value != zEOF {
+               switch l.value {
+               case zString:
+                       switch count {
+                       case 0: // Size
+                               e, m, ok := stringToCm(l.token)
+                               if !ok {
+                                       return nil, &ParseError{f, "bad LOC Size", l}, ""
+                               }
+                               rr.Size = (e & 0x0f) | (m << 4 & 0xf0)
+                       case 1: // HorizPre
+                               e, m, ok := stringToCm(l.token)
+                               if !ok {
+                                       return nil, &ParseError{f, "bad LOC HorizPre", l}, ""
+                               }
+                               rr.HorizPre = (e & 0x0f) | (m << 4 & 0xf0)
+                       case 2: // VertPre
+                               e, m, ok := stringToCm(l.token)
+                               if !ok {
+                                       return nil, &ParseError{f, "bad LOC VertPre", l}, ""
+                               }
+                               rr.VertPre = (e & 0x0f) | (m << 4 & 0xf0)
+                       }
+                       count++
+               case zBlank:
+                       // Ok
+               default:
+                       return nil, &ParseError{f, "bad LOC Size, HorizPre or VertPre", l}, ""
+               }
+               l = <-c
+       }
+       return rr, nil, ""
+}
+
+func setHIP(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
+       rr := new(HIP)
+       rr.Hdr = h
+
+       // HitLength is not represented
+       l := <-c
+       if l.length == 0 {
+               return rr, nil, l.comment
+       }
+       i, e := strconv.Atoi(l.token)
+       if e != nil || l.err {
+               return nil, &ParseError{f, "bad HIP PublicKeyAlgorithm", l}, ""
+       }
+       rr.PublicKeyAlgorithm = uint8(i)
+       <-c     // zBlank
+       l = <-c // zString
+       if l.length == 0 || l.err {
+               return nil, &ParseError{f, "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
+
+       <-c     // zBlank
+       l = <-c // zString
+       if l.length == 0 || l.err {
+               return nil, &ParseError{f, "bad HIP PublicKey", l}, ""
+       }
+       rr.PublicKey = l.token // This cannot contain spaces
+       rr.PublicKeyLength = uint16(base64.StdEncoding.DecodedLen(len(rr.PublicKey)))
+
+       // RendezvousServers (if any)
+       l = <-c
+       var xs []string
+       for l.value != zNewline && l.value != zEOF {
+               switch l.value {
+               case zString:
+                       if l.token == "@" {
+                               xs = append(xs, o)
+                               l = <-c
+                               continue
+                       }
+                       _, ok := IsDomainName(l.token)
+                       if !ok || l.length == 0 || l.err {
+                               return nil, &ParseError{f, "bad HIP RendezvousServers", l}, ""
+                       }
+                       if l.token[l.length-1] != '.' {
+                               l.token = appendOrigin(l.token, o)
+                       }
+                       xs = append(xs, l.token)
+               case zBlank:
+                       // Ok
+               default:
+                       return nil, &ParseError{f, "bad HIP RendezvousServers", l}, ""
+               }
+               l = <-c
+       }
+       rr.RendezvousServers = xs
+       return rr, nil, l.comment
+}
+
+func setCERT(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
+       rr := new(CERT)
+       rr.Hdr = h
+
+       l := <-c
+       if l.length == 0 {
+               return rr, nil, l.comment
+       }
+       if v, ok := StringToCertType[l.token]; ok {
+               rr.Type = v
+       } else if i, e := strconv.Atoi(l.token); e != nil {
+               return nil, &ParseError{f, "bad CERT Type", l}, ""
+       } else {
+               rr.Type = uint16(i)
+       }
+       <-c     // zBlank
+       l = <-c // zString
+       i, e := strconv.Atoi(l.token)
+       if e != nil || l.err {
+               return nil, &ParseError{f, "bad CERT KeyTag", l}, ""
+       }
+       rr.KeyTag = uint16(i)
+       <-c     // zBlank
+       l = <-c // zString
+       if v, ok := StringToAlgorithm[l.token]; ok {
+               rr.Algorithm = v
+       } else if i, e := strconv.Atoi(l.token); e != nil {
+               return nil, &ParseError{f, "bad CERT Algorithm", l}, ""
+       } else {
+               rr.Algorithm = uint8(i)
+       }
+       s, e1, c1 := endingToString(c, "bad CERT Certificate", f)
+       if e1 != nil {
+               return nil, e1, c1
+       }
+       rr.Certificate = s
+       return rr, nil, c1
+}
+
+func setOPENPGPKEY(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
+       rr := new(OPENPGPKEY)
+       rr.Hdr = h
+
+       s, e, c1 := endingToString(c, "bad OPENPGPKEY PublicKey", f)
+       if e != nil {
+               return nil, e, c1
+       }
+       rr.PublicKey = s
+       return rr, nil, c1
+}
+
+func setSIG(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
+       r, e, s := setRRSIG(h, c, o, f)
+       if r != nil {
+               return &SIG{*r.(*RRSIG)}, e, s
+       }
+       return nil, e, s
+}
+
+func setRRSIG(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
+       rr := new(RRSIG)
+       rr.Hdr = h
+       l := <-c
+       if l.length == 0 {
+               return rr, nil, l.comment
+       }
+       if t, ok := StringToType[l.tokenUpper]; !ok {
+               if strings.HasPrefix(l.tokenUpper, "TYPE") {
+                       t, ok = typeToInt(l.tokenUpper)
+                       if !ok {
+                               return nil, &ParseError{f, "bad RRSIG Typecovered", l}, ""
+                       }
+                       rr.TypeCovered = t
+               } else {
+                       return nil, &ParseError{f, "bad RRSIG Typecovered", l}, ""
+               }
+       } else {
+               rr.TypeCovered = t
+       }
+       <-c // zBlank
+       l = <-c
+       i, err := strconv.Atoi(l.token)
+       if err != nil || l.err {
+               return nil, &ParseError{f, "bad RRSIG Algorithm", l}, ""
+       }
+       rr.Algorithm = uint8(i)
+       <-c // zBlank
+       l = <-c
+       i, err = strconv.Atoi(l.token)
+       if err != nil || l.err {
+               return nil, &ParseError{f, "bad RRSIG Labels", l}, ""
+       }
+       rr.Labels = uint8(i)
+       <-c // zBlank
+       l = <-c
+       i, err = strconv.Atoi(l.token)
+       if err != nil || l.err {
+               return nil, &ParseError{f, "bad RRSIG OrigTtl", l}, ""
+       }
+       rr.OrigTtl = uint32(i)
+       <-c // zBlank
+       l = <-c
+       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
+                       rr.Expiration = uint32(i)
+               } else {
+                       return nil, &ParseError{f, "bad RRSIG Expiration", l}, ""
+               }
+       } else {
+               rr.Expiration = i
+       }
+       <-c // zBlank
+       l = <-c
+       if i, err := StringToTime(l.token); err != nil {
+               if i, err := strconv.ParseInt(l.token, 10, 64); err == nil {
+                       rr.Inception = uint32(i)
+               } else {
+                       return nil, &ParseError{f, "bad RRSIG Inception", l}, ""
+               }
+       } else {
+               rr.Inception = i
+       }
+       <-c // zBlank
+       l = <-c
+       i, err = strconv.Atoi(l.token)
+       if err != nil || l.err {
+               return nil, &ParseError{f, "bad RRSIG KeyTag", l}, ""
+       }
+       rr.KeyTag = uint16(i)
+       <-c // zBlank
+       l = <-c
+       rr.SignerName = l.token
+       if l.token == "@" {
+               rr.SignerName = o
+       } else {
+               _, ok := IsDomainName(l.token)
+               if !ok || l.length == 0 || l.err {
+                       return nil, &ParseError{f, "bad RRSIG SignerName", l}, ""
+               }
+               if rr.SignerName[l.length-1] != '.' {
+                       rr.SignerName = appendOrigin(rr.SignerName, o)
+               }
+       }
+       s, e, c1 := endingToString(c, "bad RRSIG Signature", f)
+       if e != nil {
+               return nil, e, c1
+       }
+       rr.Signature = s
+       return rr, nil, c1
+}
+
+func setNSEC(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
+       rr := new(NSEC)
+       rr.Hdr = h
+
+       l := <-c
+       rr.NextDomain = l.token
+       if l.length == 0 {
+               return rr, nil, l.comment
+       }
+       if l.token == "@" {
+               rr.NextDomain = o
+       } else {
+               _, ok := IsDomainName(l.token)
+               if !ok || l.length == 0 || l.err {
+                       return nil, &ParseError{f, "bad NSEC NextDomain", l}, ""
+               }
+               if rr.NextDomain[l.length-1] != '.' {
+                       rr.NextDomain = appendOrigin(rr.NextDomain, o)
+               }
+       }
+
+       rr.TypeBitMap = make([]uint16, 0)
+       var (
+               k  uint16
+               ok bool
+       )
+       l = <-c
+       for l.value != zNewline && l.value != zEOF {
+               switch l.value {
+               case zBlank:
+                       // Ok
+               case zString:
+                       if k, ok = StringToType[l.tokenUpper]; !ok {
+                               if k, ok = typeToInt(l.tokenUpper); !ok {
+                                       return nil, &ParseError{f, "bad NSEC TypeBitMap", l}, ""
+                               }
+                       }
+                       rr.TypeBitMap = append(rr.TypeBitMap, k)
+               default:
+                       return nil, &ParseError{f, "bad NSEC TypeBitMap", l}, ""
+               }
+               l = <-c
+       }
+       return rr, nil, l.comment
+}
+
+func setNSEC3(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
+       rr := new(NSEC3)
+       rr.Hdr = h
+
+       l := <-c
+       if l.length == 0 {
+               return rr, nil, l.comment
+       }
+       i, e := strconv.Atoi(l.token)
+       if e != nil || l.err {
+               return nil, &ParseError{f, "bad NSEC3 Hash", l}, ""
+       }
+       rr.Hash = uint8(i)
+       <-c // zBlank
+       l = <-c
+       i, e = strconv.Atoi(l.token)
+       if e != nil || l.err {
+               return nil, &ParseError{f, "bad NSEC3 Flags", l}, ""
+       }
+       rr.Flags = uint8(i)
+       <-c // zBlank
+       l = <-c
+       i, e = strconv.Atoi(l.token)
+       if e != nil || l.err {
+               return nil, &ParseError{f, "bad NSEC3 Iterations", l}, ""
+       }
+       rr.Iterations = uint16(i)
+       <-c
+       l = <-c
+       if len(l.token) == 0 || l.err {
+               return nil, &ParseError{f, "bad NSEC3 Salt", l}, ""
+       }
+       rr.SaltLength = uint8(len(l.token)) / 2
+       rr.Salt = l.token
+
+       <-c
+       l = <-c
+       if len(l.token) == 0 || l.err {
+               return nil, &ParseError{f, "bad NSEC3 NextDomain", l}, ""
+       }
+       rr.HashLength = 20 // Fix for NSEC3 (sha1 160 bits)
+       rr.NextDomain = l.token
+
+       rr.TypeBitMap = make([]uint16, 0)
+       var (
+               k  uint16
+               ok bool
+       )
+       l = <-c
+       for l.value != zNewline && l.value != zEOF {
+               switch l.value {
+               case zBlank:
+                       // Ok
+               case zString:
+                       if k, ok = StringToType[l.tokenUpper]; !ok {
+                               if k, ok = typeToInt(l.tokenUpper); !ok {
+                                       return nil, &ParseError{f, "bad NSEC3 TypeBitMap", l}, ""
+                               }
+                       }
+                       rr.TypeBitMap = append(rr.TypeBitMap, k)
+               default:
+                       return nil, &ParseError{f, "bad NSEC3 TypeBitMap", l}, ""
+               }
+               l = <-c
+       }
+       return rr, nil, l.comment
+}
+
+func setNSEC3PARAM(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
+       rr := new(NSEC3PARAM)
+       rr.Hdr = h
+
+       l := <-c
+       if l.length == 0 {
+               return rr, nil, ""
+       }
+       i, e := strconv.Atoi(l.token)
+       if e != nil || l.err {
+               return nil, &ParseError{f, "bad NSEC3PARAM Hash", l}, ""
+       }
+       rr.Hash = uint8(i)
+       <-c // zBlank
+       l = <-c
+       i, e = strconv.Atoi(l.token)
+       if e != nil || l.err {
+               return nil, &ParseError{f, "bad NSEC3PARAM Flags", l}, ""
+       }
+       rr.Flags = uint8(i)
+       <-c // zBlank
+       l = <-c
+       i, e = strconv.Atoi(l.token)
+       if e != nil || l.err {
+               return nil, &ParseError{f, "bad NSEC3PARAM Iterations", l}, ""
+       }
+       rr.Iterations = uint16(i)
+       <-c
+       l = <-c
+       rr.SaltLength = uint8(len(l.token))
+       rr.Salt = l.token
+       return rr, nil, ""
+}
+
+func setEUI48(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
+       rr := new(EUI48)
+       rr.Hdr = h
+
+       l := <-c
+       if l.length == 0 {
+               return rr, nil, ""
+       }
+       if l.length != 17 || l.err {
+               return nil, &ParseError{f, "bad EUI48 Address", l}, ""
+       }
+       addr := make([]byte, 12)
+       dash := 0
+       for i := 0; i < 10; i += 2 {
+               addr[i] = l.token[i+dash]
+               addr[i+1] = l.token[i+1+dash]
+               dash++
+               if l.token[i+1+dash] != '-' {
+                       return nil, &ParseError{f, "bad EUI48 Address", l}, ""
+               }
+       }
+       addr[10] = l.token[15]
+       addr[11] = l.token[16]
+
+       i, e := strconv.ParseUint(string(addr), 16, 48)
+       if e != nil {
+               return nil, &ParseError{f, "bad EUI48 Address", l}, ""
+       }
+       rr.Address = i
+       return rr, nil, ""
+}
+
+func setEUI64(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
+       rr := new(EUI64)
+       rr.Hdr = h
+
+       l := <-c
+       if l.length == 0 {
+               return rr, nil, ""
+       }
+       if l.length != 23 || l.err {
+               return nil, &ParseError{f, "bad EUI64 Address", l}, ""
+       }
+       addr := make([]byte, 16)
+       dash := 0
+       for i := 0; i < 14; i += 2 {
+               addr[i] = l.token[i+dash]
+               addr[i+1] = l.token[i+1+dash]
+               dash++
+               if l.token[i+1+dash] != '-' {
+                       return nil, &ParseError{f, "bad EUI64 Address", l}, ""
+               }
+       }
+       addr[14] = l.token[21]
+       addr[15] = l.token[22]
+
+       i, e := strconv.ParseUint(string(addr), 16, 64)
+       if e != nil {
+               return nil, &ParseError{f, "bad EUI68 Address", l}, ""
+       }
+       rr.Address = uint64(i)
+       return rr, nil, ""
+}
+
+func setSSHFP(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
+       rr := new(SSHFP)
+       rr.Hdr = h
+
+       l := <-c
+       if l.length == 0 {
+               return rr, nil, ""
+       }
+       i, e := strconv.Atoi(l.token)
+       if e != nil || l.err {
+               return nil, &ParseError{f, "bad SSHFP Algorithm", l}, ""
+       }
+       rr.Algorithm = uint8(i)
+       <-c // zBlank
+       l = <-c
+       i, e = strconv.Atoi(l.token)
+       if e != nil || l.err {
+               return nil, &ParseError{f, "bad SSHFP Type", l}, ""
+       }
+       rr.Type = uint8(i)
+       <-c // zBlank
+       s, e1, c1 := endingToString(c, "bad SSHFP Fingerprint", f)
+       if e1 != nil {
+               return nil, e1, c1
+       }
+       rr.FingerPrint = s
+       return rr, nil, ""
+}
+
+func setDNSKEYs(h RR_Header, c chan lex, o, f, typ string) (RR, *ParseError, string) {
+       rr := new(DNSKEY)
+       rr.Hdr = h
+
+       l := <-c
+       if l.length == 0 {
+               return rr, nil, l.comment
+       }
+       i, e := strconv.Atoi(l.token)
+       if e != nil || l.err {
+               return nil, &ParseError{f, "bad " + typ + " Flags", l}, ""
+       }
+       rr.Flags = uint16(i)
+       <-c     // zBlank
+       l = <-c // zString
+       i, e = strconv.Atoi(l.token)
+       if e != nil || l.err {
+               return nil, &ParseError{f, "bad " + typ + " Protocol", l}, ""
+       }
+       rr.Protocol = uint8(i)
+       <-c     // zBlank
+       l = <-c // zString
+       i, e = strconv.Atoi(l.token)
+       if e != nil || l.err {
+               return nil, &ParseError{f, "bad " + typ + " Algorithm", l}, ""
+       }
+       rr.Algorithm = uint8(i)
+       s, e1, c1 := endingToString(c, "bad "+typ+" PublicKey", f)
+       if e1 != nil {
+               return nil, e1, c1
+       }
+       rr.PublicKey = s
+       return rr, nil, c1
+}
+
+func setKEY(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
+       r, e, s := setDNSKEYs(h, c, o, f, "KEY")
+       if r != nil {
+               return &KEY{*r.(*DNSKEY)}, e, s
+       }
+       return nil, e, s
+}
+
+func setDNSKEY(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
+       r, e, s := setDNSKEYs(h, c, o, f, "DNSKEY")
+       return r, e, s
+}
+
+func setCDNSKEY(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
+       r, e, s := setDNSKEYs(h, c, o, f, "CDNSKEY")
+       if r != nil {
+               return &CDNSKEY{*r.(*DNSKEY)}, e, s
+       }
+       return nil, e, s
+}
+
+func setRKEY(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
+       rr := new(RKEY)
+       rr.Hdr = h
+
+       l := <-c
+       if l.length == 0 {
+               return rr, nil, l.comment
+       }
+       i, e := strconv.Atoi(l.token)
+       if e != nil || l.err {
+               return nil, &ParseError{f, "bad RKEY Flags", l}, ""
+       }
+       rr.Flags = uint16(i)
+       <-c     // zBlank
+       l = <-c // zString
+       i, e = strconv.Atoi(l.token)
+       if e != nil || l.err {
+               return nil, &ParseError{f, "bad RKEY Protocol", l}, ""
+       }
+       rr.Protocol = uint8(i)
+       <-c     // zBlank
+       l = <-c // zString
+       i, e = strconv.Atoi(l.token)
+       if e != nil || l.err {
+               return nil, &ParseError{f, "bad RKEY Algorithm", l}, ""
+       }
+       rr.Algorithm = uint8(i)
+       s, e1, c1 := endingToString(c, "bad RKEY PublicKey", f)
+       if e1 != nil {
+               return nil, e1, c1
+       }
+       rr.PublicKey = s
+       return rr, nil, c1
+}
+
+func setEID(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
+       rr := new(EID)
+       rr.Hdr = h
+       s, e, c1 := endingToString(c, "bad EID Endpoint", f)
+       if e != nil {
+               return nil, e, c1
+       }
+       rr.Endpoint = s
+       return rr, nil, c1
+}
+
+func setNIMLOC(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
+       rr := new(NIMLOC)
+       rr.Hdr = h
+       s, e, c1 := endingToString(c, "bad NIMLOC Locator", f)
+       if e != nil {
+               return nil, e, c1
+       }
+       rr.Locator = s
+       return rr, nil, c1
+}
+
+func setGPOS(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
+       rr := new(GPOS)
+       rr.Hdr = h
+       l := <-c
+       if l.length == 0 {
+               return rr, nil, ""
+       }
+       _, e := strconv.ParseFloat(l.token, 64)
+       if e != nil || l.err {
+               return nil, &ParseError{f, "bad GPOS Longitude", l}, ""
+       }
+       rr.Longitude = l.token
+       <-c // zBlank
+       l = <-c
+       _, e = strconv.ParseFloat(l.token, 64)
+       if e != nil || l.err {
+               return nil, &ParseError{f, "bad GPOS Latitude", l}, ""
+       }
+       rr.Latitude = l.token
+       <-c // zBlank
+       l = <-c
+       _, e = strconv.ParseFloat(l.token, 64)
+       if e != nil || l.err {
+               return nil, &ParseError{f, "bad GPOS Altitude", l}, ""
+       }
+       rr.Altitude = l.token
+       return rr, nil, ""
+}
+
+func setDSs(h RR_Header, c chan lex, o, f, typ string) (RR, *ParseError, string) {
+       rr := new(DS)
+       rr.Hdr = h
+       l := <-c
+       if l.length == 0 {
+               return rr, nil, l.comment
+       }
+       i, e := strconv.Atoi(l.token)
+       if e != nil || l.err {
+               return nil, &ParseError{f, "bad " + typ + " KeyTag", l}, ""
+       }
+       rr.KeyTag = uint16(i)
+       <-c // zBlank
+       l = <-c
+       if i, e := strconv.Atoi(l.token); e != nil {
+               i, ok := StringToAlgorithm[l.tokenUpper]
+               if !ok || l.err {
+                       return nil, &ParseError{f, "bad " + typ + " Algorithm", l}, ""
+               }
+               rr.Algorithm = i
+       } else {
+               rr.Algorithm = uint8(i)
+       }
+       <-c // zBlank
+       l = <-c
+       i, e = strconv.Atoi(l.token)
+       if e != nil || l.err {
+               return nil, &ParseError{f, "bad " + typ + " DigestType", l}, ""
+       }
+       rr.DigestType = uint8(i)
+       s, e1, c1 := endingToString(c, "bad "+typ+" Digest", f)
+       if e1 != nil {
+               return nil, e1, c1
+       }
+       rr.Digest = s
+       return rr, nil, c1
+}
+
+func setDS(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
+       r, e, s := setDSs(h, c, o, f, "DS")
+       return r, e, s
+}
+
+func setDLV(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
+       r, e, s := setDSs(h, c, o, f, "DLV")
+       if r != nil {
+               return &DLV{*r.(*DS)}, e, s
+       }
+       return nil, e, s
+}
+
+func setCDS(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
+       r, e, s := setDSs(h, c, o, f, "CDS")
+       if r != nil {
+               return &CDS{*r.(*DS)}, e, s
+       }
+       return nil, e, s
+}
+
+func setTA(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
+       rr := new(TA)
+       rr.Hdr = h
+       l := <-c
+       if l.length == 0 {
+               return rr, nil, l.comment
+       }
+       i, e := strconv.Atoi(l.token)
+       if e != nil || l.err {
+               return nil, &ParseError{f, "bad TA KeyTag", l}, ""
+       }
+       rr.KeyTag = uint16(i)
+       <-c // zBlank
+       l = <-c
+       if i, e := strconv.Atoi(l.token); e != nil {
+               i, ok := StringToAlgorithm[l.tokenUpper]
+               if !ok || l.err {
+                       return nil, &ParseError{f, "bad TA Algorithm", l}, ""
+               }
+               rr.Algorithm = i
+       } else {
+               rr.Algorithm = uint8(i)
+       }
+       <-c // zBlank
+       l = <-c
+       i, e = strconv.Atoi(l.token)
+       if e != nil || l.err {
+               return nil, &ParseError{f, "bad TA DigestType", l}, ""
+       }
+       rr.DigestType = uint8(i)
+       s, e, c1 := endingToString(c, "bad TA Digest", f)
+       if e != nil {
+               return nil, e.(*ParseError), c1
+       }
+       rr.Digest = s
+       return rr, nil, c1
+}
+
+func setTLSA(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
+       rr := new(TLSA)
+       rr.Hdr = h
+       l := <-c
+       if l.length == 0 {
+               return rr, nil, l.comment
+       }
+       i, e := strconv.Atoi(l.token)
+       if e != nil || l.err {
+               return nil, &ParseError{f, "bad TLSA Usage", l}, ""
+       }
+       rr.Usage = uint8(i)
+       <-c // zBlank
+       l = <-c
+       i, e = strconv.Atoi(l.token)
+       if e != nil || l.err {
+               return nil, &ParseError{f, "bad TLSA Selector", l}, ""
+       }
+       rr.Selector = uint8(i)
+       <-c // zBlank
+       l = <-c
+       i, e = strconv.Atoi(l.token)
+       if e != nil || l.err {
+               return nil, &ParseError{f, "bad TLSA MatchingType", l}, ""
+       }
+       rr.MatchingType = uint8(i)
+       // So this needs be e2 (i.e. different than e), because...??t
+       s, e2, c1 := endingToString(c, "bad TLSA Certificate", f)
+       if e2 != nil {
+               return nil, e2, c1
+       }
+       rr.Certificate = s
+       return rr, nil, c1
+}
+
+func setRFC3597(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
+       rr := new(RFC3597)
+       rr.Hdr = h
+       l := <-c
+       if l.token != "\\#" {
+               return nil, &ParseError{f, "bad RFC3597 Rdata", l}, ""
+       }
+       <-c // zBlank
+       l = <-c
+       rdlength, e := strconv.Atoi(l.token)
+       if e != nil || l.err {
+               return nil, &ParseError{f, "bad RFC3597 Rdata ", l}, ""
+       }
+
+       s, e1, c1 := endingToString(c, "bad RFC3597 Rdata", f)
+       if e1 != nil {
+               return nil, e1, c1
+       }
+       if rdlength*2 != len(s) {
+               return nil, &ParseError{f, "bad RFC3597 Rdata", l}, ""
+       }
+       rr.Rdata = s
+       return rr, nil, c1
+}
+
+func setSPF(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
+       rr := new(SPF)
+       rr.Hdr = h
+
+       s, e, c1 := endingToTxtSlice(c, "bad SPF Txt", f)
+       if e != nil {
+               return nil, e, ""
+       }
+       rr.Txt = s
+       return rr, nil, c1
+}
+
+func setTXT(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
+       rr := new(TXT)
+       rr.Hdr = h
+
+       // no zBlank reading here, because all this rdata is TXT
+       s, e, c1 := endingToTxtSlice(c, "bad TXT Txt", f)
+       if e != nil {
+               return nil, e, ""
+       }
+       rr.Txt = s
+       return rr, nil, c1
+}
+
+// identical to setTXT
+func setNINFO(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
+       rr := new(NINFO)
+       rr.Hdr = h
+
+       s, e, c1 := endingToTxtSlice(c, "bad NINFO ZSData", f)
+       if e != nil {
+               return nil, e, ""
+       }
+       rr.ZSData = s
+       return rr, nil, c1
+}
+
+func setURI(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
+       rr := new(URI)
+       rr.Hdr = h
+
+       l := <-c
+       if l.length == 0 { // Dynamic updates.
+               return rr, nil, ""
+       }
+
+       i, e := strconv.Atoi(l.token)
+       if e != nil || l.err {
+               return nil, &ParseError{f, "bad URI Priority", l}, ""
+       }
+       rr.Priority = uint16(i)
+       <-c // zBlank
+       l = <-c
+       i, e = strconv.Atoi(l.token)
+       if e != nil || l.err {
+               return nil, &ParseError{f, "bad URI Weight", l}, ""
+       }
+       rr.Weight = uint16(i)
+
+       <-c // zBlank
+       s, err, c1 := endingToTxtSlice(c, "bad URI Target", f)
+       if err != nil {
+               return nil, err, ""
+       }
+       if len(s) > 1 {
+               return nil, &ParseError{f, "bad URI Target", l}, ""
+       }
+       rr.Target = s[0]
+       return rr, nil, c1
+}
+
+func setDHCID(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
+       // awesome record to parse!
+       rr := new(DHCID)
+       rr.Hdr = h
+
+       s, e, c1 := endingToString(c, "bad DHCID Digest", f)
+       if e != nil {
+               return nil, e, c1
+       }
+       rr.Digest = s
+       return rr, nil, c1
+}
+
+func setNID(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
+       rr := new(NID)
+       rr.Hdr = h
+
+       l := <-c
+       if l.length == 0 {
+               return rr, nil, ""
+       }
+       i, e := strconv.Atoi(l.token)
+       if e != nil || l.err {
+               return nil, &ParseError{f, "bad NID Preference", l}, ""
+       }
+       rr.Preference = uint16(i)
+       <-c     // zBlank
+       l = <-c // zString
+       u, err := stringToNodeID(l)
+       if err != nil || l.err {
+               return nil, err, ""
+       }
+       rr.NodeID = u
+       return rr, nil, ""
+}
+
+func setL32(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
+       rr := new(L32)
+       rr.Hdr = h
+
+       l := <-c
+       if l.length == 0 {
+               return rr, nil, ""
+       }
+       i, e := strconv.Atoi(l.token)
+       if e != nil || l.err {
+               return nil, &ParseError{f, "bad L32 Preference", l}, ""
+       }
+       rr.Preference = uint16(i)
+       <-c     // zBlank
+       l = <-c // zString
+       rr.Locator32 = net.ParseIP(l.token)
+       if rr.Locator32 == nil || l.err {
+               return nil, &ParseError{f, "bad L32 Locator", l}, ""
+       }
+       return rr, nil, ""
+}
+
+func setLP(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
+       rr := new(LP)
+       rr.Hdr = h
+
+       l := <-c
+       if l.length == 0 {
+               return rr, nil, ""
+       }
+       i, e := strconv.Atoi(l.token)
+       if e != nil || l.err {
+               return nil, &ParseError{f, "bad LP Preference", l}, ""
+       }
+       rr.Preference = uint16(i)
+       <-c     // zBlank
+       l = <-c // zString
+       rr.Fqdn = l.token
+       if l.length == 0 {
+               return rr, nil, ""
+       }
+       if l.token == "@" {
+               rr.Fqdn = o
+               return rr, nil, ""
+       }
+       _, ok := IsDomainName(l.token)
+       if !ok || l.length == 0 || l.err {
+               return nil, &ParseError{f, "bad LP Fqdn", l}, ""
+       }
+       if rr.Fqdn[l.length-1] != '.' {
+               rr.Fqdn = appendOrigin(rr.Fqdn, o)
+       }
+       return rr, nil, ""
+}
+
+func setL64(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
+       rr := new(L64)
+       rr.Hdr = h
+
+       l := <-c
+       if l.length == 0 {
+               return rr, nil, ""
+       }
+       i, e := strconv.Atoi(l.token)
+       if e != nil || l.err {
+               return nil, &ParseError{f, "bad L64 Preference", l}, ""
+       }
+       rr.Preference = uint16(i)
+       <-c     // zBlank
+       l = <-c // zString
+       u, err := stringToNodeID(l)
+       if err != nil || l.err {
+               return nil, err, ""
+       }
+       rr.Locator64 = u
+       return rr, nil, ""
+}
+
+func setUID(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
+       rr := new(UID)
+       rr.Hdr = h
+       l := <-c
+       if l.length == 0 {
+               return rr, nil, ""
+       }
+       i, e := strconv.Atoi(l.token)
+       if e != nil || l.err {
+               return nil, &ParseError{f, "bad UID Uid", l}, ""
+       }
+       rr.Uid = uint32(i)
+       return rr, nil, ""
+}
+
+func setGID(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
+       rr := new(GID)
+       rr.Hdr = h
+       l := <-c
+       if l.length == 0 {
+               return rr, nil, ""
+       }
+       i, e := strconv.Atoi(l.token)
+       if e != nil || l.err {
+               return nil, &ParseError{f, "bad GID Gid", l}, ""
+       }
+       rr.Gid = uint32(i)
+       return rr, nil, ""
+}
+
+func setUINFO(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
+       rr := new(UINFO)
+       rr.Hdr = h
+       s, e, c1 := endingToTxtSlice(c, "bad UINFO Uinfo", f)
+       if e != nil {
+               return nil, e, ""
+       }
+       rr.Uinfo = s[0] // silently discard anything above
+       return rr, nil, c1
+}
+
+func setPX(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
+       rr := new(PX)
+       rr.Hdr = h
+
+       l := <-c
+       if l.length == 0 {
+               return rr, nil, ""
+       }
+       i, e := strconv.Atoi(l.token)
+       if e != nil || l.err {
+               return nil, &ParseError{f, "bad PX Preference", l}, ""
+       }
+       rr.Preference = uint16(i)
+       <-c     // zBlank
+       l = <-c // zString
+       rr.Map822 = l.token
+       if l.length == 0 {
+               return rr, nil, ""
+       }
+       if l.token == "@" {
+               rr.Map822 = o
+               return rr, nil, ""
+       }
+       _, ok := IsDomainName(l.token)
+       if !ok || l.length == 0 || l.err {
+               return nil, &ParseError{f, "bad PX Map822", l}, ""
+       }
+       if rr.Map822[l.length-1] != '.' {
+               rr.Map822 = appendOrigin(rr.Map822, o)
+       }
+       <-c     // zBlank
+       l = <-c // zString
+       rr.Mapx400 = l.token
+       if l.token == "@" {
+               rr.Mapx400 = o
+               return rr, nil, ""
+       }
+       _, ok = IsDomainName(l.token)
+       if !ok || l.length == 0 || l.err {
+               return nil, &ParseError{f, "bad PX Mapx400", l}, ""
+       }
+       if rr.Mapx400[l.length-1] != '.' {
+               rr.Mapx400 = appendOrigin(rr.Mapx400, o)
+       }
+       return rr, nil, ""
+}
+
+func setCAA(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
+       rr := new(CAA)
+       rr.Hdr = h
+       l := <-c
+       if l.length == 0 {
+               return rr, nil, l.comment
+       }
+       i, err := strconv.Atoi(l.token)
+       if err != nil || l.err {
+               return nil, &ParseError{f, "bad CAA Flag", l}, ""
+       }
+       rr.Flag = uint8(i)
+
+       <-c     // zBlank
+       l = <-c // zString
+       if l.value != zString {
+               return nil, &ParseError{f, "bad CAA Tag", l}, ""
+       }
+       rr.Tag = l.token
+
+       <-c // zBlank
+       s, e, c1 := endingToTxtSlice(c, "bad CAA Value", f)
+       if e != nil {
+               return nil, e, ""
+       }
+       if len(s) > 1 {
+               return nil, &ParseError{f, "bad CAA Value", l}, ""
+       }
+       rr.Value = s[0]
+       return rr, nil, c1
+}
+
+var typeToparserFunc = map[uint16]parserFunc{
+       TypeAAAA:       {setAAAA, false},
+       TypeAFSDB:      {setAFSDB, false},
+       TypeA:          {setA, false},
+       TypeCAA:        {setCAA, true},
+       TypeCDS:        {setCDS, true},
+       TypeCDNSKEY:    {setCDNSKEY, true},
+       TypeCERT:       {setCERT, true},
+       TypeCNAME:      {setCNAME, false},
+       TypeDHCID:      {setDHCID, true},
+       TypeDLV:        {setDLV, true},
+       TypeDNAME:      {setDNAME, false},
+       TypeKEY:        {setKEY, true},
+       TypeDNSKEY:     {setDNSKEY, true},
+       TypeDS:         {setDS, true},
+       TypeEID:        {setEID, true},
+       TypeEUI48:      {setEUI48, false},
+       TypeEUI64:      {setEUI64, false},
+       TypeGID:        {setGID, false},
+       TypeGPOS:       {setGPOS, false},
+       TypeHINFO:      {setHINFO, true},
+       TypeHIP:        {setHIP, true},
+       TypeKX:         {setKX, false},
+       TypeL32:        {setL32, false},
+       TypeL64:        {setL64, false},
+       TypeLOC:        {setLOC, true},
+       TypeLP:         {setLP, false},
+       TypeMB:         {setMB, false},
+       TypeMD:         {setMD, false},
+       TypeMF:         {setMF, false},
+       TypeMG:         {setMG, false},
+       TypeMINFO:      {setMINFO, false},
+       TypeMR:         {setMR, false},
+       TypeMX:         {setMX, false},
+       TypeNAPTR:      {setNAPTR, false},
+       TypeNID:        {setNID, false},
+       TypeNIMLOC:     {setNIMLOC, true},
+       TypeNINFO:      {setNINFO, true},
+       TypeNSAPPTR:    {setNSAPPTR, false},
+       TypeNSEC3PARAM: {setNSEC3PARAM, false},
+       TypeNSEC3:      {setNSEC3, true},
+       TypeNSEC:       {setNSEC, true},
+       TypeNS:         {setNS, false},
+       TypeOPENPGPKEY: {setOPENPGPKEY, true},
+       TypePTR:        {setPTR, false},
+       TypePX:         {setPX, false},
+       TypeSIG:        {setSIG, true},
+       TypeRKEY:       {setRKEY, true},
+       TypeRP:         {setRP, false},
+       TypeRRSIG:      {setRRSIG, true},
+       TypeRT:         {setRT, false},
+       TypeSOA:        {setSOA, false},
+       TypeSPF:        {setSPF, true},
+       TypeSRV:        {setSRV, false},
+       TypeSSHFP:      {setSSHFP, true},
+       TypeTALINK:     {setTALINK, false},
+       TypeTA:         {setTA, true},
+       TypeTLSA:       {setTLSA, true},
+       TypeTXT:        {setTXT, true},
+       TypeUID:        {setUID, false},
+       TypeUINFO:      {setUINFO, true},
+       TypeURI:        {setURI, true},
+       TypeX25:        {setX25, false},
+}
diff --git a/vendor/github.com/miekg/dns/scanner.go b/vendor/github.com/miekg/dns/scanner.go
new file mode 100644 (file)
index 0000000..c29bc2f
--- /dev/null
@@ -0,0 +1,43 @@
+package dns
+
+// Implement a simple scanner, return a byte stream from an io reader.
+
+import (
+       "bufio"
+       "io"
+       "text/scanner"
+)
+
+type scan struct {
+       src      *bufio.Reader
+       position scanner.Position
+       eof      bool // Have we just seen a eof
+}
+
+func scanInit(r io.Reader) *scan {
+       s := new(scan)
+       s.src = bufio.NewReader(r)
+       s.position.Line = 1
+       return s
+}
+
+// tokenText returns the next byte from the input
+func (s *scan) tokenText() (byte, error) {
+       c, err := s.src.ReadByte()
+       if err != nil {
+               return c, err
+       }
+       // delay the newline handling until the next token is delivered,
+       // fixes off-by-one errors when reporting a parse error.
+       if s.eof == true {
+               s.position.Line++
+               s.position.Column = 0
+               s.eof = false
+       }
+       if c == '\n' {
+               s.eof = true
+               return c, nil
+       }
+       s.position.Column++
+       return c, nil
+}
diff --git a/vendor/github.com/miekg/dns/server.go b/vendor/github.com/miekg/dns/server.go
new file mode 100644 (file)
index 0000000..2b4bff4
--- /dev/null
@@ -0,0 +1,732 @@
+// DNS server implementation.
+
+package dns
+
+import (
+       "bytes"
+       "crypto/tls"
+       "encoding/binary"
+       "io"
+       "net"
+       "sync"
+       "time"
+)
+
+// Maximum number of TCP queries before we close the socket.
+const maxTCPQueries = 128
+
+// Handler is implemented by any value that implements ServeDNS.
+type Handler interface {
+       ServeDNS(w ResponseWriter, r *Msg)
+}
+
+// A ResponseWriter interface is used by an DNS handler to
+// construct an DNS response.
+type ResponseWriter interface {
+       // LocalAddr returns the net.Addr of the server
+       LocalAddr() net.Addr
+       // RemoteAddr returns the net.Addr of the client that sent the current request.
+       RemoteAddr() net.Addr
+       // 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.
+       TsigStatus() error
+       // TsigTimersOnly sets the tsig timers only boolean.
+       TsigTimersOnly(bool)
+       // Hijack lets the caller take over the connection.
+       // After a call to Hijack(), the DNS package will not do anything with the connection.
+       Hijack()
+}
+
+type response struct {
+       hijacked       bool // connection has been hijacked by handler
+       tsigStatus     error
+       tsigTimersOnly bool
+       tsigRequestMAC string
+       tsigSecret     map[string]string // the tsig secrets
+       udp            *net.UDPConn      // 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
+       remoteAddr     net.Addr          // address of the client
+       writer         Writer            // writer to output the raw DNS bits
+}
+
+// ServeMux is an DNS request multiplexer. It matches the
+// zone name of each incoming request against a list of
+// registered patterns add calls the handler for the pattern
+// that most closely matches the zone name. ServeMux is DNSSEC aware, meaning
+// that queries for the DS record are redirected to the parent zone (if that
+// is also registered), otherwise the child gets the query.
+// ServeMux is also safe for concurrent access from multiple goroutines.
+type ServeMux struct {
+       z map[string]Handler
+       m *sync.RWMutex
+}
+
+// NewServeMux allocates and returns a new ServeMux.
+func NewServeMux() *ServeMux { return &ServeMux{z: make(map[string]Handler), m: new(sync.RWMutex)} }
+
+// DefaultServeMux is the default ServeMux used by Serve.
+var DefaultServeMux = NewServeMux()
+
+// The HandlerFunc type is an adapter to allow the use of
+// ordinary functions as DNS handlers.  If f is a function
+// with the appropriate signature, HandlerFunc(f) is a
+// Handler object that calls f.
+type HandlerFunc func(ResponseWriter, *Msg)
+
+// ServeDNS calls f(w, r).
+func (f HandlerFunc) ServeDNS(w ResponseWriter, r *Msg) {
+       f(w, r)
+}
+
+// HandleFailed returns a HandlerFunc that returns SERVFAIL for every request it gets.
+func HandleFailed(w ResponseWriter, r *Msg) {
+       m := new(Msg)
+       m.SetRcode(r, RcodeServerFailure)
+       // does not matter if this write fails
+       w.WriteMsg(m)
+}
+
+func failedHandler() Handler { return HandlerFunc(HandleFailed) }
+
+// ListenAndServe Starts a server on address and network specified Invoke handler
+// for incoming queries.
+func ListenAndServe(addr string, network string, handler Handler) error {
+       server := &Server{Addr: addr, Net: network, Handler: handler}
+       return server.ListenAndServe()
+}
+
+// ListenAndServeTLS acts like http.ListenAndServeTLS, more information in
+// http://golang.org/pkg/net/http/#ListenAndServeTLS
+func ListenAndServeTLS(addr, certFile, keyFile string, handler Handler) error {
+       cert, err := tls.LoadX509KeyPair(certFile, keyFile)
+       if err != nil {
+               return err
+       }
+
+       config := tls.Config{
+               Certificates: []tls.Certificate{cert},
+       }
+
+       server := &Server{
+               Addr:      addr,
+               Net:       "tcp-tls",
+               TLSConfig: &config,
+               Handler:   handler,
+       }
+
+       return server.ListenAndServe()
+}
+
+// ActivateAndServe activates a server with a listener from systemd,
+// l and p should not both be non-nil.
+// If both l and p are not nil only p will be used.
+// Invoke handler for incoming queries.
+func ActivateAndServe(l net.Listener, p net.PacketConn, handler Handler) error {
+       server := &Server{Listener: l, PacketConn: p, Handler: handler}
+       return server.ActivateAndServe()
+}
+
+func (mux *ServeMux) match(q string, t uint16) Handler {
+       mux.m.RLock()
+       defer mux.m.RUnlock()
+       var handler Handler
+       b := make([]byte, len(q)) // worst case, one label of length q
+       off := 0
+       end := false
+       for {
+               l := len(q[off:])
+               for i := 0; i < l; i++ {
+                       b[i] = q[off+i]
+                       if b[i] >= 'A' && b[i] <= 'Z' {
+                               b[i] |= ('a' - 'A')
+                       }
+               }
+               if h, ok := mux.z[string(b[:l])]; ok { // 'causes garbage, might want to change the map key
+                       if t != TypeDS {
+                               return h
+                       }
+                       // Continue for DS to see if we have a parent too, if so delegeate to the parent
+                       handler = h
+               }
+               off, end = NextLabel(q, off)
+               if end {
+                       break
+               }
+       }
+       // Wildcard match, if we have found nothing try the root zone as a last resort.
+       if h, ok := mux.z["."]; ok {
+               return h
+       }
+       return handler
+}
+
+// Handle adds a handler to the ServeMux for pattern.
+func (mux *ServeMux) Handle(pattern string, handler Handler) {
+       if pattern == "" {
+               panic("dns: invalid pattern " + pattern)
+       }
+       mux.m.Lock()
+       mux.z[Fqdn(pattern)] = handler
+       mux.m.Unlock()
+}
+
+// HandleFunc adds a handler function to the ServeMux for pattern.
+func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Msg)) {
+       mux.Handle(pattern, HandlerFunc(handler))
+}
+
+// HandleRemove deregistrars the handler specific for pattern from the ServeMux.
+func (mux *ServeMux) HandleRemove(pattern string) {
+       if pattern == "" {
+               panic("dns: invalid pattern " + pattern)
+       }
+       mux.m.Lock()
+       delete(mux.z, Fqdn(pattern))
+       mux.m.Unlock()
+}
+
+// ServeDNS dispatches the request to the handler whose
+// pattern most closely matches the request message. If DefaultServeMux
+// is used the correct thing for DS queries is done: a possible parent
+// is sought.
+// If no handler is found a standard SERVFAIL message is returned
+// If the request message does not have exactly one question in the
+// question section a SERVFAIL is returned, unlesss Unsafe is true.
+func (mux *ServeMux) ServeDNS(w ResponseWriter, request *Msg) {
+       var h Handler
+       if len(request.Question) < 1 { // allow more than one question
+               h = failedHandler()
+       } else {
+               if h = mux.match(request.Question[0].Name, request.Question[0].Qtype); h == nil {
+                       h = failedHandler()
+               }
+       }
+       h.ServeDNS(w, request)
+}
+
+// Handle registers the handler with the given pattern
+// in the DefaultServeMux. The documentation for
+// ServeMux explains how patterns are matched.
+func Handle(pattern string, handler Handler) { DefaultServeMux.Handle(pattern, handler) }
+
+// HandleRemove deregisters the handle with the given pattern
+// in the DefaultServeMux.
+func HandleRemove(pattern string) { DefaultServeMux.HandleRemove(pattern) }
+
+// HandleFunc registers the handler function with the given pattern
+// in the DefaultServeMux.
+func HandleFunc(pattern string, handler func(ResponseWriter, *Msg)) {
+       DefaultServeMux.HandleFunc(pattern, handler)
+}
+
+// Writer writes raw DNS messages; each call to Write should send an entire message.
+type Writer interface {
+       io.Writer
+}
+
+// Reader reads raw DNS messages; each call to ReadTCP or ReadUDP should return an entire message.
+type Reader interface {
+       // ReadTCP reads a raw message from a TCP connection. Implementations may alter
+       // connection properties, for example the read-deadline.
+       ReadTCP(conn net.Conn, timeout time.Duration) ([]byte, error)
+       // ReadUDP reads a raw message from a UDP connection. Implementations may alter
+       // connection properties, for example the read-deadline.
+       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.
+type defaultReader struct {
+       *Server
+}
+
+func (dr *defaultReader) ReadTCP(conn net.Conn, timeout time.Duration) ([]byte, error) {
+       return dr.readTCP(conn, timeout)
+}
+
+func (dr *defaultReader) ReadUDP(conn *net.UDPConn, timeout time.Duration) ([]byte, *SessionUDP, error) {
+       return dr.readUDP(conn, timeout)
+}
+
+// DecorateReader is a decorator hook for extending or supplanting the functionality of a Reader.
+// Implementations should never return a nil Reader.
+type DecorateReader func(Reader) Reader
+
+// DecorateWriter is a decorator hook for extending or supplanting the functionality of a Writer.
+// Implementations should never return a nil Writer.
+type DecorateWriter func(Writer) Writer
+
+// A Server defines parameters for running an DNS server.
+type Server struct {
+       // Address to listen on, ":dns" if empty.
+       Addr string
+       // if "tcp" or "tcp-tls" (DNS over TLS) it will invoke a TCP listener, otherwise an UDP one
+       Net string
+       // TCP Listener to use, this is to aid in systemd's socket activation.
+       Listener net.Listener
+       // TLS connection configuration
+       TLSConfig *tls.Config
+       // UDP "Listener" to use, this is to aid in systemd's socket activation.
+       PacketConn net.PacketConn
+       // Handler to invoke, dns.DefaultServeMux if nil.
+       Handler Handler
+       // Default buffer size to use to read incoming UDP messages. If not set
+       // it defaults to MinMsgSize (512 B).
+       UDPSize int
+       // The net.Conn.SetReadTimeout value for new connections, defaults to 2 * time.Second.
+       ReadTimeout time.Duration
+       // The net.Conn.SetWriteTimeout value for new connections, defaults to 2 * time.Second.
+       WriteTimeout time.Duration
+       // TCP idle timeout for multiple queries, if nil, defaults to 8 * time.Second (RFC 5966).
+       IdleTimeout func() time.Duration
+       // Secret(s) for Tsig map[<zonename>]<base64 secret>.
+       TsigSecret map[string]string
+       // Unsafe instructs the server to disregard any sanity checks and directly hand the message to
+       // the handler. It will specifically not check if the query has the QR bit not set.
+       Unsafe bool
+       // If NotifyStartedFunc is set it is called once the server has started listening.
+       NotifyStartedFunc func()
+       // DecorateReader is optional, allows customization of the process that reads raw DNS messages.
+       DecorateReader DecorateReader
+       // DecorateWriter is optional, allows customization of the process that writes raw DNS messages.
+       DecorateWriter DecorateWriter
+
+       // Graceful shutdown handling
+
+       inFlight sync.WaitGroup
+
+       lock    sync.RWMutex
+       started bool
+}
+
+// ListenAndServe starts a nameserver on the configured address in *Server.
+func (srv *Server) ListenAndServe() error {
+       srv.lock.Lock()
+       defer srv.lock.Unlock()
+       if srv.started {
+               return &Error{err: "server already started"}
+       }
+       addr := srv.Addr
+       if addr == "" {
+               addr = ":domain"
+       }
+       if srv.UDPSize == 0 {
+               srv.UDPSize = MinMsgSize
+       }
+       switch srv.Net {
+       case "tcp", "tcp4", "tcp6":
+               a, err := net.ResolveTCPAddr(srv.Net, addr)
+               if err != nil {
+                       return err
+               }
+               l, err := net.ListenTCP(srv.Net, a)
+               if err != nil {
+                       return err
+               }
+               srv.Listener = l
+               srv.started = true
+               srv.lock.Unlock()
+               err = srv.serveTCP(l)
+               srv.lock.Lock() // to satisfy the defer at the top
+               return err
+       case "tcp-tls", "tcp4-tls", "tcp6-tls":
+               network := "tcp"
+               if srv.Net == "tcp4-tls" {
+                       network = "tcp4"
+               } else if srv.Net == "tcp6" {
+                       network = "tcp6"
+               }
+
+               l, err := tls.Listen(network, addr, srv.TLSConfig)
+               if err != nil {
+                       return err
+               }
+               srv.Listener = l
+               srv.started = true
+               srv.lock.Unlock()
+               err = srv.serveTCP(l)
+               srv.lock.Lock() // to satisfy the defer at the top
+               return err
+       case "udp", "udp4", "udp6":
+               a, err := net.ResolveUDPAddr(srv.Net, addr)
+               if err != nil {
+                       return err
+               }
+               l, err := net.ListenUDP(srv.Net, a)
+               if err != nil {
+                       return err
+               }
+               if e := setUDPSocketOptions(l); e != nil {
+                       return e
+               }
+               srv.PacketConn = l
+               srv.started = true
+               srv.lock.Unlock()
+               err = srv.serveUDP(l)
+               srv.lock.Lock() // to satisfy the defer at the top
+               return err
+       }
+       return &Error{err: "bad network"}
+}
+
+// ActivateAndServe starts a nameserver with the PacketConn or Listener
+// configured in *Server. Its main use is to start a server from systemd.
+func (srv *Server) ActivateAndServe() error {
+       srv.lock.Lock()
+       defer srv.lock.Unlock()
+       if srv.started {
+               return &Error{err: "server already started"}
+       }
+       pConn := srv.PacketConn
+       l := srv.Listener
+       if pConn != nil {
+               if srv.UDPSize == 0 {
+                       srv.UDPSize = MinMsgSize
+               }
+               if t, ok := pConn.(*net.UDPConn); ok {
+                       if e := setUDPSocketOptions(t); e != nil {
+                               return e
+                       }
+                       srv.started = true
+                       srv.lock.Unlock()
+                       e := srv.serveUDP(t)
+                       srv.lock.Lock() // to satisfy the defer at the top
+                       return e
+               }
+       }
+       if l != nil {
+               srv.started = true
+               srv.lock.Unlock()
+               e := srv.serveTCP(l)
+               srv.lock.Lock() // to satisfy the defer at the top
+               return e
+       }
+       return &Error{err: "bad listeners"}
+}
+
+// Shutdown gracefully shuts down a server. After a call to Shutdown, ListenAndServe and
+// ActivateAndServe will return. All in progress queries are completed before the server
+// is taken down. If the Shutdown is taking longer than the reading timeout an error
+// is returned.
+func (srv *Server) Shutdown() error {
+       srv.lock.Lock()
+       if !srv.started {
+               srv.lock.Unlock()
+               return &Error{err: "server not started"}
+       }
+       srv.started = false
+       srv.lock.Unlock()
+
+       if srv.PacketConn != nil {
+               srv.PacketConn.Close()
+       }
+       if srv.Listener != nil {
+               srv.Listener.Close()
+       }
+
+       fin := make(chan bool)
+       go func() {
+               srv.inFlight.Wait()
+               fin <- true
+       }()
+
+       select {
+       case <-time.After(srv.getReadTimeout()):
+               return &Error{err: "server shutdown is pending"}
+       case <-fin:
+               return nil
+       }
+}
+
+// getReadTimeout is a helper func to use system timeout if server did not intend to change it.
+func (srv *Server) getReadTimeout() time.Duration {
+       rtimeout := dnsTimeout
+       if srv.ReadTimeout != 0 {
+               rtimeout = srv.ReadTimeout
+       }
+       return rtimeout
+}
+
+// serveTCP starts a TCP listener for the server.
+// Each request is handled in a separate goroutine.
+func (srv *Server) serveTCP(l net.Listener) error {
+       defer l.Close()
+
+       if srv.NotifyStartedFunc != nil {
+               srv.NotifyStartedFunc()
+       }
+
+       reader := Reader(&defaultReader{srv})
+       if srv.DecorateReader != nil {
+               reader = srv.DecorateReader(reader)
+       }
+
+       handler := srv.Handler
+       if handler == nil {
+               handler = DefaultServeMux
+       }
+       rtimeout := srv.getReadTimeout()
+       // deadline is not used here
+       for {
+               rw, err := l.Accept()
+               if err != nil {
+                       if neterr, ok := err.(net.Error); ok && neterr.Temporary() {
+                               continue
+                       }
+                       return err
+               }
+               m, err := reader.ReadTCP(rw, rtimeout)
+               srv.lock.RLock()
+               if !srv.started {
+                       srv.lock.RUnlock()
+                       return nil
+               }
+               srv.lock.RUnlock()
+               if err != nil {
+                       continue
+               }
+               srv.inFlight.Add(1)
+               go srv.serve(rw.RemoteAddr(), handler, m, nil, nil, rw)
+       }
+}
+
+// serveUDP starts a UDP listener for the server.
+// Each request is handled in a separate goroutine.
+func (srv *Server) serveUDP(l *net.UDPConn) error {
+       defer l.Close()
+
+       if srv.NotifyStartedFunc != nil {
+               srv.NotifyStartedFunc()
+       }
+
+       reader := Reader(&defaultReader{srv})
+       if srv.DecorateReader != nil {
+               reader = srv.DecorateReader(reader)
+       }
+
+       handler := srv.Handler
+       if handler == nil {
+               handler = DefaultServeMux
+       }
+       rtimeout := srv.getReadTimeout()
+       // deadline is not used here
+       for {
+               m, s, err := reader.ReadUDP(l, rtimeout)
+               srv.lock.RLock()
+               if !srv.started {
+                       srv.lock.RUnlock()
+                       return nil
+               }
+               srv.lock.RUnlock()
+               if err != nil {
+                       continue
+               }
+               srv.inFlight.Add(1)
+               go srv.serve(s.RemoteAddr(), handler, m, l, s, nil)
+       }
+}
+
+// Serve a new connection.
+func (srv *Server) serve(a net.Addr, h Handler, m []byte, u *net.UDPConn, s *SessionUDP, t net.Conn) {
+       defer srv.inFlight.Done()
+
+       w := &response{tsigSecret: srv.TsigSecret, udp: u, tcp: t, remoteAddr: a, udpSession: s}
+       if srv.DecorateWriter != nil {
+               w.writer = srv.DecorateWriter(w)
+       } else {
+               w.writer = w
+       }
+
+       q := 0 // counter for the amount of TCP queries we get
+
+       reader := Reader(&defaultReader{srv})
+       if srv.DecorateReader != nil {
+               reader = srv.DecorateReader(reader)
+       }
+Redo:
+       req := new(Msg)
+       err := req.Unpack(m)
+       if err != nil { // Send a FormatError back
+               x := new(Msg)
+               x.SetRcodeFormatError(req)
+               w.WriteMsg(x)
+               goto Exit
+       }
+       if !srv.Unsafe && req.Response {
+               goto Exit
+       }
+
+       w.tsigStatus = nil
+       if w.tsigSecret != nil {
+               if t := req.IsTsig(); t != nil {
+                       secret := t.Hdr.Name
+                       if _, ok := w.tsigSecret[secret]; !ok {
+                               w.tsigStatus = ErrKeyAlg
+                       }
+                       w.tsigStatus = TsigVerify(m, w.tsigSecret[secret], "", false)
+                       w.tsigTimersOnly = false
+                       w.tsigRequestMAC = req.Extra[len(req.Extra)-1].(*TSIG).MAC
+               }
+       }
+       h.ServeDNS(w, req) // Writes back to the client
+
+Exit:
+       if w.tcp == nil {
+               return
+       }
+       // TODO(miek): make this number configurable?
+       if q > maxTCPQueries { // close socket after this many queries
+               w.Close()
+               return
+       }
+
+       if w.hijacked {
+               return // client calls Close()
+       }
+       if u != nil { // UDP, "close" and return
+               w.Close()
+               return
+       }
+       idleTimeout := tcpIdleTimeout
+       if srv.IdleTimeout != nil {
+               idleTimeout = srv.IdleTimeout()
+       }
+       m, err = reader.ReadTCP(w.tcp, idleTimeout)
+       if err == nil {
+               q++
+               goto Redo
+       }
+       w.Close()
+       return
+}
+
+func (srv *Server) readTCP(conn net.Conn, timeout time.Duration) ([]byte, error) {
+       conn.SetReadDeadline(time.Now().Add(timeout))
+       l := make([]byte, 2)
+       n, err := conn.Read(l)
+       if err != nil || n != 2 {
+               if err != nil {
+                       return nil, err
+               }
+               return nil, ErrShortRead
+       }
+       length := binary.BigEndian.Uint16(l)
+       if length == 0 {
+               return nil, ErrShortRead
+       }
+       m := make([]byte, int(length))
+       n, err = conn.Read(m[:int(length)])
+       if err != nil || n == 0 {
+               if err != nil {
+                       return nil, err
+               }
+               return nil, ErrShortRead
+       }
+       i := n
+       for i < int(length) {
+               j, err := conn.Read(m[i:int(length)])
+               if err != nil {
+                       return nil, err
+               }
+               i += j
+       }
+       n = i
+       m = m[:n]
+       return m, nil
+}
+
+func (srv *Server) readUDP(conn *net.UDPConn, timeout time.Duration) ([]byte, *SessionUDP, error) {
+       conn.SetReadDeadline(time.Now().Add(timeout))
+       m := make([]byte, srv.UDPSize)
+       n, s, err := ReadFromSessionUDP(conn, m)
+       if err != nil || n == 0 {
+               if err != nil {
+                       return nil, nil, err
+               }
+               return nil, nil, ErrShortRead
+       }
+       m = m[:n]
+       return m, s, nil
+}
+
+// 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 {
+                       data, w.tsigRequestMAC, err = TsigGenerate(m, w.tsigSecret[t.Hdr.Name], w.tsigRequestMAC, w.tsigTimersOnly)
+                       if err != nil {
+                               return err
+                       }
+                       _, err = w.writer.Write(data)
+                       return err
+               }
+       }
+       data, err = m.Pack()
+       if err != nil {
+               return err
+       }
+       _, err = w.writer.Write(data)
+       return err
+}
+
+// Write implements the ResponseWriter.Write method.
+func (w *response) Write(m []byte) (int, error) {
+       switch {
+       case w.udp != nil:
+               n, err := WriteToSessionUDP(w.udp, m, w.udpSession)
+               return n, err
+       case w.tcp != nil:
+               lm := len(m)
+               if lm < 2 {
+                       return 0, io.ErrShortBuffer
+               }
+               if lm > MaxMsgSize {
+                       return 0, &Error{err: "message too large"}
+               }
+               l := make([]byte, 2, 2+lm)
+               binary.BigEndian.PutUint16(l, uint16(lm))
+               m = append(l, m...)
+
+               n, err := io.Copy(w.tcp, bytes.NewReader(m))
+               return int(n), err
+       }
+       panic("not reached")
+}
+
+// LocalAddr implements the ResponseWriter.LocalAddr method.
+func (w *response) LocalAddr() net.Addr {
+       if w.tcp != nil {
+               return w.tcp.LocalAddr()
+       }
+       return w.udp.LocalAddr()
+}
+
+// RemoteAddr implements the ResponseWriter.RemoteAddr method.
+func (w *response) RemoteAddr() net.Addr { return w.remoteAddr }
+
+// TsigStatus implements the ResponseWriter.TsigStatus method.
+func (w *response) TsigStatus() error { return w.tsigStatus }
+
+// TsigTimersOnly implements the ResponseWriter.TsigTimersOnly method.
+func (w *response) TsigTimersOnly(b bool) { w.tsigTimersOnly = b }
+
+// Hijack implements the ResponseWriter.Hijack method.
+func (w *response) Hijack() { w.hijacked = true }
+
+// Close implements the ResponseWriter.Close method
+func (w *response) Close() error {
+       // Can't close the udp conn, as that is actually the listener.
+       if w.tcp != nil {
+               e := w.tcp.Close()
+               w.tcp = nil
+               return e
+       }
+       return nil
+}
diff --git a/vendor/github.com/miekg/dns/sig0.go b/vendor/github.com/miekg/dns/sig0.go
new file mode 100644 (file)
index 0000000..2dce06a
--- /dev/null
@@ -0,0 +1,219 @@
+package dns
+
+import (
+       "crypto"
+       "crypto/dsa"
+       "crypto/ecdsa"
+       "crypto/rsa"
+       "encoding/binary"
+       "math/big"
+       "strings"
+       "time"
+)
+
+// Sign signs a dns.Msg. It fills the signature with the appropriate data.
+// The SIG record should have the SignerName, KeyTag, Algorithm, Inception
+// and Expiration set.
+func (rr *SIG) Sign(k crypto.Signer, m *Msg) ([]byte, error) {
+       if k == nil {
+               return nil, ErrPrivKey
+       }
+       if rr.KeyTag == 0 || len(rr.SignerName) == 0 || rr.Algorithm == 0 {
+               return nil, ErrKey
+       }
+       rr.Header().Rrtype = TypeSIG
+       rr.Header().Class = ClassANY
+       rr.Header().Ttl = 0
+       rr.Header().Name = "."
+       rr.OrigTtl = 0
+       rr.TypeCovered = 0
+       rr.Labels = 0
+
+       buf := make([]byte, m.Len()+rr.len())
+       mbuf, err := m.PackBuffer(buf)
+       if err != nil {
+               return nil, err
+       }
+       if &buf[0] != &mbuf[0] {
+               return nil, ErrBuf
+       }
+       off, err := PackRR(rr, buf, len(mbuf), nil, false)
+       if err != nil {
+               return nil, err
+       }
+       buf = buf[:off:cap(buf)]
+
+       hash, ok := AlgorithmToHash[rr.Algorithm]
+       if !ok {
+               return nil, ErrAlg
+       }
+
+       hasher := hash.New()
+       // Write SIG rdata
+       hasher.Write(buf[len(mbuf)+1+2+2+4+2:])
+       // Write message
+       hasher.Write(buf[:len(mbuf)])
+
+       signature, err := sign(k, hasher.Sum(nil), hash, rr.Algorithm)
+       if err != nil {
+               return nil, err
+       }
+
+       rr.Signature = toBase64(signature)
+       sig := string(signature)
+
+       buf = append(buf, sig...)
+       if len(buf) > int(^uint16(0)) {
+               return nil, ErrBuf
+       }
+       // Adjust sig data length
+       rdoff := len(mbuf) + 1 + 2 + 2 + 4
+       rdlen := binary.BigEndian.Uint16(buf[rdoff:])
+       rdlen += uint16(len(sig))
+       binary.BigEndian.PutUint16(buf[rdoff:], rdlen)
+       // Adjust additional count
+       adc := binary.BigEndian.Uint16(buf[10:])
+       adc++
+       binary.BigEndian.PutUint16(buf[10:], adc)
+       return buf, nil
+}
+
+// Verify validates the message buf using the key k.
+// It's assumed that buf is a valid message from which rr was unpacked.
+func (rr *SIG) Verify(k *KEY, buf []byte) error {
+       if k == nil {
+               return ErrKey
+       }
+       if rr.KeyTag == 0 || len(rr.SignerName) == 0 || rr.Algorithm == 0 {
+               return ErrKey
+       }
+
+       var hash crypto.Hash
+       switch rr.Algorithm {
+       case DSA, RSASHA1:
+               hash = crypto.SHA1
+       case RSASHA256, ECDSAP256SHA256:
+               hash = crypto.SHA256
+       case ECDSAP384SHA384:
+               hash = crypto.SHA384
+       case RSASHA512:
+               hash = crypto.SHA512
+       default:
+               return ErrAlg
+       }
+       hasher := hash.New()
+
+       buflen := len(buf)
+       qdc := binary.BigEndian.Uint16(buf[4:])
+       anc := binary.BigEndian.Uint16(buf[6:])
+       auc := binary.BigEndian.Uint16(buf[8:])
+       adc := binary.BigEndian.Uint16(buf[10:])
+       offset := 12
+       var err error
+       for i := uint16(0); i < qdc && offset < buflen; i++ {
+               _, offset, err = UnpackDomainName(buf, offset)
+               if err != nil {
+                       return err
+               }
+               // Skip past Type and Class
+               offset += 2 + 2
+       }
+       for i := uint16(1); i < anc+auc+adc && offset < buflen; i++ {
+               _, offset, err = UnpackDomainName(buf, offset)
+               if err != nil {
+                       return err
+               }
+               // Skip past Type, Class and TTL
+               offset += 2 + 2 + 4
+               if offset+1 >= buflen {
+                       continue
+               }
+               var rdlen uint16
+               rdlen = binary.BigEndian.Uint16(buf[offset:])
+               offset += 2
+               offset += int(rdlen)
+       }
+       if offset >= buflen {
+               return &Error{err: "overflowing unpacking signed message"}
+       }
+
+       // offset should be just prior to SIG
+       bodyend := offset
+       // owner name SHOULD be root
+       _, offset, err = UnpackDomainName(buf, offset)
+       if err != nil {
+               return err
+       }
+       // Skip Type, Class, TTL, RDLen
+       offset += 2 + 2 + 4 + 2
+       sigstart := offset
+       // Skip Type Covered, Algorithm, Labels, Original TTL
+       offset += 2 + 1 + 1 + 4
+       if offset+4+4 >= buflen {
+               return &Error{err: "overflow unpacking signed message"}
+       }
+       expire := binary.BigEndian.Uint32(buf[offset:])
+       offset += 4
+       incept := binary.BigEndian.Uint32(buf[offset:])
+       offset += 4
+       now := uint32(time.Now().Unix())
+       if now < incept || now > expire {
+               return ErrTime
+       }
+       // Skip key tag
+       offset += 2
+       var signername string
+       signername, offset, err = UnpackDomainName(buf, offset)
+       if err != nil {
+               return err
+       }
+       // If key has come from the DNS name compression might
+       // have mangled the case of the name
+       if strings.ToLower(signername) != strings.ToLower(k.Header().Name) {
+               return &Error{err: "signer name doesn't match key name"}
+       }
+       sigend := offset
+       hasher.Write(buf[sigstart:sigend])
+       hasher.Write(buf[:10])
+       hasher.Write([]byte{
+               byte((adc - 1) << 8),
+               byte(adc - 1),
+       })
+       hasher.Write(buf[12:bodyend])
+
+       hashed := hasher.Sum(nil)
+       sig := buf[sigend:]
+       switch k.Algorithm {
+       case DSA:
+               pk := k.publicKeyDSA()
+               sig = sig[1:]
+               r := big.NewInt(0)
+               r.SetBytes(sig[:len(sig)/2])
+               s := big.NewInt(0)
+               s.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 {
+                       return rsa.VerifyPKCS1v15(pk, hash, hashed, sig)
+               }
+       case ECDSAP256SHA256, ECDSAP384SHA384:
+               pk := k.publicKeyECDSA()
+               r := big.NewInt(0)
+               r.SetBytes(sig[:len(sig)/2])
+               s := big.NewInt(0)
+               s.SetBytes(sig[len(sig)/2:])
+               if pk != nil {
+                       if ecdsa.Verify(pk, hashed, r, s) {
+                               return nil
+                       }
+                       return ErrSig
+               }
+       }
+       return ErrKeyAlg
+}
diff --git a/vendor/github.com/miekg/dns/singleinflight.go b/vendor/github.com/miekg/dns/singleinflight.go
new file mode 100644 (file)
index 0000000..9573c7d
--- /dev/null
@@ -0,0 +1,57 @@
+// Copyright 2013 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Adapted for dns package usage by Miek Gieben.
+
+package dns
+
+import "sync"
+import "time"
+
+// call is an in-flight or completed singleflight.Do call
+type call struct {
+       wg   sync.WaitGroup
+       val  *Msg
+       rtt  time.Duration
+       err  error
+       dups int
+}
+
+// singleflight represents a class of work and forms a namespace in
+// which units of work can be executed with duplicate suppression.
+type singleflight struct {
+       sync.Mutex                  // protects m
+       m          map[string]*call // lazily initialized
+}
+
+// Do executes and returns the results of the given function, making
+// sure that only one execution is in-flight for a given key at a
+// time. If a duplicate comes in, the duplicate caller waits for the
+// original to complete and receives the same results.
+// The return value shared indicates whether v was given to multiple callers.
+func (g *singleflight) Do(key string, fn func() (*Msg, time.Duration, error)) (v *Msg, rtt time.Duration, err error, shared bool) {
+       g.Lock()
+       if g.m == nil {
+               g.m = make(map[string]*call)
+       }
+       if c, ok := g.m[key]; ok {
+               c.dups++
+               g.Unlock()
+               c.wg.Wait()
+               return c.val, c.rtt, c.err, true
+       }
+       c := new(call)
+       c.wg.Add(1)
+       g.m[key] = c
+       g.Unlock()
+
+       c.val, c.rtt, c.err = fn()
+       c.wg.Done()
+
+       g.Lock()
+       delete(g.m, key)
+       g.Unlock()
+
+       return c.val, c.rtt, c.err, c.dups > 0
+}
diff --git a/vendor/github.com/miekg/dns/tlsa.go b/vendor/github.com/miekg/dns/tlsa.go
new file mode 100644 (file)
index 0000000..34fe661
--- /dev/null
@@ -0,0 +1,86 @@
+package dns
+
+import (
+       "crypto/sha256"
+       "crypto/sha512"
+       "crypto/x509"
+       "encoding/hex"
+       "errors"
+       "io"
+       "net"
+       "strconv"
+)
+
+// CertificateToDANE converts a certificate to a hex string as used in the TLSA record.
+func CertificateToDANE(selector, matchingType uint8, cert *x509.Certificate) (string, error) {
+       switch matchingType {
+       case 0:
+               switch selector {
+               case 0:
+                       return hex.EncodeToString(cert.Raw), nil
+               case 1:
+                       return hex.EncodeToString(cert.RawSubjectPublicKeyInfo), nil
+               }
+       case 1:
+               h := sha256.New()
+               switch selector {
+               case 0:
+                       io.WriteString(h, string(cert.Raw))
+                       return hex.EncodeToString(h.Sum(nil)), nil
+               case 1:
+                       io.WriteString(h, string(cert.RawSubjectPublicKeyInfo))
+                       return hex.EncodeToString(h.Sum(nil)), nil
+               }
+       case 2:
+               h := sha512.New()
+               switch selector {
+               case 0:
+                       io.WriteString(h, string(cert.Raw))
+                       return hex.EncodeToString(h.Sum(nil)), nil
+               case 1:
+                       io.WriteString(h, string(cert.RawSubjectPublicKeyInfo))
+                       return hex.EncodeToString(h.Sum(nil)), nil
+               }
+       }
+       return "", errors.New("dns: bad TLSA MatchingType or TLSA Selector")
+}
+
+// Sign creates a TLSA record from an SSL certificate.
+func (r *TLSA) Sign(usage, selector, matchingType int, cert *x509.Certificate) (err error) {
+       r.Hdr.Rrtype = TypeTLSA
+       r.Usage = uint8(usage)
+       r.Selector = uint8(selector)
+       r.MatchingType = uint8(matchingType)
+
+       r.Certificate, err = CertificateToDANE(r.Selector, r.MatchingType, cert)
+       if err != nil {
+               return err
+       }
+       return nil
+}
+
+// Verify verifies a TLSA record against an SSL certificate. If it is OK
+// a nil error is returned.
+func (r *TLSA) Verify(cert *x509.Certificate) error {
+       c, err := CertificateToDANE(r.Selector, r.MatchingType, cert)
+       if err != nil {
+               return err // Not also ErrSig?
+       }
+       if r.Certificate == c {
+               return nil
+       }
+       return ErrSig // ErrSig, really?
+}
+
+// TLSAName returns the ownername of a TLSA resource record as per the
+// rules specified in RFC 6698, Section 3.
+func TLSAName(name, service, network string) (string, error) {
+       if !IsFqdn(name) {
+               return "", ErrFqdn
+       }
+       p, err := net.LookupPort(network, service)
+       if err != nil {
+               return "", err
+       }
+       return "_" + strconv.Itoa(p) + "._" + network + "." + name, nil
+}
diff --git a/vendor/github.com/miekg/dns/tsig.go b/vendor/github.com/miekg/dns/tsig.go
new file mode 100644 (file)
index 0000000..78365e1
--- /dev/null
@@ -0,0 +1,384 @@
+package dns
+
+import (
+       "crypto/hmac"
+       "crypto/md5"
+       "crypto/sha1"
+       "crypto/sha256"
+       "crypto/sha512"
+       "encoding/binary"
+       "encoding/hex"
+       "hash"
+       "io"
+       "strconv"
+       "strings"
+       "time"
+)
+
+// HMAC hashing codes. These are transmitted as domain names.
+const (
+       HmacMD5    = "hmac-md5.sig-alg.reg.int."
+       HmacSHA1   = "hmac-sha1."
+       HmacSHA256 = "hmac-sha256."
+       HmacSHA512 = "hmac-sha512."
+)
+
+// TSIG is the RR the holds the transaction signature of a message.
+// See RFC 2845 and RFC 4635.
+type TSIG struct {
+       Hdr        RR_Header
+       Algorithm  string `dns:"domain-name"`
+       TimeSigned uint64 `dns:"uint48"`
+       Fudge      uint16
+       MACSize    uint16
+       MAC        string `dns:"size-hex:MACSize"`
+       OrigId     uint16
+       Error      uint16
+       OtherLen   uint16
+       OtherData  string `dns:"size-hex:OtherLen"`
+}
+
+// TSIG has no official presentation format, but this will suffice.
+
+func (rr *TSIG) String() string {
+       s := "\n;; TSIG PSEUDOSECTION:\n"
+       s += rr.Hdr.String() +
+               " " + rr.Algorithm +
+               " " + tsigTimeToString(rr.TimeSigned) +
+               " " + strconv.Itoa(int(rr.Fudge)) +
+               " " + strconv.Itoa(int(rr.MACSize)) +
+               " " + strings.ToUpper(rr.MAC) +
+               " " + strconv.Itoa(int(rr.OrigId)) +
+               " " + strconv.Itoa(int(rr.Error)) + // BIND prints NOERROR
+               " " + strconv.Itoa(int(rr.OtherLen)) +
+               " " + rr.OtherData
+       return s
+}
+
+// The following values must be put in wireformat, so that the MAC can be calculated.
+// RFC 2845, section 3.4.2. TSIG Variables.
+type tsigWireFmt struct {
+       // From RR_Header
+       Name  string `dns:"domain-name"`
+       Class uint16
+       Ttl   uint32
+       // Rdata of the TSIG
+       Algorithm  string `dns:"domain-name"`
+       TimeSigned uint64 `dns:"uint48"`
+       Fudge      uint16
+       // MACSize, MAC and OrigId excluded
+       Error     uint16
+       OtherLen  uint16
+       OtherData string `dns:"size-hex:OtherLen"`
+}
+
+// If we have the MAC use this type to convert it to wiredata. Section 3.4.3. Request MAC
+type macWireFmt struct {
+       MACSize uint16
+       MAC     string `dns:"size-hex:MACSize"`
+}
+
+// 3.3. Time values used in TSIG calculations
+type timerWireFmt struct {
+       TimeSigned uint64 `dns:"uint48"`
+       Fudge      uint16
+}
+
+// TsigGenerate fills out the TSIG record attached to the message.
+// The message should contain
+// a "stub" TSIG RR with the algorithm, key name (owner name of the RR),
+// time fudge (defaults to 300 seconds) and the current time
+// The TSIG MAC is saved in that Tsig RR.
+// When TsigGenerate is called for the first time requestMAC is set to the empty string and
+// timersOnly is false.
+// If something goes wrong an error is returned, otherwise it is nil.
+func TsigGenerate(m *Msg, secret, requestMAC string, timersOnly bool) ([]byte, string, error) {
+       if m.IsTsig() == nil {
+               panic("dns: TSIG not last RR in additional")
+       }
+       // If we barf here, the caller is to blame
+       rawsecret, err := fromBase64([]byte(secret))
+       if err != nil {
+               return nil, "", err
+       }
+
+       rr := m.Extra[len(m.Extra)-1].(*TSIG)
+       m.Extra = m.Extra[0 : len(m.Extra)-1] // kill the TSIG from the msg
+       mbuf, err := m.Pack()
+       if err != nil {
+               return nil, "", err
+       }
+       buf := tsigBuffer(mbuf, rr, requestMAC, timersOnly)
+
+       t := new(TSIG)
+       var h hash.Hash
+       switch strings.ToLower(rr.Algorithm) {
+       case HmacMD5:
+               h = hmac.New(md5.New, []byte(rawsecret))
+       case HmacSHA1:
+               h = hmac.New(sha1.New, []byte(rawsecret))
+       case HmacSHA256:
+               h = hmac.New(sha256.New, []byte(rawsecret))
+       case HmacSHA512:
+               h = hmac.New(sha512.New, []byte(rawsecret))
+       default:
+               return nil, "", ErrKeyAlg
+       }
+       io.WriteString(h, string(buf))
+       t.MAC = hex.EncodeToString(h.Sum(nil))
+       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.Fudge = rr.Fudge
+       t.TimeSigned = rr.TimeSigned
+       t.Algorithm = rr.Algorithm
+       t.OrigId = m.Id
+
+       tbuf := make([]byte, t.len())
+       if off, err := PackRR(t, tbuf, 0, nil, false); err == nil {
+               tbuf = tbuf[:off] // reset to actual size used
+       } else {
+               return nil, "", err
+       }
+       mbuf = append(mbuf, tbuf...)
+       // Update the ArCount directly in the buffer.
+       binary.BigEndian.PutUint16(mbuf[10:], uint16(len(m.Extra)+1))
+
+       return mbuf, t.MAC, nil
+}
+
+// TsigVerify verifies the TSIG on a message.
+// If the signature does not validate err contains the
+// error, otherwise it is nil.
+func TsigVerify(msg []byte, secret, requestMAC string, timersOnly bool) error {
+       rawsecret, err := fromBase64([]byte(secret))
+       if err != nil {
+               return err
+       }
+       // Strip the TSIG from the incoming msg
+       stripped, tsig, err := stripTsig(msg)
+       if err != nil {
+               return err
+       }
+
+       msgMAC, err := hex.DecodeString(tsig.MAC)
+       if err != nil {
+               return err
+       }
+
+       buf := tsigBuffer(stripped, tsig, requestMAC, timersOnly)
+
+       // Fudge factor works both ways. A message can arrive before it was signed because
+       // of clock skew.
+       now := uint64(time.Now().Unix())
+       ti := now - tsig.TimeSigned
+       if now < tsig.TimeSigned {
+               ti = tsig.TimeSigned - now
+       }
+       if uint64(tsig.Fudge) < ti {
+               return ErrTime
+       }
+
+       var h hash.Hash
+       switch strings.ToLower(tsig.Algorithm) {
+       case HmacMD5:
+               h = hmac.New(md5.New, rawsecret)
+       case HmacSHA1:
+               h = hmac.New(sha1.New, rawsecret)
+       case HmacSHA256:
+               h = hmac.New(sha256.New, rawsecret)
+       case HmacSHA512:
+               h = hmac.New(sha512.New, rawsecret)
+       default:
+               return ErrKeyAlg
+       }
+       h.Write(buf)
+       if !hmac.Equal(h.Sum(nil), msgMAC) {
+               return ErrSig
+       }
+       return nil
+}
+
+// Create a wiredata buffer for the MAC calculation.
+func tsigBuffer(msgbuf []byte, rr *TSIG, requestMAC string, timersOnly bool) []byte {
+       var buf []byte
+       if rr.TimeSigned == 0 {
+               rr.TimeSigned = uint64(time.Now().Unix())
+       }
+       if rr.Fudge == 0 {
+               rr.Fudge = 300 // Standard (RFC) default.
+       }
+
+       if requestMAC != "" {
+               m := new(macWireFmt)
+               m.MACSize = uint16(len(requestMAC) / 2)
+               m.MAC = requestMAC
+               buf = make([]byte, len(requestMAC)) // long enough
+               n, _ := packMacWire(m, buf)
+               buf = buf[:n]
+       }
+
+       tsigvar := make([]byte, DefaultMsgSize)
+       if timersOnly {
+               tsig := new(timerWireFmt)
+               tsig.TimeSigned = rr.TimeSigned
+               tsig.Fudge = rr.Fudge
+               n, _ := packTimerWire(tsig, tsigvar)
+               tsigvar = tsigvar[:n]
+       } else {
+               tsig := new(tsigWireFmt)
+               tsig.Name = strings.ToLower(rr.Hdr.Name)
+               tsig.Class = ClassANY
+               tsig.Ttl = rr.Hdr.Ttl
+               tsig.Algorithm = strings.ToLower(rr.Algorithm)
+               tsig.TimeSigned = rr.TimeSigned
+               tsig.Fudge = rr.Fudge
+               tsig.Error = rr.Error
+               tsig.OtherLen = rr.OtherLen
+               tsig.OtherData = rr.OtherData
+               n, _ := packTsigWire(tsig, tsigvar)
+               tsigvar = tsigvar[:n]
+       }
+
+       if requestMAC != "" {
+               x := append(buf, msgbuf...)
+               buf = append(x, tsigvar...)
+       } else {
+               buf = append(msgbuf, tsigvar...)
+       }
+       return buf
+}
+
+// Strip the TSIG from the raw message.
+func stripTsig(msg []byte) ([]byte, *TSIG, error) {
+       // Copied from msg.go's Unpack() Header, but modified.
+       var (
+               dh  Header
+               err error
+       )
+       off, tsigoff := 0, 0
+
+       if dh, off, err = unpackMsgHdr(msg, off); err != nil {
+               return nil, nil, err
+       }
+       if dh.Arcount == 0 {
+               return nil, nil, ErrNoSig
+       }
+
+       // Rcode, see msg.go Unpack()
+       if int(dh.Bits&0xF) == RcodeNotAuth {
+               return nil, nil, ErrAuth
+       }
+
+       for i := 0; i < int(dh.Qdcount); i++ {
+               _, off, err = unpackQuestion(msg, off)
+               if err != nil {
+                       return nil, nil, err
+               }
+       }
+
+       _, off, err = unpackRRslice(int(dh.Ancount), msg, off)
+       if err != nil {
+               return nil, nil, err
+       }
+       _, off, err = unpackRRslice(int(dh.Nscount), msg, off)
+       if err != nil {
+               return nil, nil, err
+       }
+
+       rr := new(TSIG)
+       var extra RR
+       for i := 0; i < int(dh.Arcount); i++ {
+               tsigoff = off
+               extra, off, err = UnpackRR(msg, off)
+               if err != nil {
+                       return nil, nil, err
+               }
+               if extra.Header().Rrtype == TypeTSIG {
+                       rr = extra.(*TSIG)
+                       // Adjust Arcount.
+                       arcount := binary.BigEndian.Uint16(msg[10:])
+                       binary.BigEndian.PutUint16(msg[10:], arcount-1)
+                       break
+               }
+       }
+       if rr == nil {
+               return nil, nil, ErrNoSig
+       }
+       return msg[:tsigoff], rr, nil
+}
+
+// Translate the TSIG time signed into a date. There is no
+// need for RFC1982 calculations as this date is 48 bits.
+func tsigTimeToString(t uint64) string {
+       ti := time.Unix(int64(t), 0).UTC()
+       return ti.Format("20060102150405")
+}
+
+func packTsigWire(tw *tsigWireFmt, msg []byte) (int, error) {
+       // copied from zmsg.go TSIG packing
+       // RR_Header
+       off, err := PackDomainName(tw.Name, msg, 0, nil, false)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint16(tw.Class, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint32(tw.Ttl, msg, off)
+       if err != nil {
+               return off, err
+       }
+
+       off, err = PackDomainName(tw.Algorithm, msg, off, nil, false)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint48(tw.TimeSigned, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint16(tw.Fudge, msg, off)
+       if err != nil {
+               return off, err
+       }
+
+       off, err = packUint16(tw.Error, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint16(tw.OtherLen, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packStringHex(tw.OtherData, msg, off)
+       if err != nil {
+               return off, err
+       }
+       return off, nil
+}
+
+func packMacWire(mw *macWireFmt, msg []byte) (int, error) {
+       off, err := packUint16(mw.MACSize, msg, 0)
+       if err != nil {
+               return off, err
+       }
+       off, err = packStringHex(mw.MAC, msg, off)
+       if err != nil {
+               return off, err
+       }
+       return off, nil
+}
+
+func packTimerWire(tw *timerWireFmt, msg []byte) (int, error) {
+       off, err := packUint48(tw.TimeSigned, msg, 0)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint16(tw.Fudge, msg, off)
+       if err != nil {
+               return off, err
+       }
+       return off, nil
+}
diff --git a/vendor/github.com/miekg/dns/types.go b/vendor/github.com/miekg/dns/types.go
new file mode 100644 (file)
index 0000000..e737064
--- /dev/null
@@ -0,0 +1,1250 @@
+package dns
+
+import (
+       "fmt"
+       "net"
+       "strconv"
+       "strings"
+       "time"
+)
+
+type (
+       // Type is a DNS type.
+       Type uint16
+       // Class is a DNS class.
+       Class uint16
+       // Name is a DNS domain name.
+       Name string
+)
+
+// Packet formats
+
+// Wire constants and supported types.
+const (
+       // valid RR_Header.Rrtype and Question.qtype
+
+       TypeNone       uint16 = 0
+       TypeA          uint16 = 1
+       TypeNS         uint16 = 2
+       TypeMD         uint16 = 3
+       TypeMF         uint16 = 4
+       TypeCNAME      uint16 = 5
+       TypeSOA        uint16 = 6
+       TypeMB         uint16 = 7
+       TypeMG         uint16 = 8
+       TypeMR         uint16 = 9
+       TypeNULL       uint16 = 10
+       TypePTR        uint16 = 12
+       TypeHINFO      uint16 = 13
+       TypeMINFO      uint16 = 14
+       TypeMX         uint16 = 15
+       TypeTXT        uint16 = 16
+       TypeRP         uint16 = 17
+       TypeAFSDB      uint16 = 18
+       TypeX25        uint16 = 19
+       TypeISDN       uint16 = 20
+       TypeRT         uint16 = 21
+       TypeNSAPPTR    uint16 = 23
+       TypeSIG        uint16 = 24
+       TypeKEY        uint16 = 25
+       TypePX         uint16 = 26
+       TypeGPOS       uint16 = 27
+       TypeAAAA       uint16 = 28
+       TypeLOC        uint16 = 29
+       TypeNXT        uint16 = 30
+       TypeEID        uint16 = 31
+       TypeNIMLOC     uint16 = 32
+       TypeSRV        uint16 = 33
+       TypeATMA       uint16 = 34
+       TypeNAPTR      uint16 = 35
+       TypeKX         uint16 = 36
+       TypeCERT       uint16 = 37
+       TypeDNAME      uint16 = 39
+       TypeOPT        uint16 = 41 // EDNS
+       TypeDS         uint16 = 43
+       TypeSSHFP      uint16 = 44
+       TypeRRSIG      uint16 = 46
+       TypeNSEC       uint16 = 47
+       TypeDNSKEY     uint16 = 48
+       TypeDHCID      uint16 = 49
+       TypeNSEC3      uint16 = 50
+       TypeNSEC3PARAM uint16 = 51
+       TypeTLSA       uint16 = 52
+       TypeHIP        uint16 = 55
+       TypeNINFO      uint16 = 56
+       TypeRKEY       uint16 = 57
+       TypeTALINK     uint16 = 58
+       TypeCDS        uint16 = 59
+       TypeCDNSKEY    uint16 = 60
+       TypeOPENPGPKEY uint16 = 61
+       TypeSPF        uint16 = 99
+       TypeUINFO      uint16 = 100
+       TypeUID        uint16 = 101
+       TypeGID        uint16 = 102
+       TypeUNSPEC     uint16 = 103
+       TypeNID        uint16 = 104
+       TypeL32        uint16 = 105
+       TypeL64        uint16 = 106
+       TypeLP         uint16 = 107
+       TypeEUI48      uint16 = 108
+       TypeEUI64      uint16 = 109
+       TypeURI        uint16 = 256
+       TypeCAA        uint16 = 257
+
+       TypeTKEY uint16 = 249
+       TypeTSIG uint16 = 250
+
+       // valid Question.Qtype only
+       TypeIXFR  uint16 = 251
+       TypeAXFR  uint16 = 252
+       TypeMAILB uint16 = 253
+       TypeMAILA uint16 = 254
+       TypeANY   uint16 = 255
+
+       TypeTA       uint16 = 32768
+       TypeDLV      uint16 = 32769
+       TypeReserved uint16 = 65535
+
+       // valid Question.Qclass
+       ClassINET   = 1
+       ClassCSNET  = 2
+       ClassCHAOS  = 3
+       ClassHESIOD = 4
+       ClassNONE   = 254
+       ClassANY    = 255
+
+       // Message Response Codes.
+       RcodeSuccess        = 0
+       RcodeFormatError    = 1
+       RcodeServerFailure  = 2
+       RcodeNameError      = 3
+       RcodeNotImplemented = 4
+       RcodeRefused        = 5
+       RcodeYXDomain       = 6
+       RcodeYXRrset        = 7
+       RcodeNXRrset        = 8
+       RcodeNotAuth        = 9
+       RcodeNotZone        = 10
+       RcodeBadSig         = 16 // TSIG
+       RcodeBadVers        = 16 // EDNS0
+       RcodeBadKey         = 17
+       RcodeBadTime        = 18
+       RcodeBadMode        = 19 // TKEY
+       RcodeBadName        = 20
+       RcodeBadAlg         = 21
+       RcodeBadTrunc       = 22 // TSIG
+       RcodeBadCookie      = 23 // DNS Cookies
+
+       // Message Opcodes. There is no 3.
+       OpcodeQuery  = 0
+       OpcodeIQuery = 1
+       OpcodeStatus = 2
+       OpcodeNotify = 4
+       OpcodeUpdate = 5
+)
+
+// Headers is the wire format for the DNS packet header.
+type Header struct {
+       Id                                 uint16
+       Bits                               uint16
+       Qdcount, Ancount, Nscount, Arcount uint16
+}
+
+const (
+       headerSize = 12
+
+       // Header.Bits
+       _QR = 1 << 15 // query/response (response=1)
+       _AA = 1 << 10 // authoritative
+       _TC = 1 << 9  // truncated
+       _RD = 1 << 8  // recursion desired
+       _RA = 1 << 7  // recursion available
+       _Z  = 1 << 6  // Z
+       _AD = 1 << 5  // authticated data
+       _CD = 1 << 4  // checking disabled
+
+       LOC_EQUATOR       = 1 << 31 // RFC 1876, Section 2.
+       LOC_PRIMEMERIDIAN = 1 << 31 // RFC 1876, Section 2.
+
+       LOC_HOURS   = 60 * 1000
+       LOC_DEGREES = 60 * LOC_HOURS
+
+       LOC_ALTITUDEBASE = 100000
+)
+
+// Different Certificate Types, see RFC 4398, Section 2.1
+const (
+       CertPKIX = 1 + iota
+       CertSPKI
+       CertPGP
+       CertIPIX
+       CertISPKI
+       CertIPGP
+       CertACPKIX
+       CertIACPKIX
+       CertURI = 253
+       CertOID = 254
+)
+
+// CertTypeToString converts the Cert Type to its string representation.
+// See RFC 4398 and RFC 6944.
+var CertTypeToString = map[uint16]string{
+       CertPKIX:    "PKIX",
+       CertSPKI:    "SPKI",
+       CertPGP:     "PGP",
+       CertIPIX:    "IPIX",
+       CertISPKI:   "ISPKI",
+       CertIPGP:    "IPGP",
+       CertACPKIX:  "ACPKIX",
+       CertIACPKIX: "IACPKIX",
+       CertURI:     "URI",
+       CertOID:     "OID",
+}
+
+// StringToCertType is the reverseof CertTypeToString.
+var StringToCertType = reverseInt16(CertTypeToString)
+
+//go:generate go run types_generate.go
+
+// Question holds a DNS question. There can be multiple questions in the
+// question section of a message. Usually there is just one.
+type Question struct {
+       Name   string `dns:"cdomain-name"` // "cdomain-name" specifies encoding (and may be compressed)
+       Qtype  uint16
+       Qclass uint16
+}
+
+func (q *Question) len() int {
+       return len(q.Name) + 1 + 2 + 2
+}
+
+func (q *Question) String() (s string) {
+       // prefix with ; (as in dig)
+       s = ";" + sprintName(q.Name) + "\t"
+       s += Class(q.Qclass).String() + "\t"
+       s += " " + Type(q.Qtype).String()
+       return s
+}
+
+// ANY is a wildcard record. See RFC 1035, Section 3.2.3. ANY
+// is named "*" there.
+type ANY struct {
+       Hdr RR_Header
+       // Does not have any rdata
+}
+
+func (rr *ANY) String() string { return rr.Hdr.String() }
+
+type CNAME struct {
+       Hdr    RR_Header
+       Target string `dns:"cdomain-name"`
+}
+
+func (rr *CNAME) String() string { return rr.Hdr.String() + sprintName(rr.Target) }
+
+type HINFO struct {
+       Hdr RR_Header
+       Cpu string
+       Os  string
+}
+
+func (rr *HINFO) String() string {
+       return rr.Hdr.String() + sprintTxt([]string{rr.Cpu, rr.Os})
+}
+
+type MB struct {
+       Hdr RR_Header
+       Mb  string `dns:"cdomain-name"`
+}
+
+func (rr *MB) String() string { return rr.Hdr.String() + sprintName(rr.Mb) }
+
+type MG struct {
+       Hdr RR_Header
+       Mg  string `dns:"cdomain-name"`
+}
+
+func (rr *MG) String() string { return rr.Hdr.String() + sprintName(rr.Mg) }
+
+type MINFO struct {
+       Hdr   RR_Header
+       Rmail string `dns:"cdomain-name"`
+       Email string `dns:"cdomain-name"`
+}
+
+func (rr *MINFO) String() string {
+       return rr.Hdr.String() + sprintName(rr.Rmail) + " " + sprintName(rr.Email)
+}
+
+type MR struct {
+       Hdr RR_Header
+       Mr  string `dns:"cdomain-name"`
+}
+
+func (rr *MR) String() string {
+       return rr.Hdr.String() + sprintName(rr.Mr)
+}
+
+type MF struct {
+       Hdr RR_Header
+       Mf  string `dns:"cdomain-name"`
+}
+
+func (rr *MF) String() string {
+       return rr.Hdr.String() + sprintName(rr.Mf)
+}
+
+type MD struct {
+       Hdr RR_Header
+       Md  string `dns:"cdomain-name"`
+}
+
+func (rr *MD) String() string {
+       return rr.Hdr.String() + sprintName(rr.Md)
+}
+
+type MX struct {
+       Hdr        RR_Header
+       Preference uint16
+       Mx         string `dns:"cdomain-name"`
+}
+
+func (rr *MX) String() string {
+       return rr.Hdr.String() + strconv.Itoa(int(rr.Preference)) + " " + sprintName(rr.Mx)
+}
+
+type AFSDB struct {
+       Hdr      RR_Header
+       Subtype  uint16
+       Hostname string `dns:"cdomain-name"`
+}
+
+func (rr *AFSDB) String() string {
+       return rr.Hdr.String() + strconv.Itoa(int(rr.Subtype)) + " " + sprintName(rr.Hostname)
+}
+
+type X25 struct {
+       Hdr         RR_Header
+       PSDNAddress string
+}
+
+func (rr *X25) String() string {
+       return rr.Hdr.String() + rr.PSDNAddress
+}
+
+type RT struct {
+       Hdr        RR_Header
+       Preference uint16
+       Host       string `dns:"cdomain-name"`
+}
+
+func (rr *RT) String() string {
+       return rr.Hdr.String() + strconv.Itoa(int(rr.Preference)) + " " + sprintName(rr.Host)
+}
+
+type NS struct {
+       Hdr RR_Header
+       Ns  string `dns:"cdomain-name"`
+}
+
+func (rr *NS) String() string {
+       return rr.Hdr.String() + sprintName(rr.Ns)
+}
+
+type PTR struct {
+       Hdr RR_Header
+       Ptr string `dns:"cdomain-name"`
+}
+
+func (rr *PTR) String() string {
+       return rr.Hdr.String() + sprintName(rr.Ptr)
+}
+
+type RP struct {
+       Hdr  RR_Header
+       Mbox string `dns:"domain-name"`
+       Txt  string `dns:"domain-name"`
+}
+
+func (rr *RP) String() string {
+       return rr.Hdr.String() + rr.Mbox + " " + sprintTxt([]string{rr.Txt})
+}
+
+type SOA struct {
+       Hdr     RR_Header
+       Ns      string `dns:"cdomain-name"`
+       Mbox    string `dns:"cdomain-name"`
+       Serial  uint32
+       Refresh uint32
+       Retry   uint32
+       Expire  uint32
+       Minttl  uint32
+}
+
+func (rr *SOA) String() string {
+       return rr.Hdr.String() + sprintName(rr.Ns) + " " + sprintName(rr.Mbox) +
+               " " + strconv.FormatInt(int64(rr.Serial), 10) +
+               " " + strconv.FormatInt(int64(rr.Refresh), 10) +
+               " " + strconv.FormatInt(int64(rr.Retry), 10) +
+               " " + strconv.FormatInt(int64(rr.Expire), 10) +
+               " " + strconv.FormatInt(int64(rr.Minttl), 10)
+}
+
+type TXT struct {
+       Hdr RR_Header
+       Txt []string `dns:"txt"`
+}
+
+func (rr *TXT) String() string { return rr.Hdr.String() + sprintTxt(rr.Txt) }
+
+func sprintName(s string) string {
+       src := []byte(s)
+       dst := make([]byte, 0, len(src))
+       for i := 0; i < len(src); {
+               if i+1 < len(src) && src[i] == '\\' && src[i+1] == '.' {
+                       dst = append(dst, src[i:i+2]...)
+                       i += 2
+               } else {
+                       b, n := nextByte(src, i)
+                       if n == 0 {
+                               i++ // dangling back slash
+                       } else if b == '.' {
+                               dst = append(dst, b)
+                       } else {
+                               dst = appendDomainNameByte(dst, b)
+                       }
+                       i += n
+               }
+       }
+       return string(dst)
+}
+
+func sprintTxtOctet(s string) string {
+       src := []byte(s)
+       dst := make([]byte, 0, len(src))
+       dst = append(dst, '"')
+       for i := 0; i < len(src); {
+               if i+1 < len(src) && src[i] == '\\' && src[i+1] == '.' {
+                       dst = append(dst, src[i:i+2]...)
+                       i += 2
+               } else {
+                       b, n := nextByte(src, i)
+                       if n == 0 {
+                               i++ // dangling back slash
+                       } else if b == '.' {
+                               dst = append(dst, b)
+                       } else {
+                               if b < ' ' || b > '~' {
+                                       dst = appendByte(dst, b)
+                               } else {
+                                       dst = append(dst, b)
+                               }
+                       }
+                       i += n
+               }
+       }
+       dst = append(dst, '"')
+       return string(dst)
+}
+
+func sprintTxt(txt []string) string {
+       var out []byte
+       for i, s := range txt {
+               if i > 0 {
+                       out = append(out, ` "`...)
+               } else {
+                       out = append(out, '"')
+               }
+               bs := []byte(s)
+               for j := 0; j < len(bs); {
+                       b, n := nextByte(bs, j)
+                       if n == 0 {
+                               break
+                       }
+                       out = appendTXTStringByte(out, b)
+                       j += n
+               }
+               out = append(out, '"')
+       }
+       return string(out)
+}
+
+func appendDomainNameByte(s []byte, b byte) []byte {
+       switch b {
+       case '.', ' ', '\'', '@', ';', '(', ')': // additional chars to escape
+               return append(s, '\\', b)
+       }
+       return appendTXTStringByte(s, b)
+}
+
+func appendTXTStringByte(s []byte, b byte) []byte {
+       switch b {
+       case '\t':
+               return append(s, '\\', 't')
+       case '\r':
+               return append(s, '\\', 'r')
+       case '\n':
+               return append(s, '\\', 'n')
+       case '"', '\\':
+               return append(s, '\\', b)
+       }
+       if b < ' ' || b > '~' {
+               return appendByte(s, b)
+       }
+       return append(s, b)
+}
+
+func appendByte(s []byte, b byte) []byte {
+       var buf [3]byte
+       bufs := strconv.AppendInt(buf[:0], int64(b), 10)
+       s = append(s, '\\')
+       for i := 0; i < 3-len(bufs); i++ {
+               s = append(s, '0')
+       }
+       for _, r := range bufs {
+               s = append(s, r)
+       }
+       return s
+}
+
+func nextByte(b []byte, offset int) (byte, int) {
+       if offset >= len(b) {
+               return 0, 0
+       }
+       if b[offset] != '\\' {
+               // not an escape sequence
+               return b[offset], 1
+       }
+       switch len(b) - offset {
+       case 1: // dangling escape
+               return 0, 0
+       case 2, 3: // too short to be \ddd
+       default: // maybe \ddd
+               if isDigit(b[offset+1]) && isDigit(b[offset+2]) && isDigit(b[offset+3]) {
+                       return dddToByte(b[offset+1:]), 4
+               }
+       }
+       // not \ddd, maybe a control char
+       switch b[offset+1] {
+       case 't':
+               return '\t', 2
+       case 'r':
+               return '\r', 2
+       case 'n':
+               return '\n', 2
+       default:
+               return b[offset+1], 2
+       }
+}
+
+type SPF struct {
+       Hdr RR_Header
+       Txt []string `dns:"txt"`
+}
+
+func (rr *SPF) String() string { return rr.Hdr.String() + sprintTxt(rr.Txt) }
+
+type SRV struct {
+       Hdr      RR_Header
+       Priority uint16
+       Weight   uint16
+       Port     uint16
+       Target   string `dns:"domain-name"`
+}
+
+func (rr *SRV) String() string {
+       return rr.Hdr.String() +
+               strconv.Itoa(int(rr.Priority)) + " " +
+               strconv.Itoa(int(rr.Weight)) + " " +
+               strconv.Itoa(int(rr.Port)) + " " + sprintName(rr.Target)
+}
+
+type NAPTR struct {
+       Hdr         RR_Header
+       Order       uint16
+       Preference  uint16
+       Flags       string
+       Service     string
+       Regexp      string
+       Replacement string `dns:"domain-name"`
+}
+
+func (rr *NAPTR) String() string {
+       return rr.Hdr.String() +
+               strconv.Itoa(int(rr.Order)) + " " +
+               strconv.Itoa(int(rr.Preference)) + " " +
+               "\"" + rr.Flags + "\" " +
+               "\"" + rr.Service + "\" " +
+               "\"" + rr.Regexp + "\" " +
+               rr.Replacement
+}
+
+// The CERT resource record, see RFC 4398.
+type CERT struct {
+       Hdr         RR_Header
+       Type        uint16
+       KeyTag      uint16
+       Algorithm   uint8
+       Certificate string `dns:"base64"`
+}
+
+func (rr *CERT) String() string {
+       var (
+               ok                  bool
+               certtype, algorithm string
+       )
+       if certtype, ok = CertTypeToString[rr.Type]; !ok {
+               certtype = strconv.Itoa(int(rr.Type))
+       }
+       if algorithm, ok = AlgorithmToString[rr.Algorithm]; !ok {
+               algorithm = strconv.Itoa(int(rr.Algorithm))
+       }
+       return rr.Hdr.String() + certtype +
+               " " + strconv.Itoa(int(rr.KeyTag)) +
+               " " + algorithm +
+               " " + rr.Certificate
+}
+
+// The DNAME resource record, see RFC 2672.
+type DNAME struct {
+       Hdr    RR_Header
+       Target string `dns:"domain-name"`
+}
+
+func (rr *DNAME) String() string {
+       return rr.Hdr.String() + sprintName(rr.Target)
+}
+
+type A struct {
+       Hdr RR_Header
+       A   net.IP `dns:"a"`
+}
+
+func (rr *A) String() string {
+       if rr.A == nil {
+               return rr.Hdr.String()
+       }
+       return rr.Hdr.String() + rr.A.String()
+}
+
+type AAAA struct {
+       Hdr  RR_Header
+       AAAA net.IP `dns:"aaaa"`
+}
+
+func (rr *AAAA) String() string {
+       if rr.AAAA == nil {
+               return rr.Hdr.String()
+       }
+       return rr.Hdr.String() + rr.AAAA.String()
+}
+
+type PX struct {
+       Hdr        RR_Header
+       Preference uint16
+       Map822     string `dns:"domain-name"`
+       Mapx400    string `dns:"domain-name"`
+}
+
+func (rr *PX) String() string {
+       return rr.Hdr.String() + strconv.Itoa(int(rr.Preference)) + " " + sprintName(rr.Map822) + " " + sprintName(rr.Mapx400)
+}
+
+type GPOS struct {
+       Hdr       RR_Header
+       Longitude string
+       Latitude  string
+       Altitude  string
+}
+
+func (rr *GPOS) String() string {
+       return rr.Hdr.String() + rr.Longitude + " " + rr.Latitude + " " + rr.Altitude
+}
+
+type LOC struct {
+       Hdr       RR_Header
+       Version   uint8
+       Size      uint8
+       HorizPre  uint8
+       VertPre   uint8
+       Latitude  uint32
+       Longitude uint32
+       Altitude  uint32
+}
+
+// cmToM takes a cm value expressed in RFC1876 SIZE mantissa/exponent
+// format and returns a string in m (two decimals for the cm)
+func cmToM(m, e uint8) string {
+       if e < 2 {
+               if e == 1 {
+                       m *= 10
+               }
+
+               return fmt.Sprintf("0.%02d", m)
+       }
+
+       s := fmt.Sprintf("%d", m)
+       for e > 2 {
+               s += "0"
+               e--
+       }
+       return s
+}
+
+func (rr *LOC) String() string {
+       s := rr.Hdr.String()
+
+       lat := rr.Latitude
+       ns := "N"
+       if lat > LOC_EQUATOR {
+               lat = lat - LOC_EQUATOR
+       } else {
+               ns = "S"
+               lat = LOC_EQUATOR - lat
+       }
+       h := lat / LOC_DEGREES
+       lat = lat % LOC_DEGREES
+       m := lat / LOC_HOURS
+       lat = lat % LOC_HOURS
+       s += fmt.Sprintf("%02d %02d %0.3f %s ", h, m, (float64(lat) / 1000), ns)
+
+       lon := rr.Longitude
+       ew := "E"
+       if lon > LOC_PRIMEMERIDIAN {
+               lon = lon - LOC_PRIMEMERIDIAN
+       } else {
+               ew = "W"
+               lon = LOC_PRIMEMERIDIAN - lon
+       }
+       h = lon / LOC_DEGREES
+       lon = lon % LOC_DEGREES
+       m = lon / LOC_HOURS
+       lon = lon % LOC_HOURS
+       s += fmt.Sprintf("%02d %02d %0.3f %s ", h, m, (float64(lon) / 1000), ew)
+
+       var alt = float64(rr.Altitude) / 100
+       alt -= LOC_ALTITUDEBASE
+       if rr.Altitude%100 != 0 {
+               s += fmt.Sprintf("%.2fm ", alt)
+       } else {
+               s += fmt.Sprintf("%.0fm ", alt)
+       }
+
+       s += cmToM((rr.Size&0xf0)>>4, rr.Size&0x0f) + "m "
+       s += cmToM((rr.HorizPre&0xf0)>>4, rr.HorizPre&0x0f) + "m "
+       s += cmToM((rr.VertPre&0xf0)>>4, rr.VertPre&0x0f) + "m"
+
+       return s
+}
+
+// SIG is identical to RRSIG and nowadays only used for SIG(0), RFC2931.
+type SIG struct {
+       RRSIG
+}
+
+type RRSIG struct {
+       Hdr         RR_Header
+       TypeCovered uint16
+       Algorithm   uint8
+       Labels      uint8
+       OrigTtl     uint32
+       Expiration  uint32
+       Inception   uint32
+       KeyTag      uint16
+       SignerName  string `dns:"domain-name"`
+       Signature   string `dns:"base64"`
+}
+
+func (rr *RRSIG) String() string {
+       s := rr.Hdr.String()
+       s += Type(rr.TypeCovered).String()
+       s += " " + strconv.Itoa(int(rr.Algorithm)) +
+               " " + strconv.Itoa(int(rr.Labels)) +
+               " " + strconv.FormatInt(int64(rr.OrigTtl), 10) +
+               " " + TimeToString(rr.Expiration) +
+               " " + TimeToString(rr.Inception) +
+               " " + strconv.Itoa(int(rr.KeyTag)) +
+               " " + sprintName(rr.SignerName) +
+               " " + rr.Signature
+       return s
+}
+
+type NSEC struct {
+       Hdr        RR_Header
+       NextDomain string   `dns:"domain-name"`
+       TypeBitMap []uint16 `dns:"nsec"`
+}
+
+func (rr *NSEC) String() string {
+       s := rr.Hdr.String() + sprintName(rr.NextDomain)
+       for i := 0; i < len(rr.TypeBitMap); i++ {
+               s += " " + Type(rr.TypeBitMap[i]).String()
+       }
+       return s
+}
+
+func (rr *NSEC) len() int {
+       l := rr.Hdr.len() + len(rr.NextDomain) + 1
+       lastwindow := uint32(2 ^ 32 + 1)
+       for _, t := range rr.TypeBitMap {
+               window := t / 256
+               if uint32(window) != lastwindow {
+                       l += 1 + 32
+               }
+               lastwindow = uint32(window)
+       }
+       return l
+}
+
+type DLV struct {
+       DS
+}
+
+type CDS struct {
+       DS
+}
+
+type DS struct {
+       Hdr        RR_Header
+       KeyTag     uint16
+       Algorithm  uint8
+       DigestType uint8
+       Digest     string `dns:"hex"`
+}
+
+func (rr *DS) 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)
+}
+
+type KX struct {
+       Hdr        RR_Header
+       Preference uint16
+       Exchanger  string `dns:"domain-name"`
+}
+
+func (rr *KX) String() string {
+       return rr.Hdr.String() + strconv.Itoa(int(rr.Preference)) +
+               " " + sprintName(rr.Exchanger)
+}
+
+type TA struct {
+       Hdr        RR_Header
+       KeyTag     uint16
+       Algorithm  uint8
+       DigestType uint8
+       Digest     string `dns:"hex"`
+}
+
+func (rr *TA) 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)
+}
+
+type TALINK struct {
+       Hdr          RR_Header
+       PreviousName string `dns:"domain-name"`
+       NextName     string `dns:"domain-name"`
+}
+
+func (rr *TALINK) String() string {
+       return rr.Hdr.String() +
+               sprintName(rr.PreviousName) + " " + sprintName(rr.NextName)
+}
+
+type SSHFP struct {
+       Hdr         RR_Header
+       Algorithm   uint8
+       Type        uint8
+       FingerPrint string `dns:"hex"`
+}
+
+func (rr *SSHFP) String() string {
+       return rr.Hdr.String() + strconv.Itoa(int(rr.Algorithm)) +
+               " " + strconv.Itoa(int(rr.Type)) +
+               " " + strings.ToUpper(rr.FingerPrint)
+}
+
+type KEY struct {
+       DNSKEY
+}
+
+type CDNSKEY struct {
+       DNSKEY
+}
+
+type DNSKEY struct {
+       Hdr       RR_Header
+       Flags     uint16
+       Protocol  uint8
+       Algorithm uint8
+       PublicKey string `dns:"base64"`
+}
+
+func (rr *DNSKEY) String() string {
+       return rr.Hdr.String() + strconv.Itoa(int(rr.Flags)) +
+               " " + strconv.Itoa(int(rr.Protocol)) +
+               " " + strconv.Itoa(int(rr.Algorithm)) +
+               " " + rr.PublicKey
+}
+
+type RKEY struct {
+       Hdr       RR_Header
+       Flags     uint16
+       Protocol  uint8
+       Algorithm uint8
+       PublicKey string `dns:"base64"`
+}
+
+func (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
+}
+
+type NSAPPTR struct {
+       Hdr RR_Header
+       Ptr string `dns:"domain-name"`
+}
+
+func (rr *NSAPPTR) String() string { return rr.Hdr.String() + sprintName(rr.Ptr) }
+
+type NSEC3 struct {
+       Hdr        RR_Header
+       Hash       uint8
+       Flags      uint8
+       Iterations uint16
+       SaltLength uint8
+       Salt       string `dns:"size-hex:SaltLength"`
+       HashLength uint8
+       NextDomain string   `dns:"size-base32:HashLength"`
+       TypeBitMap []uint16 `dns:"nsec"`
+}
+
+func (rr *NSEC3) String() string {
+       s := rr.Hdr.String()
+       s += strconv.Itoa(int(rr.Hash)) +
+               " " + strconv.Itoa(int(rr.Flags)) +
+               " " + strconv.Itoa(int(rr.Iterations)) +
+               " " + saltToString(rr.Salt) +
+               " " + rr.NextDomain
+       for i := 0; i < len(rr.TypeBitMap); i++ {
+               s += " " + Type(rr.TypeBitMap[i]).String()
+       }
+       return s
+}
+
+func (rr *NSEC3) len() int {
+       l := rr.Hdr.len() + 6 + len(rr.Salt)/2 + 1 + len(rr.NextDomain) + 1
+       lastwindow := uint32(2 ^ 32 + 1)
+       for _, t := range rr.TypeBitMap {
+               window := t / 256
+               if uint32(window) != lastwindow {
+                       l += 1 + 32
+               }
+               lastwindow = uint32(window)
+       }
+       return l
+}
+
+type NSEC3PARAM struct {
+       Hdr        RR_Header
+       Hash       uint8
+       Flags      uint8
+       Iterations uint16
+       SaltLength uint8
+       Salt       string `dns:"hex"`
+}
+
+func (rr *NSEC3PARAM) String() string {
+       s := rr.Hdr.String()
+       s += strconv.Itoa(int(rr.Hash)) +
+               " " + strconv.Itoa(int(rr.Flags)) +
+               " " + strconv.Itoa(int(rr.Iterations)) +
+               " " + saltToString(rr.Salt)
+       return s
+}
+
+type TKEY struct {
+       Hdr        RR_Header
+       Algorithm  string `dns:"domain-name"`
+       Inception  uint32
+       Expiration uint32
+       Mode       uint16
+       Error      uint16
+       KeySize    uint16
+       Key        string
+       OtherLen   uint16
+       OtherData  string
+}
+
+func (rr *TKEY) String() string {
+       // It has no presentation format
+       return ""
+}
+
+// RFC3597 represents an unknown/generic RR.
+type RFC3597 struct {
+       Hdr   RR_Header
+       Rdata string `dns:"hex"`
+}
+
+func (rr *RFC3597) String() string {
+       // Let's call it a hack
+       s := rfc3597Header(rr.Hdr)
+
+       s += "\\# " + strconv.Itoa(len(rr.Rdata)/2) + " " + rr.Rdata
+       return s
+}
+
+func rfc3597Header(h RR_Header) string {
+       var s string
+
+       s += sprintName(h.Name) + "\t"
+       s += strconv.FormatInt(int64(h.Ttl), 10) + "\t"
+       s += "CLASS" + strconv.Itoa(int(h.Class)) + "\t"
+       s += "TYPE" + strconv.Itoa(int(h.Rrtype)) + "\t"
+       return s
+}
+
+type URI struct {
+       Hdr      RR_Header
+       Priority uint16
+       Weight   uint16
+       Target   string `dns:"octet"`
+}
+
+func (rr *URI) String() string {
+       return rr.Hdr.String() + strconv.Itoa(int(rr.Priority)) +
+               " " + strconv.Itoa(int(rr.Weight)) + " " + sprintTxtOctet(rr.Target)
+}
+
+type DHCID struct {
+       Hdr    RR_Header
+       Digest string `dns:"base64"`
+}
+
+func (rr *DHCID) String() string { return rr.Hdr.String() + rr.Digest }
+
+type TLSA struct {
+       Hdr          RR_Header
+       Usage        uint8
+       Selector     uint8
+       MatchingType uint8
+       Certificate  string `dns:"hex"`
+}
+
+func (rr *TLSA) String() string {
+       return rr.Hdr.String() +
+               strconv.Itoa(int(rr.Usage)) +
+               " " + strconv.Itoa(int(rr.Selector)) +
+               " " + strconv.Itoa(int(rr.MatchingType)) +
+               " " + rr.Certificate
+}
+
+type HIP struct {
+       Hdr                RR_Header
+       HitLength          uint8
+       PublicKeyAlgorithm uint8
+       PublicKeyLength    uint16
+       Hit                string   `dns:"size-hex:HitLength"`
+       PublicKey          string   `dns:"size-base64:PublicKeyLength"`
+       RendezvousServers  []string `dns:"domain-name"`
+}
+
+func (rr *HIP) String() string {
+       s := rr.Hdr.String() +
+               strconv.Itoa(int(rr.PublicKeyAlgorithm)) +
+               " " + rr.Hit +
+               " " + rr.PublicKey
+       for _, d := range rr.RendezvousServers {
+               s += " " + sprintName(d)
+       }
+       return s
+}
+
+type NINFO struct {
+       Hdr    RR_Header
+       ZSData []string `dns:"txt"`
+}
+
+func (rr *NINFO) String() string { return rr.Hdr.String() + sprintTxt(rr.ZSData) }
+
+type NID struct {
+       Hdr        RR_Header
+       Preference uint16
+       NodeID     uint64
+}
+
+func (rr *NID) String() string {
+       s := rr.Hdr.String() + strconv.Itoa(int(rr.Preference))
+       node := fmt.Sprintf("%0.16x", rr.NodeID)
+       s += " " + node[0:4] + ":" + node[4:8] + ":" + node[8:12] + ":" + node[12:16]
+       return s
+}
+
+type L32 struct {
+       Hdr        RR_Header
+       Preference uint16
+       Locator32  net.IP `dns:"a"`
+}
+
+func (rr *L32) String() string {
+       if rr.Locator32 == nil {
+               return rr.Hdr.String() + strconv.Itoa(int(rr.Preference))
+       }
+       return rr.Hdr.String() + strconv.Itoa(int(rr.Preference)) +
+               " " + rr.Locator32.String()
+}
+
+type L64 struct {
+       Hdr        RR_Header
+       Preference uint16
+       Locator64  uint64
+}
+
+func (rr *L64) String() string {
+       s := rr.Hdr.String() + strconv.Itoa(int(rr.Preference))
+       node := fmt.Sprintf("%0.16X", rr.Locator64)
+       s += " " + node[0:4] + ":" + node[4:8] + ":" + node[8:12] + ":" + node[12:16]
+       return s
+}
+
+type LP struct {
+       Hdr        RR_Header
+       Preference uint16
+       Fqdn       string `dns:"domain-name"`
+}
+
+func (rr *LP) String() string {
+       return rr.Hdr.String() + strconv.Itoa(int(rr.Preference)) + " " + sprintName(rr.Fqdn)
+}
+
+type EUI48 struct {
+       Hdr     RR_Header
+       Address uint64 `dns:"uint48"`
+}
+
+func (rr *EUI48) String() string { return rr.Hdr.String() + euiToString(rr.Address, 48) }
+
+type EUI64 struct {
+       Hdr     RR_Header
+       Address uint64
+}
+
+func (rr *EUI64) String() string { return rr.Hdr.String() + euiToString(rr.Address, 64) }
+
+type CAA struct {
+       Hdr   RR_Header
+       Flag  uint8
+       Tag   string
+       Value string `dns:"octet"`
+}
+
+func (rr *CAA) String() string {
+       return rr.Hdr.String() + strconv.Itoa(int(rr.Flag)) + " " + rr.Tag + " " + sprintTxtOctet(rr.Value)
+}
+
+type UID struct {
+       Hdr RR_Header
+       Uid uint32
+}
+
+func (rr *UID) String() string { return rr.Hdr.String() + strconv.FormatInt(int64(rr.Uid), 10) }
+
+type GID struct {
+       Hdr RR_Header
+       Gid uint32
+}
+
+func (rr *GID) String() string { return rr.Hdr.String() + strconv.FormatInt(int64(rr.Gid), 10) }
+
+type UINFO struct {
+       Hdr   RR_Header
+       Uinfo string
+}
+
+func (rr *UINFO) String() string { return rr.Hdr.String() + sprintTxt([]string{rr.Uinfo}) }
+
+type EID struct {
+       Hdr      RR_Header
+       Endpoint string `dns:"hex"`
+}
+
+func (rr *EID) String() string { return rr.Hdr.String() + strings.ToUpper(rr.Endpoint) }
+
+type NIMLOC struct {
+       Hdr     RR_Header
+       Locator string `dns:"hex"`
+}
+
+func (rr *NIMLOC) String() string { return rr.Hdr.String() + strings.ToUpper(rr.Locator) }
+
+type OPENPGPKEY struct {
+       Hdr       RR_Header
+       PublicKey string `dns:"base64"`
+}
+
+func (rr *OPENPGPKEY) String() string { return rr.Hdr.String() + rr.PublicKey }
+
+// TimeToString translates the RRSIG's incep. and expir. times to the
+// string representation used when printing the record.
+// It takes serial arithmetic (RFC 1982) into account.
+func TimeToString(t uint32) string {
+       mod := ((int64(t) - time.Now().Unix()) / year68) - 1
+       if mod < 0 {
+               mod = 0
+       }
+       ti := time.Unix(int64(t)-(mod*year68), 0).UTC()
+       return ti.Format("20060102150405")
+}
+
+// StringToTime translates the RRSIG's incep. and expir. times from
+// string values like "20110403154150" to an 32 bit integer.
+// It takes serial arithmetic (RFC 1982) into account.
+func StringToTime(s string) (uint32, error) {
+       t, err := time.Parse("20060102150405", s)
+       if err != nil {
+               return 0, err
+       }
+       mod := (t.Unix() / year68) - 1
+       if mod < 0 {
+               mod = 0
+       }
+       return uint32(t.Unix() - (mod * year68)), nil
+}
+
+// saltToString converts a NSECX salt to uppercase and
+// returns "-" when it is empty
+func saltToString(s string) string {
+       if len(s) == 0 {
+               return "-"
+       }
+       return strings.ToUpper(s)
+}
+
+func euiToString(eui uint64, bits int) (hex string) {
+       switch bits {
+       case 64:
+               hex = fmt.Sprintf("%16.16x", eui)
+               hex = hex[0:2] + "-" + hex[2:4] + "-" + hex[4:6] + "-" + hex[6:8] +
+                       "-" + hex[8:10] + "-" + hex[10:12] + "-" + hex[12:14] + "-" + hex[14:16]
+       case 48:
+               hex = fmt.Sprintf("%12.12x", eui)
+               hex = hex[0:2] + "-" + hex[2:4] + "-" + hex[4:6] + "-" + hex[6:8] +
+                       "-" + hex[8:10] + "-" + hex[10:12]
+       }
+       return
+}
+
+// copyIP returns a copy of ip.
+func copyIP(ip net.IP) net.IP {
+       p := make(net.IP, len(ip))
+       copy(p, ip)
+       return p
+}
diff --git a/vendor/github.com/miekg/dns/types_generate.go b/vendor/github.com/miekg/dns/types_generate.go
new file mode 100644 (file)
index 0000000..bf80da3
--- /dev/null
@@ -0,0 +1,271 @@
+//+build ignore
+
+// types_generate.go is meant to run with go generate. It will use
+// go/{importer,types} to track down all the RR struct types. Then for each type
+// it will generate conversion tables (TypeToRR and TypeToString) and banal
+// methods (len, Header, copy) based on the struct tags. The generated source is
+// written to ztypes.go, and is meant to be checked into git.
+package main
+
+import (
+       "bytes"
+       "fmt"
+       "go/format"
+       "go/importer"
+       "go/types"
+       "log"
+       "os"
+       "strings"
+       "text/template"
+)
+
+var skipLen = map[string]struct{}{
+       "NSEC":  {},
+       "NSEC3": {},
+       "OPT":   {},
+}
+
+var packageHdr = `
+// *** DO NOT MODIFY ***
+// AUTOGENERATED BY go generate from type_generate.go
+
+package dns
+
+import (
+       "encoding/base64"
+       "net"
+)
+
+`
+
+var TypeToRR = template.Must(template.New("TypeToRR").Parse(`
+// TypeToRR is a map of constructors for each RR type.
+var TypeToRR = map[uint16]func() RR{
+{{range .}}{{if ne . "RFC3597"}}  Type{{.}}:  func() RR { return new({{.}}) },
+{{end}}{{end}}                    }
+
+`))
+
+var typeToString = template.Must(template.New("typeToString").Parse(`
+// TypeToString is a map of strings for each RR type.
+var TypeToString = map[uint16]string{
+{{range .}}{{if ne . "NSAPPTR"}}  Type{{.}}: "{{.}}",
+{{end}}{{end}}                    TypeNSAPPTR:    "NSAP-PTR",
+}
+
+`))
+
+var headerFunc = template.Must(template.New("headerFunc").Parse(`
+// Header() functions
+{{range .}}  func (rr *{{.}}) Header() *RR_Header { return &rr.Hdr }
+{{end}}
+
+`))
+
+// getTypeStruct will take a type and the package scope, and return the
+// (innermost) struct if the type is considered a RR type (currently defined as
+// those structs beginning with a RR_Header, could be redefined as implementing
+// the RR interface). The bool return value indicates if embedded structs were
+// resolved.
+func getTypeStruct(t types.Type, scope *types.Scope) (*types.Struct, bool) {
+       st, ok := t.Underlying().(*types.Struct)
+       if !ok {
+               return nil, false
+       }
+       if st.Field(0).Type() == scope.Lookup("RR_Header").Type() {
+               return st, false
+       }
+       if st.Field(0).Anonymous() {
+               st, _ := getTypeStruct(st.Field(0).Type(), scope)
+               return st, true
+       }
+       return nil, false
+}
+
+func main() {
+       // Import and type-check the package
+       pkg, err := importer.Default().Import("github.com/miekg/dns")
+       fatalIfErr(err)
+       scope := pkg.Scope()
+
+       // Collect constants like TypeX
+       var numberedTypes []string
+       for _, name := range scope.Names() {
+               o := scope.Lookup(name)
+               if o == nil || !o.Exported() {
+                       continue
+               }
+               b, ok := o.Type().(*types.Basic)
+               if !ok || b.Kind() != types.Uint16 {
+                       continue
+               }
+               if !strings.HasPrefix(o.Name(), "Type") {
+                       continue
+               }
+               name := strings.TrimPrefix(o.Name(), "Type")
+               if name == "PrivateRR" {
+                       continue
+               }
+               numberedTypes = append(numberedTypes, name)
+       }
+
+       // Collect actual types (*X)
+       var namedTypes []string
+       for _, name := range scope.Names() {
+               o := scope.Lookup(name)
+               if o == nil || !o.Exported() {
+                       continue
+               }
+               if st, _ := getTypeStruct(o.Type(), scope); st == nil {
+                       continue
+               }
+               if name == "PrivateRR" {
+                       continue
+               }
+
+               // Check if corresponding TypeX exists
+               if scope.Lookup("Type"+o.Name()) == nil && o.Name() != "RFC3597" {
+                       log.Fatalf("Constant Type%s does not exist.", o.Name())
+               }
+
+               namedTypes = append(namedTypes, o.Name())
+       }
+
+       b := &bytes.Buffer{}
+       b.WriteString(packageHdr)
+
+       // Generate TypeToRR
+       fatalIfErr(TypeToRR.Execute(b, namedTypes))
+
+       // Generate typeToString
+       fatalIfErr(typeToString.Execute(b, numberedTypes))
+
+       // Generate headerFunc
+       fatalIfErr(headerFunc.Execute(b, namedTypes))
+
+       // Generate len()
+       fmt.Fprint(b, "// len() functions\n")
+       for _, name := range namedTypes {
+               if _, ok := skipLen[name]; ok {
+                       continue
+               }
+               o := scope.Lookup(name)
+               st, isEmbedded := getTypeStruct(o.Type(), scope)
+               if isEmbedded {
+                       continue
+               }
+               fmt.Fprintf(b, "func (rr *%s) len() int {\n", name)
+               fmt.Fprintf(b, "l := rr.Hdr.len()\n")
+               for i := 1; i < st.NumFields(); i++ {
+                       o := func(s string) { fmt.Fprintf(b, s, st.Field(i).Name()) }
+
+                       if _, ok := st.Field(i).Type().(*types.Slice); ok {
+                               switch st.Tag(i) {
+                               case `dns:"-"`:
+                                       // ignored
+                               case `dns:"cdomain-name"`, `dns:"domain-name"`, `dns:"txt"`:
+                                       o("for _, x := range rr.%s { l += len(x) + 1 }\n")
+                               default:
+                                       log.Fatalln(name, st.Field(i).Name(), st.Tag(i))
+                               }
+                               continue
+                       }
+
+                       switch {
+                       case st.Tag(i) == `dns:"-"`:
+                               // ignored
+                       case st.Tag(i) == `dns:"cdomain-name"`, st.Tag(i) == `dns:"domain-name"`:
+                               o("l += len(rr.%s) + 1\n")
+                       case st.Tag(i) == `dns:"octet"`:
+                               o("l += len(rr.%s)\n")
+                       case strings.HasPrefix(st.Tag(i), `dns:"size-base64`):
+                               fallthrough
+                       case st.Tag(i) == `dns:"base64"`:
+                               o("l += base64.StdEncoding.DecodedLen(len(rr.%s))\n")
+                       case strings.HasPrefix(st.Tag(i), `dns:"size-hex`):
+                               fallthrough
+                       case st.Tag(i) == `dns:"hex"`:
+                               o("l += len(rr.%s)/2 + 1\n")
+                       case st.Tag(i) == `dns:"a"`:
+                               o("l += net.IPv4len // %s\n")
+                       case st.Tag(i) == `dns:"aaaa"`:
+                               o("l += net.IPv6len // %s\n")
+                       case st.Tag(i) == `dns:"txt"`:
+                               o("for _, t := range rr.%s { l += len(t) + 1 }\n")
+                       case st.Tag(i) == `dns:"uint48"`:
+                               o("l += 6 // %s\n")
+                       case st.Tag(i) == "":
+                               switch st.Field(i).Type().(*types.Basic).Kind() {
+                               case types.Uint8:
+                                       o("l += 1 // %s\n")
+                               case types.Uint16:
+                                       o("l += 2 // %s\n")
+                               case types.Uint32:
+                                       o("l += 4 // %s\n")
+                               case types.Uint64:
+                                       o("l += 8 // %s\n")
+                               case types.String:
+                                       o("l += len(rr.%s) + 1\n")
+                               default:
+                                       log.Fatalln(name, st.Field(i).Name())
+                               }
+                       default:
+                               log.Fatalln(name, st.Field(i).Name(), st.Tag(i))
+                       }
+               }
+               fmt.Fprintf(b, "return l }\n")
+       }
+
+       // Generate copy()
+       fmt.Fprint(b, "// copy() functions\n")
+       for _, name := range namedTypes {
+               o := scope.Lookup(name)
+               st, isEmbedded := getTypeStruct(o.Type(), scope)
+               if isEmbedded {
+                       continue
+               }
+               fmt.Fprintf(b, "func (rr *%s) copy() RR {\n", name)
+               fields := []string{"*rr.Hdr.copyHeader()"}
+               for i := 1; i < st.NumFields(); i++ {
+                       f := st.Field(i).Name()
+                       if sl, ok := st.Field(i).Type().(*types.Slice); ok {
+                               t := sl.Underlying().String()
+                               t = strings.TrimPrefix(t, "[]")
+                               if strings.Contains(t, ".") {
+                                       splits := strings.Split(t, ".")
+                                       t = splits[len(splits)-1]
+                               }
+                               fmt.Fprintf(b, "%s := make([]%s, len(rr.%s)); copy(%s, rr.%s)\n",
+                                       f, t, f, f, f)
+                               fields = append(fields, f)
+                               continue
+                       }
+                       if st.Field(i).Type().String() == "net.IP" {
+                               fields = append(fields, "copyIP(rr."+f+")")
+                               continue
+                       }
+                       fields = append(fields, "rr."+f)
+               }
+               fmt.Fprintf(b, "return &%s{%s}\n", name, strings.Join(fields, ","))
+               fmt.Fprintf(b, "}\n")
+       }
+
+       // gofmt
+       res, err := format.Source(b.Bytes())
+       if err != nil {
+               b.WriteTo(os.Stderr)
+               log.Fatal(err)
+       }
+
+       // write result
+       f, err := os.Create("ztypes.go")
+       fatalIfErr(err)
+       defer f.Close()
+       f.Write(res)
+}
+
+func fatalIfErr(err error) {
+       if err != nil {
+               log.Fatal(err)
+       }
+}
diff --git a/vendor/github.com/miekg/dns/udp.go b/vendor/github.com/miekg/dns/udp.go
new file mode 100644 (file)
index 0000000..c79c6c8
--- /dev/null
@@ -0,0 +1,58 @@
+// +build !windows,!plan9
+
+package dns
+
+import (
+       "net"
+       "syscall"
+)
+
+// SessionUDP holds the remote address and the associated
+// out-of-band data.
+type SessionUDP struct {
+       raddr   *net.UDPAddr
+       context []byte
+}
+
+// RemoteAddr returns the remote network address.
+func (s *SessionUDP) RemoteAddr() net.Addr { return s.raddr }
+
+// setUDPSocketOptions sets the UDP socket options.
+// This function is implemented on a per platform basis. See udp_*.go for more details
+func setUDPSocketOptions(conn *net.UDPConn) error {
+       sa, err := getUDPSocketName(conn)
+       if err != nil {
+               return err
+       }
+       switch sa.(type) {
+       case *syscall.SockaddrInet6:
+               v6only, err := getUDPSocketOptions6Only(conn)
+               if err != nil {
+                       return err
+               }
+               setUDPSocketOptions6(conn)
+               if !v6only {
+                       setUDPSocketOptions4(conn)
+               }
+       case *syscall.SockaddrInet4:
+               setUDPSocketOptions4(conn)
+       }
+       return nil
+}
+
+// ReadFromSessionUDP acts just like net.UDPConn.ReadFrom(), but returns a session object instead of a
+// net.UDPAddr.
+func ReadFromSessionUDP(conn *net.UDPConn, b []byte) (int, *SessionUDP, error) {
+       oob := make([]byte, 40)
+       n, oobn, _, raddr, err := conn.ReadMsgUDP(b, oob)
+       if err != nil {
+               return n, nil, err
+       }
+       return n, &SessionUDP{raddr, oob[:oobn]}, err
+}
+
+// WriteToSessionUDP acts just like net.UDPConn.WritetTo(), but uses a *SessionUDP instead of a net.Addr.
+func WriteToSessionUDP(conn *net.UDPConn, b []byte, session *SessionUDP) (int, error) {
+       n, _, err := conn.WriteMsgUDP(b, session.context, session.raddr)
+       return n, err
+}
diff --git a/vendor/github.com/miekg/dns/udp_linux.go b/vendor/github.com/miekg/dns/udp_linux.go
new file mode 100644 (file)
index 0000000..c62d218
--- /dev/null
@@ -0,0 +1,73 @@
+// +build linux
+
+package dns
+
+// See:
+// * http://stackoverflow.com/questions/3062205/setting-the-source-ip-for-a-udp-socket and
+// * http://blog.powerdns.com/2012/10/08/on-binding-datagram-udp-sockets-to-the-any-addresses/
+//
+// Why do we need this: When listening on 0.0.0.0 with UDP so kernel decides what is the outgoing
+// interface, this might not always be the correct one. This code will make sure the egress
+// packet's interface matched the ingress' one.
+
+import (
+       "net"
+       "syscall"
+)
+
+// setUDPSocketOptions4 prepares the v4 socket for sessions.
+func setUDPSocketOptions4(conn *net.UDPConn) error {
+       file, err := conn.File()
+       if err != nil {
+               return err
+       }
+       if err := syscall.SetsockoptInt(int(file.Fd()), syscall.IPPROTO_IP, syscall.IP_PKTINFO, 1); err != nil {
+               return err
+       }
+       // Calling File() above results in the connection becoming blocking, we must fix that.
+       // See https://github.com/miekg/dns/issues/279
+       err = syscall.SetNonblock(int(file.Fd()), true)
+       if err != nil {
+               return err
+       }
+       return nil
+}
+
+// setUDPSocketOptions6 prepares the v6 socket for sessions.
+func setUDPSocketOptions6(conn *net.UDPConn) error {
+       file, err := conn.File()
+       if err != nil {
+               return err
+       }
+       if err := syscall.SetsockoptInt(int(file.Fd()), syscall.IPPROTO_IPV6, syscall.IPV6_RECVPKTINFO, 1); err != nil {
+               return err
+       }
+       err = syscall.SetNonblock(int(file.Fd()), true)
+       if err != nil {
+               return err
+       }
+       return nil
+}
+
+// getUDPSocketOption6Only return true if the socket is v6 only and false when it is v4/v6 combined
+// (dualstack).
+func getUDPSocketOptions6Only(conn *net.UDPConn) (bool, error) {
+       file, err := conn.File()
+       if err != nil {
+               return false, err
+       }
+       // dual stack. See http://stackoverflow.com/questions/1618240/how-to-support-both-ipv4-and-ipv6-connections
+       v6only, err := syscall.GetsockoptInt(int(file.Fd()), syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY)
+       if err != nil {
+               return false, err
+       }
+       return v6only == 1, nil
+}
+
+func getUDPSocketName(conn *net.UDPConn) (syscall.Sockaddr, error) {
+       file, err := conn.File()
+       if err != nil {
+               return nil, err
+       }
+       return syscall.Getsockname(int(file.Fd()))
+}
diff --git a/vendor/github.com/miekg/dns/udp_other.go b/vendor/github.com/miekg/dns/udp_other.go
new file mode 100644 (file)
index 0000000..d407324
--- /dev/null
@@ -0,0 +1,17 @@
+// +build !linux,!plan9
+
+package dns
+
+import (
+       "net"
+       "syscall"
+)
+
+// These do nothing. See udp_linux.go for an example of how to implement this.
+
+// We tried to adhire to some kind of naming scheme.
+
+func setUDPSocketOptions4(conn *net.UDPConn) error                 { return nil }
+func setUDPSocketOptions6(conn *net.UDPConn) error                 { return nil }
+func getUDPSocketOptions6Only(conn *net.UDPConn) (bool, error)     { return false, nil }
+func getUDPSocketName(conn *net.UDPConn) (syscall.Sockaddr, error) { return nil, nil }
diff --git a/vendor/github.com/miekg/dns/udp_plan9.go b/vendor/github.com/miekg/dns/udp_plan9.go
new file mode 100644 (file)
index 0000000..b794dee
--- /dev/null
@@ -0,0 +1,34 @@
+package dns
+
+import (
+       "net"
+)
+
+func setUDPSocketOptions(conn *net.UDPConn) error { return nil }
+
+// SessionUDP holds the remote address and the associated
+// out-of-band data.
+type SessionUDP struct {
+       raddr   *net.UDPAddr
+       context []byte
+}
+
+// RemoteAddr returns the remote network address.
+func (s *SessionUDP) RemoteAddr() net.Addr { return s.raddr }
+
+// ReadFromSessionUDP acts just like net.UDPConn.ReadFrom(), but returns a session object instead of a
+// net.UDPAddr.
+func ReadFromSessionUDP(conn *net.UDPConn, b []byte) (int, *SessionUDP, error) {
+       oob := make([]byte, 40)
+       n, oobn, _, raddr, err := conn.ReadMsgUDP(b, oob)
+       if err != nil {
+               return n, nil, err
+       }
+       return n, &SessionUDP{raddr, oob[:oobn]}, err
+}
+
+// WriteToSessionUDP acts just like net.UDPConn.WritetTo(), but uses a *SessionUDP instead of a net.Addr.
+func WriteToSessionUDP(conn *net.UDPConn, b []byte, session *SessionUDP) (int, error) {
+       n, _, err := conn.WriteMsgUDP(b, session.context, session.raddr)
+       return n, err
+}
diff --git a/vendor/github.com/miekg/dns/udp_windows.go b/vendor/github.com/miekg/dns/udp_windows.go
new file mode 100644 (file)
index 0000000..2ce4b33
--- /dev/null
@@ -0,0 +1,34 @@
+// +build windows
+
+package dns
+
+import "net"
+
+type SessionUDP struct {
+       raddr *net.UDPAddr
+}
+
+// ReadFromSessionUDP acts just like net.UDPConn.ReadFrom(), but returns a session object instead of a
+// net.UDPAddr.
+func ReadFromSessionUDP(conn *net.UDPConn, b []byte) (int, *SessionUDP, error) {
+       n, raddr, err := conn.ReadFrom(b)
+       if err != nil {
+               return n, nil, err
+       }
+       session := &SessionUDP{raddr.(*net.UDPAddr)}
+       return n, session, err
+}
+
+// WriteToSessionUDP acts just like net.UDPConn.WritetTo(), but uses a *SessionUDP instead of a net.Addr.
+func WriteToSessionUDP(conn *net.UDPConn, b []byte, session *SessionUDP) (int, error) {
+       n, err := conn.WriteTo(b, session.raddr)
+       return n, err
+}
+
+func (s *SessionUDP) RemoteAddr() net.Addr { return s.raddr }
+
+// setUDPSocketOptions sets the UDP socket options.
+// This function is implemented on a per platform basis. See udp_*.go for more details
+func setUDPSocketOptions(conn *net.UDPConn) error {
+       return nil
+}
diff --git a/vendor/github.com/miekg/dns/update.go b/vendor/github.com/miekg/dns/update.go
new file mode 100644 (file)
index 0000000..e90c5c9
--- /dev/null
@@ -0,0 +1,106 @@
+package dns
+
+// NameUsed sets the RRs in the prereq section to
+// "Name is in use" RRs. RFC 2136 section 2.4.4.
+func (u *Msg) NameUsed(rr []RR) {
+       if u.Answer == nil {
+               u.Answer = make([]RR, 0, len(rr))
+       }
+       for _, r := range rr {
+               u.Answer = append(u.Answer, &ANY{Hdr: RR_Header{Name: r.Header().Name, Ttl: 0, Rrtype: TypeANY, Class: ClassANY}})
+       }
+}
+
+// NameNotUsed sets the RRs in the prereq section to
+// "Name is in not use" RRs. RFC 2136 section 2.4.5.
+func (u *Msg) NameNotUsed(rr []RR) {
+       if u.Answer == nil {
+               u.Answer = make([]RR, 0, len(rr))
+       }
+       for _, r := range rr {
+               u.Answer = append(u.Answer, &ANY{Hdr: RR_Header{Name: r.Header().Name, Ttl: 0, Rrtype: TypeANY, Class: ClassNONE}})
+       }
+}
+
+// Used sets the RRs in the prereq section to
+// "RRset exists (value dependent -- with rdata)" RRs. RFC 2136 section 2.4.2.
+func (u *Msg) Used(rr []RR) {
+       if len(u.Question) == 0 {
+               panic("dns: empty question section")
+       }
+       if u.Answer == nil {
+               u.Answer = make([]RR, 0, len(rr))
+       }
+       for _, r := range rr {
+               r.Header().Class = u.Question[0].Qclass
+               u.Answer = append(u.Answer, r)
+       }
+}
+
+// RRsetUsed sets the RRs in the prereq section to
+// "RRset exists (value independent -- no rdata)" RRs. RFC 2136 section 2.4.1.
+func (u *Msg) RRsetUsed(rr []RR) {
+       if u.Answer == nil {
+               u.Answer = make([]RR, 0, len(rr))
+       }
+       for _, r := range rr {
+               u.Answer = append(u.Answer, &ANY{Hdr: RR_Header{Name: r.Header().Name, Ttl: 0, Rrtype: r.Header().Rrtype, Class: ClassANY}})
+       }
+}
+
+// RRsetNotUsed sets the RRs in the prereq section to
+// "RRset does not exist" RRs. RFC 2136 section 2.4.3.
+func (u *Msg) RRsetNotUsed(rr []RR) {
+       if u.Answer == nil {
+               u.Answer = make([]RR, 0, len(rr))
+       }
+       for _, r := range rr {
+               u.Answer = append(u.Answer, &ANY{Hdr: RR_Header{Name: r.Header().Name, Ttl: 0, Rrtype: r.Header().Rrtype, Class: ClassNONE}})
+       }
+}
+
+// Insert creates a dynamic update packet that adds an complete RRset, see RFC 2136 section 2.5.1.
+func (u *Msg) Insert(rr []RR) {
+       if len(u.Question) == 0 {
+               panic("dns: empty question section")
+       }
+       if u.Ns == nil {
+               u.Ns = make([]RR, 0, len(rr))
+       }
+       for _, r := range rr {
+               r.Header().Class = u.Question[0].Qclass
+               u.Ns = append(u.Ns, r)
+       }
+}
+
+// RemoveRRset creates a dynamic update packet that deletes an RRset, see RFC 2136 section 2.5.2.
+func (u *Msg) RemoveRRset(rr []RR) {
+       if u.Ns == nil {
+               u.Ns = make([]RR, 0, len(rr))
+       }
+       for _, r := range rr {
+               u.Ns = append(u.Ns, &ANY{Hdr: RR_Header{Name: r.Header().Name, Ttl: 0, Rrtype: r.Header().Rrtype, Class: ClassANY}})
+       }
+}
+
+// RemoveName creates a dynamic update packet that deletes all RRsets of a name, see RFC 2136 section 2.5.3
+func (u *Msg) RemoveName(rr []RR) {
+       if u.Ns == nil {
+               u.Ns = make([]RR, 0, len(rr))
+       }
+       for _, r := range rr {
+               u.Ns = append(u.Ns, &ANY{Hdr: RR_Header{Name: r.Header().Name, Ttl: 0, Rrtype: TypeANY, Class: ClassANY}})
+       }
+}
+
+// Remove creates a dynamic update packet deletes RR from a RRSset, see RFC 2136 section 2.5.4
+func (u *Msg) Remove(rr []RR) {
+       if u.Ns == nil {
+               u.Ns = make([]RR, 0, len(rr))
+       }
+       for _, r := range rr {
+               r.Header().Class = ClassNONE
+               r.Header().Ttl = 0
+               u.Ns = append(u.Ns, r)
+       }
+}
diff --git a/vendor/github.com/miekg/dns/xfr.go b/vendor/github.com/miekg/dns/xfr.go
new file mode 100644 (file)
index 0000000..7346def
--- /dev/null
@@ -0,0 +1,244 @@
+package dns
+
+import (
+       "time"
+)
+
+// Envelope is used when doing a zone transfer with a remote server.
+type Envelope struct {
+       RR    []RR  // The set of RRs in the answer section of the xfr reply message.
+       Error error // If something went wrong, this contains the error.
+}
+
+// A Transfer defines parameters that are used during a zone transfer.
+type Transfer struct {
+       *Conn
+       DialTimeout    time.Duration     // net.DialTimeout, defaults to 2 seconds
+       ReadTimeout    time.Duration     // net.Conn.SetReadTimeout value for connections, defaults to 2 seconds
+       WriteTimeout   time.Duration     // net.Conn.SetWriteTimeout value for connections, defaults to 2 seconds
+       TsigSecret     map[string]string // Secret(s) for Tsig map[<zonename>]<base64 secret>, zonename must be fully qualified
+       tsigTimersOnly bool
+}
+
+// Think we need to away to stop the transfer
+
+// In performs an incoming transfer with the server in a.
+// If you would like to set the source IP, or some other attribute
+// of a Dialer for a Transfer, you can do so by specifying the attributes
+// in the Transfer.Conn:
+//
+//     d := net.Dialer{LocalAddr: transfer_source}
+//     con, err := d.Dial("tcp", master)
+//     dnscon := &dns.Conn{Conn:con}
+//     transfer = &dns.Transfer{Conn: dnscon}
+//     channel, err := transfer.In(message, master)
+//
+func (t *Transfer) In(q *Msg, a string) (env chan *Envelope, err error) {
+       timeout := dnsTimeout
+       if t.DialTimeout != 0 {
+               timeout = t.DialTimeout
+       }
+       if t.Conn == nil {
+               t.Conn, err = DialTimeout("tcp", a, timeout)
+               if err != nil {
+                       return nil, err
+               }
+       }
+       if err := t.WriteMsg(q); err != nil {
+               return nil, err
+       }
+       env = make(chan *Envelope)
+       go func() {
+               if q.Question[0].Qtype == TypeAXFR {
+                       go t.inAxfr(q.Id, env)
+                       return
+               }
+               if q.Question[0].Qtype == TypeIXFR {
+                       go t.inIxfr(q.Id, env)
+                       return
+               }
+       }()
+       return env, nil
+}
+
+func (t *Transfer) inAxfr(id uint16, c chan *Envelope) {
+       first := true
+       defer t.Close()
+       defer close(c)
+       timeout := dnsTimeout
+       if t.ReadTimeout != 0 {
+               timeout = t.ReadTimeout
+       }
+       for {
+               t.Conn.SetReadDeadline(time.Now().Add(timeout))
+               in, err := t.ReadMsg()
+               if err != nil {
+                       c <- &Envelope{nil, err}
+                       return
+               }
+               if id != in.Id {
+                       c <- &Envelope{in.Answer, ErrId}
+                       return
+               }
+               if first {
+                       if !isSOAFirst(in) {
+                               c <- &Envelope{in.Answer, ErrSoa}
+                               return
+                       }
+                       first = !first
+                       // only one answer that is SOA, receive more
+                       if len(in.Answer) == 1 {
+                               t.tsigTimersOnly = true
+                               c <- &Envelope{in.Answer, nil}
+                               continue
+                       }
+               }
+
+               if !first {
+                       t.tsigTimersOnly = true // Subsequent envelopes use this.
+                       if isSOALast(in) {
+                               c <- &Envelope{in.Answer, nil}
+                               return
+                       }
+                       c <- &Envelope{in.Answer, nil}
+               }
+       }
+}
+
+func (t *Transfer) inIxfr(id uint16, c chan *Envelope) {
+       serial := uint32(0) // The first serial seen is the current server serial
+       first := true
+       defer t.Close()
+       defer close(c)
+       timeout := dnsTimeout
+       if t.ReadTimeout != 0 {
+               timeout = t.ReadTimeout
+       }
+       for {
+               t.SetReadDeadline(time.Now().Add(timeout))
+               in, err := t.ReadMsg()
+               if err != nil {
+                       c <- &Envelope{nil, err}
+                       return
+               }
+               if id != in.Id {
+                       c <- &Envelope{in.Answer, ErrId}
+                       return
+               }
+               if first {
+                       // A single SOA RR signals "no changes"
+                       if len(in.Answer) == 1 && isSOAFirst(in) {
+                               c <- &Envelope{in.Answer, nil}
+                               return
+                       }
+
+                       // Check if the returned answer is ok
+                       if !isSOAFirst(in) {
+                               c <- &Envelope{in.Answer, ErrSoa}
+                               return
+                       }
+                       // This serial is important
+                       serial = in.Answer[0].(*SOA).Serial
+                       first = !first
+               }
+
+               // Now we need to check each message for SOA records, to see what we need to do
+               if !first {
+                       t.tsigTimersOnly = true
+                       // If the last record in the IXFR contains the servers' SOA,  we should quit
+                       if v, ok := in.Answer[len(in.Answer)-1].(*SOA); ok {
+                               if v.Serial == serial {
+                                       c <- &Envelope{in.Answer, nil}
+                                       return
+                               }
+                       }
+                       c <- &Envelope{in.Answer, nil}
+               }
+       }
+}
+
+// Out performs an outgoing transfer with the client connecting in w.
+// Basic use pattern:
+//
+//     ch := make(chan *dns.Envelope)
+//     tr := new(dns.Transfer)
+//     go tr.Out(w, r, ch)
+//     ch <- &dns.Envelope{RR: []dns.RR{soa, rr1, rr2, rr3, soa}}
+//     close(ch)
+//     w.Hijack()
+//     // w.Close() // Client closes connection
+//
+// The server is responsible for sending the correct sequence of RRs through the
+// channel ch.
+func (t *Transfer) Out(w ResponseWriter, q *Msg, ch chan *Envelope) error {
+       for x := range ch {
+               r := new(Msg)
+               // Compress?
+               r.SetReply(q)
+               r.Authoritative = true
+               // assume it fits TODO(miek): fix
+               r.Answer = append(r.Answer, x.RR...)
+               if err := w.WriteMsg(r); err != nil {
+                       return err
+               }
+       }
+       w.TsigTimersOnly(true)
+       return nil
+}
+
+// ReadMsg reads a message from the transfer connection t.
+func (t *Transfer) ReadMsg() (*Msg, error) {
+       m := new(Msg)
+       p := make([]byte, MaxMsgSize)
+       n, err := t.Read(p)
+       if err != nil && n == 0 {
+               return nil, err
+       }
+       p = p[:n]
+       if err := m.Unpack(p); err != nil {
+               return nil, err
+       }
+       if ts := m.IsTsig(); ts != nil && t.TsigSecret != nil {
+               if _, ok := t.TsigSecret[ts.Hdr.Name]; !ok {
+                       return m, ErrSecret
+               }
+               // Need to work on the original message p, as that was used to calculate the tsig.
+               err = TsigVerify(p, t.TsigSecret[ts.Hdr.Name], t.tsigRequestMAC, t.tsigTimersOnly)
+               t.tsigRequestMAC = ts.MAC
+       }
+       return m, err
+}
+
+// WriteMsg writes a message through the transfer connection t.
+func (t *Transfer) WriteMsg(m *Msg) (err error) {
+       var out []byte
+       if ts := m.IsTsig(); ts != nil && t.TsigSecret != nil {
+               if _, ok := t.TsigSecret[ts.Hdr.Name]; !ok {
+                       return ErrSecret
+               }
+               out, t.tsigRequestMAC, err = TsigGenerate(m, t.TsigSecret[ts.Hdr.Name], t.tsigRequestMAC, t.tsigTimersOnly)
+       } else {
+               out, err = m.Pack()
+       }
+       if err != nil {
+               return err
+       }
+       if _, err = t.Write(out); err != nil {
+               return err
+       }
+       return nil
+}
+
+func isSOAFirst(in *Msg) bool {
+       if len(in.Answer) > 0 {
+               return in.Answer[0].Header().Rrtype == TypeSOA
+       }
+       return false
+}
+
+func isSOALast(in *Msg) bool {
+       if len(in.Answer) > 0 {
+               return in.Answer[len(in.Answer)-1].Header().Rrtype == TypeSOA
+       }
+       return false
+}
diff --git a/vendor/github.com/miekg/dns/zmsg.go b/vendor/github.com/miekg/dns/zmsg.go
new file mode 100644 (file)
index 0000000..e5f3cf2
--- /dev/null
@@ -0,0 +1,3462 @@
+// *** DO NOT MODIFY ***
+// AUTOGENERATED BY go generate from msg_generate.go
+
+package dns
+
+// pack*() functions
+
+func (rr *A) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
+       off, err := rr.Hdr.pack(msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       headerEnd := off
+       off, err = packDataA(rr.A, msg, off)
+       if err != nil {
+               return off, err
+       }
+       rr.Header().Rdlength = uint16(off - headerEnd)
+       return off, nil
+}
+
+func (rr *AAAA) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
+       off, err := rr.Hdr.pack(msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       headerEnd := off
+       off, err = packDataAAAA(rr.AAAA, msg, off)
+       if err != nil {
+               return off, err
+       }
+       rr.Header().Rdlength = uint16(off - headerEnd)
+       return off, nil
+}
+
+func (rr *AFSDB) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
+       off, err := rr.Hdr.pack(msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       headerEnd := off
+       off, err = packUint16(rr.Subtype, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = PackDomainName(rr.Hostname, msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       rr.Header().Rdlength = uint16(off - headerEnd)
+       return off, nil
+}
+
+func (rr *ANY) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
+       off, err := rr.Hdr.pack(msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       headerEnd := off
+       rr.Header().Rdlength = uint16(off - headerEnd)
+       return off, nil
+}
+
+func (rr *CAA) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
+       off, err := rr.Hdr.pack(msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       headerEnd := off
+       off, err = packUint8(rr.Flag, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packString(rr.Tag, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packStringOctet(rr.Value, msg, off)
+       if err != nil {
+               return off, err
+       }
+       rr.Header().Rdlength = uint16(off - headerEnd)
+       return off, nil
+}
+
+func (rr *CDNSKEY) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
+       off, err := rr.Hdr.pack(msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       headerEnd := off
+       off, err = packUint16(rr.Flags, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint8(rr.Protocol, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint8(rr.Algorithm, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packStringBase64(rr.PublicKey, msg, off)
+       if err != nil {
+               return off, err
+       }
+       rr.Header().Rdlength = uint16(off - headerEnd)
+       return off, nil
+}
+
+func (rr *CDS) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
+       off, err := rr.Hdr.pack(msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       headerEnd := off
+       off, err = packUint16(rr.KeyTag, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint8(rr.Algorithm, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint8(rr.DigestType, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packStringHex(rr.Digest, msg, off)
+       if err != nil {
+               return off, err
+       }
+       rr.Header().Rdlength = uint16(off - headerEnd)
+       return off, nil
+}
+
+func (rr *CERT) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
+       off, err := rr.Hdr.pack(msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       headerEnd := off
+       off, err = packUint16(rr.Type, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint16(rr.KeyTag, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint8(rr.Algorithm, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packStringBase64(rr.Certificate, msg, off)
+       if err != nil {
+               return off, err
+       }
+       rr.Header().Rdlength = uint16(off - headerEnd)
+       return off, nil
+}
+
+func (rr *CNAME) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
+       off, err := rr.Hdr.pack(msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       headerEnd := off
+       off, err = PackDomainName(rr.Target, msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       rr.Header().Rdlength = uint16(off - headerEnd)
+       return off, nil
+}
+
+func (rr *DHCID) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
+       off, err := rr.Hdr.pack(msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       headerEnd := off
+       off, err = packStringBase64(rr.Digest, msg, off)
+       if err != nil {
+               return off, err
+       }
+       rr.Header().Rdlength = uint16(off - headerEnd)
+       return off, nil
+}
+
+func (rr *DLV) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
+       off, err := rr.Hdr.pack(msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       headerEnd := off
+       off, err = packUint16(rr.KeyTag, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint8(rr.Algorithm, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint8(rr.DigestType, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packStringHex(rr.Digest, msg, off)
+       if err != nil {
+               return off, err
+       }
+       rr.Header().Rdlength = uint16(off - headerEnd)
+       return off, nil
+}
+
+func (rr *DNAME) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
+       off, err := rr.Hdr.pack(msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       headerEnd := off
+       off, err = PackDomainName(rr.Target, msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       rr.Header().Rdlength = uint16(off - headerEnd)
+       return off, nil
+}
+
+func (rr *DNSKEY) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
+       off, err := rr.Hdr.pack(msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       headerEnd := off
+       off, err = packUint16(rr.Flags, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint8(rr.Protocol, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint8(rr.Algorithm, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packStringBase64(rr.PublicKey, msg, off)
+       if err != nil {
+               return off, err
+       }
+       rr.Header().Rdlength = uint16(off - headerEnd)
+       return off, nil
+}
+
+func (rr *DS) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
+       off, err := rr.Hdr.pack(msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       headerEnd := off
+       off, err = packUint16(rr.KeyTag, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint8(rr.Algorithm, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint8(rr.DigestType, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packStringHex(rr.Digest, msg, off)
+       if err != nil {
+               return off, err
+       }
+       rr.Header().Rdlength = uint16(off - headerEnd)
+       return off, nil
+}
+
+func (rr *EID) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
+       off, err := rr.Hdr.pack(msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       headerEnd := off
+       off, err = packStringHex(rr.Endpoint, msg, off)
+       if err != nil {
+               return off, err
+       }
+       rr.Header().Rdlength = uint16(off - headerEnd)
+       return off, nil
+}
+
+func (rr *EUI48) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
+       off, err := rr.Hdr.pack(msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       headerEnd := off
+       off, err = packUint48(rr.Address, msg, off)
+       if err != nil {
+               return off, err
+       }
+       rr.Header().Rdlength = uint16(off - headerEnd)
+       return off, nil
+}
+
+func (rr *EUI64) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
+       off, err := rr.Hdr.pack(msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       headerEnd := off
+       off, err = packUint64(rr.Address, msg, off)
+       if err != nil {
+               return off, err
+       }
+       rr.Header().Rdlength = uint16(off - headerEnd)
+       return off, nil
+}
+
+func (rr *GID) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
+       off, err := rr.Hdr.pack(msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       headerEnd := off
+       off, err = packUint32(rr.Gid, msg, off)
+       if err != nil {
+               return off, err
+       }
+       rr.Header().Rdlength = uint16(off - headerEnd)
+       return off, nil
+}
+
+func (rr *GPOS) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
+       off, err := rr.Hdr.pack(msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       headerEnd := off
+       off, err = packString(rr.Longitude, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packString(rr.Latitude, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packString(rr.Altitude, msg, off)
+       if err != nil {
+               return off, err
+       }
+       rr.Header().Rdlength = uint16(off - headerEnd)
+       return off, nil
+}
+
+func (rr *HINFO) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
+       off, err := rr.Hdr.pack(msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       headerEnd := off
+       off, err = packString(rr.Cpu, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packString(rr.Os, msg, off)
+       if err != nil {
+               return off, err
+       }
+       rr.Header().Rdlength = uint16(off - headerEnd)
+       return off, nil
+}
+
+func (rr *HIP) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
+       off, err := rr.Hdr.pack(msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       headerEnd := off
+       off, err = packUint8(rr.HitLength, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint8(rr.PublicKeyAlgorithm, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint16(rr.PublicKeyLength, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packStringHex(rr.Hit, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packStringBase64(rr.PublicKey, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packDataDomainNames(rr.RendezvousServers, msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       rr.Header().Rdlength = uint16(off - headerEnd)
+       return off, nil
+}
+
+func (rr *KEY) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
+       off, err := rr.Hdr.pack(msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       headerEnd := off
+       off, err = packUint16(rr.Flags, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint8(rr.Protocol, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint8(rr.Algorithm, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packStringBase64(rr.PublicKey, msg, off)
+       if err != nil {
+               return off, err
+       }
+       rr.Header().Rdlength = uint16(off - headerEnd)
+       return off, nil
+}
+
+func (rr *KX) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
+       off, err := rr.Hdr.pack(msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       headerEnd := off
+       off, err = packUint16(rr.Preference, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = PackDomainName(rr.Exchanger, msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       rr.Header().Rdlength = uint16(off - headerEnd)
+       return off, nil
+}
+
+func (rr *L32) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
+       off, err := rr.Hdr.pack(msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       headerEnd := off
+       off, err = packUint16(rr.Preference, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packDataA(rr.Locator32, msg, off)
+       if err != nil {
+               return off, err
+       }
+       rr.Header().Rdlength = uint16(off - headerEnd)
+       return off, nil
+}
+
+func (rr *L64) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
+       off, err := rr.Hdr.pack(msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       headerEnd := off
+       off, err = packUint16(rr.Preference, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint64(rr.Locator64, msg, off)
+       if err != nil {
+               return off, err
+       }
+       rr.Header().Rdlength = uint16(off - headerEnd)
+       return off, nil
+}
+
+func (rr *LOC) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
+       off, err := rr.Hdr.pack(msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       headerEnd := off
+       off, err = packUint8(rr.Version, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint8(rr.Size, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint8(rr.HorizPre, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint8(rr.VertPre, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint32(rr.Latitude, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint32(rr.Longitude, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint32(rr.Altitude, msg, off)
+       if err != nil {
+               return off, err
+       }
+       rr.Header().Rdlength = uint16(off - headerEnd)
+       return off, nil
+}
+
+func (rr *LP) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
+       off, err := rr.Hdr.pack(msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       headerEnd := off
+       off, err = packUint16(rr.Preference, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = PackDomainName(rr.Fqdn, msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       rr.Header().Rdlength = uint16(off - headerEnd)
+       return off, nil
+}
+
+func (rr *MB) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
+       off, err := rr.Hdr.pack(msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       headerEnd := off
+       off, err = PackDomainName(rr.Mb, msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       rr.Header().Rdlength = uint16(off - headerEnd)
+       return off, nil
+}
+
+func (rr *MD) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
+       off, err := rr.Hdr.pack(msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       headerEnd := off
+       off, err = PackDomainName(rr.Md, msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       rr.Header().Rdlength = uint16(off - headerEnd)
+       return off, nil
+}
+
+func (rr *MF) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
+       off, err := rr.Hdr.pack(msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       headerEnd := off
+       off, err = PackDomainName(rr.Mf, msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       rr.Header().Rdlength = uint16(off - headerEnd)
+       return off, nil
+}
+
+func (rr *MG) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
+       off, err := rr.Hdr.pack(msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       headerEnd := off
+       off, err = PackDomainName(rr.Mg, msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       rr.Header().Rdlength = uint16(off - headerEnd)
+       return off, nil
+}
+
+func (rr *MINFO) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
+       off, err := rr.Hdr.pack(msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       headerEnd := off
+       off, err = PackDomainName(rr.Rmail, msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       off, err = PackDomainName(rr.Email, msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       rr.Header().Rdlength = uint16(off - headerEnd)
+       return off, nil
+}
+
+func (rr *MR) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
+       off, err := rr.Hdr.pack(msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       headerEnd := off
+       off, err = PackDomainName(rr.Mr, msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       rr.Header().Rdlength = uint16(off - headerEnd)
+       return off, nil
+}
+
+func (rr *MX) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
+       off, err := rr.Hdr.pack(msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       headerEnd := off
+       off, err = packUint16(rr.Preference, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = PackDomainName(rr.Mx, msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       rr.Header().Rdlength = uint16(off - headerEnd)
+       return off, nil
+}
+
+func (rr *NAPTR) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
+       off, err := rr.Hdr.pack(msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       headerEnd := off
+       off, err = packUint16(rr.Order, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint16(rr.Preference, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packString(rr.Flags, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packString(rr.Service, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packString(rr.Regexp, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = PackDomainName(rr.Replacement, msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       rr.Header().Rdlength = uint16(off - headerEnd)
+       return off, nil
+}
+
+func (rr *NID) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
+       off, err := rr.Hdr.pack(msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       headerEnd := off
+       off, err = packUint16(rr.Preference, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint64(rr.NodeID, msg, off)
+       if err != nil {
+               return off, err
+       }
+       rr.Header().Rdlength = uint16(off - headerEnd)
+       return off, nil
+}
+
+func (rr *NIMLOC) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
+       off, err := rr.Hdr.pack(msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       headerEnd := off
+       off, err = packStringHex(rr.Locator, msg, off)
+       if err != nil {
+               return off, err
+       }
+       rr.Header().Rdlength = uint16(off - headerEnd)
+       return off, nil
+}
+
+func (rr *NINFO) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
+       off, err := rr.Hdr.pack(msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       headerEnd := off
+       off, err = packStringTxt(rr.ZSData, msg, off)
+       if err != nil {
+               return off, err
+       }
+       rr.Header().Rdlength = uint16(off - headerEnd)
+       return off, nil
+}
+
+func (rr *NS) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
+       off, err := rr.Hdr.pack(msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       headerEnd := off
+       off, err = PackDomainName(rr.Ns, msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       rr.Header().Rdlength = uint16(off - headerEnd)
+       return off, nil
+}
+
+func (rr *NSAPPTR) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
+       off, err := rr.Hdr.pack(msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       headerEnd := off
+       off, err = PackDomainName(rr.Ptr, msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       rr.Header().Rdlength = uint16(off - headerEnd)
+       return off, nil
+}
+
+func (rr *NSEC) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
+       off, err := rr.Hdr.pack(msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       headerEnd := off
+       off, err = PackDomainName(rr.NextDomain, msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       off, err = packDataNsec(rr.TypeBitMap, msg, off)
+       if err != nil {
+               return off, err
+       }
+       rr.Header().Rdlength = uint16(off - headerEnd)
+       return off, nil
+}
+
+func (rr *NSEC3) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
+       off, err := rr.Hdr.pack(msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       headerEnd := off
+       off, err = packUint8(rr.Hash, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint8(rr.Flags, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint16(rr.Iterations, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint8(rr.SaltLength, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packStringHex(rr.Salt, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint8(rr.HashLength, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packStringBase32(rr.NextDomain, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packDataNsec(rr.TypeBitMap, msg, off)
+       if err != nil {
+               return off, err
+       }
+       rr.Header().Rdlength = uint16(off - headerEnd)
+       return off, nil
+}
+
+func (rr *NSEC3PARAM) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
+       off, err := rr.Hdr.pack(msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       headerEnd := off
+       off, err = packUint8(rr.Hash, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint8(rr.Flags, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint16(rr.Iterations, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint8(rr.SaltLength, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packStringHex(rr.Salt, msg, off)
+       if err != nil {
+               return off, err
+       }
+       rr.Header().Rdlength = uint16(off - headerEnd)
+       return off, nil
+}
+
+func (rr *OPENPGPKEY) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
+       off, err := rr.Hdr.pack(msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       headerEnd := off
+       off, err = packStringBase64(rr.PublicKey, msg, off)
+       if err != nil {
+               return off, err
+       }
+       rr.Header().Rdlength = uint16(off - headerEnd)
+       return off, nil
+}
+
+func (rr *OPT) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
+       off, err := rr.Hdr.pack(msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       headerEnd := off
+       off, err = packDataOpt(rr.Option, msg, off)
+       if err != nil {
+               return off, err
+       }
+       rr.Header().Rdlength = uint16(off - headerEnd)
+       return off, nil
+}
+
+func (rr *PTR) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
+       off, err := rr.Hdr.pack(msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       headerEnd := off
+       off, err = PackDomainName(rr.Ptr, msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       rr.Header().Rdlength = uint16(off - headerEnd)
+       return off, nil
+}
+
+func (rr *PX) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
+       off, err := rr.Hdr.pack(msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       headerEnd := off
+       off, err = packUint16(rr.Preference, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = PackDomainName(rr.Map822, msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       off, err = PackDomainName(rr.Mapx400, msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       rr.Header().Rdlength = uint16(off - headerEnd)
+       return off, nil
+}
+
+func (rr *RFC3597) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
+       off, err := rr.Hdr.pack(msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       headerEnd := off
+       off, err = packStringHex(rr.Rdata, msg, off)
+       if err != nil {
+               return off, err
+       }
+       rr.Header().Rdlength = uint16(off - headerEnd)
+       return off, nil
+}
+
+func (rr *RKEY) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
+       off, err := rr.Hdr.pack(msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       headerEnd := off
+       off, err = packUint16(rr.Flags, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint8(rr.Protocol, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint8(rr.Algorithm, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packStringBase64(rr.PublicKey, msg, off)
+       if err != nil {
+               return off, err
+       }
+       rr.Header().Rdlength = uint16(off - headerEnd)
+       return off, nil
+}
+
+func (rr *RP) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
+       off, err := rr.Hdr.pack(msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       headerEnd := off
+       off, err = PackDomainName(rr.Mbox, msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       off, err = PackDomainName(rr.Txt, msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       rr.Header().Rdlength = uint16(off - headerEnd)
+       return off, nil
+}
+
+func (rr *RRSIG) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
+       off, err := rr.Hdr.pack(msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       headerEnd := off
+       off, err = packUint16(rr.TypeCovered, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint8(rr.Algorithm, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint8(rr.Labels, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint32(rr.OrigTtl, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint32(rr.Expiration, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint32(rr.Inception, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint16(rr.KeyTag, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = PackDomainName(rr.SignerName, msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       off, err = packStringBase64(rr.Signature, msg, off)
+       if err != nil {
+               return off, err
+       }
+       rr.Header().Rdlength = uint16(off - headerEnd)
+       return off, nil
+}
+
+func (rr *RT) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
+       off, err := rr.Hdr.pack(msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       headerEnd := off
+       off, err = packUint16(rr.Preference, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = PackDomainName(rr.Host, msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       rr.Header().Rdlength = uint16(off - headerEnd)
+       return off, nil
+}
+
+func (rr *SIG) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
+       off, err := rr.Hdr.pack(msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       headerEnd := off
+       off, err = packUint16(rr.TypeCovered, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint8(rr.Algorithm, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint8(rr.Labels, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint32(rr.OrigTtl, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint32(rr.Expiration, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint32(rr.Inception, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint16(rr.KeyTag, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = PackDomainName(rr.SignerName, msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       off, err = packStringBase64(rr.Signature, msg, off)
+       if err != nil {
+               return off, err
+       }
+       rr.Header().Rdlength = uint16(off - headerEnd)
+       return off, nil
+}
+
+func (rr *SOA) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
+       off, err := rr.Hdr.pack(msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       headerEnd := off
+       off, err = PackDomainName(rr.Ns, msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       off, err = PackDomainName(rr.Mbox, msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint32(rr.Serial, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint32(rr.Refresh, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint32(rr.Retry, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint32(rr.Expire, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint32(rr.Minttl, msg, off)
+       if err != nil {
+               return off, err
+       }
+       rr.Header().Rdlength = uint16(off - headerEnd)
+       return off, nil
+}
+
+func (rr *SPF) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
+       off, err := rr.Hdr.pack(msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       headerEnd := off
+       off, err = packStringTxt(rr.Txt, msg, off)
+       if err != nil {
+               return off, err
+       }
+       rr.Header().Rdlength = uint16(off - headerEnd)
+       return off, nil
+}
+
+func (rr *SRV) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
+       off, err := rr.Hdr.pack(msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       headerEnd := off
+       off, err = packUint16(rr.Priority, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint16(rr.Weight, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint16(rr.Port, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = PackDomainName(rr.Target, msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       rr.Header().Rdlength = uint16(off - headerEnd)
+       return off, nil
+}
+
+func (rr *SSHFP) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
+       off, err := rr.Hdr.pack(msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       headerEnd := off
+       off, err = packUint8(rr.Algorithm, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint8(rr.Type, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packStringHex(rr.FingerPrint, msg, off)
+       if err != nil {
+               return off, err
+       }
+       rr.Header().Rdlength = uint16(off - headerEnd)
+       return off, nil
+}
+
+func (rr *TA) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
+       off, err := rr.Hdr.pack(msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       headerEnd := off
+       off, err = packUint16(rr.KeyTag, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint8(rr.Algorithm, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint8(rr.DigestType, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packStringHex(rr.Digest, msg, off)
+       if err != nil {
+               return off, err
+       }
+       rr.Header().Rdlength = uint16(off - headerEnd)
+       return off, nil
+}
+
+func (rr *TALINK) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
+       off, err := rr.Hdr.pack(msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       headerEnd := off
+       off, err = PackDomainName(rr.PreviousName, msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       off, err = PackDomainName(rr.NextName, msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       rr.Header().Rdlength = uint16(off - headerEnd)
+       return off, nil
+}
+
+func (rr *TKEY) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
+       off, err := rr.Hdr.pack(msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       headerEnd := off
+       off, err = PackDomainName(rr.Algorithm, msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint32(rr.Inception, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint32(rr.Expiration, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint16(rr.Mode, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint16(rr.Error, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint16(rr.KeySize, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packString(rr.Key, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint16(rr.OtherLen, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packString(rr.OtherData, msg, off)
+       if err != nil {
+               return off, err
+       }
+       rr.Header().Rdlength = uint16(off - headerEnd)
+       return off, nil
+}
+
+func (rr *TLSA) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
+       off, err := rr.Hdr.pack(msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       headerEnd := off
+       off, err = packUint8(rr.Usage, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint8(rr.Selector, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint8(rr.MatchingType, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packStringHex(rr.Certificate, msg, off)
+       if err != nil {
+               return off, err
+       }
+       rr.Header().Rdlength = uint16(off - headerEnd)
+       return off, nil
+}
+
+func (rr *TSIG) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
+       off, err := rr.Hdr.pack(msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       headerEnd := off
+       off, err = PackDomainName(rr.Algorithm, msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint48(rr.TimeSigned, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint16(rr.Fudge, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint16(rr.MACSize, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packStringHex(rr.MAC, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint16(rr.OrigId, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint16(rr.Error, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint16(rr.OtherLen, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packStringHex(rr.OtherData, msg, off)
+       if err != nil {
+               return off, err
+       }
+       rr.Header().Rdlength = uint16(off - headerEnd)
+       return off, nil
+}
+
+func (rr *TXT) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
+       off, err := rr.Hdr.pack(msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       headerEnd := off
+       off, err = packStringTxt(rr.Txt, msg, off)
+       if err != nil {
+               return off, err
+       }
+       rr.Header().Rdlength = uint16(off - headerEnd)
+       return off, nil
+}
+
+func (rr *UID) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
+       off, err := rr.Hdr.pack(msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       headerEnd := off
+       off, err = packUint32(rr.Uid, msg, off)
+       if err != nil {
+               return off, err
+       }
+       rr.Header().Rdlength = uint16(off - headerEnd)
+       return off, nil
+}
+
+func (rr *UINFO) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
+       off, err := rr.Hdr.pack(msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       headerEnd := off
+       off, err = packString(rr.Uinfo, msg, off)
+       if err != nil {
+               return off, err
+       }
+       rr.Header().Rdlength = uint16(off - headerEnd)
+       return off, nil
+}
+
+func (rr *URI) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
+       off, err := rr.Hdr.pack(msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       headerEnd := off
+       off, err = packUint16(rr.Priority, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packUint16(rr.Weight, msg, off)
+       if err != nil {
+               return off, err
+       }
+       off, err = packStringOctet(rr.Target, msg, off)
+       if err != nil {
+               return off, err
+       }
+       rr.Header().Rdlength = uint16(off - headerEnd)
+       return off, nil
+}
+
+func (rr *X25) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
+       off, err := rr.Hdr.pack(msg, off, compression, compress)
+       if err != nil {
+               return off, err
+       }
+       headerEnd := off
+       off, err = packString(rr.PSDNAddress, msg, off)
+       if err != nil {
+               return off, err
+       }
+       rr.Header().Rdlength = uint16(off - headerEnd)
+       return off, nil
+}
+
+// unpack*() functions
+
+func unpackA(h RR_Header, msg []byte, off int) (RR, int, error) {
+       rr := new(A)
+       rr.Hdr = h
+       if noRdata(h) {
+               return rr, off, nil
+       }
+       var err error
+       rdStart := off
+       _ = rdStart
+
+       rr.A, off, err = unpackDataA(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       return rr, off, err
+}
+
+func unpackAAAA(h RR_Header, msg []byte, off int) (RR, int, error) {
+       rr := new(AAAA)
+       rr.Hdr = h
+       if noRdata(h) {
+               return rr, off, nil
+       }
+       var err error
+       rdStart := off
+       _ = rdStart
+
+       rr.AAAA, off, err = unpackDataAAAA(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       return rr, off, err
+}
+
+func unpackAFSDB(h RR_Header, msg []byte, off int) (RR, int, error) {
+       rr := new(AFSDB)
+       rr.Hdr = h
+       if noRdata(h) {
+               return rr, off, nil
+       }
+       var err error
+       rdStart := off
+       _ = rdStart
+
+       rr.Subtype, off, err = unpackUint16(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.Hostname, off, err = UnpackDomainName(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       return rr, off, err
+}
+
+func unpackANY(h RR_Header, msg []byte, off int) (RR, int, error) {
+       rr := new(ANY)
+       rr.Hdr = h
+       if noRdata(h) {
+               return rr, off, nil
+       }
+       var err error
+       rdStart := off
+       _ = rdStart
+
+       return rr, off, err
+}
+
+func unpackCAA(h RR_Header, msg []byte, off int) (RR, int, error) {
+       rr := new(CAA)
+       rr.Hdr = h
+       if noRdata(h) {
+               return rr, off, nil
+       }
+       var err error
+       rdStart := off
+       _ = rdStart
+
+       rr.Flag, off, err = unpackUint8(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.Tag, off, err = unpackString(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.Value, off, err = unpackStringOctet(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       return rr, off, err
+}
+
+func unpackCDNSKEY(h RR_Header, msg []byte, off int) (RR, int, error) {
+       rr := new(CDNSKEY)
+       rr.Hdr = h
+       if noRdata(h) {
+               return rr, off, nil
+       }
+       var err error
+       rdStart := off
+       _ = rdStart
+
+       rr.Flags, off, err = unpackUint16(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.Protocol, off, err = unpackUint8(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.Algorithm, off, err = unpackUint8(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.PublicKey, off, err = unpackStringBase64(msg, off, rdStart+int(rr.Hdr.Rdlength))
+       if err != nil {
+               return rr, off, err
+       }
+       return rr, off, err
+}
+
+func unpackCDS(h RR_Header, msg []byte, off int) (RR, int, error) {
+       rr := new(CDS)
+       rr.Hdr = h
+       if noRdata(h) {
+               return rr, off, nil
+       }
+       var err error
+       rdStart := off
+       _ = rdStart
+
+       rr.KeyTag, off, err = unpackUint16(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.Algorithm, off, err = unpackUint8(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.DigestType, off, err = unpackUint8(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.Digest, off, err = unpackStringHex(msg, off, rdStart+int(rr.Hdr.Rdlength))
+       if err != nil {
+               return rr, off, err
+       }
+       return rr, off, err
+}
+
+func unpackCERT(h RR_Header, msg []byte, off int) (RR, int, error) {
+       rr := new(CERT)
+       rr.Hdr = h
+       if noRdata(h) {
+               return rr, off, nil
+       }
+       var err error
+       rdStart := off
+       _ = rdStart
+
+       rr.Type, off, err = unpackUint16(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.KeyTag, off, err = unpackUint16(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.Algorithm, off, err = unpackUint8(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.Certificate, off, err = unpackStringBase64(msg, off, rdStart+int(rr.Hdr.Rdlength))
+       if err != nil {
+               return rr, off, err
+       }
+       return rr, off, err
+}
+
+func unpackCNAME(h RR_Header, msg []byte, off int) (RR, int, error) {
+       rr := new(CNAME)
+       rr.Hdr = h
+       if noRdata(h) {
+               return rr, off, nil
+       }
+       var err error
+       rdStart := off
+       _ = rdStart
+
+       rr.Target, off, err = UnpackDomainName(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       return rr, off, err
+}
+
+func unpackDHCID(h RR_Header, msg []byte, off int) (RR, int, error) {
+       rr := new(DHCID)
+       rr.Hdr = h
+       if noRdata(h) {
+               return rr, off, nil
+       }
+       var err error
+       rdStart := off
+       _ = rdStart
+
+       rr.Digest, off, err = unpackStringBase64(msg, off, rdStart+int(rr.Hdr.Rdlength))
+       if err != nil {
+               return rr, off, err
+       }
+       return rr, off, err
+}
+
+func unpackDLV(h RR_Header, msg []byte, off int) (RR, int, error) {
+       rr := new(DLV)
+       rr.Hdr = h
+       if noRdata(h) {
+               return rr, off, nil
+       }
+       var err error
+       rdStart := off
+       _ = rdStart
+
+       rr.KeyTag, off, err = unpackUint16(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.Algorithm, off, err = unpackUint8(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.DigestType, off, err = unpackUint8(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.Digest, off, err = unpackStringHex(msg, off, rdStart+int(rr.Hdr.Rdlength))
+       if err != nil {
+               return rr, off, err
+       }
+       return rr, off, err
+}
+
+func unpackDNAME(h RR_Header, msg []byte, off int) (RR, int, error) {
+       rr := new(DNAME)
+       rr.Hdr = h
+       if noRdata(h) {
+               return rr, off, nil
+       }
+       var err error
+       rdStart := off
+       _ = rdStart
+
+       rr.Target, off, err = UnpackDomainName(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       return rr, off, err
+}
+
+func unpackDNSKEY(h RR_Header, msg []byte, off int) (RR, int, error) {
+       rr := new(DNSKEY)
+       rr.Hdr = h
+       if noRdata(h) {
+               return rr, off, nil
+       }
+       var err error
+       rdStart := off
+       _ = rdStart
+
+       rr.Flags, off, err = unpackUint16(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.Protocol, off, err = unpackUint8(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.Algorithm, off, err = unpackUint8(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.PublicKey, off, err = unpackStringBase64(msg, off, rdStart+int(rr.Hdr.Rdlength))
+       if err != nil {
+               return rr, off, err
+       }
+       return rr, off, err
+}
+
+func unpackDS(h RR_Header, msg []byte, off int) (RR, int, error) {
+       rr := new(DS)
+       rr.Hdr = h
+       if noRdata(h) {
+               return rr, off, nil
+       }
+       var err error
+       rdStart := off
+       _ = rdStart
+
+       rr.KeyTag, off, err = unpackUint16(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.Algorithm, off, err = unpackUint8(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.DigestType, off, err = unpackUint8(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.Digest, off, err = unpackStringHex(msg, off, rdStart+int(rr.Hdr.Rdlength))
+       if err != nil {
+               return rr, off, err
+       }
+       return rr, off, err
+}
+
+func unpackEID(h RR_Header, msg []byte, off int) (RR, int, error) {
+       rr := new(EID)
+       rr.Hdr = h
+       if noRdata(h) {
+               return rr, off, nil
+       }
+       var err error
+       rdStart := off
+       _ = rdStart
+
+       rr.Endpoint, off, err = unpackStringHex(msg, off, rdStart+int(rr.Hdr.Rdlength))
+       if err != nil {
+               return rr, off, err
+       }
+       return rr, off, err
+}
+
+func unpackEUI48(h RR_Header, msg []byte, off int) (RR, int, error) {
+       rr := new(EUI48)
+       rr.Hdr = h
+       if noRdata(h) {
+               return rr, off, nil
+       }
+       var err error
+       rdStart := off
+       _ = rdStart
+
+       rr.Address, off, err = unpackUint48(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       return rr, off, err
+}
+
+func unpackEUI64(h RR_Header, msg []byte, off int) (RR, int, error) {
+       rr := new(EUI64)
+       rr.Hdr = h
+       if noRdata(h) {
+               return rr, off, nil
+       }
+       var err error
+       rdStart := off
+       _ = rdStart
+
+       rr.Address, off, err = unpackUint64(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       return rr, off, err
+}
+
+func unpackGID(h RR_Header, msg []byte, off int) (RR, int, error) {
+       rr := new(GID)
+       rr.Hdr = h
+       if noRdata(h) {
+               return rr, off, nil
+       }
+       var err error
+       rdStart := off
+       _ = rdStart
+
+       rr.Gid, off, err = unpackUint32(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       return rr, off, err
+}
+
+func unpackGPOS(h RR_Header, msg []byte, off int) (RR, int, error) {
+       rr := new(GPOS)
+       rr.Hdr = h
+       if noRdata(h) {
+               return rr, off, nil
+       }
+       var err error
+       rdStart := off
+       _ = rdStart
+
+       rr.Longitude, off, err = unpackString(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.Latitude, off, err = unpackString(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.Altitude, off, err = unpackString(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       return rr, off, err
+}
+
+func unpackHINFO(h RR_Header, msg []byte, off int) (RR, int, error) {
+       rr := new(HINFO)
+       rr.Hdr = h
+       if noRdata(h) {
+               return rr, off, nil
+       }
+       var err error
+       rdStart := off
+       _ = rdStart
+
+       rr.Cpu, off, err = unpackString(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.Os, off, err = unpackString(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       return rr, off, err
+}
+
+func unpackHIP(h RR_Header, msg []byte, off int) (RR, int, error) {
+       rr := new(HIP)
+       rr.Hdr = h
+       if noRdata(h) {
+               return rr, off, nil
+       }
+       var err error
+       rdStart := off
+       _ = rdStart
+
+       rr.HitLength, off, err = unpackUint8(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.PublicKeyAlgorithm, off, err = unpackUint8(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.PublicKeyLength, off, err = unpackUint16(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.Hit, off, err = unpackStringHex(msg, off, off+int(rr.HitLength))
+       if err != nil {
+               return rr, off, err
+       }
+       rr.PublicKey, off, err = unpackStringBase64(msg, off, off+int(rr.PublicKeyLength))
+       if err != nil {
+               return rr, off, err
+       }
+       rr.RendezvousServers, off, err = unpackDataDomainNames(msg, off, rdStart+int(rr.Hdr.Rdlength))
+       if err != nil {
+               return rr, off, err
+       }
+       return rr, off, err
+}
+
+func unpackKEY(h RR_Header, msg []byte, off int) (RR, int, error) {
+       rr := new(KEY)
+       rr.Hdr = h
+       if noRdata(h) {
+               return rr, off, nil
+       }
+       var err error
+       rdStart := off
+       _ = rdStart
+
+       rr.Flags, off, err = unpackUint16(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.Protocol, off, err = unpackUint8(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.Algorithm, off, err = unpackUint8(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.PublicKey, off, err = unpackStringBase64(msg, off, rdStart+int(rr.Hdr.Rdlength))
+       if err != nil {
+               return rr, off, err
+       }
+       return rr, off, err
+}
+
+func unpackKX(h RR_Header, msg []byte, off int) (RR, int, error) {
+       rr := new(KX)
+       rr.Hdr = h
+       if noRdata(h) {
+               return rr, off, nil
+       }
+       var err error
+       rdStart := off
+       _ = rdStart
+
+       rr.Preference, off, err = unpackUint16(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.Exchanger, off, err = UnpackDomainName(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       return rr, off, err
+}
+
+func unpackL32(h RR_Header, msg []byte, off int) (RR, int, error) {
+       rr := new(L32)
+       rr.Hdr = h
+       if noRdata(h) {
+               return rr, off, nil
+       }
+       var err error
+       rdStart := off
+       _ = rdStart
+
+       rr.Preference, off, err = unpackUint16(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.Locator32, off, err = unpackDataA(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       return rr, off, err
+}
+
+func unpackL64(h RR_Header, msg []byte, off int) (RR, int, error) {
+       rr := new(L64)
+       rr.Hdr = h
+       if noRdata(h) {
+               return rr, off, nil
+       }
+       var err error
+       rdStart := off
+       _ = rdStart
+
+       rr.Preference, off, err = unpackUint16(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.Locator64, off, err = unpackUint64(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       return rr, off, err
+}
+
+func unpackLOC(h RR_Header, msg []byte, off int) (RR, int, error) {
+       rr := new(LOC)
+       rr.Hdr = h
+       if noRdata(h) {
+               return rr, off, nil
+       }
+       var err error
+       rdStart := off
+       _ = rdStart
+
+       rr.Version, off, err = unpackUint8(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.Size, off, err = unpackUint8(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.HorizPre, off, err = unpackUint8(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.VertPre, off, err = unpackUint8(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.Latitude, off, err = unpackUint32(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.Longitude, off, err = unpackUint32(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.Altitude, off, err = unpackUint32(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       return rr, off, err
+}
+
+func unpackLP(h RR_Header, msg []byte, off int) (RR, int, error) {
+       rr := new(LP)
+       rr.Hdr = h
+       if noRdata(h) {
+               return rr, off, nil
+       }
+       var err error
+       rdStart := off
+       _ = rdStart
+
+       rr.Preference, off, err = unpackUint16(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.Fqdn, off, err = UnpackDomainName(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       return rr, off, err
+}
+
+func unpackMB(h RR_Header, msg []byte, off int) (RR, int, error) {
+       rr := new(MB)
+       rr.Hdr = h
+       if noRdata(h) {
+               return rr, off, nil
+       }
+       var err error
+       rdStart := off
+       _ = rdStart
+
+       rr.Mb, off, err = UnpackDomainName(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       return rr, off, err
+}
+
+func unpackMD(h RR_Header, msg []byte, off int) (RR, int, error) {
+       rr := new(MD)
+       rr.Hdr = h
+       if noRdata(h) {
+               return rr, off, nil
+       }
+       var err error
+       rdStart := off
+       _ = rdStart
+
+       rr.Md, off, err = UnpackDomainName(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       return rr, off, err
+}
+
+func unpackMF(h RR_Header, msg []byte, off int) (RR, int, error) {
+       rr := new(MF)
+       rr.Hdr = h
+       if noRdata(h) {
+               return rr, off, nil
+       }
+       var err error
+       rdStart := off
+       _ = rdStart
+
+       rr.Mf, off, err = UnpackDomainName(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       return rr, off, err
+}
+
+func unpackMG(h RR_Header, msg []byte, off int) (RR, int, error) {
+       rr := new(MG)
+       rr.Hdr = h
+       if noRdata(h) {
+               return rr, off, nil
+       }
+       var err error
+       rdStart := off
+       _ = rdStart
+
+       rr.Mg, off, err = UnpackDomainName(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       return rr, off, err
+}
+
+func unpackMINFO(h RR_Header, msg []byte, off int) (RR, int, error) {
+       rr := new(MINFO)
+       rr.Hdr = h
+       if noRdata(h) {
+               return rr, off, nil
+       }
+       var err error
+       rdStart := off
+       _ = rdStart
+
+       rr.Rmail, off, err = UnpackDomainName(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.Email, off, err = UnpackDomainName(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       return rr, off, err
+}
+
+func unpackMR(h RR_Header, msg []byte, off int) (RR, int, error) {
+       rr := new(MR)
+       rr.Hdr = h
+       if noRdata(h) {
+               return rr, off, nil
+       }
+       var err error
+       rdStart := off
+       _ = rdStart
+
+       rr.Mr, off, err = UnpackDomainName(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       return rr, off, err
+}
+
+func unpackMX(h RR_Header, msg []byte, off int) (RR, int, error) {
+       rr := new(MX)
+       rr.Hdr = h
+       if noRdata(h) {
+               return rr, off, nil
+       }
+       var err error
+       rdStart := off
+       _ = rdStart
+
+       rr.Preference, off, err = unpackUint16(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.Mx, off, err = UnpackDomainName(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       return rr, off, err
+}
+
+func unpackNAPTR(h RR_Header, msg []byte, off int) (RR, int, error) {
+       rr := new(NAPTR)
+       rr.Hdr = h
+       if noRdata(h) {
+               return rr, off, nil
+       }
+       var err error
+       rdStart := off
+       _ = rdStart
+
+       rr.Order, off, err = unpackUint16(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.Preference, off, err = unpackUint16(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.Flags, off, err = unpackString(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.Service, off, err = unpackString(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.Regexp, off, err = unpackString(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.Replacement, off, err = UnpackDomainName(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       return rr, off, err
+}
+
+func unpackNID(h RR_Header, msg []byte, off int) (RR, int, error) {
+       rr := new(NID)
+       rr.Hdr = h
+       if noRdata(h) {
+               return rr, off, nil
+       }
+       var err error
+       rdStart := off
+       _ = rdStart
+
+       rr.Preference, off, err = unpackUint16(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.NodeID, off, err = unpackUint64(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       return rr, off, err
+}
+
+func unpackNIMLOC(h RR_Header, msg []byte, off int) (RR, int, error) {
+       rr := new(NIMLOC)
+       rr.Hdr = h
+       if noRdata(h) {
+               return rr, off, nil
+       }
+       var err error
+       rdStart := off
+       _ = rdStart
+
+       rr.Locator, off, err = unpackStringHex(msg, off, rdStart+int(rr.Hdr.Rdlength))
+       if err != nil {
+               return rr, off, err
+       }
+       return rr, off, err
+}
+
+func unpackNINFO(h RR_Header, msg []byte, off int) (RR, int, error) {
+       rr := new(NINFO)
+       rr.Hdr = h
+       if noRdata(h) {
+               return rr, off, nil
+       }
+       var err error
+       rdStart := off
+       _ = rdStart
+
+       rr.ZSData, off, err = unpackStringTxt(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       return rr, off, err
+}
+
+func unpackNS(h RR_Header, msg []byte, off int) (RR, int, error) {
+       rr := new(NS)
+       rr.Hdr = h
+       if noRdata(h) {
+               return rr, off, nil
+       }
+       var err error
+       rdStart := off
+       _ = rdStart
+
+       rr.Ns, off, err = UnpackDomainName(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       return rr, off, err
+}
+
+func unpackNSAPPTR(h RR_Header, msg []byte, off int) (RR, int, error) {
+       rr := new(NSAPPTR)
+       rr.Hdr = h
+       if noRdata(h) {
+               return rr, off, nil
+       }
+       var err error
+       rdStart := off
+       _ = rdStart
+
+       rr.Ptr, off, err = UnpackDomainName(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       return rr, off, err
+}
+
+func unpackNSEC(h RR_Header, msg []byte, off int) (RR, int, error) {
+       rr := new(NSEC)
+       rr.Hdr = h
+       if noRdata(h) {
+               return rr, off, nil
+       }
+       var err error
+       rdStart := off
+       _ = rdStart
+
+       rr.NextDomain, off, err = UnpackDomainName(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.TypeBitMap, off, err = unpackDataNsec(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       return rr, off, err
+}
+
+func unpackNSEC3(h RR_Header, msg []byte, off int) (RR, int, error) {
+       rr := new(NSEC3)
+       rr.Hdr = h
+       if noRdata(h) {
+               return rr, off, nil
+       }
+       var err error
+       rdStart := off
+       _ = rdStart
+
+       rr.Hash, off, err = unpackUint8(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.Flags, off, err = unpackUint8(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.Iterations, off, err = unpackUint16(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.SaltLength, off, err = unpackUint8(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.Salt, off, err = unpackStringHex(msg, off, off+int(rr.SaltLength))
+       if err != nil {
+               return rr, off, err
+       }
+       rr.HashLength, off, err = unpackUint8(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.NextDomain, off, err = unpackStringBase32(msg, off, off+int(rr.HashLength))
+       if err != nil {
+               return rr, off, err
+       }
+       rr.TypeBitMap, off, err = unpackDataNsec(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       return rr, off, err
+}
+
+func unpackNSEC3PARAM(h RR_Header, msg []byte, off int) (RR, int, error) {
+       rr := new(NSEC3PARAM)
+       rr.Hdr = h
+       if noRdata(h) {
+               return rr, off, nil
+       }
+       var err error
+       rdStart := off
+       _ = rdStart
+
+       rr.Hash, off, err = unpackUint8(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.Flags, off, err = unpackUint8(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.Iterations, off, err = unpackUint16(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.SaltLength, off, err = unpackUint8(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.Salt, off, err = unpackStringHex(msg, off, rdStart+int(rr.Hdr.Rdlength))
+       if err != nil {
+               return rr, off, err
+       }
+       return rr, off, err
+}
+
+func unpackOPENPGPKEY(h RR_Header, msg []byte, off int) (RR, int, error) {
+       rr := new(OPENPGPKEY)
+       rr.Hdr = h
+       if noRdata(h) {
+               return rr, off, nil
+       }
+       var err error
+       rdStart := off
+       _ = rdStart
+
+       rr.PublicKey, off, err = unpackStringBase64(msg, off, rdStart+int(rr.Hdr.Rdlength))
+       if err != nil {
+               return rr, off, err
+       }
+       return rr, off, err
+}
+
+func unpackOPT(h RR_Header, msg []byte, off int) (RR, int, error) {
+       rr := new(OPT)
+       rr.Hdr = h
+       if noRdata(h) {
+               return rr, off, nil
+       }
+       var err error
+       rdStart := off
+       _ = rdStart
+
+       rr.Option, off, err = unpackDataOpt(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       return rr, off, err
+}
+
+func unpackPTR(h RR_Header, msg []byte, off int) (RR, int, error) {
+       rr := new(PTR)
+       rr.Hdr = h
+       if noRdata(h) {
+               return rr, off, nil
+       }
+       var err error
+       rdStart := off
+       _ = rdStart
+
+       rr.Ptr, off, err = UnpackDomainName(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       return rr, off, err
+}
+
+func unpackPX(h RR_Header, msg []byte, off int) (RR, int, error) {
+       rr := new(PX)
+       rr.Hdr = h
+       if noRdata(h) {
+               return rr, off, nil
+       }
+       var err error
+       rdStart := off
+       _ = rdStart
+
+       rr.Preference, off, err = unpackUint16(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.Map822, off, err = UnpackDomainName(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.Mapx400, off, err = UnpackDomainName(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       return rr, off, err
+}
+
+func unpackRFC3597(h RR_Header, msg []byte, off int) (RR, int, error) {
+       rr := new(RFC3597)
+       rr.Hdr = h
+       if noRdata(h) {
+               return rr, off, nil
+       }
+       var err error
+       rdStart := off
+       _ = rdStart
+
+       rr.Rdata, off, err = unpackStringHex(msg, off, rdStart+int(rr.Hdr.Rdlength))
+       if err != nil {
+               return rr, off, err
+       }
+       return rr, off, err
+}
+
+func unpackRKEY(h RR_Header, msg []byte, off int) (RR, int, error) {
+       rr := new(RKEY)
+       rr.Hdr = h
+       if noRdata(h) {
+               return rr, off, nil
+       }
+       var err error
+       rdStart := off
+       _ = rdStart
+
+       rr.Flags, off, err = unpackUint16(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.Protocol, off, err = unpackUint8(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.Algorithm, off, err = unpackUint8(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.PublicKey, off, err = unpackStringBase64(msg, off, rdStart+int(rr.Hdr.Rdlength))
+       if err != nil {
+               return rr, off, err
+       }
+       return rr, off, err
+}
+
+func unpackRP(h RR_Header, msg []byte, off int) (RR, int, error) {
+       rr := new(RP)
+       rr.Hdr = h
+       if noRdata(h) {
+               return rr, off, nil
+       }
+       var err error
+       rdStart := off
+       _ = rdStart
+
+       rr.Mbox, off, err = UnpackDomainName(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.Txt, off, err = UnpackDomainName(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       return rr, off, err
+}
+
+func unpackRRSIG(h RR_Header, msg []byte, off int) (RR, int, error) {
+       rr := new(RRSIG)
+       rr.Hdr = h
+       if noRdata(h) {
+               return rr, off, nil
+       }
+       var err error
+       rdStart := off
+       _ = rdStart
+
+       rr.TypeCovered, off, err = unpackUint16(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.Algorithm, off, err = unpackUint8(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.Labels, off, err = unpackUint8(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.OrigTtl, off, err = unpackUint32(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.Expiration, off, err = unpackUint32(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.Inception, off, err = unpackUint32(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.KeyTag, off, err = unpackUint16(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.SignerName, off, err = UnpackDomainName(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.Signature, off, err = unpackStringBase64(msg, off, rdStart+int(rr.Hdr.Rdlength))
+       if err != nil {
+               return rr, off, err
+       }
+       return rr, off, err
+}
+
+func unpackRT(h RR_Header, msg []byte, off int) (RR, int, error) {
+       rr := new(RT)
+       rr.Hdr = h
+       if noRdata(h) {
+               return rr, off, nil
+       }
+       var err error
+       rdStart := off
+       _ = rdStart
+
+       rr.Preference, off, err = unpackUint16(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.Host, off, err = UnpackDomainName(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       return rr, off, err
+}
+
+func unpackSIG(h RR_Header, msg []byte, off int) (RR, int, error) {
+       rr := new(SIG)
+       rr.Hdr = h
+       if noRdata(h) {
+               return rr, off, nil
+       }
+       var err error
+       rdStart := off
+       _ = rdStart
+
+       rr.TypeCovered, off, err = unpackUint16(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.Algorithm, off, err = unpackUint8(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.Labels, off, err = unpackUint8(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.OrigTtl, off, err = unpackUint32(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.Expiration, off, err = unpackUint32(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.Inception, off, err = unpackUint32(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.KeyTag, off, err = unpackUint16(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.SignerName, off, err = UnpackDomainName(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.Signature, off, err = unpackStringBase64(msg, off, rdStart+int(rr.Hdr.Rdlength))
+       if err != nil {
+               return rr, off, err
+       }
+       return rr, off, err
+}
+
+func unpackSOA(h RR_Header, msg []byte, off int) (RR, int, error) {
+       rr := new(SOA)
+       rr.Hdr = h
+       if noRdata(h) {
+               return rr, off, nil
+       }
+       var err error
+       rdStart := off
+       _ = rdStart
+
+       rr.Ns, off, err = UnpackDomainName(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.Mbox, off, err = UnpackDomainName(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.Serial, off, err = unpackUint32(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.Refresh, off, err = unpackUint32(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.Retry, off, err = unpackUint32(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.Expire, off, err = unpackUint32(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.Minttl, off, err = unpackUint32(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       return rr, off, err
+}
+
+func unpackSPF(h RR_Header, msg []byte, off int) (RR, int, error) {
+       rr := new(SPF)
+       rr.Hdr = h
+       if noRdata(h) {
+               return rr, off, nil
+       }
+       var err error
+       rdStart := off
+       _ = rdStart
+
+       rr.Txt, off, err = unpackStringTxt(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       return rr, off, err
+}
+
+func unpackSRV(h RR_Header, msg []byte, off int) (RR, int, error) {
+       rr := new(SRV)
+       rr.Hdr = h
+       if noRdata(h) {
+               return rr, off, nil
+       }
+       var err error
+       rdStart := off
+       _ = rdStart
+
+       rr.Priority, off, err = unpackUint16(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.Weight, off, err = unpackUint16(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.Port, off, err = unpackUint16(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.Target, off, err = UnpackDomainName(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       return rr, off, err
+}
+
+func unpackSSHFP(h RR_Header, msg []byte, off int) (RR, int, error) {
+       rr := new(SSHFP)
+       rr.Hdr = h
+       if noRdata(h) {
+               return rr, off, nil
+       }
+       var err error
+       rdStart := off
+       _ = rdStart
+
+       rr.Algorithm, off, err = unpackUint8(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.Type, off, err = unpackUint8(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.FingerPrint, off, err = unpackStringHex(msg, off, rdStart+int(rr.Hdr.Rdlength))
+       if err != nil {
+               return rr, off, err
+       }
+       return rr, off, err
+}
+
+func unpackTA(h RR_Header, msg []byte, off int) (RR, int, error) {
+       rr := new(TA)
+       rr.Hdr = h
+       if noRdata(h) {
+               return rr, off, nil
+       }
+       var err error
+       rdStart := off
+       _ = rdStart
+
+       rr.KeyTag, off, err = unpackUint16(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.Algorithm, off, err = unpackUint8(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.DigestType, off, err = unpackUint8(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.Digest, off, err = unpackStringHex(msg, off, rdStart+int(rr.Hdr.Rdlength))
+       if err != nil {
+               return rr, off, err
+       }
+       return rr, off, err
+}
+
+func unpackTALINK(h RR_Header, msg []byte, off int) (RR, int, error) {
+       rr := new(TALINK)
+       rr.Hdr = h
+       if noRdata(h) {
+               return rr, off, nil
+       }
+       var err error
+       rdStart := off
+       _ = rdStart
+
+       rr.PreviousName, off, err = UnpackDomainName(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.NextName, off, err = UnpackDomainName(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       return rr, off, err
+}
+
+func unpackTKEY(h RR_Header, msg []byte, off int) (RR, int, error) {
+       rr := new(TKEY)
+       rr.Hdr = h
+       if noRdata(h) {
+               return rr, off, nil
+       }
+       var err error
+       rdStart := off
+       _ = rdStart
+
+       rr.Algorithm, off, err = UnpackDomainName(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.Inception, off, err = unpackUint32(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.Expiration, off, err = unpackUint32(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.Mode, off, err = unpackUint16(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.Error, off, err = unpackUint16(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.KeySize, off, err = unpackUint16(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.Key, off, err = unpackString(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.OtherLen, off, err = unpackUint16(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.OtherData, off, err = unpackString(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       return rr, off, err
+}
+
+func unpackTLSA(h RR_Header, msg []byte, off int) (RR, int, error) {
+       rr := new(TLSA)
+       rr.Hdr = h
+       if noRdata(h) {
+               return rr, off, nil
+       }
+       var err error
+       rdStart := off
+       _ = rdStart
+
+       rr.Usage, off, err = unpackUint8(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.Selector, off, err = unpackUint8(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.MatchingType, off, err = unpackUint8(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.Certificate, off, err = unpackStringHex(msg, off, rdStart+int(rr.Hdr.Rdlength))
+       if err != nil {
+               return rr, off, err
+       }
+       return rr, off, err
+}
+
+func unpackTSIG(h RR_Header, msg []byte, off int) (RR, int, error) {
+       rr := new(TSIG)
+       rr.Hdr = h
+       if noRdata(h) {
+               return rr, off, nil
+       }
+       var err error
+       rdStart := off
+       _ = rdStart
+
+       rr.Algorithm, off, err = UnpackDomainName(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.TimeSigned, off, err = unpackUint48(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.Fudge, off, err = unpackUint16(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.MACSize, off, err = unpackUint16(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.MAC, off, err = unpackStringHex(msg, off, off+int(rr.MACSize))
+       if err != nil {
+               return rr, off, err
+       }
+       rr.OrigId, off, err = unpackUint16(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.Error, off, err = unpackUint16(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.OtherLen, off, err = unpackUint16(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.OtherData, off, err = unpackStringHex(msg, off, off+int(rr.OtherLen))
+       if err != nil {
+               return rr, off, err
+       }
+       return rr, off, err
+}
+
+func unpackTXT(h RR_Header, msg []byte, off int) (RR, int, error) {
+       rr := new(TXT)
+       rr.Hdr = h
+       if noRdata(h) {
+               return rr, off, nil
+       }
+       var err error
+       rdStart := off
+       _ = rdStart
+
+       rr.Txt, off, err = unpackStringTxt(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       return rr, off, err
+}
+
+func unpackUID(h RR_Header, msg []byte, off int) (RR, int, error) {
+       rr := new(UID)
+       rr.Hdr = h
+       if noRdata(h) {
+               return rr, off, nil
+       }
+       var err error
+       rdStart := off
+       _ = rdStart
+
+       rr.Uid, off, err = unpackUint32(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       return rr, off, err
+}
+
+func unpackUINFO(h RR_Header, msg []byte, off int) (RR, int, error) {
+       rr := new(UINFO)
+       rr.Hdr = h
+       if noRdata(h) {
+               return rr, off, nil
+       }
+       var err error
+       rdStart := off
+       _ = rdStart
+
+       rr.Uinfo, off, err = unpackString(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       return rr, off, err
+}
+
+func unpackURI(h RR_Header, msg []byte, off int) (RR, int, error) {
+       rr := new(URI)
+       rr.Hdr = h
+       if noRdata(h) {
+               return rr, off, nil
+       }
+       var err error
+       rdStart := off
+       _ = rdStart
+
+       rr.Priority, off, err = unpackUint16(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.Weight, off, err = unpackUint16(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       if off == len(msg) {
+               return rr, off, nil
+       }
+       rr.Target, off, err = unpackStringOctet(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       return rr, off, err
+}
+
+func unpackX25(h RR_Header, msg []byte, off int) (RR, int, error) {
+       rr := new(X25)
+       rr.Hdr = h
+       if noRdata(h) {
+               return rr, off, nil
+       }
+       var err error
+       rdStart := off
+       _ = rdStart
+
+       rr.PSDNAddress, off, err = unpackString(msg, off)
+       if err != nil {
+               return rr, off, err
+       }
+       return rr, off, err
+}
+
+var typeToUnpack = map[uint16]func(RR_Header, []byte, int) (RR, int, error){
+       TypeA:          unpackA,
+       TypeAAAA:       unpackAAAA,
+       TypeAFSDB:      unpackAFSDB,
+       TypeANY:        unpackANY,
+       TypeCAA:        unpackCAA,
+       TypeCDNSKEY:    unpackCDNSKEY,
+       TypeCDS:        unpackCDS,
+       TypeCERT:       unpackCERT,
+       TypeCNAME:      unpackCNAME,
+       TypeDHCID:      unpackDHCID,
+       TypeDLV:        unpackDLV,
+       TypeDNAME:      unpackDNAME,
+       TypeDNSKEY:     unpackDNSKEY,
+       TypeDS:         unpackDS,
+       TypeEID:        unpackEID,
+       TypeEUI48:      unpackEUI48,
+       TypeEUI64:      unpackEUI64,
+       TypeGID:        unpackGID,
+       TypeGPOS:       unpackGPOS,
+       TypeHINFO:      unpackHINFO,
+       TypeHIP:        unpackHIP,
+       TypeKEY:        unpackKEY,
+       TypeKX:         unpackKX,
+       TypeL32:        unpackL32,
+       TypeL64:        unpackL64,
+       TypeLOC:        unpackLOC,
+       TypeLP:         unpackLP,
+       TypeMB:         unpackMB,
+       TypeMD:         unpackMD,
+       TypeMF:         unpackMF,
+       TypeMG:         unpackMG,
+       TypeMINFO:      unpackMINFO,
+       TypeMR:         unpackMR,
+       TypeMX:         unpackMX,
+       TypeNAPTR:      unpackNAPTR,
+       TypeNID:        unpackNID,
+       TypeNIMLOC:     unpackNIMLOC,
+       TypeNINFO:      unpackNINFO,
+       TypeNS:         unpackNS,
+       TypeNSAPPTR:    unpackNSAPPTR,
+       TypeNSEC:       unpackNSEC,
+       TypeNSEC3:      unpackNSEC3,
+       TypeNSEC3PARAM: unpackNSEC3PARAM,
+       TypeOPENPGPKEY: unpackOPENPGPKEY,
+       TypeOPT:        unpackOPT,
+       TypePTR:        unpackPTR,
+       TypePX:         unpackPX,
+       TypeRKEY:       unpackRKEY,
+       TypeRP:         unpackRP,
+       TypeRRSIG:      unpackRRSIG,
+       TypeRT:         unpackRT,
+       TypeSIG:        unpackSIG,
+       TypeSOA:        unpackSOA,
+       TypeSPF:        unpackSPF,
+       TypeSRV:        unpackSRV,
+       TypeSSHFP:      unpackSSHFP,
+       TypeTA:         unpackTA,
+       TypeTALINK:     unpackTALINK,
+       TypeTKEY:       unpackTKEY,
+       TypeTLSA:       unpackTLSA,
+       TypeTSIG:       unpackTSIG,
+       TypeTXT:        unpackTXT,
+       TypeUID:        unpackUID,
+       TypeUINFO:      unpackUINFO,
+       TypeURI:        unpackURI,
+       TypeX25:        unpackX25,
+}
diff --git a/vendor/github.com/miekg/dns/ztypes.go b/vendor/github.com/miekg/dns/ztypes.go
new file mode 100644 (file)
index 0000000..a4ecbb0
--- /dev/null
@@ -0,0 +1,828 @@
+// *** DO NOT MODIFY ***
+// AUTOGENERATED BY go generate from type_generate.go
+
+package dns
+
+import (
+       "encoding/base64"
+       "net"
+)
+
+// TypeToRR is a map of constructors for each RR type.
+var TypeToRR = map[uint16]func() RR{
+       TypeA:          func() RR { return new(A) },
+       TypeAAAA:       func() RR { return new(AAAA) },
+       TypeAFSDB:      func() RR { return new(AFSDB) },
+       TypeANY:        func() RR { return new(ANY) },
+       TypeCAA:        func() RR { return new(CAA) },
+       TypeCDNSKEY:    func() RR { return new(CDNSKEY) },
+       TypeCDS:        func() RR { return new(CDS) },
+       TypeCERT:       func() RR { return new(CERT) },
+       TypeCNAME:      func() RR { return new(CNAME) },
+       TypeDHCID:      func() RR { return new(DHCID) },
+       TypeDLV:        func() RR { return new(DLV) },
+       TypeDNAME:      func() RR { return new(DNAME) },
+       TypeDNSKEY:     func() RR { return new(DNSKEY) },
+       TypeDS:         func() RR { return new(DS) },
+       TypeEID:        func() RR { return new(EID) },
+       TypeEUI48:      func() RR { return new(EUI48) },
+       TypeEUI64:      func() RR { return new(EUI64) },
+       TypeGID:        func() RR { return new(GID) },
+       TypeGPOS:       func() RR { return new(GPOS) },
+       TypeHINFO:      func() RR { return new(HINFO) },
+       TypeHIP:        func() RR { return new(HIP) },
+       TypeKEY:        func() RR { return new(KEY) },
+       TypeKX:         func() RR { return new(KX) },
+       TypeL32:        func() RR { return new(L32) },
+       TypeL64:        func() RR { return new(L64) },
+       TypeLOC:        func() RR { return new(LOC) },
+       TypeLP:         func() RR { return new(LP) },
+       TypeMB:         func() RR { return new(MB) },
+       TypeMD:         func() RR { return new(MD) },
+       TypeMF:         func() RR { return new(MF) },
+       TypeMG:         func() RR { return new(MG) },
+       TypeMINFO:      func() RR { return new(MINFO) },
+       TypeMR:         func() RR { return new(MR) },
+       TypeMX:         func() RR { return new(MX) },
+       TypeNAPTR:      func() RR { return new(NAPTR) },
+       TypeNID:        func() RR { return new(NID) },
+       TypeNIMLOC:     func() RR { return new(NIMLOC) },
+       TypeNINFO:      func() RR { return new(NINFO) },
+       TypeNS:         func() RR { return new(NS) },
+       TypeNSAPPTR:    func() RR { return new(NSAPPTR) },
+       TypeNSEC:       func() RR { return new(NSEC) },
+       TypeNSEC3:      func() RR { return new(NSEC3) },
+       TypeNSEC3PARAM: func() RR { return new(NSEC3PARAM) },
+       TypeOPENPGPKEY: func() RR { return new(OPENPGPKEY) },
+       TypeOPT:        func() RR { return new(OPT) },
+       TypePTR:        func() RR { return new(PTR) },
+       TypePX:         func() RR { return new(PX) },
+       TypeRKEY:       func() RR { return new(RKEY) },
+       TypeRP:         func() RR { return new(RP) },
+       TypeRRSIG:      func() RR { return new(RRSIG) },
+       TypeRT:         func() RR { return new(RT) },
+       TypeSIG:        func() RR { return new(SIG) },
+       TypeSOA:        func() RR { return new(SOA) },
+       TypeSPF:        func() RR { return new(SPF) },
+       TypeSRV:        func() RR { return new(SRV) },
+       TypeSSHFP:      func() RR { return new(SSHFP) },
+       TypeTA:         func() RR { return new(TA) },
+       TypeTALINK:     func() RR { return new(TALINK) },
+       TypeTKEY:       func() RR { return new(TKEY) },
+       TypeTLSA:       func() RR { return new(TLSA) },
+       TypeTSIG:       func() RR { return new(TSIG) },
+       TypeTXT:        func() RR { return new(TXT) },
+       TypeUID:        func() RR { return new(UID) },
+       TypeUINFO:      func() RR { return new(UINFO) },
+       TypeURI:        func() RR { return new(URI) },
+       TypeX25:        func() RR { return new(X25) },
+}
+
+// TypeToString is a map of strings for each RR type.
+var TypeToString = map[uint16]string{
+       TypeA:          "A",
+       TypeAAAA:       "AAAA",
+       TypeAFSDB:      "AFSDB",
+       TypeANY:        "ANY",
+       TypeATMA:       "ATMA",
+       TypeAXFR:       "AXFR",
+       TypeCAA:        "CAA",
+       TypeCDNSKEY:    "CDNSKEY",
+       TypeCDS:        "CDS",
+       TypeCERT:       "CERT",
+       TypeCNAME:      "CNAME",
+       TypeDHCID:      "DHCID",
+       TypeDLV:        "DLV",
+       TypeDNAME:      "DNAME",
+       TypeDNSKEY:     "DNSKEY",
+       TypeDS:         "DS",
+       TypeEID:        "EID",
+       TypeEUI48:      "EUI48",
+       TypeEUI64:      "EUI64",
+       TypeGID:        "GID",
+       TypeGPOS:       "GPOS",
+       TypeHINFO:      "HINFO",
+       TypeHIP:        "HIP",
+       TypeISDN:       "ISDN",
+       TypeIXFR:       "IXFR",
+       TypeKEY:        "KEY",
+       TypeKX:         "KX",
+       TypeL32:        "L32",
+       TypeL64:        "L64",
+       TypeLOC:        "LOC",
+       TypeLP:         "LP",
+       TypeMAILA:      "MAILA",
+       TypeMAILB:      "MAILB",
+       TypeMB:         "MB",
+       TypeMD:         "MD",
+       TypeMF:         "MF",
+       TypeMG:         "MG",
+       TypeMINFO:      "MINFO",
+       TypeMR:         "MR",
+       TypeMX:         "MX",
+       TypeNAPTR:      "NAPTR",
+       TypeNID:        "NID",
+       TypeNIMLOC:     "NIMLOC",
+       TypeNINFO:      "NINFO",
+       TypeNS:         "NS",
+       TypeNSEC:       "NSEC",
+       TypeNSEC3:      "NSEC3",
+       TypeNSEC3PARAM: "NSEC3PARAM",
+       TypeNULL:       "NULL",
+       TypeNXT:        "NXT",
+       TypeNone:       "None",
+       TypeOPENPGPKEY: "OPENPGPKEY",
+       TypeOPT:        "OPT",
+       TypePTR:        "PTR",
+       TypePX:         "PX",
+       TypeRKEY:       "RKEY",
+       TypeRP:         "RP",
+       TypeRRSIG:      "RRSIG",
+       TypeRT:         "RT",
+       TypeReserved:   "Reserved",
+       TypeSIG:        "SIG",
+       TypeSOA:        "SOA",
+       TypeSPF:        "SPF",
+       TypeSRV:        "SRV",
+       TypeSSHFP:      "SSHFP",
+       TypeTA:         "TA",
+       TypeTALINK:     "TALINK",
+       TypeTKEY:       "TKEY",
+       TypeTLSA:       "TLSA",
+       TypeTSIG:       "TSIG",
+       TypeTXT:        "TXT",
+       TypeUID:        "UID",
+       TypeUINFO:      "UINFO",
+       TypeUNSPEC:     "UNSPEC",
+       TypeURI:        "URI",
+       TypeX25:        "X25",
+       TypeNSAPPTR:    "NSAP-PTR",
+}
+
+// Header() functions
+func (rr *A) Header() *RR_Header          { return &rr.Hdr }
+func (rr *AAAA) Header() *RR_Header       { return &rr.Hdr }
+func (rr *AFSDB) Header() *RR_Header      { return &rr.Hdr }
+func (rr *ANY) Header() *RR_Header        { return &rr.Hdr }
+func (rr *CAA) Header() *RR_Header        { return &rr.Hdr }
+func (rr *CDNSKEY) Header() *RR_Header    { return &rr.Hdr }
+func (rr *CDS) Header() *RR_Header        { return &rr.Hdr }
+func (rr *CERT) Header() *RR_Header       { return &rr.Hdr }
+func (rr *CNAME) Header() *RR_Header      { return &rr.Hdr }
+func (rr *DHCID) Header() *RR_Header      { return &rr.Hdr }
+func (rr *DLV) Header() *RR_Header        { return &rr.Hdr }
+func (rr *DNAME) Header() *RR_Header      { return &rr.Hdr }
+func (rr *DNSKEY) Header() *RR_Header     { return &rr.Hdr }
+func (rr *DS) Header() *RR_Header         { return &rr.Hdr }
+func (rr *EID) Header() *RR_Header        { return &rr.Hdr }
+func (rr *EUI48) Header() *RR_Header      { return &rr.Hdr }
+func (rr *EUI64) Header() *RR_Header      { return &rr.Hdr }
+func (rr *GID) Header() *RR_Header        { return &rr.Hdr }
+func (rr *GPOS) Header() *RR_Header       { return &rr.Hdr }
+func (rr *HINFO) Header() *RR_Header      { return &rr.Hdr }
+func (rr *HIP) Header() *RR_Header        { return &rr.Hdr }
+func (rr *KEY) Header() *RR_Header        { return &rr.Hdr }
+func (rr *KX) Header() *RR_Header         { return &rr.Hdr }
+func (rr *L32) Header() *RR_Header        { return &rr.Hdr }
+func (rr *L64) Header() *RR_Header        { return &rr.Hdr }
+func (rr *LOC) Header() *RR_Header        { return &rr.Hdr }
+func (rr *LP) Header() *RR_Header         { return &rr.Hdr }
+func (rr *MB) Header() *RR_Header         { return &rr.Hdr }
+func (rr *MD) Header() *RR_Header         { return &rr.Hdr }
+func (rr *MF) Header() *RR_Header         { return &rr.Hdr }
+func (rr *MG) Header() *RR_Header         { return &rr.Hdr }
+func (rr *MINFO) Header() *RR_Header      { return &rr.Hdr }
+func (rr *MR) Header() *RR_Header         { return &rr.Hdr }
+func (rr *MX) Header() *RR_Header         { return &rr.Hdr }
+func (rr *NAPTR) Header() *RR_Header      { return &rr.Hdr }
+func (rr *NID) Header() *RR_Header        { return &rr.Hdr }
+func (rr *NIMLOC) Header() *RR_Header     { return &rr.Hdr }
+func (rr *NINFO) Header() *RR_Header      { return &rr.Hdr }
+func (rr *NS) Header() *RR_Header         { return &rr.Hdr }
+func (rr *NSAPPTR) Header() *RR_Header    { return &rr.Hdr }
+func (rr *NSEC) Header() *RR_Header       { return &rr.Hdr }
+func (rr *NSEC3) Header() *RR_Header      { return &rr.Hdr }
+func (rr *NSEC3PARAM) Header() *RR_Header { return &rr.Hdr }
+func (rr *OPENPGPKEY) Header() *RR_Header { return &rr.Hdr }
+func (rr *OPT) Header() *RR_Header        { return &rr.Hdr }
+func (rr *PTR) Header() *RR_Header        { return &rr.Hdr }
+func (rr *PX) Header() *RR_Header         { return &rr.Hdr }
+func (rr *RFC3597) Header() *RR_Header    { return &rr.Hdr }
+func (rr *RKEY) Header() *RR_Header       { return &rr.Hdr }
+func (rr *RP) Header() *RR_Header         { return &rr.Hdr }
+func (rr *RRSIG) Header() *RR_Header      { return &rr.Hdr }
+func (rr *RT) Header() *RR_Header         { return &rr.Hdr }
+func (rr *SIG) Header() *RR_Header        { return &rr.Hdr }
+func (rr *SOA) Header() *RR_Header        { return &rr.Hdr }
+func (rr *SPF) Header() *RR_Header        { return &rr.Hdr }
+func (rr *SRV) Header() *RR_Header        { return &rr.Hdr }
+func (rr *SSHFP) Header() *RR_Header      { return &rr.Hdr }
+func (rr *TA) Header() *RR_Header         { return &rr.Hdr }
+func (rr *TALINK) Header() *RR_Header     { return &rr.Hdr }
+func (rr *TKEY) Header() *RR_Header       { return &rr.Hdr }
+func (rr *TLSA) Header() *RR_Header       { return &rr.Hdr }
+func (rr *TSIG) Header() *RR_Header       { return &rr.Hdr }
+func (rr *TXT) Header() *RR_Header        { return &rr.Hdr }
+func (rr *UID) Header() *RR_Header        { return &rr.Hdr }
+func (rr *UINFO) Header() *RR_Header      { return &rr.Hdr }
+func (rr *URI) Header() *RR_Header        { return &rr.Hdr }
+func (rr *X25) Header() *RR_Header        { return &rr.Hdr }
+
+// len() functions
+func (rr *A) len() int {
+       l := rr.Hdr.len()
+       l += net.IPv4len // A
+       return l
+}
+func (rr *AAAA) len() int {
+       l := rr.Hdr.len()
+       l += net.IPv6len // AAAA
+       return l
+}
+func (rr *AFSDB) len() int {
+       l := rr.Hdr.len()
+       l += 2 // Subtype
+       l += len(rr.Hostname) + 1
+       return l
+}
+func (rr *ANY) len() int {
+       l := rr.Hdr.len()
+       return l
+}
+func (rr *CAA) len() int {
+       l := rr.Hdr.len()
+       l += 1 // Flag
+       l += len(rr.Tag) + 1
+       l += len(rr.Value)
+       return l
+}
+func (rr *CERT) len() int {
+       l := rr.Hdr.len()
+       l += 2 // Type
+       l += 2 // KeyTag
+       l += 1 // Algorithm
+       l += base64.StdEncoding.DecodedLen(len(rr.Certificate))
+       return l
+}
+func (rr *CNAME) len() int {
+       l := rr.Hdr.len()
+       l += len(rr.Target) + 1
+       return l
+}
+func (rr *DHCID) len() int {
+       l := rr.Hdr.len()
+       l += base64.StdEncoding.DecodedLen(len(rr.Digest))
+       return l
+}
+func (rr *DNAME) len() int {
+       l := rr.Hdr.len()
+       l += len(rr.Target) + 1
+       return l
+}
+func (rr *DNSKEY) len() int {
+       l := rr.Hdr.len()
+       l += 2 // Flags
+       l += 1 // Protocol
+       l += 1 // Algorithm
+       l += base64.StdEncoding.DecodedLen(len(rr.PublicKey))
+       return l
+}
+func (rr *DS) len() int {
+       l := rr.Hdr.len()
+       l += 2 // KeyTag
+       l += 1 // Algorithm
+       l += 1 // DigestType
+       l += len(rr.Digest)/2 + 1
+       return l
+}
+func (rr *EID) len() int {
+       l := rr.Hdr.len()
+       l += len(rr.Endpoint)/2 + 1
+       return l
+}
+func (rr *EUI48) len() int {
+       l := rr.Hdr.len()
+       l += 6 // Address
+       return l
+}
+func (rr *EUI64) len() int {
+       l := rr.Hdr.len()
+       l += 8 // Address
+       return l
+}
+func (rr *GID) len() int {
+       l := rr.Hdr.len()
+       l += 4 // Gid
+       return l
+}
+func (rr *GPOS) len() int {
+       l := rr.Hdr.len()
+       l += len(rr.Longitude) + 1
+       l += len(rr.Latitude) + 1
+       l += len(rr.Altitude) + 1
+       return l
+}
+func (rr *HINFO) len() int {
+       l := rr.Hdr.len()
+       l += len(rr.Cpu) + 1
+       l += len(rr.Os) + 1
+       return l
+}
+func (rr *HIP) len() int {
+       l := rr.Hdr.len()
+       l += 1 // HitLength
+       l += 1 // PublicKeyAlgorithm
+       l += 2 // PublicKeyLength
+       l += len(rr.Hit)/2 + 1
+       l += base64.StdEncoding.DecodedLen(len(rr.PublicKey))
+       for _, x := range rr.RendezvousServers {
+               l += len(x) + 1
+       }
+       return l
+}
+func (rr *KX) len() int {
+       l := rr.Hdr.len()
+       l += 2 // Preference
+       l += len(rr.Exchanger) + 1
+       return l
+}
+func (rr *L32) len() int {
+       l := rr.Hdr.len()
+       l += 2           // Preference
+       l += net.IPv4len // Locator32
+       return l
+}
+func (rr *L64) len() int {
+       l := rr.Hdr.len()
+       l += 2 // Preference
+       l += 8 // Locator64
+       return l
+}
+func (rr *LOC) len() int {
+       l := rr.Hdr.len()
+       l += 1 // Version
+       l += 1 // Size
+       l += 1 // HorizPre
+       l += 1 // VertPre
+       l += 4 // Latitude
+       l += 4 // Longitude
+       l += 4 // Altitude
+       return l
+}
+func (rr *LP) len() int {
+       l := rr.Hdr.len()
+       l += 2 // Preference
+       l += len(rr.Fqdn) + 1
+       return l
+}
+func (rr *MB) len() int {
+       l := rr.Hdr.len()
+       l += len(rr.Mb) + 1
+       return l
+}
+func (rr *MD) len() int {
+       l := rr.Hdr.len()
+       l += len(rr.Md) + 1
+       return l
+}
+func (rr *MF) len() int {
+       l := rr.Hdr.len()
+       l += len(rr.Mf) + 1
+       return l
+}
+func (rr *MG) len() int {
+       l := rr.Hdr.len()
+       l += len(rr.Mg) + 1
+       return l
+}
+func (rr *MINFO) len() int {
+       l := rr.Hdr.len()
+       l += len(rr.Rmail) + 1
+       l += len(rr.Email) + 1
+       return l
+}
+func (rr *MR) len() int {
+       l := rr.Hdr.len()
+       l += len(rr.Mr) + 1
+       return l
+}
+func (rr *MX) len() int {
+       l := rr.Hdr.len()
+       l += 2 // Preference
+       l += len(rr.Mx) + 1
+       return l
+}
+func (rr *NAPTR) len() int {
+       l := rr.Hdr.len()
+       l += 2 // Order
+       l += 2 // Preference
+       l += len(rr.Flags) + 1
+       l += len(rr.Service) + 1
+       l += len(rr.Regexp) + 1
+       l += len(rr.Replacement) + 1
+       return l
+}
+func (rr *NID) len() int {
+       l := rr.Hdr.len()
+       l += 2 // Preference
+       l += 8 // NodeID
+       return l
+}
+func (rr *NIMLOC) len() int {
+       l := rr.Hdr.len()
+       l += len(rr.Locator)/2 + 1
+       return l
+}
+func (rr *NINFO) len() int {
+       l := rr.Hdr.len()
+       for _, x := range rr.ZSData {
+               l += len(x) + 1
+       }
+       return l
+}
+func (rr *NS) len() int {
+       l := rr.Hdr.len()
+       l += len(rr.Ns) + 1
+       return l
+}
+func (rr *NSAPPTR) len() int {
+       l := rr.Hdr.len()
+       l += len(rr.Ptr) + 1
+       return l
+}
+func (rr *NSEC3PARAM) len() int {
+       l := rr.Hdr.len()
+       l += 1 // Hash
+       l += 1 // Flags
+       l += 2 // Iterations
+       l += 1 // SaltLength
+       l += len(rr.Salt)/2 + 1
+       return l
+}
+func (rr *OPENPGPKEY) len() int {
+       l := rr.Hdr.len()
+       l += base64.StdEncoding.DecodedLen(len(rr.PublicKey))
+       return l
+}
+func (rr *PTR) len() int {
+       l := rr.Hdr.len()
+       l += len(rr.Ptr) + 1
+       return l
+}
+func (rr *PX) len() int {
+       l := rr.Hdr.len()
+       l += 2 // Preference
+       l += len(rr.Map822) + 1
+       l += len(rr.Mapx400) + 1
+       return l
+}
+func (rr *RFC3597) len() int {
+       l := rr.Hdr.len()
+       l += len(rr.Rdata)/2 + 1
+       return l
+}
+func (rr *RKEY) len() int {
+       l := rr.Hdr.len()
+       l += 2 // Flags
+       l += 1 // Protocol
+       l += 1 // Algorithm
+       l += base64.StdEncoding.DecodedLen(len(rr.PublicKey))
+       return l
+}
+func (rr *RP) len() int {
+       l := rr.Hdr.len()
+       l += len(rr.Mbox) + 1
+       l += len(rr.Txt) + 1
+       return l
+}
+func (rr *RRSIG) len() int {
+       l := rr.Hdr.len()
+       l += 2 // TypeCovered
+       l += 1 // Algorithm
+       l += 1 // Labels
+       l += 4 // OrigTtl
+       l += 4 // Expiration
+       l += 4 // Inception
+       l += 2 // KeyTag
+       l += len(rr.SignerName) + 1
+       l += base64.StdEncoding.DecodedLen(len(rr.Signature))
+       return l
+}
+func (rr *RT) len() int {
+       l := rr.Hdr.len()
+       l += 2 // Preference
+       l += len(rr.Host) + 1
+       return l
+}
+func (rr *SOA) len() int {
+       l := rr.Hdr.len()
+       l += len(rr.Ns) + 1
+       l += len(rr.Mbox) + 1
+       l += 4 // Serial
+       l += 4 // Refresh
+       l += 4 // Retry
+       l += 4 // Expire
+       l += 4 // Minttl
+       return l
+}
+func (rr *SPF) len() int {
+       l := rr.Hdr.len()
+       for _, x := range rr.Txt {
+               l += len(x) + 1
+       }
+       return l
+}
+func (rr *SRV) len() int {
+       l := rr.Hdr.len()
+       l += 2 // Priority
+       l += 2 // Weight
+       l += 2 // Port
+       l += len(rr.Target) + 1
+       return l
+}
+func (rr *SSHFP) len() int {
+       l := rr.Hdr.len()
+       l += 1 // Algorithm
+       l += 1 // Type
+       l += len(rr.FingerPrint)/2 + 1
+       return l
+}
+func (rr *TA) len() int {
+       l := rr.Hdr.len()
+       l += 2 // KeyTag
+       l += 1 // Algorithm
+       l += 1 // DigestType
+       l += len(rr.Digest)/2 + 1
+       return l
+}
+func (rr *TALINK) len() int {
+       l := rr.Hdr.len()
+       l += len(rr.PreviousName) + 1
+       l += len(rr.NextName) + 1
+       return l
+}
+func (rr *TKEY) len() int {
+       l := rr.Hdr.len()
+       l += len(rr.Algorithm) + 1
+       l += 4 // Inception
+       l += 4 // Expiration
+       l += 2 // Mode
+       l += 2 // Error
+       l += 2 // KeySize
+       l += len(rr.Key) + 1
+       l += 2 // OtherLen
+       l += len(rr.OtherData) + 1
+       return l
+}
+func (rr *TLSA) len() int {
+       l := rr.Hdr.len()
+       l += 1 // Usage
+       l += 1 // Selector
+       l += 1 // MatchingType
+       l += len(rr.Certificate)/2 + 1
+       return l
+}
+func (rr *TSIG) len() int {
+       l := rr.Hdr.len()
+       l += len(rr.Algorithm) + 1
+       l += 6 // TimeSigned
+       l += 2 // Fudge
+       l += 2 // MACSize
+       l += len(rr.MAC)/2 + 1
+       l += 2 // OrigId
+       l += 2 // Error
+       l += 2 // OtherLen
+       l += len(rr.OtherData)/2 + 1
+       return l
+}
+func (rr *TXT) len() int {
+       l := rr.Hdr.len()
+       for _, x := range rr.Txt {
+               l += len(x) + 1
+       }
+       return l
+}
+func (rr *UID) len() int {
+       l := rr.Hdr.len()
+       l += 4 // Uid
+       return l
+}
+func (rr *UINFO) len() int {
+       l := rr.Hdr.len()
+       l += len(rr.Uinfo) + 1
+       return l
+}
+func (rr *URI) len() int {
+       l := rr.Hdr.len()
+       l += 2 // Priority
+       l += 2 // Weight
+       l += len(rr.Target)
+       return l
+}
+func (rr *X25) len() int {
+       l := rr.Hdr.len()
+       l += len(rr.PSDNAddress) + 1
+       return l
+}
+
+// copy() functions
+func (rr *A) copy() RR {
+       return &A{*rr.Hdr.copyHeader(), copyIP(rr.A)}
+}
+func (rr *AAAA) copy() RR {
+       return &AAAA{*rr.Hdr.copyHeader(), copyIP(rr.AAAA)}
+}
+func (rr *AFSDB) copy() RR {
+       return &AFSDB{*rr.Hdr.copyHeader(), rr.Subtype, rr.Hostname}
+}
+func (rr *ANY) copy() RR {
+       return &ANY{*rr.Hdr.copyHeader()}
+}
+func (rr *CAA) copy() RR {
+       return &CAA{*rr.Hdr.copyHeader(), rr.Flag, rr.Tag, rr.Value}
+}
+func (rr *CERT) copy() RR {
+       return &CERT{*rr.Hdr.copyHeader(), rr.Type, rr.KeyTag, rr.Algorithm, rr.Certificate}
+}
+func (rr *CNAME) copy() RR {
+       return &CNAME{*rr.Hdr.copyHeader(), rr.Target}
+}
+func (rr *DHCID) copy() RR {
+       return &DHCID{*rr.Hdr.copyHeader(), rr.Digest}
+}
+func (rr *DNAME) copy() RR {
+       return &DNAME{*rr.Hdr.copyHeader(), rr.Target}
+}
+func (rr *DNSKEY) copy() RR {
+       return &DNSKEY{*rr.Hdr.copyHeader(), rr.Flags, rr.Protocol, rr.Algorithm, rr.PublicKey}
+}
+func (rr *DS) copy() RR {
+       return &DS{*rr.Hdr.copyHeader(), rr.KeyTag, rr.Algorithm, rr.DigestType, rr.Digest}
+}
+func (rr *EID) copy() RR {
+       return &EID{*rr.Hdr.copyHeader(), rr.Endpoint}
+}
+func (rr *EUI48) copy() RR {
+       return &EUI48{*rr.Hdr.copyHeader(), rr.Address}
+}
+func (rr *EUI64) copy() RR {
+       return &EUI64{*rr.Hdr.copyHeader(), rr.Address}
+}
+func (rr *GID) copy() RR {
+       return &GID{*rr.Hdr.copyHeader(), rr.Gid}
+}
+func (rr *GPOS) copy() RR {
+       return &GPOS{*rr.Hdr.copyHeader(), rr.Longitude, rr.Latitude, rr.Altitude}
+}
+func (rr *HINFO) copy() RR {
+       return &HINFO{*rr.Hdr.copyHeader(), rr.Cpu, rr.Os}
+}
+func (rr *HIP) copy() RR {
+       RendezvousServers := make([]string, len(rr.RendezvousServers))
+       copy(RendezvousServers, rr.RendezvousServers)
+       return &HIP{*rr.Hdr.copyHeader(), rr.HitLength, rr.PublicKeyAlgorithm, rr.PublicKeyLength, rr.Hit, rr.PublicKey, RendezvousServers}
+}
+func (rr *KX) copy() RR {
+       return &KX{*rr.Hdr.copyHeader(), rr.Preference, rr.Exchanger}
+}
+func (rr *L32) copy() RR {
+       return &L32{*rr.Hdr.copyHeader(), rr.Preference, copyIP(rr.Locator32)}
+}
+func (rr *L64) copy() RR {
+       return &L64{*rr.Hdr.copyHeader(), rr.Preference, rr.Locator64}
+}
+func (rr *LOC) copy() RR {
+       return &LOC{*rr.Hdr.copyHeader(), rr.Version, rr.Size, rr.HorizPre, rr.VertPre, rr.Latitude, rr.Longitude, rr.Altitude}
+}
+func (rr *LP) copy() RR {
+       return &LP{*rr.Hdr.copyHeader(), rr.Preference, rr.Fqdn}
+}
+func (rr *MB) copy() RR {
+       return &MB{*rr.Hdr.copyHeader(), rr.Mb}
+}
+func (rr *MD) copy() RR {
+       return &MD{*rr.Hdr.copyHeader(), rr.Md}
+}
+func (rr *MF) copy() RR {
+       return &MF{*rr.Hdr.copyHeader(), rr.Mf}
+}
+func (rr *MG) copy() RR {
+       return &MG{*rr.Hdr.copyHeader(), rr.Mg}
+}
+func (rr *MINFO) copy() RR {
+       return &MINFO{*rr.Hdr.copyHeader(), rr.Rmail, rr.Email}
+}
+func (rr *MR) copy() RR {
+       return &MR{*rr.Hdr.copyHeader(), rr.Mr}
+}
+func (rr *MX) copy() RR {
+       return &MX{*rr.Hdr.copyHeader(), rr.Preference, rr.Mx}
+}
+func (rr *NAPTR) copy() RR {
+       return &NAPTR{*rr.Hdr.copyHeader(), rr.Order, rr.Preference, rr.Flags, rr.Service, rr.Regexp, rr.Replacement}
+}
+func (rr *NID) copy() RR {
+       return &NID{*rr.Hdr.copyHeader(), rr.Preference, rr.NodeID}
+}
+func (rr *NIMLOC) copy() RR {
+       return &NIMLOC{*rr.Hdr.copyHeader(), rr.Locator}
+}
+func (rr *NINFO) copy() RR {
+       ZSData := make([]string, len(rr.ZSData))
+       copy(ZSData, rr.ZSData)
+       return &NINFO{*rr.Hdr.copyHeader(), ZSData}
+}
+func (rr *NS) copy() RR {
+       return &NS{*rr.Hdr.copyHeader(), rr.Ns}
+}
+func (rr *NSAPPTR) copy() RR {
+       return &NSAPPTR{*rr.Hdr.copyHeader(), rr.Ptr}
+}
+func (rr *NSEC) copy() RR {
+       TypeBitMap := make([]uint16, len(rr.TypeBitMap))
+       copy(TypeBitMap, rr.TypeBitMap)
+       return &NSEC{*rr.Hdr.copyHeader(), rr.NextDomain, TypeBitMap}
+}
+func (rr *NSEC3) copy() RR {
+       TypeBitMap := make([]uint16, len(rr.TypeBitMap))
+       copy(TypeBitMap, rr.TypeBitMap)
+       return &NSEC3{*rr.Hdr.copyHeader(), rr.Hash, rr.Flags, rr.Iterations, rr.SaltLength, rr.Salt, rr.HashLength, rr.NextDomain, TypeBitMap}
+}
+func (rr *NSEC3PARAM) copy() RR {
+       return &NSEC3PARAM{*rr.Hdr.copyHeader(), rr.Hash, rr.Flags, rr.Iterations, rr.SaltLength, rr.Salt}
+}
+func (rr *OPENPGPKEY) copy() RR {
+       return &OPENPGPKEY{*rr.Hdr.copyHeader(), rr.PublicKey}
+}
+func (rr *OPT) copy() RR {
+       Option := make([]EDNS0, len(rr.Option))
+       copy(Option, rr.Option)
+       return &OPT{*rr.Hdr.copyHeader(), Option}
+}
+func (rr *PTR) copy() RR {
+       return &PTR{*rr.Hdr.copyHeader(), rr.Ptr}
+}
+func (rr *PX) copy() RR {
+       return &PX{*rr.Hdr.copyHeader(), rr.Preference, rr.Map822, rr.Mapx400}
+}
+func (rr *RFC3597) copy() RR {
+       return &RFC3597{*rr.Hdr.copyHeader(), rr.Rdata}
+}
+func (rr *RKEY) copy() RR {
+       return &RKEY{*rr.Hdr.copyHeader(), rr.Flags, rr.Protocol, rr.Algorithm, rr.PublicKey}
+}
+func (rr *RP) copy() RR {
+       return &RP{*rr.Hdr.copyHeader(), rr.Mbox, rr.Txt}
+}
+func (rr *RRSIG) copy() RR {
+       return &RRSIG{*rr.Hdr.copyHeader(), rr.TypeCovered, rr.Algorithm, rr.Labels, rr.OrigTtl, rr.Expiration, rr.Inception, rr.KeyTag, rr.SignerName, rr.Signature}
+}
+func (rr *RT) copy() RR {
+       return &RT{*rr.Hdr.copyHeader(), rr.Preference, rr.Host}
+}
+func (rr *SOA) copy() RR {
+       return &SOA{*rr.Hdr.copyHeader(), rr.Ns, rr.Mbox, rr.Serial, rr.Refresh, rr.Retry, rr.Expire, rr.Minttl}
+}
+func (rr *SPF) copy() RR {
+       Txt := make([]string, len(rr.Txt))
+       copy(Txt, rr.Txt)
+       return &SPF{*rr.Hdr.copyHeader(), Txt}
+}
+func (rr *SRV) copy() RR {
+       return &SRV{*rr.Hdr.copyHeader(), rr.Priority, rr.Weight, rr.Port, rr.Target}
+}
+func (rr *SSHFP) copy() RR {
+       return &SSHFP{*rr.Hdr.copyHeader(), rr.Algorithm, rr.Type, rr.FingerPrint}
+}
+func (rr *TA) copy() RR {
+       return &TA{*rr.Hdr.copyHeader(), rr.KeyTag, rr.Algorithm, rr.DigestType, rr.Digest}
+}
+func (rr *TALINK) copy() RR {
+       return &TALINK{*rr.Hdr.copyHeader(), rr.PreviousName, rr.NextName}
+}
+func (rr *TKEY) copy() RR {
+       return &TKEY{*rr.Hdr.copyHeader(), rr.Algorithm, rr.Inception, rr.Expiration, rr.Mode, rr.Error, rr.KeySize, rr.Key, rr.OtherLen, rr.OtherData}
+}
+func (rr *TLSA) copy() RR {
+       return &TLSA{*rr.Hdr.copyHeader(), rr.Usage, rr.Selector, rr.MatchingType, rr.Certificate}
+}
+func (rr *TSIG) copy() RR {
+       return &TSIG{*rr.Hdr.copyHeader(), rr.Algorithm, rr.TimeSigned, rr.Fudge, rr.MACSize, rr.MAC, rr.OrigId, rr.Error, rr.OtherLen, rr.OtherData}
+}
+func (rr *TXT) copy() RR {
+       Txt := make([]string, len(rr.Txt))
+       copy(Txt, rr.Txt)
+       return &TXT{*rr.Hdr.copyHeader(), Txt}
+}
+func (rr *UID) copy() RR {
+       return &UID{*rr.Hdr.copyHeader(), rr.Uid}
+}
+func (rr *UINFO) copy() RR {
+       return &UINFO{*rr.Hdr.copyHeader(), rr.Uinfo}
+}
+func (rr *URI) copy() RR {
+       return &URI{*rr.Hdr.copyHeader(), rr.Priority, rr.Weight, rr.Target}
+}
+func (rr *X25) copy() RR {
+       return &X25{*rr.Hdr.copyHeader(), rr.PSDNAddress}
+}
index 7707a948b7cfc07af6861ccf9e2f783044bce5dc..5dadf54ee3f34de52dd8857c0c68ff3bdee0ed63 100644 (file)
                        "revision": "d0c3fe89de86839aecf2e0579c40ba3bb336a453",
                        "revisionTime": "2015-10-11T12:25:29+02:00"
                },
+               {
+                       "checksumSHA1": "Y89CHl2URaBbobeyCOr4kzbLwYE=",
+                       "path": "github.com/miekg/dns",
+                       "revision": "5d001d020961ae1c184f9f8152fdc73810481677",
+                       "revisionTime": "2016-06-14T16:21:01Z"
+               },
                {
                        "path": "github.com/prometheus/client_golang/prometheus",
                        "revision": "90c15b5efa0dc32a7d259234e02ac9a99e6d3b82",