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