]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/resolve/resolved-manager.c
journal-cat: don't allocate memory for the syslog identifier
[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
2d895038 209 r = sd_netlink_attach_event(m->rtnl, m->event, SD_EVENT_PRIORITY_IMPORTANT);
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)
77abf3c1 291 log_warning_errno(r, "Could not update "PRIVATE_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)
2d895038
LP
315 return r;
316
317 r = sd_event_source_set_priority(m->network_event_source, SD_EVENT_PRIORITY_IMPORTANT+5);
318 if (r < 0)
74b2466e
LP
319 return r;
320
aa4a9deb
LP
321 (void) sd_event_source_set_description(m->network_event_source, "network-monitor");
322
74b2466e
LP
323 return 0;
324}
325
78c6a153 326static int determine_hostname(char **llmnr_hostname, char **mdns_hostname) {
eb60f9cd 327 _cleanup_free_ char *h = NULL, *n = NULL;
78c6a153
LP
328 char label[DNS_LABEL_MAX];
329 const char *p;
330 int r, k;
eb60f9cd 331
78c6a153
LP
332 assert(llmnr_hostname);
333 assert(mdns_hostname);
334
335 /* Extract and normalize the first label of the locally
336 * configured hostname, and check it's not "localhost". */
eb60f9cd
LP
337
338 h = gethostname_malloc();
339 if (!h)
340 return log_oom();
341
78c6a153
LP
342 p = h;
343 r = dns_label_unescape(&p, label, sizeof(label));
344 if (r < 0)
345 return log_error_errno(r, "Failed to unescape host name: %m");
346 if (r == 0) {
347 log_error("Couldn't find a single label in hosntame.");
348 return -EINVAL;
349 }
350
351 k = dns_label_undo_idna(label, r, label, sizeof(label));
352 if (k < 0)
353 return log_error_errno(k, "Failed to undo IDNA: %m");
354 if (k > 0)
355 r = k;
356
357 if (!utf8_is_valid(label)) {
eb60f9cd
LP
358 log_error("System hostname is not UTF-8 clean.");
359 return -EINVAL;
360 }
361
422baca0 362 r = dns_label_escape_new(label, r, &n);
78c6a153
LP
363 if (r < 0)
364 return log_error_errno(r, "Failed to escape host name: %m");
365
366 if (is_localhost(n)) {
367 log_debug("System hostname is 'localhost', ignoring.");
368 return -EINVAL;
eb60f9cd
LP
369 }
370
78c6a153
LP
371 r = dns_name_concat(n, "local", mdns_hostname);
372 if (r < 0)
373 return log_error_errno(r, "Failed to determine mDNS hostname: %m");
374
375 *llmnr_hostname = n;
eb60f9cd
LP
376 n = NULL;
377
378 return 0;
379}
380
381static int on_hostname_change(sd_event_source *es, int fd, uint32_t revents, void *userdata) {
78c6a153 382 _cleanup_free_ char *llmnr_hostname = NULL, *mdns_hostname = NULL;
eb60f9cd
LP
383 Manager *m = userdata;
384 int r;
385
386 assert(m);
387
78c6a153 388 r = determine_hostname(&llmnr_hostname, &mdns_hostname);
eb60f9cd
LP
389 if (r < 0)
390 return 0; /* ignore invalid hostnames */
391
78c6a153 392 if (streq(llmnr_hostname, m->llmnr_hostname) && streq(mdns_hostname, m->mdns_hostname))
eb60f9cd
LP
393 return 0;
394
78c6a153
LP
395 log_info("System hostname changed to '%s'.", llmnr_hostname);
396
397 free(m->llmnr_hostname);
398 free(m->mdns_hostname);
399
400 m->llmnr_hostname = llmnr_hostname;
401 m->mdns_hostname = mdns_hostname;
402
403 llmnr_hostname = mdns_hostname = NULL;
eb60f9cd
LP
404
405 manager_refresh_rrs(m);
406
407 return 0;
408}
409
410static int manager_watch_hostname(Manager *m) {
eb60f9cd
LP
411 int r;
412
413 assert(m);
414
415 m->hostname_fd = open("/proc/sys/kernel/hostname", O_RDONLY|O_CLOEXEC|O_NDELAY|O_NOCTTY);
416 if (m->hostname_fd < 0) {
56f64d95 417 log_warning_errno(errno, "Failed to watch hostname: %m");
eb60f9cd
LP
418 return 0;
419 }
420
421 r = sd_event_add_io(m->event, &m->hostname_event_source, m->hostname_fd, 0, on_hostname_change, m);
422 if (r < 0) {
423 if (r == -EPERM)
424 /* kernels prior to 3.2 don't support polling this file. Ignore the failure. */
425 m->hostname_fd = safe_close(m->hostname_fd);
8d3d7072
MS
426 else
427 return log_error_errno(r, "Failed to add hostname event source: %m");
eb60f9cd
LP
428 }
429
aa4a9deb
LP
430 (void) sd_event_source_set_description(m->hostname_event_source, "hostname");
431
78c6a153 432 r = determine_hostname(&m->llmnr_hostname, &m->mdns_hostname);
eb60f9cd
LP
433 if (r < 0) {
434 log_info("Defaulting to hostname 'linux'.");
78c6a153
LP
435 m->llmnr_hostname = strdup("linux");
436 if (!m->llmnr_hostname)
437 return log_oom();
438
439 m->mdns_hostname = strdup("linux.local");
440 if (!m->mdns_hostname)
eb60f9cd
LP
441 return log_oom();
442 } else
78c6a153 443 log_info("Using system hostname '%s'.", m->llmnr_hostname);
eb60f9cd
LP
444
445 return 0;
446}
447
4d506d6b
LP
448static int manager_sigusr1(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
449 _cleanup_free_ char *buffer = NULL;
450 _cleanup_fclose_ FILE *f = NULL;
451 Manager *m = userdata;
452 size_t size = 0;
453 DnsScope *scope;
454
455 assert(s);
456 assert(si);
457 assert(m);
458
459 f = open_memstream(&buffer, &size);
460 if (!f)
461 return log_oom();
462
463 LIST_FOREACH(scopes, scope, m->dns_scopes)
464 dns_scope_dump(scope, f);
465
466 if (fflush_and_check(f) < 0)
467 return log_oom();
468
469 log_dump(LOG_INFO, buffer);
470 return 0;
471}
472
091a364c 473int manager_new(Manager **ret) {
74b2466e 474 _cleanup_(manager_freep) Manager *m = NULL;
091a364c
TG
475 int r;
476
c92e531c
LP
477 assert(ret);
478
091a364c
TG
479 m = new0(Manager, 1);
480 if (!m)
481 return -ENOMEM;
482
1716f6dc 483 m->llmnr_ipv4_udp_fd = m->llmnr_ipv6_udp_fd = -1;
623a4c97 484 m->llmnr_ipv4_tcp_fd = m->llmnr_ipv6_tcp_fd = -1;
bc7702b0 485 m->mdns_ipv4_fd = m->mdns_ipv6_fd = -1;
eb60f9cd 486 m->hostname_fd = -1;
1716f6dc 487
af49ca27 488 m->llmnr_support = RESOLVE_SUPPORT_YES;
ad6c0475
LP
489 m->mdns_support = RESOLVE_SUPPORT_NO;
490 m->dnssec_mode = DNSSEC_NO;
5cb36f41 491 m->read_resolv_conf = true;
00fa60ae 492 m->need_builtin_fallbacks = true;
dd0bc0f1 493 m->etc_hosts_last = m->etc_hosts_mtime = USEC_INFINITY;
091a364c 494
0d2cd476
LP
495 r = dns_trust_anchor_load(&m->trust_anchor);
496 if (r < 0)
497 return r;
498
ad6c0475
LP
499 r = manager_parse_config_file(m);
500 if (r < 0)
501 return r;
502
091a364c
TG
503 r = sd_event_default(&m->event);
504 if (r < 0)
505 return r;
506
507 sd_event_add_signal(m->event, NULL, SIGTERM, NULL, NULL);
508 sd_event_add_signal(m->event, NULL, SIGINT, NULL, NULL);
509
510 sd_event_set_watchdog(m->event, true);
511
eb60f9cd
LP
512 r = manager_watch_hostname(m);
513 if (r < 0)
514 return r;
515
1716f6dc 516 r = dns_scope_new(m, &m->unicast_scope, NULL, DNS_PROTOCOL_DNS, AF_UNSPEC);
74b2466e
LP
517 if (r < 0)
518 return r;
519
520 r = manager_network_monitor_listen(m);
521 if (r < 0)
522 return r;
523
524 r = manager_rtnl_listen(m);
525 if (r < 0)
526 return r;
527
528 r = manager_connect_bus(m);
529 if (r < 0)
530 return r;
531
4d506d6b
LP
532 (void) sd_event_add_signal(m->event, &m->sigusr1_event_source, SIGUSR1, manager_sigusr1, m);
533
091a364c
TG
534 *ret = m;
535 m = NULL;
536
537 return 0;
538}
539
edc501d4
LP
540int manager_start(Manager *m) {
541 int r;
542
543 assert(m);
544
545 r = manager_llmnr_start(m);
546 if (r < 0)
547 return r;
548
bc7702b0
DM
549 r = manager_mdns_start(m);
550 if (r < 0)
551 return r;
552
edc501d4
LP
553 return 0;
554}
555
74b2466e
LP
556Manager *manager_free(Manager *m) {
557 Link *l;
091a364c
TG
558
559 if (!m)
74b2466e
LP
560 return NULL;
561
4b95f179
LP
562 dns_server_unlink_all(m->dns_servers);
563 dns_server_unlink_all(m->fallback_dns_servers);
a51c1048
LP
564 dns_search_domain_unlink_all(m->search_domains);
565
74b2466e
LP
566 while ((l = hashmap_first(m->links)))
567 link_free(l);
f0e15467
LP
568
569 while (m->dns_queries)
570 dns_query_free(m->dns_queries);
74b2466e 571
cab5b059
LP
572 dns_scope_free(m->unicast_scope);
573
f0e15467
LP
574 hashmap_free(m->links);
575 hashmap_free(m->dns_transactions);
576
096b6773
LP
577 sd_event_source_unref(m->network_event_source);
578 sd_network_monitor_unref(m->network_monitor);
091a364c 579
a564ca2f
LP
580 sd_netlink_unref(m->rtnl);
581 sd_event_source_unref(m->rtnl_event_source);
582
edc501d4 583 manager_llmnr_stop(m);
bc7702b0 584 manager_mdns_stop(m);
623a4c97 585
902bb5d8 586 sd_bus_slot_unref(m->prepare_for_sleep_slot);
74b2466e
LP
587 sd_event_source_unref(m->bus_retry_event_source);
588 sd_bus_unref(m->bus);
091a364c 589
4d506d6b
LP
590 sd_event_source_unref(m->sigusr1_event_source);
591
74b2466e 592 sd_event_unref(m->event);
623a4c97 593
78c6a153
LP
594 dns_resource_key_unref(m->llmnr_host_ipv4_key);
595 dns_resource_key_unref(m->llmnr_host_ipv6_key);
eb60f9cd 596
eb60f9cd 597 sd_event_source_unref(m->hostname_event_source);
d9fcf2ba 598 safe_close(m->hostname_fd);
78c6a153
LP
599 free(m->llmnr_hostname);
600 free(m->mdns_hostname);
eb60f9cd 601
0d2cd476 602 dns_trust_anchor_flush(&m->trust_anchor);
dd0bc0f1 603 manager_etc_hosts_flush(m);
0d2cd476 604
091a364c 605 free(m);
74b2466e
LP
606
607 return NULL;
091a364c
TG
608}
609
1716f6dc 610int manager_recv(Manager *m, int fd, DnsProtocol protocol, DnsPacket **ret) {
74b2466e 611 _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
1716f6dc
LP
612 union {
613 struct cmsghdr header; /* For alignment */
40a1eebd 614 uint8_t buffer[CMSG_SPACE(MAXSIZE(struct in_pktinfo, struct in6_pktinfo))
1716f6dc 615 + CMSG_SPACE(int) /* ttl/hoplimit */
623a4c97 616 + EXTRA_CMSG_SPACE /* kernel appears to require extra buffer space */];
1716f6dc
LP
617 } control;
618 union sockaddr_union sa;
74b2466e 619 struct msghdr mh = {};
1716f6dc 620 struct cmsghdr *cmsg;
74b2466e 621 struct iovec iov;
1716f6dc 622 int ms = 0, r;
74b2466e
LP
623 ssize_t l;
624
625 assert(m);
1716f6dc 626 assert(fd >= 0);
74b2466e
LP
627 assert(ret);
628
74b2466e
LP
629 r = ioctl(fd, FIONREAD, &ms);
630 if (r < 0)
631 return -errno;
632 if (ms < 0)
633 return -EIO;
634
1716f6dc 635 r = dns_packet_new(&p, protocol, ms);
74b2466e
LP
636 if (r < 0)
637 return r;
638
639 iov.iov_base = DNS_PACKET_DATA(p);
640 iov.iov_len = p->allocated;
641
1716f6dc
LP
642 mh.msg_name = &sa.sa;
643 mh.msg_namelen = sizeof(sa);
74b2466e
LP
644 mh.msg_iov = &iov;
645 mh.msg_iovlen = 1;
1716f6dc
LP
646 mh.msg_control = &control;
647 mh.msg_controllen = sizeof(control);
74b2466e 648
a38d9945 649 l = recvmsg(fd, &mh, 0);
74b2466e 650 if (l < 0) {
ad867662 651 if (errno == EAGAIN || errno == EINTR)
74b2466e
LP
652 return 0;
653
654 return -errno;
091a364c
TG
655 }
656
74b2466e
LP
657 if (l <= 0)
658 return -EIO;
091a364c 659
1716f6dc
LP
660 assert(!(mh.msg_flags & MSG_CTRUNC));
661 assert(!(mh.msg_flags & MSG_TRUNC));
662
74b2466e 663 p->size = (size_t) l;
091a364c 664
1716f6dc 665 p->family = sa.sa.sa_family;
623a4c97
LP
666 p->ipproto = IPPROTO_UDP;
667 if (p->family == AF_INET) {
1716f6dc 668 p->sender.in = sa.in.sin_addr;
623a4c97
LP
669 p->sender_port = be16toh(sa.in.sin_port);
670 } else if (p->family == AF_INET6) {
1716f6dc 671 p->sender.in6 = sa.in6.sin6_addr;
623a4c97
LP
672 p->sender_port = be16toh(sa.in6.sin6_port);
673 p->ifindex = sa.in6.sin6_scope_id;
674 } else
1716f6dc 675 return -EAFNOSUPPORT;
74b2466e 676
2a1288ff 677 CMSG_FOREACH(cmsg, &mh) {
74b2466e 678
1716f6dc
LP
679 if (cmsg->cmsg_level == IPPROTO_IPV6) {
680 assert(p->family == AF_INET6);
74b2466e 681
1716f6dc 682 switch (cmsg->cmsg_type) {
74b2466e 683
1716f6dc
LP
684 case IPV6_PKTINFO: {
685 struct in6_pktinfo *i = (struct in6_pktinfo*) CMSG_DATA(cmsg);
74b2466e 686
623a4c97
LP
687 if (p->ifindex <= 0)
688 p->ifindex = i->ipi6_ifindex;
689
1716f6dc
LP
690 p->destination.in6 = i->ipi6_addr;
691 break;
692 }
74b2466e 693
1716f6dc
LP
694 case IPV6_HOPLIMIT:
695 p->ttl = *(int *) CMSG_DATA(cmsg);
696 break;
74b2466e 697
1716f6dc
LP
698 }
699 } else if (cmsg->cmsg_level == IPPROTO_IP) {
700 assert(p->family == AF_INET);
74b2466e 701
1716f6dc 702 switch (cmsg->cmsg_type) {
74b2466e 703
1716f6dc
LP
704 case IP_PKTINFO: {
705 struct in_pktinfo *i = (struct in_pktinfo*) CMSG_DATA(cmsg);
091a364c 706
623a4c97
LP
707 if (p->ifindex <= 0)
708 p->ifindex = i->ipi_ifindex;
709
1716f6dc
LP
710 p->destination.in = i->ipi_addr;
711 break;
712 }
74b2466e 713
623a4c97 714 case IP_TTL:
1716f6dc
LP
715 p->ttl = *(int *) CMSG_DATA(cmsg);
716 break;
717 }
718 }
719 }
74b2466e 720
623a4c97
LP
721 /* The Linux kernel sets the interface index to the loopback
722 * device if the packet came from the local host since it
723 * avoids the routing table in such a case. Let's unset the
724 * interface index in such a case. */
a5f03596 725 if (p->ifindex == LOOPBACK_IFINDEX)
623a4c97
LP
726 p->ifindex = 0;
727
86ad4cd7
TG
728 if (protocol != DNS_PROTOCOL_DNS) {
729 /* If we don't know the interface index still, we look for the
730 * first local interface with a matching address. Yuck! */
731 if (p->ifindex <= 0)
732 p->ifindex = manager_find_ifindex(m, p->family, &p->destination);
733 }
623a4c97 734
74b2466e
LP
735 *ret = p;
736 p = NULL;
737
738 return 1;
739}
740
74b2466e
LP
741static int sendmsg_loop(int fd, struct msghdr *mh, int flags) {
742 int r;
743
744 assert(fd >= 0);
745 assert(mh);
746
747 for (;;) {
748 if (sendmsg(fd, mh, flags) >= 0)
749 return 0;
750
751 if (errno == EINTR)
752 continue;
753
754 if (errno != EAGAIN)
755 return -errno;
756
757 r = fd_wait_for_event(fd, POLLOUT, SEND_TIMEOUT_USEC);
758 if (r < 0)
759 return r;
760 if (r == 0)
761 return -ETIMEDOUT;
762 }
763}
764
72290734
TG
765static int write_loop(int fd, void *message, size_t length) {
766 int r;
767
768 assert(fd >= 0);
769 assert(message);
770
771 for (;;) {
772 if (write(fd, message, length) >= 0)
773 return 0;
774
775 if (errno == EINTR)
776 continue;
777
778 if (errno != EAGAIN)
779 return -errno;
780
781 r = fd_wait_for_event(fd, POLLOUT, SEND_TIMEOUT_USEC);
782 if (r < 0)
783 return r;
784 if (r == 0)
785 return -ETIMEDOUT;
786 }
787}
788
789int manager_write(Manager *m, int fd, DnsPacket *p) {
790 int r;
791
deb3f3d3 792 log_debug("Sending %s packet with id %" PRIu16 ".", DNS_PACKET_QR(p) ? "response" : "query", DNS_PACKET_ID(p));
72290734
TG
793
794 r = write_loop(fd, DNS_PACKET_DATA(p), p->size);
795 if (r < 0)
796 return r;
797
798 return 0;
799}
800
623a4c97 801static int manager_ipv4_send(Manager *m, int fd, int ifindex, const struct in_addr *addr, uint16_t port, DnsPacket *p) {
74b2466e
LP
802 union sockaddr_union sa = {
803 .in.sin_family = AF_INET,
74b2466e 804 };
1716f6dc
LP
805 union {
806 struct cmsghdr header; /* For alignment */
807 uint8_t buffer[CMSG_SPACE(sizeof(struct in_pktinfo))];
808 } control;
74b2466e
LP
809 struct msghdr mh = {};
810 struct iovec iov;
74b2466e
LP
811
812 assert(m);
1716f6dc
LP
813 assert(fd >= 0);
814 assert(addr);
815 assert(port > 0);
74b2466e
LP
816 assert(p);
817
74b2466e
LP
818 iov.iov_base = DNS_PACKET_DATA(p);
819 iov.iov_len = p->size;
091a364c 820
1716f6dc
LP
821 sa.in.sin_addr = *addr;
822 sa.in.sin_port = htobe16(port),
091a364c 823
74b2466e
LP
824 mh.msg_iov = &iov;
825 mh.msg_iovlen = 1;
826 mh.msg_name = &sa.sa;
827 mh.msg_namelen = sizeof(sa.in);
091a364c 828
74b2466e
LP
829 if (ifindex > 0) {
830 struct cmsghdr *cmsg;
831 struct in_pktinfo *pi;
832
833 zero(control);
834
1716f6dc 835 mh.msg_control = &control;
74b2466e
LP
836 mh.msg_controllen = CMSG_LEN(sizeof(struct in_pktinfo));
837
838 cmsg = CMSG_FIRSTHDR(&mh);
839 cmsg->cmsg_len = mh.msg_controllen;
840 cmsg->cmsg_level = IPPROTO_IP;
841 cmsg->cmsg_type = IP_PKTINFO;
842
843 pi = (struct in_pktinfo*) CMSG_DATA(cmsg);
844 pi->ipi_ifindex = ifindex;
845 }
846
847 return sendmsg_loop(fd, &mh, 0);
848}
849
623a4c97 850static int manager_ipv6_send(Manager *m, int fd, int ifindex, const struct in6_addr *addr, uint16_t port, DnsPacket *p) {
74b2466e
LP
851 union sockaddr_union sa = {
852 .in6.sin6_family = AF_INET6,
74b2466e 853 };
1716f6dc
LP
854 union {
855 struct cmsghdr header; /* For alignment */
856 uint8_t buffer[CMSG_SPACE(sizeof(struct in6_pktinfo))];
857 } control;
74b2466e
LP
858 struct msghdr mh = {};
859 struct iovec iov;
74b2466e
LP
860
861 assert(m);
1716f6dc
LP
862 assert(fd >= 0);
863 assert(addr);
864 assert(port > 0);
74b2466e
LP
865 assert(p);
866
74b2466e
LP
867 iov.iov_base = DNS_PACKET_DATA(p);
868 iov.iov_len = p->size;
869
1716f6dc
LP
870 sa.in6.sin6_addr = *addr;
871 sa.in6.sin6_port = htobe16(port),
74b2466e
LP
872 sa.in6.sin6_scope_id = ifindex;
873
874 mh.msg_iov = &iov;
875 mh.msg_iovlen = 1;
876 mh.msg_name = &sa.sa;
877 mh.msg_namelen = sizeof(sa.in6);
878
879 if (ifindex > 0) {
880 struct cmsghdr *cmsg;
881 struct in6_pktinfo *pi;
882
883 zero(control);
884
1716f6dc 885 mh.msg_control = &control;
74b2466e
LP
886 mh.msg_controllen = CMSG_LEN(sizeof(struct in6_pktinfo));
887
888 cmsg = CMSG_FIRSTHDR(&mh);
889 cmsg->cmsg_len = mh.msg_controllen;
890 cmsg->cmsg_level = IPPROTO_IPV6;
891 cmsg->cmsg_type = IPV6_PKTINFO;
892
893 pi = (struct in6_pktinfo*) CMSG_DATA(cmsg);
894 pi->ipi6_ifindex = ifindex;
895 }
896
897 return sendmsg_loop(fd, &mh, 0);
898}
899
623a4c97 900int manager_send(Manager *m, int fd, int ifindex, int family, const union in_addr_union *addr, uint16_t port, DnsPacket *p) {
1716f6dc
LP
901 assert(m);
902 assert(fd >= 0);
903 assert(addr);
904 assert(port > 0);
905 assert(p);
906
deb3f3d3 907 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 908
1716f6dc
LP
909 if (family == AF_INET)
910 return manager_ipv4_send(m, fd, ifindex, &addr->in, port, p);
911 else if (family == AF_INET6)
912 return manager_ipv6_send(m, fd, ifindex, &addr->in6, port, p);
913
914 return -EAFNOSUPPORT;
915}
916
e1c95994
LP
917uint32_t manager_find_mtu(Manager *m) {
918 uint32_t mtu = 0;
919 Link *l;
920 Iterator i;
921
922 /* If we don't know on which link a DNS packet would be
923 * delivered, let's find the largest MTU that works on all
924 * interfaces we know of */
925
926 HASHMAP_FOREACH(l, m->links, i) {
927 if (l->mtu <= 0)
928 continue;
929
930 if (mtu <= 0 || l->mtu < mtu)
931 mtu = l->mtu;
932 }
933
934 return mtu;
935}
1716f6dc 936
623a4c97 937int manager_find_ifindex(Manager *m, int family, const union in_addr_union *in_addr) {
ec2c5e43
LP
938 LinkAddress *a;
939
940 assert(m);
941
4e945a6f 942 a = manager_find_link_address(m, family, in_addr);
ec2c5e43
LP
943 if (a)
944 return a->link->ifindex;
945
946 return 0;
947}
948
eb60f9cd
LP
949void manager_refresh_rrs(Manager *m) {
950 Iterator i;
951 Link *l;
952
953 assert(m);
954
78c6a153
LP
955 m->llmnr_host_ipv4_key = dns_resource_key_unref(m->llmnr_host_ipv4_key);
956 m->llmnr_host_ipv6_key = dns_resource_key_unref(m->llmnr_host_ipv6_key);
eb60f9cd
LP
957
958 HASHMAP_FOREACH(l, m->links, i) {
959 link_add_rrs(l, true);
960 link_add_rrs(l, false);
961 }
962}
963
ec2c5e43
LP
964int manager_next_hostname(Manager *m) {
965 const char *p;
556a2294 966 uint64_t u, a;
78c6a153
LP
967 char *h, *k;
968 int r;
623a4c97
LP
969
970 assert(m);
971
78c6a153 972 p = strchr(m->llmnr_hostname, 0);
ec2c5e43
LP
973 assert(p);
974
78c6a153 975 while (p > m->llmnr_hostname) {
ec2c5e43
LP
976 if (!strchr("0123456789", p[-1]))
977 break;
978
979 p--;
980 }
981
982 if (*p == 0 || safe_atou64(p, &u) < 0 || u <= 0)
983 u = 1;
984
556a2294
LP
985 /* Add a random number to the old value. This way we can avoid
986 * that two hosts pick the same hostname, win on IPv4 and lose
987 * on IPv6 (or vice versa), and pick the same hostname
988 * replacement hostname, ad infinitum. We still want the
989 * numbers to go up monotonically, hence we just add a random
990 * value 1..10 */
991
992 random_bytes(&a, sizeof(a));
993 u += 1 + a % 10;
ec2c5e43 994
78c6a153 995 if (asprintf(&h, "%.*s%" PRIu64, (int) (p - m->llmnr_hostname), m->llmnr_hostname, u) < 0)
ec2c5e43
LP
996 return -ENOMEM;
997
78c6a153
LP
998 r = dns_name_concat(h, "local", &k);
999 if (r < 0) {
1000 free(h);
1001 return r;
1002 }
1003
1004 log_info("Hostname conflict, changing published hostname from '%s' to '%s'.", m->llmnr_hostname, h);
1005
1006 free(m->llmnr_hostname);
1007 m->llmnr_hostname = h;
ec2c5e43 1008
78c6a153
LP
1009 free(m->mdns_hostname);
1010 m->mdns_hostname = k;
ec2c5e43 1011
eb60f9cd 1012 manager_refresh_rrs(m);
623a4c97
LP
1013
1014 return 0;
1015}
ec2c5e43 1016
4e945a6f 1017LinkAddress* manager_find_link_address(Manager *m, int family, const union in_addr_union *in_addr) {
ec2c5e43
LP
1018 Iterator i;
1019 Link *l;
1020
1021 assert(m);
1022
1023 HASHMAP_FOREACH(l, m->links, i) {
1024 LinkAddress *a;
1025
1026 a = link_find_address(l, family, in_addr);
1027 if (a)
1028 return a;
1029 }
1030
1031 return NULL;
1032}
1033
a4076574 1034bool manager_our_packet(Manager *m, DnsPacket *p) {
ec2c5e43
LP
1035 assert(m);
1036 assert(p);
1037
4e945a6f 1038 return !!manager_find_link_address(m, p->family, &p->sender);
ec2c5e43 1039}
4e945a6f 1040
a4076574
LP
1041DnsScope* manager_find_scope(Manager *m, DnsPacket *p) {
1042 Link *l;
1043
1044 assert(m);
1045 assert(p);
1046
1047 l = hashmap_get(m->links, INT_TO_PTR(p->ifindex));
1048 if (!l)
1049 return NULL;
1050
b4f1862d
DM
1051 switch (p->protocol) {
1052 case DNS_PROTOCOL_LLMNR:
a4076574
LP
1053 if (p->family == AF_INET)
1054 return l->llmnr_ipv4_scope;
1055 else if (p->family == AF_INET6)
1056 return l->llmnr_ipv6_scope;
b4f1862d
DM
1057
1058 break;
1059
1060 case DNS_PROTOCOL_MDNS:
1061 if (p->family == AF_INET)
1062 return l->mdns_ipv4_scope;
1063 else if (p->family == AF_INET6)
1064 return l->mdns_ipv6_scope;
1065
1066 break;
1067
1068 default:
1069 break;
a4076574
LP
1070 }
1071
1072 return NULL;
1073}
1074
902bb5d8
LP
1075void manager_verify_all(Manager *m) {
1076 DnsScope *s;
1077
1078 assert(m);
1079
1080 LIST_FOREACH(scopes, s, m->dns_scopes)
1081 dns_zone_verify_all(&s->zone);
1082}
1083
78c6a153 1084int manager_is_own_hostname(Manager *m, const char *name) {
78c6a153
LP
1085 int r;
1086
1087 assert(m);
1088 assert(name);
1089
1090 if (m->llmnr_hostname) {
1091 r = dns_name_equal(name, m->llmnr_hostname);
1092 if (r != 0)
1093 return r;
1094 }
1095
1096 if (m->mdns_hostname)
1097 return dns_name_equal(name, m->mdns_hostname);
1098
1099 return 0;
1100}
1101
9176a57c
LP
1102int manager_compile_dns_servers(Manager *m, OrderedSet **dns) {
1103 DnsServer *s;
1104 Iterator i;
1105 Link *l;
1106 int r;
1107
1108 assert(m);
1109 assert(dns);
1110
1111 r = ordered_set_ensure_allocated(dns, &dns_server_hash_ops);
1112 if (r < 0)
1113 return r;
1114
1115 /* First add the system-wide servers and domains */
1116 LIST_FOREACH(servers, s, m->dns_servers) {
1117 r = ordered_set_put(*dns, s);
1118 if (r == -EEXIST)
1119 continue;
1120 if (r < 0)
1121 return r;
1122 }
1123
1124 /* Then, add the per-link servers */
1125 HASHMAP_FOREACH(l, m->links, i) {
1126 LIST_FOREACH(servers, s, l->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 /* If we found nothing, add the fallback servers */
1136 if (ordered_set_isempty(*dns)) {
1137 LIST_FOREACH(servers, s, m->fallback_dns_servers) {
1138 r = ordered_set_put(*dns, s);
1139 if (r == -EEXIST)
1140 continue;
1141 if (r < 0)
1142 return r;
1143 }
1144 }
1145
1146 return 0;
1147}
1148
1149int manager_compile_search_domains(Manager *m, OrderedSet **domains) {
1150 DnsSearchDomain *d;
1151 Iterator i;
1152 Link *l;
1153 int r;
1154
1155 assert(m);
1156 assert(domains);
1157
1158 r = ordered_set_ensure_allocated(domains, &dns_name_hash_ops);
1159 if (r < 0)
1160 return r;
1161
1162 LIST_FOREACH(domains, d, m->search_domains) {
1163 r = ordered_set_put(*domains, d->name);
1164 if (r == -EEXIST)
1165 continue;
1166 if (r < 0)
1167 return r;
1168 }
1169
1170 HASHMAP_FOREACH(l, m->links, i) {
1171
1172 LIST_FOREACH(domains, d, l->search_domains) {
1173 r = ordered_set_put(*domains, d->name);
1174 if (r == -EEXIST)
1175 continue;
1176 if (r < 0)
1177 return r;
1178 }
1179 }
1180
1181 return 0;
1182}
c69fa7e3
LP
1183
1184DnssecMode manager_get_dnssec_mode(Manager *m) {
1185 assert(m);
1186
1187 if (m->dnssec_mode != _DNSSEC_MODE_INVALID)
1188 return m->dnssec_mode;
1189
1190 return DNSSEC_NO;
1191}
1192
1193bool manager_dnssec_supported(Manager *m) {
1194 DnsServer *server;
1195 Iterator i;
1196 Link *l;
1197
1198 assert(m);
1199
1200 if (manager_get_dnssec_mode(m) == DNSSEC_NO)
1201 return false;
1202
1203 server = manager_get_dns_server(m);
1204 if (server && !dns_server_dnssec_supported(server))
1205 return false;
1206
1207 HASHMAP_FOREACH(l, m->links, i)
1208 if (!link_dnssec_supported(l))
1209 return false;
1210
1211 return true;
1212}
59c5b597
LP
1213
1214void manager_dnssec_verdict(Manager *m, DnssecVerdict verdict, const DnsResourceKey *key) {
1215
1216 assert(verdict >= 0);
1217 assert(verdict < _DNSSEC_VERDICT_MAX);
1218
1219 if (log_get_max_level() >= LOG_DEBUG) {
1220 _cleanup_free_ char *s = NULL;
1221
1222 (void) dns_resource_key_to_string(key, &s);
1223
1224 log_debug("Found verdict for lookup %s: %s", s ? strstrip(s) : "n/a", dnssec_verdict_to_string(verdict));
1225 }
1226
1227 m->n_dnssec_verdict[verdict]++;
1228}