2 This file is part of systemd.
4 Copyright 2014 Tom Gundersen <teg@jklm.no>
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 #include <netinet/in.h>
24 #include "resolved-llmnr.h"
25 #include "resolved-manager.h"
27 void manager_llmnr_stop(Manager
*m
) {
30 m
->llmnr_ipv4_udp_event_source
= sd_event_source_unref(m
->llmnr_ipv4_udp_event_source
);
31 m
->llmnr_ipv4_udp_fd
= safe_close(m
->llmnr_ipv4_udp_fd
);
33 m
->llmnr_ipv6_udp_event_source
= sd_event_source_unref(m
->llmnr_ipv6_udp_event_source
);
34 m
->llmnr_ipv6_udp_fd
= safe_close(m
->llmnr_ipv6_udp_fd
);
36 m
->llmnr_ipv4_tcp_event_source
= sd_event_source_unref(m
->llmnr_ipv4_tcp_event_source
);
37 m
->llmnr_ipv4_tcp_fd
= safe_close(m
->llmnr_ipv4_tcp_fd
);
39 m
->llmnr_ipv6_tcp_event_source
= sd_event_source_unref(m
->llmnr_ipv6_tcp_event_source
);
40 m
->llmnr_ipv6_tcp_fd
= safe_close(m
->llmnr_ipv6_tcp_fd
);
43 int manager_llmnr_start(Manager
*m
) {
48 if (m
->llmnr_support
== RESOLVE_SUPPORT_NO
)
51 r
= manager_llmnr_ipv4_udp_fd(m
);
57 r
= manager_llmnr_ipv4_tcp_fd(m
);
63 if (socket_ipv6_is_supported()) {
64 r
= manager_llmnr_ipv6_udp_fd(m
);
70 r
= manager_llmnr_ipv6_tcp_fd(m
);
80 log_warning("Another LLMNR responder prohibits binding the socket to the same port. Turning off LLMNR support.");
81 m
->llmnr_support
= RESOLVE_SUPPORT_NO
;
82 manager_llmnr_stop(m
);
87 static int on_llmnr_packet(sd_event_source
*s
, int fd
, uint32_t revents
, void *userdata
) {
88 _cleanup_(dns_packet_unrefp
) DnsPacket
*p
= NULL
;
89 DnsTransaction
*t
= NULL
;
90 Manager
*m
= userdata
;
98 r
= manager_recv(m
, fd
, DNS_PROTOCOL_LLMNR
, &p
);
102 scope
= manager_find_scope(m
, p
);
104 log_warning("Got LLMNR UDP packet on unknown scope. Ignoring.");
105 else if (dns_packet_validate_reply(p
) > 0) {
106 log_debug("Got LLMNR UDP reply packet for id %u", DNS_PACKET_ID(p
));
108 dns_scope_check_conflicts(scope
, p
);
110 t
= hashmap_get(m
->dns_transactions
, UINT_TO_PTR(DNS_PACKET_ID(p
)));
112 dns_transaction_process_reply(t
, p
);
114 } else if (dns_packet_validate_query(p
) > 0) {
115 log_debug("Got LLMNR UDP query packet for id %u", DNS_PACKET_ID(p
));
117 dns_scope_process_query(scope
, NULL
, p
);
119 log_debug("Invalid LLMNR UDP packet, ignoring.");
124 int manager_llmnr_ipv4_udp_fd(Manager
*m
) {
125 union sockaddr_union sa
= {
126 .in
.sin_family
= AF_INET
,
127 .in
.sin_port
= htobe16(LLMNR_PORT
),
129 static const int one
= 1, pmtu
= IP_PMTUDISC_DONT
, ttl
= 255;
134 if (m
->llmnr_ipv4_udp_fd
>= 0)
135 return m
->llmnr_ipv4_udp_fd
;
137 m
->llmnr_ipv4_udp_fd
= socket(AF_INET
, SOCK_DGRAM
|SOCK_CLOEXEC
|SOCK_NONBLOCK
, 0);
138 if (m
->llmnr_ipv4_udp_fd
< 0)
139 return log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to create socket: %m");
141 /* RFC 4795, section 2.5 recommends setting the TTL of UDP packets to 255. */
142 r
= setsockopt(m
->llmnr_ipv4_udp_fd
, IPPROTO_IP
, IP_TTL
, &ttl
, sizeof(ttl
));
144 r
= log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to set IP_TTL: %m");
148 r
= setsockopt(m
->llmnr_ipv4_udp_fd
, IPPROTO_IP
, IP_MULTICAST_TTL
, &ttl
, sizeof(ttl
));
150 r
= log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to set IP_MULTICAST_TTL: %m");
154 r
= setsockopt(m
->llmnr_ipv4_udp_fd
, IPPROTO_IP
, IP_MULTICAST_LOOP
, &one
, sizeof(one
));
156 r
= log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to set IP_MULTICAST_LOOP: %m");
160 r
= setsockopt(m
->llmnr_ipv4_udp_fd
, IPPROTO_IP
, IP_PKTINFO
, &one
, sizeof(one
));
162 r
= log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to set IP_PKTINFO: %m");
166 r
= setsockopt(m
->llmnr_ipv4_udp_fd
, IPPROTO_IP
, IP_RECVTTL
, &one
, sizeof(one
));
168 r
= log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to set IP_RECVTTL: %m");
172 /* Disable Don't-Fragment bit in the IP header */
173 r
= setsockopt(m
->llmnr_ipv4_udp_fd
, IPPROTO_IP
, IP_MTU_DISCOVER
, &pmtu
, sizeof(pmtu
));
175 r
= log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to set IP_MTU_DISCOVER: %m");
179 /* first try to bind without SO_REUSEADDR to detect another LLMNR responder */
180 r
= bind(m
->llmnr_ipv4_udp_fd
, &sa
.sa
, sizeof(sa
.in
));
182 if (errno
!= EADDRINUSE
) {
183 r
= log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to bind socket: %m");
187 log_warning("LLMNR-IPv4(UDP): There appears to be another LLMNR responder running, or previously systemd-resolved crashed with some outstanding transfers.");
189 /* try again with SO_REUSEADDR */
190 r
= setsockopt(m
->llmnr_ipv4_udp_fd
, SOL_SOCKET
, SO_REUSEADDR
, &one
, sizeof(one
));
192 r
= log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to set SO_REUSEADDR: %m");
196 r
= bind(m
->llmnr_ipv4_udp_fd
, &sa
.sa
, sizeof(sa
.in
));
198 r
= log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to bind socket: %m");
202 /* enable SO_REUSEADDR for the case that the user really wants multiple LLMNR responders */
203 r
= setsockopt(m
->llmnr_ipv4_udp_fd
, SOL_SOCKET
, SO_REUSEADDR
, &one
, sizeof(one
));
205 r
= log_error_errno(errno
, "LLMNR-IPv4(UDP): Failed to set SO_REUSEADDR: %m");
210 r
= sd_event_add_io(m
->event
, &m
->llmnr_ipv4_udp_event_source
, m
->llmnr_ipv4_udp_fd
, EPOLLIN
, on_llmnr_packet
, m
);
214 (void) sd_event_source_set_description(m
->llmnr_ipv4_udp_event_source
, "llmnr-ipv4-udp");
216 return m
->llmnr_ipv4_udp_fd
;
219 m
->llmnr_ipv4_udp_fd
= safe_close(m
->llmnr_ipv4_udp_fd
);
223 int manager_llmnr_ipv6_udp_fd(Manager
*m
) {
224 union sockaddr_union sa
= {
225 .in6
.sin6_family
= AF_INET6
,
226 .in6
.sin6_port
= htobe16(LLMNR_PORT
),
228 static const int one
= 1, ttl
= 255;
233 if (m
->llmnr_ipv6_udp_fd
>= 0)
234 return m
->llmnr_ipv6_udp_fd
;
236 m
->llmnr_ipv6_udp_fd
= socket(AF_INET6
, SOCK_DGRAM
|SOCK_CLOEXEC
|SOCK_NONBLOCK
, 0);
237 if (m
->llmnr_ipv6_udp_fd
< 0)
238 return log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to create socket: %m");
240 r
= setsockopt(m
->llmnr_ipv6_udp_fd
, IPPROTO_IPV6
, IPV6_UNICAST_HOPS
, &ttl
, sizeof(ttl
));
242 r
= log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to set IPV6_UNICAST_HOPS: %m");
246 /* RFC 4795, section 2.5 recommends setting the TTL of UDP packets to 255. */
247 r
= setsockopt(m
->llmnr_ipv6_udp_fd
, IPPROTO_IPV6
, IPV6_MULTICAST_HOPS
, &ttl
, sizeof(ttl
));
249 r
= log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to set IPV6_MULTICAST_HOPS: %m");
253 r
= setsockopt(m
->llmnr_ipv6_udp_fd
, IPPROTO_IPV6
, IPV6_MULTICAST_LOOP
, &one
, sizeof(one
));
255 r
= log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to set IPV6_MULTICAST_LOOP: %m");
259 r
= setsockopt(m
->llmnr_ipv6_udp_fd
, IPPROTO_IPV6
, IPV6_V6ONLY
, &one
, sizeof(one
));
261 r
= log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to set IPV6_V6ONLY: %m");
265 r
= setsockopt(m
->llmnr_ipv6_udp_fd
, IPPROTO_IPV6
, IPV6_RECVPKTINFO
, &one
, sizeof(one
));
267 r
= log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to set IPV6_RECVPKTINFO: %m");
271 r
= setsockopt(m
->llmnr_ipv6_udp_fd
, IPPROTO_IPV6
, IPV6_RECVHOPLIMIT
, &one
, sizeof(one
));
273 r
= log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to set IPV6_RECVHOPLIMIT: %m");
277 /* first try to bind without SO_REUSEADDR to detect another LLMNR responder */
278 r
= bind(m
->llmnr_ipv6_udp_fd
, &sa
.sa
, sizeof(sa
.in6
));
280 if (errno
!= EADDRINUSE
) {
281 r
= log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to bind socket: %m");
285 log_warning("LLMNR-IPv6(UDP): There appears to be another LLMNR responder running, or previously systemd-resolved crashed with some outstanding transfers.");
287 /* try again with SO_REUSEADDR */
288 r
= setsockopt(m
->llmnr_ipv6_udp_fd
, SOL_SOCKET
, SO_REUSEADDR
, &one
, sizeof(one
));
290 r
= log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to set SO_REUSEADDR: %m");
294 r
= bind(m
->llmnr_ipv6_udp_fd
, &sa
.sa
, sizeof(sa
.in6
));
296 r
= log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to bind socket: %m");
300 /* enable SO_REUSEADDR for the case that the user really wants multiple LLMNR responders */
301 r
= setsockopt(m
->llmnr_ipv6_udp_fd
, SOL_SOCKET
, SO_REUSEADDR
, &one
, sizeof(one
));
303 r
= log_error_errno(errno
, "LLMNR-IPv6(UDP): Failed to set SO_REUSEADDR: %m");
308 r
= sd_event_add_io(m
->event
, &m
->llmnr_ipv6_udp_event_source
, m
->llmnr_ipv6_udp_fd
, EPOLLIN
, on_llmnr_packet
, m
);
312 (void) sd_event_source_set_description(m
->llmnr_ipv6_udp_event_source
, "llmnr-ipv6-udp");
314 return m
->llmnr_ipv6_udp_fd
;
317 m
->llmnr_ipv6_udp_fd
= safe_close(m
->llmnr_ipv6_udp_fd
);
321 static int on_llmnr_stream_packet(DnsStream
*s
) {
325 assert(s
->read_packet
);
327 scope
= manager_find_scope(s
->manager
, s
->read_packet
);
329 log_warning("Got LLMNR TCP packet on unknown scope. Ignoring.");
330 else if (dns_packet_validate_query(s
->read_packet
) > 0) {
331 log_debug("Got LLMNR TCP query packet for id %u", DNS_PACKET_ID(s
->read_packet
));
333 dns_scope_process_query(scope
, s
, s
->read_packet
);
335 log_debug("Invalid LLMNR TCP packet, ignoring.");
341 static int on_llmnr_stream(sd_event_source
*s
, int fd
, uint32_t revents
, void *userdata
) {
343 Manager
*m
= userdata
;
346 cfd
= accept4(fd
, NULL
, NULL
, SOCK_NONBLOCK
|SOCK_CLOEXEC
);
348 if (IN_SET(errno
, EAGAIN
, EINTR
))
354 r
= dns_stream_new(m
, &stream
, DNS_PROTOCOL_LLMNR
, cfd
);
360 stream
->on_packet
= on_llmnr_stream_packet
;
364 int manager_llmnr_ipv4_tcp_fd(Manager
*m
) {
365 union sockaddr_union sa
= {
366 .in
.sin_family
= AF_INET
,
367 .in
.sin_port
= htobe16(LLMNR_PORT
),
369 static const int one
= 1, pmtu
= IP_PMTUDISC_DONT
;
374 if (m
->llmnr_ipv4_tcp_fd
>= 0)
375 return m
->llmnr_ipv4_tcp_fd
;
377 m
->llmnr_ipv4_tcp_fd
= socket(AF_INET
, SOCK_STREAM
|SOCK_CLOEXEC
|SOCK_NONBLOCK
, 0);
378 if (m
->llmnr_ipv4_tcp_fd
< 0)
379 return log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to create socket: %m");
381 /* RFC 4795, section 2.5. requires setting the TTL of TCP streams to 1 */
382 r
= setsockopt(m
->llmnr_ipv4_tcp_fd
, IPPROTO_IP
, IP_TTL
, &one
, sizeof(one
));
384 r
= log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to set IP_TTL: %m");
388 r
= setsockopt(m
->llmnr_ipv4_tcp_fd
, IPPROTO_IP
, IP_PKTINFO
, &one
, sizeof(one
));
390 r
= log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to set IP_PKTINFO: %m");
394 r
= setsockopt(m
->llmnr_ipv4_tcp_fd
, IPPROTO_IP
, IP_RECVTTL
, &one
, sizeof(one
));
396 r
= log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to set IP_RECVTTL: %m");
400 /* Disable Don't-Fragment bit in the IP header */
401 r
= setsockopt(m
->llmnr_ipv4_tcp_fd
, IPPROTO_IP
, IP_MTU_DISCOVER
, &pmtu
, sizeof(pmtu
));
403 r
= log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to set IP_MTU_DISCOVER: %m");
407 /* first try to bind without SO_REUSEADDR to detect another LLMNR responder */
408 r
= bind(m
->llmnr_ipv4_tcp_fd
, &sa
.sa
, sizeof(sa
.in
));
410 if (errno
!= EADDRINUSE
) {
411 r
= log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to bind socket: %m");
415 log_warning("LLMNR-IPv4(TCP): There appears to be another LLMNR responder running, or previously systemd-resolved crashed with some outstanding transfers.");
417 /* try again with SO_REUSEADDR */
418 r
= setsockopt(m
->llmnr_ipv4_tcp_fd
, SOL_SOCKET
, SO_REUSEADDR
, &one
, sizeof(one
));
420 r
= log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to set SO_REUSEADDR: %m");
424 r
= bind(m
->llmnr_ipv4_tcp_fd
, &sa
.sa
, sizeof(sa
.in
));
426 r
= log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to bind socket: %m");
430 /* enable SO_REUSEADDR for the case that the user really wants multiple LLMNR responders */
431 r
= setsockopt(m
->llmnr_ipv4_tcp_fd
, SOL_SOCKET
, SO_REUSEADDR
, &one
, sizeof(one
));
433 r
= log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to set SO_REUSEADDR: %m");
438 r
= listen(m
->llmnr_ipv4_tcp_fd
, SOMAXCONN
);
440 r
= log_error_errno(errno
, "LLMNR-IPv4(TCP): Failed to listen the stream: %m");
444 r
= sd_event_add_io(m
->event
, &m
->llmnr_ipv4_tcp_event_source
, m
->llmnr_ipv4_tcp_fd
, EPOLLIN
, on_llmnr_stream
, m
);
448 (void) sd_event_source_set_description(m
->llmnr_ipv4_tcp_event_source
, "llmnr-ipv4-tcp");
450 return m
->llmnr_ipv4_tcp_fd
;
453 m
->llmnr_ipv4_tcp_fd
= safe_close(m
->llmnr_ipv4_tcp_fd
);
457 int manager_llmnr_ipv6_tcp_fd(Manager
*m
) {
458 union sockaddr_union sa
= {
459 .in6
.sin6_family
= AF_INET6
,
460 .in6
.sin6_port
= htobe16(LLMNR_PORT
),
462 static const int one
= 1;
467 if (m
->llmnr_ipv6_tcp_fd
>= 0)
468 return m
->llmnr_ipv6_tcp_fd
;
470 m
->llmnr_ipv6_tcp_fd
= socket(AF_INET6
, SOCK_STREAM
|SOCK_CLOEXEC
|SOCK_NONBLOCK
, 0);
471 if (m
->llmnr_ipv6_tcp_fd
< 0)
472 return log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to create socket: %m");
474 /* RFC 4795, section 2.5. requires setting the TTL of TCP streams to 1 */
475 r
= setsockopt(m
->llmnr_ipv6_tcp_fd
, IPPROTO_IPV6
, IPV6_UNICAST_HOPS
, &one
, sizeof(one
));
477 r
= log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to set IPV6_UNICAST_HOPS: %m");
481 r
= setsockopt(m
->llmnr_ipv6_tcp_fd
, IPPROTO_IPV6
, IPV6_V6ONLY
, &one
, sizeof(one
));
483 r
= log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to set IPV6_V6ONLY: %m");
487 r
= setsockopt(m
->llmnr_ipv6_tcp_fd
, IPPROTO_IPV6
, IPV6_RECVPKTINFO
, &one
, sizeof(one
));
489 r
= log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to set IPV6_RECVPKTINFO: %m");
493 r
= setsockopt(m
->llmnr_ipv6_tcp_fd
, IPPROTO_IPV6
, IPV6_RECVHOPLIMIT
, &one
, sizeof(one
));
495 r
= log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to set IPV6_RECVHOPLIMIT: %m");
499 /* first try to bind without SO_REUSEADDR to detect another LLMNR responder */
500 r
= bind(m
->llmnr_ipv6_tcp_fd
, &sa
.sa
, sizeof(sa
.in6
));
502 if (errno
!= EADDRINUSE
) {
503 r
= log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to bind socket: %m");
507 log_warning("LLMNR-IPv6(TCP): There appears to be another LLMNR responder running, or previously systemd-resolved crashed with some outstanding transfers.");
509 /* try again with SO_REUSEADDR */
510 r
= setsockopt(m
->llmnr_ipv6_tcp_fd
, SOL_SOCKET
, SO_REUSEADDR
, &one
, sizeof(one
));
512 r
= log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to set SO_REUSEADDR: %m");
516 r
= bind(m
->llmnr_ipv6_tcp_fd
, &sa
.sa
, sizeof(sa
.in6
));
518 r
= log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to bind socket: %m");
522 /* enable SO_REUSEADDR for the case that the user really wants multiple LLMNR responders */
523 r
= setsockopt(m
->llmnr_ipv6_tcp_fd
, SOL_SOCKET
, SO_REUSEADDR
, &one
, sizeof(one
));
525 r
= log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to set SO_REUSEADDR: %m");
530 r
= listen(m
->llmnr_ipv6_tcp_fd
, SOMAXCONN
);
532 r
= log_error_errno(errno
, "LLMNR-IPv6(TCP): Failed to listen the stream: %m");
536 r
= sd_event_add_io(m
->event
, &m
->llmnr_ipv6_tcp_event_source
, m
->llmnr_ipv6_tcp_fd
, EPOLLIN
, on_llmnr_stream
, m
);
540 (void) sd_event_source_set_description(m
->llmnr_ipv6_tcp_event_source
, "llmnr-ipv6-tcp");
542 return m
->llmnr_ipv6_tcp_fd
;
545 m
->llmnr_ipv6_tcp_fd
= safe_close(m
->llmnr_ipv6_tcp_fd
);