// ServeDNS resolution. func (h *RandomUpstream) ServeDNS(w dns.ResponseWriter, r *dns.Msg) { ns := h.upstream[rand.Intn(len(h.upstream))] ns = defaultPort(ns) for _, q := range r.Question { log.Printf("[info] [%v] <== %s %s %v (ns %s)\n", r.Id, dns.ClassToString[q.Qclass], dns.TypeToString[q.Qtype], q.Name, ns) } client := &dns.Client{ Net: w.RemoteAddr().Network(), } res, rtt, err := client.Exchange(r, ns) if err != nil { msg := new(dns.Msg) msg.SetRcode(r, dns.RcodeServerFailure) w.WriteMsg(msg) return } log.Printf("[info] [%v] ==> %s:", r.Id, rtt) for _, a := range res.Answer { log.Printf("[info] [%v] ----> %s\n", r.Id, a) } err = w.WriteMsg(res) if err != nil { log.Printf("[error] [%v] failed to respond – %s", r.Id, err) } }
// handleExternal handles DNS queries that are outside the cluster's domain such // as the Public Internet. func (d *DnsServer) handleExternal(w dns.ResponseWriter, r *dns.Msg) { dom, qType := parseQuestion(r) q := dns.TypeToString[qType] + " " + dom log.Printf("--> External: %s", q) if !d.recurse { log.Printf("<-x %s: SERVFAIL: recursion disabled", q) m := new(dns.Msg) m.SetReply(r) m.SetRcode(r, dns.RcodeServerFailure) m.Authoritative = false m.RecursionAvailable = false w.WriteMsg(m) } else { in, ns, err := d.queryExternal(r) if err != nil { log.Printf("<-x %s (@%s): SERVFAIL: %v", q, ns, err) m := new(dns.Msg) m.SetReply(r) m.SetRcode(r, dns.RcodeServerFailure) w.WriteMsg(m) } else { log.Printf("<-- %s (@%s): %d answers, %d extra, %d ns", q, ns, len(in.Answer), len(in.Extra), len(in.Ns)) in.Compress = true w.WriteMsg(in) } } }
func (s *server) NameError(req *dns.Msg) *dns.Msg { m := new(dns.Msg) m.SetRcode(req, dns.RcodeNameError) m.Ns = []dns.RR{s.NewSOA()} m.Ns[0].Header().Ttl = s.config.MinTtl return m }
// nodeLookup is used to handle a node query func (d *DNSServer) nodeLookup(network, datacenter, node string, req, resp *dns.Msg) { // Only handle ANY and A type requests qType := req.Question[0].Qtype if qType != dns.TypeANY && qType != dns.TypeA { return } // Make an RPC request args := structs.NodeSpecificRequest{ Datacenter: datacenter, Node: node, } var out structs.IndexedNodeServices if err := d.agent.RPC("Catalog.NodeServices", &args, &out); err != nil { d.logger.Printf("[ERR] dns: rpc error: %v", err) resp.SetRcode(req, dns.RcodeServerFailure) return } // If we have no address, return not found! if out.NodeServices == nil { resp.SetRcode(req, dns.RcodeNameError) return } // Add the node record records := d.formatNodeRecord(&out.NodeServices.Node, req.Question[0].Name, qType) if records != nil { resp.Answer = append(resp.Answer, records...) } }
func (srv *Server) setupRootZone() { dns.HandleFunc(".", func(w dns.ResponseWriter, r *dns.Msg) { m := new(dns.Msg) m.SetRcode(r, dns.RcodeRefused) w.WriteMsg(m) }) }
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) }
func serve(w dns.ResponseWriter, r *dns.Msg, c *Cache) { switch { case r.IsNotify(): if *flaglog { log.Printf("fks-shield: notify/update") } fallthrough case r.IsUpdate(): client := new(dns.Client) if p, e := client.Exchange(r, *server); e == nil { w.WriteMsg(p) } return } if p := c.Find(r); p != nil { b := []byte{byte(r.MsgHdr.Id >> 8), byte(r.MsgHdr.Id)} p = append(b, p...) w.Write(p) return } // Cache miss client := new(dns.Client) if p, e := client.Exchange(r, *server); e == nil { // TODO(mg): If r has edns0 and p has not we create a mismatch here w.WriteMsg(p) c.Insert(p) return } else { log.Printf("fks-shield: failed to get answer " + e.Error()) m := new(dns.Msg) m.SetRcode(r, dns.RcodeServerFailure) w.WriteMsg(m) } }
// handlerFunc receives requests, looks up the result and returns what is found. func handlerFunc(res dns.ResponseWriter, req *dns.Msg) { message := new(dns.Msg) switch req.Opcode { case dns.OpcodeQuery: message.SetReply(req) message.Compress = false message.Answer = make([]dns.RR, 0) for _, question := range message.Question { answers := answerQuestion(strings.ToLower(question.Name), question.Qtype) if len(answers) > 0 { for i := range answers { message.Answer = append(message.Answer, answers[i]) } } else { // If there are no records, go back through and search for SOA records for _, question := range message.Question { answers := answerQuestion(strings.ToLower(question.Name), dns.TypeSOA) for i := range answers { message.Ns = append(message.Ns, answers[i]) } } } } if len(message.Answer) == 0 && len(message.Ns) == 0 { message.Rcode = dns.RcodeNameError } default: message = message.SetRcode(req, dns.RcodeNotImplemented) } res.WriteMsg(message) }
func (s *DNSServer) doHandle(w dns.ResponseWriter, r *dns.Msg) *dns.Msg { m := new(dns.Msg) m.SetReply(r) // Send empty response for empty requests if len(r.Question) == 0 { m.Ns = s.createSOA() return m } switch r.Question[0].Qtype { case dns.TypePTR: s.handlePTRRequest(r, m) case dns.TypeMX: s.handleMXRequest(r, m) case dns.TypeA: s.handleARequest(r, m) case dns.TypeSOA: m.Answer = s.createSOA() default: m.Ns = s.createSOA() m.SetRcode(r, dns.RcodeNotImplemented) } return m }
func handle(writer dns.ResponseWriter, request *dns.Msg) { message := new(dns.Msg) message.SetReply(request) message.SetRcode(message, dns.RcodeSuccess) question := request.Question[0] switch request.Opcode { case dns.OpcodeNotify: log.Println(fmt.Sprintf("Recieved NOTIFY for %s", question.Name)) message = handle_notify(question, message, writer) case dns.OpcodeQuery: log.Println(fmt.Sprintf("Recieved QUERY for %s", question.Name)) message = handle_query(question, message, writer) default: message = handle_error(message, writer, "REFUSED") } // Apparently this dns library takes the question out on // certain RCodes, like REFUSED, which is not right. So we reinsert it. message.Question[0].Name = question.Name message.Question[0].Qtype = question.Qtype message.Question[0].Qclass = question.Qclass message.MsgHdr.Opcode = request.Opcode // Send an authoritative answer message.MsgHdr.Authoritative = true writer.WriteMsg(message) }
// serviceLookup is used to handle a service query func (d *DNSServer) serviceLookup(network, datacenter, service, tag string, req, resp *dns.Msg) { // Make an RPC request args := structs.ServiceSpecificRequest{ Datacenter: datacenter, ServiceName: service, ServiceTag: tag, TagFilter: tag != "", QueryOptions: structs.QueryOptions{AllowStale: d.config.AllowStale}, } var out structs.IndexedCheckServiceNodes RPC: if err := d.agent.RPC("Health.ServiceNodes", &args, &out); err != nil { d.logger.Printf("[ERR] dns: rpc error: %v", err) resp.SetRcode(req, dns.RcodeServerFailure) return } // Verify that request is not too stale, redo the request if args.AllowStale && out.LastContact > d.config.MaxStale { args.AllowStale = false d.logger.Printf("[WARN] dns: Query results too stale, re-requesting") goto RPC } // If we have no nodes, return not found! if len(out.Nodes) == 0 { resp.SetRcode(req, dns.RcodeNameError) return } // Determine the TTL var ttl time.Duration if d.config.ServiceTTL != nil { var ok bool ttl, ok = d.config.ServiceTTL[service] if !ok { ttl = d.config.ServiceTTL["*"] } } // Filter out any service nodes due to health checks out.Nodes = d.filterServiceNodes(out.Nodes) // Perform a random shuffle shuffleServiceNodes(out.Nodes) // If the network is not TCP, restrict the number of responses if network != "tcp" && len(out.Nodes) > maxServiceResponses { out.Nodes = out.Nodes[:maxServiceResponses] } // Add various responses depending on the request qType := req.Question[0].Qtype d.serviceNodeRecords(out.Nodes, req, resp, ttl) if qType == dns.TypeSRV { d.serviceSRVRecords(datacenter, out.Nodes, req, resp, ttl) } }
func formerr(w dns.ResponseWriter, req *dns.Msg) { m := new(dns.Msg) m.MsgHdr.Opcode = dns.OpcodeUpdate if req.IsTsig() != nil { m.SetTsig(userFromTsig(req), dns.HmacMD5, 300, time.Now().Unix()) } w.WriteMsg(m.SetRcode(req, dns.RcodeFormatError)) }
// NoData write a nodata response to the client. func (k Kubernetes) Err(zone string, rcode int, state middleware.State) (int, error) { m := new(dns.Msg) m.SetRcode(state.Req, rcode) m.Ns = []dns.RR{k.SOA(zone, state)} state.SizeAndDo(m) state.W.WriteMsg(m) return rcode, nil }
func (s *server) NoDataError(m, req *dns.Msg) { m.SetRcode(req, dns.RcodeSuccess) m.Ns = []dns.RR{s.NewSOA()} m.Ns[0].Header().Ttl = s.config.MinTtl StatsNoDataCount.Inc(1) promErrorCount.WithLabelValues("nodata") }
func (s *server) NameError(m, req *dns.Msg) { m.SetRcode(req, dns.RcodeNameError) m.Ns = []dns.RR{s.NewSOA()} m.Ns[0].Header().Ttl = s.config.MinTtl StatsNameErrorCount.Inc(1) promErrorCount.WithLabelValues("nxdomain") }
func ErrorHandler() Handler { return HandlerFunc(func(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) { m := new(dns.Msg) m.SetRcode(r, dns.RcodeServerFailure) w.WriteMsg(m) return dns.RcodeServerFailure, nil }) }
func (self *TrivialDnsServer) refuseWithCode(w dns.ResponseWriter, req *dns.Msg, code int) { m := new(dns.Msg) for _, r := range req.Extra { if r.Header().Rrtype == dns.TypeOPT { m.SetEdns0(4096, r.(*dns.OPT).Do()) } } m.SetRcode(req, code) w.WriteMsg(m) }
// dispatch is used to parse a request and invoke the correct handler func (d *DNSServer) dispatch(network string, req, resp *dns.Msg) { // By default the query is in the default datacenter datacenter := d.agent.config.Datacenter // Get the QName without the domain suffix qName := dns.Fqdn(req.Question[0].Name) qName = strings.TrimSuffix(qName, d.domain) // Split into the label parts labels := dns.SplitDomainName(qName) // The last label is either "node", "service" or a datacenter name PARSE: n := len(labels) if n == 0 { goto INVALID } switch labels[n-1] { case "service": if n == 1 { goto INVALID } // Extract the service service := labels[n-2] // Support "." in the label, re-join all the parts tag := "" if n >= 3 { tag = strings.Join(labels[:n-2], ".") } // Handle lookup with and without tag d.serviceLookup(network, datacenter, service, tag, req, resp) case "node": if len(labels) == 1 { goto INVALID } // Allow a "." in the node name, just join all the parts node := strings.Join(labels[:n-1], ".") d.nodeLookup(network, datacenter, node, req, resp) default: // Store the DC, and re-parse datacenter = labels[n-1] labels = labels[:n-1] goto PARSE } return INVALID: d.logger.Printf("[WARN] dns: QName invalid: %s", qName) resp.SetRcode(req, dns.RcodeNameError) }
func (s *DNSServer) handleRequest(w dns.ResponseWriter, r *dns.Msg) { m := new(dns.Msg) m.SetReply(r) // Send empty response for empty requests if len(r.Question) == 0 { m.Ns = s.createSOA() w.WriteMsg(m) return } // respond to SOA requests if r.Question[0].Qtype == dns.TypeSOA { m.Answer = s.createSOA() w.WriteMsg(m) return } m.Answer = make([]dns.RR, 0, 2) query := r.Question[0].Name // trim off any trailing dot if query[len(query)-1] == '.' { query = query[:len(query)-1] } for service := range s.queryServices(query) { var rr dns.RR switch r.Question[0].Qtype { case dns.TypeA: rr = s.makeServiceA(r.Question[0].Name, service) case dns.TypeMX: rr = s.makeServiceMX(r.Question[0].Name, service) default: // this query type isn't supported, but we do have // a record with this name. Per RFC 4074 sec. 3, we // immediately return an empty NOERROR reply. m.Ns = s.createSOA() m.MsgHdr.Authoritative = true w.WriteMsg(m) return } m.Answer = append(m.Answer, rr) } // We didn't find a record corresponding to the query if len(m.Answer) == 0 { m.Ns = s.createSOA() m.SetRcode(r, dns.RcodeNameError) // NXDOMAIN } w.WriteMsg(m) }
// 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) }
// panicRecover catches any panics from the resolvers and sets an error // code of server failure func panicRecover(f func(w dns.ResponseWriter, r *dns.Msg)) func(w dns.ResponseWriter, r *dns.Msg) { return func(w dns.ResponseWriter, r *dns.Msg) { defer func() { if rec := recover(); rec != nil { m := new(dns.Msg) m.SetRcode(r, 2) _ = w.WriteMsg(m) logging.Error.Println(rec) } }() f(w, r) } }
// nodeLookup is used to handle a node query func (d *DNSServer) nodeLookup(network, datacenter, node string, req, resp *dns.Msg) { // Only handle ANY, A and AAAA type requests qType := req.Question[0].Qtype if qType != dns.TypeANY && qType != dns.TypeA && qType != dns.TypeAAAA { return } // Make an RPC request args := structs.NodeSpecificRequest{ Datacenter: datacenter, Node: node, QueryOptions: structs.QueryOptions{ Token: d.agent.config.ACLToken, AllowStale: *d.config.AllowStale, }, } var out structs.IndexedNodeServices RPC: if err := d.agent.RPC("Catalog.NodeServices", &args, &out); err != nil { d.logger.Printf("[ERR] dns: rpc error: %v", err) resp.SetRcode(req, dns.RcodeServerFailure) return } // Verify that request is not too stale, redo the request if args.AllowStale { if out.LastContact > d.config.MaxStale { args.AllowStale = false d.logger.Printf("[WARN] dns: Query results too stale, re-requesting") goto RPC } else if out.LastContact > staleCounterThreshold { metrics.IncrCounter([]string{"consul", "dns", "stale_queries"}, 1) } } // If we have no address, return not found! if out.NodeServices == nil { d.addSOA(d.domain, resp) resp.SetRcode(req, dns.RcodeNameError) return } // Add the node record n := out.NodeServices.Node addr := translateAddress(d.agent.config, datacenter, n.Address, n.TaggedAddresses) records := d.formatNodeRecord(out.NodeServices.Node, addr, req.Question[0].Name, qType, d.config.NodeTTL) if records != nil { resp.Answer = append(resp.Answer, records...) } }
func handleForwardingRaw(nameservers []string, req *dns.Msg, remote net.Addr) *dns.Msg { if len(nameservers) == 0 { log.Printf("no nameservers defined, can not forward\n") m := new(dns.Msg) m.SetReply(req) m.SetRcode(req, dns.RcodeServerFailure) m.Authoritative = false // no matter what set to false m.RecursionAvailable = true // and this is still true return m } tcp := false if _, ok := remote.(*net.TCPAddr); ok { tcp = true } var ( r *dns.Msg err error try int ) // Use request Id for "random" nameserver selection. nsid := int(req.Id) % len(nameservers) dnsClient := &dns.Client{Net: "udp", ReadTimeout: 4 * time.Second, WriteTimeout: 4 * time.Second, SingleInflight: true} if tcp { dnsClient.Net = "tcp" } Redo: nameserver := nameservers[nsid] if i := strings.Index(nameserver, ":"); i < 0 { nameserver += ":53" } r, _, err = dnsClient.Exchange(req, nameserver) if err == nil { r.Compress = true return r } // Seen an error, this can only mean, "server not reached", try again // but only if we have not exausted our nameservers. if try < len(nameservers) { try++ nsid = (nsid + 1) % len(nameservers) goto Redo } log.Printf("failure to forward request %q\n", err) m := new(dns.Msg) m.SetReply(req) m.SetRcode(req, dns.RcodeServerFailure) return m }
func Handle(writer dns.ResponseWriter, request *dns.Msg) { question := request.Question[0] message := new(dns.Msg) message.SetReply(request) message.SetRcode(message, dns.RcodeSuccess) full_address := writer.RemoteAddr().String() address := strings.Split(full_address, ":")[0] if allowed(address) != true { msg := fmt.Sprintf("ERROR %s : %s not allowed to talk to slappy", question.Name, address) logger.Error(msg) message = handle_error(message, writer, "REFUSED") respond(message, question, *request, writer) return } logger.Debug(debug_request(*request, question, writer)) go Stat("query") switch request.Opcode { case dns.OpcodeNotify: message = handle_notify(question, message, writer) case CC: if question.Qclass == ClassCC { switch question.Qtype { case CREATE: message = handle_create(question, message, writer) case DELETE: message = handle_delete(question, message, writer) default: message = handle_error(message, writer, "REFUSED") } } else { logger.Debug(fmt.Sprintf("ERROR %s : unsupported rrclass %d", question.Name, question.Qclass)) message = handle_error(message, writer, "REFUSED") } default: if question.Name == conf.Stats_uri { message = Stats_dns_message(message, writer) logger.Debug("SUCCESS STATS : Sent runtime stats") break } logger.Debug(fmt.Sprintf("ERROR %s : unsupported opcode %d", question.Name, request.Opcode)) message = handle_error(message, writer, "REFUSED") } respond(message, question, *request, writer) }
// Creates an empty response to the specified request. If `err` is // specified, the `RCODE` field in the response will be set to this value. // If `err` is set to 0, the `RCODE` field will not be modified, and the // resulting packet will just mean that the domain exists (not `NXDOMAIN`) // but there are no records of the requested type associated to it. // If `NXDOMAIN` is sent as a reply to the hijacked `AAAA` records of hostnames // when IPv6 routing is disabled, some web browsers (e.g. Chrome) will display // an error message stating `DNS_PROBE_FINISHED_NXDOMAIN`, even though a request // for `A` records types is sent and properly replied to by the server to the client. // Even though the original `ResponseWriter` object is taken as an argument, // this function does not send a reply to the client. Instead, the // packet is returned for further processing by the caller. func getEmptyMsg(w dns.ResponseWriter, req *dns.Msg, err int) *dns.Msg { m := new(dns.Msg) m.SetReply(req) if err != 0 { m.SetRcode(req, err) } m.Authoritative = false m.RecursionAvailable = true return m }
// ServeDNSForward forwards a request to a nameservers and returns the response. func (s *server) ServeDNSForward(w dns.ResponseWriter, req *dns.Msg) { StatsForwardCount.Inc(1) if len(s.config.Nameservers) == 0 || dns.CountLabel(req.Question[0].Name) < s.config.Ndots { s.config.log.Infof("no nameservers defined or name too short, can not forward") m := new(dns.Msg) m.SetReply(req) m.SetRcode(req, dns.RcodeServerFailure) m.Authoritative = false // no matter what set to false m.RecursionAvailable = true // and this is still true w.WriteMsg(m) return } tcp := false if _, ok := w.RemoteAddr().(*net.TCPAddr); ok { tcp = true } var ( r *dns.Msg err error try int ) // Use request Id for "random" nameserver selection. nsid := int(req.Id) % len(s.config.Nameservers) Redo: switch tcp { case false: r, _, err = s.dnsUDPclient.Exchange(req, s.config.Nameservers[nsid]) case true: r, _, err = s.dnsTCPclient.Exchange(req, s.config.Nameservers[nsid]) } if err == nil { r.Compress = true w.WriteMsg(r) return } // Seen an error, this can only mean, "server not reached", try again // but only if we have not exausted our nameservers. if try < len(s.config.Nameservers) { try++ nsid = (nsid + 1) % len(s.config.Nameservers) goto Redo } s.config.log.Errorf("failure to forward request %q", err) m := new(dns.Msg) m.SetReply(req) m.SetRcode(req, dns.RcodeServerFailure) w.WriteMsg(m) }
func serve(w dns.ResponseWriter, req *dns.Msg, z *dns.Zone) { if z == nil { panic("fksd: no zone") } m := new(dns.Msg) // Just NACK ANYs if req.Question[0].Qtype == dns.TypeANY { m.SetRcode(req, dns.RcodeServerFailure) ednsFromRequest(req, m) w.WriteMsg(m) return } logPrintf("[zone %s] incoming %s %s %d from %s\n", z.Origin, req.Question[0].Name, dns.TypeToString[req.Question[0].Qtype], req.MsgHdr.Id, w.RemoteAddr()) node, exact, ref := z.FindFunc(req.Question[0].Name, func(n interface{}) bool { return n.(*dns.ZoneData).NonAuth }) if ref { logPrintf("[zone %s] referral due\n", z.Origin) m.SetReply(req) m.Ns = node.RR[dns.TypeNS] for _, n := range m.Ns { if dns.IsSubDomain(n.(*dns.NS).Ns, n.Header().Name) { findGlue(m, z, n.(*dns.NS).Ns) } } ednsFromRequest(req, m) w.WriteMsg(m) return } if exact { exactMatch(w, req, m, z, node) return } // Not an exact match nor an referral if z.Wildcard > 0 { lx := dns.SplitLabels(req.Question[0].Name) wc := "*." + strings.Join(lx[1:], ".") node, exact = z.Find(wc) if exact { logPrintf("[zone %s] wildcard answer\n", z.Origin) // as exact,but not complete -- only the last part } } nameerror(w, m, req) return }
func Respond(w dns.ResponseWriter, req *dns.Msg, records []dns.RR) { m := new(dns.Msg) m.SetReply(req) m.Authoritative = true m.RecursionAvailable = true m.Compress = true m.Answer = records // Figure out the max response size bufsize := uint16(512) tcp := isTcp(w) if o := req.IsEdns0(); o != nil { bufsize = o.UDPSize() } if tcp { bufsize = dns.MaxMsgSize - 1 } else if bufsize < 512 { bufsize = 512 } if m.Len() > dns.MaxMsgSize { fqdn := dns.Fqdn(req.Question[0].Name) log.WithFields(log.Fields{"fqdn": fqdn}).Debug("Response too big, dropping Extra") m.Extra = nil if m.Len() > dns.MaxMsgSize { log.WithFields(log.Fields{"fqdn": fqdn}).Debug("Response still too big") m := new(dns.Msg) m.SetRcode(m, dns.RcodeServerFailure) } } if m.Len() > int(bufsize) && !tcp { log.Debug("Too big 1") m.Extra = nil if m.Len() > int(bufsize) { log.Debug("Too big 2") m.Answer = nil m.Truncated = true } } err := w.WriteMsg(m) if err != nil { log.Warn("Failed to return reply: ", err, m.Len()) } }
// makes non-mesos queries to external nameserver func (res *Resolver) HandleNonMesos(w dns.ResponseWriter, r *dns.Msg) { var err error var m *dns.Msg // tracing info logging.CurLog.NonMesosRequests.Inc() // If external request are disabled if !res.config.ExternalOn { m = new(dns.Msg) // set refused m.SetRcode(r, 5) } else { proto := "udp" if _, ok := w.RemoteAddr().(*net.TCPAddr); ok { proto = "tcp" } for _, resolver := range res.config.Resolvers { nameserver := net.JoinHostPort(resolver, "53") m, err = res.extResolver(r, nameserver, proto, recurseCnt) if err == nil { break } } } // extResolver returns nil Msg sometimes cause of perf if m == nil { m = new(dns.Msg) m.SetRcode(r, 2) err = errors.New("nil msg") } if err != nil { logging.Error.Println(r.Question[0].Name) logging.Error.Println(err) logging.CurLog.NonMesosFailed.Inc() } else { // nxdomain if len(m.Answer) == 0 { logging.CurLog.NonMesosNXDomain.Inc() } else { logging.CurLog.NonMesosSuccess.Inc() } } reply(w, m) }
// ServeDNS is the handler for DNS requests, responsible for parsing DNS request, possibly forwarding // it to a real dns server and returning a response. func (s *Server) ServeDNS(w dns.ResponseWriter, req *dns.Msg) { stats.RequestCount.Inc(1) q := req.Question[0] log.Printf("Received DNS Request for %q from %q", q.Name, w.RemoteAddr()) // If the query does not fall in our s.domain, forward it if !strings.HasSuffix(q.Name, dns.Fqdn(s.domain)) { s.ServeDNSForward(w, req) return } m := new(dns.Msg) m.SetReply(req) m.Authoritative = true m.RecursionAvailable = true m.Answer = make([]dns.RR, 0, 10) defer w.WriteMsg(m) if q.Qtype == dns.TypeANY || q.Qtype == dns.TypeSRV { records, extra, err := s.getSRVRecords(q) if err != nil { // We are authoritative for this name, but it does not exist: NXDOMAIN m.SetRcode(req, dns.RcodeNameError) m.Ns = s.createSOA() log.Println("Error: ", err) return } m.Answer = append(m.Answer, records...) m.Extra = append(m.Extra, extra...) } if q.Qtype == dns.TypeA || q.Qtype == dns.TypeAAAA { records, err := s.getARecords(q) if err != nil { m.SetRcode(req, dns.RcodeNameError) m.Ns = s.createSOA() log.Println("Error: ", err) return } m.Answer = append(m.Answer, records...) } if len(m.Answer) == 0 { // Send back a NODATA response m.Ns = s.createSOA() } }