1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
5 #include "alloc-util.h"
6 #include "dns-domain.h"
8 #include "resolved-dns-question.h"
9 #include "resolved-dns-rr.h"
10 #include "socket-util.h"
11 #include "string-util.h"
13 DnsQuestion
*dns_question_new(size_t n
) {
16 if (n
> UINT16_MAX
) /* We can only place 64K key in an question section at max */
19 q
= malloc0(offsetof(DnsQuestion
, items
) + sizeof(DnsQuestionItem
) * n
);
29 static DnsQuestion
*dns_question_free(DnsQuestion
*q
) {
34 DNS_QUESTION_FOREACH(key
, q
)
35 dns_resource_key_unref(key
);
40 DEFINE_TRIVIAL_REF_UNREF_FUNC(DnsQuestion
, dns_question
, dns_question_free
);
42 int dns_question_add_raw(DnsQuestion
*q
, DnsResourceKey
*key
, DnsQuestionFlags flags
) {
43 /* Insert without checking for duplicates. */
48 if (q
->n_keys
>= q
->n_allocated
)
51 q
->items
[q
->n_keys
++] = (DnsQuestionItem
) {
52 .key
= dns_resource_key_ref(key
),
58 static int dns_question_add_raw_all(DnsQuestion
*a
, DnsQuestion
*b
) {
59 DnsQuestionItem
*item
;
62 DNS_QUESTION_FOREACH_ITEM(item
, b
) {
63 r
= dns_question_add_raw(a
, item
->key
, item
->flags
);
71 int dns_question_add(DnsQuestion
*q
, DnsResourceKey
*key
, DnsQuestionFlags flags
) {
72 DnsQuestionItem
*item
;
80 DNS_QUESTION_FOREACH_ITEM(item
, q
) {
81 r
= dns_resource_key_equal(item
->key
, key
);
84 if (r
> 0 && item
->flags
== flags
)
88 return dns_question_add_raw(q
, key
, flags
);
91 static int dns_question_add_all(DnsQuestion
*a
, DnsQuestion
*b
) {
92 DnsQuestionItem
*item
;
95 DNS_QUESTION_FOREACH_ITEM(item
, b
) {
96 r
= dns_question_add(a
, item
->key
, item
->flags
);
104 int dns_question_matches_rr(DnsQuestion
*q
, DnsResourceRecord
*rr
, const char *search_domain
) {
113 DNS_QUESTION_FOREACH(key
, q
) {
114 r
= dns_resource_key_match_rr(key
, rr
, search_domain
);
122 int dns_question_matches_cname_or_dname(DnsQuestion
*q
, DnsResourceRecord
*rr
, const char *search_domain
) {
131 if (!IN_SET(rr
->key
->type
, DNS_TYPE_CNAME
, DNS_TYPE_DNAME
))
134 DNS_QUESTION_FOREACH(key
, q
) {
135 /* For a {C,D}NAME record we can never find a matching {C,D}NAME record */
136 if (!dns_type_may_redirect(key
->type
))
139 r
= dns_resource_key_match_cname_or_dname(key
, rr
->key
, search_domain
);
147 int dns_question_is_valid_for_query(DnsQuestion
*q
) {
158 if (q
->n_keys
> 65535)
161 name
= dns_resource_key_name(q
->items
[0].key
);
165 /* Check that all keys in this question bear the same name */
166 for (i
= 0; i
< q
->n_keys
; i
++) {
167 assert(q
->items
[i
].key
);
170 r
= dns_name_equal(dns_resource_key_name(q
->items
[i
].key
), name
);
175 if (!dns_type_is_valid_query(q
->items
[i
].key
->type
))
182 int dns_question_contains_key(DnsQuestion
*q
, const DnsResourceKey
*k
) {
191 for (j
= 0; j
< q
->n_keys
; j
++) {
192 r
= dns_resource_key_equal(q
->items
[j
].key
, k
);
200 static int dns_question_contains_item(DnsQuestion
*q
, const DnsQuestionItem
*i
) {
201 DnsQuestionItem
*item
;
206 DNS_QUESTION_FOREACH_ITEM(item
, q
) {
207 if (item
->flags
!= i
->flags
)
209 r
= dns_resource_key_equal(item
->key
, i
->key
);
217 int dns_question_is_equal(DnsQuestion
*a
, DnsQuestion
*b
) {
218 DnsQuestionItem
*item
;
225 return !b
|| b
->n_keys
== 0;
227 return a
->n_keys
== 0;
229 /* Checks if all items in a are also contained b, and vice versa */
231 DNS_QUESTION_FOREACH_ITEM(item
, a
) {
232 r
= dns_question_contains_item(b
, item
);
236 DNS_QUESTION_FOREACH_ITEM(item
, b
) {
237 r
= dns_question_contains_item(a
, item
);
245 int dns_question_cname_redirect(DnsQuestion
*q
, const DnsResourceRecord
*cname
, DnsQuestion
**ret
) {
246 _cleanup_(dns_question_unrefp
) DnsQuestion
*n
= NULL
;
253 assert(IN_SET(cname
->key
->type
, DNS_TYPE_CNAME
, DNS_TYPE_DNAME
));
255 if (dns_question_size(q
) <= 0) {
260 DNS_QUESTION_FOREACH(key
, q
) {
261 _cleanup_free_
char *destination
= NULL
;
264 if (cname
->key
->type
== DNS_TYPE_CNAME
)
265 d
= cname
->cname
.name
;
267 r
= dns_name_change_suffix(dns_resource_key_name(key
), dns_resource_key_name(cname
->key
), cname
->dname
.name
, &destination
);
276 r
= dns_name_equal(dns_resource_key_name(key
), d
);
286 /* Fully the same, indicate we didn't do a thing */
292 n
= dns_question_new(q
->n_keys
);
296 /* Create a new question, and patch in the new name */
297 DNS_QUESTION_FOREACH(key
, q
) {
298 _cleanup_(dns_resource_key_unrefp
) DnsResourceKey
*k
= NULL
;
300 k
= dns_resource_key_new_redirect(key
, cname
);
304 r
= dns_question_add(n
, k
, 0);
314 const char* dns_question_first_name(DnsQuestion
*q
) {
322 return dns_resource_key_name(q
->items
[0].key
);
325 int dns_question_new_address(DnsQuestion
**ret
, int family
, const char *name
, bool convert_idna
) {
326 _cleanup_(dns_question_unrefp
) DnsQuestion
*q
= NULL
;
327 _cleanup_free_
char *buf
= NULL
;
333 if (!IN_SET(family
, AF_INET
, AF_INET6
, AF_UNSPEC
))
334 return -EAFNOSUPPORT
;
336 /* If IPv6 is off and the request has an unspecified lookup family, restrict it automatically to
338 if (family
== AF_UNSPEC
&& !socket_ipv6_is_enabled())
342 r
= dns_name_apply_idna(name
, &buf
);
345 if (r
> 0 && !streq(name
, buf
))
348 /* We did not manage to create convert the idna name, or it's
349 * the same as the original name. We assume the caller already
350 * created an unconverted question, so let's not repeat work
355 q
= dns_question_new(family
== AF_UNSPEC
? 2 : 1);
359 if (family
!= AF_INET6
) {
360 _cleanup_(dns_resource_key_unrefp
) DnsResourceKey
*key
= NULL
;
362 key
= dns_resource_key_new(DNS_CLASS_IN
, DNS_TYPE_A
, name
);
366 r
= dns_question_add(q
, key
, 0);
371 if (family
!= AF_INET
) {
372 _cleanup_(dns_resource_key_unrefp
) DnsResourceKey
*key
= NULL
;
374 key
= dns_resource_key_new(DNS_CLASS_IN
, DNS_TYPE_AAAA
, name
);
378 r
= dns_question_add(q
, key
, 0);
388 int dns_question_new_reverse(DnsQuestion
**ret
, int family
, const union in_addr_union
*a
) {
389 _cleanup_(dns_resource_key_unrefp
) DnsResourceKey
*key
= NULL
;
390 _cleanup_(dns_question_unrefp
) DnsQuestion
*q
= NULL
;
391 _cleanup_free_
char *reverse
= NULL
;
397 if (!IN_SET(family
, AF_INET
, AF_INET6
, AF_UNSPEC
))
398 return -EAFNOSUPPORT
;
400 r
= dns_name_reverse(family
, a
, &reverse
);
404 q
= dns_question_new(1);
408 key
= dns_resource_key_new_consume(DNS_CLASS_IN
, DNS_TYPE_PTR
, reverse
);
414 r
= dns_question_add(q
, key
, 0);
423 int dns_question_new_service(
431 _cleanup_(dns_resource_key_unrefp
) DnsResourceKey
*key
= NULL
;
432 _cleanup_(dns_question_unrefp
) DnsQuestion
*q
= NULL
;
433 _cleanup_free_
char *buf
= NULL
, *joined
= NULL
;
439 /* We support three modes of invocation:
441 * 1. Only a domain is specified, in which case we assume a properly encoded SRV RR name, including service
442 * type and possibly a service name. If specified in this way we assume it's already IDNA converted if
445 * 2. Both service type and a domain specified, in which case a normal SRV RR is assumed, without a DNS-SD
446 * style prefix. In this case we'll IDNA convert the domain, if that's requested.
448 * 3. All three of service name, type and domain are specified, in which case a DNS-SD service is put
449 * together. The service name is never IDNA converted, and the domain is if requested.
451 * It's not supported to specify a service name without a type, or no domain name.
459 r
= dns_name_apply_idna(domain
, &buf
);
466 r
= dns_service_join(service
, type
, domain
, &joined
);
478 q
= dns_question_new(1 + with_txt
);
482 key
= dns_resource_key_new(DNS_CLASS_IN
, DNS_TYPE_SRV
, name
);
486 r
= dns_question_add(q
, key
, 0);
491 dns_resource_key_unref(key
);
492 key
= dns_resource_key_new(DNS_CLASS_IN
, DNS_TYPE_TXT
, name
);
496 r
= dns_question_add(q
, key
, 0);
507 * This function is not used in the code base, but is useful when debugging. Do not delete.
509 void dns_question_dump(DnsQuestion
*question
, FILE *f
) {
515 DNS_QUESTION_FOREACH(k
, question
) {
516 char buf
[DNS_RESOURCE_KEY_STRING_MAX
];
519 fputs(dns_resource_key_to_string(k
, buf
, sizeof(buf
)), f
);
524 int dns_question_merge(DnsQuestion
*a
, DnsQuestion
*b
, DnsQuestion
**ret
) {
525 _cleanup_(dns_question_unrefp
) DnsQuestion
*k
= NULL
;
530 if (a
== b
|| dns_question_size(b
) <= 0) {
531 *ret
= dns_question_ref(a
);
535 if (dns_question_size(a
) <= 0) {
536 *ret
= dns_question_ref(b
);
540 k
= dns_question_new(dns_question_size(a
) + dns_question_size(b
));
544 r
= dns_question_add_raw_all(k
, a
);
548 r
= dns_question_add_all(k
, b
);
556 bool dns_question_contains_key_type(DnsQuestion
*q
, uint16_t type
) {
558 DNS_QUESTION_FOREACH(t
, q
)