]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/netdev/tuntap.c
fuzz-unit-file: allow a space between variable name and "=" (#8670)
[thirdparty/systemd.git] / src / network / netdev / tuntap.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
30ae9dfd
SS
2/***
3 This file is part of systemd.
4
5 Copyright 2014 Susant Sahani <susant@redhat.com>
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19***/
20
dccca82b 21#include <errno.h>
634f0f98 22#include <fcntl.h>
30ae9dfd 23#include <linux/if_tun.h>
634f0f98 24#include <net/if.h>
e306723e 25#include <netinet/if_ether.h>
634f0f98
ZJS
26#include <sys/ioctl.h>
27#include <sys/stat.h>
28#include <sys/types.h>
30ae9dfd 29
b5efdb8a 30#include "alloc-util.h"
3ffd4af2 31#include "fd-util.h"
441e9ae4 32#include "netdev/tuntap.h"
b1d4f8e1 33#include "user-util.h"
30ae9dfd
SS
34
35#define TUN_DEV "/dev/net/tun"
36
30ae9dfd 37static int netdev_fill_tuntap_message(NetDev *netdev, struct ifreq *ifr) {
aa9f1140 38 TunTap *t;
30ae9dfd
SS
39
40 assert(netdev);
aa9f1140 41 assert(netdev->ifname);
30ae9dfd
SS
42 assert(ifr);
43
aa9f1140
TG
44 if (netdev->kind == NETDEV_KIND_TAP) {
45 t = TAP(netdev);
30ae9dfd 46 ifr->ifr_flags |= IFF_TAP;
aa9f1140
TG
47 } else {
48 t = TUN(netdev);
63dadd90 49 ifr->ifr_flags |= IFF_TUN;
aa9f1140 50 }
63dadd90 51
aa9f1140 52 if (!t->packet_info)
30ae9dfd
SS
53 ifr->ifr_flags |= IFF_NO_PI;
54
aa9f1140 55 if (t->one_queue)
30ae9dfd
SS
56 ifr->ifr_flags |= IFF_ONE_QUEUE;
57
aa9f1140 58 if (t->multi_queue)
30ae9dfd
SS
59 ifr->ifr_flags |= IFF_MULTI_QUEUE;
60
f5f07dbf
SS
61 if (t->vnet_hdr)
62 ifr->ifr_flags |= IFF_VNET_HDR;
63
30ae9dfd
SS
64 strncpy(ifr->ifr_name, netdev->ifname, IFNAMSIZ-1);
65
66 return 0;
67}
68
69static int netdev_tuntap_add(NetDev *netdev, struct ifreq *ifr) {
70 _cleanup_close_ int fd;
aa9f1140 71 TunTap *t = NULL;
30ae9dfd
SS
72 const char *user;
73 const char *group;
74 uid_t uid;
75 gid_t gid;
6f44acfb 76 int r;
30ae9dfd 77
aa9f1140
TG
78 assert(netdev);
79 assert(ifr);
80
30ae9dfd 81 fd = open(TUN_DEV, O_RDWR);
ce67afb0
SS
82 if (fd < 0)
83 return log_netdev_error_errno(netdev, -errno, "Failed to open tun dev: %m");
30ae9dfd
SS
84
85 r = ioctl(fd, TUNSETIFF, ifr);
ce67afb0
SS
86 if (r < 0)
87 return log_netdev_error_errno(netdev, -errno, "TUNSETIFF failed on tun dev: %m");
30ae9dfd 88
aa9f1140
TG
89 if (netdev->kind == NETDEV_KIND_TAP)
90 t = TAP(netdev);
91 else
92 t = TUN(netdev);
93
94 assert(t);
30ae9dfd 95
9ed794a3 96 if (t->user_name) {
aa9f1140
TG
97
98 user = t->user_name;
30ae9dfd
SS
99
100 r = get_user_creds(&user, &uid, NULL, NULL, NULL);
ce67afb0
SS
101 if (r < 0)
102 return log_netdev_error_errno(netdev, r, "Cannot resolve user name %s: %m", t->user_name);
30ae9dfd
SS
103
104 r = ioctl(fd, TUNSETOWNER, uid);
ce67afb0
SS
105 if (r < 0)
106 return log_netdev_error_errno(netdev, -errno, "TUNSETOWNER failed on tun dev: %m");
30ae9dfd
SS
107 }
108
98b32556 109 if (t->group_name) {
30ae9dfd 110
aa9f1140 111 group = t->group_name;
30ae9dfd
SS
112
113 r = get_group_creds(&group, &gid);
ce67afb0
SS
114 if (r < 0)
115 return log_netdev_error_errno(netdev, r, "Cannot resolve group name %s: %m", t->group_name);
30ae9dfd
SS
116
117 r = ioctl(fd, TUNSETGROUP, gid);
ce67afb0
SS
118 if (r < 0)
119 return log_netdev_error_errno(netdev, -errno, "TUNSETGROUP failed on tun dev: %m");
30ae9dfd
SS
120
121 }
122
123 r = ioctl(fd, TUNSETPERSIST, 1);
ce67afb0
SS
124 if (r < 0)
125 return log_netdev_error_errno(netdev, -errno, "TUNSETPERSIST failed on tun dev: %m");
30ae9dfd 126
6f44acfb 127 return 0;
30ae9dfd
SS
128}
129
3be1d7e0 130static int netdev_create_tuntap(NetDev *netdev) {
aa9f1140 131 struct ifreq ifr = {};
30ae9dfd
SS
132 int r;
133
30ae9dfd 134 r = netdev_fill_tuntap_message(netdev, &ifr);
9ed794a3 135 if (r < 0)
30ae9dfd
SS
136 return r;
137
30ae9dfd
SS
138 return netdev_tuntap_add(netdev, &ifr);
139}
3be1d7e0 140
aa9f1140
TG
141static void tuntap_done(NetDev *netdev) {
142 TunTap *t = NULL;
143
144 assert(netdev);
145
146 if (netdev->kind == NETDEV_KIND_TUN)
147 t = TUN(netdev);
148 else
149 t = TAP(netdev);
150
151 assert(t);
152
a1e58e8e
LP
153 t->user_name = mfree(t->user_name);
154 t->group_name = mfree(t->group_name);
aa9f1140
TG
155}
156
e0fbf1fc 157static int tuntap_verify(NetDev *netdev, const char *filename) {
e0fbf1fc
TG
158 assert(netdev);
159
98b32556
LP
160 if (netdev->mtu)
161 log_netdev_warning(netdev, "MTU configured for %s, ignoring", netdev_kind_to_string(netdev->kind));
e0fbf1fc 162
98b32556
LP
163 if (netdev->mac)
164 log_netdev_warning(netdev, "MAC configured for %s, ignoring", netdev_kind_to_string(netdev->kind));
e0fbf1fc
TG
165
166 return 0;
167}
168
3be1d7e0 169const NetDevVTable tun_vtable = {
aa9f1140
TG
170 .object_size = sizeof(TunTap),
171 .sections = "Match\0NetDev\0Tun\0",
e0fbf1fc 172 .config_verify = tuntap_verify,
aa9f1140 173 .done = tuntap_done,
3be1d7e0 174 .create = netdev_create_tuntap,
aa9f1140 175 .create_type = NETDEV_CREATE_INDEPENDENT,
3be1d7e0
TG
176};
177
178const NetDevVTable tap_vtable = {
aa9f1140
TG
179 .object_size = sizeof(TunTap),
180 .sections = "Match\0NetDev\0Tap\0",
e0fbf1fc 181 .config_verify = tuntap_verify,
aa9f1140 182 .done = tuntap_done,
3be1d7e0 183 .create = netdev_create_tuntap,
aa9f1140 184 .create_type = NETDEV_CREATE_INDEPENDENT,
3be1d7e0 185};