mirror of
https://github.com/pi-hole/dnsmasq.git
synced 2025-12-19 10:18:25 +00:00
Fix for case-sensitivity problems in DNS.
Fix a case sensitivity problem which has been lurking for a long while. When we get example.com and Example.com and combine them, we send whichever query arrives first upstream and then later answer it, and we also answer the second with the same answer. That means that if example.com arrives first, it will get the answer example.com - good - but Example.com will _also_ get the answer example.com - not so good. In theory, fixing this is simple without having to keep seperate copies of all the queries: Just use the bit-vector representation of case flipping that we have for 0x20-encoding to keep the differences in case. The complication comes from the fact that the existing bit-vector code only holds data on the first 32 alpha letters, because we only flip that up to many for 0x20 encoding. In practise, the delta between combined queries can almost always be represented with that data, since almost all queries are all lower case and we only purturb the first 32 letters with 0x20 encoding. It's therefore worth keeping the existing, efficient data structure for the 99.9% of the time it works. For the 0.1% it doesn't, however, one needs an arbitrary-length data structure with the resource implications of that. Thanks to Peter Tirsek for the well researched bug report which set me on to these problems.
This commit is contained in:
@@ -19,7 +19,11 @@
|
||||
/* EXTR_NAME_EXTRACT -> extract name
|
||||
EXTR_NAME_COMPARE -> compare name, case insensitive
|
||||
EXTR_NAME_NOCASE -> compare name, case sensitive
|
||||
EXTR_NAME_FLIP -> flip 0x20 bits in packet, controlled by bitmap in parm. name may be NULL
|
||||
EXTR_NAME_FLIP -> flip 0x20 bits in packet.
|
||||
|
||||
For flip, name is an array of ints, whose size
|
||||
is given in parm, which forms the bitmap. Bits beyond the size
|
||||
are assumed to be zero.
|
||||
|
||||
return = 0 -> error
|
||||
return = 1 -> extract OK, compare OK, flip OK
|
||||
@@ -31,14 +35,21 @@ int extract_name(struct dns_header *header, size_t plen, unsigned char **pp,
|
||||
{
|
||||
unsigned char *cp = (unsigned char *)name, *p = *pp, *p1 = NULL;
|
||||
unsigned int j, l, namelen = 0, hops = 0;
|
||||
unsigned int bigmap_counter = 0, bigmap_posn = 0, bigmap_size, bitmap;
|
||||
int retvalue = 1, case_insens = 1, isExtract = 0, flip = 0, extrabytes = (int)parm;
|
||||
|
||||
unsigned int *bigmap;
|
||||
|
||||
if (func == EXTR_NAME_EXTRACT)
|
||||
isExtract = 1, *cp = 0;
|
||||
else if (func == EXTR_NAME_NOCASE)
|
||||
case_insens = 0;
|
||||
else if (func == EXTR_NAME_FLIP)
|
||||
flip = 1, extrabytes = 0;
|
||||
{
|
||||
flip = 1, extrabytes = 0;
|
||||
bigmap = (unsigned int *)name;
|
||||
name = NULL;
|
||||
bigmap_size = parm;
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
@@ -116,12 +127,18 @@ int extract_name(struct dns_header *header, size_t plen, unsigned char **pp,
|
||||
{
|
||||
unsigned char c = *p;
|
||||
|
||||
/* parm is unsigned. We only flip up to the first 32 alpha-chars. */
|
||||
if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
|
||||
{
|
||||
if (parm & 1)
|
||||
/* Get the next int of the bitmap */
|
||||
if (bigmap_posn < bigmap_size && bigmap_counter-- == 0)
|
||||
{
|
||||
bitmap = bigmap[bigmap_posn++];
|
||||
bigmap_counter = (sizeof(unsigned int) * 8) - 1;
|
||||
}
|
||||
|
||||
if (bitmap & 1)
|
||||
*p ^= 0x20;
|
||||
parm >>= 1;
|
||||
bitmap >>= 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
Reference in New Issue
Block a user