1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 #include <netinet/in.h>
7 #include "resolved-llmnr.h"
8 #include "resolved-manager.h"
10 void manager_llmnr_stop(Manager
*m
) {
13 m
->llmnr_ipv4_udp_event_source
= sd_event_source_unref(m
->llmnr_ipv4_udp_event_source
);
14 m
->llmnr_ipv4_udp_fd
= safe_close(m
->llmnr_ipv4_udp_fd
);
16 m
->llmnr_ipv6_udp_event_source
= sd_event_source_unref(m
->llmnr_ipv6_udp_event_source
);
17 m
->llmnr_ipv6_udp_fd
= safe_close(m
->llmnr_ipv6_udp_fd
);
19 m
->llmnr_ipv4_tcp_event_source
= sd_event_source_unref(m
->llmnr_ipv4_tcp_event_source
);
20 m
->llmnr_ipv4_tcp_fd
= safe_close(m
->llmnr_ipv4_tcp_fd
);
22 m
->llmnr_ipv6_tcp_event_source
= sd_event_source_unref(m
->llmnr_ipv6_tcp_event_source
);
23 m
->llmnr_ipv6_tcp_fd
= safe_close(m
->llmnr_ipv6_tcp_fd
);
26 int manager_llmnr_start(Manager
*m
) {
31 if (m
->llmnr_support
== RESOLVE_SUPPORT_NO
)
34 r
= manager_llmnr_ipv4_udp_fd(m
);
40 r
= manager_llmnr_ipv4_tcp_fd(m
);
46 if (socket_ipv6_is_supported()) {
47 r
= manager_llmnr_ipv6_udp_fd(m
);
53 r
= manager_llmnr_ipv6_tcp_fd(m
);
63 log_warning("Another LLMNR responder prohibits binding the socket to the same port. Turning off LLMNR support.");
64 m
->llmnr_support
= RESOLVE_SUPPORT_NO
;
65 manager_llmnr_stop(m
);
70 static int on_llmnr_packet(sd_event_source
*s
, int fd
, uint32_t revents
, void *userdata
) {
71 _cleanup_(dns_packet_unrefp
) DnsPacket
*p
= NULL
;
72 DnsTransaction
*t
= NULL
;
73 Manager
*m
= userdata
;
81 r
= manager_recv(m
, fd
, DNS_PROTOCOL_LLMNR
, &p
);
85 if (manager_our_packet(m
, p
))
88 scope
= manager_find_scope(m
, p
);
90 log_debug("Got LLMNR UDP packet on unknown scope. Ignoring.");
94 if (dns_packet_validate_reply(p
) > 0) {
95 log_debug("Got LLMNR UDP reply packet for id %u", DNS_PACKET_ID(p
));
97 dns_scope_check_conflicts(scope
, p
);
99 t
= hashmap_get(m
->dns_transactions
, UINT_TO_PTR(DNS_PACKET_ID(p
)));
101 dns_transaction_process_reply(t
, p
);
103 } else if (dns_packet_validate_query(p
) > 0) {
104 log_debug("Got LLMNR UDP query packet for id %u", DNS_PACKET_ID(p
));
106 dns_scope_process_query(scope
, NULL
, p
);
108 log_debug("Invalid LLMNR UDP packet, ignoring.");
113 int manager_llmnr_ipv4_udp_fd(Manager
*m
) {
114 union sockaddr_union sa
= {
115 .in
.sin_family
= AF_INET
,
116 .in
.sin_port
= htobe16(LLMNR_PORT
),
118 static const int pmtu
= IP_PMTUDISC_DONT
, ttl
= 255;
123 if (m
->llmnr_ipv4_udp_fd
>= 0)
124 return m
->llmnr_ipv4_udp_fd
;
126 m
->llmnr_ipv4_udp_fd
= socket(AF_INET
, SOCK_DGRAM
|SOCK_CLOEXEC
|SOCK_NONBLOCK
, 0);
127 if (m
->llmnr_ipv4_udp_fd
< 0)
128 return log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to create socket: %m");
130 /* RFC 4795, section 2.5 recommends setting the TTL of UDP packets to 255. */
131 r
= setsockopt(m
->llmnr_ipv4_udp_fd
, IPPROTO_IP
, IP_TTL
, &ttl
, sizeof(ttl
));
133 r
= log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to set IP_TTL: %m");
137 r
= setsockopt(m
->llmnr_ipv4_udp_fd
, IPPROTO_IP
, IP_MULTICAST_TTL
, &ttl
, sizeof(ttl
));
139 r
= log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to set IP_MULTICAST_TTL: %m");
143 r
= setsockopt(m
->llmnr_ipv4_udp_fd
, IPPROTO_IP
, IP_MULTICAST_LOOP
, &const_int_one
, sizeof(const_int_one
));
145 r
= log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to set IP_MULTICAST_LOOP: %m");
149 r
= setsockopt(m
->llmnr_ipv4_udp_fd
, IPPROTO_IP
, IP_PKTINFO
, &const_int_one
, sizeof(const_int_one
));
151 r
= log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to set IP_PKTINFO: %m");
155 r
= setsockopt(m
->llmnr_ipv4_udp_fd
, IPPROTO_IP
, IP_RECVTTL
, &const_int_one
, sizeof(const_int_one
));
157 r
= log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to set IP_RECVTTL: %m");
161 /* Disable Don't-Fragment bit in the IP header */
162 r
= setsockopt(m
->llmnr_ipv4_udp_fd
, IPPROTO_IP
, IP_MTU_DISCOVER
, &pmtu
, sizeof(pmtu
));
164 r
= log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to set IP_MTU_DISCOVER: %m");
168 /* first try to bind without SO_REUSEADDR to detect another LLMNR responder */
169 r
= bind(m
->llmnr_ipv4_udp_fd
, &sa
.sa
, sizeof(sa
.in
));
171 if (errno
!= EADDRINUSE
) {
172 r
= log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to bind socket: %m");
176 log_warning("LLMNR-IPv4(UDP): There appears to be another LLMNR responder running, or previously systemd-resolved crashed with some outstanding transfers.");
178 /* try again with SO_REUSEADDR */
179 r
= setsockopt(m
->llmnr_ipv4_udp_fd
, SOL_SOCKET
, SO_REUSEADDR
, &const_int_one
, sizeof(const_int_one
));
181 r
= log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to set SO_REUSEADDR: %m");
185 r
= bind(m
->llmnr_ipv4_udp_fd
, &sa
.sa
, sizeof(sa
.in
));
187 r
= log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to bind socket: %m");
191 /* enable SO_REUSEADDR for the case that the user really wants multiple LLMNR responders */
192 r
= setsockopt(m
->llmnr_ipv4_udp_fd
, SOL_SOCKET
, SO_REUSEADDR
, &const_int_one
, sizeof(const_int_one
));
194 r
= log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to set SO_REUSEADDR: %m");
199 r
= sd_event_add_io(m
->event
, &m
->llmnr_ipv4_udp_event_source
, m
->llmnr_ipv4_udp_fd
, EPOLLIN
, on_llmnr_packet
, m
);
203 (void) sd_event_source_set_description(m
->llmnr_ipv4_udp_event_source
, "llmnr-ipv4-udp");
205 return m
->llmnr_ipv4_udp_fd
;
208 m
->llmnr_ipv4_udp_fd
= safe_close(m
->llmnr_ipv4_udp_fd
);
212 int manager_llmnr_ipv6_udp_fd(Manager
*m
) {
213 union sockaddr_union sa
= {
214 .in6
.sin6_family
= AF_INET6
,
215 .in6
.sin6_port
= htobe16(LLMNR_PORT
),
217 static const int ttl
= 255;
222 if (m
->llmnr_ipv6_udp_fd
>= 0)
223 return m
->llmnr_ipv6_udp_fd
;
225 m
->llmnr_ipv6_udp_fd
= socket(AF_INET6
, SOCK_DGRAM
|SOCK_CLOEXEC
|SOCK_NONBLOCK
, 0);
226 if (m
->llmnr_ipv6_udp_fd
< 0)
227 return log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to create socket: %m");
229 r
= setsockopt(m
->llmnr_ipv6_udp_fd
, IPPROTO_IPV6
, IPV6_UNICAST_HOPS
, &ttl
, sizeof(ttl
));
231 r
= log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to set IPV6_UNICAST_HOPS: %m");
235 /* RFC 4795, section 2.5 recommends setting the TTL of UDP packets to 255. */
236 r
= setsockopt(m
->llmnr_ipv6_udp_fd
, IPPROTO_IPV6
, IPV6_MULTICAST_HOPS
, &ttl
, sizeof(ttl
));
238 r
= log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to set IPV6_MULTICAST_HOPS: %m");
242 r
= setsockopt(m
->llmnr_ipv6_udp_fd
, IPPROTO_IPV6
, IPV6_MULTICAST_LOOP
, &const_int_one
, sizeof(const_int_one
));
244 r
= log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to set IPV6_MULTICAST_LOOP: %m");
248 r
= setsockopt(m
->llmnr_ipv6_udp_fd
, IPPROTO_IPV6
, IPV6_V6ONLY
, &const_int_one
, sizeof(const_int_one
));
250 r
= log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to set IPV6_V6ONLY: %m");
254 r
= setsockopt(m
->llmnr_ipv6_udp_fd
, IPPROTO_IPV6
, IPV6_RECVPKTINFO
, &const_int_one
, sizeof(const_int_one
));
256 r
= log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to set IPV6_RECVPKTINFO: %m");
260 r
= setsockopt(m
->llmnr_ipv6_udp_fd
, IPPROTO_IPV6
, IPV6_RECVHOPLIMIT
, &const_int_one
, sizeof(const_int_one
));
262 r
= log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to set IPV6_RECVHOPLIMIT: %m");
266 /* first try to bind without SO_REUSEADDR to detect another LLMNR responder */
267 r
= bind(m
->llmnr_ipv6_udp_fd
, &sa
.sa
, sizeof(sa
.in6
));
269 if (errno
!= EADDRINUSE
) {
270 r
= log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to bind socket: %m");
274 log_warning("LLMNR-IPv6(UDP): There appears to be another LLMNR responder running, or previously systemd-resolved crashed with some outstanding transfers.");
276 /* try again with SO_REUSEADDR */
277 r
= setsockopt(m
->llmnr_ipv6_udp_fd
, SOL_SOCKET
, SO_REUSEADDR
, &const_int_one
, sizeof(const_int_one
));
279 r
= log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to set SO_REUSEADDR: %m");
283 r
= bind(m
->llmnr_ipv6_udp_fd
, &sa
.sa
, sizeof(sa
.in6
));
285 r
= log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to bind socket: %m");
289 /* enable SO_REUSEADDR for the case that the user really wants multiple LLMNR responders */
290 r
= setsockopt(m
->llmnr_ipv6_udp_fd
, SOL_SOCKET
, SO_REUSEADDR
, &const_int_one
, sizeof(const_int_one
));
292 r
= log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to set SO_REUSEADDR: %m");
297 r
= sd_event_add_io(m
->event
, &m
->llmnr_ipv6_udp_event_source
, m
->llmnr_ipv6_udp_fd
, EPOLLIN
, on_llmnr_packet
, m
);
301 (void) sd_event_source_set_description(m
->llmnr_ipv6_udp_event_source
, "llmnr-ipv6-udp");
303 return m
->llmnr_ipv6_udp_fd
;
306 m
->llmnr_ipv6_udp_fd
= safe_close(m
->llmnr_ipv6_udp_fd
);
310 static int on_llmnr_stream_packet(DnsStream
*s
) {
314 assert(s
->read_packet
);
316 scope
= manager_find_scope(s
->manager
, s
->read_packet
);
318 log_debug("Got LLMNR TCP packet on unknown scope. Ignoring.");
319 else if (dns_packet_validate_query(s
->read_packet
) > 0) {
320 log_debug("Got LLMNR TCP query packet for id %u", DNS_PACKET_ID(s
->read_packet
));
322 dns_scope_process_query(scope
, s
, s
->read_packet
);
324 log_debug("Invalid LLMNR TCP packet, ignoring.");
330 static int on_llmnr_stream(sd_event_source
*s
, int fd
, uint32_t revents
, void *userdata
) {
332 Manager
*m
= userdata
;
335 cfd
= accept4(fd
, NULL
, NULL
, SOCK_NONBLOCK
|SOCK_CLOEXEC
);
337 if (IN_SET(errno
, EAGAIN
, EINTR
))
343 r
= dns_stream_new(m
, &stream
, DNS_PROTOCOL_LLMNR
, cfd
, NULL
);
349 stream
->on_packet
= on_llmnr_stream_packet
;
353 int manager_llmnr_ipv4_tcp_fd(Manager
*m
) {
354 union sockaddr_union sa
= {
355 .in
.sin_family
= AF_INET
,
356 .in
.sin_port
= htobe16(LLMNR_PORT
),
358 static const int pmtu
= IP_PMTUDISC_DONT
;
363 if (m
->llmnr_ipv4_tcp_fd
>= 0)
364 return m
->llmnr_ipv4_tcp_fd
;
366 m
->llmnr_ipv4_tcp_fd
= socket(AF_INET
, SOCK_STREAM
|SOCK_CLOEXEC
|SOCK_NONBLOCK
, 0);
367 if (m
->llmnr_ipv4_tcp_fd
< 0)
368 return log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to create socket: %m");
370 /* RFC 4795, section 2.5. requires setting the TTL of TCP streams to 1 */
371 r
= setsockopt(m
->llmnr_ipv4_tcp_fd
, IPPROTO_IP
, IP_TTL
, &const_int_one
, sizeof(const_int_one
));
373 r
= log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to set IP_TTL: %m");
377 r
= setsockopt(m
->llmnr_ipv4_tcp_fd
, IPPROTO_IP
, IP_PKTINFO
, &const_int_one
, sizeof(const_int_one
));
379 r
= log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to set IP_PKTINFO: %m");
383 r
= setsockopt(m
->llmnr_ipv4_tcp_fd
, IPPROTO_IP
, IP_RECVTTL
, &const_int_one
, sizeof(const_int_one
));
385 r
= log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to set IP_RECVTTL: %m");
389 /* Disable Don't-Fragment bit in the IP header */
390 r
= setsockopt(m
->llmnr_ipv4_tcp_fd
, IPPROTO_IP
, IP_MTU_DISCOVER
, &pmtu
, sizeof(pmtu
));
392 r
= log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to set IP_MTU_DISCOVER: %m");
396 /* first try to bind without SO_REUSEADDR to detect another LLMNR responder */
397 r
= bind(m
->llmnr_ipv4_tcp_fd
, &sa
.sa
, sizeof(sa
.in
));
399 if (errno
!= EADDRINUSE
) {
400 r
= log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to bind socket: %m");
404 log_warning("LLMNR-IPv4(TCP): There appears to be another LLMNR responder running, or previously systemd-resolved crashed with some outstanding transfers.");
406 /* try again with SO_REUSEADDR */
407 r
= setsockopt(m
->llmnr_ipv4_tcp_fd
, SOL_SOCKET
, SO_REUSEADDR
, &const_int_one
, sizeof(const_int_one
));
409 r
= log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to set SO_REUSEADDR: %m");
413 r
= bind(m
->llmnr_ipv4_tcp_fd
, &sa
.sa
, sizeof(sa
.in
));
415 r
= log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to bind socket: %m");
419 /* enable SO_REUSEADDR for the case that the user really wants multiple LLMNR responders */
420 r
= setsockopt(m
->llmnr_ipv4_tcp_fd
, SOL_SOCKET
, SO_REUSEADDR
, &const_int_one
, sizeof(const_int_one
));
422 r
= log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to set SO_REUSEADDR: %m");
427 r
= listen(m
->llmnr_ipv4_tcp_fd
, SOMAXCONN
);
429 r
= log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to listen the stream: %m");
433 r
= sd_event_add_io(m
->event
, &m
->llmnr_ipv4_tcp_event_source
, m
->llmnr_ipv4_tcp_fd
, EPOLLIN
, on_llmnr_stream
, m
);
437 (void) sd_event_source_set_description(m
->llmnr_ipv4_tcp_event_source
, "llmnr-ipv4-tcp");
439 return m
->llmnr_ipv4_tcp_fd
;
442 m
->llmnr_ipv4_tcp_fd
= safe_close(m
->llmnr_ipv4_tcp_fd
);
446 int manager_llmnr_ipv6_tcp_fd(Manager
*m
) {
447 union sockaddr_union sa
= {
448 .in6
.sin6_family
= AF_INET6
,
449 .in6
.sin6_port
= htobe16(LLMNR_PORT
),
455 if (m
->llmnr_ipv6_tcp_fd
>= 0)
456 return m
->llmnr_ipv6_tcp_fd
;
458 m
->llmnr_ipv6_tcp_fd
= socket(AF_INET6
, SOCK_STREAM
|SOCK_CLOEXEC
|SOCK_NONBLOCK
, 0);
459 if (m
->llmnr_ipv6_tcp_fd
< 0)
460 return log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to create socket: %m");
462 /* RFC 4795, section 2.5. requires setting the TTL of TCP streams to 1 */
463 r
= setsockopt(m
->llmnr_ipv6_tcp_fd
, IPPROTO_IPV6
, IPV6_UNICAST_HOPS
, &const_int_one
, sizeof(const_int_one
));
465 r
= log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to set IPV6_UNICAST_HOPS: %m");
469 r
= setsockopt(m
->llmnr_ipv6_tcp_fd
, IPPROTO_IPV6
, IPV6_V6ONLY
, &const_int_one
, sizeof(const_int_one
));
471 r
= log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to set IPV6_V6ONLY: %m");
475 r
= setsockopt(m
->llmnr_ipv6_tcp_fd
, IPPROTO_IPV6
, IPV6_RECVPKTINFO
, &const_int_one
, sizeof(const_int_one
));
477 r
= log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to set IPV6_RECVPKTINFO: %m");
481 r
= setsockopt(m
->llmnr_ipv6_tcp_fd
, IPPROTO_IPV6
, IPV6_RECVHOPLIMIT
, &const_int_one
, sizeof(const_int_one
));
483 r
= log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to set IPV6_RECVHOPLIMIT: %m");
487 /* first try to bind without SO_REUSEADDR to detect another LLMNR responder */
488 r
= bind(m
->llmnr_ipv6_tcp_fd
, &sa
.sa
, sizeof(sa
.in6
));
490 if (errno
!= EADDRINUSE
) {
491 r
= log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to bind socket: %m");
495 log_warning("LLMNR-IPv6(TCP): There appears to be another LLMNR responder running, or previously systemd-resolved crashed with some outstanding transfers.");
497 /* try again with SO_REUSEADDR */
498 r
= setsockopt(m
->llmnr_ipv6_tcp_fd
, SOL_SOCKET
, SO_REUSEADDR
, &const_int_one
, sizeof(const_int_one
));
500 r
= log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to set SO_REUSEADDR: %m");
504 r
= bind(m
->llmnr_ipv6_tcp_fd
, &sa
.sa
, sizeof(sa
.in6
));
506 r
= log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to bind socket: %m");
510 /* enable SO_REUSEADDR for the case that the user really wants multiple LLMNR responders */
511 r
= setsockopt(m
->llmnr_ipv6_tcp_fd
, SOL_SOCKET
, SO_REUSEADDR
, &const_int_one
, sizeof(const_int_one
));
513 r
= log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to set SO_REUSEADDR: %m");
518 r
= listen(m
->llmnr_ipv6_tcp_fd
, SOMAXCONN
);
520 r
= log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to listen the stream: %m");
524 r
= sd_event_add_io(m
->event
, &m
->llmnr_ipv6_tcp_event_source
, m
->llmnr_ipv6_tcp_fd
, EPOLLIN
, on_llmnr_stream
, m
);
528 (void) sd_event_source_set_description(m
->llmnr_ipv6_tcp_event_source
, "llmnr-ipv6-tcp");
530 return m
->llmnr_ipv6_tcp_fd
;
533 m
->llmnr_ipv6_tcp_fd
= safe_close(m
->llmnr_ipv6_tcp_fd
);