mirror of
https://github.com/systemd/systemd.git
synced 2025-03-09 12:58:26 +03:00
network/tuntap: save tun or tap file descriptor in fd store
This commit is contained in:
parent
f8b7c17764
commit
af7a86b8a6
@ -237,6 +237,9 @@ void netdev_drop(NetDev *netdev) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (NETDEV_VTABLE(netdev) && NETDEV_VTABLE(netdev)->drop)
|
||||
NETDEV_VTABLE(netdev)->drop(netdev);
|
||||
|
||||
netdev->state = NETDEV_STATE_LINGER;
|
||||
|
||||
log_netdev_debug(netdev, "netdev removed");
|
||||
|
@ -142,6 +142,9 @@ typedef struct NetDevVTable {
|
||||
* to be set != 0. */
|
||||
void (*init)(NetDev *n);
|
||||
|
||||
/* This is called when the interface is removed. */
|
||||
void (*drop)(NetDev *n);
|
||||
|
||||
/* This should free all kind-specific variables. It should be
|
||||
* idempotent. */
|
||||
void (*done)(NetDev *n);
|
||||
|
@ -10,7 +10,11 @@
|
||||
#include <linux/if_tun.h>
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "daemon-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "networkd-link.h"
|
||||
#include "networkd-manager.h"
|
||||
#include "socket-util.h"
|
||||
#include "tuntap.h"
|
||||
#include "user-util.h"
|
||||
|
||||
@ -29,6 +33,73 @@ static TunTap* TUNTAP(NetDev *netdev) {
|
||||
}
|
||||
}
|
||||
|
||||
static void *close_fd_ptr(void *p) {
|
||||
safe_close(PTR_TO_FD(p));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DEFINE_PRIVATE_HASH_OPS_FULL(named_fd_hash_ops, char, string_hash_func, string_compare_func, free, void, close_fd_ptr);
|
||||
|
||||
int manager_add_tuntap_fd(Manager *m, int fd, const char *name) {
|
||||
_cleanup_free_ char *tuntap_name = NULL;
|
||||
const char *p;
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
assert(fd >= 0);
|
||||
assert(name);
|
||||
|
||||
p = startswith(name, "tuntap-");
|
||||
if (!p)
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Received unknown fd (%s).", name);
|
||||
|
||||
if (!ifname_valid(p))
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Received tuntap fd with invalid name (%s).", p);
|
||||
|
||||
tuntap_name = strdup(p);
|
||||
if (!tuntap_name)
|
||||
return log_oom_debug();
|
||||
|
||||
r = hashmap_ensure_put(&m->tuntap_fds_by_name, &named_fd_hash_ops, tuntap_name, FD_TO_PTR(fd));
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to store tuntap fd: %m");
|
||||
|
||||
TAKE_PTR(tuntap_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void manager_clear_unmanaged_tuntap_fds(Manager *m) {
|
||||
char *name;
|
||||
void *p;
|
||||
|
||||
assert(m);
|
||||
|
||||
while ((p = hashmap_steal_first_key_and_value(m->tuntap_fds_by_name, (void**) &name))) {
|
||||
close_and_notify_warn(PTR_TO_FD(p), name);
|
||||
name = mfree(name);
|
||||
}
|
||||
}
|
||||
|
||||
static int tuntap_take_fd(NetDev *netdev) {
|
||||
_cleanup_free_ char *name = NULL;
|
||||
void *p;
|
||||
int r;
|
||||
|
||||
assert(netdev);
|
||||
assert(netdev->manager);
|
||||
|
||||
r = link_get_by_name(netdev->manager, netdev->ifname, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
p = hashmap_remove2(netdev->manager->tuntap_fds_by_name, netdev->ifname, (void**) &name);
|
||||
if (!p)
|
||||
return -ENOENT;
|
||||
|
||||
log_netdev_debug(netdev, "Found file descriptor in fd store.");
|
||||
return PTR_TO_FD(p);
|
||||
}
|
||||
|
||||
static int netdev_create_tuntap(NetDev *netdev) {
|
||||
_cleanup_close_ int fd = -1;
|
||||
struct ifreq ifr = {};
|
||||
@ -39,7 +110,11 @@ static int netdev_create_tuntap(NetDev *netdev) {
|
||||
t = TUNTAP(netdev);
|
||||
assert(t);
|
||||
|
||||
fd = open(TUN_DEV, O_RDWR|O_CLOEXEC);
|
||||
fd = TAKE_FD(t->fd);
|
||||
if (fd < 0)
|
||||
fd = tuntap_take_fd(netdev);
|
||||
if (fd < 0)
|
||||
fd = open(TUN_DEV, O_RDWR|O_CLOEXEC);
|
||||
if (fd < 0)
|
||||
return log_netdev_error_errno(netdev, errno, "Failed to open " TUN_DEV ": %m");
|
||||
|
||||
@ -90,8 +165,10 @@ static int netdev_create_tuntap(NetDev *netdev) {
|
||||
if (ioctl(fd, TUNSETPERSIST, 1) < 0)
|
||||
return log_netdev_error_errno(netdev, errno, "TUNSETPERSIST failed: %m");
|
||||
|
||||
if (t->keep_fd)
|
||||
if (t->keep_fd) {
|
||||
t->fd = TAKE_FD(fd);
|
||||
(void) notify_push_fdf(t->fd, "tuntap-%s", netdev->ifname);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -106,6 +183,16 @@ static void tuntap_init(NetDev *netdev) {
|
||||
t->fd = -1;
|
||||
}
|
||||
|
||||
static void tuntap_drop(NetDev *netdev) {
|
||||
TunTap *t;
|
||||
|
||||
assert(netdev);
|
||||
t = TUNTAP(netdev);
|
||||
assert(t);
|
||||
|
||||
t->fd = close_and_notify_warn(t->fd, netdev->ifname);
|
||||
}
|
||||
|
||||
static void tuntap_done(NetDev *netdev) {
|
||||
TunTap *t;
|
||||
|
||||
@ -141,6 +228,7 @@ const NetDevVTable tun_vtable = {
|
||||
.sections = NETDEV_COMMON_SECTIONS "Tun\0",
|
||||
.config_verify = tuntap_verify,
|
||||
.init = tuntap_init,
|
||||
.drop = tuntap_drop,
|
||||
.done = tuntap_done,
|
||||
.create = netdev_create_tuntap,
|
||||
.create_type = NETDEV_CREATE_INDEPENDENT,
|
||||
@ -152,6 +240,7 @@ const NetDevVTable tap_vtable = {
|
||||
.sections = NETDEV_COMMON_SECTIONS "Tap\0",
|
||||
.config_verify = tuntap_verify,
|
||||
.init = tuntap_init,
|
||||
.drop = tuntap_drop,
|
||||
.done = tuntap_done,
|
||||
.create = netdev_create_tuntap,
|
||||
.create_type = NETDEV_CREATE_INDEPENDENT,
|
||||
|
@ -21,3 +21,6 @@ DEFINE_NETDEV_CAST(TUN, TunTap);
|
||||
DEFINE_NETDEV_CAST(TAP, TunTap);
|
||||
extern const NetDevVTable tun_vtable;
|
||||
extern const NetDevVTable tap_vtable;
|
||||
|
||||
int manager_add_tuntap_fd(Manager *m, int fd, const char *name);
|
||||
void manager_clear_unmanaged_tuntap_fds(Manager *m);
|
||||
|
@ -64,6 +64,7 @@
|
||||
#include "strv.h"
|
||||
#include "tc.h"
|
||||
#include "tmpfile-util.h"
|
||||
#include "tuntap.h"
|
||||
#include "udev-util.h"
|
||||
#include "util.h"
|
||||
#include "vrf.h"
|
||||
|
@ -8,7 +8,6 @@
|
||||
#include <linux/nexthop.h>
|
||||
#include <linux/nl80211.h>
|
||||
|
||||
#include "sd-daemon.h"
|
||||
#include "sd-netlink.h"
|
||||
|
||||
#include "alloc-util.h"
|
||||
@ -18,6 +17,7 @@
|
||||
#include "bus-polkit.h"
|
||||
#include "bus-util.h"
|
||||
#include "conf-parser.h"
|
||||
#include "daemon-util.h"
|
||||
#include "def.h"
|
||||
#include "device-private.h"
|
||||
#include "device-util.h"
|
||||
@ -58,6 +58,7 @@
|
||||
#include "sysctl-util.h"
|
||||
#include "tclass.h"
|
||||
#include "tmpfile-util.h"
|
||||
#include "tuntap.h"
|
||||
#include "udev-util.h"
|
||||
|
||||
/* use 128 MB for receive socket kernel queue. */
|
||||
@ -243,22 +244,45 @@ static int manager_connect_udev(Manager *m) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int systemd_netlink_fd(void) {
|
||||
int n, fd, rtnl_fd = -EINVAL;
|
||||
static int manager_listen_fds(Manager *m, int *ret_rtnl_fd) {
|
||||
_cleanup_strv_free_ char **names = NULL;
|
||||
int n, rtnl_fd = -1;
|
||||
|
||||
n = sd_listen_fds(true);
|
||||
if (n <= 0)
|
||||
assert(m);
|
||||
assert(ret_rtnl_fd);
|
||||
|
||||
n = sd_listen_fds_with_names(/* unset_environment = */ true, &names);
|
||||
if (n < 0)
|
||||
return n;
|
||||
|
||||
if (strv_length(names) != (size_t) n)
|
||||
return -EINVAL;
|
||||
|
||||
for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd ++)
|
||||
for (int i = 0; i < n; i++) {
|
||||
int fd = i + SD_LISTEN_FDS_START;
|
||||
|
||||
if (sd_is_socket(fd, AF_NETLINK, SOCK_RAW, -1) > 0) {
|
||||
if (rtnl_fd >= 0)
|
||||
return -EINVAL;
|
||||
if (rtnl_fd >= 0) {
|
||||
log_debug("Received multiple netlink socket, ignoring.");
|
||||
safe_close(fd);
|
||||
continue;
|
||||
}
|
||||
|
||||
rtnl_fd = fd;
|
||||
continue;
|
||||
}
|
||||
|
||||
return rtnl_fd;
|
||||
if (manager_add_tuntap_fd(m, fd, names[i]) >= 0)
|
||||
continue;
|
||||
|
||||
if (m->test_mode)
|
||||
safe_close(fd);
|
||||
else
|
||||
close_and_notify_warn(fd, names[i]);
|
||||
}
|
||||
|
||||
*ret_rtnl_fd = rtnl_fd;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int manager_connect_genl(Manager *m) {
|
||||
@ -325,18 +349,21 @@ static int manager_setup_rtnl_filter(Manager *manager) {
|
||||
return sd_netlink_attach_filter(manager->rtnl, ELEMENTSOF(filter), filter);
|
||||
}
|
||||
|
||||
static int manager_connect_rtnl(Manager *m) {
|
||||
int fd, r;
|
||||
static int manager_connect_rtnl(Manager *m, int fd) {
|
||||
_unused_ _cleanup_close_ int fd_close = fd;
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
|
||||
fd = systemd_netlink_fd();
|
||||
/* This takes input fd. */
|
||||
|
||||
if (fd < 0)
|
||||
r = sd_netlink_open(&m->rtnl);
|
||||
else
|
||||
r = sd_netlink_open_fd(&m->rtnl, fd);
|
||||
if (r < 0)
|
||||
return r;
|
||||
TAKE_FD(fd_close);
|
||||
|
||||
/* 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
|
||||
@ -487,6 +514,7 @@ static int manager_set_keep_configuration(Manager *m) {
|
||||
}
|
||||
|
||||
int manager_setup(Manager *m) {
|
||||
_cleanup_close_ int rtnl_fd = -1;
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
@ -510,7 +538,11 @@ int manager_setup(Manager *m) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = manager_connect_rtnl(m);
|
||||
r = manager_listen_fds(m, &rtnl_fd);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = manager_connect_rtnl(m, TAKE_FD(rtnl_fd));
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@ -600,6 +632,8 @@ Manager* manager_free(Manager *m) {
|
||||
|
||||
m->netdevs = hashmap_free_with_destructor(m->netdevs, netdev_unref);
|
||||
|
||||
m->tuntap_fds_by_name = hashmap_free(m->tuntap_fds_by_name);
|
||||
|
||||
m->wiphy_by_name = hashmap_free(m->wiphy_by_name);
|
||||
m->wiphy_by_index = hashmap_free_with_destructor(m->wiphy_by_index, wiphy_free);
|
||||
|
||||
@ -678,6 +712,8 @@ int manager_load_config(Manager *m) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
manager_clear_unmanaged_tuntap_fds(m);
|
||||
|
||||
r = network_load(m, &m->networks);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
@ -100,6 +100,8 @@ struct Manager {
|
||||
FirewallContext *fw_ctx;
|
||||
|
||||
OrderedSet *request_queue;
|
||||
|
||||
Hashmap *tuntap_fds_by_name;
|
||||
};
|
||||
|
||||
int manager_new(Manager **ret, bool test_mode);
|
||||
|
@ -25,6 +25,7 @@ CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_NET_BROADCAST CAP_N
|
||||
DeviceAllow=char-* rw
|
||||
ExecStart=!!{{ROOTLIBEXECDIR}}/systemd-networkd
|
||||
ExecReload=networkctl reload
|
||||
FileDescriptorStoreMax=512
|
||||
LockPersonality=yes
|
||||
MemoryDenyWriteExecute=yes
|
||||
NoNewPrivileges=yes
|
||||
|
Loading…
x
Reference in New Issue
Block a user