1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 #include <netinet/in.h>
4 #include <netinet/tcp.h>
7 #include "errno-util.h"
9 #include "resolved-llmnr.h"
10 #include "resolved-manager.h"
12 void manager_llmnr_stop(Manager
*m
) {
15 m
->llmnr_ipv4_udp_event_source
= sd_event_source_disable_unref(m
->llmnr_ipv4_udp_event_source
);
16 m
->llmnr_ipv4_udp_fd
= safe_close(m
->llmnr_ipv4_udp_fd
);
18 m
->llmnr_ipv6_udp_event_source
= sd_event_source_disable_unref(m
->llmnr_ipv6_udp_event_source
);
19 m
->llmnr_ipv6_udp_fd
= safe_close(m
->llmnr_ipv6_udp_fd
);
21 m
->llmnr_ipv4_tcp_event_source
= sd_event_source_disable_unref(m
->llmnr_ipv4_tcp_event_source
);
22 m
->llmnr_ipv4_tcp_fd
= safe_close(m
->llmnr_ipv4_tcp_fd
);
24 m
->llmnr_ipv6_tcp_event_source
= sd_event_source_disable_unref(m
->llmnr_ipv6_tcp_event_source
);
25 m
->llmnr_ipv6_tcp_fd
= safe_close(m
->llmnr_ipv6_tcp_fd
);
28 int manager_llmnr_start(Manager
*m
) {
33 if (m
->llmnr_support
== RESOLVE_SUPPORT_NO
)
36 r
= manager_llmnr_ipv4_udp_fd(m
);
42 r
= manager_llmnr_ipv4_tcp_fd(m
);
48 if (socket_ipv6_is_supported()) {
49 r
= manager_llmnr_ipv6_udp_fd(m
);
55 r
= manager_llmnr_ipv6_tcp_fd(m
);
65 log_warning("Another LLMNR responder prohibits binding the socket to the same port. Turning off LLMNR support.");
66 m
->llmnr_support
= RESOLVE_SUPPORT_NO
;
67 manager_llmnr_stop(m
);
72 static int on_llmnr_packet(sd_event_source
*s
, int fd
, uint32_t revents
, void *userdata
) {
73 _cleanup_(dns_packet_unrefp
) DnsPacket
*p
= NULL
;
74 DnsTransaction
*t
= NULL
;
75 Manager
*m
= ASSERT_PTR(userdata
);
82 r
= manager_recv(m
, fd
, DNS_PROTOCOL_LLMNR
, &p
);
86 if (manager_packet_from_local_address(m
, p
))
89 scope
= manager_find_scope(m
, p
);
91 log_debug("Got LLMNR UDP packet on unknown scope. Ignoring.");
95 if (dns_packet_validate_reply(p
) > 0) {
96 log_debug("Got LLMNR UDP reply packet for id %u", DNS_PACKET_ID(p
));
98 dns_scope_check_conflicts(scope
, p
);
100 t
= hashmap_get(m
->dns_transactions
, UINT_TO_PTR(DNS_PACKET_ID(p
)));
102 dns_transaction_process_reply(t
, p
, false);
104 } else if (dns_packet_validate_query(p
) > 0) {
105 log_debug("Got LLMNR UDP query packet for id %u", DNS_PACKET_ID(p
));
107 dns_scope_process_query(scope
, NULL
, p
);
109 log_debug("Invalid LLMNR UDP packet, ignoring.");
114 static int set_llmnr_common_socket_options(int fd
, int family
) {
117 r
= socket_set_recvpktinfo(fd
, family
, true);
121 r
= socket_set_recvttl(fd
, family
, true);
128 static int set_llmnr_common_udp_socket_options(int fd
, int family
) {
131 /* RFC 4795, section 2.5 recommends setting the TTL of UDP packets to 255. */
132 r
= socket_set_ttl(fd
, family
, 255);
139 int manager_llmnr_ipv4_udp_fd(Manager
*m
) {
140 union sockaddr_union sa
= {
141 .in
.sin_family
= AF_INET
,
142 .in
.sin_port
= htobe16(LLMNR_PORT
),
144 _cleanup_close_
int s
= -1;
149 if (m
->llmnr_ipv4_udp_fd
>= 0)
150 return m
->llmnr_ipv4_udp_fd
;
152 s
= socket(AF_INET
, SOCK_DGRAM
|SOCK_CLOEXEC
|SOCK_NONBLOCK
, 0);
154 return log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to create socket: %m");
156 r
= set_llmnr_common_socket_options(s
, AF_INET
);
158 return log_error_errno(r
, "LLMNR-IPv4(UDP): Failed to set common socket options: %m");
160 r
= set_llmnr_common_udp_socket_options(s
, AF_INET
);
162 return log_error_errno(r
, "LLMNR-IPv4(UDP): Failed to set common UDP socket options: %m");
164 r
= setsockopt_int(s
, IPPROTO_IP
, IP_MULTICAST_TTL
, 255);
166 return log_error_errno(r
, "LLMNR-IPv4(UDP): Failed to set IP_MULTICAST_TTL: %m");
168 r
= setsockopt_int(s
, IPPROTO_IP
, IP_MULTICAST_LOOP
, true);
170 return log_error_errno(r
, "LLMNR-IPv4(UDP): Failed to set IP_MULTICAST_LOOP: %m");
172 /* Disable Don't-Fragment bit in the IP header */
173 r
= setsockopt_int(s
, IPPROTO_IP
, IP_MTU_DISCOVER
, IP_PMTUDISC_DONT
);
175 return log_error_errno(r
, "LLMNR-IPv4(UDP): Failed to set IP_MTU_DISCOVER: %m");
177 /* first try to bind without SO_REUSEADDR to detect another LLMNR responder */
178 r
= bind(s
, &sa
.sa
, sizeof(sa
.in
));
180 if (errno
!= EADDRINUSE
)
181 return log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to bind socket: %m");
183 log_warning("LLMNR-IPv4(UDP): There appears to be another LLMNR responder running, or previously systemd-resolved crashed with some outstanding transfers.");
185 /* try again with SO_REUSEADDR */
186 r
= setsockopt_int(s
, SOL_SOCKET
, SO_REUSEADDR
, true);
188 return log_error_errno(r
, "LLMNR-IPv4(UDP): Failed to set SO_REUSEADDR: %m");
190 r
= bind(s
, &sa
.sa
, sizeof(sa
.in
));
192 return log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to bind socket: %m");
194 /* enable SO_REUSEADDR for the case that the user really wants multiple LLMNR responders */
195 r
= setsockopt_int(s
, SOL_SOCKET
, SO_REUSEADDR
, true);
197 return log_error_errno(r
, "LLMNR-IPv4(UDP): Failed to set SO_REUSEADDR: %m");
200 r
= sd_event_add_io(m
->event
, &m
->llmnr_ipv4_udp_event_source
, s
, EPOLLIN
, on_llmnr_packet
, m
);
202 return log_error_errno(r
, "LLMNR-IPv4(UDP): Failed to create event source: %m");
204 (void) sd_event_source_set_description(m
->llmnr_ipv4_udp_event_source
, "llmnr-ipv4-udp");
206 return m
->llmnr_ipv4_udp_fd
= TAKE_FD(s
);
209 int manager_llmnr_ipv6_udp_fd(Manager
*m
) {
210 union sockaddr_union sa
= {
211 .in6
.sin6_family
= AF_INET6
,
212 .in6
.sin6_port
= htobe16(LLMNR_PORT
),
214 _cleanup_close_
int s
= -1;
219 if (m
->llmnr_ipv6_udp_fd
>= 0)
220 return m
->llmnr_ipv6_udp_fd
;
222 s
= socket(AF_INET6
, SOCK_DGRAM
|SOCK_CLOEXEC
|SOCK_NONBLOCK
, 0);
224 return log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to create socket: %m");
226 r
= set_llmnr_common_socket_options(s
, AF_INET6
);
228 return log_error_errno(r
, "LLMNR-IPv6(UDP): Failed to set common socket options: %m");
230 r
= set_llmnr_common_udp_socket_options(s
, AF_INET6
);
232 return log_error_errno(r
, "LLMNR-IPv6(UDP): Failed to set common UDP socket options: %m");
234 /* RFC 4795, section 2.5 recommends setting the TTL of UDP packets to 255. */
235 r
= setsockopt_int(s
, IPPROTO_IPV6
, IPV6_MULTICAST_HOPS
, 255);
237 return log_error_errno(r
, "LLMNR-IPv6(UDP): Failed to set IPV6_MULTICAST_HOPS: %m");
239 r
= setsockopt_int(s
, IPPROTO_IPV6
, IPV6_MULTICAST_LOOP
, true);
241 return log_error_errno(r
, "LLMNR-IPv6(UDP): Failed to set IPV6_MULTICAST_LOOP: %m");
243 r
= setsockopt_int(s
, IPPROTO_IPV6
, IPV6_V6ONLY
, true);
245 return log_error_errno(r
, "LLMNR-IPv6(UDP): Failed to set IPV6_V6ONLY: %m");
247 /* first try to bind without SO_REUSEADDR to detect another LLMNR responder */
248 r
= bind(s
, &sa
.sa
, sizeof(sa
.in6
));
250 if (errno
!= EADDRINUSE
)
251 return log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to bind socket: %m");
253 log_warning("LLMNR-IPv6(UDP): There appears to be another LLMNR responder running, or previously systemd-resolved crashed with some outstanding transfers.");
255 /* try again with SO_REUSEADDR */
256 r
= setsockopt_int(s
, SOL_SOCKET
, SO_REUSEADDR
, true);
258 return log_error_errno(r
, "LLMNR-IPv6(UDP): Failed to set SO_REUSEADDR: %m");
260 r
= bind(s
, &sa
.sa
, sizeof(sa
.in6
));
262 return log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to bind socket: %m");
264 /* enable SO_REUSEADDR for the case that the user really wants multiple LLMNR responders */
265 r
= setsockopt_int(s
, SOL_SOCKET
, SO_REUSEADDR
, true);
267 return log_error_errno(r
, "LLMNR-IPv6(UDP): Failed to set SO_REUSEADDR: %m");
270 r
= sd_event_add_io(m
->event
, &m
->llmnr_ipv6_udp_event_source
, s
, EPOLLIN
, on_llmnr_packet
, m
);
272 return log_error_errno(r
, "LLMNR-IPv6(UDP): Failed to create event source: %m");
274 (void) sd_event_source_set_description(m
->llmnr_ipv6_udp_event_source
, "llmnr-ipv6-udp");
276 return m
->llmnr_ipv6_udp_fd
= TAKE_FD(s
);
279 static int on_llmnr_stream_packet(DnsStream
*s
, DnsPacket
*p
) {
286 scope
= manager_find_scope(s
->manager
, p
);
288 log_debug("Got LLMNR TCP packet on unknown scope. Ignoring.");
289 else if (dns_packet_validate_query(p
) > 0) {
290 log_debug("Got LLMNR TCP query packet for id %u", DNS_PACKET_ID(p
));
292 dns_scope_process_query(scope
, s
, p
);
294 log_debug("Invalid LLMNR TCP packet, ignoring.");
299 static int on_llmnr_stream(sd_event_source
*s
, int fd
, uint32_t revents
, void *userdata
) {
301 Manager
*m
= userdata
;
304 cfd
= accept4(fd
, NULL
, NULL
, SOCK_NONBLOCK
|SOCK_CLOEXEC
);
306 if (ERRNO_IS_ACCEPT_AGAIN(errno
))
312 /* We don't configure a "complete" handler here, we rely on the default handler, thus freeing it */
313 r
= dns_stream_new(m
, &stream
, DNS_STREAM_LLMNR_RECV
, DNS_PROTOCOL_LLMNR
, cfd
, NULL
,
314 on_llmnr_stream_packet
, NULL
, DNS_STREAM_DEFAULT_TIMEOUT_USEC
);
323 static int set_llmnr_common_tcp_socket_options(int fd
, int family
) {
326 /* RFC 4795, section 2.5. requires setting the TTL of TCP streams to 1 */
327 r
= socket_set_ttl(fd
, family
, 1);
331 r
= setsockopt_int(fd
, IPPROTO_TCP
, TCP_FASTOPEN
, 5); /* Everybody appears to pick qlen=5, let's do the same here. */
333 log_debug_errno(r
, "Failed to enable TCP_FASTOPEN on TCP listening socket, ignoring: %m");
335 r
= setsockopt_int(fd
, IPPROTO_TCP
, TCP_NODELAY
, true);
337 log_debug_errno(r
, "Failed to enable TCP_NODELAY mode, ignoring: %m");
342 int manager_llmnr_ipv4_tcp_fd(Manager
*m
) {
343 union sockaddr_union sa
= {
344 .in
.sin_family
= AF_INET
,
345 .in
.sin_port
= htobe16(LLMNR_PORT
),
347 _cleanup_close_
int s
= -1;
352 if (m
->llmnr_ipv4_tcp_fd
>= 0)
353 return m
->llmnr_ipv4_tcp_fd
;
355 s
= socket(AF_INET
, SOCK_STREAM
|SOCK_CLOEXEC
|SOCK_NONBLOCK
, 0);
357 return log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to create socket: %m");
359 r
= set_llmnr_common_socket_options(s
, AF_INET
);
361 return log_error_errno(r
, "LLMNR-IPv4(TCP): Failed to set common socket options: %m");
363 r
= set_llmnr_common_tcp_socket_options(s
, AF_INET
);
365 return log_error_errno(r
, "LLMNR-IPv4(TCP): Failed to set common TCP socket options: %m");
367 /* Disable Don't-Fragment bit in the IP header */
368 r
= setsockopt_int(s
, IPPROTO_IP
, IP_MTU_DISCOVER
, IP_PMTUDISC_DONT
);
370 return log_error_errno(r
, "LLMNR-IPv4(TCP): Failed to set IP_MTU_DISCOVER: %m");
372 /* first try to bind without SO_REUSEADDR to detect another LLMNR responder */
373 r
= bind(s
, &sa
.sa
, sizeof(sa
.in
));
375 if (errno
!= EADDRINUSE
)
376 return log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to bind socket: %m");
378 log_warning("LLMNR-IPv4(TCP): There appears to be another LLMNR responder running, or previously systemd-resolved crashed with some outstanding transfers.");
380 /* try again with SO_REUSEADDR */
381 r
= setsockopt_int(s
, SOL_SOCKET
, SO_REUSEADDR
, true);
383 return log_error_errno(r
, "LLMNR-IPv4(TCP): Failed to set SO_REUSEADDR: %m");
385 r
= bind(s
, &sa
.sa
, sizeof(sa
.in
));
387 return log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to bind socket: %m");
389 /* enable SO_REUSEADDR for the case that the user really wants multiple LLMNR responders */
390 r
= setsockopt_int(s
, SOL_SOCKET
, SO_REUSEADDR
, true);
392 return log_error_errno(r
, "LLMNR-IPv4(TCP): Failed to set SO_REUSEADDR: %m");
395 r
= listen(s
, SOMAXCONN
);
397 return log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to listen the stream: %m");
399 r
= sd_event_add_io(m
->event
, &m
->llmnr_ipv4_tcp_event_source
, s
, EPOLLIN
, on_llmnr_stream
, m
);
401 return log_error_errno(r
, "LLMNR-IPv4(TCP): Failed to create event source: %m");
403 (void) sd_event_source_set_description(m
->llmnr_ipv4_tcp_event_source
, "llmnr-ipv4-tcp");
405 return m
->llmnr_ipv4_tcp_fd
= TAKE_FD(s
);
408 int manager_llmnr_ipv6_tcp_fd(Manager
*m
) {
409 union sockaddr_union sa
= {
410 .in6
.sin6_family
= AF_INET6
,
411 .in6
.sin6_port
= htobe16(LLMNR_PORT
),
413 _cleanup_close_
int s
= -1;
418 if (m
->llmnr_ipv6_tcp_fd
>= 0)
419 return m
->llmnr_ipv6_tcp_fd
;
421 s
= socket(AF_INET6
, SOCK_STREAM
|SOCK_CLOEXEC
|SOCK_NONBLOCK
, 0);
423 return log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to create socket: %m");
425 r
= setsockopt_int(s
, IPPROTO_IPV6
, IPV6_V6ONLY
, true);
427 return log_error_errno(r
, "LLMNR-IPv6(TCP): Failed to set IPV6_V6ONLY: %m");
429 r
= set_llmnr_common_socket_options(s
, AF_INET6
);
431 return log_error_errno(r
, "LLMNR-IPv6(TCP): Failed to set common socket options: %m");
433 r
= set_llmnr_common_tcp_socket_options(s
, AF_INET6
);
435 return log_error_errno(r
, "LLMNR-IPv6(TCP): Failed to set common TCP socket options: %m");
437 /* first try to bind without SO_REUSEADDR to detect another LLMNR responder */
438 r
= bind(s
, &sa
.sa
, sizeof(sa
.in6
));
440 if (errno
!= EADDRINUSE
)
441 return log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to bind socket: %m");
443 log_warning("LLMNR-IPv6(TCP): There appears to be another LLMNR responder running, or previously systemd-resolved crashed with some outstanding transfers.");
445 /* try again with SO_REUSEADDR */
446 r
= setsockopt_int(s
, SOL_SOCKET
, SO_REUSEADDR
, true);
448 return log_error_errno(r
, "LLMNR-IPv6(TCP): Failed to set SO_REUSEADDR: %m");
450 r
= bind(s
, &sa
.sa
, sizeof(sa
.in6
));
452 return log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to bind socket: %m");
454 /* enable SO_REUSEADDR for the case that the user really wants multiple LLMNR responders */
455 r
= setsockopt_int(s
, SOL_SOCKET
, SO_REUSEADDR
, true);
457 return log_error_errno(r
, "LLMNR-IPv6(TCP): Failed to set SO_REUSEADDR: %m");
460 r
= listen(s
, SOMAXCONN
);
462 return log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to listen the stream: %m");
464 r
= sd_event_add_io(m
->event
, &m
->llmnr_ipv6_tcp_event_source
, s
, EPOLLIN
, on_llmnr_stream
, m
);
466 return log_error_errno(r
, "LLMNR-IPv6(TCP): Failed to create event source: %m");
468 (void) sd_event_source_set_description(m
->llmnr_ipv6_tcp_event_source
, "llmnr-ipv6-tcp");
470 return m
->llmnr_ipv6_tcp_fd
= TAKE_FD(s
);