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"
|
2025-09-10 23:08:27 +03:00
|
|
|
"maps"
|
2016-08-19 17:14:17 -07:00
|
|
|
"net"
|
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 {
|
2025-09-09 19:06:44 -07:00
|
|
|
Addr string // Address we listen on
|
|
|
|
|
IdleTimeout time.Duration // Idle timeout for TCP
|
|
|
|
|
ReadTimeout time.Duration // Read timeout for TCP
|
|
|
|
|
WriteTimeout time.Duration // Write timeout for TCP
|
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
|
|
|
|
|
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-06-27 15:48:34 -04:00
|
|
|
|
|
|
|
|
tsigSecret map[string]string
|
2025-09-19 14:01:53 +03:00
|
|
|
|
|
|
|
|
// Ensure Stop is idempotent when invoked concurrently (e.g., during reload and SIGTERM).
|
2025-09-27 06:34:03 -07:00
|
|
|
stopOnce sync.Once
|
|
|
|
|
stopErr error
|
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,
|
2025-09-09 19:06:44 -07: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
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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 {
|
2025-09-09 19:06:44 -07:00
|
|
|
s.ReadTimeout = site.ReadTimeout
|
2022-12-28 11:14:16 +00:00
|
|
|
}
|
|
|
|
|
if site.WriteTimeout != 0 {
|
2025-09-09 19:06:44 -07:00
|
|
|
s.WriteTimeout = site.WriteTimeout
|
2022-12-28 11:14:16 +00:00
|
|
|
}
|
|
|
|
|
if site.IdleTimeout != 0 {
|
2025-09-09 19:06:44 -07:00
|
|
|
s.IdleTimeout = site.IdleTimeout
|
2022-12-28 11:14:16 +00:00
|
|
|
}
|
|
|
|
|
|
2022-06-27 15:48:34 -04:00
|
|
|
// copy tsig secrets
|
2025-09-10 23:08:27 +03:00
|
|
|
maps.Copy(s.tsigSecret, site.TsigSecret)
|
2022-06-27 15:48:34 -04:00
|
|
|
|
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,
|
2025-09-09 19:06:44 -07:00
|
|
|
ReadTimeout: s.ReadTimeout,
|
|
|
|
|
WriteTimeout: s.WriteTimeout,
|
2022-12-28 11:14:16 +00:00
|
|
|
IdleTimeout: func() time.Duration {
|
2025-09-09 19:06:44 -07:00
|
|
|
return s.IdleTimeout
|
2022-12-28 11:14:16 +00:00
|
|
|
},
|
|
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-27 06:34:03 -07:00
|
|
|
// Stop attempts to gracefully stop the server.
|
|
|
|
|
// It waits until the server is stopped and its connections are closed,
|
|
|
|
|
// up to a max timeout of a few seconds. If unsuccessful, an error is returned.
|
|
|
|
|
//
|
2017-02-10 19:50:31 +00:00
|
|
|
// This implements Caddy.Stopper interface.
|
2025-09-27 06:34:03 -07:00
|
|
|
func (s *Server) Stop() error {
|
2025-09-19 14:01:53 +03:00
|
|
|
s.stopOnce.Do(func() {
|
2025-09-27 06:34:03 -07:00
|
|
|
ctx, cancelCtx := context.WithTimeout(context.Background(), s.graceTimeout)
|
|
|
|
|
defer cancelCtx()
|
2016-08-19 17:14:17 -07:00
|
|
|
|
2025-09-27 06:34:03 -07:00
|
|
|
var wg sync.WaitGroup
|
2025-09-19 14:01:53 +03:00
|
|
|
s.m.Lock()
|
|
|
|
|
for _, s1 := range s.server {
|
|
|
|
|
// We might not have started and initialized the full set of servers
|
2025-09-27 06:34:03 -07:00
|
|
|
if s1 == nil {
|
|
|
|
|
continue
|
2025-09-19 14:01:53 +03:00
|
|
|
}
|
2025-09-27 06:34:03 -07:00
|
|
|
|
|
|
|
|
wg.Add(1)
|
|
|
|
|
go func() {
|
|
|
|
|
s1.ShutdownContext(ctx)
|
|
|
|
|
wg.Done()
|
|
|
|
|
}()
|
2017-02-10 19:50:31 +00:00
|
|
|
}
|
2025-09-19 14:01:53 +03:00
|
|
|
s.m.Unlock()
|
2025-09-27 06:34:03 -07:00
|
|
|
wg.Wait()
|
|
|
|
|
|
|
|
|
|
s.stopErr = ctx.Err()
|
2025-09-19 14:01:53 +03:00
|
|
|
})
|
2025-09-27 06:34:03 -07:00
|
|
|
return s.stopErr
|
2016-08-19 17:14:17 -07:00
|
|
|
}
|
|
|
|
|
|
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
|