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