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