]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/resolve/resolved-manager.c
shared: fix format string for usec_t type
[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>
25
26#include "resolved.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"
091a364c
TG
33
34static int set_fallback_dns(Manager *m, const char *string) {
35 char *word, *state;
36 size_t length;
37 int r;
38
39 assert(m);
40 assert(string);
41
42 FOREACH_WORD_QUOTED(word, length, string, state) {
43 _cleanup_free_ Address *address = NULL;
44 Address *tail;
45 _cleanup_free_ char *addrstr = NULL;
46
47 address = new0(Address, 1);
48 if (!address)
49 return -ENOMEM;
50
51 addrstr = strndup(word, length);
52 if (!addrstr)
53 return -ENOMEM;
54
55 r = net_parse_inaddr(addrstr, &address->family, &address->in_addr);
56 if (r < 0) {
57 log_debug("Ignoring invalid DNS address '%s'", addrstr);
58 continue;
59 }
60
61 LIST_FIND_TAIL(addresses, m->fallback_dns, tail);
62 LIST_INSERT_AFTER(addresses, m->fallback_dns, tail, address);
63 address = NULL;
64 }
65
66 return 0;
67}
68
69int config_parse_dnsv(
70 const char *unit,
71 const char *filename,
72 unsigned line,
73 const char *section,
74 unsigned section_line,
75 const char *lvalue,
76 int ltype,
77 const char *rvalue,
78 void *data,
79 void *userdata) {
80
81 Manager *m = userdata;
82 Address *address;
83
84 assert(filename);
85 assert(lvalue);
86 assert(rvalue);
87 assert(m);
88
89 while ((address = m->fallback_dns)) {
90 LIST_REMOVE(addresses, m->fallback_dns, address);
91 free(address);
92 }
93
94 set_fallback_dns(m, rvalue);
95
96 return 0;
97}
98
99static int manager_parse_config_file(Manager *m) {
100 static const char fn[] = "/etc/systemd/resolved.conf";
101 _cleanup_fclose_ FILE *f = NULL;
102 int r;
103
104 assert(m);
105
106 f = fopen(fn, "re");
107 if (!f) {
108 if (errno == ENOENT)
109 return 0;
110
111 log_warning("Failed to open configuration file %s: %m", fn);
112 return -errno;
113 }
114
115 r = config_parse(NULL, fn, f, "Resolve\0", config_item_perf_lookup,
116 (void*) resolved_gperf_lookup, false, false, m);
117 if (r < 0)
118 log_warning("Failed to parse configuration file: %s", strerror(-r));
119
120 return r;
121}
122
123int manager_new(Manager **ret) {
124 _cleanup_manager_free_ Manager *m = NULL;
125 int r;
126
127 m = new0(Manager, 1);
128 if (!m)
129 return -ENOMEM;
130
131 r = set_fallback_dns(m, DNS_SERVERS);
132 if (r < 0)
133 return r;
134
135 r = manager_parse_config_file(m);
136 if (r < 0)
137 return r;
138
139 r = sd_event_default(&m->event);
140 if (r < 0)
141 return r;
142
143 sd_event_add_signal(m->event, NULL, SIGTERM, NULL, NULL);
144 sd_event_add_signal(m->event, NULL, SIGINT, NULL, NULL);
145
146 sd_event_set_watchdog(m->event, true);
147
148 *ret = m;
149 m = NULL;
150
151 return 0;
152}
153
154void manager_free(Manager *m) {
155 Address *address;
156
157 if (!m)
158 return;
159
160 sd_event_unref(m->event);
161
162 while ((address = m->fallback_dns)) {
163 LIST_REMOVE(addresses, m->fallback_dns, address);
164 free(address);
165 }
166
167 free(m);
168}
169
170static void append_dns(FILE *f, void *dns, unsigned char family, unsigned *count) {
171 char buf[INET6_ADDRSTRLEN];
172 const char *address;
173
174 assert(f);
175 assert(dns);
176 assert(count);
177
178 address = inet_ntop(family, dns, buf, INET6_ADDRSTRLEN);
179 if (!address) {
180 log_warning("Invalid DNS address. Ignoring.");
181 return;
182 }
183
184 if (*count == MAXNS)
185 fputs("# Too many DNS servers configured, the following entries "
186 "may be ignored\n", f);
187
188 fprintf(f, "nameserver %s\n", address);
189
190 (*count) ++;
191}
192
193int manager_update_resolv_conf(Manager *m) {
b686acb2 194 const char *path = "/run/systemd/resolve/resolv.conf";
091a364c
TG
195 _cleanup_free_ char *temp_path = NULL;
196 _cleanup_fclose_ FILE *f = NULL;
197 _cleanup_free_ unsigned *indices = NULL;
198 Address *address;
199 unsigned count = 0;
200 int n, r, i;
201
202 assert(m);
203
b686acb2 204 r = fopen_temporary(path, &f, &temp_path);
091a364c
TG
205 if (r < 0)
206 return r;
207
208 fchmod(fileno(f), 0644);
209
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);
215
216 n = sd_network_get_ifindices(&indices);
217 if (n < 0)
218 n = 0;
219
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;
225
226 r = sd_network_dhcp_use_dns(indices[i]);
227 if (r > 0) {
228 r = sd_network_get_dhcp_lease(indices[i], &lease);
229 if (r >= 0) {
230 r = sd_dhcp_lease_get_dns(lease, &nameservers, &nameservers_size);
231 if (r >= 0) {
232 unsigned j;
233
234 for (j = 0; j < nameservers_size; j++)
235 append_dns(f, &nameservers[j], AF_INET, &count);
236 }
237 }
238 }
239
240 r = sd_network_get_dns(indices[i], &nameservers, &nameservers_size);
241 if (r >= 0) {
242 unsigned j;
243
244 for (j = 0; j < nameservers_size; j++)
245 append_dns(f, &nameservers[j], AF_INET, &count);
246
247 free(nameservers);
248 }
249
250 r = sd_network_get_dns6(indices[i], &nameservers6, &nameservers_size);
251 if (r >= 0) {
252 unsigned j;
253
254 for (j = 0; j < nameservers_size; j++)
255 append_dns(f, &nameservers6[j], AF_INET6, &count);
256
257 free(nameservers6);
258 }
259 }
260
261 LIST_FOREACH(addresses, address, m->fallback_dns)
262 append_dns(f, &address->in_addr, address->family, &count);
263
264 fflush(f);
265
b686acb2 266 if (ferror(f) || rename(temp_path, path) < 0) {
091a364c 267 r = -errno;
b686acb2 268 unlink(path);
091a364c
TG
269 unlink(temp_path);
270 return r;
271 }
272
273 return 0;
274}
275
276static int manager_network_event_handler(sd_event_source *s, int fd, uint32_t revents,
277 void *userdata) {
278 Manager *m = userdata;
279 int r;
280
281 assert(m);
282
283 r = manager_update_resolv_conf(m);
284 if (r < 0)
285 log_warning("Could not update resolv.conf: %s", strerror(-r));
286
287 sd_network_monitor_flush(m->network_monitor);
288
289 return 0;
290}
291
292int 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;
295 int r, fd, events;
296
297 r = sd_network_monitor_new(NULL, &monitor);
298 if (r < 0)
299 return r;
300
301 fd = sd_network_monitor_get_fd(monitor);
302 if (fd < 0)
303 return fd;
304
305 events = sd_network_monitor_get_events(monitor);
306 if (events < 0)
307 return events;
308
309 r = sd_event_add_io(m->event, &event_source, fd, events,
310 &manager_network_event_handler, m);
311 if (r < 0)
312 return r;
313
314 m->network_monitor = monitor;
315 m->network_event_source = event_source;
316 monitor = NULL;
317 event_source = NULL;
318
319 return 0;
320}