]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/resolve/resolved-manager.c
networkd: remove unused variable
[thirdparty/systemd.git] / src / resolve / resolved-manager.c
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"
33
34 static 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
69 int 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
99 static int manager_parse_config_file(Manager *m) {
100 int r;
101
102 assert(m);
103
104 r = config_parse(NULL, "/etc/systemd/resolved.conf", NULL,
105 "Resolve\0", config_item_perf_lookup, (void*) resolved_gperf_lookup,
106 false, false, m);
107 if (r < 0)
108 log_warning("Failed to parse configuration file: %s", strerror(-r));
109
110 return r;
111 }
112
113 int manager_new(Manager **ret) {
114 _cleanup_manager_free_ Manager *m = NULL;
115 int r;
116
117 assert(ret);
118
119 m = new0(Manager, 1);
120 if (!m)
121 return -ENOMEM;
122
123 r = set_fallback_dns(m, DNS_SERVERS);
124 if (r < 0)
125 return r;
126
127 r = manager_parse_config_file(m);
128 if (r < 0)
129 return r;
130
131 r = sd_event_default(&m->event);
132 if (r < 0)
133 return r;
134
135 sd_event_add_signal(m->event, NULL, SIGTERM, NULL, NULL);
136 sd_event_add_signal(m->event, NULL, SIGINT, NULL, NULL);
137
138 sd_event_set_watchdog(m->event, true);
139
140 *ret = m;
141 m = NULL;
142
143 return 0;
144 }
145
146 void manager_free(Manager *m) {
147 Address *address;
148
149 if (!m)
150 return;
151
152 sd_event_source_unref(m->network_event_source);
153 sd_network_monitor_unref(m->network_monitor);
154 sd_event_unref(m->event);
155
156 while ((address = m->fallback_dns)) {
157 LIST_REMOVE(addresses, m->fallback_dns, address);
158 free(address);
159 }
160
161 free(m);
162 }
163
164 static void append_dns(FILE *f, void *dns, unsigned char family, unsigned *count) {
165 char buf[INET6_ADDRSTRLEN];
166 const char *address;
167
168 assert(f);
169 assert(dns);
170 assert(count);
171
172 address = inet_ntop(family, dns, buf, INET6_ADDRSTRLEN);
173 if (!address) {
174 log_warning("Invalid DNS address. Ignoring.");
175 return;
176 }
177
178 if (*count == MAXNS)
179 fputs("# Too many DNS servers configured, the following entries "
180 "may be ignored\n", f);
181
182 fprintf(f, "nameserver %s\n", address);
183
184 (*count) ++;
185 }
186
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;
192 Address *address;
193 unsigned count = 0;
194 int n, r, i;
195
196 assert(m);
197
198 r = fopen_temporary(path, &f, &temp_path);
199 if (r < 0)
200 return r;
201
202 fchmod(fileno(f), 0644);
203
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);
209
210 n = sd_network_get_ifindices(&indices);
211 if (n < 0)
212 n = 0;
213
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;
219
220 r = sd_network_dhcp_use_dns(indices[i]);
221 if (r > 0) {
222 r = sd_network_get_dhcp_lease(indices[i], &lease);
223 if (r >= 0) {
224 r = sd_dhcp_lease_get_dns(lease, &nameservers, &nameservers_size);
225 if (r >= 0) {
226 unsigned j;
227
228 for (j = 0; j < nameservers_size; j++)
229 append_dns(f, &nameservers[j], AF_INET, &count);
230 }
231 }
232 }
233
234 r = sd_network_get_dns(indices[i], &nameservers, &nameservers_size);
235 if (r >= 0) {
236 unsigned j;
237
238 for (j = 0; j < nameservers_size; j++)
239 append_dns(f, &nameservers[j], AF_INET, &count);
240
241 free(nameservers);
242 }
243
244 r = sd_network_get_dns6(indices[i], &nameservers6, &nameservers_size);
245 if (r >= 0) {
246 unsigned j;
247
248 for (j = 0; j < nameservers_size; j++)
249 append_dns(f, &nameservers6[j], AF_INET6, &count);
250
251 free(nameservers6);
252 }
253 }
254
255 LIST_FOREACH(addresses, address, m->fallback_dns)
256 append_dns(f, &address->in_addr, address->family, &count);
257
258 fflush(f);
259
260 if (ferror(f) || rename(temp_path, path) < 0) {
261 r = -errno;
262 unlink(path);
263 unlink(temp_path);
264 return r;
265 }
266
267 return 0;
268 }
269
270 static int manager_network_event_handler(sd_event_source *s, int fd, uint32_t revents,
271 void *userdata) {
272 Manager *m = userdata;
273 int r;
274
275 assert(m);
276
277 r = manager_update_resolv_conf(m);
278 if (r < 0)
279 log_warning("Could not update resolv.conf: %s", strerror(-r));
280
281 sd_network_monitor_flush(m->network_monitor);
282
283 return 0;
284 }
285
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;
289 int r, fd, events;
290
291 r = sd_network_monitor_new(NULL, &monitor);
292 if (r < 0)
293 return r;
294
295 fd = sd_network_monitor_get_fd(monitor);
296 if (fd < 0)
297 return fd;
298
299 events = sd_network_monitor_get_events(monitor);
300 if (events < 0)
301 return events;
302
303 r = sd_event_add_io(m->event, &event_source, fd, events,
304 &manager_network_event_handler, m);
305 if (r < 0)
306 return r;
307
308 m->network_monitor = monitor;
309 m->network_event_source = event_source;
310 monitor = NULL;
311 event_source = NULL;
312
313 return 0;
314 }