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