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