]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/resolve/resolved-manager.c
po: add Ukrainian translation
[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 assert(m);
377
36f822c4
ZJS
378 return config_parse(NULL, "/etc/systemd/resolved.conf", NULL,
379 "Resolve\0",
380 config_item_perf_lookup, resolved_gperf_lookup,
381 false, false, true, m);
091a364c
TG
382}
383
384int manager_new(Manager **ret) {
74b2466e 385 _cleanup_(manager_freep) Manager *m = NULL;
091a364c
TG
386 int r;
387
c92e531c
LP
388 assert(ret);
389
091a364c
TG
390 m = new0(Manager, 1);
391 if (!m)
392 return -ENOMEM;
393
74b2466e 394 m->dns_ipv4_fd = m->dns_ipv6_fd = -1;
091a364c 395
74b2466e 396 r = parse_dns_server_string(m, /* "172.31.0.125 2001:4860:4860::8888 2001:4860:4860::8889" */ DNS_SERVERS);
091a364c
TG
397 if (r < 0)
398 return r;
399
400 r = sd_event_default(&m->event);
401 if (r < 0)
402 return r;
403
404 sd_event_add_signal(m->event, NULL, SIGTERM, NULL, NULL);
405 sd_event_add_signal(m->event, NULL, SIGINT, NULL, NULL);
406
407 sd_event_set_watchdog(m->event, true);
408
74b2466e
LP
409 r = dns_scope_new(m, &m->unicast_scope, DNS_SCOPE_DNS);
410 if (r < 0)
411 return r;
412
413 r = manager_network_monitor_listen(m);
414 if (r < 0)
415 return r;
416
417 r = manager_rtnl_listen(m);
418 if (r < 0)
419 return r;
420
421 r = manager_connect_bus(m);
422 if (r < 0)
423 return r;
424
091a364c
TG
425 *ret = m;
426 m = NULL;
427
428 return 0;
429}
430
74b2466e
LP
431Manager *manager_free(Manager *m) {
432 Link *l;
091a364c
TG
433
434 if (!m)
74b2466e
LP
435 return NULL;
436
437 while (m->dns_queries)
438 dns_query_free(m->dns_queries);
439
440 hashmap_free(m->dns_query_transactions);
441
442 while ((l = hashmap_first(m->links)))
443 link_free(l);
444 hashmap_free(m->links);
445
446 dns_scope_free(m->unicast_scope);
447
448 while (m->dns_servers)
449 dns_server_free(m->dns_servers);
091a364c 450
096b6773
LP
451 sd_event_source_unref(m->network_event_source);
452 sd_network_monitor_unref(m->network_monitor);
091a364c 453
74b2466e
LP
454 sd_event_source_unref(m->dns_ipv4_event_source);
455 sd_event_source_unref(m->dns_ipv6_event_source);
456
457 safe_close(m->dns_ipv4_fd);
458 safe_close(m->dns_ipv6_fd);
459
460 sd_event_source_unref(m->bus_retry_event_source);
461 sd_bus_unref(m->bus);
091a364c 462
74b2466e 463 sd_event_unref(m->event);
091a364c 464 free(m);
74b2466e
LP
465
466 return NULL;
091a364c
TG
467}
468
74b2466e
LP
469static void write_resolve_conf_server(DnsServer *s, FILE *f, unsigned *count) {
470 _cleanup_free_ char *t = NULL;
471 int r;
091a364c 472
74b2466e 473 assert(s);
091a364c 474 assert(f);
091a364c
TG
475 assert(count);
476
74b2466e
LP
477 r = in_addr_to_string(s->family, &s->address, &t);
478 if (r < 0) {
091a364c
TG
479 log_warning("Invalid DNS address. Ignoring.");
480 return;
481 }
482
483 if (*count == MAXNS)
74b2466e 484 fputs("# Too many DNS servers configured, the following entries may be ignored\n", f);
091a364c 485
74b2466e 486 fprintf(f, "nameserver %s\n", t);
091a364c
TG
487 (*count) ++;
488}
489
74b2466e 490int manager_write_resolv_conf(Manager *m) {
b686acb2 491 const char *path = "/run/systemd/resolve/resolv.conf";
091a364c
TG
492 _cleanup_free_ char *temp_path = NULL;
493 _cleanup_fclose_ FILE *f = NULL;
091a364c 494 unsigned count = 0;
74b2466e
LP
495 DnsServer *s;
496 Iterator i;
497 Link *l;
498 int r;
091a364c
TG
499
500 assert(m);
501
b686acb2 502 r = fopen_temporary(path, &f, &temp_path);
091a364c
TG
503 if (r < 0)
504 return r;
505
506 fchmod(fileno(f), 0644);
507
508 fputs("# This file is managed by systemd-resolved(8). Do not edit.\n#\n"
509 "# Third party programs must not access this file directly, but\n"
510 "# only through the symlink at /etc/resolv.conf. To manage\n"
511 "# resolv.conf(5) in a different way, replace the symlink by a\n"
512 "# static file or a different symlink.\n\n", f);
513
74b2466e
LP
514 HASHMAP_FOREACH(l, m->links, i) {
515 LIST_FOREACH(servers, s, l->link_dns_servers)
516 write_resolve_conf_server(s, f, &count);
091a364c 517
74b2466e
LP
518 LIST_FOREACH(servers, s, l->dhcp_dns_servers)
519 write_resolve_conf_server(s, f, &count);
520 }
091a364c 521
74b2466e
LP
522 LIST_FOREACH(servers, s, m->dns_servers)
523 write_resolve_conf_server(s, f, &count);
091a364c 524
74b2466e
LP
525 r = fflush_and_check(f);
526 if (r < 0)
527 goto fail;
528
529 if (rename(temp_path, path) < 0) {
530 r = -errno;
531 goto fail;
532 }
091a364c 533
74b2466e 534 return 0;
091a364c 535
74b2466e
LP
536fail:
537 unlink(path);
538 unlink(temp_path);
539 return r;
540}
091a364c 541
74b2466e
LP
542int manager_dns_ipv4_recv(Manager *m, DnsPacket **ret) {
543 _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
544 struct msghdr mh = {};
545 int fd, ms = 0, r;
546 struct iovec iov;
547 ssize_t l;
548
549 assert(m);
550 assert(ret);
551
552 fd = manager_dns_ipv4_fd(m);
553 if (fd < 0)
554 return fd;
555
556 r = ioctl(fd, FIONREAD, &ms);
557 if (r < 0)
558 return -errno;
559 if (ms < 0)
560 return -EIO;
561
562 r = dns_packet_new(&p, ms);
563 if (r < 0)
564 return r;
565
566 iov.iov_base = DNS_PACKET_DATA(p);
567 iov.iov_len = p->allocated;
568
569 mh.msg_iov = &iov;
570 mh.msg_iovlen = 1;
571
572 l = recvmsg(fd, &mh, 0);
573 if (l < 0) {
ad867662 574 if (errno == EAGAIN || errno == EINTR)
74b2466e
LP
575 return 0;
576
577 return -errno;
091a364c
TG
578 }
579
74b2466e
LP
580 if (l <= 0)
581 return -EIO;
091a364c 582
74b2466e 583 p->size = (size_t) l;
091a364c 584
74b2466e
LP
585 *ret = p;
586 p = NULL;
587
588 return 1;
589}
590
591int manager_dns_ipv6_recv(Manager *m, DnsPacket **ret) {
592 _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
593 struct msghdr mh = {};
594 struct iovec iov;
595 int fd, ms = 0, r;
596 ssize_t l;
597
598 assert(m);
599 assert(ret);
600
601 fd = manager_dns_ipv6_fd(m);
602 if (fd < 0)
603 return fd;
604
605 r = ioctl(fd, FIONREAD, &ms);
606 if (r < 0)
607 return -errno;
608 if (ms < 0)
609 return -EIO;
610
611 r = dns_packet_new(&p, ms);
612 if (r < 0)
091a364c 613 return r;
74b2466e
LP
614
615 iov.iov_base = DNS_PACKET_DATA(p);
616 iov.iov_len = p->allocated;
617
618 mh.msg_iov = &iov;
619 mh.msg_iovlen = 1;
620
621 l = recvmsg(fd, &mh, 0);
622 if (l < 0) {
ad867662 623 if (errno == EAGAIN || errno == EINTR)
74b2466e
LP
624 return 0;
625
626 return -errno;
091a364c
TG
627 }
628
74b2466e
LP
629 if (l <= 0)
630 return -EIO;
631
632 p->size = (size_t) l;
633
634 *ret = p;
635 p = NULL;
636
637 return 1;
638}
639
640static int on_dns_ipv4_packet(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
641 _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
642 DnsQueryTransaction *t = NULL;
643 Manager *m = userdata;
644 int r;
645
646 r = manager_dns_ipv4_recv(m, &p);
647 if (r <= 0)
648 return r;
649
3cb10d3a 650 t = hashmap_get(m->dns_query_transactions, UINT_TO_PTR(DNS_PACKET_ID(p)));
74b2466e
LP
651 if (!t)
652 return 0;
653
ad867662
LP
654 dns_query_transaction_reply(t, p);
655 return 0;
091a364c
TG
656}
657
74b2466e
LP
658static int on_dns_ipv6_packet(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
659 _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
660 DnsQueryTransaction *t = NULL;
091a364c
TG
661 Manager *m = userdata;
662 int r;
663
74b2466e
LP
664 r = manager_dns_ipv6_recv(m, &p);
665 if (r <= 0)
666 return r;
667
3cb10d3a 668 t = hashmap_get(m->dns_query_transactions, UINT_TO_PTR(DNS_PACKET_ID(p)));
74b2466e
LP
669 if (!t)
670 return 0;
671
ad867662
LP
672 dns_query_transaction_reply(t, p);
673 return 0;
74b2466e
LP
674}
675
676int manager_dns_ipv4_fd(Manager *m) {
677 int r;
678
091a364c
TG
679 assert(m);
680
74b2466e
LP
681 if (m->dns_ipv4_fd >= 0)
682 return m->dns_ipv4_fd;
091a364c 683
74b2466e
LP
684 m->dns_ipv4_fd = socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
685 if (m->dns_ipv4_fd < 0)
686 return -errno;
091a364c 687
74b2466e
LP
688 r = sd_event_add_io(m->event, &m->dns_ipv4_event_source, m->dns_ipv4_fd, EPOLLIN, on_dns_ipv4_packet, m);
689 if (r < 0)
690 return r;
691
692 return m->dns_ipv4_fd;
091a364c
TG
693}
694
74b2466e
LP
695int manager_dns_ipv6_fd(Manager *m) {
696 int r;
697
698 assert(m);
091a364c 699
74b2466e
LP
700 if (m->dns_ipv6_fd >= 0)
701 return m->dns_ipv6_fd;
702
703 m->dns_ipv6_fd = socket(AF_INET6, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
704 if (m->dns_ipv6_fd < 0)
705 return -errno;
706
707 r = sd_event_add_io(m->event, &m->dns_ipv6_event_source, m->dns_ipv6_fd, EPOLLIN, on_dns_ipv6_packet, m);
091a364c
TG
708 if (r < 0)
709 return r;
710
74b2466e
LP
711 return m->dns_ipv6_fd;
712}
713
714static int sendmsg_loop(int fd, struct msghdr *mh, int flags) {
715 int r;
716
717 assert(fd >= 0);
718 assert(mh);
719
720 for (;;) {
721 if (sendmsg(fd, mh, flags) >= 0)
722 return 0;
723
724 if (errno == EINTR)
725 continue;
726
727 if (errno != EAGAIN)
728 return -errno;
729
730 r = fd_wait_for_event(fd, POLLOUT, SEND_TIMEOUT_USEC);
731 if (r < 0)
732 return r;
733 if (r == 0)
734 return -ETIMEDOUT;
735 }
736}
737
738int manager_dns_ipv4_send(Manager *m, DnsServer *srv, int ifindex, DnsPacket *p) {
739 union sockaddr_union sa = {
740 .in.sin_family = AF_INET,
741 .in.sin_port = htobe16(53),
742 };
743 struct msghdr mh = {};
744 struct iovec iov;
745 uint8_t control[CMSG_SPACE(sizeof(struct in_pktinfo))];
746 int fd;
747
748 assert(m);
749 assert(srv);
750 assert(p);
751
752 fd = manager_dns_ipv4_fd(m);
091a364c
TG
753 if (fd < 0)
754 return fd;
755
74b2466e
LP
756 iov.iov_base = DNS_PACKET_DATA(p);
757 iov.iov_len = p->size;
091a364c 758
74b2466e 759 sa.in.sin_addr = srv->address.in;
091a364c 760
74b2466e
LP
761 mh.msg_iov = &iov;
762 mh.msg_iovlen = 1;
763 mh.msg_name = &sa.sa;
764 mh.msg_namelen = sizeof(sa.in);
091a364c 765
74b2466e
LP
766 if (ifindex > 0) {
767 struct cmsghdr *cmsg;
768 struct in_pktinfo *pi;
769
770 zero(control);
771
772 mh.msg_control = control;
773 mh.msg_controllen = CMSG_LEN(sizeof(struct in_pktinfo));
774
775 cmsg = CMSG_FIRSTHDR(&mh);
776 cmsg->cmsg_len = mh.msg_controllen;
777 cmsg->cmsg_level = IPPROTO_IP;
778 cmsg->cmsg_type = IP_PKTINFO;
779
780 pi = (struct in_pktinfo*) CMSG_DATA(cmsg);
781 pi->ipi_ifindex = ifindex;
782 }
783
784 return sendmsg_loop(fd, &mh, 0);
785}
786
787int manager_dns_ipv6_send(Manager *m, DnsServer *srv, int ifindex, DnsPacket *p) {
788 union sockaddr_union sa = {
789 .in6.sin6_family = AF_INET6,
790 .in6.sin6_port = htobe16(53),
791 };
792
793 struct msghdr mh = {};
794 struct iovec iov;
795 uint8_t control[CMSG_SPACE(sizeof(struct in6_pktinfo))];
796 int fd;
797
798 assert(m);
799 assert(srv);
800 assert(p);
801
802 fd = manager_dns_ipv6_fd(m);
803 if (fd < 0)
804 return fd;
805
806 iov.iov_base = DNS_PACKET_DATA(p);
807 iov.iov_len = p->size;
808
809 sa.in6.sin6_addr = srv->address.in6;
810 sa.in6.sin6_scope_id = ifindex;
811
812 mh.msg_iov = &iov;
813 mh.msg_iovlen = 1;
814 mh.msg_name = &sa.sa;
815 mh.msg_namelen = sizeof(sa.in6);
816
817 if (ifindex > 0) {
818 struct cmsghdr *cmsg;
819 struct in6_pktinfo *pi;
820
821 zero(control);
822
823 mh.msg_control = control;
824 mh.msg_controllen = CMSG_LEN(sizeof(struct in6_pktinfo));
825
826 cmsg = CMSG_FIRSTHDR(&mh);
827 cmsg->cmsg_len = mh.msg_controllen;
828 cmsg->cmsg_level = IPPROTO_IPV6;
829 cmsg->cmsg_type = IPV6_PKTINFO;
830
831 pi = (struct in6_pktinfo*) CMSG_DATA(cmsg);
832 pi->ipi6_ifindex = ifindex;
833 }
834
835 return sendmsg_loop(fd, &mh, 0);
836}
837
838DnsServer* manager_find_dns_server(Manager *m, unsigned char family, union in_addr_union *in_addr) {
839 DnsServer *s;
840
841 assert(m);
842 assert(in_addr);
843
844 LIST_FOREACH(servers, s, m->dns_servers) {
845
846 if (s->family == family &&
847 in_addr_equal(family, &s->address, in_addr))
848 return s;
849 }
850
851 return NULL;
852}
853
854DnsServer *manager_get_dns_server(Manager *m) {
855 assert(m);
856
857 if (!m->current_dns_server)
858 m->current_dns_server = m->dns_servers;
859
860 return m->current_dns_server;
861}
862
863void manager_next_dns_server(Manager *m) {
864 assert(m);
865
866 if (!m->current_dns_server) {
867 m->current_dns_server = m->dns_servers;
868 return;
869 }
870
871 if (!m->current_dns_server)
872 return;
873
874 if (m->current_dns_server->servers_next) {
875 m->current_dns_server = m->current_dns_server->servers_next;
876 return;
877 }
878
879 m->current_dns_server = m->dns_servers;
091a364c 880}