1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2014 Tom Gundersen <teg@jklm.no>
8 #include <netinet/in.h>
12 #include "resolved-llmnr.h"
13 #include "resolved-manager.h"
15 void manager_llmnr_stop(Manager
*m
) {
18 m
->llmnr_ipv4_udp_event_source
= sd_event_source_unref(m
->llmnr_ipv4_udp_event_source
);
19 m
->llmnr_ipv4_udp_fd
= safe_close(m
->llmnr_ipv4_udp_fd
);
21 m
->llmnr_ipv6_udp_event_source
= sd_event_source_unref(m
->llmnr_ipv6_udp_event_source
);
22 m
->llmnr_ipv6_udp_fd
= safe_close(m
->llmnr_ipv6_udp_fd
);
24 m
->llmnr_ipv4_tcp_event_source
= sd_event_source_unref(m
->llmnr_ipv4_tcp_event_source
);
25 m
->llmnr_ipv4_tcp_fd
= safe_close(m
->llmnr_ipv4_tcp_fd
);
27 m
->llmnr_ipv6_tcp_event_source
= sd_event_source_unref(m
->llmnr_ipv6_tcp_event_source
);
28 m
->llmnr_ipv6_tcp_fd
= safe_close(m
->llmnr_ipv6_tcp_fd
);
31 int manager_llmnr_start(Manager
*m
) {
36 if (m
->llmnr_support
== RESOLVE_SUPPORT_NO
)
39 r
= manager_llmnr_ipv4_udp_fd(m
);
45 r
= manager_llmnr_ipv4_tcp_fd(m
);
51 if (socket_ipv6_is_supported()) {
52 r
= manager_llmnr_ipv6_udp_fd(m
);
58 r
= manager_llmnr_ipv6_tcp_fd(m
);
68 log_warning("Another LLMNR responder prohibits binding the socket to the same port. Turning off LLMNR support.");
69 m
->llmnr_support
= RESOLVE_SUPPORT_NO
;
70 manager_llmnr_stop(m
);
75 static int on_llmnr_packet(sd_event_source
*s
, int fd
, uint32_t revents
, void *userdata
) {
76 _cleanup_(dns_packet_unrefp
) DnsPacket
*p
= NULL
;
77 DnsTransaction
*t
= NULL
;
78 Manager
*m
= userdata
;
86 r
= manager_recv(m
, fd
, DNS_PROTOCOL_LLMNR
, &p
);
90 if (manager_our_packet(m
, p
))
93 scope
= manager_find_scope(m
, p
);
95 log_debug("Got LLMNR UDP packet on unknown scope. Ignoring.");
99 if (dns_packet_validate_reply(p
) > 0) {
100 log_debug("Got LLMNR UDP reply packet for id %u", DNS_PACKET_ID(p
));
102 dns_scope_check_conflicts(scope
, p
);
104 t
= hashmap_get(m
->dns_transactions
, UINT_TO_PTR(DNS_PACKET_ID(p
)));
106 dns_transaction_process_reply(t
, p
);
108 } else if (dns_packet_validate_query(p
) > 0) {
109 log_debug("Got LLMNR UDP query packet for id %u", DNS_PACKET_ID(p
));
111 dns_scope_process_query(scope
, NULL
, p
);
113 log_debug("Invalid LLMNR UDP packet, ignoring.");
118 int manager_llmnr_ipv4_udp_fd(Manager
*m
) {
119 union sockaddr_union sa
= {
120 .in
.sin_family
= AF_INET
,
121 .in
.sin_port
= htobe16(LLMNR_PORT
),
123 static const int one
= 1, pmtu
= IP_PMTUDISC_DONT
, ttl
= 255;
128 if (m
->llmnr_ipv4_udp_fd
>= 0)
129 return m
->llmnr_ipv4_udp_fd
;
131 m
->llmnr_ipv4_udp_fd
= socket(AF_INET
, SOCK_DGRAM
|SOCK_CLOEXEC
|SOCK_NONBLOCK
, 0);
132 if (m
->llmnr_ipv4_udp_fd
< 0)
133 return log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to create socket: %m");
135 /* RFC 4795, section 2.5 recommends setting the TTL of UDP packets to 255. */
136 r
= setsockopt(m
->llmnr_ipv4_udp_fd
, IPPROTO_IP
, IP_TTL
, &ttl
, sizeof(ttl
));
138 r
= log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to set IP_TTL: %m");
142 r
= setsockopt(m
->llmnr_ipv4_udp_fd
, IPPROTO_IP
, IP_MULTICAST_TTL
, &ttl
, sizeof(ttl
));
144 r
= log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to set IP_MULTICAST_TTL: %m");
148 r
= setsockopt(m
->llmnr_ipv4_udp_fd
, IPPROTO_IP
, IP_MULTICAST_LOOP
, &one
, sizeof(one
));
150 r
= log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to set IP_MULTICAST_LOOP: %m");
154 r
= setsockopt(m
->llmnr_ipv4_udp_fd
, IPPROTO_IP
, IP_PKTINFO
, &one
, sizeof(one
));
156 r
= log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to set IP_PKTINFO: %m");
160 r
= setsockopt(m
->llmnr_ipv4_udp_fd
, IPPROTO_IP
, IP_RECVTTL
, &one
, sizeof(one
));
162 r
= log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to set IP_RECVTTL: %m");
166 /* Disable Don't-Fragment bit in the IP header */
167 r
= setsockopt(m
->llmnr_ipv4_udp_fd
, IPPROTO_IP
, IP_MTU_DISCOVER
, &pmtu
, sizeof(pmtu
));
169 r
= log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to set IP_MTU_DISCOVER: %m");
173 /* first try to bind without SO_REUSEADDR to detect another LLMNR responder */
174 r
= bind(m
->llmnr_ipv4_udp_fd
, &sa
.sa
, sizeof(sa
.in
));
176 if (errno
!= EADDRINUSE
) {
177 r
= log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to bind socket: %m");
181 log_warning("LLMNR-IPv4(UDP): There appears to be another LLMNR responder running, or previously systemd-resolved crashed with some outstanding transfers.");
183 /* try again with SO_REUSEADDR */
184 r
= setsockopt(m
->llmnr_ipv4_udp_fd
, SOL_SOCKET
, SO_REUSEADDR
, &one
, sizeof(one
));
186 r
= log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to set SO_REUSEADDR: %m");
190 r
= bind(m
->llmnr_ipv4_udp_fd
, &sa
.sa
, sizeof(sa
.in
));
192 r
= log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to bind socket: %m");
196 /* enable SO_REUSEADDR for the case that the user really wants multiple LLMNR responders */
197 r
= setsockopt(m
->llmnr_ipv4_udp_fd
, SOL_SOCKET
, SO_REUSEADDR
, &one
, sizeof(one
));
199 r
= log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to set SO_REUSEADDR: %m");
204 r
= sd_event_add_io(m
->event
, &m
->llmnr_ipv4_udp_event_source
, m
->llmnr_ipv4_udp_fd
, EPOLLIN
, on_llmnr_packet
, m
);
208 (void) sd_event_source_set_description(m
->llmnr_ipv4_udp_event_source
, "llmnr-ipv4-udp");
210 return m
->llmnr_ipv4_udp_fd
;
213 m
->llmnr_ipv4_udp_fd
= safe_close(m
->llmnr_ipv4_udp_fd
);
217 int manager_llmnr_ipv6_udp_fd(Manager
*m
) {
218 union sockaddr_union sa
= {
219 .in6
.sin6_family
= AF_INET6
,
220 .in6
.sin6_port
= htobe16(LLMNR_PORT
),
222 static const int one
= 1, ttl
= 255;
227 if (m
->llmnr_ipv6_udp_fd
>= 0)
228 return m
->llmnr_ipv6_udp_fd
;
230 m
->llmnr_ipv6_udp_fd
= socket(AF_INET6
, SOCK_DGRAM
|SOCK_CLOEXEC
|SOCK_NONBLOCK
, 0);
231 if (m
->llmnr_ipv6_udp_fd
< 0)
232 return log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to create socket: %m");
234 r
= setsockopt(m
->llmnr_ipv6_udp_fd
, IPPROTO_IPV6
, IPV6_UNICAST_HOPS
, &ttl
, sizeof(ttl
));
236 r
= log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to set IPV6_UNICAST_HOPS: %m");
240 /* RFC 4795, section 2.5 recommends setting the TTL of UDP packets to 255. */
241 r
= setsockopt(m
->llmnr_ipv6_udp_fd
, IPPROTO_IPV6
, IPV6_MULTICAST_HOPS
, &ttl
, sizeof(ttl
));
243 r
= log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to set IPV6_MULTICAST_HOPS: %m");
247 r
= setsockopt(m
->llmnr_ipv6_udp_fd
, IPPROTO_IPV6
, IPV6_MULTICAST_LOOP
, &one
, sizeof(one
));
249 r
= log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to set IPV6_MULTICAST_LOOP: %m");
253 r
= setsockopt(m
->llmnr_ipv6_udp_fd
, IPPROTO_IPV6
, IPV6_V6ONLY
, &one
, sizeof(one
));
255 r
= log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to set IPV6_V6ONLY: %m");
259 r
= setsockopt(m
->llmnr_ipv6_udp_fd
, IPPROTO_IPV6
, IPV6_RECVPKTINFO
, &one
, sizeof(one
));
261 r
= log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to set IPV6_RECVPKTINFO: %m");
265 r
= setsockopt(m
->llmnr_ipv6_udp_fd
, IPPROTO_IPV6
, IPV6_RECVHOPLIMIT
, &one
, sizeof(one
));
267 r
= log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to set IPV6_RECVHOPLIMIT: %m");
271 /* first try to bind without SO_REUSEADDR to detect another LLMNR responder */
272 r
= bind(m
->llmnr_ipv6_udp_fd
, &sa
.sa
, sizeof(sa
.in6
));
274 if (errno
!= EADDRINUSE
) {
275 r
= log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to bind socket: %m");
279 log_warning("LLMNR-IPv6(UDP): There appears to be another LLMNR responder running, or previously systemd-resolved crashed with some outstanding transfers.");
281 /* try again with SO_REUSEADDR */
282 r
= setsockopt(m
->llmnr_ipv6_udp_fd
, SOL_SOCKET
, SO_REUSEADDR
, &one
, sizeof(one
));
284 r
= log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to set SO_REUSEADDR: %m");
288 r
= bind(m
->llmnr_ipv6_udp_fd
, &sa
.sa
, sizeof(sa
.in6
));
290 r
= log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to bind socket: %m");
294 /* enable SO_REUSEADDR for the case that the user really wants multiple LLMNR responders */
295 r
= setsockopt(m
->llmnr_ipv6_udp_fd
, SOL_SOCKET
, SO_REUSEADDR
, &one
, sizeof(one
));
297 r
= log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to set SO_REUSEADDR: %m");
302 r
= sd_event_add_io(m
->event
, &m
->llmnr_ipv6_udp_event_source
, m
->llmnr_ipv6_udp_fd
, EPOLLIN
, on_llmnr_packet
, m
);
306 (void) sd_event_source_set_description(m
->llmnr_ipv6_udp_event_source
, "llmnr-ipv6-udp");
308 return m
->llmnr_ipv6_udp_fd
;
311 m
->llmnr_ipv6_udp_fd
= safe_close(m
->llmnr_ipv6_udp_fd
);
315 static int on_llmnr_stream_packet(DnsStream
*s
) {
319 assert(s
->read_packet
);
321 scope
= manager_find_scope(s
->manager
, s
->read_packet
);
323 log_debug("Got LLMNR TCP packet on unknown scope. Ignoring.");
324 else if (dns_packet_validate_query(s
->read_packet
) > 0) {
325 log_debug("Got LLMNR TCP query packet for id %u", DNS_PACKET_ID(s
->read_packet
));
327 dns_scope_process_query(scope
, s
, s
->read_packet
);
329 log_debug("Invalid LLMNR TCP packet, ignoring.");
335 static int on_llmnr_stream(sd_event_source
*s
, int fd
, uint32_t revents
, void *userdata
) {
337 Manager
*m
= userdata
;
340 cfd
= accept4(fd
, NULL
, NULL
, SOCK_NONBLOCK
|SOCK_CLOEXEC
);
342 if (IN_SET(errno
, EAGAIN
, EINTR
))
348 r
= dns_stream_new(m
, &stream
, DNS_PROTOCOL_LLMNR
, cfd
, NULL
);
354 stream
->on_packet
= on_llmnr_stream_packet
;
358 int manager_llmnr_ipv4_tcp_fd(Manager
*m
) {
359 union sockaddr_union sa
= {
360 .in
.sin_family
= AF_INET
,
361 .in
.sin_port
= htobe16(LLMNR_PORT
),
363 static const int one
= 1, pmtu
= IP_PMTUDISC_DONT
;
368 if (m
->llmnr_ipv4_tcp_fd
>= 0)
369 return m
->llmnr_ipv4_tcp_fd
;
371 m
->llmnr_ipv4_tcp_fd
= socket(AF_INET
, SOCK_STREAM
|SOCK_CLOEXEC
|SOCK_NONBLOCK
, 0);
372 if (m
->llmnr_ipv4_tcp_fd
< 0)
373 return log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to create socket: %m");
375 /* RFC 4795, section 2.5. requires setting the TTL of TCP streams to 1 */
376 r
= setsockopt(m
->llmnr_ipv4_tcp_fd
, IPPROTO_IP
, IP_TTL
, &one
, sizeof(one
));
378 r
= log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to set IP_TTL: %m");
382 r
= setsockopt(m
->llmnr_ipv4_tcp_fd
, IPPROTO_IP
, IP_PKTINFO
, &one
, sizeof(one
));
384 r
= log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to set IP_PKTINFO: %m");
388 r
= setsockopt(m
->llmnr_ipv4_tcp_fd
, IPPROTO_IP
, IP_RECVTTL
, &one
, sizeof(one
));
390 r
= log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to set IP_RECVTTL: %m");
394 /* Disable Don't-Fragment bit in the IP header */
395 r
= setsockopt(m
->llmnr_ipv4_tcp_fd
, IPPROTO_IP
, IP_MTU_DISCOVER
, &pmtu
, sizeof(pmtu
));
397 r
= log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to set IP_MTU_DISCOVER: %m");
401 /* first try to bind without SO_REUSEADDR to detect another LLMNR responder */
402 r
= bind(m
->llmnr_ipv4_tcp_fd
, &sa
.sa
, sizeof(sa
.in
));
404 if (errno
!= EADDRINUSE
) {
405 r
= log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to bind socket: %m");
409 log_warning("LLMNR-IPv4(TCP): There appears to be another LLMNR responder running, or previously systemd-resolved crashed with some outstanding transfers.");
411 /* try again with SO_REUSEADDR */
412 r
= setsockopt(m
->llmnr_ipv4_tcp_fd
, SOL_SOCKET
, SO_REUSEADDR
, &one
, sizeof(one
));
414 r
= log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to set SO_REUSEADDR: %m");
418 r
= bind(m
->llmnr_ipv4_tcp_fd
, &sa
.sa
, sizeof(sa
.in
));
420 r
= log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to bind socket: %m");
424 /* enable SO_REUSEADDR for the case that the user really wants multiple LLMNR responders */
425 r
= setsockopt(m
->llmnr_ipv4_tcp_fd
, SOL_SOCKET
, SO_REUSEADDR
, &one
, sizeof(one
));
427 r
= log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to set SO_REUSEADDR: %m");
432 r
= listen(m
->llmnr_ipv4_tcp_fd
, SOMAXCONN
);
434 r
= log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to listen the stream: %m");
438 r
= sd_event_add_io(m
->event
, &m
->llmnr_ipv4_tcp_event_source
, m
->llmnr_ipv4_tcp_fd
, EPOLLIN
, on_llmnr_stream
, m
);
442 (void) sd_event_source_set_description(m
->llmnr_ipv4_tcp_event_source
, "llmnr-ipv4-tcp");
444 return m
->llmnr_ipv4_tcp_fd
;
447 m
->llmnr_ipv4_tcp_fd
= safe_close(m
->llmnr_ipv4_tcp_fd
);
451 int manager_llmnr_ipv6_tcp_fd(Manager
*m
) {
452 union sockaddr_union sa
= {
453 .in6
.sin6_family
= AF_INET6
,
454 .in6
.sin6_port
= htobe16(LLMNR_PORT
),
456 static const int one
= 1;
461 if (m
->llmnr_ipv6_tcp_fd
>= 0)
462 return m
->llmnr_ipv6_tcp_fd
;
464 m
->llmnr_ipv6_tcp_fd
= socket(AF_INET6
, SOCK_STREAM
|SOCK_CLOEXEC
|SOCK_NONBLOCK
, 0);
465 if (m
->llmnr_ipv6_tcp_fd
< 0)
466 return log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to create socket: %m");
468 /* RFC 4795, section 2.5. requires setting the TTL of TCP streams to 1 */
469 r
= setsockopt(m
->llmnr_ipv6_tcp_fd
, IPPROTO_IPV6
, IPV6_UNICAST_HOPS
, &one
, sizeof(one
));
471 r
= log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to set IPV6_UNICAST_HOPS: %m");
475 r
= setsockopt(m
->llmnr_ipv6_tcp_fd
, IPPROTO_IPV6
, IPV6_V6ONLY
, &one
, sizeof(one
));
477 r
= log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to set IPV6_V6ONLY: %m");
481 r
= setsockopt(m
->llmnr_ipv6_tcp_fd
, IPPROTO_IPV6
, IPV6_RECVPKTINFO
, &one
, sizeof(one
));
483 r
= log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to set IPV6_RECVPKTINFO: %m");
487 r
= setsockopt(m
->llmnr_ipv6_tcp_fd
, IPPROTO_IPV6
, IPV6_RECVHOPLIMIT
, &one
, sizeof(one
));
489 r
= log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to set IPV6_RECVHOPLIMIT: %m");
493 /* first try to bind without SO_REUSEADDR to detect another LLMNR responder */
494 r
= bind(m
->llmnr_ipv6_tcp_fd
, &sa
.sa
, sizeof(sa
.in6
));
496 if (errno
!= EADDRINUSE
) {
497 r
= log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to bind socket: %m");
501 log_warning("LLMNR-IPv6(TCP): There appears to be another LLMNR responder running, or previously systemd-resolved crashed with some outstanding transfers.");
503 /* try again with SO_REUSEADDR */
504 r
= setsockopt(m
->llmnr_ipv6_tcp_fd
, SOL_SOCKET
, SO_REUSEADDR
, &one
, sizeof(one
));
506 r
= log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to set SO_REUSEADDR: %m");
510 r
= bind(m
->llmnr_ipv6_tcp_fd
, &sa
.sa
, sizeof(sa
.in6
));
512 r
= log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to bind socket: %m");
516 /* enable SO_REUSEADDR for the case that the user really wants multiple LLMNR responders */
517 r
= setsockopt(m
->llmnr_ipv6_tcp_fd
, SOL_SOCKET
, SO_REUSEADDR
, &one
, sizeof(one
));
519 r
= log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to set SO_REUSEADDR: %m");
524 r
= listen(m
->llmnr_ipv6_tcp_fd
, SOMAXCONN
);
526 r
= log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to listen the stream: %m");
530 r
= sd_event_add_io(m
->event
, &m
->llmnr_ipv6_tcp_event_source
, m
->llmnr_ipv6_tcp_fd
, EPOLLIN
, on_llmnr_stream
, m
);
534 (void) sd_event_source_set_description(m
->llmnr_ipv6_tcp_event_source
, "llmnr-ipv6-tcp");
536 return m
->llmnr_ipv6_tcp_fd
;
539 m
->llmnr_ipv6_tcp_fd
= safe_close(m
->llmnr_ipv6_tcp_fd
);