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