예제 #1
0
파일: service.go 프로젝트: ozym/zone
func (s *Service) Transfer(zone string) ([]dns.RR, error) {
	m := new(dns.Msg)
	m.SetAxfr(zone)

	h, err := s.ServerPort()
	if err != nil {
		return nil, err
	}

	tr := new(dns.Transfer)
	a, err := tr.In(m, h)
	if err != nil {
		return nil, err
	}

	var res []dns.RR
	for ex := range a {
		if ex.Error != nil {
			return nil, ex.Error
		}
		res = append(res, ex.RR...)
	}

	return res, nil
}
예제 #2
0
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)
}
예제 #3
0
// AXFR attempts a zone transfer for the domain.
func AXFR(domain, serverAddr string) *Tsk {
	t := newTsk("axfr")
	servers, err := LookupNS(domain, serverAddr)
	if err != nil {
		t.SetErr(err)
		return t
	}

	for _, s := range servers {
		tr := dns.Transfer{}
		m := &dns.Msg{}
		m.SetAxfr(dns.Fqdn(domain))
		in, err := tr.In(m, s+":53")
		if err != nil {
			t.SetErr(err)
			return t
		}
		for ex := range in {
			for _, a := range ex.RR {
				var ip, hostname string
				switch v := a.(type) {
				case *dns.A:
					ip = v.A.String()
					hostname = v.Hdr.Name
				case *dns.AAAA:
					ip = v.AAAA.String()
					hostname = v.Hdr.Name
				case *dns.PTR:
					ip = v.Hdr.Name
					hostname = v.Ptr
				case *dns.NS:
					cip, err := LookupName(v.Ns, serverAddr)
					if err != nil || cip == "" {
						continue
					}
					ip = cip
					hostname = v.Ns
				case *dns.CNAME:
					cip, err := LookupName(v.Target, serverAddr)
					if err != nil || cip == "" {
						continue
					}
					hostname = v.Hdr.Name
					ip = cip
				case *dns.SRV:
					cip, err := LookupName(v.Target, serverAddr)
					if err != nil || ip == "" {
						continue
					}
					ip = cip
					hostname = v.Target
				default:
					continue
				}
				t.AddResult(ip, strings.TrimRight(hostname, "."))
			}
		}
	}
	return t
}
예제 #4
0
파일: equipment.go 프로젝트: ozym/zone
func (e *Equipment) transfer() ([]dns.RR, error) {
	m := new(dns.Msg)
	m.SetAxfr(e.Zone)

	port := e.Port
	if port == "" {
		port = DEF_PORT
	}

	s, err := net.LookupHost(e.Server)
	if err != nil {
		return nil, err
	}

	tr := new(dns.Transfer)
	a, err := tr.In(m, net.JoinHostPort(s[0], port))
	if err != nil {
		return nil, err
	}

	var res []dns.RR
	for ex := range a {
		if ex.Error != nil {
			return nil, ex.Error
		}
		res = append(res, ex.RR...)
	}

	return res, nil
}
예제 #5
0
func (r *RFC2136Provider) list() ([]dns.RR, error) {
	logrus.Debugf("Fetching records for '%s'", r.zoneName)
	t := new(dns.Transfer)
	t.TsigSecret = map[string]string{r.tsigKeyName: r.tsigSecret}

	m := new(dns.Msg)
	m.SetAxfr(r.zoneName)
	m.SetTsig(r.tsigKeyName, dns.HmacMD5, 300, time.Now().Unix())

	env, err := t.In(m, r.nameserver)
	if err != nil {
		return nil, fmt.Errorf("Failed to fetch records via AXFR: %v", err)
	}

	records := make([]dns.RR, 0)
	for e := range env {
		if e.Error != nil {
			logrus.Errorf("AXFR envelope error: %v", e.Error)
			continue
		}
		records = append(records, e.RR...)
	}

	return records, nil
}
예제 #6
0
파일: secondary.go 프로젝트: yuewko/coredns
// TransferIn retrieves the zone from the masters, parses it and sets it live.
func (z *Zone) TransferIn() error {
	if len(z.TransferFrom) == 0 {
		return nil
	}
	m := new(dns.Msg)
	m.SetAxfr(z.origin)

	z1 := z.Copy()
	var (
		Err error
		tr  string
	)

Transfer:
	for _, tr = range z.TransferFrom {
		t := new(dns.Transfer)
		c, err := t.In(m, tr)
		if err != nil {
			log.Printf("[ERROR] Failed to setup transfer `%s' with `%s': %v", z.origin, tr, err)
			Err = err
			continue Transfer
		}
		for env := range c {
			if env.Error != nil {
				log.Printf("[ERROR] Failed to parse transfer `%s': %v", z.origin, env.Error)
				Err = env.Error
				continue Transfer
			}
			for _, rr := range env.RR {
				if err := z1.Insert(rr); err != nil {
					log.Printf("[ERROR] Failed to parse transfer `%s': %v", z.origin, err)
					Err = err
					continue Transfer
				}
			}
		}
		Err = nil
		break
	}
	if Err != nil {
		log.Printf("[ERROR] Failed to transfer %s: %s", z.origin, Err)
		return Err
	}

	z.Tree = z1.Tree
	z.Apex = z1.Apex
	*z.Expired = false
	log.Printf("[INFO] Transferred: %s from %s", z.origin, tr)
	return nil
}
예제 #7
0
func ZoneTransfer(domain string) Results {
	results := NewResultSet()
	fqdn := dns.Fqdn(domain)

	servers, err := net.LookupNS(domain)
	if err != nil {
		log.Fatal(err)
	}

	for _, server := range servers {
		msg := new(dns.Msg)
		msg.SetAxfr(fqdn)

		transfer := new(dns.Transfer)
		answerChan, err := transfer.In(msg, net.JoinHostPort(server.Host, "53"))
		if err != nil {
			log.Println(err)
			continue
		}

		for envelope := range answerChan {
			if envelope.Error != nil {
				log.Println(envelope.Error)
				break
			}

			for _, rr := range envelope.RR {
				switch v := rr.(type) {
				case *dns.A:
					results.Add(strings.TrimRight(v.Header().Name, "."), v.A.String())
				case *dns.AAAA:
					results.Add(strings.TrimRight(v.Header().Name, "."), v.AAAA.String())
				default:
				}
			}
		}
	}

	return results.Results()
}
예제 #8
0
파일: xfr.go 프로젝트: yuewko/coredns
// Serve an AXFR (and fallback of IXFR) as well.
func (x Xfr) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) {
	state := middleware.State{W: w, Req: r}
	if !x.TransferAllowed(state) {
		return dns.RcodeServerFailure, nil
	}
	if state.QType() != dns.TypeAXFR && state.QType() != dns.TypeIXFR {
		return 0, fmt.Errorf("xfr called with non transfer type: %d", state.QType())
	}

	records := x.All()
	if len(records) == 0 {
		return dns.RcodeServerFailure, nil
	}

	ch := make(chan *dns.Envelope)
	defer close(ch)
	tr := new(dns.Transfer)
	go tr.Out(w, r, ch)

	j, l := 0, 0
	records = append(records, records[0]) // add closing SOA to the end
	log.Printf("[INFO] Outgoing transfer of %d records of zone %s to %s started", len(records), x.origin, state.IP())
	for i, r := range records {
		l += dns.Len(r)
		if l > transferLength {
			ch <- &dns.Envelope{RR: records[j:i]}
			l = 0
			j = i
		}
	}
	if j < len(records) {
		ch <- &dns.Envelope{RR: records[j:]}
	}

	w.Hijack()
	// w.Close() // Client closes connection
	return dns.RcodeSuccess, nil
}
예제 #9
0
func handleReflect(w dns.ResponseWriter, r *dns.Msg) {
	reflectHandled += 1
	if reflectHandled%1000 == 0 {
		fmt.Printf("Served %d reflections\n", reflectHandled)
	}
	var (
		v4  bool
		rr  dns.RR
		str string
		a   net.IP
	)
	m := new(dns.Msg)
	m.SetReply(r)
	m.Compress = *compress
	if ip, ok := w.RemoteAddr().(*net.UDPAddr); ok {
		str = "Port: " + strconv.Itoa(ip.Port) + " (udp)"
		a = ip.IP
		v4 = a.To4() != nil
	}
	if ip, ok := w.RemoteAddr().(*net.TCPAddr); ok {
		str = "Port: " + strconv.Itoa(ip.Port) + " (tcp)"
		a = ip.IP
		v4 = a.To4() != nil
	}

	if v4 {
		rr = new(dns.A)
		rr.(*dns.A).Hdr = dns.RR_Header{Name: dom, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 0}
		rr.(*dns.A).A = a.To4()
	} else {
		rr = new(dns.AAAA)
		rr.(*dns.AAAA).Hdr = dns.RR_Header{Name: dom, Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Ttl: 0}
		rr.(*dns.AAAA).AAAA = a
	}

	t := new(dns.TXT)
	t.Hdr = dns.RR_Header{Name: dom, Rrtype: dns.TypeTXT, Class: dns.ClassINET, Ttl: 0}
	t.Txt = []string{str}

	switch r.Question[0].Qtype {
	case dns.TypeTXT:
		m.Answer = append(m.Answer, t)
		m.Extra = append(m.Extra, rr)
	default:
		fallthrough
	case dns.TypeAAAA, dns.TypeA:
		m.Answer = append(m.Answer, rr)
		m.Extra = append(m.Extra, t)

	case dns.TypeAXFR, dns.TypeIXFR:
		c := make(chan *dns.Envelope)
		tr := new(dns.Transfer)
		defer close(c)
		err := tr.Out(w, r, c)
		if err != nil {
			return
		}
		soa, _ := dns.NewRR(`whoami.miek.nl. 0 IN SOA linode.atoom.net. miek.miek.nl. 2009032802 21600 7200 604800 3600`)
		c <- &dns.Envelope{RR: []dns.RR{soa, t, rr, soa}}
		w.Hijack()
		// w.Close() // Client closes connection
		return

	}

	if r.IsTsig() != nil {
		if w.TsigStatus() == nil {
			m.SetTsig(r.Extra[len(r.Extra)-1].(*dns.TSIG).Hdr.Name, dns.HmacMD5, 300, time.Now().Unix())
		} else {
			println("Status", w.TsigStatus().Error())
		}
	}
	if *printf {
		fmt.Printf("%v\n", m.String())
	}
	// set TC when question is tc.miek.nl.
	if m.Question[0].Name == "tc.miek.nl." {
		m.Truncated = true
		// send half a message
		buf, _ := m.Pack()
		w.Write(buf[:len(buf)/2])
		return
	}
	w.WriteMsg(m)
}
예제 #10
0
파일: q.go 프로젝트: valm0unt/exdns
func main() {
	short = flag.Bool("short", false, "abbreviate long DNSSEC records")
	dnssec := flag.Bool("dnssec", false, "request DNSSEC records")
	query := flag.Bool("question", false, "show question")
	check := flag.Bool("check", false, "check internal DNSSEC consistency")
	six := flag.Bool("6", false, "use IPv6 only")
	four := flag.Bool("4", false, "use IPv4 only")
	anchor := flag.String("anchor", "", "use the DNSKEY in this file as trust anchor")
	tsig := flag.String("tsig", "", "request tsig with key: [hmac:]name:key")
	port := flag.Int("port", 53, "port number to use")
	aa := flag.Bool("aa", false, "set AA flag in query")
	ad := flag.Bool("ad", false, "set AD flag in query")
	cd := flag.Bool("cd", false, "set CD flag in query")
	rd := flag.Bool("rd", true, "set RD flag in query")
	fallback := flag.Bool("fallback", false, "fallback to 4096 bytes bufsize and after that TCP")
	tcp := flag.Bool("tcp", false, "TCP mode, multiple queries are asked over the same connection")
	nsid := flag.Bool("nsid", false, "set edns nsid option")
	client := flag.String("client", "", "set edns client-subnet option")
	clientdraftcode := flag.Bool("clientdraft", false, "set edns client-subnet option using the draft option code")
	opcode := flag.String("opcode", "query", "set opcode to query|update|notify")
	rcode := flag.String("rcode", "success", "set rcode to noerror|formerr|nxdomain|servfail|...")
	//serial := flag.Int("serial", 0, "perform an IXFR with this serial")
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage: %s [options] [@server] [qtype...] [qclass...] [name ...]\n", os.Args[0])
		flag.PrintDefaults()
	}

	var (
		qtype  []uint16
		qclass []uint16
		qname  []string
	)

	flag.Parse()
	if *anchor != "" {
		f, err := os.Open(*anchor)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Failure to open %s: %s\n", *anchor, err.Error())
		}
		r, err := dns.ReadRR(f, *anchor)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Failure to read an RR from %s: %s\n", *anchor, err.Error())
		}
		if k, ok := r.(*dns.DNSKEY); !ok {
			fmt.Fprintf(os.Stderr, "No DNSKEY read from %s\n", *anchor)
		} else {
			dnskey = k
		}
	}

	var nameserver string

Flags:
	for i := 0; i < flag.NArg(); i++ {
		// If it starts with @ it is a nameserver
		if flag.Arg(i)[0] == '@' {
			nameserver = flag.Arg(i)
			continue Flags
		}
		// First class, then type, to make ANY queries possible
		// And if it looks like type, it is a type
		if k, ok := dns.StringToType[strings.ToUpper(flag.Arg(i))]; ok {
			qtype = append(qtype, k)
			continue Flags
		}
		// If it looks like a class, it is a class
		if k, ok := dns.StringToClass[strings.ToUpper(flag.Arg(i))]; ok {
			qclass = append(qclass, k)
			continue Flags
		}
		// If it starts with TYPExxx it is unknown rr
		if strings.HasPrefix(flag.Arg(i), "TYPE") {
			i, e := strconv.Atoi(string([]byte(flag.Arg(i))[4:]))
			if e == nil {
				qtype = append(qtype, uint16(i))
				continue Flags
			}
		}
		// If it starts with CLASSxxx it is unknown class
		if strings.HasPrefix(flag.Arg(i), "CLASS") {
			i, e := strconv.Atoi(string([]byte(flag.Arg(i))[5:]))
			if e == nil {
				qclass = append(qclass, uint16(i))
				continue Flags
			}
		}
		// Anything else is a qname
		qname = append(qname, flag.Arg(i))
	}
	if len(qname) == 0 {
		qname = []string{"."}
		if len(qtype) == 0 {
			qtype = append(qtype, dns.TypeNS)
		}
	}
	if len(qtype) == 0 {
		qtype = append(qtype, dns.TypeA)
	}
	if len(qclass) == 0 {
		qclass = append(qclass, dns.ClassINET)
	}

	if len(nameserver) == 0 {
		conf, err := dns.ClientConfigFromFile("/etc/resolv.conf")
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(2)
		}
		nameserver = "@" + conf.Servers[0]
	}

	nameserver = string([]byte(nameserver)[1:]) // chop off @
	// if the nameserver is from /etc/resolv.conf the [ and ] are already
	// added, thereby breaking net.ParseIP. Check for this and don't
	// fully qualify such a name
	if nameserver[0] == '[' && nameserver[len(nameserver)-1] == ']' {
		nameserver = nameserver[1 : len(nameserver)-1]
	}
	if i := net.ParseIP(nameserver); i != nil {
		nameserver = net.JoinHostPort(nameserver, strconv.Itoa(*port))
	} else {
		nameserver = dns.Fqdn(nameserver) + ":" + strconv.Itoa(*port)
	}
	c := new(dns.Client)
	t := new(dns.Transfer)
	c.Net = "udp"
	if *four {
		c.Net = "udp4"
	}
	if *six {
		c.Net = "udp6"
	}
	if *tcp {
		c.Net = "tcp"
		if *four {
			c.Net = "tcp4"
		}
		if *six {
			c.Net = "tcp6"
		}
	}

	m := new(dns.Msg)
	m.MsgHdr.Authoritative = *aa
	m.MsgHdr.AuthenticatedData = *ad
	m.MsgHdr.CheckingDisabled = *cd
	m.MsgHdr.RecursionDesired = *rd
	m.Question = make([]dns.Question, 1)
	m.Opcode = dns.OpcodeQuery
	if op, ok := dns.StringToOpcode[strings.ToUpper(*opcode)]; ok {
		m.Opcode = op
	}
	m.Rcode = dns.RcodeSuccess
	if rc, ok := dns.StringToRcode[strings.ToUpper(*rcode)]; ok {
		m.Rcode = rc
	}

	if *dnssec || *nsid || *client != "" {
		o := new(dns.OPT)
		o.Hdr.Name = "."
		o.Hdr.Rrtype = dns.TypeOPT
		if *dnssec {
			o.SetDo()
			o.SetUDPSize(dns.DefaultMsgSize)
		}
		if *nsid {
			e := new(dns.EDNS0_NSID)
			e.Code = dns.EDNS0NSID
			o.Option = append(o.Option, e)
			// NSD will not return nsid when the udp message size is too small
			o.SetUDPSize(dns.DefaultMsgSize)
		}
		if *client != "" {
			e := new(dns.EDNS0_SUBNET)
			e.Code = dns.EDNS0SUBNET
			if *clientdraftcode {
				e.DraftOption = true
			}
			e.SourceScope = 0
			e.Address = net.ParseIP(*client)
			if e.Address == nil {
				fmt.Fprintf(os.Stderr, "Failure to parse IP address: %s\n", *client)
				return
			}
			e.Family = 1 // IP4
			e.SourceNetmask = net.IPv4len * 8
			if e.Address.To4() == nil {
				e.Family = 2 // IP6
				e.SourceNetmask = net.IPv6len * 8
			}
			o.Option = append(o.Option, e)
		}
		m.Extra = append(m.Extra, o)
	}
	if *tcp {
		co := new(dns.Conn)
		tcp := "tcp"
		if *six {
			tcp = "tcp6"
		}
		var err error
		if co.Conn, err = net.DialTimeout(tcp, nameserver, 2*time.Second); err != nil {
			fmt.Fprintf(os.Stderr, "Dialing "+nameserver+" failed: "+err.Error()+"\n")
			return
		}
		defer co.Close()
		qt := dns.TypeA
		qc := uint16(dns.ClassINET)
		for i, v := range qname {
			if i < len(qtype) {
				qt = qtype[i]
			}
			if i < len(qclass) {
				qc = qclass[i]
			}
			m.Question[0] = dns.Question{dns.Fqdn(v), qt, qc}
			m.Id = dns.Id()
			if *tsig != "" {
				if algo, name, secret, ok := tsigKeyParse(*tsig); ok {
					m.SetTsig(name, algo, 300, time.Now().Unix())
					c.TsigSecret = map[string]string{name: secret}
					t.TsigSecret = map[string]string{name: secret}
				} else {
					fmt.Fprintf(os.Stderr, ";; TSIG key data error\n")
					continue
				}
			}
			co.SetReadDeadline(time.Now().Add(2 * time.Second))
			co.SetWriteDeadline(time.Now().Add(2 * time.Second))

			if *query {
				fmt.Printf("%s", m.String())
				fmt.Printf("\n;; size: %d bytes\n\n", m.Len())
			}
			then := time.Now()
			if e := co.WriteMsg(m); e != nil {
				fmt.Fprintf(os.Stderr, ";; %s\n", e.Error())
				continue
			}
			r, e := co.ReadMsg()
			if e != nil {
				fmt.Fprintf(os.Stderr, ";; %s\n", e.Error())
				continue
			}
			rtt := time.Since(then)
			if r.Id != m.Id {
				fmt.Fprintf(os.Stderr, "Id mismatch\n")
				continue
			}

			if *check {
				sigCheck(r, nameserver, true)
				denialCheck(r)
				fmt.Println()
			}
			if *short {
				r = shortMsg(r)
			}

			fmt.Printf("%v", r)
			fmt.Printf("\n;; query time: %.3d µs, server: %s(%s), size: %d bytes\n", rtt/1e3, nameserver, tcp, r.Len())
		}
		return
	}

	qt := dns.TypeA
	qc := uint16(dns.ClassINET)

Query:
	for i, v := range qname {
		if i < len(qtype) {
			qt = qtype[i]
		}
		if i < len(qclass) {
			qc = qclass[i]
		}
		m.Question[0] = dns.Question{dns.Fqdn(v), qt, qc}
		m.Id = dns.Id()
		if *tsig != "" {
			if algo, name, secret, ok := tsigKeyParse(*tsig); ok {
				m.SetTsig(name, algo, 300, time.Now().Unix())
				c.TsigSecret = map[string]string{name: secret}
				t.TsigSecret = map[string]string{name: secret}
			} else {
				fmt.Fprintf(os.Stderr, "TSIG key data error\n")
				continue
			}
		}
		if *query {
			fmt.Printf("%s", m.String())
			fmt.Printf("\n;; size: %d bytes\n\n", m.Len())
		}
		if qt == dns.TypeAXFR || qt == dns.TypeIXFR {
			env, err := t.In(m, nameserver)
			if err != nil {
				fmt.Printf(";; %s\n", err.Error())
				continue
			}
			envelope := 0
			record := 0
			for e := range env {
				if e.Error != nil {
					fmt.Printf(";; %s\n", e.Error.Error())
					continue Query
				}
				for _, r := range e.RR {
					fmt.Printf("%s\n", r)
				}
				record += len(e.RR)
				envelope++
			}
			fmt.Printf("\n;; xfr size: %d records (envelopes %d)\n", record, envelope)
			continue
		}
		r, rtt, e := c.Exchange(m, nameserver)
	Redo:
		if e != nil {
			fmt.Printf(";; %s\n", e.Error())
			continue
		}
		if r.Id != m.Id {
			fmt.Fprintf(os.Stderr, "Id mismatch\n")
			return
		}
		if r.MsgHdr.Truncated && *fallback {
			if !*dnssec {
				fmt.Printf(";; Truncated, trying %d bytes bufsize\n", dns.DefaultMsgSize)
				o := new(dns.OPT)
				o.Hdr.Name = "."
				o.Hdr.Rrtype = dns.TypeOPT
				o.SetUDPSize(dns.DefaultMsgSize)
				m.Extra = append(m.Extra, o)
				r, rtt, e = c.Exchange(m, nameserver)
				*dnssec = true
				goto Redo
			} else {
				// First EDNS, then TCP
				fmt.Printf(";; Truncated, trying TCP\n")
				c.Net = "tcp"
				r, rtt, e = c.Exchange(m, nameserver)
				goto Redo
			}
		}
		if r.MsgHdr.Truncated && !*fallback {
			fmt.Printf(";; Truncated\n")
		}
		if *check {
			sigCheck(r, nameserver, *tcp)
			denialCheck(r)
			fmt.Println()
		}
		if *short {
			r = shortMsg(r)
		}

		fmt.Printf("%v", r)
		fmt.Printf("\n;; query time: %.3d µs, server: %s(%s), size: %d bytes\n", rtt/1e3, nameserver, c.Net, r.Len())
	}
}
예제 #11
0
// AXFR attempts a zone transfer for the domain.
func AXFR(domain, serverAddr string) (string, Results, error) {
	task := "axfr"
	results := Results{}

	servers, err := LookupNS(domain, serverAddr)
	if err != nil {
		return task, results, err
	}

	for _, s := range servers {
		tr := dns.Transfer{}
		m := &dns.Msg{}
		m.SetAxfr(dns.Fqdn(domain))
		in, err := tr.In(m, s+":53")
		if err != nil {
			return task, results, err
		}
		for ex := range in {
			for _, a := range ex.RR {
				var ip, hostname string
				switch v := a.(type) {
				case *dns.A:
					ip = v.A.String()
					hostname = v.Hdr.Name
				case *dns.AAAA:
					ip = v.AAAA.String()
					hostname = v.Hdr.Name
				case *dns.PTR:
					ip = v.Hdr.Name
					hostname = v.Ptr
				case *dns.NS:
					cip, err := LookupName(v.Ns, serverAddr)
					if err != nil || cip == "" {
						continue
					}
					ip = cip
					hostname = v.Ns
				case *dns.CNAME:
					cip, err := LookupName(v.Target, serverAddr)
					if err != nil || cip == "" {
						continue
					}
					hostname = v.Hdr.Name
					ip = cip
				case *dns.SRV:
					cip, err := LookupName(v.Target, serverAddr)
					if err != nil || ip == "" {
						continue
					}
					ip = cip
					hostname = v.Target
				default:
					continue
				}
				results = append(results, Result{
					Source:   task,
					IP:       ip,
					Hostname: strings.TrimRight(hostname, "."),
				})
			}
		}
	}
	return task, results, nil
}