Esempio n. 1
0
// 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
		}
	}
}
Esempio n. 2
0
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)
}
Esempio n. 3
0
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)
}
Esempio n. 4
0
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)
	}
}
Esempio n. 5
0
// 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
}
Esempio n. 6
0
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)
}
Esempio n. 7
0
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)
}
Esempio n. 8
0
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())
	}

}
Esempio n. 9
0
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)
}
Esempio n. 10
0
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
	}
}
Esempio n. 11
0
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)
}
Esempio n. 12
0
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)
}
Esempio n. 13
0
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)
}
Esempio n. 14
0
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)
}
Esempio n. 15
0
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())
	}
}
Esempio n. 16
0
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())
	}
}
Esempio n. 17
0
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)
}
Esempio n. 18
0
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())
	}
}
Esempio n. 19
0
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)
}
Esempio n. 20
0
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
}
Esempio n. 21
0
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())
	}
}
Esempio n. 22
0
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)
}
Esempio n. 23
0
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)
}
Esempio n. 24
0
File: serve.go Progetto: abh/geodns
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
}
Esempio n. 25
0
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())
	}
}