]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-netdev-tuntap.c
Merge pull request #63 from arvidjaar/issue/50
[thirdparty/systemd.git] / src / network / networkd-netdev-tuntap.c
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 static int netdev_fill_tuntap_message(NetDev *netdev, struct ifreq *ifr) {
31 TunTap *t;
32
33 assert(netdev);
34 assert(netdev->ifname);
35 assert(ifr);
36
37 if (netdev->kind == NETDEV_KIND_TAP) {
38 t = TAP(netdev);
39 ifr->ifr_flags |= IFF_TAP;
40 } else {
41 t = TUN(netdev);
42 ifr->ifr_flags |= IFF_TUN;
43 }
44
45 if (!t->packet_info)
46 ifr->ifr_flags |= IFF_NO_PI;
47
48 if (t->one_queue)
49 ifr->ifr_flags |= IFF_ONE_QUEUE;
50
51 if (t->multi_queue)
52 ifr->ifr_flags |= IFF_MULTI_QUEUE;
53
54 strncpy(ifr->ifr_name, netdev->ifname, IFNAMSIZ-1);
55
56 return 0;
57 }
58
59 static int netdev_tuntap_add(NetDev *netdev, struct ifreq *ifr) {
60 _cleanup_close_ int fd;
61 TunTap *t = NULL;
62 const char *user;
63 const char *group;
64 uid_t uid;
65 gid_t gid;
66 int r;
67
68 assert(netdev);
69 assert(ifr);
70
71 fd = open(TUN_DEV, O_RDWR);
72 if (fd < 0) {
73 log_netdev_error(netdev, "Failed to open tun dev: %m");
74 return -errno;
75 }
76
77 r = ioctl(fd, TUNSETIFF, ifr);
78 if (r < 0) {
79 log_netdev_error(netdev,
80 "TUNSETIFF failed on tun dev: %s",
81 strerror(-r));
82 return r;
83 }
84
85 if (netdev->kind == NETDEV_KIND_TAP)
86 t = TAP(netdev);
87 else
88 t = TUN(netdev);
89
90 assert(t);
91
92 if(t->user_name) {
93
94 user = t->user_name;
95
96 r = get_user_creds(&user, &uid, NULL, NULL, NULL);
97 if (r < 0) {
98 log_error_errno(r, "Cannot resolve user name %s: %m",
99 t->user_name);
100 return 0;
101 }
102
103 r = ioctl(fd, TUNSETOWNER, uid);
104 if ( r < 0) {
105 log_netdev_error(netdev,
106 "TUNSETOWNER failed on tun dev: %s",
107 strerror(-r));
108 }
109 }
110
111 if (t->group_name) {
112
113 group = t->group_name;
114
115 r = get_group_creds(&group, &gid);
116 if (r < 0) {
117 log_error_errno(r, "Cannot resolve group name %s: %m",
118 t->group_name);
119 return 0;
120 }
121
122 r = ioctl(fd, TUNSETGROUP, gid);
123 if( r < 0) {
124 log_netdev_error(netdev,
125 "TUNSETGROUP failed on tun dev: %s",
126 strerror(-r));
127 return r;
128 }
129
130 }
131
132 r = ioctl(fd, TUNSETPERSIST, 1);
133 if (r < 0) {
134 log_netdev_error(netdev,
135 "TUNSETPERSIST failed on tun dev: %s",
136 strerror(-r));
137 return r;
138 }
139
140 return 0;
141 }
142
143 static int netdev_create_tuntap(NetDev *netdev) {
144 struct ifreq ifr = {};
145 int r;
146
147 r = netdev_fill_tuntap_message(netdev, &ifr);
148 if(r < 0)
149 return r;
150
151 return netdev_tuntap_add(netdev, &ifr);
152 }
153
154 static void tuntap_done(NetDev *netdev) {
155 TunTap *t = NULL;
156
157 assert(netdev);
158
159 if (netdev->kind == NETDEV_KIND_TUN)
160 t = TUN(netdev);
161 else
162 t = TAP(netdev);
163
164 assert(t);
165
166 free(t->user_name);
167 t->user_name = NULL;
168
169 free(t->group_name);
170 t->group_name = NULL;
171 }
172
173 static int tuntap_verify(NetDev *netdev, const char *filename) {
174 assert(netdev);
175
176 if (netdev->mtu)
177 log_netdev_warning(netdev, "MTU configured for %s, ignoring", netdev_kind_to_string(netdev->kind));
178
179 if (netdev->mac)
180 log_netdev_warning(netdev, "MAC configured for %s, ignoring", netdev_kind_to_string(netdev->kind));
181
182 return 0;
183 }
184
185 const NetDevVTable tun_vtable = {
186 .object_size = sizeof(TunTap),
187 .sections = "Match\0NetDev\0Tun\0",
188 .config_verify = tuntap_verify,
189 .done = tuntap_done,
190 .create = netdev_create_tuntap,
191 .create_type = NETDEV_CREATE_INDEPENDENT,
192 };
193
194 const NetDevVTable tap_vtable = {
195 .object_size = sizeof(TunTap),
196 .sections = "Match\0NetDev\0Tap\0",
197 .config_verify = tuntap_verify,
198 .done = tuntap_done,
199 .create = netdev_create_tuntap,
200 .create_type = NETDEV_CREATE_INDEPENDENT,
201 };