coredns/plugin/erratic/erratic.go
Miek Gieben d998aa6c25
plugin/erratic: add axfr support (#1977)
* plugin/erratic: add axfr support

Add support for axfr. This to fix and test long standing axfr issues
that are hard to test if we don't support it directly in coredns.

The most intriguing feature is withholding the last SOA from a response
so the client needs to wait; drop (no reply) and delay is also
supported. All TTLs are set to zero.

Add simple tests that checks if first record is a SOA.

Signed-off-by: Miek Gieben <miek@miek.nl>

* more test coverage

Signed-off-by: Miek Gieben <miek@miek.nl>
2018-07-20 10:25:54 +01:00

106 lines
2 KiB
Go

// Package erratic implements a plugin that returns erratic answers (delayed, dropped).
package erratic
import (
"context"
"sync/atomic"
"time"
"github.com/coredns/coredns/request"
"github.com/miekg/dns"
)
// Erratic is a plugin that returns erratic responses to each client.
type Erratic struct {
drop uint64
delay uint64
duration time.Duration
truncate uint64
q uint64 // counter of queries
}
// ServeDNS implements the plugin.Handler interface.
func (e *Erratic) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) {
state := request.Request{W: w, Req: r}
drop := false
delay := false
trunc := false
queryNr := atomic.LoadUint64(&e.q)
atomic.AddUint64(&e.q, 1)
if e.drop > 0 && queryNr%e.drop == 0 {
drop = true
}
if e.delay > 0 && queryNr%e.delay == 0 {
delay = true
}
if e.truncate > 0 && queryNr&e.truncate == 0 {
trunc = true
}
m := new(dns.Msg)
m.SetReply(r)
m.Authoritative = true
if trunc {
m.Truncated = true
}
// small dance to copy rrA or rrAAAA into a non-pointer var that allows us to overwrite the ownername
// in a non-racy way.
switch state.QType() {
case dns.TypeA:
rr := *(rrA.(*dns.A))
rr.Header().Name = state.QName()
m.Answer = append(m.Answer, &rr)
case dns.TypeAAAA:
rr := *(rrAAAA.(*dns.AAAA))
rr.Header().Name = state.QName()
m.Answer = append(m.Answer, &rr)
case dns.TypeAXFR:
if drop {
return 0, nil
}
if delay {
time.Sleep(e.duration)
}
xfr(state, trunc)
return 0, nil
default:
if drop {
return 0, nil
}
if delay {
time.Sleep(e.duration)
}
// coredns will return error.
return dns.RcodeServerFailure, nil
}
if drop {
return 0, nil
}
if delay {
time.Sleep(e.duration)
}
state.SizeAndDo(m)
w.WriteMsg(m)
return 0, nil
}
// Name implements the Handler interface.
func (e *Erratic) Name() string { return "erratic" }
var (
rrA, _ = dns.NewRR(". IN 0 A 192.0.2.53")
rrAAAA, _ = dns.NewRR(". IN 0 AAAA 2001:DB8::53")
)