1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
6 #include <netinet/if_ether.h>
10 #include <linux/if_tun.h>
12 #include "alloc-util.h"
13 #include "daemon-util.h"
15 #include "networkd-link.h"
16 #include "networkd-manager.h"
17 #include "socket-util.h"
19 #include "user-util.h"
21 #define TUN_DEV "/dev/net/tun"
23 static TunTap
* TUNTAP(NetDev
*netdev
) {
26 switch (netdev
->kind
) {
36 static void *close_fd_ptr(void *p
) {
37 safe_close(PTR_TO_FD(p
));
41 DEFINE_PRIVATE_HASH_OPS_FULL(named_fd_hash_ops
, char, string_hash_func
, string_compare_func
, free
, void, close_fd_ptr
);
43 int manager_add_tuntap_fd(Manager
*m
, int fd
, const char *name
) {
44 _cleanup_free_
char *tuntap_name
= NULL
;
52 p
= startswith(name
, "tuntap-");
54 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL
), "Received unknown fd (%s).", name
);
57 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL
), "Received tuntap fd with invalid name (%s).", p
);
59 tuntap_name
= strdup(p
);
61 return log_oom_debug();
63 r
= hashmap_ensure_put(&m
->tuntap_fds_by_name
, &named_fd_hash_ops
, tuntap_name
, FD_TO_PTR(fd
));
65 return log_debug_errno(r
, "Failed to store tuntap fd: %m");
67 TAKE_PTR(tuntap_name
);
71 void manager_clear_unmanaged_tuntap_fds(Manager
*m
) {
77 while ((p
= hashmap_steal_first_key_and_value(m
->tuntap_fds_by_name
, (void**) &name
))) {
78 close_and_notify_warn(PTR_TO_FD(p
), name
);
83 static int tuntap_take_fd(NetDev
*netdev
) {
84 _cleanup_free_
char *name
= NULL
;
89 assert(netdev
->manager
);
91 r
= link_get_by_name(netdev
->manager
, netdev
->ifname
, NULL
);
95 p
= hashmap_remove2(netdev
->manager
->tuntap_fds_by_name
, netdev
->ifname
, (void**) &name
);
99 log_netdev_debug(netdev
, "Found file descriptor in fd store.");
103 static int netdev_create_tuntap(NetDev
*netdev
) {
104 _cleanup_close_
int fd
= -EBADF
;
105 struct ifreq ifr
= {};
115 fd
= tuntap_take_fd(netdev
);
117 fd
= open(TUN_DEV
, O_RDWR
|O_CLOEXEC
);
119 return log_netdev_error_errno(netdev
, errno
, "Failed to open " TUN_DEV
": %m");
121 if (netdev
->kind
== NETDEV_KIND_TAP
)
122 ifr
.ifr_flags
|= IFF_TAP
;
124 ifr
.ifr_flags
|= IFF_TUN
;
127 ifr
.ifr_flags
|= IFF_NO_PI
;
130 ifr
.ifr_flags
|= IFF_MULTI_QUEUE
;
133 ifr
.ifr_flags
|= IFF_VNET_HDR
;
135 strncpy(ifr
.ifr_name
, netdev
->ifname
, IFNAMSIZ
-1);
137 if (ioctl(fd
, TUNSETIFF
, &ifr
) < 0)
138 return log_netdev_error_errno(netdev
, errno
, "TUNSETIFF failed: %m");
141 const char *user
= t
->user_name
;
144 r
= get_user_creds(&user
, &uid
, NULL
, NULL
, NULL
, USER_CREDS_ALLOW_MISSING
);
146 return log_netdev_error_errno(netdev
, r
, "Cannot resolve user name %s: %m", t
->user_name
);
148 if (ioctl(fd
, TUNSETOWNER
, uid
) < 0)
149 return log_netdev_error_errno(netdev
, errno
, "TUNSETOWNER failed: %m");
153 const char *group
= t
->group_name
;
156 r
= get_group_creds(&group
, &gid
, USER_CREDS_ALLOW_MISSING
);
158 return log_netdev_error_errno(netdev
, r
, "Cannot resolve group name %s: %m", t
->group_name
);
160 if (ioctl(fd
, TUNSETGROUP
, gid
) < 0)
161 return log_netdev_error_errno(netdev
, errno
, "TUNSETGROUP failed: %m");
165 if (ioctl(fd
, TUNSETPERSIST
, 1) < 0)
166 return log_netdev_error_errno(netdev
, errno
, "TUNSETPERSIST failed: %m");
170 (void) notify_push_fdf(t
->fd
, "tuntap-%s", netdev
->ifname
);
176 static void tuntap_init(NetDev
*netdev
) {
186 static void tuntap_drop(NetDev
*netdev
) {
193 t
->fd
= close_and_notify_warn(t
->fd
, netdev
->ifname
);
196 static void tuntap_done(NetDev
*netdev
) {
203 t
->fd
= safe_close(t
->fd
);
204 t
->user_name
= mfree(t
->user_name
);
205 t
->group_name
= mfree(t
->group_name
);
208 static int tuntap_verify(NetDev
*netdev
, const char *filename
) {
211 if (netdev
->mtu
!= 0)
212 log_netdev_warning(netdev
,
213 "MTUBytes= configured for %s device in %s will be ignored.\n"
214 "Please set it in the corresponding .network file.",
215 netdev_kind_to_string(netdev
->kind
), filename
);
217 if (netdev
->hw_addr
.length
> 0)
218 log_netdev_warning(netdev
,
219 "MACAddress= configured for %s device in %s will be ignored.\n"
220 "Please set it in the corresponding .network file.",
221 netdev_kind_to_string(netdev
->kind
), filename
);
226 const NetDevVTable tun_vtable
= {
227 .object_size
= sizeof(TunTap
),
228 .sections
= NETDEV_COMMON_SECTIONS
"Tun\0",
229 .config_verify
= tuntap_verify
,
233 .create
= netdev_create_tuntap
,
234 .create_type
= NETDEV_CREATE_INDEPENDENT
,
235 .iftype
= ARPHRD_NONE
,
238 const NetDevVTable tap_vtable
= {
239 .object_size
= sizeof(TunTap
),
240 .sections
= NETDEV_COMMON_SECTIONS
"Tap\0",
241 .config_verify
= tuntap_verify
,
245 .create
= netdev_create_tuntap
,
246 .create_type
= NETDEV_CREATE_INDEPENDENT
,
247 .iftype
= ARPHRD_ETHER
,