فهرست منبع

Update miekg/dns

~1 month of changes.
Ask Bjørn Hansen 10 سال پیش
والد
کامیت
3e3e6c5b55
33فایلهای تغییر یافته به همراه952 افزوده شده و 523 حذف شده
  1. 1 1
      Godeps/Godeps.json
  2. 3 2
      Godeps/_workspace/src/github.com/miekg/dns/.travis.yml
  3. 7 3
      Godeps/_workspace/src/github.com/miekg/dns/README.md
  4. 11 9
      Godeps/_workspace/src/github.com/miekg/dns/client_test.go
  5. 1 3
      Godeps/_workspace/src/github.com/miekg/dns/dns.go
  6. 129 108
      Godeps/_workspace/src/github.com/miekg/dns/dnssec.go
  7. 5 4
      Godeps/_workspace/src/github.com/miekg/dns/dnssec_keygen.go
  8. 6 5
      Godeps/_workspace/src/github.com/miekg/dns/dnssec_keyscan.go
  9. 61 120
      Godeps/_workspace/src/github.com/miekg/dns/dnssec_privkey.go
  10. 13 10
      Godeps/_workspace/src/github.com/miekg/dns/dnssec_test.go
  11. 6 5
      Godeps/_workspace/src/github.com/miekg/dns/doc.go
  12. 5 4
      Godeps/_workspace/src/github.com/miekg/dns/edns.go
  13. 25 0
      Godeps/_workspace/src/github.com/miekg/dns/fuzz_test.go
  14. 67 4
      Godeps/_workspace/src/github.com/miekg/dns/idn/punycode.go
  15. 4 3
      Godeps/_workspace/src/github.com/miekg/dns/idn/punycode_test.go
  16. 3 3
      Godeps/_workspace/src/github.com/miekg/dns/labels.go
  17. 6 7
      Godeps/_workspace/src/github.com/miekg/dns/msg.go
  18. 9 12
      Godeps/_workspace/src/github.com/miekg/dns/parse_test.go
  19. 3 1
      Godeps/_workspace/src/github.com/miekg/dns/privaterr.go
  20. 19 0
      Godeps/_workspace/src/github.com/miekg/dns/remote_test.go
  21. 84 0
      Godeps/_workspace/src/github.com/miekg/dns/sanitize.go
  22. 85 0
      Godeps/_workspace/src/github.com/miekg/dns/sanitize_test.go
  23. 93 23
      Godeps/_workspace/src/github.com/miekg/dns/server.go
  24. 52 1
      Godeps/_workspace/src/github.com/miekg/dns/server_test.go
  25. 10 15
      Godeps/_workspace/src/github.com/miekg/dns/sig0.go
  26. 4 3
      Godeps/_workspace/src/github.com/miekg/dns/sig0_test.go
  27. 13 25
      Godeps/_workspace/src/github.com/miekg/dns/types.go
  28. 3 0
      Godeps/_workspace/src/github.com/miekg/dns/udp.go
  29. 0 1
      Godeps/_workspace/src/github.com/miekg/dns/xfr.go
  30. 72 3
      Godeps/_workspace/src/github.com/miekg/dns/xfr_test.go
  31. 2 2
      Godeps/_workspace/src/github.com/miekg/dns/zgenerate.go
  32. 14 6
      Godeps/_workspace/src/github.com/miekg/dns/zscan.go
  33. 136 140
      Godeps/_workspace/src/github.com/miekg/dns/zscan_rr.go

+ 1 - 1
Godeps/Godeps.json

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

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

@@ -1,6 +1,7 @@
 language: go
+sudo: false
 go:
-  - 1.3
   - 1.4
+  - 1.5
 script:
-  - go test -short -bench=.
+  - go test -race -bench=.

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

@@ -24,6 +24,7 @@ If you like this, you may also be interested in:
 
 A not-so-up-to-date-list-that-may-be-actually-current:
 
+* https://cloudflare.com
 * https://github.com/abh/geodns
 * http://www.statdns.com/
 * http://www.dnsinspect.com/
@@ -38,6 +39,9 @@ A not-so-up-to-date-list-that-may-be-actually-current:
 * https://github.com/tianon/rawdns
 * https://mesosphere.github.io/mesos-dns/
 * https://pulse.turbobytes.com/
+* https://play.google.com/store/apps/details?id=com.turbobytes.dig
+* https://github.com/fcambus/statzone
+* https://github.com/benschw/dns-clb-go
 
 Send pull request if you want to be listed here.
 
@@ -81,7 +85,7 @@ Example programs can be found in the `github.com/miekg/exdns` repository.
 *all of them*
 
 * 103{4,5} - DNS standard
-* 1348 - NSAP record
+* 1348 - NSAP record (removed the record)
 * 1982 - Serial Arithmetic
 * 1876 - LOC record
 * 1995 - IXFR
@@ -138,7 +142,7 @@ Example programs can be found in the `github.com/miekg/exdns` repository.
 ## TODO
 
 * privatekey.Precompute() when signing?
-* Last remaining RRs: APL, ATMA, A6 and NXT.
-* Missing in parsing: ISDN, UNSPEC, ATMA.
+* Last remaining RRs: APL, ATMA, A6, NSAP and NXT.
+* Missing in parsing: ISDN, UNSPEC, NSAP and ATMA.
 * NSEC(3) cover/match/closest enclose.
 * Replies with TC bit are not parsed to the end.

+ 11 - 9
Godeps/_workspace/src/github.com/miekg/dns/client_test.go

@@ -88,7 +88,6 @@ func TestClientEDNS0(t *testing.T) {
 
 // Validates the transmission and parsing of local EDNS0 options.
 func TestClientEDNS0Local(t *testing.T) {
-
 	optStr1 := "1979:0x0707"
 	optStr2 := strconv.Itoa(EDNS0LOCALSTART) + ":0x0601"
 
@@ -149,20 +148,24 @@ func TestClientEDNS0Local(t *testing.T) {
 	// Validate the local options in the reply.
 	got := r.Extra[1].(*OPT).Option[0].(*EDNS0_LOCAL).String()
 	if got != optStr1 {
-		t.Log("failed to get local edns0 answer; got %s, expected %s", got, optStr1)
+		t.Logf("failed to get local edns0 answer; got %s, expected %s", got, optStr1)
 		t.Fail()
 		t.Logf("%v\n", r)
 	}
 
 	got = r.Extra[1].(*OPT).Option[1].(*EDNS0_LOCAL).String()
 	if got != optStr2 {
-		t.Log("failed to get local edns0 answer; got %s, expected %s", got, optStr2)
+		t.Logf("failed to get local edns0 answer; got %s, expected %s", got, optStr2)
 		t.Fail()
 		t.Logf("%v\n", r)
 	}
 }
 
-func TestSingleSingleInflight(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.")
 
@@ -177,7 +180,7 @@ func TestSingleSingleInflight(t *testing.T) {
 
 	c := new(Client)
 	c.SingleInflight = true
-	nr := 10
+	nr := 3
 	ch := make(chan time.Duration)
 	for i := 0; i < nr; i++ {
 		go func() {
@@ -188,7 +191,7 @@ func TestSingleSingleInflight(t *testing.T) {
 	i := 0
 	var first time.Duration
 	// With inflight *all* rtt are identical, and by doing actual lookups
-	// the changes that this is a coincidence is small.
+	// the chances that this is a coincidence is small.
 Loop:
 	for {
 		select {
@@ -197,11 +200,11 @@ Loop:
 				first = rtt
 			} else {
 				if first != rtt {
-					t.Errorf("all rtts should be equal.  got %d want %d", rtt, first)
+					t.Errorf("all rtts should be equal, got %d want %d", rtt, first)
 				}
 			}
 			i++
-			if i == 10 {
+			if i == nr {
 				break Loop
 			}
 		}
@@ -282,5 +285,4 @@ func TestClientConn(t *testing.T) {
 	if err = r.Unpack(buf); err != nil {
 		t.Errorf("unable to unpack message fully: %v", err)
 	}
-
 }

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

@@ -36,9 +36,7 @@ type RR interface {
 	len() int
 }
 
-// DNS resource records.
-// There are many types of RRs,
-// but they all share the same header.
+// RR_Header is the header all DNS resource records share.
 type RR_Header struct {
 	Name     string `dns:"cdomain-name"`
 	Rrtype   uint16

+ 129 - 108
Godeps/_workspace/src/github.com/miekg/dns/dnssec.go

@@ -6,14 +6,14 @@ import (
 	"crypto/dsa"
 	"crypto/ecdsa"
 	"crypto/elliptic"
-	"crypto/md5"
+	_ "crypto/md5"
+	"crypto/rand"
 	"crypto/rsa"
-	"crypto/sha1"
-	"crypto/sha256"
-	"crypto/sha512"
+	_ "crypto/sha1"
+	_ "crypto/sha256"
+	_ "crypto/sha512"
+	"encoding/asn1"
 	"encoding/hex"
-	"hash"
-	"io"
 	"math/big"
 	"sort"
 	"strings"
@@ -42,6 +42,38 @@ const (
 	PRIVATEOID uint8 = 254
 )
 
+// Map for algorithm names.
+var AlgorithmToString = map[uint8]string{
+	RSAMD5:           "RSAMD5",
+	DH:               "DH",
+	DSA:              "DSA",
+	RSASHA1:          "RSASHA1",
+	DSANSEC3SHA1:     "DSA-NSEC3-SHA1",
+	RSASHA1NSEC3SHA1: "RSASHA1-NSEC3-SHA1",
+	RSASHA256:        "RSASHA256",
+	RSASHA512:        "RSASHA512",
+	ECCGOST:          "ECC-GOST",
+	ECDSAP256SHA256:  "ECDSAP256SHA256",
+	ECDSAP384SHA384:  "ECDSAP384SHA384",
+	INDIRECT:         "INDIRECT",
+	PRIVATEDNS:       "PRIVATEDNS",
+	PRIVATEOID:       "PRIVATEOID",
+}
+
+// Map of algorithm strings.
+var StringToAlgorithm = reverseInt8(AlgorithmToString)
+
+// Map of algorithm crypto hashes.
+var AlgorithmToHash = map[uint8]crypto.Hash{
+	RSAMD5:           crypto.MD5, // Deprecated in RFC 6725
+	RSASHA1:          crypto.SHA1,
+	RSASHA1NSEC3SHA1: crypto.SHA1,
+	RSASHA256:        crypto.SHA256,
+	ECDSAP256SHA256:  crypto.SHA256,
+	ECDSAP384SHA384:  crypto.SHA384,
+	RSASHA512:        crypto.SHA512,
+}
+
 // DNSSEC hashing algorithm codes.
 const (
 	_      uint8 = iota
@@ -52,6 +84,18 @@ const (
 	SHA512       // Experimental
 )
 
+// Map for hash names.
+var HashToString = map[uint8]string{
+	SHA1:   "SHA1",
+	SHA256: "SHA256",
+	GOST94: "GOST94",
+	SHA384: "SHA384",
+	SHA512: "SHA512",
+}
+
+// Map of hash strings.
+var StringToHash = reverseInt8(HashToString)
+
 // DNSKEY flag values.
 const (
 	SEP    = 1
@@ -168,24 +212,23 @@ func (k *DNSKEY) ToDS(h uint8) *DS {
 	// digest buffer
 	digest := append(owner, wire...) // another copy
 
+	var hash crypto.Hash
 	switch h {
 	case SHA1:
-		s := sha1.New()
-		io.WriteString(s, string(digest))
-		ds.Digest = hex.EncodeToString(s.Sum(nil))
+		hash = crypto.SHA1
 	case SHA256:
-		s := sha256.New()
-		io.WriteString(s, string(digest))
-		ds.Digest = hex.EncodeToString(s.Sum(nil))
+		hash = crypto.SHA256
 	case SHA384:
-		s := sha512.New384()
-		io.WriteString(s, string(digest))
-		ds.Digest = hex.EncodeToString(s.Sum(nil))
-	case GOST94:
-		/* I have no clue */
+		hash = crypto.SHA384
+	case SHA512:
+		hash = crypto.SHA512
 	default:
 		return nil
 	}
+
+	s := hash.New()
+	s.Write(digest)
+	ds.Digest = hex.EncodeToString(s.Sum(nil))
 	return ds
 }
 
@@ -212,7 +255,7 @@ func (d *DS) ToCDS() *CDS {
 // 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 PrivateKey, rrset []RR) error {
+func (rr *RRSIG) Sign(k crypto.Signer, rrset []RR) error {
 	if k == nil {
 		return ErrPrivKey
 	}
@@ -258,39 +301,66 @@ func (rr *RRSIG) Sign(k PrivateKey, rrset []RR) error {
 	}
 	signdata = append(signdata, wire...)
 
-	var h hash.Hash
-	switch rr.Algorithm {
-	case DSA, DSANSEC3SHA1:
-		// TODO: this seems bugged, will panic
-	case RSASHA1, RSASHA1NSEC3SHA1:
-		h = sha1.New()
-	case RSASHA256, ECDSAP256SHA256:
-		h = sha256.New()
-	case ECDSAP384SHA384:
-		h = sha512.New384()
-	case RSASHA512:
-		h = sha512.New()
-	case RSAMD5:
-		fallthrough // Deprecated in RFC 6725
-	default:
+	hash, ok := AlgorithmToHash[rr.Algorithm]
+	if !ok {
 		return ErrAlg
 	}
 
-	_, err = h.Write(signdata)
-	if err != nil {
-		return err
-	}
-	sighash := h.Sum(nil)
+	h := hash.New()
+	h.Write(signdata)
 
-	signature, err := k.Sign(sighash, rr.Algorithm)
+	signature, err := sign(k, h.Sum(nil), hash, rr.Algorithm)
 	if err != nil {
 		return err
 	}
+
 	rr.Signature = toBase64(signature)
 
 	return nil
 }
 
+func sign(k crypto.Signer, hashed []byte, hash crypto.Hash, alg uint8) ([]byte, error) {
+	signature, err := k.Sign(rand.Reader, hashed, hash)
+	if err != nil {
+		return nil, err
+	}
+
+	switch alg {
+	case RSASHA1, RSASHA1NSEC3SHA1, RSASHA256, RSASHA512:
+		return signature, nil
+
+	case ECDSAP256SHA256, ECDSAP384SHA384:
+		ecdsaSignature := &struct {
+			R, S *big.Int
+		}{}
+		if _, err := asn1.Unmarshal(signature, ecdsaSignature); err != nil {
+			return nil, err
+		}
+
+		var intlen int
+		switch alg {
+		case ECDSAP256SHA256:
+			intlen = 32
+		case ECDSAP384SHA384:
+			intlen = 48
+		}
+
+		signature := intToBytes(ecdsaSignature.R, intlen)
+		signature = append(signature, intToBytes(ecdsaSignature.S, intlen)...)
+		return signature, nil
+
+	// There is no defined interface for what a DSA backed crypto.Signer returns
+	case DSA, DSANSEC3SHA1:
+		// 	t := divRoundUp(divRoundUp(p.PublicKey.Y.BitLen(), 8)-64, 8)
+		// 	signature := []byte{byte(t)}
+		// 	signature = append(signature, intToBytes(r1, 20)...)
+		// 	signature = append(signature, intToBytes(s1, 20)...)
+		// 	rr.Signature = signature
+	}
+
+	return nil, ErrAlg
+}
+
 // Verify validates an RRSet with the signature and key. This is only the
 // cryptographic test, the signature validity period must be checked separately.
 // This function copies the rdata of some RRs (to lowercase domain names) for the validation to work.
@@ -355,6 +425,11 @@ func (rr *RRSIG) Verify(k *DNSKEY, rrset []RR) error {
 		// remove the domain name and assume its our
 	}
 
+	hash, ok := AlgorithmToHash[rr.Algorithm]
+	if !ok {
+		return ErrAlg
+	}
+
 	switch rr.Algorithm {
 	case RSASHA1, RSASHA1NSEC3SHA1, RSASHA256, RSASHA512, RSAMD5:
 		// TODO(mg): this can be done quicker, ie. cache the pubkey data somewhere??
@@ -362,52 +437,31 @@ func (rr *RRSIG) Verify(k *DNSKEY, rrset []RR) error {
 		if pubkey == nil {
 			return ErrKey
 		}
-		// Setup the hash as defined for this alg.
-		var h hash.Hash
-		var ch crypto.Hash
-		switch rr.Algorithm {
-		case RSAMD5:
-			h = md5.New()
-			ch = crypto.MD5
-		case RSASHA1, RSASHA1NSEC3SHA1:
-			h = sha1.New()
-			ch = crypto.SHA1
-		case RSASHA256:
-			h = sha256.New()
-			ch = crypto.SHA256
-		case RSASHA512:
-			h = sha512.New()
-			ch = crypto.SHA512
-		}
-		io.WriteString(h, string(signeddata))
-		sighash := h.Sum(nil)
-		return rsa.VerifyPKCS1v15(pubkey, ch, sighash, sigbuf)
+
+		h := hash.New()
+		h.Write(signeddata)
+		return rsa.VerifyPKCS1v15(pubkey, hash, h.Sum(nil), sigbuf)
+
 	case ECDSAP256SHA256, ECDSAP384SHA384:
 		pubkey := k.publicKeyECDSA()
 		if pubkey == nil {
 			return ErrKey
 		}
-		var h hash.Hash
-		switch rr.Algorithm {
-		case ECDSAP256SHA256:
-			h = sha256.New()
-		case ECDSAP384SHA384:
-			h = sha512.New384()
-		}
-		io.WriteString(h, string(signeddata))
-		sighash := h.Sum(nil)
+
 		// Split sigbuf into the r and s coordinates
-		r := big.NewInt(0)
-		r.SetBytes(sigbuf[:len(sigbuf)/2])
-		s := big.NewInt(0)
-		s.SetBytes(sigbuf[len(sigbuf)/2:])
-		if ecdsa.Verify(pubkey, sighash, r, s) {
+		r := new(big.Int).SetBytes(sigbuf[:len(sigbuf)/2])
+		s := new(big.Int).SetBytes(sigbuf[len(sigbuf)/2:])
+
+		h := hash.New()
+		h.Write(signeddata)
+		if ecdsa.Verify(pubkey, h.Sum(nil), r, s) {
 			return nil
 		}
 		return ErrSig
+
+	default:
+		return ErrAlg
 	}
-	// Unknown alg
-	return ErrAlg
 }
 
 // ValidityPeriod uses RFC1982 serial arithmetic to calculate
@@ -603,36 +657,3 @@ func rawSignatureData(rrset []RR, s *RRSIG) (buf []byte, err error) {
 	}
 	return buf, nil
 }
-
-// Map for algorithm names.
-var AlgorithmToString = map[uint8]string{
-	RSAMD5:           "RSAMD5",
-	DH:               "DH",
-	DSA:              "DSA",
-	RSASHA1:          "RSASHA1",
-	DSANSEC3SHA1:     "DSA-NSEC3-SHA1",
-	RSASHA1NSEC3SHA1: "RSASHA1-NSEC3-SHA1",
-	RSASHA256:        "RSASHA256",
-	RSASHA512:        "RSASHA512",
-	ECCGOST:          "ECC-GOST",
-	ECDSAP256SHA256:  "ECDSAP256SHA256",
-	ECDSAP384SHA384:  "ECDSAP384SHA384",
-	INDIRECT:         "INDIRECT",
-	PRIVATEDNS:       "PRIVATEDNS",
-	PRIVATEOID:       "PRIVATEOID",
-}
-
-// Map of algorithm strings.
-var StringToAlgorithm = reverseInt8(AlgorithmToString)
-
-// Map for hash names.
-var HashToString = map[uint8]string{
-	SHA1:   "SHA1",
-	SHA256: "SHA256",
-	GOST94: "GOST94",
-	SHA384: "SHA384",
-	SHA512: "SHA512",
-}
-
-// Map of hash strings.
-var StringToHash = reverseInt8(HashToString)

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

@@ -1,6 +1,7 @@
 package dns
 
 import (
+	"crypto"
 	"crypto/dsa"
 	"crypto/ecdsa"
 	"crypto/elliptic"
@@ -15,7 +16,7 @@ import (
 // what kind of DNSKEY will be generated.
 // The ECDSA algorithms imply a fixed keysize, in that case
 // bits should be set to the size of the algorithm.
-func (k *DNSKEY) Generate(bits int) (PrivateKey, error) {
+func (k *DNSKEY) Generate(bits int) (crypto.PrivateKey, error) {
 	switch k.Algorithm {
 	case DSA, DSANSEC3SHA1:
 		if bits != 1024 {
@@ -52,14 +53,14 @@ func (k *DNSKEY) Generate(bits int) (PrivateKey, error) {
 			return nil, err
 		}
 		k.setPublicKeyDSA(params.Q, params.P, params.G, priv.PublicKey.Y)
-		return (*DSAPrivateKey)(priv), nil
+		return priv, nil
 	case RSAMD5, RSASHA1, RSASHA256, RSASHA512, RSASHA1NSEC3SHA1:
 		priv, err := rsa.GenerateKey(rand.Reader, bits)
 		if err != nil {
 			return nil, err
 		}
 		k.setPublicKeyRSA(priv.PublicKey.E, priv.PublicKey.N)
-		return (*RSAPrivateKey)(priv), nil
+		return priv, nil
 	case ECDSAP256SHA256, ECDSAP384SHA384:
 		var c elliptic.Curve
 		switch k.Algorithm {
@@ -73,7 +74,7 @@ func (k *DNSKEY) Generate(bits int) (PrivateKey, error) {
 			return nil, err
 		}
 		k.setPublicKeyECDSA(priv.PublicKey.X, priv.PublicKey.Y)
-		return (*ECDSAPrivateKey)(priv), nil
+		return priv, nil
 	default:
 		return nil, ErrAlg
 	}

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

@@ -1,6 +1,7 @@
 package dns
 
 import (
+	"crypto"
 	"crypto/dsa"
 	"crypto/ecdsa"
 	"crypto/rsa"
@@ -12,7 +13,7 @@ import (
 
 // NewPrivateKey returns a PrivateKey by parsing the string s.
 // s should be in the same form of the BIND private key files.
-func (k *DNSKEY) NewPrivateKey(s string) (PrivateKey, error) {
+func (k *DNSKEY) NewPrivateKey(s string) (crypto.PrivateKey, error) {
 	if s[len(s)-1] != '\n' { // We need a closing newline
 		return k.ReadPrivateKey(strings.NewReader(s+"\n"), "")
 	}
@@ -23,7 +24,7 @@ func (k *DNSKEY) NewPrivateKey(s string) (PrivateKey, error) {
 // only used in error reporting.
 // The public key must be known, because some cryptographic algorithms embed
 // the public inside the privatekey.
-func (k *DNSKEY) ReadPrivateKey(q io.Reader, file string) (PrivateKey, error) {
+func (k *DNSKEY) ReadPrivateKey(q io.Reader, file string) (crypto.PrivateKey, error) {
 	m, e := parseKey(q, file)
 	if m == nil {
 		return nil, e
@@ -50,7 +51,7 @@ func (k *DNSKEY) ReadPrivateKey(q io.Reader, file string) (PrivateKey, error) {
 			return nil, ErrKey
 		}
 		priv.PublicKey = *pub
-		return (*DSAPrivateKey)(priv), e
+		return priv, e
 	case RSAMD5:
 		fallthrough
 	case RSASHA1:
@@ -69,7 +70,7 @@ func (k *DNSKEY) ReadPrivateKey(q io.Reader, file string) (PrivateKey, error) {
 			return nil, ErrKey
 		}
 		priv.PublicKey = *pub
-		return (*RSAPrivateKey)(priv), e
+		return priv, e
 	case ECCGOST:
 		return nil, ErrPrivKey
 	case ECDSAP256SHA256:
@@ -84,7 +85,7 @@ func (k *DNSKEY) ReadPrivateKey(q io.Reader, file string) (PrivateKey, error) {
 			return nil, ErrKey
 		}
 		priv.PublicKey = *pub
-		return (*ECDSAPrivateKey)(priv), e
+		return priv, e
 	default:
 		return nil, ErrPrivKey
 	}

+ 61 - 120
Godeps/_workspace/src/github.com/miekg/dns/dnssec_privkey.go

@@ -4,7 +4,6 @@ import (
 	"crypto"
 	"crypto/dsa"
 	"crypto/ecdsa"
-	"crypto/rand"
 	"crypto/rsa"
 	"math/big"
 	"strconv"
@@ -12,133 +11,75 @@ import (
 
 const format = "Private-key-format: v1.3\n"
 
-// PrivateKey ... TODO(miek)
-type PrivateKey interface {
-	Sign([]byte, uint8) ([]byte, error)
-	String(uint8) string
-}
-
 // PrivateKeyString converts a PrivateKey to a string. This string has the same
 // format as the private-key-file of BIND9 (Private-key-format: v1.3).
-// It needs some info from the key (the algorithm), so its a method of the
-// DNSKEY and calls PrivateKey.String(alg).
-func (r *DNSKEY) PrivateKeyString(p PrivateKey) string {
-	return p.String(r.Algorithm)
-}
+// It needs some info from the key (the algorithm), so its a method of the DNSKEY
+// It supports rsa.PrivateKey, ecdsa.PrivateKey and dsa.PrivateKey
+func (r *DNSKEY) PrivateKeyString(p crypto.PrivateKey) string {
+	algorithm := strconv.Itoa(int(r.Algorithm))
+	algorithm += " (" + AlgorithmToString[r.Algorithm] + ")"
 
-type RSAPrivateKey rsa.PrivateKey
+	switch p := p.(type) {
+	case *rsa.PrivateKey:
+		modulus := toBase64(p.PublicKey.N.Bytes())
+		e := big.NewInt(int64(p.PublicKey.E))
+		publicExponent := toBase64(e.Bytes())
+		privateExponent := toBase64(p.D.Bytes())
+		prime1 := toBase64(p.Primes[0].Bytes())
+		prime2 := toBase64(p.Primes[1].Bytes())
+		// Calculate Exponent1/2 and Coefficient as per: http://en.wikipedia.org/wiki/RSA#Using_the_Chinese_remainder_algorithm
+		// and from: http://code.google.com/p/go/issues/detail?id=987
+		one := big.NewInt(1)
+		p1 := big.NewInt(0).Sub(p.Primes[0], one)
+		q1 := big.NewInt(0).Sub(p.Primes[1], one)
+		exp1 := big.NewInt(0).Mod(p.D, p1)
+		exp2 := big.NewInt(0).Mod(p.D, q1)
+		coeff := big.NewInt(0).ModInverse(p.Primes[1], p.Primes[0])
 
-func (p *RSAPrivateKey) Sign(hashed []byte, alg uint8) ([]byte, error) {
-	var hash crypto.Hash
-	switch alg {
-	case RSASHA1, RSASHA1NSEC3SHA1:
-		hash = crypto.SHA1
-	case RSASHA256:
-		hash = crypto.SHA256
-	case RSASHA512:
-		hash = crypto.SHA512
-	default:
-		return nil, ErrAlg
-	}
-	return rsa.SignPKCS1v15(nil, (*rsa.PrivateKey)(p), hash, hashed)
-}
-
-func (p *RSAPrivateKey) String(alg uint8) string {
-	algorithm := strconv.Itoa(int(alg)) + " (" + AlgorithmToString[alg] + ")"
-	modulus := toBase64(p.PublicKey.N.Bytes())
-	e := big.NewInt(int64(p.PublicKey.E))
-	publicExponent := toBase64(e.Bytes())
-	privateExponent := toBase64(p.D.Bytes())
-	prime1 := toBase64(p.Primes[0].Bytes())
-	prime2 := toBase64(p.Primes[1].Bytes())
-	// Calculate Exponent1/2 and Coefficient as per: http://en.wikipedia.org/wiki/RSA#Using_the_Chinese_remainder_algorithm
-	// and from: http://code.google.com/p/go/issues/detail?id=987
-	one := big.NewInt(1)
-	p1 := big.NewInt(0).Sub(p.Primes[0], one)
-	q1 := big.NewInt(0).Sub(p.Primes[1], one)
-	exp1 := big.NewInt(0).Mod(p.D, p1)
-	exp2 := big.NewInt(0).Mod(p.D, q1)
-	coeff := big.NewInt(0).ModInverse(p.Primes[1], p.Primes[0])
+		exponent1 := toBase64(exp1.Bytes())
+		exponent2 := toBase64(exp2.Bytes())
+		coefficient := toBase64(coeff.Bytes())
 
-	exponent1 := toBase64(exp1.Bytes())
-	exponent2 := toBase64(exp2.Bytes())
-	coefficient := toBase64(coeff.Bytes())
+		return format +
+			"Algorithm: " + algorithm + "\n" +
+			"Modulus: " + modulus + "\n" +
+			"PublicExponent: " + publicExponent + "\n" +
+			"PrivateExponent: " + privateExponent + "\n" +
+			"Prime1: " + prime1 + "\n" +
+			"Prime2: " + prime2 + "\n" +
+			"Exponent1: " + exponent1 + "\n" +
+			"Exponent2: " + exponent2 + "\n" +
+			"Coefficient: " + coefficient + "\n"
 
-	return format +
-		"Algorithm: " + algorithm + "\n" +
-		"Modulus: " + modulus + "\n" +
-		"PublicExponent: " + publicExponent + "\n" +
-		"PrivateExponent: " + privateExponent + "\n" +
-		"Prime1: " + prime1 + "\n" +
-		"Prime2: " + prime2 + "\n" +
-		"Exponent1: " + exponent1 + "\n" +
-		"Exponent2: " + exponent2 + "\n" +
-		"Coefficient: " + coefficient + "\n"
-}
+	case *ecdsa.PrivateKey:
+		var intlen int
+		switch r.Algorithm {
+		case ECDSAP256SHA256:
+			intlen = 32
+		case ECDSAP384SHA384:
+			intlen = 48
+		}
+		private := toBase64(intToBytes(p.D, intlen))
+		return format +
+			"Algorithm: " + algorithm + "\n" +
+			"PrivateKey: " + private + "\n"
 
-type ECDSAPrivateKey ecdsa.PrivateKey
+	case *dsa.PrivateKey:
+		T := divRoundUp(divRoundUp(p.PublicKey.Parameters.G.BitLen(), 8)-64, 8)
+		prime := toBase64(intToBytes(p.PublicKey.Parameters.P, 64+T*8))
+		subprime := toBase64(intToBytes(p.PublicKey.Parameters.Q, 20))
+		base := toBase64(intToBytes(p.PublicKey.Parameters.G, 64+T*8))
+		priv := toBase64(intToBytes(p.X, 20))
+		pub := toBase64(intToBytes(p.PublicKey.Y, 64+T*8))
+		return format +
+			"Algorithm: " + algorithm + "\n" +
+			"Prime(p): " + prime + "\n" +
+			"Subprime(q): " + subprime + "\n" +
+			"Base(g): " + base + "\n" +
+			"Private_value(x): " + priv + "\n" +
+			"Public_value(y): " + pub + "\n"
 
-func (p *ECDSAPrivateKey) Sign(hashed []byte, alg uint8) ([]byte, error) {
-	var intlen int
-	switch alg {
-	case ECDSAP256SHA256:
-		intlen = 32
-	case ECDSAP384SHA384:
-		intlen = 48
 	default:
-		return nil, ErrAlg
-	}
-	r1, s1, err := ecdsa.Sign(rand.Reader, (*ecdsa.PrivateKey)(p), hashed)
-	if err != nil {
-		return nil, err
+		return ""
 	}
-	signature := intToBytes(r1, intlen)
-	signature = append(signature, intToBytes(s1, intlen)...)
-	return signature, nil
-}
-
-func (p *ECDSAPrivateKey) String(alg uint8) string {
-	algorithm := strconv.Itoa(int(alg)) + " (" + AlgorithmToString[alg] + ")"
-	var intlen int
-	switch alg {
-	case ECDSAP256SHA256:
-		intlen = 32
-	case ECDSAP384SHA384:
-		intlen = 48
-	}
-	private := toBase64(intToBytes(p.D, intlen))
-	return format +
-		"Algorithm: " + algorithm + "\n" +
-		"PrivateKey: " + private + "\n"
-}
-
-type DSAPrivateKey dsa.PrivateKey
-
-func (p *DSAPrivateKey) Sign(hashed []byte, alg uint8) ([]byte, error) {
-	r1, s1, err := dsa.Sign(rand.Reader, (*dsa.PrivateKey)(p), hashed)
-	if err != nil {
-		return nil, err
-	}
-	t := divRoundUp(divRoundUp(p.PublicKey.Y.BitLen(), 8)-64, 8)
-	signature := []byte{byte(t)}
-	signature = append(signature, intToBytes(r1, 20)...)
-	signature = append(signature, intToBytes(s1, 20)...)
-	return signature, nil
-}
-
-func (p *DSAPrivateKey) String(alg uint8) string {
-	algorithm := strconv.Itoa(int(alg)) + " (" + AlgorithmToString[alg] + ")"
-	T := divRoundUp(divRoundUp(p.PublicKey.Parameters.G.BitLen(), 8)-64, 8)
-	prime := toBase64(intToBytes(p.PublicKey.Parameters.P, 64+T*8))
-	subprime := toBase64(intToBytes(p.PublicKey.Parameters.Q, 20))
-	base := toBase64(intToBytes(p.PublicKey.Parameters.G, 64+T*8))
-	priv := toBase64(intToBytes(p.X, 20))
-	pub := toBase64(intToBytes(p.PublicKey.Y, 64+T*8))
-	return format +
-		"Algorithm: " + algorithm + "\n" +
-		"Prime(p): " + prime + "\n" +
-		"Subprime(q): " + subprime + "\n" +
-		"Base(g): " + base + "\n" +
-		"Private_value(x): " + priv + "\n" +
-		"Public_value(y): " + pub + "\n"
 }

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

@@ -1,6 +1,9 @@
 package dns
 
 import (
+	"crypto"
+	"crypto/ecdsa"
+	"crypto/rsa"
 	"reflect"
 	"strings"
 	"testing"
@@ -192,7 +195,7 @@ func TestSignVerify(t *testing.T) {
 	sig.Algorithm = RSASHA256
 
 	for _, r := range []RR{soa, soa1, srv} {
-		if sig.Sign(privkey, []RR{r}) != nil {
+		if sig.Sign(privkey.(*rsa.PrivateKey), []RR{r}) != nil {
 			t.Error("failure to sign the record")
 			continue
 		}
@@ -228,7 +231,7 @@ func Test65534(t *testing.T) {
 	sig.KeyTag = key.KeyTag()
 	sig.SignerName = key.Hdr.Name
 	sig.Algorithm = RSASHA256
-	if err := sig.Sign(privkey, []RR{t6}); err != nil {
+	if err := sig.Sign(privkey.(*rsa.PrivateKey), []RR{t6}); err != nil {
 		t.Error(err)
 		t.Error("failure to sign the TYPE65534 record")
 	}
@@ -324,7 +327,7 @@ func TestKeyRSA(t *testing.T) {
 	sig.KeyTag = key.KeyTag()
 	sig.SignerName = key.Hdr.Name
 
-	if err := sig.Sign(priv, []RR{soa}); err != nil {
+	if err := sig.Sign(priv.(*rsa.PrivateKey), []RR{soa}); err != nil {
 		t.Error("failed to sign")
 		return
 	}
@@ -374,7 +377,7 @@ Activate: 20110302104537`
 		t.Error(err)
 	}
 	switch priv := p.(type) {
-	case *RSAPrivateKey:
+	case *rsa.PrivateKey:
 		if 65537 != priv.PublicKey.E {
 			t.Error("exponenent should be 65537")
 		}
@@ -403,7 +406,7 @@ Activate: 20110302104537`
 	sig.SignerName = k.Hdr.Name
 	sig.Algorithm = k.Algorithm
 
-	sig.Sign(p, []RR{soa})
+	sig.Sign(p.(*rsa.PrivateKey), []RR{soa})
 	if sig.Signature != "D5zsobpQcmMmYsUMLxCVEtgAdCvTu8V/IEeP4EyLBjqPJmjt96bwM9kqihsccofA5LIJ7DN91qkCORjWSTwNhzCv7bMyr2o5vBZElrlpnRzlvsFIoAZCD9xg6ZY7ZyzUJmU6IcTwG4v3xEYajcpbJJiyaw/RqR90MuRdKPiBzSo=" {
 		t.Errorf("signature is not correct: %v", sig)
 	}
@@ -443,7 +446,7 @@ PrivateKey: WURgWHCcYIYUPWgeLmiPY2DJJk02vgrmTfitxgqcL4vwW7BOrbawVmVe0d9V94SR`
 	sig.SignerName = eckey.(*DNSKEY).Hdr.Name
 	sig.Algorithm = eckey.(*DNSKEY).Algorithm
 
-	if sig.Sign(privkey, []RR{a}) != nil {
+	if sig.Sign(privkey.(*ecdsa.PrivateKey), []RR{a}) != nil {
 		t.Fatal("failure to sign the record")
 	}
 
@@ -491,7 +494,7 @@ func TestSignVerifyECDSA2(t *testing.T) {
 	sig.SignerName = key.Hdr.Name
 	sig.Algorithm = ECDSAP256SHA256
 
-	if sig.Sign(privkey, []RR{srv}) != nil {
+	if sig.Sign(privkey.(*ecdsa.PrivateKey), []RR{srv}) != nil {
 		t.Fatal("failure to sign the record")
 	}
 
@@ -564,7 +567,7 @@ PrivateKey: GU6SnQ/Ou+xC5RumuIUIuJZteXT2z0O/ok1s38Et6mQ=`
 	}
 	ourRRSIG.Expiration, _ = StringToTime("20100909100439")
 	ourRRSIG.Inception, _ = StringToTime("20100812100439")
-	err = ourRRSIG.Sign(priv, []RR{rrA})
+	err = ourRRSIG.Sign(priv.(*ecdsa.PrivateKey), []RR{rrA})
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -640,7 +643,7 @@ PrivateKey: WURgWHCcYIYUPWgeLmiPY2DJJk02vgrmTfitxgqcL4vwW7BOrbawVmVe0d9V94SR`
 	}
 	ourRRSIG.Expiration, _ = StringToTime("20100909102025")
 	ourRRSIG.Inception, _ = StringToTime("20100812102025")
-	err = ourRRSIG.Sign(priv, []RR{rrA})
+	err = ourRRSIG.Sign(priv.(*ecdsa.PrivateKey), []RR{rrA})
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -709,7 +712,7 @@ func TestInvalidRRSet(t *testing.T) {
 	}
 
 	// Sign the good record set and then make sure verification fails on the bad record set
-	if err := signature.Sign(privatekey, goodRecords); err != nil {
+	if err := signature.Sign(privatekey.(crypto.Signer), goodRecords); err != nil {
 		t.Fatal("Signing good records failed")
 	}
 

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

@@ -13,7 +13,8 @@ Resource records are native types. They are not stored in wire format.
 Basic usage pattern for creating a new resource record:
 
      r := new(dns.MX)
-     r.Hdr = dns.RR_Header{Name: "miek.nl.", Rrtype: dns.TypeMX, Class: dns.ClassINET, Ttl: 3600}
+     r.Hdr = dns.RR_Header{Name: "miek.nl.", Rrtype: dns.TypeMX,
+	Class: dns.ClassINET, Ttl: 3600}
      r.Preference = 10
      r.Mx = "mx.miek.nl."
 
@@ -57,8 +58,8 @@ server configured on 127.0.0.1 and port 53:
      c := new(dns.Client)
      in, rtt, err := c.Exchange(m1, "127.0.0.1:53")
 
-Suppressing
-multiple outstanding queries (with the same question, type and class) is as easy as setting:
+Suppressing multiple outstanding queries (with the same question, type and
+class) is as easy as setting:
 
 	c.SingleInflight = true
 
@@ -118,7 +119,7 @@ certain resource records or names in a zone to specify if resource records
 should be added or removed. The table from RFC 2136 supplemented with the Go
 DNS function shows which functions exist to specify the prerequisites.
 
-3.2.4 - Table Of Metavalues Used In Prerequisite Section
+ 3.2.4 - Table Of Metavalues Used In Prerequisite Section
 
   CLASS    TYPE     RDATA    Meaning                    Function
   --------------------------------------------------------------
@@ -133,7 +134,7 @@ If you have decided on the prerequisites you can tell what RRs should
 be added or deleted. The next table shows the options you have and
 what functions to call.
 
-3.4.2.6 - Table Of Metavalues Used In Update Section
+ 3.4.2.6 - Table Of Metavalues Used In Update Section
 
   CLASS    TYPE     RDATA    Meaning                     Function
   ---------------------------------------------------------------

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

@@ -30,6 +30,7 @@ type OPT struct {
 	Option []EDNS0 `dns:"opt"`
 }
 
+// Header implements the RR interface.
 func (rr *OPT) Header() *RR_Header {
 	return &rr.Hdr
 }
@@ -176,7 +177,7 @@ func (e *EDNS0_NSID) Option() uint16        { return EDNS0NSID }
 func (e *EDNS0_NSID) unpack(b []byte) error { e.Nsid = hex.EncodeToString(b); return nil }
 func (e *EDNS0_NSID) String() string        { return string(e.Nsid) }
 
-// The subnet EDNS0 option is used to give the remote nameserver
+// EDNS0_SUBNET is the subnet option that is used to give the remote nameserver
 // an idea of where the client lives. It can then give back a different
 // answer depending on the location or network topology.
 // Basic use pattern for creating an subnet option:
@@ -291,7 +292,7 @@ func (e *EDNS0_SUBNET) String() (s string) {
 	return
 }
 
-// The UL (Update Lease) EDNS0 (draft RFC) option is used to tell the server to set
+// The EDNS0_UL (Update Lease) (draft RFC) option is used to tell the server to set
 // an expiration on an update RR. This is helpful for clients that cannot clean
 // up after themselves. This is a draft RFC and more information can be found at
 // http://files.dns-sd.org/draft-sekar-dns-ul.txt
@@ -329,7 +330,7 @@ func (e *EDNS0_UL) unpack(b []byte) error {
 	return nil
 }
 
-// Long Lived Queries: http://tools.ietf.org/html/draft-sekar-dns-llq-01
+// EDNS0_LLQ stands for Long Lived Queries: http://tools.ietf.org/html/draft-sekar-dns-llq-01
 // Implemented for completeness, as the EDNS0 type code is assigned.
 type EDNS0_LLQ struct {
 	Code      uint16 // Always EDNS0LLQ
@@ -471,7 +472,7 @@ func (e *EDNS0_EXPIRE) unpack(b []byte) error {
 	return nil
 }
 
-// The local EDNS0 option is used for local/experimental purposes.  The option
+// The EDNS0_LOCAL option is used for local/experimental purposes. The option
 // code is recommended to be within the range [EDNS0LOCALSTART, EDNS0LOCALEND]
 // (RFC6891), although any unassigned code can actually be used.  The content of
 // the option is made available in Data, unaltered.

+ 25 - 0
Godeps/_workspace/src/github.com/miekg/dns/fuzz_test.go

@@ -0,0 +1,25 @@
+package dns
+
+import "testing"
+
+func TestFuzzString(t *testing.T) {
+	testcases := []string{"", " MINFO ", "	RP ", "	NSEC 0 0", "	\" NSEC 0 0\"", "  \" MINFO \"",
+		";a ", ";a����������",
+		"	NSAP O ", "  NSAP N ",
+		" TYPE4 TYPE6a789a3bc0045c8a5fb42c7d1bd998f5444 IN 9579b47d46817afbd17273e6",
+		" TYPE45 3 3 4147994 TYPE\\(\\)\\)\\(\\)\\(\\(\\)\\(\\)\\)\\)\\(\\)\\(\\)\\(\\(\\R 948\"\")\\(\\)\\)\\)\\(\\ ",
+		"$GENERATE 0-3 ${441189,5039418474430,o}",
+		"$INCLUDE 00 TYPE00000000000n ",
+		"$INCLUDE PE4 TYPE061463623/727071511 \\(\\)\\$GENERATE 6-462/0",
+	}
+	for i, tc := range testcases {
+		rr, err := NewRR(tc)
+		if err == nil {
+			// rr can be nil because we can (for instance) just parse a comment
+			if rr == nil {
+				continue
+			}
+			t.Fatalf("parsed mailformed RR %d: %s", i, rr.String())
+		}
+	}
+}

+ 67 - 4
Godeps/_workspace/src/github.com/miekg/dns/idn/punycode.go

@@ -5,6 +5,7 @@ import (
 	"bytes"
 	"strings"
 	"unicode"
+	"unicode/utf8"
 
 	"github.com/abh/geodns/Godeps/_workspace/src/github.com/miekg/dns"
 )
@@ -27,9 +28,15 @@ const (
 )
 
 // ToPunycode converts unicode domain names to DNS-appropriate punycode names.
-// This function would return an empty string result for domain names with
+// This function will return an empty string result for domain names with
 // invalid unicode strings. This function expects domain names in lowercase.
 func ToPunycode(s string) string {
+	// Early check to see if encoding is needed.
+	// This will prevent making heap allocations when not needed.
+	if !needToPunycode(s) {
+		return s
+	}
+
 	tokens := dns.SplitDomainName(s)
 	switch {
 	case s == "":
@@ -51,7 +58,14 @@ func ToPunycode(s string) string {
 }
 
 // FromPunycode returns unicode domain name from provided punycode string.
+// This function expects punycode strings in lowercase.
 func FromPunycode(s string) string {
+	// Early check to see if decoding is needed.
+	// This will prevent making heap allocations when not needed.
+	if !needFromPunycode(s) {
+		return s
+	}
+
 	tokens := dns.SplitDomainName(s)
 	switch {
 	case s == "":
@@ -124,7 +138,7 @@ func next(b []rune, boundary rune) rune {
 }
 
 // preprune converts unicode rune to lower case. At this time it's not
-// supporting all things described in RFCs
+// supporting all things described in RFCs.
 func preprune(r rune) rune {
 	if unicode.IsUpper(r) {
 		r = unicode.ToLower(r)
@@ -132,7 +146,7 @@ func preprune(r rune) rune {
 	return r
 }
 
-// tfunc is a function that helps calculate each character weight
+// tfunc is a function that helps calculate each character weight.
 func tfunc(k, bias rune) rune {
 	switch {
 	case k <= bias:
@@ -143,6 +157,51 @@ func tfunc(k, bias rune) rune {
 	return k - bias
 }
 
+// needToPunycode returns true for strings that require punycode encoding
+// (contain unicode characters).
+func needToPunycode(s string) bool {
+	// This function is very similar to bytes.Runes. We don't use bytes.Runes
+	// because it makes a heap allocation that's not needed here.
+	for i := 0; len(s) > 0; i++ {
+		r, l := utf8.DecodeRuneInString(s)
+		if r > 0x7f {
+			return true
+		}
+		s = s[l:]
+	}
+	return false
+}
+
+// needFromPunycode returns true for strings that require punycode decoding.
+func needFromPunycode(s string) bool {
+	if s == "." {
+		return false
+	}
+
+	off := 0
+	end := false
+	pl := len(_PREFIX)
+	sl := len(s)
+
+	// If s starts with _PREFIX.
+	if sl > pl && s[off:off+pl] == _PREFIX {
+		return true
+	}
+
+	for {
+		// Find the part after the next ".".
+		off, end = dns.NextLabel(s, off)
+		if end {
+			return false
+		}
+		// If this parts starts with _PREFIX.
+		if sl-off > pl && s[off:off+pl] == _PREFIX {
+			return true
+		}
+	}
+	panic("dns: not reached")
+}
+
 // encode transforms Unicode input bytes (that represent DNS label) into
 // punycode bytestream. This function would return nil if there's an invalid
 // character in the label.
@@ -217,7 +276,7 @@ func encode(input []byte) []byte {
 	return out.Bytes()
 }
 
-// decode transforms punycode input bytes (that represent DNS label) into Unicode bytestream
+// decode transforms punycode input bytes (that represent DNS label) into Unicode bytestream.
 func decode(b []byte) []byte {
 	src := b // b would move and we need to keep it
 
@@ -254,6 +313,10 @@ func decode(b []byte) []byte {
 				return src
 			}
 			i += digit * w
+			if i < 0 {
+				// safety check for rune overflow
+				return src
+			}
 
 			t = tfunc(k, bias)
 			if digit < t {

+ 4 - 3
Godeps/_workspace/src/github.com/miekg/dns/idn/punycode_test.go

@@ -8,9 +8,9 @@ import (
 var testcases = [][2]string{
 	{"", ""},
 	{"a", "a"},
-	{"A-B", "a-b"},
-	{"A-B-C", "a-b-c"},
-	{"AbC", "abc"},
+	{"a-b", "a-b"},
+	{"a-b-c", "a-b-c"},
+	{"abc", "abc"},
 	{"я", "xn--41a"},
 	{"zя", "xn--z-0ub"},
 	{"яZ", "xn--z-zub"},
@@ -86,6 +86,7 @@ var invalidACEs = []string{
 	"xn--*",
 	"xn--",
 	"xn---",
+	"xn--a000000000",
 }
 
 func TestInvalidPunycode(t *testing.T) {

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

@@ -98,12 +98,11 @@ func CountLabel(s string) (labels int) {
 			return
 		}
 	}
-	panic("dns: not reached")
 }
 
 // Split splits a name s into its label indexes.
 // www.miek.nl. returns []int{0, 4, 9}, www.miek.nl also returns []int{0, 4, 9}.
-// The root name (.) returns nil. Also see dns.SplitDomainName.
+// The root name (.) returns nil. Also see SplitDomainName.
 func Split(s string) []int {
 	if s == "." {
 		return nil
@@ -119,12 +118,12 @@ func Split(s string) []int {
 		}
 		idx = append(idx, off)
 	}
-	panic("dns: not reached")
 }
 
 // NextLabel returns the index of the start of the next label in the
 // string s starting at offset.
 // The bool end is true when the end of the string has been reached.
+// Also see PrevLabel.
 func NextLabel(s string, offset int) (i int, end bool) {
 	quote := false
 	for i = offset; i < len(s)-1; i++ {
@@ -147,6 +146,7 @@ func NextLabel(s string, offset int) (i int, end bool) {
 // PrevLabel returns the index of the label when starting from the right and
 // jumping n labels to the left.
 // The bool start is true when the start of the string has been overshot.
+// Also see NextLabel.
 func PrevLabel(s string, n int) (i int, start bool) {
 	if n == 0 {
 		return len(s), false

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

@@ -29,8 +29,6 @@ var (
 	ErrAuth error = &Error{err: "bad authentication"}
 	// ErrBuf indicates that the buffer used it too small for the message.
 	ErrBuf error = &Error{err: "buffer size too small"}
-	// ErrConn indicates that a connection has both a TCP and UDP socket.
-	ErrConn error = &Error{err: "conn holds both UDP and TCP connection"}
 	// ErrConnEmpty indicates a connection is being uses before it is initialized.
 	ErrConnEmpty error = &Error{err: "conn has no connection"}
 	// ErrExtendedRcode ...
@@ -38,7 +36,8 @@ var (
 	// ErrFqdn indicates that a domain name does not have a closing dot.
 	ErrFqdn error = &Error{err: "domain must be fully qualified"}
 	// ErrId indicates there is a mismatch with the message's ID.
-	ErrId        error = &Error{err: "id mismatch"}
+	ErrId error = &Error{err: "id mismatch"}
+	// ErrKeyAlg indicates that the algorithm in the key is not valid.
 	ErrKeyAlg    error = &Error{err: "bad key algorithm"}
 	ErrKey       error = &Error{err: "bad key"}
 	ErrKeySize   error = &Error{err: "bad key size"}
@@ -51,8 +50,6 @@ var (
 	ErrShortRead error = &Error{err: "short read"}
 	// ErrSig indicates that a signature can not be cryptographically validated.
 	ErrSig error = &Error{err: "bad signature"}
-	// ErrSigGen indicates a faulure to generate a signature.
-	ErrSigGen error = &Error{err: "bad signature generation"}
 	// ErrSOA indicates that no SOA RR was seen when doing zone transfers.
 	ErrSoa error = &Error{err: "no SOA"}
 	// ErrTime indicates a timing error in TSIG authentication.
@@ -138,7 +135,6 @@ var TypeToString = map[uint16]string{
 	TypeNINFO:      "NINFO",
 	TypeNIMLOC:     "NIMLOC",
 	TypeNS:         "NS",
-	TypeNSAP:       "NSAP",
 	TypeNSAPPTR:    "NSAP-PTR",
 	TypeNSEC3:      "NSEC3",
 	TypeNSEC3PARAM: "NSEC3PARAM",
@@ -237,7 +233,7 @@ var RcodeToString = map[int]string{
 // PackDomainName packs a domain name s into msg[off:].
 // If compression is wanted compress must be true and the compression
 // map needs to hold a mapping between domain names and offsets
-// pointing into msg[].
+// pointing into msg.
 func PackDomainName(s string, msg []byte, off int, compression map[string]int, compress bool) (off1 int, err error) {
 	off1, _, err = packDomainName(s, msg, off, compression, compress)
 	return
@@ -1701,6 +1697,9 @@ func (dns *Msg) Unpack(msg []byte) (err error) {
 	// 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

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

@@ -905,16 +905,13 @@ func TestILNP(t *testing.T) {
 	}
 }
 
-func TestNsapGposEidNimloc(t *testing.T) {
+func TestGposEidNimloc(t *testing.T) {
 	dt := map[string]string{
-		"foo.bar.com.    IN  NSAP   21 47000580ffff000000321099991111222233334444": "foo.bar.com.\t3600\tIN\tNSAP\t0x47000580ffff000000321099991111222233334444",
-		"foo.bar.com.    IN  NSAP   0x47000580ffff000000321099991111222233334444":  "foo.bar.com.\t3600\tIN\tNSAP\t0x47000580ffff000000321099991111222233334444",
-		"host.school.de  IN  NSAP   17 39276f3100111100002222333344449876":         "host.school.de.\t3600\tIN\tNSAP\t0x39276f3100111100002222333344449876",
-		"444433332222111199990123000000ff. NSAP-PTR foo.bar.com.":                  "444433332222111199990123000000ff.\t3600\tIN\tNSAP-PTR\tfoo.bar.com.",
-		"lillee. IN  GPOS -32.6882 116.8652 10.0":                                  "lillee.\t3600\tIN\tGPOS\t-32.6882 116.8652 10.0",
-		"hinault. IN GPOS -22.6882 116.8652 250.0":                                 "hinault.\t3600\tIN\tGPOS\t-22.6882 116.8652 250.0",
-		"VENERA.   IN NIMLOC  75234159EAC457800920":                                "VENERA.\t3600\tIN\tNIMLOC\t75234159EAC457800920",
-		"VAXA.     IN EID     3141592653589793":                                    "VAXA.\t3600\tIN\tEID\t3141592653589793",
+		"444433332222111199990123000000ff. NSAP-PTR foo.bar.com.": "444433332222111199990123000000ff.\t3600\tIN\tNSAP-PTR\tfoo.bar.com.",
+		"lillee. IN  GPOS -32.6882 116.8652 10.0":                 "lillee.\t3600\tIN\tGPOS\t-32.6882 116.8652 10.0",
+		"hinault. IN GPOS -22.6882 116.8652 250.0":                "hinault.\t3600\tIN\tGPOS\t-22.6882 116.8652 250.0",
+		"VENERA.   IN NIMLOC  75234159EAC457800920":               "VENERA.\t3600\tIN\tNIMLOC\t75234159EAC457800920",
+		"VAXA.     IN EID     3141592653589793":                   "VAXA.\t3600\tIN\tEID\t3141592653589793",
 	}
 	for i, o := range dt {
 		rr, err := NewRR(i)
@@ -1240,8 +1237,8 @@ func TestNewPrivateKey(t *testing.T) {
 		}
 
 		switch newPrivKey := newPrivKey.(type) {
-		case *RSAPrivateKey:
-			(*rsa.PrivateKey)(newPrivKey).Precompute()
+		case *rsa.PrivateKey:
+			newPrivKey.Precompute()
 		}
 
 		if !reflect.DeepEqual(privkey, newPrivKey) {
@@ -1510,7 +1507,7 @@ func TestPackCAA(t *testing.T) {
 func TestParseURI(t *testing.T) {
 	lt := map[string]string{
 		"_http._tcp. IN URI   10 1 \"http://www.example.com/path\"": "_http._tcp.\t3600\tIN\tURI\t10 1 \"http://www.example.com/path\"",
-		"_http._tcp. IN URI   10 1 \"\"": "_http._tcp.\t3600\tIN\tURI\t10 1 \"\"",
+		"_http._tcp. IN URI   10 1 \"\"":                            "_http._tcp.\t3600\tIN\tURI\t10 1 \"\"",
 	}
 	for i, o := range lt {
 		rr, err := NewRR(i)

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

@@ -46,8 +46,10 @@ func mkPrivateRR(rrtype uint16) *PrivateRR {
 	panic(fmt.Sprintf("dns: RR is not a PrivateRR, typeToRR[%d] generator returned %T", rrtype, anyrr))
 }
 
+// Header return the RR header of r.
 func (r *PrivateRR) Header() *RR_Header { return &r.Hdr }
-func (r *PrivateRR) String() string     { return r.Hdr.String() + r.Data.String() }
+
+func (r *PrivateRR) String() string { return r.Hdr.String() + r.Data.String() }
 
 // Private len and copy parts to satisfy RR interface.
 func (r *PrivateRR) len() int { return r.Hdr.len() + r.Data.Len() }

+ 19 - 0
Godeps/_workspace/src/github.com/miekg/dns/remote_test.go

@@ -0,0 +1,19 @@
+package dns
+
+import "testing"
+
+const LinodeAddr = "176.58.119.54:53"
+
+func TestClientRemote(t *testing.T) {
+	m := new(Msg)
+	m.SetQuestion("go.dns.miek.nl.", TypeTXT)
+
+	c := new(Client)
+	r, _, err := c.Exchange(m, LinodeAddr)
+	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)
+	}
+}

+ 84 - 0
Godeps/_workspace/src/github.com/miekg/dns/sanitize.go

@@ -0,0 +1,84 @@
+package dns
+
+// Dedup removes identical RRs from rrs. It preserves the original ordering.
+// The lowest TTL of any duplicates is used in the remaining one. Dedup modifies
+// rrs.
+// m is used to store the RRs temporay. If it is nil a new map will be allocated.
+func Dedup(rrs []RR, m map[string]RR) []RR {
+	if m == nil {
+		m = make(map[string]RR)
+	}
+	// Save the keys, so we don't have to call normalizedString twice.
+	keys := make([]*string, 0, len(rrs))
+
+	for _, r := range rrs {
+		key := normalizedString(r)
+		keys = append(keys, &key)
+		if _, ok := m[key]; ok {
+			// Shortest TTL wins.
+			if m[key].Header().Ttl > r.Header().Ttl {
+				m[key].Header().Ttl = r.Header().Ttl
+			}
+			continue
+		}
+
+		m[key] = r
+	}
+	// If the length of the result map equals the amount of RRs we got,
+	// it means they were all different. We can then just return the original rrset.
+	if len(m) == len(rrs) {
+		return rrs
+	}
+
+	j := 0
+	for i, r := range rrs {
+		// If keys[i] lives in the map, we should copy and remove it.
+		if _, ok := m[*keys[i]]; ok {
+			delete(m, *keys[i])
+			rrs[j] = r
+			j++
+		}
+
+		if len(m) == 0 {
+			break
+		}
+	}
+
+	return rrs[:j]
+}
+
+// normalizedString returns a normalized string from r. The TTL
+// is removed and the domain name is lowercased. We go from this:
+// DomainName<TAB>TTL<TAB>CLASS<TAB>TYPE<TAB>RDATA to:
+// lowercasename<TAB>CLASS<TAB>TYPE...
+func normalizedString(r RR) string {
+	// A string Go DNS makes has: domainname<TAB>TTL<TAB>...
+	b := []byte(r.String())
+
+	// find the first non-escaped tab, then another, so we capture where the TTL lives.
+	esc := false
+	ttlStart, ttlEnd := 0, 0
+	for i := 0; i < len(b) && ttlEnd == 0; i++ {
+		switch {
+		case b[i] == '\\':
+			esc = !esc
+		case b[i] == '\t' && !esc:
+			if ttlStart == 0 {
+				ttlStart = i
+				continue
+			}
+			if ttlEnd == 0 {
+				ttlEnd = i
+			}
+		case b[i] >= 'A' && b[i] <= 'Z' && !esc:
+			b[i] += 32
+		default:
+			esc = false
+		}
+	}
+
+	// remove TTL.
+	copy(b[ttlStart:], b[ttlEnd:])
+	cut := ttlEnd - ttlStart
+	return string(b[:len(b)-cut])
+}

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

@@ -0,0 +1,85 @@
+package dns
+
+import "testing"
+
+func TestDedup(t *testing.T) {
+	// make it []string
+	testcases := map[[3]RR][]string{
+		[...]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. IN A 127.0.0.1"),
+		}: []string{"mIek.nl.\t3600\tIN\tA\t127.0.0.1"},
+		[...]RR{
+			newRR(t, "miEk.nl. 2000 IN A 127.0.0.1"),
+			newRR(t, "mieK.Nl. 1000 IN A 127.0.0.1"),
+			newRR(t, "Miek.nL. 500 IN A 127.0.0.1"),
+		}: []string{"miEk.nl.\t500\tIN\tA\t127.0.0.1"},
+		[...]RR{
+			newRR(t, "miek.nl. IN A 127.0.0.1"),
+			newRR(t, "miek.nl. CH A 127.0.0.1"),
+			newRR(t, "miek.nl. IN A 127.0.0.1"),
+		}: []string{"miek.nl.\t3600\tIN\tA\t127.0.0.1",
+			"miek.nl.\t3600\tCH\tA\t127.0.0.1",
+		},
+		[...]RR{
+			newRR(t, "miek.nl. CH A 127.0.0.1"),
+			newRR(t, "miek.nl. IN A 127.0.0.1"),
+			newRR(t, "miek.de. IN A 127.0.0.1"),
+		}: []string{"miek.nl.\t3600\tCH\tA\t127.0.0.1",
+			"miek.nl.\t3600\tIN\tA\t127.0.0.1",
+			"miek.de.\t3600\tIN\tA\t127.0.0.1",
+		},
+		[...]RR{
+			newRR(t, "miek.de. IN A 127.0.0.1"),
+			newRR(t, "miek.nl. 200 IN A 127.0.0.1"),
+			newRR(t, "miek.nl. 300 IN A 127.0.0.1"),
+		}: []string{"miek.de.\t3600\tIN\tA\t127.0.0.1",
+			"miek.nl.\t200\tIN\tA\t127.0.0.1",
+		},
+	}
+
+	for rr, expected := range testcases {
+		out := Dedup([]RR{rr[0], rr[1], rr[2]}, nil)
+		for i, o := range out {
+			if o.String() != expected[i] {
+				t.Fatalf("expected %v, got %v", expected[i], o.String())
+			}
+		}
+	}
+}
+
+func BenchmarkDedup(b *testing.B) {
+	rrs := []RR{
+		newRR(nil, "miEk.nl. 2000 IN A 127.0.0.1"),
+		newRR(nil, "mieK.Nl. 1000 IN A 127.0.0.1"),
+		newRR(nil, "Miek.nL. 500 IN A 127.0.0.1"),
+	}
+	m := make(map[string]RR)
+	for i := 0; i < b.N; i++ {
+		Dedup(rrs,m )
+	}
+}
+
+func TestNormalizedString(t *testing.T) {
+	tests := map[RR]string{
+		newRR(t, "mIEk.Nl. 3600 IN A 127.0.0.1"):     "miek.nl.\tIN\tA\t127.0.0.1",
+		newRR(t, "m\\ iek.nL. 3600 IN A 127.0.0.1"):  "m\\ iek.nl.\tIN\tA\t127.0.0.1",
+		newRR(t, "m\\\tIeK.nl. 3600 in A 127.0.0.1"): "m\\tiek.nl.\tIN\tA\t127.0.0.1",
+	}
+	for tc, expected := range tests {
+		n := normalizedString(tc)
+		if n != expected {
+			t.Logf("expected %s, got %s", expected, n)
+			t.Fail()
+		}
+	}
+}
+
+func newRR(t *testing.T, s string) RR {
+	r, e := NewRR(s)
+	if e != nil {
+		t.Logf("newRR: %s", e)
+	}
+	return r
+}

+ 93 - 23
Godeps/_workspace/src/github.com/miekg/dns/server.go

@@ -10,6 +10,9 @@ import (
 	"time"
 )
 
+// Maximum number of TCP queries before we close the socket.
+const maxTCPQueries = 128
+
 // Handler is implemented by any value that implements ServeDNS.
 type Handler interface {
 	ServeDNS(w ResponseWriter, r *Msg)
@@ -47,6 +50,7 @@ type response struct {
 	tcp            *net.TCPConn      // i/o connection if TCP was used
 	udpSession     *SessionUDP       // oob data to get egress interface right
 	remoteAddr     net.Addr          // address of the client
+	writer         Writer            // writer to output the raw DNS bits
 }
 
 // ServeMux is an DNS request multiplexer. It matches the
@@ -158,9 +162,9 @@ func (mux *ServeMux) HandleRemove(pattern string) {
 	if pattern == "" {
 		panic("dns: invalid pattern " + pattern)
 	}
-	// don't need a mutex here, because deleting is OK, even if the
-	// entry is note there.
+	mux.m.Lock()
 	delete(mux.z, Fqdn(pattern))
+	mux.m.Unlock()
 }
 
 // ServeDNS dispatches the request to the handler whose
@@ -197,6 +201,43 @@ func HandleFunc(pattern string, handler func(ResponseWriter, *Msg)) {
 	DefaultServeMux.HandleFunc(pattern, handler)
 }
 
+// Writer writes raw DNS messages; each call to Write should send an entire message.
+type Writer interface {
+	io.Writer
+}
+
+// Reader reads raw DNS messages; each call to ReadTCP or ReadUDP should return an entire message.
+type Reader interface {
+	// ReadTCP reads a raw message from a TCP connection. Implementations may alter
+	// connection properties, for example the read-deadline.
+	ReadTCP(conn *net.TCPConn, timeout time.Duration) ([]byte, error)
+	// ReadUDP reads a raw message from a UDP connection. Implementations may alter
+	// connection properties, for example the read-deadline.
+	ReadUDP(conn *net.UDPConn, timeout time.Duration) ([]byte, *SessionUDP, error)
+}
+
+// defaultReader is an adapter for the Server struct that implements the Reader interface
+// using the readTCP and readUDP func of the embedded Server.
+type defaultReader struct {
+	*Server
+}
+
+func (dr *defaultReader) ReadTCP(conn *net.TCPConn, timeout time.Duration) ([]byte, error) {
+	return dr.readTCP(conn, timeout)
+}
+
+func (dr *defaultReader) ReadUDP(conn *net.UDPConn, timeout time.Duration) ([]byte, *SessionUDP, error) {
+	return dr.readUDP(conn, timeout)
+}
+
+// DecorateReader is a decorator hook for extending or supplanting the functionality of a Reader.
+// Implementations should never return a nil Reader.
+type DecorateReader func(Reader) Reader
+
+// DecorateWriter is a decorator hook for extending or supplanting the functionality of a Writer.
+// Implementations should never return a nil Writer.
+type DecorateWriter func(Writer) Writer
+
 // A Server defines parameters for running an DNS server.
 type Server struct {
 	// Address to listen on, ":dns" if empty.
@@ -223,8 +264,12 @@ type Server struct {
 	// 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.
 	Unsafe bool
-	// If NotifyStartedFunc is set is is called, once the server has started listening.
+	// If NotifyStartedFunc is set it is called once the server has started listening.
 	NotifyStartedFunc func()
+	// DecorateReader is optional, allows customization of the process that reads raw DNS messages.
+	DecorateReader DecorateReader
+	// DecorateWriter is optional, allows customization of the process that writes raw DNS messages.
+	DecorateWriter DecorateWriter
 
 	// For graceful shutdown.
 	stopUDP chan bool
@@ -246,7 +291,6 @@ func (srv *Server) ListenAndServe() error {
 	}
 	srv.stopUDP, srv.stopTCP = make(chan bool), make(chan bool)
 	srv.started = true
-	srv.lock.Unlock()
 	addr := srv.Addr
 	if addr == "" {
 		addr = ":domain"
@@ -265,6 +309,7 @@ func (srv *Server) ListenAndServe() error {
 			return e
 		}
 		srv.Listener = l
+		srv.lock.Unlock()
 		return srv.serveTCP(l)
 	case "udp", "udp4", "udp6":
 		a, e := net.ResolveUDPAddr(srv.Net, addr)
@@ -279,8 +324,10 @@ func (srv *Server) ListenAndServe() error {
 			return e
 		}
 		srv.PacketConn = l
+		srv.lock.Unlock()
 		return srv.serveUDP(l)
 	}
+	srv.lock.Unlock()
 	return &Error{err: "bad network"}
 }
 
@@ -294,20 +341,22 @@ func (srv *Server) ActivateAndServe() error {
 	}
 	srv.stopUDP, srv.stopTCP = make(chan bool), make(chan bool)
 	srv.started = true
+	pConn := srv.PacketConn
+	l := srv.Listener
 	srv.lock.Unlock()
-	if srv.PacketConn != nil {
+	if pConn != nil {
 		if srv.UDPSize == 0 {
 			srv.UDPSize = MinMsgSize
 		}
-		if t, ok := srv.PacketConn.(*net.UDPConn); ok {
+		if t, ok := pConn.(*net.UDPConn); ok {
 			if e := setUDPSocketOptions(t); e != nil {
 				return e
 			}
 			return srv.serveUDP(t)
 		}
 	}
-	if srv.Listener != nil {
-		if t, ok := srv.Listener.(*net.TCPListener); ok {
+	if l != nil {
+		if t, ok := l.(*net.TCPListener); ok {
 			return srv.serveTCP(t)
 		}
 	}
@@ -316,7 +365,7 @@ func (srv *Server) ActivateAndServe() error {
 
 // Shutdown gracefully shuts down a server. After a call to Shutdown, ListenAndServe and
 // ActivateAndServe will return. All in progress queries are completed before the server
-// is taken down. If the Shutdown is taking longer than the reading timeout and error
+// is taken down. If the Shutdown is taking longer than the reading timeout an error
 // is returned.
 func (srv *Server) Shutdown() error {
 	srv.lock.Lock()
@@ -325,7 +374,6 @@ func (srv *Server) Shutdown() error {
 		return &Error{err: "server not started"}
 	}
 	srv.started = false
-	srv.lock.Unlock()
 	net, addr := srv.Net, srv.Addr
 	switch {
 	case srv.Listener != nil:
@@ -335,6 +383,7 @@ func (srv *Server) Shutdown() error {
 		a := srv.PacketConn.LocalAddr()
 		net, addr = a.Network(), a.String()
 	}
+	srv.lock.Unlock()
 
 	fin := make(chan bool)
 	switch net {
@@ -382,6 +431,11 @@ func (srv *Server) serveTCP(l *net.TCPListener) error {
 		srv.NotifyStartedFunc()
 	}
 
+	reader := Reader(&defaultReader{srv})
+	if srv.DecorateReader != nil {
+		reader = srv.DecorateReader(reader)
+	}
+
 	handler := srv.Handler
 	if handler == nil {
 		handler = DefaultServeMux
@@ -393,7 +447,7 @@ func (srv *Server) serveTCP(l *net.TCPListener) error {
 		if e != nil {
 			continue
 		}
-		m, e := srv.readTCP(rw, rtimeout)
+		m, e := reader.ReadTCP(rw, rtimeout)
 		select {
 		case <-srv.stopTCP:
 			return nil
@@ -405,7 +459,6 @@ func (srv *Server) serveTCP(l *net.TCPListener) error {
 		srv.wgTCP.Add(1)
 		go srv.serve(rw.RemoteAddr(), handler, m, nil, nil, rw)
 	}
-	panic("dns: not reached")
 }
 
 // serveUDP starts a UDP listener for the server.
@@ -417,6 +470,11 @@ func (srv *Server) serveUDP(l *net.UDPConn) error {
 		srv.NotifyStartedFunc()
 	}
 
+	reader := Reader(&defaultReader{srv})
+	if srv.DecorateReader != nil {
+		reader = srv.DecorateReader(reader)
+	}
+
 	handler := srv.Handler
 	if handler == nil {
 		handler = DefaultServeMux
@@ -424,7 +482,7 @@ func (srv *Server) serveUDP(l *net.UDPConn) error {
 	rtimeout := srv.getReadTimeout()
 	// deadline is not used here
 	for {
-		m, s, e := srv.readUDP(l, rtimeout)
+		m, s, e := reader.ReadUDP(l, rtimeout)
 		select {
 		case <-srv.stopUDP:
 			return nil
@@ -436,13 +494,19 @@ func (srv *Server) serveUDP(l *net.UDPConn) error {
 		srv.wgUDP.Add(1)
 		go srv.serve(s.RemoteAddr(), handler, m, l, s, nil)
 	}
-	panic("dns: not reached")
 }
 
 // Serve a new connection.
 func (srv *Server) serve(a net.Addr, h Handler, m []byte, u *net.UDPConn, s *SessionUDP, t *net.TCPConn) {
 	w := &response{tsigSecret: srv.TsigSecret, udp: u, tcp: t, remoteAddr: a, udpSession: s}
-	q := 0
+	if srv.DecorateWriter != nil {
+		w.writer = srv.DecorateWriter(w)
+	} else {
+		w.writer = w
+	}
+
+	q := 0 // counter for the amount of TCP queries we get
+
 	defer func() {
 		if u != nil {
 			srv.wgUDP.Done()
@@ -451,6 +515,11 @@ func (srv *Server) serve(a net.Addr, h Handler, m []byte, u *net.UDPConn, s *Ses
 			srv.wgTCP.Done()
 		}
 	}()
+
+	reader := Reader(&defaultReader{srv})
+	if srv.DecorateReader != nil {
+		reader = srv.DecorateReader(reader)
+	}
 Redo:
 	req := new(Msg)
 	err := req.Unpack(m)
@@ -479,6 +548,12 @@ Redo:
 	h.ServeDNS(w, req) // Writes back to the client
 
 Exit:
+	// TODO(miek): make this number configurable?
+	if q > maxTCPQueries { // close socket after this many queries
+		w.Close()
+		return
+	}
+
 	if w.hijacked {
 		return // client calls Close()
 	}
@@ -490,14 +565,9 @@ Exit:
 	if srv.IdleTimeout != nil {
 		idleTimeout = srv.IdleTimeout()
 	}
-	m, e := srv.readTCP(w.tcp, idleTimeout)
+	m, e := reader.ReadTCP(w.tcp, idleTimeout)
 	if e == nil {
 		q++
-		// TODO(miek): make this number configurable?
-		if q > 128 { // close socket after this many queries
-			w.Close()
-			return
-		}
 		goto Redo
 	}
 	w.Close()
@@ -562,7 +632,7 @@ func (w *response) WriteMsg(m *Msg) (err error) {
 			if err != nil {
 				return err
 			}
-			_, err = w.Write(data)
+			_, err = w.writer.Write(data)
 			return err
 		}
 	}
@@ -570,7 +640,7 @@ func (w *response) WriteMsg(m *Msg) (err error) {
 	if err != nil {
 		return err
 	}
-	_, err = w.Write(data)
+	_, err = w.writer.Write(data)
 	return err
 }
 

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

@@ -20,7 +20,7 @@ func HelloServer(w ResponseWriter, req *Msg) {
 func HelloServerBadId(w ResponseWriter, req *Msg) {
 	m := new(Msg)
 	m.SetReply(req)
-	m.Id += 1
+	m.Id++
 
 	m.Extra = make([]RR, 1)
 	m.Extra[0] = &TXT{Hdr: RR_Header{Name: m.Question[0].Name, Rrtype: TypeTXT, Class: ClassINET, Ttl: 0}, Txt: []string{"Hello world"}}
@@ -397,3 +397,54 @@ func TestShutdownUDP(t *testing.T) {
 		t.Errorf("Could not shutdown test UDP server, %v", err)
 	}
 }
+
+type ExampleFrameLengthWriter struct {
+	Writer
+}
+
+func (e *ExampleFrameLengthWriter) Write(m []byte) (int, error) {
+	fmt.Println("writing raw DNS message of length", len(m))
+	return e.Writer.Write(m)
+}
+
+func ExampleDecorateWriter() {
+	// instrument raw DNS message writing
+	wf := DecorateWriter(func(w Writer) Writer {
+		return &ExampleFrameLengthWriter{w}
+	})
+
+	// simple UDP server
+	pc, err := net.ListenPacket("udp", "127.0.0.1:0")
+	if err != nil {
+		fmt.Println(err.Error())
+		return
+	}
+	server := &Server{
+		PacketConn:     pc,
+		DecorateWriter: wf,
+	}
+
+	waitLock := sync.Mutex{}
+	waitLock.Lock()
+	server.NotifyStartedFunc = waitLock.Unlock
+	defer server.Shutdown()
+
+	go func() {
+		server.ActivateAndServe()
+		pc.Close()
+	}()
+
+	waitLock.Lock()
+
+	HandleFunc("miek.nl.", HelloServer)
+
+	c := new(Client)
+	m := new(Msg)
+	m.SetQuestion("miek.nl.", TypeTXT)
+	_, _, err = c.Exchange(m, pc.LocalAddr().String())
+	if err != nil {
+		fmt.Println("failed to exchange", err.Error())
+		return
+	}
+	// Output: writing raw DNS message of length 56
+}

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

@@ -13,7 +13,7 @@ import (
 // Sign signs a dns.Msg. It fills the signature with the appropriate data.
 // The SIG record should have the SignerName, KeyTag, Algorithm, Inception
 // and Expiration set.
-func (rr *SIG) Sign(k PrivateKey, m *Msg) ([]byte, error) {
+func (rr *SIG) Sign(k crypto.Signer, m *Msg) ([]byte, error) {
 	if k == nil {
 		return nil, ErrPrivKey
 	}
@@ -41,31 +41,26 @@ func (rr *SIG) Sign(k PrivateKey, m *Msg) ([]byte, error) {
 		return nil, err
 	}
 	buf = buf[:off:cap(buf)]
-	var hash crypto.Hash
-	switch rr.Algorithm {
-	case DSA, RSASHA1:
-		hash = crypto.SHA1
-	case RSASHA256, ECDSAP256SHA256:
-		hash = crypto.SHA256
-	case ECDSAP384SHA384:
-		hash = crypto.SHA384
-	case RSASHA512:
-		hash = crypto.SHA512
-	default:
+
+	hash, ok := AlgorithmToHash[rr.Algorithm]
+	if !ok {
 		return nil, ErrAlg
 	}
+
 	hasher := hash.New()
 	// Write SIG rdata
 	hasher.Write(buf[len(mbuf)+1+2+2+4+2:])
 	// Write message
 	hasher.Write(buf[:len(mbuf)])
-	hashed := hasher.Sum(nil)
 
-	sig, err := k.Sign(hashed, rr.Algorithm)
+	signature, err := sign(k, hasher.Sum(nil), hash, rr.Algorithm)
 	if err != nil {
 		return nil, err
 	}
-	rr.Signature = toBase64(sig)
+
+	rr.Signature = toBase64(signature)
+	sig := string(signature)
+
 	buf = append(buf, sig...)
 	if len(buf) > int(^uint16(0)) {
 		return nil, ErrBuf

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

@@ -1,6 +1,7 @@
 package dns
 
 import (
+	"crypto"
 	"testing"
 	"time"
 )
@@ -11,7 +12,7 @@ func TestSIG0(t *testing.T) {
 	}
 	m := new(Msg)
 	m.SetQuestion("example.org.", TypeSOA)
-	for _, alg := range []uint8{DSA, ECDSAP256SHA256, ECDSAP384SHA384, RSASHA1, RSASHA256, RSASHA512} {
+	for _, alg := range []uint8{ECDSAP256SHA256, ECDSAP384SHA384, RSASHA1, RSASHA256, RSASHA512} {
 		algstr := AlgorithmToString[alg]
 		keyrr := new(KEY)
 		keyrr.Hdr.Name = algstr + "."
@@ -40,7 +41,7 @@ func TestSIG0(t *testing.T) {
 		sigrr.Inception = now - 300
 		sigrr.KeyTag = keyrr.KeyTag()
 		sigrr.SignerName = keyrr.Hdr.Name
-		mb, err := sigrr.Sign(pk, m)
+		mb, err := sigrr.Sign(pk.(crypto.Signer), m)
 		if err != nil {
 			t.Errorf("Failed to sign message using “%s”: %v", algstr, err)
 			continue
@@ -79,7 +80,7 @@ func TestSIG0(t *testing.T) {
 		}
 		sigrr.Expiration = 2
 		sigrr.Inception = 1
-		mb, _ = sigrr.Sign(pk, m)
+		mb, _ = sigrr.Sign(pk.(crypto.Signer), m)
 		if err := sigrr.Verify(keyrr, mb); err == nil {
 			t.Errorf("Verify succeeded on an expired message using “%s”", algstr)
 			continue

+ 13 - 25
Godeps/_workspace/src/github.com/miekg/dns/types.go

@@ -46,7 +46,6 @@ const (
 	TypeX25        uint16 = 19
 	TypeISDN       uint16 = 20
 	TypeRT         uint16 = 21
-	TypeNSAP       uint16 = 22
 	TypeNSAPPTR    uint16 = 23
 	TypeSIG        uint16 = 24
 	TypeKEY        uint16 = 25
@@ -92,26 +91,24 @@ const (
 	TypeLP         uint16 = 107
 	TypeEUI48      uint16 = 108
 	TypeEUI64      uint16 = 109
+	TypeURI        uint16 = 256
+	TypeCAA        uint16 = 257
 
 	TypeTKEY uint16 = 249
 	TypeTSIG uint16 = 250
 
 	// valid Question.Qtype only
-
 	TypeIXFR  uint16 = 251
 	TypeAXFR  uint16 = 252
 	TypeMAILB uint16 = 253
 	TypeMAILA uint16 = 254
 	TypeANY   uint16 = 255
 
-	TypeURI      uint16 = 256
-	TypeCAA      uint16 = 257
 	TypeTA       uint16 = 32768
 	TypeDLV      uint16 = 32769
 	TypeReserved uint16 = 65535
 
 	// valid Question.Qclass
-
 	ClassINET   = 1
 	ClassCSNET  = 2
 	ClassCHAOS  = 3
@@ -119,8 +116,7 @@ const (
 	ClassNONE   = 254
 	ClassANY    = 255
 
-	// Msg.rcode
-
+	// Message Response Codes.
 	RcodeSuccess        = 0
 	RcodeFormatError    = 1
 	RcodeServerFailure  = 2
@@ -141,8 +137,7 @@ const (
 	RcodeBadAlg         = 21
 	RcodeBadTrunc       = 22 // TSIG
 
-	// Opcode, there is no 3
-
+	// Message Opcodes. There is no 3.
 	OpcodeQuery  = 0
 	OpcodeIQuery = 1
 	OpcodeStatus = 2
@@ -150,7 +145,7 @@ const (
 	OpcodeUpdate = 5
 )
 
-// The wire format for the DNS packet header.
+// Headers is the wire format for the DNS packet header.
 type Header struct {
 	Id                                 uint16
 	Bits                               uint16
@@ -179,7 +174,7 @@ const (
 	LOC_ALTITUDEBASE = 100000
 )
 
-// RFC 4398, Section 2.1
+// Different Certificate Types, see RFC 4398, Section 2.1
 const (
 	CertPKIX = 1 + iota
 	CertSPKI
@@ -193,6 +188,8 @@ const (
 	CertOID = 254
 )
 
+// CertTypeToString converts the Cert Type to its string representation.
+// See RFC 4398 and RFC 6944.
 var CertTypeToString = map[uint16]string{
 	CertPKIX:    "PKIX",
 	CertSPKI:    "SPKI",
@@ -206,6 +203,7 @@ var CertTypeToString = map[uint16]string{
 	CertOID:     "OID",
 }
 
+// StringToCertType is the reverseof CertTypeToString.
 var StringToCertType = reverseInt16(CertTypeToString)
 
 // Question holds a DNS question. There can be multiple questions in the
@@ -229,6 +227,8 @@ func (q *Question) len() int {
 	return l + 4
 }
 
+// ANY is a wildcard record. See RFC 1035, Section 3.2.3. ANY
+// is named "*" there.
 type ANY struct {
 	Hdr RR_Header
 	// Does not have any rdata
@@ -702,7 +702,7 @@ func (rr *NAPTR) len() int {
 		len(rr.Regexp) + 1 + len(rr.Replacement) + 1
 }
 
-// See RFC 4398.
+// The CERT resource record, see RFC 4398.
 type CERT struct {
 	Hdr         RR_Header
 	Type        uint16
@@ -738,7 +738,7 @@ func (rr *CERT) len() int {
 		base64.StdEncoding.DecodedLen(len(rr.Certificate))
 }
 
-// See RFC 2672.
+// The DNAME resource record, see RFC 2672.
 type DNAME struct {
 	Hdr    RR_Header
 	Target string `dns:"domain-name"`
@@ -850,7 +850,6 @@ func cmToM(m, e uint8) string {
 	return s
 }
 
-// String returns a string version of a LOC
 func (rr *LOC) String() string {
 	s := rr.Hdr.String()
 
@@ -1180,16 +1179,6 @@ func (rr *RKEY) String() string {
 		" " + rr.PublicKey
 }
 
-type NSAP struct {
-	Hdr  RR_Header
-	Nsap string
-}
-
-func (rr *NSAP) Header() *RR_Header { return &rr.Hdr }
-func (rr *NSAP) copy() RR           { return &NSAP{*rr.Hdr.copyHeader(), rr.Nsap} }
-func (rr *NSAP) String() string     { return rr.Hdr.String() + "0x" + rr.Nsap }
-func (rr *NSAP) len() int           { return rr.Hdr.len() + 1 + len(rr.Nsap) + 1 }
-
 type NSAPPTR struct {
 	Hdr RR_Header
 	Ptr string `dns:"domain-name"`
@@ -1721,7 +1710,6 @@ var typeToRR = map[uint16]func() RR{
 	TypeNINFO:      func() RR { return new(NINFO) },
 	TypeNIMLOC:     func() RR { return new(NIMLOC) },
 	TypeNS:         func() RR { return new(NS) },
-	TypeNSAP:       func() RR { return new(NSAP) },
 	TypeNSAPPTR:    func() RR { return new(NSAPPTR) },
 	TypeNSEC3:      func() RR { return new(NSEC3) },
 	TypeNSEC3PARAM: func() RR { return new(NSEC3PARAM) },

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

@@ -7,11 +7,14 @@ import (
 	"syscall"
 )
 
+// SessionUDP holds the remote address and the associated
+// out-of-band data.
 type SessionUDP struct {
 	raddr   *net.UDPAddr
 	context []byte
 }
 
+// RemoteAddr returns the remote network address.
 func (s *SessionUDP) RemoteAddr() net.Addr { return s.raddr }
 
 // setUDPSocketOptions sets the UDP socket options.

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

@@ -91,7 +91,6 @@ func (t *Transfer) inAxfr(id uint16, c chan *Envelope) {
 			c <- &Envelope{in.Answer, nil}
 		}
 	}
-	panic("dns: not reached")
 }
 
 func (t *Transfer) inIxfr(id uint16, c chan *Envelope) {

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

@@ -1,3 +1,5 @@
+// +build net
+
 package dns
 
 import (
@@ -16,7 +18,8 @@ func getIP(s string) string {
 
 // flaky, need to setup local server and test from
 // that.
-func testClientAXFR(t *testing.T) {
+func TestAXFR_Miek(t *testing.T) {
+	// This test runs against a server maintained by Miek
 	if testing.Short() {
 		return
 	}
@@ -43,7 +46,8 @@ func testClientAXFR(t *testing.T) {
 }
 
 // fails.
-func testClientAXFRMultipleEnvelopes(t *testing.T) {
+func TestAXFR_NLNL_MultipleEnvelopes(t *testing.T) {
+	// This test runs against a server maintained by NLnet Labs
 	if testing.Short() {
 		return
 	}
@@ -65,7 +69,8 @@ func testClientAXFRMultipleEnvelopes(t *testing.T) {
 	}
 }
 
-func testClientTsigAXFR(t *testing.T) {
+func TestAXFR_Miek_Tsig(t *testing.T) {
+	// This test runs against a server maintained by Miek
 	if testing.Short() {
 		return
 	}
@@ -90,3 +95,67 @@ func testClientTsigAXFR(t *testing.T) {
 		}
 	}
 }
+
+func TestAXFR_SIDN_NSD3_NONE(t *testing.T)   { testAXFRSIDN(t, "nsd", "") }
+func TestAXFR_SIDN_NSD3_MD5(t *testing.T)    { testAXFRSIDN(t, "nsd", HmacMD5) }
+func TestAXFR_SIDN_NSD3_SHA1(t *testing.T)   { testAXFRSIDN(t, "nsd", HmacSHA1) }
+func TestAXFR_SIDN_NSD3_SHA256(t *testing.T) { testAXFRSIDN(t, "nsd", HmacSHA256) }
+
+func TestAXFR_SIDN_NSD4_NONE(t *testing.T)   { testAXFRSIDN(t, "nsd4", "") }
+func TestAXFR_SIDN_NSD4_MD5(t *testing.T)    { testAXFRSIDN(t, "nsd4", HmacMD5) }
+func TestAXFR_SIDN_NSD4_SHA1(t *testing.T)   { testAXFRSIDN(t, "nsd4", HmacSHA1) }
+func TestAXFR_SIDN_NSD4_SHA256(t *testing.T) { testAXFRSIDN(t, "nsd4", HmacSHA256) }
+
+func TestAXFR_SIDN_BIND9_NONE(t *testing.T)   { testAXFRSIDN(t, "bind9", "") }
+func TestAXFR_SIDN_BIND9_MD5(t *testing.T)    { testAXFRSIDN(t, "bind9", HmacMD5) }
+func TestAXFR_SIDN_BIND9_SHA1(t *testing.T)   { testAXFRSIDN(t, "bind9", HmacSHA1) }
+func TestAXFR_SIDN_BIND9_SHA256(t *testing.T) { testAXFRSIDN(t, "bind9", HmacSHA256) }
+
+func TestAXFR_SIDN_KNOT_NONE(t *testing.T)   { testAXFRSIDN(t, "knot", "") }
+func TestAXFR_SIDN_KNOT_MD5(t *testing.T)    { testAXFRSIDN(t, "knot", HmacMD5) }
+func TestAXFR_SIDN_KNOT_SHA1(t *testing.T)   { testAXFRSIDN(t, "knot", HmacSHA1) }
+func TestAXFR_SIDN_KNOT_SHA256(t *testing.T) { testAXFRSIDN(t, "knot", HmacSHA256) }
+
+func TestAXFR_SIDN_POWERDNS_NONE(t *testing.T)   { testAXFRSIDN(t, "powerdns", "") }
+func TestAXFR_SIDN_POWERDNS_MD5(t *testing.T)    { testAXFRSIDN(t, "powerdns", HmacMD5) }
+func TestAXFR_SIDN_POWERDNS_SHA1(t *testing.T)   { testAXFRSIDN(t, "powerdns", HmacSHA1) }
+func TestAXFR_SIDN_POWERDNS_SHA256(t *testing.T) { testAXFRSIDN(t, "powerdns", HmacSHA256) }
+
+func TestAXFR_SIDN_YADIFA_NONE(t *testing.T)   { testAXFRSIDN(t, "yadifa", "") }
+func TestAXFR_SIDN_YADIFA_MD5(t *testing.T)    { testAXFRSIDN(t, "yadifa", HmacMD5) }
+func TestAXFR_SIDN_YADIFA_SHA1(t *testing.T)   { testAXFRSIDN(t, "yadifa", HmacSHA1) }
+func TestAXFR_SIDN_YADIFA_SHA256(t *testing.T) { testAXFRSIDN(t, "yadifa", HmacSHA256) }
+
+func testAXFRSIDN(t *testing.T, host, alg string) {
+	// This tests run against a server maintained by SIDN labs, see:
+	// https://workbench.sidnlabs.nl/
+	if testing.Short() {
+		return
+	}
+	x := new(Transfer)
+	x.TsigSecret = map[string]string{
+		"wb_md5.":          "Wu/utSasZUkoeCNku152Zw==",
+		"wb_sha1_longkey.": "uhMpEhPq/RAD9Bt4mqhfmi+7ZdKmjLQb/lcrqYPXR4s/nnbsqw==",
+		"wb_sha256.":       "npfrIJjt/MJOjGJoBNZtsjftKMhkSpIYMv2RzRZt1f8=",
+	}
+	keyname := map[string]string{
+		HmacMD5:    "wb_md5.",
+		HmacSHA1:   "wb_sha1_longkey.",
+		HmacSHA256: "wb_sha256.",
+	}[alg]
+
+	m := new(Msg)
+	m.SetAxfr("types.wb.sidnlabs.nl.")
+	if keyname != "" {
+		m.SetTsig(keyname, alg, 300, time.Now().Unix())
+	}
+	c, err := x.In(m, host+".sidnlabs.nl:53")
+	if err != nil {
+		t.Fatal(err)
+	}
+	for e := range c {
+		if e.Error != nil {
+			t.Fatal(e.Error)
+		}
+	}
+}

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

@@ -141,11 +141,11 @@ func modToPrintf(s string) (string, int, string) {
 		return "", 0, "bad base in $GENERATE"
 	}
 	offset, err := strconv.Atoi(xs[0])
-	if err != nil {
+	if err != nil || offset > 255 {
 		return "", 0, "bad offset in $GENERATE"
 	}
 	width, err := strconv.Atoi(xs[1])
-	if err != nil {
+	if err != nil || width > 255 {
 		return "", offset, "bad width in $GENERATE"
 	}
 	switch {

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

@@ -131,11 +131,11 @@ func ReadRR(q io.Reader, filename string) (RR, error) {
 	return r.RR, nil
 }
 
-// ParseZone reads a RFC 1035 style one from r. It returns *Tokens on the
+// ParseZone reads a RFC 1035 style zonefile from r. It returns *Tokens on the
 // returned channel, which consist out the parsed RR, a potential comment or an error.
 // If there is an error the RR is nil. The string file is only used
 // in error reporting. The string origin is used as the initial origin, as
-// if the file would start with: $ORIGIN origin  .
+// if the file would start with: $ORIGIN origin .
 // The directives $INCLUDE, $ORIGIN, $TTL and $GENERATE are supported.
 // The channel t is closed by ParseZone when the end of r is reached.
 //
@@ -152,7 +152,7 @@ func ReadRR(q io.Reader, filename string) (RR, error) {
 //
 //	foo. IN A 10.0.0.1 ; this is a comment
 //
-// The text "; this is comment" is returned in Token.Comment . Comments inside the
+// The text "; this is comment" is returned in Token.Comment. Comments inside the
 // RR are discarded. Comments on a line by themselves are discarded too.
 func ParseZone(r io.Reader, origin, file string) chan *Token {
 	return parseZoneHelper(r, origin, file, 10000)
@@ -281,7 +281,7 @@ func parseZone(r io.Reader, origin, f string, t chan *Token, include int) {
 			case zBlank:
 				l := <-c
 				if l.value == zString {
-					if _, ok := IsDomainName(l.token); !ok {
+					if _, ok := IsDomainName(l.token); !ok || l.length == 0 || l.err {
 						t <- &Token{Error: &ParseError{f, "bad origin name", l}}
 						return
 					}
@@ -806,7 +806,11 @@ func zlexer(s *scan, c chan lex) {
 
 // Extract the class number from CLASSxx
 func classToInt(token string) (uint16, bool) {
-	class, ok := strconv.Atoi(token[5:])
+	offset := 5
+	if len(token) < offset+1 {
+		return 0, false
+	}
+	class, ok := strconv.Atoi(token[offset:])
 	if ok != nil || class > maxUint16 {
 		return 0, false
 	}
@@ -815,7 +819,11 @@ func classToInt(token string) (uint16, bool) {
 
 // Extract the rr number from TYPExxx
 func typeToInt(token string) (uint16, bool) {
-	typ, ok := strconv.Atoi(token[4:])
+	offset := 4
+	if len(token) < offset+1 {
+		return 0, false
+	}
+	typ, ok := strconv.Atoi(token[offset:])
 	if ok != nil || typ > maxUint16 {
 		return 0, false
 	}

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 136 - 140
Godeps/_workspace/src/github.com/miekg/dns/zscan_rr.go


برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است