]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/resolve/resolved-dns-query.c
Add SPDX license identifiers to source files under the LGPL
[thirdparty/systemd.git] / src / resolve / resolved-dns-query.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
74b2466e
LP
2/***
3 This file is part of systemd.
4
5 Copyright 2014 Lennart Poettering
6
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.
11
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.
16
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/>.
19***/
20
b5efdb8a 21#include "alloc-util.h"
2a1037af 22#include "dns-domain.h"
011696f7 23#include "dns-type.h"
b5efdb8a 24#include "hostname-util.h"
78c6a153 25#include "local-addresses.h"
74b2466e 26#include "resolved-dns-query.h"
839a4a20 27#include "resolved-dns-synthesize.h"
dd0bc0f1 28#include "resolved-etc-hosts.h"
23b298bc 29#include "string-util.h"
74b2466e 30
0c903ae7 31/* How long to wait for the query in total */
74a3ed74 32#define QUERY_TIMEOUT_USEC (60 * USEC_PER_SEC)
0c903ae7 33
8ba9fd9c 34#define CNAME_MAX 8
39762fdf 35#define QUERIES_MAX 2048
45ec7efb 36#define AUXILIARY_QUERIES_MAX 64
8ba9fd9c 37
801ad6a6
LP
38static int dns_query_candidate_new(DnsQueryCandidate **ret, DnsQuery *q, DnsScope *s) {
39 DnsQueryCandidate *c;
74b2466e 40
801ad6a6 41 assert(ret);
faa133f3 42 assert(q);
801ad6a6 43 assert(s);
74b2466e 44
801ad6a6
LP
45 c = new0(DnsQueryCandidate, 1);
46 if (!c)
47 return -ENOMEM;
48
49 c->query = q;
50 c->scope = s;
51
52 LIST_PREPEND(candidates_by_query, q->candidates, c);
53 LIST_PREPEND(candidates_by_scope, s->query_candidates, c);
54
55 *ret = c;
56 return 0;
57}
58
59static void dns_query_candidate_stop(DnsQueryCandidate *c) {
60 DnsTransaction *t;
74b2466e 61
801ad6a6
LP
62 assert(c);
63
64 while ((t = set_steal_first(c->transactions))) {
547973de 65 set_remove(t->notify_query_candidates, c);
35aa04e9 66 set_remove(t->notify_query_candidates_done, c);
ec2c5e43 67 dns_transaction_gc(t);
74b2466e 68 }
74b2466e
LP
69}
70
801ad6a6
LP
71DnsQueryCandidate* dns_query_candidate_free(DnsQueryCandidate *c) {
72
73 if (!c)
74 return NULL;
75
76 dns_query_candidate_stop(c);
77
78 set_free(c->transactions);
79 dns_search_domain_unref(c->search_domain);
80
81 if (c->query)
82 LIST_REMOVE(candidates_by_query, c->query->candidates, c);
83
84 if (c->scope)
85 LIST_REMOVE(candidates_by_scope, c->scope->query_candidates, c);
86
6b430fdb 87 return mfree(c);
801ad6a6
LP
88}
89
90static int dns_query_candidate_next_search_domain(DnsQueryCandidate *c) {
801ad6a6
LP
91 DnsSearchDomain *next = NULL;
92
93 assert(c);
94
ad44b56b 95 if (c->search_domain && c->search_domain->linked)
801ad6a6 96 next = c->search_domain->domains_next;
ad44b56b
LP
97 else
98 next = dns_scope_get_search_domains(c->scope);
801ad6a6 99
ad44b56b 100 for (;;) {
6627b7e2
LP
101 if (!next) /* We hit the end of the list */
102 return 0;
801ad6a6 103
ad44b56b
LP
104 if (!next->route_only)
105 break;
801ad6a6 106
ad44b56b
LP
107 /* Skip over route-only domains */
108 next = next->domains_next;
801ad6a6
LP
109 }
110
111 dns_search_domain_unref(c->search_domain);
112 c->search_domain = dns_search_domain_ref(next);
6627b7e2 113
801ad6a6
LP
114 return 1;
115}
116
117static int dns_query_candidate_add_transaction(DnsQueryCandidate *c, DnsResourceKey *key) {
118 DnsTransaction *t;
119 int r;
120
121 assert(c);
122 assert(key);
123
801ad6a6
LP
124 t = dns_scope_find_transaction(c->scope, key, true);
125 if (!t) {
126 r = dns_transaction_new(&t, c->scope, key);
127 if (r < 0)
128 return r;
547973de
LP
129 } else {
130 if (set_contains(c->transactions, t))
131 return 0;
801ad6a6
LP
132 }
133
547973de
LP
134 r = set_ensure_allocated(&c->transactions, NULL);
135 if (r < 0)
136 goto gc;
137
138 r = set_ensure_allocated(&t->notify_query_candidates, NULL);
801ad6a6
LP
139 if (r < 0)
140 goto gc;
141
35aa04e9
LP
142 r = set_ensure_allocated(&t->notify_query_candidates_done, NULL);
143 if (r < 0)
144 goto gc;
145
547973de 146 r = set_put(t->notify_query_candidates, c);
801ad6a6
LP
147 if (r < 0)
148 goto gc;
149
150 r = set_put(c->transactions, t);
151 if (r < 0) {
547973de 152 (void) set_remove(t->notify_query_candidates, c);
801ad6a6
LP
153 goto gc;
154 }
155
17c8de63 156 t->clamp_ttl = c->query->clamp_ttl;
547973de 157 return 1;
801ad6a6
LP
158
159gc:
160 dns_transaction_gc(t);
161 return r;
162}
163
164static int dns_query_candidate_go(DnsQueryCandidate *c) {
165 DnsTransaction *t;
166 Iterator i;
167 int r;
011696f7 168 unsigned n = 0;
801ad6a6
LP
169
170 assert(c);
171
172 /* Start the transactions that are not started yet */
173 SET_FOREACH(t, c->transactions, i) {
174 if (t->state != DNS_TRANSACTION_NULL)
175 continue;
176
177 r = dns_transaction_go(t);
178 if (r < 0)
179 return r;
011696f7
LP
180
181 n++;
801ad6a6
LP
182 }
183
011696f7
LP
184 /* If there was nothing to start, then let's proceed immediately */
185 if (n == 0)
186 dns_query_candidate_notify(c);
187
801ad6a6
LP
188 return 0;
189}
190
191static DnsTransactionState dns_query_candidate_state(DnsQueryCandidate *c) {
192 DnsTransactionState state = DNS_TRANSACTION_NO_SERVERS;
193 DnsTransaction *t;
194 Iterator i;
195
196 assert(c);
197
198 if (c->error_code != 0)
7cc6ed7b 199 return DNS_TRANSACTION_ERRNO;
801ad6a6
LP
200
201 SET_FOREACH(t, c->transactions, i) {
202
203 switch (t->state) {
204
5264131a
LP
205 case DNS_TRANSACTION_NULL:
206 /* If there's a NULL transaction pending, then
207 * this means not all transactions where
208 * started yet, and we were called from within
209 * the stackframe that is supposed to start
210 * remaining transactions. In this case,
211 * simply claim the candidate is pending. */
212
801ad6a6 213 case DNS_TRANSACTION_PENDING:
547973de
LP
214 case DNS_TRANSACTION_VALIDATING:
215 /* If there's one transaction currently in
216 * VALIDATING state, then this means there's
217 * also one in PENDING state, hence we can
218 * return PENDING immediately. */
219 return DNS_TRANSACTION_PENDING;
801ad6a6
LP
220
221 case DNS_TRANSACTION_SUCCESS:
222 state = t->state;
223 break;
224
225 default:
226 if (state != DNS_TRANSACTION_SUCCESS)
227 state = t->state;
228
229 break;
230 }
231 }
232
233 return state;
234}
235
011696f7
LP
236static bool dns_query_candidate_is_routable(DnsQueryCandidate *c, uint16_t type) {
237 int family;
238
239 assert(c);
240
241 /* Checks whether the specified RR type matches an address family that is routable on the link(s) the scope of
242 * this candidate belongs to. Specifically, whether there's a routable IPv4 address on it if we query an A RR,
243 * or a routable IPv6 address if we query an AAAA RR. */
244
245 if (!c->query->suppress_unroutable_family)
246 return true;
247
248 if (c->scope->protocol != DNS_PROTOCOL_DNS)
249 return true;
250
251 family = dns_type_to_af(type);
252 if (family < 0)
253 return true;
254
255 if (c->scope->link)
256 return link_relevant(c->scope->link, family, false);
257 else
258 return manager_routable(c->scope->manager, family);
259}
260
801ad6a6 261static int dns_query_candidate_setup_transactions(DnsQueryCandidate *c) {
23b298bc 262 DnsQuestion *question;
801ad6a6
LP
263 DnsResourceKey *key;
264 int n = 0, r;
265
266 assert(c);
267
268 dns_query_candidate_stop(c);
269
23b298bc
LP
270 question = dns_query_question_for_protocol(c->query, c->scope->protocol);
271
801ad6a6 272 /* Create one transaction per question key */
23b298bc 273 DNS_QUESTION_FOREACH(key, question) {
801ad6a6 274 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *new_key = NULL;
011696f7
LP
275 DnsResourceKey *qkey;
276
277 if (!dns_query_candidate_is_routable(c, key->type))
278 continue;
801ad6a6
LP
279
280 if (c->search_domain) {
281 r = dns_resource_key_new_append_suffix(&new_key, key, c->search_domain->name);
282 if (r < 0)
283 goto fail;
801ad6a6 284
011696f7
LP
285 qkey = new_key;
286 } else
287 qkey = key;
288
289 if (!dns_scope_good_key(c->scope, qkey))
290 continue;
291
292 r = dns_query_candidate_add_transaction(c, qkey);
801ad6a6
LP
293 if (r < 0)
294 goto fail;
295
296 n++;
297 }
298
299 return n;
300
301fail:
302 dns_query_candidate_stop(c);
303 return r;
304}
305
547973de 306void dns_query_candidate_notify(DnsQueryCandidate *c) {
801ad6a6
LP
307 DnsTransactionState state;
308 int r;
309
310 assert(c);
311
312 state = dns_query_candidate_state(c);
313
547973de 314 if (DNS_TRANSACTION_IS_LIVE(state))
801ad6a6
LP
315 return;
316
317 if (state != DNS_TRANSACTION_SUCCESS && c->search_domain) {
318
319 r = dns_query_candidate_next_search_domain(c);
320 if (r < 0)
321 goto fail;
322
323 if (r > 0) {
324 /* OK, there's another search domain to try, let's do so. */
325
326 r = dns_query_candidate_setup_transactions(c);
327 if (r < 0)
328 goto fail;
329
330 if (r > 0) {
331 /* New transactions where queued. Start them and wait */
332
333 r = dns_query_candidate_go(c);
334 if (r < 0)
335 goto fail;
336
337 return;
338 }
339 }
340
341 }
342
343 dns_query_ready(c->query);
344 return;
345
346fail:
347 log_warning_errno(r, "Failed to follow search domains: %m");
348 c->error_code = r;
349 dns_query_ready(c->query);
350}
351
352static void dns_query_stop(DnsQuery *q) {
353 DnsQueryCandidate *c;
354
355 assert(q);
356
357 q->timeout_event_source = sd_event_source_unref(q->timeout_event_source);
358
359 LIST_FOREACH(candidates_by_query, c, q->candidates)
360 dns_query_candidate_stop(c);
361}
362
7820b320
LP
363static void dns_query_free_candidates(DnsQuery *q) {
364 assert(q);
365
366 while (q->candidates)
367 dns_query_candidate_free(q->candidates);
368}
369
370static void dns_query_reset_answer(DnsQuery *q) {
371 assert(q);
372
373 q->answer = dns_answer_unref(q->answer);
374 q->answer_rcode = 0;
375 q->answer_dnssec_result = _DNSSEC_RESULT_INVALID;
7cc6ed7b 376 q->answer_errno = 0;
7820b320
LP
377 q->answer_authenticated = false;
378 q->answer_protocol = _DNS_PROTOCOL_INVALID;
379 q->answer_family = AF_UNSPEC;
380 q->answer_search_domain = dns_search_domain_unref(q->answer_search_domain);
381}
382
74b2466e 383DnsQuery *dns_query_free(DnsQuery *q) {
74b2466e
LP
384 if (!q)
385 return NULL;
386
45ec7efb
LP
387 while (q->auxiliary_queries)
388 dns_query_free(q->auxiliary_queries);
389
390 if (q->auxiliary_for) {
391 assert(q->auxiliary_for->n_auxiliary_queries > 0);
392 q->auxiliary_for->n_auxiliary_queries--;
393 LIST_REMOVE(auxiliary_queries, q->auxiliary_for->auxiliary_queries, q);
394 }
395
7820b320 396 dns_query_free_candidates(q);
322345fd 397
23b298bc
LP
398 dns_question_unref(q->question_idna);
399 dns_question_unref(q->question_utf8);
7820b320
LP
400
401 dns_query_reset_answer(q);
322345fd 402
ec2c5e43 403 sd_bus_message_unref(q->request);
82bd6ddd 404 sd_bus_track_unref(q->bus_track);
74b2466e 405
b30bf55d 406 dns_packet_unref(q->request_dns_packet);
e8d23f92 407 dns_packet_unref(q->reply_dns_packet);
b30bf55d
LP
408
409 if (q->request_dns_stream) {
410 /* Detach the stream from our query, in case something else keeps a reference to it. */
411 q->request_dns_stream->complete = NULL;
412 q->request_dns_stream->on_packet = NULL;
413 q->request_dns_stream->query = NULL;
414 dns_stream_unref(q->request_dns_stream);
415 }
416
23b298bc
LP
417 free(q->request_address_string);
418
39762fdf 419 if (q->manager) {
74b2466e 420 LIST_REMOVE(queries, q->manager->dns_queries, q);
39762fdf
LP
421 q->manager->n_dns_queries--;
422 }
74b2466e 423
6b430fdb 424 return mfree(q);
74b2466e
LP
425}
426
23b298bc
LP
427int dns_query_new(
428 Manager *m,
429 DnsQuery **ret,
430 DnsQuestion *question_utf8,
431 DnsQuestion *question_idna,
17c8de63
LP
432 int ifindex,
433 uint64_t flags) {
23b298bc 434
74b2466e 435 _cleanup_(dns_query_freep) DnsQuery *q = NULL;
23b298bc
LP
436 DnsResourceKey *key;
437 bool good = false;
faa133f3 438 int r;
202b76ae 439 char key_str[DNS_RESOURCE_KEY_STRING_MAX];
74b2466e
LP
440
441 assert(m);
442
23b298bc
LP
443 if (dns_question_size(question_utf8) > 0) {
444 r = dns_question_is_valid_for_query(question_utf8);
445 if (r < 0)
446 return r;
447 if (r == 0)
448 return -EINVAL;
449
450 good = true;
451 }
452
453 /* If the IDNA and UTF8 questions are the same, merge their references */
454 r = dns_question_is_equal(question_idna, question_utf8);
faa133f3
LP
455 if (r < 0)
456 return r;
23b298bc
LP
457 if (r > 0)
458 question_idna = question_utf8;
459 else {
460 if (dns_question_size(question_idna) > 0) {
461 r = dns_question_is_valid_for_query(question_idna);
462 if (r < 0)
463 return r;
464 if (r == 0)
465 return -EINVAL;
466
467 good = true;
468 }
469 }
470
471 if (!good) /* don't allow empty queries */
472 return -EINVAL;
74b2466e 473
39762fdf
LP
474 if (m->n_dns_queries >= QUERIES_MAX)
475 return -EBUSY;
476
74b2466e
LP
477 q = new0(DnsQuery, 1);
478 if (!q)
479 return -ENOMEM;
480
23b298bc
LP
481 q->question_utf8 = dns_question_ref(question_utf8);
482 q->question_idna = dns_question_ref(question_idna);
51323288
LP
483 q->ifindex = ifindex;
484 q->flags = flags;
7820b320 485 q->answer_dnssec_result = _DNSSEC_RESULT_INVALID;
801ad6a6 486 q->answer_protocol = _DNS_PROTOCOL_INVALID;
7820b320 487 q->answer_family = AF_UNSPEC;
322345fd 488
23b298bc 489 /* First dump UTF8 question */
202b76ae
ZJS
490 DNS_QUESTION_FOREACH(key, question_utf8)
491 log_debug("Looking up RR for %s.",
492 dns_resource_key_to_string(key, key_str, sizeof key_str));
23b298bc
LP
493
494 /* And then dump the IDNA question, but only what hasn't been dumped already through the UTF8 question. */
495 DNS_QUESTION_FOREACH(key, question_idna) {
23b298bc
LP
496 r = dns_question_contains(question_utf8, key);
497 if (r < 0)
498 return r;
499 if (r > 0)
500 continue;
501
202b76ae
ZJS
502 log_debug("Looking up IDNA RR for %s.",
503 dns_resource_key_to_string(key, key_str, sizeof key_str));
74b2466e
LP
504 }
505
506 LIST_PREPEND(queries, m->dns_queries, q);
39762fdf 507 m->n_dns_queries++;
74b2466e
LP
508 q->manager = m;
509
8ba9fd9c
LP
510 if (ret)
511 *ret = q;
512 q = NULL;
513
514 return 0;
515}
516
45ec7efb
LP
517int dns_query_make_auxiliary(DnsQuery *q, DnsQuery *auxiliary_for) {
518 assert(q);
519 assert(auxiliary_for);
520
61233823 521 /* Ensure that the query is not auxiliary yet, and
45ec7efb
LP
522 * nothing else is auxiliary to it either */
523 assert(!q->auxiliary_for);
524 assert(!q->auxiliary_queries);
525
526 /* Ensure that the unit we shall be made auxiliary for isn't
527 * auxiliary itself */
528 assert(!auxiliary_for->auxiliary_for);
529
530 if (auxiliary_for->n_auxiliary_queries >= AUXILIARY_QUERIES_MAX)
531 return -EAGAIN;
532
533 LIST_PREPEND(auxiliary_queries, auxiliary_for->auxiliary_queries, q);
534 q->auxiliary_for = auxiliary_for;
535
536 auxiliary_for->n_auxiliary_queries++;
537 return 0;
538}
539
ec2c5e43 540static void dns_query_complete(DnsQuery *q, DnsTransactionState state) {
8ba9fd9c 541 assert(q);
547973de
LP
542 assert(!DNS_TRANSACTION_IS_LIVE(state));
543 assert(DNS_TRANSACTION_IS_LIVE(q->state));
8ba9fd9c 544
322345fd
LP
545 /* Note that this call might invalidate the query. Callers
546 * should hence not attempt to access the query or transaction
547 * after calling this function. */
8ba9fd9c 548
8ba9fd9c
LP
549 q->state = state;
550
322345fd
LP
551 dns_query_stop(q);
552 if (q->complete)
553 q->complete(q);
8ba9fd9c
LP
554}
555
556static int on_query_timeout(sd_event_source *s, usec_t usec, void *userdata) {
557 DnsQuery *q = userdata;
558
559 assert(s);
560 assert(q);
561
ec2c5e43 562 dns_query_complete(q, DNS_TRANSACTION_TIMEOUT);
8ba9fd9c
LP
563 return 0;
564}
565
801ad6a6
LP
566static int dns_query_add_candidate(DnsQuery *q, DnsScope *s) {
567 DnsQueryCandidate *c;
faa133f3
LP
568 int r;
569
570 assert(q);
ec2c5e43 571 assert(s);
faa133f3 572
801ad6a6 573 r = dns_query_candidate_new(&c, q, s);
faa133f3
LP
574 if (r < 0)
575 return r;
576
801ad6a6 577 /* If this a single-label domain on DNS, we might append a suitable search domain first. */
22f711bb 578 if ((q->flags & SD_RESOLVED_NO_SEARCH) == 0) {
23b298bc 579 r = dns_scope_name_needs_search_domain(s, dns_question_first_name(q->question_idna));
22f711bb 580 if (r < 0)
801ad6a6 581 goto fail;
22f711bb
LP
582 if (r > 0) {
583 /* OK, we need a search domain now. Let's find one for this scope */
584
585 r = dns_query_candidate_next_search_domain(c);
586 if (r <= 0) /* if there's no search domain, then we won't add any transaction. */
587 goto fail;
588 }
faa133f3
LP
589 }
590
801ad6a6
LP
591 r = dns_query_candidate_setup_transactions(c);
592 if (r < 0)
593 goto fail;
594
faa133f3
LP
595 return 0;
596
801ad6a6
LP
597fail:
598 dns_query_candidate_free(c);
faa133f3
LP
599 return r;
600}
601
78c6a153 602static int dns_query_synthesize_reply(DnsQuery *q, DnsTransactionState *state) {
2a1037af 603 _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
dd0bc0f1 604 int r;
2a1037af
LP
605
606 assert(q);
607 assert(state);
608
dd0bc0f1
LP
609 /* Tries to synthesize localhost RR replies (and others) where appropriate. Note that this is done *after* the
610 * the normal lookup finished. The data from the network hence takes precedence over the data we
611 * synthesize. (But note that many scopes refuse to resolve certain domain names) */
2a1037af
LP
612
613 if (!IN_SET(*state,
3bbdc31d 614 DNS_TRANSACTION_RCODE_FAILURE,
2a1037af
LP
615 DNS_TRANSACTION_NO_SERVERS,
616 DNS_TRANSACTION_TIMEOUT,
edbcc1fd 617 DNS_TRANSACTION_ATTEMPTS_MAX_REACHED,
0791110f
LP
618 DNS_TRANSACTION_NETWORK_DOWN,
619 DNS_TRANSACTION_NOT_FOUND))
78c6a153 620 return 0;
2a1037af 621
839a4a20
LP
622 r = dns_synthesize_answer(
623 q->manager,
624 q->question_utf8,
625 q->ifindex,
dd0bc0f1 626 &answer);
acf06088
LP
627 if (r == -ENXIO) {
628 /* If we get ENXIO this tells us to generate NXDOMAIN unconditionally. */
2a1037af 629
acf06088
LP
630 dns_query_reset_answer(q);
631 q->answer_rcode = DNS_RCODE_NXDOMAIN;
632 q->answer_protocol = dns_synthesize_protocol(q->flags);
633 q->answer_family = dns_synthesize_family(q->flags);
634 q->answer_authenticated = true;
635 *state = DNS_TRANSACTION_RCODE_FAILURE;
636
637 return 0;
638 }
839a4a20
LP
639 if (r <= 0)
640 return r;
2a1037af 641
839a4a20 642 dns_query_reset_answer(q);
2a1037af 643
2a1037af
LP
644 q->answer = answer;
645 answer = NULL;
2a1037af 646 q->answer_rcode = DNS_RCODE_SUCCESS;
dd0bc0f1
LP
647 q->answer_protocol = dns_synthesize_protocol(q->flags);
648 q->answer_family = dns_synthesize_family(q->flags);
839a4a20 649 q->answer_authenticated = true;
2a1037af
LP
650
651 *state = DNS_TRANSACTION_SUCCESS;
78c6a153
LP
652
653 return 1;
2a1037af
LP
654}
655
dd0bc0f1
LP
656static int dns_query_try_etc_hosts(DnsQuery *q) {
657 _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
658 int r;
659
660 assert(q);
661
662 /* Looks in /etc/hosts for matching entries. Note that this is done *before* the normal lookup is done. The
663 * data from /etc/hosts hence takes precedence over the network. */
664
665 r = manager_etc_hosts_lookup(
666 q->manager,
667 q->question_utf8,
668 &answer);
669 if (r <= 0)
670 return r;
671
672 dns_query_reset_answer(q);
673
674 q->answer = answer;
675 answer = NULL;
676 q->answer_rcode = DNS_RCODE_SUCCESS;
677 q->answer_protocol = dns_synthesize_protocol(q->flags);
678 q->answer_family = dns_synthesize_family(q->flags);
679 q->answer_authenticated = true;
680
681 return 1;
682}
683
322345fd 684int dns_query_go(DnsQuery *q) {
8ba9fd9c
LP
685 DnsScopeMatch found = DNS_SCOPE_NO;
686 DnsScope *s, *first = NULL;
801ad6a6 687 DnsQueryCandidate *c;
8ba9fd9c
LP
688 int r;
689
690 assert(q);
691
ec2c5e43 692 if (q->state != DNS_TRANSACTION_NULL)
8ba9fd9c
LP
693 return 0;
694
dd0bc0f1
LP
695 r = dns_query_try_etc_hosts(q);
696 if (r < 0)
697 return r;
698 if (r > 0) {
699 dns_query_complete(q, DNS_TRANSACTION_SUCCESS);
700 return 1;
701 }
702
8ba9fd9c 703 LIST_FOREACH(scopes, s, q->manager->dns_scopes) {
74b2466e 704 DnsScopeMatch match;
23b298bc
LP
705 const char *name;
706
707 name = dns_question_first_name(dns_query_question_for_protocol(q, s->protocol));
708 if (!name)
709 continue;
74b2466e 710
51323288 711 match = dns_scope_good_domain(s, q->ifindex, q->flags, name);
74b2466e
LP
712 if (match < 0)
713 return match;
714
715 if (match == DNS_SCOPE_NO)
716 continue;
717
718 found = match;
719
720 if (match == DNS_SCOPE_YES) {
721 first = s;
722 break;
723 } else {
724 assert(match == DNS_SCOPE_MAYBE);
725
726 if (!first)
727 first = s;
728 }
729 }
730
2a1037af
LP
731 if (found == DNS_SCOPE_NO) {
732 DnsTransactionState state = DNS_TRANSACTION_NO_SERVERS;
733
7cc6ed7b
LP
734 r = dns_query_synthesize_reply(q, &state);
735 if (r < 0)
736 return r;
737
d634711b
LP
738 dns_query_complete(q, state);
739 return 1;
2a1037af 740 }
74b2466e 741
801ad6a6 742 r = dns_query_add_candidate(q, first);
74b2466e 743 if (r < 0)
ec2c5e43 744 goto fail;
74b2466e 745
74b2466e
LP
746 LIST_FOREACH(scopes, s, first->scopes_next) {
747 DnsScopeMatch match;
23b298bc
LP
748 const char *name;
749
750 name = dns_question_first_name(dns_query_question_for_protocol(q, s->protocol));
751 if (!name)
752 continue;
74b2466e 753
51323288 754 match = dns_scope_good_domain(s, q->ifindex, q->flags, name);
74b2466e 755 if (match < 0)
ec2c5e43 756 goto fail;
74b2466e
LP
757
758 if (match != found)
759 continue;
760
801ad6a6 761 r = dns_query_add_candidate(q, s);
74b2466e 762 if (r < 0)
ec2c5e43 763 goto fail;
74b2466e
LP
764 }
765
ab88b6d0 766 dns_query_reset_answer(q);
74b2466e 767
9a015429
LP
768 r = sd_event_add_time(
769 q->manager->event,
770 &q->timeout_event_source,
771 clock_boottime_or_monotonic(),
772 now(clock_boottime_or_monotonic()) + QUERY_TIMEOUT_USEC, 0,
773 on_query_timeout, q);
74b2466e
LP
774 if (r < 0)
775 goto fail;
776
aa4a9deb
LP
777 (void) sd_event_source_set_description(q->timeout_event_source, "query-timeout");
778
ec2c5e43 779 q->state = DNS_TRANSACTION_PENDING;
faa133f3 780 q->block_ready++;
74b2466e 781
801ad6a6
LP
782 /* Start the transactions */
783 LIST_FOREACH(candidates_by_query, c, q->candidates) {
784 r = dns_query_candidate_go(c);
785 if (r < 0) {
786 q->block_ready--;
ec2c5e43 787 goto fail;
801ad6a6 788 }
74b2466e
LP
789 }
790
faa133f3
LP
791 q->block_ready--;
792 dns_query_ready(q);
322345fd 793
8ba9fd9c 794 return 1;
74b2466e
LP
795
796fail:
8ba9fd9c 797 dns_query_stop(q);
74b2466e
LP
798 return r;
799}
800
801ad6a6 801static void dns_query_accept(DnsQuery *q, DnsQueryCandidate *c) {
ec2c5e43 802 DnsTransactionState state = DNS_TRANSACTION_NO_SERVERS;
547973de 803 bool has_authenticated = false, has_non_authenticated = false;
019036a4 804 DnssecResult dnssec_result_authenticated = _DNSSEC_RESULT_INVALID, dnssec_result_non_authenticated = _DNSSEC_RESULT_INVALID;
801ad6a6 805 DnsTransaction *t;
faa133f3 806 Iterator i;
547973de 807 int r;
74b2466e
LP
808
809 assert(q);
810
801ad6a6 811 if (!c) {
7cc6ed7b
LP
812 r = dns_query_synthesize_reply(q, &state);
813 if (r < 0)
814 goto fail;
815
801ad6a6 816 dns_query_complete(q, state);
74b2466e 817 return;
801ad6a6 818 }
74b2466e 819
a7bf2ada
LP
820 if (c->error_code != 0) {
821 /* If the candidate had an error condition of its own, start with that. */
822 state = DNS_TRANSACTION_ERRNO;
823 q->answer = dns_answer_unref(q->answer);
824 q->answer_rcode = 0;
825 q->answer_dnssec_result = _DNSSEC_RESULT_INVALID;
cbb1aabb 826 q->answer_authenticated = false;
a7bf2ada
LP
827 q->answer_errno = c->error_code;
828 }
829
801ad6a6 830 SET_FOREACH(t, c->transactions, i) {
74b2466e 831
801ad6a6 832 switch (t->state) {
934e9b10 833
801ad6a6 834 case DNS_TRANSACTION_SUCCESS: {
f8e2f4d6 835 /* We found a successfully reply, merge it into the answer */
547973de 836 r = dns_answer_extend(&q->answer, t->answer);
7cc6ed7b
LP
837 if (r < 0)
838 goto fail;
019036a4 839
ae6a4bbf 840 q->answer_rcode = t->answer_rcode;
7cc6ed7b 841 q->answer_errno = 0;
801ad6a6 842
019036a4 843 if (t->answer_authenticated) {
931851e8 844 has_authenticated = true;
019036a4
LP
845 dnssec_result_authenticated = t->answer_dnssec_result;
846 } else {
931851e8 847 has_non_authenticated = true;
019036a4
LP
848 dnssec_result_non_authenticated = t->answer_dnssec_result;
849 }
931851e8 850
801ad6a6
LP
851 state = DNS_TRANSACTION_SUCCESS;
852 break;
853 }
854
801ad6a6 855 case DNS_TRANSACTION_NULL:
547973de
LP
856 case DNS_TRANSACTION_PENDING:
857 case DNS_TRANSACTION_VALIDATING:
801ad6a6
LP
858 case DNS_TRANSACTION_ABORTED:
859 /* Ignore transactions that didn't complete */
860 continue;
861
862 default:
cbb1aabb 863 /* Any kind of failure? Store the data away, if there's nothing stored yet. */
019036a4
LP
864 if (state == DNS_TRANSACTION_SUCCESS)
865 continue;
934e9b10 866
cbb1aabb
LP
867 /* If there's already an authenticated negative reply stored, then prefer that over any unauthenticated one */
868 if (q->answer_authenticated && !t->answer_authenticated)
869 continue;
870
d38d5ca6 871 q->answer = dns_answer_unref(q->answer);
019036a4
LP
872 q->answer_rcode = t->answer_rcode;
873 q->answer_dnssec_result = t->answer_dnssec_result;
cbb1aabb 874 q->answer_authenticated = t->answer_authenticated;
7cc6ed7b 875 q->answer_errno = t->answer_errno;
934e9b10 876
019036a4 877 state = t->state;
801ad6a6 878 break;
74b2466e 879 }
801ad6a6 880 }
74b2466e 881
019036a4
LP
882 if (state == DNS_TRANSACTION_SUCCESS) {
883 q->answer_authenticated = has_authenticated && !has_non_authenticated;
884 q->answer_dnssec_result = q->answer_authenticated ? dnssec_result_authenticated : dnssec_result_non_authenticated;
885 }
886
801ad6a6
LP
887 q->answer_protocol = c->scope->protocol;
888 q->answer_family = c->scope->family;
934e9b10 889
801ad6a6
LP
890 dns_search_domain_unref(q->answer_search_domain);
891 q->answer_search_domain = dns_search_domain_ref(c->search_domain);
7e8e0422 892
7cc6ed7b
LP
893 r = dns_query_synthesize_reply(q, &state);
894 if (r < 0)
895 goto fail;
896
801ad6a6 897 dns_query_complete(q, state);
7cc6ed7b
LP
898 return;
899
900fail:
901 q->answer_errno = -r;
902 dns_query_complete(q, DNS_TRANSACTION_ERRNO);
801ad6a6 903}
934e9b10 904
801ad6a6 905void dns_query_ready(DnsQuery *q) {
74b2466e 906
801ad6a6
LP
907 DnsQueryCandidate *bad = NULL, *c;
908 bool pending = false;
74b2466e 909
801ad6a6 910 assert(q);
547973de 911 assert(DNS_TRANSACTION_IS_LIVE(q->state));
e4501ed4 912
801ad6a6
LP
913 /* Note that this call might invalidate the query. Callers
914 * should hence not attempt to access the query or transaction
915 * after calling this function, unless the block_ready
916 * counter was explicitly bumped before doing so. */
917
918 if (q->block_ready > 0)
919 return;
920
921 LIST_FOREACH(candidates_by_query, c, q->candidates) {
922 DnsTransactionState state;
923
924 state = dns_query_candidate_state(c);
925 switch (state) {
926
927 case DNS_TRANSACTION_SUCCESS:
547973de 928 /* One of the candidates is successful,
801ad6a6
LP
929 * let's use it, and copy its data out */
930 dns_query_accept(q, c);
e4501ed4
LP
931 return;
932
801ad6a6 933 case DNS_TRANSACTION_NULL:
547973de
LP
934 case DNS_TRANSACTION_PENDING:
935 case DNS_TRANSACTION_VALIDATING:
936 /* One of the candidates is still going on,
937 * let's maybe wait for it */
801ad6a6
LP
938 pending = true;
939 break;
e4501ed4 940
801ad6a6
LP
941 default:
942 /* Any kind of failure */
943 bad = c;
944 break;
945 }
faa133f3 946 }
74b2466e 947
801ad6a6
LP
948 if (pending)
949 return;
2a1037af 950
801ad6a6 951 dns_query_accept(q, bad);
74b2466e 952}
8ba9fd9c 953
45ec7efb 954static int dns_query_cname_redirect(DnsQuery *q, const DnsResourceRecord *cname) {
23b298bc
LP
955 _cleanup_(dns_question_unrefp) DnsQuestion *nq_idna = NULL, *nq_utf8 = NULL;
956 int r, k;
8ba9fd9c
LP
957
958 assert(q);
959
313cefa1 960 q->n_cname_redirects++;
faa133f3 961 if (q->n_cname_redirects > CNAME_MAX)
8ba9fd9c
LP
962 return -ELOOP;
963
23b298bc 964 r = dns_question_cname_redirect(q->question_idna, cname, &nq_idna);
faa133f3
LP
965 if (r < 0)
966 return r;
23b298bc 967 else if (r > 0)
8ec76e6a 968 log_debug("Following CNAME/DNAME %s → %s.", dns_question_first_name(q->question_idna), dns_question_first_name(nq_idna));
23b298bc
LP
969
970 k = dns_question_is_equal(q->question_idna, q->question_utf8);
971 if (k < 0)
972 return r;
973 if (k > 0) {
974 /* Same question? Shortcut new question generation */
975 nq_utf8 = dns_question_ref(nq_idna);
976 k = r;
977 } else {
978 k = dns_question_cname_redirect(q->question_utf8, cname, &nq_utf8);
979 if (k < 0)
980 return k;
981 else if (k > 0)
8ec76e6a 982 log_debug("Following UTF8 CNAME/DNAME %s → %s.", dns_question_first_name(q->question_utf8), dns_question_first_name(nq_utf8));
23b298bc 983 }
8ba9fd9c 984
23b298bc
LP
985 if (r == 0 && k == 0) /* No actual cname happened? */
986 return -ELOOP;
987
8e5de09f
LP
988 if (q->answer_protocol == DNS_PROTOCOL_DNS) {
989 /* Don't permit CNAME redirects from unicast DNS to LLMNR or MulticastDNS, so that global resources
990 * cannot invade the local namespace. The opposite way we permit: local names may redirect to global
991 * ones. */
992
993 q->flags &= ~(SD_RESOLVED_LLMNR|SD_RESOLVED_MDNS); /* mask away the local protocols */
994 }
995
996 /* Turn off searching for the new name */
997 q->flags |= SD_RESOLVED_NO_SEARCH;
998
23b298bc
LP
999 dns_question_unref(q->question_idna);
1000 q->question_idna = nq_idna;
1001 nq_idna = NULL;
bc7669cf 1002
23b298bc
LP
1003 dns_question_unref(q->question_utf8);
1004 q->question_utf8 = nq_utf8;
1005 nq_utf8 = NULL;
8ba9fd9c 1006
7820b320
LP
1007 dns_query_free_candidates(q);
1008 dns_query_reset_answer(q);
322345fd 1009
8e5de09f 1010 q->state = DNS_TRANSACTION_NULL;
59a89990 1011
8ba9fd9c
LP
1012 return 0;
1013}
82bd6ddd 1014
45ec7efb
LP
1015int dns_query_process_cname(DnsQuery *q) {
1016 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *cname = NULL;
23b298bc 1017 DnsQuestion *question;
45ec7efb
LP
1018 DnsResourceRecord *rr;
1019 int r;
1020
1021 assert(q);
1022
7588460a
TG
1023 if (!IN_SET(q->state, DNS_TRANSACTION_SUCCESS, DNS_TRANSACTION_NULL))
1024 return DNS_QUERY_NOMATCH;
45ec7efb 1025
23b298bc 1026 question = dns_query_question_for_protocol(q, q->answer_protocol);
45ec7efb 1027
23b298bc
LP
1028 DNS_ANSWER_FOREACH(rr, q->answer) {
1029 r = dns_question_matches_rr(question, rr, DNS_SEARCH_DOMAIN_NAME(q->answer_search_domain));
45ec7efb
LP
1030 if (r < 0)
1031 return r;
1032 if (r > 0)
7588460a 1033 return DNS_QUERY_MATCH; /* The answer matches directly, no need to follow cnames */
45ec7efb 1034
542e0c84 1035 r = dns_question_matches_cname_or_dname(question, rr, DNS_SEARCH_DOMAIN_NAME(q->answer_search_domain));
45ec7efb
LP
1036 if (r < 0)
1037 return r;
1038 if (r > 0 && !cname)
1039 cname = dns_resource_record_ref(rr);
1040 }
1041
1042 if (!cname)
7588460a 1043 return DNS_QUERY_NOMATCH; /* No match and no cname to follow */
45ec7efb
LP
1044
1045 if (q->flags & SD_RESOLVED_NO_CNAME)
1046 return -ELOOP;
1047
28830a64
LP
1048 if (!q->answer_authenticated)
1049 q->previous_redirect_unauthenticated = true;
1050
45ec7efb
LP
1051 /* OK, let's actually follow the CNAME */
1052 r = dns_query_cname_redirect(q, cname);
1053 if (r < 0)
1054 return r;
1055
1056 /* Let's see if the answer can already answer the new
1057 * redirected question */
7588460a
TG
1058 r = dns_query_process_cname(q);
1059 if (r != DNS_QUERY_NOMATCH)
1060 return r;
45ec7efb
LP
1061
1062 /* OK, it cannot, let's begin with the new query */
1063 r = dns_query_go(q);
1064 if (r < 0)
1065 return r;
1066
7588460a 1067 return DNS_QUERY_RESTARTED; /* We restarted the query for a new cname */
45ec7efb
LP
1068}
1069
82bd6ddd
LP
1070static int on_bus_track(sd_bus_track *t, void *userdata) {
1071 DnsQuery *q = userdata;
1072
1073 assert(t);
1074 assert(q);
1075
1076 log_debug("Client of active query vanished, aborting query.");
1077 dns_query_complete(q, DNS_TRANSACTION_ABORTED);
1078 return 0;
1079}
1080
966c66e3 1081int dns_query_bus_track(DnsQuery *q, sd_bus_message *m) {
82bd6ddd
LP
1082 int r;
1083
1084 assert(q);
1085 assert(m);
1086
1087 if (!q->bus_track) {
966c66e3 1088 r = sd_bus_track_new(sd_bus_message_get_bus(m), &q->bus_track, on_bus_track, q);
82bd6ddd
LP
1089 if (r < 0)
1090 return r;
1091 }
1092
1093 r = sd_bus_track_add_sender(q->bus_track, m);
1094 if (r < 0)
1095 return r;
1096
1097 return 0;
1098}
23b298bc
LP
1099
1100DnsQuestion* dns_query_question_for_protocol(DnsQuery *q, DnsProtocol protocol) {
1101 assert(q);
1102
1103 switch (protocol) {
1104
1105 case DNS_PROTOCOL_DNS:
1106 return q->question_idna;
1107
1108 case DNS_PROTOCOL_MDNS:
1109 case DNS_PROTOCOL_LLMNR:
1110 return q->question_utf8;
1111
1112 default:
1113 return NULL;
1114 }
1115}
1116
1117const char *dns_query_string(DnsQuery *q) {
1118 const char *name;
1119 int r;
1120
1121 /* Returns a somewhat useful human-readable lookup key string for this query */
1122
1123 if (q->request_address_string)
1124 return q->request_address_string;
1125
1126 if (q->request_address_valid) {
1127 r = in_addr_to_string(q->request_family, &q->request_address, &q->request_address_string);
1128 if (r >= 0)
1129 return q->request_address_string;
1130 }
1131
1132 name = dns_question_first_name(q->question_utf8);
1133 if (name)
1134 return name;
1135
1136 return dns_question_first_name(q->question_idna);
1137}
28830a64
LP
1138
1139bool dns_query_fully_authenticated(DnsQuery *q) {
1140 assert(q);
1141
1142 return q->answer_authenticated && !q->previous_redirect_unauthenticated;
1143}