]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/netdev/tuntap.c
license: LGPL-2.1+ -> LGPL-2.1-or-later
[thirdparty/systemd.git] / src / network / netdev / tuntap.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
30ae9dfd 2
dccca82b 3#include <errno.h>
634f0f98 4#include <fcntl.h>
634f0f98 5#include <net/if.h>
e306723e 6#include <netinet/if_ether.h>
634f0f98
ZJS
7#include <sys/ioctl.h>
8#include <sys/stat.h>
9#include <sys/types.h>
9aa5d8ba 10#include <linux/if_tun.h>
30ae9dfd 11
b5efdb8a 12#include "alloc-util.h"
3ffd4af2 13#include "fd-util.h"
737f1405 14#include "tuntap.h"
b1d4f8e1 15#include "user-util.h"
30ae9dfd
SS
16
17#define TUN_DEV "/dev/net/tun"
18
30ae9dfd 19static int netdev_fill_tuntap_message(NetDev *netdev, struct ifreq *ifr) {
aa9f1140 20 TunTap *t;
30ae9dfd
SS
21
22 assert(netdev);
aa9f1140 23 assert(netdev->ifname);
30ae9dfd
SS
24 assert(ifr);
25
aa9f1140
TG
26 if (netdev->kind == NETDEV_KIND_TAP) {
27 t = TAP(netdev);
30ae9dfd 28 ifr->ifr_flags |= IFF_TAP;
aa9f1140
TG
29 } else {
30 t = TUN(netdev);
63dadd90 31 ifr->ifr_flags |= IFF_TUN;
aa9f1140 32 }
63dadd90 33
aa9f1140 34 if (!t->packet_info)
30ae9dfd
SS
35 ifr->ifr_flags |= IFF_NO_PI;
36
aa9f1140 37 if (t->multi_queue)
30ae9dfd
SS
38 ifr->ifr_flags |= IFF_MULTI_QUEUE;
39
f5f07dbf
SS
40 if (t->vnet_hdr)
41 ifr->ifr_flags |= IFF_VNET_HDR;
42
30ae9dfd
SS
43 strncpy(ifr->ifr_name, netdev->ifname, IFNAMSIZ-1);
44
45 return 0;
46}
47
48static int netdev_tuntap_add(NetDev *netdev, struct ifreq *ifr) {
49 _cleanup_close_ int fd;
aa9f1140 50 TunTap *t = NULL;
30ae9dfd
SS
51 const char *user;
52 const char *group;
53 uid_t uid;
54 gid_t gid;
6f44acfb 55 int r;
30ae9dfd 56
aa9f1140
TG
57 assert(netdev);
58 assert(ifr);
59
163a035a 60 fd = open(TUN_DEV, O_RDWR|O_CLOEXEC);
ce67afb0
SS
61 if (fd < 0)
62 return log_netdev_error_errno(netdev, -errno, "Failed to open tun dev: %m");
30ae9dfd 63
ad16158c 64 if (ioctl(fd, TUNSETIFF, ifr) < 0)
ce67afb0 65 return log_netdev_error_errno(netdev, -errno, "TUNSETIFF failed on tun dev: %m");
30ae9dfd 66
aa9f1140
TG
67 if (netdev->kind == NETDEV_KIND_TAP)
68 t = TAP(netdev);
69 else
70 t = TUN(netdev);
71
72 assert(t);
30ae9dfd 73
9ed794a3 74 if (t->user_name) {
aa9f1140 75 user = t->user_name;
30ae9dfd 76
fafff8f1 77 r = get_user_creds(&user, &uid, NULL, NULL, NULL, USER_CREDS_ALLOW_MISSING);
ce67afb0
SS
78 if (r < 0)
79 return log_netdev_error_errno(netdev, r, "Cannot resolve user name %s: %m", t->user_name);
30ae9dfd 80
ad16158c 81 if (ioctl(fd, TUNSETOWNER, uid) < 0)
ce67afb0 82 return log_netdev_error_errno(netdev, -errno, "TUNSETOWNER failed on tun dev: %m");
30ae9dfd
SS
83 }
84
98b32556 85 if (t->group_name) {
aa9f1140 86 group = t->group_name;
30ae9dfd 87
fafff8f1 88 r = get_group_creds(&group, &gid, USER_CREDS_ALLOW_MISSING);
ce67afb0
SS
89 if (r < 0)
90 return log_netdev_error_errno(netdev, r, "Cannot resolve group name %s: %m", t->group_name);
30ae9dfd 91
ad16158c 92 if (ioctl(fd, TUNSETGROUP, gid) < 0)
ce67afb0 93 return log_netdev_error_errno(netdev, -errno, "TUNSETGROUP failed on tun dev: %m");
30ae9dfd
SS
94
95 }
96
ad16158c 97 if (ioctl(fd, TUNSETPERSIST, 1) < 0)
ce67afb0 98 return log_netdev_error_errno(netdev, -errno, "TUNSETPERSIST failed on tun dev: %m");
30ae9dfd 99
6f44acfb 100 return 0;
30ae9dfd
SS
101}
102
3be1d7e0 103static int netdev_create_tuntap(NetDev *netdev) {
aa9f1140 104 struct ifreq ifr = {};
30ae9dfd
SS
105 int r;
106
30ae9dfd 107 r = netdev_fill_tuntap_message(netdev, &ifr);
9ed794a3 108 if (r < 0)
30ae9dfd
SS
109 return r;
110
30ae9dfd
SS
111 return netdev_tuntap_add(netdev, &ifr);
112}
3be1d7e0 113
aa9f1140
TG
114static void tuntap_done(NetDev *netdev) {
115 TunTap *t = NULL;
116
117 assert(netdev);
118
119 if (netdev->kind == NETDEV_KIND_TUN)
120 t = TUN(netdev);
121 else
122 t = TAP(netdev);
123
124 assert(t);
125
a1e58e8e
LP
126 t->user_name = mfree(t->user_name);
127 t->group_name = mfree(t->group_name);
aa9f1140
TG
128}
129
e0fbf1fc 130static int tuntap_verify(NetDev *netdev, const char *filename) {
e0fbf1fc
TG
131 assert(netdev);
132
4e964aa0 133 if (netdev->mtu != 0)
1df569bf
YW
134 log_netdev_warning(netdev,
135 "MTUBytes= configured for %s device in %s will be ignored.\n"
136 "Please set it in the corresponding .network file.",
137 netdev_kind_to_string(netdev->kind), filename);
e0fbf1fc 138
98b32556 139 if (netdev->mac)
1df569bf
YW
140 log_netdev_warning(netdev,
141 "MACAddress= configured for %s device in %s will be ignored.\n"
142 "Please set it in the corresponding .network file.",
143 netdev_kind_to_string(netdev->kind), filename);
e0fbf1fc
TG
144
145 return 0;
146}
147
3be1d7e0 148const NetDevVTable tun_vtable = {
aa9f1140 149 .object_size = sizeof(TunTap),
130b812f 150 .sections = NETDEV_COMMON_SECTIONS "Tun\0",
e0fbf1fc 151 .config_verify = tuntap_verify,
aa9f1140 152 .done = tuntap_done,
3be1d7e0 153 .create = netdev_create_tuntap,
aa9f1140 154 .create_type = NETDEV_CREATE_INDEPENDENT,
3be1d7e0
TG
155};
156
157const NetDevVTable tap_vtable = {
aa9f1140 158 .object_size = sizeof(TunTap),
130b812f 159 .sections = NETDEV_COMMON_SECTIONS "Tap\0",
e0fbf1fc 160 .config_verify = tuntap_verify,
aa9f1140 161 .done = tuntap_done,
3be1d7e0 162 .create = netdev_create_tuntap,
aa9f1140 163 .create_type = NETDEV_CREATE_INDEPENDENT,
3be1d7e0 164};