]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/resolve/resolved-dns-query.c
resolved: fix minor memory leak when shuttin down
[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
8ba9fd9c 33
ec2c5e43
LP
34static void dns_query_stop(DnsQuery *q) {
35 DnsTransaction *t;
74b2466e 36
faa133f3 37 assert(q);
74b2466e 38
ec2c5e43 39 q->timeout_event_source = sd_event_source_unref(q->timeout_event_source);
74b2466e 40
ec2c5e43
LP
41 while ((t = set_steal_first(q->transactions))) {
42 set_remove(t->queries, q);
43 dns_transaction_gc(t);
74b2466e 44 }
74b2466e
LP
45}
46
47DnsQuery *dns_query_free(DnsQuery *q) {
74b2466e
LP
48 if (!q)
49 return NULL;
50
ec2c5e43
LP
51 dns_query_stop(q);
52 set_free(q->transactions);
322345fd 53
faa133f3
LP
54 dns_question_unref(q->question);
55 dns_answer_unref(q->answer);
322345fd 56
ec2c5e43 57 sd_bus_message_unref(q->request);
82bd6ddd 58 sd_bus_track_unref(q->bus_track);
74b2466e 59
39762fdf 60 if (q->manager) {
74b2466e 61 LIST_REMOVE(queries, q->manager->dns_queries, q);
39762fdf
LP
62 q->manager->n_dns_queries--;
63 }
74b2466e 64
74b2466e
LP
65 free(q);
66
67 return NULL;
68}
69
51323288 70int dns_query_new(Manager *m, DnsQuery **ret, DnsQuestion *question, int ifindex, uint64_t flags) {
74b2466e 71 _cleanup_(dns_query_freep) DnsQuery *q = NULL;
faa133f3
LP
72 unsigned i;
73 int r;
74b2466e
LP
74
75 assert(m);
faa133f3 76 assert(question);
74b2466e 77
faa133f3
LP
78 r = dns_question_is_valid(question);
79 if (r < 0)
80 return r;
74b2466e 81
39762fdf
LP
82 if (m->n_dns_queries >= QUERIES_MAX)
83 return -EBUSY;
84
74b2466e
LP
85 q = new0(DnsQuery, 1);
86 if (!q)
87 return -ENOMEM;
88
faa133f3 89 q->question = dns_question_ref(question);
51323288
LP
90 q->ifindex = ifindex;
91 q->flags = flags;
322345fd 92
faa133f3 93 for (i = 0; i < question->n_keys; i++) {
e4501ed4
LP
94 _cleanup_free_ char *p;
95
96 r = dns_resource_key_to_string(question->keys[i], &p);
97 if (r < 0)
98 return r;
99
100 log_debug("Looking up RR for %s", p);
74b2466e
LP
101 }
102
103 LIST_PREPEND(queries, m->dns_queries, q);
39762fdf 104 m->n_dns_queries++;
74b2466e
LP
105 q->manager = m;
106
8ba9fd9c
LP
107 if (ret)
108 *ret = q;
109 q = NULL;
110
111 return 0;
112}
113
ec2c5e43 114static void dns_query_complete(DnsQuery *q, DnsTransactionState state) {
8ba9fd9c 115 assert(q);
ec2c5e43
LP
116 assert(!IN_SET(state, DNS_TRANSACTION_NULL, DNS_TRANSACTION_PENDING));
117 assert(IN_SET(q->state, DNS_TRANSACTION_NULL, DNS_TRANSACTION_PENDING));
8ba9fd9c 118
322345fd
LP
119 /* Note that this call might invalidate the query. Callers
120 * should hence not attempt to access the query or transaction
121 * after calling this function. */
8ba9fd9c 122
8ba9fd9c
LP
123 q->state = state;
124
322345fd
LP
125 dns_query_stop(q);
126 if (q->complete)
127 q->complete(q);
8ba9fd9c
LP
128}
129
130static int on_query_timeout(sd_event_source *s, usec_t usec, void *userdata) {
131 DnsQuery *q = userdata;
132
133 assert(s);
134 assert(q);
135
ec2c5e43 136 dns_query_complete(q, DNS_TRANSACTION_TIMEOUT);
8ba9fd9c
LP
137 return 0;
138}
139
934e9b10 140static int dns_query_add_transaction(DnsQuery *q, DnsScope *s, DnsResourceKey *key) {
ec2c5e43 141 DnsTransaction *t;
faa133f3
LP
142 int r;
143
144 assert(q);
ec2c5e43 145 assert(s);
26b1c471 146 assert(key);
faa133f3 147
d5099efc 148 r = set_ensure_allocated(&q->transactions, NULL);
faa133f3
LP
149 if (r < 0)
150 return r;
151
f52e61da 152 t = dns_scope_find_transaction(s, key, true);
faa133f3 153 if (!t) {
f52e61da 154 r = dns_transaction_new(&t, s, key);
faa133f3
LP
155 if (r < 0)
156 return r;
157 }
158
d5099efc 159 r = set_ensure_allocated(&t->queries, NULL);
faa133f3 160 if (r < 0)
ec2c5e43 161 goto gc;
faa133f3
LP
162
163 r = set_put(t->queries, q);
164 if (r < 0)
ec2c5e43 165 goto gc;
faa133f3
LP
166
167 r = set_put(q->transactions, t);
168 if (r < 0) {
169 set_remove(t->queries, q);
ec2c5e43 170 goto gc;
faa133f3
LP
171 }
172
173 return 0;
174
ec2c5e43
LP
175gc:
176 dns_transaction_gc(t);
faa133f3
LP
177 return r;
178}
179
934e9b10 180static int dns_query_add_transaction_split(DnsQuery *q, DnsScope *s) {
26b1c471 181 unsigned i;
934e9b10
LP
182 int r;
183
184 assert(q);
185 assert(s);
186
26b1c471
LP
187 /* Create one transaction per question key */
188
189 for (i = 0; i < q->question->n_keys; i++) {
190 r = dns_query_add_transaction(q, s, q->question->keys[i]);
934e9b10
LP
191 if (r < 0)
192 return r;
934e9b10
LP
193 }
194
195 return 0;
196}
197
2a1037af
LP
198static int SYNTHESIZE_IFINDEX(int ifindex) {
199
78c6a153
LP
200 /* When the caller asked for resolving on a specific
201 * interface, we synthesize the answer for that
202 * interface. However, if nothing specific was claimed and we
203 * only return localhost RRs, we synthesize the answer for
2a1037af
LP
204 * localhost. */
205
206 if (ifindex > 0)
207 return ifindex;
208
209 return LOOPBACK_IFINDEX;
210}
211
212static int SYNTHESIZE_FAMILY(uint64_t flags) {
213
214 /* Picks an address family depending on set flags. This is
215 * purely for synthesized answers, where the family we return
216 * for the reply should match what was requested in the
217 * question, even though we are synthesizing the answer
218 * here. */
219
220 if (!(flags & SD_RESOLVED_DNS)) {
221 if (flags & SD_RESOLVED_LLMNR_IPV4)
222 return AF_INET;
223 if (flags & SD_RESOLVED_LLMNR_IPV6)
224 return AF_INET6;
225 }
226
227 return AF_UNSPEC;
228}
229
230static DnsProtocol SYNTHESIZE_PROTOCOL(uint64_t flags) {
231
232 /* Similar as SYNTHESIZE_FAMILY() but does this for the
233 * protocol. If resolving via DNS was requested, we claim it
234 * was DNS. Similar, if nothing specific was
235 * requested. However, if only resolving via LLMNR was
236 * requested we return that. */
237
238 if (flags & SD_RESOLVED_DNS)
239 return DNS_PROTOCOL_DNS;
240 if (flags & SD_RESOLVED_LLMNR)
241 return DNS_PROTOCOL_LLMNR;
242
243 return DNS_PROTOCOL_DNS;
244}
245
78c6a153
LP
246static int dns_type_to_af(uint16_t t) {
247 switch (t) {
248
249 case DNS_TYPE_A:
250 return AF_INET;
251
252 case DNS_TYPE_AAAA:
253 return AF_INET6;
254
255 case DNS_TYPE_ANY:
256 return AF_UNSPEC;
257
258 default:
259 return -EINVAL;
260 }
261}
262
263static int synthesize_localhost_rr(DnsQuery *q, DnsResourceKey *key, DnsAnswer **answer) {
264 int r;
265
266 assert(q);
267 assert(key);
268 assert(answer);
269
270 r = dns_answer_reserve(answer, 2);
271 if (r < 0)
272 return r;
273
274 if (IN_SET(key->type, DNS_TYPE_A, DNS_TYPE_ANY)) {
275 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
276
277 rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_A, DNS_RESOURCE_KEY_NAME(key));
278 if (!rr)
279 return -ENOMEM;
280
281 rr->a.in_addr.s_addr = htobe32(INADDR_LOOPBACK);
282
283 r = dns_answer_add(*answer, rr, SYNTHESIZE_IFINDEX(q->ifindex));
284 if (r < 0)
285 return r;
286 }
287
288 if (IN_SET(key->type, DNS_TYPE_AAAA, DNS_TYPE_ANY)) {
289 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
290
291 rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_AAAA, DNS_RESOURCE_KEY_NAME(key));
292 if (!rr)
293 return -ENOMEM;
294
295 rr->aaaa.in6_addr = in6addr_loopback;
296
297 r = dns_answer_add(*answer, rr, SYNTHESIZE_IFINDEX(q->ifindex));
298 if (r < 0)
299 return r;
300 }
301
302 return 0;
303}
304
305static int answer_add_ptr(DnsAnswer **answer, const char *from, const char *to, int ifindex) {
306 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
307
308 rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_PTR, from);
309 if (!rr)
310 return -ENOMEM;
311
312 rr->ptr.name = strdup(to);
313 if (!rr->ptr.name)
314 return -ENOMEM;
315
316 return dns_answer_add(*answer, rr, ifindex);
317}
318
319static int synthesize_localhost_ptr(DnsQuery *q, DnsResourceKey *key, DnsAnswer **answer) {
320 int r;
321
322 assert(q);
323 assert(key);
324 assert(answer);
325
326 r = dns_answer_reserve(answer, 1);
327 if (r < 0)
328 return r;
329
330 if (IN_SET(key->type, DNS_TYPE_PTR, DNS_TYPE_ANY)) {
331 r = answer_add_ptr(answer, DNS_RESOURCE_KEY_NAME(key), "localhost", SYNTHESIZE_IFINDEX(q->ifindex));
332 if (r < 0)
333 return r;
334 }
335
336 return 0;
337}
338
339static int answer_add_addresses_rr(
340 DnsAnswer **answer,
341 const char *name,
342 struct local_address *addresses,
343 unsigned n_addresses) {
344
345 unsigned j;
346 int r;
347
348 assert(answer);
349 assert(name);
350
351 r = dns_answer_reserve(answer, n_addresses);
352 if (r < 0)
353 return r;
354
355 for (j = 0; j < n_addresses; j++) {
356 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
357
358 r = dns_resource_record_new_address(&rr, addresses[j].family, &addresses[j].address, name);
359 if (r < 0)
360 return r;
361
362 r = dns_answer_add(*answer, rr, addresses[j].ifindex);
363 if (r < 0)
364 return r;
365 }
366
367 return 0;
368}
369
370static int answer_add_addresses_ptr(
371 DnsAnswer **answer,
372 const char *name,
373 struct local_address *addresses,
374 unsigned n_addresses,
375 int af, const union in_addr_union *match) {
376
377 unsigned j;
378 int r;
379
380 assert(answer);
381 assert(name);
382
383 for (j = 0; j < n_addresses; j++) {
384 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
385
386 if (af != AF_UNSPEC) {
387
388 if (addresses[j].family != af)
389 continue;
390
391 if (match && !in_addr_equal(af, match, &addresses[j].address))
392 continue;
393 }
394
395 r = dns_answer_reserve(answer, 1);
396 if (r < 0)
397 return r;
398
399 r = dns_resource_record_new_reverse(&rr, addresses[j].family, &addresses[j].address, name);
400 if (r < 0)
401 return r;
402
403 r = dns_answer_add(*answer, rr, addresses[j].ifindex);
404 if (r < 0)
405 return r;
406 }
407
408 return 0;
409}
410
411static int synthesize_system_hostname_rr(DnsQuery *q, DnsResourceKey *key, DnsAnswer **answer) {
412 _cleanup_free_ struct local_address *addresses = NULL;
413 int n = 0, af;
414
415 assert(q);
416 assert(key);
417 assert(answer);
418
419 af = dns_type_to_af(key->type);
420 if (af >= 0) {
421 n = local_addresses(q->manager->rtnl, q->ifindex, af, &addresses);
422 if (n < 0)
423 return n;
424
425 if (n == 0) {
426 struct local_address buffer[2];
427
428 /* If we have no local addresses then use ::1
429 * and 127.0.0.2 as local ones. */
430
431 if (af == AF_INET || af == AF_UNSPEC)
432 buffer[n++] = (struct local_address) {
433 .family = AF_INET,
434 .ifindex = SYNTHESIZE_IFINDEX(q->ifindex),
435 .address.in.s_addr = htobe32(0x7F000002),
436 };
437
438 if (af == AF_INET6 || af == AF_UNSPEC)
439 buffer[n++] = (struct local_address) {
440 .family = AF_INET6,
441 .ifindex = SYNTHESIZE_IFINDEX(q->ifindex),
442 .address.in6 = in6addr_loopback,
443 };
444
445 return answer_add_addresses_rr(answer, DNS_RESOURCE_KEY_NAME(key), buffer, n);
446 }
447 }
448
449 return answer_add_addresses_rr(answer, DNS_RESOURCE_KEY_NAME(key), addresses, n);
450}
451
452static int synthesize_system_hostname_ptr(DnsQuery *q, int af, const union in_addr_union *address, DnsAnswer **answer) {
453 _cleanup_free_ struct local_address *addresses = NULL;
454 int n, r;
455
456 assert(q);
457 assert(address);
458 assert(answer);
459
460 if (af == AF_INET && address->in.s_addr == htobe32(0x7F000002)) {
461
462 /* Always map the IPv4 address 127.0.0.2 to the local
463 * hostname, in addition to "localhost": */
464
465 r = dns_answer_reserve(answer, 3);
466 if (r < 0)
467 return r;
468
469 r = answer_add_ptr(answer, "2.0.0.127.in-addr.arpa", q->manager->llmnr_hostname, SYNTHESIZE_IFINDEX(q->ifindex));
470 if (r < 0)
471 return r;
472
473 r = answer_add_ptr(answer, "2.0.0.127.in-addr.arpa", q->manager->mdns_hostname, SYNTHESIZE_IFINDEX(q->ifindex));
474 if (r < 0)
475 return r;
476
477 r = answer_add_ptr(answer, "2.0.0.127.in-addr.arpa", "localhost", SYNTHESIZE_IFINDEX(q->ifindex));
478 if (r < 0)
479 return r;
480
481 return 0;
482 }
483
484 n = local_addresses(q->manager->rtnl, q->ifindex, af, &addresses);
485 if (n < 0)
486 return n;
487
488 r = answer_add_addresses_ptr(answer, q->manager->llmnr_hostname, addresses, n, af, address);
489 if (r < 0)
490 return r;
491
492 return answer_add_addresses_ptr(answer, q->manager->mdns_hostname, addresses, n, af, address);
493}
494
495static int synthesize_gateway_rr(DnsQuery *q, DnsResourceKey *key, DnsAnswer **answer) {
496 _cleanup_free_ struct local_address *addresses = NULL;
497 int n = 0, af;
498
499 assert(q);
500 assert(key);
501 assert(answer);
502
503 af = dns_type_to_af(key->type);
504 if (af >= 0) {
505 n = local_gateways(q->manager->rtnl, q->ifindex, af, &addresses);
506 if (n < 0)
507 return n;
508 }
509
510 return answer_add_addresses_rr(answer, DNS_RESOURCE_KEY_NAME(key), addresses, n);
511}
512
513static int synthesize_gateway_ptr(DnsQuery *q, int af, const union in_addr_union *address, DnsAnswer **answer) {
514 _cleanup_free_ struct local_address *addresses = NULL;
515 int n;
516
517 assert(q);
518 assert(address);
519 assert(answer);
520
521 n = local_gateways(q->manager->rtnl, q->ifindex, af, &addresses);
522 if (n < 0)
523 return n;
524
525 return answer_add_addresses_ptr(answer, "gateway", addresses, n, af, address);
526}
527
528static int dns_query_synthesize_reply(DnsQuery *q, DnsTransactionState *state) {
2a1037af
LP
529 _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
530 unsigned i;
531 int r;
532
533 assert(q);
534 assert(state);
535
536 /* Tries to synthesize localhost RR replies where appropriate */
537
538 if (!IN_SET(*state,
539 DNS_TRANSACTION_FAILURE,
540 DNS_TRANSACTION_NO_SERVERS,
541 DNS_TRANSACTION_TIMEOUT,
542 DNS_TRANSACTION_ATTEMPTS_MAX_REACHED))
78c6a153 543 return 0;
2a1037af
LP
544
545 for (i = 0; i < q->question->n_keys; i++) {
78c6a153 546 union in_addr_union address;
2a1037af 547 const char *name;
78c6a153 548 int af;
2a1037af
LP
549
550 if (q->question->keys[i]->class != DNS_CLASS_IN &&
551 q->question->keys[i]->class != DNS_CLASS_ANY)
552 continue;
553
554 name = DNS_RESOURCE_KEY_NAME(q->question->keys[i]);
555
556 if (is_localhost(name)) {
557
78c6a153
LP
558 r = synthesize_localhost_rr(q, q->question->keys[i], &answer);
559 if (r < 0)
560 return log_error_errno(r, "Failed to synthesize localhost RRs: %m");
2a1037af 561
78c6a153 562 } else if (manager_is_own_hostname(q->manager, name)) {
2a1037af 563
78c6a153
LP
564 r = synthesize_system_hostname_rr(q, q->question->keys[i], &answer);
565 if (r < 0)
566 return log_error_errno(r, "Failed to synthesize system hostname RRs: %m");
2a1037af 567
78c6a153 568 } else if (is_gateway_hostname(name)) {
2a1037af 569
78c6a153
LP
570 r = synthesize_gateway_rr(q, q->question->keys[i], &answer);
571 if (r < 0)
572 return log_error_errno(r, "Failed to synthesize gateway RRs: %m");
2a1037af 573
78c6a153
LP
574 } else if ((dns_name_endswith(name, "127.in-addr.arpa") > 0 && dns_name_equal(name, "2.0.0.127.in-addr.arpa") == 0) ||
575 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 576
78c6a153
LP
577 r = synthesize_localhost_ptr(q, q->question->keys[i], &answer);
578 if (r < 0)
579 return log_error_errno(r, "Failed to synthesize localhost PTR RRs: %m");
2a1037af 580
78c6a153 581 } else if (dns_name_address(name, &af, &address) > 0) {
2a1037af 582
78c6a153
LP
583 r = synthesize_system_hostname_ptr(q, af, &address, &answer);
584 if (r < 0)
585 return log_error_errno(r, "Failed to synthesize system hostname PTR RR: %m");
2a1037af 586
78c6a153
LP
587 r = synthesize_gateway_ptr(q, af, &address, &answer);
588 if (r < 0)
589 return log_error_errno(r, "Failed to synthesize gateway hostname PTR RR: %m");
2a1037af
LP
590 }
591 }
592
593 if (!answer)
78c6a153 594 return 0;
2a1037af
LP
595
596 dns_answer_unref(q->answer);
597 q->answer = answer;
598 answer = NULL;
599
2a1037af
LP
600 q->answer_family = SYNTHESIZE_FAMILY(q->flags);
601 q->answer_protocol = SYNTHESIZE_PROTOCOL(q->flags);
602 q->answer_rcode = DNS_RCODE_SUCCESS;
603
604 *state = DNS_TRANSACTION_SUCCESS;
78c6a153
LP
605
606 return 1;
2a1037af
LP
607}
608
322345fd 609int dns_query_go(DnsQuery *q) {
8ba9fd9c
LP
610 DnsScopeMatch found = DNS_SCOPE_NO;
611 DnsScope *s, *first = NULL;
ec2c5e43 612 DnsTransaction *t;
faa133f3
LP
613 const char *name;
614 Iterator i;
8ba9fd9c
LP
615 int r;
616
617 assert(q);
618
ec2c5e43 619 if (q->state != DNS_TRANSACTION_NULL)
8ba9fd9c
LP
620 return 0;
621
faa133f3
LP
622 assert(q->question);
623 assert(q->question->n_keys > 0);
624
625 name = DNS_RESOURCE_KEY_NAME(q->question->keys[0]);
8ba9fd9c
LP
626
627 LIST_FOREACH(scopes, s, q->manager->dns_scopes) {
74b2466e
LP
628 DnsScopeMatch match;
629
51323288 630 match = dns_scope_good_domain(s, q->ifindex, q->flags, name);
74b2466e
LP
631 if (match < 0)
632 return match;
633
634 if (match == DNS_SCOPE_NO)
635 continue;
636
637 found = match;
638
639 if (match == DNS_SCOPE_YES) {
640 first = s;
641 break;
642 } else {
643 assert(match == DNS_SCOPE_MAYBE);
644
645 if (!first)
646 first = s;
647 }
648 }
649
2a1037af
LP
650 if (found == DNS_SCOPE_NO) {
651 DnsTransactionState state = DNS_TRANSACTION_NO_SERVERS;
652
653 dns_query_synthesize_reply(q, &state);
d634711b
LP
654 dns_query_complete(q, state);
655 return 1;
2a1037af 656 }
74b2466e 657
934e9b10 658 r = dns_query_add_transaction_split(q, first);
74b2466e 659 if (r < 0)
ec2c5e43 660 goto fail;
74b2466e 661
74b2466e
LP
662 LIST_FOREACH(scopes, s, first->scopes_next) {
663 DnsScopeMatch match;
664
51323288 665 match = dns_scope_good_domain(s, q->ifindex, q->flags, name);
74b2466e 666 if (match < 0)
ec2c5e43 667 goto fail;
74b2466e
LP
668
669 if (match != found)
670 continue;
671
934e9b10 672 r = dns_query_add_transaction_split(q, s);
74b2466e 673 if (r < 0)
ec2c5e43 674 goto fail;
74b2466e
LP
675 }
676
faa133f3 677 q->answer = dns_answer_unref(q->answer);
faa133f3 678 q->answer_rcode = 0;
51323288
LP
679 q->answer_family = AF_UNSPEC;
680 q->answer_protocol = _DNS_PROTOCOL_INVALID;
74b2466e 681
9a015429
LP
682 r = sd_event_add_time(
683 q->manager->event,
684 &q->timeout_event_source,
685 clock_boottime_or_monotonic(),
686 now(clock_boottime_or_monotonic()) + QUERY_TIMEOUT_USEC, 0,
687 on_query_timeout, q);
74b2466e
LP
688 if (r < 0)
689 goto fail;
690
ec2c5e43 691 q->state = DNS_TRANSACTION_PENDING;
faa133f3 692 q->block_ready++;
74b2466e 693
ec2c5e43 694 /* Start the transactions that are not started yet */
faa133f3 695 SET_FOREACH(t, q->transactions, i) {
ec2c5e43
LP
696 if (t->state != DNS_TRANSACTION_NULL)
697 continue;
698
699 r = dns_transaction_go(t);
700 if (r < 0)
701 goto fail;
74b2466e
LP
702 }
703
faa133f3
LP
704 q->block_ready--;
705 dns_query_ready(q);
322345fd 706
8ba9fd9c 707 return 1;
74b2466e
LP
708
709fail:
8ba9fd9c 710 dns_query_stop(q);
74b2466e
LP
711 return r;
712}
713
faa133f3 714void dns_query_ready(DnsQuery *q) {
ec2c5e43
LP
715 DnsTransaction *t;
716 DnsTransactionState state = DNS_TRANSACTION_NO_SERVERS;
934e9b10
LP
717 _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
718 int rcode = 0;
719 DnsScope *scope = NULL;
e4501ed4 720 bool pending = false;
faa133f3 721 Iterator i;
74b2466e
LP
722
723 assert(q);
ec2c5e43 724 assert(IN_SET(q->state, DNS_TRANSACTION_NULL, DNS_TRANSACTION_PENDING));
74b2466e 725
322345fd
LP
726 /* Note that this call might invalidate the query. Callers
727 * should hence not attempt to access the query or transaction
faa133f3 728 * after calling this function, unless the block_ready
322345fd
LP
729 * counter was explicitly bumped before doing so. */
730
faa133f3 731 if (q->block_ready > 0)
74b2466e
LP
732 return;
733
faa133f3 734 SET_FOREACH(t, q->transactions, i) {
74b2466e 735
934e9b10 736 /* If we found a successful answer, ignore all answers from other scopes */
ec2c5e43 737 if (state == DNS_TRANSACTION_SUCCESS && t->scope != scope)
934e9b10
LP
738 continue;
739
e4501ed4 740 /* One of the transactions is still going on, let's maybe wait for it */
ec2c5e43 741 if (IN_SET(t->state, DNS_TRANSACTION_PENDING, DNS_TRANSACTION_NULL)) {
e4501ed4
LP
742 pending = true;
743 continue;
744 }
74b2466e 745
322345fd
LP
746 /* One of the transactions is successful, let's use
747 * it, and copy its data out */
ec2c5e43 748 if (t->state == DNS_TRANSACTION_SUCCESS) {
934e9b10
LP
749 DnsAnswer *a;
750
faa133f3 751 if (t->received) {
934e9b10
LP
752 rcode = DNS_PACKET_RCODE(t->received);
753 a = t->received->answer;
faa133f3 754 } else {
934e9b10
LP
755 rcode = t->cached_rcode;
756 a = t->cached;
faa133f3 757 }
322345fd 758
ec2c5e43 759 if (state == DNS_TRANSACTION_SUCCESS) {
934e9b10
LP
760 DnsAnswer *merged;
761
762 merged = dns_answer_merge(answer, a);
763 if (!merged) {
ec2c5e43 764 dns_query_complete(q, DNS_TRANSACTION_RESOURCES);
934e9b10
LP
765 return;
766 }
767
768 dns_answer_unref(answer);
769 answer = merged;
770 } else {
771 dns_answer_unref(answer);
772 answer = dns_answer_ref(a);
773 }
774
775 scope = t->scope;
ec2c5e43 776 state = DNS_TRANSACTION_SUCCESS;
934e9b10 777 continue;
74b2466e
LP
778 }
779
ad867662
LP
780 /* One of the transactions has failed, let's see
781 * whether we find anything better, but if not, return
934e9b10 782 * its response data */
ec2c5e43 783 if (state != DNS_TRANSACTION_SUCCESS && t->state == DNS_TRANSACTION_FAILURE) {
934e9b10
LP
784 DnsAnswer *a;
785
7e8e0422 786 if (t->received) {
934e9b10
LP
787 rcode = DNS_PACKET_RCODE(t->received);
788 a = t->received->answer;
7e8e0422 789 } else {
934e9b10
LP
790 rcode = t->cached_rcode;
791 a = t->cached;
7e8e0422
LP
792 }
793
934e9b10
LP
794 dns_answer_unref(answer);
795 answer = dns_answer_ref(a);
796
797 scope = t->scope;
ec2c5e43 798 state = DNS_TRANSACTION_FAILURE;
ad867662
LP
799 continue;
800 }
74b2466e 801
ec2c5e43 802 if (state == DNS_TRANSACTION_NO_SERVERS && t->state != DNS_TRANSACTION_NO_SERVERS)
74b2466e
LP
803 state = t->state;
804 }
805
e4501ed4
LP
806 if (pending) {
807
808 /* If so far we weren't successful, and there's
809 * something still pending, then wait for it */
ec2c5e43 810 if (state != DNS_TRANSACTION_SUCCESS)
e4501ed4
LP
811 return;
812
813 /* If we already were successful, then only wait for
814 * other transactions on the same scope to finish. */
815 SET_FOREACH(t, q->transactions, i) {
ec2c5e43 816 if (t->scope == scope && IN_SET(t->state, DNS_TRANSACTION_PENDING, DNS_TRANSACTION_NULL))
e4501ed4
LP
817 return;
818 }
819 }
820
ec2c5e43 821 if (IN_SET(state, DNS_TRANSACTION_SUCCESS, DNS_TRANSACTION_FAILURE)) {
934e9b10
LP
822 q->answer = dns_answer_ref(answer);
823 q->answer_rcode = rcode;
51323288
LP
824 q->answer_protocol = scope ? scope->protocol : _DNS_PROTOCOL_INVALID;
825 q->answer_family = scope ? scope->family : AF_UNSPEC;
faa133f3 826 }
74b2466e 827
2a1037af
LP
828 /* Try to synthesize a reply if we couldn't resolve something. */
829 dns_query_synthesize_reply(q, &state);
830
322345fd 831 dns_query_complete(q, state);
74b2466e 832}
8ba9fd9c 833
36d9205d 834int dns_query_cname_redirect(DnsQuery *q, const DnsResourceRecord *cname) {
faa133f3
LP
835 _cleanup_(dns_question_unrefp) DnsQuestion *nq = NULL;
836 int r;
8ba9fd9c
LP
837
838 assert(q);
839
faa133f3 840 if (q->n_cname_redirects > CNAME_MAX)
8ba9fd9c
LP
841 return -ELOOP;
842
36d9205d 843 r = dns_question_cname_redirect(q->question, cname, &nq);
faa133f3
LP
844 if (r < 0)
845 return r;
8ba9fd9c 846
faa133f3
LP
847 dns_question_unref(q->question);
848 q->question = nq;
849 nq = NULL;
8ba9fd9c 850
faa133f3 851 q->n_cname_redirects++;
8ba9fd9c 852
322345fd 853 dns_query_stop(q);
ec2c5e43 854 q->state = DNS_TRANSACTION_NULL;
322345fd 855
8ba9fd9c
LP
856 return 0;
857}
82bd6ddd
LP
858
859static int on_bus_track(sd_bus_track *t, void *userdata) {
860 DnsQuery *q = userdata;
861
862 assert(t);
863 assert(q);
864
865 log_debug("Client of active query vanished, aborting query.");
866 dns_query_complete(q, DNS_TRANSACTION_ABORTED);
867 return 0;
868}
869
966c66e3 870int dns_query_bus_track(DnsQuery *q, sd_bus_message *m) {
82bd6ddd
LP
871 int r;
872
873 assert(q);
874 assert(m);
875
876 if (!q->bus_track) {
966c66e3 877 r = sd_bus_track_new(sd_bus_message_get_bus(m), &q->bus_track, on_bus_track, q);
82bd6ddd
LP
878 if (r < 0)
879 return r;
880 }
881
882 r = sd_bus_track_add_sender(q->bus_track, m);
883 if (r < 0)
884 return r;
885
886 return 0;
887}