// 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 }
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) }
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 } } }
// 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 }
// 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 }
// 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) }
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 }
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 }
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 }
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") } }
// // === 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 } }
// 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 } }
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) } }
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) }
// 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") }
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 }
// 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") }
// 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 }
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 }
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 }
/* ---------------------------------------------------------------------------- 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) } }
// 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 }
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 }
/* 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 }
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 }
// 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") }
// 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 }