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 if (manager_our_packet(m
, p
))
106 scope
= manager_find_scope(m
, p
);
108 log_debug("Got LLMNR UDP packet on unknown scope. Ignoring.");
112 if (dns_packet_validate_reply(p
) > 0) {
113 log_debug("Got LLMNR UDP reply packet for id %u", DNS_PACKET_ID(p
));
115 dns_scope_check_conflicts(scope
, p
);
117 t
= hashmap_get(m
->dns_transactions
, UINT_TO_PTR(DNS_PACKET_ID(p
)));
119 dns_transaction_process_reply(t
, p
);
121 } else if (dns_packet_validate_query(p
) > 0) {
122 log_debug("Got LLMNR UDP query packet for id %u", DNS_PACKET_ID(p
));
124 dns_scope_process_query(scope
, NULL
, p
);
126 log_debug("Invalid LLMNR UDP packet, ignoring.");
131 int manager_llmnr_ipv4_udp_fd(Manager
*m
) {
132 union sockaddr_union sa
= {
133 .in
.sin_family
= AF_INET
,
134 .in
.sin_port
= htobe16(LLMNR_PORT
),
136 static const int one
= 1, pmtu
= IP_PMTUDISC_DONT
, ttl
= 255;
141 if (m
->llmnr_ipv4_udp_fd
>= 0)
142 return m
->llmnr_ipv4_udp_fd
;
144 m
->llmnr_ipv4_udp_fd
= socket(AF_INET
, SOCK_DGRAM
|SOCK_CLOEXEC
|SOCK_NONBLOCK
, 0);
145 if (m
->llmnr_ipv4_udp_fd
< 0)
146 return log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to create socket: %m");
148 /* RFC 4795, section 2.5 recommends setting the TTL of UDP packets to 255. */
149 r
= setsockopt(m
->llmnr_ipv4_udp_fd
, IPPROTO_IP
, IP_TTL
, &ttl
, sizeof(ttl
));
151 r
= log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to set IP_TTL: %m");
155 r
= setsockopt(m
->llmnr_ipv4_udp_fd
, IPPROTO_IP
, IP_MULTICAST_TTL
, &ttl
, sizeof(ttl
));
157 r
= log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to set IP_MULTICAST_TTL: %m");
161 r
= setsockopt(m
->llmnr_ipv4_udp_fd
, IPPROTO_IP
, IP_MULTICAST_LOOP
, &one
, sizeof(one
));
163 r
= log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to set IP_MULTICAST_LOOP: %m");
167 r
= setsockopt(m
->llmnr_ipv4_udp_fd
, IPPROTO_IP
, IP_PKTINFO
, &one
, sizeof(one
));
169 r
= log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to set IP_PKTINFO: %m");
173 r
= setsockopt(m
->llmnr_ipv4_udp_fd
, IPPROTO_IP
, IP_RECVTTL
, &one
, sizeof(one
));
175 r
= log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to set IP_RECVTTL: %m");
179 /* Disable Don't-Fragment bit in the IP header */
180 r
= setsockopt(m
->llmnr_ipv4_udp_fd
, IPPROTO_IP
, IP_MTU_DISCOVER
, &pmtu
, sizeof(pmtu
));
182 r
= log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to set IP_MTU_DISCOVER: %m");
186 /* first try to bind without SO_REUSEADDR to detect another LLMNR responder */
187 r
= bind(m
->llmnr_ipv4_udp_fd
, &sa
.sa
, sizeof(sa
.in
));
189 if (errno
!= EADDRINUSE
) {
190 r
= log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to bind socket: %m");
194 log_warning("LLMNR-IPv4(UDP): There appears to be another LLMNR responder running, or previously systemd-resolved crashed with some outstanding transfers.");
196 /* try again with SO_REUSEADDR */
197 r
= setsockopt(m
->llmnr_ipv4_udp_fd
, SOL_SOCKET
, SO_REUSEADDR
, &one
, sizeof(one
));
199 r
= log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to set SO_REUSEADDR: %m");
203 r
= bind(m
->llmnr_ipv4_udp_fd
, &sa
.sa
, sizeof(sa
.in
));
205 r
= log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to bind socket: %m");
209 /* enable SO_REUSEADDR for the case that the user really wants multiple LLMNR responders */
210 r
= setsockopt(m
->llmnr_ipv4_udp_fd
, SOL_SOCKET
, SO_REUSEADDR
, &one
, sizeof(one
));
212 r
= log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to set SO_REUSEADDR: %m");
217 r
= sd_event_add_io(m
->event
, &m
->llmnr_ipv4_udp_event_source
, m
->llmnr_ipv4_udp_fd
, EPOLLIN
, on_llmnr_packet
, m
);
221 (void) sd_event_source_set_description(m
->llmnr_ipv4_udp_event_source
, "llmnr-ipv4-udp");
223 return m
->llmnr_ipv4_udp_fd
;
226 m
->llmnr_ipv4_udp_fd
= safe_close(m
->llmnr_ipv4_udp_fd
);
230 int manager_llmnr_ipv6_udp_fd(Manager
*m
) {
231 union sockaddr_union sa
= {
232 .in6
.sin6_family
= AF_INET6
,
233 .in6
.sin6_port
= htobe16(LLMNR_PORT
),
235 static const int one
= 1, ttl
= 255;
240 if (m
->llmnr_ipv6_udp_fd
>= 0)
241 return m
->llmnr_ipv6_udp_fd
;
243 m
->llmnr_ipv6_udp_fd
= socket(AF_INET6
, SOCK_DGRAM
|SOCK_CLOEXEC
|SOCK_NONBLOCK
, 0);
244 if (m
->llmnr_ipv6_udp_fd
< 0)
245 return log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to create socket: %m");
247 r
= setsockopt(m
->llmnr_ipv6_udp_fd
, IPPROTO_IPV6
, IPV6_UNICAST_HOPS
, &ttl
, sizeof(ttl
));
249 r
= log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to set IPV6_UNICAST_HOPS: %m");
253 /* RFC 4795, section 2.5 recommends setting the TTL of UDP packets to 255. */
254 r
= setsockopt(m
->llmnr_ipv6_udp_fd
, IPPROTO_IPV6
, IPV6_MULTICAST_HOPS
, &ttl
, sizeof(ttl
));
256 r
= log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to set IPV6_MULTICAST_HOPS: %m");
260 r
= setsockopt(m
->llmnr_ipv6_udp_fd
, IPPROTO_IPV6
, IPV6_MULTICAST_LOOP
, &one
, sizeof(one
));
262 r
= log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to set IPV6_MULTICAST_LOOP: %m");
266 r
= setsockopt(m
->llmnr_ipv6_udp_fd
, IPPROTO_IPV6
, IPV6_V6ONLY
, &one
, sizeof(one
));
268 r
= log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to set IPV6_V6ONLY: %m");
272 r
= setsockopt(m
->llmnr_ipv6_udp_fd
, IPPROTO_IPV6
, IPV6_RECVPKTINFO
, &one
, sizeof(one
));
274 r
= log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to set IPV6_RECVPKTINFO: %m");
278 r
= setsockopt(m
->llmnr_ipv6_udp_fd
, IPPROTO_IPV6
, IPV6_RECVHOPLIMIT
, &one
, sizeof(one
));
280 r
= log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to set IPV6_RECVHOPLIMIT: %m");
284 /* first try to bind without SO_REUSEADDR to detect another LLMNR responder */
285 r
= bind(m
->llmnr_ipv6_udp_fd
, &sa
.sa
, sizeof(sa
.in6
));
287 if (errno
!= EADDRINUSE
) {
288 r
= log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to bind socket: %m");
292 log_warning("LLMNR-IPv6(UDP): There appears to be another LLMNR responder running, or previously systemd-resolved crashed with some outstanding transfers.");
294 /* try again with SO_REUSEADDR */
295 r
= setsockopt(m
->llmnr_ipv6_udp_fd
, SOL_SOCKET
, SO_REUSEADDR
, &one
, sizeof(one
));
297 r
= log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to set SO_REUSEADDR: %m");
301 r
= bind(m
->llmnr_ipv6_udp_fd
, &sa
.sa
, sizeof(sa
.in6
));
303 r
= log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to bind socket: %m");
307 /* enable SO_REUSEADDR for the case that the user really wants multiple LLMNR responders */
308 r
= setsockopt(m
->llmnr_ipv6_udp_fd
, SOL_SOCKET
, SO_REUSEADDR
, &one
, sizeof(one
));
310 r
= log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to set SO_REUSEADDR: %m");
315 r
= sd_event_add_io(m
->event
, &m
->llmnr_ipv6_udp_event_source
, m
->llmnr_ipv6_udp_fd
, EPOLLIN
, on_llmnr_packet
, m
);
319 (void) sd_event_source_set_description(m
->llmnr_ipv6_udp_event_source
, "llmnr-ipv6-udp");
321 return m
->llmnr_ipv6_udp_fd
;
324 m
->llmnr_ipv6_udp_fd
= safe_close(m
->llmnr_ipv6_udp_fd
);
328 static int on_llmnr_stream_packet(DnsStream
*s
) {
332 assert(s
->read_packet
);
334 scope
= manager_find_scope(s
->manager
, s
->read_packet
);
336 log_debug("Got LLMNR TCP packet on unknown scope. Ignoring.");
337 else if (dns_packet_validate_query(s
->read_packet
) > 0) {
338 log_debug("Got LLMNR TCP query packet for id %u", DNS_PACKET_ID(s
->read_packet
));
340 dns_scope_process_query(scope
, s
, s
->read_packet
);
342 log_debug("Invalid LLMNR TCP packet, ignoring.");
348 static int on_llmnr_stream(sd_event_source
*s
, int fd
, uint32_t revents
, void *userdata
) {
350 Manager
*m
= userdata
;
353 cfd
= accept4(fd
, NULL
, NULL
, SOCK_NONBLOCK
|SOCK_CLOEXEC
);
355 if (IN_SET(errno
, EAGAIN
, EINTR
))
361 r
= dns_stream_new(m
, &stream
, DNS_PROTOCOL_LLMNR
, cfd
);
367 stream
->on_packet
= on_llmnr_stream_packet
;
371 int manager_llmnr_ipv4_tcp_fd(Manager
*m
) {
372 union sockaddr_union sa
= {
373 .in
.sin_family
= AF_INET
,
374 .in
.sin_port
= htobe16(LLMNR_PORT
),
376 static const int one
= 1, pmtu
= IP_PMTUDISC_DONT
;
381 if (m
->llmnr_ipv4_tcp_fd
>= 0)
382 return m
->llmnr_ipv4_tcp_fd
;
384 m
->llmnr_ipv4_tcp_fd
= socket(AF_INET
, SOCK_STREAM
|SOCK_CLOEXEC
|SOCK_NONBLOCK
, 0);
385 if (m
->llmnr_ipv4_tcp_fd
< 0)
386 return log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to create socket: %m");
388 /* RFC 4795, section 2.5. requires setting the TTL of TCP streams to 1 */
389 r
= setsockopt(m
->llmnr_ipv4_tcp_fd
, IPPROTO_IP
, IP_TTL
, &one
, sizeof(one
));
391 r
= log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to set IP_TTL: %m");
395 r
= setsockopt(m
->llmnr_ipv4_tcp_fd
, IPPROTO_IP
, IP_PKTINFO
, &one
, sizeof(one
));
397 r
= log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to set IP_PKTINFO: %m");
401 r
= setsockopt(m
->llmnr_ipv4_tcp_fd
, IPPROTO_IP
, IP_RECVTTL
, &one
, sizeof(one
));
403 r
= log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to set IP_RECVTTL: %m");
407 /* Disable Don't-Fragment bit in the IP header */
408 r
= setsockopt(m
->llmnr_ipv4_tcp_fd
, IPPROTO_IP
, IP_MTU_DISCOVER
, &pmtu
, sizeof(pmtu
));
410 r
= log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to set IP_MTU_DISCOVER: %m");
414 /* first try to bind without SO_REUSEADDR to detect another LLMNR responder */
415 r
= bind(m
->llmnr_ipv4_tcp_fd
, &sa
.sa
, sizeof(sa
.in
));
417 if (errno
!= EADDRINUSE
) {
418 r
= log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to bind socket: %m");
422 log_warning("LLMNR-IPv4(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(m
->llmnr_ipv4_tcp_fd
, SOL_SOCKET
, SO_REUSEADDR
, &one
, sizeof(one
));
427 r
= log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to set SO_REUSEADDR: %m");
431 r
= bind(m
->llmnr_ipv4_tcp_fd
, &sa
.sa
, sizeof(sa
.in
));
433 r
= log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to bind socket: %m");
437 /* enable SO_REUSEADDR for the case that the user really wants multiple LLMNR responders */
438 r
= setsockopt(m
->llmnr_ipv4_tcp_fd
, SOL_SOCKET
, SO_REUSEADDR
, &one
, sizeof(one
));
440 r
= log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to set SO_REUSEADDR: %m");
445 r
= listen(m
->llmnr_ipv4_tcp_fd
, SOMAXCONN
);
447 r
= log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to listen the stream: %m");
451 r
= sd_event_add_io(m
->event
, &m
->llmnr_ipv4_tcp_event_source
, m
->llmnr_ipv4_tcp_fd
, EPOLLIN
, on_llmnr_stream
, m
);
455 (void) sd_event_source_set_description(m
->llmnr_ipv4_tcp_event_source
, "llmnr-ipv4-tcp");
457 return m
->llmnr_ipv4_tcp_fd
;
460 m
->llmnr_ipv4_tcp_fd
= safe_close(m
->llmnr_ipv4_tcp_fd
);
464 int manager_llmnr_ipv6_tcp_fd(Manager
*m
) {
465 union sockaddr_union sa
= {
466 .in6
.sin6_family
= AF_INET6
,
467 .in6
.sin6_port
= htobe16(LLMNR_PORT
),
469 static const int one
= 1;
474 if (m
->llmnr_ipv6_tcp_fd
>= 0)
475 return m
->llmnr_ipv6_tcp_fd
;
477 m
->llmnr_ipv6_tcp_fd
= socket(AF_INET6
, SOCK_STREAM
|SOCK_CLOEXEC
|SOCK_NONBLOCK
, 0);
478 if (m
->llmnr_ipv6_tcp_fd
< 0)
479 return log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to create socket: %m");
481 /* RFC 4795, section 2.5. requires setting the TTL of TCP streams to 1 */
482 r
= setsockopt(m
->llmnr_ipv6_tcp_fd
, IPPROTO_IPV6
, IPV6_UNICAST_HOPS
, &one
, sizeof(one
));
484 r
= log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to set IPV6_UNICAST_HOPS: %m");
488 r
= setsockopt(m
->llmnr_ipv6_tcp_fd
, IPPROTO_IPV6
, IPV6_V6ONLY
, &one
, sizeof(one
));
490 r
= log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to set IPV6_V6ONLY: %m");
494 r
= setsockopt(m
->llmnr_ipv6_tcp_fd
, IPPROTO_IPV6
, IPV6_RECVPKTINFO
, &one
, sizeof(one
));
496 r
= log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to set IPV6_RECVPKTINFO: %m");
500 r
= setsockopt(m
->llmnr_ipv6_tcp_fd
, IPPROTO_IPV6
, IPV6_RECVHOPLIMIT
, &one
, sizeof(one
));
502 r
= log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to set IPV6_RECVHOPLIMIT: %m");
506 /* first try to bind without SO_REUSEADDR to detect another LLMNR responder */
507 r
= bind(m
->llmnr_ipv6_tcp_fd
, &sa
.sa
, sizeof(sa
.in6
));
509 if (errno
!= EADDRINUSE
) {
510 r
= log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to bind socket: %m");
514 log_warning("LLMNR-IPv6(TCP): There appears to be another LLMNR responder running, or previously systemd-resolved crashed with some outstanding transfers.");
516 /* try again with SO_REUSEADDR */
517 r
= setsockopt(m
->llmnr_ipv6_tcp_fd
, SOL_SOCKET
, SO_REUSEADDR
, &one
, sizeof(one
));
519 r
= log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to set SO_REUSEADDR: %m");
523 r
= bind(m
->llmnr_ipv6_tcp_fd
, &sa
.sa
, sizeof(sa
.in6
));
525 r
= log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to bind socket: %m");
529 /* enable SO_REUSEADDR for the case that the user really wants multiple LLMNR responders */
530 r
= setsockopt(m
->llmnr_ipv6_tcp_fd
, SOL_SOCKET
, SO_REUSEADDR
, &one
, sizeof(one
));
532 r
= log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to set SO_REUSEADDR: %m");
537 r
= listen(m
->llmnr_ipv6_tcp_fd
, SOMAXCONN
);
539 r
= log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to listen the stream: %m");
543 r
= sd_event_add_io(m
->event
, &m
->llmnr_ipv6_tcp_event_source
, m
->llmnr_ipv6_tcp_fd
, EPOLLIN
, on_llmnr_stream
, m
);
547 (void) sd_event_source_set_description(m
->llmnr_ipv6_tcp_event_source
, "llmnr-ipv6-tcp");
549 return m
->llmnr_ipv6_tcp_fd
;
552 m
->llmnr_ipv6_tcp_fd
= safe_close(m
->llmnr_ipv6_tcp_fd
);