serve_mux.go raw

   1  package dns
   2  
   3  import (
   4  	"sync"
   5  )
   6  
   7  // ServeMux is an DNS request multiplexer. It matches the zone name of
   8  // each incoming request against a list of registered patterns add calls
   9  // the handler for the pattern that most closely matches the zone name.
  10  //
  11  // ServeMux is DNSSEC aware, meaning that queries for the DS record are
  12  // redirected to the parent zone (if that is also registered), otherwise
  13  // the child gets the query.
  14  //
  15  // ServeMux is also safe for concurrent access from multiple goroutines.
  16  //
  17  // The zero ServeMux is empty and ready for use.
  18  type ServeMux struct {
  19  	z map[string]Handler
  20  	m sync.RWMutex
  21  }
  22  
  23  // NewServeMux allocates and returns a new ServeMux.
  24  func NewServeMux() *ServeMux {
  25  	return new(ServeMux)
  26  }
  27  
  28  // DefaultServeMux is the default ServeMux used by Serve.
  29  var DefaultServeMux = NewServeMux()
  30  
  31  func (mux *ServeMux) match(q string, t uint16) Handler {
  32  	mux.m.RLock()
  33  	defer mux.m.RUnlock()
  34  	if mux.z == nil {
  35  		return nil
  36  	}
  37  
  38  	q = CanonicalName(q)
  39  
  40  	var handler Handler
  41  	for off, end := 0, false; !end; off, end = NextLabel(q, off) {
  42  		if h, ok := mux.z[q[off:]]; ok {
  43  			if t != TypeDS {
  44  				return h
  45  			}
  46  			// Continue for DS to see if we have a parent too, if so delegate to the parent
  47  			handler = h
  48  		}
  49  	}
  50  
  51  	// Wildcard match, if we have found nothing try the root zone as a last resort.
  52  	if h, ok := mux.z["."]; ok {
  53  		return h
  54  	}
  55  
  56  	return handler
  57  }
  58  
  59  // Handle adds a handler to the ServeMux for pattern.
  60  func (mux *ServeMux) Handle(pattern string, handler Handler) {
  61  	if pattern == "" {
  62  		panic("dns: invalid pattern " + pattern)
  63  	}
  64  	mux.m.Lock()
  65  	if mux.z == nil {
  66  		mux.z = make(map[string]Handler)
  67  	}
  68  	mux.z[CanonicalName(pattern)] = handler
  69  	mux.m.Unlock()
  70  }
  71  
  72  // HandleFunc adds a handler function to the ServeMux for pattern.
  73  func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Msg)) {
  74  	mux.Handle(pattern, HandlerFunc(handler))
  75  }
  76  
  77  // HandleRemove deregisters the handler specific for pattern from the ServeMux.
  78  func (mux *ServeMux) HandleRemove(pattern string) {
  79  	if pattern == "" {
  80  		panic("dns: invalid pattern " + pattern)
  81  	}
  82  	mux.m.Lock()
  83  	delete(mux.z, CanonicalName(pattern))
  84  	mux.m.Unlock()
  85  }
  86  
  87  // ServeDNS dispatches the request to the handler whose pattern most
  88  // closely matches the request message.
  89  //
  90  // ServeDNS is DNSSEC aware, meaning that queries for the DS record
  91  // are redirected to the parent zone (if that is also registered),
  92  // otherwise the child gets the query.
  93  //
  94  // If no handler is found, or there is no question, a standard REFUSED
  95  // message is returned
  96  func (mux *ServeMux) ServeDNS(w ResponseWriter, req *Msg) {
  97  	var h Handler
  98  	if len(req.Question) >= 1 { // allow more than one question
  99  		h = mux.match(req.Question[0].Name, req.Question[0].Qtype)
 100  	}
 101  
 102  	if h != nil {
 103  		h.ServeDNS(w, req)
 104  	} else {
 105  		handleRefused(w, req)
 106  	}
 107  }
 108  
 109  // Handle registers the handler with the given pattern
 110  // in the DefaultServeMux. The documentation for
 111  // ServeMux explains how patterns are matched.
 112  func Handle(pattern string, handler Handler) { DefaultServeMux.Handle(pattern, handler) }
 113  
 114  // HandleRemove deregisters the handle with the given pattern
 115  // in the DefaultServeMux.
 116  func HandleRemove(pattern string) { DefaultServeMux.HandleRemove(pattern) }
 117  
 118  // HandleFunc registers the handler function with the given pattern
 119  // in the DefaultServeMux.
 120  func HandleFunc(pattern string, handler func(ResponseWriter, *Msg)) {
 121  	DefaultServeMux.HandleFunc(pattern, handler)
 122  }
 123