]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/resolve/resolved-dns-cache.c
Merge pull request #30284 from YHNdnzj/fstab-wantedby-defaultdeps
[thirdparty/systemd.git] / src / resolve / resolved-dns-cache.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
322345fd 2
202b76ae
ZJS
3#include <net/if.h>
4
5#include "af-list.h"
b5efdb8a 6#include "alloc-util.h"
58db254a 7#include "dns-domain.h"
518a66ec 8#include "format-util.h"
02c2857b 9#include "resolved-dns-answer.h"
322345fd 10#include "resolved-dns-cache.h"
7e8e0422 11#include "resolved-dns-packet.h"
58db254a 12#include "string-util.h"
322345fd 13
6af47493
LP
14/* Never cache more than 4K entries. RFC 1536, Section 5 suggests to
15 * leave DNS caches unbounded, but that's crazy. */
d98e5504 16#define CACHE_MAX 4096
cbd4560e 17
5ed91481 18/* We never keep any item longer than 2h in our cache unless StaleRetentionSec is greater than zero. */
d98e5504 19#define CACHE_TTL_MAX_USEC (2 * USEC_PER_HOUR)
322345fd 20
5ed91481
KV
21/* The max TTL for stale data is set to 30 seconds. See RFC 8767, Section 6. */
22#define CACHE_STALE_TTL_MAX_USEC (30 * USEC_PER_SEC)
23
201d9958
LP
24/* How long to cache strange rcodes, i.e. rcodes != SUCCESS and != NXDOMAIN (specifically: that's only SERVFAIL for
25 * now) */
19bcef9d 26#define CACHE_TTL_STRANGE_RCODE_USEC (10 * USEC_PER_SEC)
201d9958 27
43fc4baa 28#define CACHEABLE_QUERY_FLAGS (SD_RESOLVED_AUTHENTICATED|SD_RESOLVED_CONFIDENTIAL)
6f055e43 29
623a4c97
LP
30typedef enum DnsCacheItemType DnsCacheItemType;
31typedef struct DnsCacheItem DnsCacheItem;
32
33enum DnsCacheItemType {
34 DNS_CACHE_POSITIVE,
35 DNS_CACHE_NODATA,
36 DNS_CACHE_NXDOMAIN,
201d9958 37 DNS_CACHE_RCODE, /* "strange" RCODE (effective only SERVFAIL for now) */
623a4c97
LP
38};
39
40struct DnsCacheItem {
d2579eec 41 DnsCacheItemType type;
8e95506a 42 int rcode;
775ae354
LP
43 DnsResourceKey *key; /* The key for this item, i.e. the lookup key */
44 DnsResourceRecord *rr; /* The RR for this item, i.e. the lookup value for positive queries */
45 DnsAnswer *answer; /* The full validated answer, if this is an RRset acquired via a "primary" lookup */
46 DnsPacket *full_packet; /* The full packet this information was acquired with */
d2579eec 47
5ed91481
KV
48 usec_t until; /* If StaleRetentionSec is greater than zero, until is set to a duration of StaleRetentionSec from the time of TTL expiry. If StaleRetentionSec is zero, both until and until_valid will be set to ttl. */
49 usec_t until_valid; /* The key is for storing the time when the TTL set to expire. */
43fc4baa 50 uint64_t query_flags; /* SD_RESOLVED_AUTHENTICATED and/or SD_RESOLVED_CONFIDENTIAL */
775ae354 51 DnssecResult dnssec_result;
d2579eec 52
06d12754 53 int ifindex;
a4076574
LP
54 int owner_family;
55 union in_addr_union owner_address;
d2579eec
LP
56
57 unsigned prioq_idx;
623a4c97 58 LIST_FIELDS(DnsCacheItem, by_key);
8e95506a
YW
59
60 bool shared_owner;
623a4c97
LP
61};
62
775ae354
LP
63/* Returns true if this is a cache item created as result of an explicit lookup, or created as "side-effect"
64 * of another request. "Primary" entries will carry the full answer data (with NSEC, …) that can aso prove
6b5e8240 65 * wildcard expansion, non-existence and such, while entries that were created as "side-effect" just contain
775ae354
LP
66 * immediate RR data for the specified RR key, but nothing else. */
67#define DNS_CACHE_ITEM_IS_PRIMARY(item) (!!(item)->answer)
68
201d9958
LP
69static const char *dns_cache_item_type_to_string(DnsCacheItem *item) {
70 assert(item);
71
72 switch (item->type) {
73
74 case DNS_CACHE_POSITIVE:
75 return "POSITIVE";
76
77 case DNS_CACHE_NODATA:
78 return "NODATA";
79
80 case DNS_CACHE_NXDOMAIN:
81 return "NXDOMAIN";
82
83 case DNS_CACHE_RCODE:
84 return dns_rcode_to_string(item->rcode);
85 }
86
87 return NULL;
88}
89
75db809a 90static DnsCacheItem* dns_cache_item_free(DnsCacheItem *i) {
322345fd 91 if (!i)
75db809a 92 return NULL;
322345fd
LP
93
94 dns_resource_record_unref(i->rr);
7e8e0422 95 dns_resource_key_unref(i->key);
775ae354
LP
96 dns_answer_unref(i->answer);
97 dns_packet_unref(i->full_packet);
75db809a 98 return mfree(i);
322345fd 99}
322345fd
LP
100DEFINE_TRIVIAL_CLEANUP_FUNC(DnsCacheItem*, dns_cache_item_free);
101
39963f11 102static void dns_cache_item_unlink_and_free(DnsCache *c, DnsCacheItem *i) {
322345fd
LP
103 DnsCacheItem *first;
104
105 assert(c);
106
107 if (!i)
108 return;
109
7e8e0422
LP
110 first = hashmap_get(c->by_key, i->key);
111 LIST_REMOVE(by_key, first, i);
322345fd
LP
112
113 if (first)
7e8e0422 114 assert_se(hashmap_replace(c->by_key, first->key, first) >= 0);
322345fd 115 else
7e8e0422 116 hashmap_remove(c->by_key, i->key);
322345fd 117
7e8e0422 118 prioq_remove(c->by_expiry, i, &i->prioq_idx);
322345fd
LP
119
120 dns_cache_item_free(i);
121}
122
f5bdeb01 123static bool dns_cache_remove_by_rr(DnsCache *c, DnsResourceRecord *rr) {
03677889 124 DnsCacheItem *first;
f5bdeb01
LP
125 int r;
126
127 first = hashmap_get(c->by_key, rr->key);
128 LIST_FOREACH(by_key, i, first) {
129 r = dns_resource_record_equal(i->rr, rr);
130 if (r < 0)
131 return r;
132 if (r > 0) {
39963f11 133 dns_cache_item_unlink_and_free(c, i);
f5bdeb01
LP
134 return true;
135 }
136 }
137
138 return false;
139}
140
2dda578f 141static bool dns_cache_remove_by_key(DnsCache *c, DnsResourceKey *key) {
03677889 142 DnsCacheItem *first;
322345fd
LP
143
144 assert(c);
145 assert(key);
146
1f97052f
LP
147 first = hashmap_remove(c->by_key, key);
148 if (!first)
149 return false;
150
80a226b2 151 LIST_FOREACH(by_key, i, first) {
1f97052f
LP
152 prioq_remove(c->by_expiry, i, &i->prioq_idx);
153 dns_cache_item_free(i);
6b34a6c9
TG
154 }
155
1f97052f 156 return true;
322345fd
LP
157}
158
ef9a3e3c
LP
159void dns_cache_flush(DnsCache *c) {
160 DnsResourceKey *key;
161
162 assert(c);
163
164 while ((key = hashmap_first_key(c->by_key)))
2dda578f 165 dns_cache_remove_by_key(c, key);
ef9a3e3c 166
43127aeb
YW
167 assert(hashmap_isempty(c->by_key));
168 assert(prioq_isempty(c->by_expiry));
ef9a3e3c
LP
169
170 c->by_key = hashmap_free(c->by_key);
171 c->by_expiry = prioq_free(c->by_expiry);
172}
173
322345fd
LP
174static void dns_cache_make_space(DnsCache *c, unsigned add) {
175 assert(c);
176
177 if (add <= 0)
178 return;
179
180 /* Makes space for n new entries. Note that we actually allow
181 * the cache to grow beyond CACHE_MAX, but only when we shall
182 * add more RRs to the cache than CACHE_MAX at once. In that
183 * case the cache will be emptied completely otherwise. */
184
185 for (;;) {
faa133f3 186 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
322345fd
LP
187 DnsCacheItem *i;
188
43127aeb 189 if (prioq_isempty(c->by_expiry))
322345fd
LP
190 break;
191
7e8e0422 192 if (prioq_size(c->by_expiry) + add < CACHE_MAX)
322345fd
LP
193 break;
194
7e8e0422 195 i = prioq_peek(c->by_expiry);
cbd4560e
LP
196 assert(i);
197
faa133f3 198 /* Take an extra reference to the key so that it
cbd4560e 199 * doesn't go away in the middle of the remove call */
7e8e0422 200 key = dns_resource_key_ref(i->key);
2dda578f 201 dns_cache_remove_by_key(c, key);
322345fd
LP
202 }
203}
204
205void dns_cache_prune(DnsCache *c) {
206 usec_t t = 0;
207
208 assert(c);
209
210 /* Remove all entries that are past their TTL */
211
212 for (;;) {
213 DnsCacheItem *i;
202b76ae 214 char key_str[DNS_RESOURCE_KEY_STRING_MAX];
322345fd 215
7e8e0422 216 i = prioq_peek(c->by_expiry);
322345fd
LP
217 if (!i)
218 break;
219
322345fd 220 if (t <= 0)
ba4e0427 221 t = now(CLOCK_BOOTTIME);
322345fd 222
7e8e0422 223 if (i->until > t)
322345fd
LP
224 break;
225
d2579eec 226 /* Depending whether this is an mDNS shared entry
202b76ae
ZJS
227 * either remove only this one RR or the whole RRset */
228 log_debug("Removing %scache entry for %s (expired "USEC_FMT"s ago)",
229 i->shared_owner ? "shared " : "",
230 dns_resource_key_to_string(i->key, key_str, sizeof key_str),
231 (t - i->until) / USEC_PER_SEC);
232
d2579eec 233 if (i->shared_owner)
39963f11 234 dns_cache_item_unlink_and_free(c, i);
d2579eec
LP
235 else {
236 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
237
238 /* Take an extra reference to the key so that it
239 * doesn't go away in the middle of the remove call */
240 key = dns_resource_key_ref(i->key);
2dda578f 241 dns_cache_remove_by_key(c, key);
d2579eec 242 }
322345fd
LP
243 }
244}
245
246static int dns_cache_item_prioq_compare_func(const void *a, const void *b) {
322345fd
LP
247 const DnsCacheItem *x = a, *y = b;
248
a0edd02e 249 return CMP(x->until, y->until);
322345fd
LP
250}
251
623a4c97 252static int dns_cache_init(DnsCache *c) {
7e8e0422
LP
253 int r;
254
623a4c97
LP
255 assert(c);
256
7e8e0422
LP
257 r = prioq_ensure_allocated(&c->by_expiry, dns_cache_item_prioq_compare_func);
258 if (r < 0)
259 return r;
260
d5099efc 261 r = hashmap_ensure_allocated(&c->by_key, &dns_resource_key_hash_ops);
7e8e0422
LP
262 if (r < 0)
263 return r;
264
265 return r;
266}
267
268static int dns_cache_link_item(DnsCache *c, DnsCacheItem *i) {
269 DnsCacheItem *first;
270 int r;
271
322345fd
LP
272 assert(c);
273 assert(i);
322345fd 274
7e8e0422
LP
275 r = prioq_put(c->by_expiry, i, &i->prioq_idx);
276 if (r < 0)
277 return r;
322345fd 278
7e8e0422
LP
279 first = hashmap_get(c->by_key, i->key);
280 if (first) {
d7ac0952 281 _unused_ _cleanup_(dns_resource_key_unrefp) DnsResourceKey *k = NULL;
f57e3cd5
LP
282
283 /* Keep a reference to the original key, while we manipulate the list. */
284 k = dns_resource_key_ref(first->key);
285
286 /* Now, try to reduce the number of keys we keep */
287 dns_resource_key_reduce(&first->key, &i->key);
288
289 if (first->rr)
290 dns_resource_key_reduce(&first->rr->key, &i->key);
291 if (i->rr)
292 dns_resource_key_reduce(&i->rr->key, &i->key);
293
7e8e0422
LP
294 LIST_PREPEND(by_key, first, i);
295 assert_se(hashmap_replace(c->by_key, first->key, first) >= 0);
296 } else {
297 r = hashmap_put(c->by_key, i->key, i);
298 if (r < 0) {
299 prioq_remove(c->by_expiry, i, &i->prioq_idx);
300 return r;
301 }
322345fd
LP
302 }
303
7e8e0422 304 return 0;
322345fd
LP
305}
306
faa133f3 307static DnsCacheItem* dns_cache_get(DnsCache *c, DnsResourceRecord *rr) {
faa133f3
LP
308 assert(c);
309 assert(rr);
310
03677889 311 LIST_FOREACH(by_key, i, (DnsCacheItem*) hashmap_get(c->by_key, rr->key))
3ef77d04 312 if (i->rr && dns_resource_record_equal(i->rr, rr) > 0)
faa133f3
LP
313 return i;
314
315 return NULL;
316}
317
5ed91481 318static usec_t calculate_until_valid(
b974211a
LP
319 DnsResourceRecord *rr,
320 uint32_t min_ttl,
321 uint32_t nsec_ttl,
322 usec_t timestamp,
323 bool use_soa_minimum) {
324
b211dc7e
LP
325 uint32_t ttl;
326 usec_t u;
ee3d6aff
LP
327
328 assert(rr);
329
b974211a 330 ttl = MIN(min_ttl, nsec_ttl);
b211dc7e 331 if (rr->key->type == DNS_TYPE_SOA && use_soa_minimum) {
3b7006cb
LP
332 /* If this is a SOA RR, and it is requested, clamp to the SOA's minimum field. This is used
333 * when we do negative caching, to determine the TTL for the negative caching entry. See RFC
334 * 2308, Section 5. */
ee3d6aff 335
b211dc7e
LP
336 if (ttl > rr->soa.minimum)
337 ttl = rr->soa.minimum;
338 }
339
340 u = ttl * USEC_PER_SEC;
341 if (u > CACHE_TTL_MAX_USEC)
342 u = CACHE_TTL_MAX_USEC;
ee3d6aff
LP
343
344 if (rr->expiry != USEC_INFINITY) {
345 usec_t left;
346
3b7006cb 347 /* Make use of the DNSSEC RRSIG expiry info, if we have it */
ee3d6aff
LP
348
349 left = LESS_BY(rr->expiry, now(CLOCK_REALTIME));
b211dc7e
LP
350 if (u > left)
351 u = left;
ee3d6aff
LP
352 }
353
b211dc7e 354 return timestamp + u;
ee3d6aff
LP
355}
356
5ed91481
KV
357static usec_t calculate_until(
358 usec_t until_valid,
359 usec_t stale_retention_usec) {
360
361 return stale_retention_usec > 0 ? usec_add(until_valid, stale_retention_usec) : until_valid;
362}
363
d2579eec
LP
364static void dns_cache_item_update_positive(
365 DnsCache *c,
366 DnsCacheItem *i,
367 DnsResourceRecord *rr,
775ae354
LP
368 DnsAnswer *answer,
369 DnsPacket *full_packet,
b974211a 370 uint32_t min_ttl,
6f055e43 371 uint64_t query_flags,
d2579eec 372 bool shared_owner,
775ae354 373 DnssecResult dnssec_result,
d2579eec 374 usec_t timestamp,
06d12754 375 int ifindex,
d2579eec 376 int owner_family,
5ed91481
KV
377 const union in_addr_union *owner_address,
378 usec_t stale_retention_usec) {
d2579eec 379
7e8e0422
LP
380 assert(c);
381 assert(i);
382 assert(rr);
d2579eec 383 assert(owner_address);
7e8e0422
LP
384
385 i->type = DNS_CACHE_POSITIVE;
386
ece174c5 387 if (!i->by_key_prev)
7e8e0422
LP
388 /* We are the first item in the list, we need to
389 * update the key used in the hashmap */
390
391 assert_se(hashmap_replace(c->by_key, rr->key, i) >= 0);
7e8e0422 392
7daeec3e 393 DNS_RR_REPLACE(i->rr, dns_resource_record_ref(rr));
7e8e0422 394
57318441 395 DNS_RESOURCE_KEY_REPLACE(i->key, dns_resource_key_ref(rr->key));
7e8e0422 396
1117a960 397 DNS_ANSWER_REPLACE(i->answer, dns_answer_ref(answer));
775ae354 398
899e3cda 399 DNS_PACKET_REPLACE(i->full_packet, dns_packet_ref(full_packet));
775ae354 400
5ed91481
KV
401 i->until_valid = calculate_until_valid(rr, min_ttl, UINT32_MAX, timestamp, false);
402 i->until = calculate_until(i->until_valid, stale_retention_usec);
6f055e43 403 i->query_flags = query_flags & CACHEABLE_QUERY_FLAGS;
d2579eec 404 i->shared_owner = shared_owner;
775ae354 405 i->dnssec_result = dnssec_result;
d2579eec 406
06d12754
LP
407 i->ifindex = ifindex;
408
d2579eec
LP
409 i->owner_family = owner_family;
410 i->owner_address = *owner_address;
7e8e0422
LP
411
412 prioq_reshuffle(c->by_expiry, i, &i->prioq_idx);
413}
414
a4076574
LP
415static int dns_cache_put_positive(
416 DnsCache *c,
a78049fc 417 DnsProtocol protocol,
a4076574 418 DnsResourceRecord *rr,
775ae354
LP
419 DnsAnswer *answer,
420 DnsPacket *full_packet,
6f055e43 421 uint64_t query_flags,
d2579eec 422 bool shared_owner,
775ae354 423 DnssecResult dnssec_result,
a4076574 424 usec_t timestamp,
06d12754 425 int ifindex,
a4076574 426 int owner_family,
5ed91481
KV
427 const union in_addr_union *owner_address,
428 usec_t stale_retention_usec) {
a4076574 429
518a66ec 430 char key_str[DNS_RESOURCE_KEY_STRING_MAX];
b974211a
LP
431 DnsCacheItem *existing;
432 uint32_t min_ttl;
f6d80c36 433 int r;
322345fd
LP
434
435 assert(c);
436 assert(rr);
a4076574 437 assert(owner_address);
322345fd 438
222148b6
LP
439 /* Never cache pseudo RRs */
440 if (dns_class_is_pseudo(rr->key->class))
441 return 0;
442 if (dns_type_is_pseudo(rr->key->type))
443 return 0;
444
b974211a
LP
445 /* Determine the minimal TTL of all RRs in the answer plus the one by the main RR we are supposed to
446 * cache. Since we cache whole answers to questions we should never return answers where only some
447 * RRs are still valid, hence find the lowest here */
18da9364 448 min_ttl = MIN(dns_answer_min_ttl(answer), rr->ttl);
b974211a 449
f5bdeb01 450 /* New TTL is 0? Delete this specific entry... */
b974211a 451 if (min_ttl <= 0) {
f6d80c36 452 r = dns_cache_remove_by_rr(c, rr);
202b76ae 453 log_debug("%s: %s",
f6d80c36 454 r > 0 ? "Removed zero TTL entry from cache" : "Not caching zero TTL cache entry",
18665d1f 455 dns_resource_key_to_string(rr->key, key_str, sizeof key_str));
322345fd
LP
456 return 0;
457 }
458
13e785f7 459 /* Entry exists already? Update TTL, timestamp and owner */
322345fd
LP
460 existing = dns_cache_get(c, rr);
461 if (existing) {
d2579eec
LP
462 dns_cache_item_update_positive(
463 c,
464 existing,
465 rr,
775ae354
LP
466 answer,
467 full_packet,
b974211a 468 min_ttl,
6f055e43 469 query_flags,
d2579eec 470 shared_owner,
775ae354 471 dnssec_result,
d2579eec 472 timestamp,
06d12754 473 ifindex,
d2579eec 474 owner_family,
5ed91481
KV
475 owner_address,
476 stale_retention_usec);
322345fd
LP
477 return 0;
478 }
479
a78049fc
YW
480 /* Do not cache mDNS goodbye packet. */
481 if (protocol == DNS_PROTOCOL_MDNS && rr->ttl <= 1)
482 return 0;
483
322345fd 484 /* Otherwise, add the new RR */
623a4c97 485 r = dns_cache_init(c);
322345fd
LP
486 if (r < 0)
487 return r;
488
7e8e0422
LP
489 dns_cache_make_space(c, 1);
490
f69ea167 491 _cleanup_(dns_cache_item_freep) DnsCacheItem *i = new(DnsCacheItem, 1);
7e8e0422
LP
492 if (!i)
493 return -ENOMEM;
494
5ed91481
KV
495 /* If StaleRetentionSec is greater than zero, the 'until' property is set to a duration
496 * of StaleRetentionSec from the time of TTL expiry.
497 * If StaleRetentionSec is zero, both the 'until' and 'until_valid' are set to the TTL duration,
498 * leading to the eviction of the record once the TTL expires.*/
499 usec_t until_valid = calculate_until_valid(rr, min_ttl, UINT32_MAX, timestamp, false);
1ed31408
LP
500 *i = (DnsCacheItem) {
501 .type = DNS_CACHE_POSITIVE,
502 .key = dns_resource_key_ref(rr->key),
503 .rr = dns_resource_record_ref(rr),
775ae354
LP
504 .answer = dns_answer_ref(answer),
505 .full_packet = dns_packet_ref(full_packet),
5ed91481
KV
506 .until = calculate_until(until_valid, stale_retention_usec),
507 .until_valid = until_valid,
6f055e43 508 .query_flags = query_flags & CACHEABLE_QUERY_FLAGS,
1ed31408 509 .shared_owner = shared_owner,
775ae354 510 .dnssec_result = dnssec_result,
1ed31408
LP
511 .ifindex = ifindex,
512 .owner_family = owner_family,
513 .owner_address = *owner_address,
514 .prioq_idx = PRIOQ_IDX_NULL,
515 };
7e8e0422
LP
516
517 r = dns_cache_link_item(c, i);
518 if (r < 0)
519 return r;
520
84dbb3fd
ZJS
521 log_debug("Added positive %s %s%s cache entry for %s "USEC_FMT"s on %s/%s/%s",
522 FLAGS_SET(i->query_flags, SD_RESOLVED_AUTHENTICATED) ? "authenticated" : "unauthenticated",
523 FLAGS_SET(i->query_flags, SD_RESOLVED_CONFIDENTIAL) ? "confidential" : "non-confidential",
524 i->shared_owner ? " shared" : "",
525 dns_resource_key_to_string(i->key, key_str, sizeof key_str),
526 (i->until - timestamp) / USEC_PER_SEC,
527 i->ifindex == 0 ? "*" : FORMAT_IFNAME(i->ifindex),
528 af_to_name_short(i->owner_family),
529 IN_ADDR_TO_STRING(i->owner_family, &i->owner_address));
6b34a6c9 530
f69ea167 531 TAKE_PTR(i);
7e8e0422
LP
532 return 0;
533}
534
a4076574
LP
535static int dns_cache_put_negative(
536 DnsCache *c,
537 DnsResourceKey *key,
538 int rcode,
775ae354
LP
539 DnsAnswer *answer,
540 DnsPacket *full_packet,
6f055e43 541 uint64_t query_flags,
775ae354 542 DnssecResult dnssec_result,
d3760be0 543 uint32_t nsec_ttl,
a4076574 544 usec_t timestamp,
b211dc7e 545 DnsResourceRecord *soa,
a4076574
LP
546 int owner_family,
547 const union in_addr_union *owner_address) {
548
7e8e0422 549 _cleanup_(dns_cache_item_freep) DnsCacheItem *i = NULL;
202b76ae 550 char key_str[DNS_RESOURCE_KEY_STRING_MAX];
7e8e0422
LP
551 int r;
552
553 assert(c);
554 assert(key);
a4076574 555 assert(owner_address);
7e8e0422 556
98b6be77
LP
557 /* Never cache pseudo RR keys. DNS_TYPE_ANY is particularly
558 * important to filter out as we use this as a pseudo-type for
559 * NXDOMAIN entries */
222148b6 560 if (dns_class_is_pseudo(key->class))
ddf16339 561 return 0;
c33be4a6 562 if (dns_type_is_pseudo(key->type))
ddf16339 563 return 0;
222148b6 564
201d9958
LP
565 if (IN_SET(rcode, DNS_RCODE_SUCCESS, DNS_RCODE_NXDOMAIN)) {
566 if (!soa)
567 return 0;
ddf16339 568
201d9958
LP
569 /* For negative replies, check if we have a TTL of a SOA */
570 if (nsec_ttl <= 0 || soa->soa.minimum <= 0 || soa->ttl <= 0) {
571 log_debug("Not caching negative entry with zero SOA/NSEC/NSEC3 TTL: %s",
572 dns_resource_key_to_string(key, key_str, sizeof key_str));
573 return 0;
574 }
575 } else if (rcode != DNS_RCODE_SERVFAIL)
7e8e0422
LP
576 return 0;
577
623a4c97 578 r = dns_cache_init(c);
322345fd
LP
579 if (r < 0)
580 return r;
581
582 dns_cache_make_space(c, 1);
583
1ed31408 584 i = new(DnsCacheItem, 1);
322345fd
LP
585 if (!i)
586 return -ENOMEM;
587
1ed31408
LP
588 *i = (DnsCacheItem) {
589 .type =
590 rcode == DNS_RCODE_SUCCESS ? DNS_CACHE_NODATA :
591 rcode == DNS_RCODE_NXDOMAIN ? DNS_CACHE_NXDOMAIN : DNS_CACHE_RCODE,
6f055e43 592 .query_flags = query_flags & CACHEABLE_QUERY_FLAGS,
775ae354 593 .dnssec_result = dnssec_result,
1ed31408
LP
594 .owner_family = owner_family,
595 .owner_address = *owner_address,
596 .prioq_idx = PRIOQ_IDX_NULL,
597 .rcode = rcode,
775ae354
LP
598 .answer = dns_answer_ref(answer),
599 .full_packet = dns_packet_ref(full_packet),
1ed31408 600 };
322345fd 601
b974211a
LP
602 /* Determine how long to cache this entry. In case we have some RRs in the answer use the lowest TTL
603 * of any of them. Typically that's the SOA's TTL, which is OK, but could possibly be lower because
604 * of some other RR. Let's better take the lowest option here than a needlessly high one */
88c6f8f8 605 i->until = i->until_valid =
eaa26948 606 i->type == DNS_CACHE_RCODE ? timestamp + CACHE_TTL_STRANGE_RCODE_USEC :
5ed91481 607 calculate_until_valid(soa, dns_answer_min_ttl(answer), nsec_ttl, timestamp, true);
eaa26948 608
71e13669
TG
609 if (i->type == DNS_CACHE_NXDOMAIN) {
610 /* NXDOMAIN entries should apply equally to all types, so we use ANY as
611 * a pseudo type for this purpose here. */
1c02e7ba 612 i->key = dns_resource_key_new(key->class, DNS_TYPE_ANY, dns_resource_key_name(key));
71e13669
TG
613 if (!i->key)
614 return -ENOMEM;
a5444ca9
LP
615
616 /* Make sure to remove any previous entry for this
617 * specific ANY key. (For non-ANY keys the cache data
618 * is already cleared by the caller.) Note that we
619 * don't bother removing positive or NODATA cache
620 * items in this case, because it would either be slow
621 * or require explicit indexing by name */
622 dns_cache_remove_by_key(c, key);
71e13669
TG
623 } else
624 i->key = dns_resource_key_ref(key);
625
7e8e0422 626 r = dns_cache_link_item(c, i);
322345fd
LP
627 if (r < 0)
628 return r;
629
202b76ae 630 log_debug("Added %s cache entry for %s "USEC_FMT"s",
201d9958 631 dns_cache_item_type_to_string(i),
202b76ae
ZJS
632 dns_resource_key_to_string(i->key, key_str, sizeof key_str),
633 (i->until - timestamp) / USEC_PER_SEC);
6b34a6c9 634
322345fd 635 i = NULL;
322345fd
LP
636 return 0;
637}
638
d2579eec
LP
639static void dns_cache_remove_previous(
640 DnsCache *c,
641 DnsResourceKey *key,
642 DnsAnswer *answer) {
643
644 DnsResourceRecord *rr;
645 DnsAnswerFlags flags;
646
647 assert(c);
648
649 /* First, if we were passed a key (i.e. on LLMNR/DNS, but
650 * not on mDNS), delete all matching old RRs, so that we only
651 * keep complete by_key in place. */
652 if (key)
2dda578f 653 dns_cache_remove_by_key(c, key);
d2579eec
LP
654
655 /* Second, flush all entries matching the answer, unless this
656 * is an RR that is explicitly marked to be "shared" between
657 * peers (i.e. mDNS RRs without the flush-cache bit set). */
658 DNS_ANSWER_FOREACH_FLAGS(rr, flags, answer) {
659 if ((flags & DNS_ANSWER_CACHEABLE) == 0)
660 continue;
661
662 if (flags & DNS_ANSWER_SHARED_OWNER)
663 continue;
664
2dda578f 665 dns_cache_remove_by_key(c, rr->key);
d2579eec
LP
666 }
667}
668
f6618dcd
LP
669static bool rr_eligible(DnsResourceRecord *rr) {
670 assert(rr);
671
672 /* When we see an NSEC/NSEC3 RR, we'll only cache it if it is from the lower zone, not the upper zone, since
673 * that's where the interesting bits are (with exception of DS RRs). Of course, this way we cannot derive DS
674 * existence from any cached NSEC/NSEC3, but that should be fine. */
675
676 switch (rr->key->type) {
677
678 case DNS_TYPE_NSEC:
679 return !bitmap_isset(rr->nsec.types, DNS_TYPE_NS) ||
680 bitmap_isset(rr->nsec.types, DNS_TYPE_SOA);
681
682 case DNS_TYPE_NSEC3:
683 return !bitmap_isset(rr->nsec3.types, DNS_TYPE_NS) ||
684 bitmap_isset(rr->nsec3.types, DNS_TYPE_SOA);
685
686 default:
687 return true;
688 }
689}
690
a4076574
LP
691int dns_cache_put(
692 DnsCache *c,
37d7a7d9 693 DnsCacheMode cache_mode,
a78049fc 694 DnsProtocol protocol,
8e427d9b 695 DnsResourceKey *key,
a4076574
LP
696 int rcode,
697 DnsAnswer *answer,
775ae354 698 DnsPacket *full_packet,
6f055e43 699 uint64_t query_flags,
775ae354 700 DnssecResult dnssec_result,
d3760be0 701 uint32_t nsec_ttl,
a4076574 702 int owner_family,
5ed91481
KV
703 const union in_addr_union *owner_address,
704 usec_t stale_retention_usec) {
a4076574 705
9c5fcb8a 706 DnsResourceRecord *soa = NULL;
201d9958 707 bool weird_rcode = false;
9c5fcb8a 708 DnsAnswerItem *item;
105e1512
LP
709 DnsAnswerFlags flags;
710 unsigned cache_keys;
43475909 711 usec_t timestamp;
9c5fcb8a 712 int r;
322345fd
LP
713
714 assert(c);
d2579eec 715 assert(owner_address);
322345fd 716
d2579eec 717 dns_cache_remove_previous(c, key, answer);
0ec7c46e 718
201d9958
LP
719 /* We only care for positive replies and NXDOMAINs, on all other replies we will simply flush the respective
720 * entries, and that's it. (Well, with one further exception: since some DNS zones (akamai!) return SERVFAIL
721 * consistently for some lookups, and forwarders tend to propagate that we'll cache that too, but only for a
722 * short time.) */
6ff01a0d 723
201d9958 724 if (IN_SET(rcode, DNS_RCODE_SUCCESS, DNS_RCODE_NXDOMAIN)) {
77db3cae 725 if (dns_answer_isempty(answer)) {
e55fc5b0
YW
726 if (key) {
727 char key_str[DNS_RESOURCE_KEY_STRING_MAX];
201d9958 728
e55fc5b0
YW
729 log_debug("Not caching negative entry without a SOA record: %s",
730 dns_resource_key_to_string(key, key_str, sizeof key_str));
731 }
775ae354 732
201d9958
LP
733 return 0;
734 }
735
736 } else {
737 /* Only cache SERVFAIL as "weird" rcode for now. We can add more later, should that turn out to be
738 * beneficial. */
739 if (rcode != DNS_RCODE_SERVFAIL)
740 return 0;
741
742 weird_rcode = true;
c3cb6dc2 743 }
0ec7c46e 744
ea207b63 745 cache_keys = dns_answer_size(answer);
8e427d9b 746 if (key)
313cefa1 747 cache_keys++;
eff91ee0 748
7e8e0422 749 /* Make some space for our new entries */
eff91ee0 750 dns_cache_make_space(c, cache_keys);
322345fd 751
ba4e0427 752 timestamp = now(CLOCK_BOOTTIME);
322345fd 753
7e8e0422 754 /* Second, add in positive entries for all contained RRs */
9c5fcb8a 755 DNS_ANSWER_FOREACH_ITEM(item, answer) {
775ae354
LP
756 int primary = false;
757
758 if (!FLAGS_SET(item->flags, DNS_ANSWER_CACHEABLE) ||
9c5fcb8a 759 !rr_eligible(item->rr))
f6618dcd
LP
760 continue;
761
775ae354
LP
762 if (key) {
763 /* We store the auxiliary RRs and packet data in the cache only if they were in
764 * direct response to the original query. If we cache an RR we also received, and
765 * that is just auxiliary information we can't use the data, hence don't. */
766
767 primary = dns_resource_key_match_rr(key, item->rr, NULL);
768 if (primary < 0)
769 return primary;
770 if (primary == 0) {
771 primary = dns_resource_key_match_cname_or_dname(key, item->rr->key, NULL);
772 if (primary < 0)
773 return primary;
774 }
775 }
776
777 if (!primary) {
778 DnsCacheItem *first;
779
780 /* Do not replace existing cache items for primary lookups with non-primary
781 * data. After all the primary lookup data is a lot more useful. */
782 first = hashmap_get(c->by_key, item->rr->key);
783 if (first && DNS_CACHE_ITEM_IS_PRIMARY(first))
784 return 0;
785 }
786
d2579eec
LP
787 r = dns_cache_put_positive(
788 c,
a78049fc 789 protocol,
9c5fcb8a 790 item->rr,
775ae354
LP
791 primary ? answer : NULL,
792 primary ? full_packet : NULL,
43fc4baa
LP
793 ((item->flags & DNS_ANSWER_AUTHENTICATED) ? SD_RESOLVED_AUTHENTICATED : 0) |
794 (query_flags & SD_RESOLVED_CONFIDENTIAL),
9c5fcb8a 795 item->flags & DNS_ANSWER_SHARED_OWNER,
775ae354 796 dnssec_result,
d2579eec 797 timestamp,
9c5fcb8a 798 item->ifindex,
775ae354 799 owner_family,
5ed91481
KV
800 owner_address,
801 stale_retention_usec);
7e8e0422
LP
802 if (r < 0)
803 goto fail;
804 }
805
d2579eec 806 if (!key) /* mDNS doesn't know negative caching, really */
eff91ee0
DM
807 return 0;
808
8e427d9b 809 /* Third, add in negative entries if the key has no RR */
105e1512 810 r = dns_answer_match_key(answer, key, NULL);
8e427d9b
TG
811 if (r < 0)
812 goto fail;
813 if (r > 0)
814 return 0;
7e8e0422 815
3b7006cb
LP
816 /* But not if it has a matching CNAME/DNAME (the negative caching will be done on the canonical name,
817 * not on the alias) */
105e1512 818 r = dns_answer_find_cname_or_dname(answer, key, NULL, NULL);
5d27351f
TG
819 if (r < 0)
820 goto fail;
821 if (r > 0)
822 return 0;
823
201d9958
LP
824 /* See https://tools.ietf.org/html/rfc2308, which say that a matching SOA record in the packet is used to
825 * enable negative caching. We apply one exception though: if we are about to cache a weird rcode we do so
826 * regardless of a SOA. */
fd009cd8 827 r = dns_answer_find_soa(answer, key, &soa, &flags);
8e427d9b
TG
828 if (r < 0)
829 goto fail;
201d9958 830 if (r == 0 && !weird_rcode)
fd009cd8 831 return 0;
201d9958 832 if (r > 0) {
3b7006cb 833 /* Refuse using the SOA data if it is unsigned, but the key is signed */
6f055e43
LP
834 if (FLAGS_SET(query_flags, SD_RESOLVED_AUTHENTICATED) &&
835 (flags & DNS_ANSWER_AUTHENTICATED) == 0)
201d9958
LP
836 return 0;
837 }
fd009cd8 838
37d7a7d9
JN
839 if (cache_mode == DNS_CACHE_MODE_NO_NEGATIVE) {
840 char key_str[DNS_RESOURCE_KEY_STRING_MAX];
841 log_debug("Not caching negative entry for: %s, cache mode set to no-negative",
b12058e8 842 dns_resource_key_to_string(key, key_str, sizeof key_str));
37d7a7d9
JN
843 return 0;
844 }
845
d2579eec
LP
846 r = dns_cache_put_negative(
847 c,
848 key,
849 rcode,
775ae354
LP
850 answer,
851 full_packet,
6f055e43 852 query_flags,
775ae354 853 dnssec_result,
d3760be0 854 nsec_ttl,
d2579eec 855 timestamp,
b211dc7e 856 soa,
5ed91481
KV
857 owner_family,
858 owner_address);
8e427d9b
TG
859 if (r < 0)
860 goto fail;
322345fd
LP
861
862 return 0;
863
864fail:
865 /* Adding all RRs failed. Let's clean up what we already
866 * added, just in case */
867
8e427d9b 868 if (key)
2dda578f 869 dns_cache_remove_by_key(c, key);
eff91ee0 870
9c5fcb8a
LP
871 DNS_ANSWER_FOREACH_ITEM(item, answer) {
872 if ((item->flags & DNS_ANSWER_CACHEABLE) == 0)
105e1512
LP
873 continue;
874
9c5fcb8a 875 dns_cache_remove_by_key(c, item->rr->key);
105e1512 876 }
322345fd
LP
877
878 return r;
879}
880
37da8931 881static DnsCacheItem *dns_cache_get_by_key_follow_cname_dname_nsec(DnsCache *c, DnsResourceKey *k) {
58db254a
LP
882 DnsCacheItem *i;
883 const char *n;
884 int r;
5643c00a
TG
885
886 assert(c);
887 assert(k);
888
58db254a
LP
889 /* If we hit some OOM error, or suchlike, we don't care too
890 * much, after all this is just a cache */
891
5643c00a 892 i = hashmap_get(c->by_key, k);
d7ce6c94 893 if (i)
37da8931
LP
894 return i;
895
1c02e7ba 896 n = dns_resource_key_name(k);
37da8931 897
71e13669
TG
898 /* Check if we have an NXDOMAIN cache item for the name, notice that we use
899 * the pseudo-type ANY for NXDOMAIN cache items. */
900 i = hashmap_get(c->by_key, &DNS_RESOURCE_KEY_CONST(k->class, DNS_TYPE_ANY, n));
901 if (i && i->type == DNS_CACHE_NXDOMAIN)
902 return i;
903
d3c7e913 904 if (dns_type_may_redirect(k->type)) {
d7ce6c94
TG
905 /* Check if we have a CNAME record instead */
906 i = hashmap_get(c->by_key, &DNS_RESOURCE_KEY_CONST(k->class, DNS_TYPE_CNAME, n));
3740146a 907 if (i && i->type != DNS_CACHE_NODATA)
d7ce6c94 908 return i;
5643c00a 909
d7ce6c94
TG
910 /* OK, let's look for cached DNAME records. */
911 for (;;) {
d7ce6c94
TG
912 if (isempty(n))
913 return NULL;
914
915 i = hashmap_get(c->by_key, &DNS_RESOURCE_KEY_CONST(k->class, DNS_TYPE_DNAME, n));
3740146a 916 if (i && i->type != DNS_CACHE_NODATA)
d7ce6c94 917 return i;
58db254a 918
d7ce6c94 919 /* Jump one label ahead */
950b692b 920 r = dns_name_parent(&n);
d7ce6c94
TG
921 if (r <= 0)
922 return NULL;
923 }
924 }
5643c00a 925
950b692b 926 if (k->type != DNS_TYPE_NSEC) {
d7ce6c94
TG
927 /* Check if we have an NSEC record instead for the name. */
928 i = hashmap_get(c->by_key, &DNS_RESOURCE_KEY_CONST(k->class, DNS_TYPE_NSEC, n));
58db254a
LP
929 if (i)
930 return i;
58db254a
LP
931 }
932
933 return NULL;
5643c00a
TG
934}
935
775ae354
LP
936static int answer_add_clamp_ttl(
937 DnsAnswer **answer,
938 DnsResourceRecord *rr,
939 int ifindex,
940 DnsAnswerFlags answer_flags,
941 DnsResourceRecord *rrsig,
942 uint64_t query_flags,
943 usec_t until,
944 usec_t current) {
945
946 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *patched = NULL, *patched_rrsig = NULL;
947 int r;
948
949 assert(answer);
950 assert(rr);
951
952 if (FLAGS_SET(query_flags, SD_RESOLVED_CLAMP_TTL)) {
a1acc6e3
LP
953 uint32_t left_ttl;
954
e7d48709
ZJS
955 assert(current > 0);
956
a1acc6e3
LP
957 /* Let's determine how much time is left for this cache entry. Note that we round down, but
958 * clamp this to be 1s at minimum, since we usually want records to remain cached better too
959 * short a time than too long a time, but otoh don't want to return 0 ever, since that has
960 * special semantics in various contexts — in particular in mDNS */
961
962 left_ttl = MAX(1U, LESS_BY(until, current) / USEC_PER_SEC);
963
775ae354
LP
964 patched = dns_resource_record_ref(rr);
965
a1acc6e3 966 r = dns_resource_record_clamp_ttl(&patched, left_ttl);
775ae354
LP
967 if (r < 0)
968 return r;
969
970 rr = patched;
971
972 if (rrsig) {
973 patched_rrsig = dns_resource_record_ref(rrsig);
a1acc6e3 974 r = dns_resource_record_clamp_ttl(&patched_rrsig, left_ttl);
775ae354
LP
975 if (r < 0)
976 return r;
977
978 rrsig = patched_rrsig;
979 }
980 }
981
982 r = dns_answer_add_extend(answer, rr, ifindex, answer_flags, rrsig);
983 if (r < 0)
984 return r;
985
986 return 0;
987}
988
989int dns_cache_lookup(
990 DnsCache *c,
991 DnsResourceKey *key,
992 uint64_t query_flags,
993 int *ret_rcode,
994 DnsAnswer **ret_answer,
995 DnsPacket **ret_full_packet,
6f055e43 996 uint64_t *ret_query_flags,
775ae354
LP
997 DnssecResult *ret_dnssec_result) {
998
999 _cleanup_(dns_packet_unrefp) DnsPacket *full_packet = NULL;
faa133f3 1000 _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
202b76ae 1001 char key_str[DNS_RESOURCE_KEY_STRING_MAX];
f52e61da 1002 unsigned n = 0;
322345fd 1003 int r;
7e8e0422 1004 bool nxdomain = false;
03677889 1005 DnsCacheItem *first, *nsec = NULL;
43fc4baa 1006 bool have_authenticated = false, have_non_authenticated = false, have_confidential = false, have_non_confidential = false;
e7d48709 1007 usec_t current = 0;
201d9958 1008 int found_rcode = -1;
775ae354
LP
1009 DnssecResult dnssec_result = -1;
1010 int have_dnssec_result = -1;
322345fd
LP
1011
1012 assert(c);
f52e61da 1013 assert(key);
322345fd 1014
202b76ae 1015 if (key->type == DNS_TYPE_ANY || key->class == DNS_CLASS_ANY) {
775ae354
LP
1016 /* If we have ANY lookups we don't use the cache, so that the caller refreshes via the
1017 * network. */
322345fd 1018
202b76ae
ZJS
1019 log_debug("Ignoring cache for ANY lookup: %s",
1020 dns_resource_key_to_string(key, key_str, sizeof key_str));
775ae354 1021 goto miss;
f52e61da 1022 }
6b34a6c9 1023
37da8931 1024 first = dns_cache_get_by_key_follow_cname_dname_nsec(c, key);
f52e61da
LP
1025 if (!first) {
1026 /* If one question cannot be answered we need to refresh */
ddf16339 1027
202b76ae
ZJS
1028 log_debug("Cache miss for %s",
1029 dns_resource_key_to_string(key, key_str, sizeof key_str));
775ae354
LP
1030 goto miss;
1031 }
6b34a6c9 1032
6756b616 1033 if ((query_flags & (SD_RESOLVED_CLAMP_TTL | SD_RESOLVED_NO_STALE)) != 0) {
e7d48709 1034 /* 'current' is always passed to answer_add_clamp_ttl(), but is only used conditionally.
6756b616
YW
1035 * We'll do the same assert there to make sure that it was initialized properly.
1036 * 'current' is also used below when SD_RESOLVED_NO_STALE is set. */
ba4e0427 1037 current = now(CLOCK_BOOTTIME);
e7d48709
ZJS
1038 assert(current > 0);
1039 }
a150ff5e 1040
775ae354
LP
1041 LIST_FOREACH(by_key, j, first) {
1042 /* If the caller doesn't allow us to answer questions from cache data learned from
1043 * "side-effect", skip this entry. */
1044 if (FLAGS_SET(query_flags, SD_RESOLVED_REQUIRE_PRIMARY) &&
1045 !DNS_CACHE_ITEM_IS_PRIMARY(j)) {
1046 log_debug("Primary answer was requested for cache lookup for %s, which we don't have.",
1047 dns_resource_key_to_string(key, key_str, sizeof key_str));
2d4a4e14 1048
775ae354
LP
1049 goto miss;
1050 }
6b34a6c9 1051
5ed91481
KV
1052 /* Skip the next part if ttl is expired and requested with no stale flag. */
1053 if (FLAGS_SET(query_flags, SD_RESOLVED_NO_STALE) && j->until_valid < current) {
1054 log_debug("Requested with no stale and TTL expired for %s",
1055 dns_resource_key_to_string(key, key_str, sizeof key_str));
1056
1057 goto miss;
1058 }
1059
775ae354
LP
1060 if (j->type == DNS_CACHE_NXDOMAIN)
1061 nxdomain = true;
1062 else if (j->type == DNS_CACHE_RCODE)
1063 found_rcode = j->rcode;
1064 else if (j->rr) {
37da8931 1065 if (j->rr->key->type == DNS_TYPE_NSEC)
931851e8
LP
1066 nsec = j;
1067
f52e61da 1068 n++;
775ae354 1069 }
931851e8 1070
6f055e43 1071 if (FLAGS_SET(j->query_flags, SD_RESOLVED_AUTHENTICATED))
931851e8
LP
1072 have_authenticated = true;
1073 else
1074 have_non_authenticated = true;
775ae354 1075
43fc4baa
LP
1076 if (FLAGS_SET(j->query_flags, SD_RESOLVED_CONFIDENTIAL))
1077 have_confidential = true;
1078 else
1079 have_non_confidential = true;
1080
775ae354
LP
1081 if (j->dnssec_result < 0) {
1082 have_dnssec_result = false; /* an entry without dnssec result? then invalidate things for good */
1083 dnssec_result = _DNSSEC_RESULT_INVALID;
1084 } else if (have_dnssec_result < 0) {
1085 have_dnssec_result = true; /* So far no result seen, let's pick this one up */
1086 dnssec_result = j->dnssec_result;
1087 } else if (have_dnssec_result > 0 && j->dnssec_result != dnssec_result) {
1088 have_dnssec_result = false; /* conflicting result seen? then invalidate for good */
1089 dnssec_result = _DNSSEC_RESULT_INVALID;
1090 }
1091
5ed91481
KV
1092 /* If the question is being resolved using stale data, the clamp TTL will be set to CACHE_STALE_TTL_MAX_USEC. */
1093 usec_t until = FLAGS_SET(query_flags, SD_RESOLVED_NO_STALE) ? j->until_valid
1094 : usec_add(current, CACHE_STALE_TTL_MAX_USEC);
1095
775ae354
LP
1096 /* Append the answer RRs to our answer. Ideally we have the answer object, which we
1097 * preferably use. But if the cached entry was generated as "side-effect" of a reply,
1098 * i.e. from validated auxiliary records rather than from the main reply, then we use the
1099 * individual RRs only instead. */
1100 if (j->answer) {
1101
1102 /* Minor optimization, if the full answer object of this and the previous RR is the
1103 * same, don't bother adding it again. Typically we store a full RRset here, hence
1104 * that should be the case. */
1105 if (!j->by_key_prev || j->answer != j->by_key_prev->answer) {
1106 DnsAnswerItem *item;
1107
1108 DNS_ANSWER_FOREACH_ITEM(item, j->answer) {
b974211a
LP
1109 r = answer_add_clamp_ttl(
1110 &answer,
1111 item->rr,
1112 item->ifindex,
1113 item->flags,
1114 item->rrsig,
1115 query_flags,
5ed91481 1116 until,
b974211a 1117 current);
775ae354
LP
1118 if (r < 0)
1119 return r;
1120 }
1121 }
1122
1123 } else if (j->rr) {
b974211a
LP
1124 r = answer_add_clamp_ttl(
1125 &answer,
1126 j->rr,
1127 j->ifindex,
1128 FLAGS_SET(j->query_flags, SD_RESOLVED_AUTHENTICATED) ? DNS_ANSWER_AUTHENTICATED : 0,
1129 NULL,
1130 query_flags,
5ed91481 1131 until,
b974211a 1132 current);
775ae354
LP
1133 if (r < 0)
1134 return r;
1135 }
1136
1137 /* We'll return any packet we have for this. Typically all cache entries for the same key
1138 * should come from the same packet anyway, hence it doesn't really matter which packet we
1139 * return here, they should all resolve to the same anyway. */
1140 if (!full_packet && j->full_packet)
1141 full_packet = dns_packet_ref(j->full_packet);
f52e61da 1142 }
6b34a6c9 1143
201d9958
LP
1144 if (found_rcode >= 0) {
1145 log_debug("RCODE %s cache hit for %s",
0d609349 1146 FORMAT_DNS_RCODE(found_rcode),
201d9958
LP
1147 dns_resource_key_to_string(key, key_str, sizeof(key_str)));
1148
775ae354
LP
1149 if (ret_rcode)
1150 *ret_rcode = found_rcode;
1151 if (ret_answer)
1152 *ret_answer = TAKE_PTR(answer);
1153 if (ret_full_packet)
1154 *ret_full_packet = TAKE_PTR(full_packet);
6f055e43
LP
1155 if (ret_query_flags)
1156 *ret_query_flags = 0;
775ae354
LP
1157 if (ret_dnssec_result)
1158 *ret_dnssec_result = dnssec_result;
201d9958
LP
1159
1160 c->n_hit++;
1161 return 1;
1162 }
1163
f6618dcd 1164 if (nsec && !IN_SET(key->type, DNS_TYPE_NSEC, DNS_TYPE_DS)) {
775ae354
LP
1165 /* Note that we won't derive information for DS RRs from an NSEC, because we only cache NSEC
1166 * RRs from the lower-zone of a zone cut, but the DS RRs are on the upper zone. */
f6618dcd 1167
202b76ae
ZJS
1168 log_debug("NSEC NODATA cache hit for %s",
1169 dns_resource_key_to_string(key, key_str, sizeof key_str));
37da8931 1170
775ae354
LP
1171 /* We only found an NSEC record that matches our name. If it says the type doesn't exist
1172 * report NODATA. Otherwise report a cache miss. */
37da8931 1173
775ae354
LP
1174 if (ret_rcode)
1175 *ret_rcode = DNS_RCODE_SUCCESS;
1176 if (ret_answer)
1177 *ret_answer = TAKE_PTR(answer);
1178 if (ret_full_packet)
1179 *ret_full_packet = TAKE_PTR(full_packet);
6f055e43
LP
1180 if (ret_query_flags)
1181 *ret_query_flags = nsec->query_flags;
775ae354
LP
1182 if (ret_dnssec_result)
1183 *ret_dnssec_result = nsec->dnssec_result;
37da8931 1184
a150ff5e
LP
1185 if (!bitmap_isset(nsec->rr->nsec.types, key->type) &&
1186 !bitmap_isset(nsec->rr->nsec.types, DNS_TYPE_CNAME) &&
1187 !bitmap_isset(nsec->rr->nsec.types, DNS_TYPE_DNAME)) {
1188 c->n_hit++;
1189 return 1;
1190 }
1191
1192 c->n_miss++;
1193 return 0;
37da8931
LP
1194 }
1195
202b76ae
ZJS
1196 log_debug("%s cache hit for %s",
1197 n > 0 ? "Positive" :
1198 nxdomain ? "NXDOMAIN" : "NODATA",
1199 dns_resource_key_to_string(key, key_str, sizeof key_str));
faa133f3 1200
7e8e0422 1201 if (n <= 0) {
a150ff5e
LP
1202 c->n_hit++;
1203
775ae354
LP
1204 if (ret_rcode)
1205 *ret_rcode = nxdomain ? DNS_RCODE_NXDOMAIN : DNS_RCODE_SUCCESS;
1206 if (ret_answer)
1207 *ret_answer = TAKE_PTR(answer);
1208 if (ret_full_packet)
1209 *ret_full_packet = TAKE_PTR(full_packet);
6f055e43 1210 if (ret_query_flags)
43fc4baa
LP
1211 *ret_query_flags =
1212 ((have_authenticated && !have_non_authenticated) ? SD_RESOLVED_AUTHENTICATED : 0) |
1213 ((have_confidential && !have_non_confidential) ? SD_RESOLVED_CONFIDENTIAL : 0);
775ae354
LP
1214 if (ret_dnssec_result)
1215 *ret_dnssec_result = dnssec_result;
17c8de63 1216
775ae354 1217 return 1;
322345fd
LP
1218 }
1219
a150ff5e
LP
1220 c->n_hit++;
1221
775ae354
LP
1222 if (ret_rcode)
1223 *ret_rcode = DNS_RCODE_SUCCESS;
1224 if (ret_answer)
1225 *ret_answer = TAKE_PTR(answer);
1226 if (ret_full_packet)
1227 *ret_full_packet = TAKE_PTR(full_packet);
6f055e43 1228 if (ret_query_flags)
43fc4baa
LP
1229 *ret_query_flags =
1230 ((have_authenticated && !have_non_authenticated) ? SD_RESOLVED_AUTHENTICATED : 0) |
1231 ((have_confidential && !have_non_confidential) ? SD_RESOLVED_CONFIDENTIAL : 0);
775ae354
LP
1232 if (ret_dnssec_result)
1233 *ret_dnssec_result = dnssec_result;
faa133f3
LP
1234
1235 return n;
775ae354
LP
1236
1237miss:
1238 if (ret_rcode)
1239 *ret_rcode = DNS_RCODE_SUCCESS;
1240 if (ret_answer)
1241 *ret_answer = NULL;
1242 if (ret_full_packet)
1243 *ret_full_packet = NULL;
6f055e43
LP
1244 if (ret_query_flags)
1245 *ret_query_flags = 0;
775ae354
LP
1246 if (ret_dnssec_result)
1247 *ret_dnssec_result = _DNSSEC_RESULT_INVALID;
1248
1249 c->n_miss++;
1250 return 0;
322345fd 1251}
a4076574
LP
1252
1253int dns_cache_check_conflicts(DnsCache *cache, DnsResourceRecord *rr, int owner_family, const union in_addr_union *owner_address) {
03677889 1254 DnsCacheItem *first;
a4076574
LP
1255 bool same_owner = true;
1256
1257 assert(cache);
1258 assert(rr);
1259
1260 dns_cache_prune(cache);
1261
1262 /* See if there's a cache entry for the same key. If there
1263 * isn't there's no conflict */
1264 first = hashmap_get(cache->by_key, rr->key);
1265 if (!first)
1266 return 0;
1267
1268 /* See if the RR key is owned by the same owner, if so, there
1269 * isn't a conflict either */
1270 LIST_FOREACH(by_key, i, first) {
1271 if (i->owner_family != owner_family ||
1272 !in_addr_equal(owner_family, &i->owner_address, owner_address)) {
1273 same_owner = false;
1274 break;
1275 }
1276 }
1277 if (same_owner)
1278 return 0;
1279
1280 /* See if there's the exact same RR in the cache. If yes, then
1281 * there's no conflict. */
1282 if (dns_cache_get(cache, rr))
1283 return 0;
1284
1285 /* There's a conflict */
1286 return 1;
1287}
4d506d6b 1288
325513bc 1289int dns_cache_export_shared_to_packet(DnsCache *cache, DnsPacket *p, usec_t ts, unsigned max_rr) {
7778dfff 1290 unsigned ancount = 0;
7778dfff
DM
1291 DnsCacheItem *i;
1292 int r;
1293
1294 assert(cache);
261f3673 1295 assert(p);
325513bc 1296 assert(p->protocol == DNS_PROTOCOL_MDNS);
f941c124 1297
03677889 1298 HASHMAP_FOREACH(i, cache->by_key)
7778dfff 1299 LIST_FOREACH(by_key, j, i) {
7778dfff
DM
1300 if (!j->rr)
1301 continue;
1302
d2579eec 1303 if (!j->shared_owner)
7778dfff
DM
1304 continue;
1305
f941c124
VCS
1306 /* RFC6762 7.1: Don't append records with less than half the TTL remaining
1307 * as known answers. */
325513bc 1308 if (usec_sub_unsigned(j->until, ts) < j->rr->ttl * USEC_PER_SEC / 2)
f941c124
VCS
1309 continue;
1310
6cfa4fc4
YW
1311 if (max_rr > 0 && ancount >= max_rr) {
1312 DNS_PACKET_HEADER(p)->ancount = htobe16(ancount);
1313 ancount = 0;
1314
1315 r = dns_packet_new_query(&p->more, p->protocol, 0, true);
1316 if (r < 0)
1317 return r;
1318
1319 p = p->more;
1320
1321 max_rr = UINT_MAX;
1322 }
1323
58ab31d5 1324 r = dns_packet_append_rr(p, j->rr, 0, NULL, NULL);
325513bc
YW
1325 if (r == -EMSGSIZE) {
1326 if (max_rr == 0)
1327 /* If max_rr == 0, do not allocate more packets. */
1328 goto finalize;
1329
1330 /* If we're unable to stuff all known answers into the given packet, allocate
1331 * a new one, push the RR into that one and link it to the current one. */
261f3673
DM
1332
1333 DNS_PACKET_HEADER(p)->ancount = htobe16(ancount);
1334 ancount = 0;
1335
1336 r = dns_packet_new_query(&p->more, p->protocol, 0, true);
1337 if (r < 0)
1338 return r;
1339
1340 /* continue with new packet */
1341 p = p->more;
58ab31d5 1342 r = dns_packet_append_rr(p, j->rr, 0, NULL, NULL);
261f3673
DM
1343 }
1344
7778dfff
DM
1345 if (r < 0)
1346 return r;
1347
313cefa1 1348 ancount++;
7778dfff 1349 }
7778dfff 1350
325513bc 1351finalize:
7778dfff
DM
1352 DNS_PACKET_HEADER(p)->ancount = htobe16(ancount);
1353
1354 return 0;
1355}
1356
ca9fab88 1357void dns_cache_dump(DnsCache *cache, FILE *f) {
4d506d6b 1358 DnsCacheItem *i;
4d506d6b
LP
1359
1360 if (!cache)
1361 return;
1362
1363 if (!f)
1364 f = stdout;
1365
03677889 1366 HASHMAP_FOREACH(i, cache->by_key)
4d506d6b 1367 LIST_FOREACH(by_key, j, i) {
4d506d6b
LP
1368
1369 fputc('\t', f);
1370
1371 if (j->rr) {
7b50eb2e
LP
1372 const char *t;
1373 t = dns_resource_record_to_string(j->rr);
1374 if (!t) {
4d506d6b
LP
1375 log_oom();
1376 continue;
1377 }
1378
1379 fputs(t, f);
1380 fputc('\n', f);
1381 } else {
202b76ae 1382 char key_str[DNS_RESOURCE_KEY_STRING_MAX];
4d506d6b 1383
202b76ae 1384 fputs(dns_resource_key_to_string(j->key, key_str, sizeof key_str), f);
4d506d6b 1385 fputs(" -- ", f);
201d9958 1386 fputs(dns_cache_item_type_to_string(j), f);
4d506d6b
LP
1387 fputc('\n', f);
1388 }
1389 }
4d506d6b
LP
1390}
1391
e0930aa6
LP
1392int dns_cache_dump_to_json(DnsCache *cache, JsonVariant **ret) {
1393 _cleanup_(json_variant_unrefp) JsonVariant *c = NULL;
1394 DnsCacheItem *i;
1395 int r;
1396
1397 assert(cache);
1398 assert(ret);
1399
1400 HASHMAP_FOREACH(i, cache->by_key) {
1401 _cleanup_(json_variant_unrefp) JsonVariant *d = NULL, *k = NULL;
1402
1403 r = dns_resource_key_to_json(i->key, &k);
1404 if (r < 0)
1405 return r;
1406
1407 if (i->rr) {
1408 _cleanup_(json_variant_unrefp) JsonVariant *l = NULL;
1409
1410 LIST_FOREACH(by_key, j, i) {
c91f581c 1411 _cleanup_(json_variant_unrefp) JsonVariant *rj = NULL;
e0930aa6
LP
1412
1413 assert(j->rr);
1414
1415 r = dns_resource_record_to_json(j->rr, &rj);
1416 if (r < 0)
1417 return r;
1418
1419 r = dns_resource_record_to_wire_format(j->rr, /* canonical= */ false); /* don't use DNSSEC canonical format, since it removes casing, but we want that for DNS_SD compat */
1420 if (r < 0)
1421 return r;
1422
c91f581c
LP
1423 r = json_variant_append_arrayb(
1424 &l,
1425 JSON_BUILD_OBJECT(
1426 JSON_BUILD_PAIR_VARIANT("rr", rj),
1427 JSON_BUILD_PAIR_BASE64("raw", j->rr->wire_format, j->rr->wire_format_size)));
e0930aa6
LP
1428 if (r < 0)
1429 return r;
1430 }
1431
1432 if (!l) {
1433 r = json_variant_new_array(&l, NULL, 0);
1434 if (r < 0)
1435 return r;
1436 }
1437
1438 r = json_build(&d,
1439 JSON_BUILD_OBJECT(
1440 JSON_BUILD_PAIR_VARIANT("key", k),
1441 JSON_BUILD_PAIR_VARIANT("rrs", l),
1442 JSON_BUILD_PAIR_UNSIGNED("until", i->until)));
1443 } else if (i->type == DNS_CACHE_NODATA) {
1444 r = json_build(&d,
1445 JSON_BUILD_OBJECT(
1446 JSON_BUILD_PAIR_VARIANT("key", k),
1447 JSON_BUILD_PAIR_EMPTY_ARRAY("rrs"),
1448 JSON_BUILD_PAIR_UNSIGNED("until", i->until)));
1449 } else
1450 r = json_build(&d,
1451 JSON_BUILD_OBJECT(
1452 JSON_BUILD_PAIR_VARIANT("key", k),
1453 JSON_BUILD_PAIR_STRING("type", dns_cache_item_type_to_string(i)),
1454 JSON_BUILD_PAIR_UNSIGNED("until", i->until)));
1455 if (r < 0)
1456 return r;
1457
1458 r = json_variant_append_array(&c, d);
1459 if (r < 0)
1460 return r;
1461 }
1462
1463 if (!c)
1464 return json_variant_new_array(ret, NULL, 0);
1465
1466 *ret = TAKE_PTR(c);
1467 return 0;
1468}
1469
4d506d6b
LP
1470bool dns_cache_is_empty(DnsCache *cache) {
1471 if (!cache)
1472 return true;
1473
1474 return hashmap_isempty(cache->by_key);
1475}
a150ff5e
LP
1476
1477unsigned dns_cache_size(DnsCache *cache) {
1478 if (!cache)
1479 return 0;
1480
1481 return hashmap_size(cache->by_key);
1482}