Tidy up replies to non-QUERY DNS opcodes in auth mode.
authorSimon Kelley <simon@thekelleys.org.uk>
Tue, 22 Apr 2025 17:07:24 +0000 (18:07 +0100)
committerSimon Kelley <simon@thekelleys.org.uk>
Tue, 22 Apr 2025 17:07:24 +0000 (18:07 +0100)
src/auth.c
src/cache.c
src/forward.c

index b2cee26..7c34522 100644 (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;
   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);
     }
index 1bd1a22..5cae80c 100644 (file)
@@ -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 #<portnum> */
-  
+  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])
index 79830c9..8950304 100644 (file)
@@ -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.