Case-sensitive matching of questions and answers.

When checking that an answer is the answer to the question that
we asked, compare the name in a case-sensitive manner.

Clients can set the letters in a query to a random pattern of
uppercase and lowercase to add more randomness as protection against
cache-poisoning attacks, and we don't want to nullify that.

This actually restores the status quo before
commit ed6d29a784
since matching questions and answers using a checksum
can't help but be case sensitive.

This patch is a preparation for introducing DNS-0x20
in the dnsmasq query path.
This commit is contained in:
Simon Kelley
2025-01-19 00:08:36 +00:00
parent b72ecb3a59
commit 65f9c1aca1
2 changed files with 23 additions and 10 deletions

View File

@@ -1999,12 +1999,14 @@ static ssize_t tcp_talk(int first, int last, int start, unsigned char *packet,
continue;
}
/* If the question section of the reply doesn't match the crc we sent, then
/* If the question section of the reply doesn't match the question we sent, then
someone might be attempting to insert bogus values into the cache by
sending replies containing questions and bogus answers.
We compare the query name in a case sensitive manner, so that
DNS-0x20 encoding is effective.
Try another server, or give up */
p = (unsigned char *)(header+1);
if (extract_name(header, rsize, &p, daemon->namebuff, 0, 4) != 1)
if (extract_name(header, rsize, &p, daemon->namebuff, -1, 4) != 1)
continue;
GETSHORT(rtype, p);
GETSHORT(rclass, p);
@@ -3046,7 +3048,8 @@ static struct frec *lookup_frec(char *target, int class, int rrtype, int id, int
unsigned char *p = (unsigned char *)(header+1);
int hclass, hrrtype;
if (extract_name(header, f->stash_len, &p, target, 0, 4) != 1)
/* Case sensitive compare for DNS-0x20 encoding. */
if (extract_name(header, f->stash_len, &p, target, -1, 4) != 1)
continue;
GETSHORT(hrrtype, p);

View File

@@ -16,14 +16,24 @@
#include "dnsmasq.h"
/* isExtract == 1 -> extract name
isExtract == 0 -> compare name, case insensitive
isExtract == -1 -> compare name, case sensitive
return = 0 -> error
return = 1 -> extract OK, compare OK
return = 2 -> extract OK, compare failed.
*/
int extract_name(struct dns_header *header, size_t plen, unsigned char **pp,
char *name, int isExtract, int extrabytes)
{
unsigned char *cp = (unsigned char *)name, *p = *pp, *p1 = NULL;
unsigned int j, l, namelen = 0, hops = 0;
int retvalue = 1;
int retvalue = 1, case_insens = 1;
if (isExtract)
if (isExtract == -1)
isExtract = case_insens = 0;
else if (isExtract)
*cp = 0;
while (1)
@@ -107,13 +117,13 @@ int extract_name(struct dns_header *header, size_t plen, unsigned char **pp,
else
{
cp++;
if (c1 >= 'A' && c1 <= 'Z')
if (case_insens && c1 >= 'A' && c1 <= 'Z')
c1 += 'a' - 'A';
if (c1 == NAME_ESCAPE)
c1 = (*cp++)-1;
if (c2 >= 'A' && c2 <= 'Z')
if (case_insens && c2 >= 'A' && c2 <= 'Z')
c2 += 'a' - 'A';
if (c1 != c2)