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) {
37 sd_event_source_unref(t->timeout_event_source);
39 dns_packet_unref(t->sent);
40 dns_packet_unref(t->received);
42 dns_resource_record_freev(t->cached_rrs, t->n_cached_rrs);
44 sd_event_source_unref(t->tcp_event_source);
45 safe_close(t->tcp_fd);
48 LIST_REMOVE(transactions_by_query, t->query->transactions, t);
49 hashmap_remove(t->query->manager->dns_query_transactions, UINT_TO_PTR(t->id));
53 LIST_REMOVE(transactions_by_scope, t->scope->transactions, t);
59 DEFINE_TRIVIAL_CLEANUP_FUNC(DnsQueryTransaction*, dns_query_transaction_free);
61 static int dns_query_transaction_new(DnsQuery *q, DnsQueryTransaction **ret, DnsScope *s) {
62 _cleanup_(dns_query_transaction_freep) DnsQueryTransaction *t = NULL;
68 r = hashmap_ensure_allocated(&q->manager->dns_query_transactions, NULL, NULL);
72 t = new0(DnsQueryTransaction, 1);
79 random_bytes(&t->id, sizeof(t->id));
81 hashmap_get(q->manager->dns_query_transactions, UINT_TO_PTR(t->id)));
83 r = hashmap_put(q->manager->dns_query_transactions, UINT_TO_PTR(t->id), t);
89 LIST_PREPEND(transactions_by_query, q->transactions, t);
92 LIST_PREPEND(transactions_by_scope, s->transactions, t);
103 static void dns_query_transaction_stop(DnsQueryTransaction *t) {
106 t->timeout_event_source = sd_event_source_unref(t->timeout_event_source);
107 t->tcp_event_source = sd_event_source_unref(t->tcp_event_source);
108 t->tcp_fd = safe_close(t->tcp_fd);
111 static void dns_query_transaction_complete(DnsQueryTransaction *t, DnsQueryState state) {
113 assert(!IN_SET(state, DNS_QUERY_NULL, DNS_QUERY_PENDING));
114 assert(IN_SET(t->state, DNS_QUERY_NULL, DNS_QUERY_PENDING));
116 /* Note that this call might invalidate the query. Callers
117 * should hence not attempt to access the query or transaction
118 * after calling this function. */
122 dns_query_transaction_stop(t);
123 dns_query_finish(t->query);
126 static int on_tcp_ready(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
127 DnsQueryTransaction *t = userdata;
132 if (revents & EPOLLOUT) {
137 sz = htobe16(t->sent->size);
139 iov[0].iov_base = &sz;
140 iov[0].iov_len = sizeof(sz);
141 iov[1].iov_base = DNS_PACKET_DATA(t->sent);
142 iov[1].iov_len = t->sent->size;
144 IOVEC_INCREMENT(iov, 2, t->tcp_written);
146 ss = writev(fd, iov, 2);
148 if (errno != EINTR && errno != EAGAIN) {
149 dns_query_transaction_complete(t, DNS_QUERY_RESOURCES);
153 t->tcp_written += ss;
155 /* Are we done? If so, disable the event source for EPOLLOUT */
156 if (t->tcp_written >= sizeof(sz) + t->sent->size) {
157 r = sd_event_source_set_io_events(s, EPOLLIN);
159 dns_query_transaction_complete(t, DNS_QUERY_RESOURCES);
165 if (revents & (EPOLLIN|EPOLLHUP|EPOLLRDHUP)) {
167 if (t->tcp_read < sizeof(t->tcp_read_size)) {
170 ss = read(fd, (uint8_t*) &t->tcp_read_size + t->tcp_read, sizeof(t->tcp_read_size) - t->tcp_read);
172 if (errno != EINTR && errno != EAGAIN) {
173 dns_query_transaction_complete(t, DNS_QUERY_RESOURCES);
176 } else if (ss == 0) {
177 dns_query_transaction_complete(t, DNS_QUERY_RESOURCES);
183 if (t->tcp_read >= sizeof(t->tcp_read_size)) {
185 if (be16toh(t->tcp_read_size) < DNS_PACKET_HEADER_SIZE) {
186 dns_query_transaction_complete(t, DNS_QUERY_INVALID_REPLY);
190 if (t->tcp_read < sizeof(t->tcp_read_size) + be16toh(t->tcp_read_size)) {
194 r = dns_packet_new(&t->received, be16toh(t->tcp_read_size));
196 dns_query_transaction_complete(t, DNS_QUERY_RESOURCES);
202 (uint8_t*) DNS_PACKET_DATA(t->received) + t->tcp_read - sizeof(t->tcp_read_size),
203 sizeof(t->tcp_read_size) + be16toh(t->tcp_read_size) - t->tcp_read);
205 if (errno != EINTR && errno != EAGAIN) {
206 dns_query_transaction_complete(t, DNS_QUERY_RESOURCES);
209 } else if (ss == 0) {
210 dns_query_transaction_complete(t, DNS_QUERY_RESOURCES);
216 if (t->tcp_read >= sizeof(t->tcp_read_size) + be16toh(t->tcp_read_size)) {
217 t->received->size = be16toh(t->tcp_read_size);
218 dns_query_transaction_reply(t, t->received);
227 static int dns_query_transaction_open_tcp(DnsQueryTransaction *t) {
237 t->received = dns_packet_unref(t->received);
239 t->tcp_fd = dns_scope_tcp_socket(t->scope);
243 r = sd_event_add_io(t->query->manager->event, &t->tcp_event_source, t->tcp_fd, EPOLLIN|EPOLLOUT, on_tcp_ready, t);
245 t->tcp_fd = safe_close(t->tcp_fd);
252 void dns_query_transaction_reply(DnsQueryTransaction *t, DnsPacket *p) {
257 assert(t->state == DNS_QUERY_PENDING);
259 /* Note that this call might invalidate the query. Callers
260 * should hence not attempt to access the query or transaction
261 * after calling this function. */
263 if (t->received != p) {
264 dns_packet_unref(t->received);
265 t->received = dns_packet_ref(p);
268 if (t->tcp_fd >= 0) {
269 if (DNS_PACKET_TC(p)) {
270 /* Truncated via TCP? Somebody must be fucking with us */
271 dns_query_transaction_complete(t, DNS_QUERY_INVALID_REPLY);
275 if (DNS_PACKET_ID(p) != t->id) {
276 /* Not the reply to our query? Somebody must be fucking with us */
277 dns_query_transaction_complete(t, DNS_QUERY_INVALID_REPLY);
282 if (DNS_PACKET_TC(p)) {
283 /* Response was truncated, let's try again with good old TCP */
284 r = dns_query_transaction_open_tcp(t);
286 /* No servers found? Damn! */
287 dns_query_transaction_complete(t, DNS_QUERY_NO_SERVERS);
291 /* Couldn't send? Try immediately again, with a new server */
292 dns_scope_next_dns_server(t->scope);
294 r = dns_query_transaction_go(t);
296 dns_query_transaction_complete(t, DNS_QUERY_RESOURCES);
304 /* Parse and update the cache */
305 r = dns_packet_extract_rrs(p);
307 dns_query_transaction_complete(t, DNS_QUERY_INVALID_REPLY);
310 dns_cache_put_rrs(&t->scope->cache, p->rrs, r, 0);
312 if (DNS_PACKET_RCODE(p) == DNS_RCODE_SUCCESS)
313 dns_query_transaction_complete(t, DNS_QUERY_SUCCESS);
315 dns_query_transaction_complete(t, DNS_QUERY_FAILURE);
318 static int on_transaction_timeout(sd_event_source *s, usec_t usec, void *userdata) {
319 DnsQueryTransaction *t = userdata;
325 /* Timeout reached? Try again, with a new server */
326 dns_scope_next_dns_server(t->scope);
328 r = dns_query_transaction_go(t);
330 dns_query_transaction_complete(t, DNS_QUERY_RESOURCES);
335 static int dns_query_make_packet(DnsQueryTransaction *t) {
336 _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
345 r = dns_packet_new_query(&p, 0);
349 for (n = 0; n < t->query->n_keys; n++) {
350 r = dns_packet_append_key(p, &t->query->keys[n], NULL);
355 DNS_PACKET_HEADER(p)->qdcount = htobe16(t->query->n_keys);
356 DNS_PACKET_HEADER(p)->id = t->id;
364 static int dns_query_transaction_go(DnsQueryTransaction *t) {
369 dns_query_transaction_stop(t);
371 if (t->n_attempts >= ATTEMPTS_MAX) {
372 dns_query_transaction_complete(t, DNS_QUERY_ATTEMPTS_MAX);
377 t->received = dns_packet_unref(t->received);
378 t->cached_rrs = dns_resource_record_freev(t->cached_rrs, t->n_cached_rrs);
381 /* First, let's try the cache */
382 dns_cache_prune(&t->scope->cache);
383 r = dns_cache_lookup_many(&t->scope->cache, t->query->keys, t->query->n_keys, &t->cached_rrs);
388 dns_query_transaction_complete(t, DNS_QUERY_SUCCESS);
392 /* Otherwise, we need to ask the network */
393 r = dns_query_make_packet(t);
397 /* Try via UDP, and if that fails due to large size try via TCP */
398 r = dns_scope_send(t->scope, t->sent);
400 r = dns_query_transaction_open_tcp(t);
402 dns_query_transaction_complete(t, DNS_QUERY_NO_SERVERS);
406 /* Couldn't send? Try immediately again, with a new server */
407 dns_scope_next_dns_server(t->scope);
409 return dns_query_transaction_go(t);
412 r = sd_event_add_time(t->query->manager->event, &t->timeout_event_source, CLOCK_MONOTONIC, now(CLOCK_MONOTONIC) + TRANSACTION_TIMEOUT_USEC, 0, on_transaction_timeout, t);
416 t->state = DNS_QUERY_PENDING;
420 DnsQuery *dns_query_free(DnsQuery *q) {
426 sd_bus_message_unref(q->request);
427 dns_packet_unref(q->received);
429 dns_resource_record_freev(q->cached_rrs, q->n_cached_rrs);
431 sd_event_source_unref(q->timeout_event_source);
433 while (q->transactions)
434 dns_query_transaction_free(q->transactions);
437 LIST_REMOVE(queries, q->manager->dns_queries, q);
438 q->manager->n_dns_queries--;
441 for (n = 0; n < q->n_keys; n++)
442 free(q->keys[n].name);
449 int dns_query_new(Manager *m, DnsQuery **ret, DnsResourceKey *keys, unsigned n_keys) {
450 _cleanup_(dns_query_freep) DnsQuery *q = NULL;
451 const char *name = NULL;
455 if (n_keys <= 0 || n_keys >= 65535)
458 if (m->n_dns_queries >= QUERIES_MAX)
463 q = new0(DnsQuery, 1);
467 q->keys = new(DnsResourceKey, n_keys);
471 for (q->n_keys = 0; q->n_keys < n_keys; q->n_keys++) {
472 q->keys[q->n_keys].class = keys[q->n_keys].class;
473 q->keys[q->n_keys].type = keys[q->n_keys].type;
474 q->keys[q->n_keys].name = strdup(keys[q->n_keys].name);
475 if (!q->keys[q->n_keys].name)
479 name = q->keys[q->n_keys].name;
480 else if (!dns_name_equal(name, q->keys[q->n_keys].name))
483 log_debug("Looking up RR for %s %s %s",
484 strna(dns_class_to_string(keys[q->n_keys].class)),
485 strna(dns_type_to_string(keys[q->n_keys].type)),
486 keys[q->n_keys].name);
489 LIST_PREPEND(queries, m->dns_queries, q);
500 static void dns_query_stop(DnsQuery *q) {
503 q->timeout_event_source = sd_event_source_unref(q->timeout_event_source);
505 while (q->transactions)
506 dns_query_transaction_free(q->transactions);
509 static void dns_query_complete(DnsQuery *q, DnsQueryState state) {
511 assert(!IN_SET(state, DNS_QUERY_NULL, DNS_QUERY_PENDING));
512 assert(IN_SET(q->state, DNS_QUERY_NULL, DNS_QUERY_PENDING));
514 /* Note that this call might invalidate the query. Callers
515 * should hence not attempt to access the query or transaction
516 * after calling this function. */
525 static int on_query_timeout(sd_event_source *s, usec_t usec, void *userdata) {
526 DnsQuery *q = userdata;
531 dns_query_complete(q, DNS_QUERY_TIMEOUT);
535 int dns_query_go(DnsQuery *q) {
536 DnsScopeMatch found = DNS_SCOPE_NO;
537 DnsScope *s, *first = NULL;
538 DnsQueryTransaction *t;
543 if (q->state != DNS_QUERY_NULL)
546 assert(q->n_keys > 0);
548 LIST_FOREACH(scopes, s, q->manager->dns_scopes) {
551 match = dns_scope_test(s, q->keys[0].name);
555 if (match == DNS_SCOPE_NO)
560 if (match == DNS_SCOPE_YES) {
564 assert(match == DNS_SCOPE_MAYBE);
571 if (found == DNS_SCOPE_NO)
574 r = dns_query_transaction_new(q, NULL, first);
578 LIST_FOREACH(scopes, s, first->scopes_next) {
581 match = dns_scope_test(s, q->keys[0].name);
588 r = dns_query_transaction_new(q, NULL, s);
593 q->received = dns_packet_unref(q->received);
595 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);
599 q->state = DNS_QUERY_PENDING;
602 LIST_FOREACH(transactions_by_query, t, q->transactions) {
603 r = dns_query_transaction_go(t);
618 void dns_query_finish(DnsQuery *q) {
619 DnsQueryTransaction *t;
620 DnsQueryState state = DNS_QUERY_NO_SERVERS;
621 DnsPacket *received = NULL;
624 assert(IN_SET(q->state, DNS_QUERY_NULL, DNS_QUERY_PENDING));
626 /* Note that this call might invalidate the query. Callers
627 * should hence not attempt to access the query or transaction
628 * after calling this function, unless the block_finish
629 * counter was explicitly bumped before doing so. */
631 if (q->block_finish > 0)
634 LIST_FOREACH(transactions_by_query, t, q->transactions) {
636 /* One of the transactions is still going on, let's wait for it */
637 if (t->state == DNS_QUERY_PENDING || t->state == DNS_QUERY_NULL)
640 /* One of the transactions is successful, let's use
641 * it, and copy its data out */
642 if (t->state == DNS_QUERY_SUCCESS) {
643 q->received = dns_packet_ref(t->received);
645 /* We simply steal the cached RRs array */
646 q->cached_rrs = t->cached_rrs;
647 q->n_cached_rrs = t->n_cached_rrs;
648 t->cached_rrs = NULL;
651 dns_query_complete(q, DNS_QUERY_SUCCESS);
655 /* One of the transactions has failed, let's see
656 * whether we find anything better, but if not, return
657 * its response packet */
658 if (t->state == DNS_QUERY_FAILURE) {
659 received = t->received;
660 state = DNS_QUERY_FAILURE;
664 if (state == DNS_QUERY_NO_SERVERS && t->state != DNS_QUERY_NO_SERVERS)
668 if (state == DNS_QUERY_FAILURE)
669 q->received = dns_packet_ref(received);
671 dns_query_complete(q, state);
674 int dns_query_cname_redirect(DnsQuery *q, const char *name) {
675 DnsResourceKey *keys;
680 if (q->n_cname > CNAME_MAX)
683 keys = new(DnsResourceKey, q->n_keys);
687 for (i = 0; i < q->n_keys; i++) {
688 keys[i].class = q->keys[i].class;
689 keys[i].type = q->keys[i].type;
690 keys[i].name = strdup(name);
694 free(keys[i-1].name);
700 for (i = 0; i < q->n_keys; i++)
701 free(q->keys[i].name);
709 q->state = DNS_QUERY_NULL;
714 int dns_query_matches_rr(DnsQuery *q, DnsResourceRecord *rr) {
721 for (i = 0; i < q->n_keys; i++) {
723 if (rr->key.class != q->keys[i].class)
726 if (rr->key.type != q->keys[i].type &&
727 q->keys[i].type != DNS_TYPE_ANY)
730 r = dns_name_equal(rr->key.name, q->keys[i].name);
738 int dns_query_matches_cname(DnsQuery *q, DnsResourceRecord *rr) {
745 for (i = 0; i < q->n_keys; i++) {
747 if (rr->key.class != q->keys[i].class)
750 if (rr->key.type != DNS_TYPE_CNAME)
753 r = dns_name_equal(rr->key.name, q->keys[i].name);
761 int dns_query_get_rrs(DnsQuery *q, DnsResourceRecord ***rrs) {
767 if (IN_SET(q->state, DNS_QUERY_NULL, DNS_QUERY_PENDING))
771 r = dns_packet_extract_rrs(q->received);
779 *rrs = q->received->rrs;
784 *rrs = q->cached_rrs;
785 return q->n_cached_rrs;
791 int dns_query_get_rcode(DnsQuery *q) {
794 if (IN_SET(q->state, DNS_QUERY_NULL, DNS_QUERY_PENDING))
800 return DNS_PACKET_RCODE(q->received);
803 int dns_query_get_ifindex(DnsQuery *q) {
806 if (IN_SET(q->state, DNS_QUERY_NULL, DNS_QUERY_PENDING))
812 return q->received->ifindex;