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_debug("Got LLMNR UDP packet on unknown scope. Ignoring.");
109 if (dns_packet_validate_reply(p
) > 0) {
110 log_debug("Got LLMNR UDP reply packet for id %u", DNS_PACKET_ID(p
));
112 dns_scope_check_conflicts(scope
, p
);
114 t
= hashmap_get(m
->dns_transactions
, UINT_TO_PTR(DNS_PACKET_ID(p
)));
116 dns_transaction_process_reply(t
, p
);
118 } else if (dns_packet_validate_query(p
) > 0) {
119 log_debug("Got LLMNR UDP query packet for id %u", DNS_PACKET_ID(p
));
121 dns_scope_process_query(scope
, NULL
, p
);
123 log_debug("Invalid LLMNR UDP packet, ignoring.");
128 int manager_llmnr_ipv4_udp_fd(Manager
*m
) {
129 union sockaddr_union sa
= {
130 .in
.sin_family
= AF_INET
,
131 .in
.sin_port
= htobe16(LLMNR_PORT
),
133 static const int one
= 1, pmtu
= IP_PMTUDISC_DONT
, ttl
= 255;
138 if (m
->llmnr_ipv4_udp_fd
>= 0)
139 return m
->llmnr_ipv4_udp_fd
;
141 m
->llmnr_ipv4_udp_fd
= socket(AF_INET
, SOCK_DGRAM
|SOCK_CLOEXEC
|SOCK_NONBLOCK
, 0);
142 if (m
->llmnr_ipv4_udp_fd
< 0)
143 return log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to create socket: %m");
145 /* RFC 4795, section 2.5 recommends setting the TTL of UDP packets to 255. */
146 r
= setsockopt(m
->llmnr_ipv4_udp_fd
, IPPROTO_IP
, IP_TTL
, &ttl
, sizeof(ttl
));
148 r
= log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to set IP_TTL: %m");
152 r
= setsockopt(m
->llmnr_ipv4_udp_fd
, IPPROTO_IP
, IP_MULTICAST_TTL
, &ttl
, sizeof(ttl
));
154 r
= log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to set IP_MULTICAST_TTL: %m");
158 r
= setsockopt(m
->llmnr_ipv4_udp_fd
, IPPROTO_IP
, IP_MULTICAST_LOOP
, &one
, sizeof(one
));
160 r
= log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to set IP_MULTICAST_LOOP: %m");
164 r
= setsockopt(m
->llmnr_ipv4_udp_fd
, IPPROTO_IP
, IP_PKTINFO
, &one
, sizeof(one
));
166 r
= log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to set IP_PKTINFO: %m");
170 r
= setsockopt(m
->llmnr_ipv4_udp_fd
, IPPROTO_IP
, IP_RECVTTL
, &one
, sizeof(one
));
172 r
= log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to set IP_RECVTTL: %m");
176 /* Disable Don't-Fragment bit in the IP header */
177 r
= setsockopt(m
->llmnr_ipv4_udp_fd
, IPPROTO_IP
, IP_MTU_DISCOVER
, &pmtu
, sizeof(pmtu
));
179 r
= log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to set IP_MTU_DISCOVER: %m");
183 /* first try to bind without SO_REUSEADDR to detect another LLMNR responder */
184 r
= bind(m
->llmnr_ipv4_udp_fd
, &sa
.sa
, sizeof(sa
.in
));
186 if (errno
!= EADDRINUSE
) {
187 r
= log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to bind socket: %m");
191 log_warning("LLMNR-IPv4(UDP): There appears to be another LLMNR responder running, or previously systemd-resolved crashed with some outstanding transfers.");
193 /* try again with SO_REUSEADDR */
194 r
= setsockopt(m
->llmnr_ipv4_udp_fd
, SOL_SOCKET
, SO_REUSEADDR
, &one
, sizeof(one
));
196 r
= log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to set SO_REUSEADDR: %m");
200 r
= bind(m
->llmnr_ipv4_udp_fd
, &sa
.sa
, sizeof(sa
.in
));
202 r
= log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to bind socket: %m");
206 /* enable SO_REUSEADDR for the case that the user really wants multiple LLMNR responders */
207 r
= setsockopt(m
->llmnr_ipv4_udp_fd
, SOL_SOCKET
, SO_REUSEADDR
, &one
, sizeof(one
));
209 r
= log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to set SO_REUSEADDR: %m");
214 r
= sd_event_add_io(m
->event
, &m
->llmnr_ipv4_udp_event_source
, m
->llmnr_ipv4_udp_fd
, EPOLLIN
, on_llmnr_packet
, m
);
218 (void) sd_event_source_set_description(m
->llmnr_ipv4_udp_event_source
, "llmnr-ipv4-udp");
220 return m
->llmnr_ipv4_udp_fd
;
223 m
->llmnr_ipv4_udp_fd
= safe_close(m
->llmnr_ipv4_udp_fd
);
227 int manager_llmnr_ipv6_udp_fd(Manager
*m
) {
228 union sockaddr_union sa
= {
229 .in6
.sin6_family
= AF_INET6
,
230 .in6
.sin6_port
= htobe16(LLMNR_PORT
),
232 static const int one
= 1, ttl
= 255;
237 if (m
->llmnr_ipv6_udp_fd
>= 0)
238 return m
->llmnr_ipv6_udp_fd
;
240 m
->llmnr_ipv6_udp_fd
= socket(AF_INET6
, SOCK_DGRAM
|SOCK_CLOEXEC
|SOCK_NONBLOCK
, 0);
241 if (m
->llmnr_ipv6_udp_fd
< 0)
242 return log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to create socket: %m");
244 r
= setsockopt(m
->llmnr_ipv6_udp_fd
, IPPROTO_IPV6
, IPV6_UNICAST_HOPS
, &ttl
, sizeof(ttl
));
246 r
= log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to set IPV6_UNICAST_HOPS: %m");
250 /* RFC 4795, section 2.5 recommends setting the TTL of UDP packets to 255. */
251 r
= setsockopt(m
->llmnr_ipv6_udp_fd
, IPPROTO_IPV6
, IPV6_MULTICAST_HOPS
, &ttl
, sizeof(ttl
));
253 r
= log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to set IPV6_MULTICAST_HOPS: %m");
257 r
= setsockopt(m
->llmnr_ipv6_udp_fd
, IPPROTO_IPV6
, IPV6_MULTICAST_LOOP
, &one
, sizeof(one
));
259 r
= log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to set IPV6_MULTICAST_LOOP: %m");
263 r
= setsockopt(m
->llmnr_ipv6_udp_fd
, IPPROTO_IPV6
, IPV6_V6ONLY
, &one
, sizeof(one
));
265 r
= log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to set IPV6_V6ONLY: %m");
269 r
= setsockopt(m
->llmnr_ipv6_udp_fd
, IPPROTO_IPV6
, IPV6_RECVPKTINFO
, &one
, sizeof(one
));
271 r
= log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to set IPV6_RECVPKTINFO: %m");
275 r
= setsockopt(m
->llmnr_ipv6_udp_fd
, IPPROTO_IPV6
, IPV6_RECVHOPLIMIT
, &one
, sizeof(one
));
277 r
= log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to set IPV6_RECVHOPLIMIT: %m");
281 /* first try to bind without SO_REUSEADDR to detect another LLMNR responder */
282 r
= bind(m
->llmnr_ipv6_udp_fd
, &sa
.sa
, sizeof(sa
.in6
));
284 if (errno
!= EADDRINUSE
) {
285 r
= log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to bind socket: %m");
289 log_warning("LLMNR-IPv6(UDP): There appears to be another LLMNR responder running, or previously systemd-resolved crashed with some outstanding transfers.");
291 /* try again with SO_REUSEADDR */
292 r
= setsockopt(m
->llmnr_ipv6_udp_fd
, SOL_SOCKET
, SO_REUSEADDR
, &one
, sizeof(one
));
294 r
= log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to set SO_REUSEADDR: %m");
298 r
= bind(m
->llmnr_ipv6_udp_fd
, &sa
.sa
, sizeof(sa
.in6
));
300 r
= log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to bind socket: %m");
304 /* enable SO_REUSEADDR for the case that the user really wants multiple LLMNR responders */
305 r
= setsockopt(m
->llmnr_ipv6_udp_fd
, SOL_SOCKET
, SO_REUSEADDR
, &one
, sizeof(one
));
307 r
= log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to set SO_REUSEADDR: %m");
312 r
= sd_event_add_io(m
->event
, &m
->llmnr_ipv6_udp_event_source
, m
->llmnr_ipv6_udp_fd
, EPOLLIN
, on_llmnr_packet
, m
);
316 (void) sd_event_source_set_description(m
->llmnr_ipv6_udp_event_source
, "llmnr-ipv6-udp");
318 return m
->llmnr_ipv6_udp_fd
;
321 m
->llmnr_ipv6_udp_fd
= safe_close(m
->llmnr_ipv6_udp_fd
);
325 static int on_llmnr_stream_packet(DnsStream
*s
) {
329 assert(s
->read_packet
);
331 scope
= manager_find_scope(s
->manager
, s
->read_packet
);
333 log_debug("Got LLMNR TCP packet on unknown scope. Ignoring.");
334 else if (dns_packet_validate_query(s
->read_packet
) > 0) {
335 log_debug("Got LLMNR TCP query packet for id %u", DNS_PACKET_ID(s
->read_packet
));
337 dns_scope_process_query(scope
, s
, s
->read_packet
);
339 log_debug("Invalid LLMNR TCP packet, ignoring.");
345 static int on_llmnr_stream(sd_event_source
*s
, int fd
, uint32_t revents
, void *userdata
) {
347 Manager
*m
= userdata
;
350 cfd
= accept4(fd
, NULL
, NULL
, SOCK_NONBLOCK
|SOCK_CLOEXEC
);
352 if (IN_SET(errno
, EAGAIN
, EINTR
))
358 r
= dns_stream_new(m
, &stream
, DNS_PROTOCOL_LLMNR
, cfd
);
364 stream
->on_packet
= on_llmnr_stream_packet
;
368 int manager_llmnr_ipv4_tcp_fd(Manager
*m
) {
369 union sockaddr_union sa
= {
370 .in
.sin_family
= AF_INET
,
371 .in
.sin_port
= htobe16(LLMNR_PORT
),
373 static const int one
= 1, pmtu
= IP_PMTUDISC_DONT
;
378 if (m
->llmnr_ipv4_tcp_fd
>= 0)
379 return m
->llmnr_ipv4_tcp_fd
;
381 m
->llmnr_ipv4_tcp_fd
= socket(AF_INET
, SOCK_STREAM
|SOCK_CLOEXEC
|SOCK_NONBLOCK
, 0);
382 if (m
->llmnr_ipv4_tcp_fd
< 0)
383 return log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to create socket: %m");
385 /* RFC 4795, section 2.5. requires setting the TTL of TCP streams to 1 */
386 r
= setsockopt(m
->llmnr_ipv4_tcp_fd
, IPPROTO_IP
, IP_TTL
, &one
, sizeof(one
));
388 r
= log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to set IP_TTL: %m");
392 r
= setsockopt(m
->llmnr_ipv4_tcp_fd
, IPPROTO_IP
, IP_PKTINFO
, &one
, sizeof(one
));
394 r
= log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to set IP_PKTINFO: %m");
398 r
= setsockopt(m
->llmnr_ipv4_tcp_fd
, IPPROTO_IP
, IP_RECVTTL
, &one
, sizeof(one
));
400 r
= log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to set IP_RECVTTL: %m");
404 /* Disable Don't-Fragment bit in the IP header */
405 r
= setsockopt(m
->llmnr_ipv4_tcp_fd
, IPPROTO_IP
, IP_MTU_DISCOVER
, &pmtu
, sizeof(pmtu
));
407 r
= log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to set IP_MTU_DISCOVER: %m");
411 /* first try to bind without SO_REUSEADDR to detect another LLMNR responder */
412 r
= bind(m
->llmnr_ipv4_tcp_fd
, &sa
.sa
, sizeof(sa
.in
));
414 if (errno
!= EADDRINUSE
) {
415 r
= log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to bind socket: %m");
419 log_warning("LLMNR-IPv4(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(m
->llmnr_ipv4_tcp_fd
, SOL_SOCKET
, SO_REUSEADDR
, &one
, sizeof(one
));
424 r
= log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to set SO_REUSEADDR: %m");
428 r
= bind(m
->llmnr_ipv4_tcp_fd
, &sa
.sa
, sizeof(sa
.in
));
430 r
= log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to bind socket: %m");
434 /* enable SO_REUSEADDR for the case that the user really wants multiple LLMNR responders */
435 r
= setsockopt(m
->llmnr_ipv4_tcp_fd
, SOL_SOCKET
, SO_REUSEADDR
, &one
, sizeof(one
));
437 r
= log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to set SO_REUSEADDR: %m");
442 r
= listen(m
->llmnr_ipv4_tcp_fd
, SOMAXCONN
);
444 r
= log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to listen the stream: %m");
448 r
= sd_event_add_io(m
->event
, &m
->llmnr_ipv4_tcp_event_source
, m
->llmnr_ipv4_tcp_fd
, EPOLLIN
, on_llmnr_stream
, m
);
452 (void) sd_event_source_set_description(m
->llmnr_ipv4_tcp_event_source
, "llmnr-ipv4-tcp");
454 return m
->llmnr_ipv4_tcp_fd
;
457 m
->llmnr_ipv4_tcp_fd
= safe_close(m
->llmnr_ipv4_tcp_fd
);
461 int manager_llmnr_ipv6_tcp_fd(Manager
*m
) {
462 union sockaddr_union sa
= {
463 .in6
.sin6_family
= AF_INET6
,
464 .in6
.sin6_port
= htobe16(LLMNR_PORT
),
466 static const int one
= 1;
471 if (m
->llmnr_ipv6_tcp_fd
>= 0)
472 return m
->llmnr_ipv6_tcp_fd
;
474 m
->llmnr_ipv6_tcp_fd
= socket(AF_INET6
, SOCK_STREAM
|SOCK_CLOEXEC
|SOCK_NONBLOCK
, 0);
475 if (m
->llmnr_ipv6_tcp_fd
< 0)
476 return log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to create socket: %m");
478 /* RFC 4795, section 2.5. requires setting the TTL of TCP streams to 1 */
479 r
= setsockopt(m
->llmnr_ipv6_tcp_fd
, IPPROTO_IPV6
, IPV6_UNICAST_HOPS
, &one
, sizeof(one
));
481 r
= log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to set IPV6_UNICAST_HOPS: %m");
485 r
= setsockopt(m
->llmnr_ipv6_tcp_fd
, IPPROTO_IPV6
, IPV6_V6ONLY
, &one
, sizeof(one
));
487 r
= log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to set IPV6_V6ONLY: %m");
491 r
= setsockopt(m
->llmnr_ipv6_tcp_fd
, IPPROTO_IPV6
, IPV6_RECVPKTINFO
, &one
, sizeof(one
));
493 r
= log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to set IPV6_RECVPKTINFO: %m");
497 r
= setsockopt(m
->llmnr_ipv6_tcp_fd
, IPPROTO_IPV6
, IPV6_RECVHOPLIMIT
, &one
, sizeof(one
));
499 r
= log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to set IPV6_RECVHOPLIMIT: %m");
503 /* first try to bind without SO_REUSEADDR to detect another LLMNR responder */
504 r
= bind(m
->llmnr_ipv6_tcp_fd
, &sa
.sa
, sizeof(sa
.in6
));
506 if (errno
!= EADDRINUSE
) {
507 r
= log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to bind socket: %m");
511 log_warning("LLMNR-IPv6(TCP): There appears to be another LLMNR responder running, or previously systemd-resolved crashed with some outstanding transfers.");
513 /* try again with SO_REUSEADDR */
514 r
= setsockopt(m
->llmnr_ipv6_tcp_fd
, SOL_SOCKET
, SO_REUSEADDR
, &one
, sizeof(one
));
516 r
= log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to set SO_REUSEADDR: %m");
520 r
= bind(m
->llmnr_ipv6_tcp_fd
, &sa
.sa
, sizeof(sa
.in6
));
522 r
= log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to bind socket: %m");
526 /* enable SO_REUSEADDR for the case that the user really wants multiple LLMNR responders */
527 r
= setsockopt(m
->llmnr_ipv6_tcp_fd
, SOL_SOCKET
, SO_REUSEADDR
, &one
, sizeof(one
));
529 r
= log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to set SO_REUSEADDR: %m");
534 r
= listen(m
->llmnr_ipv6_tcp_fd
, SOMAXCONN
);
536 r
= log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to listen the stream: %m");
540 r
= sd_event_add_io(m
->event
, &m
->llmnr_ipv6_tcp_event_source
, m
->llmnr_ipv6_tcp_fd
, EPOLLIN
, on_llmnr_stream
, m
);
544 (void) sd_event_source_set_description(m
->llmnr_ipv6_tcp_event_source
, "llmnr-ipv6-tcp");
546 return m
->llmnr_ipv6_tcp_fd
;
549 m
->llmnr_ipv6_tcp_fd
= safe_close(m
->llmnr_ipv6_tcp_fd
);