1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 Copyright 2014 Tom Gundersen <teg@jklm.no>
6 #include <netinet/in.h>
10 #include "resolved-llmnr.h"
11 #include "resolved-manager.h"
13 void manager_llmnr_stop(Manager
*m
) {
16 m
->llmnr_ipv4_udp_event_source
= sd_event_source_unref(m
->llmnr_ipv4_udp_event_source
);
17 m
->llmnr_ipv4_udp_fd
= safe_close(m
->llmnr_ipv4_udp_fd
);
19 m
->llmnr_ipv6_udp_event_source
= sd_event_source_unref(m
->llmnr_ipv6_udp_event_source
);
20 m
->llmnr_ipv6_udp_fd
= safe_close(m
->llmnr_ipv6_udp_fd
);
22 m
->llmnr_ipv4_tcp_event_source
= sd_event_source_unref(m
->llmnr_ipv4_tcp_event_source
);
23 m
->llmnr_ipv4_tcp_fd
= safe_close(m
->llmnr_ipv4_tcp_fd
);
25 m
->llmnr_ipv6_tcp_event_source
= sd_event_source_unref(m
->llmnr_ipv6_tcp_event_source
);
26 m
->llmnr_ipv6_tcp_fd
= safe_close(m
->llmnr_ipv6_tcp_fd
);
29 int manager_llmnr_start(Manager
*m
) {
34 if (m
->llmnr_support
== RESOLVE_SUPPORT_NO
)
37 r
= manager_llmnr_ipv4_udp_fd(m
);
43 r
= manager_llmnr_ipv4_tcp_fd(m
);
49 if (socket_ipv6_is_supported()) {
50 r
= manager_llmnr_ipv6_udp_fd(m
);
56 r
= manager_llmnr_ipv6_tcp_fd(m
);
66 log_warning("Another LLMNR responder prohibits binding the socket to the same port. Turning off LLMNR support.");
67 m
->llmnr_support
= RESOLVE_SUPPORT_NO
;
68 manager_llmnr_stop(m
);
73 static int on_llmnr_packet(sd_event_source
*s
, int fd
, uint32_t revents
, void *userdata
) {
74 _cleanup_(dns_packet_unrefp
) DnsPacket
*p
= NULL
;
75 DnsTransaction
*t
= NULL
;
76 Manager
*m
= userdata
;
84 r
= manager_recv(m
, fd
, DNS_PROTOCOL_LLMNR
, &p
);
88 if (manager_our_packet(m
, p
))
91 scope
= manager_find_scope(m
, p
);
93 log_debug("Got LLMNR UDP packet on unknown scope. Ignoring.");
97 if (dns_packet_validate_reply(p
) > 0) {
98 log_debug("Got LLMNR UDP reply packet for id %u", DNS_PACKET_ID(p
));
100 dns_scope_check_conflicts(scope
, p
);
102 t
= hashmap_get(m
->dns_transactions
, UINT_TO_PTR(DNS_PACKET_ID(p
)));
104 dns_transaction_process_reply(t
, p
);
106 } else if (dns_packet_validate_query(p
) > 0) {
107 log_debug("Got LLMNR UDP query packet for id %u", DNS_PACKET_ID(p
));
109 dns_scope_process_query(scope
, NULL
, p
);
111 log_debug("Invalid LLMNR UDP packet, ignoring.");
116 int manager_llmnr_ipv4_udp_fd(Manager
*m
) {
117 union sockaddr_union sa
= {
118 .in
.sin_family
= AF_INET
,
119 .in
.sin_port
= htobe16(LLMNR_PORT
),
121 static const int one
= 1, pmtu
= IP_PMTUDISC_DONT
, ttl
= 255;
126 if (m
->llmnr_ipv4_udp_fd
>= 0)
127 return m
->llmnr_ipv4_udp_fd
;
129 m
->llmnr_ipv4_udp_fd
= socket(AF_INET
, SOCK_DGRAM
|SOCK_CLOEXEC
|SOCK_NONBLOCK
, 0);
130 if (m
->llmnr_ipv4_udp_fd
< 0)
131 return log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to create socket: %m");
133 /* RFC 4795, section 2.5 recommends setting the TTL of UDP packets to 255. */
134 r
= setsockopt(m
->llmnr_ipv4_udp_fd
, IPPROTO_IP
, IP_TTL
, &ttl
, sizeof(ttl
));
136 r
= log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to set IP_TTL: %m");
140 r
= setsockopt(m
->llmnr_ipv4_udp_fd
, IPPROTO_IP
, IP_MULTICAST_TTL
, &ttl
, sizeof(ttl
));
142 r
= log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to set IP_MULTICAST_TTL: %m");
146 r
= setsockopt(m
->llmnr_ipv4_udp_fd
, IPPROTO_IP
, IP_MULTICAST_LOOP
, &one
, sizeof(one
));
148 r
= log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to set IP_MULTICAST_LOOP: %m");
152 r
= setsockopt(m
->llmnr_ipv4_udp_fd
, IPPROTO_IP
, IP_PKTINFO
, &one
, sizeof(one
));
154 r
= log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to set IP_PKTINFO: %m");
158 r
= setsockopt(m
->llmnr_ipv4_udp_fd
, IPPROTO_IP
, IP_RECVTTL
, &one
, sizeof(one
));
160 r
= log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to set IP_RECVTTL: %m");
164 /* Disable Don't-Fragment bit in the IP header */
165 r
= setsockopt(m
->llmnr_ipv4_udp_fd
, IPPROTO_IP
, IP_MTU_DISCOVER
, &pmtu
, sizeof(pmtu
));
167 r
= log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to set IP_MTU_DISCOVER: %m");
171 /* first try to bind without SO_REUSEADDR to detect another LLMNR responder */
172 r
= bind(m
->llmnr_ipv4_udp_fd
, &sa
.sa
, sizeof(sa
.in
));
174 if (errno
!= EADDRINUSE
) {
175 r
= log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to bind socket: %m");
179 log_warning("LLMNR-IPv4(UDP): There appears to be another LLMNR responder running, or previously systemd-resolved crashed with some outstanding transfers.");
181 /* try again with SO_REUSEADDR */
182 r
= setsockopt(m
->llmnr_ipv4_udp_fd
, SOL_SOCKET
, SO_REUSEADDR
, &one
, sizeof(one
));
184 r
= log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to set SO_REUSEADDR: %m");
188 r
= bind(m
->llmnr_ipv4_udp_fd
, &sa
.sa
, sizeof(sa
.in
));
190 r
= 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(m
->llmnr_ipv4_udp_fd
, SOL_SOCKET
, SO_REUSEADDR
, &one
, sizeof(one
));
197 r
= log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to set SO_REUSEADDR: %m");
202 r
= sd_event_add_io(m
->event
, &m
->llmnr_ipv4_udp_event_source
, m
->llmnr_ipv4_udp_fd
, EPOLLIN
, on_llmnr_packet
, m
);
206 (void) sd_event_source_set_description(m
->llmnr_ipv4_udp_event_source
, "llmnr-ipv4-udp");
208 return m
->llmnr_ipv4_udp_fd
;
211 m
->llmnr_ipv4_udp_fd
= safe_close(m
->llmnr_ipv4_udp_fd
);
215 int manager_llmnr_ipv6_udp_fd(Manager
*m
) {
216 union sockaddr_union sa
= {
217 .in6
.sin6_family
= AF_INET6
,
218 .in6
.sin6_port
= htobe16(LLMNR_PORT
),
220 static const int one
= 1, ttl
= 255;
225 if (m
->llmnr_ipv6_udp_fd
>= 0)
226 return m
->llmnr_ipv6_udp_fd
;
228 m
->llmnr_ipv6_udp_fd
= socket(AF_INET6
, SOCK_DGRAM
|SOCK_CLOEXEC
|SOCK_NONBLOCK
, 0);
229 if (m
->llmnr_ipv6_udp_fd
< 0)
230 return log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to create socket: %m");
232 r
= setsockopt(m
->llmnr_ipv6_udp_fd
, IPPROTO_IPV6
, IPV6_UNICAST_HOPS
, &ttl
, sizeof(ttl
));
234 r
= log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to set IPV6_UNICAST_HOPS: %m");
238 /* RFC 4795, section 2.5 recommends setting the TTL of UDP packets to 255. */
239 r
= setsockopt(m
->llmnr_ipv6_udp_fd
, IPPROTO_IPV6
, IPV6_MULTICAST_HOPS
, &ttl
, sizeof(ttl
));
241 r
= log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to set IPV6_MULTICAST_HOPS: %m");
245 r
= setsockopt(m
->llmnr_ipv6_udp_fd
, IPPROTO_IPV6
, IPV6_MULTICAST_LOOP
, &one
, sizeof(one
));
247 r
= log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to set IPV6_MULTICAST_LOOP: %m");
251 r
= setsockopt(m
->llmnr_ipv6_udp_fd
, IPPROTO_IPV6
, IPV6_V6ONLY
, &one
, sizeof(one
));
253 r
= log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to set IPV6_V6ONLY: %m");
257 r
= setsockopt(m
->llmnr_ipv6_udp_fd
, IPPROTO_IPV6
, IPV6_RECVPKTINFO
, &one
, sizeof(one
));
259 r
= log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to set IPV6_RECVPKTINFO: %m");
263 r
= setsockopt(m
->llmnr_ipv6_udp_fd
, IPPROTO_IPV6
, IPV6_RECVHOPLIMIT
, &one
, sizeof(one
));
265 r
= log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to set IPV6_RECVHOPLIMIT: %m");
269 /* first try to bind without SO_REUSEADDR to detect another LLMNR responder */
270 r
= bind(m
->llmnr_ipv6_udp_fd
, &sa
.sa
, sizeof(sa
.in6
));
272 if (errno
!= EADDRINUSE
) {
273 r
= log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to bind socket: %m");
277 log_warning("LLMNR-IPv6(UDP): There appears to be another LLMNR responder running, or previously systemd-resolved crashed with some outstanding transfers.");
279 /* try again with SO_REUSEADDR */
280 r
= setsockopt(m
->llmnr_ipv6_udp_fd
, SOL_SOCKET
, SO_REUSEADDR
, &one
, sizeof(one
));
282 r
= log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to set SO_REUSEADDR: %m");
286 r
= bind(m
->llmnr_ipv6_udp_fd
, &sa
.sa
, sizeof(sa
.in6
));
288 r
= log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to bind socket: %m");
292 /* enable SO_REUSEADDR for the case that the user really wants multiple LLMNR responders */
293 r
= setsockopt(m
->llmnr_ipv6_udp_fd
, SOL_SOCKET
, SO_REUSEADDR
, &one
, sizeof(one
));
295 r
= log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to set SO_REUSEADDR: %m");
300 r
= sd_event_add_io(m
->event
, &m
->llmnr_ipv6_udp_event_source
, m
->llmnr_ipv6_udp_fd
, EPOLLIN
, on_llmnr_packet
, m
);
304 (void) sd_event_source_set_description(m
->llmnr_ipv6_udp_event_source
, "llmnr-ipv6-udp");
306 return m
->llmnr_ipv6_udp_fd
;
309 m
->llmnr_ipv6_udp_fd
= safe_close(m
->llmnr_ipv6_udp_fd
);
313 static int on_llmnr_stream_packet(DnsStream
*s
) {
317 assert(s
->read_packet
);
319 scope
= manager_find_scope(s
->manager
, s
->read_packet
);
321 log_debug("Got LLMNR TCP packet on unknown scope. Ignoring.");
322 else if (dns_packet_validate_query(s
->read_packet
) > 0) {
323 log_debug("Got LLMNR TCP query packet for id %u", DNS_PACKET_ID(s
->read_packet
));
325 dns_scope_process_query(scope
, s
, s
->read_packet
);
327 log_debug("Invalid LLMNR TCP packet, ignoring.");
333 static int on_llmnr_stream(sd_event_source
*s
, int fd
, uint32_t revents
, void *userdata
) {
335 Manager
*m
= userdata
;
338 cfd
= accept4(fd
, NULL
, NULL
, SOCK_NONBLOCK
|SOCK_CLOEXEC
);
340 if (IN_SET(errno
, EAGAIN
, EINTR
))
346 r
= dns_stream_new(m
, &stream
, DNS_PROTOCOL_LLMNR
, cfd
, NULL
);
352 stream
->on_packet
= on_llmnr_stream_packet
;
356 int manager_llmnr_ipv4_tcp_fd(Manager
*m
) {
357 union sockaddr_union sa
= {
358 .in
.sin_family
= AF_INET
,
359 .in
.sin_port
= htobe16(LLMNR_PORT
),
361 static const int one
= 1, pmtu
= IP_PMTUDISC_DONT
;
366 if (m
->llmnr_ipv4_tcp_fd
>= 0)
367 return m
->llmnr_ipv4_tcp_fd
;
369 m
->llmnr_ipv4_tcp_fd
= socket(AF_INET
, SOCK_STREAM
|SOCK_CLOEXEC
|SOCK_NONBLOCK
, 0);
370 if (m
->llmnr_ipv4_tcp_fd
< 0)
371 return log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to create socket: %m");
373 /* RFC 4795, section 2.5. requires setting the TTL of TCP streams to 1 */
374 r
= setsockopt(m
->llmnr_ipv4_tcp_fd
, IPPROTO_IP
, IP_TTL
, &one
, sizeof(one
));
376 r
= log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to set IP_TTL: %m");
380 r
= setsockopt(m
->llmnr_ipv4_tcp_fd
, IPPROTO_IP
, IP_PKTINFO
, &one
, sizeof(one
));
382 r
= log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to set IP_PKTINFO: %m");
386 r
= setsockopt(m
->llmnr_ipv4_tcp_fd
, IPPROTO_IP
, IP_RECVTTL
, &one
, sizeof(one
));
388 r
= log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to set IP_RECVTTL: %m");
392 /* Disable Don't-Fragment bit in the IP header */
393 r
= setsockopt(m
->llmnr_ipv4_tcp_fd
, IPPROTO_IP
, IP_MTU_DISCOVER
, &pmtu
, sizeof(pmtu
));
395 r
= log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to set IP_MTU_DISCOVER: %m");
399 /* first try to bind without SO_REUSEADDR to detect another LLMNR responder */
400 r
= bind(m
->llmnr_ipv4_tcp_fd
, &sa
.sa
, sizeof(sa
.in
));
402 if (errno
!= EADDRINUSE
) {
403 r
= log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to bind socket: %m");
407 log_warning("LLMNR-IPv4(TCP): There appears to be another LLMNR responder running, or previously systemd-resolved crashed with some outstanding transfers.");
409 /* try again with SO_REUSEADDR */
410 r
= setsockopt(m
->llmnr_ipv4_tcp_fd
, SOL_SOCKET
, SO_REUSEADDR
, &one
, sizeof(one
));
412 r
= log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to set SO_REUSEADDR: %m");
416 r
= bind(m
->llmnr_ipv4_tcp_fd
, &sa
.sa
, sizeof(sa
.in
));
418 r
= log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to bind socket: %m");
422 /* enable SO_REUSEADDR for the case that the user really wants multiple LLMNR responders */
423 r
= setsockopt(m
->llmnr_ipv4_tcp_fd
, SOL_SOCKET
, SO_REUSEADDR
, &one
, sizeof(one
));
425 r
= log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to set SO_REUSEADDR: %m");
430 r
= listen(m
->llmnr_ipv4_tcp_fd
, SOMAXCONN
);
432 r
= log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to listen the stream: %m");
436 r
= sd_event_add_io(m
->event
, &m
->llmnr_ipv4_tcp_event_source
, m
->llmnr_ipv4_tcp_fd
, EPOLLIN
, on_llmnr_stream
, m
);
440 (void) sd_event_source_set_description(m
->llmnr_ipv4_tcp_event_source
, "llmnr-ipv4-tcp");
442 return m
->llmnr_ipv4_tcp_fd
;
445 m
->llmnr_ipv4_tcp_fd
= safe_close(m
->llmnr_ipv4_tcp_fd
);
449 int manager_llmnr_ipv6_tcp_fd(Manager
*m
) {
450 union sockaddr_union sa
= {
451 .in6
.sin6_family
= AF_INET6
,
452 .in6
.sin6_port
= htobe16(LLMNR_PORT
),
454 static const int one
= 1;
459 if (m
->llmnr_ipv6_tcp_fd
>= 0)
460 return m
->llmnr_ipv6_tcp_fd
;
462 m
->llmnr_ipv6_tcp_fd
= socket(AF_INET6
, SOCK_STREAM
|SOCK_CLOEXEC
|SOCK_NONBLOCK
, 0);
463 if (m
->llmnr_ipv6_tcp_fd
< 0)
464 return log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to create socket: %m");
466 /* RFC 4795, section 2.5. requires setting the TTL of TCP streams to 1 */
467 r
= setsockopt(m
->llmnr_ipv6_tcp_fd
, IPPROTO_IPV6
, IPV6_UNICAST_HOPS
, &one
, sizeof(one
));
469 r
= log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to set IPV6_UNICAST_HOPS: %m");
473 r
= setsockopt(m
->llmnr_ipv6_tcp_fd
, IPPROTO_IPV6
, IPV6_V6ONLY
, &one
, sizeof(one
));
475 r
= log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to set IPV6_V6ONLY: %m");
479 r
= setsockopt(m
->llmnr_ipv6_tcp_fd
, IPPROTO_IPV6
, IPV6_RECVPKTINFO
, &one
, sizeof(one
));
481 r
= log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to set IPV6_RECVPKTINFO: %m");
485 r
= setsockopt(m
->llmnr_ipv6_tcp_fd
, IPPROTO_IPV6
, IPV6_RECVHOPLIMIT
, &one
, sizeof(one
));
487 r
= log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to set IPV6_RECVHOPLIMIT: %m");
491 /* first try to bind without SO_REUSEADDR to detect another LLMNR responder */
492 r
= bind(m
->llmnr_ipv6_tcp_fd
, &sa
.sa
, sizeof(sa
.in6
));
494 if (errno
!= EADDRINUSE
) {
495 r
= log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to bind socket: %m");
499 log_warning("LLMNR-IPv6(TCP): There appears to be another LLMNR responder running, or previously systemd-resolved crashed with some outstanding transfers.");
501 /* try again with SO_REUSEADDR */
502 r
= setsockopt(m
->llmnr_ipv6_tcp_fd
, SOL_SOCKET
, SO_REUSEADDR
, &one
, sizeof(one
));
504 r
= log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to set SO_REUSEADDR: %m");
508 r
= bind(m
->llmnr_ipv6_tcp_fd
, &sa
.sa
, sizeof(sa
.in6
));
510 r
= log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to bind socket: %m");
514 /* enable SO_REUSEADDR for the case that the user really wants multiple LLMNR responders */
515 r
= setsockopt(m
->llmnr_ipv6_tcp_fd
, SOL_SOCKET
, SO_REUSEADDR
, &one
, sizeof(one
));
517 r
= log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to set SO_REUSEADDR: %m");
522 r
= listen(m
->llmnr_ipv6_tcp_fd
, SOMAXCONN
);
524 r
= log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to listen the stream: %m");
528 r
= sd_event_add_io(m
->event
, &m
->llmnr_ipv6_tcp_event_source
, m
->llmnr_ipv6_tcp_fd
, EPOLLIN
, on_llmnr_stream
, m
);
532 (void) sd_event_source_set_description(m
->llmnr_ipv6_tcp_event_source
, "llmnr-ipv6-tcp");
534 return m
->llmnr_ipv6_tcp_fd
;
537 m
->llmnr_ipv6_tcp_fd
= safe_close(m
->llmnr_ipv6_tcp_fd
);