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