chiark / gitweb /
resolved: implement negative caching
[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         } else
339                 dns_cache_put(&t->scope->cache, p->question, DNS_PACKET_RCODE(p), p->answer, 0);
340
341         if (DNS_PACKET_RCODE(p) == DNS_RCODE_SUCCESS)
342                 dns_query_transaction_complete(t, DNS_QUERY_SUCCESS);
343         else
344                 dns_query_transaction_complete(t, DNS_QUERY_FAILURE);
345 }
346
347 static int on_transaction_timeout(sd_event_source *s, usec_t usec, void *userdata) {
348         DnsQueryTransaction *t = userdata;
349         int r;
350
351         assert(s);
352         assert(t);
353
354         /* Timeout reached? Try again, with a new server */
355         dns_scope_next_dns_server(t->scope);
356
357         r = dns_query_transaction_go(t);
358         if (r < 0)
359                 dns_query_transaction_complete(t, DNS_QUERY_RESOURCES);
360
361         return 0;
362 }
363
364 static int dns_query_make_packet(DnsQueryTransaction *t) {
365         _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
366         unsigned n, added = 0;
367         int r;
368
369         assert(t);
370
371         if (t->sent)
372                 return 0;
373
374         r = dns_packet_new_query(&p, t->scope->protocol, 0);
375         if (r < 0)
376                 return r;
377
378         for (n = 0; n < t->question->n_keys; n++) {
379                 r = dns_scope_good_key(t->scope, t->question->keys[n]);
380                 if (r < 0)
381                         return r;
382                 if (r == 0)
383                         continue;
384
385                 r = dns_packet_append_key(p, t->question->keys[n], NULL);
386                 if (r < 0)
387                         return r;
388
389                 added++;
390         }
391
392         if (added <= 0)
393                 return -EDOM;
394
395         DNS_PACKET_HEADER(p)->qdcount = htobe16(added);
396         DNS_PACKET_HEADER(p)->id = t->id;
397
398         t->sent = p;
399         p = NULL;
400
401         return 0;
402 }
403
404 static int dns_query_transaction_go(DnsQueryTransaction *t) {
405         int r;
406
407         assert(t);
408
409         dns_query_transaction_stop(t);
410
411         if (t->n_attempts >= ATTEMPTS_MAX) {
412                 dns_query_transaction_complete(t, DNS_QUERY_ATTEMPTS_MAX);
413                 return 0;
414         }
415
416         t->n_attempts++;
417         t->received = dns_packet_unref(t->received);
418         t->cached = dns_answer_unref(t->cached);
419         t->cached_rcode = 0;
420
421         /* First, let's try the cache */
422         dns_cache_prune(&t->scope->cache);
423         r = dns_cache_lookup(&t->scope->cache, t->question, &t->cached_rcode, &t->cached);
424         if (r < 0)
425                 return r;
426         if (r > 0) {
427                 if (t->cached_rcode == DNS_RCODE_SUCCESS)
428                         dns_query_transaction_complete(t, DNS_QUERY_SUCCESS);
429                 else
430                         dns_query_transaction_complete(t, DNS_QUERY_FAILURE);
431                 return 0;
432         }
433
434         /* Otherwise, we need to ask the network */
435         r = dns_query_make_packet(t);
436         if (r == -EDOM) {
437                 /* Not the right request to make on this network?
438                  * (i.e. an A request made on IPv6 or an AAAA request
439                  * made on IPv4, on LLMNR or mDNS.) */
440                 dns_query_transaction_complete(t, DNS_QUERY_NO_SERVERS);
441                 return 0;
442         }
443         if (r < 0)
444                 return r;
445
446         /* Try via UDP, and if that fails due to large size try via TCP */
447         r = dns_scope_send(t->scope, t->sent);
448         if (r == -EMSGSIZE)
449                 r = dns_query_transaction_open_tcp(t);
450         if (r == -ESRCH) {
451                 /* No servers to send this to? */
452                 dns_query_transaction_complete(t, DNS_QUERY_NO_SERVERS);
453                 return 0;
454         }
455         if (r < 0) {
456                 /* Couldn't send? Try immediately again, with a new server */
457                 dns_scope_next_dns_server(t->scope);
458
459                 return dns_query_transaction_go(t);
460         }
461
462         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);
463         if (r < 0)
464                 return r;
465
466         t->state = DNS_QUERY_PENDING;
467         return 1;
468 }
469
470 DnsQuery *dns_query_free(DnsQuery *q) {
471         DnsQueryTransaction *t;
472
473         if (!q)
474                 return NULL;
475
476         sd_bus_message_unref(q->request);
477
478         dns_question_unref(q->question);
479         dns_answer_unref(q->answer);
480
481         sd_event_source_unref(q->timeout_event_source);
482
483         while ((t = set_steal_first(q->transactions))) {
484                 set_remove(t->queries, q);
485                 dns_query_transaction_gc(t);
486         }
487
488         set_free(q->transactions);
489
490         if (q->manager) {
491                 LIST_REMOVE(queries, q->manager->dns_queries, q);
492                 q->manager->n_dns_queries--;
493         }
494
495         free(q);
496
497         return NULL;
498 }
499
500 int dns_query_new(Manager *m, DnsQuery **ret, DnsQuestion *question) {
501         _cleanup_(dns_query_freep) DnsQuery *q = NULL;
502         unsigned i;
503         int r;
504
505         assert(m);
506         assert(question);
507
508         r = dns_question_is_valid(question);
509         if (r < 0)
510                 return r;
511
512         if (m->n_dns_queries >= QUERIES_MAX)
513                 return -EBUSY;
514
515         q = new0(DnsQuery, 1);
516         if (!q)
517                 return -ENOMEM;
518
519         q->question = dns_question_ref(question);
520
521         for (i = 0; i < question->n_keys; i++) {
522                 log_debug("Looking up RR for %s %s %s",
523                           strna(dns_class_to_string(question->keys[i]->class)),
524                           strna(dns_type_to_string(question->keys[i]->type)),
525                           DNS_RESOURCE_KEY_NAME(question->keys[i]));
526         }
527
528         LIST_PREPEND(queries, m->dns_queries, q);
529         m->n_dns_queries++;
530         q->manager = m;
531
532         if (ret)
533                 *ret = q;
534         q = NULL;
535
536         return 0;
537 }
538
539 static void dns_query_stop(DnsQuery *q) {
540         DnsQueryTransaction *t;
541
542         assert(q);
543
544         q->timeout_event_source = sd_event_source_unref(q->timeout_event_source);
545
546         while ((t = set_steal_first(q->transactions))) {
547                 set_remove(t->queries, q);
548                 dns_query_transaction_gc(t);
549         }
550 }
551
552 static void dns_query_complete(DnsQuery *q, DnsQueryState state) {
553         assert(q);
554         assert(!IN_SET(state, DNS_QUERY_NULL, DNS_QUERY_PENDING));
555         assert(IN_SET(q->state, DNS_QUERY_NULL, DNS_QUERY_PENDING));
556
557         /* Note that this call might invalidate the query. Callers
558          * should hence not attempt to access the query or transaction
559          * after calling this function. */
560
561         q->state = state;
562
563         dns_query_stop(q);
564         if (q->complete)
565                 q->complete(q);
566 }
567
568 static int on_query_timeout(sd_event_source *s, usec_t usec, void *userdata) {
569         DnsQuery *q = userdata;
570
571         assert(s);
572         assert(q);
573
574         dns_query_complete(q, DNS_QUERY_TIMEOUT);
575         return 0;
576 }
577
578 static int dns_query_add_transaction(DnsQuery *q, DnsScope *s) {
579         DnsQueryTransaction *t;
580         int r;
581
582         assert(q);
583
584         r = set_ensure_allocated(&q->transactions, NULL, NULL);
585         if (r < 0)
586                 return r;
587
588         LIST_FOREACH(transactions_by_scope, t, s->transactions)
589                 if (dns_question_is_superset(t->question, q->question))
590                         break;
591
592         if (!t) {
593                 r = dns_query_transaction_new(&t, s, q->question);
594                 if (r < 0)
595                         return r;
596         }
597
598         r = set_ensure_allocated(&t->queries, NULL, NULL);
599         if (r < 0)
600                 goto fail;
601
602         r = set_put(t->queries, q);
603         if (r < 0)
604                 goto fail;
605
606         r = set_put(q->transactions, t);
607         if (r < 0) {
608                 set_remove(t->queries, q);
609                 goto fail;
610         }
611
612         return 0;
613
614 fail:
615         dns_query_transaction_gc(t);
616         return r;
617 }
618
619 int dns_query_go(DnsQuery *q) {
620         DnsScopeMatch found = DNS_SCOPE_NO;
621         DnsScope *s, *first = NULL;
622         DnsQueryTransaction *t;
623         const char *name;
624         Iterator i;
625         int r;
626
627         assert(q);
628
629         if (q->state != DNS_QUERY_NULL)
630                 return 0;
631
632         assert(q->question);
633         assert(q->question->n_keys > 0);
634
635         name = DNS_RESOURCE_KEY_NAME(q->question->keys[0]);
636
637         LIST_FOREACH(scopes, s, q->manager->dns_scopes) {
638                 DnsScopeMatch match;
639
640                 match = dns_scope_good_domain(s, name);
641                 if (match < 0)
642                         return match;
643
644                 if (match == DNS_SCOPE_NO)
645                         continue;
646
647                 found = match;
648
649                 if (match == DNS_SCOPE_YES) {
650                         first = s;
651                         break;
652                 } else {
653                         assert(match == DNS_SCOPE_MAYBE);
654
655                         if (!first)
656                                 first = s;
657                 }
658         }
659
660         if (found == DNS_SCOPE_NO)
661                 return -ESRCH;
662
663         r = dns_query_add_transaction(q, first);
664         if (r < 0)
665                 return r;
666
667         LIST_FOREACH(scopes, s, first->scopes_next) {
668                 DnsScopeMatch match;
669
670                 match = dns_scope_good_domain(s, name);
671                 if (match < 0)
672                         return match;
673
674                 if (match != found)
675                         continue;
676
677                 r = dns_query_add_transaction(q, s);
678                 if (r < 0)
679                         return r;
680         }
681
682         q->answer = dns_answer_unref(q->answer);
683         q->answer_ifindex = 0;
684         q->answer_rcode = 0;
685
686         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);
687         if (r < 0)
688                 goto fail;
689
690         q->state = DNS_QUERY_PENDING;
691         q->block_ready++;
692
693         SET_FOREACH(t, q->transactions, i) {
694                 if (t->state == DNS_QUERY_NULL) {
695                         r = dns_query_transaction_go(t);
696                         if (r < 0)
697                                 goto fail;
698                 }
699         }
700
701         q->block_ready--;
702         dns_query_ready(q);
703
704         return 1;
705
706 fail:
707         dns_query_stop(q);
708         return r;
709 }
710
711 void dns_query_ready(DnsQuery *q) {
712         DnsQueryTransaction *t;
713         DnsQueryState state = DNS_QUERY_NO_SERVERS;
714         DnsAnswer *failure_answer = NULL;
715         int failure_rcode = 0, failure_ifindex = 0;
716         Iterator i;
717
718         assert(q);
719         assert(IN_SET(q->state, DNS_QUERY_NULL, DNS_QUERY_PENDING));
720
721         /* Note that this call might invalidate the query. Callers
722          * should hence not attempt to access the query or transaction
723          * after calling this function, unless the block_ready
724          * counter was explicitly bumped before doing so. */
725
726         if (q->block_ready > 0)
727                 return;
728
729         SET_FOREACH(t, q->transactions, i) {
730
731                 /* One of the transactions is still going on, let's wait for it */
732                 if (t->state == DNS_QUERY_PENDING || t->state == DNS_QUERY_NULL)
733                         return;
734
735                 /* One of the transactions is successful, let's use
736                  * it, and copy its data out */
737                 if (t->state == DNS_QUERY_SUCCESS) {
738                         if (t->received) {
739                                 q->answer = dns_answer_ref(t->received->answer);
740                                 q->answer_ifindex = t->received->ifindex;
741                                 q->answer_rcode = DNS_PACKET_RCODE(t->received);
742                         } else {
743                                 q->answer = dns_answer_ref(t->cached);
744                                 q->answer_ifindex = t->scope->link ? t->scope->link->ifindex : 0;
745                                 q->answer_rcode = t->cached_rcode;
746                         }
747
748                         dns_query_complete(q, DNS_QUERY_SUCCESS);
749                         return;
750                 }
751
752                 /* One of the transactions has failed, let's see
753                  * whether we find anything better, but if not, return
754                  * its response packet */
755                 if (t->state == DNS_QUERY_FAILURE) {
756                         if (t->received) {
757                                 failure_answer = t->received->answer;
758                                 failure_ifindex = t->received->ifindex;
759                                 failure_rcode = DNS_PACKET_RCODE(t->received);
760                         } else {
761                                 failure_answer = t->cached;
762                                 failure_ifindex = t->scope->link ? t->scope->link->ifindex : 0;
763                                 failure_rcode = t->cached_rcode;
764                         }
765
766                         state = DNS_QUERY_FAILURE;
767                         continue;
768                 }
769
770                 if (state == DNS_QUERY_NO_SERVERS && t->state != DNS_QUERY_NO_SERVERS)
771                         state = t->state;
772         }
773
774         if (state == DNS_QUERY_FAILURE) {
775                 q->answer = dns_answer_ref(failure_answer);
776                 q->answer_ifindex = failure_ifindex;
777                 q->answer_rcode = failure_rcode;
778         }
779
780         dns_query_complete(q, state);
781 }
782
783 int dns_query_cname_redirect(DnsQuery *q, const char *name) {
784         _cleanup_(dns_question_unrefp) DnsQuestion *nq = NULL;
785         int r;
786
787         assert(q);
788
789         if (q->n_cname_redirects > CNAME_MAX)
790                 return -ELOOP;
791
792         r = dns_question_cname_redirect(q->question, name, &nq);
793         if (r < 0)
794                 return r;
795
796         dns_question_unref(q->question);
797         q->question = nq;
798         nq = NULL;
799
800         q->n_cname_redirects++;
801
802         dns_query_stop(q);
803         q->state = DNS_QUERY_NULL;
804
805         return 0;
806 }