diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index 0744a05c12e..92511653a1d 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -1335,7 +1335,7 @@ }, { "ImportPath": "github.com/miekg/dns", - "Rev": "3f504e8dabd5d562e997d19ce0200aa41973e1b2" + "Rev": "c2b278e70f35902fd68b54b69238cd10bb1b7451" }, { "ImportPath": "github.com/mistifyio/go-zfs", @@ -1779,8 +1779,8 @@ }, { "ImportPath": "github.com/skynetservices/skydns/msg", - "Comment": "2.5.1a", - "Rev": "1be70b5b8aa07acccd972146d84011b670af88b4" + "Comment": "2.5.3a-32-gf7b6fb7", + "Rev": "f7b6fb74bcfab300b4e7e0e27b1fe6c0ed555f78" }, { "ImportPath": "github.com/spf13/cobra", diff --git a/vendor/github.com/miekg/dns/.travis.yml b/vendor/github.com/miekg/dns/.travis.yml index 4485679769d..1f056ab7ccc 100644 --- a/vendor/github.com/miekg/dns/.travis.yml +++ b/vendor/github.com/miekg/dns/.travis.yml @@ -1,21 +1,7 @@ language: go +sudo: false go: - - 1.2 - - 1.3 -env: - # "gvm update" resets GOOS and GOARCH environment variable, workaround it by setting - # BUILD_GOOS and BUILD_GOARCH and overriding GOARCH and GOOS in the build script - global: - - BUILD_GOARCH=amd64 - matrix: - - BUILD_GOOS=linux - - BUILD_GOOS=darwin - - BUILD_GOOS=windows + - 1.5 + - 1.6 script: - - gvm cross $BUILD_GOOS $BUILD_GOARCH - - GOARCH=$BUILD_GOARCH GOOS=$BUILD_GOOS go build - - # only test on linux - # also specify -short; the crypto tests fail in weird ways *sometimes* - # See issue #151 - - if [ $BUILD_GOOS == "linux" ]; then GOARCH=$BUILD_GOARCH GOOS=$BUILD_GOOS go test -short -bench=.; fi + - go test -race -v -bench=. diff --git a/vendor/github.com/miekg/dns/README.md b/vendor/github.com/miekg/dns/README.md index 3cb850a0b07..011d085f18d 100644 --- a/vendor/github.com/miekg/dns/README.md +++ b/vendor/github.com/miekg/dns/README.md @@ -10,9 +10,9 @@ If there is stuff you should know as a DNS programmer there isn't a convenience function for it. Server side and client side programming is supported, i.e. you can build servers and resolvers with it. -If you like this, you may also be interested in: - -* https://github.com/miekg/unbound -- Go wrapper for the Unbound resolver. +We try to keep the "master" branch as sane as possible and at the bleeding edge +of standards, avoiding breaking changes wherever reasonable. We support the last +two versions of Go, currently: 1.4 and 1.5. # Goals @@ -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/ @@ -32,8 +33,21 @@ A not-so-up-to-date-list-that-may-be-actually-current: * https://github.com/fcambus/rrda * https://github.com/kenshinx/godns * https://github.com/skynetservices/skydns +* https://github.com/hashicorp/consul * https://github.com/DevelopersPL/godnsagent * https://github.com/duedil-ltd/discodns +* https://github.com/StalkR/dns-reverse-proxy +* https://github.com/tianon/rawdns +* https://mesosphere.github.io/mesos-dns/ +* https://pulse.turbobytes.com/ +* https://play.google.com/store/apps/details?id=com.turbobytes.dig +* https://github.com/fcambus/statzone +* https://github.com/benschw/dns-clb-go +* https://github.com/corny/dnscheck for http://public-dns.info/ +* https://namesmith.io +* https://github.com/miekg/unbound +* https://github.com/miekg/exdns +* https://dnslookup.org Send pull request if you want to be listed here. @@ -50,6 +64,7 @@ Send pull request if you want to be listed here. * EDNS0, NSID; * AXFR/IXFR; * TSIG, SIG(0); +* DNS over TLS: optional encrypted connection between client and server; * DNS name compression; * Depends only on the standard library. @@ -67,7 +82,7 @@ correctly, the following should work: ## Examples -A short "how to use the API" is at the beginning of dns.go (this also will show +A short "how to use the API" is at the beginning of doc.go (this also will show when you call `godoc github.com/miekg/dns`). Example programs can be found in the `github.com/miekg/exdns` repository. @@ -77,7 +92,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 @@ -95,7 +110,8 @@ Example programs can be found in the `github.com/miekg/exdns` repository. * 3225 - DO bit (DNSSEC OK) * 340{1,2,3} - NAPTR record * 3445 - Limiting the scope of (DNS)KEY -* 3597 - Unkown RRs +* 3597 - Unknown RRs +* 4025 - IPSECKEY * 403{3,4,5} - DNSSEC + validation functions * 4255 - SSHFP record * 4343 - Case insensitivity @@ -114,13 +130,16 @@ Example programs can be found in the `github.com/miekg/exdns` repository. * 6605 - ECDSA * 6725 - IANA Registry Update * 6742 - ILNP DNS +* 6840 - Clarifications and Implementation Notes for DNS Security +* 6844 - CAA record * 6891 - EDNS0 update * 6895 - DNS IANA considerations * 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) +* yyyy - DNS over TLS: Initiation and Performance Considerations (draft) ## Loosely based upon @@ -132,9 +151,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; -* CAA parsing is broken; -* NSEC(3) cover/match/closest enclose; -* Replies with TC bit are not parsed to the end; -* Create IsMsg to validate a message before fully parsing it. +* 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/vendor/github.com/miekg/dns/client.go b/vendor/github.com/miekg/dns/client.go index ee8e22333b1..7a05eb99cc7 100644 --- a/vendor/github.com/miekg/dns/client.go +++ b/vendor/github.com/miekg/dns/client.go @@ -4,12 +4,13 @@ package dns import ( "bytes" + "crypto/tls" "io" "net" "time" ) -const dnsTimeout time.Duration = 2 * 1e9 +const dnsTimeout time.Duration = 2 * time.Second const tcpIdleTimeout time.Duration = 8 * time.Second // A Conn represents a connection to a DNS server. @@ -24,11 +25,12 @@ type Conn struct { // A Client defines parameters for a DNS client. type Client struct { - Net string // if "tcp" a TCP query will be initiated, otherwise an UDP one (default is "" for UDP) + Net string // if "tcp" or "tcp-tls" (DNS over TLS) a TCP query will be initiated, otherwise an UDP one (default is "" for UDP) UDPSize uint16 // minimum receive buffer for UDP messages - DialTimeout time.Duration // net.DialTimeout (ns), defaults to 2 * 1e9 - ReadTimeout time.Duration // net.Conn.SetReadTimeout value for connections (ns), defaults to 2 * 1e9 - WriteTimeout time.Duration // net.Conn.SetWriteTimeout value for connections (ns), defaults to 2 * 1e9 + TLSConfig *tls.Config // TLS connection configuration + DialTimeout time.Duration // net.DialTimeout, defaults to 2 seconds + ReadTimeout time.Duration // net.Conn.SetReadTimeout value for connections, defaults to 2 seconds + WriteTimeout time.Duration // net.Conn.SetWriteTimeout value for connections, defaults to 2 seconds TsigSecret map[string]string // secret(s) for Tsig map[], zonename must be fully qualified SingleInflight bool // if true suppress multiple outstanding queries for the same Qname, Qtype and Qclass group singleflight @@ -37,14 +39,7 @@ type Client struct { // Exchange performs a synchronous UDP query. It sends the message m to the address // contained in a and waits for an reply. Exchange does not retry a failed query, nor // will it fall back to TCP in case of truncation. -// If you need to send a DNS message on an already existing connection, you can use the -// following: -// -// co := &dns.Conn{Conn: c} // c is your net.Conn -// co.WriteMsg(m) -// in, err := co.ReadMsg() -// co.Close() -// +// See client.Exchange for more information on setting larger buffer sizes. func Exchange(m *Msg, a string) (r *Msg, err error) { var co *Conn co, err = DialTimeout("udp", a, dnsTimeout) @@ -53,12 +48,23 @@ func Exchange(m *Msg, a string) (r *Msg, err error) { } defer co.Close() - co.SetReadDeadline(time.Now().Add(dnsTimeout)) + + opt := m.IsEdns0() + // If EDNS0 is used use that for size. + if opt != nil && opt.UDPSize() >= MinMsgSize { + co.UDPSize = opt.UDPSize() + } + co.SetWriteDeadline(time.Now().Add(dnsTimeout)) if err = co.WriteMsg(m); err != nil { return nil, err } + + co.SetReadDeadline(time.Now().Add(dnsTimeout)) r, err = co.ReadMsg() + if err == nil && r.Id != m.Id { + err = ErrId + } return r, err } @@ -79,6 +85,9 @@ func ExchangeConn(c net.Conn, m *Msg) (r *Msg, err error) { return nil, err } r, err = co.ReadMsg() + if err == nil && r.Id != m.Id { + err = ErrId + } return r, err } @@ -90,6 +99,10 @@ func ExchangeConn(c net.Conn, m *Msg) (r *Msg, err error) { // // Exchange does not retry a failed query, nor will it fall back to TCP in // case of truncation. +// It is up to the caller to create a message that allows for larger responses to be +// returned. Specifically this means adding an EDNS0 OPT RR that will advertise a larger +// buffer, see SetEdns0. Messsages without an OPT RR will fallback to the historic limit +// of 512 bytes. func (c *Client) Exchange(m *Msg, a string) (r *Msg, rtt time.Duration, err error) { if !c.SingleInflight { return c.exchange(m, a) @@ -115,31 +128,59 @@ func (c *Client) Exchange(m *Msg, a string) (r *Msg, rtt time.Duration, err erro return r, rtt, nil } -func (c *Client) exchange(m *Msg, a string) (r *Msg, rtt time.Duration, err error) { - timeout := dnsTimeout - var co *Conn +func (c *Client) dialTimeout() time.Duration { if c.DialTimeout != 0 { - timeout = c.DialTimeout + return c.DialTimeout } - if c.Net == "" { - co, err = DialTimeout("udp", a, timeout) + return dnsTimeout +} + +func (c *Client) readTimeout() time.Duration { + if c.ReadTimeout != 0 { + return c.ReadTimeout + } + return dnsTimeout +} + +func (c *Client) writeTimeout() time.Duration { + if c.WriteTimeout != 0 { + return c.WriteTimeout + } + return dnsTimeout +} + +func (c *Client) exchange(m *Msg, a string) (r *Msg, rtt time.Duration, err error) { + var co *Conn + network := "udp" + tls := false + + switch c.Net { + case "tcp-tls": + network = "tcp" + tls = true + case "tcp4-tls": + network = "tcp4" + tls = true + case "tcp6-tls": + network = "tcp6" + tls = true + default: + if c.Net != "" { + network = c.Net + } + } + + if tls { + co, err = DialTimeoutWithTLS(network, a, c.TLSConfig, c.dialTimeout()) } else { - co, err = DialTimeout(c.Net, a, timeout) + co, err = DialTimeout(network, a, c.dialTimeout()) } + if err != nil { return nil, 0, err } - timeout = dnsTimeout - if c.ReadTimeout != 0 { - timeout = c.ReadTimeout - } - co.SetReadDeadline(time.Now().Add(timeout)) - timeout = dnsTimeout - if c.WriteTimeout != 0 { - timeout = c.WriteTimeout - } - co.SetWriteDeadline(time.Now().Add(timeout)) defer co.Close() + opt := m.IsEdns0() // If EDNS0 is used use that for size. if opt != nil && opt.UDPSize() >= MinMsgSize { @@ -149,11 +190,18 @@ func (c *Client) exchange(m *Msg, a string) (r *Msg, rtt time.Duration, err erro if opt == nil && c.UDPSize >= MinMsgSize { co.UDPSize = c.UDPSize } + co.TsigSecret = c.TsigSecret + co.SetWriteDeadline(time.Now().Add(c.writeTimeout())) if err = co.WriteMsg(m); err != nil { return nil, 0, err } + + co.SetReadDeadline(time.Now().Add(c.readTimeout())) r, err = co.ReadMsg() + if err == nil && r.Id != m.Id { + err = ErrId + } return r, co.rtt, err } @@ -161,26 +209,21 @@ func (c *Client) exchange(m *Msg, a string) (r *Msg, rtt time.Duration, err erro // If the received message contains a TSIG record the transaction // signature is verified. func (co *Conn) ReadMsg() (*Msg, error) { - var p []byte + p, err := co.ReadMsgHeader(nil) + if err != nil { + return nil, err + } + m := new(Msg) - if _, ok := co.Conn.(*net.TCPConn); ok { - p = make([]byte, MaxMsgSize) - } else { - if co.UDPSize >= 512 { - p = make([]byte, co.UDPSize) - } else { - p = make([]byte, MinMsgSize) - } - } - n, err := co.Read(p) - if err != nil && n == 0 { - return nil, err - } - p = p[:n] if err := m.Unpack(p); err != nil { + // If ErrTruncated was returned, we still want to allow the user to use + // the message, but naively they can just check err if they don't want + // to use a truncated message + if err == ErrTruncated { + return m, err + } return nil, err } - co.rtt = time.Since(co.t) if t := m.IsTsig(); t != nil { if _, ok := co.TsigSecret[t.Hdr.Name]; !ok { return m, ErrSecret @@ -191,6 +234,86 @@ func (co *Conn) ReadMsg() (*Msg, error) { return m, err } +// ReadMsgHeader reads a DNS message, parses and populates hdr (when hdr is not nil). +// Returns message as a byte slice to be parsed with Msg.Unpack later on. +// Note that error handling on the message body is not possible as only the header is parsed. +func (co *Conn) ReadMsgHeader(hdr *Header) ([]byte, error) { + var ( + p []byte + n int + err error + ) + + switch t := co.Conn.(type) { + case *net.TCPConn, *tls.Conn: + r := t.(io.Reader) + + // First two bytes specify the length of the entire message. + l, err := tcpMsgLen(r) + if err != nil { + return nil, err + } + p = make([]byte, l) + n, err = tcpRead(r, p) + co.rtt = time.Since(co.t) + default: + if co.UDPSize > MinMsgSize { + p = make([]byte, co.UDPSize) + } else { + p = make([]byte, MinMsgSize) + } + n, err = co.Read(p) + co.rtt = time.Since(co.t) + } + + if err != nil { + return nil, err + } else if n < headerSize { + return nil, ErrShortRead + } + + p = p[:n] + if hdr != nil { + if _, err = UnpackStruct(hdr, p, 0); err != nil { + return nil, err + } + } + return p, err +} + +// tcpMsgLen is a helper func to read first two bytes of stream as uint16 packet length. +func tcpMsgLen(t io.Reader) (int, error) { + p := []byte{0, 0} + n, err := t.Read(p) + if err != nil { + return 0, err + } + if n != 2 { + return 0, ErrShortRead + } + l, _ := unpackUint16(p, 0) + if l == 0 { + return 0, ErrShortRead + } + return int(l), nil +} + +// tcpRead calls TCPConn.Read enough times to fill allocated buffer. +func tcpRead(t io.Reader, p []byte) (int, error) { + n, err := t.Read(p) + if err != nil { + return n, err + } + for n < len(p) { + j, err := t.Read(p[n:]) + if err != nil { + return n, err + } + n += j + } + return n, err +} + // Read implements the net.Conn read method. func (co *Conn) Read(p []byte) (n int, err error) { if co.Conn == nil { @@ -199,32 +322,18 @@ func (co *Conn) Read(p []byte) (n int, err error) { if len(p) < 2 { return 0, io.ErrShortBuffer } - if t, ok := co.Conn.(*net.TCPConn); ok { - n, err = t.Read(p[0:2]) - if err != nil || n != 2 { - return n, err + switch t := co.Conn.(type) { + case *net.TCPConn, *tls.Conn: + r := t.(io.Reader) + + l, err := tcpMsgLen(r) + if err != nil { + return 0, err } - l, _ := unpackUint16(p[0:2], 0) - if l == 0 { - return 0, ErrShortRead - } - if int(l) > len(p) { + if l > len(p) { return int(l), io.ErrShortBuffer } - n, err = t.Read(p[:l]) - if err != nil { - return n, err - } - i := n - for i < int(l) { - j, err := t.Read(p[i:int(l)]) - if err != nil { - return i, err - } - i += j - } - n = i - return n, err + return tcpRead(r, p[:l]) } // UDP connection n, err = co.Conn.Read(p) @@ -234,7 +343,7 @@ func (co *Conn) Read(p []byte) (n int, err error) { return n, err } -// WriteMsg sends a message throught the connection co. +// WriteMsg sends a message through the connection co. // If the message m contains a TSIG record the transaction // signature is calculated. func (co *Conn) WriteMsg(m *Msg) (err error) { @@ -245,7 +354,7 @@ func (co *Conn) WriteMsg(m *Msg) (err error) { return ErrSecret } out, mac, err = TsigGenerate(m, co.TsigSecret[t.Hdr.Name], co.tsigRequestMAC, false) - // Set for the next read, allthough only used in zone transfers + // Set for the next read, although only used in zone transfers co.tsigRequestMAC = mac } else { out, err = m.Pack() @@ -262,7 +371,10 @@ func (co *Conn) WriteMsg(m *Msg) (err error) { // Write implements the net.Conn Write method. func (co *Conn) Write(p []byte) (n int, err error) { - if t, ok := co.Conn.(*net.TCPConn); ok { + switch t := co.Conn.(type) { + case *net.TCPConn, *tls.Conn: + w := t.(io.Writer) + lp := len(p) if lp < 2 { return 0, io.ErrShortBuffer @@ -273,7 +385,7 @@ func (co *Conn) Write(p []byte) (n int, err error) { l := make([]byte, 2, lp+2) l[0], l[1] = packUint16(uint16(lp)) p = append(l, p...) - n, err := io.Copy(t, bytes.NewReader(p)) + n, err := io.Copy(w, bytes.NewReader(p)) return int(n), err } n, err = co.Conn.(*net.UDPConn).Write(p) @@ -290,7 +402,7 @@ func Dial(network, address string) (conn *Conn, err error) { return conn, nil } -// Dialtimeout acts like Dial but takes a timeout. +// DialTimeout acts like Dial but takes a timeout. func DialTimeout(network, address string, timeout time.Duration) (conn *Conn, err error) { conn = new(Conn) conn.Conn, err = net.DialTimeout(network, address, timeout) @@ -300,20 +412,25 @@ func DialTimeout(network, address string, timeout time.Duration) (conn *Conn, er return conn, nil } -// Close implements the net.Conn Close method. -func (co *Conn) Close() error { return co.Conn.Close() } +// DialWithTLS connects to the address on the named network with TLS. +func DialWithTLS(network, address string, tlsConfig *tls.Config) (conn *Conn, err error) { + conn = new(Conn) + conn.Conn, err = tls.Dial(network, address, tlsConfig) + if err != nil { + return nil, err + } + return conn, nil +} -// LocalAddr implements the net.Conn LocalAddr method. -func (co *Conn) LocalAddr() net.Addr { return co.Conn.LocalAddr() } +// DialTimeoutWithTLS acts like DialWithTLS but takes a timeout. +func DialTimeoutWithTLS(network, address string, tlsConfig *tls.Config, timeout time.Duration) (conn *Conn, err error) { + var dialer net.Dialer + dialer.Timeout = timeout -// RemoteAddr implements the net.Conn RemoteAddr method. -func (co *Conn) RemoteAddr() net.Addr { return co.Conn.RemoteAddr() } - -// SetDeadline implements the net.Conn SetDeadline method. -func (co *Conn) SetDeadline(t time.Time) error { return co.Conn.SetDeadline(t) } - -// SetReadDeadline implements the net.Conn SetReadDeadline method. -func (co *Conn) SetReadDeadline(t time.Time) error { return co.Conn.SetReadDeadline(t) } - -// SetWriteDeadline implements the net.Conn SetWriteDeadline method. -func (co *Conn) SetWriteDeadline(t time.Time) error { return co.Conn.SetWriteDeadline(t) } + conn = new(Conn) + conn.Conn, err = tls.DialWithDialer(&dialer, network, address, tlsConfig) + if err != nil { + return nil, err + } + return conn, nil +} diff --git a/vendor/github.com/miekg/dns/clientconfig.go b/vendor/github.com/miekg/dns/clientconfig.go index 87cf8961862..cfa9ad0b228 100644 --- a/vendor/github.com/miekg/dns/clientconfig.go +++ b/vendor/github.com/miekg/dns/clientconfig.go @@ -7,7 +7,7 @@ import ( "strings" ) -// Wraps the contents of the /etc/resolv.conf. +// ClientConfig wraps the contents of the /etc/resolv.conf file. type ClientConfig struct { Servers []string // servers to use Search []string // suffixes to append to local name @@ -26,14 +26,19 @@ func ClientConfigFromFile(resolvconf string) (*ClientConfig, error) { } defer file.Close() c := new(ClientConfig) - b := bufio.NewReader(file) + scanner := bufio.NewScanner(file) c.Servers = make([]string, 0) c.Search = make([]string, 0) c.Port = "53" c.Ndots = 1 c.Timeout = 5 c.Attempts = 2 - for line, ok := b.ReadString('\n'); ok == nil; line, ok = b.ReadString('\n') { + + for scanner.Scan() { + if err := scanner.Err(); err != nil { + return nil, err + } + line := scanner.Text() f := strings.Fields(line) if len(f) < 1 { continue diff --git a/vendor/github.com/miekg/dns/defaults.go b/vendor/github.com/miekg/dns/defaults.go index 0c8fa9c84b6..63165b4fa9c 100644 --- a/vendor/github.com/miekg/dns/defaults.go +++ b/vendor/github.com/miekg/dns/defaults.go @@ -24,7 +24,9 @@ func (dns *Msg) SetReply(request *Msg) *Msg { return dns } -// SetQuestion creates a question message. +// SetQuestion creates a question message, it sets the Question +// section, generates an Id and sets the RecursionDesired (RD) +// bit to true. func (dns *Msg) SetQuestion(z string, t uint16) *Msg { dns.Id = Id() dns.RecursionDesired = true @@ -33,7 +35,9 @@ func (dns *Msg) SetQuestion(z string, t uint16) *Msg { return dns } -// SetNotify creates a notify message. +// SetNotify creates a notify message, it sets the Question +// section, generates an Id and sets the Authoritative (AA) +// bit to true. func (dns *Msg) SetNotify(z string) *Msg { dns.Opcode = OpcodeNotify dns.Authoritative = true @@ -73,13 +77,15 @@ func (dns *Msg) SetUpdate(z string) *Msg { } // SetIxfr creates message for requesting an IXFR. -func (dns *Msg) SetIxfr(z string, serial uint32) *Msg { +func (dns *Msg) SetIxfr(z string, serial uint32, ns, mbox string) *Msg { dns.Id = Id() dns.Question = make([]Question, 1) dns.Ns = make([]RR, 1) s := new(SOA) s.Hdr = RR_Header{z, TypeSOA, ClassINET, defaultTtl, 0} s.Serial = serial + s.Ns = ns + s.Mbox = mbox dns.Question[0] = Question{z, TypeIXFR, ClassINET} dns.Ns[0] = s return dns @@ -144,11 +150,14 @@ func (dns *Msg) IsEdns0() *OPT { return nil } -// IsDomainName checks if s is a valid domainname, it returns -// the number of labels and true, when a domain name is valid. -// Note that non fully qualified domain name is considered valid, in this case the -// last label is counted in the number of labels. -// When false is returned the number of labels is not defined. +// IsDomainName checks if s is a valid domain name, it returns the number of +// labels and true, when a domain name is valid. Note that non fully qualified +// domain name is considered valid, in this case the last label is counted in +// the number of labels. When false is returned the number of labels is not +// defined. Also note that this function is extremely liberal; almost any +// string is a valid domain name as the DNS is 8 bit protocol. It checks if each +// label fits in 63 characters, but there is no length check for the entire +// string s. I.e. a domain name longer than 255 characters is considered valid. func IsDomainName(s string) (labels int, ok bool) { _, labels, err := packDomainName(s, nil, 0, nil, false) return labels, err == nil @@ -182,7 +191,34 @@ func IsFqdn(s string) bool { return s[l-1] == '.' } -// Fqdns return the fully qualified domain name from s. +// IsRRset checks if a set of RRs is a valid RRset as defined by RFC 2181. +// This means the RRs need to have the same type, name, and class. Returns true +// if the RR set is valid, otherwise false. +func IsRRset(rrset []RR) bool { + if len(rrset) == 0 { + return false + } + if len(rrset) == 1 { + return true + } + rrHeader := rrset[0].Header() + rrType := rrHeader.Rrtype + rrClass := rrHeader.Class + rrName := rrHeader.Name + + for _, rr := range rrset[1:] { + curRRHeader := rr.Header() + if curRRHeader.Rrtype != rrType || curRRHeader.Class != rrClass || curRRHeader.Name != rrName { + // Mismatch between the records, so this is not a valid rrset for + //signing/verifying + return false + } + } + + return true +} + +// Fqdn return the fully qualified domain name from s. // If s is already fully qualified, it behaves as the identity function. func Fqdn(s string) string { if IsFqdn(s) { diff --git a/vendor/github.com/miekg/dns/dns.go b/vendor/github.com/miekg/dns/dns.go index 7540c0d5bca..a3e4a0efae5 100644 --- a/vendor/github.com/miekg/dns/dns.go +++ b/vendor/github.com/miekg/dns/dns.go @@ -1,108 +1,16 @@ -// Package dns implements a full featured interface to the Domain Name System. -// Server- and client-side programming is supported. -// The package allows complete control over what is send out to the DNS. The package -// API follows the less-is-more principle, by presenting a small, clean interface. -// -// The package dns supports (asynchronous) querying/replying, incoming/outgoing zone transfers, -// TSIG, EDNS0, dynamic updates, notifies and DNSSEC validation/signing. -// Note that domain names MUST be fully qualified, before sending them, unqualified -// names in a message will result in a packing failure. -// -// Resource records are native types. They are not stored in wire format. -// Basic usage pattern for creating a new resource record: -// -// r := new(dns.MX) -// r.Hdr = dns.RR_Header{Name: "miek.nl.", Rrtype: dns.TypeMX, Class: dns.ClassINET, Ttl: 3600} -// r.Preference = 10 -// r.Mx = "mx.miek.nl." -// -// Or directly from a string: -// -// mx, err := dns.NewRR("miek.nl. 3600 IN MX 10 mx.miek.nl.") -// -// Or when the default TTL (3600) and class (IN) suit you: -// -// mx, err := dns.NewRR("miek.nl. MX 10 mx.miek.nl.") -// -// Or even: -// -// mx, err := dns.NewRR("$ORIGIN nl.\nmiek 1H IN MX 10 mx.miek") -// -// In the DNS messages are exchanged, these messages contain resource -// records (sets). Use pattern for creating a message: -// -// m := new(dns.Msg) -// m.SetQuestion("miek.nl.", dns.TypeMX) -// -// Or when not certain if the domain name is fully qualified: -// -// m.SetQuestion(dns.Fqdn("miek.nl"), dns.TypeMX) -// -// The message m is now a message with the question section set to ask -// the MX records for the miek.nl. zone. -// -// The following is slightly more verbose, but more flexible: -// -// m1 := new(dns.Msg) -// m1.Id = dns.Id() -// m1.RecursionDesired = true -// m1.Question = make([]dns.Question, 1) -// m1.Question[0] = dns.Question{"miek.nl.", dns.TypeMX, dns.ClassINET} -// -// After creating a message it can be send. -// Basic use pattern for synchronous querying the DNS at a -// server configured on 127.0.0.1 and port 53: -// -// c := new(dns.Client) -// in, rtt, err := c.Exchange(m1, "127.0.0.1:53") -// -// Suppressing -// multiple outstanding queries (with the same question, type and class) is as easy as setting: -// -// c.SingleInflight = true -// -// If these "advanced" features are not needed, a simple UDP query can be send, -// with: -// -// in, err := dns.Exchange(m1, "127.0.0.1:53") -// -// When this functions returns you will get dns message. A dns message consists -// out of four sections. -// The question section: in.Question, the answer section: in.Answer, -// the authority section: in.Ns and the additional section: in.Extra. -// -// Each of these sections (except the Question section) contain a []RR. Basic -// use pattern for accessing the rdata of a TXT RR as the first RR in -// the Answer section: -// -// if t, ok := in.Answer[0].(*dns.TXT); ok { -// // do something with t.Txt -// } -// -// Domain Name and TXT Character String Representations -// -// Both domain names and TXT character strings are converted to presentation -// form both when unpacked and when converted to strings. -// -// For TXT character strings, tabs, carriage returns and line feeds will be -// converted to \t, \r and \n respectively. Back slashes and quotations marks -// will be escaped. Bytes below 32 and above 127 will be converted to \DDD -// form. -// -// For domain names, in addition to the above rules brackets, periods, -// spaces, semicolons and the at symbol are escaped. package dns -import ( - "strconv" -) +import "strconv" const ( - year68 = 1 << 31 // For RFC1982 (Serial Arithmetic) calculations in 32 bits. - DefaultMsgSize = 4096 // Standard default for larger than 512 bytes. - MinMsgSize = 512 // Minimal size of a DNS packet. - MaxMsgSize = 65536 // Largest possible DNS packet. - defaultTtl = 3600 // Default TTL. + year68 = 1 << 31 // For RFC1982 (Serial Arithmetic) calculations in 32 bits. + // DefaultMsgSize is the standard default for messages larger than 512 bytes. + DefaultMsgSize = 4096 + // MinMsgSize is the minimal size of a DNS packet. + MinMsgSize = 512 + // MaxMsgSize is the largest possible DNS packet. + MaxMsgSize = 65535 + defaultTtl = 3600 // Default internal TTL. ) // Error represents a DNS error @@ -124,13 +32,11 @@ type RR interface { String() string // copy returns a copy of the RR copy() RR - // len returns the length (in octects) of the uncompressed RR in wire format. + // len returns the length (in octets) of the uncompressed RR in wire format. 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 @@ -139,9 +45,10 @@ type RR_Header struct { Rdlength uint16 // length of data after header } +// Header returns itself. This is here to make RR_Header implement the RR interface. func (h *RR_Header) Header() *RR_Header { return h } -// Just to imlement the RR interface +// Just to imlement the RR interface. func (h *RR_Header) copy() RR { return nil } func (h *RR_Header) copyHeader() *RR_Header { diff --git a/vendor/github.com/miekg/dns/dnssec.go b/vendor/github.com/miekg/dns/dnssec.go index d1c2ae62582..84cb21421b9 100644 --- a/vendor/github.com/miekg/dns/dnssec.go +++ b/vendor/github.com/miekg/dns/dnssec.go @@ -1,16 +1,3 @@ -// DNSSEC -// -// DNSSEC (DNS Security Extension) adds a layer of security to the DNS. It -// uses public key cryptography to sign resource records. The -// public keys are stored in DNSKEY records and the signatures in RRSIG records. -// -// Requesting DNSSEC information for a zone is done by adding the DO (DNSSEC OK) bit -// to an request. -// -// m := new(dns.Msg) -// m.SetEdns0(4096, true) -// -// Signature generation, signature verification and key generation are all supported. package dns import ( @@ -19,15 +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" @@ -56,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 @@ -66,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 @@ -74,7 +104,7 @@ const ( ) // The RRSIG needs to be converted to wireformat with some of -// the rdata (the signature) missing. Use this struct to easy +// the rdata (the signature) missing. Use this struct to ease // the conversion (and re-use the pack/unpack functions). type rrsigWireFmt struct { TypeCovered uint16 @@ -182,35 +212,49 @@ 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 } -// Sign signs an RRSet. The signature needs to be filled in with -// the values: Inception, Expiration, KeyTag, SignerName and Algorithm. -// The rest is copied from the RRset. Sign returns true when the signing went OK, -// otherwise false. -// There is no check if RRSet is a proper (RFC 2181) RRSet. -// If OrigTTL is non zero, it is used as-is, otherwise the TTL of the RRset -// is used as the OrigTTL. -func (rr *RRSIG) Sign(k PrivateKey, rrset []RR) error { +// ToCDNSKEY converts a DNSKEY record to a CDNSKEY record. +func (k *DNSKEY) ToCDNSKEY() *CDNSKEY { + c := &CDNSKEY{DNSKEY: *k} + c.Hdr = *k.Hdr.copyHeader() + c.Hdr.Rrtype = TypeCDNSKEY + return c +} + +// ToCDS converts a DS record to a CDS record. +func (d *DS) ToCDS() *CDS { + c := &CDS{DS: *d} + c.Hdr = *d.Hdr.copyHeader() + c.Hdr.Rrtype = TypeCDS + return c +} + +// Sign signs an RRSet. The signature needs to be filled in with the values: +// Inception, Expiration, KeyTag, SignerName and Algorithm. The rest is copied +// from the RRset. Sign returns a non-nill error when the signing went OK. +// There is no check if RRSet is a proper (RFC 2181) RRSet. If OrigTTL is non +// zero, it is used as-is, otherwise the TTL of the RRset is used as the +// OrigTTL. +func (rr *RRSIG) Sign(k crypto.Signer, rrset []RR) error { if k == nil { return ErrPrivKey } @@ -256,72 +300,72 @@ func (rr *RRSIG) Sign(k PrivateKey, rrset []RR) error { } signdata = append(signdata, wire...) - var sighash []byte - var h hash.Hash - var ch crypto.Hash // Only need for RSA - var intlen int - switch rr.Algorithm { - case DSA, DSANSEC3SHA1: - // Implicit in the ParameterSizes - case RSASHA1, RSASHA1NSEC3SHA1: - h = sha1.New() - ch = crypto.SHA1 - case RSASHA256, ECDSAP256SHA256: - h = sha256.New() - ch = crypto.SHA256 - intlen = 32 - case ECDSAP384SHA384: - h = sha512.New384() - intlen = 48 - case RSASHA512: - h = sha512.New() - ch = crypto.SHA512 - case RSAMD5: - fallthrough // Deprecated in RFC 6725 - default: + hash, ok := AlgorithmToHash[rr.Algorithm] + if !ok { return ErrAlg } - io.WriteString(h, string(signdata)) - sighash = h.Sum(nil) - switch p := k.(type) { - case *dsa.PrivateKey: - r1, s1, err := dsa.Sign(rand.Reader, p, sighash) - if err != nil { - return err - } - signature := []byte{0x4D} // T value, here the ASCII M for Miek (not used in DNSSEC) - signature = append(signature, intToBytes(r1, 20)...) - signature = append(signature, intToBytes(s1, 20)...) - rr.Signature = toBase64(signature) - case *rsa.PrivateKey: - // We can use nil as rand.Reader here (says AGL) - signature, err := rsa.SignPKCS1v15(nil, p, ch, sighash) - if err != nil { - return err - } - rr.Signature = toBase64(signature) - case *ecdsa.PrivateKey: - r1, s1, err := ecdsa.Sign(rand.Reader, p, sighash) - if err != nil { - return err - } - signature := intToBytes(r1, intlen) - signature = append(signature, intToBytes(s1, intlen)...) - rr.Signature = toBase64(signature) - default: - // Not given the correct key - return ErrKeyAlg + h := hash.New() + h.Write(signdata) + + signature, err := sign(k, h.Sum(nil), hash, rr.Algorithm) + if err != nil { + return err } + + rr.Signature = toBase64(signature) + return nil } +func sign(k crypto.Signer, hashed []byte, hash crypto.Hash, alg uint8) ([]byte, error) { + signature, err := k.Sign(rand.Reader, hashed, hash) + if err != nil { + return nil, err + } + + switch alg { + case RSASHA1, RSASHA1NSEC3SHA1, RSASHA256, RSASHA512: + return signature, nil + + case ECDSAP256SHA256, ECDSAP384SHA384: + ecdsaSignature := &struct { + R, S *big.Int + }{} + if _, err := asn1.Unmarshal(signature, ecdsaSignature); err != nil { + return nil, err + } + + var intlen int + switch alg { + case ECDSAP256SHA256: + intlen = 32 + case ECDSAP384SHA384: + intlen = 48 + } + + signature := intToBytes(ecdsaSignature.R, intlen) + signature = append(signature, intToBytes(ecdsaSignature.S, intlen)...) + return signature, nil + + // There is no defined interface for what a DSA backed crypto.Signer returns + case DSA, DSANSEC3SHA1: + // t := divRoundUp(divRoundUp(p.PublicKey.Y.BitLen(), 8)-64, 8) + // signature := []byte{byte(t)} + // signature = append(signature, intToBytes(r1, 20)...) + // signature = append(signature, intToBytes(s1, 20)...) + // rr.Signature = signature + } + + return nil, ErrAlg +} + // Verify validates an RRSet with the signature and key. This is only the // cryptographic test, the signature validity period must be checked separately. // This function copies the rdata of some RRs (to lowercase domain names) for the validation to work. func (rr *RRSIG) Verify(k *DNSKEY, rrset []RR) error { // First the easy checks - if len(rrset) == 0 { + if !IsRRset(rrset) { return ErrRRset } if rr.KeyTag != k.KeyTag() { @@ -339,14 +383,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) @@ -373,8 +420,13 @@ func (rr *RRSIG) Verify(k *DNSKEY, rrset []RR) error { sigbuf := rr.sigBuf() // Get the binary signature data if rr.Algorithm == PRIVATEDNS { // PRIVATEOID - // TODO(mg) - // remove the domain name and assume its our + // TODO(miek) + // remove the domain name and assume its ours? + } + + hash, ok := AlgorithmToHash[rr.Algorithm] + if !ok { + return ErrAlg } switch rr.Algorithm { @@ -384,57 +436,37 @@ 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.publicKeyCurve() + 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 // 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() { @@ -450,39 +482,14 @@ func (rr *RRSIG) ValidityPeriod(t time.Time) bool { } // Return the signatures base64 encodedig sigdata as a byte slice. -func (s *RRSIG) sigBuf() []byte { - sigbuf, err := fromBase64([]byte(s.Signature)) +func (rr *RRSIG) sigBuf() []byte { + sigbuf, err := fromBase64([]byte(rr.Signature)) if err != nil { return nil } return sigbuf } -// setPublicKeyInPrivate sets the public key in the private key. -func (k *DNSKEY) setPublicKeyInPrivate(p PrivateKey) bool { - switch t := p.(type) { - case *dsa.PrivateKey: - x := k.publicKeyDSA() - if x == nil { - return false - } - t.PublicKey = *x - case *rsa.PrivateKey: - x := k.publicKeyRSA() - if x == nil { - return false - } - t.PublicKey = *x - case *ecdsa.PrivateKey: - x := k.publicKeyCurve() - if x == nil { - return false - } - t.PublicKey = *x - } - return true -} - // publicKeyRSA returns the RSA public key from a DNSKEY record. func (k *DNSKEY) publicKeyRSA() *rsa.PublicKey { keybuf, err := fromBase64([]byte(k.PublicKey)) @@ -521,8 +528,8 @@ func (k *DNSKEY) publicKeyRSA() *rsa.PublicKey { return pubkey } -// publicKeyCurve returns the Curve public key from the DNSKEY record. -func (k *DNSKEY) publicKeyCurve() *ecdsa.PublicKey { +// publicKeyECDSA returns the Curve public key from the DNSKEY record. +func (k *DNSKEY) publicKeyECDSA() *ecdsa.PublicKey { keybuf, err := fromBase64([]byte(k.PublicKey)) if err != nil { return nil @@ -573,81 +580,6 @@ func (k *DNSKEY) publicKeyDSA() *dsa.PublicKey { return pubkey } -// Set the public key (the value E and N) -func (k *DNSKEY) setPublicKeyRSA(_E int, _N *big.Int) bool { - if _E == 0 || _N == nil { - return false - } - buf := exponentToBuf(_E) - buf = append(buf, _N.Bytes()...) - k.PublicKey = toBase64(buf) - return true -} - -// Set the public key for Elliptic Curves -func (k *DNSKEY) setPublicKeyCurve(_X, _Y *big.Int) bool { - if _X == nil || _Y == nil { - return false - } - var intlen int - switch k.Algorithm { - case ECDSAP256SHA256: - intlen = 32 - case ECDSAP384SHA384: - intlen = 48 - } - k.PublicKey = toBase64(curveToBuf(_X, _Y, intlen)) - return true -} - -// Set the public key for DSA -func (k *DNSKEY) setPublicKeyDSA(_Q, _P, _G, _Y *big.Int) bool { - if _Q == nil || _P == nil || _G == nil || _Y == nil { - return false - } - buf := dsaToBuf(_Q, _P, _G, _Y) - k.PublicKey = toBase64(buf) - return true -} - -// Set the public key (the values E and N) for RSA -// RFC 3110: Section 2. RSA Public KEY Resource Records -func exponentToBuf(_E int) []byte { - var buf []byte - i := big.NewInt(int64(_E)) - if len(i.Bytes()) < 256 { - buf = make([]byte, 1) - buf[0] = uint8(len(i.Bytes())) - } else { - buf = make([]byte, 3) - buf[0] = 0 - buf[1] = uint8(len(i.Bytes()) >> 8) - buf[2] = uint8(len(i.Bytes())) - } - buf = append(buf, i.Bytes()...) - return buf -} - -// Set the public key for X and Y for Curve. The two -// values are just concatenated. -func curveToBuf(_X, _Y *big.Int, intlen int) []byte { - buf := intToBytes(_X, intlen) - buf = append(buf, intToBytes(_Y, intlen)...) - return buf -} - -// Set the public key for X and Y for Curve. The two -// values are just concatenated. -func dsaToBuf(_Q, _P, _G, _Y *big.Int) []byte { - t := divRoundUp(divRoundUp(_G.BitLen(), 8)-64, 8) - buf := []byte{byte(t)} - buf = append(buf, intToBytes(_Q, 20)...) - buf = append(buf, intToBytes(_P, 64+t*8)...) - buf = append(buf, intToBytes(_G, 64+t*8)...) - buf = append(buf, intToBytes(_Y, 64+t*8)...) - return buf -} - type wireSlice [][]byte func (p wireSlice) Len() int { return len(p) } @@ -676,6 +608,12 @@ func rawSignatureData(rrset []RR, s *RRSIG) (buf []byte, err error) { // NS, MD, MF, CNAME, SOA, MB, MG, MR, PTR, // HINFO, MINFO, MX, RP, AFSDB, RT, SIG, PX, NXT, NAPTR, KX, // SRV, DNAME, A6 + // + // RFC 6840 - Clarifications and Implementation Notes for DNS Security (DNSSEC): + // Section 6.2 of [RFC4034] also erroneously lists HINFO as a record + // that needs conversion to lowercase, and twice at that. Since HINFO + // records contain no domain names, they are not subject to case + // conversion. switch x := r1.(type) { case *NS: x.Ns = strings.ToLower(x.Ns) @@ -716,41 +654,11 @@ func rawSignatureData(rrset []RR, s *RRSIG) (buf []byte, err error) { wires[i] = wire } sort.Sort(wires) - for _, wire := range wires { + for i, wire := range wires { + if i > 0 && bytes.Equal(wire, wires[i-1]) { + continue + } buf = append(buf, wire...) } 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) diff --git a/vendor/github.com/miekg/dns/dnssec_keygen.go b/vendor/github.com/miekg/dns/dnssec_keygen.go new file mode 100644 index 00000000000..229a079370b --- /dev/null +++ b/vendor/github.com/miekg/dns/dnssec_keygen.go @@ -0,0 +1,156 @@ +package dns + +import ( + "crypto" + "crypto/dsa" + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" + "crypto/rsa" + "math/big" +) + +// Generate generates a DNSKEY of the given bit size. +// The public part is put inside the DNSKEY record. +// The Algorithm in the key must be set as this will define +// what kind of DNSKEY will be generated. +// The ECDSA algorithms imply a fixed keysize, in that case +// bits should be set to the size of the algorithm. +func (k *DNSKEY) Generate(bits int) (crypto.PrivateKey, error) { + switch k.Algorithm { + case DSA, DSANSEC3SHA1: + if bits != 1024 { + return nil, ErrKeySize + } + case RSAMD5, RSASHA1, RSASHA256, RSASHA1NSEC3SHA1: + if bits < 512 || bits > 4096 { + return nil, ErrKeySize + } + case RSASHA512: + if bits < 1024 || bits > 4096 { + return nil, ErrKeySize + } + case ECDSAP256SHA256: + if bits != 256 { + return nil, ErrKeySize + } + case ECDSAP384SHA384: + if bits != 384 { + return nil, ErrKeySize + } + } + + switch k.Algorithm { + case DSA, DSANSEC3SHA1: + params := new(dsa.Parameters) + if err := dsa.GenerateParameters(params, rand.Reader, dsa.L1024N160); err != nil { + return nil, err + } + priv := new(dsa.PrivateKey) + priv.PublicKey.Parameters = *params + err := dsa.GenerateKey(priv, rand.Reader) + if err != nil { + return nil, err + } + k.setPublicKeyDSA(params.Q, params.P, params.G, priv.PublicKey.Y) + return priv, nil + case RSAMD5, RSASHA1, RSASHA256, RSASHA512, RSASHA1NSEC3SHA1: + priv, err := rsa.GenerateKey(rand.Reader, bits) + if err != nil { + return nil, err + } + k.setPublicKeyRSA(priv.PublicKey.E, priv.PublicKey.N) + return priv, nil + case ECDSAP256SHA256, ECDSAP384SHA384: + var c elliptic.Curve + switch k.Algorithm { + case ECDSAP256SHA256: + c = elliptic.P256() + case ECDSAP384SHA384: + c = elliptic.P384() + } + priv, err := ecdsa.GenerateKey(c, rand.Reader) + if err != nil { + return nil, err + } + k.setPublicKeyECDSA(priv.PublicKey.X, priv.PublicKey.Y) + return priv, nil + default: + return nil, ErrAlg + } +} + +// Set the public key (the value E and N) +func (k *DNSKEY) setPublicKeyRSA(_E int, _N *big.Int) bool { + if _E == 0 || _N == nil { + return false + } + buf := exponentToBuf(_E) + buf = append(buf, _N.Bytes()...) + k.PublicKey = toBase64(buf) + return true +} + +// Set the public key for Elliptic Curves +func (k *DNSKEY) setPublicKeyECDSA(_X, _Y *big.Int) bool { + if _X == nil || _Y == nil { + return false + } + var intlen int + switch k.Algorithm { + case ECDSAP256SHA256: + intlen = 32 + case ECDSAP384SHA384: + intlen = 48 + } + k.PublicKey = toBase64(curveToBuf(_X, _Y, intlen)) + return true +} + +// Set the public key for DSA +func (k *DNSKEY) setPublicKeyDSA(_Q, _P, _G, _Y *big.Int) bool { + if _Q == nil || _P == nil || _G == nil || _Y == nil { + return false + } + buf := dsaToBuf(_Q, _P, _G, _Y) + k.PublicKey = toBase64(buf) + return true +} + +// Set the public key (the values E and N) for RSA +// RFC 3110: Section 2. RSA Public KEY Resource Records +func exponentToBuf(_E int) []byte { + var buf []byte + i := big.NewInt(int64(_E)) + if len(i.Bytes()) < 256 { + buf = make([]byte, 1) + buf[0] = uint8(len(i.Bytes())) + } else { + buf = make([]byte, 3) + buf[0] = 0 + buf[1] = uint8(len(i.Bytes()) >> 8) + buf[2] = uint8(len(i.Bytes())) + } + buf = append(buf, i.Bytes()...) + return buf +} + +// Set the public key for X and Y for Curve. The two +// values are just concatenated. +func curveToBuf(_X, _Y *big.Int, intlen int) []byte { + buf := intToBytes(_X, intlen) + buf = append(buf, intToBytes(_Y, intlen)...) + return buf +} + +// Set the public key for X and Y for Curve. The two +// values are just concatenated. +func dsaToBuf(_Q, _P, _G, _Y *big.Int) []byte { + t := divRoundUp(divRoundUp(_G.BitLen(), 8)-64, 8) + buf := []byte{byte(t)} + buf = append(buf, intToBytes(_Q, 20)...) + buf = append(buf, intToBytes(_P, 64+t*8)...) + buf = append(buf, intToBytes(_G, 64+t*8)...) + buf = append(buf, intToBytes(_Y, 64+t*8)...) + return buf +} diff --git a/vendor/github.com/miekg/dns/kscan.go b/vendor/github.com/miekg/dns/dnssec_keyscan.go similarity index 73% rename from vendor/github.com/miekg/dns/kscan.go rename to vendor/github.com/miekg/dns/dnssec_keyscan.go index c48ca2d24b7..19a783389ab 100644 --- a/vendor/github.com/miekg/dns/kscan.go +++ b/vendor/github.com/miekg/dns/dnssec_keyscan.go @@ -1,15 +1,19 @@ package dns import ( + "crypto" "crypto/dsa" "crypto/ecdsa" "crypto/rsa" "io" "math/big" + "strconv" "strings" ) -func (k *DNSKEY) NewPrivateKey(s string) (PrivateKey, error) { +// NewPrivateKey returns a PrivateKey by parsing the string s. +// s should be in the same form of the BIND private key files. +func (k *DNSKEY) NewPrivateKey(s string) (crypto.PrivateKey, error) { if s[len(s)-1] != '\n' { // We need a closing newline return k.ReadPrivateKey(strings.NewReader(s+"\n"), "") } @@ -18,9 +22,9 @@ func (k *DNSKEY) NewPrivateKey(s string) (PrivateKey, error) { // ReadPrivateKey reads a private key from the io.Reader q. The string file is // only used in error reporting. -// The public key must be -// known, because some cryptographic algorithms embed the public inside the privatekey. -func (k *DNSKEY) ReadPrivateKey(q io.Reader, file string) (PrivateKey, error) { +// The public key must be known, because some cryptographic algorithms embed +// the public inside the privatekey. +func (k *DNSKEY) ReadPrivateKey(q io.Reader, file string) (crypto.PrivateKey, error) { m, e := parseKey(q, file) if m == nil { return nil, e @@ -32,57 +36,63 @@ func (k *DNSKEY) ReadPrivateKey(q io.Reader, file string) (PrivateKey, error) { return nil, ErrPrivKey } // TODO(mg): check if the pubkey matches the private key - switch m["algorithm"] { - case "3 (DSA)": - p, e := readPrivateKeyDSA(m) - if e != nil { - return nil, e - } - if !k.setPublicKeyInPrivate(p) { - return nil, ErrKey - } - return p, e - case "1 (RSAMD5)": - fallthrough - case "5 (RSASHA1)": - fallthrough - case "7 (RSASHA1NSEC3SHA1)": - fallthrough - case "8 (RSASHA256)": - fallthrough - case "10 (RSASHA512)": - p, e := readPrivateKeyRSA(m) - if e != nil { - return nil, e - } - if !k.setPublicKeyInPrivate(p) { - return nil, ErrKey - } - return p, e - case "12 (ECC-GOST)": - p, e := readPrivateKeyGOST(m) - if e != nil { - return nil, e - } - // setPublicKeyInPrivate(p) - return p, e - case "13 (ECDSAP256SHA256)": - fallthrough - case "14 (ECDSAP384SHA384)": - p, e := readPrivateKeyECDSA(m) - if e != nil { - return nil, e - } - if !k.setPublicKeyInPrivate(p) { - return nil, ErrKey - } - return p, e + algo, err := strconv.Atoi(strings.SplitN(m["algorithm"], " ", 2)[0]) + if err != nil { + return nil, ErrPrivKey + } + switch uint8(algo) { + case DSA: + priv, e := readPrivateKeyDSA(m) + if e != nil { + return nil, e + } + pub := k.publicKeyDSA() + if pub == nil { + return nil, ErrKey + } + priv.PublicKey = *pub + return priv, e + case RSAMD5: + fallthrough + case RSASHA1: + fallthrough + case RSASHA1NSEC3SHA1: + fallthrough + case RSASHA256: + fallthrough + case RSASHA512: + priv, e := readPrivateKeyRSA(m) + if e != nil { + return nil, e + } + pub := k.publicKeyRSA() + if pub == nil { + return nil, ErrKey + } + priv.PublicKey = *pub + return priv, e + case ECCGOST: + return nil, ErrPrivKey + case ECDSAP256SHA256: + fallthrough + case ECDSAP384SHA384: + priv, e := readPrivateKeyECDSA(m) + if e != nil { + return nil, e + } + pub := k.publicKeyECDSA() + if pub == nil { + return nil, ErrKey + } + priv.PublicKey = *pub + return priv, e + default: + return nil, ErrPrivKey } - return nil, ErrPrivKey } // Read a private key (file) string and create a public key. Return the private key. -func readPrivateKeyRSA(m map[string]string) (PrivateKey, error) { +func readPrivateKeyRSA(m map[string]string) (*rsa.PrivateKey, error) { p := new(rsa.PrivateKey) p.Primes = []*big.Int{nil, nil} for k, v := range m { @@ -119,7 +129,7 @@ func readPrivateKeyRSA(m map[string]string) (PrivateKey, error) { return p, nil } -func readPrivateKeyDSA(m map[string]string) (PrivateKey, error) { +func readPrivateKeyDSA(m map[string]string) (*dsa.PrivateKey, error) { p := new(dsa.PrivateKey) p.X = big.NewInt(0) for k, v := range m { @@ -137,7 +147,7 @@ func readPrivateKeyDSA(m map[string]string) (PrivateKey, error) { return p, nil } -func readPrivateKeyECDSA(m map[string]string) (PrivateKey, error) { +func readPrivateKeyECDSA(m map[string]string) (*ecdsa.PrivateKey, error) { p := new(ecdsa.PrivateKey) p.D = big.NewInt(0) // TODO: validate that the required flags are present @@ -156,11 +166,6 @@ func readPrivateKeyECDSA(m map[string]string) (PrivateKey, error) { return p, nil } -func readPrivateKeyGOST(m map[string]string) (PrivateKey, error) { - // TODO(miek) - return nil, nil -} - // parseKey reads a private key from r. It returns a map[string]string, // with the key-value pairs, or an error when the file is not correct. func parseKey(r io.Reader, file string) (map[string]string, error) { @@ -173,9 +178,9 @@ func parseKey(r io.Reader, file string) (map[string]string, error) { for l := range c { // It should alternate switch l.value { - case _KEY: + case zKey: k = l.token - case _VALUE: + case zValue: if k == "" { return nil, &ParseError{file, "no private key seen", l} } @@ -205,14 +210,14 @@ func klexer(s *scan, c chan lex) { } l.token = str if key { - l.value = _KEY + l.value = zKey c <- l // Next token is a space, eat it s.tokenText() key = false str = "" } else { - l.value = _VALUE + l.value = zValue } case ';': commt = true @@ -221,7 +226,7 @@ func klexer(s *scan, c chan lex) { // Reset a comment commt = false } - l.value = _VALUE + l.value = zValue l.token = str c <- l str = "" @@ -238,7 +243,7 @@ func klexer(s *scan, c chan lex) { if len(str) > 0 { // Send remainder l.token = str - l.value = _VALUE + l.value = zValue c <- l } } diff --git a/vendor/github.com/miekg/dns/dnssec_privkey.go b/vendor/github.com/miekg/dns/dnssec_privkey.go new file mode 100644 index 00000000000..56f3ea934f6 --- /dev/null +++ b/vendor/github.com/miekg/dns/dnssec_privkey.go @@ -0,0 +1,85 @@ +package dns + +import ( + "crypto" + "crypto/dsa" + "crypto/ecdsa" + "crypto/rsa" + "math/big" + "strconv" +) + +const format = "Private-key-format: v1.3\n" + +// PrivateKeyString converts a PrivateKey to a string. This string has the same +// format as the private-key-file of BIND9 (Private-key-format: v1.3). +// It needs some info from the key (the algorithm), so its a method of the DNSKEY +// It supports rsa.PrivateKey, ecdsa.PrivateKey and dsa.PrivateKey +func (r *DNSKEY) PrivateKeyString(p crypto.PrivateKey) string { + algorithm := strconv.Itoa(int(r.Algorithm)) + algorithm += " (" + AlgorithmToString[r.Algorithm] + ")" + + switch p := p.(type) { + case *rsa.PrivateKey: + modulus := toBase64(p.PublicKey.N.Bytes()) + e := big.NewInt(int64(p.PublicKey.E)) + publicExponent := toBase64(e.Bytes()) + privateExponent := toBase64(p.D.Bytes()) + prime1 := toBase64(p.Primes[0].Bytes()) + prime2 := toBase64(p.Primes[1].Bytes()) + // Calculate Exponent1/2 and Coefficient as per: http://en.wikipedia.org/wiki/RSA#Using_the_Chinese_remainder_algorithm + // and from: http://code.google.com/p/go/issues/detail?id=987 + one := big.NewInt(1) + p1 := big.NewInt(0).Sub(p.Primes[0], one) + q1 := big.NewInt(0).Sub(p.Primes[1], one) + exp1 := big.NewInt(0).Mod(p.D, p1) + exp2 := big.NewInt(0).Mod(p.D, q1) + coeff := big.NewInt(0).ModInverse(p.Primes[1], p.Primes[0]) + + exponent1 := toBase64(exp1.Bytes()) + exponent2 := toBase64(exp2.Bytes()) + coefficient := toBase64(coeff.Bytes()) + + return format + + "Algorithm: " + algorithm + "\n" + + "Modulus: " + modulus + "\n" + + "PublicExponent: " + publicExponent + "\n" + + "PrivateExponent: " + privateExponent + "\n" + + "Prime1: " + prime1 + "\n" + + "Prime2: " + prime2 + "\n" + + "Exponent1: " + exponent1 + "\n" + + "Exponent2: " + exponent2 + "\n" + + "Coefficient: " + coefficient + "\n" + + case *ecdsa.PrivateKey: + var intlen int + switch r.Algorithm { + case ECDSAP256SHA256: + intlen = 32 + case ECDSAP384SHA384: + intlen = 48 + } + private := toBase64(intToBytes(p.D, intlen)) + return format + + "Algorithm: " + algorithm + "\n" + + "PrivateKey: " + private + "\n" + + case *dsa.PrivateKey: + T := divRoundUp(divRoundUp(p.PublicKey.Parameters.G.BitLen(), 8)-64, 8) + prime := toBase64(intToBytes(p.PublicKey.Parameters.P, 64+T*8)) + subprime := toBase64(intToBytes(p.PublicKey.Parameters.Q, 20)) + base := toBase64(intToBytes(p.PublicKey.Parameters.G, 64+T*8)) + priv := toBase64(intToBytes(p.X, 20)) + pub := toBase64(intToBytes(p.PublicKey.Y, 64+T*8)) + return format + + "Algorithm: " + algorithm + "\n" + + "Prime(p): " + prime + "\n" + + "Subprime(q): " + subprime + "\n" + + "Base(g): " + base + "\n" + + "Private_value(x): " + priv + "\n" + + "Public_value(y): " + pub + "\n" + + default: + return "" + } +} diff --git a/vendor/github.com/miekg/dns/doc.go b/vendor/github.com/miekg/dns/doc.go new file mode 100644 index 00000000000..f3555e43399 --- /dev/null +++ b/vendor/github.com/miekg/dns/doc.go @@ -0,0 +1,251 @@ +/* +Package dns implements a full featured interface to the Domain Name System. +Server- and client-side programming is supported. +The package allows complete control over what is send out to the DNS. The package +API follows the less-is-more principle, by presenting a small, clean interface. + +The package dns supports (asynchronous) querying/replying, incoming/outgoing zone transfers, +TSIG, EDNS0, dynamic updates, notifies and DNSSEC validation/signing. +Note that domain names MUST be fully qualified, before sending them, unqualified +names in a message will result in a packing failure. + +Resource records are native types. They are not stored in wire format. +Basic usage pattern for creating a new resource record: + + r := new(dns.MX) + r.Hdr = dns.RR_Header{Name: "miek.nl.", Rrtype: dns.TypeMX, + Class: dns.ClassINET, Ttl: 3600} + r.Preference = 10 + r.Mx = "mx.miek.nl." + +Or directly from a string: + + mx, err := dns.NewRR("miek.nl. 3600 IN MX 10 mx.miek.nl.") + +Or when the default TTL (3600) and class (IN) suit you: + + mx, err := dns.NewRR("miek.nl. MX 10 mx.miek.nl.") + +Or even: + + mx, err := dns.NewRR("$ORIGIN nl.\nmiek 1H IN MX 10 mx.miek") + +In the DNS messages are exchanged, these messages contain resource +records (sets). Use pattern for creating a message: + + m := new(dns.Msg) + m.SetQuestion("miek.nl.", dns.TypeMX) + +Or when not certain if the domain name is fully qualified: + + m.SetQuestion(dns.Fqdn("miek.nl"), dns.TypeMX) + +The message m is now a message with the question section set to ask +the MX records for the miek.nl. zone. + +The following is slightly more verbose, but more flexible: + + m1 := new(dns.Msg) + m1.Id = dns.Id() + m1.RecursionDesired = true + m1.Question = make([]dns.Question, 1) + m1.Question[0] = dns.Question{"miek.nl.", dns.TypeMX, dns.ClassINET} + +After creating a message it can be send. +Basic use pattern for synchronous querying the DNS at a +server configured on 127.0.0.1 and port 53: + + c := new(dns.Client) + in, rtt, err := c.Exchange(m1, "127.0.0.1:53") + +Suppressing multiple outstanding queries (with the same question, type and +class) is as easy as setting: + + c.SingleInflight = true + +If these "advanced" features are not needed, a simple UDP query can be send, +with: + + in, err := dns.Exchange(m1, "127.0.0.1:53") + +When this functions returns you will get dns message. A dns message consists +out of four sections. +The question section: in.Question, the answer section: in.Answer, +the authority section: in.Ns and the additional section: in.Extra. + +Each of these sections (except the Question section) contain a []RR. Basic +use pattern for accessing the rdata of a TXT RR as the first RR in +the Answer section: + + if t, ok := in.Answer[0].(*dns.TXT); ok { + // do something with t.Txt + } + +Domain Name and TXT Character String Representations + +Both domain names and TXT character strings are converted to presentation +form both when unpacked and when converted to strings. + +For TXT character strings, tabs, carriage returns and line feeds will be +converted to \t, \r and \n respectively. Back slashes and quotations marks +will be escaped. Bytes below 32 and above 127 will be converted to \DDD +form. + +For domain names, in addition to the above rules brackets, periods, +spaces, semicolons and the at symbol are escaped. + +DNSSEC + +DNSSEC (DNS Security Extension) adds a layer of security to the DNS. It +uses public key cryptography to sign resource records. The +public keys are stored in DNSKEY records and the signatures in RRSIG records. + +Requesting DNSSEC information for a zone is done by adding the DO (DNSSEC OK) bit +to a request. + + m := new(dns.Msg) + m.SetEdns0(4096, true) + +Signature generation, signature verification and key generation are all supported. + +DYNAMIC UPDATES + +Dynamic updates reuses the DNS message format, but renames three of +the sections. Question is Zone, Answer is Prerequisite, Authority is +Update, only the Additional is not renamed. See RFC 2136 for the gory details. + +You can set a rather complex set of rules for the existence of absence of +certain resource records or names in a zone to specify if resource records +should be added or removed. The table from RFC 2136 supplemented with the Go +DNS function shows which functions exist to specify the prerequisites. + + 3.2.4 - Table Of Metavalues Used In Prerequisite Section + + CLASS TYPE RDATA Meaning Function + -------------------------------------------------------------- + ANY ANY empty Name is in use dns.NameUsed + ANY rrset empty RRset exists (value indep) dns.RRsetUsed + NONE ANY empty Name is not in use dns.NameNotUsed + NONE rrset empty RRset does not exist dns.RRsetNotUsed + zone rrset rr RRset exists (value dep) dns.Used + +The prerequisite section can also be left empty. +If you have decided on the prerequisites you can tell what RRs should +be added or deleted. The next table shows the options you have and +what functions to call. + + 3.4.2.6 - Table Of Metavalues Used In Update Section + + CLASS TYPE RDATA Meaning Function + --------------------------------------------------------------- + ANY ANY empty Delete all RRsets from name dns.RemoveName + ANY rrset empty Delete an RRset dns.RemoveRRset + NONE rrset rr Delete an RR from RRset dns.Remove + zone rrset rr Add to an RRset dns.Insert + +TRANSACTION SIGNATURE + +An TSIG or transaction signature adds a HMAC TSIG record to each message sent. +The supported algorithms include: HmacMD5, HmacSHA1, HmacSHA256 and HmacSHA512. + +Basic use pattern when querying with a TSIG name "axfr." (note that these key names +must be fully qualified - as they are domain names) and the base64 secret +"so6ZGir4GPAqINNh9U5c3A==": + + c := new(dns.Client) + c.TsigSecret = map[string]string{"axfr.": "so6ZGir4GPAqINNh9U5c3A=="} + m := new(dns.Msg) + m.SetQuestion("miek.nl.", dns.TypeMX) + m.SetTsig("axfr.", dns.HmacMD5, 300, time.Now().Unix()) + ... + // When sending the TSIG RR is calculated and filled in before sending + +When requesting an zone transfer (almost all TSIG usage is when requesting zone transfers), with +TSIG, this is the basic use pattern. In this example we request an AXFR for +miek.nl. with TSIG key named "axfr." and secret "so6ZGir4GPAqINNh9U5c3A==" +and using the server 176.58.119.54: + + t := new(dns.Transfer) + m := new(dns.Msg) + t.TsigSecret = map[string]string{"axfr.": "so6ZGir4GPAqINNh9U5c3A=="} + m.SetAxfr("miek.nl.") + m.SetTsig("axfr.", dns.HmacMD5, 300, time.Now().Unix()) + c, err := t.In(m, "176.58.119.54:53") + for r := range c { ... } + +You can now read the records from the transfer as they come in. Each envelope is checked with TSIG. +If something is not correct an error is returned. + +Basic use pattern validating and replying to a message that has TSIG set. + + server := &dns.Server{Addr: ":53", Net: "udp"} + server.TsigSecret = map[string]string{"axfr.": "so6ZGir4GPAqINNh9U5c3A=="} + go server.ListenAndServe() + dns.HandleFunc(".", handleRequest) + + func handleRequest(w dns.ResponseWriter, r *dns.Msg) { + m := new(dns.Msg) + m.SetReply(r) + if r.IsTsig() != nil { + if w.TsigStatus() == nil { + // *Msg r has an TSIG record and it was validated + m.SetTsig("axfr.", dns.HmacMD5, 300, time.Now().Unix()) + } else { + // *Msg r has an TSIG records and it was not valided + } + } + w.WriteMsg(m) + } + +PRIVATE RRS + +RFC 6895 sets aside a range of type codes for private use. This range +is 65,280 - 65,534 (0xFF00 - 0xFFFE). When experimenting with new Resource Records these +can be used, before requesting an official type code from IANA. + +see http://miek.nl/posts/2014/Sep/21/Private%20RRs%20and%20IDN%20in%20Go%20DNS/ for more +information. + +EDNS0 + +EDNS0 is an extension mechanism for the DNS defined in RFC 2671 and updated +by RFC 6891. It defines an new RR type, the OPT RR, which is then completely +abused. +Basic use pattern for creating an (empty) OPT RR: + + o := new(dns.OPT) + o.Hdr.Name = "." // MUST be the root zone, per definition. + o.Hdr.Rrtype = dns.TypeOPT + +The rdata of an OPT RR consists out of a slice of EDNS0 (RFC 6891) +interfaces. Currently only a few have been standardized: EDNS0_NSID +(RFC 5001) and EDNS0_SUBNET (draft-vandergaast-edns-client-subnet-02). Note +that these options may be combined in an OPT RR. +Basic use pattern for a server to check if (and which) options are set: + + // o is a dns.OPT + for _, s := range o.Option { + switch e := s.(type) { + case *dns.EDNS0_NSID: + // do stuff with e.Nsid + case *dns.EDNS0_SUBNET: + // access e.Family, e.Address, etc. + } + } + +SIG(0) + +From RFC 2931: + + SIG(0) provides protection for DNS transactions and requests .... + ... protection for glue records, DNS requests, protection for message headers + on requests and responses, and protection of the overall integrity of a response. + +It works like TSIG, except that SIG(0) uses public key cryptography, instead of the shared +secret approach in TSIG. +Supported algorithms: DSA, ECDSAP256SHA256, ECDSAP384SHA384, RSASHA1, RSASHA256 and +RSASHA512. + +Signing subsequent messages in multi-message sessions is not implemented. +*/ +package dns diff --git a/vendor/github.com/miekg/dns/edns.go b/vendor/github.com/miekg/dns/edns.go index 8b676e61241..0c47f6ea5a4 100644 --- a/vendor/github.com/miekg/dns/edns.go +++ b/vendor/github.com/miekg/dns/edns.go @@ -1,29 +1,3 @@ -// EDNS0 -// -// EDNS0 is an extension mechanism for the DNS defined in RFC 2671 and updated -// by RFC 6891. It defines an new RR type, the OPT RR, which is then completely -// abused. -// Basic use pattern for creating an (empty) OPT RR: -// -// o := new(dns.OPT) -// o.Hdr.Name = "." // MUST be the root zone, per definition. -// o.Hdr.Rrtype = dns.TypeOPT -// -// The rdata of an OPT RR consists out of a slice of EDNS0 (RFC 6891) -// interfaces. Currently only a few have been standardized: EDNS0_NSID -// (RFC 5001) and EDNS0_SUBNET (draft-vandergaast-edns-client-subnet-02). Note -// that these options may be combined in an OPT RR. -// Basic use pattern for a server to check if (and which) options are set: -// -// // o is a dns.OPT -// for _, s := range o.Option { -// switch e := s.(type) { -// case *dns.EDNS0_NSID: -// // do stuff with e.Nsid -// case *dns.EDNS0_SUBNET: -// // access e.Family, e.Address, etc. -// } -// } package dns import ( @@ -44,18 +18,18 @@ const ( EDNS0SUBNET = 0x8 // client-subnet (RFC6891) EDNS0EXPIRE = 0x9 // EDNS0 expire EDNS0SUBNETDRAFT = 0x50fa // Don't use! Use EDNS0SUBNET + EDNS0LOCALSTART = 0xFDE9 // Beginning of range reserved for local/experimental use (RFC6891) + EDNS0LOCALEND = 0xFFFE // End of range reserved for local/experimental use (RFC6891) _DO = 1 << 15 // dnssec ok ) +// OPT is the EDNS0 RR appended to messages to convey extra (meta) information. +// See RFC 6891. type OPT struct { Hdr RR_Header Option []EDNS0 `dns:"opt"` } -func (rr *OPT) Header() *RR_Header { - return &rr.Hdr -} - func (rr *OPT) String() string { s := "\n;; OPT PSEUDOSECTION:\n; EDNS: version " + strconv.Itoa(int(rr.Version())) + "; " if rr.Do() { @@ -92,6 +66,8 @@ func (rr *OPT) String() string { s += "\n; DS HASH UNDERSTOOD: " + o.String() case *EDNS0_N3U: s += "\n; NSEC3 HASH UNDERSTOOD: " + o.String() + case *EDNS0_LOCAL: + s += "\n; LOCAL OPT: " + o.String() } } return s @@ -100,16 +76,13 @@ func (rr *OPT) String() string { func (rr *OPT) len() int { l := rr.Hdr.len() for i := 0; i < len(rr.Option); i++ { + l += 4 // Account for 2-byte option code and 2-byte option length. lo, _ := rr.Option[i].pack() - l += 2 + len(lo) + l += len(lo) } return l } -func (rr *OPT) copy() RR { - return &OPT{*rr.Hdr.copyHeader(), rr.Option} -} - // return the old value -> delete SetVersion? // Version returns the EDNS version used. Only zero is defined. @@ -195,7 +168,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: @@ -211,6 +184,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 @@ -237,38 +215,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") } @@ -276,8 +238,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) @@ -285,25 +246,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 } @@ -320,7 +283,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 @@ -358,7 +321,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 @@ -499,3 +462,44 @@ func (e *EDNS0_EXPIRE) unpack(b []byte) error { e.Expire = uint32(b[0])<<24 | uint32(b[1])<<16 | uint32(b[2])<<8 | uint32(b[3]) return nil } + +// The EDNS0_LOCAL option is used for local/experimental purposes. The option +// code is recommended to be within the range [EDNS0LOCALSTART, EDNS0LOCALEND] +// (RFC6891), although any unassigned code can actually be used. The content of +// the option is made available in Data, unaltered. +// Basic use pattern for creating a local option: +// +// o := new(dns.OPT) +// o.Hdr.Name = "." +// o.Hdr.Rrtype = dns.TypeOPT +// e := new(dns.EDNS0_LOCAL) +// e.Code = dns.EDNS0LOCALSTART +// e.Data = []byte{72, 82, 74} +// o.Option = append(o.Option, e) +type EDNS0_LOCAL struct { + Code uint16 + Data []byte +} + +func (e *EDNS0_LOCAL) Option() uint16 { return e.Code } +func (e *EDNS0_LOCAL) String() string { + return strconv.FormatInt(int64(e.Code), 10) + ":0x" + hex.EncodeToString(e.Data) +} + +func (e *EDNS0_LOCAL) pack() ([]byte, error) { + b := make([]byte, len(e.Data)) + copied := copy(b, e.Data) + if copied != len(e.Data) { + return nil, ErrBuf + } + return b, nil +} + +func (e *EDNS0_LOCAL) unpack(b []byte) error { + e.Data = make([]byte, len(b)) + copied := copy(e.Data, b) + if copied != len(b) { + return ErrBuf + } + return nil +} diff --git a/vendor/github.com/miekg/dns/format.go b/vendor/github.com/miekg/dns/format.go new file mode 100644 index 00000000000..1ac1664fe29 --- /dev/null +++ b/vendor/github.com/miekg/dns/format.go @@ -0,0 +1,96 @@ +package dns + +import ( + "net" + "reflect" + "strconv" +) + +// NumField returns the number of rdata fields r has. +func NumField(r RR) int { + return reflect.ValueOf(r).Elem().NumField() - 1 // Remove RR_Header +} + +// Field returns the rdata field i as a string. Fields are indexed starting from 1. +// RR types that holds slice data, for instance the NSEC type bitmap will return a single +// string where the types are concatenated using a space. +// Accessing non existing fields will cause a panic. +func Field(r RR, i int) string { + if i == 0 { + return "" + } + d := reflect.ValueOf(r).Elem().Field(i) + switch k := d.Kind(); k { + case reflect.String: + return d.String() + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return strconv.FormatInt(d.Int(), 10) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + return strconv.FormatUint(d.Uint(), 10) + case reflect.Slice: + switch reflect.ValueOf(r).Elem().Type().Field(i).Tag { + case `dns:"a"`: + // TODO(miek): Hmm store this as 16 bytes + if d.Len() < net.IPv6len { + return net.IPv4(byte(d.Index(0).Uint()), + byte(d.Index(1).Uint()), + byte(d.Index(2).Uint()), + byte(d.Index(3).Uint())).String() + } + return net.IPv4(byte(d.Index(12).Uint()), + byte(d.Index(13).Uint()), + byte(d.Index(14).Uint()), + byte(d.Index(15).Uint())).String() + case `dns:"aaaa"`: + return net.IP{ + byte(d.Index(0).Uint()), + byte(d.Index(1).Uint()), + byte(d.Index(2).Uint()), + byte(d.Index(3).Uint()), + byte(d.Index(4).Uint()), + byte(d.Index(5).Uint()), + byte(d.Index(6).Uint()), + byte(d.Index(7).Uint()), + byte(d.Index(8).Uint()), + byte(d.Index(9).Uint()), + byte(d.Index(10).Uint()), + byte(d.Index(11).Uint()), + byte(d.Index(12).Uint()), + byte(d.Index(13).Uint()), + byte(d.Index(14).Uint()), + byte(d.Index(15).Uint()), + }.String() + case `dns:"nsec"`: + if d.Len() == 0 { + return "" + } + s := Type(d.Index(0).Uint()).String() + for i := 1; i < d.Len(); i++ { + s += " " + Type(d.Index(i).Uint()).String() + } + return s + case `dns:"wks"`: + if d.Len() == 0 { + return "" + } + s := strconv.Itoa(int(d.Index(0).Uint())) + for i := 0; i < d.Len(); i++ { + s += " " + strconv.Itoa(int(d.Index(i).Uint())) + } + return s + default: + // if it does not have a tag its a string slice + fallthrough + case `dns:"txt"`: + if d.Len() == 0 { + return "" + } + s := d.Index(0).String() + for i := 1; i < d.Len(); i++ { + s += " " + d.Index(i).String() + } + return s + } + } + return "" +} diff --git a/vendor/github.com/miekg/dns/keygen.go b/vendor/github.com/miekg/dns/keygen.go deleted file mode 100644 index dfe328ecd43..00000000000 --- a/vendor/github.com/miekg/dns/keygen.go +++ /dev/null @@ -1,157 +0,0 @@ -package dns - -import ( - "crypto/dsa" - "crypto/ecdsa" - "crypto/elliptic" - "crypto/rand" - "crypto/rsa" - "math/big" - "strconv" -) - -const _FORMAT = "Private-key-format: v1.3\n" - -// Empty interface that is used as a wrapper around all possible -// private key implementations from the crypto package. -type PrivateKey interface{} - -// Generate generates a DNSKEY of the given bit size. -// The public part is put inside the DNSKEY record. -// The Algorithm in the key must be set as this will define -// what kind of DNSKEY will be generated. -// The ECDSA algorithms imply a fixed keysize, in that case -// bits should be set to the size of the algorithm. -func (r *DNSKEY) Generate(bits int) (PrivateKey, error) { - switch r.Algorithm { - case DSA, DSANSEC3SHA1: - if bits != 1024 { - return nil, ErrKeySize - } - case RSAMD5, RSASHA1, RSASHA256, RSASHA1NSEC3SHA1: - if bits < 512 || bits > 4096 { - return nil, ErrKeySize - } - case RSASHA512: - if bits < 1024 || bits > 4096 { - return nil, ErrKeySize - } - case ECDSAP256SHA256: - if bits != 256 { - return nil, ErrKeySize - } - case ECDSAP384SHA384: - if bits != 384 { - return nil, ErrKeySize - } - } - - switch r.Algorithm { - case DSA, DSANSEC3SHA1: - params := new(dsa.Parameters) - if err := dsa.GenerateParameters(params, rand.Reader, dsa.L1024N160); err != nil { - return nil, err - } - priv := new(dsa.PrivateKey) - priv.PublicKey.Parameters = *params - err := dsa.GenerateKey(priv, rand.Reader) - if err != nil { - return nil, err - } - r.setPublicKeyDSA(params.Q, params.P, params.G, priv.PublicKey.Y) - return priv, nil - case RSAMD5, RSASHA1, RSASHA256, RSASHA512, RSASHA1NSEC3SHA1: - priv, err := rsa.GenerateKey(rand.Reader, bits) - if err != nil { - return nil, err - } - r.setPublicKeyRSA(priv.PublicKey.E, priv.PublicKey.N) - return priv, nil - case ECDSAP256SHA256, ECDSAP384SHA384: - var c elliptic.Curve - switch r.Algorithm { - case ECDSAP256SHA256: - c = elliptic.P256() - case ECDSAP384SHA384: - c = elliptic.P384() - } - priv, err := ecdsa.GenerateKey(c, rand.Reader) - if err != nil { - return nil, err - } - r.setPublicKeyCurve(priv.PublicKey.X, priv.PublicKey.Y) - return priv, nil - default: - return nil, ErrAlg - } - return nil, nil // Dummy return -} - -// 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 (hashing, keytag), so its a method of the DNSKEY. -func (r *DNSKEY) PrivateKeyString(p PrivateKey) (s string) { - switch t := p.(type) { - case *rsa.PrivateKey: - algorithm := strconv.Itoa(int(r.Algorithm)) + " (" + AlgorithmToString[r.Algorithm] + ")" - modulus := toBase64(t.PublicKey.N.Bytes()) - e := big.NewInt(int64(t.PublicKey.E)) - publicExponent := toBase64(e.Bytes()) - privateExponent := toBase64(t.D.Bytes()) - prime1 := toBase64(t.Primes[0].Bytes()) - prime2 := toBase64(t.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) - minusone := big.NewInt(-1) - p_1 := big.NewInt(0).Sub(t.Primes[0], one) - q_1 := big.NewInt(0).Sub(t.Primes[1], one) - exp1 := big.NewInt(0).Mod(t.D, p_1) - exp2 := big.NewInt(0).Mod(t.D, q_1) - coeff := big.NewInt(0).Exp(t.Primes[1], minusone, t.Primes[0]) - - exponent1 := toBase64(exp1.Bytes()) - exponent2 := toBase64(exp2.Bytes()) - coefficient := toBase64(coeff.Bytes()) - - s = _FORMAT + - "Algorithm: " + algorithm + "\n" + - "Modules: " + 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: - algorithm := strconv.Itoa(int(r.Algorithm)) + " (" + AlgorithmToString[r.Algorithm] + ")" - var intlen int - switch r.Algorithm { - case ECDSAP256SHA256: - intlen = 32 - case ECDSAP384SHA384: - intlen = 48 - } - private := toBase64(intToBytes(t.D, intlen)) - s = _FORMAT + - "Algorithm: " + algorithm + "\n" + - "PrivateKey: " + private + "\n" - case *dsa.PrivateKey: - algorithm := strconv.Itoa(int(r.Algorithm)) + " (" + AlgorithmToString[r.Algorithm] + ")" - T := divRoundUp(divRoundUp(t.PublicKey.Parameters.G.BitLen(), 8)-64, 8) - prime := toBase64(intToBytes(t.PublicKey.Parameters.P, 64+T*8)) - subprime := toBase64(intToBytes(t.PublicKey.Parameters.Q, 20)) - base := toBase64(intToBytes(t.PublicKey.Parameters.G, 64+T*8)) - priv := toBase64(intToBytes(t.X, 20)) - pub := toBase64(intToBytes(t.PublicKey.Y, 64+T*8)) - s = _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" - } - return -} diff --git a/vendor/github.com/miekg/dns/labels.go b/vendor/github.com/miekg/dns/labels.go index 758e5783de5..cb549fc672c 100644 --- a/vendor/github.com/miekg/dns/labels.go +++ b/vendor/github.com/miekg/dns/labels.go @@ -4,9 +4,11 @@ package dns // SplitDomainName splits a name string into it's labels. // www.miek.nl. returns []string{"www", "miek", "nl"} +// .www.miek.nl. returns []string{"", "www", "miek", "nl"}, // The root label (.) returns nil. Note that using // strings.Split(s) will work in most cases, but does not handle // escaped dots (\.) for instance. +// s must be a syntactically valid domain name, see IsDomainName. func SplitDomainName(s string) (labels []string) { if len(s) == 0 { return nil @@ -45,6 +47,8 @@ func SplitDomainName(s string) (labels []string) { // // www.miek.nl. and miek.nl. have two labels in common: miek and nl // www.miek.nl. and www.bla.nl. have one label in common: nl +// +// s1 and s2 must be syntactically valid domain names. func CompareDomainName(s1, s2 string) (n int) { s1 = Fqdn(s1) s2 = Fqdn(s2) @@ -85,6 +89,7 @@ func CompareDomainName(s1, s2 string) (n int) { } // CountLabel counts the the number of labels in the string s. +// s must be a syntactically valid domain name. func CountLabel(s string) (labels int) { if s == "." { return @@ -98,12 +103,12 @@ 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. +// s must be a syntactically valid domain name. func Split(s string) []int { if s == "." { return nil @@ -119,12 +124,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 +152,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 diff --git a/vendor/github.com/miekg/dns/msg.go b/vendor/github.com/miekg/dns/msg.go index ecba463ddda..7274800fc01 100644 --- a/vendor/github.com/miekg/dns/msg.go +++ b/vendor/github.com/miekg/dns/msg.go @@ -23,29 +23,40 @@ import ( const maxCompressionOffset = 2 << 13 // We have 14 bits for the compression pointer var ( - ErrAlg error = &Error{err: "bad algorithm"} - ErrAuth error = &Error{err: "bad authentication"} - ErrBuf error = &Error{err: "buffer size too small"} - ErrConnEmpty error = &Error{err: "conn has no connection"} - ErrConn error = &Error{err: "conn holds both UDP and TCP connection"} + // ErrAlg indicates an error with the (DNSSEC) algorithm. + ErrAlg error = &Error{err: "bad algorithm"} + // ErrAuth indicates an error in the TSIG authentication. + 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"} + // ErrConnEmpty indicates a connection is being uses before it is initialized. + ErrConnEmpty error = &Error{err: "conn has no connection"} + // ErrExtendedRcode ... ErrExtendedRcode error = &Error{err: "bad extended rcode"} - ErrFqdn error = &Error{err: "domain must be fully qualified"} - ErrId error = &Error{err: "id mismatch"} - ErrKeyAlg error = &Error{err: "bad key algorithm"} - ErrKey error = &Error{err: "bad key"} - ErrKeySize error = &Error{err: "bad key size"} - ErrNoSig error = &Error{err: "no signature found"} - ErrPrivKey error = &Error{err: "bad private key"} - ErrRcode error = &Error{err: "bad rcode"} - ErrRdata error = &Error{err: "bad rdata"} - ErrRRset error = &Error{err: "bad rrset"} - ErrSecret error = &Error{err: "no secrets defined"} - ErrServ error = &Error{err: "no servers could be reached"} - ErrShortRead error = &Error{err: "short read"} - ErrSig error = &Error{err: "bad signature"} - ErrSigGen error = &Error{err: "bad signature generation"} - ErrSoa error = &Error{err: "no SOA"} - ErrTime error = &Error{err: "bad time"} + // 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"} + // 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"} + ErrNoSig error = &Error{err: "no signature found"} + ErrPrivKey error = &Error{err: "bad private key"} + ErrRcode error = &Error{err: "bad rcode"} + ErrRdata error = &Error{err: "bad rdata"} + ErrRRset error = &Error{err: "bad rrset"} + ErrSecret error = &Error{err: "no secrets defined"} + ErrShortRead error = &Error{err: "short read"} + // ErrSig indicates that a signature can not be cryptographically validated. + ErrSig error = &Error{err: "bad signature"} + // 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. + ErrTime error = &Error{err: "bad time"} + // ErrTruncated indicates that we failed to unpack a truncated message. + // We unpacked as much as we had so Msg can still be used, if desired. + ErrTruncated error = &Error{err: "failed to unpack truncated message"} ) // Id, by default, returns a 16 bits random number to be used as a @@ -56,8 +67,7 @@ var ( // dns.Id = func() uint16 { return 3 } var Id func() uint16 = id -// A manually-unpacked version of (id, bits). -// This is in its own struct for easy printing. +// MsgHdr is a a manually-unpacked version of (id, bits). type MsgHdr struct { Id uint16 Response bool @@ -72,7 +82,7 @@ type MsgHdr struct { Rcode int } -// The layout of a DNS message. +// Msg contains the layout of a DNS message. type Msg struct { MsgHdr Compress bool `json:"-"` // If true, the message will be compressed when converted to wire format. This not part of the official DNS packet format. @@ -82,87 +92,10 @@ type Msg struct { Extra []RR // Holds the RR(s) of the additional section. } -// Map of strings for each RR wire type. -var TypeToString = map[uint16]string{ - TypeA: "A", - TypeAAAA: "AAAA", - TypeAFSDB: "AFSDB", - TypeANY: "ANY", // Meta RR - TypeATMA: "ATMA", - TypeAXFR: "AXFR", // Meta RR - TypeCAA: "CAA", - TypeCDNSKEY: "CDNSKEY", - TypeCDS: "CDS", - TypeCERT: "CERT", - TypeCNAME: "CNAME", - TypeDHCID: "DHCID", - TypeDLV: "DLV", - TypeDNAME: "DNAME", - TypeDNSKEY: "DNSKEY", - TypeDS: "DS", - TypeEID: "EID", - TypeEUI48: "EUI48", - TypeEUI64: "EUI64", - TypeGID: "GID", - TypeGPOS: "GPOS", - TypeHINFO: "HINFO", - TypeHIP: "HIP", - TypeIPSECKEY: "IPSECKEY", - TypeISDN: "ISDN", - TypeIXFR: "IXFR", // Meta RR - TypeKEY: "KEY", - TypeKX: "KX", - TypeL32: "L32", - TypeL64: "L64", - TypeLOC: "LOC", - TypeLP: "LP", - TypeMB: "MB", - TypeMD: "MD", - TypeMF: "MF", - TypeMG: "MG", - TypeMINFO: "MINFO", - TypeMR: "MR", - TypeMX: "MX", - TypeNAPTR: "NAPTR", - TypeNID: "NID", - TypeNINFO: "NINFO", - TypeNIMLOC: "NIMLOC", - TypeNS: "NS", - TypeNSAP: "NSAP", - TypeNSAPPTR: "NSAP-PTR", - TypeNSEC3: "NSEC3", - TypeNSEC3PARAM: "NSEC3PARAM", - TypeNSEC: "NSEC", - TypeNULL: "NULL", - TypeOPT: "OPT", - TypeOPENPGPKEY: "OPENPGPKEY", - TypePTR: "PTR", - TypeRKEY: "RKEY", - TypeRP: "RP", - TypeRRSIG: "RRSIG", - TypeRT: "RT", - TypeSIG: "SIG", - TypeSOA: "SOA", - TypeSPF: "SPF", - TypeSRV: "SRV", - TypeSSHFP: "SSHFP", - TypeTA: "TA", - TypeTALINK: "TALINK", - TypeTKEY: "TKEY", // Meta RR - TypeTLSA: "TLSA", - TypeTSIG: "TSIG", // Meta RR - TypeTXT: "TXT", - TypePX: "PX", - TypeUID: "UID", - TypeUINFO: "UINFO", - TypeUNSPEC: "UNSPEC", - TypeURI: "URI", - TypeWKS: "WKS", - TypeX25: "X25", -} - -// Reverse, needed for string parsing. +// StringToType is the reverse of TypeToString, needed for string parsing. var StringToType = reverseInt16(TypeToString) + +// StringToClass is the reverse of ClassToString, needed for string parsing. var StringToClass = reverseInt16(ClassToString) // Map of opcodes strings. @@ -171,7 +104,7 @@ var StringToOpcode = reverseInt(OpcodeToString) // Map of rcodes strings. var StringToRcode = reverseInt(RcodeToString) -// Map of strings for each CLASS wire type. +// ClassToString is a maps Classes to strings for each CLASS wire type. var ClassToString = map[uint16]string{ ClassINET: "IN", ClassCSNET: "CS", @@ -181,7 +114,7 @@ var ClassToString = map[uint16]string{ ClassANY: "ANY", } -// Map of strings for opcodes. +// OpcodeToString maps Opcodes to strings. var OpcodeToString = map[int]string{ OpcodeQuery: "QUERY", OpcodeIQuery: "IQUERY", @@ -190,7 +123,7 @@ var OpcodeToString = map[int]string{ OpcodeUpdate: "UPDATE", } -// Map of strings for rcodes. +// RcodeToString maps Rcodes to strings. var RcodeToString = map[int]string{ RcodeSuccess: "NOERROR", RcodeFormatError: "FORMERR", @@ -225,7 +158,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 @@ -264,7 +197,7 @@ func packDomainName(s string, msg []byte, off int, compression map[string]int, c // Emit sequence of counted strings, chopping at dots. begin := 0 bs := []byte(s) - ro_bs, bs_fresh, escaped_dot := s, true, false + roBs, bsFresh, escapedDot := s, true, false for i := 0; i < ls; i++ { if bs[i] == '\\' { for j := i; j < ls-1; j++ { @@ -288,13 +221,13 @@ func packDomainName(s string, msg []byte, off int, compression map[string]int, c } else if bs[i] == 'n' { bs[i] = '\n' } - escaped_dot = bs[i] == '.' - bs_fresh = false + escapedDot = bs[i] == '.' + bsFresh = false continue } if bs[i] == '.' { - if i > 0 && bs[i-1] == '.' && !escaped_dot { + if i > 0 && bs[i-1] == '.' && !escapedDot { // two dots back to back is not legal return lenmsg, labels, ErrRdata } @@ -320,16 +253,16 @@ func packDomainName(s string, msg []byte, off int, compression map[string]int, c } off++ } - if compress && !bs_fresh { - ro_bs = string(bs) - bs_fresh = true + if compress && !bsFresh { + roBs = string(bs) + bsFresh = true } - // Dont try to compress '.' - if compress && ro_bs[begin:] != "." { - if p, ok := compression[ro_bs[begin:]]; !ok { + // Don't try to compress '.' + if compress && roBs[begin:] != "." { + if p, ok := compression[roBs[begin:]]; !ok { // Only offsets smaller than this can be used. if offset < maxCompressionOffset { - compression[ro_bs[begin:]] = offset + compression[roBs[begin:]] = offset } } else { // The first hit is the longest matching dname @@ -348,7 +281,7 @@ func packDomainName(s string, msg []byte, off int, compression map[string]int, c labels++ begin = i + 1 } - escaped_dot = false + escapedDot = false } // Root label is special if len(bs) == 1 && bs[0] == '.' { @@ -401,9 +334,6 @@ Loop: case 0x00: if c == 0x00 { // end of name - if len(s) == 0 { - return ".", off, nil - } break Loop } // literal string @@ -464,6 +394,9 @@ Loop: if ptr == 0 { off1 = off } + if len(s) == 0 { + s = []byte(".") + } return string(s), off1, nil } @@ -531,17 +464,46 @@ func packTxtString(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 packOctetString(s string, msg []byte, offset int, tmp []byte) (int, error) { + if offset >= len(msg) { + return offset, ErrBuf + } + bs := tmp[:len(s)] + copy(bs, s) + for i := 0; i < len(bs); i++ { + if len(msg) <= offset { + return offset, ErrBuf + } + if bs[i] == '\\' { + i++ + if i == len(bs) { + break + } + // check for \DDD + if i+2 < len(bs) && isDigit(bs[i]) && isDigit(bs[i+1]) && isDigit(bs[i+2]) { + msg[offset] = dddToByte(bs[i:]) + i += 2 + } else { + msg[offset] = bs[i] + } + } else { + msg[offset] = bs[i] + } + offset++ + } + return offset, nil +} + +func unpackTxt(msg []byte, off0 int) (ss []string, off int, err error) { + off = off0 var s string - for 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) { @@ -652,6 +614,12 @@ func packStructValue(val reflect.Value, msg []byte, off int, compression map[str off += len(b) } case `dns:"a"`: + if val.Type().String() == "dns.IPSECKEY" { + // Field(2) is GatewayType, must be 1 + if val.Field(2).Uint() != 1 { + continue + } + } // It must be a slice of 4, even if it is 16, we encode // only the first 4 if off+net.IPv4len > lenmsg { @@ -676,6 +644,12 @@ func packStructValue(val reflect.Value, msg []byte, off int, compression map[str return lenmsg, &Error{err: "overflow packing a"} } case `dns:"aaaa"`: + if val.Type().String() == "dns.IPSECKEY" { + // Field(2) is GatewayType, must be 2 + if val.Field(2).Uint() != 2 { + continue + } + } if fv.Len() == 0 { break } @@ -694,58 +668,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) @@ -821,6 +786,13 @@ func packStructValue(val reflect.Value, msg []byte, off int, compression map[str copy(msg[off:off+len(b64)], b64) off += len(b64) case `dns:"domain-name"`: + if val.Type().String() == "dns.IPSECKEY" { + // Field(2) is GatewayType, 1 and 2 or used for addresses + x := val.Field(2).Uint() + if x == 1 || x == 2 { + continue + } + } if off, err = PackDomainName(s, msg, off, compression, false && compress); err != nil { return lenmsg, err } @@ -859,6 +831,12 @@ func packStructValue(val reflect.Value, msg []byte, off int, compression map[str // length of string. String is RAW (not encoded in hex, nor base64) copy(msg[off:off+len(s)], s) off += len(s) + case `dns:"octet"`: + bytesTmp := make([]byte, 256) + off, err = packOctetString(fv.String(), msg, off, bytesTmp) + if err != nil { + return lenmsg, err + } case `dns:"txt"`: fallthrough case "": @@ -890,17 +868,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"} } @@ -912,7 +884,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 } @@ -926,9 +898,9 @@ func unpackStructValue(val reflect.Value, msg []byte, off int) (off1 int, err er return lenmsg, &Error{"bad tag unpacking slice: " + val.Type().Field(i).Tag.Get("dns")} case `dns:"domain-name"`: // HIP record slice of name (or none) - servers := make([]string, 0) + var servers []string var s string - for off < lenrd { + for off < lenmsg { s, off, err = UnpackDomainName(msg, off) if err != nil { return lenmsg, err @@ -937,30 +909,30 @@ 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 } - edns := make([]EDNS0, 0) + 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 { @@ -1017,27 +989,44 @@ func unpackStructValue(val reflect.Value, msg []byte, off int) (off1 int, err er edns = append(edns, e) off = off1 + int(optlen) default: - // do nothing? + e := new(EDNS0_LOCAL) + e.Code = code + if err := e.unpack(msg[off1 : off1+int(optlen)]); err != nil { + return lenmsg, err + } + edns = append(edns, e) off = off1 + int(optlen) } - if off < lenrd { + if off < lenmsg { goto Option } fv.Set(reflect.ValueOf(edns)) case `dns:"a"`: - if off == lenrd { + if val.Type().String() == "dns.IPSECKEY" { + // Field(2) is GatewayType, must be 1 + if val.Field(2).Uint() != 1 { + continue + } + } + 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]))) off += net.IPv4len case `dns:"aaaa"`: - if off == lenrd { + if val.Type().String() == "dns.IPSECKEY" { + // Field(2) is GatewayType, must be 2 + if val.Field(2).Uint() != 2 { + continue + } + } + 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], @@ -1046,9 +1035,9 @@ func unpackStructValue(val reflect.Value, msg []byte, off int) (off1 int, err er off += net.IPv6len case `dns:"wks"`: // Rest of the record is the bitmap - serv := make([]uint16, 0) + var serv []uint16 j := 0 - for off < lenrd { + for off < lenmsg { if off+1 > lenmsg { return lenmsg, &Error{err: "overflow unpacking wks"} } @@ -1083,36 +1072,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"} - } - nsec := make([]uint16, 0) + 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 { @@ -1141,6 +1133,7 @@ func unpackStructValue(val reflect.Value, msg []byte, off int) (off1 int, err er } } off += length + lastwindow = window } fv.Set(reflect.ValueOf(nsec)) } @@ -1150,7 +1143,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 { @@ -1181,6 +1179,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 { @@ -1206,32 +1207,42 @@ func unpackStructValue(val reflect.Value, msg []byte, off int) (off1 int, err er switch val.Type().Field(i).Tag { default: return lenmsg, &Error{"bad tag unpacking string: " + val.Type().Field(i).Tag.Get("dns")} + case `dns:"octet"`: + 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 case `dns:"cdomain-name"`: fallthrough case `dns:"domain-name"`: - if off == lenmsg { - // zero rdata foo, OK for dyn. updates + if val.Type().String() == "dns.IPSECKEY" { + // Field(2) is GatewayType, 1 and 2 or used for addresses + x := val.Field(2).Uint() + if x == 1 || x == 2 { + continue + } + } + if off == lenmsg && int(val.FieldByName("Hdr").FieldByName("Rdlength").Uint()) == 0 { + // zero rdata is ok for dyn updates, but only if rdlength is 0 break } s, off, err = UnpackDomainName(msg, off) @@ -1375,7 +1386,7 @@ func UnpackRR(msg []byte, off int) (rr RR, off1 int, err error) { } end := off + int(h.Rdlength) // make an rr of that type and re-unpack. - mk, known := typeToRR[h.Rrtype] + mk, known := TypeToRR[h.Rrtype] if !known { rr = new(RFC3597) } else { @@ -1388,6 +1399,32 @@ func UnpackRR(msg []byte, off int) (rr RR, off1 int, err error) { return rr, off, err } +// unpackRRslice unpacks msg[off:] into an []RR. +// If we cannot unpack the whole array, then it will return nil +func unpackRRslice(l int, msg []byte, off int) (dst1 []RR, off1 int, err error) { + var r RR + // Optimistically make dst be the length that was sent + dst := make([]RR, 0, l) + for i := 0; i < l; i++ { + off1 := off + r, off, err = UnpackRR(msg, off) + if err != nil { + off = len(msg) + break + } + // If offset does not increase anymore, l is a lie + if off1 == off { + l = i + break + } + dst = append(dst, r) + } + if err != nil && off == len(msg) { + dst = nil + } + return dst, off, err +} + // Reverse a map func reverseInt8(m map[uint8]string) map[string]uint8 { n := make(map[string]uint8) @@ -1586,52 +1623,48 @@ 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) + // Optimistically use the count given to us in the header + dns.Question = make([]Question, 0, int(dh.Qdcount)) - 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 { + // Even if Truncated is set, we only will set ErrTruncated if we + // actually got the questions return err } - } - // 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! - 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) - 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) } - for i := 0; i < len(dns.Ns); i++ { - dns.Ns[i], off, err = UnpackRR(msg, off) - if err != nil { - return err - } + + dns.Answer, off, err = unpackRRslice(int(dh.Ancount), msg, off) + // The header counts might have been wrong so we need to update it + dh.Ancount = uint16(len(dns.Answer)) + if err == nil { + dns.Ns, off, err = unpackRRslice(int(dh.Nscount), msg, off) } - for i := 0; i < len(dns.Extra); i++ { - dns.Extra[i], off, err = UnpackRR(msg, off) - if err != nil { - return err - } + // The header counts might have been wrong so we need to update it + dh.Nscount = uint16(len(dns.Ns)) + if err == nil { + dns.Extra, off, err = unpackRRslice(int(dh.Arcount), msg, off) } + // The header counts might have been wrong so we need to update it + dh.Arcount = uint16(len(dns.Extra)) if off != len(msg) { // TODO(miek) make this an error? // use PackOpt to let people tell how detailed the error reporting should be? // println("dns: extra bytes in dns packet", off, "<", len(msg)) + } else if dns.Truncated { + // Whether we ran into a an error or not, we want to return that it + // was truncated + err = ErrTruncated } - return nil + return err } // Convert a complete message to a string with dig-like output. @@ -1863,9 +1896,18 @@ func Copy(r RR) RR { return r1 } +// Len returns the length (in octets) of the uncompressed RR in wire format. +func Len(r RR) int { + return r.len() +} + // Copy returns a new *Msg which is a deep-copy of dns. func (dns *Msg) Copy() *Msg { - r1 := new(Msg) + return dns.CopyTo(new(Msg)) +} + +// CopyTo copies the contents to the provided message using a deep-copy and returns the copy. +func (dns *Msg) CopyTo(r1 *Msg) *Msg { r1.MsgHdr = dns.MsgHdr r1.Compress = dns.Compress @@ -1874,25 +1916,34 @@ func (dns *Msg) Copy() *Msg { copy(r1.Question, dns.Question) // TODO(miek): Question is an immutable value, ok to do a shallow-copy } + rrArr := make([]RR, len(dns.Answer)+len(dns.Ns)+len(dns.Extra)) + var rri int + if len(dns.Answer) > 0 { - r1.Answer = make([]RR, len(dns.Answer)) + rrbegin := rri for i := 0; i < len(dns.Answer); i++ { - r1.Answer[i] = dns.Answer[i].copy() + rrArr[rri] = dns.Answer[i].copy() + rri++ } + r1.Answer = rrArr[rrbegin:rri:rri] } if len(dns.Ns) > 0 { - r1.Ns = make([]RR, len(dns.Ns)) + rrbegin := rri for i := 0; i < len(dns.Ns); i++ { - r1.Ns[i] = dns.Ns[i].copy() + rrArr[rri] = dns.Ns[i].copy() + rri++ } + r1.Ns = rrArr[rrbegin:rri:rri] } if len(dns.Extra) > 0 { - r1.Extra = make([]RR, len(dns.Extra)) + rrbegin := rri for i := 0; i < len(dns.Extra); i++ { - r1.Extra[i] = dns.Extra[i].copy() + rrArr[rri] = dns.Extra[i].copy() + rri++ } + r1.Extra = rrArr[rrbegin:rri:rri] } return r1 diff --git a/vendor/github.com/miekg/dns/nsecx.go b/vendor/github.com/miekg/dns/nsecx.go index ac48da0f5ac..d2392c6ec60 100644 --- a/vendor/github.com/miekg/dns/nsecx.go +++ b/vendor/github.com/miekg/dns/nsecx.go @@ -50,6 +50,8 @@ func HashName(label string, ha uint8, iter uint16, salt string) string { return toBase32(nsec3) } +// Denialer is an interface that should be implemented by types that are used to denial +// answers in DNSSEC. type Denialer interface { // Cover will check if the (unhashed) name is being covered by this NSEC or NSEC3. Cover(name string) bool diff --git a/vendor/github.com/miekg/dns/privaterr.go b/vendor/github.com/miekg/dns/privaterr.go index 225713743c9..c78f8859120 100644 --- a/vendor/github.com/miekg/dns/privaterr.go +++ b/vendor/github.com/miekg/dns/privaterr.go @@ -1,10 +1,3 @@ -/* -PRIVATE RR - -RFC 6895 sets aside a range of type codes for private use. This range -is 65,280 - 65,534 (0xFF00 - 0xFFFE). When experimenting with new Resource Records these -can be used, before requesting an official type code from IANA. -*/ package dns import ( @@ -40,7 +33,7 @@ type PrivateRR struct { func mkPrivateRR(rrtype uint16) *PrivateRR { // Panics if RR is not an instance of PrivateRR. - rrfunc, ok := typeToRR[rrtype] + rrfunc, ok := TypeToRR[rrtype] if !ok { panic(fmt.Sprintf("dns: invalid operation with Private RR type %d", rrtype)) } @@ -50,11 +43,13 @@ func mkPrivateRR(rrtype uint16) *PrivateRR { case *PrivateRR: return rr } - panic(fmt.Sprintf("dns: RR is not a PrivateRR, typeToRR[%d] generator returned %T", rrtype, anyrr)) + panic(fmt.Sprintf("dns: RR is not a PrivateRR, TypeToRR[%d] generator returned %T", rrtype, anyrr)) } +// Header return the RR header of r. 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() } @@ -76,7 +71,7 @@ func (r *PrivateRR) copy() RR { func PrivateHandle(rtypestr string, rtype uint16, generator func() PrivateRdata) { rtypestr = strings.ToUpper(rtypestr) - typeToRR[rtype] = func() RR { return &PrivateRR{RR_Header{}, generator()} } + TypeToRR[rtype] = func() RR { return &PrivateRR{RR_Header{}, generator()} } TypeToString[rtype] = rtypestr StringToType[rtypestr] = rtype @@ -91,9 +86,9 @@ func PrivateHandle(rtypestr string, rtype uint16, generator func() PrivateRdata) // TODO(miek): we could also be returning _QUOTE, this might or might not // be an issue (basically parsing TXT becomes hard) switch l = <-c; l.value { - case _NEWLINE, _EOF: + case zNewline, zEOF: break FETCH - case _STRING: + case zString: text = append(text, l.token) } } @@ -113,7 +108,7 @@ func PrivateHandle(rtypestr string, rtype uint16, generator func() PrivateRdata) func PrivateHandleRemove(rtype uint16) { rtypestr, ok := TypeToString[rtype] if ok { - delete(typeToRR, rtype) + delete(TypeToRR, rtype) delete(TypeToString, rtype) delete(typeToparserFunc, rtype) delete(StringToType, rtypestr) diff --git a/vendor/github.com/miekg/dns/rawmsg.go b/vendor/github.com/miekg/dns/rawmsg.go index f138b7761df..b4a706b9388 100644 --- a/vendor/github.com/miekg/dns/rawmsg.go +++ b/vendor/github.com/miekg/dns/rawmsg.go @@ -21,7 +21,7 @@ func rawSetQuestionLen(msg []byte, i uint16) bool { return true } -// rawSetAnswerLen sets the lenght of the answer section. +// rawSetAnswerLen sets the length of the answer section. func rawSetAnswerLen(msg []byte, i uint16) bool { if len(msg) < 8 { return false @@ -30,7 +30,7 @@ func rawSetAnswerLen(msg []byte, i uint16) bool { return true } -// rawSetsNsLen sets the lenght of the authority section. +// rawSetsNsLen sets the length of the authority section. func rawSetNsLen(msg []byte, i uint16) bool { if len(msg) < 10 { return false @@ -39,7 +39,7 @@ func rawSetNsLen(msg []byte, i uint16) bool { return true } -// rawSetExtraLen sets the lenght of the additional section. +// rawSetExtraLen sets the length of the additional section. func rawSetExtraLen(msg []byte, i uint16) bool { if len(msg) < 12 { return false diff --git a/vendor/github.com/miekg/dns/sanitize.go b/vendor/github.com/miekg/dns/sanitize.go new file mode 100644 index 00000000000..b489f3f050b --- /dev/null +++ b/vendor/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: +// DomainNameTTLCLASSTYPERDATA to: +// lowercasenameCLASSTYPE... +func normalizedString(r RR) string { + // A string Go DNS makes has: domainnameTTL... + b := []byte(r.String()) + + // find the first non-escaped tab, then another, so we capture where the TTL lives. + esc := false + ttlStart, ttlEnd := 0, 0 + for i := 0; i < len(b) && ttlEnd == 0; i++ { + switch { + case b[i] == '\\': + esc = !esc + case b[i] == '\t' && !esc: + if ttlStart == 0 { + ttlStart = i + continue + } + if ttlEnd == 0 { + ttlEnd = i + } + case b[i] >= 'A' && b[i] <= 'Z' && !esc: + b[i] += 32 + default: + esc = false + } + } + + // remove TTL. + copy(b[ttlStart:], b[ttlEnd:]) + cut := ttlEnd - ttlStart + return string(b[:len(b)-cut]) +} diff --git a/vendor/github.com/miekg/dns/server.go b/vendor/github.com/miekg/dns/server.go index c250ccc26a1..edc5c6258c9 100644 --- a/vendor/github.com/miekg/dns/server.go +++ b/vendor/github.com/miekg/dns/server.go @@ -4,12 +4,17 @@ package dns import ( "bytes" + "crypto/tls" "io" "net" "sync" "time" ) +// Maximum number of TCP queries before we close the socket. +const maxTCPQueries = 128 + +// Handler is implemented by any value that implements ServeDNS. type Handler interface { ServeDNS(w ResponseWriter, r *Msg) } @@ -43,9 +48,10 @@ type response struct { tsigRequestMAC string tsigSecret map[string]string // the tsig secrets udp *net.UDPConn // i/o connection if UDP was used - tcp *net.TCPConn // i/o connection if TCP was used - udpSession *sessionUDP // oob data to get egress interface right + tcp net.Conn // i/o connection if TCP was used + udpSession *SessionUDP // oob data to get egress interface right remoteAddr net.Addr // address of the client + writer Writer // writer to output the raw DNS bits } // ServeMux is an DNS request multiplexer. It matches the @@ -72,12 +78,12 @@ var DefaultServeMux = NewServeMux() // Handler object that calls f. type HandlerFunc func(ResponseWriter, *Msg) -// ServerDNS calls f(w, r) +// ServeDNS calls f(w, r). func (f HandlerFunc) ServeDNS(w ResponseWriter, r *Msg) { f(w, r) } -// FailedHandler returns a HandlerFunc that returns SERVFAIL for every request it gets. +// HandleFailed returns a HandlerFunc that returns SERVFAIL for every request it gets. func HandleFailed(w ResponseWriter, r *Msg) { m := new(Msg) m.SetRcode(r, RcodeServerFailure) @@ -87,13 +93,35 @@ func HandleFailed(w ResponseWriter, r *Msg) { func failedHandler() Handler { return HandlerFunc(HandleFailed) } -// ListenAndServe Starts a server on addresss and network speficied. Invoke handler +// ListenAndServe Starts a server on address and network specified Invoke handler // for incoming queries. func ListenAndServe(addr string, network string, handler Handler) error { server := &Server{Addr: addr, Net: network, Handler: handler} return server.ListenAndServe() } +// ListenAndServeTLS acts like http.ListenAndServeTLS, more information in +// http://golang.org/pkg/net/http/#ListenAndServeTLS +func ListenAndServeTLS(addr, certFile, keyFile string, handler Handler) error { + cert, err := tls.LoadX509KeyPair(certFile, keyFile) + if err != nil { + return err + } + + config := tls.Config{ + Certificates: []tls.Certificate{cert}, + } + + server := &Server{ + Addr: addr, + Net: "tcp-tls", + TLSConfig: &config, + Handler: handler, + } + + return server.ListenAndServe() +} + // ActivateAndServe activates a server with a listener from systemd, // l and p should not both be non-nil. // If both l and p are not nil only p will be used. @@ -121,10 +149,9 @@ func (mux *ServeMux) match(q string, t uint16) Handler { if h, ok := mux.z[string(b[:l])]; ok { // 'causes garbage, might want to change the map key if t != TypeDS { return h - } else { - // Continue for DS to see if we have a parent too, if so delegeate to the parent - handler = h } + // Continue for DS to see if we have a parent too, if so delegeate to the parent + handler = h } off, end = NextLabel(q, off) if end { @@ -148,7 +175,7 @@ func (mux *ServeMux) Handle(pattern string, handler Handler) { mux.m.Unlock() } -// Handle adds a handler to the ServeMux for pattern. +// HandleFunc adds a handler function to the ServeMux for pattern. func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Msg)) { mux.Handle(pattern, HandlerFunc(handler)) } @@ -158,9 +185,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,14 +224,53 @@ func HandleFunc(pattern string, handler func(ResponseWriter, *Msg)) { DefaultServeMux.HandleFunc(pattern, handler) } +// Writer writes raw DNS messages; each call to Write should send an entire message. +type Writer interface { + io.Writer +} + +// Reader reads raw DNS messages; each call to ReadTCP or ReadUDP should return an entire message. +type Reader interface { + // ReadTCP reads a raw message from a TCP connection. Implementations may alter + // connection properties, for example the read-deadline. + ReadTCP(conn net.Conn, timeout time.Duration) ([]byte, error) + // ReadUDP reads a raw message from a UDP connection. Implementations may alter + // connection properties, for example the read-deadline. + ReadUDP(conn *net.UDPConn, timeout time.Duration) ([]byte, *SessionUDP, error) +} + +// defaultReader is an adapter for the Server struct that implements the Reader interface +// using the readTCP and readUDP func of the embedded Server. +type defaultReader struct { + *Server +} + +func (dr *defaultReader) ReadTCP(conn net.Conn, timeout time.Duration) ([]byte, error) { + return dr.readTCP(conn, timeout) +} + +func (dr *defaultReader) ReadUDP(conn *net.UDPConn, timeout time.Duration) ([]byte, *SessionUDP, error) { + return dr.readUDP(conn, timeout) +} + +// DecorateReader is a decorator hook for extending or supplanting the functionality of a Reader. +// Implementations should never return a nil Reader. +type DecorateReader func(Reader) Reader + +// DecorateWriter is a decorator hook for extending or supplanting the functionality of a Writer. +// Implementations should never return a nil Writer. +type DecorateWriter func(Writer) Writer + // A Server defines parameters for running an DNS server. type Server struct { // Address to listen on, ":dns" if empty. Addr string - // if "tcp" it will invoke a TCP listener, otherwise an UDP one. + // if "tcp" or "tcp-tls" (DNS over TLS) it will invoke a TCP listener, otherwise an UDP one Net string // TCP Listener to use, this is to aid in systemd's socket activation. Listener net.Listener + // TLS connection configuration + TLSConfig *tls.Config // UDP "Listener" to use, this is to aid in systemd's socket activation. PacketConn net.PacketConn // Handler to invoke, dns.DefaultServeMux if nil. @@ -221,31 +287,30 @@ type Server struct { // Secret(s) for Tsig map[]. TsigSecret map[string]string // Unsafe instructs the server to disregard any sanity checks and directly hand the message to - // the handler. It will specfically not check if the query has the QR bit not set. + // the handler. It will specifically not check if the query has the QR bit not set. Unsafe bool - // If NotifyStartedFunc is set 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 - stopTCP chan bool - wgUDP sync.WaitGroup - wgTCP sync.WaitGroup + // Graceful shutdown handling - // make start/shutdown not racy - lock sync.Mutex + inFlight sync.WaitGroup + + lock sync.RWMutex started bool } // ListenAndServe starts a nameserver on the configured address in *Server. func (srv *Server) ListenAndServe() error { srv.lock.Lock() + defer srv.lock.Unlock() if srv.started { return &Error{err: "server already started"} } - srv.stopUDP, srv.stopTCP = make(chan bool), make(chan bool) - srv.started = true - srv.lock.Unlock() addr := srv.Addr if addr == "" { addr = ":domain" @@ -263,7 +328,30 @@ func (srv *Server) ListenAndServe() error { if e != nil { return e } - return srv.serveTCP(l) + srv.Listener = l + srv.started = true + srv.lock.Unlock() + e = srv.serveTCP(l) + srv.lock.Lock() // to satisfy the defer at the top + return e + case "tcp-tls", "tcp4-tls", "tcp6-tls": + network := "tcp" + if srv.Net == "tcp4-tls" { + network = "tcp4" + } else if srv.Net == "tcp6" { + network = "tcp6" + } + + l, e := tls.Listen(network, addr, srv.TLSConfig) + if e != nil { + return e + } + srv.Listener = l + srv.started = true + srv.lock.Unlock() + e = srv.serveTCP(l) + srv.lock.Lock() // to satisfy the defer at the top + return e case "udp", "udp4", "udp6": a, e := net.ResolveUDPAddr(srv.Net, addr) if e != nil { @@ -276,7 +364,12 @@ func (srv *Server) ListenAndServe() error { if e := setUDPSocketOptions(l); e != nil { return e } - return srv.serveUDP(l) + srv.PacketConn = l + srv.started = true + srv.lock.Unlock() + e = srv.serveUDP(l) + srv.lock.Lock() // to satisfy the defer at the top + return e } return &Error{err: "bad network"} } @@ -285,71 +378,62 @@ func (srv *Server) ListenAndServe() error { // configured in *Server. Its main use is to start a server from systemd. func (srv *Server) ActivateAndServe() error { srv.lock.Lock() + defer srv.lock.Unlock() if srv.started { return &Error{err: "server already started"} } - srv.stopUDP, srv.stopTCP = make(chan bool), make(chan bool) - srv.started = true - srv.lock.Unlock() - if srv.PacketConn != nil { + pConn := srv.PacketConn + l := srv.Listener + 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) + srv.started = true + srv.lock.Unlock() + e := srv.serveUDP(t) + srv.lock.Lock() // to satisfy the defer at the top + return e } } - if srv.Listener != nil { - if t, ok := srv.Listener.(*net.TCPListener); ok { - return srv.serveTCP(t) - } + if l != nil { + srv.started = true + srv.lock.Unlock() + e := srv.serveTCP(l) + srv.lock.Lock() // to satisfy the defer at the top + return e } return &Error{err: "bad listeners"} } // Shutdown gracefully shuts down a server. After a call to Shutdown, ListenAndServe and // ActivateAndServe will return. All in progress queries are completed before the server -// is taken down. If the Shutdown is taking longer than the reading timeout 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() if !srv.started { + srv.lock.Unlock() return &Error{err: "server not started"} } srv.started = false srv.lock.Unlock() - net, addr := srv.Net, srv.Addr - switch { - case srv.Listener != nil: - a := srv.Listener.Addr() - net, addr = a.Network(), a.String() - case srv.PacketConn != nil: - a := srv.PacketConn.LocalAddr() - net, addr = a.Network(), a.String() + + if srv.PacketConn != nil { + srv.PacketConn.Close() + } + if srv.Listener != nil { + srv.Listener.Close() } fin := make(chan bool) - switch net { - case "tcp", "tcp4", "tcp6": - go func() { - srv.stopTCP <- true - srv.wgTCP.Wait() - fin <- true - }() - - case "udp", "udp4", "udp6": - go func() { - srv.stopUDP <- true - srv.wgUDP.Wait() - fin <- true - }() - } - - c := &Client{Net: net} - go c.Exchange(new(Msg), addr) // extra query to help ReadXXX loop to pass + go func() { + srv.inFlight.Wait() + fin <- true + }() select { case <-time.After(srv.getReadTimeout()): @@ -369,14 +453,19 @@ func (srv *Server) getReadTimeout() time.Duration { } // serveTCP starts a TCP listener for the server. -// Each request is handled in a seperate goroutine. -func (srv *Server) serveTCP(l *net.TCPListener) error { +// Each request is handled in a separate goroutine. +func (srv *Server) serveTCP(l net.Listener) error { defer l.Close() if srv.NotifyStartedFunc != nil { srv.NotifyStartedFunc() } + reader := Reader(&defaultReader{srv}) + if srv.DecorateReader != nil { + reader = srv.DecorateReader(reader) + } + handler := srv.Handler if handler == nil { handler = DefaultServeMux @@ -384,27 +473,30 @@ func (srv *Server) serveTCP(l *net.TCPListener) error { rtimeout := srv.getReadTimeout() // deadline is not used here for { - rw, e := l.AcceptTCP() + rw, e := l.Accept() if e != nil { - continue + if neterr, ok := e.(net.Error); ok && neterr.Temporary() { + continue + } + return e } - m, e := srv.readTCP(rw, rtimeout) - select { - case <-srv.stopTCP: + m, e := reader.ReadTCP(rw, rtimeout) + srv.lock.RLock() + if !srv.started { + srv.lock.RUnlock() return nil - default: } + srv.lock.RUnlock() if e != nil { continue } - srv.wgTCP.Add(1) + srv.inFlight.Add(1) go srv.serve(rw.RemoteAddr(), handler, m, nil, nil, rw) } - panic("dns: not reached") } // serveUDP starts a UDP listener for the server. -// Each request is handled in a seperate goroutine. +// Each request is handled in a separate goroutine. func (srv *Server) serveUDP(l *net.UDPConn) error { defer l.Close() @@ -412,6 +504,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 @@ -419,35 +516,39 @@ func (srv *Server) serveUDP(l *net.UDPConn) error { rtimeout := srv.getReadTimeout() // deadline is not used here for { - m, s, e := srv.readUDP(l, rtimeout) - select { - case <-srv.stopUDP: + m, s, e := reader.ReadUDP(l, rtimeout) + srv.lock.RLock() + if !srv.started { + srv.lock.RUnlock() return nil - default: } + srv.lock.RUnlock() if e != nil { continue } - srv.wgUDP.Add(1) + srv.inFlight.Add(1) go srv.serve(s.RemoteAddr(), handler, m, l, s, nil) } - 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) { +func (srv *Server) serve(a net.Addr, h Handler, m []byte, u *net.UDPConn, s *SessionUDP, t net.Conn) { + defer srv.inFlight.Done() + w := &response{tsigSecret: srv.TsigSecret, udp: u, tcp: t, remoteAddr: a, udpSession: s} - q := 0 - defer func() { - if u != nil { - srv.wgUDP.Done() - } - if t != nil { - srv.wgTCP.Done() - } - }() + if srv.DecorateWriter != nil { + w.writer = srv.DecorateWriter(w) + } else { + w.writer = w + } + + q := 0 // counter for the amount of TCP queries we get + + reader := Reader(&defaultReader{srv}) + if srv.DecorateReader != nil { + reader = srv.DecorateReader(reader) + } Redo: - // Ideally we want use isMsg here before we allocate memory to actually parse the packet. req := new(Msg) err := req.Unpack(m) if err != nil { // Send a FormatError back @@ -475,6 +576,15 @@ Redo: h.ServeDNS(w, req) // Writes back to the client Exit: + if w.tcp == nil { + return + } + // TODO(miek): make this number configurable? + if q > maxTCPQueries { // close socket after this many queries + w.Close() + return + } + if w.hijacked { return // client calls Close() } @@ -486,21 +596,16 @@ 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() return } -func (srv *Server) readTCP(conn *net.TCPConn, timeout time.Duration) ([]byte, error) { +func (srv *Server) readTCP(conn net.Conn, timeout time.Duration) ([]byte, error) { conn.SetReadDeadline(time.Now().Add(timeout)) l := make([]byte, 2) n, err := conn.Read(l) @@ -535,10 +640,10 @@ func (srv *Server) readTCP(conn *net.TCPConn, timeout time.Duration) ([]byte, er return m, nil } -func (srv *Server) readUDP(conn *net.UDPConn, timeout time.Duration) ([]byte, *sessionUDP, error) { +func (srv *Server) readUDP(conn *net.UDPConn, timeout time.Duration) ([]byte, *SessionUDP, error) { conn.SetReadDeadline(time.Now().Add(timeout)) m := make([]byte, srv.UDPSize) - n, s, e := readFromSessionUDP(conn, m) + n, s, e := ReadFromSessionUDP(conn, m) if e != nil || n == 0 { if e != nil { return nil, nil, e @@ -558,7 +663,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 } } @@ -566,7 +671,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 } @@ -574,7 +679,7 @@ func (w *response) WriteMsg(m *Msg) (err error) { func (w *response) Write(m []byte) (int, error) { switch { case w.udp != nil: - n, err := writeToSessionUDP(w.udp, m, w.udpSession) + n, err := WriteToSessionUDP(w.udp, m, w.udpSession) return n, err case w.tcp != nil: lm := len(m) diff --git a/vendor/github.com/miekg/dns/sig0.go b/vendor/github.com/miekg/dns/sig0.go index d96b31be06b..0fccddbc150 100644 --- a/vendor/github.com/miekg/dns/sig0.go +++ b/vendor/github.com/miekg/dns/sig0.go @@ -1,25 +1,9 @@ -// SIG(0) -// -// From RFC 2931: -// -// SIG(0) provides protection for DNS transactions and requests .... -// ... protection for glue records, DNS requests, protection for message headers -// on requests and responses, and protection of the overall integrity of a response. -// -// It works like TSIG, except that SIG(0) uses public key cryptography, instead of the shared -// secret approach in TSIG. -// Supported algorithms: DSA, ECDSAP256SHA256, ECDSAP384SHA384, RSASHA1, RSASHA256 and -// RSASHA512. -// -// Signing subsequent messages in multi-message sessions is not implemented. -// package dns import ( "crypto" "crypto/dsa" "crypto/ecdsa" - "crypto/rand" "crypto/rsa" "math/big" "strings" @@ -29,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 } @@ -57,56 +41,26 @@ func (rr *SIG) Sign(k PrivateKey, m *Msg) ([]byte, error) { return nil, err } buf = buf[:off:cap(buf)] - var hash crypto.Hash - var intlen int - switch rr.Algorithm { - case DSA, RSASHA1: - hash = crypto.SHA1 - case RSASHA256, ECDSAP256SHA256: - hash = crypto.SHA256 - intlen = 32 - case ECDSAP384SHA384: - hash = crypto.SHA384 - intlen = 48 - 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) - var sig []byte - switch p := k.(type) { - case *dsa.PrivateKey: - t := divRoundUp(divRoundUp(p.PublicKey.Y.BitLen(), 8)-64, 8) - r1, s1, err := dsa.Sign(rand.Reader, p, hashed) - if err != nil { - return nil, err - } - sig = append(sig, byte(t)) - sig = append(sig, intToBytes(r1, 20)...) - sig = append(sig, intToBytes(s1, 20)...) - case *rsa.PrivateKey: - sig, err = rsa.SignPKCS1v15(rand.Reader, p, hash, hashed) - if err != nil { - return nil, err - } - case *ecdsa.PrivateKey: - r1, s1, err := ecdsa.Sign(rand.Reader, p, hashed) - if err != nil { - return nil, err - } - sig = intToBytes(r1, intlen) - sig = append(sig, intToBytes(s1, intlen)...) - default: - return nil, ErrAlg + 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 @@ -118,7 +72,7 @@ func (rr *SIG) Sign(k PrivateKey, m *Msg) ([]byte, error) { buf[rdoff], buf[rdoff+1] = packUint16(rdlen) // Adjust additional count adc, _ := unpackUint16(buf, 10) - adc += 1 + adc++ buf[10], buf[11] = packUint16(adc) return buf, nil } @@ -246,7 +200,7 @@ func (rr *SIG) Verify(k *KEY, buf []byte) error { return rsa.VerifyPKCS1v15(pk, hash, hashed, sig) } case ECDSAP256SHA256, ECDSAP384SHA384: - pk := k.publicKeyCurve() + pk := k.publicKeyECDSA() r := big.NewInt(0) r.SetBytes(sig[:len(sig)/2]) s := big.NewInt(0) diff --git a/vendor/github.com/miekg/dns/tlsa.go b/vendor/github.com/miekg/dns/tlsa.go index d3bc3b0217f..0a550dc6cbf 100644 --- a/vendor/github.com/miekg/dns/tlsa.go +++ b/vendor/github.com/miekg/dns/tlsa.go @@ -25,7 +25,8 @@ func CertificateToDANE(selector, matchingType uint8, cert *x509.Certificate) (st h := sha256.New() switch selector { case 0: - return hex.EncodeToString(cert.Raw), nil + io.WriteString(h, string(cert.Raw)) + return hex.EncodeToString(h.Sum(nil)), nil case 1: io.WriteString(h, string(cert.RawSubjectPublicKeyInfo)) return hex.EncodeToString(h.Sum(nil)), nil @@ -34,7 +35,8 @@ func CertificateToDANE(selector, matchingType uint8, cert *x509.Certificate) (st h := sha512.New() switch selector { case 0: - return hex.EncodeToString(cert.Raw), nil + io.WriteString(h, string(cert.Raw)) + return hex.EncodeToString(h.Sum(nil)), nil case 1: io.WriteString(h, string(cert.RawSubjectPublicKeyInfo)) return hex.EncodeToString(h.Sum(nil)), nil @@ -80,5 +82,5 @@ func TLSAName(name, service, network string) (string, error) { if e != nil { return "", e } - return "_" + strconv.Itoa(p) + "_" + network + "." + name, nil + return "_" + strconv.Itoa(p) + "._" + network + "." + name, nil } diff --git a/vendor/github.com/miekg/dns/tsig.go b/vendor/github.com/miekg/dns/tsig.go index 2c64ee8d548..c3374e19407 100644 --- a/vendor/github.com/miekg/dns/tsig.go +++ b/vendor/github.com/miekg/dns/tsig.go @@ -1,56 +1,3 @@ -// TRANSACTION SIGNATURE -// -// An TSIG or transaction signature adds a HMAC TSIG record to each message sent. -// The supported algorithms include: HmacMD5, HmacSHA1 and HmacSHA256. -// -// Basic use pattern when querying with a TSIG name "axfr." (note that these key names -// must be fully qualified - as they are domain names) and the base64 secret -// "so6ZGir4GPAqINNh9U5c3A==": -// -// c := new(dns.Client) -// c.TsigSecret = map[string]string{"axfr.": "so6ZGir4GPAqINNh9U5c3A=="} -// m := new(dns.Msg) -// m.SetQuestion("miek.nl.", dns.TypeMX) -// m.SetTsig("axfr.", dns.HmacMD5, 300, time.Now().Unix()) -// ... -// // When sending the TSIG RR is calculated and filled in before sending -// -// When requesting an zone transfer (almost all TSIG usage is when requesting zone transfers), with -// TSIG, this is the basic use pattern. In this example we request an AXFR for -// miek.nl. with TSIG key named "axfr." and secret "so6ZGir4GPAqINNh9U5c3A==" -// and using the server 176.58.119.54: -// -// t := new(dns.Transfer) -// m := new(dns.Msg) -// t.TsigSecret = map[string]string{"axfr.": "so6ZGir4GPAqINNh9U5c3A=="} -// m.SetAxfr("miek.nl.") -// m.SetTsig("axfr.", dns.HmacMD5, 300, time.Now().Unix()) -// c, err := t.In(m, "176.58.119.54:53") -// for r := range c { /* r.RR */ } -// -// You can now read the records from the transfer as they come in. Each envelope is checked with TSIG. -// If something is not correct an error is returned. -// -// Basic use pattern validating and replying to a message that has TSIG set. -// -// server := &dns.Server{Addr: ":53", Net: "udp"} -// server.TsigSecret = map[string]string{"axfr.": "so6ZGir4GPAqINNh9U5c3A=="} -// go server.ListenAndServe() -// dns.HandleFunc(".", handleRequest) -// -// func handleRequest(w dns.ResponseWriter, r *dns.Msg) { -// m := new(Msg) -// m.SetReply(r) -// if r.IsTsig() { -// if w.TsigStatus() == nil { -// // *Msg r has an TSIG record and it was validated -// m.SetTsig("axfr.", dns.HmacMD5, 300, time.Now().Unix()) -// } else { -// // *Msg r has an TSIG records and it was not valided -// } -// } -// w.WriteMsg(m) -// } package dns import ( @@ -58,6 +5,7 @@ import ( "crypto/md5" "crypto/sha1" "crypto/sha256" + "crypto/sha512" "encoding/hex" "hash" "io" @@ -71,8 +19,11 @@ const ( HmacMD5 = "hmac-md5.sig-alg.reg.int." HmacSHA1 = "hmac-sha1." HmacSHA256 = "hmac-sha256." + HmacSHA512 = "hmac-sha512." ) +// TSIG is the RR the holds the transaction signature of a message. +// See RFC 2845 and RFC 4635. type TSIG struct { Hdr RR_Header Algorithm string `dns:"domain-name"` @@ -86,10 +37,6 @@ type TSIG struct { OtherData string `dns:"size-hex"` } -func (rr *TSIG) Header() *RR_Header { - return &rr.Hdr -} - // TSIG has no official presentation format, but this will suffice. func (rr *TSIG) String() string { @@ -107,15 +54,6 @@ func (rr *TSIG) String() string { return s } -func (rr *TSIG) len() int { - return rr.Hdr.len() + len(rr.Algorithm) + 1 + 6 + - 4 + len(rr.MAC)/2 + 1 + 6 + len(rr.OtherData)/2 + 1 -} - -func (rr *TSIG) copy() RR { - return &TSIG{*rr.Hdr.copyHeader(), rr.Algorithm, rr.TimeSigned, rr.Fudge, rr.MACSize, rr.MAC, rr.OrigId, rr.Error, rr.OtherLen, rr.OtherData} -} - // The following values must be put in wireformat, so that the MAC can be calculated. // RFC 2845, section 3.4.2. TSIG Variables. type tsigWireFmt struct { @@ -174,13 +112,15 @@ func TsigGenerate(m *Msg, secret, requestMAC string, timersOnly bool) ([]byte, s t := new(TSIG) var h hash.Hash - switch rr.Algorithm { + switch strings.ToLower(rr.Algorithm) { case HmacMD5: h = hmac.New(md5.New, []byte(rawsecret)) case HmacSHA1: h = hmac.New(sha1.New, []byte(rawsecret)) case HmacSHA256: h = hmac.New(sha256.New, []byte(rawsecret)) + case HmacSHA512: + h = hmac.New(sha512.New, []byte(rawsecret)) default: return nil, "", ErrKeyAlg } @@ -238,13 +178,15 @@ func TsigVerify(msg []byte, secret, requestMAC string, timersOnly bool) error { } var h hash.Hash - switch tsig.Algorithm { + switch strings.ToLower(tsig.Algorithm) { case HmacMD5: h = hmac.New(md5.New, rawsecret) case HmacSHA1: h = hmac.New(sha1.New, rawsecret) case HmacSHA256: h = hmac.New(sha256.New, rawsecret) + case HmacSHA512: + h = hmac.New(sha512.New, rawsecret) default: return ErrKeyAlg } diff --git a/vendor/github.com/miekg/dns/types.go b/vendor/github.com/miekg/dns/types.go index 16bb181b9b0..64143dba511 100644 --- a/vendor/github.com/miekg/dns/types.go +++ b/vendor/github.com/miekg/dns/types.go @@ -10,9 +10,12 @@ import ( ) type ( - Type uint16 // Type is a DNS type. - Class uint16 // Class is a DNS class. - Name string // Name is a DNS domain name. + // Type is a DNS type. + Type uint16 + // Class is a DNS class. + Class uint16 + // Name is a DNS domain name. + Name string ) // Packet formats @@ -20,6 +23,7 @@ type ( // Wire constants and supported types. const ( // valid RR_Header.Rrtype and Question.qtype + TypeNone uint16 = 0 TypeA uint16 = 1 TypeNS uint16 = 2 @@ -42,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 @@ -88,9 +91,12 @@ 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 @@ -98,8 +104,6 @@ const ( TypeMAILA uint16 = 254 TypeANY uint16 = 255 - TypeURI uint16 = 256 - TypeCAA uint16 = 257 TypeTA uint16 = 32768 TypeDLV uint16 = 32769 TypeReserved uint16 = 65535 @@ -112,7 +116,7 @@ const ( ClassNONE = 254 ClassANY = 255 - // Msg.rcode + // Message Response Codes. RcodeSuccess = 0 RcodeFormatError = 1 RcodeServerFailure = 2 @@ -133,16 +137,15 @@ const ( RcodeBadAlg = 21 RcodeBadTrunc = 22 // TSIG - // Opcode + // Message Opcodes. There is no 3. OpcodeQuery = 0 OpcodeIQuery = 1 OpcodeStatus = 2 - // There is no 3 OpcodeNotify = 4 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 @@ -150,6 +153,8 @@ type Header struct { } const ( + headerSize = 12 + // Header.Bits _QR = 1 << 15 // query/response (response=1) _AA = 1 << 10 // authoritative @@ -169,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 @@ -183,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", @@ -196,15 +203,23 @@ var CertTypeToString = map[uint16]string{ CertOID: "OID", } +// StringToCertType is the reverseof CertTypeToString. var StringToCertType = reverseInt16(CertTypeToString) -// DNS queries. +//go:generate go run types_generate.go + +// Question holds a DNS question. There can be multiple questions in the +// question section of a message. Usually there is just one. type Question struct { Name string `dns:"cdomain-name"` // "cdomain-name" specifies encoding (and may be compressed) Qtype uint16 Qclass uint16 } +func (q *Question) len() int { + return len(q.Name) + 1 + 2 + 2 +} + func (q *Question) String() (s string) { // prefix with ; (as in dig) s = ";" + sprintName(q.Name) + "\t" @@ -213,30 +228,21 @@ func (q *Question) String() (s string) { return s } -func (q *Question) len() int { - l := len(q.Name) + 1 - return l + 4 -} - +// ANY is a wildcard record. See RFC 1035, Section 3.2.3. ANY +// is named "*" there. type ANY struct { Hdr RR_Header // Does not have any rdata } -func (rr *ANY) Header() *RR_Header { return &rr.Hdr } -func (rr *ANY) copy() RR { return &ANY{*rr.Hdr.copyHeader()} } -func (rr *ANY) String() string { return rr.Hdr.String() } -func (rr *ANY) len() int { return rr.Hdr.len() } +func (rr *ANY) String() string { return rr.Hdr.String() } type CNAME struct { Hdr RR_Header Target string `dns:"cdomain-name"` } -func (rr *CNAME) Header() *RR_Header { return &rr.Hdr } -func (rr *CNAME) copy() RR { return &CNAME{*rr.Hdr.copyHeader(), sprintName(rr.Target)} } -func (rr *CNAME) String() string { return rr.Hdr.String() + rr.Target } -func (rr *CNAME) len() int { return rr.Hdr.len() + len(rr.Target) + 1 } +func (rr *CNAME) String() string { return rr.Hdr.String() + sprintName(rr.Target) } type HINFO struct { Hdr RR_Header @@ -244,31 +250,23 @@ type HINFO struct { Os string } -func (rr *HINFO) Header() *RR_Header { return &rr.Hdr } -func (rr *HINFO) copy() RR { return &HINFO{*rr.Hdr.copyHeader(), rr.Cpu, rr.Os} } -func (rr *HINFO) String() string { return rr.Hdr.String() + rr.Cpu + " " + rr.Os } -func (rr *HINFO) len() int { return rr.Hdr.len() + len(rr.Cpu) + len(rr.Os) } +func (rr *HINFO) String() string { + return rr.Hdr.String() + sprintTxt([]string{rr.Cpu, rr.Os}) +} type MB struct { Hdr RR_Header Mb string `dns:"cdomain-name"` } -func (rr *MB) Header() *RR_Header { return &rr.Hdr } -func (rr *MB) copy() RR { return &MB{*rr.Hdr.copyHeader(), sprintName(rr.Mb)} } - -func (rr *MB) String() string { return rr.Hdr.String() + rr.Mb } -func (rr *MB) len() int { return rr.Hdr.len() + len(rr.Mb) + 1 } +func (rr *MB) String() string { return rr.Hdr.String() + sprintName(rr.Mb) } type MG struct { Hdr RR_Header Mg string `dns:"cdomain-name"` } -func (rr *MG) Header() *RR_Header { return &rr.Hdr } -func (rr *MG) copy() RR { return &MG{*rr.Hdr.copyHeader(), rr.Mg} } -func (rr *MG) len() int { l := len(rr.Mg) + 1; return rr.Hdr.len() + l } -func (rr *MG) String() string { return rr.Hdr.String() + sprintName(rr.Mg) } +func (rr *MG) String() string { return rr.Hdr.String() + sprintName(rr.Mg) } type MINFO struct { Hdr RR_Header @@ -276,28 +274,15 @@ type MINFO struct { Email string `dns:"cdomain-name"` } -func (rr *MINFO) Header() *RR_Header { return &rr.Hdr } -func (rr *MINFO) copy() RR { return &MINFO{*rr.Hdr.copyHeader(), rr.Rmail, rr.Email} } - func (rr *MINFO) String() string { return rr.Hdr.String() + sprintName(rr.Rmail) + " " + sprintName(rr.Email) } -func (rr *MINFO) len() int { - l := len(rr.Rmail) + 1 - n := len(rr.Email) + 1 - return rr.Hdr.len() + l + n -} - type MR struct { Hdr RR_Header Mr string `dns:"cdomain-name"` } -func (rr *MR) Header() *RR_Header { return &rr.Hdr } -func (rr *MR) copy() RR { return &MR{*rr.Hdr.copyHeader(), rr.Mr} } -func (rr *MR) len() int { l := len(rr.Mr) + 1; return rr.Hdr.len() + l } - func (rr *MR) String() string { return rr.Hdr.String() + sprintName(rr.Mr) } @@ -307,10 +292,6 @@ type MF struct { Mf string `dns:"cdomain-name"` } -func (rr *MF) Header() *RR_Header { return &rr.Hdr } -func (rr *MF) copy() RR { return &MF{*rr.Hdr.copyHeader(), rr.Mf} } -func (rr *MF) len() int { return rr.Hdr.len() + len(rr.Mf) + 1 } - func (rr *MF) String() string { return rr.Hdr.String() + sprintName(rr.Mf) } @@ -320,10 +301,6 @@ type MD struct { Md string `dns:"cdomain-name"` } -func (rr *MD) Header() *RR_Header { return &rr.Hdr } -func (rr *MD) copy() RR { return &MD{*rr.Hdr.copyHeader(), rr.Md} } -func (rr *MD) len() int { return rr.Hdr.len() + len(rr.Md) + 1 } - func (rr *MD) String() string { return rr.Hdr.String() + sprintName(rr.Md) } @@ -334,10 +311,6 @@ type MX struct { Mx string `dns:"cdomain-name"` } -func (rr *MX) Header() *RR_Header { return &rr.Hdr } -func (rr *MX) copy() RR { return &MX{*rr.Hdr.copyHeader(), rr.Preference, rr.Mx} } -func (rr *MX) len() int { l := len(rr.Mx) + 1; return rr.Hdr.len() + l + 2 } - func (rr *MX) String() string { return rr.Hdr.String() + strconv.Itoa(int(rr.Preference)) + " " + sprintName(rr.Mx) } @@ -348,10 +321,6 @@ type AFSDB struct { Hostname string `dns:"cdomain-name"` } -func (rr *AFSDB) Header() *RR_Header { return &rr.Hdr } -func (rr *AFSDB) copy() RR { return &AFSDB{*rr.Hdr.copyHeader(), rr.Subtype, rr.Hostname} } -func (rr *AFSDB) len() int { l := len(rr.Hostname) + 1; return rr.Hdr.len() + l + 2 } - func (rr *AFSDB) String() string { return rr.Hdr.String() + strconv.Itoa(int(rr.Subtype)) + " " + sprintName(rr.Hostname) } @@ -361,10 +330,6 @@ type X25 struct { PSDNAddress string } -func (rr *X25) Header() *RR_Header { return &rr.Hdr } -func (rr *X25) copy() RR { return &X25{*rr.Hdr.copyHeader(), rr.PSDNAddress} } -func (rr *X25) len() int { return rr.Hdr.len() + len(rr.PSDNAddress) + 1 } - func (rr *X25) String() string { return rr.Hdr.String() + rr.PSDNAddress } @@ -375,10 +340,6 @@ type RT struct { Host string `dns:"cdomain-name"` } -func (rr *RT) Header() *RR_Header { return &rr.Hdr } -func (rr *RT) copy() RR { return &RT{*rr.Hdr.copyHeader(), rr.Preference, rr.Host} } -func (rr *RT) len() int { l := len(rr.Host) + 1; return rr.Hdr.len() + l + 2 } - func (rr *RT) String() string { return rr.Hdr.String() + strconv.Itoa(int(rr.Preference)) + " " + sprintName(rr.Host) } @@ -388,10 +349,6 @@ type NS struct { Ns string `dns:"cdomain-name"` } -func (rr *NS) Header() *RR_Header { return &rr.Hdr } -func (rr *NS) len() int { l := len(rr.Ns) + 1; return rr.Hdr.len() + l } -func (rr *NS) copy() RR { return &NS{*rr.Hdr.copyHeader(), rr.Ns} } - func (rr *NS) String() string { return rr.Hdr.String() + sprintName(rr.Ns) } @@ -401,10 +358,6 @@ type PTR struct { Ptr string `dns:"cdomain-name"` } -func (rr *PTR) Header() *RR_Header { return &rr.Hdr } -func (rr *PTR) copy() RR { return &PTR{*rr.Hdr.copyHeader(), rr.Ptr} } -func (rr *PTR) len() int { l := len(rr.Ptr) + 1; return rr.Hdr.len() + l } - func (rr *PTR) String() string { return rr.Hdr.String() + sprintName(rr.Ptr) } @@ -415,10 +368,6 @@ type RP struct { Txt string `dns:"domain-name"` } -func (rr *RP) Header() *RR_Header { return &rr.Hdr } -func (rr *RP) copy() RR { return &RP{*rr.Hdr.copyHeader(), rr.Mbox, rr.Txt} } -func (rr *RP) len() int { return rr.Hdr.len() + len(rr.Mbox) + 1 + len(rr.Txt) + 1 } - func (rr *RP) String() string { return rr.Hdr.String() + rr.Mbox + " " + sprintTxt([]string{rr.Txt}) } @@ -434,11 +383,6 @@ type SOA struct { Minttl uint32 } -func (rr *SOA) Header() *RR_Header { return &rr.Hdr } -func (rr *SOA) copy() RR { - return &SOA{*rr.Hdr.copyHeader(), rr.Ns, rr.Mbox, rr.Serial, rr.Refresh, rr.Retry, rr.Expire, rr.Minttl} -} - func (rr *SOA) String() string { return rr.Hdr.String() + sprintName(rr.Ns) + " " + sprintName(rr.Mbox) + " " + strconv.FormatInt(int64(rr.Serial), 10) + @@ -448,24 +392,11 @@ func (rr *SOA) String() string { " " + strconv.FormatInt(int64(rr.Minttl), 10) } -func (rr *SOA) len() int { - l := len(rr.Ns) + 1 - n := len(rr.Mbox) + 1 - return rr.Hdr.len() + l + n + 20 -} - type TXT struct { Hdr RR_Header Txt []string `dns:"txt"` } -func (rr *TXT) Header() *RR_Header { return &rr.Hdr } -func (rr *TXT) copy() RR { - cp := make([]string, len(rr.Txt), cap(rr.Txt)) - copy(cp, rr.Txt) - return &TXT{*rr.Hdr.copyHeader(), cp} -} - func (rr *TXT) String() string { return rr.Hdr.String() + sprintTxt(rr.Txt) } func sprintName(s string) string { @@ -490,6 +421,34 @@ func sprintName(s string) string { return string(dst) } +func sprintTxtOctet(s string) string { + src := []byte(s) + dst := make([]byte, 0, len(src)) + dst = append(dst, '"') + for i := 0; i < len(src); { + if i+1 < len(src) && src[i] == '\\' && src[i+1] == '.' { + dst = append(dst, src[i:i+2]...) + i += 2 + } else { + b, n := nextByte(src, i) + if n == 0 { + i++ // dangling back slash + } else if b == '.' { + dst = append(dst, b) + } else { + if b < ' ' || b > '~' { + dst = appendByte(dst, b) + } else { + dst = append(dst, b) + } + } + i += n + } + } + dst = append(dst, '"') + return string(dst) +} + func sprintTxt(txt []string) string { var out []byte for i, s := range txt { @@ -532,21 +491,24 @@ func appendTXTStringByte(s []byte, b byte) []byte { return append(s, '\\', b) } if b < ' ' || b > '~' { - var buf [3]byte - bufs := strconv.AppendInt(buf[:0], int64(b), 10) - s = append(s, '\\') - for i := 0; i < 3-len(bufs); i++ { - s = append(s, '0') - } - for _, r := range bufs { - s = append(s, r) - } - return s - + return appendByte(s, b) } return append(s, b) } +func appendByte(s []byte, b byte) []byte { + var buf [3]byte + bufs := strconv.AppendInt(buf[:0], int64(b), 10) + s = append(s, '\\') + for i := 0; i < 3-len(bufs); i++ { + s = append(s, '0') + } + for _, r := range bufs { + s = append(s, r) + } + return s +} + func nextByte(b []byte, offset int) (byte, int) { if offset >= len(b) { return 0, 0 @@ -577,36 +539,13 @@ func nextByte(b []byte, offset int) (byte, int) { } } -func (rr *TXT) len() int { - l := rr.Hdr.len() - for _, t := range rr.Txt { - l += len(t) + 1 - } - return l -} - type SPF struct { Hdr RR_Header Txt []string `dns:"txt"` } -func (rr *SPF) Header() *RR_Header { return &rr.Hdr } -func (rr *SPF) copy() RR { - cp := make([]string, len(rr.Txt), cap(rr.Txt)) - copy(cp, rr.Txt) - return &SPF{*rr.Hdr.copyHeader(), cp} -} - func (rr *SPF) String() string { return rr.Hdr.String() + sprintTxt(rr.Txt) } -func (rr *SPF) len() int { - l := rr.Hdr.len() - for _, t := range rr.Txt { - l += len(t) + 1 - } - return l -} - type SRV struct { Hdr RR_Header Priority uint16 @@ -615,12 +554,6 @@ type SRV struct { Target string `dns:"domain-name"` } -func (rr *SRV) Header() *RR_Header { return &rr.Hdr } -func (rr *SRV) len() int { l := len(rr.Target) + 1; return rr.Hdr.len() + l + 6 } -func (rr *SRV) copy() RR { - return &SRV{*rr.Hdr.copyHeader(), rr.Priority, rr.Weight, rr.Port, rr.Target} -} - func (rr *SRV) String() string { return rr.Hdr.String() + strconv.Itoa(int(rr.Priority)) + " " + @@ -638,11 +571,6 @@ type NAPTR struct { Replacement string `dns:"domain-name"` } -func (rr *NAPTR) Header() *RR_Header { return &rr.Hdr } -func (rr *NAPTR) copy() RR { - return &NAPTR{*rr.Hdr.copyHeader(), rr.Order, rr.Preference, rr.Flags, rr.Service, rr.Regexp, rr.Replacement} -} - func (rr *NAPTR) String() string { return rr.Hdr.String() + strconv.Itoa(int(rr.Order)) + " " + @@ -653,12 +581,7 @@ func (rr *NAPTR) String() string { rr.Replacement } -func (rr *NAPTR) len() int { - return rr.Hdr.len() + 4 + len(rr.Flags) + 1 + len(rr.Service) + 1 + - len(rr.Regexp) + 1 + len(rr.Replacement) + 1 -} - -// See RFC 4398. +// The CERT resource record, see RFC 4398. type CERT struct { Hdr RR_Header Type uint16 @@ -667,11 +590,6 @@ type CERT struct { Certificate string `dns:"base64"` } -func (rr *CERT) Header() *RR_Header { return &rr.Hdr } -func (rr *CERT) copy() RR { - return &CERT{*rr.Hdr.copyHeader(), rr.Type, rr.KeyTag, rr.Algorithm, rr.Certificate} -} - func (rr *CERT) String() string { var ( ok bool @@ -689,21 +607,12 @@ func (rr *CERT) String() string { " " + rr.Certificate } -func (rr *CERT) len() int { - return rr.Hdr.len() + 5 + - base64.StdEncoding.DecodedLen(len(rr.Certificate)) -} - -// See RFC 2672. +// The DNAME resource record, see RFC 2672. type DNAME struct { Hdr RR_Header Target string `dns:"domain-name"` } -func (rr *DNAME) Header() *RR_Header { return &rr.Hdr } -func (rr *DNAME) copy() RR { return &DNAME{*rr.Hdr.copyHeader(), rr.Target} } -func (rr *DNAME) len() int { l := len(rr.Target) + 1; return rr.Hdr.len() + l } - func (rr *DNAME) String() string { return rr.Hdr.String() + sprintName(rr.Target) } @@ -713,10 +622,6 @@ type A struct { A net.IP `dns:"a"` } -func (rr *A) Header() *RR_Header { return &rr.Hdr } -func (rr *A) copy() RR { return &A{*rr.Hdr.copyHeader(), copyIP(rr.A)} } -func (rr *A) len() int { return rr.Hdr.len() + net.IPv4len } - func (rr *A) String() string { if rr.A == nil { return rr.Hdr.String() @@ -729,10 +634,6 @@ type AAAA struct { AAAA net.IP `dns:"aaaa"` } -func (rr *AAAA) Header() *RR_Header { return &rr.Hdr } -func (rr *AAAA) copy() RR { return &AAAA{*rr.Hdr.copyHeader(), copyIP(rr.AAAA)} } -func (rr *AAAA) len() int { return rr.Hdr.len() + net.IPv6len } - func (rr *AAAA) String() string { if rr.AAAA == nil { return rr.Hdr.String() @@ -747,12 +648,9 @@ type PX struct { Mapx400 string `dns:"domain-name"` } -func (rr *PX) Header() *RR_Header { return &rr.Hdr } -func (rr *PX) copy() RR { return &PX{*rr.Hdr.copyHeader(), rr.Preference, rr.Map822, rr.Mapx400} } func (rr *PX) String() string { return rr.Hdr.String() + strconv.Itoa(int(rr.Preference)) + " " + sprintName(rr.Map822) + " " + sprintName(rr.Mapx400) } -func (rr *PX) len() int { return rr.Hdr.len() + 2 + len(rr.Map822) + 1 + len(rr.Mapx400) + 1 } type GPOS struct { Hdr RR_Header @@ -761,11 +659,6 @@ type GPOS struct { Altitude string } -func (rr *GPOS) Header() *RR_Header { return &rr.Hdr } -func (rr *GPOS) copy() RR { return &GPOS{*rr.Hdr.copyHeader(), rr.Longitude, rr.Latitude, rr.Altitude} } -func (rr *GPOS) len() int { - return rr.Hdr.len() + len(rr.Longitude) + len(rr.Latitude) + len(rr.Altitude) + 3 -} func (rr *GPOS) String() string { return rr.Hdr.String() + rr.Longitude + " " + rr.Latitude + " " + rr.Altitude } @@ -781,12 +674,6 @@ type LOC struct { Altitude uint32 } -func (rr *LOC) Header() *RR_Header { return &rr.Hdr } -func (rr *LOC) len() int { return rr.Hdr.len() + 4 + 12 } -func (rr *LOC) copy() RR { - return &LOC{*rr.Hdr.copyHeader(), rr.Version, rr.Size, rr.HorizPre, rr.VertPre, rr.Latitude, rr.Longitude, rr.Altitude} -} - // cmToM takes a cm value expressed in RFC1876 SIZE mantissa/exponent // format and returns a string in m (two decimals for the cm) func cmToM(m, e uint8) string { @@ -801,12 +688,11 @@ func cmToM(m, e uint8) string { s := fmt.Sprintf("%d", m) for e > 2 { s += "0" - e -= 1 + e-- } return s } -// String returns a string version of a LOC func (rr *LOC) String() string { s := rr.Hdr.String() @@ -838,7 +724,7 @@ func (rr *LOC) String() string { lon = lon % LOC_HOURS s += fmt.Sprintf("%02d %02d %0.3f %s ", h, m, (float64(lon) / 1000), ew) - var alt float64 = float64(rr.Altitude) / 100 + var alt = float64(rr.Altitude) / 100 alt -= LOC_ALTITUDEBASE if rr.Altitude%100 != 0 { s += fmt.Sprintf("%.2fm ", alt) @@ -871,11 +757,6 @@ type RRSIG struct { Signature string `dns:"base64"` } -func (rr *RRSIG) Header() *RR_Header { return &rr.Hdr } -func (rr *RRSIG) copy() RR { - return &RRSIG{*rr.Hdr.copyHeader(), rr.TypeCovered, rr.Algorithm, rr.Labels, rr.OrigTtl, rr.Expiration, rr.Inception, rr.KeyTag, rr.SignerName, rr.Signature} -} - func (rr *RRSIG) String() string { s := rr.Hdr.String() s += Type(rr.TypeCovered).String() @@ -890,24 +771,12 @@ func (rr *RRSIG) String() string { return s } -func (rr *RRSIG) len() int { - return rr.Hdr.len() + len(rr.SignerName) + 1 + - base64.StdEncoding.DecodedLen(len(rr.Signature)) + 18 -} - type NSEC struct { Hdr RR_Header NextDomain string `dns:"domain-name"` TypeBitMap []uint16 `dns:"nsec"` } -func (rr *NSEC) Header() *RR_Header { return &rr.Hdr } -func (rr *NSEC) copy() RR { - cp := make([]uint16, len(rr.TypeBitMap), cap(rr.TypeBitMap)) - copy(cp, rr.TypeBitMap) - return &NSEC{*rr.Hdr.copyHeader(), rr.NextDomain, cp} -} - func (rr *NSEC) String() string { s := rr.Hdr.String() + sprintName(rr.NextDomain) for i := 0; i < len(rr.TypeBitMap); i++ { @@ -945,12 +814,6 @@ type DS struct { Digest string `dns:"hex"` } -func (rr *DS) Header() *RR_Header { return &rr.Hdr } -func (rr *DS) len() int { return rr.Hdr.len() + 4 + len(rr.Digest)/2 } -func (rr *DS) copy() RR { - return &DS{*rr.Hdr.copyHeader(), rr.KeyTag, rr.Algorithm, rr.DigestType, rr.Digest} -} - func (rr *DS) String() string { return rr.Hdr.String() + strconv.Itoa(int(rr.KeyTag)) + " " + strconv.Itoa(int(rr.Algorithm)) + @@ -964,10 +827,6 @@ type KX struct { Exchanger string `dns:"domain-name"` } -func (rr *KX) Header() *RR_Header { return &rr.Hdr } -func (rr *KX) len() int { return rr.Hdr.len() + 2 + len(rr.Exchanger) + 1 } -func (rr *KX) copy() RR { return &KX{*rr.Hdr.copyHeader(), rr.Preference, rr.Exchanger} } - func (rr *KX) String() string { return rr.Hdr.String() + strconv.Itoa(int(rr.Preference)) + " " + sprintName(rr.Exchanger) @@ -981,12 +840,6 @@ type TA struct { Digest string `dns:"hex"` } -func (rr *TA) Header() *RR_Header { return &rr.Hdr } -func (rr *TA) len() int { return rr.Hdr.len() + 4 + len(rr.Digest)/2 } -func (rr *TA) copy() RR { - return &TA{*rr.Hdr.copyHeader(), rr.KeyTag, rr.Algorithm, rr.DigestType, rr.Digest} -} - func (rr *TA) String() string { return rr.Hdr.String() + strconv.Itoa(int(rr.KeyTag)) + " " + strconv.Itoa(int(rr.Algorithm)) + @@ -1000,10 +853,6 @@ type TALINK struct { NextName string `dns:"domain-name"` } -func (rr *TALINK) Header() *RR_Header { return &rr.Hdr } -func (rr *TALINK) copy() RR { return &TALINK{*rr.Hdr.copyHeader(), rr.PreviousName, rr.NextName} } -func (rr *TALINK) len() int { return rr.Hdr.len() + len(rr.PreviousName) + len(rr.NextName) + 2 } - func (rr *TALINK) String() string { return rr.Hdr.String() + sprintName(rr.PreviousName) + " " + sprintName(rr.NextName) @@ -1016,12 +865,6 @@ type SSHFP struct { FingerPrint string `dns:"hex"` } -func (rr *SSHFP) Header() *RR_Header { return &rr.Hdr } -func (rr *SSHFP) len() int { return rr.Hdr.len() + 2 + len(rr.FingerPrint)/2 } -func (rr *SSHFP) copy() RR { - return &SSHFP{*rr.Hdr.copyHeader(), rr.Algorithm, rr.Type, rr.FingerPrint} -} - func (rr *SSHFP) String() string { return rr.Hdr.String() + strconv.Itoa(int(rr.Algorithm)) + " " + strconv.Itoa(int(rr.Type)) + @@ -1029,30 +872,54 @@ func (rr *SSHFP) String() string { } type IPSECKEY struct { - Hdr RR_Header - Precedence uint8 + Hdr RR_Header + Precedence uint8 + // GatewayType: 1: A record, 2: AAAA record, 3: domainname. + // 0 is use for no type and GatewayName should be "." then. GatewayType uint8 Algorithm uint8 - Gateway string `dns:"ipseckey"` + // Gateway can be an A record, AAAA record or a domain name. + GatewayA net.IP `dns:"a"` + GatewayAAAA net.IP `dns:"aaaa"` + GatewayName string `dns:"domain-name"` PublicKey string `dns:"base64"` } -func (rr *IPSECKEY) Header() *RR_Header { return &rr.Hdr } -func (rr *IPSECKEY) copy() RR { - return &IPSECKEY{*rr.Hdr.copyHeader(), rr.Precedence, rr.GatewayType, rr.Algorithm, rr.Gateway, rr.PublicKey} -} - func (rr *IPSECKEY) String() string { - return rr.Hdr.String() + strconv.Itoa(int(rr.Precedence)) + + s := rr.Hdr.String() + strconv.Itoa(int(rr.Precedence)) + " " + strconv.Itoa(int(rr.GatewayType)) + - " " + strconv.Itoa(int(rr.Algorithm)) + - " " + rr.Gateway + - " " + rr.PublicKey + " " + strconv.Itoa(int(rr.Algorithm)) + switch rr.GatewayType { + case 0: + fallthrough + case 3: + s += " " + rr.GatewayName + case 1: + s += " " + rr.GatewayA.String() + case 2: + s += " " + rr.GatewayAAAA.String() + default: + s += " ." + } + s += " " + rr.PublicKey + return s } func (rr *IPSECKEY) len() int { - return rr.Hdr.len() + 3 + len(rr.Gateway) + 1 + - base64.StdEncoding.DecodedLen(len(rr.PublicKey)) + l := rr.Hdr.len() + 3 + 1 + switch rr.GatewayType { + default: + fallthrough + case 0: + fallthrough + case 3: + l += len(rr.GatewayName) + case 1: + l += 4 + case 2: + l += 16 + } + return l + base64.StdEncoding.DecodedLen(len(rr.PublicKey)) } type KEY struct { @@ -1071,14 +938,6 @@ type DNSKEY struct { PublicKey string `dns:"base64"` } -func (rr *DNSKEY) Header() *RR_Header { return &rr.Hdr } -func (rr *DNSKEY) len() int { - return rr.Hdr.len() + 4 + base64.StdEncoding.DecodedLen(len(rr.PublicKey)) -} -func (rr *DNSKEY) copy() RR { - return &DNSKEY{*rr.Hdr.copyHeader(), rr.Flags, rr.Protocol, rr.Algorithm, rr.PublicKey} -} - func (rr *DNSKEY) String() string { return rr.Hdr.String() + strconv.Itoa(int(rr.Flags)) + " " + strconv.Itoa(int(rr.Protocol)) + @@ -1094,12 +953,6 @@ type RKEY struct { PublicKey string `dns:"base64"` } -func (rr *RKEY) Header() *RR_Header { return &rr.Hdr } -func (rr *RKEY) len() int { return rr.Hdr.len() + 4 + base64.StdEncoding.DecodedLen(len(rr.PublicKey)) } -func (rr *RKEY) copy() RR { - return &RKEY{*rr.Hdr.copyHeader(), rr.Flags, rr.Protocol, rr.Algorithm, rr.PublicKey} -} - func (rr *RKEY) String() string { return rr.Hdr.String() + strconv.Itoa(int(rr.Flags)) + " " + strconv.Itoa(int(rr.Protocol)) + @@ -1107,26 +960,12 @@ func (rr *RKEY) String() string { " " + rr.PublicKey } -type NSAP struct { - Hdr RR_Header - Length uint8 - Nsap string -} - -func (rr *NSAP) Header() *RR_Header { return &rr.Hdr } -func (rr *NSAP) copy() RR { return &NSAP{*rr.Hdr.copyHeader(), rr.Length, rr.Nsap} } -func (rr *NSAP) String() string { return rr.Hdr.String() + strconv.Itoa(int(rr.Length)) + " " + 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"` } -func (rr *NSAPPTR) Header() *RR_Header { return &rr.Hdr } -func (rr *NSAPPTR) copy() RR { return &NSAPPTR{*rr.Hdr.copyHeader(), rr.Ptr} } -func (rr *NSAPPTR) String() string { return rr.Hdr.String() + sprintName(rr.Ptr) } -func (rr *NSAPPTR) len() int { return rr.Hdr.len() + len(rr.Ptr) } +func (rr *NSAPPTR) String() string { return rr.Hdr.String() + sprintName(rr.Ptr) } type NSEC3 struct { Hdr RR_Header @@ -1140,13 +979,6 @@ type NSEC3 struct { TypeBitMap []uint16 `dns:"nsec"` } -func (rr *NSEC3) Header() *RR_Header { return &rr.Hdr } -func (rr *NSEC3) copy() RR { - cp := make([]uint16, len(rr.TypeBitMap), cap(rr.TypeBitMap)) - copy(cp, rr.TypeBitMap) - return &NSEC3{*rr.Hdr.copyHeader(), rr.Hash, rr.Flags, rr.Iterations, rr.SaltLength, rr.Salt, rr.HashLength, rr.NextDomain, cp} -} - func (rr *NSEC3) String() string { s := rr.Hdr.String() s += strconv.Itoa(int(rr.Hash)) + @@ -1182,12 +1014,6 @@ type NSEC3PARAM struct { Salt string `dns:"hex"` } -func (rr *NSEC3PARAM) Header() *RR_Header { return &rr.Hdr } -func (rr *NSEC3PARAM) len() int { return rr.Hdr.len() + 2 + 4 + 1 + len(rr.Salt)/2 } -func (rr *NSEC3PARAM) copy() RR { - return &NSEC3PARAM{*rr.Hdr.copyHeader(), rr.Hash, rr.Flags, rr.Iterations, rr.SaltLength, rr.Salt} -} - func (rr *NSEC3PARAM) String() string { s := rr.Hdr.String() s += strconv.Itoa(int(rr.Hash)) + @@ -1210,31 +1036,17 @@ type TKEY struct { OtherData string } -func (rr *TKEY) Header() *RR_Header { return &rr.Hdr } -func (rr *TKEY) copy() RR { - return &TKEY{*rr.Hdr.copyHeader(), rr.Algorithm, rr.Inception, rr.Expiration, rr.Mode, rr.Error, rr.KeySize, rr.Key, rr.OtherLen, rr.OtherData} -} - func (rr *TKEY) String() string { // It has no presentation format return "" } -func (rr *TKEY) len() int { - return rr.Hdr.len() + len(rr.Algorithm) + 1 + 4 + 4 + 6 + - len(rr.Key) + 2 + len(rr.OtherData) -} - // RFC3597 represents an unknown/generic RR. type RFC3597 struct { Hdr RR_Header Rdata string `dns:"hex"` } -func (rr *RFC3597) Header() *RR_Header { return &rr.Hdr } -func (rr *RFC3597) copy() RR { return &RFC3597{*rr.Hdr.copyHeader(), rr.Rdata} } -func (rr *RFC3597) len() int { return rr.Hdr.len() + len(rr.Rdata)/2 + 2 } - func (rr *RFC3597) String() string { // Let's call it a hack s := rfc3597Header(rr.Hdr) @@ -1257,27 +1069,12 @@ type URI struct { Hdr RR_Header Priority uint16 Weight uint16 - Target []string `dns:"txt"` -} - -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} + Target string `dns:"octet"` } 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 { @@ -1285,10 +1082,7 @@ type DHCID struct { Digest string `dns:"base64"` } -func (rr *DHCID) Header() *RR_Header { return &rr.Hdr } -func (rr *DHCID) copy() RR { return &DHCID{*rr.Hdr.copyHeader(), rr.Digest} } -func (rr *DHCID) String() string { return rr.Hdr.String() + rr.Digest } -func (rr *DHCID) len() int { return rr.Hdr.len() + base64.StdEncoding.DecodedLen(len(rr.Digest)) } +func (rr *DHCID) String() string { return rr.Hdr.String() + rr.Digest } type TLSA struct { Hdr RR_Header @@ -1298,13 +1092,6 @@ type TLSA struct { Certificate string `dns:"hex"` } -func (rr *TLSA) Header() *RR_Header { return &rr.Hdr } -func (rr *TLSA) len() int { return rr.Hdr.len() + 3 + len(rr.Certificate)/2 } - -func (rr *TLSA) copy() RR { - return &TLSA{*rr.Hdr.copyHeader(), rr.Usage, rr.Selector, rr.MatchingType, rr.Certificate} -} - func (rr *TLSA) String() string { return rr.Hdr.String() + strconv.Itoa(int(rr.Usage)) + @@ -1323,13 +1110,6 @@ type HIP struct { RendezvousServers []string `dns:"domain-name"` } -func (rr *HIP) Header() *RR_Header { return &rr.Hdr } -func (rr *HIP) copy() RR { - cp := make([]string, len(rr.RendezvousServers), cap(rr.RendezvousServers)) - copy(cp, rr.RendezvousServers) - return &HIP{*rr.Hdr.copyHeader(), rr.HitLength, rr.PublicKeyAlgorithm, rr.PublicKeyLength, rr.Hit, rr.PublicKey, cp} -} - func (rr *HIP) String() string { s := rr.Hdr.String() + strconv.Itoa(int(rr.PublicKeyAlgorithm)) + @@ -1341,38 +1121,13 @@ func (rr *HIP) String() string { return s } -func (rr *HIP) len() int { - l := rr.Hdr.len() + 4 + - len(rr.Hit)/2 + - base64.StdEncoding.DecodedLen(len(rr.PublicKey)) - for _, d := range rr.RendezvousServers { - l += len(d) + 1 - } - return l -} - type NINFO struct { Hdr RR_Header ZSData []string `dns:"txt"` } -func (rr *NINFO) Header() *RR_Header { return &rr.Hdr } -func (rr *NINFO) copy() RR { - cp := make([]string, len(rr.ZSData), cap(rr.ZSData)) - copy(cp, rr.ZSData) - return &NINFO{*rr.Hdr.copyHeader(), cp} -} - func (rr *NINFO) String() string { return rr.Hdr.String() + sprintTxt(rr.ZSData) } -func (rr *NINFO) len() int { - l := rr.Hdr.len() - for _, t := range rr.ZSData { - l += len(t) + 1 - } - return l -} - type WKS struct { Hdr RR_Header Address net.IP `dns:"a"` @@ -1380,13 +1135,9 @@ type WKS struct { BitMap []uint16 `dns:"wks"` } -func (rr *WKS) Header() *RR_Header { return &rr.Hdr } -func (rr *WKS) len() int { return rr.Hdr.len() + net.IPv4len + 1 } - -func (rr *WKS) copy() RR { - cp := make([]uint16, len(rr.BitMap), cap(rr.BitMap)) - copy(cp, rr.BitMap) - return &WKS{*rr.Hdr.copyHeader(), copyIP(rr.Address), rr.Protocol, cp} +func (rr *WKS) len() int { + // TODO: this is missing something... + return rr.Hdr.len() + net.IPv4len + 1 } func (rr *WKS) String() (s string) { @@ -1394,6 +1145,7 @@ func (rr *WKS) String() (s string) { if rr.Address != nil { s += rr.Address.String() } + // TODO(miek): missing protocol here, see /etc/protocols for i := 0; i < len(rr.BitMap); i++ { // should lookup the port s += " " + strconv.Itoa(int(rr.BitMap[i])) @@ -1407,10 +1159,6 @@ type NID struct { NodeID uint64 } -func (rr *NID) Header() *RR_Header { return &rr.Hdr } -func (rr *NID) copy() RR { return &NID{*rr.Hdr.copyHeader(), rr.Preference, rr.NodeID} } -func (rr *NID) len() int { return rr.Hdr.len() + 2 + 8 } - func (rr *NID) String() string { s := rr.Hdr.String() + strconv.Itoa(int(rr.Preference)) node := fmt.Sprintf("%0.16x", rr.NodeID) @@ -1424,10 +1172,6 @@ type L32 struct { Locator32 net.IP `dns:"a"` } -func (rr *L32) Header() *RR_Header { return &rr.Hdr } -func (rr *L32) copy() RR { return &L32{*rr.Hdr.copyHeader(), rr.Preference, copyIP(rr.Locator32)} } -func (rr *L32) len() int { return rr.Hdr.len() + net.IPv4len } - func (rr *L32) String() string { if rr.Locator32 == nil { return rr.Hdr.String() + strconv.Itoa(int(rr.Preference)) @@ -1442,10 +1186,6 @@ type L64 struct { Locator64 uint64 } -func (rr *L64) Header() *RR_Header { return &rr.Hdr } -func (rr *L64) copy() RR { return &L64{*rr.Hdr.copyHeader(), rr.Preference, rr.Locator64} } -func (rr *L64) len() int { return rr.Hdr.len() + 2 + 8 } - func (rr *L64) String() string { s := rr.Hdr.String() + strconv.Itoa(int(rr.Preference)) node := fmt.Sprintf("%0.16X", rr.Locator64) @@ -1459,10 +1199,6 @@ type LP struct { Fqdn string `dns:"domain-name"` } -func (rr *LP) Header() *RR_Header { return &rr.Hdr } -func (rr *LP) copy() RR { return &LP{*rr.Hdr.copyHeader(), rr.Preference, rr.Fqdn} } -func (rr *LP) len() int { return rr.Hdr.len() + 2 + len(rr.Fqdn) + 1 } - func (rr *LP) String() string { return rr.Hdr.String() + strconv.Itoa(int(rr.Preference)) + " " + sprintName(rr.Fqdn) } @@ -1472,23 +1208,15 @@ type EUI48 struct { Address uint64 `dns:"uint48"` } -func (rr *EUI48) Header() *RR_Header { return &rr.Hdr } -func (rr *EUI48) copy() RR { return &EUI48{*rr.Hdr.copyHeader(), rr.Address} } -func (rr *EUI48) String() string { return rr.Hdr.String() + euiToString(rr.Address, 48) } -func (rr *EUI48) len() int { return rr.Hdr.len() + 6 } +func (rr *EUI48) String() string { return rr.Hdr.String() + euiToString(rr.Address, 48) } type EUI64 struct { Hdr RR_Header Address uint64 } -func (rr *EUI64) Header() *RR_Header { return &rr.Hdr } -func (rr *EUI64) copy() RR { return &EUI64{*rr.Hdr.copyHeader(), rr.Address} } -func (rr *EUI64) String() string { return rr.Hdr.String() + euiToString(rr.Address, 64) } -func (rr *EUI64) len() int { return rr.Hdr.len() + 8 } +func (rr *EUI64) String() string { return rr.Hdr.String() + euiToString(rr.Address, 64) } -// Support in incomplete - just handle it as unknown record -/* type CAA struct { Hdr RR_Header Flag uint8 @@ -1496,78 +1224,51 @@ type CAA struct { Value string `dns:"octet"` } -func (rr *CAA) Header() *RR_Header { return &rr.Hdr } -func (rr *CAA) copy() RR { return &CAA{*rr.Hdr.copyHeader(), rr.Flag, rr.Tag, rr.Value} } -func (rr *CAA) len() int { return rr.Hdr.len() + 1 + len(rr.Tag) + 1 + len(rr.Value) } - func (rr *CAA) String() string { - s := rr.Hdr.String() + strconv.FormatInt(int64(rr.Flag), 10) + " " + rr.Tag - s += strconv.QuoteToASCII(rr.Value) - return s + return rr.Hdr.String() + strconv.Itoa(int(rr.Flag)) + " " + rr.Tag + " " + sprintTxtOctet(rr.Value) } -*/ type UID struct { Hdr RR_Header Uid uint32 } -func (rr *UID) Header() *RR_Header { return &rr.Hdr } -func (rr *UID) copy() RR { return &UID{*rr.Hdr.copyHeader(), rr.Uid} } -func (rr *UID) String() string { return rr.Hdr.String() + strconv.FormatInt(int64(rr.Uid), 10) } -func (rr *UID) len() int { return rr.Hdr.len() + 4 } +func (rr *UID) String() string { return rr.Hdr.String() + strconv.FormatInt(int64(rr.Uid), 10) } type GID struct { Hdr RR_Header Gid uint32 } -func (rr *GID) Header() *RR_Header { return &rr.Hdr } -func (rr *GID) copy() RR { return &GID{*rr.Hdr.copyHeader(), rr.Gid} } -func (rr *GID) String() string { return rr.Hdr.String() + strconv.FormatInt(int64(rr.Gid), 10) } -func (rr *GID) len() int { return rr.Hdr.len() + 4 } +func (rr *GID) String() string { return rr.Hdr.String() + strconv.FormatInt(int64(rr.Gid), 10) } type UINFO struct { Hdr RR_Header Uinfo string } -func (rr *UINFO) Header() *RR_Header { return &rr.Hdr } -func (rr *UINFO) copy() RR { return &UINFO{*rr.Hdr.copyHeader(), rr.Uinfo} } -func (rr *UINFO) String() string { return rr.Hdr.String() + sprintTxt([]string{rr.Uinfo}) } -func (rr *UINFO) len() int { return rr.Hdr.len() + len(rr.Uinfo) + 1 } +func (rr *UINFO) String() string { return rr.Hdr.String() + sprintTxt([]string{rr.Uinfo}) } type EID struct { Hdr RR_Header Endpoint string `dns:"hex"` } -func (rr *EID) Header() *RR_Header { return &rr.Hdr } -func (rr *EID) copy() RR { return &EID{*rr.Hdr.copyHeader(), rr.Endpoint} } -func (rr *EID) String() string { return rr.Hdr.String() + strings.ToUpper(rr.Endpoint) } -func (rr *EID) len() int { return rr.Hdr.len() + len(rr.Endpoint)/2 } +func (rr *EID) String() string { return rr.Hdr.String() + strings.ToUpper(rr.Endpoint) } type NIMLOC struct { Hdr RR_Header Locator string `dns:"hex"` } -func (rr *NIMLOC) Header() *RR_Header { return &rr.Hdr } -func (rr *NIMLOC) copy() RR { return &NIMLOC{*rr.Hdr.copyHeader(), rr.Locator} } -func (rr *NIMLOC) String() string { return rr.Hdr.String() + strings.ToUpper(rr.Locator) } -func (rr *NIMLOC) len() int { return rr.Hdr.len() + len(rr.Locator)/2 } +func (rr *NIMLOC) String() string { return rr.Hdr.String() + strings.ToUpper(rr.Locator) } type OPENPGPKEY struct { Hdr RR_Header PublicKey string `dns:"base64"` } -func (rr *OPENPGPKEY) Header() *RR_Header { return &rr.Hdr } -func (rr *OPENPGPKEY) copy() RR { return &OPENPGPKEY{*rr.Hdr.copyHeader(), rr.PublicKey} } -func (rr *OPENPGPKEY) String() string { return rr.Hdr.String() + rr.PublicKey } -func (rr *OPENPGPKEY) len() int { - return rr.Hdr.len() + base64.StdEncoding.DecodedLen(len(rr.PublicKey)) -} +func (rr *OPENPGPKEY) String() string { return rr.Hdr.String() + rr.PublicKey } // TimeToString translates the RRSIG's incep. and expir. times to the // string representation used when printing the record. @@ -1625,73 +1326,3 @@ func copyIP(ip net.IP) net.IP { copy(p, ip) return p } - -// Map of constructors for each RR type. -var typeToRR = map[uint16]func() RR{ - TypeA: func() RR { return new(A) }, - TypeAAAA: func() RR { return new(AAAA) }, - TypeAFSDB: func() RR { return new(AFSDB) }, - // TypeCAA: func() RR { return new(CAA) }, - TypeCDS: func() RR { return new(CDS) }, - TypeCERT: func() RR { return new(CERT) }, - TypeCNAME: func() RR { return new(CNAME) }, - TypeDHCID: func() RR { return new(DHCID) }, - TypeDLV: func() RR { return new(DLV) }, - TypeDNAME: func() RR { return new(DNAME) }, - TypeKEY: func() RR { return new(KEY) }, - TypeDNSKEY: func() RR { return new(DNSKEY) }, - TypeDS: func() RR { return new(DS) }, - TypeEUI48: func() RR { return new(EUI48) }, - TypeEUI64: func() RR { return new(EUI64) }, - TypeGID: func() RR { return new(GID) }, - TypeGPOS: func() RR { return new(GPOS) }, - TypeEID: func() RR { return new(EID) }, - TypeHINFO: func() RR { return new(HINFO) }, - TypeHIP: func() RR { return new(HIP) }, - TypeKX: func() RR { return new(KX) }, - TypeL32: func() RR { return new(L32) }, - TypeL64: func() RR { return new(L64) }, - TypeLOC: func() RR { return new(LOC) }, - TypeLP: func() RR { return new(LP) }, - TypeMB: func() RR { return new(MB) }, - TypeMD: func() RR { return new(MD) }, - TypeMF: func() RR { return new(MF) }, - TypeMG: func() RR { return new(MG) }, - TypeMINFO: func() RR { return new(MINFO) }, - TypeMR: func() RR { return new(MR) }, - TypeMX: func() RR { return new(MX) }, - TypeNAPTR: func() RR { return new(NAPTR) }, - TypeNID: func() RR { return new(NID) }, - TypeNINFO: func() RR { return new(NINFO) }, - TypeNIMLOC: func() RR { return new(NIMLOC) }, - TypeNS: func() RR { return new(NS) }, - TypeNSAP: func() RR { return new(NSAP) }, - TypeNSAPPTR: func() RR { return new(NSAPPTR) }, - TypeNSEC3: func() RR { return new(NSEC3) }, - TypeNSEC3PARAM: func() RR { return new(NSEC3PARAM) }, - TypeNSEC: func() RR { return new(NSEC) }, - TypeOPENPGPKEY: func() RR { return new(OPENPGPKEY) }, - TypeOPT: func() RR { return new(OPT) }, - TypePTR: func() RR { return new(PTR) }, - TypeRKEY: func() RR { return new(RKEY) }, - TypeRP: func() RR { return new(RP) }, - TypePX: func() RR { return new(PX) }, - TypeSIG: func() RR { return new(SIG) }, - TypeRRSIG: func() RR { return new(RRSIG) }, - TypeRT: func() RR { return new(RT) }, - TypeSOA: func() RR { return new(SOA) }, - TypeSPF: func() RR { return new(SPF) }, - TypeSRV: func() RR { return new(SRV) }, - TypeSSHFP: func() RR { return new(SSHFP) }, - TypeTA: func() RR { return new(TA) }, - TypeTALINK: func() RR { return new(TALINK) }, - TypeTKEY: func() RR { return new(TKEY) }, - TypeTLSA: func() RR { return new(TLSA) }, - TypeTSIG: func() RR { return new(TSIG) }, - TypeTXT: func() RR { return new(TXT) }, - TypeUID: func() RR { return new(UID) }, - TypeUINFO: func() RR { return new(UINFO) }, - TypeURI: func() RR { return new(URI) }, - TypeWKS: func() RR { return new(WKS) }, - TypeX25: func() RR { return new(X25) }, -} diff --git a/vendor/github.com/miekg/dns/types_generate.go b/vendor/github.com/miekg/dns/types_generate.go new file mode 100644 index 00000000000..b8d1cd26b0c --- /dev/null +++ b/vendor/github.com/miekg/dns/types_generate.go @@ -0,0 +1,266 @@ +//+build ignore + +// types_generate.go is meant to run with go generate. It will use +// go/{importer,types} to track down all the RR struct types. Then for each type +// it will generate conversion tables (TypeToRR and TypeToString) and banal +// methods (len, Header, copy) based on the struct tags. The generated source is +// written to ztypes.go, and is meant to be checked into git. +package main + +import ( + "bytes" + "fmt" + "go/format" + "go/importer" + "go/types" + "log" + "os" + "strings" + "text/template" +) + +var skipLen = map[string]struct{}{ + "NSEC": {}, + "NSEC3": {}, + "OPT": {}, + "WKS": {}, + "IPSECKEY": {}, +} + +var packageHdr = ` +// *** DO NOT MODIFY *** +// AUTOGENERATED BY go generate + +package dns + +import ( + "encoding/base64" + "net" +) + +` + +var TypeToRR = template.Must(template.New("TypeToRR").Parse(` +// TypeToRR is a map of constructors for each RR type. +var TypeToRR = map[uint16]func() RR{ +{{range .}}{{if ne . "RFC3597"}} Type{{.}}: func() RR { return new({{.}}) }, +{{end}}{{end}} } + +`)) + +var typeToString = template.Must(template.New("typeToString").Parse(` +// TypeToString is a map of strings for each RR type. +var TypeToString = map[uint16]string{ +{{range .}}{{if ne . "NSAPPTR"}} Type{{.}}: "{{.}}", +{{end}}{{end}} TypeNSAPPTR: "NSAP-PTR", +} + +`)) + +var headerFunc = template.Must(template.New("headerFunc").Parse(` +// Header() functions +{{range .}} func (rr *{{.}}) Header() *RR_Header { return &rr.Hdr } +{{end}} + +`)) + +// getTypeStruct will take a type and the package scope, and return the +// (innermost) struct if the type is considered a RR type (currently defined as +// those structs beginning with a RR_Header, could be redefined as implementing +// the RR interface). The bool return value indicates if embedded structs were +// resolved. +func getTypeStruct(t types.Type, scope *types.Scope) (*types.Struct, bool) { + st, ok := t.Underlying().(*types.Struct) + if !ok { + return nil, false + } + if st.Field(0).Type() == scope.Lookup("RR_Header").Type() { + return st, false + } + if st.Field(0).Anonymous() { + st, _ := getTypeStruct(st.Field(0).Type(), scope) + return st, true + } + return nil, false +} + +func main() { + // Import and type-check the package + pkg, err := importer.Default().Import("github.com/miekg/dns") + fatalIfErr(err) + scope := pkg.Scope() + + // Collect constants like TypeX + var numberedTypes []string + for _, name := range scope.Names() { + o := scope.Lookup(name) + if o == nil || !o.Exported() { + continue + } + b, ok := o.Type().(*types.Basic) + if !ok || b.Kind() != types.Uint16 { + continue + } + if !strings.HasPrefix(o.Name(), "Type") { + continue + } + name := strings.TrimPrefix(o.Name(), "Type") + if name == "PrivateRR" { + continue + } + numberedTypes = append(numberedTypes, name) + } + + // Collect actual types (*X) + var namedTypes []string + for _, name := range scope.Names() { + o := scope.Lookup(name) + if o == nil || !o.Exported() { + continue + } + if st, _ := getTypeStruct(o.Type(), scope); st == nil { + continue + } + if name == "PrivateRR" { + continue + } + + // Check if corresponding TypeX exists + if scope.Lookup("Type"+o.Name()) == nil && o.Name() != "RFC3597" { + log.Fatalf("Constant Type%s does not exist.", o.Name()) + } + + namedTypes = append(namedTypes, o.Name()) + } + + b := &bytes.Buffer{} + b.WriteString(packageHdr) + + // Generate TypeToRR + fatalIfErr(TypeToRR.Execute(b, namedTypes)) + + // Generate typeToString + fatalIfErr(typeToString.Execute(b, numberedTypes)) + + // Generate headerFunc + fatalIfErr(headerFunc.Execute(b, namedTypes)) + + // Generate len() + fmt.Fprint(b, "// len() functions\n") + for _, name := range namedTypes { + if _, ok := skipLen[name]; ok { + continue + } + o := scope.Lookup(name) + st, isEmbedded := getTypeStruct(o.Type(), scope) + if isEmbedded { + continue + } + fmt.Fprintf(b, "func (rr *%s) len() int {\n", name) + fmt.Fprintf(b, "l := rr.Hdr.len()\n") + for i := 1; i < st.NumFields(); i++ { + o := func(s string) { fmt.Fprintf(b, s, st.Field(i).Name()) } + + if _, ok := st.Field(i).Type().(*types.Slice); ok { + switch st.Tag(i) { + case `dns:"-"`: + // ignored + case `dns:"cdomain-name"`, `dns:"domain-name"`, `dns:"txt"`: + o("for _, x := range rr.%s { l += len(x) + 1 }\n") + default: + log.Fatalln(name, st.Field(i).Name(), st.Tag(i)) + } + continue + } + + switch st.Tag(i) { + case `dns:"-"`: + // ignored + case `dns:"cdomain-name"`, `dns:"domain-name"`: + o("l += len(rr.%s) + 1\n") + case `dns:"octet"`: + o("l += len(rr.%s)\n") + case `dns:"base64"`: + o("l += base64.StdEncoding.DecodedLen(len(rr.%s))\n") + case `dns:"size-hex"`, `dns:"hex"`: + o("l += len(rr.%s)/2 + 1\n") + case `dns:"a"`: + o("l += net.IPv4len // %s\n") + case `dns:"aaaa"`: + o("l += net.IPv6len // %s\n") + case `dns:"txt"`: + o("for _, t := range rr.%s { l += len(t) + 1 }\n") + case `dns:"uint48"`: + o("l += 6 // %s\n") + case "": + switch st.Field(i).Type().(*types.Basic).Kind() { + case types.Uint8: + o("l += 1 // %s\n") + case types.Uint16: + o("l += 2 // %s\n") + case types.Uint32: + o("l += 4 // %s\n") + case types.Uint64: + o("l += 8 // %s\n") + case types.String: + o("l += len(rr.%s) + 1\n") + default: + log.Fatalln(name, st.Field(i).Name()) + } + default: + log.Fatalln(name, st.Field(i).Name(), st.Tag(i)) + } + } + fmt.Fprintf(b, "return l }\n") + } + + // Generate copy() + fmt.Fprint(b, "// copy() functions\n") + for _, name := range namedTypes { + o := scope.Lookup(name) + st, isEmbedded := getTypeStruct(o.Type(), scope) + if isEmbedded { + continue + } + fmt.Fprintf(b, "func (rr *%s) copy() RR {\n", name) + fields := []string{"*rr.Hdr.copyHeader()"} + for i := 1; i < st.NumFields(); i++ { + f := st.Field(i).Name() + if sl, ok := st.Field(i).Type().(*types.Slice); ok { + t := sl.Underlying().String() + t = strings.TrimPrefix(t, "[]") + t = strings.TrimPrefix(t, "github.com/miekg/dns.") + fmt.Fprintf(b, "%s := make([]%s, len(rr.%s)); copy(%s, rr.%s)\n", + f, t, f, f, f) + fields = append(fields, f) + continue + } + if st.Field(i).Type().String() == "net.IP" { + fields = append(fields, "copyIP(rr."+f+")") + continue + } + fields = append(fields, "rr."+f) + } + fmt.Fprintf(b, "return &%s{%s}\n", name, strings.Join(fields, ",")) + fmt.Fprintf(b, "}\n") + } + + // gofmt + res, err := format.Source(b.Bytes()) + if err != nil { + b.WriteTo(os.Stderr) + log.Fatal(err) + } + + // write result + f, err := os.Create("ztypes.go") + fatalIfErr(err) + defer f.Close() + f.Write(res) +} + +func fatalIfErr(err error) { + if err != nil { + log.Fatal(err) + } +} diff --git a/vendor/github.com/miekg/dns/udp.go b/vendor/github.com/miekg/dns/udp.go index 0342543bf73..c79c6c88371 100644 --- a/vendor/github.com/miekg/dns/udp.go +++ b/vendor/github.com/miekg/dns/udp.go @@ -1,4 +1,4 @@ -// +build !windows +// +build !windows,!plan9 package dns @@ -7,12 +7,15 @@ import ( "syscall" ) -type sessionUDP struct { +// SessionUDP holds the remote address and the associated +// out-of-band data. +type SessionUDP struct { raddr *net.UDPAddr context []byte } -func (s *sessionUDP) RemoteAddr() net.Addr { return s.raddr } +// RemoteAddr returns the remote network address. +func (s *SessionUDP) RemoteAddr() net.Addr { return s.raddr } // setUDPSocketOptions sets the UDP socket options. // This function is implemented on a per platform basis. See udp_*.go for more details @@ -37,19 +40,19 @@ func setUDPSocketOptions(conn *net.UDPConn) error { return nil } -// readFromSessionUDP acts just like net.UDPConn.ReadFrom(), but returns a session object instead of a +// ReadFromSessionUDP acts just like net.UDPConn.ReadFrom(), but returns a session object instead of a // net.UDPAddr. -func readFromSessionUDP(conn *net.UDPConn, b []byte) (int, *sessionUDP, error) { +func ReadFromSessionUDP(conn *net.UDPConn, b []byte) (int, *SessionUDP, error) { oob := make([]byte, 40) n, oobn, _, raddr, err := conn.ReadMsgUDP(b, oob) if err != nil { return n, nil, err } - return n, &sessionUDP{raddr, oob[:oobn]}, err + return n, &SessionUDP{raddr, oob[:oobn]}, err } -// writeToSessionUDP acts just like net.UDPConn.WritetTo(), but uses a *sessionUDP instead of a net.Addr. -func writeToSessionUDP(conn *net.UDPConn, b []byte, session *sessionUDP) (int, error) { +// WriteToSessionUDP acts just like net.UDPConn.WritetTo(), but uses a *SessionUDP instead of a net.Addr. +func WriteToSessionUDP(conn *net.UDPConn, b []byte, session *SessionUDP) (int, error) { n, _, err := conn.WriteMsgUDP(b, session.context, session.raddr) return n, err } diff --git a/vendor/github.com/miekg/dns/udp_linux.go b/vendor/github.com/miekg/dns/udp_linux.go index 7a107857e13..c62d21881b6 100644 --- a/vendor/github.com/miekg/dns/udp_linux.go +++ b/vendor/github.com/miekg/dns/udp_linux.go @@ -24,6 +24,12 @@ func setUDPSocketOptions4(conn *net.UDPConn) error { if err := syscall.SetsockoptInt(int(file.Fd()), syscall.IPPROTO_IP, syscall.IP_PKTINFO, 1); err != nil { return err } + // Calling File() above results in the connection becoming blocking, we must fix that. + // See https://github.com/miekg/dns/issues/279 + err = syscall.SetNonblock(int(file.Fd()), true) + if err != nil { + return err + } return nil } @@ -36,6 +42,10 @@ func setUDPSocketOptions6(conn *net.UDPConn) error { if err := syscall.SetsockoptInt(int(file.Fd()), syscall.IPPROTO_IPV6, syscall.IPV6_RECVPKTINFO, 1); err != nil { return err } + err = syscall.SetNonblock(int(file.Fd()), true) + if err != nil { + return err + } return nil } diff --git a/vendor/github.com/miekg/dns/udp_other.go b/vendor/github.com/miekg/dns/udp_other.go index c38dd3e7f0e..d40732441b0 100644 --- a/vendor/github.com/miekg/dns/udp_other.go +++ b/vendor/github.com/miekg/dns/udp_other.go @@ -1,4 +1,4 @@ -// +build !linux +// +build !linux,!plan9 package dns diff --git a/vendor/github.com/miekg/dns/udp_plan9.go b/vendor/github.com/miekg/dns/udp_plan9.go new file mode 100644 index 00000000000..b794deeba0f --- /dev/null +++ b/vendor/github.com/miekg/dns/udp_plan9.go @@ -0,0 +1,34 @@ +package dns + +import ( + "net" +) + +func setUDPSocketOptions(conn *net.UDPConn) error { return nil } + +// SessionUDP holds the remote address and the associated +// out-of-band data. +type SessionUDP struct { + raddr *net.UDPAddr + context []byte +} + +// RemoteAddr returns the remote network address. +func (s *SessionUDP) RemoteAddr() net.Addr { return s.raddr } + +// ReadFromSessionUDP acts just like net.UDPConn.ReadFrom(), but returns a session object instead of a +// net.UDPAddr. +func ReadFromSessionUDP(conn *net.UDPConn, b []byte) (int, *SessionUDP, error) { + oob := make([]byte, 40) + n, oobn, _, raddr, err := conn.ReadMsgUDP(b, oob) + if err != nil { + return n, nil, err + } + return n, &SessionUDP{raddr, oob[:oobn]}, err +} + +// WriteToSessionUDP acts just like net.UDPConn.WritetTo(), but uses a *SessionUDP instead of a net.Addr. +func WriteToSessionUDP(conn *net.UDPConn, b []byte, session *SessionUDP) (int, error) { + n, _, err := conn.WriteMsgUDP(b, session.context, session.raddr) + return n, err +} diff --git a/vendor/github.com/miekg/dns/udp_windows.go b/vendor/github.com/miekg/dns/udp_windows.go index 4c48723b565..2ce4b330028 100644 --- a/vendor/github.com/miekg/dns/udp_windows.go +++ b/vendor/github.com/miekg/dns/udp_windows.go @@ -4,28 +4,28 @@ package dns import "net" -type sessionUDP struct { +type SessionUDP struct { raddr *net.UDPAddr } -// readFromSessionUDP acts just like net.UDPConn.ReadFrom(), but returns a session object instead of a +// ReadFromSessionUDP acts just like net.UDPConn.ReadFrom(), but returns a session object instead of a // net.UDPAddr. -func readFromSessionUDP(conn *net.UDPConn, b []byte) (int, *sessionUDP, error) { +func ReadFromSessionUDP(conn *net.UDPConn, b []byte) (int, *SessionUDP, error) { n, raddr, err := conn.ReadFrom(b) if err != nil { return n, nil, err } - session := &sessionUDP{raddr.(*net.UDPAddr)} + session := &SessionUDP{raddr.(*net.UDPAddr)} return n, session, err } -// writeToSessionUDP acts just like net.UDPConn.WritetTo(), but uses a *sessionUDP instead of a net.Addr. -func writeToSessionUDP(conn *net.UDPConn, b []byte, session *sessionUDP) (int, error) { +// WriteToSessionUDP acts just like net.UDPConn.WritetTo(), but uses a *SessionUDP instead of a net.Addr. +func WriteToSessionUDP(conn *net.UDPConn, b []byte, session *SessionUDP) (int, error) { n, err := conn.WriteTo(b, session.raddr) return n, err } -func (s *sessionUDP) RemoteAddr() net.Addr { return s.raddr } +func (s *SessionUDP) RemoteAddr() net.Addr { return s.raddr } // setUDPSocketOptions sets the UDP socket options. // This function is implemented on a per platform basis. See udp_*.go for more details diff --git a/vendor/github.com/miekg/dns/update.go b/vendor/github.com/miekg/dns/update.go index 275d4e6cc27..e90c5c968ec 100644 --- a/vendor/github.com/miekg/dns/update.go +++ b/vendor/github.com/miekg/dns/update.go @@ -1,55 +1,24 @@ -// DYNAMIC UPDATES -// -// Dynamic updates reuses the DNS message format, but renames three of -// the sections. Question is Zone, Answer is Prerequisite, Authority is -// Update, only the Additional is not renamed. See RFC 2136 for the gory details. -// -// You can set a rather complex set of rules for the existence of absence of -// certain resource records or names in a zone to specify if resource records -// should be added or removed. The table from RFC 2136 supplemented with the Go -// DNS function shows which functions exist to specify the prerequisites. -// -// 3.2.4 - Table Of Metavalues Used In Prerequisite Section -// -// CLASS TYPE RDATA Meaning Function -// -------------------------------------------------------------- -// ANY ANY empty Name is in use dns.NameUsed -// ANY rrset empty RRset exists (value indep) dns.RRsetUsed -// NONE ANY empty Name is not in use dns.NameNotUsed -// NONE rrset empty RRset does not exist dns.RRsetNotUsed -// zone rrset rr RRset exists (value dep) dns.Used -// -// The prerequisite section can also be left empty. -// If you have decided on the prerequisites you can tell what RRs should -// be added or deleted. The next table shows the options you have and -// what functions to call. -// -// 3.4.2.6 - Table Of Metavalues Used In Update Section -// -// CLASS TYPE RDATA Meaning Function -// --------------------------------------------------------------- -// ANY ANY empty Delete all RRsets from name dns.RemoveName -// ANY rrset empty Delete an RRset dns.RemoveRRset -// NONE rrset rr Delete an RR from RRset dns.Remove -// zone rrset rr Add to an RRset dns.Insert -// package dns // NameUsed sets the RRs in the prereq section to // "Name is in use" RRs. RFC 2136 section 2.4.4. func (u *Msg) NameUsed(rr []RR) { - u.Answer = make([]RR, len(rr)) - for i, r := range rr { - u.Answer[i] = &ANY{Hdr: RR_Header{Name: r.Header().Name, Ttl: 0, Rrtype: TypeANY, Class: ClassANY}} + if u.Answer == nil { + u.Answer = make([]RR, 0, len(rr)) + } + for _, r := range rr { + u.Answer = append(u.Answer, &ANY{Hdr: RR_Header{Name: r.Header().Name, Ttl: 0, Rrtype: TypeANY, Class: ClassANY}}) } } // NameNotUsed sets the RRs in the prereq section to // "Name is in not use" RRs. RFC 2136 section 2.4.5. func (u *Msg) NameNotUsed(rr []RR) { - u.Answer = make([]RR, len(rr)) - for i, r := range rr { - u.Answer[i] = &ANY{Hdr: RR_Header{Name: r.Header().Name, Ttl: 0, Rrtype: TypeANY, Class: ClassNONE}} + if u.Answer == nil { + u.Answer = make([]RR, 0, len(rr)) + } + for _, r := range rr { + u.Answer = append(u.Answer, &ANY{Hdr: RR_Header{Name: r.Header().Name, Ttl: 0, Rrtype: TypeANY, Class: ClassNONE}}) } } @@ -59,34 +28,34 @@ func (u *Msg) Used(rr []RR) { if len(u.Question) == 0 { panic("dns: empty question section") } - u.Answer = make([]RR, len(rr)) - for i, r := range rr { - u.Answer[i] = r - u.Answer[i].Header().Class = u.Question[0].Qclass + if u.Answer == nil { + u.Answer = make([]RR, 0, len(rr)) + } + for _, r := range rr { + r.Header().Class = u.Question[0].Qclass + u.Answer = append(u.Answer, r) } } // RRsetUsed sets the RRs in the prereq section to // "RRset exists (value independent -- no rdata)" RRs. RFC 2136 section 2.4.1. func (u *Msg) RRsetUsed(rr []RR) { - u.Answer = make([]RR, len(rr)) - for i, r := range rr { - u.Answer[i] = r - u.Answer[i].Header().Class = ClassANY - u.Answer[i].Header().Ttl = 0 - u.Answer[i].Header().Rdlength = 0 + if u.Answer == nil { + u.Answer = make([]RR, 0, len(rr)) + } + for _, r := range rr { + u.Answer = append(u.Answer, &ANY{Hdr: RR_Header{Name: r.Header().Name, Ttl: 0, Rrtype: r.Header().Rrtype, Class: ClassANY}}) } } // RRsetNotUsed sets the RRs in the prereq section to // "RRset does not exist" RRs. RFC 2136 section 2.4.3. func (u *Msg) RRsetNotUsed(rr []RR) { - u.Answer = make([]RR, len(rr)) - for i, r := range rr { - u.Answer[i] = r - u.Answer[i].Header().Class = ClassNONE - u.Answer[i].Header().Rdlength = 0 - u.Answer[i].Header().Ttl = 0 + if u.Answer == nil { + u.Answer = make([]RR, 0, len(rr)) + } + for _, r := range rr { + u.Answer = append(u.Answer, &ANY{Hdr: RR_Header{Name: r.Header().Name, Ttl: 0, Rrtype: r.Header().Rrtype, Class: ClassNONE}}) } } @@ -95,44 +64,43 @@ func (u *Msg) Insert(rr []RR) { if len(u.Question) == 0 { panic("dns: empty question section") } - u.Ns = make([]RR, len(rr)) - for i, r := range rr { - u.Ns[i] = r - u.Ns[i].Header().Class = u.Question[0].Qclass + if u.Ns == nil { + u.Ns = make([]RR, 0, len(rr)) + } + for _, r := range rr { + r.Header().Class = u.Question[0].Qclass + u.Ns = append(u.Ns, r) } } // RemoveRRset creates a dynamic update packet that deletes an RRset, see RFC 2136 section 2.5.2. func (u *Msg) RemoveRRset(rr []RR) { - m := make(map[RR_Header]struct{}) - u.Ns = make([]RR, 0, len(rr)) + if u.Ns == nil { + u.Ns = make([]RR, 0, len(rr)) + } for _, r := range rr { - h := *r.Header().copyHeader() - h.Class = ClassANY - h.Ttl = 0 - h.Rdlength = 0 - if _, ok := m[h]; ok { - continue - } - m[h] = struct{}{} - u.Ns = append(u.Ns, &ANY{h}) + u.Ns = append(u.Ns, &ANY{Hdr: RR_Header{Name: r.Header().Name, Ttl: 0, Rrtype: r.Header().Rrtype, Class: ClassANY}}) } } // RemoveName creates a dynamic update packet that deletes all RRsets of a name, see RFC 2136 section 2.5.3 func (u *Msg) RemoveName(rr []RR) { - u.Ns = make([]RR, len(rr)) - for i, r := range rr { - u.Ns[i] = &ANY{Hdr: RR_Header{Name: r.Header().Name, Ttl: 0, Rrtype: TypeANY, Class: ClassANY}} + if u.Ns == nil { + u.Ns = make([]RR, 0, len(rr)) + } + for _, r := range rr { + u.Ns = append(u.Ns, &ANY{Hdr: RR_Header{Name: r.Header().Name, Ttl: 0, Rrtype: TypeANY, Class: ClassANY}}) } } -// Remove creates a dynamic update packet deletes RR from the RRSset, see RFC 2136 section 2.5.4 +// Remove creates a dynamic update packet deletes RR from a RRSset, see RFC 2136 section 2.5.4 func (u *Msg) Remove(rr []RR) { - u.Ns = make([]RR, len(rr)) - for i, r := range rr { - u.Ns[i] = r - u.Ns[i].Header().Class = ClassNONE - u.Ns[i].Header().Ttl = 0 + if u.Ns == nil { + u.Ns = make([]RR, 0, len(rr)) + } + for _, r := range rr { + r.Header().Class = ClassNONE + r.Header().Ttl = 0 + u.Ns = append(u.Ns, r) } } diff --git a/vendor/github.com/miekg/dns/xfr.go b/vendor/github.com/miekg/dns/xfr.go index 57bfb1676f9..7d3a67b8e45 100644 --- a/vendor/github.com/miekg/dns/xfr.go +++ b/vendor/github.com/miekg/dns/xfr.go @@ -13,9 +13,9 @@ type Envelope struct { // A Transfer defines parameters that are used during a zone transfer. type Transfer struct { *Conn - DialTimeout time.Duration // net.DialTimeout (ns), defaults to 2 * 1e9 - ReadTimeout time.Duration // net.Conn.SetReadTimeout value for connections (ns), defaults to 2 * 1e9 - WriteTimeout time.Duration // net.Conn.SetWriteTimeout value for connections (ns), defaults to 2 * 1e9 + DialTimeout time.Duration // net.DialTimeout, defaults to 2 seconds + ReadTimeout time.Duration // net.Conn.SetReadTimeout value for connections, defaults to 2 seconds + WriteTimeout time.Duration // net.Conn.SetWriteTimeout value for connections, defaults to 2 seconds TsigSecret map[string]string // Secret(s) for Tsig map[], zonename must be fully qualified tsigTimersOnly bool } @@ -23,14 +23,26 @@ type Transfer struct { // Think we need to away to stop the transfer // In performs an incoming transfer with the server in a. +// If you would like to set the source IP, or some other attribute +// of a Dialer for a Transfer, you can do so by specifying the attributes +// in the Transfer.Conn: +// +// d := net.Dialer{LocalAddr: transfer_source} +// con, err := d.Dial("tcp", master) +// dnscon := &dns.Conn{Conn:con} +// transfer = &dns.Transfer{Conn: dnscon} +// channel, err := transfer.In(message, master) +// func (t *Transfer) In(q *Msg, a string) (env chan *Envelope, err error) { timeout := dnsTimeout if t.DialTimeout != 0 { timeout = t.DialTimeout } - t.Conn, err = DialTimeout("tcp", a, timeout) - if err != nil { - return nil, err + if t.Conn == nil { + t.Conn, err = DialTimeout("tcp", a, timeout) + if err != nil { + return nil, err + } } if err := t.WriteMsg(q); err != nil { return nil, err @@ -91,7 +103,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) { @@ -107,7 +118,7 @@ func (t *Transfer) inIxfr(id uint16, c chan *Envelope) { t.SetReadDeadline(time.Now().Add(timeout)) in, err := t.ReadMsg() if err != nil { - c <- &Envelope{in.Answer, err} + c <- &Envelope{nil, err} return } if id != in.Id { @@ -160,22 +171,18 @@ func (t *Transfer) inIxfr(id uint16, c chan *Envelope) { // The server is responsible for sending the correct sequence of RRs through the // channel ch. func (t *Transfer) Out(w ResponseWriter, q *Msg, ch chan *Envelope) error { - r := new(Msg) - // Compress? - r.SetReply(q) - r.Authoritative = true - - go func() { - for x := range ch { - // assume it fits TODO(miek): fix - r.Answer = append(r.Answer, x.RR...) - if err := w.WriteMsg(r); err != nil { - return - } + for x := range ch { + r := new(Msg) + // Compress? + r.SetReply(q) + r.Authoritative = true + // assume it fits TODO(miek): fix + r.Answer = append(r.Answer, x.RR...) + if err := w.WriteMsg(r); err != nil { + return err } - w.TsigTimersOnly(true) - r.Answer = nil - }() + } + w.TsigTimersOnly(true) return nil } @@ -197,6 +204,7 @@ func (t *Transfer) ReadMsg() (*Msg, error) { } // Need to work on the original message p, as that was used to calculate the tsig. err = TsigVerify(p, t.TsigSecret[ts.Hdr.Name], t.tsigRequestMAC, t.tsigTimersOnly) + t.tsigRequestMAC = ts.MAC } return m, err } diff --git a/vendor/github.com/miekg/dns/zgenerate.go b/vendor/github.com/miekg/dns/zgenerate.go index 7f1183e8740..ce7b540a5d8 100644 --- a/vendor/github.com/miekg/dns/zgenerate.go +++ b/vendor/github.com/miekg/dns/zgenerate.go @@ -1,6 +1,7 @@ package dns import ( + "bytes" "fmt" "strconv" "strings" @@ -14,7 +15,7 @@ import ( // * [[ttl][class]] // * type // * rhs (rdata) -// But we are lazy here, only the range is parsed *all* occurences +// But we are lazy here, only the range is parsed *all* occurrences // of $ after that are interpreted. // Any error are returned as a string value, the empty string signals // "no error". @@ -24,13 +25,13 @@ func generate(l lex, c chan lex, t chan *Token, o string) string { if i+1 == len(l.token) { return "bad step in $GENERATE range" } - if s, e := strconv.Atoi(l.token[i+1:]); e != nil { - return "bad step in $GENERATE range" - } else { + if s, e := strconv.Atoi(l.token[i+1:]); e == nil { if s < 0 { return "bad step in $GENERATE range" } step = s + } else { + return "bad step in $GENERATE range" } l.token = l.token[:i] } @@ -46,7 +47,7 @@ func generate(l lex, c chan lex, t chan *Token, o string) string { if err != nil { return "bad stop in $GENERATE range" } - if end < 0 || start < 0 || end <= start { + if end < 0 || start < 0 || end < start { return "bad range in $GENERATE range" } @@ -55,14 +56,14 @@ func generate(l lex, c chan lex, t chan *Token, o string) string { s := "" BuildRR: l = <-c - if l.value != _NEWLINE && l.value != _EOF { + if l.value != zNewline && l.value != zEOF { s += l.token goto BuildRR } for i := start; i <= end; i += step { var ( escape bool - dom string + dom bytes.Buffer mod string err string offset int @@ -72,7 +73,7 @@ BuildRR: switch s[j] { case '\\': if escape { - dom += "\\" + dom.WriteByte('\\') escape = false continue } @@ -81,17 +82,17 @@ BuildRR: mod = "%d" offset = 0 if escape { - dom += "$" + dom.WriteByte('$') escape = false continue } escape = false if j+1 >= len(s) { // End of the string - dom += fmt.Sprintf(mod, i+offset) + dom.WriteString(fmt.Sprintf(mod, i+offset)) continue } else { if s[j+1] == '$' { - dom += "$" + dom.WriteByte('$') j++ continue } @@ -108,17 +109,17 @@ BuildRR: } j += 2 + sep // Jump to it } - dom += fmt.Sprintf(mod, i+offset) + dom.WriteString(fmt.Sprintf(mod, i+offset)) default: if escape { // Pretty useless here escape = false continue } - dom += string(s[j]) + dom.WriteByte(s[j]) } } // Re-parse the RR and send it on the current channel t - rx, e := NewRR("$ORIGIN " + o + "\n" + dom) + rx, e := NewRR("$ORIGIN " + o + "\n" + dom.String()) if e != nil { return e.(*ParseError).err } @@ -140,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/vendor/github.com/miekg/dns/zscan.go b/vendor/github.com/miekg/dns/zscan.go index 7ba51986953..5c10fbaaaaf 100644 --- a/vendor/github.com/miekg/dns/zscan.go +++ b/vendor/github.com/miekg/dns/zscan.go @@ -29,45 +29,45 @@ const maxUint16 = 1<<16 - 1 // * Handle braces - anywhere. const ( // Zonefile - _EOF = iota - _STRING - _BLANK - _QUOTE - _NEWLINE - _RRTYPE - _OWNER - _CLASS - _DIRORIGIN // $ORIGIN - _DIRTTL // $TTL - _DIRINCLUDE // $INCLUDE - _DIRGENERATE // $GENERATE + zEOF = iota + zString + zBlank + zQuote + zNewline + zRrtpe + zOwner + zClass + zDirOrigin // $ORIGIN + zDirTtl // $TTL + zDirInclude // $INCLUDE + zDirGenerate // $GENERATE // Privatekey file - _VALUE - _KEY + zValue + zKey - _EXPECT_OWNER_DIR // Ownername - _EXPECT_OWNER_BL // Whitespace after the ownername - _EXPECT_ANY // Expect rrtype, ttl or class - _EXPECT_ANY_NOCLASS // Expect rrtype or ttl - _EXPECT_ANY_NOCLASS_BL // The whitespace after _EXPECT_ANY_NOCLASS - _EXPECT_ANY_NOTTL // Expect rrtype or class - _EXPECT_ANY_NOTTL_BL // Whitespace after _EXPECT_ANY_NOTTL - _EXPECT_RRTYPE // Expect rrtype - _EXPECT_RRTYPE_BL // Whitespace BEFORE rrtype - _EXPECT_RDATA // The first element of the rdata - _EXPECT_DIRTTL_BL // Space after directive $TTL - _EXPECT_DIRTTL // Directive $TTL - _EXPECT_DIRORIGIN_BL // Space after directive $ORIGIN - _EXPECT_DIRORIGIN // Directive $ORIGIN - _EXPECT_DIRINCLUDE_BL // Space after directive $INCLUDE - _EXPECT_DIRINCLUDE // Directive $INCLUDE - _EXPECT_DIRGENERATE // Directive $GENERATE - _EXPECT_DIRGENERATE_BL // Space after directive $GENERATE + zExpectOwnerDir // Ownername + zExpectOwnerBl // Whitespace after the ownername + zExpectAny // Expect rrtype, ttl or class + zExpectAnyNoClass // Expect rrtype or ttl + zExpectAnyNoClassBl // The whitespace after _EXPECT_ANY_NOCLASS + zExpectAnyNoTtl // Expect rrtype or class + zExpectAnyNoTtlBl // Whitespace after _EXPECT_ANY_NOTTL + zExpectRrtype // Expect rrtype + zExpectRrtypeBl // Whitespace BEFORE rrtype + zExpectRdata // The first element of the rdata + zExpectDirTtlBl // Space after directive $TTL + zExpectDirTtl // Directive $TTL + zExpectDirOriginBl // Space after directive $ORIGIN + zExpectDirOrigin // Directive $ORIGIN + zExpectDirIncludeBl // Space after directive $INCLUDE + zExpectDirInclude // Directive $INCLUDE + zExpectDirGenerate // Directive $GENERATE + zExpectDirGenerateBl // Space after directive $GENERATE ) // ParseError is a parsing error. It contains the parse error and the location in the io.Reader -// where the error occured. +// where the error occurred. type ParseError struct { file string err string @@ -86,28 +86,32 @@ func (e *ParseError) Error() (s string) { type lex struct { token string // text of the token tokenUpper string // uppercase text of the token - length int // lenght of the token + length int // length of the token err bool // when true, token text has lexer error - value uint8 // value: _STRING, _BLANK, etc. + value uint8 // value: zString, _BLANK, etc. line int // line in the file column int // column in the file torc uint16 // type or class as parsed in the lexer, we only need to look this up in the grammar comment string // any comment text seen } -// *Tokens are returned when a zone file is parsed. +// Token holds the token that are returned when a zone file is parsed. type Token struct { - RR // the scanned resource record when error is not nil - Error *ParseError // when an error occured, this has the error specifics - Comment string // a potential comment positioned after the RR and on the same line + // The scanned resource record when error is not nil. + RR + // When an error occurred, this has the error specifics. + Error *ParseError + // A potential comment positioned after the RR and on the same line. + Comment string } -// NewRR reads the RR contained in the string s. Only the first RR is returned. -// The class defaults to IN and TTL defaults to 3600. The full zone file -// syntax like $TTL, $ORIGIN, etc. is supported. -// All fields of the returned RR are set, except RR.Header().Rdlength which is set to 0. +// NewRR reads the RR contained in the string s. Only the first RR is +// returned. If s contains no RR, return nil with no error. The class +// defaults to IN and TTL defaults to 3600. The full zone file syntax +// like $TTL, $ORIGIN, etc. is supported. All fields of the returned +// RR are set, except RR.Header().Rdlength which is set to 0. func NewRR(s string) (RR, error) { - if s[len(s)-1] != '\n' { // We need a closing newline + if len(s) > 0 && s[len(s)-1] != '\n' { // We need a closing newline return ReadRR(strings.NewReader(s+"\n"), "") } return ReadRR(strings.NewReader(s), "") @@ -117,17 +121,21 @@ func NewRR(s string) (RR, error) { // See NewRR for more documentation. func ReadRR(q io.Reader, filename string) (RR, error) { r := <-parseZoneHelper(q, ".", filename, 1) + if r == nil { + return nil, nil + } + if r.Error != nil { return nil, r.Error } return r.RR, nil } -// ParseZone reads a RFC 1035 style 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. // @@ -136,15 +144,17 @@ func ReadRR(q io.Reader, filename string) (RR, error) { // // for x := range dns.ParseZone(strings.NewReader(z), "", "") { // if x.Error != nil { -// // Do something with x.RR -// } +// // log.Println(x.Error) +// } else { +// // Do something with x.RR +// } // } // // Comments specified after an RR (and on the same line!) are returned too: // // 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) @@ -163,17 +173,17 @@ func parseZone(r io.Reader, origin, f string, t chan *Token, include int) { } }() s := scanInit(r) - c := make(chan lex, 1000) + c := make(chan lex) // Start the lexer go zlexer(s, c) // 6 possible beginnings of a line, _ is a space - // 0. _RRTYPE -> all omitted until the rrtype - // 1. _OWNER _ _RRTYPE -> class/ttl omitted - // 2. _OWNER _ _STRING _ _RRTYPE -> class omitted - // 3. _OWNER _ _STRING _ _CLASS _ _RRTYPE -> ttl/class - // 4. _OWNER _ _CLASS _ _RRTYPE -> ttl omitted - // 5. _OWNER _ _CLASS _ _STRING _ _RRTYPE -> class/ttl (reversed) - // After detecting these, we know the _RRTYPE so we can jump to functions + // 0. zRRTYPE -> all omitted until the rrtype + // 1. zOwner _ zRrtype -> class/ttl omitted + // 2. zOwner _ zString _ zRrtype -> class omitted + // 3. zOwner _ zString _ zClass _ zRrtype -> ttl/class + // 4. zOwner _ zClass _ zRrtype -> ttl omitted + // 5. zOwner _ zClass _ zString _ zRrtype -> class/ttl (reversed) + // After detecting these, we know the zRrtype so we can jump to functions // handling the rdata for each of these types. if origin == "" { @@ -185,7 +195,7 @@ func parseZone(r io.Reader, origin, f string, t chan *Token, include int) { return } - st := _EXPECT_OWNER_DIR // initial state + st := zExpectOwnerDir // initial state var h RR_Header var defttl uint32 = defaultTtl var prevName string @@ -197,19 +207,19 @@ func parseZone(r io.Reader, origin, f string, t chan *Token, include int) { } switch st { - case _EXPECT_OWNER_DIR: + case zExpectOwnerDir: // We can also expect a directive, like $TTL or $ORIGIN h.Ttl = defttl h.Class = ClassINET switch l.value { - case _NEWLINE: // Empty line - st = _EXPECT_OWNER_DIR - case _OWNER: + case zNewline: + st = zExpectOwnerDir + case zOwner: h.Name = l.token if l.token[0] == '@' { h.Name = origin prevName = h.Name - st = _EXPECT_OWNER_BL + st = zExpectOwnerBl break } if h.Name[l.length-1] != '.' { @@ -221,59 +231,59 @@ func parseZone(r io.Reader, origin, f string, t chan *Token, include int) { return } prevName = h.Name - st = _EXPECT_OWNER_BL - case _DIRTTL: - st = _EXPECT_DIRTTL_BL - case _DIRORIGIN: - st = _EXPECT_DIRORIGIN_BL - case _DIRINCLUDE: - st = _EXPECT_DIRINCLUDE_BL - case _DIRGENERATE: - st = _EXPECT_DIRGENERATE_BL - case _RRTYPE: // Everthing has been omitted, this is the first thing on the line + st = zExpectOwnerBl + case zDirTtl: + st = zExpectDirTtlBl + case zDirOrigin: + st = zExpectDirOriginBl + case zDirInclude: + st = zExpectDirIncludeBl + case zDirGenerate: + st = zExpectDirGenerateBl + case zRrtpe: h.Name = prevName h.Rrtype = l.torc - st = _EXPECT_RDATA - case _CLASS: // First thing on the line is the class + st = zExpectRdata + case zClass: h.Name = prevName h.Class = l.torc - st = _EXPECT_ANY_NOCLASS_BL - case _BLANK: + st = zExpectAnyNoClassBl + case zBlank: // Discard, can happen when there is nothing on the // line except the RR type - case _STRING: // First thing on the is the ttl - if ttl, ok := stringToTtl(l.token); !ok { + case zString: + ttl, ok := stringToTtl(l.token) + if !ok { t <- &Token{Error: &ParseError{f, "not a TTL", l}} return - } else { - h.Ttl = ttl - // Don't about the defttl, we should take the $TTL value - // defttl = ttl } - st = _EXPECT_ANY_NOTTL_BL + h.Ttl = ttl + // Don't about the defttl, we should take the $TTL value + // defttl = ttl + st = zExpectAnyNoTtlBl default: t <- &Token{Error: &ParseError{f, "syntax error at beginning", l}} return } - case _EXPECT_DIRINCLUDE_BL: - if l.value != _BLANK { + case zExpectDirIncludeBl: + if l.value != zBlank { t <- &Token{Error: &ParseError{f, "no blank after $INCLUDE-directive", l}} return } - st = _EXPECT_DIRINCLUDE - case _EXPECT_DIRINCLUDE: - if l.value != _STRING { + st = zExpectDirInclude + case zExpectDirInclude: + if l.value != zString { t <- &Token{Error: &ParseError{f, "expecting $INCLUDE value, not this...", l}} return } neworigin := origin // There may be optionally a new origin set after the filename, if not use current one l := <-c switch l.value { - case _BLANK: + case zBlank: l := <-c - if l.value == _STRING { - if _, ok := IsDomainName(l.token); !ok { + if l.value == zString { + if _, ok := IsDomainName(l.token); !ok || l.length == 0 || l.err { t <- &Token{Error: &ParseError{f, "bad origin name", l}} return } @@ -288,7 +298,7 @@ func parseZone(r io.Reader, origin, f string, t chan *Token, include int) { neworigin = l.token } } - case _NEWLINE, _EOF: + case zNewline, zEOF: // Ok default: t <- &Token{Error: &ParseError{f, "garbage after $INCLUDE", l}} @@ -305,15 +315,15 @@ func parseZone(r io.Reader, origin, f string, t chan *Token, include int) { return } parseZone(r1, l.token, neworigin, t, include+1) - st = _EXPECT_OWNER_DIR - case _EXPECT_DIRTTL_BL: - if l.value != _BLANK { + st = zExpectOwnerDir + case zExpectDirTtlBl: + if l.value != zBlank { t <- &Token{Error: &ParseError{f, "no blank after $TTL-directive", l}} return } - st = _EXPECT_DIRTTL - case _EXPECT_DIRTTL: - if l.value != _STRING { + st = zExpectDirTtl + case zExpectDirTtl: + if l.value != zString { t <- &Token{Error: &ParseError{f, "expecting $TTL value, not this...", l}} return } @@ -321,21 +331,21 @@ func parseZone(r io.Reader, origin, f string, t chan *Token, include int) { t <- &Token{Error: e} return } - if ttl, ok := stringToTtl(l.token); !ok { + ttl, ok := stringToTtl(l.token) + if !ok { t <- &Token{Error: &ParseError{f, "expecting $TTL value, not this...", l}} return - } else { - defttl = ttl } - st = _EXPECT_OWNER_DIR - case _EXPECT_DIRORIGIN_BL: - if l.value != _BLANK { + defttl = ttl + st = zExpectOwnerDir + case zExpectDirOriginBl: + if l.value != zBlank { t <- &Token{Error: &ParseError{f, "no blank after $ORIGIN-directive", l}} return } - st = _EXPECT_DIRORIGIN - case _EXPECT_DIRORIGIN: - if l.value != _STRING { + st = zExpectDirOrigin + case zExpectDirOrigin: + if l.value != zString { t <- &Token{Error: &ParseError{f, "expecting $ORIGIN value, not this...", l}} return } @@ -355,15 +365,15 @@ func parseZone(r io.Reader, origin, f string, t chan *Token, include int) { } else { origin = l.token } - st = _EXPECT_OWNER_DIR - case _EXPECT_DIRGENERATE_BL: - if l.value != _BLANK { + st = zExpectOwnerDir + case zExpectDirGenerateBl: + if l.value != zBlank { t <- &Token{Error: &ParseError{f, "no blank after $GENERATE-directive", l}} return } - st = _EXPECT_DIRGENERATE - case _EXPECT_DIRGENERATE: - if l.value != _STRING { + st = zExpectDirGenerate + case zExpectDirGenerate: + if l.value != zString { t <- &Token{Error: &ParseError{f, "expecting $GENERATE value, not this...", l}} return } @@ -371,90 +381,90 @@ func parseZone(r io.Reader, origin, f string, t chan *Token, include int) { t <- &Token{Error: &ParseError{f, e, l}} return } - st = _EXPECT_OWNER_DIR - case _EXPECT_OWNER_BL: - if l.value != _BLANK { + st = zExpectOwnerDir + case zExpectOwnerBl: + if l.value != zBlank { t <- &Token{Error: &ParseError{f, "no blank after owner", l}} return } - st = _EXPECT_ANY - case _EXPECT_ANY: + st = zExpectAny + case zExpectAny: switch l.value { - case _RRTYPE: + case zRrtpe: h.Rrtype = l.torc - st = _EXPECT_RDATA - case _CLASS: + st = zExpectRdata + case zClass: h.Class = l.torc - st = _EXPECT_ANY_NOCLASS_BL - case _STRING: // TTL is this case - if ttl, ok := stringToTtl(l.token); !ok { + st = zExpectAnyNoClassBl + case zString: + ttl, ok := stringToTtl(l.token) + if !ok { t <- &Token{Error: &ParseError{f, "not a TTL", l}} return - } else { - h.Ttl = ttl - // defttl = ttl // don't set the defttl here } - st = _EXPECT_ANY_NOTTL_BL + h.Ttl = ttl + // defttl = ttl // don't set the defttl here + st = zExpectAnyNoTtlBl default: t <- &Token{Error: &ParseError{f, "expecting RR type, TTL or class, not this...", l}} return } - case _EXPECT_ANY_NOCLASS_BL: - if l.value != _BLANK { + case zExpectAnyNoClassBl: + if l.value != zBlank { t <- &Token{Error: &ParseError{f, "no blank before class", l}} return } - st = _EXPECT_ANY_NOCLASS - case _EXPECT_ANY_NOTTL_BL: - if l.value != _BLANK { + st = zExpectAnyNoClass + case zExpectAnyNoTtlBl: + if l.value != zBlank { t <- &Token{Error: &ParseError{f, "no blank before TTL", l}} return } - st = _EXPECT_ANY_NOTTL - case _EXPECT_ANY_NOTTL: + st = zExpectAnyNoTtl + case zExpectAnyNoTtl: switch l.value { - case _CLASS: + case zClass: h.Class = l.torc - st = _EXPECT_RRTYPE_BL - case _RRTYPE: + st = zExpectRrtypeBl + case zRrtpe: h.Rrtype = l.torc - st = _EXPECT_RDATA + st = zExpectRdata default: t <- &Token{Error: &ParseError{f, "expecting RR type or class, not this...", l}} return } - case _EXPECT_ANY_NOCLASS: + case zExpectAnyNoClass: switch l.value { - case _STRING: // TTL - if ttl, ok := stringToTtl(l.token); !ok { + case zString: + ttl, ok := stringToTtl(l.token) + if !ok { t <- &Token{Error: &ParseError{f, "not a TTL", l}} return - } else { - h.Ttl = ttl - // defttl = ttl // don't set the def ttl anymore } - st = _EXPECT_RRTYPE_BL - case _RRTYPE: + h.Ttl = ttl + // defttl = ttl // don't set the def ttl anymore + st = zExpectRrtypeBl + case zRrtpe: h.Rrtype = l.torc - st = _EXPECT_RDATA + st = zExpectRdata default: t <- &Token{Error: &ParseError{f, "expecting RR type or TTL, not this...", l}} return } - case _EXPECT_RRTYPE_BL: - if l.value != _BLANK { + case zExpectRrtypeBl: + if l.value != zBlank { t <- &Token{Error: &ParseError{f, "no blank before RR type", l}} return } - st = _EXPECT_RRTYPE - case _EXPECT_RRTYPE: - if l.value != _RRTYPE { + st = zExpectRrtype + case zExpectRrtype: + if l.value != zRrtpe { t <- &Token{Error: &ParseError{f, "unknown RR type", l}} return } h.Rrtype = l.torc - st = _EXPECT_RDATA - case _EXPECT_RDATA: + st = zExpectRdata + case zExpectRdata: r, e, c1 := setRR(h, c, origin, f) if e != nil { // If e.lex is nil than we have encounter a unknown RR type @@ -466,7 +476,7 @@ func parseZone(r io.Reader, origin, f string, t chan *Token, include int) { return } t <- &Token{RR: r, Comment: c1} - st = _EXPECT_OWNER_DIR + st = zExpectOwnerDir } } // If we get here, we and the h.Rrtype is still zero, we haven't parsed anything, this @@ -492,14 +502,14 @@ func zlexer(s *scan, c chan lex) { for err == nil { l.column = s.position.Column l.line = s.position.Line - if stri > maxTok { + if stri >= maxTok { l.token = "token length insufficient for parsing" l.err = true debug.Printf("[%+v]", l.token) c <- l return } - if comi > maxTok { + if comi >= maxTok { l.token = "comment length insufficient for parsing" l.err = true debug.Printf("[%+v]", l.token) @@ -530,60 +540,60 @@ func zlexer(s *scan, c chan lex) { // Space directly in the beginning, handled in the grammar } else if owner { // If we have a string and its the first, make it an owner - l.value = _OWNER + l.value = zOwner l.token = string(str[:stri]) l.tokenUpper = strings.ToUpper(l.token) l.length = stri // escape $... start with a \ not a $, so this will work switch l.tokenUpper { case "$TTL": - l.value = _DIRTTL + l.value = zDirTtl case "$ORIGIN": - l.value = _DIRORIGIN + l.value = zDirOrigin case "$INCLUDE": - l.value = _DIRINCLUDE + l.value = zDirInclude case "$GENERATE": - l.value = _DIRGENERATE + l.value = zDirGenerate } debug.Printf("[7 %+v]", l.token) c <- l } else { - l.value = _STRING + l.value = zString l.token = string(str[:stri]) l.tokenUpper = strings.ToUpper(l.token) l.length = stri if !rrtype { if t, ok := StringToType[l.tokenUpper]; ok { - l.value = _RRTYPE + l.value = zRrtpe l.torc = t rrtype = true } else { if strings.HasPrefix(l.tokenUpper, "TYPE") { - if t, ok := typeToInt(l.token); !ok { + t, ok := typeToInt(l.token) + if !ok { l.token = "unknown RR type" l.err = true c <- l return - } else { - l.value = _RRTYPE - l.torc = t } + l.value = zRrtpe + l.torc = t } } if t, ok := StringToClass[l.tokenUpper]; ok { - l.value = _CLASS + l.value = zClass l.torc = t } else { if strings.HasPrefix(l.tokenUpper, "CLASS") { - if t, ok := classToInt(l.token); !ok { + t, ok := classToInt(l.token) + if !ok { l.token = "unknown class" l.err = true c <- l return - } else { - l.value = _CLASS - l.torc = t } + l.value = zClass + l.torc = t } } } @@ -593,7 +603,7 @@ func zlexer(s *scan, c chan lex) { stri = 0 // I reverse space stuff here if !space && !commt { - l.value = _BLANK + l.value = zBlank l.token = " " l.length = 1 debug.Printf("[5 %+v]", l.token) @@ -615,7 +625,7 @@ func zlexer(s *scan, c chan lex) { break } if stri > 0 { - l.value = _STRING + l.value = zString l.token = string(str[:stri]) l.length = stri debug.Printf("[4 %+v]", l.token) @@ -651,7 +661,7 @@ func zlexer(s *scan, c chan lex) { if brace == 0 { owner = true owner = true - l.value = _NEWLINE + l.value = zNewline l.token = "\n" l.length = 1 l.comment = string(com[:comi]) @@ -669,14 +679,14 @@ func zlexer(s *scan, c chan lex) { if brace == 0 { // If there is previous text, we should output it here if stri != 0 { - l.value = _STRING + l.value = zString l.token = string(str[:stri]) l.tokenUpper = strings.ToUpper(l.token) l.length = stri if !rrtype { if t, ok := StringToType[l.tokenUpper]; ok { - l.value = _RRTYPE + l.value = zRrtpe l.torc = t rrtype = true } @@ -684,7 +694,7 @@ func zlexer(s *scan, c chan lex) { debug.Printf("[2 %+v]", l.token) c <- l } - l.value = _NEWLINE + l.value = zNewline l.token = "\n" l.length = 1 debug.Printf("[1 %+v]", l.token) @@ -728,7 +738,7 @@ func zlexer(s *scan, c chan lex) { space = false // send previous gathered text and the quote if stri != 0 { - l.value = _STRING + l.value = zString l.token = string(str[:stri]) l.length = stri @@ -738,7 +748,7 @@ func zlexer(s *scan, c chan lex) { } // send quote itself as separate token - l.value = _QUOTE + l.value = zQuote l.token = "\"" l.length = 1 c <- l @@ -790,7 +800,7 @@ func zlexer(s *scan, c chan lex) { // Send remainder l.token = string(str[:stri]) l.length = stri - l.value = _STRING + l.value = zString debug.Printf("[%+v]", l.token) c <- l } @@ -798,7 +808,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 } @@ -807,7 +821,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 } @@ -922,15 +940,15 @@ func slurpRemainder(c chan lex, f string) (*ParseError, string) { l := <-c com := "" switch l.value { - case _BLANK: + case zBlank: l = <-c com = l.comment - if l.value != _NEWLINE && l.value != _EOF { + if l.value != zNewline && l.value != zEOF { return &ParseError{f, "garbage after rdata", l}, "" } - case _NEWLINE: + case zNewline: com = l.comment - case _EOF: + case zEOF: default: return &ParseError{f, "garbage after rdata", l}, "" } diff --git a/vendor/github.com/miekg/dns/zscan_rr.go b/vendor/github.com/miekg/dns/zscan_rr.go index 5088cdb58e2..ead9614d13b 100644 --- a/vendor/github.com/miekg/dns/zscan_rr.go +++ b/vendor/github.com/miekg/dns/zscan_rr.go @@ -19,9 +19,9 @@ type parserFunc struct { } // Parse the rdata of each rrtype. -// All data from the channel c is either _STRING or _BLANK. -// After the rdata there may come a _BLANK and then a _NEWLINE -// or immediately a _NEWLINE. If this is not the case we flag +// All data from the channel c is either zString or zBlank. +// After the rdata there may come a zBlank and then a zNewline +// or immediately a zNewline. If this is not the case we flag // an *ParseError: garbage after rdata. func setRR(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { parserfunc, ok := typeToparserFunc[h.Rrtype] @@ -47,12 +47,15 @@ func setRR(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { // or an error func endingToString(c chan lex, errstr, f string) (string, *ParseError, string) { s := "" - l := <-c // _STRING - for l.value != _NEWLINE && l.value != _EOF { + l := <-c // zString + for l.value != zNewline && l.value != zEOF { + if l.err { + return s, &ParseError{f, errstr, l}, "" + } switch l.value { - case _STRING: + case zString: s += l.token - case _BLANK: // Ok + case zBlank: // Ok default: return "", &ParseError{f, errstr, l}, "" } @@ -64,25 +67,49 @@ func endingToString(c chan lex, errstr, f string) (string, *ParseError, string) // A remainder of the rdata with embedded spaces, return the parsed string slice (sans the spaces) // or an error func endingToTxtSlice(c chan lex, errstr, f string) ([]string, *ParseError, string) { - // Get the remaining data until we see a NEWLINE + // Get the remaining data until we see a zNewline quote := false l := <-c var s []string - switch l.value == _QUOTE { + if l.err { + return s, &ParseError{f, errstr, l}, "" + } + switch l.value == zQuote { case true: // A number of quoted string s = make([]string, 0) empty := true - for l.value != _NEWLINE && l.value != _EOF { + for l.value != zNewline && l.value != zEOF { + if l.err { + return nil, &ParseError{f, errstr, l}, "" + } switch l.value { - case _STRING: + case zString: empty = false + if len(l.token) > 255 { + // split up tokens that are larger than 255 into 255-chunks + sx := []string{} + p, i := 0, 255 + for { + if i <= len(l.token) { + sx = append(sx, l.token[p:i]) + } else { + sx = append(sx, l.token[p:]) + break + + } + p, i = p+255, i+255 + } + s = append(s, sx...) + break + } + s = append(s, l.token) - case _BLANK: + case zBlank: if quote { - // _BLANK can only be seen in between txt parts. + // zBlank can only be seen in between txt parts. return nil, &ParseError{f, errstr, l}, "" } - case _QUOTE: + case zQuote: if empty && quote { s = append(s, "") } @@ -98,7 +125,10 @@ func endingToTxtSlice(c chan lex, errstr, f string) ([]string, *ParseError, stri } case false: // Unquoted text record s = make([]string, 1) - for l.value != _NEWLINE && l.value != _EOF { + for l.value != zNewline && l.value != zEOF { + if l.err { + return s, &ParseError{f, errstr, l}, "" + } s[0] += l.token l = <-c } @@ -115,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, "" @@ -130,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, "" @@ -150,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] != '.' { @@ -173,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] != '.' { @@ -196,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] != '.' { @@ -218,14 +248,14 @@ 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] != '.' { rr.Mbox = appendOrigin(rr.Mbox, o) } } - <-c // _BLANK + <-c // zBlank l = <-c rr.Txt = l.token if l.token == "@" { @@ -233,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] != '.' { @@ -256,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] != '.' { @@ -279,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] != '.' { @@ -302,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] != '.' { @@ -315,11 +345,24 @@ func setHINFO(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { rr := new(HINFO) rr.Hdr = h - l := <-c - rr.Cpu = l.token - <-c // _BLANK - l = <-c // _STRING - rr.Os = l.token + chunks, e, c1 := endingToTxtSlice(c, "bad HINFO Fields", f) + if e != nil { + return nil, e, c1 + } + + if ln := len(chunks); ln == 0 { + return rr, nil, "" + } else if ln == 1 { + // Can we split it? + if out := strings.Fields(chunks[0]); len(out) > 1 { + chunks = out + } else { + chunks = append(chunks, "") + } + } + + rr.Cpu = chunks[0] + rr.Os = strings.Join(chunks[1:], " ") return rr, nil, "" } @@ -337,14 +380,14 @@ 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] != '.' { rr.Rmail = appendOrigin(rr.Rmail, o) } } - <-c // _BLANK + <-c // zBlank l = <-c rr.Email = l.token if l.token == "@" { @@ -352,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] != '.' { @@ -375,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] != '.' { @@ -398,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] != '.' { @@ -415,20 +458,20 @@ func setMX(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 { + i, e := strconv.Atoi(l.token) + if e != nil || l.err { return nil, &ParseError{f, "bad MX Pref", l}, "" - } else { - rr.Preference = uint16(i) } - <-c // _BLANK - l = <-c // _STRING + rr.Preference = uint16(i) + <-c // zBlank + l = <-c // zString rr.Mx = l.token if l.token == "@" { rr.Mx = o return rr, nil, "" } _, ok := IsDomainName(l.token) - if !ok || l.length == 0 { + if !ok || l.length == 0 || l.err { return nil, &ParseError{f, "bad MX Mx", l}, "" } if rr.Mx[l.length-1] != '.' { @@ -444,20 +487,20 @@ func setRT(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 { + i, e := strconv.Atoi(l.token) + if e != nil { return nil, &ParseError{f, "bad RT Preference", l}, "" - } else { - rr.Preference = uint16(i) } - <-c // _BLANK - l = <-c // _STRING + rr.Preference = uint16(i) + <-c // zBlank + l = <-c // zString rr.Host = l.token if l.token == "@" { rr.Host = o return rr, nil, "" } _, ok := IsDomainName(l.token) - if !ok || l.length == 0 { + if !ok || l.length == 0 || l.err { return nil, &ParseError{f, "bad RT Host", l}, "" } if rr.Host[l.length-1] != '.' { @@ -474,20 +517,20 @@ func setAFSDB(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 { + i, e := strconv.Atoi(l.token) + if e != nil || l.err { return nil, &ParseError{f, "bad AFSDB Subtype", l}, "" - } else { - rr.Subtype = uint16(i) } - <-c // _BLANK - l = <-c // _STRING + rr.Subtype = uint16(i) + <-c // zBlank + l = <-c // zString rr.Hostname = l.token if l.token == "@" { rr.Hostname = o return rr, nil, "" } _, ok := IsDomainName(l.token) - if !ok || l.length == 0 { + if !ok || l.length == 0 || l.err { return nil, &ParseError{f, "bad AFSDB Hostname", l}, "" } if rr.Hostname[l.length-1] != '.' { @@ -501,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, "" } @@ -513,20 +562,20 @@ func setKX(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 { + i, e := strconv.Atoi(l.token) + if e != nil || l.err { return nil, &ParseError{f, "bad KX Pref", l}, "" - } else { - rr.Preference = uint16(i) } - <-c // _BLANK - l = <-c // _STRING + rr.Preference = uint16(i) + <-c // zBlank + l = <-c // zString rr.Exchanger = l.token if l.token == "@" { rr.Exchanger = o return rr, nil, "" } _, ok := IsDomainName(l.token) - if !ok || l.length == 0 { + if !ok || l.length == 0 || l.err { return nil, &ParseError{f, "bad KX Exchanger", l}, "" } if rr.Exchanger[l.length-1] != '.' { @@ -549,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] != '.' { @@ -572,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] != '.' { @@ -590,12 +639,12 @@ func setSOA(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { if l.length == 0 { return rr, nil, "" } - <-c // _BLANK + <-c // zBlank if l.token == "@" { 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] != '.' { @@ -609,14 +658,14 @@ 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] != '.' { rr.Mbox = appendOrigin(rr.Mbox, o) } } - <-c // _BLANK + <-c // zBlank var ( v uint32 @@ -624,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 @@ -639,16 +691,16 @@ func setSOA(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { switch i { case 0: rr.Serial = v - <-c // _BLANK + <-c // zBlank case 1: rr.Refresh = v - <-c // _BLANK + <-c // zBlank case 2: rr.Retry = v - <-c // _BLANK + <-c // zBlank case 3: rr.Expire = v - <-c // _BLANK + <-c // zBlank case 4: rr.Minttl = v } @@ -664,34 +716,34 @@ func setSRV(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 { + i, e := strconv.Atoi(l.token) + if e != nil || l.err { return nil, &ParseError{f, "bad SRV Priority", l}, "" - } else { - rr.Priority = uint16(i) } - <-c // _BLANK - l = <-c // _STRING - if i, e := strconv.Atoi(l.token); e != nil { + rr.Priority = uint16(i) + <-c // zBlank + l = <-c // zString + i, e = strconv.Atoi(l.token) + if e != nil || l.err { return nil, &ParseError{f, "bad SRV Weight", l}, "" - } else { - rr.Weight = uint16(i) } - <-c // _BLANK - l = <-c // _STRING - if i, e := strconv.Atoi(l.token); e != nil { + rr.Weight = uint16(i) + <-c // zBlank + l = <-c // zString + i, e = strconv.Atoi(l.token) + if e != nil || l.err { return nil, &ParseError{f, "bad SRV Port", l}, "" - } else { - rr.Port = uint16(i) } - <-c // _BLANK - l = <-c // _STRING + rr.Port = uint16(i) + <-c // zBlank + l = <-c // zString rr.Target = l.token if l.token == "@" { rr.Target = o return rr, nil, "" } _, ok := IsDomainName(l.token) - if !ok || l.length == 0 { + if !ok || l.length == 0 || l.err { return nil, &ParseError{f, "bad SRV Target", l}, "" } if rr.Target[l.length-1] != '.' { @@ -708,84 +760,84 @@ func setNAPTR(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 { + i, e := strconv.Atoi(l.token) + if e != nil || l.err { return nil, &ParseError{f, "bad NAPTR Order", l}, "" - } else { - rr.Order = uint16(i) } - <-c // _BLANK - l = <-c // _STRING - if i, e := strconv.Atoi(l.token); e != nil { + rr.Order = uint16(i) + <-c // zBlank + l = <-c // zString + i, e = strconv.Atoi(l.token) + if e != nil || l.err { return nil, &ParseError{f, "bad NAPTR Preference", l}, "" - } else { - rr.Preference = uint16(i) } + rr.Preference = uint16(i) // Flags - <-c // _BLANK + <-c // zBlank l = <-c // _QUOTE - if l.value != _QUOTE { + if l.value != zQuote { return nil, &ParseError{f, "bad NAPTR Flags", l}, "" } l = <-c // Either String or Quote - if l.value == _STRING { + if l.value == zString { rr.Flags = l.token l = <-c // _QUOTE - if l.value != _QUOTE { + if l.value != zQuote { return nil, &ParseError{f, "bad NAPTR Flags", l}, "" } - } else if l.value == _QUOTE { + } else if l.value == zQuote { rr.Flags = "" } else { return nil, &ParseError{f, "bad NAPTR Flags", l}, "" } // Service - <-c // _BLANK + <-c // zBlank l = <-c // _QUOTE - if l.value != _QUOTE { + if l.value != zQuote { return nil, &ParseError{f, "bad NAPTR Service", l}, "" } l = <-c // Either String or Quote - if l.value == _STRING { + if l.value == zString { rr.Service = l.token l = <-c // _QUOTE - if l.value != _QUOTE { + if l.value != zQuote { return nil, &ParseError{f, "bad NAPTR Service", l}, "" } - } else if l.value == _QUOTE { + } else if l.value == zQuote { rr.Service = "" } else { return nil, &ParseError{f, "bad NAPTR Service", l}, "" } // Regexp - <-c // _BLANK + <-c // zBlank l = <-c // _QUOTE - if l.value != _QUOTE { + if l.value != zQuote { return nil, &ParseError{f, "bad NAPTR Regexp", l}, "" } l = <-c // Either String or Quote - if l.value == _STRING { + if l.value == zString { rr.Regexp = l.token l = <-c // _QUOTE - if l.value != _QUOTE { + if l.value != zQuote { return nil, &ParseError{f, "bad NAPTR Regexp", l}, "" } - } else if l.value == _QUOTE { + } else if l.value == zQuote { rr.Regexp = "" } else { return nil, &ParseError{f, "bad NAPTR Regexp", l}, "" } // After quote no space?? - <-c // _BLANK - l = <-c // _STRING + <-c // zBlank + l = <-c // zString rr.Replacement = l.token if l.token == "@" { rr.Replacement = o return rr, nil, "" } _, ok := IsDomainName(l.token) - if !ok || l.length == 0 { + if !ok || l.length == 0 || l.err { return nil, &ParseError{f, "bad NAPTR Replacement", l}, "" } if rr.Replacement[l.length-1] != '.' { @@ -807,14 +859,14 @@ 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] != '.' { rr.PreviousName = appendOrigin(rr.PreviousName, o) } } - <-c // _BLANK + <-c // zBlank l = <-c rr.NextName = l.token if l.token == "@" { @@ -822,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] != '.' { @@ -844,30 +896,32 @@ 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 { + i, e := strconv.Atoi(l.token) + if e != nil || l.err { return nil, &ParseError{f, "bad LOC Latitude", l}, "" - } else { - rr.Latitude = 1000 * 60 * 60 * uint32(i) } - <-c // _BLANK + rr.Latitude = 1000 * 60 * 60 * uint32(i) + + <-c // zBlank // Either number, 'N' or 'S' l = <-c if rr.Latitude, ok = locCheckNorth(l.token, rr.Latitude); ok { goto East } - if i, e := strconv.Atoi(l.token); e != nil { + i, e = strconv.Atoi(l.token) + if e != nil || l.err { return nil, &ParseError{f, "bad LOC Latitude minutes", l}, "" - } else { - rr.Latitude += 1000 * 60 * uint32(i) } - <-c // _BLANK + 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) } - <-c // _BLANK + <-c // zBlank // Either number, 'N' or 'S' l = <-c if rr.Latitude, ok = locCheckNorth(l.token, rr.Latitude); ok { @@ -878,32 +932,32 @@ func setLOC(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { East: // East - <-c // _BLANK + <-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) } - <-c // _BLANK + <-c // zBlank // Either number, 'E' or 'W' l = <-c if rr.Longitude, ok = locCheckEast(l.token, rr.Longitude); ok { goto Altitude } - if i, e := strconv.Atoi(l.token); e != nil { + 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 // _BLANK + <-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) } - <-c // _BLANK + <-c // zBlank // Either number, 'E' or 'W' l = <-c if rr.Longitude, ok = locCheckEast(l.token, rr.Longitude); ok { @@ -913,8 +967,11 @@ East: return nil, &ParseError{f, "bad LOC Longitude East/West", l}, "" Altitude: - <-c // _BLANK + <-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] } @@ -927,31 +984,31 @@ Altitude: // And now optionally the other values l = <-c count := 0 - for l.value != _NEWLINE && l.value != _EOF { + for l.value != zNewline && l.value != zEOF { switch l.value { - case _STRING: + case zString: switch count { case 0: // Size - if e, m, ok := stringToCm(l.token); !ok { + e, m, ok := stringToCm(l.token) + if !ok { return nil, &ParseError{f, "bad LOC Size", l}, "" - } else { - rr.Size = (e & 0x0f) | (m << 4 & 0xf0) } + rr.Size = (e & 0x0f) | (m << 4 & 0xf0) case 1: // HorizPre - if e, m, ok := stringToCm(l.token); !ok { + e, m, ok := stringToCm(l.token) + if !ok { return nil, &ParseError{f, "bad LOC HorizPre", l}, "" - } else { - rr.HorizPre = (e & 0x0f) | (m << 4 & 0xf0) } + rr.HorizPre = (e & 0x0f) | (m << 4 & 0xf0) case 2: // VertPre - if e, m, ok := stringToCm(l.token); !ok { + e, m, ok := stringToCm(l.token) + if !ok { return nil, &ParseError{f, "bad LOC VertPre", l}, "" - } else { - rr.VertPre = (e & 0x0f) | (m << 4 & 0xf0) } + rr.VertPre = (e & 0x0f) | (m << 4 & 0xf0) } count++ - case _BLANK: + case zBlank: // Ok default: return nil, &ParseError{f, "bad LOC Size, HorizPre or VertPre", l}, "" @@ -970,40 +1027,47 @@ func setHIP(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { if l.length == 0 { return rr, nil, l.comment } - if i, e := strconv.Atoi(l.token); e != nil { + i, e := strconv.Atoi(l.token) + if e != nil || l.err { return nil, &ParseError{f, "bad HIP PublicKeyAlgorithm", l}, "" - } else { - rr.PublicKeyAlgorithm = uint8(i) } - <-c // _BLANK - l = <-c // _STRING + rr.PublicKeyAlgorithm = uint8(i) + <-c // zBlank + l = <-c // zString + if l.length == 0 || l.err { + return nil, &ParseError{f, "bad HIP Hit", l}, "" + } rr.Hit = l.token // This can not contain spaces, see RFC 5205 Section 6. rr.HitLength = uint8(len(rr.Hit)) / 2 - <-c // _BLANK - l = <-c // _STRING + <-c // zBlank + l = <-c // zString + if l.length == 0 || l.err { + return nil, &ParseError{f, "bad HIP PublicKey", l}, "" + } rr.PublicKey = l.token // This cannot contain spaces rr.PublicKeyLength = uint16(base64.StdEncoding.DecodedLen(len(rr.PublicKey))) // RendezvousServers (if any) l = <-c - xs := make([]string, 0) - for l.value != _NEWLINE && l.value != _EOF { + var xs []string + for l.value != zNewline && l.value != zEOF { switch l.value { - case _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] != '.' { l.token = appendOrigin(l.token, o) } xs = append(xs, l.token) - case _BLANK: + case zBlank: // Ok default: return nil, &ParseError{f, "bad HIP RendezvousServers", l}, "" @@ -1029,15 +1093,15 @@ func setCERT(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { } else { rr.Type = uint16(i) } - <-c // _BLANK - l = <-c // _STRING - if i, e := strconv.Atoi(l.token); e != nil { + <-c // zBlank + l = <-c // zString + i, e := strconv.Atoi(l.token) + if e != nil || l.err { return nil, &ParseError{f, "bad CERT KeyTag", l}, "" - } else { - rr.KeyTag = uint16(i) } - <-c // _BLANK - l = <-c // _STRING + rr.KeyTag = uint16(i) + <-c // zBlank + l = <-c // zString if v, ok := StringToAlgorithm[l.token]; ok { rr.Algorithm = v } else if i, e := strconv.Atoi(l.token); e != nil { @@ -1045,9 +1109,9 @@ func setCERT(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { } else { rr.Algorithm = uint8(i) } - s, e, c1 := endingToString(c, "bad CERT Certificate", f) - if e != nil { - return nil, e, c1 + s, e1, c1 := endingToString(c, "bad CERT Certificate", f) + if e1 != nil { + return nil, e1, c1 } rr.Certificate = s return rr, nil, c1 @@ -1082,39 +1146,39 @@ func setRRSIG(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { } if t, ok := StringToType[l.tokenUpper]; !ok { if strings.HasPrefix(l.tokenUpper, "TYPE") { - if t, ok = typeToInt(l.tokenUpper); !ok { + t, ok = typeToInt(l.tokenUpper) + if !ok { return nil, &ParseError{f, "bad RRSIG Typecovered", l}, "" - } else { - rr.TypeCovered = t } + rr.TypeCovered = t } else { return nil, &ParseError{f, "bad RRSIG Typecovered", l}, "" } } else { rr.TypeCovered = t } - <-c // _BLANK + <-c // zBlank l = <-c - if i, err := strconv.Atoi(l.token); err != nil { + i, err := strconv.Atoi(l.token) + if err != nil || l.err { return nil, &ParseError{f, "bad RRSIG Algorithm", l}, "" - } else { - rr.Algorithm = uint8(i) } - <-c // _BLANK + rr.Algorithm = uint8(i) + <-c // zBlank l = <-c - if i, err := strconv.Atoi(l.token); err != nil { + i, err = strconv.Atoi(l.token) + if err != nil || l.err { return nil, &ParseError{f, "bad RRSIG Labels", l}, "" - } else { - rr.Labels = uint8(i) } - <-c // _BLANK + rr.Labels = uint8(i) + <-c // zBlank l = <-c - if i, err := strconv.Atoi(l.token); err != nil { + i, err = strconv.Atoi(l.token) + if err != nil || l.err { return nil, &ParseError{f, "bad RRSIG OrigTtl", l}, "" - } else { - rr.OrigTtl = uint32(i) } - <-c // _BLANK + rr.OrigTtl = uint32(i) + <-c // zBlank l = <-c if i, err := StringToTime(l.token); err != nil { // Try to see if all numeric and use it as epoch @@ -1127,7 +1191,7 @@ func setRRSIG(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { } else { rr.Expiration = i } - <-c // _BLANK + <-c // zBlank l = <-c if i, err := StringToTime(l.token); err != nil { if i, err := strconv.ParseInt(l.token, 10, 64); err == nil { @@ -1138,21 +1202,21 @@ func setRRSIG(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { } else { rr.Inception = i } - <-c // _BLANK + <-c // zBlank l = <-c - if i, err := strconv.Atoi(l.token); err != nil { + i, err = strconv.Atoi(l.token) + if err != nil || l.err { return nil, &ParseError{f, "bad RRSIG KeyTag", l}, "" - } else { - rr.KeyTag = uint16(i) } - <-c // _BLANK + rr.KeyTag = uint16(i) + <-c // zBlank l = <-c rr.SignerName = l.token if l.token == "@" { rr.SignerName = o } else { _, ok := IsDomainName(l.token) - if !ok || l.length == 0 { + if !ok || l.length == 0 || l.err { return nil, &ParseError{f, "bad RRSIG SignerName", l}, "" } if rr.SignerName[l.length-1] != '.' { @@ -1180,7 +1244,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] != '.' { @@ -1194,11 +1258,11 @@ func setNSEC(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { ok bool ) l = <-c - for l.value != _NEWLINE && l.value != _EOF { + for l.value != zNewline && l.value != zEOF { switch l.value { - case _BLANK: + case zBlank: // Ok - case _STRING: + case zString: if k, ok = StringToType[l.tokenUpper]; !ok { if k, ok = typeToInt(l.tokenUpper); !ok { return nil, &ParseError{f, "bad NSEC TypeBitMap", l}, "" @@ -1221,28 +1285,28 @@ func setNSEC3(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { if l.length == 0 { return rr, nil, l.comment } - if i, e := strconv.Atoi(l.token); e != nil { + i, e := strconv.Atoi(l.token) + if e != nil || l.err { return nil, &ParseError{f, "bad NSEC3 Hash", l}, "" - } else { - rr.Hash = uint8(i) } - <-c // _BLANK + rr.Hash = uint8(i) + <-c // zBlank l = <-c - if i, e := strconv.Atoi(l.token); e != nil { + i, e = strconv.Atoi(l.token) + if e != nil || l.err { return nil, &ParseError{f, "bad NSEC3 Flags", l}, "" - } else { - rr.Flags = uint8(i) } - <-c // _BLANK + rr.Flags = uint8(i) + <-c // zBlank l = <-c - if i, e := strconv.Atoi(l.token); e != nil { + i, e = strconv.Atoi(l.token) + if e != nil || l.err { return nil, &ParseError{f, "bad NSEC3 Iterations", l}, "" - } else { - rr.Iterations = uint16(i) } + 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 @@ -1250,6 +1314,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 @@ -1259,11 +1326,11 @@ func setNSEC3(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { ok bool ) l = <-c - for l.value != _NEWLINE && l.value != _EOF { + for l.value != zNewline && l.value != zEOF { switch l.value { - case _BLANK: + case zBlank: // Ok - case _STRING: + case zString: if k, ok = StringToType[l.tokenUpper]; !ok { if k, ok = typeToInt(l.tokenUpper); !ok { return nil, &ParseError{f, "bad NSEC3 TypeBitMap", l}, "" @@ -1286,25 +1353,25 @@ func setNSEC3PARAM(h RR_Header, c chan lex, o, f string) (RR, *ParseError, strin if l.length == 0 { return rr, nil, "" } - if i, e := strconv.Atoi(l.token); e != nil { + i, e := strconv.Atoi(l.token) + if e != nil || l.err { return nil, &ParseError{f, "bad NSEC3PARAM Hash", l}, "" - } else { - rr.Hash = uint8(i) } - <-c // _BLANK + rr.Hash = uint8(i) + <-c // zBlank l = <-c - if i, e := strconv.Atoi(l.token); e != nil { + i, e = strconv.Atoi(l.token) + if e != nil || l.err { return nil, &ParseError{f, "bad NSEC3PARAM Flags", l}, "" - } else { - rr.Flags = uint8(i) } - <-c // _BLANK + rr.Flags = uint8(i) + <-c // zBlank l = <-c - if i, e := strconv.Atoi(l.token); e != nil { + i, e = strconv.Atoi(l.token) + if e != nil || l.err { return nil, &ParseError{f, "bad NSEC3PARAM Iterations", l}, "" - } else { - rr.Iterations = uint16(i) } + rr.Iterations = uint16(i) <-c l = <-c rr.SaltLength = uint8(len(l.token)) @@ -1320,7 +1387,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) @@ -1336,11 +1403,11 @@ func setEUI48(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { addr[10] = l.token[15] addr[11] = l.token[16] - if i, e := strconv.ParseUint(string(addr), 16, 48); e != nil { + i, e := strconv.ParseUint(string(addr), 16, 48) + if e != nil { return nil, &ParseError{f, "bad EUI48 Address", l}, "" - } else { - rr.Address = i } + rr.Address = i return rr, nil, "" } @@ -1352,7 +1419,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) @@ -1368,11 +1435,11 @@ func setEUI64(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { addr[14] = l.token[21] addr[15] = l.token[22] - if i, e := strconv.ParseUint(string(addr), 16, 64); e != nil { + i, e := strconv.ParseUint(string(addr), 16, 64) + if e != nil { return nil, &ParseError{f, "bad EUI68 Address", l}, "" - } else { - rr.Address = uint64(i) } + rr.Address = uint64(i) return rr, nil, "" } @@ -1385,25 +1452,25 @@ 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}, "" } - <-c // _BLANK + <-c // zBlank l = <-c proto := "tcp" - if i, e := strconv.Atoi(l.token); e != nil { + i, e := strconv.Atoi(l.token) + if e != nil || l.err { + return nil, &ParseError{f, "bad WKS Protocol", l}, "" + } + rr.Protocol = uint8(i) + switch rr.Protocol { + case 17: + proto = "udp" + case 6: + proto = "tcp" + default: return nil, &ParseError{f, "bad WKS Protocol", l}, "" - } else { - rr.Protocol = uint8(i) - switch rr.Protocol { - case 17: - proto = "udp" - case 6: - proto = "tcp" - default: - return nil, &ParseError{f, "bad WKS Protocol", l}, "" - } } <-c @@ -1413,17 +1480,17 @@ func setWKS(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { k int err error ) - for l.value != _NEWLINE && l.value != _EOF { + for l.value != zNewline && l.value != zEOF { switch l.value { - case _BLANK: + case zBlank: // Ok - case _STRING: + case zString: if k, err = net.LookupPort(proto, l.token); err != nil { - if i, e := strconv.Atoi(l.token); e != nil { // If a number use that - rr.BitMap = append(rr.BitMap, uint16(i)) - } else { + i, e := strconv.Atoi(l.token) // If a number use that + if e != nil { return nil, &ParseError{f, "bad WKS BitMap", l}, "" } + rr.BitMap = append(rr.BitMap, uint16(i)) } rr.BitMap = append(rr.BitMap, uint16(k)) default: @@ -1442,21 +1509,24 @@ func setSSHFP(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 { + i, e := strconv.Atoi(l.token) + if e != nil || l.err { return nil, &ParseError{f, "bad SSHFP Algorithm", l}, "" - } else { - rr.Algorithm = uint8(i) } - <-c // _BLANK + rr.Algorithm = uint8(i) + <-c // zBlank l = <-c - if i, e := strconv.Atoi(l.token); e != nil { + i, e = strconv.Atoi(l.token) + if e != nil || l.err { return nil, &ParseError{f, "bad SSHFP Type", l}, "" - } else { - rr.Type = uint8(i) } - <-c // _BLANK - l = <-c - rr.FingerPrint = l.token + rr.Type = uint8(i) + <-c // zBlank + s, e1, c1 := endingToString(c, "bad SSHFP Fingerprint", f) + if e1 != nil { + return nil, e1, c1 + } + rr.FingerPrint = s return rr, nil, "" } @@ -1468,28 +1538,28 @@ func setDNSKEYs(h RR_Header, c chan lex, o, f, typ string) (RR, *ParseError, str if l.length == 0 { return rr, nil, l.comment } - if i, e := strconv.Atoi(l.token); e != nil { + i, e := strconv.Atoi(l.token) + if e != nil || l.err { return nil, &ParseError{f, "bad " + typ + " Flags", l}, "" - } else { - rr.Flags = uint16(i) } - <-c // _BLANK - l = <-c // _STRING - if i, e := strconv.Atoi(l.token); e != nil { + rr.Flags = uint16(i) + <-c // zBlank + l = <-c // zString + i, e = strconv.Atoi(l.token) + if e != nil || l.err { return nil, &ParseError{f, "bad " + typ + " Protocol", l}, "" - } else { - rr.Protocol = uint8(i) } - <-c // _BLANK - l = <-c // _STRING - if i, e := strconv.Atoi(l.token); e != nil { + rr.Protocol = uint8(i) + <-c // zBlank + l = <-c // zString + i, e = strconv.Atoi(l.token) + if e != nil || l.err { return nil, &ParseError{f, "bad " + typ + " Algorithm", l}, "" - } else { - rr.Algorithm = uint8(i) } - s, e, c1 := endingToString(c, "bad "+typ+" PublicKey", f) - if e != nil { - return nil, e, c1 + rr.Algorithm = uint8(i) + s, e1, c1 := endingToString(c, "bad "+typ+" PublicKey", f) + if e1 != nil { + return nil, e1, c1 } rr.PublicKey = s return rr, nil, c1 @@ -1524,28 +1594,28 @@ func setRKEY(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { if l.length == 0 { return rr, nil, l.comment } - if i, e := strconv.Atoi(l.token); e != nil { + i, e := strconv.Atoi(l.token) + if e != nil || l.err { return nil, &ParseError{f, "bad RKEY Flags", l}, "" - } else { - rr.Flags = uint16(i) } - <-c // _BLANK - l = <-c // _STRING - if i, e := strconv.Atoi(l.token); e != nil { + rr.Flags = uint16(i) + <-c // zBlank + l = <-c // zString + i, e = strconv.Atoi(l.token) + if e != nil || l.err { return nil, &ParseError{f, "bad RKEY Protocol", l}, "" - } else { - rr.Protocol = uint8(i) } - <-c // _BLANK - l = <-c // _STRING - if i, e := strconv.Atoi(l.token); e != nil { + rr.Protocol = uint8(i) + <-c // zBlank + l = <-c // zString + i, e = strconv.Atoi(l.token) + if e != nil || l.err { return nil, &ParseError{f, "bad RKEY Algorithm", l}, "" - } else { - rr.Algorithm = uint8(i) } - s, e, c1 := endingToString(c, "bad RKEY PublicKey", f) - if e != nil { - return nil, e, c1 + rr.Algorithm = uint8(i) + s, e1, c1 := endingToString(c, "bad RKEY PublicKey", f) + if e1 != nil { + return nil, e1, c1 } rr.PublicKey = s return rr, nil, c1 @@ -1573,27 +1643,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 - l := <-c - if l.length == 0 { - return rr, nil, l.comment - } - if i, e := strconv.Atoi(l.token); e != nil { - return nil, &ParseError{f, "bad NSAP Length", l}, "" - } else { - rr.Length = uint8(i) - } - <-c // _BLANK - s, e, c1 := endingToString(c, "bad NSAP Nsap", f) - if e != nil { - return nil, e, c1 - } - rr.Nsap = s - return rr, nil, c1 -} - func setGPOS(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { rr := new(GPOS) rr.Hdr = h @@ -1601,25 +1650,25 @@ func setGPOS(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { if l.length == 0 { return rr, nil, "" } - if _, e := strconv.ParseFloat(l.token, 64); e != nil { + _, e := strconv.ParseFloat(l.token, 64) + if e != nil || l.err { return nil, &ParseError{f, "bad GPOS Longitude", l}, "" - } else { - rr.Longitude = l.token } - <-c // _BLANK + rr.Longitude = l.token + <-c // zBlank l = <-c - if _, e := strconv.ParseFloat(l.token, 64); e != nil { + _, e = strconv.ParseFloat(l.token, 64) + if e != nil || l.err { return nil, &ParseError{f, "bad GPOS Latitude", l}, "" - } else { - rr.Latitude = l.token } - <-c // _BLANK + rr.Latitude = l.token + <-c // zBlank l = <-c - if _, e := strconv.ParseFloat(l.token, 64); e != nil { + _, e = strconv.ParseFloat(l.token, 64) + if e != nil || l.err { return nil, &ParseError{f, "bad GPOS Altitude", l}, "" - } else { - rr.Altitude = l.token } + rr.Altitude = l.token return rr, nil, "" } @@ -1630,32 +1679,32 @@ func setDSs(h RR_Header, c chan lex, o, f, typ string) (RR, *ParseError, string) if l.length == 0 { return rr, nil, l.comment } - if i, e := strconv.Atoi(l.token); e != nil { + i, e := strconv.Atoi(l.token) + if e != nil || l.err { return nil, &ParseError{f, "bad " + typ + " KeyTag", l}, "" - } else { - rr.KeyTag = uint16(i) } - <-c // _BLANK + rr.KeyTag = uint16(i) + <-c // zBlank l = <-c if i, e := strconv.Atoi(l.token); e != nil { - if i, ok := StringToAlgorithm[l.tokenUpper]; !ok { + i, ok := StringToAlgorithm[l.tokenUpper] + if !ok || l.err { return nil, &ParseError{f, "bad " + typ + " Algorithm", l}, "" - } else { - rr.Algorithm = i } + rr.Algorithm = i } else { rr.Algorithm = uint8(i) } - <-c // _BLANK + <-c // zBlank l = <-c - if i, e := strconv.Atoi(l.token); e != nil { + i, e = strconv.Atoi(l.token) + if e != nil || l.err { return nil, &ParseError{f, "bad " + typ + " DigestType", l}, "" - } else { - rr.DigestType = uint8(i) } - s, e, c1 := endingToString(c, "bad "+typ+" Digest", f) - if e != nil { - return nil, e, c1 + rr.DigestType = uint8(i) + s, e1, c1 := endingToString(c, "bad "+typ+" Digest", f) + if e1 != nil { + return nil, e1, c1 } rr.Digest = s return rr, nil, c1 @@ -1675,7 +1724,7 @@ func setDLV(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { } func setCDS(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { - r, e, s := setDSs(h, c, o, f, "DLV") + r, e, s := setDSs(h, c, o, f, "CDS") if r != nil { return &CDS{*r.(*DS)}, e, s } @@ -1689,32 +1738,32 @@ func setTA(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { if l.length == 0 { return rr, nil, l.comment } - if i, e := strconv.Atoi(l.token); e != nil { + i, e := strconv.Atoi(l.token) + if e != nil || l.err { return nil, &ParseError{f, "bad TA KeyTag", l}, "" - } else { - rr.KeyTag = uint16(i) } - <-c // _BLANK + rr.KeyTag = uint16(i) + <-c // zBlank l = <-c if i, e := strconv.Atoi(l.token); e != nil { - if i, ok := StringToAlgorithm[l.tokenUpper]; !ok { + i, ok := StringToAlgorithm[l.tokenUpper] + if !ok || l.err { return nil, &ParseError{f, "bad TA Algorithm", l}, "" - } else { - rr.Algorithm = i } + rr.Algorithm = i } else { rr.Algorithm = uint8(i) } - <-c // _BLANK + <-c // zBlank l = <-c - if i, e := strconv.Atoi(l.token); e != nil { + i, e = strconv.Atoi(l.token) + if e != nil || l.err { return nil, &ParseError{f, "bad TA DigestType", l}, "" - } else { - rr.DigestType = uint8(i) } + rr.DigestType = uint8(i) s, e, c1 := endingToString(c, "bad TA Digest", f) if e != nil { - return nil, e, c1 + return nil, e.(*ParseError), c1 } rr.Digest = s return rr, nil, c1 @@ -1727,28 +1776,29 @@ func setTLSA(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { if l.length == 0 { return rr, nil, l.comment } - if i, e := strconv.Atoi(l.token); e != nil { + i, e := strconv.Atoi(l.token) + if e != nil || l.err { return nil, &ParseError{f, "bad TLSA Usage", l}, "" - } else { - rr.Usage = uint8(i) } - <-c // _BLANK + rr.Usage = uint8(i) + <-c // zBlank l = <-c - if i, e := strconv.Atoi(l.token); e != nil { + i, e = strconv.Atoi(l.token) + if e != nil || l.err { return nil, &ParseError{f, "bad TLSA Selector", l}, "" - } else { - rr.Selector = uint8(i) } - <-c // _BLANK + rr.Selector = uint8(i) + <-c // zBlank l = <-c - if i, e := strconv.Atoi(l.token); e != nil { + i, e = strconv.Atoi(l.token) + if e != nil || l.err { return nil, &ParseError{f, "bad TLSA MatchingType", l}, "" - } else { - rr.MatchingType = uint8(i) } - s, e, c1 := endingToString(c, "bad TLSA Certificate", f) - if e != nil { - return nil, e, c1 + rr.MatchingType = uint8(i) + // So this needs be e2 (i.e. different than e), because...??t + s, e2, c1 := endingToString(c, "bad TLSA Certificate", f) + if e2 != nil { + return nil, e2, c1 } rr.Certificate = s return rr, nil, c1 @@ -1761,10 +1811,10 @@ func setRFC3597(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) if l.token != "\\#" { return nil, &ParseError{f, "bad RFC3597 Rdata", l}, "" } - <-c // _BLANK + <-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}, "" } @@ -1795,7 +1845,7 @@ func setTXT(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { rr := new(TXT) rr.Hdr = h - // No _BLANK reading here, because this is all rdata is TXT + // no zBlank reading here, because all this rdata is TXT s, e, c1 := endingToTxtSlice(c, "bad TXT Txt", f) if e != nil { return nil, e, "" @@ -1822,66 +1872,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, "" } - if i, e := strconv.Atoi(l.token); e != nil { + + i, e := strconv.Atoi(l.token) + if e != nil || l.err { return nil, &ParseError{f, "bad URI Priority", l}, "" - } else { - rr.Priority = uint16(i) } - <-c // _BLANK + rr.Priority = uint16(i) + <-c // zBlank l = <-c - if i, e := strconv.Atoi(l.token); e != nil { + i, e = strconv.Atoi(l.token) + if e != nil || l.err { return nil, &ParseError{f, "bad URI Weight", l}, "" - } else { - rr.Weight = uint16(i) } + rr.Weight = uint16(i) - <-c // _BLANK - s, e, c1 := endingToTxtSlice(c, "bad URI Target", f) - if e != nil { - return nil, e, "" + <-c // zBlank + s, err, c1 := endingToTxtSlice(c, "bad URI Target", f) + if err != nil { + return nil, err, "" } - rr.Target = s - return rr, nil, c1 -} - -func setIPSECKEY(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { - rr := new(IPSECKEY) - rr.Hdr = h - - l := <-c - if l.length == 0 { - return rr, nil, l.comment + if len(s) > 1 { + return nil, &ParseError{f, "bad URI Target", l}, "" } - if i, e := strconv.Atoi(l.token); e != nil { - return nil, &ParseError{f, "bad IPSECKEY Precedence", l}, "" - } else { - rr.Precedence = uint8(i) - } - <-c // _BLANK - l = <-c - if i, e := strconv.Atoi(l.token); e != nil { - return nil, &ParseError{f, "bad IPSECKEY GatewayType", l}, "" - } else { - rr.GatewayType = uint8(i) - } - <-c // _BLANK - l = <-c - if i, e := strconv.Atoi(l.token); e != nil { - return nil, &ParseError{f, "bad IPSECKEY Algorithm", l}, "" - } else { - rr.Algorithm = uint8(i) - } - <-c - l = <-c - rr.Gateway = l.token - s, e, c1 := endingToString(c, "bad IPSECKEY PublicKey", f) - if e != nil { - return nil, e, c1 - } - rr.PublicKey = s + rr.Target = s[0] return rr, nil, c1 } @@ -1906,15 +1922,15 @@ func setNID(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 { + i, e := strconv.Atoi(l.token) + if e != nil || l.err { return nil, &ParseError{f, "bad NID Preference", l}, "" - } else { - rr.Preference = uint16(i) } - <-c // _BLANK - l = <-c // _STRING + 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 @@ -1929,15 +1945,15 @@ func setL32(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 { + i, e := strconv.Atoi(l.token) + if e != nil || l.err { return nil, &ParseError{f, "bad L32 Preference", l}, "" - } else { - rr.Preference = uint16(i) } - <-c // _BLANK - l = <-c // _STRING + 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, "" @@ -1951,13 +1967,13 @@ func setLP(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 { + i, e := strconv.Atoi(l.token) + if e != nil || l.err { return nil, &ParseError{f, "bad LP Preference", l}, "" - } else { - rr.Preference = uint16(i) } - <-c // _BLANK - l = <-c // _STRING + rr.Preference = uint16(i) + <-c // zBlank + l = <-c // zString rr.Fqdn = l.token if l.length == 0 { return rr, nil, "" @@ -1967,7 +1983,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] != '.' { @@ -1984,15 +2000,15 @@ func setL64(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 { + i, e := strconv.Atoi(l.token) + if e != nil || l.err { return nil, &ParseError{f, "bad L64 Preference", l}, "" - } else { - rr.Preference = uint16(i) } - <-c // _BLANK - l = <-c // _STRING + 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 @@ -2006,11 +2022,11 @@ func setUID(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 { + i, e := strconv.Atoi(l.token) + if e != nil || l.err { return nil, &ParseError{f, "bad UID Uid", l}, "" - } else { - rr.Uid = uint32(i) } + rr.Uid = uint32(i) return rr, nil, "" } @@ -2021,11 +2037,11 @@ func setGID(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 { + i, e := strconv.Atoi(l.token) + if e != nil || l.err { return nil, &ParseError{f, "bad GID Gid", l}, "" - } else { - rr.Gid = uint32(i) } + rr.Gid = uint32(i) return rr, nil, "" } @@ -2048,13 +2064,13 @@ func setPX(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 { + i, e := strconv.Atoi(l.token) + if e != nil || l.err { return nil, &ParseError{f, "bad PX Preference", l}, "" - } else { - rr.Preference = uint16(i) } - <-c // _BLANK - l = <-c // _STRING + rr.Preference = uint16(i) + <-c // zBlank + l = <-c // zString rr.Map822 = l.token if l.length == 0 { return rr, nil, "" @@ -2064,21 +2080,21 @@ 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] != '.' { rr.Map822 = appendOrigin(rr.Map822, o) } - <-c // _BLANK - l = <-c // _STRING + <-c // zBlank + l = <-c // zString rr.Mapx400 = l.token if l.token == "@" { rr.Mapx400 = o return rr, nil, "" } _, ok = IsDomainName(l.token) - if !ok || l.length == 0 { + if !ok || l.length == 0 || l.err { return nil, &ParseError{f, "bad PX Mapx400", l}, "" } if rr.Mapx400[l.length-1] != '.' { @@ -2087,69 +2103,168 @@ func setPX(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { return rr, nil, "" } -var typeToparserFunc = map[uint16]parserFunc{ - TypeAAAA: parserFunc{setAAAA, false}, - TypeAFSDB: parserFunc{setAFSDB, false}, - TypeA: parserFunc{setA, false}, - TypeCDS: parserFunc{setCDS, true}, - TypeCDNSKEY: parserFunc{setCDNSKEY, true}, - TypeCERT: parserFunc{setCERT, true}, - TypeCNAME: parserFunc{setCNAME, false}, - TypeDHCID: parserFunc{setDHCID, true}, - TypeDLV: parserFunc{setDLV, true}, - TypeDNAME: parserFunc{setDNAME, false}, - TypeKEY: parserFunc{setKEY, true}, - TypeDNSKEY: parserFunc{setDNSKEY, true}, - TypeDS: parserFunc{setDS, true}, - TypeEID: parserFunc{setEID, true}, - TypeEUI48: parserFunc{setEUI48, false}, - TypeEUI64: parserFunc{setEUI64, false}, - TypeGID: parserFunc{setGID, false}, - TypeGPOS: parserFunc{setGPOS, false}, - TypeHINFO: parserFunc{setHINFO, false}, - TypeHIP: parserFunc{setHIP, true}, - TypeIPSECKEY: parserFunc{setIPSECKEY, true}, - TypeKX: parserFunc{setKX, false}, - TypeL32: parserFunc{setL32, false}, - TypeL64: parserFunc{setL64, false}, - TypeLOC: parserFunc{setLOC, true}, - TypeLP: parserFunc{setLP, false}, - TypeMB: parserFunc{setMB, false}, - TypeMD: parserFunc{setMD, false}, - TypeMF: parserFunc{setMF, false}, - TypeMG: parserFunc{setMG, false}, - TypeMINFO: parserFunc{setMINFO, false}, - TypeMR: parserFunc{setMR, false}, - TypeMX: parserFunc{setMX, false}, - TypeNAPTR: parserFunc{setNAPTR, false}, - TypeNID: parserFunc{setNID, false}, - TypeNIMLOC: parserFunc{setNIMLOC, true}, - TypeNINFO: parserFunc{setNINFO, true}, - TypeNSAP: parserFunc{setNSAP, true}, - TypeNSAPPTR: parserFunc{setNSAPPTR, false}, - TypeNSEC3PARAM: parserFunc{setNSEC3PARAM, false}, - TypeNSEC3: parserFunc{setNSEC3, true}, - TypeNSEC: parserFunc{setNSEC, true}, - TypeNS: parserFunc{setNS, false}, - TypeOPENPGPKEY: parserFunc{setOPENPGPKEY, true}, - TypePTR: parserFunc{setPTR, false}, - TypePX: parserFunc{setPX, false}, - TypeSIG: parserFunc{setSIG, true}, - TypeRKEY: parserFunc{setRKEY, true}, - TypeRP: parserFunc{setRP, false}, - TypeRRSIG: parserFunc{setRRSIG, true}, - TypeRT: parserFunc{setRT, false}, - TypeSOA: parserFunc{setSOA, false}, - TypeSPF: parserFunc{setSPF, true}, - TypeSRV: parserFunc{setSRV, false}, - TypeSSHFP: parserFunc{setSSHFP, false}, - TypeTALINK: parserFunc{setTALINK, false}, - TypeTA: parserFunc{setTA, true}, - TypeTLSA: parserFunc{setTLSA, true}, - TypeTXT: parserFunc{setTXT, true}, - TypeUID: parserFunc{setUID, false}, - TypeUINFO: parserFunc{setUINFO, true}, - TypeURI: parserFunc{setURI, true}, - TypeWKS: parserFunc{setWKS, true}, - TypeX25: parserFunc{setX25, false}, +func setIPSECKEY(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { + rr := new(IPSECKEY) + rr.Hdr = h + l := <-c + if l.length == 0 { + return rr, nil, l.comment + } + i, err := strconv.Atoi(l.token) + if err != nil || l.err { + return nil, &ParseError{f, "bad IPSECKEY Precedence", l}, "" + } + rr.Precedence = uint8(i) + <-c // zBlank + l = <-c + i, err = strconv.Atoi(l.token) + 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 || l.err { + return nil, &ParseError{f, "bad IPSECKEY Algorithm", l}, "" + } + rr.Algorithm = uint8(i) + + // Now according to GatewayType we can have different elements here + <-c // zBlank + l = <-c + switch rr.GatewayType { + case 0: + fallthrough + case 3: + rr.GatewayName = l.token + if l.token == "@" { + rr.GatewayName = o + } + _, ok := IsDomainName(l.token) + if !ok || l.length == 0 || l.err { + return nil, &ParseError{f, "bad IPSECKEY GatewayName", l}, "" + } + if rr.GatewayName[l.length-1] != '.' { + rr.GatewayName = appendOrigin(rr.GatewayName, o) + } + case 1: + rr.GatewayA = net.ParseIP(l.token) + if rr.GatewayA == nil { + return nil, &ParseError{f, "bad IPSECKEY GatewayA", l}, "" + } + case 2: + rr.GatewayAAAA = net.ParseIP(l.token) + if rr.GatewayAAAA == nil { + return nil, &ParseError{f, "bad IPSECKEY GatewayAAAA", l}, "" + } + default: + return nil, &ParseError{f, "bad IPSECKEY GatewayType", l}, "" + } + + s, e, c1 := endingToString(c, "bad IPSECKEY PublicKey", f) + if e != nil { + return nil, e, c1 + } + rr.PublicKey = s + return rr, nil, c1 +} + +func setCAA(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { + rr := new(CAA) + rr.Hdr = h + l := <-c + if l.length == 0 { + return rr, nil, l.comment + } + i, err := strconv.Atoi(l.token) + if err != nil || l.err { + return nil, &ParseError{f, "bad CAA Flag", l}, "" + } + rr.Flag = uint8(i) + + <-c // zBlank + l = <-c // zString + if l.value != zString { + return nil, &ParseError{f, "bad CAA Tag", l}, "" + } + rr.Tag = l.token + + <-c // zBlank + s, e, c1 := endingToTxtSlice(c, "bad CAA Value", f) + if e != nil { + return nil, e, "" + } + if len(s) > 1 { + return nil, &ParseError{f, "bad CAA Value", l}, "" + } + rr.Value = s[0] + return rr, nil, c1 +} + +var typeToparserFunc = map[uint16]parserFunc{ + TypeAAAA: {setAAAA, false}, + TypeAFSDB: {setAFSDB, false}, + TypeA: {setA, false}, + TypeCAA: {setCAA, true}, + TypeCDS: {setCDS, true}, + TypeCDNSKEY: {setCDNSKEY, true}, + TypeCERT: {setCERT, true}, + TypeCNAME: {setCNAME, false}, + TypeDHCID: {setDHCID, true}, + TypeDLV: {setDLV, true}, + TypeDNAME: {setDNAME, false}, + TypeKEY: {setKEY, true}, + TypeDNSKEY: {setDNSKEY, true}, + TypeDS: {setDS, true}, + TypeEID: {setEID, true}, + TypeEUI48: {setEUI48, false}, + TypeEUI64: {setEUI64, false}, + TypeGID: {setGID, false}, + TypeGPOS: {setGPOS, false}, + TypeHINFO: {setHINFO, true}, + TypeHIP: {setHIP, true}, + TypeIPSECKEY: {setIPSECKEY, true}, + TypeKX: {setKX, false}, + TypeL32: {setL32, false}, + TypeL64: {setL64, false}, + TypeLOC: {setLOC, true}, + TypeLP: {setLP, false}, + TypeMB: {setMB, false}, + TypeMD: {setMD, false}, + TypeMF: {setMF, false}, + TypeMG: {setMG, false}, + TypeMINFO: {setMINFO, false}, + TypeMR: {setMR, false}, + TypeMX: {setMX, false}, + TypeNAPTR: {setNAPTR, false}, + TypeNID: {setNID, false}, + TypeNIMLOC: {setNIMLOC, true}, + TypeNINFO: {setNINFO, true}, + TypeNSAPPTR: {setNSAPPTR, false}, + TypeNSEC3PARAM: {setNSEC3PARAM, false}, + TypeNSEC3: {setNSEC3, true}, + TypeNSEC: {setNSEC, true}, + TypeNS: {setNS, false}, + TypeOPENPGPKEY: {setOPENPGPKEY, true}, + TypePTR: {setPTR, false}, + TypePX: {setPX, false}, + TypeSIG: {setSIG, true}, + TypeRKEY: {setRKEY, true}, + TypeRP: {setRP, false}, + TypeRRSIG: {setRRSIG, true}, + TypeRT: {setRT, false}, + TypeSOA: {setSOA, false}, + TypeSPF: {setSPF, true}, + TypeSRV: {setSRV, false}, + TypeSSHFP: {setSSHFP, true}, + TypeTALINK: {setTALINK, false}, + TypeTA: {setTA, true}, + TypeTLSA: {setTLSA, true}, + TypeTXT: {setTXT, true}, + TypeUID: {setUID, false}, + TypeUINFO: {setUINFO, true}, + TypeURI: {setURI, true}, + TypeWKS: {setWKS, true}, + TypeX25: {setX25, false}, } diff --git a/vendor/github.com/miekg/dns/ztypes.go b/vendor/github.com/miekg/dns/ztypes.go new file mode 100644 index 00000000000..3d0f9aef573 --- /dev/null +++ b/vendor/github.com/miekg/dns/ztypes.go @@ -0,0 +1,842 @@ +// *** DO NOT MODIFY *** +// AUTOGENERATED BY go generate + +package dns + +import ( + "encoding/base64" + "net" +) + +// TypeToRR is a map of constructors for each RR type. +var TypeToRR = map[uint16]func() RR{ + TypeA: func() RR { return new(A) }, + TypeAAAA: func() RR { return new(AAAA) }, + TypeAFSDB: func() RR { return new(AFSDB) }, + TypeANY: func() RR { return new(ANY) }, + TypeCAA: func() RR { return new(CAA) }, + TypeCDNSKEY: func() RR { return new(CDNSKEY) }, + TypeCDS: func() RR { return new(CDS) }, + TypeCERT: func() RR { return new(CERT) }, + TypeCNAME: func() RR { return new(CNAME) }, + TypeDHCID: func() RR { return new(DHCID) }, + TypeDLV: func() RR { return new(DLV) }, + TypeDNAME: func() RR { return new(DNAME) }, + TypeDNSKEY: func() RR { return new(DNSKEY) }, + TypeDS: func() RR { return new(DS) }, + TypeEID: func() RR { return new(EID) }, + TypeEUI48: func() RR { return new(EUI48) }, + TypeEUI64: func() RR { return new(EUI64) }, + TypeGID: func() RR { return new(GID) }, + TypeGPOS: func() RR { return new(GPOS) }, + TypeHINFO: func() RR { return new(HINFO) }, + TypeHIP: func() RR { return new(HIP) }, + TypeIPSECKEY: func() RR { return new(IPSECKEY) }, + TypeKEY: func() RR { return new(KEY) }, + TypeKX: func() RR { return new(KX) }, + TypeL32: func() RR { return new(L32) }, + TypeL64: func() RR { return new(L64) }, + TypeLOC: func() RR { return new(LOC) }, + TypeLP: func() RR { return new(LP) }, + TypeMB: func() RR { return new(MB) }, + TypeMD: func() RR { return new(MD) }, + TypeMF: func() RR { return new(MF) }, + TypeMG: func() RR { return new(MG) }, + TypeMINFO: func() RR { return new(MINFO) }, + TypeMR: func() RR { return new(MR) }, + TypeMX: func() RR { return new(MX) }, + TypeNAPTR: func() RR { return new(NAPTR) }, + TypeNID: func() RR { return new(NID) }, + TypeNIMLOC: func() RR { return new(NIMLOC) }, + TypeNINFO: func() RR { return new(NINFO) }, + TypeNS: func() RR { return new(NS) }, + TypeNSAPPTR: func() RR { return new(NSAPPTR) }, + TypeNSEC: func() RR { return new(NSEC) }, + TypeNSEC3: func() RR { return new(NSEC3) }, + TypeNSEC3PARAM: func() RR { return new(NSEC3PARAM) }, + TypeOPENPGPKEY: func() RR { return new(OPENPGPKEY) }, + TypeOPT: func() RR { return new(OPT) }, + TypePTR: func() RR { return new(PTR) }, + TypePX: func() RR { return new(PX) }, + TypeRKEY: func() RR { return new(RKEY) }, + TypeRP: func() RR { return new(RP) }, + TypeRRSIG: func() RR { return new(RRSIG) }, + TypeRT: func() RR { return new(RT) }, + TypeSIG: func() RR { return new(SIG) }, + TypeSOA: func() RR { return new(SOA) }, + TypeSPF: func() RR { return new(SPF) }, + TypeSRV: func() RR { return new(SRV) }, + TypeSSHFP: func() RR { return new(SSHFP) }, + TypeTA: func() RR { return new(TA) }, + TypeTALINK: func() RR { return new(TALINK) }, + TypeTKEY: func() RR { return new(TKEY) }, + TypeTLSA: func() RR { return new(TLSA) }, + TypeTSIG: func() RR { return new(TSIG) }, + TypeTXT: func() RR { return new(TXT) }, + TypeUID: func() RR { return new(UID) }, + TypeUINFO: func() RR { return new(UINFO) }, + TypeURI: func() RR { return new(URI) }, + TypeWKS: func() RR { return new(WKS) }, + TypeX25: func() RR { return new(X25) }, +} + +// TypeToString is a map of strings for each RR type. +var TypeToString = map[uint16]string{ + TypeA: "A", + TypeAAAA: "AAAA", + TypeAFSDB: "AFSDB", + TypeANY: "ANY", + TypeATMA: "ATMA", + TypeAXFR: "AXFR", + TypeCAA: "CAA", + TypeCDNSKEY: "CDNSKEY", + TypeCDS: "CDS", + TypeCERT: "CERT", + TypeCNAME: "CNAME", + TypeDHCID: "DHCID", + TypeDLV: "DLV", + TypeDNAME: "DNAME", + TypeDNSKEY: "DNSKEY", + TypeDS: "DS", + TypeEID: "EID", + TypeEUI48: "EUI48", + TypeEUI64: "EUI64", + TypeGID: "GID", + TypeGPOS: "GPOS", + TypeHINFO: "HINFO", + TypeHIP: "HIP", + TypeIPSECKEY: "IPSECKEY", + TypeISDN: "ISDN", + TypeIXFR: "IXFR", + TypeKEY: "KEY", + TypeKX: "KX", + TypeL32: "L32", + TypeL64: "L64", + TypeLOC: "LOC", + TypeLP: "LP", + TypeMAILA: "MAILA", + TypeMAILB: "MAILB", + TypeMB: "MB", + TypeMD: "MD", + TypeMF: "MF", + TypeMG: "MG", + TypeMINFO: "MINFO", + TypeMR: "MR", + TypeMX: "MX", + TypeNAPTR: "NAPTR", + TypeNID: "NID", + TypeNIMLOC: "NIMLOC", + TypeNINFO: "NINFO", + TypeNS: "NS", + TypeNSEC: "NSEC", + TypeNSEC3: "NSEC3", + TypeNSEC3PARAM: "NSEC3PARAM", + TypeNULL: "NULL", + TypeNXT: "NXT", + TypeNone: "None", + TypeOPENPGPKEY: "OPENPGPKEY", + TypeOPT: "OPT", + TypePTR: "PTR", + TypePX: "PX", + TypeRKEY: "RKEY", + TypeRP: "RP", + TypeRRSIG: "RRSIG", + TypeRT: "RT", + TypeReserved: "Reserved", + TypeSIG: "SIG", + TypeSOA: "SOA", + TypeSPF: "SPF", + TypeSRV: "SRV", + TypeSSHFP: "SSHFP", + TypeTA: "TA", + TypeTALINK: "TALINK", + TypeTKEY: "TKEY", + TypeTLSA: "TLSA", + TypeTSIG: "TSIG", + TypeTXT: "TXT", + TypeUID: "UID", + TypeUINFO: "UINFO", + TypeUNSPEC: "UNSPEC", + TypeURI: "URI", + TypeWKS: "WKS", + TypeX25: "X25", + TypeNSAPPTR: "NSAP-PTR", +} + +// Header() functions +func (rr *A) Header() *RR_Header { return &rr.Hdr } +func (rr *AAAA) Header() *RR_Header { return &rr.Hdr } +func (rr *AFSDB) Header() *RR_Header { return &rr.Hdr } +func (rr *ANY) Header() *RR_Header { return &rr.Hdr } +func (rr *CAA) Header() *RR_Header { return &rr.Hdr } +func (rr *CDNSKEY) Header() *RR_Header { return &rr.Hdr } +func (rr *CDS) Header() *RR_Header { return &rr.Hdr } +func (rr *CERT) Header() *RR_Header { return &rr.Hdr } +func (rr *CNAME) Header() *RR_Header { return &rr.Hdr } +func (rr *DHCID) Header() *RR_Header { return &rr.Hdr } +func (rr *DLV) Header() *RR_Header { return &rr.Hdr } +func (rr *DNAME) Header() *RR_Header { return &rr.Hdr } +func (rr *DNSKEY) Header() *RR_Header { return &rr.Hdr } +func (rr *DS) Header() *RR_Header { return &rr.Hdr } +func (rr *EID) Header() *RR_Header { return &rr.Hdr } +func (rr *EUI48) Header() *RR_Header { return &rr.Hdr } +func (rr *EUI64) Header() *RR_Header { return &rr.Hdr } +func (rr *GID) Header() *RR_Header { return &rr.Hdr } +func (rr *GPOS) Header() *RR_Header { return &rr.Hdr } +func (rr *HINFO) Header() *RR_Header { return &rr.Hdr } +func (rr *HIP) Header() *RR_Header { return &rr.Hdr } +func (rr *IPSECKEY) Header() *RR_Header { return &rr.Hdr } +func (rr *KEY) Header() *RR_Header { return &rr.Hdr } +func (rr *KX) Header() *RR_Header { return &rr.Hdr } +func (rr *L32) Header() *RR_Header { return &rr.Hdr } +func (rr *L64) Header() *RR_Header { return &rr.Hdr } +func (rr *LOC) Header() *RR_Header { return &rr.Hdr } +func (rr *LP) Header() *RR_Header { return &rr.Hdr } +func (rr *MB) Header() *RR_Header { return &rr.Hdr } +func (rr *MD) Header() *RR_Header { return &rr.Hdr } +func (rr *MF) Header() *RR_Header { return &rr.Hdr } +func (rr *MG) Header() *RR_Header { return &rr.Hdr } +func (rr *MINFO) Header() *RR_Header { return &rr.Hdr } +func (rr *MR) Header() *RR_Header { return &rr.Hdr } +func (rr *MX) Header() *RR_Header { return &rr.Hdr } +func (rr *NAPTR) Header() *RR_Header { return &rr.Hdr } +func (rr *NID) Header() *RR_Header { return &rr.Hdr } +func (rr *NIMLOC) Header() *RR_Header { return &rr.Hdr } +func (rr *NINFO) Header() *RR_Header { return &rr.Hdr } +func (rr *NS) Header() *RR_Header { return &rr.Hdr } +func (rr *NSAPPTR) Header() *RR_Header { return &rr.Hdr } +func (rr *NSEC) Header() *RR_Header { return &rr.Hdr } +func (rr *NSEC3) Header() *RR_Header { return &rr.Hdr } +func (rr *NSEC3PARAM) Header() *RR_Header { return &rr.Hdr } +func (rr *OPENPGPKEY) Header() *RR_Header { return &rr.Hdr } +func (rr *OPT) Header() *RR_Header { return &rr.Hdr } +func (rr *PTR) Header() *RR_Header { return &rr.Hdr } +func (rr *PX) Header() *RR_Header { return &rr.Hdr } +func (rr *RFC3597) Header() *RR_Header { return &rr.Hdr } +func (rr *RKEY) Header() *RR_Header { return &rr.Hdr } +func (rr *RP) Header() *RR_Header { return &rr.Hdr } +func (rr *RRSIG) Header() *RR_Header { return &rr.Hdr } +func (rr *RT) Header() *RR_Header { return &rr.Hdr } +func (rr *SIG) Header() *RR_Header { return &rr.Hdr } +func (rr *SOA) Header() *RR_Header { return &rr.Hdr } +func (rr *SPF) Header() *RR_Header { return &rr.Hdr } +func (rr *SRV) Header() *RR_Header { return &rr.Hdr } +func (rr *SSHFP) Header() *RR_Header { return &rr.Hdr } +func (rr *TA) Header() *RR_Header { return &rr.Hdr } +func (rr *TALINK) Header() *RR_Header { return &rr.Hdr } +func (rr *TKEY) Header() *RR_Header { return &rr.Hdr } +func (rr *TLSA) Header() *RR_Header { return &rr.Hdr } +func (rr *TSIG) Header() *RR_Header { return &rr.Hdr } +func (rr *TXT) Header() *RR_Header { return &rr.Hdr } +func (rr *UID) Header() *RR_Header { return &rr.Hdr } +func (rr *UINFO) Header() *RR_Header { return &rr.Hdr } +func (rr *URI) Header() *RR_Header { return &rr.Hdr } +func (rr *WKS) Header() *RR_Header { return &rr.Hdr } +func (rr *X25) Header() *RR_Header { return &rr.Hdr } + +// len() functions +func (rr *A) len() int { + l := rr.Hdr.len() + l += net.IPv4len // A + return l +} +func (rr *AAAA) len() int { + l := rr.Hdr.len() + l += net.IPv6len // AAAA + return l +} +func (rr *AFSDB) len() int { + l := rr.Hdr.len() + l += 2 // Subtype + l += len(rr.Hostname) + 1 + return l +} +func (rr *ANY) len() int { + l := rr.Hdr.len() + return l +} +func (rr *CAA) len() int { + l := rr.Hdr.len() + l += 1 // Flag + l += len(rr.Tag) + 1 + l += len(rr.Value) + return l +} +func (rr *CERT) len() int { + l := rr.Hdr.len() + l += 2 // Type + l += 2 // KeyTag + l += 1 // Algorithm + l += base64.StdEncoding.DecodedLen(len(rr.Certificate)) + return l +} +func (rr *CNAME) len() int { + l := rr.Hdr.len() + l += len(rr.Target) + 1 + return l +} +func (rr *DHCID) len() int { + l := rr.Hdr.len() + l += base64.StdEncoding.DecodedLen(len(rr.Digest)) + return l +} +func (rr *DNAME) len() int { + l := rr.Hdr.len() + l += len(rr.Target) + 1 + return l +} +func (rr *DNSKEY) len() int { + l := rr.Hdr.len() + l += 2 // Flags + l += 1 // Protocol + l += 1 // Algorithm + l += base64.StdEncoding.DecodedLen(len(rr.PublicKey)) + return l +} +func (rr *DS) len() int { + l := rr.Hdr.len() + l += 2 // KeyTag + l += 1 // Algorithm + l += 1 // DigestType + l += len(rr.Digest)/2 + 1 + return l +} +func (rr *EID) len() int { + l := rr.Hdr.len() + l += len(rr.Endpoint)/2 + 1 + return l +} +func (rr *EUI48) len() int { + l := rr.Hdr.len() + l += 6 // Address + return l +} +func (rr *EUI64) len() int { + l := rr.Hdr.len() + l += 8 // Address + return l +} +func (rr *GID) len() int { + l := rr.Hdr.len() + l += 4 // Gid + return l +} +func (rr *GPOS) len() int { + l := rr.Hdr.len() + l += len(rr.Longitude) + 1 + l += len(rr.Latitude) + 1 + l += len(rr.Altitude) + 1 + return l +} +func (rr *HINFO) len() int { + l := rr.Hdr.len() + l += len(rr.Cpu) + 1 + l += len(rr.Os) + 1 + return l +} +func (rr *HIP) len() int { + l := rr.Hdr.len() + l += 1 // HitLength + l += 1 // PublicKeyAlgorithm + l += 2 // PublicKeyLength + l += len(rr.Hit)/2 + 1 + l += base64.StdEncoding.DecodedLen(len(rr.PublicKey)) + for _, x := range rr.RendezvousServers { + l += len(x) + 1 + } + return l +} +func (rr *KX) len() int { + l := rr.Hdr.len() + l += 2 // Preference + l += len(rr.Exchanger) + 1 + return l +} +func (rr *L32) len() int { + l := rr.Hdr.len() + l += 2 // Preference + l += net.IPv4len // Locator32 + return l +} +func (rr *L64) len() int { + l := rr.Hdr.len() + l += 2 // Preference + l += 8 // Locator64 + return l +} +func (rr *LOC) len() int { + l := rr.Hdr.len() + l += 1 // Version + l += 1 // Size + l += 1 // HorizPre + l += 1 // VertPre + l += 4 // Latitude + l += 4 // Longitude + l += 4 // Altitude + return l +} +func (rr *LP) len() int { + l := rr.Hdr.len() + l += 2 // Preference + l += len(rr.Fqdn) + 1 + return l +} +func (rr *MB) len() int { + l := rr.Hdr.len() + l += len(rr.Mb) + 1 + return l +} +func (rr *MD) len() int { + l := rr.Hdr.len() + l += len(rr.Md) + 1 + return l +} +func (rr *MF) len() int { + l := rr.Hdr.len() + l += len(rr.Mf) + 1 + return l +} +func (rr *MG) len() int { + l := rr.Hdr.len() + l += len(rr.Mg) + 1 + return l +} +func (rr *MINFO) len() int { + l := rr.Hdr.len() + l += len(rr.Rmail) + 1 + l += len(rr.Email) + 1 + return l +} +func (rr *MR) len() int { + l := rr.Hdr.len() + l += len(rr.Mr) + 1 + return l +} +func (rr *MX) len() int { + l := rr.Hdr.len() + l += 2 // Preference + l += len(rr.Mx) + 1 + return l +} +func (rr *NAPTR) len() int { + l := rr.Hdr.len() + l += 2 // Order + l += 2 // Preference + l += len(rr.Flags) + 1 + l += len(rr.Service) + 1 + l += len(rr.Regexp) + 1 + l += len(rr.Replacement) + 1 + return l +} +func (rr *NID) len() int { + l := rr.Hdr.len() + l += 2 // Preference + l += 8 // NodeID + return l +} +func (rr *NIMLOC) len() int { + l := rr.Hdr.len() + l += len(rr.Locator)/2 + 1 + return l +} +func (rr *NINFO) len() int { + l := rr.Hdr.len() + for _, x := range rr.ZSData { + l += len(x) + 1 + } + return l +} +func (rr *NS) len() int { + l := rr.Hdr.len() + l += len(rr.Ns) + 1 + return l +} +func (rr *NSAPPTR) len() int { + l := rr.Hdr.len() + l += len(rr.Ptr) + 1 + return l +} +func (rr *NSEC3PARAM) len() int { + l := rr.Hdr.len() + l += 1 // Hash + l += 1 // Flags + l += 2 // Iterations + l += 1 // SaltLength + l += len(rr.Salt)/2 + 1 + return l +} +func (rr *OPENPGPKEY) len() int { + l := rr.Hdr.len() + l += base64.StdEncoding.DecodedLen(len(rr.PublicKey)) + return l +} +func (rr *PTR) len() int { + l := rr.Hdr.len() + l += len(rr.Ptr) + 1 + return l +} +func (rr *PX) len() int { + l := rr.Hdr.len() + l += 2 // Preference + l += len(rr.Map822) + 1 + l += len(rr.Mapx400) + 1 + return l +} +func (rr *RFC3597) len() int { + l := rr.Hdr.len() + l += len(rr.Rdata)/2 + 1 + return l +} +func (rr *RKEY) len() int { + l := rr.Hdr.len() + l += 2 // Flags + l += 1 // Protocol + l += 1 // Algorithm + l += base64.StdEncoding.DecodedLen(len(rr.PublicKey)) + return l +} +func (rr *RP) len() int { + l := rr.Hdr.len() + l += len(rr.Mbox) + 1 + l += len(rr.Txt) + 1 + return l +} +func (rr *RRSIG) len() int { + l := rr.Hdr.len() + l += 2 // TypeCovered + l += 1 // Algorithm + l += 1 // Labels + l += 4 // OrigTtl + l += 4 // Expiration + l += 4 // Inception + l += 2 // KeyTag + l += len(rr.SignerName) + 1 + l += base64.StdEncoding.DecodedLen(len(rr.Signature)) + return l +} +func (rr *RT) len() int { + l := rr.Hdr.len() + l += 2 // Preference + l += len(rr.Host) + 1 + return l +} +func (rr *SOA) len() int { + l := rr.Hdr.len() + l += len(rr.Ns) + 1 + l += len(rr.Mbox) + 1 + l += 4 // Serial + l += 4 // Refresh + l += 4 // Retry + l += 4 // Expire + l += 4 // Minttl + return l +} +func (rr *SPF) len() int { + l := rr.Hdr.len() + for _, x := range rr.Txt { + l += len(x) + 1 + } + return l +} +func (rr *SRV) len() int { + l := rr.Hdr.len() + l += 2 // Priority + l += 2 // Weight + l += 2 // Port + l += len(rr.Target) + 1 + return l +} +func (rr *SSHFP) len() int { + l := rr.Hdr.len() + l += 1 // Algorithm + l += 1 // Type + l += len(rr.FingerPrint)/2 + 1 + return l +} +func (rr *TA) len() int { + l := rr.Hdr.len() + l += 2 // KeyTag + l += 1 // Algorithm + l += 1 // DigestType + l += len(rr.Digest)/2 + 1 + return l +} +func (rr *TALINK) len() int { + l := rr.Hdr.len() + l += len(rr.PreviousName) + 1 + l += len(rr.NextName) + 1 + return l +} +func (rr *TKEY) len() int { + l := rr.Hdr.len() + l += len(rr.Algorithm) + 1 + l += 4 // Inception + l += 4 // Expiration + l += 2 // Mode + l += 2 // Error + l += 2 // KeySize + l += len(rr.Key) + 1 + l += 2 // OtherLen + l += len(rr.OtherData) + 1 + return l +} +func (rr *TLSA) len() int { + l := rr.Hdr.len() + l += 1 // Usage + l += 1 // Selector + l += 1 // MatchingType + l += len(rr.Certificate)/2 + 1 + return l +} +func (rr *TSIG) len() int { + l := rr.Hdr.len() + l += len(rr.Algorithm) + 1 + l += 6 // TimeSigned + l += 2 // Fudge + l += 2 // MACSize + l += len(rr.MAC)/2 + 1 + l += 2 // OrigId + l += 2 // Error + l += 2 // OtherLen + l += len(rr.OtherData)/2 + 1 + return l +} +func (rr *TXT) len() int { + l := rr.Hdr.len() + for _, x := range rr.Txt { + l += len(x) + 1 + } + return l +} +func (rr *UID) len() int { + l := rr.Hdr.len() + l += 4 // Uid + return l +} +func (rr *UINFO) len() int { + l := rr.Hdr.len() + l += len(rr.Uinfo) + 1 + return l +} +func (rr *URI) len() int { + l := rr.Hdr.len() + l += 2 // Priority + l += 2 // Weight + l += len(rr.Target) + return l +} +func (rr *X25) len() int { + l := rr.Hdr.len() + l += len(rr.PSDNAddress) + 1 + return l +} + +// copy() functions +func (rr *A) copy() RR { + return &A{*rr.Hdr.copyHeader(), copyIP(rr.A)} +} +func (rr *AAAA) copy() RR { + return &AAAA{*rr.Hdr.copyHeader(), copyIP(rr.AAAA)} +} +func (rr *AFSDB) copy() RR { + return &AFSDB{*rr.Hdr.copyHeader(), rr.Subtype, rr.Hostname} +} +func (rr *ANY) copy() RR { + return &ANY{*rr.Hdr.copyHeader()} +} +func (rr *CAA) copy() RR { + return &CAA{*rr.Hdr.copyHeader(), rr.Flag, rr.Tag, rr.Value} +} +func (rr *CERT) copy() RR { + return &CERT{*rr.Hdr.copyHeader(), rr.Type, rr.KeyTag, rr.Algorithm, rr.Certificate} +} +func (rr *CNAME) copy() RR { + return &CNAME{*rr.Hdr.copyHeader(), rr.Target} +} +func (rr *DHCID) copy() RR { + return &DHCID{*rr.Hdr.copyHeader(), rr.Digest} +} +func (rr *DNAME) copy() RR { + return &DNAME{*rr.Hdr.copyHeader(), rr.Target} +} +func (rr *DNSKEY) copy() RR { + return &DNSKEY{*rr.Hdr.copyHeader(), rr.Flags, rr.Protocol, rr.Algorithm, rr.PublicKey} +} +func (rr *DS) copy() RR { + return &DS{*rr.Hdr.copyHeader(), rr.KeyTag, rr.Algorithm, rr.DigestType, rr.Digest} +} +func (rr *EID) copy() RR { + return &EID{*rr.Hdr.copyHeader(), rr.Endpoint} +} +func (rr *EUI48) copy() RR { + return &EUI48{*rr.Hdr.copyHeader(), rr.Address} +} +func (rr *EUI64) copy() RR { + return &EUI64{*rr.Hdr.copyHeader(), rr.Address} +} +func (rr *GID) copy() RR { + return &GID{*rr.Hdr.copyHeader(), rr.Gid} +} +func (rr *GPOS) copy() RR { + return &GPOS{*rr.Hdr.copyHeader(), rr.Longitude, rr.Latitude, rr.Altitude} +} +func (rr *HINFO) copy() RR { + return &HINFO{*rr.Hdr.copyHeader(), rr.Cpu, rr.Os} +} +func (rr *HIP) copy() RR { + RendezvousServers := make([]string, len(rr.RendezvousServers)) + copy(RendezvousServers, rr.RendezvousServers) + return &HIP{*rr.Hdr.copyHeader(), rr.HitLength, rr.PublicKeyAlgorithm, rr.PublicKeyLength, rr.Hit, rr.PublicKey, RendezvousServers} +} +func (rr *IPSECKEY) copy() RR { + return &IPSECKEY{*rr.Hdr.copyHeader(), rr.Precedence, rr.GatewayType, rr.Algorithm, copyIP(rr.GatewayA), copyIP(rr.GatewayAAAA), rr.GatewayName, rr.PublicKey} +} +func (rr *KX) copy() RR { + return &KX{*rr.Hdr.copyHeader(), rr.Preference, rr.Exchanger} +} +func (rr *L32) copy() RR { + return &L32{*rr.Hdr.copyHeader(), rr.Preference, copyIP(rr.Locator32)} +} +func (rr *L64) copy() RR { + return &L64{*rr.Hdr.copyHeader(), rr.Preference, rr.Locator64} +} +func (rr *LOC) copy() RR { + return &LOC{*rr.Hdr.copyHeader(), rr.Version, rr.Size, rr.HorizPre, rr.VertPre, rr.Latitude, rr.Longitude, rr.Altitude} +} +func (rr *LP) copy() RR { + return &LP{*rr.Hdr.copyHeader(), rr.Preference, rr.Fqdn} +} +func (rr *MB) copy() RR { + return &MB{*rr.Hdr.copyHeader(), rr.Mb} +} +func (rr *MD) copy() RR { + return &MD{*rr.Hdr.copyHeader(), rr.Md} +} +func (rr *MF) copy() RR { + return &MF{*rr.Hdr.copyHeader(), rr.Mf} +} +func (rr *MG) copy() RR { + return &MG{*rr.Hdr.copyHeader(), rr.Mg} +} +func (rr *MINFO) copy() RR { + return &MINFO{*rr.Hdr.copyHeader(), rr.Rmail, rr.Email} +} +func (rr *MR) copy() RR { + return &MR{*rr.Hdr.copyHeader(), rr.Mr} +} +func (rr *MX) copy() RR { + return &MX{*rr.Hdr.copyHeader(), rr.Preference, rr.Mx} +} +func (rr *NAPTR) copy() RR { + return &NAPTR{*rr.Hdr.copyHeader(), rr.Order, rr.Preference, rr.Flags, rr.Service, rr.Regexp, rr.Replacement} +} +func (rr *NID) copy() RR { + return &NID{*rr.Hdr.copyHeader(), rr.Preference, rr.NodeID} +} +func (rr *NIMLOC) copy() RR { + return &NIMLOC{*rr.Hdr.copyHeader(), rr.Locator} +} +func (rr *NINFO) copy() RR { + ZSData := make([]string, len(rr.ZSData)) + copy(ZSData, rr.ZSData) + return &NINFO{*rr.Hdr.copyHeader(), ZSData} +} +func (rr *NS) copy() RR { + return &NS{*rr.Hdr.copyHeader(), rr.Ns} +} +func (rr *NSAPPTR) copy() RR { + return &NSAPPTR{*rr.Hdr.copyHeader(), rr.Ptr} +} +func (rr *NSEC) copy() RR { + TypeBitMap := make([]uint16, len(rr.TypeBitMap)) + copy(TypeBitMap, rr.TypeBitMap) + return &NSEC{*rr.Hdr.copyHeader(), rr.NextDomain, TypeBitMap} +} +func (rr *NSEC3) copy() RR { + TypeBitMap := make([]uint16, len(rr.TypeBitMap)) + copy(TypeBitMap, rr.TypeBitMap) + return &NSEC3{*rr.Hdr.copyHeader(), rr.Hash, rr.Flags, rr.Iterations, rr.SaltLength, rr.Salt, rr.HashLength, rr.NextDomain, TypeBitMap} +} +func (rr *NSEC3PARAM) copy() RR { + return &NSEC3PARAM{*rr.Hdr.copyHeader(), rr.Hash, rr.Flags, rr.Iterations, rr.SaltLength, rr.Salt} +} +func (rr *OPENPGPKEY) copy() RR { + return &OPENPGPKEY{*rr.Hdr.copyHeader(), rr.PublicKey} +} +func (rr *OPT) copy() RR { + Option := make([]EDNS0, len(rr.Option)) + copy(Option, rr.Option) + return &OPT{*rr.Hdr.copyHeader(), Option} +} +func (rr *PTR) copy() RR { + return &PTR{*rr.Hdr.copyHeader(), rr.Ptr} +} +func (rr *PX) copy() RR { + return &PX{*rr.Hdr.copyHeader(), rr.Preference, rr.Map822, rr.Mapx400} +} +func (rr *RFC3597) copy() RR { + return &RFC3597{*rr.Hdr.copyHeader(), rr.Rdata} +} +func (rr *RKEY) copy() RR { + return &RKEY{*rr.Hdr.copyHeader(), rr.Flags, rr.Protocol, rr.Algorithm, rr.PublicKey} +} +func (rr *RP) copy() RR { + return &RP{*rr.Hdr.copyHeader(), rr.Mbox, rr.Txt} +} +func (rr *RRSIG) copy() RR { + return &RRSIG{*rr.Hdr.copyHeader(), rr.TypeCovered, rr.Algorithm, rr.Labels, rr.OrigTtl, rr.Expiration, rr.Inception, rr.KeyTag, rr.SignerName, rr.Signature} +} +func (rr *RT) copy() RR { + return &RT{*rr.Hdr.copyHeader(), rr.Preference, rr.Host} +} +func (rr *SOA) copy() RR { + return &SOA{*rr.Hdr.copyHeader(), rr.Ns, rr.Mbox, rr.Serial, rr.Refresh, rr.Retry, rr.Expire, rr.Minttl} +} +func (rr *SPF) copy() RR { + Txt := make([]string, len(rr.Txt)) + copy(Txt, rr.Txt) + return &SPF{*rr.Hdr.copyHeader(), Txt} +} +func (rr *SRV) copy() RR { + return &SRV{*rr.Hdr.copyHeader(), rr.Priority, rr.Weight, rr.Port, rr.Target} +} +func (rr *SSHFP) copy() RR { + return &SSHFP{*rr.Hdr.copyHeader(), rr.Algorithm, rr.Type, rr.FingerPrint} +} +func (rr *TA) copy() RR { + return &TA{*rr.Hdr.copyHeader(), rr.KeyTag, rr.Algorithm, rr.DigestType, rr.Digest} +} +func (rr *TALINK) copy() RR { + return &TALINK{*rr.Hdr.copyHeader(), rr.PreviousName, rr.NextName} +} +func (rr *TKEY) copy() RR { + return &TKEY{*rr.Hdr.copyHeader(), rr.Algorithm, rr.Inception, rr.Expiration, rr.Mode, rr.Error, rr.KeySize, rr.Key, rr.OtherLen, rr.OtherData} +} +func (rr *TLSA) copy() RR { + return &TLSA{*rr.Hdr.copyHeader(), rr.Usage, rr.Selector, rr.MatchingType, rr.Certificate} +} +func (rr *TSIG) copy() RR { + return &TSIG{*rr.Hdr.copyHeader(), rr.Algorithm, rr.TimeSigned, rr.Fudge, rr.MACSize, rr.MAC, rr.OrigId, rr.Error, rr.OtherLen, rr.OtherData} +} +func (rr *TXT) copy() RR { + Txt := make([]string, len(rr.Txt)) + copy(Txt, rr.Txt) + return &TXT{*rr.Hdr.copyHeader(), Txt} +} +func (rr *UID) copy() RR { + return &UID{*rr.Hdr.copyHeader(), rr.Uid} +} +func (rr *UINFO) copy() RR { + return &UINFO{*rr.Hdr.copyHeader(), rr.Uinfo} +} +func (rr *URI) copy() RR { + return &URI{*rr.Hdr.copyHeader(), rr.Priority, rr.Weight, rr.Target} +} +func (rr *WKS) copy() RR { + BitMap := make([]uint16, len(rr.BitMap)) + copy(BitMap, rr.BitMap) + return &WKS{*rr.Hdr.copyHeader(), copyIP(rr.Address), rr.Protocol, BitMap} +} +func (rr *X25) copy() RR { + return &X25{*rr.Hdr.copyHeader(), rr.PSDNAddress} +} diff --git a/vendor/github.com/skynetservices/skydns/msg/service.go b/vendor/github.com/skynetservices/skydns/msg/service.go index f0632e98471..e2d4a603bbe 100644 --- a/vendor/github.com/skynetservices/skydns/msg/service.go +++ b/vendor/github.com/skynetservices/skydns/msg/service.go @@ -12,6 +12,14 @@ import ( "github.com/miekg/dns" ) +// PathPrefix is the prefix used to store SkyDNS data in the backend. +// It defaults to `skydns`. +// You can change it by set `path-prefix` configuration or SKYDNS_PATH_PREFIX env. variable. +// Then: +// The SkyDNS's configuration object should be stored under the key "/mydns/config"; +// The etcd path of domain `service.staging.skydns.local.` will be "/mydns/local/skydns/staging/service". +var PathPrefix string = "skydns" + // This *is* the rdata from a SRV record, but with a twist. // Host (Target in SRV) must be a domain name, but if it looks like an IP // address (4/6), we will treat it like an IP address. @@ -29,7 +37,7 @@ type Service struct { // the record lives to a DNS name and use this as the srv.Target. When // TargetStrip > 0 we strip the left most TargetStrip labels from the // DNS name. - TargetStrip int `json:"targetstrip",omitempty"` + TargetStrip int `json:"targetstrip,omitempty"` // Group is used to group (or *not* to group) different services // together. Services with an identical Group are returned in the same @@ -42,17 +50,7 @@ type Service struct { // NewSRV returns a new SRV record based on the Service. func (s *Service) NewSRV(name string, weight uint16) *dns.SRV { - host := dns.Fqdn(s.Host) - - offset, end := 0, false - for i := 0; i < s.TargetStrip; i++ { - offset, end = dns.NextLabel(host, offset) - } - if end { - // We overshot the name, use the orignal one. - offset = 0 - } - host = host[offset:] + host := targetStrip(dns.Fqdn(s.Host), s.TargetStrip) return &dns.SRV{Hdr: dns.RR_Header{Name: name, Rrtype: dns.TypeSRV, Class: dns.ClassINET, Ttl: s.Ttl}, Priority: uint16(s.Priority), Weight: weight, Port: uint16(s.Port), Target: host} @@ -60,17 +58,7 @@ func (s *Service) NewSRV(name string, weight uint16) *dns.SRV { // NewMX returns a new MX record based on the Service. func (s *Service) NewMX(name string) *dns.MX { - host := dns.Fqdn(s.Host) - - offset, end := 0, false - for i := 0; i < s.TargetStrip; i++ { - offset, end = dns.NextLabel(host, offset) - } - if end { - // We overshot the name, use the orignal one. - offset = 0 - } - host = host[offset:] + host := targetStrip(dns.Fqdn(s.Host), s.TargetStrip) return &dns.MX{Hdr: dns.RR_Header{Name: name, Rrtype: dns.TypeMX, Class: dns.ClassINET, Ttl: s.Ttl}, Preference: uint16(s.Priority), Mx: host} @@ -118,10 +106,10 @@ func PathWithWildcard(s string) (string, bool) { } for i, k := range l { if k == "*" || k == "any" { - return path.Join(append([]string{"/skydns/"}, l[:i]...)...), true + return path.Join(append([]string{"/" + PathPrefix + "/"}, l[:i]...)...), true } } - return path.Join(append([]string{"/skydns/"}, l...)...), false + return path.Join(append([]string{"/" + PathPrefix + "/"}, l...)...), false } // Path converts a domainname to an etcd path. If s looks like service.staging.skydns.local., @@ -131,7 +119,7 @@ func Path(s string) string { for i, j := 0, len(l)-1; i < j; i, j = i+1, j-1 { l[i], l[j] = l[j], l[i] } - return path.Join(append([]string{"/skydns/"}, l...)...) + return path.Join(append([]string{"/" + PathPrefix + "/"}, l...)...) } // Domain is the opposite of Path. @@ -213,3 +201,21 @@ func split255(s string) []string { return sx } + +// targetStrip strips "targetstrip" labels from the left side of the fully qualified name. +func targetStrip(name string, targetStrip int) string { + if targetStrip == 0 { + return name + } + + offset, end := 0, false + for i := 0; i < targetStrip; i++ { + offset, end = dns.NextLabel(name, offset) + } + if end { + // We overshot the name, use the orignal one. + offset = 0 + } + name = name[offset:] + return name +}