Go Language dns seeder for Bitcoin based networks
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

171 lines
4.5 KiB

package main
import (
"log"
// "sync"
"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
}
}
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"
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)
}
}
/*
*/