]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/resolve/resolved-dns-question.c
2 This file is part of systemd.
4 Copyright 2014 Lennart Poettering
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 #include "alloc-util.h"
21 #include "dns-domain.h"
23 #include "resolved-dns-question.h"
25 DnsQuestion
*dns_question_new(unsigned n
) {
30 q
= malloc0(offsetof(DnsQuestion
, keys
) + sizeof(DnsResourceKey
*) * n
);
40 DnsQuestion
*dns_question_ref(DnsQuestion
*q
) {
49 DnsQuestion
*dns_question_unref(DnsQuestion
*q
) {
58 for (i
= 0; i
< q
->n_keys
; i
++)
59 dns_resource_key_unref(q
->keys
[i
]);
67 int dns_question_add(DnsQuestion
*q
, DnsResourceKey
*key
) {
76 for (i
= 0; i
< q
->n_keys
; i
++) {
77 r
= dns_resource_key_equal(q
->keys
[i
], key
);
84 if (q
->n_keys
>= q
->n_allocated
)
87 q
->keys
[q
->n_keys
++] = dns_resource_key_ref(key
);
91 int dns_question_matches_rr(DnsQuestion
*q
, DnsResourceRecord
*rr
, const char *search_domain
) {
100 for (i
= 0; i
< q
->n_keys
; i
++) {
101 r
= dns_resource_key_match_rr(q
->keys
[i
], rr
, search_domain
);
109 int dns_question_matches_cname_or_dname(DnsQuestion
*q
, DnsResourceRecord
*rr
, const char *search_domain
) {
118 if (!IN_SET(rr
->key
->type
, DNS_TYPE_CNAME
, DNS_TYPE_DNAME
))
121 for (i
= 0; i
< q
->n_keys
; i
++) {
122 /* For a {C,D}NAME record we can never find a matching {C,D}NAME record */
123 if (!dns_type_may_redirect(q
->keys
[i
]->type
))
126 r
= dns_resource_key_match_cname_or_dname(q
->keys
[i
], rr
->key
, search_domain
);
134 int dns_question_is_valid_for_query(DnsQuestion
*q
) {
145 if (q
->n_keys
> 65535)
148 name
= dns_resource_key_name(q
->keys
[0]);
152 /* Check that all keys in this question bear the same name */
153 for (i
= 0; i
< q
->n_keys
; i
++) {
157 r
= dns_name_equal(dns_resource_key_name(q
->keys
[i
]), name
);
162 if (!dns_type_is_valid_query(q
->keys
[i
]->type
))
169 int dns_question_contains(DnsQuestion
*a
, const DnsResourceKey
*k
) {
178 for (j
= 0; j
< a
->n_keys
; j
++) {
179 r
= dns_resource_key_equal(a
->keys
[j
], k
);
187 int dns_question_is_equal(DnsQuestion
*a
, DnsQuestion
*b
) {
195 return !b
|| b
->n_keys
== 0;
197 return a
->n_keys
== 0;
199 /* Checks if all keys in a are also contained b, and vice versa */
201 for (j
= 0; j
< a
->n_keys
; j
++) {
202 r
= dns_question_contains(b
, a
->keys
[j
]);
207 for (j
= 0; j
< b
->n_keys
; j
++) {
208 r
= dns_question_contains(a
, b
->keys
[j
]);
216 int dns_question_cname_redirect(DnsQuestion
*q
, const DnsResourceRecord
*cname
, DnsQuestion
**ret
) {
217 _cleanup_(dns_question_unrefp
) DnsQuestion
*n
= NULL
;
224 assert(IN_SET(cname
->key
->type
, DNS_TYPE_CNAME
, DNS_TYPE_DNAME
));
226 if (dns_question_size(q
) <= 0) {
231 DNS_QUESTION_FOREACH(key
, q
) {
232 _cleanup_free_
char *destination
= NULL
;
235 if (cname
->key
->type
== DNS_TYPE_CNAME
)
236 d
= cname
->cname
.name
;
238 r
= dns_name_change_suffix(dns_resource_key_name(key
), dns_resource_key_name(cname
->key
), cname
->dname
.name
, &destination
);
247 r
= dns_name_equal(dns_resource_key_name(key
), d
);
257 /* Fully the same, indicate we didn't do a thing */
263 n
= dns_question_new(q
->n_keys
);
267 /* Create a new question, and patch in the new name */
268 DNS_QUESTION_FOREACH(key
, q
) {
269 _cleanup_(dns_resource_key_unrefp
) DnsResourceKey
*k
= NULL
;
271 k
= dns_resource_key_new_redirect(key
, cname
);
275 r
= dns_question_add(n
, k
);
286 const char *dns_question_first_name(DnsQuestion
*q
) {
294 return dns_resource_key_name(q
->keys
[0]);
297 int dns_question_new_address(DnsQuestion
**ret
, int family
, const char *name
, bool convert_idna
) {
298 _cleanup_(dns_question_unrefp
) DnsQuestion
*q
= NULL
;
299 _cleanup_free_
char *buf
= NULL
;
305 if (!IN_SET(family
, AF_INET
, AF_INET6
, AF_UNSPEC
))
306 return -EAFNOSUPPORT
;
309 r
= dns_name_apply_idna(name
, &buf
);
316 q
= dns_question_new(family
== AF_UNSPEC
? 2 : 1);
320 if (family
!= AF_INET6
) {
321 _cleanup_(dns_resource_key_unrefp
) DnsResourceKey
*key
= NULL
;
323 key
= dns_resource_key_new(DNS_CLASS_IN
, DNS_TYPE_A
, name
);
327 r
= dns_question_add(q
, key
);
332 if (family
!= AF_INET
) {
333 _cleanup_(dns_resource_key_unrefp
) DnsResourceKey
*key
= NULL
;
335 key
= dns_resource_key_new(DNS_CLASS_IN
, DNS_TYPE_AAAA
, name
);
339 r
= dns_question_add(q
, key
);
350 int dns_question_new_reverse(DnsQuestion
**ret
, int family
, const union in_addr_union
*a
) {
351 _cleanup_(dns_resource_key_unrefp
) DnsResourceKey
*key
= NULL
;
352 _cleanup_(dns_question_unrefp
) DnsQuestion
*q
= NULL
;
353 _cleanup_free_
char *reverse
= NULL
;
359 if (!IN_SET(family
, AF_INET
, AF_INET6
, AF_UNSPEC
))
360 return -EAFNOSUPPORT
;
362 r
= dns_name_reverse(family
, a
, &reverse
);
366 q
= dns_question_new(1);
370 key
= dns_resource_key_new_consume(DNS_CLASS_IN
, DNS_TYPE_PTR
, reverse
);
376 r
= dns_question_add(q
, key
);
386 int dns_question_new_service(
394 _cleanup_(dns_resource_key_unrefp
) DnsResourceKey
*key
= NULL
;
395 _cleanup_(dns_question_unrefp
) DnsQuestion
*q
= NULL
;
396 _cleanup_free_
char *buf
= NULL
, *joined
= NULL
;
402 /* We support three modes of invocation:
404 * 1. Only a domain is specified, in which case we assume a properly encoded SRV RR name, including service
405 * type and possibly a service name. If specified in this way we assume it's already IDNA converted if
408 * 2. Both service type and a domain specified, in which case a normal SRV RR is assumed, without a DNS-SD
409 * style prefix. In this case we'll IDNA convert the domain, if that's requested.
411 * 3. All three of service name, type and domain are specified, in which case a DNS-SD service is put
412 * together. The service name is never IDNA converted, and the domain is if requested.
414 * It's not supported to specify a service name without a type, or no domain name.
422 r
= dns_name_apply_idna(domain
, &buf
);
429 r
= dns_service_join(service
, type
, domain
, &joined
);
441 q
= dns_question_new(1 + with_txt
);
445 key
= dns_resource_key_new(DNS_CLASS_IN
, DNS_TYPE_SRV
, name
);
449 r
= dns_question_add(q
, key
);
454 dns_resource_key_unref(key
);
455 key
= dns_resource_key_new(DNS_CLASS_IN
, DNS_TYPE_TXT
, name
);
459 r
= dns_question_add(q
, key
);