]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/resolve/resolved-dns-question.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 #include "alloc-util.h"
4 #include "dns-domain.h"
6 #include "resolved-dns-question.h"
8 DnsQuestion
*dns_question_new(size_t n
) {
11 if (n
> UINT16_MAX
) /* We can only place 64K key in an question section at max */
14 q
= malloc0(offsetof(DnsQuestion
, keys
) + sizeof(DnsResourceKey
*) * n
);
24 static DnsQuestion
*dns_question_free(DnsQuestion
*q
) {
29 for (i
= 0; i
< q
->n_keys
; i
++)
30 dns_resource_key_unref(q
->keys
[i
]);
34 DEFINE_TRIVIAL_REF_UNREF_FUNC(DnsQuestion
, dns_question
, dns_question_free
);
36 int dns_question_add_raw(DnsQuestion
*q
, DnsResourceKey
*key
) {
37 /* Insert without checking for duplicates. */
42 if (q
->n_keys
>= q
->n_allocated
)
45 q
->keys
[q
->n_keys
++] = dns_resource_key_ref(key
);
49 int dns_question_add(DnsQuestion
*q
, DnsResourceKey
*key
) {
57 for (size_t i
= 0; i
< q
->n_keys
; i
++) {
58 r
= dns_resource_key_equal(q
->keys
[i
], key
);
65 return dns_question_add_raw(q
, key
);
68 int dns_question_matches_rr(DnsQuestion
*q
, DnsResourceRecord
*rr
, const char *search_domain
) {
77 for (i
= 0; i
< q
->n_keys
; i
++) {
78 r
= dns_resource_key_match_rr(q
->keys
[i
], rr
, search_domain
);
86 int dns_question_matches_cname_or_dname(DnsQuestion
*q
, DnsResourceRecord
*rr
, const char *search_domain
) {
95 if (!IN_SET(rr
->key
->type
, DNS_TYPE_CNAME
, DNS_TYPE_DNAME
))
98 for (i
= 0; i
< q
->n_keys
; i
++) {
99 /* For a {C,D}NAME record we can never find a matching {C,D}NAME record */
100 if (!dns_type_may_redirect(q
->keys
[i
]->type
))
103 r
= dns_resource_key_match_cname_or_dname(q
->keys
[i
], rr
->key
, search_domain
);
111 int dns_question_is_valid_for_query(DnsQuestion
*q
) {
122 if (q
->n_keys
> 65535)
125 name
= dns_resource_key_name(q
->keys
[0]);
129 /* Check that all keys in this question bear the same name */
130 for (i
= 0; i
< q
->n_keys
; i
++) {
134 r
= dns_name_equal(dns_resource_key_name(q
->keys
[i
]), name
);
139 if (!dns_type_is_valid_query(q
->keys
[i
]->type
))
146 int dns_question_contains(DnsQuestion
*a
, const DnsResourceKey
*k
) {
155 for (j
= 0; j
< a
->n_keys
; j
++) {
156 r
= dns_resource_key_equal(a
->keys
[j
], k
);
164 int dns_question_is_equal(DnsQuestion
*a
, DnsQuestion
*b
) {
172 return !b
|| b
->n_keys
== 0;
174 return a
->n_keys
== 0;
176 /* Checks if all keys in a are also contained b, and vice versa */
178 for (j
= 0; j
< a
->n_keys
; j
++) {
179 r
= dns_question_contains(b
, a
->keys
[j
]);
184 for (j
= 0; j
< b
->n_keys
; j
++) {
185 r
= dns_question_contains(a
, b
->keys
[j
]);
193 int dns_question_cname_redirect(DnsQuestion
*q
, const DnsResourceRecord
*cname
, DnsQuestion
**ret
) {
194 _cleanup_(dns_question_unrefp
) DnsQuestion
*n
= NULL
;
201 assert(IN_SET(cname
->key
->type
, DNS_TYPE_CNAME
, DNS_TYPE_DNAME
));
203 if (dns_question_size(q
) <= 0) {
208 DNS_QUESTION_FOREACH(key
, q
) {
209 _cleanup_free_
char *destination
= NULL
;
212 if (cname
->key
->type
== DNS_TYPE_CNAME
)
213 d
= cname
->cname
.name
;
215 r
= dns_name_change_suffix(dns_resource_key_name(key
), dns_resource_key_name(cname
->key
), cname
->dname
.name
, &destination
);
224 r
= dns_name_equal(dns_resource_key_name(key
), d
);
234 /* Fully the same, indicate we didn't do a thing */
240 n
= dns_question_new(q
->n_keys
);
244 /* Create a new question, and patch in the new name */
245 DNS_QUESTION_FOREACH(key
, q
) {
246 _cleanup_(dns_resource_key_unrefp
) DnsResourceKey
*k
= NULL
;
248 k
= dns_resource_key_new_redirect(key
, cname
);
252 r
= dns_question_add(n
, k
);
262 const char *dns_question_first_name(DnsQuestion
*q
) {
270 return dns_resource_key_name(q
->keys
[0]);
273 int dns_question_new_address(DnsQuestion
**ret
, int family
, const char *name
, bool convert_idna
) {
274 _cleanup_(dns_question_unrefp
) DnsQuestion
*q
= NULL
;
275 _cleanup_free_
char *buf
= NULL
;
281 if (!IN_SET(family
, AF_INET
, AF_INET6
, AF_UNSPEC
))
282 return -EAFNOSUPPORT
;
285 r
= dns_name_apply_idna(name
, &buf
);
288 if (r
> 0 && !streq(name
, buf
))
291 /* We did not manage to create convert the idna name, or it's
292 * the same as the original name. We assume the caller already
293 * created an unconverted question, so let's not repeat work
298 q
= dns_question_new(family
== AF_UNSPEC
? 2 : 1);
302 if (family
!= AF_INET6
) {
303 _cleanup_(dns_resource_key_unrefp
) DnsResourceKey
*key
= NULL
;
305 key
= dns_resource_key_new(DNS_CLASS_IN
, DNS_TYPE_A
, name
);
309 r
= dns_question_add(q
, key
);
314 if (family
!= AF_INET
) {
315 _cleanup_(dns_resource_key_unrefp
) DnsResourceKey
*key
= NULL
;
317 key
= dns_resource_key_new(DNS_CLASS_IN
, DNS_TYPE_AAAA
, name
);
321 r
= dns_question_add(q
, key
);
331 int dns_question_new_reverse(DnsQuestion
**ret
, int family
, const union in_addr_union
*a
) {
332 _cleanup_(dns_resource_key_unrefp
) DnsResourceKey
*key
= NULL
;
333 _cleanup_(dns_question_unrefp
) DnsQuestion
*q
= NULL
;
334 _cleanup_free_
char *reverse
= NULL
;
340 if (!IN_SET(family
, AF_INET
, AF_INET6
, AF_UNSPEC
))
341 return -EAFNOSUPPORT
;
343 r
= dns_name_reverse(family
, a
, &reverse
);
347 q
= dns_question_new(1);
351 key
= dns_resource_key_new_consume(DNS_CLASS_IN
, DNS_TYPE_PTR
, reverse
);
357 r
= dns_question_add(q
, key
);
366 int dns_question_new_service(
374 _cleanup_(dns_resource_key_unrefp
) DnsResourceKey
*key
= NULL
;
375 _cleanup_(dns_question_unrefp
) DnsQuestion
*q
= NULL
;
376 _cleanup_free_
char *buf
= NULL
, *joined
= NULL
;
382 /* We support three modes of invocation:
384 * 1. Only a domain is specified, in which case we assume a properly encoded SRV RR name, including service
385 * type and possibly a service name. If specified in this way we assume it's already IDNA converted if
388 * 2. Both service type and a domain specified, in which case a normal SRV RR is assumed, without a DNS-SD
389 * style prefix. In this case we'll IDNA convert the domain, if that's requested.
391 * 3. All three of service name, type and domain are specified, in which case a DNS-SD service is put
392 * together. The service name is never IDNA converted, and the domain is if requested.
394 * It's not supported to specify a service name without a type, or no domain name.
402 r
= dns_name_apply_idna(domain
, &buf
);
409 r
= dns_service_join(service
, type
, domain
, &joined
);
421 q
= dns_question_new(1 + with_txt
);
425 key
= dns_resource_key_new(DNS_CLASS_IN
, DNS_TYPE_SRV
, name
);
429 r
= dns_question_add(q
, key
);
434 dns_resource_key_unref(key
);
435 key
= dns_resource_key_new(DNS_CLASS_IN
, DNS_TYPE_TXT
, name
);
439 r
= dns_question_add(q
, key
);