| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | package dnsserver
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import (
 | 
					
						
							| 
									
										
										
										
											2016-09-17 21:24:39 +01:00
										 |  |  | 	"flag"
 | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | 	"fmt"
 | 
					
						
							|  |  |  | 	"net"
 | 
					
						
							| 
									
										
										
										
											2017-10-24 10:16:03 +01:00
										 |  |  | 	"strings"
 | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | 	"time"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-14 09:36:06 +01:00
										 |  |  | 	"github.com/coredns/coredns/plugin"
 | 
					
						
							| 
									
										
										
										
											2017-10-24 10:16:03 +01:00
										 |  |  | 	"github.com/coredns/coredns/plugin/pkg/dnsutil"
 | 
					
						
							| 
									
										
										
										
											2016-09-19 11:26:00 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | 	"github.com/mholt/caddy"
 | 
					
						
							|  |  |  | 	"github.com/mholt/caddy/caddyfile"
 | 
					
						
							|  |  |  | )
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const serverType = "dns"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-25 19:19:15 +01:00
										 |  |  | // Any flags defined here, need to be namespaced to the serverType other
 | 
					
						
							|  |  |  | // wise they potentially clash with other server types.
 | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | func init() {
 | 
					
						
							| 
									
										
										
										
											2016-09-25 19:19:15 +01:00
										 |  |  | 	flag.StringVar(&Port, serverType+".port", DefaultPort, "Default port")
 | 
					
						
							| 
									
										
										
										
											2016-09-17 21:24:39 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | 	caddy.RegisterServerType(serverType, caddy.ServerType{
 | 
					
						
							| 
									
										
										
										
											2016-08-25 07:23:02 +01:00
										 |  |  | 		Directives: func() []string { return directives },
 | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | 		DefaultInput: func() caddy.Input {
 | 
					
						
							|  |  |  | 			return caddy.CaddyfileInput{
 | 
					
						
							|  |  |  | 				Filepath:       "Corefile",
 | 
					
						
							| 
									
										
										
										
											2016-09-17 21:24:39 +01:00
										 |  |  | 				Contents:       []byte(".:" + Port + " {\nwhoami\n}\n"),
 | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | 				ServerTypeName: serverType,
 | 
					
						
							|  |  |  | 			}
 | 
					
						
							|  |  |  | 		},
 | 
					
						
							|  |  |  | 		NewContext: newContext,
 | 
					
						
							|  |  |  | 	})
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func newContext() caddy.Context {
 | 
					
						
							|  |  |  | 	return &dnsContext{keysToConfigs: make(map[string]*Config)}
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type dnsContext struct {
 | 
					
						
							|  |  |  | 	keysToConfigs map[string]*Config
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// configs is the master list of all site configs.
 | 
					
						
							|  |  |  | 	configs []*Config
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (h *dnsContext) saveConfig(key string, cfg *Config) {
 | 
					
						
							|  |  |  | 	h.configs = append(h.configs, cfg)
 | 
					
						
							|  |  |  | 	h.keysToConfigs[key] = cfg
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // InspectServerBlocks make sure that everything checks out before
 | 
					
						
							|  |  |  | // executing directives and otherwise prepares the directives to
 | 
					
						
							|  |  |  | // be parsed and executed.
 | 
					
						
							|  |  |  | func (h *dnsContext) InspectServerBlocks(sourceFile string, serverBlocks []caddyfile.ServerBlock) ([]caddyfile.ServerBlock, error) {
 | 
					
						
							|  |  |  | 	// Normalize and check all the zone names and check for duplicates
 | 
					
						
							|  |  |  | 	dups := map[string]string{}
 | 
					
						
							|  |  |  | 	for _, s := range serverBlocks {
 | 
					
						
							|  |  |  | 		for i, k := range s.Keys {
 | 
					
						
							|  |  |  | 			za, err := normalizeZone(k)
 | 
					
						
							|  |  |  | 			if err != nil {
 | 
					
						
							|  |  |  | 				return nil, err
 | 
					
						
							|  |  |  | 			}
 | 
					
						
							|  |  |  | 			s.Keys[i] = za.String()
 | 
					
						
							| 
									
										
										
										
											2017-03-13 20:24:37 +00:00
										 |  |  | 			if v, ok := dups[za.String()]; ok {
 | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | 				return nil, fmt.Errorf("cannot serve %s - zone already defined for %v", za, v)
 | 
					
						
							|  |  |  | 			}
 | 
					
						
							| 
									
										
										
										
											2017-03-13 20:24:37 +00:00
										 |  |  | 			dups[za.String()] = za.String()
 | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-24 10:16:03 +01:00
										 |  |  | 			// Save the config to our master list, and key it for lookups.
 | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | 			cfg := &Config{
 | 
					
						
							| 
									
										
										
										
											2017-03-13 20:24:37 +00:00
										 |  |  | 				Zone:      za.Zone,
 | 
					
						
							|  |  |  | 				Port:      za.Port,
 | 
					
						
							|  |  |  | 				Transport: za.Transport,
 | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | 			}
 | 
					
						
							| 
									
										
										
										
											2017-10-24 10:16:03 +01:00
										 |  |  | 			if za.IPNet == nil {
 | 
					
						
							|  |  |  | 				h.saveConfig(za.String(), cfg)
 | 
					
						
							|  |  |  | 				continue
 | 
					
						
							|  |  |  | 			}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			ones, bits := za.IPNet.Mask.Size()
 | 
					
						
							|  |  |  | 			if (bits-ones)%8 != 0 { // only do this for non-octet bounderies
 | 
					
						
							|  |  |  | 				cfg.FilterFunc = func(s string) bool {
 | 
					
						
							|  |  |  | 					// TODO(miek): strings.ToLower! Slow and allocates new string.
 | 
					
						
							|  |  |  | 					addr := dnsutil.ExtractAddressFromReverse(strings.ToLower(s))
 | 
					
						
							|  |  |  | 					if addr == "" {
 | 
					
						
							|  |  |  | 						return true
 | 
					
						
							|  |  |  | 					}
 | 
					
						
							|  |  |  | 					return za.IPNet.Contains(net.ParseIP(addr))
 | 
					
						
							|  |  |  | 				}
 | 
					
						
							|  |  |  | 			}
 | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | 			h.saveConfig(za.String(), cfg)
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 	return serverBlocks, nil
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // MakeServers uses the newly-created siteConfigs to create and return a list of server instances.
 | 
					
						
							|  |  |  | func (h *dnsContext) MakeServers() ([]caddy.Server, error) {
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// we must map (group) each config to a bind address
 | 
					
						
							|  |  |  | 	groups, err := groupConfigsByListenAddr(h.configs)
 | 
					
						
							|  |  |  | 	if err != nil {
 | 
					
						
							|  |  |  | 		return nil, err
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 	// then we create a server for each group
 | 
					
						
							|  |  |  | 	var servers []caddy.Server
 | 
					
						
							|  |  |  | 	for addr, group := range groups {
 | 
					
						
							| 
									
										
										
										
											2017-03-13 20:24:37 +00:00
										 |  |  | 		// switch on addr
 | 
					
						
							|  |  |  | 		switch Transport(addr) {
 | 
					
						
							|  |  |  | 		case TransportDNS:
 | 
					
						
							|  |  |  | 			s, err := NewServer(addr, group)
 | 
					
						
							|  |  |  | 			if err != nil {
 | 
					
						
							|  |  |  | 				return nil, err
 | 
					
						
							|  |  |  | 			}
 | 
					
						
							|  |  |  | 			servers = append(servers, s)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		case TransportTLS:
 | 
					
						
							|  |  |  | 			s, err := NewServerTLS(addr, group)
 | 
					
						
							|  |  |  | 			if err != nil {
 | 
					
						
							|  |  |  | 				return nil, err
 | 
					
						
							|  |  |  | 			}
 | 
					
						
							|  |  |  | 			servers = append(servers, s)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		case TransportGRPC:
 | 
					
						
							|  |  |  | 			s, err := NewServergRPC(addr, group)
 | 
					
						
							|  |  |  | 			if err != nil {
 | 
					
						
							|  |  |  | 				return nil, err
 | 
					
						
							|  |  |  | 			}
 | 
					
						
							|  |  |  | 			servers = append(servers, s)
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | 		}
 | 
					
						
							| 
									
										
										
										
											2017-03-13 20:24:37 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return servers, nil
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-14 09:36:06 +01:00
										 |  |  | // AddPlugin adds a plugin to a site's plugin stack.
 | 
					
						
							|  |  |  | func (c *Config) AddPlugin(m plugin.Plugin) {
 | 
					
						
							|  |  |  | 	c.Plugin = append(c.Plugin, m)
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-22 14:21:42 +01:00
										 |  |  | // registerHandler adds a handler to a site's handler registration. Handlers
 | 
					
						
							| 
									
										
										
										
											2017-09-14 09:36:06 +01:00
										 |  |  | //  use this to announce that they exist to other plugin.
 | 
					
						
							|  |  |  | func (c *Config) registerHandler(h plugin.Handler) {
 | 
					
						
							| 
									
										
										
										
											2017-08-25 08:55:53 +01:00
										 |  |  | 	if c.registry == nil {
 | 
					
						
							| 
									
										
										
										
											2017-09-14 09:36:06 +01:00
										 |  |  | 		c.registry = make(map[string]plugin.Handler)
 | 
					
						
							| 
									
										
										
										
											2017-08-10 21:31:36 +01:00
										 |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Just overwrite...
 | 
					
						
							| 
									
										
										
										
											2017-08-25 08:55:53 +01:00
										 |  |  | 	c.registry[h.Name()] = h
 | 
					
						
							| 
									
										
										
										
											2017-08-10 21:31:36 +01:00
										 |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-14 09:36:06 +01:00
										 |  |  | // Handler returns the plugin handler that has been added to the config under its name.
 | 
					
						
							|  |  |  | // This is useful to inspect if a certain plugin is active in this server.
 | 
					
						
							|  |  |  | // Note that this is order dependent and the order is defined in directives.go, i.e. if your plugin
 | 
					
						
							|  |  |  | // comes before the plugin you are checking; it will not be there (yet).
 | 
					
						
							|  |  |  | func (c *Config) Handler(name string) plugin.Handler {
 | 
					
						
							| 
									
										
										
										
											2017-08-25 08:55:53 +01:00
										 |  |  | 	if c.registry == nil {
 | 
					
						
							| 
									
										
										
										
											2017-08-10 21:31:36 +01:00
										 |  |  | 		return nil
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							| 
									
										
										
										
											2017-08-25 08:55:53 +01:00
										 |  |  | 	if h, ok := c.registry[name]; ok {
 | 
					
						
							| 
									
										
										
										
											2017-08-10 21:31:36 +01:00
										 |  |  | 		return h
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 	return nil
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | // groupSiteConfigsByListenAddr groups site configs by their listen
 | 
					
						
							|  |  |  | // (bind) address, so sites that use the same listener can be served
 | 
					
						
							|  |  |  | // on the same server instance. The return value maps the listen
 | 
					
						
							|  |  |  | // address (what you pass into net.Listen) to the list of site configs.
 | 
					
						
							|  |  |  | // This function does NOT vet the configs to ensure they are compatible.
 | 
					
						
							|  |  |  | func groupConfigsByListenAddr(configs []*Config) (map[string][]*Config, error) {
 | 
					
						
							|  |  |  | 	groups := make(map[string][]*Config)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for _, conf := range configs {
 | 
					
						
							|  |  |  | 		addr, err := net.ResolveTCPAddr("tcp", net.JoinHostPort(conf.ListenHost, conf.Port))
 | 
					
						
							|  |  |  | 		if err != nil {
 | 
					
						
							|  |  |  | 			return nil, err
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							| 
									
										
										
										
											2017-03-13 20:24:37 +00:00
										 |  |  | 		addrstr := conf.Transport + "://" + addr.String()
 | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | 		groups[addrstr] = append(groups[addrstr], conf)
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return groups, nil
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const (
 | 
					
						
							|  |  |  | 	// DefaultPort is the default port.
 | 
					
						
							| 
									
										
										
										
											2016-10-07 10:14:23 +00:00
										 |  |  | 	DefaultPort = "53"
 | 
					
						
							| 
									
										
										
										
											2017-03-13 20:24:37 +00:00
										 |  |  | 	// TLSPort is the default port for DNS-over-TLS.
 | 
					
						
							|  |  |  | 	TLSPort = "853"
 | 
					
						
							|  |  |  | 	// GRPCPort is the default port for DNS-over-gRPC.
 | 
					
						
							|  |  |  | 	GRPCPort = "443"
 | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | )
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // These "soft defaults" are configurable by
 | 
					
						
							|  |  |  | // command line flags, etc.
 | 
					
						
							|  |  |  | var (
 | 
					
						
							| 
									
										
										
										
											2016-10-07 10:14:23 +00:00
										 |  |  | 	// Port is the port we listen on by default.
 | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | 	Port = DefaultPort
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// GracefulTimeout is the maximum duration of a graceful shutdown.
 | 
					
						
							|  |  |  | 	GracefulTimeout time.Duration
 | 
					
						
							|  |  |  | )
 | 
					
						
							| 
									
										
										
										
											2017-02-10 19:50:31 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | var _ caddy.GracefulServer = new(Server)
 |