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