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, t->scope->protocol, 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) {
232 if (t->scope->protocol == DNS_PROTOCOL_DNS)
240 t->received = dns_packet_unref(t->received);
242 t->tcp_fd = dns_scope_tcp_socket(t->scope);
246 r = sd_event_add_io(t->query->manager->event, &t->tcp_event_source, t->tcp_fd, EPOLLIN|EPOLLOUT, on_tcp_ready, t);
248 t->tcp_fd = safe_close(t->tcp_fd);
255 void dns_query_transaction_reply(DnsQueryTransaction *t, DnsPacket *p) {
260 assert(t->state == DNS_QUERY_PENDING);
262 /* Note that this call might invalidate the query. Callers
263 * should hence not attempt to access the query or transaction
264 * after calling this function. */
266 if (t->received != p) {
267 dns_packet_unref(t->received);
268 t->received = dns_packet_ref(p);
271 if (t->tcp_fd >= 0) {
272 if (DNS_PACKET_TC(p)) {
273 /* Truncated via TCP? Somebody must be fucking with us */
274 dns_query_transaction_complete(t, DNS_QUERY_INVALID_REPLY);
278 if (DNS_PACKET_ID(p) != t->id) {
279 /* Not the reply to our query? Somebody must be fucking with us */
280 dns_query_transaction_complete(t, DNS_QUERY_INVALID_REPLY);
285 if (DNS_PACKET_TC(p)) {
286 /* Response was truncated, let's try again with good old TCP */
287 r = dns_query_transaction_open_tcp(t);
289 /* No servers found? Damn! */
290 dns_query_transaction_complete(t, DNS_QUERY_NO_SERVERS);
294 /* Couldn't send? Try immediately again, with a new server */
295 dns_scope_next_dns_server(t->scope);
297 r = dns_query_transaction_go(t);
299 dns_query_transaction_complete(t, DNS_QUERY_RESOURCES);
307 /* Parse and update the cache */
308 r = dns_packet_extract_rrs(p);
310 dns_query_transaction_complete(t, DNS_QUERY_INVALID_REPLY);
313 dns_cache_put_rrs(&t->scope->cache, p->rrs, r, 0);
315 if (DNS_PACKET_RCODE(p) == DNS_RCODE_SUCCESS)
316 dns_query_transaction_complete(t, DNS_QUERY_SUCCESS);
318 dns_query_transaction_complete(t, DNS_QUERY_FAILURE);
321 static int on_transaction_timeout(sd_event_source *s, usec_t usec, void *userdata) {
322 DnsQueryTransaction *t = userdata;
328 /* Timeout reached? Try again, with a new server */
329 dns_scope_next_dns_server(t->scope);
331 r = dns_query_transaction_go(t);
333 dns_query_transaction_complete(t, DNS_QUERY_RESOURCES);
338 static int dns_query_make_packet(DnsQueryTransaction *t) {
339 _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
340 unsigned n, added = 0;
348 r = dns_packet_new_query(&p, t->scope->protocol, 0);
352 for (n = 0; n < t->query->n_keys; n++) {
353 r = dns_scope_good_key(t->scope, &t->query->keys[n]);
359 r = dns_packet_append_key(p, &t->query->keys[n], NULL);
369 DNS_PACKET_HEADER(p)->qdcount = htobe16(added);
370 DNS_PACKET_HEADER(p)->id = t->id;
378 static int dns_query_transaction_go(DnsQueryTransaction *t) {
383 dns_query_transaction_stop(t);
385 if (t->n_attempts >= ATTEMPTS_MAX) {
386 dns_query_transaction_complete(t, DNS_QUERY_ATTEMPTS_MAX);
391 t->received = dns_packet_unref(t->received);
392 t->cached_rrs = dns_resource_record_freev(t->cached_rrs, t->n_cached_rrs);
395 /* First, let's try the cache */
396 dns_cache_prune(&t->scope->cache);
397 r = dns_cache_lookup_many(&t->scope->cache, t->query->keys, t->query->n_keys, &t->cached_rrs);
402 dns_query_transaction_complete(t, DNS_QUERY_SUCCESS);
406 /* Otherwise, we need to ask the network */
407 r = dns_query_make_packet(t);
409 /* Not the right request to make on this network?
410 * (i.e. an A request made on IPv6 or an AAAA request
411 * made on IPv4, on LLMNR or mDNS.) */
412 dns_query_transaction_complete(t, DNS_QUERY_NO_SERVERS);
418 /* Try via UDP, and if that fails due to large size try via TCP */
419 r = dns_scope_send(t->scope, t->sent);
421 r = dns_query_transaction_open_tcp(t);
423 /* No servers to send this to? */
424 dns_query_transaction_complete(t, DNS_QUERY_NO_SERVERS);
428 /* Couldn't send? Try immediately again, with a new server */
429 dns_scope_next_dns_server(t->scope);
431 return dns_query_transaction_go(t);
434 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);
438 t->state = DNS_QUERY_PENDING;
442 DnsQuery *dns_query_free(DnsQuery *q) {
448 sd_bus_message_unref(q->request);
449 dns_packet_unref(q->received);
451 dns_resource_record_freev(q->cached_rrs, q->n_cached_rrs);
453 sd_event_source_unref(q->timeout_event_source);
455 while (q->transactions)
456 dns_query_transaction_free(q->transactions);
459 LIST_REMOVE(queries, q->manager->dns_queries, q);
460 q->manager->n_dns_queries--;
463 for (n = 0; n < q->n_keys; n++)
464 free(q->keys[n].name);
471 int dns_query_new(Manager *m, DnsQuery **ret, DnsResourceKey *keys, unsigned n_keys) {
472 _cleanup_(dns_query_freep) DnsQuery *q = NULL;
473 const char *name = NULL;
477 if (n_keys <= 0 || n_keys >= 65535)
480 if (m->n_dns_queries >= QUERIES_MAX)
485 q = new0(DnsQuery, 1);
489 q->keys = new(DnsResourceKey, n_keys);
493 for (q->n_keys = 0; q->n_keys < n_keys; q->n_keys++) {
494 q->keys[q->n_keys].class = keys[q->n_keys].class;
495 q->keys[q->n_keys].type = keys[q->n_keys].type;
496 q->keys[q->n_keys].name = strdup(keys[q->n_keys].name);
497 if (!q->keys[q->n_keys].name)
501 name = q->keys[q->n_keys].name;
502 else if (!dns_name_equal(name, q->keys[q->n_keys].name))
505 log_debug("Looking up RR for %s %s %s",
506 strna(dns_class_to_string(keys[q->n_keys].class)),
507 strna(dns_type_to_string(keys[q->n_keys].type)),
508 keys[q->n_keys].name);
511 LIST_PREPEND(queries, m->dns_queries, q);
522 static void dns_query_stop(DnsQuery *q) {
525 q->timeout_event_source = sd_event_source_unref(q->timeout_event_source);
527 while (q->transactions)
528 dns_query_transaction_free(q->transactions);
531 static void dns_query_complete(DnsQuery *q, DnsQueryState state) {
533 assert(!IN_SET(state, DNS_QUERY_NULL, DNS_QUERY_PENDING));
534 assert(IN_SET(q->state, DNS_QUERY_NULL, DNS_QUERY_PENDING));
536 /* Note that this call might invalidate the query. Callers
537 * should hence not attempt to access the query or transaction
538 * after calling this function. */
547 static int on_query_timeout(sd_event_source *s, usec_t usec, void *userdata) {
548 DnsQuery *q = userdata;
553 dns_query_complete(q, DNS_QUERY_TIMEOUT);
557 int dns_query_go(DnsQuery *q) {
558 DnsScopeMatch found = DNS_SCOPE_NO;
559 DnsScope *s, *first = NULL;
560 DnsQueryTransaction *t;
565 if (q->state != DNS_QUERY_NULL)
568 assert(q->n_keys > 0);
570 LIST_FOREACH(scopes, s, q->manager->dns_scopes) {
573 match = dns_scope_good_domain(s, q->keys[0].name);
577 if (match == DNS_SCOPE_NO)
582 if (match == DNS_SCOPE_YES) {
586 assert(match == DNS_SCOPE_MAYBE);
593 if (found == DNS_SCOPE_NO)
596 r = dns_query_transaction_new(q, NULL, first);
600 LIST_FOREACH(scopes, s, first->scopes_next) {
603 match = dns_scope_good_domain(s, q->keys[0].name);
610 r = dns_query_transaction_new(q, NULL, s);
615 q->received = dns_packet_unref(q->received);
617 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);
621 q->state = DNS_QUERY_PENDING;
624 LIST_FOREACH(transactions_by_query, t, q->transactions) {
625 r = dns_query_transaction_go(t);
640 void dns_query_finish(DnsQuery *q) {
641 DnsQueryTransaction *t;
642 DnsQueryState state = DNS_QUERY_NO_SERVERS;
643 DnsPacket *received = NULL;
646 assert(IN_SET(q->state, DNS_QUERY_NULL, DNS_QUERY_PENDING));
648 /* Note that this call might invalidate the query. Callers
649 * should hence not attempt to access the query or transaction
650 * after calling this function, unless the block_finish
651 * counter was explicitly bumped before doing so. */
653 if (q->block_finish > 0)
656 LIST_FOREACH(transactions_by_query, t, q->transactions) {
658 /* One of the transactions is still going on, let's wait for it */
659 if (t->state == DNS_QUERY_PENDING || t->state == DNS_QUERY_NULL)
662 /* One of the transactions is successful, let's use
663 * it, and copy its data out */
664 if (t->state == DNS_QUERY_SUCCESS) {
665 q->received = dns_packet_ref(t->received);
667 /* We simply steal the cached RRs array */
668 q->cached_rrs = t->cached_rrs;
669 q->n_cached_rrs = t->n_cached_rrs;
670 t->cached_rrs = NULL;
673 dns_query_complete(q, DNS_QUERY_SUCCESS);
677 /* One of the transactions has failed, let's see
678 * whether we find anything better, but if not, return
679 * its response packet */
680 if (t->state == DNS_QUERY_FAILURE) {
681 received = t->received;
682 state = DNS_QUERY_FAILURE;
686 if (state == DNS_QUERY_NO_SERVERS && t->state != DNS_QUERY_NO_SERVERS)
690 if (state == DNS_QUERY_FAILURE)
691 q->received = dns_packet_ref(received);
693 dns_query_complete(q, state);
696 int dns_query_cname_redirect(DnsQuery *q, const char *name) {
697 DnsResourceKey *keys;
702 if (q->n_cname > CNAME_MAX)
705 keys = new(DnsResourceKey, q->n_keys);
709 for (i = 0; i < q->n_keys; i++) {
710 keys[i].class = q->keys[i].class;
711 keys[i].type = q->keys[i].type;
712 keys[i].name = strdup(name);
716 free(keys[i-1].name);
722 for (i = 0; i < q->n_keys; i++)
723 free(q->keys[i].name);
731 q->state = DNS_QUERY_NULL;
736 int dns_query_matches_rr(DnsQuery *q, DnsResourceRecord *rr) {
743 for (i = 0; i < q->n_keys; i++) {
745 if (rr->key.class != q->keys[i].class)
748 if (rr->key.type != q->keys[i].type &&
749 q->keys[i].type != DNS_TYPE_ANY)
752 r = dns_name_equal(rr->key.name, q->keys[i].name);
760 int dns_query_matches_cname(DnsQuery *q, DnsResourceRecord *rr) {
767 for (i = 0; i < q->n_keys; i++) {
769 if (rr->key.class != q->keys[i].class)
772 if (rr->key.type != DNS_TYPE_CNAME)
775 r = dns_name_equal(rr->key.name, q->keys[i].name);
783 int dns_query_get_rrs(DnsQuery *q, DnsResourceRecord ***rrs) {
789 if (IN_SET(q->state, DNS_QUERY_NULL, DNS_QUERY_PENDING))
793 r = dns_packet_extract_rrs(q->received);
801 *rrs = q->received->rrs;
806 *rrs = q->cached_rrs;
807 return q->n_cached_rrs;
813 int dns_query_get_rcode(DnsQuery *q) {
816 if (IN_SET(q->state, DNS_QUERY_NULL, DNS_QUERY_PENDING))
822 return DNS_PACKET_RCODE(q->received);
825 int dns_query_get_ifindex(DnsQuery *q) {
828 if (IN_SET(q->state, DNS_QUERY_NULL, DNS_QUERY_PENDING))
834 return q->received->ifindex;