Example #1
0
// 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)
}
Example #2
0
// 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)
	}
}
// 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)
}
Example #4
0
// 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)
	}
}
Example #5
0
// 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)
}
Example #6
0
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)
}
Example #7
0
// 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
}
Example #8
0
func (r *resolver) forwardQueryStart(w dns.ResponseWriter, msg *dns.Msg, queryID uint16) bool {
	proto := w.LocalAddr().Network()
	dnsID := uint16(rand.Intn(maxDNSID))

	cc := clientConn{
		dnsID:      queryID,
		respWriter: w,
	}

	r.queryLock.Lock()
	defer r.queryLock.Unlock()

	if r.count == maxConcurrent {
		return false
	}
	r.count++

	switch proto {
	case "tcp":
		break
	case "udp":
		for ok := true; ok == true; dnsID = uint16(rand.Intn(maxDNSID)) {
			_, ok = r.client[dnsID]
		}
		log.Debugf("client dns id %v, changed id %v", queryID, dnsID)
		r.client[dnsID] = cc
		msg.Id = dnsID
	default:
		log.Errorf("Invalid protocol..")
		return false
	}

	return true
}
Example #9
0
func (r *resolver) forwardQueryEnd(w dns.ResponseWriter, msg *dns.Msg) dns.ResponseWriter {
	var (
		cc clientConn
		ok bool
	)
	proto := w.LocalAddr().Network()

	r.queryLock.Lock()
	defer r.queryLock.Unlock()

	if r.count == 0 {
		log.Errorf("Invalid concurrent query count")
	} else {
		r.count--
	}

	switch proto {
	case "tcp":
		break
	case "udp":
		if cc, ok = r.client[msg.Id]; ok == false {
			log.Debugf("Can't retrieve client context for dns id %v", msg.Id)
			return nil
		}
		log.Debugf("dns msg id %v, client id %v", msg.Id, cc.dnsID)
		delete(r.client, msg.Id)
		msg.Id = cc.dnsID
		w = cc.respWriter
	default:
		log.Errorf("Invalid protocol")
		return nil
	}
	return w
}
Example #10
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)
}
Example #11
0
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)
}
Example #12
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)
}
Example #13
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)
}
Example #14
0
// Forwards a DNS request to the specified nameservers. On success, the
// original reply packet will be returned to the caller. On failure, a
// new packet will be returned with `RCODE` set to `SERVFAIL`.
// Even though the original `ResponseWriter` object is taken as an argument,
// this function does not send a reply to the client. Instead, the
// packet is returned for further processing by the caller.
func getServerReply(w dns.ResponseWriter, req *dns.Msg) *dns.Msg {
	if *verbose {
		log.Print("Forwarding ", req.Question[0].Name, "/", dns.Type(req.Question[0].Qtype).String())
	}

	// create a new DNS client

	client := &dns.Client{Net: "udp", ReadTimeout: 4 * time.Second, WriteTimeout: 4 * time.Second, SingleInflight: true}

	if _, tcp := w.RemoteAddr().(*net.TCPAddr); tcp {
		client.Net = "tcp"
	}

	var r *dns.Msg
	var err error

	// loop through the specified nameservers and forward them the request

	// the request ID is used as a starting point in order to introduce at least
	// some element of randomness, instead of always hitting the first nameserver

	for i := 0; i < len(nameservers); i++ {
		r, _, err = client.Exchange(req, nameservers[(int(req.Id)+i)%len(nameservers)])

		if err == nil {
			r.Compress = true

			return r
		}
	}

	log.Print("Failed to forward request.", err)
	return getEmptyMsg(w, req, dns.RcodeServerFailure)
}
Example #15
0
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)
}
Example #16
0
File: main.go Project: axw/jns
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)
}
Example #17
0
// 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)
}
Example #18
0
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)
	}
}
Example #19
0
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)
}
Example #20
0
func (h ENUMHandler) ServeDNS(writer dns.ResponseWriter, request *dns.Msg) {

	defer func(s time.Time) {
		h.Trace.Printf("dns request for %v (%s) (%v) from client %s (%s)",
			request.Question[0], "udp", time.Now().Sub(s), writer.RemoteAddr().String(),
			writer.RemoteAddr().Network())
	}(time.Now())

	if answer, err := h.createAnswer(request); err == nil {

		if answer == nil {
			h.Trace.Printf("no result found for %s", request.Question[0])
			notfound := &dns.Msg{}
			notfound.SetReply(request)
			notfound.SetRcode(request, dns.RcodeSuccess)
			writer.WriteMsg(notfound)
			return
		}

		if err := writer.WriteMsg(answer); err != nil {
			h.Error.Printf("error sending answer: %v", err)
		}

	} else {
		h.Error.Printf("[ERR] Error getting the answer: %v", err)
		error := &dns.Msg{}
		error.SetReply(request)
		error.SetRcode(request, dns.RcodeServerFailure)
		writer.WriteMsg(error)
	}

}
Example #21
0
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)
}
Example #22
0
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
}
Example #23
0
func (self *TrivialDnsServer) redirectQuery(w dns.ResponseWriter, r *dns.Msg, newName string) {
	self.Count("redirected_requests")
	if !strings.HasSuffix(newName, ".") {
		newName = newName + "."
	}

	newR := new(dns.Msg)
	newR.SetQuestion(dns.Fqdn(newName), dns.TypeA)

	if response, _, err := self.exchangeWithUpstream(newR); err == nil {
		ip := self.getSingleSimpleAnswer(response)
		if ip == nil {
			debug("%s redirect to %s yielded no answer", w.RemoteAddr(), newName)
			self.Count("redirected_nowhere")
			self.refuse(w, r)
			return
		}
		self.Count("redirected_successively")
		self.respondSuccessively(w, r, *ip)
	} else {
		self.Count("upstream_errors")
		self.refuse(w, r)
		log.Printf("%s: error: %s", w.RemoteAddr(), err)
	}
}
Example #24
0
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)
}
Example #25
0
// 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)
}
Example #26
0
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
}
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)
}
Example #28
0
// 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)
}
Example #29
0
// 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)
	}
}
Example #30
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)
}