dnsseeder/dnsseed/dnsseed.go

73 lines
1.9 KiB
Go

package dnsseed
import (
"context"
"net"
"github.com/coredns/coredns/plugin"
"github.com/coredns/coredns/request"
"github.com/miekg/dns"
"github.com/zcashfoundation/dnsseeder/zcash"
)
// ZcashSeeder discovers IP addresses by asking Zcash peers for them.
type ZcashSeeder struct {
Next plugin.Handler
Zones []string
seeder *zcash.Seeder
opts *options
}
// Name satisfies the Handler interface.
func (zs ZcashSeeder) Name() string { return "dnsseed" }
// Ready implements the ready.Readiness interface, once this flips to true CoreDNS
// assumes this plugin is ready for queries; it is not checked again.
func (zs ZcashSeeder) Ready() bool {
// setup() has attempted an initial connection to the backing peer already.
return zs.seeder.Ready()
}
func (zs ZcashSeeder) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) {
// Check if it's a question for us
state := request.Request{W: w, Req: r}
zone := plugin.Zones(zs.Zones).Matches(state.Name())
if zone == "" {
return plugin.NextOrFailure(zs.Name(), zs.Next, ctx, w, r)
}
var peerIPs []net.IP
switch state.QType() {
case dns.TypeA:
peerIPs = zs.seeder.Addresses(25)
case dns.TypeAAAA:
peerIPs = zs.seeder.AddressesV6(25)
default:
return dns.RcodeNotImplemented, nil
}
a := new(dns.Msg)
a.SetReply(r)
a.Authoritative = true
a.Answer = make([]dns.RR, 0, 25)
for i := 0; i < len(peerIPs); i++ {
var rr dns.RR
if peerIPs[i].To4() == nil {
rr = new(dns.AAAA)
rr.(*dns.AAAA).Hdr = dns.RR_Header{Name: state.QName(), Rrtype: dns.TypeAAAA, Ttl: zs.opts.recordTTL, Class: state.QClass()}
rr.(*dns.AAAA).AAAA = peerIPs[i]
} else {
rr = new(dns.A)
rr.(*dns.A).Hdr = dns.RR_Header{Name: state.QName(), Rrtype: dns.TypeA, Ttl: zs.opts.recordTTL, Class: state.QClass()}
rr.(*dns.A).A = peerIPs[i]
}
a.Answer = append(a.Answer, rr)
}
w.WriteMsg(a)
return dns.RcodeSuccess, nil
}