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/>.
23 #include <netinet/in.h>
25 #include "resolved-manager.h"
26 #include "resolved-llmnr.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
== 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("There appears to be another LLMNR responder running. Turning off LLMNR support.");
82 m
->llmnr_support
= 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
;
95 r
= manager_recv(m
, fd
, DNS_PROTOCOL_LLMNR
, &p
);
99 scope
= manager_find_scope(m
, p
);
101 log_warning("Got LLMNR UDP packet on unknown scope. Ignoring.");
105 if (dns_packet_validate_reply(p
) > 0) {
106 log_debug("Got LLMNR 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 query packet for id %u", DNS_PACKET_ID(p
));
117 dns_scope_process_query(scope
, NULL
, p
);
119 log_debug("Invalid LLMNR UDP packet.");
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)
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
));
148 r
= setsockopt(m
->llmnr_ipv4_udp_fd
, IPPROTO_IP
, IP_MULTICAST_TTL
, &ttl
, sizeof(ttl
));
154 r
= setsockopt(m
->llmnr_ipv4_udp_fd
, IPPROTO_IP
, IP_MULTICAST_LOOP
, &one
, sizeof(one
));
160 r
= setsockopt(m
->llmnr_ipv4_udp_fd
, SOL_SOCKET
, SO_REUSEADDR
, &one
, sizeof(one
));
166 r
= setsockopt(m
->llmnr_ipv4_udp_fd
, IPPROTO_IP
, IP_PKTINFO
, &one
, sizeof(one
));
172 r
= setsockopt(m
->llmnr_ipv4_udp_fd
, IPPROTO_IP
, IP_RECVTTL
, &one
, sizeof(one
));
178 /* Disable Don't-Fragment bit in the IP header */
179 r
= setsockopt(m
->llmnr_ipv4_udp_fd
, IPPROTO_IP
, IP_MTU_DISCOVER
, &pmtu
, sizeof(pmtu
));
185 r
= bind(m
->llmnr_ipv4_udp_fd
, &sa
.sa
, sizeof(sa
.in
));
191 r
= sd_event_add_io(m
->event
, &m
->llmnr_ipv4_udp_event_source
, m
->llmnr_ipv4_udp_fd
, EPOLLIN
, on_llmnr_packet
, m
);
195 return m
->llmnr_ipv4_udp_fd
;
198 m
->llmnr_ipv4_udp_fd
= safe_close(m
->llmnr_ipv4_udp_fd
);
202 int manager_llmnr_ipv6_udp_fd(Manager
*m
) {
203 union sockaddr_union sa
= {
204 .in6
.sin6_family
= AF_INET6
,
205 .in6
.sin6_port
= htobe16(LLMNR_PORT
),
207 static const int one
= 1, ttl
= 255;
212 if (m
->llmnr_ipv6_udp_fd
>= 0)
213 return m
->llmnr_ipv6_udp_fd
;
215 m
->llmnr_ipv6_udp_fd
= socket(AF_INET6
, SOCK_DGRAM
|SOCK_CLOEXEC
|SOCK_NONBLOCK
, 0);
216 if (m
->llmnr_ipv6_udp_fd
< 0)
219 r
= setsockopt(m
->llmnr_ipv6_udp_fd
, IPPROTO_IPV6
, IPV6_UNICAST_HOPS
, &ttl
, sizeof(ttl
));
225 /* RFC 4795, section 2.5 recommends setting the TTL of UDP packets to 255. */
226 r
= setsockopt(m
->llmnr_ipv6_udp_fd
, IPPROTO_IPV6
, IPV6_MULTICAST_HOPS
, &ttl
, sizeof(ttl
));
232 r
= setsockopt(m
->llmnr_ipv6_udp_fd
, IPPROTO_IPV6
, IPV6_MULTICAST_LOOP
, &one
, sizeof(one
));
238 r
= setsockopt(m
->llmnr_ipv6_udp_fd
, IPPROTO_IPV6
, IPV6_V6ONLY
, &one
, sizeof(one
));
244 r
= setsockopt(m
->llmnr_ipv6_udp_fd
, SOL_SOCKET
, SO_REUSEADDR
, &one
, sizeof(one
));
250 r
= setsockopt(m
->llmnr_ipv6_udp_fd
, IPPROTO_IPV6
, IPV6_RECVPKTINFO
, &one
, sizeof(one
));
256 r
= setsockopt(m
->llmnr_ipv6_udp_fd
, IPPROTO_IPV6
, IPV6_RECVHOPLIMIT
, &one
, sizeof(one
));
262 r
= bind(m
->llmnr_ipv6_udp_fd
, &sa
.sa
, sizeof(sa
.in6
));
268 r
= sd_event_add_io(m
->event
, &m
->llmnr_ipv6_udp_event_source
, m
->llmnr_ipv6_udp_fd
, EPOLLIN
, on_llmnr_packet
, m
);
274 return m
->llmnr_ipv6_udp_fd
;
277 m
->llmnr_ipv6_udp_fd
= safe_close(m
->llmnr_ipv6_udp_fd
);
281 static int on_llmnr_stream_packet(DnsStream
*s
) {
286 scope
= manager_find_scope(s
->manager
, s
->read_packet
);
288 log_warning("Got LLMNR TCP packet on unknown scope. Ignroing.");
292 if (dns_packet_validate_query(s
->read_packet
) > 0) {
293 log_debug("Got query packet for id %u", DNS_PACKET_ID(s
->read_packet
));
295 dns_scope_process_query(scope
, s
, s
->read_packet
);
297 /* If no reply packet was set, we free the stream */
301 log_debug("Invalid LLMNR TCP packet.");
307 static int on_llmnr_stream(sd_event_source
*s
, int fd
, uint32_t revents
, void *userdata
) {
309 Manager
*m
= userdata
;
312 cfd
= accept4(fd
, NULL
, NULL
, SOCK_NONBLOCK
|SOCK_CLOEXEC
);
314 if (errno
== EAGAIN
|| errno
== EINTR
)
320 r
= dns_stream_new(m
, &stream
, DNS_PROTOCOL_LLMNR
, cfd
);
326 stream
->on_packet
= on_llmnr_stream_packet
;
330 int manager_llmnr_ipv4_tcp_fd(Manager
*m
) {
331 union sockaddr_union sa
= {
332 .in
.sin_family
= AF_INET
,
333 .in
.sin_port
= htobe16(LLMNR_PORT
),
335 static const int one
= 1, pmtu
= IP_PMTUDISC_DONT
;
340 if (m
->llmnr_ipv4_tcp_fd
>= 0)
341 return m
->llmnr_ipv4_tcp_fd
;
343 m
->llmnr_ipv4_tcp_fd
= socket(AF_INET
, SOCK_STREAM
|SOCK_CLOEXEC
|SOCK_NONBLOCK
, 0);
344 if (m
->llmnr_ipv4_tcp_fd
< 0)
347 /* RFC 4795, section 2.5. requires setting the TTL of TCP streams to 1 */
348 r
= setsockopt(m
->llmnr_ipv4_tcp_fd
, IPPROTO_IP
, IP_TTL
, &one
, sizeof(one
));
354 r
= setsockopt(m
->llmnr_ipv4_tcp_fd
, SOL_SOCKET
, SO_REUSEADDR
, &one
, sizeof(one
));
360 r
= setsockopt(m
->llmnr_ipv4_tcp_fd
, IPPROTO_IP
, IP_PKTINFO
, &one
, sizeof(one
));
366 r
= setsockopt(m
->llmnr_ipv4_tcp_fd
, IPPROTO_IP
, IP_RECVTTL
, &one
, sizeof(one
));
372 /* Disable Don't-Fragment bit in the IP header */
373 r
= setsockopt(m
->llmnr_ipv4_tcp_fd
, IPPROTO_IP
, IP_MTU_DISCOVER
, &pmtu
, sizeof(pmtu
));
379 r
= bind(m
->llmnr_ipv4_tcp_fd
, &sa
.sa
, sizeof(sa
.in
));
385 r
= listen(m
->llmnr_ipv4_tcp_fd
, SOMAXCONN
);
391 r
= sd_event_add_io(m
->event
, &m
->llmnr_ipv4_tcp_event_source
, m
->llmnr_ipv4_tcp_fd
, EPOLLIN
, on_llmnr_stream
, m
);
395 return m
->llmnr_ipv4_tcp_fd
;
398 m
->llmnr_ipv4_tcp_fd
= safe_close(m
->llmnr_ipv4_tcp_fd
);
402 int manager_llmnr_ipv6_tcp_fd(Manager
*m
) {
403 union sockaddr_union sa
= {
404 .in6
.sin6_family
= AF_INET6
,
405 .in6
.sin6_port
= htobe16(LLMNR_PORT
),
407 static const int one
= 1;
412 if (m
->llmnr_ipv6_tcp_fd
>= 0)
413 return m
->llmnr_ipv6_tcp_fd
;
415 m
->llmnr_ipv6_tcp_fd
= socket(AF_INET6
, SOCK_STREAM
|SOCK_CLOEXEC
|SOCK_NONBLOCK
, 0);
416 if (m
->llmnr_ipv6_tcp_fd
< 0)
419 /* RFC 4795, section 2.5. requires setting the TTL of TCP streams to 1 */
420 r
= setsockopt(m
->llmnr_ipv6_tcp_fd
, IPPROTO_IPV6
, IPV6_UNICAST_HOPS
, &one
, sizeof(one
));
426 r
= setsockopt(m
->llmnr_ipv6_tcp_fd
, IPPROTO_IPV6
, IPV6_V6ONLY
, &one
, sizeof(one
));
432 r
= setsockopt(m
->llmnr_ipv6_tcp_fd
, SOL_SOCKET
, SO_REUSEADDR
, &one
, sizeof(one
));
438 r
= setsockopt(m
->llmnr_ipv6_tcp_fd
, IPPROTO_IPV6
, IPV6_RECVPKTINFO
, &one
, sizeof(one
));
444 r
= setsockopt(m
->llmnr_ipv6_tcp_fd
, IPPROTO_IPV6
, IPV6_RECVHOPLIMIT
, &one
, sizeof(one
));
450 r
= bind(m
->llmnr_ipv6_tcp_fd
, &sa
.sa
, sizeof(sa
.in6
));
456 r
= listen(m
->llmnr_ipv6_tcp_fd
, SOMAXCONN
);
462 r
= sd_event_add_io(m
->event
, &m
->llmnr_ipv6_tcp_event_source
, m
->llmnr_ipv6_tcp_fd
, EPOLLIN
, on_llmnr_stream
, m
);
468 return m
->llmnr_ipv6_tcp_fd
;
471 m
->llmnr_ipv6_tcp_fd
= safe_close(m
->llmnr_ipv6_tcp_fd
);