Branch data Line data Source code
1 : : #include <unistd.h>
2 : : #include <sys/socket.h>
3 : : #include <linux/if.h>
4 : : #include <linux/if_tun.h>
5 : : #include <sys/ioctl.h>
6 : :
7 : : #include "cr_options.h"
8 : : #include "fdset.h"
9 : : #include "protobuf.h"
10 : : #include "cr-show.h"
11 : : #include "string.h"
12 : : #include "files.h"
13 : : #include "files-reg.h"
14 : : #include "tun.h"
15 : : #include "net.h"
16 : : #include "namespaces.h"
17 : :
18 : : #include "protobuf/tun.pb-c.h"
19 : :
20 : : #ifndef IFF_PERSIST
21 : : #define IFF_PERSIST 0x0800
22 : : #endif
23 : :
24 : : #ifndef IFF_NOFILTER
25 : : #define IFF_NOFILTER 0x1000
26 : : #endif
27 : :
28 : : #ifndef TUNSETQUEUE
29 : : #define TUNSETQUEUE _IOW('T', 217, int)
30 : : #define IFF_ATTACH_QUEUE 0x0200
31 : : #define IFF_DETACH_QUEUE 0x0400
32 : : #endif
33 : :
34 : : /*
35 : : * Absense of the 1st ioctl means we cannot restore tun link. But
36 : : * since the 2nd one appeared at the same time, we'll "check" this
37 : : * by trying to dump filter and abort dump if it's not there.
38 : : */
39 : :
40 : : #ifndef TUNSETIFINDEX
41 : : #define TUNSETIFINDEX _IOW('T', 218, unsigned int)
42 : : #endif
43 : :
44 : : #ifndef TUNGETFILTER
45 : : #define TUNGETFILTER _IOR('T', 219, struct sock_fprog)
46 : : #endif
47 : :
48 : : #define TUN_DEV_GEN_PATH "/dev/net/tun"
49 : :
50 : 2 : int check_tun(void)
51 : : {
52 : 2 : int fd, idx = 13, ret;
53 : :
54 [ - + ]: 2 : if (opts.check_ms_kernel) {
55 : 0 : pr_warn("Skipping tun support check\n");
56 : 0 : return 0;
57 : : }
58 : :
59 : : fd = open(TUN_DEV_GEN_PATH, O_RDWR);
60 [ - + ]: 2 : if (fd < 0) {
61 : 0 : pr_perror("Can't check tun support");
62 : 0 : return 0;
63 : : }
64 : :
65 : 2 : ret = ioctl(fd, TUNSETIFINDEX, &idx);
66 [ - + ]: 2 : if (ret < 0)
67 : 0 : pr_perror("No proper support for tun dump/restore");
68 : :
69 : 2 : close(fd);
70 : 2 : return ret;
71 : : }
72 : :
73 : : static LIST_HEAD(tun_links);
74 : :
75 : : struct tun_link {
76 : : char name[IFNAMSIZ];
77 : : struct list_head l;
78 : : union {
79 : : struct {
80 : : unsigned flags;
81 : : } rst;
82 : :
83 : : struct {
84 : : unsigned sndbuf;
85 : : unsigned vnethdr;
86 : : } dmp;
87 : : };
88 : : };
89 : :
90 : 0 : static int list_tun_link(NetDeviceEntry *nde)
91 : : {
92 : : struct tun_link *tl;
93 : :
94 [ # # ]: 0 : tl = xmalloc(sizeof(*tl));
95 [ # # ]: 0 : if (!tl)
96 : : return -1;
97 : :
98 : 0 : strlcpy(tl->name, nde->name, sizeof(tl->name));
99 : : /*
100 : : * Keep tun-flags not only for persistency fixup (see
101 : : * commend below), but also for TUNSETIFF -- we must
102 : : * open the device with the same flags it should live
103 : : * with (i.e. -- with which it was created.
104 : : */
105 : 0 : tl->rst.flags = nde->tun->flags;
106 : 0 : list_add_tail(&tl->l, &tun_links);
107 : : return 0;
108 : : }
109 : :
110 : 0 : static struct tun_link *find_tun_link(char *name)
111 : : {
112 : : struct tun_link *tl;
113 : :
114 [ # # ]: 0 : list_for_each_entry(tl, &tun_links, l)
115 [ # # ]: 0 : if (!strcmp(tl->name, name))
116 : : return tl;
117 : :
118 : : return NULL;
119 : : }
120 : :
121 : 0 : static struct tun_link *__dump_tun_link_fd(int fd, char *name, unsigned flags)
122 : : {
123 : : struct tun_link *tl;
124 : : struct sock_fprog flt;
125 : :
126 [ # # ]: 0 : tl = xmalloc(sizeof(*tl));
127 [ # # ]: 0 : if (!tl)
128 : : goto err;
129 : 0 : strlcpy(tl->name, name, sizeof(tl->name));
130 : :
131 [ # # ]: 0 : if (ioctl(fd, TUNGETVNETHDRSZ, &tl->dmp.vnethdr) < 0) {
132 : 0 : pr_perror("Can't dump vnethdr size for %s", name);
133 : 0 : goto err;
134 : : }
135 : :
136 [ # # ]: 0 : if (ioctl(fd, TUNGETSNDBUF, &tl->dmp.sndbuf) < 0) {
137 : 0 : pr_perror("Can't dump sndbuf for %s", name);
138 : 0 : goto err;
139 : : }
140 : :
141 [ # # ]: 0 : if (flags & IFF_TAP) {
142 : 0 : pr_debug("Checking filter for tap %s\n", name);
143 [ # # ]: 0 : if (ioctl(fd, TUNGETFILTER, &flt) < 0) {
144 : 0 : pr_perror("Can't get tun filter for %s", name);
145 : 0 : goto err;
146 : : }
147 : :
148 : : /*
149 : : * TUN filters are tricky -- the program itself is 'somewhere'
150 : : * in the task's memory, so we can't get one for unattached
151 : : * persistent device. The only way for doing it is opening the
152 : : * device with IFF_NOFILTER and attaching some fake one :(
153 : : */
154 : :
155 [ # # ]: 0 : if (flt.len != 0) {
156 : 0 : pr_err("Can't dump %s with filter on-board\n", name);
157 : 0 : goto err;
158 : : }
159 [ # # ]: 0 : } else if (!(flags & IFF_NOFILTER)) {
160 : 0 : pr_err("No info about %s filter, kernel is too old\n", name);
161 : 0 : goto err;
162 : : }
163 : :
164 : 0 : return tl;
165 : :
166 : : err:
167 [ # # ]: 0 : xfree(tl);
168 : : return NULL;
169 : : }
170 : :
171 : 0 : static struct tun_link *dump_tun_link_fd(int fd, char *name, unsigned flags)
172 : : {
173 : : struct tun_link *tl;
174 : :
175 : 0 : tl = find_tun_link(name);
176 [ # # ]: 0 : if (tl)
177 : : return tl;
178 : :
179 : 0 : tl = __dump_tun_link_fd(fd, name, flags);
180 [ # # ]: 0 : if (tl)
181 : : /*
182 : : * Keep this in list till links dumping code starts.
183 : : * We can't let it dump all this stuff itself, since
184 : : * multiple attaches to one tun device is limited and
185 : : * we may not be able to it that late.
186 : : *
187 : : * For persistent detached devices the get_tun_link_fd
188 : : * will attach to the device and get the needed stuff.
189 : : */
190 : 0 : list_add(&tl->l, &tun_links);
191 : :
192 : 0 : return tl;
193 : : }
194 : :
195 : 0 : static int open_tun_dev(char *name, unsigned int idx, unsigned flags)
196 : : {
197 : : int fd;
198 : : struct ifreq ifr;
199 : :
200 : : fd = open(TUN_DEV_GEN_PATH, O_RDWR);
201 [ # # ]: 0 : if (fd < 0) {
202 : 0 : pr_perror("Can't open tun device");
203 : 0 : return -1;
204 : : }
205 : :
206 [ # # ]: 0 : if (idx) {
207 : 0 : pr_debug(" restoring %u for %s tun\n", idx, name);
208 [ # # ]: 0 : if (ioctl(fd, TUNSETIFINDEX, &idx) < 0) {
209 : 0 : pr_perror("Can't restore tun's index");
210 : 0 : goto err;
211 : : }
212 : : }
213 : :
214 : : memset(&ifr, 0, sizeof(ifr));
215 : 0 : strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
216 : 0 : ifr.ifr_flags = flags;
217 : :
218 [ # # ]: 0 : if (ioctl(fd, TUNSETIFF, &ifr)) {
219 : 0 : pr_perror("Can't create tun device");
220 : 0 : goto err;
221 : : }
222 : :
223 : : return fd;
224 : :
225 : : err:
226 : 0 : close(fd);
227 : 0 : return -1;
228 : : }
229 : :
230 : 0 : static struct tun_link *get_tun_link_fd(char *name, unsigned flags)
231 : : {
232 : : struct tun_link *tl;
233 : : int fd;
234 : :
235 : 0 : tl = find_tun_link(name);
236 [ # # ]: 0 : if (tl)
237 : : return tl;
238 : :
239 : : /*
240 : : * If we haven't found this thing, then the
241 : : * device we see via netlink exists w/o any fds
242 : : * attached, i.e. -- it's persistent
243 : : */
244 : :
245 [ # # ]: 0 : if (!(flags & IFF_PERSIST)) {
246 : 0 : pr_err("No fd infor for non persistent tun device %s\n", name);
247 : 0 : return NULL;
248 : : }
249 : :
250 : : /*
251 : : * Kernel will try to attach filter (if it exists) to our memory,
252 : : * avoid this.
253 : : */
254 : :
255 : 0 : flags |= IFF_NOFILTER;
256 : :
257 : 0 : fd = open_tun_dev(name, 0, flags);
258 [ # # ]: 0 : if (fd < 0)
259 : : return NULL;
260 : :
261 : 0 : tl = __dump_tun_link_fd(fd, name, flags);
262 : 0 : close(fd);
263 : :
264 : 0 : return tl;
265 : : }
266 : :
267 : 0 : static int dump_tunfile(int lfd, u32 id, const struct fd_parms *p)
268 : : {
269 : 0 : int ret, img = fdset_fd(glob_fdset, CR_FD_TUNFILE);
270 : 0 : TunfileEntry tfe = TUNFILE_ENTRY__INIT;
271 : : struct ifreq ifr;
272 : :
273 [ # # ]: 0 : if (!(root_ns_mask & CLONE_NEWNET)) {
274 : 0 : pr_err("Net namespace is required to dump tun link\n");
275 : 0 : return -1;
276 : : }
277 : :
278 [ # # ]: 0 : if (dump_one_reg_file(lfd, id, p))
279 : : return -1;
280 : :
281 : 0 : pr_info("Dumping tun-file %d with id %#x\n", lfd, id);
282 : :
283 : 0 : tfe.id = id;
284 : 0 : ret = ioctl(lfd, TUNGETIFF, &ifr);
285 [ # # ]: 0 : if (ret < 0) {
286 [ # # ]: 0 : if (errno != EBADFD) {
287 : 0 : pr_perror("Can't dump tun-file device");
288 : 0 : return -1;
289 : : }
290 : :
291 : : /*
292 : : * Otherwise this is just opened file with not yet attached
293 : : * tun device. Go agead an write the respective entry.
294 : : */
295 : : } else {
296 : 0 : tfe.netdev = ifr.ifr_name;
297 : 0 : pr_info("`- attached to device %s (flags %x)\n", tfe.netdev, ifr.ifr_flags);
298 : :
299 [ # # ]: 0 : if (ifr.ifr_flags & IFF_DETACH_QUEUE) {
300 : 0 : tfe.has_detached = true;
301 : 0 : tfe.detached = true;
302 : : }
303 : :
304 [ # # ]: 0 : if (dump_tun_link_fd(lfd, tfe.netdev, ifr.ifr_flags) == NULL)
305 : : return -1;
306 : : }
307 : :
308 : 0 : return pb_write_one(img, &tfe, PB_TUNFILE);
309 : : }
310 : :
311 : : const struct fdtype_ops tunfile_dump_ops = {
312 : : .type = FD_TYPES__TUN,
313 : : .dump = dump_tunfile,
314 : : };
315 : :
316 : : struct tunfile_info {
317 : : struct file_desc d;
318 : : TunfileEntry *tfe;
319 : : };
320 : :
321 : 0 : static int tunfile_open(struct file_desc *d)
322 : : {
323 : : int fd;
324 : : struct tunfile_info *ti;
325 : : struct ifreq ifr;
326 : : struct tun_link *tl;
327 : :
328 : : ti = container_of(d, struct tunfile_info, d);
329 : 0 : fd = open_reg_by_id(ti->tfe->id);
330 [ # # ]: 0 : if (fd < 0)
331 : : return -1;
332 : :
333 [ # # ]: 0 : if (!ti->tfe->netdev)
334 : : /* just-opened tun file */
335 : : return fd;
336 : :
337 : 0 : tl = find_tun_link(ti->tfe->netdev);
338 [ # # ]: 0 : if (!tl) {
339 : 0 : pr_err("No tun device for file %s\n", ti->tfe->netdev);
340 : 0 : return -1;
341 : : }
342 : :
343 : : memset(&ifr, 0, sizeof(ifr));
344 : 0 : strlcpy(ifr.ifr_name, tl->name, sizeof(ifr.ifr_name));
345 : 0 : ifr.ifr_flags = tl->rst.flags;
346 : :
347 [ # # ]: 0 : if (ioctl(fd, TUNSETIFF, &ifr) < 0) {
348 : 0 : pr_perror("Can't attach tunfile to device");
349 : 0 : goto err;
350 : : }
351 : :
352 [ # # ][ # # ]: 0 : if (ti->tfe->has_detached && ti->tfe->detached) {
353 : 0 : pr_info("Detaching from %s queue\n", ti->tfe->netdev);
354 : 0 : ifr.ifr_flags = IFF_DETACH_QUEUE;
355 [ # # ]: 0 : if (ioctl(fd, TUNSETQUEUE, &ifr) < 0) {
356 : 0 : pr_perror("Can't detach queue");
357 : 0 : goto err;
358 : : }
359 : : }
360 : :
361 [ # # ]: 0 : if (!(tl->rst.flags & IFF_PERSIST)) {
362 : 0 : pr_info("Dropping persistency for %s\n", tl->name);
363 [ # # ]: 0 : if (ioctl(fd, TUNSETPERSIST, 0) < 0) {
364 : 0 : pr_perror("Error dropping persistency");
365 : 0 : goto err;
366 : : }
367 : : }
368 : :
369 : 0 : return fd;
370 : :
371 : : err:
372 : 0 : close(fd);
373 : 0 : return -1;
374 : : }
375 : :
376 : : static struct file_desc_ops tunfile_desc_ops = {
377 : : .type = FD_TYPES__TUN,
378 : : .open = tunfile_open,
379 : : };
380 : :
381 : 0 : static int collect_one_tunfile(void *o, ProtobufCMessage *base)
382 : : {
383 : : struct tunfile_info *ti = o;
384 : :
385 : 0 : ti->tfe = pb_msg(base, TunfileEntry);
386 : 0 : file_desc_add(&ti->d, ti->tfe->id, &tunfile_desc_ops);
387 : :
388 : 0 : pr_info("Collected %s tunfile\n", ti->tfe->netdev);
389 : :
390 : 0 : return 0;
391 : : }
392 : :
393 : : struct collect_image_info tunfile_cinfo = {
394 : : .fd_type = CR_FD_TUNFILE,
395 : : .pb_type = PB_TUNFILE,
396 : : .priv_size = sizeof(struct tunfile_info),
397 : : .collect = collect_one_tunfile,
398 : : .flags = COLLECT_OPTIONAL,
399 : : };
400 : :
401 : 0 : int dump_tun_link(NetDeviceEntry *nde, struct cr_fdset *fds)
402 : : {
403 : 0 : TunLinkEntry tle = TUN_LINK_ENTRY__INIT;
404 : : char spath[64];
405 : : char buf[64];
406 : : int ret = 0;
407 : : struct tun_link *tl;
408 : :
409 : 0 : sprintf(spath, "class/net/%s/tun_flags", nde->name);
410 : 0 : ret |= read_ns_sys_file(spath, buf, sizeof(buf));
411 : 0 : tle.flags = strtol(buf, NULL, 0);
412 : :
413 : 0 : sprintf(spath, "class/net/%s/owner", nde->name);
414 : 0 : ret |= read_ns_sys_file(spath, buf, sizeof(buf));
415 : 0 : tle.owner = strtol(buf, NULL, 10);
416 : :
417 : 0 : sprintf(spath, "class/net/%s/group", nde->name);
418 : 0 : ret |= read_ns_sys_file(spath, buf, sizeof(buf));
419 : 0 : tle.group = strtol(buf, NULL, 10);
420 : :
421 [ # # ]: 0 : if (ret < 0)
422 : : return ret;
423 : :
424 : 0 : tl = get_tun_link_fd(nde->name, tle.flags);
425 [ # # ]: 0 : if (!tl)
426 : : return ret;
427 : :
428 : 0 : tle.vnethdr = tl->dmp.vnethdr;
429 : 0 : tle.sndbuf = tl->dmp.sndbuf;
430 : :
431 : 0 : nde->tun = &tle;
432 : 0 : return write_netdev_img(nde, fds);
433 : : }
434 : :
435 : 0 : int restore_one_tun(NetDeviceEntry *nde, int nlsk)
436 : : {
437 : : int fd, ret = -1, aux;
438 : :
439 [ # # ]: 0 : if (!nde->tun) {
440 : 0 : pr_err("Corrupted TUN link entry %x\n", nde->ifindex);
441 : 0 : return -1;
442 : : }
443 : :
444 : 0 : pr_info("Restoring tun device %s\n", nde->name);
445 : :
446 : 0 : fd = open_tun_dev(nde->name, nde->ifindex, nde->tun->flags);
447 [ # # ]: 0 : if (fd < 0)
448 : : return -1;
449 : :
450 : 0 : aux = nde->tun->owner;
451 [ # # ][ # # ]: 0 : if ((aux != -1) && ioctl(fd, TUNSETOWNER, aux) < 0) {
452 : 0 : pr_perror("Can't set owner");
453 : 0 : goto out;
454 : : }
455 : :
456 : 0 : aux = nde->tun->group;
457 [ # # ][ # # ]: 0 : if ((aux != -1) && ioctl(fd, TUNSETGROUP, aux) < 0) {
458 : 0 : pr_perror("Can't set group");
459 : 0 : goto out;
460 : : }
461 : :
462 : 0 : aux = nde->tun->sndbuf;
463 [ # # ]: 0 : if (ioctl(fd, TUNSETSNDBUF, &aux) < 0) {
464 : 0 : pr_perror("Can't set sndbuf");
465 : 0 : goto out;
466 : : }
467 : :
468 : 0 : aux = nde->tun->vnethdr;
469 [ # # ]: 0 : if (ioctl(fd, TUNSETVNETHDRSZ, &aux) < 0) {
470 : 0 : pr_perror("Can't set vnethdr");
471 : 0 : goto out;
472 : : }
473 : :
474 : : /*
475 : : * Set this device persistent anyway and schedule
476 : : * the persistence drop if it should not be such.
477 : : * The first _real_ opener will do it.
478 : : */
479 : :
480 [ # # ]: 0 : if (ioctl(fd, TUNSETPERSIST, 1)) {
481 : 0 : pr_perror("Can't make tun device persistent");
482 : 0 : goto out;
483 : : }
484 : :
485 [ # # ]: 0 : if (restore_link_parms(nde, nlsk)) {
486 : 0 : pr_err("Error restoring %s link params\n", nde->name);
487 : 0 : goto out;
488 : : }
489 : :
490 : 0 : ret = list_tun_link(nde);
491 : : out:
492 : 0 : close(fd);
493 : 0 : return ret;
494 : : }
|