// Handles an incoming DNS request packet. This function decides whether // the hostname listed in the DNS packet is worthy of manipulation, or // not. The IP addresses listed in the reply to the user for a target // hostname are added to the routing table at this time before a // reply is sent back to the user, otherwise the user agent of the client // might connect faster than the routing changes can be made. func handleRequest(w dns.ResponseWriter, req *dns.Msg) { var m *dns.Msg // check if the the hostname in the request matches the target if len(req.Question) > 0 && isTargetZone(req.Question[0].Name) { // handle `A` and `AAAA` types accordingly // other record types will be forwarded without manipulation switch req.Question[0].Qtype { case dns.TypeA: m = handleV4Hijack(w, req) case dns.TypeAAAA: m = handleV6Hijack(w, req) } } // if no reply was previously set, forward it if m == nil { m = getServerReply(w, req) } // send reply back to user w.WriteMsg(m) }
// 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) } }
// handleDNS is a handler function to actualy perform the dns querey response func (c *CatchAll) handleDNS(w dns.ResponseWriter, r *dns.Msg) { defer w.Close() var rr dns.RR domainSpoof := r.Question[0].Name msgResp := new(dns.Msg) msgResp.SetReply(r) msgResp.Compress = false rr = new(dns.A) if c.SpoofDomain { rr.(*dns.A).Hdr = dns.RR_Header{Name: domainSpoof, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 0} } else { rr.(*dns.A).Hdr = dns.RR_Header{Name: c.Domain, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 0} } rr.(*dns.A).A = c.IP switch r.Question[0].Qtype { case dns.TypeA: msgResp.Answer = append(msgResp.Answer, rr) default: log.Warnf("Unknown dns type %T", r.Question[0].Qtype) return } w.WriteMsg(msgResp) }
// 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) } }
// ServeDNS implements the middleware.Handler interface. func (d Dnssec) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) { state := middleware.State{W: w, Req: r} do := state.Do() qname := state.Name() qtype := state.QType() zone := middleware.Zones(d.zones).Matches(qname) if zone == "" { return d.Next.ServeDNS(ctx, w, r) } // Intercept queries for DNSKEY, but only if one of the zones matches the qname, otherwise we let // the query through. if qtype == dns.TypeDNSKEY { for _, z := range d.zones { if qname == z { resp := d.getDNSKEY(state, z, do) state.SizeAndDo(resp) w.WriteMsg(resp) return dns.RcodeSuccess, nil } } } drr := NewDnssecResponseWriter(w, d) return d.Next.ServeDNS(ctx, drr, r) }
// Create DNS packet with the config in line with the meta zone // paper from Vixie func metazone(w dns.ResponseWriter, req *dns.Msg, c *Config) { logPrintf("metazone command") // Only called when the class is CHAOS // PTR zone. -> get a list of zone names // Top level zone stuff -- list them if strings.ToUpper(req.Question[0].Name) == "ZONE." { m := new(dns.Msg) m.SetReply(req) for _, z := range c.Zones { ptr, _ := dns.NewRR("zone. 0 CH PTR " + z.Origin) m.Answer = append(m.Answer, ptr) } w.WriteMsg(m) return } // Top level user stuff -- list them if strings.ToUpper(req.Question[0].Name) == "USER." { } // <zone>.ZONE. formerr(w, req) return }
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) } }
func (h dnsHandler) ServeDNS(w dns.ResponseWriter, r *dns.Msg) { if len(r.Question) != 1 { h.t.Fatalf("bad: %#v", r.Question) } name := "join.service.consul." question := r.Question[0] if question.Name != name || question.Qtype != dns.TypeANY { h.t.Fatalf("bad: %#v", question) } m := new(dns.Msg) m.SetReply(r) m.Authoritative = true m.RecursionAvailable = false m.Answer = append(m.Answer, &dns.A{ Hdr: dns.RR_Header{ Name: name, Rrtype: dns.TypeA, Class: dns.ClassINET}, A: net.ParseIP("127.0.0.1"), }) m.Answer = append(m.Answer, &dns.AAAA{ Hdr: dns.RR_Header{ Name: name, Rrtype: dns.TypeAAAA, Class: dns.ClassINET}, AAAA: net.ParseIP("2001:db8:a0b:12f0::1"), }) if err := w.WriteMsg(m); err != nil { h.t.Fatalf("err: %v", err) } }
// 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 handleDnsRequest(w dns.ResponseWriter, r *dns.Msg) { m := new(dns.Msg) m.SetReply(r) records := make([]dns.RR, 0) q := r.Question[0] if q.Qtype == dns.TypeA && strings.HasSuffix(q.Name, ".docker.") { docker, _ := dockerclient.NewDockerClient("unix:///var/run/docker.sock", &tls.Config{}) name := strings.SplitN(q.Name, ".", 2)[0] containers, err := docker.ListContainers(false, false, fmt.Sprintf("{\"name\":[\"%s\"]}", name)) if err != nil { log.Fatal(err) } for _, c := range containers { info, _ := docker.InspectContainer(c.Id) log.Printf("Container %s[%6s] has ip %s\n", name, info.Id, info.NetworkSettings.IPAddress) records = append(records, &dns.A{ Hdr: dns.RR_Header{ Name: q.Name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 60}, A: net.ParseIP(info.NetworkSettings.IPAddress), }) } } m.Answer = append(m.Answer, records...) defer w.WriteMsg(m) }
func (s *jujuNameServer) handleRequest(w dns.ResponseWriter, r *dns.Msg) { m := new(dns.Msg) m.SetReply(r) for _, q := range r.Question { rr, err := s.answer(q) if err != nil { m.SetRcodeFormatError(r) t := new(dns.TXT) t.Hdr = dns.RR_Header{ Name: q.Name, Rrtype: dns.TypeTXT, Class: dns.ClassNONE, } t.Txt = []string{err.Error()} m.Extra = append(m.Extra, t) continue } else if rr != nil { m.Answer = append(m.Answer, rr) } } m.Authoritative = true // recursion isn't really available, but it's apparently // necessary to set this to make nslookup happy. m.RecursionAvailable = true w.WriteMsg(m) }
func (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 (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 (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 *soa) TransferHandler(w dns.ResponseWriter, req *dns.Msg) { m := new(dns.Msg) m.SetReply(req) m.Answer = make([]dns.RR, 1) m.Answer[0] = test.SOA(fmt.Sprintf("%s IN SOA bla. bla. %d 0 0 0 0 ", testZone, s.serial)) w.WriteMsg(m) }
func handleSpecialNames(w dns.ResponseWriter, req *dns.Msg) bool { question := req.Question[0] nameLC := strings.ToLower(question.Name) for _, localRR := range localRRS { if nameLC == localRR.Name { m := new(dns.Msg) m.Id = req.Id m.Answer = []dns.RR{*localRR.RR} m.Response = true w.WriteMsg(m) return true } } if question.Qtype != dns.TypeANY { return false } m := new(dns.Msg) m.Id = req.Id hinfo := new(dns.HINFO) hinfo.Hdr = dns.RR_Header{Name: question.Name, Rrtype: dns.TypeHINFO, Class: dns.ClassINET, Ttl: 86400} hinfo.Cpu = "ANY is not supported any more" hinfo.Os = "See draft-jabley-dnsop-refuse-any" m.Answer = []dns.RR{hinfo} m.Response = true w.WriteMsg(m) return true }
func (l Logger) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) { state := middleware.State{W: w, Req: r} for _, rule := range l.Rules { if middleware.Name(rule.NameScope).Matches(state.Name()) { responseRecorder := middleware.NewResponseRecorder(w) rcode, err := l.Next.ServeDNS(ctx, responseRecorder, r) if rcode > 0 { // There was an error up the chain, but no response has been written yet. // The error must be handled here so the log entry will record the response size. if l.ErrorFunc != nil { l.ErrorFunc(responseRecorder, r, rcode) } else { rc := middleware.RcodeToString(rcode) answer := new(dns.Msg) answer.SetRcode(r, rcode) state.SizeAndDo(answer) metrics.Report(state, metrics.Dropped, rc, answer.Len(), time.Now()) w.WriteMsg(answer) } rcode = 0 } rep := middleware.NewReplacer(r, responseRecorder, CommonLogEmptyValue) rule.Log.Println(rep.Replace(rule.Format)) return rcode, err } } return l.Next.ServeDNS(ctx, w, r) }
func handleDNSRequest(w dns.ResponseWriter, r *dns.Msg) { if *debug { Log.Printf("handleRequest: message: %+v\n", r) } m := new(dns.Msg) m.SetReply(r) m.Compress = false switch r.Opcode { case dns.OpcodeQuery: parseQuery(m) case dns.OpcodeUpdate: for _, question := range r.Question { for _, rr := range r.Ns { updateRecord(rr, &question) } } } if r.IsTsig() != nil { if w.TsigStatus() == nil { m.SetTsig(r.Extra[len(r.Extra)-1].(*dns.TSIG).Hdr.Name, dns.HmacMD5, 300, time.Now().Unix()) } else { Log.Println("Status", w.TsigStatus().Error()) } } w.WriteMsg(m) }
func handle(writer dns.ResponseWriter, request *dns.Msg) { message := new(dns.Msg) message.SetReply(request) message.SetRcode(message, dns.RcodeSuccess) question := request.Question[0] switch request.Opcode { case dns.OpcodeNotify: log.Println(fmt.Sprintf("Recieved NOTIFY for %s", question.Name)) message = handle_notify(question, message, writer) case dns.OpcodeQuery: log.Println(fmt.Sprintf("Recieved QUERY for %s", question.Name)) message = handle_query(question, message, writer) default: message = handle_error(message, writer, "REFUSED") } // Apparently this dns library takes the question out on // certain RCodes, like REFUSED, which is not right. So we reinsert it. message.Question[0].Name = question.Name message.Question[0].Qtype = question.Qtype message.Question[0].Qclass = question.Qclass message.MsgHdr.Opcode = request.Opcode // Send an authoritative answer message.MsgHdr.Authoritative = true writer.WriteMsg(message) }
func (manager *DnsManager) dnsHandler(w dns.ResponseWriter, req *dns.Msg) { m := new(dns.Msg) m.SetReply(req) name := req.Question[0].Name name = strings.TrimSuffix(name, "."+manager.BaseName) manager.dbMutex.Lock() entry, ok := manager.db[name] manager.dbMutex.Unlock() if ok { switch req.Question[0].Qtype { case dns.TypeSRV: m.Answer = manager.makeAllSRV(entry) case dns.TypeA: m.Answer = manager.makeAllA(entry) if manager.PushSRV { m.Extra = manager.makeAllSRV(entry) } } } w.WriteMsg(m) }
// handlePtr is used to handle "reverse" DNS queries func (d *DNSServer) handlePtr(resp dns.ResponseWriter, req *dns.Msg) { q := req.Question[0] defer func(s time.Time) { d.logger.Printf("[DEBUG] dns: request for %v (%v) from client %s (%s)", q, time.Now().Sub(s), resp.RemoteAddr().String(), resp.RemoteAddr().Network()) }(time.Now()) // Setup the message response m := new(dns.Msg) m.SetReply(req) m.Authoritative = true m.RecursionAvailable = (len(d.recursors) > 0) // Only add the SOA if requested if req.Question[0].Qtype == dns.TypeSOA { d.addSOA(d.domain, m) } datacenter := d.agent.config.Datacenter // Get the QName without the domain suffix qName := strings.ToLower(dns.Fqdn(req.Question[0].Name)) args := structs.DCSpecificRequest{ Datacenter: datacenter, QueryOptions: structs.QueryOptions{ Token: d.agent.config.ACLToken, AllowStale: d.config.AllowStale, }, } var out structs.IndexedNodes // TODO: Replace ListNodes with an internal RPC that can do the filter // server side to avoid transferring the entire node list. if err := d.agent.RPC("Catalog.ListNodes", &args, &out); err == nil { for _, n := range out.Nodes { arpa, _ := dns.ReverseAddr(n.Address) if arpa == qName { ptr := &dns.PTR{ Hdr: dns.RR_Header{Name: q.Name, Rrtype: dns.TypePTR, Class: dns.ClassINET, Ttl: 0}, Ptr: fmt.Sprintf("%s.node.%s.%s", n.Node, datacenter, d.domain), } m.Answer = append(m.Answer, ptr) break } } } // nothing found locally, recurse if len(m.Answer) == 0 { d.handleRecurse(resp, req) return } // Write out the complete response if err := resp.WriteMsg(m); err != nil { d.logger.Printf("[WARN] dns: failed to respond: %v", err) } }
func (p ReverseProxy) ServeDNS(w dns.ResponseWriter, r *dns.Msg, extra []dns.RR) error { var ( reply *dns.Msg err error ) switch { case middleware.Proto(w) == "tcp": reply, err = middleware.Exchange(p.Client.TCP, r, p.Host) default: reply, err = middleware.Exchange(p.Client.UDP, r, p.Host) } if reply != nil && reply.Truncated { // Suppress proxy error for truncated responses err = nil } if err != nil { return err } reply.Compress = true reply.Id = r.Id w.WriteMsg(reply) return nil }
// resolver responds to all DNS A record requests with an address from addrpool, // maintaining a mapping to the domain's actual IP address. func resolver(w dns.ResponseWriter, req *dns.Msg) { msg, err := dns.Exchange(req, dnsserver) if err != nil { log.Printf("Couldn't query: %v", err) // TODO return error Msg return } for _, rr := range msg.Answer { // TODO do this for only one record, delete the others. if rr.Header().Rrtype == dns.TypeA { a := rr.(*dns.A) addrpool.Lock() addr, ok := addrpool.domains[a.Hdr.Name] // Maybe we should also Get it on ok to push it up the LRU cache. if !ok { addrpool.pool.RemoveOldest() addrpool.pool.Add(ip4touint32(addrpool.freeaddr), a.Hdr.Name) log.Printf("Adding %v -> %s", addrpool.freeaddr, a.Hdr.Name) addr = addrpool.freeaddr addrpool.domains[a.Hdr.Name] = addr } addrpool.Unlock() log.Println("Type A:", a.A) a.A = addr a.Hdr.Ttl = 1 } } w.WriteMsg(msg) }
// handleDomain handles DNS queries that come to the cluster func (d *DnsServer) handleDomain(w dns.ResponseWriter, r *dns.Msg) { dom, qType := parseQuestion(r) q := dns.TypeToString[qType] + " " + dom log.Printf("--> Internal: %s", q) m := new(dns.Msg) m.SetReply(r) m.Authoritative = true supported, found, recs := d.queryRR(qType, dom) if !supported { log.Printf("<-x %s: NOTIMP", q) m.SetRcode(r, dns.RcodeNotImplemented) // NOTIMP } else if !found { log.Printf("<-x %s: NXDOMAIN", q) m.SetRcode(r, dns.RcodeNameError) // NXDOMAIN } else { for _, rec := range recs { rr, err := rrtype.ToRR(qType, dom, rec) if err != nil { log.Printf("<-x %s SERVFAIL: record conv err: %v", q, err) m.SetRcode(r, dns.RcodeServerFailure) break } else { log.Printf("<-- %s: %s", q, rr.String()) m.Answer = append(m.Answer, rr) } } } w.WriteMsg(m) }
// handleTest is used to handle DNS queries in the ".consul." domain func (d *DNSServer) handleTest(resp dns.ResponseWriter, req *dns.Msg) { q := req.Question[0] defer func(s time.Time) { d.logger.Printf("[DEBUG] dns: request for %v (%v)", q, time.Now().Sub(s)) }(time.Now()) if !(q.Qtype == dns.TypeANY || q.Qtype == dns.TypeTXT) { return } if q.Name != testQuery { return } // Always respond with TXT "ok" m := new(dns.Msg) m.SetReply(req) m.Authoritative = true m.RecursionAvailable = true header := dns.RR_Header{Name: q.Name, Rrtype: dns.TypeTXT, Class: dns.ClassINET, Ttl: 0} txt := &dns.TXT{header, []string{"ok"}} m.Answer = append(m.Answer, txt) d.addSOA(consulDomain, m) if err := resp.WriteMsg(m); err != nil { d.logger.Printf("[WARN] dns: failed to respond: %v", err) } }
func (h *Handler) handleQuery(w dns.ResponseWriter, r *dns.Msg) { q := r.Question[0] m := &dns.Msg{} m.SetReply(r) switch q.Qtype { case dns.TypePTR: if q.Name == h.reverse { rr := &dns.PTR{} rr.Hdr = dns.RR_Header{Name: q.Name, Rrtype: dns.TypePTR, Class: dns.ClassINET, Ttl: 0} rr.Ptr = h.name m.Answer = append(m.Answer, rr) } case dns.TypeA: if q.Name == h.name { rr := &dns.A{} rr.Hdr = dns.RR_Header{Name: q.Name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 0} rr.A = h.ip m.Answer = append(m.Answer, rr) } } w.WriteMsg(m) }
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) }
// interceptRequest gets called upon each DNS request, and we determine // whether we want to deal with it or not func interceptRequest(w dns.ResponseWriter, r *dns.Msg) { m := r.Copy() err := error(nil) defer w.Close() if len(r.Question) < 1 { return } // Hijack the response to point to us instead if matchesCriteria(r.Question[0].Name) { fmt.Println("Matches!", r.Question[0].Name) if !(inAddressCache(r.Question[0].Name)) { updateAddressCache(r) } m = hijackResponse(r) // Pass it upstream, return the answer } else { //fmt.Println("Passing on ", r.Question[0].Name) m, err = upstreamLookup(r) if err != nil { fmt.Println("Error when passing request through upstream - network problem?") // in this instance, our response (m) has no answer } } w.WriteMsg(m) }
// reply writes the given dns.Msg out to the given dns.ResponseWriter, // compressing the message first and truncating it accordingly. func reply(w dns.ResponseWriter, m *dns.Msg) { m.Compress = true // https://github.com/mesosphere/mesos-dns/issues/{170,173,174} if err := w.WriteMsg(truncate(m, isUDP(w))); err != nil { logging.Error.Println(err) } }
// handlerFunc receives requests, looks up the result and returns what is found. func handlerFunc(res dns.ResponseWriter, req *dns.Msg) { message := new(dns.Msg) switch req.Opcode { case dns.OpcodeQuery: message.SetReply(req) message.Compress = false message.Answer = make([]dns.RR, 0) for _, question := range message.Question { answers := answerQuestion(strings.ToLower(question.Name), question.Qtype) if len(answers) > 0 { for i := range answers { message.Answer = append(message.Answer, answers[i]) } } else { // If there are no records, go back through and search for SOA records for _, question := range message.Question { answers := answerQuestion(strings.ToLower(question.Name), dns.TypeSOA) for i := range answers { message.Ns = append(message.Ns, answers[i]) } } } } if len(message.Answer) == 0 && len(message.Ns) == 0 { message.Rcode = dns.RcodeNameError } default: message = message.SetRcode(req, dns.RcodeNotImplemented) } res.WriteMsg(message) }