]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/resolve/resolved-dns-query.c
22770023047fdd3cd18b84cd42c9bccb2b15459f
[thirdparty/systemd.git] / src / resolve / resolved-dns-query.c
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
22 #include "af-list.h"
23
24 #include "resolved-dns-query.h"
25 #include "resolved-dns-domain.h"
26
27 /* After how much time to repeat classic DNS requests */
28 #define DNS_TRANSACTION_TIMEOUT_USEC (5 * USEC_PER_SEC)
29
30 /* After how much time to repeat LLMNR requests, see RFC 4795 Section 7 */
31 #define LLMNR_TRANSACTION_TIMEOUT_USEC (1 * USEC_PER_SEC)
32
33 /* How long to wait for the query in total */
34 #define QUERY_TIMEOUT_USEC (30 * USEC_PER_SEC)
35
36 /* Maximum attempts to send DNS requests, across all DNS servers */
37 #define DNS_TRANSACTION_ATTEMPTS_MAX 8
38
39 /* Maximum attempts to send LLMNR requests, see RFC 4795 Section 2.7 */
40 #define LLMNR_TRANSACTION_ATTEMPTS_MAX 3
41
42 #define CNAME_MAX 8
43 #define QUERIES_MAX 2048
44
45 #define TRANSACTION_TIMEOUT_USEC(p) ((t)->scope->protocol == DNS_PROTOCOL_LLMNR ? LLMNR_TRANSACTION_TIMEOUT_USEC : DNS_TRANSACTION_TIMEOUT_USEC)
46 #define TRANSACTION_ATTEMPTS_MAX(p) ((t)->scope->protocol == DNS_PROTOCOL_LLMNR ? LLMNR_TRANSACTION_ATTEMPTS_MAX : DNS_TRANSACTION_ATTEMPTS_MAX)
47
48 static int dns_query_transaction_go(DnsQueryTransaction *t);
49
50 DnsQueryTransaction* dns_query_transaction_free(DnsQueryTransaction *t) {
51 DnsQuery *q;
52
53 if (!t)
54 return NULL;
55
56 sd_event_source_unref(t->timeout_event_source);
57
58 dns_question_unref(t->question);
59 dns_packet_unref(t->sent);
60 dns_packet_unref(t->received);
61 dns_answer_unref(t->cached);
62
63 dns_stream_free(t->stream);
64
65 if (t->scope) {
66 LIST_REMOVE(transactions_by_scope, t->scope->transactions, t);
67
68 if (t->id != 0)
69 hashmap_remove(t->scope->manager->dns_query_transactions, UINT_TO_PTR(t->id));
70 }
71
72 while ((q = set_steal_first(t->queries)))
73 set_remove(q->transactions, t);
74
75 set_free(t->queries);
76
77 free(t);
78 return NULL;
79 }
80
81 DEFINE_TRIVIAL_CLEANUP_FUNC(DnsQueryTransaction*, dns_query_transaction_free);
82
83 static void dns_query_transaction_gc(DnsQueryTransaction *t) {
84 assert(t);
85
86 if (t->block_gc > 0)
87 return;
88
89 if (set_isempty(t->queries))
90 dns_query_transaction_free(t);
91 }
92
93 static int dns_query_transaction_new(DnsQueryTransaction **ret, DnsScope *s, DnsQuestion *q) {
94 _cleanup_(dns_query_transaction_freep) DnsQueryTransaction *t = NULL;
95 int r;
96
97 assert(ret);
98 assert(s);
99 assert(q);
100
101 r = hashmap_ensure_allocated(&s->manager->dns_query_transactions, NULL, NULL);
102 if (r < 0)
103 return r;
104
105 t = new0(DnsQueryTransaction, 1);
106 if (!t)
107 return -ENOMEM;
108
109 t->question = dns_question_ref(q);
110
111 do
112 random_bytes(&t->id, sizeof(t->id));
113 while (t->id == 0 ||
114 hashmap_get(s->manager->dns_query_transactions, UINT_TO_PTR(t->id)));
115
116 r = hashmap_put(s->manager->dns_query_transactions, UINT_TO_PTR(t->id), t);
117 if (r < 0) {
118 t->id = 0;
119 return r;
120 }
121
122 LIST_PREPEND(transactions_by_scope, s->transactions, t);
123 t->scope = s;
124
125 if (ret)
126 *ret = t;
127
128 t = NULL;
129
130 return 0;
131 }
132
133 static void dns_query_transaction_stop(DnsQueryTransaction *t) {
134 assert(t);
135
136 t->timeout_event_source = sd_event_source_unref(t->timeout_event_source);
137 t->stream = dns_stream_free(t->stream);
138 }
139
140 void dns_query_transaction_complete(DnsQueryTransaction *t, DnsQueryState state) {
141 DnsQuery *q;
142 Iterator i;
143
144 assert(t);
145 assert(!IN_SET(state, DNS_QUERY_NULL, DNS_QUERY_PENDING));
146 assert(IN_SET(t->state, DNS_QUERY_NULL, DNS_QUERY_PENDING));
147
148 /* Note that this call might invalidate the query. Callers
149 * should hence not attempt to access the query or transaction
150 * after calling this function. */
151
152 log_debug("Transaction on scope %s on %s/%s now complete with %s",
153 dns_protocol_to_string(t->scope->protocol),
154 t->scope->link ? t->scope->link->name : "*",
155 t->scope->family == AF_UNSPEC ? "*" : af_to_name(t->scope->family),
156 dns_query_state_to_string(state));
157
158 t->state = state;
159
160 dns_query_transaction_stop(t);
161
162 /* Notify all queries that are interested, but make sure the
163 * transaction isn't freed while we are still looking at it */
164 t->block_gc++;
165 SET_FOREACH(q, t->queries, i)
166 dns_query_ready(q);
167 t->block_gc--;
168
169 dns_query_transaction_gc(t);
170 }
171
172 static int on_stream_complete(DnsStream *s, int error) {
173 _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
174 DnsQueryTransaction *t;
175
176 assert(s);
177 assert(s->transaction);
178
179 /* Copy the data we care about out of the stream before we
180 * destroy it. */
181 t = s->transaction;
182 p = dns_packet_ref(s->read_packet);
183
184 t->stream = dns_stream_free(t->stream);
185
186 if (error != 0) {
187 dns_query_transaction_complete(t, DNS_QUERY_RESOURCES);
188 return 0;
189 }
190
191 t->block_gc++;
192 dns_query_transaction_process_reply(t, p);
193 t->block_gc--;
194
195 /* If the response wasn't useful, then complete the transition now */
196 if (t->state == DNS_QUERY_PENDING)
197 dns_query_transaction_complete(t, DNS_QUERY_INVALID_REPLY);
198
199 return 0;
200 }
201
202 static int dns_query_transaction_open_tcp(DnsQueryTransaction *t) {
203 _cleanup_close_ int fd = -1;
204 int r;
205
206 assert(t);
207
208 if (t->stream)
209 return 0;
210
211 if (t->scope->protocol == DNS_PROTOCOL_DNS)
212 fd = dns_scope_tcp_socket(t->scope, AF_UNSPEC, NULL, 53);
213 else if (t->scope->protocol == DNS_PROTOCOL_LLMNR) {
214
215 /* When we already received a query to this (but it was truncated), send to its sender address */
216 if (t->received)
217 fd = dns_scope_tcp_socket(t->scope, t->received->family, &t->received->sender, t->received->sender_port);
218 else {
219 union in_addr_union address;
220 int family;
221
222 /* Otherwise, try to talk to the owner of a
223 * the IP address, in case this is a reverse
224 * PTR lookup */
225 r = dns_question_extract_reverse_address(t->question, &family, &address);
226 if (r < 0)
227 return r;
228 if (r == 0)
229 return -EINVAL;
230
231 fd = dns_scope_tcp_socket(t->scope, family, &address, 5355);
232 }
233 } else
234 return -EAFNOSUPPORT;
235
236 if (fd < 0)
237 return fd;
238
239 r = dns_stream_new(t->scope->manager, &t->stream, t->scope->protocol, fd);
240 if (r < 0)
241 return r;
242
243 fd = -1;
244
245 r = dns_stream_write_packet(t->stream, t->sent);
246 if (r < 0) {
247 t->stream = dns_stream_free(t->stream);
248 return r;
249 }
250
251 t->received = dns_packet_unref(t->received);
252 t->stream->complete = on_stream_complete;
253 t->stream->transaction = t;
254
255 /* The interface index is difficult to determine if we are
256 * connecting to the local host, hence fill this in right away
257 * instead of determining it from the socket */
258 if (t->scope->link)
259 t->stream->ifindex = t->scope->link->ifindex;
260
261 return 0;
262 }
263
264 void dns_query_transaction_process_reply(DnsQueryTransaction *t, DnsPacket *p) {
265 int r;
266
267 assert(t);
268 assert(p);
269 assert(t->state == DNS_QUERY_PENDING);
270
271 /* Note that this call might invalidate the query. Callers
272 * should hence not attempt to access the query or transaction
273 * after calling this function. */
274
275 if (t->scope->protocol == DNS_PROTOCOL_LLMNR) {
276 assert(t->scope->link);
277
278 /* For LLMNR we will not accept any packets from other
279 * interfaces */
280
281 if (p->ifindex != t->scope->link->ifindex)
282 return;
283
284 if (p->family != t->scope->family)
285 return;
286
287 /* Tentative replies shall be discarded, see RFC 4795,
288 * 2.1.1 */
289
290 if (DNS_PACKET_T(p))
291 return;
292 }
293
294 if (t->scope->protocol == DNS_PROTOCOL_DNS) {
295
296 /* For DNS we are fine with accepting packets on any
297 * interface, but the source IP address must be one of
298 * a valid DNS server */
299
300 if (!dns_scope_good_dns_server(t->scope, p->family, &p->sender))
301 return;
302
303 if (p->sender_port != 53)
304 return;
305 }
306
307 if (t->received != p) {
308 dns_packet_unref(t->received);
309 t->received = dns_packet_ref(p);
310 }
311
312 if (p->ipproto == IPPROTO_TCP) {
313 if (DNS_PACKET_TC(p)) {
314 /* Truncated via TCP? Somebody must be fucking with us */
315 dns_query_transaction_complete(t, DNS_QUERY_INVALID_REPLY);
316 return;
317 }
318
319 if (DNS_PACKET_ID(p) != t->id) {
320 /* Not the reply to our query? Somebody must be fucking with us */
321 dns_query_transaction_complete(t, DNS_QUERY_INVALID_REPLY);
322 return;
323 }
324 }
325
326 if (DNS_PACKET_TC(p)) {
327 /* Response was truncated, let's try again with good old TCP */
328 r = dns_query_transaction_open_tcp(t);
329 if (r == -ESRCH) {
330 /* No servers found? Damn! */
331 dns_query_transaction_complete(t, DNS_QUERY_NO_SERVERS);
332 return;
333 }
334 if (r < 0) {
335 /* On LLMNR, if we cannot connect to the host,
336 * we immediately give up */
337 if (t->scope->protocol == DNS_PROTOCOL_LLMNR) {
338 dns_query_transaction_complete(t, DNS_QUERY_RESOURCES);
339 return;
340 }
341
342 /* On DNS, couldn't send? Try immediately again, with a new server */
343 dns_scope_next_dns_server(t->scope);
344
345 r = dns_query_transaction_go(t);
346 if (r < 0) {
347 dns_query_transaction_complete(t, DNS_QUERY_RESOURCES);
348 return;
349 }
350
351 return;
352 }
353 }
354
355 /* Parse and update the cache */
356 r = dns_packet_extract(p);
357 if (r < 0) {
358 dns_query_transaction_complete(t, DNS_QUERY_INVALID_REPLY);
359 return;
360 }
361
362 /* According to RFC 4795, section 2.9. only the RRs from the answer section shall be cached */
363 dns_cache_put(&t->scope->cache, p->question, DNS_PACKET_RCODE(p), p->answer, DNS_PACKET_ANCOUNT(p), 0);
364
365 if (DNS_PACKET_RCODE(p) == DNS_RCODE_SUCCESS)
366 dns_query_transaction_complete(t, DNS_QUERY_SUCCESS);
367 else
368 dns_query_transaction_complete(t, DNS_QUERY_FAILURE);
369 }
370
371 static int on_transaction_timeout(sd_event_source *s, usec_t usec, void *userdata) {
372 DnsQueryTransaction *t = userdata;
373 int r;
374
375 assert(s);
376 assert(t);
377
378 /* Timeout reached? Try again, with a new server */
379 dns_scope_next_dns_server(t->scope);
380
381 r = dns_query_transaction_go(t);
382 if (r < 0)
383 dns_query_transaction_complete(t, DNS_QUERY_RESOURCES);
384
385 return 0;
386 }
387
388 static int dns_query_make_packet(DnsQueryTransaction *t) {
389 _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
390 unsigned n, added = 0;
391 int r;
392
393 assert(t);
394
395 if (t->sent)
396 return 0;
397
398 r = dns_packet_new_query(&p, t->scope->protocol, 0);
399 if (r < 0)
400 return r;
401
402 for (n = 0; n < t->question->n_keys; n++) {
403 r = dns_scope_good_key(t->scope, t->question->keys[n]);
404 if (r < 0)
405 return r;
406 if (r == 0)
407 continue;
408
409 r = dns_packet_append_key(p, t->question->keys[n], NULL);
410 if (r < 0)
411 return r;
412
413 added++;
414 }
415
416 if (added <= 0)
417 return -EDOM;
418
419 DNS_PACKET_HEADER(p)->qdcount = htobe16(added);
420 DNS_PACKET_HEADER(p)->id = t->id;
421
422 t->sent = p;
423 p = NULL;
424
425 return 0;
426 }
427
428 static int dns_query_transaction_go(DnsQueryTransaction *t) {
429 bool had_stream;
430 int r;
431
432 assert(t);
433
434 had_stream = !!t->stream;
435
436 dns_query_transaction_stop(t);
437
438 log_debug("Beginning transaction on scope %s on %s/%s",
439 dns_protocol_to_string(t->scope->protocol),
440 t->scope->link ? t->scope->link->name : "*",
441 t->scope->family == AF_UNSPEC ? "*" : af_to_name(t->scope->family));
442
443 if (t->n_attempts >= TRANSACTION_ATTEMPTS_MAX(t)) {
444 dns_query_transaction_complete(t, DNS_QUERY_ATTEMPTS_MAX);
445 return 0;
446 }
447
448 if (t->scope->protocol == DNS_PROTOCOL_LLMNR && had_stream) {
449 /* If we already tried via a stream, then we don't
450 * retry on LLMNR. See RFC 4795, Section 2.7. */
451 dns_query_transaction_complete(t, DNS_QUERY_ATTEMPTS_MAX);
452 return 0;
453 }
454
455 t->n_attempts++;
456 t->received = dns_packet_unref(t->received);
457 t->cached = dns_answer_unref(t->cached);
458 t->cached_rcode = 0;
459
460 /* First, let's try the cache */
461 dns_cache_prune(&t->scope->cache);
462 r = dns_cache_lookup(&t->scope->cache, t->question, &t->cached_rcode, &t->cached);
463 if (r < 0)
464 return r;
465 if (r > 0) {
466 if (t->cached_rcode == DNS_RCODE_SUCCESS)
467 dns_query_transaction_complete(t, DNS_QUERY_SUCCESS);
468 else
469 dns_query_transaction_complete(t, DNS_QUERY_FAILURE);
470 return 0;
471 }
472
473 /* Otherwise, we need to ask the network */
474 r = dns_query_make_packet(t);
475 if (r == -EDOM) {
476 /* Not the right request to make on this network?
477 * (i.e. an A request made on IPv6 or an AAAA request
478 * made on IPv4, on LLMNR or mDNS.) */
479 dns_query_transaction_complete(t, DNS_QUERY_NO_SERVERS);
480 return 0;
481 }
482 if (r < 0)
483 return r;
484
485 if (t->scope->protocol == DNS_PROTOCOL_LLMNR &&
486 (dns_question_endswith(t->question, "in-addr.arpa") > 0 ||
487 dns_question_endswith(t->question, "ip6.arpa") > 0)) {
488
489 /* RFC 4795, Section 2.4. says reverse lookups shall
490 * always be made via TCP on LLMNR */
491 r = dns_query_transaction_open_tcp(t);
492 } else {
493 /* Try via UDP, and if that fails due to large size try via TCP */
494 r = dns_scope_send(t->scope, t->sent);
495 if (r == -EMSGSIZE)
496 r = dns_query_transaction_open_tcp(t);
497 }
498 if (r == -ESRCH) {
499 /* No servers to send this to? */
500 dns_query_transaction_complete(t, DNS_QUERY_NO_SERVERS);
501 return 0;
502 }
503 if (r < 0) {
504 /* Couldn't send? Try immediately again, with a new server */
505 dns_scope_next_dns_server(t->scope);
506
507 return dns_query_transaction_go(t);
508 }
509
510 r = sd_event_add_time(t->scope->manager->event, &t->timeout_event_source, CLOCK_MONOTONIC, now(CLOCK_MONOTONIC) + TRANSACTION_TIMEOUT_USEC(t), 0, on_transaction_timeout, t);
511 if (r < 0)
512 return r;
513
514 t->state = DNS_QUERY_PENDING;
515 return 1;
516 }
517
518 DnsQuery *dns_query_free(DnsQuery *q) {
519 DnsQueryTransaction *t;
520
521 if (!q)
522 return NULL;
523
524 sd_bus_message_unref(q->request);
525
526 dns_question_unref(q->question);
527 dns_answer_unref(q->answer);
528
529 sd_event_source_unref(q->timeout_event_source);
530
531 while ((t = set_steal_first(q->transactions))) {
532 set_remove(t->queries, q);
533 dns_query_transaction_gc(t);
534 }
535
536 set_free(q->transactions);
537
538 if (q->manager) {
539 LIST_REMOVE(queries, q->manager->dns_queries, q);
540 q->manager->n_dns_queries--;
541 }
542
543 free(q);
544
545 return NULL;
546 }
547
548 int dns_query_new(Manager *m, DnsQuery **ret, DnsQuestion *question) {
549 _cleanup_(dns_query_freep) DnsQuery *q = NULL;
550 unsigned i;
551 int r;
552
553 assert(m);
554 assert(question);
555
556 r = dns_question_is_valid(question);
557 if (r < 0)
558 return r;
559
560 if (m->n_dns_queries >= QUERIES_MAX)
561 return -EBUSY;
562
563 q = new0(DnsQuery, 1);
564 if (!q)
565 return -ENOMEM;
566
567 q->question = dns_question_ref(question);
568
569 for (i = 0; i < question->n_keys; i++) {
570 _cleanup_free_ char *p;
571
572 r = dns_resource_key_to_string(question->keys[i], &p);
573 if (r < 0)
574 return r;
575
576 log_debug("Looking up RR for %s", p);
577 }
578
579 LIST_PREPEND(queries, m->dns_queries, q);
580 m->n_dns_queries++;
581 q->manager = m;
582
583 if (ret)
584 *ret = q;
585 q = NULL;
586
587 return 0;
588 }
589
590 static void dns_query_stop(DnsQuery *q) {
591 DnsQueryTransaction *t;
592
593 assert(q);
594
595 q->timeout_event_source = sd_event_source_unref(q->timeout_event_source);
596
597 while ((t = set_steal_first(q->transactions))) {
598 set_remove(t->queries, q);
599 dns_query_transaction_gc(t);
600 }
601 }
602
603 static void dns_query_complete(DnsQuery *q, DnsQueryState state) {
604 assert(q);
605 assert(!IN_SET(state, DNS_QUERY_NULL, DNS_QUERY_PENDING));
606 assert(IN_SET(q->state, DNS_QUERY_NULL, DNS_QUERY_PENDING));
607
608 /* Note that this call might invalidate the query. Callers
609 * should hence not attempt to access the query or transaction
610 * after calling this function. */
611
612 q->state = state;
613
614 dns_query_stop(q);
615 if (q->complete)
616 q->complete(q);
617 }
618
619 static int on_query_timeout(sd_event_source *s, usec_t usec, void *userdata) {
620 DnsQuery *q = userdata;
621
622 assert(s);
623 assert(q);
624
625 dns_query_complete(q, DNS_QUERY_TIMEOUT);
626 return 0;
627 }
628
629 static int dns_query_add_transaction(DnsQuery *q, DnsScope *s, DnsResourceKey *key) {
630 _cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
631 DnsQueryTransaction *t;
632 int r;
633
634 assert(q);
635
636 r = set_ensure_allocated(&q->transactions, NULL, NULL);
637 if (r < 0)
638 return r;
639
640 if (key) {
641 question = dns_question_new(1);
642 if (!question)
643 return -ENOMEM;
644
645 r = dns_question_add(question, key);
646 if (r < 0)
647 return r;
648 } else
649 question = dns_question_ref(q->question);
650
651 LIST_FOREACH(transactions_by_scope, t, s->transactions)
652 if (dns_question_is_superset(t->question, question))
653 break;
654
655 if (!t) {
656 r = dns_query_transaction_new(&t, s, question);
657 if (r < 0)
658 return r;
659 }
660
661 r = set_ensure_allocated(&t->queries, NULL, NULL);
662 if (r < 0)
663 goto fail;
664
665 r = set_put(t->queries, q);
666 if (r < 0)
667 goto fail;
668
669 r = set_put(q->transactions, t);
670 if (r < 0) {
671 set_remove(t->queries, q);
672 goto fail;
673 }
674
675 return 0;
676
677 fail:
678 dns_query_transaction_gc(t);
679 return r;
680 }
681
682 static int dns_query_add_transaction_split(DnsQuery *q, DnsScope *s) {
683 int r;
684
685 assert(q);
686 assert(s);
687
688 if (s->protocol == DNS_PROTOCOL_MDNS) {
689 r = dns_query_add_transaction(q, s, NULL);
690 if (r < 0)
691 return r;
692 } else {
693 unsigned i;
694
695 /* On DNS and LLMNR we can only send a single
696 * question per datagram, hence issue multiple
697 * transactions. */
698
699 for (i = 0; i < q->question->n_keys; i++) {
700 r = dns_query_add_transaction(q, s, q->question->keys[i]);
701 if (r < 0)
702 return r;
703 }
704 }
705
706 return 0;
707 }
708
709 int dns_query_go(DnsQuery *q) {
710 DnsScopeMatch found = DNS_SCOPE_NO;
711 DnsScope *s, *first = NULL;
712 DnsQueryTransaction *t;
713 const char *name;
714 Iterator i;
715 int r;
716
717 assert(q);
718
719 if (q->state != DNS_QUERY_NULL)
720 return 0;
721
722 assert(q->question);
723 assert(q->question->n_keys > 0);
724
725 name = DNS_RESOURCE_KEY_NAME(q->question->keys[0]);
726
727 LIST_FOREACH(scopes, s, q->manager->dns_scopes) {
728 DnsScopeMatch match;
729
730 match = dns_scope_good_domain(s, name);
731 if (match < 0)
732 return match;
733
734 if (match == DNS_SCOPE_NO)
735 continue;
736
737 found = match;
738
739 if (match == DNS_SCOPE_YES) {
740 first = s;
741 break;
742 } else {
743 assert(match == DNS_SCOPE_MAYBE);
744
745 if (!first)
746 first = s;
747 }
748 }
749
750 if (found == DNS_SCOPE_NO)
751 return -ESRCH;
752
753 r = dns_query_add_transaction_split(q, first);
754 if (r < 0)
755 return r;
756
757 LIST_FOREACH(scopes, s, first->scopes_next) {
758 DnsScopeMatch match;
759
760 match = dns_scope_good_domain(s, name);
761 if (match < 0)
762 return match;
763
764 if (match != found)
765 continue;
766
767 r = dns_query_add_transaction_split(q, s);
768 if (r < 0)
769 return r;
770 }
771
772 q->answer = dns_answer_unref(q->answer);
773 q->answer_ifindex = 0;
774 q->answer_rcode = 0;
775
776 r = sd_event_add_time(q->manager->event, &q->timeout_event_source, CLOCK_MONOTONIC, now(CLOCK_MONOTONIC) + QUERY_TIMEOUT_USEC, 0, on_query_timeout, q);
777 if (r < 0)
778 goto fail;
779
780 q->state = DNS_QUERY_PENDING;
781 q->block_ready++;
782
783 SET_FOREACH(t, q->transactions, i) {
784 if (t->state == DNS_QUERY_NULL) {
785 r = dns_query_transaction_go(t);
786 if (r < 0)
787 goto fail;
788 }
789 }
790
791 q->block_ready--;
792 dns_query_ready(q);
793
794 return 1;
795
796 fail:
797 dns_query_stop(q);
798 return r;
799 }
800
801 void dns_query_ready(DnsQuery *q) {
802 DnsQueryTransaction *t;
803 DnsQueryState state = DNS_QUERY_NO_SERVERS;
804 _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
805 int rcode = 0;
806 DnsScope *scope = NULL;
807 bool pending = false;
808 Iterator i;
809
810 assert(q);
811 assert(IN_SET(q->state, DNS_QUERY_NULL, DNS_QUERY_PENDING));
812
813 /* Note that this call might invalidate the query. Callers
814 * should hence not attempt to access the query or transaction
815 * after calling this function, unless the block_ready
816 * counter was explicitly bumped before doing so. */
817
818 if (q->block_ready > 0)
819 return;
820
821 SET_FOREACH(t, q->transactions, i) {
822
823 /* If we found a successful answer, ignore all answers from other scopes */
824 if (state == DNS_QUERY_SUCCESS && t->scope != scope)
825 continue;
826
827 /* One of the transactions is still going on, let's maybe wait for it */
828 if (IN_SET(t->state, DNS_QUERY_PENDING, DNS_QUERY_NULL)) {
829 pending = true;
830 continue;
831 }
832
833 /* One of the transactions is successful, let's use
834 * it, and copy its data out */
835 if (t->state == DNS_QUERY_SUCCESS) {
836 DnsAnswer *a;
837
838 if (t->received) {
839 rcode = DNS_PACKET_RCODE(t->received);
840 a = t->received->answer;
841 } else {
842 rcode = t->cached_rcode;
843 a = t->cached;
844 }
845
846 if (state == DNS_QUERY_SUCCESS) {
847 DnsAnswer *merged;
848
849 merged = dns_answer_merge(answer, a);
850 if (!merged) {
851 dns_query_complete(q, DNS_QUERY_RESOURCES);
852 return;
853 }
854
855 dns_answer_unref(answer);
856 answer = merged;
857 } else {
858 dns_answer_unref(answer);
859 answer = dns_answer_ref(a);
860 }
861
862 scope = t->scope;
863 state = DNS_QUERY_SUCCESS;
864 continue;
865 }
866
867 /* One of the transactions has failed, let's see
868 * whether we find anything better, but if not, return
869 * its response data */
870 if (state != DNS_QUERY_SUCCESS && t->state == DNS_QUERY_FAILURE) {
871 DnsAnswer *a;
872
873 if (t->received) {
874 rcode = DNS_PACKET_RCODE(t->received);
875 a = t->received->answer;
876 } else {
877 rcode = t->cached_rcode;
878 a = t->cached;
879 }
880
881 dns_answer_unref(answer);
882 answer = dns_answer_ref(a);
883
884 scope = t->scope;
885 state = DNS_QUERY_FAILURE;
886 continue;
887 }
888
889 if (state == DNS_QUERY_NO_SERVERS && t->state != DNS_QUERY_NO_SERVERS)
890 state = t->state;
891 }
892
893 if (pending) {
894
895 /* If so far we weren't successful, and there's
896 * something still pending, then wait for it */
897 if (state != DNS_QUERY_SUCCESS)
898 return;
899
900 /* If we already were successful, then only wait for
901 * other transactions on the same scope to finish. */
902 SET_FOREACH(t, q->transactions, i) {
903 if (t->scope == scope && IN_SET(t->state, DNS_QUERY_PENDING, DNS_QUERY_NULL))
904 return;
905 }
906 }
907
908 if (IN_SET(state, DNS_QUERY_SUCCESS, DNS_QUERY_FAILURE)) {
909 q->answer = dns_answer_ref(answer);
910 q->answer_rcode = rcode;
911 q->answer_ifindex = (scope && scope->link) ? scope->link->ifindex : 0;
912 }
913
914 dns_query_complete(q, state);
915 }
916
917 int dns_query_cname_redirect(DnsQuery *q, const char *name) {
918 _cleanup_(dns_question_unrefp) DnsQuestion *nq = NULL;
919 int r;
920
921 assert(q);
922
923 if (q->n_cname_redirects > CNAME_MAX)
924 return -ELOOP;
925
926 r = dns_question_cname_redirect(q->question, name, &nq);
927 if (r < 0)
928 return r;
929
930 dns_question_unref(q->question);
931 q->question = nq;
932 nq = NULL;
933
934 q->n_cname_redirects++;
935
936 dns_query_stop(q);
937 q->state = DNS_QUERY_NULL;
938
939 return 0;
940 }
941
942 static const char* const dns_query_state_table[_DNS_QUERY_STATE_MAX] = {
943 [DNS_QUERY_NULL] = "null",
944 [DNS_QUERY_PENDING] = "pending",
945 [DNS_QUERY_FAILURE] = "failure",
946 [DNS_QUERY_SUCCESS] = "success",
947 [DNS_QUERY_NO_SERVERS] = "no-servers",
948 [DNS_QUERY_TIMEOUT] = "timeout",
949 [DNS_QUERY_ATTEMPTS_MAX] = "attempts-max",
950 [DNS_QUERY_INVALID_REPLY] = "invalid-reply",
951 [DNS_QUERY_RESOURCES] = "resources",
952 [DNS_QUERY_ABORTED] = "aborted",
953 };
954 DEFINE_STRING_TABLE_LOOKUP(dns_query_state, DnsQueryState);