Skip to content

Commit 62d5234

Browse files
committed
Pull request: AGDNS-3523-add-context
Merge in GO/dnsproxy from AGDNS-3523-add-context to master Squashed commit of the following: commit 59b61ec Author: Dimitry Kolyshev <dkolyshev@adguard.com> Date: Thu Mar 12 09:20:57 2026 +0700 proxy: start ctx commit fe4cbfb Merge: 10c620a b7d4b05 Author: Dimitry Kolyshev <dkolyshev@adguard.com> Date: Wed Mar 11 07:59:19 2026 +0700 Merge remote-tracking branch 'origin/master' into AGDNS-3523-add-context commit 10c620a Author: Dimitry Kolyshev <dkolyshev@adguard.com> Date: Tue Mar 10 12:21:06 2026 +0700 proxy: fix udp commit 6dbe120 Author: Dimitry Kolyshev <dkolyshev@adguard.com> Date: Fri Mar 6 12:58:47 2026 +0700 proxy: start ctx commit 88cf3e7 Author: Dimitry Kolyshev <dkolyshev@adguard.com> Date: Thu Mar 5 11:24:26 2026 +0700 proxy: req ctx constructor commit f8d8e26 Author: Dimitry Kolyshev <dkolyshev@adguard.com> Date: Tue Mar 3 08:53:28 2026 +0700 proxy: todo commit 6e32f1e Author: Dimitry Kolyshev <dkolyshev@adguard.com> Date: Mon Mar 2 09:27:03 2026 +0700 proxy: add context commit 9e42af8 Author: Dimitry Kolyshev <dkolyshev@adguard.com> Date: Sun Mar 1 09:42:30 2026 +0700 proxy: imp code commit 29e498d Author: Dimitry Kolyshev <dkolyshev@adguard.com> Date: Tue Feb 24 13:32:27 2026 +0700 all: add proxy context
1 parent b7d4b05 commit 62d5234

25 files changed

Lines changed: 247 additions & 151 deletions

internal/middleware/middleware.go

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,7 @@ var _ proxy.Middleware = (*Default)(nil)
6060
// and resolves the DNS request within proxyCtx. It only calls h if the request
6161
// isn't handled by any of the internal handlers.
6262
func (mw *Default) Wrap(h proxy.Handler) (wrapped proxy.Handler) {
63-
f := func(p *proxy.Proxy, proxyCtx *proxy.DNSContext) (err error) {
64-
ctx := context.TODO()
65-
63+
f := func(ctx context.Context, p *proxy.Proxy, proxyCtx *proxy.DNSContext) (err error) {
6664
mw.logger.DebugContext(ctx, "handling request", "req", &proxyCtx.Req.Question[0])
6765

6866
if proxyCtx.Res = mw.haltAAAA(ctx, proxyCtx.Req); proxyCtx.Res != nil {
@@ -73,7 +71,7 @@ func (mw *Default) Wrap(h proxy.Handler) (wrapped proxy.Handler) {
7371
return nil
7472
}
7573

76-
return h.ServeDNS(p, proxyCtx)
74+
return h.ServeDNS(ctx, p, proxyCtx)
7775
}
7876

7977
return proxy.HandlerFunc(f)

proxy/bogusnxdomain_internal_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"testing"
77

88
"github.com/AdguardTeam/dnsproxy/upstream"
9+
"github.com/AdguardTeam/golibs/testutil"
910
"github.com/AdguardTeam/golibs/testutil/servicetest"
1011
"github.com/miekg/dns"
1112
"github.com/stretchr/testify/assert"
@@ -89,7 +90,7 @@ func TestProxy_IsBogusNXDomain(t *testing.T) {
8990
u.ans = tc.ans
9091

9192
t.Run(tc.name, func(t *testing.T) {
92-
err := prx.Resolve(d)
93+
err := prx.Resolve(testutil.ContextWithTimeout(t, defaultTimeout), d)
9394
require.NoError(t, err)
9495
require.NotNil(t, d.Res)
9596

proxy/cache_internal_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -395,7 +395,7 @@ func TestCacheExpirationWithTTLOverride(t *testing.T) {
395395
A: net.IP{4, 3, 2, 1},
396396
}}
397397

398-
err := dnsProxy.Resolve(d)
398+
err := dnsProxy.Resolve(testutil.ContextWithTimeout(t, defaultTimeout), d)
399399
require.NoError(t, err)
400400

401401
ci, expired, key := dnsProxy.cache.get(d.Req)
@@ -419,8 +419,8 @@ func TestCacheExpirationWithTTLOverride(t *testing.T) {
419419
A: net.IP{4, 3, 2, 1},
420420
}}
421421

422-
err := dnsProxy.Resolve(d)
423-
assert.Nil(t, err)
422+
err := dnsProxy.Resolve(testutil.ContextWithTimeout(t, defaultTimeout), d)
423+
require.NoError(t, err)
424424

425425
ci, expired, key := dnsProxy.cache.get(d.Req)
426426
assert.False(t, expired)

proxy/config.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"time"
1111

1212
"github.com/AdguardTeam/dnsproxy/upstream"
13+
"github.com/AdguardTeam/golibs/contextutil"
1314
"github.com/AdguardTeam/golibs/errors"
1415
"github.com/AdguardTeam/golibs/netutil"
1516
"github.com/ameshkov/dnscrypt/v2"
@@ -55,6 +56,10 @@ type Config struct {
5556
// performing a single lookup. If nil, it will be enabled by default.
5657
PendingRequests *PendingRequestsConfig
5758

59+
// RequestContext is a context constructor that returns contexts for
60+
// requests. If not set, the proxy uses [contextutil.EmptyConstructor].
61+
RequestContext contextutil.Constructor
62+
5863
// RequestHandler is an optional custom handler for DNS requests. It's used
5964
// instead of DefaultHandler if set. In case of [ErrDrop] error returned
6065
// from this handler, the proxy will not send any response to the client.

proxy/dns64_internal_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -375,7 +375,7 @@ func TestProxy_Resolve_dns64(t *testing.T) {
375375
Addr: localCliAddr,
376376
}
377377

378-
err = p.handleDNSRequest(dctx)
378+
err = p.handleDNSRequest(testutil.ContextWithTimeout(t, defaultTimeout), dctx)
379379
require.NoError(t, err)
380380

381381
res := dctx.Res

proxy/exchange_internal_test.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,9 @@ func TestProxy_Exchange_loadBalance(t *testing.T) {
223223

224224
t.Run(tc.name, func(t *testing.T) {
225225
for range requestsNum {
226-
_ = p.Resolve(&DNSContext{Req: req, Addr: cli})
226+
ctx := testutil.ContextWithTimeout(t, defaultTimeout)
227+
228+
_ = p.Resolve(ctx, &DNSContext{Req: req, Addr: cli})
227229
}
228230

229231
assert.Equal(t, wantStat, stats)

proxy/handler_internal_test.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package proxy
22

33
import (
4+
"context"
45
"net"
56
"sync"
67
"testing"
@@ -17,13 +18,13 @@ func TestFilteringHandler(t *testing.T) {
1718
blockResponse := false
1819

1920
reqHandler := &TestHandler{
20-
OnHandle: func(p *Proxy, d *DNSContext) (err error) {
21+
OnHandle: func(ctx context.Context, p *Proxy, d *DNSContext) (err error) {
2122
m.Lock()
2223
defer m.Unlock()
2324

2425
if !blockResponse {
2526
// Use the default Resolve method if response is not blocked.
26-
return p.Resolve(d)
27+
return p.Resolve(ctx, d)
2728
}
2829

2930
resp := dns.Msg{}

proxy/lookup.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ func (p *Proxy) lookupIPAddr(
3333

3434
// TODO(d.kolyshev): Investigate why the client address is not defined.
3535
d := p.newDNSContext(ProtoUDP, req, netip.AddrPort{})
36-
err := p.Resolve(d)
36+
err := p.Resolve(ctx, d)
3737
ch <- &lookupResult{
3838
resp: d.Res,
3939
err: err,

proxy/pending_test.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package proxy_test
22

33
import (
4+
"context"
45
"net"
56
"net/netip"
67
"sync"
@@ -79,10 +80,10 @@ func TestPendingRequests(t *testing.T) {
7980
workloadWG.Add(reqsNum)
8081

8182
reqHandler := &proxy.TestHandler{
82-
OnHandle: func(p *proxy.Proxy, d *proxy.DNSContext) (err error) {
83+
OnHandle: func(ctx context.Context, p *proxy.Proxy, d *proxy.DNSContext) (err error) {
8384
workloadWG.Done()
8485

85-
return p.Resolve(d)
86+
return p.Resolve(ctx, d)
8687
},
8788
}
8889

proxy/proxy.go

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"github.com/AdguardTeam/dnsproxy/internal/dnsmsg"
2121
proxynetutil "github.com/AdguardTeam/dnsproxy/internal/netutil"
2222
"github.com/AdguardTeam/dnsproxy/upstream"
23+
"github.com/AdguardTeam/golibs/contextutil"
2324
"github.com/AdguardTeam/golibs/errors"
2425
"github.com/AdguardTeam/golibs/logutil/slogutil"
2526
"github.com/AdguardTeam/golibs/netutil"
@@ -112,6 +113,9 @@ type Proxy struct {
112113
// requests for private addresses.
113114
recDetector *recursionDetector
114115

116+
// reqCtx is a constructor for the request contexts. It is never nil.
117+
reqCtx contextutil.Constructor
118+
115119
// pendingRequests is a storage for duplicated requests. It is used to
116120
// prevent sending the same request to upstreams multiple times.
117121
pendingRequests pendingRequests
@@ -215,6 +219,10 @@ func New(c *Config) (p *Proxy, err error) {
215219
c.PrivateSubnets,
216220
netutil.SubnetSetFunc(netutil.IsLocallyServed),
217221
),
222+
reqCtx: cmp.Or[contextutil.Constructor](
223+
c.RequestContext,
224+
contextutil.EmptyConstructor{},
225+
),
218226
requestHandler: cmp.Or[Handler](c.RequestHandler, DefaultHandler{}),
219227
upstreamRTTStats: map[string]upstreamRTTStats{},
220228
rttLock: sync.Mutex{},
@@ -338,7 +346,9 @@ func (p *Proxy) Start(ctx context.Context) (err error) {
338346
return fmt.Errorf("configuring listeners: %w", errors.WithDeferred(err, closeErr))
339347
}
340348

341-
p.serveListeners()
349+
// Use context without cancel to prevent listeners' context from being
350+
// canceled.
351+
p.serveListeners(context.WithoutCancel(ctx))
342352

343353
p.started = true
344354

@@ -675,12 +685,8 @@ func addDO(msg *dns.Msg) {
675685
const defaultUDPBufSize = 2048
676686

677687
// Resolve is the default resolving method used by the DNS proxy to query
678-
// upstream servers. It expects dctx is filled with the request, the client's
679-
//
680-
// TODO(e.burkov): Add [context.Context].
681-
func (p *Proxy) Resolve(dctx *DNSContext) (err error) {
682-
ctx := context.Background()
683-
688+
// upstream servers. It expects dctx is filled with the client's request.
689+
func (p *Proxy) Resolve(ctx context.Context, dctx *DNSContext) (err error) {
684690
if p.EnableEDNSClientSubnet {
685691
dctx.processECS(p.EDNSAddr, p.logger)
686692
}

0 commit comments

Comments
 (0)