123 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			123 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package dns
 | |
| 
 | |
| import (
 | |
| 	"sync"
 | |
| )
 | |
| 
 | |
| // ServeMux is an DNS request multiplexer. It matches the zone name of
 | |
| // each incoming request against a list of registered patterns add calls
 | |
| // the handler for the pattern that most closely matches the zone name.
 | |
| //
 | |
| // ServeMux is DNSSEC aware, meaning that queries for the DS record are
 | |
| // redirected to the parent zone (if that is also registered), otherwise
 | |
| // the child gets the query.
 | |
| //
 | |
| // ServeMux is also safe for concurrent access from multiple goroutines.
 | |
| //
 | |
| // The zero ServeMux is empty and ready for use.
 | |
| type ServeMux struct {
 | |
| 	z map[string]Handler
 | |
| 	m sync.RWMutex
 | |
| }
 | |
| 
 | |
| // NewServeMux allocates and returns a new ServeMux.
 | |
| func NewServeMux() *ServeMux {
 | |
| 	return new(ServeMux)
 | |
| }
 | |
| 
 | |
| // DefaultServeMux is the default ServeMux used by Serve.
 | |
| var DefaultServeMux = NewServeMux()
 | |
| 
 | |
| func (mux *ServeMux) match(q string, t uint16) Handler {
 | |
| 	mux.m.RLock()
 | |
| 	defer mux.m.RUnlock()
 | |
| 	if mux.z == nil {
 | |
| 		return nil
 | |
| 	}
 | |
| 
 | |
| 	q = CanonicalName(q)
 | |
| 
 | |
| 	var handler Handler
 | |
| 	for off, end := 0, false; !end; off, end = NextLabel(q, off) {
 | |
| 		if h, ok := mux.z[q[off:]]; ok {
 | |
| 			if t != TypeDS {
 | |
| 				return h
 | |
| 			}
 | |
| 			// Continue for DS to see if we have a parent too, if so delegate to the parent
 | |
| 			handler = h
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	// Wildcard match, if we have found nothing try the root zone as a last resort.
 | |
| 	if h, ok := mux.z["."]; ok {
 | |
| 		return h
 | |
| 	}
 | |
| 
 | |
| 	return handler
 | |
| }
 | |
| 
 | |
| // Handle adds a handler to the ServeMux for pattern.
 | |
| func (mux *ServeMux) Handle(pattern string, handler Handler) {
 | |
| 	if pattern == "" {
 | |
| 		panic("dns: invalid pattern " + pattern)
 | |
| 	}
 | |
| 	mux.m.Lock()
 | |
| 	if mux.z == nil {
 | |
| 		mux.z = make(map[string]Handler)
 | |
| 	}
 | |
| 	mux.z[CanonicalName(pattern)] = handler
 | |
| 	mux.m.Unlock()
 | |
| }
 | |
| 
 | |
| // HandleFunc adds a handler function to the ServeMux for pattern.
 | |
| func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Msg)) {
 | |
| 	mux.Handle(pattern, HandlerFunc(handler))
 | |
| }
 | |
| 
 | |
| // HandleRemove deregisters the handler specific for pattern from the ServeMux.
 | |
| func (mux *ServeMux) HandleRemove(pattern string) {
 | |
| 	if pattern == "" {
 | |
| 		panic("dns: invalid pattern " + pattern)
 | |
| 	}
 | |
| 	mux.m.Lock()
 | |
| 	delete(mux.z, CanonicalName(pattern))
 | |
| 	mux.m.Unlock()
 | |
| }
 | |
| 
 | |
| // ServeDNS dispatches the request to the handler whose pattern most
 | |
| // closely matches the request message.
 | |
| //
 | |
| // ServeDNS is DNSSEC aware, meaning that queries for the DS record
 | |
| // are redirected to the parent zone (if that is also registered),
 | |
| // otherwise the child gets the query.
 | |
| //
 | |
| // If no handler is found, or there is no question, a standard REFUSED
 | |
| // message is returned
 | |
| func (mux *ServeMux) ServeDNS(w ResponseWriter, req *Msg) {
 | |
| 	var h Handler
 | |
| 	if len(req.Question) >= 1 { // allow more than one question
 | |
| 		h = mux.match(req.Question[0].Name, req.Question[0].Qtype)
 | |
| 	}
 | |
| 
 | |
| 	if h != nil {
 | |
| 		h.ServeDNS(w, req)
 | |
| 	} else {
 | |
| 		handleRefused(w, req)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // Handle registers the handler with the given pattern
 | |
| // in the DefaultServeMux. The documentation for
 | |
| // ServeMux explains how patterns are matched.
 | |
| func Handle(pattern string, handler Handler) { DefaultServeMux.Handle(pattern, handler) }
 | |
| 
 | |
| // HandleRemove deregisters the handle with the given pattern
 | |
| // in the DefaultServeMux.
 | |
| func HandleRemove(pattern string) { DefaultServeMux.HandleRemove(pattern) }
 | |
| 
 | |
| // HandleFunc registers the handler function with the given pattern
 | |
| // in the DefaultServeMux.
 | |
| func HandleFunc(pattern string, handler func(ResponseWriter, *Msg)) {
 | |
| 	DefaultServeMux.HandleFunc(pattern, handler)
 | |
| }
 |