]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/resolve/resolved-dns-scope.c
keymap: Fix HP Pavillon DV7
[thirdparty/systemd.git] / src / resolve / resolved-dns-scope.c
CommitLineData
74b2466e
LP
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
ad867662
LP
22#include <netinet/tcp.h>
23
623a4c97 24#include "missing.h"
74b2466e 25#include "strv.h"
ad867662 26#include "socket-util.h"
46f08bea 27#include "af-list.h"
74b2466e
LP
28#include "resolved-dns-domain.h"
29#include "resolved-dns-scope.h"
30
0dd25fb9 31int dns_scope_new(Manager *m, DnsScope **ret, Link *l, DnsProtocol protocol, int family) {
74b2466e
LP
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;
1716f6dc
LP
42 s->link = l;
43 s->protocol = protocol;
44 s->family = family;
74b2466e
LP
45
46 LIST_PREPEND(scopes, m->dns_scopes, s);
47
1716f6dc
LP
48 dns_scope_llmnr_membership(s, true);
49
46f08bea 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));
1716f6dc 51
74b2466e
LP
52 *ret = s;
53 return 0;
54}
55
56DnsScope* dns_scope_free(DnsScope *s) {
ec2c5e43 57 DnsTransaction *t;
faa133f3 58
74b2466e
LP
59 if (!s)
60 return NULL;
61
46f08bea 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));
1716f6dc
LP
63
64 dns_scope_llmnr_membership(s, false);
65
faa133f3
LP
66 while ((t = s->transactions)) {
67
68 /* Abort the transaction, but make sure it is not
69 * freed while we still look at it */
74b2466e 70
faa133f3 71 t->block_gc++;
ec2c5e43 72 dns_transaction_complete(t, DNS_TRANSACTION_ABORTED);
faa133f3 73 t->block_gc--;
74b2466e 74
ec2c5e43 75 dns_transaction_free(t);
74b2466e
LP
76 }
77
322345fd 78 dns_cache_flush(&s->cache);
623a4c97 79 dns_zone_flush(&s->zone);
322345fd 80
74b2466e
LP
81 LIST_REMOVE(scopes, s->manager->dns_scopes, s);
82 strv_free(s->domains);
83 free(s);
84
85 return NULL;
86}
87
2c27fbca 88DnsServer *dns_scope_get_dns_server(DnsScope *s) {
74b2466e
LP
89 assert(s);
90
1716f6dc
LP
91 if (s->protocol != DNS_PROTOCOL_DNS)
92 return NULL;
93
74b2466e
LP
94 if (s->link)
95 return link_get_dns_server(s->link);
96 else
97 return manager_get_dns_server(s->manager);
98}
99
100void dns_scope_next_dns_server(DnsScope *s) {
101 assert(s);
102
1716f6dc
LP
103 if (s->protocol != DNS_PROTOCOL_DNS)
104 return;
105
74b2466e
LP
106 if (s->link)
107 link_next_dns_server(s->link);
108 else
109 manager_next_dns_server(s->manager);
110}
111
112int dns_scope_send(DnsScope *s, DnsPacket *p) {
1716f6dc
LP
113 union in_addr_union addr;
114 int ifindex = 0, r;
0dd25fb9 115 int family;
1716f6dc
LP
116 uint16_t port;
117 uint32_t mtu;
118 int fd;
74b2466e
LP
119
120 assert(s);
121 assert(p);
1716f6dc 122 assert(p->protocol == s->protocol);
ad867662
LP
123
124 if (s->link) {
1716f6dc 125 mtu = s->link->mtu;
74b2466e 126 ifindex = s->link->ifindex;
1716f6dc 127 } else
e1c95994 128 mtu = manager_find_mtu(s->manager);
74b2466e 129
1716f6dc
LP
130 if (s->protocol == DNS_PROTOCOL_DNS) {
131 DnsServer *srv;
e1c95994 132
623a4c97
LP
133 if (DNS_PACKET_QDCOUNT(p) > 1)
134 return -ENOTSUP;
135
2c27fbca 136 srv = dns_scope_get_dns_server(s);
1716f6dc
LP
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;
1716f6dc
LP
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);
1716f6dc
LP
173 } else
174 return -EAFNOSUPPORT;
175 if (fd < 0)
176 return fd;
177 } else
74b2466e
LP
178 return -EAFNOSUPPORT;
179
1716f6dc 180 r = manager_send(s->manager, fd, ifindex, family, &addr, port, p);
74b2466e
LP
181 if (r < 0)
182 return r;
183
184 return 1;
185}
186
623a4c97 187int dns_scope_tcp_socket(DnsScope *s, int family, const union in_addr_union *address, uint16_t port) {
ad867662
LP
188 _cleanup_close_ int fd = -1;
189 union sockaddr_union sa = {};
190 socklen_t salen;
623a4c97
LP
191 static const int one = 1;
192 int ret, r;
ad867662
LP
193
194 assert(s);
623a4c97 195 assert((family == AF_UNSPEC) == !address);
ad867662 196
623a4c97
LP
197 if (family == AF_UNSPEC) {
198 DnsServer *srv;
199
2c27fbca 200 srv = dns_scope_get_dns_server(s);
623a4c97
LP
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 }
ad867662 231
623a4c97 232 fd = socket(sa.sa.sa_family, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
ad867662
LP
233 if (fd < 0)
234 return -errno;
235
623a4c97
LP
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) {
bf3f1271 255 /* RFC 4795, section 2.5 requires the TTL to be set to 1 */
623a4c97
LP
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 }
ad867662
LP
267
268 r = connect(fd, &sa.sa, salen);
269 if (r < 0 && errno != EINPROGRESS)
270 return -errno;
271
272 ret = fd;
273 fd = -1;
623a4c97 274
ad867662
LP
275 return ret;
276}
277
1716f6dc 278DnsScopeMatch dns_scope_good_domain(DnsScope *s, const char *domain) {
74b2466e
LP
279 char **i;
280
281 assert(s);
282 assert(domain);
283
284 STRV_FOREACH(i, s->domains)
faa133f3 285 if (dns_name_endswith(domain, *i) > 0)
74b2466e
LP
286 return DNS_SCOPE_YES;
287
faa133f3 288 if (dns_name_root(domain) != 0)
74b2466e
LP
289 return DNS_SCOPE_NO;
290
faec72d5
LP
291 if (is_localhost(domain))
292 return DNS_SCOPE_NO;
293
1716f6dc 294 if (s->protocol == DNS_PROTOCOL_DNS) {
faa133f3
LP
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;
1716f6dc 299
faa133f3 300 return DNS_SCOPE_NO;
1716f6dc
LP
301 }
302
303 if (s->protocol == DNS_PROTOCOL_MDNS) {
faa133f3
LP
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))
74b2466e
LP
307 return DNS_SCOPE_MAYBE;
308
309 return DNS_SCOPE_NO;
310 }
311
1716f6dc 312 if (s->protocol == DNS_PROTOCOL_LLMNR) {
b914e211
LP
313 if (dns_name_endswith(domain, "in-addr.arpa") > 0 ||
314 dns_name_endswith(domain, "ip6.arpa") > 0 ||
faa133f3 315 dns_name_single_label(domain) > 0)
1716f6dc 316 return DNS_SCOPE_MAYBE;
74b2466e 317
1716f6dc 318 return DNS_SCOPE_NO;
74b2466e
LP
319 }
320
1716f6dc
LP
321 assert_not_reached("Unknown scope protocol");
322}
323
324int 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
343int 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
7b4c2ee7
LP
356 /* Always first try to drop membership before we add
357 * one. This is necessary on some devices, such as
358 * veth. */
359 if (b)
360 setsockopt(fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreqn, sizeof(mreqn));
361
1716f6dc
LP
362 if (setsockopt(fd, IPPROTO_IP, b ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP, &mreqn, sizeof(mreqn)) < 0)
363 return -errno;
364
365 } else if (s->family == AF_INET6) {
366 struct ipv6_mreq mreq = {
367 .ipv6mr_multiaddr = LLMNR_MULTICAST_IPV6_ADDRESS,
368 .ipv6mr_interface = s->link->ifindex,
369 };
370
371 fd = manager_llmnr_ipv6_udp_fd(s->manager);
372 if (fd < 0)
373 return fd;
374
7b4c2ee7
LP
375 if (b)
376 setsockopt(fd, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, &mreq, sizeof(mreq));
377
1716f6dc
LP
378 if (setsockopt(fd, IPPROTO_IPV6, b ? IPV6_ADD_MEMBERSHIP : IPV6_DROP_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
379 return -errno;
380 } else
381 return -EAFNOSUPPORT;
382
383 return 0;
74b2466e 384}
623a4c97
LP
385
386int dns_scope_good_dns_server(DnsScope *s, int family, const union in_addr_union *address) {
387 assert(s);
388 assert(address);
389
390 if (s->protocol != DNS_PROTOCOL_DNS)
391 return 1;
392
393 if (s->link)
394 return !!link_find_dns_server(s->link, family, address);
395 else
2c27fbca 396 return !!manager_find_dns_server(s->manager, family, address);
623a4c97
LP
397}
398
ec2c5e43
LP
399static int dns_scope_make_reply_packet(
400 DnsScope *s,
401 uint16_t id,
402 int rcode,
403 DnsQuestion *q,
404 DnsAnswer *answer,
405 DnsAnswer *soa,
406 bool tentative,
407 DnsPacket **ret) {
408
623a4c97
LP
409 _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
410 unsigned i;
411 int r;
412
413 assert(s);
414
75cd513e
TA
415 if ((!q || q->n_keys <= 0)
416 && (!answer || answer->n_rrs <= 0)
417 && (!soa || soa->n_rrs <= 0))
623a4c97
LP
418 return -EINVAL;
419
420 r = dns_packet_new(&p, s->protocol, 0);
421 if (r < 0)
422 return r;
423
424 DNS_PACKET_HEADER(p)->id = id;
ea917db9
LP
425 DNS_PACKET_HEADER(p)->flags = htobe16(DNS_PACKET_MAKE_FLAGS(
426 1 /* qr */,
427 0 /* opcode */,
428 0 /* c */,
429 0 /* tc */,
ec2c5e43 430 tentative,
ea917db9
LP
431 0 /* (ra) */,
432 0 /* (ad) */,
433 0 /* (cd) */,
434 rcode));
623a4c97
LP
435
436 if (q) {
437 for (i = 0; i < q->n_keys; i++) {
438 r = dns_packet_append_key(p, q->keys[i], NULL);
439 if (r < 0)
440 return r;
441 }
442
443 DNS_PACKET_HEADER(p)->qdcount = htobe16(q->n_keys);
444 }
445
8bf52d3d
LP
446 if (answer) {
447 for (i = 0; i < answer->n_rrs; i++) {
448 r = dns_packet_append_rr(p, answer->rrs[i], NULL);
623a4c97
LP
449 if (r < 0)
450 return r;
451 }
452
8bf52d3d
LP
453 DNS_PACKET_HEADER(p)->ancount = htobe16(answer->n_rrs);
454 }
455
456 if (soa) {
457 for (i = 0; i < soa->n_rrs; i++) {
458 r = dns_packet_append_rr(p, soa->rrs[i], NULL);
459 if (r < 0)
460 return r;
461 }
462
463 DNS_PACKET_HEADER(p)->arcount = htobe16(soa->n_rrs);
623a4c97
LP
464 }
465
466 *ret = p;
467 p = NULL;
468
469 return 0;
470}
471
472void dns_scope_process_query(DnsScope *s, DnsStream *stream, DnsPacket *p) {
473 _cleanup_(dns_packet_unrefp) DnsPacket *reply = NULL;
8bf52d3d 474 _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL, *soa = NULL;
ec2c5e43 475 bool tentative = false;
623a4c97
LP
476 int r, fd;
477
478 assert(s);
479 assert(p);
480
481 if (p->protocol != DNS_PROTOCOL_LLMNR)
482 return;
483
2442b93d
LP
484 if (p->ipproto == IPPROTO_UDP) {
485 /* Don't accept UDP queries directed to anything but
486 * the LLMNR multicast addresses. See RFC 4795,
487 * section 2.5.*/
488
489 if (p->family == AF_INET && !in_addr_equal(AF_INET, &p->destination, (union in_addr_union*) &LLMNR_MULTICAST_IPV4_ADDRESS))
490 return;
491
492 if (p->family == AF_INET6 && !in_addr_equal(AF_INET6, &p->destination, (union in_addr_union*) &LLMNR_MULTICAST_IPV6_ADDRESS))
493 return;
494 }
495
623a4c97
LP
496 r = dns_packet_extract(p);
497 if (r < 0) {
498 log_debug("Failed to extract resources from incoming packet: %s", strerror(-r));
499 return;
500 }
501
ea917db9
LP
502 if (DNS_PACKET_C(p)) {
503 /* FIXME: Somebody notified us about a likely conflict */
504 return;
505 }
506
ec2c5e43 507 r = dns_zone_lookup(&s->zone, p->question, &answer, &soa, &tentative);
623a4c97
LP
508 if (r < 0) {
509 log_debug("Failed to lookup key: %s", strerror(-r));
510 return;
511 }
512 if (r == 0)
513 return;
514
fcf57f9c
LP
515 if (answer)
516 dns_answer_order_by_scope(answer, in_addr_is_link_local(p->family, &p->sender) > 0);
af93291c 517
ec2c5e43 518 r = dns_scope_make_reply_packet(s, DNS_PACKET_ID(p), DNS_RCODE_SUCCESS, p->question, answer, soa, tentative, &reply);
623a4c97
LP
519 if (r < 0) {
520 log_debug("Failed to build reply packet: %s", strerror(-r));
521 return;
522 }
523
524 if (stream)
525 r = dns_stream_write_packet(stream, reply);
526 else {
527 if (p->family == AF_INET)
528 fd = manager_llmnr_ipv4_udp_fd(s->manager);
529 else if (p->family == AF_INET6)
530 fd = manager_llmnr_ipv6_udp_fd(s->manager);
531 else {
532 log_debug("Unknown protocol");
533 return;
534 }
535 if (fd < 0) {
536 log_debug("Failed to get reply socket: %s", strerror(-fd));
537 return;
538 }
539
540 r = manager_send(s->manager, fd, p->ifindex, p->family, &p->sender, p->sender_port, reply);
541 }
542
543 if (r < 0) {
544 log_debug("Failed to send reply packet: %s", strerror(-r));
545 return;
546 }
547}
ec2c5e43 548
dc4d47e2 549DnsTransaction *dns_scope_find_transaction(DnsScope *scope, DnsQuestion *question, bool cache_ok) {
ec2c5e43
LP
550 DnsTransaction *t;
551
552 assert(scope);
553 assert(question);
554
555 /* Try to find an ongoing transaction that is a equal or a
556 * superset of the specified question */
557
dc4d47e2
LP
558 LIST_FOREACH(transactions_by_scope, t, scope->transactions) {
559
560 /* Refuse reusing transactions that completed based on
561 * cached data instead of a real packet, if that's
562 * requested. */
563 if (!cache_ok &&
564 IN_SET(t->state, DNS_TRANSACTION_SUCCESS, DNS_TRANSACTION_FAILURE) &&
565 !t->received)
566 continue;
567
ec2c5e43
LP
568 if (dns_question_is_superset(t->question, question) > 0)
569 return t;
dc4d47e2 570 }
ec2c5e43
LP
571
572 return NULL;
573}