1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2014 Tom Gundersen <teg@jklm.no>
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
21 #include <netinet/in.h>
25 #include "resolved-llmnr.h"
26 #include "resolved-manager.h"
28 void manager_llmnr_stop(Manager
*m
) {
31 m
->llmnr_ipv4_udp_event_source
= sd_event_source_unref(m
->llmnr_ipv4_udp_event_source
);
32 m
->llmnr_ipv4_udp_fd
= safe_close(m
->llmnr_ipv4_udp_fd
);
34 m
->llmnr_ipv6_udp_event_source
= sd_event_source_unref(m
->llmnr_ipv6_udp_event_source
);
35 m
->llmnr_ipv6_udp_fd
= safe_close(m
->llmnr_ipv6_udp_fd
);
37 m
->llmnr_ipv4_tcp_event_source
= sd_event_source_unref(m
->llmnr_ipv4_tcp_event_source
);
38 m
->llmnr_ipv4_tcp_fd
= safe_close(m
->llmnr_ipv4_tcp_fd
);
40 m
->llmnr_ipv6_tcp_event_source
= sd_event_source_unref(m
->llmnr_ipv6_tcp_event_source
);
41 m
->llmnr_ipv6_tcp_fd
= safe_close(m
->llmnr_ipv6_tcp_fd
);
44 int manager_llmnr_start(Manager
*m
) {
49 if (m
->llmnr_support
== RESOLVE_SUPPORT_NO
)
52 r
= manager_llmnr_ipv4_udp_fd(m
);
58 r
= manager_llmnr_ipv4_tcp_fd(m
);
64 if (socket_ipv6_is_supported()) {
65 r
= manager_llmnr_ipv6_udp_fd(m
);
71 r
= manager_llmnr_ipv6_tcp_fd(m
);
81 log_warning("Another LLMNR responder prohibits binding the socket to the same port. Turning off LLMNR support.");
82 m
->llmnr_support
= RESOLVE_SUPPORT_NO
;
83 manager_llmnr_stop(m
);
88 static int on_llmnr_packet(sd_event_source
*s
, int fd
, uint32_t revents
, void *userdata
) {
89 _cleanup_(dns_packet_unrefp
) DnsPacket
*p
= NULL
;
90 DnsTransaction
*t
= NULL
;
91 Manager
*m
= userdata
;
99 r
= manager_recv(m
, fd
, DNS_PROTOCOL_LLMNR
, &p
);
103 scope
= manager_find_scope(m
, p
);
105 log_warning("Got LLMNR UDP packet on unknown scope. Ignoring.");
106 else if (dns_packet_validate_reply(p
) > 0) {
107 log_debug("Got LLMNR UDP reply packet for id %u", DNS_PACKET_ID(p
));
109 dns_scope_check_conflicts(scope
, p
);
111 t
= hashmap_get(m
->dns_transactions
, UINT_TO_PTR(DNS_PACKET_ID(p
)));
113 dns_transaction_process_reply(t
, p
);
115 } else if (dns_packet_validate_query(p
) > 0) {
116 log_debug("Got LLMNR UDP query packet for id %u", DNS_PACKET_ID(p
));
118 dns_scope_process_query(scope
, NULL
, p
);
120 log_debug("Invalid LLMNR UDP packet, ignoring.");
125 int manager_llmnr_ipv4_udp_fd(Manager
*m
) {
126 union sockaddr_union sa
= {
127 .in
.sin_family
= AF_INET
,
128 .in
.sin_port
= htobe16(LLMNR_PORT
),
130 static const int one
= 1, pmtu
= IP_PMTUDISC_DONT
, ttl
= 255;
135 if (m
->llmnr_ipv4_udp_fd
>= 0)
136 return m
->llmnr_ipv4_udp_fd
;
138 m
->llmnr_ipv4_udp_fd
= socket(AF_INET
, SOCK_DGRAM
|SOCK_CLOEXEC
|SOCK_NONBLOCK
, 0);
139 if (m
->llmnr_ipv4_udp_fd
< 0)
140 return log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to create socket: %m");
142 /* RFC 4795, section 2.5 recommends setting the TTL of UDP packets to 255. */
143 r
= setsockopt(m
->llmnr_ipv4_udp_fd
, IPPROTO_IP
, IP_TTL
, &ttl
, sizeof(ttl
));
145 r
= log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to set IP_TTL: %m");
149 r
= setsockopt(m
->llmnr_ipv4_udp_fd
, IPPROTO_IP
, IP_MULTICAST_TTL
, &ttl
, sizeof(ttl
));
151 r
= log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to set IP_MULTICAST_TTL: %m");
155 r
= setsockopt(m
->llmnr_ipv4_udp_fd
, IPPROTO_IP
, IP_MULTICAST_LOOP
, &one
, sizeof(one
));
157 r
= log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to set IP_MULTICAST_LOOP: %m");
161 r
= setsockopt(m
->llmnr_ipv4_udp_fd
, IPPROTO_IP
, IP_PKTINFO
, &one
, sizeof(one
));
163 r
= log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to set IP_PKTINFO: %m");
167 r
= setsockopt(m
->llmnr_ipv4_udp_fd
, IPPROTO_IP
, IP_RECVTTL
, &one
, sizeof(one
));
169 r
= log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to set IP_RECVTTL: %m");
173 /* Disable Don't-Fragment bit in the IP header */
174 r
= setsockopt(m
->llmnr_ipv4_udp_fd
, IPPROTO_IP
, IP_MTU_DISCOVER
, &pmtu
, sizeof(pmtu
));
176 r
= log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to set IP_MTU_DISCOVER: %m");
180 /* first try to bind without SO_REUSEADDR to detect another LLMNR responder */
181 r
= bind(m
->llmnr_ipv4_udp_fd
, &sa
.sa
, sizeof(sa
.in
));
183 if (errno
!= EADDRINUSE
) {
184 r
= log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to bind socket: %m");
188 log_warning("LLMNR-IPv4(UDP): There appears to be another LLMNR responder running, or previously systemd-resolved crashed with some outstanding transfers.");
190 /* try again with SO_REUSEADDR */
191 r
= setsockopt(m
->llmnr_ipv4_udp_fd
, SOL_SOCKET
, SO_REUSEADDR
, &one
, sizeof(one
));
193 r
= log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to set SO_REUSEADDR: %m");
197 r
= bind(m
->llmnr_ipv4_udp_fd
, &sa
.sa
, sizeof(sa
.in
));
199 r
= log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to bind socket: %m");
203 /* enable SO_REUSEADDR for the case that the user really wants multiple LLMNR responders */
204 r
= setsockopt(m
->llmnr_ipv4_udp_fd
, SOL_SOCKET
, SO_REUSEADDR
, &one
, sizeof(one
));
206 r
= log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to set SO_REUSEADDR: %m");
211 r
= sd_event_add_io(m
->event
, &m
->llmnr_ipv4_udp_event_source
, m
->llmnr_ipv4_udp_fd
, EPOLLIN
, on_llmnr_packet
, m
);
215 (void) sd_event_source_set_description(m
->llmnr_ipv4_udp_event_source
, "llmnr-ipv4-udp");
217 return m
->llmnr_ipv4_udp_fd
;
220 m
->llmnr_ipv4_udp_fd
= safe_close(m
->llmnr_ipv4_udp_fd
);
224 int manager_llmnr_ipv6_udp_fd(Manager
*m
) {
225 union sockaddr_union sa
= {
226 .in6
.sin6_family
= AF_INET6
,
227 .in6
.sin6_port
= htobe16(LLMNR_PORT
),
229 static const int one
= 1, ttl
= 255;
234 if (m
->llmnr_ipv6_udp_fd
>= 0)
235 return m
->llmnr_ipv6_udp_fd
;
237 m
->llmnr_ipv6_udp_fd
= socket(AF_INET6
, SOCK_DGRAM
|SOCK_CLOEXEC
|SOCK_NONBLOCK
, 0);
238 if (m
->llmnr_ipv6_udp_fd
< 0)
239 return log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to create socket: %m");
241 r
= setsockopt(m
->llmnr_ipv6_udp_fd
, IPPROTO_IPV6
, IPV6_UNICAST_HOPS
, &ttl
, sizeof(ttl
));
243 r
= log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to set IPV6_UNICAST_HOPS: %m");
247 /* RFC 4795, section 2.5 recommends setting the TTL of UDP packets to 255. */
248 r
= setsockopt(m
->llmnr_ipv6_udp_fd
, IPPROTO_IPV6
, IPV6_MULTICAST_HOPS
, &ttl
, sizeof(ttl
));
250 r
= log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to set IPV6_MULTICAST_HOPS: %m");
254 r
= setsockopt(m
->llmnr_ipv6_udp_fd
, IPPROTO_IPV6
, IPV6_MULTICAST_LOOP
, &one
, sizeof(one
));
256 r
= log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to set IPV6_MULTICAST_LOOP: %m");
260 r
= setsockopt(m
->llmnr_ipv6_udp_fd
, IPPROTO_IPV6
, IPV6_V6ONLY
, &one
, sizeof(one
));
262 r
= log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to set IPV6_V6ONLY: %m");
266 r
= setsockopt(m
->llmnr_ipv6_udp_fd
, IPPROTO_IPV6
, IPV6_RECVPKTINFO
, &one
, sizeof(one
));
268 r
= log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to set IPV6_RECVPKTINFO: %m");
272 r
= setsockopt(m
->llmnr_ipv6_udp_fd
, IPPROTO_IPV6
, IPV6_RECVHOPLIMIT
, &one
, sizeof(one
));
274 r
= log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to set IPV6_RECVHOPLIMIT: %m");
278 /* first try to bind without SO_REUSEADDR to detect another LLMNR responder */
279 r
= bind(m
->llmnr_ipv6_udp_fd
, &sa
.sa
, sizeof(sa
.in6
));
281 if (errno
!= EADDRINUSE
) {
282 r
= log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to bind socket: %m");
286 log_warning("LLMNR-IPv6(UDP): There appears to be another LLMNR responder running, or previously systemd-resolved crashed with some outstanding transfers.");
288 /* try again with SO_REUSEADDR */
289 r
= setsockopt(m
->llmnr_ipv6_udp_fd
, SOL_SOCKET
, SO_REUSEADDR
, &one
, sizeof(one
));
291 r
= log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to set SO_REUSEADDR: %m");
295 r
= bind(m
->llmnr_ipv6_udp_fd
, &sa
.sa
, sizeof(sa
.in6
));
297 r
= log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to bind socket: %m");
301 /* enable SO_REUSEADDR for the case that the user really wants multiple LLMNR responders */
302 r
= setsockopt(m
->llmnr_ipv6_udp_fd
, SOL_SOCKET
, SO_REUSEADDR
, &one
, sizeof(one
));
304 r
= log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to set SO_REUSEADDR: %m");
309 r
= sd_event_add_io(m
->event
, &m
->llmnr_ipv6_udp_event_source
, m
->llmnr_ipv6_udp_fd
, EPOLLIN
, on_llmnr_packet
, m
);
313 (void) sd_event_source_set_description(m
->llmnr_ipv6_udp_event_source
, "llmnr-ipv6-udp");
315 return m
->llmnr_ipv6_udp_fd
;
318 m
->llmnr_ipv6_udp_fd
= safe_close(m
->llmnr_ipv6_udp_fd
);
322 static int on_llmnr_stream_packet(DnsStream
*s
) {
326 assert(s
->read_packet
);
328 scope
= manager_find_scope(s
->manager
, s
->read_packet
);
330 log_warning("Got LLMNR TCP packet on unknown scope. Ignoring.");
331 else if (dns_packet_validate_query(s
->read_packet
) > 0) {
332 log_debug("Got LLMNR TCP query packet for id %u", DNS_PACKET_ID(s
->read_packet
));
334 dns_scope_process_query(scope
, s
, s
->read_packet
);
336 log_debug("Invalid LLMNR TCP packet, ignoring.");
342 static int on_llmnr_stream(sd_event_source
*s
, int fd
, uint32_t revents
, void *userdata
) {
344 Manager
*m
= userdata
;
347 cfd
= accept4(fd
, NULL
, NULL
, SOCK_NONBLOCK
|SOCK_CLOEXEC
);
349 if (IN_SET(errno
, EAGAIN
, EINTR
))
355 r
= dns_stream_new(m
, &stream
, DNS_PROTOCOL_LLMNR
, cfd
);
361 stream
->on_packet
= on_llmnr_stream_packet
;
365 int manager_llmnr_ipv4_tcp_fd(Manager
*m
) {
366 union sockaddr_union sa
= {
367 .in
.sin_family
= AF_INET
,
368 .in
.sin_port
= htobe16(LLMNR_PORT
),
370 static const int one
= 1, pmtu
= IP_PMTUDISC_DONT
;
375 if (m
->llmnr_ipv4_tcp_fd
>= 0)
376 return m
->llmnr_ipv4_tcp_fd
;
378 m
->llmnr_ipv4_tcp_fd
= socket(AF_INET
, SOCK_STREAM
|SOCK_CLOEXEC
|SOCK_NONBLOCK
, 0);
379 if (m
->llmnr_ipv4_tcp_fd
< 0)
380 return log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to create socket: %m");
382 /* RFC 4795, section 2.5. requires setting the TTL of TCP streams to 1 */
383 r
= setsockopt(m
->llmnr_ipv4_tcp_fd
, IPPROTO_IP
, IP_TTL
, &one
, sizeof(one
));
385 r
= log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to set IP_TTL: %m");
389 r
= setsockopt(m
->llmnr_ipv4_tcp_fd
, IPPROTO_IP
, IP_PKTINFO
, &one
, sizeof(one
));
391 r
= log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to set IP_PKTINFO: %m");
395 r
= setsockopt(m
->llmnr_ipv4_tcp_fd
, IPPROTO_IP
, IP_RECVTTL
, &one
, sizeof(one
));
397 r
= log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to set IP_RECVTTL: %m");
401 /* Disable Don't-Fragment bit in the IP header */
402 r
= setsockopt(m
->llmnr_ipv4_tcp_fd
, IPPROTO_IP
, IP_MTU_DISCOVER
, &pmtu
, sizeof(pmtu
));
404 r
= log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to set IP_MTU_DISCOVER: %m");
408 /* first try to bind without SO_REUSEADDR to detect another LLMNR responder */
409 r
= bind(m
->llmnr_ipv4_tcp_fd
, &sa
.sa
, sizeof(sa
.in
));
411 if (errno
!= EADDRINUSE
) {
412 r
= log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to bind socket: %m");
416 log_warning("LLMNR-IPv4(TCP): There appears to be another LLMNR responder running, or previously systemd-resolved crashed with some outstanding transfers.");
418 /* try again with SO_REUSEADDR */
419 r
= setsockopt(m
->llmnr_ipv4_tcp_fd
, SOL_SOCKET
, SO_REUSEADDR
, &one
, sizeof(one
));
421 r
= log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to set SO_REUSEADDR: %m");
425 r
= bind(m
->llmnr_ipv4_tcp_fd
, &sa
.sa
, sizeof(sa
.in
));
427 r
= log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to bind socket: %m");
431 /* enable SO_REUSEADDR for the case that the user really wants multiple LLMNR responders */
432 r
= setsockopt(m
->llmnr_ipv4_tcp_fd
, SOL_SOCKET
, SO_REUSEADDR
, &one
, sizeof(one
));
434 r
= log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to set SO_REUSEADDR: %m");
439 r
= listen(m
->llmnr_ipv4_tcp_fd
, SOMAXCONN
);
441 r
= log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to listen the stream: %m");
445 r
= sd_event_add_io(m
->event
, &m
->llmnr_ipv4_tcp_event_source
, m
->llmnr_ipv4_tcp_fd
, EPOLLIN
, on_llmnr_stream
, m
);
449 (void) sd_event_source_set_description(m
->llmnr_ipv4_tcp_event_source
, "llmnr-ipv4-tcp");
451 return m
->llmnr_ipv4_tcp_fd
;
454 m
->llmnr_ipv4_tcp_fd
= safe_close(m
->llmnr_ipv4_tcp_fd
);
458 int manager_llmnr_ipv6_tcp_fd(Manager
*m
) {
459 union sockaddr_union sa
= {
460 .in6
.sin6_family
= AF_INET6
,
461 .in6
.sin6_port
= htobe16(LLMNR_PORT
),
463 static const int one
= 1;
468 if (m
->llmnr_ipv6_tcp_fd
>= 0)
469 return m
->llmnr_ipv6_tcp_fd
;
471 m
->llmnr_ipv6_tcp_fd
= socket(AF_INET6
, SOCK_STREAM
|SOCK_CLOEXEC
|SOCK_NONBLOCK
, 0);
472 if (m
->llmnr_ipv6_tcp_fd
< 0)
473 return log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to create socket: %m");
475 /* RFC 4795, section 2.5. requires setting the TTL of TCP streams to 1 */
476 r
= setsockopt(m
->llmnr_ipv6_tcp_fd
, IPPROTO_IPV6
, IPV6_UNICAST_HOPS
, &one
, sizeof(one
));
478 r
= log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to set IPV6_UNICAST_HOPS: %m");
482 r
= setsockopt(m
->llmnr_ipv6_tcp_fd
, IPPROTO_IPV6
, IPV6_V6ONLY
, &one
, sizeof(one
));
484 r
= log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to set IPV6_V6ONLY: %m");
488 r
= setsockopt(m
->llmnr_ipv6_tcp_fd
, IPPROTO_IPV6
, IPV6_RECVPKTINFO
, &one
, sizeof(one
));
490 r
= log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to set IPV6_RECVPKTINFO: %m");
494 r
= setsockopt(m
->llmnr_ipv6_tcp_fd
, IPPROTO_IPV6
, IPV6_RECVHOPLIMIT
, &one
, sizeof(one
));
496 r
= log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to set IPV6_RECVHOPLIMIT: %m");
500 /* first try to bind without SO_REUSEADDR to detect another LLMNR responder */
501 r
= bind(m
->llmnr_ipv6_tcp_fd
, &sa
.sa
, sizeof(sa
.in6
));
503 if (errno
!= EADDRINUSE
) {
504 r
= log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to bind socket: %m");
508 log_warning("LLMNR-IPv6(TCP): There appears to be another LLMNR responder running, or previously systemd-resolved crashed with some outstanding transfers.");
510 /* try again with SO_REUSEADDR */
511 r
= setsockopt(m
->llmnr_ipv6_tcp_fd
, SOL_SOCKET
, SO_REUSEADDR
, &one
, sizeof(one
));
513 r
= log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to set SO_REUSEADDR: %m");
517 r
= bind(m
->llmnr_ipv6_tcp_fd
, &sa
.sa
, sizeof(sa
.in6
));
519 r
= log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to bind socket: %m");
523 /* enable SO_REUSEADDR for the case that the user really wants multiple LLMNR responders */
524 r
= setsockopt(m
->llmnr_ipv6_tcp_fd
, SOL_SOCKET
, SO_REUSEADDR
, &one
, sizeof(one
));
526 r
= log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to set SO_REUSEADDR: %m");
531 r
= listen(m
->llmnr_ipv6_tcp_fd
, SOMAXCONN
);
533 r
= log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to listen the stream: %m");
537 r
= sd_event_add_io(m
->event
, &m
->llmnr_ipv6_tcp_event_source
, m
->llmnr_ipv6_tcp_fd
, EPOLLIN
, on_llmnr_stream
, m
);
541 (void) sd_event_source_set_description(m
->llmnr_ipv6_tcp_event_source
, "llmnr-ipv6-tcp");
543 return m
->llmnr_ipv6_tcp_fd
;
546 m
->llmnr_ipv6_tcp_fd
= safe_close(m
->llmnr_ipv6_tcp_fd
);