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 _cleanup_close_
int s
= -1;
123 if (m
->llmnr_ipv4_udp_fd
>= 0)
124 return m
->llmnr_ipv4_udp_fd
;
126 s
= socket(AF_INET
, SOCK_DGRAM
|SOCK_CLOEXEC
|SOCK_NONBLOCK
, 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_int(s
, IPPROTO_IP
, IP_TTL
, 255);
133 return log_error_errno(r
, "LLMNR-IPv4(UDP): Failed to set IP_TTL: %m");
135 r
= setsockopt_int(s
, IPPROTO_IP
, IP_MULTICAST_TTL
, 255);
137 return log_error_errno(r
, "LLMNR-IPv4(UDP): Failed to set IP_MULTICAST_TTL: %m");
139 r
= setsockopt_int(s
, IPPROTO_IP
, IP_MULTICAST_LOOP
, true);
141 return log_error_errno(r
, "LLMNR-IPv4(UDP): Failed to set IP_MULTICAST_LOOP: %m");
143 r
= setsockopt_int(s
, IPPROTO_IP
, IP_PKTINFO
, true);
145 return log_error_errno(r
, "LLMNR-IPv4(UDP): Failed to set IP_PKTINFO: %m");
147 r
= setsockopt_int(s
, IPPROTO_IP
, IP_RECVTTL
, true);
149 return log_error_errno(r
, "LLMNR-IPv4(UDP): Failed to set IP_RECVTTL: %m");
151 /* Disable Don't-Fragment bit in the IP header */
152 r
= setsockopt_int(s
, IPPROTO_IP
, IP_MTU_DISCOVER
, IP_PMTUDISC_DONT
);
154 return log_error_errno(r
, "LLMNR-IPv4(UDP): Failed to set IP_MTU_DISCOVER: %m");
156 /* first try to bind without SO_REUSEADDR to detect another LLMNR responder */
157 r
= bind(s
, &sa
.sa
, sizeof(sa
.in
));
159 if (errno
!= EADDRINUSE
)
160 return log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to bind socket: %m");
162 log_warning("LLMNR-IPv4(UDP): There appears to be another LLMNR responder running, or previously systemd-resolved crashed with some outstanding transfers.");
164 /* try again with SO_REUSEADDR */
165 r
= setsockopt_int(s
, SOL_SOCKET
, SO_REUSEADDR
, true);
167 return log_error_errno(r
, "LLMNR-IPv4(UDP): Failed to set SO_REUSEADDR: %m");
169 r
= bind(s
, &sa
.sa
, sizeof(sa
.in
));
171 return log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to bind socket: %m");
173 /* enable SO_REUSEADDR for the case that the user really wants multiple LLMNR responders */
174 r
= setsockopt_int(s
, SOL_SOCKET
, SO_REUSEADDR
, true);
176 return log_error_errno(r
, "LLMNR-IPv4(UDP): Failed to set SO_REUSEADDR: %m");
179 r
= sd_event_add_io(m
->event
, &m
->llmnr_ipv4_udp_event_source
, s
, EPOLLIN
, on_llmnr_packet
, m
);
181 return log_error_errno(r
, "LLMNR-IPv4(UDP): Failed to create event source: %m");
183 (void) sd_event_source_set_description(m
->llmnr_ipv4_udp_event_source
, "llmnr-ipv4-udp");
185 return m
->llmnr_ipv4_udp_fd
= TAKE_FD(s
);
188 int manager_llmnr_ipv6_udp_fd(Manager
*m
) {
189 union sockaddr_union sa
= {
190 .in6
.sin6_family
= AF_INET6
,
191 .in6
.sin6_port
= htobe16(LLMNR_PORT
),
193 _cleanup_close_
int s
= -1;
198 if (m
->llmnr_ipv6_udp_fd
>= 0)
199 return m
->llmnr_ipv6_udp_fd
;
201 s
= socket(AF_INET6
, SOCK_DGRAM
|SOCK_CLOEXEC
|SOCK_NONBLOCK
, 0);
203 return log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to create socket: %m");
205 r
= setsockopt_int(s
, IPPROTO_IPV6
, IPV6_UNICAST_HOPS
, 255);
207 return log_error_errno(r
, "LLMNR-IPv6(UDP): Failed to set IPV6_UNICAST_HOPS: %m");
209 /* RFC 4795, section 2.5 recommends setting the TTL of UDP packets to 255. */
210 r
= setsockopt_int(s
, IPPROTO_IPV6
, IPV6_MULTICAST_HOPS
, 255);
212 return log_error_errno(r
, "LLMNR-IPv6(UDP): Failed to set IPV6_MULTICAST_HOPS: %m");
214 r
= setsockopt_int(s
, IPPROTO_IPV6
, IPV6_MULTICAST_LOOP
, true);
216 return log_error_errno(r
, "LLMNR-IPv6(UDP): Failed to set IPV6_MULTICAST_LOOP: %m");
218 r
= setsockopt_int(s
, IPPROTO_IPV6
, IPV6_V6ONLY
, true);
220 return log_error_errno(r
, "LLMNR-IPv6(UDP): Failed to set IPV6_V6ONLY: %m");
222 r
= setsockopt_int(s
, IPPROTO_IPV6
, IPV6_RECVPKTINFO
, true);
224 return log_error_errno(r
, "LLMNR-IPv6(UDP): Failed to set IPV6_RECVPKTINFO: %m");
226 r
= setsockopt_int(s
, IPPROTO_IPV6
, IPV6_RECVHOPLIMIT
, true);
228 return log_error_errno(r
, "LLMNR-IPv6(UDP): Failed to set IPV6_RECVHOPLIMIT: %m");
230 /* first try to bind without SO_REUSEADDR to detect another LLMNR responder */
231 r
= bind(s
, &sa
.sa
, sizeof(sa
.in6
));
233 if (errno
!= EADDRINUSE
)
234 return log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to bind socket: %m");
236 log_warning("LLMNR-IPv6(UDP): There appears to be another LLMNR responder running, or previously systemd-resolved crashed with some outstanding transfers.");
238 /* try again with SO_REUSEADDR */
239 r
= setsockopt_int(s
, SOL_SOCKET
, SO_REUSEADDR
, true);
241 return log_error_errno(r
, "LLMNR-IPv6(UDP): Failed to set SO_REUSEADDR: %m");
243 r
= bind(s
, &sa
.sa
, sizeof(sa
.in6
));
245 return log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to bind socket: %m");
247 /* enable SO_REUSEADDR for the case that the user really wants multiple LLMNR responders */
248 r
= setsockopt_int(s
, SOL_SOCKET
, SO_REUSEADDR
, true);
250 return log_error_errno(r
, "LLMNR-IPv6(UDP): Failed to set SO_REUSEADDR: %m");
253 r
= sd_event_add_io(m
->event
, &m
->llmnr_ipv6_udp_event_source
, s
, EPOLLIN
, on_llmnr_packet
, m
);
255 return log_error_errno(r
, "LLMNR-IPv6(UDP): Failed to create event source: %m");
257 (void) sd_event_source_set_description(m
->llmnr_ipv6_udp_event_source
, "llmnr-ipv6-udp");
259 return m
->llmnr_ipv6_udp_fd
= TAKE_FD(s
);
262 static int on_llmnr_stream_packet(DnsStream
*s
) {
263 _cleanup_(dns_packet_unrefp
) DnsPacket
*p
= NULL
;
268 p
= dns_stream_take_read_packet(s
);
271 scope
= manager_find_scope(s
->manager
, p
);
273 log_debug("Got LLMNR TCP packet on unknown scope. Ignoring.");
274 else if (dns_packet_validate_query(p
) > 0) {
275 log_debug("Got LLMNR TCP query packet for id %u", DNS_PACKET_ID(p
));
277 dns_scope_process_query(scope
, s
, p
);
279 log_debug("Invalid LLMNR TCP packet, ignoring.");
285 static int on_llmnr_stream(sd_event_source
*s
, int fd
, uint32_t revents
, void *userdata
) {
287 Manager
*m
= userdata
;
290 cfd
= accept4(fd
, NULL
, NULL
, SOCK_NONBLOCK
|SOCK_CLOEXEC
);
292 if (IN_SET(errno
, EAGAIN
, EINTR
))
298 r
= dns_stream_new(m
, &stream
, DNS_STREAM_LLMNR_RECV
, DNS_PROTOCOL_LLMNR
, cfd
, NULL
);
304 stream
->on_packet
= on_llmnr_stream_packet
;
305 /* We don't configure a "complete" handler here, we rely on the default handler than simply drops the
306 * reference to the stream, thus freeing it */
310 int manager_llmnr_ipv4_tcp_fd(Manager
*m
) {
311 union sockaddr_union sa
= {
312 .in
.sin_family
= AF_INET
,
313 .in
.sin_port
= htobe16(LLMNR_PORT
),
315 _cleanup_close_
int s
= -1;
320 if (m
->llmnr_ipv4_tcp_fd
>= 0)
321 return m
->llmnr_ipv4_tcp_fd
;
323 s
= socket(AF_INET
, SOCK_STREAM
|SOCK_CLOEXEC
|SOCK_NONBLOCK
, 0);
325 return log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to create socket: %m");
327 /* RFC 4795, section 2.5. requires setting the TTL of TCP streams to 1 */
328 r
= setsockopt_int(s
, IPPROTO_IP
, IP_TTL
, true);
330 return log_error_errno(r
, "LLMNR-IPv4(TCP): Failed to set IP_TTL: %m");
332 r
= setsockopt_int(s
, IPPROTO_IP
, IP_PKTINFO
, true);
334 return log_error_errno(r
, "LLMNR-IPv4(TCP): Failed to set IP_PKTINFO: %m");
336 r
= setsockopt_int(s
, IPPROTO_IP
, IP_RECVTTL
, true);
338 return log_error_errno(r
, "LLMNR-IPv4(TCP): Failed to set IP_RECVTTL: %m");
340 /* Disable Don't-Fragment bit in the IP header */
341 r
= setsockopt_int(s
, IPPROTO_IP
, IP_MTU_DISCOVER
, IP_PMTUDISC_DONT
);
343 return log_error_errno(r
, "LLMNR-IPv4(TCP): Failed to set IP_MTU_DISCOVER: %m");
345 /* first try to bind without SO_REUSEADDR to detect another LLMNR responder */
346 r
= bind(s
, &sa
.sa
, sizeof(sa
.in
));
348 if (errno
!= EADDRINUSE
)
349 return log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to bind socket: %m");
351 log_warning("LLMNR-IPv4(TCP): There appears to be another LLMNR responder running, or previously systemd-resolved crashed with some outstanding transfers.");
353 /* try again with SO_REUSEADDR */
354 r
= setsockopt_int(s
, SOL_SOCKET
, SO_REUSEADDR
, true);
356 return log_error_errno(r
, "LLMNR-IPv4(TCP): Failed to set SO_REUSEADDR: %m");
358 r
= bind(s
, &sa
.sa
, sizeof(sa
.in
));
360 return log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to bind socket: %m");
362 /* enable SO_REUSEADDR for the case that the user really wants multiple LLMNR responders */
363 r
= setsockopt_int(s
, SOL_SOCKET
, SO_REUSEADDR
, true);
365 return log_error_errno(r
, "LLMNR-IPv4(TCP): Failed to set SO_REUSEADDR: %m");
368 r
= listen(s
, SOMAXCONN
);
370 return log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to listen the stream: %m");
372 r
= sd_event_add_io(m
->event
, &m
->llmnr_ipv4_tcp_event_source
, s
, EPOLLIN
, on_llmnr_stream
, m
);
374 return log_error_errno(r
, "LLMNR-IPv4(TCP): Failed to create event source: %m");
376 (void) sd_event_source_set_description(m
->llmnr_ipv4_tcp_event_source
, "llmnr-ipv4-tcp");
378 return m
->llmnr_ipv4_tcp_fd
= TAKE_FD(s
);
381 int manager_llmnr_ipv6_tcp_fd(Manager
*m
) {
382 union sockaddr_union sa
= {
383 .in6
.sin6_family
= AF_INET6
,
384 .in6
.sin6_port
= htobe16(LLMNR_PORT
),
386 _cleanup_close_
int s
= -1;
391 if (m
->llmnr_ipv6_tcp_fd
>= 0)
392 return m
->llmnr_ipv6_tcp_fd
;
394 s
= socket(AF_INET6
, SOCK_STREAM
|SOCK_CLOEXEC
|SOCK_NONBLOCK
, 0);
396 return log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to create socket: %m");
398 /* RFC 4795, section 2.5. requires setting the TTL of TCP streams to 1 */
399 r
= setsockopt_int(s
, IPPROTO_IPV6
, IPV6_UNICAST_HOPS
, true);
401 return log_error_errno(r
, "LLMNR-IPv6(TCP): Failed to set IPV6_UNICAST_HOPS: %m");
403 r
= setsockopt_int(s
, IPPROTO_IPV6
, IPV6_V6ONLY
, true);
405 return log_error_errno(r
, "LLMNR-IPv6(TCP): Failed to set IPV6_V6ONLY: %m");
407 r
= setsockopt_int(s
, IPPROTO_IPV6
, IPV6_RECVPKTINFO
, true);
409 return log_error_errno(r
, "LLMNR-IPv6(TCP): Failed to set IPV6_RECVPKTINFO: %m");
411 r
= setsockopt_int(s
, IPPROTO_IPV6
, IPV6_RECVHOPLIMIT
, true);
413 return log_error_errno(r
, "LLMNR-IPv6(TCP): Failed to set IPV6_RECVHOPLIMIT: %m");
415 /* first try to bind without SO_REUSEADDR to detect another LLMNR responder */
416 r
= bind(s
, &sa
.sa
, sizeof(sa
.in6
));
418 if (errno
!= EADDRINUSE
)
419 return log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to bind socket: %m");
421 log_warning("LLMNR-IPv6(TCP): There appears to be another LLMNR responder running, or previously systemd-resolved crashed with some outstanding transfers.");
423 /* try again with SO_REUSEADDR */
424 r
= setsockopt_int(s
, SOL_SOCKET
, SO_REUSEADDR
, true);
426 return log_error_errno(r
, "LLMNR-IPv6(TCP): Failed to set SO_REUSEADDR: %m");
428 r
= bind(s
, &sa
.sa
, sizeof(sa
.in6
));
430 return log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to bind socket: %m");
432 /* enable SO_REUSEADDR for the case that the user really wants multiple LLMNR responders */
433 r
= setsockopt_int(s
, SOL_SOCKET
, SO_REUSEADDR
, true);
435 return log_error_errno(r
, "LLMNR-IPv6(TCP): Failed to set SO_REUSEADDR: %m");
438 r
= listen(s
, SOMAXCONN
);
440 return log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to listen the stream: %m");
442 r
= sd_event_add_io(m
->event
, &m
->llmnr_ipv6_tcp_event_source
, s
, EPOLLIN
, on_llmnr_stream
, m
);
444 return log_error_errno(r
, "LLMNR-IPv6(TCP): Failed to create event source: %m");
446 (void) sd_event_source_set_description(m
->llmnr_ipv6_tcp_event_source
, "llmnr-ipv6-tcp");
448 return m
->llmnr_ipv6_tcp_fd
= TAKE_FD(s
);