]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/resolve/resolved-manager.c
resolved: fix error propagation
[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
af49ca27 479 m->llmnr_support = RESOLVE_SUPPORT_YES;
ad6c0475
LP
480 m->mdns_support = RESOLVE_SUPPORT_NO;
481 m->dnssec_mode = DNSSEC_NO;
5cb36f41 482 m->read_resolv_conf = true;
00fa60ae 483 m->need_builtin_fallbacks = true;
091a364c 484
0d2cd476
LP
485 r = dns_trust_anchor_load(&m->trust_anchor);
486 if (r < 0)
487 return r;
488
ad6c0475
LP
489 r = manager_parse_config_file(m);
490 if (r < 0)
491 return r;
492
091a364c
TG
493 r = sd_event_default(&m->event);
494 if (r < 0)
495 return r;
496
497 sd_event_add_signal(m->event, NULL, SIGTERM, NULL, NULL);
498 sd_event_add_signal(m->event, NULL, SIGINT, NULL, NULL);
499
500 sd_event_set_watchdog(m->event, true);
501
eb60f9cd
LP
502 r = manager_watch_hostname(m);
503 if (r < 0)
504 return r;
505
1716f6dc 506 r = dns_scope_new(m, &m->unicast_scope, NULL, DNS_PROTOCOL_DNS, AF_UNSPEC);
74b2466e
LP
507 if (r < 0)
508 return r;
509
510 r = manager_network_monitor_listen(m);
511 if (r < 0)
512 return r;
513
514 r = manager_rtnl_listen(m);
515 if (r < 0)
516 return r;
517
518 r = manager_connect_bus(m);
519 if (r < 0)
520 return r;
521
4d506d6b
LP
522 (void) sd_event_add_signal(m->event, &m->sigusr1_event_source, SIGUSR1, manager_sigusr1, m);
523
091a364c
TG
524 *ret = m;
525 m = NULL;
526
527 return 0;
528}
529
edc501d4
LP
530int manager_start(Manager *m) {
531 int r;
532
533 assert(m);
534
535 r = manager_llmnr_start(m);
536 if (r < 0)
537 return r;
538
bc7702b0
DM
539 r = manager_mdns_start(m);
540 if (r < 0)
541 return r;
542
edc501d4
LP
543 return 0;
544}
545
74b2466e
LP
546Manager *manager_free(Manager *m) {
547 Link *l;
091a364c
TG
548
549 if (!m)
74b2466e
LP
550 return NULL;
551
4b95f179
LP
552 dns_server_unlink_all(m->dns_servers);
553 dns_server_unlink_all(m->fallback_dns_servers);
a51c1048
LP
554 dns_search_domain_unlink_all(m->search_domains);
555
74b2466e
LP
556 while ((l = hashmap_first(m->links)))
557 link_free(l);
f0e15467
LP
558
559 while (m->dns_queries)
560 dns_query_free(m->dns_queries);
74b2466e 561
cab5b059
LP
562 dns_scope_free(m->unicast_scope);
563
f0e15467
LP
564 hashmap_free(m->links);
565 hashmap_free(m->dns_transactions);
566
096b6773
LP
567 sd_event_source_unref(m->network_event_source);
568 sd_network_monitor_unref(m->network_monitor);
091a364c 569
a564ca2f
LP
570 sd_netlink_unref(m->rtnl);
571 sd_event_source_unref(m->rtnl_event_source);
572
edc501d4 573 manager_llmnr_stop(m);
bc7702b0 574 manager_mdns_stop(m);
623a4c97 575
902bb5d8 576 sd_bus_slot_unref(m->prepare_for_sleep_slot);
74b2466e
LP
577 sd_event_source_unref(m->bus_retry_event_source);
578 sd_bus_unref(m->bus);
091a364c 579
4d506d6b
LP
580 sd_event_source_unref(m->sigusr1_event_source);
581
74b2466e 582 sd_event_unref(m->event);
623a4c97 583
78c6a153
LP
584 dns_resource_key_unref(m->llmnr_host_ipv4_key);
585 dns_resource_key_unref(m->llmnr_host_ipv6_key);
eb60f9cd 586
eb60f9cd 587 sd_event_source_unref(m->hostname_event_source);
d9fcf2ba 588 safe_close(m->hostname_fd);
78c6a153
LP
589 free(m->llmnr_hostname);
590 free(m->mdns_hostname);
eb60f9cd 591
0d2cd476
LP
592 dns_trust_anchor_flush(&m->trust_anchor);
593
091a364c 594 free(m);
74b2466e
LP
595
596 return NULL;
091a364c
TG
597}
598
1716f6dc 599int manager_recv(Manager *m, int fd, DnsProtocol protocol, DnsPacket **ret) {
74b2466e 600 _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
1716f6dc
LP
601 union {
602 struct cmsghdr header; /* For alignment */
40a1eebd 603 uint8_t buffer[CMSG_SPACE(MAXSIZE(struct in_pktinfo, struct in6_pktinfo))
1716f6dc 604 + CMSG_SPACE(int) /* ttl/hoplimit */
623a4c97 605 + EXTRA_CMSG_SPACE /* kernel appears to require extra buffer space */];
1716f6dc
LP
606 } control;
607 union sockaddr_union sa;
74b2466e 608 struct msghdr mh = {};
1716f6dc 609 struct cmsghdr *cmsg;
74b2466e 610 struct iovec iov;
1716f6dc 611 int ms = 0, r;
74b2466e
LP
612 ssize_t l;
613
614 assert(m);
1716f6dc 615 assert(fd >= 0);
74b2466e
LP
616 assert(ret);
617
74b2466e
LP
618 r = ioctl(fd, FIONREAD, &ms);
619 if (r < 0)
620 return -errno;
621 if (ms < 0)
622 return -EIO;
623
1716f6dc 624 r = dns_packet_new(&p, protocol, ms);
74b2466e
LP
625 if (r < 0)
626 return r;
627
628 iov.iov_base = DNS_PACKET_DATA(p);
629 iov.iov_len = p->allocated;
630
1716f6dc
LP
631 mh.msg_name = &sa.sa;
632 mh.msg_namelen = sizeof(sa);
74b2466e
LP
633 mh.msg_iov = &iov;
634 mh.msg_iovlen = 1;
1716f6dc
LP
635 mh.msg_control = &control;
636 mh.msg_controllen = sizeof(control);
74b2466e 637
a38d9945 638 l = recvmsg(fd, &mh, 0);
74b2466e 639 if (l < 0) {
ad867662 640 if (errno == EAGAIN || errno == EINTR)
74b2466e
LP
641 return 0;
642
643 return -errno;
091a364c
TG
644 }
645
74b2466e
LP
646 if (l <= 0)
647 return -EIO;
091a364c 648
1716f6dc
LP
649 assert(!(mh.msg_flags & MSG_CTRUNC));
650 assert(!(mh.msg_flags & MSG_TRUNC));
651
74b2466e 652 p->size = (size_t) l;
091a364c 653
1716f6dc 654 p->family = sa.sa.sa_family;
623a4c97
LP
655 p->ipproto = IPPROTO_UDP;
656 if (p->family == AF_INET) {
1716f6dc 657 p->sender.in = sa.in.sin_addr;
623a4c97
LP
658 p->sender_port = be16toh(sa.in.sin_port);
659 } else if (p->family == AF_INET6) {
1716f6dc 660 p->sender.in6 = sa.in6.sin6_addr;
623a4c97
LP
661 p->sender_port = be16toh(sa.in6.sin6_port);
662 p->ifindex = sa.in6.sin6_scope_id;
663 } else
1716f6dc 664 return -EAFNOSUPPORT;
74b2466e 665
2a1288ff 666 CMSG_FOREACH(cmsg, &mh) {
74b2466e 667
1716f6dc
LP
668 if (cmsg->cmsg_level == IPPROTO_IPV6) {
669 assert(p->family == AF_INET6);
74b2466e 670
1716f6dc 671 switch (cmsg->cmsg_type) {
74b2466e 672
1716f6dc
LP
673 case IPV6_PKTINFO: {
674 struct in6_pktinfo *i = (struct in6_pktinfo*) CMSG_DATA(cmsg);
74b2466e 675
623a4c97
LP
676 if (p->ifindex <= 0)
677 p->ifindex = i->ipi6_ifindex;
678
1716f6dc
LP
679 p->destination.in6 = i->ipi6_addr;
680 break;
681 }
74b2466e 682
1716f6dc
LP
683 case IPV6_HOPLIMIT:
684 p->ttl = *(int *) CMSG_DATA(cmsg);
685 break;
74b2466e 686
1716f6dc
LP
687 }
688 } else if (cmsg->cmsg_level == IPPROTO_IP) {
689 assert(p->family == AF_INET);
74b2466e 690
1716f6dc 691 switch (cmsg->cmsg_type) {
74b2466e 692
1716f6dc
LP
693 case IP_PKTINFO: {
694 struct in_pktinfo *i = (struct in_pktinfo*) CMSG_DATA(cmsg);
091a364c 695
623a4c97
LP
696 if (p->ifindex <= 0)
697 p->ifindex = i->ipi_ifindex;
698
1716f6dc
LP
699 p->destination.in = i->ipi_addr;
700 break;
701 }
74b2466e 702
623a4c97 703 case IP_TTL:
1716f6dc
LP
704 p->ttl = *(int *) CMSG_DATA(cmsg);
705 break;
706 }
707 }
708 }
74b2466e 709
623a4c97
LP
710 /* The Linux kernel sets the interface index to the loopback
711 * device if the packet came from the local host since it
712 * avoids the routing table in such a case. Let's unset the
713 * interface index in such a case. */
a5f03596 714 if (p->ifindex == LOOPBACK_IFINDEX)
623a4c97
LP
715 p->ifindex = 0;
716
86ad4cd7
TG
717 if (protocol != DNS_PROTOCOL_DNS) {
718 /* If we don't know the interface index still, we look for the
719 * first local interface with a matching address. Yuck! */
720 if (p->ifindex <= 0)
721 p->ifindex = manager_find_ifindex(m, p->family, &p->destination);
722 }
623a4c97 723
74b2466e
LP
724 *ret = p;
725 p = NULL;
726
727 return 1;
728}
729
74b2466e
LP
730static int sendmsg_loop(int fd, struct msghdr *mh, int flags) {
731 int r;
732
733 assert(fd >= 0);
734 assert(mh);
735
736 for (;;) {
737 if (sendmsg(fd, mh, flags) >= 0)
738 return 0;
739
740 if (errno == EINTR)
741 continue;
742
743 if (errno != EAGAIN)
744 return -errno;
745
746 r = fd_wait_for_event(fd, POLLOUT, SEND_TIMEOUT_USEC);
747 if (r < 0)
748 return r;
749 if (r == 0)
750 return -ETIMEDOUT;
751 }
752}
753
72290734
TG
754static int write_loop(int fd, void *message, size_t length) {
755 int r;
756
757 assert(fd >= 0);
758 assert(message);
759
760 for (;;) {
761 if (write(fd, message, length) >= 0)
762 return 0;
763
764 if (errno == EINTR)
765 continue;
766
767 if (errno != EAGAIN)
768 return -errno;
769
770 r = fd_wait_for_event(fd, POLLOUT, SEND_TIMEOUT_USEC);
771 if (r < 0)
772 return r;
773 if (r == 0)
774 return -ETIMEDOUT;
775 }
776}
777
778int manager_write(Manager *m, int fd, DnsPacket *p) {
779 int r;
780
deb3f3d3 781 log_debug("Sending %s packet with id %" PRIu16 ".", DNS_PACKET_QR(p) ? "response" : "query", DNS_PACKET_ID(p));
72290734
TG
782
783 r = write_loop(fd, DNS_PACKET_DATA(p), p->size);
784 if (r < 0)
785 return r;
786
787 return 0;
788}
789
623a4c97 790static int manager_ipv4_send(Manager *m, int fd, int ifindex, const struct in_addr *addr, uint16_t port, DnsPacket *p) {
74b2466e
LP
791 union sockaddr_union sa = {
792 .in.sin_family = AF_INET,
74b2466e 793 };
1716f6dc
LP
794 union {
795 struct cmsghdr header; /* For alignment */
796 uint8_t buffer[CMSG_SPACE(sizeof(struct in_pktinfo))];
797 } control;
74b2466e
LP
798 struct msghdr mh = {};
799 struct iovec iov;
74b2466e
LP
800
801 assert(m);
1716f6dc
LP
802 assert(fd >= 0);
803 assert(addr);
804 assert(port > 0);
74b2466e
LP
805 assert(p);
806
74b2466e
LP
807 iov.iov_base = DNS_PACKET_DATA(p);
808 iov.iov_len = p->size;
091a364c 809
1716f6dc
LP
810 sa.in.sin_addr = *addr;
811 sa.in.sin_port = htobe16(port),
091a364c 812
74b2466e
LP
813 mh.msg_iov = &iov;
814 mh.msg_iovlen = 1;
815 mh.msg_name = &sa.sa;
816 mh.msg_namelen = sizeof(sa.in);
091a364c 817
74b2466e
LP
818 if (ifindex > 0) {
819 struct cmsghdr *cmsg;
820 struct in_pktinfo *pi;
821
822 zero(control);
823
1716f6dc 824 mh.msg_control = &control;
74b2466e
LP
825 mh.msg_controllen = CMSG_LEN(sizeof(struct in_pktinfo));
826
827 cmsg = CMSG_FIRSTHDR(&mh);
828 cmsg->cmsg_len = mh.msg_controllen;
829 cmsg->cmsg_level = IPPROTO_IP;
830 cmsg->cmsg_type = IP_PKTINFO;
831
832 pi = (struct in_pktinfo*) CMSG_DATA(cmsg);
833 pi->ipi_ifindex = ifindex;
834 }
835
836 return sendmsg_loop(fd, &mh, 0);
837}
838
623a4c97 839static int manager_ipv6_send(Manager *m, int fd, int ifindex, const struct in6_addr *addr, uint16_t port, DnsPacket *p) {
74b2466e
LP
840 union sockaddr_union sa = {
841 .in6.sin6_family = AF_INET6,
74b2466e 842 };
1716f6dc
LP
843 union {
844 struct cmsghdr header; /* For alignment */
845 uint8_t buffer[CMSG_SPACE(sizeof(struct in6_pktinfo))];
846 } control;
74b2466e
LP
847 struct msghdr mh = {};
848 struct iovec iov;
74b2466e
LP
849
850 assert(m);
1716f6dc
LP
851 assert(fd >= 0);
852 assert(addr);
853 assert(port > 0);
74b2466e
LP
854 assert(p);
855
74b2466e
LP
856 iov.iov_base = DNS_PACKET_DATA(p);
857 iov.iov_len = p->size;
858
1716f6dc
LP
859 sa.in6.sin6_addr = *addr;
860 sa.in6.sin6_port = htobe16(port),
74b2466e
LP
861 sa.in6.sin6_scope_id = ifindex;
862
863 mh.msg_iov = &iov;
864 mh.msg_iovlen = 1;
865 mh.msg_name = &sa.sa;
866 mh.msg_namelen = sizeof(sa.in6);
867
868 if (ifindex > 0) {
869 struct cmsghdr *cmsg;
870 struct in6_pktinfo *pi;
871
872 zero(control);
873
1716f6dc 874 mh.msg_control = &control;
74b2466e
LP
875 mh.msg_controllen = CMSG_LEN(sizeof(struct in6_pktinfo));
876
877 cmsg = CMSG_FIRSTHDR(&mh);
878 cmsg->cmsg_len = mh.msg_controllen;
879 cmsg->cmsg_level = IPPROTO_IPV6;
880 cmsg->cmsg_type = IPV6_PKTINFO;
881
882 pi = (struct in6_pktinfo*) CMSG_DATA(cmsg);
883 pi->ipi6_ifindex = ifindex;
884 }
885
886 return sendmsg_loop(fd, &mh, 0);
887}
888
623a4c97 889int manager_send(Manager *m, int fd, int ifindex, int family, const union in_addr_union *addr, uint16_t port, DnsPacket *p) {
1716f6dc
LP
890 assert(m);
891 assert(fd >= 0);
892 assert(addr);
893 assert(port > 0);
894 assert(p);
895
deb3f3d3 896 log_debug("Sending %s packet with id %" PRIu16 " on interface %i/%s.", DNS_PACKET_QR(p) ? "response" : "query", DNS_PACKET_ID(p), ifindex, af_to_name(family));
a2a416f7 897
1716f6dc
LP
898 if (family == AF_INET)
899 return manager_ipv4_send(m, fd, ifindex, &addr->in, port, p);
900 else if (family == AF_INET6)
901 return manager_ipv6_send(m, fd, ifindex, &addr->in6, port, p);
902
903 return -EAFNOSUPPORT;
904}
905
e1c95994
LP
906uint32_t manager_find_mtu(Manager *m) {
907 uint32_t mtu = 0;
908 Link *l;
909 Iterator i;
910
911 /* If we don't know on which link a DNS packet would be
912 * delivered, let's find the largest MTU that works on all
913 * interfaces we know of */
914
915 HASHMAP_FOREACH(l, m->links, i) {
916 if (l->mtu <= 0)
917 continue;
918
919 if (mtu <= 0 || l->mtu < mtu)
920 mtu = l->mtu;
921 }
922
923 return mtu;
924}
1716f6dc 925
623a4c97 926int manager_find_ifindex(Manager *m, int family, const union in_addr_union *in_addr) {
ec2c5e43
LP
927 LinkAddress *a;
928
929 assert(m);
930
4e945a6f 931 a = manager_find_link_address(m, family, in_addr);
ec2c5e43
LP
932 if (a)
933 return a->link->ifindex;
934
935 return 0;
936}
937
eb60f9cd
LP
938void manager_refresh_rrs(Manager *m) {
939 Iterator i;
940 Link *l;
941
942 assert(m);
943
78c6a153
LP
944 m->llmnr_host_ipv4_key = dns_resource_key_unref(m->llmnr_host_ipv4_key);
945 m->llmnr_host_ipv6_key = dns_resource_key_unref(m->llmnr_host_ipv6_key);
eb60f9cd
LP
946
947 HASHMAP_FOREACH(l, m->links, i) {
948 link_add_rrs(l, true);
949 link_add_rrs(l, false);
950 }
951}
952
ec2c5e43
LP
953int manager_next_hostname(Manager *m) {
954 const char *p;
556a2294 955 uint64_t u, a;
78c6a153
LP
956 char *h, *k;
957 int r;
623a4c97
LP
958
959 assert(m);
960
78c6a153 961 p = strchr(m->llmnr_hostname, 0);
ec2c5e43
LP
962 assert(p);
963
78c6a153 964 while (p > m->llmnr_hostname) {
ec2c5e43
LP
965 if (!strchr("0123456789", p[-1]))
966 break;
967
968 p--;
969 }
970
971 if (*p == 0 || safe_atou64(p, &u) < 0 || u <= 0)
972 u = 1;
973
556a2294
LP
974 /* Add a random number to the old value. This way we can avoid
975 * that two hosts pick the same hostname, win on IPv4 and lose
976 * on IPv6 (or vice versa), and pick the same hostname
977 * replacement hostname, ad infinitum. We still want the
978 * numbers to go up monotonically, hence we just add a random
979 * value 1..10 */
980
981 random_bytes(&a, sizeof(a));
982 u += 1 + a % 10;
ec2c5e43 983
78c6a153 984 if (asprintf(&h, "%.*s%" PRIu64, (int) (p - m->llmnr_hostname), m->llmnr_hostname, u) < 0)
ec2c5e43
LP
985 return -ENOMEM;
986
78c6a153
LP
987 r = dns_name_concat(h, "local", &k);
988 if (r < 0) {
989 free(h);
990 return r;
991 }
992
993 log_info("Hostname conflict, changing published hostname from '%s' to '%s'.", m->llmnr_hostname, h);
994
995 free(m->llmnr_hostname);
996 m->llmnr_hostname = h;
ec2c5e43 997
78c6a153
LP
998 free(m->mdns_hostname);
999 m->mdns_hostname = k;
ec2c5e43 1000
eb60f9cd 1001 manager_refresh_rrs(m);
623a4c97
LP
1002
1003 return 0;
1004}
ec2c5e43 1005
4e945a6f 1006LinkAddress* manager_find_link_address(Manager *m, int family, const union in_addr_union *in_addr) {
ec2c5e43
LP
1007 Iterator i;
1008 Link *l;
1009
1010 assert(m);
1011
1012 HASHMAP_FOREACH(l, m->links, i) {
1013 LinkAddress *a;
1014
1015 a = link_find_address(l, family, in_addr);
1016 if (a)
1017 return a;
1018 }
1019
1020 return NULL;
1021}
1022
a4076574 1023bool manager_our_packet(Manager *m, DnsPacket *p) {
ec2c5e43
LP
1024 assert(m);
1025 assert(p);
1026
4e945a6f 1027 return !!manager_find_link_address(m, p->family, &p->sender);
ec2c5e43 1028}
4e945a6f 1029
a4076574
LP
1030DnsScope* manager_find_scope(Manager *m, DnsPacket *p) {
1031 Link *l;
1032
1033 assert(m);
1034 assert(p);
1035
1036 l = hashmap_get(m->links, INT_TO_PTR(p->ifindex));
1037 if (!l)
1038 return NULL;
1039
b4f1862d
DM
1040 switch (p->protocol) {
1041 case DNS_PROTOCOL_LLMNR:
a4076574
LP
1042 if (p->family == AF_INET)
1043 return l->llmnr_ipv4_scope;
1044 else if (p->family == AF_INET6)
1045 return l->llmnr_ipv6_scope;
b4f1862d
DM
1046
1047 break;
1048
1049 case DNS_PROTOCOL_MDNS:
1050 if (p->family == AF_INET)
1051 return l->mdns_ipv4_scope;
1052 else if (p->family == AF_INET6)
1053 return l->mdns_ipv6_scope;
1054
1055 break;
1056
1057 default:
1058 break;
a4076574
LP
1059 }
1060
1061 return NULL;
1062}
1063
902bb5d8
LP
1064void manager_verify_all(Manager *m) {
1065 DnsScope *s;
1066
1067 assert(m);
1068
1069 LIST_FOREACH(scopes, s, m->dns_scopes)
1070 dns_zone_verify_all(&s->zone);
1071}
1072
78c6a153 1073int manager_is_own_hostname(Manager *m, const char *name) {
78c6a153
LP
1074 int r;
1075
1076 assert(m);
1077 assert(name);
1078
1079 if (m->llmnr_hostname) {
1080 r = dns_name_equal(name, m->llmnr_hostname);
1081 if (r != 0)
1082 return r;
1083 }
1084
1085 if (m->mdns_hostname)
1086 return dns_name_equal(name, m->mdns_hostname);
1087
1088 return 0;
1089}
1090
9176a57c
LP
1091int manager_compile_dns_servers(Manager *m, OrderedSet **dns) {
1092 DnsServer *s;
1093 Iterator i;
1094 Link *l;
1095 int r;
1096
1097 assert(m);
1098 assert(dns);
1099
1100 r = ordered_set_ensure_allocated(dns, &dns_server_hash_ops);
1101 if (r < 0)
1102 return r;
1103
1104 /* First add the system-wide servers and domains */
1105 LIST_FOREACH(servers, s, m->dns_servers) {
1106 r = ordered_set_put(*dns, s);
1107 if (r == -EEXIST)
1108 continue;
1109 if (r < 0)
1110 return r;
1111 }
1112
1113 /* Then, add the per-link servers */
1114 HASHMAP_FOREACH(l, m->links, i) {
1115 LIST_FOREACH(servers, s, l->dns_servers) {
1116 r = ordered_set_put(*dns, s);
1117 if (r == -EEXIST)
1118 continue;
1119 if (r < 0)
1120 return r;
1121 }
1122 }
1123
1124 /* If we found nothing, add the fallback servers */
1125 if (ordered_set_isempty(*dns)) {
1126 LIST_FOREACH(servers, s, m->fallback_dns_servers) {
1127 r = ordered_set_put(*dns, s);
1128 if (r == -EEXIST)
1129 continue;
1130 if (r < 0)
1131 return r;
1132 }
1133 }
1134
1135 return 0;
1136}
1137
1138int manager_compile_search_domains(Manager *m, OrderedSet **domains) {
1139 DnsSearchDomain *d;
1140 Iterator i;
1141 Link *l;
1142 int r;
1143
1144 assert(m);
1145 assert(domains);
1146
1147 r = ordered_set_ensure_allocated(domains, &dns_name_hash_ops);
1148 if (r < 0)
1149 return r;
1150
1151 LIST_FOREACH(domains, d, m->search_domains) {
1152 r = ordered_set_put(*domains, d->name);
1153 if (r == -EEXIST)
1154 continue;
1155 if (r < 0)
1156 return r;
1157 }
1158
1159 HASHMAP_FOREACH(l, m->links, i) {
1160
1161 LIST_FOREACH(domains, d, l->search_domains) {
1162 r = ordered_set_put(*domains, d->name);
1163 if (r == -EEXIST)
1164 continue;
1165 if (r < 0)
1166 return r;
1167 }
1168 }
1169
1170 return 0;
1171}