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