]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/resolve/resolved-dns-answer.c
executor: check for all permission related errnos when setting up IPC namespace
[thirdparty/systemd.git] / src / resolve / resolved-dns-answer.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <stdio.h>
4
5 #include "alloc-util.h"
6 #include "dns-domain.h"
7 #include "random-util.h"
8 #include "resolved-dns-answer.h"
9 #include "resolved-dns-dnssec.h"
10 #include "string-util.h"
11
12 static DnsAnswerItem *dns_answer_item_free(DnsAnswerItem *item) {
13 if (!item)
14 return NULL;
15
16 dns_resource_record_unref(item->rr);
17 dns_resource_record_unref(item->rrsig);
18
19 return mfree(item);
20 }
21
22 DEFINE_PRIVATE_TRIVIAL_REF_UNREF_FUNC(DnsAnswerItem, dns_answer_item, dns_answer_item_free);
23 DEFINE_TRIVIAL_CLEANUP_FUNC(DnsAnswerItem*, dns_answer_item_unref);
24
25 static void dns_answer_item_hash_func(const DnsAnswerItem *a, struct siphash *state) {
26 assert(a);
27 assert(state);
28
29 siphash24_compress_typesafe(a->ifindex, state);
30
31 dns_resource_record_hash_func(a->rr, state);
32 }
33
34 static int dns_answer_item_compare_func(const DnsAnswerItem *a, const DnsAnswerItem *b) {
35 int r;
36
37 assert(a);
38 assert(b);
39
40 r = CMP(a->ifindex, b->ifindex);
41 if (r != 0)
42 return r;
43
44 return dns_resource_record_compare_func(a->rr, b->rr);
45 }
46
47 DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
48 dns_answer_item_hash_ops,
49 DnsAnswerItem,
50 dns_answer_item_hash_func,
51 dns_answer_item_compare_func,
52 dns_answer_item_unref);
53
54 static int dns_answer_reserve_internal(DnsAnswer *a, size_t n) {
55 size_t m;
56
57 assert(a);
58 assert(a->items);
59
60 m = ordered_set_size(a->items);
61 assert(m <= UINT16_MAX); /* We can only place 64K RRs in an answer at max */
62
63 n = saturate_add(m, n, UINT16_MAX);
64
65 /* Higher multipliers give slightly higher efficiency through hash collisions, but the gains
66 * quickly drop off after 2. */
67 return ordered_set_reserve(a->items, n * 2);
68 }
69
70 DnsAnswer *dns_answer_new(size_t n) {
71 _cleanup_ordered_set_free_ OrderedSet *s = NULL;
72 _cleanup_(dns_answer_unrefp) DnsAnswer *a = NULL;
73
74 if (n > UINT16_MAX)
75 n = UINT16_MAX;
76
77 s = ordered_set_new(&dns_answer_item_hash_ops);
78 if (!s)
79 return NULL;
80
81 a = new(DnsAnswer, 1);
82 if (!a)
83 return NULL;
84
85 *a = (DnsAnswer) {
86 .n_ref = 1,
87 .items = TAKE_PTR(s),
88 };
89
90 if (dns_answer_reserve_internal(a, n) < 0)
91 return NULL;
92
93 return TAKE_PTR(a);
94 }
95
96 static DnsAnswer *dns_answer_free(DnsAnswer *a) {
97 assert(a);
98
99 ordered_set_free(a->items);
100 return mfree(a);
101 }
102
103 DEFINE_TRIVIAL_REF_UNREF_FUNC(DnsAnswer, dns_answer, dns_answer_free);
104
105 static int dns_answer_add_raw(
106 DnsAnswer *a,
107 DnsResourceRecord *rr,
108 int ifindex,
109 DnsAnswerFlags flags,
110 DnsResourceRecord *rrsig) {
111
112 _cleanup_(dns_answer_item_unrefp) DnsAnswerItem *item = NULL;
113 int r;
114
115 assert(rr);
116
117 if (!a)
118 return -ENOSPC;
119
120 if (dns_answer_size(a) >= UINT16_MAX)
121 return -ENOSPC;
122
123 item = new(DnsAnswerItem, 1);
124 if (!item)
125 return -ENOMEM;
126
127 *item = (DnsAnswerItem) {
128 .n_ref = 1,
129 .rr = dns_resource_record_ref(rr),
130 .ifindex = ifindex,
131 .flags = flags,
132 .rrsig = dns_resource_record_ref(rrsig),
133 };
134
135 r = ordered_set_put(a->items, item);
136 if (r < 0)
137 return r;
138
139 TAKE_PTR(item);
140 return 1;
141 }
142
143 static int dns_answer_add_raw_all(DnsAnswer *a, DnsAnswer *source) {
144 DnsAnswerItem *item;
145 int r;
146
147 DNS_ANSWER_FOREACH_ITEM(item, source) {
148 r = dns_answer_add_raw(
149 a,
150 item->rr,
151 item->ifindex,
152 item->flags,
153 item->rrsig);
154 if (r < 0)
155 return r;
156 }
157
158 return 0;
159 }
160
161 int dns_answer_add(
162 DnsAnswer *a,
163 DnsResourceRecord *rr,
164 int ifindex,
165 DnsAnswerFlags flags,
166 DnsResourceRecord *rrsig) {
167
168 DnsAnswerItem tmp, *exist;
169
170 assert(rr);
171
172 if (!a)
173 return -ENOSPC;
174 if (a->n_ref > 1)
175 return -EBUSY;
176
177 tmp = (DnsAnswerItem) {
178 .rr = rr,
179 .ifindex = ifindex,
180 };
181
182 exist = ordered_set_get(a->items, &tmp);
183 if (exist) {
184 /* There's already an RR of the same RRset in place! Let's see if the TTLs more or
185 * less match. RFC 2181, Section 5.2 suggests clients should reject RRsets
186 * containing RRs with differing TTLs. We are more tolerant of this situation except
187 * if one RR has a zero TTL and the other a nonzero TTL. In mDNS, zero TTLs are
188 * special, so we must error in that case. */
189 if ((rr->ttl == 0) != (exist->rr->ttl == 0)) {
190 if ((exist->flags | flags) & DNS_ANSWER_REFUSE_TTL_NO_MATCH)
191 return log_debug_errno(
192 SYNTHETIC_ERRNO(EINVAL),
193 "Refusing to merge RRs with zero TTL and non-zero TTL: %s vs. %s",
194 dns_resource_record_to_string(rr),
195 dns_resource_record_to_string(exist->rr));
196
197 log_debug("Merging RRs with zero TTL and non-zero TTL (not RFC 2181/5.2 compliant): %s vs. %s",
198 dns_resource_record_to_string(rr),
199 dns_resource_record_to_string(exist->rr));
200 }
201
202 /* Entry already exists, keep the entry with the higher TTL. */
203 if (rr->ttl > exist->rr->ttl) {
204 DNS_RR_REPLACE(exist->rr, dns_resource_record_ref(rr));
205
206 /* Update RRSIG and RR at the same time */
207 if (rrsig)
208 DNS_RR_REPLACE(exist->rrsig, dns_resource_record_ref(rrsig));
209 }
210
211 exist->flags |= flags;
212
213 if (rr->key->type == DNS_TYPE_RRSIG) {
214 /* If the rr is RRSIG, then move the rr to the end. */
215 assert_se(ordered_set_remove(a->items, exist) == exist);
216 assert_se(ordered_set_put(a->items, exist) == 1);
217 }
218 return 0;
219 }
220
221 return dns_answer_add_raw(a, rr, ifindex, flags, rrsig);
222 }
223
224 static int dns_answer_add_all(DnsAnswer *a, DnsAnswer *b) {
225 DnsAnswerItem *item;
226 int r;
227
228 DNS_ANSWER_FOREACH_ITEM(item, b) {
229 r = dns_answer_add(a, item->rr, item->ifindex, item->flags, item->rrsig);
230 if (r < 0)
231 return r;
232 }
233
234 return 0;
235 }
236
237 int dns_answer_add_extend(
238 DnsAnswer **a,
239 DnsResourceRecord *rr,
240 int ifindex,
241 DnsAnswerFlags flags,
242 DnsResourceRecord *rrsig) {
243
244 int r;
245
246 assert(a);
247 assert(rr);
248
249 r = dns_answer_reserve_or_clone(a, 1);
250 if (r < 0)
251 return r;
252
253 return dns_answer_add(*a, rr, ifindex, flags, rrsig);
254 }
255
256 int dns_answer_add_soa(DnsAnswer *a, const char *name, uint32_t ttl, int ifindex) {
257 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *soa = NULL;
258
259 soa = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_SOA, name);
260 if (!soa)
261 return -ENOMEM;
262
263 soa->ttl = ttl;
264
265 soa->soa.mname = strdup(name);
266 if (!soa->soa.mname)
267 return -ENOMEM;
268
269 soa->soa.rname = strjoin("root.", name);
270 if (!soa->soa.rname)
271 return -ENOMEM;
272
273 soa->soa.serial = 1;
274 soa->soa.refresh = 1;
275 soa->soa.retry = 1;
276 soa->soa.expire = 1;
277 soa->soa.minimum = ttl;
278
279 return dns_answer_add(a, soa, ifindex, DNS_ANSWER_AUTHENTICATED, NULL);
280 }
281
282 int dns_answer_match_key(DnsAnswer *a, const DnsResourceKey *key, DnsAnswerFlags *ret_flags) {
283 DnsAnswerFlags flags = 0, i_flags;
284 DnsResourceRecord *i;
285 bool found = false;
286 int r;
287
288 assert(key);
289
290 DNS_ANSWER_FOREACH_FLAGS(i, i_flags, a) {
291 r = dns_resource_key_match_rr(key, i, NULL);
292 if (r < 0)
293 return r;
294 if (r == 0)
295 continue;
296
297 if (!ret_flags)
298 return 1;
299
300 if (found)
301 flags &= i_flags;
302 else {
303 flags = i_flags;
304 found = true;
305 }
306 }
307
308 if (ret_flags)
309 *ret_flags = flags;
310
311 return found;
312 }
313
314 bool dns_answer_contains_nsec_or_nsec3(DnsAnswer *a) {
315 DnsResourceRecord *i;
316
317 DNS_ANSWER_FOREACH(i, a)
318 if (IN_SET(i->key->type, DNS_TYPE_NSEC, DNS_TYPE_NSEC3))
319 return true;
320
321 return false;
322 }
323
324 int dns_answer_contains_zone_nsec3(DnsAnswer *answer, const char *zone) {
325 DnsResourceRecord *rr;
326 int r;
327
328 /* Checks whether the specified answer contains at least one NSEC3 RR in the specified zone */
329
330 DNS_ANSWER_FOREACH(rr, answer) {
331 const char *p;
332
333 if (rr->key->type != DNS_TYPE_NSEC3)
334 continue;
335
336 p = dns_resource_key_name(rr->key);
337 r = dns_name_parent(&p);
338 if (r < 0)
339 return r;
340 if (r == 0)
341 continue;
342
343 r = dns_name_equal(p, zone);
344 if (r != 0)
345 return r;
346 }
347
348 return false;
349 }
350
351 bool dns_answer_contains(DnsAnswer *answer, DnsResourceRecord *rr) {
352 DnsResourceRecord *i;
353
354 DNS_ANSWER_FOREACH(i, answer)
355 if (dns_resource_record_equal(i, rr))
356 return true;
357
358 return false;
359 }
360
361 int dns_answer_find_soa(
362 DnsAnswer *a,
363 const DnsResourceKey *key,
364 DnsResourceRecord **ret,
365 DnsAnswerFlags *ret_flags) {
366
367 DnsResourceRecord *rr, *soa = NULL;
368 DnsAnswerFlags rr_flags, soa_flags = 0;
369 int r;
370
371 assert(key);
372
373 /* For a SOA record we can never find a matching SOA record */
374 if (key->type == DNS_TYPE_SOA)
375 goto not_found;
376
377 DNS_ANSWER_FOREACH_FLAGS(rr, rr_flags, a) {
378 r = dns_resource_key_match_soa(key, rr->key);
379 if (r < 0)
380 return r;
381 if (r > 0) {
382
383 if (soa) {
384 r = dns_name_endswith(dns_resource_key_name(rr->key), dns_resource_key_name(soa->key));
385 if (r < 0)
386 return r;
387 if (r > 0)
388 continue;
389 }
390
391 soa = rr;
392 soa_flags = rr_flags;
393 }
394 }
395
396 if (!soa)
397 goto not_found;
398
399 if (ret)
400 *ret = soa;
401 if (ret_flags)
402 *ret_flags = soa_flags;
403
404 return 1;
405
406 not_found:
407 if (ret)
408 *ret = NULL;
409 if (ret_flags)
410 *ret_flags = 0;
411
412 return 0;
413 }
414
415 int dns_answer_find_cname_or_dname(
416 DnsAnswer *a,
417 const DnsResourceKey *key,
418 DnsResourceRecord **ret,
419 DnsAnswerFlags *ret_flags) {
420
421 DnsResourceRecord *rr;
422 DnsAnswerFlags rr_flags;
423 int r;
424
425 assert(key);
426
427 /* For a {C,D}NAME record we can never find a matching {C,D}NAME record */
428 if (!dns_type_may_redirect(key->type))
429 return 0;
430
431 DNS_ANSWER_FOREACH_FLAGS(rr, rr_flags, a) {
432 r = dns_resource_key_match_cname_or_dname(key, rr->key, NULL);
433 if (r < 0)
434 return r;
435 if (r > 0) {
436 if (ret)
437 *ret = rr;
438 if (ret_flags)
439 *ret_flags = rr_flags;
440 return 1;
441 }
442 }
443
444 if (ret)
445 *ret = NULL;
446 if (ret_flags)
447 *ret_flags = 0;
448
449 return 0;
450 }
451
452 int dns_answer_merge(DnsAnswer *a, DnsAnswer *b, DnsAnswer **ret) {
453 _cleanup_(dns_answer_unrefp) DnsAnswer *k = NULL;
454 int r;
455
456 assert(ret);
457
458 if (a == b) {
459 *ret = dns_answer_ref(a);
460 return 0;
461 }
462
463 if (dns_answer_size(a) <= 0) {
464 *ret = dns_answer_ref(b);
465 return 0;
466 }
467
468 if (dns_answer_size(b) <= 0) {
469 *ret = dns_answer_ref(a);
470 return 0;
471 }
472
473 k = dns_answer_new(dns_answer_size(a) + dns_answer_size(b));
474 if (!k)
475 return -ENOMEM;
476
477 r = dns_answer_add_raw_all(k, a);
478 if (r < 0)
479 return r;
480
481 r = dns_answer_add_all(k, b);
482 if (r < 0)
483 return r;
484
485 *ret = TAKE_PTR(k);
486
487 return 0;
488 }
489
490 int dns_answer_extend(DnsAnswer **a, DnsAnswer *b) {
491 DnsAnswer *merged;
492 int r;
493
494 assert(a);
495
496 r = dns_answer_merge(*a, b, &merged);
497 if (r < 0)
498 return r;
499
500 DNS_ANSWER_REPLACE(*a, merged);
501 return 0;
502 }
503
504 int dns_answer_remove_by_key(DnsAnswer **a, const DnsResourceKey *key) {
505 DnsAnswerItem *item;
506 bool found = false;
507 int r;
508
509 assert(a);
510 assert(key);
511
512 /* Remove all entries matching the specified key from *a */
513
514 DNS_ANSWER_FOREACH_ITEM(item, *a) {
515 r = dns_resource_key_equal(item->rr->key, key);
516 if (r < 0)
517 return r;
518 if (r > 0) {
519 dns_answer_item_unref(ordered_set_remove((*a)->items, item));
520 found = true;
521 }
522 }
523
524 if (!found)
525 return 0;
526
527 if (dns_answer_isempty(*a))
528 *a = dns_answer_unref(*a); /* Return NULL for the empty answer */
529
530 return 1;
531 }
532
533 int dns_answer_remove_by_rr(DnsAnswer **a, DnsResourceRecord *rr) {
534 _unused_ _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr_ref = dns_resource_record_ref(rr);
535 DnsAnswerItem *item;
536 bool found = false;
537 int r;
538
539 assert(a);
540 assert(rr);
541
542 /* Remove all entries matching the specified RR from *a */
543
544 DNS_ANSWER_FOREACH_ITEM(item, *a) {
545 r = dns_resource_record_equal(item->rr, rr);
546 if (r < 0)
547 return r;
548 if (r > 0) {
549 dns_answer_item_unref(ordered_set_remove((*a)->items, item));
550 found = true;
551 }
552 }
553
554 if (!found)
555 return 0;
556
557 if (dns_answer_isempty(*a))
558 *a = dns_answer_unref(*a); /* Return NULL for the empty answer */
559
560 return 1;
561 }
562
563 int dns_answer_remove_by_answer_keys(DnsAnswer **a, DnsAnswer *b) {
564 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *prev = NULL;
565 DnsAnswerItem *item;
566 int r;
567
568 /* Removes all items from '*a' that have a matching key in 'b' */
569
570 DNS_ANSWER_FOREACH_ITEM(item, b) {
571
572 if (prev && dns_resource_key_equal(item->rr->key, prev)) /* Skip this one, we already looked at it */
573 continue;
574
575 r = dns_answer_remove_by_key(a, item->rr->key);
576 if (r < 0)
577 return r;
578 if (!*a)
579 return 0; /* a is already empty. */
580
581 /* Let's remember this entry's RR key, to optimize the loop a bit: if we have an RRset with
582 * more than one item then we don't need to remove the key multiple times */
583 DNS_RESOURCE_KEY_REPLACE(prev, dns_resource_key_ref(item->rr->key));
584 }
585
586 return 0;
587 }
588
589 int dns_answer_copy_by_key(
590 DnsAnswer **a,
591 DnsAnswer *source,
592 const DnsResourceKey *key,
593 DnsAnswerFlags or_flags,
594 DnsResourceRecord *rrsig) {
595
596 DnsAnswerItem *item;
597 int r;
598
599 assert(a);
600 assert(key);
601
602 /* Copy all RRs matching the specified key from source into *a */
603
604 DNS_ANSWER_FOREACH_ITEM(item, source) {
605
606 r = dns_resource_key_equal(item->rr->key, key);
607 if (r < 0)
608 return r;
609 if (r == 0)
610 continue;
611
612 r = dns_answer_add_extend(a, item->rr, item->ifindex, item->flags|or_flags, rrsig ?: item->rrsig);
613 if (r < 0)
614 return r;
615 }
616
617 return 0;
618 }
619
620 int dns_answer_move_by_key(
621 DnsAnswer **to,
622 DnsAnswer **from,
623 const DnsResourceKey *key,
624 DnsAnswerFlags or_flags,
625 DnsResourceRecord *rrsig) {
626
627 int r;
628
629 assert(to);
630 assert(from);
631 assert(key);
632
633 r = dns_answer_copy_by_key(to, *from, key, or_flags, rrsig);
634 if (r < 0)
635 return r;
636
637 return dns_answer_remove_by_key(from, key);
638 }
639
640 void dns_answer_order_by_scope(DnsAnswer *a, bool prefer_link_local) {
641 _cleanup_free_ DnsAnswerItem **items = NULL;
642 DnsAnswerItem **p, *item;
643 size_t n;
644
645 n = dns_answer_size(a);
646 if (n <= 1)
647 return;
648
649 /* RFC 4795, Section 2.6 suggests we should order entries
650 * depending on whether the sender is a link-local address. */
651
652 p = items = new(DnsAnswerItem*, n);
653 if (!items)
654 return (void) log_oom();
655
656 /* Order preferred address records and other records to the beginning of the array */
657 DNS_ANSWER_FOREACH_ITEM(item, a)
658 if (dns_resource_record_is_link_local_address(item->rr) == prefer_link_local)
659 *p++ = dns_answer_item_ref(item);
660
661 /* Order address records that are not preferred to the end of the array */
662 DNS_ANSWER_FOREACH_ITEM(item, a)
663 if (dns_resource_record_is_link_local_address(item->rr) != prefer_link_local)
664 *p++ = dns_answer_item_ref(item);
665
666
667 assert((size_t) (p - items) == n);
668
669 ordered_set_clear(a->items);
670 for (size_t i = 0; i < n; i++)
671 assert_se(ordered_set_put(a->items, items[i]) >= 0);
672 }
673
674 int dns_answer_reserve(DnsAnswer **a, size_t n_free) {
675 assert(a);
676
677 if (n_free <= 0)
678 return 0;
679
680 if (!*a) {
681 DnsAnswer *n;
682
683 n = dns_answer_new(n_free);
684 if (!n)
685 return -ENOMEM;
686
687 *a = n;
688 return 0;
689 }
690
691 if ((*a)->n_ref > 1)
692 return -EBUSY;
693
694 return dns_answer_reserve_internal(*a, n_free);
695 }
696
697 int dns_answer_reserve_or_clone(DnsAnswer **a, size_t n_free) {
698 _cleanup_(dns_answer_unrefp) DnsAnswer *n = NULL;
699 size_t ns;
700 int r;
701
702 assert(a);
703
704 r = dns_answer_reserve(a, n_free);
705 if (r != -EBUSY)
706 return r;
707
708 ns = dns_answer_size(*a);
709 assert(ns <= UINT16_MAX); /* Maximum number of RRs we can stick into a DNS packet section */
710
711 ns = saturate_add(ns, n_free, UINT16_MAX);
712
713 n = dns_answer_new(ns);
714 if (!n)
715 return -ENOMEM;
716
717 r = dns_answer_add_raw_all(n, *a);
718 if (r < 0)
719 return r;
720
721 DNS_ANSWER_REPLACE(*a, TAKE_PTR(n));
722 return 0;
723 }
724
725 /*
726 * This function is not used in the code base, but is useful when debugging. Do not delete.
727 */
728 void dns_answer_dump(DnsAnswer *answer, FILE *f) {
729 DnsAnswerItem *item;
730
731 if (!f)
732 f = stdout;
733
734 DNS_ANSWER_FOREACH_ITEM(item, answer) {
735 const char *t;
736
737 fputc('\t', f);
738
739 t = dns_resource_record_to_string(item->rr);
740 if (!t) {
741 log_oom();
742 continue;
743 }
744
745 fputs(t, f);
746 fputs("\t;", f);
747 fprintf(f, " ttl=%" PRIu32, item->rr->ttl);
748
749 if (item->ifindex != 0)
750 fprintf(f, " ifindex=%i", item->ifindex);
751 if (item->rrsig)
752 fputs(" rrsig", f);
753 if (item->flags & DNS_ANSWER_AUTHENTICATED)
754 fputs(" authenticated", f);
755 if (item->flags & DNS_ANSWER_CACHEABLE)
756 fputs(" cacheable", f);
757 if (item->flags & DNS_ANSWER_SHARED_OWNER)
758 fputs(" shared-owner", f);
759 if (item->flags & DNS_ANSWER_CACHE_FLUSH)
760 fputs(" cache-flush", f);
761 if (item->flags & DNS_ANSWER_GOODBYE)
762 fputs(" goodbye", f);
763 if (item->flags & DNS_ANSWER_SECTION_ANSWER)
764 fputs(" section-answer", f);
765 if (item->flags & DNS_ANSWER_SECTION_AUTHORITY)
766 fputs(" section-authority", f);
767 if (item->flags & DNS_ANSWER_SECTION_ADDITIONAL)
768 fputs(" section-additional", f);
769
770 fputc('\n', f);
771 }
772 }
773
774 int dns_answer_has_dname_for_cname(DnsAnswer *a, DnsResourceRecord *cname) {
775 DnsResourceRecord *rr;
776 int r;
777
778 assert(cname);
779
780 /* Checks whether the answer contains a DNAME record that indicates that the specified CNAME record is
781 * synthesized from it */
782
783 if (cname->key->type != DNS_TYPE_CNAME)
784 return 0;
785
786 DNS_ANSWER_FOREACH(rr, a) {
787 _cleanup_free_ char *n = NULL;
788
789 if (rr->key->type != DNS_TYPE_DNAME)
790 continue;
791 if (rr->key->class != cname->key->class)
792 continue;
793
794 r = dns_name_change_suffix(cname->cname.name, rr->dname.name, dns_resource_key_name(rr->key), &n);
795 if (r < 0)
796 return r;
797 if (r == 0)
798 continue;
799
800 r = dns_name_equal(n, dns_resource_key_name(cname->key));
801 if (r < 0)
802 return r;
803 if (r > 0)
804 return 1;
805 }
806
807 return 0;
808 }
809
810 void dns_answer_randomize(DnsAnswer *a) {
811 _cleanup_free_ DnsAnswerItem **items = NULL;
812 DnsAnswerItem **p, *item;
813 size_t n;
814
815 /* Permutes the answer list randomly (Knuth shuffle) */
816
817 n = dns_answer_size(a);
818 if (n <= 1)
819 return;
820
821 p = items = new(DnsAnswerItem*, n);
822 if (!items)
823 return (void) log_oom();
824
825 DNS_ANSWER_FOREACH_ITEM(item, a)
826 *p++ = dns_answer_item_ref(item);
827
828 assert((size_t) (p - items) == n);
829
830 for (size_t i = 0; i < n; i++) {
831 size_t k;
832
833 k = random_u64_range(n);
834 if (k == i)
835 continue;
836
837 SWAP_TWO(items[i], items[k]);
838 }
839
840 ordered_set_clear(a->items);
841 for (size_t i = 0; i < n; i++)
842 assert_se(ordered_set_put(a->items, items[i]) >= 0);
843 }
844
845 uint32_t dns_answer_min_ttl(DnsAnswer *a) {
846 uint32_t ttl = UINT32_MAX;
847 DnsResourceRecord *rr;
848
849 /* Return the smallest TTL of all RRs in this answer */
850
851 DNS_ANSWER_FOREACH(rr, a) {
852 /* Don't consider OPT (where the TTL field is used for other purposes than an actual TTL) */
853
854 if (dns_type_is_pseudo(rr->key->type) ||
855 dns_class_is_pseudo(rr->key->class))
856 continue;
857
858 ttl = MIN(ttl, rr->ttl);
859 }
860
861 return ttl;
862 }