diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index 7ba60e7ab..f45d7c8e8 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -82,7 +82,7 @@ }, { "ImportPath": "github.com/miekg/dns", - "Rev": "259969e797348d20e8c144a7573c23f06fa962f5" + "Rev": "7ff8d29c8b70b10f383a11f03b7bf5b7408bf41a" }, { "ImportPath": "github.com/miekg/pkcs11", diff --git a/Godeps/_workspace/src/github.com/miekg/dns/.travis.yml b/Godeps/_workspace/src/github.com/miekg/dns/.travis.yml index f0a9d223c..e09157b36 100644 --- a/Godeps/_workspace/src/github.com/miekg/dns/.travis.yml +++ b/Godeps/_workspace/src/github.com/miekg/dns/.travis.yml @@ -1,6 +1,6 @@ language: go go: - - 1.3 - 1.4 + - 1.5rc1 script: - go test -short -bench=. diff --git a/Godeps/_workspace/src/github.com/miekg/dns/README.md b/Godeps/_workspace/src/github.com/miekg/dns/README.md index 73d627098..6e980b5e0 100644 --- a/Godeps/_workspace/src/github.com/miekg/dns/README.md +++ b/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,7 @@ 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 Send pull request if you want to be listed here. @@ -81,7 +83,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 @@ -125,7 +127,7 @@ Example programs can be found in the `github.com/miekg/exdns` repository. * 6975 - Algorithm Understanding in DNSSEC * 7043 - EUI48/EUI64 records * 7314 - DNS (EDNS) EXPIRE Option -* xxxx - URI record (draft) +* 7553 - URI record * xxxx - EDNS0 DNS Update Lease (draft) ## Loosely based upon @@ -138,7 +140,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 and IPSECKEY; -* Missing in parsing: ISDN, UNSPEC, ATMA; -* NSEC(3) cover/match/closest enclose; -* Replies with TC bit are not parsed to the end; +* 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. diff --git a/Godeps/_workspace/src/github.com/miekg/dns/defaults.go b/Godeps/_workspace/src/github.com/miekg/dns/defaults.go index 09331c9f6..7c5ecae03 100644 --- a/Godeps/_workspace/src/github.com/miekg/dns/defaults.go +++ b/Godeps/_workspace/src/github.com/miekg/dns/defaults.go @@ -188,6 +188,33 @@ func IsFqdn(s string) bool { return s[l-1] == '.' } +// IsRRset checks if a set of RRs is a valid RRset as defined by RFC 2181. +// This means the RRs need to have the same type, name, and class. Returns true +// if the RR set is valid, otherwise false. +func IsRRset(rrset []RR) bool { + if len(rrset) == 0 { + return false + } + if len(rrset) == 1 { + return true + } + rrHeader := rrset[0].Header() + rrType := rrHeader.Rrtype + rrClass := rrHeader.Class + rrName := rrHeader.Name + + for _, rr := range rrset[1:] { + curRRHeader := rr.Header() + if curRRHeader.Rrtype != rrType || curRRHeader.Class != rrClass || curRRHeader.Name != rrName { + // Mismatch between the records, so this is not a valid rrset for + //signing/verifying + return false + } + } + + return true +} + // Fqdn return the fully qualified domain name from s. // If s is already fully qualified, it behaves as the identity function. func Fqdn(s string) string { diff --git a/Godeps/_workspace/src/github.com/miekg/dns/dnssec.go b/Godeps/_workspace/src/github.com/miekg/dns/dnssec.go index 21ef3775a..1a993a0e9 100644 --- a/Godeps/_workspace/src/github.com/miekg/dns/dnssec.go +++ b/Godeps/_workspace/src/github.com/miekg/dns/dnssec.go @@ -296,7 +296,7 @@ func (rr *RRSIG) Sign(k PrivateKey, rrset []RR) error { // This function copies the rdata of some RRs (to lowercase domain names) for the validation to work. func (rr *RRSIG) Verify(k *DNSKEY, rrset []RR) error { // First the easy checks - if len(rrset) == 0 { + if !IsRRset(rrset) { return ErrRRset } if rr.KeyTag != k.KeyTag() { @@ -314,14 +314,17 @@ func (rr *RRSIG) Verify(k *DNSKEY, rrset []RR) error { if k.Protocol != 3 { return ErrKey } - for _, r := range rrset { - if r.Header().Class != rr.Hdr.Class { - return ErrRRset - } - if r.Header().Rrtype != rr.TypeCovered { - return ErrRRset - } + + // IsRRset checked that we have at least one RR and that the RRs in + // the set have consistent type, class, and name. Also check that type and + // class matches the RRSIG record. + if rrset[0].Header().Class != rr.Hdr.Class { + return ErrRRset } + if rrset[0].Header().Rrtype != rr.TypeCovered { + return ErrRRset + } + // RFC 4035 5.3.2. Reconstructing the Signed Data // Copy the sig, except the rrsig data sigwire := new(rrsigWireFmt) @@ -409,7 +412,8 @@ func (rr *RRSIG) Verify(k *DNSKEY, rrset []RR) error { // ValidityPeriod uses RFC1982 serial arithmetic to calculate // if a signature period is valid. If t is the zero time, the -// current time is taken other t is. +// current time is taken other t is. Returns true if the signature +// is valid at the given time, otherwise returns false. func (rr *RRSIG) ValidityPeriod(t time.Time) bool { var utc int64 if t.IsZero() { diff --git a/Godeps/_workspace/src/github.com/miekg/dns/dnssec_test.go b/Godeps/_workspace/src/github.com/miekg/dns/dnssec_test.go index 48c22362c..0975ed507 100644 --- a/Godeps/_workspace/src/github.com/miekg/dns/dnssec_test.go +++ b/Godeps/_workspace/src/github.com/miekg/dns/dnssec_test.go @@ -656,3 +656,64 @@ PrivateKey: WURgWHCcYIYUPWgeLmiPY2DJJk02vgrmTfitxgqcL4vwW7BOrbawVmVe0d9V94SR` t.Fatalf("RRSIG record differs:\n%v\n%v", ourRRSIG, rrRRSIG.(*RRSIG)) } } + +func TestInvalidRRSet(t *testing.T) { + goodRecords := make([]RR, 2) + goodRecords[0] = &TXT{Hdr: RR_Header{Name: "name.cloudflare.com.", Rrtype: TypeTXT, Class: ClassINET, Ttl: 0}, Txt: []string{"Hello world"}} + goodRecords[1] = &TXT{Hdr: RR_Header{Name: "name.cloudflare.com.", Rrtype: TypeTXT, Class: ClassINET, Ttl: 0}, Txt: []string{"_o/"}} + + // Generate key + keyname := "cloudflare.com." + key := &DNSKEY{ + Hdr: RR_Header{Name: keyname, Rrtype: TypeDNSKEY, Class: ClassINET, Ttl: 0}, + Algorithm: ECDSAP256SHA256, + Flags: ZONE, + Protocol: 3, + } + privatekey, err := key.Generate(256) + if err != nil { + t.Fatal(err.Error()) + } + + // Need to fill in: Inception, Expiration, KeyTag, SignerName and Algorithm + curTime := time.Now() + signature := &RRSIG{ + Inception: uint32(curTime.Unix()), + Expiration: uint32(curTime.Add(time.Hour).Unix()), + KeyTag: key.KeyTag(), + SignerName: keyname, + Algorithm: ECDSAP256SHA256, + } + + // Inconsistent name between records + badRecords := make([]RR, 2) + badRecords[0] = &TXT{Hdr: RR_Header{Name: "name.cloudflare.com.", Rrtype: TypeTXT, Class: ClassINET, Ttl: 0}, Txt: []string{"Hello world"}} + badRecords[1] = &TXT{Hdr: RR_Header{Name: "nama.cloudflare.com.", Rrtype: TypeTXT, Class: ClassINET, Ttl: 0}, Txt: []string{"_o/"}} + + if IsRRset(badRecords) { + t.Fatal("Record set with inconsistent names considered valid") + } + + badRecords[0] = &TXT{Hdr: RR_Header{Name: "name.cloudflare.com.", Rrtype: TypeTXT, Class: ClassINET, Ttl: 0}, Txt: []string{"Hello world"}} + badRecords[1] = &A{Hdr: RR_Header{Name: "name.cloudflare.com.", Rrtype: TypeA, Class: ClassINET, Ttl: 0}} + + if IsRRset(badRecords) { + t.Fatal("Record set with inconsistent record types considered valid") + } + + badRecords[0] = &TXT{Hdr: RR_Header{Name: "name.cloudflare.com.", Rrtype: TypeTXT, Class: ClassINET, Ttl: 0}, Txt: []string{"Hello world"}} + badRecords[1] = &TXT{Hdr: RR_Header{Name: "name.cloudflare.com.", Rrtype: TypeTXT, Class: ClassCHAOS, Ttl: 0}, Txt: []string{"_o/"}} + + if IsRRset(badRecords) { + t.Fatal("Record set with inconsistent record class considered valid") + } + + // Sign the good record set and then make sure verification fails on the bad record set + if err := signature.Sign(privatekey, goodRecords); err != nil { + t.Fatal("Signing good records failed") + } + + if err := signature.Verify(key, badRecords); err != ErrRRset { + t.Fatal("Verification did not return ErrRRset with inconsistent records") + } +} diff --git a/Godeps/_workspace/src/github.com/miekg/dns/edns.go b/Godeps/_workspace/src/github.com/miekg/dns/edns.go index d2bfecbb2..5314c543b 100644 --- a/Godeps/_workspace/src/github.com/miekg/dns/edns.go +++ b/Godeps/_workspace/src/github.com/miekg/dns/edns.go @@ -192,6 +192,11 @@ func (e *EDNS0_NSID) String() string { return string(e.Nsid) } // e.Address = net.ParseIP("127.0.0.1").To4() // for IPv4 // // e.Address = net.ParseIP("2001:7b8:32a::2") // for IPV6 // o.Option = append(o.Option, e) +// +// Note: the spec (draft-ietf-dnsop-edns-client-subnet-00) has some insane logic +// for which netmask applies to the address. This code will parse all the +// available bits when unpacking (up to optlen). When packing it will apply +// SourceNetmask. If you need more advanced logic, patches welcome and good luck. type EDNS0_SUBNET struct { Code uint16 // Always EDNS0SUBNET Family uint16 // 1 for IP, 2 for IP6 @@ -218,38 +223,22 @@ func (e *EDNS0_SUBNET) pack() ([]byte, error) { if e.SourceNetmask > net.IPv4len*8 { return nil, errors.New("dns: bad netmask") } - ip := make([]byte, net.IPv4len) - a := e.Address.To4().Mask(net.CIDRMask(int(e.SourceNetmask), net.IPv4len*8)) - for i := 0; i < net.IPv4len; i++ { - if i+1 > len(e.Address) { - break - } - ip[i] = a[i] + if len(e.Address.To4()) != net.IPv4len { + return nil, errors.New("dns: bad address") } - needLength := e.SourceNetmask / 8 - if e.SourceNetmask%8 > 0 { - needLength++ - } - ip = ip[:needLength] - b = append(b, ip...) + ip := e.Address.To4().Mask(net.CIDRMask(int(e.SourceNetmask), net.IPv4len*8)) + needLength := (e.SourceNetmask + 8 - 1) / 8 // division rounding up + b = append(b, ip[:needLength]...) case 2: if e.SourceNetmask > net.IPv6len*8 { return nil, errors.New("dns: bad netmask") } - ip := make([]byte, net.IPv6len) - a := e.Address.Mask(net.CIDRMask(int(e.SourceNetmask), net.IPv6len*8)) - for i := 0; i < net.IPv6len; i++ { - if i+1 > len(e.Address) { - break - } - ip[i] = a[i] + if len(e.Address) != net.IPv6len { + return nil, errors.New("dns: bad address") } - needLength := e.SourceNetmask / 8 - if e.SourceNetmask%8 > 0 { - needLength++ - } - ip = ip[:needLength] - b = append(b, ip...) + ip := e.Address.Mask(net.CIDRMask(int(e.SourceNetmask), net.IPv6len*8)) + needLength := (e.SourceNetmask + 8 - 1) / 8 // division rounding up + b = append(b, ip[:needLength]...) default: return nil, errors.New("dns: bad address family") } @@ -257,8 +246,7 @@ func (e *EDNS0_SUBNET) pack() ([]byte, error) { } func (e *EDNS0_SUBNET) unpack(b []byte) error { - lb := len(b) - if lb < 4 { + if len(b) < 4 { return ErrBuf } e.Family, _ = unpackUint16(b, 0) @@ -266,25 +254,27 @@ func (e *EDNS0_SUBNET) unpack(b []byte) error { e.SourceScope = b[3] switch e.Family { case 1: - addr := make([]byte, 4) - for i := 0; i < int(e.SourceNetmask/8); i++ { - if i >= len(addr) || 4+i >= len(b) { - return ErrBuf - } + if e.SourceNetmask > net.IPv4len*8 || e.SourceScope > net.IPv4len*8 { + return errors.New("dns: bad netmask") + } + addr := make([]byte, net.IPv4len) + for i := 0; i < net.IPv4len && 4+i < len(b); i++ { addr[i] = b[4+i] } e.Address = net.IPv4(addr[0], addr[1], addr[2], addr[3]) case 2: - addr := make([]byte, 16) - for i := 0; i < int(e.SourceNetmask/8); i++ { - if i >= len(addr) || 4+i >= len(b) { - return ErrBuf - } + if e.SourceNetmask > net.IPv6len*8 || e.SourceScope > net.IPv6len*8 { + return errors.New("dns: bad netmask") + } + addr := make([]byte, net.IPv6len) + for i := 0; i < net.IPv6len && 4+i < len(b); i++ { addr[i] = b[4+i] } e.Address = net.IP{addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], addr[6], addr[7], addr[8], addr[9], addr[10], addr[11], addr[12], addr[13], addr[14], addr[15]} + default: + return errors.New("dns: bad address family") } return nil } diff --git a/Godeps/_workspace/src/github.com/miekg/dns/idn/punycode.go b/Godeps/_workspace/src/github.com/miekg/dns/idn/punycode.go index 26e407bfc..9167e1f86 100644 --- a/Godeps/_workspace/src/github.com/miekg/dns/idn/punycode.go +++ b/Godeps/_workspace/src/github.com/miekg/dns/idn/punycode.go @@ -5,6 +5,7 @@ import ( "bytes" "strings" "unicode" + "unicode/utf8" "github.com/letsencrypt/boulder/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 { diff --git a/Godeps/_workspace/src/github.com/miekg/dns/idn/punycode_test.go b/Godeps/_workspace/src/github.com/miekg/dns/idn/punycode_test.go index f8b355ca7..9c9a15f0b 100644 --- a/Godeps/_workspace/src/github.com/miekg/dns/idn/punycode_test.go +++ b/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) { diff --git a/Godeps/_workspace/src/github.com/miekg/dns/msg.go b/Godeps/_workspace/src/github.com/miekg/dns/msg.go index 34896a75c..eb7c0f2fa 100644 --- a/Godeps/_workspace/src/github.com/miekg/dns/msg.go +++ b/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 ... @@ -51,8 +49,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 +134,6 @@ var TypeToString = map[uint16]string{ TypeNINFO: "NINFO", TypeNIMLOC: "NIMLOC", TypeNS: "NS", - TypeNSAP: "NSAP", TypeNSAPPTR: "NSAP-PTR", TypeNSEC3: "NSEC3", TypeNSEC3PARAM: "NSEC3PARAM", @@ -237,7 +232,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 @@ -413,9 +408,6 @@ Loop: case 0x00: if c == 0x00 { // end of name - if len(s) == 0 { - return ".", off, nil - } break Loop } // literal string @@ -476,6 +468,9 @@ Loop: if ptr == 0 { off1 = off } + if len(s) == 0 { + s = []byte(".") + } return string(s), off1, nil } @@ -573,17 +568,16 @@ func packOctetString(s string, msg []byte, offset int, tmp []byte) (int, error) return offset, nil } -func unpackTxt(msg []byte, offset, rdend int) ([]string, int, error) { - var err error - var ss []string +func unpackTxt(msg []byte, off0 int) (ss []string, off int, err error) { + off = off0 var s string - for offset < rdend && err == nil { - s, offset, err = unpackTxtString(msg, offset) + for off < len(msg) && err == nil { + s, off, err = unpackTxtString(msg, off) if err == nil { ss = append(ss, s) } } - return ss, offset, err + return } func unpackTxtString(msg []byte, offset int) (string, int, error) { @@ -748,58 +742,49 @@ func packStructValue(val reflect.Value, msg []byte, off int, compression map[str if val.Field(i).Len() == 0 { break } - var bitmapbyte uint16 + off1 := off for j := 0; j < val.Field(i).Len(); j++ { - serv := uint16((fv.Index(j).Uint())) - bitmapbyte = uint16(serv / 8) - if int(bitmapbyte) > lenmsg { - return lenmsg, &Error{err: "overflow packing wks"} + serv := int(fv.Index(j).Uint()) + if off+serv/8+1 > len(msg) { + return len(msg), &Error{err: "overflow packing wks"} + } + msg[off+serv/8] |= byte(1 << (7 - uint(serv%8))) + if off+serv/8+1 > off1 { + off1 = off + serv/8 + 1 } - bit := uint16(serv) - bitmapbyte*8 - msg[bitmapbyte] = byte(1 << (7 - bit)) } - off += int(bitmapbyte) + off = off1 case `dns:"nsec"`: // NSEC/NSEC3 // This is the uint16 type bitmap if val.Field(i).Len() == 0 { // Do absolutely nothing break } - - lastwindow := uint16(0) - length := uint16(0) - if off+2 > lenmsg { - return lenmsg, &Error{err: "overflow packing nsecx"} - } + var lastwindow, lastlength uint16 for j := 0; j < val.Field(i).Len(); j++ { - t := uint16((fv.Index(j).Uint())) - window := uint16(t / 256) - if lastwindow != window { + t := uint16(fv.Index(j).Uint()) + window := t / 256 + length := (t-window*256)/8 + 1 + if window > lastwindow && lastlength != 0 { // New window, jump to the new offset - off += int(length) + 3 - if off > lenmsg { - return lenmsg, &Error{err: "overflow packing nsecx bitmap"} - } + off += int(lastlength) + 2 + lastlength = 0 } - length = (t - window*256) / 8 - bit := t - (window * 256) - (length * 8) - if off+2+int(length) > lenmsg { - return lenmsg, &Error{err: "overflow packing nsecx bitmap"} + if window < lastwindow || length < lastlength { + return len(msg), &Error{err: "nsec bits out of order"} + } + if off+2+int(length) > len(msg) { + return len(msg), &Error{err: "overflow packing nsec"} } - // Setting the window # msg[off] = byte(window) // Setting the octets length - msg[off+1] = byte(length + 1) + msg[off+1] = byte(length) // Setting the bit value for the type in the right octet - msg[off+2+int(length)] |= byte(1 << (7 - bit)) - lastwindow = window - } - off += 2 + int(length) - off++ - if off > lenmsg { - return lenmsg, &Error{err: "overflow packing nsecx bitmap"} + msg[off+1+int(length)] |= byte(1 << (7 - (t % 8))) + lastwindow, lastlength = window, length } + off += int(lastlength) + 2 } case reflect.Struct: off, err = packStructValue(fv, msg, off, compression, compress) @@ -957,17 +942,11 @@ func packStructCompress(any interface{}, msg []byte, off int, compression map[st return off, err } -// TODO(miek): Fix use of rdlength here - // Unpack a reflect.StructValue from msg. // Same restrictions as packStructValue. func unpackStructValue(val reflect.Value, msg []byte, off int) (off1 int, err error) { - var lenrd int lenmsg := len(msg) for i := 0; i < val.NumField(); i++ { - if lenrd != 0 && lenrd == off { - break - } if off > lenmsg { return lenmsg, &Error{"bad offset unpacking"} } @@ -979,7 +958,7 @@ func unpackStructValue(val reflect.Value, msg []byte, off int) (off1 int, err er // therefore it's expected that this interface would be PrivateRdata switch data := fv.Interface().(type) { case PrivateRdata: - n, err := data.Unpack(msg[off:lenrd]) + n, err := data.Unpack(msg[off:]) if err != nil { return lenmsg, err } @@ -995,7 +974,7 @@ func unpackStructValue(val reflect.Value, msg []byte, off int) (off1 int, err er // HIP record slice of name (or none) var servers []string var s string - for off < lenrd { + for off < lenmsg { s, off, err = UnpackDomainName(msg, off) if err != nil { return lenmsg, err @@ -1004,17 +983,17 @@ func unpackStructValue(val reflect.Value, msg []byte, off int) (off1 int, err er } fv.Set(reflect.ValueOf(servers)) case `dns:"txt"`: - if off == lenmsg || lenrd == off { + if off == lenmsg { break } var txt []string - txt, off, err = unpackTxt(msg, off, lenrd) + txt, off, err = unpackTxt(msg, off) if err != nil { return lenmsg, err } fv.Set(reflect.ValueOf(txt)) case `dns:"opt"`: // edns0 - if off == lenrd { + if off == lenmsg { // This is an EDNS0 (OPT Record) with no rdata // We can safely return here. break @@ -1022,12 +1001,12 @@ func unpackStructValue(val reflect.Value, msg []byte, off int) (off1 int, err er var edns []EDNS0 Option: code := uint16(0) - if off+2 > lenmsg { + if off+4 > lenmsg { return lenmsg, &Error{err: "overflow unpacking opt"} } code, off = unpackUint16(msg, off) optlen, off1 := unpackUint16(msg, off) - if off1+int(optlen) > lenrd { + if off1+int(optlen) > lenmsg { return lenmsg, &Error{err: "overflow unpacking opt"} } switch code { @@ -1092,7 +1071,7 @@ func unpackStructValue(val reflect.Value, msg []byte, off int) (off1 int, err er edns = append(edns, e) off = off1 + int(optlen) } - if off < lenrd { + if off < lenmsg { goto Option } fv.Set(reflect.ValueOf(edns)) @@ -1103,10 +1082,10 @@ func unpackStructValue(val reflect.Value, msg []byte, off int) (off1 int, err er continue } } - if off == lenrd { + if off == lenmsg { break // dyn. update } - if off+net.IPv4len > lenrd || off+net.IPv4len > lenmsg { + if off+net.IPv4len > lenmsg { return lenmsg, &Error{err: "overflow unpacking a"} } fv.Set(reflect.ValueOf(net.IPv4(msg[off], msg[off+1], msg[off+2], msg[off+3]))) @@ -1118,10 +1097,10 @@ func unpackStructValue(val reflect.Value, msg []byte, off int) (off1 int, err er continue } } - if off == lenrd { + if off == lenmsg { break } - if off+net.IPv6len > lenrd || off+net.IPv6len > lenmsg { + if off+net.IPv6len > lenmsg { return lenmsg, &Error{err: "overflow unpacking aaaa"} } fv.Set(reflect.ValueOf(net.IP{msg[off], msg[off+1], msg[off+2], msg[off+3], msg[off+4], @@ -1132,7 +1111,7 @@ func unpackStructValue(val reflect.Value, msg []byte, off int) (off1 int, err er // Rest of the record is the bitmap var serv []uint16 j := 0 - for off < lenrd { + for off < lenmsg { if off+1 > lenmsg { return lenmsg, &Error{err: "overflow unpacking wks"} } @@ -1167,36 +1146,39 @@ func unpackStructValue(val reflect.Value, msg []byte, off int) (off1 int, err er } fv.Set(reflect.ValueOf(serv)) case `dns:"nsec"`: // NSEC/NSEC3 - if off == lenrd { + if off == len(msg) { break } // Rest of the record is the type bitmap - if off+2 > lenrd || off+2 > lenmsg { - return lenmsg, &Error{err: "overflow unpacking nsecx"} - } var nsec []uint16 length := 0 window := 0 - for off+2 < lenrd { + lastwindow := -1 + for off < len(msg) { + if off+2 > len(msg) { + return len(msg), &Error{err: "overflow unpacking nsecx"} + } window = int(msg[off]) length = int(msg[off+1]) - //println("off, windows, length, end", off, window, length, endrr) + off += 2 + if window <= lastwindow { + // RFC 4034: Blocks are present in the NSEC RR RDATA in + // increasing numerical order. + return len(msg), &Error{err: "out of order NSEC block"} + } if length == 0 { - // A length window of zero is strange. If there - // the window should not have been specified. Bail out - // println("dns: length == 0 when unpacking NSEC") - return lenmsg, &Error{err: "overflow unpacking nsecx"} + // RFC 4034: Blocks with no types present MUST NOT be included. + return len(msg), &Error{err: "empty NSEC block"} } if length > 32 { - return lenmsg, &Error{err: "overflow unpacking nsecx"} + return len(msg), &Error{err: "NSEC block too long"} + } + if off+length > len(msg) { + return len(msg), &Error{err: "overflowing NSEC block"} } - // Walk the bytes in the window - and check the bit settings... - off += 2 + // Walk the bytes in the window and extract the type bits for j := 0; j < length; j++ { - if off+j+1 > lenmsg { - return lenmsg, &Error{err: "overflow unpacking nsecx"} - } b := msg[off+j] // Check the bits one by one, and set the type if b&0x80 == 0x80 { @@ -1225,6 +1207,7 @@ func unpackStructValue(val reflect.Value, msg []byte, off int) (off1 int, err er } } off += length + lastwindow = window } fv.Set(reflect.ValueOf(nsec)) } @@ -1234,7 +1217,12 @@ func unpackStructValue(val reflect.Value, msg []byte, off int) (off1 int, err er return lenmsg, err } if val.Type().Field(i).Name == "Hdr" { - lenrd = off + int(val.FieldByName("Hdr").FieldByName("Rdlength").Uint()) + lenrd := off + int(val.FieldByName("Hdr").FieldByName("Rdlength").Uint()) + if lenrd > lenmsg { + return lenmsg, &Error{err: "overflowing header size"} + } + msg = msg[:lenrd] + lenmsg = len(msg) } case reflect.Uint8: if off == lenmsg { @@ -1265,6 +1253,9 @@ func unpackStructValue(val reflect.Value, msg []byte, off int) (off1 int, err er fv.SetUint(uint64(uint32(msg[off])<<24 | uint32(msg[off+1])<<16 | uint32(msg[off+2])<<8 | uint32(msg[off+3]))) off += 4 case reflect.Uint64: + if off == lenmsg { + break + } switch val.Type().Field(i).Tag { default: if off+8 > lenmsg { @@ -1291,30 +1282,26 @@ func unpackStructValue(val reflect.Value, msg []byte, off int) (off1 int, err er default: return lenmsg, &Error{"bad tag unpacking string: " + val.Type().Field(i).Tag.Get("dns")} case `dns:"octet"`: - strend := lenrd - if strend > lenmsg { - return lenmsg, &Error{err: "overflow unpacking octet"} - } - s = string(msg[off:strend]) - off = strend + s = string(msg[off:]) + off = lenmsg case `dns:"hex"`: - hexend := lenrd + hexend := lenmsg if val.FieldByName("Hdr").FieldByName("Rrtype").Uint() == uint64(TypeHIP) { hexend = off + int(val.FieldByName("HitLength").Uint()) } - if hexend > lenrd || hexend > lenmsg { - return lenmsg, &Error{err: "overflow unpacking hex"} + if hexend > lenmsg { + return lenmsg, &Error{err: "overflow unpacking HIP hex"} } s = hex.EncodeToString(msg[off:hexend]) off = hexend case `dns:"base64"`: // Rest of the RR is base64 encoded value - b64end := lenrd + b64end := lenmsg if val.FieldByName("Hdr").FieldByName("Rrtype").Uint() == uint64(TypeHIP) { b64end = off + int(val.FieldByName("PublicKeyLength").Uint()) } - if b64end > lenrd || b64end > lenmsg { - return lenmsg, &Error{err: "overflow unpacking base64"} + if b64end > lenmsg { + return lenmsg, &Error{err: "overflow unpacking HIP base64"} } s = toBase64(msg[off:b64end]) off = b64end @@ -1684,45 +1671,77 @@ func (dns *Msg) Unpack(msg []byte) (err error) { dns.CheckingDisabled = (dh.Bits & _CD) != 0 dns.Rcode = int(dh.Bits & 0xF) - // Arrays. - dns.Question = make([]Question, dh.Qdcount) - dns.Answer = make([]RR, dh.Ancount) - dns.Ns = make([]RR, dh.Nscount) - dns.Extra = make([]RR, dh.Arcount) + // 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) - for i := 0; i < len(dns.Question); i++ { - off, err = UnpackStruct(&dns.Question[i], msg, off) + var q Question + for i := 0; i < int(dh.Qdcount); i++ { + off1 := off + off, err = UnpackStruct(&q, msg, off) if err != nil { return err } + if off1 == off { // Offset does not increase anymore, dh.Qdcount is a lie! + dh.Qdcount = uint16(i) + break + } + + dns.Question = append(dns.Question, q) + } // If we see a TC bit being set we return here, without // an error, because technically it isn't an error. So return // without parsing the potentially corrupt packet and hitting an error. // TODO(miek): this isn't the best strategy! + // Better stragey would be: set boolean indicating truncated message, go forth and parse + // until we hit an error, return the message without the latest parsed rr if this boolean + // is true. if dns.Truncated { dns.Answer = nil dns.Ns = nil dns.Extra = nil return nil } - for i := 0; i < len(dns.Answer); i++ { - dns.Answer[i], off, err = UnpackRR(msg, off) + + 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) } - for i := 0; i < len(dns.Ns); i++ { - dns.Ns[i], off, err = UnpackRR(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 < len(dns.Extra); i++ { - dns.Extra[i], off, err = UnpackRR(msg, off) + 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) } if off != len(msg) { // TODO(miek) make this an error? diff --git a/Godeps/_workspace/src/github.com/miekg/dns/parse_test.go b/Godeps/_workspace/src/github.com/miekg/dns/parse_test.go index 1f2517270..36a586d2e 100644 --- a/Godeps/_workspace/src/github.com/miekg/dns/parse_test.go +++ b/Godeps/_workspace/src/github.com/miekg/dns/parse_test.go @@ -905,11 +905,8 @@ 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", @@ -1506,3 +1503,22 @@ func TestPackCAA(t *testing.T) { t.Fatalf("invalid flag for unpacked answer") } } + +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 \"\"", + } + for i, o := range lt { + rr, err := NewRR(i) + if err != nil { + t.Error("failed to parse RR: ", err) + continue + } + if rr.String() != o { + t.Errorf("`%s' should be equal to\n`%s', but is `%s'", i, o, rr.String()) + } else { + t.Logf("RR is OK: `%s'", rr.String()) + } + } +} diff --git a/Godeps/_workspace/src/github.com/miekg/dns/server.go b/Godeps/_workspace/src/github.com/miekg/dns/server.go index 5e4ec92ba..74d96264c 100644 --- a/Godeps/_workspace/src/github.com/miekg/dns/server.go +++ b/Godeps/_workspace/src/github.com/miekg/dns/server.go @@ -47,6 +47,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 @@ -197,6 +198,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 +261,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 @@ -244,9 +286,9 @@ func (srv *Server) ListenAndServe() error { srv.lock.Unlock() return &Error{err: "server already started"} } + defer srv.lock.Unlock() srv.stopUDP, srv.stopTCP = make(chan bool), make(chan bool) srv.started = true - srv.lock.Unlock() addr := srv.Addr if addr == "" { addr = ":domain" @@ -294,20 +336,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 +360,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 +369,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 +378,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 +426,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 +442,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 @@ -417,6 +466,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 +478,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 @@ -442,6 +496,12 @@ func (srv *Server) serveUDP(l *net.UDPConn) error { // 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} + if srv.DecorateWriter != nil { + w.writer = srv.DecorateWriter(w) + } else { + w.writer = w + } + q := 0 defer func() { if u != nil { @@ -451,6 +511,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) @@ -490,7 +555,7 @@ 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? @@ -562,7 +627,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 +635,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 } diff --git a/Godeps/_workspace/src/github.com/miekg/dns/server_test.go b/Godeps/_workspace/src/github.com/miekg/dns/server_test.go index dff0fb528..2ff606ac3 100644 --- a/Godeps/_workspace/src/github.com/miekg/dns/server_test.go +++ b/Godeps/_workspace/src/github.com/miekg/dns/server_test.go @@ -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 +} diff --git a/Godeps/_workspace/src/github.com/miekg/dns/types.go b/Godeps/_workspace/src/github.com/miekg/dns/types.go index 49813b1cf..98912e46b 100644 --- a/Godeps/_workspace/src/github.com/miekg/dns/types.go +++ b/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 @@ -503,7 +502,7 @@ func sprintName(s string) string { return string(dst) } -func sprintCAAValue(s string) string { +func sprintTxtOctet(s string) string { src := []byte(s) dst := make([]byte, 0, len(src)) dst = append(dst, '"') @@ -850,7 +849,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 +1178,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"` @@ -1329,27 +1317,15 @@ type URI struct { Hdr RR_Header Priority uint16 Weight uint16 - Target []string `dns:"txt"` + Target string `dns:"octet"` } func (rr *URI) Header() *RR_Header { return &rr.Hdr } -func (rr *URI) copy() RR { - cp := make([]string, len(rr.Target), cap(rr.Target)) - copy(cp, rr.Target) - return &URI{*rr.Hdr.copyHeader(), rr.Weight, rr.Priority, cp} -} - +func (rr *URI) copy() RR { return &URI{*rr.Hdr.copyHeader(), rr.Weight, rr.Priority, rr.Target} } +func (rr *URI) len() int { return rr.Hdr.len() + 4 + len(rr.Target) } func (rr *URI) String() string { return rr.Hdr.String() + strconv.Itoa(int(rr.Priority)) + - " " + strconv.Itoa(int(rr.Weight)) + sprintTxt(rr.Target) -} - -func (rr *URI) len() int { - l := rr.Hdr.len() + 4 - for _, t := range rr.Target { - l += len(t) + 1 - } - return l + " " + strconv.Itoa(int(rr.Weight)) + " " + sprintTxtOctet(rr.Target) } type DHCID struct { @@ -1571,7 +1547,7 @@ func (rr *CAA) Header() *RR_Header { return &rr.Hdr } func (rr *CAA) copy() RR { return &CAA{*rr.Hdr.copyHeader(), rr.Flag, rr.Tag, rr.Value} } func (rr *CAA) len() int { return rr.Hdr.len() + 2 + len(rr.Tag) + len(rr.Value) } func (rr *CAA) String() string { - return rr.Hdr.String() + strconv.Itoa(int(rr.Flag)) + " " + rr.Tag + " " + sprintCAAValue(rr.Value) + return rr.Hdr.String() + strconv.Itoa(int(rr.Flag)) + " " + rr.Tag + " " + sprintTxtOctet(rr.Value) } type UID struct { @@ -1733,7 +1709,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) }, diff --git a/Godeps/_workspace/src/github.com/miekg/dns/zgenerate.go b/Godeps/_workspace/src/github.com/miekg/dns/zgenerate.go index ae9253157..c506e9626 100644 --- a/Godeps/_workspace/src/github.com/miekg/dns/zgenerate.go +++ b/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 { diff --git a/Godeps/_workspace/src/github.com/miekg/dns/zscan.go b/Godeps/_workspace/src/github.com/miekg/dns/zscan.go index 06be9cc6d..40ba35c36 100644 --- a/Godeps/_workspace/src/github.com/miekg/dns/zscan.go +++ b/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 } diff --git a/Godeps/_workspace/src/github.com/miekg/dns/zscan_rr.go b/Godeps/_workspace/src/github.com/miekg/dns/zscan_rr.go index 3763d3f4c..32e79586f 100644 --- a/Godeps/_workspace/src/github.com/miekg/dns/zscan_rr.go +++ b/Godeps/_workspace/src/github.com/miekg/dns/zscan_rr.go @@ -145,7 +145,7 @@ func setA(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { return rr, nil, "" } rr.A = net.ParseIP(l.token) - if rr.A == nil { + if rr.A == nil || l.err { return nil, &ParseError{f, "bad A A", l}, "" } return rr, nil, "" @@ -160,7 +160,7 @@ func setAAAA(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { return rr, nil, "" } rr.AAAA = net.ParseIP(l.token) - if rr.AAAA == nil { + if rr.AAAA == nil || l.err { return nil, &ParseError{f, "bad AAAA AAAA", l}, "" } return rr, nil, "" @@ -180,7 +180,7 @@ func setNS(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { return rr, nil, "" } _, ok := IsDomainName(l.token) - if !ok { + if !ok || l.length == 0 || l.err { return nil, &ParseError{f, "bad NS Ns", l}, "" } if rr.Ns[l.length-1] != '.' { @@ -203,7 +203,7 @@ func setPTR(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { return rr, nil, "" } _, ok := IsDomainName(l.token) - if !ok { + if !ok || l.length == 0 || l.err { return nil, &ParseError{f, "bad PTR Ptr", l}, "" } if rr.Ptr[l.length-1] != '.' { @@ -226,7 +226,7 @@ func setNSAPPTR(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) return rr, nil, "" } _, ok := IsDomainName(l.token) - if !ok { + if !ok || l.length == 0 || l.err { return nil, &ParseError{f, "bad NSAP-PTR Ptr", l}, "" } if rr.Ptr[l.length-1] != '.' { @@ -248,7 +248,7 @@ func setRP(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { rr.Mbox = o } else { _, ok := IsDomainName(l.token) - if !ok { + if !ok || l.length == 0 || l.err { return nil, &ParseError{f, "bad RP Mbox", l}, "" } if rr.Mbox[l.length-1] != '.' { @@ -263,7 +263,7 @@ func setRP(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { return rr, nil, "" } _, ok := IsDomainName(l.token) - if !ok { + if !ok || l.length == 0 || l.err { return nil, &ParseError{f, "bad RP Txt", l}, "" } if rr.Txt[l.length-1] != '.' { @@ -286,7 +286,7 @@ func setMR(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { return rr, nil, "" } _, ok := IsDomainName(l.token) - if !ok { + if !ok || l.length == 0 || l.err { return nil, &ParseError{f, "bad MR Mr", l}, "" } if rr.Mr[l.length-1] != '.' { @@ -309,7 +309,7 @@ func setMB(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { return rr, nil, "" } _, ok := IsDomainName(l.token) - if !ok { + if !ok || l.length == 0 || l.err { return nil, &ParseError{f, "bad MB Mb", l}, "" } if rr.Mb[l.length-1] != '.' { @@ -332,7 +332,7 @@ func setMG(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { return rr, nil, "" } _, ok := IsDomainName(l.token) - if !ok { + if !ok || l.length == 0 || l.err { return nil, &ParseError{f, "bad MG Mg", l}, "" } if rr.Mg[l.length-1] != '.' { @@ -380,7 +380,7 @@ func setMINFO(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { rr.Rmail = o } else { _, ok := IsDomainName(l.token) - if !ok { + if !ok || l.length == 0 || l.err { return nil, &ParseError{f, "bad MINFO Rmail", l}, "" } if rr.Rmail[l.length-1] != '.' { @@ -395,7 +395,7 @@ func setMINFO(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { return rr, nil, "" } _, ok := IsDomainName(l.token) - if !ok { + if !ok || l.length == 0 || l.err { return nil, &ParseError{f, "bad MINFO Email", l}, "" } if rr.Email[l.length-1] != '.' { @@ -418,7 +418,7 @@ func setMF(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { return rr, nil, "" } _, ok := IsDomainName(l.token) - if !ok { + if !ok || l.length == 0 || l.err { return nil, &ParseError{f, "bad MF Mf", l}, "" } if rr.Mf[l.length-1] != '.' { @@ -441,7 +441,7 @@ func setMD(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { return rr, nil, "" } _, ok := IsDomainName(l.token) - if !ok { + if !ok || l.length == 0 || l.err { return nil, &ParseError{f, "bad MD Md", l}, "" } if rr.Md[l.length-1] != '.' { @@ -459,7 +459,7 @@ func setMX(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { return rr, nil, "" } i, e := strconv.Atoi(l.token) - if e != nil { + if e != nil || l.err { return nil, &ParseError{f, "bad MX Pref", l}, "" } rr.Preference = uint16(i) @@ -471,7 +471,7 @@ func setMX(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { return rr, nil, "" } _, ok := IsDomainName(l.token) - if !ok || l.length == 0 { + if !ok || l.length == 0 || l.err { return nil, &ParseError{f, "bad MX Mx", l}, "" } if rr.Mx[l.length-1] != '.' { @@ -500,7 +500,7 @@ func setRT(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { return rr, nil, "" } _, ok := IsDomainName(l.token) - if !ok || l.length == 0 { + if !ok || l.length == 0 || l.err { return nil, &ParseError{f, "bad RT Host", l}, "" } if rr.Host[l.length-1] != '.' { @@ -518,7 +518,7 @@ func setAFSDB(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { return rr, nil, "" } i, e := strconv.Atoi(l.token) - if e != nil { + if e != nil || l.err { return nil, &ParseError{f, "bad AFSDB Subtype", l}, "" } rr.Subtype = uint16(i) @@ -530,7 +530,7 @@ func setAFSDB(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { return rr, nil, "" } _, ok := IsDomainName(l.token) - if !ok || l.length == 0 { + if !ok || l.length == 0 || l.err { return nil, &ParseError{f, "bad AFSDB Hostname", l}, "" } if rr.Hostname[l.length-1] != '.' { @@ -544,6 +544,12 @@ func setX25(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { rr.Hdr = h l := <-c + if l.length == 0 { + return rr, nil, "" + } + if l.err { + return nil, &ParseError{f, "bad X25 PSDNAddress", l}, "" + } rr.PSDNAddress = l.token return rr, nil, "" } @@ -557,7 +563,7 @@ func setKX(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { return rr, nil, "" } i, e := strconv.Atoi(l.token) - if e != nil { + if e != nil || l.err { return nil, &ParseError{f, "bad KX Pref", l}, "" } rr.Preference = uint16(i) @@ -569,7 +575,7 @@ func setKX(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { return rr, nil, "" } _, ok := IsDomainName(l.token) - if !ok || l.length == 0 { + if !ok || l.length == 0 || l.err { return nil, &ParseError{f, "bad KX Exchanger", l}, "" } if rr.Exchanger[l.length-1] != '.' { @@ -592,7 +598,7 @@ func setCNAME(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { return rr, nil, "" } _, ok := IsDomainName(l.token) - if !ok || l.length == 0 { + if !ok || l.length == 0 || l.err { return nil, &ParseError{f, "bad CNAME Target", l}, "" } if rr.Target[l.length-1] != '.' { @@ -615,7 +621,7 @@ func setDNAME(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { return rr, nil, "" } _, ok := IsDomainName(l.token) - if !ok { + if !ok || l.length == 0 || l.err { return nil, &ParseError{f, "bad CNAME Target", l}, "" } if rr.Target[l.length-1] != '.' { @@ -638,7 +644,7 @@ func setSOA(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { rr.Ns = o } else { _, ok := IsDomainName(l.token) - if !ok { + if !ok || l.length == 0 || l.err { return nil, &ParseError{f, "bad SOA Ns", l}, "" } if rr.Ns[l.length-1] != '.' { @@ -652,7 +658,7 @@ func setSOA(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { rr.Mbox = o } else { _, ok := IsDomainName(l.token) - if !ok || l.length == 0 { + if !ok || l.length == 0 || l.err { return nil, &ParseError{f, "bad SOA Mbox", l}, "" } if rr.Mbox[l.length-1] != '.' { @@ -667,6 +673,9 @@ func setSOA(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { ) for i := 0; i < 5; i++ { l = <-c + if l.err { + return nil, &ParseError{f, "bad SOA zone parameter", l}, "" + } if j, e := strconv.Atoi(l.token); e != nil { if i == 0 { // Serial should be a number @@ -708,21 +717,21 @@ func setSRV(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { return rr, nil, "" } i, e := strconv.Atoi(l.token) - if e != nil { + if e != nil || l.err { return nil, &ParseError{f, "bad SRV Priority", l}, "" } rr.Priority = uint16(i) <-c // zBlank l = <-c // zString i, e = strconv.Atoi(l.token) - if e != nil { + if e != nil || l.err { return nil, &ParseError{f, "bad SRV Weight", l}, "" } rr.Weight = uint16(i) <-c // zBlank l = <-c // zString i, e = strconv.Atoi(l.token) - if e != nil { + if e != nil || l.err { return nil, &ParseError{f, "bad SRV Port", l}, "" } rr.Port = uint16(i) @@ -734,7 +743,7 @@ func setSRV(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { return rr, nil, "" } _, ok := IsDomainName(l.token) - if !ok || l.length == 0 { + if !ok || l.length == 0 || l.err { return nil, &ParseError{f, "bad SRV Target", l}, "" } if rr.Target[l.length-1] != '.' { @@ -752,14 +761,14 @@ func setNAPTR(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { return rr, nil, "" } i, e := strconv.Atoi(l.token) - if e != nil { + if e != nil || l.err { return nil, &ParseError{f, "bad NAPTR Order", l}, "" } rr.Order = uint16(i) <-c // zBlank l = <-c // zString i, e = strconv.Atoi(l.token) - if e != nil { + if e != nil || l.err { return nil, &ParseError{f, "bad NAPTR Preference", l}, "" } rr.Preference = uint16(i) @@ -828,7 +837,7 @@ func setNAPTR(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { return rr, nil, "" } _, ok := IsDomainName(l.token) - if !ok || l.length == 0 { + if !ok || l.length == 0 || l.err { return nil, &ParseError{f, "bad NAPTR Replacement", l}, "" } if rr.Replacement[l.length-1] != '.' { @@ -850,7 +859,7 @@ func setTALINK(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { rr.PreviousName = o } else { _, ok := IsDomainName(l.token) - if !ok { + if !ok || l.length == 0 || l.err { return nil, &ParseError{f, "bad TALINK PreviousName", l}, "" } if rr.PreviousName[l.length-1] != '.' { @@ -865,7 +874,7 @@ func setTALINK(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { return rr, nil, "" } _, ok := IsDomainName(l.token) - if !ok || l.length == 0 { + if !ok || l.length == 0 || l.err { return nil, &ParseError{f, "bad TALINK NextName", l}, "" } if rr.NextName[l.length-1] != '.' { @@ -887,7 +896,7 @@ func setLOC(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { if l.length == 0 { return rr, nil, "" } - if i, e := strconv.Atoi(l.token); e != nil { + if i, e := strconv.Atoi(l.token); e != nil || l.err { return nil, &ParseError{f, "bad LOC Latitude", l}, "" } else { rr.Latitude = 1000 * 60 * 60 * uint32(i) @@ -898,14 +907,14 @@ func setLOC(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { if rr.Latitude, ok = locCheckNorth(l.token, rr.Latitude); ok { goto East } - if i, e := strconv.Atoi(l.token); e != nil { + if i, e := strconv.Atoi(l.token); e != nil || l.err { return nil, &ParseError{f, "bad LOC Latitude minutes", l}, "" } else { rr.Latitude += 1000 * 60 * uint32(i) } <-c // zBlank l = <-c - if i, e := strconv.ParseFloat(l.token, 32); e != nil { + if i, e := strconv.ParseFloat(l.token, 32); e != nil || l.err { return nil, &ParseError{f, "bad LOC Latitude seconds", l}, "" } else { rr.Latitude += uint32(1000 * i) @@ -923,7 +932,7 @@ East: // East <-c // zBlank l = <-c - if i, e := strconv.Atoi(l.token); e != nil { + if i, e := strconv.Atoi(l.token); e != nil || l.err { return nil, &ParseError{f, "bad LOC Longitude", l}, "" } else { rr.Longitude = 1000 * 60 * 60 * uint32(i) @@ -934,14 +943,14 @@ East: if rr.Longitude, ok = locCheckEast(l.token, rr.Longitude); ok { goto Altitude } - if i, e := strconv.Atoi(l.token); e != nil { + if i, e := strconv.Atoi(l.token); e != nil || l.err { return nil, &ParseError{f, "bad LOC Longitude minutes", l}, "" } else { rr.Longitude += 1000 * 60 * uint32(i) } <-c // zBlank l = <-c - if i, e := strconv.ParseFloat(l.token, 32); e != nil { + if i, e := strconv.ParseFloat(l.token, 32); e != nil || l.err { return nil, &ParseError{f, "bad LOC Longitude seconds", l}, "" } else { rr.Longitude += uint32(1000 * i) @@ -958,6 +967,9 @@ East: Altitude: <-c // zBlank l = <-c + if l.length == 0 || l.err { + return nil, &ParseError{f, "bad LOC Altitude", l}, "" + } if l.token[len(l.token)-1] == 'M' || l.token[len(l.token)-1] == 'm' { l.token = l.token[0 : len(l.token)-1] } @@ -1014,17 +1026,23 @@ func setHIP(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { return rr, nil, l.comment } i, e := strconv.Atoi(l.token) - if e != nil { + if e != nil || l.err { return nil, &ParseError{f, "bad HIP PublicKeyAlgorithm", l}, "" } rr.PublicKeyAlgorithm = uint8(i) - <-c // zBlank - l = <-c // zString + <-c // zBlank + l = <-c // zString + if l.length == 0 || l.err { + return nil, &ParseError{f, "bad HIP Hit", l}, "" + } rr.Hit = l.token // This can not contain spaces, see RFC 5205 Section 6. rr.HitLength = uint8(len(rr.Hit)) / 2 - <-c // zBlank - l = <-c // zString + <-c // zBlank + l = <-c // zString + if l.length == 0 || l.err { + return nil, &ParseError{f, "bad HIP PublicKey", l}, "" + } rr.PublicKey = l.token // This cannot contain spaces rr.PublicKeyLength = uint16(base64.StdEncoding.DecodedLen(len(rr.PublicKey))) @@ -1036,10 +1054,11 @@ func setHIP(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { case zString: if l.token == "@" { xs = append(xs, o) + l = <-c continue } _, ok := IsDomainName(l.token) - if !ok || l.length == 0 { + if !ok || l.length == 0 || l.err { return nil, &ParseError{f, "bad HIP RendezvousServers", l}, "" } if l.token[l.length-1] != '.' { @@ -1075,7 +1094,7 @@ func setCERT(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { <-c // zBlank l = <-c // zString i, e := strconv.Atoi(l.token) - if e != nil { + if e != nil || l.err { return nil, &ParseError{f, "bad CERT KeyTag", l}, "" } rr.KeyTag = uint16(i) @@ -1139,21 +1158,21 @@ func setRRSIG(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { <-c // zBlank l = <-c i, err := strconv.Atoi(l.token) - if err != nil { + if err != nil || l.err { return nil, &ParseError{f, "bad RRSIG Algorithm", l}, "" } rr.Algorithm = uint8(i) <-c // zBlank l = <-c i, err = strconv.Atoi(l.token) - if err != nil { + if err != nil || l.err { return nil, &ParseError{f, "bad RRSIG Labels", l}, "" } rr.Labels = uint8(i) <-c // zBlank l = <-c i, err = strconv.Atoi(l.token) - if err != nil { + if err != nil || l.err { return nil, &ParseError{f, "bad RRSIG OrigTtl", l}, "" } rr.OrigTtl = uint32(i) @@ -1184,7 +1203,7 @@ func setRRSIG(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { <-c // zBlank l = <-c i, err = strconv.Atoi(l.token) - if err != nil { + if err != nil || l.err { return nil, &ParseError{f, "bad RRSIG KeyTag", l}, "" } rr.KeyTag = uint16(i) @@ -1195,7 +1214,7 @@ func setRRSIG(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { rr.SignerName = o } else { _, ok := IsDomainName(l.token) - if !ok || l.length == 0 { + if !ok || l.length == 0 || l.err { return nil, &ParseError{f, "bad RRSIG SignerName", l}, "" } if rr.SignerName[l.length-1] != '.' { @@ -1223,7 +1242,7 @@ func setNSEC(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { rr.NextDomain = o } else { _, ok := IsDomainName(l.token) - if !ok { + if !ok || l.length == 0 || l.err { return nil, &ParseError{f, "bad NSEC NextDomain", l}, "" } if rr.NextDomain[l.length-1] != '.' { @@ -1265,27 +1284,27 @@ func setNSEC3(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { return rr, nil, l.comment } i, e := strconv.Atoi(l.token) - if e != nil { + if e != nil || l.err { return nil, &ParseError{f, "bad NSEC3 Hash", l}, "" } rr.Hash = uint8(i) <-c // zBlank l = <-c i, e = strconv.Atoi(l.token) - if e != nil { + if e != nil || l.err { return nil, &ParseError{f, "bad NSEC3 Flags", l}, "" } rr.Flags = uint8(i) <-c // zBlank l = <-c i, e = strconv.Atoi(l.token) - if e != nil { + if e != nil || l.err { return nil, &ParseError{f, "bad NSEC3 Iterations", l}, "" } rr.Iterations = uint16(i) <-c l = <-c - if len(l.token) == 0 { + if len(l.token) == 0 || l.err { return nil, &ParseError{f, "bad NSEC3 Salt", l}, "" } rr.SaltLength = uint8(len(l.token)) / 2 @@ -1293,6 +1312,9 @@ func setNSEC3(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { <-c l = <-c + if len(l.token) == 0 || l.err { + return nil, &ParseError{f, "bad NSEC3 NextDomain", l}, "" + } rr.HashLength = 20 // Fix for NSEC3 (sha1 160 bits) rr.NextDomain = l.token @@ -1330,21 +1352,21 @@ func setNSEC3PARAM(h RR_Header, c chan lex, o, f string) (RR, *ParseError, strin return rr, nil, "" } i, e := strconv.Atoi(l.token) - if e != nil { + if e != nil || l.err { return nil, &ParseError{f, "bad NSEC3PARAM Hash", l}, "" } rr.Hash = uint8(i) <-c // zBlank l = <-c i, e = strconv.Atoi(l.token) - if e != nil { + if e != nil || l.err { return nil, &ParseError{f, "bad NSEC3PARAM Flags", l}, "" } rr.Flags = uint8(i) <-c // zBlank l = <-c i, e = strconv.Atoi(l.token) - if e != nil { + if e != nil || l.err { return nil, &ParseError{f, "bad NSEC3PARAM Iterations", l}, "" } rr.Iterations = uint16(i) @@ -1363,7 +1385,7 @@ func setEUI48(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { if l.length == 0 { return rr, nil, "" } - if l.length != 17 { + if l.length != 17 || l.err { return nil, &ParseError{f, "bad EUI48 Address", l}, "" } addr := make([]byte, 12) @@ -1395,7 +1417,7 @@ func setEUI64(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { if l.length == 0 { return rr, nil, "" } - if l.length != 23 { + if l.length != 23 || l.err { return nil, &ParseError{f, "bad EUI64 Address", l}, "" } addr := make([]byte, 16) @@ -1428,7 +1450,7 @@ func setWKS(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { return rr, nil, l.comment } rr.Address = net.ParseIP(l.token) - if rr.Address == nil { + if rr.Address == nil || l.err { return nil, &ParseError{f, "bad WKS Address", l}, "" } @@ -1436,7 +1458,7 @@ func setWKS(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { l = <-c proto := "tcp" i, e := strconv.Atoi(l.token) - if e != nil { + if e != nil || l.err { return nil, &ParseError{f, "bad WKS Protocol", l}, "" } rr.Protocol = uint8(i) @@ -1486,14 +1508,14 @@ func setSSHFP(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { return rr, nil, "" } i, e := strconv.Atoi(l.token) - if e != nil { + if e != nil || l.err { return nil, &ParseError{f, "bad SSHFP Algorithm", l}, "" } rr.Algorithm = uint8(i) <-c // zBlank l = <-c i, e = strconv.Atoi(l.token) - if e != nil { + if e != nil || l.err { return nil, &ParseError{f, "bad SSHFP Type", l}, "" } rr.Type = uint8(i) @@ -1515,21 +1537,21 @@ func setDNSKEYs(h RR_Header, c chan lex, o, f, typ string) (RR, *ParseError, str return rr, nil, l.comment } i, e := strconv.Atoi(l.token) - if e != nil { + if e != nil || l.err { return nil, &ParseError{f, "bad " + typ + " Flags", l}, "" } rr.Flags = uint16(i) <-c // zBlank l = <-c // zString i, e = strconv.Atoi(l.token) - if e != nil { + if e != nil || l.err { return nil, &ParseError{f, "bad " + typ + " Protocol", l}, "" } rr.Protocol = uint8(i) <-c // zBlank l = <-c // zString i, e = strconv.Atoi(l.token) - if e != nil { + if e != nil || l.err { return nil, &ParseError{f, "bad " + typ + " Algorithm", l}, "" } rr.Algorithm = uint8(i) @@ -1571,21 +1593,21 @@ func setRKEY(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { return rr, nil, l.comment } i, e := strconv.Atoi(l.token) - if e != nil { + if e != nil || l.err { return nil, &ParseError{f, "bad RKEY Flags", l}, "" } rr.Flags = uint16(i) <-c // zBlank l = <-c // zString i, e = strconv.Atoi(l.token) - if e != nil { + if e != nil || l.err { return nil, &ParseError{f, "bad RKEY Protocol", l}, "" } rr.Protocol = uint8(i) <-c // zBlank l = <-c // zString i, e = strconv.Atoi(l.token) - if e != nil { + if e != nil || l.err { return nil, &ParseError{f, "bad RKEY Algorithm", l}, "" } rr.Algorithm = uint8(i) @@ -1619,34 +1641,6 @@ func setNIMLOC(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { return rr, nil, c1 } -func setNSAP(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { - rr := new(NSAP) - rr.Hdr = h - chunks, e1, c1 := endingToTxtSlice(c, "bad NSAP Nsap", f) - if e1 != nil { - return nil, e1, c1 - } - // data would come as one string or multiple... Just to ignore possible - // variety let's merge things back together and split to actual "words" - s := strings.Fields(strings.Join(chunks, " ")) - if len(s) == 0 { - return rr, nil, c1 - } - if len(s[0]) >= 2 && s[0][0:2] == "0x" || s[0][0:2] == "0X" { - // although RFC only suggests 0x there is no clarification that X is not allowed - rr.Nsap = strings.Join(s, "")[2:] - } else { - // since we do not know what to do with this data, and, we would not use original length - // in formatting, it's moot to check correctness of the length - _, err := strconv.Atoi(s[0]) - if err != nil { - return nil, &ParseError{f, "bad NSAP Length", lex{token: s[0]}}, "" - } - rr.Nsap = strings.Join(s[1:], "") - } - return rr, nil, c1 -} - func setGPOS(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { rr := new(GPOS) rr.Hdr = h @@ -1655,21 +1649,21 @@ func setGPOS(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { return rr, nil, "" } _, e := strconv.ParseFloat(l.token, 64) - if e != nil { + if e != nil || l.err { return nil, &ParseError{f, "bad GPOS Longitude", l}, "" } rr.Longitude = l.token <-c // zBlank l = <-c _, e = strconv.ParseFloat(l.token, 64) - if e != nil { + if e != nil || l.err { return nil, &ParseError{f, "bad GPOS Latitude", l}, "" } rr.Latitude = l.token <-c // zBlank l = <-c _, e = strconv.ParseFloat(l.token, 64) - if e != nil { + if e != nil || l.err { return nil, &ParseError{f, "bad GPOS Altitude", l}, "" } rr.Altitude = l.token @@ -1684,7 +1678,7 @@ func setDSs(h RR_Header, c chan lex, o, f, typ string) (RR, *ParseError, string) return rr, nil, l.comment } i, e := strconv.Atoi(l.token) - if e != nil { + if e != nil || l.err { return nil, &ParseError{f, "bad " + typ + " KeyTag", l}, "" } rr.KeyTag = uint16(i) @@ -1692,7 +1686,7 @@ func setDSs(h RR_Header, c chan lex, o, f, typ string) (RR, *ParseError, string) l = <-c if i, e := strconv.Atoi(l.token); e != nil { i, ok := StringToAlgorithm[l.tokenUpper] - if !ok { + if !ok || l.err { return nil, &ParseError{f, "bad " + typ + " Algorithm", l}, "" } rr.Algorithm = i @@ -1702,7 +1696,7 @@ func setDSs(h RR_Header, c chan lex, o, f, typ string) (RR, *ParseError, string) <-c // zBlank l = <-c i, e = strconv.Atoi(l.token) - if e != nil { + if e != nil || l.err { return nil, &ParseError{f, "bad " + typ + " DigestType", l}, "" } rr.DigestType = uint8(i) @@ -1743,7 +1737,7 @@ func setTA(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { return rr, nil, l.comment } i, e := strconv.Atoi(l.token) - if e != nil { + if e != nil || l.err { return nil, &ParseError{f, "bad TA KeyTag", l}, "" } rr.KeyTag = uint16(i) @@ -1751,7 +1745,7 @@ func setTA(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { l = <-c if i, e := strconv.Atoi(l.token); e != nil { i, ok := StringToAlgorithm[l.tokenUpper] - if !ok { + if !ok || l.err { return nil, &ParseError{f, "bad TA Algorithm", l}, "" } rr.Algorithm = i @@ -1761,7 +1755,7 @@ func setTA(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { <-c // zBlank l = <-c i, e = strconv.Atoi(l.token) - if e != nil { + if e != nil || l.err { return nil, &ParseError{f, "bad TA DigestType", l}, "" } rr.DigestType = uint8(i) @@ -1781,21 +1775,21 @@ func setTLSA(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { return rr, nil, l.comment } i, e := strconv.Atoi(l.token) - if e != nil { + if e != nil || l.err { return nil, &ParseError{f, "bad TLSA Usage", l}, "" } rr.Usage = uint8(i) <-c // zBlank l = <-c i, e = strconv.Atoi(l.token) - if e != nil { + if e != nil || l.err { return nil, &ParseError{f, "bad TLSA Selector", l}, "" } rr.Selector = uint8(i) <-c // zBlank l = <-c i, e = strconv.Atoi(l.token) - if e != nil { + if e != nil || l.err { return nil, &ParseError{f, "bad TLSA MatchingType", l}, "" } rr.MatchingType = uint8(i) @@ -1818,7 +1812,7 @@ func setRFC3597(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) <-c // zBlank l = <-c rdlength, e := strconv.Atoi(l.token) - if e != nil { + if e != nil || l.err { return nil, &ParseError{f, "bad RFC3597 Rdata ", l}, "" } @@ -1876,28 +1870,32 @@ func setURI(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { rr.Hdr = h l := <-c - if l.length == 0 { - return rr, nil, l.comment + if l.length == 0 { // Dynamic updates. + return rr, nil, "" } + i, e := strconv.Atoi(l.token) - if e != nil { + if e != nil || l.err { return nil, &ParseError{f, "bad URI Priority", l}, "" } rr.Priority = uint16(i) <-c // zBlank l = <-c i, e = strconv.Atoi(l.token) - if e != nil { + if e != nil || l.err { return nil, &ParseError{f, "bad URI Weight", l}, "" } rr.Weight = uint16(i) <-c // zBlank - s, e, c1 := endingToTxtSlice(c, "bad URI Target", f) - if e != nil { - return nil, e.(*ParseError), "" + s, err, c1 := endingToTxtSlice(c, "bad URI Target", f) + if err != nil { + return nil, err, "" } - rr.Target = s + if len(s) > 1 { + return nil, &ParseError{f, "bad URI Target", l}, "" + } + rr.Target = s[0] return rr, nil, c1 } @@ -1923,14 +1921,14 @@ func setNID(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { return rr, nil, "" } i, e := strconv.Atoi(l.token) - if e != nil { + if e != nil || l.err { return nil, &ParseError{f, "bad NID Preference", l}, "" } rr.Preference = uint16(i) <-c // zBlank l = <-c // zString u, err := stringToNodeID(l) - if err != nil { + if err != nil || l.err { return nil, err, "" } rr.NodeID = u @@ -1946,14 +1944,14 @@ func setL32(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { return rr, nil, "" } i, e := strconv.Atoi(l.token) - if e != nil { + if e != nil || l.err { return nil, &ParseError{f, "bad L32 Preference", l}, "" } rr.Preference = uint16(i) <-c // zBlank l = <-c // zString rr.Locator32 = net.ParseIP(l.token) - if rr.Locator32 == nil { + if rr.Locator32 == nil || l.err { return nil, &ParseError{f, "bad L32 Locator", l}, "" } return rr, nil, "" @@ -1968,7 +1966,7 @@ func setLP(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { return rr, nil, "" } i, e := strconv.Atoi(l.token) - if e != nil { + if e != nil || l.err { return nil, &ParseError{f, "bad LP Preference", l}, "" } rr.Preference = uint16(i) @@ -1983,7 +1981,7 @@ func setLP(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { return rr, nil, "" } _, ok := IsDomainName(l.token) - if !ok || l.length == 0 { + if !ok || l.length == 0 || l.err { return nil, &ParseError{f, "bad LP Fqdn", l}, "" } if rr.Fqdn[l.length-1] != '.' { @@ -2001,14 +1999,14 @@ func setL64(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { return rr, nil, "" } i, e := strconv.Atoi(l.token) - if e != nil { + if e != nil || l.err { return nil, &ParseError{f, "bad L64 Preference", l}, "" } rr.Preference = uint16(i) <-c // zBlank l = <-c // zString u, err := stringToNodeID(l) - if err != nil { + if err != nil || l.err { return nil, err, "" } rr.Locator64 = u @@ -2023,7 +2021,7 @@ func setUID(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { return rr, nil, "" } i, e := strconv.Atoi(l.token) - if e != nil { + if e != nil || l.err { return nil, &ParseError{f, "bad UID Uid", l}, "" } rr.Uid = uint32(i) @@ -2038,7 +2036,7 @@ func setGID(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { return rr, nil, "" } i, e := strconv.Atoi(l.token) - if e != nil { + if e != nil || l.err { return nil, &ParseError{f, "bad GID Gid", l}, "" } rr.Gid = uint32(i) @@ -2065,7 +2063,7 @@ func setPX(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { return rr, nil, "" } i, e := strconv.Atoi(l.token) - if e != nil { + if e != nil || l.err { return nil, &ParseError{f, "bad PX Preference", l}, "" } rr.Preference = uint16(i) @@ -2080,7 +2078,7 @@ func setPX(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { return rr, nil, "" } _, ok := IsDomainName(l.token) - if !ok { + if !ok || l.length == 0 || l.err { return nil, &ParseError{f, "bad PX Map822", l}, "" } if rr.Map822[l.length-1] != '.' { @@ -2094,7 +2092,7 @@ func setPX(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { return rr, nil, "" } _, ok = IsDomainName(l.token) - if !ok || l.length == 0 { + if !ok || l.length == 0 || l.err { return nil, &ParseError{f, "bad PX Mapx400", l}, "" } if rr.Mapx400[l.length-1] != '.' { @@ -2111,21 +2109,21 @@ func setIPSECKEY(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) return rr, nil, l.comment } i, err := strconv.Atoi(l.token) - if err != nil { + if err != nil || l.err { return nil, &ParseError{f, "bad IPSECKEY Precedence", l}, "" } rr.Precedence = uint8(i) <-c // zBlank l = <-c i, err = strconv.Atoi(l.token) - if err != nil { + if err != nil || l.err { return nil, &ParseError{f, "bad IPSECKEY GatewayType", l}, "" } rr.GatewayType = uint8(i) <-c // zBlank l = <-c i, err = strconv.Atoi(l.token) - if err != nil { + if err != nil || l.err { return nil, &ParseError{f, "bad IPSECKEY Algorithm", l}, "" } rr.Algorithm = uint8(i) @@ -2142,7 +2140,7 @@ func setIPSECKEY(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) rr.GatewayName = o } _, ok := IsDomainName(l.token) - if !ok { + if !ok || l.length == 0 || l.err { return nil, &ParseError{f, "bad IPSECKEY GatewayName", l}, "" } if rr.GatewayName[l.length-1] != '.' { @@ -2178,12 +2176,12 @@ func setCAA(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { return rr, nil, l.comment } i, err := strconv.Atoi(l.token) - if err != nil { + if err != nil || l.err { return nil, &ParseError{f, "bad CAA Flag", l}, "" } rr.Flag = uint8(i) - <-c // zBlank + <-c // zBlank l = <-c // zString if l.value != zString { return nil, &ParseError{f, "bad CAA Tag", l}, "" @@ -2197,9 +2195,8 @@ func setCAA(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { } if len(s) > 1 { return nil, &ParseError{f, "bad CAA Value", l}, "" - } else { - rr.Value = s[0] } + rr.Value = s[0] return rr, nil, c1 } @@ -2242,7 +2239,6 @@ var typeToparserFunc = map[uint16]parserFunc{ TypeNID: parserFunc{setNID, false}, TypeNIMLOC: parserFunc{setNIMLOC, true}, TypeNINFO: parserFunc{setNINFO, true}, - TypeNSAP: parserFunc{setNSAP, true}, TypeNSAPPTR: parserFunc{setNSAPPTR, false}, TypeNSEC3PARAM: parserFunc{setNSEC3PARAM, false}, TypeNSEC3: parserFunc{setNSEC3, true}, diff --git a/core/dns.go b/core/dns.go index 6b34eff51..0227b0b4d 100644 --- a/core/dns.go +++ b/core/dns.go @@ -9,6 +9,7 @@ import ( "fmt" "math/rand" "net" + "strings" "time" "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/miekg/dns" @@ -88,9 +89,7 @@ func (dnsResolver *DNSResolverImpl) LookupTXT(hostname string) ([]string, time.D for _, answer := range r.Answer { if answer.Header().Rrtype == dns.TypeTXT { if txtRec, ok := answer.(*dns.TXT); ok { - for _, field := range txtRec.Txt { - txt = append(txt, field) - } + txt = append(txt, strings.Join(txtRec.Txt, "")) } } } diff --git a/core/dns_test.go b/core/dns_test.go index 423e68c7a..1a2580b00 100644 --- a/core/dns_test.go +++ b/core/dns_test.go @@ -98,6 +98,13 @@ func mockDNSQuery(w dns.ResponseWriter, r *dns.Msg) { record.Flag = 1 appendAnswer(record) } + case dns.TypeTXT: + if q.Name == "split-txt.letsencrypt.org." { + record := new(dns.TXT) + record.Hdr = dns.RR_Header{Name: "split-txt.letsencrypt.org.", Rrtype: dns.TypeTXT, Class: dns.ClassINET, Ttl: 0} + record.Txt = []string{"a", "b", "c"} + appendAnswer(record) + } } } @@ -200,9 +207,14 @@ func TestDNSLookupTXT(t *testing.T) { obj := NewDNSResolverImpl(time.Second*10, []string{dnsLoopbackAddr}) a, rtt, err := obj.LookupTXT("letsencrypt.org") - t.Logf("A: %v RTT %s", a, rtt) test.AssertNotError(t, err, "No message") + + a, rtt, err = obj.LookupTXT("split-txt.letsencrypt.org") + t.Logf("A: %v RTT %s", a, rtt) + test.AssertNotError(t, err, "No message") + test.AssertEquals(t, len(a), 1) + test.AssertEquals(t, a[0], "abc") } func TestDNSLookupHost(t *testing.T) { diff --git a/core/objects.go b/core/objects.go index 21a476fb9..7b61333ab 100644 --- a/core/objects.go +++ b/core/objects.go @@ -201,13 +201,13 @@ type Registration struct { ID int64 `json:"id" db:"id"` // Account key to which the details are attached - Key jose.JsonWebKey `json:"key" db:"jwk"` + Key jose.JsonWebKey `json:"key"` // Contact URIs - Contact []*AcmeURL `json:"contact,omitempty" db:"contact"` + Contact []*AcmeURL `json:"contact,omitempty"` // Agreement with terms of service - Agreement string `json:"agreement,omitempty" db:"agreement"` + Agreement string `json:"agreement,omitempty"` } // MergeUpdate copies a subset of information from the input Registration diff --git a/sa/type-converter.go b/sa/type-converter.go index 11a43946c..592c14ac5 100644 --- a/sa/type-converter.go +++ b/sa/type-converter.go @@ -38,8 +38,6 @@ func (tc BoulderTypeConverter) ToDb(val interface{}) (interface{}, error) { return string(t), nil case core.OCSPStatus: return string(t), nil - case core.JSONBuffer: - return []byte(t), nil default: return val, nil } @@ -48,7 +46,7 @@ func (tc BoulderTypeConverter) ToDb(val interface{}) (interface{}, error) { // FromDb converts a DB representation back into a Boulder object. func (tc BoulderTypeConverter) FromDb(target interface{}) (gorp.CustomScanner, bool) { switch target.(type) { - case *core.AcmeIdentifier, *[]core.Challenge, *[]*core.AcmeURL, *[][]int, core.JSONBuffer: + case *core.AcmeIdentifier, *[]core.Challenge, *[]*core.AcmeURL, *[][]int: binder := func(holder, target interface{}) error { s, ok := holder.(*string) if !ok { diff --git a/test.sh b/test.sh index afdc50e9a..7c104c592 100755 --- a/test.sh +++ b/test.sh @@ -118,7 +118,7 @@ function run_unit_tests() { if [ "${TRAVIS}" == "true" ]; then # Run each test by itself for Travis, so we can get coverage for dir in ${TESTDIRS}; do - run go test -race -covermode=count -coverprofile=${dir}.coverprofile ./${dir}/ + run go test -race -cover -coverprofile=${dir}.coverprofile ./${dir}/ done # Gather all the coverprofiles