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