diff options
author | 2016-09-23 09:14:12 +0100 | |
---|---|---|
committer | 2016-09-23 09:14:12 +0100 | |
commit | 090d1872e92b3becd198f92baa79869389212750 (patch) | |
tree | 9016e01a543412291ec9656bad26ea880772d0a5 | |
parent | cacbb0e0b1cfcd7f4e95b76358a5332d6d90e6ea (diff) | |
download | coredns-090d1872e92b3becd198f92baa79869389212750.tar.gz coredns-090d1872e92b3becd198f92baa79869389212750.tar.zst coredns-090d1872e92b3becd198f92baa79869389212750.zip |
Golint2 (#280)
* Fix linter errors
* More linting fixes
* More docs and making members private that dont need to be public
* Fix linter errors
* More linting fixes
* More docs and making members private that dont need to be public
* More lint fixes
This leaves:
~~~
middleware/kubernetes/nametemplate/nametemplate.go:64:6: exported type NameTemplate should have comment or be unexported
middleware/kubernetes/nametemplate/nametemplate.go:71:1: exported method NameTemplate.SetTemplate should have comment or be unexported
middleware/kubernetes/nametemplate/nametemplate.go:108:1: exported method NameTemplate.GetZoneFromSegmentArray should have comment or be unexported
middleware/kubernetes/nametemplate/nametemplate.go:116:1: exported method NameTemplate.GetNamespaceFromSegmentArray should have comment or be unexported
middleware/kubernetes/nametemplate/nametemplate.go:120:1: exported method NameTemplate.GetServiceFromSegmentArray should have comment or be unexported
middleware/kubernetes/nametemplate/nametemplate.go:124:1: exported method NameTemplate.GetTypeFromSegmentArray should have comment or be unexported
middleware/kubernetes/nametemplate/nametemplate.go:135:1: exported method NameTemplate.GetSymbolFromSegmentArray should have comment or be unexported
middleware/kubernetes/nametemplate/nametemplate.go:167:1: exported method NameTemplate.IsValid should have comment or be unexported
middleware/kubernetes/nametemplate/nametemplate.go:182:6: exported type NameValues should have comment or be unexported
middleware/kubernetes/util/util.go:1:1: package comment should be of the form "Package util ..."
middleware/kubernetes/util/util.go:27:2: exported const WildcardStar should have comment (or a comment on this block) or be unexported
middleware/proxy/lookup.go:66:1: exported method Proxy.Forward should have comment or be unexported
middleware/proxy/proxy.go:24:6: exported type Client should have comment or be unexported
middleware/proxy/proxy.go:107:1: exported function Clients should have comment or be unexported
middleware/proxy/reverseproxy.go:10:6: exported type ReverseProxy should have comment or be unexported
middleware/proxy/reverseproxy.go:16:1: exported method ReverseProxy.ServeDNS should have comment or be unexported
middleware/proxy/upstream.go:42:6: exported type Options should have comment or be unexported
~~~
I plan on reworking the proxy anyway, so I'll leave that be.
61 files changed, 381 insertions, 577 deletions
diff --git a/middleware/cache/cache.go b/middleware/cache/cache.go index bd29a815c..3bb1b21f9 100644 --- a/middleware/cache/cache.go +++ b/middleware/cache/cache.go @@ -20,6 +20,7 @@ type Cache struct { cap time.Duration } +// NewCache returns a new cache. func NewCache(ttl int, zones []string, next middleware.Handler) Cache { return Cache{Next: next, Zones: zones, cache: gcache.New(defaultDuration, purgeDuration), cap: time.Duration(ttl) * time.Second} } @@ -46,17 +47,20 @@ func cacheKey(m *dns.Msg, t response.Type, do bool) string { return "" } -type CachingResponseWriter struct { +// ResponseWriter is a response writer that caches the reply message. +type ResponseWriter struct { dns.ResponseWriter cache *gcache.Cache cap time.Duration } -func NewCachingResponseWriter(w dns.ResponseWriter, cache *gcache.Cache, cap time.Duration) *CachingResponseWriter { - return &CachingResponseWriter{w, cache, cap} +// NewCachingResponseWriter returns a new ResponseWriter. +func NewCachingResponseWriter(w dns.ResponseWriter, cache *gcache.Cache, cap time.Duration) *ResponseWriter { + return &ResponseWriter{w, cache, cap} } -func (c *CachingResponseWriter) WriteMsg(res *dns.Msg) error { +// WriteMsg implements the dns.ResponseWriter interface. +func (c *ResponseWriter) WriteMsg(res *dns.Msg) error { do := false mt, opt := response.Classify(res) if opt != nil { @@ -73,7 +77,7 @@ func (c *CachingResponseWriter) WriteMsg(res *dns.Msg) error { return c.ResponseWriter.WriteMsg(res) } -func (c *CachingResponseWriter) set(m *dns.Msg, key string, mt response.Type) { +func (c *ResponseWriter) set(m *dns.Msg, key string, mt response.Type) { if key == "" { log.Printf("[ERROR] Caching called with empty cache key") return @@ -83,14 +87,14 @@ func (c *CachingResponseWriter) set(m *dns.Msg, key string, mt response.Type) { switch mt { case response.Success, response.Delegation: if c.cap == 0 { - duration = minTtl(m.Answer, mt) + duration = minTTL(m.Answer, mt) } i := newItem(m, duration) c.cache.Set(key, i, duration) case response.NameError, response.NoData: if c.cap == 0 { - duration = minTtl(m.Ns, mt) + duration = minTTL(m.Ns, mt) } i := newItem(m, duration) @@ -102,23 +106,25 @@ func (c *CachingResponseWriter) set(m *dns.Msg, key string, mt response.Type) { } } -func (c *CachingResponseWriter) Write(buf []byte) (int, error) { +// Write implements the dns.ResponseWriter interface. +func (c *ResponseWriter) Write(buf []byte) (int, error) { log.Printf("[WARNING] Caching called with Write: not caching reply") n, err := c.ResponseWriter.Write(buf) return n, err } -func (c *CachingResponseWriter) Hijack() { +// Hijack implements the dns.ResponseWriter interface. +func (c *ResponseWriter) Hijack() { c.ResponseWriter.Hijack() return } -func minTtl(rrs []dns.RR, mt response.Type) time.Duration { +func minTTL(rrs []dns.RR, mt response.Type) time.Duration { if mt != response.Success && mt != response.NameError && mt != response.NoData { return 0 } - minTtl := maxTtl + minTTL := maxTTL for _, r := range rrs { switch mt { case response.NameError, response.NoData: @@ -126,17 +132,17 @@ func minTtl(rrs []dns.RR, mt response.Type) time.Duration { return time.Duration(r.(*dns.SOA).Minttl) * time.Second } case response.Success, response.Delegation: - if r.Header().Ttl < minTtl { - minTtl = r.Header().Ttl + if r.Header().Ttl < minTTL { + minTTL = r.Header().Ttl } } } - return time.Duration(minTtl) * time.Second + return time.Duration(minTTL) * time.Second } const ( purgeDuration = 1 * time.Minute defaultDuration = 20 * time.Minute - baseTtl = 5 // minimum ttl that we will allow - maxTtl uint32 = 2 * 3600 + baseTTL = 5 // minimum TTL that we will allow + maxTTL uint32 = 2 * 3600 ) diff --git a/middleware/cache/cache_test.go b/middleware/cache/cache_test.go index dc44fa8a3..95a1d50b8 100644 --- a/middleware/cache/cache_test.go +++ b/middleware/cache/cache_test.go @@ -65,7 +65,7 @@ func cacheMsg(m *dns.Msg, tc cacheTestCase) *dns.Msg { return m } -func newTestCache() (Cache, *CachingResponseWriter) { +func newTestCache() (Cache, *ResponseWriter) { c := NewCache(0, []string{"."}, nil) crr := NewCachingResponseWriter(nil, c.cache, time.Duration(0)) return c, crr diff --git a/middleware/cache/item.go b/middleware/cache/item.go index 544de3c9a..f2585b0cc 100644 --- a/middleware/cache/item.go +++ b/middleware/cache/item.go @@ -15,7 +15,7 @@ type item struct { Ns []dns.RR Extra []dns.RR - origTtl uint32 + origTTL uint32 stored time.Time } @@ -38,7 +38,7 @@ func newItem(m *dns.Msg, d time.Duration) *item { } i.Extra = i.Extra[:j] - i.origTtl = uint32(d.Seconds()) + i.origTTL = uint32(d.Seconds()) i.stored = time.Now().UTC() return i @@ -57,9 +57,9 @@ func (i *item) toMsg(m *dns.Msg) *dns.Msg { m1.Ns = i.Ns m1.Extra = i.Extra - ttl := int(i.origTtl) - int(time.Now().UTC().Sub(i.stored).Seconds()) - if ttl < baseTtl { - ttl = baseTtl + ttl := int(i.origTTL) - int(time.Now().UTC().Sub(i.stored).Seconds()) + if ttl < baseTTL { + ttl = baseTTL } setCap(m1, uint32(ttl)) return m1 diff --git a/middleware/chaos/chaos.go b/middleware/chaos/chaos.go index 8b6df3e84..dc80f47a9 100644 --- a/middleware/chaos/chaos.go +++ b/middleware/chaos/chaos.go @@ -18,6 +18,7 @@ type Chaos struct { Authors map[string]bool } +// ServeDNS implements the middleware.Handler interface. func (c Chaos) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) { state := request.Request{W: w, Req: r} if state.QClass() != dns.ClassCHAOS || state.QType() != dns.TypeTXT { @@ -32,7 +33,7 @@ func (c Chaos) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) ( default: return c.Next.ServeDNS(ctx, w, r) case "authors.bind.": - for a, _ := range c.Authors { + for a := range c.Authors { m.Answer = append(m.Answer, &dns.TXT{Hdr: hdr, Txt: []string{trim(a)}}) } case "version.bind.", "version.server.": diff --git a/middleware/dnssec/dnskey.go b/middleware/dnssec/dnskey.go index af345f906..df19571c8 100644 --- a/middleware/dnssec/dnskey.go +++ b/middleware/dnssec/dnskey.go @@ -13,6 +13,7 @@ import ( "github.com/miekg/dns" ) +// DNSKEY holds a DNSSEC public and private key used for on-the-fly signing. type DNSKEY struct { K *dns.DNSKEY s crypto.Signer diff --git a/middleware/dnssec/dnssec.go b/middleware/dnssec/dnssec.go index ea914c0ee..9dcb6e434 100644 --- a/middleware/dnssec/dnssec.go +++ b/middleware/dnssec/dnssec.go @@ -12,6 +12,7 @@ import ( gcache "github.com/patrickmn/go-cache" ) +// Dnssec signs the reply on-the-fly. type Dnssec struct { Next middleware.Handler @@ -21,6 +22,7 @@ type Dnssec struct { cache *gcache.Cache } +// New returns a new Dnssec. func New(zones []string, keys []*DNSKEY, next middleware.Handler) Dnssec { return Dnssec{Next: next, zones: zones, @@ -95,7 +97,7 @@ func (d Dnssec) sign(rrs []dns.RR, signerName string, ttl, incep, expir uint32) sigs := make([]dns.RR, len(d.keys)) var e error for i, k := range d.keys { - sig := k.NewRRSIG(signerName, ttl, incep, expir) + sig := k.newRRSIG(signerName, ttl, incep, expir) e = sig.Sign(k.s, rrs) sigs[i] = sig } diff --git a/middleware/dnssec/handler.go b/middleware/dnssec/handler.go index 609150028..aaed62bdf 100644 --- a/middleware/dnssec/handler.go +++ b/middleware/dnssec/handler.go @@ -35,7 +35,7 @@ func (d Dnssec) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) } } - drr := NewDnssecResponseWriter(w, d) + drr := &ResponseWriter{w, d} return d.Next.ServeDNS(ctx, drr, r) } diff --git a/middleware/dnssec/responsewriter.go b/middleware/dnssec/responsewriter.go index 95378c091..547561fb9 100644 --- a/middleware/dnssec/responsewriter.go +++ b/middleware/dnssec/responsewriter.go @@ -10,15 +10,13 @@ import ( "github.com/miekg/dns" ) +// ResponseWriter sign the response on the fly. type ResponseWriter struct { dns.ResponseWriter d Dnssec } -func NewDnssecResponseWriter(w dns.ResponseWriter, d Dnssec) *ResponseWriter { - return &ResponseWriter{w, d} -} - +// WriteMsg implements the dns.ResponseWriter interface. func (d *ResponseWriter) WriteMsg(res *dns.Msg) error { // By definition we should sign anything that comes back, we should still figure out for // which zone it should be. @@ -38,13 +36,12 @@ func (d *ResponseWriter) WriteMsg(res *dns.Msg) error { return d.ResponseWriter.WriteMsg(res) } +// Write implements the dns.ResponseWriter interface. func (d *ResponseWriter) Write(buf []byte) (int, error) { log.Printf("[WARNING] Dnssec called with Write: not signing reply") n, err := d.ResponseWriter.Write(buf) return n, err } -func (d *ResponseWriter) Hijack() { - d.ResponseWriter.Hijack() - return -} +// Hijack implements the dns.ResponseWriter interface. +func (d *ResponseWriter) Hijack() { d.ResponseWriter.Hijack() } diff --git a/middleware/dnssec/rrsig.go b/middleware/dnssec/rrsig.go index 17bc1195b..c68413622 100644 --- a/middleware/dnssec/rrsig.go +++ b/middleware/dnssec/rrsig.go @@ -3,7 +3,7 @@ package dnssec import "github.com/miekg/dns" // newRRSIG return a new RRSIG, with all fields filled out, except the signed data. -func (k *DNSKEY) NewRRSIG(signerName string, ttl, incep, expir uint32) *dns.RRSIG { +func (k *DNSKEY) newRRSIG(signerName string, ttl, incep, expir uint32) *dns.RRSIG { sig := new(dns.RRSIG) sig.Hdr.Rrtype = dns.TypeRRSIG @@ -11,7 +11,7 @@ func (k *DNSKEY) NewRRSIG(signerName string, ttl, incep, expir uint32) *dns.RRSI sig.KeyTag = k.keytag sig.SignerName = signerName sig.Hdr.Ttl = ttl - sig.OrigTtl = origTtl + sig.OrigTtl = origTTL sig.Inception = incep sig.Expiration = expir @@ -50,4 +50,4 @@ func rrSets(rrs []dns.RR) map[rrset][]dns.RR { return nil } -const origTtl = 3600 +const origTTL = 3600 diff --git a/middleware/dnssec/setup.go b/middleware/dnssec/setup.go index 74a70f87f..78d285f09 100644 --- a/middleware/dnssec/setup.go +++ b/middleware/dnssec/setup.go @@ -52,7 +52,7 @@ func dnssecParse(c *caddy.Controller) ([]string, []*DNSKEY, error) { } } } - for i, _ := range zones { + for i := range zones { zones[i] = middleware.Host(zones[i]).Normalize() } return zones, keys, nil diff --git a/middleware/errors/errors.go b/middleware/errors/errors.go index 6f490ea74..afaa8cf4d 100644 --- a/middleware/errors/errors.go +++ b/middleware/errors/errors.go @@ -15,15 +15,16 @@ import ( "golang.org/x/net/context" ) -// ErrorHandler handles DNS errors (and errors from other middleware). -type ErrorHandler struct { +// errorHandler handles DNS errors (and errors from other middleware). +type errorHandler struct { Next middleware.Handler LogFile string Log *log.Logger Debug bool // if true, errors are written out to client rather than to a log } -func (h ErrorHandler) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) { +// ServeDNS implements the middleware.Handler interface. +func (h errorHandler) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) { defer h.recovery(ctx, w, r) rcode, err := h.Next.ServeDNS(ctx, w, r) @@ -47,7 +48,7 @@ func (h ErrorHandler) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns return rcode, err } -func (h ErrorHandler) recovery(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) { +func (h errorHandler) recovery(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) { rec := recover() if rec == nil { return diff --git a/middleware/errors/errors_test.go b/middleware/errors/errors_test.go index 4c8f56fa2..1bf81444b 100644 --- a/middleware/errors/errors_test.go +++ b/middleware/errors/errors_test.go @@ -18,7 +18,7 @@ import ( func TestErrors(t *testing.T) { buf := bytes.Buffer{} - em := ErrorHandler{Log: log.New(&buf, "", 0)} + em := errorHandler{Log: log.New(&buf, "", 0)} testErr := errors.New("test error") tests := []struct { @@ -68,7 +68,7 @@ func TestErrors(t *testing.T) { func TestVisibleErrorWithPanic(t *testing.T) { const panicMsg = "I'm a panic" - eh := ErrorHandler{ + eh := errorHandler{ Debug: true, Next: middleware.HandlerFunc(func(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) { panic(panicMsg) diff --git a/middleware/errors/setup.go b/middleware/errors/setup.go index 437c6a996..f15141919 100644 --- a/middleware/errors/setup.go +++ b/middleware/errors/setup.go @@ -62,8 +62,8 @@ func setup(c *caddy.Controller) error { return nil } -func errorsParse(c *caddy.Controller) (ErrorHandler, error) { - handler := ErrorHandler{} +func errorsParse(c *caddy.Controller) (errorHandler, error) { + handler := errorHandler{} optionalBlock := func() (bool, error) { var hadBlock bool diff --git a/middleware/errors/setup_test.go b/middleware/errors/setup_test.go index 5b5108d42..adae0009c 100644 --- a/middleware/errors/setup_test.go +++ b/middleware/errors/setup_test.go @@ -10,19 +10,19 @@ func TestErrorsParse(t *testing.T) { tests := []struct { inputErrorsRules string shouldErr bool - expectedErrorHandler ErrorHandler + expectedErrorHandler errorHandler }{ - {`errors`, false, ErrorHandler{ + {`errors`, false, errorHandler{ LogFile: "", }}, - {`errors errors.txt`, false, ErrorHandler{ + {`errors errors.txt`, false, errorHandler{ LogFile: "errors.txt", }}, - {`errors visible`, false, ErrorHandler{ + {`errors visible`, false, errorHandler{ LogFile: "", Debug: true, }}, - {`errors { log visible }`, false, ErrorHandler{ + {`errors { log visible }`, false, errorHandler{ LogFile: "", Debug: true, }}, diff --git a/middleware/etcd/etcd.go b/middleware/etcd/etcd.go index 4b5b424f4..09cd5ba55 100644 --- a/middleware/etcd/etcd.go +++ b/middleware/etcd/etcd.go @@ -16,6 +16,7 @@ import ( "golang.org/x/net/context" ) +// Etcd is a middleware talks to an etcd cluster. type Etcd struct { Next middleware.Handler Zones []string @@ -113,7 +114,7 @@ Nodes: bx[b] = true serv.Key = n.Key - serv.Ttl = e.TTL(n, serv) + serv.TTL = e.TTL(n, serv) if serv.Priority == 0 { serv.Priority = priority } @@ -127,19 +128,19 @@ Nodes: func (e *Etcd) TTL(node *etcdc.Node, serv *msg.Service) uint32 { etcdTTL := uint32(node.TTL) - if etcdTTL == 0 && serv.Ttl == 0 { + if etcdTTL == 0 && serv.TTL == 0 { return ttl } if etcdTTL == 0 { - return serv.Ttl + return serv.TTL } - if serv.Ttl == 0 { + if serv.TTL == 0 { return etcdTTL } - if etcdTTL < serv.Ttl { + if etcdTTL < serv.TTL { return etcdTTL } - return serv.Ttl + return serv.TTL } // etcNameError checks if the error is ErrorCodeKeyNotFound from etcd. diff --git a/middleware/etcd/handler.go b/middleware/etcd/handler.go index 40f9523f0..75aa582bd 100644 --- a/middleware/etcd/handler.go +++ b/middleware/etcd/handler.go @@ -5,12 +5,14 @@ import ( "github.com/miekg/coredns/middleware" "github.com/miekg/coredns/middleware/etcd/msg" + "github.com/miekg/coredns/middleware/pkg/dnsutil" "github.com/miekg/coredns/request" "github.com/miekg/dns" "golang.org/x/net/context" ) +// ServeDNS implements the middleware.Handler interface. func (e *Etcd) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) { opt := Options{} state := request.Request{W: w, Req: r} @@ -108,7 +110,7 @@ func (e *Etcd) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) ( m.Extra = append(m.Extra, servicesToTxt(debug)...) } - m = dedup(m) + m = dnsutil.Dedup(m) state.SizeAndDo(m) m, _ = state.Scrub(m) w.WriteMsg(m) @@ -133,11 +135,3 @@ func (e *Etcd) Err(zone string, rcode int, state request.Request, debug []msg.Se // Return success as the rcode to signal we have written to the client. return dns.RcodeSuccess, nil } - -func dedup(m *dns.Msg) *dns.Msg { - // TODO(miek): expensive! - m.Answer = dns.Dedup(m.Answer, nil) - m.Ns = dns.Dedup(m.Ns, nil) - m.Extra = dns.Dedup(m.Extra, nil) - return m -} diff --git a/middleware/etcd/lookup.go b/middleware/etcd/lookup.go index b13c257e6..9f2309e94 100644 --- a/middleware/etcd/lookup.go +++ b/middleware/etcd/lookup.go @@ -14,8 +14,9 @@ import ( "github.com/miekg/dns" ) +// Options are extra options that can be specified for a lookup. type Options struct { - Debug string + Debug string // This is a debug query. A query prefixed with debug.o-o } func (e Etcd) records(state request.Request, exact bool, opt Options) (services, debug []msg.Service, err error) { @@ -30,6 +31,7 @@ func (e Etcd) records(state request.Request, exact bool, opt Options) (services, return } +// A returns A records from etcd or an error. func (e Etcd) A(zone string, state request.Request, previousRecords []dns.RR, opt Options) (records []dns.RR, debug []msg.Service, err error) { services, debug, err := e.records(state, false, opt) if err != nil { @@ -92,6 +94,7 @@ func (e Etcd) A(zone string, state request.Request, previousRecords []dns.RR, op return records, debug, nil } +// AAAA returns AAAA records from etcd or an error. func (e Etcd) AAAA(zone string, state request.Request, previousRecords []dns.RR, opt Options) (records []dns.RR, debug []msg.Service, err error) { services, debug, err := e.records(state, false, opt) if err != nil { @@ -313,6 +316,7 @@ func (e Etcd) MX(zone string, state request.Request, opt Options) (records, extr return records, extra, debug, nil } +// CNAME returns CNAME records from etcd or an error. func (e Etcd) CNAME(zone string, state request.Request, opt Options) (records []dns.RR, debug []msg.Service, err error) { services, debug, err := e.records(state, true, opt) if err != nil { @@ -343,6 +347,7 @@ func (e Etcd) PTR(zone string, state request.Request, opt Options) (records []dn return records, debug, nil } +// TXT returns TXT records from etcd or an error. func (e Etcd) TXT(zone string, state request.Request, opt Options) (records []dns.RR, debug []msg.Service, err error) { services, debug, err := e.records(state, false, opt) if err != nil { @@ -358,6 +363,7 @@ func (e Etcd) TXT(zone string, state request.Request, opt Options) (records []dn return records, debug, nil } +// NS returns NS records from etcd or an error. func (e Etcd) NS(zone string, state request.Request, opt Options) (records, extra []dns.RR, debug []msg.Service, err error) { // NS record for this zone live in a special place, ns.dns.<zone>. Fake our lookup. // only a tad bit fishy... @@ -390,7 +396,7 @@ func (e Etcd) NS(zone string, state request.Request, opt Options) (records, extr return records, extra, debug, nil } -// SOA Record returns a SOA record. +// SOA returns a SOA record from etcd. func (e Etcd) SOA(zone string, state request.Request, opt Options) ([]dns.RR, []msg.Service, error) { header := dns.RR_Header{Name: zone, Rrtype: dns.TypeSOA, Ttl: 300, Class: dns.ClassINET} diff --git a/middleware/etcd/msg/path.go b/middleware/etcd/msg/path.go index 16c1bbd60..aeb52f665 100644 --- a/middleware/etcd/msg/path.go +++ b/middleware/etcd/msg/path.go @@ -27,7 +27,7 @@ func Domain(s string) string { return dns.Fqdn(strings.Join(l[1:len(l)-1], ".")) } -// As Path, but if a name contains wildcards (* or any), the name will be +// PathWithWildcard ascts as Path, but if a name contains wildcards (* or any), the name will be // chopped of before the (first) wildcard, and we do a highler evel search and // later find the matching names. So service.*.skydns.local, will look for all // services under skydns.local and will later check for names that match diff --git a/middleware/etcd/msg/service.go b/middleware/etcd/msg/service.go index 059b3263b..bd8055289 100644 --- a/middleware/etcd/msg/service.go +++ b/middleware/etcd/msg/service.go @@ -8,9 +8,9 @@ import ( "github.com/miekg/dns" ) -// 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. +// Service defines a discoverable service in etcd. It 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. type Service struct { Host string `json:"host,omitempty"` Port int `json:"port,omitempty"` @@ -18,7 +18,7 @@ type Service struct { Weight int `json:"weight,omitempty"` Text string `json:"text,omitempty"` Mail bool `json:"mail,omitempty"` // Be an MX record. Priority becomes Preference. - Ttl uint32 `json:"ttl,omitempty"` + TTL uint32 `json:"ttl,omitempty"` // When a SRV record with a "Host: IP-address" is added, we synthesize // a srv.Target domain name. Normally we convert the full Key where @@ -54,7 +54,7 @@ func (s *Service) RR() *dns.TXT { } t := new(dns.TXT) t.Hdr.Class = dns.ClassCHAOS - t.Hdr.Ttl = s.Ttl + t.Hdr.Ttl = s.TTL t.Hdr.Rrtype = dns.TypeTXT t.Hdr.Name = Domain(s.Key) @@ -70,7 +70,7 @@ func (s *Service) RR() *dns.TXT { func (s *Service) NewSRV(name string, weight uint16) *dns.SRV { 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}, + 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: dns.Fqdn(host)} } @@ -78,39 +78,39 @@ func (s *Service) NewSRV(name string, weight uint16) *dns.SRV { func (s *Service) NewMX(name string) *dns.MX { 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}, + return &dns.MX{Hdr: dns.RR_Header{Name: name, Rrtype: dns.TypeMX, Class: dns.ClassINET, Ttl: s.TTL}, Preference: uint16(s.Priority), Mx: host} } // NewA returns a new A record based on the Service. func (s *Service) NewA(name string, ip net.IP) *dns.A { - return &dns.A{Hdr: dns.RR_Header{Name: name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: s.Ttl}, A: ip} + return &dns.A{Hdr: dns.RR_Header{Name: name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: s.TTL}, A: ip} } // NewAAAA returns a new AAAA record based on the Service. func (s *Service) NewAAAA(name string, ip net.IP) *dns.AAAA { - return &dns.AAAA{Hdr: dns.RR_Header{Name: name, Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Ttl: s.Ttl}, AAAA: ip} + return &dns.AAAA{Hdr: dns.RR_Header{Name: name, Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Ttl: s.TTL}, AAAA: ip} } // NewCNAME returns a new CNAME record based on the Service. func (s *Service) NewCNAME(name string, target string) *dns.CNAME { - return &dns.CNAME{Hdr: dns.RR_Header{Name: name, Rrtype: dns.TypeCNAME, Class: dns.ClassINET, Ttl: s.Ttl}, Target: dns.Fqdn(target)} + return &dns.CNAME{Hdr: dns.RR_Header{Name: name, Rrtype: dns.TypeCNAME, Class: dns.ClassINET, Ttl: s.TTL}, Target: dns.Fqdn(target)} } // NewTXT returns a new TXT record based on the Service. func (s *Service) NewTXT(name string) *dns.TXT { - return &dns.TXT{Hdr: dns.RR_Header{Name: name, Rrtype: dns.TypeTXT, Class: dns.ClassINET, Ttl: s.Ttl}, Txt: split255(s.Text)} + return &dns.TXT{Hdr: dns.RR_Header{Name: name, Rrtype: dns.TypeTXT, Class: dns.ClassINET, Ttl: s.TTL}, Txt: split255(s.Text)} } // NewPTR returns a new PTR record based on the Service. func (s *Service) NewPTR(name string, target string) *dns.PTR { - return &dns.PTR{Hdr: dns.RR_Header{Name: name, Rrtype: dns.TypePTR, Class: dns.ClassINET, Ttl: s.Ttl}, Ptr: dns.Fqdn(target)} + return &dns.PTR{Hdr: dns.RR_Header{Name: name, Rrtype: dns.TypePTR, Class: dns.ClassINET, Ttl: s.TTL}, Ptr: dns.Fqdn(target)} } // NewNS returns a new NS record based on the Service. func (s *Service) NewNS(name string) *dns.NS { host := targetStrip(dns.Fqdn(s.Host), s.TargetStrip) - return &dns.NS{Hdr: dns.RR_Header{Name: name, Rrtype: dns.TypeNS, Class: dns.ClassINET, Ttl: s.Ttl}, Ns: host} + return &dns.NS{Hdr: dns.RR_Header{Name: name, Rrtype: dns.TypeNS, Class: dns.ClassINET, Ttl: s.TTL}, Ns: host} } // Group checks the services in sx, it looks for a Group attribute on the shortest diff --git a/middleware/etcd/setup.go b/middleware/etcd/setup.go index 47e253a69..9097fff91 100644 --- a/middleware/etcd/setup.go +++ b/middleware/etcd/setup.go @@ -171,7 +171,7 @@ func newEtcdClient(endpoints []string, tlsCert, tlsKey, tlsCACert string) (etcdc } func newHTTPSTransport(tlsCertFile, tlsKeyFile, tlsCACertFile string) etcdc.CancelableTransport { - var cc *tls.Config = nil + var cc *tls.Config if tlsCertFile != "" && tlsKeyFile != "" { var rpool *x509.CertPool diff --git a/middleware/etcd/stub.go b/middleware/etcd/stub.go index b45d4a5dd..1c4634853 100644 --- a/middleware/etcd/stub.go +++ b/middleware/etcd/stub.go @@ -13,6 +13,7 @@ import ( "github.com/miekg/dns" ) +// UpdateStubZones checks etcd for an update on the stubzones. func (e *Etcd) UpdateStubZones() { go func() { for { diff --git a/middleware/etcd/stub_handler.go b/middleware/etcd/stub_handler.go index 10a3d2198..b5120041a 100644 --- a/middleware/etcd/stub_handler.go +++ b/middleware/etcd/stub_handler.go @@ -16,6 +16,7 @@ type Stub struct { Zone string // for what zone (and thus what nameservers are we called) } +// ServeDNS implements the middleware.Handler interface. func (s Stub) ServeDNS(ctx context.Context, w dns.ResponseWriter, req *dns.Msg) (int, error) { if hasStubEdns0(req) { log.Printf("[WARNING] Forwarding cycle detected, refusing msg: %s", req.Question[0].Name) diff --git a/middleware/file/delegation_test.go b/middleware/file/delegation_test.go index 30a6e430c..e9a20eb25 100644 --- a/middleware/file/delegation_test.go +++ b/middleware/file/delegation_test.go @@ -46,7 +46,7 @@ var delegationTestCases = []test.Case{ } func TestLookupDelegation(t *testing.T) { - zone, err := Parse(strings.NewReader(dbMiekNL_delegation), testzone, "stdin") + zone, err := Parse(strings.NewReader(dbMiekNLDelegation), testzone, "stdin") if err != nil { t.Fatalf("expect no error when reading zone, got %q", err) } @@ -85,7 +85,7 @@ func TestLookupDelegation(t *testing.T) { } } -const dbMiekNL_delegation = ` +const dbMiekNLDelegation = ` $TTL 30M $ORIGIN miek.nl. @ IN SOA linode.atoom.net. miek.miek.nl. ( diff --git a/middleware/file/dnssec_test.go b/middleware/file/dnssec_test.go index 434ebed8f..63099afb4 100644 --- a/middleware/file/dnssec_test.go +++ b/middleware/file/dnssec_test.go @@ -105,7 +105,7 @@ var dnssecTestCases = []test.Case{ } func TestLookupDNSSEC(t *testing.T) { - zone, err := Parse(strings.NewReader(dbMiekNL_signed), testzone, "stdin") + zone, err := Parse(strings.NewReader(dbMiekNLSigned), testzone, "stdin") if err != nil { t.Fatalf("expect no error when reading zone, got %q", err) } @@ -147,7 +147,7 @@ func TestLookupDNSSEC(t *testing.T) { } func BenchmarkLookupDNSSEC(b *testing.B) { - zone, err := Parse(strings.NewReader(dbMiekNL_signed), testzone, "stdin") + zone, err := Parse(strings.NewReader(dbMiekNLSigned), testzone, "stdin") if err != nil { return } @@ -178,7 +178,7 @@ func BenchmarkLookupDNSSEC(b *testing.B) { } } -const dbMiekNL_signed = ` +const dbMiekNLSigned = ` ; File written on Sun Mar 27 04:13:01 2016 ; dnssec_signzone version 9.10.3-P4-Ubuntu miek.nl. 1800 IN SOA linode.atoom.net. miek.miek.nl. ( diff --git a/middleware/file/file.go b/middleware/file/file.go index d2ced17e4..5dc63a292 100644 --- a/middleware/file/file.go +++ b/middleware/file/file.go @@ -13,17 +13,20 @@ import ( ) type ( + // File is the middleware that reads zone data from disk. File struct { Next middleware.Handler Zones Zones } + // Zones maps zone names to a *Zone. Zones struct { Z map[string]*Zone Names []string } ) +// ServeDNS implements the middleware.Handle interface. func (f File) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) { state := request.Request{W: w, Req: r} diff --git a/middleware/file/lookup.go b/middleware/file/lookup.go index f7ba23a87..6a09c7072 100644 --- a/middleware/file/lookup.go +++ b/middleware/file/lookup.go @@ -10,10 +10,15 @@ import ( type Result int const ( + // Success is a successful lookup. Success Result = iota + // NameError indicates a nameerror NameError + // Delegation indicates the lookup resulted in a delegation. Delegation + // NoData indicates the lookup resulted in a NODATA. NoData + // ServerFailure indicates a server failure during the lookup. ServerFailure ) diff --git a/middleware/file/nsec3_test.go b/middleware/file/nsec3_test.go index d9e48921a..938ff120c 100644 --- a/middleware/file/nsec3_test.go +++ b/middleware/file/nsec3_test.go @@ -6,7 +6,7 @@ import ( ) func TestParseNSEC3PARAM(t *testing.T) { - _, err := Parse(strings.NewReader(nsec3param_test), "miek.nl", "stdin") + _, err := Parse(strings.NewReader(nsec3paramTest), "miek.nl", "stdin") if err == nil { t.Fatalf("expected error when reading zone, got nothing") } @@ -14,17 +14,17 @@ func TestParseNSEC3PARAM(t *testing.T) { } func TestParseNSEC3(t *testing.T) { - _, err := Parse(strings.NewReader(nsec3_test), "miek.nl", "stdin") + _, err := Parse(strings.NewReader(nsec3Test), "miek.nl", "stdin") if err == nil { t.Fatalf("expected error when reading zone, got nothing") } t.Logf("%v\n", err) } -const nsec3param_test = `miek.nl. 1800 IN SOA linode.atoom.net. miek.miek.nl. 1460175181 14400 3600 604800 14400 +const nsec3paramTest = `miek.nl. 1800 IN SOA linode.atoom.net. miek.miek.nl. 1460175181 14400 3600 604800 14400 miek.nl. 1800 IN NS omval.tednet.nl. miek.nl. 0 IN NSEC3PARAM 1 0 5 A3DEBC9CC4F695C7` -const nsec3_test = `example.org. 1800 IN SOA sns.dns.icann.org. noc.dns.icann.org. 2016082508 7200 3600 1209600 3600 +const nsec3Test = `example.org. 1800 IN SOA sns.dns.icann.org. noc.dns.icann.org. 2016082508 7200 3600 1209600 3600 aub8v9ce95ie18spjubsr058h41n7pa5.example.org. 284 IN NSEC3 1 1 5 D0CBEAAF0AC77314 AUB95P93VPKP55G6U5S4SGS7LS61ND85 NS SOA TXT RRSIG DNSKEY NSEC3PARAM aub8v9ce95ie18spjubsr058h41n7pa5.example.org. 284 IN RRSIG NSEC3 8 2 600 20160910232502 20160827231002 14028 example.org. XBNpA7KAIjorPbXvTinOHrc1f630aHic2U716GHLHA4QMx9cl9ss4QjR Wj2UpDM9zBW/jNYb1xb0yjQoez/Jv200w0taSWjRci5aUnRpOi9bmcrz STHb6wIUjUsbJ+NstQsUwVkj6679UviF1FqNwr4GlJnWG3ZrhYhE+NI6 s0k=` diff --git a/middleware/file/secondary.go b/middleware/file/secondary.go index ef44e124f..6f5d9ef4a 100644 --- a/middleware/file/secondary.go +++ b/middleware/file/secondary.go @@ -178,7 +178,6 @@ Restart: } } -// The maximum difference between two serial numbers. If the difference between -// two serials is greater than this number, the smaller one is considered -// greater. +// MaxSerialIncrement is the maximum difference between two serial numbers. If the difference between +// two serials is greater than this number, the smaller one is considered greater. const MaxSerialIncrement uint32 = 2147483647 diff --git a/middleware/file/setup.go b/middleware/file/setup.go index 5a2c80e6b..114b370f5 100644 --- a/middleware/file/setup.go +++ b/middleware/file/setup.go @@ -70,7 +70,7 @@ func fileParse(c *caddy.Controller) (Zones, error) { return Zones{}, err } - for i, _ := range origins { + for i := range origins { origins[i] = middleware.Host(origins[i]).Normalize() zone, err := Parse(reader, origins[i], fileName) if err == nil { @@ -116,7 +116,7 @@ func TransferParse(c *caddy.Controller) (tos, froms []string, err error) { case "transfer": if value == "to" { tos = c.RemainingArgs() - for i, _ := range tos { + for i := range tos { if tos[i] != "*" { if x := net.ParseIP(tos[i]); x == nil { return nil, nil, fmt.Errorf("must specify an IP addres: `%s'", tos[i]) @@ -127,7 +127,7 @@ func TransferParse(c *caddy.Controller) (tos, froms []string, err error) { } if value == "from" { froms = c.RemainingArgs() - for i, _ := range froms { + for i := range froms { if froms[i] != "*" { if x := net.ParseIP(froms[i]); x == nil { return nil, nil, fmt.Errorf("must specify an IP addres: `%s'", froms[i]) diff --git a/middleware/file/tree/elem.go b/middleware/file/tree/elem.go index 785d64660..ac913042a 100644 --- a/middleware/file/tree/elem.go +++ b/middleware/file/tree/elem.go @@ -2,6 +2,7 @@ package tree import "github.com/miekg/dns" +// Elem is an element in the tree. type Elem struct { m map[uint16][]dns.RR } diff --git a/middleware/file/tree/tree.go b/middleware/file/tree/tree.go index 99560cda1..0e2171cf5 100644 --- a/middleware/file/tree/tree.go +++ b/middleware/file/tree/tree.go @@ -19,13 +19,14 @@ package tree import "github.com/miekg/dns" const ( - TD234 = iota - BU23 + td234 = iota + bu23 ) // Result is a result of a Search. type Result int +// Various constants that indicated the type a resource returned. const ( Found Result = iota NameError @@ -34,10 +35,10 @@ const ( ) // Operation mode of the LLRB tree. -const Mode = BU23 +const mode = bu23 func init() { - if Mode != TD234 && Mode != BU23 { + if mode != td234 && mode != bu23 { panic("tree: unknown mode") } } @@ -48,8 +49,8 @@ type Color bool const ( // Red as false give us the defined behaviour that new nodes are red. Although this // is incorrect for the root node, that is resolved on the first insertion. - Red Color = false - Black Color = true + red Color = false + black Color = true ) // A Node represents a node in the LLRB tree. @@ -70,7 +71,7 @@ type Tree struct { // color returns the effect color of a Node. A nil node returns black. func (n *Node) color() Color { if n == nil { - return Black + return black } return n.Color } @@ -82,7 +83,7 @@ func (n *Node) rotateLeft() (root *Node) { n.Right = root.Left root.Left = n root.Color = n.Color - n.Color = Red + n.Color = red return } @@ -93,7 +94,7 @@ func (n *Node) rotateRight() (root *Node) { n.Left = root.Right root.Right = n root.Color = n.Color - n.Color = Red + n.Color = red return } @@ -108,16 +109,16 @@ func (n *Node) flipColors() { // fixUp ensures that black link balance is correct, that red nodes lean left, // and that 4 nodes are split in the case of BU23 and properly balanced in TD234. func (n *Node) fixUp() *Node { - if n.Right.color() == Red { - if Mode == TD234 && n.Right.Left.color() == Red { + if n.Right.color() == red { + if mode == td234 && n.Right.Left.color() == red { n.Right = n.Right.rotateRight() } n = n.rotateLeft() } - if n.Left.color() == Red && n.Left.Left.color() == Red { + if n.Left.color() == red && n.Left.Left.color() == red { n = n.rotateRight() } - if Mode == BU23 && n.Left.color() == Red && n.Right.color() == Red { + if mode == bu23 && n.Left.color() == red && n.Right.color() == red { n.flipColors() } return n @@ -125,11 +126,11 @@ func (n *Node) fixUp() *Node { func (n *Node) moveRedLeft() *Node { n.flipColors() - if n.Right.Left.color() == Red { + if n.Right.Left.color() == red { n.Right = n.Right.rotateRight() n = n.rotateLeft() n.flipColors() - if Mode == TD234 && n.Right.Right.color() == Red { + if mode == td234 && n.Right.Right.color() == red { n.Right = n.Right.rotateLeft() } } @@ -138,7 +139,7 @@ func (n *Node) moveRedLeft() *Node { func (n *Node) moveRedRight() *Node { n.flipColors() - if n.Left.Left.color() == Red { + if n.Left.Left.color() == red { n = n.rotateRight() n.flipColors() } @@ -212,7 +213,7 @@ func (t *Tree) Insert(rr dns.RR) { var d int t.Root, d = t.Root.insert(rr) t.Count += d - t.Root.Color = Black + t.Root.Color = black } func (n *Node) insert(rr dns.RR) (root *Node, d int) { @@ -223,8 +224,8 @@ func (n *Node) insert(rr dns.RR) (root *Node, d int) { return n, 1 } - if Mode == TD234 { - if n.Left.color() == Red && n.Right.color() == Red { + if mode == td234 { + if n.Left.color() == red && n.Right.color() == red { n.flipColors() } } @@ -238,15 +239,15 @@ func (n *Node) insert(rr dns.RR) (root *Node, d int) { n.Right, d = n.Right.insert(rr) } - if n.Right.color() == Red && n.Left.color() == Black { + if n.Right.color() == red && n.Left.color() == black { n = n.rotateLeft() } - if n.Left.color() == Red && n.Left.Left.color() == Red { + if n.Left.color() == red && n.Left.Left.color() == red { n = n.rotateRight() } - if Mode == BU23 { - if n.Left.color() == Red && n.Right.color() == Red { + if mode == bu23 { + if n.Left.color() == red && n.Right.color() == red { n.flipColors() } } @@ -267,14 +268,14 @@ func (t *Tree) DeleteMin() { if t.Root == nil { return } - t.Root.Color = Black + t.Root.Color = black } func (n *Node) deleteMin() (root *Node, d int) { if n.Left == nil { return nil, -1 } - if n.Left.color() == Black && n.Left.Left.color() == Black { + if n.Left.color() == black && n.Left.Left.color() == black { n = n.moveRedLeft() } n.Left, d = n.Left.deleteMin() @@ -295,17 +296,17 @@ func (t *Tree) DeleteMax() { if t.Root == nil { return } - t.Root.Color = Black + t.Root.Color = black } func (n *Node) deleteMax() (root *Node, d int) { - if n.Left != nil && n.Left.color() == Red { + if n.Left != nil && n.Left.color() == red { n = n.rotateRight() } if n.Right == nil { return nil, -1 } - if n.Right.color() == Black && n.Right.Left.color() == Black { + if n.Right.color() == black && n.Right.Left.color() == black { n = n.moveRedRight() } n.Right, d = n.Right.deleteMax() @@ -345,26 +346,26 @@ func (t *Tree) DeleteNode(rr dns.RR) { if t.Root == nil { return } - t.Root.Color = Black + t.Root.Color = black } func (n *Node) delete(rr dns.RR) (root *Node, d int) { if Less(n.Elem, rr.Header().Name) < 0 { if n.Left != nil { - if n.Left.color() == Black && n.Left.Left.color() == Black { + if n.Left.color() == black && n.Left.Left.color() == black { n = n.moveRedLeft() } n.Left, d = n.Left.delete(rr) } } else { - if n.Left.color() == Red { + if n.Left.color() == red { n = n.rotateRight() } if n.Right == nil && Less(n.Elem, rr.Header().Name) == 0 { return nil, -1 } if n.Right != nil { - if n.Right.color() == Black && n.Right.Left.color() == Black { + if n.Right.color() == black && n.Right.Left.color() == black { n = n.moveRedRight() } if Less(n.Elem, rr.Header().Name) == 0 { diff --git a/middleware/file/wildcard_test.go b/middleware/file/wildcard_test.go index b0cc4c610..847275ffc 100644 --- a/middleware/file/wildcard_test.go +++ b/middleware/file/wildcard_test.go @@ -46,7 +46,7 @@ var wildcardTestCases = []test.Case{ } func TestLookupWildcard(t *testing.T) { - zone, err := Parse(strings.NewReader(dbDnssexNL_signed), testzone1, "stdin") + zone, err := Parse(strings.NewReader(dbDnssexNLSigned), testzone1, "stdin") if err != nil { t.Fatalf("expect no error when reading zone, got %q", err) } @@ -85,7 +85,7 @@ func TestLookupWildcard(t *testing.T) { } } -const dbDnssexNL_signed = ` +const dbDnssexNLSigned = ` ; File written on Tue Mar 29 21:02:24 2016 ; dnssec_signzone version 9.10.3-P4-Ubuntu dnssex.nl. 1800 IN SOA linode.atoom.net. miek.miek.nl. ( diff --git a/middleware/file/xfr.go b/middleware/file/xfr.go index d5ea1f2d3..e4fcd7efa 100644 --- a/middleware/file/xfr.go +++ b/middleware/file/xfr.go @@ -10,13 +10,12 @@ import ( "golang.org/x/net/context" ) -type ( - Xfr struct { - *Zone - } -) +// Xfr serves up an AXFR. +type Xfr struct { + *Zone +} -// Serve an AXFR (and fallback of IXFR) as well. +// ServeDNS implements the middleware.Handler interface. func (x Xfr) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) { state := request.Request{W: w, Req: r} if !x.TransferAllowed(state) { diff --git a/middleware/file/zone.go b/middleware/file/zone.go index ff8795d77..abb837499 100644 --- a/middleware/file/zone.go +++ b/middleware/file/zone.go @@ -15,6 +15,7 @@ import ( "github.com/miekg/dns" ) +// Zone defines a structure that contains all data related to a DNS zone. type Zone struct { origin string file string @@ -31,6 +32,7 @@ type Zone struct { // TODO: shutdown watcher channel } +// Apex contains the apex records of a zone: SOA, NS and their potential signatures. type Apex struct { SOA *dns.SOA NS []dns.RR @@ -135,6 +137,7 @@ func (z *Zone) All() []dns.RR { return append([]dns.RR{z.Apex.SOA}, records...) } +// Reload reloads a zone when it is changed on disk. If z.NoRoload is true, no reloading will be done. func (z *Zone) Reload(shutdown chan bool) error { if z.NoReload { return nil diff --git a/middleware/health/health.go b/middleware/health/health.go index 1d47e409e..513791688 100644 --- a/middleware/health/health.go +++ b/middleware/health/health.go @@ -10,32 +10,33 @@ import ( var once sync.Once -type Health struct { +type health struct { Addr string ln net.Listener mux *http.ServeMux } -func health(w http.ResponseWriter, r *http.Request) { - io.WriteString(w, ok) -} - -func (h *Health) Startup() error { +func (h *health) Startup() error { if h.Addr == "" { h.Addr = defAddr } once.Do(func() { - if ln, err := net.Listen("tcp", h.Addr); err != nil { + ln, err := net.Listen("tcp", h.Addr) + if err != nil { log.Printf("[ERROR] Failed to start health handler: %s", err) return - } else { - h.ln = ln } + + h.ln = ln + h.mux = http.NewServeMux() - h.mux.HandleFunc(path, health) + h.mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) { + io.WriteString(w, ok) + }) + go func() { http.Serve(h.ln, h.mux) }() @@ -43,7 +44,7 @@ func (h *Health) Startup() error { return nil } -func (h *Health) Shutdown() error { +func (h *health) Shutdown() error { if h.ln != nil { return h.ln.Close() } diff --git a/middleware/health/health_test.go b/middleware/health/health_test.go index c5ef9cc42..de95eb103 100644 --- a/middleware/health/health_test.go +++ b/middleware/health/health_test.go @@ -10,14 +10,14 @@ import ( func TestHealth(t *testing.T) { // We use a random port instead of a fixed port like 8080 that may have been // occupied by some other process. - health := Health{Addr: ":0"} - if err := health.Startup(); err != nil { + h := health{Addr: ":0"} + if err := h.Startup(); err != nil { t.Fatalf("Unable to startup the health server: %v", err) } - defer health.Shutdown() + defer h.Shutdown() // Reconstruct the http address based on the port allocated by operating system. - address := fmt.Sprintf("http://%s%s", health.ln.Addr().String(), path) + address := fmt.Sprintf("http://%s%s", h.ln.Addr().String(), path) response, err := http.Get(address) if err != nil { diff --git a/middleware/health/setup.go b/middleware/health/setup.go index ca8c6684f..a396d2902 100644 --- a/middleware/health/setup.go +++ b/middleware/health/setup.go @@ -19,9 +19,9 @@ func setup(c *caddy.Controller) error { return middleware.Error("health", err) } - health := &Health{Addr: addr} - c.OnStartup(health.Startup) - c.OnShutdown(health.Shutdown) + h := &health{Addr: addr} + c.OnStartup(h.Startup) + c.OnShutdown(h.Shutdown) // Don't do AddMiddleware, as health is not *really* a middleware just a separate // webserver running. diff --git a/middleware/kubernetes/handler.go b/middleware/kubernetes/handler.go index 8e8ae15fa..1b1abf44b 100644 --- a/middleware/kubernetes/handler.go +++ b/middleware/kubernetes/handler.go @@ -11,6 +11,7 @@ import ( "golang.org/x/net/context" ) +// ServeDNS implements the middleware.Handler interface. func (k Kubernetes) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) { state := request.Request{W: w, Req: r} if state.QClass() != dns.ClassINET { @@ -29,7 +30,7 @@ func (k Kubernetes) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.M srvPTR := &records[0] m.Answer = append(m.Answer, srvPTR.NewPTR(state.QName(), ip)) - m = dedup(m) + m = dnsutil.Dedup(m) state.SizeAndDo(m) m, _ = state.Scrub(m) w.WriteMsg(m) @@ -93,14 +94,14 @@ func (k Kubernetes) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.M m.Answer = append(m.Answer, records...) m.Extra = append(m.Extra, extra...) - m = dedup(m) + m = dnsutil.Dedup(m) state.SizeAndDo(m) m, _ = state.Scrub(m) w.WriteMsg(m) return dns.RcodeSuccess, nil } -// NoData write a nodata response to the client. +// Err writes an error response back to the client. func (k Kubernetes) Err(zone string, rcode int, state request.Request) (int, error) { m := new(dns.Msg) m.SetRcode(state.Req, rcode) @@ -109,11 +110,3 @@ func (k Kubernetes) Err(zone string, rcode int, state request.Request) (int, err state.W.WriteMsg(m) return rcode, nil } - -func dedup(m *dns.Msg) *dns.Msg { - // TODO(miek): expensive! - m.Answer = dns.Dedup(m.Answer, nil) - m.Ns = dns.Dedup(m.Ns, nil) - m.Extra = dns.Dedup(m.Extra, nil) - return m -} diff --git a/middleware/kubernetes/kubernetes.go b/middleware/kubernetes/kubernetes.go index 7e21d5759..7f5a86649 100644 --- a/middleware/kubernetes/kubernetes.go +++ b/middleware/kubernetes/kubernetes.go @@ -7,7 +7,7 @@ import ( "time" "github.com/miekg/coredns/middleware" - "github.com/miekg/coredns/middleware/kubernetes/msg" + "github.com/miekg/coredns/middleware/etcd/msg" "github.com/miekg/coredns/middleware/kubernetes/nametemplate" "github.com/miekg/coredns/middleware/kubernetes/util" "github.com/miekg/coredns/middleware/pkg/dnsutil" @@ -22,6 +22,7 @@ import ( "k8s.io/kubernetes/pkg/labels" ) +// Kubernetes implements a middleware that connects to a Kubernetes cluster. type Kubernetes struct { Next middleware.Handler Zones []string @@ -35,6 +36,8 @@ type Kubernetes struct { Selector *labels.Selector } +// InitKubeCache initializes a new Kubernetes cache. +// TODO(miek): is this correct? func (k *Kubernetes) InitKubeCache() error { // For a custom api server or running outside a k8s cluster // set URL in env.KUBERNETES_MASTER or set endpoint in Corefile @@ -232,7 +235,7 @@ func (k *Kubernetes) getServiceRecordForIP(ip, name string) []msg.Service { const ( priority = 10 // default priority when nothing is set ttl = 300 // default ttl when nothing is set - minTtl = 60 + minTTL = 60 hostmaster = "hostmaster" k8sTimeout = 5 * time.Second ) diff --git a/middleware/kubernetes/lookup.go b/middleware/kubernetes/lookup.go index e14d2275e..fa41686a6 100644 --- a/middleware/kubernetes/lookup.go +++ b/middleware/kubernetes/lookup.go @@ -7,7 +7,7 @@ import ( "time" "github.com/miekg/coredns/middleware" - "github.com/miekg/coredns/middleware/kubernetes/msg" + "github.com/miekg/coredns/middleware/etcd/msg" "github.com/miekg/coredns/middleware/pkg/dnsutil" "github.com/miekg/coredns/request" @@ -24,6 +24,7 @@ func (k Kubernetes) records(state request.Request, exact bool) ([]msg.Service, e return services, nil } +// A returns A records from kubernetes or an error. func (k Kubernetes) A(zone string, state request.Request, previousRecords []dns.RR) (records []dns.RR, err error) { services, err := k.records(state, false) if err != nil { @@ -83,6 +84,7 @@ func (k Kubernetes) A(zone string, state request.Request, previousRecords []dns. return records, nil } +// AAAA returns AAAA records from kubernetes or an error. func (k Kubernetes) AAAA(zone string, state request.Request, previousRecords []dns.RR) (records []dns.RR, err error) { services, err := k.records(state, false) if err != nil { @@ -144,7 +146,8 @@ func (k Kubernetes) AAAA(zone string, state request.Request, previousRecords []d } // SRV returns SRV records from kubernetes. -// If the Target is not a name but an IP address, a name is created on the fly. +// If the Target is not a name but an IP address, a name is created on the fly and the IP address is put in +// the additional section. func (k Kubernetes) SRV(zone string, state request.Request) (records []dns.RR, extra []dns.RR, err error) { services, err := k.records(state, false) if err != nil { @@ -226,21 +229,22 @@ func (k Kubernetes) SRV(zone string, state request.Request) (records []dns.RR, e return records, extra, nil } -// Returning MX records from kubernetes not implemented. +// MX returns MX records from kubernetes. Not implemented! func (k Kubernetes) MX(zone string, state request.Request) (records []dns.RR, extra []dns.RR, err error) { return nil, nil, err } -// Returning CNAME records from kubernetes not implemented. +// CNAME returns CNAME records from kubernetes. Not implemented! func (k Kubernetes) CNAME(zone string, state request.Request) (records []dns.RR, err error) { return nil, err } -// Returning TXT records from kubernetes not implemented. +// TXT returns TXT records from kubernetes. Not implemented! func (k Kubernetes) TXT(zone string, state request.Request) (records []dns.RR, err error) { return nil, err } +// NS returns NS records from kubernetes. func (k Kubernetes) NS(zone string, state request.Request) (records, extra []dns.RR, err error) { // NS record for this zone live in a special place, ns.dns.<zone>. Fake our lookup. // only a tad bit fishy... @@ -273,7 +277,7 @@ func (k Kubernetes) NS(zone string, state request.Request) (records, extra []dns return records, extra, nil } -// SOA Record returns a SOA record. +// SOA Record returns a SOA record from kubernetes. func (k Kubernetes) SOA(zone string, state request.Request) *dns.SOA { header := dns.RR_Header{Name: zone, Rrtype: dns.TypeSOA, Ttl: 300, Class: dns.ClassINET} return &dns.SOA{Hdr: header, @@ -287,6 +291,7 @@ func (k Kubernetes) SOA(zone string, state request.Request) *dns.SOA { } } +// PTR Record returns PTR records from kubernetes. func (k Kubernetes) PTR(zone string, state request.Request) ([]dns.RR, error) { reverseIP := dnsutil.ExtractAddressFromReverse(state.Name()) if reverseIP == "" { diff --git a/middleware/kubernetes/msg/service.go b/middleware/kubernetes/msg/service.go deleted file mode 100644 index 24af6b4fd..000000000 --- a/middleware/kubernetes/msg/service.go +++ /dev/null @@ -1,171 +0,0 @@ -package msg - -import ( - "net" - "strings" - - "github.com/miekg/dns" -) - -// 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. -type Service struct { - Host string `json:"host,omitempty"` - Port int `json:"port,omitempty"` - Priority int `json:"priority,omitempty"` - Weight int `json:"weight,omitempty"` - Text string `json:"text,omitempty"` - Mail bool `json:"mail,omitempty"` // Be an MX record. Priority becomes Preference. - Ttl uint32 `json:"ttl,omitempty"` - - // When a SRV record with a "Host: IP-address" is added, we synthesize - // a srv.Target domain name. Normally we convert the full Key where - // 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"` - - // Group is used to group (or *not* to group) different services - // together. Services with an identical Group are returned in the same - // answer. - Group string `json:"group,omitempty"` - - // Etcd key where we found this service and ignored from json un-/marshalling - Key string `json:"-"` -} - -// NewSRV returns a new SRV record based on the Service. -func (s *Service) NewSRV(name string, weight uint16) *dns.SRV { - 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: dns.Fqdn(host)} -} - -// NewMX returns a new MX record based on the Service. -func (s *Service) NewMX(name string) *dns.MX { - 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} -} - -// NewA returns a new A record based on the Service. -func (s *Service) NewA(name string, ip net.IP) *dns.A { - return &dns.A{Hdr: dns.RR_Header{Name: name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: s.Ttl}, A: ip} -} - -// NewAAAA returns a new AAAA record based on the Service. -func (s *Service) NewAAAA(name string, ip net.IP) *dns.AAAA { - return &dns.AAAA{Hdr: dns.RR_Header{Name: name, Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Ttl: s.Ttl}, AAAA: ip} -} - -// NewCNAME returns a new CNAME record based on the Service. -func (s *Service) NewCNAME(name string, target string) *dns.CNAME { - return &dns.CNAME{Hdr: dns.RR_Header{Name: name, Rrtype: dns.TypeCNAME, Class: dns.ClassINET, Ttl: s.Ttl}, Target: dns.Fqdn(target)} -} - -// NewTXT returns a new TXT record based on the Service. -func (s *Service) NewTXT(name string) *dns.TXT { - return &dns.TXT{Hdr: dns.RR_Header{Name: name, Rrtype: dns.TypeTXT, Class: dns.ClassINET, Ttl: s.Ttl}, Txt: split255(s.Text)} -} - -// NewNS returns a new NS record based on the Service. -func (s *Service) NewNS(name string) *dns.NS { - host := targetStrip(dns.Fqdn(s.Host), s.TargetStrip) - return &dns.NS{Hdr: dns.RR_Header{Name: name, Rrtype: dns.TypeNS, Class: dns.ClassINET, Ttl: s.Ttl}, Ns: host} -} - -// NewPTR returns a new PTR record based on the Service. -func (s *Service) NewPTR(name string, target string) *dns.PTR { - return &dns.PTR{Hdr: dns.RR_Header{Name: name, Rrtype: dns.TypePTR, Class: dns.ClassINET, Ttl: s.Ttl}, Ptr: dns.Fqdn(target)} -} - -// Group checks the services in sx, it looks for a Group attribute on the shortest -// keys. If there are multiple shortest keys *and* the group attribute disagrees (and -// is not empty), we don't consider it a group. -// If a group is found, only services with *that* group (or no group) will be returned. -func Group(sx []Service) []Service { - if len(sx) == 0 { - return sx - } - - // Shortest key with group attribute sets the group for this set. - group := sx[0].Group - slashes := strings.Count(sx[0].Key, "/") - length := make([]int, len(sx)) - for i, s := range sx { - x := strings.Count(s.Key, "/") - length[i] = x - if x < slashes { - if s.Group == "" { - break - } - slashes = x - group = s.Group - } - } - - if group == "" { - return sx - } - - ret := []Service{} // with slice-tricks in sx we can prolly save this allocation (TODO) - - for i, s := range sx { - if s.Group == "" { - ret = append(ret, s) - continue - } - - // Disagreement on the same level - if length[i] == slashes && s.Group != group { - return sx - } - - if s.Group == group { - ret = append(ret, s) - } - } - return ret -} - -// Split255 splits a string into 255 byte chunks. -func split255(s string) []string { - if len(s) < 255 { - return []string{s} - } - sx := []string{} - p, i := 0, 255 - for { - if i <= len(s) { - sx = append(sx, s[p:i]) - } else { - sx = append(sx, s[p:]) - break - - } - p, i = p+255, i+255 - } - - 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 -} diff --git a/middleware/kubernetes/msg/service_test.go b/middleware/kubernetes/msg/service_test.go deleted file mode 100644 index 0c19ba95b..000000000 --- a/middleware/kubernetes/msg/service_test.go +++ /dev/null @@ -1,125 +0,0 @@ -package msg - -import "testing" - -func TestSplit255(t *testing.T) { - xs := split255("abc") - if len(xs) != 1 && xs[0] != "abc" { - t.Errorf("Failure to split abc") - } - s := "" - for i := 0; i < 255; i++ { - s += "a" - } - xs = split255(s) - if len(xs) != 1 && xs[0] != s { - t.Errorf("failure to split 255 char long string") - } - s += "b" - xs = split255(s) - if len(xs) != 2 || xs[1] != "b" { - t.Errorf("failure to split 256 char long string: %d", len(xs)) - } - for i := 0; i < 255; i++ { - s += "a" - } - xs = split255(s) - if len(xs) != 3 || xs[2] != "a" { - t.Errorf("failure to split 510 char long string: %d", len(xs)) - } -} - -func TestGroup(t *testing.T) { - // Key are in the wrong order, but for this test it does not matter. - sx := Group( - []Service{ - {Host: "127.0.0.1", Group: "g1", Key: "b/sub/dom1/skydns/test"}, - {Host: "127.0.0.2", Group: "g2", Key: "a/dom1/skydns/test"}, - }, - ) - // Expecting to return the shortest key with a Group attribute. - if len(sx) != 1 { - t.Fatalf("failure to group zeroth set: %v", sx) - } - if sx[0].Key != "a/dom1/skydns/test" { - t.Fatalf("failure to group zeroth set: %v, wrong Key", sx) - } - - // Groups disagree, so we will not do anything. - sx = Group( - []Service{ - {Host: "server1", Group: "g1", Key: "region1/skydns/test"}, - {Host: "server2", Group: "g2", Key: "region1/skydns/test"}, - }, - ) - if len(sx) != 2 { - t.Fatalf("failure to group first set: %v", sx) - } - - // Group is g1, include only the top-level one. - sx = Group( - []Service{ - {Host: "server1", Group: "g1", Key: "a/dom/region1/skydns/test"}, - {Host: "server2", Group: "g2", Key: "a/subdom/dom/region1/skydns/test"}, - }, - ) - if len(sx) != 1 { - t.Fatalf("failure to group second set: %v", sx) - } - - // Groupless services must be included. - sx = Group( - []Service{ - {Host: "server1", Group: "g1", Key: "a/dom/region1/skydns/test"}, - {Host: "server2", Group: "g2", Key: "a/subdom/dom/region1/skydns/test"}, - {Host: "server2", Group: "", Key: "b/subdom/dom/region1/skydns/test"}, - }, - ) - if len(sx) != 2 { - t.Fatalf("failure to group third set: %v", sx) - } - - // Empty group on the highest level: include that one also. - sx = Group( - []Service{ - {Host: "server1", Group: "g1", Key: "a/dom/region1/skydns/test"}, - {Host: "server1", Group: "", Key: "b/dom/region1/skydns/test"}, - {Host: "server2", Group: "g2", Key: "a/subdom/dom/region1/skydns/test"}, - }, - ) - if len(sx) != 2 { - t.Fatalf("failure to group fourth set: %v", sx) - } - - // Empty group on the highest level: include that one also, and the rest. - sx = Group( - []Service{ - {Host: "server1", Group: "g5", Key: "a/dom/region1/skydns/test"}, - {Host: "server1", Group: "", Key: "b/dom/region1/skydns/test"}, - {Host: "server2", Group: "g5", Key: "a/subdom/dom/region1/skydns/test"}, - }, - ) - if len(sx) != 3 { - t.Fatalf("failure to group fith set: %v", sx) - } - - // One group. - sx = Group( - []Service{ - {Host: "server1", Group: "g6", Key: "a/dom/region1/skydns/test"}, - }, - ) - if len(sx) != 1 { - t.Fatalf("failure to group sixth set: %v", sx) - } - - // No group, once service - sx = Group( - []Service{ - {Host: "server1", Key: "a/dom/region1/skydns/test"}, - }, - ) - if len(sx) != 1 { - t.Fatalf("failure to group seventh set: %v", sx) - } -} diff --git a/middleware/kubernetes/nametemplate/nametemplate.go b/middleware/kubernetes/nametemplate/nametemplate.go index 3e1ac4bb3..b9c2f20e4 100644 --- a/middleware/kubernetes/nametemplate/nametemplate.go +++ b/middleware/kubernetes/nametemplate/nametemplate.go @@ -60,6 +60,7 @@ var requiredSymbols = []string{ // Where the query string is longer than the template, need to define which // symbol consumes the other segments. Most likely this would be the servicename. // Also consider how to handle static strings in the format template. + type NameTemplate struct { formatString string splitFormat []string @@ -105,11 +106,11 @@ func (t *NameTemplate) SetTemplate(s string) error { // step down the stack to find the right element. func (t *NameTemplate) GetZoneFromSegmentArray(segments []string) string { - if index, ok := t.Element["zone"]; !ok { + index, ok := t.Element["zone"] + if !ok { return "" - } else { - return strings.Join(segments[index:len(segments)], ".") } + return strings.Join(segments[index:len(segments)], ".") } func (t *NameTemplate) GetNamespaceFromSegmentArray(segments []string) string { @@ -132,11 +133,11 @@ func (t *NameTemplate) GetTypeFromSegmentArray(segments []string) string { } func (t *NameTemplate) GetSymbolFromSegmentArray(symbol string, segments []string) string { - if index, ok := t.Element[symbol]; !ok { + index, ok := t.Element[symbol] + if !ok { return "" - } else { - return segments[index] } + return segments[index] } // GetRecordNameFromNameValues returns the string produced by applying the @@ -164,6 +165,7 @@ func (t *NameTemplate) GetRecordNameFromNameValues(values NameValues) string { } func (t *NameTemplate) IsValid() bool { + // This is *only* used in a test, for the test this should be a private method. result := true // Ensure that all requiredSymbols are found in NameTemplate diff --git a/middleware/loadbalance/handler.go b/middleware/loadbalance/handler.go index 119b4d5d2..151eb57d0 100644 --- a/middleware/loadbalance/handler.go +++ b/middleware/loadbalance/handler.go @@ -15,6 +15,6 @@ type RoundRobin struct { // ServeDNS implements the middleware.Handler interface. func (rr RoundRobin) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) { - wrr := NewRoundRobinResponseWriter(w) + wrr := &RoundRobinResponseWriter{w} return rr.Next.ServeDNS(ctx, wrr, r) } diff --git a/middleware/loadbalance/loadbalance.go b/middleware/loadbalance/loadbalance.go index 1d0d7a848..57f1f9174 100644 --- a/middleware/loadbalance/loadbalance.go +++ b/middleware/loadbalance/loadbalance.go @@ -6,14 +6,12 @@ import ( "github.com/miekg/dns" ) +// RoundRobinResponseWriter is a response writer that shuffles A and AAAA records. type RoundRobinResponseWriter struct { dns.ResponseWriter } -func NewRoundRobinResponseWriter(w dns.ResponseWriter) *RoundRobinResponseWriter { - return &RoundRobinResponseWriter{w} -} - +// WriteMsg implements the dns.ResponseWriter interface. func (r *RoundRobinResponseWriter) WriteMsg(res *dns.Msg) error { if res.Rcode != dns.RcodeSuccess { return r.ResponseWriter.WriteMsg(res) @@ -63,13 +61,15 @@ func roundRobin(in []dns.RR) []dns.RR { return out } -// Should we pack and unpack here to fiddle with the packet... Not likely. +// Write implements the dns.ResponseWriter interface. func (r *RoundRobinResponseWriter) Write(buf []byte) (int, error) { + // Should we pack and unpack here to fiddle with the packet... Not likely. log.Printf("[WARNING] RoundRobin called with Write: no shuffling records") n, err := r.ResponseWriter.Write(buf) return n, err } +// Hijack implements the dns.ResponseWriter interface. func (r *RoundRobinResponseWriter) Hijack() { r.ResponseWriter.Hijack() return diff --git a/middleware/log/log.go b/middleware/log/log.go index 3c941849b..1d368765e 100644 --- a/middleware/log/log.go +++ b/middleware/log/log.go @@ -23,6 +23,7 @@ type Logger struct { ErrorFunc func(dns.ResponseWriter, *dns.Msg, int) // failover error handler } +// ServeDNS implements the middleware.Handler interface. func (l Logger) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) { state := request.Request{W: w, Req: r} for _, rule := range l.Rules { diff --git a/middleware/metrics/handler.go b/middleware/metrics/handler.go index 6cac7e81e..2856621b5 100644 --- a/middleware/metrics/handler.go +++ b/middleware/metrics/handler.go @@ -12,6 +12,7 @@ import ( "golang.org/x/net/context" ) +// ServeDNS implements the Handler interface. func (m Metrics) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) { state := request.Request{W: w, Req: r} diff --git a/middleware/metrics/metrics.go b/middleware/metrics/metrics.go index a9d09c202..b7473a00e 100644 --- a/middleware/metrics/metrics.go +++ b/middleware/metrics/metrics.go @@ -34,16 +34,19 @@ type Metrics struct { ZoneNames []string } -func (m *Metrics) Startup() error { +// OnStartup sets up the metrics on startup. +func (m *Metrics) OnStartup() error { m.Once.Do(func() { define() - if ln, err := net.Listen("tcp", m.Addr); err != nil { + ln, err := net.Listen("tcp", m.Addr) + if err != nil { log.Printf("[ERROR] Failed to start metrics handler: %s", err) return - } else { - m.ln = ln } + + m.ln = ln + m.mux = http.NewServeMux() prometheus.MustRegister(requestCount) @@ -66,7 +69,8 @@ func (m *Metrics) Startup() error { return nil } -func (m *Metrics) Shutdown() error { +// OnShutdown tears down the metrics on shutdown. +func (m *Metrics) OnShutdown() error { if m.ln != nil { return m.ln.Close() } diff --git a/middleware/metrics/setup.go b/middleware/metrics/setup.go index 077a809d5..c7b5a0333 100644 --- a/middleware/metrics/setup.go +++ b/middleware/metrics/setup.go @@ -28,8 +28,8 @@ func setup(c *caddy.Controller) error { }) metricsOnce.Do(func() { - c.OnStartup(m.Startup) - c.OnShutdown(m.Shutdown) + c.OnStartup(m.OnStartup) + c.OnShutdown(m.OnShutdown) }) return nil diff --git a/middleware/pkg/dnsutil/dedup.go b/middleware/pkg/dnsutil/dedup.go new file mode 100644 index 000000000..dae656a01 --- /dev/null +++ b/middleware/pkg/dnsutil/dedup.go @@ -0,0 +1,12 @@ +package dnsutil + +import "github.com/miekg/dns" + +// Dedup de-duplicates a message. +func Dedup(m *dns.Msg) *dns.Msg { + // TODO(miek): expensive! + m.Answer = dns.Dedup(m.Answer, nil) + m.Ns = dns.Dedup(m.Ns, nil) + m.Extra = dns.Dedup(m.Extra, nil) + return m +} diff --git a/middleware/pprof/pprof.go b/middleware/pprof/pprof.go index cbef104d3..f2f580d76 100644 --- a/middleware/pprof/pprof.go +++ b/middleware/pprof/pprof.go @@ -7,12 +7,12 @@ import ( pp "net/http/pprof" ) -type Handler struct { +type handler struct { ln net.Listener mux *http.ServeMux } -func (h *Handler) Startup() error { +func (h *handler) Startup() error { ln, err := net.Listen("tcp", addr) if err != nil { log.Printf("[ERROR] Failed to start pprof handler: %s", err) @@ -34,7 +34,7 @@ func (h *Handler) Startup() error { return nil } -func (h *Handler) Shutdown() error { +func (h *handler) Shutdown() error { if h.ln != nil { return h.ln.Close() } diff --git a/middleware/pprof/setup.go b/middleware/pprof/setup.go index 00e192919..8dc621da9 100644 --- a/middleware/pprof/setup.go +++ b/middleware/pprof/setup.go @@ -29,10 +29,10 @@ func setup(c *caddy.Controller) error { found = true } - handler := &Handler{} + h := &handler{} pprofOnce.Do(func() { - c.OnStartup(handler.Startup) - c.OnShutdown(handler.Shutdown) + c.OnStartup(h.Startup) + c.OnShutdown(h.Shutdown) }) return nil diff --git a/middleware/proxy/upstream.go b/middleware/proxy/upstream.go index 08795e290..dc08a48e0 100644 --- a/middleware/proxy/upstream.go +++ b/middleware/proxy/upstream.go @@ -38,6 +38,7 @@ type staticUpstream struct { IgnoredSubDomains []string options Options } + type Options struct { Ecs []*net.IPNet // EDNS0 CLIENT SUBNET address (v4/v6) to add in CIDR notaton. } diff --git a/middleware/rewrite/reverter.go b/middleware/rewrite/reverter.go index c3425866e..400fb5fff 100644 --- a/middleware/rewrite/reverter.go +++ b/middleware/rewrite/reverter.go @@ -2,7 +2,7 @@ package rewrite import "github.com/miekg/dns" -// ResponseRevert reverses the operations done on the question section of a packet. +// ResponseReverter reverses the operations done on the question section of a packet. // This is need because the client will otherwise disregards the response, i.e. // dig will complain with ';; Question section mismatch: got miek.nl/HINFO/IN' type ResponseReverter struct { @@ -10,6 +10,7 @@ type ResponseReverter struct { original dns.Question } +// NewResponseReverter returns a pointer to a new ResponseReverter. func NewResponseReverter(w dns.ResponseWriter, r *dns.Msg) *ResponseReverter { return &ResponseReverter{ ResponseWriter: w, diff --git a/middleware/rewrite/rewrite.go b/middleware/rewrite/rewrite.go index 2f2f404c9..c88fa3549 100644 --- a/middleware/rewrite/rewrite.go +++ b/middleware/rewrite/rewrite.go @@ -30,7 +30,7 @@ type Rewrite struct { noRevert bool } -// ServeHTTP implements the middleware.Handler interface. +// ServeDNS implements the middleware.Handler interface. func (rw Rewrite) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) { wr := NewResponseReverter(w, r) for _, rule := range rw.Rules { diff --git a/middleware/rewrite/setup.go b/middleware/rewrite/setup.go index 707ad962a..9405fcd6a 100644 --- a/middleware/rewrite/setup.go +++ b/middleware/rewrite/setup.go @@ -1,7 +1,6 @@ package rewrite import ( - "strconv" "strings" "github.com/miekg/coredns/core/dnsserver" @@ -36,73 +35,76 @@ func rewriteParse(c *caddy.Controller) ([]Rule, error) { for c.Next() { var rule Rule - var err error - var base = "." - var pattern, to string - var status int - var ext []string + /* + var base = "." + var err error + var pattern, to string + var status int + var ifs []If + var ext []string + */ args := c.RemainingArgs() - var ifs []If - switch len(args) { case 1: - base = args[0] - fallthrough + /* + base = args[0] + fallthrough + */ case 0: - for c.NextBlock() { - switch c.Val() { - case "r", "regexp": - if !c.NextArg() { - return nil, c.ArgErr() - } - pattern = c.Val() - case "to": - args1 := c.RemainingArgs() - if len(args1) == 0 { - return nil, c.ArgErr() - } - to = strings.Join(args1, " ") - case "ext": // TODO(miek): fix or remove - args1 := c.RemainingArgs() - if len(args1) == 0 { - return nil, c.ArgErr() - } - ext = args1 - case "if": - args1 := c.RemainingArgs() - if len(args1) != 3 { + /* + for c.NextBlock() { + switch c.Val() { + case "r", "regexp": + if !c.NextArg() { + return nil, c.ArgErr() + } + pattern = c.Val() + case "to": + args1 := c.RemainingArgs() + if len(args1) == 0 { + return nil, c.ArgErr() + } + to = strings.Join(args1, " ") + case "ext": // TODO(miek): fix or remove + args1 := c.RemainingArgs() + if len(args1) == 0 { + return nil, c.ArgErr() + } + ext = args1 + case "if": + args1 := c.RemainingArgs() + if len(args1) != 3 { + return nil, c.ArgErr() + } + ifCond, err := NewIf(args1[0], args1[1], args1[2]) + if err != nil { + return nil, err + } + ifs = append(ifs, ifCond) + case "status": // TODO(miek): fix or remove + if !c.NextArg() { + return nil, c.ArgErr() + } + status, _ = strconv.Atoi(c.Val()) + if status < 200 || (status > 299 && status < 400) || status > 499 { + return nil, c.Err("status must be 2xx or 4xx") + } + default: return nil, c.ArgErr() } - ifCond, err := NewIf(args1[0], args1[1], args1[2]) - if err != nil { - return nil, err - } - ifs = append(ifs, ifCond) - case "status": // TODO(miek): fix or remove - if !c.NextArg() { - return nil, c.ArgErr() - } - status, _ = strconv.Atoi(c.Val()) - if status < 200 || (status > 299 && status < 400) || status > 499 { - return nil, c.Err("status must be 2xx or 4xx") - } - default: + } + // ensure to or status is specified + if to == "" && status == 0 { return nil, c.ArgErr() } - } - // ensure to or status is specified - if to == "" && status == 0 { - return nil, c.ArgErr() - } - // TODO(miek): complex rules - base, pattern, to, status, ext, ifs = base, pattern, to, status, ext, ifs - err = err - // if rule, err = NewComplexRule(base, pattern, to, status, ext, ifs); err != nil { - // return nil, err - // } - regexpRules = append(regexpRules, rule) + // TODO(miek): complex rules + if rule, err = NewComplexRule(base, pattern, to, status, ext, ifs); err != nil { + return nil, err + } + regexpRules = append(regexpRules, rule) + */ // the only unhandled case is 2 and above default: diff --git a/middleware/secondary/secondary.go b/middleware/secondary/secondary.go index 60006b69c..c0d101f7c 100644 --- a/middleware/secondary/secondary.go +++ b/middleware/secondary/secondary.go @@ -2,6 +2,8 @@ package secondary import "github.com/miekg/coredns/middleware/file" +// Secondary implements a secondary middleware that allows CoreDNS to retrieve (via AXFR) +// zone information from a primary server. type Secondary struct { file.File } diff --git a/middleware/test/helpers.go b/middleware/test/helpers.go index 37d046cb3..157bdce66 100644 --- a/middleware/test/helpers.go +++ b/middleware/test/helpers.go @@ -7,21 +7,26 @@ import ( "golang.org/x/net/context" ) -type Sect int +type sect int const ( - Answer Sect = iota + // Answer is the answer section in an Msg. + Answer sect = iota + // Ns is the authrotitative section in an Msg. Ns + // Extra is the additional section in an Msg. Extra ) +// RRSet represents a list of RRs. type RRSet []dns.RR func (p RRSet) Len() int { return len(p) } func (p RRSet) Swap(i, j int) { p[i], p[j] = p[j], p[i] } func (p RRSet) Less(i, j int) bool { return p[i].String() < p[j].String() } -// If the TTL of a record is 303 we don't care what the TTL is. +// Case represents a test case that encapsulates various data from a query and response. +// Note that is the TTL of a record is 303 we don't compare it with the TTL. type Case struct { Qname string Qtype uint16 @@ -32,6 +37,7 @@ type Case struct { Extra []dns.RR } +// Msg returns a *dns.Msg embedded in c. func (c Case) Msg() *dns.Msg { m := new(dns.Msg) m.SetQuestion(dns.Fqdn(c.Qname), c.Qtype) @@ -46,19 +52,43 @@ func (c Case) Msg() *dns.Msg { return m } -func A(rr string) *dns.A { r, _ := dns.NewRR(rr); return r.(*dns.A) } -func AAAA(rr string) *dns.AAAA { r, _ := dns.NewRR(rr); return r.(*dns.AAAA) } -func CNAME(rr string) *dns.CNAME { r, _ := dns.NewRR(rr); return r.(*dns.CNAME) } -func SRV(rr string) *dns.SRV { r, _ := dns.NewRR(rr); return r.(*dns.SRV) } -func SOA(rr string) *dns.SOA { r, _ := dns.NewRR(rr); return r.(*dns.SOA) } -func NS(rr string) *dns.NS { r, _ := dns.NewRR(rr); return r.(*dns.NS) } -func PTR(rr string) *dns.PTR { r, _ := dns.NewRR(rr); return r.(*dns.PTR) } -func TXT(rr string) *dns.TXT { r, _ := dns.NewRR(rr); return r.(*dns.TXT) } -func MX(rr string) *dns.MX { r, _ := dns.NewRR(rr); return r.(*dns.MX) } -func RRSIG(rr string) *dns.RRSIG { r, _ := dns.NewRR(rr); return r.(*dns.RRSIG) } -func NSEC(rr string) *dns.NSEC { r, _ := dns.NewRR(rr); return r.(*dns.NSEC) } +// A returns an A record from rr. It panics on errors. +func A(rr string) *dns.A { r, _ := dns.NewRR(rr); return r.(*dns.A) } + +// AAAA returns an AAAA record from rr. It panics on errors. +func AAAA(rr string) *dns.AAAA { r, _ := dns.NewRR(rr); return r.(*dns.AAAA) } + +// CNAME returns a CNAME record from rr. It panics on errors. +func CNAME(rr string) *dns.CNAME { r, _ := dns.NewRR(rr); return r.(*dns.CNAME) } + +// SRV returns a SRV record from rr. It panics on errors. +func SRV(rr string) *dns.SRV { r, _ := dns.NewRR(rr); return r.(*dns.SRV) } + +// SOA returns a SOA record from rr. It panics on errors. +func SOA(rr string) *dns.SOA { r, _ := dns.NewRR(rr); return r.(*dns.SOA) } + +// NS returns an NS record from rr. It panics on errors. +func NS(rr string) *dns.NS { r, _ := dns.NewRR(rr); return r.(*dns.NS) } + +// PTR returns a PTR record from rr. It panics on errors. +func PTR(rr string) *dns.PTR { r, _ := dns.NewRR(rr); return r.(*dns.PTR) } + +// TXT returns a TXT record from rr. It panics on errors. +func TXT(rr string) *dns.TXT { r, _ := dns.NewRR(rr); return r.(*dns.TXT) } + +// MX returns an MX record from rr. It panics on errors. +func MX(rr string) *dns.MX { r, _ := dns.NewRR(rr); return r.(*dns.MX) } + +// RRSIG returns an RRSIG record from rr. It panics on errors. +func RRSIG(rr string) *dns.RRSIG { r, _ := dns.NewRR(rr); return r.(*dns.RRSIG) } + +// NSEC returns an NSEC record from rr. It panics on errors. +func NSEC(rr string) *dns.NSEC { r, _ := dns.NewRR(rr); return r.(*dns.NSEC) } + +// DNSKEY returns a DNSKEY record from rr. It panics on errors. func DNSKEY(rr string) *dns.DNSKEY { r, _ := dns.NewRR(rr); return r.(*dns.DNSKEY) } +// OPT returns an OPT record with UDP buffer size set to bufsize and the DO bit set to do. func OPT(bufsize int, do bool) *dns.OPT { o := new(dns.OPT) o.Hdr.Name = "." @@ -71,6 +101,7 @@ func OPT(bufsize int, do bool) *dns.OPT { return o } +// Header test if the header in resp matches the header as defined in tc. func Header(t *testing.T, tc Case, resp *dns.Msg) bool { if resp.Rcode != tc.Rcode { t.Errorf("rcode is %q, expected %q", dns.RcodeToString[resp.Rcode], dns.RcodeToString[tc.Rcode]) @@ -92,9 +123,10 @@ func Header(t *testing.T, tc Case, resp *dns.Msg) bool { return true } -func Section(t *testing.T, tc Case, sect Sect, rr []dns.RR) bool { +// Section tests if the the section in tc matches rr. +func Section(t *testing.T, tc Case, sec sect, rr []dns.RR) bool { section := []dns.RR{} - switch sect { + switch sec { case 0: section = tc.Answer case 1: @@ -224,7 +256,7 @@ func Section(t *testing.T, tc Case, sect Sect, rr []dns.RR) bool { return true } -// ErrorHanlder returns a Handler that returns ServerFailure error when called. +// ErrorHandler returns a Handler that returns ServerFailure error when called. func ErrorHandler() Handler { return HandlerFunc(func(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) { m := new(dns.Msg) @@ -242,11 +274,13 @@ func NextHandler(rcode int, err error) Handler { } // Copied here to prevent an import cycle, so that we can define to above handlers. + type ( // HandlerFunc is a convenience type like dns.HandlerFunc, except // ServeDNS returns an rcode and an error. HandlerFunc func(context.Context, dns.ResponseWriter, *dns.Msg) (int, error) + // Handler interface defines a middleware. Handler interface { ServeDNS(context.Context, dns.ResponseWriter, *dns.Msg) (int, error) } diff --git a/middleware/test/responsewriter.go b/middleware/test/responsewriter.go index 925dc7b35..7aa6dd133 100644 --- a/middleware/test/responsewriter.go +++ b/middleware/test/responsewriter.go @@ -25,9 +25,20 @@ func (t *ResponseWriter) RemoteAddr() net.Addr { return &net.UDPAddr{IP: ip, Port: port, Zone: ""} } -func (t *ResponseWriter) WriteMsg(m *dns.Msg) error { return nil } +// WriteMsg implement dns.ResponseWriter interface. +func (t *ResponseWriter) WriteMsg(m *dns.Msg) error { return nil } + +// Write implement dns.ResponseWriter interface. func (t *ResponseWriter) Write(buf []byte) (int, error) { return len(buf), nil } -func (t *ResponseWriter) Close() error { return nil } -func (t *ResponseWriter) TsigStatus() error { return nil } -func (t *ResponseWriter) TsigTimersOnly(bool) { return } -func (t *ResponseWriter) Hijack() { return } + +// Close implement dns.ResponseWriter interface. +func (t *ResponseWriter) Close() error { return nil } + +// TsigStatus implement dns.ResponseWriter interface. +func (t *ResponseWriter) TsigStatus() error { return nil } + +// TsigTimersOnly implement dns.ResponseWriter interface. +func (t *ResponseWriter) TsigTimersOnly(bool) { return } + +// Hijack implement dns.ResponseWriter interface. +func (t *ResponseWriter) Hijack() { return } diff --git a/middleware/test/server.go b/middleware/test/server.go index c3dbd904a..03237df5b 100644 --- a/middleware/test/server.go +++ b/middleware/test/server.go @@ -9,6 +9,7 @@ import ( "github.com/miekg/dns" ) +// TCPServer starts a DNS server with a TCP listener on laddr. func TCPServer(t *testing.T, laddr string) (*dns.Server, string, error) { l, err := net.Listen("tcp", laddr) if err != nil { @@ -30,6 +31,7 @@ func TCPServer(t *testing.T, laddr string) (*dns.Server, string, error) { return server, l.Addr().String(), nil } +// UDPServer starts a DNS server with an UDP listener on laddr. func UDPServer(t *testing.T, laddr string) (*dns.Server, string, error) { pc, err := net.ListenPacket("udp", laddr) if err != nil { diff --git a/middleware/whoami/whoami.go b/middleware/whoami/whoami.go index 354bf6b4f..4de9a9cdb 100644 --- a/middleware/whoami/whoami.go +++ b/middleware/whoami/whoami.go @@ -11,10 +11,13 @@ import ( "golang.org/x/net/context" ) +// Whoami is a middleware that returns your IP address, port and the protocol used for connecting +// to CoreDNS. type Whoami struct { Next middleware.Handler } +// ServeDNS implements the middleware.Handler interface. func (wh Whoami) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) { state := request.Request{W: w, Req: r} |