Beispiel #1
0
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
}
Beispiel #2
0
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)
	}
}
Beispiel #3
0
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()
	}
}
Beispiel #5
0
// 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
}
Beispiel #6
0
// 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)
}
Beispiel #7
0
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)
}
Beispiel #8
0
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
}
Beispiel #9
0
// 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
}
Beispiel #10
0
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)
		}
	}
}
Beispiel #11
0
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
}
Beispiel #12
0
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
}
Beispiel #13
0
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")
}
Beispiel #14
0
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
}
Beispiel #15
0
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
}
Beispiel #16
0
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")
}
Beispiel #17
0
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
}
Beispiel #18
0
// 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
}
Beispiel #19
0
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
}
Beispiel #20
0
// 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
	}
}
Beispiel #21
0
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
}
Beispiel #22
0
// 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
}
Beispiel #23
0
// 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))
		}
	}
}
Beispiel #24
0
// 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))
		}
	}
}
Beispiel #25
0
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)
}
Beispiel #26
0
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))
		}
	}
}
Beispiel #27
0
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)
}
Beispiel #28
0
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
}
Beispiel #29
0
// 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)
	}
}
Beispiel #30
0
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)
	}
}