serve_mux.go (3449B)
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 }