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