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