Line data Source code
1 : /* SPDX-License-Identifier: LGPL-2.1+ */
2 :
3 : #include <errno.h>
4 : #include <fcntl.h>
5 : #include <net/if.h>
6 : #include <netinet/if_ether.h>
7 : #include <sys/ioctl.h>
8 : #include <sys/stat.h>
9 : #include <sys/types.h>
10 : #include <linux/if_tun.h>
11 :
12 : #include "alloc-util.h"
13 : #include "fd-util.h"
14 : #include "netdev/tuntap.h"
15 : #include "user-util.h"
16 :
17 : #define TUN_DEV "/dev/net/tun"
18 :
19 0 : static int netdev_fill_tuntap_message(NetDev *netdev, struct ifreq *ifr) {
20 : TunTap *t;
21 :
22 0 : assert(netdev);
23 0 : assert(netdev->ifname);
24 0 : assert(ifr);
25 :
26 0 : if (netdev->kind == NETDEV_KIND_TAP) {
27 0 : t = TAP(netdev);
28 0 : ifr->ifr_flags |= IFF_TAP;
29 : } else {
30 0 : t = TUN(netdev);
31 0 : ifr->ifr_flags |= IFF_TUN;
32 : }
33 :
34 0 : if (!t->packet_info)
35 0 : ifr->ifr_flags |= IFF_NO_PI;
36 :
37 0 : if (t->multi_queue)
38 0 : ifr->ifr_flags |= IFF_MULTI_QUEUE;
39 :
40 0 : if (t->vnet_hdr)
41 0 : ifr->ifr_flags |= IFF_VNET_HDR;
42 :
43 0 : strncpy(ifr->ifr_name, netdev->ifname, IFNAMSIZ-1);
44 :
45 0 : return 0;
46 : }
47 :
48 0 : static int netdev_tuntap_add(NetDev *netdev, struct ifreq *ifr) {
49 0 : _cleanup_close_ int fd;
50 0 : TunTap *t = NULL;
51 : const char *user;
52 : const char *group;
53 : uid_t uid;
54 : gid_t gid;
55 : int r;
56 :
57 0 : assert(netdev);
58 0 : assert(ifr);
59 :
60 0 : fd = open(TUN_DEV, O_RDWR|O_CLOEXEC);
61 0 : if (fd < 0)
62 0 : return log_netdev_error_errno(netdev, -errno, "Failed to open tun dev: %m");
63 :
64 0 : if (ioctl(fd, TUNSETIFF, ifr) < 0)
65 0 : return log_netdev_error_errno(netdev, -errno, "TUNSETIFF failed on tun dev: %m");
66 :
67 0 : if (netdev->kind == NETDEV_KIND_TAP)
68 0 : t = TAP(netdev);
69 : else
70 0 : t = TUN(netdev);
71 :
72 0 : assert(t);
73 :
74 0 : if (t->user_name) {
75 0 : user = t->user_name;
76 :
77 0 : r = get_user_creds(&user, &uid, NULL, NULL, NULL, USER_CREDS_ALLOW_MISSING);
78 0 : if (r < 0)
79 0 : return log_netdev_error_errno(netdev, r, "Cannot resolve user name %s: %m", t->user_name);
80 :
81 0 : if (ioctl(fd, TUNSETOWNER, uid) < 0)
82 0 : return log_netdev_error_errno(netdev, -errno, "TUNSETOWNER failed on tun dev: %m");
83 : }
84 :
85 0 : if (t->group_name) {
86 0 : group = t->group_name;
87 :
88 0 : r = get_group_creds(&group, &gid, USER_CREDS_ALLOW_MISSING);
89 0 : if (r < 0)
90 0 : return log_netdev_error_errno(netdev, r, "Cannot resolve group name %s: %m", t->group_name);
91 :
92 0 : if (ioctl(fd, TUNSETGROUP, gid) < 0)
93 0 : return log_netdev_error_errno(netdev, -errno, "TUNSETGROUP failed on tun dev: %m");
94 :
95 : }
96 :
97 0 : if (ioctl(fd, TUNSETPERSIST, 1) < 0)
98 0 : return log_netdev_error_errno(netdev, -errno, "TUNSETPERSIST failed on tun dev: %m");
99 :
100 0 : return 0;
101 : }
102 :
103 0 : static int netdev_create_tuntap(NetDev *netdev) {
104 0 : struct ifreq ifr = {};
105 : int r;
106 :
107 0 : r = netdev_fill_tuntap_message(netdev, &ifr);
108 0 : if (r < 0)
109 0 : return r;
110 :
111 0 : return netdev_tuntap_add(netdev, &ifr);
112 : }
113 :
114 0 : static void tuntap_done(NetDev *netdev) {
115 0 : TunTap *t = NULL;
116 :
117 0 : assert(netdev);
118 :
119 0 : if (netdev->kind == NETDEV_KIND_TUN)
120 0 : t = TUN(netdev);
121 : else
122 0 : t = TAP(netdev);
123 :
124 0 : assert(t);
125 :
126 0 : t->user_name = mfree(t->user_name);
127 0 : t->group_name = mfree(t->group_name);
128 0 : }
129 :
130 0 : static int tuntap_verify(NetDev *netdev, const char *filename) {
131 0 : assert(netdev);
132 :
133 0 : if (netdev->mtu != 0)
134 0 : log_netdev_warning(netdev,
135 : "MTUBytes= configured for %s device in %s will be ignored.\n"
136 : "Please set it in the corresponding .network file.",
137 : netdev_kind_to_string(netdev->kind), filename);
138 :
139 0 : if (netdev->mac)
140 0 : log_netdev_warning(netdev,
141 : "MACAddress= configured for %s device in %s will be ignored.\n"
142 : "Please set it in the corresponding .network file.",
143 : netdev_kind_to_string(netdev->kind), filename);
144 :
145 0 : return 0;
146 : }
147 :
148 : const NetDevVTable tun_vtable = {
149 : .object_size = sizeof(TunTap),
150 : .sections = "Match\0NetDev\0Tun\0",
151 : .config_verify = tuntap_verify,
152 : .done = tuntap_done,
153 : .create = netdev_create_tuntap,
154 : .create_type = NETDEV_CREATE_INDEPENDENT,
155 : };
156 :
157 : const NetDevVTable tap_vtable = {
158 : .object_size = sizeof(TunTap),
159 : .sections = "Match\0NetDev\0Tap\0",
160 : .config_verify = tuntap_verify,
161 : .done = tuntap_done,
162 : .create = netdev_create_tuntap,
163 : .create_type = NETDEV_CREATE_INDEPENDENT,
164 : };
|