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