Default to scrubbing replies in the server (#2012)
Every plugin needs to deal with EDNS0 and should call Scrub to make a message fit the client's buffer. Move this functionality into the server and wrapping the ResponseWriter into a ScrubWriter that handles these bits for us. Result: Less code and faster, because multiple chained plugins could all be calling scrub and SizeAndDo - now there is just one place. Most tests in file/* and dnssec/* needed adjusting because in those unit tests you don't see OPT RRs anymore. The DNSSEC signer was also looking at the returned OPT RR to see if it needed to sign - as those are now added by the server (and thus later), this needed to change slightly. Scrub itself still exist (for backward compat reasons), but has been made a noop. Scrub has been renamed to scrub as it should not be used by external plugins. Fixes: #2010 Signed-off-by: Miek Gieben <miek@miek.nl>
This commit is contained in:
parent
eb51e8bac9
commit
ba1efee4f1
27 changed files with 65 additions and 156 deletions
|
@ -237,6 +237,9 @@ func (s *Server) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg)
|
|||
|
||||
var dshandler *Config
|
||||
|
||||
// Wrap the response writer in a ScrubWriter so we automatically make the reply fit in the client's buffer.
|
||||
w = request.NewScrubWriter(r, w)
|
||||
|
||||
for {
|
||||
l := len(q[off:])
|
||||
for i := 0; i < l; i++ {
|
||||
|
|
|
@ -84,8 +84,6 @@ func (a Auto) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (i
|
|||
return dns.RcodeServerFailure, nil
|
||||
}
|
||||
|
||||
state.SizeAndDo(m)
|
||||
m, _ = state.Scrub(m)
|
||||
w.WriteMsg(m)
|
||||
return dns.RcodeSuccess, nil
|
||||
}
|
||||
|
|
2
plugin/cache/handler.go
vendored
2
plugin/cache/handler.go
vendored
|
@ -31,8 +31,6 @@ func (c *Cache) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg)
|
|||
if i != nil && found {
|
||||
resp := i.toMsg(r, now)
|
||||
|
||||
state.SizeAndDo(resp)
|
||||
resp, _ = state.Scrub(resp)
|
||||
w.WriteMsg(resp)
|
||||
|
||||
if c.prefetch > 0 {
|
||||
|
|
|
@ -46,21 +46,6 @@ func (d Dnssec) Sign(state request.Request, now time.Time, server string) *dns.M
|
|||
|
||||
mt, _ := response.Typify(req, time.Now().UTC()) // TODO(miek): need opt record here?
|
||||
if mt == response.Delegation {
|
||||
// This reverts 11203e44. Reverting with git revert leads to conflicts in dnskey.go, and I'm
|
||||
// not sure yet if we just should fiddle with inserting DSs or not.
|
||||
// Easy way to, see #1211 for discussion.
|
||||
/*
|
||||
ttl := req.Ns[0].Header().Ttl
|
||||
|
||||
ds := []dns.RR{}
|
||||
for i := range d.keys {
|
||||
ds = append(ds, d.keys[i].D)
|
||||
}
|
||||
if sigs, err := d.sign(ds, zone, ttl, incep, expir); err == nil {
|
||||
req.Ns = append(req.Ns, ds...)
|
||||
req.Ns = append(req.Ns, sigs...)
|
||||
}
|
||||
*/
|
||||
return req
|
||||
}
|
||||
|
||||
|
@ -98,7 +83,7 @@ func (d Dnssec) Sign(state request.Request, now time.Time, server string) *dns.M
|
|||
for _, r := range rrSets(req.Extra) {
|
||||
ttl := r[0].Header().Ttl
|
||||
if sigs, err := d.sign(r, state.Zone, ttl, incep, expir, server); err == nil {
|
||||
req.Extra = append(sigs, req.Extra...) // prepend to leave OPT alone
|
||||
req.Extra = append(req.Extra, sigs...)
|
||||
}
|
||||
}
|
||||
return req
|
||||
|
@ -125,9 +110,7 @@ func (d Dnssec) sign(rrs []dns.RR, signerName string, ttl, incep, expir uint32,
|
|||
return sigs.([]dns.RR), err
|
||||
}
|
||||
|
||||
func (d Dnssec) set(key uint32, sigs []dns.RR) {
|
||||
d.cache.Add(key, sigs)
|
||||
}
|
||||
func (d Dnssec) set(key uint32, sigs []dns.RR) { d.cache.Add(key, sigs) }
|
||||
|
||||
func (d Dnssec) get(key uint32, server string) ([]dns.RR, bool) {
|
||||
if s, ok := d.cache.Get(key); ok {
|
||||
|
|
|
@ -41,8 +41,12 @@ func (d Dnssec) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg)
|
|||
}
|
||||
}
|
||||
|
||||
drr := &ResponseWriter{w, d, server}
|
||||
return plugin.NextOrFailure(d.Name(), d.Next, ctx, drr, r)
|
||||
if do {
|
||||
drr := &ResponseWriter{w, d, server}
|
||||
return plugin.NextOrFailure(d.Name(), d.Next, ctx, drr, r)
|
||||
}
|
||||
|
||||
return plugin.NextOrFailure(d.Name(), d.Next, ctx, w, r)
|
||||
}
|
||||
|
||||
var (
|
||||
|
|
|
@ -56,7 +56,6 @@ var dnsTestCases = []test.Case{
|
|||
test.NS("miek.nl. 1800 IN NS linode.atoom.net."),
|
||||
test.RRSIG("miek.nl. 1800 IN RRSIG NS 13 2 3600 20161217114912 20161209084912 18512 miek.nl. ad9gA8VWgF1H8ze9/0Rk2Q=="),
|
||||
},
|
||||
Extra: []dns.RR{test.OPT(4096, true)},
|
||||
},
|
||||
{
|
||||
Qname: "www.miek.nl.", Qtype: dns.TypeAAAA, Do: true,
|
||||
|
@ -70,7 +69,6 @@ var dnsTestCases = []test.Case{
|
|||
test.NS("miek.nl. 1800 IN NS linode.atoom.net."),
|
||||
test.RRSIG("miek.nl. 1800 IN RRSIG NS 13 2 3600 20161217114912 20161209084912 18512 miek.nl. ad9gA8VWgF1H8ze9/0Rk2Q=="),
|
||||
},
|
||||
Extra: []dns.RR{test.OPT(4096, true)},
|
||||
},
|
||||
{
|
||||
Qname: "wwwww.miek.nl.", Qtype: dns.TypeAAAA, Do: true,
|
||||
|
@ -80,7 +78,6 @@ var dnsTestCases = []test.Case{
|
|||
test.NSEC("wwwww.miek.nl. 1800 IN NSEC \\000.wwwww.miek.nl. A HINFO TXT LOC SRV CERT SSHFP RRSIG NSEC TLSA HIP OPENPGPKEY SPF"),
|
||||
test.RRSIG("wwwww.miek.nl. 1800 IN RRSIG NSEC 13 3 3600 20171220135446 20171212105446 18512 miek.nl. cVUQWs8xw=="),
|
||||
},
|
||||
Extra: []dns.RR{test.OPT(4096, true)},
|
||||
},
|
||||
{
|
||||
Qname: "miek.nl.", Qtype: dns.TypeHINFO, Do: true,
|
||||
|
@ -90,12 +87,10 @@ var dnsTestCases = []test.Case{
|
|||
test.RRSIG("miek.nl. 1800 IN RRSIG SOA 13 2 3600 20171220141741 20171212111741 18512 miek.nl. 8bLTReqmuQtw=="),
|
||||
test.SOA("miek.nl. 1800 IN SOA linode.atoom.net. miek.miek.nl. 1282630057 14400 3600 604800 14400"),
|
||||
},
|
||||
Extra: []dns.RR{test.OPT(4096, true)},
|
||||
},
|
||||
{
|
||||
Qname: "www.example.org.", Qtype: dns.TypeAAAA, Do: true,
|
||||
Rcode: dns.RcodeServerFailure,
|
||||
// Extra: []dns.RR{test.OPT(4096, true)}, // test.ErrorHandler is a simple handler that does not do EDNS on ServerFailure
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -110,20 +105,18 @@ func TestLookupZone(t *testing.T) {
|
|||
defer rm2()
|
||||
c := cache.New(defaultCap)
|
||||
dh := New([]string{"miek.nl."}, []*DNSKEY{dnskey}, fm, c)
|
||||
ctx := context.TODO()
|
||||
|
||||
for _, tc := range dnsTestCases {
|
||||
m := tc.Msg()
|
||||
|
||||
rec := dnstest.NewRecorder(&test.ResponseWriter{})
|
||||
_, err := dh.ServeDNS(ctx, rec, m)
|
||||
_, err := dh.ServeDNS(context.TODO(), rec, m)
|
||||
if err != nil {
|
||||
t.Errorf("Expected no error, got %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
resp := rec.Msg
|
||||
test.SortAndCheck(t, resp, tc)
|
||||
test.SortAndCheck(t, rec.Msg, tc)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -133,13 +126,12 @@ func TestLookupDNSKEY(t *testing.T) {
|
|||
defer rm2()
|
||||
c := cache.New(defaultCap)
|
||||
dh := New([]string{"miek.nl."}, []*DNSKEY{dnskey}, test.ErrorHandler(), c)
|
||||
ctx := context.TODO()
|
||||
|
||||
for _, tc := range dnssecTestCases {
|
||||
m := tc.Msg()
|
||||
|
||||
rec := dnstest.NewRecorder(&test.ResponseWriter{})
|
||||
_, err := dh.ServeDNS(ctx, rec, m)
|
||||
_, err := dh.ServeDNS(context.TODO(), rec, m)
|
||||
if err != nil {
|
||||
t.Errorf("Expected no error, got %v\n", err)
|
||||
return
|
||||
|
|
|
@ -28,12 +28,9 @@ func (d *ResponseWriter) WriteMsg(res *dns.Msg) error {
|
|||
}
|
||||
state.Zone = zone
|
||||
|
||||
if state.Do() {
|
||||
res = d.d.Sign(state, time.Now().UTC(), d.server)
|
||||
|
||||
cacheSize.WithLabelValues(d.server, "signature").Set(float64(d.d.cache.Len()))
|
||||
}
|
||||
state.SizeAndDo(res)
|
||||
res = d.d.Sign(state, time.Now().UTC(), d.server)
|
||||
cacheSize.WithLabelValues(d.server, "signature").Set(float64(d.d.cache.Len()))
|
||||
// No need for EDNS0 trickery, as that is handled by the server.
|
||||
|
||||
return d.ResponseWriter.WriteMsg(res)
|
||||
}
|
||||
|
@ -44,6 +41,3 @@ func (d *ResponseWriter) Write(buf []byte) (int, error) {
|
|||
n, err := d.ResponseWriter.Write(buf)
|
||||
return n, err
|
||||
}
|
||||
|
||||
// Hijack implements the dns.ResponseWriter interface.
|
||||
func (d *ResponseWriter) Hijack() { d.ResponseWriter.Hijack() }
|
||||
|
|
|
@ -86,8 +86,6 @@ func (e *Etcd) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (
|
|||
m.Answer = append(m.Answer, records...)
|
||||
m.Extra = append(m.Extra, extra...)
|
||||
|
||||
state.SizeAndDo(m)
|
||||
m, _ = state.Scrub(m)
|
||||
w.WriteMsg(m)
|
||||
return dns.RcodeSuccess, nil
|
||||
}
|
||||
|
|
|
@ -33,8 +33,6 @@ func (s Stub) ServeDNS(ctx context.Context, w dns.ResponseWriter, req *dns.Msg)
|
|||
return dns.RcodeServerFailure, e
|
||||
}
|
||||
m.RecursionAvailable = true
|
||||
state.SizeAndDo(m)
|
||||
m, _ = state.Scrub(m)
|
||||
w.WriteMsg(m)
|
||||
return dns.RcodeSuccess, nil
|
||||
}
|
||||
|
|
|
@ -83,6 +83,5 @@ var dnsTestCasesStub = []test.Case{
|
|||
{
|
||||
Qname: "example.net.", Qtype: dns.TypeA,
|
||||
Answer: []dns.RR{test.A("example.net. 86400 IN A 93.184.216.34")},
|
||||
Extra: []dns.RR{test.OPT(4096, false)}, // This will have an EDNS0 section, because *we* added our local stub forward to detect loops.
|
||||
},
|
||||
}
|
||||
|
|
|
@ -85,8 +85,6 @@ func (f *Federation) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.
|
|||
a.Header().Name = qname
|
||||
}
|
||||
|
||||
state.SizeAndDo(m)
|
||||
m, _ = state.Scrub(m)
|
||||
w.WriteMsg(m)
|
||||
|
||||
return dns.RcodeSuccess, nil
|
||||
|
@ -107,10 +105,7 @@ func (f *Federation) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.
|
|||
|
||||
m.Answer = []dns.RR{service.NewCNAME(state.QName(), service.Host)}
|
||||
|
||||
state.SizeAndDo(m)
|
||||
m, _ = state.Scrub(m)
|
||||
w.WriteMsg(m)
|
||||
|
||||
return dns.RcodeSuccess, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -73,8 +73,7 @@ var delegationTestCases = []test.Case{
|
|||
|
||||
var secureDelegationTestCases = []test.Case{
|
||||
{
|
||||
Qname: "a.delegated.example.org.", Qtype: dns.TypeTXT,
|
||||
Do: true,
|
||||
Qname: "a.delegated.example.org.", Qtype: dns.TypeTXT, Do: true,
|
||||
Ns: []dns.RR{
|
||||
test.DS("delegated.example.org. 1800 IN DS 10056 5 1 EE72CABD1927759CDDA92A10DBF431504B9E1F13"),
|
||||
test.DS("delegated.example.org. 1800 IN DS 10056 5 2 E4B05F87725FA86D9A64F1E53C3D0E6250946599DFE639C45955B0ED416CDDFA"),
|
||||
|
@ -83,14 +82,12 @@ var secureDelegationTestCases = []test.Case{
|
|||
test.RRSIG("delegated.example.org. 1800 IN RRSIG DS 13 3 1800 20161129153240 20161030153240 49035 example.org. rlNNzcUmtbjLSl02ZzQGUbWX75yCUx0Mug1jHtKVqRq1hpPE2S3863tIWSlz+W9wz4o19OI4jbznKKqk+DGKog=="),
|
||||
},
|
||||
Extra: []dns.RR{
|
||||
test.OPT(4096, true),
|
||||
test.A("a.delegated.example.org. 1800 IN A 139.162.196.78"),
|
||||
test.AAAA("a.delegated.example.org. 1800 IN AAAA 2a01:7e00::f03c:91ff:fef1:6735"),
|
||||
},
|
||||
},
|
||||
{
|
||||
Qname: "delegated.example.org.", Qtype: dns.TypeNS,
|
||||
Do: true,
|
||||
Qname: "delegated.example.org.", Qtype: dns.TypeNS, Do: true,
|
||||
Ns: []dns.RR{
|
||||
test.DS("delegated.example.org. 1800 IN DS 10056 5 1 EE72CABD1927759CDDA92A10DBF431504B9E1F13"),
|
||||
test.DS("delegated.example.org. 1800 IN DS 10056 5 2 E4B05F87725FA86D9A64F1E53C3D0E6250946599DFE639C45955B0ED416CDDFA"),
|
||||
|
@ -99,14 +96,12 @@ var secureDelegationTestCases = []test.Case{
|
|||
test.RRSIG("delegated.example.org. 1800 IN RRSIG DS 13 3 1800 20161129153240 20161030153240 49035 example.org. rlNNzcUmtbjLSl02ZzQGUbWX75yCUx0Mug1jHtKVqRq1hpPE2S3863tIWSlz+W9wz4o19OI4jbznKKqk+DGKog=="),
|
||||
},
|
||||
Extra: []dns.RR{
|
||||
test.OPT(4096, true),
|
||||
test.A("a.delegated.example.org. 1800 IN A 139.162.196.78"),
|
||||
test.AAAA("a.delegated.example.org. 1800 IN AAAA 2a01:7e00::f03c:91ff:fef1:6735"),
|
||||
},
|
||||
},
|
||||
{
|
||||
Qname: "foo.delegated.example.org.", Qtype: dns.TypeA,
|
||||
Do: true,
|
||||
Qname: "foo.delegated.example.org.", Qtype: dns.TypeA, Do: true,
|
||||
Ns: []dns.RR{
|
||||
test.DS("delegated.example.org. 1800 IN DS 10056 5 1 EE72CABD1927759CDDA92A10DBF431504B9E1F13"),
|
||||
test.DS("delegated.example.org. 1800 IN DS 10056 5 2 E4B05F87725FA86D9A64F1E53C3D0E6250946599DFE639C45955B0ED416CDDFA"),
|
||||
|
@ -115,14 +110,12 @@ var secureDelegationTestCases = []test.Case{
|
|||
test.RRSIG("delegated.example.org. 1800 IN RRSIG DS 13 3 1800 20161129153240 20161030153240 49035 example.org. rlNNzcUmtbjLSl02ZzQGUbWX75yCUx0Mug1jHtKVqRq1hpPE2S3863tIWSlz+W9wz4o19OI4jbznKKqk+DGKog=="),
|
||||
},
|
||||
Extra: []dns.RR{
|
||||
test.OPT(4096, true),
|
||||
test.A("a.delegated.example.org. 1800 IN A 139.162.196.78"),
|
||||
test.AAAA("a.delegated.example.org. 1800 IN AAAA 2a01:7e00::f03c:91ff:fef1:6735"),
|
||||
},
|
||||
},
|
||||
{
|
||||
Qname: "foo.delegated.example.org.", Qtype: dns.TypeDS,
|
||||
Do: true,
|
||||
Qname: "foo.delegated.example.org.", Qtype: dns.TypeDS, Do: true,
|
||||
Ns: []dns.RR{
|
||||
test.DS("delegated.example.org. 1800 IN DS 10056 5 1 EE72CABD1927759CDDA92A10DBF431504B9E1F13"),
|
||||
test.DS("delegated.example.org. 1800 IN DS 10056 5 2 E4B05F87725FA86D9A64F1E53C3D0E6250946599DFE639C45955B0ED416CDDFA"),
|
||||
|
@ -131,14 +124,12 @@ var secureDelegationTestCases = []test.Case{
|
|||
test.RRSIG("delegated.example.org. 1800 IN RRSIG DS 13 3 1800 20161129153240 20161030153240 49035 example.org. rlNNzcUmtbjLSl02ZzQGUbWX75yCUx0Mug1jHtKVqRq1hpPE2S3863tIWSlz+W9wz4o19OI4jbznKKqk+DGKog=="),
|
||||
},
|
||||
Extra: []dns.RR{
|
||||
test.OPT(4096, true),
|
||||
test.A("a.delegated.example.org. 1800 IN A 139.162.196.78"),
|
||||
test.AAAA("a.delegated.example.org. 1800 IN AAAA 2a01:7e00::f03c:91ff:fef1:6735"),
|
||||
},
|
||||
},
|
||||
{
|
||||
Qname: "delegated.example.org.", Qtype: dns.TypeDS,
|
||||
Do: true,
|
||||
Qname: "delegated.example.org.", Qtype: dns.TypeDS, Do: true,
|
||||
Answer: []dns.RR{
|
||||
test.DS("delegated.example.org. 1800 IN DS 10056 5 1 EE72CABD1927759CDDA92A10DBF431504B9E1F13"),
|
||||
test.DS("delegated.example.org. 1800 IN DS 10056 5 2 E4B05F87725FA86D9A64F1E53C3D0E6250946599DFE639C45955B0ED416CDDFA"),
|
||||
|
@ -149,9 +140,6 @@ var secureDelegationTestCases = []test.Case{
|
|||
test.NS("example.org. 1800 IN NS b.iana-servers.net."),
|
||||
test.RRSIG("example.org. 1800 IN RRSIG NS 13 2 1800 20161129153240 20161030153240 49035 example.org. llrHoIuw="),
|
||||
},
|
||||
Extra: []dns.RR{
|
||||
test.OPT(4096, true),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -122,23 +122,19 @@ var dnameDnssecTestCases = []test.Case{
|
|||
},
|
||||
},
|
||||
{
|
||||
Qname: "dname.example.org.", Qtype: dns.TypeDNAME,
|
||||
Do: true,
|
||||
Qname: "dname.example.org.", Qtype: dns.TypeDNAME, Do: true,
|
||||
Answer: []dns.RR{
|
||||
test.DNAME("dname.example.org. 1800 IN DNAME test.example.org."),
|
||||
test.RRSIG("dname.example.org. 1800 IN RRSIG DNAME 5 3 1800 20170702091734 20170602091734 54282 example.org. HvXtiBM="),
|
||||
},
|
||||
Extra: []dns.RR{test.OPT(4096, true)},
|
||||
},
|
||||
{
|
||||
Qname: "a.dname.example.org.", Qtype: dns.TypeA,
|
||||
Do: true,
|
||||
Qname: "a.dname.example.org.", Qtype: dns.TypeA, Do: true,
|
||||
Answer: []dns.RR{
|
||||
test.CNAME("a.dname.example.org. 1800 IN CNAME a.test.example.org."),
|
||||
test.DNAME("dname.example.org. 1800 IN DNAME test.example.org."),
|
||||
test.RRSIG("dname.example.org. 1800 IN RRSIG DNAME 5 3 1800 20170702091734 20170602091734 54282 example.org. HvXtiBM="),
|
||||
},
|
||||
Extra: []dns.RR{test.OPT(4096, true)},
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ import (
|
|||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
// All OPT RR are added in server.go, so we don't specify them in the unit tests.
|
||||
var dnssecTestCases = []test.Case{
|
||||
{
|
||||
Qname: "miek.nl.", Qtype: dns.TypeSOA, Do: true,
|
||||
|
@ -18,8 +19,7 @@ var dnssecTestCases = []test.Case{
|
|||
test.RRSIG("miek.nl. 1800 IN RRSIG SOA 8 2 1800 20160426031301 20160327031301 12051 miek.nl. FIrzy07acBbtyQczy1dc="),
|
||||
test.SOA("miek.nl. 1800 IN SOA linode.atoom.net. miek.miek.nl. 1282630057 14400 3600 604800 14400"),
|
||||
},
|
||||
Ns: auth,
|
||||
Extra: []dns.RR{test.OPT(4096, true)},
|
||||
Ns: auth,
|
||||
},
|
||||
{
|
||||
Qname: "miek.nl.", Qtype: dns.TypeAAAA, Do: true,
|
||||
|
@ -27,8 +27,7 @@ var dnssecTestCases = []test.Case{
|
|||
test.AAAA("miek.nl. 1800 IN AAAA 2a01:7e00::f03c:91ff:fef1:6735"),
|
||||
test.RRSIG("miek.nl. 1800 IN RRSIG AAAA 8 2 1800 20160426031301 20160327031301 12051 miek.nl. SsRT="),
|
||||
},
|
||||
Ns: auth,
|
||||
Extra: []dns.RR{test.OPT(4096, true)},
|
||||
Ns: auth,
|
||||
},
|
||||
{
|
||||
Qname: "miek.nl.", Qtype: dns.TypeNS, Do: true,
|
||||
|
@ -39,7 +38,6 @@ var dnssecTestCases = []test.Case{
|
|||
test.NS("miek.nl. 1800 IN NS omval.tednet.nl."),
|
||||
test.RRSIG("miek.nl. 1800 IN RRSIG NS 8 2 1800 20160426031301 20160327031301 12051 miek.nl. ZLtsQhwaz+lHfNpztFoR1Vxs="),
|
||||
},
|
||||
Extra: []dns.RR{test.OPT(4096, true)},
|
||||
},
|
||||
{
|
||||
Qname: "miek.nl.", Qtype: dns.TypeMX, Do: true,
|
||||
|
@ -51,8 +49,7 @@ var dnssecTestCases = []test.Case{
|
|||
test.MX("miek.nl. 1800 IN MX 5 alt2.aspmx.l.google.com."),
|
||||
test.RRSIG("miek.nl. 1800 IN RRSIG MX 8 2 1800 20160426031301 20160327031301 12051 miek.nl. kLqG+iOr="),
|
||||
},
|
||||
Ns: auth,
|
||||
Extra: []dns.RR{test.OPT(4096, true)},
|
||||
Ns: auth,
|
||||
},
|
||||
{
|
||||
Qname: "www.miek.nl.", Qtype: dns.TypeA, Do: true,
|
||||
|
@ -63,9 +60,6 @@ var dnssecTestCases = []test.Case{
|
|||
test.RRSIG("www.miek.nl. 1800 RRSIG CNAME 8 3 1800 20160426031301 20160327031301 12051 miek.nl. NVZmMJaypS+wDL2Lar4Zw1zF"),
|
||||
},
|
||||
Ns: auth,
|
||||
Extra: []dns.RR{
|
||||
test.OPT(4096, true),
|
||||
},
|
||||
},
|
||||
{
|
||||
// NoData
|
||||
|
@ -76,7 +70,6 @@ var dnssecTestCases = []test.Case{
|
|||
test.RRSIG("miek.nl. 1800 IN RRSIG SOA 8 2 1800 20160426031301 20160327031301 12051 miek.nl. FIrzy07acBbtyQczy1dc="),
|
||||
test.SOA("miek.nl. 1800 IN SOA linode.atoom.net. miek.miek.nl. 1282630057 14400 3600 604800 14400"),
|
||||
},
|
||||
Extra: []dns.RR{test.OPT(4096, true)},
|
||||
},
|
||||
{
|
||||
Qname: "b.miek.nl.", Qtype: dns.TypeA, Do: true,
|
||||
|
@ -89,7 +82,6 @@ var dnssecTestCases = []test.Case{
|
|||
test.RRSIG("miek.nl. 1800 IN RRSIG SOA 8 2 1800 20160426031301 20160327031301 12051 miek.nl. FIrzy07acBbtyQczy1dc="),
|
||||
test.SOA("miek.nl. 1800 IN SOA linode.atoom.net. miek.miek.nl. 1282630057 14400 3600 604800 14400"),
|
||||
},
|
||||
Extra: []dns.RR{test.OPT(4096, true)},
|
||||
},
|
||||
{
|
||||
Qname: "b.blaat.miek.nl.", Qtype: dns.TypeA, Do: true,
|
||||
|
@ -102,7 +94,6 @@ var dnssecTestCases = []test.Case{
|
|||
test.RRSIG("miek.nl. 1800 IN RRSIG SOA 8 2 1800 20160426031301 20160327031301 12051 miek.nl. FIrzy07acBbtyQczy1dc="),
|
||||
test.SOA("miek.nl. 1800 IN SOA linode.atoom.net. miek.miek.nl. 1282630057 14400 3600 604800 14400"),
|
||||
},
|
||||
Extra: []dns.RR{test.OPT(4096, true)},
|
||||
},
|
||||
{
|
||||
Qname: "b.a.miek.nl.", Qtype: dns.TypeA, Do: true,
|
||||
|
@ -114,7 +105,6 @@ var dnssecTestCases = []test.Case{
|
|||
test.RRSIG("miek.nl. 1800 IN RRSIG SOA 8 2 1800 20160426031301 20160327031301 12051 miek.nl. FIrzy07acBbtyQczy1dc="),
|
||||
test.SOA("miek.nl. 1800 IN SOA linode.atoom.net. miek.miek.nl. 1282630057 14400 3600 604800 14400"),
|
||||
},
|
||||
Extra: []dns.RR{test.OPT(4096, true)},
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -26,7 +26,6 @@ var entTestCases = []test.Case{
|
|||
test.RRSIG("miek.nl. 1800 IN RRSIG SOA 8 2 1800 20160502144311 20160402144311 12051 miek.nl. KegoBxA3Tbrhlc4cEdkRiteIkOfsq"),
|
||||
test.SOA("miek.nl. 1800 IN SOA linode.atoom.net. miek.miek.nl. 1282630057 14400 3600 604800 14400"),
|
||||
},
|
||||
Extra: []dns.RR{test.OPT(4096, true)},
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -98,8 +98,6 @@ func (f File) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (i
|
|||
return dns.RcodeServerFailure, nil
|
||||
}
|
||||
|
||||
state.SizeAndDo(m)
|
||||
m, _ = state.Scrub(m)
|
||||
w.WriteMsg(m)
|
||||
return dns.RcodeSuccess, nil
|
||||
}
|
||||
|
|
|
@ -11,8 +11,7 @@ import (
|
|||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
// another personal zone (helps in testing as my secondary is NSD
|
||||
// atoom = atom in English.
|
||||
// another personal zone (helps in testing as my secondary is NSD, atoom = atom in English.
|
||||
var atoomTestCases = []test.Case{
|
||||
{
|
||||
Qname: atoom, Qtype: dns.TypeNS, Do: true,
|
||||
|
@ -23,7 +22,7 @@ var atoomTestCases = []test.Case{
|
|||
test.RRSIG("atoom.net. 1800 IN RRSIG NS 8 2 1800 20170112031301 20161213031301 53289 atoom.net. DLe+G1 jlw="),
|
||||
},
|
||||
Extra: []dns.RR{
|
||||
test.OPT(4096, true),
|
||||
// test.OPT(4096, true), // added by server, not test in this unit test.
|
||||
test.A("linode.atoom.net. 1800 IN A 176.58.119.54"),
|
||||
test.AAAA("linode.atoom.net. 1800 IN AAAA 2a01:7e00::f03c:91ff:fe79:234c"),
|
||||
test.RRSIG("linode.atoom.net. 1800 IN RRSIG A 8 3 1800 20170112031301 20161213031301 53289 atoom.net. Z4Ka4OLDoyxj72CL vkI="),
|
||||
|
|
|
@ -11,6 +11,7 @@ import (
|
|||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
// these examples don't have an additional opt RR set, because that's gets added by the server.
|
||||
var wildcardTestCases = []test.Case{
|
||||
{
|
||||
Qname: "wild.dnssex.nl.", Qtype: dns.TypeTXT,
|
||||
|
@ -36,7 +37,6 @@ var wildcardTestCases = []test.Case{
|
|||
test.NSEC("a.dnssex.nl. 14400 IN NSEC www.dnssex.nl. A AAAA RRSIG NSEC"),
|
||||
test.RRSIG("a.dnssex.nl. 14400 IN RRSIG NSEC 8 3 14400 20160428190224 20160329190224 14460 dnssex.nl. S+UMs2ySgRaaRY"),
|
||||
}, dnssexAuth...),
|
||||
Extra: []dns.RR{test.OPT(4096, true)},
|
||||
},
|
||||
{
|
||||
Qname: "a.wild.dnssex.nl.", Qtype: dns.TypeTXT, Do: true,
|
||||
|
@ -48,7 +48,6 @@ var wildcardTestCases = []test.Case{
|
|||
test.NSEC("a.dnssex.nl. 14400 IN NSEC www.dnssex.nl. A AAAA RRSIG NSEC"),
|
||||
test.RRSIG("a.dnssex.nl. 14400 IN RRSIG NSEC 8 3 14400 20160428190224 20160329190224 14460 dnssex.nl. S+UMs2ySgRaaRY"),
|
||||
}, dnssexAuth...),
|
||||
Extra: []dns.RR{test.OPT(4096, true)},
|
||||
},
|
||||
// nodata responses
|
||||
{
|
||||
|
@ -66,7 +65,6 @@ var wildcardTestCases = []test.Case{
|
|||
test.RRSIG(`dnssex.nl. 1800 IN RRSIG SOA 8 2 1800 20160428190224 20160329190224 14460 dnssex.nl. CA/Y3m9hCOiKC/8ieSOv8SeP964Bq++lyH8BZJcTaabAsERs4xj5PRtcxicwQXZiF8fYUCpROlUS0YR8Cdw=`),
|
||||
test.SOA(`dnssex.nl. 1800 IN SOA linode.atoom.net. miek.miek.nl. 1459281744 14400 3600 604800 14400`),
|
||||
},
|
||||
Extra: []dns.RR{test.OPT(4096, true)},
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -148,13 +148,7 @@ func (f *Forward) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg
|
|||
return 0, nil
|
||||
}
|
||||
|
||||
// When using force_tcp the upstream can send a message that is too big for
|
||||
// the udp buffer, hence we need to truncate the message to at least make it
|
||||
// fit the udp buffer.
|
||||
ret, _ = state.Scrub(ret)
|
||||
|
||||
w.WriteMsg(ret)
|
||||
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -66,8 +66,6 @@ func (h Hosts) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (
|
|||
m.Authoritative, m.RecursionAvailable = true, true
|
||||
m.Answer = answers
|
||||
|
||||
state.SizeAndDo(m)
|
||||
m, _ = state.Scrub(m)
|
||||
w.WriteMsg(m)
|
||||
return dns.RcodeSuccess, nil
|
||||
}
|
||||
|
|
|
@ -78,8 +78,6 @@ func (k Kubernetes) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.M
|
|||
m.Answer = append(m.Answer, records...)
|
||||
m.Extra = append(m.Extra, extra...)
|
||||
|
||||
state.SizeAndDo(m)
|
||||
m, _ = state.Scrub(m)
|
||||
w.WriteMsg(m)
|
||||
return dns.RcodeSuccess, nil
|
||||
}
|
||||
|
|
|
@ -64,10 +64,6 @@ func (d *dnsEx) Exchange(ctx context.Context, addr string, state request.Request
|
|||
return nil, err
|
||||
}
|
||||
reply.Id = state.Req.Id
|
||||
// When using force_tcp the upstream can send a message that is too big for
|
||||
// the udp buffer, hence we need to truncate the message to at least make it
|
||||
// fit the udp buffer.
|
||||
reply, _ = state.Scrub(reply)
|
||||
|
||||
return reply, nil
|
||||
}
|
||||
|
|
|
@ -63,8 +63,6 @@ func (rr Route53) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg
|
|||
m.Authoritative, m.RecursionAvailable = true, true
|
||||
m.Answer = answers
|
||||
|
||||
state.SizeAndDo(m)
|
||||
m, _ = state.Scrub(m)
|
||||
w.WriteMsg(m)
|
||||
return dns.RcodeSuccess, nil
|
||||
}
|
||||
|
|
|
@ -104,8 +104,6 @@ func (h Handler) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg)
|
|||
msg.Ns = append(msg.Ns, rr)
|
||||
}
|
||||
|
||||
state.SizeAndDo(msg)
|
||||
state.Scrub(msg)
|
||||
w.WriteMsg(msg)
|
||||
return template.rcode, nil
|
||||
}
|
||||
|
|
|
@ -226,19 +226,11 @@ func (r *Request) SizeAndDo(m *dns.Msg) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
// Result is the result of Scrub.
|
||||
type Result int
|
||||
// Scrub is a noop function, added for backwards compatibility reasons. The original Scrub is now called
|
||||
// automatically by the server on writing the reply. See ScrubWriter.
|
||||
func (r *Request) Scrub(reply *dns.Msg) (*dns.Msg, int) { return reply, 0 }
|
||||
|
||||
const (
|
||||
// ScrubIgnored is returned when Scrub did nothing to the message.
|
||||
ScrubIgnored Result = iota
|
||||
// ScrubExtra is returned when the reply has been scrubbed by removing RRs from the additional section.
|
||||
ScrubExtra
|
||||
// ScrubAnswer is returned when the reply has been scrubbed by removing RRs from the answer section.
|
||||
ScrubAnswer
|
||||
)
|
||||
|
||||
// Scrub scrubs the reply message so that it will fit the client's buffer. It will first
|
||||
// scrub scrubs the reply message so that it will fit the client's buffer. It will first
|
||||
// check if the reply fits without compression and then *with* compression.
|
||||
// Scrub will then use binary search to find a save cut off point in the additional section.
|
||||
// If even *without* the additional section the reply still doesn't fit we
|
||||
|
@ -246,19 +238,19 @@ const (
|
|||
// we set the TC bit on the reply; indicating the client should retry over TCP.
|
||||
// Note, the TC bit will be set regardless of protocol, even TCP message will
|
||||
// get the bit, the client should then retry with pigeons.
|
||||
func (r *Request) Scrub(reply *dns.Msg) (*dns.Msg, Result) {
|
||||
func (r *Request) scrub(reply *dns.Msg) *dns.Msg {
|
||||
size := r.Size()
|
||||
|
||||
reply.Compress = false
|
||||
rl := reply.Len()
|
||||
if size >= rl {
|
||||
return reply, ScrubIgnored
|
||||
return reply
|
||||
}
|
||||
|
||||
reply.Compress = true
|
||||
rl = reply.Len()
|
||||
if size >= rl {
|
||||
return reply, ScrubIgnored
|
||||
return reply
|
||||
}
|
||||
|
||||
// Account for the OPT record that gets added in SizeAndDo(), subtract that length.
|
||||
|
@ -298,7 +290,7 @@ func (r *Request) Scrub(reply *dns.Msg) (*dns.Msg, Result) {
|
|||
|
||||
if rl < size {
|
||||
r.SizeAndDo(reply)
|
||||
return reply, ScrubExtra
|
||||
return reply
|
||||
}
|
||||
|
||||
ra := len(reply.Answer)
|
||||
|
@ -330,7 +322,7 @@ func (r *Request) Scrub(reply *dns.Msg) (*dns.Msg, Result) {
|
|||
|
||||
r.SizeAndDo(reply)
|
||||
reply.Truncated = true
|
||||
return reply, ScrubAnswer
|
||||
return reply
|
||||
}
|
||||
|
||||
// Type returns the type of the question as a string. If the request is malformed the empty string is returned.
|
||||
|
|
|
@ -73,10 +73,7 @@ func TestRequestScrubAnswer(t *testing.T) {
|
|||
fmt.Sprintf("large.example.com. 10 IN SRV 0 0 80 10-0-0-%d.default.pod.k8s.example.com.", i)))
|
||||
}
|
||||
|
||||
_, got := req.Scrub(reply)
|
||||
if want := ScrubAnswer; want != got {
|
||||
t.Errorf("Want scrub result %d, got %d", want, got)
|
||||
}
|
||||
req.scrub(reply)
|
||||
if want, got := req.Size(), reply.Len(); want < got {
|
||||
t.Errorf("Want scrub to reduce message length below %d bytes, got %d bytes", want, got)
|
||||
}
|
||||
|
@ -97,10 +94,7 @@ func TestRequestScrubExtra(t *testing.T) {
|
|||
fmt.Sprintf("large.example.com. 10 IN SRV 0 0 80 10-0-0-%d.default.pod.k8s.example.com.", i)))
|
||||
}
|
||||
|
||||
_, got := req.Scrub(reply)
|
||||
if want := ScrubExtra; want != got {
|
||||
t.Errorf("Want scrub result %d, got %d", want, got)
|
||||
}
|
||||
req.scrub(reply)
|
||||
if want, got := req.Size(), reply.Len(); want < got {
|
||||
t.Errorf("Want scrub to reduce message length below %d bytes, got %d bytes", want, got)
|
||||
}
|
||||
|
@ -122,10 +116,7 @@ func TestRequestScrubExtraEdns0(t *testing.T) {
|
|||
fmt.Sprintf("large.example.com. 10 IN SRV 0 0 80 10-0-0-%d.default.pod.k8s.example.com.", i)))
|
||||
}
|
||||
|
||||
_, got := req.Scrub(reply)
|
||||
if want := ScrubExtra; want != got {
|
||||
t.Errorf("Want scrub result %d, got %d", want, got)
|
||||
}
|
||||
req.scrub(reply)
|
||||
if want, got := req.Size(), reply.Len(); want < got {
|
||||
t.Errorf("Want scrub to reduce message length below %d bytes, got %d bytes", want, got)
|
||||
}
|
||||
|
@ -155,10 +146,7 @@ func TestRequestScrubExtraRegression(t *testing.T) {
|
|||
fmt.Sprintf("10-0-0-%d.default.pod.k8s.example.com. 10 IN A 10.0.0.%d", i, i)))
|
||||
}
|
||||
|
||||
_, got := req.Scrub(reply)
|
||||
if want := ScrubExtra; want != got {
|
||||
t.Errorf("Want scrub result %d, got %d", want, got)
|
||||
}
|
||||
reply = req.scrub(reply)
|
||||
if want, got := req.Size(), reply.Len(); want < got {
|
||||
t.Errorf("Want scrub to reduce message length below %d bytes, got %d bytes", want, got)
|
||||
}
|
||||
|
@ -183,10 +171,7 @@ func TestRequestScrubAnswerExact(t *testing.T) {
|
|||
reply.Answer = append(reply.Answer, test.A(fmt.Sprintf("large.example.com. 10 IN A 127.0.0.%d", i)))
|
||||
}
|
||||
|
||||
_, got := req.Scrub(reply)
|
||||
if want := ScrubAnswer; want != got {
|
||||
t.Errorf("Want scrub result %d, got %d", want, got)
|
||||
}
|
||||
req.scrub(reply)
|
||||
if want, got := req.Size(), reply.Len(); want < got {
|
||||
t.Errorf("Want scrub to reduce message length below %d bytes, got %d bytes", want, got)
|
||||
}
|
||||
|
|
20
request/writer.go
Normal file
20
request/writer.go
Normal file
|
@ -0,0 +1,20 @@
|
|||
package request
|
||||
|
||||
import "github.com/miekg/dns"
|
||||
|
||||
// ScrubWriter will, when writing the message, call scrub to make it fit the client's buffer.
|
||||
type ScrubWriter struct {
|
||||
dns.ResponseWriter
|
||||
req *dns.Msg // original request
|
||||
}
|
||||
|
||||
// NewScrubWriter returns a new and initialized ScrubWriter.
|
||||
func NewScrubWriter(req *dns.Msg, w dns.ResponseWriter) *ScrubWriter { return &ScrubWriter{w, req} }
|
||||
|
||||
// WriteMsg overrides the default implementation of the underlaying dns.ResponseWriter and calls
|
||||
// scrub on the message m and will then write it to the client.
|
||||
func (s *ScrubWriter) WriteMsg(m *dns.Msg) error {
|
||||
state := Request{Req: s.req, W: s.ResponseWriter}
|
||||
new, _ := state.Scrub(m)
|
||||
return s.ResponseWriter.WriteMsg(new)
|
||||
}
|
Loading…
Add table
Reference in a new issue