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("There appears to be another LLMNR responder running. 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
;
94 r
= manager_recv(m
, fd
, DNS_PROTOCOL_LLMNR
, &p
);
98 scope
= manager_find_scope(m
, p
);
100 log_warning("Got LLMNR UDP packet on unknown scope. Ignoring.");
104 if (dns_packet_validate_reply(p
) > 0) {
105 log_debug("Got LLMNR reply packet for id %u", DNS_PACKET_ID(p
));
107 dns_scope_check_conflicts(scope
, p
);
109 t
= hashmap_get(m
->dns_transactions
, UINT_TO_PTR(DNS_PACKET_ID(p
)));
111 dns_transaction_process_reply(t
, p
);
113 } else if (dns_packet_validate_query(p
) > 0) {
114 log_debug("Got LLMNR query packet for id %u", DNS_PACKET_ID(p
));
116 dns_scope_process_query(scope
, NULL
, p
);
118 log_debug("Invalid LLMNR UDP packet, ignoring.");
123 int manager_llmnr_ipv4_udp_fd(Manager
*m
) {
124 union sockaddr_union sa
= {
125 .in
.sin_family
= AF_INET
,
126 .in
.sin_port
= htobe16(LLMNR_PORT
),
128 static const int one
= 1, pmtu
= IP_PMTUDISC_DONT
, ttl
= 255;
133 if (m
->llmnr_ipv4_udp_fd
>= 0)
134 return m
->llmnr_ipv4_udp_fd
;
136 m
->llmnr_ipv4_udp_fd
= socket(AF_INET
, SOCK_DGRAM
|SOCK_CLOEXEC
|SOCK_NONBLOCK
, 0);
137 if (m
->llmnr_ipv4_udp_fd
< 0)
140 /* RFC 4795, section 2.5 recommends setting the TTL of UDP packets to 255. */
141 r
= setsockopt(m
->llmnr_ipv4_udp_fd
, IPPROTO_IP
, IP_TTL
, &ttl
, sizeof(ttl
));
147 r
= setsockopt(m
->llmnr_ipv4_udp_fd
, IPPROTO_IP
, IP_MULTICAST_TTL
, &ttl
, sizeof(ttl
));
153 r
= setsockopt(m
->llmnr_ipv4_udp_fd
, IPPROTO_IP
, IP_MULTICAST_LOOP
, &one
, sizeof(one
));
159 r
= setsockopt(m
->llmnr_ipv4_udp_fd
, SOL_SOCKET
, SO_REUSEADDR
, &one
, sizeof(one
));
165 r
= setsockopt(m
->llmnr_ipv4_udp_fd
, IPPROTO_IP
, IP_PKTINFO
, &one
, sizeof(one
));
171 r
= setsockopt(m
->llmnr_ipv4_udp_fd
, IPPROTO_IP
, IP_RECVTTL
, &one
, sizeof(one
));
177 /* Disable Don't-Fragment bit in the IP header */
178 r
= setsockopt(m
->llmnr_ipv4_udp_fd
, IPPROTO_IP
, IP_MTU_DISCOVER
, &pmtu
, sizeof(pmtu
));
184 r
= bind(m
->llmnr_ipv4_udp_fd
, &sa
.sa
, sizeof(sa
.in
));
190 r
= sd_event_add_io(m
->event
, &m
->llmnr_ipv4_udp_event_source
, m
->llmnr_ipv4_udp_fd
, EPOLLIN
, on_llmnr_packet
, m
);
194 (void) sd_event_source_set_description(m
->llmnr_ipv4_udp_event_source
, "llmnr-ipv4-udp");
196 return m
->llmnr_ipv4_udp_fd
;
199 m
->llmnr_ipv4_udp_fd
= safe_close(m
->llmnr_ipv4_udp_fd
);
203 int manager_llmnr_ipv6_udp_fd(Manager
*m
) {
204 union sockaddr_union sa
= {
205 .in6
.sin6_family
= AF_INET6
,
206 .in6
.sin6_port
= htobe16(LLMNR_PORT
),
208 static const int one
= 1, ttl
= 255;
213 if (m
->llmnr_ipv6_udp_fd
>= 0)
214 return m
->llmnr_ipv6_udp_fd
;
216 m
->llmnr_ipv6_udp_fd
= socket(AF_INET6
, SOCK_DGRAM
|SOCK_CLOEXEC
|SOCK_NONBLOCK
, 0);
217 if (m
->llmnr_ipv6_udp_fd
< 0)
220 r
= setsockopt(m
->llmnr_ipv6_udp_fd
, IPPROTO_IPV6
, IPV6_UNICAST_HOPS
, &ttl
, sizeof(ttl
));
226 /* RFC 4795, section 2.5 recommends setting the TTL of UDP packets to 255. */
227 r
= setsockopt(m
->llmnr_ipv6_udp_fd
, IPPROTO_IPV6
, IPV6_MULTICAST_HOPS
, &ttl
, sizeof(ttl
));
233 r
= setsockopt(m
->llmnr_ipv6_udp_fd
, IPPROTO_IPV6
, IPV6_MULTICAST_LOOP
, &one
, sizeof(one
));
239 r
= setsockopt(m
->llmnr_ipv6_udp_fd
, IPPROTO_IPV6
, IPV6_V6ONLY
, &one
, sizeof(one
));
245 r
= setsockopt(m
->llmnr_ipv6_udp_fd
, SOL_SOCKET
, SO_REUSEADDR
, &one
, sizeof(one
));
251 r
= setsockopt(m
->llmnr_ipv6_udp_fd
, IPPROTO_IPV6
, IPV6_RECVPKTINFO
, &one
, sizeof(one
));
257 r
= setsockopt(m
->llmnr_ipv6_udp_fd
, IPPROTO_IPV6
, IPV6_RECVHOPLIMIT
, &one
, sizeof(one
));
263 r
= bind(m
->llmnr_ipv6_udp_fd
, &sa
.sa
, sizeof(sa
.in6
));
269 r
= sd_event_add_io(m
->event
, &m
->llmnr_ipv6_udp_event_source
, m
->llmnr_ipv6_udp_fd
, EPOLLIN
, on_llmnr_packet
, m
);
273 (void) sd_event_source_set_description(m
->llmnr_ipv6_udp_event_source
, "llmnr-ipv6-udp");
275 return m
->llmnr_ipv6_udp_fd
;
278 m
->llmnr_ipv6_udp_fd
= safe_close(m
->llmnr_ipv6_udp_fd
);
282 static int on_llmnr_stream_packet(DnsStream
*s
) {
287 scope
= manager_find_scope(s
->manager
, s
->read_packet
);
289 log_warning("Got LLMNR TCP packet on unknown scope. Ignroing.");
293 if (dns_packet_validate_query(s
->read_packet
) > 0) {
294 log_debug("Got query packet for id %u", DNS_PACKET_ID(s
->read_packet
));
296 dns_scope_process_query(scope
, s
, s
->read_packet
);
298 /* If no reply packet was set, we free the stream */
302 log_debug("Invalid LLMNR TCP packet.");
308 static int on_llmnr_stream(sd_event_source
*s
, int fd
, uint32_t revents
, void *userdata
) {
310 Manager
*m
= userdata
;
313 cfd
= accept4(fd
, NULL
, NULL
, SOCK_NONBLOCK
|SOCK_CLOEXEC
);
315 if (errno
== EAGAIN
|| errno
== EINTR
)
321 r
= dns_stream_new(m
, &stream
, DNS_PROTOCOL_LLMNR
, cfd
);
327 stream
->on_packet
= on_llmnr_stream_packet
;
331 int manager_llmnr_ipv4_tcp_fd(Manager
*m
) {
332 union sockaddr_union sa
= {
333 .in
.sin_family
= AF_INET
,
334 .in
.sin_port
= htobe16(LLMNR_PORT
),
336 static const int one
= 1, pmtu
= IP_PMTUDISC_DONT
;
341 if (m
->llmnr_ipv4_tcp_fd
>= 0)
342 return m
->llmnr_ipv4_tcp_fd
;
344 m
->llmnr_ipv4_tcp_fd
= socket(AF_INET
, SOCK_STREAM
|SOCK_CLOEXEC
|SOCK_NONBLOCK
, 0);
345 if (m
->llmnr_ipv4_tcp_fd
< 0)
348 /* RFC 4795, section 2.5. requires setting the TTL of TCP streams to 1 */
349 r
= setsockopt(m
->llmnr_ipv4_tcp_fd
, IPPROTO_IP
, IP_TTL
, &one
, sizeof(one
));
355 r
= setsockopt(m
->llmnr_ipv4_tcp_fd
, SOL_SOCKET
, SO_REUSEADDR
, &one
, sizeof(one
));
361 r
= setsockopt(m
->llmnr_ipv4_tcp_fd
, IPPROTO_IP
, IP_PKTINFO
, &one
, sizeof(one
));
367 r
= setsockopt(m
->llmnr_ipv4_tcp_fd
, IPPROTO_IP
, IP_RECVTTL
, &one
, sizeof(one
));
373 /* Disable Don't-Fragment bit in the IP header */
374 r
= setsockopt(m
->llmnr_ipv4_tcp_fd
, IPPROTO_IP
, IP_MTU_DISCOVER
, &pmtu
, sizeof(pmtu
));
380 r
= bind(m
->llmnr_ipv4_tcp_fd
, &sa
.sa
, sizeof(sa
.in
));
386 r
= listen(m
->llmnr_ipv4_tcp_fd
, SOMAXCONN
);
392 r
= sd_event_add_io(m
->event
, &m
->llmnr_ipv4_tcp_event_source
, m
->llmnr_ipv4_tcp_fd
, EPOLLIN
, on_llmnr_stream
, m
);
396 (void) sd_event_source_set_description(m
->llmnr_ipv4_tcp_event_source
, "llmnr-ipv4-tcp");
398 return m
->llmnr_ipv4_tcp_fd
;
401 m
->llmnr_ipv4_tcp_fd
= safe_close(m
->llmnr_ipv4_tcp_fd
);
405 int manager_llmnr_ipv6_tcp_fd(Manager
*m
) {
406 union sockaddr_union sa
= {
407 .in6
.sin6_family
= AF_INET6
,
408 .in6
.sin6_port
= htobe16(LLMNR_PORT
),
410 static const int one
= 1;
415 if (m
->llmnr_ipv6_tcp_fd
>= 0)
416 return m
->llmnr_ipv6_tcp_fd
;
418 m
->llmnr_ipv6_tcp_fd
= socket(AF_INET6
, SOCK_STREAM
|SOCK_CLOEXEC
|SOCK_NONBLOCK
, 0);
419 if (m
->llmnr_ipv6_tcp_fd
< 0)
422 /* RFC 4795, section 2.5. requires setting the TTL of TCP streams to 1 */
423 r
= setsockopt(m
->llmnr_ipv6_tcp_fd
, IPPROTO_IPV6
, IPV6_UNICAST_HOPS
, &one
, sizeof(one
));
429 r
= setsockopt(m
->llmnr_ipv6_tcp_fd
, IPPROTO_IPV6
, IPV6_V6ONLY
, &one
, sizeof(one
));
435 r
= setsockopt(m
->llmnr_ipv6_tcp_fd
, SOL_SOCKET
, SO_REUSEADDR
, &one
, sizeof(one
));
441 r
= setsockopt(m
->llmnr_ipv6_tcp_fd
, IPPROTO_IPV6
, IPV6_RECVPKTINFO
, &one
, sizeof(one
));
447 r
= setsockopt(m
->llmnr_ipv6_tcp_fd
, IPPROTO_IPV6
, IPV6_RECVHOPLIMIT
, &one
, sizeof(one
));
453 r
= bind(m
->llmnr_ipv6_tcp_fd
, &sa
.sa
, sizeof(sa
.in6
));
459 r
= listen(m
->llmnr_ipv6_tcp_fd
, SOMAXCONN
);
465 r
= sd_event_add_io(m
->event
, &m
->llmnr_ipv6_tcp_event_source
, m
->llmnr_ipv6_tcp_fd
, EPOLLIN
, on_llmnr_stream
, m
);
469 (void) sd_event_source_set_description(m
->llmnr_ipv6_tcp_event_source
, "llmnr-ipv6-tcp");
471 return m
->llmnr_ipv6_tcp_fd
;
474 m
->llmnr_ipv6_tcp_fd
= safe_close(m
->llmnr_ipv6_tcp_fd
);