| 
									
										
										
										
											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" | 
					
						
							| 
									
										
										
										
											2022-05-24 14:36:36 +02:00
										 |  |  | 	"runtime/debug" | 
					
						
							| 
									
										
										
										
											2019-09-25 18:18:54 +01:00
										 |  |  | 	"strings" | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | 	"sync" | 
					
						
							|  |  |  | 	"time" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-24 18:14:41 +02:00
										 |  |  | 	"github.com/coredns/caddy" | 
					
						
							| 
									
										
										
										
											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" | 
					
						
							| 
									
										
										
										
											2019-11-17 02:02:46 +00:00
										 |  |  | 	"github.com/coredns/coredns/plugin/pkg/reuseport" | 
					
						
							| 
									
										
										
										
											2017-09-14 09:36:06 +01:00
										 |  |  | 	"github.com/coredns/coredns/plugin/pkg/trace" | 
					
						
							| 
									
										
										
										
											2018-09-19 07:29:37 +01:00
										 |  |  | 	"github.com/coredns/coredns/plugin/pkg/transport" | 
					
						
							| 
									
										
										
										
											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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-08 14:56:27 -04:00
										 |  |  | 	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 | 
					
						
							| 
									
										
										
										
											2022-12-28 11:14:16 +00:00
										 |  |  | 	idleTimeout  time.Duration        // Idle timeout for TCP | 
					
						
							|  |  |  | 	readTimeout  time.Duration        // Read timeout for TCP | 
					
						
							|  |  |  | 	writeTimeout time.Duration        // Write timeout for TCP | 
					
						
							| 
									
										
										
										
											2022-06-27 15:48:34 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	tsigSecret map[string]string | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-08 14:56:27 -04:00
										 |  |  | // MetadataCollector is a plugin that can retrieve metadata functions from all metadata providing plugins | 
					
						
							|  |  |  | type MetadataCollector interface { | 
					
						
							|  |  |  | 	Collect(context.Context, request.Request) context.Context | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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{ | 
					
						
							| 
									
										
										
										
											2019-03-31 08:32:55 +01:00
										 |  |  | 		Addr:         addr, | 
					
						
							| 
									
										
										
										
											2022-09-08 14:56:27 -04:00
										 |  |  | 		zones:        make(map[string][]*Config), | 
					
						
							| 
									
										
										
										
											2019-03-31 08:32:55 +01:00
										 |  |  | 		graceTimeout: 5 * time.Second, | 
					
						
							| 
									
										
										
										
											2022-12-28 11:14:16 +00:00
										 |  |  | 		idleTimeout:  10 * time.Second, | 
					
						
							|  |  |  | 		readTimeout:  3 * time.Second, | 
					
						
							|  |  |  | 		writeTimeout: 5 * time.Second, | 
					
						
							| 
									
										
										
										
											2022-07-04 10:29:59 +00:00
										 |  |  | 		tsigSecret:   make(map[string]string), | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// 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 | 
					
						
							| 
									
										
										
										
											2019-05-23 21:02:30 +01:00
										 |  |  | 			log.D.Set() | 
					
						
							| 
									
										
										
										
											2017-06-13 15:47:17 -07:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2022-05-24 14:36:36 +02:00
										 |  |  | 		s.stacktrace = site.Stacktrace | 
					
						
							| 
									
										
										
										
											2022-09-08 14:56:27 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// append the config to the zone's configs | 
					
						
							|  |  |  | 		s.zones[site.Zone] = append(s.zones[site.Zone], site) | 
					
						
							| 
									
										
										
										
											2019-03-30 11:50:19 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-28 11:14:16 +00:00
										 |  |  | 		// set timeouts | 
					
						
							|  |  |  | 		if site.ReadTimeout != 0 { | 
					
						
							|  |  |  | 			s.readTimeout = site.ReadTimeout | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if site.WriteTimeout != 0 { | 
					
						
							|  |  |  | 			s.writeTimeout = site.WriteTimeout | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if site.IdleTimeout != 0 { | 
					
						
							|  |  |  | 			s.idleTimeout = site.IdleTimeout | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-27 15:48:34 -04:00
										 |  |  | 		// copy tsig secrets | 
					
						
							|  |  |  | 		for key, secret := range site.TsigSecret { | 
					
						
							|  |  |  | 			s.tsigSecret[key] = secret | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-14 09:36:06 +01:00
										 |  |  | 		// compile custom plugin for everything | 
					
						
							|  |  |  | 		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) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-08 14:56:27 -04:00
										 |  |  | 			// 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 | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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. | 
					
						
							| 
									
										
										
										
											2018-12-10 10:17:15 +00:00
										 |  |  | 			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
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-24 09:12:00 +02:00
										 |  |  | 	if !s.debug { | 
					
						
							|  |  |  | 		// When reloading we need to explicitly disable debug logging if it is now disabled. | 
					
						
							|  |  |  | 		log.D.Clear() | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | 	return s, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-06 16:25:07 +08:00
										 |  |  | // Compile-time check to ensure Server implements the caddy.GracefulServer interface | 
					
						
							|  |  |  | var _ caddy.GracefulServer = &Server{} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | // 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() | 
					
						
							| 
									
										
										
										
											2022-12-28 11:14:16 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	s.server[tcp] = &dns.Server{Listener: l, | 
					
						
							|  |  |  | 		Net:           "tcp", | 
					
						
							|  |  |  | 		TsigSecret:    s.tsigSecret, | 
					
						
							|  |  |  | 		MaxTCPQueries: tcpMaxQueries, | 
					
						
							|  |  |  | 		ReadTimeout:   s.readTimeout, | 
					
						
							|  |  |  | 		WriteTimeout:  s.writeTimeout, | 
					
						
							|  |  |  | 		IdleTimeout: func() time.Duration { | 
					
						
							|  |  |  | 			return s.idleTimeout | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		Handler: dns.HandlerFunc(func(w dns.ResponseWriter, r *dns.Msg) { | 
					
						
							|  |  |  | 			ctx := context.WithValue(context.Background(), Key{}, s) | 
					
						
							|  |  |  | 			ctx = context.WithValue(ctx, LoopKey{}, 0) | 
					
						
							|  |  |  | 			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) | 
					
						
							| 
									
										
										
										
											2021-01-15 19:26:04 +01:00
										 |  |  | 		ctx = context.WithValue(ctx, LoopKey{}, 0) | 
					
						
							| 
									
										
										
										
											2017-03-09 09:11:59 +00:00
										 |  |  | 		s.ServeDNS(ctx, w, r) | 
					
						
							| 
									
										
										
										
											2022-06-27 15:48:34 -04:00
										 |  |  | 	}), TsigSecret: s.tsigSecret} | 
					
						
							| 
									
										
										
										
											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) { | 
					
						
							| 
									
										
										
										
											2019-11-17 02:02:46 +00:00
										 |  |  | 	l, err := reuseport.Listen("tcp", s.Addr[len(transport.DNS+"://"):]) | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return l, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-17 15:11:19 +00:00
										 |  |  | // WrapListener Listen implements caddy.GracefulServer interface. | 
					
						
							|  |  |  | func (s *Server) WrapListener(ln net.Listener) net.Listener { | 
					
						
							|  |  |  | 	return ln | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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) { | 
					
						
							| 
									
										
										
										
											2019-11-17 02:02:46 +00:00
										 |  |  | 	p, err := reuseport.ListenPacket("udp", s.Addr[len(transport.DNS+"://"):]) | 
					
						
							| 
									
										
										
										
											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 { | 
					
						
							| 
									
										
										
										
											2019-03-31 08:32:55 +01:00
										 |  |  | 		case <-time.After(s.graceTimeout): | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | 		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 } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-06 17:57:56 -07:00
										 |  |  | // ServeDNS is the entry point for every request to the address that | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | // 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 { | 
					
						
							| 
									
										
										
										
											2019-03-25 19:04:03 +00:00
										 |  |  | 		errorAndMetricsFunc(s.Addr, 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 { | 
					
						
							| 
									
										
										
										
											2022-05-24 14:36:36 +02:00
										 |  |  | 				if s.stacktrace { | 
					
						
							|  |  |  | 					log.Errorf("Recovered from panic in server: %q %v\n%s", s.Addr, rec, string(debug.Stack())) | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					log.Errorf("Recovered from panic in server: %q %v", s.Addr, rec) | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2018-05-05 19:47:41 +02:00
										 |  |  | 				vars.Panic.Inc() | 
					
						
							| 
									
										
										
										
											2019-03-25 19:04:03 +00:00
										 |  |  | 				errorAndMetricsFunc(s.Addr, 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 { | 
					
						
							| 
									
										
										
										
											2019-03-25 19:04:03 +00:00
										 |  |  | 		errorAndMetricsFunc(s.Addr, 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-08-29 12:26:22 +01:00
										 |  |  | 	// Wrap the response writer in a ScrubWriter so we automatically make the reply fit in the client's buffer. | 
					
						
							|  |  |  | 	w = request.NewScrubWriter(r, w) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-25 18:18:54 +01:00
										 |  |  | 	q := strings.ToLower(r.Question[0].Name) | 
					
						
							|  |  |  | 	var ( | 
					
						
							|  |  |  | 		off       int | 
					
						
							|  |  |  | 		end       bool | 
					
						
							|  |  |  | 		dshandler *Config | 
					
						
							|  |  |  | 	) | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-25 18:18:54 +01:00
										 |  |  | 	for { | 
					
						
							| 
									
										
										
										
											2022-09-08 14:56:27 -04:00
										 |  |  | 		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 | 
					
						
							| 
									
										
										
										
											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) { | 
					
						
							| 
									
										
										
										
											2019-03-25 17:46:44 +00:00
										 |  |  | 			errorFunc(s.Addr, 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. | 
					
						
							| 
									
										
										
										
											2022-09-08 14:56:27 -04:00
										 |  |  | 	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 | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-01 17:59:07 -08:00
										 |  |  | 	// Still here? Error out with REFUSED. | 
					
						
							| 
									
										
										
										
											2019-03-25 19:04:03 +00:00
										 |  |  | 	errorAndMetricsFunc(s.Addr, w, r, dns.RcodeRefused) | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-08 14:56:27 -04:00
										 |  |  | // 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 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-25 03:36:46 +00:00
										 |  |  | // errorFunc responds to an DNS request with an error. | 
					
						
							| 
									
										
										
										
											2019-03-25 17:46:44 +00:00
										 |  |  | func errorFunc(server string, 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) | 
					
						
							| 
									
										
										
										
											2019-03-25 19:04:03 +00:00
										 |  |  | 	state.SizeAndDo(answer) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	w.WriteMsg(answer) | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2016-09-07 11:10:16 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-25 19:04:03 +00:00
										 |  |  | func errorAndMetricsFunc(server string, w dns.ResponseWriter, r *dns.Msg, rc int) { | 
					
						
							|  |  |  | 	state := request.Request{W: w, Req: r} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	answer := new(dns.Msg) | 
					
						
							|  |  |  | 	answer.SetRcode(r, rc) | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | 	state.SizeAndDo(answer) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-08 14:56:27 -04:00
										 |  |  | 	vars.Report(server, state, vars.Dropped, "", rcode.ToString(rc), "" /* plugin */, answer.Len(), time.Now()) | 
					
						
							| 
									
										
										
										
											2016-10-26 10:01:52 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | 	w.WriteMsg(answer) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const ( | 
					
						
							| 
									
										
										
										
											2019-03-25 19:04:03 +00:00
										 |  |  | 	tcp = 0 | 
					
						
							|  |  |  | 	udp = 1 | 
					
						
							| 
									
										
										
										
											2022-12-28 11:14:16 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	tcpMaxQueries = -1 | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | ) | 
					
						
							| 
									
										
										
										
											2016-09-25 18:42:08 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-15 19:26:04 +01:00
										 |  |  | type ( | 
					
						
							|  |  |  | 	// Key is the context key for the current server added to the context. | 
					
						
							|  |  |  | 	Key struct{} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// LoopKey is the context key to detect server wide loops. | 
					
						
							|  |  |  | 	LoopKey struct{} | 
					
						
							| 
									
										
										
										
											2022-09-08 14:56:27 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// ViewKey is the context key for the current view, if defined | 
					
						
							|  |  |  | 	ViewKey struct{} | 
					
						
							| 
									
										
										
										
											2021-01-15 19:26:04 +01:00
										 |  |  | ) | 
					
						
							| 
									
										
										
										
											2018-02-14 15:11:26 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-10 10:17:15 +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]struct{}{ | 
					
						
							| 
									
										
										
										
											2019-04-08 11:13:46 +01:00
										 |  |  | 	"chaos":   {}, | 
					
						
							|  |  |  | 	"forward": {}, | 
					
						
							|  |  |  | 	"proxy":   {}, | 
					
						
							| 
									
										
										
										
											2018-02-08 12:59:30 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-21 09:30:59 +01:00
										 |  |  | // Quiet mode will not show any informative output on initialization. | 
					
						
							|  |  |  | var Quiet bool |