chiark / gitweb /
networkd: resolv.conf - reword comment
[elogind.git] / src / network / networkd-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 2013 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 <resolv.h>
23
24 #include "path-util.h"
25 #include "networkd.h"
26 #include "libudev-private.h"
27 #include "udev-util.h"
28 #include "mkdir.h"
29
30 const char* const network_dirs[] = {
31         "/etc/systemd/network",
32         "/run/systemd/network",
33         "/usr/lib/systemd/network",
34 #ifdef HAVE_SPLIT_USER
35         "/lib/systemd/network",
36 #endif
37         NULL};
38
39 int manager_new(Manager **ret) {
40         _cleanup_manager_free_ Manager *m = NULL;
41         int r;
42
43         m = new0(Manager, 1);
44         if (!m)
45                 return -ENOMEM;
46
47         r = sd_event_default(&m->event);
48         if (r < 0)
49                 return r;
50
51         sd_event_set_watchdog(m->event, true);
52
53         r = sd_rtnl_open(RTMGRP_LINK | RTMGRP_IPV4_IFADDR, &m->rtnl);
54         if (r < 0)
55                 return r;
56
57         r = sd_bus_default_system(&m->bus);
58         if (r < 0)
59                 return r;
60
61         m->udev = udev_new();
62         if (!m->udev)
63                 return -ENOMEM;
64
65         m->udev_monitor = udev_monitor_new_from_netlink(m->udev, "udev");
66         if (!m->udev_monitor)
67                 return -ENOMEM;
68
69         m->links = hashmap_new(uint64_hash_func, uint64_compare_func);
70         if (!m->links)
71                 return -ENOMEM;
72
73         m->bridges = hashmap_new(string_hash_func, string_compare_func);
74         if (!m->bridges)
75                 return -ENOMEM;
76
77         LIST_HEAD_INIT(m->networks);
78
79         *ret = m;
80         m = NULL;
81
82         return 0;
83 }
84
85 void manager_free(Manager *m) {
86         Network *network;
87         Bridge *bridge;
88         Link *link;
89
90         udev_monitor_unref(m->udev_monitor);
91         udev_unref(m->udev);
92         sd_bus_unref(m->bus);
93         sd_event_source_unref(m->udev_event_source);
94         sd_event_unref(m->event);
95
96         while ((network = m->networks))
97                 network_free(network);
98
99         while ((link = hashmap_first(m->links)))
100                 link_free(link);
101         hashmap_free(m->links);
102
103         while ((bridge = hashmap_first(m->bridges)))
104                 bridge_free(bridge);
105         hashmap_free(m->bridges);
106
107         sd_rtnl_unref(m->rtnl);
108
109         free(m);
110 }
111
112 int manager_load_config(Manager *m) {
113         int r;
114
115         /* update timestamp */
116         paths_check_timestamp(network_dirs, &m->network_dirs_ts_usec, true);
117
118         r = bridge_load(m);
119         if (r < 0)
120                 return r;
121
122         r = network_load(m);
123         if (r < 0)
124                 return r;
125
126         return 0;
127 }
128
129 bool manager_should_reload(Manager *m) {
130         return paths_check_timestamp(network_dirs, &m->network_dirs_ts_usec, false);
131 }
132
133 static int manager_process_link(Manager *m, struct udev_device *device) {
134         Link *link;
135         int r;
136
137         if (streq_ptr(udev_device_get_action(device), "remove")) {
138                 uint64_t ifindex;
139
140                 log_debug("%s: link removed", udev_device_get_sysname(device));
141
142                 ifindex = udev_device_get_ifindex(device);
143                 link = hashmap_get(m->links, &ifindex);
144                 if (!link)
145                         return 0;
146
147                 link_free(link);
148         } else {
149                 r = link_add(m, device, &link);
150                 if (r < 0) {
151                         if (r == -EEXIST)
152                                 log_debug("%s: link already exists, ignoring",
153                                           link->ifname);
154                         else
155                                 log_error("%s: could not handle link: %s",
156                                           udev_device_get_sysname(device),
157                                           strerror(-r));
158                 } else
159                         log_debug("%s: link (with ifindex %" PRIu64") added",
160                                   link->ifname, link->ifindex);
161         }
162
163         return 0;
164 }
165
166 int manager_udev_enumerate_links(Manager *m) {
167         _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
168         struct udev_list_entry *item = NULL, *first = NULL;
169         int r;
170
171         assert(m);
172
173         e = udev_enumerate_new(m->udev);
174         if (!e)
175                 return -ENOMEM;
176
177         r = udev_enumerate_add_match_subsystem(e, "net");
178         if (r < 0)
179                 return r;
180
181         r = udev_enumerate_add_match_is_initialized(e);
182         if (r < 0)
183                 return r;
184
185         r = udev_enumerate_scan_devices(e);
186         if (r < 0)
187                 return r;
188
189         first = udev_enumerate_get_list_entry(e);
190         udev_list_entry_foreach(item, first) {
191                 _cleanup_udev_device_unref_ struct udev_device *d = NULL;
192                 int k;
193
194                 d = udev_device_new_from_syspath(m->udev, udev_list_entry_get_name(item));
195                 if (!d)
196                         return -ENOMEM;
197
198                 k = manager_process_link(m, d);
199                 if (k < 0)
200                         r = k;
201         }
202
203         return r;
204 }
205
206 static int manager_dispatch_link_udev(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
207         Manager *m = userdata;
208         struct udev_monitor *monitor = m->udev_monitor;
209         _cleanup_udev_device_unref_ struct udev_device *device = NULL;
210
211         device = udev_monitor_receive_device(monitor);
212         if (!device)
213                 return -ENOMEM;
214
215         manager_process_link(m, device);
216         return 0;
217 }
218
219 int manager_udev_listen(Manager *m) {
220         int r;
221
222         r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_monitor, "net", NULL);
223         if (r < 0) {
224                 log_error("Could not add udev monitor filter: %s", strerror(-r));
225                 return r;
226         }
227
228         r = udev_monitor_enable_receiving(m->udev_monitor);
229         if (r < 0) {
230                 log_error("Could not enable udev monitor");
231                 return r;
232         }
233
234         r = sd_event_add_io(m->event,
235                         udev_monitor_get_fd(m->udev_monitor),
236                         EPOLLIN, manager_dispatch_link_udev,
237                         m, &m->udev_event_source);
238         if (r < 0)
239                 return r;
240
241         return 0;
242 }
243
244 static int manager_rtnl_process_link(sd_rtnl *rtnl, sd_rtnl_message *message, void *userdata) {
245         Manager *m = userdata;
246         Link *link;
247         uint64_t ifindex_64;
248         int r, ifindex;
249
250         r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
251         if (r < 0) {
252                 log_debug("received RTM_NEWLINK message without valid ifindex");
253                 return 0;
254         }
255
256         ifindex_64 = ifindex;
257         link = hashmap_get(m->links, &ifindex_64);
258         if (!link) {
259                 log_debug("received RTM_NEWLINK message for untracked ifindex %d", ifindex);
260                 return 0;
261         }
262
263         /* only track the status of links we want to manage */
264         if (link->network) {
265                 r = link_update(link, message);
266                 if (r < 0)
267                         return 0;
268         } else
269                 log_debug("%s: received RTM_NEWLINK message for unmanaged link", link->ifname);
270
271         return 1;
272 }
273
274 int manager_rtnl_listen(Manager *m) {
275         int r;
276
277         r = sd_rtnl_attach_event(m->rtnl, m->event, 0);
278         if (r < 0)
279                 return r;
280
281         r = sd_rtnl_add_match(m->rtnl, RTM_NEWLINK, &manager_rtnl_process_link, m);
282         if (r < 0)
283                 return r;
284
285         return 0;
286 }
287
288 int manager_bus_listen(Manager *m) {
289         int r;
290
291         r = sd_bus_attach_event(m->bus, m->event, 0);
292         if (r < 0)
293                 return r;
294
295         return 0;
296 }
297
298 static void append_dns(FILE *f, struct in_addr *dns, unsigned char family, unsigned *count) {
299         char buf[INET6_ADDRSTRLEN];
300         const char *address;
301
302         address = inet_ntop(family, dns, buf, INET6_ADDRSTRLEN);
303         if (!address) {
304                 log_warning("Invalid DNS address. Ignoring.");
305                 return;
306         }
307
308         if (*count == MAXNS)
309                 fputs("# Too many DNS servers configured, the following entries "
310                       "will be ignored\n", f);
311
312         fprintf(f, "nameserver %s\n", address);
313
314         (*count) ++;
315 }
316
317 int manager_update_resolv_conf(Manager *m) {
318         _cleanup_free_ char *temp_path = NULL;
319         _cleanup_fclose_ FILE *f = NULL;
320         Link *link;
321         Iterator i;
322         unsigned count = 0;
323         int r;
324
325         assert(m);
326
327         r = mkdir_safe_label("/run/systemd/network", 0755, 0, 0);
328         if (r < 0)
329                 return r;
330
331         r = fopen_temporary("/run/systemd/network/resolv.conf", &f, &temp_path);
332         if (r < 0)
333                 return r;
334
335         fchmod(fileno(f), 0644);
336
337         fputs("# This file is managed by systemd-networkd(8). Do not edit.\n#\n"
338               "# Third party programs must not access this file directly, but\n"
339               "# only through the symlink at /etc/resolv.conf. To manage\n"
340               "# resolv.conf(5) in a different way, replace the symlink by a\n"
341               "# static file or a different symlink.\n\n", f);
342
343         HASHMAP_FOREACH(link, m->links, i) {
344                 if (link->dhcp) {
345                         struct in_addr *nameservers;
346                         size_t nameservers_size;
347
348                         r = sd_dhcp_client_get_dns(link->dhcp, &nameservers, &nameservers_size);
349                         if (r >= 0) {
350                                 unsigned j;
351
352                                 for (j = 0; j < nameservers_size; j++)
353                                         append_dns(f, &nameservers[j], AF_INET, &count);
354                         }
355                 }
356         }
357
358         HASHMAP_FOREACH(link, m->links, i)
359                 if (link->network && link->network->dns)
360                         append_dns(f, &link->network->dns->in_addr.in,
361                                    link->network->dns->family, &count);
362
363         fflush(f);
364
365         if (ferror(f) || rename(temp_path, "/run/systemd/network/resolv.conf") < 0) {
366                 r = -errno;
367                 unlink("/run/systemd/network/resolv.conf");
368                 unlink(temp_path);
369                 return r;
370         }
371
372         return 0;
373 }