diff --git a/src/datastructure.h b/src/datastructure.h index d1f3a714..e6316698 100644 --- a/src/datastructure.h +++ b/src/datastructure.h @@ -117,6 +117,7 @@ typedef struct { enum query_type query_type; unsigned int domainID; unsigned int clientID; + unsigned int CNAME_domainID; // only valid if query has a CNAME blocking status int list_id; uint32_t hash; time_t expires; diff --git a/src/dnsmasq_interface.c b/src/dnsmasq_interface.c index 2f2984da..a595ccbf 100644 --- a/src/dnsmasq_interface.c +++ b/src/dnsmasq_interface.c @@ -1537,7 +1537,9 @@ static bool FTL_check_blocking(const unsigned int queryID, const unsigned int do if(!query->flags.allowed) { force_next_DNS_reply = dns_cache->force_reply; - query_blocked(query, domain, client, QUERY_DENYLIST); + query_blocked(query, domain, client, blocking_status); + if(blocking_status == QUERY_DENYLIST_CNAME) + query->CNAME_domainID = dns_cache->CNAME_domainID; return true; } break; @@ -1554,7 +1556,9 @@ static bool FTL_check_blocking(const unsigned int queryID, const unsigned int do if(!query->flags.allowed) { force_next_DNS_reply = dns_cache->force_reply; - query_blocked(query, domain, client, QUERY_GRAVITY); + query_blocked(query, domain, client, blocking_status); + if(blocking_status == QUERY_GRAVITY_CNAME) + query->CNAME_domainID = dns_cache->CNAME_domainID; return true; } break; @@ -1573,7 +1577,9 @@ static bool FTL_check_blocking(const unsigned int queryID, const unsigned int do { force_next_DNS_reply = dns_cache->force_reply; last_regex_idx = dns_cache->list_id; - query_blocked(query, domain, client, QUERY_REGEX); + query_blocked(query, domain, client, blocking_status); + if(blocking_status == QUERY_REGEX_CNAME) + query->CNAME_domainID = dns_cache->CNAME_domainID; return true; } break; @@ -1863,6 +1869,12 @@ bool FTL_CNAME(const char *dst, const char *src, const int id) // Store domain that was the reason for blocking the entire chain query->CNAME_domainID = child_domainID; + // Store CNAME domain ID in DNS cache + const int parent_cacheID = query->cacheID > -1 ? query->cacheID : findCacheID(parent_domainID, clientID, query->type, false); + DNSCacheData *parent_cache = parent_cacheID < 0 ? NULL : getDNSCache(parent_cacheID, true); + if(parent_cache != NULL) + parent_cache->CNAME_domainID = child_domainID; + // Change blocking reason into CNAME-caused blocking if(query->status == QUERY_GRAVITY) { @@ -1870,12 +1882,10 @@ bool FTL_CNAME(const char *dst, const char *src, const int id) } else if(query->status == QUERY_REGEX) { - // Get parent and child DNS cache entries - const int parent_cacheID = query->cacheID > -1 ? query->cacheID : findCacheID(parent_domainID, clientID, query->type, false); + // Get child DNS cache entries const int child_cacheID = findCacheID(child_domainID, clientID, query->type, false); - // Get cache pointers - DNSCacheData *parent_cache = parent_cacheID < 0 ? NULL : getDNSCache(parent_cacheID, true); + // Get child's cache pointer const DNSCacheData *child_cache = child_cacheID < 0 ? NULL : getDNSCache(child_cacheID, true); // Propagate ID of responsible regex up from the child to the parent diff --git a/src/gc.c b/src/gc.c index f340fb96..060b0c58 100644 --- a/src/gc.c +++ b/src/gc.c @@ -102,6 +102,22 @@ static void recycle(void) cache_used[query->cacheID] = true; } + // Scan cache records for CNAME domain pointers that prevent domains + // from being recyclable + for(unsigned int cacheID = 0; cacheID < counters->dns_cache_size; cacheID++) + { + const DNSCacheData *cache = getDNSCache(cacheID, true); + if(cache == NULL) + continue; + + // Mark domains as used when this is a CNAME-related cache + // record + if(cache->blocking_status == QUERY_GRAVITY_CNAME || + cache->blocking_status == QUERY_REGEX_CNAME || + cache->blocking_status == QUERY_DENYLIST_CNAME) + domain_used[cache->CNAME_domainID] = true; + } + // Recycle clients unsigned int clients_recycled = 0; for(unsigned int clientID = 0; clientID < counters->clients; clientID++)