]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/resolve/resolved-dns-query.c
Merge pull request #2269 from poettering/dnssec11
[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
105e1512 557 r = dns_answer_add(*answer, rr, SYNTHESIZE_IFINDEX(q->ifindex), DNS_ANSWER_AUTHENTICATED);
78c6a153
LP
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
105e1512 571 r = dns_answer_add(*answer, rr, SYNTHESIZE_IFINDEX(q->ifindex), DNS_ANSWER_AUTHENTICATED);
78c6a153
LP
572 if (r < 0)
573 return r;
574 }
575
576 return 0;
577}
578
105e1512 579static int answer_add_ptr(DnsAnswer **answer, const char *from, const char *to, int ifindex, DnsAnswerFlags flags) {
78c6a153
LP
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
105e1512 590 return dns_answer_add(*answer, rr, ifindex, flags);
78c6a153
LP
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
78c6a153 600 if (IN_SET(key->type, DNS_TYPE_PTR, DNS_TYPE_ANY)) {
105e1512
LP
601 r = dns_answer_reserve(answer, 1);
602 if (r < 0)
603 return r;
604
605 r = answer_add_ptr(answer, DNS_RESOURCE_KEY_NAME(key), "localhost", SYNTHESIZE_IFINDEX(q->ifindex), DNS_ANSWER_AUTHENTICATED);
78c6a153
LP
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
105e1512 636 r = dns_answer_add(*answer, rr, addresses[j].ifindex, DNS_ANSWER_AUTHENTICATED);
78c6a153
LP
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
105e1512 677 r = dns_answer_add(*answer, rr, addresses[j].ifindex, DNS_ANSWER_AUTHENTICATED);
78c6a153
LP
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
105e1512 743 r = answer_add_ptr(answer, "2.0.0.127.in-addr.arpa", q->manager->llmnr_hostname, SYNTHESIZE_IFINDEX(q->ifindex), DNS_ANSWER_AUTHENTICATED);
78c6a153
LP
744 if (r < 0)
745 return r;
746
105e1512 747 r = answer_add_ptr(answer, "2.0.0.127.in-addr.arpa", q->manager->mdns_hostname, SYNTHESIZE_IFINDEX(q->ifindex), DNS_ANSWER_AUTHENTICATED);
78c6a153
LP
748 if (r < 0)
749 return r;
750
105e1512 751 r = answer_add_ptr(answer, "2.0.0.127.in-addr.arpa", "localhost", SYNTHESIZE_IFINDEX(q->ifindex), DNS_ANSWER_AUTHENTICATED);
78c6a153
LP
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,
3bbdc31d 813 DNS_TRANSACTION_RCODE_FAILURE,
2a1037af
LP
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;
019036a4 989 DnssecResult dnssec_result_authenticated = _DNSSEC_RESULT_INVALID, dnssec_result_non_authenticated = _DNSSEC_RESULT_INVALID;
801ad6a6 990 DnsTransaction *t;
faa133f3 991 Iterator i;
547973de 992 int r;
74b2466e
LP
993
994 assert(q);
995
801ad6a6
LP
996 if (!c) {
997 dns_query_synthesize_reply(q, &state);
998 dns_query_complete(q, state);
74b2466e 999 return;
801ad6a6 1000 }
74b2466e 1001
801ad6a6 1002 SET_FOREACH(t, c->transactions, i) {
74b2466e 1003
801ad6a6 1004 switch (t->state) {
934e9b10 1005
801ad6a6
LP
1006 case DNS_TRANSACTION_SUCCESS: {
1007 /* We found a successfuly reply, merge it into the answer */
547973de
LP
1008 r = dns_answer_extend(&q->answer, t->answer);
1009 if (r < 0) {
801ad6a6
LP
1010 dns_query_complete(q, DNS_TRANSACTION_RESOURCES);
1011 return;
1012 }
019036a4 1013
ae6a4bbf 1014 q->answer_rcode = t->answer_rcode;
801ad6a6 1015
019036a4 1016 if (t->answer_authenticated) {
931851e8 1017 has_authenticated = true;
019036a4
LP
1018 dnssec_result_authenticated = t->answer_dnssec_result;
1019 } else {
931851e8 1020 has_non_authenticated = true;
019036a4
LP
1021 dnssec_result_non_authenticated = t->answer_dnssec_result;
1022 }
931851e8 1023
801ad6a6
LP
1024 state = DNS_TRANSACTION_SUCCESS;
1025 break;
1026 }
1027
801ad6a6 1028 case DNS_TRANSACTION_NULL:
547973de
LP
1029 case DNS_TRANSACTION_PENDING:
1030 case DNS_TRANSACTION_VALIDATING:
801ad6a6
LP
1031 case DNS_TRANSACTION_ABORTED:
1032 /* Ignore transactions that didn't complete */
1033 continue;
1034
1035 default:
1036 /* Any kind of failure? Store the data away,
1037 * if there's nothing stored yet. */
934e9b10 1038
019036a4
LP
1039 if (state == DNS_TRANSACTION_SUCCESS)
1040 continue;
934e9b10 1041
d38d5ca6 1042 q->answer = dns_answer_unref(q->answer);
019036a4
LP
1043 q->answer_rcode = t->answer_rcode;
1044 q->answer_dnssec_result = t->answer_dnssec_result;
934e9b10 1045
019036a4 1046 state = t->state;
801ad6a6 1047 break;
74b2466e 1048 }
801ad6a6 1049 }
74b2466e 1050
019036a4
LP
1051 if (state == DNS_TRANSACTION_SUCCESS) {
1052 q->answer_authenticated = has_authenticated && !has_non_authenticated;
1053 q->answer_dnssec_result = q->answer_authenticated ? dnssec_result_authenticated : dnssec_result_non_authenticated;
1054 }
1055
801ad6a6
LP
1056 q->answer_protocol = c->scope->protocol;
1057 q->answer_family = c->scope->family;
934e9b10 1058
801ad6a6
LP
1059 dns_search_domain_unref(q->answer_search_domain);
1060 q->answer_search_domain = dns_search_domain_ref(c->search_domain);
7e8e0422 1061
801ad6a6
LP
1062 dns_query_synthesize_reply(q, &state);
1063 dns_query_complete(q, state);
1064}
934e9b10 1065
801ad6a6 1066void dns_query_ready(DnsQuery *q) {
74b2466e 1067
801ad6a6
LP
1068 DnsQueryCandidate *bad = NULL, *c;
1069 bool pending = false;
74b2466e 1070
801ad6a6 1071 assert(q);
547973de 1072 assert(DNS_TRANSACTION_IS_LIVE(q->state));
e4501ed4 1073
801ad6a6
LP
1074 /* Note that this call might invalidate the query. Callers
1075 * should hence not attempt to access the query or transaction
1076 * after calling this function, unless the block_ready
1077 * counter was explicitly bumped before doing so. */
1078
1079 if (q->block_ready > 0)
1080 return;
1081
1082 LIST_FOREACH(candidates_by_query, c, q->candidates) {
1083 DnsTransactionState state;
1084
1085 state = dns_query_candidate_state(c);
1086 switch (state) {
1087
1088 case DNS_TRANSACTION_SUCCESS:
547973de 1089 /* One of the candidates is successful,
801ad6a6
LP
1090 * let's use it, and copy its data out */
1091 dns_query_accept(q, c);
e4501ed4
LP
1092 return;
1093
801ad6a6 1094 case DNS_TRANSACTION_NULL:
547973de
LP
1095 case DNS_TRANSACTION_PENDING:
1096 case DNS_TRANSACTION_VALIDATING:
1097 /* One of the candidates is still going on,
1098 * let's maybe wait for it */
801ad6a6
LP
1099 pending = true;
1100 break;
e4501ed4 1101
801ad6a6
LP
1102 default:
1103 /* Any kind of failure */
1104 bad = c;
1105 break;
1106 }
faa133f3 1107 }
74b2466e 1108
801ad6a6
LP
1109 if (pending)
1110 return;
2a1037af 1111
801ad6a6 1112 dns_query_accept(q, bad);
74b2466e 1113}
8ba9fd9c 1114
45ec7efb 1115static int dns_query_cname_redirect(DnsQuery *q, const DnsResourceRecord *cname) {
faa133f3
LP
1116 _cleanup_(dns_question_unrefp) DnsQuestion *nq = NULL;
1117 int r;
8ba9fd9c
LP
1118
1119 assert(q);
1120
48d5616b
LP
1121 log_debug("Following CNAME %s → %s", dns_question_first_name(q->question), cname->cname.name);
1122
45ec7efb 1123 q->n_cname_redirects ++;
faa133f3 1124 if (q->n_cname_redirects > CNAME_MAX)
8ba9fd9c
LP
1125 return -ELOOP;
1126
36d9205d 1127 r = dns_question_cname_redirect(q->question, cname, &nq);
faa133f3
LP
1128 if (r < 0)
1129 return r;
8ba9fd9c 1130
faa133f3
LP
1131 dns_question_unref(q->question);
1132 q->question = nq;
1133 nq = NULL;
8ba9fd9c 1134
322345fd 1135 dns_query_stop(q);
ec2c5e43 1136 q->state = DNS_TRANSACTION_NULL;
322345fd 1137
8ba9fd9c
LP
1138 return 0;
1139}
82bd6ddd 1140
45ec7efb
LP
1141int dns_query_process_cname(DnsQuery *q) {
1142 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *cname = NULL;
1143 DnsResourceRecord *rr;
1144 int r;
1145
1146 assert(q);
1147
1148 if (q->state != DNS_TRANSACTION_SUCCESS)
1149 return 0;
1150
1151 DNS_ANSWER_FOREACH(rr, q->answer) {
1152
801ad6a6 1153 r = dns_question_matches_rr(q->question, rr, DNS_SEARCH_DOMAIN_NAME(q->answer_search_domain));
45ec7efb
LP
1154 if (r < 0)
1155 return r;
1156 if (r > 0)
1157 return 0; /* The answer matches directly, no need to follow cnames */
1158
801ad6a6 1159 r = dns_question_matches_cname(q->question, rr, DNS_SEARCH_DOMAIN_NAME(q->answer_search_domain));
45ec7efb
LP
1160 if (r < 0)
1161 return r;
1162 if (r > 0 && !cname)
1163 cname = dns_resource_record_ref(rr);
1164 }
1165
1166 if (!cname)
1167 return 0; /* No cname to follow */
1168
1169 if (q->flags & SD_RESOLVED_NO_CNAME)
1170 return -ELOOP;
1171
1172 /* OK, let's actually follow the CNAME */
1173 r = dns_query_cname_redirect(q, cname);
1174 if (r < 0)
1175 return r;
1176
1177 /* Let's see if the answer can already answer the new
1178 * redirected question */
1179 DNS_ANSWER_FOREACH(rr, q->answer) {
801ad6a6 1180 r = dns_question_matches_rr(q->question, rr, NULL);
45ec7efb
LP
1181 if (r < 0)
1182 return r;
1183 if (r > 0)
1184 return 0; /* It can answer it, yay! */
1185 }
1186
1187 /* OK, it cannot, let's begin with the new query */
1188 r = dns_query_go(q);
1189 if (r < 0)
1190 return r;
1191
1192 return 1; /* We return > 0, if we restarted the query for a new cname */
1193}
1194
82bd6ddd
LP
1195static int on_bus_track(sd_bus_track *t, void *userdata) {
1196 DnsQuery *q = userdata;
1197
1198 assert(t);
1199 assert(q);
1200
1201 log_debug("Client of active query vanished, aborting query.");
1202 dns_query_complete(q, DNS_TRANSACTION_ABORTED);
1203 return 0;
1204}
1205
966c66e3 1206int dns_query_bus_track(DnsQuery *q, sd_bus_message *m) {
82bd6ddd
LP
1207 int r;
1208
1209 assert(q);
1210 assert(m);
1211
1212 if (!q->bus_track) {
966c66e3 1213 r = sd_bus_track_new(sd_bus_message_get_bus(m), &q->bus_track, on_bus_track, q);
82bd6ddd
LP
1214 if (r < 0)
1215 return r;
1216 }
1217
1218 r = sd_bus_track_add_sender(q->bus_track, m);
1219 if (r < 0)
1220 return r;
1221
1222 return 0;
1223}