mirror of
https://git.vectorsigma.ru/public/AdGuardHome.git
synced 2026-07-29 07:39:12 +00:00
Merge in DNS/adguard-home from AGDNS-3007-fix-ups-logger to master
Squashed commit of the following:
commit 7b198ab6f075ec0be9ab638925d65dcf16c3aa67
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date: Wed Jul 9 09:54:15 2025 +0400
dnsforward: fix merge
commit dd0a680bd1b995bbe570861723f85244855de2ce
Merge: 081526039 63c64b10e
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date: Wed Jul 9 09:43:22 2025 +0400
Merge remote-tracking branch 'origin/master' into AGDNS-3007-fix-ups-logger
commit 081526039fb7841ca2ca94f3effe339bfb01d295
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date: Mon Jul 7 17:53:37 2025 +0400
all: imp code
commit 88b5398c8b2dce1b942ed239d488fc9dc2d342ab
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date: Thu Jul 3 09:59:28 2025 +0400
all: imp code
commit c9440af9a5a21f16d126b0d494a21537fda0d339
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date: Thu Jul 3 09:51:44 2025 +0400
all: imp code
commit 4aff2860eda8f5050bc0450f6c7027b1da451ab8
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date: Wed Jul 2 13:41:00 2025 +0400
all: upstream dnsproxy prefix
commit 4cbc65608ec9431b6e4380a5e931cf3300b18fd0
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date: Wed Jul 2 13:37:45 2025 +0400
aghslog: add dnsproxy prefix
commit fdc1ed02c380e6687fafbac973f74f461974d1d2
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date: Wed Jul 2 13:33:10 2025 +0400
client: imp upstream log
commit 19438ba7e8497dc7753180d60202afa620b22df9
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date: Wed Jul 2 13:30:10 2025 +0400
all: aghslog consts
commit ee5e3875c7af342412b03240cbc8c0699f431de4
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date: Wed Jul 2 13:26:42 2025 +0400
dnsforward: imp tests
commit 8b8c608032658897742df38910d7f5370a26adaa
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date: Tue Jul 1 14:04:59 2025 +0400
client: fix upd conf logger
commit 98227476a21fc305e9ecf62be60f1af992bac36f
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date: Tue Jul 1 13:26:09 2025 +0400
next: dnssvc: use aghslog constants
commit b331ba921cac60cdd7dac6a169c7e071acba5b2b
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date: Tue Jul 1 13:23:33 2025 +0400
all: fix upd conf logger
242 lines
7.3 KiB
Go
242 lines
7.3 KiB
Go
package client
|
|
|
|
import (
|
|
"fmt"
|
|
"log/slog"
|
|
"slices"
|
|
"time"
|
|
|
|
"github.com/AdguardTeam/AdGuardHome/internal/aghnet"
|
|
"github.com/AdguardTeam/AdGuardHome/internal/aghslog"
|
|
"github.com/AdguardTeam/dnsproxy/proxy"
|
|
"github.com/AdguardTeam/dnsproxy/upstream"
|
|
"github.com/AdguardTeam/golibs/errors"
|
|
"github.com/AdguardTeam/golibs/logutil/slogutil"
|
|
"github.com/AdguardTeam/golibs/stringutil"
|
|
"github.com/AdguardTeam/golibs/timeutil"
|
|
)
|
|
|
|
// CommonUpstreamConfig contains common settings for custom client upstream
|
|
// configurations.
|
|
type CommonUpstreamConfig struct {
|
|
Bootstrap upstream.Resolver
|
|
UpstreamTimeout time.Duration
|
|
BootstrapPreferIPv6 bool
|
|
EDNSClientSubnetEnabled bool
|
|
UseHTTP3Upstreams bool
|
|
}
|
|
|
|
// customUpstreamConfig contains custom client upstream configuration and the
|
|
// timestamp of the latest configuration update.
|
|
type customUpstreamConfig struct {
|
|
// proxyConf is the constructed upstream configuration for the [proxy],
|
|
// derived from the fields below. It is initialized on demand with
|
|
// [newCustomUpstreamConfig].
|
|
proxyConf *proxy.CustomUpstreamConfig
|
|
|
|
// commonConfUpdate is the timestamp of the latest configuration update,
|
|
// used to check against [upstreamManager.confUpdate] to determine if the
|
|
// configuration is up to date.
|
|
commonConfUpdate time.Time
|
|
|
|
// upstreams is the cached list of custom upstream DNS servers used for the
|
|
// configuration of proxyConf.
|
|
upstreams []string
|
|
|
|
// upstreamsCacheSize is the cached value of the cache size of the
|
|
// upstreams, used for the configuration of proxyConf.
|
|
upstreamsCacheSize uint32
|
|
|
|
// upstreamsCacheEnabled is the cached value indicating whether the cache of
|
|
// the upstreams is enabled for the configuration of proxyConf.
|
|
upstreamsCacheEnabled bool
|
|
|
|
// isChanged indicates whether the proxyConf needs to be updated.
|
|
isChanged bool
|
|
}
|
|
|
|
// upstreamManager stores and updates custom client upstream configurations.
|
|
type upstreamManager struct {
|
|
// baseLogger is used to create loggers for client upstream configurations.
|
|
// It should not have a prefix and must not be nil.
|
|
baseLogger *slog.Logger
|
|
|
|
// logger is used for logging the operation of the upstream manager. It
|
|
// must not be nil.
|
|
logger *slog.Logger
|
|
|
|
// uidToCustomConf maps persistent client UID to the custom client upstream
|
|
// configuration. Stored UIDs must be in sync with the [index.uidToClient].
|
|
uidToCustomConf map[UID]*customUpstreamConfig
|
|
|
|
// commonConf is the common upstream configuration.
|
|
commonConf *CommonUpstreamConfig
|
|
|
|
// clock is used to get the current time. It must not be nil.
|
|
clock timeutil.Clock
|
|
|
|
// confUpdate is the timestamp of the latest common upstream configuration
|
|
// update.
|
|
confUpdate time.Time
|
|
}
|
|
|
|
// newUpstreamManager returns the new properly initialized upstream manager.
|
|
func newUpstreamManager(baseLogger *slog.Logger, clock timeutil.Clock) (m *upstreamManager) {
|
|
return &upstreamManager{
|
|
baseLogger: baseLogger,
|
|
logger: baseLogger.With(slogutil.KeyPrefix, "upstream_manager"),
|
|
uidToCustomConf: make(map[UID]*customUpstreamConfig),
|
|
clock: clock,
|
|
}
|
|
}
|
|
|
|
// updateCommonUpstreamConfig updates the common upstream configuration and the
|
|
// timestamp of the latest configuration update.
|
|
func (m *upstreamManager) updateCommonUpstreamConfig(conf *CommonUpstreamConfig) {
|
|
m.commonConf = conf
|
|
m.confUpdate = m.clock.Now()
|
|
}
|
|
|
|
// updateCustomUpstreamConfig updates the stored custom client upstream
|
|
// configuration associated with the persistent client. It also sets
|
|
// [customUpstreamConfig.isChanged] to true so [customUpstreamConfig.proxyConf]
|
|
// can be updated later in [upstreamManager.customUpstreamConfig].
|
|
func (m *upstreamManager) updateCustomUpstreamConfig(c *Persistent) {
|
|
cliConf, ok := m.uidToCustomConf[c.UID]
|
|
if !ok {
|
|
cliConf = &customUpstreamConfig{
|
|
commonConfUpdate: m.confUpdate,
|
|
}
|
|
|
|
m.uidToCustomConf[c.UID] = cliConf
|
|
}
|
|
|
|
// TODO(s.chzhen): Compare before cloning.
|
|
cliConf.upstreams = slices.Clone(c.Upstreams)
|
|
cliConf.upstreamsCacheSize = c.UpstreamsCacheSize
|
|
cliConf.upstreamsCacheEnabled = c.UpstreamsCacheEnabled
|
|
cliConf.isChanged = true
|
|
}
|
|
|
|
// customUpstreamConfig returns the custom client upstream configuration.
|
|
func (m *upstreamManager) customUpstreamConfig(
|
|
uid UID,
|
|
clientName string,
|
|
) (proxyConf *proxy.CustomUpstreamConfig) {
|
|
cliConf, ok := m.uidToCustomConf[uid]
|
|
if !ok {
|
|
// TODO(s.chzhen): Consider panic.
|
|
m.logger.Error("no associated custom client upstream config")
|
|
|
|
return nil
|
|
}
|
|
|
|
if !m.isConfigChanged(cliConf) {
|
|
return cliConf.proxyConf
|
|
}
|
|
|
|
if cliConf.proxyConf != nil {
|
|
err := cliConf.proxyConf.Close()
|
|
if err != nil {
|
|
// TODO(s.chzhen): Pass context.
|
|
m.logger.Debug("closing custom upstream config", slogutil.KeyError, err)
|
|
}
|
|
}
|
|
|
|
cliLogger := aghslog.NewForUpstream(m.baseLogger, aghslog.UpstreamTypeCustom).With(
|
|
aghslog.KeyClientName,
|
|
clientName,
|
|
)
|
|
proxyConf = newCustomUpstreamConfig(cliConf, m.commonConf, cliLogger)
|
|
cliConf.proxyConf = proxyConf
|
|
cliConf.commonConfUpdate = m.confUpdate
|
|
cliConf.isChanged = false
|
|
|
|
return proxyConf
|
|
}
|
|
|
|
// isConfigChanged returns true if the update is necessary for the custom client
|
|
// upstream configuration.
|
|
func (m *upstreamManager) isConfigChanged(cliConf *customUpstreamConfig) (ok bool) {
|
|
return !m.confUpdate.Equal(cliConf.commonConfUpdate) || cliConf.isChanged
|
|
}
|
|
|
|
// clearUpstreamCache clears the upstream cache for each stored custom client
|
|
// upstream configuration.
|
|
func (m *upstreamManager) clearUpstreamCache() {
|
|
for _, c := range m.uidToCustomConf {
|
|
if c.proxyConf != nil {
|
|
c.proxyConf.ClearCache()
|
|
}
|
|
}
|
|
}
|
|
|
|
// remove deletes the custom client upstream configuration and closes
|
|
// [customUpstreamConfig.proxyConf] if necessary.
|
|
func (m *upstreamManager) remove(uid UID) (err error) {
|
|
cliConf, ok := m.uidToCustomConf[uid]
|
|
if !ok {
|
|
// TODO(s.chzhen): Consider panic.
|
|
return errors.Error("no associated custom client upstream config")
|
|
}
|
|
|
|
delete(m.uidToCustomConf, uid)
|
|
|
|
if cliConf.proxyConf != nil {
|
|
return cliConf.proxyConf.Close()
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// close shuts down each stored custom client upstream configuration.
|
|
func (m *upstreamManager) close() (err error) {
|
|
var errs []error
|
|
for _, c := range m.uidToCustomConf {
|
|
if c.proxyConf == nil {
|
|
continue
|
|
}
|
|
|
|
errs = append(errs, c.proxyConf.Close())
|
|
}
|
|
|
|
return errors.Join(errs...)
|
|
}
|
|
|
|
// newCustomUpstreamConfig returns the new properly initialized custom proxy
|
|
// upstream configuration for the client. cliConf, conf, and cliLogger must not
|
|
// be nil.
|
|
func newCustomUpstreamConfig(
|
|
cliConf *customUpstreamConfig,
|
|
conf *CommonUpstreamConfig,
|
|
cliLogger *slog.Logger,
|
|
) (proxyConf *proxy.CustomUpstreamConfig) {
|
|
upstreams := stringutil.FilterOut(cliConf.upstreams, aghnet.IsCommentOrEmpty)
|
|
if len(upstreams) == 0 {
|
|
return nil
|
|
}
|
|
|
|
upsConf, err := proxy.ParseUpstreamsConfig(
|
|
upstreams,
|
|
&upstream.Options{
|
|
Logger: cliLogger,
|
|
Bootstrap: conf.Bootstrap,
|
|
Timeout: conf.UpstreamTimeout,
|
|
HTTPVersions: aghnet.UpstreamHTTPVersions(conf.UseHTTP3Upstreams),
|
|
PreferIPv6: conf.BootstrapPreferIPv6,
|
|
},
|
|
)
|
|
if err != nil {
|
|
// Should not happen because upstreams are already validated. See
|
|
// [Persistent.validate].
|
|
panic(fmt.Errorf("creating custom upstream config: %w", err))
|
|
}
|
|
|
|
return proxy.NewCustomUpstreamConfig(
|
|
upsConf,
|
|
cliConf.upstreamsCacheEnabled,
|
|
int(cliConf.upstreamsCacheSize),
|
|
conf.EDNSClientSubnetEnabled,
|
|
)
|
|
}
|