1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
5 #include "alloc-util.h"
6 #include "dns-domain.h"
8 #include "random-util.h"
9 #include "resolved-dns-answer.h"
10 #include "resolved-dns-rr.h"
11 #include "siphash24.h"
12 #include "string-util.h"
14 static DnsAnswerItem
*dns_answer_item_free(DnsAnswerItem
*item
) {
18 dns_resource_record_unref(item
->rr
);
19 dns_resource_record_unref(item
->rrsig
);
24 DEFINE_PRIVATE_TRIVIAL_REF_UNREF_FUNC(DnsAnswerItem
, dns_answer_item
, dns_answer_item_free
);
25 DEFINE_TRIVIAL_CLEANUP_FUNC(DnsAnswerItem
*, dns_answer_item_unref
);
27 static void dns_answer_item_hash_func(const DnsAnswerItem
*a
, struct siphash
*state
) {
31 siphash24_compress_typesafe(a
->ifindex
, state
);
33 dns_resource_record_hash_func(a
->rr
, state
);
36 static int dns_answer_item_compare_func(const DnsAnswerItem
*a
, const DnsAnswerItem
*b
) {
42 r
= CMP(a
->ifindex
, b
->ifindex
);
46 return dns_resource_record_compare_func(a
->rr
, b
->rr
);
49 DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
50 dns_answer_item_hash_ops
,
52 dns_answer_item_hash_func
,
53 dns_answer_item_compare_func
,
54 dns_answer_item_unref
);
56 static int dns_answer_reserve_internal(DnsAnswer
*a
, size_t n
) {
62 m
= ordered_set_size(a
->items
);
63 assert(m
<= UINT16_MAX
); /* We can only place 64K RRs in an answer at max */
65 n
= saturate_add(m
, n
, UINT16_MAX
);
67 /* Higher multipliers give slightly higher efficiency through hash collisions, but the gains
68 * quickly drop off after 2. */
69 return ordered_set_reserve(a
->items
, n
* 2);
72 DnsAnswer
*dns_answer_new(size_t n
) {
73 _cleanup_ordered_set_free_ OrderedSet
*s
= NULL
;
74 _cleanup_(dns_answer_unrefp
) DnsAnswer
*a
= NULL
;
79 s
= ordered_set_new(&dns_answer_item_hash_ops
);
83 a
= new(DnsAnswer
, 1);
92 if (dns_answer_reserve_internal(a
, n
) < 0)
98 static DnsAnswer
*dns_answer_free(DnsAnswer
*a
) {
101 ordered_set_free(a
->items
);
105 DEFINE_TRIVIAL_REF_UNREF_FUNC(DnsAnswer
, dns_answer
, dns_answer_free
);
107 static int dns_answer_add_raw(
109 DnsResourceRecord
*rr
,
111 DnsAnswerFlags flags
,
112 DnsResourceRecord
*rrsig
) {
114 _cleanup_(dns_answer_item_unrefp
) DnsAnswerItem
*item
= NULL
;
122 if (dns_answer_size(a
) >= UINT16_MAX
)
125 item
= new(DnsAnswerItem
, 1);
129 *item
= (DnsAnswerItem
) {
131 .rr
= dns_resource_record_ref(rr
),
134 .rrsig
= dns_resource_record_ref(rrsig
),
137 r
= ordered_set_put(a
->items
, item
);
145 static int dns_answer_add_raw_all(DnsAnswer
*a
, DnsAnswer
*source
) {
149 DNS_ANSWER_FOREACH_ITEM(item
, source
) {
150 r
= dns_answer_add_raw(
165 DnsResourceRecord
*rr
,
167 DnsAnswerFlags flags
,
168 DnsResourceRecord
*rrsig
) {
170 DnsAnswerItem tmp
, *exist
;
179 tmp
= (DnsAnswerItem
) {
184 exist
= ordered_set_get(a
->items
, &tmp
);
186 /* There's already an RR of the same RRset in place! Let's see if the TTLs more or
187 * less match. RFC 2181, Section 5.2 suggests clients should reject RRsets
188 * containing RRs with differing TTLs. We are more tolerant of this situation except
189 * if one RR has a zero TTL and the other a nonzero TTL. In mDNS, zero TTLs are
190 * special, so we must error in that case. */
191 if ((rr
->ttl
== 0) != (exist
->rr
->ttl
== 0)) {
192 if ((exist
->flags
| flags
) & DNS_ANSWER_REFUSE_TTL_NO_MATCH
)
193 return log_debug_errno(
194 SYNTHETIC_ERRNO(EINVAL
),
195 "Refusing to merge RRs with zero TTL and non-zero TTL: %s vs. %s",
196 dns_resource_record_to_string(rr
),
197 dns_resource_record_to_string(exist
->rr
));
199 log_debug("Merging RRs with zero TTL and non-zero TTL (not RFC 2181/5.2 compliant): %s vs. %s",
200 dns_resource_record_to_string(rr
),
201 dns_resource_record_to_string(exist
->rr
));
204 /* Entry already exists, keep the entry with the higher TTL. */
205 if (rr
->ttl
> exist
->rr
->ttl
) {
206 DNS_RR_REPLACE(exist
->rr
, dns_resource_record_ref(rr
));
208 /* Update RRSIG and RR at the same time */
210 DNS_RR_REPLACE(exist
->rrsig
, dns_resource_record_ref(rrsig
));
213 exist
->flags
|= flags
;
215 if (rr
->key
->type
== DNS_TYPE_RRSIG
) {
216 /* If the rr is RRSIG, then move the rr to the end. */
217 assert_se(ordered_set_remove(a
->items
, exist
) == exist
);
218 assert_se(ordered_set_put(a
->items
, exist
) == 1);
223 return dns_answer_add_raw(a
, rr
, ifindex
, flags
, rrsig
);
226 static int dns_answer_add_all(DnsAnswer
*a
, DnsAnswer
*b
) {
230 DNS_ANSWER_FOREACH_ITEM(item
, b
) {
231 r
= dns_answer_add(a
, item
->rr
, item
->ifindex
, item
->flags
, item
->rrsig
);
239 int dns_answer_add_extend(
241 DnsResourceRecord
*rr
,
243 DnsAnswerFlags flags
,
244 DnsResourceRecord
*rrsig
) {
251 r
= dns_answer_reserve_or_clone(a
, 1);
255 return dns_answer_add(*a
, rr
, ifindex
, flags
, rrsig
);
258 int dns_answer_add_soa(DnsAnswer
*a
, const char *name
, uint32_t ttl
, int ifindex
) {
259 _cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*soa
= NULL
;
261 soa
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_SOA
, name
);
267 soa
->soa
.mname
= strdup(name
);
271 soa
->soa
.rname
= strjoin("root.", name
);
276 soa
->soa
.refresh
= 1;
279 soa
->soa
.minimum
= ttl
;
281 return dns_answer_add(a
, soa
, ifindex
, DNS_ANSWER_AUTHENTICATED
, NULL
);
284 int dns_answer_match_key(DnsAnswer
*a
, const DnsResourceKey
*key
, DnsAnswerFlags
*ret_flags
) {
285 DnsAnswerFlags flags
= 0, i_flags
;
286 DnsResourceRecord
*i
;
292 DNS_ANSWER_FOREACH_FLAGS(i
, i_flags
, a
) {
293 r
= dns_resource_key_match_rr(key
, i
, NULL
);
316 bool dns_answer_contains_nsec_or_nsec3(DnsAnswer
*a
) {
317 DnsResourceRecord
*i
;
319 DNS_ANSWER_FOREACH(i
, a
)
320 if (IN_SET(i
->key
->type
, DNS_TYPE_NSEC
, DNS_TYPE_NSEC3
))
326 int dns_answer_contains_zone_nsec3(DnsAnswer
*answer
, const char *zone
) {
327 DnsResourceRecord
*rr
;
330 /* Checks whether the specified answer contains at least one NSEC3 RR in the specified zone */
332 DNS_ANSWER_FOREACH(rr
, answer
) {
335 if (rr
->key
->type
!= DNS_TYPE_NSEC3
)
338 p
= dns_resource_key_name(rr
->key
);
339 r
= dns_name_parent(&p
);
345 r
= dns_name_equal(p
, zone
);
353 bool dns_answer_contains(DnsAnswer
*answer
, DnsResourceRecord
*rr
) {
354 DnsResourceRecord
*i
;
356 DNS_ANSWER_FOREACH(i
, answer
)
357 if (dns_resource_record_equal(i
, rr
))
363 int dns_answer_find_soa(
365 const DnsResourceKey
*key
,
366 DnsResourceRecord
**ret
,
367 DnsAnswerFlags
*ret_flags
) {
369 DnsResourceRecord
*rr
, *soa
= NULL
;
370 DnsAnswerFlags rr_flags
, soa_flags
= 0;
375 /* For a SOA record we can never find a matching SOA record */
376 if (key
->type
== DNS_TYPE_SOA
)
379 DNS_ANSWER_FOREACH_FLAGS(rr
, rr_flags
, a
) {
380 r
= dns_resource_key_match_soa(key
, rr
->key
);
386 r
= dns_name_endswith(dns_resource_key_name(rr
->key
), dns_resource_key_name(soa
->key
));
394 soa_flags
= rr_flags
;
404 *ret_flags
= soa_flags
;
417 int dns_answer_find_cname_or_dname(
419 const DnsResourceKey
*key
,
420 DnsResourceRecord
**ret
,
421 DnsAnswerFlags
*ret_flags
) {
423 DnsResourceRecord
*rr
;
424 DnsAnswerFlags rr_flags
;
429 /* For a {C,D}NAME record we can never find a matching {C,D}NAME record */
430 if (!dns_type_may_redirect(key
->type
))
433 DNS_ANSWER_FOREACH_FLAGS(rr
, rr_flags
, a
) {
434 r
= dns_resource_key_match_cname_or_dname(key
, rr
->key
, NULL
);
441 *ret_flags
= rr_flags
;
454 int dns_answer_merge(DnsAnswer
*a
, DnsAnswer
*b
, DnsAnswer
**ret
) {
455 _cleanup_(dns_answer_unrefp
) DnsAnswer
*k
= NULL
;
461 *ret
= dns_answer_ref(a
);
465 if (dns_answer_size(a
) <= 0) {
466 *ret
= dns_answer_ref(b
);
470 if (dns_answer_size(b
) <= 0) {
471 *ret
= dns_answer_ref(a
);
475 k
= dns_answer_new(dns_answer_size(a
) + dns_answer_size(b
));
479 r
= dns_answer_add_raw_all(k
, a
);
483 r
= dns_answer_add_all(k
, b
);
492 int dns_answer_extend(DnsAnswer
**a
, DnsAnswer
*b
) {
498 r
= dns_answer_merge(*a
, b
, &merged
);
502 DNS_ANSWER_REPLACE(*a
, merged
);
506 int dns_answer_remove_by_key(DnsAnswer
**a
, const DnsResourceKey
*key
) {
514 /* Remove all entries matching the specified key from *a */
516 DNS_ANSWER_FOREACH_ITEM(item
, *a
) {
517 r
= dns_resource_key_equal(item
->rr
->key
, key
);
521 dns_answer_item_unref(ordered_set_remove((*a
)->items
, item
));
529 if (dns_answer_isempty(*a
))
530 *a
= dns_answer_unref(*a
); /* Return NULL for the empty answer */
535 int dns_answer_remove_by_rr(DnsAnswer
**a
, DnsResourceRecord
*rr
) {
536 _unused_
_cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*rr_ref
= dns_resource_record_ref(rr
);
544 /* Remove all entries matching the specified RR from *a */
546 DNS_ANSWER_FOREACH_ITEM(item
, *a
) {
547 r
= dns_resource_record_equal(item
->rr
, rr
);
551 dns_answer_item_unref(ordered_set_remove((*a
)->items
, item
));
559 if (dns_answer_isempty(*a
))
560 *a
= dns_answer_unref(*a
); /* Return NULL for the empty answer */
565 int dns_answer_remove_by_answer_keys(DnsAnswer
**a
, DnsAnswer
*b
) {
566 _cleanup_(dns_resource_key_unrefp
) DnsResourceKey
*prev
= NULL
;
570 /* Removes all items from '*a' that have a matching key in 'b' */
572 DNS_ANSWER_FOREACH_ITEM(item
, b
) {
574 if (prev
&& dns_resource_key_equal(item
->rr
->key
, prev
)) /* Skip this one, we already looked at it */
577 r
= dns_answer_remove_by_key(a
, item
->rr
->key
);
581 return 0; /* a is already empty. */
583 /* Let's remember this entry's RR key, to optimize the loop a bit: if we have an RRset with
584 * more than one item then we don't need to remove the key multiple times */
585 DNS_RESOURCE_KEY_REPLACE(prev
, dns_resource_key_ref(item
->rr
->key
));
591 int dns_answer_copy_by_key(
594 const DnsResourceKey
*key
,
595 DnsAnswerFlags or_flags
,
596 DnsResourceRecord
*rrsig
) {
604 /* Copy all RRs matching the specified key from source into *a */
606 DNS_ANSWER_FOREACH_ITEM(item
, source
) {
608 r
= dns_resource_key_equal(item
->rr
->key
, key
);
614 r
= dns_answer_add_extend(a
, item
->rr
, item
->ifindex
, item
->flags
|or_flags
, rrsig
?: item
->rrsig
);
622 int dns_answer_move_by_key(
625 const DnsResourceKey
*key
,
626 DnsAnswerFlags or_flags
,
627 DnsResourceRecord
*rrsig
) {
635 r
= dns_answer_copy_by_key(to
, *from
, key
, or_flags
, rrsig
);
639 return dns_answer_remove_by_key(from
, key
);
642 void dns_answer_order_by_scope(DnsAnswer
*a
, bool prefer_link_local
) {
643 _cleanup_free_ DnsAnswerItem
**items
= NULL
;
644 DnsAnswerItem
**p
, *item
;
647 n
= dns_answer_size(a
);
651 /* RFC 4795, Section 2.6 suggests we should order entries
652 * depending on whether the sender is a link-local address. */
654 p
= items
= new(DnsAnswerItem
*, n
);
656 return (void) log_oom();
658 /* Order preferred address records and other records to the beginning of the array */
659 DNS_ANSWER_FOREACH_ITEM(item
, a
)
660 if (dns_resource_record_is_link_local_address(item
->rr
) == prefer_link_local
)
661 *p
++ = dns_answer_item_ref(item
);
663 /* Order address records that are not preferred to the end of the array */
664 DNS_ANSWER_FOREACH_ITEM(item
, a
)
665 if (dns_resource_record_is_link_local_address(item
->rr
) != prefer_link_local
)
666 *p
++ = dns_answer_item_ref(item
);
668 assert((size_t) (p
- items
) == n
);
670 ordered_set_clear(a
->items
);
671 for (size_t i
= 0; i
< n
; i
++)
672 assert_se(ordered_set_put(a
->items
, items
[i
]) >= 0);
675 int dns_answer_reserve(DnsAnswer
**a
, size_t n_free
) {
684 n
= dns_answer_new(n_free
);
695 return dns_answer_reserve_internal(*a
, n_free
);
698 int dns_answer_reserve_or_clone(DnsAnswer
**a
, size_t n_free
) {
699 _cleanup_(dns_answer_unrefp
) DnsAnswer
*n
= NULL
;
705 r
= dns_answer_reserve(a
, n_free
);
709 ns
= dns_answer_size(*a
);
710 assert(ns
<= UINT16_MAX
); /* Maximum number of RRs we can stick into a DNS packet section */
712 ns
= saturate_add(ns
, n_free
, UINT16_MAX
);
714 n
= dns_answer_new(ns
);
718 r
= dns_answer_add_raw_all(n
, *a
);
722 DNS_ANSWER_REPLACE(*a
, TAKE_PTR(n
));
727 * This function is not used in the code base, but is useful when debugging. Do not delete.
729 void dns_answer_dump(DnsAnswer
*answer
, FILE *f
) {
735 DNS_ANSWER_FOREACH_ITEM(item
, answer
) {
740 t
= dns_resource_record_to_string(item
->rr
);
748 fprintf(f
, " ttl=%" PRIu32
, item
->rr
->ttl
);
750 if (item
->ifindex
!= 0)
751 fprintf(f
, " ifindex=%i", item
->ifindex
);
754 if (item
->flags
& DNS_ANSWER_AUTHENTICATED
)
755 fputs(" authenticated", f
);
756 if (item
->flags
& DNS_ANSWER_CACHEABLE
)
757 fputs(" cacheable", f
);
758 if (item
->flags
& DNS_ANSWER_SHARED_OWNER
)
759 fputs(" shared-owner", f
);
760 if (item
->flags
& DNS_ANSWER_CACHE_FLUSH
)
761 fputs(" cache-flush", f
);
762 if (item
->flags
& DNS_ANSWER_GOODBYE
)
763 fputs(" goodbye", f
);
764 if (item
->flags
& DNS_ANSWER_SECTION_ANSWER
)
765 fputs(" section-answer", f
);
766 if (item
->flags
& DNS_ANSWER_SECTION_AUTHORITY
)
767 fputs(" section-authority", f
);
768 if (item
->flags
& DNS_ANSWER_SECTION_ADDITIONAL
)
769 fputs(" section-additional", f
);
775 int dns_answer_has_dname_for_cname(DnsAnswer
*a
, DnsResourceRecord
*cname
) {
776 DnsResourceRecord
*rr
;
781 /* Checks whether the answer contains a DNAME record that indicates that the specified CNAME record is
782 * synthesized from it */
784 if (cname
->key
->type
!= DNS_TYPE_CNAME
)
787 DNS_ANSWER_FOREACH(rr
, a
) {
788 _cleanup_free_
char *n
= NULL
;
790 if (rr
->key
->type
!= DNS_TYPE_DNAME
)
792 if (rr
->key
->class != cname
->key
->class)
795 r
= dns_name_change_suffix(cname
->cname
.name
, rr
->dname
.name
, dns_resource_key_name(rr
->key
), &n
);
801 r
= dns_name_equal(n
, dns_resource_key_name(cname
->key
));
811 void dns_answer_randomize(DnsAnswer
*a
) {
812 _cleanup_free_ DnsAnswerItem
**items
= NULL
;
813 DnsAnswerItem
**p
, *item
;
816 /* Permutes the answer list randomly (Knuth shuffle) */
818 n
= dns_answer_size(a
);
822 p
= items
= new(DnsAnswerItem
*, n
);
824 return (void) log_oom();
826 DNS_ANSWER_FOREACH_ITEM(item
, a
)
827 *p
++ = dns_answer_item_ref(item
);
829 assert((size_t) (p
- items
) == n
);
831 for (size_t i
= 0; i
< n
; i
++) {
834 k
= random_u64_range(n
);
838 SWAP_TWO(items
[i
], items
[k
]);
841 ordered_set_clear(a
->items
);
842 for (size_t i
= 0; i
< n
; i
++)
843 assert_se(ordered_set_put(a
->items
, items
[i
]) >= 0);
846 uint32_t dns_answer_min_ttl(DnsAnswer
*a
) {
847 uint32_t ttl
= UINT32_MAX
;
848 DnsResourceRecord
*rr
;
850 /* Return the smallest TTL of all RRs in this answer */
852 DNS_ANSWER_FOREACH(rr
, a
) {
853 /* Don't consider OPT (where the TTL field is used for other purposes than an actual TTL) */
855 if (dns_type_is_pseudo(rr
->key
->type
) ||
856 dns_class_is_pseudo(rr
->key
->class))
859 ttl
= MIN(ttl
, rr
->ttl
);