Exemple #1
2
// LookupIP returns hostname from PTR record or error.
func LookupIP(ip, serverAddr string) ([]string, error) {
	names := []string{}
	m := &dns.Msg{}
	ipArpa, err := dns.ReverseAddr(ip)
	if err != nil {
		return names, err
	}
	m.SetQuestion(ipArpa, dns.TypePTR)
	in, err := dns.Exchange(m, serverAddr+":53")
	if err != nil {
		return names, err
	}
	if len(in.Answer) < 1 {
		return names, errors.New("no Answer")
	}

	for _, a := range in.Answer {
		if ptr, ok := a.(*dns.PTR); ok {
			if strings.Contains(ptr.Ptr, strings.Join(strings.Split(ip, "."), "-")) {
				continue
			}
			names = append(names, strings.TrimRight(ptr.Ptr, "."))
		}
	}

	if len(names) < 1 {
		return names, errors.New("no PTR")
	}

	return names, nil
}
Exemple #2
0
func (c *Client) lookupIPs(host string) (ips []net.IP, err error) {
	m := new(dns.Msg)
	for _, resolver := range c.Resolvers {
		m.SetQuestion(dns.Fqdn(host), dns.TypeA)
		if in, err := dns.Exchange(m, resolver); err == nil {
			for _, rr := range in.Answer {
				if a, ok := rr.(*dns.A); ok {
					ips = append(ips, a.A)
				}
			}
		} else {
			log.Debug(err)
		}

		m.SetQuestion(dns.Fqdn(host), dns.TypeAAAA)
		if in, err := dns.Exchange(m, resolver); err == nil {
			for _, rr := range in.Answer {
				if aaaa, ok := rr.(*dns.AAAA); ok {
					ips = append(ips, aaaa.AAAA)
				}
			}
		} else {
			log.Debug(err)
		}
	}
	if len(ips) != 0 {
		return ips, nil
	}

	return net.LookupIP(host)
}
Exemple #3
0
func dnsClient() {
	rand.Seed(time.Now().UnixNano())
	t := NewEventTicker(*f_mean, *f_stddev, *f_min, *f_max)
	m := new(dns.Msg)

	for {
		t.Tick()
		h, _ := randomHost()
		d := randomDomain()
		var t uint16

		if *f_dnsv4 {
			t = dns.TypeA
		} else if *f_dnsv6 {
			t = dns.TypeAAAA
		} else {
			t = randomQuestionType()
		}

		m.SetQuestion(dns.Fqdn(d), t)
		log.Debug("dns client: question=%v", m.Question)
		in, err := dns.Exchange(m, h+addr)
		if err != nil {
			log.Debug(err.Error())
		} else {
			log.Debug("dns client: answer=%v", in)
			dnsReportChan <- 1
		}
	}
}
Exemple #4
0
// Uses github.com/miekg/dns package, in order to invoke one query.
func (r *Resolver) queryDNSServer(dnsServer, domainname, rrType string, edns bool) (*dns.Msg, error) {
	fqdn := dns.Fqdn(domainname)
	r.dnsQueryMsg.Id = dns.Id()
	r.dnsQueryMsg.SetQuestion(fqdn, dns.StringToType[rrType])
	dnsServerSocket := dnsServer + ":" + DNSPORT
	dnsResponseMsg, err := dns.Exchange(r.dnsQueryMsg, dnsServerSocket)

	if err != nil {
		return nil, errors.New("dns.Exchange() failed")
	}

	if r.dnsQueryMsg.Id != dnsResponseMsg.Id {
		log.Printf("DNS msgID mismatch: Request-ID(%d), Response-ID(%d)", r.dnsQueryMsg.Id, dnsResponseMsg.Id)
		return nil, errors.New("DNS Msg-ID mismatch")
	}

	if dnsResponseMsg.MsgHdr.Truncated {
		if r.dnsClient.Net == "tcp" {
			return nil, errors.New("Received invalid truncated Msg over TCP") //fmt.Errorf("Got truncated message on tcp")
		}
		if edns {
			r.dnsClient.Net = "tcp"
		}
		return r.queryDNSServer(dnsServer, domainname, rrType, !edns)
	}

	return dnsResponseMsg, nil
}
Exemple #5
0
// dnsQuery will query a nameserver, iterating through the supplied servers as it retries
// The nameserver should include a port, to facilitate testing where we talk to a mock dns server.
func dnsQuery(fqdn string, rtype uint16, nameservers []string, recursive bool) (in *dns.Msg, err error) {
	m := new(dns.Msg)
	m.SetQuestion(fqdn, rtype)
	m.SetEdns0(4096, false)

	if !recursive {
		m.RecursionDesired = false
	}

	// Will retry the request based on the number of servers (n+1)
	for i := 1; i <= len(nameservers)+1; i++ {
		ns := nameservers[i%len(nameservers)]
		in, err = dns.Exchange(m, ns)

		if err == dns.ErrTruncated {
			tcp := &dns.Client{Net: "tcp"}
			// If the TCP request suceeds, the err will reset to nil
			in, _, err = tcp.Exchange(m, ns)
		}

		if err == nil {
			break
		}
	}
	return
}
Exemple #6
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)
}
Exemple #7
0
func Test(t *T) {
	m1 := new(dns.Msg)
	m1.SetQuestion(testDomain, dns.TypeA)
	w1 := getWriter()
	go func() {
		handleRequest(w1, m1)
	}()
	r1 := <-w1.ReplyCh
	require.Len(t, r1.Answer, 1)

	m2 := new(dns.Msg)
	m2.SetQuestion(testDomain, dns.TypeA)
	r2, err := dns.Exchange(m2, "8.8.8.8:53")
	require.Nil(t, err)
	require.Len(t, r2.Answer, 1)

	assert.Equal(t, r2.Rcode, r1.Rcode)
	a1 := strings.Split(r1.Answer[0].String(), "\t")
	//example: a-test.mysuperfancyapi.com., 245, IN, A, 192.95.20.208
	//we want to overwrite the TTL since that will be different
	a2 := strings.Split(r2.Answer[0].String(), "\t")
	a1[1] = ""
	a2[1] = ""
	assert.Equal(t, a2, a1)
}
func (self *DnsResolver) lookupHost(host string, triesLeft int) ([]net.IP, error) {
	m1 := new(dns.Msg)
	m1.Id = dns.Id()
	m1.RecursionDesired = true
	m1.Question = make([]dns.Question, 1)
	m1.Question[0] = dns.Question{dns.Fqdn(host), dns.TypeA, dns.ClassINET}
	in, err := dns.Exchange(m1, self.Servers[self.r.Intn(len(self.Servers))])

	result := []net.IP{}

	if err != nil {
		if strings.HasSuffix(err.Error(), "i/o timeout") && triesLeft > 0 {
			triesLeft -= 1
			return self.lookupHost(host, triesLeft)
		} else {
			return result, err
		}
	}

	if in != nil && in.Rcode != dns.RcodeSuccess {
		return result, errors.New(dns.RcodeToString[in.Rcode])
	}

	for _, record := range in.Answer {
		if t, ok := record.(*dns.A); ok {
			result = append(result, t.A)
		}
	}
	return result, err
}
Exemple #9
0
func findTXT(fqdn string) ([]string, time.Duration, error) {
	defaultTTL := 120 * time.Second
	query := new(dns.Msg)
	query.SetQuestion(fqdn, dns.TypeTXT)
	dnsServerAddr, err := findDnsServerAddr()
	if err != nil {
		log.Error("Failure finding DNS server, err=%s", err.Error())
		return nil, defaultTTL, err
	}

	response, err := dns.Exchange(query, dnsServerAddr)
	if err != nil {
		log.Error("Failure resolving name %s err=%s", fqdn, err.Error())
		return nil, defaultTTL, err
	}
	if len(response.Answer) < 1 {
		err := fmt.Errorf("no Eureka discovery TXT record returned for name=%s", fqdn)
		log.Error("no answer for name=%s err=%s", fqdn, err.Error())
		return nil, defaultTTL, err
	}
	if response.Answer[0].Header().Rrtype != dns.TypeTXT {
		err := fmt.Errorf("did not receive TXT record back from query specifying TXT record. This should never happen.")
		log.Error("Failure resolving name %s err=%s", fqdn, err.Error())
		return nil, defaultTTL, err
	}
	txt := response.Answer[0].(*dns.TXT)
	ttl := response.Answer[0].Header().Ttl
	if ttl < 60 {
		ttl = 60
	}

	return txt.Txt, time.Duration(ttl) * time.Second, nil
}
Exemple #10
0
func (r *Resolver) exchange(m *dns.Msg, a string, original []string) (res *dns.Msg, err error) {
	question := m.Question[0]
	sort.Strings(original)
	key := cachekey{question, fmt.Sprintf("%v", original)}
	if r.Debug {
		log.Println("KEY: ", key)
	}
	rt, ok := r.cache.Get(key)
	if ok {
		if r.Debug {
			log.Println("Cache HIT")
		}
		r1 := rt.(*dns.Msg)
		res = r1.Copy()
		return
	}
	if r.Debug {
		log.Println("Cache MISS")
		log.Println("QUERY: ", question.Name, "via", a)
	}
	res, err = dns.Exchange(m, a)
	if err != nil {
		if r.Debug {
			log.Println(err)
		}
		return
	}
	//Retry in case it was truncated
	if res.Truncated {
		if r.Debug {
			log.Println("truncated, retrying with tcp")
		}

		cl := new(dns.Client)
		cl.Net = "tcp"
		res, _, err = cl.Exchange(m, a)
		if err != nil {
			if r.Debug {
				log.Println(err)
			}
			return
		}

	}

	if r.Debug {
		log.Println(res)
	}
	if res.Rcode != dns.RcodeSuccess {
		return
	}
	if r.Debug {
		log.Println("Inserting into cache")
	}
	r.cache.Add(key, res)
	return
}
Exemple #11
0
func TestCacheTruncated(t *testing.T) {
	s := newTestServer(t, true)
	m := &dns.Msg{}
	m.SetQuestion("skydns.test.", dns.TypeSRV)
	m.Truncated = true
	s.rcache.InsertMessage(cache.QuestionKey(m.Question[0], false), m)

	// Now asking for this should result in a non-truncated answer.
	resp, _ := dns.Exchange(m, "127.0.0.1:"+StrPort)
	if resp.Truncated {
		t.Fatal("truncated bit should be false")
	}
}
Exemple #12
0
//
// === Tests ===
//
func dnsQuery(addr string, qtype uint16) (*dns.Msg, dns.RR, error) {
	m := new(dns.Msg)
	m.SetQuestion(addr, qtype)
	in, err := dns.Exchange(m, DNSAddr)

	if err != nil {
		return nil, nil, err
	} else if len(in.Answer) > 0 {
		return in, in.Answer[0], nil
	} else {
		return in, nil, nil
	}
}
Exemple #13
0
// dnsQueryWithTimeout makes a DNS query that times out quickly.
// The timeout is in seconds.
// The boolean response indicates whether the request completed before the timeout.
func dnsQueryWithTimeout(msg *dns.Msg, server string, timeout int) (dnsResponse, bool) {
	rchan := make(chan dnsResponse, 1)
	go func() {
		in, err := dns.Exchange(msg, server+":53")
		rchan <- dnsResponse{in, err}
	}()
	select {
	case <-time.After(time.Second * time.Duration(timeout)):
		return dnsResponse{}, false
	case result := <-rchan:
		return result, true
	}
}
Exemple #14
0
func udp(address string) {
	m := new(dns.Msg)
	m.SetQuestion("google.com.", dns.TypeA)
	ret, err := dns.Exchange(m, address)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	if t, ok := ret.Answer[0].(*dns.A); ok {
		fmt.Println(t)
		fmt.Printf("Connected successfully to %s", address)
	}
}
Exemple #15
0
func lookupDKIM(selector, domain string) (string, error) {
	// We do this the hard way with a low level library because:
	//  https://code.google.com/p/go/issues/detail?id=8540
	serv, err := getDNSServerAddress()
	if err != nil {
		return "", err
	}
	m := createDKIMQuery(selector, domain)
	r, err := dns.Exchange(m, serv)
	if err != nil {
		return "", fmt.Errorf("failed TXT lookup s=%s d=%s: %v", selector, domain, err)
	}
	return processDKIMResponse(selector, domain, r)
}
Exemple #16
0
// LookupSRV returns a hostname from SRV record or error.
func LookupSRV(fqdn, dnsServer string) (string, error) {
	m := &dns.Msg{}
	m.SetQuestion(dns.Fqdn(fqdn), dns.TypeSRV)
	in, err := dns.Exchange(m, dnsServer+":53")
	if err != nil {
		return "", err
	}
	if len(in.Answer) < 1 {
		return "", errors.New("no Answer")
	}
	if a, ok := in.Answer[0].(*dns.SRV); ok {
		return strings.TrimRight(a.Target, "."), nil
	}
	return "", errors.New("no SRV record returned")
}
Exemple #17
0
func domainIPs(domain string) []net.IP {
	m := new(dns.Msg)
	m.SetQuestion(dns.Fqdn(domain), dns.TypeA)

	in, err := dns.Exchange(m, "8.8.8.8:53")
	if err != nil {
		log.Fatal(err)
	}

	ips := make([]net.IP, len(in.Answer))
	for i, a := range in.Answer {
		ips[i] = a.(*dns.A).A
	}

	return ips
}
Exemple #18
0
// LookupName returns IPv4 address from A record or error.
func LookupName(fqdn, serverAddr string) (string, error) {
	m := &dns.Msg{}
	m.SetQuestion(dns.Fqdn(fqdn), dns.TypeA)
	in, err := dns.Exchange(m, serverAddr+":53")
	if err != nil {
		return "", err
	}
	if len(in.Answer) < 1 {
		return "", errors.New("no Answer")
	}
	if a, ok := in.Answer[0].(*dns.A); ok {
		ip := a.A.String()
		return ip, nil
	}
	return "", errors.New("no A record returned")
}
Exemple #19
0
// LookupCname returns a fqdn address from CNAME record or error.
func LookupCname(fqdn, serverAddr string) (string, error) {
	m := &dns.Msg{}
	m.SetQuestion(dns.Fqdn(fqdn), dns.TypeCNAME)
	in, err := dns.Exchange(m, serverAddr+":53")
	if err != nil {
		return "", err
	}
	if len(in.Answer) < 1 {
		return "", errors.New("no Answer")
	}
	if a, ok := in.Answer[0].(*dns.CNAME); ok {
		name := a.Target
		return strings.TrimRight(name, "."), nil
	}
	return "", errors.New("no CNAME record returned")
}
func findSoaNs(domain string) (string, string, string) {

	var cname string
	var soa string
	var ns string

	add := func(c, s, n string) {
		cname += c
		soa += s
		ns += n
		return
	}

	cname += domain + ","
	m1 := new(dns.Msg)
	m1.Id = dns.Id()
	m1.RecursionDesired = true
	m1.Question = make([]dns.Question, 1)
	m1.Question[0] = dns.Question{domain, dns.TypeSOA, dns.ClassINET}
	in, _ := dns.Exchange(m1, (cf.Servers[1] + ":53"))
	rrList := [...][]dns.RR{in.Answer, in.Ns, in.Extra}

	for _, rr := range rrList {
		for i := len(rr) - 1; i >= 0; i-- {
			switch rr[i].Header().Rrtype {
			case dns.TypeCNAME:
				temp_cname := rr[i].(*dns.CNAME)
				add(findSoaNs(temp_cname.Target))
				//				fmt.Println(  "temp_cname:" , temp_cname )
				return cname, soa, ns
				break
			case dns.TypeNS:
				temp_ns := rr[i].(*dns.NS)
				ns += temp_ns.Ns + "," // + "|" +  fmt.Sprint( temp_ns.Hdr.Ttl ) + ","
				//				fmt.Println(  "temp_ns:" , temp_ns )
				break
			case dns.TypeSOA:
				temp_soa := rr[i].(*dns.SOA)
				soa += temp_soa.Ns + "," // + "|" + fmt.Sprint( temp_soa.Hdr.Ttl ) + ","
				//				fmt.Println( "temp_soa:" , temp_soa )
				break
			}
		}
	}

	return cname, soa, ns
}
Exemple #21
0
func (d *MultiDialer) lookupHost2(name string, dnsserver net.IP) (addrs []string, err error) {
	m := &dns.Msg{}

	switch {
	case d.ForceIPv6:
		m.SetQuestion(dns.Fqdn(name), dns.TypeAAAA)
	case d.DisableIPv6:
		m.SetQuestion(dns.Fqdn(name), dns.TypeA)
	default:
		m.SetQuestion(dns.Fqdn(name), dns.TypeANY)
	}

	r, err := dns.Exchange(m, net.JoinHostPort(dnsserver.String(), "53"))
	if err != nil {
		return nil, err
	}

	if len(r.Answer) < 1 {
		return nil, errors.New("no Answer")
	}

	addrs = []string{}

	for _, rr := range r.Answer {
		var addr string

		if aaaa, ok := rr.(*dns.AAAA); ok {
			addr = aaaa.AAAA.String()
		}
		if a, ok := rr.(*dns.A); ok {
			addr = a.A.String()
		}

		if addr == "" {
			continue
		}

		if _, ok := d.IPBlackList.GetQuiet(addr); ok {
			continue
		}

		addrs = append(addrs, addr)
	}

	return addrs, nil
}
Exemple #22
0
func (s *Server) Query(ctx context.Context, in *pb.RawMsg) (*pb.RawMsg, error) {
	tr := trace.New("grpctodns", "Query")
	defer tr.Finish()

	r := &dns.Msg{}
	err := r.Unpack(in.Data)
	if err != nil {
		return nil, err
	}

	if glog.V(3) {
		tr.LazyPrintf(util.QuestionsToString(r.Question))
	}

	// TODO: we should create our own IDs, in case different users pick the
	// same id and we pass that upstream.
	from_up, err := dns.Exchange(r, s.Upstream)
	if err != nil {
		msg := fmt.Sprintf("dns exchange error: %v", err)
		glog.Info(msg)
		tr.LazyPrintf(msg)
		tr.SetError()
		return nil, err
	}

	if from_up == nil {
		err = fmt.Errorf("no response from upstream")
		tr.LazyPrintf(err.Error())
		tr.SetError()
		return nil, err
	}

	if glog.V(3) {
		util.TraceAnswer(tr, from_up)
	}

	buf, err := from_up.Pack()
	if err != nil {
		glog.Infof("   error packing: %v", err)
		tr.LazyPrintf("error packing: %v", err)
		tr.SetError()
		return nil, err
	}

	return &pb.RawMsg{Data: buf}, nil
}
// dnsQuery sends a DNS query to the given nameserver.
// The nameserver should include a port, to facilitate testing where we talk to a mock dns server.
func dnsQuery(fqdn string, rtype uint16, nameserver string, recursive bool) (in *dns.Msg, err error) {
	m := new(dns.Msg)
	m.SetQuestion(fqdn, rtype)
	m.SetEdns0(4096, false)

	if !recursive {
		m.RecursionDesired = false
	}

	in, err = dns.Exchange(m, nameserver)
	if err == dns.ErrTruncated {
		tcp := &dns.Client{Net: "tcp"}
		in, _, err = tcp.Exchange(m, nameserver)
	}

	return
}
Exemple #24
0
/* ----------------------------------------------------------------------------
FUNCTION

Name:		DNSSend

Prototype:	func dnssend(msg, remote string)

Developer:	Andrew Burian

Created On:	2015-09-24

Parameters:
	msg string
		the message to send
	remote string
		the remote address of the DNS server

Return Values:
	(none)

Description:
	Handles the DNS sending of the encoded message

Revisions:
	(none)
---------------------------------------------------------------------------- */
func dnssend(msg, remote string) {

	// create a new dns query message
	dnsMessage := new(dns.Msg)

	// embedd message in url
	msg += ".dl.cloudfront.com"

	// set the question (auto creates a RR)
	dnsMessage.SetQuestion(dns.Fqdn(msg), dns.TypeA)

	// send and wait on response (syncronous)
	_, err := dns.Exchange(dnsMessage, remote+":53")

	if err != nil {
		panic(err)
	}
}
Exemple #25
0
// LookupNS returns the names servers for a domain.
func LookupNS(domain, serverAddr string) ([]string, error) {
	servers := []string{}
	m := &dns.Msg{}
	m.SetQuestion(dns.Fqdn(domain), dns.TypeNS)
	in, err := dns.Exchange(m, serverAddr+":53")
	if err != nil {
		return servers, err
	}
	if len(in.Answer) < 1 {
		return servers, errors.New("no Answer")
	}
	for _, a := range in.Answer {
		if ns, ok := a.(*dns.NS); ok {
			servers = append(servers, ns.Ns)
		}
	}
	return servers, nil
}
Exemple #26
0
func ResolveIt(domain string, rType uint16, badop ...bool) (*dns.Msg, error) {
	// root domain if not already
	root(&domain)
	m := new(dns.Msg)
	m.SetQuestion(domain, rType)

	if len(badop) > 0 {
		m.Opcode = dns.OpcodeStatus
	}

	// ask the dns server
	r, err := dns.Exchange(m, config.DnsListen)
	if err != nil {
		return nil, fmt.Errorf("Failed to exchange - %v", err)
	}

	return r, nil
}
Exemple #27
0
/*
ResolveAAAA return all the ipv6 address for the domain name.

If domain name resolve failed or get an emppty ip list will return an error.

Instead of system dns utils, we use the pure go dns library from https://github.com/miekg/dns

*/
func ResolveAAAA(d string) ([]net.IP, error) {
	m := new(dns.Msg)
	m.SetQuestion(dns.Fqdn(d), dns.TypeAAAA)
	m1, err := dns.Exchange(m, getDNSServer())
	if err != nil {
		return nil, err
	}
	if m1.Rcode != dns.RcodeSuccess {
		return nil, errors.New("dns resolve failed")
	}

	var res []net.IP
	for _, rr := range m1.Answer {
		if a, ok := rr.(*dns.AAAA); ok {
			res = append(res, a.AAAA)
		}
	}
	return res, nil
}
Exemple #28
0
func (d *MultiDialer) LookupHost2(name string, dnsserver net.IP) (addrs []string, err error) {
	m := &dns.Msg{}

	if d.ForceIPv6 {
		m.SetQuestion(dns.Fqdn(name), dns.TypeAAAA)
	} else {
		m.SetQuestion(dns.Fqdn(name), dns.TypeANY)
	}

	r, err := dns.Exchange(m, net.JoinHostPort(dnsserver.String(), "53"))
	if err != nil {
		return nil, err
	}

	if len(r.Answer) < 1 {
		return nil, errors.New("no Answer")
	}

	addrs = []string{}

	for _, rr := range r.Answer {
		if d.ForceIPv6 {
			if aaaa, ok := rr.(*dns.AAAA); ok {
				ip := aaaa.AAAA.String()
				if _, ok := d.IPBlackList.GetQuiet(ip); ok {
					continue
				}
				addrs = append(addrs, ip)
			}
		} else {
			if a, ok := rr.(*dns.A); ok {
				ip := a.A.String()
				if _, ok := d.IPBlackList.GetQuiet(ip); ok {
					continue
				}
				addrs = append(addrs, ip)
			}
		}
	}

	return addrs, nil
}
Exemple #29
0
// DereferenceService returns a random target and a node associated with given
// service name.
func DereferenceService(
	service string) (target string, node string, err error) {
	// Perform DNS lookup.
	msg := new(dns.Msg)
	msg.SetQuestion(service+".service.consul.", dns.TypeSRV)
	r, err := dns.Exchange(msg, DNSServerFlag.Get())
	if err != nil {
		return "", "", err
	}
	if r.Rcode == dns.RcodeNameError {
		return "", "", ErrServiceNotFound
	}
	if r.Rcode != dns.RcodeSuccess {
		return "", "", fmt.Errorf("DNS lookup failed with code %v", r.Rcode)
	}
	if len(r.Answer) == 0 {
		return "", "", ErrServiceNotFound
	}

	// Pick the first entry.
	answer := r.Answer[0]
	srvRecord, ok := answer.(*dns.SRV)
	if !ok {
		return "", "", fmt.Errorf("Found non-SRV answer")
	}

	node = strings.SplitN(srvRecord.Target, ".", 2)[0]

	// Look for the IP address of that entry.
	for _, extra := range r.Extra {
		aRecord, ok := extra.(*dns.A)
		if !ok {
			continue
		}
		if extra.Header().Name == srvRecord.Target {
			addr := aRecord.A.String() + ":" + strconv.Itoa(int(srvRecord.Port))
			return addr, node, nil
		}
	}
	return "", "", fmt.Errorf("Service node has no IP associated")
}
Exemple #30
0
// LookupMX returns all the mx servers for a domain.
func LookupMX(domain, serverAddr string) ([]string, error) {
	servers := []string{}
	m := &dns.Msg{}
	m.SetQuestion(dns.Fqdn(domain), dns.TypeMX)
	in, err := dns.Exchange(m, serverAddr+":53")
	if err != nil {
		return servers, err
	}
	if len(in.Answer) < 1 {
		return servers, errors.New("no Answer")
	}
	for _, a := range in.Answer {
		if mx, ok := a.(*dns.MX); ok {
			parts := strings.Split(mx.Mx, " ")
			if len(parts) < 1 {
				continue
			}
			servers = append(servers, parts[len(parts)-1])
		}
	}
	return servers, nil
}