summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Kelley <simon@thekelleys.org.uk>2015-07-16 22:23:13 +0100
committerSimon Kelley <simon@thekelleys.org.uk>2015-07-16 22:23:13 +0100
commit13480e8c2a0e170a5e070f82c46e6ae00c464a89 (patch)
tree62470036a3d21f84a9632b8666726190e293b9c2
parent5b3b93f80a1f555e9f42e13de27abf34c8190402 (diff)
downloaddnsmasq-2.74rc2.tar.gz
DNSSEC fix, signed wildcard CNAME to unsigned domain.v2.74rc2
-rw-r--r--CHANGELOG4
-rw-r--r--src/dnssec.c42
2 files changed, 45 insertions, 1 deletions
diff --git a/CHANGELOG b/CHANGELOG
index 0eb3c0c..7c621e2 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -5,6 +5,10 @@ version 2.74
Fix inotify code to handle dangling symlinks better and
not SEGV in some circumstances.
+ DNSSEC fix. In the case of a signed CNAME generated by a
+ wildcard which pointed to an unsigned domain, the wrong
+ status would be logged, and some necessary checks omitted.
+
version 2.73
Fix crash at startup when an empty suffix is supplied to
diff --git a/src/dnssec.c b/src/dnssec.c
index 52d1454..5fb375c 100644
--- a/src/dnssec.c
+++ b/src/dnssec.c
@@ -2112,6 +2112,7 @@ int dnssec_chase_cname(time_t now, struct dns_header *header, size_t plen, char
unsigned char *p = (unsigned char *)(header+1);
int type, class, qclass, rdlen, j, rc;
int cname_count = CNAME_CHAIN;
+ char *wildname;
/* Get question */
if (!extract_name(header, plen, &p, name, 1, 4))
@@ -2145,7 +2146,46 @@ int dnssec_chase_cname(time_t now, struct dns_header *header, size_t plen, char
return STAT_INSECURE;
/* validate CNAME chain, return if insecure or need more data */
- rc = validate_rrset(now, header, plen, class, type, name, keyname, NULL, NULL, 0, 0, 0);
+ rc = validate_rrset(now, header, plen, class, type, name, keyname, &wildname, NULL, 0, 0, 0);
+
+ if (rc == STAT_SECURE_WILDCARD)
+ {
+ int nsec_type, nsec_count, i;
+ unsigned char **nsecs;
+
+ /* An attacker can replay a wildcard answer with a different
+ answer and overlay a genuine RR. To prove this
+ hasn't happened, the answer must prove that
+ the genuine record doesn't exist. Check that here. */
+ if (!(nsec_type = find_nsec_records(header, plen, &nsecs, &nsec_count, class)))
+ return STAT_BOGUS; /* No NSECs or bad packet */
+
+ /* Note that we're called here because something didn't validate in validate_reply,
+ so we can't assume that any NSEC records have been validated. We do them by steam here */
+
+ for (i = 0; i < nsec_count; i++)
+ {
+ unsigned char *p1 = nsecs[i];
+
+ if (!extract_name(header, plen, &p1, daemon->workspacename, 1, 0))
+ return STAT_BOGUS;
+
+ rc = validate_rrset(now, header, plen, class, nsec_type, daemon->workspacename, keyname, NULL, NULL, 0, 0, 0);
+
+ if (rc != STAT_SECURE)
+ return rc;
+ }
+
+ if (nsec_type == T_NSEC)
+ rc = prove_non_existence_nsec(header, plen, nsecs, nsec_count, daemon->workspacename, keyname, name, type, NULL);
+ else
+ rc = prove_non_existence_nsec3(header, plen, nsecs, nsec_count, daemon->workspacename,
+ keyname, name, type, wildname, NULL);
+
+ if (rc != STAT_SECURE)
+ return rc;
+ }
+
if (rc != STAT_SECURE)
{
if (rc == STAT_NO_SIG)