]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/resolve/resolved-dns-query.c
resolved: handle properly if there are multiple transactions for the same key per...
[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"
b5efdb8a 24#include "hostname-util.h"
78c6a153 25#include "local-addresses.h"
74b2466e 26#include "resolved-dns-query.h"
74b2466e 27
0c903ae7 28/* How long to wait for the query in total */
74b2466e 29#define QUERY_TIMEOUT_USEC (30 * USEC_PER_SEC)
0c903ae7 30
8ba9fd9c 31#define CNAME_MAX 8
39762fdf 32#define QUERIES_MAX 2048
45ec7efb 33#define AUXILIARY_QUERIES_MAX 64
8ba9fd9c 34
801ad6a6
LP
35static int dns_query_candidate_new(DnsQueryCandidate **ret, DnsQuery *q, DnsScope *s) {
36 DnsQueryCandidate *c;
74b2466e 37
801ad6a6 38 assert(ret);
faa133f3 39 assert(q);
801ad6a6 40 assert(s);
74b2466e 41
801ad6a6
LP
42 c = new0(DnsQueryCandidate, 1);
43 if (!c)
44 return -ENOMEM;
45
46 c->query = q;
47 c->scope = s;
48
49 LIST_PREPEND(candidates_by_query, q->candidates, c);
50 LIST_PREPEND(candidates_by_scope, s->query_candidates, c);
51
52 *ret = c;
53 return 0;
54}
55
56static void dns_query_candidate_stop(DnsQueryCandidate *c) {
57 DnsTransaction *t;
74b2466e 58
801ad6a6
LP
59 assert(c);
60
61 while ((t = set_steal_first(c->transactions))) {
62 set_remove(t->query_candidates, c);
ec2c5e43 63 dns_transaction_gc(t);
74b2466e 64 }
74b2466e
LP
65}
66
801ad6a6
LP
67DnsQueryCandidate* dns_query_candidate_free(DnsQueryCandidate *c) {
68
69 if (!c)
70 return NULL;
71
72 dns_query_candidate_stop(c);
73
74 set_free(c->transactions);
75 dns_search_domain_unref(c->search_domain);
76
77 if (c->query)
78 LIST_REMOVE(candidates_by_query, c->query->candidates, c);
79
80 if (c->scope)
81 LIST_REMOVE(candidates_by_scope, c->scope->query_candidates, c);
82
83 free(c);
84
85 return NULL;
86}
87
88static int dns_query_candidate_next_search_domain(DnsQueryCandidate *c) {
89 _cleanup_(dns_search_domain_unrefp) DnsSearchDomain *previous = NULL;
90 DnsSearchDomain *next = NULL;
91
92 assert(c);
93
94 if (c->search_domain && c->search_domain->linked) {
95 next = c->search_domain->domains_next;
96
97 if (!next) {
98 /* We hit the last entry. Let's see if this
99 * was the per-link search domain list. If so,
100 * let's continue with the global one. */
101
102 if (c->search_domain->type == DNS_SEARCH_DOMAIN_LINK)
103 next = c->query->manager->search_domains;
104
105 if (!next) /* Still no item? Then we really hit the end of the list. */
106 return 0;
107 }
108
109 } else {
110 /* If we have, start with the per-link domains */
111 next = dns_scope_get_search_domains(c->scope);
112
113 if (!next) /* Fall back to the global search domains */
114 next = c->scope->manager->search_domains;
115
116 if (!next) /* OK, there's really nothing. */
117 return 0;
118 }
119
120 dns_search_domain_unref(c->search_domain);
121 c->search_domain = dns_search_domain_ref(next);
122 return 1;
123}
124
125static int dns_query_candidate_add_transaction(DnsQueryCandidate *c, DnsResourceKey *key) {
126 DnsTransaction *t;
127 int r;
128
129 assert(c);
130 assert(key);
131
132 r = set_ensure_allocated(&c->transactions, NULL);
133 if (r < 0)
134 return r;
135
136 t = dns_scope_find_transaction(c->scope, key, true);
137 if (!t) {
138 r = dns_transaction_new(&t, c->scope, key);
139 if (r < 0)
140 return r;
141 }
142
143 r = set_ensure_allocated(&t->query_candidates, NULL);
144 if (r < 0)
145 goto gc;
146
147 r = set_put(t->query_candidates, c);
148 if (r < 0)
149 goto gc;
150
151 r = set_put(c->transactions, t);
152 if (r < 0) {
153 set_remove(t->query_candidates, c);
154 goto gc;
155 }
156
157 return 0;
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;
168
169 assert(c);
170
171 /* Start the transactions that are not started yet */
172 SET_FOREACH(t, c->transactions, i) {
173 if (t->state != DNS_TRANSACTION_NULL)
174 continue;
175
176 r = dns_transaction_go(t);
177 if (r < 0)
178 return r;
179 }
180
181 return 0;
182}
183
184static DnsTransactionState dns_query_candidate_state(DnsQueryCandidate *c) {
185 DnsTransactionState state = DNS_TRANSACTION_NO_SERVERS;
186 DnsTransaction *t;
187 Iterator i;
188
189 assert(c);
190
191 if (c->error_code != 0)
192 return DNS_TRANSACTION_RESOURCES;
193
194 SET_FOREACH(t, c->transactions, i) {
195
196 switch (t->state) {
197
198 case DNS_TRANSACTION_PENDING:
199 case DNS_TRANSACTION_NULL:
200 return t->state;
201
202 case DNS_TRANSACTION_SUCCESS:
203 state = t->state;
204 break;
205
206 default:
207 if (state != DNS_TRANSACTION_SUCCESS)
208 state = t->state;
209
210 break;
211 }
212 }
213
214 return state;
215}
216
217static int dns_query_candidate_setup_transactions(DnsQueryCandidate *c) {
218 DnsResourceKey *key;
219 int n = 0, r;
220
221 assert(c);
222
223 dns_query_candidate_stop(c);
224
225 /* Create one transaction per question key */
226 DNS_QUESTION_FOREACH(key, c->query->question) {
227 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *new_key = NULL;
228
229 if (c->search_domain) {
230 r = dns_resource_key_new_append_suffix(&new_key, key, c->search_domain->name);
231 if (r < 0)
232 goto fail;
233 }
234
235 r = dns_query_candidate_add_transaction(c, new_key ?: key);
236 if (r < 0)
237 goto fail;
238
239 n++;
240 }
241
242 return n;
243
244fail:
245 dns_query_candidate_stop(c);
246 return r;
247}
248
249void dns_query_candidate_ready(DnsQueryCandidate *c) {
250 DnsTransactionState state;
251 int r;
252
253 assert(c);
254
255 state = dns_query_candidate_state(c);
256
257 if (IN_SET(state, DNS_TRANSACTION_PENDING, DNS_TRANSACTION_NULL))
258 return;
259
260 if (state != DNS_TRANSACTION_SUCCESS && c->search_domain) {
261
262 r = dns_query_candidate_next_search_domain(c);
263 if (r < 0)
264 goto fail;
265
266 if (r > 0) {
267 /* OK, there's another search domain to try, let's do so. */
268
269 r = dns_query_candidate_setup_transactions(c);
270 if (r < 0)
271 goto fail;
272
273 if (r > 0) {
274 /* New transactions where queued. Start them and wait */
275
276 r = dns_query_candidate_go(c);
277 if (r < 0)
278 goto fail;
279
280 return;
281 }
282 }
283
284 }
285
286 dns_query_ready(c->query);
287 return;
288
289fail:
290 log_warning_errno(r, "Failed to follow search domains: %m");
291 c->error_code = r;
292 dns_query_ready(c->query);
293}
294
295static void dns_query_stop(DnsQuery *q) {
296 DnsQueryCandidate *c;
297
298 assert(q);
299
300 q->timeout_event_source = sd_event_source_unref(q->timeout_event_source);
301
302 LIST_FOREACH(candidates_by_query, c, q->candidates)
303 dns_query_candidate_stop(c);
304}
305
74b2466e 306DnsQuery *dns_query_free(DnsQuery *q) {
74b2466e
LP
307 if (!q)
308 return NULL;
309
45ec7efb
LP
310 while (q->auxiliary_queries)
311 dns_query_free(q->auxiliary_queries);
312
313 if (q->auxiliary_for) {
314 assert(q->auxiliary_for->n_auxiliary_queries > 0);
315 q->auxiliary_for->n_auxiliary_queries--;
316 LIST_REMOVE(auxiliary_queries, q->auxiliary_for->auxiliary_queries, q);
317 }
318
801ad6a6
LP
319 while (q->candidates)
320 dns_query_candidate_free(q->candidates);
322345fd 321
faa133f3
LP
322 dns_question_unref(q->question);
323 dns_answer_unref(q->answer);
801ad6a6 324 dns_search_domain_unref(q->answer_search_domain);
322345fd 325
ec2c5e43 326 sd_bus_message_unref(q->request);
82bd6ddd 327 sd_bus_track_unref(q->bus_track);
74b2466e 328
39762fdf 329 if (q->manager) {
74b2466e 330 LIST_REMOVE(queries, q->manager->dns_queries, q);
39762fdf
LP
331 q->manager->n_dns_queries--;
332 }
74b2466e 333
74b2466e
LP
334 free(q);
335
336 return NULL;
337}
338
51323288 339int dns_query_new(Manager *m, DnsQuery **ret, DnsQuestion *question, int ifindex, uint64_t flags) {
74b2466e 340 _cleanup_(dns_query_freep) DnsQuery *q = NULL;
faa133f3
LP
341 unsigned i;
342 int r;
74b2466e
LP
343
344 assert(m);
faa133f3 345 assert(question);
74b2466e 346
703e4f5e 347 r = dns_question_is_valid_for_query(question);
faa133f3
LP
348 if (r < 0)
349 return r;
74b2466e 350
39762fdf
LP
351 if (m->n_dns_queries >= QUERIES_MAX)
352 return -EBUSY;
353
74b2466e
LP
354 q = new0(DnsQuery, 1);
355 if (!q)
356 return -ENOMEM;
357
faa133f3 358 q->question = dns_question_ref(question);
51323288
LP
359 q->ifindex = ifindex;
360 q->flags = flags;
801ad6a6
LP
361 q->answer_family = AF_UNSPEC;
362 q->answer_protocol = _DNS_PROTOCOL_INVALID;
322345fd 363
faa133f3 364 for (i = 0; i < question->n_keys; i++) {
e4501ed4
LP
365 _cleanup_free_ char *p;
366
367 r = dns_resource_key_to_string(question->keys[i], &p);
368 if (r < 0)
369 return r;
370
371 log_debug("Looking up RR for %s", p);
74b2466e
LP
372 }
373
374 LIST_PREPEND(queries, m->dns_queries, q);
39762fdf 375 m->n_dns_queries++;
74b2466e
LP
376 q->manager = m;
377
8ba9fd9c
LP
378 if (ret)
379 *ret = q;
380 q = NULL;
381
382 return 0;
383}
384
45ec7efb
LP
385int dns_query_make_auxiliary(DnsQuery *q, DnsQuery *auxiliary_for) {
386 assert(q);
387 assert(auxiliary_for);
388
389 /* Ensure that that the query is not auxiliary yet, and
390 * nothing else is auxiliary to it either */
391 assert(!q->auxiliary_for);
392 assert(!q->auxiliary_queries);
393
394 /* Ensure that the unit we shall be made auxiliary for isn't
395 * auxiliary itself */
396 assert(!auxiliary_for->auxiliary_for);
397
398 if (auxiliary_for->n_auxiliary_queries >= AUXILIARY_QUERIES_MAX)
399 return -EAGAIN;
400
401 LIST_PREPEND(auxiliary_queries, auxiliary_for->auxiliary_queries, q);
402 q->auxiliary_for = auxiliary_for;
403
404 auxiliary_for->n_auxiliary_queries++;
405 return 0;
406}
407
ec2c5e43 408static void dns_query_complete(DnsQuery *q, DnsTransactionState state) {
8ba9fd9c 409 assert(q);
ec2c5e43
LP
410 assert(!IN_SET(state, DNS_TRANSACTION_NULL, DNS_TRANSACTION_PENDING));
411 assert(IN_SET(q->state, DNS_TRANSACTION_NULL, DNS_TRANSACTION_PENDING));
8ba9fd9c 412
322345fd
LP
413 /* Note that this call might invalidate the query. Callers
414 * should hence not attempt to access the query or transaction
415 * after calling this function. */
8ba9fd9c 416
8ba9fd9c
LP
417 q->state = state;
418
322345fd
LP
419 dns_query_stop(q);
420 if (q->complete)
421 q->complete(q);
8ba9fd9c
LP
422}
423
424static int on_query_timeout(sd_event_source *s, usec_t usec, void *userdata) {
425 DnsQuery *q = userdata;
426
427 assert(s);
428 assert(q);
429
ec2c5e43 430 dns_query_complete(q, DNS_TRANSACTION_TIMEOUT);
8ba9fd9c
LP
431 return 0;
432}
433
801ad6a6
LP
434static int dns_query_add_candidate(DnsQuery *q, DnsScope *s) {
435 DnsQueryCandidate *c;
faa133f3
LP
436 int r;
437
438 assert(q);
ec2c5e43 439 assert(s);
faa133f3 440
801ad6a6 441 r = dns_query_candidate_new(&c, q, s);
faa133f3
LP
442 if (r < 0)
443 return r;
444
801ad6a6
LP
445 /* If this a single-label domain on DNS, we might append a suitable search domain first. */
446 r = dns_scope_name_needs_search_domain(s, dns_question_first_name(q->question));
faa133f3 447 if (r < 0)
801ad6a6
LP
448 goto fail;
449 if (r > 0) {
450 /* OK, we need a search domain now. Let's find one for this scope */
faa133f3 451
801ad6a6
LP
452 r = dns_query_candidate_next_search_domain(c);
453 if (r <= 0) /* if there's no search domain, then we won't add any transaction. */
454 goto fail;
faa133f3
LP
455 }
456
801ad6a6
LP
457 r = dns_query_candidate_setup_transactions(c);
458 if (r < 0)
459 goto fail;
460
faa133f3
LP
461 return 0;
462
801ad6a6
LP
463fail:
464 dns_query_candidate_free(c);
faa133f3
LP
465 return r;
466}
467
2a1037af
LP
468static int SYNTHESIZE_IFINDEX(int ifindex) {
469
78c6a153
LP
470 /* When the caller asked for resolving on a specific
471 * interface, we synthesize the answer for that
472 * interface. However, if nothing specific was claimed and we
473 * only return localhost RRs, we synthesize the answer for
2a1037af
LP
474 * localhost. */
475
476 if (ifindex > 0)
477 return ifindex;
478
479 return LOOPBACK_IFINDEX;
480}
481
482static int SYNTHESIZE_FAMILY(uint64_t flags) {
483
484 /* Picks an address family depending on set flags. This is
485 * purely for synthesized answers, where the family we return
486 * for the reply should match what was requested in the
487 * question, even though we are synthesizing the answer
488 * here. */
489
490 if (!(flags & SD_RESOLVED_DNS)) {
491 if (flags & SD_RESOLVED_LLMNR_IPV4)
492 return AF_INET;
493 if (flags & SD_RESOLVED_LLMNR_IPV6)
494 return AF_INET6;
495 }
496
497 return AF_UNSPEC;
498}
499
500static DnsProtocol SYNTHESIZE_PROTOCOL(uint64_t flags) {
501
502 /* Similar as SYNTHESIZE_FAMILY() but does this for the
503 * protocol. If resolving via DNS was requested, we claim it
504 * was DNS. Similar, if nothing specific was
505 * requested. However, if only resolving via LLMNR was
506 * requested we return that. */
507
508 if (flags & SD_RESOLVED_DNS)
509 return DNS_PROTOCOL_DNS;
510 if (flags & SD_RESOLVED_LLMNR)
511 return DNS_PROTOCOL_LLMNR;
512
513 return DNS_PROTOCOL_DNS;
514}
515
78c6a153
LP
516static int dns_type_to_af(uint16_t t) {
517 switch (t) {
518
519 case DNS_TYPE_A:
520 return AF_INET;
521
522 case DNS_TYPE_AAAA:
523 return AF_INET6;
524
525 case DNS_TYPE_ANY:
526 return AF_UNSPEC;
527
528 default:
529 return -EINVAL;
530 }
531}
532
533static int synthesize_localhost_rr(DnsQuery *q, DnsResourceKey *key, DnsAnswer **answer) {
534 int r;
535
536 assert(q);
537 assert(key);
538 assert(answer);
539
540 r = dns_answer_reserve(answer, 2);
541 if (r < 0)
542 return r;
543
544 if (IN_SET(key->type, DNS_TYPE_A, DNS_TYPE_ANY)) {
545 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
546
547 rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_A, DNS_RESOURCE_KEY_NAME(key));
548 if (!rr)
549 return -ENOMEM;
550
551 rr->a.in_addr.s_addr = htobe32(INADDR_LOOPBACK);
552
553 r = dns_answer_add(*answer, rr, SYNTHESIZE_IFINDEX(q->ifindex));
554 if (r < 0)
555 return r;
556 }
557
558 if (IN_SET(key->type, DNS_TYPE_AAAA, DNS_TYPE_ANY)) {
559 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
560
561 rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_AAAA, DNS_RESOURCE_KEY_NAME(key));
562 if (!rr)
563 return -ENOMEM;
564
565 rr->aaaa.in6_addr = in6addr_loopback;
566
567 r = dns_answer_add(*answer, rr, SYNTHESIZE_IFINDEX(q->ifindex));
568 if (r < 0)
569 return r;
570 }
571
572 return 0;
573}
574
575static int answer_add_ptr(DnsAnswer **answer, const char *from, const char *to, int ifindex) {
576 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
577
578 rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_PTR, from);
579 if (!rr)
580 return -ENOMEM;
581
582 rr->ptr.name = strdup(to);
583 if (!rr->ptr.name)
584 return -ENOMEM;
585
586 return dns_answer_add(*answer, rr, ifindex);
587}
588
589static int synthesize_localhost_ptr(DnsQuery *q, DnsResourceKey *key, DnsAnswer **answer) {
590 int r;
591
592 assert(q);
593 assert(key);
594 assert(answer);
595
596 r = dns_answer_reserve(answer, 1);
597 if (r < 0)
598 return r;
599
600 if (IN_SET(key->type, DNS_TYPE_PTR, DNS_TYPE_ANY)) {
601 r = answer_add_ptr(answer, DNS_RESOURCE_KEY_NAME(key), "localhost", SYNTHESIZE_IFINDEX(q->ifindex));
602 if (r < 0)
603 return r;
604 }
605
606 return 0;
607}
608
609static int answer_add_addresses_rr(
610 DnsAnswer **answer,
611 const char *name,
612 struct local_address *addresses,
613 unsigned n_addresses) {
614
615 unsigned j;
616 int r;
617
618 assert(answer);
619 assert(name);
620
621 r = dns_answer_reserve(answer, n_addresses);
622 if (r < 0)
623 return r;
624
625 for (j = 0; j < n_addresses; j++) {
626 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
627
628 r = dns_resource_record_new_address(&rr, addresses[j].family, &addresses[j].address, name);
629 if (r < 0)
630 return r;
631
632 r = dns_answer_add(*answer, rr, addresses[j].ifindex);
633 if (r < 0)
634 return r;
635 }
636
637 return 0;
638}
639
640static int answer_add_addresses_ptr(
641 DnsAnswer **answer,
642 const char *name,
643 struct local_address *addresses,
644 unsigned n_addresses,
645 int af, const union in_addr_union *match) {
646
647 unsigned j;
648 int r;
649
650 assert(answer);
651 assert(name);
652
653 for (j = 0; j < n_addresses; j++) {
654 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
655
656 if (af != AF_UNSPEC) {
657
658 if (addresses[j].family != af)
659 continue;
660
661 if (match && !in_addr_equal(af, match, &addresses[j].address))
662 continue;
663 }
664
665 r = dns_answer_reserve(answer, 1);
666 if (r < 0)
667 return r;
668
669 r = dns_resource_record_new_reverse(&rr, addresses[j].family, &addresses[j].address, name);
670 if (r < 0)
671 return r;
672
673 r = dns_answer_add(*answer, rr, addresses[j].ifindex);
674 if (r < 0)
675 return r;
676 }
677
678 return 0;
679}
680
681static int synthesize_system_hostname_rr(DnsQuery *q, DnsResourceKey *key, DnsAnswer **answer) {
682 _cleanup_free_ struct local_address *addresses = NULL;
683 int n = 0, af;
684
685 assert(q);
686 assert(key);
687 assert(answer);
688
689 af = dns_type_to_af(key->type);
690 if (af >= 0) {
691 n = local_addresses(q->manager->rtnl, q->ifindex, af, &addresses);
692 if (n < 0)
693 return n;
694
695 if (n == 0) {
696 struct local_address buffer[2];
697
698 /* If we have no local addresses then use ::1
699 * and 127.0.0.2 as local ones. */
700
701 if (af == AF_INET || af == AF_UNSPEC)
702 buffer[n++] = (struct local_address) {
703 .family = AF_INET,
704 .ifindex = SYNTHESIZE_IFINDEX(q->ifindex),
705 .address.in.s_addr = htobe32(0x7F000002),
706 };
707
708 if (af == AF_INET6 || af == AF_UNSPEC)
709 buffer[n++] = (struct local_address) {
710 .family = AF_INET6,
711 .ifindex = SYNTHESIZE_IFINDEX(q->ifindex),
712 .address.in6 = in6addr_loopback,
713 };
714
715 return answer_add_addresses_rr(answer, DNS_RESOURCE_KEY_NAME(key), buffer, n);
716 }
717 }
718
719 return answer_add_addresses_rr(answer, DNS_RESOURCE_KEY_NAME(key), addresses, n);
720}
721
722static int synthesize_system_hostname_ptr(DnsQuery *q, int af, const union in_addr_union *address, DnsAnswer **answer) {
723 _cleanup_free_ struct local_address *addresses = NULL;
724 int n, r;
725
726 assert(q);
727 assert(address);
728 assert(answer);
729
730 if (af == AF_INET && address->in.s_addr == htobe32(0x7F000002)) {
731
732 /* Always map the IPv4 address 127.0.0.2 to the local
733 * hostname, in addition to "localhost": */
734
735 r = dns_answer_reserve(answer, 3);
736 if (r < 0)
737 return r;
738
739 r = answer_add_ptr(answer, "2.0.0.127.in-addr.arpa", q->manager->llmnr_hostname, SYNTHESIZE_IFINDEX(q->ifindex));
740 if (r < 0)
741 return r;
742
743 r = answer_add_ptr(answer, "2.0.0.127.in-addr.arpa", q->manager->mdns_hostname, SYNTHESIZE_IFINDEX(q->ifindex));
744 if (r < 0)
745 return r;
746
747 r = answer_add_ptr(answer, "2.0.0.127.in-addr.arpa", "localhost", SYNTHESIZE_IFINDEX(q->ifindex));
748 if (r < 0)
749 return r;
750
751 return 0;
752 }
753
754 n = local_addresses(q->manager->rtnl, q->ifindex, af, &addresses);
755 if (n < 0)
756 return n;
757
758 r = answer_add_addresses_ptr(answer, q->manager->llmnr_hostname, addresses, n, af, address);
759 if (r < 0)
760 return r;
761
762 return answer_add_addresses_ptr(answer, q->manager->mdns_hostname, addresses, n, af, address);
763}
764
765static int synthesize_gateway_rr(DnsQuery *q, DnsResourceKey *key, DnsAnswer **answer) {
766 _cleanup_free_ struct local_address *addresses = NULL;
767 int n = 0, af;
768
769 assert(q);
770 assert(key);
771 assert(answer);
772
773 af = dns_type_to_af(key->type);
774 if (af >= 0) {
775 n = local_gateways(q->manager->rtnl, q->ifindex, af, &addresses);
776 if (n < 0)
777 return n;
778 }
779
780 return answer_add_addresses_rr(answer, DNS_RESOURCE_KEY_NAME(key), addresses, n);
781}
782
783static int synthesize_gateway_ptr(DnsQuery *q, int af, const union in_addr_union *address, DnsAnswer **answer) {
784 _cleanup_free_ struct local_address *addresses = NULL;
785 int n;
786
787 assert(q);
788 assert(address);
789 assert(answer);
790
791 n = local_gateways(q->manager->rtnl, q->ifindex, af, &addresses);
792 if (n < 0)
793 return n;
794
795 return answer_add_addresses_ptr(answer, "gateway", addresses, n, af, address);
796}
797
798static int dns_query_synthesize_reply(DnsQuery *q, DnsTransactionState *state) {
2a1037af
LP
799 _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
800 unsigned i;
801 int r;
802
803 assert(q);
804 assert(state);
805
806 /* Tries to synthesize localhost RR replies where appropriate */
807
808 if (!IN_SET(*state,
809 DNS_TRANSACTION_FAILURE,
810 DNS_TRANSACTION_NO_SERVERS,
811 DNS_TRANSACTION_TIMEOUT,
812 DNS_TRANSACTION_ATTEMPTS_MAX_REACHED))
78c6a153 813 return 0;
2a1037af
LP
814
815 for (i = 0; i < q->question->n_keys; i++) {
78c6a153 816 union in_addr_union address;
2a1037af 817 const char *name;
78c6a153 818 int af;
2a1037af
LP
819
820 if (q->question->keys[i]->class != DNS_CLASS_IN &&
821 q->question->keys[i]->class != DNS_CLASS_ANY)
822 continue;
823
824 name = DNS_RESOURCE_KEY_NAME(q->question->keys[i]);
825
826 if (is_localhost(name)) {
827
78c6a153
LP
828 r = synthesize_localhost_rr(q, q->question->keys[i], &answer);
829 if (r < 0)
830 return log_error_errno(r, "Failed to synthesize localhost RRs: %m");
2a1037af 831
78c6a153 832 } else if (manager_is_own_hostname(q->manager, name)) {
2a1037af 833
78c6a153
LP
834 r = synthesize_system_hostname_rr(q, q->question->keys[i], &answer);
835 if (r < 0)
836 return log_error_errno(r, "Failed to synthesize system hostname RRs: %m");
2a1037af 837
78c6a153 838 } else if (is_gateway_hostname(name)) {
2a1037af 839
78c6a153
LP
840 r = synthesize_gateway_rr(q, q->question->keys[i], &answer);
841 if (r < 0)
842 return log_error_errno(r, "Failed to synthesize gateway RRs: %m");
2a1037af 843
78c6a153
LP
844 } else if ((dns_name_endswith(name, "127.in-addr.arpa") > 0 && dns_name_equal(name, "2.0.0.127.in-addr.arpa") == 0) ||
845 dns_name_equal(name, "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa") > 0) {
2a1037af 846
78c6a153
LP
847 r = synthesize_localhost_ptr(q, q->question->keys[i], &answer);
848 if (r < 0)
849 return log_error_errno(r, "Failed to synthesize localhost PTR RRs: %m");
2a1037af 850
78c6a153 851 } else if (dns_name_address(name, &af, &address) > 0) {
2a1037af 852
78c6a153
LP
853 r = synthesize_system_hostname_ptr(q, af, &address, &answer);
854 if (r < 0)
855 return log_error_errno(r, "Failed to synthesize system hostname PTR RR: %m");
2a1037af 856
78c6a153
LP
857 r = synthesize_gateway_ptr(q, af, &address, &answer);
858 if (r < 0)
859 return log_error_errno(r, "Failed to synthesize gateway hostname PTR RR: %m");
2a1037af
LP
860 }
861 }
862
863 if (!answer)
78c6a153 864 return 0;
2a1037af
LP
865
866 dns_answer_unref(q->answer);
867 q->answer = answer;
868 answer = NULL;
869
2a1037af 870 q->answer_rcode = DNS_RCODE_SUCCESS;
801ad6a6
LP
871 q->answer_protocol = SYNTHESIZE_PROTOCOL(q->flags);
872 q->answer_family = SYNTHESIZE_FAMILY(q->flags);
2a1037af
LP
873
874 *state = DNS_TRANSACTION_SUCCESS;
78c6a153
LP
875
876 return 1;
2a1037af
LP
877}
878
322345fd 879int dns_query_go(DnsQuery *q) {
8ba9fd9c
LP
880 DnsScopeMatch found = DNS_SCOPE_NO;
881 DnsScope *s, *first = NULL;
801ad6a6 882 DnsQueryCandidate *c;
faa133f3 883 const char *name;
8ba9fd9c
LP
884 int r;
885
886 assert(q);
887
ec2c5e43 888 if (q->state != DNS_TRANSACTION_NULL)
8ba9fd9c
LP
889 return 0;
890
faa133f3
LP
891 assert(q->question);
892 assert(q->question->n_keys > 0);
893
703e4f5e 894 name = dns_question_first_name(q->question);
8ba9fd9c
LP
895
896 LIST_FOREACH(scopes, s, q->manager->dns_scopes) {
74b2466e
LP
897 DnsScopeMatch match;
898
51323288 899 match = dns_scope_good_domain(s, q->ifindex, q->flags, name);
74b2466e
LP
900 if (match < 0)
901 return match;
902
903 if (match == DNS_SCOPE_NO)
904 continue;
905
906 found = match;
907
908 if (match == DNS_SCOPE_YES) {
909 first = s;
910 break;
911 } else {
912 assert(match == DNS_SCOPE_MAYBE);
913
914 if (!first)
915 first = s;
916 }
917 }
918
2a1037af
LP
919 if (found == DNS_SCOPE_NO) {
920 DnsTransactionState state = DNS_TRANSACTION_NO_SERVERS;
921
922 dns_query_synthesize_reply(q, &state);
d634711b
LP
923 dns_query_complete(q, state);
924 return 1;
2a1037af 925 }
74b2466e 926
801ad6a6 927 r = dns_query_add_candidate(q, first);
74b2466e 928 if (r < 0)
ec2c5e43 929 goto fail;
74b2466e 930
74b2466e
LP
931 LIST_FOREACH(scopes, s, first->scopes_next) {
932 DnsScopeMatch match;
933
51323288 934 match = dns_scope_good_domain(s, q->ifindex, q->flags, name);
74b2466e 935 if (match < 0)
ec2c5e43 936 goto fail;
74b2466e
LP
937
938 if (match != found)
939 continue;
940
801ad6a6 941 r = dns_query_add_candidate(q, s);
74b2466e 942 if (r < 0)
ec2c5e43 943 goto fail;
74b2466e
LP
944 }
945
faa133f3 946 q->answer = dns_answer_unref(q->answer);
faa133f3 947 q->answer_rcode = 0;
51323288
LP
948 q->answer_family = AF_UNSPEC;
949 q->answer_protocol = _DNS_PROTOCOL_INVALID;
74b2466e 950
9a015429
LP
951 r = sd_event_add_time(
952 q->manager->event,
953 &q->timeout_event_source,
954 clock_boottime_or_monotonic(),
955 now(clock_boottime_or_monotonic()) + QUERY_TIMEOUT_USEC, 0,
956 on_query_timeout, q);
74b2466e
LP
957 if (r < 0)
958 goto fail;
959
ec2c5e43 960 q->state = DNS_TRANSACTION_PENDING;
faa133f3 961 q->block_ready++;
74b2466e 962
801ad6a6
LP
963 /* Start the transactions */
964 LIST_FOREACH(candidates_by_query, c, q->candidates) {
965 r = dns_query_candidate_go(c);
966 if (r < 0) {
967 q->block_ready--;
ec2c5e43 968 goto fail;
801ad6a6 969 }
74b2466e
LP
970 }
971
faa133f3
LP
972 q->block_ready--;
973 dns_query_ready(q);
322345fd 974
8ba9fd9c 975 return 1;
74b2466e
LP
976
977fail:
8ba9fd9c 978 dns_query_stop(q);
74b2466e
LP
979 return r;
980}
981
801ad6a6 982static void dns_query_accept(DnsQuery *q, DnsQueryCandidate *c) {
ec2c5e43 983 DnsTransactionState state = DNS_TRANSACTION_NO_SERVERS;
801ad6a6 984 DnsTransaction *t;
faa133f3 985 Iterator i;
74b2466e
LP
986
987 assert(q);
988
801ad6a6
LP
989 if (!c) {
990 dns_query_synthesize_reply(q, &state);
991 dns_query_complete(q, state);
74b2466e 992 return;
801ad6a6 993 }
74b2466e 994
801ad6a6 995 SET_FOREACH(t, c->transactions, i) {
74b2466e 996
801ad6a6 997 switch (t->state) {
934e9b10 998
801ad6a6
LP
999 case DNS_TRANSACTION_SUCCESS: {
1000 /* We found a successfuly reply, merge it into the answer */
ae6a4bbf 1001 DnsAnswer *merged;
322345fd 1002
ae6a4bbf 1003 merged = dns_answer_merge(q->answer, t->answer);
801ad6a6
LP
1004 if (!merged) {
1005 dns_query_complete(q, DNS_TRANSACTION_RESOURCES);
1006 return;
1007 }
1008
1009 dns_answer_unref(q->answer);
1010 q->answer = merged;
ae6a4bbf 1011 q->answer_rcode = t->answer_rcode;
801ad6a6
LP
1012
1013 state = DNS_TRANSACTION_SUCCESS;
1014 break;
1015 }
1016
1017 case DNS_TRANSACTION_PENDING:
1018 case DNS_TRANSACTION_NULL:
1019 case DNS_TRANSACTION_ABORTED:
1020 /* Ignore transactions that didn't complete */
1021 continue;
1022
1023 default:
1024 /* Any kind of failure? Store the data away,
1025 * if there's nothing stored yet. */
934e9b10 1026
801ad6a6
LP
1027 if (state != DNS_TRANSACTION_SUCCESS) {
1028
1029 dns_answer_unref(q->answer);
ae6a4bbf
LP
1030 q->answer = dns_answer_ref(t->answer);
1031 q->answer_rcode = t->answer_rcode;
934e9b10 1032
801ad6a6 1033 state = t->state;
934e9b10
LP
1034 }
1035
801ad6a6 1036 break;
74b2466e 1037 }
801ad6a6 1038 }
74b2466e 1039
801ad6a6
LP
1040 q->answer_protocol = c->scope->protocol;
1041 q->answer_family = c->scope->family;
934e9b10 1042
801ad6a6
LP
1043 dns_search_domain_unref(q->answer_search_domain);
1044 q->answer_search_domain = dns_search_domain_ref(c->search_domain);
7e8e0422 1045
801ad6a6
LP
1046 dns_query_synthesize_reply(q, &state);
1047 dns_query_complete(q, state);
1048}
934e9b10 1049
801ad6a6 1050void dns_query_ready(DnsQuery *q) {
74b2466e 1051
801ad6a6
LP
1052 DnsQueryCandidate *bad = NULL, *c;
1053 bool pending = false;
74b2466e 1054
801ad6a6
LP
1055 assert(q);
1056 assert(IN_SET(q->state, DNS_TRANSACTION_NULL, DNS_TRANSACTION_PENDING));
e4501ed4 1057
801ad6a6
LP
1058 /* Note that this call might invalidate the query. Callers
1059 * should hence not attempt to access the query or transaction
1060 * after calling this function, unless the block_ready
1061 * counter was explicitly bumped before doing so. */
1062
1063 if (q->block_ready > 0)
1064 return;
1065
1066 LIST_FOREACH(candidates_by_query, c, q->candidates) {
1067 DnsTransactionState state;
1068
1069 state = dns_query_candidate_state(c);
1070 switch (state) {
1071
1072 case DNS_TRANSACTION_SUCCESS:
1073 /* One of the transactions is successful,
1074 * let's use it, and copy its data out */
1075 dns_query_accept(q, c);
e4501ed4
LP
1076 return;
1077
801ad6a6
LP
1078 case DNS_TRANSACTION_PENDING:
1079 case DNS_TRANSACTION_NULL:
1080 /* One of the transactions is still going on, let's maybe wait for it */
1081 pending = true;
1082 break;
e4501ed4 1083
801ad6a6
LP
1084 default:
1085 /* Any kind of failure */
1086 bad = c;
1087 break;
1088 }
faa133f3 1089 }
74b2466e 1090
801ad6a6
LP
1091 if (pending)
1092 return;
2a1037af 1093
801ad6a6 1094 dns_query_accept(q, bad);
74b2466e 1095}
8ba9fd9c 1096
45ec7efb 1097static int dns_query_cname_redirect(DnsQuery *q, const DnsResourceRecord *cname) {
faa133f3
LP
1098 _cleanup_(dns_question_unrefp) DnsQuestion *nq = NULL;
1099 int r;
8ba9fd9c
LP
1100
1101 assert(q);
1102
45ec7efb 1103 q->n_cname_redirects ++;
faa133f3 1104 if (q->n_cname_redirects > CNAME_MAX)
8ba9fd9c
LP
1105 return -ELOOP;
1106
36d9205d 1107 r = dns_question_cname_redirect(q->question, cname, &nq);
faa133f3
LP
1108 if (r < 0)
1109 return r;
8ba9fd9c 1110
faa133f3
LP
1111 dns_question_unref(q->question);
1112 q->question = nq;
1113 nq = NULL;
8ba9fd9c 1114
322345fd 1115 dns_query_stop(q);
ec2c5e43 1116 q->state = DNS_TRANSACTION_NULL;
322345fd 1117
8ba9fd9c
LP
1118 return 0;
1119}
82bd6ddd 1120
45ec7efb
LP
1121int dns_query_process_cname(DnsQuery *q) {
1122 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *cname = NULL;
1123 DnsResourceRecord *rr;
1124 int r;
1125
1126 assert(q);
1127
1128 if (q->state != DNS_TRANSACTION_SUCCESS)
1129 return 0;
1130
1131 DNS_ANSWER_FOREACH(rr, q->answer) {
1132
801ad6a6 1133 r = dns_question_matches_rr(q->question, rr, DNS_SEARCH_DOMAIN_NAME(q->answer_search_domain));
45ec7efb
LP
1134 if (r < 0)
1135 return r;
1136 if (r > 0)
1137 return 0; /* The answer matches directly, no need to follow cnames */
1138
801ad6a6 1139 r = dns_question_matches_cname(q->question, rr, DNS_SEARCH_DOMAIN_NAME(q->answer_search_domain));
45ec7efb
LP
1140 if (r < 0)
1141 return r;
1142 if (r > 0 && !cname)
1143 cname = dns_resource_record_ref(rr);
1144 }
1145
1146 if (!cname)
1147 return 0; /* No cname to follow */
1148
1149 if (q->flags & SD_RESOLVED_NO_CNAME)
1150 return -ELOOP;
1151
1152 /* OK, let's actually follow the CNAME */
1153 r = dns_query_cname_redirect(q, cname);
1154 if (r < 0)
1155 return r;
1156
1157 /* Let's see if the answer can already answer the new
1158 * redirected question */
1159 DNS_ANSWER_FOREACH(rr, q->answer) {
801ad6a6 1160 r = dns_question_matches_rr(q->question, rr, NULL);
45ec7efb
LP
1161 if (r < 0)
1162 return r;
1163 if (r > 0)
1164 return 0; /* It can answer it, yay! */
1165 }
1166
1167 /* OK, it cannot, let's begin with the new query */
1168 r = dns_query_go(q);
1169 if (r < 0)
1170 return r;
1171
1172 return 1; /* We return > 0, if we restarted the query for a new cname */
1173}
1174
82bd6ddd
LP
1175static int on_bus_track(sd_bus_track *t, void *userdata) {
1176 DnsQuery *q = userdata;
1177
1178 assert(t);
1179 assert(q);
1180
1181 log_debug("Client of active query vanished, aborting query.");
1182 dns_query_complete(q, DNS_TRANSACTION_ABORTED);
1183 return 0;
1184}
1185
966c66e3 1186int dns_query_bus_track(DnsQuery *q, sd_bus_message *m) {
82bd6ddd
LP
1187 int r;
1188
1189 assert(q);
1190 assert(m);
1191
1192 if (!q->bus_track) {
966c66e3 1193 r = sd_bus_track_new(sd_bus_message_get_bus(m), &q->bus_track, on_bus_track, q);
82bd6ddd
LP
1194 if (r < 0)
1195 return r;
1196 }
1197
1198 r = sd_bus_track_add_sender(q->bus_track, m);
1199 if (r < 0)
1200 return r;
1201
1202 return 0;
1203}