Log truncated DNS replies.

This commit is contained in:
Simon Kelley
2023-05-17 23:19:30 +01:00
parent 31c91b40bd
commit 1419de285f
3 changed files with 35 additions and 17 deletions

View File

@@ -2049,9 +2049,10 @@ static char *edestr(int ede)
void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg, unsigned short type) void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg, unsigned short type)
{ {
char *source, *dest = arg; char *source, *dest;
char *verb = "is"; char *verb = "is";
char *extra = ""; char *extra = "";
char *gap = " ";
char portstring[7]; /* space for #<portnum> */ char portstring[7]; /* space for #<portnum> */
if (!option_bool(OPT_LOG)) if (!option_bool(OPT_LOG))
@@ -2061,6 +2062,8 @@ void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg,
if (!(flags & (F_SERVER | F_IPSET)) && type > 0) if (!(flags & (F_SERVER | F_IPSET)) && type > 0)
arg = querystr(arg, type); arg = querystr(arg, type);
dest = arg;
#ifdef HAVE_DNSSEC #ifdef HAVE_DNSSEC
if ((flags & F_DNSSECOK) && option_bool(OPT_EXTRALOG)) if ((flags & F_DNSSECOK) && option_bool(OPT_EXTRALOG))
extra = " (DNSSEC signed)"; extra = " (DNSSEC signed)";
@@ -2186,19 +2189,21 @@ void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg,
else else
source = "cached"; source = "cached";
if (name && !name[0]) if (!name)
gap = name = "";
else if (!name[0])
name = "."; name = ".";
if (option_bool(OPT_EXTRALOG)) if (option_bool(OPT_EXTRALOG))
{ {
if (flags & F_NOEXTRA) if (flags & F_NOEXTRA)
my_syslog(LOG_INFO, "%u %s %s %s %s%s", daemon->log_display_id, source, name, verb, dest, extra); my_syslog(LOG_INFO, "%u %s %s%s%s %s%s", daemon->log_display_id, source, name, gap, verb, dest, extra);
else else
{ {
int port = prettyprint_addr(daemon->log_source_addr, daemon->addrbuff2); int port = prettyprint_addr(daemon->log_source_addr, daemon->addrbuff2);
my_syslog(LOG_INFO, "%u %s/%u %s %s %s %s%s", daemon->log_display_id, daemon->addrbuff2, port, source, name, verb, dest, extra); my_syslog(LOG_INFO, "%u %s/%u %s %s%s%s %s%s", daemon->log_display_id, daemon->addrbuff2, port, source, name, gap, verb, dest, extra);
} }
} }
else else
my_syslog(LOG_INFO, "%s %s %s %s%s", source, name, verb, dest, extra); my_syslog(LOG_INFO, "%s %s%s%s %s%s", source, name, gap, verb, dest, extra);
} }

View File

@@ -894,17 +894,24 @@ static void dnssec_validate(struct frec *forward, struct dns_header *header,
if (forward->blocking_query) if (forward->blocking_query)
return; return;
/* Truncated answer can't be validated.
If this is an answer to a DNSSEC-generated query, we still
need to get the client to retry over TCP, so return
an answer with the TC bit set, even if the actual answer fits.
*/
if (header->hb3 & HB3_TC)
status = STAT_TRUNCATED;
/* If all replies to a query are REFUSED, give up. */ /* If all replies to a query are REFUSED, give up. */
if (RCODE(header) == REFUSED) if (RCODE(header) == REFUSED)
status = STAT_ABANDONED; status = STAT_ABANDONED;
else if (header->hb3 & HB3_TC)
{
/* Truncated answer can't be validated.
If this is an answer to a DNSSEC-generated query, we still
need to get the client to retry over TCP, so return
an answer with the TC bit set, even if the actual answer fits.
*/
status = STAT_TRUNCATED;
if (forward->flags & (FREC_DNSKEY_QUERY | FREC_DS_QUERY))
{
unsigned char *p = (unsigned char *)(header+1);
if (extract_name(header, plen, &p, daemon->namebuff, 0, 4) == 1)
log_query(F_UPSTREAM | F_NOEXTRA, daemon->namebuff, NULL, "truncated", (forward->flags & FREC_DNSKEY_QUERY) ? T_DNSKEY : T_DS);
}
}
/* As soon as anything returns BOGUS, we stop and unwind, to do otherwise /* As soon as anything returns BOGUS, we stop and unwind, to do otherwise
would invite infinite loops, since the answers to DNSKEY and DS queries would invite infinite loops, since the answers to DNSKEY and DS queries
@@ -1293,7 +1300,10 @@ static void return_reply(time_t now, struct frec *forward, struct dns_header *he
no_cache_dnssec = 0; no_cache_dnssec = 0;
if (STAT_ISEQUAL(status, STAT_TRUNCATED)) if (STAT_ISEQUAL(status, STAT_TRUNCATED))
header->hb3 |= HB3_TC; {
header->hb3 |= HB3_TC;
log_query(F_SECSTAT, "result", NULL, "TRUNCATED", 0);
}
else else
{ {
char *result, *domain = "result"; char *result, *domain = "result";

View File

@@ -981,6 +981,9 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
} }
} }
if (header->hb3 & HB3_TC)
log_query(F_UPSTREAM, NULL, NULL, "truncated", 0);
/* Don't put stuff from a truncated packet into the cache. /* Don't put stuff from a truncated packet into the cache.
Don't cache replies from non-recursive nameservers, since we may get a Don't cache replies from non-recursive nameservers, since we may get a
reply containing a CNAME but not its target, even though the target reply containing a CNAME but not its target, even though the target