| 
									
										
										
										
											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 |