]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/resolve/resolved-dns-question.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 #include "alloc-util.h"
4 #include "dns-domain.h"
6 #include "resolved-dns-question.h"
8 DnsQuestion
*dns_question_new(size_t n
) {
13 q
= malloc0(offsetof(DnsQuestion
, keys
) + sizeof(DnsResourceKey
*) * n
);
23 static DnsQuestion
*dns_question_free(DnsQuestion
*q
) {
28 for (i
= 0; i
< q
->n_keys
; i
++)
29 dns_resource_key_unref(q
->keys
[i
]);
33 DEFINE_TRIVIAL_REF_UNREF_FUNC(DnsQuestion
, dns_question
, dns_question_free
);
35 int dns_question_add_raw(DnsQuestion
*q
, DnsResourceKey
*key
) {
36 /* Insert without checking for duplicates. */
41 if (q
->n_keys
>= q
->n_allocated
)
44 q
->keys
[q
->n_keys
++] = dns_resource_key_ref(key
);
48 int dns_question_add(DnsQuestion
*q
, DnsResourceKey
*key
) {
56 for (size_t i
= 0; i
< q
->n_keys
; i
++) {
57 r
= dns_resource_key_equal(q
->keys
[i
], key
);
64 return dns_question_add_raw(q
, key
);
67 int dns_question_matches_rr(DnsQuestion
*q
, DnsResourceRecord
*rr
, const char *search_domain
) {
76 for (i
= 0; i
< q
->n_keys
; i
++) {
77 r
= dns_resource_key_match_rr(q
->keys
[i
], rr
, search_domain
);
85 int dns_question_matches_cname_or_dname(DnsQuestion
*q
, DnsResourceRecord
*rr
, const char *search_domain
) {
94 if (!IN_SET(rr
->key
->type
, DNS_TYPE_CNAME
, DNS_TYPE_DNAME
))
97 for (i
= 0; i
< q
->n_keys
; i
++) {
98 /* For a {C,D}NAME record we can never find a matching {C,D}NAME record */
99 if (!dns_type_may_redirect(q
->keys
[i
]->type
))
102 r
= dns_resource_key_match_cname_or_dname(q
->keys
[i
], rr
->key
, search_domain
);
110 int dns_question_is_valid_for_query(DnsQuestion
*q
) {
121 if (q
->n_keys
> 65535)
124 name
= dns_resource_key_name(q
->keys
[0]);
128 /* Check that all keys in this question bear the same name */
129 for (i
= 0; i
< q
->n_keys
; i
++) {
133 r
= dns_name_equal(dns_resource_key_name(q
->keys
[i
]), name
);
138 if (!dns_type_is_valid_query(q
->keys
[i
]->type
))
145 int dns_question_contains(DnsQuestion
*a
, const DnsResourceKey
*k
) {
154 for (j
= 0; j
< a
->n_keys
; j
++) {
155 r
= dns_resource_key_equal(a
->keys
[j
], k
);
163 int dns_question_is_equal(DnsQuestion
*a
, DnsQuestion
*b
) {
171 return !b
|| b
->n_keys
== 0;
173 return a
->n_keys
== 0;
175 /* Checks if all keys in a are also contained b, and vice versa */
177 for (j
= 0; j
< a
->n_keys
; j
++) {
178 r
= dns_question_contains(b
, a
->keys
[j
]);
183 for (j
= 0; j
< b
->n_keys
; j
++) {
184 r
= dns_question_contains(a
, b
->keys
[j
]);
192 int dns_question_cname_redirect(DnsQuestion
*q
, const DnsResourceRecord
*cname
, DnsQuestion
**ret
) {
193 _cleanup_(dns_question_unrefp
) DnsQuestion
*n
= NULL
;
200 assert(IN_SET(cname
->key
->type
, DNS_TYPE_CNAME
, DNS_TYPE_DNAME
));
202 if (dns_question_size(q
) <= 0) {
207 DNS_QUESTION_FOREACH(key
, q
) {
208 _cleanup_free_
char *destination
= NULL
;
211 if (cname
->key
->type
== DNS_TYPE_CNAME
)
212 d
= cname
->cname
.name
;
214 r
= dns_name_change_suffix(dns_resource_key_name(key
), dns_resource_key_name(cname
->key
), cname
->dname
.name
, &destination
);
223 r
= dns_name_equal(dns_resource_key_name(key
), d
);
233 /* Fully the same, indicate we didn't do a thing */
239 n
= dns_question_new(q
->n_keys
);
243 /* Create a new question, and patch in the new name */
244 DNS_QUESTION_FOREACH(key
, q
) {
245 _cleanup_(dns_resource_key_unrefp
) DnsResourceKey
*k
= NULL
;
247 k
= dns_resource_key_new_redirect(key
, cname
);
251 r
= dns_question_add(n
, k
);
261 const char *dns_question_first_name(DnsQuestion
*q
) {
269 return dns_resource_key_name(q
->keys
[0]);
272 int dns_question_new_address(DnsQuestion
**ret
, int family
, const char *name
, bool convert_idna
) {
273 _cleanup_(dns_question_unrefp
) DnsQuestion
*q
= NULL
;
274 _cleanup_free_
char *buf
= NULL
;
280 if (!IN_SET(family
, AF_INET
, AF_INET6
, AF_UNSPEC
))
281 return -EAFNOSUPPORT
;
284 r
= dns_name_apply_idna(name
, &buf
);
287 if (r
> 0 && !streq(name
, buf
))
290 /* We did not manage to create convert the idna name, or it's
291 * the same as the original name. We assume the caller already
292 * created an unconverted question, so let's not repeat work
297 q
= dns_question_new(family
== AF_UNSPEC
? 2 : 1);
301 if (family
!= AF_INET6
) {
302 _cleanup_(dns_resource_key_unrefp
) DnsResourceKey
*key
= NULL
;
304 key
= dns_resource_key_new(DNS_CLASS_IN
, DNS_TYPE_A
, name
);
308 r
= dns_question_add(q
, key
);
313 if (family
!= AF_INET
) {
314 _cleanup_(dns_resource_key_unrefp
) DnsResourceKey
*key
= NULL
;
316 key
= dns_resource_key_new(DNS_CLASS_IN
, DNS_TYPE_AAAA
, name
);
320 r
= dns_question_add(q
, key
);
330 int dns_question_new_reverse(DnsQuestion
**ret
, int family
, const union in_addr_union
*a
) {
331 _cleanup_(dns_resource_key_unrefp
) DnsResourceKey
*key
= NULL
;
332 _cleanup_(dns_question_unrefp
) DnsQuestion
*q
= NULL
;
333 _cleanup_free_
char *reverse
= NULL
;
339 if (!IN_SET(family
, AF_INET
, AF_INET6
, AF_UNSPEC
))
340 return -EAFNOSUPPORT
;
342 r
= dns_name_reverse(family
, a
, &reverse
);
346 q
= dns_question_new(1);
350 key
= dns_resource_key_new_consume(DNS_CLASS_IN
, DNS_TYPE_PTR
, reverse
);
356 r
= dns_question_add(q
, key
);
365 int dns_question_new_service(
373 _cleanup_(dns_resource_key_unrefp
) DnsResourceKey
*key
= NULL
;
374 _cleanup_(dns_question_unrefp
) DnsQuestion
*q
= NULL
;
375 _cleanup_free_
char *buf
= NULL
, *joined
= NULL
;
381 /* We support three modes of invocation:
383 * 1. Only a domain is specified, in which case we assume a properly encoded SRV RR name, including service
384 * type and possibly a service name. If specified in this way we assume it's already IDNA converted if
387 * 2. Both service type and a domain specified, in which case a normal SRV RR is assumed, without a DNS-SD
388 * style prefix. In this case we'll IDNA convert the domain, if that's requested.
390 * 3. All three of service name, type and domain are specified, in which case a DNS-SD service is put
391 * together. The service name is never IDNA converted, and the domain is if requested.
393 * It's not supported to specify a service name without a type, or no domain name.
401 r
= dns_name_apply_idna(domain
, &buf
);
408 r
= dns_service_join(service
, type
, domain
, &joined
);
420 q
= dns_question_new(1 + with_txt
);
424 key
= dns_resource_key_new(DNS_CLASS_IN
, DNS_TYPE_SRV
, name
);
428 r
= dns_question_add(q
, key
);
433 dns_resource_key_unref(key
);
434 key
= dns_resource_key_new(DNS_CLASS_IN
, DNS_TYPE_TXT
, name
);
438 r
= dns_question_add(q
, key
);