]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/resolve/resolved-dns-question.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2014 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
22 #include "alloc-util.h"
23 #include "dns-domain.h"
25 #include "resolved-dns-question.h"
27 DnsQuestion
*dns_question_new(unsigned n
) {
32 q
= malloc0(offsetof(DnsQuestion
, keys
) + sizeof(DnsResourceKey
*) * n
);
42 DnsQuestion
*dns_question_ref(DnsQuestion
*q
) {
51 DnsQuestion
*dns_question_unref(DnsQuestion
*q
) {
60 for (i
= 0; i
< q
->n_keys
; i
++)
61 dns_resource_key_unref(q
->keys
[i
]);
69 int dns_question_add(DnsQuestion
*q
, DnsResourceKey
*key
) {
78 for (i
= 0; i
< q
->n_keys
; i
++) {
79 r
= dns_resource_key_equal(q
->keys
[i
], key
);
86 if (q
->n_keys
>= q
->n_allocated
)
89 q
->keys
[q
->n_keys
++] = dns_resource_key_ref(key
);
93 int dns_question_matches_rr(DnsQuestion
*q
, DnsResourceRecord
*rr
, const char *search_domain
) {
102 for (i
= 0; i
< q
->n_keys
; i
++) {
103 r
= dns_resource_key_match_rr(q
->keys
[i
], rr
, search_domain
);
111 int dns_question_matches_cname_or_dname(DnsQuestion
*q
, DnsResourceRecord
*rr
, const char *search_domain
) {
120 if (!IN_SET(rr
->key
->type
, DNS_TYPE_CNAME
, DNS_TYPE_DNAME
))
123 for (i
= 0; i
< q
->n_keys
; i
++) {
124 /* For a {C,D}NAME record we can never find a matching {C,D}NAME record */
125 if (!dns_type_may_redirect(q
->keys
[i
]->type
))
128 r
= dns_resource_key_match_cname_or_dname(q
->keys
[i
], rr
->key
, search_domain
);
136 int dns_question_is_valid_for_query(DnsQuestion
*q
) {
147 if (q
->n_keys
> 65535)
150 name
= DNS_RESOURCE_KEY_NAME(q
->keys
[0]);
154 /* Check that all keys in this question bear the same name */
155 for (i
= 0; i
< q
->n_keys
; i
++) {
159 r
= dns_name_equal(DNS_RESOURCE_KEY_NAME(q
->keys
[i
]), name
);
164 if (!dns_type_is_valid_query(q
->keys
[i
]->type
))
171 int dns_question_contains(DnsQuestion
*a
, const DnsResourceKey
*k
) {
180 for (j
= 0; j
< a
->n_keys
; j
++) {
181 r
= dns_resource_key_equal(a
->keys
[j
], k
);
189 int dns_question_is_equal(DnsQuestion
*a
, DnsQuestion
*b
) {
197 return !b
|| b
->n_keys
== 0;
199 return a
->n_keys
== 0;
201 /* Checks if all keys in a are also contained b, and vice versa */
203 for (j
= 0; j
< a
->n_keys
; j
++) {
204 r
= dns_question_contains(b
, a
->keys
[j
]);
209 for (j
= 0; j
< b
->n_keys
; j
++) {
210 r
= dns_question_contains(a
, b
->keys
[j
]);
218 int dns_question_cname_redirect(DnsQuestion
*q
, const DnsResourceRecord
*cname
, DnsQuestion
**ret
) {
219 _cleanup_(dns_question_unrefp
) DnsQuestion
*n
= NULL
;
226 assert(IN_SET(cname
->key
->type
, DNS_TYPE_CNAME
, DNS_TYPE_DNAME
));
228 if (dns_question_size(q
) <= 0) {
233 DNS_QUESTION_FOREACH(key
, q
) {
234 _cleanup_free_
char *destination
= NULL
;
237 if (cname
->key
->type
== DNS_TYPE_CNAME
)
238 d
= cname
->cname
.name
;
240 r
= dns_name_change_suffix(DNS_RESOURCE_KEY_NAME(key
), DNS_RESOURCE_KEY_NAME(cname
->key
), cname
->dname
.name
, &destination
);
249 r
= dns_name_equal(DNS_RESOURCE_KEY_NAME(key
), d
);
259 /* Fully the same, indicate we didn't do a thing */
265 n
= dns_question_new(q
->n_keys
);
269 /* Create a new question, and patch in the new name */
270 DNS_QUESTION_FOREACH(key
, q
) {
271 _cleanup_(dns_resource_key_unrefp
) DnsResourceKey
*k
= NULL
;
273 k
= dns_resource_key_new_redirect(key
, cname
);
277 r
= dns_question_add(n
, k
);
288 const char *dns_question_first_name(DnsQuestion
*q
) {
296 return DNS_RESOURCE_KEY_NAME(q
->keys
[0]);
299 int dns_question_new_address(DnsQuestion
**ret
, int family
, const char *name
, bool convert_idna
) {
300 _cleanup_(dns_question_unrefp
) DnsQuestion
*q
= NULL
;
301 _cleanup_free_
char *buf
= NULL
;
307 if (!IN_SET(family
, AF_INET
, AF_INET6
, AF_UNSPEC
))
308 return -EAFNOSUPPORT
;
311 r
= dns_name_apply_idna(name
, &buf
);
318 q
= dns_question_new(family
== AF_UNSPEC
? 2 : 1);
322 if (family
!= AF_INET6
) {
323 _cleanup_(dns_resource_key_unrefp
) DnsResourceKey
*key
= NULL
;
325 key
= dns_resource_key_new(DNS_CLASS_IN
, DNS_TYPE_A
, name
);
329 r
= dns_question_add(q
, key
);
334 if (family
!= AF_INET
) {
335 _cleanup_(dns_resource_key_unrefp
) DnsResourceKey
*key
= NULL
;
337 key
= dns_resource_key_new(DNS_CLASS_IN
, DNS_TYPE_AAAA
, name
);
341 r
= dns_question_add(q
, key
);
352 int dns_question_new_reverse(DnsQuestion
**ret
, int family
, const union in_addr_union
*a
) {
353 _cleanup_(dns_resource_key_unrefp
) DnsResourceKey
*key
= NULL
;
354 _cleanup_(dns_question_unrefp
) DnsQuestion
*q
= NULL
;
355 _cleanup_free_
char *reverse
= NULL
;
361 if (!IN_SET(family
, AF_INET
, AF_INET6
, AF_UNSPEC
))
362 return -EAFNOSUPPORT
;
364 r
= dns_name_reverse(family
, a
, &reverse
);
368 q
= dns_question_new(1);
372 key
= dns_resource_key_new_consume(DNS_CLASS_IN
, DNS_TYPE_PTR
, reverse
);
378 r
= dns_question_add(q
, key
);
388 int dns_question_new_service(
396 _cleanup_(dns_resource_key_unrefp
) DnsResourceKey
*key
= NULL
;
397 _cleanup_(dns_question_unrefp
) DnsQuestion
*q
= NULL
;
398 _cleanup_free_
char *buf
= NULL
, *joined
= NULL
;
404 /* We support three modes of invocation:
406 * 1. Only a domain is specified, in which case we assume a properly encoded SRV RR name, including service
407 * type and possibly a service name. If specified in this way we assume it's already IDNA converted if
410 * 2. Both service type and a domain specified, in which case a normal SRV RR is assumed, without a DNS-SD
411 * style prefix. In this case we'll IDNA convert the domain, if that's requested.
413 * 3. All three of service name, type and domain are specified, in which case a DNS-SD service is put
414 * together. The service name is never IDNA converted, and the domain is if requested.
416 * It's not supported to specify a service name without a type, or no domain name.
424 r
= dns_name_apply_idna(domain
, &buf
);
431 r
= dns_service_join(service
, type
, domain
, &joined
);
443 q
= dns_question_new(1 + with_txt
);
447 key
= dns_resource_key_new(DNS_CLASS_IN
, DNS_TYPE_SRV
, name
);
451 r
= dns_question_add(q
, key
);
456 dns_resource_key_unref(key
);
457 key
= dns_resource_key_new(DNS_CLASS_IN
, DNS_TYPE_TXT
, name
);
461 r
= dns_question_add(q
, key
);