| 
									
										
										
										
											2016-03-18 20:57:35 +00:00
										 |  |  | package core
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import (
 | 
					
						
							|  |  |  | 	"bytes"
 | 
					
						
							|  |  |  | 	"fmt"
 | 
					
						
							|  |  |  | 	"io"
 | 
					
						
							|  |  |  | 	"log"
 | 
					
						
							|  |  |  | 	"net"
 | 
					
						
							|  |  |  | 	"sync"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/miekg/coredns/core/parse"
 | 
					
						
							|  |  |  | 	"github.com/miekg/coredns/core/setup"
 | 
					
						
							|  |  |  | 	"github.com/miekg/coredns/server"
 | 
					
						
							|  |  |  | )
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const (
 | 
					
						
							|  |  |  | 	// DefaultConfigFile is the name of the configuration file that is loaded
 | 
					
						
							|  |  |  | 	// by default if no other file is specified.
 | 
					
						
							|  |  |  | 	DefaultConfigFile = "Corefile"
 | 
					
						
							|  |  |  | )
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func loadConfigsUpToIncludingTLS(filename string, input io.Reader) ([]server.Config, []parse.ServerBlock, int, error) {
 | 
					
						
							|  |  |  | 	var configs []server.Config
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Each server block represents similar hosts/addresses, since they
 | 
					
						
							|  |  |  | 	// were grouped together in the Caddyfile.
 | 
					
						
							|  |  |  | 	serverBlocks, err := parse.ServerBlocks(filename, input, true)
 | 
					
						
							|  |  |  | 	if err != nil {
 | 
					
						
							|  |  |  | 		return nil, nil, 0, err
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 	if len(serverBlocks) == 0 {
 | 
					
						
							|  |  |  | 		newInput := DefaultInput()
 | 
					
						
							|  |  |  | 		serverBlocks, err = parse.ServerBlocks(newInput.Path(), bytes.NewReader(newInput.Body()), true)
 | 
					
						
							|  |  |  | 		if err != nil {
 | 
					
						
							|  |  |  | 			return nil, nil, 0, err
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var lastDirectiveIndex int // we set up directives in two parts; this stores where we left off
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Iterate each server block and make a config for each one,
 | 
					
						
							|  |  |  | 	// executing the directives that were parsed in order up to the tls
 | 
					
						
							|  |  |  | 	// directive; this is because we must activate Let's Encrypt.
 | 
					
						
							|  |  |  | 	for i, sb := range serverBlocks {
 | 
					
						
							|  |  |  | 		onces := makeOnces()
 | 
					
						
							|  |  |  | 		storages := makeStorages()
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		for j, addr := range sb.Addresses {
 | 
					
						
							|  |  |  | 			config := server.Config{
 | 
					
						
							|  |  |  | 				Host:       addr.Host,
 | 
					
						
							|  |  |  | 				Port:       addr.Port,
 | 
					
						
							|  |  |  | 				Root:       Root,
 | 
					
						
							|  |  |  | 				ConfigFile: filename,
 | 
					
						
							|  |  |  | 				AppName:    AppName,
 | 
					
						
							|  |  |  | 				AppVersion: AppVersion,
 | 
					
						
							|  |  |  | 			}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// It is crucial that directives are executed in the proper order.
 | 
					
						
							|  |  |  | 			for k, dir := range directiveOrder {
 | 
					
						
							|  |  |  | 				// Execute directive if it is in the server block
 | 
					
						
							|  |  |  | 				if tokens, ok := sb.Tokens[dir.name]; ok {
 | 
					
						
							|  |  |  | 					// Each setup function gets a controller, from which setup functions
 | 
					
						
							|  |  |  | 					// get access to the config, tokens, and other state information useful
 | 
					
						
							|  |  |  | 					// to set up its own host only.
 | 
					
						
							|  |  |  | 					controller := &setup.Controller{
 | 
					
						
							|  |  |  | 						Config:    &config,
 | 
					
						
							|  |  |  | 						Dispenser: parse.NewDispenserTokens(filename, tokens),
 | 
					
						
							|  |  |  | 						OncePerServerBlock: func(f func() error) error {
 | 
					
						
							|  |  |  | 							var err error
 | 
					
						
							|  |  |  | 							onces[dir.name].Do(func() {
 | 
					
						
							|  |  |  | 								err = f()
 | 
					
						
							|  |  |  | 							})
 | 
					
						
							|  |  |  | 							return err
 | 
					
						
							|  |  |  | 						},
 | 
					
						
							|  |  |  | 						ServerBlockIndex:     i,
 | 
					
						
							|  |  |  | 						ServerBlockHostIndex: j,
 | 
					
						
							|  |  |  | 						ServerBlockHosts:     sb.HostList(),
 | 
					
						
							|  |  |  | 						ServerBlockStorage:   storages[dir.name],
 | 
					
						
							|  |  |  | 					}
 | 
					
						
							|  |  |  | 					// execute setup function and append middleware handler, if any
 | 
					
						
							|  |  |  | 					midware, err := dir.setup(controller)
 | 
					
						
							|  |  |  | 					if err != nil {
 | 
					
						
							|  |  |  | 						return nil, nil, lastDirectiveIndex, err
 | 
					
						
							|  |  |  | 					}
 | 
					
						
							|  |  |  | 					if midware != nil {
 | 
					
						
							|  |  |  | 						config.Middleware = append(config.Middleware, midware)
 | 
					
						
							|  |  |  | 					}
 | 
					
						
							|  |  |  | 					storages[dir.name] = controller.ServerBlockStorage // persist for this server block
 | 
					
						
							|  |  |  | 				}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// Stop after TLS setup, since we need to activate Let's Encrypt before continuing;
 | 
					
						
							|  |  |  | 				// it makes some changes to the configs that middlewares might want to know about.
 | 
					
						
							|  |  |  | 				if dir.name == "tls" {
 | 
					
						
							|  |  |  | 					lastDirectiveIndex = k
 | 
					
						
							|  |  |  | 					break
 | 
					
						
							|  |  |  | 				}
 | 
					
						
							|  |  |  | 			}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			configs = append(configs, config)
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 	return configs, serverBlocks, lastDirectiveIndex, nil
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // loadConfigs reads input (named filename) and parses it, returning the
 | 
					
						
							|  |  |  | // server configurations in the order they appeared in the input. As part
 | 
					
						
							|  |  |  | // of this, it activates Let's Encrypt for the configs that are produced.
 | 
					
						
							|  |  |  | // Thus, the returned configs are already optimally configured for HTTPS.
 | 
					
						
							|  |  |  | func loadConfigs(filename string, input io.Reader) ([]server.Config, error) {
 | 
					
						
							|  |  |  | 	configs, serverBlocks, lastDirectiveIndex, err := loadConfigsUpToIncludingTLS(filename, input)
 | 
					
						
							|  |  |  | 	if err != nil {
 | 
					
						
							|  |  |  | 		return nil, err
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Now we have all the configs, but they have only been set up to the
 | 
					
						
							|  |  |  | 	// point of tls. We need to activate Let's Encrypt before setting up
 | 
					
						
							|  |  |  | 	// the rest of the middlewares so they have correct information regarding
 | 
					
						
							|  |  |  | 	// TLS configuration, if necessary. (this only appends, so our iterations
 | 
					
						
							|  |  |  | 	// over server blocks below shouldn't be affected)
 | 
					
						
							|  |  |  | 	if !IsRestart() && !Quiet {
 | 
					
						
							|  |  |  | 		fmt.Println("Activating privacy features...")
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 	/* TODO(miek): stopped for now
 | 
					
						
							|  |  |  | 	configs, err = https.Activate(configs)
 | 
					
						
							|  |  |  | 	if err != nil {
 | 
					
						
							|  |  |  | 		return nil, err
 | 
					
						
							|  |  |  | 	} else if !IsRestart() && !Quiet {
 | 
					
						
							|  |  |  | 		fmt.Println(" done.")
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 	*/
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Finish setting up the rest of the directives, now that TLS is
 | 
					
						
							|  |  |  | 	// optimally configured. These loops are similar to above except
 | 
					
						
							|  |  |  | 	// we don't iterate all the directives from the beginning and we
 | 
					
						
							|  |  |  | 	// don't create new configs.
 | 
					
						
							|  |  |  | 	configIndex := -1
 | 
					
						
							|  |  |  | 	for i, sb := range serverBlocks {
 | 
					
						
							|  |  |  | 		onces := makeOnces()
 | 
					
						
							|  |  |  | 		storages := makeStorages()
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		for j := range sb.Addresses {
 | 
					
						
							|  |  |  | 			configIndex++
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			for k := lastDirectiveIndex + 1; k < len(directiveOrder); k++ {
 | 
					
						
							|  |  |  | 				dir := directiveOrder[k]
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				if tokens, ok := sb.Tokens[dir.name]; ok {
 | 
					
						
							|  |  |  | 					controller := &setup.Controller{
 | 
					
						
							|  |  |  | 						Config:    &configs[configIndex],
 | 
					
						
							|  |  |  | 						Dispenser: parse.NewDispenserTokens(filename, tokens),
 | 
					
						
							|  |  |  | 						OncePerServerBlock: func(f func() error) error {
 | 
					
						
							|  |  |  | 							var err error
 | 
					
						
							|  |  |  | 							onces[dir.name].Do(func() {
 | 
					
						
							|  |  |  | 								err = f()
 | 
					
						
							|  |  |  | 							})
 | 
					
						
							|  |  |  | 							return err
 | 
					
						
							|  |  |  | 						},
 | 
					
						
							|  |  |  | 						ServerBlockIndex:     i,
 | 
					
						
							|  |  |  | 						ServerBlockHostIndex: j,
 | 
					
						
							|  |  |  | 						ServerBlockHosts:     sb.HostList(),
 | 
					
						
							|  |  |  | 						ServerBlockStorage:   storages[dir.name],
 | 
					
						
							|  |  |  | 					}
 | 
					
						
							|  |  |  | 					midware, err := dir.setup(controller)
 | 
					
						
							|  |  |  | 					if err != nil {
 | 
					
						
							|  |  |  | 						return nil, err
 | 
					
						
							|  |  |  | 					}
 | 
					
						
							|  |  |  | 					if midware != nil {
 | 
					
						
							|  |  |  | 						configs[configIndex].Middleware = append(configs[configIndex].Middleware, midware)
 | 
					
						
							|  |  |  | 					}
 | 
					
						
							|  |  |  | 					storages[dir.name] = controller.ServerBlockStorage // persist for this server block
 | 
					
						
							|  |  |  | 				}
 | 
					
						
							|  |  |  | 			}
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return configs, nil
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // makeOnces makes a map of directive name to sync.Once
 | 
					
						
							|  |  |  | // instance. This is intended to be called once per server
 | 
					
						
							|  |  |  | // block when setting up configs so that Setup functions
 | 
					
						
							|  |  |  | // for each directive can perform a task just once per
 | 
					
						
							|  |  |  | // server block, even if there are multiple hosts on the block.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // We need one Once per directive, otherwise the first
 | 
					
						
							|  |  |  | // directive to use it would exclude other directives from
 | 
					
						
							|  |  |  | // using it at all, which would be a bug.
 | 
					
						
							|  |  |  | func makeOnces() map[string]*sync.Once {
 | 
					
						
							|  |  |  | 	onces := make(map[string]*sync.Once)
 | 
					
						
							|  |  |  | 	for _, dir := range directiveOrder {
 | 
					
						
							|  |  |  | 		onces[dir.name] = new(sync.Once)
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 	return onces
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // makeStorages makes a map of directive name to interface{}
 | 
					
						
							|  |  |  | // so that directives' setup functions can persist state
 | 
					
						
							|  |  |  | // between different hosts on the same server block during the
 | 
					
						
							|  |  |  | // setup phase.
 | 
					
						
							|  |  |  | func makeStorages() map[string]interface{} {
 | 
					
						
							|  |  |  | 	storages := make(map[string]interface{})
 | 
					
						
							|  |  |  | 	for _, dir := range directiveOrder {
 | 
					
						
							|  |  |  | 		storages[dir.name] = nil
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 	return storages
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // arrangeBindings groups configurations by their bind address. For example,
 | 
					
						
							|  |  |  | // a server that should listen on localhost and another on 127.0.0.1 will
 | 
					
						
							|  |  |  | // be grouped into the same address: 127.0.0.1. It will return an error
 | 
					
						
							|  |  |  | // if an address is malformed or a TLS listener is configured on the
 | 
					
						
							|  |  |  | // same address as a plaintext HTTP listener. The return value is a map of
 | 
					
						
							|  |  |  | // bind address to list of configs that would become VirtualHosts on that
 | 
					
						
							|  |  |  | // server. Use the keys of the returned map to create listeners, and use
 | 
					
						
							|  |  |  | // the associated values to set up the virtualhosts.
 | 
					
						
							|  |  |  | func arrangeBindings(allConfigs []server.Config) (bindingGroup, error) {
 | 
					
						
							|  |  |  | 	var groupings bindingGroup
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Group configs by bind address
 | 
					
						
							|  |  |  | 	for _, conf := range allConfigs {
 | 
					
						
							|  |  |  | 		// use default port if none is specified
 | 
					
						
							|  |  |  | 		if conf.Port == "" {
 | 
					
						
							|  |  |  | 			conf.Port = Port
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		bindAddr, warnErr, fatalErr := resolveAddr(conf)
 | 
					
						
							|  |  |  | 		if fatalErr != nil {
 | 
					
						
							|  |  |  | 			return groupings, fatalErr
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							|  |  |  | 		if warnErr != nil {
 | 
					
						
							|  |  |  | 			log.Printf("[WARNING] Resolving bind address for %s: %v", conf.Address(), warnErr)
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Make sure to compare the string representation of the address,
 | 
					
						
							|  |  |  | 		// not the pointer, since a new *TCPAddr is created each time.
 | 
					
						
							|  |  |  | 		var existing bool
 | 
					
						
							|  |  |  | 		for i := 0; i < len(groupings); i++ {
 | 
					
						
							|  |  |  | 			if groupings[i].BindAddr.String() == bindAddr.String() {
 | 
					
						
							|  |  |  | 				groupings[i].Configs = append(groupings[i].Configs, conf)
 | 
					
						
							|  |  |  | 				existing = true
 | 
					
						
							|  |  |  | 				break
 | 
					
						
							|  |  |  | 			}
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							|  |  |  | 		if !existing {
 | 
					
						
							|  |  |  | 			groupings = append(groupings, bindingMapping{
 | 
					
						
							|  |  |  | 				BindAddr: bindAddr,
 | 
					
						
							|  |  |  | 				Configs:  []server.Config{conf},
 | 
					
						
							|  |  |  | 			})
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Don't allow HTTP and HTTPS to be served on the same address
 | 
					
						
							|  |  |  | 	for _, group := range groupings {
 | 
					
						
							|  |  |  | 		isTLS := group.Configs[0].TLS.Enabled
 | 
					
						
							|  |  |  | 		for _, config := range group.Configs {
 | 
					
						
							|  |  |  | 			if config.TLS.Enabled != isTLS {
 | 
					
						
							|  |  |  | 				thisConfigProto, otherConfigProto := "HTTP", "HTTP"
 | 
					
						
							|  |  |  | 				if config.TLS.Enabled {
 | 
					
						
							|  |  |  | 					thisConfigProto = "HTTPS"
 | 
					
						
							|  |  |  | 				}
 | 
					
						
							|  |  |  | 				if group.Configs[0].TLS.Enabled {
 | 
					
						
							|  |  |  | 					otherConfigProto = "HTTPS"
 | 
					
						
							|  |  |  | 				}
 | 
					
						
							|  |  |  | 				return groupings, fmt.Errorf("configuration error: Cannot multiplex %s (%s) and %s (%s) on same address",
 | 
					
						
							|  |  |  | 					group.Configs[0].Address(), otherConfigProto, config.Address(), thisConfigProto)
 | 
					
						
							|  |  |  | 			}
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return groupings, nil
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // resolveAddr determines the address (host and port) that a config will
 | 
					
						
							|  |  |  | // bind to. The returned address, resolvAddr, should be used to bind the
 | 
					
						
							|  |  |  | // listener or group the config with other configs using the same address.
 | 
					
						
							|  |  |  | // The first error, if not nil, is just a warning and should be reported
 | 
					
						
							|  |  |  | // but execution may continue. The second error, if not nil, is a real
 | 
					
						
							|  |  |  | // problem and the server should not be started.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // This function does not handle edge cases like port "http" or "https" if
 | 
					
						
							|  |  |  | // they are not known to the system. It does, however, serve on the wildcard
 | 
					
						
							|  |  |  | // host if resolving the address of the specific hostname fails.
 | 
					
						
							|  |  |  | func resolveAddr(conf server.Config) (resolvAddr *net.TCPAddr, warnErr, fatalErr error) {
 | 
					
						
							|  |  |  | 	resolvAddr, warnErr = net.ResolveTCPAddr("tcp", net.JoinHostPort(conf.BindHost, conf.Port))
 | 
					
						
							|  |  |  | 	if warnErr != nil {
 | 
					
						
							|  |  |  | 		// the hostname probably couldn't be resolved, just bind to wildcard then
 | 
					
						
							|  |  |  | 		resolvAddr, fatalErr = net.ResolveTCPAddr("tcp", net.JoinHostPort("", conf.Port))
 | 
					
						
							|  |  |  | 		if fatalErr != nil {
 | 
					
						
							|  |  |  | 			return
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // validDirective returns true if d is a valid
 | 
					
						
							|  |  |  | // directive; false otherwise.
 | 
					
						
							|  |  |  | func validDirective(d string) bool {
 | 
					
						
							|  |  |  | 	for _, dir := range directiveOrder {
 | 
					
						
							|  |  |  | 		if dir.name == d {
 | 
					
						
							|  |  |  | 			return true
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 	return false
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // DefaultInput returns the default Caddyfile input
 | 
					
						
							|  |  |  | // to use when it is otherwise empty or missing.
 | 
					
						
							| 
									
										
										
										
											2016-03-19 14:46:32 +00:00
										 |  |  | // It uses the default host and port and root.
 | 
					
						
							| 
									
										
										
										
											2016-03-18 20:57:35 +00:00
										 |  |  | func DefaultInput() CaddyfileInput {
 | 
					
						
							|  |  |  | 	port := Port
 | 
					
						
							|  |  |  | 	return CaddyfileInput{
 | 
					
						
							|  |  |  | 		Contents: []byte(fmt.Sprintf("%s:%s\nroot %s", Host, port, Root)),
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // These defaults are configurable through the command line
 | 
					
						
							|  |  |  | var (
 | 
					
						
							|  |  |  | 	// Root is the site root
 | 
					
						
							|  |  |  | 	Root = DefaultRoot
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Host is the site host
 | 
					
						
							|  |  |  | 	Host = DefaultHost
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Port is the site port
 | 
					
						
							|  |  |  | 	Port = DefaultPort
 | 
					
						
							|  |  |  | )
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // bindingMapping maps a network address to configurations
 | 
					
						
							|  |  |  | // that will bind to it. The order of the configs is important.
 | 
					
						
							|  |  |  | type bindingMapping struct {
 | 
					
						
							|  |  |  | 	BindAddr *net.TCPAddr
 | 
					
						
							|  |  |  | 	Configs  []server.Config
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // bindingGroup maps network addresses to their configurations.
 | 
					
						
							|  |  |  | // Preserving the order of the groupings is important
 | 
					
						
							|  |  |  | // (related to graceful shutdown and restart)
 | 
					
						
							|  |  |  | // so this is a slice, not a literal map.
 | 
					
						
							|  |  |  | type bindingGroup []bindingMapping
 |