Compare commits

..
11 Commits
Author SHA1 Message Date
Simon Kelley da58455508 Tweak 7d915a0bb9
A downstream query may have gone to TCP, not just DNSSEC queries.
2025-01-13 11:03:30 +00:00
Simon Kelley b915c9a661 Attempt to keep running if a child process dies.
If a child process dies unexpectedly, log the error and
try and tidy up so the main process continues to run and
doesn't block awaiting the dead child.
2025-01-13 10:56:19 +00:00
Simon Kelley 424aaa0f9d Fix another 509afcd1d2 SNAFU 2025-01-13 10:32:55 +00:00
Andrew Sayers c72c895869 Improve "no upstream servers configured" when D-Bus is enabled
Print a specific INFO message instead of a generic WARNING message,
so users know what to do.

Starting dnsmasq without upstream servers indicates a problem by default,
but is perfectly normal with D-Bus enabled.  For example, NetworkManager
starts dnsmasq with no upstream servers, then immediately populates it
over D-Bus.
2025-01-12 22:32:32 +00:00
Simon Kelley b7156116c2 Fix SNAFU in 509afcd1d2 2025-01-12 22:28:12 +00:00
Simon Kelley 7d915a0bb9 Don't do retries over UDP when we've sent the query by TCP. 2025-01-12 22:02:05 +00:00
Simon Kelley 509afcd1d2 Refactor poll() loop.
Handling events on file descriptors can result in new file
descriptors being created or old ones being deleted. As such
the results of the last call to poll() become invalid in subtle
ways.

After handling each file descriptor in  check_dns_listeners()
return, to go around the poll() loop again and get valid data
for the new situation.

Thanks to Dominik Derigs for his indefatigable sleuthing of this one.
2025-01-12 21:36:09 +00:00
Simon Kelley 51343bd9a2 Treat replies with CD flag set the same for UDP and TCP code paths. 2025-01-12 16:25:07 +00:00
Simon Kelley b58276a73c Return EDE OTHER error when DNSSEC validation abandoned.
This distinguishes the case where we found a message was bogus
from cases where the process failed.
2025-01-12 16:00:09 +00:00
Matthias Andree f162d344c0 cache: Fix potential NULL deref in arcane situations. 2025-01-08 23:34:12 +00:00
Simon Kelley 0003db15cb Fix crash introduced in 6656790f24 2025-01-07 23:08:35 +00:00
3 changed files with 140 additions and 69 deletions

No files matched your search

+1 -1
View File
@@ -479,7 +479,7 @@ static struct crec *cache_scan_free(char *name, union all_addr *addr, unsigned s
if ((crecp->flags & F_FORWARD) && hostname_isequal(cache_get_name(crecp), name)) if ((crecp->flags & F_FORWARD) && hostname_isequal(cache_get_name(crecp), name))
{ {
int rrmatch = 0; int rrmatch = 0;
if (crecp->flags & flags & F_RR) if (addr && (crecp->flags & flags & F_RR))
{ {
unsigned short rrc = (crecp->flags & F_KEYTAG) ? crecp->addr.rrblock.rrtype : crecp->addr.rrdata.rrtype; unsigned short rrc = (crecp->flags & F_KEYTAG) ? crecp->addr.rrblock.rrtype : crecp->addr.rrdata.rrtype;
unsigned short rra = (flags & F_KEYTAG) ? addr->rrblock.rrtype : addr->rrdata.rrtype; unsigned short rra = (flags & F_KEYTAG) ? addr->rrblock.rrtype : addr->rrdata.rrtype;
+105 -49
View File
@@ -32,6 +32,7 @@ static volatile int pipewrite;
static void set_dns_listeners(void); static void set_dns_listeners(void);
static void set_tftp_listeners(void); static void set_tftp_listeners(void);
static void check_dns_listeners(time_t now); static void check_dns_listeners(time_t now);
static void do_tcp_connection(struct listener *listener, time_t now, int slot);
static void sig_handler(int sig); static void sig_handler(int sig);
static void async_event(int pipe, time_t now); static void async_event(int pipe, time_t now);
static void fatal_event(struct event_desc *ev, char *msg); static void fatal_event(struct event_desc *ev, char *msg);
@@ -961,8 +962,15 @@ int main (int argc, char **argv)
my_syslog(LOG_WARNING, _("warning: ignoring resolv-file flag because no-resolv is set")); my_syslog(LOG_WARNING, _("warning: ignoring resolv-file flag because no-resolv is set"));
daemon->resolv_files = NULL; daemon->resolv_files = NULL;
if (!daemon->servers) if (!daemon->servers)
{
#ifdef HAVE_DBUS
if (option_bool(OPT_DBUS))
my_syslog(LOG_INFO, _("no upstream servers configured - please set them from DBus"));
else
#endif
my_syslog(LOG_WARNING, _("warning: no upstream servers configured")); my_syslog(LOG_WARNING, _("warning: no upstream servers configured"));
} }
}
if (daemon->max_logs != 0) if (daemon->max_logs != 0)
my_syslog(LOG_INFO, _("asynchronous logging enabled, queue limit is %d messages"), daemon->max_logs); my_syslog(LOG_INFO, _("asynchronous logging enabled, queue limit is %d messages"), daemon->max_logs);
@@ -1476,7 +1484,7 @@ static void async_event(int pipe, time_t now)
{ {
pid_t p; pid_t p;
struct event_desc ev; struct event_desc ev;
int i, check = 0; int wstatus, i, check = 0;
char *msg; char *msg;
/* NOTE: the memory used to return msg is leaked: use msgs in events only /* NOTE: the memory used to return msg is leaked: use msgs in events only
@@ -1539,7 +1547,7 @@ static void async_event(int pipe, time_t now)
case EVENT_CHILD: case EVENT_CHILD:
/* See Stevens 5.10 */ /* See Stevens 5.10 */
while ((p = waitpid(-1, NULL, WNOHANG)) != 0) while ((p = waitpid(-1, &wstatus, WNOHANG)) != 0)
if (p == -1) if (p == -1)
{ {
if (errno != EINTR) if (errno != EINTR)
@@ -1550,6 +1558,20 @@ static void async_event(int pipe, time_t now)
if (daemon->tcp_pids[i] == p) if (daemon->tcp_pids[i] == p)
{ {
daemon->tcp_pids[i] = 0; daemon->tcp_pids[i] = 0;
if (!WIFEXITED(wstatus))
{
/* If a helper process dies, (eg with SIGSEV)
log that and attempt to patch things up so that the
parent can continue to function. */
my_syslog(LOG_WARNING, _("TCP helper process %u died unexpectedly"), (unsigned int)p);
if (daemon->tcp_pipes[i] != -1)
{
close(daemon->tcp_pipes[i]);
daemon->tcp_pipes[i] = -1;
}
}
/* tcp_pipes == -1 && tcp_pids == 0 required to free slot */ /* tcp_pipes == -1 && tcp_pids == 0 required to free slot */
if (daemon->tcp_pipes[i] == -1) if (daemon->tcp_pipes[i] == -1)
daemon->metrics[METRIC_TCP_CONNECTIONS]--; daemon->metrics[METRIC_TCP_CONNECTIONS]--;
@@ -1832,22 +1854,17 @@ static void check_dns_listeners(time_t now)
struct listener *listener; struct listener *listener;
struct randfd_list *rfl; struct randfd_list *rfl;
int i; int i;
int pipefd[2];
for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next) /* Note that handling events here can create or destroy fds and
if (poll_check(serverfdp->fd, POLLIN)) render the result of the last poll() call invalid. Once
reply_query(serverfdp->fd, now); we find an fd that needs service, do it, then return to go around the
poll() loop again. This avoid really, really, wierd bugs. */
for (i = 0; i < daemon->numrrand; i++)
if (daemon->randomsocks[i].refcount != 0 &&
poll_check(daemon->randomsocks[i].fd, POLLIN))
reply_query(daemon->randomsocks[i].fd, now);
/* Check overflow random sockets too. */
for (rfl = daemon->rfl_poll; rfl; rfl = rfl->next)
if (poll_check(rfl->rfd->fd, POLLIN))
reply_query(rfl->rfd->fd, now);
if (!option_bool(OPT_DEBUG))
for (i = 0; i < daemon->max_procs; i++)
if (daemon->tcp_pipes[i] != -1 &&
poll_check(daemon->tcp_pipes[i], POLLIN | POLLHUP))
{
/* Races. The child process can die before we read all of the data from the /* Races. The child process can die before we read all of the data from the
pipe, or vice versa. Therefore send tcp_pids to zero when we wait() the pipe, or vice versa. Therefore send tcp_pids to zero when we wait() the
process, and tcp_pipes to -1 and close the FD when we read the last process, and tcp_pipes to -1 and close the FD when we read the last
@@ -1855,11 +1872,7 @@ static void check_dns_listeners(time_t now)
The order of these events is indeterminate, and both are needed The order of these events is indeterminate, and both are needed
to free the process slot. Once the child process has gone, poll() to free the process slot. Once the child process has gone, poll()
returns POLLHUP, not POLLIN, so have to check for both here. */ returns POLLHUP, not POLLIN, so have to check for both here. */
if (!option_bool(OPT_DEBUG)) if (!cache_recv_insert(now, daemon->tcp_pipes[i]))
for (i = 0; i < daemon->max_procs; i++)
if (daemon->tcp_pipes[i] != -1 &&
poll_check(daemon->tcp_pipes[i], POLLIN | POLLHUP) &&
!cache_recv_insert(now, daemon->tcp_pipes[i]))
{ {
close(daemon->tcp_pipes[i]); close(daemon->tcp_pipes[i]);
daemon->tcp_pipes[i] = -1; daemon->tcp_pipes[i] = -1;
@@ -1867,11 +1880,38 @@ static void check_dns_listeners(time_t now)
if (daemon->tcp_pids[i] == 0) if (daemon->tcp_pids[i] == 0)
daemon->metrics[METRIC_TCP_CONNECTIONS]--; daemon->metrics[METRIC_TCP_CONNECTIONS]--;
} }
return;
}
for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
if (poll_check(serverfdp->fd, POLLIN))
{
reply_query(serverfdp->fd, now);
return;
}
for (i = 0; i < daemon->numrrand; i++)
if (daemon->randomsocks[i].refcount != 0 &&
poll_check(daemon->randomsocks[i].fd, POLLIN))
{
reply_query(daemon->randomsocks[i].fd, now);
return;
}
/* Check overflow random sockets too. */
for (rfl = daemon->rfl_poll; rfl; rfl = rfl->next)
if (poll_check(rfl->rfd->fd, POLLIN))
{
reply_query(rfl->rfd->fd, now);
return;
}
for (listener = daemon->listeners; listener; listener = listener->next) for (listener = daemon->listeners; listener; listener = listener->next)
{
if (listener->fd != -1 && poll_check(listener->fd, POLLIN)) if (listener->fd != -1 && poll_check(listener->fd, POLLIN))
{
receive_query(listener, now); receive_query(listener, now);
return;
}
/* check to see if we have a free tcp process slot. /* check to see if we have a free tcp process slot.
Note that we can't assume that because we had Note that we can't assume that because we had
@@ -1882,23 +1922,39 @@ static void check_dns_listeners(time_t now)
if (daemon->tcp_pids[i] == 0 && daemon->tcp_pipes[i] == -1) if (daemon->tcp_pids[i] == 0 && daemon->tcp_pipes[i] == -1)
break; break;
if (listener->tcpfd != -1 && i >= 0 && poll_check(listener->tcpfd, POLLIN)) if (i >= 0)
for (listener = daemon->listeners; listener; listener = listener->next)
if (listener->tcpfd != -1 && poll_check(listener->tcpfd, POLLIN))
{
do_tcp_connection(listener, now, i);
return;
}
}
static void do_tcp_connection(struct listener *listener, time_t now, int slot)
{ {
int confd, client_ok = 1; int confd, client_ok = 1;
struct irec *iface = NULL; struct irec *iface = NULL;
pid_t p; pid_t p;
union mysockaddr tcp_addr; union mysockaddr tcp_addr;
socklen_t tcp_len = sizeof(union mysockaddr); socklen_t tcp_len = sizeof(union mysockaddr);
unsigned char a = 0, *buff;
struct server *s;
int flags, auth_dns;
struct in_addr netmask;
int pipefd[2];
while ((confd = accept(listener->tcpfd, NULL, NULL)) == -1 && errno == EINTR); while ((confd = accept(listener->tcpfd, NULL, NULL)) == -1 && errno == EINTR);
if (confd == -1) if (confd == -1)
continue; return;
if (getsockname(confd, (struct sockaddr *)&tcp_addr, &tcp_len) == -1) if (getsockname(confd, (struct sockaddr *)&tcp_addr, &tcp_len) == -1)
{ {
closeconandreturn:
shutdown(confd, SHUT_RDWR);
close(confd); close(confd);
continue; return;
} }
/* Make sure that the interface list is up-to-date. /* Make sure that the interface list is up-to-date.
@@ -1961,17 +2017,26 @@ static void check_dns_listeners(time_t now)
} }
if (!client_ok) if (!client_ok)
goto closeconandreturn;
if (!option_bool(OPT_DEBUG))
{ {
shutdown(confd, SHUT_RDWR); if (pipe(pipefd) == -1)
close(confd); goto closeconandreturn; /* pipe failed */
}
else if (!option_bool(OPT_DEBUG) && pipe(pipefd) == 0 && (p = fork()) != 0) if ((p = fork()) == -1)
{ {
close(pipefd[1]); /* parent needs read pipe end. */ /* fork failed */
if (p == -1)
close(pipefd[0]); close(pipefd[0]);
else close(pipefd[1]);
goto closeconandreturn;
}
if (p != 0)
{ {
/* fork() done: parent side */
close(pipefd[1]); /* parent needs read pipe end. */
#ifdef HAVE_LINUX_NETWORK #ifdef HAVE_LINUX_NETWORK
/* The child process inherits the netlink socket, /* The child process inherits the netlink socket,
which it never uses, but when the parent (us) which it never uses, but when the parent (us)
@@ -1987,17 +2052,16 @@ static void check_dns_listeners(time_t now)
is sent by the child after it has closed the is sent by the child after it has closed the
netlink socket. */ netlink socket. */
unsigned char a;
read_write(pipefd[0], &a, 1, RW_READ); read_write(pipefd[0], &a, 1, RW_READ);
#endif #endif
/* i holds index of free slot */
daemon->tcp_pids[i] = p; daemon->tcp_pids[slot] = p;
daemon->tcp_pipes[i] = pipefd[0]; daemon->tcp_pipes[slot] = pipefd[0];
daemon->metrics[METRIC_TCP_CONNECTIONS]++; daemon->metrics[METRIC_TCP_CONNECTIONS]++;
if (daemon->metrics[METRIC_TCP_CONNECTIONS] > daemon->max_procs_used) if (daemon->metrics[METRIC_TCP_CONNECTIONS] > daemon->max_procs_used)
daemon->max_procs_used = daemon->metrics[METRIC_TCP_CONNECTIONS]; daemon->max_procs_used = daemon->metrics[METRIC_TCP_CONNECTIONS];
}
close(confd); close(confd);
/* The child can use up to TCP_MAX_QUERIES ids, so skip that many. */ /* The child can use up to TCP_MAX_QUERIES ids, so skip that many. */
@@ -2007,14 +2071,10 @@ static void check_dns_listeners(time_t now)
if (option_bool(OPT_DNSSEC_VALID)) if (option_bool(OPT_DNSSEC_VALID))
daemon->log_id += daemon->limit[LIMIT_WORK]; daemon->log_id += daemon->limit[LIMIT_WORK];
#endif #endif
return;
}
} }
else
{
unsigned char *buff;
struct server *s;
int flags;
struct in_addr netmask;
int auth_dns;
if (iface) if (iface)
{ {
@@ -2033,8 +2093,6 @@ static void check_dns_listeners(time_t now)
{ {
#ifdef HAVE_LINUX_NETWORK #ifdef HAVE_LINUX_NETWORK
/* See comment above re: netlink socket. */ /* See comment above re: netlink socket. */
unsigned char a = 0;
close(daemon->netlinkfd); close(daemon->netlinkfd);
read_write(pipefd[1], &a, 1, RW_WRITE); read_write(pipefd[1], &a, 1, RW_WRITE);
#endif #endif
@@ -2069,9 +2127,7 @@ static void check_dns_listeners(time_t now)
_exit(0); _exit(0);
} }
} }
}
}
}
#ifdef HAVE_DNSSEC #ifdef HAVE_DNSSEC
/* If a DNSSEC query over UDP returns a truncated answer, /* If a DNSSEC query over UDP returns a truncated answer,
+34 -19
View File
@@ -163,7 +163,7 @@ static int domain_no_rebind(char *domain)
return 0; return 0;
} }
static int forward_query(int udpfd, union mysockaddr *udpaddr, static void forward_query(int udpfd, union mysockaddr *udpaddr,
union all_addr *dst_addr, unsigned int dst_iface, union all_addr *dst_addr, unsigned int dst_iface,
struct dns_header *header, size_t plen, size_t replylimit, time_t now, struct dns_header *header, size_t plen, size_t replylimit, time_t now,
struct frec *forward, unsigned int fwd_flags, int fast_retry) struct frec *forward, unsigned int fwd_flags, int fast_retry)
@@ -190,6 +190,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
{ {
old_src = 1; old_src = 1;
old_reply = 1; old_reply = 1;
fwd_flags = forward->flags;
} }
else if (gotname && (forward = lookup_frec(daemon->namebuff, C_IN, (int)rrtype, -1, fwd_flags, else if (gotname && (forward = lookup_frec(daemon->namebuff, C_IN, (int)rrtype, -1, fwd_flags,
FREC_CHECKING_DISABLED | FREC_AD_QUESTION | FREC_DO_QUESTION | FREC_CHECKING_DISABLED | FREC_AD_QUESTION | FREC_DO_QUESTION |
@@ -253,7 +254,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
it's safe to wait for the reply from the first without it's safe to wait for the reply from the first without
forwarding the second. */ forwarding the second. */
if (difftime(now, forward->time) < 2) if (difftime(now, forward->time) < 2)
return 0; return;
} }
/* use our id when resending */ /* use our id when resending */
@@ -373,6 +374,10 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
while (forward->blocking_query) while (forward->blocking_query)
forward = forward->blocking_query; forward = forward->blocking_query;
/* Don't retry if we've already sent it via TCP. */
if (forward->flags & FREC_GONE_TO_TCP)
return;
if (forward->flags & (FREC_DNSKEY_QUERY | FREC_DS_QUERY)) if (forward->flags & (FREC_DNSKEY_QUERY | FREC_DS_QUERY))
{ {
/* log_id should match previous DNSSEC query. */ /* log_id should match previous DNSSEC query. */
@@ -385,7 +390,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
/* Find suitable servers: should never fail. */ /* Find suitable servers: should never fail. */
if (!filter_servers(forward->sentto->arrayposn, F_DNSSECOK, &first, &last)) if (!filter_servers(forward->sentto->arrayposn, F_DNSSECOK, &first, &last))
return 0; return;
is_dnssec = 1; is_dnssec = 1;
forward->forwardall = 1; forward->forwardall = 1;
@@ -501,8 +506,9 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
if (forwarded || is_dnssec) if (forwarded || is_dnssec)
{ {
daemon->metrics[METRIC_DNS_QUERIES_FORWARDED]++;
forward->forward_timestamp = dnsmasq_milliseconds(); forward->forward_timestamp = dnsmasq_milliseconds();
return 1; return;
} }
/* could not send on, prepare to return */ /* could not send on, prepare to return */
@@ -514,9 +520,9 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
if (udpfd != -1) if (udpfd != -1)
{ {
if (!(plen = make_local_answer(flags, gotname, plen, header, daemon->namebuff, (char *)(header + replylimit), first, last, ede))) if (!(plen = make_local_answer(flags, gotname, plen, header, daemon->namebuff, (char *)(header + replylimit), first, last, ede)))
return 0; return;
if (forward->flags & FREC_HAS_PHEADER) if (fwd_flags & FREC_HAS_PHEADER)
{ {
u16 swap = htons((u16)ede); u16 swap = htons((u16)ede);
@@ -542,7 +548,8 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
send_from(udpfd, option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND), (char *)header, plen, udpaddr, dst_addr, dst_iface); send_from(udpfd, option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND), (char *)header, plen, udpaddr, dst_addr, dst_iface);
} }
return 0; daemon->metrics[METRIC_DNS_LOCAL_ANSWERED]++;
return;
} }
/* Check if any frecs need to do a retry, and action that if so. /* Check if any frecs need to do a retry, and action that if so.
@@ -779,10 +786,9 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
header->ancount = htons(0); header->ancount = htons(0);
header->nscount = htons(0); header->nscount = htons(0);
header->arcount = htons(0); header->arcount = htons(0);
ede = EDE_DNSSEC_BOGUS;
} }
} }
else if (!(header->hb4 & HB4_CD) && ad_reqd && cache_secure) else if (ad_reqd && cache_secure)
header->hb4 |= HB4_AD; header->hb4 |= HB4_AD;
/* If the requestor didn't set the DO bit, don't return DNSSEC info. */ /* If the requestor didn't set the DO bit, don't return DNSSEC info. */
@@ -1243,20 +1249,25 @@ void return_reply(time_t now, struct frec *forward, struct dns_header *header, s
char *result, *domain = "result"; char *result, *domain = "result";
union all_addr a; union all_addr a;
a.log.ede = ede = errflags_to_ede(status); ede = errflags_to_ede(status);
if (STAT_ISEQUAL(status, STAT_ABANDONED)) if (STAT_ISEQUAL(status, STAT_ABANDONED))
{ {
result = "ABANDONED"; result = "ABANDONED";
status = STAT_BOGUS; status = STAT_BOGUS;
if (ede == EDE_UNSET)
ede = EDE_OTHER;
} }
else else
result = (STAT_ISEQUAL(status, STAT_SECURE) ? "SECURE" : (STAT_ISEQUAL(status, STAT_INSECURE) ? "INSECURE" : "BOGUS")); result = (STAT_ISEQUAL(status, STAT_SECURE) ? "SECURE" : (STAT_ISEQUAL(status, STAT_INSECURE) ? "INSECURE" : "BOGUS"));
if (STAT_ISEQUAL(status, STAT_SECURE)) if (STAT_ISEQUAL(status, STAT_SECURE))
cache_secure = 1; cache_secure = 1;
else if (STAT_ISEQUAL(status, STAT_BOGUS)) else if (STAT_ISEQUAL(status, STAT_BOGUS))
{ {
if (ede == EDE_UNSET)
ede = EDE_DNSSEC_BOGUS;
no_cache_dnssec = 1; no_cache_dnssec = 1;
bogusanswer = 1; bogusanswer = 1;
@@ -1264,6 +1275,7 @@ void return_reply(time_t now, struct frec *forward, struct dns_header *header, s
domain = daemon->namebuff; domain = daemon->namebuff;
} }
a.log.ede = ede;
log_query(F_SECSTAT, domain, &a, result, 0); log_query(F_SECSTAT, domain, &a, result, 0);
} }
} }
@@ -1845,11 +1857,8 @@ void receive_query(struct listener *listen, time_t now)
blockdata_free(saved_question); blockdata_free(saved_question);
saved_question = NULL; saved_question = NULL;
if (forward_query(fd, &source_addr, &dst_addr, if_index, header, (size_t)n, forward_query(fd, &source_addr, &dst_addr, if_index, header, (size_t)n,
udp_size, now, NULL, fwd_flags, 0)) udp_size, now, NULL, fwd_flags, 0);
daemon->metrics[METRIC_DNS_QUERIES_FORWARDED]++;
else
daemon->metrics[METRIC_DNS_LOCAL_ANSWERED]++;
} }
blockdata_free(saved_question); blockdata_free(saved_question);
@@ -2394,8 +2403,7 @@ unsigned char *tcp_request(int confd, time_t now,
size = saved_size; size = saved_size;
/* save state of "cd" flag in query */ /* save state of "cd" flag in query */
if ((checking_disabled = header->hb4 & HB4_CD)) checking_disabled = header->hb4 & HB4_CD;
no_cache_dnssec = 1;
if (lookup_domain(daemon->namebuff, gotname, &first, &last)) if (lookup_domain(daemon->namebuff, gotname, &first, &last))
flags = is_local_answer(now, first, daemon->namebuff); flags = is_local_answer(now, first, daemon->namebuff);
@@ -2447,7 +2455,9 @@ unsigned char *tcp_request(int confd, time_t now,
/* Clear this in case we don't call tcp_key_recurse() below */ /* Clear this in case we don't call tcp_key_recurse() below */
memset(daemon->rr_status, 0, sizeof(*daemon->rr_status) * daemon->rr_status_sz); memset(daemon->rr_status, 0, sizeof(*daemon->rr_status) * daemon->rr_status_sz);
if (!checking_disabled && (master->flags & SERV_DO_DNSSEC)) if (checking_disabled || (header->hb4 & HB4_CD))
no_cache_dnssec = 1;
else if (master->flags & SERV_DO_DNSSEC)
{ {
int keycount = daemon->limit[LIMIT_WORK]; /* Limit to number of DNSSEC questions, to catch loops and avoid filling cache. */ int keycount = daemon->limit[LIMIT_WORK]; /* Limit to number of DNSSEC questions, to catch loops and avoid filling cache. */
int validatecount = daemon->limit[LIMIT_CRYPTO]; int validatecount = daemon->limit[LIMIT_CRYPTO];
@@ -2456,12 +2466,14 @@ unsigned char *tcp_request(int confd, time_t now,
char *result, *domain = "result"; char *result, *domain = "result";
union all_addr a; union all_addr a;
a.log.ede = ede = errflags_to_ede(status); ede = errflags_to_ede(status);
if (STAT_ISEQUAL(status, STAT_ABANDONED)) if (STAT_ISEQUAL(status, STAT_ABANDONED))
{ {
result = "ABANDONED"; result = "ABANDONED";
status = STAT_BOGUS; status = STAT_BOGUS;
if (ede == EDE_UNSET)
ede = EDE_OTHER;
} }
else else
result = (STAT_ISEQUAL(status, STAT_SECURE) ? "SECURE" : (STAT_ISEQUAL(status, STAT_INSECURE) ? "INSECURE" : "BOGUS")); result = (STAT_ISEQUAL(status, STAT_SECURE) ? "SECURE" : (STAT_ISEQUAL(status, STAT_INSECURE) ? "INSECURE" : "BOGUS"));
@@ -2470,6 +2482,8 @@ unsigned char *tcp_request(int confd, time_t now,
cache_secure = 1; cache_secure = 1;
else if (STAT_ISEQUAL(status, STAT_BOGUS)) else if (STAT_ISEQUAL(status, STAT_BOGUS))
{ {
if (ede == EDE_UNSET)
ede = EDE_DNSSEC_BOGUS;
no_cache_dnssec = 1; no_cache_dnssec = 1;
bogusanswer = 1; bogusanswer = 1;
@@ -2477,6 +2491,7 @@ unsigned char *tcp_request(int confd, time_t now,
domain = daemon->namebuff; domain = daemon->namebuff;
} }
a.log.ede = ede;
log_query(F_SECSTAT, domain, &a, result, 0); log_query(F_SECSTAT, domain, &a, result, 0);
if ((daemon->limit[LIMIT_CRYPTO] - validatecount) > (int)daemon->metrics[METRIC_CRYPTO_HWM]) if ((daemon->limit[LIMIT_CRYPTO] - validatecount) > (int)daemon->metrics[METRIC_CRYPTO_HWM])