Commit 288df49c authored by Simon Kelley's avatar Simon Kelley

Fix bug when resulted in NXDOMAIN answers instead of NODATA.

check_for_local_domain() was broken due to new code matching F_*
bits in cache entries for DNSSEC. Because F_DNSKEY | F_DS is
used to match RRSIG entries, cache_find_by_name() insists on an exact match
of those bits. So adding F_DS to the bits that check_for_local_domain()
sends to cache_find_by_name() won't result in DS records as well
as the others, it results in only DS records. Add a new bit, F_NSIGMATCH
which suitably changes the behaviour of cache_find_by_name().
parent 10cfc0dd
...@@ -31,6 +31,9 @@ version 2.72 ...@@ -31,6 +31,9 @@ version 2.72
--conf-dir=/etc/dnsmasq.d,\*.conf --conf-dir=/etc/dnsmasq.d,\*.conf
will load all the files in /etc/dnsmasq.d which end in .conf will load all the files in /etc/dnsmasq.d which end in .conf
Fix bug when resulted in NXDOMAIN answers instead of NODATA in
some circumstances.
version 2.71 version 2.71
Subtle change to error handling to help DNSSEC validation Subtle change to error handling to help DNSSEC validation
......
...@@ -636,7 +636,7 @@ struct crec *cache_find_by_name(struct crec *crecp, char *name, time_t now, unsi ...@@ -636,7 +636,7 @@ struct crec *cache_find_by_name(struct crec *crecp, char *name, time_t now, unsi
{ {
if ((crecp->flags & F_FORWARD) && if ((crecp->flags & F_FORWARD) &&
#ifdef HAVE_DNSSEC #ifdef HAVE_DNSSEC
((crecp->flags & (F_DNSKEY | F_DS)) == (prot & (F_DNSKEY | F_DS))) && (((crecp->flags & (F_DNSKEY | F_DS)) == (prot & (F_DNSKEY | F_DS))) || (prot & F_NSIGMATCH)) &&
#endif #endif
(crecp->flags & prot) && (crecp->flags & prot) &&
hostname_isequal(cache_get_name(crecp), name)) hostname_isequal(cache_get_name(crecp), name))
...@@ -696,7 +696,7 @@ struct crec *cache_find_by_name(struct crec *crecp, char *name, time_t now, unsi ...@@ -696,7 +696,7 @@ struct crec *cache_find_by_name(struct crec *crecp, char *name, time_t now, unsi
if (ans && if (ans &&
(ans->flags & F_FORWARD) && (ans->flags & F_FORWARD) &&
#ifdef HAVE_DNSSEC #ifdef HAVE_DNSSEC
((ans->flags & (F_DNSKEY | F_DS)) == (prot & (F_DNSKEY | F_DS))) && (((ans->flags & (F_DNSKEY | F_DS)) == (prot & (F_DNSKEY | F_DS))) || (prot & F_NSIGMATCH)) &&
#endif #endif
(ans->flags & prot) && (ans->flags & prot) &&
hostname_isequal(cache_get_name(ans), name)) hostname_isequal(cache_get_name(ans), name))
......
...@@ -440,6 +440,7 @@ struct crec { ...@@ -440,6 +440,7 @@ struct crec {
#define F_SECSTAT (1u<<24) #define F_SECSTAT (1u<<24)
#define F_NO_RR (1u<<25) #define F_NO_RR (1u<<25)
#define F_IPSET (1u<<26) #define F_IPSET (1u<<26)
#define F_NSIGMATCH (1u<<27)
/* Values of uid in crecs with F_CONFIG bit set. */ /* Values of uid in crecs with F_CONFIG bit set. */
#define SRC_INTERFACE 0 #define SRC_INTERFACE 0
......
...@@ -1246,7 +1246,12 @@ int check_for_local_domain(char *name, time_t now) ...@@ -1246,7 +1246,12 @@ int check_for_local_domain(char *name, time_t now)
struct ptr_record *ptr; struct ptr_record *ptr;
struct naptr *naptr; struct naptr *naptr;
if ((crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6 | F_CNAME | F_DS | F_NO_RR)) && /* Note: the call to cache_find_by_name is intended to find any record which matches
ie A, AAAA, CNAME, DS. Because RRSIG records are marked by setting both F_DS and F_DNSKEY,
cache_find_by name ordinarily only returns records with an exact match on those bits (ie
for the call below, only DS records). The F_NSIGMATCH bit changes this behaviour */
if ((crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6 | F_CNAME | F_DS | F_NO_RR | F_NSIGMATCH)) &&
(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG))) (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
return 1; return 1;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment