dnsseed: implement scaffold for a coredns plugin

This commit is contained in:
George Tankersley 2020-05-19 22:32:23 -04:00
parent d1ebd57070
commit f1c13a8fd6
5 changed files with 132 additions and 0 deletions

30
dnsseed/dnsseed.go Normal file
View File

@ -0,0 +1,30 @@
package dnsseed
import (
"context"
"github.com/coredns/coredns/plugin"
"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
seeder *zcash.Seeder
}
// 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) {
return plugin.NextOrFailure(zs.Name(), zs.Next, ctx, w, r)
}

3
dnsseed/dnsseed_test.go Normal file
View File

@ -0,0 +1,3 @@
package dnsseed
// TODO: intialize mock peers and test serving their addr inventories as A records

67
dnsseed/setup.go Normal file
View File

@ -0,0 +1,67 @@
package dnsseed
import (
"net"
"github.com/caddyserver/caddy"
"github.com/coredns/coredns/core/dnsserver"
"github.com/coredns/coredns/plugin"
clog "github.com/coredns/coredns/plugin/pkg/log"
"github.com/zcashfoundation/dnsseeder/zcash"
"github.com/zcashfoundation/dnsseeder/zcash/network"
)
var log = clog.NewWithPlugin("dnsseed")
func init() { plugin.Register("dnsseed", setup) }
// setup is the function that gets called when the config parser see the token "dnsseed". Setup is responsible
// for parsing any extra options the example plugin may have. The first token this function sees is "dnsseed".
func setup(c *caddy.Controller) error {
var networkArg, hostArg string
c.Next() // Ignore "dnsseed" and give us the next token.
if !c.Args(&networkArg, &hostArg) {
return plugin.Error("dnsseed", c.ArgErr())
}
var magic network.Network
switch networkArg {
case "mainnet":
magic = network.Mainnet
case "testnet":
magic = network.Testnet
default:
return plugin.Error("dnsseed", c.Errf("Config error: expected {mainnet, testnet}, got %s", networkArg))
}
address, port, err := net.SplitHostPort(hostArg)
if err != nil {
return plugin.Error("dnsseed", c.Errf("Config error: expected 'host:port', got %s", hostArg))
}
// XXX: If we wanted to register Prometheus metrics, this would be the place.
seeder, err := zcash.NewSeeder(magic)
if err != nil {
return plugin.Error("dnsseed", err)
}
err = seeder.Connect(address, port)
if err != nil {
return plugin.Error("dnsseed", err)
}
// TODO: make initial addr request
// TODO: begin update timer
// Add the Plugin to CoreDNS, so Servers can use it in their plugin chain.
dnsserver.GetConfig(c).AddPlugin(func(next plugin.Handler) plugin.Handler {
return ZcashSeeder{Next: next, seeder: seeder}
})
// All OK, return a nil error.
return nil
}

26
dnsseed/setup_test.go Normal file
View File

@ -0,0 +1,26 @@
package dnsseed
import (
"strings"
"testing"
"github.com/caddyserver/caddy"
)
// TestSetup tests the various things that should be parsed by setup.
func TestSetup(t *testing.T) {
c := caddy.NewTestController("dns", "dnsseed mainnet 127.0.0.1:8233")
if err := setup(c); err != nil {
if strings.Contains(err.Error(), "connection refused") {
// No local peer running
// TODO: mock a local peer, which will be easier with an API rework in the zcash package
t.Skip()
}
t.Fatalf("Expected no errors, but got: %v", err)
}
c = caddy.NewTestController("dns", "dnsseed boop snoot")
if err := setup(c); err == nil {
t.Fatalf("Expected errors, but got: %v", err)
}
}

View File

@ -271,3 +271,9 @@ func (s *Seeder) WaitForAddresses(n int, timeout time.Duration) error {
return ErrAddressTimeout
}
}
// Ready reports if the seeder is ready to provide addresses.
func (s *Seeder) Ready() bool {
// TODO report ready when we have some addresses
return false
}