1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 #include <netinet/in.h>
6 #include "errno-util.h"
8 #include "resolved-llmnr.h"
9 #include "resolved-manager.h"
11 void manager_llmnr_stop(Manager
*m
) {
14 m
->llmnr_ipv4_udp_event_source
= sd_event_source_unref(m
->llmnr_ipv4_udp_event_source
);
15 m
->llmnr_ipv4_udp_fd
= safe_close(m
->llmnr_ipv4_udp_fd
);
17 m
->llmnr_ipv6_udp_event_source
= sd_event_source_unref(m
->llmnr_ipv6_udp_event_source
);
18 m
->llmnr_ipv6_udp_fd
= safe_close(m
->llmnr_ipv6_udp_fd
);
20 m
->llmnr_ipv4_tcp_event_source
= sd_event_source_unref(m
->llmnr_ipv4_tcp_event_source
);
21 m
->llmnr_ipv4_tcp_fd
= safe_close(m
->llmnr_ipv4_tcp_fd
);
23 m
->llmnr_ipv6_tcp_event_source
= sd_event_source_unref(m
->llmnr_ipv6_tcp_event_source
);
24 m
->llmnr_ipv6_tcp_fd
= safe_close(m
->llmnr_ipv6_tcp_fd
);
27 int manager_llmnr_start(Manager
*m
) {
32 if (m
->llmnr_support
== RESOLVE_SUPPORT_NO
)
35 r
= manager_llmnr_ipv4_udp_fd(m
);
41 r
= manager_llmnr_ipv4_tcp_fd(m
);
47 if (socket_ipv6_is_supported()) {
48 r
= manager_llmnr_ipv6_udp_fd(m
);
54 r
= manager_llmnr_ipv6_tcp_fd(m
);
64 log_warning("Another LLMNR responder prohibits binding the socket to the same port. Turning off LLMNR support.");
65 m
->llmnr_support
= RESOLVE_SUPPORT_NO
;
66 manager_llmnr_stop(m
);
71 static int on_llmnr_packet(sd_event_source
*s
, int fd
, uint32_t revents
, void *userdata
) {
72 _cleanup_(dns_packet_unrefp
) DnsPacket
*p
= NULL
;
73 DnsTransaction
*t
= NULL
;
74 Manager
*m
= userdata
;
82 r
= manager_recv(m
, fd
, DNS_PROTOCOL_LLMNR
, &p
);
86 if (manager_our_packet(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
);
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 int manager_llmnr_ipv4_udp_fd(Manager
*m
) {
115 union sockaddr_union sa
= {
116 .in
.sin_family
= AF_INET
,
117 .in
.sin_port
= htobe16(LLMNR_PORT
),
119 _cleanup_close_
int s
= -1;
124 if (m
->llmnr_ipv4_udp_fd
>= 0)
125 return m
->llmnr_ipv4_udp_fd
;
127 s
= socket(AF_INET
, SOCK_DGRAM
|SOCK_CLOEXEC
|SOCK_NONBLOCK
, 0);
129 return log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to create socket: %m");
131 /* RFC 4795, section 2.5 recommends setting the TTL of UDP packets to 255. */
132 r
= setsockopt_int(s
, IPPROTO_IP
, IP_TTL
, 255);
134 return log_error_errno(r
, "LLMNR-IPv4(UDP): Failed to set IP_TTL: %m");
136 r
= setsockopt_int(s
, IPPROTO_IP
, IP_MULTICAST_TTL
, 255);
138 return log_error_errno(r
, "LLMNR-IPv4(UDP): Failed to set IP_MULTICAST_TTL: %m");
140 r
= setsockopt_int(s
, IPPROTO_IP
, IP_MULTICAST_LOOP
, true);
142 return log_error_errno(r
, "LLMNR-IPv4(UDP): Failed to set IP_MULTICAST_LOOP: %m");
144 r
= setsockopt_int(s
, IPPROTO_IP
, IP_PKTINFO
, true);
146 return log_error_errno(r
, "LLMNR-IPv4(UDP): Failed to set IP_PKTINFO: %m");
148 r
= setsockopt_int(s
, IPPROTO_IP
, IP_RECVTTL
, true);
150 return log_error_errno(r
, "LLMNR-IPv4(UDP): Failed to set IP_RECVTTL: %m");
152 /* Disable Don't-Fragment bit in the IP header */
153 r
= setsockopt_int(s
, IPPROTO_IP
, IP_MTU_DISCOVER
, IP_PMTUDISC_DONT
);
155 return log_error_errno(r
, "LLMNR-IPv4(UDP): Failed to set IP_MTU_DISCOVER: %m");
157 /* first try to bind without SO_REUSEADDR to detect another LLMNR responder */
158 r
= bind(s
, &sa
.sa
, sizeof(sa
.in
));
160 if (errno
!= EADDRINUSE
)
161 return log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to bind socket: %m");
163 log_warning("LLMNR-IPv4(UDP): There appears to be another LLMNR responder running, or previously systemd-resolved crashed with some outstanding transfers.");
165 /* try again with SO_REUSEADDR */
166 r
= setsockopt_int(s
, SOL_SOCKET
, SO_REUSEADDR
, true);
168 return log_error_errno(r
, "LLMNR-IPv4(UDP): Failed to set SO_REUSEADDR: %m");
170 r
= bind(s
, &sa
.sa
, sizeof(sa
.in
));
172 return log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to bind socket: %m");
174 /* enable SO_REUSEADDR for the case that the user really wants multiple LLMNR responders */
175 r
= setsockopt_int(s
, SOL_SOCKET
, SO_REUSEADDR
, true);
177 return log_error_errno(r
, "LLMNR-IPv4(UDP): Failed to set SO_REUSEADDR: %m");
180 r
= sd_event_add_io(m
->event
, &m
->llmnr_ipv4_udp_event_source
, s
, EPOLLIN
, on_llmnr_packet
, m
);
182 return log_error_errno(r
, "LLMNR-IPv4(UDP): Failed to create event source: %m");
184 (void) sd_event_source_set_description(m
->llmnr_ipv4_udp_event_source
, "llmnr-ipv4-udp");
186 return m
->llmnr_ipv4_udp_fd
= TAKE_FD(s
);
189 int manager_llmnr_ipv6_udp_fd(Manager
*m
) {
190 union sockaddr_union sa
= {
191 .in6
.sin6_family
= AF_INET6
,
192 .in6
.sin6_port
= htobe16(LLMNR_PORT
),
194 _cleanup_close_
int s
= -1;
199 if (m
->llmnr_ipv6_udp_fd
>= 0)
200 return m
->llmnr_ipv6_udp_fd
;
202 s
= socket(AF_INET6
, SOCK_DGRAM
|SOCK_CLOEXEC
|SOCK_NONBLOCK
, 0);
204 return log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to create socket: %m");
206 r
= setsockopt_int(s
, IPPROTO_IPV6
, IPV6_UNICAST_HOPS
, 255);
208 return log_error_errno(r
, "LLMNR-IPv6(UDP): Failed to set IPV6_UNICAST_HOPS: %m");
210 /* RFC 4795, section 2.5 recommends setting the TTL of UDP packets to 255. */
211 r
= setsockopt_int(s
, IPPROTO_IPV6
, IPV6_MULTICAST_HOPS
, 255);
213 return log_error_errno(r
, "LLMNR-IPv6(UDP): Failed to set IPV6_MULTICAST_HOPS: %m");
215 r
= setsockopt_int(s
, IPPROTO_IPV6
, IPV6_MULTICAST_LOOP
, true);
217 return log_error_errno(r
, "LLMNR-IPv6(UDP): Failed to set IPV6_MULTICAST_LOOP: %m");
219 r
= setsockopt_int(s
, IPPROTO_IPV6
, IPV6_V6ONLY
, true);
221 return log_error_errno(r
, "LLMNR-IPv6(UDP): Failed to set IPV6_V6ONLY: %m");
223 r
= setsockopt_int(s
, IPPROTO_IPV6
, IPV6_RECVPKTINFO
, true);
225 return log_error_errno(r
, "LLMNR-IPv6(UDP): Failed to set IPV6_RECVPKTINFO: %m");
227 r
= setsockopt_int(s
, IPPROTO_IPV6
, IPV6_RECVHOPLIMIT
, true);
229 return log_error_errno(r
, "LLMNR-IPv6(UDP): Failed to set IPV6_RECVHOPLIMIT: %m");
231 /* first try to bind without SO_REUSEADDR to detect another LLMNR responder */
232 r
= bind(s
, &sa
.sa
, sizeof(sa
.in6
));
234 if (errno
!= EADDRINUSE
)
235 return log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to bind socket: %m");
237 log_warning("LLMNR-IPv6(UDP): There appears to be another LLMNR responder running, or previously systemd-resolved crashed with some outstanding transfers.");
239 /* try again with SO_REUSEADDR */
240 r
= setsockopt_int(s
, SOL_SOCKET
, SO_REUSEADDR
, true);
242 return log_error_errno(r
, "LLMNR-IPv6(UDP): Failed to set SO_REUSEADDR: %m");
244 r
= bind(s
, &sa
.sa
, sizeof(sa
.in6
));
246 return log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to bind socket: %m");
248 /* enable SO_REUSEADDR for the case that the user really wants multiple LLMNR responders */
249 r
= setsockopt_int(s
, SOL_SOCKET
, SO_REUSEADDR
, true);
251 return log_error_errno(r
, "LLMNR-IPv6(UDP): Failed to set SO_REUSEADDR: %m");
254 r
= sd_event_add_io(m
->event
, &m
->llmnr_ipv6_udp_event_source
, s
, EPOLLIN
, on_llmnr_packet
, m
);
256 return log_error_errno(r
, "LLMNR-IPv6(UDP): Failed to create event source: %m");
258 (void) sd_event_source_set_description(m
->llmnr_ipv6_udp_event_source
, "llmnr-ipv6-udp");
260 return m
->llmnr_ipv6_udp_fd
= TAKE_FD(s
);
263 static int on_llmnr_stream_packet(DnsStream
*s
) {
264 _cleanup_(dns_packet_unrefp
) DnsPacket
*p
= NULL
;
269 p
= dns_stream_take_read_packet(s
);
272 scope
= manager_find_scope(s
->manager
, p
);
274 log_debug("Got LLMNR TCP packet on unknown scope. Ignoring.");
275 else if (dns_packet_validate_query(p
) > 0) {
276 log_debug("Got LLMNR TCP query packet for id %u", DNS_PACKET_ID(p
));
278 dns_scope_process_query(scope
, s
, p
);
280 log_debug("Invalid LLMNR TCP packet, ignoring.");
286 static int on_llmnr_stream(sd_event_source
*s
, int fd
, uint32_t revents
, void *userdata
) {
288 Manager
*m
= userdata
;
291 cfd
= accept4(fd
, NULL
, NULL
, SOCK_NONBLOCK
|SOCK_CLOEXEC
);
293 if (ERRNO_IS_ACCEPT_AGAIN(errno
))
299 r
= dns_stream_new(m
, &stream
, DNS_STREAM_LLMNR_RECV
, DNS_PROTOCOL_LLMNR
, cfd
, NULL
);
305 stream
->on_packet
= on_llmnr_stream_packet
;
306 /* We don't configure a "complete" handler here, we rely on the default handler than simply drops the
307 * reference to the stream, thus freeing it */
311 int manager_llmnr_ipv4_tcp_fd(Manager
*m
) {
312 union sockaddr_union sa
= {
313 .in
.sin_family
= AF_INET
,
314 .in
.sin_port
= htobe16(LLMNR_PORT
),
316 _cleanup_close_
int s
= -1;
321 if (m
->llmnr_ipv4_tcp_fd
>= 0)
322 return m
->llmnr_ipv4_tcp_fd
;
324 s
= socket(AF_INET
, SOCK_STREAM
|SOCK_CLOEXEC
|SOCK_NONBLOCK
, 0);
326 return log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to create socket: %m");
328 /* RFC 4795, section 2.5. requires setting the TTL of TCP streams to 1 */
329 r
= setsockopt_int(s
, IPPROTO_IP
, IP_TTL
, true);
331 return log_error_errno(r
, "LLMNR-IPv4(TCP): Failed to set IP_TTL: %m");
333 r
= setsockopt_int(s
, IPPROTO_IP
, IP_PKTINFO
, true);
335 return log_error_errno(r
, "LLMNR-IPv4(TCP): Failed to set IP_PKTINFO: %m");
337 r
= setsockopt_int(s
, IPPROTO_IP
, IP_RECVTTL
, true);
339 return log_error_errno(r
, "LLMNR-IPv4(TCP): Failed to set IP_RECVTTL: %m");
341 /* Disable Don't-Fragment bit in the IP header */
342 r
= setsockopt_int(s
, IPPROTO_IP
, IP_MTU_DISCOVER
, IP_PMTUDISC_DONT
);
344 return log_error_errno(r
, "LLMNR-IPv4(TCP): Failed to set IP_MTU_DISCOVER: %m");
346 /* first try to bind without SO_REUSEADDR to detect another LLMNR responder */
347 r
= bind(s
, &sa
.sa
, sizeof(sa
.in
));
349 if (errno
!= EADDRINUSE
)
350 return log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to bind socket: %m");
352 log_warning("LLMNR-IPv4(TCP): There appears to be another LLMNR responder running, or previously systemd-resolved crashed with some outstanding transfers.");
354 /* try again with SO_REUSEADDR */
355 r
= setsockopt_int(s
, SOL_SOCKET
, SO_REUSEADDR
, true);
357 return log_error_errno(r
, "LLMNR-IPv4(TCP): Failed to set SO_REUSEADDR: %m");
359 r
= bind(s
, &sa
.sa
, sizeof(sa
.in
));
361 return log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to bind socket: %m");
363 /* enable SO_REUSEADDR for the case that the user really wants multiple LLMNR responders */
364 r
= setsockopt_int(s
, SOL_SOCKET
, SO_REUSEADDR
, true);
366 return log_error_errno(r
, "LLMNR-IPv4(TCP): Failed to set SO_REUSEADDR: %m");
369 r
= listen(s
, SOMAXCONN
);
371 return log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to listen the stream: %m");
373 r
= sd_event_add_io(m
->event
, &m
->llmnr_ipv4_tcp_event_source
, s
, EPOLLIN
, on_llmnr_stream
, m
);
375 return log_error_errno(r
, "LLMNR-IPv4(TCP): Failed to create event source: %m");
377 (void) sd_event_source_set_description(m
->llmnr_ipv4_tcp_event_source
, "llmnr-ipv4-tcp");
379 return m
->llmnr_ipv4_tcp_fd
= TAKE_FD(s
);
382 int manager_llmnr_ipv6_tcp_fd(Manager
*m
) {
383 union sockaddr_union sa
= {
384 .in6
.sin6_family
= AF_INET6
,
385 .in6
.sin6_port
= htobe16(LLMNR_PORT
),
387 _cleanup_close_
int s
= -1;
392 if (m
->llmnr_ipv6_tcp_fd
>= 0)
393 return m
->llmnr_ipv6_tcp_fd
;
395 s
= socket(AF_INET6
, SOCK_STREAM
|SOCK_CLOEXEC
|SOCK_NONBLOCK
, 0);
397 return log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to create socket: %m");
399 /* RFC 4795, section 2.5. requires setting the TTL of TCP streams to 1 */
400 r
= setsockopt_int(s
, IPPROTO_IPV6
, IPV6_UNICAST_HOPS
, true);
402 return log_error_errno(r
, "LLMNR-IPv6(TCP): Failed to set IPV6_UNICAST_HOPS: %m");
404 r
= setsockopt_int(s
, IPPROTO_IPV6
, IPV6_V6ONLY
, true);
406 return log_error_errno(r
, "LLMNR-IPv6(TCP): Failed to set IPV6_V6ONLY: %m");
408 r
= setsockopt_int(s
, IPPROTO_IPV6
, IPV6_RECVPKTINFO
, true);
410 return log_error_errno(r
, "LLMNR-IPv6(TCP): Failed to set IPV6_RECVPKTINFO: %m");
412 r
= setsockopt_int(s
, IPPROTO_IPV6
, IPV6_RECVHOPLIMIT
, true);
414 return log_error_errno(r
, "LLMNR-IPv6(TCP): Failed to set IPV6_RECVHOPLIMIT: %m");
416 /* first try to bind without SO_REUSEADDR to detect another LLMNR responder */
417 r
= bind(s
, &sa
.sa
, sizeof(sa
.in6
));
419 if (errno
!= EADDRINUSE
)
420 return log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to bind socket: %m");
422 log_warning("LLMNR-IPv6(TCP): There appears to be another LLMNR responder running, or previously systemd-resolved crashed with some outstanding transfers.");
424 /* try again with SO_REUSEADDR */
425 r
= setsockopt_int(s
, SOL_SOCKET
, SO_REUSEADDR
, true);
427 return log_error_errno(r
, "LLMNR-IPv6(TCP): Failed to set SO_REUSEADDR: %m");
429 r
= bind(s
, &sa
.sa
, sizeof(sa
.in6
));
431 return log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to bind socket: %m");
433 /* enable SO_REUSEADDR for the case that the user really wants multiple LLMNR responders */
434 r
= setsockopt_int(s
, SOL_SOCKET
, SO_REUSEADDR
, true);
436 return log_error_errno(r
, "LLMNR-IPv6(TCP): Failed to set SO_REUSEADDR: %m");
439 r
= listen(s
, SOMAXCONN
);
441 return log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to listen the stream: %m");
443 r
= sd_event_add_io(m
->event
, &m
->llmnr_ipv6_tcp_event_source
, s
, EPOLLIN
, on_llmnr_stream
, m
);
445 return log_error_errno(r
, "LLMNR-IPv6(TCP): Failed to create event source: %m");
447 (void) sd_event_source_set_description(m
->llmnr_ipv6_tcp_event_source
, "llmnr-ipv6-tcp");
449 return m
->llmnr_ipv6_tcp_fd
= TAKE_FD(s
);