summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Kelley <simon@thekelleys.org.uk>2022-08-29 21:44:05 +0100
committerSimon Kelley <simon@thekelleys.org.uk>2022-09-06 22:43:33 +0100
commitd334e7c34fcb6955a9c4fd856c54fa815ca0452d (patch)
tree1a31718060111a790c87721168946cb543ea200e
parentd21438a7df78f64810fa1ebec1fe64478444fa80 (diff)
downloaddnsmasq-d334e7c34fcb6955a9c4fd856c54fa815ca0452d.tar.gz
Add --use-stale-cache option.
-rw-r--r--CHANGELOG10
-rw-r--r--man/dnsmasq.86
-rw-r--r--src/cache.c6
-rw-r--r--src/dnsmasq.c3
-rw-r--r--src/dnsmasq.h7
-rw-r--r--src/forward.c191
-rw-r--r--src/option.c3
-rw-r--r--src/rfc1035.c88
8 files changed, 238 insertions, 76 deletions
diff --git a/CHANGELOG b/CHANGELOG
index deb82d1..69af8a3 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -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",