func (s *DNSServer) doHandle(w dns.ResponseWriter, r *dns.Msg) *dns.Msg { m := new(dns.Msg) m.SetReply(r) // Send empty response for empty requests if len(r.Question) == 0 { m.Ns = s.createSOA() return m } switch r.Question[0].Qtype { case dns.TypePTR: s.handlePTRRequest(r, m) case dns.TypeMX: s.handleMXRequest(r, m) case dns.TypeA: s.handleARequest(r, m) case dns.TypeSOA: m.Answer = s.createSOA() default: m.Ns = s.createSOA() m.SetRcode(r, dns.RcodeNotImplemented) } return m }
func (s *DNSServer) handleReverseRequest(w dns.ResponseWriter, r *dns.Msg) { m := new(dns.Msg) m.SetReply(r) // Send empty response for empty requests if len(r.Question) == 0 { m.Ns = s.createSOA() w.WriteMsg(m) return } m.Answer = make([]dns.RR, 0, 2) query := r.Question[0].Name // trim off any trailing dot if query[len(query)-1] == '.' { query = query[:len(query)-1] } for service := range s.queryIp(query) { if r.Question[0].Qtype != dns.TypePTR { m.Ns = s.createSOA() w.WriteMsg(m) return } var ttl int if service.Ttl != -1 { ttl = service.Ttl } else { ttl = s.config.ttl } for domain := range s.listDomains(service) { rr := new(dns.PTR) rr.Hdr = dns.RR_Header{ Name: r.Question[0].Name, Rrtype: dns.TypePTR, Class: dns.ClassINET, Ttl: uint32(ttl), } rr.Ptr = domain m.Answer = append(m.Answer, rr) } } if len(m.Answer) != 0 { w.WriteMsg(m) } else { // We didn't find a record corresponding to the query, // try forwarding s.handleForward(w, r) } }
func (s *DNSServer) handleRequest(w dns.ResponseWriter, r *dns.Msg) { m := new(dns.Msg) m.SetReply(r) // Send empty response for empty requests if len(r.Question) == 0 { m.Ns = s.createSOA() w.WriteMsg(m) return } // respond to SOA requests if r.Question[0].Qtype == dns.TypeSOA { m.Answer = s.createSOA() w.WriteMsg(m) return } m.Answer = make([]dns.RR, 0, 2) query := r.Question[0].Name // trim off any trailing dot if query[len(query)-1] == '.' { query = query[:len(query)-1] } for service := range s.queryServices(query) { var rr dns.RR switch r.Question[0].Qtype { case dns.TypeA: rr = s.makeServiceA(r.Question[0].Name, service) case dns.TypeMX: rr = s.makeServiceMX(r.Question[0].Name, service) default: // this query type isn't supported, but we do have // a record with this name. Per RFC 4074 sec. 3, we // immediately return an empty NOERROR reply. m.Ns = s.createSOA() m.MsgHdr.Authoritative = true w.WriteMsg(m) return } m.Answer = append(m.Answer, rr) } // We didn't find a record corresponding to the query if len(m.Answer) == 0 { m.Ns = s.createSOA() m.SetRcode(r, dns.RcodeNameError) // NXDOMAIN } w.WriteMsg(m) }
// ServeDNS is the handler for DNS requests, responsible for parsing DNS request, possibly forwarding // it to a real dns server and returning a response. func (s *Server) ServeDNS(w dns.ResponseWriter, req *dns.Msg) { stats.RequestCount.Inc(1) q := req.Question[0] log.Printf("Received DNS Request for %q from %q", q.Name, w.RemoteAddr()) // If the query does not fall in our s.domain, forward it if !strings.HasSuffix(q.Name, dns.Fqdn(s.domain)) { s.ServeDNSForward(w, req) return } m := new(dns.Msg) m.SetReply(req) m.Authoritative = true m.RecursionAvailable = true m.Answer = make([]dns.RR, 0, 10) defer w.WriteMsg(m) if q.Qtype == dns.TypeANY || q.Qtype == dns.TypeSRV { records, extra, err := s.getSRVRecords(q) if err != nil { // We are authoritative for this name, but it does not exist: NXDOMAIN m.SetRcode(req, dns.RcodeNameError) m.Ns = s.createSOA() log.Println("Error: ", err) return } m.Answer = append(m.Answer, records...) m.Extra = append(m.Extra, extra...) } if q.Qtype == dns.TypeA || q.Qtype == dns.TypeAAAA { records, err := s.getARecords(q) if err != nil { m.SetRcode(req, dns.RcodeNameError) m.Ns = s.createSOA() log.Println("Error: ", err) return } m.Answer = append(m.Answer, records...) } if len(m.Answer) == 0 { // Send back a NODATA response m.Ns = s.createSOA() } }
// Construct a response for a single DNS request. func (ds *DjdnsServer) Handle(query *dns.Msg) (*dns.Msg, error) { response := new(dns.Msg) response.MsgHdr.Id = query.MsgHdr.Id response.Question = query.Question if len(query.Question) > 0 { // Ignore secondary questions question := query.Question[0] records, err := ds.GetRecords(question.Name) if err != nil { return nil, err } response.Answer = make([]dns.RR, len(records)) for i, record := range records { answer, err := record.ToDns() if err != nil { return nil, err } response.Answer[i] = answer } response.Ns = make([]dns.RR, 0) response.Extra = make([]dns.RR, 0) } return response, nil }
// 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) }
func rootZone(w dns.ResponseWriter, req *dns.Msg) { m := new(dns.Msg) m.SetReply(req) rr, _ := dns.NewRR(". 0 IN SOA a.root-servers.net. nstld.verisign-grs.com. 2016110600 1800 900 604800 86400") m.Ns = []dns.RR{rr} w.WriteMsg(m) }
func (s *server) NameError(req *dns.Msg) *dns.Msg { m := new(dns.Msg) m.SetRcode(req, dns.RcodeNameError) m.Ns = []dns.RR{s.NewSOA()} m.Ns[0].Header().Ttl = s.config.MinTtl return m }
// write adds the SOA record to message m in the namespaces section. func (s *soa) write(m *dns.Msg) { s.mux.RLock() defer s.mux.RUnlock() m.Ns = make([]dns.RR, 1) m.Ns[0] = s.soa }
func main() { runtime.GOMAXPROCS(runtime.NumCPU() * 4) for z, rr := range zones { rrx := rr.(*dns.SOA) // Needed to create the actual RR, and not an reference. dns.HandleFunc(z, func(w dns.ResponseWriter, r *dns.Msg) { m := new(dns.Msg) m.SetReply(r) m.Authoritative = true m.Ns = []dns.RR{rrx} w.WriteMsg(m) }) } go func() { err := dns.ListenAndServe(":8053", "tcp", nil) if err != nil { log.Fatal("Failed to set tcp listener %s\n", err.Error()) } }() go func() { err := dns.ListenAndServe(":8053", "udp", nil) if err != nil { log.Fatal("Failed to set udp listener %s\n", err.Error()) } }() sig := make(chan os.Signal) signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM) for { select { case s := <-sig: log.Fatalf("Signal (%d) received, stopping\n", s) } } }
func dedup(m *dns.Msg) *dns.Msg { // TODO(miek): expensive! m.Answer = dns.Dedup(m.Answer, nil) m.Ns = dns.Dedup(m.Ns, nil) m.Extra = dns.Dedup(m.Extra, nil) return m }
func (res *Resolver) handleEmpty(rs *records.RecordGenerator, name string, m, r *dns.Msg) error { qType := r.Question[0].Qtype switch qType { case dns.TypeSOA, dns.TypeNS, dns.TypeSRV: logging.CurLog.MesosSuccess.Inc() return nil } m.Rcode = dns.RcodeNameError if qType == dns.TypeAAAA && len(rs.SRVs[name])+len(rs.As[name]) > 0 { m.Rcode = dns.RcodeSuccess } logging.CurLog.MesosNXDomain.Inc() logging.VeryVerbose.Println("total A rrs:\t" + strconv.Itoa(len(rs.As))) logging.VeryVerbose.Println("failed looking for " + r.Question[0].String()) rr, err := res.formatSOA(r.Question[0].Name) if err != nil { return err } m.Ns = append(m.Ns, rr) return nil }
func (s *server) NoDataError(m, req *dns.Msg) { m.SetRcode(req, dns.RcodeSuccess) m.Ns = []dns.RR{s.NewSOA()} m.Ns[0].Header().Ttl = s.config.MinTtl StatsNoDataCount.Inc(1) promErrorCount.WithLabelValues("nodata") }
func findApex(m *dns.Msg, z *dns.Zone) { apex, exact := z.Find(z.Origin) if exact { // What if we don't have this? TODO(mg) m.Ns = apex.RR[dns.TypeSOA] } return }
func findApex(m *dns.Msg, z *dns.Zone) { apex := z.Apex() if apex != nil { // What if we don't have this? TODO(mg) m.Ns = apex.RR[dns.TypeSOA] } return }
func (s *server) NameError(m, req *dns.Msg) { m.SetRcode(req, dns.RcodeNameError) m.Ns = []dns.RR{s.NewSOA()} m.Ns[0].Header().Ttl = s.config.MinTtl StatsNameErrorCount.Inc(1) promErrorCount.WithLabelValues("nxdomain") }
func (res *Resolver) handleSOA(m, r *dns.Msg) error { rr, err := res.formatSOA(r.Question[0].Name) if err != nil { return err } m.Ns = append(m.Ns, rr) return nil }
// NoData write a nodata response to the client. func (k Kubernetes) Err(zone string, rcode int, state middleware.State) (int, error) { m := new(dns.Msg) m.SetRcode(state.Req, rcode) m.Ns = []dns.RR{k.SOA(zone, state)} state.SizeAndDo(m) state.W.WriteMsg(m) return rcode, nil }
func (res *Resolver) handleNS(m, r *dns.Msg) error { rr, err := res.formatNS(r.Question[0].Name) logging.Error.Println("NS request") if err != nil { return err } m.Ns = append(m.Ns, rr) return nil }
// Perform probing & announcement //TODO: implement a proper probing & conflict resolution func (s *Server) probe() { q := new(dns.Msg) q.SetQuestion(s.service.ServiceInstanceName(), dns.TypePTR) q.RecursionDesired = false srv := &dns.SRV{ Hdr: dns.RR_Header{ Name: s.service.ServiceInstanceName(), Rrtype: dns.TypeSRV, Class: dns.ClassINET, Ttl: s.ttl, }, Priority: 0, Weight: 0, Port: uint16(s.service.Port), Target: s.service.HostName, } txt := &dns.TXT{ Hdr: dns.RR_Header{ Name: s.service.ServiceInstanceName(), Rrtype: dns.TypeTXT, Class: dns.ClassINET, Ttl: s.ttl, }, Txt: s.service.Text, } q.Ns = []dns.RR{srv, txt} randomizer := rand.New(rand.NewSource(time.Now().UnixNano())) for i := 0; i < 3; i++ { if err := s.multicastResponse(q); err != nil { log.Println("[ERR] bonjour: failed to send probe:", err.Error()) } time.Sleep(time.Duration(randomizer.Intn(250)) * time.Millisecond) } resp := new(dns.Msg) resp.MsgHdr.Response = true resp.Answer = []dns.RR{} resp.Extra = []dns.RR{} s.composeLookupAnswers(resp, s.ttl) // From RFC6762 // The Multicast DNS responder MUST send at least two unsolicited // responses, one second apart. To provide increased robustness against // packet loss, a responder MAY send up to eight unsolicited responses, // provided that the interval between unsolicited responses increases by // at least a factor of two with every response sent. timeout := 1 * time.Second for i := 0; i < 3; i++ { if err := s.multicastResponse(resp); err != nil { log.Println("[ERR] bonjour: failed to send announcement:", err.Error()) } time.Sleep(timeout) timeout *= 2 } }
func cacheMsg(m *dns.Msg, tc cacheTestCase) *dns.Msg { m.RecursionAvailable = tc.RecursionAvailable m.AuthenticatedData = tc.AuthenticatedData m.Authoritative = tc.Authoritative m.Truncated = tc.Truncated m.Answer = tc.in.Answer m.Ns = tc.in.Ns // m.Extra = tc.in.Extra , not the OPT record! return m }
// Sign signs a message m, it takes care of negative or nodata responses as // well by synthesising NSEC3 records. It will also cache the signatures, using // a hash of the signed data as a key. // We also fake the origin TTL in the signature, because we don't want to // throw away signatures when services decide to have longer TTL. So we just // set the origTTL to 60. // TODO(miek): revisit origTTL func (s *server) Sign(m *dns.Msg, bufsize uint16) { now := time.Now().UTC() incep := uint32(now.Add(-3 * time.Hour).Unix()) // 2+1 hours, be sure to catch daylight saving time and such expir := uint32(now.Add(7 * 24 * time.Hour).Unix()) // sign for a week defer func() { promCacheSize.WithLabelValues("signature").Set(float64(s.scache.Size())) }() for _, r := range rrSets(m.Answer) { if r[0].Header().Rrtype == dns.TypeRRSIG { continue } if !dns.IsSubDomain(s.config.Domain, r[0].Header().Name) { continue } if sig, err := s.signSet(r, now, incep, expir); err == nil { m.Answer = append(m.Answer, sig) } } for _, r := range rrSets(m.Ns) { if r[0].Header().Rrtype == dns.TypeRRSIG { continue } if !dns.IsSubDomain(s.config.Domain, r[0].Header().Name) { continue } if sig, err := s.signSet(r, now, incep, expir); err == nil { m.Ns = append(m.Ns, sig) } } for _, r := range rrSets(m.Extra) { if r[0].Header().Rrtype == dns.TypeRRSIG || r[0].Header().Rrtype == dns.TypeOPT { continue } if !dns.IsSubDomain(s.config.Domain, r[0].Header().Name) { continue } if sig, err := s.signSet(r, now, incep, expir); err == nil { m.Extra = append(m.Extra, sig) } } if bufsize >= 512 || bufsize <= 4096 { // TCP here? promErrorCount.WithLabelValues("truncated").Inc() m.Truncated = m.Len() > int(bufsize) } o := new(dns.OPT) o.Hdr.Name = "." o.Hdr.Rrtype = dns.TypeOPT o.SetDo() o.SetUDPSize(4096) // TODO(miek): echo client m.Extra = append(m.Extra, o) return }
// Denial creates (if needed) NSEC3 records that are included in the reply. func (s *server) Denial(m *dns.Msg) { if m.Rcode == dns.RcodeNameError { // Deny Qname nsec3 nsec3 := s.NewNSEC3NameError(m.Question[0].Name) m.Ns = append(m.Ns, nsec3) if nsec3.Hdr.Name != s.config.ClosestEncloser.Hdr.Name { m.Ns = append(m.Ns, s.config.ClosestEncloser) } if nsec3.Hdr.Name != s.config.DenyWildcard.Hdr.Name { m.Ns = append(m.Ns, s.config.DenyWildcard) } } if m.Rcode == dns.RcodeSuccess && len(m.Ns) == 1 { // NODATA if _, ok := m.Ns[0].(*dns.SOA); ok { m.Ns = append(m.Ns, s.NewNSEC3NoData(m.Question[0].Name)) } } }
// Denial creates (if needed) NSEC3 records that are included in the reply. func (s *server) Denial(m *dns.Msg) { if m.Rcode == dns.RcodeNameError { // qname nsec nsec1 := s.NewNSEC3(m.Question[0].Name) m.Ns = append(m.Ns, nsec1) // wildcard nsec idx := dns.Split(m.Question[0].Name) wildcard := "*." + m.Question[0].Name[idx[0]:] nsec2 := s.NewNSEC3(wildcard) if nsec1.Hdr.Name != nsec2.Hdr.Name || nsec1.NextDomain != nsec2.NextDomain { // different NSEC3, add it m.Ns = append(m.Ns, nsec2) } } if m.Rcode == dns.RcodeSuccess && len(m.Ns) == 1 { if _, ok := m.Ns[0].(*dns.SOA); ok { m.Ns = append(m.Ns, s.NewNSEC3(m.Question[0].Name)) } } }
func (r *RoundRobinResponseWriter) WriteMsg(res *dns.Msg) error { if res.Rcode != dns.RcodeSuccess { return r.ResponseWriter.WriteMsg(res) } res.Answer = roundRobin(res.Answer) res.Ns = roundRobin(res.Ns) res.Extra = roundRobin(res.Extra) return r.ResponseWriter.WriteMsg(res) }
func (s *server) Denial(m *dns.Msg) { if m.Rcode == dns.RcodeNameError { // ce is qname minus the left label idx := dns.Split(m.Question[0].Name) ce := m.Question[0].Name[idx[1]:] nsec3ce, nsec3wildcard := newNSEC3CEandWildcard(s.config.Domain, ce, s.config.MinTtl) // Add ce and wildcard m.Ns = append(m.Ns, nsec3ce) m.Ns = append(m.Ns, nsec3wildcard) // Deny Qname nsec3 m.Ns = append(m.Ns, s.newNSEC3NameError(m.Question[0].Name)) } if m.Rcode == dns.RcodeSuccess && len(m.Ns) == 1 { // NODATA if _, ok := m.Ns[0].(*dns.SOA); ok { m.Ns = append(m.Ns, s.newNSEC3NoData(m.Question[0].Name)) } } }
func (s *Service) handle(w dns.ResponseWriter, r *dns.Msg) { reply := new(dns.Msg) reply.SetReply(r) reply.Authoritative = true for _, q := range r.Question { answers := s.answer(q) if len(answers) > 0 { reply.Answer = append(reply.Answer, answers...) } else { reply.Ns = append(reply.Ns, s.soa(q)) } } w.WriteMsg(reply) }
func serve(w dns.ResponseWriter, req *dns.Msg, z *dns.Zone) { if z == nil { panic("fksd: no zone") } m := new(dns.Msg) // Just NACK ANYs if req.Question[0].Qtype == dns.TypeANY { m.SetRcode(req, dns.RcodeServerFailure) ednsFromRequest(req, m) w.WriteMsg(m) return } logPrintf("[zone %s] incoming %s %s %d from %s\n", z.Origin, req.Question[0].Name, dns.TypeToString[req.Question[0].Qtype], req.MsgHdr.Id, w.RemoteAddr()) node, exact, ref := z.FindFunc(req.Question[0].Name, func(n interface{}) bool { return n.(*dns.ZoneData).NonAuth }) if ref { logPrintf("[zone %s] referral due\n", z.Origin) m.SetReply(req) m.Ns = node.RR[dns.TypeNS] for _, n := range m.Ns { if dns.IsSubDomain(n.(*dns.NS).Ns, n.Header().Name) { findGlue(m, z, n.(*dns.NS).Ns) } } ednsFromRequest(req, m) w.WriteMsg(m) return } if exact { exactMatch(w, req, m, z, node) return } // Not an exact match nor an referral if z.Wildcard > 0 { lx := dns.SplitLabels(req.Question[0].Name) wc := "*." + strings.Join(lx[1:], ".") node, exact = z.Find(wc) if exact { logPrintf("[zone %s] wildcard answer\n", z.Origin) // as exact,but not complete -- only the last part } } nameerror(w, m, req) return }
// handleDnsCNAME modifies m to respond to a CNAME query for name by looking it up // from the repository. NXDOMAIN and the SOA record are returned for nonexisting entries. func (s *server) handleDnsCNAME(name host, m *dns.Msg) { s.mux.RLock() defer s.mux.RUnlock() rec := s.repo.get(name) if rec != nil && rec.cname != nil { m.Answer = append(m.Answer, rec.cname) m.Ns = nil m.MsgHdr.Rcode = dns.RcodeSuccess } else { m.Answer = nil m.MsgHdr.Rcode = dns.RcodeNameError s.soa.write(m) } }
func (s *DNSServer) handleForward(w dns.ResponseWriter, r *dns.Msg) { // Otherwise just forward the request to another server c := new(dns.Client) if in, _, err := c.Exchange(r, s.config.nameserver); err != nil { log.Print(err) m := new(dns.Msg) m.SetReply(r) m.Ns = s.createSOA() m.SetRcode(r, dns.RcodeRefused) // REFUSED w.WriteMsg(m) } else { w.WriteMsg(in) } }