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/>.
24 #include "resolved-dns-transaction.h"
26 DnsTransaction* dns_transaction_free(DnsTransaction *t) {
33 sd_event_source_unref(t->timeout_event_source);
35 dns_question_unref(t->question);
36 dns_packet_unref(t->sent);
37 dns_packet_unref(t->received);
38 dns_answer_unref(t->cached);
40 dns_stream_free(t->stream);
43 LIST_REMOVE(transactions_by_scope, t->scope->transactions, t);
46 hashmap_remove(t->scope->manager->dns_transactions, UINT_TO_PTR(t->id));
49 while ((q = set_steal_first(t->queries)))
50 set_remove(q->transactions, t);
53 while ((i = set_steal_first(t->zone_items)))
54 i->probe_transaction = NULL;
55 set_free(t->zone_items);
61 DEFINE_TRIVIAL_CLEANUP_FUNC(DnsTransaction*, dns_transaction_free);
63 void dns_transaction_gc(DnsTransaction *t) {
69 if (set_isempty(t->queries) && set_isempty(t->zone_items))
70 dns_transaction_free(t);
73 int dns_transaction_new(DnsTransaction **ret, DnsScope *s, DnsQuestion *q) {
74 _cleanup_(dns_transaction_freep) DnsTransaction *t = NULL;
81 r = hashmap_ensure_allocated(&s->manager->dns_transactions, NULL, NULL);
85 t = new0(DnsTransaction, 1);
89 t->question = dns_question_ref(q);
92 random_bytes(&t->id, sizeof(t->id));
94 hashmap_get(s->manager->dns_transactions, UINT_TO_PTR(t->id)));
96 r = hashmap_put(s->manager->dns_transactions, UINT_TO_PTR(t->id), t);
102 LIST_PREPEND(transactions_by_scope, s->transactions, t);
113 static void dns_transaction_stop(DnsTransaction *t) {
116 t->timeout_event_source = sd_event_source_unref(t->timeout_event_source);
117 t->stream = dns_stream_free(t->stream);
120 static void dns_transaction_tentative(DnsTransaction *t, DnsPacket *p) {
127 if (manager_our_packet(t->scope->manager, p) != 0)
130 log_debug("Transaction on scope %s on %s/%s got tentative packet",
131 dns_protocol_to_string(t->scope->protocol),
132 t->scope->link ? t->scope->link->name : "*",
133 t->scope->family == AF_UNSPEC ? "*" : af_to_name(t->scope->family));
136 SET_FOREACH(z, t->zone_items, i)
137 dns_zone_item_conflict(z);
140 dns_transaction_gc(t);
143 void dns_transaction_complete(DnsTransaction *t, DnsTransactionState state) {
149 assert(!IN_SET(state, DNS_TRANSACTION_NULL, DNS_TRANSACTION_PENDING));
150 assert(IN_SET(t->state, DNS_TRANSACTION_NULL, DNS_TRANSACTION_PENDING));
152 /* Note that this call might invalidate the query. Callers
153 * should hence not attempt to access the query or transaction
154 * after calling this function. */
156 log_debug("Transaction on scope %s on %s/%s now complete with <%s>",
157 dns_protocol_to_string(t->scope->protocol),
158 t->scope->link ? t->scope->link->name : "*",
159 t->scope->family == AF_UNSPEC ? "*" : af_to_name(t->scope->family),
160 dns_transaction_state_to_string(state));
164 dns_transaction_stop(t);
166 /* Notify all queries that are interested, but make sure the
167 * transaction isn't freed while we are still looking at it */
169 SET_FOREACH(q, t->queries, i)
171 SET_FOREACH(z, t->zone_items, i)
172 dns_zone_item_ready(z);
175 dns_transaction_gc(t);
178 static int on_stream_complete(DnsStream *s, int error) {
179 _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
183 assert(s->transaction);
185 /* Copy the data we care about out of the stream before we
188 p = dns_packet_ref(s->read_packet);
190 t->stream = dns_stream_free(t->stream);
193 dns_transaction_complete(t, DNS_TRANSACTION_RESOURCES);
198 dns_transaction_process_reply(t, p);
201 /* If the response wasn't useful, then complete the transition now */
202 if (t->state == DNS_TRANSACTION_PENDING)
203 dns_transaction_complete(t, DNS_TRANSACTION_INVALID_REPLY);
208 static int dns_transaction_open_tcp(DnsTransaction *t) {
209 _cleanup_close_ int fd = -1;
217 if (t->scope->protocol == DNS_PROTOCOL_DNS)
218 fd = dns_scope_tcp_socket(t->scope, AF_UNSPEC, NULL, 53);
219 else if (t->scope->protocol == DNS_PROTOCOL_LLMNR) {
221 /* When we already received a query to this (but it was truncated), send to its sender address */
223 fd = dns_scope_tcp_socket(t->scope, t->received->family, &t->received->sender, t->received->sender_port);
225 union in_addr_union address;
228 /* Otherwise, try to talk to the owner of a
229 * the IP address, in case this is a reverse
231 r = dns_question_extract_reverse_address(t->question, &family, &address);
237 fd = dns_scope_tcp_socket(t->scope, family, &address, 5355);
240 return -EAFNOSUPPORT;
245 r = dns_stream_new(t->scope->manager, &t->stream, t->scope->protocol, fd);
251 r = dns_stream_write_packet(t->stream, t->sent);
253 t->stream = dns_stream_free(t->stream);
257 t->received = dns_packet_unref(t->received);
258 t->stream->complete = on_stream_complete;
259 t->stream->transaction = t;
261 /* The interface index is difficult to determine if we are
262 * connecting to the local host, hence fill this in right away
263 * instead of determining it from the socket */
265 t->stream->ifindex = t->scope->link->ifindex;
270 void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) {
275 assert(t->state == DNS_TRANSACTION_PENDING);
277 /* Note that this call might invalidate the query. Callers
278 * should hence not attempt to access the query or transaction
279 * after calling this function. */
281 if (t->scope->protocol == DNS_PROTOCOL_LLMNR) {
282 assert(t->scope->link);
284 /* For LLMNR we will not accept any packets from other
287 if (p->ifindex != t->scope->link->ifindex)
290 if (p->family != t->scope->family)
293 /* Tentative packets are not full responses but still
294 * useful for identifying uniqueness conflicts during
296 if (DNS_PACKET_T(p)) {
297 dns_transaction_tentative(t, p);
302 if (t->scope->protocol == DNS_PROTOCOL_DNS) {
304 /* For DNS we are fine with accepting packets on any
305 * interface, but the source IP address must be one of
306 * a valid DNS server */
308 if (!dns_scope_good_dns_server(t->scope, p->family, &p->sender))
311 if (p->sender_port != 53)
315 if (t->received != p) {
316 dns_packet_unref(t->received);
317 t->received = dns_packet_ref(p);
320 if (p->ipproto == IPPROTO_TCP) {
321 if (DNS_PACKET_TC(p)) {
322 /* Truncated via TCP? Somebody must be fucking with us */
323 dns_transaction_complete(t, DNS_TRANSACTION_INVALID_REPLY);
327 if (DNS_PACKET_ID(p) != t->id) {
328 /* Not the reply to our query? Somebody must be fucking with us */
329 dns_transaction_complete(t, DNS_TRANSACTION_INVALID_REPLY);
334 if (DNS_PACKET_TC(p)) {
335 /* Response was truncated, let's try again with good old TCP */
336 r = dns_transaction_open_tcp(t);
338 /* No servers found? Damn! */
339 dns_transaction_complete(t, DNS_TRANSACTION_NO_SERVERS);
343 /* On LLMNR, if we cannot connect to the host,
344 * we immediately give up */
345 if (t->scope->protocol == DNS_PROTOCOL_LLMNR) {
346 dns_transaction_complete(t, DNS_TRANSACTION_RESOURCES);
350 /* On DNS, couldn't send? Try immediately again, with a new server */
351 dns_scope_next_dns_server(t->scope);
353 r = dns_transaction_go(t);
355 dns_transaction_complete(t, DNS_TRANSACTION_RESOURCES);
363 /* Parse and update the cache */
364 r = dns_packet_extract(p);
366 dns_transaction_complete(t, DNS_TRANSACTION_INVALID_REPLY);
370 /* According to RFC 4795, section 2.9. only the RRs from the answer section shall be cached */
371 dns_cache_put(&t->scope->cache, p->question, DNS_PACKET_RCODE(p), p->answer, DNS_PACKET_ANCOUNT(p), 0);
373 if (DNS_PACKET_RCODE(p) == DNS_RCODE_SUCCESS)
374 dns_transaction_complete(t, DNS_TRANSACTION_SUCCESS);
376 dns_transaction_complete(t, DNS_TRANSACTION_FAILURE);
379 static int on_transaction_timeout(sd_event_source *s, usec_t usec, void *userdata) {
380 DnsTransaction *t = userdata;
386 /* Timeout reached? Try again, with a new server */
387 dns_scope_next_dns_server(t->scope);
389 r = dns_transaction_go(t);
391 dns_transaction_complete(t, DNS_TRANSACTION_RESOURCES);
396 static int dns_transaction_make_packet(DnsTransaction *t) {
397 _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
398 unsigned n, added = 0;
406 r = dns_packet_new_query(&p, t->scope->protocol, 0);
410 for (n = 0; n < t->question->n_keys; n++) {
411 r = dns_scope_good_key(t->scope, t->question->keys[n]);
417 r = dns_packet_append_key(p, t->question->keys[n], NULL);
427 DNS_PACKET_HEADER(p)->qdcount = htobe16(added);
428 DNS_PACKET_HEADER(p)->id = t->id;
436 int dns_transaction_go(DnsTransaction *t) {
442 had_stream = !!t->stream;
444 dns_transaction_stop(t);
446 log_debug("Beginning transaction on scope %s on %s/%s",
447 dns_protocol_to_string(t->scope->protocol),
448 t->scope->link ? t->scope->link->name : "*",
449 t->scope->family == AF_UNSPEC ? "*" : af_to_name(t->scope->family));
451 if (t->n_attempts >= TRANSACTION_ATTEMPTS_MAX(t->scope->protocol)) {
452 dns_transaction_complete(t, DNS_TRANSACTION_ATTEMPTS_MAX_REACHED);
456 if (t->scope->protocol == DNS_PROTOCOL_LLMNR && had_stream) {
457 /* If we already tried via a stream, then we don't
458 * retry on LLMNR. See RFC 4795, Section 2.7. */
459 dns_transaction_complete(t, DNS_TRANSACTION_ATTEMPTS_MAX_REACHED);
464 t->received = dns_packet_unref(t->received);
465 t->cached = dns_answer_unref(t->cached);
468 /* First, let's try the cache */
469 dns_cache_prune(&t->scope->cache);
470 r = dns_cache_lookup(&t->scope->cache, t->question, &t->cached_rcode, &t->cached);
474 if (t->cached_rcode == DNS_RCODE_SUCCESS)
475 dns_transaction_complete(t, DNS_TRANSACTION_SUCCESS);
477 dns_transaction_complete(t, DNS_TRANSACTION_FAILURE);
481 /* Otherwise, we need to ask the network */
482 r = dns_transaction_make_packet(t);
484 /* Not the right request to make on this network?
485 * (i.e. an A request made on IPv6 or an AAAA request
486 * made on IPv4, on LLMNR or mDNS.) */
487 dns_transaction_complete(t, DNS_TRANSACTION_NO_SERVERS);
493 if (t->scope->protocol == DNS_PROTOCOL_LLMNR &&
494 (dns_question_endswith(t->question, "in-addr.arpa") > 0 ||
495 dns_question_endswith(t->question, "ip6.arpa") > 0)) {
497 /* RFC 4795, Section 2.4. says reverse lookups shall
498 * always be made via TCP on LLMNR */
499 r = dns_transaction_open_tcp(t);
501 /* Try via UDP, and if that fails due to large size try via TCP */
502 r = dns_scope_send(t->scope, t->sent);
504 r = dns_transaction_open_tcp(t);
507 /* No servers to send this to? */
508 dns_transaction_complete(t, DNS_TRANSACTION_NO_SERVERS);
512 /* Couldn't send? Try immediately again, with a new server */
513 dns_scope_next_dns_server(t->scope);
515 return dns_transaction_go(t);
518 r = sd_event_add_time(t->scope->manager->event, &t->timeout_event_source, CLOCK_MONOTONIC, now(CLOCK_MONOTONIC) + TRANSACTION_TIMEOUT_USEC(t->scope->protocol), 0, on_transaction_timeout, t);
522 t->state = DNS_TRANSACTION_PENDING;
526 static const char* const dns_transaction_state_table[_DNS_TRANSACTION_STATE_MAX] = {
527 [DNS_TRANSACTION_NULL] = "null",
528 [DNS_TRANSACTION_PENDING] = "pending",
529 [DNS_TRANSACTION_FAILURE] = "failure",
530 [DNS_TRANSACTION_SUCCESS] = "success",
531 [DNS_TRANSACTION_NO_SERVERS] = "no-servers",
532 [DNS_TRANSACTION_TIMEOUT] = "timeout",
533 [DNS_TRANSACTION_ATTEMPTS_MAX_REACHED] = "attempts-max-reached",
534 [DNS_TRANSACTION_INVALID_REPLY] = "invalid-reply",
535 [DNS_TRANSACTION_RESOURCES] = "resources",
536 [DNS_TRANSACTION_ABORTED] = "aborted",
538 DEFINE_STRING_TABLE_LOOKUP(dns_transaction_state, DnsTransactionState);