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