]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/resolve/resolved-manager.c
resolved: add a DNS client stub resolver
[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
22#include <arpa/inet.h>
23#include <resolv.h>
24#include <linux/if.h>
74b2466e
LP
25#include <sys/ioctl.h>
26#include <sys/poll.h>
27#include <netinet/in.h>
091a364c 28
74b2466e 29#include "rtnl-util.h"
091a364c
TG
30#include "event-util.h"
31#include "network-util.h"
32#include "sd-dhcp-lease.h"
33#include "dhcp-lease-internal.h"
34#include "network-internal.h"
35#include "conf-parser.h"
74b2466e
LP
36#include "socket-util.h"
37#include "resolved.h"
38
39#define SEND_TIMEOUT_USEC (200 * USEC_PER_MSEC)
40
41static int manager_process_link(sd_rtnl *rtnl, sd_rtnl_message *mm, void *userdata) {
42 Manager *m = userdata;
43 uint16_t type;
44 Link *l;
45 int ifindex, r;
46
47 assert(rtnl);
48 assert(m);
49 assert(mm);
50
51 r = sd_rtnl_message_get_type(mm, &type);
52 if (r < 0)
53 goto fail;
54
55 r = sd_rtnl_message_link_get_ifindex(mm, &ifindex);
56 if (r < 0)
57 goto fail;
58
59 l = hashmap_get(m->links, INT_TO_PTR(ifindex));
60
61 switch (type) {
62
63 case RTM_NEWLINK:
64 if (!l) {
65 log_debug("Found link %i", ifindex);
66
67 r = link_new(m, &l, ifindex);
68 if (r < 0)
69 goto fail;
70 }
71
72 r = link_update_rtnl(l, mm);
73 if (r < 0)
74 goto fail;
75
76 break;
77
78 case RTM_DELLINK:
79 if (l) {
80 log_debug("Removing link %i", l->ifindex);
81 link_free(l);
82 }
83
84 break;
85 }
86
87 return 0;
88
89fail:
90 log_warning("Failed to process RTNL link message: %s", strerror(-r));
91 return 0;
92}
93
94static int manager_process_address(sd_rtnl *rtnl, sd_rtnl_message *mm, void *userdata) {
95 Manager *m = userdata;
96 union in_addr_union address;
97 unsigned char family;
98 uint16_t type;
99 int r, ifindex;
100 LinkAddress *a;
101 Link *l;
102
103 assert(rtnl);
104 assert(mm);
105 assert(m);
106
107 r = sd_rtnl_message_get_type(mm, &type);
108 if (r < 0)
109 goto fail;
110
111 r = sd_rtnl_message_addr_get_ifindex(mm, &ifindex);
112 if (r < 0)
113 goto fail;
114
115 l = hashmap_get(m->links, INT_TO_PTR(ifindex));
116 if (!l)
117 return 0;
118
119 r = sd_rtnl_message_addr_get_family(mm, &family);
120 if (r < 0)
121 goto fail;
122
123 switch (family) {
124
125 case AF_INET:
126 r = sd_rtnl_message_read_in_addr(mm, IFA_LOCAL, &address.in);
127 if (r < 0) {
128 r = sd_rtnl_message_read_in_addr(mm, IFA_ADDRESS, &address.in);
129 if (r < 0)
130 goto fail;
131 }
132
133 break;
134
135 case AF_INET6:
136 r = sd_rtnl_message_read_in6_addr(mm, IFA_LOCAL, &address.in6);
137 if (r < 0) {
138 r = sd_rtnl_message_read_in6_addr(mm, IFA_ADDRESS, &address.in6);
139 if (r < 0)
140 goto fail;
141 }
142
143 break;
144
145 default:
146 return 0;
147 }
148
149 a = link_find_address(l, family, &address);
150
151 switch (type) {
152
153 case RTM_NEWADDR:
154
155 if (!a) {
156 r = link_address_new(l, &a, family, &address);
157 if (r < 0)
158 return r;
159 }
160
161 r = link_address_update_rtnl(a, mm);
162 if (r < 0)
163 return r;
164
165 break;
166
167 case RTM_DELADDR:
168 if (a)
169 link_address_free(a);
170 break;
171 }
172
173 return 0;
174
175fail:
176 log_warning("Failed to process RTNL address message: %s", strerror(-r));
177 return 0;
178}
179
180
181static int manager_rtnl_listen(Manager *m) {
182 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
183 sd_rtnl_message *i;
184 int r;
185
186 assert(m);
187
188 /* First, subscibe to interfaces coming and going */
189 r = sd_rtnl_open(&m->rtnl, 3, RTNLGRP_LINK, RTNLGRP_IPV4_IFADDR, RTNLGRP_IPV6_IFADDR);
190 if (r < 0)
191 return r;
192
193 r = sd_rtnl_attach_event(m->rtnl, m->event, 0);
194 if (r < 0)
195 return r;
196
197 r = sd_rtnl_add_match(m->rtnl, RTM_NEWLINK, manager_process_link, m);
198 if (r < 0)
199 return r;
200
201 r = sd_rtnl_add_match(m->rtnl, RTM_DELLINK, manager_process_link, m);
202 if (r < 0)
203 return r;
204
205 r = sd_rtnl_add_match(m->rtnl, RTM_NEWADDR, manager_process_address, m);
206 if (r < 0)
207 return r;
091a364c 208
74b2466e
LP
209 r = sd_rtnl_add_match(m->rtnl, RTM_DELADDR, manager_process_address, m);
210 if (r < 0)
211 return r;
212
213 /* Then, enumerate all links */
214 r = sd_rtnl_message_new_link(m->rtnl, &req, RTM_GETLINK, 0);
215 if (r < 0)
216 return r;
217
218 r = sd_rtnl_message_request_dump(req, true);
219 if (r < 0)
220 return r;
221
222 r = sd_rtnl_call(m->rtnl, req, 0, &reply);
223 if (r < 0)
224 return r;
225
226 for (i = reply; i; i = sd_rtnl_message_next(i)) {
227 r = manager_process_link(m->rtnl, i, m);
228 if (r < 0)
229 return r;
230 }
231
232 req = sd_rtnl_message_unref(req);
233 reply = sd_rtnl_message_unref(reply);
234
235 /* Finally, enumerate all addresses, too */
236 r = sd_rtnl_message_new_addr(m->rtnl, &req, RTM_GETADDR, 0, AF_UNSPEC);
237 if (r < 0)
238 return r;
239
240 r = sd_rtnl_message_request_dump(req, true);
241 if (r < 0)
242 return r;
243
244 r = sd_rtnl_call(m->rtnl, req, 0, &reply);
245 if (r < 0)
246 return r;
247
248 for (i = reply; i; i = sd_rtnl_message_next(i)) {
249 r = manager_process_address(m->rtnl, i, m);
250 if (r < 0)
251 return r;
252 }
253
254 return r;
255}
256
257static int on_network_event(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
258 Manager *m = userdata;
259 Iterator i;
260 Link *l;
261 int r;
262
263 assert(m);
264
265 sd_network_monitor_flush(m->network_monitor);
266
267 HASHMAP_FOREACH(l, m->links, i) {
268 r = link_update_monitor(l);
269 if (r < 0)
270 log_warning("Failed to update monitor information for %i: %s", l->ifindex, strerror(-r));
271 }
272
273 r = manager_write_resolv_conf(m);
274 if (r < 0)
275 log_warning("Could not update resolv.conf: %s", strerror(-r));
276
277 return 0;
278}
279
280static int manager_network_monitor_listen(Manager *m) {
281 int r, fd, events;
282
283 assert(m);
284
285 r = sd_network_monitor_new(NULL, &m->network_monitor);
286 if (r < 0)
287 return r;
288
289 fd = sd_network_monitor_get_fd(m->network_monitor);
290 if (fd < 0)
291 return fd;
292
293 events = sd_network_monitor_get_events(m->network_monitor);
294 if (events < 0)
295 return events;
296
297 r = sd_event_add_io(m->event, &m->network_event_source, fd, events, &on_network_event, m);
298 if (r < 0)
299 return r;
300
301 return 0;
302}
303
304static int parse_dns_server_string(Manager *m, const char *string) {
091a364c
TG
305 char *word, *state;
306 size_t length;
307 int r;
308
309 assert(m);
310 assert(string);
311
312 FOREACH_WORD_QUOTED(word, length, string, state) {
74b2466e
LP
313 char buffer[length+1];
314 unsigned family;
315 union in_addr_union addr;
091a364c 316
74b2466e
LP
317 memcpy(buffer, word, length);
318 buffer[length] = 0;
091a364c 319
74b2466e 320 r = in_addr_from_string_auto(buffer, &family, &addr);
091a364c 321 if (r < 0) {
74b2466e 322 log_warning("Ignoring invalid DNS address '%s'", buffer);
091a364c
TG
323 continue;
324 }
325
74b2466e
LP
326 /* filter out duplicates */
327 if (manager_find_dns_server(m, family, &addr))
328 continue;
329
330 r = dns_server_new(m, NULL, DNS_SERVER_SYSTEM, NULL, family, &addr);
331 if (r < 0)
332 return r;
091a364c
TG
333 }
334
335 return 0;
336}
337
338int config_parse_dnsv(
339 const char *unit,
340 const char *filename,
341 unsigned line,
342 const char *section,
343 unsigned section_line,
344 const char *lvalue,
345 int ltype,
346 const char *rvalue,
347 void *data,
348 void *userdata) {
349
350 Manager *m = userdata;
74b2466e 351 int r;
091a364c
TG
352
353 assert(filename);
354 assert(lvalue);
355 assert(rvalue);
356 assert(m);
357
74b2466e
LP
358 /* Empty assignment means clear the list */
359 if (isempty(rvalue)) {
360 while (m->dns_servers)
361 dns_server_free(m->dns_servers);
362
363 return 0;
091a364c
TG
364 }
365
74b2466e
LP
366 r = parse_dns_server_string(m, rvalue);
367 if (r < 0) {
368 log_error("Failed to parse DNS server string");
369 return r;
370 }
091a364c
TG
371
372 return 0;
373}
374
74b2466e 375int manager_parse_config_file(Manager *m) {
091a364c
TG
376 int r;
377
378 assert(m);
379
74b2466e
LP
380 r = config_parse(NULL,
381 "/etc/systemd/resolved.conf", NULL,
382 "Resolve\0",
383 config_item_perf_lookup, (void*) resolved_gperf_lookup,
987d561f 384 false, false, m);
091a364c
TG
385 if (r < 0)
386 log_warning("Failed to parse configuration file: %s", strerror(-r));
387
74b2466e 388 return 0;
091a364c
TG
389}
390
391int manager_new(Manager **ret) {
74b2466e 392 _cleanup_(manager_freep) Manager *m = NULL;
091a364c
TG
393 int r;
394
c92e531c
LP
395 assert(ret);
396
091a364c
TG
397 m = new0(Manager, 1);
398 if (!m)
399 return -ENOMEM;
400
74b2466e 401 m->dns_ipv4_fd = m->dns_ipv6_fd = -1;
091a364c 402
74b2466e 403 r = parse_dns_server_string(m, /* "172.31.0.125 2001:4860:4860::8888 2001:4860:4860::8889" */ DNS_SERVERS);
091a364c
TG
404 if (r < 0)
405 return r;
406
407 r = sd_event_default(&m->event);
408 if (r < 0)
409 return r;
410
411 sd_event_add_signal(m->event, NULL, SIGTERM, NULL, NULL);
412 sd_event_add_signal(m->event, NULL, SIGINT, NULL, NULL);
413
414 sd_event_set_watchdog(m->event, true);
415
74b2466e
LP
416 r = dns_scope_new(m, &m->unicast_scope, DNS_SCOPE_DNS);
417 if (r < 0)
418 return r;
419
420 r = manager_network_monitor_listen(m);
421 if (r < 0)
422 return r;
423
424 r = manager_rtnl_listen(m);
425 if (r < 0)
426 return r;
427
428 r = manager_connect_bus(m);
429 if (r < 0)
430 return r;
431
091a364c
TG
432 *ret = m;
433 m = NULL;
434
435 return 0;
436}
437
74b2466e
LP
438Manager *manager_free(Manager *m) {
439 Link *l;
091a364c
TG
440
441 if (!m)
74b2466e
LP
442 return NULL;
443
444 while (m->dns_queries)
445 dns_query_free(m->dns_queries);
446
447 hashmap_free(m->dns_query_transactions);
448
449 while ((l = hashmap_first(m->links)))
450 link_free(l);
451 hashmap_free(m->links);
452
453 dns_scope_free(m->unicast_scope);
454
455 while (m->dns_servers)
456 dns_server_free(m->dns_servers);
091a364c 457
096b6773
LP
458 sd_event_source_unref(m->network_event_source);
459 sd_network_monitor_unref(m->network_monitor);
091a364c 460
74b2466e
LP
461 sd_event_source_unref(m->dns_ipv4_event_source);
462 sd_event_source_unref(m->dns_ipv6_event_source);
463
464 safe_close(m->dns_ipv4_fd);
465 safe_close(m->dns_ipv6_fd);
466
467 sd_event_source_unref(m->bus_retry_event_source);
468 sd_bus_unref(m->bus);
091a364c 469
74b2466e 470 sd_event_unref(m->event);
091a364c 471 free(m);
74b2466e
LP
472
473 return NULL;
091a364c
TG
474}
475
74b2466e
LP
476static void write_resolve_conf_server(DnsServer *s, FILE *f, unsigned *count) {
477 _cleanup_free_ char *t = NULL;
478 int r;
091a364c 479
74b2466e 480 assert(s);
091a364c 481 assert(f);
091a364c
TG
482 assert(count);
483
74b2466e
LP
484 r = in_addr_to_string(s->family, &s->address, &t);
485 if (r < 0) {
091a364c
TG
486 log_warning("Invalid DNS address. Ignoring.");
487 return;
488 }
489
490 if (*count == MAXNS)
74b2466e 491 fputs("# Too many DNS servers configured, the following entries may be ignored\n", f);
091a364c 492
74b2466e 493 fprintf(f, "nameserver %s\n", t);
091a364c
TG
494 (*count) ++;
495}
496
74b2466e 497int manager_write_resolv_conf(Manager *m) {
b686acb2 498 const char *path = "/run/systemd/resolve/resolv.conf";
091a364c
TG
499 _cleanup_free_ char *temp_path = NULL;
500 _cleanup_fclose_ FILE *f = NULL;
091a364c 501 unsigned count = 0;
74b2466e
LP
502 DnsServer *s;
503 Iterator i;
504 Link *l;
505 int r;
091a364c
TG
506
507 assert(m);
508
b686acb2 509 r = fopen_temporary(path, &f, &temp_path);
091a364c
TG
510 if (r < 0)
511 return r;
512
513 fchmod(fileno(f), 0644);
514
515 fputs("# This file is managed by systemd-resolved(8). Do not edit.\n#\n"
516 "# Third party programs must not access this file directly, but\n"
517 "# only through the symlink at /etc/resolv.conf. To manage\n"
518 "# resolv.conf(5) in a different way, replace the symlink by a\n"
519 "# static file or a different symlink.\n\n", f);
520
74b2466e
LP
521 HASHMAP_FOREACH(l, m->links, i) {
522 LIST_FOREACH(servers, s, l->link_dns_servers)
523 write_resolve_conf_server(s, f, &count);
091a364c 524
74b2466e
LP
525 LIST_FOREACH(servers, s, l->dhcp_dns_servers)
526 write_resolve_conf_server(s, f, &count);
527 }
091a364c 528
74b2466e
LP
529 LIST_FOREACH(servers, s, m->dns_servers)
530 write_resolve_conf_server(s, f, &count);
091a364c 531
74b2466e
LP
532 r = fflush_and_check(f);
533 if (r < 0)
534 goto fail;
535
536 if (rename(temp_path, path) < 0) {
537 r = -errno;
538 goto fail;
539 }
091a364c 540
74b2466e 541 return 0;
091a364c 542
74b2466e
LP
543fail:
544 unlink(path);
545 unlink(temp_path);
546 return r;
547}
091a364c 548
74b2466e
LP
549int manager_dns_ipv4_recv(Manager *m, DnsPacket **ret) {
550 _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
551 struct msghdr mh = {};
552 int fd, ms = 0, r;
553 struct iovec iov;
554 ssize_t l;
555
556 assert(m);
557 assert(ret);
558
559 fd = manager_dns_ipv4_fd(m);
560 if (fd < 0)
561 return fd;
562
563 r = ioctl(fd, FIONREAD, &ms);
564 if (r < 0)
565 return -errno;
566 if (ms < 0)
567 return -EIO;
568
569 r = dns_packet_new(&p, ms);
570 if (r < 0)
571 return r;
572
573 iov.iov_base = DNS_PACKET_DATA(p);
574 iov.iov_len = p->allocated;
575
576 mh.msg_iov = &iov;
577 mh.msg_iovlen = 1;
578
579 l = recvmsg(fd, &mh, 0);
580 if (l < 0) {
581 if (errno == EAGAIN)
582 return 0;
583
584 return -errno;
091a364c
TG
585 }
586
74b2466e
LP
587 if (l <= 0)
588 return -EIO;
091a364c 589
74b2466e 590 p->size = (size_t) l;
091a364c 591
74b2466e
LP
592 *ret = p;
593 p = NULL;
594
595 return 1;
596}
597
598int manager_dns_ipv6_recv(Manager *m, DnsPacket **ret) {
599 _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
600 struct msghdr mh = {};
601 struct iovec iov;
602 int fd, ms = 0, r;
603 ssize_t l;
604
605 assert(m);
606 assert(ret);
607
608 fd = manager_dns_ipv6_fd(m);
609 if (fd < 0)
610 return fd;
611
612 r = ioctl(fd, FIONREAD, &ms);
613 if (r < 0)
614 return -errno;
615 if (ms < 0)
616 return -EIO;
617
618 r = dns_packet_new(&p, ms);
619 if (r < 0)
091a364c 620 return r;
74b2466e
LP
621
622 iov.iov_base = DNS_PACKET_DATA(p);
623 iov.iov_len = p->allocated;
624
625 mh.msg_iov = &iov;
626 mh.msg_iovlen = 1;
627
628 l = recvmsg(fd, &mh, 0);
629 if (l < 0) {
630 if (errno == EAGAIN)
631 return 0;
632
633 return -errno;
091a364c
TG
634 }
635
74b2466e
LP
636 if (l <= 0)
637 return -EIO;
638
639 p->size = (size_t) l;
640
641 *ret = p;
642 p = NULL;
643
644 return 1;
645}
646
647static int on_dns_ipv4_packet(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
648 _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
649 DnsQueryTransaction *t = NULL;
650 Manager *m = userdata;
651 int r;
652
653 r = manager_dns_ipv4_recv(m, &p);
654 if (r <= 0)
655 return r;
656
657 t = hashmap_get(m->dns_query_transactions, UINT_TO_PTR(DNS_PACKET_HEADER(p)->id));
658 if (!t)
659 return 0;
660
661 return dns_query_transaction_reply(t, p);
091a364c
TG
662}
663
74b2466e
LP
664static int on_dns_ipv6_packet(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
665 _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
666 DnsQueryTransaction *t = NULL;
091a364c
TG
667 Manager *m = userdata;
668 int r;
669
74b2466e
LP
670 r = manager_dns_ipv6_recv(m, &p);
671 if (r <= 0)
672 return r;
673
674 t = hashmap_get(m->dns_query_transactions, UINT_TO_PTR(DNS_PACKET_HEADER(p)->id));
675 if (!t)
676 return 0;
677
678 return dns_query_transaction_reply(t, p);
679}
680
681int manager_dns_ipv4_fd(Manager *m) {
682 int r;
683
091a364c
TG
684 assert(m);
685
74b2466e
LP
686 if (m->dns_ipv4_fd >= 0)
687 return m->dns_ipv4_fd;
091a364c 688
74b2466e
LP
689 m->dns_ipv4_fd = socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
690 if (m->dns_ipv4_fd < 0)
691 return -errno;
091a364c 692
74b2466e
LP
693 r = sd_event_add_io(m->event, &m->dns_ipv4_event_source, m->dns_ipv4_fd, EPOLLIN, on_dns_ipv4_packet, m);
694 if (r < 0)
695 return r;
696
697 return m->dns_ipv4_fd;
091a364c
TG
698}
699
74b2466e
LP
700int manager_dns_ipv6_fd(Manager *m) {
701 int r;
702
703 assert(m);
091a364c 704
74b2466e
LP
705 if (m->dns_ipv6_fd >= 0)
706 return m->dns_ipv6_fd;
707
708 m->dns_ipv6_fd = socket(AF_INET6, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
709 if (m->dns_ipv6_fd < 0)
710 return -errno;
711
712 r = sd_event_add_io(m->event, &m->dns_ipv6_event_source, m->dns_ipv6_fd, EPOLLIN, on_dns_ipv6_packet, m);
091a364c
TG
713 if (r < 0)
714 return r;
715
74b2466e
LP
716 return m->dns_ipv6_fd;
717}
718
719static int sendmsg_loop(int fd, struct msghdr *mh, int flags) {
720 int r;
721
722 assert(fd >= 0);
723 assert(mh);
724
725 for (;;) {
726 if (sendmsg(fd, mh, flags) >= 0)
727 return 0;
728
729 if (errno == EINTR)
730 continue;
731
732 if (errno != EAGAIN)
733 return -errno;
734
735 r = fd_wait_for_event(fd, POLLOUT, SEND_TIMEOUT_USEC);
736 if (r < 0)
737 return r;
738 if (r == 0)
739 return -ETIMEDOUT;
740 }
741}
742
743int manager_dns_ipv4_send(Manager *m, DnsServer *srv, int ifindex, DnsPacket *p) {
744 union sockaddr_union sa = {
745 .in.sin_family = AF_INET,
746 .in.sin_port = htobe16(53),
747 };
748 struct msghdr mh = {};
749 struct iovec iov;
750 uint8_t control[CMSG_SPACE(sizeof(struct in_pktinfo))];
751 int fd;
752
753 assert(m);
754 assert(srv);
755 assert(p);
756
757 fd = manager_dns_ipv4_fd(m);
091a364c
TG
758 if (fd < 0)
759 return fd;
760
74b2466e
LP
761 iov.iov_base = DNS_PACKET_DATA(p);
762 iov.iov_len = p->size;
091a364c 763
74b2466e 764 sa.in.sin_addr = srv->address.in;
091a364c 765
74b2466e
LP
766 mh.msg_iov = &iov;
767 mh.msg_iovlen = 1;
768 mh.msg_name = &sa.sa;
769 mh.msg_namelen = sizeof(sa.in);
091a364c 770
74b2466e
LP
771 if (ifindex > 0) {
772 struct cmsghdr *cmsg;
773 struct in_pktinfo *pi;
774
775 zero(control);
776
777 mh.msg_control = control;
778 mh.msg_controllen = CMSG_LEN(sizeof(struct in_pktinfo));
779
780 cmsg = CMSG_FIRSTHDR(&mh);
781 cmsg->cmsg_len = mh.msg_controllen;
782 cmsg->cmsg_level = IPPROTO_IP;
783 cmsg->cmsg_type = IP_PKTINFO;
784
785 pi = (struct in_pktinfo*) CMSG_DATA(cmsg);
786 pi->ipi_ifindex = ifindex;
787 }
788
789 return sendmsg_loop(fd, &mh, 0);
790}
791
792int manager_dns_ipv6_send(Manager *m, DnsServer *srv, int ifindex, DnsPacket *p) {
793 union sockaddr_union sa = {
794 .in6.sin6_family = AF_INET6,
795 .in6.sin6_port = htobe16(53),
796 };
797
798 struct msghdr mh = {};
799 struct iovec iov;
800 uint8_t control[CMSG_SPACE(sizeof(struct in6_pktinfo))];
801 int fd;
802
803 assert(m);
804 assert(srv);
805 assert(p);
806
807 fd = manager_dns_ipv6_fd(m);
808 if (fd < 0)
809 return fd;
810
811 iov.iov_base = DNS_PACKET_DATA(p);
812 iov.iov_len = p->size;
813
814 sa.in6.sin6_addr = srv->address.in6;
815 sa.in6.sin6_scope_id = ifindex;
816
817 mh.msg_iov = &iov;
818 mh.msg_iovlen = 1;
819 mh.msg_name = &sa.sa;
820 mh.msg_namelen = sizeof(sa.in6);
821
822 if (ifindex > 0) {
823 struct cmsghdr *cmsg;
824 struct in6_pktinfo *pi;
825
826 zero(control);
827
828 mh.msg_control = control;
829 mh.msg_controllen = CMSG_LEN(sizeof(struct in6_pktinfo));
830
831 cmsg = CMSG_FIRSTHDR(&mh);
832 cmsg->cmsg_len = mh.msg_controllen;
833 cmsg->cmsg_level = IPPROTO_IPV6;
834 cmsg->cmsg_type = IPV6_PKTINFO;
835
836 pi = (struct in6_pktinfo*) CMSG_DATA(cmsg);
837 pi->ipi6_ifindex = ifindex;
838 }
839
840 return sendmsg_loop(fd, &mh, 0);
841}
842
843DnsServer* manager_find_dns_server(Manager *m, unsigned char family, union in_addr_union *in_addr) {
844 DnsServer *s;
845
846 assert(m);
847 assert(in_addr);
848
849 LIST_FOREACH(servers, s, m->dns_servers) {
850
851 if (s->family == family &&
852 in_addr_equal(family, &s->address, in_addr))
853 return s;
854 }
855
856 return NULL;
857}
858
859DnsServer *manager_get_dns_server(Manager *m) {
860 assert(m);
861
862 if (!m->current_dns_server)
863 m->current_dns_server = m->dns_servers;
864
865 return m->current_dns_server;
866}
867
868void manager_next_dns_server(Manager *m) {
869 assert(m);
870
871 if (!m->current_dns_server) {
872 m->current_dns_server = m->dns_servers;
873 return;
874 }
875
876 if (!m->current_dns_server)
877 return;
878
879 if (m->current_dns_server->servers_next) {
880 m->current_dns_server = m->current_dns_server->servers_next;
881 return;
882 }
883
884 m->current_dns_server = m->dns_servers;
091a364c 885}