forked from cpacia/dnsseeder
-
Notifications
You must be signed in to change notification settings - Fork 4
/
dns.go
191 lines (160 loc) · 5.18 KB
/
dns.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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
package main
import (
"log"
"time"
"github.com/btcsuite/btcd/wire"
"github.com/miekg/dns"
)
// updateDNS updates the current slices of dns.RR so incoming requests get a
// fast answer
func updateDNS(s *dnsseeder) {
var rr4std, rr4non, rr6std, rr6non []dns.RR
s.mtx.RLock()
// loop over each dns recprd type we need
for t := range []int{dnsV4Std, dnsV4Non, dnsV6Std, dnsV6Non} {
// FIXME above needs to be convertwd into one scan of theList if possible
numRR := 0
for _, nd := range s.theList {
// when we reach max exit
if numRR >= 25 {
break
}
if nd.status != statusCG {
continue
}
if t == dnsV4Std || t == dnsV4Non {
if t == dnsV4Std && nd.dnsType == dnsV4Std {
r := new(dns.A)
r.Hdr = dns.RR_Header{Name: s.dnsHost + ".", Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: s.ttl}
r.A = nd.na.IP
rr4std = append(rr4std, r)
numRR++
}
// if the node is using a non standard port then add the encoded port info to DNS
if t == dnsV4Non && nd.dnsType == dnsV4Non {
r := new(dns.A)
r.Hdr = dns.RR_Header{Name: "nonstd." + s.dnsHost + ".", Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: s.ttl}
r.A = nd.na.IP
rr4non = append(rr4non, r)
numRR++
r = new(dns.A)
r.Hdr = dns.RR_Header{Name: "nonstd." + s.dnsHost + ".", Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: s.ttl}
r.A = nd.nonstdIP
rr4non = append(rr4non, r)
numRR++
}
}
if t == dnsV6Std || t == dnsV6Non {
if t == dnsV6Std && nd.dnsType == dnsV6Std {
r := new(dns.AAAA)
r.Hdr = dns.RR_Header{Name: s.dnsHost + ".", Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Ttl: s.ttl}
r.AAAA = nd.na.IP
rr6std = append(rr6std, r)
numRR++
}
// if the node is using a non standard port then add the encoded port info to DNS
if t == dnsV6Non && nd.dnsType == dnsV6Non {
r := new(dns.AAAA)
r.Hdr = dns.RR_Header{Name: "nonstd." + s.dnsHost + ".", Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Ttl: s.ttl}
r.AAAA = nd.na.IP
rr6non = append(rr6non, r)
numRR++
r = new(dns.AAAA)
r.Hdr = dns.RR_Header{Name: "nonstd." + s.dnsHost + ".", Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Ttl: s.ttl}
r.AAAA = nd.nonstdIP
rr6non = append(rr6non, r)
numRR++
}
}
}
}
s.mtx.RUnlock()
config.dnsmtx.Lock()
// update the map holding the details for this seeder
for t := range []int{dnsV4Std, dnsV4Non, dnsV6Std, dnsV6Non} {
switch t {
case dnsV4Std:
config.dns[s.dnsHost+".A"] = rr4std
case dnsV4Non:
config.dns["nonstd."+s.dnsHost+".A"] = rr4non
case dnsV6Std:
config.dns[s.dnsHost+".AAAA"] = rr6std
case dnsV6Non:
config.dns["nonstd."+s.dnsHost+".AAAA"] = rr6non
}
}
// Add NS and SOA answers
r := new(dns.NS)
r.Hdr = dns.RR_Header{Name: s.dnsHost + ".", Rrtype: dns.TypeNS, Class: dns.ClassINET, Ttl: 40000}
r.Ns = s.nameServer + "."
config.dns[s.dnsHost+".NS"] = []dns.RR{r}
r2 := new(dns.SOA)
r2.Hdr = dns.RR_Header{Name: s.dnsHost + ".", Rrtype: dns.TypeSOA, Class: dns.ClassINET, Ttl: 40000}
r2.Ns = s.nameServer + "."
r2.Mbox = s.mbox + "."
r2.Refresh = 604800
r2.Retry = 86400
r2.Expire = 2592000
r2.Minttl = 604800
r2.Serial = uint32(time.Now().Unix())
config.dns[s.dnsHost+".SOA"] = []dns.RR{r2}
config.dnsmtx.Unlock()
if config.stats {
s.counts.mtx.RLock()
log.Printf("%s - DNS available: v4std: %v v4non: %v v6std: %v v6non: %v\n", s.name, len(rr4std), len(rr4non), len(rr6std), len(rr6non))
log.Printf("%s - DNS counts: v4std: %v v4non: %v v6std: %v v6non: %v total: %v\n",
s.name,
s.counts.DNSCounts[dnsV4Std],
s.counts.DNSCounts[dnsV4Non],
s.counts.DNSCounts[dnsV6Std],
s.counts.DNSCounts[dnsV6Non],
s.counts.DNSCounts[dnsV4Std]+s.counts.DNSCounts[dnsV4Non]+s.counts.DNSCounts[dnsV6Std]+s.counts.DNSCounts[dnsV6Non])
s.counts.mtx.RUnlock()
}
}
// handleDNS processes a DNS request from remote client and returns
// a list of current ip addresses that the crawlers consider current.
func handleDNS(w dns.ResponseWriter, r *dns.Msg) {
m := &dns.Msg{MsgHdr: dns.MsgHdr{
Authoritative: true,
RecursionAvailable: false,
}}
m.SetReply(r)
var qtype string
switch r.Question[0].Qtype {
case dns.TypeA:
qtype = "A"
case dns.TypeAAAA:
qtype = "AAAA"
case dns.TypeTXT:
qtype = "TXT"
case dns.TypeMX:
qtype = "MX"
case dns.TypeNS:
qtype = "NS"
case dns.TypeSOA:
qtype = "SOA"
default:
qtype = "UNKNOWN"
}
config.dnsmtx.RLock()
// if the dns map does not have a key for the request it will return an empty slice
m.Answer = config.dns[r.Question[0].Name+qtype]
config.dnsmtx.RUnlock()
w.WriteMsg(m)
if config.debug {
log.Printf("debug - DNS response Type: standard To IP: %s Query Type: %s\n", w.RemoteAddr().String(), qtype)
}
// update the stats in a goroutine
go updateDNSCounts(r.Question[0].Name, qtype)
}
// serve starts the requested DNS server listening on the requested port
func serve(net, port string) {
server := &dns.Server{Addr: ":" + port, Net: net, TsigSecret: nil}
if err := server.ListenAndServe(); err != nil {
log.Printf("Failed to setup the "+net+" server: %v\n", err)
}
}
func HasService(services wire.ServiceFlag, flag wire.ServiceFlag) bool {
return services&flag == flag
}