Revert "Implement notifies for transfer plugin (#3972)" (#3995)

This reverts commit 68f1dd5ddf.

Signed-off-by: Yong Tang <yong.tang.github@outlook.com>
This commit is contained in:
Yong Tang
2020-07-08 09:00:26 -07:00
committed by GitHub
parent 68f1dd5ddf
commit 614d08cba2
42 changed files with 988 additions and 707 deletions

View File

@@ -2,38 +2,34 @@
## Name
*transfer* - perform (outgoing) zone transfers for other plugins.
*transfer* - perform zone transfers for other plugins.
## Description
This plugin answers zone transfers for authoritative plugins that implement `transfer.Transferer`.
This plugin answers zone transfers for authoritative plugins that implement
`transfer.Transferer`. Currently, no internal plugins implement this interface.
*transfer* answers full zone transfer (AXFR) requests and incremental zone transfer (IXFR) requests
Transfer answers full zone transfer (AXFR) requests and incremental zone transfer (IXFR) requests
with AXFR fallback if the zone has changed.
When a plugin wants to notify it's secondaries it will call back into the *transfer* plugin.
The following plugins implement zone transfers using this plugin: *file*, *auto*, *secondary*, and
*kubernetes*. See `transfer.go` for implementation details if you are a plugin author that wants to
use this plugin.
Notifies are not currently supported.
## Syntax
~~~
transfer [ZONE...] {
to ADDRESS...
to HOST...
}
~~~
* **ZONE** The zones *transfer* will answer zone transfer requests for. If left blank, the zones
are inherited from the enclosing server block. To answer zone transfers for a given zone,
there must be another plugin in the same server block that serves the same zone, and implements
`transfer.Transferer`.
* **ZONES** The zones *transfer* will answer zone requests for. If left blank,
the zones are inherited from the enclosing server block. To answer zone
transfers for a given zone, there must be another plugin in the same server
block that serves the same zone, and implements `transfer.Transferer`.
* `to` **ADDRESS...** The hosts *transfer* will transfer to. Use `*` to permit transfers to all
addresses. **ADDRESS** must be denoted in CIDR notation (e.g., 127.0.0.1/32) or just as plain
addresses. `to` may be specified multiple times.
* `to ` **HOST...** The hosts *transfer* will transfer to. Use `*` to permit
transfers to all hosts.
## Examples
See the specific plugins using this plugin for examples on it's usage.
TODO

View File

@@ -1,58 +0,0 @@
package transfer
import (
"fmt"
"github.com/coredns/coredns/plugin/pkg/rcode"
"github.com/miekg/dns"
)
// Notify will send notifies to all configured to hosts IP addresses. If the zone isn't known
// to t an error will be returned. The string zone must be lowercased.
func (t *Transfer) Notify(zone string) error {
if t == nil { // t might be nil, mostly expected in tests, so intercept and to a noop in that case
return nil
}
m := new(dns.Msg)
m.SetNotify(zone)
c := new(dns.Client)
x := longestMatch(t.xfrs, zone)
if x == nil {
return fmt.Errorf("no such zone registred in the transfer plugin: %s", zone)
}
var err1 error
for _, t := range x.to {
if t == "*" {
continue
}
if err := sendNotify(c, m, t); err != nil {
err1 = err
}
}
log.Debugf("Sent notifies for zone %q to %v", zone, x.to)
return err1 // this only captures the last error
}
func sendNotify(c *dns.Client, m *dns.Msg, s string) error {
var err error
code := dns.RcodeServerFailure
for i := 0; i < 3; i++ {
ret, _, err := c.Exchange(m, s)
if err != nil {
continue
}
code = ret.Rcode
if code == dns.RcodeSuccess {
return nil
}
}
if err != nil {
return fmt.Errorf("notify for zone %q was not accepted by %q: %q", m.Question[0].Name, s, err)
}
return fmt.Errorf("notify for zone %q was not accepted by %q: rcode was %q", m.Question[0].Name, s, rcode.ToString(code))
}

View File

@@ -1,58 +0,0 @@
package transfer
import (
"context"
"fmt"
"testing"
"github.com/coredns/coredns/plugin/pkg/dnstest"
"github.com/coredns/coredns/plugin/test"
"github.com/miekg/dns"
)
type (
t1 struct{}
t2 struct{}
)
func (t t1) Transfer(zone string, serial uint32) (<-chan []dns.RR, error) {
const z = "example.org."
if zone != z {
return nil, ErrNotAuthoritative
}
return nil, fmt.Errorf(z)
}
func (t t2) Transfer(zone string, serial uint32) (<-chan []dns.RR, error) {
const z = "sub.example.org."
if zone != z {
return nil, ErrNotAuthoritative
}
return nil, fmt.Errorf(z)
}
func TestZoneSelection(t *testing.T) {
tr := &Transfer{
Transferers: []Transferer{t1{}, t2{}},
xfrs: []*xfr{
{
Zones: []string{"example.org."},
to: []string{"192.0.2.1"}, // RFC 5737 IP, no interface should have this address.
},
{
Zones: []string{"sub.example.org."},
to: []string{"*"},
},
},
}
r := new(dns.Msg)
r.SetAxfr("sub.example.org.")
w := dnstest.NewRecorder(&test.ResponseWriter{})
_, err := tr.ServeDNS(context.TODO(), w, r)
if err == nil {
t.Fatal("Expected error, got nil")
}
if x := err.Error(); x != "sub.example.org." {
t.Errorf("Expected transfer for zone %s, got %s", "sub.example.org", x)
}
}

View File

@@ -3,7 +3,7 @@ package transfer
import (
"github.com/coredns/coredns/core/dnsserver"
"github.com/coredns/coredns/plugin"
"github.com/coredns/coredns/plugin/pkg/parse"
parsepkg "github.com/coredns/coredns/plugin/pkg/parse"
"github.com/coredns/coredns/plugin/pkg/transport"
"github.com/caddyserver/caddy"
@@ -17,7 +17,7 @@ func init() {
}
func setup(c *caddy.Controller) error {
t, err := parseTransfer(c)
t, err := parse(c)
if err != nil {
return plugin.Error("transfer", err)
@@ -44,7 +44,8 @@ func setup(c *caddy.Controller) error {
return nil
}
func parseTransfer(c *caddy.Controller) (*Transfer, error) {
func parse(c *caddy.Controller) (*Transfer, error) {
t := &Transfer{}
for c.Next() {
x := &xfr{}
@@ -82,14 +83,14 @@ func parseTransfer(c *caddy.Controller) (*Transfer, error) {
x.to = append(x.to, host)
continue
}
normalized, err := parse.HostPort(host, transport.Port)
normalized, err := parsepkg.HostPort(host, transport.Port)
if err != nil {
return nil, err
}
x.to = append(x.to, normalized)
}
default:
return nil, plugin.Error("transfer", c.Errf("unknown property %q", c.Val()))
return nil, plugin.Error("transfer", c.Errf("unknown property '%s'", c.Val()))
}
}
if len(x.to) == 0 {

View File

@@ -6,6 +6,12 @@ import (
"github.com/caddyserver/caddy"
)
func newTestControllerWithZones(input string, zones []string) *caddy.Controller {
ctr := caddy.NewTestController("dns", input)
ctr.ServerBlockKeys = append(ctr.ServerBlockKeys, zones...)
return ctr
}
func TestParse(t *testing.T) {
tests := []struct {
input string
@@ -69,10 +75,8 @@ func TestParse(t *testing.T) {
},
}
for i, tc := range tests {
c := caddy.NewTestController("dns", tc.input)
c.ServerBlockKeys = append(c.ServerBlockKeys, tc.zones...)
transfer, err := parseTransfer(c)
c := newTestControllerWithZones(tc.input, tc.zones)
transfer, err := parse(c)
if err == nil && tc.shouldErr {
t.Fatalf("Test %d expected errors, but got no error", i)

View File

@@ -3,6 +3,7 @@ package transfer
import (
"context"
"errors"
"fmt"
"net"
"sync"
@@ -17,9 +18,9 @@ var log = clog.NewWithPlugin("transfer")
// Transfer is a plugin that handles zone transfers.
type Transfer struct {
Transferers []Transferer // List of plugins that implement Transferer
Transferers []Transferer // the list of plugins that implement Transferer
xfrs []*xfr
Next plugin.Handler
Next plugin.Handler // the next plugin in the chain
}
type xfr struct {
@@ -31,53 +32,53 @@ type xfr struct {
type Transferer interface {
// Transfer returns a channel to which it writes responses to the transfer request.
// If the plugin is not authoritative for the zone, it should immediately return the
// transfer.ErrNotAuthoritative error. This is important otherwise the transfer plugin can
// use plugin X while it should transfer the data from plugin Y.
// Transfer.ErrNotAuthoritative error.
//
// If serial is 0, handle as an AXFR request. Transfer should send all records
// in the zone to the channel. The SOA should be written to the channel first, followed
// by all other records, including all NS + glue records. The implemenation is also responsible
// for sending the last SOA record (to signal end of the transfer). This plugin will just grab
// these records and send them back to the requester, there is little validation done.
// by all other records, including all NS + glue records.
//
// If serial is not 0, it will be handled as an IXFR request. If the serial is equal to or greater (newer) than
// the current serial for the zone, send a single SOA record to the channel and then close it.
// If serial is not 0, handle as an IXFR request. If the serial is equal to or greater (newer) than
// the current serial for the zone, send a single SOA record to the channel.
// If the serial is less (older) than the current serial for the zone, perform an AXFR fallback
// by proceeding as if an AXFR was requested (as above).
Transfer(zone string, serial uint32) (<-chan []dns.RR, error)
}
var (
// ErrNotAuthoritative is returned by Transfer() when the plugin is not authoritative for the zone.
// ErrNotAuthoritative is returned by Transfer() when the plugin is not authoritative for the zone
ErrNotAuthoritative = errors.New("not authoritative for zone")
)
// ServeDNS implements the plugin.Handler interface.
func (t *Transfer) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) {
func (t Transfer) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) {
state := request.Request{W: w, Req: r}
if state.QType() != dns.TypeAXFR && state.QType() != dns.TypeIXFR {
return plugin.NextOrFailure(t.Name(), t.Next, ctx, w, r)
}
x := longestMatch(t.xfrs, state.QName())
// Find the first transfer instance for which the queried zone is a subdomain.
var x *xfr
for _, xfr := range t.xfrs {
zone := plugin.Zones(xfr.Zones).Matches(state.Name())
if zone == "" {
continue
}
x = xfr
}
if x == nil {
// Requested zone did not match any transfer instance zones.
// Pass request down chain in case later plugins are capable of handling transfer requests themselves.
return plugin.NextOrFailure(t.Name(), t.Next, ctx, w, r)
}
if !x.allowed(state) {
// write msg here, so logging will pick it up
m := new(dns.Msg)
m.SetRcode(r, dns.RcodeRefused)
w.WriteMsg(m)
return 0, nil
return dns.RcodeRefused, nil
}
// Get serial from request if this is an IXFR.
// Get serial from request if this is an IXFR
var serial uint32
if state.QType() == dns.TypeIXFR {
if len(r.Ns) != 1 {
return dns.RcodeServerFailure, nil
}
soa, ok := r.Ns[0].(*dns.SOA)
if !ok {
return dns.RcodeServerFailure, nil
@@ -85,11 +86,11 @@ func (t *Transfer) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Ms
serial = soa.Serial
}
// Get a receiving channel from the first Transferer plugin that returns one.
var pchan <-chan []dns.RR
var err error
// Get a receiving channel from the first Transferer plugin that returns one
var fromPlugin <-chan []dns.RR
for _, p := range t.Transferers {
pchan, err = p.Transfer(state.QName(), serial)
var err error
fromPlugin, err = p.Transfer(state.QName(), serial)
if err == ErrNotAuthoritative {
// plugin was not authoritative for the zone, try next plugin
continue
@@ -100,7 +101,7 @@ func (t *Transfer) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Ms
break
}
if pchan == nil {
if fromPlugin == nil {
return plugin.NextOrFailure(t.Name(), t.Next, ctx, w, r)
}
@@ -114,51 +115,26 @@ func (t *Transfer) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Ms
wg.Done()
}()
var soa *dns.SOA
rrs := []dns.RR{}
l := 0
var soa *dns.SOA
for records := range pchan {
if x, ok := records[0].(*dns.SOA); ok && soa == nil {
soa = x
receive:
for records := range fromPlugin {
for _, record := range records {
if soa == nil {
if soa = record.(*dns.SOA); soa == nil {
break receive
}
serial = soa.Serial
}
rrs = append(rrs, record)
if len(rrs) > 500 {
ch <- &dns.Envelope{RR: rrs}
l += len(rrs)
rrs = []dns.RR{}
}
}
rrs = append(rrs, records...)
if len(rrs) > 500 {
ch <- &dns.Envelope{RR: rrs}
l += len(rrs)
rrs = []dns.RR{}
}
}
// if we are here and we only hold 1 soa (len(rrs) == 1) and soa != nil, and IXFR fallback should
// be performed. We haven't send anything on ch yet, so that can be closed (and waited for), and we only
// need to return the SOA back to the client and return.
if len(rrs) == 1 && soa != nil { // soa should never be nil...
close(ch)
wg.Wait()
m := new(dns.Msg)
m.SetReply(r)
m.Answer = []dns.RR{soa}
w.WriteMsg(m)
log.Infof("Outgoing incremental transfer for up to date zone %q to %s for %d SOA serial", state.QName(), state.IP(), serial)
return 0, nil
}
// if we are here and we only hold 1 soa (len(rrs) == 1) and soa != nil, and IXFR fallback should
// be performed. We haven't send anything on ch yet, so that can be closed (and waited for), and we only
// need to return the SOA back to the client and return.
if len(rrs) == 1 && soa != nil { // soa should never be nil...
close(ch)
wg.Wait()
m := new(dns.Msg)
m.SetReply(r)
m.Answer = []dns.RR{soa}
w.WriteMsg(m)
log.Infof("Outgoing noop, incremental transfer for up to date zone %q to %s for %d SOA serial", state.QName(), state.IP(), soa.Serial)
return 0, nil
}
if len(rrs) > 0 {
@@ -167,15 +143,20 @@ func (t *Transfer) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Ms
rrs = []dns.RR{}
}
if soa != nil {
ch <- &dns.Envelope{RR: []dns.RR{soa}} // closing SOA.
l++
}
close(ch) // Even though we close the channel here, we still have
wg.Wait() // to wait before we can return and close the connection.
logserial := uint32(0)
if soa != nil {
logserial = soa.Serial
if soa == nil {
return dns.RcodeServerFailure, fmt.Errorf("first record in zone %s is not SOA", state.QName())
}
log.Infof("Outgoing transfer of %d records of zone %q to %s for %d SOA serial", l, state.QName(), state.IP(), logserial)
return 0, nil
log.Infof("Outgoing transfer of %d records of zone %s to %s with %d SOA serial", l, state.QName(), state.IP(), serial)
return dns.RcodeSuccess, nil
}
func (x xfr) allowed(state request.Request) bool {
@@ -187,30 +168,14 @@ func (x xfr) allowed(state request.Request) bool {
if err != nil {
return false
}
// If remote IP matches we accept. TODO(): make this works with ranges
if to == state.IP() {
// If remote IP matches we accept.
remote := state.IP()
if to == remote {
return true
}
}
return false
}
// Find the first transfer instance for which the queried zone is the longest match. When nothing
// is found nil is returned.
func longestMatch(xfrs []*xfr, name string) *xfr {
// TODO(xxx): optimize and make it a map (or maps)
var x *xfr
zone := "" // longest zone match wins
for _, xfr := range xfrs {
if z := plugin.Zones(xfr.Zones).Matches(name); z != "" {
if z > zone {
zone = z
x = xfr
}
}
}
return x
}
// Name implements the Handler interface.
func (Transfer) Name() string { return "transfer" }

View File

@@ -12,18 +12,18 @@ import (
"github.com/miekg/dns"
)
// transfererPlugin implements transfer.Transferer and plugin.Handler.
// transfererPlugin implements transfer.Transferer and plugin.Handler
type transfererPlugin struct {
Zone string
Serial uint32
Next plugin.Handler
}
// Name implements plugin.Handler.
func (*transfererPlugin) Name() string { return "transfererplugin" }
// Name implements plugin.Handler
func (transfererPlugin) Name() string { return "transfererplugin" }
// ServeDNS implements plugin.Handler.
func (p *transfererPlugin) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) {
// ServeDNS implements plugin.Handler
func (p transfererPlugin) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) {
if r.Question[0].Name != p.Zone {
return p.Next.ServeDNS(ctx, w, r)
}
@@ -31,12 +31,12 @@ func (p *transfererPlugin) ServeDNS(ctx context.Context, w dns.ResponseWriter, r
}
// Transfer implements transfer.Transferer - it returns a static AXFR response, or
// if serial is current, an abbreviated IXFR response.
func (p *transfererPlugin) Transfer(zone string, serial uint32) (<-chan []dns.RR, error) {
// if serial is current, an abbreviated IXFR response
func (p transfererPlugin) Transfer(zone string, serial uint32) (<-chan []dns.RR, error) {
if zone != p.Zone {
return nil, ErrNotAuthoritative
}
ch := make(chan []dns.RR, 3) // sending 3 bits and don't want to block, nor do a waitgroup
ch := make(chan []dns.RR, 2)
defer close(ch)
ch <- []dns.RR{test.SOA(fmt.Sprintf("%s 100 IN SOA ns.dns.%s hostmaster.%s %d 7200 1800 86400 100", p.Zone, p.Zone, p.Zone, p.Serial))}
if serial >= p.Serial {
@@ -46,31 +46,30 @@ func (p *transfererPlugin) Transfer(zone string, serial uint32) (<-chan []dns.RR
test.NS(fmt.Sprintf("%s 100 IN NS ns.dns.%s", p.Zone, p.Zone)),
test.A(fmt.Sprintf("ns.dns.%s 100 IN A 1.2.3.4", p.Zone)),
}
ch <- []dns.RR{test.SOA(fmt.Sprintf("%s 100 IN SOA ns.dns.%s hostmaster.%s %d 7200 1800 86400 100", p.Zone, p.Zone, p.Zone, p.Serial))}
return ch, nil
}
type terminatingPlugin struct{}
// Name implements plugin.Handler.
func (*terminatingPlugin) Name() string { return "testplugin" }
// Name implements plugin.Handler
func (terminatingPlugin) Name() string { return "testplugin" }
// ServeDNS implements plugin.Handler that returns NXDOMAIN for all requests.
func (*terminatingPlugin) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) {
// ServeDNS implements plugin.Handler that returns NXDOMAIN for all requests
func (terminatingPlugin) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) {
m := new(dns.Msg)
m.SetRcode(r, dns.RcodeNameError)
w.WriteMsg(m)
return dns.RcodeNameError, nil
}
func newTestTransfer() *Transfer {
func newTestTransfer() Transfer {
nextPlugin1 := transfererPlugin{Zone: "example.com.", Serial: 12345}
nextPlugin2 := transfererPlugin{Zone: "example.org.", Serial: 12345}
nextPlugin2.Next = &terminatingPlugin{}
nextPlugin1.Next = &nextPlugin2
nextPlugin2.Next = terminatingPlugin{}
nextPlugin1.Next = nextPlugin2
transfer := &Transfer{
Transferers: []Transferer{&nextPlugin1, &nextPlugin2},
transfer := Transfer{
Transferers: []Transferer{nextPlugin1, nextPlugin2},
xfrs: []*xfr{
{
Zones: []string{"example.org."},
@@ -81,21 +80,22 @@ func newTestTransfer() *Transfer {
to: []string{"*"},
},
},
Next: &nextPlugin1,
Next: nextPlugin1,
}
return transfer
}
func TestTransferNonZone(t *testing.T) {
transfer := newTestTransfer()
ctx := context.TODO()
for _, tc := range []string{"sub.example.org.", "example.test."} {
w := dnstest.NewRecorder(&test.ResponseWriter{})
m := &dns.Msg{}
m.SetAxfr(tc)
dnsmsg := &dns.Msg{}
dnsmsg.SetAxfr(tc)
_, err := transfer.ServeDNS(ctx, w, m)
_, err := transfer.ServeDNS(ctx, w, dnsmsg)
if err != nil {
t.Error(err)
}
@@ -111,14 +111,15 @@ func TestTransferNonZone(t *testing.T) {
}
func TestTransferNotAXFRorIXFR(t *testing.T) {
transfer := newTestTransfer()
ctx := context.TODO()
w := dnstest.NewRecorder(&test.ResponseWriter{})
m := &dns.Msg{}
m.SetQuestion("test.domain.", dns.TypeA)
dnsmsg := &dns.Msg{}
dnsmsg.SetQuestion("test.domain.", dns.TypeA)
_, err := transfer.ServeDNS(ctx, w, m)
_, err := transfer.ServeDNS(ctx, w, dnsmsg)
if err != nil {
t.Error(err)
}
@@ -133,14 +134,15 @@ func TestTransferNotAXFRorIXFR(t *testing.T) {
}
func TestTransferAXFRExampleOrg(t *testing.T) {
transfer := newTestTransfer()
ctx := context.TODO()
w := dnstest.NewMultiRecorder(&test.ResponseWriter{})
m := &dns.Msg{}
m.SetAxfr(transfer.xfrs[0].Zones[0])
dnsmsg := &dns.Msg{}
dnsmsg.SetAxfr(transfer.xfrs[0].Zones[0])
_, err := transfer.ServeDNS(ctx, w, m)
_, err := transfer.ServeDNS(ctx, w, dnsmsg)
if err != nil {
t.Error(err)
}
@@ -149,14 +151,39 @@ func TestTransferAXFRExampleOrg(t *testing.T) {
}
func TestTransferAXFRExampleCom(t *testing.T) {
transfer := newTestTransfer()
ctx := context.TODO()
w := dnstest.NewMultiRecorder(&test.ResponseWriter{})
m := &dns.Msg{}
m.SetAxfr(transfer.xfrs[1].Zones[0])
dnsmsg := &dns.Msg{}
dnsmsg.SetAxfr(transfer.xfrs[1].Zones[0])
_, err := transfer.ServeDNS(ctx, w, m)
_, err := transfer.ServeDNS(ctx, w, dnsmsg)
if err != nil {
t.Error(err)
}
validateAXFRResponse(t, w)
}
func TestTransferIXFRFallback(t *testing.T) {
transfer := newTestTransfer()
testPlugin := transfer.Transferers[0].(transfererPlugin)
ctx := context.TODO()
w := dnstest.NewMultiRecorder(&test.ResponseWriter{})
dnsmsg := &dns.Msg{}
dnsmsg.SetIxfr(
transfer.xfrs[0].Zones[0],
testPlugin.Serial-1,
"ns.dns."+testPlugin.Zone,
"hostmaster.dns."+testPlugin.Zone,
)
_, err := transfer.ServeDNS(ctx, w, dnsmsg)
if err != nil {
t.Error(err)
}
@@ -165,21 +192,28 @@ func TestTransferAXFRExampleCom(t *testing.T) {
}
func TestTransferIXFRCurrent(t *testing.T) {
transfer := newTestTransfer()
testPlugin := transfer.Transferers[0].(*transfererPlugin)
testPlugin := transfer.Transferers[0].(transfererPlugin)
ctx := context.TODO()
w := dnstest.NewMultiRecorder(&test.ResponseWriter{})
m := &dns.Msg{}
m.SetIxfr(transfer.xfrs[0].Zones[0], testPlugin.Serial, "ns.dns."+testPlugin.Zone, "hostmaster.dns."+testPlugin.Zone)
dnsmsg := &dns.Msg{}
dnsmsg.SetIxfr(
transfer.xfrs[0].Zones[0],
testPlugin.Serial,
"ns.dns."+testPlugin.Zone,
"hostmaster.dns."+testPlugin.Zone,
)
_, err := transfer.ServeDNS(ctx, w, m)
_, err := transfer.ServeDNS(ctx, w, dnsmsg)
if err != nil {
t.Error(err)
}
if len(w.Msgs) == 0 {
t.Logf("%+v\n", w)
t.Fatal("Did not get back a zone response")
}
@@ -194,31 +228,9 @@ func TestTransferIXFRCurrent(t *testing.T) {
}
}
func TestTransferIXFRFallback(t *testing.T) {
transfer := newTestTransfer()
testPlugin := transfer.Transferers[0].(*transfererPlugin)
ctx := context.TODO()
w := dnstest.NewMultiRecorder(&test.ResponseWriter{})
m := &dns.Msg{}
m.SetIxfr(
transfer.xfrs[0].Zones[0],
testPlugin.Serial-1,
"ns.dns."+testPlugin.Zone,
"hostmaster.dns."+testPlugin.Zone,
)
_, err := transfer.ServeDNS(ctx, w, m)
if err != nil {
t.Error(err)
}
validateAXFRResponse(t, w)
}
func validateAXFRResponse(t *testing.T, w *dnstest.MultiRecorder) {
if len(w.Msgs) == 0 {
t.Logf("%+v\n", w)
t.Fatal("Did not get back a zone response")
}
@@ -251,28 +263,29 @@ func TestTransferNotAllowed(t *testing.T) {
nextPlugin := transfererPlugin{Zone: "example.org.", Serial: 12345}
transfer := Transfer{
Transferers: []Transferer{&nextPlugin},
Transferers: []Transferer{nextPlugin},
xfrs: []*xfr{
{
Zones: []string{"example.org."},
to: []string{"1.2.3.4"},
},
},
Next: &nextPlugin,
Next: nextPlugin,
}
ctx := context.TODO()
w := dnstest.NewRecorder(&test.ResponseWriter{})
m := &dns.Msg{}
m.SetAxfr(transfer.xfrs[0].Zones[0])
w := dnstest.NewMultiRecorder(&test.ResponseWriter{})
dnsmsg := &dns.Msg{}
dnsmsg.SetAxfr(transfer.xfrs[0].Zones[0])
_, err := transfer.ServeDNS(ctx, w, m)
rcode, err := transfer.ServeDNS(ctx, w, dnsmsg)
if err != nil {
t.Error(err)
}
if w.Msg.Rcode != dns.RcodeRefused {
t.Errorf("Expected REFUSED response code, got %s", dns.RcodeToString[w.Msg.Rcode])
if rcode != dns.RcodeRefused {
t.Errorf("Expected REFUSED response code, got %s", dns.RcodeToString[rcode])
}
}