func rootZone(w dns.ResponseWriter, req *dns.Msg) { m := new(dns.Msg) m.SetReply(req) rr, _ := dns.NewRR(". 0 IN SOA a.root-servers.net. nstld.verisign-grs.com. 2016110600 1800 900 604800 86400") m.Ns = []dns.RR{rr} w.WriteMsg(m) }
// 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 createRespMsg(query *dns.Msg) *dns.Msg { resp := new(dns.Msg) resp.SetReply(query) setCommonFlags(resp) return resp }
// 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) } }
// handleQUery is used to handle DNS queries in the configured domain func (d *DNSServer) handleQuery(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()) // Switch to TCP if the client is network := "udp" if _, ok := resp.RemoteAddr().(*net.TCPAddr); ok { network = "tcp" } // 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) } // Dispatch the correct handler d.dispatch(network, req, m) // Write out the complete response if err := resp.WriteMsg(m); err != nil { d.logger.Printf("[WARN] dns: failed to respond: %v", err) } }
// handleDomain handles DNS queries that come to the cluster func (d *DnsServer) handleDomain(w dns.ResponseWriter, r *dns.Msg) { dom, qType := parseQuestion(r) q := dns.TypeToString[qType] + " " + dom log.Printf("--> Internal: %s", q) m := new(dns.Msg) m.SetReply(r) m.Authoritative = true supported, found, recs := d.queryRR(qType, dom) if !supported { log.Printf("<-x %s: NOTIMP", q) m.SetRcode(r, dns.RcodeNotImplemented) // NOTIMP } else if !found { log.Printf("<-x %s: NXDOMAIN", q) m.SetRcode(r, dns.RcodeNameError) // NXDOMAIN } else { for _, rec := range recs { rr, err := rrtype.ToRR(qType, dom, rec) if err != nil { log.Printf("<-x %s SERVFAIL: record conv err: %v", q, err) m.SetRcode(r, dns.RcodeServerFailure) break } else { log.Printf("<-- %s: %s", q, rr.String()) m.Answer = append(m.Answer, rr) } } } w.WriteMsg(m) }
// 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 (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 }
func (c *Config) GenerateServeDNS(hostname string) func(dns.ResponseWriter, *dns.Msg) { if len(hostname) > 0 { if hostname[len(hostname)-1] != '.' { hostname += "." } } return func(w dns.ResponseWriter, r *dns.Msg) { m := new(dns.Msg) m.SetReply(r) m.Authoritative = true ip, err := c.GetOrLaunchInstance() if err != nil { // TODO: error handling log.Println("Error in GetOrLaunchInstance:", err) w.Close() return } rr := new(dns.A) rr.Hdr = dns.RR_Header{Name: hostname, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: uint32(c.MaxIdleTime.Seconds())} rr.A = ip m.Answer = []dns.RR{rr} w.WriteMsg(m) } }
func (s *DNS) handleDNSInternal(w dns.ResponseWriter, req *dns.Msg) { q := req.Question[0] if q.Qtype == dns.TypeA && q.Qclass == dns.ClassINET { if record, ok := s.cache.Get(q.Name); ok { log.Printf("Found internal record for %s", q.Name) m := new(dns.Msg) m.SetReply(req) rr_header := dns.RR_Header{ Name: q.Name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 0, } a := &dns.A{rr_header, net.ParseIP(record.ip)} m.Answer = append(m.Answer, a) w.WriteMsg(m) return } log.Printf("No internal record found for %s", q.Name) dns.HandleFailed(w, req) } log.Printf("Only handling type A requests, skipping") dns.HandleFailed(w, req) }
func handleDnsRequest(w dns.ResponseWriter, r *dns.Msg) { m := new(dns.Msg) m.SetReply(r) records := make([]dns.RR, 0) q := r.Question[0] if q.Qtype == dns.TypeA && strings.HasSuffix(q.Name, ".docker.") { docker, _ := dockerclient.NewDockerClient("unix:///var/run/docker.sock", &tls.Config{}) name := strings.SplitN(q.Name, ".", 2)[0] containers, err := docker.ListContainers(false, false, fmt.Sprintf("{\"name\":[\"%s\"]}", name)) if err != nil { log.Fatal(err) } for _, c := range containers { info, _ := docker.InspectContainer(c.Id) log.Printf("Container %s[%6s] has ip %s\n", name, info.Id, info.NetworkSettings.IPAddress) records = append(records, &dns.A{ Hdr: dns.RR_Header{ Name: q.Name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 60}, A: net.ParseIP(info.NetworkSettings.IPAddress), }) } } m.Answer = append(m.Answer, records...) defer w.WriteMsg(m) }
func (s *DNS) handleReverseDNSLookup(w dns.ResponseWriter, req *dns.Msg) { q := req.Question[0] if q.Qtype == dns.TypePTR && q.Qclass == dns.ClassINET { if record, ok := s.cache.Get(q.Name); ok { log.Printf("Found internal record for %s", q.Name) m := new(dns.Msg) m.SetReply(req) rr_header := dns.RR_Header{ Name: q.Name, Rrtype: dns.TypePTR, Class: dns.ClassINET, Ttl: 0, } a := &dns.PTR{rr_header, record.fqdn} m.Answer = append(m.Answer, a) w.WriteMsg(m) return } log.Printf("Forwarding request to external recursor for: %s", q.Name) // Forward the request s.handleDNSExternal(w, req) } dns.HandleFailed(w, req) }
// 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 handlerToAnswer(w dns.ResponseWriter, r *dns.Msg) { db, err := sql.Open("mysql", "inserter:qwerty@/dnsServerCache") //Handler for database if err != nil { panic(err.Error()) // Just for example purpose. You should use proper error handling instead of panic } answer := new(dns.Msg) //Set answer to client answer.SetReply(r) //Set reply flag and start collecting data for reply var answersAll []dns.RR answersAll = dbRespond(db, r.Question[0].String()) if len(answersAll) != 0 { for _, answers := range answersAll { answer.Answer = append(answer.Answer, answers) } } else { client := new(dns.Client) var err1 error config, _ := dns.ClientConfigFromFile("/etc/resolv.conf") answer, _, err1 = client.Exchange(r, config.Servers[0]+":"+config.Port) if err1 != nil { panic(err1.Error()) } if r.Rcode != dns.RcodeSuccess { return } go dbWriter(answer.Answer, db, r.Question[0].String()) } w.WriteMsg(answer) }
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 (s *jujuNameServer) handleRequest(w dns.ResponseWriter, r *dns.Msg) { m := new(dns.Msg) m.SetReply(r) for _, q := range r.Question { rr, err := s.answer(q) if err != nil { m.SetRcodeFormatError(r) t := new(dns.TXT) t.Hdr = dns.RR_Header{ Name: q.Name, Rrtype: dns.TypeTXT, Class: dns.ClassNONE, } t.Txt = []string{err.Error()} m.Extra = append(m.Extra, t) continue } else if rr != nil { m.Answer = append(m.Answer, rr) } } m.Authoritative = true // recursion isn't really available, but it's apparently // necessary to set this to make nslookup happy. m.RecursionAvailable = true w.WriteMsg(m) }
// 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 (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 (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) }
// Instantiate a new answer as a reply of the passed message. func (h *ENUMHandler) answerForRequest(message *dns.Msg) *dns.Msg { answer := new(dns.Msg) answer.SetReply(message) answer.Authoritative = true answer.RecursionAvailable = false return answer }
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) }
func handleDNSRequest(w dns.ResponseWriter, r *dns.Msg) { if *debug { Log.Printf("handleRequest: message: %+v\n", r) } m := new(dns.Msg) m.SetReply(r) m.Compress = false switch r.Opcode { case dns.OpcodeQuery: parseQuery(m) case dns.OpcodeUpdate: for _, question := range r.Question { for _, rr := range r.Ns { updateRecord(rr, &question) } } } if r.IsTsig() != nil { if w.TsigStatus() == nil { m.SetTsig(r.Extra[len(r.Extra)-1].(*dns.TSIG).Hdr.Name, dns.HmacMD5, 300, time.Now().Unix()) } else { Log.Println("Status", w.TsigStatus().Error()) } } w.WriteMsg(m) }
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 makeReply(r *dns.Msg, as []dns.RR) *dns.Msg { m := new(dns.Msg) m.SetReply(r) m.RecursionAvailable = true m.Answer = as return m }
func main() { runtime.GOMAXPROCS(runtime.NumCPU() * 4) for z, rr := range zones { rrx := rr.(*dns.SOA) // Needed to create the actual RR, and not an reference. dns.HandleFunc(z, func(w dns.ResponseWriter, r *dns.Msg) { m := new(dns.Msg) m.SetReply(r) m.Authoritative = true m.Ns = []dns.RR{rrx} w.WriteMsg(m) }) } go func() { err := dns.ListenAndServe(":8053", "tcp", nil) if err != nil { log.Fatal("Failed to set tcp listener %s\n", err.Error()) } }() go func() { err := dns.ListenAndServe(":8053", "udp", nil) if err != nil { log.Fatal("Failed to set udp listener %s\n", err.Error()) } }() sig := make(chan os.Signal) signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM) for { select { case s := <-sig: log.Fatalf("Signal (%d) received, stopping\n", s) } } }
func makeTruncatedReply(r *dns.Msg) *dns.Msg { // for truncated response, we create a minimal reply with the Truncated bit set reply := new(dns.Msg) reply.SetReply(r) reply.Truncated = true return reply }
// 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) }
func makeDNSFailResponse(r *dns.Msg) *dns.Msg { m := new(dns.Msg) m.SetReply(r) m.RecursionAvailable = true m.Rcode = dns.RcodeNameError return m }
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 }
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 }