diff options
author | Simon Kelley <simon@thekelleys.org.uk> | 2022-12-22 23:19:05 +0000 |
---|---|---|
committer | Simon Kelley <simon@thekelleys.org.uk> | 2022-12-22 23:19:05 +0000 |
commit | 43a2a66531c3d998e78c53ad792b98acf3417d49 (patch) | |
tree | 20317804353f086a430ef7dfb292766ae988de00 | |
parent | e6841ea2e00a6cd7c21b0aebce56e82932f0959d (diff) | |
download | dnsmasq-43a2a66531c3d998e78c53ad792b98acf3417d49.tar.gz |
If we hit a cache internal error, log the entry we failed to remove.
This is code which should never run, but if it does,
we now log information useful for debugging.
-rw-r--r-- | src/cache.c | 179 |
1 files changed, 97 insertions, 82 deletions
diff --git a/src/cache.c b/src/cache.c index 8f73233..100c572 100644 --- a/src/cache.c +++ b/src/cache.c @@ -28,6 +28,7 @@ static int bignames_left, hash_size; static void make_non_terminals(struct crec *source); static struct crec *really_insert(char *name, union all_addr *addr, unsigned short class, time_t now, unsigned long ttl, unsigned int flags); +static void dump_cache_entry(struct crec *cache, time_t now); /* type->string mapping: this is also used by the name-hash function as a mixing table. */ /* taken from https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml */ @@ -594,7 +595,7 @@ static struct crec *really_insert(char *name, union all_addr *addr, unsigned sho struct crec *new, *target_crec = NULL; union bigname *big_name = NULL; int freed_all = (flags & F_REVERSE); - int free_avail = 0; + struct crec *free_avail = NULL; unsigned int target_uid; /* if previous insertion failed give up now. */ @@ -642,7 +643,7 @@ static struct crec *really_insert(char *name, union all_addr *addr, unsigned sho /* Free entry at end of LRU list, use it. */ if (!(new->flags & (F_FORWARD | F_REVERSE))) - break; + break; /* End of LRU list is still in use: if we didn't scan all the hash chains for expired entries do that now. If we already tried that @@ -658,6 +659,8 @@ static struct crec *really_insert(char *name, union all_addr *addr, unsigned sho if (!warned) { my_syslog(LOG_ERR, _("Internal error in cache.")); + /* Log the entry we tried to delete. */ + dump_cache_entry(free_avail, now); warned = 1; } insert_error = 1; @@ -667,13 +670,13 @@ static struct crec *really_insert(char *name, union all_addr *addr, unsigned sho if (freed_all) { /* For DNSSEC records, uid holds class. */ - free_avail = 1; /* Must be free space now. */ + free_avail = new; /* Must be free space now. */ /* condition valid when stale-caching */ if (difftime(now, new->ttd) < 0) daemon->metrics[METRIC_DNS_CACHE_LIVE_FREED]++; - cache_scan_free(cache_get_name(new), &new->addr, new->uid, now, new->flags, NULL, NULL); + cache_scan_free(cache_get_name(new), &new->addr, new->uid, now, new->flags, NULL, NULL); } else { @@ -1760,6 +1763,94 @@ static char *sanitise(char *name) return name; } +static void dump_cache_entry(struct crec *cache, time_t now) +{ + (void)now; + static char *buff = NULL; + + char *p, *t = " "; + char *a = daemon->addrbuff, *n = cache_get_name(cache); + + /* String length is limited below */ + if (!buff && !(buff = whine_malloc(150))) + return; + + p = buff; + + *a = 0; + if (strlen(n) == 0 && !(cache->flags & F_REVERSE)) + n = "<Root>"; + p += sprintf(p, "%-30.30s ", sanitise(n)); + if ((cache->flags & F_CNAME) && !is_outdated_cname_pointer(cache)) + a = sanitise(cache_get_cname_target(cache)); + else if ((cache->flags & F_SRV) && !(cache->flags & F_NEG)) + { + int targetlen = cache->addr.srv.targetlen; + ssize_t len = sprintf(a, "%u %u %u ", cache->addr.srv.priority, + cache->addr.srv.weight, cache->addr.srv.srvport); + + if (targetlen > (40 - len)) + targetlen = 40 - len; + blockdata_retrieve(cache->addr.srv.target, targetlen, a + len); + a[len + targetlen] = 0; + } +#ifdef HAVE_DNSSEC + else if (cache->flags & F_DS) + { + if (!(cache->flags & F_NEG)) + sprintf(a, "%5u %3u %3u", cache->addr.ds.keytag, + cache->addr.ds.algo, cache->addr.ds.digest); + } + else if (cache->flags & F_DNSKEY) + sprintf(a, "%5u %3u %3u", cache->addr.key.keytag, + cache->addr.key.algo, cache->addr.key.flags); +#endif + else if (!(cache->flags & F_NEG) || !(cache->flags & F_FORWARD)) + { + a = daemon->addrbuff; + if (cache->flags & F_IPV4) + inet_ntop(AF_INET, &cache->addr, a, ADDRSTRLEN); + else if (cache->flags & F_IPV6) + inet_ntop(AF_INET6, &cache->addr, a, ADDRSTRLEN); + } + + if (cache->flags & F_IPV4) + t = "4"; + else if (cache->flags & F_IPV6) + t = "6"; + else if (cache->flags & F_CNAME) + t = "C"; + else if (cache->flags & F_SRV) + t = "V"; +#ifdef HAVE_DNSSEC + else if (cache->flags & F_DS) + t = "S"; + else if (cache->flags & F_DNSKEY) + t = "K"; +#endif + else /* non-terminal */ + t = "!"; + + p += sprintf(p, "%-40.40s %s%s%s%s%s%s%s%s%s%s ", a, t, + cache->flags & F_FORWARD ? "F" : " ", + cache->flags & F_REVERSE ? "R" : " ", + cache->flags & F_IMMORTAL ? "I" : " ", + cache->flags & F_DHCP ? "D" : " ", + cache->flags & F_NEG ? "N" : " ", + cache->flags & F_NXDOMAIN ? "X" : " ", + cache->flags & F_HOSTS ? "H" : " ", + cache->flags & F_CONFIG ? "C" : " ", + cache->flags & F_DNSSECOK ? "V" : " "); +#ifdef HAVE_BROKEN_RTC + p += sprintf(p, "%-24lu", cache->flags & F_IMMORTAL ? 0: (unsigned long)(cache->ttd - now)); +#else + p += sprintf(p, "%-24.24s", cache->flags & F_IMMORTAL ? "" : ctime(&(cache->ttd))); +#endif + if(cache->flags & (F_HOSTS | F_CONFIG) && cache->uid > 0) + p += sprintf(p, " %-40.40s", record_source(cache->uid)); + + my_syslog(LOG_INFO, "%s", buff); +} void dump_cache(time_t now) { @@ -1807,90 +1898,14 @@ void dump_cache(time_t now) if (option_bool(OPT_DEBUG) || option_bool(OPT_LOG)) { - struct crec *cache ; + struct crec *cache; int i; my_syslog(LOG_INFO, "Host Address Flags Expires Source"); my_syslog(LOG_INFO, "------------------------------ ---------------------------------------- ---------- ------------------------ ------------"); for (i=0; i<hash_size; i++) for (cache = hash_table[i]; cache; cache = cache->hash_next) - { - char *t = " "; - char *a = daemon->addrbuff, *p = daemon->namebuff, *n = cache_get_name(cache); - *a = 0; - if (strlen(n) == 0 && !(cache->flags & F_REVERSE)) - n = "<Root>"; - p += sprintf(p, "%-30.30s ", sanitise(n)); - if ((cache->flags & F_CNAME) && !is_outdated_cname_pointer(cache)) - a = sanitise(cache_get_cname_target(cache)); - else if ((cache->flags & F_SRV) && !(cache->flags & F_NEG)) - { - int targetlen = cache->addr.srv.targetlen; - ssize_t len = sprintf(a, "%u %u %u ", cache->addr.srv.priority, - cache->addr.srv.weight, cache->addr.srv.srvport); - - if (targetlen > (40 - len)) - targetlen = 40 - len; - blockdata_retrieve(cache->addr.srv.target, targetlen, a + len); - a[len + targetlen] = 0; - } -#ifdef HAVE_DNSSEC - else if (cache->flags & F_DS) - { - if (!(cache->flags & F_NEG)) - sprintf(a, "%5u %3u %3u", cache->addr.ds.keytag, - cache->addr.ds.algo, cache->addr.ds.digest); - } - else if (cache->flags & F_DNSKEY) - sprintf(a, "%5u %3u %3u", cache->addr.key.keytag, - cache->addr.key.algo, cache->addr.key.flags); -#endif - else if (!(cache->flags & F_NEG) || !(cache->flags & F_FORWARD)) - { - a = daemon->addrbuff; - if (cache->flags & F_IPV4) - inet_ntop(AF_INET, &cache->addr, a, ADDRSTRLEN); - else if (cache->flags & F_IPV6) - inet_ntop(AF_INET6, &cache->addr, a, ADDRSTRLEN); - } - - if (cache->flags & F_IPV4) - t = "4"; - else if (cache->flags & F_IPV6) - t = "6"; - else if (cache->flags & F_CNAME) - t = "C"; - else if (cache->flags & F_SRV) - t = "V"; -#ifdef HAVE_DNSSEC - else if (cache->flags & F_DS) - t = "S"; - else if (cache->flags & F_DNSKEY) - t = "K"; -#endif - else /* non-terminal */ - t = "!"; - - p += sprintf(p, "%-40.40s %s%s%s%s%s%s%s%s%s%s ", a, t, - cache->flags & F_FORWARD ? "F" : " ", - cache->flags & F_REVERSE ? "R" : " ", - cache->flags & F_IMMORTAL ? "I" : " ", - cache->flags & F_DHCP ? "D" : " ", - cache->flags & F_NEG ? "N" : " ", - cache->flags & F_NXDOMAIN ? "X" : " ", - cache->flags & F_HOSTS ? "H" : " ", - cache->flags & F_CONFIG ? "C" : " ", - cache->flags & F_DNSSECOK ? "V" : " "); -#ifdef HAVE_BROKEN_RTC - p += sprintf(p, "%-24lu", cache->flags & F_IMMORTAL ? 0: (unsigned long)(cache->ttd - now)); -#else - p += sprintf(p, "%-24.24s", cache->flags & F_IMMORTAL ? "" : ctime(&(cache->ttd))); -#endif - if(cache->flags & (F_HOSTS | F_CONFIG) && cache->uid > 0) - p += sprintf(p, " %s", record_source(cache->uid)); - - my_syslog(LOG_INFO, "%s", daemon->namebuff); - } + dump_cache_entry(cache, now); } } |