AGH-148 Imp-proxy-tests-vol.2 (25)

This commit is contained in:
Fedor Setrakov
2026-09-24 13:36:03 +03:00
committed by GitHub
parent ddf250f16f
commit 0887a6c594
14 changed files with 282 additions and 354 deletions
+32 -9
View File
@@ -26,18 +26,20 @@ const (
// TLSServerName is a common TLS server name value for tests.
TLSServerName = "testdns.adguard.com"
// Host is a common host for tests.
Host = "test.example"
// TTL is a common time-to-live value in seconds for tests.
TTL = 300
)
var (
// LocalhostAnyPort is a [netip.AddrPort] having a value of 127.0.0.1:0.
LocalhostAnyPort = netip.AddrPortFrom(netutil.IPv4Localhost(), 0)
// IPv4 is a common IPv4 address for test response A records. It uses the
// [net.IP] form for convenient comparisons with [dns.A.A].
//
// TODO(f.setrakov): Use an address from one of the IPv4 documentation
// ranges.
IPv4 = net.IPv4(8, 8, 8, 8)
// IPv4 is a common IPv4 address for tests.
IPv4 = net.IPv4(192, 0, 2, 1)
)
// DefaultTrustedProxies is a set of trusted proxies that includes all possible
@@ -47,12 +49,14 @@ var DefaultTrustedProxies = netutil.SliceSubnetSet{
netip.MustParsePrefix("::/0"),
}
// NewTestRequest returns common DNS request for tests.
// NewTestRequest returns common DNS request for tests. This helper must not be
// used in IPv6-related tests.
func NewTestRequest() (msg *dns.Msg) {
return NewTestRequestWithHost("google-public-dns-a.google.com")
return NewTestRequestWithHost(Host)
}
// NewTestRequestWithHost returns DNS request with common values and given host.
// This helper must not be used in IPv6-related tests.
func NewTestRequestWithHost(host string) (req *dns.Msg) {
return &dns.Msg{
MsgHdr: dns.MsgHdr{
@@ -67,9 +71,28 @@ func NewTestRequestWithHost(host string) (req *dns.Msg) {
}
}
// NewTestResponse is a helper that returns new default response for given
// request. Response will contain single A record with [IPv4] value. req must
// not be nil. This helper must not be used in IPv6-related tests.
func NewTestResponse(req *dns.Msg) (resp *dns.Msg) {
resp = (&dns.Msg{}).SetReply(req)
resp.Answer = []dns.RR{&dns.A{
Hdr: dns.RR_Header{
Name: req.Question[0].Name,
Class: dns.ClassINET,
Rrtype: dns.TypeA,
Ttl: TTL,
},
A: IPv4,
}}
return resp
}
// RequireResponse is a test helper that ensures that the DNS reply matches the
// request and contains an A record with [IPv4]. It is intended to be used
// alongside [NewTestRequest] or [NewTestRequestWithHost].
// alongside [NewTestRequest] or [NewTestRequestWithHost]. This helper must not
// be used in IPv6-related tests.
func RequireResponse(tb testing.TB, req, reply *dns.Msg) {
tb.Helper()
+3 -4
View File
@@ -18,10 +18,9 @@ func TestProxy_IsBogusNXDomain(t *testing.T) {
var ans []dns.RR
onExchange := newECSReplyHandler(&ans, nil, nil)
u := newTestECSUpstream(onExchange)
upsConf := newTestUpstreamConfig(t, defaultTimeout, testDefaultUpstreamAddr)
upsConf.Upstreams = []upstream.Upstream{u}
upsConf := &UpstreamConfig{
Upstreams: []upstream.Upstream{newTestUpstreamWithExchange(t, onExchange)},
}
prx := mustNew(t, &Config{
Logger: testLogger,
+3 -3
View File
@@ -52,7 +52,7 @@ func TestServeCached(t *testing.T) {
Logger: testLogger,
UDPListenAddr: []*net.UDPAddr{net.UDPAddrFromAddrPort(dnsproxytest.LocalhostAnyPort)},
TCPListenAddr: []*net.TCPAddr{net.TCPAddrFromAddrPort(dnsproxytest.LocalhostAnyPort)},
UpstreamConfig: newTestUpstreamConfig(t, defaultTimeout, testDefaultUpstreamAddr),
UpstreamConfig: newTestUpstreamConfig(t, newTestUpstream(t)),
TrustedProxies: dnsproxytest.DefaultTrustedProxies,
DNSSECEnabled: false,
CacheEnabled: true,
@@ -305,7 +305,7 @@ func TestCacheExpiration(t *testing.T) {
Logger: testLogger,
UDPListenAddr: []*net.UDPAddr{net.UDPAddrFromAddrPort(dnsproxytest.LocalhostAnyPort)},
TCPListenAddr: []*net.TCPAddr{net.TCPAddrFromAddrPort(dnsproxytest.LocalhostAnyPort)},
UpstreamConfig: newTestUpstreamConfig(t, defaultTimeout, testDefaultUpstreamAddr),
UpstreamConfig: newTestUpstreamConfig(t, newTestUpstream(t)),
TrustedProxies: dnsproxytest.DefaultTrustedProxies,
CacheEnabled: true,
})
@@ -360,7 +360,7 @@ func TestCacheExpirationWithTTLOverride(t *testing.T) {
var ans []dns.RR
onExchange := newECSReplyHandler(&ans, nil, nil)
u := newTestECSUpstream(onExchange)
u := newTestUpstreamWithExchange(t, onExchange)
dnsProxy := mustNew(t, &Config{
Logger: testLogger,
+1 -1
View File
@@ -18,7 +18,7 @@ import (
const ipv4OnlyFqdn = "ipv4.only."
func TestProxy_handleDNSRequest_DNS64Race(t *testing.T) {
func TestProxy_HandleDNSRequest_dns64Race(t *testing.T) {
ans := newRR(t, ipv4OnlyFqdn, dns.TypeA, 3600, dnsproxytest.IPv4)
ups := &testUpstream{
OnExchange: func(req *dns.Msg) (resp *dns.Msg, err error) {
+1 -1
View File
@@ -43,7 +43,7 @@ func TestFilteringHandler(t *testing.T) {
dnsProxy := mustNew(t, &Config{
Logger: testLogger,
TrustedProxies: dnsproxytest.DefaultTrustedProxies,
UpstreamConfig: newTestUpstreamConfig(t, defaultTimeout, testDefaultUpstreamAddr),
UpstreamConfig: newTestUpstreamConfig(t, newTestUpstream(t)),
RequestHandler: reqHandler,
UDPListenAddr: []*net.UDPAddr{net.UDPAddrFromAddrPort(dnsproxytest.LocalhostAnyPort)},
TCPListenAddr: []*net.TCPAddr{net.TCPAddrFromAddrPort(dnsproxytest.LocalhostAnyPort)},
+13 -23
View File
@@ -1,45 +1,35 @@
package proxy
import (
"context"
"net/netip"
"testing"
"time"
"github.com/AdguardTeam/dnsproxy/upstream"
"github.com/AdguardTeam/dnsproxy/internal/dnsproxytest"
"github.com/AdguardTeam/golibs/testutil"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// testTimeout is a common timeout for tests.
const testTimeout = 1 * time.Second
func TestLookupNetIP(t *testing.T) {
// Use AdGuard DNS here.
dnsUpstream, err := upstream.AddressToUpstream(
"94.140.14.14",
&upstream.Options{
Logger: testLogger,
Timeout: defaultTimeout,
},
)
require.NoError(t, err)
t.Parallel()
conf := &Config{
Logger: testLogger,
UpstreamConfig: &UpstreamConfig{
Upstreams: []upstream.Upstream{dnsUpstream},
},
Logger: testLogger,
UpstreamConfig: newTestUpstreamConfig(t, newTestUpstream(t)),
}
p, err := New(conf)
require.NoError(t, err)
// Now let's try doing some lookups.
addrs, err := p.LookupNetIP(context.Background(), "", "dns.google")
ctx := testutil.ContextWithTimeout(t, testTimeout)
addrs, err := p.LookupNetIP(ctx, "", dnsproxytest.Host)
require.NoError(t, err)
require.NotEmpty(t, addrs)
assert.Contains(t, addrs, netip.MustParseAddr("8.8.8.8"))
assert.Contains(t, addrs, netip.MustParseAddr("8.8.4.4"))
if len(addrs) > 2 {
assert.Contains(t, addrs, netip.MustParseAddr("2001:4860:4860::8888"))
assert.Contains(t, addrs, netip.MustParseAddr("2001:4860:4860::8844"))
}
wantAddr := netip.AddrFrom4([4]byte(dnsproxytest.IPv4.To4()))
assert.Contains(t, addrs, wantAddr)
}
+174 -243
View File
@@ -5,7 +5,6 @@ import (
"crypto/rand"
"net"
"net/netip"
"net/url"
"sync"
"testing"
"time"
@@ -13,6 +12,7 @@ import (
"github.com/AdguardTeam/dnsproxy/internal/dnsproxytest"
"github.com/AdguardTeam/dnsproxy/upstream"
glcache "github.com/AdguardTeam/golibs/cache"
"github.com/AdguardTeam/golibs/container"
"github.com/AdguardTeam/golibs/contextutil"
"github.com/AdguardTeam/golibs/logutil/slogutil"
"github.com/AdguardTeam/golibs/netutil"
@@ -24,8 +24,7 @@ import (
)
const (
listenIP = "127.0.0.1"
testDefaultUpstreamAddr = "8.8.8.8:53"
listenIP = "127.0.0.1"
// defaultTestTTL used to guarantee caching.
defaultTestTTL = 1000
@@ -68,48 +67,42 @@ func firstIP(resp *dns.Msg) (ip net.IP) {
return nil
}
// newTestUpstreamConfigWithBoot creates a new UpstreamConfig with upstream
// addresses and a bootstrapped resolver.
func newTestUpstreamConfigWithBoot(
t require.TestingT,
timeout time.Duration,
addrs ...string,
) (u *UpstreamConfig) {
googleRslv, err := upstream.NewUpstreamResolver(
"8.8.8.8:53",
&upstream.Options{
Logger: testLogger,
Timeout: timeout,
},
)
require.NoError(t, err)
upsConf, err := ParseUpstreamsConfig(addrs, &upstream.Options{
Logger: testLogger,
Timeout: timeout,
Bootstrap: upstream.NewCachingResolver(googleRslv),
})
require.NoError(t, err)
return upsConf
}
// newTestUpstreamConfig creates a new UpstreamConfig with given upstream
// addresses and timeout.
func newTestUpstreamConfig(
tb testing.TB,
timeout time.Duration,
addrs ...string,
) (u *UpstreamConfig) {
// newTestUpstreamConfig creates a new UpstreamConfig with given upstreams set.
func newTestUpstreamConfig(tb testing.TB, ups ...upstream.Upstream) (u *UpstreamConfig) {
tb.Helper()
upsConf, err := ParseUpstreamsConfig(addrs, &upstream.Options{
Logger: testLogger,
Timeout: timeout,
})
require.NoError(tb, err)
return &UpstreamConfig{
Upstreams: ups,
}
}
return upsConf
// newTestUpstream returns default upstream mock, which responds with single A
// record with [dnsproxytest.IPv4] value to all requests. Other upstream
// methods will be replaced with stub implementations.
func newTestUpstream(tb testing.TB) (uc upstream.Upstream) {
tb.Helper()
onExchange := func(req *dns.Msg) (resp *dns.Msg, err error) {
return dnsproxytest.NewTestResponse(req), nil
}
return newTestUpstreamWithExchange(tb, onExchange)
}
// newTestUpstreamWithExchange returns upstream mock which uses given callback
// for [upstream.Upstream.Exchange] implementation. Other upstream methods will
// be replaced with stub implementations.
func newTestUpstreamWithExchange(
tb testing.TB,
onExchange func(req *dns.Msg) (resp *dns.Msg, err error),
) (uc upstream.Upstream) {
tb.Helper()
return &testUpstream{
OnAddress: func() (addr string) { return "" },
OnExchange: onExchange,
OnClose: func() (err error) { return nil },
}
}
// newTxts returns new test TXT RR strings.
@@ -352,95 +345,107 @@ func TestProxy_Resolve_dnssecCache(t *testing.T) {
}
}
func TestProxy_handleDNSRequest_exchangeWithReservedDomains(t *testing.T) {
func TestProxy_HandleDNSRequest_exchangeWithReservedDomains(t *testing.T) {
t.Parallel()
emptyUpstream := newTestUpstreamWithExchange(t, func(req *dns.Msg) (resp *dns.Msg, err error) {
return (&dns.Msg{}).SetReply(req), nil
})
const (
host1 = "example-1.test"
host2 = "test.example-1.test"
fqdn1 = host1 + "."
fqdn2 = host2 + "."
)
upsConf := &UpstreamConfig{
DomainReservedUpstreams: map[string][]upstream.Upstream{
fqdn1: {emptyUpstream},
fqdn2: {},
},
SpecifiedDomainUpstreams: map[string][]upstream.Upstream{
fqdn1: {emptyUpstream},
fqdn2: {},
},
SubdomainExclusions: container.NewMapSet[string](),
Upstreams: []upstream.Upstream{newTestUpstream(t)},
}
dnsProxy := mustNew(t, &Config{
Logger: testLogger,
UDPListenAddr: []*net.UDPAddr{net.UDPAddrFromAddrPort(dnsproxytest.LocalhostAnyPort)},
TCPListenAddr: []*net.TCPAddr{net.TCPAddrFromAddrPort(dnsproxytest.LocalhostAnyPort)},
UpstreamConfig: newTestUpstreamConfigWithBoot(
t,
dnsproxytest.Timeout,
"[/adguard.com/]192.0.2.1",
"[/google.ru/]192.0.2.2",
"[/maps.google.ru/]#",
"tls://1.1.1.1",
),
Logger: testLogger,
UDPListenAddr: []*net.UDPAddr{net.UDPAddrFromAddrPort(dnsproxytest.LocalhostAnyPort)},
TCPListenAddr: []*net.TCPAddr{net.TCPAddrFromAddrPort(dnsproxytest.LocalhostAnyPort)},
UpstreamConfig: upsConf,
TrustedProxies: dnsproxytest.DefaultTrustedProxies,
})
servicetest.RequireRun(t, dnsProxy, dnsproxytest.Timeout)
// Create a DNS-over-TCP client connection.
addr := dnsProxy.Addr(ProtoTCP)
conn, err := dns.Dial("tcp", addr.String())
require.NoError(t, err)
// Create google-a test message.
req := dnsproxytest.NewTestRequest()
err = conn.WriteMsg(req)
require.NoError(t, err)
var res *dns.Msg
require.True(t, t.Run("common", func(t *testing.T) {
req := dnsproxytest.NewTestRequest()
err = conn.WriteMsg(req)
require.NoError(t, err)
// Make sure that dnsproxy is working.
res, err := conn.ReadMsg()
require.NoError(t, err)
dnsproxytest.RequireResponse(t, req, res)
res, err = conn.ReadMsg()
require.NoError(t, err)
dnsproxytest.RequireResponse(t, req, res)
}))
// Create adguard.com test message.
req = dnsproxytest.NewTestRequestWithHost("adguard.com")
err = conn.WriteMsg(req)
require.NoError(t, err)
require.True(t, t.Run("empty_upstream_response", func(t *testing.T) {
req := dnsproxytest.NewTestRequestWithHost(host1)
err = conn.WriteMsg(req)
require.NoError(t, err)
// Test message should not be resolved.
res, _ = conn.ReadMsg()
require.Nil(t, res.Answer)
res, err = conn.ReadMsg()
require.NoError(t, err)
require.Nil(t, res.Answer)
}))
// Create www.google.ru test message.
req = dnsproxytest.NewTestRequestWithHost("www.google.ru")
err = conn.WriteMsg(req)
require.NoError(t, err)
require.True(t, t.Run("non_empty_response_for_subdomain", func(t *testing.T) {
req := dnsproxytest.NewTestRequestWithHost(host2)
err = conn.WriteMsg(req)
require.NoError(t, err)
// Test message should not be resolved.
res, _ = conn.ReadMsg()
require.Empty(t, res.Answer)
// Create maps.google.ru test message.
req = dnsproxytest.NewTestRequestWithHost("maps.google.ru")
err = conn.WriteMsg(req)
require.NoError(t, err)
// Test message should be resolved.
res, _ = conn.ReadMsg()
require.NotNil(t, res.Answer)
res, err = conn.ReadMsg()
require.NoError(t, err)
dnsproxytest.RequireResponse(t, req, res)
}))
}
func TestProxy_handleDNSRequest_oneByOneUpstreamsExchange(t *testing.T) {
func TestProxy_HandleDNSRequest_oneByOneUpstreamsExchange(t *testing.T) {
t.Parallel()
errUpstream := newTestUpstreamWithExchange(t, func(req *dns.Msg) (resp *dns.Msg, err error) {
return nil, assert.AnError
})
dnsProxy := mustNew(t, &Config{
Logger: testLogger,
UDPListenAddr: []*net.UDPAddr{net.UDPAddrFromAddrPort(dnsproxytest.LocalhostAnyPort)},
TCPListenAddr: []*net.TCPAddr{net.TCPAddrFromAddrPort(dnsproxytest.LocalhostAnyPort)},
UpstreamConfig: newTestUpstreamConfigWithBoot(
UpstreamConfig: newTestUpstreamConfig(
t,
dnsproxytest.Timeout,
"https://fake-dns.com/fake-dns-query",
"tls://fake-dns.com",
"1.1.1.1",
errUpstream,
errUpstream,
newTestUpstream(t),
),
TrustedProxies: dnsproxytest.DefaultTrustedProxies,
Fallbacks: newTestUpstreamConfig(t, dnsproxytest.Timeout, "1.2.3.4:567"),
Fallbacks: newTestUpstreamConfig(t, errUpstream),
})
servicetest.RequireRun(t, dnsProxy, dnsproxytest.Timeout)
// create a DNS-over-TCP client connection
addr := dnsProxy.Addr(ProtoTCP)
conn, err := dns.Dial("tcp", addr.String())
require.NoError(t, err)
// make sure that the response is okay and resolved by valid upstream
req := dnsproxytest.NewTestRequest()
err = conn.WriteMsg(req)
require.NoError(t, err)
@@ -454,80 +459,72 @@ func TestProxy_handleDNSRequest_oneByOneUpstreamsExchange(t *testing.T) {
assert.Greater(t, 3*dnsproxytest.Timeout, elapsed)
}
// newLocalUpstreamListener creates a new localhost listener on the specified
// port for tcp4 network and returns its listening address.
func newLocalUpstreamListener(tb testing.TB, port uint16, h dns.Handler) (real netip.AddrPort) {
tb.Helper()
startCh := make(chan struct{})
upsSrv := &dns.Server{
Addr: netip.AddrPortFrom(netutil.IPv4Localhost(), port).String(),
Net: "tcp",
Handler: h,
NotifyStartedFunc: func() { close(startCh) },
}
go func() {
err := upsSrv.ListenAndServe()
require.NoError(testutil.NewPanicT(tb), err)
}()
<-startCh
testutil.CleanupAndRequireSuccess(tb, upsSrv.Shutdown)
return testutil.RequireTypeAssert[*net.TCPAddr](tb, upsSrv.Listener.Addr()).AddrPort()
}
func TestProxy_handleDNSRequest_fallback(t *testing.T) {
func TestProxy_HandleDNSRequest_fallback(t *testing.T) {
t.Parallel()
const (
hostSuccess = "specific.example"
hostFail = "failing.example"
hostFallbackSuccess = "fallback.success.example"
fqdnSuccess = hostSuccess + "."
fqdnFail = hostFail + "."
fqdnFallbackSuccess = hostFallbackSuccess + "."
)
responseCh := make(chan uint16)
failCh := make(chan uint16)
successHandler := dns.HandlerFunc(func(w dns.ResponseWriter, r *dns.Msg) {
testutil.RequireSend(testutil.NewPanicT(t), responseCh, r.Id, dnsproxytest.Timeout)
pt := testutil.NewPanicT(t)
require.NoError(testutil.NewPanicT(t), w.WriteMsg((&dns.Msg{}).SetReply(r)))
})
failHandler := dns.HandlerFunc(func(w dns.ResponseWriter, r *dns.Msg) {
testutil.RequireSend(testutil.NewPanicT(t), failCh, r.Id, dnsproxytest.Timeout)
successExchange := func(req *dns.Msg) (resp *dns.Msg, err error) {
testutil.RequireSend(pt, responseCh, req.Id, dnsproxytest.Timeout)
require.NoError(testutil.NewPanicT(t), w.WriteMsg(&dns.Msg{}))
return dnsproxytest.NewTestResponse(req), nil
}
successUpstream := newTestUpstreamWithExchange(t, successExchange)
failUpstream := newTestUpstreamWithExchange(t, func(req *dns.Msg) (resp *dns.Msg, err error) {
testutil.RequireSend(pt, failCh, req.Id, dnsproxytest.Timeout)
return nil, assert.AnError
})
successAddr := (&url.URL{
Scheme: string(ProtoTCP),
Host: newLocalUpstreamListener(t, 0, successHandler).String(),
}).String()
alsoSuccessAddr := (&url.URL{
Scheme: string(ProtoTCP),
Host: newLocalUpstreamListener(t, 0, successHandler).String(),
}).String()
failAddr := (&url.URL{
Scheme: string(ProtoTCP),
Host: newLocalUpstreamListener(t, 0, failHandler).String(),
}).String()
upsConf := &UpstreamConfig{
DomainReservedUpstreams: map[string][]upstream.Upstream{
fqdnSuccess: {successUpstream},
fqdnFail: {failUpstream},
},
SpecifiedDomainUpstreams: map[string][]upstream.Upstream{
fqdnSuccess: {successUpstream},
fqdnFail: {failUpstream},
},
SubdomainExclusions: container.NewMapSet[string](),
Upstreams: []upstream.Upstream{failUpstream},
}
fallbackConf := &UpstreamConfig{
DomainReservedUpstreams: map[string][]upstream.Upstream{
fqdnFail: {failUpstream},
fqdnFallbackSuccess: {successUpstream},
},
SpecifiedDomainUpstreams: map[string][]upstream.Upstream{
fqdnFail: {failUpstream},
fqdnFallbackSuccess: {successUpstream},
},
SubdomainExclusions: container.NewMapSet[string](),
Upstreams: []upstream.Upstream{failUpstream, successUpstream},
}
dnsProxy := mustNew(t, &Config{
Logger: testLogger,
UDPListenAddr: []*net.UDPAddr{net.UDPAddrFromAddrPort(dnsproxytest.LocalhostAnyPort)},
TCPListenAddr: []*net.TCPAddr{net.TCPAddrFromAddrPort(dnsproxytest.LocalhostAnyPort)},
UpstreamConfig: newTestUpstreamConfig(
t,
dnsproxytest.Timeout,
failAddr,
"[/specific.example/]"+alsoSuccessAddr,
// almost.failing.example will fall here first.
"[/failing.example/]"+failAddr,
),
Logger: testLogger,
UDPListenAddr: []*net.UDPAddr{net.UDPAddrFromAddrPort(dnsproxytest.LocalhostAnyPort)},
TCPListenAddr: []*net.TCPAddr{net.TCPAddrFromAddrPort(dnsproxytest.LocalhostAnyPort)},
UpstreamConfig: upsConf,
TrustedProxies: dnsproxytest.DefaultTrustedProxies,
Fallbacks: newTestUpstreamConfig(
t,
dnsproxytest.Timeout,
failAddr,
successAddr,
"[/failing.example/]"+failAddr,
"[/almost.failing.example/]"+alsoSuccessAddr,
),
Fallbacks: fallbackConf,
})
servicetest.RequireRun(t, dnsProxy, dnsproxytest.Timeout)
@@ -539,7 +536,7 @@ func TestProxy_handleDNSRequest_fallback(t *testing.T) {
name string
wantSignals []chan uint16
}{{
name: "general.example",
name: dnsproxytest.Host,
wantSignals: []chan uint16{
failCh,
// Both non-specific fallbacks tried.
@@ -547,18 +544,18 @@ func TestProxy_handleDNSRequest_fallback(t *testing.T) {
responseCh,
},
}, {
name: "specific.example",
name: hostSuccess,
wantSignals: []chan uint16{
responseCh,
},
}, {
name: "failing.example",
name: hostFail,
wantSignals: []chan uint16{
failCh,
failCh,
},
}, {
name: "almost.failing.example",
name: hostFallbackSuccess,
wantSignals: []chan uint16{
failCh,
responseCh,
@@ -584,81 +581,28 @@ func TestProxy_handleDNSRequest_fallback(t *testing.T) {
}
}
func TestProxy_handleDNSRequest_fallbackFromInvalidBootstrap(t *testing.T) {
t.Parallel()
invalidRslv, err := upstream.NewUpstreamResolver("8.8.8.8:555", &upstream.Options{
Logger: testLogger,
Timeout: dnsproxytest.Timeout,
})
require.NoError(t, err)
// Prepare the proxy server
upsConf, err := ParseUpstreamsConfig([]string{"tls://dns.adguard.com"}, &upstream.Options{
Logger: testLogger,
Bootstrap: invalidRslv,
Timeout: dnsproxytest.Timeout,
})
require.NoError(t, err)
dnsProxy := mustNew(t, &Config{
Logger: testLogger,
UDPListenAddr: []*net.UDPAddr{net.UDPAddrFromAddrPort(dnsproxytest.LocalhostAnyPort)},
TCPListenAddr: []*net.TCPAddr{net.TCPAddrFromAddrPort(dnsproxytest.LocalhostAnyPort)},
UpstreamConfig: upsConf,
TrustedProxies: dnsproxytest.DefaultTrustedProxies,
Fallbacks: newTestUpstreamConfig(
t,
dnsproxytest.Timeout,
"1.0.0.1",
"8.8.8.8",
),
})
servicetest.RequireRun(t, dnsProxy, dnsproxytest.Timeout)
// Create a DNS-over-UDP client connection
addr := dnsProxy.Addr(ProtoUDP)
conn, err := dns.Dial("udp", addr.String())
require.NoError(t, err)
// Make sure that the response is okay and resolved by the fallback
req := dnsproxytest.NewTestRequest()
err = conn.WriteMsg(req)
require.NoError(t, err)
start := time.Now()
res, err := conn.ReadMsg()
require.NoError(t, err)
dnsproxytest.RequireResponse(t, req, res)
elapsed := time.Since(start)
assert.Greater(t, 3*dnsproxytest.Timeout, elapsed)
}
func TestProxy_Resolve_exchangeCustomUpstreamConfig(t *testing.T) {
p := mustNew(t, &Config{
Logger: testLogger,
UDPListenAddr: []*net.UDPAddr{net.UDPAddrFromAddrPort(dnsproxytest.LocalhostAnyPort)},
TCPListenAddr: []*net.TCPAddr{net.TCPAddrFromAddrPort(dnsproxytest.LocalhostAnyPort)},
UpstreamConfig: newTestUpstreamConfig(t, defaultTimeout, testDefaultUpstreamAddr),
UpstreamConfig: newTestUpstreamConfig(t, newTestUpstream(t)),
TrustedProxies: dnsproxytest.DefaultTrustedProxies,
})
servicetest.RequireRun(t, p, dnsproxytest.Timeout)
ansIP := net.IP{4, 3, 2, 1}
ans := []dns.RR{&dns.A{
Hdr: dns.RR_Header{
Rrtype: dns.TypeA,
Name: "host.",
Name: dns.Fqdn(dnsproxytest.Host),
Ttl: 60,
},
A: ansIP,
A: dnsproxytest.IPv4,
}}
onExchange := newECSReplyHandler(&ans, nil, nil)
u := newTestECSUpstream(onExchange)
u := newTestUpstreamWithExchange(t, onExchange)
d := &DNSContext{
CustomUpstreamConfig: NewCustomUpstreamConfig(
@@ -667,14 +611,14 @@ func TestProxy_Resolve_exchangeCustomUpstreamConfig(t *testing.T) {
0,
false,
),
Req: dnsproxytest.NewTestRequestWithHost("host"),
Addr: netip.MustParseAddrPort("1.2.3.0:1234"),
Req: dnsproxytest.NewTestRequest(),
Addr: netip.MustParseAddrPort("192.0.2.0:1234"),
}
err := p.Resolve(testutil.ContextWithTimeout(t, defaultTimeout), d)
require.NoError(t, err)
assert.Equal(t, ansIP, firstIP(d.Res))
assert.Equal(t, dnsproxytest.IPv4, firstIP(d.Res))
}
func TestProxy_Resolve_customUpstreamConfigCache(t *testing.T) {
@@ -682,7 +626,7 @@ func TestProxy_Resolve_customUpstreamConfigCache(t *testing.T) {
Logger: testLogger,
UDPListenAddr: []*net.UDPAddr{net.UDPAddrFromAddrPort(dnsproxytest.LocalhostAnyPort)},
TCPListenAddr: []*net.TCPAddr{net.TCPAddrFromAddrPort(dnsproxytest.LocalhostAnyPort)},
UpstreamConfig: newTestUpstreamConfig(t, defaultTimeout, testDefaultUpstreamAddr),
UpstreamConfig: newTestUpstreamConfig(t, newTestUpstream(t)),
TrustedProxies: dnsproxytest.DefaultTrustedProxies,
CacheEnabled: true,
DNSSECEnabled: true,
@@ -692,7 +636,6 @@ func TestProxy_Resolve_customUpstreamConfigCache(t *testing.T) {
var count int
ansIP := net.IP{4, 3, 2, 1}
exchangeFunc := func(m *dns.Msg) (resp *dns.Msg, err error) {
resp = &dns.Msg{}
resp.SetReply(m)
@@ -703,7 +646,7 @@ func TestProxy_Resolve_customUpstreamConfigCache(t *testing.T) {
Rrtype: dns.TypeA,
Ttl: defaultTestTTL,
},
A: ansIP,
A: dnsproxytest.IPv4,
})
count++
@@ -726,7 +669,7 @@ func TestProxy_Resolve_customUpstreamConfigCache(t *testing.T) {
d := &DNSContext{
CustomUpstreamConfig: customUpstreamConfig,
Req: dnsproxytest.NewTestRequestWithHost("host"),
Addr: netip.MustParseAddrPort("1.2.3.0:1234"),
Addr: netip.MustParseAddrPort("192.0.2.0:1234"),
}
ctx := testutil.ContextWithTimeout(t, defaultTimeout)
@@ -734,13 +677,13 @@ func TestProxy_Resolve_customUpstreamConfigCache(t *testing.T) {
require.NoError(t, err)
require.Equal(t, 1, count)
assert.Equal(t, ansIP, firstIP(d.Res))
assert.Equal(t, dnsproxytest.IPv4, firstIP(d.Res).To16())
err = prx.Resolve(ctx, d)
require.NoError(t, err)
assert.Equal(t, 1, count)
assert.Equal(t, ansIP, firstIP(d.Res))
assert.Equal(t, dnsproxytest.IPv4, firstIP(d.Res).To16())
customUpstreamConfig.ClearCache()
@@ -748,7 +691,7 @@ func TestProxy_Resolve_customUpstreamConfigCache(t *testing.T) {
require.NoError(t, err)
assert.Equal(t, 2, count)
assert.Equal(t, ansIP, firstIP(d.Res))
assert.Equal(t, dnsproxytest.IPv4, firstIP(d.Res).To16())
}
func TestSetECS(t *testing.T) {
@@ -805,7 +748,7 @@ func TestProxy_Resolve_ecs(t *testing.T) {
)
onExchange := newECSReplyHandler(&ans, &ecsIP, &ecsReqIP)
u := newTestECSUpstream(onExchange)
u := newTestUpstreamWithExchange(t, onExchange)
ans = []dns.RR{&dns.A{
Hdr: dns.RR_Header{Rrtype: dns.TypeA, Name: "host.", Ttl: 60},
@@ -923,7 +866,7 @@ func TestProxy_Resolve_ecsProxyCacheMinMaxTTL(t *testing.T) {
)
onExchange := newECSReplyHandler(&ans, &ecsIP, nil)
u := newTestECSUpstream(onExchange)
u := newTestUpstreamWithExchange(t, onExchange)
ans = []dns.RR{&dns.A{
Hdr: dns.RR_Header{
@@ -1116,7 +1059,7 @@ func TestProxy_Resolve_withOptimisticResolver(t *testing.T) {
assert.EqualValues(t, nonOptimisticTTL, unpacked.m.Answer[0].Header().Ttl)
}
func TestProxy_validateRequest(t *testing.T) {
func TestProxy_ValidateRequest(t *testing.T) {
t.Parallel()
const (
@@ -1267,18 +1210,6 @@ type testUpstream struct {
OnClose func() (err error)
}
// newTestECSUpstream creates a new test upstream with the given OnExchange
// handler.
func newTestECSUpstream(
onExchange func(req *dns.Msg) (resp *dns.Msg, err error),
) (u *testUpstream) {
return &testUpstream{
OnAddress: func() string { return "" },
OnClose: func() error { return nil },
OnExchange: onExchange,
}
}
// newECSReplyHandler creates an OnExchange handler that builds a DNS reply
// with optional answer records and ECS support.
//
+28 -30
View File
@@ -28,9 +28,6 @@ const (
// testTTL is a common time-to-live value in seconds for tests.
testTTL = 60
// testDefaultUpstreamAddr is the default upstream address for tests.
testDefaultUpstreamAddr = "8.8.8.8:53"
)
var (
@@ -41,24 +38,30 @@ var (
testIPv4 = net.IP{192, 0, 2, 0}
)
// newTestUpstreamConfig creates a new UpstreamConfig with given upstream
// addresses and timeout.
// newTestUpstreamConfig creates a new upstream config with the default mock
// upstream, which expects the request will contain a single question with the
// [proxytest.Host] name.
//
// TODO(f.setrakov): Dry with internal version.
func newTestUpstreamConfig(
tb testing.TB,
timeout time.Duration,
addrs ...string,
) (u *proxy.UpstreamConfig) {
tb.Helper()
// TODO(f.setrakov): DRY with internal version.
func newTestUpstreamConfig(tb testing.TB) (uc *proxy.UpstreamConfig) {
onExchange := func(req *dns.Msg) (resp *dns.Msg, err error) {
pt := testutil.NewPanicT(tb)
upsConf, err := proxy.ParseUpstreamsConfig(addrs, &upstream.Options{
Logger: testLogger,
Timeout: timeout,
})
require.NoError(tb, err)
require.Len(pt, req.Question, 1)
assert.Equal(pt, dns.Fqdn(proxytest.Host), req.Question[0].Name)
return upsConf
return proxytest.NewTestResponse(req), nil
}
u := &dnsproxytest.Upstream{
OnAddress: func() (addr string) { return "" },
OnExchange: onExchange,
OnClose: func() (err error) { return nil },
}
return &proxy.UpstreamConfig{
Upstreams: []upstream.Upstream{u},
}
}
// mustStartDefaultProxy starts a new proxy with default settings and returns
@@ -70,7 +73,7 @@ func mustStartDefaultProxy(tb testing.TB) (p *proxy.Proxy) {
Logger: testLogger,
UDPListenAddr: []*net.UDPAddr{net.UDPAddrFromAddrPort(proxytest.LocalhostAnyPort)},
TCPListenAddr: []*net.TCPAddr{net.TCPAddrFromAddrPort(proxytest.LocalhostAnyPort)},
UpstreamConfig: newTestUpstreamConfig(tb, defaultTimeout, testDefaultUpstreamAddr),
UpstreamConfig: newTestUpstreamConfig(tb),
TrustedProxies: proxytest.DefaultTrustedProxies,
})
require.NoError(tb, err)
@@ -181,15 +184,9 @@ func isCachedWithCustomConfig(
return s[0].IsCached
}
// TODO(f.setrakov): Make it work without a real network.
func TestProxy_HandleDNSRequest_race(t *testing.T) {
upsConf := newTestUpstreamConfig(
t,
defaultTimeout,
// Use the same upstream twice so that we could rotate them
testDefaultUpstreamAddr,
testDefaultUpstreamAddr,
)
upsConf := newTestUpstreamConfig(t)
dnsProxy, err := proxy.New(&proxy.Config{
Logger: testLogger,
UDPListenAddr: []*net.UDPAddr{net.UDPAddrFromAddrPort(proxytest.LocalhostAnyPort)},
@@ -222,17 +219,18 @@ func TestProxy_HandleDNSRequest_race(t *testing.T) {
require.NotNil(pt, res)
require.Len(pt, res.Answer, 1)
a := testutil.RequireTypeAssert[*dns.A](pt, res.Answer[0])
require.IsType(pt, &dns.A{}, res.Answer[0])
a := res.Answer[0].(*dns.A)
require.Equal(pt, net.IPv4(8, 8, 8, 8), a.A.To16())
require.Equal(pt, proxytest.IPv4.To16(), a.A.To16())
})
}
wg.Wait()
}
func TestProxy_handleDNSRequest_responseInRequest(t *testing.T) {
func TestProxy_HandleDNSRequest_responseInRequest(t *testing.T) {
dnsProxy := mustStartDefaultProxy(t)
addr := dnsProxy.Addr(proxy.ProtoTCP)
+2 -3
View File
@@ -15,7 +15,7 @@ import (
"github.com/stretchr/testify/require"
)
func TestDNSCryptProxy(t *testing.T) {
func TestProxy_HandleDNSRequest_dnscrypt(t *testing.T) {
t.Parallel()
// Prepare the proxy server.
@@ -46,7 +46,6 @@ func newTestDNSCryptProxy(tb testing.TB) (p *Proxy, rc dnscrypt.ResolverConfig)
require.NoError(tb, err)
port := nettest.NewFreePort(tb)
upstreamConf := newTestUpstreamConfig(tb, defaultTimeout, testDefaultUpstreamAddr)
p = mustNew(tb, &Config{
Logger: testLogger,
DNSCryptUDPListenAddr: []*net.UDPAddr{{
@@ -55,7 +54,7 @@ func newTestDNSCryptProxy(tb testing.TB) (p *Proxy, rc dnscrypt.ResolverConfig)
DNSCryptTCPListenAddr: []*net.TCPAddr{{
Port: int(port), IP: net.ParseIP(listenIP),
}},
UpstreamConfig: upstreamConf,
UpstreamConfig: newTestUpstreamConfig(tb, newTestUpstream(tb)),
TrustedProxies: dnsproxytest.DefaultTrustedProxies,
EnableEDNSClientSubnet: true,
CacheEnabled: true,
+4 -4
View File
@@ -24,7 +24,7 @@ import (
"github.com/stretchr/testify/require"
)
func TestProxy_handleDNSRequest_https(t *testing.T) {
func TestProxy_HandleDNSRequest_https(t *testing.T) {
testCases := []struct {
name string
http3 bool
@@ -49,7 +49,7 @@ func TestProxy_handleDNSRequest_https(t *testing.T) {
TLSListenAddr: []*net.TCPAddr{net.TCPAddrFromAddrPort(dnsproxytest.LocalhostAnyPort)},
QUICListenAddr: []*net.UDPAddr{net.UDPAddrFromAddrPort(dnsproxytest.LocalhostAnyPort)},
TLSConfig: tlsConf,
UpstreamConfig: newTestUpstreamConfig(t, defaultTimeout, testDefaultUpstreamAddr),
UpstreamConfig: newTestUpstreamConfig(t, newTestUpstream(t)),
TrustedProxies: dnsproxytest.DefaultTrustedProxies,
HTTPConfig: httpConf,
})
@@ -70,7 +70,7 @@ func TestProxy_handleDNSRequest_https(t *testing.T) {
}
}
func TestProxy_handleDNSRequest_trustedProxies(t *testing.T) {
func TestProxy_HandleDNSRequest_trustedProxies(t *testing.T) {
var (
clientAddr = netip.MustParseAddr("1.2.3.4")
proxyAddr = netip.MustParseAddr("127.0.0.1")
@@ -93,7 +93,7 @@ func TestProxy_handleDNSRequest_trustedProxies(t *testing.T) {
}
dnsProxy := mustNew(t, &Config{
Logger: testLogger,
UpstreamConfig: newTestUpstreamConfig(t, defaultTimeout, testDefaultUpstreamAddr),
UpstreamConfig: newTestUpstreamConfig(t, newTestUpstream(t)),
TrustedProxies: dnsproxytest.DefaultTrustedProxies,
RequestHandler: reqHandler,
TLSConfig: tlsConf,
+14 -28
View File
@@ -20,7 +20,7 @@ import (
"github.com/stretchr/testify/require"
)
func TestProxy_handleDNSRequest_quic(t *testing.T) {
func TestProxy_HandleDNSRequest_quic(t *testing.T) {
serverConfig, caPem := dnsproxytest.NewTLSConfig(t)
roots := x509.NewCertPool()
@@ -35,7 +35,7 @@ func TestProxy_handleDNSRequest_quic(t *testing.T) {
Logger: testLogger,
QUICListenAddr: []*net.UDPAddr{net.UDPAddrFromAddrPort(dnsproxytest.LocalhostAnyPort)},
TLSConfig: serverConfig,
UpstreamConfig: newTestUpstreamConfig(t, defaultTimeout, testDefaultUpstreamAddr),
UpstreamConfig: newTestUpstreamConfig(t, newTestUpstream(t)),
TrustedProxies: dnsproxytest.DefaultTrustedProxies,
}
@@ -63,7 +63,7 @@ func TestProxy_handleDNSRequest_quic(t *testing.T) {
require.False(t, t.Failed())
conf.QUICListenAddr = []*net.UDPAddr{addr}
conf.UpstreamConfig = newTestUpstreamConfig(t, defaultTimeout, testDefaultUpstreamAddr)
conf.UpstreamConfig = newTestUpstreamConfig(t, newTestUpstream(t))
t.Run("rerun", func(t *testing.T) {
dnsProxy := mustNew(t, conf)
@@ -83,19 +83,21 @@ func TestProxy_handleDNSRequest_quic(t *testing.T) {
})
}
func TestProxy_handleDNSRequest_quicLargePackets(t *testing.T) {
reqHandler := &testHandler{
OnHandle: func(_ context.Context, _ *Proxy, d *DNSContext) (err error) {
d.Res = newTestResponse(d)
func TestProxy_HandleDNSRequest_quicLargePackets(t *testing.T) {
onHandle := func(_ context.Context, _ *Proxy, d *DNSContext) (err error) {
d.Res = dnsproxytest.NewTestResponse(d.Req)
return nil
},
return nil
}
reqHandler := &testHandler{
OnHandle: onHandle,
}
serverConfig, caPem := dnsproxytest.NewTLSConfig(t)
dnsProxy := mustNew(t, &Config{
Logger: testLogger,
UpstreamConfig: newTestUpstreamConfig(t, defaultTimeout, testDefaultUpstreamAddr),
UpstreamConfig: newTestUpstreamConfig(t, newTestUpstream(t)),
TrustedProxies: dnsproxytest.DefaultTrustedProxies,
RequestHandler: reqHandler,
TLSConfig: serverConfig,
@@ -138,14 +140,14 @@ func TestProxy_handleDNSRequest_quicLargePackets(t *testing.T) {
dnsproxytest.RequireResponse(t, msg, resp)
}
func TestProxy_handleDNSRequest_quicTruncatedRequest(t *testing.T) {
func TestProxy_HandleDNSRequest_quicTruncatedRequest(t *testing.T) {
serverConfig, caPem := dnsproxytest.NewTLSConfig(t)
conf := &Config{
Logger: testLogger,
QUICListenAddr: []*net.UDPAddr{net.UDPAddrFromAddrPort(dnsproxytest.LocalhostAnyPort)},
TLSConfig: serverConfig,
UpstreamConfig: newTestUpstreamConfig(t, defaultTimeout, testDefaultUpstreamAddr),
UpstreamConfig: newTestUpstreamConfig(t, newTestUpstream(t)),
TrustedProxies: dnsproxytest.DefaultTrustedProxies,
RequestHandler: &testHandler{
OnHandle: func(ctx context.Context, p *Proxy, d *DNSContext) (_ error) {
@@ -218,22 +220,6 @@ func TestProxy_handleDNSRequest_quicTruncatedRequest(t *testing.T) {
assert.Greater(t, n, minDNSPacketSize)
}
// newTestResponse creates a test response for the specified request.
func newTestResponse(d *DNSContext) (resp *dns.Msg) {
resp = &dns.Msg{}
resp.SetReply(d.Req)
resp.Answer = []dns.RR{&dns.A{
Hdr: dns.RR_Header{
Name: d.Req.Question[0].Name,
Rrtype: dns.TypeA,
Class: dns.ClassINET,
},
A: net.IP{8, 8, 8, 8},
}}
return resp
}
// sendQUICMessage sends msg to the specified QUIC connection.
func sendQUICMessage(
t *testing.T,
+3 -3
View File
@@ -20,7 +20,7 @@ import (
"github.com/stretchr/testify/require"
)
func TestProxy_handleDNSRequest_tcp(t *testing.T) {
func TestProxy_HandleDNSRequest_tcp(t *testing.T) {
dnsProxy := mustStartDefaultProxy(t)
// Create a DNS-over-TCP client connection
@@ -31,14 +31,14 @@ func TestProxy_handleDNSRequest_tcp(t *testing.T) {
sendTestMessages(t, conn)
}
func TestProxy_handleDNSRequest_tls(t *testing.T) {
func TestProxy_HandleDNSRequest_tls(t *testing.T) {
serverConfig, caPem := proxytest.NewTLSConfig(t)
dnsProxy, err := proxy.New(&proxy.Config{
Logger: testLogger,
TLSListenAddr: []*net.TCPAddr{net.TCPAddrFromAddrPort(proxytest.LocalhostAnyPort)},
QUICListenAddr: []*net.UDPAddr{net.UDPAddrFromAddrPort(proxytest.LocalhostAnyPort)},
TLSConfig: serverConfig,
UpstreamConfig: newTestUpstreamConfig(t, defaultTimeout, testDefaultUpstreamAddr),
UpstreamConfig: newTestUpstreamConfig(t),
TrustedProxies: proxytest.DefaultTrustedProxies,
})
require.NoError(t, err)
+1 -1
View File
@@ -8,7 +8,7 @@ import (
"github.com/stretchr/testify/require"
)
func TestProxy_handleDNSRequest_udp(t *testing.T) {
func TestProxy_HandleDNSRequest_udp(t *testing.T) {
dnsProxy := mustStartDefaultProxy(t)
// Create a DNS-over-UDP client connection
+3 -1
View File
@@ -15,7 +15,9 @@ import (
"github.com/stretchr/testify/require"
)
func TestCollectQueryStats(t *testing.T) {
func TestDNSContext_QueryStatistics(t *testing.T) {
t.Parallel()
testReq := &dns.Msg{
Question: []dns.Question{{
Name: "test.",