diff options
author | Simon Kelley <simon@thekelleys.org.uk> | 2022-08-29 21:44:05 +0100 |
---|---|---|
committer | Simon Kelley <simon@thekelleys.org.uk> | 2022-09-06 22:43:33 +0100 |
commit | d334e7c34fcb6955a9c4fd856c54fa815ca0452d (patch) | |
tree | 1a31718060111a790c87721168946cb543ea200e | |
parent | d21438a7df78f64810fa1ebec1fe64478444fa80 (diff) | |
download | dnsmasq-d334e7c34fcb6955a9c4fd856c54fa815ca0452d.tar.gz |
Add --use-stale-cache option.
-rw-r--r-- | CHANGELOG | 10 | ||||
-rw-r--r-- | man/dnsmasq.8 | 6 | ||||
-rw-r--r-- | src/cache.c | 6 | ||||
-rw-r--r-- | src/dnsmasq.c | 3 | ||||
-rw-r--r-- | src/dnsmasq.h | 7 | ||||
-rw-r--r-- | src/forward.c | 191 | ||||
-rw-r--r-- | src/option.c | 3 | ||||
-rw-r--r-- | src/rfc1035.c | 88 |
8 files changed, 238 insertions, 76 deletions
@@ -90,6 +90,16 @@ version 2.87 when doing DNSSEC over unreliable upstream network. It comes with some cost in memory usage and network bandwidth. + Add -use-stale-cache option. When set, if a DNS name exists + in the cache, but its time-to-live has expired, dnsmasq will + return the data anyway. (It attempts to refresh the + data with an upstream query after returning the stale data.) + This can improve speed and reliability. It comes + at the expense of sometimes returning out-of-date data and + less efficient cache utilisation, since old data cannot be + flushed when its TTL expires, so the cache becomes + strictly least-recently-used. + version 2.86 Handle DHCPREBIND requests in the DHCPv6 server code. diff --git a/man/dnsmasq.8 b/man/dnsmasq.8 index e4b2e56..11640a7 100644 --- a/man/dnsmasq.8 +++ b/man/dnsmasq.8 @@ -812,6 +812,12 @@ Disable negative caching. Negative caching allows dnsmasq to remember "no such domain" answers from upstream nameservers and answer identical queries without forwarding them again. .TP +.B --use-stale-cache +When set, if a DNS name exists in the cache, but its time-to-live has expired, dnsmasq will return the data anyway. (It attempts to refresh the +data with an upstream query after returning the stale data.) This can improve speed and reliability. It comes at the expense +of sometimes returning out-of-date data and less efficient cache utilisation, since old data cannot be flushed when its TTL expires, so the cache becomes +strictly least-recently-used. +.TP .B \-0, --dns-forward-max=<queries> Set the maximum number of concurrent DNS queries. The default value is 150, which should be fine for most setups. The only known situation diff --git a/src/cache.c b/src/cache.c index 8ed4740..404147b 100644 --- a/src/cache.c +++ b/src/cache.c @@ -374,6 +374,10 @@ static int is_outdated_cname_pointer(struct crec *crecp) static int is_expired(time_t now, struct crec *crecp) { + /* Don't dump expired entries if we're using them, cache becomes strictly LRU in that case. */ + if (option_bool(OPT_STALE_CACHE)) + return 0; + if (crecp->flags & F_IMMORTAL) return 0; @@ -2079,6 +2083,8 @@ void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg, name = arg; verb = daemon->addrbuff; } + else if (flags & F_STALE) + source = "cached-stale"; else source = "cached"; diff --git a/src/dnsmasq.c b/src/dnsmasq.c index bfd1f16..4742a97 100644 --- a/src/dnsmasq.c +++ b/src/dnsmasq.c @@ -2015,9 +2015,6 @@ static void check_dns_listeners(time_t now) buff = tcp_request(confd, now, &tcp_addr, netmask, auth_dns); - shutdown(confd, SHUT_RDWR); - close(confd); - if (buff) free(buff); diff --git a/src/dnsmasq.h b/src/dnsmasq.h index a455a77..1bfb965 100644 --- a/src/dnsmasq.h +++ b/src/dnsmasq.h @@ -279,7 +279,8 @@ struct event_desc { #define OPT_FILTER_AAAA 68 #define OPT_STRIP_ECS 69 #define OPT_STRIP_MAC 70 -#define OPT_LAST 71 +#define OPT_STALE_CACHE 71 +#define OPT_LAST 72 #define OPTION_BITS (sizeof(unsigned int)*8) #define OPTION_SIZE ( (OPT_LAST/OPTION_BITS)+((OPT_LAST%OPTION_BITS)!=0) ) @@ -510,6 +511,7 @@ struct crec { #define F_DOMAINSRV (1u<<28) #define F_RCODE (1u<<29) #define F_SRV (1u<<30) +#define F_STALE (1u<<31) #define UID_NONE 0 /* Values of uid in crecs with F_CONFIG bit set. */ @@ -1340,7 +1342,8 @@ void report_addresses(struct dns_header *header, size_t len, u32 mark); #endif size_t answer_request(struct dns_header *header, char *limit, size_t qlen, struct in_addr local_addr, struct in_addr local_netmask, - time_t now, int ad_reqd, int do_bit, int have_pseudoheader); + time_t now, int ad_reqd, int do_bit, int have_pseudoheader, + int *stale); int check_for_bogus_wildcard(struct dns_header *header, size_t qlen, char *name, time_t now); int check_for_ignored_address(struct dns_header *header, size_t qlen); diff --git a/src/forward.c b/src/forward.c index 0c9b962..9cfdf8a 100644 --- a/src/forward.c +++ b/src/forward.c @@ -1183,11 +1183,6 @@ void reply_query(int fd, time_t now) else if (udp_size < PACKETSZ) udp_size = PACKETSZ; /* Sanity check - can't reduce below default. RFC 6891 6.2.3 */ - if (!is_sign && - (nn = resize_packet(header, (size_t)n, pheader, plen)) && - (forward->flags & FREC_DO_QUESTION)) - add_do_bit(header, nn, (unsigned char *)pheader + plen); - header->ancount = htons(0); header->nscount = htons(0); header->arcount = htons(0); @@ -1197,6 +1192,11 @@ void reply_query(int fd, time_t now) header->hb4 |= HB4_CD; if (forward->flags & FREC_AD_QUESTION) header->hb4 |= HB4_AD; + + if (!is_sign && + (nn = resize_packet(header, (size_t)n, pheader, plen)) && + (forward->flags & FREC_DO_QUESTION)) + add_do_bit(header, nn, (unsigned char *)pheader + plen); } } @@ -1343,10 +1343,6 @@ static void return_reply(time_t now, struct frec *forward, struct dns_header *he { header->id = htons(src->orig_id); -#ifdef HAVE_DUMPFILE - dump_packet_udp(DUMP_REPLY, daemon->packet, (size_t)nn, NULL, &src->source, src->fd); -#endif - #if defined(HAVE_CONNTRACK) && defined(HAVE_UBUS) if (option_bool(OPT_CMARK_ALST_EN)) { @@ -1357,14 +1353,20 @@ static void return_reply(time_t now, struct frec *forward, struct dns_header *he } #endif - send_from(src->fd, option_bool(OPT_NOWILD) || option_bool (OPT_CLEVERBIND), daemon->packet, nn, - &src->source, &src->dest, src->iface); - - if (option_bool(OPT_EXTRALOG) && src != &forward->frec_src) + if (src->fd != -1) { - daemon->log_display_id = src->log_id; - daemon->log_source_addr = &src->source; - log_query(F_UPSTREAM, "query", NULL, "duplicate", 0); +#ifdef HAVE_DUMPFILE + dump_packet_udp(DUMP_REPLY, daemon->packet, (size_t)nn, NULL, &src->source, src->fd); +#endif + send_from(src->fd, option_bool(OPT_NOWILD) || option_bool (OPT_CLEVERBIND), daemon->packet, nn, + &src->source, &src->dest, src->iface); + + if (option_bool(OPT_EXTRALOG) && src != &forward->frec_src) + { + daemon->log_display_id = src->log_id; + daemon->log_source_addr = &src->source; + log_query(F_UPSTREAM, "query", NULL, "duplicate", 0); + } } } } @@ -1454,7 +1456,7 @@ void receive_query(struct listener *listen, time_t now) int family = listen->addr.sa.sa_family; /* Can always get recvd interface for IPv6 */ int check_dst = !option_bool(OPT_NOWILD) || family == AF_INET6; - + /* packet buffer overwritten */ daemon->srv_save = NULL; @@ -1777,13 +1779,17 @@ void receive_query(struct listener *listen, time_t now) #endif else { + int stale; int ad_reqd = do_bit; + u16 hb3 = header->hb3, hb4 = header->hb4; + int fd = listen->fd; + /* RFC 6840 5.7 */ if (header->hb4 & HB4_AD) ad_reqd = 1; m = answer_request(header, ((char *) header) + udp_size, (size_t)n, - dst_addr_4, netmask, now, ad_reqd, do_bit, have_pseudoheader); + dst_addr_4, netmask, now, ad_reqd, do_bit, have_pseudoheader, &stale); if (m >= 1) { @@ -1798,11 +1804,36 @@ void receive_query(struct listener *listen, time_t now) (char *)header, m, &source_addr, &dst_addr, if_index); daemon->metrics[METRIC_DNS_LOCAL_ANSWERED]++; } - else if (forward_query(listen->fd, &source_addr, &dst_addr, if_index, - header, (size_t)n, ((char *) header) + udp_size, now, NULL, ad_reqd, do_bit)) - daemon->metrics[METRIC_DNS_QUERIES_FORWARDED]++; - else - daemon->metrics[METRIC_DNS_LOCAL_ANSWERED]++; + + if (m == 0 || stale) + { + if (m != 0) + { + size_t plen; + + /* We answered with stale cache data, so forward the query anyway to + refresh that. Restore the query from the answer packet. */ + pheader = find_pseudoheader(header, (size_t)m, &plen, NULL, NULL, NULL); + + header->hb3 = hb3; + header->hb4 = hb4; + header->ancount = htons(0); + header->nscount = htons(0); + header->arcount = htons(0); + + m = resize_packet(header, m, pheader, plen); + + /* We've already answered the client, so don't send it the answer + when it comes back. */ + fd = -1; + } + + if (forward_query(fd, &source_addr, &dst_addr, if_index, + header, (size_t)n, ((char *) header) + udp_size, now, NULL, ad_reqd, do_bit)) + daemon->metrics[METRIC_DNS_QUERIES_FORWARDED]++; + else + daemon->metrics[METRIC_DNS_LOCAL_ANSWERED]++; + } } } @@ -2029,8 +2060,9 @@ unsigned char *tcp_request(int confd, time_t now, unsigned char *pheader; unsigned int mark = 0; int have_mark = 0; - int first, last; + int first, last, stale, do_stale = 0; unsigned int flags = 0; + u16 hb3, hb4; if (!packet || getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) == -1) return packet; @@ -2085,13 +2117,37 @@ unsigned char *tcp_request(int confd, time_t now, { int ede = EDE_UNSET; - if (query_count == TCP_MAX_QUERIES || - !packet || - !read_write(confd, &c1, 1, 1) || !read_write(confd, &c2, 1, 1) || - !(size = c1 << 8 | c2) || - !read_write(confd, payload, size, 1)) - return packet; - + if (query_count == TCP_MAX_QUERIES) + return packet; + + if (do_stale) + { + size_t plen; + + /* We answered the last query with stale data. Now try and get fresh data. + Restore query from answer. */ + pheader = find_pseudoheader(header, m, &plen, NULL, NULL, NULL); + + header->hb3 = hb3; + header->hb4 = hb4; + header->ancount = htons(0); + header->nscount = htons(0); + header->arcount = htons(0); + + size = resize_packet(header, m, pheader, plen); + } + else + { + if (!read_write(confd, &c1, 1, 1) || !read_write(confd, &c2, 1, 1) || + !(size = c1 << 8 | c2) || + !read_write(confd, payload, size, 1)) + return packet; + + /* for stale-answer processing. */ + hb3 = header->hb3; + hb4 = header->hb4; + } + if (size < (int)sizeof(struct dns_header)) continue; @@ -2116,24 +2172,27 @@ unsigned char *tcp_request(int confd, time_t now, struct auth_zone *zone; #endif - log_query_mysockaddr(F_QUERY | F_FORWARD, daemon->namebuff, - &peer_addr, auth_dns ? "auth" : "query", qtype); - #ifdef HAVE_CONNTRACK is_single_query = 1; #endif - + + if (!do_stale) + { + log_query_mysockaddr(F_QUERY | F_FORWARD, daemon->namebuff, + &peer_addr, auth_dns ? "auth" : "query", qtype); + #ifdef HAVE_AUTH - /* find queries for zones we're authoritative for, and answer them directly */ - if (!auth_dns && !option_bool(OPT_LOCALISE)) - for (zone = daemon->auth_zones; zone; zone = zone->next) - if (in_zone(zone, daemon->namebuff, NULL)) - { - auth_dns = 1; - local_auth = 1; - break; - } + /* find queries for zones we're authoritative for, and answer them directly */ + if (!auth_dns && !option_bool(OPT_LOCALISE)) + for (zone = daemon->auth_zones; zone; zone = zone->next) + if (in_zone(zone, daemon->namebuff, NULL)) + { + auth_dns = 1; + local_auth = 1; + break; + } #endif + } } norebind = domain_no_rebind(daemon->namebuff); @@ -2189,11 +2248,14 @@ unsigned char *tcp_request(int confd, time_t now, /* RFC 6840 5.7 */ if (header->hb4 & HB4_AD) ad_reqd = 1; + + if (do_stale) + m = 0; + else + /* m > 0 if answered from cache */ + m = answer_request(header, ((char *) header) + 65536, (size_t)size, + dst_addr_4, netmask, now, ad_reqd, do_bit, have_pseudoheader, &stale); - /* m > 0 if answered from cache */ - m = answer_request(header, ((char *) header) + 65536, (size_t)size, - dst_addr_4, netmask, now, ad_reqd, do_bit, have_pseudoheader); - /* Do this by steam now we're not in the select() loop */ check_log_writer(1); @@ -2311,6 +2373,9 @@ unsigned char *tcp_request(int confd, time_t now, } } + if (do_stale) + break; + /* In case of local answer or no connections made. */ if (m == 0) { @@ -2321,11 +2386,11 @@ unsigned char *tcp_request(int confd, time_t now, if (have_pseudoheader) { u16 swap = htons((u16)ede); - - if (ede != EDE_UNSET) - m = add_pseudoheader(header, m, ((unsigned char *) header) + 65536, daemon->edns_pktsz, EDNS0_OPTION_EDE, (unsigned char *)&swap, 2, do_bit, 0); - else - m = add_pseudoheader(header, m, ((unsigned char *) header) + 65536, daemon->edns_pktsz, 0, NULL, 0, do_bit, 0); + + if (ede != EDE_UNSET) + m = add_pseudoheader(header, m, ((unsigned char *) header) + 65536, daemon->edns_pktsz, EDNS0_OPTION_EDE, (unsigned char *)&swap, 2, do_bit, 0); + else + m = add_pseudoheader(header, m, ((unsigned char *) header) + 65536, daemon->edns_pktsz, 0, NULL, 0, do_bit, 0); } } @@ -2342,8 +2407,26 @@ unsigned char *tcp_request(int confd, time_t now, #endif if (!read_write(confd, packet, m + sizeof(u16), 0)) break; + + /* If we answered with stale data, this process will now try and get fresh data into + the cache then and cannot therefore accept new queries. Close the incoming + connection to signal that to the client. Then set do_stale and loop round + once more to try and get fresh data, after which we exit. */ + if (stale) + { + shutdown(confd, SHUT_RDWR); + close(confd); + do_stale = 1; + } } - + + /* If we ran once to get fresh data, confd is already closed. */ + if (!do_stale) + { + shutdown(confd, SHUT_RDWR); + close(confd); + } + return packet; } diff --git a/src/option.c b/src/option.c index 8614f51..aaecebe 100644 --- a/src/option.c +++ b/src/option.c @@ -183,6 +183,7 @@ struct myoption { #define LOPT_CONF_SCRIPT 374 #define LOPT_RANDPORT_LIM 375 #define LOPT_FAST_RETRY 376 +#define LOPT_STALE_CACHE 377 #ifdef HAVE_GETOPT_LONG static const struct option opts[] = @@ -370,6 +371,7 @@ static const struct myoption opts[] = { "quiet-tftp", 0, 0, LOPT_QUIET_TFTP }, { "port-limit", 1, 0, LOPT_RANDPORT_LIM }, { "fast-dns-retry", 1, 0, LOPT_FAST_RETRY }, + { "use-stale-cache", 0, 0 , LOPT_STALE_CACHE }, { NULL, 0, 0, 0 } }; @@ -427,6 +429,7 @@ static struct { { 'M', ARG_DUP, "<bootp opts>", gettext_noop("Specify BOOTP options to DHCP server."), NULL }, { 'n', OPT_NO_POLL, NULL, gettext_noop("Do NOT poll %s file, reload only on SIGHUP."), RESOLVFILE }, { 'N', OPT_NO_NEG, NULL, gettext_noop("Do NOT cache failed search results."), NULL }, + { LOPT_STALE_CACHE, OPT_STALE_CACHE, NULL, gettext_noop("Use expired cache data for faster reply."), NULL }, { 'o', OPT_ORDER, NULL, gettext_noop("Use nameservers strictly in the order given in %s."), RESOLVFILE }, { 'O', ARG_DUP, "<optspec>", gettext_noop("Specify options to be sent to DHCP clients."), NULL }, { LOPT_FORCE, ARG_DUP, "<optspec>", gettext_noop("DHCP option sent even if the client does not request it."), NULL}, diff --git a/src/rfc1035.c b/src/rfc1035.c index 60ef272..d6d3b49 100644 --- a/src/rfc1035.c +++ b/src/rfc1035.c @@ -1360,8 +1360,15 @@ int add_resource_record(struct dns_header *header, char *limit, int *truncp, int #undef CHECK_LIMIT } +static int crec_isstale(struct crec *crecp, time_t now) +{ + return (!(crecp->flags & F_IMMORTAL)) && difftime(crecp->ttd, now) < 0; +} + static unsigned long crec_ttl(struct crec *crecp, time_t now) { + signed long ttl = difftime(crecp->ttd, now); + /* Return 0 ttl for DHCP entries, which might change before the lease expires, unless configured otherwise. */ @@ -1370,8 +1377,8 @@ static unsigned long crec_ttl(struct crec *crecp, time_t now) int conf_ttl = daemon->use_dhcp_ttl ? daemon->dhcp_ttl : daemon->local_ttl; /* Apply ceiling of actual lease length to configured TTL. */ - if (!(crecp->flags & F_IMMORTAL) && (crecp->ttd - now) < conf_ttl) - return crecp->ttd - now; + if (!(crecp->flags & F_IMMORTAL) && ttl < conf_ttl) + return ttl; return conf_ttl; } @@ -1380,9 +1387,13 @@ static unsigned long crec_ttl(struct crec *crecp, time_t now) if (crecp->flags & F_IMMORTAL) return crecp->ttd; + /* Stale cache entries. */ + if (ttl < 0) + return 0; + /* Return the Max TTL value if it is lower than the actual TTL */ - if (daemon->max_ttl == 0 || ((unsigned)(crecp->ttd - now) < daemon->max_ttl)) - return crecp->ttd - now; + if (daemon->max_ttl == 0 || ((unsigned)ttl < daemon->max_ttl)) + return ttl; else return daemon->max_ttl; } @@ -1395,7 +1406,8 @@ static int cache_validated(const struct crec *crecp) /* return zero if we can't answer from cache, or packet size if we can */ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, struct in_addr local_addr, struct in_addr local_netmask, - time_t now, int ad_reqd, int do_bit, int have_pseudoheader) + time_t now, int ad_reqd, int do_bit, int have_pseudoheader, + int *stale) { char *name = daemon->namebuff; unsigned char *p, *ansp; @@ -1411,6 +1423,9 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, size_t len; int rd_bit = (header->hb3 & HB3_RD); + if (stale) + *stale = 0; + /* never answer queries with RD unset, to avoid cache snooping. */ if (ntohs(header->ancount) != 0 || ntohs(header->nscount) != 0 || @@ -1459,13 +1474,22 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, while (--count != 0 && (crecp = cache_find_by_name(NULL, name, now, F_CNAME | F_NXDOMAIN))) { char *cname_target; - + int stale_flag = 0; + + if (crec_isstale(crecp, now)) + { + if (stale) + *stale = 1; + + stale_flag = F_STALE; + } + if (crecp->flags & F_NXDOMAIN) { if (qtype == T_CNAME) { if (!dryrun) - log_query(crecp->flags, name, NULL, record_source(crecp->uid), 0); + log_query(stale_flag | crecp->flags, name, NULL, record_source(crecp->uid), 0); auth = 0; nxdomain = 1; ans = 1; @@ -1487,7 +1511,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, if (!dryrun) { - log_query(crecp->flags, name, NULL, record_source(crecp->uid), 0); + log_query(stale_flag | crecp->flags, name, NULL, record_source(crecp->uid), 0); if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, crec_ttl(crecp, now), &nameoffset, T_CNAME, C_IN, "d", cname_target)) @@ -1656,22 +1680,33 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, { do { + int stale_flag = 0; + + if (crec_isstale(crecp, now)) + { + if (stale) + *stale = 1; + + stale_flag = F_STALE; + } + /* don't answer wildcard queries with data not from /etc/hosts or dhcp leases */ if (qtype == T_ANY && !(crecp->flags & (F_HOSTS | F_DHCP))) continue; + if (!(crecp->flags & F_DNSSECOK)) sec_data = 0; - + ans = 1; - + if (crecp->flags & F_NEG) { auth = 0; if (crecp->flags & F_NXDOMAIN) nxdomain = 1; if (!dryrun) - log_query(crecp->flags & ~F_FORWARD, name, &addr, NULL, 0); + log_query(stale_flag | (crecp->flags & ~F_FORWARD), name, &addr, NULL, 0); } else { @@ -1679,7 +1714,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, auth = 0; if (!dryrun) { - log_query(crecp->flags & ~F_FORWARD, cache_get_name(crecp), &addr, + log_query(stale_flag | (crecp->flags & ~F_FORWARD), cache_get_name(crecp), &addr, record_source(crecp->uid), 0); if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, @@ -1788,7 +1823,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, if ((crecp = cache_find_by_name(NULL, name, now, flag | F_NXDOMAIN | (dryrun ? F_NO_RR : 0)))) { int localise = 0; - + /* See if a putative address is on the network from which we received the query, is so we'll filter other answers. */ if (local_addr.s_addr != 0 && option_bool(OPT_LOCALISE) && flag == F_IPV4) @@ -1810,6 +1845,16 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, (rd_bit && (!do_bit || cache_validated(crecp)) )) do { + int stale_flag = 0; + + if (crec_isstale(crecp, now)) + { + if (stale) + *stale = 1; + + stale_flag = F_STALE; + } + /* don't answer wildcard queries with data not from /etc/hosts or DHCP leases */ if (qtype == T_ANY && !(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG))) @@ -1825,7 +1870,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, if (crecp->flags & F_NXDOMAIN) nxdomain = 1; if (!dryrun) - log_query(crecp->flags, name, NULL, NULL, 0); + log_query(stale_flag | crecp->flags, name, NULL, NULL, 0); } else { @@ -1842,7 +1887,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, ans = 1; if (!dryrun) { - log_query(crecp->flags & ~F_REVERSE, name, &crecp->addr, + log_query(stale_flag | (crecp->flags & ~F_REVERSE), name, &crecp->addr, record_source(crecp->uid), 0); if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, @@ -1953,6 +1998,15 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, rd_bit && (!do_bit || (option_bool(OPT_DNSSEC_VALID) && !(crecp->flags & F_DNSSECOK)))) do { + int stale_flag = 0; + + if (crec_isstale(crecp, now)) + { + if (stale) + *stale = 1; + + stale_flag = F_STALE; + } /* don't answer wildcard queries with data not from /etc/hosts or dhcp leases, except for NXDOMAIN */ if (qtype == T_ANY && !(crecp->flags & (F_NXDOMAIN))) break; @@ -1968,12 +2022,12 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, if (crecp->flags & F_NXDOMAIN) nxdomain = 1; if (!dryrun) - log_query(crecp->flags, name, NULL, NULL, 0); + log_query(stale_flag | crecp->flags, name, NULL, NULL, 0); } else if (!dryrun) { char *target = blockdata_retrieve(crecp->addr.srv.target, crecp->addr.srv.targetlen, NULL); - log_query(crecp->flags, name, NULL, NULL, 0); + log_query(stale_flag | crecp->flags, name, NULL, NULL, 0); if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, crec_ttl(crecp, now), NULL, T_SRV, C_IN, "sssd", |