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