|
1 | 1 | package main
|
2 | 2 |
|
3 | 3 | import (
|
| 4 | + "flag" |
4 | 5 | "fmt"
|
5 | 6 | "log"
|
6 |
| - "net" |
| 7 | + "os" |
7 | 8 |
|
8 | 9 | "github.com/miekg/dns"
|
| 10 | + "golang.org/x/sync/errgroup" |
9 | 11 | )
|
10 | 12 |
|
11 |
| -type root struct { |
12 |
| - // map of TLDs to nameservers |
13 |
| - tld map[string][]string |
14 |
| - // map of nameservers to ipv4 and ipv6 |
15 |
| - ip map[string][]net.IP |
16 |
| -} |
| 13 | +var ( |
| 14 | + initialNameserver = flag.String("ns", "", "initial nameserver to use to get the root") |
| 15 | + parallel = flag.Uint("parallel", 10, "number of parallel zone transfers to perform") |
| 16 | + saveDir = flag.String("out", ".", "directory to save found zones in") |
| 17 | + verbose = flag.Bool("verbose", false, "enable verbose output") |
| 18 | +) |
17 | 19 |
|
18 |
| -func (r *root) AddTLD(tld, nameserver string) { |
19 |
| - if r.tld == nil { |
20 |
| - r.tld = make(map[string][]string) |
21 |
| - } |
22 |
| - _, ok := r.tld[tld] |
23 |
| - if !ok { |
24 |
| - r.tld[tld] = make([]string, 0, 4) |
| 20 | +func main() { |
| 21 | + flag.Parse() |
| 22 | + localNameserver, err := getInitialNameserver() |
| 23 | + check(err) |
| 24 | + if *verbose { |
| 25 | + log.Printf("Using initial nameserver %s", localNameserver) |
25 | 26 | }
|
26 |
| - r.tld[tld] = append(r.tld[tld], nameserver) |
27 |
| -} |
| 27 | + rootNameservers, err := getRootServers(localNameserver) |
| 28 | + check(err) |
28 | 29 |
|
29 |
| -func (r *root) AddIP(nameserver string, ip net.IP) { |
30 |
| - if r.ip == nil { |
31 |
| - r.ip = make(map[string][]net.IP) |
| 30 | + var root zone |
| 31 | + // not all the root nameservers allow AXFR, try them until we find one that does |
| 32 | + for _, ns := range rootNameservers { |
| 33 | + if *verbose { |
| 34 | + log.Printf("Trying root nameserver %s", ns) |
| 35 | + } |
| 36 | + root, err = rootAXFR(ns) |
| 37 | + if err == nil { |
| 38 | + break |
| 39 | + } |
32 | 40 | }
|
33 |
| - _, ok := r.ip[nameserver] |
34 |
| - if !ok { |
35 |
| - r.ip[nameserver] = make([]net.IP, 0, 4) |
| 41 | + if root.CountNS() == 0 { |
| 42 | + log.Fatal("Got empty root zone") |
36 | 43 | }
|
37 |
| - r.ip[nameserver] = append(r.ip[nameserver], ip) |
38 |
| -} |
39 | 44 |
|
40 |
| -func (r *root) Print() { |
41 |
| - fmt.Println("NS:") |
42 |
| - for zone := range r.tld { |
43 |
| - fmt.Printf("%s\n", zone) |
44 |
| - for i := range r.tld[zone] { |
45 |
| - fmt.Printf("\t%s\n", r.tld[zone][i]) |
46 |
| - } |
47 |
| - } |
48 |
| - fmt.Println("IP:") |
49 |
| - for ns := range r.ip { |
50 |
| - fmt.Printf("%s\n", ns) |
51 |
| - for i := range r.ip[ns] { |
52 |
| - fmt.Printf("\t%s\n", r.ip[ns][i]) |
53 |
| - } |
| 45 | + // create outpout dir if does not exist |
| 46 | + if _, err := os.Stat(*saveDir); os.IsNotExist(err) { |
| 47 | + err = os.MkdirAll(*saveDir, os.ModePerm) |
| 48 | + check(err) |
54 | 49 | }
|
55 |
| -} |
56 | 50 |
|
57 |
| -func (r *root) PrintTree() { |
58 |
| - fmt.Println("Zones:") |
59 |
| - for zone := range r.tld { |
60 |
| - fmt.Printf("%s\n", zone) |
61 |
| - for i := range r.tld[zone] { |
62 |
| - fmt.Printf("\t%s\n", r.tld[zone][i]) |
63 |
| - for j := range r.ip[r.tld[zone][i]] { |
64 |
| - fmt.Printf("\t\t%s\n", r.ip[r.tld[zone][i]][j]) |
65 |
| - } |
66 |
| - } |
| 51 | + if *verbose { |
| 52 | + root.PrintTree() |
67 | 53 | }
|
68 |
| -} |
| 54 | + rootChan := root.GetNsIPChan() |
| 55 | + var g errgroup.Group |
69 | 56 |
|
70 |
| -func main() { |
71 |
| - server, err := getRootServer() |
72 |
| - check(err) |
| 57 | + // start workers |
| 58 | + for i := uint(0); i < *parallel; i++ { |
| 59 | + g.Go(func() error { return worker(rootChan) }) |
| 60 | + } |
73 | 61 |
|
74 |
| - log.Printf("using server %s", server) |
75 |
| - err = rootAXFR(server) |
| 62 | + err = g.Wait() |
76 | 63 | check(err)
|
77 |
| - log.Printf("done") |
78 | 64 | }
|
79 | 65 |
|
80 |
| -func check(err error) { |
81 |
| - if err != nil { |
82 |
| - log.Fatal(err) |
83 |
| - } |
84 |
| -} |
85 |
| - |
86 |
| -func rootAXFR(ns string) error { |
87 |
| - m := new(dns.Msg) |
88 |
| - m.SetQuestion(".", dns.TypeAXFR) |
89 |
| - |
90 |
| - t := new(dns.Transfer) |
91 |
| - |
92 |
| - var root root |
93 |
| - |
94 |
| - env, err := t.In(m, fmt.Sprintf("%s:53", ns)) |
95 |
| - if err != nil { |
96 |
| - return err |
97 |
| - } |
98 |
| - var envelope, record int |
99 |
| - for e := range env { |
100 |
| - //fmt.Println("envelope loop") // 108, contains abut 200 records |
101 |
| - if e.Error != nil { |
102 |
| - return e.Error |
| 66 | +func worker(c chan nsip) error { |
| 67 | + for { |
| 68 | + r, more := <-c |
| 69 | + if !more { |
| 70 | + return nil |
103 | 71 | }
|
104 |
| - for _, r := range e.RR { |
105 |
| - //fmt.Println("RR loop") // 22077 |
106 |
| - //fmt.Printf("IAN: %s\n", r) |
107 |
| - switch t := r.(type) { |
108 |
| - case *dns.A: |
109 |
| - root.AddIP(t.Hdr.Name, t.A) |
110 |
| - case *dns.AAAA: |
111 |
| - root.AddIP(t.Hdr.Name, t.AAAA) |
112 |
| - case *dns.NS: |
113 |
| - root.AddTLD(t.Hdr.Name, t.Ns) |
114 |
| - } |
| 72 | + err := axfr(r.domain, r.ns, r.ip) |
| 73 | + if err != nil { |
| 74 | + return err |
115 | 75 | }
|
116 |
| - record += len(e.RR) |
117 |
| - envelope++ |
118 | 76 | }
|
119 |
| - log.Printf("\n;; xfr size: %d records (envelopes %d)\n", record, envelope) |
120 |
| - |
121 |
| - root.PrintTree() |
122 |
| - return nil |
123 | 77 | }
|
124 | 78 |
|
125 |
| -var ErrNoRoot = fmt.Errorf("Unable to find Root Server") |
126 |
| - |
127 |
| -func getRootServer() (string, error) { |
128 |
| - // get root server from local DNS |
129 |
| - conf, err := dns.ClientConfigFromFile("/etc/resolv.conf") |
| 79 | +func check(err error) { |
130 | 80 | if err != nil {
|
131 |
| - return "", err |
| 81 | + log.Fatal(err) |
132 | 82 | }
|
133 |
| - localserver := fmt.Sprintf("%s:%s", conf.Servers[0], conf.Port) |
| 83 | +} |
134 | 84 |
|
135 |
| - // get root servers |
136 |
| - m := new(dns.Msg) |
137 |
| - m.SetQuestion(".", dns.TypeNS) |
138 |
| - in, err := dns.Exchange(m, localserver) |
139 |
| - if err != nil { |
140 |
| - return "", err |
141 |
| - } |
142 |
| - //fmt.Println(in) |
143 |
| - for _, a := range in.Answer { |
144 |
| - if ns, ok := a.(*dns.NS); ok { |
145 |
| - return ns.Ns, nil |
| 85 | +func getInitialNameserver() (string, error) { |
| 86 | + var server string |
| 87 | + if len(*initialNameserver) == 0 { |
| 88 | + // get root server from local DNS |
| 89 | + conf, err := dns.ClientConfigFromFile("/etc/resolv.conf") |
| 90 | + if err != nil { |
| 91 | + return "", err |
146 | 92 | }
|
| 93 | + server = fmt.Sprintf("%s:%s", conf.Servers[0], conf.Port) |
| 94 | + } else { |
| 95 | + server = fmt.Sprintf("%s:53", *initialNameserver) |
147 | 96 | }
|
148 |
| - return "", ErrNoRoot |
| 97 | + return server, nil |
149 | 98 | }
|
0 commit comments