func (manager *DnsManager) dnsHandler(w dns.ResponseWriter, req *dns.Msg) { m := new(dns.Msg) m.SetReply(req) name := req.Question[0].Name name = strings.TrimSuffix(name, "."+manager.BaseName) manager.dbMutex.Lock() entry, ok := manager.db[name] manager.dbMutex.Unlock() if ok { switch req.Question[0].Qtype { case dns.TypeSRV: m.Answer = manager.makeAllSRV(entry) case dns.TypeA: m.Answer = manager.makeAllA(entry) if manager.PushSRV { m.Extra = manager.makeAllSRV(entry) } } } w.WriteMsg(m) }
func TestShuffleAnswers(t *testing.T) { var res Resolver m := new(dns.Msg) for i := 0; i < 10; i++ { name := "10.0.0." + strconv.Itoa(i) rr, err := res.formatA("blah.com", name) if err != nil { t.Error(err) } m.Answer = append(m.Answer, rr) } n := new(dns.Msg) c := make([]dns.RR, len(m.Answer)) copy(c, m.Answer) n.Answer = c _ = shuffleAnswers(m.Answer) sflag := false // 10! chance of failing here for i := 0; i < 10; i++ { if n.Answer[i] != m.Answer[i] { sflag = true break } } if !sflag { t.Error("not shuffling") } }
func handleSpecialNames(w dns.ResponseWriter, req *dns.Msg) bool { question := req.Question[0] nameLC := strings.ToLower(question.Name) for _, localRR := range localRRS { if nameLC == localRR.Name { m := new(dns.Msg) m.Id = req.Id m.Answer = []dns.RR{*localRR.RR} m.Response = true w.WriteMsg(m) return true } } if question.Qtype != dns.TypeANY { return false } m := new(dns.Msg) m.Id = req.Id hinfo := new(dns.HINFO) hinfo.Hdr = dns.RR_Header{Name: question.Name, Rrtype: dns.TypeHINFO, Class: dns.ClassINET, Ttl: 86400} hinfo.Cpu = "ANY is not supported any more" hinfo.Os = "See draft-jabley-dnsop-refuse-any" m.Answer = []dns.RR{hinfo} m.Response = true w.WriteMsg(m) return true }
func (s *DNSServer) handleARequest(r *dns.Msg, m *dns.Msg) { m.Answer = make([]dns.RR, 0, 2) query := r.Question[0].Name if query[len(query)-1] == '.' { query = query[:len(query)-1] } for service := range s.queryServices(query) { rr := new(dns.A) var ttl int if service.Ttl != -1 { ttl = service.Ttl } else { ttl = s.config.ttl } rr.Hdr = dns.RR_Header{ Name: r.Question[0].Name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: uint32(ttl), } rr.A = service.Ip m.Answer = append(m.Answer, rr) } }
func (s *DNSServer) handlePTRRequest(r *dns.Msg, m *dns.Msg) { m.Answer = make([]dns.RR, 0, 2) query := r.Question[0].Name if query[len(query)-1] == '.' { query = query[:len(query)-1] } for service := range s.queryIp(query) { var ttl int if service.Ttl != -1 { ttl = service.Ttl } else { ttl = s.config.ttl } for domain := range s.listDomains(service) { rr := new(dns.PTR) rr.Hdr = dns.RR_Header{ Name: r.Question[0].Name, Rrtype: dns.TypePTR, Class: dns.ClassINET, Ttl: uint32(ttl), } rr.Ptr = domain m.Answer = append(m.Answer, rr) } } }
func (h dnsHandler) ServeDNS(w dns.ResponseWriter, r *dns.Msg) { if len(r.Question) != 1 { h.t.Fatalf("bad: %#v", r.Question) } name := "join.service.consul." question := r.Question[0] if question.Name != name || question.Qtype != dns.TypeANY { h.t.Fatalf("bad: %#v", question) } m := new(dns.Msg) m.SetReply(r) m.Authoritative = true m.RecursionAvailable = false m.Answer = append(m.Answer, &dns.A{ Hdr: dns.RR_Header{ Name: name, Rrtype: dns.TypeA, Class: dns.ClassINET}, A: net.ParseIP("127.0.0.1"), }) m.Answer = append(m.Answer, &dns.AAAA{ Hdr: dns.RR_Header{ Name: name, Rrtype: dns.TypeAAAA, Class: dns.ClassINET}, AAAA: net.ParseIP("2001:db8:a0b:12f0::1"), }) if err := w.WriteMsg(m); err != nil { h.t.Fatalf("err: %v", err) } }
func (r *resolver) handleIPQuery(name string, query *dns.Msg, ipType int) (*dns.Msg, error) { addr := r.sb.ResolveName(name, ipType) if addr == nil { return nil, nil } log.Debugf("Lookup for %s: IP %v", name, addr) resp := new(dns.Msg) resp.SetReply(query) setCommonFlags(resp) if len(addr) > 1 { addr = shuffleAddr(addr) } if ipType == netutils.IPv4 { for _, ip := range addr { rr := new(dns.A) rr.Hdr = dns.RR_Header{Name: name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: respTTL} rr.A = ip resp.Answer = append(resp.Answer, rr) } } else { for _, ip := range addr { rr := new(dns.AAAA) rr.Hdr = dns.RR_Header{Name: name, Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Ttl: respTTL} rr.AAAA = ip resp.Answer = append(resp.Answer, rr) } } return resp, nil }
// 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 (c Chaos) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) { state := middleware.State{W: w, Req: r} if state.QClass() != dns.ClassCHAOS || state.QType() != dns.TypeTXT { return c.Next.ServeDNS(ctx, w, r) } m := new(dns.Msg) m.SetReply(r) hdr := dns.RR_Header{Name: state.QName(), Rrtype: dns.TypeTXT, Class: dns.ClassCHAOS, Ttl: 0} switch state.Name() { default: return c.Next.ServeDNS(ctx, w, r) case "authors.bind.": for a, _ := range c.Authors { m.Answer = append(m.Answer, &dns.TXT{Hdr: hdr, Txt: []string{trim(a)}}) } case "version.bind.", "version.server.": m.Answer = []dns.RR{&dns.TXT{Hdr: hdr, Txt: []string{trim(c.Version)}}} case "hostname.bind.", "id.server.": hostname, err := os.Hostname() if err != nil { hostname = "localhost" } m.Answer = []dns.RR{&dns.TXT{Hdr: hdr, Txt: []string{trim(hostname)}}} } state.SizeAndDo(m) w.WriteMsg(m) return 0, nil }
func (s HelixServer) Handler(w dns.ResponseWriter, req *dns.Msg) { m := new(dns.Msg) m.SetReply(req) qType := req.Question[0].Qtype qClass := req.Question[0].Qclass header := dns.RR_Header{Name: m.Question[0].Name, Rrtype: qType, Class: qClass, Ttl: 5} resp, err := s.getResponse(req.Question[0]) if err != nil { if s.DNSClient != nil { log.Printf("Could not get record for %s, forwarding to %s", req.Question[0].Name, s.DNSClient.GetAddress()) in, _ := s.DNSClient.Lookup(req) w.WriteMsg(in) } else { log.Printf("Could not get record for %s", req.Question[0].Name) w.WriteMsg(m) } return } switch qType { case dns.TypeA: m.Answer = make([]dns.RR, 1) m.Answer[0] = &dns.A{Hdr: header, A: net.ParseIP(resp.Value())} case dns.TypeAAAA: m.Answer = make([]dns.RR, 1) m.Answer[0] = &dns.AAAA{Hdr: header, AAAA: net.ParseIP(resp.Value())} case dns.TypeSRV: var records []SrvRecord err := json.Unmarshal([]byte(resp.Value()), &records) if err != nil { log.Printf("Could not unmarshal SRV record from etcd: %s", resp.Value()) } else { m.Answer = make([]dns.RR, len(records)) for i := range records { m.Answer[i] = &dns.SRV{ Hdr: header, Priority: records[i].Priority, Weight: records[i].Weight, Port: records[i].Port, Target: records[i].Target, } } } case dns.TypePTR: m.Answer = make([]dns.RR, 1) m.Answer[0] = &dns.PTR{Hdr: header, Ptr: resp.Value()} case dns.TypeCNAME: m.Answer = make([]dns.RR, 1) m.Answer[0] = &dns.CNAME{Hdr: header, Target: resp.Value()} default: log.Printf("Unrecognised record type: %d", qType) } w.WriteMsg(m) }
func (s *DNSServer) handleReverseRequest(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 } 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.queryIp(query) { if r.Question[0].Qtype != dns.TypePTR { m.Ns = s.createSOA() w.WriteMsg(m) return } var ttl int if service.Ttl != -1 { ttl = service.Ttl } else { ttl = s.config.ttl } for domain := range s.listDomains(service) { rr := new(dns.PTR) rr.Hdr = dns.RR_Header{ Name: r.Question[0].Name, Rrtype: dns.TypePTR, Class: dns.ClassINET, Ttl: uint32(ttl), } rr.Ptr = domain m.Answer = append(m.Answer, rr) } } if len(m.Answer) != 0 { w.WriteMsg(m) } else { // We didn't find a record corresponding to the query, // try forwarding s.handleForward(w, r) } }
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) }
func (z *zone) zoneHandler(c *config, w dns.ResponseWriter, req *dns.Msg) { c.stats.Incr("query.request", 1) m := new(dns.Msg) m.SetReply(req) m.Authoritative = true m.Answer = []dns.RR{} questions := []string{} answers := []string{} if len(req.Question) != 1 { c.stats.Incr("query.error", 1) log.Printf("Warning: len(req.Question) != 1") return } q := req.Question[0] questions = append(questions, fmt.Sprintf("%s[%s]", q.Name, dns.TypeToString[q.Qtype])) if q.Qclass != uint16(dns.ClassINET) { c.stats.Incr("query.error", 1) log.Printf("Warning: skipping unhandled class: %s", dns.ClassToString[q.Qclass]) return } for _, record := range z.rrs { h := record.Header() if q.Name != h.Name { continue } txt := record.String() if q.Qtype == dns.TypeA && h.Rrtype == dns.TypeCNAME { // special handling for A queries w/CNAME results if q.Name == dns.Fqdn(z.name) { // flatten root CNAME flat, err := c.flattenCNAME(record.(*dns.CNAME)) if err != nil || flat == nil { log.Printf("flattenCNAME error: %s", err.Error()) } else { for _, record := range flat { m.Answer = append(m.Answer, record) answers = append(answers, "(FLAT)"+record.String()) } } continue } // don't flatten other CNAMEs for now } else if q.Qtype != h.Rrtype && q.Qtype != dns.TypeANY { // skip RRs that don't match continue } m.Answer = append(m.Answer, record) answers = append(answers, txt) } //m.Extra = []dns.RR{} //m.Extra = append(m.Extra, &dns.TXT{Hdr: dns.RR_Header{Name: m.Question[0].Name, Rrtype: dns.TypeTXT, Class: dns.ClassINET, Ttl: 0}, Txt: []string{"DNS rocks"}}) c.debug(fmt.Sprintf("Query [%s] %s -> %s ", w.RemoteAddr().String(), strings.Join(questions, ","), strings.Join(answers, ","))) c.stats.Incr("query.answer", 1) w.WriteMsg(m) }
func (c *config) registerVersionHandler() { // special handler for reporting version: dig . @host TXT dns.HandleFunc(".", func(w dns.ResponseWriter, req *dns.Msg) { m := new(dns.Msg) m.SetReply(req) if req.Question[0].Name == "." && req.Question[0].Qtype == dns.TypeTXT { m.Authoritative = true m.Answer = []dns.RR{} m.Answer = append(m.Answer, &dns.TXT{Hdr: dns.RR_Header{Name: m.Question[0].Name, Rrtype: dns.TypeTXT, Class: dns.ClassINET, Ttl: 0}, Txt: []string{"v" + version}}) m.Extra = []dns.RR{} m.Extra = append(m.Extra, &dns.TXT{Hdr: dns.RR_Header{Name: m.Question[0].Name, Rrtype: dns.TypeTXT, Class: dns.ClassINET, Ttl: 0}, Txt: []string{"NedDNS"}}) } w.WriteMsg(m) }) }
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()) } }
// trimAnswers makes sure a UDP response is not longer than allowed by RFC 1035. // We first enforce an arbitrary limit, and then make sure the response doesn't // exceed 512 bytes. func trimAnswers(resp *dns.Msg) (trimmed bool) { numAnswers := len(resp.Answer) // This cuts UDP responses to a useful but limited number of responses. if numAnswers > maxServiceResponses { resp.Answer = resp.Answer[:maxServiceResponses] } // This enforces the hard limit of 512 bytes per the RFC. for len(resp.Answer) > 0 && resp.Len() > 512 { resp.Answer = resp.Answer[:len(resp.Answer)-1] } return len(resp.Answer) < numAnswers }
// handleDnsCNAME modifies m to respond to a CNAME query for name by looking it up // from the repository. NXDOMAIN and the SOA record are returned for nonexisting entries. func (s *server) handleDnsCNAME(name host, m *dns.Msg) { s.mux.RLock() defer s.mux.RUnlock() rec := s.repo.get(name) if rec != nil && rec.cname != nil { m.Answer = append(m.Answer, rec.cname) m.Ns = nil m.MsgHdr.Rcode = dns.RcodeSuccess } else { m.Answer = nil m.MsgHdr.Rcode = dns.RcodeNameError s.soa.write(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() } }
func (s *Server) composeBrowsingAnswers(resp *dns.Msg, ttl uint32) { ptr := &dns.PTR{ Hdr: dns.RR_Header{ Name: s.service.ServiceName(), Rrtype: dns.TypePTR, Class: dns.ClassINET, Ttl: ttl, }, Ptr: s.service.ServiceInstanceName(), } resp.Answer = append(resp.Answer, ptr) txt := &dns.TXT{ Hdr: dns.RR_Header{ Name: s.service.ServiceInstanceName(), Rrtype: dns.TypeTXT, Class: dns.ClassINET, Ttl: ttl, }, Txt: s.service.Text, } srv := &dns.SRV{ Hdr: dns.RR_Header{ Name: s.service.ServiceInstanceName(), Rrtype: dns.TypeSRV, Class: dns.ClassINET, Ttl: ttl, }, Priority: 0, Weight: 0, Port: uint16(s.service.Port), Target: s.service.HostName, } resp.Extra = append(resp.Extra, srv, txt) if s.service.AddrIPv4 != nil { a := &dns.A{ Hdr: dns.RR_Header{ Name: s.service.HostName, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: ttl, }, A: s.service.AddrIPv4, } resp.Extra = append(resp.Extra, a) } if s.service.AddrIPv6 != nil { aaaa := &dns.AAAA{ Hdr: dns.RR_Header{ Name: s.service.HostName, Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Ttl: ttl, }, AAAA: s.service.AddrIPv6, } resp.Extra = append(resp.Extra, aaaa) } }
func (r *resolver) handlePTRQuery(ptr string, query *dns.Msg) (*dns.Msg, error) { parts := []string{} if strings.HasSuffix(ptr, ptrIPv4domain) { parts = strings.Split(ptr, ptrIPv4domain) } else if strings.HasSuffix(ptr, ptrIPv6domain) { parts = strings.Split(ptr, ptrIPv6domain) } else { return nil, fmt.Errorf("invalid PTR query, %v", ptr) } host := r.backend.ResolveIP(parts[0]) if len(host) == 0 { return nil, nil } logrus.Debugf("Lookup for IP %s: name %s", parts[0], host) fqdn := dns.Fqdn(host) resp := new(dns.Msg) resp.SetReply(query) setCommonFlags(resp) rr := new(dns.PTR) rr.Hdr = dns.RR_Header{Name: ptr, Rrtype: dns.TypePTR, Class: dns.ClassINET, Ttl: respTTL} rr.Ptr = fqdn resp.Answer = append(resp.Answer, rr) return resp, nil }
// truncate removes answers until the given dns.Msg fits the permitted // length of the given transmission channel and sets the TC bit. // See https://tools.ietf.org/html/rfc1035#section-4.2.1 func truncate(m *dns.Msg, udp bool) *dns.Msg { max := dns.MinMsgSize if !udp { max = dns.MaxMsgSize } else if opt := m.IsEdns0(); opt != nil { max = int(opt.UDPSize()) } m.Truncated = m.Len() > max if !m.Truncated { return m } m.Extra = nil // Drop all extra records first if m.Len() < max { return m } answers := m.Answer[:] left, right := 0, len(m.Answer) for { if left == right { break } mid := (left + right) / 2 m.Answer = answers[:mid] if m.Len() < max { left = mid + 1 continue } right = mid } return m }
func (res *Resolver) handleSRV(rs *records.RecordGenerator, name string, m, r *dns.Msg) error { var errs multiError added := map[string]struct{}{} // track the A RR's we've already added, avoid dups for srv := range rs.SRVs[name] { srvRR, err := res.formatSRV(r.Question[0].Name, srv) if err != nil { errs.Add(err) continue } m.Answer = append(m.Answer, srvRR) host := strings.Split(srv, ":")[0] if _, found := added[host]; found { // avoid dups continue } if len(rs.As[host]) == 0 { continue } if a, ok := rs.As.First(host); ok { aRR, err := res.formatA(host, a) if err != nil { errs.Add(err) continue } m.Extra = append(m.Extra, aRR) added[host] = struct{}{} } } return errs }
// handleDNS is a handler function to actualy perform the dns querey response func (c *CatchAll) handleDNS(w dns.ResponseWriter, r *dns.Msg) { defer w.Close() var rr dns.RR domainSpoof := r.Question[0].Name msgResp := new(dns.Msg) msgResp.SetReply(r) msgResp.Compress = false rr = new(dns.A) if c.SpoofDomain { rr.(*dns.A).Hdr = dns.RR_Header{Name: domainSpoof, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 0} } else { rr.(*dns.A).Hdr = dns.RR_Header{Name: c.Domain, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 0} } rr.(*dns.A).A = c.IP switch r.Question[0].Qtype { case dns.TypeA: msgResp.Answer = append(msgResp.Answer, rr) default: log.Warnf("Unknown dns type %T", r.Question[0].Qtype) return } w.WriteMsg(msgResp) }
// serviceARecords is used to add the SRV records for a service lookup func (d *DNSServer) serviceSRVRecords(dc string, nodes structs.CheckServiceNodes, req, resp *dns.Msg, ttl time.Duration) { handled := make(map[string]struct{}) for _, node := range nodes { // Avoid duplicate entries, possible if a node has // the same service the same port, etc. tuple := fmt.Sprintf("%s:%d", node.Node.Node, node.Service.Port) if _, ok := handled[tuple]; ok { continue } handled[tuple] = struct{}{} // Add the SRV record srvRec := &dns.SRV{ Hdr: dns.RR_Header{ Name: req.Question[0].Name, Rrtype: dns.TypeSRV, Class: dns.ClassINET, Ttl: uint32(ttl / time.Second), }, Priority: 1, Weight: 1, Port: uint16(node.Service.Port), Target: fmt.Sprintf("%s.node.%s.%s", node.Node.Node, dc, d.domain), } resp.Answer = append(resp.Answer, srvRec) // Add the extra record records := d.formatNodeRecord(&node.Node, srvRec.Target, dns.TypeANY, ttl) if records != nil { resp.Extra = append(resp.Extra, records...) } } }
// handleTest is used to handle DNS queries in the ".consul." domain func (d *DNSServer) handleTest(resp dns.ResponseWriter, req *dns.Msg) { q := req.Question[0] defer func(s time.Time) { d.logger.Printf("[DEBUG] dns: request for %v (%v)", q, time.Now().Sub(s)) }(time.Now()) if !(q.Qtype == dns.TypeANY || q.Qtype == dns.TypeTXT) { return } if q.Name != testQuery { return } // Always respond with TXT "ok" m := new(dns.Msg) m.SetReply(req) m.Authoritative = true m.RecursionAvailable = true header := dns.RR_Header{Name: q.Name, Rrtype: dns.TypeTXT, Class: dns.ClassINET, Ttl: 0} txt := &dns.TXT{header, []string{"ok"}} m.Answer = append(m.Answer, txt) d.addSOA(consulDomain, m) if err := resp.WriteMsg(m); err != nil { d.logger.Printf("[WARN] dns: failed to respond: %v", err) } }
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 }
// handlePtr is used to handle "reverse" DNS queries func (d *DNSServer) handlePtr(resp dns.ResponseWriter, req *dns.Msg) { q := req.Question[0] defer func(s time.Time) { d.logger.Printf("[DEBUG] dns: request for %v (%v) from client %s (%s)", q, time.Now().Sub(s), resp.RemoteAddr().String(), resp.RemoteAddr().Network()) }(time.Now()) // Setup the message response m := new(dns.Msg) m.SetReply(req) m.Authoritative = true m.RecursionAvailable = (len(d.recursors) > 0) // Only add the SOA if requested if req.Question[0].Qtype == dns.TypeSOA { d.addSOA(d.domain, m) } datacenter := d.agent.config.Datacenter // Get the QName without the domain suffix qName := strings.ToLower(dns.Fqdn(req.Question[0].Name)) args := structs.DCSpecificRequest{ Datacenter: datacenter, QueryOptions: structs.QueryOptions{ Token: d.agent.config.ACLToken, AllowStale: d.config.AllowStale, }, } var out structs.IndexedNodes // TODO: Replace ListNodes with an internal RPC that can do the filter // server side to avoid transferring the entire node list. if err := d.agent.RPC("Catalog.ListNodes", &args, &out); err == nil { for _, n := range out.Nodes { arpa, _ := dns.ReverseAddr(n.Address) if arpa == qName { ptr := &dns.PTR{ Hdr: dns.RR_Header{Name: q.Name, Rrtype: dns.TypePTR, Class: dns.ClassINET, Ttl: 0}, Ptr: fmt.Sprintf("%s.node.%s.%s", n.Node, datacenter, d.domain), } m.Answer = append(m.Answer, ptr) break } } } // nothing found locally, recurse if len(m.Answer) == 0 { d.handleRecurse(resp, req) return } // Write out the complete response if err := resp.WriteMsg(m); err != nil { d.logger.Printf("[WARN] dns: failed to respond: %v", err) } }
// serviceNodeRecords is used to add the node records for a service lookup func (d *DNSServer) serviceNodeRecords(dc string, nodes structs.CheckServiceNodes, req, resp *dns.Msg, ttl time.Duration) { qName := req.Question[0].Name qType := req.Question[0].Qtype handled := make(map[string]struct{}) for _, node := range nodes { // Start with the translated address but use the service address, // if specified. addr := translateAddress(d.agent.config, dc, node.Node.Address, node.Node.TaggedAddresses) if node.Service.Address != "" { addr = node.Service.Address } // Avoid duplicate entries, possible if a node has // the same service on multiple ports, etc. if _, ok := handled[addr]; ok { continue } handled[addr] = struct{}{} // Add the node record records := d.formatNodeRecord(node.Node, addr, qName, qType, ttl) if records != nil { resp.Answer = append(resp.Answer, records...) } } }
// Create DNS packet with the config in line with the meta zone // paper from Vixie func metazone(w dns.ResponseWriter, req *dns.Msg, c *Config) { logPrintf("metazone command") // Only called when the class is CHAOS // PTR zone. -> get a list of zone names // Top level zone stuff -- list them if strings.ToUpper(req.Question[0].Name) == "ZONE." { m := new(dns.Msg) m.SetReply(req) for _, z := range c.Zones { ptr, _ := dns.NewRR("zone. 0 CH PTR " + z.Origin) m.Answer = append(m.Answer, ptr) } w.WriteMsg(m) return } // Top level user stuff -- list them if strings.ToUpper(req.Question[0].Name) == "USER." { } // <zone>.ZONE. formerr(w, req) return }
func (s *soa) TransferHandler(w dns.ResponseWriter, req *dns.Msg) { m := new(dns.Msg) m.SetReply(req) m.Answer = make([]dns.RR, 1) m.Answer[0] = test.SOA(fmt.Sprintf("%s IN SOA bla. bla. %d 0 0 0 0 ", testZone, s.serial)) w.WriteMsg(m) }