2017-11-18 17:09:20 +01:00
|
|
|
/* SPDX-License-Identifier: LGPL-2.1+ */
|
2013-10-17 03:18:36 +02:00
|
|
|
/***
|
|
|
|
This file is part of systemd.
|
|
|
|
|
|
|
|
Copyright 2013 Tom Gundersen <teg@jklm.no>
|
|
|
|
***/
|
|
|
|
|
2014-05-18 22:10:48 +02:00
|
|
|
#include <sys/socket.h>
|
2014-05-08 17:21:37 +02:00
|
|
|
#include <linux/if.h>
|
2017-09-14 21:51:39 +02:00
|
|
|
#include <linux/fib_rules.h>
|
2017-12-11 19:50:30 +01:00
|
|
|
#include <stdio_ext.h>
|
2014-01-05 23:01:10 +01:00
|
|
|
|
2015-08-27 13:59:06 +02:00
|
|
|
#include "sd-daemon.h"
|
2015-10-24 22:58:24 +02:00
|
|
|
#include "sd-netlink.h"
|
2015-08-27 13:59:06 +02:00
|
|
|
|
2015-10-27 03:01:06 +01:00
|
|
|
#include "alloc-util.h"
|
2015-02-04 15:00:20 +01:00
|
|
|
#include "bus-util.h"
|
2015-10-24 22:58:24 +02:00
|
|
|
#include "conf-parser.h"
|
2015-02-04 15:00:20 +01:00
|
|
|
#include "def.h"
|
2016-01-25 20:33:47 +01:00
|
|
|
#include "dns-domain.h"
|
2015-10-25 13:14:12 +01:00
|
|
|
#include "fd-util.h"
|
2015-10-26 18:05:03 +01:00
|
|
|
#include "fileio.h"
|
2015-10-24 22:58:24 +02:00
|
|
|
#include "libudev-private.h"
|
2015-08-27 16:45:24 +02:00
|
|
|
#include "local-addresses.h"
|
2015-10-24 22:58:24 +02:00
|
|
|
#include "netlink-util.h"
|
2016-11-13 04:59:06 +01:00
|
|
|
#include "networkd-manager.h"
|
2016-01-25 20:31:11 +01:00
|
|
|
#include "ordered-set.h"
|
2015-10-24 22:58:24 +02:00
|
|
|
#include "path-util.h"
|
|
|
|
#include "set.h"
|
|
|
|
#include "udev-util.h"
|
|
|
|
#include "virt.h"
|
2014-04-15 14:21:44 +02:00
|
|
|
|
2014-11-27 18:50:48 +01:00
|
|
|
/* use 8 MB for receive socket kernel queue. */
|
|
|
|
#define RCVBUF_SIZE (8*1024*1024)
|
|
|
|
|
2014-01-08 23:41:41 +01:00
|
|
|
const char* const network_dirs[] = {
|
|
|
|
"/etc/systemd/network",
|
|
|
|
"/run/systemd/network",
|
|
|
|
"/usr/lib/systemd/network",
|
2017-10-03 10:41:51 +02:00
|
|
|
#if HAVE_SPLIT_USR
|
2014-01-08 23:41:41 +01:00
|
|
|
"/lib/systemd/network",
|
|
|
|
#endif
|
|
|
|
NULL};
|
|
|
|
|
2014-06-18 18:22:14 +02:00
|
|
|
static int setup_default_address_pool(Manager *m) {
|
|
|
|
AddressPool *p;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
|
|
|
|
/* Add in the well-known private address ranges. */
|
|
|
|
|
|
|
|
r = address_pool_new_from_string(m, &p, AF_INET6, "fc00::", 7);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = address_pool_new_from_string(m, &p, AF_INET, "192.168.0.0", 16);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = address_pool_new_from_string(m, &p, AF_INET, "172.16.0.0", 12);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = address_pool_new_from_string(m, &p, AF_INET, "10.0.0.0", 8);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-02-03 15:44:12 +01:00
|
|
|
static int manager_reset_all(Manager *m) {
|
|
|
|
Link *link;
|
|
|
|
Iterator i;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
|
|
|
|
HASHMAP_FOREACH(link, m->links, i) {
|
|
|
|
r = link_carrier_reset(link);
|
|
|
|
if (r < 0)
|
2015-08-26 20:43:28 +02:00
|
|
|
log_link_warning_errno(link, r, "Could not reset carrier: %m");
|
2015-02-03 15:44:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-04-29 18:35:10 +02:00
|
|
|
static int match_prepare_for_sleep(sd_bus_message *message, void *userdata, sd_bus_error *ret_error) {
|
2015-02-03 15:44:12 +01:00
|
|
|
Manager *m = userdata;
|
|
|
|
int b, r;
|
|
|
|
|
2015-04-29 18:35:10 +02:00
|
|
|
assert(message);
|
2017-12-19 15:54:30 +01:00
|
|
|
assert(m);
|
2015-02-03 15:44:12 +01:00
|
|
|
|
|
|
|
r = sd_bus_message_read(message, "b", &b);
|
|
|
|
if (r < 0) {
|
|
|
|
log_debug_errno(r, "Failed to parse PrepareForSleep signal: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (b)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
log_debug("Coming back from suspend, resetting all connections...");
|
|
|
|
|
2017-12-21 19:07:23 +01:00
|
|
|
(void) manager_reset_all(m);
|
2015-02-03 15:44:12 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-12-19 15:54:30 +01:00
|
|
|
static int on_connected(sd_bus_message *message, void *userdata, sd_bus_error *ret_error) {
|
|
|
|
Manager *m = userdata;
|
2015-02-03 15:44:12 +01:00
|
|
|
|
2017-12-19 15:54:30 +01:00
|
|
|
assert(message);
|
2015-02-03 15:44:12 +01:00
|
|
|
assert(m);
|
|
|
|
|
2017-12-19 15:54:30 +01:00
|
|
|
/* Did we get a timezone or transient hostname from DHCP while D-Bus wasn't up yet? */
|
|
|
|
if (m->dynamic_hostname)
|
|
|
|
(void) manager_set_hostname(m, m->dynamic_hostname);
|
|
|
|
if (m->dynamic_timezone)
|
|
|
|
(void) manager_set_timezone(m, m->dynamic_timezone);
|
2015-02-03 15:44:12 +01:00
|
|
|
|
2017-12-19 15:54:30 +01:00
|
|
|
return 0;
|
|
|
|
}
|
2015-02-03 15:44:12 +01:00
|
|
|
|
2017-12-19 15:54:30 +01:00
|
|
|
int manager_connect_bus(Manager *m) {
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(m);
|
2015-02-03 15:44:12 +01:00
|
|
|
|
2017-12-19 15:54:30 +01:00
|
|
|
if (m->bus)
|
2015-02-03 15:44:12 +01:00
|
|
|
return 0;
|
2015-08-06 00:31:09 +02:00
|
|
|
|
2018-04-17 16:55:27 +02:00
|
|
|
r = bus_open_system_watch_bind_with_description(&m->bus, "bus-api-network");
|
2015-02-03 15:44:12 +01:00
|
|
|
if (r < 0)
|
2017-12-19 15:54:30 +01:00
|
|
|
return log_error_errno(r, "Failed to connect to bus: %m");
|
2015-02-03 15:44:12 +01:00
|
|
|
|
2015-02-04 11:44:37 +01:00
|
|
|
r = sd_bus_add_object_vtable(m->bus, NULL, "/org/freedesktop/network1", "org.freedesktop.network1.Manager", manager_vtable, m);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to add manager object vtable: %m");
|
|
|
|
|
|
|
|
r = sd_bus_add_fallback_vtable(m->bus, NULL, "/org/freedesktop/network1/link", "org.freedesktop.network1.Link", link_vtable, link_object_find, m);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to add link object vtable: %m");
|
|
|
|
|
|
|
|
r = sd_bus_add_node_enumerator(m->bus, NULL, "/org/freedesktop/network1/link", link_node_enumerator, m);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to add link enumerator: %m");
|
2015-02-08 13:27:56 +01:00
|
|
|
|
|
|
|
r = sd_bus_add_fallback_vtable(m->bus, NULL, "/org/freedesktop/network1/network", "org.freedesktop.network1.Network", network_vtable, network_object_find, m);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to add network object vtable: %m");
|
|
|
|
|
|
|
|
r = sd_bus_add_node_enumerator(m->bus, NULL, "/org/freedesktop/network1/network", network_node_enumerator, m);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to add network enumerator: %m");
|
2015-02-04 11:44:37 +01:00
|
|
|
|
2018-05-22 15:37:34 +02:00
|
|
|
r = bus_request_name_async_may_reload_dbus(m->bus, NULL, "org.freedesktop.network1", 0, NULL);
|
2015-02-04 11:44:37 +01:00
|
|
|
if (r < 0)
|
2017-12-18 22:10:11 +01:00
|
|
|
return log_error_errno(r, "Failed to request name: %m");
|
2015-02-04 11:44:37 +01:00
|
|
|
|
|
|
|
r = sd_bus_attach_event(m->bus, m->event, 0);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to attach bus to event loop: %m");
|
|
|
|
|
2017-12-19 15:54:30 +01:00
|
|
|
r = sd_bus_match_signal_async(
|
|
|
|
m->bus,
|
|
|
|
&m->connected_slot,
|
|
|
|
"org.freedesktop.DBus.Local",
|
|
|
|
NULL,
|
|
|
|
"org.freedesktop.DBus.Local",
|
|
|
|
"Connected",
|
|
|
|
on_connected, NULL, m);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to request match on Connected signal: %m");
|
|
|
|
|
|
|
|
r = sd_bus_match_signal_async(
|
|
|
|
m->bus,
|
|
|
|
&m->prepare_for_sleep_slot,
|
|
|
|
"org.freedesktop.login1",
|
|
|
|
"/org/freedesktop/login1",
|
|
|
|
"org.freedesktop.login1.Manager",
|
|
|
|
"PrepareForSleep",
|
|
|
|
match_prepare_for_sleep, NULL, m);
|
|
|
|
if (r < 0)
|
|
|
|
log_warning_errno(r, "Failed to request match for PrepareForSleep, ignoring: %m");
|
2016-11-22 08:36:20 +01:00
|
|
|
|
2015-02-03 15:44:12 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-02-03 15:44:50 +01:00
|
|
|
static int manager_udev_process_link(Manager *m, struct udev_device *device) {
|
|
|
|
Link *link = NULL;
|
|
|
|
int r, ifindex;
|
2015-02-01 22:13:26 +01:00
|
|
|
|
2015-02-03 15:44:50 +01:00
|
|
|
assert(m);
|
|
|
|
assert(device);
|
2015-02-01 22:13:26 +01:00
|
|
|
|
2015-02-03 15:44:50 +01:00
|
|
|
if (!streq_ptr(udev_device_get_action(device), "add"))
|
|
|
|
return 0;
|
2015-02-01 22:13:26 +01:00
|
|
|
|
2015-02-03 15:44:50 +01:00
|
|
|
ifindex = udev_device_get_ifindex(device);
|
|
|
|
if (ifindex <= 0) {
|
2015-08-26 20:43:28 +02:00
|
|
|
log_debug("Ignoring udev ADD event for device with invalid ifindex");
|
2015-02-03 15:44:50 +01:00
|
|
|
return 0;
|
2015-02-01 22:13:26 +01:00
|
|
|
}
|
|
|
|
|
2015-02-03 15:44:50 +01:00
|
|
|
r = link_get(m, ifindex, &link);
|
|
|
|
if (r == -ENODEV)
|
|
|
|
return 0;
|
|
|
|
else if (r < 0)
|
2013-10-17 03:18:36 +02:00
|
|
|
return r;
|
|
|
|
|
2015-02-03 15:44:50 +01:00
|
|
|
r = link_initialized(link, device);
|
2015-02-02 23:21:20 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2015-02-03 15:44:50 +01:00
|
|
|
return 0;
|
|
|
|
}
|
2014-11-27 18:50:48 +01:00
|
|
|
|
2015-02-03 15:44:50 +01:00
|
|
|
static int manager_dispatch_link_udev(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
|
|
|
|
Manager *m = userdata;
|
|
|
|
struct udev_monitor *monitor = m->udev_monitor;
|
tree-wide: drop redundant _cleanup_ macros (#8810)
This drops a good number of type-specific _cleanup_ macros, and patches
all users to just use the generic ones.
In most recent code we abstained from defining type-specific macros, and
this basically removes all those added already, with the exception of
the really low-level ones.
Having explicit macros for this is not too useful, as the expression
without the extra macro is generally just 2ch wider. We should generally
emphesize generic code, unless there are really good reasons for
specific code, hence let's follow this in this case too.
Note that _cleanup_free_ and similar really low-level, libc'ish, Linux
API'ish macros continue to be defined, only the really high-level OO
ones are dropped. From now on this should really be the rule: for really
low-level stuff, such as memory allocation, fd handling and so one, go
ahead and define explicit per-type macros, but for high-level, specific
program code, just use the generic _cleanup_() macro directly, in order
to keep things simple and as readable as possible for the uninitiated.
Note that before this patch some of the APIs (notable libudev ones) were
already used with the high-level macros at some places and with the
generic _cleanup_ macro at others. With this patch we hence unify on the
latter.
2018-04-25 12:31:45 +02:00
|
|
|
_cleanup_(udev_device_unrefp) struct udev_device *device = NULL;
|
2013-10-17 03:18:36 +02:00
|
|
|
|
2015-02-03 15:44:50 +01:00
|
|
|
device = udev_monitor_receive_device(monitor);
|
|
|
|
if (!device)
|
2013-11-24 23:37:56 +01:00
|
|
|
return -ENOMEM;
|
|
|
|
|
2017-12-21 19:07:23 +01:00
|
|
|
(void) manager_udev_process_link(m, device);
|
|
|
|
|
2013-10-17 03:18:36 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-02-03 15:44:50 +01:00
|
|
|
static int manager_connect_udev(Manager *m) {
|
|
|
|
int r;
|
2013-10-17 03:18:36 +02:00
|
|
|
|
2015-02-03 15:44:50 +01:00
|
|
|
/* udev does not initialize devices inside containers,
|
|
|
|
* so we rely on them being already initialized before
|
|
|
|
* entering the container */
|
2015-09-07 13:42:47 +02:00
|
|
|
if (detect_container() > 0)
|
2015-02-03 15:44:50 +01:00
|
|
|
return 0;
|
2013-10-17 03:18:36 +02:00
|
|
|
|
2015-02-03 15:44:50 +01:00
|
|
|
m->udev = udev_new();
|
|
|
|
if (!m->udev)
|
|
|
|
return -ENOMEM;
|
2013-11-24 23:37:56 +01:00
|
|
|
|
2015-02-03 15:44:50 +01:00
|
|
|
m->udev_monitor = udev_monitor_new_from_netlink(m->udev, "udev");
|
|
|
|
if (!m->udev_monitor)
|
|
|
|
return -ENOMEM;
|
2013-11-24 23:37:56 +01:00
|
|
|
|
2015-02-03 15:44:50 +01:00
|
|
|
r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_monitor, "net", NULL);
|
2013-11-24 23:37:56 +01:00
|
|
|
if (r < 0)
|
2015-02-03 15:44:50 +01:00
|
|
|
return log_error_errno(r, "Could not add udev monitor filter: %m");
|
2013-11-24 23:37:56 +01:00
|
|
|
|
2015-02-03 15:44:50 +01:00
|
|
|
r = udev_monitor_enable_receiving(m->udev_monitor);
|
|
|
|
if (r < 0) {
|
|
|
|
log_error("Could not enable udev monitor");
|
2013-11-24 23:37:56 +01:00
|
|
|
return r;
|
2014-04-19 20:49:06 +02:00
|
|
|
}
|
2014-04-15 14:21:44 +02:00
|
|
|
|
2015-02-03 15:44:50 +01:00
|
|
|
r = sd_event_add_io(m->event,
|
|
|
|
&m->udev_event_source,
|
|
|
|
udev_monitor_get_fd(m->udev_monitor),
|
|
|
|
EPOLLIN, manager_dispatch_link_udev,
|
|
|
|
m);
|
|
|
|
if (r < 0)
|
2014-04-19 20:49:06 +02:00
|
|
|
return r;
|
2014-04-15 14:21:44 +02:00
|
|
|
|
2015-02-03 15:44:50 +01:00
|
|
|
r = sd_event_source_set_description(m->udev_event_source, "networkd-udev");
|
2014-04-15 14:21:44 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2014-02-18 21:42:05 +01:00
|
|
|
|
2014-04-15 14:21:44 +02:00
|
|
|
return 0;
|
|
|
|
}
|
2013-10-17 03:18:36 +02:00
|
|
|
|
2015-10-25 14:46:21 +01:00
|
|
|
int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, void *userdata) {
|
|
|
|
Manager *m = userdata;
|
|
|
|
Link *link = NULL;
|
|
|
|
uint16_t type;
|
|
|
|
uint32_t ifindex, priority = 0;
|
2017-09-19 16:28:26 +02:00
|
|
|
unsigned char protocol, scope, tos, table, rt_type;
|
2015-10-25 14:46:21 +01:00
|
|
|
int family;
|
|
|
|
unsigned char dst_prefixlen, src_prefixlen;
|
|
|
|
union in_addr_union dst = {}, gw = {}, src = {}, prefsrc = {};
|
|
|
|
Route *route = NULL;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(rtnl);
|
|
|
|
assert(message);
|
|
|
|
assert(m);
|
|
|
|
|
|
|
|
if (sd_netlink_message_is_error(message)) {
|
|
|
|
r = sd_netlink_message_get_errno(message);
|
|
|
|
if (r < 0)
|
2017-12-21 19:07:23 +01:00
|
|
|
log_warning_errno(r, "rtnl: failed to receive route, ignoring: %m");
|
2015-10-25 14:46:21 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_netlink_message_get_type(message, &type);
|
|
|
|
if (r < 0) {
|
2017-12-21 19:07:23 +01:00
|
|
|
log_warning_errno(r, "rtnl: could not get message type, ignoring: %m");
|
2015-10-25 14:46:21 +01:00
|
|
|
return 0;
|
2017-09-28 08:37:38 +02:00
|
|
|
} else if (!IN_SET(type, RTM_NEWROUTE, RTM_DELROUTE)) {
|
2017-12-21 19:07:23 +01:00
|
|
|
log_warning("rtnl: received unexpected message type when processing route, ignoring");
|
2015-10-25 14:46:21 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_netlink_message_read_u32(message, RTA_OIF, &ifindex);
|
|
|
|
if (r == -ENODATA) {
|
|
|
|
log_debug("rtnl: received route without ifindex, ignoring");
|
|
|
|
return 0;
|
|
|
|
} else if (r < 0) {
|
|
|
|
log_warning_errno(r, "rtnl: could not get ifindex from route, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
} else if (ifindex <= 0) {
|
|
|
|
log_warning("rtnl: received route message with invalid ifindex, ignoring: %d", ifindex);
|
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
r = link_get(m, ifindex, &link);
|
|
|
|
if (r < 0 || !link) {
|
|
|
|
/* when enumerating we might be out of sync, but we will
|
|
|
|
* get the route again, so just ignore it */
|
|
|
|
if (!m->enumerating)
|
|
|
|
log_warning("rtnl: received route for nonexistent link (%d), ignoring", ifindex);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_rtnl_message_route_get_family(message, &family);
|
|
|
|
if (r < 0 || !IN_SET(family, AF_INET, AF_INET6)) {
|
2017-12-21 19:07:23 +01:00
|
|
|
log_link_warning(link, "rtnl: received address with invalid family, ignoring");
|
2015-10-25 14:46:21 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_rtnl_message_route_get_protocol(message, &protocol);
|
|
|
|
if (r < 0) {
|
|
|
|
log_warning_errno(r, "rtnl: could not get route protocol: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (family) {
|
|
|
|
case AF_INET:
|
|
|
|
r = sd_netlink_message_read_in_addr(message, RTA_DST, &dst.in);
|
|
|
|
if (r < 0 && r != -ENODATA) {
|
|
|
|
log_link_warning_errno(link, r, "rtnl: received route without valid destination, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_netlink_message_read_in_addr(message, RTA_GATEWAY, &gw.in);
|
|
|
|
if (r < 0 && r != -ENODATA) {
|
|
|
|
log_link_warning_errno(link, r, "rtnl: received route with invalid gateway, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_netlink_message_read_in_addr(message, RTA_SRC, &src.in);
|
|
|
|
if (r < 0 && r != -ENODATA) {
|
|
|
|
log_link_warning_errno(link, r, "rtnl: received route with invalid source, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_netlink_message_read_in_addr(message, RTA_PREFSRC, &prefsrc.in);
|
|
|
|
if (r < 0 && r != -ENODATA) {
|
|
|
|
log_link_warning_errno(link, r, "rtnl: received route with invalid preferred source, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case AF_INET6:
|
|
|
|
r = sd_netlink_message_read_in6_addr(message, RTA_DST, &dst.in6);
|
|
|
|
if (r < 0 && r != -ENODATA) {
|
|
|
|
log_link_warning_errno(link, r, "rtnl: received route without valid destination, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_netlink_message_read_in6_addr(message, RTA_GATEWAY, &gw.in6);
|
|
|
|
if (r < 0 && r != -ENODATA) {
|
|
|
|
log_link_warning_errno(link, r, "rtnl: received route with invalid gateway, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_netlink_message_read_in6_addr(message, RTA_SRC, &src.in6);
|
|
|
|
if (r < 0 && r != -ENODATA) {
|
|
|
|
log_link_warning_errno(link, r, "rtnl: received route with invalid source, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_netlink_message_read_in6_addr(message, RTA_PREFSRC, &prefsrc.in6);
|
|
|
|
if (r < 0 && r != -ENODATA) {
|
|
|
|
log_link_warning_errno(link, r, "rtnl: received route with invalid preferred source, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2017-09-28 08:38:50 +02:00
|
|
|
assert_not_reached("Received unsupported address family");
|
2015-10-25 14:46:21 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_rtnl_message_route_get_dst_prefixlen(message, &dst_prefixlen);
|
|
|
|
if (r < 0) {
|
|
|
|
log_link_warning_errno(link, r, "rtnl: received route with invalid destination prefixlen, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_rtnl_message_route_get_src_prefixlen(message, &src_prefixlen);
|
|
|
|
if (r < 0) {
|
|
|
|
log_link_warning_errno(link, r, "rtnl: received route with invalid source prefixlen, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_rtnl_message_route_get_scope(message, &scope);
|
|
|
|
if (r < 0) {
|
|
|
|
log_link_warning_errno(link, r, "rtnl: received route with invalid scope, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_rtnl_message_route_get_tos(message, &tos);
|
|
|
|
if (r < 0) {
|
|
|
|
log_link_warning_errno(link, r, "rtnl: received route with invalid tos, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-09-19 16:28:26 +02:00
|
|
|
r = sd_rtnl_message_route_get_type(message, &rt_type);
|
|
|
|
if (r < 0) {
|
|
|
|
log_link_warning_errno(link, r, "rtnl: received route with invalid type, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-10-25 14:46:21 +01:00
|
|
|
r = sd_rtnl_message_route_get_table(message, &table);
|
|
|
|
if (r < 0) {
|
|
|
|
log_link_warning_errno(link, r, "rtnl: received route with invalid table, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_netlink_message_read_u32(message, RTA_PRIORITY, &priority);
|
|
|
|
if (r < 0 && r != -ENODATA) {
|
|
|
|
log_link_warning_errno(link, r, "rtnl: received route with invalid priority, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-12-21 19:07:23 +01:00
|
|
|
(void) route_get(link, family, &dst, dst_prefixlen, tos, priority, table, &route);
|
2015-10-25 14:46:21 +01:00
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
case RTM_NEWROUTE:
|
|
|
|
if (!route) {
|
|
|
|
/* A route appeared that we did not request */
|
|
|
|
r = route_add_foreign(link, family, &dst, dst_prefixlen, tos, priority, table, &route);
|
2017-12-21 19:07:23 +01:00
|
|
|
if (r < 0) {
|
|
|
|
log_link_warning_errno(link, r, "Failed to add route, ignoring: %m");
|
2015-10-25 14:46:21 +01:00
|
|
|
return 0;
|
2017-12-21 19:07:23 +01:00
|
|
|
}
|
2015-10-25 14:46:21 +01:00
|
|
|
}
|
|
|
|
|
2017-11-27 13:08:37 +01:00
|
|
|
route_update(route, &src, src_prefixlen, &gw, &prefsrc, scope, protocol, rt_type);
|
2015-10-25 14:46:21 +01:00
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case RTM_DELROUTE:
|
2016-05-14 22:46:01 +02:00
|
|
|
route_free(route);
|
2015-10-25 14:46:21 +01:00
|
|
|
break;
|
2016-05-14 22:46:01 +02:00
|
|
|
|
2015-10-25 14:46:21 +01:00
|
|
|
default:
|
|
|
|
assert_not_reached("Received invalid RTNL message type");
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2015-09-22 17:18:20 +02:00
|
|
|
int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message, void *userdata) {
|
|
|
|
Manager *m = userdata;
|
|
|
|
Link *link = NULL;
|
|
|
|
uint16_t type;
|
|
|
|
unsigned char flags;
|
2015-09-24 01:22:05 +02:00
|
|
|
int family;
|
|
|
|
unsigned char prefixlen;
|
|
|
|
unsigned char scope;
|
|
|
|
union in_addr_union in_addr;
|
|
|
|
struct ifa_cacheinfo cinfo;
|
|
|
|
Address *address = NULL;
|
2015-09-22 17:18:20 +02:00
|
|
|
char buf[INET6_ADDRSTRLEN], valid_buf[FORMAT_TIMESPAN_MAX];
|
|
|
|
const char *valid_str = NULL;
|
|
|
|
int r, ifindex;
|
|
|
|
|
|
|
|
assert(rtnl);
|
|
|
|
assert(message);
|
|
|
|
assert(m);
|
|
|
|
|
|
|
|
if (sd_netlink_message_is_error(message)) {
|
|
|
|
r = sd_netlink_message_get_errno(message);
|
|
|
|
if (r < 0)
|
2017-12-21 19:07:23 +01:00
|
|
|
log_warning_errno(r, "rtnl: failed to receive address, ignoring: %m");
|
2015-09-22 17:18:20 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_netlink_message_get_type(message, &type);
|
|
|
|
if (r < 0) {
|
2017-12-21 19:07:23 +01:00
|
|
|
log_warning_errno(r, "rtnl: could not get message type, ignoring: %m");
|
2015-09-22 17:18:20 +02:00
|
|
|
return 0;
|
2017-09-28 08:37:38 +02:00
|
|
|
} else if (!IN_SET(type, RTM_NEWADDR, RTM_DELADDR)) {
|
2017-12-21 19:07:23 +01:00
|
|
|
log_warning("rtnl: received unexpected message type when processing address, ignoring");
|
2015-09-22 17:18:20 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_rtnl_message_addr_get_ifindex(message, &ifindex);
|
|
|
|
if (r < 0) {
|
2017-12-21 19:07:23 +01:00
|
|
|
log_warning_errno(r, "rtnl: could not get ifindex from address, ignoring: %m");
|
2015-09-22 17:18:20 +02:00
|
|
|
return 0;
|
|
|
|
} else if (ifindex <= 0) {
|
2017-12-21 19:07:23 +01:00
|
|
|
log_warning("rtnl: received address message with invalid ifindex, ignoring: %d", ifindex);
|
2015-09-22 17:18:20 +02:00
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
r = link_get(m, ifindex, &link);
|
|
|
|
if (r < 0 || !link) {
|
|
|
|
/* when enumerating we might be out of sync, but we will
|
|
|
|
* get the address again, so just ignore it */
|
|
|
|
if (!m->enumerating)
|
|
|
|
log_warning("rtnl: received address for nonexistent link (%d), ignoring", ifindex);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-24 01:22:05 +02:00
|
|
|
r = sd_rtnl_message_addr_get_family(message, &family);
|
|
|
|
if (r < 0 || !IN_SET(family, AF_INET, AF_INET6)) {
|
2017-12-21 19:07:23 +01:00
|
|
|
log_link_warning(link, "rtnl: received address with invalid family, ignoring");
|
2015-09-22 17:18:20 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-09-24 01:22:05 +02:00
|
|
|
r = sd_rtnl_message_addr_get_prefixlen(message, &prefixlen);
|
2015-09-22 17:18:20 +02:00
|
|
|
if (r < 0) {
|
|
|
|
log_link_warning_errno(link, r, "rtnl: received address with invalid prefixlen, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-09-24 01:22:05 +02:00
|
|
|
r = sd_rtnl_message_addr_get_scope(message, &scope);
|
2015-09-22 17:18:20 +02:00
|
|
|
if (r < 0) {
|
|
|
|
log_link_warning_errno(link, r, "rtnl: received address with invalid scope, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_rtnl_message_addr_get_flags(message, &flags);
|
|
|
|
if (r < 0) {
|
|
|
|
log_link_warning_errno(link, r, "rtnl: received address with invalid flags, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-09-24 01:22:05 +02:00
|
|
|
switch (family) {
|
2015-09-22 17:18:20 +02:00
|
|
|
case AF_INET:
|
2015-09-24 01:22:05 +02:00
|
|
|
r = sd_netlink_message_read_in_addr(message, IFA_LOCAL, &in_addr.in);
|
2015-09-22 17:18:20 +02:00
|
|
|
if (r < 0) {
|
|
|
|
log_link_warning_errno(link, r, "rtnl: received address without valid address, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case AF_INET6:
|
2015-09-24 01:22:05 +02:00
|
|
|
r = sd_netlink_message_read_in6_addr(message, IFA_ADDRESS, &in_addr.in6);
|
2015-09-22 17:18:20 +02:00
|
|
|
if (r < 0) {
|
|
|
|
log_link_warning_errno(link, r, "rtnl: received address without valid address, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2017-12-21 19:07:23 +01:00
|
|
|
assert_not_reached("Received unsupported address family");
|
2015-09-22 17:18:20 +02:00
|
|
|
}
|
|
|
|
|
2015-09-24 01:22:05 +02:00
|
|
|
if (!inet_ntop(family, &in_addr, buf, INET6_ADDRSTRLEN)) {
|
2017-12-21 19:07:23 +01:00
|
|
|
log_link_warning(link, "Could not print address, ignoring");
|
2015-09-22 17:18:20 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-09-24 01:22:05 +02:00
|
|
|
r = sd_netlink_message_read_cache_info(message, IFA_CACHEINFO, &cinfo);
|
2017-12-21 19:07:23 +01:00
|
|
|
if (r < 0 && r != -ENODATA) {
|
|
|
|
log_link_warning_errno(link, r, "rtnl: cannot get IFA_CACHEINFO attribute, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
} else if (r >= 0) {
|
2015-11-10 21:45:41 +01:00
|
|
|
if (cinfo.ifa_valid != CACHE_INFO_INFINITY_LIFE_TIME)
|
2015-09-22 17:18:20 +02:00
|
|
|
valid_str = format_timespan(valid_buf, FORMAT_TIMESPAN_MAX,
|
2015-09-24 01:22:05 +02:00
|
|
|
cinfo.ifa_valid * USEC_PER_SEC,
|
2015-09-22 17:18:20 +02:00
|
|
|
USEC_PER_SEC);
|
|
|
|
}
|
|
|
|
|
2017-12-21 19:07:23 +01:00
|
|
|
(void) address_get(link, family, &in_addr, prefixlen, &address);
|
2015-09-22 17:18:20 +02:00
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
case RTM_NEWADDR:
|
2015-09-28 17:16:12 +02:00
|
|
|
if (address)
|
2015-11-10 21:45:41 +01:00
|
|
|
log_link_debug(link, "Updating address: %s/%u (valid %s%s)", buf, prefixlen,
|
2017-11-24 10:31:08 +01:00
|
|
|
valid_str ? "for " : "forever", strempty(valid_str));
|
2015-09-28 17:16:12 +02:00
|
|
|
else {
|
2015-09-30 14:01:44 +02:00
|
|
|
/* An address appeared that we did not request */
|
|
|
|
r = address_add_foreign(link, family, &in_addr, prefixlen, &address);
|
2015-09-23 01:53:29 +02:00
|
|
|
if (r < 0) {
|
2017-12-21 19:07:23 +01:00
|
|
|
log_link_warning_errno(link, r, "Failed to add address %s/%u, ignoring: %m", buf, prefixlen);
|
2015-09-23 01:53:29 +02:00
|
|
|
return 0;
|
|
|
|
} else
|
2015-11-10 21:45:41 +01:00
|
|
|
log_link_debug(link, "Adding address: %s/%u (valid %s%s)", buf, prefixlen,
|
2017-11-24 10:31:08 +01:00
|
|
|
valid_str ? "for " : "forever", strempty(valid_str));
|
2015-09-22 17:18:20 +02:00
|
|
|
}
|
|
|
|
|
2017-12-21 19:07:23 +01:00
|
|
|
r = address_update(address, flags, scope, &cinfo);
|
|
|
|
if (r < 0) {
|
|
|
|
log_link_warning_errno(link, r, "Failed to update address %s/%u, ignoring: %m", buf, prefixlen);
|
|
|
|
return 0;
|
|
|
|
}
|
2015-09-28 17:16:12 +02:00
|
|
|
|
2015-09-22 17:18:20 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case RTM_DELADDR:
|
|
|
|
|
2015-09-24 01:22:05 +02:00
|
|
|
if (address) {
|
2015-11-10 21:45:41 +01:00
|
|
|
log_link_debug(link, "Removing address: %s/%u (valid %s%s)", buf, prefixlen,
|
2017-11-24 10:31:08 +01:00
|
|
|
valid_str ? "for " : "forever", strempty(valid_str));
|
2017-12-21 19:07:23 +01:00
|
|
|
(void) address_drop(address);
|
2015-09-22 17:18:20 +02:00
|
|
|
} else
|
2017-12-21 19:07:23 +01:00
|
|
|
log_link_warning(link, "Removing non-existent address: %s/%u (valid %s%s), ignoring", buf, prefixlen,
|
2017-11-24 10:31:08 +01:00
|
|
|
valid_str ? "for " : "forever", strempty(valid_str));
|
2015-09-22 17:18:20 +02:00
|
|
|
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
assert_not_reached("Received invalid RTNL message type");
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
static int manager_rtnl_process_link(sd_netlink *rtnl, sd_netlink_message *message, void *userdata) {
|
2014-04-15 14:21:44 +02:00
|
|
|
Manager *m = userdata;
|
|
|
|
Link *link = NULL;
|
2014-05-09 17:59:20 +02:00
|
|
|
NetDev *netdev = NULL;
|
2014-05-08 18:55:11 +02:00
|
|
|
uint16_t type;
|
2014-07-18 02:35:16 +02:00
|
|
|
const char *name;
|
2014-04-15 14:21:44 +02:00
|
|
|
int r, ifindex;
|
2013-10-17 03:18:36 +02:00
|
|
|
|
2014-04-15 14:21:44 +02:00
|
|
|
assert(rtnl);
|
|
|
|
assert(message);
|
2013-10-17 03:18:36 +02:00
|
|
|
assert(m);
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
if (sd_netlink_message_is_error(message)) {
|
|
|
|
r = sd_netlink_message_get_errno(message);
|
2014-12-08 19:54:06 +01:00
|
|
|
if (r < 0)
|
2017-12-21 19:07:23 +01:00
|
|
|
log_warning_errno(r, "rtnl: Could not receive link, ignoring: %m");
|
2014-12-08 19:54:06 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_message_get_type(message, &type);
|
2014-05-08 18:55:11 +02:00
|
|
|
if (r < 0) {
|
2017-12-21 19:07:23 +01:00
|
|
|
log_warning_errno(r, "rtnl: Could not get message type, ignoring: %m");
|
2014-05-08 18:55:11 +02:00
|
|
|
return 0;
|
2017-09-28 08:37:38 +02:00
|
|
|
} else if (!IN_SET(type, RTM_NEWLINK, RTM_DELLINK)) {
|
2017-12-21 19:07:23 +01:00
|
|
|
log_warning("rtnl: Received unexpected message type when processing link, ignoring");
|
2015-04-03 15:21:03 +02:00
|
|
|
return 0;
|
2014-05-08 18:55:11 +02:00
|
|
|
}
|
|
|
|
|
2014-04-15 14:21:44 +02:00
|
|
|
r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
|
2014-12-08 19:54:06 +01:00
|
|
|
if (r < 0) {
|
2017-12-21 19:07:23 +01:00
|
|
|
log_warning_errno(r, "rtnl: Could not get ifindex from link, ignoring: %m");
|
2014-12-08 19:54:06 +01:00
|
|
|
return 0;
|
|
|
|
} else if (ifindex <= 0) {
|
2017-12-21 19:07:23 +01:00
|
|
|
log_warning("rtnl: received link message with invalid ifindex %d, ignoring", ifindex);
|
2014-04-15 14:21:44 +02:00
|
|
|
return 0;
|
2016-01-20 01:25:45 +01:00
|
|
|
}
|
2013-10-17 03:18:36 +02:00
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_message_read_string(message, IFLA_IFNAME, &name);
|
2014-12-08 19:54:06 +01:00
|
|
|
if (r < 0) {
|
2017-12-21 19:07:23 +01:00
|
|
|
log_warning_errno(r, "rtnl: Received link message without ifname, ignoring: %m");
|
2014-05-09 17:59:20 +02:00
|
|
|
return 0;
|
2016-01-20 01:25:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
(void) link_get(m, ifindex, &link);
|
|
|
|
(void) netdev_get(m, name, &netdev);
|
2014-05-09 17:59:20 +02:00
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
case RTM_NEWLINK:
|
|
|
|
if (!link) {
|
|
|
|
/* link is new, so add it */
|
|
|
|
r = link_add(m, message, &link);
|
|
|
|
if (r < 0) {
|
2017-12-21 19:07:23 +01:00
|
|
|
log_warning_errno(r, "Could not add new link, ignoring: %m");
|
2014-05-09 17:59:20 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (netdev) {
|
|
|
|
/* netdev exists, so make sure the ifindex matches */
|
2014-04-15 14:21:44 +02:00
|
|
|
r = netdev_set_ifindex(netdev, message);
|
|
|
|
if (r < 0) {
|
2017-12-21 19:07:23 +01:00
|
|
|
log_warning_errno(r, "Could not set ifindex on netdev, ignoring: %m");
|
2014-04-15 14:21:44 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
2013-12-18 17:12:15 +01:00
|
|
|
|
2014-05-08 18:55:11 +02:00
|
|
|
r = link_update(link, message);
|
2017-12-21 19:07:23 +01:00
|
|
|
if (r < 0) {
|
|
|
|
log_warning_errno(r, "Could not update link, ignoring: %m");
|
2014-05-08 18:55:11 +02:00
|
|
|
return 0;
|
2017-12-21 19:07:23 +01:00
|
|
|
}
|
2014-05-09 17:59:20 +02:00
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case RTM_DELLINK:
|
|
|
|
link_drop(link);
|
|
|
|
netdev_drop(netdev);
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
assert_not_reached("Received invalid RTNL message type.");
|
2014-05-08 18:55:11 +02:00
|
|
|
}
|
2014-04-15 14:21:44 +02:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2017-09-14 21:51:39 +02:00
|
|
|
int manager_rtnl_process_rule(sd_netlink *rtnl, sd_netlink_message *message, void *userdata) {
|
|
|
|
uint8_t tos = 0, to_prefixlen = 0, from_prefixlen = 0;
|
2017-12-21 13:27:45 +01:00
|
|
|
union in_addr_union to = {}, from = {};
|
2017-09-14 21:51:39 +02:00
|
|
|
RoutingPolicyRule *rule = NULL;
|
|
|
|
uint32_t fwmark = 0, table = 0;
|
2017-12-21 13:27:45 +01:00
|
|
|
char *iif = NULL, *oif = NULL;
|
2017-09-14 21:51:39 +02:00
|
|
|
Manager *m = userdata;
|
|
|
|
uint16_t type;
|
|
|
|
int family;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(rtnl);
|
|
|
|
assert(message);
|
|
|
|
assert(m);
|
|
|
|
|
|
|
|
if (sd_netlink_message_is_error(message)) {
|
|
|
|
r = sd_netlink_message_get_errno(message);
|
|
|
|
if (r < 0)
|
2017-12-21 19:07:23 +01:00
|
|
|
log_warning_errno(r, "rtnl: failed to receive rule, ignoring: %m");
|
2017-09-14 21:51:39 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_netlink_message_get_type(message, &type);
|
|
|
|
if (r < 0) {
|
2017-12-21 19:07:23 +01:00
|
|
|
log_warning_errno(r, "rtnl: could not get message type, ignoring: %m");
|
2017-09-14 21:51:39 +02:00
|
|
|
return 0;
|
|
|
|
} else if (!IN_SET(type, RTM_NEWRULE, RTM_DELRULE)) {
|
2017-12-21 19:07:23 +01:00
|
|
|
log_warning("rtnl: received unexpected message type '%u' when processing rule, ignoring", type);
|
2017-09-14 21:51:39 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_rtnl_message_get_family(message, &family);
|
2017-09-27 17:55:13 +02:00
|
|
|
if (r < 0) {
|
2017-12-21 19:07:23 +01:00
|
|
|
log_warning_errno(r, "rtnl: could not get rule family, ignoring: %m");
|
2017-09-27 17:55:13 +02:00
|
|
|
return 0;
|
|
|
|
} else if (!IN_SET(family, AF_INET, AF_INET6)) {
|
2017-12-21 19:07:23 +01:00
|
|
|
log_debug("rtnl: received address with invalid family %u, ignoring", family);
|
2017-09-14 21:51:39 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (family) {
|
|
|
|
case AF_INET:
|
|
|
|
r = sd_netlink_message_read_in_addr(message, FRA_SRC, &from.in);
|
2017-12-21 19:07:23 +01:00
|
|
|
if (r < 0 && r != -ENODATA) {
|
|
|
|
log_warning_errno(r, "rtnl: could not get FRA_SRC attribute, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
} else if (r >= 0) {
|
2017-09-14 21:51:39 +02:00
|
|
|
r = sd_rtnl_message_routing_policy_rule_get_rtm_src_prefixlen(message, &from_prefixlen);
|
2017-12-21 19:07:23 +01:00
|
|
|
if (r < 0) {
|
|
|
|
log_warning_errno(r, "rtnl: failed to retrive rule from prefix length, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
2017-09-14 21:51:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_netlink_message_read_in_addr(message, FRA_DST, &to.in);
|
2017-12-21 19:07:23 +01:00
|
|
|
if (r < 0 && r != -ENODATA) {
|
|
|
|
log_warning_errno(r, "rtnl: could not get FRA_DST attribute, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
} else if (r >= 0) {
|
2017-09-14 21:51:39 +02:00
|
|
|
r = sd_rtnl_message_routing_policy_rule_get_rtm_dst_prefixlen(message, &to_prefixlen);
|
2017-12-21 19:07:23 +01:00
|
|
|
if (r < 0) {
|
|
|
|
log_warning_errno(r, "rtnl: failed to retrive rule to prefix length, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
2017-09-14 21:51:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case AF_INET6:
|
|
|
|
r = sd_netlink_message_read_in6_addr(message, FRA_SRC, &from.in6);
|
2017-12-21 19:07:23 +01:00
|
|
|
if (r < 0 && r != -ENODATA) {
|
|
|
|
log_warning_errno(r, "rtnl: could not get FRA_SRC attribute, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
} else if (r >= 0) {
|
2017-09-14 21:51:39 +02:00
|
|
|
r = sd_rtnl_message_routing_policy_rule_get_rtm_src_prefixlen(message, &from_prefixlen);
|
2017-12-21 19:07:23 +01:00
|
|
|
if (r < 0) {
|
|
|
|
log_warning_errno(r, "rtnl: failed to retrive rule from prefix length, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
2017-09-14 21:51:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_netlink_message_read_in6_addr(message, FRA_DST, &to.in6);
|
2017-12-21 19:07:23 +01:00
|
|
|
if (r < 0 && r != -ENODATA) {
|
|
|
|
log_warning_errno(r, "rtnl: could not get FRA_DST attribute, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
} else if (r >= 0) {
|
2017-09-14 21:51:39 +02:00
|
|
|
r = sd_rtnl_message_routing_policy_rule_get_rtm_dst_prefixlen(message, &to_prefixlen);
|
2017-12-21 19:07:23 +01:00
|
|
|
if (r < 0) {
|
|
|
|
log_warning_errno(r, "rtnl: failed to retrive rule to prefix length, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
2017-09-14 21:51:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2017-09-28 08:38:50 +02:00
|
|
|
assert_not_reached("Received unsupported address family");
|
2017-09-14 21:51:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (from_prefixlen == 0 && to_prefixlen == 0)
|
|
|
|
return 0;
|
|
|
|
|
2017-12-21 19:07:23 +01:00
|
|
|
r = sd_netlink_message_read_u32(message, FRA_FWMARK, &fwmark);
|
|
|
|
if (r < 0 && r != -ENODATA) {
|
|
|
|
log_warning_errno(r, "rtnl: could not get FRA_FWMARK attribute, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_netlink_message_read_u32(message, FRA_TABLE, &table);
|
|
|
|
if (r < 0 && r != -ENODATA) {
|
|
|
|
log_warning_errno(r, "rtnl: could not get FRA_TABLE attribute, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_rtnl_message_routing_policy_rule_get_tos(message, &tos);
|
|
|
|
if (r < 0 && r != -ENODATA) {
|
|
|
|
log_warning_errno(r, "rtnl: could not get ip rule TOS, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_netlink_message_read_string(message, FRA_IIFNAME, (const char **) &iif);
|
|
|
|
if (r < 0 && r != -ENODATA) {
|
|
|
|
log_warning_errno(r, "rtnl: could not get FRA_IIFNAME attribute, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_netlink_message_read_string(message, FRA_OIFNAME, (const char **) &oif);
|
|
|
|
if (r < 0 && r != -ENODATA) {
|
|
|
|
log_warning_errno(r, "rtnl: could not get FRA_OIFNAME attribute, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
2017-09-14 21:51:39 +02:00
|
|
|
|
2017-11-21 11:51:50 +01:00
|
|
|
(void) routing_policy_rule_get(m, family, &from, from_prefixlen, &to, to_prefixlen, tos, fwmark, table, iif, oif, &rule);
|
2017-09-14 21:51:39 +02:00
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
case RTM_NEWRULE:
|
2017-12-02 01:49:52 +01:00
|
|
|
if (!rule) {
|
2017-11-21 11:51:50 +01:00
|
|
|
r = routing_policy_rule_add_foreign(m, family, &from, from_prefixlen, &to, to_prefixlen, tos, fwmark, table, iif, oif, &rule);
|
2017-09-14 21:51:39 +02:00
|
|
|
if (r < 0) {
|
2017-12-21 19:07:23 +01:00
|
|
|
log_warning_errno(r, "Could not add rule, ignoring: %m");
|
2017-09-14 21:51:39 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case RTM_DELRULE:
|
|
|
|
routing_policy_rule_free(rule);
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
assert_not_reached("Received invalid RTNL message type");
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2015-02-03 15:44:50 +01:00
|
|
|
static int systemd_netlink_fd(void) {
|
|
|
|
int n, fd, rtnl_fd = -EINVAL;
|
|
|
|
|
|
|
|
n = sd_listen_fds(true);
|
|
|
|
if (n <= 0)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd ++) {
|
|
|
|
if (sd_is_socket(fd, AF_NETLINK, SOCK_RAW, -1) > 0) {
|
|
|
|
if (rtnl_fd >= 0)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
rtnl_fd = fd;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return rtnl_fd;
|
|
|
|
}
|
|
|
|
|
2017-12-18 15:17:06 +01:00
|
|
|
static int manager_connect_genl(Manager *m) {
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
|
|
|
|
r = sd_genl_socket_open(&m->genl);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = sd_netlink_inc_rcvbuf(m->genl, RCVBUF_SIZE);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = sd_netlink_attach_event(m->genl, m->event, 0);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-02-03 15:44:50 +01:00
|
|
|
static int manager_connect_rtnl(Manager *m) {
|
|
|
|
int fd, r;
|
2014-04-15 14:21:44 +02:00
|
|
|
|
|
|
|
assert(m);
|
|
|
|
|
2015-02-03 15:44:50 +01:00
|
|
|
fd = systemd_netlink_fd();
|
|
|
|
if (fd < 0)
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_open(&m->rtnl);
|
2015-02-03 15:44:50 +01:00
|
|
|
else
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_open_fd(&m->rtnl, fd);
|
2014-04-15 14:21:44 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_inc_rcvbuf(m->rtnl, RCVBUF_SIZE);
|
2013-10-17 03:18:36 +02:00
|
|
|
if (r < 0)
|
2013-12-18 03:37:26 +01:00
|
|
|
return r;
|
2013-10-17 03:18:36 +02:00
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_attach_event(m->rtnl, m->event, 0);
|
2014-04-15 14:21:44 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2013-10-17 03:18:36 +02:00
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_add_match(m->rtnl, RTM_NEWLINK, &manager_rtnl_process_link, m);
|
2015-02-03 15:44:50 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2014-04-15 14:21:44 +02:00
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_add_match(m->rtnl, RTM_DELLINK, &manager_rtnl_process_link, m);
|
2015-02-03 15:44:50 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2014-12-08 19:54:06 +01:00
|
|
|
|
2015-09-22 17:18:20 +02:00
|
|
|
r = sd_netlink_add_match(m->rtnl, RTM_NEWADDR, &manager_rtnl_process_address, m);
|
2015-02-03 15:44:50 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2015-09-22 17:18:20 +02:00
|
|
|
r = sd_netlink_add_match(m->rtnl, RTM_DELADDR, &manager_rtnl_process_address, m);
|
2015-02-03 15:44:50 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2015-10-25 14:46:21 +01:00
|
|
|
r = sd_netlink_add_match(m->rtnl, RTM_NEWROUTE, &manager_rtnl_process_route, m);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = sd_netlink_add_match(m->rtnl, RTM_DELROUTE, &manager_rtnl_process_route, m);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2017-09-14 21:51:39 +02:00
|
|
|
r = sd_netlink_add_match(m->rtnl, RTM_NEWRULE, &manager_rtnl_process_rule, m);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = sd_netlink_add_match(m->rtnl, RTM_DELRULE, &manager_rtnl_process_rule, m);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2015-02-03 15:44:50 +01:00
|
|
|
return 0;
|
2014-12-08 19:54:06 +01:00
|
|
|
}
|
2014-04-15 14:21:44 +02:00
|
|
|
|
2016-11-18 17:04:26 +01:00
|
|
|
static int ordered_set_put_in_addr_data(OrderedSet *s, const struct in_addr_data *address) {
|
2015-09-30 18:17:43 +02:00
|
|
|
char *p;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(s);
|
2016-11-18 17:04:26 +01:00
|
|
|
assert(address);
|
|
|
|
|
|
|
|
r = in_addr_to_string(address->family, &address->address, &p);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = ordered_set_consume(s, p);
|
|
|
|
if (r == -EEXIST)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int ordered_set_put_in_addr_datav(OrderedSet *s, const struct in_addr_data *addresses, unsigned n) {
|
|
|
|
int r, c = 0;
|
|
|
|
unsigned i;
|
|
|
|
|
|
|
|
assert(s);
|
|
|
|
assert(addresses || n == 0);
|
|
|
|
|
|
|
|
for (i = 0; i < n; i++) {
|
|
|
|
r = ordered_set_put_in_addr_data(s, addresses+i);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
c += r;
|
|
|
|
}
|
|
|
|
|
|
|
|
return c;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int ordered_set_put_in4_addr(OrderedSet *s, const struct in_addr *address) {
|
|
|
|
char *p;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(s);
|
|
|
|
assert(address);
|
2015-09-30 18:17:43 +02:00
|
|
|
|
|
|
|
r = in_addr_to_string(AF_INET, (const union in_addr_union*) address, &p);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2016-01-25 20:31:11 +01:00
|
|
|
r = ordered_set_consume(s, p);
|
2015-09-30 18:17:43 +02:00
|
|
|
if (r == -EEXIST)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2016-11-18 17:04:26 +01:00
|
|
|
static int ordered_set_put_in4_addrv(OrderedSet *s, const struct in_addr *addresses, unsigned n) {
|
|
|
|
int r, c = 0;
|
|
|
|
unsigned i;
|
2015-09-30 18:17:43 +02:00
|
|
|
|
|
|
|
assert(s);
|
2016-11-18 17:04:26 +01:00
|
|
|
assert(n == 0 || addresses);
|
2015-09-30 18:17:43 +02:00
|
|
|
|
|
|
|
for (i = 0; i < n; i++) {
|
2016-11-18 17:04:26 +01:00
|
|
|
r = ordered_set_put_in4_addr(s, addresses+i);
|
2015-09-30 18:17:43 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
c += r;
|
|
|
|
}
|
|
|
|
|
|
|
|
return c;
|
|
|
|
}
|
|
|
|
|
2016-01-25 20:31:11 +01:00
|
|
|
static void print_string_set(FILE *f, const char *field, OrderedSet *s) {
|
2015-09-30 18:17:43 +02:00
|
|
|
bool space = false;
|
|
|
|
Iterator i;
|
|
|
|
char *p;
|
|
|
|
|
2016-01-25 20:31:11 +01:00
|
|
|
if (ordered_set_isempty(s))
|
2015-09-30 18:17:43 +02:00
|
|
|
return;
|
|
|
|
|
2017-12-11 19:50:30 +01:00
|
|
|
fputs(field, f);
|
2015-09-30 18:17:43 +02:00
|
|
|
|
2016-01-25 22:42:36 +01:00
|
|
|
ORDERED_SET_FOREACH(p, s, i)
|
|
|
|
fputs_with_space(f, p, NULL, &space);
|
|
|
|
|
2017-12-11 19:50:30 +01:00
|
|
|
fputc('\n', f);
|
2015-09-30 18:17:43 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static int manager_save(Manager *m) {
|
2016-01-25 20:31:11 +01:00
|
|
|
_cleanup_ordered_set_free_free_ OrderedSet *dns = NULL, *ntp = NULL, *search_domains = NULL, *route_domains = NULL;
|
2015-09-30 18:17:43 +02:00
|
|
|
Link *link;
|
|
|
|
Iterator i;
|
|
|
|
_cleanup_free_ char *temp_path = NULL;
|
|
|
|
_cleanup_fclose_ FILE *f = NULL;
|
|
|
|
LinkOperationalState operstate = LINK_OPERSTATE_OFF;
|
|
|
|
const char *operstate_str;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
assert(m->state_file);
|
|
|
|
|
|
|
|
/* We add all NTP and DNS server to a set, to filter out duplicates */
|
2016-01-25 20:31:11 +01:00
|
|
|
dns = ordered_set_new(&string_hash_ops);
|
2015-09-30 18:17:43 +02:00
|
|
|
if (!dns)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2016-01-25 20:31:11 +01:00
|
|
|
ntp = ordered_set_new(&string_hash_ops);
|
2015-09-30 18:17:43 +02:00
|
|
|
if (!ntp)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2016-01-25 20:33:47 +01:00
|
|
|
search_domains = ordered_set_new(&dns_name_hash_ops);
|
networkd: rework Domains= setting
Previously, .network files only knew a vaguely defined "Domains=" concept, for which the documentation declared it was
the "DNS domain" for the network connection, without specifying what that means.
With this the Domains setting is reworked, so that there are now "routing" domains and "search" domains. The former are
to be used by resolved to route DNS request to specific network interfaces, the latter is to be used for searching
single-label hostnames with (in addition to being used for routing). Both settings are configured in the "Domains="
setting. Normal domain names listed in it are now considered search domains (for compatibility with existing setups),
while those prefixed with "~" are considered routing domains only. To route all lookups to a specific interface the
routing domain "." may be used, referring to the root domain. An alternative syntax for this is the "*", as was already
implemented before using the "wildcard" domain concept.
This commit adds proper parsers for this new logic, and exposes this via the sd-network API. This information is not
used by resolved yet, this will be added in a later commit.
2016-01-25 19:46:00 +01:00
|
|
|
if (!search_domains)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2016-01-25 20:33:47 +01:00
|
|
|
route_domains = ordered_set_new(&dns_name_hash_ops);
|
networkd: rework Domains= setting
Previously, .network files only knew a vaguely defined "Domains=" concept, for which the documentation declared it was
the "DNS domain" for the network connection, without specifying what that means.
With this the Domains setting is reworked, so that there are now "routing" domains and "search" domains. The former are
to be used by resolved to route DNS request to specific network interfaces, the latter is to be used for searching
single-label hostnames with (in addition to being used for routing). Both settings are configured in the "Domains="
setting. Normal domain names listed in it are now considered search domains (for compatibility with existing setups),
while those prefixed with "~" are considered routing domains only. To route all lookups to a specific interface the
routing domain "." may be used, referring to the root domain. An alternative syntax for this is the "*", as was already
implemented before using the "wildcard" domain concept.
This commit adds proper parsers for this new logic, and exposes this via the sd-network API. This information is not
used by resolved yet, this will be added in a later commit.
2016-01-25 19:46:00 +01:00
|
|
|
if (!route_domains)
|
2015-09-30 18:17:43 +02:00
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
HASHMAP_FOREACH(link, m->links, i) {
|
|
|
|
if (link->flags & IFF_LOOPBACK)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (link->operstate > operstate)
|
|
|
|
operstate = link->operstate;
|
|
|
|
|
|
|
|
if (!link->network)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* First add the static configured entries */
|
2016-11-18 17:04:26 +01:00
|
|
|
r = ordered_set_put_in_addr_datav(dns, link->network->dns, link->network->n_dns);
|
2015-09-30 18:17:43 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2016-01-25 20:31:11 +01:00
|
|
|
r = ordered_set_put_strdupv(ntp, link->network->ntp);
|
2015-09-30 18:17:43 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2016-01-25 20:31:11 +01:00
|
|
|
r = ordered_set_put_strdupv(search_domains, link->network->search_domains);
|
networkd: rework Domains= setting
Previously, .network files only knew a vaguely defined "Domains=" concept, for which the documentation declared it was
the "DNS domain" for the network connection, without specifying what that means.
With this the Domains setting is reworked, so that there are now "routing" domains and "search" domains. The former are
to be used by resolved to route DNS request to specific network interfaces, the latter is to be used for searching
single-label hostnames with (in addition to being used for routing). Both settings are configured in the "Domains="
setting. Normal domain names listed in it are now considered search domains (for compatibility with existing setups),
while those prefixed with "~" are considered routing domains only. To route all lookups to a specific interface the
routing domain "." may be used, referring to the root domain. An alternative syntax for this is the "*", as was already
implemented before using the "wildcard" domain concept.
This commit adds proper parsers for this new logic, and exposes this via the sd-network API. This information is not
used by resolved yet, this will be added in a later commit.
2016-01-25 19:46:00 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2016-01-25 20:31:11 +01:00
|
|
|
r = ordered_set_put_strdupv(route_domains, link->network->route_domains);
|
2015-09-30 18:17:43 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
if (!link->dhcp_lease)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* Secondly, add the entries acquired via DHCP */
|
2016-01-25 21:47:02 +01:00
|
|
|
if (link->network->dhcp_use_dns) {
|
2015-09-30 18:17:43 +02:00
|
|
|
const struct in_addr *addresses;
|
|
|
|
|
|
|
|
r = sd_dhcp_lease_get_dns(link->dhcp_lease, &addresses);
|
|
|
|
if (r > 0) {
|
2016-11-18 17:04:26 +01:00
|
|
|
r = ordered_set_put_in4_addrv(dns, addresses, r);
|
2015-09-30 18:17:43 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
} else if (r < 0 && r != -ENODATA)
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2016-01-25 21:47:02 +01:00
|
|
|
if (link->network->dhcp_use_ntp) {
|
2015-09-30 18:17:43 +02:00
|
|
|
const struct in_addr *addresses;
|
|
|
|
|
|
|
|
r = sd_dhcp_lease_get_ntp(link->dhcp_lease, &addresses);
|
|
|
|
if (r > 0) {
|
2016-11-18 17:04:26 +01:00
|
|
|
r = ordered_set_put_in4_addrv(ntp, addresses, r);
|
2015-09-30 18:17:43 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
} else if (r < 0 && r != -ENODATA)
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2016-01-25 22:27:01 +01:00
|
|
|
if (link->network->dhcp_use_domains != DHCP_USE_DOMAINS_NO) {
|
2015-09-30 18:17:43 +02:00
|
|
|
const char *domainname;
|
2017-05-13 16:19:32 +02:00
|
|
|
char **domains = NULL;
|
2015-09-30 18:17:43 +02:00
|
|
|
|
2017-05-13 16:19:32 +02:00
|
|
|
OrderedSet *target_domains = (link->network->dhcp_use_domains == DHCP_USE_DOMAINS_YES) ? search_domains : route_domains;
|
2015-09-30 18:17:43 +02:00
|
|
|
r = sd_dhcp_lease_get_domainname(link->dhcp_lease, &domainname);
|
|
|
|
if (r >= 0) {
|
2017-05-13 16:19:32 +02:00
|
|
|
r = ordered_set_put_strdup(target_domains, domainname);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
} else if (r != -ENODATA)
|
|
|
|
return r;
|
2016-01-25 22:27:01 +01:00
|
|
|
|
2017-05-13 16:19:32 +02:00
|
|
|
r = sd_dhcp_lease_get_search_domains(link->dhcp_lease, &domains);
|
|
|
|
if (r >= 0) {
|
|
|
|
r = ordered_set_put_strdupv(target_domains, domains);
|
2015-09-30 18:17:43 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
} else if (r != -ENODATA)
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
operstate_str = link_operstate_to_string(operstate);
|
|
|
|
assert(operstate_str);
|
|
|
|
|
|
|
|
r = fopen_temporary(m->state_file, &f, &temp_path);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2017-12-11 19:50:30 +01:00
|
|
|
(void) __fsetlocking(f, FSETLOCKING_BYCALLER);
|
2016-11-18 17:04:26 +01:00
|
|
|
(void) fchmod(fileno(f), 0644);
|
2015-09-30 18:17:43 +02:00
|
|
|
|
|
|
|
fprintf(f,
|
|
|
|
"# This is private data. Do not parse.\n"
|
|
|
|
"OPER_STATE=%s\n", operstate_str);
|
|
|
|
|
|
|
|
print_string_set(f, "DNS=", dns);
|
|
|
|
print_string_set(f, "NTP=", ntp);
|
networkd: rework Domains= setting
Previously, .network files only knew a vaguely defined "Domains=" concept, for which the documentation declared it was
the "DNS domain" for the network connection, without specifying what that means.
With this the Domains setting is reworked, so that there are now "routing" domains and "search" domains. The former are
to be used by resolved to route DNS request to specific network interfaces, the latter is to be used for searching
single-label hostnames with (in addition to being used for routing). Both settings are configured in the "Domains="
setting. Normal domain names listed in it are now considered search domains (for compatibility with existing setups),
while those prefixed with "~" are considered routing domains only. To route all lookups to a specific interface the
routing domain "." may be used, referring to the root domain. An alternative syntax for this is the "*", as was already
implemented before using the "wildcard" domain concept.
This commit adds proper parsers for this new logic, and exposes this via the sd-network API. This information is not
used by resolved yet, this will be added in a later commit.
2016-01-25 19:46:00 +01:00
|
|
|
print_string_set(f, "DOMAINS=", search_domains);
|
|
|
|
print_string_set(f, "ROUTE_DOMAINS=", route_domains);
|
2015-09-30 18:17:43 +02:00
|
|
|
|
2017-11-27 11:22:51 +01:00
|
|
|
r = routing_policy_serialize_rules(m->rules, f);
|
|
|
|
if (r < 0)
|
|
|
|
goto fail;
|
2017-09-14 21:51:39 +02:00
|
|
|
|
2015-09-30 18:17:43 +02:00
|
|
|
r = fflush_and_check(f);
|
|
|
|
if (r < 0)
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
if (rename(temp_path, m->state_file) < 0) {
|
|
|
|
r = -errno;
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m->operational_state != operstate) {
|
|
|
|
m->operational_state = operstate;
|
|
|
|
r = manager_send_changed(m, "OperationalState", NULL);
|
|
|
|
if (r < 0)
|
|
|
|
log_error_errno(r, "Could not emit changed OperationalState: %m");
|
|
|
|
}
|
|
|
|
|
|
|
|
m->dirty = false;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
fail:
|
|
|
|
(void) unlink(m->state_file);
|
|
|
|
(void) unlink(temp_path);
|
|
|
|
|
|
|
|
return log_error_errno(r, "Failed to save network state to %s: %m", m->state_file);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int manager_dirty_handler(sd_event_source *s, void *userdata) {
|
|
|
|
Manager *m = userdata;
|
|
|
|
Link *link;
|
|
|
|
Iterator i;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
|
|
|
|
if (m->dirty)
|
|
|
|
manager_save(m);
|
|
|
|
|
|
|
|
SET_FOREACH(link, m->dirty_links, i) {
|
|
|
|
r = link_save(link);
|
|
|
|
if (r >= 0)
|
|
|
|
link_clean(link);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2018-01-04 14:11:58 +01:00
|
|
|
Link *manager_dhcp6_prefix_get(Manager *m, struct in6_addr *addr) {
|
|
|
|
assert_return(m, NULL);
|
|
|
|
assert_return(m->dhcp6_prefixes, NULL);
|
|
|
|
assert_return(addr, NULL);
|
|
|
|
|
|
|
|
return hashmap_get(m->dhcp6_prefixes, addr);
|
|
|
|
}
|
|
|
|
|
2018-01-04 14:12:00 +01:00
|
|
|
static int dhcp6_route_add_callback(sd_netlink *nl, sd_netlink_message *m,
|
|
|
|
void *userdata) {
|
|
|
|
Link *l = userdata;
|
|
|
|
int r;
|
|
|
|
union in_addr_union prefix;
|
|
|
|
_cleanup_free_ char *buf = NULL;
|
|
|
|
|
|
|
|
r = sd_netlink_message_get_errno(m);
|
|
|
|
if (r != 0) {
|
|
|
|
log_link_debug_errno(l, r, "Received error adding DHCPv6 Prefix Delegation route: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_netlink_message_read_in6_addr(m, RTA_DST, &prefix.in6);
|
|
|
|
if (r < 0) {
|
|
|
|
log_link_debug_errno(l, r, "Could not read IPv6 address from DHCPv6 Prefix Delegation while adding route: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
(void) in_addr_to_string(AF_INET6, &prefix, &buf);
|
|
|
|
log_link_debug(l, "Added DHCPv6 Prefix Deleagtion route %s/64",
|
|
|
|
strnull(buf));
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-01-04 14:11:58 +01:00
|
|
|
int manager_dhcp6_prefix_add(Manager *m, struct in6_addr *addr, Link *link) {
|
2018-01-04 14:12:00 +01:00
|
|
|
int r;
|
|
|
|
Route *route;
|
|
|
|
|
2018-01-04 14:11:58 +01:00
|
|
|
assert_return(m, -EINVAL);
|
|
|
|
assert_return(m->dhcp6_prefixes, -ENODATA);
|
|
|
|
assert_return(addr, -EINVAL);
|
|
|
|
|
2018-01-04 14:12:00 +01:00
|
|
|
r = route_add(link, AF_INET6, (union in_addr_union *) addr, 64,
|
|
|
|
0, 0, 0, &route);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = route_configure(route, link, dhcp6_route_add_callback);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2018-01-04 14:11:58 +01:00
|
|
|
return hashmap_put(m->dhcp6_prefixes, addr, link);
|
|
|
|
}
|
|
|
|
|
2018-01-04 14:12:00 +01:00
|
|
|
static int dhcp6_route_remove_callback(sd_netlink *nl, sd_netlink_message *m,
|
|
|
|
void *userdata) {
|
|
|
|
Link *l = userdata;
|
|
|
|
int r;
|
|
|
|
union in_addr_union prefix;
|
|
|
|
_cleanup_free_ char *buf = NULL;
|
|
|
|
|
|
|
|
r = sd_netlink_message_get_errno(m);
|
|
|
|
if (r != 0) {
|
|
|
|
log_link_debug_errno(l, r, "Received error on DHCPv6 Prefix Delegation route removal: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_netlink_message_read_in6_addr(m, RTA_DST, &prefix.in6);
|
|
|
|
if (r < 0) {
|
|
|
|
log_link_debug_errno(l, r, "Could not read IPv6 address from DHCPv6 Prefix Delegation while removing route: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
(void) in_addr_to_string(AF_INET6, &prefix, &buf);
|
|
|
|
log_link_debug(l, "Removed DHCPv6 Prefix Delegation route %s/64",
|
|
|
|
strnull(buf));
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-01-04 14:11:58 +01:00
|
|
|
int manager_dhcp6_prefix_remove(Manager *m, struct in6_addr *addr) {
|
|
|
|
Link *l;
|
2018-01-04 14:12:00 +01:00
|
|
|
int r;
|
|
|
|
Route *route;
|
2018-01-04 14:11:58 +01:00
|
|
|
|
|
|
|
assert_return(m, -EINVAL);
|
|
|
|
assert_return(m->dhcp6_prefixes, -ENODATA);
|
|
|
|
assert_return(addr, -EINVAL);
|
|
|
|
|
|
|
|
l = hashmap_remove(m->dhcp6_prefixes, addr);
|
|
|
|
if (!l)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
(void) sd_radv_remove_prefix(l->radv, addr, 64);
|
2018-01-04 14:12:00 +01:00
|
|
|
r = route_get(l, AF_INET6, (union in_addr_union *) addr, 64,
|
|
|
|
0, 0, 0, &route);
|
|
|
|
if (r >= 0)
|
|
|
|
(void) route_remove(route, l, dhcp6_route_remove_callback);
|
2018-01-04 14:11:58 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int manager_dhcp6_prefix_remove_all(Manager *m, Link *link) {
|
|
|
|
Iterator i;
|
|
|
|
Link *l;
|
|
|
|
struct in6_addr *addr;
|
|
|
|
|
|
|
|
assert_return(m, -EINVAL);
|
2018-01-16 17:29:13 +01:00
|
|
|
assert_return(link, -EINVAL);
|
2018-01-04 14:11:58 +01:00
|
|
|
|
|
|
|
HASHMAP_FOREACH_KEY(l, addr, m->dhcp6_prefixes, i) {
|
|
|
|
if (l != link)
|
|
|
|
continue;
|
|
|
|
|
2018-01-04 14:12:00 +01:00
|
|
|
(void) manager_dhcp6_prefix_remove(m, addr);
|
2018-01-04 14:11:58 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void dhcp6_prefixes_hash_func(const void *p, struct siphash *state) {
|
|
|
|
const struct in6_addr *addr = p;
|
|
|
|
|
|
|
|
assert(p);
|
|
|
|
|
|
|
|
siphash24_compress(addr, sizeof(*addr), state);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int dhcp6_prefixes_compare_func(const void *_a, const void *_b) {
|
|
|
|
const struct in6_addr *a = _a, *b = _b;
|
|
|
|
|
2018-02-06 09:05:58 +01:00
|
|
|
return memcmp(a, b, sizeof(*a));
|
2018-01-04 14:11:58 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static const struct hash_ops dhcp6_prefixes_hash_ops = {
|
|
|
|
.hash = dhcp6_prefixes_hash_func,
|
|
|
|
.compare = dhcp6_prefixes_compare_func,
|
|
|
|
};
|
|
|
|
|
2016-11-28 20:42:40 +01:00
|
|
|
int manager_new(Manager **ret, sd_event *event) {
|
tree-wide: drop redundant _cleanup_ macros (#8810)
This drops a good number of type-specific _cleanup_ macros, and patches
all users to just use the generic ones.
In most recent code we abstained from defining type-specific macros, and
this basically removes all those added already, with the exception of
the really low-level ones.
Having explicit macros for this is not too useful, as the expression
without the extra macro is generally just 2ch wider. We should generally
emphesize generic code, unless there are really good reasons for
specific code, hence let's follow this in this case too.
Note that _cleanup_free_ and similar really low-level, libc'ish, Linux
API'ish macros continue to be defined, only the really high-level OO
ones are dropped. From now on this should really be the rule: for really
low-level stuff, such as memory allocation, fd handling and so one, go
ahead and define explicit per-type macros, but for high-level, specific
program code, just use the generic _cleanup_() macro directly, in order
to keep things simple and as readable as possible for the uninitiated.
Note that before this patch some of the APIs (notable libudev ones) were
already used with the high-level macros at some places and with the
generic _cleanup_ macro at others. With this patch we hence unify on the
latter.
2018-04-25 12:31:45 +02:00
|
|
|
_cleanup_(manager_freep) Manager *m = NULL;
|
2014-12-08 19:54:06 +01:00
|
|
|
int r;
|
2013-10-17 03:18:36 +02:00
|
|
|
|
2015-02-03 15:44:50 +01:00
|
|
|
m = new0(Manager, 1);
|
|
|
|
if (!m)
|
|
|
|
return -ENOMEM;
|
2014-12-08 19:54:06 +01:00
|
|
|
|
2015-02-03 15:44:50 +01:00
|
|
|
m->state_file = strdup("/run/systemd/netif/state");
|
|
|
|
if (!m->state_file)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2016-11-28 20:42:40 +01:00
|
|
|
m->event = sd_event_ref(event);
|
2015-02-03 15:44:50 +01:00
|
|
|
|
2015-09-30 18:17:43 +02:00
|
|
|
r = sd_event_add_post(m->event, NULL, manager_dirty_handler, m);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2015-02-03 15:44:50 +01:00
|
|
|
r = manager_connect_rtnl(m);
|
2014-12-08 19:54:06 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2017-12-18 15:17:06 +01:00
|
|
|
r = manager_connect_genl(m);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2015-02-03 15:44:50 +01:00
|
|
|
r = manager_connect_udev(m);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2014-12-08 19:54:06 +01:00
|
|
|
|
2015-02-03 15:44:50 +01:00
|
|
|
m->netdevs = hashmap_new(&string_hash_ops);
|
|
|
|
if (!m->netdevs)
|
|
|
|
return -ENOMEM;
|
2013-10-17 03:18:36 +02:00
|
|
|
|
2015-02-03 15:44:50 +01:00
|
|
|
LIST_HEAD_INIT(m->networks);
|
2013-10-17 03:18:36 +02:00
|
|
|
|
2017-12-18 15:17:06 +01:00
|
|
|
r = sd_resolve_default(&m->resolve);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = sd_resolve_attach_event(m->resolve, m->event, 0);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2015-02-03 15:44:50 +01:00
|
|
|
r = setup_default_address_pool(m);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2013-10-17 03:18:36 +02:00
|
|
|
|
2018-01-04 14:11:58 +01:00
|
|
|
m->dhcp6_prefixes = hashmap_new(&dhcp6_prefixes_hash_ops);
|
|
|
|
if (!m->dhcp6_prefixes)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
networkd: rework duid_{type,duid_type,duid,duid_len} setting
Separate fields are replaced with a struct.
Second second duid type field is removed. The first field was used to carry
the result of DUIDType= configuration, and the second was either a copy of
this, or contained the type extracted from DuidRawData. The semantics are changed
so that the type specified in DUIDType is always used. DUIDRawData= no longer
overrides the type setting.
The networkd code is now more constrained than the sd-dhcp code:
DUIDRawData cannot have 0 length, length 0 is treated the same as unsetting.
Likewise, it is not possible to set a DUIDType=0. If it ever becomes necessary
to set type=0 or a zero-length duid, the code can be changed to support that.
Nevertheless, I think that's unlikely.
This addresses #3127 § 1 and 3.
v2:
- rename DUID.duid, DUID.duid_len to DUID.raw_data, DUID.raw_data_len
2016-04-29 05:23:45 +02:00
|
|
|
m->duid.type = DUID_TYPE_EN;
|
2016-03-31 01:33:55 +02:00
|
|
|
|
2017-11-27 11:22:51 +01:00
|
|
|
(void) routing_policy_load_rules(m->state_file, &m->rules_saved);
|
2017-09-14 21:51:39 +02:00
|
|
|
|
2018-04-05 07:26:26 +02:00
|
|
|
*ret = TAKE_PTR(m);
|
2013-10-17 03:18:36 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-02-03 15:44:50 +01:00
|
|
|
void manager_free(Manager *m) {
|
|
|
|
Network *network;
|
|
|
|
NetDev *netdev;
|
|
|
|
Link *link;
|
|
|
|
AddressPool *pool;
|
2013-10-17 03:18:36 +02:00
|
|
|
|
2015-02-03 15:44:50 +01:00
|
|
|
if (!m)
|
|
|
|
return;
|
2014-04-15 14:21:44 +02:00
|
|
|
|
2015-02-03 15:44:50 +01:00
|
|
|
free(m->state_file);
|
2014-04-15 14:21:44 +02:00
|
|
|
|
2017-09-14 21:51:39 +02:00
|
|
|
while ((network = m->networks))
|
|
|
|
network_free(network);
|
|
|
|
|
2018-01-04 14:11:58 +01:00
|
|
|
while ((link = hashmap_first(m->dhcp6_prefixes)))
|
|
|
|
link_unref(link);
|
|
|
|
hashmap_free(m->dhcp6_prefixes);
|
|
|
|
|
2015-02-03 15:44:50 +01:00
|
|
|
while ((link = hashmap_first(m->links)))
|
|
|
|
link_unref(link);
|
|
|
|
hashmap_free(m->links);
|
2013-10-17 03:18:36 +02:00
|
|
|
|
2015-02-08 13:29:35 +01:00
|
|
|
hashmap_free(m->networks_by_name);
|
|
|
|
|
2015-02-03 15:44:50 +01:00
|
|
|
while ((netdev = hashmap_first(m->netdevs)))
|
|
|
|
netdev_unref(netdev);
|
|
|
|
hashmap_free(m->netdevs);
|
|
|
|
|
|
|
|
while ((pool = m->address_pools))
|
|
|
|
address_pool_free(pool);
|
|
|
|
|
2017-09-14 21:51:39 +02:00
|
|
|
set_free(m->rules);
|
|
|
|
set_free(m->rules_foreign);
|
|
|
|
|
2017-11-28 13:02:33 +01:00
|
|
|
set_free_with_destructor(m->rules_saved, routing_policy_rule_free);
|
2017-09-14 21:51:39 +02:00
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
sd_netlink_unref(m->rtnl);
|
2015-08-27 17:38:05 +02:00
|
|
|
sd_event_unref(m->event);
|
2015-02-03 15:44:50 +01:00
|
|
|
|
2017-12-18 15:17:06 +01:00
|
|
|
sd_resolve_unref(m->resolve);
|
|
|
|
|
2015-10-09 21:36:04 +02:00
|
|
|
sd_event_source_unref(m->udev_event_source);
|
|
|
|
udev_monitor_unref(m->udev_monitor);
|
|
|
|
udev_unref(m->udev);
|
|
|
|
|
|
|
|
sd_bus_unref(m->bus);
|
|
|
|
sd_bus_slot_unref(m->prepare_for_sleep_slot);
|
2017-12-19 15:54:30 +01:00
|
|
|
sd_bus_slot_unref(m->connected_slot);
|
2015-10-09 21:36:04 +02:00
|
|
|
|
2016-11-22 08:36:20 +01:00
|
|
|
free(m->dynamic_timezone);
|
|
|
|
free(m->dynamic_hostname);
|
|
|
|
|
2015-02-03 15:44:50 +01:00
|
|
|
free(m);
|
|
|
|
}
|
|
|
|
|
2016-11-28 20:42:40 +01:00
|
|
|
int manager_start(Manager *m) {
|
2015-09-30 18:17:43 +02:00
|
|
|
Link *link;
|
|
|
|
Iterator i;
|
|
|
|
|
2015-02-04 15:00:20 +01:00
|
|
|
assert(m);
|
|
|
|
|
2015-09-30 18:17:43 +02:00
|
|
|
/* The dirty handler will deal with future serialization, but the first one
|
|
|
|
must be done explicitly. */
|
|
|
|
|
|
|
|
manager_save(m);
|
|
|
|
|
|
|
|
HASHMAP_FOREACH(link, m->links, i)
|
|
|
|
link_save(link);
|
|
|
|
|
2016-11-28 20:42:40 +01:00
|
|
|
return 0;
|
2015-02-04 15:00:20 +01:00
|
|
|
}
|
|
|
|
|
2015-02-03 15:44:50 +01:00
|
|
|
int manager_load_config(Manager *m) {
|
|
|
|
int r;
|
|
|
|
|
|
|
|
/* update timestamp */
|
|
|
|
paths_check_timestamp(network_dirs, &m->network_dirs_ts_usec, true);
|
|
|
|
|
|
|
|
r = netdev_load(m);
|
2013-10-17 03:18:36 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2015-02-03 15:44:50 +01:00
|
|
|
r = network_load(m);
|
2014-08-28 15:46:29 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2013-10-17 03:18:36 +02:00
|
|
|
return 0;
|
|
|
|
}
|
2013-11-14 16:22:51 +01:00
|
|
|
|
2015-02-03 15:44:50 +01:00
|
|
|
bool manager_should_reload(Manager *m) {
|
|
|
|
return paths_check_timestamp(network_dirs, &m->network_dirs_ts_usec, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
int manager_rtnl_enumerate_links(Manager *m) {
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
|
2015-06-12 16:31:33 +02:00
|
|
|
sd_netlink_message *link;
|
2013-11-14 16:22:51 +01:00
|
|
|
int r;
|
|
|
|
|
2014-07-01 10:09:52 +02:00
|
|
|
assert(m);
|
2015-02-03 15:44:50 +01:00
|
|
|
assert(m->rtnl);
|
2014-07-01 10:09:52 +02:00
|
|
|
|
2015-02-03 15:44:50 +01:00
|
|
|
r = sd_rtnl_message_new_link(m->rtnl, &req, RTM_GETLINK, 0);
|
2013-11-14 16:22:51 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_message_request_dump(req, true);
|
2013-12-03 18:48:20 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_call(m->rtnl, req, 0, &reply);
|
2014-05-08 18:55:11 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
for (link = reply; link; link = sd_netlink_message_next(link)) {
|
2015-02-03 15:44:50 +01:00
|
|
|
int k;
|
2014-05-10 19:39:03 +02:00
|
|
|
|
2015-02-04 10:08:12 +01:00
|
|
|
m->enumerating = true;
|
|
|
|
|
2015-02-03 15:44:50 +01:00
|
|
|
k = manager_rtnl_process_link(m->rtnl, link, m);
|
|
|
|
if (k < 0)
|
|
|
|
r = k;
|
2015-02-04 10:08:12 +01:00
|
|
|
|
|
|
|
m->enumerating = false;
|
2015-02-03 15:44:50 +01:00
|
|
|
}
|
2014-05-10 19:39:03 +02:00
|
|
|
|
2015-02-03 15:44:50 +01:00
|
|
|
return r;
|
2013-11-14 16:22:51 +01:00
|
|
|
}
|
2014-01-05 23:01:10 +01:00
|
|
|
|
2015-02-03 15:44:50 +01:00
|
|
|
int manager_rtnl_enumerate_addresses(Manager *m) {
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
|
2015-06-12 16:31:33 +02:00
|
|
|
sd_netlink_message *addr;
|
2014-01-13 23:48:28 +01:00
|
|
|
int r;
|
|
|
|
|
2015-02-03 15:44:50 +01:00
|
|
|
assert(m);
|
|
|
|
assert(m->rtnl);
|
2014-01-18 01:37:35 +01:00
|
|
|
|
2015-02-03 15:44:50 +01:00
|
|
|
r = sd_rtnl_message_new_addr(m->rtnl, &req, RTM_GETADDR, 0, 0);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2014-01-18 01:37:35 +01:00
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_message_request_dump(req, true);
|
2014-01-13 23:48:28 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_call(m->rtnl, req, 0, &reply);
|
2015-02-03 15:44:50 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
for (addr = reply; addr; addr = sd_netlink_message_next(addr)) {
|
2015-02-03 15:44:50 +01:00
|
|
|
int k;
|
|
|
|
|
2015-02-04 10:08:12 +01:00
|
|
|
m->enumerating = true;
|
|
|
|
|
2015-09-22 17:18:20 +02:00
|
|
|
k = manager_rtnl_process_address(m->rtnl, addr, m);
|
2015-02-03 15:44:50 +01:00
|
|
|
if (k < 0)
|
|
|
|
r = k;
|
2015-02-04 10:08:12 +01:00
|
|
|
|
|
|
|
m->enumerating = false;
|
2015-02-03 15:44:50 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return r;
|
2014-01-13 23:48:28 +01:00
|
|
|
}
|
|
|
|
|
2015-10-25 14:46:21 +01:00
|
|
|
int manager_rtnl_enumerate_routes(Manager *m) {
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
|
2015-10-25 14:46:21 +01:00
|
|
|
sd_netlink_message *route;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
assert(m->rtnl);
|
|
|
|
|
|
|
|
r = sd_rtnl_message_new_route(m->rtnl, &req, RTM_GETROUTE, 0, 0);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = sd_netlink_message_request_dump(req, true);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = sd_netlink_call(m->rtnl, req, 0, &reply);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
for (route = reply; route; route = sd_netlink_message_next(route)) {
|
|
|
|
int k;
|
|
|
|
|
|
|
|
m->enumerating = true;
|
|
|
|
|
|
|
|
k = manager_rtnl_process_route(m->rtnl, route, m);
|
|
|
|
if (k < 0)
|
|
|
|
r = k;
|
|
|
|
|
|
|
|
m->enumerating = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2017-09-14 21:51:39 +02:00
|
|
|
int manager_rtnl_enumerate_rules(Manager *m) {
|
|
|
|
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
|
|
|
|
sd_netlink_message *rule;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
assert(m->rtnl);
|
|
|
|
|
|
|
|
r = sd_rtnl_message_new_routing_policy_rule(m->rtnl, &req, RTM_GETRULE, 0);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = sd_netlink_message_request_dump(req, true);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = sd_netlink_call(m->rtnl, req, 0, &reply);
|
networkd: Don't stop networkd if CONFIG_FIB_RULES=n in kernel (#7030)
If FIB Rules are not supported by the kernel then networkd fails to
start as it retuns error=-EOPNOTSUPP.
In this case just ignore and let start networkd.
```
sendto(5, {{len=28, type=RTM_GETRULE, flags=NLM_F_REQUEST|NLM_F_ACK|NLM_F_DUMP, seq=8, pid=0}, {family=AF_UNSPEC, dst_len=0, src_len=0, tos=0, table=RT_TABLE_UNSPEC, action=FR_ACT_TO_TBL, flags=0}}, 28, 0, {sa_family=AF_NETLINK, nl_pid=0, nl_groups=00000000}, 16) = 28
recvmsg(5, {msg_name={sa_family=AF_NETLINK, nl_pid=0, nl_groups=00000000}, msg_namelen=128->12, msg_iov=[{iov_base=NULL, iov_len=0}], msg_iovlen=1, msg_control=[{cmsg_len=20, cmsg_level=SOL_NETLINK, cmsg_type=0x3}], msg_controllen=24, msg_flags=MSG_TRUNC}, MSG_PEEK|MSG_TRUNC) = 48
recvmsg(5, {msg_name={sa_family=AF_NETLINK, nl_pid=0, nl_groups=00000000}, msg_namelen=128->12, msg_iov=[{iov_base={{len=48, type=NLMSG_ERROR, flags=0, seq=8, pid=8856}, {error=-EOPNOTSUPP, msg={{len=28, type=RTM_GETRULE, flags=NLM_F_REQUEST|NLM_F_ACK|NLM_F_DUMP, seq=8, pid=0}, {family=AF_UNSPEC, dst_len=0, src_len=0, tos=0, table=RT_TABLE_UNSPEC, action=FR_ACT_TO_TBL, flags=0}}}}, iov_len=7416}], msg_iovlen=1, msg_control=[{cmsg_len=20, cmsg_level=SOL_NETLINK, cmsg_type=0x3}], msg_controllen=24, msg_flags=0}, MSG_TRUNC) = 48
```
```
Oct 08 10:22:24 naomi systemd[1]: Starting Network Service...
Oct 08 10:22:24 naomi systemd-networkd[983]: Could not enumerate rules: Operation not supported
Oct 08 10:22:24 naomi systemd[1]: systemd-networkd.service: Main process exited, code=exited, status=1/FAILURE
```
Fixes #7027
2017-10-18 08:25:57 +02:00
|
|
|
if (r < 0) {
|
|
|
|
if (r == -EOPNOTSUPP) {
|
|
|
|
log_debug("FIB Rules are not supported by the kernel. Ignoring.");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-09-14 21:51:39 +02:00
|
|
|
return r;
|
networkd: Don't stop networkd if CONFIG_FIB_RULES=n in kernel (#7030)
If FIB Rules are not supported by the kernel then networkd fails to
start as it retuns error=-EOPNOTSUPP.
In this case just ignore and let start networkd.
```
sendto(5, {{len=28, type=RTM_GETRULE, flags=NLM_F_REQUEST|NLM_F_ACK|NLM_F_DUMP, seq=8, pid=0}, {family=AF_UNSPEC, dst_len=0, src_len=0, tos=0, table=RT_TABLE_UNSPEC, action=FR_ACT_TO_TBL, flags=0}}, 28, 0, {sa_family=AF_NETLINK, nl_pid=0, nl_groups=00000000}, 16) = 28
recvmsg(5, {msg_name={sa_family=AF_NETLINK, nl_pid=0, nl_groups=00000000}, msg_namelen=128->12, msg_iov=[{iov_base=NULL, iov_len=0}], msg_iovlen=1, msg_control=[{cmsg_len=20, cmsg_level=SOL_NETLINK, cmsg_type=0x3}], msg_controllen=24, msg_flags=MSG_TRUNC}, MSG_PEEK|MSG_TRUNC) = 48
recvmsg(5, {msg_name={sa_family=AF_NETLINK, nl_pid=0, nl_groups=00000000}, msg_namelen=128->12, msg_iov=[{iov_base={{len=48, type=NLMSG_ERROR, flags=0, seq=8, pid=8856}, {error=-EOPNOTSUPP, msg={{len=28, type=RTM_GETRULE, flags=NLM_F_REQUEST|NLM_F_ACK|NLM_F_DUMP, seq=8, pid=0}, {family=AF_UNSPEC, dst_len=0, src_len=0, tos=0, table=RT_TABLE_UNSPEC, action=FR_ACT_TO_TBL, flags=0}}}}, iov_len=7416}], msg_iovlen=1, msg_control=[{cmsg_len=20, cmsg_level=SOL_NETLINK, cmsg_type=0x3}], msg_controllen=24, msg_flags=0}, MSG_TRUNC) = 48
```
```
Oct 08 10:22:24 naomi systemd[1]: Starting Network Service...
Oct 08 10:22:24 naomi systemd-networkd[983]: Could not enumerate rules: Operation not supported
Oct 08 10:22:24 naomi systemd[1]: systemd-networkd.service: Main process exited, code=exited, status=1/FAILURE
```
Fixes #7027
2017-10-18 08:25:57 +02:00
|
|
|
}
|
2017-09-14 21:51:39 +02:00
|
|
|
|
|
|
|
for (rule = reply; rule; rule = sd_netlink_message_next(rule)) {
|
|
|
|
int k;
|
|
|
|
|
|
|
|
m->enumerating = true;
|
|
|
|
|
|
|
|
k = manager_rtnl_process_rule(m->rtnl, rule, m);
|
|
|
|
if (k < 0)
|
|
|
|
r = k;
|
|
|
|
|
|
|
|
m->enumerating = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2014-07-18 16:09:30 +02:00
|
|
|
int manager_address_pool_acquire(Manager *m, int family, unsigned prefixlen, union in_addr_union *found) {
|
2014-06-18 18:22:14 +02:00
|
|
|
AddressPool *p;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
assert(prefixlen > 0);
|
|
|
|
assert(found);
|
|
|
|
|
|
|
|
LIST_FOREACH(address_pools, p, m->address_pools) {
|
|
|
|
if (p->family != family)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
r = address_pool_acquire(p, prefixlen, found);
|
|
|
|
if (r != 0)
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2015-08-27 16:45:24 +02:00
|
|
|
|
|
|
|
Link* manager_find_uplink(Manager *m, Link *exclude) {
|
|
|
|
_cleanup_free_ struct local_address *gateways = NULL;
|
|
|
|
int n, i;
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
|
|
|
|
/* Looks for a suitable "uplink", via black magic: an
|
|
|
|
* interface that is up and where the default route with the
|
|
|
|
* highest priority points to. */
|
|
|
|
|
|
|
|
n = local_gateways(m->rtnl, 0, AF_UNSPEC, &gateways);
|
|
|
|
if (n < 0) {
|
|
|
|
log_warning_errno(n, "Failed to determine list of default gateways: %m");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < n; i++) {
|
|
|
|
Link *link;
|
|
|
|
|
|
|
|
link = hashmap_get(m->links, INT_TO_PTR(gateways[i].ifindex));
|
|
|
|
if (!link) {
|
2015-08-27 20:23:17 +02:00
|
|
|
log_debug("Weird, found a gateway for a link we don't know. Ignoring.");
|
2015-08-27 16:45:24 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (link == exclude)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (link->operstate < LINK_OPERSTATE_ROUTABLE)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
return link;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
2015-09-30 18:17:43 +02:00
|
|
|
|
|
|
|
void manager_dirty(Manager *manager) {
|
|
|
|
assert(manager);
|
|
|
|
|
|
|
|
/* the serialized state in /run is no longer up-to-date */
|
|
|
|
manager->dirty = true;
|
|
|
|
}
|
2016-11-21 23:15:41 +01:00
|
|
|
|
|
|
|
static int set_hostname_handler(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
|
|
|
|
Manager *manager = userdata;
|
|
|
|
const sd_bus_error *e;
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
assert(manager);
|
|
|
|
|
|
|
|
e = sd_bus_message_get_error(m);
|
|
|
|
if (e)
|
|
|
|
log_warning_errno(sd_bus_error_get_errno(e), "Could not set hostname: %s", e->message);
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int manager_set_hostname(Manager *m, const char *hostname) {
|
|
|
|
int r;
|
|
|
|
|
|
|
|
log_debug("Setting transient hostname: '%s'", strna(hostname));
|
2017-12-19 15:54:30 +01:00
|
|
|
|
2016-11-22 08:36:20 +01:00
|
|
|
if (free_and_strdup(&m->dynamic_hostname, hostname) < 0)
|
|
|
|
return log_oom();
|
2016-11-21 23:15:41 +01:00
|
|
|
|
2017-12-19 15:54:30 +01:00
|
|
|
if (!m->bus || sd_bus_is_ready(m->bus) <= 0) {
|
|
|
|
log_info("Not connected to system bus, not setting hostname.");
|
2016-11-21 23:15:41 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_bus_call_method_async(
|
|
|
|
m->bus,
|
|
|
|
NULL,
|
|
|
|
"org.freedesktop.hostname1",
|
|
|
|
"/org/freedesktop/hostname1",
|
|
|
|
"org.freedesktop.hostname1",
|
|
|
|
"SetHostname",
|
|
|
|
set_hostname_handler,
|
|
|
|
m,
|
|
|
|
"sb",
|
|
|
|
hostname,
|
|
|
|
false);
|
|
|
|
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Could not set transient hostname: %m");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int set_timezone_handler(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
|
|
|
|
Manager *manager = userdata;
|
|
|
|
const sd_bus_error *e;
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
assert(manager);
|
|
|
|
|
|
|
|
e = sd_bus_message_get_error(m);
|
|
|
|
if (e)
|
|
|
|
log_warning_errno(sd_bus_error_get_errno(e), "Could not set timezone: %s", e->message);
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int manager_set_timezone(Manager *m, const char *tz) {
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
assert(tz);
|
|
|
|
|
|
|
|
log_debug("Setting system timezone: '%s'", tz);
|
2016-11-22 08:36:20 +01:00
|
|
|
if (free_and_strdup(&m->dynamic_timezone, tz) < 0)
|
|
|
|
return log_oom();
|
2016-11-21 23:15:41 +01:00
|
|
|
|
2017-12-19 15:54:30 +01:00
|
|
|
if (!m->bus || sd_bus_is_ready(m->bus) <= 0) {
|
2018-04-04 17:33:22 +02:00
|
|
|
log_info("Not connected to system bus, not setting timezone.");
|
2016-11-21 23:15:41 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_bus_call_method_async(
|
|
|
|
m->bus,
|
|
|
|
NULL,
|
|
|
|
"org.freedesktop.timedate1",
|
|
|
|
"/org/freedesktop/timedate1",
|
|
|
|
"org.freedesktop.timedate1",
|
|
|
|
"SetTimezone",
|
|
|
|
set_timezone_handler,
|
|
|
|
m,
|
|
|
|
"sb",
|
|
|
|
tz,
|
|
|
|
false);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Could not set timezone: %m");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|