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