feat: implement (full) DNS server App, provider as ACMEDNSProvider
This is a rewrite of almost everything. The provided modules no longer rely on undocumented/deprecated behavior. It's no longer possible to have multiple DNS "servers" on different sockets, but the new version allows serving arbitrary records. Records can be defined in the config or Caddyfile. The provider communicates with the Server via a channel.
This commit is contained in:
parent
a6d39a06aa
commit
15a4840b03
5 changed files with 639 additions and 215 deletions
144
provider.go
Normal file
144
provider.go
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
package stub
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/caddyserver/caddy/v2"
|
||||
"github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
|
||||
"github.com/libdns/libdns"
|
||||
"github.com/miekg/dns"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
type Provider struct {
|
||||
app_channel chan request
|
||||
logger *zap.Logger // set in Provision()
|
||||
}
|
||||
|
||||
// CaddyModule returns the Caddy module information.
|
||||
func (Provider) CaddyModule() caddy.ModuleInfo {
|
||||
return caddy.ModuleInfo{
|
||||
ID: "dns.providers.internal",
|
||||
New: func() caddy.Module { return &Provider{} },
|
||||
}
|
||||
}
|
||||
|
||||
// Provision sets up the module. Implements caddy.Provisioner.
|
||||
func (p *Provider) Provision(ctx caddy.Context) error {
|
||||
p.logger = ctx.Logger()
|
||||
if !ctx.AppIsConfigured("dns") {
|
||||
p.logger.Warn("DNS app not yet configured")
|
||||
}
|
||||
app, err := ctx.App("dns")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if app == nil {
|
||||
return fmt.Errorf("failed to load DNS app")
|
||||
}
|
||||
dns_app, ok := app.(*App)
|
||||
if !ok {
|
||||
return fmt.Errorf("received invalid app")
|
||||
}
|
||||
p.app_channel = dns_app.requests
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalCaddyfile sets up the DNS provider from Caddyfile tokens. Syntax:
|
||||
//
|
||||
// dns internal
|
||||
func (p *Provider) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
|
||||
for d.Next() {
|
||||
if d.NextArg() {
|
||||
return d.ArgErr()
|
||||
}
|
||||
for nesting := d.Nesting(); d.NextBlock(nesting); {
|
||||
switch d.Val() {
|
||||
default:
|
||||
return d.Errf("unrecognized subdirective '%s'", d.Val())
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Provider) convert(zone string, set []libdns.Record) ([]dns.RR, error) {
|
||||
converted := []dns.RR{}
|
||||
|
||||
for _, r := range set {
|
||||
rr, err := record_to_rr(zone, r)
|
||||
if err != nil {
|
||||
p.logger.Error(
|
||||
"failed to convert",
|
||||
zap.Error(err),
|
||||
zap.String("zone", zone),
|
||||
zap.Object("record", log_libdns_record(&r)),
|
||||
)
|
||||
return nil, err
|
||||
}
|
||||
converted = append(converted, rr)
|
||||
}
|
||||
return converted, nil
|
||||
}
|
||||
|
||||
func (p *Provider) make_request(
|
||||
ctx context.Context,
|
||||
zone string,
|
||||
append bool,
|
||||
recs []libdns.Record,
|
||||
) ([]libdns.Record, error) {
|
||||
resp := make(chan error)
|
||||
|
||||
records, err := p.convert(zone, recs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req := request{
|
||||
append: append,
|
||||
zone: zone,
|
||||
records: records,
|
||||
responder: resp,
|
||||
}
|
||||
|
||||
p.app_channel <- req
|
||||
p.logger.Debug("sent request", zap.Object("request", req))
|
||||
|
||||
select {
|
||||
case err = <-resp:
|
||||
if err != nil {
|
||||
p.logger.Debug("request failed", zap.Error(err))
|
||||
return nil, err
|
||||
} else {
|
||||
p.logger.Debug("request succeeded")
|
||||
return recs, nil
|
||||
}
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Provider) AppendRecords(
|
||||
ctx context.Context,
|
||||
zone string,
|
||||
recs []libdns.Record,
|
||||
) ([]libdns.Record, error) {
|
||||
return p.make_request(ctx, zone, true, recs)
|
||||
}
|
||||
|
||||
func (p *Provider) DeleteRecords(
|
||||
ctx context.Context,
|
||||
zone string,
|
||||
recs []libdns.Record,
|
||||
) ([]libdns.Record, error) {
|
||||
return p.make_request(ctx, zone, false, recs)
|
||||
}
|
||||
|
||||
// Interface guards
|
||||
var (
|
||||
_ caddy.Provisioner = (*Provider)(nil)
|
||||
_ caddyfile.Unmarshaler = (*Provider)(nil)
|
||||
_ libdns.RecordAppender = (*Provider)(nil)
|
||||
_ libdns.RecordDeleter = (*Provider)(nil)
|
||||
)
|
||||
Loading…
Add table
Add a link
Reference in a new issue