1package dns 2 3import ( 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. 18type ServeMux struct { 19 z map[string]Handler 20 m sync.RWMutex 21} 22 23// NewServeMux allocates and returns a new ServeMux. 24func NewServeMux() *ServeMux { 25 return new(ServeMux) 26} 27 28// DefaultServeMux is the default ServeMux used by Serve. 29var DefaultServeMux = NewServeMux() 30 31func (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. 60func (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. 73func (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. 78func (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 96func (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. 112func Handle(pattern string, handler Handler) { DefaultServeMux.Handle(pattern, handler) } 113 114// HandleRemove deregisters the handle with the given pattern 115// in the DefaultServeMux. 116func HandleRemove(pattern string) { DefaultServeMux.HandleRemove(pattern) } 117 118// HandleFunc registers the handler function with the given pattern 119// in the DefaultServeMux. 120func HandleFunc(pattern string, handler func(ResponseWriter, *Msg)) { 121 DefaultServeMux.HandleFunc(pattern, handler) 122} 123