]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/resolve/resolved-manager.c
resolved: add code to join/leave mDNS multicast groups
[thirdparty/systemd.git] / src / resolve / resolved-manager.c
CommitLineData
091a364c
TG
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
07630cea
LP
22#include <netinet/in.h>
23#include <poll.h>
74b2466e 24#include <sys/ioctl.h>
091a364c 25
a2a416f7 26#include "af-list.h"
b5efdb8a 27#include "alloc-util.h"
07630cea 28#include "dns-domain.h"
3ffd4af2 29#include "fd-util.h"
a5a807e6 30#include "fileio-label.h"
07630cea 31#include "hostname-util.h"
c004493c 32#include "io-util.h"
07630cea
LP
33#include "netlink-util.h"
34#include "network-internal.h"
822db23c 35#include "ordered-set.h"
6bedfcbb 36#include "parse-util.h"
3df3e884 37#include "random-util.h"
39d8db04 38#include "resolved-bus.h"
07630cea 39#include "resolved-conf.h"
5f402ae8 40#include "resolved-llmnr.h"
07630cea 41#include "resolved-manager.h"
f8dc7e34 42#include "resolved-resolv-conf.h"
bc7702b0 43#include "resolved-mdns.h"
07630cea 44#include "socket-util.h"
8b43440b 45#include "string-table.h"
07630cea
LP
46#include "string-util.h"
47#include "utf8.h"
74b2466e
LP
48
49#define SEND_TIMEOUT_USEC (200 * USEC_PER_MSEC)
50
1c4baffc 51static int manager_process_link(sd_netlink *rtnl, sd_netlink_message *mm, void *userdata) {
74b2466e
LP
52 Manager *m = userdata;
53 uint16_t type;
54 Link *l;
55 int ifindex, r;
56
57 assert(rtnl);
58 assert(m);
59 assert(mm);
60
1c4baffc 61 r = sd_netlink_message_get_type(mm, &type);
74b2466e
LP
62 if (r < 0)
63 goto fail;
64
65 r = sd_rtnl_message_link_get_ifindex(mm, &ifindex);
66 if (r < 0)
67 goto fail;
68
69 l = hashmap_get(m->links, INT_TO_PTR(ifindex));
70
71 switch (type) {
72
a2a416f7
LP
73 case RTM_NEWLINK:{
74 bool is_new = !l;
74b2466e 75
a2a416f7 76 if (!l) {
74b2466e
LP
77 r = link_new(m, &l, ifindex);
78 if (r < 0)
79 goto fail;
80 }
81
82 r = link_update_rtnl(l, mm);
83 if (r < 0)
84 goto fail;
85
21d73c87
LP
86 r = link_update_monitor(l);
87 if (r < 0)
88 goto fail;
89
a2a416f7
LP
90 if (is_new)
91 log_debug("Found new link %i/%s", ifindex, l->name);
92
74b2466e 93 break;
a2a416f7 94 }
74b2466e
LP
95
96 case RTM_DELLINK:
97 if (l) {
a2a416f7 98 log_debug("Removing link %i/%s", l->ifindex, l->name);
74b2466e
LP
99 link_free(l);
100 }
101
102 break;
103 }
104
105 return 0;
106
107fail:
da927ba9 108 log_warning_errno(r, "Failed to process RTNL link message: %m");
74b2466e
LP
109 return 0;
110}
111
1c4baffc 112static int manager_process_address(sd_netlink *rtnl, sd_netlink_message *mm, void *userdata) {
74b2466e
LP
113 Manager *m = userdata;
114 union in_addr_union address;
74b2466e 115 uint16_t type;
0dd25fb9 116 int r, ifindex, family;
74b2466e
LP
117 LinkAddress *a;
118 Link *l;
119
120 assert(rtnl);
121 assert(mm);
122 assert(m);
123
1c4baffc 124 r = sd_netlink_message_get_type(mm, &type);
74b2466e
LP
125 if (r < 0)
126 goto fail;
127
128 r = sd_rtnl_message_addr_get_ifindex(mm, &ifindex);
129 if (r < 0)
130 goto fail;
131
132 l = hashmap_get(m->links, INT_TO_PTR(ifindex));
133 if (!l)
134 return 0;
135
136 r = sd_rtnl_message_addr_get_family(mm, &family);
137 if (r < 0)
138 goto fail;
139
140 switch (family) {
141
142 case AF_INET:
1c4baffc 143 r = sd_netlink_message_read_in_addr(mm, IFA_LOCAL, &address.in);
74b2466e 144 if (r < 0) {
1c4baffc 145 r = sd_netlink_message_read_in_addr(mm, IFA_ADDRESS, &address.in);
74b2466e
LP
146 if (r < 0)
147 goto fail;
148 }
149
150 break;
151
152 case AF_INET6:
1c4baffc 153 r = sd_netlink_message_read_in6_addr(mm, IFA_LOCAL, &address.in6);
74b2466e 154 if (r < 0) {
1c4baffc 155 r = sd_netlink_message_read_in6_addr(mm, IFA_ADDRESS, &address.in6);
74b2466e
LP
156 if (r < 0)
157 goto fail;
158 }
159
160 break;
161
162 default:
163 return 0;
164 }
165
166 a = link_find_address(l, family, &address);
167
168 switch (type) {
169
170 case RTM_NEWADDR:
171
172 if (!a) {
173 r = link_address_new(l, &a, family, &address);
174 if (r < 0)
175 return r;
176 }
177
178 r = link_address_update_rtnl(a, mm);
179 if (r < 0)
180 return r;
181
182 break;
183
184 case RTM_DELADDR:
3e044c49 185 link_address_free(a);
74b2466e
LP
186 break;
187 }
188
189 return 0;
190
191fail:
da927ba9 192 log_warning_errno(r, "Failed to process RTNL address message: %m");
74b2466e
LP
193 return 0;
194}
195
74b2466e 196static int manager_rtnl_listen(Manager *m) {
4afd3348 197 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
1c4baffc 198 sd_netlink_message *i;
74b2466e
LP
199 int r;
200
201 assert(m);
202
cc98b302 203 /* First, subscribe to interfaces coming and going */
1c4baffc 204 r = sd_netlink_open(&m->rtnl);
74b2466e
LP
205 if (r < 0)
206 return r;
207
1c4baffc 208 r = sd_netlink_attach_event(m->rtnl, m->event, 0);
74b2466e
LP
209 if (r < 0)
210 return r;
211
1c4baffc 212 r = sd_netlink_add_match(m->rtnl, RTM_NEWLINK, manager_process_link, m);
74b2466e
LP
213 if (r < 0)
214 return r;
215
1c4baffc 216 r = sd_netlink_add_match(m->rtnl, RTM_DELLINK, manager_process_link, m);
74b2466e
LP
217 if (r < 0)
218 return r;
219
1c4baffc 220 r = sd_netlink_add_match(m->rtnl, RTM_NEWADDR, manager_process_address, m);
74b2466e
LP
221 if (r < 0)
222 return r;
091a364c 223
1c4baffc 224 r = sd_netlink_add_match(m->rtnl, RTM_DELADDR, manager_process_address, m);
74b2466e
LP
225 if (r < 0)
226 return r;
227
228 /* Then, enumerate all links */
229 r = sd_rtnl_message_new_link(m->rtnl, &req, RTM_GETLINK, 0);
230 if (r < 0)
231 return r;
232
1c4baffc 233 r = sd_netlink_message_request_dump(req, true);
74b2466e
LP
234 if (r < 0)
235 return r;
236
1c4baffc 237 r = sd_netlink_call(m->rtnl, req, 0, &reply);
74b2466e
LP
238 if (r < 0)
239 return r;
240
1c4baffc 241 for (i = reply; i; i = sd_netlink_message_next(i)) {
74b2466e
LP
242 r = manager_process_link(m->rtnl, i, m);
243 if (r < 0)
244 return r;
245 }
246
1c4baffc
TG
247 req = sd_netlink_message_unref(req);
248 reply = sd_netlink_message_unref(reply);
74b2466e
LP
249
250 /* Finally, enumerate all addresses, too */
251 r = sd_rtnl_message_new_addr(m->rtnl, &req, RTM_GETADDR, 0, AF_UNSPEC);
252 if (r < 0)
253 return r;
254
1c4baffc 255 r = sd_netlink_message_request_dump(req, true);
74b2466e
LP
256 if (r < 0)
257 return r;
258
1c4baffc 259 r = sd_netlink_call(m->rtnl, req, 0, &reply);
74b2466e
LP
260 if (r < 0)
261 return r;
262
1c4baffc 263 for (i = reply; i; i = sd_netlink_message_next(i)) {
74b2466e
LP
264 r = manager_process_address(m->rtnl, i, m);
265 if (r < 0)
266 return r;
267 }
268
269 return r;
270}
271
272static int on_network_event(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
273 Manager *m = userdata;
274 Iterator i;
275 Link *l;
276 int r;
277
278 assert(m);
279
280 sd_network_monitor_flush(m->network_monitor);
281
282 HASHMAP_FOREACH(l, m->links, i) {
283 r = link_update_monitor(l);
284 if (r < 0)
da927ba9 285 log_warning_errno(r, "Failed to update monitor information for %i: %m", l->ifindex);
74b2466e
LP
286 }
287
288 r = manager_write_resolv_conf(m);
289 if (r < 0)
da927ba9 290 log_warning_errno(r, "Could not update resolv.conf: %m");
74b2466e
LP
291
292 return 0;
293}
294
295static int manager_network_monitor_listen(Manager *m) {
296 int r, fd, events;
297
298 assert(m);
299
0014a4ad 300 r = sd_network_monitor_new(&m->network_monitor, NULL);
74b2466e
LP
301 if (r < 0)
302 return r;
303
304 fd = sd_network_monitor_get_fd(m->network_monitor);
305 if (fd < 0)
306 return fd;
307
308 events = sd_network_monitor_get_events(m->network_monitor);
309 if (events < 0)
310 return events;
311
312 r = sd_event_add_io(m->event, &m->network_event_source, fd, events, &on_network_event, m);
313 if (r < 0)
314 return r;
315
316 return 0;
317}
318
78c6a153 319static int determine_hostname(char **llmnr_hostname, char **mdns_hostname) {
eb60f9cd 320 _cleanup_free_ char *h = NULL, *n = NULL;
78c6a153
LP
321 char label[DNS_LABEL_MAX];
322 const char *p;
323 int r, k;
eb60f9cd 324
78c6a153
LP
325 assert(llmnr_hostname);
326 assert(mdns_hostname);
327
328 /* Extract and normalize the first label of the locally
329 * configured hostname, and check it's not "localhost". */
eb60f9cd
LP
330
331 h = gethostname_malloc();
332 if (!h)
333 return log_oom();
334
78c6a153
LP
335 p = h;
336 r = dns_label_unescape(&p, label, sizeof(label));
337 if (r < 0)
338 return log_error_errno(r, "Failed to unescape host name: %m");
339 if (r == 0) {
340 log_error("Couldn't find a single label in hosntame.");
341 return -EINVAL;
342 }
343
344 k = dns_label_undo_idna(label, r, label, sizeof(label));
345 if (k < 0)
346 return log_error_errno(k, "Failed to undo IDNA: %m");
347 if (k > 0)
348 r = k;
349
350 if (!utf8_is_valid(label)) {
eb60f9cd
LP
351 log_error("System hostname is not UTF-8 clean.");
352 return -EINVAL;
353 }
354
422baca0 355 r = dns_label_escape_new(label, r, &n);
78c6a153
LP
356 if (r < 0)
357 return log_error_errno(r, "Failed to escape host name: %m");
358
359 if (is_localhost(n)) {
360 log_debug("System hostname is 'localhost', ignoring.");
361 return -EINVAL;
eb60f9cd
LP
362 }
363
78c6a153
LP
364 r = dns_name_concat(n, "local", mdns_hostname);
365 if (r < 0)
366 return log_error_errno(r, "Failed to determine mDNS hostname: %m");
367
368 *llmnr_hostname = n;
eb60f9cd
LP
369 n = NULL;
370
371 return 0;
372}
373
374static int on_hostname_change(sd_event_source *es, int fd, uint32_t revents, void *userdata) {
78c6a153 375 _cleanup_free_ char *llmnr_hostname = NULL, *mdns_hostname = NULL;
eb60f9cd
LP
376 Manager *m = userdata;
377 int r;
378
379 assert(m);
380
78c6a153 381 r = determine_hostname(&llmnr_hostname, &mdns_hostname);
eb60f9cd
LP
382 if (r < 0)
383 return 0; /* ignore invalid hostnames */
384
78c6a153 385 if (streq(llmnr_hostname, m->llmnr_hostname) && streq(mdns_hostname, m->mdns_hostname))
eb60f9cd
LP
386 return 0;
387
78c6a153
LP
388 log_info("System hostname changed to '%s'.", llmnr_hostname);
389
390 free(m->llmnr_hostname);
391 free(m->mdns_hostname);
392
393 m->llmnr_hostname = llmnr_hostname;
394 m->mdns_hostname = mdns_hostname;
395
396 llmnr_hostname = mdns_hostname = NULL;
eb60f9cd
LP
397
398 manager_refresh_rrs(m);
399
400 return 0;
401}
402
403static int manager_watch_hostname(Manager *m) {
eb60f9cd
LP
404 int r;
405
406 assert(m);
407
408 m->hostname_fd = open("/proc/sys/kernel/hostname", O_RDONLY|O_CLOEXEC|O_NDELAY|O_NOCTTY);
409 if (m->hostname_fd < 0) {
56f64d95 410 log_warning_errno(errno, "Failed to watch hostname: %m");
eb60f9cd
LP
411 return 0;
412 }
413
414 r = sd_event_add_io(m->event, &m->hostname_event_source, m->hostname_fd, 0, on_hostname_change, m);
415 if (r < 0) {
416 if (r == -EPERM)
417 /* kernels prior to 3.2 don't support polling this file. Ignore the failure. */
418 m->hostname_fd = safe_close(m->hostname_fd);
8d3d7072
MS
419 else
420 return log_error_errno(r, "Failed to add hostname event source: %m");
eb60f9cd
LP
421 }
422
78c6a153 423 r = determine_hostname(&m->llmnr_hostname, &m->mdns_hostname);
eb60f9cd
LP
424 if (r < 0) {
425 log_info("Defaulting to hostname 'linux'.");
78c6a153
LP
426 m->llmnr_hostname = strdup("linux");
427 if (!m->llmnr_hostname)
428 return log_oom();
429
430 m->mdns_hostname = strdup("linux.local");
431 if (!m->mdns_hostname)
eb60f9cd
LP
432 return log_oom();
433 } else
78c6a153 434 log_info("Using system hostname '%s'.", m->llmnr_hostname);
eb60f9cd
LP
435
436 return 0;
437}
438
4d506d6b
LP
439static int manager_sigusr1(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
440 _cleanup_free_ char *buffer = NULL;
441 _cleanup_fclose_ FILE *f = NULL;
442 Manager *m = userdata;
443 size_t size = 0;
444 DnsScope *scope;
445
446 assert(s);
447 assert(si);
448 assert(m);
449
450 f = open_memstream(&buffer, &size);
451 if (!f)
452 return log_oom();
453
454 LIST_FOREACH(scopes, scope, m->dns_scopes)
455 dns_scope_dump(scope, f);
456
457 if (fflush_and_check(f) < 0)
458 return log_oom();
459
460 log_dump(LOG_INFO, buffer);
461 return 0;
462}
463
091a364c 464int manager_new(Manager **ret) {
74b2466e 465 _cleanup_(manager_freep) Manager *m = NULL;
091a364c
TG
466 int r;
467
c92e531c
LP
468 assert(ret);
469
091a364c
TG
470 m = new0(Manager, 1);
471 if (!m)
472 return -ENOMEM;
473
1716f6dc 474 m->llmnr_ipv4_udp_fd = m->llmnr_ipv6_udp_fd = -1;
623a4c97 475 m->llmnr_ipv4_tcp_fd = m->llmnr_ipv6_tcp_fd = -1;
bc7702b0 476 m->mdns_ipv4_fd = m->mdns_ipv6_fd = -1;
eb60f9cd 477 m->hostname_fd = -1;
1716f6dc 478
4e945a6f 479 m->llmnr_support = SUPPORT_YES;
5cb36f41 480 m->read_resolv_conf = true;
00fa60ae 481 m->need_builtin_fallbacks = true;
091a364c 482
0d2cd476
LP
483 r = dns_trust_anchor_load(&m->trust_anchor);
484 if (r < 0)
485 return r;
486
091a364c
TG
487 r = sd_event_default(&m->event);
488 if (r < 0)
489 return r;
490
491 sd_event_add_signal(m->event, NULL, SIGTERM, NULL, NULL);
492 sd_event_add_signal(m->event, NULL, SIGINT, NULL, NULL);
493
494 sd_event_set_watchdog(m->event, true);
495
eb60f9cd
LP
496 r = manager_watch_hostname(m);
497 if (r < 0)
498 return r;
499
1716f6dc 500 r = dns_scope_new(m, &m->unicast_scope, NULL, DNS_PROTOCOL_DNS, AF_UNSPEC);
74b2466e
LP
501 if (r < 0)
502 return r;
503
504 r = manager_network_monitor_listen(m);
505 if (r < 0)
506 return r;
507
508 r = manager_rtnl_listen(m);
509 if (r < 0)
510 return r;
511
512 r = manager_connect_bus(m);
513 if (r < 0)
514 return r;
515
4d506d6b
LP
516 (void) sd_event_add_signal(m->event, &m->sigusr1_event_source, SIGUSR1, manager_sigusr1, m);
517
091a364c
TG
518 *ret = m;
519 m = NULL;
520
521 return 0;
522}
523
edc501d4
LP
524int manager_start(Manager *m) {
525 int r;
526
527 assert(m);
528
529 r = manager_llmnr_start(m);
530 if (r < 0)
531 return r;
532
bc7702b0
DM
533 r = manager_mdns_start(m);
534 if (r < 0)
535 return r;
536
edc501d4
LP
537 return 0;
538}
539
74b2466e
LP
540Manager *manager_free(Manager *m) {
541 Link *l;
091a364c
TG
542
543 if (!m)
74b2466e
LP
544 return NULL;
545
4b95f179
LP
546 dns_server_unlink_all(m->dns_servers);
547 dns_server_unlink_all(m->fallback_dns_servers);
a51c1048
LP
548 dns_search_domain_unlink_all(m->search_domains);
549
74b2466e
LP
550 while ((l = hashmap_first(m->links)))
551 link_free(l);
f0e15467
LP
552
553 while (m->dns_queries)
554 dns_query_free(m->dns_queries);
74b2466e 555
cab5b059
LP
556 dns_scope_free(m->unicast_scope);
557
f0e15467
LP
558 hashmap_free(m->links);
559 hashmap_free(m->dns_transactions);
560
096b6773
LP
561 sd_event_source_unref(m->network_event_source);
562 sd_network_monitor_unref(m->network_monitor);
091a364c 563
a564ca2f
LP
564 sd_netlink_unref(m->rtnl);
565 sd_event_source_unref(m->rtnl_event_source);
566
edc501d4 567 manager_llmnr_stop(m);
bc7702b0 568 manager_mdns_stop(m);
623a4c97 569
902bb5d8 570 sd_bus_slot_unref(m->prepare_for_sleep_slot);
74b2466e
LP
571 sd_event_source_unref(m->bus_retry_event_source);
572 sd_bus_unref(m->bus);
091a364c 573
4d506d6b
LP
574 sd_event_source_unref(m->sigusr1_event_source);
575
74b2466e 576 sd_event_unref(m->event);
623a4c97 577
78c6a153
LP
578 dns_resource_key_unref(m->llmnr_host_ipv4_key);
579 dns_resource_key_unref(m->llmnr_host_ipv6_key);
eb60f9cd 580
eb60f9cd 581 sd_event_source_unref(m->hostname_event_source);
d9fcf2ba 582 safe_close(m->hostname_fd);
78c6a153
LP
583 free(m->llmnr_hostname);
584 free(m->mdns_hostname);
eb60f9cd 585
0d2cd476
LP
586 dns_trust_anchor_flush(&m->trust_anchor);
587
091a364c 588 free(m);
74b2466e
LP
589
590 return NULL;
091a364c
TG
591}
592
1716f6dc 593int manager_recv(Manager *m, int fd, DnsProtocol protocol, DnsPacket **ret) {
74b2466e 594 _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
1716f6dc
LP
595 union {
596 struct cmsghdr header; /* For alignment */
40a1eebd 597 uint8_t buffer[CMSG_SPACE(MAXSIZE(struct in_pktinfo, struct in6_pktinfo))
1716f6dc 598 + CMSG_SPACE(int) /* ttl/hoplimit */
623a4c97 599 + EXTRA_CMSG_SPACE /* kernel appears to require extra buffer space */];
1716f6dc
LP
600 } control;
601 union sockaddr_union sa;
74b2466e 602 struct msghdr mh = {};
1716f6dc 603 struct cmsghdr *cmsg;
74b2466e 604 struct iovec iov;
1716f6dc 605 int ms = 0, r;
74b2466e
LP
606 ssize_t l;
607
608 assert(m);
1716f6dc 609 assert(fd >= 0);
74b2466e
LP
610 assert(ret);
611
74b2466e
LP
612 r = ioctl(fd, FIONREAD, &ms);
613 if (r < 0)
614 return -errno;
615 if (ms < 0)
616 return -EIO;
617
1716f6dc 618 r = dns_packet_new(&p, protocol, ms);
74b2466e
LP
619 if (r < 0)
620 return r;
621
622 iov.iov_base = DNS_PACKET_DATA(p);
623 iov.iov_len = p->allocated;
624
1716f6dc
LP
625 mh.msg_name = &sa.sa;
626 mh.msg_namelen = sizeof(sa);
74b2466e
LP
627 mh.msg_iov = &iov;
628 mh.msg_iovlen = 1;
1716f6dc
LP
629 mh.msg_control = &control;
630 mh.msg_controllen = sizeof(control);
74b2466e 631
a38d9945 632 l = recvmsg(fd, &mh, 0);
74b2466e 633 if (l < 0) {
ad867662 634 if (errno == EAGAIN || errno == EINTR)
74b2466e
LP
635 return 0;
636
637 return -errno;
091a364c
TG
638 }
639
74b2466e
LP
640 if (l <= 0)
641 return -EIO;
091a364c 642
1716f6dc
LP
643 assert(!(mh.msg_flags & MSG_CTRUNC));
644 assert(!(mh.msg_flags & MSG_TRUNC));
645
74b2466e 646 p->size = (size_t) l;
091a364c 647
1716f6dc 648 p->family = sa.sa.sa_family;
623a4c97
LP
649 p->ipproto = IPPROTO_UDP;
650 if (p->family == AF_INET) {
1716f6dc 651 p->sender.in = sa.in.sin_addr;
623a4c97
LP
652 p->sender_port = be16toh(sa.in.sin_port);
653 } else if (p->family == AF_INET6) {
1716f6dc 654 p->sender.in6 = sa.in6.sin6_addr;
623a4c97
LP
655 p->sender_port = be16toh(sa.in6.sin6_port);
656 p->ifindex = sa.in6.sin6_scope_id;
657 } else
1716f6dc 658 return -EAFNOSUPPORT;
74b2466e 659
2a1288ff 660 CMSG_FOREACH(cmsg, &mh) {
74b2466e 661
1716f6dc
LP
662 if (cmsg->cmsg_level == IPPROTO_IPV6) {
663 assert(p->family == AF_INET6);
74b2466e 664
1716f6dc 665 switch (cmsg->cmsg_type) {
74b2466e 666
1716f6dc
LP
667 case IPV6_PKTINFO: {
668 struct in6_pktinfo *i = (struct in6_pktinfo*) CMSG_DATA(cmsg);
74b2466e 669
623a4c97
LP
670 if (p->ifindex <= 0)
671 p->ifindex = i->ipi6_ifindex;
672
1716f6dc
LP
673 p->destination.in6 = i->ipi6_addr;
674 break;
675 }
74b2466e 676
1716f6dc
LP
677 case IPV6_HOPLIMIT:
678 p->ttl = *(int *) CMSG_DATA(cmsg);
679 break;
74b2466e 680
1716f6dc
LP
681 }
682 } else if (cmsg->cmsg_level == IPPROTO_IP) {
683 assert(p->family == AF_INET);
74b2466e 684
1716f6dc 685 switch (cmsg->cmsg_type) {
74b2466e 686
1716f6dc
LP
687 case IP_PKTINFO: {
688 struct in_pktinfo *i = (struct in_pktinfo*) CMSG_DATA(cmsg);
091a364c 689
623a4c97
LP
690 if (p->ifindex <= 0)
691 p->ifindex = i->ipi_ifindex;
692
1716f6dc
LP
693 p->destination.in = i->ipi_addr;
694 break;
695 }
74b2466e 696
623a4c97 697 case IP_TTL:
1716f6dc
LP
698 p->ttl = *(int *) CMSG_DATA(cmsg);
699 break;
700 }
701 }
702 }
74b2466e 703
623a4c97
LP
704 /* The Linux kernel sets the interface index to the loopback
705 * device if the packet came from the local host since it
706 * avoids the routing table in such a case. Let's unset the
707 * interface index in such a case. */
a5f03596 708 if (p->ifindex == LOOPBACK_IFINDEX)
623a4c97
LP
709 p->ifindex = 0;
710
86ad4cd7
TG
711 if (protocol != DNS_PROTOCOL_DNS) {
712 /* If we don't know the interface index still, we look for the
713 * first local interface with a matching address. Yuck! */
714 if (p->ifindex <= 0)
715 p->ifindex = manager_find_ifindex(m, p->family, &p->destination);
716 }
623a4c97 717
74b2466e
LP
718 *ret = p;
719 p = NULL;
720
721 return 1;
722}
723
74b2466e
LP
724static int sendmsg_loop(int fd, struct msghdr *mh, int flags) {
725 int r;
726
727 assert(fd >= 0);
728 assert(mh);
729
730 for (;;) {
731 if (sendmsg(fd, mh, flags) >= 0)
732 return 0;
733
734 if (errno == EINTR)
735 continue;
736
737 if (errno != EAGAIN)
738 return -errno;
739
740 r = fd_wait_for_event(fd, POLLOUT, SEND_TIMEOUT_USEC);
741 if (r < 0)
742 return r;
743 if (r == 0)
744 return -ETIMEDOUT;
745 }
746}
747
72290734
TG
748static int write_loop(int fd, void *message, size_t length) {
749 int r;
750
751 assert(fd >= 0);
752 assert(message);
753
754 for (;;) {
755 if (write(fd, message, length) >= 0)
756 return 0;
757
758 if (errno == EINTR)
759 continue;
760
761 if (errno != EAGAIN)
762 return -errno;
763
764 r = fd_wait_for_event(fd, POLLOUT, SEND_TIMEOUT_USEC);
765 if (r < 0)
766 return r;
767 if (r == 0)
768 return -ETIMEDOUT;
769 }
770}
771
772int manager_write(Manager *m, int fd, DnsPacket *p) {
773 int r;
774
775 log_debug("Sending %s packet with id %u", DNS_PACKET_QR(p) ? "response" : "query", DNS_PACKET_ID(p));
776
777 r = write_loop(fd, DNS_PACKET_DATA(p), p->size);
778 if (r < 0)
779 return r;
780
781 return 0;
782}
783
623a4c97 784static int manager_ipv4_send(Manager *m, int fd, int ifindex, const struct in_addr *addr, uint16_t port, DnsPacket *p) {
74b2466e
LP
785 union sockaddr_union sa = {
786 .in.sin_family = AF_INET,
74b2466e 787 };
1716f6dc
LP
788 union {
789 struct cmsghdr header; /* For alignment */
790 uint8_t buffer[CMSG_SPACE(sizeof(struct in_pktinfo))];
791 } control;
74b2466e
LP
792 struct msghdr mh = {};
793 struct iovec iov;
74b2466e
LP
794
795 assert(m);
1716f6dc
LP
796 assert(fd >= 0);
797 assert(addr);
798 assert(port > 0);
74b2466e
LP
799 assert(p);
800
74b2466e
LP
801 iov.iov_base = DNS_PACKET_DATA(p);
802 iov.iov_len = p->size;
091a364c 803
1716f6dc
LP
804 sa.in.sin_addr = *addr;
805 sa.in.sin_port = htobe16(port),
091a364c 806
74b2466e
LP
807 mh.msg_iov = &iov;
808 mh.msg_iovlen = 1;
809 mh.msg_name = &sa.sa;
810 mh.msg_namelen = sizeof(sa.in);
091a364c 811
74b2466e
LP
812 if (ifindex > 0) {
813 struct cmsghdr *cmsg;
814 struct in_pktinfo *pi;
815
816 zero(control);
817
1716f6dc 818 mh.msg_control = &control;
74b2466e
LP
819 mh.msg_controllen = CMSG_LEN(sizeof(struct in_pktinfo));
820
821 cmsg = CMSG_FIRSTHDR(&mh);
822 cmsg->cmsg_len = mh.msg_controllen;
823 cmsg->cmsg_level = IPPROTO_IP;
824 cmsg->cmsg_type = IP_PKTINFO;
825
826 pi = (struct in_pktinfo*) CMSG_DATA(cmsg);
827 pi->ipi_ifindex = ifindex;
828 }
829
830 return sendmsg_loop(fd, &mh, 0);
831}
832
623a4c97 833static int manager_ipv6_send(Manager *m, int fd, int ifindex, const struct in6_addr *addr, uint16_t port, DnsPacket *p) {
74b2466e
LP
834 union sockaddr_union sa = {
835 .in6.sin6_family = AF_INET6,
74b2466e 836 };
1716f6dc
LP
837 union {
838 struct cmsghdr header; /* For alignment */
839 uint8_t buffer[CMSG_SPACE(sizeof(struct in6_pktinfo))];
840 } control;
74b2466e
LP
841 struct msghdr mh = {};
842 struct iovec iov;
74b2466e
LP
843
844 assert(m);
1716f6dc
LP
845 assert(fd >= 0);
846 assert(addr);
847 assert(port > 0);
74b2466e
LP
848 assert(p);
849
74b2466e
LP
850 iov.iov_base = DNS_PACKET_DATA(p);
851 iov.iov_len = p->size;
852
1716f6dc
LP
853 sa.in6.sin6_addr = *addr;
854 sa.in6.sin6_port = htobe16(port),
74b2466e
LP
855 sa.in6.sin6_scope_id = ifindex;
856
857 mh.msg_iov = &iov;
858 mh.msg_iovlen = 1;
859 mh.msg_name = &sa.sa;
860 mh.msg_namelen = sizeof(sa.in6);
861
862 if (ifindex > 0) {
863 struct cmsghdr *cmsg;
864 struct in6_pktinfo *pi;
865
866 zero(control);
867
1716f6dc 868 mh.msg_control = &control;
74b2466e
LP
869 mh.msg_controllen = CMSG_LEN(sizeof(struct in6_pktinfo));
870
871 cmsg = CMSG_FIRSTHDR(&mh);
872 cmsg->cmsg_len = mh.msg_controllen;
873 cmsg->cmsg_level = IPPROTO_IPV6;
874 cmsg->cmsg_type = IPV6_PKTINFO;
875
876 pi = (struct in6_pktinfo*) CMSG_DATA(cmsg);
877 pi->ipi6_ifindex = ifindex;
878 }
879
880 return sendmsg_loop(fd, &mh, 0);
881}
882
623a4c97 883int manager_send(Manager *m, int fd, int ifindex, int family, const union in_addr_union *addr, uint16_t port, DnsPacket *p) {
1716f6dc
LP
884 assert(m);
885 assert(fd >= 0);
886 assert(addr);
887 assert(port > 0);
888 assert(p);
889
a2a416f7
LP
890 log_debug("Sending %s packet with id %u on interface %i/%s", DNS_PACKET_QR(p) ? "response" : "query", DNS_PACKET_ID(p), ifindex, af_to_name(family));
891
1716f6dc
LP
892 if (family == AF_INET)
893 return manager_ipv4_send(m, fd, ifindex, &addr->in, port, p);
894 else if (family == AF_INET6)
895 return manager_ipv6_send(m, fd, ifindex, &addr->in6, port, p);
896
897 return -EAFNOSUPPORT;
898}
899
e1c95994
LP
900uint32_t manager_find_mtu(Manager *m) {
901 uint32_t mtu = 0;
902 Link *l;
903 Iterator i;
904
905 /* If we don't know on which link a DNS packet would be
906 * delivered, let's find the largest MTU that works on all
907 * interfaces we know of */
908
909 HASHMAP_FOREACH(l, m->links, i) {
910 if (l->mtu <= 0)
911 continue;
912
913 if (mtu <= 0 || l->mtu < mtu)
914 mtu = l->mtu;
915 }
916
917 return mtu;
918}
1716f6dc 919
623a4c97 920int manager_find_ifindex(Manager *m, int family, const union in_addr_union *in_addr) {
ec2c5e43
LP
921 LinkAddress *a;
922
923 assert(m);
924
4e945a6f 925 a = manager_find_link_address(m, family, in_addr);
ec2c5e43
LP
926 if (a)
927 return a->link->ifindex;
928
929 return 0;
930}
931
eb60f9cd
LP
932void manager_refresh_rrs(Manager *m) {
933 Iterator i;
934 Link *l;
935
936 assert(m);
937
78c6a153
LP
938 m->llmnr_host_ipv4_key = dns_resource_key_unref(m->llmnr_host_ipv4_key);
939 m->llmnr_host_ipv6_key = dns_resource_key_unref(m->llmnr_host_ipv6_key);
eb60f9cd
LP
940
941 HASHMAP_FOREACH(l, m->links, i) {
942 link_add_rrs(l, true);
943 link_add_rrs(l, false);
944 }
945}
946
ec2c5e43
LP
947int manager_next_hostname(Manager *m) {
948 const char *p;
556a2294 949 uint64_t u, a;
78c6a153
LP
950 char *h, *k;
951 int r;
623a4c97
LP
952
953 assert(m);
954
78c6a153 955 p = strchr(m->llmnr_hostname, 0);
ec2c5e43
LP
956 assert(p);
957
78c6a153 958 while (p > m->llmnr_hostname) {
ec2c5e43
LP
959 if (!strchr("0123456789", p[-1]))
960 break;
961
962 p--;
963 }
964
965 if (*p == 0 || safe_atou64(p, &u) < 0 || u <= 0)
966 u = 1;
967
556a2294
LP
968 /* Add a random number to the old value. This way we can avoid
969 * that two hosts pick the same hostname, win on IPv4 and lose
970 * on IPv6 (or vice versa), and pick the same hostname
971 * replacement hostname, ad infinitum. We still want the
972 * numbers to go up monotonically, hence we just add a random
973 * value 1..10 */
974
975 random_bytes(&a, sizeof(a));
976 u += 1 + a % 10;
ec2c5e43 977
78c6a153 978 if (asprintf(&h, "%.*s%" PRIu64, (int) (p - m->llmnr_hostname), m->llmnr_hostname, u) < 0)
ec2c5e43
LP
979 return -ENOMEM;
980
78c6a153
LP
981 r = dns_name_concat(h, "local", &k);
982 if (r < 0) {
983 free(h);
984 return r;
985 }
986
987 log_info("Hostname conflict, changing published hostname from '%s' to '%s'.", m->llmnr_hostname, h);
988
989 free(m->llmnr_hostname);
990 m->llmnr_hostname = h;
ec2c5e43 991
78c6a153
LP
992 free(m->mdns_hostname);
993 m->mdns_hostname = k;
ec2c5e43 994
eb60f9cd 995 manager_refresh_rrs(m);
623a4c97
LP
996
997 return 0;
998}
ec2c5e43 999
4e945a6f 1000LinkAddress* manager_find_link_address(Manager *m, int family, const union in_addr_union *in_addr) {
ec2c5e43
LP
1001 Iterator i;
1002 Link *l;
1003
1004 assert(m);
1005
1006 HASHMAP_FOREACH(l, m->links, i) {
1007 LinkAddress *a;
1008
1009 a = link_find_address(l, family, in_addr);
1010 if (a)
1011 return a;
1012 }
1013
1014 return NULL;
1015}
1016
a4076574 1017bool manager_our_packet(Manager *m, DnsPacket *p) {
ec2c5e43
LP
1018 assert(m);
1019 assert(p);
1020
4e945a6f 1021 return !!manager_find_link_address(m, p->family, &p->sender);
ec2c5e43 1022}
4e945a6f 1023
a4076574
LP
1024DnsScope* manager_find_scope(Manager *m, DnsPacket *p) {
1025 Link *l;
1026
1027 assert(m);
1028 assert(p);
1029
1030 l = hashmap_get(m->links, INT_TO_PTR(p->ifindex));
1031 if (!l)
1032 return NULL;
1033
1034 if (p->protocol == DNS_PROTOCOL_LLMNR) {
1035 if (p->family == AF_INET)
1036 return l->llmnr_ipv4_scope;
1037 else if (p->family == AF_INET6)
1038 return l->llmnr_ipv6_scope;
1039 }
1040
1041 return NULL;
1042}
1043
902bb5d8
LP
1044void manager_verify_all(Manager *m) {
1045 DnsScope *s;
1046
1047 assert(m);
1048
1049 LIST_FOREACH(scopes, s, m->dns_scopes)
1050 dns_zone_verify_all(&s->zone);
1051}
1052
78c6a153 1053int manager_is_own_hostname(Manager *m, const char *name) {
78c6a153
LP
1054 int r;
1055
1056 assert(m);
1057 assert(name);
1058
1059 if (m->llmnr_hostname) {
1060 r = dns_name_equal(name, m->llmnr_hostname);
1061 if (r != 0)
1062 return r;
1063 }
1064
1065 if (m->mdns_hostname)
1066 return dns_name_equal(name, m->mdns_hostname);
1067
1068 return 0;
1069}
1070
9176a57c
LP
1071int manager_compile_dns_servers(Manager *m, OrderedSet **dns) {
1072 DnsServer *s;
1073 Iterator i;
1074 Link *l;
1075 int r;
1076
1077 assert(m);
1078 assert(dns);
1079
1080 r = ordered_set_ensure_allocated(dns, &dns_server_hash_ops);
1081 if (r < 0)
1082 return r;
1083
1084 /* First add the system-wide servers and domains */
1085 LIST_FOREACH(servers, s, m->dns_servers) {
1086 r = ordered_set_put(*dns, s);
1087 if (r == -EEXIST)
1088 continue;
1089 if (r < 0)
1090 return r;
1091 }
1092
1093 /* Then, add the per-link servers */
1094 HASHMAP_FOREACH(l, m->links, i) {
1095 LIST_FOREACH(servers, s, l->dns_servers) {
1096 r = ordered_set_put(*dns, s);
1097 if (r == -EEXIST)
1098 continue;
1099 if (r < 0)
1100 return r;
1101 }
1102 }
1103
1104 /* If we found nothing, add the fallback servers */
1105 if (ordered_set_isempty(*dns)) {
1106 LIST_FOREACH(servers, s, m->fallback_dns_servers) {
1107 r = ordered_set_put(*dns, s);
1108 if (r == -EEXIST)
1109 continue;
1110 if (r < 0)
1111 return r;
1112 }
1113 }
1114
1115 return 0;
1116}
1117
1118int manager_compile_search_domains(Manager *m, OrderedSet **domains) {
1119 DnsSearchDomain *d;
1120 Iterator i;
1121 Link *l;
1122 int r;
1123
1124 assert(m);
1125 assert(domains);
1126
1127 r = ordered_set_ensure_allocated(domains, &dns_name_hash_ops);
1128 if (r < 0)
1129 return r;
1130
1131 LIST_FOREACH(domains, d, m->search_domains) {
1132 r = ordered_set_put(*domains, d->name);
1133 if (r == -EEXIST)
1134 continue;
1135 if (r < 0)
1136 return r;
1137 }
1138
1139 HASHMAP_FOREACH(l, m->links, i) {
1140
1141 LIST_FOREACH(domains, d, l->search_domains) {
1142 r = ordered_set_put(*domains, d->name);
1143 if (r == -EEXIST)
1144 continue;
1145 if (r < 0)
1146 return r;
1147 }
1148 }
1149
1150 return 0;
1151}
1152
4e945a6f
LP
1153static const char* const support_table[_SUPPORT_MAX] = {
1154 [SUPPORT_NO] = "no",
1155 [SUPPORT_YES] = "yes",
1156 [SUPPORT_RESOLVE] = "resolve",
1157};
1158DEFINE_STRING_TABLE_LOOKUP(support, Support);