mirror of
https://github.com/AdguardTeam/AdGuardDNS.git
synced 2026-01-18 12:08:46 -05:00
220 lines
5.8 KiB
Go
220 lines
5.8 KiB
Go
package cache_test
|
|
|
|
import (
|
|
"context"
|
|
"net"
|
|
"net/netip"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver"
|
|
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver/cache"
|
|
"github.com/AdguardTeam/AdGuardDNS/internal/dnsserver/dnsservertest"
|
|
"github.com/AdguardTeam/golibs/logutil/slogutil"
|
|
"github.com/miekg/dns"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
// testLogger is the common logger for tests.
|
|
var testLogger = slogutil.NewDiscardLogger()
|
|
|
|
func TestMiddleware_Wrap(t *testing.T) {
|
|
const (
|
|
servFailMaxCacheTTL = 30
|
|
|
|
reqHost = "example.com"
|
|
reqCNAME = "cname.example.com"
|
|
reqNs1 = "ns1.example.com"
|
|
reqNs2 = "ns2.example.com"
|
|
|
|
defaultTTL uint32 = 3600
|
|
)
|
|
|
|
reqAddr := netip.MustParseAddr("1.2.3.4")
|
|
testTTL := 60 * time.Second
|
|
|
|
aReq := dnsservertest.NewReq(reqHost, dns.TypeA, dns.ClassINET)
|
|
cnameReq := dnsservertest.NewReq(reqHost, dns.TypeCNAME, dns.ClassINET)
|
|
cnameAns := dnsservertest.SectionAnswer{dnsservertest.NewCNAME(reqHost, defaultTTL, reqCNAME)}
|
|
soaNs := dnsservertest.SectionNs{dnsservertest.NewSOA(reqHost, defaultTTL, reqNs1, reqNs2)}
|
|
|
|
const N = 5
|
|
testCases := []struct {
|
|
req *dns.Msg
|
|
resp *dns.Msg
|
|
minTTL *time.Duration
|
|
name string
|
|
wantNumReq int
|
|
wantTTL uint32
|
|
}{{
|
|
req: aReq,
|
|
resp: dnsservertest.NewResp(dns.RcodeSuccess, aReq, dnsservertest.SectionAnswer{
|
|
dnsservertest.NewA(reqHost, defaultTTL, reqAddr),
|
|
}),
|
|
name: "simple_a",
|
|
wantNumReq: 1,
|
|
minTTL: nil,
|
|
wantTTL: defaultTTL,
|
|
}, {
|
|
req: aReq,
|
|
resp: dnsservertest.NewResp(dns.RcodeSuccess, aReq),
|
|
name: "empty_answer",
|
|
wantNumReq: N,
|
|
minTTL: nil,
|
|
wantTTL: 0,
|
|
}, {
|
|
req: aReq,
|
|
resp: dnsservertest.NewResp(dns.RcodeSuccess, aReq, soaNs),
|
|
name: "authoritative_nodata",
|
|
wantNumReq: 1,
|
|
minTTL: nil,
|
|
wantTTL: defaultTTL,
|
|
}, {
|
|
req: aReq,
|
|
resp: dnsservertest.NewResp(dns.RcodeSuccess, aReq, cnameAns, soaNs),
|
|
name: "nodata_with_cname",
|
|
wantNumReq: 1,
|
|
minTTL: nil,
|
|
wantTTL: defaultTTL,
|
|
}, {
|
|
req: aReq,
|
|
resp: dnsservertest.NewResp(dns.RcodeSuccess, aReq, cnameAns),
|
|
name: "nodata_with_cname_no_soa",
|
|
wantNumReq: N,
|
|
minTTL: nil,
|
|
wantTTL: defaultTTL,
|
|
}, {
|
|
req: aReq,
|
|
resp: dnsservertest.NewResp(dns.RcodeNameError, aReq, dnsservertest.SectionNs{
|
|
dnsservertest.NewNS(reqHost, defaultTTL, reqNs1),
|
|
}),
|
|
name: "non_authoritative_nxdomain",
|
|
// TODO(ameshkov): Consider https://datatracker.ietf.org/doc/html/rfc2308#section-3.
|
|
wantNumReq: 1,
|
|
minTTL: nil,
|
|
wantTTL: defaultTTL,
|
|
}, {
|
|
req: aReq,
|
|
resp: dnsservertest.NewResp(dns.RcodeNameError, aReq, soaNs),
|
|
name: "authoritative_nxdomain",
|
|
wantNumReq: 1,
|
|
minTTL: nil,
|
|
wantTTL: defaultTTL,
|
|
}, {
|
|
req: aReq,
|
|
resp: dnsservertest.NewResp(dns.RcodeServerFailure, aReq),
|
|
name: "simple_server_failure",
|
|
wantNumReq: 1,
|
|
minTTL: nil,
|
|
wantTTL: servFailMaxCacheTTL,
|
|
}, {
|
|
req: cnameReq,
|
|
resp: dnsservertest.NewResp(dns.RcodeSuccess, cnameReq, dnsservertest.SectionAnswer{
|
|
dnsservertest.NewCNAME(reqHost, defaultTTL, reqCNAME),
|
|
}),
|
|
name: "simple_cname_ans",
|
|
wantNumReq: 1,
|
|
minTTL: nil,
|
|
wantTTL: defaultTTL,
|
|
}, {
|
|
req: aReq,
|
|
resp: dnsservertest.NewResp(dns.RcodeSuccess, aReq, dnsservertest.SectionAnswer{
|
|
dnsservertest.NewA(reqHost, 0, reqAddr),
|
|
}),
|
|
name: "expired_one",
|
|
wantNumReq: N,
|
|
minTTL: nil,
|
|
wantTTL: 0,
|
|
}, {
|
|
req: aReq,
|
|
resp: dnsservertest.NewResp(dns.RcodeSuccess, aReq, dnsservertest.SectionAnswer{
|
|
dnsservertest.NewA(reqHost, 10, reqAddr),
|
|
}),
|
|
name: "override_ttl_ok",
|
|
wantNumReq: 1,
|
|
minTTL: &testTTL,
|
|
wantTTL: uint32(testTTL.Seconds()),
|
|
}, {
|
|
req: aReq,
|
|
resp: dnsservertest.NewResp(dns.RcodeSuccess, aReq, dnsservertest.SectionAnswer{
|
|
dnsservertest.NewA(reqHost, 1000, reqAddr),
|
|
}),
|
|
name: "override_ttl_max",
|
|
wantNumReq: 1,
|
|
minTTL: &testTTL,
|
|
wantTTL: 1000,
|
|
}, {
|
|
req: aReq,
|
|
resp: dnsservertest.NewResp(dns.RcodeSuccess, aReq, dnsservertest.SectionAnswer{
|
|
dnsservertest.NewA(reqHost, 0, reqAddr),
|
|
}),
|
|
name: "override_ttl_zero",
|
|
wantNumReq: N,
|
|
minTTL: &testTTL,
|
|
wantTTL: 0,
|
|
}, {
|
|
req: aReq,
|
|
resp: dnsservertest.NewResp(dns.RcodeServerFailure, aReq, dnsservertest.SectionAnswer{
|
|
dnsservertest.NewA(reqHost, servFailMaxCacheTTL, reqAddr),
|
|
}),
|
|
name: "override_ttl_servfail",
|
|
wantNumReq: 1,
|
|
minTTL: nil,
|
|
wantTTL: servFailMaxCacheTTL,
|
|
}, {
|
|
req: aReq,
|
|
resp: dnsservertest.NewResp(dns.RcodeNotImplemented, aReq, soaNs),
|
|
name: "unexpected_response",
|
|
wantNumReq: N,
|
|
minTTL: nil,
|
|
wantTTL: defaultTTL,
|
|
}}
|
|
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
numReq := 0
|
|
handler := dnsserver.HandlerFunc(
|
|
func(ctx context.Context, rw dnsserver.ResponseWriter, req *dns.Msg) error {
|
|
numReq++
|
|
|
|
return rw.WriteMsg(ctx, req, tc.resp)
|
|
},
|
|
)
|
|
|
|
var minTTL time.Duration
|
|
if tc.minTTL != nil {
|
|
minTTL = *tc.minTTL
|
|
}
|
|
|
|
withCache := dnsserver.WithMiddlewares(
|
|
handler,
|
|
cache.NewMiddleware(&cache.MiddlewareConfig{
|
|
Logger: testLogger,
|
|
Count: 100,
|
|
MinTTL: minTTL,
|
|
OverrideTTL: tc.minTTL != nil,
|
|
}),
|
|
)
|
|
|
|
var err error
|
|
var nrw *dnsserver.NonWriterResponseWriter
|
|
for range N {
|
|
addr := &net.UDPAddr{IP: net.IP{1, 2, 3, 4}, Port: 53}
|
|
nrw = dnsserver.NewNonWriterResponseWriter(addr, addr)
|
|
err = withCache.ServeDNS(context.Background(), nrw, tc.req)
|
|
}
|
|
|
|
require.NoError(t, err)
|
|
|
|
m := nrw.Msg()
|
|
assert.Equal(t, tc.resp, m)
|
|
assert.Equal(t, tc.wantNumReq, numReq)
|
|
|
|
if len(m.Answer) > 0 {
|
|
assert.Equal(t, tc.wantTTL, m.Answer[0].Header().Ttl)
|
|
}
|
|
})
|
|
}
|
|
}
|