// ProxyDNS returns a handler for a proxy DNS server. func ProxyDNS(server *app.App) func(w dns.ResponseWriter, req *dns.Msg) { return func(w dns.ResponseWriter, req *dns.Msg) { if len(req.Question) == 0 { dns.HandleFailed(w, req) return } name := req.Question[0].Name record, err := models.FindRecordBySubOfFQDN(server.DB, name) if err != nil || record.ID == "" { dns.HandleFailed(w, req) return } if record.Blacklist { dns.HandleFailed(w, req) return } transport := "udp" if _, ok := w.RemoteAddr().(*net.TCPAddr); ok { transport = "tcp" } c := &dns.Client{Net: transport} resp, _, err := c.Exchange(req, record.HandlerHost+":"+strconv.Itoa(record.HandlerPort)) if err != nil { dns.HandleFailed(w, req) return } if err := w.WriteMsg(resp); err != nil { dns.HandleFailed(w, req) return } } }
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) }
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 (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) } }
// NewServer creates a new Server with the given options. func NewServer(o Options) (*Server, error) { if err := o.validate(); err != nil { return nil, err } s := Server{ c: &dns.Client{}, s: &dns.Server{ Net: o.Net, Addr: o.Bind, }, white: o.Whitelist != "", hosts: hosts{}, hostsRX: hostsRX{}, privateHosts: map[string]struct{}{}, privateHostsRX: map[string]*regexp.Regexp{}, } hostListPath := o.Whitelist if hostListPath == "" { hostListPath = o.Blacklist } s.hostsFile.path = hostListPath if err := s.loadHostEntries(); err != nil { return nil, err } if o.Poll != 0 { go s.monitorHostEntries(o.Poll) } s.s.Handler = dns.HandlerFunc(func(w dns.ResponseWriter, r *dns.Msg) { // If no upstream proxy is present, drop the query: if len(o.Resolve) == 0 { dns.HandleFailed(w, r) return } // Filter Questions: if r.Question = s.filter(r.Question); len(r.Question) == 0 { w.WriteMsg(r) return } // Proxy Query: for _, addr := range o.Resolve { in, _, err := s.c.Exchange(r, addr) if err != nil { continue } w.WriteMsg(in) return } dns.HandleFailed(w, r) }) return &s, nil }
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) }
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) }
func (h *GODNSHandler) do(Net string, w dns.ResponseWriter, req *dns.Msg) { q := req.Question[0] Q := Question{UnFqdn(q.Name), dns.TypeToString[q.Qtype], dns.ClassToString[q.Qclass]} Debug("Question: %s", Q.String()) // Query hosts if settings.Hosts.Enable && h.isIPQuery(q) { if ip, ok := h.hosts.Get(Q.qname); ok { m := new(dns.Msg) m.SetReply(req) rr_header := dns.RR_Header{Name: q.Name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: settings.Hosts.TTL} a := &dns.A{rr_header, net.ParseIP(ip)} m.Answer = append(m.Answer, a) w.WriteMsg(m) Debug("%s found in hosts", Q.qname) return } } // Only query cache when qtype == 'A' , qclass == 'IN' key := KeyGen(Q) if h.isIPQuery(q) { mesg, err := h.cache.Get(key) if err != nil { Debug("%s didn't hit cache: %s", Q.String(), err) } else { Debug("%s hit cache", Q.String()) mesg.Id = req.Id w.WriteMsg(mesg) return } } mesg, err := h.resolver.Lookup(Net, req) if err != nil { Debug("%s", err) dns.HandleFailed(w, req) return } w.WriteMsg(mesg) if h.isIPQuery(q) { err = h.cache.Set(key, mesg) if err != nil { Debug("Set %s cache failed: %s", Q.String(), err.Error()) } Debug("Insert %s into cache", Q.String()) } }
func (s *Server) recurse(w dns.ResponseWriter, req *dns.Msg) { if s.recurseTo == "" { dns.HandleFailed(w, req) return } c := new(dns.Client) in, _, err := c.Exchange(req, s.recurseTo) if err == nil { if in.MsgHdr.Truncated { c.Net = "tcp" in, _, err = c.Exchange(req, s.recurseTo) } w.WriteMsg(in) return } log.Warnf("Recursive error: %+v", err) dns.HandleFailed(w, req) }
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 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 route(w dns.ResponseWriter, req *dns.Msg) { if len(req.Question) == 0 || !allowed(w, req) { dns.HandleFailed(w, req) return } for name, addr := range routes { if strings.HasSuffix(req.Question[0].Name, name) { proxy(addr, w, req) return } } proxy(*defaultServer, w, req) }
func serve(w dns.ResponseWriter, req *dns.Msg) { var resp dns.Msg var err error key := msgKey(req) cacheLock.Lock() cached, ok := cache[key] // cached value will not change until return because of SingleInflight cacheLock.Unlock() if !ok { log.Printf("%04X┐%s\n", req.Id, key) for attempt := 1; attempt <= queryAttempts; attempt++ { cached, _, err = dnsclient.Exchange(req, *flUpstream) if err != nil { cacheLock.Lock() _, ok = cache[key] cacheLock.Unlock() if ok { // concurrent exchange succeeded err = nil break } sep := "·" if attempt == queryAttempts { sep = "╳" } log.Printf("%04X%s%s: [%d/%d] %v\n", req.Id, sep, key, attempt, queryAttempts, err) } } if err != nil { dns.HandleFailed(w, req) return } cacheLock.Lock() cached2, ok := cache[key] if ok { // concurrent exchange has already updated the cache cached = cached2 log.Printf("%04X┴%04X\n", req.Id, cached.Id) } else { cache[key] = cached log.Printf("%04X└%s = %s\n", req.Id, key, answersSummary(cached)) } cacheLock.Unlock() } resp = *cached resp.Id = req.Id err = w.WriteMsg(&resp) eprint(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 (h *GODNSHandler) do(Net string, w dns.ResponseWriter, req *dns.Msg) { q := req.Question[0] Q := Question{UnFqdn(q.Name), dns.TypeToString[q.Qtype], dns.ClassToString[q.Qclass]} fmt.Println("DNS Lookup ", Q.String()) IPQuery := h.isIPQuery(q) key := fmt.Sprintf("%s-%s", h.GetHour(), Q.String()) fmt.Println("Cache key: ", key) if IPQuery > 0 { mesg, ok := h.Cache.Get(key) if ok == true { fmt.Println("Hit cache", Q.String()) rmesg := mesg.(*dns.Msg) rmesg.Id = req.Id w.WriteMsg(BuildDNSMsg(rmesg)) return } } mesg, err := h.resolver.Lookup(Net, req) if err != nil { mesg, err = h.resolver.Lookup(Net, req) // try to lookup again if err != nil { fmt.Println("Resolve query error ", err) dns.HandleFailed(w, req) } return } w.WriteMsg(BuildDNSMsg(mesg)) if IPQuery > 0 && len(mesg.Answer) > 0 { h.Cache.Add(key, mesg) fmt.Println("Insert into cache", Q.String()) } }
func (h *GODNSHandler) do(Net string, w dns.ResponseWriter, req *dns.Msg) { q := req.Question[0] Q := Question{UnFqdn(q.Name), dns.TypeToString[q.Qtype], dns.ClassToString[q.Qclass]} fmt.Println("DNS Lookup ", Q.String()) IPQuery := h.isIPQuery(q) // Only query cache when qtype == 'A'|'AAAA' , qclass == 'IN' hasher := md5.New() hasher.Write([]byte(Q.String())) key := hex.EncodeToString(hasher.Sum(nil)) if IPQuery > 0 { mesg, err := h.Cache.Get(key) if err == nil { fmt.Println("Hit cache", Q.String()) mesg.Id = req.Id w.WriteMsg(mesg) return } } mesg, err := h.resolver.Lookup(Net, req) if err != nil { fmt.Println("Resolve query error ", err) dns.HandleFailed(w, req) return } w.WriteMsg(mesg) if IPQuery > 0 && len(mesg.Answer) > 0 { h.Cache.Set(key, mesg) fmt.Println("Insert into cache", Q.String()) } }
func route(w dns.ResponseWriter, req *dns.Msg) { clientIp, _, _ := net.SplitHostPort(w.RemoteAddr().String()) // One question at a time please if len(req.Question) != 1 { dns.HandleFailed(w, req) log.WithFields(log.Fields{"client": clientIp}).Warn("Rejected multi-question query") return } question := req.Question[0] rrString := dns.Type(question.Qtype).String() // We are assuming the JSON config has all names as lower case fqdn := strings.ToLower(question.Name) // Internets only if question.Qclass != dns.ClassINET { m := new(dns.Msg) m.SetReply(req) m.Authoritative = false m.RecursionDesired = false m.RecursionAvailable = false m.Rcode = dns.RcodeNotImplemented w.WriteMsg(m) log.WithFields(log.Fields{"question": fqdn, "type": rrString, "client": clientIp}).Warn("Rejected non-inet query") return } // ANY queries are bad, mmmkay... if question.Qtype == dns.TypeANY { m := new(dns.Msg) m.SetReply(req) m.Authoritative = false m.RecursionDesired = false m.RecursionAvailable = false m.Rcode = dns.RcodeNotImplemented w.WriteMsg(m) log.WithFields(log.Fields{"question": fqdn, "type": rrString, "client": clientIp}).Warn("Rejected ANY query") return } proto := "UDP" if isTcp(w) { proto = "TCP" } log.WithFields(log.Fields{"question": fqdn, "type": rrString, "client": clientIp, "proto": proto}).Debug("Request") // A records may return CNAME answer(s) plus A answer(s) if question.Qtype == dns.TypeA { found, ok := answers.Addresses(clientIp, fqdn, nil, 1) if ok && len(found) > 0 { log.WithFields(log.Fields{"client": clientIp, "type": rrString, "question": fqdn, "answers": len(found)}).Info("Answered locally") Respond(w, req, found) return } } else { // Specific request for another kind of record keys := []string{clientIp, DEFAULT_KEY} for _, key := range keys { // Client-specific answers found, ok := answers.Matching(question.Qtype, key, fqdn) if ok { log.WithFields(log.Fields{"client": key, "type": rrString, "question": fqdn, "answers": len(found)}).Info("Answered from config for ", key) Respond(w, req, found) return } } log.Debug("No match found in config") } // Phone a friend msg, err := ResolveTryAll(fqdn, question.Qtype, answers.Recursers(clientIp)) if err == nil { msg.SetReply(req) w.WriteMsg(msg) log.WithFields(log.Fields{"client": clientIp, "type": rrString, "question": fqdn}).Info("Sent recursive response") return } // I give up log.WithFields(log.Fields{"client": clientIp, "type": rrString, "question": fqdn}).Warn("No answer found") dns.HandleFailed(w, req) }
func (h *GODNSHandler) do(Net string, w dns.ResponseWriter, req *dns.Msg) { q := req.Question[0] Q := Question{UnFqdn(q.Name), dns.TypeToString[q.Qtype], dns.ClassToString[q.Qclass]} var remote net.IP if Net == "tcp" { remote = w.RemoteAddr().(*net.TCPAddr).IP } else { remote = w.RemoteAddr().(*net.UDPAddr).IP } logger.Info("%s lookup %s", remote, Q.String()) IPQuery := h.isIPQuery(q) // Query hosts if settings.Hosts.Enable && IPQuery > 0 { if ips, ok := h.hosts.Get(Q.qname, IPQuery); ok { m := new(dns.Msg) m.SetReply(req) switch IPQuery { case _IP4Query: rr_header := dns.RR_Header{ Name: q.Name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: settings.Hosts.TTL, } for _, ip := range ips { a := &dns.A{rr_header, ip} m.Answer = append(m.Answer, a) } case _IP6Query: rr_header := dns.RR_Header{ Name: q.Name, Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Ttl: settings.Hosts.TTL, } for _, ip := range ips { aaaa := &dns.AAAA{rr_header, ip} m.Answer = append(m.Answer, aaaa) } } w.WriteMsg(m) logger.Debug("%s found in hosts file", Q.qname) return } else { logger.Debug("%s didn't found in hosts file", Q.qname) } } // Only query cache when qtype == 'A'|'AAAA' , qclass == 'IN' key := KeyGen(Q) if IPQuery > 0 { mesg, err := h.cache.Get(key) if err != nil { if mesg, err = h.negCache.Get(key); err != nil { logger.Debug("%s didn't hit cache", Q.String()) } else { logger.Debug("%s hit negative cache", Q.String()) dns.HandleFailed(w, req) return } } else { logger.Debug("%s hit cache", Q.String()) // we need this copy against concurrent modification of Id msg := *mesg msg.Id = req.Id w.WriteMsg(&msg) return } } mesg, err := h.resolver.Lookup(Net, req) if err != nil { logger.Warn("Resolve query error %s", err) dns.HandleFailed(w, req) // cache the failure, too! if err = h.negCache.Set(key, nil); err != nil { logger.Warn("Set %s negative cache failed: %v", Q.String(), err) } return } w.WriteMsg(mesg) if IPQuery > 0 && len(mesg.Answer) > 0 { err = h.cache.Set(key, mesg) if err != nil { logger.Warn("Set %s cache failed: %s", Q.String(), err.Error()) } logger.Debug("Insert %s into cache", Q.String()) } }
func route(w dns.ResponseWriter, req *dns.Msg) { // Setup reply m := new(dns.Msg) m.SetReply(req) m.Authoritative = true m.RecursionAvailable = true m.Compress = true clientIp, _, _ := net.SplitHostPort(w.RemoteAddr().String()) // One question at a time please if len(req.Question) != 1 { dns.HandleFailed(w, req) log.WithFields(log.Fields{"client": clientIp}).Warn("Rejected multi-question query") return } question := req.Question[0] rrString := dns.Type(question.Qtype).String() // We are assuming the config has all names as lower case fqdn := strings.ToLower(question.Name) // Internets only if question.Qclass != dns.ClassINET { m.Authoritative = false m.RecursionDesired = false m.RecursionAvailable = false m.Rcode = dns.RcodeNotImplemented w.WriteMsg(m) log.WithFields(log.Fields{"question": fqdn, "type": rrString, "client": clientIp}).Warn("Rejected non-inet query") return } // ANY queries are bad, mmmkay... if question.Qtype == dns.TypeANY { m.Authoritative = false m.RecursionDesired = false m.RecursionAvailable = false m.Rcode = dns.RcodeNotImplemented w.WriteMsg(m) log.WithFields(log.Fields{"question": fqdn, "type": rrString, "client": clientIp}).Warn("Rejected ANY query") return } proto := "UDP" if isTcp(w) { proto = "TCP" } log.WithFields(log.Fields{"question": fqdn, "type": rrString, "client": clientIp, "proto": proto}).Debug("Request") if msg := clientSpecificCacheHit(clientIp, req); msg != nil { Respond(w, req, msg) log.WithFields(log.Fields{"client": clientIp, "type": rrString, "question": fqdn}).Debug("Sent client-specific cached response") return } if msg := globalCacheHit(req); msg != nil { Respond(w, req, msg) log.WithFields(log.Fields{"client": clientIp, "type": rrString, "question": fqdn}).Debug("Sent globally cached response") return } // A records may return CNAME answer(s) plus A answer(s) if question.Qtype == dns.TypeA { found, ok := answers.Addresses(clientIp, fqdn, nil, 1) if ok && len(found) > 0 { log.WithFields(log.Fields{"client": clientIp, "type": rrString, "question": fqdn, "answers": len(found)}).Debug("Answered locally") m.Answer = found addToClientSpecificCache(clientIp, req, m) Respond(w, req, m) return } } else { // Specific request for another kind of record keys := []string{clientIp, DEFAULT_KEY} for _, key := range keys { // Client-specific answers found, ok := answers.Matching(question.Qtype, key, fqdn) if ok { log.WithFields(log.Fields{"client": key, "type": rrString, "question": fqdn, "answers": len(found)}).Debug("Answered from config for ", key) m.Answer = found addToClientSpecificCache(clientIp, req, m) Respond(w, req, m) return } } log.Debug("No match found in config") } // If we are authoritative for a suffix the label has, there's no point trying the recursive DNS authoritativeFor := answers.AuthoritativeSuffixes() for _, suffix := range authoritativeFor { if strings.HasSuffix(fqdn, suffix) { log.WithFields(log.Fields{"client": clientIp, "type": rrString, "question": fqdn}).Debugf("Not answered locally, but I am authoritative for %s", suffix) m.Authoritative = true m.RecursionAvailable = false me := strings.TrimLeft(suffix, ".") hdr := dns.RR_Header{Name: me, Rrtype: dns.TypeSOA, Class: dns.ClassINET, Ttl: uint32(*defaultTtl)} serial++ record := &dns.SOA{Hdr: hdr, Ns: me, Mbox: me, Serial: serial, Refresh: 60, Retry: 10, Expire: 86400, Minttl: 1} m.Ns = append(m.Ns, record) Respond(w, req, m) return } } // Phone a friend - Forward original query msg, err := ResolveTryAll(req, answers.Recursers(clientIp)) if err == nil { msg.Compress = true msg.Id = req.Id // We don't support AAAA, but an NXDOMAIN from the recursive resolver // doesn't necessarily mean there are never any records for that domain, // so rewrite the response code to NOERROR. if (question.Qtype == dns.TypeAAAA) && (msg.Rcode == dns.RcodeNameError) { log.WithFields(log.Fields{"client": clientIp, "type": rrString, "question": fqdn}).Debug("Rewrote AAAA NXDOMAIN to NOERROR") msg.Rcode = dns.RcodeSuccess } addToGlobalCache(req, msg) Respond(w, req, msg) log.WithFields(log.Fields{"client": clientIp, "type": rrString, "question": fqdn}).Debug("Sent recursive response") return } // I give up log.WithFields(log.Fields{"client": clientIp, "type": rrString, "question": fqdn}).Info("No answer found") dns.HandleFailed(w, req) }
func serve(w dns.ResponseWriter, req *dns.Msg, z *Zone) { qtype := req.Question[0].Qtype logPrintf("[zone %s] incoming %s %s %d from %s\n", z.Origin, req.Question[0].Name, dns.Rr_str[qtype], req.MsgHdr.Id, w.RemoteAddr()) // is this safe/atomic or does it need to go through a channel? qCounter++ logPrintln("Got request", req) label := getQuestionName(z, req) var country string if geoIP != nil { ip, _, _ := net.SplitHostPort(w.RemoteAddr().String()) country = strings.ToLower(geoIP.GetCountry(ip)) logPrintln("Country:", ip, country) } m := new(dns.Msg) m.SetReply(req) if e := m.IsEdns0(); e != nil { m.SetEdns0(4096, e.Do()) } m.Authoritative = true // TODO(ask) Fix the findLabels API to make this work better if alias := z.findLabels(label, "", dns.TypeMF); alias != nil && alias.Records[dns.TypeMF] != nil { // We found an alias record, so pretend the question was for that name instead label = alias.firstRR(dns.TypeMF).(*dns.RR_MF).Mf } labels := z.findLabels(label, country, qtype) if labels == nil { if label == "_status" && (qtype == dns.TypeANY || qtype == dns.TypeTXT) { m.Answer = statusRR(z) m.Authoritative = true w.Write(m) return } if label == "_country" && (qtype == dns.TypeANY || qtype == dns.TypeTXT) { h := dns.RR_Header{Ttl: 1, Class: dns.ClassINET, Rrtype: dns.TypeTXT} h.Name = "_country." + z.Origin + "." m.Answer = []dns.RR{&dns.RR_TXT{Hdr: h, Txt: []string{ w.RemoteAddr().String(), string(country), string(countries.CountryContinent[country]), }, }} m.Authoritative = true w.Write(m) return } // return NXDOMAIN m.SetRcode(req, dns.RcodeNameError) m.Authoritative = true m.Ns = []dns.RR{z.SoaRR()} w.Write(m) return } if servers := labels.Picker(qtype, labels.MaxHosts); servers != nil { var rrs []dns.RR for _, record := range servers { rr := record.RR rr.Header().Name = req.Question[0].Name rrs = append(rrs, rr) } m.Answer = rrs } if len(m.Answer) == 0 { if labels := z.Labels[label]; labels != nil { if _, ok := labels.Records[dns.TypeCNAME]; ok { cname := labels.firstRR(dns.TypeCNAME) m.Answer = append(m.Answer, cname) } } else { m.Ns = append(m.Ns, z.SoaRR()) } } logPrintln(m) err := w.Write(m) if err != nil { // if Pack'ing fails the Write fails. Return SERVFAIL. log.Println("Error writing packet", m) dns.HandleFailed(w, req) } return }
func (h *GODNSHandler) do(Net string, w dns.ResponseWriter, req *dns.Msg) { q := req.Question[0] Q := Question{UnFqdn(q.Name), dns.TypeToString[q.Qtype], dns.ClassToString[q.Qclass]} Debug("Question: %s", Q.String()) IPQuery := h.isIPQuery(q) go func() { h.statsd.Incr("dns.query", 1) Debug("Increment Dns Query") }() // Query hosts if settings.Hosts.Enable && IPQuery > 0 { if ip, ok := h.hosts.Get(Q.qname, IPQuery); ok { m := new(dns.Msg) m.SetReply(req) switch IPQuery { case _IP4Query: rr_header := dns.RR_Header{ Name: q.Name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: settings.Hosts.TTL, } a := &dns.A{rr_header, ip} m.Answer = append(m.Answer, a) case _IP6Query: rr_header := dns.RR_Header{ Name: q.Name, Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Ttl: settings.Hosts.TTL, } aaaa := &dns.AAAA{rr_header, ip} m.Answer = append(m.Answer, aaaa) } w.WriteMsg(m) Debug("%s found in hosts file", Q.qname) go func() { h.statsd.Incr("dns.local", 1) Debug("Increment Dns Query") }() return } else { Debug("%s didn't found in hosts file", Q.qname) } } // Only query cache when qtype == 'A'|'AAAA' , qclass == 'IN' key := KeyGen(Q) if IPQuery > 0 { mesg, err := h.cache.Get(key) if err != nil { if mesg, err = h.negCache.Get(key); err != nil { Debug("%s didn't hit cache: %s", Q.String(), err) } else { Debug("%s hit negative cache", Q.String()) dns.HandleFailed(w, req) return } } else { Debug("%s hit cache", Q.String()) // we need this copy against concurrent modification of Id msg := *mesg msg.Id = req.Id w.WriteMsg(&msg) return } } mesg, err := h.resolver.Lookup(Net, req) if err != nil { Debug("%s", err) dns.HandleFailed(w, req) // cache the failure, too! if err = h.negCache.Set(key, nil); err != nil { Debug("Set %s negative cache failed: %v", Q.String(), err) } return } w.WriteMsg(mesg) if IPQuery > 0 && len(mesg.Answer) > 0 { err = h.cache.Set(key, mesg) if err != nil { Debug("Set %s cache failed: %s", Q.String(), err.Error()) } Debug("Insert %s into cache", Q.String()) } }
func (s *Server) Handler(w dns.ResponseWriter, r *dns.Msg) { tr := trace.New("dnstox", "Handler") defer tr.Finish() tr.LazyPrintf("from:%v id:%v", w.RemoteAddr(), r.Id) if glog.V(3) { tr.LazyPrintf(util.QuestionsToString(r.Question)) } // We only support single-question queries. if len(r.Question) != 1 { tr.LazyPrintf("len(Q) != 1, failing") dns.HandleFailed(w, r) return } // Forward to the unqualified upstream server if: // - We have one configured. // - There's only one question in the request, to keep things simple. // - The question is unqualified (only one '.' in the name). useUnqUpstream := s.unqUpstream != "" && strings.Count(r.Question[0].Name, ".") <= 1 if useUnqUpstream { u, err := dns.Exchange(r, s.unqUpstream) if err == nil { tr.LazyPrintf("used unqualified upstream") if glog.V(3) { util.TraceAnswer(tr, u) } w.WriteMsg(u) } else { tr.LazyPrintf("unqualified upstream error: %v", err) dns.HandleFailed(w, r) } return } // Forward to the fallback server if the domain is on our list. if _, ok := s.fallbackDomains[r.Question[0].Name]; ok { u, err := dns.Exchange(r, s.fallbackUpstream) if err == nil { tr.LazyPrintf("used fallback upstream (%s)", s.fallbackUpstream) if glog.V(3) { util.TraceAnswer(tr, u) } w.WriteMsg(u) } else { tr.LazyPrintf("fallback upstream error: %v", err) dns.HandleFailed(w, r) } return } // Create our own IDs, in case different users pick the same id and we // pass that upstream. oldid := r.Id r.Id = <-newId from_up, err := s.resolver.Query(r, tr) if err != nil { glog.Infof(err.Error()) tr.LazyPrintf(err.Error()) tr.SetError() return } if glog.V(3) { util.TraceAnswer(tr, from_up) } from_up.Id = oldid w.WriteMsg(from_up) }
func handleRoot(w dns.ResponseWriter, r *dns.Msg) { var err error var res *dns.Msg domain := r.Question[0].Name /* reply from hosts */ if record_hosts != nil { rr := record_hosts.Get(domain, r.Question[0].Qtype) if rr != nil { msg := new(dns.Msg) msg.SetReply(r) msg.Answer = append(msg.Answer, rr) w.WriteMsg(msg) logger.Debug("%s query %s %s %s, reply from hosts\n", w.RemoteAddr(), domain, dns.ClassToString[r.Question[0].Qclass], dns.TypeToString[r.Question[0].Qtype], ) return } } key := fmt.Sprintf("%s_%s", domain, dns.TypeToString[r.Question[0].Qtype]) if enable_cache { // reply from cache if a, ok := dns_cache.Get(key); ok { msg := new(dns.Msg) msg.SetReply(r) aa := strings.Split(a.(string), "|") for _, a1 := range aa { rr, _ := dns.NewRR(a1) if rr != nil { msg.Answer = append(msg.Answer, rr) } } w.WriteMsg(msg) logger.Debug("%s query %s %s %s, reply from cache\n", w.RemoteAddr(), domain, dns.ClassToString[r.Question[0].Qclass], dns.TypeToString[r.Question[0].Qtype], ) return } } // forward to upstream server for i := 0; i < 2; i++ { for _, sv := range Servers { if sv.match(domain) { res, err = sv.query(r) if err != nil { logger.Error("%s", err) continue } logger.Debug("%s query %s %s %s, forward to %s:%s, %s\n", w.RemoteAddr(), domain, dns.ClassToString[r.Question[0].Qclass], dns.TypeToString[r.Question[0].Qtype], sv.Proto, sv.Addr, dns.RcodeToString[res.Rcode], ) if res.Rcode == dns.RcodeSuccess && !in_blacklist(res) && len(res.Answer) > 0 { if enable_cache { // add to cache v := []string{} for _, as := range res.Answer { v = append(v, as.String()) } dns_cache.Add(key, strings.Join(v, "|")) } w.WriteMsg(res) return } } } } // fallback to default upstream server for i := 0; i < 2; i++ { logger.Debug("%s query %s %s %s, use default server\n", w.RemoteAddr(), domain, dns.ClassToString[r.Question[0].Qclass], dns.TypeToString[r.Question[0].Qtype], ) res := query(r) if res != nil { //logger.Debug("get: %s", res) if enable_cache && res.Rcode == dns.RcodeSuccess && len(res.Answer) > 0 { // add to cache v := []string{} for _, as := range res.Answer { v = append(v, as.String()) } dns_cache.Add(key, strings.Join(v, "|")) } w.WriteMsg(res) return } } dns.HandleFailed(w, r) }
func (srv *Server) serve(w dns.ResponseWriter, req *dns.Msg, z *Zone) { qname := req.Question[0].Name qtype := req.Question[0].Qtype var qle *querylog.Entry if srv.queryLogger != nil { qle = &querylog.Entry{ Time: time.Now().UnixNano(), Origin: z.Origin, Name: qname, Qtype: qtype, } defer srv.queryLogger.Write(qle) } logPrintf("[zone %s] incoming %s %s (id %d) from %s\n", z.Origin, qname, dns.TypeToString[qtype], req.Id, w.RemoteAddr()) // Global meter metrics.Get("queries").(metrics.Meter).Mark(1) // Zone meter z.Metrics.Queries.Mark(1) logPrintln("Got request", req) label := getQuestionName(z, req) z.Metrics.LabelStats.Add(label) // IP that's talking to us (not EDNS CLIENT SUBNET) var realIP net.IP if addr, ok := w.RemoteAddr().(*net.UDPAddr); ok { realIP = make(net.IP, len(addr.IP)) copy(realIP, addr.IP) } else if addr, ok := w.RemoteAddr().(*net.TCPAddr); ok { realIP = make(net.IP, len(addr.IP)) copy(realIP, addr.IP) } if qle != nil { qle.RemoteAddr = realIP.String() } z.Metrics.ClientStats.Add(realIP.String()) var ip net.IP // EDNS or real IP var edns *dns.EDNS0_SUBNET var opt_rr *dns.OPT for _, extra := range req.Extra { switch extra.(type) { case *dns.OPT: for _, o := range extra.(*dns.OPT).Option { opt_rr = extra.(*dns.OPT) switch e := o.(type) { case *dns.EDNS0_NSID: // do stuff with e.Nsid case *dns.EDNS0_SUBNET: z.Metrics.EdnsQueries.Mark(1) logPrintln("Got edns", e.Address, e.Family, e.SourceNetmask, e.SourceScope) if e.Address != nil { edns = e ip = e.Address if qle != nil { qle.HasECS = true qle.ClientAddr = fmt.Sprintf("%s/%d", ip, e.SourceNetmask) } } } } } } if len(ip) == 0 { // no edns subnet ip = realIP if qle != nil { qle.ClientAddr = fmt.Sprintf("%s/%d", ip, len(ip)*8) } } targets, netmask := z.Options.Targeting.GetTargets(ip) if qle != nil { qle.Targets = targets } m := new(dns.Msg) if qle != nil { defer func() { qle.Rcode = m.Rcode qle.Answers = len(m.Answer) }() } m.SetReply(req) if e := m.IsEdns0(); e != nil { m.SetEdns0(4096, e.Do()) } m.Authoritative = true // TODO: set scope to 0 if there are no alternate responses if edns != nil { if edns.Family != 0 { if netmask < 16 { netmask = 16 } edns.SourceScope = uint8(netmask) m.Extra = append(m.Extra, opt_rr) } } labels, labelQtype := z.findLabels(label, targets, qTypes{dns.TypeMF, dns.TypeCNAME, qtype}) if labelQtype == 0 { labelQtype = qtype } if labels == nil { permitDebug := !*flagPrivateDebug || (realIP != nil && realIP.IsLoopback()) firstLabel := (strings.Split(label, "."))[0] if qle != nil { qle.LabelName = firstLabel } if permitDebug && firstLabel == "_status" { if qtype == dns.TypeANY || qtype == dns.TypeTXT { m.Answer = statusRR(label + "." + z.Origin + ".") } else { m.Ns = append(m.Ns, z.SoaRR()) } m.Authoritative = true w.WriteMsg(m) return } if firstLabel == "_country" { if qtype == dns.TypeANY || qtype == dns.TypeTXT { h := dns.RR_Header{Ttl: 1, Class: dns.ClassINET, Rrtype: dns.TypeTXT} h.Name = label + "." + z.Origin + "." txt := []string{ w.RemoteAddr().String(), ip.String(), } targets, netmask := z.Options.Targeting.GetTargets(ip) txt = append(txt, strings.Join(targets, " ")) txt = append(txt, fmt.Sprintf("/%d", netmask), serverID, serverIP) m.Answer = []dns.RR{&dns.TXT{Hdr: h, Txt: txt, }} } else { m.Ns = append(m.Ns, z.SoaRR()) } m.Authoritative = true w.WriteMsg(m) return } // return NXDOMAIN m.SetRcode(req, dns.RcodeNameError) m.Authoritative = true m.Ns = []dns.RR{z.SoaRR()} w.WriteMsg(m) return } if servers := labels.Picker(labelQtype, labels.MaxHosts); servers != nil { var rrs []dns.RR for _, record := range servers { rr := dns.Copy(record.RR) rr.Header().Name = qname rrs = append(rrs, rr) } m.Answer = rrs } if len(m.Answer) == 0 { // Return a SOA so the NOERROR answer gets cached m.Ns = append(m.Ns, z.SoaRR()) } logPrintln(m) if qle != nil { qle.LabelName = labels.Label qle.Answers = len(m.Answer) qle.Rcode = m.Rcode } err := w.WriteMsg(m) if err != nil { // if Pack'ing fails the Write fails. Return SERVFAIL. log.Println("Error writing packet", m) dns.HandleFailed(w, req) } return }
func (h *DNSProxyHandler) do(Net string, w dns.ResponseWriter, req *dns.Msg) { q := req.Question[0] if (settings.Filters.OnlyIPQ) && (q.Qtype == dns.TypeANY) { q.Qtype = dns.TypeA } Q := Question{UnFqdn(q.Name), dns.TypeToString[q.Qtype], dns.ClassToString[q.Qclass]} Debug("Question: %s", Q.String()) IPQuery := h.isIPQuery(q) if (IPQuery == 0) && (settings.Filters.OnlyIPQ) { Debug("Only IP queries allowed (A,AAAA)") m := new(dns.Msg) m.SetReply(req) // return servfail m.MsgHdr.Rcode = 2 w.WriteMsg(m) return } if len(settings.Filters.Suffixes) > 0 { j := -1 for i := range settings.Filters.Suffixes { Debug("Suffix: %s", settings.Filters.Suffixes[i]) if strings.HasSuffix(q.Name, settings.Filters.Suffixes[i]) { dot := "." dot += settings.Filters.Suffixes[i] if settings.Filters.Suffixes[i][0] == '.' { j = i break } else if len(q.Name) == len(settings.Filters.Suffixes[i]) { // exact match j = i break } else if strings.HasSuffix(q.Name, dot) { // matches '.'+suffix j = i break } } } if j == -1 { Debug("Request %s does not match any suffix filter -> SRVFAIL", q.Name) m := new(dns.Msg) m.SetReply(req) // return servfail m.MsgHdr.Rcode = 2 w.WriteMsg(m) return } else { Debug("Request %s matches suffix filter %s", q.Name, settings.Filters.Suffixes[j]) } } // Query hosts if settings.Hosts.Enable && IPQuery > 0 { if ip, ok := h.hosts.Get(Q.qname, IPQuery); ok { m := new(dns.Msg) m.SetReply(req) switch IPQuery { case _IP4Query: rr_header := dns.RR_Header{ Name: q.Name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: settings.Hosts.TTL, } a := &dns.A{rr_header, ip} m.Answer = append(m.Answer, a) case _IP6Query: rr_header := dns.RR_Header{ Name: q.Name, Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Ttl: settings.Hosts.TTL, } aaaa := &dns.AAAA{rr_header, ip} m.Answer = append(m.Answer, aaaa) } w.WriteMsg(m) Debug("%s found in hosts file", Q.qname) return } else { Debug("%s didn't found in hosts file", Q.qname) } } // Only query cache when qtype == 'A' , qclass == 'IN' key := KeyGen(Q) if IPQuery > 0 { mesg, err := h.cache.Get(key) if err != nil { Debug("%s didn't hit cache: %s", Q.String(), err) } else { Debug("%s hit cache", Q.String()) h.mu.Lock() mesg.Id = req.Id w.WriteMsg(mesg) h.mu.Unlock() return } } mesg, err := h.resolver.Lookup(Net, req) if ((settings.Filters.OnlyIPQ) || (len(settings.Filters.IPFilter) > 0)) && (err == nil) { var newans []dns.RR for a := range mesg.Answer { ah := mesg.Answer[a].Header() Debug("ANS[%d]: %s", a, mesg.Answer[a]) if (ah.Rrtype == dns.TypeA) && (len(settings.Filters.IPFilter) > 0) { t, _ := mesg.Answer[a].(*dns.A) j := 0 for i := range settings.Filters.IPFilter { if strings.HasPrefix(t.A.String(), settings.Filters.IPFilter[i]) { Debug("A answer %s matches IPFilter %s", t.A.String(), settings.Filters.IPFilter[i]) j = 1 break } } if j == 0 { Debug("A answer %s does not match any IPFilter -> NXD", q.Name) err = dns.ErrId break } } if settings.Filters.OnlyIPQ { if (ah.Rrtype == dns.TypeA) || (ah.Rrtype == dns.TypeAAAA) || (ah.Rrtype == dns.TypeCNAME) { newans = append(newans, mesg.Answer[a]) } } } if settings.Filters.OnlyIPQ { mesg.Answer = newans } } if err != nil { if len(settings.Filters.SwapNXDIP) > 0 { rr_header := dns.RR_Header{ Name: q.Name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: settings.Filters.SwapNXDTTL, } m := new(dns.Msg) m.SetReply(req) ip := net.ParseIP(settings.Filters.SwapNXDIP).To4() a := &dns.A{rr_header, ip} m.Answer = append(m.Answer, a) m.MsgHdr.Authoritative = true w.WriteMsg(m) return } else { Debug("%s", err) dns.HandleFailed(w, req) return } } w.WriteMsg(mesg) if IPQuery > 0 && len(mesg.Answer) > 0 { err = h.cache.Set(key, mesg) if err != nil { Debug("Set %s cache failed: %s", Q.String(), err.Error()) } Debug("Insert %s into cache", Q.String()) } }