-
-
Notifications
You must be signed in to change notification settings - Fork 62
/
xfr.go
100 lines (84 loc) · 2.05 KB
/
xfr.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
package main
import (
"fmt"
"io"
"os"
"path"
"strings"
"time"
"github.com/miekg/dns"
log "github.com/sirupsen/logrus"
"github.com/natesales/q/util"
)
var (
queried map[string]bool
all []dns.RR
)
func axfr(label, server string) []dns.RR {
t := new(dns.Transfer)
m := new(dns.Msg)
m.SetAxfr(dns.Fqdn(label))
ch, err := t.In(m, server)
if err != nil {
log.Fatalf("Failed to transfer zone: %s", err)
}
var rrs []dns.RR
for env := range ch {
if env.Error != nil {
log.Warnf("AXFR section error (%s): %s", label, env.Error)
continue
}
rrs = append(rrs, env.RR...)
}
return rrs
}
// RecAXFR performs an AXFR on the given label and all of its children and writes the zone file to disk
func RecAXFR(label, server string, out io.Writer) []dns.RR {
util.MustWritef(out, "Attempting recursive AXFR for %s\n", label)
// Reset state
queried = make(map[string]bool)
all = make([]dns.RR, 0)
dir := fmt.Sprintf("%s_%s_recaxfr",
strings.TrimPrefix(label, "."),
strings.ReplaceAll(time.Now().Format(time.UnixDate), " ", "-"),
)
// Create recursive AXFR directory if it doesn't exist
if _, err := os.Stat(dir); os.IsNotExist(err) {
err := os.MkdirAll(dir, 0755)
if err != nil {
log.Fatalf("creating recaxfr directory: %s", err)
}
}
addToTree(label, dir, server, out)
util.MustWritef(out, "AXFR complete, %d records saved to %s\n", len(all), dir)
return all
}
func addToTree(label, dir, server string, out io.Writer) {
label = dns.Fqdn(label)
if queried[label] {
return
}
util.MustWritef(out, "AXFR %s\n", label)
queried[label] = true
rrs := axfr(label, server)
// Write RRs to zone file
if len(rrs) > 0 {
var zoneFile string
for _, rr := range rrs {
zoneFile += rr.String() + "\n"
}
if err := os.WriteFile(
path.Join(dir, strings.TrimSuffix(label, ".")+".zone"),
[]byte(zoneFile),
0644,
); err != nil {
log.Fatalf("Failed to write zone file: %s", err)
}
}
for _, rr := range rrs {
all = append(all, rr)
if _, ok := rr.(*dns.NS); ok {
addToTree(rr.Header().Name, dir, server, out)
}
}
}