1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2014 Lennart Poettering
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.
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.
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/>.
22 #include "resolved-dns-query.h"
23 #include "resolved-dns-domain.h"
25 #define TRANSACTION_TIMEOUT_USEC (5 * USEC_PER_SEC)
26 #define QUERY_TIMEOUT_USEC (30 * USEC_PER_SEC)
27 #define ATTEMPTS_MAX 8
29 #define QUERIES_MAX 2048
31 static int dns_query_transaction_go(DnsQueryTransaction *t);
33 DnsQueryTransaction* dns_query_transaction_free(DnsQueryTransaction *t) {
39 sd_event_source_unref(t->timeout_event_source);
41 dns_question_unref(t->question);
42 dns_packet_unref(t->sent);
43 dns_packet_unref(t->received);
44 dns_answer_unref(t->cached);
46 sd_event_source_unref(t->tcp_event_source);
47 safe_close(t->tcp_fd);
50 LIST_REMOVE(transactions_by_scope, t->scope->transactions, t);
53 hashmap_remove(t->scope->manager->dns_query_transactions, UINT_TO_PTR(t->id));
56 while ((q = set_steal_first(t->queries)))
57 set_remove(q->transactions, t);
65 DEFINE_TRIVIAL_CLEANUP_FUNC(DnsQueryTransaction*, dns_query_transaction_free);
67 static void dns_query_transaction_gc(DnsQueryTransaction *t) {
73 if (set_isempty(t->queries))
74 dns_query_transaction_free(t);
77 static int dns_query_transaction_new(DnsQueryTransaction **ret, DnsScope *s, DnsQuestion *q) {
78 _cleanup_(dns_query_transaction_freep) DnsQueryTransaction *t = NULL;
85 r = hashmap_ensure_allocated(&s->manager->dns_query_transactions, NULL, NULL);
89 t = new0(DnsQueryTransaction, 1);
94 t->question = dns_question_ref(q);
97 random_bytes(&t->id, sizeof(t->id));
99 hashmap_get(s->manager->dns_query_transactions, UINT_TO_PTR(t->id)));
101 r = hashmap_put(s->manager->dns_query_transactions, UINT_TO_PTR(t->id), t);
107 LIST_PREPEND(transactions_by_scope, s->transactions, t);
118 static void dns_query_transaction_stop(DnsQueryTransaction *t) {
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);
126 void dns_query_transaction_complete(DnsQueryTransaction *t, DnsQueryState state) {
131 assert(!IN_SET(state, DNS_QUERY_NULL, DNS_QUERY_PENDING));
132 assert(IN_SET(t->state, DNS_QUERY_NULL, DNS_QUERY_PENDING));
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. */
140 dns_query_transaction_stop(t);
142 /* Notify all queries that are interested, but make sure the
143 * transaction isn't freed while we are still looking at it */
145 SET_FOREACH(q, t->queries, i)
149 dns_query_transaction_gc(t);
152 static int on_tcp_ready(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
153 DnsQueryTransaction *t = userdata;
158 if (revents & EPOLLOUT) {
163 sz = htobe16(t->sent->size);
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;
170 IOVEC_INCREMENT(iov, 2, t->tcp_written);
172 ss = writev(fd, iov, 2);
174 if (errno != EINTR && errno != EAGAIN) {
175 dns_query_transaction_complete(t, DNS_QUERY_RESOURCES);
179 t->tcp_written += ss;
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);
185 dns_query_transaction_complete(t, DNS_QUERY_RESOURCES);
191 if (revents & (EPOLLIN|EPOLLHUP|EPOLLRDHUP)) {
193 if (t->tcp_read < sizeof(t->tcp_read_size)) {
196 ss = read(fd, (uint8_t*) &t->tcp_read_size + t->tcp_read, sizeof(t->tcp_read_size) - t->tcp_read);
198 if (errno != EINTR && errno != EAGAIN) {
199 dns_query_transaction_complete(t, DNS_QUERY_RESOURCES);
202 } else if (ss == 0) {
203 dns_query_transaction_complete(t, DNS_QUERY_RESOURCES);
209 if (t->tcp_read >= sizeof(t->tcp_read_size)) {
211 if (be16toh(t->tcp_read_size) < DNS_PACKET_HEADER_SIZE) {
212 dns_query_transaction_complete(t, DNS_QUERY_INVALID_REPLY);
216 if (t->tcp_read < sizeof(t->tcp_read_size) + be16toh(t->tcp_read_size)) {
220 r = dns_packet_new(&t->received, t->scope->protocol, be16toh(t->tcp_read_size));
222 dns_query_transaction_complete(t, DNS_QUERY_RESOURCES);
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);
231 if (errno != EINTR && errno != EAGAIN) {
232 dns_query_transaction_complete(t, DNS_QUERY_RESOURCES);
235 } else if (ss == 0) {
236 dns_query_transaction_complete(t, DNS_QUERY_RESOURCES);
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);
253 static int dns_query_transaction_open_tcp(DnsQueryTransaction *t) {
258 if (t->scope->protocol == DNS_PROTOCOL_DNS)
266 t->received = dns_packet_unref(t->received);
268 t->tcp_fd = dns_scope_tcp_socket(t->scope);
272 r = sd_event_add_io(t->scope->manager->event, &t->tcp_event_source, t->tcp_fd, EPOLLIN|EPOLLOUT, on_tcp_ready, t);
274 t->tcp_fd = safe_close(t->tcp_fd);
281 void dns_query_transaction_process_reply(DnsQueryTransaction *t, DnsPacket *p) {
286 assert(t->state == DNS_QUERY_PENDING);
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. */
292 if (t->received != p) {
293 dns_packet_unref(t->received);
294 t->received = dns_packet_ref(p);
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);
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);
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);
315 /* No servers found? Damn! */
316 dns_query_transaction_complete(t, DNS_QUERY_NO_SERVERS);
320 /* Couldn't send? Try immediately again, with a new server */
321 dns_scope_next_dns_server(t->scope);
323 r = dns_query_transaction_go(t);
325 dns_query_transaction_complete(t, DNS_QUERY_RESOURCES);
333 /* Parse and update the cache */
334 r = dns_packet_extract(p);
336 dns_query_transaction_complete(t, DNS_QUERY_INVALID_REPLY);
340 dns_cache_put(&t->scope->cache, p->question, DNS_PACKET_RCODE(p), p->answer, 0);
342 if (DNS_PACKET_RCODE(p) == DNS_RCODE_SUCCESS)
343 dns_query_transaction_complete(t, DNS_QUERY_SUCCESS);
345 dns_query_transaction_complete(t, DNS_QUERY_FAILURE);
348 static int on_transaction_timeout(sd_event_source *s, usec_t usec, void *userdata) {
349 DnsQueryTransaction *t = userdata;
355 /* Timeout reached? Try again, with a new server */
356 dns_scope_next_dns_server(t->scope);
358 r = dns_query_transaction_go(t);
360 dns_query_transaction_complete(t, DNS_QUERY_RESOURCES);
365 static int dns_query_make_packet(DnsQueryTransaction *t) {
366 _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
367 unsigned n, added = 0;
375 r = dns_packet_new_query(&p, t->scope->protocol, 0);
379 for (n = 0; n < t->question->n_keys; n++) {
380 r = dns_scope_good_key(t->scope, t->question->keys[n]);
386 r = dns_packet_append_key(p, t->question->keys[n], NULL);
396 DNS_PACKET_HEADER(p)->qdcount = htobe16(added);
397 DNS_PACKET_HEADER(p)->id = t->id;
405 static int dns_query_transaction_go(DnsQueryTransaction *t) {
410 dns_query_transaction_stop(t);
412 if (t->n_attempts >= ATTEMPTS_MAX) {
413 dns_query_transaction_complete(t, DNS_QUERY_ATTEMPTS_MAX);
418 t->received = dns_packet_unref(t->received);
419 t->cached = dns_answer_unref(t->cached);
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);
428 if (t->cached_rcode == DNS_RCODE_SUCCESS)
429 dns_query_transaction_complete(t, DNS_QUERY_SUCCESS);
431 dns_query_transaction_complete(t, DNS_QUERY_FAILURE);
435 /* Otherwise, we need to ask the network */
436 r = dns_query_make_packet(t);
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);
447 /* Try via UDP, and if that fails due to large size try via TCP */
448 r = dns_scope_send(t->scope, t->sent);
450 r = dns_query_transaction_open_tcp(t);
452 /* No servers to send this to? */
453 dns_query_transaction_complete(t, DNS_QUERY_NO_SERVERS);
457 /* Couldn't send? Try immediately again, with a new server */
458 dns_scope_next_dns_server(t->scope);
460 return dns_query_transaction_go(t);
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);
467 t->state = DNS_QUERY_PENDING;
471 DnsQuery *dns_query_free(DnsQuery *q) {
472 DnsQueryTransaction *t;
477 sd_bus_message_unref(q->request);
479 dns_question_unref(q->question);
480 dns_answer_unref(q->answer);
482 sd_event_source_unref(q->timeout_event_source);
484 while ((t = set_steal_first(q->transactions))) {
485 set_remove(t->queries, q);
486 dns_query_transaction_gc(t);
489 set_free(q->transactions);
492 LIST_REMOVE(queries, q->manager->dns_queries, q);
493 q->manager->n_dns_queries--;
501 int dns_query_new(Manager *m, DnsQuery **ret, DnsQuestion *question) {
502 _cleanup_(dns_query_freep) DnsQuery *q = NULL;
509 r = dns_question_is_valid(question);
513 if (m->n_dns_queries >= QUERIES_MAX)
516 q = new0(DnsQuery, 1);
520 q->question = dns_question_ref(question);
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]));
529 LIST_PREPEND(queries, m->dns_queries, q);
540 static void dns_query_stop(DnsQuery *q) {
541 DnsQueryTransaction *t;
545 q->timeout_event_source = sd_event_source_unref(q->timeout_event_source);
547 while ((t = set_steal_first(q->transactions))) {
548 set_remove(t->queries, q);
549 dns_query_transaction_gc(t);
553 static void dns_query_complete(DnsQuery *q, DnsQueryState state) {
555 assert(!IN_SET(state, DNS_QUERY_NULL, DNS_QUERY_PENDING));
556 assert(IN_SET(q->state, DNS_QUERY_NULL, DNS_QUERY_PENDING));
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. */
569 static int on_query_timeout(sd_event_source *s, usec_t usec, void *userdata) {
570 DnsQuery *q = userdata;
575 dns_query_complete(q, DNS_QUERY_TIMEOUT);
579 static int dns_query_add_transaction(DnsQuery *q, DnsScope *s, DnsResourceKey *key) {
580 _cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
581 DnsQueryTransaction *t;
586 r = set_ensure_allocated(&q->transactions, NULL, NULL);
591 question = dns_question_new(1);
595 r = dns_question_add(question, key);
599 question = dns_question_ref(q->question);
601 LIST_FOREACH(transactions_by_scope, t, s->transactions)
602 if (dns_question_is_superset(t->question, question))
606 r = dns_query_transaction_new(&t, s, question);
611 r = set_ensure_allocated(&t->queries, NULL, NULL);
615 r = set_put(t->queries, q);
619 r = set_put(q->transactions, t);
621 set_remove(t->queries, q);
628 dns_query_transaction_gc(t);
632 static int dns_query_add_transaction_split(DnsQuery *q, DnsScope *s) {
638 if (s->protocol == DNS_PROTOCOL_MDNS) {
639 r = dns_query_add_transaction(q, s, NULL);
645 /* On DNS and LLMNR we can only send a single
646 * question per datagram, hence issue multiple
649 for (i = 0; i < q->question->n_keys; i++) {
650 r = dns_query_add_transaction(q, s, q->question->keys[i]);
659 int dns_query_go(DnsQuery *q) {
660 DnsScopeMatch found = DNS_SCOPE_NO;
661 DnsScope *s, *first = NULL;
662 DnsQueryTransaction *t;
669 if (q->state != DNS_QUERY_NULL)
673 assert(q->question->n_keys > 0);
675 name = DNS_RESOURCE_KEY_NAME(q->question->keys[0]);
677 LIST_FOREACH(scopes, s, q->manager->dns_scopes) {
680 match = dns_scope_good_domain(s, name);
684 if (match == DNS_SCOPE_NO)
689 if (match == DNS_SCOPE_YES) {
693 assert(match == DNS_SCOPE_MAYBE);
700 if (found == DNS_SCOPE_NO)
703 r = dns_query_add_transaction_split(q, first);
707 LIST_FOREACH(scopes, s, first->scopes_next) {
710 match = dns_scope_good_domain(s, name);
717 r = dns_query_add_transaction_split(q, s);
722 q->answer = dns_answer_unref(q->answer);
723 q->answer_ifindex = 0;
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);
730 q->state = DNS_QUERY_PENDING;
733 SET_FOREACH(t, q->transactions, i) {
734 if (t->state == DNS_QUERY_NULL) {
735 r = dns_query_transaction_go(t);
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;
756 DnsScope *scope = NULL;
760 assert(IN_SET(q->state, DNS_QUERY_NULL, DNS_QUERY_PENDING));
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. */
767 if (q->block_ready > 0)
770 SET_FOREACH(t, q->transactions, i) {
772 /* If we found a successful answer, ignore all answers from other scopes */
773 if (state == DNS_QUERY_SUCCESS && t->scope != scope)
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)
780 /* One of the transactions is successful, let's use
781 * it, and copy its data out */
782 if (t->state == DNS_QUERY_SUCCESS) {
786 rcode = DNS_PACKET_RCODE(t->received);
787 a = t->received->answer;
789 rcode = t->cached_rcode;
793 if (state == DNS_QUERY_SUCCESS) {
796 merged = dns_answer_merge(answer, a);
798 dns_query_complete(q, DNS_QUERY_RESOURCES);
802 dns_answer_unref(answer);
805 dns_answer_unref(answer);
806 answer = dns_answer_ref(a);
810 state = DNS_QUERY_SUCCESS;
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) {
821 rcode = DNS_PACKET_RCODE(t->received);
822 a = t->received->answer;
824 rcode = t->cached_rcode;
828 dns_answer_unref(answer);
829 answer = dns_answer_ref(a);
832 state = DNS_QUERY_FAILURE;
836 if (state == DNS_QUERY_NO_SERVERS && t->state != DNS_QUERY_NO_SERVERS)
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;
846 dns_query_complete(q, state);
849 int dns_query_cname_redirect(DnsQuery *q, const char *name) {
850 _cleanup_(dns_question_unrefp) DnsQuestion *nq = NULL;
855 if (q->n_cname_redirects > CNAME_MAX)
858 r = dns_question_cname_redirect(q->question, name, &nq);
862 dns_question_unref(q->question);
866 q->n_cname_redirects++;
869 q->state = DNS_QUERY_NULL;