Tidy up replies to non-QUERY DNS opcodes in auth mode.

This commit is contained in:
Simon Kelley
2025-04-22 18:07:24 +01:00
parent cfa1313e1f
commit 9e67099ce7
3 changed files with 51 additions and 29 deletions

View File

@@ -103,9 +103,9 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
unsigned char *p, *ansp; unsigned char *p, *ansp;
int qtype, qclass, rc; int qtype, qclass, rc;
int nameoffset, axfroffset = 0; int nameoffset, axfroffset = 0;
int q, anscount = 0, authcount = 0; int anscount = 0, authcount = 0;
struct crec *crecp; struct crec *crecp;
int auth = !local_query, trunc = 0, nxdomain = 1, soa = 0, ns = 0, axfr = 0, out_of_zone = 0; int auth = !local_query, trunc = 0, nxdomain = 1, soa = 0, ns = 0, axfr = 0, out_of_zone = 0, notimp = 0;
struct auth_zone *zone = NULL; struct auth_zone *zone = NULL;
struct addrlist *subnet = NULL; struct addrlist *subnet = NULL;
char *cut; char *cut;
@@ -118,17 +118,18 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
unsigned int wclen; unsigned int wclen;
unsigned int log_flags = local_query ? 0 : F_NOERR; unsigned int log_flags = local_query ? 0 : F_NOERR;
if (ntohs(header->qdcount) == 0 || OPCODE(header) != QUERY ) if (ntohs(header->qdcount) != 1)
return 0; return 0;
/* determine end of question section (we put answers there) */ /* determine end of question section (we put answers there) */
if (!(ansp = skip_questions(header, qlen))) if (!(ansp = skip_questions(header, qlen)))
return 0; /* bad packet */ return 0; /* bad packet */
/* now process each question, answers go in RRs after the question */
p = (unsigned char *)(header+1); p = (unsigned char *)(header+1);
for (q = ntohs(header->qdcount); q != 0; q--) if (OPCODE(header) != QUERY)
notimp = 1;
else
{ {
unsigned int flag = 0; unsigned int flag = 0;
int found = 0; int found = 0;
@@ -148,7 +149,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
{ {
auth = 0; auth = 0;
out_of_zone = 1; out_of_zone = 1;
continue; goto done;
} }
if ((qtype == T_PTR || qtype == T_SOA || qtype == T_NS) && if ((qtype == T_PTR || qtype == T_SOA || qtype == T_NS) &&
@@ -163,7 +164,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
{ {
out_of_zone = 1; out_of_zone = 1;
auth = 0; auth = 0;
continue; goto done;
} }
else if (qtype == T_SOA) else if (qtype == T_SOA)
soa = 1, found = 1; soa = 1, found = 1;
@@ -272,7 +273,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
else else
log_query(log_flags | flag | F_NEG | F_NXDOMAIN | F_REVERSE | (auth ? F_AUTH : 0), NULL, &addr, NULL, 0); log_query(log_flags | flag | F_NEG | F_NXDOMAIN | F_REVERSE | (auth ? F_AUTH : 0), NULL, &addr, NULL, 0);
continue; goto done;
} }
cname_restart: cname_restart:
@@ -289,7 +290,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
{ {
out_of_zone = 1; out_of_zone = 1;
auth = 0; auth = 0;
continue; goto done;
} }
} }
@@ -583,6 +584,8 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
} }
} }
done:
/* Add auth section */ /* Add auth section */
if (auth && zone) if (auth && zone)
@@ -886,13 +889,22 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
header->nscount = htons(authcount); header->nscount = htons(authcount);
header->arcount = htons(0); header->arcount = htons(0);
if (!local_query && out_of_zone) if ((!local_query && out_of_zone) || notimp)
{ {
SET_RCODE(header, REFUSED); if (out_of_zone)
{
addr.log.rcode = REFUSED;
addr.log.ede = EDE_NOT_AUTH;
}
else
{
addr.log.rcode = NOTIMP;
addr.log.ede = EDE_UNSET;
}
SET_RCODE(header, addr.log.rcode);
header->ancount = htons(0); header->ancount = htons(0);
header->nscount = htons(0); header->nscount = htons(0);
addr.log.rcode = REFUSED;
addr.log.ede = EDE_NOT_AUTH;
log_query(log_flags | F_UPSTREAM | F_RCODE, "error", &addr, NULL, 0); log_query(log_flags | F_UPSTREAM | F_RCODE, "error", &addr, NULL, 0);
return resize_packet(header, ansp - (unsigned char *)header, NULL, 0); return resize_packet(header, ansp - (unsigned char *)header, NULL, 0);
} }

View File

@@ -2180,7 +2180,8 @@ void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg,
char *extra = ""; char *extra = "";
char *gap = " "; char *gap = " ";
char portstring[7]; /* space for #<portnum> */ char portstring[7]; /* space for #<portnum> */
char opcodestring[3]; /* maximum is 15 */
if (!option_bool(OPT_LOG)) if (!option_bool(OPT_LOG))
return; return;
@@ -2189,7 +2190,7 @@ void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg,
return; return;
/* build query type string if requested */ /* build query type string if requested */
if (!(flags & (F_SERVER | F_IPSET)) && type > 0) if (!(flags & (F_SERVER | F_IPSET | F_QUERY)) && type > 0)
arg = querystr(arg, type); arg = querystr(arg, type);
dest = arg; dest = arg;
@@ -2282,6 +2283,8 @@ void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg,
source = arg; source = arg;
else if (flags & F_UPSTREAM) else if (flags & F_UPSTREAM)
source = "reply"; source = "reply";
else if (flags & F_AUTH)
source = "auth";
else if (flags & F_SECSTAT) else if (flags & F_SECSTAT)
{ {
if (addr && addr->log.ede != EDE_UNSET && option_bool(OPT_EXTRALOG)) if (addr && addr->log.ede != EDE_UNSET && option_bool(OPT_EXTRALOG))
@@ -2292,8 +2295,6 @@ void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg,
source = "validation"; source = "validation";
dest = arg; dest = arg;
} }
else if (flags & F_AUTH)
source = "auth";
else if (flags & F_DNSSEC) else if (flags & F_DNSSEC)
{ {
source = arg; source = arg;
@@ -2304,11 +2305,6 @@ void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg,
source = "forwarded"; source = "forwarded";
verb = "to"; verb = "to";
} }
else if (flags & F_QUERY)
{
source = arg;
verb = "from";
}
else if (flags & F_IPSET) else if (flags & F_IPSET)
{ {
source = type ? "ipset add" : "nftset add"; source = type ? "ipset add" : "nftset add";
@@ -2320,7 +2316,21 @@ void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg,
source = "cached-stale"; source = "cached-stale";
else else
source = "cached"; source = "cached";
if (flags & F_QUERY)
{
if (flags & F_CONFIG)
{
sprintf(opcodestring, "%u", type & 0xf);
source = "non-query opcode";
name = opcodestring;
}
else if (!(flags & F_AUTH))
source = "query";
verb = "from";
}
if (!name) if (!name)
gap = name = ""; gap = name = "";
else if (!name[0]) else if (!name[0])

View File

@@ -1816,14 +1816,14 @@ void receive_query(struct listener *listen, time_t now)
#endif #endif
if (OPCODE(header) != QUERY) if (OPCODE(header) != QUERY)
log_query_mysockaddr(F_QUERY | F_FORWARD, "opcode", &source_addr, "non-query", 0); log_query_mysockaddr((auth_dns ? F_NOERR : 0) | F_QUERY | F_FORWARD | F_CONFIG, NULL, &source_addr, NULL, OPCODE(header));
else if (extract_request(header, (size_t)n, daemon->namebuff, &type, NULL)) else if (extract_request(header, (size_t)n, daemon->namebuff, &type, NULL))
{ {
#ifdef HAVE_AUTH #ifdef HAVE_AUTH
struct auth_zone *zone; struct auth_zone *zone;
#endif #endif
log_query_mysockaddr((auth_dns ? F_NOERR : 0 ) | F_QUERY | F_FORWARD, daemon->namebuff, log_query_mysockaddr((auth_dns ? F_NOERR | F_AUTH : 0 ) | F_QUERY | F_FORWARD, daemon->namebuff,
&source_addr, auth_dns ? "auth" : "query", type); &source_addr, NULL, type);
#ifdef HAVE_AUTH #ifdef HAVE_AUTH
/* Find queries for zones we're authoritative for, and answer them directly. /* Find queries for zones we're authoritative for, and answer them directly.
@@ -2459,7 +2459,7 @@ unsigned char *tcp_request(int confd, time_t now,
if (OPCODE(header) != QUERY) if (OPCODE(header) != QUERY)
{ {
log_query_mysockaddr(F_QUERY | F_FORWARD, "opcode", &peer_addr, "non-query", 0); log_query_mysockaddr((auth_dns ? F_NOERR : 0) | F_QUERY | F_FORWARD | F_CONFIG, NULL, &peer_addr, NULL, OPCODE(header));
gotname = 0; gotname = 0;
flags = F_RCODE; flags = F_RCODE;
} }
@@ -2488,8 +2488,8 @@ unsigned char *tcp_request(int confd, time_t now,
saved_question = blockdata_alloc((char *)header, (size_t)size); saved_question = blockdata_alloc((char *)header, (size_t)size);
saved_size = size; saved_size = size;
log_query_mysockaddr((auth_dns ? F_NOERR : 0) | F_QUERY | F_FORWARD, daemon->namebuff, log_query_mysockaddr((auth_dns ? F_NOERR | F_AUTH : 0) | F_QUERY | F_FORWARD, daemon->namebuff,
&peer_addr, auth_dns ? "auth" : "query", qtype); &peer_addr, NULL, qtype);
#ifdef HAVE_AUTH #ifdef HAVE_AUTH
/* Find queries for zones we're authoritative for, and answer them directly. /* Find queries for zones we're authoritative for, and answer them directly.