1 From 93be5b1e023b0c661e1ec2cd6d811a8ec9055c49 Mon Sep 17 00:00:00 2001
2 From: Simon Kelley <simon@thekelleys.org.uk>
3 Date: Tue, 15 Dec 2015 12:04:40 +0000
4 Subject: [PATCH] Abandon caching RRSIGs and returning them from cache.
6 The list of exceptions to being able to locally answer
7 cached data for validated records when DNSSEC data is requested
8 was getting too long, so don't ever do that. This means
9 that the cache no longer has to hold RRSIGS and allows
10 us to lose lots of code. Note that cached validated
11 answers are still returned as long as do=0
13 src/cache.c | 38 ++---------
14 src/dnsmasq.h | 10 +--
15 src/dnssec.c | 94 ++++-----------------------
16 src/rfc1035.c | 197 ++++++---------------------------------------------------
17 4 files changed, 42 insertions(+), 297 deletions(-)
19 diff --git a/src/cache.c b/src/cache.c
20 index 1b76b67..51ba7cc 100644
23 @@ -189,12 +189,7 @@ static void cache_hash(struct crec *crecp)
24 static void cache_blockdata_free(struct crec *crecp)
26 if (crecp->flags & F_DNSKEY)
28 - if (crecp->flags & F_DS)
29 - blockdata_free(crecp->addr.sig.keydata);
31 - blockdata_free(crecp->addr.key.keydata);
33 + blockdata_free(crecp->addr.key.keydata);
34 else if ((crecp->flags & F_DS) && !(crecp->flags & F_NEG))
35 blockdata_free(crecp->addr.ds.keydata);
37 @@ -369,13 +364,8 @@ static struct crec *cache_scan_free(char *name, struct all_addr *addr, time_t no
41 - /* Deletion has to be class-sensitive for DS, DNSKEY, RRSIG, also
42 - type-covered sensitive for RRSIG */
43 - if ((flags & (F_DNSKEY | F_DS)) &&
44 - (flags & (F_DNSKEY | F_DS)) == (crecp->flags & (F_DNSKEY | F_DS)) &&
45 - crecp->uid == addr->addr.dnssec.class &&
46 - (!((flags & (F_DS | F_DNSKEY)) == (F_DS | F_DNSKEY)) ||
47 - crecp->addr.sig.type_covered == addr->addr.dnssec.type))
48 + /* Deletion has to be class-sensitive for DS and DNSKEY */
49 + if ((flags & crecp->flags & (F_DNSKEY | F_DS)) && crecp->uid == addr->addr.dnssec.class)
51 if (crecp->flags & F_CONFIG)
53 @@ -532,13 +522,9 @@ struct crec *cache_insert(char *name, struct all_addr *addr,
54 struct all_addr free_addr = new->addr.addr;;
57 - /* For DNSSEC records, addr holds class and type_covered for RRSIG */
58 + /* For DNSSEC records, addr holds class. */
59 if (new->flags & (F_DS | F_DNSKEY))
61 - free_addr.addr.dnssec.class = new->uid;
62 - if ((new->flags & (F_DS | F_DNSKEY)) == (F_DS | F_DNSKEY))
63 - free_addr.addr.dnssec.type = new->addr.sig.type_covered;
65 + free_addr.addr.dnssec.class = new->uid;
68 free_avail = 1; /* Must be free space now. */
69 @@ -653,9 +639,6 @@ struct crec *cache_find_by_name(struct crec *crecp, char *name, time_t now, unsi
70 if (!is_expired(now, crecp) && !is_outdated_cname_pointer(crecp))
72 if ((crecp->flags & F_FORWARD) &&
74 - (((crecp->flags & (F_DNSKEY | F_DS)) == (prot & (F_DNSKEY | F_DS))) || (prot & F_NSIGMATCH)) &&
76 (crecp->flags & prot) &&
77 hostname_isequal(cache_get_name(crecp), name))
79 @@ -713,9 +696,6 @@ struct crec *cache_find_by_name(struct crec *crecp, char *name, time_t now, unsi
82 (ans->flags & F_FORWARD) &&
84 - (((ans->flags & (F_DNSKEY | F_DS)) == (prot & (F_DNSKEY | F_DS))) || (prot & F_NSIGMATCH)) &&
86 (ans->flags & prot) &&
87 hostname_isequal(cache_get_name(ans), name))
89 @@ -1472,11 +1452,7 @@ void dump_cache(time_t now)
91 else if (cache->flags & F_DS)
93 - if (cache->flags & F_DNSKEY)
95 - sprintf(a, "%5u %3u %s", cache->addr.sig.keytag,
96 - cache->addr.sig.algo, querystr("", cache->addr.sig.type_covered));
97 - else if (!(cache->flags & F_NEG))
98 + if (!(cache->flags & F_NEG))
99 sprintf(a, "%5u %3u %3u", cache->addr.ds.keytag,
100 cache->addr.ds.algo, cache->addr.ds.digest);
102 @@ -1502,8 +1478,6 @@ void dump_cache(time_t now)
103 else if (cache->flags & F_CNAME)
106 - else if ((cache->flags & (F_DS | F_DNSKEY)) == (F_DS | F_DNSKEY))
107 - t = "G"; /* DNSKEY and DS set -> RRISG */
108 else if (cache->flags & F_DS)
110 else if (cache->flags & F_DNSKEY)
111 diff --git a/src/dnsmasq.h b/src/dnsmasq.h
112 index 023a1cf..4344cae 100644
115 @@ -398,14 +398,9 @@ struct crec {
117 unsigned char digest;
120 - struct blockdata *keydata;
121 - unsigned short keylen, type_covered, keytag;
125 time_t ttd; /* time to die */
126 - /* used as class if DNSKEY/DS/RRSIG, index to source for F_HOSTS */
127 + /* used as class if DNSKEY/DS, index to source for F_HOSTS */
129 unsigned short flags;
131 @@ -445,8 +440,7 @@ struct crec {
132 #define F_SECSTAT (1u<<24)
133 #define F_NO_RR (1u<<25)
134 #define F_IPSET (1u<<26)
135 -#define F_NSIGMATCH (1u<<27)
136 -#define F_NOEXTRA (1u<<28)
137 +#define F_NOEXTRA (1u<<27)
139 /* Values of uid in crecs with F_CONFIG bit set. */
140 #define SRC_INTERFACE 0
141 diff --git a/src/dnssec.c b/src/dnssec.c
142 index de7b335..1ae03a6 100644
145 @@ -1004,7 +1004,7 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
147 unsigned char *psave, *p = (unsigned char *)(header+1);
148 struct crec *crecp, *recp1;
149 - int rc, j, qtype, qclass, ttl, rdlen, flags, algo, valid, keytag, type_covered;
150 + int rc, j, qtype, qclass, ttl, rdlen, flags, algo, valid, keytag;
151 struct blockdata *key;
154 @@ -1115,7 +1115,7 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
158 - /* DNSKEY RRset determined to be OK, now cache it and the RRsigs that sign it. */
159 + /* DNSKEY RRset determined to be OK, now cache it. */
160 cache_start_insert();
162 p = skip_questions(header, plen);
163 @@ -1155,7 +1155,10 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
164 if ((key = blockdata_alloc((char*)p, rdlen - 4)))
166 if (!(recp1 = cache_insert(name, &a, now, ttl, F_FORWARD | F_DNSKEY | F_DNSSECOK)))
167 - blockdata_free(key);
169 + blockdata_free(key);
174 a.addr.keytag = keytag;
175 @@ -1169,38 +1172,7 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
179 - else if (qtype == T_RRSIG)
181 - /* RRSIG, cache if covers DNSKEY RRset */
183 - return STAT_BOGUS; /* bad packet */
185 - GETSHORT(type_covered, p);
187 - if (type_covered == T_DNSKEY)
189 - a.addr.dnssec.class = class;
190 - a.addr.dnssec.type = type_covered;
193 - p += 13; /* labels, orig_ttl, expiration, inception */
194 - GETSHORT(keytag, p);
195 - if ((key = blockdata_alloc((char*)psave, rdlen)))
197 - if (!(crecp = cache_insert(name, &a, now, ttl, F_FORWARD | F_DNSKEY | F_DS)))
198 - blockdata_free(key);
201 - crecp->addr.sig.keydata = key;
202 - crecp->addr.sig.keylen = rdlen;
203 - crecp->addr.sig.keytag = keytag;
204 - crecp->addr.sig.type_covered = type_covered;
205 - crecp->addr.sig.algo = algo;
215 @@ -1326,7 +1298,8 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
216 cache_start_insert();
218 a.addr.dnssec.class = class;
219 - cache_insert(name, &a, now, ttl, flags);
220 + if (!cache_insert(name, &a, now, ttl, flags))
225 @@ -2028,14 +2001,13 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
226 /* Not done, validate now */
229 - int ttl, keytag, algo, digest, type_covered, sigcnt, rrcnt;
230 + int ttl, keytag, algo, digest, sigcnt, rrcnt;
231 unsigned char *psave;
233 struct blockdata *key;
236 - int have_wildcard = 0;
239 if (!explore_rrset(header, plen, class1, type1, name, keyname, &sigcnt, &rrcnt))
242 @@ -2096,8 +2068,6 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
244 if (rc == STAT_SECURE_WILDCARD)
248 /* An attacker replay a wildcard answer with a different
249 answer and overlay a genuine RR. To prove this
250 hasn't happened, the answer must prove that
251 @@ -2119,7 +2089,7 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
255 - /* Cache RRsigs in answer section, and if we just validated a DS RRset, cache it */
256 + /* If we just validated a DS RRset, cache it */
257 /* Also note if the RRset is the answer to the question, or the target of a CNAME */
258 cache_start_insert();
260 @@ -2168,45 +2138,7 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
264 - else if (type2 == T_RRSIG)
267 - return STAT_BOGUS; /* bad packet */
269 - GETSHORT(type_covered, p2);
271 - if (type_covered == type1 &&
272 - (type_covered == T_A || type_covered == T_AAAA ||
273 - type_covered == T_CNAME || type_covered == T_DS ||
274 - type_covered == T_DNSKEY || type_covered == T_PTR))
276 - a.addr.dnssec.type = type_covered;
277 - a.addr.dnssec.class = class1;
280 - p2 += 13; /* labels, orig_ttl, expiration, inception */
281 - GETSHORT(keytag, p2);
283 - /* We don't cache sigs for wildcard answers, because to reproduce the
284 - answer from the cache will require one or more NSEC/NSEC3 records
285 - which we don't cache. The lack of the RRSIG ensures that a query for
286 - this RRset asking for a secure answer will always be forwarded. */
287 - if (!have_wildcard && (key = blockdata_alloc((char*)psave, rdlen2)))
289 - if (!(crecp = cache_insert(name, &a, now, ttl, F_FORWARD | F_DNSKEY | F_DS)))
290 - blockdata_free(key);
293 - crecp->addr.sig.keydata = key;
294 - crecp->addr.sig.keylen = rdlen2;
295 - crecp->addr.sig.keytag = keytag;
296 - crecp->addr.sig.type_covered = type_covered;
297 - crecp->addr.sig.algo = algo;
307 diff --git a/src/rfc1035.c b/src/rfc1035.c
308 index 4eb1772..def8fa0 100644
311 @@ -1275,11 +1275,9 @@ int check_for_local_domain(char *name, time_t now)
314 /* Note: the call to cache_find_by_name is intended to find any record which matches
315 - ie A, AAAA, CNAME, DS. Because RRSIG records are marked by setting both F_DS and F_DNSKEY,
316 - cache_find_by name ordinarily only returns records with an exact match on those bits (ie
317 - for the call below, only DS records). The F_NSIGMATCH bit changes this behaviour */
318 + ie A, AAAA, CNAME. */
320 - if ((crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6 | F_CNAME | F_DS | F_NO_RR | F_NSIGMATCH)) &&
321 + if ((crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6 | F_CNAME |F_NO_RR)) &&
322 (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
325 @@ -1566,9 +1564,11 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
326 GETSHORT(flags, pheader);
328 if ((sec_reqd = flags & 0x8000))
329 - *do_bit = 1;/* do bit */
331 + *do_bit = 1;/* do bit */
339 @@ -1636,98 +1636,6 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
344 - if (option_bool(OPT_DNSSEC_VALID) && (qtype == T_DNSKEY || qtype == T_DS))
347 - struct blockdata *keydata;
349 - /* Do we have RRSIG? Can't do DS or DNSKEY otherwise. */
353 - while ((crecp = cache_find_by_name(crecp, name, now, F_DNSKEY | F_DS)))
354 - if (crecp->uid == qclass && crecp->addr.sig.type_covered == qtype)
358 - if (!sec_reqd || crecp)
363 - while ((crecp = cache_find_by_name(crecp, name, now, F_DS)))
364 - if (crecp->uid == qclass)
369 - if (crecp->flags & F_NEG)
371 - if (crecp->flags & F_NXDOMAIN)
373 - log_query(F_UPSTREAM, name, NULL, "no DS");
375 - else if ((keydata = blockdata_retrieve(crecp->addr.ds.keydata, crecp->addr.ds.keylen, NULL)))
378 - a.addr.keytag = crecp->addr.ds.keytag;
379 - log_query(F_KEYTAG | (crecp->flags & F_CONFIG), name, &a, "DS keytag %u");
380 - if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
381 - crec_ttl(crecp, now), &nameoffset,
382 - T_DS, qclass, "sbbt",
383 - crecp->addr.ds.keytag, crecp->addr.ds.algo,
384 - crecp->addr.ds.digest, crecp->addr.ds.keylen, keydata))
394 - while ((crecp = cache_find_by_name(crecp, name, now, F_DNSKEY)))
395 - if (crecp->uid == qclass)
398 - if (!dryrun && (keydata = blockdata_retrieve(crecp->addr.key.keydata, crecp->addr.key.keylen, NULL)))
401 - a.addr.keytag = crecp->addr.key.keytag;
402 - log_query(F_KEYTAG | (crecp->flags & F_CONFIG), name, &a, "DNSKEY keytag %u");
403 - if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
404 - crec_ttl(crecp, now), &nameoffset,
405 - T_DNSKEY, qclass, "sbbt",
406 - crecp->addr.key.flags, 3, crecp->addr.key.algo, crecp->addr.key.keylen, keydata))
413 - /* Now do RRSIGs */
418 - if (!dryrun && sec_reqd)
421 - while ((crecp = cache_find_by_name(crecp, name, now, F_DNSKEY | F_DS)))
422 - if (crecp->uid == qclass && crecp->addr.sig.type_covered == qtype &&
423 - (keydata = blockdata_retrieve(crecp->addr.sig.keydata, crecp->addr.sig.keylen, NULL)))
425 - add_resource_record(header, limit, &trunc, nameoffset, &ansp,
426 - crec_ttl(crecp, now), &nameoffset,
427 - T_RRSIG, qclass, "t", crecp->addr.sig.keylen, keydata);
437 struct txt_record *t;
438 @@ -1736,6 +1644,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
439 if ((t->class == qtype || qtype == T_ANY) && hostname_isequal(name, t->name))
445 log_query(F_CONFIG | F_RRNAME, name, NULL, "<RR>");
446 @@ -1792,6 +1701,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
454 @@ -1805,6 +1715,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
461 log_query(F_CONFIG | F_RRNAME, name, NULL, "<PTR>");
462 @@ -1819,38 +1730,8 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
464 else if ((crecp = cache_find_by_addr(NULL, &addr, now, is_arpa)))
466 - if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) && sec_reqd)
468 - if (!option_bool(OPT_DNSSEC_VALID) || ((crecp->flags & F_NEG) && (crecp->flags & F_DNSSECOK)))
471 - else if (crecp->flags & F_DNSSECOK)
474 - struct crec *rr_crec = NULL;
476 - while ((rr_crec = cache_find_by_name(rr_crec, name, now, F_DS | F_DNSKEY)))
478 - if (rr_crec->addr.sig.type_covered == T_PTR && rr_crec->uid == C_IN)
480 - char *sigdata = blockdata_retrieve(rr_crec->addr.sig.keydata, rr_crec->addr.sig.keylen, NULL);
484 - add_resource_record(header, limit, &trunc, nameoffset, &ansp,
485 - rr_crec->ttd - now, &nameoffset,
486 - T_RRSIG, C_IN, "t", crecp->addr.sig.keylen, sigdata))
498 + /* Don't use cache when DNSSEC data required. */
499 + if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) || !sec_reqd || !(crecp->flags & F_DNSSECOK))
503 @@ -1860,19 +1741,19 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
505 if (!(crecp->flags & F_DNSSECOK))
511 if (crecp->flags & F_NEG)
515 if (crecp->flags & F_NXDOMAIN)
518 log_query(crecp->flags & ~F_FORWARD, name, &addr, NULL);
520 - else if ((crecp->flags & (F_HOSTS | F_DHCP)) || !sec_reqd || option_bool(OPT_DNSSEC_VALID))
524 if (!(crecp->flags & (F_HOSTS | F_DHCP)))
527 @@ -1892,6 +1773,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
528 else if (is_rev_synth(is_arpa, &addr, name))
534 log_query(F_CONFIG | F_REVERSE | is_arpa, name, &addr, NULL);
535 @@ -1908,6 +1790,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
537 /* if not in cache, enabled and private IPV4 address, return NXDOMAIN */
542 log_query(F_CONFIG | F_REVERSE | F_IPV4 | F_NEG | F_NXDOMAIN,
543 @@ -1955,6 +1838,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
550 addr.addr.addr4.s_addr = htonl(a);
551 @@ -1993,6 +1877,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
559 @@ -2032,48 +1917,8 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
563 - /* If the client asked for DNSSEC and we can't provide RRSIGs, either
564 - because we've not doing DNSSEC or the cached answer is signed by negative,
565 - don't answer from the cache, forward instead. */
566 - if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) && sec_reqd)
568 - if (!option_bool(OPT_DNSSEC_VALID) || ((crecp->flags & F_NEG) && (crecp->flags & F_DNSSECOK)))
571 - else if (crecp->flags & F_DNSSECOK)
573 - /* We're returning validated data, need to return the RRSIG too. */
574 - struct crec *rr_crec = NULL;
575 - int sigtype = type;
576 - /* The signature may have expired even though the data is still in cache,
577 - forward instead of answering from cache if so. */
580 - if (crecp->flags & F_CNAME)
583 - while ((rr_crec = cache_find_by_name(rr_crec, name, now, F_DS | F_DNSKEY)))
585 - if (rr_crec->addr.sig.type_covered == sigtype && rr_crec->uid == C_IN)
587 - char *sigdata = blockdata_retrieve(rr_crec->addr.sig.keydata, rr_crec->addr.sig.keylen, NULL);
591 - add_resource_record(header, limit, &trunc, nameoffset, &ansp,
592 - rr_crec->ttd - now, &nameoffset,
593 - T_RRSIG, C_IN, "t", rr_crec->addr.sig.keylen, sigdata))
605 + /* If the client asked for DNSSEC don't use cached data. */
606 + if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) || !sec_reqd || !(crecp->flags & F_DNSSECOK))
609 /* don't answer wildcard queries with data not from /etc/hosts