aboutsummaryrefslogtreecommitdiff
path: root/core/dnsserver/server.go
diff options
context:
space:
mode:
Diffstat (limited to 'core/dnsserver/server.go')
-rw-r--r--core/dnsserver/server.go122
1 files changed, 90 insertions, 32 deletions
diff --git a/core/dnsserver/server.go b/core/dnsserver/server.go
index 15d1f90ce..478287bf8 100644
--- a/core/dnsserver/server.go
+++ b/core/dnsserver/server.go
@@ -37,23 +37,28 @@ type Server struct {
server [2]*dns.Server // 0 is a net.Listener, 1 is a net.PacketConn (a *UDPConn) in our case.
m sync.Mutex // protects the servers
- zones map[string]*Config // zones keyed by their address
- dnsWg sync.WaitGroup // used to wait on outstanding connections
- graceTimeout time.Duration // the maximum duration of a graceful shutdown
- trace trace.Trace // the trace plugin for the server
- debug bool // disable recover()
- stacktrace bool // enable stacktrace in recover error log
- classChaos bool // allow non-INET class queries
+ zones map[string][]*Config // zones keyed by their address
+ dnsWg sync.WaitGroup // used to wait on outstanding connections
+ graceTimeout time.Duration // the maximum duration of a graceful shutdown
+ trace trace.Trace // the trace plugin for the server
+ debug bool // disable recover()
+ stacktrace bool // enable stacktrace in recover error log
+ classChaos bool // allow non-INET class queries
tsigSecret map[string]string
}
+// MetadataCollector is a plugin that can retrieve metadata functions from all metadata providing plugins
+type MetadataCollector interface {
+ Collect(context.Context, request.Request) context.Context
+}
+
// NewServer returns a new CoreDNS server and compiles all plugins in to it. By default CH class
// queries are blocked unless queries from enableChaos are loaded.
func NewServer(addr string, group []*Config) (*Server, error) {
s := &Server{
Addr: addr,
- zones: make(map[string]*Config),
+ zones: make(map[string][]*Config),
graceTimeout: 5 * time.Second,
tsigSecret: make(map[string]string),
}
@@ -72,8 +77,9 @@ func NewServer(addr string, group []*Config) (*Server, error) {
log.D.Set()
}
s.stacktrace = site.Stacktrace
- // set the config per zone
- s.zones[site.Zone] = site
+
+ // append the config to the zone's configs
+ s.zones[site.Zone] = append(s.zones[site.Zone], site)
// copy tsig secrets
for key, secret := range site.TsigSecret {
@@ -88,6 +94,12 @@ func NewServer(addr string, group []*Config) (*Server, error) {
// register the *handler* also
site.registerHandler(stack)
+ // If the current plugin is a MetadataCollector, bookmark it for later use. This loop traverses the plugin
+ // list backwards, so the first MetadataCollector plugin wins.
+ if mdc, ok := stack.(MetadataCollector); ok {
+ site.metaCollector = mdc
+ }
+
if s.trace == nil && stack.Name() == "trace" {
// we have to stash away the plugin, not the
// Tracer object, because the Tracer won't be initialized yet
@@ -254,24 +266,39 @@ func (s *Server) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg)
)
for {
- if h, ok := s.zones[q[off:]]; ok {
- if h.pluginChain == nil { // zone defined, but has not got any plugins
- errorAndMetricsFunc(s.Addr, w, r, dns.RcodeRefused)
- return
- }
- if r.Question[0].Qtype != dns.TypeDS {
- rcode, _ := h.pluginChain.ServeDNS(ctx, w, r)
- if !plugin.ClientWrite(rcode) {
- errorFunc(s.Addr, w, r, rcode)
+ if z, ok := s.zones[q[off:]]; ok {
+ for _, h := range z {
+ if h.pluginChain == nil { // zone defined, but has not got any plugins
+ errorAndMetricsFunc(s.Addr, w, r, dns.RcodeRefused)
+ return
+ }
+
+ if h.metaCollector != nil {
+ // Collect metadata now, so it can be used before we send a request down the plugin chain.
+ ctx = h.metaCollector.Collect(ctx, request.Request{Req: r, W: w})
+ }
+
+ // If all filter funcs pass, use this config.
+ if passAllFilterFuncs(ctx, h.FilterFuncs, &request.Request{Req: r, W: w}) {
+ if h.ViewName != "" {
+ // if there was a view defined for this Config, set the view name in the context
+ ctx = context.WithValue(ctx, ViewKey{}, h.ViewName)
+ }
+ if r.Question[0].Qtype != dns.TypeDS {
+ rcode, _ := h.pluginChain.ServeDNS(ctx, w, r)
+ if !plugin.ClientWrite(rcode) {
+ errorFunc(s.Addr, w, r, rcode)
+ }
+ return
+ }
+ // The type is DS, keep the handler, but keep on searching as maybe we are serving
+ // the parent as well and the DS should be routed to it - this will probably *misroute* DS
+ // queries to a possibly grand parent, but there is no way for us to know at this point
+ // if there is an actual delegation from grandparent -> parent -> zone.
+ // In all fairness: direct DS queries should not be needed.
+ dshandler = h
}
- return
}
- // The type is DS, keep the handler, but keep on searching as maybe we are serving
- // the parent as well and the DS should be routed to it - this will probably *misroute* DS
- // queries to a possibly grand parent, but there is no way for us to know at this point
- // if there is an actual delegation from grandparent -> parent -> zone.
- // In all fairness: direct DS queries should not be needed.
- dshandler = h
}
off, end = dns.NextLabel(q, off)
if end {
@@ -289,18 +316,46 @@ func (s *Server) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg)
}
// Wildcard match, if we have found nothing try the root zone as a last resort.
- if h, ok := s.zones["."]; ok && h.pluginChain != nil {
- rcode, _ := h.pluginChain.ServeDNS(ctx, w, r)
- if !plugin.ClientWrite(rcode) {
- errorFunc(s.Addr, w, r, rcode)
+ if z, ok := s.zones["."]; ok {
+ for _, h := range z {
+ if h.pluginChain == nil {
+ continue
+ }
+
+ if h.metaCollector != nil {
+ // Collect metadata now, so it can be used before we send a request down the plugin chain.
+ ctx = h.metaCollector.Collect(ctx, request.Request{Req: r, W: w})
+ }
+
+ // If all filter funcs pass, use this config.
+ if passAllFilterFuncs(ctx, h.FilterFuncs, &request.Request{Req: r, W: w}) {
+ if h.ViewName != "" {
+ // if there was a view defined for this Config, set the view name in the context
+ ctx = context.WithValue(ctx, ViewKey{}, h.ViewName)
+ }
+ rcode, _ := h.pluginChain.ServeDNS(ctx, w, r)
+ if !plugin.ClientWrite(rcode) {
+ errorFunc(s.Addr, w, r, rcode)
+ }
+ return
+ }
}
- return
}
// Still here? Error out with REFUSED.
errorAndMetricsFunc(s.Addr, w, r, dns.RcodeRefused)
}
+// passAllFilterFuncs returns true if all filter funcs evaluate to true for the given request
+func passAllFilterFuncs(ctx context.Context, filterFuncs []FilterFunc, req *request.Request) bool {
+ for _, ff := range filterFuncs {
+ if !ff(ctx, req) {
+ return false
+ }
+ }
+ return true
+}
+
// OnStartupComplete lists the sites served by this server
// and any relevant information, assuming Quiet is false.
func (s *Server) OnStartupComplete() {
@@ -341,7 +396,7 @@ func errorAndMetricsFunc(server string, w dns.ResponseWriter, r *dns.Msg, rc int
answer.SetRcode(r, rc)
state.SizeAndDo(answer)
- vars.Report(server, state, vars.Dropped, rcode.ToString(rc), "" /* plugin */, answer.Len(), time.Now())
+ vars.Report(server, state, vars.Dropped, "", rcode.ToString(rc), "" /* plugin */, answer.Len(), time.Now())
w.WriteMsg(answer)
}
@@ -357,6 +412,9 @@ type (
// LoopKey is the context key to detect server wide loops.
LoopKey struct{}
+
+ // ViewKey is the context key for the current view, if defined
+ ViewKey struct{}
)
// EnableChaos is a map with plugin names for which we should open CH class queries as we block these by default.