]> git.proxmox.com Git - systemd.git/blame - src/resolve/resolved-llmnr.c
New upstream version 236
[systemd.git] / src / resolve / resolved-llmnr.c
CommitLineData
52ad194e 1/* SPDX-License-Identifier: LGPL-2.1+ */
7035cd9e
MP
2/***
3 This file is part of systemd.
4
5 Copyright 2014 Tom Gundersen <teg@jklm.no>
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19 ***/
20
7035cd9e 21#include <netinet/in.h>
db2df898 22#include <resolv.h>
7035cd9e 23
db2df898 24#include "fd-util.h"
7035cd9e 25#include "resolved-llmnr.h"
db2df898 26#include "resolved-manager.h"
7035cd9e
MP
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
4c89c718 49 if (m->llmnr_support == RESOLVE_SUPPORT_NO)
7035cd9e
MP
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:
81c58355 81 log_warning("Another LLMNR responder prohibits binding the socket to the same port. Turning off LLMNR support.");
4c89c718 82 m->llmnr_support = RESOLVE_SUPPORT_NO;
7035cd9e
MP
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
5a920b42
MP
95 assert(s);
96 assert(fd >= 0);
97 assert(m);
98
7035cd9e
MP
99 r = manager_recv(m, fd, DNS_PROTOCOL_LLMNR, &p);
100 if (r <= 0)
101 return r;
102
52ad194e
MB
103 if (manager_our_packet(m, p))
104 return 0;
105
7035cd9e 106 scope = manager_find_scope(m, p);
52ad194e
MB
107 if (!scope) {
108 log_debug("Got LLMNR UDP packet on unknown scope. Ignoring.");
109 return 0;
110 }
111
112 if (dns_packet_validate_reply(p) > 0) {
5a920b42 113 log_debug("Got LLMNR UDP reply packet for id %u", DNS_PACKET_ID(p));
7035cd9e
MP
114
115 dns_scope_check_conflicts(scope, p);
116
117 t = hashmap_get(m->dns_transactions, UINT_TO_PTR(DNS_PACKET_ID(p)));
118 if (t)
119 dns_transaction_process_reply(t, p);
120
121 } else if (dns_packet_validate_query(p) > 0) {
5a920b42 122 log_debug("Got LLMNR UDP query packet for id %u", DNS_PACKET_ID(p));
7035cd9e
MP
123
124 dns_scope_process_query(scope, NULL, p);
125 } else
4c89c718 126 log_debug("Invalid LLMNR UDP packet, ignoring.");
7035cd9e
MP
127
128 return 0;
129}
130
131int manager_llmnr_ipv4_udp_fd(Manager *m) {
132 union sockaddr_union sa = {
133 .in.sin_family = AF_INET,
134 .in.sin_port = htobe16(LLMNR_PORT),
135 };
136 static const int one = 1, pmtu = IP_PMTUDISC_DONT, ttl = 255;
137 int r;
138
139 assert(m);
140
141 if (m->llmnr_ipv4_udp_fd >= 0)
142 return m->llmnr_ipv4_udp_fd;
143
144 m->llmnr_ipv4_udp_fd = socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
145 if (m->llmnr_ipv4_udp_fd < 0)
81c58355 146 return log_error_errno(errno, "LLMNR-IPv4(UDP): Failed to create socket: %m");
7035cd9e
MP
147
148 /* RFC 4795, section 2.5 recommends setting the TTL of UDP packets to 255. */
149 r = setsockopt(m->llmnr_ipv4_udp_fd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl));
150 if (r < 0) {
81c58355 151 r = log_error_errno(errno, "LLMNR-IPv4(UDP): Failed to set IP_TTL: %m");
7035cd9e
MP
152 goto fail;
153 }
154
155 r = setsockopt(m->llmnr_ipv4_udp_fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl));
156 if (r < 0) {
81c58355 157 r = log_error_errno(errno, "LLMNR-IPv4(UDP): Failed to set IP_MULTICAST_TTL: %m");
7035cd9e
MP
158 goto fail;
159 }
160
161 r = setsockopt(m->llmnr_ipv4_udp_fd, IPPROTO_IP, IP_MULTICAST_LOOP, &one, sizeof(one));
162 if (r < 0) {
81c58355 163 r = log_error_errno(errno, "LLMNR-IPv4(UDP): Failed to set IP_MULTICAST_LOOP: %m");
7035cd9e
MP
164 goto fail;
165 }
166
167 r = setsockopt(m->llmnr_ipv4_udp_fd, IPPROTO_IP, IP_PKTINFO, &one, sizeof(one));
168 if (r < 0) {
81c58355 169 r = log_error_errno(errno, "LLMNR-IPv4(UDP): Failed to set IP_PKTINFO: %m");
7035cd9e
MP
170 goto fail;
171 }
172
173 r = setsockopt(m->llmnr_ipv4_udp_fd, IPPROTO_IP, IP_RECVTTL, &one, sizeof(one));
174 if (r < 0) {
81c58355 175 r = log_error_errno(errno, "LLMNR-IPv4(UDP): Failed to set IP_RECVTTL: %m");
7035cd9e
MP
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) {
81c58355 182 r = log_error_errno(errno, "LLMNR-IPv4(UDP): Failed to set IP_MTU_DISCOVER: %m");
7035cd9e
MP
183 goto fail;
184 }
185
81c58355 186 /* first try to bind without SO_REUSEADDR to detect another LLMNR responder */
7035cd9e
MP
187 r = bind(m->llmnr_ipv4_udp_fd, &sa.sa, sizeof(sa.in));
188 if (r < 0) {
81c58355
MB
189 if (errno != EADDRINUSE) {
190 r = log_error_errno(errno, "LLMNR-IPv4(UDP): Failed to bind socket: %m");
191 goto fail;
192 }
193
194 log_warning("LLMNR-IPv4(UDP): There appears to be another LLMNR responder running, or previously systemd-resolved crashed with some outstanding transfers.");
195
196 /* try again with SO_REUSEADDR */
197 r = setsockopt(m->llmnr_ipv4_udp_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
198 if (r < 0) {
199 r = log_error_errno(errno, "LLMNR-IPv4(UDP): Failed to set SO_REUSEADDR: %m");
200 goto fail;
201 }
202
203 r = bind(m->llmnr_ipv4_udp_fd, &sa.sa, sizeof(sa.in));
204 if (r < 0) {
205 r = log_error_errno(errno, "LLMNR-IPv4(UDP): Failed to bind socket: %m");
206 goto fail;
207 }
208 } else {
209 /* enable SO_REUSEADDR for the case that the user really wants multiple LLMNR responders */
210 r = setsockopt(m->llmnr_ipv4_udp_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
211 if (r < 0) {
212 r = log_error_errno(errno, "LLMNR-IPv4(UDP): Failed to set SO_REUSEADDR: %m");
213 goto fail;
214 }
7035cd9e
MP
215 }
216
217 r = sd_event_add_io(m->event, &m->llmnr_ipv4_udp_event_source, m->llmnr_ipv4_udp_fd, EPOLLIN, on_llmnr_packet, m);
218 if (r < 0)
219 goto fail;
220
4c89c718
MP
221 (void) sd_event_source_set_description(m->llmnr_ipv4_udp_event_source, "llmnr-ipv4-udp");
222
7035cd9e
MP
223 return m->llmnr_ipv4_udp_fd;
224
225fail:
226 m->llmnr_ipv4_udp_fd = safe_close(m->llmnr_ipv4_udp_fd);
227 return r;
228}
229
230int manager_llmnr_ipv6_udp_fd(Manager *m) {
231 union sockaddr_union sa = {
232 .in6.sin6_family = AF_INET6,
233 .in6.sin6_port = htobe16(LLMNR_PORT),
234 };
235 static const int one = 1, ttl = 255;
236 int r;
237
238 assert(m);
239
240 if (m->llmnr_ipv6_udp_fd >= 0)
241 return m->llmnr_ipv6_udp_fd;
242
243 m->llmnr_ipv6_udp_fd = socket(AF_INET6, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
244 if (m->llmnr_ipv6_udp_fd < 0)
81c58355 245 return log_error_errno(errno, "LLMNR-IPv6(UDP): Failed to create socket: %m");
7035cd9e
MP
246
247 r = setsockopt(m->llmnr_ipv6_udp_fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl));
248 if (r < 0) {
81c58355 249 r = log_error_errno(errno, "LLMNR-IPv6(UDP): Failed to set IPV6_UNICAST_HOPS: %m");
7035cd9e
MP
250 goto fail;
251 }
252
253 /* RFC 4795, section 2.5 recommends setting the TTL of UDP packets to 255. */
254 r = setsockopt(m->llmnr_ipv6_udp_fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &ttl, sizeof(ttl));
255 if (r < 0) {
81c58355 256 r = log_error_errno(errno, "LLMNR-IPv6(UDP): Failed to set IPV6_MULTICAST_HOPS: %m");
7035cd9e
MP
257 goto fail;
258 }
259
260 r = setsockopt(m->llmnr_ipv6_udp_fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &one, sizeof(one));
261 if (r < 0) {
81c58355 262 r = log_error_errno(errno, "LLMNR-IPv6(UDP): Failed to set IPV6_MULTICAST_LOOP: %m");
7035cd9e
MP
263 goto fail;
264 }
265
266 r = setsockopt(m->llmnr_ipv6_udp_fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one));
267 if (r < 0) {
81c58355 268 r = log_error_errno(errno, "LLMNR-IPv6(UDP): Failed to set IPV6_V6ONLY: %m");
7035cd9e
MP
269 goto fail;
270 }
271
272 r = setsockopt(m->llmnr_ipv6_udp_fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &one, sizeof(one));
273 if (r < 0) {
81c58355 274 r = log_error_errno(errno, "LLMNR-IPv6(UDP): Failed to set IPV6_RECVPKTINFO: %m");
7035cd9e
MP
275 goto fail;
276 }
277
278 r = setsockopt(m->llmnr_ipv6_udp_fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &one, sizeof(one));
279 if (r < 0) {
81c58355 280 r = log_error_errno(errno, "LLMNR-IPv6(UDP): Failed to set IPV6_RECVHOPLIMIT: %m");
7035cd9e
MP
281 goto fail;
282 }
283
81c58355 284 /* first try to bind without SO_REUSEADDR to detect another LLMNR responder */
7035cd9e
MP
285 r = bind(m->llmnr_ipv6_udp_fd, &sa.sa, sizeof(sa.in6));
286 if (r < 0) {
81c58355
MB
287 if (errno != EADDRINUSE) {
288 r = log_error_errno(errno, "LLMNR-IPv6(UDP): Failed to bind socket: %m");
289 goto fail;
290 }
291
292 log_warning("LLMNR-IPv6(UDP): There appears to be another LLMNR responder running, or previously systemd-resolved crashed with some outstanding transfers.");
293
294 /* try again with SO_REUSEADDR */
295 r = setsockopt(m->llmnr_ipv6_udp_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
296 if (r < 0) {
297 r = log_error_errno(errno, "LLMNR-IPv6(UDP): Failed to set SO_REUSEADDR: %m");
298 goto fail;
299 }
300
301 r = bind(m->llmnr_ipv6_udp_fd, &sa.sa, sizeof(sa.in6));
302 if (r < 0) {
303 r = log_error_errno(errno, "LLMNR-IPv6(UDP): Failed to bind socket: %m");
304 goto fail;
305 }
306 } else {
307 /* enable SO_REUSEADDR for the case that the user really wants multiple LLMNR responders */
308 r = setsockopt(m->llmnr_ipv6_udp_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
309 if (r < 0) {
310 r = log_error_errno(errno, "LLMNR-IPv6(UDP): Failed to set SO_REUSEADDR: %m");
311 goto fail;
312 }
7035cd9e
MP
313 }
314
315 r = sd_event_add_io(m->event, &m->llmnr_ipv6_udp_event_source, m->llmnr_ipv6_udp_fd, EPOLLIN, on_llmnr_packet, m);
4c89c718 316 if (r < 0)
7035cd9e 317 goto fail;
4c89c718
MP
318
319 (void) sd_event_source_set_description(m->llmnr_ipv6_udp_event_source, "llmnr-ipv6-udp");
7035cd9e
MP
320
321 return m->llmnr_ipv6_udp_fd;
322
323fail:
324 m->llmnr_ipv6_udp_fd = safe_close(m->llmnr_ipv6_udp_fd);
325 return r;
326}
327
328static int on_llmnr_stream_packet(DnsStream *s) {
329 DnsScope *scope;
330
331 assert(s);
5a920b42 332 assert(s->read_packet);
7035cd9e
MP
333
334 scope = manager_find_scope(s->manager, s->read_packet);
5a920b42 335 if (!scope)
52ad194e 336 log_debug("Got LLMNR TCP packet on unknown scope. Ignoring.");
5a920b42
MP
337 else if (dns_packet_validate_query(s->read_packet) > 0) {
338 log_debug("Got LLMNR TCP query packet for id %u", DNS_PACKET_ID(s->read_packet));
7035cd9e
MP
339
340 dns_scope_process_query(scope, s, s->read_packet);
7035cd9e 341 } else
5a920b42 342 log_debug("Invalid LLMNR TCP packet, ignoring.");
7035cd9e 343
5a920b42 344 dns_stream_unref(s);
7035cd9e
MP
345 return 0;
346}
347
348static int on_llmnr_stream(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
349 DnsStream *stream;
350 Manager *m = userdata;
351 int cfd, r;
352
353 cfd = accept4(fd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC);
354 if (cfd < 0) {
f5e65279 355 if (IN_SET(errno, EAGAIN, EINTR))
7035cd9e
MP
356 return 0;
357
358 return -errno;
359 }
360
361 r = dns_stream_new(m, &stream, DNS_PROTOCOL_LLMNR, cfd);
362 if (r < 0) {
363 safe_close(cfd);
364 return r;
365 }
366
367 stream->on_packet = on_llmnr_stream_packet;
368 return 0;
369}
370
371int manager_llmnr_ipv4_tcp_fd(Manager *m) {
372 union sockaddr_union sa = {
373 .in.sin_family = AF_INET,
374 .in.sin_port = htobe16(LLMNR_PORT),
375 };
376 static const int one = 1, pmtu = IP_PMTUDISC_DONT;
377 int r;
378
379 assert(m);
380
381 if (m->llmnr_ipv4_tcp_fd >= 0)
382 return m->llmnr_ipv4_tcp_fd;
383
384 m->llmnr_ipv4_tcp_fd = socket(AF_INET, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
385 if (m->llmnr_ipv4_tcp_fd < 0)
81c58355 386 return log_error_errno(errno, "LLMNR-IPv4(TCP): Failed to create socket: %m");
7035cd9e
MP
387
388 /* RFC 4795, section 2.5. requires setting the TTL of TCP streams to 1 */
389 r = setsockopt(m->llmnr_ipv4_tcp_fd, IPPROTO_IP, IP_TTL, &one, sizeof(one));
390 if (r < 0) {
81c58355 391 r = log_error_errno(errno, "LLMNR-IPv4(TCP): Failed to set IP_TTL: %m");
7035cd9e
MP
392 goto fail;
393 }
394
395 r = setsockopt(m->llmnr_ipv4_tcp_fd, IPPROTO_IP, IP_PKTINFO, &one, sizeof(one));
396 if (r < 0) {
81c58355 397 r = log_error_errno(errno, "LLMNR-IPv4(TCP): Failed to set IP_PKTINFO: %m");
7035cd9e
MP
398 goto fail;
399 }
400
401 r = setsockopt(m->llmnr_ipv4_tcp_fd, IPPROTO_IP, IP_RECVTTL, &one, sizeof(one));
402 if (r < 0) {
81c58355 403 r = log_error_errno(errno, "LLMNR-IPv4(TCP): Failed to set IP_RECVTTL: %m");
7035cd9e
MP
404 goto fail;
405 }
406
407 /* Disable Don't-Fragment bit in the IP header */
408 r = setsockopt(m->llmnr_ipv4_tcp_fd, IPPROTO_IP, IP_MTU_DISCOVER, &pmtu, sizeof(pmtu));
409 if (r < 0) {
81c58355 410 r = log_error_errno(errno, "LLMNR-IPv4(TCP): Failed to set IP_MTU_DISCOVER: %m");
7035cd9e
MP
411 goto fail;
412 }
413
81c58355 414 /* first try to bind without SO_REUSEADDR to detect another LLMNR responder */
7035cd9e
MP
415 r = bind(m->llmnr_ipv4_tcp_fd, &sa.sa, sizeof(sa.in));
416 if (r < 0) {
81c58355
MB
417 if (errno != EADDRINUSE) {
418 r = log_error_errno(errno, "LLMNR-IPv4(TCP): Failed to bind socket: %m");
419 goto fail;
420 }
421
422 log_warning("LLMNR-IPv4(TCP): There appears to be another LLMNR responder running, or previously systemd-resolved crashed with some outstanding transfers.");
423
424 /* try again with SO_REUSEADDR */
425 r = setsockopt(m->llmnr_ipv4_tcp_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
426 if (r < 0) {
427 r = log_error_errno(errno, "LLMNR-IPv4(TCP): Failed to set SO_REUSEADDR: %m");
428 goto fail;
429 }
430
431 r = bind(m->llmnr_ipv4_tcp_fd, &sa.sa, sizeof(sa.in));
432 if (r < 0) {
433 r = log_error_errno(errno, "LLMNR-IPv4(TCP): Failed to bind socket: %m");
434 goto fail;
435 }
436 } else {
437 /* enable SO_REUSEADDR for the case that the user really wants multiple LLMNR responders */
438 r = setsockopt(m->llmnr_ipv4_tcp_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
439 if (r < 0) {
440 r = log_error_errno(errno, "LLMNR-IPv4(TCP): Failed to set SO_REUSEADDR: %m");
441 goto fail;
442 }
7035cd9e
MP
443 }
444
445 r = listen(m->llmnr_ipv4_tcp_fd, SOMAXCONN);
446 if (r < 0) {
81c58355 447 r = log_error_errno(errno, "LLMNR-IPv4(TCP): Failed to listen the stream: %m");
7035cd9e
MP
448 goto fail;
449 }
450
451 r = sd_event_add_io(m->event, &m->llmnr_ipv4_tcp_event_source, m->llmnr_ipv4_tcp_fd, EPOLLIN, on_llmnr_stream, m);
452 if (r < 0)
453 goto fail;
454
4c89c718
MP
455 (void) sd_event_source_set_description(m->llmnr_ipv4_tcp_event_source, "llmnr-ipv4-tcp");
456
7035cd9e
MP
457 return m->llmnr_ipv4_tcp_fd;
458
459fail:
460 m->llmnr_ipv4_tcp_fd = safe_close(m->llmnr_ipv4_tcp_fd);
461 return r;
462}
463
464int manager_llmnr_ipv6_tcp_fd(Manager *m) {
465 union sockaddr_union sa = {
466 .in6.sin6_family = AF_INET6,
467 .in6.sin6_port = htobe16(LLMNR_PORT),
468 };
469 static const int one = 1;
470 int r;
471
472 assert(m);
473
474 if (m->llmnr_ipv6_tcp_fd >= 0)
475 return m->llmnr_ipv6_tcp_fd;
476
477 m->llmnr_ipv6_tcp_fd = socket(AF_INET6, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
478 if (m->llmnr_ipv6_tcp_fd < 0)
81c58355 479 return log_error_errno(errno, "LLMNR-IPv6(TCP): Failed to create socket: %m");
7035cd9e
MP
480
481 /* RFC 4795, section 2.5. requires setting the TTL of TCP streams to 1 */
482 r = setsockopt(m->llmnr_ipv6_tcp_fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &one, sizeof(one));
483 if (r < 0) {
81c58355 484 r = log_error_errno(errno, "LLMNR-IPv6(TCP): Failed to set IPV6_UNICAST_HOPS: %m");
7035cd9e
MP
485 goto fail;
486 }
487
488 r = setsockopt(m->llmnr_ipv6_tcp_fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one));
489 if (r < 0) {
81c58355 490 r = log_error_errno(errno, "LLMNR-IPv6(TCP): Failed to set IPV6_V6ONLY: %m");
7035cd9e
MP
491 goto fail;
492 }
493
494 r = setsockopt(m->llmnr_ipv6_tcp_fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &one, sizeof(one));
495 if (r < 0) {
81c58355 496 r = log_error_errno(errno, "LLMNR-IPv6(TCP): Failed to set IPV6_RECVPKTINFO: %m");
7035cd9e
MP
497 goto fail;
498 }
499
500 r = setsockopt(m->llmnr_ipv6_tcp_fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &one, sizeof(one));
501 if (r < 0) {
81c58355 502 r = log_error_errno(errno, "LLMNR-IPv6(TCP): Failed to set IPV6_RECVHOPLIMIT: %m");
7035cd9e
MP
503 goto fail;
504 }
505
81c58355 506 /* first try to bind without SO_REUSEADDR to detect another LLMNR responder */
7035cd9e
MP
507 r = bind(m->llmnr_ipv6_tcp_fd, &sa.sa, sizeof(sa.in6));
508 if (r < 0) {
81c58355
MB
509 if (errno != EADDRINUSE) {
510 r = log_error_errno(errno, "LLMNR-IPv6(TCP): Failed to bind socket: %m");
511 goto fail;
512 }
513
514 log_warning("LLMNR-IPv6(TCP): There appears to be another LLMNR responder running, or previously systemd-resolved crashed with some outstanding transfers.");
515
516 /* try again with SO_REUSEADDR */
517 r = setsockopt(m->llmnr_ipv6_tcp_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
518 if (r < 0) {
519 r = log_error_errno(errno, "LLMNR-IPv6(TCP): Failed to set SO_REUSEADDR: %m");
520 goto fail;
521 }
522
523 r = bind(m->llmnr_ipv6_tcp_fd, &sa.sa, sizeof(sa.in6));
524 if (r < 0) {
525 r = log_error_errno(errno, "LLMNR-IPv6(TCP): Failed to bind socket: %m");
526 goto fail;
527 }
528 } else {
529 /* enable SO_REUSEADDR for the case that the user really wants multiple LLMNR responders */
530 r = setsockopt(m->llmnr_ipv6_tcp_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
531 if (r < 0) {
532 r = log_error_errno(errno, "LLMNR-IPv6(TCP): Failed to set SO_REUSEADDR: %m");
533 goto fail;
534 }
7035cd9e
MP
535 }
536
537 r = listen(m->llmnr_ipv6_tcp_fd, SOMAXCONN);
538 if (r < 0) {
81c58355 539 r = log_error_errno(errno, "LLMNR-IPv6(TCP): Failed to listen the stream: %m");
7035cd9e
MP
540 goto fail;
541 }
542
543 r = sd_event_add_io(m->event, &m->llmnr_ipv6_tcp_event_source, m->llmnr_ipv6_tcp_fd, EPOLLIN, on_llmnr_stream, m);
4c89c718 544 if (r < 0)
7035cd9e 545 goto fail;
4c89c718
MP
546
547 (void) sd_event_source_set_description(m->llmnr_ipv6_tcp_event_source, "llmnr-ipv6-tcp");
7035cd9e
MP
548
549 return m->llmnr_ipv6_tcp_fd;
550
551fail:
552 m->llmnr_ipv6_tcp_fd = safe_close(m->llmnr_ipv6_tcp_fd);
553 return r;
554}