chiark / gitweb /
networkd: tuntap - return correct error when /dev/net/tun cannot be opened
[elogind.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_error_netdev(netdev, "Failed to open tun dev: %m");
74                 return -errno;
75         }
76
77         r = ioctl(fd, TUNSETIFF, ifr);
78         if (r < 0) {
79                 log_error_netdev(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("Cannot resolve user name %s: %s",
99                                   t->user_name, strerror(-r));
100                         return 0;
101                 }
102
103                 r = ioctl(fd, TUNSETOWNER, uid);
104                 if ( r < 0) {
105                         log_error_netdev(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("Cannot resolve group name %s: %s",
118                                   t->group_name, strerror(-r));
119                         return 0;
120                 }
121
122                 r = ioctl(fd, TUNSETGROUP, gid);
123                 if( r < 0) {
124                         log_error_netdev(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_error_netdev(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         TunTap *t = NULL;
175
176         assert(netdev);
177
178         if (netdev->kind == NETDEV_KIND_TUN)
179                 t = TUN(netdev);
180         else
181                 t = TAP(netdev);
182
183         assert(t);
184
185         if (netdev->mtu) {
186                 log_warning_netdev(netdev, "MTU configured for %s, ignoring",
187                                    netdev_kind_to_string(netdev->kind));
188         }
189
190         if (netdev->mac) {
191                 log_warning_netdev(netdev, "MAC configured for %s, ignoring",
192                                    netdev_kind_to_string(netdev->kind));
193         }
194
195         return 0;
196 }
197
198 const NetDevVTable tun_vtable = {
199         .object_size = sizeof(TunTap),
200         .sections = "Match\0NetDev\0Tun\0",
201         .config_verify = tuntap_verify,
202         .done = tuntap_done,
203         .create = netdev_create_tuntap,
204         .create_type = NETDEV_CREATE_INDEPENDENT,
205 };
206
207 const NetDevVTable tap_vtable = {
208         .object_size = sizeof(TunTap),
209         .sections = "Match\0NetDev\0Tap\0",
210         .config_verify = tuntap_verify,
211         .done = tuntap_done,
212         .create = netdev_create_tuntap,
213         .create_type = NETDEV_CREATE_INDEPENDENT,
214 };