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