func (l Logger) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) { state := middleware.State{W: w, Req: r} for _, rule := range l.Rules { if middleware.Name(rule.NameScope).Matches(state.Name()) { responseRecorder := middleware.NewResponseRecorder(w) rcode, err := l.Next.ServeDNS(ctx, responseRecorder, r) if rcode > 0 { // There was an error up the chain, but no response has been written yet. // The error must be handled here so the log entry will record the response size. if l.ErrorFunc != nil { l.ErrorFunc(responseRecorder, r, rcode) } else { rc := middleware.RcodeToString(rcode) answer := new(dns.Msg) answer.SetRcode(r, rcode) state.SizeAndDo(answer) metrics.Report(state, metrics.Dropped, rc, answer.Len(), time.Now()) w.WriteMsg(answer) } rcode = 0 } rep := middleware.NewReplacer(r, responseRecorder, CommonLogEmptyValue) rule.Log.Println(rep.Replace(rule.Format)) return rcode, err } } return l.Next.ServeDNS(ctx, w, r) }
// DefaultErrorFunc responds to an DNS request with an error. func DefaultErrorFunc(w dns.ResponseWriter, r *dns.Msg, rcode int) { state := middleware.State{W: w, Req: r} rc := middleware.RcodeToString(rcode) answer := new(dns.Msg) answer.SetRcode(r, rcode) state.SizeAndDo(answer) metrics.Report(state, metrics.Dropped, rc, answer.Len(), time.Now()) w.WriteMsg(answer) }
// ServeDNS is the entry point for every request to the address that s // is bound to. It acts as a multiplexer for the requests zonename as // defined in the request so that the correct zone // (configuration and middleware stack) will handle the request. func (s *Server) ServeDNS(w dns.ResponseWriter, r *dns.Msg) { defer func() { // In case the user doesn't enable error middleware, we still // need to make sure that we stay alive up here if rec := recover(); rec != nil { DefaultErrorFunc(w, r, dns.RcodeServerFailure) } }() if m, err := middleware.Edns0Version(r); err != nil { // Wrong EDNS version, return at once. rc := middleware.RcodeToString(dns.RcodeBadVers) state := middleware.State{W: w, Req: r} metrics.Report(state, metrics.Dropped, rc, m.Len(), time.Now()) w.WriteMsg(m) return } // Execute the optional request callback if it exists if s.ReqCallback != nil && s.ReqCallback(w, r) { return } q := r.Question[0].Name b := make([]byte, len(q)) off, end := 0, false ctx := context.Background() for { l := len(q[off:]) for i := 0; i < l; i++ { b[i] = q[off+i] // normalize the name for the lookup if b[i] >= 'A' && b[i] <= 'Z' { b[i] |= ('a' - 'A') } } if h, ok := s.zones[string(b[:l])]; ok { if r.Question[0].Qtype != dns.TypeDS { rcode, _ := h.stack.ServeDNS(ctx, w, r) if RcodeNoClientWrite(rcode) { DefaultErrorFunc(w, r, rcode) } return } } off, end = dns.NextLabel(q, off) if end { break } } // Wildcard match, if we have found nothing try the root zone as a last resort. if h, ok := s.zones["."]; ok { rcode, _ := h.stack.ServeDNS(ctx, w, r) if RcodeNoClientWrite(rcode) { DefaultErrorFunc(w, r, rcode) } return } // Still here? Error out with REFUSED and some logging remoteHost := w.RemoteAddr().String() DefaultErrorFunc(w, r, dns.RcodeRefused) log.Printf("[INFO] \"%s %s %s\" - No such zone at %s (Remote: %s)", dns.Type(r.Question[0].Qtype), dns.Class(r.Question[0].Qclass), q, s.Addr, remoteHost) }