1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
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"
12 static DnsAnswerItem
*dns_answer_item_free(DnsAnswerItem
*item
) {
16 dns_resource_record_unref(item
->rr
);
17 dns_resource_record_unref(item
->rrsig
);
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
);
25 static void dns_answer_item_hash_func(const DnsAnswerItem
*a
, struct siphash
*state
) {
29 siphash24_compress_typesafe(a
->ifindex
, state
);
31 dns_resource_record_hash_func(a
->rr
, state
);
34 static int dns_answer_item_compare_func(const DnsAnswerItem
*a
, const DnsAnswerItem
*b
) {
40 r
= CMP(a
->ifindex
, b
->ifindex
);
44 return dns_resource_record_compare_func(a
->rr
, b
->rr
);
47 DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
48 dns_answer_item_hash_ops
,
50 dns_answer_item_hash_func
,
51 dns_answer_item_compare_func
,
52 dns_answer_item_unref
);
54 static int dns_answer_reserve_internal(DnsAnswer
*a
, size_t n
) {
60 m
= ordered_set_size(a
->items
);
61 assert(m
<= UINT16_MAX
); /* We can only place 64K RRs in an answer at max */
63 n
= saturate_add(m
, n
, UINT16_MAX
);
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);
70 DnsAnswer
*dns_answer_new(size_t n
) {
71 _cleanup_ordered_set_free_ OrderedSet
*s
= NULL
;
72 _cleanup_(dns_answer_unrefp
) DnsAnswer
*a
= NULL
;
77 s
= ordered_set_new(&dns_answer_item_hash_ops
);
81 a
= new(DnsAnswer
, 1);
90 if (dns_answer_reserve_internal(a
, n
) < 0)
96 static DnsAnswer
*dns_answer_free(DnsAnswer
*a
) {
99 ordered_set_free(a
->items
);
103 DEFINE_TRIVIAL_REF_UNREF_FUNC(DnsAnswer
, dns_answer
, dns_answer_free
);
105 static int dns_answer_add_raw(
107 DnsResourceRecord
*rr
,
109 DnsAnswerFlags flags
,
110 DnsResourceRecord
*rrsig
) {
112 _cleanup_(dns_answer_item_unrefp
) DnsAnswerItem
*item
= NULL
;
120 if (dns_answer_size(a
) >= UINT16_MAX
)
123 item
= new(DnsAnswerItem
, 1);
127 *item
= (DnsAnswerItem
) {
129 .rr
= dns_resource_record_ref(rr
),
132 .rrsig
= dns_resource_record_ref(rrsig
),
135 r
= ordered_set_put(a
->items
, item
);
143 static int dns_answer_add_raw_all(DnsAnswer
*a
, DnsAnswer
*source
) {
147 DNS_ANSWER_FOREACH_ITEM(item
, source
) {
148 r
= dns_answer_add_raw(
163 DnsResourceRecord
*rr
,
165 DnsAnswerFlags flags
,
166 DnsResourceRecord
*rrsig
) {
168 DnsAnswerItem tmp
, *exist
;
177 tmp
= (DnsAnswerItem
) {
182 exist
= ordered_set_get(a
->items
, &tmp
);
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
));
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
));
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
));
206 /* Update RRSIG and RR at the same time */
208 DNS_RR_REPLACE(exist
->rrsig
, dns_resource_record_ref(rrsig
));
211 exist
->flags
|= flags
;
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);
221 return dns_answer_add_raw(a
, rr
, ifindex
, flags
, rrsig
);
224 static int dns_answer_add_all(DnsAnswer
*a
, DnsAnswer
*b
) {
228 DNS_ANSWER_FOREACH_ITEM(item
, b
) {
229 r
= dns_answer_add(a
, item
->rr
, item
->ifindex
, item
->flags
, item
->rrsig
);
237 int dns_answer_add_extend(
239 DnsResourceRecord
*rr
,
241 DnsAnswerFlags flags
,
242 DnsResourceRecord
*rrsig
) {
249 r
= dns_answer_reserve_or_clone(a
, 1);
253 return dns_answer_add(*a
, rr
, ifindex
, flags
, rrsig
);
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
;
259 soa
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_SOA
, name
);
265 soa
->soa
.mname
= strdup(name
);
269 soa
->soa
.rname
= strjoin("root.", name
);
274 soa
->soa
.refresh
= 1;
277 soa
->soa
.minimum
= ttl
;
279 return dns_answer_add(a
, soa
, ifindex
, DNS_ANSWER_AUTHENTICATED
, NULL
);
282 int dns_answer_match_key(DnsAnswer
*a
, const DnsResourceKey
*key
, DnsAnswerFlags
*ret_flags
) {
283 DnsAnswerFlags flags
= 0, i_flags
;
284 DnsResourceRecord
*i
;
290 DNS_ANSWER_FOREACH_FLAGS(i
, i_flags
, a
) {
291 r
= dns_resource_key_match_rr(key
, i
, NULL
);
314 bool dns_answer_contains_nsec_or_nsec3(DnsAnswer
*a
) {
315 DnsResourceRecord
*i
;
317 DNS_ANSWER_FOREACH(i
, a
)
318 if (IN_SET(i
->key
->type
, DNS_TYPE_NSEC
, DNS_TYPE_NSEC3
))
324 int dns_answer_contains_zone_nsec3(DnsAnswer
*answer
, const char *zone
) {
325 DnsResourceRecord
*rr
;
328 /* Checks whether the specified answer contains at least one NSEC3 RR in the specified zone */
330 DNS_ANSWER_FOREACH(rr
, answer
) {
333 if (rr
->key
->type
!= DNS_TYPE_NSEC3
)
336 p
= dns_resource_key_name(rr
->key
);
337 r
= dns_name_parent(&p
);
343 r
= dns_name_equal(p
, zone
);
351 bool dns_answer_contains(DnsAnswer
*answer
, DnsResourceRecord
*rr
) {
352 DnsResourceRecord
*i
;
354 DNS_ANSWER_FOREACH(i
, answer
)
355 if (dns_resource_record_equal(i
, rr
))
361 int dns_answer_find_soa(
363 const DnsResourceKey
*key
,
364 DnsResourceRecord
**ret
,
365 DnsAnswerFlags
*ret_flags
) {
367 DnsResourceRecord
*rr
, *soa
= NULL
;
368 DnsAnswerFlags rr_flags
, soa_flags
= 0;
373 /* For a SOA record we can never find a matching SOA record */
374 if (key
->type
== DNS_TYPE_SOA
)
377 DNS_ANSWER_FOREACH_FLAGS(rr
, rr_flags
, a
) {
378 r
= dns_resource_key_match_soa(key
, rr
->key
);
384 r
= dns_name_endswith(dns_resource_key_name(rr
->key
), dns_resource_key_name(soa
->key
));
392 soa_flags
= rr_flags
;
402 *ret_flags
= soa_flags
;
415 int dns_answer_find_cname_or_dname(
417 const DnsResourceKey
*key
,
418 DnsResourceRecord
**ret
,
419 DnsAnswerFlags
*ret_flags
) {
421 DnsResourceRecord
*rr
;
422 DnsAnswerFlags rr_flags
;
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
))
431 DNS_ANSWER_FOREACH_FLAGS(rr
, rr_flags
, a
) {
432 r
= dns_resource_key_match_cname_or_dname(key
, rr
->key
, NULL
);
439 *ret_flags
= rr_flags
;
452 int dns_answer_merge(DnsAnswer
*a
, DnsAnswer
*b
, DnsAnswer
**ret
) {
453 _cleanup_(dns_answer_unrefp
) DnsAnswer
*k
= NULL
;
459 *ret
= dns_answer_ref(a
);
463 if (dns_answer_size(a
) <= 0) {
464 *ret
= dns_answer_ref(b
);
468 if (dns_answer_size(b
) <= 0) {
469 *ret
= dns_answer_ref(a
);
473 k
= dns_answer_new(dns_answer_size(a
) + dns_answer_size(b
));
477 r
= dns_answer_add_raw_all(k
, a
);
481 r
= dns_answer_add_all(k
, b
);
490 int dns_answer_extend(DnsAnswer
**a
, DnsAnswer
*b
) {
496 r
= dns_answer_merge(*a
, b
, &merged
);
500 DNS_ANSWER_REPLACE(*a
, merged
);
504 int dns_answer_remove_by_key(DnsAnswer
**a
, const DnsResourceKey
*key
) {
512 /* Remove all entries matching the specified key from *a */
514 DNS_ANSWER_FOREACH_ITEM(item
, *a
) {
515 r
= dns_resource_key_equal(item
->rr
->key
, key
);
519 dns_answer_item_unref(ordered_set_remove((*a
)->items
, item
));
527 if (dns_answer_isempty(*a
))
528 *a
= dns_answer_unref(*a
); /* Return NULL for the empty answer */
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
);
542 /* Remove all entries matching the specified RR from *a */
544 DNS_ANSWER_FOREACH_ITEM(item
, *a
) {
545 r
= dns_resource_record_equal(item
->rr
, rr
);
549 dns_answer_item_unref(ordered_set_remove((*a
)->items
, item
));
557 if (dns_answer_isempty(*a
))
558 *a
= dns_answer_unref(*a
); /* Return NULL for the empty answer */
563 int dns_answer_remove_by_answer_keys(DnsAnswer
**a
, DnsAnswer
*b
) {
564 _cleanup_(dns_resource_key_unrefp
) DnsResourceKey
*prev
= NULL
;
568 /* Removes all items from '*a' that have a matching key in 'b' */
570 DNS_ANSWER_FOREACH_ITEM(item
, b
) {
572 if (prev
&& dns_resource_key_equal(item
->rr
->key
, prev
)) /* Skip this one, we already looked at it */
575 r
= dns_answer_remove_by_key(a
, item
->rr
->key
);
579 return 0; /* a is already empty. */
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
));
589 int dns_answer_copy_by_key(
592 const DnsResourceKey
*key
,
593 DnsAnswerFlags or_flags
,
594 DnsResourceRecord
*rrsig
) {
602 /* Copy all RRs matching the specified key from source into *a */
604 DNS_ANSWER_FOREACH_ITEM(item
, source
) {
606 r
= dns_resource_key_equal(item
->rr
->key
, key
);
612 r
= dns_answer_add_extend(a
, item
->rr
, item
->ifindex
, item
->flags
|or_flags
, rrsig
?: item
->rrsig
);
620 int dns_answer_move_by_key(
623 const DnsResourceKey
*key
,
624 DnsAnswerFlags or_flags
,
625 DnsResourceRecord
*rrsig
) {
633 r
= dns_answer_copy_by_key(to
, *from
, key
, or_flags
, rrsig
);
637 return dns_answer_remove_by_key(from
, key
);
640 void dns_answer_order_by_scope(DnsAnswer
*a
, bool prefer_link_local
) {
641 _cleanup_free_ DnsAnswerItem
**items
= NULL
;
642 DnsAnswerItem
**p
, *item
;
645 n
= dns_answer_size(a
);
649 /* RFC 4795, Section 2.6 suggests we should order entries
650 * depending on whether the sender is a link-local address. */
652 p
= items
= new(DnsAnswerItem
*, n
);
654 return (void) log_oom();
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
);
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
);
667 assert((size_t) (p
- items
) == n
);
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);
674 int dns_answer_reserve(DnsAnswer
**a
, size_t n_free
) {
683 n
= dns_answer_new(n_free
);
694 return dns_answer_reserve_internal(*a
, n_free
);
697 int dns_answer_reserve_or_clone(DnsAnswer
**a
, size_t n_free
) {
698 _cleanup_(dns_answer_unrefp
) DnsAnswer
*n
= NULL
;
704 r
= dns_answer_reserve(a
, n_free
);
708 ns
= dns_answer_size(*a
);
709 assert(ns
<= UINT16_MAX
); /* Maximum number of RRs we can stick into a DNS packet section */
711 ns
= saturate_add(ns
, n_free
, UINT16_MAX
);
713 n
= dns_answer_new(ns
);
717 r
= dns_answer_add_raw_all(n
, *a
);
721 DNS_ANSWER_REPLACE(*a
, TAKE_PTR(n
));
726 * This function is not used in the code base, but is useful when debugging. Do not delete.
728 void dns_answer_dump(DnsAnswer
*answer
, FILE *f
) {
734 DNS_ANSWER_FOREACH_ITEM(item
, answer
) {
739 t
= dns_resource_record_to_string(item
->rr
);
747 fprintf(f
, " ttl=%" PRIu32
, item
->rr
->ttl
);
749 if (item
->ifindex
!= 0)
750 fprintf(f
, " ifindex=%i", item
->ifindex
);
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
);
774 int dns_answer_has_dname_for_cname(DnsAnswer
*a
, DnsResourceRecord
*cname
) {
775 DnsResourceRecord
*rr
;
780 /* Checks whether the answer contains a DNAME record that indicates that the specified CNAME record is
781 * synthesized from it */
783 if (cname
->key
->type
!= DNS_TYPE_CNAME
)
786 DNS_ANSWER_FOREACH(rr
, a
) {
787 _cleanup_free_
char *n
= NULL
;
789 if (rr
->key
->type
!= DNS_TYPE_DNAME
)
791 if (rr
->key
->class != cname
->key
->class)
794 r
= dns_name_change_suffix(cname
->cname
.name
, rr
->dname
.name
, dns_resource_key_name(rr
->key
), &n
);
800 r
= dns_name_equal(n
, dns_resource_key_name(cname
->key
));
810 void dns_answer_randomize(DnsAnswer
*a
) {
811 _cleanup_free_ DnsAnswerItem
**items
= NULL
;
812 DnsAnswerItem
**p
, *item
;
815 /* Permutes the answer list randomly (Knuth shuffle) */
817 n
= dns_answer_size(a
);
821 p
= items
= new(DnsAnswerItem
*, n
);
823 return (void) log_oom();
825 DNS_ANSWER_FOREACH_ITEM(item
, a
)
826 *p
++ = dns_answer_item_ref(item
);
828 assert((size_t) (p
- items
) == n
);
830 for (size_t i
= 0; i
< n
; i
++) {
833 k
= random_u64_range(n
);
837 SWAP_TWO(items
[i
], items
[k
]);
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);
845 uint32_t dns_answer_min_ttl(DnsAnswer
*a
) {
846 uint32_t ttl
= UINT32_MAX
;
847 DnsResourceRecord
*rr
;
849 /* Return the smallest TTL of all RRs in this answer */
851 DNS_ANSWER_FOREACH(rr
, a
) {
852 /* Don't consider OPT (where the TTL field is used for other purposes than an actual TTL) */
854 if (dns_type_is_pseudo(rr
->key
->type
) ||
855 dns_class_is_pseudo(rr
->key
->class))
858 ttl
= MIN(ttl
, rr
->ttl
);