summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2015-12-21 20:00:34 +0100
committerLennart Poettering <lennart@poettering.net>2015-12-26 19:09:10 +0100
commit13b78323bad1e41e0474b833da2a0b72aab56f09 (patch)
treeb6ea500391cf2f41aa5fe3f66624afc8621524c0
parente7ff0e0b391341bdc4d9c08dff1c477e1df6a682 (diff)
resolved: when doing NSEC3 proof, first find right NSEC3 suffix
When doing an NSEC3 proof, before detrmining whether a name is the closest encloser we first need to figure out the longest common suffix we have with any NSEC3 RR in the reply.
-rw-r--r--src/resolve/resolved-dns-dnssec.c47
1 files changed, 41 insertions, 6 deletions
diff --git a/src/resolve/resolved-dns-dnssec.c b/src/resolve/resolved-dns-dnssec.c
index 9ddad38fa6..dbda71b03d 100644
--- a/src/resolve/resolved-dns-dnssec.c
+++ b/src/resolve/resolved-dns-dnssec.c
@@ -912,7 +912,7 @@ finish:
static int dnssec_test_nsec3(DnsAnswer *answer, DnsResourceKey *key, DnssecNsecResult *result) {
_cleanup_free_ char *next_closer_domain = NULL, *l = NULL;
uint8_t hashed[DNSSEC_HASH_SIZE_MAX];
- const char *p, *pp = NULL;
+ const char *suffix, *p, *pp = NULL;
DnsResourceRecord *rr;
DnsAnswerFlags flags;
int hashed_size, r;
@@ -920,7 +920,42 @@ static int dnssec_test_nsec3(DnsAnswer *answer, DnsResourceKey *key, DnssecNsecR
assert(key);
assert(result);
- /* First step, look for the closest encloser NSEC3 RR in 'answer' that matches 'key' */
+ /* First step, look for the longest common suffix we find with any NSEC3 RR in the response. */
+ suffix = DNS_RESOURCE_KEY_NAME(key);
+ for (;;) {
+ DNS_ANSWER_FOREACH_FLAGS(rr, flags, answer) {
+ _cleanup_free_ char *hashed_domain = NULL, *label = NULL;
+
+ if ((flags & DNS_ANSWER_AUTHENTICATED) == 0)
+ continue;
+
+ if (rr->key->type != DNS_TYPE_NSEC3)
+ continue;
+
+ /* RFC 5155, Section 8.2 says we MUST ignore NSEC3 RRs with flags != 0 or 1 */
+ if (!IN_SET(rr->nsec3.flags, 0, 1))
+ continue;
+
+ r = dns_name_endswith(DNS_RESOURCE_KEY_NAME(rr->key), suffix);
+ if (r < 0)
+ return r;
+ if (r > 0)
+ goto found_suffix;
+ }
+
+ /* Strip one label from the front */
+ r = dns_name_parent(&suffix);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ break;
+ }
+
+ *result = DNSSEC_NSEC_NO_RR;
+ return 0;
+
+found_suffix:
+ /* Second step, find the closest encloser NSEC3 RR in 'answer' that matches 'key' */
p = DNS_RESOURCE_KEY_NAME(key);
for (;;) {
DNS_ANSWER_FOREACH_FLAGS(rr, flags, answer) {
@@ -936,7 +971,7 @@ static int dnssec_test_nsec3(DnsAnswer *answer, DnsResourceKey *key, DnssecNsecR
if (!IN_SET(rr->nsec3.flags, 0, 1))
continue;
- r = dns_name_endswith(DNS_RESOURCE_KEY_NAME(rr->key), p);
+ r = dns_name_endswith(DNS_RESOURCE_KEY_NAME(rr->key), suffix);
if (r < 0)
return r;
if (r == 0)
@@ -956,7 +991,7 @@ static int dnssec_test_nsec3(DnsAnswer *answer, DnsResourceKey *key, DnssecNsecR
if (!label)
return -ENOMEM;
- hashed_domain = strjoin(label, ".", p, NULL);
+ hashed_domain = strjoin(label, ".", suffix, NULL);
if (!hashed_domain)
return -ENOMEM;
@@ -964,7 +999,7 @@ static int dnssec_test_nsec3(DnsAnswer *answer, DnsResourceKey *key, DnssecNsecR
if (r < 0)
return r;
if (r > 0)
- goto found;
+ goto found_closest_encloser;
}
/* We didn't find the closest encloser with this name,
@@ -984,7 +1019,7 @@ static int dnssec_test_nsec3(DnsAnswer *answer, DnsResourceKey *key, DnssecNsecR
*result = DNSSEC_NSEC_NO_RR;
return 0;
-found:
+found_closest_encloser:
/* We found a closest encloser in 'p'; next closer is 'pp' */
/* Ensure this is not a DNAME domain, see RFC5155, section 8.3. */