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 void dns_answer_item_hash_func(const DnsAnswerItem
*a
, struct siphash
*state
) {
16 siphash24_compress(&a
->ifindex
, sizeof(a
->ifindex
), state
);
18 dns_resource_record_hash_func(a
->rr
, state
);
21 static int dns_answer_item_compare_func(const DnsAnswerItem
*a
, const DnsAnswerItem
*b
) {
27 r
= CMP(a
->ifindex
, b
->ifindex
);
31 return dns_resource_record_compare_func(a
->rr
, b
->rr
);
34 DEFINE_PRIVATE_HASH_OPS(dns_answer_item_hash_ops
, DnsAnswerItem
, dns_answer_item_hash_func
, dns_answer_item_compare_func
);
36 DnsAnswer
*dns_answer_new(size_t n
) {
37 _cleanup_set_free_ Set
*s
= NULL
;
40 if (n
> UINT16_MAX
) /* We can only place 64K RRs in an answer at max */
43 s
= set_new(&dns_answer_item_hash_ops
);
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)
52 a
= malloc0(offsetof(DnsAnswer
, items
) + sizeof(DnsAnswerItem
) * n
);
58 a
->set_items
= TAKE_PTR(s
);
62 static void dns_answer_flush(DnsAnswer
*a
) {
68 a
->set_items
= set_free(a
->set_items
);
70 DNS_ANSWER_FOREACH_ITEM(item
, a
) {
71 dns_resource_record_unref(item
->rr
);
72 dns_resource_record_unref(item
->rrsig
);
78 static DnsAnswer
*dns_answer_free(DnsAnswer
*a
) {
85 DEFINE_TRIVIAL_REF_UNREF_FUNC(DnsAnswer
, dns_answer
, dns_answer_free
);
87 static int dns_answer_add_raw(
89 DnsResourceRecord
*rr
,
92 DnsResourceRecord
*rrsig
) {
101 if (a
->n_rrs
>= a
->n_allocated
)
104 a
->items
[a
->n_rrs
] = (DnsAnswerItem
) {
108 .rrsig
= dns_resource_record_ref(rrsig
),
111 r
= set_put(a
->set_items
, &a
->items
[a
->n_rrs
]);
117 dns_resource_record_ref(rr
);
123 static int dns_answer_add_raw_all(DnsAnswer
*a
, DnsAnswer
*source
) {
127 DNS_ANSWER_FOREACH_ITEM(item
, source
) {
128 r
= dns_answer_add_raw(
143 DnsResourceRecord
*rr
,
145 DnsAnswerFlags flags
,
146 DnsResourceRecord
*rrsig
) {
148 DnsAnswerItem tmp
, *exist
;
157 tmp
= (DnsAnswerItem
) {
162 exist
= set_get(a
->set_items
, &tmp
);
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))
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
);
175 /* Update RRSIG and RR at the same time */
177 dns_resource_record_ref(rrsig
);
178 dns_resource_record_unref(exist
->rrsig
);
179 exist
->rrsig
= rrsig
;
183 exist
->flags
|= flags
;
187 return dns_answer_add_raw(a
, rr
, ifindex
, flags
, rrsig
);
190 static int dns_answer_add_all(DnsAnswer
*a
, DnsAnswer
*b
) {
194 DNS_ANSWER_FOREACH_ITEM(item
, b
) {
195 r
= dns_answer_add(a
, item
->rr
, item
->ifindex
, item
->flags
, item
->rrsig
);
203 int dns_answer_add_extend(
205 DnsResourceRecord
*rr
,
207 DnsAnswerFlags flags
,
208 DnsResourceRecord
*rrsig
) {
215 r
= dns_answer_reserve_or_clone(a
, 1);
219 return dns_answer_add(*a
, rr
, ifindex
, flags
, rrsig
);
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
;
225 soa
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_SOA
, name
);
231 soa
->soa
.mname
= strdup(name
);
235 soa
->soa
.rname
= strjoin("root.", name
);
240 soa
->soa
.refresh
= 1;
243 soa
->soa
.minimum
= ttl
;
245 return dns_answer_add(a
, soa
, ifindex
, DNS_ANSWER_AUTHENTICATED
, NULL
);
248 int dns_answer_match_key(DnsAnswer
*a
, const DnsResourceKey
*key
, DnsAnswerFlags
*ret_flags
) {
249 DnsAnswerFlags flags
= 0, i_flags
;
250 DnsResourceRecord
*i
;
256 DNS_ANSWER_FOREACH_FLAGS(i
, i_flags
, a
) {
257 r
= dns_resource_key_match_rr(key
, i
, NULL
);
280 int dns_answer_contains_nsec_or_nsec3(DnsAnswer
*a
) {
281 DnsResourceRecord
*i
;
283 DNS_ANSWER_FOREACH(i
, a
)
284 if (IN_SET(i
->key
->type
, DNS_TYPE_NSEC
, DNS_TYPE_NSEC3
))
290 int dns_answer_contains_zone_nsec3(DnsAnswer
*answer
, const char *zone
) {
291 DnsResourceRecord
*rr
;
294 /* Checks whether the specified answer contains at least one NSEC3 RR in the specified zone */
296 DNS_ANSWER_FOREACH(rr
, answer
) {
299 if (rr
->key
->type
!= DNS_TYPE_NSEC3
)
302 p
= dns_resource_key_name(rr
->key
);
303 r
= dns_name_parent(&p
);
309 r
= dns_name_equal(p
, zone
);
317 int dns_answer_contains(DnsAnswer
*answer
, DnsResourceRecord
*rr
) {
318 DnsResourceRecord
*i
;
320 DNS_ANSWER_FOREACH(i
, answer
)
321 if (dns_resource_record_equal(i
, rr
))
327 int dns_answer_find_soa(
329 const DnsResourceKey
*key
,
330 DnsResourceRecord
**ret
,
331 DnsAnswerFlags
*ret_flags
) {
333 DnsResourceRecord
*rr
, *soa
= NULL
;
334 DnsAnswerFlags rr_flags
, soa_flags
= 0;
339 /* For a SOA record we can never find a matching SOA record */
340 if (key
->type
== DNS_TYPE_SOA
)
343 DNS_ANSWER_FOREACH_FLAGS(rr
, rr_flags
, a
) {
344 r
= dns_resource_key_match_soa(key
, rr
->key
);
350 r
= dns_name_endswith(dns_resource_key_name(rr
->key
), dns_resource_key_name(soa
->key
));
358 soa_flags
= rr_flags
;
368 *ret_flags
= soa_flags
;
381 int dns_answer_find_cname_or_dname(
383 const DnsResourceKey
*key
,
384 DnsResourceRecord
**ret
,
385 DnsAnswerFlags
*ret_flags
) {
387 DnsResourceRecord
*rr
;
388 DnsAnswerFlags rr_flags
;
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
))
397 DNS_ANSWER_FOREACH_FLAGS(rr
, rr_flags
, a
) {
398 r
= dns_resource_key_match_cname_or_dname(key
, rr
->key
, NULL
);
405 *ret_flags
= rr_flags
;
418 int dns_answer_merge(DnsAnswer
*a
, DnsAnswer
*b
, DnsAnswer
**ret
) {
419 _cleanup_(dns_answer_unrefp
) DnsAnswer
*k
= NULL
;
425 *ret
= dns_answer_ref(a
);
429 if (dns_answer_size(a
) <= 0) {
430 *ret
= dns_answer_ref(b
);
434 if (dns_answer_size(b
) <= 0) {
435 *ret
= dns_answer_ref(a
);
439 k
= dns_answer_new(a
->n_rrs
+ b
->n_rrs
);
443 r
= dns_answer_add_raw_all(k
, a
);
447 r
= dns_answer_add_all(k
, b
);
456 int dns_answer_extend(DnsAnswer
**a
, DnsAnswer
*b
) {
462 r
= dns_answer_merge(*a
, b
, &merged
);
466 dns_answer_unref(*a
);
472 int dns_answer_remove_by_key(DnsAnswer
**a
, const DnsResourceKey
*key
) {
473 bool found
= false, other
= false;
474 DnsResourceRecord
*rr
;
481 /* Remove all entries matching the specified key from *a */
483 DNS_ANSWER_FOREACH(rr
, *a
) {
484 r
= dns_resource_key_equal(rr
->key
, key
);
500 *a
= dns_answer_unref(*a
); /* Return NULL for the empty answer */
504 if ((*a
)->n_ref
> 1) {
505 _cleanup_(dns_answer_unrefp
) DnsAnswer
*copy
= NULL
;
508 copy
= dns_answer_new((*a
)->n_rrs
);
512 DNS_ANSWER_FOREACH_ITEM(item
, *a
) {
513 r
= dns_resource_key_equal(item
->rr
->key
, key
);
519 r
= dns_answer_add_raw(copy
, item
->rr
, item
->ifindex
, item
->flags
, item
->rrsig
);
524 dns_answer_unref(*a
);
530 /* Only a single reference, edit in-place */
534 if (i
>= (*a
)->n_rrs
)
537 r
= dns_resource_key_equal((*a
)->items
[i
].rr
->key
, key
);
541 /* Kill this entry */
543 dns_resource_record_unref((*a
)->items
[i
].rr
);
544 dns_resource_record_unref((*a
)->items
[i
].rrsig
);
546 memmove((*a
)->items
+ i
, (*a
)->items
+ i
+ 1, sizeof(DnsAnswerItem
) * ((*a
)->n_rrs
- i
- 1));
551 /* Keep this entry */
558 int dns_answer_remove_by_rr(DnsAnswer
**a
, DnsResourceRecord
*rm
) {
559 bool found
= false, other
= false;
560 DnsResourceRecord
*rr
;
567 /* Remove all entries matching the specified RR from *a */
569 DNS_ANSWER_FOREACH(rr
, *a
) {
570 r
= dns_resource_record_equal(rr
, rm
);
586 *a
= dns_answer_unref(*a
); /* Return NULL for the empty answer */
590 if ((*a
)->n_ref
> 1) {
591 _cleanup_(dns_answer_unrefp
) DnsAnswer
*copy
= NULL
;
594 copy
= dns_answer_new((*a
)->n_rrs
);
598 DNS_ANSWER_FOREACH_ITEM(item
, *a
) {
599 r
= dns_resource_record_equal(item
->rr
, rm
);
605 r
= dns_answer_add_raw(copy
, item
->rr
, item
->ifindex
, item
->flags
, item
->rrsig
);
610 dns_answer_unref(*a
);
616 /* Only a single reference, edit in-place */
620 if (i
>= (*a
)->n_rrs
)
623 r
= dns_resource_record_equal((*a
)->items
[i
].rr
, rm
);
627 /* Kill this entry */
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));
636 /* Keep this entry */
643 int dns_answer_copy_by_key(
646 const DnsResourceKey
*key
,
647 DnsAnswerFlags or_flags
,
648 DnsResourceRecord
*rrsig
) {
656 /* Copy all RRs matching the specified key from source into *a */
658 DNS_ANSWER_FOREACH_ITEM(item
, source
) {
660 r
= dns_resource_key_equal(item
->rr
->key
, key
);
666 /* Make space for at least one entry */
667 r
= dns_answer_reserve_or_clone(a
, 1);
671 r
= dns_answer_add(*a
, item
->rr
, item
->ifindex
, item
->flags
|or_flags
, item
->rrsig
);
679 int dns_answer_move_by_key(
682 const DnsResourceKey
*key
,
683 DnsAnswerFlags or_flags
,
684 DnsResourceRecord
*rrsig
) {
691 r
= dns_answer_copy_by_key(to
, *from
, key
, or_flags
, rrsig
);
695 return dns_answer_remove_by_key(from
, key
);
698 void dns_answer_order_by_scope(DnsAnswer
*a
, bool prefer_link_local
) {
699 DnsAnswerItem
*items
;
700 size_t i
, start
, end
;
711 /* RFC 4795, Section 2.6 suggests we should order entries
712 * depending on whether the sender is a link-local address. */
714 items
= newa(DnsAnswerItem
, a
->n_rrs
);
715 for (i
= 0; i
< a
->n_rrs
; i
++) {
716 if (dns_resource_record_is_link_local_address(a
->items
[i
].rr
) != prefer_link_local
)
717 /* Order address records that are not preferred to the end of the array */
718 items
[end
--] = a
->items
[i
];
720 /* Order all other records to the beginning of the array */
721 items
[start
++] = a
->items
[i
];
724 assert(start
== end
+1);
725 memcpy(a
->items
, items
, sizeof(DnsAnswerItem
) * a
->n_rrs
);
728 int dns_answer_reserve(DnsAnswer
**a
, size_t n_free
) {
744 assert(ns
<= UINT16_MAX
); /* Maximum number of RRs we can stick into a DNS packet section */
746 if (n_free
> UINT16_MAX
- ns
) /* overflow check */
751 if ((*a
)->n_allocated
>= ns
)
754 /* Allocate more than we need, but not more than UINT16_MAX */
755 if (ns
<= UINT16_MAX
/2)
760 /* This must be done before realloc() below. Otherwise, the original DnsAnswer object
762 r
= set_reserve((*a
)->set_items
, ns
);
766 n
= realloc(*a
, offsetof(DnsAnswer
, items
) + sizeof(DnsAnswerItem
) * ns
);
772 /* Previously all items are stored in the set, and the enough memory area is allocated
773 * in the above. So set_put() in the below cannot fail. */
774 set_clear(n
->set_items
);
775 for (size_t i
= 0; i
< n
->n_rrs
; i
++)
776 assert_se(set_put(n
->set_items
, &n
->items
[i
]) > 0);
778 n
= dns_answer_new(n_free
);
787 int dns_answer_reserve_or_clone(DnsAnswer
**a
, size_t n_free
) {
792 /* Tries to extend the DnsAnswer object. And if that's not possible, since we are not the sole owner,
793 * then allocate a new, appropriately sized one. Either way, after this call the object will only
794 * have a single reference, and has room for at least the specified number of RRs. */
796 if (*a
&& (*a
)->n_ref
> 1) {
797 _cleanup_(dns_answer_unrefp
) DnsAnswer
*n
= NULL
;
801 assert(ns
<= UINT16_MAX
); /* Maximum number of RRs we can stick into a DNS packet section */
803 if (n_free
> UINT16_MAX
- ns
) /* overflow check */
805 else if (n_free
> 0) { /* Increase size and double the result, just in case — except if the
806 * increase is specified as 0, in which case we just allocate the
807 * exact amount as before, under the assumption this is just a request
808 * to copy the answer. */
811 if (ns
<= UINT16_MAX
/2) /* overflow check */
817 n
= dns_answer_new(ns
);
821 r
= dns_answer_add_raw_all(n
, *a
);
825 dns_answer_unref(*a
);
826 assert_se(*a
= TAKE_PTR(n
));
827 } else if (n_free
> 0) {
828 r
= dns_answer_reserve(a
, n_free
);
837 * This function is not used in the code base, but is useful when debugging. Do not delete.
839 void dns_answer_dump(DnsAnswer
*answer
, FILE *f
) {
845 DNS_ANSWER_FOREACH_ITEM(item
, answer
) {
850 t
= dns_resource_record_to_string(item
->rr
);
858 if (item
->ifindex
!= 0 || item
->rrsig
|| item
->flags
!= 0)
861 if (item
->ifindex
!= 0)
862 fprintf(f
, " ifindex=%i", item
->ifindex
);
865 if (item
->flags
& DNS_ANSWER_AUTHENTICATED
)
866 fputs(" authenticated", f
);
867 if (item
->flags
& DNS_ANSWER_CACHEABLE
)
868 fputs(" cacheable", f
);
869 if (item
->flags
& DNS_ANSWER_SHARED_OWNER
)
870 fputs(" shared-owner", f
);
871 if (item
->flags
& DNS_ANSWER_CACHE_FLUSH
)
872 fputs(" cache-flush", f
);
873 if (item
->flags
& DNS_ANSWER_GOODBYE
)
874 fputs(" goodbye", f
);
875 if (item
->flags
& DNS_ANSWER_SECTION_ANSWER
)
876 fputs(" section-answer", f
);
877 if (item
->flags
& DNS_ANSWER_SECTION_AUTHORITY
)
878 fputs(" section-authority", f
);
879 if (item
->flags
& DNS_ANSWER_SECTION_ADDITIONAL
)
880 fputs(" section-additional", f
);
886 int dns_answer_has_dname_for_cname(DnsAnswer
*a
, DnsResourceRecord
*cname
) {
887 DnsResourceRecord
*rr
;
892 /* Checks whether the answer contains a DNAME record that indicates that the specified CNAME record is
893 * synthesized from it */
895 if (cname
->key
->type
!= DNS_TYPE_CNAME
)
898 DNS_ANSWER_FOREACH(rr
, a
) {
899 _cleanup_free_
char *n
= NULL
;
901 if (rr
->key
->type
!= DNS_TYPE_DNAME
)
903 if (rr
->key
->class != cname
->key
->class)
906 r
= dns_name_change_suffix(cname
->cname
.name
, rr
->dname
.name
, dns_resource_key_name(rr
->key
), &n
);
912 r
= dns_name_equal(n
, dns_resource_key_name(cname
->key
));
922 void dns_answer_randomize(DnsAnswer
*a
) {
925 /* Permutes the answer list randomly (Knuth shuffle) */
927 n
= dns_answer_size(a
);
931 for (size_t i
= 0; i
< n
; i
++) {
934 k
= random_u64_range(n
);
938 SWAP_TWO(a
->items
[i
], a
->items
[k
]);