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