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",
 			"ImportPath": "github.com/miekg/dns",
-			"Rev": "8395762c3490507cf5a27405fcd0e3d3dc547109"
+			"Rev": "b9171237b0642de1d8e8004f16869970e065f46b"
 		},
 		},
 		{
 		{
 			"ImportPath": "github.com/pborman/uuid",
 			"ImportPath": "github.com/pborman/uuid",

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

@@ -1,7 +1,7 @@
 language: go
 language: go
 sudo: false
 sudo: false
 go:
 go:
-  - 1.4
   - 1.5
   - 1.5
+  - 1.6
 script:
 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
 function for it. Server side and client side programming is supported, i.e. you
 can build servers and resolvers with it.
 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
 # 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/fcambus/rrda
 * https://github.com/kenshinx/godns
 * https://github.com/kenshinx/godns
 * https://github.com/skynetservices/skydns
 * https://github.com/skynetservices/skydns
+* https://github.com/hashicorp/consul
 * https://github.com/DevelopersPL/godnsagent
 * https://github.com/DevelopersPL/godnsagent
 * https://github.com/duedil-ltd/discodns
 * https://github.com/duedil-ltd/discodns
 * https://github.com/StalkR/dns-reverse-proxy
 * 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://play.google.com/store/apps/details?id=com.turbobytes.dig
 * https://github.com/fcambus/statzone
 * https://github.com/fcambus/statzone
 * https://github.com/benschw/dns-clb-go
 * 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.
 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;
 * EDNS0, NSID;
 * AXFR/IXFR;
 * AXFR/IXFR;
 * TSIG, SIG(0);
 * TSIG, SIG(0);
+* DNS over TLS: optional encrypted connection between client and server;
 * DNS name compression;
 * DNS name compression;
 * Depends only on the standard library.
 * Depends only on the standard library.
 
 
@@ -123,6 +130,7 @@ Example programs can be found in the `github.com/miekg/exdns` repository.
 * 6605 - ECDSA
 * 6605 - ECDSA
 * 6725 - IANA Registry Update
 * 6725 - IANA Registry Update
 * 6742 - ILNP DNS
 * 6742 - ILNP DNS
+* 6840 - Clarifications and Implementation Notes for DNS Security
 * 6844 - CAA record
 * 6844 - CAA record
 * 6891 - EDNS0 update
 * 6891 - EDNS0 update
 * 6895 - DNS IANA considerations
 * 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
 * 7314 - DNS (EDNS) EXPIRE Option
 * 7553 - URI record
 * 7553 - URI record
 * xxxx - EDNS0 DNS Update Lease (draft)
 * xxxx - EDNS0 DNS Update Lease (draft)
+* yyyy - DNS over TLS: Initiation and Performance Considerations (draft)
 
 
 ## Loosely based upon
 ## Loosely based upon
 
 

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

@@ -4,6 +4,7 @@ package dns
 
 
 import (
 import (
 	"bytes"
 	"bytes"
+	"crypto/tls"
 	"io"
 	"io"
 	"net"
 	"net"
 	"time"
 	"time"
@@ -24,8 +25,9 @@ type Conn struct {
 
 
 // A Client defines parameters for a DNS client.
 // A Client defines parameters for a DNS client.
 type Client struct {
 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
 	UDPSize        uint16            // minimum receive buffer for UDP messages
+	TLSConfig      *tls.Config       // TLS connection configuration
 	DialTimeout    time.Duration     // net.DialTimeout, defaults to 2 seconds
 	DialTimeout    time.Duration     // net.DialTimeout, defaults to 2 seconds
 	ReadTimeout    time.Duration     // net.Conn.SetReadTimeout value for connections, 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
 	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
 // 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
 // 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.
 // 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) {
 func Exchange(m *Msg, a string) (r *Msg, err error) {
 	var co *Conn
 	var co *Conn
 	co, err = DialTimeout("udp", a, dnsTimeout)
 	co, err = DialTimeout("udp", a, dnsTimeout)
@@ -53,8 +48,6 @@ func Exchange(m *Msg, a string) (r *Msg, err error) {
 	}
 	}
 
 
 	defer co.Close()
 	defer co.Close()
-	co.SetReadDeadline(time.Now().Add(dnsTimeout))
-	co.SetWriteDeadline(time.Now().Add(dnsTimeout))
 
 
 	opt := m.IsEdns0()
 	opt := m.IsEdns0()
 	// If EDNS0 is used use that for size.
 	// 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.UDPSize = opt.UDPSize()
 	}
 	}
 
 
+	co.SetWriteDeadline(time.Now().Add(dnsTimeout))
 	if err = co.WriteMsg(m); err != nil {
 	if err = co.WriteMsg(m); err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
+
+	co.SetReadDeadline(time.Now().Add(dnsTimeout))
 	r, err = co.ReadMsg()
 	r, err = co.ReadMsg()
 	if err == nil && r.Id != m.Id {
 	if err == nil && r.Id != m.Id {
 		err = ErrId
 		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
 // Exchange does not retry a failed query, nor will it fall back to TCP in
 // case of truncation.
 // 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) {
 func (c *Client) Exchange(m *Msg, a string) (r *Msg, rtt time.Duration, err error) {
 	if !c.SingleInflight {
 	if !c.SingleInflight {
 		return c.exchange(m, a)
 		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) {
 func (c *Client) exchange(m *Msg, a string) (r *Msg, rtt time.Duration, err error) {
 	var co *Conn
 	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 {
 	} else {
-		co, err = DialTimeout(c.Net, a, c.dialTimeout())
+		co, err = DialTimeout(network, a, c.dialTimeout())
 	}
 	}
+
 	if err != nil {
 	if err != nil {
 		return nil, 0, err
 		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.UDPSize = c.UDPSize
 	}
 	}
 
 
-	co.SetReadDeadline(time.Now().Add(c.readTimeout()))
-	co.SetWriteDeadline(time.Now().Add(c.writeTimeout()))
-
 	co.TsigSecret = c.TsigSecret
 	co.TsigSecret = c.TsigSecret
+	co.SetWriteDeadline(time.Now().Add(c.writeTimeout()))
 	if err = co.WriteMsg(m); err != nil {
 	if err = co.WriteMsg(m); err != nil {
 		return nil, 0, err
 		return nil, 0, err
 	}
 	}
+
+	co.SetReadDeadline(time.Now().Add(c.readTimeout()))
 	r, err = co.ReadMsg()
 	r, err = co.ReadMsg()
 	if err == nil && r.Id != m.Id {
 	if err == nil && r.Id != m.Id {
 		err = ErrId
 		err = ErrId
@@ -196,6 +216,12 @@ func (co *Conn) ReadMsg() (*Msg, error) {
 
 
 	m := new(Msg)
 	m := new(Msg)
 	if err := m.Unpack(p); err != nil {
 	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
 		return nil, err
 	}
 	}
 	if t := m.IsTsig(); t != nil {
 	if t := m.IsTsig(); t != nil {
@@ -218,21 +244,26 @@ func (co *Conn) ReadMsgHeader(hdr *Header) ([]byte, error) {
 		err 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.
 		// First two bytes specify the length of the entire message.
-		l, err := tcpMsgLen(t)
+		l, err := tcpMsgLen(r)
 		if err != nil {
 		if err != nil {
 			return nil, err
 			return nil, err
 		}
 		}
 		p = make([]byte, l)
 		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 {
 		if co.UDPSize > MinMsgSize {
 			p = make([]byte, co.UDPSize)
 			p = make([]byte, co.UDPSize)
 		} else {
 		} else {
 			p = make([]byte, MinMsgSize)
 			p = make([]byte, MinMsgSize)
 		}
 		}
 		n, err = co.Read(p)
 		n, err = co.Read(p)
+		co.rtt = time.Since(co.t)
 	}
 	}
 
 
 	if err != nil {
 	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.
 // 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}
 	p := []byte{0, 0}
 	n, err := t.Read(p)
 	n, err := t.Read(p)
 	if err != nil {
 	if err != nil {
@@ -268,7 +299,7 @@ func tcpMsgLen(t *net.TCPConn) (int, error) {
 }
 }
 
 
 // tcpRead calls TCPConn.Read enough times to fill allocated buffer.
 // 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)
 	n, err := t.Read(p)
 	if err != nil {
 	if err != nil {
 		return n, err
 		return n, err
@@ -291,27 +322,28 @@ func (co *Conn) Read(p []byte) (n int, err error) {
 	if len(p) < 2 {
 	if len(p) < 2 {
 		return 0, io.ErrShortBuffer
 		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 {
 		if err != nil {
 			return 0, err
 			return 0, err
 		}
 		}
 		if l > len(p) {
 		if l > len(p) {
 			return int(l), io.ErrShortBuffer
 			return int(l), io.ErrShortBuffer
 		}
 		}
-		return tcpRead(t, p[:l])
+		return tcpRead(r, p[:l])
 	}
 	}
 	// UDP connection
 	// UDP connection
 	n, err = co.Conn.Read(p)
 	n, err = co.Conn.Read(p)
 	if err != nil {
 	if err != nil {
 		return n, err
 		return n, err
 	}
 	}
-
-	co.rtt = time.Since(co.t)
 	return n, err
 	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
 // If the message m contains a TSIG record the transaction
 // signature is calculated.
 // signature is calculated.
 func (co *Conn) WriteMsg(m *Msg) (err error) {
 func (co *Conn) WriteMsg(m *Msg) (err error) {
@@ -322,7 +354,7 @@ func (co *Conn) WriteMsg(m *Msg) (err error) {
 			return ErrSecret
 			return ErrSecret
 		}
 		}
 		out, mac, err = TsigGenerate(m, co.TsigSecret[t.Hdr.Name], co.tsigRequestMAC, false)
 		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
 		co.tsigRequestMAC = mac
 	} else {
 	} else {
 		out, err = m.Pack()
 		out, err = m.Pack()
@@ -339,7 +371,10 @@ func (co *Conn) WriteMsg(m *Msg) (err error) {
 
 
 // Write implements the net.Conn Write method.
 // Write implements the net.Conn Write method.
 func (co *Conn) Write(p []byte) (n int, err error) {
 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)
 		lp := len(p)
 		if lp < 2 {
 		if lp < 2 {
 			return 0, io.ErrShortBuffer
 			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 := make([]byte, 2, lp+2)
 		l[0], l[1] = packUint16(uint16(lp))
 		l[0], l[1] = packUint16(uint16(lp))
 		p = append(l, p...)
 		p = append(l, p...)
-		n, err := io.Copy(t, bytes.NewReader(p))
+		n, err := io.Copy(w, bytes.NewReader(p))
 		return int(n), err
 		return int(n), err
 	}
 	}
 	n, err = co.Conn.(*net.UDPConn).Write(p)
 	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
 	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
 package dns
 
 
 import (
 import (
+	"crypto/tls"
+	"fmt"
+	"net"
 	"strconv"
 	"strconv"
 	"testing"
 	"testing"
 	"time"
 	"time"
@@ -12,7 +15,7 @@ func TestClientSync(t *testing.T) {
 
 
 	s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
 	s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
 	if err != nil {
 	if err != nil {
-		t.Fatalf("Unable to run test server: %v", err)
+		t.Fatalf("unable to run test server: %v", err)
 	}
 	}
 	defer s.Shutdown()
 	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) {
 func TestClientSyncBadId(t *testing.T) {
 	HandleFunc("miek.nl.", HelloServerBadId)
 	HandleFunc("miek.nl.", HelloServerBadId)
 	defer HandleRemove("miek.nl.")
 	defer HandleRemove("miek.nl.")
 
 
 	s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
 	s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
 	if err != nil {
 	if err != nil {
-		t.Fatalf("Unable to run test server: %v", err)
+		t.Fatalf("unable to run test server: %v", err)
 	}
 	}
 	defer s.Shutdown()
 	defer s.Shutdown()
 
 
@@ -66,7 +106,7 @@ func TestClientEDNS0(t *testing.T) {
 
 
 	s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
 	s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
 	if err != nil {
 	if err != nil {
-		t.Fatalf("Unable to run test server: %v", err)
+		t.Fatalf("unable to run test server: %v", err)
 	}
 	}
 	defer s.Shutdown()
 	defer s.Shutdown()
 
 
@@ -113,7 +153,7 @@ func TestClientEDNS0Local(t *testing.T) {
 
 
 	s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
 	s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
 	if err != nil {
 	if err != nil {
-		t.Fatalf("Unable to run test server: %s", err)
+		t.Fatalf("unable to run test server: %s", err)
 	}
 	}
 	defer s.Shutdown()
 	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 := new(Msg)
 	m.SetUpdate("t.local.ip6.io.")
 	m.SetUpdate("t.local.ip6.io.")
 	rr, _ := NewRR("t.local.ip6.io. 30 A 127.0.0.1")
 	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")
 	_, _, err := c.Exchange(m, "127.0.0.1:53")
 	if err != nil {
 	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
 	// This uses TCP just to make it slightly different than TestClientSync
 	s, addrstr, err := RunLocalTCPServer("127.0.0.1:0")
 	s, addrstr, err := RunLocalTCPServer("127.0.0.1:0")
 	if err != nil {
 	if err != nil {
-		t.Fatalf("Unable to run test server: %v", err)
+		t.Fatalf("unable to run test server: %v", err)
 	}
 	}
 	defer s.Shutdown()
 	defer s.Shutdown()
 
 
@@ -286,3 +276,146 @@ func TestClientConn(t *testing.T) {
 		t.Errorf("unable to unpack message fully: %v", err)
 		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) {
 func testConfig(t *testing.T, data string) {
 	tempDir, err := ioutil.TempDir("", "")
 	tempDir, err := ioutil.TempDir("", "")
 	if err != nil {
 	if err != nil {
-		t.Fatalf("TempDir: %v", err)
+		t.Fatalf("tempDir: %v", err)
 	}
 	}
 	defer os.RemoveAll(tempDir)
 	defer os.RemoveAll(tempDir)
 
 
 	path := filepath.Join(tempDir, "resolv.conf")
 	path := filepath.Join(tempDir, "resolv.conf")
 	if err := ioutil.WriteFile(path, []byte(data), 0644); err != nil {
 	if err := ioutil.WriteFile(path, []byte(data), 0644); err != nil {
-		t.Fatalf("WriteFile: %v", err)
+		t.Fatalf("writeFile: %v", err)
 	}
 	}
 	cc, err := ClientConfigFromFile(path)
 	cc, err := ClientConfigFromFile(path)
 	if err != nil {
 	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
 	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) {
 func IsDomainName(s string) (labels int, ok bool) {
 	_, labels, err := packDomainName(s, nil, 0, nil, false)
 	_, labels, err := packDomainName(s, nil, 0, nil, false)
 	return labels, err == nil
 	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) {
 func TestNoRdataPack(t *testing.T) {
 	data := make([]byte, 1024)
 	data := make([]byte, 1024)
-	for typ, fn := range typeToRR {
+	for typ, fn := range TypeToRR {
 		r := fn()
 		r := fn()
 		*r.Header() = RR_Header{Name: "miek.nl.", Rrtype: typ, Class: ClassINET, Ttl: 3600}
 		*r.Header() = RR_Header{Name: "miek.nl.", Rrtype: typ, Class: ClassINET, Ttl: 3600}
 		_, err := PackRR(r, data, 0, nil, false)
 		_, 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
 // TODO(miek): fix dns buffer too small errors this throws
 func TestNoRdataUnpack(t *testing.T) {
 func TestNoRdataUnpack(t *testing.T) {
 	data := make([]byte, 1024)
 	data := make([]byte, 1024)
-	for typ, fn := range typeToRR {
+	for typ, fn := range TypeToRR {
 		if typ == TypeSOA || typ == TypeTSIG || typ == TypeWKS {
 		if typ == TypeSOA || typ == TypeTSIG || typ == TypeWKS {
 			// SOA, TSIG will not be seen (like this) in dyn. updates?
 			// SOA, TSIG will not be seen (like this) in dyn. updates?
 			// WKS is an bug, but...deprecated record.
 			// 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 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).
 // the conversion (and re-use the pack/unpack functions).
 type rrsigWireFmt struct {
 type rrsigWireFmt struct {
 	TypeCovered uint16
 	TypeCovered uint16
@@ -248,13 +248,12 @@ func (d *DS) ToCDS() *CDS {
 	return c
 	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 {
 func (rr *RRSIG) Sign(k crypto.Signer, rrset []RR) error {
 	if k == nil {
 	if k == nil {
 		return ErrPrivKey
 		return ErrPrivKey
@@ -421,8 +420,8 @@ func (rr *RRSIG) Verify(k *DNSKEY, rrset []RR) error {
 
 
 	sigbuf := rr.sigBuf()           // Get the binary signature data
 	sigbuf := rr.sigBuf()           // Get the binary signature data
 	if rr.Algorithm == PRIVATEDNS { // PRIVATEOID
 	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]
 	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,
 		//   NS, MD, MF, CNAME, SOA, MB, MG, MR, PTR,
 		//   HINFO, MINFO, MX, RP, AFSDB, RT, SIG, PX, NXT, NAPTR, KX,
 		//   HINFO, MINFO, MX, RP, AFSDB, RT, SIG, PX, NXT, NAPTR, KX,
 		//   SRV, DNAME, A6
 		//   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) {
 		switch x := r1.(type) {
 		case *NS:
 		case *NS:
 			x.Ns = strings.ToLower(x.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.Weight = 800
 	srv.Target = "web1.miek.nl."
 	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
 	// With this key
 	key := new(DNSKEY)
 	key := new(DNSKEY)
 	key.Hdr.Rrtype = TypeDNSKEY
 	key.Hdr.Rrtype = TypeDNSKEY
@@ -194,12 +205,12 @@ func TestSignVerify(t *testing.T) {
 	sig.SignerName = key.Hdr.Name
 	sig.SignerName = key.Hdr.Name
 	sig.Algorithm = RSASHA256
 	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
 			continue
 		}
 		}
-		if sig.Verify(key, []RR{r}) != nil {
+		if err := sig.Verify(key, []RR{r}); err != nil {
 			t.Error("failure to validate")
 			t.Error("failure to validate")
 			continue
 			continue
 		}
 		}
@@ -451,7 +462,7 @@ PrivateKey: WURgWHCcYIYUPWgeLmiPY2DJJk02vgrmTfitxgqcL4vwW7BOrbawVmVe0d9V94SR`
 	}
 	}
 
 
 	if err := sig.Verify(eckey.(*DNSKEY), []RR{a}); err != nil {
 	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(),
 			eckey.(*DNSKEY).String(),
 			a.String(),
 			a.String(),
 			sig.String(),
 			sig.String(),
@@ -500,7 +511,7 @@ func TestSignVerifyECDSA2(t *testing.T) {
 
 
 	err = sig.Verify(key, []RR{srv})
 	err = sig.Verify(key, []RR{srv})
 	if err != nil {
 	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(),
 			key.String(),
 			srv.String(),
 			srv.String(),
 			sig.String(),
 			sig.String(),
@@ -554,7 +565,7 @@ PrivateKey: GU6SnQ/Ou+xC5RumuIUIuJZteXT2z0O/ok1s38Et6mQ=`
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
 	if err = rrRRSIG.(*RRSIG).Verify(rrDNSKEY.(*DNSKEY), []RR{rrA}); err != nil {
 	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{
 	ourRRSIG := &RRSIG{
@@ -573,7 +584,7 @@ PrivateKey: GU6SnQ/Ou+xC5RumuIUIuJZteXT2z0O/ok1s38Et6mQ=`
 	}
 	}
 
 
 	if err = ourRRSIG.Verify(rrDNSKEY.(*DNSKEY), []RR{rrA}); err != nil {
 	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
 	// Signatures are randomized
@@ -630,7 +641,7 @@ PrivateKey: WURgWHCcYIYUPWgeLmiPY2DJJk02vgrmTfitxgqcL4vwW7BOrbawVmVe0d9V94SR`
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
 	if err = rrRRSIG.(*RRSIG).Verify(rrDNSKEY.(*DNSKEY), []RR{rrA}); err != nil {
 	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{
 	ourRRSIG := &RRSIG{
@@ -649,7 +660,7 @@ PrivateKey: WURgWHCcYIYUPWgeLmiPY2DJJk02vgrmTfitxgqcL4vwW7BOrbawVmVe0d9V94SR`
 	}
 	}
 
 
 	if err = ourRRSIG.Verify(rrDNSKEY.(*DNSKEY), []RR{rrA}); err != nil {
 	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
 	// 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.
 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
 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 := new(dns.Msg)
      m.SetEdns0(4096, true)
      m.SetEdns0(4096, true)
@@ -184,9 +184,9 @@ Basic use pattern validating and replying to a message that has TSIG set.
 	dns.HandleFunc(".", handleRequest)
 	dns.HandleFunc(".", handleRequest)
 
 
 	func handleRequest(w dns.ResponseWriter, r *dns.Msg) {
 	func handleRequest(w dns.ResponseWriter, r *dns.Msg) {
-		m := new(Msg)
+		m := new(dns.Msg)
 		m.SetReply(r)
 		m.SetReply(r)
-		if r.IsTsig() {
+		if r.IsTsig() != nil {
 			if w.TsigStatus() == nil {
 			if w.TsigStatus() == nil {
 				// *Msg r has an TSIG record and it was validated
 				// *Msg r has an TSIG record and it was validated
 				m.SetTsig("axfr.", dns.HmacMD5, 300, time.Now().Unix())
 				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"`
 	Option []EDNS0 `dns:"opt"`
 }
 }
 
 
-// Header implements the RR interface.
-func (rr *OPT) Header() *RR_Header {
-	return &rr.Hdr
-}
-
 func (rr *OPT) String() string {
 func (rr *OPT) String() string {
 	s := "\n;; OPT PSEUDOSECTION:\n; EDNS: version " + strconv.Itoa(int(rr.Version())) + "; "
 	s := "\n;; OPT PSEUDOSECTION:\n; EDNS: version " + strconv.Itoa(int(rr.Version())) + "; "
 	if rr.Do() {
 	if rr.Do() {
@@ -88,10 +83,6 @@ func (rr *OPT) len() int {
 	return l
 	return l
 }
 }
 
 
-func (rr *OPT) copy() RR {
-	return &OPT{*rr.Hdr.copyHeader(), rr.Option}
-}
-
 // return the old value -> delete SetVersion?
 // return the old value -> delete SetVersion?
 
 
 // Version returns the EDNS version used. Only zero is defined.
 // 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 (
 import (
 	"errors"
 	"errors"
 	"fmt"
 	"fmt"
-	"github.com/abh/geodns/Godeps/_workspace/src/github.com/miekg/dns"
 	"log"
 	"log"
 	"net"
 	"net"
+
+	"github.com/abh/geodns/Godeps/_workspace/src/github.com/miekg/dns"
 )
 )
 
 
 // Retrieve the MX records for miek.nl.
 // Retrieve the MX records for miek.nl.
@@ -31,13 +32,11 @@ func ExampleMX() {
 
 
 // Retrieve the DNSKEY records of a zone and convert them
 // Retrieve the DNSKEY records of a zone and convert them
 // to DS records for SHA1, SHA256 and SHA384.
 // to DS records for SHA1, SHA256 and SHA384.
-func ExampleDS(zone string) {
+func ExampleDS() {
 	config, _ := dns.ClientConfigFromFile("/etc/resolv.conf")
 	config, _ := dns.ClientConfigFromFile("/etc/resolv.conf")
 	c := new(dns.Client)
 	c := new(dns.Client)
 	m := new(dns.Msg)
 	m := new(dns.Msg)
-	if zone == "" {
-		zone = "miek.nl"
-	}
+	zone := "miek.nl"
 	m.SetQuestion(dns.Fqdn(zone), dns.TypeDNSKEY)
 	m.SetQuestion(dns.Fqdn(zone), dns.TypeDNSKEY)
 	m.SetEdns0(4096, true)
 	m.SetEdns0(4096, true)
 	r, _, err := c.Exchange(m, config.Servers[0]+":"+config.Port)
 	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
 			return true
 		}
 		}
 	}
 	}
-	panic("dns: not reached")
 }
 }
 
 
 // encode transforms Unicode input bytes (that represent DNS label) into
 // 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.
 // 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"}
+// .www.miek.nl. returns []string{"", "www", "miek", "nl"},
 // The root label (.) returns nil. Note that using
 // The root label (.) returns nil. Note that using
 // strings.Split(s) will work in most cases, but does not handle
 // strings.Split(s) will work in most cases, but does not handle
 // escaped dots (\.) for instance.
 // escaped dots (\.) for instance.
+// s must be a syntactically valid domain name, see IsDomainName.
 func SplitDomainName(s string) (labels []string) {
 func SplitDomainName(s string) (labels []string) {
 	if len(s) == 0 {
 	if len(s) == 0 {
 		return nil
 		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 miek.nl. have two labels in common: miek and nl
 // www.miek.nl. and www.bla.nl. have one label in common: 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) {
 func CompareDomainName(s1, s2 string) (n int) {
 	s1 = Fqdn(s1)
 	s1 = Fqdn(s1)
 	s2 = Fqdn(s2)
 	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.
 // 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) {
 func CountLabel(s string) (labels int) {
 	if s == "." {
 	if s == "." {
 		return
 		return
@@ -102,7 +107,8 @@ func CountLabel(s string) (labels int) {
 
 
 // Split splits a name s into its label indexes.
 // 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}.
 // 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 {
 func Split(s string) []int {
 	if s == "." {
 	if s == "." {
 		return nil
 		return nil

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

@@ -1,8 +1,6 @@
 package dns
 package dns
 
 
-import (
-	"testing"
-)
+import "testing"
 
 
 func TestCompareDomainName(t *testing.T) {
 func TestCompareDomainName(t *testing.T) {
 	s1 := "www.miek.nl."
 	s1 := "www.miek.nl."
@@ -61,9 +59,9 @@ func TestSplit(t *testing.T) {
 
 
 func TestSplit2(t *testing.T) {
 func TestSplit2(t *testing.T) {
 	splitter := map[string][]int{
 	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 {
 	for s, i := range splitter {
 		x := Split(s)
 		x := Split(s)
@@ -125,13 +123,14 @@ func TestCountLabel(t *testing.T) {
 
 
 func TestSplitDomainName(t *testing.T) {
 func TestSplitDomainName(t *testing.T) {
 	labels := map[string][]string{
 	labels := map[string][]string{
-		"miek.nl":       []string{"miek", "nl"},
+		"miek.nl":       {"miek", "nl"},
 		".":             nil,
 		".":             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:
 domainLoop:
 	for domain, splits := range labels {
 	for domain, splits := range labels {
@@ -155,13 +154,13 @@ func TestIsDomainName(t *testing.T) {
 		lab int
 		lab int
 	}
 	}
 	names := map[string]*ret{
 	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 {
 	for d, ok := range names {
 		l, k := IsDomainName(d)
 		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"}
 	ErrSoa error = &Error{err: "no SOA"}
 	// ErrTime indicates a timing error in TSIG authentication.
 	// ErrTime indicates a timing error in TSIG authentication.
 	ErrTime error = &Error{err: "bad time"}
 	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
 // 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.
 	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.
 // StringToType is the reverse of TypeToString, needed for string parsing.
 var StringToType = reverseInt16(TypeToString)
 var StringToType = reverseInt16(TypeToString)
 
 
@@ -332,7 +257,7 @@ func packDomainName(s string, msg []byte, off int, compression map[string]int, c
 				roBs = string(bs)
 				roBs = string(bs)
 				bsFresh = true
 				bsFresh = true
 			}
 			}
-			// Dont try to compress '.'
+			// Don't try to compress '.'
 			if compress && roBs[begin:] != "." {
 			if compress && roBs[begin:] != "." {
 				if p, ok := compression[roBs[begin:]]; !ok {
 				if p, ok := compression[roBs[begin:]]; !ok {
 					// Only offsets smaller than this can be used.
 					// 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
 						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
 					break
 				}
 				}
 				s, off, err = UnpackDomainName(msg, off)
 				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)
 	end := off + int(h.Rdlength)
 	// make an rr of that type and re-unpack.
 	// make an rr of that type and re-unpack.
-	mk, known := typeToRR[h.Rrtype]
+	mk, known := TypeToRR[h.Rrtype]
 	if !known {
 	if !known {
 		rr = new(RFC3597)
 		rr = new(RFC3597)
 	} else {
 	} else {
@@ -1474,6 +1399,32 @@ func UnpackRR(msg []byte, off int) (rr RR, off1 int, err error) {
 	return rr, off, err
 	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
 // Reverse a map
 func reverseInt8(m map[uint8]string) map[string]uint8 {
 func reverseInt8(m map[uint8]string) map[string]uint8 {
 	n := make(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.CheckingDisabled = (dh.Bits & _CD) != 0
 	dns.Rcode = int(dh.Bits & 0xF)
 	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
 	var q Question
 	for i := 0; i < int(dh.Qdcount); i++ {
 	for i := 0; i < int(dh.Qdcount); i++ {
 		off1 := off
 		off1 := off
 		off, err = UnpackStruct(&q, msg, off)
 		off, err = UnpackStruct(&q, msg, off)
 		if err != nil {
 		if err != nil {
+			// Even if Truncated is set, we only will set ErrTruncated if we
+			// actually got the questions
 			return err
 			return err
 		}
 		}
 		if off1 == off { // Offset does not increase anymore, dh.Qdcount is a lie!
 		if off1 == off { // Offset does not increase anymore, dh.Qdcount is a lie!
 			dh.Qdcount = uint16(i)
 			dh.Qdcount = uint16(i)
 			break
 			break
 		}
 		}
-
 		dns.Question = append(dns.Question, q)
 		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) {
 	if off != len(msg) {
 		// TODO(miek) make this an error?
 		// TODO(miek) make this an error?
 		// use PackOpt to let people tell how detailed the error reporting should be?
 		// use PackOpt to let people tell how detailed the error reporting should be?
 		// println("dns: extra bytes in dns packet", off, "<", len(msg))
 		// 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.
 // 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 {
 	for _, s := range test {
 		rr, err := NewRR(fmt.Sprintf("example.com. IN TXT %v", s[0]))
 		rr, err := NewRR(fmt.Sprintf("example.com. IN TXT %v", s[0]))
 		if err != nil {
 		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
 			continue
 		}
 		}
 
 
 		txt := sprintTxt(rr.(*TXT).Txt)
 		txt := sprintTxt(rr.(*TXT).Txt)
 		if txt != s[1] {
 		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))
 	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 .
 	zone := `$ORIGIN .
 $TTL 3600       ; 1 hour
 $TTL 3600       ; 1 hour
 name                    IN SOA  a6.nstld.com. hostmaster.nic.name. (
 name                    IN SOA  a6.nstld.com. hostmaster.nic.name. (
@@ -768,7 +768,7 @@ func TestRfc1982(t *testing.T) {
 }
 }
 
 
 func TestEmpty(t *testing.T) {
 func TestEmpty(t *testing.T) {
-	for _ = range ParseZone(strings.NewReader(""), "", "") {
+	for range ParseZone(strings.NewReader(""), "", "") {
 		t.Errorf("should be empty")
 		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
 	// 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"
 	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.", "")
 	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.")
 		t.Skip("skipping test in short mode.")
 	}
 	}
 	algorithms := []algorithm{
 	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 {
 	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 {
 func mkPrivateRR(rrtype uint16) *PrivateRR {
 	// Panics if RR is not an instance of PrivateRR.
 	// Panics if RR is not an instance of PrivateRR.
-	rrfunc, ok := typeToRR[rrtype]
+	rrfunc, ok := TypeToRR[rrtype]
 	if !ok {
 	if !ok {
 		panic(fmt.Sprintf("dns: invalid operation with Private RR type %d", rrtype))
 		panic(fmt.Sprintf("dns: invalid operation with Private RR type %d", rrtype))
 	}
 	}
@@ -43,7 +43,7 @@ func mkPrivateRR(rrtype uint16) *PrivateRR {
 	case *PrivateRR:
 	case *PrivateRR:
 		return rr
 		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.
 // 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) {
 func PrivateHandle(rtypestr string, rtype uint16, generator func() PrivateRdata) {
 	rtypestr = strings.ToUpper(rtypestr)
 	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
 	TypeToString[rtype] = rtypestr
 	StringToType[rtypestr] = rtype
 	StringToType[rtypestr] = rtype
 
 
@@ -108,7 +108,7 @@ func PrivateHandle(rtypestr string, rtype uint16, generator func() PrivateRdata)
 func PrivateHandleRemove(rtype uint16) {
 func PrivateHandleRemove(rtype uint16) {
 	rtypestr, ok := TypeToString[rtype]
 	rtypestr, ok := TypeToString[rtype]
 	if ok {
 	if ok {
-		delete(typeToRR, rtype)
+		delete(TypeToRR, rtype)
 		delete(TypeToString, rtype)
 		delete(TypeToString, rtype)
 		delete(typeToparserFunc, rtype)
 		delete(typeToparserFunc, rtype)
 		delete(StringToType, rtypestr)
 		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 {
 	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 {
 	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 {
 	} else {
 		t.Log(rr1.String())
 		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
 	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 {
 func rawSetAnswerLen(msg []byte, i uint16) bool {
 	if len(msg) < 8 {
 	if len(msg) < 8 {
 		return false
 		return false
@@ -30,7 +30,7 @@ func rawSetAnswerLen(msg []byte, i uint16) bool {
 	return true
 	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 {
 func rawSetNsLen(msg []byte, i uint16) bool {
 	if len(msg) < 10 {
 	if len(msg) < 10 {
 		return false
 		return false
@@ -39,7 +39,7 @@ func rawSetNsLen(msg []byte, i uint16) bool {
 	return true
 	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 {
 func rawSetExtraLen(msg []byte, i uint16) bool {
 	if len(msg) < 12 {
 	if len(msg) < 12 {
 		return false
 		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"),
 			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{
 		[...]RR{
 			newRR(t, "miEk.nl. 2000 IN A 127.0.0.1"),
 			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. 1000 IN A 127.0.0.1"),
 			newRR(t, "Miek.nL. 500 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{
 		[...]RR{
 			newRR(t, "miek.nl. IN A 127.0.0.1"),
 			newRR(t, "miek.nl. IN A 127.0.0.1"),
 			newRR(t, "miek.nl. CH 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"),
 			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",
 			"miek.nl.\t3600\tCH\tA\t127.0.0.1",
 		},
 		},
 		[...]RR{
 		[...]RR{
 			newRR(t, "miek.nl. CH 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"),
 			newRR(t, "miek.nl. IN A 127.0.0.1"),
 			newRR(t, "miek.de. 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.nl.\t3600\tIN\tA\t127.0.0.1",
 			"miek.de.\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.de. IN A 127.0.0.1"),
 			newRR(t, "miek.nl. 200 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"),
 			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",
 			"miek.nl.\t200\tIN\tA\t127.0.0.1",
 		},
 		},
 	}
 	}
@@ -57,7 +57,7 @@ func BenchmarkDedup(b *testing.B) {
 	}
 	}
 	m := make(map[string]RR)
 	m := make(map[string]RR)
 	for i := 0; i < b.N; i++ {
 	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 (
 import (
 	"bytes"
 	"bytes"
+	"crypto/tls"
 	"io"
 	"io"
 	"net"
 	"net"
 	"sync"
 	"sync"
@@ -47,7 +48,7 @@ type response struct {
 	tsigRequestMAC string
 	tsigRequestMAC string
 	tsigSecret     map[string]string // the tsig secrets
 	tsigSecret     map[string]string // the tsig secrets
 	udp            *net.UDPConn      // i/o connection if UDP was used
 	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
 	udpSession     *SessionUDP       // oob data to get egress interface right
 	remoteAddr     net.Addr          // address of the client
 	remoteAddr     net.Addr          // address of the client
 	writer         Writer            // writer to output the raw DNS bits
 	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) }
 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.
 // for incoming queries.
 func ListenAndServe(addr string, network string, handler Handler) error {
 func ListenAndServe(addr string, network string, handler Handler) error {
 	server := &Server{Addr: addr, Net: network, Handler: handler}
 	server := &Server{Addr: addr, Net: network, Handler: handler}
 	return server.ListenAndServe()
 	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,
 // ActivateAndServe activates a server with a listener from systemd,
 // l and p should not both be non-nil.
 // l and p should not both be non-nil.
 // If both l and p are not nil only p will be used.
 // If both l and p are not nil only p will be used.
@@ -210,7 +233,7 @@ type Writer interface {
 type Reader interface {
 type Reader interface {
 	// ReadTCP reads a raw message from a TCP connection. Implementations may alter
 	// ReadTCP reads a raw message from a TCP connection. Implementations may alter
 	// connection properties, for example the read-deadline.
 	// 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
 	// ReadUDP reads a raw message from a UDP connection. Implementations may alter
 	// connection properties, for example the read-deadline.
 	// connection properties, for example the read-deadline.
 	ReadUDP(conn *net.UDPConn, timeout time.Duration) ([]byte, *SessionUDP, error)
 	ReadUDP(conn *net.UDPConn, timeout time.Duration) ([]byte, *SessionUDP, error)
@@ -222,7 +245,7 @@ type defaultReader struct {
 	*Server
 	*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)
 	return dr.readTCP(conn, timeout)
 }
 }
 
 
@@ -242,10 +265,12 @@ type DecorateWriter func(Writer) Writer
 type Server struct {
 type Server struct {
 	// Address to listen on, ":dns" if empty.
 	// Address to listen on, ":dns" if empty.
 	Addr string
 	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
 	Net string
 	// TCP Listener to use, this is to aid in systemd's socket activation.
 	// TCP Listener to use, this is to aid in systemd's socket activation.
 	Listener net.Listener
 	Listener net.Listener
+	// TLS connection configuration
+	TLSConfig *tls.Config
 	// UDP "Listener" to use, this is to aid in systemd's socket activation.
 	// UDP "Listener" to use, this is to aid in systemd's socket activation.
 	PacketConn net.PacketConn
 	PacketConn net.PacketConn
 	// Handler to invoke, dns.DefaultServeMux if nil.
 	// Handler to invoke, dns.DefaultServeMux if nil.
@@ -262,7 +287,7 @@ type Server struct {
 	// Secret(s) for Tsig map[<zonename>]<base64 secret>.
 	// Secret(s) for Tsig map[<zonename>]<base64 secret>.
 	TsigSecret map[string]string
 	TsigSecret map[string]string
 	// Unsafe instructs the server to disregard any sanity checks and directly hand the message to
 	// 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
 	Unsafe bool
 	// If NotifyStartedFunc is set it is called once the server has started listening.
 	// If NotifyStartedFunc is set it is called once the server has started listening.
 	NotifyStartedFunc func()
 	NotifyStartedFunc func()
@@ -271,26 +296,21 @@ type Server struct {
 	// DecorateWriter is optional, allows customization of the process that writes raw DNS messages.
 	// DecorateWriter is optional, allows customization of the process that writes raw DNS messages.
 	DecorateWriter DecorateWriter
 	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
 	started bool
 }
 }
 
 
 // ListenAndServe starts a nameserver on the configured address in *Server.
 // ListenAndServe starts a nameserver on the configured address in *Server.
 func (srv *Server) ListenAndServe() error {
 func (srv *Server) ListenAndServe() error {
 	srv.lock.Lock()
 	srv.lock.Lock()
+	defer srv.lock.Unlock()
 	if srv.started {
 	if srv.started {
-		srv.lock.Unlock()
 		return &Error{err: "server already started"}
 		return &Error{err: "server already started"}
 	}
 	}
-	srv.stopUDP, srv.stopTCP = make(chan bool), make(chan bool)
-	srv.started = true
 	addr := srv.Addr
 	addr := srv.Addr
 	if addr == "" {
 	if addr == "" {
 		addr = ":domain"
 		addr = ":domain"
@@ -309,8 +329,29 @@ func (srv *Server) ListenAndServe() error {
 			return e
 			return e
 		}
 		}
 		srv.Listener = l
 		srv.Listener = l
+		srv.started = true
 		srv.lock.Unlock()
 		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":
 	case "udp", "udp4", "udp6":
 		a, e := net.ResolveUDPAddr(srv.Net, addr)
 		a, e := net.ResolveUDPAddr(srv.Net, addr)
 		if e != nil {
 		if e != nil {
@@ -324,10 +365,12 @@ func (srv *Server) ListenAndServe() error {
 			return e
 			return e
 		}
 		}
 		srv.PacketConn = l
 		srv.PacketConn = l
+		srv.started = true
 		srv.lock.Unlock()
 		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"}
 	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.
 // configured in *Server. Its main use is to start a server from systemd.
 func (srv *Server) ActivateAndServe() error {
 func (srv *Server) ActivateAndServe() error {
 	srv.lock.Lock()
 	srv.lock.Lock()
+	defer srv.lock.Unlock()
 	if srv.started {
 	if srv.started {
-		srv.lock.Unlock()
 		return &Error{err: "server already started"}
 		return &Error{err: "server already started"}
 	}
 	}
-	srv.stopUDP, srv.stopTCP = make(chan bool), make(chan bool)
-	srv.started = true
 	pConn := srv.PacketConn
 	pConn := srv.PacketConn
 	l := srv.Listener
 	l := srv.Listener
-	srv.lock.Unlock()
 	if pConn != nil {
 	if pConn != nil {
 		if srv.UDPSize == 0 {
 		if srv.UDPSize == 0 {
 			srv.UDPSize = MinMsgSize
 			srv.UDPSize = MinMsgSize
@@ -352,13 +392,19 @@ func (srv *Server) ActivateAndServe() error {
 			if e := setUDPSocketOptions(t); e != nil {
 			if e := setUDPSocketOptions(t); e != nil {
 				return e
 				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 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"}
 	return &Error{err: "bad listeners"}
 }
 }
@@ -374,36 +420,20 @@ func (srv *Server) Shutdown() error {
 		return &Error{err: "server not started"}
 		return &Error{err: "server not started"}
 	}
 	}
 	srv.started = false
 	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()
 	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 {
 	select {
 	case <-time.After(srv.getReadTimeout()):
 	case <-time.After(srv.getReadTimeout()):
@@ -424,7 +454,7 @@ func (srv *Server) getReadTimeout() time.Duration {
 
 
 // serveTCP starts a TCP listener for the server.
 // serveTCP starts a TCP listener for the server.
 // Each request is handled in a separate goroutine.
 // 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()
 	defer l.Close()
 
 
 	if srv.NotifyStartedFunc != nil {
 	if srv.NotifyStartedFunc != nil {
@@ -443,20 +473,24 @@ func (srv *Server) serveTCP(l *net.TCPListener) error {
 	rtimeout := srv.getReadTimeout()
 	rtimeout := srv.getReadTimeout()
 	// deadline is not used here
 	// deadline is not used here
 	for {
 	for {
-		rw, e := l.AcceptTCP()
+		rw, e := l.Accept()
 		if e != nil {
 		if e != nil {
-			continue
+			if neterr, ok := e.(net.Error); ok && neterr.Temporary() {
+				continue
+			}
+			return e
 		}
 		}
 		m, e := reader.ReadTCP(rw, rtimeout)
 		m, e := reader.ReadTCP(rw, rtimeout)
-		select {
-		case <-srv.stopTCP:
+		srv.lock.RLock()
+		if !srv.started {
+			srv.lock.RUnlock()
 			return nil
 			return nil
-		default:
 		}
 		}
+		srv.lock.RUnlock()
 		if e != nil {
 		if e != nil {
 			continue
 			continue
 		}
 		}
-		srv.wgTCP.Add(1)
+		srv.inFlight.Add(1)
 		go srv.serve(rw.RemoteAddr(), handler, m, nil, nil, rw)
 		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
 	// deadline is not used here
 	for {
 	for {
 		m, s, e := reader.ReadUDP(l, rtimeout)
 		m, s, e := reader.ReadUDP(l, rtimeout)
-		select {
-		case <-srv.stopUDP:
+		srv.lock.RLock()
+		if !srv.started {
+			srv.lock.RUnlock()
 			return nil
 			return nil
-		default:
 		}
 		}
+		srv.lock.RUnlock()
 		if e != nil {
 		if e != nil {
 			continue
 			continue
 		}
 		}
-		srv.wgUDP.Add(1)
+		srv.inFlight.Add(1)
 		go srv.serve(s.RemoteAddr(), handler, m, l, s, nil)
 		go srv.serve(s.RemoteAddr(), handler, m, l, s, nil)
 	}
 	}
 }
 }
 
 
 // Serve a new connection.
 // 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}
 	w := &response{tsigSecret: srv.TsigSecret, udp: u, tcp: t, remoteAddr: a, udpSession: s}
 	if srv.DecorateWriter != nil {
 	if srv.DecorateWriter != nil {
 		w.writer = srv.DecorateWriter(w)
 		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
 	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})
 	reader := Reader(&defaultReader{srv})
 	if srv.DecorateReader != nil {
 	if srv.DecorateReader != nil {
 		reader = srv.DecorateReader(reader)
 		reader = srv.DecorateReader(reader)
@@ -548,6 +576,9 @@ Redo:
 	h.ServeDNS(w, req) // Writes back to the client
 	h.ServeDNS(w, req) // Writes back to the client
 
 
 Exit:
 Exit:
+	if w.tcp == nil {
+		return
+	}
 	// TODO(miek): make this number configurable?
 	// TODO(miek): make this number configurable?
 	if q > maxTCPQueries { // close socket after this many queries
 	if q > maxTCPQueries { // close socket after this many queries
 		w.Close()
 		w.Close()
@@ -574,7 +605,7 @@ Exit:
 	return
 	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))
 	conn.SetReadDeadline(time.Now().Add(timeout))
 	l := make([]byte, 2)
 	l := make([]byte, 2)
 	n, err := conn.Read(l)
 	n, err := conn.Read(l)

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

@@ -1,11 +1,14 @@
 package dns
 package dns
 
 
 import (
 import (
+	"crypto/tls"
 	"fmt"
 	"fmt"
+	"io"
 	"net"
 	"net"
 	"runtime"
 	"runtime"
 	"sync"
 	"sync"
 	"testing"
 	"testing"
+	"time"
 )
 )
 
 
 func HelloServer(w ResponseWriter, req *Msg) {
 func HelloServer(w ResponseWriter, req *Msg) {
@@ -37,23 +40,32 @@ func AnotherHelloServer(w ResponseWriter, req *Msg) {
 }
 }
 
 
 func RunLocalUDPServer(laddr string) (*Server, string, error) {
 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)
 	pc, err := net.ListenPacket("udp", laddr)
 	if err != nil {
 	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 := sync.Mutex{}
 	waitLock.Lock()
 	waitLock.Lock()
 	server.NotifyStartedFunc = waitLock.Unlock
 	server.NotifyStartedFunc = waitLock.Unlock
 
 
+	fin := make(chan struct{}, 0)
+
 	go func() {
 	go func() {
 		server.ActivateAndServe()
 		server.ActivateAndServe()
+		close(fin)
 		pc.Close()
 		pc.Close()
 	}()
 	}()
 
 
 	waitLock.Lock()
 	waitLock.Lock()
-	return server, pc.LocalAddr().String(), nil
+	return server, pc.LocalAddr().String(), fin, nil
 }
 }
 
 
 func RunLocalUDPServerUnsafe(laddr string) (*Server, string, error) {
 func RunLocalUDPServerUnsafe(laddr string) (*Server, string, error) {
@@ -61,7 +73,8 @@ func RunLocalUDPServerUnsafe(laddr string) (*Server, string, error) {
 	if err != nil {
 	if err != nil {
 		return nil, "", err
 		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 := sync.Mutex{}
 	waitLock.Lock()
 	waitLock.Lock()
@@ -82,7 +95,28 @@ func RunLocalTCPServer(laddr string) (*Server, string, error) {
 		return nil, "", err
 		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 := sync.Mutex{}
 	waitLock.Lock()
 	waitLock.Lock()
@@ -105,7 +139,7 @@ func TestServing(t *testing.T) {
 
 
 	s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
 	s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
 	if err != nil {
 	if err != nil {
-		t.Fatalf("Unable to run test server: %v", err)
+		t.Fatalf("unable to run test server: %v", err)
 	}
 	}
 	defer s.Shutdown()
 	defer s.Shutdown()
 
 
@@ -118,7 +152,7 @@ func TestServing(t *testing.T) {
 	}
 	}
 	txt := r.Extra[0].(*TXT).Txt[0]
 	txt := r.Extra[0].(*TXT).Txt[0]
 	if txt != "Hello world" {
 	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)
 	m.SetQuestion("example.com.", TypeTXT)
@@ -128,7 +162,7 @@ func TestServing(t *testing.T) {
 	}
 	}
 	txt = r.Extra[0].(*TXT).Txt[0]
 	txt = r.Extra[0].(*TXT).Txt[0]
 	if txt != "Hello example" {
 	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.
 	// Test Mixes cased as noticed by Ask.
@@ -139,7 +173,67 @@ func TestServing(t *testing.T) {
 	}
 	}
 	txt = r.Extra[0].(*TXT).Txt[0]
 	txt = r.Extra[0].(*TXT).Txt[0]
 	if txt != "Hello example" {
 	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")
 	s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
 	if err != nil {
 	if err != nil {
-		b.Fatalf("Unable to run test server: %v", err)
+		b.Fatalf("unable to run test server: %v", err)
 	}
 	}
 	defer s.Shutdown()
 	defer s.Shutdown()
 
 
@@ -173,7 +267,7 @@ func benchmarkServe6(b *testing.B) {
 	a := runtime.GOMAXPROCS(4)
 	a := runtime.GOMAXPROCS(4)
 	s, addrstr, err := RunLocalUDPServer("[::1]:0")
 	s, addrstr, err := RunLocalUDPServer("[::1]:0")
 	if err != nil {
 	if err != nil {
-		b.Fatalf("Unable to run test server: %v", err)
+		b.Fatalf("unable to run test server: %v", err)
 	}
 	}
 	defer s.Shutdown()
 	defer s.Shutdown()
 
 
@@ -204,7 +298,7 @@ func BenchmarkServeCompress(b *testing.B) {
 	a := runtime.GOMAXPROCS(4)
 	a := runtime.GOMAXPROCS(4)
 	s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
 	s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
 	if err != nil {
 	if err != nil {
-		b.Fatalf("Unable to run test server: %v", err)
+		b.Fatalf("unable to run test server: %v", err)
 	}
 	}
 	defer s.Shutdown()
 	defer s.Shutdown()
 
 
@@ -305,7 +399,7 @@ func TestServingLargeResponses(t *testing.T) {
 
 
 	s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
 	s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
 	if err != nil {
 	if err != nil {
-		t.Fatalf("Unable to run test server: %v", err)
+		t.Fatalf("unable to run test server: %v", err)
 	}
 	}
 	defer s.Shutdown()
 	defer s.Shutdown()
 
 
@@ -345,7 +439,7 @@ func TestServingResponse(t *testing.T) {
 	HandleFunc("miek.nl.", HelloServer)
 	HandleFunc("miek.nl.", HelloServer)
 	s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
 	s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
 	if err != nil {
 	if err != nil {
-		t.Fatalf("Unable to run test server: %v", err)
+		t.Fatalf("unable to run test server: %v", err)
 	}
 	}
 
 
 	c := new(Client)
 	c := new(Client)
@@ -365,7 +459,7 @@ func TestServingResponse(t *testing.T) {
 	s.Shutdown()
 	s.Shutdown()
 	s, addrstr, err = RunLocalUDPServerUnsafe("127.0.0.1:0")
 	s, addrstr, err = RunLocalUDPServerUnsafe("127.0.0.1:0")
 	if err != nil {
 	if err != nil {
-		t.Fatalf("Unable to run test server: %v", err)
+		t.Fatalf("unable to run test server: %v", err)
 	}
 	}
 	defer s.Shutdown()
 	defer s.Shutdown()
 
 
@@ -379,22 +473,104 @@ func TestServingResponse(t *testing.T) {
 func TestShutdownTCP(t *testing.T) {
 func TestShutdownTCP(t *testing.T) {
 	s, _, err := RunLocalTCPServer("127.0.0.1:0")
 	s, _, err := RunLocalTCPServer("127.0.0.1:0")
 	if err != nil {
 	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()
 	err = s.Shutdown()
 	if err != nil {
 	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) {
 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 {
 	if err != nil {
-		t.Fatalf("Unable to run test server: %v", err)
+		t.Fatalf("unable to run test server: %v", err)
 	}
 	}
 	err = s.Shutdown()
 	err = s.Shutdown()
 	if err != nil {
 	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{
 	server := &Server{
 		PacketConn:     pc,
 		PacketConn:     pc,
 		DecorateWriter: wf,
 		DecorateWriter: wf,
+		ReadTimeout:    time.Hour, WriteTimeout: time.Hour,
 	}
 	}
 
 
 	waitLock := sync.Mutex{}
 	waitLock := sync.Mutex{}
@@ -448,3 +625,55 @@ func ExampleDecorateWriter() {
 	}
 	}
 	// Output: writing raw DNS message of length 56
 	// 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)
 		pk, err := keyrr.Generate(keysize)
 		if err != nil {
 		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
 			continue
 		}
 		}
 		now := uint32(time.Now().Unix())
 		now := uint32(time.Now().Unix())
@@ -43,16 +43,16 @@ func TestSIG0(t *testing.T) {
 		sigrr.SignerName = keyrr.Hdr.Name
 		sigrr.SignerName = keyrr.Hdr.Name
 		mb, err := sigrr.Sign(pk.(crypto.Signer), m)
 		mb, err := sigrr.Sign(pk.(crypto.Signer), m)
 		if err != nil {
 		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
 			continue
 		}
 		}
 		m := new(Msg)
 		m := new(Msg)
 		if err := m.Unpack(mb); err != nil {
 		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
 			continue
 		}
 		}
 		if len(m.Extra) != 1 {
 		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
 			continue
 		}
 		}
 		var sigrrwire *SIG
 		var sigrrwire *SIG
@@ -60,7 +60,7 @@ func TestSIG0(t *testing.T) {
 		case *SIG:
 		case *SIG:
 			sigrrwire = rr
 			sigrrwire = rr
 		default:
 		default:
-			t.Errorf("Expected SIG RR, instead: %v", rr)
+			t.Errorf("expected SIG RR, instead: %v", rr)
 			continue
 			continue
 		}
 		}
 		for _, rr := range []*SIG{sigrr, sigrrwire} {
 		for _, rr := range []*SIG{sigrr, sigrrwire} {
@@ -69,20 +69,20 @@ func TestSIG0(t *testing.T) {
 				id = "sigrrwire"
 				id = "sigrrwire"
 			}
 			}
 			if err := rr.Verify(keyrr, mb); err != nil {
 			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
 				continue
 			}
 			}
 		}
 		}
 		mb[13]++
 		mb[13]++
 		if err := sigrr.Verify(keyrr, mb); err == nil {
 		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
 			continue
 		}
 		}
 		sigrr.Expiration = 2
 		sigrr.Expiration = 2
 		sigrr.Inception = 1
 		sigrr.Inception = 1
 		mb, _ = sigrr.Sign(pk.(crypto.Signer), m)
 		mb, _ = sigrr.Sign(pk.(crypto.Signer), m)
 		if err := sigrr.Verify(keyrr, mb); err == nil {
 		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
 			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 {
 	if e != nil {
 		return "", e
 		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"`
 	OtherData  string `dns:"size-hex"`
 }
 }
 
 
-func (rr *TSIG) Header() *RR_Header {
-	return &rr.Hdr
-}
-
 // TSIG has no official presentation format, but this will suffice.
 // TSIG has no official presentation format, but this will suffice.
 
 
 func (rr *TSIG) String() string {
 func (rr *TSIG) String() string {
@@ -58,15 +54,6 @@ func (rr *TSIG) String() string {
 	return s
 	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.
 // The following values must be put in wireformat, so that the MAC can be calculated.
 // RFC 2845, section 3.4.2. TSIG Variables.
 // RFC 2845, section 3.4.2. TSIG Variables.
 type tsigWireFmt struct {
 type tsigWireFmt struct {
@@ -125,7 +112,7 @@ func TsigGenerate(m *Msg, secret, requestMAC string, timersOnly bool) ([]byte, s
 
 
 	t := new(TSIG)
 	t := new(TSIG)
 	var h hash.Hash
 	var h hash.Hash
-	switch rr.Algorithm {
+	switch strings.ToLower(rr.Algorithm) {
 	case HmacMD5:
 	case HmacMD5:
 		h = hmac.New(md5.New, []byte(rawsecret))
 		h = hmac.New(md5.New, []byte(rawsecret))
 	case HmacSHA1:
 	case HmacSHA1:
@@ -191,7 +178,7 @@ func TsigVerify(msg []byte, secret, requestMAC string, timersOnly bool) error {
 	}
 	}
 
 
 	var h hash.Hash
 	var h hash.Hash
-	switch tsig.Algorithm {
+	switch strings.ToLower(tsig.Algorithm) {
 	case HmacMD5:
 	case HmacMD5:
 		h = hmac.New(md5.New, rawsecret)
 		h = hmac.New(md5.New, rawsecret)
 	case HmacSHA1:
 	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.
 // StringToCertType is the reverseof CertTypeToString.
 var StringToCertType = reverseInt16(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 holds a DNS question. There can be multiple questions in the
 // question section of a message. Usually there is just one.
 // question section of a message. Usually there is just one.
 type Question struct {
 type Question struct {
@@ -214,6 +216,10 @@ type Question struct {
 	Qclass uint16
 	Qclass uint16
 }
 }
 
 
+func (q *Question) len() int {
+	return len(q.Name) + 1 + 2 + 2
+}
+
 func (q *Question) String() (s string) {
 func (q *Question) String() (s string) {
 	// prefix with ; (as in dig)
 	// prefix with ; (as in dig)
 	s = ";" + sprintName(q.Name) + "\t"
 	s = ";" + sprintName(q.Name) + "\t"
@@ -222,11 +228,6 @@ func (q *Question) String() (s string) {
 	return s
 	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
 // ANY is a wildcard record. See RFC 1035, Section 3.2.3. ANY
 // is named "*" there.
 // is named "*" there.
 type ANY struct {
 type ANY struct {
@@ -234,20 +235,14 @@ type ANY struct {
 	// Does not have any rdata
 	// 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 {
 type CNAME struct {
 	Hdr    RR_Header
 	Hdr    RR_Header
 	Target string `dns:"cdomain-name"`
 	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 {
 type HINFO struct {
 	Hdr RR_Header
 	Hdr RR_Header
@@ -255,33 +250,23 @@ type HINFO struct {
 	Os  string
 	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 {
 func (rr *HINFO) String() string {
 	return rr.Hdr.String() + sprintTxt([]string{rr.Cpu, rr.Os})
 	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 {
 type MB struct {
 	Hdr RR_Header
 	Hdr RR_Header
 	Mb  string `dns:"cdomain-name"`
 	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 {
 type MG struct {
 	Hdr RR_Header
 	Hdr RR_Header
 	Mg  string `dns:"cdomain-name"`
 	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 {
 type MINFO struct {
 	Hdr   RR_Header
 	Hdr   RR_Header
@@ -289,28 +274,15 @@ type MINFO struct {
 	Email string `dns:"cdomain-name"`
 	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 {
 func (rr *MINFO) String() string {
 	return rr.Hdr.String() + sprintName(rr.Rmail) + " " + sprintName(rr.Email)
 	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 {
 type MR struct {
 	Hdr RR_Header
 	Hdr RR_Header
 	Mr  string `dns:"cdomain-name"`
 	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 {
 func (rr *MR) String() string {
 	return rr.Hdr.String() + sprintName(rr.Mr)
 	return rr.Hdr.String() + sprintName(rr.Mr)
 }
 }
@@ -320,10 +292,6 @@ type MF struct {
 	Mf  string `dns:"cdomain-name"`
 	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 {
 func (rr *MF) String() string {
 	return rr.Hdr.String() + sprintName(rr.Mf)
 	return rr.Hdr.String() + sprintName(rr.Mf)
 }
 }
@@ -333,10 +301,6 @@ type MD struct {
 	Md  string `dns:"cdomain-name"`
 	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 {
 func (rr *MD) String() string {
 	return rr.Hdr.String() + sprintName(rr.Md)
 	return rr.Hdr.String() + sprintName(rr.Md)
 }
 }
@@ -347,10 +311,6 @@ type MX struct {
 	Mx         string `dns:"cdomain-name"`
 	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 {
 func (rr *MX) String() string {
 	return rr.Hdr.String() + strconv.Itoa(int(rr.Preference)) + " " + sprintName(rr.Mx)
 	return rr.Hdr.String() + strconv.Itoa(int(rr.Preference)) + " " + sprintName(rr.Mx)
 }
 }
@@ -361,10 +321,6 @@ type AFSDB struct {
 	Hostname string `dns:"cdomain-name"`
 	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 {
 func (rr *AFSDB) String() string {
 	return rr.Hdr.String() + strconv.Itoa(int(rr.Subtype)) + " " + sprintName(rr.Hostname)
 	return rr.Hdr.String() + strconv.Itoa(int(rr.Subtype)) + " " + sprintName(rr.Hostname)
 }
 }
@@ -374,10 +330,6 @@ type X25 struct {
 	PSDNAddress string
 	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 {
 func (rr *X25) String() string {
 	return rr.Hdr.String() + rr.PSDNAddress
 	return rr.Hdr.String() + rr.PSDNAddress
 }
 }
@@ -388,10 +340,6 @@ type RT struct {
 	Host       string `dns:"cdomain-name"`
 	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 {
 func (rr *RT) String() string {
 	return rr.Hdr.String() + strconv.Itoa(int(rr.Preference)) + " " + sprintName(rr.Host)
 	return rr.Hdr.String() + strconv.Itoa(int(rr.Preference)) + " " + sprintName(rr.Host)
 }
 }
@@ -401,10 +349,6 @@ type NS struct {
 	Ns  string `dns:"cdomain-name"`
 	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 {
 func (rr *NS) String() string {
 	return rr.Hdr.String() + sprintName(rr.Ns)
 	return rr.Hdr.String() + sprintName(rr.Ns)
 }
 }
@@ -414,10 +358,6 @@ type PTR struct {
 	Ptr string `dns:"cdomain-name"`
 	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 {
 func (rr *PTR) String() string {
 	return rr.Hdr.String() + sprintName(rr.Ptr)
 	return rr.Hdr.String() + sprintName(rr.Ptr)
 }
 }
@@ -428,10 +368,6 @@ type RP struct {
 	Txt  string `dns:"domain-name"`
 	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 {
 func (rr *RP) String() string {
 	return rr.Hdr.String() + rr.Mbox + " " + sprintTxt([]string{rr.Txt})
 	return rr.Hdr.String() + rr.Mbox + " " + sprintTxt([]string{rr.Txt})
 }
 }
@@ -447,11 +383,6 @@ type SOA struct {
 	Minttl  uint32
 	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 {
 func (rr *SOA) String() string {
 	return rr.Hdr.String() + sprintName(rr.Ns) + " " + sprintName(rr.Mbox) +
 	return rr.Hdr.String() + sprintName(rr.Ns) + " " + sprintName(rr.Mbox) +
 		" " + strconv.FormatInt(int64(rr.Serial), 10) +
 		" " + strconv.FormatInt(int64(rr.Serial), 10) +
@@ -461,24 +392,11 @@ func (rr *SOA) String() string {
 		" " + strconv.FormatInt(int64(rr.Minttl), 10)
 		" " + 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 {
 type TXT struct {
 	Hdr RR_Header
 	Hdr RR_Header
 	Txt []string `dns:"txt"`
 	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 (rr *TXT) String() string { return rr.Hdr.String() + sprintTxt(rr.Txt) }
 
 
 func sprintName(s string) string {
 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 {
 type SPF struct {
 	Hdr RR_Header
 	Hdr RR_Header
 	Txt []string `dns:"txt"`
 	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) 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 {
 type SRV struct {
 	Hdr      RR_Header
 	Hdr      RR_Header
 	Priority uint16
 	Priority uint16
@@ -659,12 +554,6 @@ type SRV struct {
 	Target   string `dns:"domain-name"`
 	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 {
 func (rr *SRV) String() string {
 	return rr.Hdr.String() +
 	return rr.Hdr.String() +
 		strconv.Itoa(int(rr.Priority)) + " " +
 		strconv.Itoa(int(rr.Priority)) + " " +
@@ -682,11 +571,6 @@ type NAPTR struct {
 	Replacement string `dns:"domain-name"`
 	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 {
 func (rr *NAPTR) String() string {
 	return rr.Hdr.String() +
 	return rr.Hdr.String() +
 		strconv.Itoa(int(rr.Order)) + " " +
 		strconv.Itoa(int(rr.Order)) + " " +
@@ -697,11 +581,6 @@ func (rr *NAPTR) String() string {
 		rr.Replacement
 		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.
 // The CERT resource record, see RFC 4398.
 type CERT struct {
 type CERT struct {
 	Hdr         RR_Header
 	Hdr         RR_Header
@@ -711,11 +590,6 @@ type CERT struct {
 	Certificate string `dns:"base64"`
 	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 {
 func (rr *CERT) String() string {
 	var (
 	var (
 		ok                  bool
 		ok                  bool
@@ -733,21 +607,12 @@ func (rr *CERT) String() string {
 		" " + rr.Certificate
 		" " + 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.
 // The DNAME resource record, see RFC 2672.
 type DNAME struct {
 type DNAME struct {
 	Hdr    RR_Header
 	Hdr    RR_Header
 	Target string `dns:"domain-name"`
 	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 {
 func (rr *DNAME) String() string {
 	return rr.Hdr.String() + sprintName(rr.Target)
 	return rr.Hdr.String() + sprintName(rr.Target)
 }
 }
@@ -757,10 +622,6 @@ type A struct {
 	A   net.IP `dns:"a"`
 	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 {
 func (rr *A) String() string {
 	if rr.A == nil {
 	if rr.A == nil {
 		return rr.Hdr.String()
 		return rr.Hdr.String()
@@ -773,10 +634,6 @@ type AAAA struct {
 	AAAA net.IP `dns:"aaaa"`
 	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 {
 func (rr *AAAA) String() string {
 	if rr.AAAA == nil {
 	if rr.AAAA == nil {
 		return rr.Hdr.String()
 		return rr.Hdr.String()
@@ -791,12 +648,9 @@ type PX struct {
 	Mapx400    string `dns:"domain-name"`
 	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 {
 func (rr *PX) String() string {
 	return rr.Hdr.String() + strconv.Itoa(int(rr.Preference)) + " " + sprintName(rr.Map822) + " " + sprintName(rr.Mapx400)
 	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 {
 type GPOS struct {
 	Hdr       RR_Header
 	Hdr       RR_Header
@@ -805,11 +659,6 @@ type GPOS struct {
 	Altitude  string
 	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 {
 func (rr *GPOS) String() string {
 	return rr.Hdr.String() + rr.Longitude + " " + rr.Latitude + " " + rr.Altitude
 	return rr.Hdr.String() + rr.Longitude + " " + rr.Latitude + " " + rr.Altitude
 }
 }
@@ -825,12 +674,6 @@ type LOC struct {
 	Altitude  uint32
 	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
 // cmToM takes a cm value expressed in RFC1876 SIZE mantissa/exponent
 // format and returns a string in m (two decimals for the cm)
 // format and returns a string in m (two decimals for the cm)
 func cmToM(m, e uint8) string {
 func cmToM(m, e uint8) string {
@@ -914,11 +757,6 @@ type RRSIG struct {
 	Signature   string `dns:"base64"`
 	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 {
 func (rr *RRSIG) String() string {
 	s := rr.Hdr.String()
 	s := rr.Hdr.String()
 	s += Type(rr.TypeCovered).String()
 	s += Type(rr.TypeCovered).String()
@@ -933,24 +771,12 @@ func (rr *RRSIG) String() string {
 	return s
 	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 {
 type NSEC struct {
 	Hdr        RR_Header
 	Hdr        RR_Header
 	NextDomain string   `dns:"domain-name"`
 	NextDomain string   `dns:"domain-name"`
 	TypeBitMap []uint16 `dns:"nsec"`
 	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 {
 func (rr *NSEC) String() string {
 	s := rr.Hdr.String() + sprintName(rr.NextDomain)
 	s := rr.Hdr.String() + sprintName(rr.NextDomain)
 	for i := 0; i < len(rr.TypeBitMap); i++ {
 	for i := 0; i < len(rr.TypeBitMap); i++ {
@@ -988,12 +814,6 @@ type DS struct {
 	Digest     string `dns:"hex"`
 	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 {
 func (rr *DS) String() string {
 	return rr.Hdr.String() + strconv.Itoa(int(rr.KeyTag)) +
 	return rr.Hdr.String() + strconv.Itoa(int(rr.KeyTag)) +
 		" " + strconv.Itoa(int(rr.Algorithm)) +
 		" " + strconv.Itoa(int(rr.Algorithm)) +
@@ -1007,10 +827,6 @@ type KX struct {
 	Exchanger  string `dns:"domain-name"`
 	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 {
 func (rr *KX) String() string {
 	return rr.Hdr.String() + strconv.Itoa(int(rr.Preference)) +
 	return rr.Hdr.String() + strconv.Itoa(int(rr.Preference)) +
 		" " + sprintName(rr.Exchanger)
 		" " + sprintName(rr.Exchanger)
@@ -1024,12 +840,6 @@ type TA struct {
 	Digest     string `dns:"hex"`
 	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 {
 func (rr *TA) String() string {
 	return rr.Hdr.String() + strconv.Itoa(int(rr.KeyTag)) +
 	return rr.Hdr.String() + strconv.Itoa(int(rr.KeyTag)) +
 		" " + strconv.Itoa(int(rr.Algorithm)) +
 		" " + strconv.Itoa(int(rr.Algorithm)) +
@@ -1043,10 +853,6 @@ type TALINK struct {
 	NextName     string `dns:"domain-name"`
 	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 {
 func (rr *TALINK) String() string {
 	return rr.Hdr.String() +
 	return rr.Hdr.String() +
 		sprintName(rr.PreviousName) + " " + sprintName(rr.NextName)
 		sprintName(rr.PreviousName) + " " + sprintName(rr.NextName)
@@ -1059,12 +865,6 @@ type SSHFP struct {
 	FingerPrint string `dns:"hex"`
 	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 {
 func (rr *SSHFP) String() string {
 	return rr.Hdr.String() + strconv.Itoa(int(rr.Algorithm)) +
 	return rr.Hdr.String() + strconv.Itoa(int(rr.Algorithm)) +
 		" " + strconv.Itoa(int(rr.Type)) +
 		" " + strconv.Itoa(int(rr.Type)) +
@@ -1085,11 +885,6 @@ type IPSECKEY struct {
 	PublicKey   string `dns:"base64"`
 	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 {
 func (rr *IPSECKEY) String() string {
 	s := rr.Hdr.String() + strconv.Itoa(int(rr.Precedence)) +
 	s := rr.Hdr.String() + strconv.Itoa(int(rr.Precedence)) +
 		" " + strconv.Itoa(int(rr.GatewayType)) +
 		" " + strconv.Itoa(int(rr.GatewayType)) +
@@ -1143,14 +938,6 @@ type DNSKEY struct {
 	PublicKey string `dns:"base64"`
 	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 {
 func (rr *DNSKEY) String() string {
 	return rr.Hdr.String() + strconv.Itoa(int(rr.Flags)) +
 	return rr.Hdr.String() + strconv.Itoa(int(rr.Flags)) +
 		" " + strconv.Itoa(int(rr.Protocol)) +
 		" " + strconv.Itoa(int(rr.Protocol)) +
@@ -1166,12 +953,6 @@ type RKEY struct {
 	PublicKey string `dns:"base64"`
 	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 {
 func (rr *RKEY) String() string {
 	return rr.Hdr.String() + strconv.Itoa(int(rr.Flags)) +
 	return rr.Hdr.String() + strconv.Itoa(int(rr.Flags)) +
 		" " + strconv.Itoa(int(rr.Protocol)) +
 		" " + strconv.Itoa(int(rr.Protocol)) +
@@ -1184,10 +965,7 @@ type NSAPPTR struct {
 	Ptr string `dns:"domain-name"`
 	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 {
 type NSEC3 struct {
 	Hdr        RR_Header
 	Hdr        RR_Header
@@ -1201,13 +979,6 @@ type NSEC3 struct {
 	TypeBitMap []uint16 `dns:"nsec"`
 	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 {
 func (rr *NSEC3) String() string {
 	s := rr.Hdr.String()
 	s := rr.Hdr.String()
 	s += strconv.Itoa(int(rr.Hash)) +
 	s += strconv.Itoa(int(rr.Hash)) +
@@ -1243,12 +1014,6 @@ type NSEC3PARAM struct {
 	Salt       string `dns:"hex"`
 	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 {
 func (rr *NSEC3PARAM) String() string {
 	s := rr.Hdr.String()
 	s := rr.Hdr.String()
 	s += strconv.Itoa(int(rr.Hash)) +
 	s += strconv.Itoa(int(rr.Hash)) +
@@ -1271,31 +1036,17 @@ type TKEY struct {
 	OtherData  string
 	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 {
 func (rr *TKEY) String() string {
 	// It has no presentation format
 	// It has no presentation format
 	return ""
 	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.
 // RFC3597 represents an unknown/generic RR.
 type RFC3597 struct {
 type RFC3597 struct {
 	Hdr   RR_Header
 	Hdr   RR_Header
 	Rdata string `dns:"hex"`
 	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 {
 func (rr *RFC3597) String() string {
 	// Let's call it a hack
 	// Let's call it a hack
 	s := rfc3597Header(rr.Hdr)
 	s := rfc3597Header(rr.Hdr)
@@ -1321,9 +1072,6 @@ type URI struct {
 	Target   string `dns:"octet"`
 	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 {
 func (rr *URI) String() string {
 	return rr.Hdr.String() + strconv.Itoa(int(rr.Priority)) +
 	return rr.Hdr.String() + strconv.Itoa(int(rr.Priority)) +
 		" " + strconv.Itoa(int(rr.Weight)) + " " + sprintTxtOctet(rr.Target)
 		" " + strconv.Itoa(int(rr.Weight)) + " " + sprintTxtOctet(rr.Target)
@@ -1334,10 +1082,7 @@ type DHCID struct {
 	Digest string `dns:"base64"`
 	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 {
 type TLSA struct {
 	Hdr          RR_Header
 	Hdr          RR_Header
@@ -1347,13 +1092,6 @@ type TLSA struct {
 	Certificate  string `dns:"hex"`
 	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 {
 func (rr *TLSA) String() string {
 	return rr.Hdr.String() +
 	return rr.Hdr.String() +
 		strconv.Itoa(int(rr.Usage)) +
 		strconv.Itoa(int(rr.Usage)) +
@@ -1372,13 +1110,6 @@ type HIP struct {
 	RendezvousServers  []string `dns:"domain-name"`
 	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 {
 func (rr *HIP) String() string {
 	s := rr.Hdr.String() +
 	s := rr.Hdr.String() +
 		strconv.Itoa(int(rr.PublicKeyAlgorithm)) +
 		strconv.Itoa(int(rr.PublicKeyAlgorithm)) +
@@ -1390,38 +1121,13 @@ func (rr *HIP) String() string {
 	return s
 	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 {
 type NINFO struct {
 	Hdr    RR_Header
 	Hdr    RR_Header
 	ZSData []string `dns:"txt"`
 	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) 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 {
 type WKS struct {
 	Hdr      RR_Header
 	Hdr      RR_Header
 	Address  net.IP `dns:"a"`
 	Address  net.IP `dns:"a"`
@@ -1429,13 +1135,9 @@ type WKS struct {
 	BitMap   []uint16 `dns:"wks"`
 	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) {
 func (rr *WKS) String() (s string) {
@@ -1457,10 +1159,6 @@ type NID struct {
 	NodeID     uint64
 	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 {
 func (rr *NID) String() string {
 	s := rr.Hdr.String() + strconv.Itoa(int(rr.Preference))
 	s := rr.Hdr.String() + strconv.Itoa(int(rr.Preference))
 	node := fmt.Sprintf("%0.16x", rr.NodeID)
 	node := fmt.Sprintf("%0.16x", rr.NodeID)
@@ -1474,10 +1172,6 @@ type L32 struct {
 	Locator32  net.IP `dns:"a"`
 	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 {
 func (rr *L32) String() string {
 	if rr.Locator32 == nil {
 	if rr.Locator32 == nil {
 		return rr.Hdr.String() + strconv.Itoa(int(rr.Preference))
 		return rr.Hdr.String() + strconv.Itoa(int(rr.Preference))
@@ -1492,10 +1186,6 @@ type L64 struct {
 	Locator64  uint64
 	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 {
 func (rr *L64) String() string {
 	s := rr.Hdr.String() + strconv.Itoa(int(rr.Preference))
 	s := rr.Hdr.String() + strconv.Itoa(int(rr.Preference))
 	node := fmt.Sprintf("%0.16X", rr.Locator64)
 	node := fmt.Sprintf("%0.16X", rr.Locator64)
@@ -1509,10 +1199,6 @@ type LP struct {
 	Fqdn       string `dns:"domain-name"`
 	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 {
 func (rr *LP) String() string {
 	return rr.Hdr.String() + strconv.Itoa(int(rr.Preference)) + " " + sprintName(rr.Fqdn)
 	return rr.Hdr.String() + strconv.Itoa(int(rr.Preference)) + " " + sprintName(rr.Fqdn)
 }
 }
@@ -1522,20 +1208,14 @@ type EUI48 struct {
 	Address uint64 `dns:"uint48"`
 	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 {
 type EUI64 struct {
 	Hdr     RR_Header
 	Hdr     RR_Header
 	Address uint64
 	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 {
 type CAA struct {
 	Hdr   RR_Header
 	Hdr   RR_Header
@@ -1544,9 +1224,6 @@ type CAA struct {
 	Value string `dns:"octet"`
 	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 {
 func (rr *CAA) String() string {
 	return rr.Hdr.String() + strconv.Itoa(int(rr.Flag)) + " " + rr.Tag + " " + sprintTxtOctet(rr.Value)
 	return rr.Hdr.String() + strconv.Itoa(int(rr.Flag)) + " " + rr.Tag + " " + sprintTxtOctet(rr.Value)
 }
 }
@@ -1556,62 +1233,42 @@ type UID struct {
 	Uid uint32
 	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 {
 type GID struct {
 	Hdr RR_Header
 	Hdr RR_Header
 	Gid uint32
 	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 {
 type UINFO struct {
 	Hdr   RR_Header
 	Hdr   RR_Header
 	Uinfo string
 	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 {
 type EID struct {
 	Hdr      RR_Header
 	Hdr      RR_Header
 	Endpoint string `dns:"hex"`
 	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 {
 type NIMLOC struct {
 	Hdr     RR_Header
 	Hdr     RR_Header
 	Locator string `dns:"hex"`
 	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 {
 type OPENPGPKEY struct {
 	Hdr       RR_Header
 	Hdr       RR_Header
 	PublicKey string `dns:"base64"`
 	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
 // TimeToString translates the RRSIG's incep. and expir. times to the
 // string representation used when printing the record.
 // string representation used when printing the record.
@@ -1669,73 +1326,3 @@ func copyIP(ip net.IP) net.IP {
 	copy(p, ip)
 	copy(p, ip)
 	return p
 	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 {
 	if err := syscall.SetsockoptInt(int(file.Fd()), syscall.IPPROTO_IP, syscall.IP_PKTINFO, 1); err != nil {
 		return err
 		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
 	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 {
 	if err := syscall.SetsockoptInt(int(file.Fd()), syscall.IPPROTO_IPV6, syscall.IPV6_RECVPKTINFO, 1); err != nil {
 		return err
 		return err
 	}
 	}
+	err = syscall.SetNonblock(int(file.Fd()), true)
+	if err != nil {
+		return err
+	}
 	return nil
 	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
 // NameUsed sets the RRs in the prereq section to
 // "Name is in use" RRs. RFC 2136 section 2.4.4.
 // "Name is in use" RRs. RFC 2136 section 2.4.4.
 func (u *Msg) NameUsed(rr []RR) {
 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
 // NameNotUsed sets the RRs in the prereq section to
 // "Name is in not use" RRs. RFC 2136 section 2.4.5.
 // "Name is in not use" RRs. RFC 2136 section 2.4.5.
 func (u *Msg) NameNotUsed(rr []RR) {
 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 {
 	if len(u.Question) == 0 {
 		panic("dns: empty question section")
 		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
 // RRsetUsed sets the RRs in the prereq section to
 // "RRset exists (value independent -- no rdata)" RRs. RFC 2136 section 2.4.1.
 // "RRset exists (value independent -- no rdata)" RRs. RFC 2136 section 2.4.1.
 func (u *Msg) RRsetUsed(rr []RR) {
 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
 // RRsetNotUsed sets the RRs in the prereq section to
 // "RRset does not exist" RRs. RFC 2136 section 2.4.3.
 // "RRset does not exist" RRs. RFC 2136 section 2.4.3.
 func (u *Msg) RRsetNotUsed(rr []RR) {
 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 {
 	if len(u.Question) == 0 {
 		panic("dns: empty question section")
 		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.
 // RemoveRRset creates a dynamic update packet that deletes an RRset, see RFC 2136 section 2.5.2.
 func (u *Msg) RemoveRRset(rr []RR) {
 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
 // 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) {
 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) {
 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 "
 	prefix := "example.com. IN "
 	for _, typ := range TypeToString {
 	for _, typ := range TypeToString {
 		if typ == "OPT" || typ == "AXFR" || typ == "IXFR" || typ == "ANY" || typ == "TKEY" ||
 		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
 			continue
 		}
 		}
 		r, err := NewRR(prefix + typ)
 		r, err := NewRR(prefix + typ)
@@ -57,28 +58,88 @@ func TestRemoveRRset(t *testing.T) {
 	// for each set mentioned in the RRs provided to it.
 	// for each set mentioned in the RRs provided to it.
 	rr, err := NewRR(". 100 IN A 127.0.0.1")
 	rr, err := NewRR(". 100 IN A 127.0.0.1")
 	if err != nil {
 	if err != nil {
-		t.Fatalf("Error constructing RR: %v", err)
+		t.Fatalf("error constructing RR: %v", err)
 	}
 	}
 	m := new(Msg)
 	m := new(Msg)
 	m.Ns = []RR{&RR_Header{Name: ".", Rrtype: TypeA, Class: ClassANY, Ttl: 0, Rdlength: 0}}
 	m.Ns = []RR{&RR_Header{Name: ".", Rrtype: TypeA, Class: ClassANY, Ttl: 0, Rdlength: 0}}
 	expectstr := m.String()
 	expectstr := m.String()
 	expect, err := m.Pack()
 	expect, err := m.Pack()
 	if err != nil {
 	if err != nil {
-		t.Fatalf("Error packing expected msg: %v", err)
+		t.Fatalf("error packing expected msg: %v", err)
 	}
 	}
 
 
 	m.Ns = nil
 	m.Ns = nil
 	m.RemoveRRset([]RR{rr})
 	m.RemoveRRset([]RR{rr})
 	actual, err := m.Pack()
 	actual, err := m.Pack()
 	if err != nil {
 	if err != nil {
-		t.Fatalf("Error packing actual msg: %v", err)
+		t.Fatalf("error packing actual msg: %v", err)
 	}
 	}
 	if !bytes.Equal(actual, expect) {
 	if !bytes.Equal(actual, expect) {
 		tmp := new(Msg)
 		tmp := new(Msg)
 		if err := tmp.Unpack(actual); err != nil {
 		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
 // Think we need to away to stop the transfer
 
 
 // In performs an incoming transfer with the server in a.
 // 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) {
 func (t *Transfer) In(q *Msg, a string) (env chan *Envelope, err error) {
 	timeout := dnsTimeout
 	timeout := dnsTimeout
 	if t.DialTimeout != 0 {
 	if t.DialTimeout != 0 {
 		timeout = t.DialTimeout
 		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 {
 	if err := t.WriteMsg(q); err != nil {
 		return nil, err
 		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)
 	tr := new(Transfer)
 	if a, err := tr.In(m, net.JoinHostPort(server, "53")); err != nil {
 	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 {
 	} else {
 		for ex := range a {
 		for ex := range a {
 			if ex.Error != nil {
 			if ex.Error != nil {
-				t.Errorf("Error %v", ex.Error)
+				t.Errorf("error %v", ex.Error)
 				break
 				break
 			}
 			}
 		}
 		}

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

@@ -15,7 +15,7 @@ import (
 // * [[ttl][class]]
 // * [[ttl][class]]
 // * type
 // * type
 // * rhs (rdata)
 // * 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.
 // of $ after that are interpreted.
 // Any error are returned as a string value, the empty string signals
 // Any error are returned as a string value, the empty string signals
 // "no error".
 // "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
 // 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 {
 type ParseError struct {
 	file string
 	file string
 	err  string
 	err  string
@@ -86,7 +86,7 @@ func (e *ParseError) Error() (s string) {
 type lex struct {
 type lex struct {
 	token      string // text of the token
 	token      string // text of the token
 	tokenUpper string // uppercase 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
 	err        bool   // when true, token text has lexer error
 	value      uint8  // value: zString, _BLANK, etc.
 	value      uint8  // value: zString, _BLANK, etc.
 	line       int    // line in the file
 	line       int    // line in the file
@@ -99,7 +99,7 @@ type lex struct {
 type Token struct {
 type Token struct {
 	// The scanned resource record when error is not nil.
 	// The scanned resource record when error is not nil.
 	RR
 	RR
-	// When an error occured, this has the error specifics.
+	// When an error occurred, this has the error specifics.
 	Error *ParseError
 	Error *ParseError
 	// A potential comment positioned after the RR and on the same line.
 	// A potential comment positioned after the RR and on the same line.
 	Comment string
 	Comment string
@@ -144,8 +144,10 @@ func ReadRR(q io.Reader, filename string) (RR, error) {
 //
 //
 //	for x := range dns.ParseZone(strings.NewReader(z), "", "") {
 //	for x := range dns.ParseZone(strings.NewReader(z), "", "") {
 //		if x.Error != nil {
 //		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:
 // 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{
 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}
+}