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