Ejemplo n.º 1
0
func (c *Config) GenerateServeDNS(hostname string) func(dns.ResponseWriter, *dns.Msg) {
	if len(hostname) > 0 {
		if hostname[len(hostname)-1] != '.' {
			hostname += "."
		}
	}

	return func(w dns.ResponseWriter, r *dns.Msg) {
		m := new(dns.Msg)
		m.SetReply(r)
		m.Authoritative = true

		ip, err := c.GetOrLaunchInstance()
		if err != nil {
			// TODO: error handling
			log.Println("Error in GetOrLaunchInstance:", err)
			w.Close()
			return
		}

		rr := new(dns.A)
		rr.Hdr = dns.RR_Header{Name: hostname, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: uint32(c.MaxIdleTime.Seconds())}
		rr.A = ip

		m.Answer = []dns.RR{rr}
		w.WriteMsg(m)
	}
}
Ejemplo n.º 2
0
func (r *resolver) handleIPQuery(name string, query *dns.Msg, ipType int) (*dns.Msg, error) {
	addr, ipv6Miss := r.sb.ResolveName(name, ipType)
	if addr == nil && ipv6Miss {
		// Send a reply without any Answer sections
		log.Debugf("Lookup name %s present without IPv6 address", name)
		resp := createRespMsg(query)
		return resp, nil
	}
	if addr == nil {
		return nil, nil
	}

	log.Debugf("Lookup for %s: IP %v", name, addr)

	resp := createRespMsg(query)
	if len(addr) > 1 {
		addr = shuffleAddr(addr)
	}
	if ipType == types.IPv4 {
		for _, ip := range addr {
			rr := new(dns.A)
			rr.Hdr = dns.RR_Header{Name: name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: respTTL}
			rr.A = ip
			resp.Answer = append(resp.Answer, rr)
		}
	} else {
		for _, ip := range addr {
			rr := new(dns.AAAA)
			rr.Hdr = dns.RR_Header{Name: name, Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Ttl: respTTL}
			rr.AAAA = ip
			resp.Answer = append(resp.Answer, rr)
		}
	}
	return resp, nil
}
Ejemplo n.º 3
0
func (s *DNSServer) handleARequest(r *dns.Msg, m *dns.Msg) {
	m.Answer = make([]dns.RR, 0, 2)
	query := r.Question[0].Name

	if query[len(query)-1] == '.' {
		query = query[:len(query)-1]
	}

	for service := range s.queryServices(query) {
		rr := new(dns.A)

		var ttl int
		if service.Ttl != -1 {
			ttl = service.Ttl
		} else {
			ttl = s.config.ttl
		}

		rr.Hdr = dns.RR_Header{
			Name:   r.Question[0].Name,
			Rrtype: dns.TypeA,
			Class:  dns.ClassINET,
			Ttl:    uint32(ttl),
		}
		rr.A = service.Ip
		m.Answer = append(m.Answer, rr)
	}
}
Ejemplo n.º 4
0
func (r *resolver) handleIPQuery(name string, query *dns.Msg, ipType int) (*dns.Msg, error) {
	addr := r.sb.ResolveName(name, ipType)
	if addr == nil {
		return nil, nil
	}

	log.Debugf("Lookup for %s: IP %v", name, addr)

	resp := new(dns.Msg)
	resp.SetReply(query)
	setCommonFlags(resp)

	if len(addr) > 1 {
		addr = shuffleAddr(addr)
	}
	if ipType == netutils.IPv4 {
		for _, ip := range addr {
			rr := new(dns.A)
			rr.Hdr = dns.RR_Header{Name: name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: respTTL}
			rr.A = ip
			resp.Answer = append(resp.Answer, rr)
		}
	} else {
		for _, ip := range addr {
			rr := new(dns.AAAA)
			rr.Hdr = dns.RR_Header{Name: name, Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Ttl: respTTL}
			rr.AAAA = ip
			resp.Answer = append(resp.Answer, rr)
		}
	}
	return resp, nil
}
Ejemplo n.º 5
0
func (r *resolver) handleSRVQuery(svc string, query *dns.Msg) (*dns.Msg, error) {

	srv, ip := r.backend.ResolveService(svc)

	if len(srv) == 0 {
		return nil, nil
	}
	if len(srv) != len(ip) {
		return nil, fmt.Errorf("invalid reply for SRV query %s", svc)
	}

	resp := createRespMsg(query)

	for i, r := range srv {
		rr := new(dns.SRV)
		rr.Hdr = dns.RR_Header{Name: svc, Rrtype: dns.TypePTR, Class: dns.ClassINET, Ttl: respTTL}
		rr.Port = r.Port
		rr.Target = r.Target
		resp.Answer = append(resp.Answer, rr)

		rr1 := new(dns.A)
		rr1.Hdr = dns.RR_Header{Name: r.Target, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: respTTL}
		rr1.A = ip[i]
		resp.Extra = append(resp.Extra, rr1)
	}
	return resp, nil

}
Ejemplo n.º 6
0
func answerA(q dns.Question, value net.IP) dns.RR {
	answer := new(dns.A)
	answer.Header().Name = q.Name
	answer.Header().Rrtype = dns.TypeA
	answer.Header().Class = dns.ClassINET
	answer.A = value
	return answer
}
Ejemplo n.º 7
0
func answerA(q *dns.Question, v *DNSValue) dns.RR {
	answer := new(dns.A)
	answer.Header().Name = q.Name
	answer.Header().Rrtype = dns.TypeA
	answer.Header().Class = dns.ClassINET
	answer.A = net.ParseIP(v.Value)
	return answer
}
Ejemplo n.º 8
0
// DNS requests go to this function
func dnsHandle(w dns.ResponseWriter, r *dns.Msg) {
	name := r.Question[0].Name
	if !namePattern.MatchString(name) {
		kilog.Debug("%v does not match pattern, forwarding", name)
		dnsForward(w, r)
		return
	}
	// otherwise
	kilog.Debug("%v matches pattern, handling", name)
	dnsLock.Lock()
	defer dnsLock.Unlock()
	// check in table first
	fakeIP, ok := nameToIP[name]
	if !ok {
		// place in table
		var nwIP string
		for {
			haha := ipAlloc().String()
			_, exists := ipToName[haha]
			if exists {
				continue
			}
			nwIP = haha
			break
		}
		fakeIP = nwIP
		nameToIP[name] = fakeIP
		ipToName[fakeIP] = name
		// remove in 30 minutes
		go func() {
			time.Sleep(time.Minute * 30)
			dnsLock.Lock()
			defer dnsLock.Unlock()
			delete(nameToIP, name)
			delete(ipToName, fakeIP)
		}()
	}
	// return the fake IP to the user
	resp := new(dns.A)
	resp.Hdr.Name = name
	resp.Hdr.Ttl = 1 // very short
	resp.Hdr.Class = dns.ClassINET
	resp.Hdr.Rrtype = dns.TypeA
	resp.A = net.ParseIP(fakeIP)

	towrite := new(dns.Msg)
	towrite.Id = r.Id
	towrite.RecursionAvailable = true
	towrite.RecursionDesired = true
	towrite.Response = true
	towrite.Question = r.Question
	towrite.Answer = make([]dns.RR, 1)
	towrite.Answer[0] = resp
	w.WriteMsg(towrite)
	kilog.Debug("returning mapping %v -> %v", name, fakeIP)
}
Ejemplo n.º 9
0
func newRR(host string, addr net.IP) dns.RR {
	rr := new(dns.A)
	rr.Hdr = dns.RR_Header{
		Name:   host,
		Rrtype: dns.TypeA,
		Class:  dns.ClassINET,
		Ttl:    0}
	rr.A = addr.To4()
	return rr
}
Ejemplo n.º 10
0
// hijackResponse returns a modified version on the input dns.Msg with the A record modified
// to point to our server
func hijackResponse(r *dns.Msg) (m *dns.Msg) {
	m = new(dns.Msg)
	m.SetReply(r)
	m.Answer = make([]dns.RR, 1)

	rr := new(dns.A)
	rr.Hdr = dns.RR_Header{Name: m.Question[0].Name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 600}
	rr.A = net.ParseIP(config.EXTERNAL_ADDRESS)
	m.Answer[0] = rr
	return m
}
Ejemplo n.º 11
0
func dnsAddressRecord(query *dns.Msg, name string, addrs []net.IP) *dns.Msg {
	resp := new(dns.Msg)
	resp.SetReply(query)
	for _, addr := range addrs {
		rr := new(dns.A)
		rr.Hdr = dns.RR_Header{Name: name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 0}
		rr.A = addr

		resp.Answer = append(resp.Answer, rr)
	}
	return resp
}
Ejemplo n.º 12
0
func (r *resolver) handleIPv4Query(name string, query *dns.Msg) (*dns.Msg, error) {
	addr := r.sb.ResolveName(name)
	if addr == nil {
		return nil, nil
	}

	log.Debugf("Lookup for %s: IP %s", name, addr.String())

	resp := new(dns.Msg)
	resp.SetReply(query)

	rr := new(dns.A)
	rr.Hdr = dns.RR_Header{Name: name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: respTTL}
	rr.A = addr
	resp.Answer = append(resp.Answer, rr)
	return resp, nil
}
Ejemplo n.º 13
0
/* ----------------------------------------------------------------------------
FUNCTION

Name:		Serve Response

Prototype:	func serveResponse(w dns.ResponseWriter, r *dns.Msg)

Developer:	Andrew Burian

Created On:	2015-09-24

Parameters:
	w dns.ResponseWriter
		the writer that will respond to the dns query
	r dns.Msg
		the dns query to respond to

Return Values:
	(none)

Description:
	Handles a single dns request by generating and writing
	a response to the provided writer.
	Also strips out the contained data and sends it over a
	channel

Revisions:
	(none)
---------------------------------------------------------------------------- */
func serveResponse(w dns.ResponseWriter, r *dns.Msg) {

	// create a message to respond with
	respMsg := new(dns.Msg)

	// set this message to be a response to the first
	respMsg.SetReply(r)

	// create a new record to respond with
	respRec := new(dns.A)
	respRec.Hdr = dns.RR_Header{
		Name:   r.Question[0].Name,
		Rrtype: dns.TypeA,
		Class:  dns.ClassINET,
		Ttl:    0} // 0 TTL to avoid caching

	// pseudo random IP
	rand_bytes := make([]byte, 4)
	rand.Read(rand_bytes)
	respRec.A = rand_bytes

	respMsg.Answer = append(respMsg.Answer, respRec)

	w.WriteMsg(respMsg)

	// now that the response has been handled
	// process the covert data

	// get the data from the query
	data := (strings.Split(r.Question[0].Name, "."))[0]

	// create the new message channel
	datachan := make(chan byte, len(data))

	// send it to the main
	messages <- datachan

	// read all the bytes into the channel
	for _, b := range []byte(data) {
		datachan <- b
	}

	close(datachan)

}
Ejemplo n.º 14
0
func route(w dns.ResponseWriter, req *dns.Msg) {
	if len(req.Question) != 1 {
		failWithRcode(w, req, dns.RcodeRefused)
		return
	}
	question := req.Question[0]
	qtype := question.Qtype
	if question.Qclass != dns.ClassINET {
		failWithRcode(w, req, dns.RcodeRefused)
		return
	}
	remoteIP := w.RemoteAddr().(*net.UDPAddr).IP
	m := new(dns.Msg)
	m.Id = req.Id
	switch qtype {
	case dns.TypeA:
		if remoteIP4 := remoteIP.To4(); remoteIP4 != nil {
			rr := new(dns.A)
			rr.Hdr = dns.RR_Header{Name: question.Name, Rrtype: question.Qtype,
				Class: dns.ClassINET, Ttl: 10}
			rr.A = remoteIP4
			m.Answer = []dns.RR{rr}
		}
	case dns.TypeAAAA:
		if remoteIP16 := remoteIP.To16(); remoteIP16 != nil {
			rr := new(dns.AAAA)
			rr.Hdr = dns.RR_Header{Name: question.Name, Rrtype: question.Qtype,
				Class: dns.ClassINET, Ttl: 10}
			rr.AAAA = remoteIP16
			m.Answer = []dns.RR{rr}
		}
	case dns.TypeTXT:
		rr := new(dns.TXT)
		rr.Hdr = dns.RR_Header{Name: question.Name, Rrtype: question.Qtype,
			Class: dns.ClassINET, Ttl: 10}
		rr.Txt = []string{fmt.Sprintf("Resolver IP: %v", remoteIP.String())}
		m.Answer = []dns.RR{rr}
	}
	m.Question = req.Question
	m.Response = true
	m.Authoritative = true
	w.WriteMsg(m)
}
Ejemplo n.º 15
0
func (s *SenseDNS) fillWithData(pairs api.KVPairs, network string) {
	zs := s.dnsServer.zones
	zs.Lock()
	defer zs.Unlock()
	key := s.dnsServer.getNetDomain(network)
	zs.store[key] = make(map[dns.RR_Header][]dns.RR)
	for _, value := range pairs {
		path := strings.Split(value.Key, "/")
		hostname := fmt.Sprintf("%s.%s.%s", path[3], network, s.dnsServer.networkTLD)
		ip := string(value.Value)
		rr := new(dns.A)
		rr.A = net.ParseIP(ip)
		rr.Hdr = dns.RR_Header{Name: dns.Fqdn(hostname), Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 3600}
		key2 := dns.RR_Header{Name: dns.Fqdn(rr.Header().Name), Rrtype: rr.Header().Rrtype, Class: rr.Header().Class}
		zs.store[key][key2] = append(zs.store[key][key2], rr)
	}
	if log.Level == logrus.DebugLevel {
		s.dnsServer.printRoutingTable()
	}
}
Ejemplo n.º 16
0
func (s *DNSServer) makeServiceA(n string, service *Service) dns.RR {
	rr := new(dns.A)

	var ttl int
	if service.Ttl != -1 {
		ttl = service.Ttl
	} else {
		ttl = s.config.ttl
	}

	rr.Hdr = dns.RR_Header{
		Name:   n,
		Rrtype: dns.TypeA,
		Class:  dns.ClassINET,
		Ttl:    uint32(ttl),
	}

	rr.A = service.Ip

	return rr
}
Ejemplo n.º 17
0
func handleRequest(w dns.ResponseWriter, r *dns.Msg) {
	q := r.Question[0]

	info := fmt.Sprintf("Question: Type=%s Class=%s Name=%s", dns.TypeToString[q.Qtype], dns.ClassToString[q.Qclass], q.Name)

	if q.Qtype == dns.TypeA && q.Qclass == dns.ClassINET {
		m := new(dns.Msg)
		m.SetReply(r)
		a := new(dns.A)
		a.Hdr = dns.RR_Header{Name: q.Name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 600}
		a.A = resolveIP
		m.Answer = []dns.RR{a}
		w.WriteMsg(m)
		log.Printf("%s (RESOLVED)\n", info)
	} else {
		m := new(dns.Msg)
		m.SetReply(r)
		m.Rcode = dns.RcodeNameError // NXDOMAIN
		w.WriteMsg(m)
		log.Printf("%s (NXDOMAIN)\n", info)
	}
}
Ejemplo n.º 18
0
func dnsHandler(w dns.ResponseWriter, r *dns.Msg) {
	defer w.Close()
	m := new(dns.Msg)
	m.SetReply(r)
	m.Compress = false

	for _, q := range r.Question {
		fmt.Printf("dns-srv: Query -- [%s] %s\n", q.Name, dns.TypeToString[q.Qtype])
		switch q.Qtype {
		case dns.TypeA:
			record := new(dns.A)
			record.Hdr = dns.RR_Header{
				Name:   q.Name,
				Rrtype: dns.TypeA,
				Class:  dns.ClassINET,
				Ttl:    0,
			}
			record.A = net.ParseIP("127.0.0.1")

			m.Answer = append(m.Answer, record)
		case dns.TypeMX:
			record := new(dns.MX)
			record.Hdr = dns.RR_Header{
				Name:   q.Name,
				Rrtype: dns.TypeMX,
				Class:  dns.ClassINET,
				Ttl:    0,
			}
			record.Mx = "mail." + q.Name
			record.Preference = 10

			m.Answer = append(m.Answer, record)
		}
	}

	w.WriteMsg(m)
	return
}
Ejemplo n.º 19
0
func (c *config) flattenCNAME(in *dns.CNAME) ([]dns.RR, error) { // TODO: cache CNAME lookups
	h := in.Header()
	answers := []dns.RR{}
	m := new(dns.Msg)
	m.SetQuestion(in.Target, dns.TypeA)
	m.RecursionDesired = true
	d := new(dns.Client)
	record, _, err := d.Exchange(m, c.resolver) // TODO: try multiple resolvers
	if err != nil {
		return nil, err
	}
	if record == nil || record.Rcode == dns.RcodeNameError || record.Rcode != dns.RcodeSuccess {
		return nil, fmt.Errorf("Record error code %s: %s", record.Rcode, err.Error())
	}
	for _, a := range record.Answer {
		if r, ok := a.(*dns.A); ok {
			out := new(dns.A)
			out.Hdr = dns.RR_Header{Name: h.Name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 300}
			out.A = r.A
			answers = append(answers, out)
		}
	}
	return answers, nil
}
Ejemplo n.º 20
0
func (s *server) AddressRecords(q dns.Question, name string) (records []dns.RR, err error) {
	results, err := s.hosts.FindHosts(name)
	if err != nil {
		return nil, err
	}

	for _, ip := range results {
		switch {
		case ip.To4() != nil && (q.Qtype == dns.TypeA || q.Qtype == dns.TypeANY):
			r := new(dns.A)
			r.Hdr = dns.RR_Header{Name: q.Name, Rrtype: dns.TypeA,
				Class: dns.ClassINET, Ttl: s.config.HostsTtl}
			r.A = ip.To4()
			records = append(records, r)
		case ip.To4() == nil && (q.Qtype == dns.TypeAAAA || q.Qtype == dns.TypeANY):
			r := new(dns.AAAA)
			r.Hdr = dns.RR_Header{Name: q.Name, Rrtype: dns.TypeAAAA,
				Class: dns.ClassINET, Ttl: s.config.HostsTtl}
			r.AAAA = ip.To16()
			records = append(records, r)
		}
	}
	return records, nil
}
Ejemplo n.º 21
0
func proxyServe(w dns.ResponseWriter, req *dns.Msg) {
	var (
		key       string
		m         *dns.Msg
		err       error
		tried     bool
		data      []byte
		id        uint16
		query     []string
		questions []dns.Question
		used      string
	)

	defer func() {
		if err := recover(); err != nil {
			fmt.Println(err)
		}
	}()

	if req.MsgHdr.Response == true {
		return
	}

	query = make([]string, len(req.Question))

	for i, q := range req.Question {
		if q.Qtype != dns.TypeAAAA || *ipv6 {
			questions = append(questions, q)
		}
		query[i] = fmt.Sprintf("(%s %s %s)", q.Name, dns.ClassToString[q.Qclass], dns.TypeToString[q.Qtype])
	}

	if len(questions) == 0 {
		return
	}

	//check local map
	dom := req.Question[0].Name
	domain := dom[0 : len(dom)-1]

	v, ok := localMap[domain]

	if ok {
		tm := new(dns.Msg)
		tm.Id = req.Id
		tm.Answer = make([]dns.RR, 1)
		dom := req.Question[0].Name
		trr := new(dns.A)
		trr.Hdr = dns.RR_Header{Name: dom, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 5}
		trr.A = net.ParseIP(v)
		tm.Answer[0] = trr

		err = w.WriteMsg(tm)

		if DEBUG > 0 {
			log.Printf("hosts:%v ip:%v\n", domain, v)
		}

		goto end
	}

	req.Question = questions
	id = req.Id

	req.Id = 0
	key = toMd5(req.String())
	req.Id = id

	if ENCACHE {
		if reply, ok := conn.Get(key); ok {
			data, _ = reply.([]byte)
		}

		if data != nil && len(data) > 0 {
			m = &dns.Msg{}
			m.Unpack(data)
			m.Id = id
			err = w.WriteMsg(m)

			if DEBUG > 0 {
				log.Printf("id:%5d cache: HIT %v\n", id, query)
			}

			goto end
		} else {
			if DEBUG > 0 {
				log.Printf("id: %5d cache: MISS %v\n", id, query)
			}
		}
	}

	for i, parts := range DNS {
		dns := parts[0]
		proto := parts[1]

		tried = i > 0

		if DEBUG > 0 {
			if tried {
				log.Printf("id: 5%d try: %v %s %s\n", id, query, dns, proto)
			} else {
				log.Printf("id: 5%d resolve: %v %s %s\n", id, query, dns, proto)
			}
		}

		client := clientUDP
		if proto == "tcp" {
			client = clientTCP
		}

		m, _, err = client.Exchange(req, dns)

		if err == nil && len(m.Answer) > 0 {
			used = dns
			break
		}
	}

	if err == nil {
		if DEBUG > 0 {
			if tried {
				if len(m.Answer) == 0 {
					log.Printf("id: %5d failed: %v\n", id, query)
				} else {
					log.Printf("id: %5d bingo: %v %s\n", id, query, used)
				}
			}
		}

		data, err = m.Pack()

		if err == nil {
			_, err = w.Write(data)

			if err == nil {
				if ENCACHE {
					m.Id = 0
					data, _ = m.Pack()
					ttl := 0

					if len(m.Answer) > 0 {
						ttl = int(m.Answer[0].Header().Ttl)

						if ttl < 0 {
							ttl = 0
						}
					}
					conn.Set(key, data, time.Second*time.Duration(ttl))

					m.Id = id
					if DEBUG > 0 {
						log.Printf("id: %5d cache: CACHED %v TTL %v\n", id, query, ttl)
					}
				}
			}
		}
	}

end:
	if DEBUG > 1 {
		fmt.Println(req)

		if m != nil {
			fmt.Println(m)
		}
	}

	if err != nil {
		log.Printf("id: %5d error: %v %s\n", id, query, err)
	}

	if DEBUG > 1 {
		fmt.Println("======================================")
	}
}
Ejemplo n.º 22
0
func (s *server) AddressRecords(q dns.Question) (records []dns.RR, err error) {
	name := strings.ToLower(q.Name)
	if name == "master."+s.config.Domain || name == s.config.Domain {
		for _, m := range s.client.GetCluster() {
			u, e := url.Parse(m)
			if e != nil {
				continue
			}
			h, _, e := net.SplitHostPort(u.Host)
			if e != nil {
				continue
			}
			ip := net.ParseIP(h)
			switch {
			case ip.To4() != nil && q.Qtype == dns.TypeA:
				records = append(records, &dns.A{Hdr: dns.RR_Header{Name: q.Name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: s.Ttl}, A: ip.To4()})
			case ip.To4() == nil && q.Qtype == dns.TypeAAAA:
				records = append(records, &dns.AAAA{Hdr: dns.RR_Header{Name: q.Name, Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Ttl: s.Ttl}, AAAA: ip.To16()})
			}
		}
		return
	}
	r, err := s.client.Get(path(name), false, true)
	if err != nil {
		println(err.Error())
		return nil, err
	}
	var serv *Service
	if !r.Node.Dir { // single element
		if err := json.Unmarshal([]byte(r.Node.Value), &serv); err != nil {
			log.Printf("error: Failure to parse value: %q", err)
			return nil, err
		}
		ip := net.ParseIP(serv.Host)
		ttl := uint32(r.Node.TTL)
		if ttl == 0 {
			ttl = s.Ttl
		}
		switch {
		case ip == nil:
		case ip.To4() != nil && q.Qtype == dns.TypeA:
			a := new(dns.A)
			a.Hdr = dns.RR_Header{Name: q.Name, Rrtype: q.Qtype, Class: dns.ClassINET, Ttl: ttl}
			a.A = ip.To4()
			records = append(records, a)
		case ip.To4() == nil && q.Qtype == dns.TypeAAAA:
			aaaa := new(dns.AAAA)
			aaaa.Hdr = dns.RR_Header{Name: q.Name, Rrtype: q.Qtype, Class: dns.ClassINET, Ttl: ttl}
			aaaa.AAAA = ip.To16()
			records = append(records, aaaa)
		}
		return records, nil
	}
	for _, serv := range s.loopNodes(&r.Node.Nodes) {
		ip := net.ParseIP(serv.Host)
		switch {
		case ip == nil:
		case ip.To4() != nil && q.Qtype == dns.TypeA:
			a := new(dns.A)
			a.Hdr = dns.RR_Header{Name: q.Name, Rrtype: q.Qtype, Class: dns.ClassINET, Ttl: uint32(r.Node.TTL)}
			a.A = ip.To4()
			records = append(records, a)
		case ip.To4() == nil && q.Qtype == dns.TypeAAAA:
			aaaa := new(dns.AAAA)
			aaaa.Hdr = dns.RR_Header{Name: q.Name, Rrtype: q.Qtype, Class: dns.ClassINET, Ttl: uint32(r.Node.TTL)}
			aaaa.AAAA = ip.To16()
			records = append(records, aaaa)
		}
	}
	if s.config.RoundRobin {
		switch l := len(records); l {
		case 2:
			if dns.Id()%2 == 0 {
				records[0], records[1] = records[1], records[0]
			}
		default:
			// Do a minimum of l swap, maximum of 4l swaps
			for j := 0; j < l*(int(dns.Id())%4+1); j++ {
				q := int(dns.Id()) % l
				p := int(dns.Id()) % l
				if q == p {
					p = (p + 1) % l
				}
				records[q], records[p] = records[p], records[q]
			}
		}
	}
	return records, nil
}
Ejemplo n.º 23
0
func handleDnsRequest(w dns.ResponseWriter, req *dns.Msg) {
	r := new(dns.Msg)
	r.SetReply(req)
	r.Authoritative = true

	if len(req.Question) > 1 || req.Rcode != dns.OpcodeQuery {
		r.SetRcode(req, dns.RcodeNotImplemented)
	}

	if len(req.Question) == 0 {
		r.SetRcode(req, dns.RcodeFormatError)
	}

	if r.Rcode != dns.RcodeSuccess {
		w.WriteMsg(r)
		dnsReportChan <- 1
		return
	}

	q := req.Question[0]
	log.Debug("dns server: question=%v type=%v remote_host=%v", q.Name, q.Qtype, w.RemoteAddr())

	switch q.Qtype {
	case dns.TypeA:
		h, _ := randomHost()
		if h == "" || !isIPv4(h) {
			if *f_randomhosts {
				h = randomIPv4Addr()
			} else {
				// return NXDOMAIN
				r.SetRcode(req, dns.RcodeNameError)
				break
			}
		}

		resp := new(dns.A)
		resp.Hdr = dns.RR_Header{
			Name:   q.Name,
			Rrtype: dns.TypeA,
			Class:  dns.ClassINET,
			Ttl:    ttl,
		}
		resp.A = net.ParseIP(h)
		r.Answer = append(r.Answer, resp)
	case dns.TypeAAAA:
		h, _ := randomHost()
		if h == "" || !isIPv6(h) {
			if *f_randomhosts {
				h = randomIPv6Addr()
			} else {
				// return NXDOMAIN
				r.SetRcode(req, dns.RcodeNameError)
				break
			}
		}

		resp := new(dns.AAAA)
		resp.Hdr = dns.RR_Header{
			Name:   q.Name,
			Rrtype: dns.TypeAAAA,
			Class:  dns.ClassINET,
			Ttl:    ttl,
		}
		resp.AAAA = net.ParseIP(h)
		r.Answer = append(r.Answer, resp)
	case dns.TypeCNAME:
		resp := new(dns.CNAME)
		resp.Hdr = dns.RR_Header{
			Name:   q.Name,
			Rrtype: dns.TypeCNAME,
			Class:  dns.ClassINET,
			Ttl:    ttl,
		}
		resp.Target = fmt.Sprintf("cname.%s", q.Name)
		r.Answer = append(r.Answer, resp)
	case dns.TypeMX:
		resp := new(dns.MX)
		resp.Hdr = dns.RR_Header{
			Name:   q.Name,
			Rrtype: dns.TypeMX,
			Class:  dns.ClassINET,
			Ttl:    ttl,
		}
		resp.Mx = fmt.Sprintf("mx.%s", q.Name)
		r.Answer = append(r.Answer, resp)
	case dns.TypeSOA:
		resp := new(dns.SOA)
		resp.Hdr = dns.RR_Header{
			Name:   q.Name,
			Rrtype: dns.TypeSOA,
			Class:  dns.ClassINET,
			Ttl:    ttl,
		}
		resp.Ns = fmt.Sprintf("ns.%s", q.Name)
		resp.Mbox = fmt.Sprintf("admin-%s", q.Name)
		r.Answer = append(r.Answer, resp)
	}
	w.WriteMsg(r)
	dnsReportChan <- 1
}
Ejemplo n.º 24
0
Archivo: main.go Proyecto: axw/jns
// TODO(axw) define an error for "no answer"
func (s *jujuNameServer) answer(q dns.Question) (dns.RR, error) {
	if q.Qtype != dns.TypeA {
		return nil, nil
	}

	var envName string
	entityName := strings.ToLower(strings.TrimSuffix(q.Name, "."+zone))
	if i := strings.IndexRune(entityName, '.'); i >= 0 {
		envName = entityName[i+1:]
		entityName = entityName[:i]
	} else {
		var err error
		envName, err = envcmd.GetDefaultEnvironment()
		if err != nil {
			return nil, err
		}
	}

	// TODO(axw) cache API connection
	api, err := s.openAPI(envName)
	if err != nil {
		return nil, err
	}
	defer api.Close()
	client := api.Client()

	// If the entity name parses as a tag, extract the ID. This enables
	// us to address "unit-mysql-0", where we couldn't otherwise, since
	// slashes are not allowed in domain names. Similarly for container
	// machines (e.g. to address "0/lxc/0", pass "machine-0-lxc-0").
	if tag, err := names.ParseTag(entityName); err == nil {
		entityName = tag.Id()
	}

	var addr string
	if names.IsValidService(entityName) {
		status, err := client.Status([]string{entityName})
		if err != nil {
			return nil, err
		}
		service := status.Services[entityName]
		addresses := make([]string, 0, len(service.Units))
		for _, unit := range service.Units {
			if unit.PublicAddress == "" {
				continue
			}
			if includeLost || unit.UnitAgent.Status != "lost" {
				addresses = append(addresses, unit.PublicAddress)
			}
		}
		// Might be nice to have additional info in TXT?
		if len(addresses) == 0 {
			return nil, nil
		}
		addr = addresses[rand.Intn(len(addresses))]
	} else {
		// Assume it's a machine or unit name.
		addr, err = client.PublicAddress(entityName)
		if err != nil {
			return nil, err
		}
	}

	ip := net.ParseIP(addr)
	if ip != nil {
		rr := new(dns.A)
		rr.Hdr = dns.RR_Header{
			Name:   q.Name,
			Rrtype: dns.TypeA,
			Class:  dns.ClassINET,
			Ttl:    0,
		}
		rr.A = ip
		return rr, nil
	} else {
		rr := new(dns.CNAME)
		rr.Hdr = dns.RR_Header{
			Name:   q.Name,
			Rrtype: dns.TypeCNAME,
			Class:  dns.ClassINET,
			Ttl:    0,
		}
		rr.Target = addr + "."
		return rr, nil
	}
}
Ejemplo n.º 25
0
// updateDNS updates the current slices of dns.RR so incoming requests get a
// fast answer
func updateDNS(s *dnsseeder) {

	var rr4std, rr4non, rr6std, rr6non []dns.RR

	s.mtx.RLock()

	// loop over each dns recprd type we need
	for t := range []int{dnsV4Std, dnsV4Non, dnsV6Std, dnsV6Non} {
		// FIXME above needs to be convertwd into one scan of theList if possible

		numRR := 0

		for _, nd := range s.theList {
			// when we reach max exit
			if numRR >= 25 {
				break
			}

			if nd.status != statusCG {
				continue
			}

			if t == dnsV4Std || t == dnsV4Non {
				if t == dnsV4Std && nd.dnsType == dnsV4Std {
					r := new(dns.A)
					r.Hdr = dns.RR_Header{Name: s.dnsHost + ".", Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: s.ttl}
					r.A = nd.na.IP
					rr4std = append(rr4std, r)
					numRR++
				}

				// if the node is using a non standard port then add the encoded port info to DNS
				if t == dnsV4Non && nd.dnsType == dnsV4Non {
					r := new(dns.A)
					r.Hdr = dns.RR_Header{Name: "nonstd." + s.dnsHost + ".", Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: s.ttl}
					r.A = nd.na.IP
					rr4non = append(rr4non, r)
					numRR++
					r = new(dns.A)
					r.Hdr = dns.RR_Header{Name: "nonstd." + s.dnsHost + ".", Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: s.ttl}
					r.A = nd.nonstdIP
					rr4non = append(rr4non, r)
					numRR++
				}
			}
			if t == dnsV6Std || t == dnsV6Non {
				if t == dnsV6Std && nd.dnsType == dnsV6Std {
					r := new(dns.AAAA)
					r.Hdr = dns.RR_Header{Name: s.dnsHost + ".", Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Ttl: s.ttl}
					r.AAAA = nd.na.IP
					rr6std = append(rr6std, r)
					numRR++
				}
				// if the node is using a non standard port then add the encoded port info to DNS
				if t == dnsV6Non && nd.dnsType == dnsV6Non {
					r := new(dns.AAAA)
					r.Hdr = dns.RR_Header{Name: "nonstd." + s.dnsHost + ".", Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Ttl: s.ttl}
					r.AAAA = nd.na.IP
					rr6non = append(rr6non, r)
					numRR++
					r = new(dns.AAAA)
					r.Hdr = dns.RR_Header{Name: "nonstd." + s.dnsHost + ".", Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Ttl: s.ttl}
					r.AAAA = nd.nonstdIP
					rr6non = append(rr6non, r)
					numRR++
				}
			}

		}

	}

	s.mtx.RUnlock()

	config.dnsmtx.Lock()

	// update the map holding the details for this seeder
	for t := range []int{dnsV4Std, dnsV4Non, dnsV6Std, dnsV6Non} {
		switch t {
		case dnsV4Std:
			config.dns[s.dnsHost+".A"] = rr4std
		case dnsV4Non:
			config.dns["nonstd."+s.dnsHost+".A"] = rr4non
		case dnsV6Std:
			config.dns[s.dnsHost+".AAAA"] = rr6std
		case dnsV6Non:
			config.dns["nonstd."+s.dnsHost+".AAAA"] = rr6non
		}
	}

	config.dnsmtx.Unlock()

	if config.stats {
		s.counts.mtx.RLock()
		log.Printf("%s - DNS available: v4std: %v v4non: %v v6std: %v v6non: %v\n", s.name, len(rr4std), len(rr4non), len(rr6std), len(rr6non))
		log.Printf("%s - DNS counts: v4std: %v v4non: %v v6std: %v v6non: %v total: %v\n",
			s.name,
			s.counts.DNSCounts[dnsV4Std],
			s.counts.DNSCounts[dnsV4Non],
			s.counts.DNSCounts[dnsV6Std],
			s.counts.DNSCounts[dnsV6Non],
			s.counts.DNSCounts[dnsV4Std]+s.counts.DNSCounts[dnsV4Non]+s.counts.DNSCounts[dnsV6Std]+s.counts.DNSCounts[dnsV6Non])

		s.counts.mtx.RUnlock()

	}
}
Ejemplo n.º 26
0
func (ts *testSrv) dnsHandler(w dns.ResponseWriter, r *dns.Msg) {
	m := new(dns.Msg)
	m.SetReply(r)
	m.Compress = false

	// Normally this test DNS server will return 127.0.0.1 for everything.
	// However, in some situations (for instance Docker), it's useful to return a
	// different hardcoded host. You can do so by setting the FAKE_DNS environment
	// variable.
	fakeDNS := os.Getenv("FAKE_DNS")
	if fakeDNS == "" {
		fakeDNS = "127.0.0.1"
	}
	for _, q := range r.Question {
		fmt.Printf("dns-srv: Query -- [%s] %s\n", q.Name, dns.TypeToString[q.Qtype])
		switch q.Qtype {
		case dns.TypeA:
			record := new(dns.A)
			record.Hdr = dns.RR_Header{
				Name:   q.Name,
				Rrtype: dns.TypeA,
				Class:  dns.ClassINET,
				Ttl:    0,
			}
			record.A = net.ParseIP(fakeDNS)

			m.Answer = append(m.Answer, record)
		case dns.TypeMX:
			record := new(dns.MX)
			record.Hdr = dns.RR_Header{
				Name:   q.Name,
				Rrtype: dns.TypeMX,
				Class:  dns.ClassINET,
				Ttl:    0,
			}
			record.Mx = "mail." + q.Name
			record.Preference = 10

			m.Answer = append(m.Answer, record)
		case dns.TypeTXT:
			ts.mu.RLock()
			value, present := ts.txtRecords[q.Name]
			ts.mu.RUnlock()
			if !present {
				continue
			}
			record := new(dns.TXT)
			record.Hdr = dns.RR_Header{
				Name:   q.Name,
				Rrtype: dns.TypeTXT,
				Class:  dns.ClassINET,
				Ttl:    0,
			}
			record.Txt = []string{value}
			m.Answer = append(m.Answer, record)
		case dns.TypeCAA:
			if q.Name == "bad-caa-reserved.com." || q.Name == "good-caa-reserved.com." {
				record := new(dns.CAA)
				record.Hdr = dns.RR_Header{
					Name:   q.Name,
					Rrtype: dns.TypeCAA,
					Class:  dns.ClassINET,
					Ttl:    0,
				}
				record.Tag = "issue"
				if q.Name == "bad-caa-reserved.com." {
					record.Value = "sad-hacker-ca.invalid"
				} else if q.Name == "good-caa-reserved.com." {
					record.Value = "happy-hacker-ca.invalid"
				}
				m.Answer = append(m.Answer, record)
			}
		}
	}

	auth := new(dns.SOA)
	auth.Hdr = dns.RR_Header{Name: "boulder.invalid.", Rrtype: dns.TypeSOA, Class: dns.ClassINET, Ttl: 0}
	auth.Ns = "ns.boulder.invalid."
	auth.Mbox = "master.boulder.invalid."
	auth.Serial = 1
	auth.Refresh = 1
	auth.Retry = 1
	auth.Expire = 1
	auth.Minttl = 1
	m.Ns = append(m.Ns, auth)

	w.WriteMsg(m)
	return
}