Line data Source code
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 <sys/socket.h>
23 : #include <linux/if.h>
24 :
25 : #include "conf-parser.h"
26 : #include "path-util.h"
27 : #include "networkd.h"
28 : #include "networkd-netdev.h"
29 : #include "networkd-link.h"
30 : #include "libudev-private.h"
31 : #include "udev-util.h"
32 : #include "netlink-util.h"
33 : #include "bus-util.h"
34 : #include "def.h"
35 : #include "virt.h"
36 :
37 : #include "sd-netlink.h"
38 : #include "sd-daemon.h"
39 :
40 : /* use 8 MB for receive socket kernel queue. */
41 : #define RCVBUF_SIZE (8*1024*1024)
42 :
43 : const char* const network_dirs[] = {
44 : "/etc/systemd/network",
45 : "/run/systemd/network",
46 : "/usr/lib/systemd/network",
47 : #ifdef HAVE_SPLIT_USR
48 : "/lib/systemd/network",
49 : #endif
50 : NULL};
51 :
52 1 : static int setup_default_address_pool(Manager *m) {
53 : AddressPool *p;
54 : int r;
55 :
56 1 : assert(m);
57 :
58 : /* Add in the well-known private address ranges. */
59 :
60 1 : r = address_pool_new_from_string(m, &p, AF_INET6, "fc00::", 7);
61 1 : if (r < 0)
62 0 : return r;
63 :
64 1 : r = address_pool_new_from_string(m, &p, AF_INET, "192.168.0.0", 16);
65 1 : if (r < 0)
66 0 : return r;
67 :
68 1 : r = address_pool_new_from_string(m, &p, AF_INET, "172.16.0.0", 12);
69 1 : if (r < 0)
70 0 : return r;
71 :
72 1 : r = address_pool_new_from_string(m, &p, AF_INET, "10.0.0.0", 8);
73 1 : if (r < 0)
74 0 : return r;
75 :
76 1 : return 0;
77 : }
78 :
79 0 : static int on_bus_retry(sd_event_source *s, usec_t usec, void *userdata) {
80 0 : Manager *m = userdata;
81 :
82 0 : assert(s);
83 0 : assert(m);
84 :
85 0 : m->bus_retry_event_source = sd_event_source_unref(m->bus_retry_event_source);
86 :
87 0 : manager_connect_bus(m);
88 :
89 0 : return 0;
90 : }
91 :
92 0 : static int manager_reset_all(Manager *m) {
93 : Link *link;
94 : Iterator i;
95 : int r;
96 :
97 0 : assert(m);
98 :
99 0 : HASHMAP_FOREACH(link, m->links, i) {
100 0 : r = link_carrier_reset(link);
101 0 : if (r < 0)
102 0 : log_link_warning_errno(link, r, "could not reset carrier: %m");
103 : }
104 :
105 0 : return 0;
106 : }
107 :
108 0 : static int match_prepare_for_sleep(sd_bus_message *message, void *userdata, sd_bus_error *ret_error) {
109 0 : Manager *m = userdata;
110 : int b, r;
111 :
112 0 : assert(message);
113 :
114 0 : r = sd_bus_message_read(message, "b", &b);
115 0 : if (r < 0) {
116 0 : log_debug_errno(r, "Failed to parse PrepareForSleep signal: %m");
117 0 : return 0;
118 : }
119 :
120 0 : if (b)
121 0 : return 0;
122 :
123 0 : log_debug("Coming back from suspend, resetting all connections...");
124 :
125 0 : manager_reset_all(m);
126 :
127 0 : return 0;
128 : }
129 :
130 0 : int manager_connect_bus(Manager *m) {
131 : int r;
132 :
133 0 : assert(m);
134 :
135 0 : r = sd_bus_default_system(&m->bus);
136 0 : if (r == -ENOENT) {
137 : /* We failed to connect? Yuck, we must be in early
138 : * boot. Let's try in 5s again. As soon as we have
139 : * kdbus we can stop doing this... */
140 :
141 0 : log_debug_errno(r, "Failed to connect to bus, trying again in 5s: %m");
142 :
143 0 : r = sd_event_add_time(m->event, &m->bus_retry_event_source, CLOCK_MONOTONIC, now(CLOCK_MONOTONIC) + 5*USEC_PER_SEC, 0, on_bus_retry, m);
144 0 : if (r < 0)
145 0 : return log_error_errno(r, "Failed to install bus reconnect time event: %m");
146 :
147 0 : return 0;
148 0 : } if (r < 0)
149 0 : return r;
150 :
151 0 : r = sd_bus_add_match(m->bus, &m->prepare_for_sleep_slot,
152 : "type='signal',"
153 : "sender='org.freedesktop.login1',"
154 : "interface='org.freedesktop.login1.Manager',"
155 : "member='PrepareForSleep',"
156 : "path='/org/freedesktop/login1'",
157 : match_prepare_for_sleep,
158 : m);
159 0 : if (r < 0)
160 0 : return log_error_errno(r, "Failed to add match for PrepareForSleep: %m");
161 :
162 0 : r = sd_bus_add_object_vtable(m->bus, NULL, "/org/freedesktop/network1", "org.freedesktop.network1.Manager", manager_vtable, m);
163 0 : if (r < 0)
164 0 : return log_error_errno(r, "Failed to add manager object vtable: %m");
165 :
166 0 : r = sd_bus_add_fallback_vtable(m->bus, NULL, "/org/freedesktop/network1/link", "org.freedesktop.network1.Link", link_vtable, link_object_find, m);
167 0 : if (r < 0)
168 0 : return log_error_errno(r, "Failed to add link object vtable: %m");
169 :
170 0 : r = sd_bus_add_node_enumerator(m->bus, NULL, "/org/freedesktop/network1/link", link_node_enumerator, m);
171 0 : if (r < 0)
172 0 : return log_error_errno(r, "Failed to add link enumerator: %m");
173 :
174 0 : r = sd_bus_add_fallback_vtable(m->bus, NULL, "/org/freedesktop/network1/network", "org.freedesktop.network1.Network", network_vtable, network_object_find, m);
175 0 : if (r < 0)
176 0 : return log_error_errno(r, "Failed to add network object vtable: %m");
177 :
178 0 : r = sd_bus_add_node_enumerator(m->bus, NULL, "/org/freedesktop/network1/network", network_node_enumerator, m);
179 0 : if (r < 0)
180 0 : return log_error_errno(r, "Failed to add network enumerator: %m");
181 :
182 0 : r = sd_bus_request_name(m->bus, "org.freedesktop.network1", 0);
183 0 : if (r < 0)
184 0 : return log_error_errno(r, "Failed to register name: %m");
185 :
186 0 : r = sd_bus_attach_event(m->bus, m->event, 0);
187 0 : if (r < 0)
188 0 : return log_error_errno(r, "Failed to attach bus to event loop: %m");
189 :
190 0 : return 0;
191 : }
192 :
193 0 : static int manager_udev_process_link(Manager *m, struct udev_device *device) {
194 0 : Link *link = NULL;
195 : int r, ifindex;
196 :
197 0 : assert(m);
198 0 : assert(device);
199 :
200 0 : if (!streq_ptr(udev_device_get_action(device), "add"))
201 0 : return 0;
202 :
203 0 : ifindex = udev_device_get_ifindex(device);
204 0 : if (ifindex <= 0) {
205 0 : log_debug("ignoring udev ADD event for device with invalid ifindex");
206 0 : return 0;
207 : }
208 :
209 0 : r = link_get(m, ifindex, &link);
210 0 : if (r == -ENODEV)
211 0 : return 0;
212 0 : else if (r < 0)
213 0 : return r;
214 :
215 0 : r = link_initialized(link, device);
216 0 : if (r < 0)
217 0 : return r;
218 :
219 0 : return 0;
220 : }
221 :
222 0 : static int manager_dispatch_link_udev(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
223 0 : Manager *m = userdata;
224 0 : struct udev_monitor *monitor = m->udev_monitor;
225 0 : _cleanup_udev_device_unref_ struct udev_device *device = NULL;
226 :
227 0 : device = udev_monitor_receive_device(monitor);
228 0 : if (!device)
229 0 : return -ENOMEM;
230 :
231 0 : manager_udev_process_link(m, device);
232 0 : return 0;
233 : }
234 :
235 1 : static int manager_connect_udev(Manager *m) {
236 : int r;
237 :
238 : /* udev does not initialize devices inside containers,
239 : * so we rely on them being already initialized before
240 : * entering the container */
241 1 : if (detect_container(NULL) > 0)
242 0 : return 0;
243 :
244 1 : m->udev = udev_new();
245 1 : if (!m->udev)
246 0 : return -ENOMEM;
247 :
248 1 : m->udev_monitor = udev_monitor_new_from_netlink(m->udev, "udev");
249 1 : if (!m->udev_monitor)
250 0 : return -ENOMEM;
251 :
252 1 : r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_monitor, "net", NULL);
253 1 : if (r < 0)
254 0 : return log_error_errno(r, "Could not add udev monitor filter: %m");
255 :
256 1 : r = udev_monitor_enable_receiving(m->udev_monitor);
257 1 : if (r < 0) {
258 0 : log_error("Could not enable udev monitor");
259 0 : return r;
260 : }
261 :
262 1 : r = sd_event_add_io(m->event,
263 : &m->udev_event_source,
264 : udev_monitor_get_fd(m->udev_monitor),
265 : EPOLLIN, manager_dispatch_link_udev,
266 : m);
267 1 : if (r < 0)
268 0 : return r;
269 :
270 1 : r = sd_event_source_set_description(m->udev_event_source, "networkd-udev");
271 1 : if (r < 0)
272 0 : return r;
273 :
274 1 : return 0;
275 : }
276 :
277 4 : static int manager_rtnl_process_link(sd_netlink *rtnl, sd_netlink_message *message, void *userdata) {
278 4 : Manager *m = userdata;
279 4 : Link *link = NULL;
280 4 : NetDev *netdev = NULL;
281 : uint16_t type;
282 : const char *name;
283 : int r, ifindex;
284 :
285 4 : assert(rtnl);
286 4 : assert(message);
287 4 : assert(m);
288 :
289 4 : if (sd_netlink_message_is_error(message)) {
290 0 : r = sd_netlink_message_get_errno(message);
291 0 : if (r < 0)
292 0 : log_warning_errno(r, "rtnl: could not receive link: %m");
293 :
294 0 : return 0;
295 : }
296 :
297 4 : r = sd_netlink_message_get_type(message, &type);
298 4 : if (r < 0) {
299 0 : log_warning_errno(r, "rtnl: could not get message type: %m");
300 0 : return 0;
301 4 : } else if (type != RTM_NEWLINK && type != RTM_DELLINK) {
302 0 : log_warning("rtnl: received unexpected message type when processing link");
303 0 : return 0;
304 : }
305 :
306 4 : r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
307 4 : if (r < 0) {
308 0 : log_warning_errno(r, "rtnl: could not get ifindex from link: %m");
309 0 : return 0;
310 4 : } else if (ifindex <= 0) {
311 0 : log_warning("rtnl: received link message with invalid ifindex: %d", ifindex);
312 0 : return 0;
313 : } else
314 4 : link_get(m, ifindex, &link);
315 :
316 4 : r = sd_netlink_message_read_string(message, IFLA_IFNAME, &name);
317 4 : if (r < 0) {
318 0 : log_warning_errno(r, "rtnl: received link message without ifname: %m");
319 0 : return 0;
320 : } else
321 4 : netdev_get(m, name, &netdev);
322 :
323 4 : switch (type) {
324 : case RTM_NEWLINK:
325 4 : if (!link) {
326 : /* link is new, so add it */
327 4 : r = link_add(m, message, &link);
328 4 : if (r < 0) {
329 0 : log_warning_errno(r, "could not add new link: %m");
330 0 : return 0;
331 : }
332 : }
333 :
334 4 : if (netdev) {
335 : /* netdev exists, so make sure the ifindex matches */
336 0 : r = netdev_set_ifindex(netdev, message);
337 0 : if (r < 0) {
338 0 : log_warning_errno(r, "could not set ifindex on netdev: %m");
339 0 : return 0;
340 : }
341 : }
342 :
343 4 : r = link_update(link, message);
344 4 : if (r < 0)
345 0 : return 0;
346 :
347 4 : break;
348 :
349 : case RTM_DELLINK:
350 0 : link_drop(link);
351 0 : netdev_drop(netdev);
352 :
353 0 : break;
354 :
355 : default:
356 0 : assert_not_reached("Received invalid RTNL message type.");
357 : }
358 :
359 4 : return 1;
360 : }
361 :
362 1 : static int systemd_netlink_fd(void) {
363 1 : int n, fd, rtnl_fd = -EINVAL;
364 :
365 1 : n = sd_listen_fds(true);
366 1 : if (n <= 0)
367 1 : return -EINVAL;
368 :
369 0 : for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd ++) {
370 0 : if (sd_is_socket(fd, AF_NETLINK, SOCK_RAW, -1) > 0) {
371 0 : if (rtnl_fd >= 0)
372 0 : return -EINVAL;
373 :
374 0 : rtnl_fd = fd;
375 : }
376 : }
377 :
378 0 : return rtnl_fd;
379 : }
380 :
381 1 : static int manager_connect_rtnl(Manager *m) {
382 : int fd, r;
383 :
384 1 : assert(m);
385 :
386 1 : fd = systemd_netlink_fd();
387 1 : if (fd < 0)
388 1 : r = sd_netlink_open(&m->rtnl);
389 : else
390 0 : r = sd_netlink_open_fd(&m->rtnl, fd);
391 1 : if (r < 0)
392 0 : return r;
393 :
394 1 : r = sd_netlink_inc_rcvbuf(m->rtnl, RCVBUF_SIZE);
395 1 : if (r < 0)
396 0 : return r;
397 :
398 1 : r = sd_netlink_attach_event(m->rtnl, m->event, 0);
399 1 : if (r < 0)
400 0 : return r;
401 :
402 1 : r = sd_netlink_add_match(m->rtnl, RTM_NEWLINK, &manager_rtnl_process_link, m);
403 1 : if (r < 0)
404 0 : return r;
405 :
406 1 : r = sd_netlink_add_match(m->rtnl, RTM_DELLINK, &manager_rtnl_process_link, m);
407 1 : if (r < 0)
408 0 : return r;
409 :
410 1 : r = sd_netlink_add_match(m->rtnl, RTM_NEWADDR, &link_rtnl_process_address, m);
411 1 : if (r < 0)
412 0 : return r;
413 :
414 1 : r = sd_netlink_add_match(m->rtnl, RTM_DELADDR, &link_rtnl_process_address, m);
415 1 : if (r < 0)
416 0 : return r;
417 :
418 1 : return 0;
419 : }
420 :
421 1 : int manager_new(Manager **ret) {
422 2 : _cleanup_manager_free_ Manager *m = NULL;
423 : int r;
424 :
425 1 : m = new0(Manager, 1);
426 1 : if (!m)
427 0 : return -ENOMEM;
428 :
429 1 : m->state_file = strdup("/run/systemd/netif/state");
430 1 : if (!m->state_file)
431 0 : return -ENOMEM;
432 :
433 1 : r = sd_event_default(&m->event);
434 1 : if (r < 0)
435 0 : return r;
436 :
437 1 : sd_event_set_watchdog(m->event, true);
438 :
439 1 : sd_event_add_signal(m->event, NULL, SIGTERM, NULL, NULL);
440 1 : sd_event_add_signal(m->event, NULL, SIGINT, NULL, NULL);
441 :
442 1 : r = manager_connect_rtnl(m);
443 1 : if (r < 0)
444 0 : return r;
445 :
446 1 : r = manager_connect_udev(m);
447 1 : if (r < 0)
448 0 : return r;
449 :
450 1 : m->netdevs = hashmap_new(&string_hash_ops);
451 1 : if (!m->netdevs)
452 0 : return -ENOMEM;
453 :
454 1 : LIST_HEAD_INIT(m->networks);
455 :
456 1 : r = setup_default_address_pool(m);
457 1 : if (r < 0)
458 0 : return r;
459 :
460 1 : *ret = m;
461 1 : m = NULL;
462 :
463 1 : return 0;
464 : }
465 :
466 1 : void manager_free(Manager *m) {
467 : Network *network;
468 : NetDev *netdev;
469 : Link *link;
470 : AddressPool *pool;
471 :
472 1 : if (!m)
473 0 : return;
474 :
475 1 : free(m->state_file);
476 :
477 1 : udev_monitor_unref(m->udev_monitor);
478 1 : udev_unref(m->udev);
479 1 : sd_bus_unref(m->bus);
480 1 : sd_bus_slot_unref(m->prepare_for_sleep_slot);
481 1 : sd_event_source_unref(m->udev_event_source);
482 1 : sd_event_source_unref(m->bus_retry_event_source);
483 1 : sd_event_unref(m->event);
484 :
485 10 : while ((link = hashmap_first(m->links)))
486 8 : link_unref(link);
487 1 : hashmap_free(m->links);
488 :
489 5 : while ((network = m->networks))
490 3 : network_free(network);
491 :
492 1 : hashmap_free(m->networks_by_name);
493 :
494 2 : while ((netdev = hashmap_first(m->netdevs)))
495 0 : netdev_unref(netdev);
496 1 : hashmap_free(m->netdevs);
497 :
498 6 : while ((pool = m->address_pools))
499 4 : address_pool_free(pool);
500 :
501 1 : sd_netlink_unref(m->rtnl);
502 :
503 1 : free(m);
504 : }
505 :
506 0 : static bool manager_check_idle(void *userdata) {
507 0 : Manager *m = userdata;
508 : Link *link;
509 : Iterator i;
510 :
511 0 : assert(m);
512 :
513 0 : HASHMAP_FOREACH(link, m->links, i) {
514 : /* we are not woken on udev activity, so let's just wait for the
515 : * pending udev event */
516 0 : if (link->state == LINK_STATE_PENDING)
517 0 : return false;
518 :
519 0 : if (!link->network)
520 0 : continue;
521 :
522 : /* we are not woken on netork activity, so let's stay around */
523 0 : if (link_lldp_enabled(link) ||
524 0 : link_ipv4ll_enabled(link) ||
525 0 : link_dhcp4_server_enabled(link) ||
526 0 : link_dhcp4_enabled(link) ||
527 0 : link_dhcp6_enabled(link))
528 0 : return false;
529 : }
530 :
531 0 : return true;
532 : }
533 :
534 0 : int manager_run(Manager *m) {
535 0 : assert(m);
536 :
537 0 : if (m->bus)
538 0 : return bus_event_loop_with_idle(
539 : m->event,
540 : m->bus,
541 : "org.freedesktop.network1",
542 : DEFAULT_EXIT_USEC,
543 : manager_check_idle,
544 : m);
545 : else
546 : /* failed to connect to the bus, so we lose exit-on-idle logic,
547 : this should not happen except if dbus is not around at all */
548 0 : return sd_event_loop(m->event);
549 : }
550 :
551 1 : int manager_load_config(Manager *m) {
552 : int r;
553 :
554 : /* update timestamp */
555 1 : paths_check_timestamp(network_dirs, &m->network_dirs_ts_usec, true);
556 :
557 1 : r = netdev_load(m);
558 1 : if (r < 0)
559 0 : return r;
560 :
561 1 : r = network_load(m);
562 1 : if (r < 0)
563 0 : return r;
564 :
565 1 : return 0;
566 : }
567 :
568 1 : bool manager_should_reload(Manager *m) {
569 1 : return paths_check_timestamp(network_dirs, &m->network_dirs_ts_usec, false);
570 : }
571 :
572 1 : int manager_rtnl_enumerate_links(Manager *m) {
573 2 : _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL, *reply = NULL;
574 : sd_netlink_message *link;
575 : int r;
576 :
577 1 : assert(m);
578 1 : assert(m->rtnl);
579 :
580 1 : r = sd_rtnl_message_new_link(m->rtnl, &req, RTM_GETLINK, 0);
581 1 : if (r < 0)
582 0 : return r;
583 :
584 1 : r = sd_netlink_message_request_dump(req, true);
585 1 : if (r < 0)
586 0 : return r;
587 :
588 1 : r = sd_netlink_call(m->rtnl, req, 0, &reply);
589 1 : if (r < 0)
590 0 : return r;
591 :
592 5 : for (link = reply; link; link = sd_netlink_message_next(link)) {
593 : int k;
594 :
595 4 : m->enumerating = true;
596 :
597 4 : k = manager_rtnl_process_link(m->rtnl, link, m);
598 4 : if (k < 0)
599 0 : r = k;
600 :
601 4 : m->enumerating = false;
602 : }
603 :
604 1 : return r;
605 : }
606 :
607 0 : int manager_rtnl_enumerate_addresses(Manager *m) {
608 0 : _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL, *reply = NULL;
609 : sd_netlink_message *addr;
610 : int r;
611 :
612 0 : assert(m);
613 0 : assert(m->rtnl);
614 :
615 0 : r = sd_rtnl_message_new_addr(m->rtnl, &req, RTM_GETADDR, 0, 0);
616 0 : if (r < 0)
617 0 : return r;
618 :
619 0 : r = sd_netlink_message_request_dump(req, true);
620 0 : if (r < 0)
621 0 : return r;
622 :
623 0 : r = sd_netlink_call(m->rtnl, req, 0, &reply);
624 0 : if (r < 0)
625 0 : return r;
626 :
627 0 : for (addr = reply; addr; addr = sd_netlink_message_next(addr)) {
628 : int k;
629 :
630 0 : m->enumerating = true;
631 :
632 0 : k = link_rtnl_process_address(m->rtnl, addr, m);
633 0 : if (k < 0)
634 0 : r = k;
635 :
636 0 : m->enumerating = false;
637 : }
638 :
639 0 : return r;
640 : }
641 :
642 0 : static int set_put_in_addr(Set *s, const struct in_addr *address) {
643 : char *p;
644 : int r;
645 :
646 0 : assert(s);
647 :
648 0 : r = in_addr_to_string(AF_INET, (const union in_addr_union*) address, &p);
649 0 : if (r < 0)
650 0 : return r;
651 :
652 0 : r = set_consume(s, p);
653 0 : if (r == -EEXIST)
654 0 : return 0;
655 :
656 0 : return r;
657 : }
658 :
659 0 : static int set_put_in_addrv(Set *s, const struct in_addr *addresses, int n) {
660 0 : int r, i, c = 0;
661 :
662 0 : assert(s);
663 0 : assert(n <= 0 || addresses);
664 :
665 0 : for (i = 0; i < n; i++) {
666 0 : r = set_put_in_addr(s, addresses+i);
667 0 : if (r < 0)
668 0 : return r;
669 :
670 0 : c += r;
671 : }
672 :
673 0 : return c;
674 : }
675 :
676 0 : static void print_string_set(FILE *f, const char *field, Set *s) {
677 0 : bool space = false;
678 : Iterator i;
679 : char *p;
680 :
681 0 : if (set_isempty(s))
682 0 : return;
683 :
684 0 : fputs(field, f);
685 :
686 0 : SET_FOREACH(p, s, i) {
687 0 : if (space)
688 0 : fputc(' ', f);
689 0 : fputs(p, f);
690 0 : space = true;
691 : }
692 0 : fputc('\n', f);
693 : }
694 :
695 4 : int manager_save(Manager *m) {
696 8 : _cleanup_set_free_free_ Set *dns = NULL, *ntp = NULL, *domains = NULL;
697 : Link *link;
698 : Iterator i;
699 8 : _cleanup_free_ char *temp_path = NULL;
700 8 : _cleanup_fclose_ FILE *f = NULL;
701 4 : LinkOperationalState operstate = LINK_OPERSTATE_OFF;
702 : const char *operstate_str;
703 : int r;
704 :
705 4 : assert(m);
706 4 : assert(m->state_file);
707 :
708 : /* We add all NTP and DNS server to a set, to filter out duplicates */
709 4 : dns = set_new(&string_hash_ops);
710 4 : if (!dns)
711 0 : return -ENOMEM;
712 :
713 4 : ntp = set_new(&string_hash_ops);
714 4 : if (!ntp)
715 0 : return -ENOMEM;
716 :
717 4 : domains = set_new(&string_hash_ops);
718 4 : if (!domains)
719 0 : return -ENOMEM;
720 :
721 18 : HASHMAP_FOREACH(link, m->links, i) {
722 10 : if (link->flags & IFF_LOOPBACK)
723 1 : continue;
724 :
725 9 : if (link->operstate > operstate)
726 4 : operstate = link->operstate;
727 :
728 9 : if (!link->network)
729 9 : continue;
730 :
731 : /* First add the static configured entries */
732 0 : r = set_put_strdupv(dns, link->network->dns);
733 0 : if (r < 0)
734 0 : return r;
735 :
736 0 : r = set_put_strdupv(ntp, link->network->ntp);
737 0 : if (r < 0)
738 0 : return r;
739 :
740 0 : r = set_put_strdupv(domains, link->network->domains);
741 0 : if (r < 0)
742 0 : return r;
743 :
744 0 : if (!link->dhcp_lease)
745 0 : continue;
746 :
747 : /* Secondly, add the entries acquired via DHCP */
748 0 : if (link->network->dhcp_dns) {
749 : const struct in_addr *addresses;
750 :
751 0 : r = sd_dhcp_lease_get_dns(link->dhcp_lease, &addresses);
752 0 : if (r > 0) {
753 0 : r = set_put_in_addrv(dns, addresses, r);
754 0 : if (r < 0)
755 0 : return r;
756 0 : } else if (r < 0 && r != -ENOENT)
757 0 : return r;
758 : }
759 :
760 0 : if (link->network->dhcp_ntp) {
761 : const struct in_addr *addresses;
762 :
763 0 : r = sd_dhcp_lease_get_ntp(link->dhcp_lease, &addresses);
764 0 : if (r > 0) {
765 0 : r = set_put_in_addrv(ntp, addresses, r);
766 0 : if (r < 0)
767 0 : return r;
768 0 : } else if (r < 0 && r != -ENOENT)
769 0 : return r;
770 : }
771 :
772 0 : if (link->network->dhcp_domains) {
773 : const char *domainname;
774 :
775 0 : r = sd_dhcp_lease_get_domainname(link->dhcp_lease, &domainname);
776 0 : if (r >= 0) {
777 0 : r = set_put_strdup(domains, domainname);
778 0 : if (r < 0)
779 0 : return r;
780 0 : } else if (r != -ENOENT)
781 0 : return r;
782 : }
783 : }
784 :
785 4 : operstate_str = link_operstate_to_string(operstate);
786 4 : assert(operstate_str);
787 :
788 4 : r = fopen_temporary(m->state_file, &f, &temp_path);
789 4 : if (r < 0)
790 4 : return r;
791 :
792 0 : fchmod(fileno(f), 0644);
793 :
794 0 : fprintf(f,
795 : "# This is private data. Do not parse.\n"
796 : "OPER_STATE=%s\n", operstate_str);
797 :
798 0 : print_string_set(f, "DNS=", dns);
799 0 : print_string_set(f, "NTP=", ntp);
800 0 : print_string_set(f, "DOMAINS=", domains);
801 :
802 0 : r = fflush_and_check(f);
803 0 : if (r < 0)
804 0 : goto fail;
805 :
806 0 : if (rename(temp_path, m->state_file) < 0) {
807 0 : r = -errno;
808 0 : goto fail;
809 : }
810 :
811 0 : if (m->operational_state != operstate) {
812 0 : m->operational_state = operstate;
813 0 : r = manager_send_changed(m, "OperationalState", NULL);
814 0 : if (r < 0)
815 0 : log_error_errno(r, "Could not emit changed OperationalState: %m");
816 : }
817 :
818 0 : return 0;
819 :
820 : fail:
821 0 : log_error_errno(r, "Failed to save network state to %s: %m", m->state_file);
822 0 : unlink(m->state_file);
823 0 : unlink(temp_path);
824 0 : return r;
825 : }
826 :
827 0 : int manager_address_pool_acquire(Manager *m, int family, unsigned prefixlen, union in_addr_union *found) {
828 : AddressPool *p;
829 : int r;
830 :
831 0 : assert(m);
832 0 : assert(prefixlen > 0);
833 0 : assert(found);
834 :
835 0 : LIST_FOREACH(address_pools, p, m->address_pools) {
836 0 : if (p->family != family)
837 0 : continue;
838 :
839 0 : r = address_pool_acquire(p, prefixlen, found);
840 0 : if (r != 0)
841 0 : return r;
842 : }
843 :
844 0 : return 0;
845 : }
846 :
847 6 : const char *address_family_boolean_to_string(AddressFamilyBoolean b) {
848 6 : if (b == ADDRESS_FAMILY_YES ||
849 : b == ADDRESS_FAMILY_NO)
850 2 : return yes_no(b == ADDRESS_FAMILY_YES);
851 :
852 4 : if (b == ADDRESS_FAMILY_IPV4)
853 1 : return "ipv4";
854 3 : if (b == ADDRESS_FAMILY_IPV6)
855 1 : return "ipv6";
856 :
857 2 : return NULL;
858 : }
859 :
860 10 : AddressFamilyBoolean address_family_boolean_from_string(const char *s) {
861 : int r;
862 :
863 : /* Make this a true superset of a boolean */
864 :
865 10 : r = parse_boolean(s);
866 10 : if (r > 0)
867 5 : return ADDRESS_FAMILY_YES;
868 5 : if (r == 0)
869 1 : return ADDRESS_FAMILY_NO;
870 :
871 4 : if (streq(s, "ipv4"))
872 1 : return ADDRESS_FAMILY_IPV4;
873 3 : if (streq(s, "ipv6"))
874 1 : return ADDRESS_FAMILY_IPV6;
875 :
876 2 : return _ADDRESS_FAMILY_BOOLEAN_INVALID;
877 : }
878 :
879 2 : DEFINE_CONFIG_PARSE_ENUM(config_parse_address_family_boolean, address_family_boolean, AddressFamilyBoolean, "Failed to parse option");
|