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
dns_answer_item_free(DnsAnswerItem * item)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
dns_answer_item_hash_func(const DnsAnswerItem * a,struct siphash * state)25 static void dns_answer_item_hash_func(const DnsAnswerItem *a, struct siphash *state) {
26 assert(a);
27 assert(state);
28
29 siphash24_compress(&a->ifindex, sizeof(a->ifindex), state);
30
31 dns_resource_record_hash_func(a->rr, state);
32 }
33
dns_answer_item_compare_func(const DnsAnswerItem * a,const DnsAnswerItem * b)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
dns_answer_reserve_internal(DnsAnswer * a,size_t n)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
dns_answer_new(size_t n)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
dns_answer_free(DnsAnswer * a)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
dns_answer_add_raw(DnsAnswer * a,DnsResourceRecord * rr,int ifindex,DnsAnswerFlags flags,DnsResourceRecord * rrsig)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
dns_answer_add_raw_all(DnsAnswer * a,DnsAnswer * source)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
dns_answer_add(DnsAnswer * a,DnsResourceRecord * rr,int ifindex,DnsAnswerFlags flags,DnsResourceRecord * rrsig)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 less
185 * match. We don't really care if they match precisely, but we do care whether one is 0 and
186 * the other is not. See RFC 2181, Section 5.2. */
187 if ((rr->ttl == 0) != (exist->rr->ttl == 0))
188 return -EINVAL;
189
190 /* Entry already exists, keep the entry with the higher TTL. */
191 if (rr->ttl > exist->rr->ttl) {
192 DNS_RR_REPLACE(exist->rr, dns_resource_record_ref(rr));
193
194 /* Update RRSIG and RR at the same time */
195 if (rrsig)
196 DNS_RR_REPLACE(exist->rrsig, dns_resource_record_ref(rrsig));
197 }
198
199 exist->flags |= flags;
200
201 if (rr->key->type == DNS_TYPE_RRSIG) {
202 /* If the rr is RRSIG, then move the rr to the end. */
203 assert_se(ordered_set_remove(a->items, exist) == exist);
204 assert_se(ordered_set_put(a->items, exist) == 1);
205 }
206 return 0;
207 }
208
209 return dns_answer_add_raw(a, rr, ifindex, flags, rrsig);
210 }
211
dns_answer_add_all(DnsAnswer * a,DnsAnswer * b)212 static int dns_answer_add_all(DnsAnswer *a, DnsAnswer *b) {
213 DnsAnswerItem *item;
214 int r;
215
216 DNS_ANSWER_FOREACH_ITEM(item, b) {
217 r = dns_answer_add(a, item->rr, item->ifindex, item->flags, item->rrsig);
218 if (r < 0)
219 return r;
220 }
221
222 return 0;
223 }
224
dns_answer_add_extend(DnsAnswer ** a,DnsResourceRecord * rr,int ifindex,DnsAnswerFlags flags,DnsResourceRecord * rrsig)225 int dns_answer_add_extend(
226 DnsAnswer **a,
227 DnsResourceRecord *rr,
228 int ifindex,
229 DnsAnswerFlags flags,
230 DnsResourceRecord *rrsig) {
231
232 int r;
233
234 assert(a);
235 assert(rr);
236
237 r = dns_answer_reserve_or_clone(a, 1);
238 if (r < 0)
239 return r;
240
241 return dns_answer_add(*a, rr, ifindex, flags, rrsig);
242 }
243
dns_answer_add_soa(DnsAnswer * a,const char * name,uint32_t ttl,int ifindex)244 int dns_answer_add_soa(DnsAnswer *a, const char *name, uint32_t ttl, int ifindex) {
245 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *soa = NULL;
246
247 soa = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_SOA, name);
248 if (!soa)
249 return -ENOMEM;
250
251 soa->ttl = ttl;
252
253 soa->soa.mname = strdup(name);
254 if (!soa->soa.mname)
255 return -ENOMEM;
256
257 soa->soa.rname = strjoin("root.", name);
258 if (!soa->soa.rname)
259 return -ENOMEM;
260
261 soa->soa.serial = 1;
262 soa->soa.refresh = 1;
263 soa->soa.retry = 1;
264 soa->soa.expire = 1;
265 soa->soa.minimum = ttl;
266
267 return dns_answer_add(a, soa, ifindex, DNS_ANSWER_AUTHENTICATED, NULL);
268 }
269
dns_answer_match_key(DnsAnswer * a,const DnsResourceKey * key,DnsAnswerFlags * ret_flags)270 int dns_answer_match_key(DnsAnswer *a, const DnsResourceKey *key, DnsAnswerFlags *ret_flags) {
271 DnsAnswerFlags flags = 0, i_flags;
272 DnsResourceRecord *i;
273 bool found = false;
274 int r;
275
276 assert(key);
277
278 DNS_ANSWER_FOREACH_FLAGS(i, i_flags, a) {
279 r = dns_resource_key_match_rr(key, i, NULL);
280 if (r < 0)
281 return r;
282 if (r == 0)
283 continue;
284
285 if (!ret_flags)
286 return 1;
287
288 if (found)
289 flags &= i_flags;
290 else {
291 flags = i_flags;
292 found = true;
293 }
294 }
295
296 if (ret_flags)
297 *ret_flags = flags;
298
299 return found;
300 }
301
dns_answer_contains_nsec_or_nsec3(DnsAnswer * a)302 bool dns_answer_contains_nsec_or_nsec3(DnsAnswer *a) {
303 DnsResourceRecord *i;
304
305 DNS_ANSWER_FOREACH(i, a)
306 if (IN_SET(i->key->type, DNS_TYPE_NSEC, DNS_TYPE_NSEC3))
307 return true;
308
309 return false;
310 }
311
dns_answer_contains_zone_nsec3(DnsAnswer * answer,const char * zone)312 int dns_answer_contains_zone_nsec3(DnsAnswer *answer, const char *zone) {
313 DnsResourceRecord *rr;
314 int r;
315
316 /* Checks whether the specified answer contains at least one NSEC3 RR in the specified zone */
317
318 DNS_ANSWER_FOREACH(rr, answer) {
319 const char *p;
320
321 if (rr->key->type != DNS_TYPE_NSEC3)
322 continue;
323
324 p = dns_resource_key_name(rr->key);
325 r = dns_name_parent(&p);
326 if (r < 0)
327 return r;
328 if (r == 0)
329 continue;
330
331 r = dns_name_equal(p, zone);
332 if (r != 0)
333 return r;
334 }
335
336 return false;
337 }
338
dns_answer_contains(DnsAnswer * answer,DnsResourceRecord * rr)339 bool dns_answer_contains(DnsAnswer *answer, DnsResourceRecord *rr) {
340 DnsResourceRecord *i;
341
342 DNS_ANSWER_FOREACH(i, answer)
343 if (dns_resource_record_equal(i, rr))
344 return true;
345
346 return false;
347 }
348
dns_answer_find_soa(DnsAnswer * a,const DnsResourceKey * key,DnsResourceRecord ** ret,DnsAnswerFlags * ret_flags)349 int dns_answer_find_soa(
350 DnsAnswer *a,
351 const DnsResourceKey *key,
352 DnsResourceRecord **ret,
353 DnsAnswerFlags *ret_flags) {
354
355 DnsResourceRecord *rr, *soa = NULL;
356 DnsAnswerFlags rr_flags, soa_flags = 0;
357 int r;
358
359 assert(key);
360
361 /* For a SOA record we can never find a matching SOA record */
362 if (key->type == DNS_TYPE_SOA)
363 goto not_found;
364
365 DNS_ANSWER_FOREACH_FLAGS(rr, rr_flags, a) {
366 r = dns_resource_key_match_soa(key, rr->key);
367 if (r < 0)
368 return r;
369 if (r > 0) {
370
371 if (soa) {
372 r = dns_name_endswith(dns_resource_key_name(rr->key), dns_resource_key_name(soa->key));
373 if (r < 0)
374 return r;
375 if (r > 0)
376 continue;
377 }
378
379 soa = rr;
380 soa_flags = rr_flags;
381 }
382 }
383
384 if (!soa)
385 goto not_found;
386
387 if (ret)
388 *ret = soa;
389 if (ret_flags)
390 *ret_flags = soa_flags;
391
392 return 1;
393
394 not_found:
395 if (ret)
396 *ret = NULL;
397 if (ret_flags)
398 *ret_flags = 0;
399
400 return 0;
401 }
402
dns_answer_find_cname_or_dname(DnsAnswer * a,const DnsResourceKey * key,DnsResourceRecord ** ret,DnsAnswerFlags * ret_flags)403 int dns_answer_find_cname_or_dname(
404 DnsAnswer *a,
405 const DnsResourceKey *key,
406 DnsResourceRecord **ret,
407 DnsAnswerFlags *ret_flags) {
408
409 DnsResourceRecord *rr;
410 DnsAnswerFlags rr_flags;
411 int r;
412
413 assert(key);
414
415 /* For a {C,D}NAME record we can never find a matching {C,D}NAME record */
416 if (!dns_type_may_redirect(key->type))
417 return 0;
418
419 DNS_ANSWER_FOREACH_FLAGS(rr, rr_flags, a) {
420 r = dns_resource_key_match_cname_or_dname(key, rr->key, NULL);
421 if (r < 0)
422 return r;
423 if (r > 0) {
424 if (ret)
425 *ret = rr;
426 if (ret_flags)
427 *ret_flags = rr_flags;
428 return 1;
429 }
430 }
431
432 if (ret)
433 *ret = NULL;
434 if (ret_flags)
435 *ret_flags = 0;
436
437 return 0;
438 }
439
dns_answer_merge(DnsAnswer * a,DnsAnswer * b,DnsAnswer ** ret)440 int dns_answer_merge(DnsAnswer *a, DnsAnswer *b, DnsAnswer **ret) {
441 _cleanup_(dns_answer_unrefp) DnsAnswer *k = NULL;
442 int r;
443
444 assert(ret);
445
446 if (a == b) {
447 *ret = dns_answer_ref(a);
448 return 0;
449 }
450
451 if (dns_answer_size(a) <= 0) {
452 *ret = dns_answer_ref(b);
453 return 0;
454 }
455
456 if (dns_answer_size(b) <= 0) {
457 *ret = dns_answer_ref(a);
458 return 0;
459 }
460
461 k = dns_answer_new(dns_answer_size(a) + dns_answer_size(b));
462 if (!k)
463 return -ENOMEM;
464
465 r = dns_answer_add_raw_all(k, a);
466 if (r < 0)
467 return r;
468
469 r = dns_answer_add_all(k, b);
470 if (r < 0)
471 return r;
472
473 *ret = TAKE_PTR(k);
474
475 return 0;
476 }
477
dns_answer_extend(DnsAnswer ** a,DnsAnswer * b)478 int dns_answer_extend(DnsAnswer **a, DnsAnswer *b) {
479 DnsAnswer *merged;
480 int r;
481
482 assert(a);
483
484 r = dns_answer_merge(*a, b, &merged);
485 if (r < 0)
486 return r;
487
488 DNS_ANSWER_REPLACE(*a, merged);
489 return 0;
490 }
491
dns_answer_remove_by_key(DnsAnswer ** a,const DnsResourceKey * key)492 int dns_answer_remove_by_key(DnsAnswer **a, const DnsResourceKey *key) {
493 DnsAnswerItem *item;
494 bool found = false;
495 int r;
496
497 assert(a);
498 assert(key);
499
500 /* Remove all entries matching the specified key from *a */
501
502 DNS_ANSWER_FOREACH_ITEM(item, *a) {
503 r = dns_resource_key_equal(item->rr->key, key);
504 if (r < 0)
505 return r;
506 if (r > 0) {
507 dns_answer_item_unref(ordered_set_remove((*a)->items, item));
508 found = true;
509 }
510 }
511
512 if (!found)
513 return 0;
514
515 if (dns_answer_isempty(*a))
516 *a = dns_answer_unref(*a); /* Return NULL for the empty answer */
517
518 return 1;
519 }
520
dns_answer_remove_by_rr(DnsAnswer ** a,DnsResourceRecord * rr)521 int dns_answer_remove_by_rr(DnsAnswer **a, DnsResourceRecord *rr) {
522 _unused_ _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr_ref = dns_resource_record_ref(rr);
523 DnsAnswerItem *item;
524 bool found = false;
525 int r;
526
527 assert(a);
528 assert(rr);
529
530 /* Remove all entries matching the specified RR from *a */
531
532 DNS_ANSWER_FOREACH_ITEM(item, *a) {
533 r = dns_resource_record_equal(item->rr, rr);
534 if (r < 0)
535 return r;
536 if (r > 0) {
537 dns_answer_item_unref(ordered_set_remove((*a)->items, item));
538 found = true;
539 }
540 }
541
542 if (!found)
543 return 0;
544
545 if (dns_answer_isempty(*a))
546 *a = dns_answer_unref(*a); /* Return NULL for the empty answer */
547
548 return 1;
549 }
550
dns_answer_remove_by_answer_keys(DnsAnswer ** a,DnsAnswer * b)551 int dns_answer_remove_by_answer_keys(DnsAnswer **a, DnsAnswer *b) {
552 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *prev = NULL;
553 DnsAnswerItem *item;
554 int r;
555
556 /* Removes all items from '*a' that have a matching key in 'b' */
557
558 DNS_ANSWER_FOREACH_ITEM(item, b) {
559
560 if (prev && dns_resource_key_equal(item->rr->key, prev)) /* Skip this one, we already looked at it */
561 continue;
562
563 r = dns_answer_remove_by_key(a, item->rr->key);
564 if (r < 0)
565 return r;
566 if (!*a)
567 return 0; /* a is already empty. */
568
569 /* Let's remember this entry's RR key, to optimize the loop a bit: if we have an RRset with
570 * more than one item then we don't need to remove the key multiple times */
571 DNS_RESOURCE_KEY_REPLACE(prev, dns_resource_key_ref(item->rr->key));
572 }
573
574 return 0;
575 }
576
dns_answer_copy_by_key(DnsAnswer ** a,DnsAnswer * source,const DnsResourceKey * key,DnsAnswerFlags or_flags,DnsResourceRecord * rrsig)577 int dns_answer_copy_by_key(
578 DnsAnswer **a,
579 DnsAnswer *source,
580 const DnsResourceKey *key,
581 DnsAnswerFlags or_flags,
582 DnsResourceRecord *rrsig) {
583
584 DnsAnswerItem *item;
585 int r;
586
587 assert(a);
588 assert(key);
589
590 /* Copy all RRs matching the specified key from source into *a */
591
592 DNS_ANSWER_FOREACH_ITEM(item, source) {
593
594 r = dns_resource_key_equal(item->rr->key, key);
595 if (r < 0)
596 return r;
597 if (r == 0)
598 continue;
599
600 r = dns_answer_add_extend(a, item->rr, item->ifindex, item->flags|or_flags, rrsig ?: item->rrsig);
601 if (r < 0)
602 return r;
603 }
604
605 return 0;
606 }
607
dns_answer_move_by_key(DnsAnswer ** to,DnsAnswer ** from,const DnsResourceKey * key,DnsAnswerFlags or_flags,DnsResourceRecord * rrsig)608 int dns_answer_move_by_key(
609 DnsAnswer **to,
610 DnsAnswer **from,
611 const DnsResourceKey *key,
612 DnsAnswerFlags or_flags,
613 DnsResourceRecord *rrsig) {
614
615 int r;
616
617 assert(to);
618 assert(from);
619 assert(key);
620
621 r = dns_answer_copy_by_key(to, *from, key, or_flags, rrsig);
622 if (r < 0)
623 return r;
624
625 return dns_answer_remove_by_key(from, key);
626 }
627
dns_answer_order_by_scope(DnsAnswer * a,bool prefer_link_local)628 void dns_answer_order_by_scope(DnsAnswer *a, bool prefer_link_local) {
629 _cleanup_free_ DnsAnswerItem **items = NULL;
630 DnsAnswerItem **p, *item;
631 size_t n;
632
633 n = dns_answer_size(a);
634 if (n <= 1)
635 return;
636
637 /* RFC 4795, Section 2.6 suggests we should order entries
638 * depending on whether the sender is a link-local address. */
639
640 p = items = new(DnsAnswerItem*, n);
641 if (!items)
642 return (void) log_oom();
643
644 /* Order preferred address records and other records to the beginning of the array */
645 DNS_ANSWER_FOREACH_ITEM(item, a)
646 if (dns_resource_record_is_link_local_address(item->rr) == prefer_link_local)
647 *p++ = dns_answer_item_ref(item);
648
649 /* Order address records that are not preferred to the end of the array */
650 DNS_ANSWER_FOREACH_ITEM(item, a)
651 if (dns_resource_record_is_link_local_address(item->rr) != prefer_link_local)
652 *p++ = dns_answer_item_ref(item);
653
654
655 assert((size_t) (p - items) == n);
656
657 ordered_set_clear(a->items);
658 for (size_t i = 0; i < n; i++)
659 assert_se(ordered_set_put(a->items, items[i]) >= 0);
660 }
661
dns_answer_reserve(DnsAnswer ** a,size_t n_free)662 int dns_answer_reserve(DnsAnswer **a, size_t n_free) {
663 assert(a);
664
665 if (n_free <= 0)
666 return 0;
667
668 if (!*a) {
669 DnsAnswer *n;
670
671 n = dns_answer_new(n_free);
672 if (!n)
673 return -ENOMEM;
674
675 *a = n;
676 return 0;
677 }
678
679 if ((*a)->n_ref > 1)
680 return -EBUSY;
681
682 return dns_answer_reserve_internal(*a, n_free);
683 }
684
dns_answer_reserve_or_clone(DnsAnswer ** a,size_t n_free)685 int dns_answer_reserve_or_clone(DnsAnswer **a, size_t n_free) {
686 _cleanup_(dns_answer_unrefp) DnsAnswer *n = NULL;
687 size_t ns;
688 int r;
689
690 assert(a);
691
692 r = dns_answer_reserve(a, n_free);
693 if (r != -EBUSY)
694 return r;
695
696 ns = dns_answer_size(*a);
697 assert(ns <= UINT16_MAX); /* Maximum number of RRs we can stick into a DNS packet section */
698
699 ns = saturate_add(ns, n_free, UINT16_MAX);
700
701 n = dns_answer_new(ns);
702 if (!n)
703 return -ENOMEM;
704
705 r = dns_answer_add_raw_all(n, *a);
706 if (r < 0)
707 return r;
708
709 DNS_ANSWER_REPLACE(*a, TAKE_PTR(n));
710 return 0;
711 }
712
713 /*
714 * This function is not used in the code base, but is useful when debugging. Do not delete.
715 */
dns_answer_dump(DnsAnswer * answer,FILE * f)716 void dns_answer_dump(DnsAnswer *answer, FILE *f) {
717 DnsAnswerItem *item;
718
719 if (!f)
720 f = stdout;
721
722 DNS_ANSWER_FOREACH_ITEM(item, answer) {
723 const char *t;
724
725 fputc('\t', f);
726
727 t = dns_resource_record_to_string(item->rr);
728 if (!t) {
729 log_oom();
730 continue;
731 }
732
733 fputs(t, f);
734 fputs("\t;", f);
735 fprintf(f, " ttl=%" PRIu32, item->rr->ttl);
736
737 if (item->ifindex != 0)
738 fprintf(f, " ifindex=%i", item->ifindex);
739 if (item->rrsig)
740 fputs(" rrsig", f);
741 if (item->flags & DNS_ANSWER_AUTHENTICATED)
742 fputs(" authenticated", f);
743 if (item->flags & DNS_ANSWER_CACHEABLE)
744 fputs(" cacheable", f);
745 if (item->flags & DNS_ANSWER_SHARED_OWNER)
746 fputs(" shared-owner", f);
747 if (item->flags & DNS_ANSWER_CACHE_FLUSH)
748 fputs(" cache-flush", f);
749 if (item->flags & DNS_ANSWER_GOODBYE)
750 fputs(" goodbye", f);
751 if (item->flags & DNS_ANSWER_SECTION_ANSWER)
752 fputs(" section-answer", f);
753 if (item->flags & DNS_ANSWER_SECTION_AUTHORITY)
754 fputs(" section-authority", f);
755 if (item->flags & DNS_ANSWER_SECTION_ADDITIONAL)
756 fputs(" section-additional", f);
757
758 fputc('\n', f);
759 }
760 }
761
dns_answer_has_dname_for_cname(DnsAnswer * a,DnsResourceRecord * cname)762 int dns_answer_has_dname_for_cname(DnsAnswer *a, DnsResourceRecord *cname) {
763 DnsResourceRecord *rr;
764 int r;
765
766 assert(cname);
767
768 /* Checks whether the answer contains a DNAME record that indicates that the specified CNAME record is
769 * synthesized from it */
770
771 if (cname->key->type != DNS_TYPE_CNAME)
772 return 0;
773
774 DNS_ANSWER_FOREACH(rr, a) {
775 _cleanup_free_ char *n = NULL;
776
777 if (rr->key->type != DNS_TYPE_DNAME)
778 continue;
779 if (rr->key->class != cname->key->class)
780 continue;
781
782 r = dns_name_change_suffix(cname->cname.name, rr->dname.name, dns_resource_key_name(rr->key), &n);
783 if (r < 0)
784 return r;
785 if (r == 0)
786 continue;
787
788 r = dns_name_equal(n, dns_resource_key_name(cname->key));
789 if (r < 0)
790 return r;
791 if (r > 0)
792 return 1;
793 }
794
795 return 0;
796 }
797
dns_answer_randomize(DnsAnswer * a)798 void dns_answer_randomize(DnsAnswer *a) {
799 _cleanup_free_ DnsAnswerItem **items = NULL;
800 DnsAnswerItem **p, *item;
801 size_t n;
802
803 /* Permutes the answer list randomly (Knuth shuffle) */
804
805 n = dns_answer_size(a);
806 if (n <= 1)
807 return;
808
809 p = items = new(DnsAnswerItem*, n);
810 if (!items)
811 return (void) log_oom();
812
813 DNS_ANSWER_FOREACH_ITEM(item, a)
814 *p++ = dns_answer_item_ref(item);
815
816 assert((size_t) (p - items) == n);
817
818 for (size_t i = 0; i < n; i++) {
819 size_t k;
820
821 k = random_u64_range(n);
822 if (k == i)
823 continue;
824
825 SWAP_TWO(items[i], items[k]);
826 }
827
828 ordered_set_clear(a->items);
829 for (size_t i = 0; i < n; i++)
830 assert_se(ordered_set_put(a->items, items[i]) >= 0);
831 }
832
dns_answer_min_ttl(DnsAnswer * a)833 uint32_t dns_answer_min_ttl(DnsAnswer *a) {
834 uint32_t ttl = UINT32_MAX;
835 DnsResourceRecord *rr;
836
837 /* Return the smallest TTL of all RRs in this answer */
838
839 DNS_ANSWER_FOREACH(rr, a) {
840 /* Don't consider OPT (where the TTL field is used for other purposes than an actual TTL) */
841
842 if (dns_type_is_pseudo(rr->key->type) ||
843 dns_class_is_pseudo(rr->key->class))
844 continue;
845
846 ttl = MIN(ttl, rr->ttl);
847 }
848
849 return ttl;
850 }
851