// 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 }
// 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) }
// 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) } }
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) }
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 (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) } }
// 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 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) } } }
// 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) } } }
// 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) } }
func prepareFailureMsg(req *dns.Msg) *dns.Msg { failMsg := new(dns.Msg) failMsg.Id = req.Id failMsg.Response = true failMsg.Authoritative = true failMsg.Question = req.Question failMsg.Rcode = dns.RcodeNameError return failMsg }
func (ds *DNSServer) ServeDNS(rw dns.ResponseWriter, mes *dns.Msg) { resp := new(dns.Msg) for _, q := range mes.Question { log.Printf("DNS request from %s: %s", rw.RemoteAddr(), &q) switch q.Qtype { case dns.TypeA, dns.TypeAAAA: val, err := ds.HandleLookup(q.Name) if err != nil { log.Println(err) continue } if q.Qclass != dns.ClassINET { log.Printf("error: got invalid DNS question class %d\n", q.Qclass) continue } header := dns.RR_Header{ Name: q.Name, Rrtype: q.Qtype, Class: dns.ClassINET, Ttl: DefaultResponseTTL, } var rr dns.RR // not really super sure why these have to be different types if q.Qtype == dns.TypeA { rr = &dns.A{ A: net.ParseIP(val), Hdr: header, } } else if q.Qtype == dns.TypeAAAA { rr = &dns.AAAA{ AAAA: net.ParseIP(val), Hdr: header, } } else { panic("unreachable") } resp.Answer = append(resp.Answer, rr) default: log.Printf("unhandled qtype: %d\n", q.Qtype) } } resp.Authoritative = true resp.Id = mes.Id resp.Response = true if err := rw.WriteMsg(resp); err != nil { log.Printf("error responding to DNS query: %s", err) } }
func cacheMsg(m *dns.Msg, tc cacheTestCase) *dns.Msg { m.RecursionAvailable = tc.RecursionAvailable m.AuthenticatedData = tc.AuthenticatedData m.Authoritative = tc.Authoritative m.Truncated = tc.Truncated m.Answer = tc.in.Answer m.Ns = tc.in.Ns // m.Extra = tc.in.Extra , not the OPT record! return m }
func prepareAnswerMsg(req *dns.Msg, answers []dns.RR) *dns.Msg { answerMsg := new(dns.Msg) answerMsg.Id = req.Id answerMsg.Response = true answerMsg.Authoritative = true answerMsg.Question = req.Question answerMsg.Answer = answers answerMsg.Rcode = dns.RcodeSuccess answerMsg.Extra = []dns.RR{} return answerMsg }
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 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 (s *Service) handle(w dns.ResponseWriter, r *dns.Msg) { reply := new(dns.Msg) reply.SetReply(r) reply.Authoritative = true for _, q := range r.Question { answers := s.answer(q) if len(answers) > 0 { reply.Answer = append(reply.Answer, answers...) } else { reply.Ns = append(reply.Ns, s.soa(q)) } } w.WriteMsg(reply) }
// 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 (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) }) }
// 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 }
// ServeDNSReverse is the handler for DNS requests for the reverse zone. If nothing is found // locally the request is forwarded to the forwarder for resolution. func (s *server) ServeDNSReverse(w dns.ResponseWriter, req *dns.Msg) *dns.Msg { m := new(dns.Msg) m.SetReply(req) m.Compress = true m.Authoritative = false m.RecursionAvailable = true if records, err := s.PTRRecords(req.Question[0]); err == nil && len(records) > 0 { m.Answer = records writeMsg(w, m) return m } // Always forward if not found locally. return s.ServeDNSForward(w, req) }
// ServeDNSReverse is the handler for DNS requests for the reverse zone. If nothing is found // locally the request is forwarded to the forwarder for resolution. func (s *server) ServeDNSReverse(w dns.ResponseWriter, req *dns.Msg) { m := new(dns.Msg) m.SetReply(req) m.Authoritative = false // Set to false, because I don't know what to do wrt DNSSEC. m.RecursionAvailable = true var err error if m.Answer, err = s.PTRRecords(req.Question[0]); err == nil { // TODO(miek): Reverse DNSSEC. We should sign this, but requires a key....and more // Probably not worth the hassle? w.WriteMsg(m) } // Always forward if not found locally. s.ServeDNSForward(w, req) }
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()) } }
// 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 (d *DNSServer) handleReverse(client *dns.Client, defaultMaxResponseSize int) func(dns.ResponseWriter, *dns.Msg) { return func(w dns.ResponseWriter, req *dns.Msg) { d.ns.debugf("reverse request: %+v", *req) if len(req.Question) != 1 || req.Question[0].Qtype != dns.TypePTR { d.errorResponse(req, dns.RcodeNameError, w) return } ipStr := strings.TrimSuffix(req.Question[0].Name, "."+reverseDNSdomain) ip, err := address.ParseIP(ipStr) if err != nil { d.errorResponse(req, dns.RcodeNameError, w) return } hostname, err := d.ns.ReverseLookup(ip.Reverse()) if err != nil { d.handleRecursive(client, defaultMaxResponseSize)(w, req) return } response := dns.Msg{} response.RecursionAvailable = true response.Authoritative = true response.SetReply(req) header := dns.RR_Header{ Name: req.Question[0].Name, Rrtype: dns.TypePTR, Class: dns.ClassINET, Ttl: d.ttl, } response.Answer = []dns.RR{&dns.PTR{ Hdr: header, Ptr: hostname, }} maxResponseSize := getMaxResponseSize(req, defaultMaxResponseSize) truncateResponse(&response, maxResponseSize) d.ns.debugf("response: %+v", response) if err := w.WriteMsg(&response); err != nil { d.ns.infof("error responding: %v", err) } } }
func (d *DNSServer) handleLocal(defaultMaxResponseSize int) func(dns.ResponseWriter, *dns.Msg) { return func(w dns.ResponseWriter, req *dns.Msg) { d.ns.debugf("local request: %+v", *req) if len(req.Question) != 1 || req.Question[0].Qtype != dns.TypeA { d.errorResponse(req, dns.RcodeNameError, w) return } hostname := dns.Fqdn(req.Question[0].Name) if strings.Count(hostname, ".") == 1 { hostname = hostname + d.domain } addrs := d.ns.Lookup(hostname) if len(addrs) == 0 { d.errorResponse(req, dns.RcodeNameError, w) return } response := dns.Msg{} response.RecursionAvailable = true response.Authoritative = true response.SetReply(req) response.Answer = make([]dns.RR, len(addrs)) header := dns.RR_Header{ Name: req.Question[0].Name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: d.ttl, } for i, addr := range addrs { ip := addr.IP4() response.Answer[i] = &dns.A{Hdr: header, A: ip} } shuffleAnswers(&response.Answer) maxResponseSize := getMaxResponseSize(req, defaultMaxResponseSize) truncateResponse(&response, maxResponseSize) d.ns.debugf("response: %+v", response) if err := w.WriteMsg(&response); err != nil { d.ns.infof("error responding: %v", err) } } }
func (s *Server) do(Net string, w dns.ResponseWriter, req *dns.Msg) { if len(req.Question) != 1 { dns.HandleFailed(w, req) return } zone, name := s.zones.match(req.Question[0].Name, req.Question[0].Qtype) if zone == nil { s.recurse(w, req) return } s.zones.Lock() defer s.zones.Unlock() m := new(dns.Msg) m.SetReply(req) var answerKnown bool dnsreq := dns.RR_Header{Name: req.Question[0].Name, Rrtype: req.Question[0].Qtype, Class: req.Question[0].Qclass} for _, r := range (*zone)[dnsreq] { m.Answer = append(m.Answer, r) answerKnown = true } // TODO: more logs here s.roundRobin(zone, dnsreq) if !answerKnown && s.recurseTo != "" { s.recurse(w, req) return } // Add Authority section for _, r := range (*zone)[dns.RR_Header{Name: name, Rrtype: dns.TypeNS, Class: dns.ClassINET}] { m.Ns = append(m.Ns, r) // Resolve Authority if possible and serve as Extra for _, r := range (*zone)[dns.RR_Header{Name: r.(*dns.NS).Ns, Rrtype: dns.TypeA, Class: dns.ClassINET}] { m.Extra = append(m.Extra, r) } for _, r := range (*zone)[dns.RR_Header{Name: r.(*dns.NS).Ns, Rrtype: dns.TypeAAAA, Class: dns.ClassINET}] { m.Extra = append(m.Extra, r) } } m.Authoritative = true w.WriteMsg(m) }
func main() { cpuprofile := flag.String("cpuprofile", "", "write cpu profile to file") // ratelimit := flag.Bool("ratelimit", false, "ratelimit responses using RRL") port := flag.Int("port", 8053, "port to run on") flag.Parse() if *cpuprofile != "" { f, err := os.Create(*cpuprofile) if err != nil { log.Fatal(err) } pprof.StartCPUProfile(f) defer pprof.StopCPUProfile() } 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() { srv := &dns.Server{Addr: ":" + strconv.Itoa(*port), Net: "udp"} err := srv.ListenAndServe() if err != nil { log.Fatal("Failed to set udp listener %s\n", err.Error()) } }() go func() { srv := &dns.Server{Addr: ":" + strconv.Itoa(*port), Net: "tcp"} err := srv.ListenAndServe() if err != nil { log.Fatal("Failed to set tcp 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 (self *TrivialDnsServer) respondSuccessively(w dns.ResponseWriter, r *dns.Msg, addr net.IP) { q := self.getSingleSimpleQuestion(r) a := &dns.A{ Hdr: dns.RR_Header{ Name: q.Name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 30, Rdlength: 4, }, A: addr, } m := new(dns.Msg) m.SetReply(r) m.Answer = []dns.RR{a} m.Authoritative = false w.WriteMsg(m) }
// ServeDNSForward forwards a request to a nameservers and returns the response. func (s *server) ServeDNSForward(w dns.ResponseWriter, req *dns.Msg) { if len(s.config.Nameservers) == 0 { log.Printf("error: Failure to Forward DNS Request, no servers configured %q", dns.ErrServ) 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 } network := "udp" if _, ok := w.RemoteAddr().(*net.TCPAddr); ok { network = "tcp" } c := &dns.Client{Net: network, ReadTimeout: s.config.ReadTimeout} // Use request Id for "random" nameserver selection nsid := int(req.Id) % len(s.config.Nameservers) try := 0 Redo: r, _, err := c.Exchange(req, s.config.Nameservers[nsid]) if err == nil { log.Printf("Forwarded DNS Request %q to %q", req.Question[0].Name, s.config.Nameservers[nsid]) 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) { log.Printf("error: Failure to Forward DNS Request %q to %q", err, s.config.Nameservers[nsid]) try++ nsid = (nsid + 1) % len(s.config.Nameservers) goto Redo } log.Printf("error: Failure to Forward DNS Request %q", err) m := new(dns.Msg) m.SetReply(req) m.SetRcode(req, dns.RcodeServerFailure) w.WriteMsg(m) }