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_PROTOCOL_LLMNR
, cfd
, NULL
);
304 stream
->on_packet
= on_llmnr_stream_packet
;
308 int manager_llmnr_ipv4_tcp_fd(Manager
*m
) {
309 union sockaddr_union sa
= {
310 .in
.sin_family
= AF_INET
,
311 .in
.sin_port
= htobe16(LLMNR_PORT
),
313 _cleanup_close_
int s
= -1;
318 if (m
->llmnr_ipv4_tcp_fd
>= 0)
319 return m
->llmnr_ipv4_tcp_fd
;
321 s
= socket(AF_INET
, SOCK_STREAM
|SOCK_CLOEXEC
|SOCK_NONBLOCK
, 0);
323 return log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to create socket: %m");
325 /* RFC 4795, section 2.5. requires setting the TTL of TCP streams to 1 */
326 r
= setsockopt_int(s
, IPPROTO_IP
, IP_TTL
, true);
328 return log_error_errno(r
, "LLMNR-IPv4(TCP): Failed to set IP_TTL: %m");
330 r
= setsockopt_int(s
, IPPROTO_IP
, IP_PKTINFO
, true);
332 return log_error_errno(r
, "LLMNR-IPv4(TCP): Failed to set IP_PKTINFO: %m");
334 r
= setsockopt_int(s
, IPPROTO_IP
, IP_RECVTTL
, true);
336 return log_error_errno(r
, "LLMNR-IPv4(TCP): Failed to set IP_RECVTTL: %m");
338 /* Disable Don't-Fragment bit in the IP header */
339 r
= setsockopt_int(s
, IPPROTO_IP
, IP_MTU_DISCOVER
, IP_PMTUDISC_DONT
);
341 return log_error_errno(r
, "LLMNR-IPv4(TCP): Failed to set IP_MTU_DISCOVER: %m");
343 /* first try to bind without SO_REUSEADDR to detect another LLMNR responder */
344 r
= bind(s
, &sa
.sa
, sizeof(sa
.in
));
346 if (errno
!= EADDRINUSE
)
347 return log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to bind socket: %m");
349 log_warning("LLMNR-IPv4(TCP): There appears to be another LLMNR responder running, or previously systemd-resolved crashed with some outstanding transfers.");
351 /* try again with SO_REUSEADDR */
352 r
= setsockopt_int(s
, SOL_SOCKET
, SO_REUSEADDR
, true);
354 return log_error_errno(r
, "LLMNR-IPv4(TCP): Failed to set SO_REUSEADDR: %m");
356 r
= bind(s
, &sa
.sa
, sizeof(sa
.in
));
358 return log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to bind socket: %m");
360 /* enable SO_REUSEADDR for the case that the user really wants multiple LLMNR responders */
361 r
= setsockopt_int(s
, SOL_SOCKET
, SO_REUSEADDR
, true);
363 return log_error_errno(r
, "LLMNR-IPv4(TCP): Failed to set SO_REUSEADDR: %m");
366 r
= listen(s
, SOMAXCONN
);
368 return log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to listen the stream: %m");
370 r
= sd_event_add_io(m
->event
, &m
->llmnr_ipv4_tcp_event_source
, s
, EPOLLIN
, on_llmnr_stream
, m
);
372 return log_error_errno(r
, "LLMNR-IPv4(TCP): Failed to create event source: %m");
374 (void) sd_event_source_set_description(m
->llmnr_ipv4_tcp_event_source
, "llmnr-ipv4-tcp");
376 return m
->llmnr_ipv4_tcp_fd
= TAKE_FD(s
);
379 int manager_llmnr_ipv6_tcp_fd(Manager
*m
) {
380 union sockaddr_union sa
= {
381 .in6
.sin6_family
= AF_INET6
,
382 .in6
.sin6_port
= htobe16(LLMNR_PORT
),
384 _cleanup_close_
int s
= -1;
389 if (m
->llmnr_ipv6_tcp_fd
>= 0)
390 return m
->llmnr_ipv6_tcp_fd
;
392 s
= socket(AF_INET6
, SOCK_STREAM
|SOCK_CLOEXEC
|SOCK_NONBLOCK
, 0);
394 return log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to create socket: %m");
396 /* RFC 4795, section 2.5. requires setting the TTL of TCP streams to 1 */
397 r
= setsockopt_int(s
, IPPROTO_IPV6
, IPV6_UNICAST_HOPS
, true);
399 return log_error_errno(r
, "LLMNR-IPv6(TCP): Failed to set IPV6_UNICAST_HOPS: %m");
401 r
= setsockopt_int(s
, IPPROTO_IPV6
, IPV6_V6ONLY
, true);
403 return log_error_errno(r
, "LLMNR-IPv6(TCP): Failed to set IPV6_V6ONLY: %m");
405 r
= setsockopt_int(s
, IPPROTO_IPV6
, IPV6_RECVPKTINFO
, true);
407 return log_error_errno(r
, "LLMNR-IPv6(TCP): Failed to set IPV6_RECVPKTINFO: %m");
409 r
= setsockopt_int(s
, IPPROTO_IPV6
, IPV6_RECVHOPLIMIT
, true);
411 return log_error_errno(r
, "LLMNR-IPv6(TCP): Failed to set IPV6_RECVHOPLIMIT: %m");
413 /* first try to bind without SO_REUSEADDR to detect another LLMNR responder */
414 r
= bind(s
, &sa
.sa
, sizeof(sa
.in6
));
416 if (errno
!= EADDRINUSE
)
417 return log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to bind socket: %m");
419 log_warning("LLMNR-IPv6(TCP): There appears to be another LLMNR responder running, or previously systemd-resolved crashed with some outstanding transfers.");
421 /* try again with SO_REUSEADDR */
422 r
= setsockopt_int(s
, SOL_SOCKET
, SO_REUSEADDR
, true);
424 return log_error_errno(r
, "LLMNR-IPv6(TCP): Failed to set SO_REUSEADDR: %m");
426 r
= bind(s
, &sa
.sa
, sizeof(sa
.in6
));
428 return log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to bind socket: %m");
430 /* enable SO_REUSEADDR for the case that the user really wants multiple LLMNR responders */
431 r
= setsockopt_int(s
, SOL_SOCKET
, SO_REUSEADDR
, true);
433 return log_error_errno(r
, "LLMNR-IPv6(TCP): Failed to set SO_REUSEADDR: %m");
436 r
= listen(s
, SOMAXCONN
);
438 return log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to listen the stream: %m");
440 r
= sd_event_add_io(m
->event
, &m
->llmnr_ipv6_tcp_event_source
, s
, EPOLLIN
, on_llmnr_stream
, m
);
442 return log_error_errno(r
, "LLMNR-IPv6(TCP): Failed to create event source: %m");
444 (void) sd_event_source_set_description(m
->llmnr_ipv6_tcp_event_source
, "llmnr-ipv6-tcp");
446 return m
->llmnr_ipv6_tcp_fd
= TAKE_FD(s
);