]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/resolve/resolved-llmnr.c
Add SPDX license identifiers to source files under the LGPL
[thirdparty/systemd.git] / src / resolve / resolved-llmnr.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
5f402ae8
DM
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
5f402ae8 21#include <netinet/in.h>
cf0fbc49 22#include <resolv.h>
5f402ae8 23
3ffd4af2 24#include "fd-util.h"
5f402ae8 25#include "resolved-llmnr.h"
3ffd4af2 26#include "resolved-manager.h"
5f402ae8
DM
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
af49ca27 49 if (m->llmnr_support == RESOLVE_SUPPORT_NO)
5f402ae8
DM
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:
007ef0a2 81 log_warning("Another LLMNR responder prohibits binding the socket to the same port. Turning off LLMNR support.");
af49ca27 82 m->llmnr_support = RESOLVE_SUPPORT_NO;
5f402ae8
DM
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
b30bf55d
LP
95 assert(s);
96 assert(fd >= 0);
97 assert(m);
98
5f402ae8
DM
99 r = manager_recv(m, fd, DNS_PROTOCOL_LLMNR, &p);
100 if (r <= 0)
101 return r;
102
103 scope = manager_find_scope(m, p);
b30bf55d 104 if (!scope)
5f402ae8 105 log_warning("Got LLMNR UDP packet on unknown scope. Ignoring.");
b30bf55d
LP
106 else if (dns_packet_validate_reply(p) > 0) {
107 log_debug("Got LLMNR UDP reply packet for id %u", DNS_PACKET_ID(p));
5f402ae8
DM
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) {
b30bf55d 116 log_debug("Got LLMNR UDP query packet for id %u", DNS_PACKET_ID(p));
5f402ae8
DM
117
118 dns_scope_process_query(scope, NULL, p);
119 } else
2c6bf498 120 log_debug("Invalid LLMNR UDP packet, ignoring.");
5f402ae8
DM
121
122 return 0;
123}
124
125int manager_llmnr_ipv4_udp_fd(Manager *m) {
126 union sockaddr_union sa = {
127 .in.sin_family = AF_INET,
22a37591 128 .in.sin_port = htobe16(LLMNR_PORT),
5f402ae8
DM
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)
007ef0a2 140 return log_error_errno(errno, "LLMNR-IPv4(UDP): Failed to create socket: %m");
5f402ae8
DM
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) {
007ef0a2 145 r = log_error_errno(errno, "LLMNR-IPv4(UDP): Failed to set IP_TTL: %m");
5f402ae8
DM
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) {
007ef0a2 151 r = log_error_errno(errno, "LLMNR-IPv4(UDP): Failed to set IP_MULTICAST_TTL: %m");
5f402ae8
DM
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) {
007ef0a2 157 r = log_error_errno(errno, "LLMNR-IPv4(UDP): Failed to set IP_MULTICAST_LOOP: %m");
5f402ae8
DM
158 goto fail;
159 }
160
161 r = setsockopt(m->llmnr_ipv4_udp_fd, IPPROTO_IP, IP_PKTINFO, &one, sizeof(one));
162 if (r < 0) {
007ef0a2 163 r = log_error_errno(errno, "LLMNR-IPv4(UDP): Failed to set IP_PKTINFO: %m");
5f402ae8
DM
164 goto fail;
165 }
166
167 r = setsockopt(m->llmnr_ipv4_udp_fd, IPPROTO_IP, IP_RECVTTL, &one, sizeof(one));
168 if (r < 0) {
007ef0a2 169 r = log_error_errno(errno, "LLMNR-IPv4(UDP): Failed to set IP_RECVTTL: %m");
5f402ae8
DM
170 goto fail;
171 }
172
173 /* Disable Don't-Fragment bit in the IP header */
174 r = setsockopt(m->llmnr_ipv4_udp_fd, IPPROTO_IP, IP_MTU_DISCOVER, &pmtu, sizeof(pmtu));
175 if (r < 0) {
007ef0a2 176 r = log_error_errno(errno, "LLMNR-IPv4(UDP): Failed to set IP_MTU_DISCOVER: %m");
5f402ae8
DM
177 goto fail;
178 }
179
007ef0a2 180 /* first try to bind without SO_REUSEADDR to detect another LLMNR responder */
5f402ae8
DM
181 r = bind(m->llmnr_ipv4_udp_fd, &sa.sa, sizeof(sa.in));
182 if (r < 0) {
007ef0a2
YW
183 if (errno != EADDRINUSE) {
184 r = log_error_errno(errno, "LLMNR-IPv4(UDP): Failed to bind socket: %m");
185 goto fail;
186 }
187
188 log_warning("LLMNR-IPv4(UDP): There appears to be another LLMNR responder running, or previously systemd-resolved crashed with some outstanding transfers.");
189
190 /* try again with SO_REUSEADDR */
191 r = setsockopt(m->llmnr_ipv4_udp_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
192 if (r < 0) {
193 r = log_error_errno(errno, "LLMNR-IPv4(UDP): Failed to set SO_REUSEADDR: %m");
194 goto fail;
195 }
196
197 r = bind(m->llmnr_ipv4_udp_fd, &sa.sa, sizeof(sa.in));
198 if (r < 0) {
199 r = log_error_errno(errno, "LLMNR-IPv4(UDP): Failed to bind socket: %m");
200 goto fail;
201 }
202 } else {
203 /* enable SO_REUSEADDR for the case that the user really wants multiple LLMNR responders */
204 r = setsockopt(m->llmnr_ipv4_udp_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
205 if (r < 0) {
206 r = log_error_errno(errno, "LLMNR-IPv4(UDP): Failed to set SO_REUSEADDR: %m");
207 goto fail;
208 }
5f402ae8
DM
209 }
210
211 r = sd_event_add_io(m->event, &m->llmnr_ipv4_udp_event_source, m->llmnr_ipv4_udp_fd, EPOLLIN, on_llmnr_packet, m);
212 if (r < 0)
213 goto fail;
214
aa4a9deb
LP
215 (void) sd_event_source_set_description(m->llmnr_ipv4_udp_event_source, "llmnr-ipv4-udp");
216
5f402ae8
DM
217 return m->llmnr_ipv4_udp_fd;
218
219fail:
220 m->llmnr_ipv4_udp_fd = safe_close(m->llmnr_ipv4_udp_fd);
221 return r;
222}
223
224int manager_llmnr_ipv6_udp_fd(Manager *m) {
225 union sockaddr_union sa = {
226 .in6.sin6_family = AF_INET6,
22a37591 227 .in6.sin6_port = htobe16(LLMNR_PORT),
5f402ae8
DM
228 };
229 static const int one = 1, ttl = 255;
230 int r;
231
232 assert(m);
233
234 if (m->llmnr_ipv6_udp_fd >= 0)
235 return m->llmnr_ipv6_udp_fd;
236
237 m->llmnr_ipv6_udp_fd = socket(AF_INET6, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
238 if (m->llmnr_ipv6_udp_fd < 0)
007ef0a2 239 return log_error_errno(errno, "LLMNR-IPv6(UDP): Failed to create socket: %m");
5f402ae8
DM
240
241 r = setsockopt(m->llmnr_ipv6_udp_fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl));
242 if (r < 0) {
007ef0a2 243 r = log_error_errno(errno, "LLMNR-IPv6(UDP): Failed to set IPV6_UNICAST_HOPS: %m");
5f402ae8
DM
244 goto fail;
245 }
246
247 /* RFC 4795, section 2.5 recommends setting the TTL of UDP packets to 255. */
248 r = setsockopt(m->llmnr_ipv6_udp_fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &ttl, sizeof(ttl));
249 if (r < 0) {
007ef0a2 250 r = log_error_errno(errno, "LLMNR-IPv6(UDP): Failed to set IPV6_MULTICAST_HOPS: %m");
5f402ae8
DM
251 goto fail;
252 }
253
254 r = setsockopt(m->llmnr_ipv6_udp_fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &one, sizeof(one));
255 if (r < 0) {
007ef0a2 256 r = log_error_errno(errno, "LLMNR-IPv6(UDP): Failed to set IPV6_MULTICAST_LOOP: %m");
5f402ae8
DM
257 goto fail;
258 }
259
260 r = setsockopt(m->llmnr_ipv6_udp_fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one));
261 if (r < 0) {
007ef0a2 262 r = log_error_errno(errno, "LLMNR-IPv6(UDP): Failed to set IPV6_V6ONLY: %m");
5f402ae8
DM
263 goto fail;
264 }
265
266 r = setsockopt(m->llmnr_ipv6_udp_fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &one, sizeof(one));
267 if (r < 0) {
007ef0a2 268 r = log_error_errno(errno, "LLMNR-IPv6(UDP): Failed to set IPV6_RECVPKTINFO: %m");
5f402ae8
DM
269 goto fail;
270 }
271
272 r = setsockopt(m->llmnr_ipv6_udp_fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &one, sizeof(one));
273 if (r < 0) {
007ef0a2 274 r = log_error_errno(errno, "LLMNR-IPv6(UDP): Failed to set IPV6_RECVHOPLIMIT: %m");
5f402ae8
DM
275 goto fail;
276 }
277
007ef0a2 278 /* first try to bind without SO_REUSEADDR to detect another LLMNR responder */
5f402ae8
DM
279 r = bind(m->llmnr_ipv6_udp_fd, &sa.sa, sizeof(sa.in6));
280 if (r < 0) {
007ef0a2
YW
281 if (errno != EADDRINUSE) {
282 r = log_error_errno(errno, "LLMNR-IPv6(UDP): Failed to bind socket: %m");
283 goto fail;
284 }
285
286 log_warning("LLMNR-IPv6(UDP): There appears to be another LLMNR responder running, or previously systemd-resolved crashed with some outstanding transfers.");
287
288 /* try again with SO_REUSEADDR */
289 r = setsockopt(m->llmnr_ipv6_udp_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
290 if (r < 0) {
291 r = log_error_errno(errno, "LLMNR-IPv6(UDP): Failed to set SO_REUSEADDR: %m");
292 goto fail;
293 }
294
295 r = bind(m->llmnr_ipv6_udp_fd, &sa.sa, sizeof(sa.in6));
296 if (r < 0) {
297 r = log_error_errno(errno, "LLMNR-IPv6(UDP): Failed to bind socket: %m");
298 goto fail;
299 }
300 } else {
301 /* enable SO_REUSEADDR for the case that the user really wants multiple LLMNR responders */
302 r = setsockopt(m->llmnr_ipv6_udp_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
303 if (r < 0) {
304 r = log_error_errno(errno, "LLMNR-IPv6(UDP): Failed to set SO_REUSEADDR: %m");
305 goto fail;
306 }
5f402ae8
DM
307 }
308
309 r = sd_event_add_io(m->event, &m->llmnr_ipv6_udp_event_source, m->llmnr_ipv6_udp_fd, EPOLLIN, on_llmnr_packet, m);
35908b98 310 if (r < 0)
5f402ae8 311 goto fail;
5f402ae8 312
aa4a9deb
LP
313 (void) sd_event_source_set_description(m->llmnr_ipv6_udp_event_source, "llmnr-ipv6-udp");
314
5f402ae8
DM
315 return m->llmnr_ipv6_udp_fd;
316
317fail:
318 m->llmnr_ipv6_udp_fd = safe_close(m->llmnr_ipv6_udp_fd);
319 return r;
320}
321
322static int on_llmnr_stream_packet(DnsStream *s) {
323 DnsScope *scope;
324
325 assert(s);
b30bf55d 326 assert(s->read_packet);
5f402ae8
DM
327
328 scope = manager_find_scope(s->manager, s->read_packet);
b30bf55d 329 if (!scope)
0ea929d5 330 log_warning("Got LLMNR TCP packet on unknown scope. Ignoring.");
b30bf55d
LP
331 else if (dns_packet_validate_query(s->read_packet) > 0) {
332 log_debug("Got LLMNR TCP query packet for id %u", DNS_PACKET_ID(s->read_packet));
5f402ae8
DM
333
334 dns_scope_process_query(scope, s, s->read_packet);
5f402ae8 335 } else
b30bf55d 336 log_debug("Invalid LLMNR TCP packet, ignoring.");
5f402ae8 337
b30bf55d 338 dns_stream_unref(s);
5f402ae8
DM
339 return 0;
340}
341
342static int on_llmnr_stream(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
343 DnsStream *stream;
344 Manager *m = userdata;
345 int cfd, r;
346
347 cfd = accept4(fd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC);
348 if (cfd < 0) {
3742095b 349 if (IN_SET(errno, EAGAIN, EINTR))
5f402ae8
DM
350 return 0;
351
352 return -errno;
353 }
354
355 r = dns_stream_new(m, &stream, DNS_PROTOCOL_LLMNR, cfd);
356 if (r < 0) {
357 safe_close(cfd);
358 return r;
359 }
360
361 stream->on_packet = on_llmnr_stream_packet;
362 return 0;
363}
364
365int manager_llmnr_ipv4_tcp_fd(Manager *m) {
366 union sockaddr_union sa = {
367 .in.sin_family = AF_INET,
22a37591 368 .in.sin_port = htobe16(LLMNR_PORT),
5f402ae8
DM
369 };
370 static const int one = 1, pmtu = IP_PMTUDISC_DONT;
371 int r;
372
373 assert(m);
374
375 if (m->llmnr_ipv4_tcp_fd >= 0)
376 return m->llmnr_ipv4_tcp_fd;
377
378 m->llmnr_ipv4_tcp_fd = socket(AF_INET, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
379 if (m->llmnr_ipv4_tcp_fd < 0)
007ef0a2 380 return log_error_errno(errno, "LLMNR-IPv4(TCP): Failed to create socket: %m");
5f402ae8
DM
381
382 /* RFC 4795, section 2.5. requires setting the TTL of TCP streams to 1 */
383 r = setsockopt(m->llmnr_ipv4_tcp_fd, IPPROTO_IP, IP_TTL, &one, sizeof(one));
384 if (r < 0) {
007ef0a2 385 r = log_error_errno(errno, "LLMNR-IPv4(TCP): Failed to set IP_TTL: %m");
5f402ae8
DM
386 goto fail;
387 }
388
389 r = setsockopt(m->llmnr_ipv4_tcp_fd, IPPROTO_IP, IP_PKTINFO, &one, sizeof(one));
390 if (r < 0) {
007ef0a2 391 r = log_error_errno(errno, "LLMNR-IPv4(TCP): Failed to set IP_PKTINFO: %m");
5f402ae8
DM
392 goto fail;
393 }
394
395 r = setsockopt(m->llmnr_ipv4_tcp_fd, IPPROTO_IP, IP_RECVTTL, &one, sizeof(one));
396 if (r < 0) {
007ef0a2 397 r = log_error_errno(errno, "LLMNR-IPv4(TCP): Failed to set IP_RECVTTL: %m");
5f402ae8
DM
398 goto fail;
399 }
400
401 /* Disable Don't-Fragment bit in the IP header */
402 r = setsockopt(m->llmnr_ipv4_tcp_fd, IPPROTO_IP, IP_MTU_DISCOVER, &pmtu, sizeof(pmtu));
403 if (r < 0) {
007ef0a2 404 r = log_error_errno(errno, "LLMNR-IPv4(TCP): Failed to set IP_MTU_DISCOVER: %m");
5f402ae8
DM
405 goto fail;
406 }
407
007ef0a2 408 /* first try to bind without SO_REUSEADDR to detect another LLMNR responder */
5f402ae8
DM
409 r = bind(m->llmnr_ipv4_tcp_fd, &sa.sa, sizeof(sa.in));
410 if (r < 0) {
007ef0a2
YW
411 if (errno != EADDRINUSE) {
412 r = log_error_errno(errno, "LLMNR-IPv4(TCP): Failed to bind socket: %m");
413 goto fail;
414 }
415
416 log_warning("LLMNR-IPv4(TCP): There appears to be another LLMNR responder running, or previously systemd-resolved crashed with some outstanding transfers.");
417
418 /* try again with SO_REUSEADDR */
419 r = setsockopt(m->llmnr_ipv4_tcp_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
420 if (r < 0) {
421 r = log_error_errno(errno, "LLMNR-IPv4(TCP): Failed to set SO_REUSEADDR: %m");
422 goto fail;
423 }
424
425 r = bind(m->llmnr_ipv4_tcp_fd, &sa.sa, sizeof(sa.in));
426 if (r < 0) {
427 r = log_error_errno(errno, "LLMNR-IPv4(TCP): Failed to bind socket: %m");
428 goto fail;
429 }
430 } else {
431 /* enable SO_REUSEADDR for the case that the user really wants multiple LLMNR responders */
432 r = setsockopt(m->llmnr_ipv4_tcp_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
433 if (r < 0) {
434 r = log_error_errno(errno, "LLMNR-IPv4(TCP): Failed to set SO_REUSEADDR: %m");
435 goto fail;
436 }
5f402ae8
DM
437 }
438
439 r = listen(m->llmnr_ipv4_tcp_fd, SOMAXCONN);
440 if (r < 0) {
007ef0a2 441 r = log_error_errno(errno, "LLMNR-IPv4(TCP): Failed to listen the stream: %m");
5f402ae8
DM
442 goto fail;
443 }
444
445 r = sd_event_add_io(m->event, &m->llmnr_ipv4_tcp_event_source, m->llmnr_ipv4_tcp_fd, EPOLLIN, on_llmnr_stream, m);
446 if (r < 0)
447 goto fail;
448
aa4a9deb
LP
449 (void) sd_event_source_set_description(m->llmnr_ipv4_tcp_event_source, "llmnr-ipv4-tcp");
450
5f402ae8
DM
451 return m->llmnr_ipv4_tcp_fd;
452
453fail:
454 m->llmnr_ipv4_tcp_fd = safe_close(m->llmnr_ipv4_tcp_fd);
455 return r;
456}
457
458int manager_llmnr_ipv6_tcp_fd(Manager *m) {
459 union sockaddr_union sa = {
460 .in6.sin6_family = AF_INET6,
22a37591 461 .in6.sin6_port = htobe16(LLMNR_PORT),
5f402ae8
DM
462 };
463 static const int one = 1;
464 int r;
465
466 assert(m);
467
468 if (m->llmnr_ipv6_tcp_fd >= 0)
469 return m->llmnr_ipv6_tcp_fd;
470
471 m->llmnr_ipv6_tcp_fd = socket(AF_INET6, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
472 if (m->llmnr_ipv6_tcp_fd < 0)
007ef0a2 473 return log_error_errno(errno, "LLMNR-IPv6(TCP): Failed to create socket: %m");
5f402ae8
DM
474
475 /* RFC 4795, section 2.5. requires setting the TTL of TCP streams to 1 */
476 r = setsockopt(m->llmnr_ipv6_tcp_fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &one, sizeof(one));
477 if (r < 0) {
007ef0a2 478 r = log_error_errno(errno, "LLMNR-IPv6(TCP): Failed to set IPV6_UNICAST_HOPS: %m");
5f402ae8
DM
479 goto fail;
480 }
481
482 r = setsockopt(m->llmnr_ipv6_tcp_fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one));
483 if (r < 0) {
007ef0a2 484 r = log_error_errno(errno, "LLMNR-IPv6(TCP): Failed to set IPV6_V6ONLY: %m");
5f402ae8
DM
485 goto fail;
486 }
487
488 r = setsockopt(m->llmnr_ipv6_tcp_fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &one, sizeof(one));
489 if (r < 0) {
007ef0a2 490 r = log_error_errno(errno, "LLMNR-IPv6(TCP): Failed to set IPV6_RECVPKTINFO: %m");
5f402ae8
DM
491 goto fail;
492 }
493
494 r = setsockopt(m->llmnr_ipv6_tcp_fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &one, sizeof(one));
495 if (r < 0) {
007ef0a2 496 r = log_error_errno(errno, "LLMNR-IPv6(TCP): Failed to set IPV6_RECVHOPLIMIT: %m");
5f402ae8
DM
497 goto fail;
498 }
499
007ef0a2 500 /* first try to bind without SO_REUSEADDR to detect another LLMNR responder */
5f402ae8
DM
501 r = bind(m->llmnr_ipv6_tcp_fd, &sa.sa, sizeof(sa.in6));
502 if (r < 0) {
007ef0a2
YW
503 if (errno != EADDRINUSE) {
504 r = log_error_errno(errno, "LLMNR-IPv6(TCP): Failed to bind socket: %m");
505 goto fail;
506 }
507
508 log_warning("LLMNR-IPv6(TCP): There appears to be another LLMNR responder running, or previously systemd-resolved crashed with some outstanding transfers.");
509
510 /* try again with SO_REUSEADDR */
511 r = setsockopt(m->llmnr_ipv6_tcp_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
512 if (r < 0) {
513 r = log_error_errno(errno, "LLMNR-IPv6(TCP): Failed to set SO_REUSEADDR: %m");
514 goto fail;
515 }
516
517 r = bind(m->llmnr_ipv6_tcp_fd, &sa.sa, sizeof(sa.in6));
518 if (r < 0) {
519 r = log_error_errno(errno, "LLMNR-IPv6(TCP): Failed to bind socket: %m");
520 goto fail;
521 }
522 } else {
523 /* enable SO_REUSEADDR for the case that the user really wants multiple LLMNR responders */
524 r = setsockopt(m->llmnr_ipv6_tcp_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
525 if (r < 0) {
526 r = log_error_errno(errno, "LLMNR-IPv6(TCP): Failed to set SO_REUSEADDR: %m");
527 goto fail;
528 }
5f402ae8
DM
529 }
530
531 r = listen(m->llmnr_ipv6_tcp_fd, SOMAXCONN);
532 if (r < 0) {
007ef0a2 533 r = log_error_errno(errno, "LLMNR-IPv6(TCP): Failed to listen the stream: %m");
5f402ae8
DM
534 goto fail;
535 }
536
537 r = sd_event_add_io(m->event, &m->llmnr_ipv6_tcp_event_source, m->llmnr_ipv6_tcp_fd, EPOLLIN, on_llmnr_stream, m);
ee8d9305 538 if (r < 0)
5f402ae8 539 goto fail;
5f402ae8 540
aa4a9deb
LP
541 (void) sd_event_source_set_description(m->llmnr_ipv6_tcp_event_source, "llmnr-ipv6-tcp");
542
5f402ae8
DM
543 return m->llmnr_ipv6_tcp_fd;
544
545fail:
546 m->llmnr_ipv6_tcp_fd = safe_close(m->llmnr_ipv6_tcp_fd);
547 return r;
548}