145 lines
3 KiB
Go
145 lines
3 KiB
Go
package caddydns01
|
|
|
|
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()
|
|
_, err := ctx.AppIfConfigured("dns01")
|
|
if err != nil {
|
|
p.logger.Warn("DNS app not yet configured")
|
|
}
|
|
app, err := ctx.App("dns01")
|
|
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)
|
|
)
|