]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/resolve/resolved-dns-question.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2014 Lennart Poettering
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
21 #include "alloc-util.h"
22 #include "dns-domain.h"
24 #include "resolved-dns-question.h"
26 DnsQuestion
*dns_question_new(unsigned n
) {
31 q
= malloc0(offsetof(DnsQuestion
, keys
) + sizeof(DnsResourceKey
*) * n
);
41 DnsQuestion
*dns_question_ref(DnsQuestion
*q
) {
50 DnsQuestion
*dns_question_unref(DnsQuestion
*q
) {
59 for (i
= 0; i
< q
->n_keys
; i
++)
60 dns_resource_key_unref(q
->keys
[i
]);
68 int dns_question_add(DnsQuestion
*q
, DnsResourceKey
*key
) {
77 for (i
= 0; i
< q
->n_keys
; i
++) {
78 r
= dns_resource_key_equal(q
->keys
[i
], key
);
85 if (q
->n_keys
>= q
->n_allocated
)
88 q
->keys
[q
->n_keys
++] = dns_resource_key_ref(key
);
92 int dns_question_matches_rr(DnsQuestion
*q
, DnsResourceRecord
*rr
, const char *search_domain
) {
101 for (i
= 0; i
< q
->n_keys
; i
++) {
102 r
= dns_resource_key_match_rr(q
->keys
[i
], rr
, search_domain
);
110 int dns_question_matches_cname_or_dname(DnsQuestion
*q
, DnsResourceRecord
*rr
, const char *search_domain
) {
119 if (!IN_SET(rr
->key
->type
, DNS_TYPE_CNAME
, DNS_TYPE_DNAME
))
122 for (i
= 0; i
< q
->n_keys
; i
++) {
123 /* For a {C,D}NAME record we can never find a matching {C,D}NAME record */
124 if (!dns_type_may_redirect(q
->keys
[i
]->type
))
127 r
= dns_resource_key_match_cname_or_dname(q
->keys
[i
], rr
->key
, search_domain
);
135 int dns_question_is_valid_for_query(DnsQuestion
*q
) {
146 if (q
->n_keys
> 65535)
149 name
= dns_resource_key_name(q
->keys
[0]);
153 /* Check that all keys in this question bear the same name */
154 for (i
= 0; i
< q
->n_keys
; i
++) {
158 r
= dns_name_equal(dns_resource_key_name(q
->keys
[i
]), name
);
163 if (!dns_type_is_valid_query(q
->keys
[i
]->type
))
170 int dns_question_contains(DnsQuestion
*a
, const DnsResourceKey
*k
) {
179 for (j
= 0; j
< a
->n_keys
; j
++) {
180 r
= dns_resource_key_equal(a
->keys
[j
], k
);
188 int dns_question_is_equal(DnsQuestion
*a
, DnsQuestion
*b
) {
196 return !b
|| b
->n_keys
== 0;
198 return a
->n_keys
== 0;
200 /* Checks if all keys in a are also contained b, and vice versa */
202 for (j
= 0; j
< a
->n_keys
; j
++) {
203 r
= dns_question_contains(b
, a
->keys
[j
]);
208 for (j
= 0; j
< b
->n_keys
; j
++) {
209 r
= dns_question_contains(a
, b
->keys
[j
]);
217 int dns_question_cname_redirect(DnsQuestion
*q
, const DnsResourceRecord
*cname
, DnsQuestion
**ret
) {
218 _cleanup_(dns_question_unrefp
) DnsQuestion
*n
= NULL
;
225 assert(IN_SET(cname
->key
->type
, DNS_TYPE_CNAME
, DNS_TYPE_DNAME
));
227 if (dns_question_size(q
) <= 0) {
232 DNS_QUESTION_FOREACH(key
, q
) {
233 _cleanup_free_
char *destination
= NULL
;
236 if (cname
->key
->type
== DNS_TYPE_CNAME
)
237 d
= cname
->cname
.name
;
239 r
= dns_name_change_suffix(dns_resource_key_name(key
), dns_resource_key_name(cname
->key
), cname
->dname
.name
, &destination
);
248 r
= dns_name_equal(dns_resource_key_name(key
), d
);
258 /* Fully the same, indicate we didn't do a thing */
264 n
= dns_question_new(q
->n_keys
);
268 /* Create a new question, and patch in the new name */
269 DNS_QUESTION_FOREACH(key
, q
) {
270 _cleanup_(dns_resource_key_unrefp
) DnsResourceKey
*k
= NULL
;
272 k
= dns_resource_key_new_redirect(key
, cname
);
276 r
= dns_question_add(n
, k
);
287 const char *dns_question_first_name(DnsQuestion
*q
) {
295 return dns_resource_key_name(q
->keys
[0]);
298 int dns_question_new_address(DnsQuestion
**ret
, int family
, const char *name
, bool convert_idna
) {
299 _cleanup_(dns_question_unrefp
) DnsQuestion
*q
= NULL
;
300 _cleanup_free_
char *buf
= NULL
;
306 if (!IN_SET(family
, AF_INET
, AF_INET6
, AF_UNSPEC
))
307 return -EAFNOSUPPORT
;
310 r
= dns_name_apply_idna(name
, &buf
);
313 if (r
> 0 && !streq(name
, buf
))
316 /* We did not manage to create convert the idna name, or it's
317 * the same as the original name. We assume the caller already
318 * created an uncoverted question, so let's not repeat work
323 q
= dns_question_new(family
== AF_UNSPEC
? 2 : 1);
327 if (family
!= AF_INET6
) {
328 _cleanup_(dns_resource_key_unrefp
) DnsResourceKey
*key
= NULL
;
330 key
= dns_resource_key_new(DNS_CLASS_IN
, DNS_TYPE_A
, name
);
334 r
= dns_question_add(q
, key
);
339 if (family
!= AF_INET
) {
340 _cleanup_(dns_resource_key_unrefp
) DnsResourceKey
*key
= NULL
;
342 key
= dns_resource_key_new(DNS_CLASS_IN
, DNS_TYPE_AAAA
, name
);
346 r
= dns_question_add(q
, key
);
357 int dns_question_new_reverse(DnsQuestion
**ret
, int family
, const union in_addr_union
*a
) {
358 _cleanup_(dns_resource_key_unrefp
) DnsResourceKey
*key
= NULL
;
359 _cleanup_(dns_question_unrefp
) DnsQuestion
*q
= NULL
;
360 _cleanup_free_
char *reverse
= NULL
;
366 if (!IN_SET(family
, AF_INET
, AF_INET6
, AF_UNSPEC
))
367 return -EAFNOSUPPORT
;
369 r
= dns_name_reverse(family
, a
, &reverse
);
373 q
= dns_question_new(1);
377 key
= dns_resource_key_new_consume(DNS_CLASS_IN
, DNS_TYPE_PTR
, reverse
);
383 r
= dns_question_add(q
, key
);
393 int dns_question_new_service(
401 _cleanup_(dns_resource_key_unrefp
) DnsResourceKey
*key
= NULL
;
402 _cleanup_(dns_question_unrefp
) DnsQuestion
*q
= NULL
;
403 _cleanup_free_
char *buf
= NULL
, *joined
= NULL
;
409 /* We support three modes of invocation:
411 * 1. Only a domain is specified, in which case we assume a properly encoded SRV RR name, including service
412 * type and possibly a service name. If specified in this way we assume it's already IDNA converted if
415 * 2. Both service type and a domain specified, in which case a normal SRV RR is assumed, without a DNS-SD
416 * style prefix. In this case we'll IDNA convert the domain, if that's requested.
418 * 3. All three of service name, type and domain are specified, in which case a DNS-SD service is put
419 * together. The service name is never IDNA converted, and the domain is if requested.
421 * It's not supported to specify a service name without a type, or no domain name.
429 r
= dns_name_apply_idna(domain
, &buf
);
436 r
= dns_service_join(service
, type
, domain
, &joined
);
448 q
= dns_question_new(1 + with_txt
);
452 key
= dns_resource_key_new(DNS_CLASS_IN
, DNS_TYPE_SRV
, name
);
456 r
= dns_question_add(q
, key
);
461 dns_resource_key_unref(key
);
462 key
= dns_resource_key_new(DNS_CLASS_IN
, DNS_TYPE_TXT
, name
);
466 r
= dns_question_add(q
, key
);