chiark / gitweb /
resolved: be a bit more communicative about conflicts
[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         _cleanup_free_ char *pretty = NULL;
122         DnsZoneItem *z;
123         Iterator i;
124
125         assert(t);
126         assert(p);
127
128         if (manager_our_packet(t->scope->manager, p) != 0)
129                 return;
130
131         in_addr_to_string(p->family, &p->sender, &pretty);
132
133         log_debug("Transaction on scope %s on %s/%s got tentative packet from %s",
134                   dns_protocol_to_string(t->scope->protocol),
135                   t->scope->link ? t->scope->link->name : "*",
136                   t->scope->family == AF_UNSPEC ? "*" : af_to_name(t->scope->family),
137                   pretty);
138
139         /* RFC 4795, Section 4.1 says that the peer with the
140          * lexicographically smaller IP address loses */
141         if (memcmp(&p->sender, &p->destination, FAMILY_ADDRESS_SIZE(p->family)) < 0) {
142                 log_debug("Peer has lexicographically smaller IP address and thus lost in the conflict.");
143                 return;
144         }
145
146         log_debug("We have the lexicographically smaller IP address and thus lost in the conflict.");
147
148         t->block_gc++;
149         SET_FOREACH(z, t->zone_items, i)
150                 dns_zone_item_conflict(z);
151         t->block_gc--;
152
153         dns_transaction_gc(t);
154 }
155
156 void dns_transaction_complete(DnsTransaction *t, DnsTransactionState state) {
157         DnsQuery *q;
158         DnsZoneItem *z;
159         Iterator i;
160
161         assert(t);
162         assert(!IN_SET(state, DNS_TRANSACTION_NULL, DNS_TRANSACTION_PENDING));
163
164         if (!IN_SET(t->state, DNS_TRANSACTION_NULL, DNS_TRANSACTION_PENDING))
165                 return;
166
167         /* Note that this call might invalidate the query. Callers
168          * should hence not attempt to access the query or transaction
169          * after calling this function. */
170
171         log_debug("Transaction on scope %s on %s/%s now complete with <%s>",
172                   dns_protocol_to_string(t->scope->protocol),
173                   t->scope->link ? t->scope->link->name : "*",
174                   t->scope->family == AF_UNSPEC ? "*" : af_to_name(t->scope->family),
175                   dns_transaction_state_to_string(state));
176
177         t->state = state;
178
179         dns_transaction_stop(t);
180
181         /* Notify all queries that are interested, but make sure the
182          * transaction isn't freed while we are still looking at it */
183         t->block_gc++;
184         SET_FOREACH(q, t->queries, i)
185                 dns_query_ready(q);
186         SET_FOREACH(z, t->zone_items, i)
187                 dns_zone_item_ready(z);
188         t->block_gc--;
189
190         dns_transaction_gc(t);
191 }
192
193 static int on_stream_complete(DnsStream *s, int error) {
194         _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
195         DnsTransaction *t;
196
197         assert(s);
198         assert(s->transaction);
199
200         /* Copy the data we care about out of the stream before we
201          * destroy it. */
202         t = s->transaction;
203         p = dns_packet_ref(s->read_packet);
204
205         t->stream = dns_stream_free(t->stream);
206
207         if (error != 0) {
208                 dns_transaction_complete(t, DNS_TRANSACTION_RESOURCES);
209                 return 0;
210         }
211
212         if (dns_packet_validate_reply(p) <= 0) {
213                 log_debug("Invalid LLMNR TCP packet.");
214                 dns_transaction_complete(t, DNS_TRANSACTION_INVALID_REPLY);
215                 return 0;
216         }
217
218         dns_scope_check_conflicts(t->scope, p);
219
220         t->block_gc++;
221         dns_transaction_process_reply(t, p);
222         t->block_gc--;
223
224         /* If the response wasn't useful, then complete the transition now */
225         if (t->state == DNS_TRANSACTION_PENDING)
226                 dns_transaction_complete(t, DNS_TRANSACTION_INVALID_REPLY);
227
228         return 0;
229 }
230
231 static int dns_transaction_open_tcp(DnsTransaction *t) {
232         _cleanup_close_ int fd = -1;
233         int r;
234
235         assert(t);
236
237         if (t->stream)
238                 return 0;
239
240         if (t->scope->protocol == DNS_PROTOCOL_DNS)
241                 fd = dns_scope_tcp_socket(t->scope, AF_UNSPEC, NULL, 53);
242         else if (t->scope->protocol == DNS_PROTOCOL_LLMNR) {
243
244                 /* When we already received a query to this (but it was truncated), send to its sender address */
245                 if (t->received)
246                         fd = dns_scope_tcp_socket(t->scope, t->received->family, &t->received->sender, t->received->sender_port);
247                 else {
248                         union in_addr_union address;
249                         int family;
250
251                         /* Otherwise, try to talk to the owner of a
252                          * the IP address, in case this is a reverse
253                          * PTR lookup */
254                         r = dns_question_extract_reverse_address(t->question, &family, &address);
255                         if (r < 0)
256                                 return r;
257                         if (r == 0)
258                                 return -EINVAL;
259
260                         fd = dns_scope_tcp_socket(t->scope, family, &address, 5355);
261                 }
262         } else
263                 return -EAFNOSUPPORT;
264
265         if (fd < 0)
266                 return fd;
267
268         r = dns_stream_new(t->scope->manager, &t->stream, t->scope->protocol, fd);
269         if (r < 0)
270                 return r;
271
272         fd = -1;
273
274         r = dns_stream_write_packet(t->stream, t->sent);
275         if (r < 0) {
276                 t->stream = dns_stream_free(t->stream);
277                 return r;
278         }
279
280         t->received = dns_packet_unref(t->received);
281         t->stream->complete = on_stream_complete;
282         t->stream->transaction = t;
283
284         /* The interface index is difficult to determine if we are
285          * connecting to the local host, hence fill this in right away
286          * instead of determining it from the socket */
287         if (t->scope->link)
288                 t->stream->ifindex = t->scope->link->ifindex;
289
290         return 0;
291 }
292
293 void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) {
294         int r;
295
296         assert(t);
297         assert(p);
298         assert(t->state == DNS_TRANSACTION_PENDING);
299
300         /* Note that this call might invalidate the query. Callers
301          * should hence not attempt to access the query or transaction
302          * after calling this function. */
303
304         if (t->scope->protocol == DNS_PROTOCOL_LLMNR) {
305                 assert(t->scope->link);
306
307                 /* For LLMNR we will not accept any packets from other
308                  * interfaces */
309
310                 if (p->ifindex != t->scope->link->ifindex)
311                         return;
312
313                 if (p->family != t->scope->family)
314                         return;
315
316                 /* Tentative packets are not full responses but still
317                  * useful for identifying uniqueness conflicts during
318                  * probing. */
319                 if (DNS_PACKET_T(p)) {
320                         dns_transaction_tentative(t, p);
321                         return;
322                 }
323         }
324
325         if (t->scope->protocol == DNS_PROTOCOL_DNS) {
326
327                 /* For DNS we are fine with accepting packets on any
328                  * interface, but the source IP address must be one of
329                  * a valid DNS server */
330
331                 if (!dns_scope_good_dns_server(t->scope, p->family, &p->sender))
332                         return;
333
334                 if (p->sender_port != 53)
335                         return;
336         }
337
338         if (t->received != p) {
339                 dns_packet_unref(t->received);
340                 t->received = dns_packet_ref(p);
341         }
342
343         if (p->ipproto == IPPROTO_TCP) {
344                 if (DNS_PACKET_TC(p)) {
345                         /* Truncated via TCP? Somebody must be fucking with us */
346                         dns_transaction_complete(t, DNS_TRANSACTION_INVALID_REPLY);
347                         return;
348                 }
349
350                 if (DNS_PACKET_ID(p) != t->id) {
351                         /* Not the reply to our query? Somebody must be fucking with us */
352                         dns_transaction_complete(t, DNS_TRANSACTION_INVALID_REPLY);
353                         return;
354                 }
355         }
356
357         if (DNS_PACKET_TC(p)) {
358                 /* Response was truncated, let's try again with good old TCP */
359                 r = dns_transaction_open_tcp(t);
360                 if (r == -ESRCH) {
361                         /* No servers found? Damn! */
362                         dns_transaction_complete(t, DNS_TRANSACTION_NO_SERVERS);
363                         return;
364                 }
365                 if (r < 0) {
366                         /* On LLMNR, if we cannot connect to the host,
367                          * we immediately give up */
368                         if (t->scope->protocol == DNS_PROTOCOL_LLMNR) {
369                                 dns_transaction_complete(t, DNS_TRANSACTION_RESOURCES);
370                                 return;
371                         }
372
373                         /* On DNS, couldn't send? Try immediately again, with a new server */
374                         dns_scope_next_dns_server(t->scope);
375
376                         r = dns_transaction_go(t);
377                         if (r < 0) {
378                                 dns_transaction_complete(t, DNS_TRANSACTION_RESOURCES);
379                                 return;
380                         }
381
382                         return;
383                 }
384         }
385
386         /* Parse and update the cache */
387         r = dns_packet_extract(p);
388         if (r < 0) {
389                 dns_transaction_complete(t, DNS_TRANSACTION_INVALID_REPLY);
390                 return;
391         }
392
393         /* According to RFC 4795, section 2.9. only the RRs from the answer section shall be cached */
394         dns_cache_put(&t->scope->cache, p->question, DNS_PACKET_RCODE(p), p->answer, DNS_PACKET_ANCOUNT(p), 0, p->family, &p->sender);
395
396         if (DNS_PACKET_RCODE(p) == DNS_RCODE_SUCCESS)
397                 dns_transaction_complete(t, DNS_TRANSACTION_SUCCESS);
398         else
399                 dns_transaction_complete(t, DNS_TRANSACTION_FAILURE);
400 }
401
402 static int on_transaction_timeout(sd_event_source *s, usec_t usec, void *userdata) {
403         DnsTransaction *t = userdata;
404         int r;
405
406         assert(s);
407         assert(t);
408
409         /* Timeout reached? Try again, with a new server */
410         dns_scope_next_dns_server(t->scope);
411
412         r = dns_transaction_go(t);
413         if (r < 0)
414                 dns_transaction_complete(t, DNS_TRANSACTION_RESOURCES);
415
416         return 0;
417 }
418
419 static int dns_transaction_make_packet(DnsTransaction *t) {
420         _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
421         unsigned n, added = 0;
422         int r;
423
424         assert(t);
425
426         if (t->sent)
427                 return 0;
428
429         r = dns_packet_new_query(&p, t->scope->protocol, 0);
430         if (r < 0)
431                 return r;
432
433         for (n = 0; n < t->question->n_keys; n++) {
434                 r = dns_scope_good_key(t->scope, t->question->keys[n]);
435                 if (r < 0)
436                         return r;
437                 if (r == 0)
438                         continue;
439
440                 r = dns_packet_append_key(p, t->question->keys[n], NULL);
441                 if (r < 0)
442                         return r;
443
444                 added++;
445         }
446
447         if (added <= 0)
448                 return -EDOM;
449
450         DNS_PACKET_HEADER(p)->qdcount = htobe16(added);
451         DNS_PACKET_HEADER(p)->id = t->id;
452
453         t->sent = p;
454         p = NULL;
455
456         return 0;
457 }
458
459 int dns_transaction_go(DnsTransaction *t) {
460         bool had_stream;
461         int r;
462
463         assert(t);
464
465         had_stream = !!t->stream;
466
467         dns_transaction_stop(t);
468
469         log_debug("Excercising transaction on scope %s on %s/%s",
470                   dns_protocol_to_string(t->scope->protocol),
471                   t->scope->link ? t->scope->link->name : "*",
472                   t->scope->family == AF_UNSPEC ? "*" : af_to_name(t->scope->family));
473
474         if (t->n_attempts >= TRANSACTION_ATTEMPTS_MAX(t->scope->protocol)) {
475                 dns_transaction_complete(t, DNS_TRANSACTION_ATTEMPTS_MAX_REACHED);
476                 return 0;
477         }
478
479         if (t->scope->protocol == DNS_PROTOCOL_LLMNR && had_stream) {
480                 /* If we already tried via a stream, then we don't
481                  * retry on LLMNR. See RFC 4795, Section 2.7. */
482                 dns_transaction_complete(t, DNS_TRANSACTION_ATTEMPTS_MAX_REACHED);
483                 return 0;
484         }
485
486         t->n_attempts++;
487         t->received = dns_packet_unref(t->received);
488         t->cached = dns_answer_unref(t->cached);
489         t->cached_rcode = 0;
490
491         /* Check the cache, but only if this transaction is not used
492          * for probing or verifying a zone item. */
493         if (set_isempty(t->zone_items)) {
494
495                 /* Before trying the cache, let's make sure we figured out a
496                  * server to use. Should this cause a change of server this
497                  * might flush the cache. */
498                 dns_scope_get_dns_server(t->scope);
499
500                 /* Let's then prune all outdated entries */
501                 dns_cache_prune(&t->scope->cache);
502
503                 r = dns_cache_lookup(&t->scope->cache, t->question, &t->cached_rcode, &t->cached);
504                 if (r < 0)
505                         return r;
506                 if (r > 0) {
507                         log_debug("Cache hit!");
508                         if (t->cached_rcode == DNS_RCODE_SUCCESS)
509                                 dns_transaction_complete(t, DNS_TRANSACTION_SUCCESS);
510                         else
511                                 dns_transaction_complete(t, DNS_TRANSACTION_FAILURE);
512                         return 0;
513                 }
514         }
515
516         if (t->scope->protocol == DNS_PROTOCOL_LLMNR && !t->initial_jitter) {
517                 usec_t jitter;
518
519                 /* RFC 4795 Section 2.7 suggests all queries should be
520                  * delayed by a random time from 0 to JITTER_INTERVAL. */
521
522                 t->initial_jitter = true;
523
524                 random_bytes(&jitter, sizeof(jitter));
525                 jitter %= LLMNR_JITTER_INTERVAL_USEC;
526
527                 r = sd_event_add_time(
528                                 t->scope->manager->event,
529                                 &t->timeout_event_source,
530                                 clock_boottime_or_monotonic(),
531                                 now(clock_boottime_or_monotonic()) + jitter,
532                                 LLMNR_JITTER_INTERVAL_USEC,
533                                 on_transaction_timeout, t);
534                 if (r < 0)
535                         return r;
536
537                 t->n_attempts = 0;
538                 t->state = DNS_TRANSACTION_PENDING;
539
540                 log_debug("Delaying LLMNR transaction for " USEC_FMT "us.", jitter);
541                 return 0;
542         }
543
544         log_debug("Cache miss!");
545
546         /* Otherwise, we need to ask the network */
547         r = dns_transaction_make_packet(t);
548         if (r == -EDOM) {
549                 /* Not the right request to make on this network?
550                  * (i.e. an A request made on IPv6 or an AAAA request
551                  * made on IPv4, on LLMNR or mDNS.) */
552                 dns_transaction_complete(t, DNS_TRANSACTION_NO_SERVERS);
553                 return 0;
554         }
555         if (r < 0)
556                 return r;
557
558         if (t->scope->protocol == DNS_PROTOCOL_LLMNR &&
559             (dns_question_endswith(t->question, "in-addr.arpa") > 0 ||
560              dns_question_endswith(t->question, "ip6.arpa") > 0)) {
561
562                 /* RFC 4795, Section 2.4. says reverse lookups shall
563                  * always be made via TCP on LLMNR */
564                 r = dns_transaction_open_tcp(t);
565         } else {
566                 /* Try via UDP, and if that fails due to large size try via TCP */
567                 r = dns_scope_emit(t->scope, t->sent);
568                 if (r == -EMSGSIZE)
569                         r = dns_transaction_open_tcp(t);
570         }
571         if (r == -ESRCH) {
572                 /* No servers to send this to? */
573                 dns_transaction_complete(t, DNS_TRANSACTION_NO_SERVERS);
574                 return 0;
575         }
576         if (r < 0) {
577                 if (t->scope->protocol != DNS_PROTOCOL_DNS) {
578                         dns_transaction_complete(t, DNS_TRANSACTION_RESOURCES);
579                         return 0;
580                 }
581
582                 /* Couldn't send? Try immediately again, with a new server */
583                 dns_scope_next_dns_server(t->scope);
584
585                 return dns_transaction_go(t);
586         }
587
588         r = sd_event_add_time(
589                         t->scope->manager->event,
590                         &t->timeout_event_source,
591                         clock_boottime_or_monotonic(),
592                         now(clock_boottime_or_monotonic()) + TRANSACTION_TIMEOUT_USEC(t->scope->protocol), 0,
593                         on_transaction_timeout, t);
594         if (r < 0)
595                 return r;
596
597         t->state = DNS_TRANSACTION_PENDING;
598         return 1;
599 }
600
601 static const char* const dns_transaction_state_table[_DNS_TRANSACTION_STATE_MAX] = {
602         [DNS_TRANSACTION_NULL] = "null",
603         [DNS_TRANSACTION_PENDING] = "pending",
604         [DNS_TRANSACTION_FAILURE] = "failure",
605         [DNS_TRANSACTION_SUCCESS] = "success",
606         [DNS_TRANSACTION_NO_SERVERS] = "no-servers",
607         [DNS_TRANSACTION_TIMEOUT] = "timeout",
608         [DNS_TRANSACTION_ATTEMPTS_MAX_REACHED] = "attempts-max-reached",
609         [DNS_TRANSACTION_INVALID_REPLY] = "invalid-reply",
610         [DNS_TRANSACTION_RESOURCES] = "resources",
611         [DNS_TRANSACTION_ABORTED] = "aborted",
612 };
613 DEFINE_STRING_TABLE_LOOKUP(dns_transaction_state, DnsTransactionState);