Merge pull request #585 from safing/fix/dns-cache-invalidation

Clear DNS cache when DNS resolver config changes and update resolver config
This commit is contained in:
Daniel 2022-04-07 16:19:31 +02:00 committed by GitHub
commit fca92a70f2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 42 additions and 21 deletions

View file

@ -12,7 +12,7 @@ func registerAPI() error {
Path: "dns/clear", Path: "dns/clear",
Write: api.PermitUser, Write: api.PermitUser,
BelongsTo: module, BelongsTo: module,
ActionFunc: clearNameCache, ActionFunc: clearNameCacheHandler,
Name: "Clear cached DNS records", Name: "Clear cached DNS records",
Description: "Deletes all saved DNS records from the database.", Description: "Deletes all saved DNS records from the database.",
}); err != nil { }); err != nil {

View file

@ -31,7 +31,7 @@ var (
// Cloudflare (encrypted DNS, with malware protection) // Cloudflare (encrypted DNS, with malware protection)
`dot://1.1.1.2:853?verify=cloudflare-dns.com&name=Cloudflare&blockedif=zeroip`, `dot://1.1.1.2:853?verify=cloudflare-dns.com&name=Cloudflare&blockedif=zeroip`,
// `dot://1.0.0.2:853?verify=cloudflare-dns.com&name=Cloudflare&blockedif=zeroip`, `dot://1.0.0.2:853?verify=cloudflare-dns.com&name=Cloudflare&blockedif=zeroip`,
// AdGuard (encrypted DNS, default flavor) // AdGuard (encrypted DNS, default flavor)
// `dot://94.140.14.14:853?verify=dns.adguard.com&name=AdGuard&blockedif=zeroip`, // `dot://94.140.14.14:853?verify=dns.adguard.com&name=AdGuard&blockedif=zeroip`,
@ -107,8 +107,9 @@ The format is: "protocol://ip:port?parameter=value&parameter=value"
- "search": specify prioritized domains/TLDs for this resolver (delimited by ",") - "search": specify prioritized domains/TLDs for this resolver (delimited by ",")
- "search-only": use this resolver for domains in the "search" parameter only (no value) - "search-only": use this resolver for domains in the "search" parameter only (no value)
`, `"`, "`"), `, `"`, "`"),
Sensitive: true,
OptType: config.OptTypeStringArray, OptType: config.OptTypeStringArray,
ExpertiseLevel: config.ExpertiseLevelExpert, ExpertiseLevel: config.ExpertiseLevelUser,
ReleaseLevel: config.ReleaseLevelStable, ReleaseLevel: config.ReleaseLevelStable,
DefaultValue: defaultNameServers, DefaultValue: defaultNameServers,
ValidationRegex: fmt.Sprintf("^(%s|%s|%s)://.*", ServerTypeDoT, ServerTypeDNS, ServerTypeTCP), ValidationRegex: fmt.Sprintf("^(%s|%s|%s)://.*", ServerTypeDoT, ServerTypeDNS, ServerTypeTCP),
@ -118,6 +119,14 @@ The format is: "protocol://ip:port?parameter=value&parameter=value"
config.DisplayOrderAnnotation: cfgOptionNameServersOrder, config.DisplayOrderAnnotation: cfgOptionNameServersOrder,
config.CategoryAnnotation: "Servers", config.CategoryAnnotation: "Servers",
config.QuickSettingsAnnotation: []config.QuickSetting{ config.QuickSettingsAnnotation: []config.QuickSetting{
{
Name: "Cloudflare (with Malware Filter)",
Action: config.QuickReplace,
Value: []string{
"dot://1.1.1.2:853?verify=cloudflare-dns.com&name=Cloudflare&blockedif=zeroip",
"dot://1.0.0.2:853?verify=cloudflare-dns.com&name=Cloudflare&blockedif=zeroip",
},
},
{ {
Name: "Quad9", Name: "Quad9",
Action: config.QuickReplace, Action: config.QuickReplace,
@ -142,14 +151,6 @@ The format is: "protocol://ip:port?parameter=value&parameter=value"
"dot://94.130.106.88:443?verify=dot1.applied-privacy.net&name=AppliedPrivacy", "dot://94.130.106.88:443?verify=dot1.applied-privacy.net&name=AppliedPrivacy",
}, },
}, },
{
Name: "Cloudflare (with Malware Filter)",
Action: config.QuickReplace,
Value: []string{
"dot://1.1.1.2:853?verify=cloudflare-dns.com&name=Cloudflare&blockedif=zeroip",
"dot://1.0.0.2:853?verify=cloudflare-dns.com&name=Cloudflare&blockedif=zeroip",
},
},
}, },
"self:detail:internalSpecialUseDomains": internalSpecialUseDomains, "self:detail:internalSpecialUseDomains": internalSpecialUseDomains,
"self:detail:connectivityDomains": netenv.ConnectivityDomains, "self:detail:connectivityDomains": netenv.ConnectivityDomains,

View file

@ -1,6 +1,7 @@
package resolver package resolver
import ( import (
"context"
"errors" "errors"
"fmt" "fmt"
"sync" "sync"
@ -129,13 +130,18 @@ func (nameRecord *NameRecord) Save() error {
return recordDatabase.PutNew(nameRecord) return recordDatabase.PutNew(nameRecord)
} }
// clearNameCache clears all dns caches from the database. // clearNameCacheHandler is an API handler that clears all dns caches from the database.
func clearNameCache(ar *api.Request) (msg string, err error) { func clearNameCacheHandler(ar *api.Request) (msg string, err error) {
log.Info("resolver: user requested dns cache clearing via action") log.Info("resolver: user requested dns cache clearing via action")
return clearNameCache(ar.Context())
}
// clearNameCache clears all dns caches from the database.
func clearNameCache(ctx context.Context) (msg string, err error) {
recordDatabase.FlushCache() recordDatabase.FlushCache()
recordDatabase.ClearCache() recordDatabase.ClearCache()
n, err := recordDatabase.Purge(ar.Context(), query.New(nameRecordsKeyPrefix)) n, err := recordDatabase.Purge(ctx, query.New(nameRecordsKeyPrefix))
if err != nil { if err != nil {
return "", err return "", err
} }

View file

@ -1,6 +1,7 @@
package resolver package resolver
import ( import (
"context"
"fmt" "fmt"
"net" "net"
"net/url" "net/url"
@ -39,6 +40,7 @@ var (
systemResolvers []*Resolver // all resolvers that were assigned by the system systemResolvers []*Resolver // all resolvers that were assigned by the system
localScopes []*Scope // list of scopes with a list of local resolvers that can resolve the scope localScopes []*Scope // list of scopes with a list of local resolvers that can resolve the scope
activeResolvers map[string]*Resolver // lookup map of all resolvers activeResolvers map[string]*Resolver // lookup map of all resolvers
currentResolverConfig []string // current active resolver config, to detect changes
resolversLock sync.RWMutex resolversLock sync.RWMutex
) )
@ -285,8 +287,20 @@ func loadResolvers() {
// Resolve module error about missing resolvers. // Resolve module error about missing resolvers.
module.Resolve(missingResolversErrorID) module.Resolve(missingResolversErrorID)
// Check if settings were changed and clear name cache when they did.
newResolverConfig := configuredNameServers()
if len(currentResolverConfig) > 0 &&
!utils.StringSliceEqual(currentResolverConfig, newResolverConfig) {
module.StartWorker("clear dns cache", func(ctx context.Context) error {
log.Info("resolver: clearing dns cache due to changed resolver config")
_, err := clearNameCache(ctx)
return err
})
}
currentResolverConfig = newResolverConfig
newResolvers := append( newResolvers := append(
getConfiguredResolvers(configuredNameServers()), getConfiguredResolvers(newResolverConfig),
getSystemResolvers()..., getSystemResolvers()...,
) )