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