Browse Source

Update github.com/miekg/dns

(Sep 12 2015 to Mar 12 2016, 8395762c349..b9171237b064)
Ask Bjørn Hansen 9 years ago
parent
commit
5ce33417e1
42 changed files with 2439 additions and 1008 deletions
  1. 1 1
      Godeps/Godeps.json
  2. 2 2
      Godeps/_workspace/src/github.com/miekg/dns/.travis.yml
  3. 12 3
      Godeps/_workspace/src/github.com/miekg/dns/README.md
  4. 90 32
      Godeps/_workspace/src/github.com/miekg/dns/client.go
  5. 191 58
      Godeps/_workspace/src/github.com/miekg/dns/client_test.go
  6. 4 9
      Godeps/_workspace/src/github.com/miekg/dns/clientconfig_test.go
  7. 8 5
      Godeps/_workspace/src/github.com/miekg/dns/defaults.go
  8. 2 2
      Godeps/_workspace/src/github.com/miekg/dns/dns_test.go
  9. 15 10
      Godeps/_workspace/src/github.com/miekg/dns/dnssec.go
  10. 21 10
      Godeps/_workspace/src/github.com/miekg/dns/dnssec_test.go
  11. 79 0
      Godeps/_workspace/src/github.com/miekg/dns/dnsutil/util.go
  12. 130 0
      Godeps/_workspace/src/github.com/miekg/dns/dnsutil/util_test.go
  13. 3 3
      Godeps/_workspace/src/github.com/miekg/dns/doc.go
  14. 0 9
      Godeps/_workspace/src/github.com/miekg/dns/edns.go
  15. 4 5
      Godeps/_workspace/src/github.com/miekg/dns/example_test.go
  16. 0 1
      Godeps/_workspace/src/github.com/miekg/dns/idn/punycode.go
  17. 23 0
      Godeps/_workspace/src/github.com/miekg/dns/issue_test.go
  18. 7 1
      Godeps/_workspace/src/github.com/miekg/dns/labels.go
  19. 18 19
      Godeps/_workspace/src/github.com/miekg/dns/labels_test.go
  20. 53 138
      Godeps/_workspace/src/github.com/miekg/dns/msg.go
  21. 10 10
      Godeps/_workspace/src/github.com/miekg/dns/parse_test.go
  22. 4 4
      Godeps/_workspace/src/github.com/miekg/dns/privaterr.go
  23. 2 2
      Godeps/_workspace/src/github.com/miekg/dns/privaterr_test.go
  24. 3 3
      Godeps/_workspace/src/github.com/miekg/dns/rawmsg.go
  25. 6 6
      Godeps/_workspace/src/github.com/miekg/dns/sanitize_test.go
  26. 106 75
      Godeps/_workspace/src/github.com/miekg/dns/server.go
  27. 249 20
      Godeps/_workspace/src/github.com/miekg/dns/server_test.go
  28. 8 8
      Godeps/_workspace/src/github.com/miekg/dns/sig0_test.go
  29. 1 1
      Godeps/_workspace/src/github.com/miekg/dns/tlsa.go
  30. 2 15
      Godeps/_workspace/src/github.com/miekg/dns/tsig.go
  31. 37 0
      Godeps/_workspace/src/github.com/miekg/dns/tsig_test.go
  32. 23 436
      Godeps/_workspace/src/github.com/miekg/dns/types.go
  33. 266 0
      Godeps/_workspace/src/github.com/miekg/dns/types_generate.go
  34. 10 0
      Godeps/_workspace/src/github.com/miekg/dns/udp_linux.go
  35. 50 38
      Godeps/_workspace/src/github.com/miekg/dns/update.go
  36. 68 7
      Godeps/_workspace/src/github.com/miekg/dns/update_test.go
  37. 15 3
      Godeps/_workspace/src/github.com/miekg/dns/xfr.go
  38. 2 2
      Godeps/_workspace/src/github.com/miekg/dns/xfr_test.go
  39. 1 1
      Godeps/_workspace/src/github.com/miekg/dns/zgenerate.go
  40. 7 5
      Godeps/_workspace/src/github.com/miekg/dns/zscan.go
  41. 64 64
      Godeps/_workspace/src/github.com/miekg/dns/zscan_rr.go
  42. 842 0
      Godeps/_workspace/src/github.com/miekg/dns/ztypes.go

+ 1 - 1
Godeps/Godeps.json

@@ -16,7 +16,7 @@
 		},
 		{
 			"ImportPath": "github.com/miekg/dns",
-			"Rev": "8395762c3490507cf5a27405fcd0e3d3dc547109"
+			"Rev": "b9171237b0642de1d8e8004f16869970e065f46b"
 		},
 		{
 			"ImportPath": "github.com/pborman/uuid",

+ 2 - 2
Godeps/_workspace/src/github.com/miekg/dns/.travis.yml

@@ -1,7 +1,7 @@
 language: go
 sudo: false
 go:
-  - 1.4
   - 1.5
+  - 1.6
 script:
-  - go test -race -bench=.
+  - go test -race -v -bench=.

+ 12 - 3
Godeps/_workspace/src/github.com/miekg/dns/README.md

@@ -10,9 +10,9 @@ 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.
 
-If you like this, you may also be interested in:
-
-* https://github.com/miekg/unbound -- Go wrapper for the Unbound resolver.
+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.4 and 1.5.
 
 # Goals
 
@@ -33,6 +33,7 @@ A not-so-up-to-date-list-that-may-be-actually-current:
 * 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
@@ -42,6 +43,11 @@ A not-so-up-to-date-list-that-may-be-actually-current:
 * 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
 
 Send pull request if you want to be listed here.
 
@@ -58,6 +64,7 @@ Send pull request if you want to be listed here.
 * EDNS0, NSID;
 * AXFR/IXFR;
 * TSIG, SIG(0);
+* DNS over TLS: optional encrypted connection between client and server;
 * DNS name compression;
 * Depends only on the standard library.
 
@@ -123,6 +130,7 @@ Example programs can be found in the `github.com/miekg/exdns` repository.
 * 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
@@ -131,6 +139,7 @@ Example programs can be found in the `github.com/miekg/exdns` repository.
 * 7314 - DNS (EDNS) EXPIRE Option
 * 7553 - URI record
 * xxxx - EDNS0 DNS Update Lease (draft)
+* yyyy - DNS over TLS: Initiation and Performance Considerations (draft)
 
 ## Loosely based upon
 

+ 90 - 32
Godeps/_workspace/src/github.com/miekg/dns/client.go

@@ -4,6 +4,7 @@ package dns
 
 import (
 	"bytes"
+	"crypto/tls"
 	"io"
 	"net"
 	"time"
@@ -24,8 +25,9 @@ type Conn struct {
 
 // A Client defines parameters for a DNS client.
 type Client struct {
-	Net            string            // if "tcp" a TCP query will be initiated, otherwise an UDP one (default is "" for UDP)
+	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
 	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
@@ -37,14 +39,7 @@ type Client struct {
 // 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.
-// If you need to send a DNS message on an already existing connection, you can use the
-// following:
-//
-//	co := &dns.Conn{Conn: c} // c is your net.Conn
-//	co.WriteMsg(m)
-//	in, err  := co.ReadMsg()
-//	co.Close()
-//
+// 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)
@@ -53,8 +48,6 @@ func Exchange(m *Msg, a string) (r *Msg, err error) {
 	}
 
 	defer co.Close()
-	co.SetReadDeadline(time.Now().Add(dnsTimeout))
-	co.SetWriteDeadline(time.Now().Add(dnsTimeout))
 
 	opt := m.IsEdns0()
 	// If EDNS0 is used use that for size.
@@ -62,9 +55,12 @@ func Exchange(m *Msg, a string) (r *Msg, err error) {
 		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
@@ -103,6 +99,10 @@ func ExchangeConn(c net.Conn, m *Msg) (r *Msg, err error) {
 //
 // 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)
@@ -151,11 +151,31 @@ func (c *Client) writeTimeout() time.Duration {
 
 func (c *Client) exchange(m *Msg, a string) (r *Msg, rtt time.Duration, err error) {
 	var co *Conn
-	if c.Net == "" {
-		co, err = DialTimeout("udp", a, c.dialTimeout())
+	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
+		}
+	}
+
+	if tls {
+		co, err = DialTimeoutWithTLS(network, a, c.TLSConfig, c.dialTimeout())
 	} else {
-		co, err = DialTimeout(c.Net, a, c.dialTimeout())
+		co, err = DialTimeout(network, a, c.dialTimeout())
 	}
+
 	if err != nil {
 		return nil, 0, err
 	}
@@ -171,13 +191,13 @@ func (c *Client) exchange(m *Msg, a string) (r *Msg, rtt time.Duration, err erro
 		co.UDPSize = c.UDPSize
 	}
 
-	co.SetReadDeadline(time.Now().Add(c.readTimeout()))
-	co.SetWriteDeadline(time.Now().Add(c.writeTimeout()))
-
 	co.TsigSecret = c.TsigSecret
+	co.SetWriteDeadline(time.Now().Add(c.writeTimeout()))
 	if err = co.WriteMsg(m); err != nil {
 		return nil, 0, err
 	}
+
+	co.SetReadDeadline(time.Now().Add(c.readTimeout()))
 	r, err = co.ReadMsg()
 	if err == nil && r.Id != m.Id {
 		err = ErrId
@@ -196,6 +216,12 @@ func (co *Conn) ReadMsg() (*Msg, error) {
 
 	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 {
@@ -218,21 +244,26 @@ func (co *Conn) ReadMsgHeader(hdr *Header) ([]byte, error) {
 		err error
 	)
 
-	if t, ok := co.Conn.(*net.TCPConn); ok {
+	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(t)
+		l, err := tcpMsgLen(r)
 		if err != nil {
 			return nil, err
 		}
 		p = make([]byte, l)
-		n, err = tcpRead(t, p)
-	} else {
+		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 {
@@ -251,7 +282,7 @@ func (co *Conn) ReadMsgHeader(hdr *Header) ([]byte, error) {
 }
 
 // tcpMsgLen is a helper func to read first two bytes of stream as uint16 packet length.
-func tcpMsgLen(t *net.TCPConn) (int, error) {
+func tcpMsgLen(t io.Reader) (int, error) {
 	p := []byte{0, 0}
 	n, err := t.Read(p)
 	if err != nil {
@@ -268,7 +299,7 @@ func tcpMsgLen(t *net.TCPConn) (int, error) {
 }
 
 // tcpRead calls TCPConn.Read enough times to fill allocated buffer.
-func tcpRead(t *net.TCPConn, p []byte) (int, error) {
+func tcpRead(t io.Reader, p []byte) (int, error) {
 	n, err := t.Read(p)
 	if err != nil {
 		return n, err
@@ -291,27 +322,28 @@ func (co *Conn) Read(p []byte) (n int, err error) {
 	if len(p) < 2 {
 		return 0, io.ErrShortBuffer
 	}
-	if t, ok := co.Conn.(*net.TCPConn); ok {
-		l, err := tcpMsgLen(t)
+	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(t, p[:l])
+		return tcpRead(r, p[:l])
 	}
 	// UDP connection
 	n, err = co.Conn.Read(p)
 	if err != nil {
 		return n, err
 	}
-
-	co.rtt = time.Since(co.t)
 	return n, err
 }
 
-// WriteMsg sends a message throught the connection co.
+// 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) {
@@ -322,7 +354,7 @@ func (co *Conn) WriteMsg(m *Msg) (err error) {
 			return ErrSecret
 		}
 		out, mac, err = TsigGenerate(m, co.TsigSecret[t.Hdr.Name], co.tsigRequestMAC, false)
-		// Set for the next read, allthough only used in zone transfers
+		// Set for the next read, although only used in zone transfers
 		co.tsigRequestMAC = mac
 	} else {
 		out, err = m.Pack()
@@ -339,7 +371,10 @@ func (co *Conn) WriteMsg(m *Msg) (err error) {
 
 // Write implements the net.Conn Write method.
 func (co *Conn) Write(p []byte) (n int, err error) {
-	if t, ok := co.Conn.(*net.TCPConn); ok {
+	switch t := co.Conn.(type) {
+	case *net.TCPConn, *tls.Conn:
+		w := t.(io.Writer)
+
 		lp := len(p)
 		if lp < 2 {
 			return 0, io.ErrShortBuffer
@@ -350,7 +385,7 @@ func (co *Conn) Write(p []byte) (n int, err error) {
 		l := make([]byte, 2, lp+2)
 		l[0], l[1] = packUint16(uint16(lp))
 		p = append(l, p...)
-		n, err := io.Copy(t, bytes.NewReader(p))
+		n, err := io.Copy(w, bytes.NewReader(p))
 		return int(n), err
 	}
 	n, err = co.Conn.(*net.UDPConn).Write(p)
@@ -376,3 +411,26 @@ func DialTimeout(network, address string, timeout time.Duration) (conn *Conn, er
 	}
 	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
+}

+ 191 - 58
Godeps/_workspace/src/github.com/miekg/dns/client_test.go

@@ -1,6 +1,9 @@
 package dns
 
 import (
+	"crypto/tls"
+	"fmt"
+	"net"
 	"strconv"
 	"testing"
 	"time"
@@ -12,7 +15,7 @@ func TestClientSync(t *testing.T) {
 
 	s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
 	if err != nil {
-		t.Fatalf("Unable to run test server: %v", err)
+		t.Fatalf("unable to run test server: %v", err)
 	}
 	defer s.Shutdown()
 
@@ -37,13 +40,50 @@ func TestClientSync(t *testing.T) {
 	}
 }
 
+func TestClientTLSSync(t *testing.T) {
+	HandleFunc("miek.nl.", HelloServer)
+	defer HandleRemove("miek.nl.")
+
+	cert, err := tls.X509KeyPair(CertPEMBlock, KeyPEMBlock)
+	if err != nil {
+		t.Fatalf("unable to build certificate: %v", err)
+	}
+
+	config := tls.Config{
+		Certificates: []tls.Certificate{cert},
+	}
+
+	s, addrstr, err := RunLocalTLSServer("127.0.0.1:0", &config)
+	if err != nil {
+		t.Fatalf("unable to run test server: %v", err)
+	}
+	defer s.Shutdown()
+
+	m := new(Msg)
+	m.SetQuestion("miek.nl.", TypeSOA)
+
+	c := new(Client)
+	c.Net = "tcp-tls"
+	c.TLSConfig = &tls.Config{
+		InsecureSkipVerify: true,
+	}
+
+	r, _, err := c.Exchange(m, addrstr)
+	if err != nil {
+		t.Errorf("failed to exchange: %v", err)
+	}
+	if r != nil && r.Rcode != RcodeSuccess {
+		t.Errorf("failed to get an valid answer\n%v", r)
+	}
+}
+
 func TestClientSyncBadId(t *testing.T) {
 	HandleFunc("miek.nl.", HelloServerBadId)
 	defer HandleRemove("miek.nl.")
 
 	s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
 	if err != nil {
-		t.Fatalf("Unable to run test server: %v", err)
+		t.Fatalf("unable to run test server: %v", err)
 	}
 	defer s.Shutdown()
 
@@ -66,7 +106,7 @@ func TestClientEDNS0(t *testing.T) {
 
 	s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
 	if err != nil {
-		t.Fatalf("Unable to run test server: %v", err)
+		t.Fatalf("unable to run test server: %v", err)
 	}
 	defer s.Shutdown()
 
@@ -113,7 +153,7 @@ func TestClientEDNS0Local(t *testing.T) {
 
 	s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
 	if err != nil {
-		t.Fatalf("Unable to run test server: %s", err)
+		t.Fatalf("unable to run test server: %s", err)
 	}
 	defer s.Shutdown()
 
@@ -161,58 +201,8 @@ func TestClientEDNS0Local(t *testing.T) {
 	}
 }
 
-func TestSingleInflight(t *testing.T) {
-	// Test is inherently racy, because queries might actually be returned before the test
-	// is over, leading to multiple queries even with SingleInflight. This ofcourse then
-	// leads to diff. rrts and the test fails. Number of tests is now 3, to lower the chance
-	// for the race to hit.
-	HandleFunc("miek.nl.", HelloServer)
-	defer HandleRemove("miek.nl.")
-
-	s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
-	if err != nil {
-		t.Fatalf("Unable to run test server: %v", err)
-	}
-	defer s.Shutdown()
-
-	m := new(Msg)
-	m.SetQuestion("miek.nl.", TypeDNSKEY)
-
-	c := new(Client)
-	c.SingleInflight = true
-	nr := 3
-	ch := make(chan time.Duration)
-	for i := 0; i < nr; i++ {
-		go func() {
-			_, rtt, _ := c.Exchange(m, addrstr)
-			ch <- rtt
-		}()
-	}
-	i := 0
-	var first time.Duration
-	// With inflight *all* rtt are identical, and by doing actual lookups
-	// the chances that this is a coincidence is small.
-Loop:
-	for {
-		select {
-		case rtt := <-ch:
-			if i == 0 {
-				first = rtt
-			} else {
-				if first != rtt {
-					t.Errorf("all rtts should be equal, got %d want %d", rtt, first)
-				}
-			}
-			i++
-			if i == nr {
-				break Loop
-			}
-		}
-	}
-}
-
-// ExampleUpdateLeaseTSIG shows how to update a lease signed with TSIG.
-func ExampleUpdateLeaseTSIG(t *testing.T) {
+// ExampleTsigSecret_updateLeaseTSIG shows how to update a lease signed with TSIG
+func ExampleTsigSecret_updateLeaseTSIG() {
 	m := new(Msg)
 	m.SetUpdate("t.local.ip6.io.")
 	rr, _ := NewRR("t.local.ip6.io. 30 A 127.0.0.1")
@@ -235,7 +225,7 @@ func ExampleUpdateLeaseTSIG(t *testing.T) {
 
 	_, _, err := c.Exchange(m, "127.0.0.1:53")
 	if err != nil {
-		t.Error(err)
+		panic(err)
 	}
 }
 
@@ -246,7 +236,7 @@ func TestClientConn(t *testing.T) {
 	// This uses TCP just to make it slightly different than TestClientSync
 	s, addrstr, err := RunLocalTCPServer("127.0.0.1:0")
 	if err != nil {
-		t.Fatalf("Unable to run test server: %v", err)
+		t.Fatalf("unable to run test server: %v", err)
 	}
 	defer s.Shutdown()
 
@@ -286,3 +276,146 @@ func TestClientConn(t *testing.T) {
 		t.Errorf("unable to unpack message fully: %v", err)
 	}
 }
+
+func TestTruncatedMsg(t *testing.T) {
+	m := new(Msg)
+	m.SetQuestion("miek.nl.", TypeSRV)
+	cnt := 10
+	for i := 0; i < cnt; i++ {
+		r := &SRV{
+			Hdr:    RR_Header{Name: m.Question[0].Name, Rrtype: TypeSRV, Class: ClassINET, Ttl: 0},
+			Port:   uint16(i + 8000),
+			Target: "target.miek.nl.",
+		}
+		m.Answer = append(m.Answer, r)
+
+		re := &A{
+			Hdr: RR_Header{Name: m.Question[0].Name, Rrtype: TypeA, Class: ClassINET, Ttl: 0},
+			A:   net.ParseIP(fmt.Sprintf("127.0.0.%d", i)).To4(),
+		}
+		m.Extra = append(m.Extra, re)
+	}
+	buf, err := m.Pack()
+	if err != nil {
+		t.Errorf("failed to pack: %v", err)
+	}
+
+	r := new(Msg)
+	if err = r.Unpack(buf); err != nil {
+		t.Errorf("unable to unpack message: %v", err)
+	}
+	if len(r.Answer) != cnt {
+		t.Logf("answer count after regular unpack doesn't match: %d", len(r.Answer))
+		t.Fail()
+	}
+	if len(r.Extra) != cnt {
+		t.Logf("extra count after regular unpack doesn't match: %d", len(r.Extra))
+		t.Fail()
+	}
+
+	m.Truncated = true
+	buf, err = m.Pack()
+	if err != nil {
+		t.Errorf("failed to pack truncated: %v", err)
+	}
+
+	r = new(Msg)
+	if err = r.Unpack(buf); err != nil && err != ErrTruncated {
+		t.Errorf("unable to unpack truncated message: %v", err)
+	}
+	if !r.Truncated {
+		t.Log("truncated message wasn't unpacked as truncated")
+		t.Fail()
+	}
+	if len(r.Answer) != cnt {
+		t.Logf("answer count after truncated unpack doesn't match: %d", len(r.Answer))
+		t.Fail()
+	}
+	if len(r.Extra) != cnt {
+		t.Logf("extra count after truncated unpack doesn't match: %d", len(r.Extra))
+		t.Fail()
+	}
+
+	// Now we want to remove almost all of the extra records
+	// We're going to loop over the extra to get the count of the size of all
+	// of them
+	off := 0
+	buf1 := make([]byte, m.Len())
+	for i := 0; i < len(m.Extra); i++ {
+		off, err = PackRR(m.Extra[i], buf1, off, nil, m.Compress)
+		if err != nil {
+			t.Errorf("failed to pack extra: %v", err)
+		}
+	}
+
+	// Remove all of the extra bytes but 10 bytes from the end of buf
+	off -= 10
+	buf1 = buf[:len(buf)-off]
+
+	r = new(Msg)
+	if err = r.Unpack(buf1); err != nil && err != ErrTruncated {
+		t.Errorf("unable to unpack cutoff message: %v", err)
+	}
+	if !r.Truncated {
+		t.Log("truncated cutoff message wasn't unpacked as truncated")
+		t.Fail()
+	}
+	if len(r.Answer) != cnt {
+		t.Logf("answer count after cutoff unpack doesn't match: %d", len(r.Answer))
+		t.Fail()
+	}
+	if len(r.Extra) != 0 {
+		t.Logf("extra count after cutoff unpack is not zero: %d", len(r.Extra))
+		t.Fail()
+	}
+
+	// Now we want to remove almost all of the answer records too
+	buf1 = make([]byte, m.Len())
+	as := 0
+	for i := 0; i < len(m.Extra); i++ {
+		off1 := off
+		off, err = PackRR(m.Extra[i], buf1, off, nil, m.Compress)
+		as = off - off1
+		if err != nil {
+			t.Errorf("failed to pack extra: %v", err)
+		}
+	}
+
+	// Keep exactly one answer left
+	// This should still cause Answer to be nil
+	off -= as
+	buf1 = buf[:len(buf)-off]
+
+	r = new(Msg)
+	if err = r.Unpack(buf1); err != nil && err != ErrTruncated {
+		t.Errorf("unable to unpack cutoff message: %v", err)
+	}
+	if !r.Truncated {
+		t.Log("truncated cutoff message wasn't unpacked as truncated")
+		t.Fail()
+	}
+	if len(r.Answer) != 0 {
+		t.Logf("answer count after second cutoff unpack is not zero: %d", len(r.Answer))
+		t.Fail()
+	}
+
+	// Now leave only 1 byte of the question
+	// Since the header is always 12 bytes, we just need to keep 13
+	buf1 = buf[:13]
+
+	r = new(Msg)
+	err = r.Unpack(buf1)
+	if err == nil || err == ErrTruncated {
+		t.Logf("error should not be ErrTruncated from question cutoff unpack: %v", err)
+		t.Fail()
+	}
+
+	// Finally, if we only have the header, we should still return an error
+	buf1 = buf[:12]
+
+	r = new(Msg)
+	if err = r.Unpack(buf1); err == nil || err != ErrTruncated {
+		t.Logf("error not ErrTruncated from header-only unpack: %v", err)
+		t.Fail()
+	}
+}

+ 4 - 9
Godeps/_workspace/src/github.com/miekg/dns/clientconfig_test.go

@@ -22,13 +22,13 @@ nameserver 11.28.10.1` // <- NOTE: NO newline.
 func testConfig(t *testing.T, data string) {
 	tempDir, err := ioutil.TempDir("", "")
 	if err != nil {
-		t.Fatalf("TempDir: %v", err)
+		t.Fatalf("tempDir: %v", err)
 	}
 	defer os.RemoveAll(tempDir)
 
 	path := filepath.Join(tempDir, "resolv.conf")
 	if err := ioutil.WriteFile(path, []byte(data), 0644); err != nil {
-		t.Fatalf("WriteFile: %v", err)
+		t.Fatalf("writeFile: %v", err)
 	}
 	cc, err := ClientConfigFromFile(path)
 	if err != nil {
@@ -46,10 +46,5 @@ func testConfig(t *testing.T, data string) {
 	}
 }
 
-func TestNameserver(t *testing.T) {
-	testConfig(t, normal)
-}
-
-func TestMissingFinalNewLine(t *testing.T) {
-	testConfig(t, missingNewline)
-}
+func TestNameserver(t *testing.T)          { testConfig(t, normal) }
+func TestMissingFinalNewLine(t *testing.T) { testConfig(t, missingNewline) }

+ 8 - 5
Godeps/_workspace/src/github.com/miekg/dns/defaults.go

@@ -150,11 +150,14 @@ func (dns *Msg) IsEdns0() *OPT {
 	return nil
 }
 
-// IsDomainName checks if s is a valid domainname, 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.
+// 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

+ 2 - 2
Godeps/_workspace/src/github.com/miekg/dns/dns_test.go

@@ -428,7 +428,7 @@ func TestToRFC3597(t *testing.T) {
 
 func TestNoRdataPack(t *testing.T) {
 	data := make([]byte, 1024)
-	for typ, fn := range typeToRR {
+	for typ, fn := range TypeToRR {
 		r := fn()
 		*r.Header() = RR_Header{Name: "miek.nl.", Rrtype: typ, Class: ClassINET, Ttl: 3600}
 		_, err := PackRR(r, data, 0, nil, false)
@@ -441,7 +441,7 @@ func TestNoRdataPack(t *testing.T) {
 // TODO(miek): fix dns buffer too small errors this throws
 func TestNoRdataUnpack(t *testing.T) {
 	data := make([]byte, 1024)
-	for typ, fn := range typeToRR {
+	for typ, fn := range TypeToRR {
 		if typ == TypeSOA || typ == TypeTSIG || typ == TypeWKS {
 			// SOA, TSIG will not be seen (like this) in dyn. updates?
 			// WKS is an bug, but...deprecated record.

+ 15 - 10
Godeps/_workspace/src/github.com/miekg/dns/dnssec.go

@@ -104,7 +104,7 @@ const (
 )
 
 // The RRSIG needs to be converted to wireformat with some of
-// the rdata (the signature) missing. Use this struct to easy
+// the rdata (the signature) missing. Use this struct to ease
 // the conversion (and re-use the pack/unpack functions).
 type rrsigWireFmt struct {
 	TypeCovered uint16
@@ -248,13 +248,12 @@ func (d *DS) ToCDS() *CDS {
 	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 true when the signing went OK,
-// otherwise false.
-// 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.
+// 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
@@ -421,8 +420,8 @@ func (rr *RRSIG) Verify(k *DNSKEY, rrset []RR) error {
 
 	sigbuf := rr.sigBuf()           // Get the binary signature data
 	if rr.Algorithm == PRIVATEDNS { // PRIVATEOID
-		// TODO(mg)
-		// remove the domain name and assume its our
+		// TODO(miek)
+		// remove the domain name and assume its ours?
 	}
 
 	hash, ok := AlgorithmToHash[rr.Algorithm]
@@ -609,6 +608,12 @@ func rawSignatureData(rrset []RR, s *RRSIG) (buf []byte, err error) {
 		//   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)

+ 21 - 10
Godeps/_workspace/src/github.com/miekg/dns/dnssec_test.go

@@ -171,6 +171,17 @@ func TestSignVerify(t *testing.T) {
 	srv.Weight = 800
 	srv.Target = "web1.miek.nl."
 
+	hinfo := &HINFO{
+		Hdr: RR_Header{
+			Name:   "miek.nl.",
+			Rrtype: TypeHINFO,
+			Class:  ClassINET,
+			Ttl:    3789,
+		},
+		Cpu: "X",
+		Os:  "Y",
+	}
+
 	// With this key
 	key := new(DNSKEY)
 	key.Hdr.Rrtype = TypeDNSKEY
@@ -194,12 +205,12 @@ func TestSignVerify(t *testing.T) {
 	sig.SignerName = key.Hdr.Name
 	sig.Algorithm = RSASHA256
 
-	for _, r := range []RR{soa, soa1, srv} {
-		if sig.Sign(privkey.(*rsa.PrivateKey), []RR{r}) != nil {
-			t.Error("failure to sign the record")
+	for _, r := range []RR{soa, soa1, srv, hinfo} {
+		if err := sig.Sign(privkey.(*rsa.PrivateKey), []RR{r}); err != nil {
+			t.Error("failure to sign the record:", err)
 			continue
 		}
-		if sig.Verify(key, []RR{r}) != nil {
+		if err := sig.Verify(key, []RR{r}); err != nil {
 			t.Error("failure to validate")
 			continue
 		}
@@ -451,7 +462,7 @@ PrivateKey: WURgWHCcYIYUPWgeLmiPY2DJJk02vgrmTfitxgqcL4vwW7BOrbawVmVe0d9V94SR`
 	}
 
 	if err := sig.Verify(eckey.(*DNSKEY), []RR{a}); err != nil {
-		t.Fatalf("Failure to validate:\n%s\n%s\n%s\n\n%s\n\n%v",
+		t.Fatalf("failure to validate:\n%s\n%s\n%s\n\n%s\n\n%v",
 			eckey.(*DNSKEY).String(),
 			a.String(),
 			sig.String(),
@@ -500,7 +511,7 @@ func TestSignVerifyECDSA2(t *testing.T) {
 
 	err = sig.Verify(key, []RR{srv})
 	if err != nil {
-		t.Logf("Failure to validate:\n%s\n%s\n%s\n\n%s\n\n%v",
+		t.Logf("failure to validate:\n%s\n%s\n%s\n\n%s\n\n%v",
 			key.String(),
 			srv.String(),
 			sig.String(),
@@ -554,7 +565,7 @@ PrivateKey: GU6SnQ/Ou+xC5RumuIUIuJZteXT2z0O/ok1s38Et6mQ=`
 		t.Fatal(err)
 	}
 	if err = rrRRSIG.(*RRSIG).Verify(rrDNSKEY.(*DNSKEY), []RR{rrA}); err != nil {
-		t.Errorf("Failure to validate the spec RRSIG: %v", err)
+		t.Errorf("failure to validate the spec RRSIG: %v", err)
 	}
 
 	ourRRSIG := &RRSIG{
@@ -573,7 +584,7 @@ PrivateKey: GU6SnQ/Ou+xC5RumuIUIuJZteXT2z0O/ok1s38Et6mQ=`
 	}
 
 	if err = ourRRSIG.Verify(rrDNSKEY.(*DNSKEY), []RR{rrA}); err != nil {
-		t.Errorf("Failure to validate our RRSIG: %v", err)
+		t.Errorf("failure to validate our RRSIG: %v", err)
 	}
 
 	// Signatures are randomized
@@ -630,7 +641,7 @@ PrivateKey: WURgWHCcYIYUPWgeLmiPY2DJJk02vgrmTfitxgqcL4vwW7BOrbawVmVe0d9V94SR`
 		t.Fatal(err)
 	}
 	if err = rrRRSIG.(*RRSIG).Verify(rrDNSKEY.(*DNSKEY), []RR{rrA}); err != nil {
-		t.Errorf("Failure to validate the spec RRSIG: %v", err)
+		t.Errorf("failure to validate the spec RRSIG: %v", err)
 	}
 
 	ourRRSIG := &RRSIG{
@@ -649,7 +660,7 @@ PrivateKey: WURgWHCcYIYUPWgeLmiPY2DJJk02vgrmTfitxgqcL4vwW7BOrbawVmVe0d9V94SR`
 	}
 
 	if err = ourRRSIG.Verify(rrDNSKEY.(*DNSKEY), []RR{rrA}); err != nil {
-		t.Errorf("Failure to validate our RRSIG: %v", err)
+		t.Errorf("failure to validate our RRSIG: %v", err)
 	}
 
 	// Signatures are randomized

+ 79 - 0
Godeps/_workspace/src/github.com/miekg/dns/dnsutil/util.go

@@ -0,0 +1,79 @@
+// Package dnsutil contains higher-level methods useful with the dns
+// package.  While package dns implements the DNS protocols itself,
+// these functions are related but not directly required for protocol
+// processing.  They are often useful in preparing input/output of the
+// functions in package dns.
+package dnsutil
+
+import (
+	"strings"
+
+	"github.com/abh/geodns/Godeps/_workspace/src/github.com/miekg/dns"
+)
+
+// AddDomain adds origin to s if s is not already a FQDN.
+// Note that the result may not be a FQDN.  If origin does not end
+// with a ".", the result won't either.
+// This implements the zonefile convention (specified in RFC 1035,
+// Section "5.1. Format") that "@" represents the
+// apex (bare) domain. i.e. AddOrigin("@", "foo.com.") returns "foo.com.".
+func AddOrigin(s, origin string) string {
+	// ("foo.", "origin.") -> "foo." (already a FQDN)
+	// ("foo", "origin.") -> "foo.origin."
+	// ("foo"), "origin" -> "foo.origin"
+	// ("@", "origin.") -> "origin." (@ represents the apex (bare) domain)
+	// ("", "origin.") -> "origin." (not obvious)
+	// ("foo", "") -> "foo" (not obvious)
+
+	if dns.IsFqdn(s) {
+		return s // s is already a FQDN, no need to mess with it.
+	}
+	if len(origin) == 0 {
+		return s // Nothing to append.
+	}
+	if s == "@" || len(s) == 0 {
+		return origin // Expand apex.
+	}
+
+	if origin == "." {
+		return s + origin // AddOrigin(s, ".") is an expensive way to add a ".".
+	}
+
+	return s + "." + origin // The simple case.
+}
+
+// TrimDomainName trims origin from s if s is a subdomain.
+// This function will never return "", but returns "@" instead (@ represents the apex (bare) domain).
+func TrimDomainName(s, origin string) string {
+	// An apex (bare) domain is always returned as "@".
+	// If the return value ends in a ".", the domain was not the suffix.
+	// origin can end in "." or not. Either way the results should be the same.
+
+	if len(s) == 0 {
+		return "@" // Return the apex (@) rather than "".
+	}
+	// Someone is using TrimDomainName(s, ".") to remove a dot if it exists.
+	if origin == "." {
+		return strings.TrimSuffix(s, origin)
+	}
+
+	// Dude, you aren't even if the right subdomain!
+	if !dns.IsSubDomain(origin, s) {
+		return s
+	}
+
+	slabels := dns.Split(s)
+	olabels := dns.Split(origin)
+	m := dns.CompareDomainName(s, origin)
+	if len(olabels) == m {
+		if len(olabels) == len(slabels) {
+			return "@" // origin == s
+		}
+		if (s[0] == '.') && (len(slabels) == (len(olabels) + 1)) {
+			return "@" // TrimDomainName(".foo.", "foo.")
+		}
+	}
+
+	// Return the first (len-m) labels:
+	return s[:slabels[len(slabels)-m]-1]
+}

+ 130 - 0
Godeps/_workspace/src/github.com/miekg/dns/dnsutil/util_test.go

@@ -0,0 +1,130 @@
+package dnsutil
+
+import "testing"
+
+func TestAddOrigin(t *testing.T) {
+	var tests = []struct{ e1, e2, expected string }{
+		{"@", "example.com", "example.com"},
+		{"foo", "example.com", "foo.example.com"},
+		{"foo.", "example.com", "foo."},
+		{"@", "example.com.", "example.com."},
+		{"foo", "example.com.", "foo.example.com."},
+		{"foo.", "example.com.", "foo."},
+		// Oddball tests:
+		// In general origin should not be "" or "." but at least
+		// these tests verify we don't crash and will keep results
+		// from changing unexpectedly.
+		{"*.", "", "*."},
+		{"@", "", "@"},
+		{"foobar", "", "foobar"},
+		{"foobar.", "", "foobar."},
+		{"*.", ".", "*."},
+		{"@", ".", "."},
+		{"foobar", ".", "foobar."},
+		{"foobar.", ".", "foobar."},
+	}
+	for _, test := range tests {
+		actual := AddOrigin(test.e1, test.e2)
+		if test.expected != actual {
+			t.Errorf("AddOrigin(%#v, %#v) expected %#v, go %#v\n", test.e1, test.e2, test.expected, actual)
+		}
+	}
+}
+
+func TestTrimDomainName(t *testing.T) {
+
+	// Basic tests.
+	// Try trimming "example.com" and "example.com." from typical use cases.
+	var tests_examplecom = []struct{ experiment, expected string }{
+		{"foo.example.com", "foo"},
+		{"foo.example.com.", "foo"},
+		{".foo.example.com", ".foo"},
+		{".foo.example.com.", ".foo"},
+		{"*.example.com", "*"},
+		{"example.com", "@"},
+		{"example.com.", "@"},
+		{"com.", "com."},
+		{"foo.", "foo."},
+		{"serverfault.com.", "serverfault.com."},
+		{"serverfault.com", "serverfault.com"},
+		{".foo.ronco.com", ".foo.ronco.com"},
+		{".foo.ronco.com.", ".foo.ronco.com."},
+	}
+	for _, dom := range []string{"example.com", "example.com."} {
+		for i, test := range tests_examplecom {
+			actual := TrimDomainName(test.experiment, dom)
+			if test.expected != actual {
+				t.Errorf("%d TrimDomainName(%#v, %#v): expected (%v) got (%v)\n", i, test.experiment, dom, test.expected, actual)
+			}
+		}
+	}
+
+	// Paranoid tests.
+	// These test shouldn't be needed but I was weary of off-by-one errors.
+	// In theory, these can't happen because there are no single-letter TLDs,
+	// but it is good to exercize the code this way.
+	var tests = []struct{ experiment, expected string }{
+		{"", "@"},
+		{".", "."},
+		{"a.b.c.d.e.f.", "a.b.c.d.e"},
+		{"b.c.d.e.f.", "b.c.d.e"},
+		{"c.d.e.f.", "c.d.e"},
+		{"d.e.f.", "d.e"},
+		{"e.f.", "e"},
+		{"f.", "@"},
+		{".a.b.c.d.e.f.", ".a.b.c.d.e"},
+		{".b.c.d.e.f.", ".b.c.d.e"},
+		{".c.d.e.f.", ".c.d.e"},
+		{".d.e.f.", ".d.e"},
+		{".e.f.", ".e"},
+		{".f.", "@"},
+		{"a.b.c.d.e.f", "a.b.c.d.e"},
+		{"a.b.c.d.e.", "a.b.c.d.e."},
+		{"a.b.c.d.e", "a.b.c.d.e"},
+		{"a.b.c.d.", "a.b.c.d."},
+		{"a.b.c.d", "a.b.c.d"},
+		{"a.b.c.", "a.b.c."},
+		{"a.b.c", "a.b.c"},
+		{"a.b.", "a.b."},
+		{"a.b", "a.b"},
+		{"a.", "a."},
+		{"a", "a"},
+		{".a.b.c.d.e.f", ".a.b.c.d.e"},
+		{".a.b.c.d.e.", ".a.b.c.d.e."},
+		{".a.b.c.d.e", ".a.b.c.d.e"},
+		{".a.b.c.d.", ".a.b.c.d."},
+		{".a.b.c.d", ".a.b.c.d"},
+		{".a.b.c.", ".a.b.c."},
+		{".a.b.c", ".a.b.c"},
+		{".a.b.", ".a.b."},
+		{".a.b", ".a.b"},
+		{".a.", ".a."},
+		{".a", ".a"},
+	}
+	for _, dom := range []string{"f", "f."} {
+		for i, test := range tests {
+			actual := TrimDomainName(test.experiment, dom)
+			if test.expected != actual {
+				t.Errorf("%d TrimDomainName(%#v, %#v): expected (%v) got (%v)\n", i, test.experiment, dom, test.expected, actual)
+			}
+		}
+	}
+
+	// Test cases for bugs found in the wild.
+	// These test cases provide both origin, s, and the expected result.
+	// If you find a bug in the while, this is probably the easiest place
+	// to add it as a test case.
+	var tests_wild = []struct{ e1, e2, expected string }{
+		{"mathoverflow.net.", ".", "mathoverflow.net"},
+		{"mathoverflow.net", ".", "mathoverflow.net"},
+		{"", ".", "@"},
+		{"@", ".", "@"},
+	}
+	for i, test := range tests_wild {
+		actual := TrimDomainName(test.e1, test.e2)
+		if test.expected != actual {
+			t.Errorf("%d TrimDomainName(%#v, %#v): expected (%v) got (%v)\n", i, test.e1, test.e2, test.expected, actual)
+		}
+	}
+
+}

+ 3 - 3
Godeps/_workspace/src/github.com/miekg/dns/doc.go

@@ -101,7 +101,7 @@ 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 an request.
+to a request.
 
      m := new(dns.Msg)
      m.SetEdns0(4096, true)
@@ -184,9 +184,9 @@ Basic use pattern validating and replying to a message that has TSIG set.
 	dns.HandleFunc(".", handleRequest)
 
 	func handleRequest(w dns.ResponseWriter, r *dns.Msg) {
-		m := new(Msg)
+		m := new(dns.Msg)
 		m.SetReply(r)
-		if r.IsTsig() {
+		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())

+ 0 - 9
Godeps/_workspace/src/github.com/miekg/dns/edns.go

@@ -30,11 +30,6 @@ type OPT struct {
 	Option []EDNS0 `dns:"opt"`
 }
 
-// Header implements the RR interface.
-func (rr *OPT) Header() *RR_Header {
-	return &rr.Hdr
-}
-
 func (rr *OPT) String() string {
 	s := "\n;; OPT PSEUDOSECTION:\n; EDNS: version " + strconv.Itoa(int(rr.Version())) + "; "
 	if rr.Do() {
@@ -88,10 +83,6 @@ func (rr *OPT) len() int {
 	return l
 }
 
-func (rr *OPT) copy() RR {
-	return &OPT{*rr.Hdr.copyHeader(), rr.Option}
-}
-
 // return the old value -> delete SetVersion?
 
 // Version returns the EDNS version used. Only zero is defined.

+ 4 - 5
Godeps/_workspace/src/github.com/miekg/dns/example_test.go

@@ -3,9 +3,10 @@ package dns_test
 import (
 	"errors"
 	"fmt"
-	"github.com/abh/geodns/Godeps/_workspace/src/github.com/miekg/dns"
 	"log"
 	"net"
+
+	"github.com/abh/geodns/Godeps/_workspace/src/github.com/miekg/dns"
 )
 
 // Retrieve the MX records for miek.nl.
@@ -31,13 +32,11 @@ func ExampleMX() {
 
 // Retrieve the DNSKEY records of a zone and convert them
 // to DS records for SHA1, SHA256 and SHA384.
-func ExampleDS(zone string) {
+func ExampleDS() {
 	config, _ := dns.ClientConfigFromFile("/etc/resolv.conf")
 	c := new(dns.Client)
 	m := new(dns.Msg)
-	if zone == "" {
-		zone = "miek.nl"
-	}
+	zone := "miek.nl"
 	m.SetQuestion(dns.Fqdn(zone), dns.TypeDNSKEY)
 	m.SetEdns0(4096, true)
 	r, _, err := c.Exchange(m, config.Servers[0]+":"+config.Port)

+ 0 - 1
Godeps/_workspace/src/github.com/miekg/dns/idn/punycode.go

@@ -199,7 +199,6 @@ func needFromPunycode(s string) bool {
 			return true
 		}
 	}
-	panic("dns: not reached")
 }
 
 // encode transforms Unicode input bytes (that represent DNS label) into

+ 23 - 0
Godeps/_workspace/src/github.com/miekg/dns/issue_test.go

@@ -0,0 +1,23 @@
+package dns
+
+// Tests that solve that an specific issue.
+
+import "testing"
+
+func TestTCPRtt(t *testing.T) {
+	m := new(Msg)
+	m.RecursionDesired = true
+	m.SetQuestion("example.org.", TypeA)
+
+	c := &Client{}
+	for _, proto := range []string{"udp", "tcp"} {
+		c.Net = proto
+		_, rtt, err := c.Exchange(m, "8.8.4.4:53")
+		if err != nil {
+			t.Fatal(err)
+		}
+		if rtt == 0 {
+			t.Fatalf("expecting non zero rtt %s, got zero", c.Net)
+		}
+	}
+}

+ 7 - 1
Godeps/_workspace/src/github.com/miekg/dns/labels.go

@@ -4,9 +4,11 @@ package dns
 
 // 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
@@ -45,6 +47,8 @@ func SplitDomainName(s string) (labels []string) {
 //
 // 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)
@@ -85,6 +89,7 @@ func CompareDomainName(s1, s2 string) (n int) {
 }
 
 // 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
@@ -102,7 +107,8 @@ func CountLabel(s string) (labels int) {
 
 // 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.
+// 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

+ 18 - 19
Godeps/_workspace/src/github.com/miekg/dns/labels_test.go

@@ -1,8 +1,6 @@
 package dns
 
-import (
-	"testing"
-)
+import "testing"
 
 func TestCompareDomainName(t *testing.T) {
 	s1 := "www.miek.nl."
@@ -61,9 +59,9 @@ func TestSplit(t *testing.T) {
 
 func TestSplit2(t *testing.T) {
 	splitter := map[string][]int{
-		"www.miek.nl.": []int{0, 4, 9},
-		"www.miek.nl":  []int{0, 4, 9},
-		"nl":           []int{0},
+		"www.miek.nl.": {0, 4, 9},
+		"www.miek.nl":  {0, 4, 9},
+		"nl":           {0},
 	}
 	for s, i := range splitter {
 		x := Split(s)
@@ -125,13 +123,14 @@ func TestCountLabel(t *testing.T) {
 
 func TestSplitDomainName(t *testing.T) {
 	labels := map[string][]string{
-		"miek.nl":       []string{"miek", "nl"},
+		"miek.nl":       {"miek", "nl"},
 		".":             nil,
-		"www.miek.nl.":  []string{"www", "miek", "nl"},
-		"www.miek.nl":   []string{"www", "miek", "nl"},
-		"www..miek.nl":  []string{"www", "", "miek", "nl"},
-		`www\.miek.nl`:  []string{`www\.miek`, "nl"},
-		`www\\.miek.nl`: []string{`www\\`, "miek", "nl"},
+		"www.miek.nl.":  {"www", "miek", "nl"},
+		"www.miek.nl":   {"www", "miek", "nl"},
+		"www..miek.nl":  {"www", "", "miek", "nl"},
+		`www\.miek.nl`:  {`www\.miek`, "nl"},
+		`www\\.miek.nl`: {`www\\`, "miek", "nl"},
+		".www.miek.nl.": {"", "www", "miek", "nl"},
 	}
 domainLoop:
 	for domain, splits := range labels {
@@ -155,13 +154,13 @@ func TestIsDomainName(t *testing.T) {
 		lab int
 	}
 	names := map[string]*ret{
-		"..":               &ret{false, 1},
-		"@.":               &ret{true, 1},
-		"www.example.com":  &ret{true, 3},
-		"www.e%ample.com":  &ret{true, 3},
-		"www.example.com.": &ret{true, 3},
-		"mi\\k.nl.":        &ret{true, 2},
-		"mi\\k.nl":         &ret{true, 2},
+		"..":               {false, 1},
+		"@.":               {true, 1},
+		"www.example.com":  {true, 3},
+		"www.e%ample.com":  {true, 3},
+		"www.example.com.": {true, 3},
+		"mi\\k.nl.":        {true, 2},
+		"mi\\k.nl":         {true, 2},
 	}
 	for d, ok := range names {
 		l, k := IsDomainName(d)

+ 53 - 138
Godeps/_workspace/src/github.com/miekg/dns/msg.go

@@ -54,6 +54,9 @@ var (
 	ErrSoa error = &Error{err: "no SOA"}
 	// ErrTime indicates a timing error in TSIG authentication.
 	ErrTime error = &Error{err: "bad time"}
+	// 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.
+	ErrTruncated error = &Error{err: "failed to unpack truncated message"}
 )
 
 // Id, by default, returns a 16 bits random number to be used as a
@@ -89,84 +92,6 @@ type Msg struct {
 	Extra    []RR       // Holds the RR(s) of the additional section.
 }
 
-// TypeToString is a map of strings for each RR wire type.
-var TypeToString = map[uint16]string{
-	TypeA:          "A",
-	TypeAAAA:       "AAAA",
-	TypeAFSDB:      "AFSDB",
-	TypeANY:        "ANY", // Meta RR
-	TypeATMA:       "ATMA",
-	TypeAXFR:       "AXFR", // Meta RR
-	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",
-	TypeIPSECKEY:   "IPSECKEY",
-	TypeISDN:       "ISDN",
-	TypeIXFR:       "IXFR", // Meta RR
-	TypeKEY:        "KEY",
-	TypeKX:         "KX",
-	TypeL32:        "L32",
-	TypeL64:        "L64",
-	TypeLOC:        "LOC",
-	TypeLP:         "LP",
-	TypeMB:         "MB",
-	TypeMD:         "MD",
-	TypeMF:         "MF",
-	TypeMG:         "MG",
-	TypeMINFO:      "MINFO",
-	TypeMR:         "MR",
-	TypeMX:         "MX",
-	TypeNAPTR:      "NAPTR",
-	TypeNID:        "NID",
-	TypeNINFO:      "NINFO",
-	TypeNIMLOC:     "NIMLOC",
-	TypeNS:         "NS",
-	TypeNSAPPTR:    "NSAP-PTR",
-	TypeNSEC3:      "NSEC3",
-	TypeNSEC3PARAM: "NSEC3PARAM",
-	TypeNSEC:       "NSEC",
-	TypeNULL:       "NULL",
-	TypeOPT:        "OPT",
-	TypeOPENPGPKEY: "OPENPGPKEY",
-	TypePTR:        "PTR",
-	TypeRKEY:       "RKEY",
-	TypeRP:         "RP",
-	TypeRRSIG:      "RRSIG",
-	TypeRT:         "RT",
-	TypeSIG:        "SIG",
-	TypeSOA:        "SOA",
-	TypeSPF:        "SPF",
-	TypeSRV:        "SRV",
-	TypeSSHFP:      "SSHFP",
-	TypeTA:         "TA",
-	TypeTALINK:     "TALINK",
-	TypeTKEY:       "TKEY", // Meta RR
-	TypeTLSA:       "TLSA",
-	TypeTSIG:       "TSIG", // Meta RR
-	TypeTXT:        "TXT",
-	TypePX:         "PX",
-	TypeUID:        "UID",
-	TypeUINFO:      "UINFO",
-	TypeUNSPEC:     "UNSPEC",
-	TypeURI:        "URI",
-	TypeWKS:        "WKS",
-	TypeX25:        "X25",
-}
-
 // StringToType is the reverse of TypeToString, needed for string parsing.
 var StringToType = reverseInt16(TypeToString)
 
@@ -332,7 +257,7 @@ func packDomainName(s string, msg []byte, off int, compression map[string]int, c
 				roBs = string(bs)
 				bsFresh = true
 			}
-			// Dont try to compress '.'
+			// Don't try to compress '.'
 			if compress && roBs[begin:] != "." {
 				if p, ok := compression[roBs[begin:]]; !ok {
 					// Only offsets smaller than this can be used.
@@ -1316,8 +1241,8 @@ func unpackStructValue(val reflect.Value, msg []byte, off int) (off1 int, err er
 						continue
 					}
 				}
-				if off == lenmsg {
-					// zero rdata foo, OK for dyn. updates
+				if off == lenmsg && int(val.FieldByName("Hdr").FieldByName("Rdlength").Uint()) == 0 {
+					// zero rdata is ok for dyn updates, but only if rdlength is 0
 					break
 				}
 				s, off, err = UnpackDomainName(msg, off)
@@ -1461,7 +1386,7 @@ func UnpackRR(msg []byte, off int) (rr RR, off1 int, err error) {
 	}
 	end := off + int(h.Rdlength)
 	// make an rr of that type and re-unpack.
-	mk, known := typeToRR[h.Rrtype]
+	mk, known := TypeToRR[h.Rrtype]
 	if !known {
 		rr = new(RFC3597)
 	} else {
@@ -1474,6 +1399,32 @@ func UnpackRR(msg []byte, off int) (rr RR, off1 int, err error) {
 	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
+}
+
 // Reverse a map
 func reverseInt8(m map[uint8]string) map[string]uint8 {
 	n := make(map[string]uint8)
@@ -1672,84 +1623,48 @@ func (dns *Msg) Unpack(msg []byte) (err error) {
 	dns.CheckingDisabled = (dh.Bits & _CD) != 0
 	dns.Rcode = int(dh.Bits & 0xF)
 
-	// Don't pre-alloc these arrays, the incoming lengths are from the network.
-	dns.Question = make([]Question, 0, 1)
-	dns.Answer = make([]RR, 0, 10)
-	dns.Ns = make([]RR, 0, 10)
-	dns.Extra = make([]RR, 0, 10)
+	// Optimistically use the count given to us in the header
+	dns.Question = make([]Question, 0, int(dh.Qdcount))
 
 	var q Question
 	for i := 0; i < int(dh.Qdcount); i++ {
 		off1 := off
 		off, err = UnpackStruct(&q, 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)
-
-	}
-	// If we see a TC bit being set we return here, without
-	// an error, because technically it isn't an error. So return
-	// without parsing the potentially corrupt packet and hitting an error.
-	// TODO(miek): this isn't the best strategy!
-	// Better stragey would be: set boolean indicating truncated message, go forth and parse
-	// until we hit an error, return the message without the latest parsed rr if this boolean
-	// is true.
-	if dns.Truncated {
-		dns.Answer = nil
-		dns.Ns = nil
-		dns.Extra = nil
-		return nil
 	}
 
-	var r RR
-	for i := 0; i < int(dh.Ancount); i++ {
-		off1 := off
-		r, off, err = UnpackRR(msg, off)
-		if err != nil {
-			return err
-		}
-		if off1 == off { // Offset does not increase anymore, dh.Ancount is a lie!
-			dh.Ancount = uint16(i)
-			break
-		}
-		dns.Answer = append(dns.Answer, r)
+	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)
 	}
-	for i := 0; i < int(dh.Nscount); i++ {
-		off1 := off
-		r, off, err = UnpackRR(msg, off)
-		if err != nil {
-			return err
-		}
-		if off1 == off { // Offset does not increase anymore, dh.Nscount is a lie!
-			dh.Nscount = uint16(i)
-			break
-		}
-		dns.Ns = append(dns.Ns, r)
-	}
-	for i := 0; i < int(dh.Arcount); i++ {
-		off1 := off
-		r, off, err = UnpackRR(msg, off)
-		if err != nil {
-			return err
-		}
-		if off1 == off { // Offset does not increase anymore, dh.Arcount is a lie!
-			dh.Arcount = uint16(i)
-			break
-		}
-		dns.Extra = append(dns.Extra, r)
+	// 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 nil
+	return err
 }
 
 // Convert a complete message to a string with dig-like output.

+ 10 - 10
Godeps/_workspace/src/github.com/miekg/dns/parse_test.go

@@ -145,13 +145,13 @@ func TestTXTEscapeParsing(t *testing.T) {
 	for _, s := range test {
 		rr, err := NewRR(fmt.Sprintf("example.com. IN TXT %v", s[0]))
 		if err != nil {
-			t.Errorf("Could not parse %v TXT: %s", s[0], err)
+			t.Errorf("could not parse %v TXT: %s", s[0], err)
 			continue
 		}
 
 		txt := sprintTxt(rr.(*TXT).Txt)
 		if txt != s[1] {
-			t.Errorf("Mismatch after parsing `%v` TXT record: `%v` != `%v`", s[0], txt, s[1])
+			t.Errorf("mismatch after parsing `%v` TXT record: `%v` != `%v`", s[0], txt, s[1])
 		}
 	}
 }
@@ -569,7 +569,7 @@ test                          IN CNAME test.a.example.com.
 	t.Logf("%d RRs parsed in %.2f s (%.2f RR/s)", i, float32(delta)/1e9, float32(i)/(float32(delta)/1e9))
 }
 
-func ExampleZone() {
+func ExampleParseZone() {
 	zone := `$ORIGIN .
 $TTL 3600       ; 1 hour
 name                    IN SOA  a6.nstld.com. hostmaster.nic.name. (
@@ -768,7 +768,7 @@ func TestRfc1982(t *testing.T) {
 }
 
 func TestEmpty(t *testing.T) {
-	for _ = range ParseZone(strings.NewReader(""), "", "") {
+	for range ParseZone(strings.NewReader(""), "", "") {
 		t.Errorf("should be empty")
 	}
 }
@@ -799,7 +799,7 @@ func TestLowercaseTokens(t *testing.T) {
 	}
 }
 
-func ExampleGenerate() {
+func ExampleParseZone_generate() {
 	// From the manual: http://www.bind9.net/manual/bind/9.3.2/Bv9ARM.ch06.html#id2566761
 	zone := "$GENERATE 1-2 0 NS SERVER$.EXAMPLE.\n$GENERATE 1-8 $ CNAME $.0"
 	to := ParseZone(strings.NewReader(zone), "0.0.192.IN-ADDR.ARPA.", "")
@@ -1208,11 +1208,11 @@ func TestNewPrivateKey(t *testing.T) {
 		t.Skip("skipping test in short mode.")
 	}
 	algorithms := []algorithm{
-		algorithm{ECDSAP256SHA256, 256},
-		algorithm{ECDSAP384SHA384, 384},
-		algorithm{RSASHA1, 1024},
-		algorithm{RSASHA256, 2048},
-		algorithm{DSA, 1024},
+		{ECDSAP256SHA256, 256},
+		{ECDSAP384SHA384, 384},
+		{RSASHA1, 1024},
+		{RSASHA256, 2048},
+		{DSA, 1024},
 	}
 
 	for _, algo := range algorithms {

+ 4 - 4
Godeps/_workspace/src/github.com/miekg/dns/privaterr.go

@@ -33,7 +33,7 @@ type PrivateRR struct {
 
 func mkPrivateRR(rrtype uint16) *PrivateRR {
 	// Panics if RR is not an instance of PrivateRR.
-	rrfunc, ok := typeToRR[rrtype]
+	rrfunc, ok := TypeToRR[rrtype]
 	if !ok {
 		panic(fmt.Sprintf("dns: invalid operation with Private RR type %d", rrtype))
 	}
@@ -43,7 +43,7 @@ func mkPrivateRR(rrtype uint16) *PrivateRR {
 	case *PrivateRR:
 		return rr
 	}
-	panic(fmt.Sprintf("dns: RR is not a PrivateRR, typeToRR[%d] generator returned %T", rrtype, anyrr))
+	panic(fmt.Sprintf("dns: RR is not a PrivateRR, TypeToRR[%d] generator returned %T", rrtype, anyrr))
 }
 
 // Header return the RR header of r.
@@ -71,7 +71,7 @@ func (r *PrivateRR) copy() RR {
 func PrivateHandle(rtypestr string, rtype uint16, generator func() PrivateRdata) {
 	rtypestr = strings.ToUpper(rtypestr)
 
-	typeToRR[rtype] = func() RR { return &PrivateRR{RR_Header{}, generator()} }
+	TypeToRR[rtype] = func() RR { return &PrivateRR{RR_Header{}, generator()} }
 	TypeToString[rtype] = rtypestr
 	StringToType[rtypestr] = rtype
 
@@ -108,7 +108,7 @@ func PrivateHandle(rtypestr string, rtype uint16, generator func() PrivateRdata)
 func PrivateHandleRemove(rtype uint16) {
 	rtypestr, ok := TypeToString[rtype]
 	if ok {
-		delete(typeToRR, rtype)
+		delete(TypeToRR, rtype)
 		delete(TypeToString, rtype)
 		delete(typeToparserFunc, rtype)
 		delete(StringToType, rtypestr)

+ 2 - 2
Godeps/_workspace/src/github.com/miekg/dns/privaterr_test.go

@@ -90,11 +90,11 @@ func TestPrivateByteSlice(t *testing.T) {
 	}
 
 	if off1 != off {
-		t.Errorf("Offset after unpacking differs: %d != %d", off1, off)
+		t.Errorf("offset after unpacking differs: %d != %d", off1, off)
 	}
 
 	if rr1.String() != testrecord {
-		t.Errorf("Record string representation did not match original %#v != %#v", rr1.String(), testrecord)
+		t.Errorf("record string representation did not match original %#v != %#v", rr1.String(), testrecord)
 	} else {
 		t.Log(rr1.String())
 	}

+ 3 - 3
Godeps/_workspace/src/github.com/miekg/dns/rawmsg.go

@@ -21,7 +21,7 @@ func rawSetQuestionLen(msg []byte, i uint16) bool {
 	return true
 }
 
-// rawSetAnswerLen sets the lenght of the answer section.
+// rawSetAnswerLen sets the length of the answer section.
 func rawSetAnswerLen(msg []byte, i uint16) bool {
 	if len(msg) < 8 {
 		return false
@@ -30,7 +30,7 @@ func rawSetAnswerLen(msg []byte, i uint16) bool {
 	return true
 }
 
-// rawSetsNsLen sets the lenght of the authority section.
+// rawSetsNsLen sets the length of the authority section.
 func rawSetNsLen(msg []byte, i uint16) bool {
 	if len(msg) < 10 {
 		return false
@@ -39,7 +39,7 @@ func rawSetNsLen(msg []byte, i uint16) bool {
 	return true
 }
 
-// rawSetExtraLen sets the lenght of the additional section.
+// rawSetExtraLen sets the length of the additional section.
 func rawSetExtraLen(msg []byte, i uint16) bool {
 	if len(msg) < 12 {
 		return false

+ 6 - 6
Godeps/_workspace/src/github.com/miekg/dns/sanitize_test.go

@@ -9,24 +9,24 @@ func TestDedup(t *testing.T) {
 			newRR(t, "mIek.nl. IN A 127.0.0.1"),
 			newRR(t, "mieK.nl. IN A 127.0.0.1"),
 			newRR(t, "miek.Nl. IN A 127.0.0.1"),
-		}: []string{"mIek.nl.\t3600\tIN\tA\t127.0.0.1"},
+		}: {"mIek.nl.\t3600\tIN\tA\t127.0.0.1"},
 		[...]RR{
 			newRR(t, "miEk.nl. 2000 IN A 127.0.0.1"),
 			newRR(t, "mieK.Nl. 1000 IN A 127.0.0.1"),
 			newRR(t, "Miek.nL. 500 IN A 127.0.0.1"),
-		}: []string{"miEk.nl.\t500\tIN\tA\t127.0.0.1"},
+		}: {"miEk.nl.\t500\tIN\tA\t127.0.0.1"},
 		[...]RR{
 			newRR(t, "miek.nl. IN A 127.0.0.1"),
 			newRR(t, "miek.nl. CH A 127.0.0.1"),
 			newRR(t, "miek.nl. IN A 127.0.0.1"),
-		}: []string{"miek.nl.\t3600\tIN\tA\t127.0.0.1",
+		}: {"miek.nl.\t3600\tIN\tA\t127.0.0.1",
 			"miek.nl.\t3600\tCH\tA\t127.0.0.1",
 		},
 		[...]RR{
 			newRR(t, "miek.nl. CH A 127.0.0.1"),
 			newRR(t, "miek.nl. IN A 127.0.0.1"),
 			newRR(t, "miek.de. IN A 127.0.0.1"),
-		}: []string{"miek.nl.\t3600\tCH\tA\t127.0.0.1",
+		}: {"miek.nl.\t3600\tCH\tA\t127.0.0.1",
 			"miek.nl.\t3600\tIN\tA\t127.0.0.1",
 			"miek.de.\t3600\tIN\tA\t127.0.0.1",
 		},
@@ -34,7 +34,7 @@ func TestDedup(t *testing.T) {
 			newRR(t, "miek.de. IN A 127.0.0.1"),
 			newRR(t, "miek.nl. 200 IN A 127.0.0.1"),
 			newRR(t, "miek.nl. 300 IN A 127.0.0.1"),
-		}: []string{"miek.de.\t3600\tIN\tA\t127.0.0.1",
+		}: {"miek.de.\t3600\tIN\tA\t127.0.0.1",
 			"miek.nl.\t200\tIN\tA\t127.0.0.1",
 		},
 	}
@@ -57,7 +57,7 @@ func BenchmarkDedup(b *testing.B) {
 	}
 	m := make(map[string]RR)
 	for i := 0; i < b.N; i++ {
-		Dedup(rrs,m )
+		Dedup(rrs, m)
 	}
 }
 

+ 106 - 75
Godeps/_workspace/src/github.com/miekg/dns/server.go

@@ -4,6 +4,7 @@ package dns
 
 import (
 	"bytes"
+	"crypto/tls"
 	"io"
 	"net"
 	"sync"
@@ -47,7 +48,7 @@ type response struct {
 	tsigRequestMAC string
 	tsigSecret     map[string]string // the tsig secrets
 	udp            *net.UDPConn      // i/o connection if UDP was used
-	tcp            *net.TCPConn      // i/o connection if TCP was used
+	tcp            net.Conn          // i/o connection if TCP was used
 	udpSession     *SessionUDP       // oob data to get egress interface right
 	remoteAddr     net.Addr          // address of the client
 	writer         Writer            // writer to output the raw DNS bits
@@ -92,13 +93,35 @@ func HandleFailed(w ResponseWriter, r *Msg) {
 
 func failedHandler() Handler { return HandlerFunc(HandleFailed) }
 
-// ListenAndServe Starts a server on addresss and network speficied. Invoke handler
+// 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.
@@ -210,7 +233,7 @@ type Writer interface {
 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.TCPConn, timeout time.Duration) ([]byte, error)
+	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)
@@ -222,7 +245,7 @@ type defaultReader struct {
 	*Server
 }
 
-func (dr *defaultReader) ReadTCP(conn *net.TCPConn, timeout time.Duration) ([]byte, error) {
+func (dr *defaultReader) ReadTCP(conn net.Conn, timeout time.Duration) ([]byte, error) {
 	return dr.readTCP(conn, timeout)
 }
 
@@ -242,10 +265,12 @@ type DecorateWriter func(Writer) Writer
 type Server struct {
 	// Address to listen on, ":dns" if empty.
 	Addr string
-	// if "tcp" it will invoke a TCP listener, otherwise an UDP one.
+	// 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.
@@ -262,7 +287,7 @@ type Server struct {
 	// 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 specfically not check if the query has the QR bit not set.
+	// 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()
@@ -271,26 +296,21 @@ type Server struct {
 	// DecorateWriter is optional, allows customization of the process that writes raw DNS messages.
 	DecorateWriter DecorateWriter
 
-	// For graceful shutdown.
-	stopUDP chan bool
-	stopTCP chan bool
-	wgUDP   sync.WaitGroup
-	wgTCP   sync.WaitGroup
+	// Graceful shutdown handling
+
+	inFlight sync.WaitGroup
 
-	// make start/shutdown not racy
-	lock    sync.Mutex
+	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 {
-		srv.lock.Unlock()
 		return &Error{err: "server already started"}
 	}
-	srv.stopUDP, srv.stopTCP = make(chan bool), make(chan bool)
-	srv.started = true
 	addr := srv.Addr
 	if addr == "" {
 		addr = ":domain"
@@ -309,8 +329,29 @@ func (srv *Server) ListenAndServe() error {
 			return e
 		}
 		srv.Listener = l
+		srv.started = true
 		srv.lock.Unlock()
-		return srv.serveTCP(l)
+		e = srv.serveTCP(l)
+		srv.lock.Lock() // to satisfy the defer at the top
+		return e
+	case "tcp-tls", "tcp4-tls", "tcp6-tls":
+		network := "tcp"
+		if srv.Net == "tcp4-tls" {
+			network = "tcp4"
+		} else if srv.Net == "tcp6" {
+			network = "tcp6"
+		}
+
+		l, e := tls.Listen(network, addr, srv.TLSConfig)
+		if e != nil {
+			return e
+		}
+		srv.Listener = l
+		srv.started = true
+		srv.lock.Unlock()
+		e = srv.serveTCP(l)
+		srv.lock.Lock() // to satisfy the defer at the top
+		return e
 	case "udp", "udp4", "udp6":
 		a, e := net.ResolveUDPAddr(srv.Net, addr)
 		if e != nil {
@@ -324,10 +365,12 @@ func (srv *Server) ListenAndServe() error {
 			return e
 		}
 		srv.PacketConn = l
+		srv.started = true
 		srv.lock.Unlock()
-		return srv.serveUDP(l)
+		e = srv.serveUDP(l)
+		srv.lock.Lock() // to satisfy the defer at the top
+		return e
 	}
-	srv.lock.Unlock()
 	return &Error{err: "bad network"}
 }
 
@@ -335,15 +378,12 @@ func (srv *Server) ListenAndServe() error {
 // 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 {
-		srv.lock.Unlock()
 		return &Error{err: "server already started"}
 	}
-	srv.stopUDP, srv.stopTCP = make(chan bool), make(chan bool)
-	srv.started = true
 	pConn := srv.PacketConn
 	l := srv.Listener
-	srv.lock.Unlock()
 	if pConn != nil {
 		if srv.UDPSize == 0 {
 			srv.UDPSize = MinMsgSize
@@ -352,13 +392,19 @@ func (srv *Server) ActivateAndServe() error {
 			if e := setUDPSocketOptions(t); e != nil {
 				return e
 			}
-			return srv.serveUDP(t)
+			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 {
-		if t, ok := l.(*net.TCPListener); ok {
-			return srv.serveTCP(t)
-		}
+		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"}
 }
@@ -374,36 +420,20 @@ func (srv *Server) Shutdown() error {
 		return &Error{err: "server not started"}
 	}
 	srv.started = false
-	net, addr := srv.Net, srv.Addr
-	switch {
-	case srv.Listener != nil:
-		a := srv.Listener.Addr()
-		net, addr = a.Network(), a.String()
-	case srv.PacketConn != nil:
-		a := srv.PacketConn.LocalAddr()
-		net, addr = a.Network(), a.String()
-	}
 	srv.lock.Unlock()
 
-	fin := make(chan bool)
-	switch net {
-	case "tcp", "tcp4", "tcp6":
-		go func() {
-			srv.stopTCP <- true
-			srv.wgTCP.Wait()
-			fin <- true
-		}()
-
-	case "udp", "udp4", "udp6":
-		go func() {
-			srv.stopUDP <- true
-			srv.wgUDP.Wait()
-			fin <- true
-		}()
+	if srv.PacketConn != nil {
+		srv.PacketConn.Close()
+	}
+	if srv.Listener != nil {
+		srv.Listener.Close()
 	}
 
-	c := &Client{Net: net}
-	go c.Exchange(new(Msg), addr) // extra query to help ReadXXX loop to pass
+	fin := make(chan bool)
+	go func() {
+		srv.inFlight.Wait()
+		fin <- true
+	}()
 
 	select {
 	case <-time.After(srv.getReadTimeout()):
@@ -424,7 +454,7 @@ func (srv *Server) getReadTimeout() time.Duration {
 
 // serveTCP starts a TCP listener for the server.
 // Each request is handled in a separate goroutine.
-func (srv *Server) serveTCP(l *net.TCPListener) error {
+func (srv *Server) serveTCP(l net.Listener) error {
 	defer l.Close()
 
 	if srv.NotifyStartedFunc != nil {
@@ -443,20 +473,24 @@ func (srv *Server) serveTCP(l *net.TCPListener) error {
 	rtimeout := srv.getReadTimeout()
 	// deadline is not used here
 	for {
-		rw, e := l.AcceptTCP()
+		rw, e := l.Accept()
 		if e != nil {
-			continue
+			if neterr, ok := e.(net.Error); ok && neterr.Temporary() {
+				continue
+			}
+			return e
 		}
 		m, e := reader.ReadTCP(rw, rtimeout)
-		select {
-		case <-srv.stopTCP:
+		srv.lock.RLock()
+		if !srv.started {
+			srv.lock.RUnlock()
 			return nil
-		default:
 		}
+		srv.lock.RUnlock()
 		if e != nil {
 			continue
 		}
-		srv.wgTCP.Add(1)
+		srv.inFlight.Add(1)
 		go srv.serve(rw.RemoteAddr(), handler, m, nil, nil, rw)
 	}
 }
@@ -483,21 +517,24 @@ func (srv *Server) serveUDP(l *net.UDPConn) error {
 	// deadline is not used here
 	for {
 		m, s, e := reader.ReadUDP(l, rtimeout)
-		select {
-		case <-srv.stopUDP:
+		srv.lock.RLock()
+		if !srv.started {
+			srv.lock.RUnlock()
 			return nil
-		default:
 		}
+		srv.lock.RUnlock()
 		if e != nil {
 			continue
 		}
-		srv.wgUDP.Add(1)
+		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.TCPConn) {
+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)
@@ -507,15 +544,6 @@ func (srv *Server) serve(a net.Addr, h Handler, m []byte, u *net.UDPConn, s *Ses
 
 	q := 0 // counter for the amount of TCP queries we get
 
-	defer func() {
-		if u != nil {
-			srv.wgUDP.Done()
-		}
-		if t != nil {
-			srv.wgTCP.Done()
-		}
-	}()
-
 	reader := Reader(&defaultReader{srv})
 	if srv.DecorateReader != nil {
 		reader = srv.DecorateReader(reader)
@@ -548,6 +576,9 @@ Redo:
 	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()
@@ -574,7 +605,7 @@ Exit:
 	return
 }
 
-func (srv *Server) readTCP(conn *net.TCPConn, timeout time.Duration) ([]byte, error) {
+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)

+ 249 - 20
Godeps/_workspace/src/github.com/miekg/dns/server_test.go

@@ -1,11 +1,14 @@
 package dns
 
 import (
+	"crypto/tls"
 	"fmt"
+	"io"
 	"net"
 	"runtime"
 	"sync"
 	"testing"
+	"time"
 )
 
 func HelloServer(w ResponseWriter, req *Msg) {
@@ -37,23 +40,32 @@ func AnotherHelloServer(w ResponseWriter, req *Msg) {
 }
 
 func RunLocalUDPServer(laddr string) (*Server, string, error) {
+	server, l, _, err := RunLocalUDPServerWithFinChan(laddr)
+
+	return server, l, err
+}
+
+func RunLocalUDPServerWithFinChan(laddr string) (*Server, string, chan struct{}, error) {
 	pc, err := net.ListenPacket("udp", laddr)
 	if err != nil {
-		return nil, "", err
+		return nil, "", nil, err
 	}
-	server := &Server{PacketConn: pc}
+	server := &Server{PacketConn: pc, ReadTimeout: time.Hour, WriteTimeout: time.Hour}
 
 	waitLock := sync.Mutex{}
 	waitLock.Lock()
 	server.NotifyStartedFunc = waitLock.Unlock
 
+	fin := make(chan struct{}, 0)
+
 	go func() {
 		server.ActivateAndServe()
+		close(fin)
 		pc.Close()
 	}()
 
 	waitLock.Lock()
-	return server, pc.LocalAddr().String(), nil
+	return server, pc.LocalAddr().String(), fin, nil
 }
 
 func RunLocalUDPServerUnsafe(laddr string) (*Server, string, error) {
@@ -61,7 +73,8 @@ func RunLocalUDPServerUnsafe(laddr string) (*Server, string, error) {
 	if err != nil {
 		return nil, "", err
 	}
-	server := &Server{PacketConn: pc, Unsafe: true}
+	server := &Server{PacketConn: pc, Unsafe: true,
+		ReadTimeout: time.Hour, WriteTimeout: time.Hour}
 
 	waitLock := sync.Mutex{}
 	waitLock.Lock()
@@ -82,7 +95,28 @@ func RunLocalTCPServer(laddr string) (*Server, string, error) {
 		return nil, "", err
 	}
 
-	server := &Server{Listener: l}
+	server := &Server{Listener: l, ReadTimeout: time.Hour, WriteTimeout: time.Hour}
+
+	waitLock := sync.Mutex{}
+	waitLock.Lock()
+	server.NotifyStartedFunc = waitLock.Unlock
+
+	go func() {
+		server.ActivateAndServe()
+		l.Close()
+	}()
+
+	waitLock.Lock()
+	return server, l.Addr().String(), nil
+}
+
+func RunLocalTLSServer(laddr string, config *tls.Config) (*Server, string, error) {
+	l, err := tls.Listen("tcp", laddr, config)
+	if err != nil {
+		return nil, "", err
+	}
+
+	server := &Server{Listener: l, ReadTimeout: time.Hour, WriteTimeout: time.Hour}
 
 	waitLock := sync.Mutex{}
 	waitLock.Lock()
@@ -105,7 +139,7 @@ func TestServing(t *testing.T) {
 
 	s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
 	if err != nil {
-		t.Fatalf("Unable to run test server: %v", err)
+		t.Fatalf("unable to run test server: %v", err)
 	}
 	defer s.Shutdown()
 
@@ -118,7 +152,7 @@ func TestServing(t *testing.T) {
 	}
 	txt := r.Extra[0].(*TXT).Txt[0]
 	if txt != "Hello world" {
-		t.Error("Unexpected result for miek.nl", txt, "!= Hello world")
+		t.Error("unexpected result for miek.nl", txt, "!= Hello world")
 	}
 
 	m.SetQuestion("example.com.", TypeTXT)
@@ -128,7 +162,7 @@ func TestServing(t *testing.T) {
 	}
 	txt = r.Extra[0].(*TXT).Txt[0]
 	if txt != "Hello example" {
-		t.Error("Unexpected result for example.com", txt, "!= Hello example")
+		t.Error("unexpected result for example.com", txt, "!= Hello example")
 	}
 
 	// Test Mixes cased as noticed by Ask.
@@ -139,7 +173,67 @@ func TestServing(t *testing.T) {
 	}
 	txt = r.Extra[0].(*TXT).Txt[0]
 	if txt != "Hello example" {
-		t.Error("Unexpected result for example.com", txt, "!= Hello example")
+		t.Error("unexpected result for example.com", txt, "!= Hello example")
+	}
+}
+
+func TestServingTLS(t *testing.T) {
+	HandleFunc("miek.nl.", HelloServer)
+	HandleFunc("example.com.", AnotherHelloServer)
+	defer HandleRemove("miek.nl.")
+	defer HandleRemove("example.com.")
+
+	cert, err := tls.X509KeyPair(CertPEMBlock, KeyPEMBlock)
+	if err != nil {
+		t.Fatalf("unable to build certificate: %v", err)
+	}
+
+	config := tls.Config{
+		Certificates: []tls.Certificate{cert},
+	}
+
+	s, addrstr, err := RunLocalTLSServer("127.0.0.1:0", &config)
+	if err != nil {
+		t.Fatalf("unable to run test server: %v", err)
+	}
+	defer s.Shutdown()
+
+	c := new(Client)
+	c.Net = "tcp-tls"
+	c.TLSConfig = &tls.Config{
+		InsecureSkipVerify: true,
+	}
+
+	m := new(Msg)
+	m.SetQuestion("miek.nl.", TypeTXT)
+	r, _, err := c.Exchange(m, addrstr)
+	if err != nil || len(r.Extra) == 0 {
+		t.Fatal("failed to exchange miek.nl", err)
+	}
+	txt := r.Extra[0].(*TXT).Txt[0]
+	if txt != "Hello world" {
+		t.Error("unexpected result for miek.nl", txt, "!= Hello world")
+	}
+
+	m.SetQuestion("example.com.", TypeTXT)
+	r, _, err = c.Exchange(m, addrstr)
+	if err != nil {
+		t.Fatal("failed to exchange example.com", err)
+	}
+	txt = r.Extra[0].(*TXT).Txt[0]
+	if txt != "Hello example" {
+		t.Error("unexpected result for example.com", txt, "!= Hello example")
+	}
+
+	// Test Mixes cased as noticed by Ask.
+	m.SetQuestion("eXaMplE.cOm.", TypeTXT)
+	r, _, err = c.Exchange(m, addrstr)
+	if err != nil {
+		t.Error("failed to exchange eXaMplE.cOm", err)
+	}
+	txt = r.Extra[0].(*TXT).Txt[0]
+	if txt != "Hello example" {
+		t.Error("unexpected result for example.com", txt, "!= Hello example")
 	}
 }
 
@@ -151,7 +245,7 @@ func BenchmarkServe(b *testing.B) {
 
 	s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
 	if err != nil {
-		b.Fatalf("Unable to run test server: %v", err)
+		b.Fatalf("unable to run test server: %v", err)
 	}
 	defer s.Shutdown()
 
@@ -173,7 +267,7 @@ func benchmarkServe6(b *testing.B) {
 	a := runtime.GOMAXPROCS(4)
 	s, addrstr, err := RunLocalUDPServer("[::1]:0")
 	if err != nil {
-		b.Fatalf("Unable to run test server: %v", err)
+		b.Fatalf("unable to run test server: %v", err)
 	}
 	defer s.Shutdown()
 
@@ -204,7 +298,7 @@ func BenchmarkServeCompress(b *testing.B) {
 	a := runtime.GOMAXPROCS(4)
 	s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
 	if err != nil {
-		b.Fatalf("Unable to run test server: %v", err)
+		b.Fatalf("unable to run test server: %v", err)
 	}
 	defer s.Shutdown()
 
@@ -305,7 +399,7 @@ func TestServingLargeResponses(t *testing.T) {
 
 	s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
 	if err != nil {
-		t.Fatalf("Unable to run test server: %v", err)
+		t.Fatalf("unable to run test server: %v", err)
 	}
 	defer s.Shutdown()
 
@@ -345,7 +439,7 @@ func TestServingResponse(t *testing.T) {
 	HandleFunc("miek.nl.", HelloServer)
 	s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
 	if err != nil {
-		t.Fatalf("Unable to run test server: %v", err)
+		t.Fatalf("unable to run test server: %v", err)
 	}
 
 	c := new(Client)
@@ -365,7 +459,7 @@ func TestServingResponse(t *testing.T) {
 	s.Shutdown()
 	s, addrstr, err = RunLocalUDPServerUnsafe("127.0.0.1:0")
 	if err != nil {
-		t.Fatalf("Unable to run test server: %v", err)
+		t.Fatalf("unable to run test server: %v", err)
 	}
 	defer s.Shutdown()
 
@@ -379,22 +473,104 @@ func TestServingResponse(t *testing.T) {
 func TestShutdownTCP(t *testing.T) {
 	s, _, err := RunLocalTCPServer("127.0.0.1:0")
 	if err != nil {
-		t.Fatalf("Unable to run test server: %v", err)
+		t.Fatalf("unable to run test server: %v", err)
+	}
+	err = s.Shutdown()
+	if err != nil {
+		t.Errorf("could not shutdown test TCP server, %v", err)
+	}
+}
+
+func TestShutdownTLS(t *testing.T) {
+	cert, err := tls.X509KeyPair(CertPEMBlock, KeyPEMBlock)
+	if err != nil {
+		t.Fatalf("unable to build certificate: %v", err)
+	}
+
+	config := tls.Config{
+		Certificates: []tls.Certificate{cert},
+	}
+
+	s, _, err := RunLocalTLSServer("127.0.0.1:0", &config)
+	if err != nil {
+		t.Fatalf("unable to run test server: %v", err)
 	}
 	err = s.Shutdown()
 	if err != nil {
-		t.Errorf("Could not shutdown test TCP server, %v", err)
+		t.Errorf("could not shutdown test TLS server, %v", err)
+	}
+}
+
+type trigger struct {
+	done bool
+	sync.RWMutex
+}
+
+func (t *trigger) Set() {
+	t.Lock()
+	defer t.Unlock()
+	t.done = true
+}
+func (t *trigger) Get() bool {
+	t.RLock()
+	defer t.RUnlock()
+	return t.done
+}
+
+func TestHandlerCloseTCP(t *testing.T) {
+
+	ln, err := net.Listen("tcp", "127.0.0.1:0")
+	if err != nil {
+		panic(err)
+	}
+	addr := ln.Addr().String()
+
+	server := &Server{Addr: addr, Net: "tcp", Listener: ln}
+
+	hname := "testhandlerclosetcp."
+	triggered := &trigger{}
+	HandleFunc(hname, func(w ResponseWriter, r *Msg) {
+		triggered.Set()
+		w.Close()
+	})
+	defer HandleRemove(hname)
+
+	go func() {
+		defer server.Shutdown()
+		c := &Client{Net: "tcp"}
+		m := new(Msg).SetQuestion(hname, 1)
+		tries := 0
+	exchange:
+		_, _, err := c.Exchange(m, addr)
+		if err != nil && err != io.EOF {
+			t.Logf("exchange failed: %s\n", err)
+			if tries == 3 {
+				return
+			}
+			time.Sleep(time.Second / 10)
+			tries += 1
+			goto exchange
+		}
+	}()
+	server.ActivateAndServe()
+	if !triggered.Get() {
+		t.Fatalf("handler never called")
 	}
 }
 
 func TestShutdownUDP(t *testing.T) {
-	s, _, err := RunLocalUDPServer("127.0.0.1:0")
+	s, _, fin, err := RunLocalUDPServerWithFinChan("127.0.0.1:0")
 	if err != nil {
-		t.Fatalf("Unable to run test server: %v", err)
+		t.Fatalf("unable to run test server: %v", err)
 	}
 	err = s.Shutdown()
 	if err != nil {
-		t.Errorf("Could not shutdown test UDP server, %v", err)
+		t.Errorf("could not shutdown test UDP server, %v", err)
+	}
+	select {
+	case <-fin:
+	case <-time.After(2 * time.Second):
+		t.Error("Could not shutdown test UDP server. Gave up waiting")
 	}
 }
 
@@ -422,6 +598,7 @@ func ExampleDecorateWriter() {
 	server := &Server{
 		PacketConn:     pc,
 		DecorateWriter: wf,
+		ReadTimeout:    time.Hour, WriteTimeout: time.Hour,
 	}
 
 	waitLock := sync.Mutex{}
@@ -448,3 +625,55 @@ func ExampleDecorateWriter() {
 	}
 	// Output: writing raw DNS message of length 56
 }
+
+var (
+	// CertPEMBlock is a X509 data used to test TLS servers (used with tls.X509KeyPair)
+	CertPEMBlock = []byte(`-----BEGIN CERTIFICATE-----
+MIIDAzCCAeugAwIBAgIRAJFYMkcn+b8dpU15wjf++GgwDQYJKoZIhvcNAQELBQAw
+EjEQMA4GA1UEChMHQWNtZSBDbzAeFw0xNjAxMDgxMjAzNTNaFw0xNzAxMDcxMjAz
+NTNaMBIxEDAOBgNVBAoTB0FjbWUgQ28wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
+ggEKAoIBAQDXjqO6skvP03k58CNjQggd9G/mt+Wa+xRU+WXiKCCHttawM8x+slq5
+yfsHCwxlwsGn79HmJqecNqgHb2GWBXAvVVokFDTcC1hUP4+gp2gu9Ny27UHTjlLm
+O0l/xZ5MN8tfKyYlFw18tXu3fkaPyHj8v/D1RDkuo4ARdFvGSe8TqisbhLk2+9ow
+xfIGbEM9Fdiw8qByC2+d+FfvzIKz3GfQVwn0VoRom8L6NBIANq1IGrB5JefZB6nv
+DnfuxkBmY7F1513HKuEJ8KsLWWZWV9OPU4j4I4Rt+WJNlKjbD2srHxyrS2RDsr91
+8nCkNoWVNO3sZq0XkWKecdc921vL4ginAgMBAAGjVDBSMA4GA1UdDwEB/wQEAwIC
+pDATBgNVHSUEDDAKBggrBgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MBoGA1UdEQQT
+MBGCCWxvY2FsaG9zdIcEfwAAATANBgkqhkiG9w0BAQsFAAOCAQEAGcU3iyLBIVZj
+aDzSvEDHUd1bnLBl1C58Xu/CyKlPqVU7mLfK0JcgEaYQTSX6fCJVNLbbCrcGLsPJ
+fbjlBbyeLjTV413fxPVuona62pBFjqdtbli2Qe8FRH2KBdm41JUJGdo+SdsFu7nc
+BFOcubdw6LLIXvsTvwndKcHWx1rMX709QU1Vn1GAIsbJV/DWI231Jyyb+lxAUx/C
+8vce5uVxiKcGS+g6OjsN3D3TtiEQGSXLh013W6Wsih8td8yMCMZ3w8LQ38br1GUe
+ahLIgUJ9l6HDguM17R7kGqxNvbElsMUHfTtXXP7UDQUiYXDakg8xDP6n9DCDhJ8Y
+bSt7OLB7NQ==
+-----END CERTIFICATE-----`)
+
+	// KeyPEMBlock is a X509 data used to test TLS servers (used with tls.X509KeyPair)
+	KeyPEMBlock = []byte(`-----BEGIN RSA PRIVATE KEY-----
+MIIEpQIBAAKCAQEA146jurJLz9N5OfAjY0IIHfRv5rflmvsUVPll4iggh7bWsDPM
+frJaucn7BwsMZcLBp+/R5iannDaoB29hlgVwL1VaJBQ03AtYVD+PoKdoLvTctu1B
+045S5jtJf8WeTDfLXysmJRcNfLV7t35Gj8h4/L/w9UQ5LqOAEXRbxknvE6orG4S5
+NvvaMMXyBmxDPRXYsPKgcgtvnfhX78yCs9xn0FcJ9FaEaJvC+jQSADatSBqweSXn
+2Qep7w537sZAZmOxdeddxyrhCfCrC1lmVlfTj1OI+COEbfliTZSo2w9rKx8cq0tk
+Q7K/dfJwpDaFlTTt7GatF5FinnHXPdtby+IIpwIDAQABAoIBAAJK4RDmPooqTJrC
+JA41MJLo+5uvjwCT9QZmVKAQHzByUFw1YNJkITTiognUI0CdzqNzmH7jIFs39ZeG
+proKusO2G6xQjrNcZ4cV2fgyb5g4QHStl0qhs94A+WojduiGm2IaumAgm6Mc5wDv
+ld6HmknN3Mku/ZCyanVFEIjOVn2WB7ZQLTBs6ZYaebTJG2Xv6p9t2YJW7pPQ9Xce
+s9ohAWohyM4X/OvfnfnLtQp2YLw/BxwehBsCR5SXM3ibTKpFNtxJC8hIfTuWtxZu
+2ywrmXShYBRB1WgtZt5k04bY/HFncvvcHK3YfI1+w4URKtwdaQgPUQRbVwDwuyBn
+flfkCJECgYEA/eWt01iEyE/lXkGn6V9lCocUU7lCU6yk5UT8VXVUc5If4KZKPfCk
+p4zJDOqwn2eM673aWz/mG9mtvAvmnugaGjcaVCyXOp/D/GDmKSoYcvW5B/yjfkLy
+dK6Yaa5LDRVYlYgyzcdCT5/9Qc626NzFwKCZNI4ncIU8g7ViATRxWJ8CgYEA2Ver
+vZ0M606sfgC0H3NtwNBxmuJ+lIF5LNp/wDi07lDfxRR1rnZMX5dnxjcpDr/zvm8J
+WtJJX3xMgqjtHuWKL3yKKony9J5ZPjichSbSbhrzfovgYIRZLxLLDy4MP9L3+CX/
+yBXnqMWuSnFX+M5fVGxdDWiYF3V+wmeOv9JvavkCgYEAiXAPDFzaY+R78O3xiu7M
+r0o3wqqCMPE/wav6O/hrYrQy9VSO08C0IM6g9pEEUwWmzuXSkZqhYWoQFb8Lc/GI
+T7CMXAxXQLDDUpbRgG79FR3Wr3AewHZU8LyiXHKwxcBMV4WGmsXGK3wbh8fyU1NO
+6NsGk+BvkQVOoK1LBAPzZ1kCgYEAsBSmD8U33T9s4dxiEYTrqyV0lH3g/SFz8ZHH
+pAyNEPI2iC1ONhyjPWKlcWHpAokiyOqeUpVBWnmSZtzC1qAydsxYB6ShT+sl9BHb
+RMix/QAauzBJhQhUVJ3OIys0Q1UBDmqCsjCE8SfOT4NKOUnA093C+YT+iyrmmktZ
+zDCJkckCgYEAndqM5KXGk5xYo+MAA1paZcbTUXwaWwjLU+XSRSSoyBEi5xMtfvUb
+7+a1OMhLwWbuz+pl64wFKrbSUyimMOYQpjVE/1vk/kb99pxbgol27hdKyTH1d+ov
+kFsxKCqxAnBVGEWAvVZAiiTOxleQFjz5RnL0BQp9Lg2cQe+dvuUmIAA=
+-----END RSA PRIVATE KEY-----`)
+)

+ 8 - 8
Godeps/_workspace/src/github.com/miekg/dns/sig0_test.go

@@ -28,7 +28,7 @@ func TestSIG0(t *testing.T) {
 		}
 		pk, err := keyrr.Generate(keysize)
 		if err != nil {
-			t.Errorf("Failed to generate key for “%s”: %v", algstr, err)
+			t.Errorf("failed to generate key for “%s”: %v", algstr, err)
 			continue
 		}
 		now := uint32(time.Now().Unix())
@@ -43,16 +43,16 @@ func TestSIG0(t *testing.T) {
 		sigrr.SignerName = keyrr.Hdr.Name
 		mb, err := sigrr.Sign(pk.(crypto.Signer), m)
 		if err != nil {
-			t.Errorf("Failed to sign message using “%s”: %v", algstr, err)
+			t.Errorf("failed to sign message using “%s”: %v", algstr, err)
 			continue
 		}
 		m := new(Msg)
 		if err := m.Unpack(mb); err != nil {
-			t.Errorf("Failed to unpack message signed using “%s”: %v", algstr, err)
+			t.Errorf("failed to unpack message signed using “%s”: %v", algstr, err)
 			continue
 		}
 		if len(m.Extra) != 1 {
-			t.Errorf("Missing SIG for message signed using “%s”", algstr)
+			t.Errorf("missing SIG for message signed using “%s”", algstr)
 			continue
 		}
 		var sigrrwire *SIG
@@ -60,7 +60,7 @@ func TestSIG0(t *testing.T) {
 		case *SIG:
 			sigrrwire = rr
 		default:
-			t.Errorf("Expected SIG RR, instead: %v", rr)
+			t.Errorf("expected SIG RR, instead: %v", rr)
 			continue
 		}
 		for _, rr := range []*SIG{sigrr, sigrrwire} {
@@ -69,20 +69,20 @@ func TestSIG0(t *testing.T) {
 				id = "sigrrwire"
 			}
 			if err := rr.Verify(keyrr, mb); err != nil {
-				t.Errorf("Failed to verify “%s” signed SIG(%s): %v", algstr, id, err)
+				t.Errorf("failed to verify “%s” signed SIG(%s): %v", algstr, id, err)
 				continue
 			}
 		}
 		mb[13]++
 		if err := sigrr.Verify(keyrr, mb); err == nil {
-			t.Errorf("Verify succeeded on an altered message using “%s”", algstr)
+			t.Errorf("verify succeeded on an altered message using “%s”", algstr)
 			continue
 		}
 		sigrr.Expiration = 2
 		sigrr.Inception = 1
 		mb, _ = sigrr.Sign(pk.(crypto.Signer), m)
 		if err := sigrr.Verify(keyrr, mb); err == nil {
-			t.Errorf("Verify succeeded on an expired message using “%s”", algstr)
+			t.Errorf("verify succeeded on an expired message using “%s”", algstr)
 			continue
 		}
 	}

+ 1 - 1
Godeps/_workspace/src/github.com/miekg/dns/tlsa.go

@@ -82,5 +82,5 @@ func TLSAName(name, service, network string) (string, error) {
 	if e != nil {
 		return "", e
 	}
-	return "_" + strconv.Itoa(p) + "_" + network + "." + name, nil
+	return "_" + strconv.Itoa(p) + "._" + network + "." + name, nil
 }

+ 2 - 15
Godeps/_workspace/src/github.com/miekg/dns/tsig.go

@@ -37,10 +37,6 @@ type TSIG struct {
 	OtherData  string `dns:"size-hex"`
 }
 
-func (rr *TSIG) Header() *RR_Header {
-	return &rr.Hdr
-}
-
 // TSIG has no official presentation format, but this will suffice.
 
 func (rr *TSIG) String() string {
@@ -58,15 +54,6 @@ func (rr *TSIG) String() string {
 	return s
 }
 
-func (rr *TSIG) len() int {
-	return rr.Hdr.len() + len(rr.Algorithm) + 1 + 6 +
-		4 + len(rr.MAC)/2 + 1 + 6 + len(rr.OtherData)/2 + 1
-}
-
-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}
-}
-
 // 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 {
@@ -125,7 +112,7 @@ func TsigGenerate(m *Msg, secret, requestMAC string, timersOnly bool) ([]byte, s
 
 	t := new(TSIG)
 	var h hash.Hash
-	switch rr.Algorithm {
+	switch strings.ToLower(rr.Algorithm) {
 	case HmacMD5:
 		h = hmac.New(md5.New, []byte(rawsecret))
 	case HmacSHA1:
@@ -191,7 +178,7 @@ func TsigVerify(msg []byte, secret, requestMAC string, timersOnly bool) error {
 	}
 
 	var h hash.Hash
-	switch tsig.Algorithm {
+	switch strings.ToLower(tsig.Algorithm) {
 	case HmacMD5:
 		h = hmac.New(md5.New, rawsecret)
 	case HmacSHA1:

+ 37 - 0
Godeps/_workspace/src/github.com/miekg/dns/tsig_test.go

@@ -0,0 +1,37 @@
+package dns
+
+import (
+	"testing"
+	"time"
+)
+
+func newTsig(algo string) *Msg {
+	m := new(Msg)
+	m.SetQuestion("example.org.", TypeA)
+	m.SetTsig("example.", algo, 300, time.Now().Unix())
+	return m
+}
+
+func TestTsig(t *testing.T) {
+	m := newTsig(HmacMD5)
+	buf, _, err := TsigGenerate(m, "pRZgBrBvI4NAHZYhxmhs/Q==", "", false)
+	if err != nil {
+		t.Fatal(err)
+	}
+	err = TsigVerify(buf, "pRZgBrBvI4NAHZYhxmhs/Q==", "", false)
+	if err != nil {
+		t.Fatal(err)
+	}
+}
+
+func TestTsigCase(t *testing.T) {
+	m := newTsig("HmAc-mD5.sig-ALg.rEg.int.") // HmacMD5
+	buf, _, err := TsigGenerate(m, "pRZgBrBvI4NAHZYhxmhs/Q==", "", false)
+	if err != nil {
+		t.Fatal(err)
+	}
+	err = TsigVerify(buf, "pRZgBrBvI4NAHZYhxmhs/Q==", "", false)
+	if err != nil {
+		t.Fatal(err)
+	}
+}

+ 23 - 436
Godeps/_workspace/src/github.com/miekg/dns/types.go

@@ -206,6 +206,8 @@ var CertTypeToString = map[uint16]string{
 // 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 {
@@ -214,6 +216,10 @@ type Question struct {
 	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"
@@ -222,11 +228,6 @@ func (q *Question) String() (s string) {
 	return s
 }
 
-func (q *Question) len() int {
-	l := len(q.Name) + 1
-	return l + 4
-}
-
 // ANY is a wildcard record. See RFC 1035, Section 3.2.3. ANY
 // is named "*" there.
 type ANY struct {
@@ -234,20 +235,14 @@ type ANY struct {
 	// Does not have any rdata
 }
 
-func (rr *ANY) Header() *RR_Header { return &rr.Hdr }
-func (rr *ANY) copy() RR           { return &ANY{*rr.Hdr.copyHeader()} }
-func (rr *ANY) String() string     { return rr.Hdr.String() }
-func (rr *ANY) len() int           { return rr.Hdr.len() }
+func (rr *ANY) String() string { return rr.Hdr.String() }
 
 type CNAME struct {
 	Hdr    RR_Header
 	Target string `dns:"cdomain-name"`
 }
 
-func (rr *CNAME) Header() *RR_Header { return &rr.Hdr }
-func (rr *CNAME) copy() RR           { return &CNAME{*rr.Hdr.copyHeader(), sprintName(rr.Target)} }
-func (rr *CNAME) String() string     { return rr.Hdr.String() + rr.Target }
-func (rr *CNAME) len() int           { return rr.Hdr.len() + len(rr.Target) + 1 }
+func (rr *CNAME) String() string { return rr.Hdr.String() + sprintName(rr.Target) }
 
 type HINFO struct {
 	Hdr RR_Header
@@ -255,33 +250,23 @@ type HINFO struct {
 	Os  string
 }
 
-func (rr *HINFO) Header() *RR_Header { return &rr.Hdr }
-func (rr *HINFO) copy() RR           { return &HINFO{*rr.Hdr.copyHeader(), rr.Cpu, rr.Os} }
 func (rr *HINFO) String() string {
 	return rr.Hdr.String() + sprintTxt([]string{rr.Cpu, rr.Os})
 }
-func (rr *HINFO) len() int { return rr.Hdr.len() + len(rr.Cpu) + len(rr.Os) }
 
 type MB struct {
 	Hdr RR_Header
 	Mb  string `dns:"cdomain-name"`
 }
 
-func (rr *MB) Header() *RR_Header { return &rr.Hdr }
-func (rr *MB) copy() RR           { return &MB{*rr.Hdr.copyHeader(), sprintName(rr.Mb)} }
-
-func (rr *MB) String() string { return rr.Hdr.String() + rr.Mb }
-func (rr *MB) len() int       { return rr.Hdr.len() + len(rr.Mb) + 1 }
+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) Header() *RR_Header { return &rr.Hdr }
-func (rr *MG) copy() RR           { return &MG{*rr.Hdr.copyHeader(), rr.Mg} }
-func (rr *MG) len() int           { l := len(rr.Mg) + 1; return rr.Hdr.len() + l }
-func (rr *MG) String() string     { return rr.Hdr.String() + sprintName(rr.Mg) }
+func (rr *MG) String() string { return rr.Hdr.String() + sprintName(rr.Mg) }
 
 type MINFO struct {
 	Hdr   RR_Header
@@ -289,28 +274,15 @@ type MINFO struct {
 	Email string `dns:"cdomain-name"`
 }
 
-func (rr *MINFO) Header() *RR_Header { return &rr.Hdr }
-func (rr *MINFO) copy() RR           { return &MINFO{*rr.Hdr.copyHeader(), rr.Rmail, rr.Email} }
-
 func (rr *MINFO) String() string {
 	return rr.Hdr.String() + sprintName(rr.Rmail) + " " + sprintName(rr.Email)
 }
 
-func (rr *MINFO) len() int {
-	l := len(rr.Rmail) + 1
-	n := len(rr.Email) + 1
-	return rr.Hdr.len() + l + n
-}
-
 type MR struct {
 	Hdr RR_Header
 	Mr  string `dns:"cdomain-name"`
 }
 
-func (rr *MR) Header() *RR_Header { return &rr.Hdr }
-func (rr *MR) copy() RR           { return &MR{*rr.Hdr.copyHeader(), rr.Mr} }
-func (rr *MR) len() int           { l := len(rr.Mr) + 1; return rr.Hdr.len() + l }
-
 func (rr *MR) String() string {
 	return rr.Hdr.String() + sprintName(rr.Mr)
 }
@@ -320,10 +292,6 @@ type MF struct {
 	Mf  string `dns:"cdomain-name"`
 }
 
-func (rr *MF) Header() *RR_Header { return &rr.Hdr }
-func (rr *MF) copy() RR           { return &MF{*rr.Hdr.copyHeader(), rr.Mf} }
-func (rr *MF) len() int           { return rr.Hdr.len() + len(rr.Mf) + 1 }
-
 func (rr *MF) String() string {
 	return rr.Hdr.String() + sprintName(rr.Mf)
 }
@@ -333,10 +301,6 @@ type MD struct {
 	Md  string `dns:"cdomain-name"`
 }
 
-func (rr *MD) Header() *RR_Header { return &rr.Hdr }
-func (rr *MD) copy() RR           { return &MD{*rr.Hdr.copyHeader(), rr.Md} }
-func (rr *MD) len() int           { return rr.Hdr.len() + len(rr.Md) + 1 }
-
 func (rr *MD) String() string {
 	return rr.Hdr.String() + sprintName(rr.Md)
 }
@@ -347,10 +311,6 @@ type MX struct {
 	Mx         string `dns:"cdomain-name"`
 }
 
-func (rr *MX) Header() *RR_Header { return &rr.Hdr }
-func (rr *MX) copy() RR           { return &MX{*rr.Hdr.copyHeader(), rr.Preference, rr.Mx} }
-func (rr *MX) len() int           { l := len(rr.Mx) + 1; return rr.Hdr.len() + l + 2 }
-
 func (rr *MX) String() string {
 	return rr.Hdr.String() + strconv.Itoa(int(rr.Preference)) + " " + sprintName(rr.Mx)
 }
@@ -361,10 +321,6 @@ type AFSDB struct {
 	Hostname string `dns:"cdomain-name"`
 }
 
-func (rr *AFSDB) Header() *RR_Header { return &rr.Hdr }
-func (rr *AFSDB) copy() RR           { return &AFSDB{*rr.Hdr.copyHeader(), rr.Subtype, rr.Hostname} }
-func (rr *AFSDB) len() int           { l := len(rr.Hostname) + 1; return rr.Hdr.len() + l + 2 }
-
 func (rr *AFSDB) String() string {
 	return rr.Hdr.String() + strconv.Itoa(int(rr.Subtype)) + " " + sprintName(rr.Hostname)
 }
@@ -374,10 +330,6 @@ type X25 struct {
 	PSDNAddress string
 }
 
-func (rr *X25) Header() *RR_Header { return &rr.Hdr }
-func (rr *X25) copy() RR           { return &X25{*rr.Hdr.copyHeader(), rr.PSDNAddress} }
-func (rr *X25) len() int           { return rr.Hdr.len() + len(rr.PSDNAddress) + 1 }
-
 func (rr *X25) String() string {
 	return rr.Hdr.String() + rr.PSDNAddress
 }
@@ -388,10 +340,6 @@ type RT struct {
 	Host       string `dns:"cdomain-name"`
 }
 
-func (rr *RT) Header() *RR_Header { return &rr.Hdr }
-func (rr *RT) copy() RR           { return &RT{*rr.Hdr.copyHeader(), rr.Preference, rr.Host} }
-func (rr *RT) len() int           { l := len(rr.Host) + 1; return rr.Hdr.len() + l + 2 }
-
 func (rr *RT) String() string {
 	return rr.Hdr.String() + strconv.Itoa(int(rr.Preference)) + " " + sprintName(rr.Host)
 }
@@ -401,10 +349,6 @@ type NS struct {
 	Ns  string `dns:"cdomain-name"`
 }
 
-func (rr *NS) Header() *RR_Header { return &rr.Hdr }
-func (rr *NS) len() int           { l := len(rr.Ns) + 1; return rr.Hdr.len() + l }
-func (rr *NS) copy() RR           { return &NS{*rr.Hdr.copyHeader(), rr.Ns} }
-
 func (rr *NS) String() string {
 	return rr.Hdr.String() + sprintName(rr.Ns)
 }
@@ -414,10 +358,6 @@ type PTR struct {
 	Ptr string `dns:"cdomain-name"`
 }
 
-func (rr *PTR) Header() *RR_Header { return &rr.Hdr }
-func (rr *PTR) copy() RR           { return &PTR{*rr.Hdr.copyHeader(), rr.Ptr} }
-func (rr *PTR) len() int           { l := len(rr.Ptr) + 1; return rr.Hdr.len() + l }
-
 func (rr *PTR) String() string {
 	return rr.Hdr.String() + sprintName(rr.Ptr)
 }
@@ -428,10 +368,6 @@ type RP struct {
 	Txt  string `dns:"domain-name"`
 }
 
-func (rr *RP) Header() *RR_Header { return &rr.Hdr }
-func (rr *RP) copy() RR           { return &RP{*rr.Hdr.copyHeader(), rr.Mbox, rr.Txt} }
-func (rr *RP) len() int           { return rr.Hdr.len() + len(rr.Mbox) + 1 + len(rr.Txt) + 1 }
-
 func (rr *RP) String() string {
 	return rr.Hdr.String() + rr.Mbox + " " + sprintTxt([]string{rr.Txt})
 }
@@ -447,11 +383,6 @@ type SOA struct {
 	Minttl  uint32
 }
 
-func (rr *SOA) Header() *RR_Header { return &rr.Hdr }
-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 *SOA) String() string {
 	return rr.Hdr.String() + sprintName(rr.Ns) + " " + sprintName(rr.Mbox) +
 		" " + strconv.FormatInt(int64(rr.Serial), 10) +
@@ -461,24 +392,11 @@ func (rr *SOA) String() string {
 		" " + strconv.FormatInt(int64(rr.Minttl), 10)
 }
 
-func (rr *SOA) len() int {
-	l := len(rr.Ns) + 1
-	n := len(rr.Mbox) + 1
-	return rr.Hdr.len() + l + n + 20
-}
-
 type TXT struct {
 	Hdr RR_Header
 	Txt []string `dns:"txt"`
 }
 
-func (rr *TXT) Header() *RR_Header { return &rr.Hdr }
-func (rr *TXT) copy() RR {
-	cp := make([]string, len(rr.Txt), cap(rr.Txt))
-	copy(cp, rr.Txt)
-	return &TXT{*rr.Hdr.copyHeader(), cp}
-}
-
 func (rr *TXT) String() string { return rr.Hdr.String() + sprintTxt(rr.Txt) }
 
 func sprintName(s string) string {
@@ -621,36 +539,13 @@ func nextByte(b []byte, offset int) (byte, int) {
 	}
 }
 
-func (rr *TXT) len() int {
-	l := rr.Hdr.len()
-	for _, t := range rr.Txt {
-		l += len(t) + 1
-	}
-	return l
-}
-
 type SPF struct {
 	Hdr RR_Header
 	Txt []string `dns:"txt"`
 }
 
-func (rr *SPF) Header() *RR_Header { return &rr.Hdr }
-func (rr *SPF) copy() RR {
-	cp := make([]string, len(rr.Txt), cap(rr.Txt))
-	copy(cp, rr.Txt)
-	return &SPF{*rr.Hdr.copyHeader(), cp}
-}
-
 func (rr *SPF) String() string { return rr.Hdr.String() + sprintTxt(rr.Txt) }
 
-func (rr *SPF) len() int {
-	l := rr.Hdr.len()
-	for _, t := range rr.Txt {
-		l += len(t) + 1
-	}
-	return l
-}
-
 type SRV struct {
 	Hdr      RR_Header
 	Priority uint16
@@ -659,12 +554,6 @@ type SRV struct {
 	Target   string `dns:"domain-name"`
 }
 
-func (rr *SRV) Header() *RR_Header { return &rr.Hdr }
-func (rr *SRV) len() int           { l := len(rr.Target) + 1; return rr.Hdr.len() + l + 6 }
-func (rr *SRV) copy() RR {
-	return &SRV{*rr.Hdr.copyHeader(), rr.Priority, rr.Weight, rr.Port, rr.Target}
-}
-
 func (rr *SRV) String() string {
 	return rr.Hdr.String() +
 		strconv.Itoa(int(rr.Priority)) + " " +
@@ -682,11 +571,6 @@ type NAPTR struct {
 	Replacement string `dns:"domain-name"`
 }
 
-func (rr *NAPTR) Header() *RR_Header { return &rr.Hdr }
-func (rr *NAPTR) copy() RR {
-	return &NAPTR{*rr.Hdr.copyHeader(), rr.Order, rr.Preference, rr.Flags, rr.Service, rr.Regexp, rr.Replacement}
-}
-
 func (rr *NAPTR) String() string {
 	return rr.Hdr.String() +
 		strconv.Itoa(int(rr.Order)) + " " +
@@ -697,11 +581,6 @@ func (rr *NAPTR) String() string {
 		rr.Replacement
 }
 
-func (rr *NAPTR) len() int {
-	return rr.Hdr.len() + 4 + len(rr.Flags) + 1 + len(rr.Service) + 1 +
-		len(rr.Regexp) + 1 + len(rr.Replacement) + 1
-}
-
 // The CERT resource record, see RFC 4398.
 type CERT struct {
 	Hdr         RR_Header
@@ -711,11 +590,6 @@ type CERT struct {
 	Certificate string `dns:"base64"`
 }
 
-func (rr *CERT) Header() *RR_Header { return &rr.Hdr }
-func (rr *CERT) copy() RR {
-	return &CERT{*rr.Hdr.copyHeader(), rr.Type, rr.KeyTag, rr.Algorithm, rr.Certificate}
-}
-
 func (rr *CERT) String() string {
 	var (
 		ok                  bool
@@ -733,21 +607,12 @@ func (rr *CERT) String() string {
 		" " + rr.Certificate
 }
 
-func (rr *CERT) len() int {
-	return rr.Hdr.len() + 5 +
-		base64.StdEncoding.DecodedLen(len(rr.Certificate))
-}
-
 // The DNAME resource record, see RFC 2672.
 type DNAME struct {
 	Hdr    RR_Header
 	Target string `dns:"domain-name"`
 }
 
-func (rr *DNAME) Header() *RR_Header { return &rr.Hdr }
-func (rr *DNAME) copy() RR           { return &DNAME{*rr.Hdr.copyHeader(), rr.Target} }
-func (rr *DNAME) len() int           { l := len(rr.Target) + 1; return rr.Hdr.len() + l }
-
 func (rr *DNAME) String() string {
 	return rr.Hdr.String() + sprintName(rr.Target)
 }
@@ -757,10 +622,6 @@ type A struct {
 	A   net.IP `dns:"a"`
 }
 
-func (rr *A) Header() *RR_Header { return &rr.Hdr }
-func (rr *A) copy() RR           { return &A{*rr.Hdr.copyHeader(), copyIP(rr.A)} }
-func (rr *A) len() int           { return rr.Hdr.len() + net.IPv4len }
-
 func (rr *A) String() string {
 	if rr.A == nil {
 		return rr.Hdr.String()
@@ -773,10 +634,6 @@ type AAAA struct {
 	AAAA net.IP `dns:"aaaa"`
 }
 
-func (rr *AAAA) Header() *RR_Header { return &rr.Hdr }
-func (rr *AAAA) copy() RR           { return &AAAA{*rr.Hdr.copyHeader(), copyIP(rr.AAAA)} }
-func (rr *AAAA) len() int           { return rr.Hdr.len() + net.IPv6len }
-
 func (rr *AAAA) String() string {
 	if rr.AAAA == nil {
 		return rr.Hdr.String()
@@ -791,12 +648,9 @@ type PX struct {
 	Mapx400    string `dns:"domain-name"`
 }
 
-func (rr *PX) Header() *RR_Header { return &rr.Hdr }
-func (rr *PX) copy() RR           { return &PX{*rr.Hdr.copyHeader(), rr.Preference, rr.Map822, rr.Mapx400} }
 func (rr *PX) String() string {
 	return rr.Hdr.String() + strconv.Itoa(int(rr.Preference)) + " " + sprintName(rr.Map822) + " " + sprintName(rr.Mapx400)
 }
-func (rr *PX) len() int { return rr.Hdr.len() + 2 + len(rr.Map822) + 1 + len(rr.Mapx400) + 1 }
 
 type GPOS struct {
 	Hdr       RR_Header
@@ -805,11 +659,6 @@ type GPOS struct {
 	Altitude  string
 }
 
-func (rr *GPOS) Header() *RR_Header { return &rr.Hdr }
-func (rr *GPOS) copy() RR           { return &GPOS{*rr.Hdr.copyHeader(), rr.Longitude, rr.Latitude, rr.Altitude} }
-func (rr *GPOS) len() int {
-	return rr.Hdr.len() + len(rr.Longitude) + len(rr.Latitude) + len(rr.Altitude) + 3
-}
 func (rr *GPOS) String() string {
 	return rr.Hdr.String() + rr.Longitude + " " + rr.Latitude + " " + rr.Altitude
 }
@@ -825,12 +674,6 @@ type LOC struct {
 	Altitude  uint32
 }
 
-func (rr *LOC) Header() *RR_Header { return &rr.Hdr }
-func (rr *LOC) len() int           { return rr.Hdr.len() + 4 + 12 }
-func (rr *LOC) copy() RR {
-	return &LOC{*rr.Hdr.copyHeader(), rr.Version, rr.Size, rr.HorizPre, rr.VertPre, rr.Latitude, rr.Longitude, rr.Altitude}
-}
-
 // 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 {
@@ -914,11 +757,6 @@ type RRSIG struct {
 	Signature   string `dns:"base64"`
 }
 
-func (rr *RRSIG) Header() *RR_Header { return &rr.Hdr }
-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 *RRSIG) String() string {
 	s := rr.Hdr.String()
 	s += Type(rr.TypeCovered).String()
@@ -933,24 +771,12 @@ func (rr *RRSIG) String() string {
 	return s
 }
 
-func (rr *RRSIG) len() int {
-	return rr.Hdr.len() + len(rr.SignerName) + 1 +
-		base64.StdEncoding.DecodedLen(len(rr.Signature)) + 18
-}
-
 type NSEC struct {
 	Hdr        RR_Header
 	NextDomain string   `dns:"domain-name"`
 	TypeBitMap []uint16 `dns:"nsec"`
 }
 
-func (rr *NSEC) Header() *RR_Header { return &rr.Hdr }
-func (rr *NSEC) copy() RR {
-	cp := make([]uint16, len(rr.TypeBitMap), cap(rr.TypeBitMap))
-	copy(cp, rr.TypeBitMap)
-	return &NSEC{*rr.Hdr.copyHeader(), rr.NextDomain, cp}
-}
-
 func (rr *NSEC) String() string {
 	s := rr.Hdr.String() + sprintName(rr.NextDomain)
 	for i := 0; i < len(rr.TypeBitMap); i++ {
@@ -988,12 +814,6 @@ type DS struct {
 	Digest     string `dns:"hex"`
 }
 
-func (rr *DS) Header() *RR_Header { return &rr.Hdr }
-func (rr *DS) len() int           { return rr.Hdr.len() + 4 + len(rr.Digest)/2 }
-func (rr *DS) copy() RR {
-	return &DS{*rr.Hdr.copyHeader(), rr.KeyTag, rr.Algorithm, rr.DigestType, rr.Digest}
-}
-
 func (rr *DS) String() string {
 	return rr.Hdr.String() + strconv.Itoa(int(rr.KeyTag)) +
 		" " + strconv.Itoa(int(rr.Algorithm)) +
@@ -1007,10 +827,6 @@ type KX struct {
 	Exchanger  string `dns:"domain-name"`
 }
 
-func (rr *KX) Header() *RR_Header { return &rr.Hdr }
-func (rr *KX) len() int           { return rr.Hdr.len() + 2 + len(rr.Exchanger) + 1 }
-func (rr *KX) copy() RR           { return &KX{*rr.Hdr.copyHeader(), rr.Preference, rr.Exchanger} }
-
 func (rr *KX) String() string {
 	return rr.Hdr.String() + strconv.Itoa(int(rr.Preference)) +
 		" " + sprintName(rr.Exchanger)
@@ -1024,12 +840,6 @@ type TA struct {
 	Digest     string `dns:"hex"`
 }
 
-func (rr *TA) Header() *RR_Header { return &rr.Hdr }
-func (rr *TA) len() int           { return rr.Hdr.len() + 4 + len(rr.Digest)/2 }
-func (rr *TA) copy() RR {
-	return &TA{*rr.Hdr.copyHeader(), rr.KeyTag, rr.Algorithm, rr.DigestType, rr.Digest}
-}
-
 func (rr *TA) String() string {
 	return rr.Hdr.String() + strconv.Itoa(int(rr.KeyTag)) +
 		" " + strconv.Itoa(int(rr.Algorithm)) +
@@ -1043,10 +853,6 @@ type TALINK struct {
 	NextName     string `dns:"domain-name"`
 }
 
-func (rr *TALINK) Header() *RR_Header { return &rr.Hdr }
-func (rr *TALINK) copy() RR           { return &TALINK{*rr.Hdr.copyHeader(), rr.PreviousName, rr.NextName} }
-func (rr *TALINK) len() int           { return rr.Hdr.len() + len(rr.PreviousName) + len(rr.NextName) + 2 }
-
 func (rr *TALINK) String() string {
 	return rr.Hdr.String() +
 		sprintName(rr.PreviousName) + " " + sprintName(rr.NextName)
@@ -1059,12 +865,6 @@ type SSHFP struct {
 	FingerPrint string `dns:"hex"`
 }
 
-func (rr *SSHFP) Header() *RR_Header { return &rr.Hdr }
-func (rr *SSHFP) len() int           { return rr.Hdr.len() + 2 + len(rr.FingerPrint)/2 }
-func (rr *SSHFP) copy() RR {
-	return &SSHFP{*rr.Hdr.copyHeader(), rr.Algorithm, rr.Type, rr.FingerPrint}
-}
-
 func (rr *SSHFP) String() string {
 	return rr.Hdr.String() + strconv.Itoa(int(rr.Algorithm)) +
 		" " + strconv.Itoa(int(rr.Type)) +
@@ -1085,11 +885,6 @@ type IPSECKEY struct {
 	PublicKey   string `dns:"base64"`
 }
 
-func (rr *IPSECKEY) Header() *RR_Header { return &rr.Hdr }
-func (rr *IPSECKEY) copy() RR {
-	return &IPSECKEY{*rr.Hdr.copyHeader(), rr.Precedence, rr.GatewayType, rr.Algorithm, rr.GatewayA, rr.GatewayAAAA, rr.GatewayName, rr.PublicKey}
-}
-
 func (rr *IPSECKEY) String() string {
 	s := rr.Hdr.String() + strconv.Itoa(int(rr.Precedence)) +
 		" " + strconv.Itoa(int(rr.GatewayType)) +
@@ -1143,14 +938,6 @@ type DNSKEY struct {
 	PublicKey string `dns:"base64"`
 }
 
-func (rr *DNSKEY) Header() *RR_Header { return &rr.Hdr }
-func (rr *DNSKEY) len() int {
-	return rr.Hdr.len() + 4 + base64.StdEncoding.DecodedLen(len(rr.PublicKey))
-}
-func (rr *DNSKEY) copy() RR {
-	return &DNSKEY{*rr.Hdr.copyHeader(), rr.Flags, rr.Protocol, rr.Algorithm, rr.PublicKey}
-}
-
 func (rr *DNSKEY) String() string {
 	return rr.Hdr.String() + strconv.Itoa(int(rr.Flags)) +
 		" " + strconv.Itoa(int(rr.Protocol)) +
@@ -1166,12 +953,6 @@ type RKEY struct {
 	PublicKey string `dns:"base64"`
 }
 
-func (rr *RKEY) Header() *RR_Header { return &rr.Hdr }
-func (rr *RKEY) len() int           { return rr.Hdr.len() + 4 + base64.StdEncoding.DecodedLen(len(rr.PublicKey)) }
-func (rr *RKEY) copy() RR {
-	return &RKEY{*rr.Hdr.copyHeader(), rr.Flags, rr.Protocol, rr.Algorithm, rr.PublicKey}
-}
-
 func (rr *RKEY) String() string {
 	return rr.Hdr.String() + strconv.Itoa(int(rr.Flags)) +
 		" " + strconv.Itoa(int(rr.Protocol)) +
@@ -1184,10 +965,7 @@ type NSAPPTR struct {
 	Ptr string `dns:"domain-name"`
 }
 
-func (rr *NSAPPTR) Header() *RR_Header { return &rr.Hdr }
-func (rr *NSAPPTR) copy() RR           { return &NSAPPTR{*rr.Hdr.copyHeader(), rr.Ptr} }
-func (rr *NSAPPTR) String() string     { return rr.Hdr.String() + sprintName(rr.Ptr) }
-func (rr *NSAPPTR) len() int           { return rr.Hdr.len() + len(rr.Ptr) }
+func (rr *NSAPPTR) String() string { return rr.Hdr.String() + sprintName(rr.Ptr) }
 
 type NSEC3 struct {
 	Hdr        RR_Header
@@ -1201,13 +979,6 @@ type NSEC3 struct {
 	TypeBitMap []uint16 `dns:"nsec"`
 }
 
-func (rr *NSEC3) Header() *RR_Header { return &rr.Hdr }
-func (rr *NSEC3) copy() RR {
-	cp := make([]uint16, len(rr.TypeBitMap), cap(rr.TypeBitMap))
-	copy(cp, rr.TypeBitMap)
-	return &NSEC3{*rr.Hdr.copyHeader(), rr.Hash, rr.Flags, rr.Iterations, rr.SaltLength, rr.Salt, rr.HashLength, rr.NextDomain, cp}
-}
-
 func (rr *NSEC3) String() string {
 	s := rr.Hdr.String()
 	s += strconv.Itoa(int(rr.Hash)) +
@@ -1243,12 +1014,6 @@ type NSEC3PARAM struct {
 	Salt       string `dns:"hex"`
 }
 
-func (rr *NSEC3PARAM) Header() *RR_Header { return &rr.Hdr }
-func (rr *NSEC3PARAM) len() int           { return rr.Hdr.len() + 2 + 4 + 1 + len(rr.Salt)/2 }
-func (rr *NSEC3PARAM) copy() RR {
-	return &NSEC3PARAM{*rr.Hdr.copyHeader(), rr.Hash, rr.Flags, rr.Iterations, rr.SaltLength, rr.Salt}
-}
-
 func (rr *NSEC3PARAM) String() string {
 	s := rr.Hdr.String()
 	s += strconv.Itoa(int(rr.Hash)) +
@@ -1271,31 +1036,17 @@ type TKEY struct {
 	OtherData  string
 }
 
-func (rr *TKEY) Header() *RR_Header { return &rr.Hdr }
-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 *TKEY) String() string {
 	// It has no presentation format
 	return ""
 }
 
-func (rr *TKEY) len() int {
-	return rr.Hdr.len() + len(rr.Algorithm) + 1 + 4 + 4 + 6 +
-		len(rr.Key) + 2 + len(rr.OtherData)
-}
-
 // RFC3597 represents an unknown/generic RR.
 type RFC3597 struct {
 	Hdr   RR_Header
 	Rdata string `dns:"hex"`
 }
 
-func (rr *RFC3597) Header() *RR_Header { return &rr.Hdr }
-func (rr *RFC3597) copy() RR           { return &RFC3597{*rr.Hdr.copyHeader(), rr.Rdata} }
-func (rr *RFC3597) len() int           { return rr.Hdr.len() + len(rr.Rdata)/2 + 2 }
-
 func (rr *RFC3597) String() string {
 	// Let's call it a hack
 	s := rfc3597Header(rr.Hdr)
@@ -1321,9 +1072,6 @@ type URI struct {
 	Target   string `dns:"octet"`
 }
 
-func (rr *URI) Header() *RR_Header { return &rr.Hdr }
-func (rr *URI) copy() RR           { return &URI{*rr.Hdr.copyHeader(), rr.Weight, rr.Priority, rr.Target} }
-func (rr *URI) len() int           { return rr.Hdr.len() + 4 + len(rr.Target) }
 func (rr *URI) String() string {
 	return rr.Hdr.String() + strconv.Itoa(int(rr.Priority)) +
 		" " + strconv.Itoa(int(rr.Weight)) + " " + sprintTxtOctet(rr.Target)
@@ -1334,10 +1082,7 @@ type DHCID struct {
 	Digest string `dns:"base64"`
 }
 
-func (rr *DHCID) Header() *RR_Header { return &rr.Hdr }
-func (rr *DHCID) copy() RR           { return &DHCID{*rr.Hdr.copyHeader(), rr.Digest} }
-func (rr *DHCID) String() string     { return rr.Hdr.String() + rr.Digest }
-func (rr *DHCID) len() int           { return rr.Hdr.len() + base64.StdEncoding.DecodedLen(len(rr.Digest)) }
+func (rr *DHCID) String() string { return rr.Hdr.String() + rr.Digest }
 
 type TLSA struct {
 	Hdr          RR_Header
@@ -1347,13 +1092,6 @@ type TLSA struct {
 	Certificate  string `dns:"hex"`
 }
 
-func (rr *TLSA) Header() *RR_Header { return &rr.Hdr }
-func (rr *TLSA) len() int           { return rr.Hdr.len() + 3 + len(rr.Certificate)/2 }
-
-func (rr *TLSA) copy() RR {
-	return &TLSA{*rr.Hdr.copyHeader(), rr.Usage, rr.Selector, rr.MatchingType, rr.Certificate}
-}
-
 func (rr *TLSA) String() string {
 	return rr.Hdr.String() +
 		strconv.Itoa(int(rr.Usage)) +
@@ -1372,13 +1110,6 @@ type HIP struct {
 	RendezvousServers  []string `dns:"domain-name"`
 }
 
-func (rr *HIP) Header() *RR_Header { return &rr.Hdr }
-func (rr *HIP) copy() RR {
-	cp := make([]string, len(rr.RendezvousServers), cap(rr.RendezvousServers))
-	copy(cp, rr.RendezvousServers)
-	return &HIP{*rr.Hdr.copyHeader(), rr.HitLength, rr.PublicKeyAlgorithm, rr.PublicKeyLength, rr.Hit, rr.PublicKey, cp}
-}
-
 func (rr *HIP) String() string {
 	s := rr.Hdr.String() +
 		strconv.Itoa(int(rr.PublicKeyAlgorithm)) +
@@ -1390,38 +1121,13 @@ func (rr *HIP) String() string {
 	return s
 }
 
-func (rr *HIP) len() int {
-	l := rr.Hdr.len() + 4 +
-		len(rr.Hit)/2 +
-		base64.StdEncoding.DecodedLen(len(rr.PublicKey))
-	for _, d := range rr.RendezvousServers {
-		l += len(d) + 1
-	}
-	return l
-}
-
 type NINFO struct {
 	Hdr    RR_Header
 	ZSData []string `dns:"txt"`
 }
 
-func (rr *NINFO) Header() *RR_Header { return &rr.Hdr }
-func (rr *NINFO) copy() RR {
-	cp := make([]string, len(rr.ZSData), cap(rr.ZSData))
-	copy(cp, rr.ZSData)
-	return &NINFO{*rr.Hdr.copyHeader(), cp}
-}
-
 func (rr *NINFO) String() string { return rr.Hdr.String() + sprintTxt(rr.ZSData) }
 
-func (rr *NINFO) len() int {
-	l := rr.Hdr.len()
-	for _, t := range rr.ZSData {
-		l += len(t) + 1
-	}
-	return l
-}
-
 type WKS struct {
 	Hdr      RR_Header
 	Address  net.IP `dns:"a"`
@@ -1429,13 +1135,9 @@ type WKS struct {
 	BitMap   []uint16 `dns:"wks"`
 }
 
-func (rr *WKS) Header() *RR_Header { return &rr.Hdr }
-func (rr *WKS) len() int           { return rr.Hdr.len() + net.IPv4len + 1 }
-
-func (rr *WKS) copy() RR {
-	cp := make([]uint16, len(rr.BitMap), cap(rr.BitMap))
-	copy(cp, rr.BitMap)
-	return &WKS{*rr.Hdr.copyHeader(), copyIP(rr.Address), rr.Protocol, cp}
+func (rr *WKS) len() int {
+	// TODO: this is missing something...
+	return rr.Hdr.len() + net.IPv4len + 1
 }
 
 func (rr *WKS) String() (s string) {
@@ -1457,10 +1159,6 @@ type NID struct {
 	NodeID     uint64
 }
 
-func (rr *NID) Header() *RR_Header { return &rr.Hdr }
-func (rr *NID) copy() RR           { return &NID{*rr.Hdr.copyHeader(), rr.Preference, rr.NodeID} }
-func (rr *NID) len() int           { return rr.Hdr.len() + 2 + 8 }
-
 func (rr *NID) String() string {
 	s := rr.Hdr.String() + strconv.Itoa(int(rr.Preference))
 	node := fmt.Sprintf("%0.16x", rr.NodeID)
@@ -1474,10 +1172,6 @@ type L32 struct {
 	Locator32  net.IP `dns:"a"`
 }
 
-func (rr *L32) Header() *RR_Header { return &rr.Hdr }
-func (rr *L32) copy() RR           { return &L32{*rr.Hdr.copyHeader(), rr.Preference, copyIP(rr.Locator32)} }
-func (rr *L32) len() int           { return rr.Hdr.len() + net.IPv4len }
-
 func (rr *L32) String() string {
 	if rr.Locator32 == nil {
 		return rr.Hdr.String() + strconv.Itoa(int(rr.Preference))
@@ -1492,10 +1186,6 @@ type L64 struct {
 	Locator64  uint64
 }
 
-func (rr *L64) Header() *RR_Header { return &rr.Hdr }
-func (rr *L64) copy() RR           { return &L64{*rr.Hdr.copyHeader(), rr.Preference, rr.Locator64} }
-func (rr *L64) len() int           { return rr.Hdr.len() + 2 + 8 }
-
 func (rr *L64) String() string {
 	s := rr.Hdr.String() + strconv.Itoa(int(rr.Preference))
 	node := fmt.Sprintf("%0.16X", rr.Locator64)
@@ -1509,10 +1199,6 @@ type LP struct {
 	Fqdn       string `dns:"domain-name"`
 }
 
-func (rr *LP) Header() *RR_Header { return &rr.Hdr }
-func (rr *LP) copy() RR           { return &LP{*rr.Hdr.copyHeader(), rr.Preference, rr.Fqdn} }
-func (rr *LP) len() int           { return rr.Hdr.len() + 2 + len(rr.Fqdn) + 1 }
-
 func (rr *LP) String() string {
 	return rr.Hdr.String() + strconv.Itoa(int(rr.Preference)) + " " + sprintName(rr.Fqdn)
 }
@@ -1522,20 +1208,14 @@ type EUI48 struct {
 	Address uint64 `dns:"uint48"`
 }
 
-func (rr *EUI48) Header() *RR_Header { return &rr.Hdr }
-func (rr *EUI48) copy() RR           { return &EUI48{*rr.Hdr.copyHeader(), rr.Address} }
-func (rr *EUI48) String() string     { return rr.Hdr.String() + euiToString(rr.Address, 48) }
-func (rr *EUI48) len() int           { return rr.Hdr.len() + 6 }
+func (rr *EUI48) String() string { return rr.Hdr.String() + euiToString(rr.Address, 48) }
 
 type EUI64 struct {
 	Hdr     RR_Header
 	Address uint64
 }
 
-func (rr *EUI64) Header() *RR_Header { return &rr.Hdr }
-func (rr *EUI64) copy() RR           { return &EUI64{*rr.Hdr.copyHeader(), rr.Address} }
-func (rr *EUI64) String() string     { return rr.Hdr.String() + euiToString(rr.Address, 64) }
-func (rr *EUI64) len() int           { return rr.Hdr.len() + 8 }
+func (rr *EUI64) String() string { return rr.Hdr.String() + euiToString(rr.Address, 64) }
 
 type CAA struct {
 	Hdr   RR_Header
@@ -1544,9 +1224,6 @@ type CAA struct {
 	Value string `dns:"octet"`
 }
 
-func (rr *CAA) Header() *RR_Header { return &rr.Hdr }
-func (rr *CAA) copy() RR           { return &CAA{*rr.Hdr.copyHeader(), rr.Flag, rr.Tag, rr.Value} }
-func (rr *CAA) len() int           { return rr.Hdr.len() + 2 + len(rr.Tag) + len(rr.Value) }
 func (rr *CAA) String() string {
 	return rr.Hdr.String() + strconv.Itoa(int(rr.Flag)) + " " + rr.Tag + " " + sprintTxtOctet(rr.Value)
 }
@@ -1556,62 +1233,42 @@ type UID struct {
 	Uid uint32
 }
 
-func (rr *UID) Header() *RR_Header { return &rr.Hdr }
-func (rr *UID) copy() RR           { return &UID{*rr.Hdr.copyHeader(), rr.Uid} }
-func (rr *UID) String() string     { return rr.Hdr.String() + strconv.FormatInt(int64(rr.Uid), 10) }
-func (rr *UID) len() int           { return rr.Hdr.len() + 4 }
+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) Header() *RR_Header { return &rr.Hdr }
-func (rr *GID) copy() RR           { return &GID{*rr.Hdr.copyHeader(), rr.Gid} }
-func (rr *GID) String() string     { return rr.Hdr.String() + strconv.FormatInt(int64(rr.Gid), 10) }
-func (rr *GID) len() int           { return rr.Hdr.len() + 4 }
+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) Header() *RR_Header { return &rr.Hdr }
-func (rr *UINFO) copy() RR           { return &UINFO{*rr.Hdr.copyHeader(), rr.Uinfo} }
-func (rr *UINFO) String() string     { return rr.Hdr.String() + sprintTxt([]string{rr.Uinfo}) }
-func (rr *UINFO) len() int           { return rr.Hdr.len() + len(rr.Uinfo) + 1 }
+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) Header() *RR_Header { return &rr.Hdr }
-func (rr *EID) copy() RR           { return &EID{*rr.Hdr.copyHeader(), rr.Endpoint} }
-func (rr *EID) String() string     { return rr.Hdr.String() + strings.ToUpper(rr.Endpoint) }
-func (rr *EID) len() int           { return rr.Hdr.len() + len(rr.Endpoint)/2 }
+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) Header() *RR_Header { return &rr.Hdr }
-func (rr *NIMLOC) copy() RR           { return &NIMLOC{*rr.Hdr.copyHeader(), rr.Locator} }
-func (rr *NIMLOC) String() string     { return rr.Hdr.String() + strings.ToUpper(rr.Locator) }
-func (rr *NIMLOC) len() int           { return rr.Hdr.len() + len(rr.Locator)/2 }
+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) Header() *RR_Header { return &rr.Hdr }
-func (rr *OPENPGPKEY) copy() RR           { return &OPENPGPKEY{*rr.Hdr.copyHeader(), rr.PublicKey} }
-func (rr *OPENPGPKEY) String() string     { return rr.Hdr.String() + rr.PublicKey }
-func (rr *OPENPGPKEY) len() int {
-	return rr.Hdr.len() + base64.StdEncoding.DecodedLen(len(rr.PublicKey))
-}
+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.
@@ -1669,73 +1326,3 @@ func copyIP(ip net.IP) net.IP {
 	copy(p, ip)
 	return p
 }
-
-// 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) },
-	TypeCAA:        func() RR { return new(CAA) },
-	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) },
-	TypeKEY:        func() RR { return new(KEY) },
-	TypeDNSKEY:     func() RR { return new(DNSKEY) },
-	TypeDS:         func() RR { return new(DS) },
-	TypeEUI48:      func() RR { return new(EUI48) },
-	TypeEUI64:      func() RR { return new(EUI64) },
-	TypeGID:        func() RR { return new(GID) },
-	TypeGPOS:       func() RR { return new(GPOS) },
-	TypeEID:        func() RR { return new(EID) },
-	TypeHINFO:      func() RR { return new(HINFO) },
-	TypeHIP:        func() RR { return new(HIP) },
-	TypeIPSECKEY:   func() RR { return new(IPSECKEY) },
-	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) },
-	TypeNINFO:      func() RR { return new(NINFO) },
-	TypeNIMLOC:     func() RR { return new(NIMLOC) },
-	TypeNS:         func() RR { return new(NS) },
-	TypeNSAPPTR:    func() RR { return new(NSAPPTR) },
-	TypeNSEC3:      func() RR { return new(NSEC3) },
-	TypeNSEC3PARAM: func() RR { return new(NSEC3PARAM) },
-	TypeNSEC:       func() RR { return new(NSEC) },
-	TypeOPENPGPKEY: func() RR { return new(OPENPGPKEY) },
-	TypeOPT:        func() RR { return new(OPT) },
-	TypePTR:        func() RR { return new(PTR) },
-	TypeRKEY:       func() RR { return new(RKEY) },
-	TypeRP:         func() RR { return new(RP) },
-	TypePX:         func() RR { return new(PX) },
-	TypeSIG:        func() RR { return new(SIG) },
-	TypeRRSIG:      func() RR { return new(RRSIG) },
-	TypeRT:         func() RR { return new(RT) },
-	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) },
-	TypeWKS:        func() RR { return new(WKS) },
-	TypeX25:        func() RR { return new(X25) },
-}

+ 266 - 0
Godeps/_workspace/src/github.com/miekg/dns/types_generate.go

@@ -0,0 +1,266 @@
+//+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":      {},
+	"WKS":      {},
+	"IPSECKEY": {},
+}
+
+var packageHdr = `
+// *** DO NOT MODIFY ***
+// AUTOGENERATED BY go generate
+
+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 st.Tag(i) {
+			case `dns:"-"`:
+				// ignored
+			case `dns:"cdomain-name"`, `dns:"domain-name"`:
+				o("l += len(rr.%s) + 1\n")
+			case `dns:"octet"`:
+				o("l += len(rr.%s)\n")
+			case `dns:"base64"`:
+				o("l += base64.StdEncoding.DecodedLen(len(rr.%s))\n")
+			case `dns:"size-hex"`, `dns:"hex"`:
+				o("l += len(rr.%s)/2 + 1\n")
+			case `dns:"a"`:
+				o("l += net.IPv4len // %s\n")
+			case `dns:"aaaa"`:
+				o("l += net.IPv6len // %s\n")
+			case `dns:"txt"`:
+				o("for _, t := range rr.%s { l += len(t) + 1 }\n")
+			case `dns:"uint48"`:
+				o("l += 6 // %s\n")
+			case "":
+				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, "[]")
+				t = strings.TrimPrefix(t, "github.com/miekg/dns.")
+				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)
+	}
+}

+ 10 - 0
Godeps/_workspace/src/github.com/miekg/dns/udp_linux.go

@@ -24,6 +24,12 @@ func setUDPSocketOptions4(conn *net.UDPConn) error {
 	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
 }
 
@@ -36,6 +42,10 @@ func setUDPSocketOptions6(conn *net.UDPConn) error {
 	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
 }
 

+ 50 - 38
Godeps/_workspace/src/github.com/miekg/dns/update.go

@@ -3,18 +3,22 @@ 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) {
-	u.Answer = make([]RR, len(rr))
-	for i, r := range rr {
-		u.Answer[i] = &ANY{Hdr: RR_Header{Name: r.Header().Name, Ttl: 0, Rrtype: TypeANY, Class: ClassANY}}
+	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) {
-	u.Answer = make([]RR, len(rr))
-	for i, r := range rr {
-		u.Answer[i] = &ANY{Hdr: RR_Header{Name: r.Header().Name, Ttl: 0, Rrtype: TypeANY, Class: ClassNONE}}
+	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}})
 	}
 }
 
@@ -24,34 +28,34 @@ func (u *Msg) Used(rr []RR) {
 	if len(u.Question) == 0 {
 		panic("dns: empty question section")
 	}
-	u.Answer = make([]RR, len(rr))
-	for i, r := range rr {
-		u.Answer[i] = r
-		u.Answer[i].Header().Class = u.Question[0].Qclass
+	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) {
-	u.Answer = make([]RR, len(rr))
-	for i, r := range rr {
-		u.Answer[i] = r
-		u.Answer[i].Header().Class = ClassANY
-		u.Answer[i].Header().Ttl = 0
-		u.Answer[i].Header().Rdlength = 0
+	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) {
-	u.Answer = make([]RR, len(rr))
-	for i, r := range rr {
-		u.Answer[i] = r
-		u.Answer[i].Header().Class = ClassNONE
-		u.Answer[i].Header().Rdlength = 0
-		u.Answer[i].Header().Ttl = 0
+	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}})
 	}
 }
 
@@ -60,35 +64,43 @@ func (u *Msg) Insert(rr []RR) {
 	if len(u.Question) == 0 {
 		panic("dns: empty question section")
 	}
-	u.Ns = make([]RR, len(rr))
-	for i, r := range rr {
-		u.Ns[i] = r
-		u.Ns[i].Header().Class = u.Question[0].Qclass
+	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) {
-	u.Ns = make([]RR, len(rr))
-	for i, r := range rr {
-		u.Ns[i] = &ANY{Hdr: RR_Header{Name: r.Header().Name, Ttl: 0, Rrtype: r.Header().Rrtype, Class: ClassANY}}
+	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) {
-	u.Ns = make([]RR, len(rr))
-	for i, r := range rr {
-		u.Ns[i] = &ANY{Hdr: RR_Header{Name: r.Header().Name, Ttl: 0, Rrtype: TypeANY, Class: ClassANY}}
+	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 the RRSset, see RFC 2136 section 2.5.4
+// Remove creates a dynamic update packet deletes RR from a RRSset, see RFC 2136 section 2.5.4
 func (u *Msg) Remove(rr []RR) {
-	u.Ns = make([]RR, len(rr))
-	for i, r := range rr {
-		u.Ns[i] = r
-		u.Ns[i].Header().Class = ClassNONE
-		u.Ns[i].Header().Ttl = 0
+	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)
 	}
 }

+ 68 - 7
Godeps/_workspace/src/github.com/miekg/dns/update_test.go

@@ -9,7 +9,8 @@ func TestDynamicUpdateParsing(t *testing.T) {
 	prefix := "example.com. IN "
 	for _, typ := range TypeToString {
 		if typ == "OPT" || typ == "AXFR" || typ == "IXFR" || typ == "ANY" || typ == "TKEY" ||
-			typ == "TSIG" || typ == "ISDN" || typ == "UNSPEC" || typ == "NULL" || typ == "ATMA" {
+			typ == "TSIG" || typ == "ISDN" || typ == "UNSPEC" || typ == "NULL" || typ == "ATMA" ||
+			typ == "Reserved" || typ == "None" || typ == "NXT" || typ == "MAILB" || typ == "MAILA" {
 			continue
 		}
 		r, err := NewRR(prefix + typ)
@@ -57,28 +58,88 @@ func TestRemoveRRset(t *testing.T) {
 	// for each set mentioned in the RRs provided to it.
 	rr, err := NewRR(". 100 IN A 127.0.0.1")
 	if err != nil {
-		t.Fatalf("Error constructing RR: %v", err)
+		t.Fatalf("error constructing RR: %v", err)
 	}
 	m := new(Msg)
 	m.Ns = []RR{&RR_Header{Name: ".", Rrtype: TypeA, Class: ClassANY, Ttl: 0, Rdlength: 0}}
 	expectstr := m.String()
 	expect, err := m.Pack()
 	if err != nil {
-		t.Fatalf("Error packing expected msg: %v", err)
+		t.Fatalf("error packing expected msg: %v", err)
 	}
 
 	m.Ns = nil
 	m.RemoveRRset([]RR{rr})
 	actual, err := m.Pack()
 	if err != nil {
-		t.Fatalf("Error packing actual msg: %v", err)
+		t.Fatalf("error packing actual msg: %v", err)
 	}
 	if !bytes.Equal(actual, expect) {
 		tmp := new(Msg)
 		if err := tmp.Unpack(actual); err != nil {
-			t.Fatalf("Error unpacking actual msg: %v", err)
+			t.Fatalf("error unpacking actual msg: %v", err)
 		}
-		t.Errorf("Expected msg:\n%s", expectstr)
-		t.Errorf("Actual msg:\n%v", tmp)
+		t.Errorf("expected msg:\n%s", expectstr)
+		t.Errorf("actual msg:\n%v", tmp)
+	}
+}
+
+func TestPreReqAndRemovals(t *testing.T) {
+	// Build a list of multiple prereqs and then somes removes followed by an insert.
+	// We should be able to add multiple prereqs and updates.
+	m := new(Msg)
+	m.SetUpdate("example.org.")
+	m.Id = 1234
+
+	// Use a full set of RRs each time, so we are sure the rdata is stripped.
+	rr_name1, _ := NewRR("name_used. 3600 IN A 127.0.0.1")
+	rr_name2, _ := NewRR("name_not_used. 3600 IN A 127.0.0.1")
+	rr_remove1, _ := NewRR("remove1. 3600 IN A 127.0.0.1")
+	rr_remove2, _ := NewRR("remove2. 3600 IN A 127.0.0.1")
+	rr_remove3, _ := NewRR("remove3. 3600 IN A 127.0.0.1")
+	rr_insert, _ := NewRR("insert. 3600 IN A 127.0.0.1")
+	rr_rrset1, _ := NewRR("rrset_used1. 3600 IN A 127.0.0.1")
+	rr_rrset2, _ := NewRR("rrset_used2. 3600 IN A 127.0.0.1")
+	rr_rrset3, _ := NewRR("rrset_not_used. 3600 IN A 127.0.0.1")
+
+	// Handle the prereqs.
+	m.NameUsed([]RR{rr_name1})
+	m.NameNotUsed([]RR{rr_name2})
+	m.RRsetUsed([]RR{rr_rrset1})
+	m.Used([]RR{rr_rrset2})
+	m.RRsetNotUsed([]RR{rr_rrset3})
+
+	// and now the updates.
+	m.RemoveName([]RR{rr_remove1})
+	m.RemoveRRset([]RR{rr_remove2})
+	m.Remove([]RR{rr_remove3})
+	m.Insert([]RR{rr_insert})
+
+	// This test function isn't a Example function because we print these RR with tabs at the
+	// end and the Example function trim these, thus they never match.
+	// TODO(miek): don't print these tabs and make this into an Example function.
+	expect := `;; opcode: UPDATE, status: NOERROR, id: 1234
+;; flags:; QUERY: 1, ANSWER: 5, AUTHORITY: 4, ADDITIONAL: 0
+
+;; QUESTION SECTION:
+;example.org.	IN	 SOA
+
+;; ANSWER SECTION:
+name_used.	0	ANY	ANY	
+name_not_used.	0	NONE	ANY	
+rrset_used1.	0	ANY	A	
+rrset_used2.	3600	IN	A	127.0.0.1
+rrset_not_used.	0	NONE	A	
+
+;; AUTHORITY SECTION:
+remove1.	0	ANY	ANY	
+remove2.	0	ANY	A	
+remove3.	0	NONE	A	127.0.0.1
+insert.	3600	IN	A	127.0.0.1
+`
+
+	if m.String() != expect {
+		t.Errorf("expected msg:\n%s", expect)
+		t.Errorf("actual msg:\n%v", m.String())
 	}
 }

+ 15 - 3
Godeps/_workspace/src/github.com/miekg/dns/xfr.go

@@ -23,14 +23,26 @@ type Transfer struct {
 // 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
 	}
-	t.Conn, err = DialTimeout("tcp", a, timeout)
-	if err != nil {
-		return nil, err
+	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

+ 2 - 2
Godeps/_workspace/src/github.com/miekg/dns/xfr_test.go

@@ -58,11 +58,11 @@ func TestAXFR_NLNL_MultipleEnvelopes(t *testing.T) {
 
 	tr := new(Transfer)
 	if a, err := tr.In(m, net.JoinHostPort(server, "53")); err != nil {
-		t.Fatalf("Failed to setup axfr %v for server: %v", err, server)
+		t.Fatalf("failed to setup axfr %v for server: %v", err, server)
 	} else {
 		for ex := range a {
 			if ex.Error != nil {
-				t.Errorf("Error %v", ex.Error)
+				t.Errorf("error %v", ex.Error)
 				break
 			}
 		}

+ 1 - 1
Godeps/_workspace/src/github.com/miekg/dns/zgenerate.go

@@ -15,7 +15,7 @@ import (
 // * [[ttl][class]]
 // * type
 // * rhs (rdata)
-// But we are lazy here, only the range is parsed *all* occurences
+// 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".

+ 7 - 5
Godeps/_workspace/src/github.com/miekg/dns/zscan.go

@@ -67,7 +67,7 @@ const (
 )
 
 // ParseError is a parsing error. It contains the parse error and the location in the io.Reader
-// where the error occured.
+// where the error occurred.
 type ParseError struct {
 	file string
 	err  string
@@ -86,7 +86,7 @@ func (e *ParseError) Error() (s string) {
 type lex struct {
 	token      string // text of the token
 	tokenUpper string // uppercase text of the token
-	length     int    // lenght 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
@@ -99,7 +99,7 @@ type lex struct {
 type Token struct {
 	// The scanned resource record when error is not nil.
 	RR
-	// When an error occured, this has the error specifics.
+	// 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
@@ -144,8 +144,10 @@ func ReadRR(q io.Reader, filename string) (RR, error) {
 //
 //	for x := range dns.ParseZone(strings.NewReader(z), "", "") {
 //		if x.Error != nil {
-//			// Do something with x.RR
-//		}
+//                  // log.Println(x.Error)
+//              } else {
+//                  // Do something with x.RR
+//              }
 //	}
 //
 // Comments specified after an RR (and on the same line!) are returned too:

+ 64 - 64
Godeps/_workspace/src/github.com/miekg/dns/zscan_rr.go

@@ -2203,68 +2203,68 @@ func setCAA(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
 }
 
 var typeToparserFunc = map[uint16]parserFunc{
-	TypeAAAA:       parserFunc{setAAAA, false},
-	TypeAFSDB:      parserFunc{setAFSDB, false},
-	TypeA:          parserFunc{setA, false},
-	TypeCAA:        parserFunc{setCAA, true},
-	TypeCDS:        parserFunc{setCDS, true},
-	TypeCDNSKEY:    parserFunc{setCDNSKEY, true},
-	TypeCERT:       parserFunc{setCERT, true},
-	TypeCNAME:      parserFunc{setCNAME, false},
-	TypeDHCID:      parserFunc{setDHCID, true},
-	TypeDLV:        parserFunc{setDLV, true},
-	TypeDNAME:      parserFunc{setDNAME, false},
-	TypeKEY:        parserFunc{setKEY, true},
-	TypeDNSKEY:     parserFunc{setDNSKEY, true},
-	TypeDS:         parserFunc{setDS, true},
-	TypeEID:        parserFunc{setEID, true},
-	TypeEUI48:      parserFunc{setEUI48, false},
-	TypeEUI64:      parserFunc{setEUI64, false},
-	TypeGID:        parserFunc{setGID, false},
-	TypeGPOS:       parserFunc{setGPOS, false},
-	TypeHINFO:      parserFunc{setHINFO, true},
-	TypeHIP:        parserFunc{setHIP, true},
-	TypeIPSECKEY:   parserFunc{setIPSECKEY, true},
-	TypeKX:         parserFunc{setKX, false},
-	TypeL32:        parserFunc{setL32, false},
-	TypeL64:        parserFunc{setL64, false},
-	TypeLOC:        parserFunc{setLOC, true},
-	TypeLP:         parserFunc{setLP, false},
-	TypeMB:         parserFunc{setMB, false},
-	TypeMD:         parserFunc{setMD, false},
-	TypeMF:         parserFunc{setMF, false},
-	TypeMG:         parserFunc{setMG, false},
-	TypeMINFO:      parserFunc{setMINFO, false},
-	TypeMR:         parserFunc{setMR, false},
-	TypeMX:         parserFunc{setMX, false},
-	TypeNAPTR:      parserFunc{setNAPTR, false},
-	TypeNID:        parserFunc{setNID, false},
-	TypeNIMLOC:     parserFunc{setNIMLOC, true},
-	TypeNINFO:      parserFunc{setNINFO, true},
-	TypeNSAPPTR:    parserFunc{setNSAPPTR, false},
-	TypeNSEC3PARAM: parserFunc{setNSEC3PARAM, false},
-	TypeNSEC3:      parserFunc{setNSEC3, true},
-	TypeNSEC:       parserFunc{setNSEC, true},
-	TypeNS:         parserFunc{setNS, false},
-	TypeOPENPGPKEY: parserFunc{setOPENPGPKEY, true},
-	TypePTR:        parserFunc{setPTR, false},
-	TypePX:         parserFunc{setPX, false},
-	TypeSIG:        parserFunc{setSIG, true},
-	TypeRKEY:       parserFunc{setRKEY, true},
-	TypeRP:         parserFunc{setRP, false},
-	TypeRRSIG:      parserFunc{setRRSIG, true},
-	TypeRT:         parserFunc{setRT, false},
-	TypeSOA:        parserFunc{setSOA, false},
-	TypeSPF:        parserFunc{setSPF, true},
-	TypeSRV:        parserFunc{setSRV, false},
-	TypeSSHFP:      parserFunc{setSSHFP, true},
-	TypeTALINK:     parserFunc{setTALINK, false},
-	TypeTA:         parserFunc{setTA, true},
-	TypeTLSA:       parserFunc{setTLSA, true},
-	TypeTXT:        parserFunc{setTXT, true},
-	TypeUID:        parserFunc{setUID, false},
-	TypeUINFO:      parserFunc{setUINFO, true},
-	TypeURI:        parserFunc{setURI, true},
-	TypeWKS:        parserFunc{setWKS, true},
-	TypeX25:        parserFunc{setX25, false},
+	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},
+	TypeIPSECKEY:   {setIPSECKEY, 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},
+	TypeWKS:        {setWKS, true},
+	TypeX25:        {setX25, false},
 }

+ 842 - 0
Godeps/_workspace/src/github.com/miekg/dns/ztypes.go

@@ -0,0 +1,842 @@
+// *** DO NOT MODIFY ***
+// AUTOGENERATED BY go generate
+
+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) },
+	TypeIPSECKEY:   func() RR { return new(IPSECKEY) },
+	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) },
+	TypeWKS:        func() RR { return new(WKS) },
+	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",
+	TypeIPSECKEY:   "IPSECKEY",
+	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",
+	TypeWKS:        "WKS",
+	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 *IPSECKEY) 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 *WKS) 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 *IPSECKEY) copy() RR {
+	return &IPSECKEY{*rr.Hdr.copyHeader(), rr.Precedence, rr.GatewayType, rr.Algorithm, copyIP(rr.GatewayA), copyIP(rr.GatewayAAAA), rr.GatewayName, rr.PublicKey}
+}
+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 *WKS) copy() RR {
+	BitMap := make([]uint16, len(rr.BitMap))
+	copy(BitMap, rr.BitMap)
+	return &WKS{*rr.Hdr.copyHeader(), copyIP(rr.Address), rr.Protocol, BitMap}
+}
+func (rr *X25) copy() RR {
+	return &X25{*rr.Hdr.copyHeader(), rr.PSDNAddress}
+}