Branch data 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 : : };
|