diff --git a/dnscrypt-proxy/config.go b/dnscrypt-proxy/config.go index 7f6bafa1..6d7aac8e 100644 --- a/dnscrypt-proxy/config.go +++ b/dnscrypt-proxy/config.go @@ -631,7 +631,7 @@ func ConfigLoad(proxy *Proxy, flags *ConfigFlags) error { proxy.anonDirectCertFallback = config.AnonymizedDNS.DirectCertFallback if len(config.TLSKeyLogFile) > 0 { - f, err := os.OpenFile(config.TLSKeyLogFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0600) + f, err := os.OpenFile(config.TLSKeyLogFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0o600) if err != nil { dlog.Fatalf("Unable to create key log file [%s]: [%s]", config.TLSKeyLogFile, err) } @@ -892,8 +892,8 @@ func (config *Config) loadSource(proxy *Proxy, cfgSourceName string, cfgSource * if cfgSource.FormatStr == "" { cfgSource.FormatStr = "v2" } - if cfgSource.RefreshDelay <= 0 { - cfgSource.RefreshDelay = 72 + if cfgSource.RefreshDelay < 24 { + cfgSource.RefreshDelay = 24 } else if cfgSource.RefreshDelay > 168 { cfgSource.RefreshDelay = 168 } diff --git a/dnscrypt-proxy/example-dnscrypt-proxy.toml b/dnscrypt-proxy/example-dnscrypt-proxy.toml index 24be6d2d..89528c73 100644 --- a/dnscrypt-proxy/example-dnscrypt-proxy.toml +++ b/dnscrypt-proxy/example-dnscrypt-proxy.toml @@ -696,9 +696,9 @@ format = 'tsv' ## If the `urls` property is missing, cache files and valid signatures ## must already be present. This doesn't prevent these cache files from ## expiring after `refresh_delay` hours. -## Cache freshness is checked every 24 hours, so values for 'refresh_delay' -## of less than 24 hours will have no effect. -## A maximum delay of 168 hours (1 week) is imposed to ensure cache freshness. +## `refreshed_delay` must be in the [24..168] interval. +## The minimum delay of 24 hours (1 day) avoids unnecessary requests to servers. +## The maximum delay of 168 hours (1 week) ensures cache freshness. [sources] diff --git a/dnscrypt-proxy/sources.go b/dnscrypt-proxy/sources.go index 0b7a8263..bc3eeb8e 100644 --- a/dnscrypt-proxy/sources.go +++ b/dnscrypt-proxy/sources.go @@ -23,21 +23,18 @@ const ( SourceFormatV2 = iota ) -const ( - DefaultPrefetchDelay time.Duration = 24 * time.Hour - MinimumPrefetchInterval time.Duration = 10 * time.Minute -) +const MinimumPrefetchInterval time.Duration = 10 * time.Minute type Source struct { - name string - urls []*url.URL - bin []byte // copy of the file content - there's something wrong in our logic, we shouldn't need to keep that in memory - minisignKey *minisign.PublicKey - cacheFile string - prefix string - cacheTTL, prefetchDelay time.Duration - refresh time.Time - format SourceFormat + name string + urls []*url.URL + bin []byte // copy of the file content - there's something wrong in our logic, we shouldn't need to keep that in memory + minisignKey *minisign.PublicKey + cacheFile string + prefix string + cacheTTL time.Duration + refresh time.Time + format SourceFormat } func (source *Source) checkSignature(bin, sig []byte) (err error) { @@ -68,8 +65,8 @@ func (source *Source) fetchFromCache(now time.Time) (remaining time.Duration, er return } if elapsed := now.Sub(fi.ModTime()); elapsed < source.cacheTTL { - remaining = source.prefetchDelay - elapsed - dlog.Debugf("Source [%s] cache file [%s] is still fresh, next update: %v min", source.name, source.cacheFile, math.Round(remaining.Minutes())) + remaining = source.cacheTTL - elapsed + dlog.Debugf("Source [%s] cache file [%s] is still fresh, next update in %v min", source.name, source.cacheFile, math.Round(remaining.Minutes())) } else { dlog.Debugf("Source [%s] cache file [%s] needs to be refreshed", source.name, source.cacheFile) } @@ -174,7 +171,7 @@ func (source *Source) fetchWithCache(xTransport *XTransport, now time.Time) (tim return MinimumPrefetchInterval, err } source.updateCache(bin, sig, now) - remaining = source.prefetchDelay + remaining = source.cacheTTL source.refresh = now.Add(remaining) return remaining, nil } @@ -190,16 +187,12 @@ func NewSource( refreshDelay time.Duration, prefix string, ) (source *Source, err error) { - if refreshDelay < DefaultPrefetchDelay { - refreshDelay = DefaultPrefetchDelay - } source = &Source{ - name: name, - urls: []*url.URL{}, - cacheFile: cacheFile, - cacheTTL: refreshDelay, - prefetchDelay: DefaultPrefetchDelay, - prefix: prefix, + name: name, + urls: []*url.URL{}, + cacheFile: cacheFile, + cacheTTL: refreshDelay, + prefix: prefix, } if formatStr == "v2" { source.format = SourceFormatV2 diff --git a/dnscrypt-proxy/sources_test.go b/dnscrypt-proxy/sources_test.go index 04a6eac7..c87c415f 100644 --- a/dnscrypt-proxy/sources_test.go +++ b/dnscrypt-proxy/sources_test.go @@ -42,6 +42,8 @@ const ( TestStatePathErr // unparseable path to files (download only) ) +const DefaultPrefetchDelay time.Duration = 24 * time.Hour + type SourceTestData struct { n int // subtest counter xTransport *XTransport @@ -350,7 +352,7 @@ func prepSourceTestDownload( } if e.success { e.err = "" - e.delay = DefaultPrefetchDelay + e.delay = e.Source.cacheTTL } else { e.delay = MinimumPrefetchInterval } @@ -371,7 +373,7 @@ func setupSourceTestCase(t *testing.T, d *SourceTestData, i int, } e.Source = &Source{ name: id, urls: []*url.URL{}, format: SourceFormatV2, minisignKey: d.key, - cacheFile: e.cachePath, cacheTTL: DefaultPrefetchDelay * 3, prefetchDelay: DefaultPrefetchDelay, + cacheFile: e.cachePath, cacheTTL: DefaultPrefetchDelay * 3, } if cacheTest != nil { prepSourceTestCache(t, d, e, d.sources[i], *cacheTest) @@ -405,9 +407,9 @@ func TestNewSource(t *testing.T) { refreshDelay time.Duration e *SourceTestExpect }{ - {"", "", 0, &SourceTestExpect{err: " ", Source: &Source{name: "short refresh delay", urls: []*url.URL{}, cacheTTL: DefaultPrefetchDelay, prefetchDelay: DefaultPrefetchDelay, prefix: ""}}}, - {"v1", d.keyStr, DefaultPrefetchDelay * 2, &SourceTestExpect{err: "Unsupported source format", Source: &Source{name: "old format", urls: []*url.URL{}, cacheTTL: DefaultPrefetchDelay * 2, prefetchDelay: DefaultPrefetchDelay}}}, - {"v2", "", DefaultPrefetchDelay * 3, &SourceTestExpect{err: "Invalid encoded public key", Source: &Source{name: "invalid public key", urls: []*url.URL{}, cacheTTL: DefaultPrefetchDelay * 3, prefetchDelay: DefaultPrefetchDelay}}}, + {"", "", 0, &SourceTestExpect{err: " ", Source: &Source{name: "short refresh delay", urls: []*url.URL{}, cacheTTL: DefaultPrefetchDelay, prefix: ""}}}, + {"v1", d.keyStr, DefaultPrefetchDelay * 2, &SourceTestExpect{err: "Unsupported source format", Source: &Source{name: "old format", urls: []*url.URL{}, cacheTTL: DefaultPrefetchDelay * 2}}}, + {"v2", "", DefaultPrefetchDelay * 3, &SourceTestExpect{err: "Invalid encoded public key", Source: &Source{name: "invalid public key", urls: []*url.URL{}, cacheTTL: DefaultPrefetchDelay * 3}}}, } { t.Run(tt.e.Source.name, func(t *testing.T) { got, err := NewSource( @@ -478,6 +480,7 @@ func TestPrefetchSources(t *testing.T) { s := &Source{} *s = *e.Source s.bin = nil + s.refresh = d.timeNow sources = append(sources, s) expects = append(expects, e) }