]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/resolve/resolved-llmnr.c
59499c9c0b8d8f1063c5e788443ab6a092fa8a38
[thirdparty/systemd.git] / src / resolve / resolved-llmnr.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
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
21 #include <netinet/in.h>
22 #include <resolv.h>
23
24 #include "fd-util.h"
25 #include "resolved-llmnr.h"
26 #include "resolved-manager.h"
27
28 void 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
44 int manager_llmnr_start(Manager *m) {
45 int r;
46
47 assert(m);
48
49 if (m->llmnr_support == RESOLVE_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
80 eaddrinuse:
81 log_warning("Another LLMNR responder prohibits binding the socket to the same port. Turning off LLMNR support.");
82 m->llmnr_support = RESOLVE_SUPPORT_NO;
83 manager_llmnr_stop(m);
84
85 return 0;
86 }
87
88 static 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 assert(s);
96 assert(fd >= 0);
97 assert(m);
98
99 r = manager_recv(m, fd, DNS_PROTOCOL_LLMNR, &p);
100 if (r <= 0)
101 return r;
102
103 if (manager_our_packet(m, p))
104 return 0;
105
106 scope = manager_find_scope(m, p);
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) {
113 log_debug("Got LLMNR UDP reply packet for id %u", DNS_PACKET_ID(p));
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) {
122 log_debug("Got LLMNR UDP query packet for id %u", DNS_PACKET_ID(p));
123
124 dns_scope_process_query(scope, NULL, p);
125 } else
126 log_debug("Invalid LLMNR UDP packet, ignoring.");
127
128 return 0;
129 }
130
131 int 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)
146 return log_error_errno(errno, "LLMNR-IPv4(UDP): Failed to create socket: %m");
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) {
151 r = log_error_errno(errno, "LLMNR-IPv4(UDP): Failed to set IP_TTL: %m");
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) {
157 r = log_error_errno(errno, "LLMNR-IPv4(UDP): Failed to set IP_MULTICAST_TTL: %m");
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) {
163 r = log_error_errno(errno, "LLMNR-IPv4(UDP): Failed to set IP_MULTICAST_LOOP: %m");
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 = log_error_errno(errno, "LLMNR-IPv4(UDP): Failed to set IP_PKTINFO: %m");
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 = log_error_errno(errno, "LLMNR-IPv4(UDP): Failed to set IP_RECVTTL: %m");
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 = log_error_errno(errno, "LLMNR-IPv4(UDP): Failed to set IP_MTU_DISCOVER: %m");
183 goto fail;
184 }
185
186 /* first try to bind without SO_REUSEADDR to detect another LLMNR responder */
187 r = bind(m->llmnr_ipv4_udp_fd, &sa.sa, sizeof(sa.in));
188 if (r < 0) {
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 }
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
221 (void) sd_event_source_set_description(m->llmnr_ipv4_udp_event_source, "llmnr-ipv4-udp");
222
223 return m->llmnr_ipv4_udp_fd;
224
225 fail:
226 m->llmnr_ipv4_udp_fd = safe_close(m->llmnr_ipv4_udp_fd);
227 return r;
228 }
229
230 int 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)
245 return log_error_errno(errno, "LLMNR-IPv6(UDP): Failed to create socket: %m");
246
247 r = setsockopt(m->llmnr_ipv6_udp_fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl));
248 if (r < 0) {
249 r = log_error_errno(errno, "LLMNR-IPv6(UDP): Failed to set IPV6_UNICAST_HOPS: %m");
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) {
256 r = log_error_errno(errno, "LLMNR-IPv6(UDP): Failed to set IPV6_MULTICAST_HOPS: %m");
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) {
262 r = log_error_errno(errno, "LLMNR-IPv6(UDP): Failed to set IPV6_MULTICAST_LOOP: %m");
263 goto fail;
264 }
265
266 r = setsockopt(m->llmnr_ipv6_udp_fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one));
267 if (r < 0) {
268 r = log_error_errno(errno, "LLMNR-IPv6(UDP): Failed to set IPV6_V6ONLY: %m");
269 goto fail;
270 }
271
272 r = setsockopt(m->llmnr_ipv6_udp_fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &one, sizeof(one));
273 if (r < 0) {
274 r = log_error_errno(errno, "LLMNR-IPv6(UDP): Failed to set IPV6_RECVPKTINFO: %m");
275 goto fail;
276 }
277
278 r = setsockopt(m->llmnr_ipv6_udp_fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &one, sizeof(one));
279 if (r < 0) {
280 r = log_error_errno(errno, "LLMNR-IPv6(UDP): Failed to set IPV6_RECVHOPLIMIT: %m");
281 goto fail;
282 }
283
284 /* first try to bind without SO_REUSEADDR to detect another LLMNR responder */
285 r = bind(m->llmnr_ipv6_udp_fd, &sa.sa, sizeof(sa.in6));
286 if (r < 0) {
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 }
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);
316 if (r < 0)
317 goto fail;
318
319 (void) sd_event_source_set_description(m->llmnr_ipv6_udp_event_source, "llmnr-ipv6-udp");
320
321 return m->llmnr_ipv6_udp_fd;
322
323 fail:
324 m->llmnr_ipv6_udp_fd = safe_close(m->llmnr_ipv6_udp_fd);
325 return r;
326 }
327
328 static int on_llmnr_stream_packet(DnsStream *s) {
329 DnsScope *scope;
330
331 assert(s);
332 assert(s->read_packet);
333
334 scope = manager_find_scope(s->manager, s->read_packet);
335 if (!scope)
336 log_debug("Got LLMNR TCP packet on unknown scope. Ignoring.");
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));
339
340 dns_scope_process_query(scope, s, s->read_packet);
341 } else
342 log_debug("Invalid LLMNR TCP packet, ignoring.");
343
344 dns_stream_unref(s);
345 return 0;
346 }
347
348 static 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) {
355 if (IN_SET(errno, EAGAIN, EINTR))
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
371 int 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)
386 return log_error_errno(errno, "LLMNR-IPv4(TCP): Failed to create socket: %m");
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) {
391 r = log_error_errno(errno, "LLMNR-IPv4(TCP): Failed to set IP_TTL: %m");
392 goto fail;
393 }
394
395 r = setsockopt(m->llmnr_ipv4_tcp_fd, IPPROTO_IP, IP_PKTINFO, &one, sizeof(one));
396 if (r < 0) {
397 r = log_error_errno(errno, "LLMNR-IPv4(TCP): Failed to set IP_PKTINFO: %m");
398 goto fail;
399 }
400
401 r = setsockopt(m->llmnr_ipv4_tcp_fd, IPPROTO_IP, IP_RECVTTL, &one, sizeof(one));
402 if (r < 0) {
403 r = log_error_errno(errno, "LLMNR-IPv4(TCP): Failed to set IP_RECVTTL: %m");
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) {
410 r = log_error_errno(errno, "LLMNR-IPv4(TCP): Failed to set IP_MTU_DISCOVER: %m");
411 goto fail;
412 }
413
414 /* first try to bind without SO_REUSEADDR to detect another LLMNR responder */
415 r = bind(m->llmnr_ipv4_tcp_fd, &sa.sa, sizeof(sa.in));
416 if (r < 0) {
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 }
443 }
444
445 r = listen(m->llmnr_ipv4_tcp_fd, SOMAXCONN);
446 if (r < 0) {
447 r = log_error_errno(errno, "LLMNR-IPv4(TCP): Failed to listen the stream: %m");
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
455 (void) sd_event_source_set_description(m->llmnr_ipv4_tcp_event_source, "llmnr-ipv4-tcp");
456
457 return m->llmnr_ipv4_tcp_fd;
458
459 fail:
460 m->llmnr_ipv4_tcp_fd = safe_close(m->llmnr_ipv4_tcp_fd);
461 return r;
462 }
463
464 int 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)
479 return log_error_errno(errno, "LLMNR-IPv6(TCP): Failed to create socket: %m");
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) {
484 r = log_error_errno(errno, "LLMNR-IPv6(TCP): Failed to set IPV6_UNICAST_HOPS: %m");
485 goto fail;
486 }
487
488 r = setsockopt(m->llmnr_ipv6_tcp_fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one));
489 if (r < 0) {
490 r = log_error_errno(errno, "LLMNR-IPv6(TCP): Failed to set IPV6_V6ONLY: %m");
491 goto fail;
492 }
493
494 r = setsockopt(m->llmnr_ipv6_tcp_fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &one, sizeof(one));
495 if (r < 0) {
496 r = log_error_errno(errno, "LLMNR-IPv6(TCP): Failed to set IPV6_RECVPKTINFO: %m");
497 goto fail;
498 }
499
500 r = setsockopt(m->llmnr_ipv6_tcp_fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &one, sizeof(one));
501 if (r < 0) {
502 r = log_error_errno(errno, "LLMNR-IPv6(TCP): Failed to set IPV6_RECVHOPLIMIT: %m");
503 goto fail;
504 }
505
506 /* first try to bind without SO_REUSEADDR to detect another LLMNR responder */
507 r = bind(m->llmnr_ipv6_tcp_fd, &sa.sa, sizeof(sa.in6));
508 if (r < 0) {
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 }
535 }
536
537 r = listen(m->llmnr_ipv6_tcp_fd, SOMAXCONN);
538 if (r < 0) {
539 r = log_error_errno(errno, "LLMNR-IPv6(TCP): Failed to listen the stream: %m");
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);
544 if (r < 0)
545 goto fail;
546
547 (void) sd_event_source_set_description(m->llmnr_ipv6_tcp_event_source, "llmnr-ipv6-tcp");
548
549 return m->llmnr_ipv6_tcp_fd;
550
551 fail:
552 m->llmnr_ipv6_tcp_fd = safe_close(m->llmnr_ipv6_tcp_fd);
553 return r;
554 }