第一个dns查询
package mainimport ("fmt""github.com/miekg/dns")func main() {var msg dns.Msgfqdn := dns.Fqdn("baidu.com")msg.SetQuestion(fqdn,dns.TypeA)in, err := dns.Exchange(&msg, "114.114.114.114:53")if err!= nil{panic(err)}fmt.Println(len(in.Answer))fmt.Println(in.Answer)for _,v := range (in.Answer){fmt.Println(v.(*dns.A))}}

第19行是一个go的类型断言,确保v是dns.类型,否则就会panic
如我们修改为
fmt.Println(v.(*dns.CNAME))
实现一个子域名爆破
package mainimport ("bufio""errors""flag""fmt""github.com/miekg/dns""os""text/tabwriter")var (Server stringDomain stringWordlist stringWorkerCount int)type result struct {Ipaddr stringHostname string}type empty struct {}func lookupA(domain string)([]string,error){var ips []stringvar msg dns.Msgmsg.SetQuestion(dns.Fqdn(domain),dns.TypeA)in,err := dns.Exchange(&msg,Server)if err !=nil{return ips, err}if len(in.Answer)<1{return ips,errors.New("no record")}for _,answer := range in.Answer{if a,ok := answer.(*dns.A);ok{ips = append(ips,a.A.String())}}return ips,nil}func lookupCNAME(domain string)([]string,error) {var domains []stringvar msg dns.Msgmsg.SetQuestion(dns.Fqdn(domain),dns.TypeCNAME)in,err := dns.Exchange(&msg,Server)if err != nil{return domains, err}for _,answer := range in.Answer{if c,ok := answer.(*dns.CNAME);ok{domains = append(domains,c.Target)}}return domains,nil}func lookup(domain string) ([]result){var results []resultvar tmp_domain = domainfor{cnames,err := lookupCNAME(tmp_domain)if err == nil && len(cnames)>1{tmp_domain = cnames[0]continue}// 说明没有cname记录了ips ,err := lookupA(tmp_domain)if err != nil{break}for _,ip := range ips{results = append(results,result{Ipaddr: ip,Hostname: domain})}break}return results}func worker(tracer chan empty,domains chan string,gather chan []result) {for domain := range domains{results := lookup(domain)if len(results)>0{gather <- results}}var e emptytracer <- e}func init() {flag.StringVar(&Domain,"d","","target")flag.StringVar(&Wordlist,"w","dic/dics.txt","wordlist")flag.IntVar(&WorkerCount,"n",200,"workercount")flag.StringVar(&Server,"s","114.114.114.114:53","DNSServer")flag.Parse()if Domain == ""{flag.Usage()os.Exit(0)}}func main() {var results []resultdomains := make(chan string,WorkerCount)gather := make(chan []result)tracer := make(chan empty)dic ,err := os.Open(Wordlist)if err !=nil{panic(err)}defer dic.Close()scanner := bufio.NewScanner(dic)for i:=0;i<WorkerCount;i++{go worker(tracer,domains,gather)}for scanner.Scan(){domains <- fmt.Sprintf("%s.%s",scanner.Text(),Domain)}go func() {for r := range gather{results = append(results,r...) // gather类存储的为slice类型,...表示将slice类型打散进行传递,它是go的一个语法糖}var e emptytracer <- e}()close(domains) // 因为所有子域名已经发送完毕,关闭通道for j:=0;j<WorkerCount;j++{<-tracer}close(gather)<-tracer // 表示gather完成w := tabwriter.NewWriter(os.Stdout,0,8,4,' ', 0)for _, r := range results {fmt.Fprintf(w, "%s\t%s\n", r.Hostname, r.Ipaddr)}w.Flush()}
这段代码可能是写到现在较复杂的一段代码了。我们从main函数开始读起。首先创建了三个chan来处理数据,后面具体在看。接着打开用户指定的子域名字典按行读取。开启WorkerCount个子线程进行子域名爆破。但此时还没向chan注入数据,处于阻塞状态,再接下来开始注入数据。
domains <- fmt.Sprintf("%s.%s",scanner.Text(),Domain)
先不急着往下看,先看一下worker函数
for domain := range domains{
使用循环来依次从chan获取域名进行爆破。需要注意的是每次只能从chan里循环获取一个数据。那么它什么时候会结束循环呢,这里我们看到主函数在141行调用close函数关闭chan。本以为这里的close调用后会发送信号使循环停止,但在进行单独测试时发现不调用close,在无数据输入时循环也可以结束。调用close和不调用close的区别在于循环结束后是否执行循环体后的代码。这里就是
var e emptytracer <- e
tracer在本程序的作用是同步各线程使程序恰当结束。如果我们没有close,在主函数143-145就会发生阻塞程序无法退出。133-139行并发程序集合数据,146行关gather,完成后注入一个empty到tracer。148行如果
<-tracer // 阻塞
实现一个dns rebinding
package mainimport ("github.com/miekg/dns""log""net")var count intfunc main() {count = 0pcount := &countdns.HandleFunc(".", func(w dns.ResponseWriter, r *dns.Msg) {if count%2 == 0 {var resp dns.Msgresp.SetReply(r)for _,q := range r.Question{a := dns.A{Hdr: dns.RR_Header{Name: q.Name,Rrtype: dns.TypeA,Class: dns.ClassINET,Ttl: 0,},A:net.ParseIP("127.0.0.1").To4(),}resp.Answer = append(resp.Answer,&a)}w.WriteMsg(&resp)}else {var resp dns.Msgresp.SetReply(r)for _,q := range r.Question{a := dns.A{Hdr: dns.RR_Header{Name: q.Name,Rrtype: dns.TypeA,Class: dns.ClassINET,Ttl: 0,},A:net.ParseIP("129.211.73.107").To4(),}resp.Answer = append(resp.Answer,&a)}w.WriteMsg(&resp)}*pcount++})log.Fatal(dns.ListenAndServe(":53","udp",nil))}
最简单的方式实现了一个dns重绑定
