func multidns(query *dns.Msg, out chan *dns.Msg) { start := time.Now() response := make(chan dnsresponse, len(servers)) for _, server := range servers { go singlequery(query, server, response) //var req dnsrequest //req.query.response = query //req.query.server = server //req.channel = response //service <- req } var logline string sent := false var allresults []*dns.Msg for i := 0; i < len(servers); i++ { result := <-response if !sent && result.response != nil { //We have a winner... //Send only one response. query is satisfied. now dick around to collect more stats out <- result.response sent = true //Log with special flag. May not always be the first to answer... logline += fmt.Sprintf("%s (%s - W) ; ", result.server, time.Since(start)) } else { //... but log everyone logline += fmt.Sprintf("%s (%s) ; ", result.server, time.Since(start)) } //extract ips from result.response if result.response != nil { if iscachable(result.response) { for _, ans := range result.response.Answer { if ans.Header().Rrtype == dns.TypeA { //fmt.Printf("%s\n", ans.(*dns.A).A) ipchan <- fmt.Sprintf("%s", ans.(*dns.A).A) } } allresults = append(allresults, result.response) } } } //logline += "\n" var name []string for _, q := range query.Question { name = append(name, q.Name+":"+dns.Class(q.Qclass).String()) } fmt.Printf("%s (%s): %s\n", start, name, logline) if len(allresults) > 0 { putincache(allresults) } //fmt.Printf("Exiting...\n") }
// 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) }
// Class returns the class of the question in the request. func (s *State) Class() string { return dns.Class(s.Req.Question[0].Qclass).String() }
func questionToString(q dns.Question) string { return fmt.Sprintf("%s %s %s", q.Name, dns.Class(q.Qclass), dns.Type(q.Qtype)) }
func textConvertMessage(m *Message, s *bytes.Buffer) { isQuery := false printQueryAddress := false switch *m.Type { case Message_CLIENT_QUERY, Message_RESOLVER_QUERY, Message_AUTH_QUERY, Message_FORWARDER_QUERY, Message_TOOL_QUERY: isQuery = true case Message_CLIENT_RESPONSE, Message_RESOLVER_RESPONSE, Message_AUTH_RESPONSE, Message_FORWARDER_RESPONSE, Message_TOOL_RESPONSE: isQuery = false default: s.WriteString("[unhandled Message.Type]\n") return } if isQuery { textConvertTime(s, m.QueryTimeSec, m.QueryTimeNsec) } else { textConvertTime(s, m.ResponseTimeSec, m.ResponseTimeNsec) } s.WriteString(" ") switch *m.Type { case Message_CLIENT_QUERY, Message_CLIENT_RESPONSE: { s.WriteString("C") } case Message_RESOLVER_QUERY, Message_RESOLVER_RESPONSE: { s.WriteString("R") } case Message_AUTH_QUERY, Message_AUTH_RESPONSE: { s.WriteString("A") } case Message_FORWARDER_QUERY, Message_FORWARDER_RESPONSE: { s.WriteString("F") } case Message_STUB_QUERY, Message_STUB_RESPONSE: { s.WriteString("S") } case Message_TOOL_QUERY, Message_TOOL_RESPONSE: { s.WriteString("T") } } if isQuery { s.WriteString("Q ") } else { s.WriteString("R ") } switch *m.Type { case Message_CLIENT_QUERY, Message_CLIENT_RESPONSE, Message_AUTH_QUERY, Message_AUTH_RESPONSE: printQueryAddress = true } if printQueryAddress { textConvertIP(s, m.QueryAddress) } else { textConvertIP(s, m.ResponseAddress) } s.WriteString(" ") if m.SocketProtocol != nil { s.WriteString(m.SocketProtocol.String()) } s.WriteString(" ") var err error msg := new(dns.Msg) if isQuery { s.WriteString(strconv.Itoa(len(m.QueryMessage))) s.WriteString("b ") err = msg.Unpack(m.QueryMessage) } else { s.WriteString(strconv.Itoa(len(m.ResponseMessage))) s.WriteString("b ") err = msg.Unpack(m.ResponseMessage) } if err != nil { s.WriteString("X ") } else { s.WriteString("\"" + msg.Question[0].Name + "\" ") s.WriteString(dns.Class(msg.Question[0].Qclass).String() + " ") s.WriteString(dns.Type(msg.Question[0].Qtype).String()) } s.WriteString("\n") }