| 
									
										
										
										
											2016-10-12 12:46:35 +01:00
										 |  |  | // Package dnsserver implements all the interfaces from Caddy, so that CoreDNS can be a servertype plugin.
 | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | package dnsserver
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import (
 | 
					
						
							| 
									
										
										
										
											2018-04-20 11:01:06 +01:00
										 |  |  | 	"context"
 | 
					
						
							| 
									
										
										
										
											2016-09-17 21:24:39 +01:00
										 |  |  | 	"fmt"
 | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | 	"net"
 | 
					
						
							|  |  |  | 	"runtime"
 | 
					
						
							|  |  |  | 	"sync"
 | 
					
						
							|  |  |  | 	"time"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-14 09:36:06 +01:00
										 |  |  | 	"github.com/coredns/coredns/plugin"
 | 
					
						
							|  |  |  | 	"github.com/coredns/coredns/plugin/metrics/vars"
 | 
					
						
							|  |  |  | 	"github.com/coredns/coredns/plugin/pkg/edns"
 | 
					
						
							| 
									
										
										
										
											2018-04-18 21:02:01 +01:00
										 |  |  | 	"github.com/coredns/coredns/plugin/pkg/log"
 | 
					
						
							| 
									
										
										
										
											2017-09-14 09:36:06 +01:00
										 |  |  | 	"github.com/coredns/coredns/plugin/pkg/rcode"
 | 
					
						
							|  |  |  | 	"github.com/coredns/coredns/plugin/pkg/trace"
 | 
					
						
							| 
									
										
										
										
											2017-02-21 22:51:47 -08:00
										 |  |  | 	"github.com/coredns/coredns/request"
 | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/miekg/dns"
 | 
					
						
							| 
									
										
										
										
											2017-04-18 11:10:49 -04:00
										 |  |  | 	ot "github.com/opentracing/opentracing-go"
 | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | )
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Server represents an instance of a server, which serves
 | 
					
						
							|  |  |  | // DNS requests at a particular address (host and port). A
 | 
					
						
							|  |  |  | // server is capable of serving numerous zones on
 | 
					
						
							|  |  |  | // the same address and the listener may be stopped for
 | 
					
						
							|  |  |  | // graceful termination (POSIX only).
 | 
					
						
							|  |  |  | type Server struct {
 | 
					
						
							| 
									
										
										
										
											2017-02-19 20:34:09 +00:00
										 |  |  | 	Addr string // Address we listen on
 | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-19 20:34:09 +00:00
										 |  |  | 	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
 | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	zones       map[string]*Config // zones keyed by their address
 | 
					
						
							|  |  |  | 	dnsWg       sync.WaitGroup     // used to wait on outstanding connections
 | 
					
						
							|  |  |  | 	connTimeout time.Duration      // the maximum duration of a graceful shutdown
 | 
					
						
							| 
									
										
										
										
											2017-09-14 09:36:06 +01:00
										 |  |  | 	trace       trace.Trace        // the trace plugin for the server
 | 
					
						
							| 
									
										
										
										
											2017-06-13 15:47:17 -07:00
										 |  |  | 	debug       bool               // disable recover()
 | 
					
						
							| 
									
										
										
										
											2017-08-25 08:55:53 +01:00
										 |  |  | 	classChaos  bool               // allow non-INET class queries
 | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-24 10:16:03 +01:00
										 |  |  | // NewServer returns a new CoreDNS server and compiles all plugins in to it. By default CH class
 | 
					
						
							| 
									
										
										
										
											2018-02-08 12:59:30 +00:00
										 |  |  | // queries are blocked unless queries from enableChaos are loaded.
 | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | func NewServer(addr string, group []*Config) (*Server, error) {
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	s := &Server{
 | 
					
						
							|  |  |  | 		Addr:        addr,
 | 
					
						
							|  |  |  | 		zones:       make(map[string]*Config),
 | 
					
						
							|  |  |  | 		connTimeout: 5 * time.Second, // TODO(miek): was configurable
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// We have to bound our wg with one increment
 | 
					
						
							|  |  |  | 	// to prevent a "race condition" that is hard-coded
 | 
					
						
							|  |  |  | 	// into sync.WaitGroup.Wait() - basically, an add
 | 
					
						
							|  |  |  | 	// with a positive delta must be guaranteed to
 | 
					
						
							|  |  |  | 	// occur before Wait() is called on the wg.
 | 
					
						
							|  |  |  | 	// In a way, this kind of acts as a safety barrier.
 | 
					
						
							|  |  |  | 	s.dnsWg.Add(1)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for _, site := range group {
 | 
					
						
							| 
									
										
										
										
											2017-06-13 15:47:17 -07:00
										 |  |  | 		if site.Debug {
 | 
					
						
							|  |  |  | 			s.debug = true
 | 
					
						
							| 
									
										
										
										
											2018-04-18 21:02:01 +01:00
										 |  |  | 			log.D = true
 | 
					
						
							| 
									
										
										
										
											2017-06-13 15:47:17 -07:00
										 |  |  | 		}
 | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | 		// set the config per zone
 | 
					
						
							|  |  |  | 		s.zones[site.Zone] = site
 | 
					
						
							| 
									
										
										
										
											2017-09-14 09:36:06 +01:00
										 |  |  | 		// compile custom plugin for everything
 | 
					
						
							| 
									
										
										
										
											2018-02-23 11:54:42 -05:00
										 |  |  | 		if site.registry != nil {
 | 
					
						
							|  |  |  | 			// this config is already computed with the chain of plugin
 | 
					
						
							| 
									
										
										
										
											2018-03-27 18:32:21 +03:00
										 |  |  | 			// set classChaos in accordance with previously registered plugins
 | 
					
						
							|  |  |  | 			for name := range enableChaos {
 | 
					
						
							|  |  |  | 				if _, ok := site.registry[name]; ok {
 | 
					
						
							|  |  |  | 					s.classChaos = true
 | 
					
						
							|  |  |  | 					break
 | 
					
						
							|  |  |  | 				}
 | 
					
						
							|  |  |  | 			}
 | 
					
						
							|  |  |  | 			// set trace handler in accordance with previously registered "trace" plugin
 | 
					
						
							|  |  |  | 			if handler, ok := site.registry["trace"]; ok {
 | 
					
						
							|  |  |  | 				s.trace = handler.(trace.Trace)
 | 
					
						
							|  |  |  | 			}
 | 
					
						
							| 
									
										
										
										
											2018-02-23 11:54:42 -05:00
										 |  |  | 			continue
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							| 
									
										
										
										
											2017-09-14 09:36:06 +01:00
										 |  |  | 		var stack plugin.Handler
 | 
					
						
							|  |  |  | 		for i := len(site.Plugin) - 1; i >= 0; i-- {
 | 
					
						
							|  |  |  | 			stack = site.Plugin[i](stack)
 | 
					
						
							| 
									
										
										
										
											2017-08-22 14:21:42 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			// register the *handler* also
 | 
					
						
							|  |  |  | 			site.registerHandler(stack)
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-18 11:10:49 -04:00
										 |  |  | 			if s.trace == nil && stack.Name() == "trace" {
 | 
					
						
							| 
									
										
										
										
											2017-09-14 09:36:06 +01:00
										 |  |  | 				// we have to stash away the plugin, not the
 | 
					
						
							| 
									
										
										
										
											2017-04-18 11:10:49 -04:00
										 |  |  | 				// Tracer object, because the Tracer won't be initialized yet
 | 
					
						
							|  |  |  | 				if t, ok := stack.(trace.Trace); ok {
 | 
					
						
							|  |  |  | 					s.trace = t
 | 
					
						
							|  |  |  | 				}
 | 
					
						
							|  |  |  | 			}
 | 
					
						
							| 
									
										
										
										
											2018-02-08 12:59:30 +00:00
										 |  |  | 			// Unblock CH class queries when any of these plugins are loaded.
 | 
					
						
							|  |  |  | 			if _, ok := enableChaos[stack.Name()]; ok {
 | 
					
						
							| 
									
										
										
										
											2017-08-25 08:55:53 +01:00
										 |  |  | 				s.classChaos = true
 | 
					
						
							|  |  |  | 			}
 | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | 		}
 | 
					
						
							| 
									
										
										
										
											2017-09-14 09:36:06 +01:00
										 |  |  | 		site.pluginChain = stack
 | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return s, nil
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Serve starts the server with an existing listener. It blocks until the server stops.
 | 
					
						
							| 
									
										
										
										
											2017-02-10 19:50:31 +00:00
										 |  |  | // This implements caddy.TCPServer interface.
 | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | func (s *Server) Serve(l net.Listener) error {
 | 
					
						
							|  |  |  | 	s.m.Lock()
 | 
					
						
							| 
									
										
										
										
											2017-03-09 09:11:59 +00:00
										 |  |  | 	s.server[tcp] = &dns.Server{Listener: l, Net: "tcp", Handler: dns.HandlerFunc(func(w dns.ResponseWriter, r *dns.Msg) {
 | 
					
						
							| 
									
										
										
										
											2018-02-14 15:11:26 -05:00
										 |  |  | 		ctx := context.WithValue(context.Background(), Key{}, s)
 | 
					
						
							| 
									
										
										
										
											2017-03-09 09:11:59 +00:00
										 |  |  | 		s.ServeDNS(ctx, w, r)
 | 
					
						
							|  |  |  | 	})}
 | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | 	s.m.Unlock()
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return s.server[tcp].ActivateAndServe()
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // ServePacket starts the server with an existing packetconn. It blocks until the server stops.
 | 
					
						
							| 
									
										
										
										
											2017-02-10 19:50:31 +00:00
										 |  |  | // This implements caddy.UDPServer interface.
 | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | func (s *Server) ServePacket(p net.PacketConn) error {
 | 
					
						
							|  |  |  | 	s.m.Lock()
 | 
					
						
							| 
									
										
										
										
											2017-03-09 09:11:59 +00:00
										 |  |  | 	s.server[udp] = &dns.Server{PacketConn: p, Net: "udp", Handler: dns.HandlerFunc(func(w dns.ResponseWriter, r *dns.Msg) {
 | 
					
						
							| 
									
										
										
										
											2018-02-14 15:11:26 -05:00
										 |  |  | 		ctx := context.WithValue(context.Background(), Key{}, s)
 | 
					
						
							| 
									
										
										
										
											2017-03-09 09:11:59 +00:00
										 |  |  | 		s.ServeDNS(ctx, w, r)
 | 
					
						
							|  |  |  | 	})}
 | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | 	s.m.Unlock()
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return s.server[udp].ActivateAndServe()
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-20 23:03:36 +01:00
										 |  |  | // Listen implements caddy.TCPServer interface.
 | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | func (s *Server) Listen() (net.Listener, error) {
 | 
					
						
							| 
									
										
										
										
											2017-03-13 20:24:37 +00:00
										 |  |  | 	l, err := net.Listen("tcp", s.Addr[len(TransportDNS+"://"):])
 | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | 	if err != nil {
 | 
					
						
							|  |  |  | 		return nil, err
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 	return l, nil
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-20 23:03:36 +01:00
										 |  |  | // ListenPacket implements caddy.UDPServer interface.
 | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | func (s *Server) ListenPacket() (net.PacketConn, error) {
 | 
					
						
							| 
									
										
										
										
											2017-03-13 20:24:37 +00:00
										 |  |  | 	p, err := net.ListenPacket("udp", s.Addr[len(TransportDNS+"://"):])
 | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | 	if err != nil {
 | 
					
						
							|  |  |  | 		return nil, err
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return p, nil
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Stop stops the server. It blocks until the server is
 | 
					
						
							|  |  |  | // totally stopped. On POSIX systems, it will wait for
 | 
					
						
							|  |  |  | // connections to close (up to a max timeout of a few
 | 
					
						
							|  |  |  | // seconds); on Windows it will close the listener
 | 
					
						
							|  |  |  | // immediately.
 | 
					
						
							| 
									
										
										
										
											2017-02-10 19:50:31 +00:00
										 |  |  | // This implements Caddy.Stopper interface.
 | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | func (s *Server) Stop() (err error) {
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if runtime.GOOS != "windows" {
 | 
					
						
							|  |  |  | 		// force connections to close after timeout
 | 
					
						
							|  |  |  | 		done := make(chan struct{})
 | 
					
						
							|  |  |  | 		go func() {
 | 
					
						
							|  |  |  | 			s.dnsWg.Done() // decrement our initial increment used as a barrier
 | 
					
						
							|  |  |  | 			s.dnsWg.Wait()
 | 
					
						
							|  |  |  | 			close(done)
 | 
					
						
							|  |  |  | 		}()
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Wait for remaining connections to finish or
 | 
					
						
							|  |  |  | 		// force them all to close after timeout
 | 
					
						
							|  |  |  | 		select {
 | 
					
						
							|  |  |  | 		case <-time.After(s.connTimeout):
 | 
					
						
							|  |  |  | 		case <-done:
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Close the listener now; this stops the server without delay
 | 
					
						
							|  |  |  | 	s.m.Lock()
 | 
					
						
							|  |  |  | 	for _, s1 := range s.server {
 | 
					
						
							| 
									
										
										
										
											2017-02-10 19:50:31 +00:00
										 |  |  | 		// We might not have started and initialized the full set of servers
 | 
					
						
							|  |  |  | 		if s1 != nil {
 | 
					
						
							|  |  |  | 			err = s1.Shutdown()
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | 	}
 | 
					
						
							|  |  |  | 	s.m.Unlock()
 | 
					
						
							|  |  |  | 	return
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-10 19:50:31 +00:00
										 |  |  | // Address together with Stop() implement caddy.GracefulServer.
 | 
					
						
							|  |  |  | func (s *Server) Address() string { return s.Addr }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | // ServeDNS is the entry point for every request to the address that s
 | 
					
						
							|  |  |  | // is bound to. It acts as a multiplexer for the requests zonename as
 | 
					
						
							|  |  |  | // defined in the request so that the correct zone
 | 
					
						
							| 
									
										
										
										
											2017-09-14 09:36:06 +01:00
										 |  |  | // (configuration and plugin stack) will handle the request.
 | 
					
						
							| 
									
										
										
										
											2017-03-09 09:11:59 +00:00
										 |  |  | func (s *Server) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) {
 | 
					
						
							| 
									
										
										
										
											2017-11-10 11:19:49 +00:00
										 |  |  | 	// The default dns.Mux checks the question section size, but we have our
 | 
					
						
							|  |  |  | 	// own mux here. Check if we have a question section. If not drop them here.
 | 
					
						
							| 
									
										
										
										
											2017-09-29 22:27:40 +01:00
										 |  |  | 	if r == nil || len(r.Question) == 0 {
 | 
					
						
							| 
									
										
										
										
											2018-04-18 09:42:20 +01:00
										 |  |  | 		DefaultErrorFunc(ctx, w, r, dns.RcodeServerFailure)
 | 
					
						
							| 
									
										
										
										
											2017-09-29 22:27:40 +01:00
										 |  |  | 		return
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-13 15:47:17 -07:00
										 |  |  | 	if !s.debug {
 | 
					
						
							|  |  |  | 		defer func() {
 | 
					
						
							| 
									
										
										
										
											2017-09-14 09:36:06 +01:00
										 |  |  | 			// In case the user doesn't enable error plugin, we still
 | 
					
						
							| 
									
										
										
										
											2017-06-13 15:47:17 -07:00
										 |  |  | 			// need to make sure that we stay alive up here
 | 
					
						
							|  |  |  | 			if rec := recover(); rec != nil {
 | 
					
						
							| 
									
										
										
										
											2018-04-18 09:42:20 +01:00
										 |  |  | 				DefaultErrorFunc(ctx, w, r, dns.RcodeServerFailure)
 | 
					
						
							| 
									
										
										
										
											2017-06-13 15:47:17 -07:00
										 |  |  | 			}
 | 
					
						
							|  |  |  | 		}()
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-25 08:55:53 +01:00
										 |  |  | 	if !s.classChaos && r.Question[0].Qclass != dns.ClassINET {
 | 
					
						
							| 
									
										
										
										
											2018-04-18 09:42:20 +01:00
										 |  |  | 		DefaultErrorFunc(ctx, w, r, dns.RcodeRefused)
 | 
					
						
							| 
									
										
										
										
											2017-08-25 08:55:53 +01:00
										 |  |  | 		return
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-07 11:10:16 +01:00
										 |  |  | 	if m, err := edns.Version(r); err != nil { // Wrong EDNS version, return at once.
 | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | 		w.WriteMsg(m)
 | 
					
						
							|  |  |  | 		return
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-14 15:11:26 -05:00
										 |  |  | 	ctx, err := incrementDepthAndCheck(ctx)
 | 
					
						
							|  |  |  | 	if err != nil {
 | 
					
						
							| 
									
										
										
										
											2018-04-18 09:42:20 +01:00
										 |  |  | 		DefaultErrorFunc(ctx, w, r, dns.RcodeServerFailure)
 | 
					
						
							| 
									
										
										
										
											2018-02-14 15:11:26 -05:00
										 |  |  | 		return
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | 	q := r.Question[0].Name
 | 
					
						
							|  |  |  | 	b := make([]byte, len(q))
 | 
					
						
							| 
									
										
										
										
											2017-08-06 05:54:24 -07:00
										 |  |  | 	var off int
 | 
					
						
							|  |  |  | 	var end bool
 | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-19 17:46:03 +01:00
										 |  |  | 	var dshandler *Config
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | 	for {
 | 
					
						
							|  |  |  | 		l := len(q[off:])
 | 
					
						
							|  |  |  | 		for i := 0; i < l; i++ {
 | 
					
						
							|  |  |  | 			b[i] = q[off+i]
 | 
					
						
							|  |  |  | 			// normalize the name for the lookup
 | 
					
						
							|  |  |  | 			if b[i] >= 'A' && b[i] <= 'Z' {
 | 
					
						
							|  |  |  | 				b[i] |= ('a' - 'A')
 | 
					
						
							|  |  |  | 			}
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if h, ok := s.zones[string(b[:l])]; ok {
 | 
					
						
							| 
									
										
										
											
												Metrics (#1579)
* plugin/metrics: set server address in context
Allow cross server block metrics to co-exist; for this we should label
each metric with the server label. Put this information in the context
and provide a helper function to get it out.
Abstracting with entirely away with difficult as the release client_go
(0.8.0) doesn't have the CurryWith functions yet. So current use is like
so:
define metric, with server label:
	RcodeCount = prometheus.NewCounterVec(prometheus.CounterOpts{
		Namespace: plugin.Namespace,
		Subsystem: "forward",
		Name:      "response_rcode_count_total",
		Help:      "Counter of requests made per upstream.",
	}, []string{"server", "rcode", "to"})
And report ith with the helper function metrics.WithServer:
	RcodeCount.WithLabelValues(metrics.WithServer(ctx), rc, p.addr).Add(1)
											
										 
											2018-04-01 13:57:03 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			// Set server's address in the context so plugins can reference back to this,
 | 
					
						
							|  |  |  | 			// This will makes those metrics unique.
 | 
					
						
							|  |  |  | 			ctx = context.WithValue(ctx, plugin.ServerCtx{}, s.Addr)
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | 			if r.Question[0].Qtype != dns.TypeDS {
 | 
					
						
							| 
									
										
										
										
											2017-10-24 10:16:03 +01:00
										 |  |  | 				if h.FilterFunc == nil {
 | 
					
						
							|  |  |  | 					rcode, _ := h.pluginChain.ServeDNS(ctx, w, r)
 | 
					
						
							|  |  |  | 					if !plugin.ClientWrite(rcode) {
 | 
					
						
							| 
									
										
										
										
											2018-04-18 09:42:20 +01:00
										 |  |  | 						DefaultErrorFunc(ctx, w, r, rcode)
 | 
					
						
							| 
									
										
										
										
											2017-10-24 10:16:03 +01:00
										 |  |  | 					}
 | 
					
						
							|  |  |  | 					return
 | 
					
						
							|  |  |  | 				}
 | 
					
						
							|  |  |  | 				// FilterFunc is set, call it to see if we should use this handler.
 | 
					
						
							|  |  |  | 				// This is given to full query name.
 | 
					
						
							|  |  |  | 				if h.FilterFunc(q) {
 | 
					
						
							|  |  |  | 					rcode, _ := h.pluginChain.ServeDNS(ctx, w, r)
 | 
					
						
							|  |  |  | 					if !plugin.ClientWrite(rcode) {
 | 
					
						
							| 
									
										
										
										
											2018-04-18 09:42:20 +01:00
										 |  |  | 						DefaultErrorFunc(ctx, w, r, rcode)
 | 
					
						
							| 
									
										
										
										
											2017-10-24 10:16:03 +01:00
										 |  |  | 					}
 | 
					
						
							|  |  |  | 					return
 | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | 				}
 | 
					
						
							|  |  |  | 			}
 | 
					
						
							| 
									
										
										
										
											2016-10-19 17:46:03 +01:00
										 |  |  | 			// 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 actually delegation from grandparent -> parent -> zone.
 | 
					
						
							|  |  |  | 			// In all fairness: direct DS queries should not be needed.
 | 
					
						
							|  |  |  | 			dshandler = h
 | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | 		}
 | 
					
						
							|  |  |  | 		off, end = dns.NextLabel(q, off)
 | 
					
						
							|  |  |  | 		if end {
 | 
					
						
							|  |  |  | 			break
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							| 
									
										
										
										
											2016-10-19 17:46:03 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-22 08:55:35 +00:00
										 |  |  | 	if r.Question[0].Qtype == dns.TypeDS && dshandler != nil && dshandler.pluginChain != nil {
 | 
					
						
							| 
									
										
										
										
											2017-10-24 10:16:03 +01:00
										 |  |  | 		// DS request, and we found a zone, use the handler for the query.
 | 
					
						
							| 
									
										
										
										
											2017-09-14 09:36:06 +01:00
										 |  |  | 		rcode, _ := dshandler.pluginChain.ServeDNS(ctx, w, r)
 | 
					
						
							|  |  |  | 		if !plugin.ClientWrite(rcode) {
 | 
					
						
							| 
									
										
										
										
											2018-04-18 09:42:20 +01:00
										 |  |  | 			DefaultErrorFunc(ctx, w, r, rcode)
 | 
					
						
							| 
									
										
										
										
											2016-10-19 17:46:03 +01:00
										 |  |  | 		}
 | 
					
						
							|  |  |  | 		return
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | 	// Wildcard match, if we have found nothing try the root zone as a last resort.
 | 
					
						
							| 
									
										
										
										
											2017-12-22 08:55:35 +00:00
										 |  |  | 	if h, ok := s.zones["."]; ok && h.pluginChain != nil {
 | 
					
						
							| 
									
										
										
											
												Metrics (#1579)
* plugin/metrics: set server address in context
Allow cross server block metrics to co-exist; for this we should label
each metric with the server label. Put this information in the context
and provide a helper function to get it out.
Abstracting with entirely away with difficult as the release client_go
(0.8.0) doesn't have the CurryWith functions yet. So current use is like
so:
define metric, with server label:
	RcodeCount = prometheus.NewCounterVec(prometheus.CounterOpts{
		Namespace: plugin.Namespace,
		Subsystem: "forward",
		Name:      "response_rcode_count_total",
		Help:      "Counter of requests made per upstream.",
	}, []string{"server", "rcode", "to"})
And report ith with the helper function metrics.WithServer:
	RcodeCount.WithLabelValues(metrics.WithServer(ctx), rc, p.addr).Add(1)
											
										 
											2018-04-01 13:57:03 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// See comment above.
 | 
					
						
							|  |  |  | 		ctx = context.WithValue(ctx, plugin.ServerCtx{}, s.Addr)
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-14 09:36:06 +01:00
										 |  |  | 		rcode, _ := h.pluginChain.ServeDNS(ctx, w, r)
 | 
					
						
							|  |  |  | 		if !plugin.ClientWrite(rcode) {
 | 
					
						
							| 
									
										
										
										
											2018-04-18 09:42:20 +01:00
										 |  |  | 			DefaultErrorFunc(ctx, w, r, rcode)
 | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | 		}
 | 
					
						
							|  |  |  | 		return
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-01 17:59:07 -08:00
										 |  |  | 	// Still here? Error out with REFUSED.
 | 
					
						
							| 
									
										
										
										
											2018-04-18 09:42:20 +01:00
										 |  |  | 	DefaultErrorFunc(ctx, w, r, dns.RcodeRefused)
 | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-17 21:24:39 +01:00
										 |  |  | // OnStartupComplete lists the sites served by this server
 | 
					
						
							| 
									
										
										
										
											2016-09-25 18:42:08 +01:00
										 |  |  | // and any relevant information, assuming Quiet is false.
 | 
					
						
							| 
									
										
										
										
											2016-09-17 21:24:39 +01:00
										 |  |  | func (s *Server) OnStartupComplete() {
 | 
					
						
							|  |  |  | 	if Quiet {
 | 
					
						
							|  |  |  | 		return
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-17 19:04:01 +00:00
										 |  |  | 	out := startUpZones("", s.Addr, s.zones)
 | 
					
						
							|  |  |  | 	if out != "" {
 | 
					
						
							|  |  |  | 		fmt.Print(out)
 | 
					
						
							| 
									
										
										
										
											2016-09-17 21:24:39 +01:00
										 |  |  | 	}
 | 
					
						
							| 
									
										
										
										
											2018-03-17 19:04:01 +00:00
										 |  |  | 	return
 | 
					
						
							| 
									
										
										
										
											2016-09-17 21:24:39 +01:00
										 |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-21 09:30:59 +01:00
										 |  |  | // Tracer returns the tracer in the server if defined.
 | 
					
						
							| 
									
										
										
										
											2017-04-18 11:10:49 -04:00
										 |  |  | func (s *Server) Tracer() ot.Tracer {
 | 
					
						
							|  |  |  | 	if s.trace == nil {
 | 
					
						
							|  |  |  | 		return nil
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return s.trace.Tracer()
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | // DefaultErrorFunc responds to an DNS request with an error.
 | 
					
						
							| 
									
										
										
										
											2018-04-18 09:42:20 +01:00
										 |  |  | func DefaultErrorFunc(ctx context.Context, w dns.ResponseWriter, r *dns.Msg, rc int) {
 | 
					
						
							| 
									
										
										
										
											2016-09-07 11:10:16 +01:00
										 |  |  | 	state := request.Request{W: w, Req: r}
 | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	answer := new(dns.Msg)
 | 
					
						
							| 
									
										
										
										
											2016-10-26 10:01:52 +01:00
										 |  |  | 	answer.SetRcode(r, rc)
 | 
					
						
							| 
									
										
										
										
											2016-09-07 11:10:16 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | 	state.SizeAndDo(answer)
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-18 09:42:20 +01:00
										 |  |  | 	vars.Report(ctx, state, vars.Dropped, rcode.ToString(rc), answer.Len(), time.Now())
 | 
					
						
							| 
									
										
										
										
											2016-10-26 10:01:52 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | 	w.WriteMsg(answer)
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-14 15:11:26 -05:00
										 |  |  | // incrementDepthAndCheck increments the loop counter in the context, and returns an error if
 | 
					
						
							|  |  |  | // the counter exceeds the max number of re-entries
 | 
					
						
							|  |  |  | func incrementDepthAndCheck(ctx context.Context) (context.Context, error) {
 | 
					
						
							|  |  |  | 	// Loop counter for self directed lookups
 | 
					
						
							|  |  |  | 	loop := ctx.Value(loopKey{})
 | 
					
						
							|  |  |  | 	if loop == nil {
 | 
					
						
							|  |  |  | 		ctx = context.WithValue(ctx, loopKey{}, 0)
 | 
					
						
							|  |  |  | 		return ctx, nil
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	iloop := loop.(int) + 1
 | 
					
						
							|  |  |  | 	if iloop > maxreentries {
 | 
					
						
							|  |  |  | 		return ctx, fmt.Errorf("too deep")
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 	ctx = context.WithValue(ctx, loopKey{}, iloop)
 | 
					
						
							|  |  |  | 	return ctx, nil
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | const (
 | 
					
						
							| 
									
										
										
										
											2018-02-14 15:11:26 -05:00
										 |  |  | 	tcp          = 0
 | 
					
						
							|  |  |  | 	udp          = 1
 | 
					
						
							|  |  |  | 	maxreentries = 10
 | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | )
 | 
					
						
							| 
									
										
										
										
											2016-09-25 18:42:08 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
											
												Metrics (#1579)
* plugin/metrics: set server address in context
Allow cross server block metrics to co-exist; for this we should label
each metric with the server label. Put this information in the context
and provide a helper function to get it out.
Abstracting with entirely away with difficult as the release client_go
(0.8.0) doesn't have the CurryWith functions yet. So current use is like
so:
define metric, with server label:
	RcodeCount = prometheus.NewCounterVec(prometheus.CounterOpts{
		Namespace: plugin.Namespace,
		Subsystem: "forward",
		Name:      "response_rcode_count_total",
		Help:      "Counter of requests made per upstream.",
	}, []string{"server", "rcode", "to"})
And report ith with the helper function metrics.WithServer:
	RcodeCount.WithLabelValues(metrics.WithServer(ctx), rc, p.addr).Add(1)
											
										 
											2018-04-01 13:57:03 +01:00
										 |  |  | type (
 | 
					
						
							|  |  |  | 	// Key is the context key for the current server
 | 
					
						
							|  |  |  | 	Key     struct{}
 | 
					
						
							|  |  |  | 	loopKey struct{} // loopKey is the context key for counting self loops
 | 
					
						
							|  |  |  | )
 | 
					
						
							| 
									
										
										
										
											2018-02-14 15:11:26 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-08 12:59:30 +00:00
										 |  |  | // enableChaos is a map with plugin names for which we should open CH class queries as
 | 
					
						
							|  |  |  | // we block these by default.
 | 
					
						
							|  |  |  | var enableChaos = map[string]bool{
 | 
					
						
							|  |  |  | 	"chaos":   true,
 | 
					
						
							|  |  |  | 	"forward": true,
 | 
					
						
							|  |  |  | 	"proxy":   true,
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-21 09:30:59 +01:00
										 |  |  | // Quiet mode will not show any informative output on initialization.
 | 
					
						
							|  |  |  | var Quiet bool
 |