2020-11-09 05:23:58 +01:00
|
|
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
2013-10-17 03:18:36 +02:00
|
|
|
|
2019-05-09 02:33:45 +02:00
|
|
|
#include <netinet/in.h>
|
2014-05-18 22:10:48 +02:00
|
|
|
#include <sys/socket.h>
|
2019-05-09 02:33:45 +02:00
|
|
|
#include <unistd.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>
|
2019-10-04 21:40:51 +02:00
|
|
|
#include <linux/nexthop.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"
|
2020-11-24 07:58:04 +01:00
|
|
|
#include "bus-error.h"
|
2020-04-21 10:34:05 +02:00
|
|
|
#include "bus-log-control-api.h"
|
2020-01-22 11:39:22 +01:00
|
|
|
#include "bus-polkit.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"
|
2019-03-09 02:37:12 +01:00
|
|
|
#include "device-private.h"
|
2018-10-31 04:35:25 +01:00
|
|
|
#include "device-util.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"
|
2020-09-15 19:58:44 +02:00
|
|
|
#include "firewall-util.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"
|
2019-01-02 14:30:24 +01:00
|
|
|
#include "network-internal.h"
|
2020-10-02 07:46:29 +02:00
|
|
|
#include "networkd-address-pool.h"
|
2020-05-22 11:56:59 +02:00
|
|
|
#include "networkd-dhcp-server-bus.h"
|
2019-06-29 20:57:47 +02:00
|
|
|
#include "networkd-dhcp6.h"
|
2019-05-26 22:35:02 +02:00
|
|
|
#include "networkd-link-bus.h"
|
2019-07-02 16:26:03 +02:00
|
|
|
#include "networkd-manager-bus.h"
|
2016-11-13 04:59:06 +01:00
|
|
|
#include "networkd-manager.h"
|
2020-09-29 17:17:22 +02:00
|
|
|
#include "networkd-neighbor.h"
|
2019-06-29 22:10:35 +02:00
|
|
|
#include "networkd-network-bus.h"
|
2020-09-29 10:47:28 +02:00
|
|
|
#include "networkd-nexthop.h"
|
2020-09-29 08:29:56 +02:00
|
|
|
#include "networkd-routing-policy-rule.h"
|
2019-05-24 22:08:13 +02:00
|
|
|
#include "networkd-speed-meter.h"
|
2016-01-25 20:31:11 +01:00
|
|
|
#include "ordered-set.h"
|
2020-03-24 17:02:11 +01:00
|
|
|
#include "path-lookup.h"
|
2015-10-24 22:58:24 +02:00
|
|
|
#include "path-util.h"
|
2020-10-28 17:41:49 +01:00
|
|
|
#include "selinux-util.h"
|
2015-10-24 22:58:24 +02:00
|
|
|
#include "set.h"
|
2019-10-01 16:23:19 +02:00
|
|
|
#include "signal-util.h"
|
2020-09-08 16:26:28 +02:00
|
|
|
#include "stat-util.h"
|
2018-10-31 04:35:25 +01:00
|
|
|
#include "strv.h"
|
2019-02-18 07:00:15 +01:00
|
|
|
#include "sysctl-util.h"
|
2018-11-30 21:05:27 +01:00
|
|
|
#include "tmpfile-util.h"
|
2019-03-04 04:19:05 +01:00
|
|
|
#include "udev-util.h"
|
2014-04-15 14:21:44 +02:00
|
|
|
|
2019-12-26 07:29:26 +01:00
|
|
|
/* use 128 MB for receive socket kernel queue. */
|
|
|
|
#define RCVBUF_SIZE (128*1024*1024)
|
2014-11-27 18:50:48 +01:00
|
|
|
|
2015-02-03 15:44:12 +01:00
|
|
|
static int manager_reset_all(Manager *m) {
|
|
|
|
Link *link;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
|
2020-09-08 11:58:29 +02:00
|
|
|
HASHMAP_FOREACH(link, m->links) {
|
2015-02-03 15:44:12 +01:00
|
|
|
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) {
|
2020-07-11 12:13:01 +02:00
|
|
|
bus_log_parse_error(r);
|
2015-02-03 15:44:12 +01:00
|
|
|
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);
|
2018-07-02 20:19:15 +02:00
|
|
|
if (m->links_requesting_uuid)
|
|
|
|
(void) manager_request_product_uuid(m, NULL);
|
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");
|
|
|
|
|
2020-05-22 11:56:59 +02:00
|
|
|
r = sd_bus_add_fallback_vtable(m->bus, NULL, "/org/freedesktop/network1/link", "org.freedesktop.network1.DHCPServer", dhcp_server_vtable, link_object_find, m);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to add link object vtable: %m");
|
|
|
|
|
2015-02-04 11:44:37 +01:00
|
|
|
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
|
|
|
|
2020-04-21 10:34:05 +02:00
|
|
|
r = bus_log_control_api_register(m->bus);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
Revert "network: set DynamicUser= to systemd-networkd.service"
This reverts commit d4e9e574ea0b5d23598a317e68399584d229568b.
(systemd.conf.m4 part was already reverted in 5b5d82615011b9827466b7cd5756da35627a1608.)
Together those reverts should "fix" #10025 and #10011. ("fix" is in quotes
because this doesn't really fix the underlying issue, which is combining
DynamicUser= with strict container sandbox, but it avoids the problem by not
using that feature in our default installation.)
Dynamic users don't work well if the service requires matching configuration in
other places, for example dbus policy. This is true for those three services.
In effect, distros create the user statically [1, 2]. Dynamic users make more
sense for "add-on" services where not creating the user, or more precisely,
creating the user lazily, can save resources. For "basic" services, if we are
going to create the user on package installation anyway, setting DynamicUser=
just creates unneeded confusion. The only case where it is actually used is
when somebody forgets to do system configuration. But it's better to have the
service fail cleanly in this case too. If we want to turn on some side-effect
of DynamicUser=yes for those services, we should just do that directly through
fine-grained options. By not using DynamicUser= we also avoid the need to
restart dbus.
[1] https://salsa.debian.org/systemd-team/systemd/commit/bd9bf307274faca24699c0c2d67cb86f18c0b2cb
[2] https://src.fedoraproject.org/rpms/systemd/blob/48ac1cebdedb055d9daf3dfe28c7bde80103f7a1/f/systemd.spec#_473
(Fedora does not create systemd-timesync user.)
2018-09-19 10:06:09 +02:00
|
|
|
r = sd_bus_request_name_async(m->bus, NULL, "org.freedesktop.network1", 0, NULL, 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,
|
2018-07-17 05:36:02 +02:00
|
|
|
NULL,
|
2017-12-19 15:54:30 +01:00
|
|
|
"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,
|
2018-07-17 05:36:02 +02:00
|
|
|
NULL,
|
2017-12-19 15:54:30 +01:00
|
|
|
"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;
|
|
|
|
}
|
|
|
|
|
2018-10-08 15:47:10 +02:00
|
|
|
static int manager_udev_process_link(sd_device_monitor *monitor, sd_device *device, void *userdata) {
|
|
|
|
Manager *m = userdata;
|
2019-03-09 02:37:12 +01:00
|
|
|
DeviceAction action;
|
2015-02-03 15:44:50 +01:00
|
|
|
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
|
|
|
|
2019-03-09 02:37:12 +01:00
|
|
|
r = device_get_action(device, &action);
|
2018-10-31 04:35:25 +01:00
|
|
|
if (r < 0) {
|
2019-03-09 02:37:12 +01:00
|
|
|
log_device_debug_errno(device, r, "Failed to get udev action, ignoring device: %m");
|
2015-02-03 15:44:50 +01:00
|
|
|
return 0;
|
2018-10-31 04:35:25 +01:00
|
|
|
}
|
|
|
|
|
2018-12-12 21:32:29 +01:00
|
|
|
/* Ignore the "remove" uevent — let's remove a device only if rtnetlink says so. All other uevents
|
|
|
|
* are "positive" events in some form, i.e. inform us about a changed or new network interface, that
|
|
|
|
* still exists — and we are interested in that. */
|
|
|
|
if (action == DEVICE_ACTION_REMOVE)
|
2018-10-31 04:35:25 +01:00
|
|
|
return 0;
|
2015-02-01 22:13:26 +01:00
|
|
|
|
2018-08-22 07:30:49 +02:00
|
|
|
r = sd_device_get_ifindex(device, &ifindex);
|
2018-10-25 03:09:19 +02:00
|
|
|
if (r < 0) {
|
2018-12-12 21:32:29 +01:00
|
|
|
log_device_debug_errno(device, r, "Ignoring udev %s event for device without ifindex or with invalid ifindex: %m",
|
|
|
|
device_action_to_string(action));
|
2015-02-03 15:44:50 +01:00
|
|
|
return 0;
|
2015-02-01 22:13:26 +01:00
|
|
|
}
|
|
|
|
|
2019-03-04 04:19:05 +01:00
|
|
|
r = device_is_renaming(device);
|
|
|
|
if (r < 0) {
|
2019-03-09 02:37:12 +01:00
|
|
|
log_device_error_errno(device, r, "Failed to determine the device is renamed or not, ignoring '%s' uevent: %m",
|
|
|
|
device_action_to_string(action));
|
2019-03-04 04:19:05 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (r > 0) {
|
2020-07-21 03:33:57 +02:00
|
|
|
log_device_debug(device, "Interface is under renaming, wait for the interface to be renamed.");
|
2019-03-04 04:19:05 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-02-03 15:44:50 +01:00
|
|
|
r = link_get(m, ifindex, &link);
|
2018-10-08 15:47:10 +02:00
|
|
|
if (r < 0) {
|
|
|
|
if (r != -ENODEV)
|
|
|
|
log_debug_errno(r, "Failed to get link from ifindex %i, ignoring: %m", ifindex);
|
2015-02-03 15:44:50 +01:00
|
|
|
return 0;
|
2018-10-08 15:47:10 +02:00
|
|
|
}
|
2013-11-24 23:37:56 +01:00
|
|
|
|
2018-10-08 15:47:10 +02:00
|
|
|
(void) link_initialized(link, device);
|
2017-12-21 19:07:23 +01:00
|
|
|
|
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
|
|
|
|
2020-09-08 16:26:28 +02:00
|
|
|
/* udev does not initialize devices inside containers, so we rely on them being already
|
|
|
|
* initialized before entering the container. */
|
|
|
|
if (path_is_read_only_fs("/sys") > 0)
|
2015-02-03 15:44:50 +01:00
|
|
|
return 0;
|
2013-10-17 03:18:36 +02:00
|
|
|
|
2018-10-08 15:47:10 +02:00
|
|
|
r = sd_device_monitor_new(&m->device_monitor);
|
2013-11-24 23:37:56 +01:00
|
|
|
if (r < 0)
|
2018-10-08 15:47:10 +02:00
|
|
|
return log_error_errno(r, "Failed to initialize device monitor: %m");
|
2013-11-24 23:37:56 +01:00
|
|
|
|
2020-09-08 16:28:22 +02:00
|
|
|
r = sd_device_monitor_set_receive_buffer_size(m->device_monitor, RCVBUF_SIZE);
|
|
|
|
if (r < 0)
|
|
|
|
log_warning_errno(r, "Failed to increase buffer size for device monitor, ignoring: %m");
|
|
|
|
|
2018-10-08 15:47:10 +02:00
|
|
|
r = sd_device_monitor_filter_add_match_subsystem_devtype(m->device_monitor, "net", NULL);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Could not add device monitor filter: %m");
|
2014-04-15 14:21:44 +02:00
|
|
|
|
2018-11-10 14:50:11 +01:00
|
|
|
r = sd_device_monitor_attach_event(m->device_monitor, m->event);
|
2015-02-03 15:44:50 +01:00
|
|
|
if (r < 0)
|
2018-10-08 15:47:10 +02:00
|
|
|
return log_error_errno(r, "Failed to attach event to device monitor: %m");
|
2014-04-15 14:21:44 +02:00
|
|
|
|
2018-11-10 14:50:11 +01:00
|
|
|
r = sd_device_monitor_start(m->device_monitor, manager_udev_process_link, m);
|
2014-04-15 14:21:44 +02:00
|
|
|
if (r < 0)
|
2018-10-08 15:47:10 +02:00
|
|
|
return log_error_errno(r, "Failed to start device monitor: %m");
|
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
|
|
|
|
2020-09-29 09:20:00 +02:00
|
|
|
static int manager_rtnl_process_link(sd_netlink *rtnl, sd_netlink_message *message, Manager *m) {
|
2014-04-15 14:21:44 +02:00
|
|
|
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)
|
2019-11-30 07:54:07 +01:00
|
|
|
log_message_warning_errno(message, r, "rtnl: Could not receive link message, ignoring");
|
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)) {
|
2019-06-25 09:42:34 +02:00
|
|
|
log_warning("rtnl: Received unexpected message type %u when processing link, ignoring.", type);
|
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) {
|
2019-06-25 09:42:34 +02:00
|
|
|
log_warning_errno(r, "rtnl: Could not get ifindex from link message, ignoring: %m");
|
2014-12-08 19:54:06 +01:00
|
|
|
return 0;
|
|
|
|
} else if (ifindex <= 0) {
|
2019-06-25 09:42:34 +02: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) {
|
2019-06-25 09:42:34 +02:00
|
|
|
log_warning_errno(r, "Could not process new link message, 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) {
|
2019-06-25 09:42:34 +02:00
|
|
|
log_warning_errno(r, "Could not process new link message for 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) {
|
2019-06-25 09:42:34 +02:00
|
|
|
log_warning_errno(r, "Could not process link message, 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:
|
2019-06-25 09:42:34 +02:00
|
|
|
assert_not_reached("Received link message with invalid RTNL message type.");
|
2014-05-08 18:55:11 +02:00
|
|
|
}
|
2014-04-15 14:21:44 +02:00
|
|
|
|
|
|
|
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)
|
2020-09-08 19:48:25 +02:00
|
|
|
log_warning_errno(r, "Failed to increase receive buffer size for general netlink socket, ignoring: %m");
|
2017-12-18 15:17:06 +01:00
|
|
|
|
|
|
|
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;
|
|
|
|
|
2020-09-08 17:33:11 +02:00
|
|
|
/* Bump receiver buffer, but only if we are not called via socket activation, as in that
|
|
|
|
* case systemd sets the receive buffer size for us, and the value in the .socket unit
|
|
|
|
* should take full effect. */
|
|
|
|
if (fd < 0) {
|
|
|
|
r = sd_netlink_inc_rcvbuf(m->rtnl, RCVBUF_SIZE);
|
|
|
|
if (r < 0)
|
|
|
|
log_warning_errno(r, "Failed to increase receive buffer size for rtnl socket, ignoring: %m");
|
|
|
|
}
|
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
|
|
|
|
2020-09-29 09:20:00 +02:00
|
|
|
r = netlink_add_match(m->rtnl, NULL, RTM_NEWLINK, &manager_rtnl_process_link, NULL, m, "network-rtnl_process_link");
|
2015-02-03 15:44:50 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2014-04-15 14:21:44 +02:00
|
|
|
|
2020-09-29 09:20:00 +02:00
|
|
|
r = netlink_add_match(m->rtnl, NULL, RTM_DELLINK, &manager_rtnl_process_link, NULL, m, "network-rtnl_process_link");
|
2015-02-03 15:44:50 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2014-12-08 19:54:06 +01:00
|
|
|
|
2020-09-29 09:20:00 +02:00
|
|
|
r = netlink_add_match(m->rtnl, NULL, RTM_NEWADDR, &manager_rtnl_process_address, NULL, m, "network-rtnl_process_address");
|
2015-02-03 15:44:50 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2020-09-29 09:20:00 +02:00
|
|
|
r = netlink_add_match(m->rtnl, NULL, RTM_DELADDR, &manager_rtnl_process_address, NULL, m, "network-rtnl_process_address");
|
2015-02-03 15:44:50 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2020-09-29 09:20:00 +02:00
|
|
|
r = netlink_add_match(m->rtnl, NULL, RTM_NEWNEIGH, &manager_rtnl_process_neighbor, NULL, m, "network-rtnl_process_neighbor");
|
2019-04-19 09:53:34 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2020-09-29 09:20:00 +02:00
|
|
|
r = netlink_add_match(m->rtnl, NULL, RTM_DELNEIGH, &manager_rtnl_process_neighbor, NULL, m, "network-rtnl_process_neighbor");
|
2019-04-19 09:53:34 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2020-09-29 09:20:00 +02:00
|
|
|
r = netlink_add_match(m->rtnl, NULL, RTM_NEWROUTE, &manager_rtnl_process_route, NULL, m, "network-rtnl_process_route");
|
2015-10-25 14:46:21 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2020-09-29 09:20:00 +02:00
|
|
|
r = netlink_add_match(m->rtnl, NULL, RTM_DELROUTE, &manager_rtnl_process_route, NULL, m, "network-rtnl_process_route");
|
2015-10-25 14:46:21 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2020-09-29 09:20:00 +02:00
|
|
|
r = netlink_add_match(m->rtnl, NULL, RTM_NEWRULE, &manager_rtnl_process_rule, NULL, m, "network-rtnl_process_rule");
|
2017-09-14 21:51:39 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2020-09-29 09:20:00 +02:00
|
|
|
r = netlink_add_match(m->rtnl, NULL, RTM_DELRULE, &manager_rtnl_process_rule, NULL, m, "network-rtnl_process_rule");
|
2017-09-14 21:51:39 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2020-09-29 09:20:00 +02:00
|
|
|
r = netlink_add_match(m->rtnl, NULL, RTM_NEWNEXTHOP, &manager_rtnl_process_nexthop, NULL, m, "network-rtnl_process_nexthop");
|
2019-10-04 21:40:51 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2020-09-29 09:20:00 +02:00
|
|
|
r = netlink_add_match(m->rtnl, NULL, RTM_DELNEXTHOP, &manager_rtnl_process_nexthop, NULL, m, "network-rtnl_process_nexthop");
|
2019-10-04 21:40:51 +02:00
|
|
|
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
|
|
|
|
2020-07-03 11:34:37 +02:00
|
|
|
static int ordered_set_put_dns_server(OrderedSet *s, int ifindex, struct in_addr_full *dns) {
|
2020-07-03 09:48:29 +02:00
|
|
|
const char *p;
|
2015-09-30 18:17:43 +02:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(s);
|
2020-07-03 09:48:29 +02:00
|
|
|
assert(dns);
|
2016-11-18 17:04:26 +01:00
|
|
|
|
2020-07-03 11:34:37 +02:00
|
|
|
if (dns->ifindex != 0 && dns->ifindex != ifindex)
|
|
|
|
return 0;
|
|
|
|
|
2020-07-03 09:48:29 +02:00
|
|
|
p = in_addr_full_to_string(dns);
|
|
|
|
if (!p)
|
|
|
|
return 0;
|
2016-11-18 17:04:26 +01:00
|
|
|
|
2020-07-03 09:48:29 +02:00
|
|
|
r = ordered_set_put_strdup(s, p);
|
2016-11-18 17:04:26 +01:00
|
|
|
if (r == -EEXIST)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2020-07-03 11:34:37 +02:00
|
|
|
static int ordered_set_put_dns_servers(OrderedSet *s, int ifindex, struct in_addr_full **dns, unsigned n) {
|
2016-11-18 17:04:26 +01:00
|
|
|
int r, c = 0;
|
|
|
|
unsigned i;
|
|
|
|
|
|
|
|
assert(s);
|
2020-07-03 09:48:29 +02:00
|
|
|
assert(dns || n == 0);
|
2016-11-18 17:04:26 +01:00
|
|
|
|
|
|
|
for (i = 0; i < n; i++) {
|
2020-07-03 11:34:37 +02:00
|
|
|
r = ordered_set_put_dns_server(s, ifindex, dns[i]);
|
2016-11-18 17:04:26 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2018-12-14 16:25:01 +01:00
|
|
|
static int ordered_set_put_in4_addrv(OrderedSet *s,
|
|
|
|
const struct in_addr *addresses,
|
|
|
|
size_t n,
|
|
|
|
bool (*predicate)(const struct in_addr *addr)) {
|
2016-11-18 17:04:26 +01:00
|
|
|
int r, c = 0;
|
2018-12-14 16:25:01 +01:00
|
|
|
size_t 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++) {
|
2018-12-14 16:25:01 +01:00
|
|
|
if (predicate && !predicate(&addresses[i]))
|
|
|
|
continue;
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int manager_save(Manager *m) {
|
2020-06-16 20:35:18 +02:00
|
|
|
_cleanup_ordered_set_free_free_ OrderedSet *dns = NULL, *ntp = NULL, *sip = NULL, *search_domains = NULL, *route_domains = NULL;
|
2019-09-18 15:22:47 +02:00
|
|
|
const char *operstate_str, *carrier_state_str, *address_state_str;
|
2015-09-30 18:17:43 +02:00
|
|
|
LinkOperationalState operstate = LINK_OPERSTATE_OFF;
|
2019-06-09 22:22:25 +02:00
|
|
|
LinkCarrierState carrier_state = LINK_CARRIER_STATE_OFF;
|
|
|
|
LinkAddressState address_state = LINK_ADDRESS_STATE_OFF;
|
2019-09-18 15:22:47 +02:00
|
|
|
_cleanup_free_ char *temp_path = NULL;
|
|
|
|
_cleanup_strv_free_ char **p = NULL;
|
|
|
|
_cleanup_fclose_ FILE *f = NULL;
|
|
|
|
Link *link;
|
2015-09-30 18:17:43 +02:00
|
|
|
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;
|
|
|
|
|
2020-03-27 21:12:07 +01:00
|
|
|
sip = ordered_set_new(&string_hash_ops);
|
|
|
|
if (!sip)
|
2019-09-18 15:22:47 +02:00
|
|
|
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;
|
|
|
|
|
2020-09-08 11:58:29 +02:00
|
|
|
HASHMAP_FOREACH(link, m->links) {
|
2020-06-16 20:35:18 +02:00
|
|
|
const struct in_addr *addresses;
|
|
|
|
|
2015-09-30 18:17:43 +02:00
|
|
|
if (link->flags & IFF_LOOPBACK)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (link->operstate > operstate)
|
|
|
|
operstate = link->operstate;
|
|
|
|
|
2019-06-09 22:22:25 +02:00
|
|
|
if (link->carrier_state > carrier_state)
|
|
|
|
carrier_state = link->carrier_state;
|
|
|
|
|
|
|
|
if (link->address_state > address_state)
|
|
|
|
address_state = link->address_state;
|
|
|
|
|
2015-09-30 18:17:43 +02:00
|
|
|
if (!link->network)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* First add the static configured entries */
|
2020-07-03 11:34:37 +02:00
|
|
|
if (link->n_dns != (unsigned) -1)
|
|
|
|
r = ordered_set_put_dns_servers(dns, link->ifindex, link->dns, link->n_dns);
|
|
|
|
else
|
|
|
|
r = ordered_set_put_dns_servers(dns, link->ifindex, link->network->dns, link->network->n_dns);
|
2015-09-30 18:17:43 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2019-05-27 01:52:27 +02:00
|
|
|
r = ordered_set_put_strdupv(ntp, link->ntp ?: link->network->ntp);
|
2015-09-30 18:17:43 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2019-05-27 01:52:27 +02:00
|
|
|
r = ordered_set_put_string_set(search_domains, link->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;
|
|
|
|
|
2019-05-27 01:52:27 +02:00
|
|
|
r = ordered_set_put_string_set(route_domains, link->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
|
|
|
r = sd_dhcp_lease_get_dns(link->dhcp_lease, &addresses);
|
|
|
|
if (r > 0) {
|
2018-12-14 16:25:01 +01:00
|
|
|
r = ordered_set_put_in4_addrv(dns, addresses, r, in4_addr_is_non_local);
|
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
|
|
|
r = sd_dhcp_lease_get_ntp(link->dhcp_lease, &addresses);
|
|
|
|
if (r > 0) {
|
2018-12-14 16:25:01 +01:00
|
|
|
r = ordered_set_put_in4_addrv(ntp, addresses, r, in4_addr_is_non_local);
|
2015-09-30 18:17:43 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
} else if (r < 0 && r != -ENODATA)
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2019-09-18 15:22:47 +02:00
|
|
|
if (link->network->dhcp_use_sip) {
|
|
|
|
r = sd_dhcp_lease_get_sip(link->dhcp_lease, &addresses);
|
|
|
|
if (r > 0) {
|
|
|
|
r = ordered_set_put_in4_addrv(sip, addresses, r, in4_addr_is_non_local);
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-09 22:22:25 +02:00
|
|
|
if (carrier_state >= LINK_CARRIER_STATE_ENSLAVED)
|
|
|
|
carrier_state = LINK_CARRIER_STATE_CARRIER;
|
|
|
|
|
2015-09-30 18:17:43 +02:00
|
|
|
operstate_str = link_operstate_to_string(operstate);
|
|
|
|
assert(operstate_str);
|
|
|
|
|
2019-06-09 21:56:03 +02:00
|
|
|
carrier_state_str = link_carrier_state_to_string(carrier_state);
|
|
|
|
assert(carrier_state_str);
|
|
|
|
|
|
|
|
address_state_str = link_address_state_to_string(address_state);
|
|
|
|
assert(address_state_str);
|
|
|
|
|
2015-09-30 18:17:43 +02:00
|
|
|
r = fopen_temporary(m->state_file, &f, &temp_path);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
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"
|
2019-06-09 21:56:03 +02:00
|
|
|
"OPER_STATE=%s\n"
|
|
|
|
"CARRIER_STATE=%s\n"
|
|
|
|
"ADDRESS_STATE=%s\n",
|
|
|
|
operstate_str, carrier_state_str, address_state_str);
|
2015-09-30 18:17:43 +02:00
|
|
|
|
2019-02-20 22:39:47 +01:00
|
|
|
ordered_set_print(f, "DNS=", dns);
|
|
|
|
ordered_set_print(f, "NTP=", ntp);
|
2019-09-18 15:22:47 +02:00
|
|
|
ordered_set_print(f, "SIP=", sip);
|
2019-02-20 22:39:47 +01:00
|
|
|
ordered_set_print(f, "DOMAINS=", search_domains);
|
|
|
|
ordered_set_print(f, "ROUTE_DOMAINS=", route_domains);
|
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;
|
2019-06-09 22:22:25 +02:00
|
|
|
if (strv_extend(&p, "OperationalState") < 0)
|
|
|
|
log_oom();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m->carrier_state != carrier_state) {
|
|
|
|
m->carrier_state = carrier_state;
|
|
|
|
if (strv_extend(&p, "CarrierState") < 0)
|
|
|
|
log_oom();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m->address_state != address_state) {
|
|
|
|
m->address_state = address_state;
|
|
|
|
if (strv_extend(&p, "AddressState") < 0)
|
|
|
|
log_oom();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (p) {
|
|
|
|
r = manager_send_changed_strv(m, p);
|
2015-09-30 18:17:43 +02:00
|
|
|
if (r < 0)
|
2019-06-09 22:22:25 +02:00
|
|
|
log_error_errno(r, "Could not emit changed properties: %m");
|
2015-09-30 18:17:43 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
|
|
|
|
if (m->dirty)
|
|
|
|
manager_save(m);
|
|
|
|
|
2020-09-08 11:58:29 +02:00
|
|
|
SET_FOREACH(link, m->dirty_links)
|
2020-07-20 22:21:28 +02:00
|
|
|
(void) link_save_and_clean(link);
|
2015-09-30 18:17:43 +02:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2019-10-01 16:23:19 +02:00
|
|
|
static int signal_terminate_callback(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
|
|
|
|
Manager *m = userdata;
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
m->restarting = false;
|
|
|
|
|
|
|
|
log_debug("Terminate operation initiated.");
|
|
|
|
|
|
|
|
return sd_event_exit(sd_event_source_get_event(s), 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int signal_restart_callback(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
|
|
|
|
Manager *m = userdata;
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
m->restarting = true;
|
|
|
|
|
|
|
|
log_debug("Restart operation initiated.");
|
|
|
|
|
|
|
|
return sd_event_exit(sd_event_source_get_event(s), 0);
|
|
|
|
}
|
|
|
|
|
2018-07-18 05:37:50 +02:00
|
|
|
int manager_new(Manager **ret) {
|
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
|
|
|
|
2019-05-24 22:08:13 +02:00
|
|
|
m = new(Manager, 1);
|
2015-02-03 15:44:50 +01:00
|
|
|
if (!m)
|
|
|
|
return -ENOMEM;
|
2014-12-08 19:54:06 +01:00
|
|
|
|
2019-05-24 22:08:13 +02:00
|
|
|
*m = (Manager) {
|
|
|
|
.speed_meter_interval_usec = SPEED_METER_DEFAULT_TIME_INTERVAL,
|
2020-02-11 13:35:11 +01:00
|
|
|
.manage_foreign_routes = true,
|
2020-06-03 09:19:29 +02:00
|
|
|
.ethtool_fd = -1,
|
2019-05-24 22:08:13 +02:00
|
|
|
};
|
|
|
|
|
2015-02-03 15:44:50 +01:00
|
|
|
m->state_file = strdup("/run/systemd/netif/state");
|
|
|
|
if (!m->state_file)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2018-07-18 05:37:50 +02:00
|
|
|
r = sd_event_default(&m->event);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2019-10-01 16:23:19 +02:00
|
|
|
assert_se(sigprocmask_many(SIG_SETMASK, NULL, SIGINT, SIGTERM, SIGUSR2, -1) >= 0);
|
|
|
|
|
2018-07-20 04:29:49 +02:00
|
|
|
(void) sd_event_set_watchdog(m->event, true);
|
2019-10-01 16:23:19 +02:00
|
|
|
(void) sd_event_add_signal(m->event, NULL, SIGTERM, signal_terminate_callback, m);
|
|
|
|
(void) sd_event_add_signal(m->event, NULL, SIGINT, signal_terminate_callback, m);
|
|
|
|
(void) sd_event_add_signal(m->event, NULL, SIGUSR2, signal_restart_callback, m);
|
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
|
|
|
|
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;
|
|
|
|
|
2020-10-02 07:15:57 +02:00
|
|
|
r = address_pool_setup_default(m);
|
2015-02-03 15:44:50 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2013-10-17 03:18:36 +02:00
|
|
|
|
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
|
|
|
|
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) {
|
|
|
|
Link *link;
|
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
|
|
|
|
2020-09-08 11:58:29 +02:00
|
|
|
HASHMAP_FOREACH(link, m->links)
|
2020-10-15 00:56:27 +02:00
|
|
|
(void) link_stop_engines(link, true);
|
2019-05-06 16:06:50 +02:00
|
|
|
|
2020-07-22 20:13:42 +02:00
|
|
|
m->dhcp6_prefixes = hashmap_free_with_destructor(m->dhcp6_prefixes, dhcp6_pd_free);
|
|
|
|
m->dhcp6_pd_prefixes = set_free_with_destructor(m->dhcp6_pd_prefixes, dhcp6_pd_free);
|
2013-10-17 03:18:36 +02:00
|
|
|
|
2018-11-04 12:36:13 +01:00
|
|
|
m->dirty_links = set_free_with_destructor(m->dirty_links, link_unref);
|
2019-04-15 09:38:45 +02:00
|
|
|
m->links_requesting_uuid = set_free_with_destructor(m->links_requesting_uuid, link_unref);
|
|
|
|
m->links = hashmap_free_with_destructor(m->links, link_unref);
|
2018-07-02 20:19:15 +02:00
|
|
|
|
2019-04-15 09:38:45 +02:00
|
|
|
m->duids_requesting_uuid = set_free(m->duids_requesting_uuid);
|
2019-05-04 13:02:18 +02:00
|
|
|
m->networks = ordered_hashmap_free_with_destructor(m->networks, network_unref);
|
2015-02-08 13:29:35 +01:00
|
|
|
|
2018-11-04 12:36:13 +01:00
|
|
|
m->netdevs = hashmap_free_with_destructor(m->netdevs, netdev_unref);
|
2015-02-03 15:44:50 +01:00
|
|
|
|
2020-10-02 07:46:29 +02:00
|
|
|
ordered_set_free_free(m->address_pools);
|
2015-02-03 15:44:50 +01:00
|
|
|
|
2018-11-01 12:21:26 +01:00
|
|
|
/* routing_policy_rule_free() access m->rules and m->rules_foreign.
|
|
|
|
* So, it is necessary to set NULL after the sets are freed. */
|
2020-07-22 01:22:55 +02:00
|
|
|
m->rules = set_free(m->rules);
|
|
|
|
m->rules_foreign = set_free(m->rules_foreign);
|
2017-09-14 21:51:39 +02:00
|
|
|
|
2019-05-02 11:52:03 +02:00
|
|
|
sd_netlink_unref(m->rtnl);
|
|
|
|
sd_netlink_unref(m->genl);
|
|
|
|
sd_resolve_unref(m->resolve);
|
|
|
|
|
2020-12-04 12:50:34 +01:00
|
|
|
/* reject (e.g. unreachable) type routes are managed by Manager, but may be referenced by a
|
|
|
|
* link. E.g., DHCP6 with prefix delegation creates unreachable routes, and they are referenced
|
|
|
|
* by the upstream link. And the links may be referenced by netlink slots. Hence, two
|
|
|
|
* set_free() must be called after the above sd_netlink_unref(). */
|
|
|
|
m->routes = set_free(m->routes);
|
|
|
|
m->routes_foreign = set_free(m->routes_foreign);
|
|
|
|
|
2019-05-24 22:08:13 +02:00
|
|
|
sd_event_source_unref(m->speed_meter_event_source);
|
2015-08-27 17:38:05 +02:00
|
|
|
sd_event_unref(m->event);
|
2015-02-03 15:44:50 +01:00
|
|
|
|
2018-10-08 15:47:10 +02:00
|
|
|
sd_device_monitor_unref(m->device_monitor);
|
2015-10-09 21:36:04 +02:00
|
|
|
|
2019-05-27 01:52:27 +02:00
|
|
|
bus_verify_polkit_async_registry_free(m->polkit_registry);
|
2019-01-17 15:53:15 +01:00
|
|
|
sd_bus_flush_close_unref(m->bus);
|
2015-10-09 21:36:04 +02:00
|
|
|
|
2016-11-22 08:36:20 +01:00
|
|
|
free(m->dynamic_timezone);
|
|
|
|
free(m->dynamic_hostname);
|
|
|
|
|
2020-06-03 09:19:29 +02:00
|
|
|
safe_close(m->ethtool_fd);
|
|
|
|
|
2020-09-15 19:58:44 +02:00
|
|
|
m->fw_ctx = fw_ctx_free(m->fw_ctx);
|
|
|
|
|
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;
|
2019-05-24 22:08:13 +02:00
|
|
|
int r;
|
2015-09-30 18:17:43 +02:00
|
|
|
|
2015-02-04 15:00:20 +01:00
|
|
|
assert(m);
|
|
|
|
|
2019-05-24 22:08:13 +02:00
|
|
|
r = manager_start_speed_meter(m);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to initialize speed meter: %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);
|
|
|
|
|
2020-09-08 11:58:29 +02:00
|
|
|
HASHMAP_FOREACH(link, m->links)
|
2020-07-20 22:21:28 +02:00
|
|
|
(void) link_save(link);
|
2015-09-30 18:17:43 +02:00
|
|
|
|
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 */
|
2019-01-02 14:30:24 +01:00
|
|
|
paths_check_timestamp(NETWORK_DIRS, &m->network_dirs_ts_usec, true);
|
2015-02-03 15:44:50 +01:00
|
|
|
|
2019-09-02 14:48:08 +02:00
|
|
|
r = netdev_load(m, false);
|
2013-10-17 03:18:36 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2019-10-23 15:20:48 +02:00
|
|
|
r = network_load(m, &m->networks);
|
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) {
|
2019-01-02 14:30:24 +01:00
|
|
|
return paths_check_timestamp(NETWORK_DIRS, &m->network_dirs_ts_usec, false);
|
2015-02-03 15:44:50 +01:00
|
|
|
}
|
|
|
|
|
2020-09-29 09:44:41 +02:00
|
|
|
static int manager_enumerate_internal(
|
|
|
|
Manager *m,
|
|
|
|
sd_netlink_message *req,
|
|
|
|
int (*process)(sd_netlink *, sd_netlink_message *, Manager *),
|
|
|
|
const char *name) {
|
|
|
|
|
|
|
|
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *reply = NULL;
|
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);
|
2020-09-29 09:44:41 +02:00
|
|
|
assert(req);
|
|
|
|
assert(process);
|
2013-11-14 16:22:51 +01:00
|
|
|
|
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);
|
2020-09-29 09:44:41 +02:00
|
|
|
if (r < 0) {
|
2020-10-28 17:41:49 +01:00
|
|
|
if (name && (r == -EOPNOTSUPP || (r == -EINVAL && mac_selinux_enforcing()))) {
|
2020-09-29 09:44:41 +02:00
|
|
|
log_debug_errno(r, "%s are not supported by the kernel. Ignoring.", name);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-05-08 18:55:11 +02:00
|
|
|
return r;
|
2020-09-29 09:44:41 +02:00
|
|
|
}
|
2014-05-08 18:55:11 +02:00
|
|
|
|
2020-09-29 09:44:41 +02:00
|
|
|
for (sd_netlink_message *reply_one = reply; reply_one; reply_one = sd_netlink_message_next(reply_one)) {
|
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;
|
|
|
|
|
2020-09-29 09:44:41 +02:00
|
|
|
k = process(m->rtnl, reply_one, m);
|
|
|
|
if (k < 0 && r >= 0)
|
2015-02-03 15:44:50 +01:00
|
|
|
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
|
|
|
|
2020-09-29 09:44:41 +02:00
|
|
|
static int manager_enumerate_links(Manager *m) {
|
|
|
|
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
|
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
|
|
|
|
2020-09-29 09:44:41 +02:00
|
|
|
r = sd_rtnl_message_new_link(m->rtnl, &req, RTM_GETLINK, 0);
|
2015-02-03 15:44:50 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2020-09-29 09:44:41 +02:00
|
|
|
return manager_enumerate_internal(m, req, manager_rtnl_process_link, NULL);
|
|
|
|
}
|
2015-02-03 15:44:50 +01:00
|
|
|
|
2020-09-29 09:44:41 +02:00
|
|
|
static int manager_enumerate_addresses(Manager *m) {
|
|
|
|
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
|
|
|
|
int r;
|
2015-02-04 10:08:12 +01:00
|
|
|
|
2020-09-29 09:44:41 +02:00
|
|
|
assert(m);
|
|
|
|
assert(m->rtnl);
|
2015-02-04 10:08:12 +01:00
|
|
|
|
2020-09-29 09:44:41 +02:00
|
|
|
r = sd_rtnl_message_new_addr(m->rtnl, &req, RTM_GETADDR, 0, 0);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2015-02-03 15:44:50 +01:00
|
|
|
|
2020-09-29 09:44:41 +02:00
|
|
|
return manager_enumerate_internal(m, req, manager_rtnl_process_address, NULL);
|
2014-01-13 23:48:28 +01:00
|
|
|
}
|
2019-04-19 09:53:34 +02:00
|
|
|
|
2020-09-29 09:44:41 +02:00
|
|
|
static int manager_enumerate_neighbors(Manager *m) {
|
|
|
|
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
|
2019-04-19 09:53:34 +02:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
assert(m->rtnl);
|
|
|
|
|
|
|
|
r = sd_rtnl_message_new_neigh(m->rtnl, &req, RTM_GETNEIGH, 0, AF_UNSPEC);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2020-09-29 09:44:41 +02:00
|
|
|
return manager_enumerate_internal(m, req, manager_rtnl_process_neighbor, NULL);
|
2019-04-19 09:53:34 +02:00
|
|
|
}
|
2014-01-13 23:48:28 +01:00
|
|
|
|
2020-09-29 09:44:41 +02:00
|
|
|
static int manager_enumerate_routes(Manager *m) {
|
|
|
|
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
|
2015-10-25 14:46:21 +01:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
assert(m->rtnl);
|
|
|
|
|
2020-07-17 22:12:33 +02:00
|
|
|
if (!m->manage_foreign_routes)
|
|
|
|
return 0;
|
|
|
|
|
2015-10-25 14:46:21 +01:00
|
|
|
r = sd_rtnl_message_new_route(m->rtnl, &req, RTM_GETROUTE, 0, 0);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2020-09-29 09:44:41 +02:00
|
|
|
return manager_enumerate_internal(m, req, manager_rtnl_process_route, NULL);
|
2015-10-25 14:46:21 +01:00
|
|
|
}
|
|
|
|
|
2020-09-29 09:44:41 +02:00
|
|
|
static int manager_enumerate_rules(Manager *m) {
|
|
|
|
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
|
2017-09-14 21:51:39 +02:00
|
|
|
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;
|
|
|
|
|
2020-09-29 09:44:41 +02:00
|
|
|
return manager_enumerate_internal(m, req, manager_rtnl_process_rule, "Routing policy rules");
|
2017-09-14 21:51:39 +02:00
|
|
|
}
|
|
|
|
|
2020-09-29 09:44:41 +02:00
|
|
|
static int manager_enumerate_nexthop(Manager *m) {
|
|
|
|
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
|
2019-10-04 21:40:51 +02:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
assert(m->rtnl);
|
|
|
|
|
|
|
|
r = sd_rtnl_message_new_nexthop(m->rtnl, &req, RTM_GETNEXTHOP, 0, 0);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2020-09-29 09:44:41 +02:00
|
|
|
return manager_enumerate_internal(m, req, manager_rtnl_process_nexthop, "Nexthop rules");
|
|
|
|
}
|
2019-10-04 21:40:51 +02:00
|
|
|
|
2020-09-29 09:44:41 +02:00
|
|
|
int manager_enumerate(Manager *m) {
|
|
|
|
int r;
|
2019-10-04 21:40:51 +02:00
|
|
|
|
2020-09-29 09:44:41 +02:00
|
|
|
r = manager_enumerate_links(m);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Could not enumerate links: %m");
|
2019-10-04 21:40:51 +02:00
|
|
|
|
2020-09-29 09:44:41 +02:00
|
|
|
r = manager_enumerate_addresses(m);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Could not enumerate addresses: %m");
|
2019-10-04 21:40:51 +02:00
|
|
|
|
2020-09-29 09:44:41 +02:00
|
|
|
r = manager_enumerate_neighbors(m);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Could not enumerate neighbors: %m");
|
2019-10-04 21:40:51 +02:00
|
|
|
|
2020-09-29 09:44:41 +02:00
|
|
|
r = manager_enumerate_routes(m);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Could not enumerate routes: %m");
|
2019-10-04 21:40:51 +02:00
|
|
|
|
2020-09-29 09:44:41 +02:00
|
|
|
r = manager_enumerate_rules(m);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Could not enumerate routing policy rules: %m");
|
2019-10-04 21:40:51 +02:00
|
|
|
|
2020-09-29 09:44:41 +02:00
|
|
|
r = manager_enumerate_nexthop(m);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Could not enumerate nexthop rules: %m");
|
|
|
|
|
|
|
|
return 0;
|
2019-10-04 21:40:51 +02:00
|
|
|
}
|
|
|
|
|
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) {
|
|
|
|
const sd_bus_error *e;
|
2020-11-24 07:58:04 +01:00
|
|
|
int r;
|
2016-11-21 23:15:41 +01:00
|
|
|
|
|
|
|
assert(m);
|
|
|
|
|
|
|
|
e = sd_bus_message_get_error(m);
|
2020-11-24 07:58:04 +01:00
|
|
|
if (e) {
|
|
|
|
r = sd_bus_error_get_errno(e);
|
|
|
|
log_warning_errno(r, "Could not set hostname: %s", bus_error_message(e, r));
|
|
|
|
}
|
2016-11-21 23:15:41 +01:00
|
|
|
|
|
|
|
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) {
|
2018-07-23 20:22:28 +02:00
|
|
|
log_debug("Not connected to system bus, setting hostname later.");
|
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) {
|
|
|
|
const sd_bus_error *e;
|
2020-11-24 07:58:04 +01:00
|
|
|
int r;
|
2016-11-21 23:15:41 +01:00
|
|
|
|
|
|
|
assert(m);
|
|
|
|
|
|
|
|
e = sd_bus_message_get_error(m);
|
2020-11-24 07:58:04 +01:00
|
|
|
if (e) {
|
|
|
|
r = sd_bus_error_get_errno(e);
|
|
|
|
log_warning_errno(r, "Could not set timezone: %s", bus_error_message(e, r));
|
|
|
|
}
|
2016-11-21 23:15:41 +01:00
|
|
|
|
|
|
|
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-07-23 20:22:28 +02:00
|
|
|
log_debug("Not connected to system bus, setting timezone later.");
|
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;
|
|
|
|
}
|