func updateDns(ethereum *eth.Ethereum) { stateObject := ethereum.StateManager().CurrentState().GetStateObject(dnsreg) if stateObject != nil { ethutil.Config.Log.Debugln("Updating DNS") stateObject.State().EachStorage(func(name string, value *ethutil.Value) { val := value.Bytes()[1:] name = sanitizeString(name) + ".eth." dns.HandleRemove(name) zoneString := fmt.Sprintf("%s 2044 IN A %s", name, val) zone := NewRR(zoneString) if zone != nil { ethutil.Config.Log.Debugln("[DNS] Updated zone:", zone) dns.HandleFunc(name, func(w dns.ResponseWriter, r *dns.Msg) { switch r.Question[0].Qtype { case dns.TypeA: m := new(dns.Msg) m.SetReply(r) m.Answer = []dns.RR{zone} m.RecursionAvailable = true w.WriteMsg(m) default: ethutil.Config.Log.Debugln("[DNS] Type not supported yet") } }) } else { ethutil.Config.Log.Debugln("Invalid zone", zoneString) } }) } }
func makeDNSFailResponse(r *dns.Msg) *dns.Msg { m := new(dns.Msg) m.SetReply(r) m.RecursionAvailable = true m.Rcode = dns.RcodeNameError return 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) } } }
// 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 makeReply(r *dns.Msg, as []dns.RR) *dns.Msg { m := new(dns.Msg) m.SetReply(r) m.RecursionAvailable = true m.Answer = as return 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 (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) } }
// 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 }
// 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 *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) }
// DNS requests go to this function func dnsHandle(w dns.ResponseWriter, r *dns.Msg) { name := r.Question[0].Name if !namePattern.MatchString(name) { kilog.Debug("%v does not match pattern, forwarding", name) dnsForward(w, r) return } // otherwise kilog.Debug("%v matches pattern, handling", name) dnsLock.Lock() defer dnsLock.Unlock() // check in table first fakeIP, ok := nameToIP[name] if !ok { // place in table var nwIP string for { haha := ipAlloc().String() _, exists := ipToName[haha] if exists { continue } nwIP = haha break } fakeIP = nwIP nameToIP[name] = fakeIP ipToName[fakeIP] = name // remove in 30 minutes go func() { time.Sleep(time.Minute * 30) dnsLock.Lock() defer dnsLock.Unlock() delete(nameToIP, name) delete(ipToName, fakeIP) }() } // return the fake IP to the user resp := new(dns.A) resp.Hdr.Name = name resp.Hdr.Ttl = 1 // very short resp.Hdr.Class = dns.ClassINET resp.Hdr.Rrtype = dns.TypeA resp.A = net.ParseIP(fakeIP) towrite := new(dns.Msg) towrite.Id = r.Id towrite.RecursionAvailable = true towrite.RecursionDesired = true towrite.Response = true towrite.Question = r.Question towrite.Answer = make([]dns.RR, 1) towrite.Answer[0] = resp w.WriteMsg(towrite) kilog.Debug("returning mapping %v -> %v", name, fakeIP) }
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 (d *DNSServer) errorResponse(r *dns.Msg, code int, w dns.ResponseWriter) { m := dns.Msg{} m.SetReply(r) m.RecursionAvailable = true m.Rcode = code d.ns.debugf("error response: %+v", m) if err := w.WriteMsg(&m); err != nil { d.ns.infof("error responding: %v", err) } }
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 }
// 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) }
// 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) }
// 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) } } }
// 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) }
// toMsg turns i into a message, it tailers to reply to m. func (i *item) toMsg(m *dns.Msg) *dns.Msg { m1 := new(dns.Msg) m1.SetReply(m) m1.Authoritative = i.Authoritative m1.AuthenticatedData = i.AuthenticatedData m1.RecursionAvailable = i.RecursionAvailable m1.Compress = true m1.Answer = i.Answer m1.Ns = i.Ns m1.Extra = i.Extra ttl := int(i.origTtl) - int(time.Now().UTC().Sub(i.stored).Seconds()) if ttl < baseTtl { ttl = baseTtl } setCap(m1, uint32(ttl)) return m1 }
// 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 // Set to false, because I don't know what to do wrt DNSSEC. m.RecursionAvailable = true rmtIP := net.ParseIP(w.RemoteAddr().String()) var err error if m.Answer, err = s.PTRRecords(req.Question[0], rmtIP); err == nil { // TODO(miek): Reverse DNSSEC. We should sign this, but requires a key....and more // Probably not worth the hassle? if err := w.WriteMsg(m); err != nil { logf("failure to return reply %q", err) } return m } // Always forward if not found locally. return s.ServeDNSForward(w, req) }
func (h *Handler) Handle(response dns.ResponseWriter, req *dns.Msg) { h.requestCounter.Inc(1) h.responseTimer.Time(func() { debugMsg("Handling incoming query for domain " + req.Question[0].Name) // Lookup the dns record for the request // This method will add any answers to the message var msg *dns.Msg if h.queryFilterer.ShouldAcceptQuery(req) != true { debugMsg("Query not accepted") h.rejectCounter.Inc(1) msg = new(dns.Msg) msg.SetReply(req) msg.SetRcode(req, dns.RcodeNameError) msg.Authoritative = true msg.RecursionAvailable = false // Add a useful TXT record header := dns.RR_Header{Name: req.Question[0].Name, Class: dns.ClassINET, Rrtype: dns.TypeTXT} msg.Ns = []dns.RR{&dns.TXT{header, []string{"Rejected query based on matched filters"}}} } else { h.acceptCounter.Inc(1) msg = h.resolver.Lookup(req) } if msg != nil { err := response.WriteMsg(msg) if err != nil { debugMsg("Error writing message: ", err) } } debugMsg("Sent response to ", response.RemoteAddr()) }) }
func setCommonFlags(msg *dns.Msg) { msg.RecursionAvailable = true }
// 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] name := strings.ToLower(q.Name) log.Printf("Received DNS Request for %q from %q with type %d", q.Name, w.RemoteAddr(), q.Qtype) if !strings.HasSuffix(name, s.config.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 func() { // Check if we need to do DNSSEC and sign the reply. if s.config.PubKey != nil { if opt := req.IsEdns0(); opt != nil && opt.Do() { s.nsec(m) s.sign(m, opt.UDPSize()) } } w.WriteMsg(m) }() if name == s.config.Domain { switch q.Qtype { case dns.TypeDNSKEY: if s.config.PubKey != nil { m.Answer = append(m.Answer, s.config.PubKey) return } case dns.TypeSOA: m.Answer = []dns.RR{s.SOA()} return } } if q.Qtype == dns.TypeA || q.Qtype == dns.TypeAAAA { records, err := s.AddressRecords(q) if err != nil { m.SetRcode(req, dns.RcodeNameError) m.Ns = []dns.RR{s.SOA()} return } m.Answer = append(m.Answer, records...) } if q.Qtype == dns.TypeSRV || q.Qtype == dns.TypeANY { records, extra, err := s.SRVRecords(q) if err != nil { // NODATA } m.Answer = append(m.Answer, records...) m.Extra = append(m.Extra, extra...) } // FIXME(miek): uh, NXDOMAIN or NODATA? if len(m.Answer) == 0 { // We are authoritative for this name, but it does not exist: NXDOMAIN m.SetRcode(req, dns.RcodeNameError) m.Ns = []dns.RR{s.SOA()} return } if len(m.Answer) == 0 { // Send back a NODATA response m.Ns = []dns.RR{s.SOA()} } }
// ServeDNSForward forwards a request to a nameservers and returns the response. func (s *server) ServeDNSForward(w dns.ResponseWriter, req *dns.Msg) *dns.Msg { StatsForwardCount.Inc(1) promExternalRequestCount.WithLabelValues("recursive").Inc() if s.config.NoRec { m := new(dns.Msg) m.SetReply(req) m.SetRcode(req, dns.RcodeServerFailure) m.Authoritative = false m.RecursionAvailable = false w.WriteMsg(m) return m } if len(s.config.Nameservers) == 0 || dns.CountLabel(req.Question[0].Name) < s.config.Ndots { if s.config.Verbose { if len(s.config.Nameservers) == 0 { logf("can not forward, no nameservers defined") } else { logf("can not forward, name too short (less than %d labels): `%s'", s.config.Ndots, req.Question[0].Name) } } 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 m } tcp := isTCP(w) 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 r.Id = req.Id w.WriteMsg(r) 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(s.config.Nameservers) { try++ nsid = (nsid + 1) % len(s.config.Nameservers) goto Redo } logf("failure to forward request %q", err) m := new(dns.Msg) m.SetReply(req) m.SetRcode(req, dns.RcodeServerFailure) w.WriteMsg(m) return 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) { m := new(dns.Msg) m.SetReply(req) m.Authoritative = true m.RecursionAvailable = true m.Compress = true bufsize := uint16(512) dnssec := false tcp := false start := time.Now() if req.Question[0].Qtype == dns.TypeANY { m.Authoritative = false m.Rcode = dns.RcodeRefused m.RecursionAvailable = false m.RecursionDesired = false m.Compress = false // if write fails don't care w.WriteMsg(m) promErrorCount.WithLabelValues("refused").Inc() return } if o := req.IsEdns0(); o != nil { bufsize = o.UDPSize() dnssec = o.Do() } if bufsize < 512 { bufsize = 512 } // with TCP we can send 64K if tcp = isTCP(w); tcp { bufsize = dns.MaxMsgSize - 1 promRequestCount.WithLabelValues("tcp").Inc() } else { promRequestCount.WithLabelValues("udp").Inc() } StatsRequestCount.Inc(1) if dnssec { StatsDnssecOkCount.Inc(1) promDnssecOkCount.Inc() } defer func() { promCacheSize.WithLabelValues("response").Set(float64(s.rcache.Size())) }() // Check cache first. key := cache.QuestionKey(req.Question[0], dnssec) m1, exp, hit := s.rcache.Search(key) if hit { // Cache hit! \o/ if time.Since(exp) < 0 { m1.Id = m.Id m1.Compress = true m1.Truncated = false if dnssec { // The key for DNS/DNSSEC in cache is different, no // need to do Denial/Sign here. //if s.config.PubKey != nil { //s.Denial(m1) // not needed for cache hits //s.Sign(m1, bufsize) //} } if m1.Len() > int(bufsize) && !tcp { promErrorCount.WithLabelValues("truncated").Inc() m1.Truncated = true } // Still round-robin even with hits from the cache. // Only shuffle A and AAAA records with each other. if req.Question[0].Qtype == dns.TypeA || req.Question[0].Qtype == dns.TypeAAAA { s.RoundRobin(m1.Answer) } if err := w.WriteMsg(m1); err != nil { log.Printf("skydns: failure to return reply %q", err) } metricSizeAndDuration(m1, start, tcp) return } // Expired! /o\ s.rcache.Remove(key) } q := req.Question[0] name := strings.ToLower(q.Name) if s.config.Verbose { log.Printf("skydns: received DNS Request for %q from %q with type %d", q.Name, w.RemoteAddr(), q.Qtype) } for zone, ns := range *s.config.stub { if strings.HasSuffix(name, zone) { resp := s.ServeDNSStubForward(w, req, ns) metricSizeAndDuration(resp, start, tcp) return } } // If the qname is local.dns.skydns.local. and s.config.Local != "", substitute that name. if s.config.Local != "" && name == s.config.localDomain { name = s.config.Local } if q.Qtype == dns.TypePTR && strings.HasSuffix(name, ".in-addr.arpa.") || strings.HasSuffix(name, ".ip6.arpa.") { resp := s.ServeDNSReverse(w, req) metricSizeAndDuration(resp, start, tcp) return } if q.Qclass != dns.ClassCHAOS && !strings.HasSuffix(name, s.config.Domain) { if s.config.Verbose { log.Printf("skydns: %q is not sub of %q, forwarding...", name, s.config.Domain) } resp := s.ServeDNSForward(w, req) metricSizeAndDuration(resp, start, tcp) return } promCacheMiss.WithLabelValues("response").Inc() defer func() { if m.Rcode == dns.RcodeServerFailure { if err := w.WriteMsg(m); err != nil { log.Printf("skydns: failure to return reply %q", err) } return } // Set TTL to the minimum of the RRset and dedup the message, i.e. // remove identical RRs. m = s.dedup(m) minttl := s.config.Ttl if len(m.Answer) > 1 { for _, r := range m.Answer { if r.Header().Ttl < minttl { minttl = r.Header().Ttl } } for _, r := range m.Answer { r.Header().Ttl = minttl } } if !m.Truncated { s.rcache.InsertMessage(cache.QuestionKey(req.Question[0], dnssec), m) } if dnssec { if s.config.PubKey != nil { m.AuthenticatedData = true s.Denial(m) s.Sign(m, bufsize) } } if m.Len() > dns.MaxMsgSize { log.Printf("skydns: overflowing maximum message size: %d, dropping additional section", m.Len()) m.Extra = nil // Drop entire additional section to see if this helps. if m.Len() > dns.MaxMsgSize { // *Still* too large. log.Printf("skydns: still overflowing maximum message size: %d", m.Len()) promErrorCount.WithLabelValues("overflow").Inc() m1 := new(dns.Msg) // Use smaller msg to signal failure. m1.SetRcode(m, dns.RcodeServerFailure) if err := w.WriteMsg(m1); err != nil { log.Printf("skydns: failure to return reply %q", err) } metricSizeAndDuration(m1, start, tcp) return } } if m.Len() > int(bufsize) && !tcp { m.Extra = nil // As above, drop entire additional section. if m.Len() > int(bufsize) { promErrorCount.WithLabelValues("truncated").Inc() m.Truncated = true } } if err := w.WriteMsg(m); err != nil { log.Printf("skydns: failure to return reply %q %d", err, m.Len()) } metricSizeAndDuration(m, start, tcp) }() if name == s.config.Domain { if q.Qtype == dns.TypeSOA { m.Answer = []dns.RR{s.NewSOA()} return } if q.Qtype == dns.TypeDNSKEY { if s.config.PubKey != nil { m.Answer = []dns.RR{s.config.PubKey} return } } } if q.Qclass == dns.ClassCHAOS { if q.Qtype == dns.TypeTXT { switch name { case "authors.bind.": fallthrough case s.config.Domain: hdr := dns.RR_Header{Name: q.Name, Rrtype: dns.TypeTXT, Class: dns.ClassCHAOS, Ttl: 0} authors := []string{"Erik St. Martin", "Brian Ketelsen", "Miek Gieben", "Michael Crosby"} for _, a := range authors { m.Answer = append(m.Answer, &dns.TXT{Hdr: hdr, Txt: []string{a}}) } for j := 0; j < len(authors)*(int(dns.Id())%4+1); j++ { q := int(dns.Id()) % len(authors) p := int(dns.Id()) % len(authors) if q == p { p = (p + 1) % len(authors) } m.Answer[q], m.Answer[p] = m.Answer[p], m.Answer[q] } return case "version.bind.": fallthrough case "version.server.": hdr := dns.RR_Header{Name: q.Name, Rrtype: dns.TypeTXT, Class: dns.ClassCHAOS, Ttl: 0} m.Answer = []dns.RR{&dns.TXT{Hdr: hdr, Txt: []string{Version}}} return case "hostname.bind.": fallthrough case "id.server.": // TODO(miek): machine name to return hdr := dns.RR_Header{Name: q.Name, Rrtype: dns.TypeTXT, Class: dns.ClassCHAOS, Ttl: 0} m.Answer = []dns.RR{&dns.TXT{Hdr: hdr, Txt: []string{"localhost"}}} return } } // still here, fail m.SetReply(req) m.SetRcode(req, dns.RcodeServerFailure) return } switch q.Qtype { case dns.TypeNS: if name != s.config.Domain { log.Printf("skydns: %q unmatch default domain", name) break } // Lookup s.config.DnsDomain records, extra, err := s.NSRecords(q, s.config.dnsDomain) if err != nil { if e, ok := err.(*etcd.EtcdError); ok { if e.ErrorCode == 100 { s.NameError(m, req) return } } } m.Answer = append(m.Answer, records...) m.Extra = append(m.Extra, extra...) case dns.TypeA, dns.TypeAAAA: records, err := s.AddressRecords(q, name, nil, bufsize, dnssec, false) if err != nil { if e, ok := err.(*etcd.EtcdError); ok { if e.ErrorCode == 100 { s.NameError(m, req) return } } } m.Answer = append(m.Answer, records...) case dns.TypeTXT: records, err := s.TXTRecords(q, name) if err != nil { if e, ok := err.(*etcd.EtcdError); ok { if e.ErrorCode == 100 { s.NameError(m, req) return } } } m.Answer = append(m.Answer, records...) case dns.TypeCNAME: records, err := s.CNAMERecords(q, name) if err != nil { if e, ok := err.(*etcd.EtcdError); ok { if e.ErrorCode == 100 { s.NameError(m, req) return } } } m.Answer = append(m.Answer, records...) case dns.TypeMX: records, extra, err := s.MXRecords(q, name, bufsize, dnssec) if err != nil { if e, ok := err.(*etcd.EtcdError); ok { if e.ErrorCode == 100 { s.NameError(m, req) return } } } m.Answer = append(m.Answer, records...) m.Extra = append(m.Extra, extra...) default: fallthrough // also catch other types, so that they return NODATA case dns.TypeSRV: records, extra, err := s.SRVRecords(q, name, bufsize, dnssec) if err != nil { if e, ok := err.(*etcd.EtcdError); ok { if e.ErrorCode == 100 { s.NameError(m, req) return } } if q.Qtype == dns.TypeSRV { // Otherwise NODATA s.ServerFailure(m, req) return } } // if we are here again, check the types, because an answer may only // be given for SRV. All other types should return NODATA, the // NXDOMAIN part is handled in the above code. TODO(miek): yes this // can be done in a more elegant manor. if q.Qtype == dns.TypeSRV { m.Answer = append(m.Answer, records...) m.Extra = append(m.Extra, extra...) } } if len(m.Answer) == 0 { // NODATA response StatsNoDataCount.Inc(1) m.Ns = []dns.RR{s.NewSOA()} m.Ns[0].Header().Ttl = s.config.MinTtl } }