mirror of https://github.com/0xERR0R/blocky.git
feat: always prefetch upstream IPs to avoid stalling user queries
Otherwise, a request to blocky could end up waiting for 2 DNS requests: 1. lookup the DNS server IP 2. forward the user request to the server looked-up in 1
This commit is contained in:
parent
7c76836373
commit
63f65002e8
|
@ -616,6 +616,18 @@ type CachingConfig struct {
|
|||
PrefetchMaxItemsCount int `yaml:"prefetchMaxItemsCount"`
|
||||
}
|
||||
|
||||
func (c *CachingConfig) EnablePrefetch() {
|
||||
const day = 24 * time.Hour
|
||||
|
||||
if c.MaxCachingTime == 0 {
|
||||
// make sure resolver gets enabled
|
||||
c.MaxCachingTime = Duration(day)
|
||||
}
|
||||
|
||||
c.Prefetching = true
|
||||
c.PrefetchThreshold = 0
|
||||
}
|
||||
|
||||
// QueryLogConfig configuration for the query logging
|
||||
type QueryLogConfig struct {
|
||||
Target string `yaml:"target"`
|
||||
|
|
|
@ -63,11 +63,23 @@ func NewBootstrap(cfg *config.Config) (b *Bootstrap, err error) {
|
|||
return nil, fmt.Errorf("could not create bootstrap ParallelBestResolver: %w", err)
|
||||
}
|
||||
|
||||
// Always enable prefetching to avoid stalling user requests
|
||||
// Otherwise, a request to blocky could end up waiting for 2 DNS requests:
|
||||
// 1. lookup the DNS server IP
|
||||
// 2. forward the user request to the server looked-up in 1
|
||||
cachingCfg := cfg.Caching
|
||||
cachingCfg.EnablePrefetch()
|
||||
|
||||
if cachingCfg.MinCachingTime == 0 {
|
||||
// Set a min time in case the user didn't to avoid prefetching too often
|
||||
cachingCfg.MinCachingTime = config.Duration(time.Hour)
|
||||
}
|
||||
|
||||
b.bootstraped = bootstraped
|
||||
|
||||
b.resolver = Chain(
|
||||
NewFilteringResolver(cfg.Filtering),
|
||||
NewCachingResolver(cfg.Caching, nil),
|
||||
NewCachingResolver(cachingCfg, nil),
|
||||
parallelResolver,
|
||||
)
|
||||
|
||||
|
|
|
@ -70,10 +70,16 @@ func configureCaches(c *CachingResolver, cfg *config.CachingConfig) {
|
|||
|
||||
c.prefetchThreshold = cfg.PrefetchThreshold
|
||||
|
||||
c.prefetchingNameCache = expirationcache.NewCache(expirationcache.WithCleanUpInterval(time.Minute),
|
||||
expirationcache.WithMaxSize(uint(cfg.PrefetchMaxItemsCount)))
|
||||
c.resultCache = expirationcache.NewCache(cleanupOption, maxSizeOption,
|
||||
expirationcache.WithOnExpiredFn(c.onExpired))
|
||||
c.prefetchingNameCache = expirationcache.NewCache(
|
||||
expirationcache.WithCleanUpInterval(time.Minute),
|
||||
expirationcache.WithMaxSize(uint(cfg.PrefetchMaxItemsCount)),
|
||||
)
|
||||
|
||||
c.resultCache = expirationcache.NewCache(
|
||||
cleanupOption,
|
||||
maxSizeOption,
|
||||
expirationcache.WithOnExpiredFn(c.onExpired),
|
||||
)
|
||||
} else {
|
||||
c.resultCache = expirationcache.NewCache(cleanupOption, maxSizeOption)
|
||||
}
|
||||
|
@ -93,7 +99,11 @@ func setupRedisCacheSubscriber(c *CachingResolver) {
|
|||
}
|
||||
|
||||
// check if domain was queried > threshold in the time window
|
||||
func (r *CachingResolver) isPrefetchingDomain(cacheKey string) bool {
|
||||
func (r *CachingResolver) shouldPrefetch(cacheKey string) bool {
|
||||
if r.prefetchThreshold == 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
cnt, _ := r.prefetchingNameCache.Get(cacheKey)
|
||||
|
||||
return cnt != nil && cnt.(int) > r.prefetchThreshold
|
||||
|
@ -104,7 +114,7 @@ func (r *CachingResolver) onExpired(cacheKey string) (val interface{}, ttl time.
|
|||
|
||||
logger := log.PrefixedLog("caching_resolver")
|
||||
|
||||
if r.isPrefetchingDomain(cacheKey) {
|
||||
if r.shouldPrefetch(cacheKey) {
|
||||
logger.Debugf("prefetching '%s' (%s)", util.Obfuscate(domainName), qType.String())
|
||||
|
||||
req := newRequest(fmt.Sprintf("%s.", domainName), qType, logger)
|
||||
|
|
Loading…
Reference in New Issue