all: sync with master; upd chlog
This commit is contained in:
@@ -67,15 +67,18 @@ func (c *Client) closeUpstreams() (err error) {
|
||||
|
||||
type clientSource uint
|
||||
|
||||
// Client sources. The order determines the priority.
|
||||
// Clients information sources. The order determines the priority.
|
||||
const (
|
||||
ClientSourceWHOIS clientSource = iota
|
||||
ClientSourceNone clientSource = iota
|
||||
ClientSourceWHOIS
|
||||
ClientSourceARP
|
||||
ClientSourceRDNS
|
||||
ClientSourceDHCP
|
||||
ClientSourceHostsFile
|
||||
ClientSourcePersistent
|
||||
)
|
||||
|
||||
// type check
|
||||
var _ fmt.Stringer = clientSource(0)
|
||||
|
||||
// String returns a human-readable name of cs.
|
||||
@@ -96,6 +99,7 @@ func (cs clientSource) String() (s string) {
|
||||
}
|
||||
}
|
||||
|
||||
// type check
|
||||
var _ encoding.TextMarshaler = clientSource(0)
|
||||
|
||||
// MarshalText implements encoding.TextMarshaler for the clientSource.
|
||||
@@ -332,23 +336,24 @@ func (clients *clientsContainer) onDHCPLeaseChanged(flags int) {
|
||||
}
|
||||
}
|
||||
|
||||
// exists checks if client with this IP address already exists.
|
||||
func (clients *clientsContainer) exists(ip netip.Addr, source clientSource) (ok bool) {
|
||||
// clientSource checks if client with this IP address already exists and returns
|
||||
// the source which updated it last. It returns [ClientSourceNone] if the
|
||||
// client doesn't exist.
|
||||
func (clients *clientsContainer) clientSource(ip netip.Addr) (src clientSource) {
|
||||
clients.lock.Lock()
|
||||
defer clients.lock.Unlock()
|
||||
|
||||
_, ok = clients.findLocked(ip.String())
|
||||
_, ok := clients.findLocked(ip.String())
|
||||
if ok {
|
||||
return true
|
||||
return ClientSourcePersistent
|
||||
}
|
||||
|
||||
rc, ok := clients.ipToRC[ip]
|
||||
if !ok {
|
||||
return false
|
||||
return ClientSourceNone
|
||||
}
|
||||
|
||||
// Return false if the new source has higher priority.
|
||||
return source <= rc.Source
|
||||
return rc.Source
|
||||
}
|
||||
|
||||
func toQueryLogWHOIS(wi *RuntimeClientWHOISInfo) (cw *querylog.ClientWHOIS) {
|
||||
|
||||
@@ -67,9 +67,9 @@ func TestClients(t *testing.T) {
|
||||
|
||||
assert.Equal(t, "client2", c.Name)
|
||||
|
||||
assert.False(t, clients.exists(cliNoneIP, ClientSourceHostsFile))
|
||||
assert.True(t, clients.exists(cli1IP, ClientSourceHostsFile))
|
||||
assert.True(t, clients.exists(cli2IP, ClientSourceHostsFile))
|
||||
assert.Equal(t, clients.clientSource(cliNoneIP), ClientSourceNone)
|
||||
assert.Equal(t, clients.clientSource(cli1IP), ClientSourcePersistent)
|
||||
assert.Equal(t, clients.clientSource(cli2IP), ClientSourcePersistent)
|
||||
})
|
||||
|
||||
t.Run("add_fail_name", func(t *testing.T) {
|
||||
@@ -127,8 +127,8 @@ func TestClients(t *testing.T) {
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.False(t, clients.exists(cliOldIP, ClientSourceHostsFile))
|
||||
assert.True(t, clients.exists(cliNewIP, ClientSourceHostsFile))
|
||||
assert.Equal(t, clients.clientSource(cliOldIP), ClientSourceNone)
|
||||
assert.Equal(t, clients.clientSource(cliNewIP), ClientSourcePersistent)
|
||||
|
||||
err = clients.Update("client1", &Client{
|
||||
IDs: []string{cliNew},
|
||||
@@ -157,7 +157,7 @@ func TestClients(t *testing.T) {
|
||||
ok := clients.Del("client1-renamed")
|
||||
require.True(t, ok)
|
||||
|
||||
assert.False(t, clients.exists(netip.MustParseAddr("1.1.1.2"), ClientSourceHostsFile))
|
||||
assert.Equal(t, clients.clientSource(netip.MustParseAddr("1.1.1.2")), ClientSourceNone)
|
||||
})
|
||||
|
||||
t.Run("del_fail", func(t *testing.T) {
|
||||
@@ -176,18 +176,18 @@ func TestClients(t *testing.T) {
|
||||
ok = clients.AddHost(ip, "host3", ClientSourceHostsFile)
|
||||
assert.True(t, ok)
|
||||
|
||||
assert.True(t, clients.exists(ip, ClientSourceHostsFile))
|
||||
assert.Equal(t, clients.clientSource(ip), ClientSourceHostsFile)
|
||||
})
|
||||
|
||||
t.Run("dhcp_replaces_arp", func(t *testing.T) {
|
||||
ip := netip.MustParseAddr("1.2.3.4")
|
||||
ok := clients.AddHost(ip, "from_arp", ClientSourceARP)
|
||||
assert.True(t, ok)
|
||||
assert.True(t, clients.exists(ip, ClientSourceARP))
|
||||
assert.Equal(t, clients.clientSource(ip), ClientSourceARP)
|
||||
|
||||
ok = clients.AddHost(ip, "from_dhcp", ClientSourceDHCP)
|
||||
assert.True(t, ok)
|
||||
assert.True(t, clients.exists(ip, ClientSourceDHCP))
|
||||
assert.Equal(t, clients.clientSource(ip), ClientSourceDHCP)
|
||||
})
|
||||
|
||||
t.Run("addhost_fail", func(t *testing.T) {
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"net/netip"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"sync"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/aghalg"
|
||||
@@ -112,8 +113,10 @@ type configuration struct {
|
||||
// An active session is automatically refreshed once a day.
|
||||
WebSessionTTLHours uint32 `yaml:"web_session_ttl"`
|
||||
|
||||
DNS dnsConfig `yaml:"dns"`
|
||||
TLS tlsConfigSettings `yaml:"tls"`
|
||||
DNS dnsConfig `yaml:"dns"`
|
||||
TLS tlsConfigSettings `yaml:"tls"`
|
||||
QueryLog queryLogConfig `yaml:"querylog"`
|
||||
Stats statsConfig `yaml:"statistics"`
|
||||
|
||||
// Filters reflects the filters from [filtering.Config]. It's cloned to the
|
||||
// config used in the filtering module at the startup. Afterwards it's
|
||||
@@ -147,20 +150,6 @@ type dnsConfig struct {
|
||||
BindHosts []netip.Addr `yaml:"bind_hosts"`
|
||||
Port int `yaml:"port"`
|
||||
|
||||
// StatsInterval is the time interval for flushing statistics to the disk in
|
||||
// days.
|
||||
StatsInterval uint32 `yaml:"statistics_interval"`
|
||||
|
||||
// QueryLogEnabled defines if the query log is enabled.
|
||||
QueryLogEnabled bool `yaml:"querylog_enabled"`
|
||||
// QueryLogFileEnabled defines, if the query log is written to the file.
|
||||
QueryLogFileEnabled bool `yaml:"querylog_file_enabled"`
|
||||
// QueryLogInterval is the interval for query log's files rotation.
|
||||
QueryLogInterval timeutil.Duration `yaml:"querylog_interval"`
|
||||
// QueryLogMemSize is the number of entries kept in memory before they are
|
||||
// flushed to disk.
|
||||
QueryLogMemSize uint32 `yaml:"querylog_size_memory"`
|
||||
|
||||
// AnonymizeClientIP defines if clients' IP addresses should be anonymized
|
||||
// in query log and statistics.
|
||||
AnonymizeClientIP bool `yaml:"anonymize_client_ip"`
|
||||
@@ -188,7 +177,7 @@ type dnsConfig struct {
|
||||
UseDNS64 bool `yaml:"use_dns64"`
|
||||
|
||||
// DNS64Prefixes is the list of NAT64 prefixes to be used for DNS64.
|
||||
DNS64Prefixes []string `yaml:"dns64_prefixes"`
|
||||
DNS64Prefixes []netip.Prefix `yaml:"dns64_prefixes"`
|
||||
|
||||
// ServeHTTP3 defines if HTTP/3 is be allowed for incoming requests.
|
||||
//
|
||||
@@ -228,6 +217,37 @@ type tlsConfigSettings struct {
|
||||
dnsforward.TLSConfig `yaml:",inline" json:",inline"`
|
||||
}
|
||||
|
||||
type queryLogConfig struct {
|
||||
// Enabled defines if the query log is enabled.
|
||||
Enabled bool `yaml:"enabled"`
|
||||
|
||||
// FileEnabled defines, if the query log is written to the file.
|
||||
FileEnabled bool `yaml:"file_enabled"`
|
||||
|
||||
// Interval is the interval for query log's files rotation.
|
||||
Interval timeutil.Duration `yaml:"interval"`
|
||||
|
||||
// MemSize is the number of entries kept in memory before they are
|
||||
// flushed to disk.
|
||||
MemSize uint32 `yaml:"size_memory"`
|
||||
|
||||
// Ignored is the list of host names, which should not be written to
|
||||
// log.
|
||||
Ignored []string `yaml:"ignored"`
|
||||
}
|
||||
|
||||
type statsConfig struct {
|
||||
// Enabled defines if the statistics are enabled.
|
||||
Enabled bool `yaml:"enabled"`
|
||||
|
||||
// Interval is the time interval for flushing statistics to the disk in
|
||||
// days.
|
||||
Interval uint32 `yaml:"interval"`
|
||||
|
||||
// Ignored is the list of host names, which should not be counted.
|
||||
Ignored []string `yaml:"ignored"`
|
||||
}
|
||||
|
||||
// config is the global configuration structure.
|
||||
//
|
||||
// TODO(a.garipov, e.burkov): This global is awful and must be removed.
|
||||
@@ -238,13 +258,8 @@ var config = &configuration{
|
||||
AuthBlockMin: 15,
|
||||
WebSessionTTLHours: 30 * 24,
|
||||
DNS: dnsConfig{
|
||||
BindHosts: []netip.Addr{netip.IPv4Unspecified()},
|
||||
Port: defaultPortDNS,
|
||||
StatsInterval: 1,
|
||||
QueryLogEnabled: true,
|
||||
QueryLogFileEnabled: true,
|
||||
QueryLogInterval: timeutil.Duration{Duration: 90 * timeutil.Day},
|
||||
QueryLogMemSize: 1000,
|
||||
BindHosts: []netip.Addr{netip.IPv4Unspecified()},
|
||||
Port: defaultPortDNS,
|
||||
FilteringConfig: dnsforward.FilteringConfig{
|
||||
ProtectionEnabled: true, // whether or not use any of filtering features
|
||||
BlockingMode: dnsforward.BlockingModeDefault,
|
||||
@@ -282,6 +297,18 @@ var config = &configuration{
|
||||
PortDNSOverTLS: defaultPortTLS, // needs to be passed through to dnsproxy
|
||||
PortDNSOverQUIC: defaultPortQUIC,
|
||||
},
|
||||
QueryLog: queryLogConfig{
|
||||
Enabled: true,
|
||||
FileEnabled: true,
|
||||
Interval: timeutil.Duration{Duration: 90 * timeutil.Day},
|
||||
MemSize: 1000,
|
||||
Ignored: []string{},
|
||||
},
|
||||
Stats: statsConfig{
|
||||
Enabled: true,
|
||||
Interval: 1,
|
||||
Ignored: []string{},
|
||||
},
|
||||
// NOTE: Keep these parameters in sync with the one put into
|
||||
// client/src/helpers/filters/filters.js by scripts/vetted-filters.
|
||||
//
|
||||
@@ -458,19 +485,24 @@ func (c *configuration) write() (err error) {
|
||||
}
|
||||
|
||||
if Context.stats != nil {
|
||||
sdc := stats.DiskConfig{}
|
||||
Context.stats.WriteDiskConfig(&sdc)
|
||||
config.DNS.StatsInterval = sdc.Interval
|
||||
statsConf := stats.Config{}
|
||||
Context.stats.WriteDiskConfig(&statsConf)
|
||||
config.Stats.Interval = statsConf.LimitDays
|
||||
config.Stats.Enabled = statsConf.Enabled
|
||||
config.Stats.Ignored = statsConf.Ignored.Values()
|
||||
sort.Strings(config.Stats.Ignored)
|
||||
}
|
||||
|
||||
if Context.queryLog != nil {
|
||||
dc := querylog.Config{}
|
||||
Context.queryLog.WriteDiskConfig(&dc)
|
||||
config.DNS.QueryLogEnabled = dc.Enabled
|
||||
config.DNS.QueryLogFileEnabled = dc.FileEnabled
|
||||
config.DNS.QueryLogInterval = timeutil.Duration{Duration: dc.RotationIvl}
|
||||
config.DNS.QueryLogMemSize = dc.MemSize
|
||||
config.DNS.AnonymizeClientIP = dc.AnonymizeClientIP
|
||||
config.QueryLog.Enabled = dc.Enabled
|
||||
config.QueryLog.FileEnabled = dc.FileEnabled
|
||||
config.QueryLog.Interval = timeutil.Duration{Duration: dc.RotationIvl}
|
||||
config.QueryLog.MemSize = dc.MemSize
|
||||
config.QueryLog.Ignored = dc.Ignored.Values()
|
||||
sort.Strings(config.QueryLog.Ignored)
|
||||
}
|
||||
|
||||
if Context.filters != nil {
|
||||
|
||||
@@ -20,7 +20,7 @@ import (
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/version"
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
"github.com/AdguardTeam/golibs/log"
|
||||
"github.com/lucas-clemente/quic-go/http3"
|
||||
"github.com/quic-go/quic-go/http3"
|
||||
)
|
||||
|
||||
// getAddrsResponse is the response for /install/get_addresses endpoint.
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/aghalg"
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/aghhttp"
|
||||
@@ -20,6 +21,7 @@ import (
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
"github.com/AdguardTeam/golibs/log"
|
||||
"github.com/AdguardTeam/golibs/netutil"
|
||||
"github.com/AdguardTeam/golibs/stringutil"
|
||||
"github.com/ameshkov/dnscrypt/v2"
|
||||
yaml "gopkg.in/yaml.v3"
|
||||
)
|
||||
@@ -51,10 +53,18 @@ func initDNS() (err error) {
|
||||
|
||||
statsConf := stats.Config{
|
||||
Filename: filepath.Join(baseDir, "stats.db"),
|
||||
LimitDays: config.DNS.StatsInterval,
|
||||
LimitDays: config.Stats.Interval,
|
||||
ConfigModified: onConfigModified,
|
||||
HTTPRegister: httpRegister,
|
||||
Enabled: config.Stats.Enabled,
|
||||
}
|
||||
|
||||
set, err := nonDupEmptyHostNames(config.Stats.Ignored)
|
||||
if err != nil {
|
||||
return fmt.Errorf("statistics: ignored list: %w", err)
|
||||
}
|
||||
|
||||
statsConf.Ignored = set
|
||||
Context.stats, err = stats.New(statsConf)
|
||||
if err != nil {
|
||||
return fmt.Errorf("init stats: %w", err)
|
||||
@@ -66,12 +76,19 @@ func initDNS() (err error) {
|
||||
HTTPRegister: httpRegister,
|
||||
FindClient: Context.clients.findMultiple,
|
||||
BaseDir: baseDir,
|
||||
RotationIvl: config.DNS.QueryLogInterval.Duration,
|
||||
MemSize: config.DNS.QueryLogMemSize,
|
||||
Enabled: config.DNS.QueryLogEnabled,
|
||||
FileEnabled: config.DNS.QueryLogFileEnabled,
|
||||
AnonymizeClientIP: config.DNS.AnonymizeClientIP,
|
||||
RotationIvl: config.QueryLog.Interval.Duration,
|
||||
MemSize: config.QueryLog.MemSize,
|
||||
Enabled: config.QueryLog.Enabled,
|
||||
FileEnabled: config.QueryLog.FileEnabled,
|
||||
}
|
||||
|
||||
set, err = nonDupEmptyHostNames(config.QueryLog.Ignored)
|
||||
if err != nil {
|
||||
return fmt.Errorf("querylog: ignored list: %w", err)
|
||||
}
|
||||
|
||||
conf.Ignored = set
|
||||
Context.queryLog = querylog.New(conf)
|
||||
|
||||
Context.filters, err = filtering.New(config.DNS.DnsfilterConf, nil)
|
||||
@@ -515,3 +532,27 @@ func closeDNSServer() {
|
||||
|
||||
log.Debug("all dns modules are closed")
|
||||
}
|
||||
|
||||
// nonDupEmptyHostNames returns nil and error, if list has duplicate or empty
|
||||
// host name. Otherwise returns a set, which contains lowercase host names
|
||||
// without dot at the end, and nil error.
|
||||
func nonDupEmptyHostNames(list []string) (set *stringutil.Set, err error) {
|
||||
set = stringutil.NewSet()
|
||||
|
||||
for _, v := range list {
|
||||
host := strings.ToLower(strings.TrimSuffix(v, "."))
|
||||
// TODO(a.garipov): Think about ignoring empty (".") names in
|
||||
// the future.
|
||||
if host == "" {
|
||||
return nil, errors.Error("host name is empty")
|
||||
}
|
||||
|
||||
if set.Has(host) {
|
||||
return nil, fmt.Errorf("duplicate host name %q", host)
|
||||
}
|
||||
|
||||
set.Add(host)
|
||||
}
|
||||
|
||||
return set, nil
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/dnsforward"
|
||||
"github.com/AdguardTeam/golibs/cache"
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
"github.com/AdguardTeam/golibs/log"
|
||||
)
|
||||
|
||||
@@ -16,10 +17,6 @@ type RDNS struct {
|
||||
exchanger dnsforward.RDNSExchanger
|
||||
clients *clientsContainer
|
||||
|
||||
// usePrivate is used to store the state of current private RDNS resolving
|
||||
// settings and to react to it's changes.
|
||||
usePrivate uint32
|
||||
|
||||
// ipCh used to pass client's IP to rDNS workerLoop.
|
||||
ipCh chan netip.Addr
|
||||
|
||||
@@ -28,13 +25,21 @@ type RDNS struct {
|
||||
// address will be resolved once again. If the address couldn't be
|
||||
// resolved, cache prevents further attempts to resolve it for some time.
|
||||
ipCache cache.Cache
|
||||
|
||||
// usePrivate stores the state of current private reverse-DNS resolving
|
||||
// settings.
|
||||
usePrivate atomic.Bool
|
||||
}
|
||||
|
||||
// Default rDNS values.
|
||||
// Default AdGuard Home reverse DNS values.
|
||||
const (
|
||||
defaultRDNSCacheSize = 10000
|
||||
defaultRDNSCacheTTL = 1 * 60 * 60
|
||||
defaultRDNSIPChSize = 256
|
||||
revDNSCacheSize = 10000
|
||||
|
||||
// TODO(e.burkov): Make these values configurable.
|
||||
revDNSCacheTTL = 24 * 60 * 60
|
||||
revDNSFailureCacheTTL = 1 * 60 * 60
|
||||
|
||||
revDNSQueueSize = 256
|
||||
)
|
||||
|
||||
// NewRDNS creates and returns initialized RDNS.
|
||||
@@ -48,14 +53,13 @@ func NewRDNS(
|
||||
clients: clients,
|
||||
ipCache: cache.New(cache.Config{
|
||||
EnableLRU: true,
|
||||
MaxCount: defaultRDNSCacheSize,
|
||||
MaxCount: revDNSCacheSize,
|
||||
}),
|
||||
ipCh: make(chan netip.Addr, defaultRDNSIPChSize),
|
||||
}
|
||||
if usePrivate {
|
||||
rDNS.usePrivate = 1
|
||||
ipCh: make(chan netip.Addr, revDNSQueueSize),
|
||||
}
|
||||
|
||||
rDNS.usePrivate.Store(usePrivate)
|
||||
|
||||
go rDNS.workerLoop()
|
||||
|
||||
return rDNS
|
||||
@@ -68,12 +72,8 @@ func NewRDNS(
|
||||
// approach since only unresolved locally-served addresses should be removed.
|
||||
// Implement when improving the cache.
|
||||
func (r *RDNS) ensurePrivateCache() {
|
||||
var usePrivate uint32
|
||||
if r.exchanger.ResolvesPrivatePTR() {
|
||||
usePrivate = 1
|
||||
}
|
||||
|
||||
if atomic.CompareAndSwapUint32(&r.usePrivate, 1-usePrivate, usePrivate) {
|
||||
usePrivate := r.exchanger.ResolvesPrivatePTR()
|
||||
if r.usePrivate.CompareAndSwap(!usePrivate, usePrivate) {
|
||||
r.ipCache.Clear()
|
||||
}
|
||||
}
|
||||
@@ -84,25 +84,28 @@ func (r *RDNS) isCached(ip netip.Addr) (ok bool) {
|
||||
ipBytes := ip.AsSlice()
|
||||
now := uint64(time.Now().Unix())
|
||||
if expire := r.ipCache.Get(ipBytes); len(expire) != 0 {
|
||||
if binary.BigEndian.Uint64(expire) > now {
|
||||
return true
|
||||
}
|
||||
return binary.BigEndian.Uint64(expire) > now
|
||||
}
|
||||
|
||||
// The cache entry either expired or doesn't exist.
|
||||
ttl := make([]byte, 8)
|
||||
binary.BigEndian.PutUint64(ttl, now+defaultRDNSCacheTTL)
|
||||
r.ipCache.Set(ipBytes, ttl)
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// cache caches the ip address for ttl seconds.
|
||||
func (r *RDNS) cache(ip netip.Addr, ttl uint64) {
|
||||
ipData := ip.AsSlice()
|
||||
|
||||
ttlData := [8]byte{}
|
||||
binary.BigEndian.PutUint64(ttlData[:], uint64(time.Now().Unix())+ttl)
|
||||
|
||||
r.ipCache.Set(ipData, ttlData[:])
|
||||
}
|
||||
|
||||
// Begin adds the ip to the resolving queue if it is not cached or already
|
||||
// resolved.
|
||||
func (r *RDNS) Begin(ip netip.Addr) {
|
||||
r.ensurePrivateCache()
|
||||
|
||||
if r.isCached(ip) || r.clients.exists(ip, ClientSourceRDNS) {
|
||||
if r.isCached(ip) || r.clients.clientSource(ip) > ClientSourceRDNS {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -120,15 +123,21 @@ func (r *RDNS) workerLoop() {
|
||||
defer log.OnPanic("rdns")
|
||||
|
||||
for ip := range r.ipCh {
|
||||
ttl := uint64(revDNSCacheTTL)
|
||||
|
||||
host, err := r.exchanger.Exchange(ip.AsSlice())
|
||||
if err != nil {
|
||||
log.Debug("rdns: resolving %q: %s", ip, err)
|
||||
|
||||
continue
|
||||
} else if host == "" {
|
||||
continue
|
||||
if errors.Is(err, dnsforward.ErrRDNSFailed) {
|
||||
// Cache failure for a less time.
|
||||
ttl = revDNSFailureCacheTTL
|
||||
}
|
||||
}
|
||||
|
||||
_ = r.clients.AddHost(ip, host, ClientSourceRDNS)
|
||||
r.cache(ip, ttl)
|
||||
|
||||
if host != "" {
|
||||
_ = r.clients.AddHost(ip, host, ClientSourceRDNS)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ func TestRDNS_Begin(t *testing.T) {
|
||||
|
||||
ipCache := cache.New(cache.Config{
|
||||
EnableLRU: true,
|
||||
MaxCount: defaultRDNSCacheSize,
|
||||
MaxCount: revDNSCacheSize,
|
||||
})
|
||||
ttl := make([]byte, binary.Size(uint64(0)))
|
||||
binary.BigEndian.PutUint64(ttl, uint64(time.Now().Add(100*time.Hour).Unix()))
|
||||
@@ -153,7 +153,7 @@ func TestRDNS_ensurePrivateCache(t *testing.T) {
|
||||
|
||||
ipCache := cache.New(cache.Config{
|
||||
EnableLRU: true,
|
||||
MaxCount: defaultRDNSCacheSize,
|
||||
MaxCount: revDNSCacheSize,
|
||||
})
|
||||
|
||||
ex := &rDNSExchanger{
|
||||
@@ -200,25 +200,29 @@ func TestRDNS_WorkerLoop(t *testing.T) {
|
||||
errUpstream := aghtest.NewErrorUpstream()
|
||||
|
||||
testCases := []struct {
|
||||
ups upstream.Upstream
|
||||
cliIP netip.Addr
|
||||
wantLog string
|
||||
name string
|
||||
ups upstream.Upstream
|
||||
cliIP netip.Addr
|
||||
wantLog string
|
||||
name string
|
||||
wantClientSource clientSource
|
||||
}{{
|
||||
ups: locUpstream,
|
||||
cliIP: localIP,
|
||||
wantLog: "",
|
||||
name: "all_good",
|
||||
ups: locUpstream,
|
||||
cliIP: localIP,
|
||||
wantLog: "",
|
||||
name: "all_good",
|
||||
wantClientSource: ClientSourceRDNS,
|
||||
}, {
|
||||
ups: errUpstream,
|
||||
cliIP: netip.MustParseAddr("192.168.1.2"),
|
||||
wantLog: `rdns: resolving "192.168.1.2": test upstream error`,
|
||||
name: "resolve_error",
|
||||
ups: errUpstream,
|
||||
cliIP: netip.MustParseAddr("192.168.1.2"),
|
||||
wantLog: `rdns: resolving "192.168.1.2": test upstream error`,
|
||||
name: "resolve_error",
|
||||
wantClientSource: ClientSourceNone,
|
||||
}, {
|
||||
ups: locUpstream,
|
||||
cliIP: netip.MustParseAddr("2a00:1450:400c:c06::93"),
|
||||
wantLog: "",
|
||||
name: "ipv6_good",
|
||||
ups: locUpstream,
|
||||
cliIP: netip.MustParseAddr("2a00:1450:400c:c06::93"),
|
||||
wantLog: "",
|
||||
name: "ipv6_good",
|
||||
wantClientSource: ClientSourceRDNS,
|
||||
}}
|
||||
|
||||
for _, tc := range testCases {
|
||||
@@ -237,6 +241,10 @@ func TestRDNS_WorkerLoop(t *testing.T) {
|
||||
},
|
||||
clients: cc,
|
||||
ipCh: ch,
|
||||
ipCache: cache.New(cache.Config{
|
||||
EnableLRU: true,
|
||||
MaxCount: revDNSCacheSize,
|
||||
}),
|
||||
}
|
||||
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
@@ -253,11 +261,9 @@ func TestRDNS_WorkerLoop(t *testing.T) {
|
||||
|
||||
if tc.wantLog != "" {
|
||||
assert.Contains(t, w.String(), tc.wantLog)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
assert.True(t, cc.exists(tc.cliIP, ClientSourceRDNS))
|
||||
assert.Equal(t, tc.wantClientSource, cc.clientSource(tc.cliIP))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ import (
|
||||
)
|
||||
|
||||
// currentSchemaVersion is the current schema version.
|
||||
const currentSchemaVersion = 14
|
||||
const currentSchemaVersion = 16
|
||||
|
||||
// These aliases are provided for convenience.
|
||||
type (
|
||||
@@ -87,6 +87,8 @@ func upgradeConfigSchema(oldVersion int, diskConf yobj) (err error) {
|
||||
upgradeSchema11to12,
|
||||
upgradeSchema12to13,
|
||||
upgradeSchema13to14,
|
||||
upgradeSchema14to15,
|
||||
upgradeSchema15to16,
|
||||
}
|
||||
|
||||
n := 0
|
||||
@@ -802,6 +804,107 @@ func upgradeSchema13to14(diskConf yobj) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// upgradeSchema14to15 performs the following changes:
|
||||
//
|
||||
// # BEFORE:
|
||||
// 'dns':
|
||||
// 'querylog_enabled': true
|
||||
// 'querylog_file_enabled': true
|
||||
// 'querylog_interval': '2160h'
|
||||
// 'querylog_size_memory': 1000
|
||||
//
|
||||
// # AFTER:
|
||||
// 'querylog':
|
||||
// 'enabled': true
|
||||
// 'file_enabled': true
|
||||
// 'interval': '2160h'
|
||||
// 'size_memory': 1000
|
||||
// 'ignored': []
|
||||
func upgradeSchema14to15(diskConf yobj) (err error) {
|
||||
log.Printf("Upgrade yaml: 14 to 15")
|
||||
diskConf["schema_version"] = 15
|
||||
|
||||
dnsVal, ok := diskConf["dns"]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
dns, ok := dnsVal.(yobj)
|
||||
if !ok {
|
||||
return fmt.Errorf("unexpected type of dns: %T", dnsVal)
|
||||
}
|
||||
|
||||
type temp struct {
|
||||
from string
|
||||
to string
|
||||
val any
|
||||
}
|
||||
replaces := []temp{
|
||||
{from: "querylog_enabled", to: "enabled", val: true},
|
||||
{from: "querylog_file_enabled", to: "file_enabled", val: true},
|
||||
{from: "querylog_interval", to: "interval", val: "2160h"},
|
||||
{from: "querylog_size_memory", to: "size_memory", val: 1000},
|
||||
}
|
||||
qlog := map[string]any{
|
||||
"ignored": []any{},
|
||||
}
|
||||
for _, r := range replaces {
|
||||
v, has := dns[r.from]
|
||||
if !has {
|
||||
v = r.val
|
||||
}
|
||||
delete(dns, r.from)
|
||||
qlog[r.to] = v
|
||||
}
|
||||
diskConf["querylog"] = qlog
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// upgradeSchema15to16 performs the following changes:
|
||||
//
|
||||
// # BEFORE:
|
||||
// 'dns':
|
||||
// 'statistics_interval': 1
|
||||
//
|
||||
// # AFTER:
|
||||
// 'statistics':
|
||||
// 'enabled': true
|
||||
// 'interval': 1
|
||||
// 'ignored': []
|
||||
func upgradeSchema15to16(diskConf yobj) (err error) {
|
||||
log.Printf("Upgrade yaml: 15 to 16")
|
||||
diskConf["schema_version"] = 16
|
||||
|
||||
dnsVal, ok := diskConf["dns"]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
dns, ok := dnsVal.(yobj)
|
||||
if !ok {
|
||||
return fmt.Errorf("unexpected type of dns: %T", dnsVal)
|
||||
}
|
||||
|
||||
stats := map[string]any{
|
||||
"enabled": true,
|
||||
"interval": 1,
|
||||
"ignored": []any{},
|
||||
}
|
||||
|
||||
k := "statistics_interval"
|
||||
v, has := dns[k]
|
||||
if has {
|
||||
stats["enabled"] = v != 0
|
||||
stats["interval"] = v
|
||||
}
|
||||
delete(dns, k)
|
||||
|
||||
diskConf["statistics"] = stats
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// TODO(a.garipov): Replace with log.Output when we port it to our logging
|
||||
// package.
|
||||
func funcName() string {
|
||||
|
||||
@@ -640,3 +640,110 @@ func TestUpgradeSchema13to14(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpgradeSchema14to15(t *testing.T) {
|
||||
const newSchemaVer = 15
|
||||
|
||||
defaultWantObj := yobj{
|
||||
"querylog": map[string]any{
|
||||
"enabled": true,
|
||||
"file_enabled": true,
|
||||
"interval": "2160h",
|
||||
"size_memory": 1000,
|
||||
"ignored": []any{},
|
||||
},
|
||||
"dns": map[string]any{},
|
||||
"schema_version": newSchemaVer,
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
in yobj
|
||||
want yobj
|
||||
name string
|
||||
}{{
|
||||
in: yobj{
|
||||
"dns": map[string]any{
|
||||
"querylog_enabled": true,
|
||||
"querylog_file_enabled": true,
|
||||
"querylog_interval": "2160h",
|
||||
"querylog_size_memory": 1000,
|
||||
},
|
||||
},
|
||||
want: defaultWantObj,
|
||||
name: "basic",
|
||||
}, {
|
||||
in: yobj{
|
||||
"dns": map[string]any{},
|
||||
},
|
||||
want: defaultWantObj,
|
||||
name: "default_values",
|
||||
}}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
err := upgradeSchema14to15(tc.in)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, tc.want, tc.in)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpgradeSchema15to16(t *testing.T) {
|
||||
const newSchemaVer = 16
|
||||
|
||||
defaultWantObj := yobj{
|
||||
"statistics": map[string]any{
|
||||
"enabled": true,
|
||||
"interval": 1,
|
||||
"ignored": []any{},
|
||||
},
|
||||
"dns": map[string]any{},
|
||||
"schema_version": newSchemaVer,
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
in yobj
|
||||
want yobj
|
||||
name string
|
||||
}{{
|
||||
in: yobj{
|
||||
"dns": map[string]any{
|
||||
"statistics_interval": 1,
|
||||
},
|
||||
},
|
||||
want: defaultWantObj,
|
||||
name: "basic",
|
||||
}, {
|
||||
in: yobj{
|
||||
"dns": map[string]any{},
|
||||
},
|
||||
want: defaultWantObj,
|
||||
name: "default_values",
|
||||
}, {
|
||||
in: yobj{
|
||||
"dns": map[string]any{
|
||||
"statistics_interval": 0,
|
||||
},
|
||||
},
|
||||
want: yobj{
|
||||
"statistics": map[string]any{
|
||||
"enabled": false,
|
||||
"interval": 0,
|
||||
"ignored": []any{},
|
||||
},
|
||||
"dns": map[string]any{},
|
||||
"schema_version": newSchemaVer,
|
||||
},
|
||||
name: "stats_disabled",
|
||||
}}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
err := upgradeSchema15to16(tc.in)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, tc.want, tc.in)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,8 +15,8 @@ import (
|
||||
"github.com/AdguardTeam/golibs/log"
|
||||
"github.com/AdguardTeam/golibs/netutil"
|
||||
"github.com/NYTimes/gziphandler"
|
||||
"github.com/lucas-clemente/quic-go"
|
||||
"github.com/lucas-clemente/quic-go/http3"
|
||||
"github.com/quic-go/quic-go"
|
||||
"github.com/quic-go/quic-go/http3"
|
||||
"golang.org/x/net/http2"
|
||||
"golang.org/x/net/http2/h2c"
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user