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 dns_stream_free(t->stream);
49 LIST_REMOVE(transactions_by_scope, t->scope->transactions, t);
52 hashmap_remove(t->scope->manager->dns_query_transactions, UINT_TO_PTR(t->id));
55 while ((q = set_steal_first(t->queries)))
56 set_remove(q->transactions, t);
64 DEFINE_TRIVIAL_CLEANUP_FUNC(DnsQueryTransaction*, dns_query_transaction_free);
66 static void dns_query_transaction_gc(DnsQueryTransaction *t) {
72 if (set_isempty(t->queries))
73 dns_query_transaction_free(t);
76 static int dns_query_transaction_new(DnsQueryTransaction **ret, DnsScope *s, DnsQuestion *q) {
77 _cleanup_(dns_query_transaction_freep) DnsQueryTransaction *t = NULL;
84 r = hashmap_ensure_allocated(&s->manager->dns_query_transactions, NULL, NULL);
88 t = new0(DnsQueryTransaction, 1);
92 t->question = dns_question_ref(q);
95 random_bytes(&t->id, sizeof(t->id));
97 hashmap_get(s->manager->dns_query_transactions, UINT_TO_PTR(t->id)));
99 r = hashmap_put(s->manager->dns_query_transactions, UINT_TO_PTR(t->id), t);
105 LIST_PREPEND(transactions_by_scope, s->transactions, t);
116 static void dns_query_transaction_stop(DnsQueryTransaction *t) {
119 t->timeout_event_source = sd_event_source_unref(t->timeout_event_source);
120 t->stream = dns_stream_free(t->stream);
123 void dns_query_transaction_complete(DnsQueryTransaction *t, DnsQueryState state) {
128 assert(!IN_SET(state, DNS_QUERY_NULL, DNS_QUERY_PENDING));
129 assert(IN_SET(t->state, DNS_QUERY_NULL, DNS_QUERY_PENDING));
131 /* Note that this call might invalidate the query. Callers
132 * should hence not attempt to access the query or transaction
133 * after calling this function. */
137 dns_query_transaction_stop(t);
139 /* Notify all queries that are interested, but make sure the
140 * transaction isn't freed while we are still looking at it */
142 SET_FOREACH(q, t->queries, i)
146 dns_query_transaction_gc(t);
149 static int on_stream_complete(DnsStream *s, int error) {
150 _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
151 DnsQueryTransaction *t;
154 assert(s->transaction);
156 /* Copy the data we care about out of the stream before we
159 p = dns_packet_ref(s->read_packet);
161 t->stream = dns_stream_free(t->stream);
164 dns_query_transaction_complete(t, DNS_QUERY_RESOURCES);
169 dns_query_transaction_process_reply(t, p);
172 /* If the response wasn't useful, then complete the transition now */
173 if (t->state == DNS_QUERY_PENDING)
174 dns_query_transaction_complete(t, DNS_QUERY_INVALID_REPLY);
179 static int dns_query_transaction_open_tcp(DnsQueryTransaction *t) {
180 _cleanup_close_ int fd = -1;
188 if (t->scope->protocol == DNS_PROTOCOL_DNS)
189 fd = dns_scope_tcp_socket(t->scope, AF_UNSPEC, NULL, 53);
190 else if (t->scope->protocol == DNS_PROTOCOL_LLMNR) {
192 /* When we already received a query to this (but it was truncated), send to its sender address */
194 fd = dns_scope_tcp_socket(t->scope, t->received->family, &t->received->sender, t->received->sender_port);
196 union in_addr_union address;
199 /* Otherwise, try to talk to the owner of a
200 * the IP address, in case this is a reverse
202 r = dns_question_extract_reverse_address(t->question, &family, &address);
208 fd = dns_scope_tcp_socket(t->scope, family, &address, 5355);
211 return -EAFNOSUPPORT;
216 r = dns_stream_new(t->scope->manager, &t->stream, t->scope->protocol, fd);
222 r = dns_stream_write_packet(t->stream, t->sent);
224 t->stream = dns_stream_free(t->stream);
228 t->received = dns_packet_unref(t->received);
229 t->stream->complete = on_stream_complete;
230 t->stream->transaction = t;
232 /* The interface index is difficult to determine if we are
233 * connecting to the local host, hence fill this in right away
234 * instead of determining it from the socket */
236 t->stream->ifindex = t->scope->link->ifindex;
241 void dns_query_transaction_process_reply(DnsQueryTransaction *t, DnsPacket *p) {
246 assert(t->state == DNS_QUERY_PENDING);
248 /* Note that this call might invalidate the query. Callers
249 * should hence not attempt to access the query or transaction
250 * after calling this function. */
252 if (t->scope->protocol == DNS_PROTOCOL_LLMNR) {
253 assert(t->scope->link);
255 /* For LLMNR we will not accept any packets from other
258 if (p->ifindex != t->scope->link->ifindex)
261 if (p->family != t->scope->family)
264 if (p->ipproto == IPPROTO_UDP) {
265 if (p->family == AF_INET && !in_addr_equal(AF_INET, &p->destination, (union in_addr_union*) &LLMNR_MULTICAST_IPV4_ADDRESS))
268 if (p->family == AF_INET6 && !in_addr_equal(AF_INET6, &p->destination, (union in_addr_union*) &LLMNR_MULTICAST_IPV6_ADDRESS))
273 if (t->scope->protocol == DNS_PROTOCOL_DNS) {
275 /* For DNS we are fine with accepting packets on any
276 * interface, but the source IP address must be one of
277 * a valid DNS server */
279 if (!dns_scope_good_dns_server(t->scope, p->family, &p->sender))
282 if (p->sender_port != 53)
286 if (t->received != p) {
287 dns_packet_unref(t->received);
288 t->received = dns_packet_ref(p);
291 if (p->ipproto == IPPROTO_TCP) {
292 if (DNS_PACKET_TC(p)) {
293 /* Truncated via TCP? Somebody must be fucking with us */
294 dns_query_transaction_complete(t, DNS_QUERY_INVALID_REPLY);
298 if (DNS_PACKET_ID(p) != t->id) {
299 /* Not the reply to our query? Somebody must be fucking with us */
300 dns_query_transaction_complete(t, DNS_QUERY_INVALID_REPLY);
305 if (DNS_PACKET_TC(p)) {
306 /* Response was truncated, let's try again with good old TCP */
307 r = dns_query_transaction_open_tcp(t);
309 /* No servers found? Damn! */
310 dns_query_transaction_complete(t, DNS_QUERY_NO_SERVERS);
314 /* On LLMNR, if we cannot connect to the host,
315 * we immediately give up */
316 if (t->scope->protocol == DNS_PROTOCOL_LLMNR) {
317 dns_query_transaction_complete(t, DNS_QUERY_RESOURCES);
321 /* On DNS, couldn't send? Try immediately again, with a new server */
322 dns_scope_next_dns_server(t->scope);
324 r = dns_query_transaction_go(t);
326 dns_query_transaction_complete(t, DNS_QUERY_RESOURCES);
334 /* Parse and update the cache */
335 r = dns_packet_extract(p);
337 dns_query_transaction_complete(t, DNS_QUERY_INVALID_REPLY);
341 dns_cache_put(&t->scope->cache, p->question, DNS_PACKET_RCODE(p), p->answer, 0);
343 if (DNS_PACKET_RCODE(p) == DNS_RCODE_SUCCESS)
344 dns_query_transaction_complete(t, DNS_QUERY_SUCCESS);
346 dns_query_transaction_complete(t, DNS_QUERY_FAILURE);
349 static int on_transaction_timeout(sd_event_source *s, usec_t usec, void *userdata) {
350 DnsQueryTransaction *t = userdata;
356 /* Timeout reached? Try again, with a new server */
357 dns_scope_next_dns_server(t->scope);
359 r = dns_query_transaction_go(t);
361 dns_query_transaction_complete(t, DNS_QUERY_RESOURCES);
366 static int dns_query_make_packet(DnsQueryTransaction *t) {
367 _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
368 unsigned n, added = 0;
376 r = dns_packet_new_query(&p, t->scope->protocol, 0);
380 for (n = 0; n < t->question->n_keys; n++) {
381 r = dns_scope_good_key(t->scope, t->question->keys[n]);
387 r = dns_packet_append_key(p, t->question->keys[n], NULL);
397 DNS_PACKET_HEADER(p)->qdcount = htobe16(added);
398 DNS_PACKET_HEADER(p)->id = t->id;
406 static int dns_query_transaction_go(DnsQueryTransaction *t) {
411 dns_query_transaction_stop(t);
413 if (t->n_attempts >= ATTEMPTS_MAX) {
414 dns_query_transaction_complete(t, DNS_QUERY_ATTEMPTS_MAX);
419 t->received = dns_packet_unref(t->received);
420 t->cached = dns_answer_unref(t->cached);
423 /* First, let's try the cache */
424 dns_cache_prune(&t->scope->cache);
425 r = dns_cache_lookup(&t->scope->cache, t->question, &t->cached_rcode, &t->cached);
429 if (t->cached_rcode == DNS_RCODE_SUCCESS)
430 dns_query_transaction_complete(t, DNS_QUERY_SUCCESS);
432 dns_query_transaction_complete(t, DNS_QUERY_FAILURE);
436 /* Otherwise, we need to ask the network */
437 r = dns_query_make_packet(t);
439 /* Not the right request to make on this network?
440 * (i.e. an A request made on IPv6 or an AAAA request
441 * made on IPv4, on LLMNR or mDNS.) */
442 dns_query_transaction_complete(t, DNS_QUERY_NO_SERVERS);
448 if (t->scope->protocol == DNS_PROTOCOL_LLMNR &&
449 (dns_question_endswith(t->question, "in-addr.arpa") > 0 ||
450 dns_question_endswith(t->question, "ip6.arpa") > 0)) {
452 /* RFC 4795, Section 2.4. says reverse lookups shall
453 * always be made via TCP on LLMNR */
454 r = dns_query_transaction_open_tcp(t);
456 /* Try via UDP, and if that fails due to large size try via TCP */
457 r = dns_scope_send(t->scope, t->sent);
459 r = dns_query_transaction_open_tcp(t);
462 /* No servers to send this to? */
463 dns_query_transaction_complete(t, DNS_QUERY_NO_SERVERS);
467 /* Couldn't send? Try immediately again, with a new server */
468 dns_scope_next_dns_server(t->scope);
470 return dns_query_transaction_go(t);
473 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);
477 t->state = DNS_QUERY_PENDING;
481 DnsQuery *dns_query_free(DnsQuery *q) {
482 DnsQueryTransaction *t;
487 sd_bus_message_unref(q->request);
489 dns_question_unref(q->question);
490 dns_answer_unref(q->answer);
492 sd_event_source_unref(q->timeout_event_source);
494 while ((t = set_steal_first(q->transactions))) {
495 set_remove(t->queries, q);
496 dns_query_transaction_gc(t);
499 set_free(q->transactions);
502 LIST_REMOVE(queries, q->manager->dns_queries, q);
503 q->manager->n_dns_queries--;
511 int dns_query_new(Manager *m, DnsQuery **ret, DnsQuestion *question) {
512 _cleanup_(dns_query_freep) DnsQuery *q = NULL;
519 r = dns_question_is_valid(question);
523 if (m->n_dns_queries >= QUERIES_MAX)
526 q = new0(DnsQuery, 1);
530 q->question = dns_question_ref(question);
532 for (i = 0; i < question->n_keys; i++) {
533 log_debug("Looking up RR for %s %s %s",
534 strna(dns_class_to_string(question->keys[i]->class)),
535 strna(dns_type_to_string(question->keys[i]->type)),
536 DNS_RESOURCE_KEY_NAME(question->keys[i]));
539 LIST_PREPEND(queries, m->dns_queries, q);
550 static void dns_query_stop(DnsQuery *q) {
551 DnsQueryTransaction *t;
555 q->timeout_event_source = sd_event_source_unref(q->timeout_event_source);
557 while ((t = set_steal_first(q->transactions))) {
558 set_remove(t->queries, q);
559 dns_query_transaction_gc(t);
563 static void dns_query_complete(DnsQuery *q, DnsQueryState state) {
565 assert(!IN_SET(state, DNS_QUERY_NULL, DNS_QUERY_PENDING));
566 assert(IN_SET(q->state, DNS_QUERY_NULL, DNS_QUERY_PENDING));
568 /* Note that this call might invalidate the query. Callers
569 * should hence not attempt to access the query or transaction
570 * after calling this function. */
579 static int on_query_timeout(sd_event_source *s, usec_t usec, void *userdata) {
580 DnsQuery *q = userdata;
585 dns_query_complete(q, DNS_QUERY_TIMEOUT);
589 static int dns_query_add_transaction(DnsQuery *q, DnsScope *s, DnsResourceKey *key) {
590 _cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
591 DnsQueryTransaction *t;
596 r = set_ensure_allocated(&q->transactions, NULL, NULL);
601 question = dns_question_new(1);
605 r = dns_question_add(question, key);
609 question = dns_question_ref(q->question);
611 LIST_FOREACH(transactions_by_scope, t, s->transactions)
612 if (dns_question_is_superset(t->question, question))
616 r = dns_query_transaction_new(&t, s, question);
621 r = set_ensure_allocated(&t->queries, NULL, NULL);
625 r = set_put(t->queries, q);
629 r = set_put(q->transactions, t);
631 set_remove(t->queries, q);
638 dns_query_transaction_gc(t);
642 static int dns_query_add_transaction_split(DnsQuery *q, DnsScope *s) {
648 if (s->protocol == DNS_PROTOCOL_MDNS) {
649 r = dns_query_add_transaction(q, s, NULL);
655 /* On DNS and LLMNR we can only send a single
656 * question per datagram, hence issue multiple
659 for (i = 0; i < q->question->n_keys; i++) {
660 r = dns_query_add_transaction(q, s, q->question->keys[i]);
669 int dns_query_go(DnsQuery *q) {
670 DnsScopeMatch found = DNS_SCOPE_NO;
671 DnsScope *s, *first = NULL;
672 DnsQueryTransaction *t;
679 if (q->state != DNS_QUERY_NULL)
683 assert(q->question->n_keys > 0);
685 name = DNS_RESOURCE_KEY_NAME(q->question->keys[0]);
687 LIST_FOREACH(scopes, s, q->manager->dns_scopes) {
690 match = dns_scope_good_domain(s, name);
694 if (match == DNS_SCOPE_NO)
699 if (match == DNS_SCOPE_YES) {
703 assert(match == DNS_SCOPE_MAYBE);
710 if (found == DNS_SCOPE_NO)
713 r = dns_query_add_transaction_split(q, first);
717 LIST_FOREACH(scopes, s, first->scopes_next) {
720 match = dns_scope_good_domain(s, name);
727 r = dns_query_add_transaction_split(q, s);
732 q->answer = dns_answer_unref(q->answer);
733 q->answer_ifindex = 0;
736 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);
740 q->state = DNS_QUERY_PENDING;
743 SET_FOREACH(t, q->transactions, i) {
744 if (t->state == DNS_QUERY_NULL) {
745 r = dns_query_transaction_go(t);
761 void dns_query_ready(DnsQuery *q) {
762 DnsQueryTransaction *t;
763 DnsQueryState state = DNS_QUERY_NO_SERVERS;
764 _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
766 DnsScope *scope = NULL;
770 assert(IN_SET(q->state, DNS_QUERY_NULL, DNS_QUERY_PENDING));
772 /* Note that this call might invalidate the query. Callers
773 * should hence not attempt to access the query or transaction
774 * after calling this function, unless the block_ready
775 * counter was explicitly bumped before doing so. */
777 if (q->block_ready > 0)
780 SET_FOREACH(t, q->transactions, i) {
782 /* If we found a successful answer, ignore all answers from other scopes */
783 if (state == DNS_QUERY_SUCCESS && t->scope != scope)
786 /* One of the transactions is still going on, let's wait for it */
787 if (t->state == DNS_QUERY_PENDING || t->state == DNS_QUERY_NULL)
790 /* One of the transactions is successful, let's use
791 * it, and copy its data out */
792 if (t->state == DNS_QUERY_SUCCESS) {
796 rcode = DNS_PACKET_RCODE(t->received);
797 a = t->received->answer;
799 rcode = t->cached_rcode;
803 if (state == DNS_QUERY_SUCCESS) {
806 merged = dns_answer_merge(answer, a);
808 dns_query_complete(q, DNS_QUERY_RESOURCES);
812 dns_answer_unref(answer);
815 dns_answer_unref(answer);
816 answer = dns_answer_ref(a);
820 state = DNS_QUERY_SUCCESS;
824 /* One of the transactions has failed, let's see
825 * whether we find anything better, but if not, return
826 * its response data */
827 if (state != DNS_QUERY_SUCCESS && t->state == DNS_QUERY_FAILURE) {
831 rcode = DNS_PACKET_RCODE(t->received);
832 a = t->received->answer;
834 rcode = t->cached_rcode;
838 dns_answer_unref(answer);
839 answer = dns_answer_ref(a);
842 state = DNS_QUERY_FAILURE;
846 if (state == DNS_QUERY_NO_SERVERS && t->state != DNS_QUERY_NO_SERVERS)
850 if (IN_SET(state, DNS_QUERY_SUCCESS, DNS_QUERY_FAILURE)) {
851 q->answer = dns_answer_ref(answer);
852 q->answer_rcode = rcode;
853 q->answer_ifindex = (scope && scope->link) ? scope->link->ifindex : 0;
856 dns_query_complete(q, state);
859 int dns_query_cname_redirect(DnsQuery *q, const char *name) {
860 _cleanup_(dns_question_unrefp) DnsQuestion *nq = NULL;
865 if (q->n_cname_redirects > CNAME_MAX)
868 r = dns_question_cname_redirect(q->question, name, &nq);
872 dns_question_unref(q->question);
876 q->n_cname_redirects++;
879 q->state = DNS_QUERY_NULL;