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