chiark / gitweb /
8afaf8db6e6dfe4854705c71eb38a990358047c7
[elogind.git] / src / resolve / resolved-llmnr.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2014 Tom Gundersen <teg@jklm.no>
7
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.
12
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.
17
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/>.
20  ***/
21
22 #include <resolv.h>
23 #include <netinet/in.h>
24
25 #include "resolved-manager.h"
26 #include "resolved-llmnr.h"
27
28 void manager_llmnr_stop(Manager *m) {
29         assert(m);
30
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);
33
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);
36
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);
39
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);
42 }
43
44 int manager_llmnr_start(Manager *m) {
45         int r;
46
47         assert(m);
48
49         if (m->llmnr_support == SUPPORT_NO)
50                 return 0;
51
52         r = manager_llmnr_ipv4_udp_fd(m);
53         if (r == -EADDRINUSE)
54                 goto eaddrinuse;
55         if (r < 0)
56                 return r;
57
58         r = manager_llmnr_ipv4_tcp_fd(m);
59         if (r == -EADDRINUSE)
60                 goto eaddrinuse;
61         if (r < 0)
62                 return r;
63
64         if (socket_ipv6_is_supported()) {
65                 r = manager_llmnr_ipv6_udp_fd(m);
66                 if (r == -EADDRINUSE)
67                         goto eaddrinuse;
68                 if (r < 0)
69                         return r;
70
71                 r = manager_llmnr_ipv6_tcp_fd(m);
72                 if (r == -EADDRINUSE)
73                         goto eaddrinuse;
74                 if (r < 0)
75                         return r;
76         }
77
78         return 0;
79
80 eaddrinuse:
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);
84
85         return 0;
86 }
87
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;
92         DnsScope *scope;
93         int r;
94
95         r = manager_recv(m, fd, DNS_PROTOCOL_LLMNR, &p);
96         if (r <= 0)
97                 return r;
98
99         scope = manager_find_scope(m, p);
100         if (!scope) {
101                 log_warning("Got LLMNR UDP packet on unknown scope. Ignoring.");
102                 return 0;
103         }
104
105         if (dns_packet_validate_reply(p) > 0) {
106                 log_debug("Got LLMNR reply packet for id %u", DNS_PACKET_ID(p));
107
108                 dns_scope_check_conflicts(scope, p);
109
110                 t = hashmap_get(m->dns_transactions, UINT_TO_PTR(DNS_PACKET_ID(p)));
111                 if (t)
112                         dns_transaction_process_reply(t, p);
113
114         } else if (dns_packet_validate_query(p) > 0)  {
115                 log_debug("Got LLMNR query packet for id %u", DNS_PACKET_ID(p));
116
117                 dns_scope_process_query(scope, NULL, p);
118         } else
119                 log_debug("Invalid LLMNR UDP packet.");
120
121         return 0;
122 }
123
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),
128         };
129         static const int one = 1, pmtu = IP_PMTUDISC_DONT, ttl = 255;
130         int r;
131
132         assert(m);
133
134         if (m->llmnr_ipv4_udp_fd >= 0)
135                 return m->llmnr_ipv4_udp_fd;
136
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 -errno;
140
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));
143         if (r < 0) {
144                 r = -errno;
145                 goto fail;
146         }
147
148         r = setsockopt(m->llmnr_ipv4_udp_fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl));
149         if (r < 0) {
150                 r = -errno;
151                 goto fail;
152         }
153
154         r = setsockopt(m->llmnr_ipv4_udp_fd, IPPROTO_IP, IP_MULTICAST_LOOP, &one, sizeof(one));
155         if (r < 0) {
156                 r = -errno;
157                 goto fail;
158         }
159
160         r = setsockopt(m->llmnr_ipv4_udp_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
161         if (r < 0) {
162                 r = -errno;
163                 goto fail;
164         }
165
166         r = setsockopt(m->llmnr_ipv4_udp_fd, IPPROTO_IP, IP_PKTINFO, &one, sizeof(one));
167         if (r < 0) {
168                 r = -errno;
169                 goto fail;
170         }
171
172         r = setsockopt(m->llmnr_ipv4_udp_fd, IPPROTO_IP, IP_RECVTTL, &one, sizeof(one));
173         if (r < 0) {
174                 r = -errno;
175                 goto fail;
176         }
177
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));
180         if (r < 0) {
181                 r = -errno;
182                 goto fail;
183         }
184
185         r = bind(m->llmnr_ipv4_udp_fd, &sa.sa, sizeof(sa.in));
186         if (r < 0) {
187                 r = -errno;
188                 goto fail;
189         }
190
191         r = sd_event_add_io(m->event, &m->llmnr_ipv4_udp_event_source, m->llmnr_ipv4_udp_fd, EPOLLIN, on_llmnr_packet, m);
192         if (r < 0)
193                 goto fail;
194
195         return m->llmnr_ipv4_udp_fd;
196
197 fail:
198         m->llmnr_ipv4_udp_fd = safe_close(m->llmnr_ipv4_udp_fd);
199         return r;
200 }
201
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),
206         };
207         static const int one = 1, ttl = 255;
208         int r;
209
210         assert(m);
211
212         if (m->llmnr_ipv6_udp_fd >= 0)
213                 return m->llmnr_ipv6_udp_fd;
214
215         m->llmnr_ipv6_udp_fd = socket(AF_INET6, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
216         if (m->llmnr_ipv6_udp_fd < 0)
217                 return -errno;
218
219         r = setsockopt(m->llmnr_ipv6_udp_fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl));
220         if (r < 0) {
221                 r = -errno;
222                 goto fail;
223         }
224
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));
227         if (r < 0) {
228                 r = -errno;
229                 goto fail;
230         }
231
232         r = setsockopt(m->llmnr_ipv6_udp_fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &one, sizeof(one));
233         if (r < 0) {
234                 r = -errno;
235                 goto fail;
236         }
237
238         r = setsockopt(m->llmnr_ipv6_udp_fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one));
239         if (r < 0) {
240                 r = -errno;
241                 goto fail;
242         }
243
244         r = setsockopt(m->llmnr_ipv6_udp_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
245         if (r < 0) {
246                 r = -errno;
247                 goto fail;
248         }
249
250         r = setsockopt(m->llmnr_ipv6_udp_fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &one, sizeof(one));
251         if (r < 0) {
252                 r = -errno;
253                 goto fail;
254         }
255
256         r = setsockopt(m->llmnr_ipv6_udp_fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &one, sizeof(one));
257         if (r < 0) {
258                 r = -errno;
259                 goto fail;
260         }
261
262         r = bind(m->llmnr_ipv6_udp_fd, &sa.sa, sizeof(sa.in6));
263         if (r < 0) {
264                 r = -errno;
265                 goto fail;
266         }
267
268         r = sd_event_add_io(m->event, &m->llmnr_ipv6_udp_event_source, m->llmnr_ipv6_udp_fd, EPOLLIN, on_llmnr_packet, m);
269         if (r < 0)  {
270                 r = -errno;
271                 goto fail;
272         }
273
274         return m->llmnr_ipv6_udp_fd;
275
276 fail:
277         m->llmnr_ipv6_udp_fd = safe_close(m->llmnr_ipv6_udp_fd);
278         return r;
279 }
280
281 static int on_llmnr_stream_packet(DnsStream *s) {
282         DnsScope *scope;
283
284         assert(s);
285
286         scope = manager_find_scope(s->manager, s->read_packet);
287         if (!scope) {
288                 log_warning("Got LLMNR TCP packet on unknown scope. Ignroing.");
289                 return 0;
290         }
291
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));
294
295                 dns_scope_process_query(scope, s, s->read_packet);
296
297                 /* If no reply packet was set, we free the stream */
298                 if (s->write_packet)
299                         return 0;
300         } else
301                 log_debug("Invalid LLMNR TCP packet.");
302
303         dns_stream_free(s);
304         return 0;
305 }
306
307 static int on_llmnr_stream(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
308         DnsStream *stream;
309         Manager *m = userdata;
310         int cfd, r;
311
312         cfd = accept4(fd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC);
313         if (cfd < 0) {
314                 if (errno == EAGAIN || errno == EINTR)
315                         return 0;
316
317                 return -errno;
318         }
319
320         r = dns_stream_new(m, &stream, DNS_PROTOCOL_LLMNR, cfd);
321         if (r < 0) {
322                 safe_close(cfd);
323                 return r;
324         }
325
326         stream->on_packet = on_llmnr_stream_packet;
327         return 0;
328 }
329
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),
334         };
335         static const int one = 1, pmtu = IP_PMTUDISC_DONT;
336         int r;
337
338         assert(m);
339
340         if (m->llmnr_ipv4_tcp_fd >= 0)
341                 return m->llmnr_ipv4_tcp_fd;
342
343         m->llmnr_ipv4_tcp_fd = socket(AF_INET, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
344         if (m->llmnr_ipv4_tcp_fd < 0)
345                 return -errno;
346
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));
349         if (r < 0) {
350                 r = -errno;
351                 goto fail;
352         }
353
354         r = setsockopt(m->llmnr_ipv4_tcp_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
355         if (r < 0) {
356                 r = -errno;
357                 goto fail;
358         }
359
360         r = setsockopt(m->llmnr_ipv4_tcp_fd, IPPROTO_IP, IP_PKTINFO, &one, sizeof(one));
361         if (r < 0) {
362                 r = -errno;
363                 goto fail;
364         }
365
366         r = setsockopt(m->llmnr_ipv4_tcp_fd, IPPROTO_IP, IP_RECVTTL, &one, sizeof(one));
367         if (r < 0) {
368                 r = -errno;
369                 goto fail;
370         }
371
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));
374         if (r < 0) {
375                 r = -errno;
376                 goto fail;
377         }
378
379         r = bind(m->llmnr_ipv4_tcp_fd, &sa.sa, sizeof(sa.in));
380         if (r < 0) {
381                 r = -errno;
382                 goto fail;
383         }
384
385         r = listen(m->llmnr_ipv4_tcp_fd, SOMAXCONN);
386         if (r < 0) {
387                 r = -errno;
388                 goto fail;
389         }
390
391         r = sd_event_add_io(m->event, &m->llmnr_ipv4_tcp_event_source, m->llmnr_ipv4_tcp_fd, EPOLLIN, on_llmnr_stream, m);
392         if (r < 0)
393                 goto fail;
394
395         return m->llmnr_ipv4_tcp_fd;
396
397 fail:
398         m->llmnr_ipv4_tcp_fd = safe_close(m->llmnr_ipv4_tcp_fd);
399         return r;
400 }
401
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),
406         };
407         static const int one = 1;
408         int r;
409
410         assert(m);
411
412         if (m->llmnr_ipv6_tcp_fd >= 0)
413                 return m->llmnr_ipv6_tcp_fd;
414
415         m->llmnr_ipv6_tcp_fd = socket(AF_INET6, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
416         if (m->llmnr_ipv6_tcp_fd < 0)
417                 return -errno;
418
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));
421         if (r < 0) {
422                 r = -errno;
423                 goto fail;
424         }
425
426         r = setsockopt(m->llmnr_ipv6_tcp_fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one));
427         if (r < 0) {
428                 r = -errno;
429                 goto fail;
430         }
431
432         r = setsockopt(m->llmnr_ipv6_tcp_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
433         if (r < 0) {
434                 r = -errno;
435                 goto fail;
436         }
437
438         r = setsockopt(m->llmnr_ipv6_tcp_fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &one, sizeof(one));
439         if (r < 0) {
440                 r = -errno;
441                 goto fail;
442         }
443
444         r = setsockopt(m->llmnr_ipv6_tcp_fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &one, sizeof(one));
445         if (r < 0) {
446                 r = -errno;
447                 goto fail;
448         }
449
450         r = bind(m->llmnr_ipv6_tcp_fd, &sa.sa, sizeof(sa.in6));
451         if (r < 0) {
452                 r = -errno;
453                 goto fail;
454         }
455
456         r = listen(m->llmnr_ipv6_tcp_fd, SOMAXCONN);
457         if (r < 0) {
458                 r = -errno;
459                 goto fail;
460         }
461
462         r = sd_event_add_io(m->event, &m->llmnr_ipv6_tcp_event_source, m->llmnr_ipv6_tcp_fd, EPOLLIN, on_llmnr_stream, m);
463         if (r < 0)  {
464                 r = -errno;
465                 goto fail;
466         }
467
468         return m->llmnr_ipv6_tcp_fd;
469
470 fail:
471         m->llmnr_ipv6_tcp_fd = safe_close(m->llmnr_ipv6_tcp_fd);
472         return r;
473 }