chiark / gitweb /
resolved: don't abort if a transaction is aborted because its scope is removed
[elogind.git] / src / resolve / resolved-dns-transaction.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2014 Lennart Poettering
7
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.
12
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.
17
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/>.
20 ***/
21
22 #include "af-list.h"
23
24 #include "resolved-dns-transaction.h"
25
26 DnsTransaction* dns_transaction_free(DnsTransaction *t) {
27         DnsQuery *q;
28         DnsZoneItem *i;
29
30         if (!t)
31                 return NULL;
32
33         sd_event_source_unref(t->timeout_event_source);
34
35         dns_question_unref(t->question);
36         dns_packet_unref(t->sent);
37         dns_packet_unref(t->received);
38         dns_answer_unref(t->cached);
39
40         dns_stream_free(t->stream);
41
42         if (t->scope) {
43                 LIST_REMOVE(transactions_by_scope, t->scope->transactions, t);
44
45                 if (t->id != 0)
46                         hashmap_remove(t->scope->manager->dns_transactions, UINT_TO_PTR(t->id));
47         }
48
49         while ((q = set_steal_first(t->queries)))
50                 set_remove(q->transactions, t);
51         set_free(t->queries);
52
53         while ((i = set_steal_first(t->zone_items)))
54                 i->probe_transaction = NULL;
55         set_free(t->zone_items);
56
57         free(t);
58         return NULL;
59 }
60
61 DEFINE_TRIVIAL_CLEANUP_FUNC(DnsTransaction*, dns_transaction_free);
62
63 void dns_transaction_gc(DnsTransaction *t) {
64         assert(t);
65
66         if (t->block_gc > 0)
67                 return;
68
69         if (set_isempty(t->queries) && set_isempty(t->zone_items))
70                 dns_transaction_free(t);
71 }
72
73 int dns_transaction_new(DnsTransaction **ret, DnsScope *s, DnsQuestion *q) {
74         _cleanup_(dns_transaction_freep) DnsTransaction *t = NULL;
75         int r;
76
77         assert(ret);
78         assert(s);
79         assert(q);
80
81         r = hashmap_ensure_allocated(&s->manager->dns_transactions, NULL, NULL);
82         if (r < 0)
83                 return r;
84
85         t = new0(DnsTransaction, 1);
86         if (!t)
87                 return -ENOMEM;
88
89         t->question = dns_question_ref(q);
90
91         do
92                 random_bytes(&t->id, sizeof(t->id));
93         while (t->id == 0 ||
94                hashmap_get(s->manager->dns_transactions, UINT_TO_PTR(t->id)));
95
96         r = hashmap_put(s->manager->dns_transactions, UINT_TO_PTR(t->id), t);
97         if (r < 0) {
98                 t->id = 0;
99                 return r;
100         }
101
102         LIST_PREPEND(transactions_by_scope, s->transactions, t);
103         t->scope = s;
104
105         if (ret)
106                 *ret = t;
107
108         t = NULL;
109
110         return 0;
111 }
112
113 static void dns_transaction_stop(DnsTransaction *t) {
114         assert(t);
115
116         t->timeout_event_source = sd_event_source_unref(t->timeout_event_source);
117         t->stream = dns_stream_free(t->stream);
118 }
119
120 static void dns_transaction_tentative(DnsTransaction *t, DnsPacket *p) {
121         DnsZoneItem *z;
122         Iterator i;
123
124         assert(t);
125         assert(p);
126
127         if (manager_our_packet(t->scope->manager, p) != 0)
128                 return;
129
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));
134
135         t->block_gc++;
136         SET_FOREACH(z, t->zone_items, i)
137                 dns_zone_item_conflict(z);
138         t->block_gc--;
139
140         dns_transaction_gc(t);
141 }
142
143 void dns_transaction_complete(DnsTransaction *t, DnsTransactionState state) {
144         DnsQuery *q;
145         DnsZoneItem *z;
146         Iterator i;
147
148         assert(t);
149         assert(!IN_SET(state, DNS_TRANSACTION_NULL, DNS_TRANSACTION_PENDING));
150
151         if (!IN_SET(t->state, DNS_TRANSACTION_NULL, DNS_TRANSACTION_PENDING))
152                 return;
153
154         /* Note that this call might invalidate the query. Callers
155          * should hence not attempt to access the query or transaction
156          * after calling this function. */
157
158         log_debug("Transaction on scope %s on %s/%s now complete with <%s>",
159                   dns_protocol_to_string(t->scope->protocol),
160                   t->scope->link ? t->scope->link->name : "*",
161                   t->scope->family == AF_UNSPEC ? "*" : af_to_name(t->scope->family),
162                   dns_transaction_state_to_string(state));
163
164         t->state = state;
165
166         dns_transaction_stop(t);
167
168         /* Notify all queries that are interested, but make sure the
169          * transaction isn't freed while we are still looking at it */
170         t->block_gc++;
171         SET_FOREACH(q, t->queries, i)
172                 dns_query_ready(q);
173         SET_FOREACH(z, t->zone_items, i)
174                 dns_zone_item_ready(z);
175         t->block_gc--;
176
177         dns_transaction_gc(t);
178 }
179
180 static int on_stream_complete(DnsStream *s, int error) {
181         _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
182         DnsTransaction *t;
183
184         assert(s);
185         assert(s->transaction);
186
187         /* Copy the data we care about out of the stream before we
188          * destroy it. */
189         t = s->transaction;
190         p = dns_packet_ref(s->read_packet);
191
192         t->stream = dns_stream_free(t->stream);
193
194         if (error != 0) {
195                 dns_transaction_complete(t, DNS_TRANSACTION_RESOURCES);
196                 return 0;
197         }
198
199         t->block_gc++;
200         dns_transaction_process_reply(t, p);
201         t->block_gc--;
202
203         /* If the response wasn't useful, then complete the transition now */
204         if (t->state == DNS_TRANSACTION_PENDING)
205                 dns_transaction_complete(t, DNS_TRANSACTION_INVALID_REPLY);
206
207         return 0;
208 }
209
210 static int dns_transaction_open_tcp(DnsTransaction *t) {
211         _cleanup_close_ int fd = -1;
212         int r;
213
214         assert(t);
215
216         if (t->stream)
217                 return 0;
218
219         if (t->scope->protocol == DNS_PROTOCOL_DNS)
220                 fd = dns_scope_tcp_socket(t->scope, AF_UNSPEC, NULL, 53);
221         else if (t->scope->protocol == DNS_PROTOCOL_LLMNR) {
222
223                 /* When we already received a query to this (but it was truncated), send to its sender address */
224                 if (t->received)
225                         fd = dns_scope_tcp_socket(t->scope, t->received->family, &t->received->sender, t->received->sender_port);
226                 else {
227                         union in_addr_union address;
228                         int family;
229
230                         /* Otherwise, try to talk to the owner of a
231                          * the IP address, in case this is a reverse
232                          * PTR lookup */
233                         r = dns_question_extract_reverse_address(t->question, &family, &address);
234                         if (r < 0)
235                                 return r;
236                         if (r == 0)
237                                 return -EINVAL;
238
239                         fd = dns_scope_tcp_socket(t->scope, family, &address, 5355);
240                 }
241         } else
242                 return -EAFNOSUPPORT;
243
244         if (fd < 0)
245                 return fd;
246
247         r = dns_stream_new(t->scope->manager, &t->stream, t->scope->protocol, fd);
248         if (r < 0)
249                 return r;
250
251         fd = -1;
252
253         r = dns_stream_write_packet(t->stream, t->sent);
254         if (r < 0) {
255                 t->stream = dns_stream_free(t->stream);
256                 return r;
257         }
258
259         t->received = dns_packet_unref(t->received);
260         t->stream->complete = on_stream_complete;
261         t->stream->transaction = t;
262
263         /* The interface index is difficult to determine if we are
264          * connecting to the local host, hence fill this in right away
265          * instead of determining it from the socket */
266         if (t->scope->link)
267                 t->stream->ifindex = t->scope->link->ifindex;
268
269         return 0;
270 }
271
272 void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) {
273         int r;
274
275         assert(t);
276         assert(p);
277         assert(t->state == DNS_TRANSACTION_PENDING);
278
279         /* Note that this call might invalidate the query. Callers
280          * should hence not attempt to access the query or transaction
281          * after calling this function. */
282
283         if (t->scope->protocol == DNS_PROTOCOL_LLMNR) {
284                 assert(t->scope->link);
285
286                 /* For LLMNR we will not accept any packets from other
287                  * interfaces */
288
289                 if (p->ifindex != t->scope->link->ifindex)
290                         return;
291
292                 if (p->family != t->scope->family)
293                         return;
294
295                 /* Tentative packets are not full responses but still
296                  * useful for identifying uniqueness conflicts during
297                  * probing. */
298                 if (DNS_PACKET_T(p)) {
299                         dns_transaction_tentative(t, p);
300                         return;
301                 }
302         }
303
304         if (t->scope->protocol == DNS_PROTOCOL_DNS) {
305
306                 /* For DNS we are fine with accepting packets on any
307                  * interface, but the source IP address must be one of
308                  * a valid DNS server */
309
310                 if (!dns_scope_good_dns_server(t->scope, p->family, &p->sender))
311                         return;
312
313                 if (p->sender_port != 53)
314                         return;
315         }
316
317         if (t->received != p) {
318                 dns_packet_unref(t->received);
319                 t->received = dns_packet_ref(p);
320         }
321
322         if (p->ipproto == IPPROTO_TCP) {
323                 if (DNS_PACKET_TC(p)) {
324                         /* Truncated via TCP? Somebody must be fucking with us */
325                         dns_transaction_complete(t, DNS_TRANSACTION_INVALID_REPLY);
326                         return;
327                 }
328
329                 if (DNS_PACKET_ID(p) != t->id) {
330                         /* Not the reply to our query? Somebody must be fucking with us */
331                         dns_transaction_complete(t, DNS_TRANSACTION_INVALID_REPLY);
332                         return;
333                 }
334         }
335
336         if (DNS_PACKET_TC(p)) {
337                 /* Response was truncated, let's try again with good old TCP */
338                 r = dns_transaction_open_tcp(t);
339                 if (r == -ESRCH) {
340                         /* No servers found? Damn! */
341                         dns_transaction_complete(t, DNS_TRANSACTION_NO_SERVERS);
342                         return;
343                 }
344                 if (r < 0) {
345                         /* On LLMNR, if we cannot connect to the host,
346                          * we immediately give up */
347                         if (t->scope->protocol == DNS_PROTOCOL_LLMNR) {
348                                 dns_transaction_complete(t, DNS_TRANSACTION_RESOURCES);
349                                 return;
350                         }
351
352                         /* On DNS, couldn't send? Try immediately again, with a new server */
353                         dns_scope_next_dns_server(t->scope);
354
355                         r = dns_transaction_go(t);
356                         if (r < 0) {
357                                 dns_transaction_complete(t, DNS_TRANSACTION_RESOURCES);
358                                 return;
359                         }
360
361                         return;
362                 }
363         }
364
365         /* Parse and update the cache */
366         r = dns_packet_extract(p);
367         if (r < 0) {
368                 dns_transaction_complete(t, DNS_TRANSACTION_INVALID_REPLY);
369                 return;
370         }
371
372         /* According to RFC 4795, section 2.9. only the RRs from the answer section shall be cached */
373         dns_cache_put(&t->scope->cache, p->question, DNS_PACKET_RCODE(p), p->answer, DNS_PACKET_ANCOUNT(p), 0);
374
375         if (DNS_PACKET_RCODE(p) == DNS_RCODE_SUCCESS)
376                 dns_transaction_complete(t, DNS_TRANSACTION_SUCCESS);
377         else
378                 dns_transaction_complete(t, DNS_TRANSACTION_FAILURE);
379 }
380
381 static int on_transaction_timeout(sd_event_source *s, usec_t usec, void *userdata) {
382         DnsTransaction *t = userdata;
383         int r;
384
385         assert(s);
386         assert(t);
387
388         /* Timeout reached? Try again, with a new server */
389         dns_scope_next_dns_server(t->scope);
390
391         r = dns_transaction_go(t);
392         if (r < 0)
393                 dns_transaction_complete(t, DNS_TRANSACTION_RESOURCES);
394
395         return 0;
396 }
397
398 static int dns_transaction_make_packet(DnsTransaction *t) {
399         _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
400         unsigned n, added = 0;
401         int r;
402
403         assert(t);
404
405         if (t->sent)
406                 return 0;
407
408         r = dns_packet_new_query(&p, t->scope->protocol, 0);
409         if (r < 0)
410                 return r;
411
412         for (n = 0; n < t->question->n_keys; n++) {
413                 r = dns_scope_good_key(t->scope, t->question->keys[n]);
414                 if (r < 0)
415                         return r;
416                 if (r == 0)
417                         continue;
418
419                 r = dns_packet_append_key(p, t->question->keys[n], NULL);
420                 if (r < 0)
421                         return r;
422
423                 added++;
424         }
425
426         if (added <= 0)
427                 return -EDOM;
428
429         DNS_PACKET_HEADER(p)->qdcount = htobe16(added);
430         DNS_PACKET_HEADER(p)->id = t->id;
431
432         t->sent = p;
433         p = NULL;
434
435         return 0;
436 }
437
438 int dns_transaction_go(DnsTransaction *t) {
439         bool had_stream;
440         int r;
441
442         assert(t);
443
444         had_stream = !!t->stream;
445
446         dns_transaction_stop(t);
447
448         log_debug("Excercising transaction on scope %s on %s/%s",
449                   dns_protocol_to_string(t->scope->protocol),
450                   t->scope->link ? t->scope->link->name : "*",
451                   t->scope->family == AF_UNSPEC ? "*" : af_to_name(t->scope->family));
452
453         if (t->n_attempts >= TRANSACTION_ATTEMPTS_MAX(t->scope->protocol)) {
454                 dns_transaction_complete(t, DNS_TRANSACTION_ATTEMPTS_MAX_REACHED);
455                 return 0;
456         }
457
458         if (t->scope->protocol == DNS_PROTOCOL_LLMNR && had_stream) {
459                 /* If we already tried via a stream, then we don't
460                  * retry on LLMNR. See RFC 4795, Section 2.7. */
461                 dns_transaction_complete(t, DNS_TRANSACTION_ATTEMPTS_MAX_REACHED);
462                 return 0;
463         }
464
465         t->n_attempts++;
466         t->received = dns_packet_unref(t->received);
467         t->cached = dns_answer_unref(t->cached);
468         t->cached_rcode = 0;
469
470         /* Check the cache, but only if this transaction is not used
471          * for probing or verifying a zone item. */
472         if (set_isempty(t->zone_items)) {
473
474                 /* Before trying the cache, let's make sure we figured out a
475                  * server to use. Should this cause a change of server this
476                  * might flush the cache. */
477                 dns_scope_get_dns_server(t->scope);
478
479                 /* Let's then prune all outdated entries */
480                 dns_cache_prune(&t->scope->cache);
481
482                 r = dns_cache_lookup(&t->scope->cache, t->question, &t->cached_rcode, &t->cached);
483                 if (r < 0)
484                         return r;
485                 if (r > 0) {
486                         log_debug("Cache hit!");
487                         if (t->cached_rcode == DNS_RCODE_SUCCESS)
488                                 dns_transaction_complete(t, DNS_TRANSACTION_SUCCESS);
489                         else
490                                 dns_transaction_complete(t, DNS_TRANSACTION_FAILURE);
491                         return 0;
492                 }
493         }
494
495         if (t->scope->protocol == DNS_PROTOCOL_LLMNR && !t->initial_jitter) {
496                 usec_t jitter;
497
498                 /* RFC 4795 Section 2.7 suggests all queries should be
499                  * delayed by a random time from 0 to JITTER_INTERVAL. */
500
501                 t->initial_jitter = true;
502
503                 random_bytes(&jitter, sizeof(jitter));
504                 jitter %= LLMNR_JITTER_INTERVAL_USEC;
505
506                 r = sd_event_add_time(
507                                 t->scope->manager->event,
508                                 &t->timeout_event_source,
509                                 clock_boottime_or_monotonic(),
510                                 now(clock_boottime_or_monotonic()) + jitter, LLMNR_JITTER_INTERVAL_USEC,
511                                 on_transaction_timeout, t);
512                 if (r < 0)
513                         return r;
514
515                 t->n_attempts = 0;
516                 t->state = DNS_TRANSACTION_PENDING;
517
518                 log_debug("Delaying LLMNR transaction for " USEC_FMT "us.", jitter);
519                 return 0;
520         }
521
522         log_debug("Cache miss!");
523
524         /* Otherwise, we need to ask the network */
525         r = dns_transaction_make_packet(t);
526         if (r == -EDOM) {
527                 /* Not the right request to make on this network?
528                  * (i.e. an A request made on IPv6 or an AAAA request
529                  * made on IPv4, on LLMNR or mDNS.) */
530                 dns_transaction_complete(t, DNS_TRANSACTION_NO_SERVERS);
531                 return 0;
532         }
533         if (r < 0)
534                 return r;
535
536         if (t->scope->protocol == DNS_PROTOCOL_LLMNR &&
537             (dns_question_endswith(t->question, "in-addr.arpa") > 0 ||
538              dns_question_endswith(t->question, "ip6.arpa") > 0)) {
539
540                 /* RFC 4795, Section 2.4. says reverse lookups shall
541                  * always be made via TCP on LLMNR */
542                 r = dns_transaction_open_tcp(t);
543         } else {
544                 /* Try via UDP, and if that fails due to large size try via TCP */
545                 r = dns_scope_send(t->scope, t->sent);
546                 if (r == -EMSGSIZE)
547                         r = dns_transaction_open_tcp(t);
548         }
549         if (r == -ESRCH) {
550                 /* No servers to send this to? */
551                 dns_transaction_complete(t, DNS_TRANSACTION_NO_SERVERS);
552                 return 0;
553         }
554         if (r < 0) {
555                 if (t->scope->protocol != DNS_PROTOCOL_DNS) {
556                         dns_transaction_complete(t, DNS_TRANSACTION_RESOURCES);
557                         return 0;
558                 }
559
560                 /* Couldn't send? Try immediately again, with a new server */
561                 dns_scope_next_dns_server(t->scope);
562
563                 return dns_transaction_go(t);
564         }
565
566         r = sd_event_add_time(
567                         t->scope->manager->event,
568                         &t->timeout_event_source,
569                         clock_boottime_or_monotonic(),
570                         now(clock_boottime_or_monotonic()) + TRANSACTION_TIMEOUT_USEC(t->scope->protocol), 0,
571                         on_transaction_timeout, t);
572         if (r < 0)
573                 return r;
574
575         t->state = DNS_TRANSACTION_PENDING;
576         return 1;
577 }
578
579 static const char* const dns_transaction_state_table[_DNS_TRANSACTION_STATE_MAX] = {
580         [DNS_TRANSACTION_NULL] = "null",
581         [DNS_TRANSACTION_PENDING] = "pending",
582         [DNS_TRANSACTION_FAILURE] = "failure",
583         [DNS_TRANSACTION_SUCCESS] = "success",
584         [DNS_TRANSACTION_NO_SERVERS] = "no-servers",
585         [DNS_TRANSACTION_TIMEOUT] = "timeout",
586         [DNS_TRANSACTION_ATTEMPTS_MAX_REACHED] = "attempts-max-reached",
587         [DNS_TRANSACTION_INVALID_REPLY] = "invalid-reply",
588         [DNS_TRANSACTION_RESOURCES] = "resources",
589         [DNS_TRANSACTION_ABORTED] = "aborted",
590 };
591 DEFINE_STRING_TABLE_LOOKUP(dns_transaction_state, DnsTransactionState);