]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/netdev/tuntap.c
Add SPDX license identifiers to source files under the LGPL
[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
634f0f98 21#include <fcntl.h>
30ae9dfd 22#include <linux/if_tun.h>
634f0f98 23#include <net/if.h>
e306723e 24#include <netinet/if_ether.h>
634f0f98
ZJS
25#include <sys/ioctl.h>
26#include <sys/stat.h>
27#include <sys/types.h>
30ae9dfd 28
b5efdb8a 29#include "alloc-util.h"
3ffd4af2 30#include "fd-util.h"
441e9ae4 31#include "netdev/tuntap.h"
b1d4f8e1 32#include "user-util.h"
30ae9dfd
SS
33
34#define TUN_DEV "/dev/net/tun"
35
30ae9dfd 36static int netdev_fill_tuntap_message(NetDev *netdev, struct ifreq *ifr) {
aa9f1140 37 TunTap *t;
30ae9dfd
SS
38
39 assert(netdev);
aa9f1140 40 assert(netdev->ifname);
30ae9dfd
SS
41 assert(ifr);
42
aa9f1140
TG
43 if (netdev->kind == NETDEV_KIND_TAP) {
44 t = TAP(netdev);
30ae9dfd 45 ifr->ifr_flags |= IFF_TAP;
aa9f1140
TG
46 } else {
47 t = TUN(netdev);
63dadd90 48 ifr->ifr_flags |= IFF_TUN;
aa9f1140 49 }
63dadd90 50
aa9f1140 51 if (!t->packet_info)
30ae9dfd
SS
52 ifr->ifr_flags |= IFF_NO_PI;
53
aa9f1140 54 if (t->one_queue)
30ae9dfd
SS
55 ifr->ifr_flags |= IFF_ONE_QUEUE;
56
aa9f1140 57 if (t->multi_queue)
30ae9dfd
SS
58 ifr->ifr_flags |= IFF_MULTI_QUEUE;
59
f5f07dbf
SS
60 if (t->vnet_hdr)
61 ifr->ifr_flags |= IFF_VNET_HDR;
62
30ae9dfd
SS
63 strncpy(ifr->ifr_name, netdev->ifname, IFNAMSIZ-1);
64
65 return 0;
66}
67
68static int netdev_tuntap_add(NetDev *netdev, struct ifreq *ifr) {
69 _cleanup_close_ int fd;
aa9f1140 70 TunTap *t = NULL;
30ae9dfd
SS
71 const char *user;
72 const char *group;
73 uid_t uid;
74 gid_t gid;
6f44acfb 75 int r;
30ae9dfd 76
aa9f1140
TG
77 assert(netdev);
78 assert(ifr);
79
30ae9dfd 80 fd = open(TUN_DEV, O_RDWR);
ce67afb0
SS
81 if (fd < 0)
82 return log_netdev_error_errno(netdev, -errno, "Failed to open tun dev: %m");
30ae9dfd
SS
83
84 r = ioctl(fd, TUNSETIFF, ifr);
ce67afb0
SS
85 if (r < 0)
86 return log_netdev_error_errno(netdev, -errno, "TUNSETIFF failed on tun dev: %m");
30ae9dfd 87
aa9f1140
TG
88 if (netdev->kind == NETDEV_KIND_TAP)
89 t = TAP(netdev);
90 else
91 t = TUN(netdev);
92
93 assert(t);
30ae9dfd 94
9ed794a3 95 if (t->user_name) {
aa9f1140
TG
96
97 user = t->user_name;
30ae9dfd
SS
98
99 r = get_user_creds(&user, &uid, NULL, NULL, NULL);
ce67afb0
SS
100 if (r < 0)
101 return log_netdev_error_errno(netdev, r, "Cannot resolve user name %s: %m", t->user_name);
30ae9dfd
SS
102
103 r = ioctl(fd, TUNSETOWNER, uid);
ce67afb0
SS
104 if (r < 0)
105 return log_netdev_error_errno(netdev, -errno, "TUNSETOWNER failed on tun dev: %m");
30ae9dfd
SS
106 }
107
98b32556 108 if (t->group_name) {
30ae9dfd 109
aa9f1140 110 group = t->group_name;
30ae9dfd
SS
111
112 r = get_group_creds(&group, &gid);
ce67afb0
SS
113 if (r < 0)
114 return log_netdev_error_errno(netdev, r, "Cannot resolve group name %s: %m", t->group_name);
30ae9dfd
SS
115
116 r = ioctl(fd, TUNSETGROUP, gid);
ce67afb0
SS
117 if (r < 0)
118 return log_netdev_error_errno(netdev, -errno, "TUNSETGROUP failed on tun dev: %m");
30ae9dfd
SS
119
120 }
121
122 r = ioctl(fd, TUNSETPERSIST, 1);
ce67afb0
SS
123 if (r < 0)
124 return log_netdev_error_errno(netdev, -errno, "TUNSETPERSIST failed on tun dev: %m");
30ae9dfd 125
6f44acfb 126 return 0;
30ae9dfd
SS
127}
128
3be1d7e0 129static int netdev_create_tuntap(NetDev *netdev) {
aa9f1140 130 struct ifreq ifr = {};
30ae9dfd
SS
131 int r;
132
30ae9dfd 133 r = netdev_fill_tuntap_message(netdev, &ifr);
9ed794a3 134 if (r < 0)
30ae9dfd
SS
135 return r;
136
30ae9dfd
SS
137 return netdev_tuntap_add(netdev, &ifr);
138}
3be1d7e0 139
aa9f1140
TG
140static void tuntap_done(NetDev *netdev) {
141 TunTap *t = NULL;
142
143 assert(netdev);
144
145 if (netdev->kind == NETDEV_KIND_TUN)
146 t = TUN(netdev);
147 else
148 t = TAP(netdev);
149
150 assert(t);
151
a1e58e8e
LP
152 t->user_name = mfree(t->user_name);
153 t->group_name = mfree(t->group_name);
aa9f1140
TG
154}
155
e0fbf1fc 156static int tuntap_verify(NetDev *netdev, const char *filename) {
e0fbf1fc
TG
157 assert(netdev);
158
98b32556
LP
159 if (netdev->mtu)
160 log_netdev_warning(netdev, "MTU configured for %s, ignoring", netdev_kind_to_string(netdev->kind));
e0fbf1fc 161
98b32556
LP
162 if (netdev->mac)
163 log_netdev_warning(netdev, "MAC configured for %s, ignoring", netdev_kind_to_string(netdev->kind));
e0fbf1fc
TG
164
165 return 0;
166}
167
3be1d7e0 168const NetDevVTable tun_vtable = {
aa9f1140
TG
169 .object_size = sizeof(TunTap),
170 .sections = "Match\0NetDev\0Tun\0",
e0fbf1fc 171 .config_verify = tuntap_verify,
aa9f1140 172 .done = tuntap_done,
3be1d7e0 173 .create = netdev_create_tuntap,
aa9f1140 174 .create_type = NETDEV_CREATE_INDEPENDENT,
3be1d7e0
TG
175};
176
177const NetDevVTable tap_vtable = {
aa9f1140
TG
178 .object_size = sizeof(TunTap),
179 .sections = "Match\0NetDev\0Tap\0",
e0fbf1fc 180 .config_verify = tuntap_verify,
aa9f1140 181 .done = tuntap_done,
3be1d7e0 182 .create = netdev_create_tuntap,
aa9f1140 183 .create_type = NETDEV_CREATE_INDEPENDENT,
3be1d7e0 184};