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"
35 static int set_fallback_dns(Manager *m, const char *string) {
43 FOREACH_WORD_QUOTED(word, length, string, state) {
44 _cleanup_free_ Address *address = NULL;
46 _cleanup_free_ char *addrstr = NULL;
48 address = new0(Address, 1);
52 addrstr = strndup(word, length);
56 r = net_parse_inaddr(addrstr, &address->family, &address->in_addr);
58 log_debug("Ignoring invalid DNS address '%s'", addrstr);
62 LIST_FIND_TAIL(addresses, m->fallback_dns, tail);
63 LIST_INSERT_AFTER(addresses, m->fallback_dns, tail, address);
70 int config_parse_dnsv(
75 unsigned section_line,
82 Manager *m = userdata;
90 while ((address = m->fallback_dns)) {
91 LIST_REMOVE(addresses, m->fallback_dns, address);
95 set_fallback_dns(m, rvalue);
100 static int manager_parse_config_file(Manager *m) {
101 static const char fn[] = "/etc/systemd/resolved.conf";
102 _cleanup_fclose_ FILE *f = NULL;
112 log_warning("Failed to open configuration file %s: %m", fn);
116 r = config_parse(NULL, fn, f, "Resolve\0", config_item_perf_lookup,
117 (void*) resolved_gperf_lookup, false, false, m);
119 log_warning("Failed to parse configuration file: %s", strerror(-r));
124 int manager_new(Manager **ret) {
125 _cleanup_manager_free_ Manager *m = NULL;
128 m = new0(Manager, 1);
132 r = set_fallback_dns(m, DNS_SERVERS);
136 r = manager_parse_config_file(m);
140 r = sd_event_default(&m->event);
144 sd_event_add_signal(m->event, NULL, SIGTERM, NULL, NULL);
145 sd_event_add_signal(m->event, NULL, SIGINT, NULL, NULL);
147 sd_event_set_watchdog(m->event, true);
155 void manager_free(Manager *m) {
161 sd_event_unref(m->event);
163 while ((address = m->fallback_dns)) {
164 LIST_REMOVE(addresses, m->fallback_dns, address);
171 static void append_dns(FILE *f, void *dns, unsigned char family, unsigned *count) {
172 char buf[INET6_ADDRSTRLEN];
179 address = inet_ntop(family, dns, buf, INET6_ADDRSTRLEN);
181 log_warning("Invalid DNS address. Ignoring.");
186 fputs("# Too many DNS servers configured, the following entries "
187 "may be ignored\n", f);
189 fprintf(f, "nameserver %s\n", address);
194 int manager_update_resolv_conf(Manager *m) {
195 _cleanup_free_ char *temp_path = NULL;
196 _cleanup_fclose_ FILE *f = NULL;
197 _cleanup_free_ unsigned *indices = NULL;
204 r = fopen_temporary("/run/systemd/network/resolv.conf", &f, &temp_path);
208 fchmod(fileno(f), 0644);
210 fputs("# This file is managed by systemd-resolved(8). Do not edit.\n#\n"
211 "# Third party programs must not access this file directly, but\n"
212 "# only through the symlink at /etc/resolv.conf. To manage\n"
213 "# resolv.conf(5) in a different way, replace the symlink by a\n"
214 "# static file or a different symlink.\n\n", f);
216 n = sd_network_get_ifindices(&indices);
220 for (i = 0; i < n; i++) {
221 _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
222 struct in_addr *nameservers;
223 struct in6_addr *nameservers6;
224 size_t nameservers_size;
226 r = sd_network_dhcp_use_dns(indices[i]);
228 r = sd_network_get_dhcp_lease(indices[i], &lease);
230 r = sd_dhcp_lease_get_dns(lease, &nameservers, &nameservers_size);
234 for (j = 0; j < nameservers_size; j++)
235 append_dns(f, &nameservers[j], AF_INET, &count);
240 r = sd_network_get_dns(indices[i], &nameservers, &nameservers_size);
244 for (j = 0; j < nameservers_size; j++)
245 append_dns(f, &nameservers[j], AF_INET, &count);
250 r = sd_network_get_dns6(indices[i], &nameservers6, &nameservers_size);
254 for (j = 0; j < nameservers_size; j++)
255 append_dns(f, &nameservers6[j], AF_INET6, &count);
261 LIST_FOREACH(addresses, address, m->fallback_dns)
262 append_dns(f, &address->in_addr, address->family, &count);
266 if (ferror(f) || rename(temp_path, "/run/systemd/network/resolv.conf") < 0) {
268 unlink("/run/systemd/network/resolv.conf");
276 static int manager_network_event_handler(sd_event_source *s, int fd, uint32_t revents,
278 Manager *m = userdata;
283 r = manager_update_resolv_conf(m);
285 log_warning("Could not update resolv.conf: %s", strerror(-r));
287 sd_network_monitor_flush(m->network_monitor);
292 int manager_network_monitor_listen(Manager *m) {
293 _cleanup_event_source_unref_ sd_event_source *event_source = NULL;
294 _cleanup_network_monitor_unref_ sd_network_monitor *monitor = NULL;
297 r = sd_network_monitor_new(NULL, &monitor);
301 fd = sd_network_monitor_get_fd(monitor);
305 events = sd_network_monitor_get_events(monitor);
309 r = sd_event_add_io(m->event, &event_source, fd, events,
310 &manager_network_event_handler, m);
314 m->network_monitor = monitor;
315 m->network_event_source = event_source;