]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/resolve/resolved-llmnr.c
resolved: cache stringified transaction key once per transaction
[thirdparty/systemd.git] / src / resolve / resolved-llmnr.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 Tom Gundersen <teg@jklm.no>
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/in.h>
23 #include <resolv.h>
24
25 #include "fd-util.h"
26 #include "resolved-llmnr.h"
27 #include "resolved-manager.h"
28
29 void manager_llmnr_stop(Manager *m) {
30 assert(m);
31
32 m->llmnr_ipv4_udp_event_source = sd_event_source_unref(m->llmnr_ipv4_udp_event_source);
33 m->llmnr_ipv4_udp_fd = safe_close(m->llmnr_ipv4_udp_fd);
34
35 m->llmnr_ipv6_udp_event_source = sd_event_source_unref(m->llmnr_ipv6_udp_event_source);
36 m->llmnr_ipv6_udp_fd = safe_close(m->llmnr_ipv6_udp_fd);
37
38 m->llmnr_ipv4_tcp_event_source = sd_event_source_unref(m->llmnr_ipv4_tcp_event_source);
39 m->llmnr_ipv4_tcp_fd = safe_close(m->llmnr_ipv4_tcp_fd);
40
41 m->llmnr_ipv6_tcp_event_source = sd_event_source_unref(m->llmnr_ipv6_tcp_event_source);
42 m->llmnr_ipv6_tcp_fd = safe_close(m->llmnr_ipv6_tcp_fd);
43 }
44
45 int manager_llmnr_start(Manager *m) {
46 int r;
47
48 assert(m);
49
50 if (m->llmnr_support == SUPPORT_NO)
51 return 0;
52
53 r = manager_llmnr_ipv4_udp_fd(m);
54 if (r == -EADDRINUSE)
55 goto eaddrinuse;
56 if (r < 0)
57 return r;
58
59 r = manager_llmnr_ipv4_tcp_fd(m);
60 if (r == -EADDRINUSE)
61 goto eaddrinuse;
62 if (r < 0)
63 return r;
64
65 if (socket_ipv6_is_supported()) {
66 r = manager_llmnr_ipv6_udp_fd(m);
67 if (r == -EADDRINUSE)
68 goto eaddrinuse;
69 if (r < 0)
70 return r;
71
72 r = manager_llmnr_ipv6_tcp_fd(m);
73 if (r == -EADDRINUSE)
74 goto eaddrinuse;
75 if (r < 0)
76 return r;
77 }
78
79 return 0;
80
81 eaddrinuse:
82 log_warning("There appears to be another LLMNR responder running. Turning off LLMNR support.");
83 m->llmnr_support = SUPPORT_NO;
84 manager_llmnr_stop(m);
85
86 return 0;
87 }
88
89 static int on_llmnr_packet(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
90 _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
91 DnsTransaction *t = NULL;
92 Manager *m = userdata;
93 DnsScope *scope;
94 int r;
95
96 r = manager_recv(m, fd, DNS_PROTOCOL_LLMNR, &p);
97 if (r <= 0)
98 return r;
99
100 scope = manager_find_scope(m, p);
101 if (!scope) {
102 log_warning("Got LLMNR UDP packet on unknown scope. Ignoring.");
103 return 0;
104 }
105
106 if (dns_packet_validate_reply(p) > 0) {
107 log_debug("Got LLMNR reply packet for id %u", DNS_PACKET_ID(p));
108
109 dns_scope_check_conflicts(scope, p);
110
111 t = hashmap_get(m->dns_transactions, UINT_TO_PTR(DNS_PACKET_ID(p)));
112 if (t)
113 dns_transaction_process_reply(t, p);
114
115 } else if (dns_packet_validate_query(p) > 0) {
116 log_debug("Got LLMNR query packet for id %u", DNS_PACKET_ID(p));
117
118 dns_scope_process_query(scope, NULL, p);
119 } else
120 log_debug("Invalid LLMNR UDP packet.");
121
122 return 0;
123 }
124
125 int manager_llmnr_ipv4_udp_fd(Manager *m) {
126 union sockaddr_union sa = {
127 .in.sin_family = AF_INET,
128 .in.sin_port = htobe16(LLMNR_PORT),
129 };
130 static const int one = 1, pmtu = IP_PMTUDISC_DONT, ttl = 255;
131 int r;
132
133 assert(m);
134
135 if (m->llmnr_ipv4_udp_fd >= 0)
136 return m->llmnr_ipv4_udp_fd;
137
138 m->llmnr_ipv4_udp_fd = socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
139 if (m->llmnr_ipv4_udp_fd < 0)
140 return -errno;
141
142 /* RFC 4795, section 2.5 recommends setting the TTL of UDP packets to 255. */
143 r = setsockopt(m->llmnr_ipv4_udp_fd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl));
144 if (r < 0) {
145 r = -errno;
146 goto fail;
147 }
148
149 r = setsockopt(m->llmnr_ipv4_udp_fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl));
150 if (r < 0) {
151 r = -errno;
152 goto fail;
153 }
154
155 r = setsockopt(m->llmnr_ipv4_udp_fd, IPPROTO_IP, IP_MULTICAST_LOOP, &one, sizeof(one));
156 if (r < 0) {
157 r = -errno;
158 goto fail;
159 }
160
161 r = setsockopt(m->llmnr_ipv4_udp_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
162 if (r < 0) {
163 r = -errno;
164 goto fail;
165 }
166
167 r = setsockopt(m->llmnr_ipv4_udp_fd, IPPROTO_IP, IP_PKTINFO, &one, sizeof(one));
168 if (r < 0) {
169 r = -errno;
170 goto fail;
171 }
172
173 r = setsockopt(m->llmnr_ipv4_udp_fd, IPPROTO_IP, IP_RECVTTL, &one, sizeof(one));
174 if (r < 0) {
175 r = -errno;
176 goto fail;
177 }
178
179 /* Disable Don't-Fragment bit in the IP header */
180 r = setsockopt(m->llmnr_ipv4_udp_fd, IPPROTO_IP, IP_MTU_DISCOVER, &pmtu, sizeof(pmtu));
181 if (r < 0) {
182 r = -errno;
183 goto fail;
184 }
185
186 r = bind(m->llmnr_ipv4_udp_fd, &sa.sa, sizeof(sa.in));
187 if (r < 0) {
188 r = -errno;
189 goto fail;
190 }
191
192 r = sd_event_add_io(m->event, &m->llmnr_ipv4_udp_event_source, m->llmnr_ipv4_udp_fd, EPOLLIN, on_llmnr_packet, m);
193 if (r < 0)
194 goto fail;
195
196 return m->llmnr_ipv4_udp_fd;
197
198 fail:
199 m->llmnr_ipv4_udp_fd = safe_close(m->llmnr_ipv4_udp_fd);
200 return r;
201 }
202
203 int manager_llmnr_ipv6_udp_fd(Manager *m) {
204 union sockaddr_union sa = {
205 .in6.sin6_family = AF_INET6,
206 .in6.sin6_port = htobe16(LLMNR_PORT),
207 };
208 static const int one = 1, ttl = 255;
209 int r;
210
211 assert(m);
212
213 if (m->llmnr_ipv6_udp_fd >= 0)
214 return m->llmnr_ipv6_udp_fd;
215
216 m->llmnr_ipv6_udp_fd = socket(AF_INET6, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
217 if (m->llmnr_ipv6_udp_fd < 0)
218 return -errno;
219
220 r = setsockopt(m->llmnr_ipv6_udp_fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl));
221 if (r < 0) {
222 r = -errno;
223 goto fail;
224 }
225
226 /* RFC 4795, section 2.5 recommends setting the TTL of UDP packets to 255. */
227 r = setsockopt(m->llmnr_ipv6_udp_fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &ttl, sizeof(ttl));
228 if (r < 0) {
229 r = -errno;
230 goto fail;
231 }
232
233 r = setsockopt(m->llmnr_ipv6_udp_fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &one, sizeof(one));
234 if (r < 0) {
235 r = -errno;
236 goto fail;
237 }
238
239 r = setsockopt(m->llmnr_ipv6_udp_fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one));
240 if (r < 0) {
241 r = -errno;
242 goto fail;
243 }
244
245 r = setsockopt(m->llmnr_ipv6_udp_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
246 if (r < 0) {
247 r = -errno;
248 goto fail;
249 }
250
251 r = setsockopt(m->llmnr_ipv6_udp_fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &one, sizeof(one));
252 if (r < 0) {
253 r = -errno;
254 goto fail;
255 }
256
257 r = setsockopt(m->llmnr_ipv6_udp_fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &one, sizeof(one));
258 if (r < 0) {
259 r = -errno;
260 goto fail;
261 }
262
263 r = bind(m->llmnr_ipv6_udp_fd, &sa.sa, sizeof(sa.in6));
264 if (r < 0) {
265 r = -errno;
266 goto fail;
267 }
268
269 r = sd_event_add_io(m->event, &m->llmnr_ipv6_udp_event_source, m->llmnr_ipv6_udp_fd, EPOLLIN, on_llmnr_packet, m);
270 if (r < 0) {
271 r = -errno;
272 goto fail;
273 }
274
275 return m->llmnr_ipv6_udp_fd;
276
277 fail:
278 m->llmnr_ipv6_udp_fd = safe_close(m->llmnr_ipv6_udp_fd);
279 return r;
280 }
281
282 static int on_llmnr_stream_packet(DnsStream *s) {
283 DnsScope *scope;
284
285 assert(s);
286
287 scope = manager_find_scope(s->manager, s->read_packet);
288 if (!scope) {
289 log_warning("Got LLMNR TCP packet on unknown scope. Ignroing.");
290 return 0;
291 }
292
293 if (dns_packet_validate_query(s->read_packet) > 0) {
294 log_debug("Got query packet for id %u", DNS_PACKET_ID(s->read_packet));
295
296 dns_scope_process_query(scope, s, s->read_packet);
297
298 /* If no reply packet was set, we free the stream */
299 if (s->write_packet)
300 return 0;
301 } else
302 log_debug("Invalid LLMNR TCP packet.");
303
304 dns_stream_free(s);
305 return 0;
306 }
307
308 static int on_llmnr_stream(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
309 DnsStream *stream;
310 Manager *m = userdata;
311 int cfd, r;
312
313 cfd = accept4(fd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC);
314 if (cfd < 0) {
315 if (errno == EAGAIN || errno == EINTR)
316 return 0;
317
318 return -errno;
319 }
320
321 r = dns_stream_new(m, &stream, DNS_PROTOCOL_LLMNR, cfd);
322 if (r < 0) {
323 safe_close(cfd);
324 return r;
325 }
326
327 stream->on_packet = on_llmnr_stream_packet;
328 return 0;
329 }
330
331 int manager_llmnr_ipv4_tcp_fd(Manager *m) {
332 union sockaddr_union sa = {
333 .in.sin_family = AF_INET,
334 .in.sin_port = htobe16(LLMNR_PORT),
335 };
336 static const int one = 1, pmtu = IP_PMTUDISC_DONT;
337 int r;
338
339 assert(m);
340
341 if (m->llmnr_ipv4_tcp_fd >= 0)
342 return m->llmnr_ipv4_tcp_fd;
343
344 m->llmnr_ipv4_tcp_fd = socket(AF_INET, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
345 if (m->llmnr_ipv4_tcp_fd < 0)
346 return -errno;
347
348 /* RFC 4795, section 2.5. requires setting the TTL of TCP streams to 1 */
349 r = setsockopt(m->llmnr_ipv4_tcp_fd, IPPROTO_IP, IP_TTL, &one, sizeof(one));
350 if (r < 0) {
351 r = -errno;
352 goto fail;
353 }
354
355 r = setsockopt(m->llmnr_ipv4_tcp_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
356 if (r < 0) {
357 r = -errno;
358 goto fail;
359 }
360
361 r = setsockopt(m->llmnr_ipv4_tcp_fd, IPPROTO_IP, IP_PKTINFO, &one, sizeof(one));
362 if (r < 0) {
363 r = -errno;
364 goto fail;
365 }
366
367 r = setsockopt(m->llmnr_ipv4_tcp_fd, IPPROTO_IP, IP_RECVTTL, &one, sizeof(one));
368 if (r < 0) {
369 r = -errno;
370 goto fail;
371 }
372
373 /* Disable Don't-Fragment bit in the IP header */
374 r = setsockopt(m->llmnr_ipv4_tcp_fd, IPPROTO_IP, IP_MTU_DISCOVER, &pmtu, sizeof(pmtu));
375 if (r < 0) {
376 r = -errno;
377 goto fail;
378 }
379
380 r = bind(m->llmnr_ipv4_tcp_fd, &sa.sa, sizeof(sa.in));
381 if (r < 0) {
382 r = -errno;
383 goto fail;
384 }
385
386 r = listen(m->llmnr_ipv4_tcp_fd, SOMAXCONN);
387 if (r < 0) {
388 r = -errno;
389 goto fail;
390 }
391
392 r = sd_event_add_io(m->event, &m->llmnr_ipv4_tcp_event_source, m->llmnr_ipv4_tcp_fd, EPOLLIN, on_llmnr_stream, m);
393 if (r < 0)
394 goto fail;
395
396 return m->llmnr_ipv4_tcp_fd;
397
398 fail:
399 m->llmnr_ipv4_tcp_fd = safe_close(m->llmnr_ipv4_tcp_fd);
400 return r;
401 }
402
403 int manager_llmnr_ipv6_tcp_fd(Manager *m) {
404 union sockaddr_union sa = {
405 .in6.sin6_family = AF_INET6,
406 .in6.sin6_port = htobe16(LLMNR_PORT),
407 };
408 static const int one = 1;
409 int r;
410
411 assert(m);
412
413 if (m->llmnr_ipv6_tcp_fd >= 0)
414 return m->llmnr_ipv6_tcp_fd;
415
416 m->llmnr_ipv6_tcp_fd = socket(AF_INET6, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
417 if (m->llmnr_ipv6_tcp_fd < 0)
418 return -errno;
419
420 /* RFC 4795, section 2.5. requires setting the TTL of TCP streams to 1 */
421 r = setsockopt(m->llmnr_ipv6_tcp_fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &one, sizeof(one));
422 if (r < 0) {
423 r = -errno;
424 goto fail;
425 }
426
427 r = setsockopt(m->llmnr_ipv6_tcp_fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one));
428 if (r < 0) {
429 r = -errno;
430 goto fail;
431 }
432
433 r = setsockopt(m->llmnr_ipv6_tcp_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
434 if (r < 0) {
435 r = -errno;
436 goto fail;
437 }
438
439 r = setsockopt(m->llmnr_ipv6_tcp_fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &one, sizeof(one));
440 if (r < 0) {
441 r = -errno;
442 goto fail;
443 }
444
445 r = setsockopt(m->llmnr_ipv6_tcp_fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &one, sizeof(one));
446 if (r < 0) {
447 r = -errno;
448 goto fail;
449 }
450
451 r = bind(m->llmnr_ipv6_tcp_fd, &sa.sa, sizeof(sa.in6));
452 if (r < 0) {
453 r = -errno;
454 goto fail;
455 }
456
457 r = listen(m->llmnr_ipv6_tcp_fd, SOMAXCONN);
458 if (r < 0) {
459 r = -errno;
460 goto fail;
461 }
462
463 r = sd_event_add_io(m->event, &m->llmnr_ipv6_tcp_event_source, m->llmnr_ipv6_tcp_fd, EPOLLIN, on_llmnr_stream, m);
464 if (r < 0)
465 goto fail;
466
467 return m->llmnr_ipv6_tcp_fd;
468
469 fail:
470 m->llmnr_ipv6_tcp_fd = safe_close(m->llmnr_ipv6_tcp_fd);
471 return r;
472 }