Fix bug in 0x20 encoding.
authorSimon Kelley <simon@thekelleys.org.uk>
Thu, 6 Feb 2025 10:32:29 +0000 (10:32 +0000)
committerSimon Kelley <simon@thekelleys.org.uk>
Thu, 6 Feb 2025 10:36:21 +0000 (10:36 +0000)
We must only compare case when mapping an answer from upstream
to a forwarding record, not when checking a query to see if it's a
duplicate. Since the saved query name is scrambled, that ensures
that almost all such checks will wrongly fail.

Thanks to Peter Tirsek for an exemplary bug report for this.

src/dnsmasq.h
src/forward.c

index d563bf7..9996599 100644 (file)
@@ -775,6 +775,7 @@ struct dyndir {
 #define FREC_DO_QUESTION       64
 #define FREC_HAS_PHEADER      128
 #define FREC_GONE_TO_TCP      256
+#define FREC_ANSWER           512
 
 struct frec {
   struct frec_src {
index 08f229b..87035ed 100644 (file)
@@ -1098,7 +1098,7 @@ void reply_query(int fd, time_t now)
   GETSHORT(rrtype, p); 
   GETSHORT(class, p);
 
-  if (!(forward = lookup_frec(daemon->namebuff, class, rrtype, ntohs(header->id), 0, 0)))
+  if (!(forward = lookup_frec(daemon->namebuff, class, rrtype, ntohs(header->id), FREC_ANSWER, 0)))
     return;
 
   filter_servers(forward->sentto->arrayposn, F_SERVER, &first, &last);
@@ -3057,6 +3057,16 @@ static struct frec *lookup_frec(char *target, int class, int rrtype, int id, int
 {
   struct frec *f;
   struct dns_header *header;
+  int compare_mode = EXTR_NAME_COMPARE;
+
+  /* Only compare case-sensitive when matching frec to a an recieved anwer,
+     not when looking for a duplicated question. */
+  if (flags & FREC_ANSWER)
+    {
+      flags &= ~FREC_ANSWER;
+      if (!option_bool(OPT_NO_0x20))
+       compare_mode = EXTR_NAME_NOCASE;
+    }
   
   for (f = daemon->frec_list; f; f = f->next)
     if (f->sentto &&
@@ -3068,7 +3078,7 @@ static struct frec *lookup_frec(char *target, int class, int rrtype, int id, int
        int hclass, hrrtype, rc;
 
        /* Case sensitive compare for DNS-0x20 encoding. */
-       if ((rc = extract_name(header, f->stash_len, &p, target, option_bool(OPT_NO_0x20) ? EXTR_NAME_COMPARE : EXTR_NAME_NOCASE, 4)))
+       if ((rc = extract_name(header, f->stash_len, &p, target, compare_mode, 4)))
          {
            GETSHORT(hrrtype, p);
            GETSHORT(hclass, p);