1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2014 Tom Gundersen <teg@jklm.no>
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
22 #include <netinet/in.h>
26 #include "resolved-llmnr.h"
27 #include "resolved-manager.h"
29 void manager_llmnr_stop(Manager
*m
) {
32 m
->llmnr_ipv4_udp_event_source
= sd_event_source_unref(m
->llmnr_ipv4_udp_event_source
);
33 m
->llmnr_ipv4_udp_fd
= safe_close(m
->llmnr_ipv4_udp_fd
);
35 m
->llmnr_ipv6_udp_event_source
= sd_event_source_unref(m
->llmnr_ipv6_udp_event_source
);
36 m
->llmnr_ipv6_udp_fd
= safe_close(m
->llmnr_ipv6_udp_fd
);
38 m
->llmnr_ipv4_tcp_event_source
= sd_event_source_unref(m
->llmnr_ipv4_tcp_event_source
);
39 m
->llmnr_ipv4_tcp_fd
= safe_close(m
->llmnr_ipv4_tcp_fd
);
41 m
->llmnr_ipv6_tcp_event_source
= sd_event_source_unref(m
->llmnr_ipv6_tcp_event_source
);
42 m
->llmnr_ipv6_tcp_fd
= safe_close(m
->llmnr_ipv6_tcp_fd
);
45 int manager_llmnr_start(Manager
*m
) {
50 if (m
->llmnr_support
== SUPPORT_NO
)
53 r
= manager_llmnr_ipv4_udp_fd(m
);
59 r
= manager_llmnr_ipv4_tcp_fd(m
);
65 if (socket_ipv6_is_supported()) {
66 r
= manager_llmnr_ipv6_udp_fd(m
);
72 r
= manager_llmnr_ipv6_tcp_fd(m
);
82 log_warning("There appears to be another LLMNR responder running. Turning off LLMNR support.");
83 m
->llmnr_support
= SUPPORT_NO
;
84 manager_llmnr_stop(m
);
89 static int on_llmnr_packet(sd_event_source
*s
, int fd
, uint32_t revents
, void *userdata
) {
90 _cleanup_(dns_packet_unrefp
) DnsPacket
*p
= NULL
;
91 DnsTransaction
*t
= NULL
;
92 Manager
*m
= userdata
;
96 r
= manager_recv(m
, fd
, DNS_PROTOCOL_LLMNR
, &p
);
100 scope
= manager_find_scope(m
, p
);
102 log_warning("Got LLMNR UDP packet on unknown scope. Ignoring.");
106 if (dns_packet_validate_reply(p
) > 0) {
107 log_debug("Got LLMNR 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 query packet for id %u", DNS_PACKET_ID(p
));
118 dns_scope_process_query(scope
, NULL
, p
);
120 log_debug("Invalid LLMNR UDP packet.");
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)
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
));
149 r
= setsockopt(m
->llmnr_ipv4_udp_fd
, IPPROTO_IP
, IP_MULTICAST_TTL
, &ttl
, sizeof(ttl
));
155 r
= setsockopt(m
->llmnr_ipv4_udp_fd
, IPPROTO_IP
, IP_MULTICAST_LOOP
, &one
, sizeof(one
));
161 r
= setsockopt(m
->llmnr_ipv4_udp_fd
, SOL_SOCKET
, SO_REUSEADDR
, &one
, sizeof(one
));
167 r
= setsockopt(m
->llmnr_ipv4_udp_fd
, IPPROTO_IP
, IP_PKTINFO
, &one
, sizeof(one
));
173 r
= setsockopt(m
->llmnr_ipv4_udp_fd
, IPPROTO_IP
, IP_RECVTTL
, &one
, sizeof(one
));
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
));
186 r
= bind(m
->llmnr_ipv4_udp_fd
, &sa
.sa
, sizeof(sa
.in
));
192 r
= sd_event_add_io(m
->event
, &m
->llmnr_ipv4_udp_event_source
, m
->llmnr_ipv4_udp_fd
, EPOLLIN
, on_llmnr_packet
, m
);
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
);
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 return m
->llmnr_ipv4_tcp_fd
;
399 m
->llmnr_ipv4_tcp_fd
= safe_close(m
->llmnr_ipv4_tcp_fd
);
403 int manager_llmnr_ipv6_tcp_fd(Manager
*m
) {
404 union sockaddr_union sa
= {
405 .in6
.sin6_family
= AF_INET6
,
406 .in6
.sin6_port
= htobe16(LLMNR_PORT
),
408 static const int one
= 1;
413 if (m
->llmnr_ipv6_tcp_fd
>= 0)
414 return m
->llmnr_ipv6_tcp_fd
;
416 m
->llmnr_ipv6_tcp_fd
= socket(AF_INET6
, SOCK_STREAM
|SOCK_CLOEXEC
|SOCK_NONBLOCK
, 0);
417 if (m
->llmnr_ipv6_tcp_fd
< 0)
420 /* RFC 4795, section 2.5. requires setting the TTL of TCP streams to 1 */
421 r
= setsockopt(m
->llmnr_ipv6_tcp_fd
, IPPROTO_IPV6
, IPV6_UNICAST_HOPS
, &one
, sizeof(one
));
427 r
= setsockopt(m
->llmnr_ipv6_tcp_fd
, IPPROTO_IPV6
, IPV6_V6ONLY
, &one
, sizeof(one
));
433 r
= setsockopt(m
->llmnr_ipv6_tcp_fd
, SOL_SOCKET
, SO_REUSEADDR
, &one
, sizeof(one
));
439 r
= setsockopt(m
->llmnr_ipv6_tcp_fd
, IPPROTO_IPV6
, IPV6_RECVPKTINFO
, &one
, sizeof(one
));
445 r
= setsockopt(m
->llmnr_ipv6_tcp_fd
, IPPROTO_IPV6
, IPV6_RECVHOPLIMIT
, &one
, sizeof(one
));
451 r
= bind(m
->llmnr_ipv6_tcp_fd
, &sa
.sa
, sizeof(sa
.in6
));
457 r
= listen(m
->llmnr_ipv6_tcp_fd
, SOMAXCONN
);
463 r
= sd_event_add_io(m
->event
, &m
->llmnr_ipv6_tcp_event_source
, m
->llmnr_ipv6_tcp_fd
, EPOLLIN
, on_llmnr_stream
, m
);
467 return m
->llmnr_ipv6_tcp_fd
;
470 m
->llmnr_ipv6_tcp_fd
= safe_close(m
->llmnr_ipv6_tcp_fd
);