2016-03-18 20:57:35 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								// Package server implements a configurable, general-purpose web server. 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// It relies on configurations obtained from the adjacent config package 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// and can execute middleware as defined by the adjacent middleware package. 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								package   server 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								import   ( 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 "crypto/tls" 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 "crypto/x509" 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 "fmt" 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 "io/ioutil" 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 "log" 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 "net" 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 "os" 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 "runtime" 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 "sync" 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 "time" 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2016-04-09 11:13:04 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									 "github.com/miekg/coredns/middleware" 
  
						 
					
						
							
								
									
										
										
										
											2016-04-04 15:45:17 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									 "github.com/miekg/coredns/middleware/chaos" 
  
						 
					
						
							
								
									
										
										
										
											2016-04-09 16:17:53 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									 "github.com/miekg/coredns/middleware/metrics" 
  
						 
					
						
							
								
									
										
										
										
											2016-04-06 22:29:33 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2016-03-18 20:57:35 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									 "github.com/miekg/dns" 
  
						 
					
						
							
								
									
										
										
										
											2016-04-06 22:29:33 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									 "golang.org/x/net/context" 
  
						 
					
						
							
								
									
										
										
										
											2016-03-18 20:57:35 +00: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   { 
  
						 
					
						
							
								
									
										
										
										
											2016-04-10 18:50:11 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									 Addr     string   // Address we listen on 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 mux      * dns . ServeMux 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 server   [ 2 ] * dns . Server   // by convention 0 is tcp and 1 is udp 
  
						 
					
						
							
								
									
										
										
										
											2016-04-28 21:15:45 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 tcp          net . Listener 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 udp          net . PacketConn 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 listenerMu   sync . Mutex   // protects listener and packetconn 
  
						 
					
						
							
								
									
										
										
										
											2016-04-10 18:50:11 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2016-03-18 20:57:35 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									 tls           bool   // whether this server is serving all HTTPS hosts or not 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 TLSConfig     * tls . Config 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 OnDemandTLS   bool               // whether this server supports on-demand TLS (load certs at handshake-time) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 zones         map [ string ] zone    // zones keyed by their address 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 dnsWg         sync . WaitGroup     // used to wait on outstanding connections 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 startChan     chan   struct { }      // used to block until server is finished starting 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 connTimeout   time . Duration      // the maximum duration of a graceful shutdown 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 ReqCallback   OptionalCallback   // if non-nil, is executed at the beginning of every request 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 SNICallback   func ( clientHello   * tls . ClientHelloInfo )   ( * tls . Certificate ,   error ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								} 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// OptionalCallback is a function that may or may not handle a request. 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// It returns whether or not it handled the request. If it handled the 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// request, it is presumed that no further request handling should occur. 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								type   OptionalCallback   func ( dns . ResponseWriter ,   * dns . Msg )   bool 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// New creates a new Server which will bind to addr and serve 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// the sites/hosts configured in configs. Its listener will 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// gracefully close when the server is stopped which will take 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// no longer than gracefulTimeout. 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								//
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// This function does not start serving. 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								//
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// Do not re-use a server (start, stop, then start again). We 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// could probably add more locking to make this possible, but 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// as it stands, you should dispose of a server after stopping it. 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// The behavior of serving with a spent server is undefined. 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func   New ( addr   string ,   configs   [ ] Config ,   gracefulTimeout   time . Duration )   ( * Server ,   error )   { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 var   useTLS ,   useOnDemandTLS   bool 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 if   len ( configs )   >   0   { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 useTLS   =   configs [ 0 ] . TLS . Enabled 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 useOnDemandTLS   =   configs [ 0 ] . TLS . OnDemand 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 s   :=   & Server { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 Addr :        addr , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 TLSConfig :   new ( tls . Config ) , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 // TODO: Make these values configurable? 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 // ReadTimeout:    2 * time.Minute, 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 // WriteTimeout:   2 * time.Minute, 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 // MaxHeaderBytes: 1 << 16, 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 tls :           useTLS , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 OnDemandTLS :   useOnDemandTLS , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 zones :         make ( map [ string ] zone ) , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 startChan :     make ( chan   struct { } ) , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 connTimeout :   gracefulTimeout , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 mux   :=   dns . NewServeMux ( ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 mux . Handle ( "." ,   s )   // wildcard handler, everything will go through here 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 s . mux   =   mux 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 // 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 ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 // Set up each zone 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 for   _ ,   conf   :=   range   configs   { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 if   _ ,   exists   :=   s . zones [ conf . Host ] ;   exists   { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											 return   nil ,   fmt . Errorf ( "cannot serve %s - host already defined for address %s" ,   conf . Address ( ) ,   s . Addr ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 z   :=   zone { config :   conf } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 // Build middleware stack 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 err   :=   z . buildStack ( ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 if   err   !=   nil   { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											 return   nil ,   err 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 s . zones [ conf . Host ]   =   z 
  
						 
					
						
							
								
									
										
										
										
											2016-04-04 15:45:17 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 // A bit of a hack. Loop through the middlewares of this zone and check if 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 // they have enabled the chaos middleware. If so add the special chaos zones. 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 Middleware : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 for   _ ,   mid   :=   range   z . config . Middleware   { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											 fn   :=   mid ( nil ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											 if   _ ,   ok   :=   fn . ( chaos . Chaos ) ;   ok   { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												 for   _ ,   ch   :=   range   [ ] string { "authors.bind." ,   "version.bind." ,   "version.server." ,   "hostname.bind." ,   "id.server." }   { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													 s . zones [ ch ]   =   z 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												 } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												 break   Middleware 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											 } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 } 
  
						 
					
						
							
								
									
										
										
										
											2016-03-18 20:57:35 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									 } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 return   s ,   nil 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								} 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2016-04-10 18:50:11 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// LocalAddr return the addresses where the server is bound to. The TCP listener 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// address is the first returned, the UDP conn address the second. 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func   ( s   * Server )   LocalAddr ( )   ( net . Addr ,   net . Addr )   { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 s . listenerMu . Lock ( ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 tcp   :=   s . tcp . Addr ( ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 udp   :=   s . udp . LocalAddr ( ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 s . listenerMu . Unlock ( ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 return   tcp ,   udp 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								} 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2016-04-28 21:15:45 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// Serve starts the server with an existing listener. It blocks until the server stops. 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func   ( s   * Server )   Serve ( ln   net . Listener ,   pc   net . PacketConn )   error   { 
  
						 
					
						
							
								
									
										
										
										
											2016-03-18 20:57:35 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									 err   :=   s . setup ( ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 if   err   !=   nil   { 
  
						 
					
						
							
								
									
										
										
										
											2016-04-28 21:15:45 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										 close ( s . startChan )   // MUST defer so error is properly reported, same with all cases in this file 
  
						 
					
						
							
								
									
										
										
										
											2016-03-18 20:57:35 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										 return   err 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 } 
  
						 
					
						
							
								
									
										
										
										
											2016-04-28 21:15:45 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									 s . listenerMu . Lock ( ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 s . server [ 0 ]   =   & dns . Server { Listener :   ln ,   Net :   "tcp" ,   Handler :   s . mux } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 s . tcp   =   ln 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 s . server [ 1 ]   =   & dns . Server { PacketConn :   pc ,   Net :   "udp" ,   Handler :   s . mux } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 s . udp   =   pc 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 s . listenerMu . Unlock ( ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 go   func ( )   { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 s . server [ 0 ] . ActivateAndServe ( ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 } ( ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 close ( s . startChan ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 return   s . server [ 1 ] . ActivateAndServe ( ) 
  
						 
					
						
							
								
									
										
										
										
											2016-03-18 20:57:35 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								} 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// ListenAndServe starts the server with a new listener. It blocks until the server stops. 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func   ( s   * Server )   ListenAndServe ( )   error   { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 err   :=   s . setup ( ) 
  
						 
					
						
							
								
									
										
										
										
											2016-04-28 21:15:45 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									 // defer close(s.startChan) // Don't understand why defer wouldn't actually work in this method (prolly cause the last ActivateAndServe does not actually return? 
  
						 
					
						
							
								
									
										
										
										
											2016-03-18 20:57:35 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									 if   err   !=   nil   { 
  
						 
					
						
							
								
									
										
										
										
											2016-04-14 19:57:39 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										 close ( s . startChan ) 
  
						 
					
						
							
								
									
										
										
										
											2016-03-18 20:57:35 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										 return   err 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2016-04-10 18:50:11 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									 l ,   err   :=   net . Listen ( "tcp" ,   s . Addr ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 if   err   !=   nil   { 
  
						 
					
						
							
								
									
										
										
										
											2016-04-14 19:57:39 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										 close ( s . startChan ) 
  
						 
					
						
							
								
									
										
										
										
											2016-04-10 18:50:11 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										 return   err 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 pc ,   err   :=   net . ListenPacket ( "udp" ,   s . Addr ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 if   err   !=   nil   { 
  
						 
					
						
							
								
									
										
										
										
											2016-04-14 19:57:39 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										 close ( s . startChan ) 
  
						 
					
						
							
								
									
										
										
										
											2016-04-10 18:50:11 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										 return   err 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 s . listenerMu . Lock ( ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 s . server [ 0 ]   =   & dns . Server { Listener :   l ,   Net :   "tcp" ,   Handler :   s . mux } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 s . tcp   =   l 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 s . server [ 1 ]   =   & dns . Server { PacketConn :   pc ,   Net :   "udp" ,   Handler :   s . mux } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 s . udp   =   pc 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 s . listenerMu . Unlock ( ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2016-03-18 20:57:35 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									 go   func ( )   { 
  
						 
					
						
							
								
									
										
										
										
											2016-04-10 18:50:11 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										 s . server [ 0 ] . ActivateAndServe ( ) 
  
						 
					
						
							
								
									
										
										
										
											2016-03-18 20:57:35 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									 } ( ) 
  
						 
					
						
							
								
									
										
										
										
											2016-04-14 19:57:39 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									 close ( s . startChan ) 
  
						 
					
						
							
								
									
										
										
										
											2016-04-10 18:50:11 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									 return   s . server [ 1 ] . ActivateAndServe ( ) 
  
						 
					
						
							
								
									
										
										
										
											2016-03-18 20:57:35 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								} 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// setup prepares the server s to begin listening; it should be 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// called just before the listener announces itself on the network 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// and should only be called when the server is just starting up. 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func   ( s   * Server )   setup ( )   error   { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 // Execute startup functions now 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 for   _ ,   z   :=   range   s . zones   { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 for   _ ,   startupFunc   :=   range   z . config . Startup   { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											 err   :=   startupFunc ( ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											 if   err   !=   nil   { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												 return   err 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											 } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 return   nil 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								} 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								/ * 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								TODO ( miek ) :   no   such   thing   in   the   glorious   Go   DNS . 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// serveTLS serves TLS with SNI and client auth support if s has them enabled. It 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// blocks until s quits. 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func   serveTLS ( s   * Server ,   ln   net . Listener ,   tlsConfigs   [ ] TLSConfig )   error   { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 // Customize our TLS configuration 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 s . TLSConfig . MinVersion   =   tlsConfigs [ 0 ] . ProtocolMinVersion 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 s . TLSConfig . MaxVersion   =   tlsConfigs [ 0 ] . ProtocolMaxVersion 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 s . TLSConfig . CipherSuites   =   tlsConfigs [ 0 ] . Ciphers 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 s . TLSConfig . PreferServerCipherSuites   =   tlsConfigs [ 0 ] . PreferServerCipherSuites 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 // TLS client authentication, if user enabled it 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 err   :=   setupClientAuth ( tlsConfigs ,   s . TLSConfig ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 if   err   !=   nil   { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 defer   close ( s . startChan ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 return   err 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 // Create TLS listener - note that we do not replace s.listener 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 // with this TLS listener; tls.listener is unexported and does 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 // not implement the File() method we need for graceful restarts 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 // on POSIX systems. 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 ln   =   tls . NewListener ( ln ,   s . TLSConfig ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 close ( s . startChan )   // unblock anyone waiting for this to start listening 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 return   s . Serve ( ln ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								} 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								* / 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// 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. 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								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   { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 case   <- time . After ( s . connTimeout ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 case   <- done : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 // Close the listener now; this stops the server without delay 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 s . listenerMu . Lock ( ) 
  
						 
					
						
							
								
									
										
										
										
											2016-04-28 21:15:45 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									 if   s . tcp   !=   nil   { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 err   =   s . tcp . Close ( ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 if   s . udp   !=   nil   { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 err   =   s . udp . Close ( ) 
  
						 
					
						
							
								
									
										
										
										
											2016-03-18 20:57:35 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									 } 
  
						 
					
						
							
								
									
										
										
										
											2016-04-09 22:53:39 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 for   _ ,   s1   :=   range   s . server   { 
  
						 
					
						
							
								
									
										
										
										
											2016-04-10 18:50:11 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										 err   =   s1 . Shutdown ( ) 
  
						 
					
						
							
								
									
										
										
										
											2016-04-09 22:53:39 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									 } 
  
						 
					
						
							
								
									
										
										
										
											2016-04-10 18:50:11 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									 s . listenerMu . Unlock ( ) 
  
						 
					
						
							
								
									
										
										
										
											2016-03-18 20:57:35 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 return 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								} 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// WaitUntilStarted blocks until the server s is started, meaning 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// that practically the next instruction is to start the server loop. 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// It also unblocks if the server encounters an error during startup. 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func   ( s   * Server )   WaitUntilStarted ( )   { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 <- s . startChan 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								} 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// ListenerFd gets a dup'ed file of the listener. If there 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// is no underlying file, the return value will be nil. It 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// is the caller's responsibility to close the file. 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func   ( s   * Server )   ListenerFd ( )   * os . File   { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 s . listenerMu . Lock ( ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 defer   s . listenerMu . Unlock ( ) 
  
						 
					
						
							
								
									
										
										
										
											2016-04-28 21:15:45 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									 if   s . tcp   !=   nil   { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 file ,   _   :=   s . tcp . ( * net . TCPListener ) . File ( ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 return   file 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 return   nil 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								} 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// PacketConnFd gets a dup'ed file of the packetconn. If there 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// is no underlying file, the return value will be nil. It 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// is the caller's responsibility to close the file. 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func   ( s   * Server )   PacketConnFd ( )   * os . File   { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 s . listenerMu . Lock ( ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 defer   s . listenerMu . Unlock ( ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 if   s . udp   !=   nil   { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 file ,   _   :=   s . udp . ( * net . UDPConn ) . File ( ) 
  
						 
					
						
							
								
									
										
										
										
											2016-03-18 20:57:35 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										 return   file 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 return   nil 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								} 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// ServeDNS is the entry point for every request to the address that s 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// is bound to. It acts as a multiplexer for the requests zonename as 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// defined in the request so that the correct zone 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// (configuration and middleware stack) will handle the request. 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func   ( s   * Server )   ServeDNS ( w   dns . ResponseWriter ,   r   * dns . Msg )   { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 defer   func ( )   { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 // In case the user doesn't enable error middleware, we still 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 // need to make sure that we stay alive up here 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 if   rec   :=   recover ( ) ;   rec   !=   nil   { 
  
						 
					
						
							
								
									
										
										
										
											2016-03-19 20:53:37 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											 DefaultErrorFunc ( w ,   r ,   dns . RcodeServerFailure ) 
  
						 
					
						
							
								
									
										
										
										
											2016-03-18 20:57:35 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										 } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 } ( ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2016-04-09 11:13:04 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									 if   m ,   err   :=   middleware . Edns0Version ( r ) ;   err   !=   nil   {   // Wrong EDNS version, return at once. 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 rc   :=   middleware . RcodeToString ( dns . RcodeBadVers ) 
  
						 
					
						
							
								
									
										
										
										
											2016-06-23 11:21:12 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										 state   :=   middleware . State { W :   w ,   Req :   r } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 metrics . Report ( state ,   metrics . Dropped ,   rc ,   m . Len ( ) ,   time . Now ( ) ) 
  
						 
					
						
							
								
									
										
										
										
											2016-04-09 11:13:04 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										 w . WriteMsg ( m ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 return 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2016-03-18 20:57:35 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									 // Execute the optional request callback if it exists 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 if   s . ReqCallback   !=   nil   &&   s . ReqCallback ( w ,   r )   { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 return 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 q   :=   r . Question [ 0 ] . Name 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 b   :=   make ( [ ] byte ,   len ( q ) ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 off ,   end   :=   0 ,   false 
  
						 
					
						
							
								
									
										
										
										
											2016-03-19 07:18:57 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									 ctx   :=   context . Background ( ) 
  
						 
					
						
							
								
									
										
										
										
											2016-04-03 15:52:23 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2016-03-18 20:57:35 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									 for   { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 l   :=   len ( q [ off : ] ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 for   i   :=   0 ;   i   <   l ;   i ++   { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											 b [ i ]   =   q [ off + i ] 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											 // normalize the name for the lookup 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											 if   b [ i ]   >=   'A'   &&   b [ i ]   <=   'Z'   { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												 b [ i ]   |=   ( 'a'   -   'A' ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											 } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 if   h ,   ok   :=   s . zones [ string ( b [ : l ] ) ] ;   ok   { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											 if   r . Question [ 0 ] . Qtype   !=   dns . TypeDS   { 
  
						 
					
						
							
								
									
										
										
										
											2016-03-19 07:18:57 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												 rcode ,   _   :=   h . stack . ServeDNS ( ctx ,   w ,   r ) 
  
						 
					
						
							
								
									
										
										
										
											2016-03-19 20:53:37 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												 if   RcodeNoClientWrite ( rcode )   { 
  
						 
					
						
							
								
									
										
										
										
											2016-03-18 20:57:35 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
													 DefaultErrorFunc ( w ,   r ,   rcode ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												 } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												 return 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											 } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 off ,   end   =   dns . NextLabel ( q ,   off ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 if   end   { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											 break 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 // Wildcard match, if we have found nothing try the root zone as a last resort. 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 if   h ,   ok   :=   s . zones [ "." ] ;   ok   { 
  
						 
					
						
							
								
									
										
										
										
											2016-03-19 07:18:57 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										 rcode ,   _   :=   h . stack . ServeDNS ( ctx ,   w ,   r ) 
  
						 
					
						
							
								
									
										
										
										
											2016-03-19 20:53:37 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										 if   RcodeNoClientWrite ( rcode )   { 
  
						 
					
						
							
								
									
										
										
										
											2016-03-18 20:57:35 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
											 DefaultErrorFunc ( w ,   r ,   rcode ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 return 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2016-04-02 18:11:56 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									 // Still here? Error out with REFUSED and some logging 
  
						 
					
						
							
								
									
										
										
										
											2016-03-18 20:57:35 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									 remoteHost   :=   w . RemoteAddr ( ) . String ( ) 
  
						 
					
						
							
								
									
										
										
										
											2016-04-02 18:11:56 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									 DefaultErrorFunc ( w ,   r ,   dns . RcodeRefused ) 
  
						 
					
						
							
								
									
										
										
										
											2016-04-21 09:00:02 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									 log . Printf ( "[INFO] \"%s %s %s\" - No such zone at %s (Remote: %s)" ,   dns . Type ( r . Question [ 0 ] . Qtype ) ,   dns . Class ( r . Question [ 0 ] . Qclass ) ,   q ,   s . Addr ,   remoteHost ) 
  
						 
					
						
							
								
									
										
										
										
											2016-03-18 20:57:35 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								} 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2016-04-09 16:17:53 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// DefaultErrorFunc responds to an DNS request with an error. 
  
						 
					
						
							
								
									
										
										
										
											2016-03-18 20:57:35 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								func   DefaultErrorFunc ( w   dns . ResponseWriter ,   r   * dns . Msg ,   rcode   int )   { 
  
						 
					
						
							
								
									
										
										
										
											2016-04-09 16:17:53 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									 state   :=   middleware . State { W :   w ,   Req :   r } 
  
						 
					
						
							
								
									
										
										
										
											2016-04-09 11:13:04 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									 rc   :=   middleware . RcodeToString ( rcode ) 
  
						 
					
						
							
								
									
										
										
										
											2016-04-06 22:29:33 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2016-03-18 20:57:35 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									 answer   :=   new ( dns . Msg ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 answer . SetRcode ( r ,   rcode ) 
  
						 
					
						
							
								
									
										
										
										
											2016-04-09 16:17:53 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									 state . SizeAndDo ( answer ) 
  
						 
					
						
							
								
									
										
										
										
											2016-04-06 14:13:29 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2016-06-23 11:21:12 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									 metrics . Report ( state ,   metrics . Dropped ,   rc ,   answer . Len ( ) ,   time . Now ( ) ) 
  
						 
					
						
							
								
									
										
										
										
											2016-03-18 20:57:35 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									 w . WriteMsg ( answer ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								} 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// setupClientAuth sets up TLS client authentication only if 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// any of the TLS configs specified at least one cert file. 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func   setupClientAuth ( tlsConfigs   [ ] TLSConfig ,   config   * tls . Config )   error   { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 var   clientAuth   bool 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 for   _ ,   cfg   :=   range   tlsConfigs   { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 if   len ( cfg . ClientCerts )   >   0   { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											 clientAuth   =   true 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											 break 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 if   clientAuth   { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 pool   :=   x509 . NewCertPool ( ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 for   _ ,   cfg   :=   range   tlsConfigs   { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											 for   _ ,   caFile   :=   range   cfg . ClientCerts   { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												 caCrt ,   err   :=   ioutil . ReadFile ( caFile )   // Anyone that gets a cert from this CA can connect 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												 if   err   !=   nil   { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													 return   err 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												 } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												 if   ! pool . AppendCertsFromPEM ( caCrt )   { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													 return   fmt . Errorf ( "error loading client certificate '%s': no certificates were successfully parsed" ,   caFile ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												 } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											 } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 config . ClientCAs   =   pool 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 config . ClientAuth   =   tls . RequireAndVerifyClientCert 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 return   nil 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								} 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// RunFirstStartupFuncs runs all of the server's FirstStartup 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// callback functions unless one of them returns an error first. 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// It is the caller's responsibility to call this only once and 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// at the correct time. The functions here should not be executed 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// at restarts or where the user does not explicitly start a new 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// instance of the server. 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func   ( s   * Server )   RunFirstStartupFuncs ( )   error   { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 for   _ ,   z   :=   range   s . zones   { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 for   _ ,   f   :=   range   z . config . FirstStartup   { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											 if   err   :=   f ( ) ;   err   !=   nil   { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												 return   err 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											 } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 return   nil 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								} 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// ShutdownCallbacks executes all the shutdown callbacks 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// for all the virtualhosts in servers, and returns all the 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// errors generated during their execution. In other words, 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// an error executing one shutdown callback does not stop 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// execution of others. Only one shutdown callback is executed 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// at a time. You must protect the servers that are passed in 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// if they are shared across threads. 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func   ShutdownCallbacks ( servers   [ ] * Server )   [ ] error   { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 var   errs   [ ] error 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 for   _ ,   s   :=   range   servers   { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 for   _ ,   zone   :=   range   s . zones   { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											 for   _ ,   shutdownFunc   :=   range   zone . config . Shutdown   { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												 err   :=   shutdownFunc ( ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												 if   err   !=   nil   { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													 errs   =   append ( errs ,   err ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												 } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											 } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 return   errs 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								} 
  
						 
					
						
							
								
									
										
										
										
											2016-03-19 20:53:37 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2016-04-29 07:28:35 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								func   StartupCallbacks ( servers   [ ] * Server )   [ ] error   { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 var   errs   [ ] error 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 for   _ ,   s   :=   range   servers   { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 for   _ ,   zone   :=   range   s . zones   { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											 for   _ ,   startupFunc   :=   range   zone . config . Startup   { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												 err   :=   startupFunc ( ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												 if   err   !=   nil   { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													 errs   =   append ( errs ,   err ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												 } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											 } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 return   errs 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								} 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2016-03-19 20:53:37 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								func   RcodeNoClientWrite ( rcode   int )   bool   { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 switch   rcode   { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 case   dns . RcodeServerFailure : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 fallthrough 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 case   dns . RcodeRefused : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 fallthrough 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 case   dns . RcodeFormatError : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 fallthrough 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 case   dns . RcodeNotImplemented : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 return   true 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 return   false 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}