175 lines
3.9 KiB
Go
175 lines
3.9 KiB
Go
|
package common
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"time"
|
||
|
|
||
|
"github.com/miekg/dns"
|
||
|
)
|
||
|
|
||
|
type Pair struct {
|
||
|
Nameserver string
|
||
|
Domain string
|
||
|
}
|
||
|
|
||
|
var (
|
||
|
Nameservers, Valid, Recursive []string
|
||
|
Found bool
|
||
|
)
|
||
|
|
||
|
func message(domain string, reqtype uint16, ra bool) *dns.Msg {
|
||
|
msg := new(dns.Msg)
|
||
|
msg.Id = dns.Id()
|
||
|
msg.RecursionDesired = ra
|
||
|
msg.Question = make([]dns.Question, 1)
|
||
|
msg.Question[0] = dns.Question{dns.Fqdn(domain), reqtype, dns.ClassINET}
|
||
|
return msg
|
||
|
}
|
||
|
|
||
|
func ParseNS(nservers []string) ([]string, []string) {
|
||
|
var valid, recursive []string
|
||
|
msg := message("supernets.org", dns.TypeA, false)
|
||
|
for _, ns := range nservers {
|
||
|
in, err := dns.Exchange(msg, ns+":53")
|
||
|
if err != nil {
|
||
|
Error("nameserver " + ns + " is not responding")
|
||
|
continue
|
||
|
}
|
||
|
if in.Rcode == dns.RcodeRefused {
|
||
|
Warning("nameserver " + ns + " refused the test query, non-recursive snooping may not be viable")
|
||
|
}
|
||
|
if in.RecursionAvailable {
|
||
|
Success("nameserver " + ns + " is recursive")
|
||
|
recursive = append(recursive, ns)
|
||
|
}
|
||
|
valid = append(valid, ns)
|
||
|
}
|
||
|
return valid, recursive
|
||
|
}
|
||
|
|
||
|
func TestReq() bool {
|
||
|
msg := message("cloudflare.com", dns.TypeA, false)
|
||
|
in, err := dns.Exchange(msg, "1.1.1.1:53")
|
||
|
if err != nil {
|
||
|
return false
|
||
|
}
|
||
|
if len(in.Answer) > 0 {
|
||
|
return true
|
||
|
}
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
func PullNS(d string) {
|
||
|
nsmsg := message(d, dns.TypeNS, true)
|
||
|
in, err := dns.Exchange(nsmsg, "1.1.1.1:53")
|
||
|
if err != nil {
|
||
|
Fatal("unable to retrieve nameservers for " + d)
|
||
|
}
|
||
|
|
||
|
for _, ans := range in.Answer {
|
||
|
ns, ok := ans.(*dns.NS)
|
||
|
if ok {
|
||
|
Nameservers = append(Nameservers, ns.Ns)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
func Verify() {
|
||
|
if !TestReq() {
|
||
|
Error("neutral non-recursive query was refused, are you on a vpn or dirty box?")
|
||
|
}
|
||
|
Success("neutral non-recursive test query succeeded")
|
||
|
|
||
|
Valid, Recursive = ParseNS(Nameservers)
|
||
|
Info(fmt.Sprintf("%d/%d nameservers are recursive", len(Recursive), len(Valid)))
|
||
|
|
||
|
if len(Valid) == 0 {
|
||
|
Fatal("no valid nameservers available")
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func Query(q <-chan Pair, tracker chan<- interface{}, delay int) {
|
||
|
for pair := range q {
|
||
|
msg := message(pair.Domain, dns.TypeA, false)
|
||
|
in, err := dns.Exchange(msg, pair.Nameserver+":53")
|
||
|
if err != nil {
|
||
|
Error(err.Error())
|
||
|
continue
|
||
|
}
|
||
|
|
||
|
if len(in.Answer) > 0 {
|
||
|
Found = true
|
||
|
fmt.Printf("[%s] associated domain %s found on %s\n", Vendors[Domains[pair.Domain].Vendor], pair.Domain, pair.Nameserver)
|
||
|
}
|
||
|
time.Sleep(time.Duration(delay) * time.Millisecond)
|
||
|
}
|
||
|
tracker <- 1337
|
||
|
}
|
||
|
|
||
|
func QueryRA(q <-chan Pair, tracker chan<- interface{}, delay int) {
|
||
|
for pair := range q {
|
||
|
msg := message(pair.Domain, dns.TypeA, true)
|
||
|
for x := 0; x < 3; x++ {
|
||
|
in, err := dns.Exchange(msg, pair.Nameserver+":53")
|
||
|
if err != nil {
|
||
|
Error("hiccup on " + pair.Nameserver + " retrying...")
|
||
|
time.Sleep(1 * time.Second)
|
||
|
continue
|
||
|
}
|
||
|
|
||
|
if len(in.Answer) > 0 {
|
||
|
Found = true
|
||
|
if in.Answer[0].Header().Ttl != Domains[pair.Domain].TTL {
|
||
|
fmt.Printf("[%s] associated domain %s found on %s with mismatched TTL of %d\n", Vendors[Domains[pair.Domain].Vendor], pair.Domain, pair.Nameserver, in.Answer[0].Header().Ttl)
|
||
|
}
|
||
|
break
|
||
|
}
|
||
|
}
|
||
|
time.Sleep(time.Duration(delay) * time.Millisecond)
|
||
|
}
|
||
|
tracker <- 1337
|
||
|
}
|
||
|
|
||
|
func Run(ra bool, threads, delay int) {
|
||
|
pairs := make(chan Pair)
|
||
|
tracker := make(chan interface{})
|
||
|
|
||
|
if !ra {
|
||
|
// non-recursive snoop
|
||
|
Info(fmt.Sprintf("non-recursive snooping on %d resolvers...\n", len(Valid)))
|
||
|
go func() {
|
||
|
for i := 0; i < threads; i++ {
|
||
|
Query(pairs, tracker, delay)
|
||
|
}
|
||
|
}()
|
||
|
|
||
|
for _, ns := range Valid {
|
||
|
for k, _ := range Domains {
|
||
|
pairs <- Pair{Nameserver: ns, Domain: k}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
close(pairs)
|
||
|
} else {
|
||
|
Info(fmt.Sprintf("recursively snooping on %d resolvers...\n", len(Recursive)))
|
||
|
go func() {
|
||
|
for i := 0; i < threads; i++ {
|
||
|
QueryRA(pairs, tracker, delay)
|
||
|
}
|
||
|
}()
|
||
|
|
||
|
for _, ns := range Recursive {
|
||
|
for k, _ := range Domains {
|
||
|
pairs <- Pair{Nameserver: ns, Domain: k}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
close(pairs)
|
||
|
}
|
||
|
|
||
|
for x := 0; x < threads; x++ {
|
||
|
<-tracker
|
||
|
}
|
||
|
}
|