// 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) } }
// 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) } }
// ServeDNS resolution. func (h *RandomUpstream) ServeDNS(w dns.ResponseWriter, r *dns.Msg) { ns := h.upstream[rand.Intn(len(h.upstream))] ns = defaultPort(ns) for _, q := range r.Question { log.Printf("[info] [%v] <== %s %s %v (ns %s)\n", r.Id, dns.ClassToString[q.Qclass], dns.TypeToString[q.Qtype], q.Name, ns) } client := &dns.Client{ Net: w.RemoteAddr().Network(), } res, rtt, err := client.Exchange(r, ns) if err != nil { msg := new(dns.Msg) msg.SetRcode(r, dns.RcodeServerFailure) w.WriteMsg(msg) return } log.Printf("[info] [%v] ==> %s:", r.Id, rtt) for _, a := range res.Answer { log.Printf("[info] [%v] ----> %s\n", r.Id, a) } err = w.WriteMsg(res) if err != nil { log.Printf("[error] [%v] failed to respond – %s", r.Id, err) } }
func (self *TrivialDnsServer) redirectQuery(w dns.ResponseWriter, r *dns.Msg, newName string) { self.Count("redirected_requests") if !strings.HasSuffix(newName, ".") { newName = newName + "." } newR := new(dns.Msg) newR.SetQuestion(dns.Fqdn(newName), dns.TypeA) if response, _, err := self.exchangeWithUpstream(newR); err == nil { ip := self.getSingleSimpleAnswer(response) if ip == nil { debug("%s redirect to %s yielded no answer", w.RemoteAddr(), newName) self.Count("redirected_nowhere") self.refuse(w, r) return } self.Count("redirected_successively") self.respondSuccessively(w, r, *ip) } else { self.Count("upstream_errors") self.refuse(w, r) log.Printf("%s: error: %s", w.RemoteAddr(), err) } }
func (h ENUMHandler) ServeDNS(writer dns.ResponseWriter, request *dns.Msg) { defer func(s time.Time) { h.Trace.Printf("dns request for %v (%s) (%v) from client %s (%s)", request.Question[0], "udp", time.Now().Sub(s), writer.RemoteAddr().String(), writer.RemoteAddr().Network()) }(time.Now()) if answer, err := h.createAnswer(request); err == nil { if answer == nil { h.Trace.Printf("no result found for %s", request.Question[0]) notfound := &dns.Msg{} notfound.SetReply(request) notfound.SetRcode(request, dns.RcodeSuccess) writer.WriteMsg(notfound) return } if err := writer.WriteMsg(answer); err != nil { h.Error.Printf("error sending answer: %v", err) } } else { h.Error.Printf("[ERR] Error getting the answer: %v", err) error := &dns.Msg{} error.SetReply(request) error.SetRcode(request, dns.RcodeServerFailure) writer.WriteMsg(error) } }
func ( p Proxy ) ServeDNS (w dns.ResponseWriter, r *dns.Msg) { c := dns.NewClient () c.Net = PROTO if TCP_REGEX != nil { for _, q := range r.Question { if TCP_REGEX.MatchString (q.Name) { LOG.Printf ("Tcp proto regex match: %s", q.Name) c.Net = "tcp" break } } } c.ReadTimeout = TIMEOUT c.WriteTimeout = TIMEOUT if rs, err := c.Exchange (r, p.Server()); err == nil { if DEBUG { LOG.Printf ("DEBUG %s\n%v", w.RemoteAddr(), rs) } w.Write (rs) } else { dns.Refused (w, r) LOG.Printf ("%s %s", w.RemoteAddr(), err) } }
func proxy(addr string, w dns.ResponseWriter, req *dns.Msg) { transport := "udp" if _, ok := w.RemoteAddr().(*net.TCPAddr); ok { transport = "tcp" } if isTransfer(req) { if transport != "tcp" { dns.HandleFailed(w, req) return } t := new(dns.Transfer) c, err := t.In(req, addr) if err != nil { dns.HandleFailed(w, req) return } if err = t.Out(w, req, c); err != nil { dns.HandleFailed(w, req) return } return } c := &dns.Client{Net: transport} resp, _, err := c.Exchange(req, addr) if err != nil { dns.HandleFailed(w, req) return } w.WriteMsg(resp) }
// handleRecurse is used to handle recursive DNS queries func (d *DNSServer) handleRecurse(resp dns.ResponseWriter, req *dns.Msg) { q := req.Question[0] network := "udp" defer func(s time.Time) { d.logger.Printf("[DEBUG] dns: request for %v (%s) (%v)", q, network, time.Now().Sub(s)) }(time.Now()) // Switch to TCP if the client is if _, ok := resp.RemoteAddr().(*net.TCPAddr); ok { network = "tcp" } // Recursively resolve c := &dns.Client{Net: network} r, rtt, err := c.Exchange(req, d.recursor) // On failure, return a SERVFAIL message if err != nil { d.logger.Printf("[ERR] dns: recurse failed: %v", err) m := &dns.Msg{} m.SetReply(req) m.RecursionAvailable = true m.SetRcode(req, dns.RcodeServerFailure) resp.WriteMsg(m) return } d.logger.Printf("[DEBUG] dns: recurse RTT for %v (%v)", q, rtt) // Forward the response if err := resp.WriteMsg(r); err != nil { d.logger.Printf("[WARN] dns: failed to respond: %v", err) } }
func (s *DNS) handleDNSExternal(w dns.ResponseWriter, req *dns.Msg) { network := "udp" if _, ok := w.RemoteAddr().(*net.TCPAddr); ok { network = "tcp" } c := &dns.Client{Net: network} var r *dns.Msg var err error for _, recursor := range s.recursors { if recursor == "" { log.Printf("Found empty recursor") continue } log.Printf("Forwarding request to external recursor for: %s", req.Question[0].Name) r, _, err = c.Exchange(req, recursor) if err == nil { if err := w.WriteMsg(r); err != nil { log.Printf("DNS lookup failed %v", err) } return } } dns.HandleFailed(w, req) }
// Forwards a DNS request to the specified nameservers. On success, the // original reply packet will be returned to the caller. On failure, a // new packet will be returned with `RCODE` set to `SERVFAIL`. // 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 getServerReply(w dns.ResponseWriter, req *dns.Msg) *dns.Msg { if *verbose { log.Print("Forwarding ", req.Question[0].Name, "/", dns.Type(req.Question[0].Qtype).String()) } // create a new DNS client client := &dns.Client{Net: "udp", ReadTimeout: 4 * time.Second, WriteTimeout: 4 * time.Second, SingleInflight: true} if _, tcp := w.RemoteAddr().(*net.TCPAddr); tcp { client.Net = "tcp" } var r *dns.Msg var err error // loop through the specified nameservers and forward them the request // the request ID is used as a starting point in order to introduce at least // some element of randomness, instead of always hitting the first nameserver for i := 0; i < len(nameservers); i++ { r, _, err = client.Exchange(req, nameservers[(int(req.Id)+i)%len(nameservers)]) if err == nil { r.Compress = true return r } } log.Print("Failed to forward request.", err) return getEmptyMsg(w, req, dns.RcodeServerFailure) }
func (h *Handler) handle(proto string, w dns.ResponseWriter, r *dns.Msg) { ques := question.NewQuestion(r.Question[0]) subnet := "" if ip, ok := w.RemoteAddr().(*net.UDPAddr); ok { subnet = networks.Find(ip.IP) } if ip, ok := w.RemoteAddr().(*net.TCPAddr); ok { subnet = networks.Find(ip.IP) } if subnet == "" { dns.HandleFailed(w, r) return } if ques.IsIpQuery && ques.TopDomain == "vpn" { msg, err := h.reslvr.LookupUser(proto, ques, subnet, r) if err != nil { dns.HandleFailed(w, r) return } w.WriteMsg(msg) } else { servers := database.DnsServers[subnet] res, err := h.reslvr.Lookup(proto, servers, r) if err != nil { dns.HandleFailed(w, r) return } w.WriteMsg(res) } }
// Proto gets the protocol used as the transport. This will be udp or tcp. func Proto(w dns.ResponseWriter) string { if _, ok := w.RemoteAddr().(*net.UDPAddr); ok { return "udp" } if _, ok := w.RemoteAddr().(*net.TCPAddr); ok { return "tcp" } return "udp" }
func handleRequest(w dns.ResponseWriter, r *dns.Msg) { kv := llog.KV{} // Can be nil during testing if raddr := w.RemoteAddr(); raddr != nil { kv["srcAddr"] = raddr.String() } if err := validateRequest(r); err != nil { kv["err"] = err llog.Warn("invalid request", kv) sendFormatError(w, r) return } start := time.Now() kv["question"] = r.Question[0].Name kv["questionType"] = r.Question[0].Qtype llog.Info("handling request", kv) rr := NewReq{r, make(chan *dns.Msg)} newCh <- rr m := <-rr.ReplyCh kv["ms"] = int64(time.Since(start).Nanoseconds() / 1e6) if m == nil { llog.Warn("error handling request", kv) dns.HandleFailed(w, r) return } //we need to make sure the sent ID matches the replied one //it might be different if we combined in-flight messages //copy the struct so we don't affect anything else handling this m2 := *m m2.Id = r.Id m = &m2 //we always want to compress since there's no downsides afaik m.Compress = true kv["rcode"], _ = dns.RcodeToString[m.Rcode] if len(m.Answer) > 0 { kv["answer"] = m.Answer[0] kv["answerCnt"] = len(m.Answer) } kv["len"] = m.Len() llog.Info("responding to request", kv) err := w.WriteMsg(m) if err != nil { kv["err"] = err llog.Warn("error writing response", kv) //no need to handle HandleFailed here because we cannot write } }
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) } }
// HandleNonMesos handles non-mesos queries by forwarding to configured // external DNS servers. func (res *Resolver) HandleNonMesos(w dns.ResponseWriter, r *dns.Msg) { logging.CurLog.NonMesosRequests.Inc() m, err := res.fwd(r, w.RemoteAddr().Network()) if err != nil { m = new(dns.Msg).SetRcode(r, rcode(err)) } else if len(m.Answer) == 0 { logging.CurLog.NonMesosNXDomain.Inc() } reply(w, m) }
func sendTruncated(w dns.ResponseWriter, msgHdr dns.MsgHdr) { emptyResp := new(dns.Msg) emptyResp.MsgHdr = msgHdr emptyResp.Response = true if _, isTCP := w.RemoteAddr().(*net.TCPAddr); isTCP { dns.HandleFailed(w, emptyResp) return } emptyResp.Truncated = true w.WriteMsg(emptyResp) }
func debug_request(request dns.Msg, question dns.Question, writer dns.ResponseWriter) string { addr := writer.RemoteAddr().String() // ipaddr string s := []string{} // TODO: put tcp/udp in here s = append(s, fmt.Sprintf("Received request from %s ", addr)) s = append(s, fmt.Sprintf("for %s ", question.Name)) s = append(s, fmt.Sprintf("opcode: %d ", request.Opcode)) s = append(s, fmt.Sprintf("rrtype: %d ", question.Qtype)) s = append(s, fmt.Sprintf("rrclass: %d ", question.Qclass)) return strings.Join(s, "") }
// HandleForwarding forwards a request to the nameservers and returns the response func (s *Server) HandleForwarding(w mdns.ResponseWriter, r *mdns.Msg) (bool, error) { defer trace.End(trace.Begin(r.String())) var m *mdns.Msg var err error var try int if len(s.Nameservers) == 0 { log.Errorf("No nameservers defined, can not forward") return false, respServerFailure(w, r) } // which protocol are they talking tcp := false if _, ok := w.RemoteAddr().(*net.TCPAddr); ok { tcp = true } // Use request ID for "random" nameserver selection. nsid := int(r.Id) % len(s.Nameservers) Redo: nameserver := s.Nameservers[nsid] if i := strings.Index(nameserver, ":"); i < 0 { nameserver += ":53" } if tcp { m, _, err = s.tcpclient.Exchange(r, nameserver) } else { m, _, err = s.udpclient.Exchange(r, nameserver) } if err != nil { // 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.Nameservers) { try++ nsid = (nsid + 1) % len(s.Nameservers) goto Redo } log.Errorf("Failure to forward request: %q", err) return false, respServerFailure(w, r) } // We have a response so cache it s.cache.Add(m) m.Compress = true if err := w.WriteMsg(m); err != nil { log.Errorf("Error writing response: %q", err) return true, err } return true, nil }
func allowed(w dns.ResponseWriter, req *dns.Msg) bool { if !isTransfer(req) { return true } remote := extractHost(w.RemoteAddr().String()) for _, ip := range transferIPs { if ip == remote { return true } } return false }
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 (self *TrivialDnsServer) proxyToUpstream(w dns.ResponseWriter, r *dns.Msg) { self.Count("proxied_requests") if response, _, err := self.exchangeWithUpstream(r); err == nil { if len(response.Answer) == 0 { self.Count("proxied_refusals") } w.WriteMsg(response) } else { self.Count("upstream_errors") self.refuse(w, r) log.Printf("%s: error: %s", w.RemoteAddr(), err) } }
func Handle(writer dns.ResponseWriter, request *dns.Msg) { question := request.Question[0] message := new(dns.Msg) message.SetReply(request) message.SetRcode(message, dns.RcodeSuccess) full_address := writer.RemoteAddr().String() address := strings.Split(full_address, ":")[0] if allowed(address) != true { msg := fmt.Sprintf("ERROR %s : %s not allowed to talk to slappy", question.Name, address) logger.Error(msg) message = handle_error(message, writer, "REFUSED") respond(message, question, *request, writer) return } logger.Debug(debug_request(*request, question, writer)) go Stat("query") switch request.Opcode { case dns.OpcodeNotify: message = handle_notify(question, message, writer) case CC: if question.Qclass == ClassCC { switch question.Qtype { case CREATE: message = handle_create(question, message, writer) case DELETE: message = handle_delete(question, message, writer) default: message = handle_error(message, writer, "REFUSED") } } else { logger.Debug(fmt.Sprintf("ERROR %s : unsupported rrclass %d", question.Name, question.Qclass)) message = handle_error(message, writer, "REFUSED") } default: if question.Name == conf.Stats_uri { message = Stats_dns_message(message, writer) logger.Debug("SUCCESS STATS : Sent runtime stats") break } logger.Debug(fmt.Sprintf("ERROR %s : unsupported opcode %d", question.Name, request.Opcode)) message = handle_error(message, writer, "REFUSED") } respond(message, question, *request, writer) }
// 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) }
// makes non-mesos queries to external nameserver func (res *Resolver) HandleNonMesos(w dns.ResponseWriter, r *dns.Msg) { var err error var m *dns.Msg // tracing info logging.CurLog.NonMesosRequests.Inc() // If external request are disabled if !res.config.ExternalOn { m = new(dns.Msg) // set refused m.SetRcode(r, 5) } else { proto := "udp" if _, ok := w.RemoteAddr().(*net.TCPAddr); ok { proto = "tcp" } for _, resolver := range res.config.Resolvers { nameserver := net.JoinHostPort(resolver, "53") m, err = res.extResolver(r, nameserver, proto, recurseCnt) if err == nil { break } } } // extResolver returns nil Msg sometimes cause of perf if m == nil { m = new(dns.Msg) m.SetRcode(r, 2) err = errors.New("nil msg") } if err != nil { logging.Error.Println(r.Question[0].Name) logging.Error.Println(err) logging.CurLog.NonMesosFailed.Inc() } else { // nxdomain if len(m.Answer) == 0 { logging.CurLog.NonMesosNXDomain.Inc() } else { logging.CurLog.NonMesosSuccess.Inc() } } reply(w, m) }
// ServeDNS is the handler for DNS requests, responsible for parsing DNS request, possibly forwarding // it to a real dns server and returning a response. func (s *Server) ServeDNS(w dns.ResponseWriter, req *dns.Msg) { stats.RequestCount.Inc(1) q := req.Question[0] log.Printf("Received DNS Request for %q from %q", q.Name, w.RemoteAddr()) // If the query does not fall in our s.domain, forward it if !strings.HasSuffix(q.Name, dns.Fqdn(s.domain)) { s.ServeDNSForward(w, req) return } m := new(dns.Msg) m.SetReply(req) m.Authoritative = true m.RecursionAvailable = true m.Answer = make([]dns.RR, 0, 10) defer w.WriteMsg(m) if q.Qtype == dns.TypeANY || q.Qtype == dns.TypeSRV { records, extra, err := s.getSRVRecords(q) if err != nil { // We are authoritative for this name, but it does not exist: NXDOMAIN m.SetRcode(req, dns.RcodeNameError) m.Ns = s.createSOA() log.Println("Error: ", err) return } m.Answer = append(m.Answer, records...) m.Extra = append(m.Extra, extra...) } if q.Qtype == dns.TypeA || q.Qtype == dns.TypeAAAA { records, err := s.getARecords(q) if err != nil { m.SetRcode(req, dns.RcodeNameError) m.Ns = s.createSOA() log.Println("Error: ", err) return } m.Answer = append(m.Answer, records...) } if len(m.Answer) == 0 { // Send back a NODATA response m.Ns = s.createSOA() } }
// our ServeDNS interface, which gets invoked on every DNS message func (this ServerProxy) ServeDNS(w dns.ResponseWriter, request *dns.Msg) { // see if we have our groovy custom EDNS0 option client_supports_appfrag := false opt := request.IsEdns0() if opt != nil { for ofs, e := range opt.Option { if e.Option() == dns.EDNS0LOCALSTART { _D("%s QID:%d found EDNS0LOCALSTART", w.RemoteAddr(), request.Id) client_supports_appfrag = true // go ahead and use the maximum UDP size for the local communication // with our server opt.SetUDPSize(65535) // remove the fragmentation option opt.Option = append(opt.Option[0:ofs], opt.Option[ofs+1:]...) // in principle we should only have one of these options break } } } // proxy the query c := new(dns.Client) c.ReadTimeout = this.timeout c.WriteTimeout = this.timeout response, rtt, err := c.Exchange(request, this.SERVERS[rand.Intn(this.s_len)]) if err != nil { _D("%s QID:%d error proxying query: %s", w.RemoteAddr(), request.Id, err) this.SRVFAIL(w, request) return } _D("%s QID:%d request took %s", w.RemoteAddr(), request.Id, rtt) // if the client does not support fragmentation, we just send the response back and finish if !client_supports_appfrag { _D("%s QID:%d sending raw response to client", w.RemoteAddr(), request.Id) w.WriteMsg(response) return } // otherwise lets get our fragments all_frags := frag(response) // send our fragments for n, frag := range all_frags { _D("%s QID:%d sending fragment %d", w.RemoteAddr(), request.Id, n) w.WriteMsg(&frag) } }
func (self *TrivialDnsServer) ServeDNS(w dns.ResponseWriter, r *dns.Msg) { defer func() { if err := recover(); err != nil { runtime_debug.PrintStack() log.Printf("PANIC: %s", err) self.refuseOnPanic(w, r) } }() log.Printf("INFO: QUERY, remote_addr=%v query=%v\n", w.RemoteAddr(), r.Question[0].Name) self.Count("requests") if self.tryAnswer(w, r) { return } self.proxyToUpstream(w, r) }
// handleRecurse is used to handle recursive DNS queries func (d *DNSServer) handleRecurse(resp dns.ResponseWriter, req *dns.Msg) { q := req.Question[0] network := "udp" defer func(s time.Time) { d.logger.Printf("[DEBUG] dns: request for %v (%s) (%v) from client %s (%s)", q, network, time.Now().Sub(s), resp.RemoteAddr().String(), resp.RemoteAddr().Network()) }(time.Now()) // Switch to TCP if the client is if _, ok := resp.RemoteAddr().(*net.TCPAddr); ok { network = "tcp" } // Recursively resolve c := &dns.Client{Net: network, Timeout: d.config.RecursorTimeout} var r *dns.Msg var rtt time.Duration var err error for _, recursor := range d.recursors { r, rtt, err = c.Exchange(req, recursor) if err == nil { // Compress the response; we don't know if the incoming // response was compressed or not, so by not compressing // we might generate an invalid packet on the way out. r.Compress = !d.config.DisableCompression // Forward the response d.logger.Printf("[DEBUG] dns: recurse RTT for %v (%v)", q, rtt) if err := resp.WriteMsg(r); err != nil { d.logger.Printf("[WARN] dns: failed to respond: %v", err) } return } d.logger.Printf("[ERR] dns: recurse failed: %v", err) } // If all resolvers fail, return a SERVFAIL message d.logger.Printf("[ERR] dns: all resolvers failed for %v from client %s (%s)", q, resp.RemoteAddr().String(), resp.RemoteAddr().Network()) m := &dns.Msg{} m.SetReply(req) m.Compress = !d.config.DisableCompression m.RecursionAvailable = true m.SetRcode(req, dns.RcodeServerFailure) resp.WriteMsg(m) }
func (t *UsageTracker) ServeDNS(w dns.ResponseWriter, r *dns.Msg) { var latest *usage.ProjectVersion var event *TrackingEvent m := new(dns.Msg) m.SetReply(r) q := r.Question[0].Name pv, err := usage.ParseV1(q) if err != nil { log.Printf("error parsing %s (%s): %s", q, w.RemoteAddr().(*net.UDPAddr).IP, err) // m.Rcode = dns.RcodeRefused m.Rcode = dns.RcodeNameError goto response } latest, err = t.GetLatest(pv) if err != nil { // TODO if format is right, but project is missing, // return an NXDOMAIN error log.Printf("error fetching latest for %v: %s", pv, err) m.Rcode = dns.RcodeNameError goto response } // do this after getting the version so we don't track results for // projects that aren't found event = &TrackingEvent{*pv, ""} if addr, ok := w.RemoteAddr().(*net.UDPAddr); ok { event.ClientAddress = addr.IP.String() } if err = t.Track(event); err != nil { log.Printf("error tracking %v: %s", event, err) // tracking error is not fatal, so still return the results } m.Answer = append(m.Answer, PtrRecord(latest)) response: err = w.WriteMsg(m) if err != nil { log.Printf("error writing response %v: %s", m, 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) }