From 9e67099ce73c1105da3db9b611480bfadbf60c73 Mon Sep 17 00:00:00 2001 From: Simon Kelley Date: Tue, 22 Apr 2025 18:07:24 +0100 Subject: [PATCH] Tidy up replies to non-QUERY DNS opcodes in auth mode. --- src/auth.c | 38 +++++++++++++++++++++++++------------- src/cache.c | 30 ++++++++++++++++++++---------- src/forward.c | 12 ++++++------ 3 files changed, 51 insertions(+), 29 deletions(-) diff --git a/src/auth.c b/src/auth.c index b2cee26..7c34522 100644 --- a/src/auth.c +++ b/src/auth.c @@ -103,9 +103,9 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n unsigned char *p, *ansp; int qtype, qclass, rc; int nameoffset, axfroffset = 0; - int q, anscount = 0, authcount = 0; + int anscount = 0, authcount = 0; 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 addrlist *subnet = NULL; 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 log_flags = local_query ? 0 : F_NOERR; - if (ntohs(header->qdcount) == 0 || OPCODE(header) != QUERY ) + if (ntohs(header->qdcount) != 1) return 0; /* determine end of question section (we put answers there) */ if (!(ansp = skip_questions(header, qlen))) return 0; /* bad packet */ - /* now process each question, answers go in RRs after the question */ p = (unsigned char *)(header+1); - for (q = ntohs(header->qdcount); q != 0; q--) + if (OPCODE(header) != QUERY) + notimp = 1; + else { unsigned int flag = 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; out_of_zone = 1; - continue; + goto done; } 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; auth = 0; - continue; + goto done; } else if (qtype == T_SOA) 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 log_query(log_flags | flag | F_NEG | F_NXDOMAIN | F_REVERSE | (auth ? F_AUTH : 0), NULL, &addr, NULL, 0); - continue; + goto done; } 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; 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 */ 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->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->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); return resize_packet(header, ansp - (unsigned char *)header, NULL, 0); } diff --git a/src/cache.c b/src/cache.c index 1bd1a22..5cae80c 100644 --- a/src/cache.c +++ b/src/cache.c @@ -2180,7 +2180,8 @@ void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg, char *extra = ""; char *gap = " "; char portstring[7]; /* space for # */ - + char opcodestring[3]; /* maximum is 15 */ + if (!option_bool(OPT_LOG)) return; @@ -2189,7 +2190,7 @@ void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg, return; /* 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); dest = arg; @@ -2282,6 +2283,8 @@ void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg, source = arg; else if (flags & F_UPSTREAM) source = "reply"; + else if (flags & F_AUTH) + source = "auth"; else if (flags & F_SECSTAT) { 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"; dest = arg; } - else if (flags & F_AUTH) - source = "auth"; else if (flags & F_DNSSEC) { source = arg; @@ -2304,11 +2305,6 @@ void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg, source = "forwarded"; verb = "to"; } - else if (flags & F_QUERY) - { - source = arg; - verb = "from"; - } else if (flags & F_IPSET) { 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"; else 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) gap = name = ""; else if (!name[0]) diff --git a/src/forward.c b/src/forward.c index 79830c9..8950304 100644 --- a/src/forward.c +++ b/src/forward.c @@ -1816,14 +1816,14 @@ void receive_query(struct listener *listen, time_t now) #endif 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)) { #ifdef HAVE_AUTH struct auth_zone *zone; #endif - log_query_mysockaddr((auth_dns ? F_NOERR : 0 ) | F_QUERY | F_FORWARD, daemon->namebuff, - &source_addr, auth_dns ? "auth" : "query", type); + log_query_mysockaddr((auth_dns ? F_NOERR | F_AUTH : 0 ) | F_QUERY | F_FORWARD, daemon->namebuff, + &source_addr, NULL, type); #ifdef HAVE_AUTH /* 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) { - 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; 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_size = size; - log_query_mysockaddr((auth_dns ? F_NOERR : 0) | F_QUERY | F_FORWARD, daemon->namebuff, - &peer_addr, auth_dns ? "auth" : "query", qtype); + log_query_mysockaddr((auth_dns ? F_NOERR | F_AUTH : 0) | F_QUERY | F_FORWARD, daemon->namebuff, + &peer_addr, NULL, qtype); #ifdef HAVE_AUTH /* Find queries for zones we're authoritative for, and answer them directly. -- 2.20.1