chiark / gitweb /
networkd: update mac address in clients when it changes
[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 "rtnl-util.h"
29 #include "mkdir.h"
30 #include "virt.h"
31
32 const char* const network_dirs[] = {
33         "/etc/systemd/network",
34         "/run/systemd/network",
35         "/usr/lib/systemd/network",
36 #ifdef HAVE_SPLIT_USR
37         "/lib/systemd/network",
38 #endif
39         NULL};
40
41 static int dispatch_sigterm(sd_event_source *es, const struct signalfd_siginfo *si, void *userdata) {
42         Manager *m = userdata;
43
44         assert(m);
45
46         log_received_signal(LOG_INFO, si);
47
48         sd_event_exit(m->event, 0);
49         return 0;
50 }
51
52 static int setup_signals(Manager *m) {
53         sigset_t mask;
54         int r;
55
56         assert(m);
57
58         assert_se(sigemptyset(&mask) == 0);
59         sigset_add_many(&mask, SIGINT, SIGTERM, -1);
60         assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0);
61
62         r = sd_event_add_signal(m->event, &m->sigterm_event_source, SIGTERM, dispatch_sigterm, m);
63         if (r < 0)
64                 return r;
65
66         r = sd_event_add_signal(m->event, &m->sigint_event_source, SIGINT, dispatch_sigterm, m);
67         if (r < 0)
68                 return r;
69
70         return 0;
71 }
72
73 int manager_new(Manager **ret) {
74         _cleanup_manager_free_ Manager *m = NULL;
75         int r;
76
77         m = new0(Manager, 1);
78         if (!m)
79                 return -ENOMEM;
80
81         r = sd_event_default(&m->event);
82         if (r < 0)
83                 return r;
84
85         sd_event_set_watchdog(m->event, true);
86
87         r = sd_rtnl_open(&m->rtnl, RTMGRP_LINK | RTMGRP_IPV4_IFADDR);
88         if (r < 0)
89                 return r;
90
91         r = sd_bus_default_system(&m->bus);
92         if (r < 0 && r != -ENOENT) /* TODO: drop when we can rely on kdbus */
93                 return r;
94
95         r = setup_signals(m);
96         if (r < 0)
97                 return r;
98
99         m->udev = udev_new();
100         if (!m->udev)
101                 return -ENOMEM;
102
103         /* udev does not initialize devices inside containers,
104          * so we rely on them being already initialized before
105          * entering the container */
106         if (detect_container(NULL) > 0) {
107                 m->udev_monitor = udev_monitor_new_from_netlink(m->udev, "kernel");
108                 if (!m->udev_monitor)
109                         return -ENOMEM;
110         } else {
111                 m->udev_monitor = udev_monitor_new_from_netlink(m->udev, "udev");
112                 if (!m->udev_monitor)
113                         return -ENOMEM;
114         }
115
116         m->links = hashmap_new(uint64_hash_func, uint64_compare_func);
117         if (!m->links)
118                 return -ENOMEM;
119
120         m->netdevs = hashmap_new(string_hash_func, string_compare_func);
121         if (!m->netdevs)
122                 return -ENOMEM;
123
124         LIST_HEAD_INIT(m->networks);
125
126         *ret = m;
127         m = NULL;
128
129         return 0;
130 }
131
132 void manager_free(Manager *m) {
133         Network *network;
134         NetDev *netdev;
135         Link *link;
136
137         if (!m)
138                 return;
139
140         udev_monitor_unref(m->udev_monitor);
141         udev_unref(m->udev);
142         sd_bus_unref(m->bus);
143         sd_event_source_unref(m->udev_event_source);
144         sd_event_source_unref(m->sigterm_event_source);
145         sd_event_source_unref(m->sigint_event_source);
146         sd_event_unref(m->event);
147
148         while ((network = m->networks))
149                 network_free(network);
150
151         while ((link = hashmap_first(m->links)))
152                 link_free(link);
153         hashmap_free(m->links);
154
155         while ((netdev = hashmap_first(m->netdevs)))
156                 netdev_free(netdev);
157         hashmap_free(m->netdevs);
158
159         sd_rtnl_unref(m->rtnl);
160
161         free(m);
162 }
163
164 int manager_load_config(Manager *m) {
165         int r;
166
167         /* update timestamp */
168         paths_check_timestamp(network_dirs, &m->network_dirs_ts_usec, true);
169
170         r = netdev_load(m);
171         if (r < 0)
172                 return r;
173
174         r = network_load(m);
175         if (r < 0)
176                 return r;
177
178         return 0;
179 }
180
181 bool manager_should_reload(Manager *m) {
182         return paths_check_timestamp(network_dirs, &m->network_dirs_ts_usec, false);
183 }
184
185 static int manager_process_link(Manager *m, struct udev_device *device) {
186         Link *link = NULL;
187         int r;
188
189         assert(m);
190         assert(device);
191
192         link_get(m, udev_device_get_ifindex(device), &link);
193
194         if (streq_ptr(udev_device_get_action(device), "remove")) {
195                 log_debug("%s: link removed", udev_device_get_sysname(device));
196
197                 if (link)
198                         link_free(link);
199         } else {
200                 if (link) {
201                         log_debug("%s: link already exists, ignoring",
202                                   link->ifname);
203                         return 0;
204                 }
205
206                 r = link_add(m, device, &link);
207                 if (r < 0) {
208                         log_error("%s: could not handle link: %s",
209                                   udev_device_get_sysname(device),
210                                   strerror(-r));
211                 } else
212                         log_debug("%s: link (with ifindex %" PRIu64") added",
213                                   link->ifname, link->ifindex);
214         }
215
216         return 0;
217 }
218
219 int manager_udev_enumerate_links(Manager *m) {
220         _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
221         struct udev_list_entry *item = NULL, *first = NULL;
222         int r;
223
224         assert(m);
225
226         e = udev_enumerate_new(m->udev);
227         if (!e)
228                 return -ENOMEM;
229
230         r = udev_enumerate_add_match_subsystem(e, "net");
231         if (r < 0)
232                 return r;
233
234         /* udev does not initialize devices inside containers,
235          * so we rely on them being already initialized before
236          * entering the container */
237         if (detect_container(NULL) <= 0) {
238                 r = udev_enumerate_add_match_is_initialized(e);
239                 if (r < 0)
240                         return r;
241         }
242
243         r = udev_enumerate_scan_devices(e);
244         if (r < 0)
245                 return r;
246
247         first = udev_enumerate_get_list_entry(e);
248         udev_list_entry_foreach(item, first) {
249                 _cleanup_udev_device_unref_ struct udev_device *d = NULL;
250                 int k;
251
252                 d = udev_device_new_from_syspath(m->udev, udev_list_entry_get_name(item));
253                 if (!d)
254                         return -ENOMEM;
255
256                 k = manager_process_link(m, d);
257                 if (k < 0)
258                         r = k;
259         }
260
261         return r;
262 }
263
264 static int manager_dispatch_link_udev(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
265         Manager *m = userdata;
266         struct udev_monitor *monitor = m->udev_monitor;
267         _cleanup_udev_device_unref_ struct udev_device *device = NULL;
268
269         device = udev_monitor_receive_device(monitor);
270         if (!device)
271                 return -ENOMEM;
272
273         manager_process_link(m, device);
274         return 0;
275 }
276
277 int manager_udev_listen(Manager *m) {
278         int r;
279
280         r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_monitor, "net", NULL);
281         if (r < 0) {
282                 log_error("Could not add udev monitor filter: %s", strerror(-r));
283                 return r;
284         }
285
286         r = udev_monitor_enable_receiving(m->udev_monitor);
287         if (r < 0) {
288                 log_error("Could not enable udev monitor");
289                 return r;
290         }
291
292         r = sd_event_add_io(m->event,
293                         &m->udev_event_source,
294                         udev_monitor_get_fd(m->udev_monitor),
295                         EPOLLIN, manager_dispatch_link_udev,
296                         m);
297         if (r < 0)
298                 return r;
299
300         return 0;
301 }
302
303 static int manager_rtnl_process_link(sd_rtnl *rtnl, sd_rtnl_message *message, void *userdata) {
304         Manager *m = userdata;
305         Link *link;
306         char *name;
307         int r, ifindex;
308
309         assert(rtnl);
310         assert(message);
311         assert(m);
312
313         r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
314         if (r < 0 || ifindex <= 0) {
315                 log_warning("received RTM_NEWLINK message without valid ifindex");
316                 return 0;
317         }
318
319         r = sd_rtnl_message_read_string(message, IFLA_IFNAME, &name);
320         if (r < 0)
321                 log_warning("received RTM_NEWLINK message without valid ifname");
322         else {
323                 NetDev *netdev;
324
325                 r = netdev_get(m, name, &netdev);
326                 if (r >= 0) {
327                         r = netdev_set_ifindex(netdev, ifindex);
328                         if (r < 0)
329                                 log_debug("could not set ifindex of netdev '%s' to %d: %s",
330                                           name, ifindex, strerror(-r));
331                 }
332         }
333
334         r = link_get(m, ifindex, &link);
335         if (r < 0) {
336                 log_debug("received RTM_NEWLINK message for untracked ifindex %d", ifindex);
337                 return 0;
338         }
339
340         /* only track the status of links we want to manage */
341         if (link->network) {
342                 r = link_update(link, message);
343                 if (r < 0)
344                         return 0;
345         } else
346                 log_debug("%s: received RTM_NEWLINK message for unmanaged link", link->ifname);
347
348         return 1;
349 }
350
351 int manager_rtnl_listen(Manager *m) {
352         int r;
353
354         r = sd_rtnl_attach_event(m->rtnl, m->event, 0);
355         if (r < 0)
356                 return r;
357
358         r = sd_rtnl_add_match(m->rtnl, RTM_NEWLINK, &manager_rtnl_process_link, m);
359         if (r < 0)
360                 return r;
361
362         return 0;
363 }
364
365 int manager_bus_listen(Manager *m) {
366         int r;
367
368         assert(m->event);
369
370         if (!m->bus) /* TODO: drop when we can rely on kdbus */
371                 return 0;
372
373         r = sd_bus_attach_event(m->bus, m->event, 0);
374         if (r < 0)
375                 return r;
376
377         return 0;
378 }
379
380 static void append_dns(FILE *f, struct in_addr *dns, unsigned char family, unsigned *count) {
381         char buf[INET6_ADDRSTRLEN];
382         const char *address;
383
384         address = inet_ntop(family, dns, buf, INET6_ADDRSTRLEN);
385         if (!address) {
386                 log_warning("Invalid DNS address. Ignoring.");
387                 return;
388         }
389
390         if (*count == MAXNS)
391                 fputs("# Too many DNS servers configured, the following entries "
392                       "will be ignored\n", f);
393
394         fprintf(f, "nameserver %s\n", address);
395
396         (*count) ++;
397 }
398
399 int manager_update_resolv_conf(Manager *m) {
400         _cleanup_free_ char *temp_path = NULL;
401         _cleanup_fclose_ FILE *f = NULL;
402         Link *link;
403         Iterator i;
404         unsigned count = 0;
405         const char *domainname = NULL;
406         int r;
407
408         assert(m);
409
410         r = fopen_temporary("/run/systemd/network/resolv.conf", &f, &temp_path);
411         if (r < 0)
412                 return r;
413
414         fchmod(fileno(f), 0644);
415
416         fputs("# This file is managed by systemd-networkd(8). Do not edit.\n#\n"
417               "# Third party programs must not access this file directly, but\n"
418               "# only through the symlink at /etc/resolv.conf. To manage\n"
419               "# resolv.conf(5) in a different way, replace the symlink by a\n"
420               "# static file or a different symlink.\n\n", f);
421
422         HASHMAP_FOREACH(link, m->links, i) {
423                 if (link->dhcp_lease) {
424                         struct in_addr *nameservers;
425                         size_t nameservers_size;
426
427                         if (link->network->dhcp_dns) {
428                                 r = sd_dhcp_lease_get_dns(link->dhcp_lease, &nameservers, &nameservers_size);
429                                 if (r >= 0) {
430                                         unsigned j;
431
432                                         for (j = 0; j < nameservers_size; j++)
433                                                 append_dns(f, &nameservers[j], AF_INET, &count);
434                                 }
435                         }
436
437                         if (link->network->dhcp_domainname && !domainname) {
438                                 r = sd_dhcp_lease_get_domainname(link->dhcp_lease, &domainname);
439                                 if (r >= 0)
440                                        fprintf(f, "domain %s\n", domainname);
441                         }
442                 }
443         }
444
445         HASHMAP_FOREACH(link, m->links, i) {
446                 if (link->network && link->network->dns) {
447                         Address *address;
448                         Iterator j;
449
450                         SET_FOREACH(address, link->network->dns, j) {
451                                 append_dns(f, &address->in_addr.in,
452                                            address->family, &count);
453                         }
454                 }
455         }
456
457         fflush(f);
458
459         if (ferror(f) || rename(temp_path, "/run/systemd/network/resolv.conf") < 0) {
460                 r = -errno;
461                 unlink("/run/systemd/network/resolv.conf");
462                 unlink(temp_path);
463                 return r;
464         }
465
466         return 0;
467 }