]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/resolve/resolved-dns-question.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 Copyright 2014 Lennart Poettering
6 #include "alloc-util.h"
7 #include "dns-domain.h"
9 #include "resolved-dns-question.h"
11 DnsQuestion
*dns_question_new(size_t n
) {
16 q
= malloc0(offsetof(DnsQuestion
, keys
) + sizeof(DnsResourceKey
*) * n
);
26 DnsQuestion
*dns_question_ref(DnsQuestion
*q
) {
35 DnsQuestion
*dns_question_unref(DnsQuestion
*q
) {
44 for (i
= 0; i
< q
->n_keys
; i
++)
45 dns_resource_key_unref(q
->keys
[i
]);
53 int dns_question_add(DnsQuestion
*q
, DnsResourceKey
*key
) {
62 for (i
= 0; i
< q
->n_keys
; i
++) {
63 r
= dns_resource_key_equal(q
->keys
[i
], key
);
70 if (q
->n_keys
>= q
->n_allocated
)
73 q
->keys
[q
->n_keys
++] = dns_resource_key_ref(key
);
77 int dns_question_matches_rr(DnsQuestion
*q
, DnsResourceRecord
*rr
, const char *search_domain
) {
86 for (i
= 0; i
< q
->n_keys
; i
++) {
87 r
= dns_resource_key_match_rr(q
->keys
[i
], rr
, search_domain
);
95 int dns_question_matches_cname_or_dname(DnsQuestion
*q
, DnsResourceRecord
*rr
, const char *search_domain
) {
104 if (!IN_SET(rr
->key
->type
, DNS_TYPE_CNAME
, DNS_TYPE_DNAME
))
107 for (i
= 0; i
< q
->n_keys
; i
++) {
108 /* For a {C,D}NAME record we can never find a matching {C,D}NAME record */
109 if (!dns_type_may_redirect(q
->keys
[i
]->type
))
112 r
= dns_resource_key_match_cname_or_dname(q
->keys
[i
], rr
->key
, search_domain
);
120 int dns_question_is_valid_for_query(DnsQuestion
*q
) {
131 if (q
->n_keys
> 65535)
134 name
= dns_resource_key_name(q
->keys
[0]);
138 /* Check that all keys in this question bear the same name */
139 for (i
= 0; i
< q
->n_keys
; i
++) {
143 r
= dns_name_equal(dns_resource_key_name(q
->keys
[i
]), name
);
148 if (!dns_type_is_valid_query(q
->keys
[i
]->type
))
155 int dns_question_contains(DnsQuestion
*a
, const DnsResourceKey
*k
) {
164 for (j
= 0; j
< a
->n_keys
; j
++) {
165 r
= dns_resource_key_equal(a
->keys
[j
], k
);
173 int dns_question_is_equal(DnsQuestion
*a
, DnsQuestion
*b
) {
181 return !b
|| b
->n_keys
== 0;
183 return a
->n_keys
== 0;
185 /* Checks if all keys in a are also contained b, and vice versa */
187 for (j
= 0; j
< a
->n_keys
; j
++) {
188 r
= dns_question_contains(b
, a
->keys
[j
]);
193 for (j
= 0; j
< b
->n_keys
; j
++) {
194 r
= dns_question_contains(a
, b
->keys
[j
]);
202 int dns_question_cname_redirect(DnsQuestion
*q
, const DnsResourceRecord
*cname
, DnsQuestion
**ret
) {
203 _cleanup_(dns_question_unrefp
) DnsQuestion
*n
= NULL
;
210 assert(IN_SET(cname
->key
->type
, DNS_TYPE_CNAME
, DNS_TYPE_DNAME
));
212 if (dns_question_size(q
) <= 0) {
217 DNS_QUESTION_FOREACH(key
, q
) {
218 _cleanup_free_
char *destination
= NULL
;
221 if (cname
->key
->type
== DNS_TYPE_CNAME
)
222 d
= cname
->cname
.name
;
224 r
= dns_name_change_suffix(dns_resource_key_name(key
), dns_resource_key_name(cname
->key
), cname
->dname
.name
, &destination
);
233 r
= dns_name_equal(dns_resource_key_name(key
), d
);
243 /* Fully the same, indicate we didn't do a thing */
249 n
= dns_question_new(q
->n_keys
);
253 /* Create a new question, and patch in the new name */
254 DNS_QUESTION_FOREACH(key
, q
) {
255 _cleanup_(dns_resource_key_unrefp
) DnsResourceKey
*k
= NULL
;
257 k
= dns_resource_key_new_redirect(key
, cname
);
261 r
= dns_question_add(n
, k
);
271 const char *dns_question_first_name(DnsQuestion
*q
) {
279 return dns_resource_key_name(q
->keys
[0]);
282 int dns_question_new_address(DnsQuestion
**ret
, int family
, const char *name
, bool convert_idna
) {
283 _cleanup_(dns_question_unrefp
) DnsQuestion
*q
= NULL
;
284 _cleanup_free_
char *buf
= NULL
;
290 if (!IN_SET(family
, AF_INET
, AF_INET6
, AF_UNSPEC
))
291 return -EAFNOSUPPORT
;
294 r
= dns_name_apply_idna(name
, &buf
);
297 if (r
> 0 && !streq(name
, buf
))
300 /* We did not manage to create convert the idna name, or it's
301 * the same as the original name. We assume the caller already
302 * created an uncoverted question, so let's not repeat work
307 q
= dns_question_new(family
== AF_UNSPEC
? 2 : 1);
311 if (family
!= AF_INET6
) {
312 _cleanup_(dns_resource_key_unrefp
) DnsResourceKey
*key
= NULL
;
314 key
= dns_resource_key_new(DNS_CLASS_IN
, DNS_TYPE_A
, name
);
318 r
= dns_question_add(q
, key
);
323 if (family
!= AF_INET
) {
324 _cleanup_(dns_resource_key_unrefp
) DnsResourceKey
*key
= NULL
;
326 key
= dns_resource_key_new(DNS_CLASS_IN
, DNS_TYPE_AAAA
, name
);
330 r
= dns_question_add(q
, key
);
340 int dns_question_new_reverse(DnsQuestion
**ret
, int family
, const union in_addr_union
*a
) {
341 _cleanup_(dns_resource_key_unrefp
) DnsResourceKey
*key
= NULL
;
342 _cleanup_(dns_question_unrefp
) DnsQuestion
*q
= NULL
;
343 _cleanup_free_
char *reverse
= NULL
;
349 if (!IN_SET(family
, AF_INET
, AF_INET6
, AF_UNSPEC
))
350 return -EAFNOSUPPORT
;
352 r
= dns_name_reverse(family
, a
, &reverse
);
356 q
= dns_question_new(1);
360 key
= dns_resource_key_new_consume(DNS_CLASS_IN
, DNS_TYPE_PTR
, reverse
);
366 r
= dns_question_add(q
, key
);
375 int dns_question_new_service(
383 _cleanup_(dns_resource_key_unrefp
) DnsResourceKey
*key
= NULL
;
384 _cleanup_(dns_question_unrefp
) DnsQuestion
*q
= NULL
;
385 _cleanup_free_
char *buf
= NULL
, *joined
= NULL
;
391 /* We support three modes of invocation:
393 * 1. Only a domain is specified, in which case we assume a properly encoded SRV RR name, including service
394 * type and possibly a service name. If specified in this way we assume it's already IDNA converted if
397 * 2. Both service type and a domain specified, in which case a normal SRV RR is assumed, without a DNS-SD
398 * style prefix. In this case we'll IDNA convert the domain, if that's requested.
400 * 3. All three of service name, type and domain are specified, in which case a DNS-SD service is put
401 * together. The service name is never IDNA converted, and the domain is if requested.
403 * It's not supported to specify a service name without a type, or no domain name.
411 r
= dns_name_apply_idna(domain
, &buf
);
418 r
= dns_service_join(service
, type
, domain
, &joined
);
430 q
= dns_question_new(1 + with_txt
);
434 key
= dns_resource_key_new(DNS_CLASS_IN
, DNS_TYPE_SRV
, name
);
438 r
= dns_question_add(q
, key
);
443 dns_resource_key_unref(key
);
444 key
= dns_resource_key_new(DNS_CLASS_IN
, DNS_TYPE_TXT
, name
);
448 r
= dns_question_add(q
, key
);