1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2014 Tom Gundersen <teg@jklm.no>
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.
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.
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/>.
22 #include <arpa/inet.h>
27 #include "event-util.h"
28 #include "network-util.h"
29 #include "sd-dhcp-lease.h"
30 #include "dhcp-lease-internal.h"
31 #include "network-internal.h"
32 #include "conf-parser.h"
34 static int set_fallback_dns(Manager *m, const char *string) {
42 FOREACH_WORD_QUOTED(word, length, string, state) {
43 _cleanup_free_ Address *address = NULL;
45 _cleanup_free_ char *addrstr = NULL;
47 address = new0(Address, 1);
51 addrstr = strndup(word, length);
55 r = net_parse_inaddr(addrstr, &address->family, &address->in_addr);
57 log_debug("Ignoring invalid DNS address '%s'", addrstr);
61 LIST_FIND_TAIL(addresses, m->fallback_dns, tail);
62 LIST_INSERT_AFTER(addresses, m->fallback_dns, tail, address);
69 int config_parse_dnsv(
74 unsigned section_line,
81 Manager *m = userdata;
89 while ((address = m->fallback_dns)) {
90 LIST_REMOVE(addresses, m->fallback_dns, address);
94 set_fallback_dns(m, rvalue);
99 static int manager_parse_config_file(Manager *m) {
104 r = config_parse(NULL, "/etc/systemd/resolved.conf", NULL,
105 "Resolve\0", config_item_perf_lookup, (void*) resolved_gperf_lookup,
108 log_warning("Failed to parse configuration file: %s", strerror(-r));
113 int manager_new(Manager **ret) {
114 _cleanup_manager_free_ Manager *m = NULL;
119 m = new0(Manager, 1);
123 r = set_fallback_dns(m, DNS_SERVERS);
127 r = manager_parse_config_file(m);
131 r = sd_event_default(&m->event);
135 sd_event_add_signal(m->event, NULL, SIGTERM, NULL, NULL);
136 sd_event_add_signal(m->event, NULL, SIGINT, NULL, NULL);
138 sd_event_set_watchdog(m->event, true);
146 void manager_free(Manager *m) {
152 sd_event_source_unref(m->network_event_source);
153 sd_network_monitor_unref(m->network_monitor);
154 sd_event_unref(m->event);
156 while ((address = m->fallback_dns)) {
157 LIST_REMOVE(addresses, m->fallback_dns, address);
164 static void append_dns(FILE *f, void *dns, unsigned char family, unsigned *count) {
165 char buf[INET6_ADDRSTRLEN];
172 address = inet_ntop(family, dns, buf, INET6_ADDRSTRLEN);
174 log_warning("Invalid DNS address. Ignoring.");
179 fputs("# Too many DNS servers configured, the following entries "
180 "may be ignored\n", f);
182 fprintf(f, "nameserver %s\n", address);
187 int manager_update_resolv_conf(Manager *m) {
188 const char *path = "/run/systemd/resolve/resolv.conf";
189 _cleanup_free_ char *temp_path = NULL;
190 _cleanup_fclose_ FILE *f = NULL;
191 _cleanup_free_ unsigned *indices = NULL;
198 r = fopen_temporary(path, &f, &temp_path);
202 fchmod(fileno(f), 0644);
204 fputs("# This file is managed by systemd-resolved(8). Do not edit.\n#\n"
205 "# Third party programs must not access this file directly, but\n"
206 "# only through the symlink at /etc/resolv.conf. To manage\n"
207 "# resolv.conf(5) in a different way, replace the symlink by a\n"
208 "# static file or a different symlink.\n\n", f);
210 n = sd_network_get_ifindices(&indices);
214 for (i = 0; i < n; i++) {
215 _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
216 struct in_addr *nameservers;
217 struct in6_addr *nameservers6;
218 size_t nameservers_size;
220 r = sd_network_dhcp_use_dns(indices[i]);
222 r = sd_network_get_dhcp_lease(indices[i], &lease);
224 r = sd_dhcp_lease_get_dns(lease, &nameservers, &nameservers_size);
228 for (j = 0; j < nameservers_size; j++)
229 append_dns(f, &nameservers[j], AF_INET, &count);
234 r = sd_network_get_dns(indices[i], &nameservers, &nameservers_size);
238 for (j = 0; j < nameservers_size; j++)
239 append_dns(f, &nameservers[j], AF_INET, &count);
244 r = sd_network_get_dns6(indices[i], &nameservers6, &nameservers_size);
248 for (j = 0; j < nameservers_size; j++)
249 append_dns(f, &nameservers6[j], AF_INET6, &count);
255 LIST_FOREACH(addresses, address, m->fallback_dns)
256 append_dns(f, &address->in_addr, address->family, &count);
260 if (ferror(f) || rename(temp_path, path) < 0) {
270 static int manager_network_event_handler(sd_event_source *s, int fd, uint32_t revents,
272 Manager *m = userdata;
277 r = manager_update_resolv_conf(m);
279 log_warning("Could not update resolv.conf: %s", strerror(-r));
281 sd_network_monitor_flush(m->network_monitor);
286 int manager_network_monitor_listen(Manager *m) {
287 _cleanup_event_source_unref_ sd_event_source *event_source = NULL;
288 _cleanup_network_monitor_unref_ sd_network_monitor *monitor = NULL;
291 r = sd_network_monitor_new(NULL, &monitor);
295 fd = sd_network_monitor_get_fd(monitor);
299 events = sd_network_monitor_get_events(monitor);
303 r = sd_event_add_io(m->event, &event_source, fd, events,
304 &manager_network_event_handler, m);
308 m->network_monitor = monitor;
309 m->network_event_source = event_source;