mirror of
https://github.com/pi-hole/dnsmasq.git
synced 2025-12-19 18:28:25 +00:00
Correct domain search algorithm.
For reasons unknown, I (srk) assumed that the orginal substring domain matching algorithm was still in use, where example.comKevin Darbyshire-Bryant <kevin@darbyshire-bryant.me.uk> would match eg. sexample.com In fact the far more sensible label-based match, where example.com (or .example.com) matches example.com and www.example.com, but not sexample.com, has been in use since release 2.22. This commit implements the 2.22 to 2.85 behaviour in the new domain-search code. Thanks to Kevin Darbyshire-Bryant for spotting my mistake.
This commit is contained in:
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
#include "dnsmasq.h"
|
#include "dnsmasq.h"
|
||||||
|
|
||||||
static int order(char *qdomain, int leading_dot, size_t qlen, struct server *serv);
|
static int order(char *qdomain, size_t qlen, struct server *serv);
|
||||||
static int order_qsort(const void *a, const void *b);
|
static int order_qsort(const void *a, const void *b);
|
||||||
static int order_servers(struct server *s, struct server *s2);
|
static int order_servers(struct server *s, struct server *s2);
|
||||||
|
|
||||||
@@ -81,7 +81,7 @@ void build_server_array(void)
|
|||||||
*/
|
*/
|
||||||
int lookup_domain(char *qdomain, int flags, int *lowout, int *highout)
|
int lookup_domain(char *qdomain, int flags, int *lowout, int *highout)
|
||||||
{
|
{
|
||||||
int rc, crop_query, nodots, leading_dot = 1;
|
int rc, crop_query, nodots;
|
||||||
ssize_t qlen;
|
ssize_t qlen;
|
||||||
int try, high, low = 0;
|
int try, high, low = 0;
|
||||||
int nlow = 0, nhigh = 0;
|
int nlow = 0, nhigh = 0;
|
||||||
@@ -101,13 +101,10 @@ int lookup_domain(char *qdomain, int flags, int *lowout, int *highout)
|
|||||||
if (qlen == 0 || flags & F_DNSSECOK)
|
if (qlen == 0 || flags & F_DNSSECOK)
|
||||||
nodots = 0;
|
nodots = 0;
|
||||||
|
|
||||||
/* account for leading dot */
|
|
||||||
qlen++;
|
|
||||||
|
|
||||||
/* Search shorter and shorter RHS substrings for a match */
|
/* Search shorter and shorter RHS substrings for a match */
|
||||||
while (qlen >= 0)
|
while (qlen >= 0)
|
||||||
{
|
{
|
||||||
/* Note that when we chop off a character, all the possible matches
|
/* Note that when we chop off a label, all the possible matches
|
||||||
MUST be at a larger index than the nearest failing match with one more
|
MUST be at a larger index than the nearest failing match with one more
|
||||||
character, since the array is sorted longest to smallest. Hence
|
character, since the array is sorted longest to smallest. Hence
|
||||||
we don't reset low to zero here, we can go further below and crop the
|
we don't reset low to zero here, we can go further below and crop the
|
||||||
@@ -121,7 +118,7 @@ int lookup_domain(char *qdomain, int flags, int *lowout, int *highout)
|
|||||||
{
|
{
|
||||||
try = (low + high)/2;
|
try = (low + high)/2;
|
||||||
|
|
||||||
if ((rc = order(qdomain, leading_dot, qlen, daemon->serverarray[try])) == 0)
|
if ((rc = order(qdomain, qlen, daemon->serverarray[try])) == 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
@@ -186,13 +183,12 @@ int lookup_domain(char *qdomain, int flags, int *lowout, int *highout)
|
|||||||
if (crop_query == 0)
|
if (crop_query == 0)
|
||||||
crop_query = 1;
|
crop_query = 1;
|
||||||
|
|
||||||
|
/* strip chars off the query based on the largest possible remaining match,
|
||||||
|
then continue to the start of the next label. */
|
||||||
qlen -= crop_query;
|
qlen -= crop_query;
|
||||||
if (leading_dot)
|
|
||||||
{
|
|
||||||
leading_dot = 0;
|
|
||||||
crop_query--;
|
|
||||||
}
|
|
||||||
qdomain += crop_query;
|
qdomain += crop_query;
|
||||||
|
while (qlen > 0 && (*(qdomain-1) != '.'))
|
||||||
|
qlen--, qdomain++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* domain has no dots, and we have at least one server configured to handle such,
|
/* domain has no dots, and we have at least one server configured to handle such,
|
||||||
@@ -418,10 +414,9 @@ int dnssec_server(struct server *server, char *keyname, int *firstp, int *lastp)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* order by size, then by dictionary order */
|
/* order by size, then by dictionary order */
|
||||||
static int order(char *qdomain, int leading_dot, size_t qlen, struct server *serv)
|
static int order(char *qdomain, size_t qlen, struct server *serv)
|
||||||
{
|
{
|
||||||
size_t dlen = 0;
|
size_t dlen = 0;
|
||||||
int rc;
|
|
||||||
|
|
||||||
/* servers for dotless names always sort last
|
/* servers for dotless names always sort last
|
||||||
searched for name is never dotless. */
|
searched for name is never dotless. */
|
||||||
@@ -436,10 +431,7 @@ static int order(char *qdomain, int leading_dot, size_t qlen, struct server *ser
|
|||||||
if (qlen > dlen)
|
if (qlen > dlen)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (leading_dot && (rc = '.' - serv->domain[0]) != 0)
|
return strcmp(qdomain, serv->domain);
|
||||||
return rc;
|
|
||||||
|
|
||||||
return strcmp(qdomain, leading_dot ? &serv->domain[1] : serv->domain);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int order_servers(struct server *s1, struct server *s2)
|
static int order_servers(struct server *s1, struct server *s2)
|
||||||
@@ -450,7 +442,7 @@ static int order_servers(struct server *s1, struct server *s2)
|
|||||||
if (s1->flags & SERV_FOR_NODOTS)
|
if (s1->flags & SERV_FOR_NODOTS)
|
||||||
return (s2->flags & SERV_FOR_NODOTS) ? 0 : 1;
|
return (s2->flags & SERV_FOR_NODOTS) ? 0 : 1;
|
||||||
|
|
||||||
return order(s1->domain, 0, s1->domain_len, s2);
|
return order(s1->domain, s1->domain_len, s2);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int order_qsort(const void *a, const void *b)
|
static int order_qsort(const void *a, const void *b)
|
||||||
|
|||||||
@@ -2656,6 +2656,9 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
|||||||
char *last;
|
char *last;
|
||||||
|
|
||||||
arg++;
|
arg++;
|
||||||
|
/* elide leading dots - they are implied in the search algorithm */
|
||||||
|
while (*arg == '.') arg++;
|
||||||
|
|
||||||
domain = lastdomain = arg;
|
domain = lastdomain = arg;
|
||||||
|
|
||||||
while ((last = split_chr(arg, '/')))
|
while ((last = split_chr(arg, '/')))
|
||||||
|
|||||||
Reference in New Issue
Block a user