chiark / gitweb /
resolved: enforce ratelimit on LLMNR traffic
[elogind.git] / src / resolve / resolved-dns-scope.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 <netinet/tcp.h>
23
24 #include "missing.h"
25 #include "strv.h"
26 #include "socket-util.h"
27 #include "af-list.h"
28 #include "resolved-dns-domain.h"
29 #include "resolved-dns-scope.h"
30
31 #define MULTICAST_RATELIMIT_INTERVAL_USEC (1*USEC_PER_SEC)
32 #define MULTICAST_RATELIMIT_BURST 1000
33
34 int dns_scope_new(Manager *m, DnsScope **ret, Link *l, DnsProtocol protocol, int family) {
35         DnsScope *s;
36
37         assert(m);
38         assert(ret);
39
40         s = new0(DnsScope, 1);
41         if (!s)
42                 return -ENOMEM;
43
44         s->manager = m;
45         s->link = l;
46         s->protocol = protocol;
47         s->family = family;
48
49         LIST_PREPEND(scopes, m->dns_scopes, s);
50
51         dns_scope_llmnr_membership(s, true);
52
53         log_debug("New scope on link %s, protocol %s, family %s", l ? l->name : "*", dns_protocol_to_string(protocol), family == AF_UNSPEC ? "*" : af_to_name(family));
54
55         /* Enforce ratelimiting for the multicast protocols */
56         RATELIMIT_INIT(s->ratelimit, MULTICAST_RATELIMIT_INTERVAL_USEC, MULTICAST_RATELIMIT_BURST);
57
58         *ret = s;
59         return 0;
60 }
61
62 DnsScope* dns_scope_free(DnsScope *s) {
63         DnsTransaction *t;
64
65         if (!s)
66                 return NULL;
67
68         log_debug("Removing scope on link %s, protocol %s, family %s", s->link ? s->link->name : "*", dns_protocol_to_string(s->protocol), s->family == AF_UNSPEC ? "*" : af_to_name(s->family));
69
70         dns_scope_llmnr_membership(s, false);
71
72         while ((t = s->transactions)) {
73
74                 /* Abort the transaction, but make sure it is not
75                  * freed while we still look at it */
76
77                 t->block_gc++;
78                 dns_transaction_complete(t, DNS_TRANSACTION_ABORTED);
79                 t->block_gc--;
80
81                 dns_transaction_free(t);
82         }
83
84         dns_cache_flush(&s->cache);
85         dns_zone_flush(&s->zone);
86
87         LIST_REMOVE(scopes, s->manager->dns_scopes, s);
88         strv_free(s->domains);
89         free(s);
90
91         return NULL;
92 }
93
94 DnsServer *dns_scope_get_dns_server(DnsScope *s) {
95         assert(s);
96
97         if (s->protocol != DNS_PROTOCOL_DNS)
98                 return NULL;
99
100         if (s->link)
101                 return link_get_dns_server(s->link);
102         else
103                 return manager_get_dns_server(s->manager);
104 }
105
106 void dns_scope_next_dns_server(DnsScope *s) {
107         assert(s);
108
109         if (s->protocol != DNS_PROTOCOL_DNS)
110                 return;
111
112         if (s->link)
113                 link_next_dns_server(s->link);
114         else
115                 manager_next_dns_server(s->manager);
116 }
117
118 int dns_scope_send(DnsScope *s, DnsPacket *p) {
119         union in_addr_union addr;
120         int ifindex = 0, r;
121         int family;
122         uint16_t port;
123         uint32_t mtu;
124         int fd;
125
126         assert(s);
127         assert(p);
128         assert(p->protocol == s->protocol);
129
130         if (s->link) {
131                 mtu = s->link->mtu;
132                 ifindex = s->link->ifindex;
133         } else
134                 mtu = manager_find_mtu(s->manager);
135
136         if (s->protocol == DNS_PROTOCOL_DNS) {
137                 DnsServer *srv;
138
139                 if (DNS_PACKET_QDCOUNT(p) > 1)
140                         return -ENOTSUP;
141
142                 srv = dns_scope_get_dns_server(s);
143                 if (!srv)
144                         return -ESRCH;
145
146                 family = srv->family;
147                 addr = srv->address;
148                 port = 53;
149
150                 if (p->size > DNS_PACKET_UNICAST_SIZE_MAX)
151                         return -EMSGSIZE;
152
153                 if (p->size > mtu)
154                         return -EMSGSIZE;
155
156                 if (family == AF_INET)
157                         fd = manager_dns_ipv4_fd(s->manager);
158                 else if (family == AF_INET6)
159                         fd = manager_dns_ipv6_fd(s->manager);
160                 else
161                         return -EAFNOSUPPORT;
162                 if (fd < 0)
163                         return fd;
164
165         } else if (s->protocol == DNS_PROTOCOL_LLMNR) {
166
167                 if (DNS_PACKET_QDCOUNT(p) > 1)
168                         return -ENOTSUP;
169
170                 if (!ratelimit_test(&s->ratelimit))
171                         return -EBUSY;
172
173                 family = s->family;
174                 port = 5355;
175
176                 if (family == AF_INET) {
177                         addr.in = LLMNR_MULTICAST_IPV4_ADDRESS;
178                         fd = manager_llmnr_ipv4_udp_fd(s->manager);
179                 } else if (family == AF_INET6) {
180                         addr.in6 = LLMNR_MULTICAST_IPV6_ADDRESS;
181                         fd = manager_llmnr_ipv6_udp_fd(s->manager);
182                 } else
183                         return -EAFNOSUPPORT;
184                 if (fd < 0)
185                         return fd;
186         } else
187                 return -EAFNOSUPPORT;
188
189         r = manager_send(s->manager, fd, ifindex, family, &addr, port, p);
190         if (r < 0)
191                 return r;
192
193         return 1;
194 }
195
196 int dns_scope_tcp_socket(DnsScope *s, int family, const union in_addr_union *address, uint16_t port) {
197         _cleanup_close_ int fd = -1;
198         union sockaddr_union sa = {};
199         socklen_t salen;
200         static const int one = 1;
201         int ret, r;
202
203         assert(s);
204         assert((family == AF_UNSPEC) == !address);
205
206         if (family == AF_UNSPEC) {
207                 DnsServer *srv;
208
209                 srv = dns_scope_get_dns_server(s);
210                 if (!srv)
211                         return -ESRCH;
212
213                 sa.sa.sa_family = srv->family;
214                 if (srv->family == AF_INET) {
215                         sa.in.sin_port = htobe16(port);
216                         sa.in.sin_addr = srv->address.in;
217                         salen = sizeof(sa.in);
218                 } else if (srv->family == AF_INET6) {
219                         sa.in6.sin6_port = htobe16(port);
220                         sa.in6.sin6_addr = srv->address.in6;
221                         sa.in6.sin6_scope_id = s->link ? s->link->ifindex : 0;
222                         salen = sizeof(sa.in6);
223                 } else
224                         return -EAFNOSUPPORT;
225         } else {
226                 sa.sa.sa_family = family;
227
228                 if (family == AF_INET) {
229                         sa.in.sin_port = htobe16(port);
230                         sa.in.sin_addr = address->in;
231                         salen = sizeof(sa.in);
232                 } else if (family == AF_INET6) {
233                         sa.in6.sin6_port = htobe16(port);
234                         sa.in6.sin6_addr = address->in6;
235                         sa.in6.sin6_scope_id = s->link ? s->link->ifindex : 0;
236                         salen = sizeof(sa.in6);
237                 } else
238                         return -EAFNOSUPPORT;
239         }
240
241         fd = socket(sa.sa.sa_family, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
242         if (fd < 0)
243                 return -errno;
244
245         r = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one));
246         if (r < 0)
247                 return -errno;
248
249         if (s->link) {
250                 uint32_t ifindex = htobe32(s->link->ifindex);
251
252                 if (sa.sa.sa_family == AF_INET) {
253                         r = setsockopt(fd, IPPROTO_IP, IP_UNICAST_IF, &ifindex, sizeof(ifindex));
254                         if (r < 0)
255                                 return -errno;
256                 } else if (sa.sa.sa_family == AF_INET6) {
257                         r = setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_IF, &ifindex, sizeof(ifindex));
258                         if (r < 0)
259                                 return -errno;
260                 }
261         }
262
263         if (s->protocol == DNS_PROTOCOL_LLMNR) {
264                 /* RFC 4795, section 2.5 requires the TTL to be set to 1 */
265
266                 if (sa.sa.sa_family == AF_INET) {
267                         r = setsockopt(fd, IPPROTO_IP, IP_TTL, &one, sizeof(one));
268                         if (r < 0)
269                                 return -errno;
270                 } else if (sa.sa.sa_family == AF_INET6) {
271                         r = setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &one, sizeof(one));
272                         if (r < 0)
273                                 return -errno;
274                 }
275         }
276
277         r = connect(fd, &sa.sa, salen);
278         if (r < 0 && errno != EINPROGRESS)
279                 return -errno;
280
281         ret = fd;
282         fd = -1;
283
284         return ret;
285 }
286
287 DnsScopeMatch dns_scope_good_domain(DnsScope *s, const char *domain) {
288         char **i;
289
290         assert(s);
291         assert(domain);
292
293         STRV_FOREACH(i, s->domains)
294                 if (dns_name_endswith(domain, *i) > 0)
295                         return DNS_SCOPE_YES;
296
297         if (dns_name_root(domain) != 0)
298                 return DNS_SCOPE_NO;
299
300         if (is_localhost(domain))
301                 return DNS_SCOPE_NO;
302
303         if (s->protocol == DNS_PROTOCOL_DNS) {
304                 if (dns_name_endswith(domain, "254.169.in-addr.arpa") == 0 &&
305                     dns_name_endswith(domain, "0.8.e.f.ip6.arpa") == 0 &&
306                     dns_name_single_label(domain) == 0)
307                         return DNS_SCOPE_MAYBE;
308
309                 return DNS_SCOPE_NO;
310         }
311
312         if (s->protocol == DNS_PROTOCOL_MDNS) {
313                 if (dns_name_endswith(domain, "254.169.in-addr.arpa") > 0 ||
314                     dns_name_endswith(domain, "0.8.e.f.ip6.arpa") > 0 ||
315                     (dns_name_endswith(domain, "local") > 0 && dns_name_equal(domain, "local") == 0))
316                         return DNS_SCOPE_MAYBE;
317
318                 return DNS_SCOPE_NO;
319         }
320
321         if (s->protocol == DNS_PROTOCOL_LLMNR) {
322                 if (dns_name_endswith(domain, "in-addr.arpa") > 0 ||
323                     dns_name_endswith(domain, "ip6.arpa") > 0 ||
324                     dns_name_single_label(domain) > 0)
325                         return DNS_SCOPE_MAYBE;
326
327                 return DNS_SCOPE_NO;
328         }
329
330         assert_not_reached("Unknown scope protocol");
331 }
332
333 int dns_scope_good_key(DnsScope *s, DnsResourceKey *key) {
334         assert(s);
335         assert(key);
336
337         if (s->protocol == DNS_PROTOCOL_DNS)
338                 return true;
339
340         /* On mDNS and LLMNR, send A and AAAA queries only on the
341          * respective scopes */
342
343         if (s->family == AF_INET && key->class == DNS_CLASS_IN && key->type == DNS_TYPE_AAAA)
344                 return false;
345
346         if (s->family == AF_INET6 && key->class == DNS_CLASS_IN && key->type == DNS_TYPE_A)
347                 return false;
348
349         return true;
350 }
351
352 int dns_scope_llmnr_membership(DnsScope *s, bool b) {
353         int fd;
354
355         if (s->family == AF_INET) {
356                 struct ip_mreqn mreqn = {
357                         .imr_multiaddr = LLMNR_MULTICAST_IPV4_ADDRESS,
358                         .imr_ifindex = s->link->ifindex,
359                 };
360
361                 fd = manager_llmnr_ipv4_udp_fd(s->manager);
362                 if (fd < 0)
363                         return fd;
364
365                 /* Always first try to drop membership before we add
366                  * one. This is necessary on some devices, such as
367                  * veth. */
368                 if (b)
369                         setsockopt(fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreqn, sizeof(mreqn));
370
371                 if (setsockopt(fd, IPPROTO_IP, b ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP, &mreqn, sizeof(mreqn)) < 0)
372                         return -errno;
373
374         } else if (s->family == AF_INET6) {
375                 struct ipv6_mreq mreq = {
376                         .ipv6mr_multiaddr = LLMNR_MULTICAST_IPV6_ADDRESS,
377                         .ipv6mr_interface = s->link->ifindex,
378                 };
379
380                 fd = manager_llmnr_ipv6_udp_fd(s->manager);
381                 if (fd < 0)
382                         return fd;
383
384                 if (b)
385                         setsockopt(fd, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, &mreq, sizeof(mreq));
386
387                 if (setsockopt(fd, IPPROTO_IPV6, b ? IPV6_ADD_MEMBERSHIP : IPV6_DROP_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
388                         return -errno;
389         } else
390                 return -EAFNOSUPPORT;
391
392         return 0;
393 }
394
395 int dns_scope_good_dns_server(DnsScope *s, int family, const union in_addr_union *address) {
396         assert(s);
397         assert(address);
398
399         if (s->protocol != DNS_PROTOCOL_DNS)
400                 return 1;
401
402         if (s->link)
403                 return !!link_find_dns_server(s->link,  family, address);
404         else
405                 return !!manager_find_dns_server(s->manager, family, address);
406 }
407
408 static int dns_scope_make_reply_packet(
409                 DnsScope *s,
410                 uint16_t id,
411                 int rcode,
412                 DnsQuestion *q,
413                 DnsAnswer *answer,
414                 DnsAnswer *soa,
415                 bool tentative,
416                 DnsPacket **ret) {
417
418         _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
419         unsigned i;
420         int r;
421
422         assert(s);
423
424         if ((!q || q->n_keys <= 0)
425             && (!answer || answer->n_rrs <= 0)
426             && (!soa || soa->n_rrs <= 0))
427                 return -EINVAL;
428
429         r = dns_packet_new(&p, s->protocol, 0);
430         if (r < 0)
431                 return r;
432
433         DNS_PACKET_HEADER(p)->id = id;
434         DNS_PACKET_HEADER(p)->flags = htobe16(DNS_PACKET_MAKE_FLAGS(
435                                                               1 /* qr */,
436                                                               0 /* opcode */,
437                                                               0 /* c */,
438                                                               0 /* tc */,
439                                                               tentative,
440                                                               0 /* (ra) */,
441                                                               0 /* (ad) */,
442                                                               0 /* (cd) */,
443                                                               rcode));
444
445         if (q) {
446                 for (i = 0; i < q->n_keys; i++) {
447                         r = dns_packet_append_key(p, q->keys[i], NULL);
448                         if (r < 0)
449                                 return r;
450                 }
451
452                 DNS_PACKET_HEADER(p)->qdcount = htobe16(q->n_keys);
453         }
454
455         if (answer) {
456                 for (i = 0; i < answer->n_rrs; i++) {
457                         r = dns_packet_append_rr(p, answer->rrs[i], NULL);
458                         if (r < 0)
459                                 return r;
460                 }
461
462                 DNS_PACKET_HEADER(p)->ancount = htobe16(answer->n_rrs);
463         }
464
465         if (soa) {
466                 for (i = 0; i < soa->n_rrs; i++) {
467                         r = dns_packet_append_rr(p, soa->rrs[i], NULL);
468                         if (r < 0)
469                                 return r;
470                 }
471
472                 DNS_PACKET_HEADER(p)->arcount = htobe16(soa->n_rrs);
473         }
474
475         *ret = p;
476         p = NULL;
477
478         return 0;
479 }
480
481 void dns_scope_process_query(DnsScope *s, DnsStream *stream, DnsPacket *p) {
482         _cleanup_(dns_packet_unrefp) DnsPacket *reply = NULL;
483         _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL, *soa = NULL;
484         bool tentative = false;
485         int r, fd;
486
487         assert(s);
488         assert(p);
489
490         if (p->protocol != DNS_PROTOCOL_LLMNR)
491                 return;
492
493         if (p->ipproto == IPPROTO_UDP) {
494                 /* Don't accept UDP queries directed to anything but
495                  * the LLMNR multicast addresses. See RFC 4795,
496                  * section 2.5.*/
497
498                 if (p->family == AF_INET && !in_addr_equal(AF_INET, &p->destination, (union in_addr_union*) &LLMNR_MULTICAST_IPV4_ADDRESS))
499                         return;
500
501                 if (p->family == AF_INET6 && !in_addr_equal(AF_INET6, &p->destination, (union in_addr_union*) &LLMNR_MULTICAST_IPV6_ADDRESS))
502                         return;
503         }
504
505         r = dns_packet_extract(p);
506         if (r < 0) {
507                 log_debug("Failed to extract resources from incoming packet: %s", strerror(-r));
508                 return;
509         }
510
511         if (DNS_PACKET_C(p)) {
512                 /* FIXME: Somebody notified us about a likely conflict */
513                 return;
514         }
515
516         r = dns_zone_lookup(&s->zone, p->question, &answer, &soa, &tentative);
517         if (r < 0) {
518                 log_debug("Failed to lookup key: %s", strerror(-r));
519                 return;
520         }
521         if (r == 0)
522                 return;
523
524         if (answer)
525                 dns_answer_order_by_scope(answer, in_addr_is_link_local(p->family, &p->sender) > 0);
526
527         r = dns_scope_make_reply_packet(s, DNS_PACKET_ID(p), DNS_RCODE_SUCCESS, p->question, answer, soa, tentative, &reply);
528         if (r < 0) {
529                 log_debug("Failed to build reply packet: %s", strerror(-r));
530                 return;
531         }
532
533         if (stream)
534                 r = dns_stream_write_packet(stream, reply);
535         else {
536                 if (!ratelimit_test(&s->ratelimit))
537                         return;
538
539                 if (p->family == AF_INET)
540                         fd = manager_llmnr_ipv4_udp_fd(s->manager);
541                 else if (p->family == AF_INET6)
542                         fd = manager_llmnr_ipv6_udp_fd(s->manager);
543                 else {
544                         log_debug("Unknown protocol");
545                         return;
546                 }
547                 if (fd < 0) {
548                         log_debug("Failed to get reply socket: %s", strerror(-fd));
549                         return;
550                 }
551
552                 r = manager_send(s->manager, fd, p->ifindex, p->family, &p->sender, p->sender_port, reply);
553         }
554
555         if (r < 0) {
556                 log_debug("Failed to send reply packet: %s", strerror(-r));
557                 return;
558         }
559 }
560
561 DnsTransaction *dns_scope_find_transaction(DnsScope *scope, DnsQuestion *question, bool cache_ok) {
562         DnsTransaction *t;
563
564         assert(scope);
565         assert(question);
566
567         /* Try to find an ongoing transaction that is a equal or a
568          * superset of the specified question */
569
570         LIST_FOREACH(transactions_by_scope, t, scope->transactions) {
571
572                 /* Refuse reusing transactions that completed based on
573                  * cached data instead of a real packet, if that's
574                  * requested. */
575                 if (!cache_ok &&
576                     IN_SET(t->state, DNS_TRANSACTION_SUCCESS, DNS_TRANSACTION_FAILURE) &&
577                     !t->received)
578                         continue;
579
580                 if (dns_question_is_superset(t->question, question) > 0)
581                         return t;
582         }
583
584         return NULL;
585 }