summary refs log tree commit diff
diff options
context:
space:
mode:
authorLaurent Bercot <ska-skaware@skarnet.org>2021-01-19 22:34:30 +0000
committerLaurent Bercot <ska-skaware@skarnet.org>2021-01-19 22:34:30 +0000
commitd32f5bf90638a7ba2aa6cf8ff6c6ae2b313a9bc1 (patch)
tree02d8e5eb259a302a87c1423009fd20213917c1d5
parent6712287e957ba895aa29a82a7718e6cf33a2aaa0 (diff)
downloaddnsfunnel-d32f5bf90638a7ba2aa6cf8ff6c6ae2b313a9bc1.tar.gz
dnsfunnel-d32f5bf90638a7ba2aa6cf8ff6c6ae2b313a9bc1.tar.xz
dnsfunnel-d32f5bf90638a7ba2aa6cf8ff6c6ae2b313a9bc1.zip
Fix bugs in aux query management
-rw-r--r--src/dnsfunnel/dnsfunneld.h6
-rw-r--r--src/dnsfunnel/dnsfunneld_answer.c32
-rw-r--r--src/dnsfunnel/dnsfunneld_process.c17
3 files changed, 35 insertions, 20 deletions
diff --git a/src/dnsfunnel/dnsfunneld.h b/src/dnsfunnel/dnsfunneld.h
index 9fc0bbf..4b9acd3 100644
--- a/src/dnsfunnel/dnsfunneld.h
+++ b/src/dnsfunnel/dnsfunneld.h
@@ -27,9 +27,9 @@ struct dfquery_s
 extern unsigned int verbosity ;
 extern size_t dfanswer_pending (void) ;
 extern int dfanswer_flush (void) ;
-extern void dfanswer_fail (dfquery_t const *) ;
-extern void dfanswer_nxdomain (dfquery_t const *) ;
-extern void dfanswer_nodata (dfquery_t const *) ;
+extern void dfanswer_fail (dfquery_t const *, int) ;
+extern void dfanswer_nxdomain (dfquery_t const *, int) ;
+extern void dfanswer_nodata (dfquery_t const *, int) ;
 extern void dfanswer_pass (dfquery_t const *, char *, unsigned int) ;
 
 
diff --git a/src/dnsfunnel/dnsfunneld_answer.c b/src/dnsfunnel/dnsfunneld_answer.c
index e0fed6e..7793074 100644
--- a/src/dnsfunnel/dnsfunneld_answer.c
+++ b/src/dnsfunnel/dnsfunneld_answer.c
@@ -1,7 +1,5 @@
 /* ISC license. */
 
-#define DEBUG
-
 #include <errno.h>
 #include <stdint.h>
 #include <string.h>
@@ -13,6 +11,7 @@
 #include <skalibs/stralloc.h>
 #include <skalibs/socket.h>
 
+#include <s6-dns/s6dns-constants.h>
 #include <s6-dns/s6dns-message.h>
 
 #include "dnsfunneld.h"
@@ -62,11 +61,25 @@ int dfanswer_flush ()
   return 1 ;
 }
 
-void dfanswer_fail (dfquery_t const *q)
+static void switchaux (char *buf, uint16_t len)
+{
+  uint16_t qtype ;
+  uint16_unpack_big(buf + len - 4, &qtype) ;
+  switch (qtype)
+  {
+    case S6DNS_T_A : qtype = S6DNS_T_AAAA ; break ;
+    case S6DNS_T_AAAA : qtype = S6DNS_T_A ; break ;
+    default : strerr_dief1x(101, "can't happen: invalid qtype in auxiliary query") ;
+  }
+  uint16_pack_big(buf + len - 4, qtype) ;
+}
+
+
+void dfanswer_fail (dfquery_t const *q, int isaux)
 {
   char buf[512] ;
-  uint16_t len ;
   s6dns_message_header_t hdr ;
+  uint16_t len ;
   uint16_unpack_big(q->dt.sa.s, &len) ;
   memcpy(buf, q->dt.sa.s + 2, len) ;
   s6dns_message_header_unpack(buf, &hdr) ;
@@ -79,14 +92,15 @@ void dfanswer_fail (dfquery_t const *q)
   hdr.z = 0 ;
   hdr.rcode = 2 ;  /* servfail */
   s6dns_message_header_pack(buf, &hdr) ;
+  if (isaux) switchaux(buf, len) ;
   dfanswer_push(buf, len, q->ip, q->port) ;
 }
 
-void dfanswer_nxdomain (dfquery_t const *q)
+void dfanswer_nxdomain (dfquery_t const *q, int isaux)
 {
   char buf[512] ;
-  uint16_t len ;
   s6dns_message_header_t hdr ;
+  uint16_t len ;
   uint16_unpack_big(q->dt.sa.s, &len) ;
   memcpy(buf, q->dt.sa.s + 2, len) ;
   s6dns_message_header_unpack(buf, &hdr) ;
@@ -99,14 +113,15 @@ void dfanswer_nxdomain (dfquery_t const *q)
   hdr.z = 0 ;
   hdr.rcode = 3 ;  /* nxdomain */
   s6dns_message_header_pack(buf, &hdr) ;
+  if (isaux) switchaux(buf, len) ;
   dfanswer_push(buf, len, q->ip, q->port) ;
 }
 
-void dfanswer_nodata (dfquery_t const *q)
+void dfanswer_nodata (dfquery_t const *q, int isaux)
 {
   char buf[512] ;
-  uint16_t len ;
   s6dns_message_header_t hdr ;
+  uint16_t len ;
   uint16_unpack_big(q->dt.sa.s, &len) ;
   memcpy(buf, q->dt.sa.s + 2, len) ;
   s6dns_message_header_unpack(buf, &hdr) ;
@@ -119,6 +134,7 @@ void dfanswer_nodata (dfquery_t const *q)
   hdr.z = 0 ;
   hdr.rcode = 0 ;  /* success */
   s6dns_message_header_pack(buf, &hdr) ;
+  if (isaux) switchaux(buf, len) ;
   dfanswer_push(buf, len, q->ip, q->port) ;
 }
 
diff --git a/src/dnsfunnel/dnsfunneld_process.c b/src/dnsfunnel/dnsfunneld_process.c
index 8a0ffe2..f9055ac 100644
--- a/src/dnsfunnel/dnsfunneld_process.c
+++ b/src/dnsfunnel/dnsfunneld_process.c
@@ -104,23 +104,22 @@ static int input_event (dfquery_t const *q, unsigned int ev)
   } ;
   uint8_t b = *RINFO(q->procid - 1) ;
   uint8_t isaux = 3 * (b >> 7 != (extract_qtype(q) == S6DNS_T_AAAA)) ;
-  uint8_t state = (b >> isaux) & 7 ;
+  uint8_t state = b & 7 ;
   uint8_t c = table[state][ev + isaux] ;
   state = c & 7 ;
-  *RINFO(q->procid - 1) = (b & ~(7 << isaux)) | (state << isaux) ;
-  if (c & 0x10) dfanswer_fail(q) ;
-  if (c & 0x20) dfanswer_nxdomain(q) ;
-  if (c & 0x40) dfanswer_nodata(q) ;
-  if (c & 0x80) dfanswer_pass(q, s6dns_engine_packet(&q->dt), s6dns_engine_packetlen(&q->dt)) ;
+  *RINFO(q->procid - 1) = (b & 0xf8) | state ;
+  if (c & 0x10) dfanswer_fail(q, !!isaux) ;
+  if (c & 0x20) dfanswer_nxdomain(q, !!isaux) ;
+  if (c & 0x40) dfanswer_nodata(q, !!isaux) ;
   if (state >= 6) strerr_dief1x(101, "problem in main/aux transition table; please submit a bug-report.") ;
   if (state == 5) gensetdyn_delete(&rinfo, q->procid - 1) ;
-  return !!(c & 0xf0) ;
+  return !(c & 0x80) ;
 }
 
 void query_process_response_failure (uint32_t ops, dfquery_t const *q)
 {
   if (ops & 2 && q->procid && input_event(q, 0)) return ;
-  else dfanswer_fail(q) ;
+  else dfanswer_fail(q, 0) ;
 }
 
 void query_process_response_success (uint32_t ops, dfquery_t const *q)
@@ -129,7 +128,7 @@ void query_process_response_success (uint32_t ops, dfquery_t const *q)
   if (ops & 1 && s6dns_engine_packetlen(&q->dt) > 512)
   {
     unsigned int len = truncate_packet(s6dns_engine_packet(&q->dt), s6dns_engine_packetlen(&q->dt)) ;
-    if (!len) dfanswer_fail(q) ;
+    if (!len) dfanswer_fail(q, 0) ;
     else dfanswer_pass(q, s6dns_engine_packet(&q->dt), len) ;
   }
   else dfanswer_pass(q, s6dns_engine_packet(&q->dt), s6dns_engine_packetlen(&q->dt)) ;