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