diff options
author | Simon Kelley <simon@thekelleys.org.uk> | 2015-07-16 22:23:13 +0100 |
---|---|---|
committer | Simon Kelley <simon@thekelleys.org.uk> | 2015-07-16 22:23:13 +0100 |
commit | 13480e8c2a0e170a5e070f82c46e6ae00c464a89 (patch) | |
tree | 62470036a3d21f84a9632b8666726190e293b9c2 | |
parent | 5b3b93f80a1f555e9f42e13de27abf34c8190402 (diff) | |
download | dnsmasq-2.74rc2.tar.gz |
DNSSEC fix, signed wildcard CNAME to unsigned domain.v2.74rc2
-rw-r--r-- | CHANGELOG | 4 | ||||
-rw-r--r-- | src/dnssec.c | 42 |
2 files changed, 45 insertions, 1 deletions
@@ -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) |