blob: 59cae331c0f39e0a32ed6104b122553b9767f3fd [file] [log] [blame]
Denis Vlasenko39b68132009-01-23 02:07:14 +00001/* vi: set sw=4 ts=4: */
2/*
3 * tun devices controller
4 *
5 * Copyright (C) 2008 by Vladimir Dronnikov <dronnikov@gmail.com>
6 *
7 * Original code:
8 * Jeff Dike
9 *
Denys Vlasenko0ef64bd2010-08-16 20:14:46 +020010 * Licensed under GPLv2, see file LICENSE in this source tree.
Denis Vlasenko39b68132009-01-23 02:07:14 +000011 */
Denys Vlasenko47367e12016-11-23 09:05:14 +010012//config:config TUNCTL
Denys Vlasenkob097a842018-12-28 03:20:17 +010013//config: bool "tunctl (6.2 kb)"
Denys Vlasenko47367e12016-11-23 09:05:14 +010014//config: default y
Samuel Thibault77216c32022-10-16 02:04:59 +020015//config: select PLATFORM_LINUX
Denys Vlasenko47367e12016-11-23 09:05:14 +010016//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020017//config: tunctl creates or deletes tun devices.
Denys Vlasenko47367e12016-11-23 09:05:14 +010018//config:
19//config:config FEATURE_TUNCTL_UG
20//config: bool "Support owner:group assignment"
21//config: default y
22//config: depends on TUNCTL
23//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020024//config: Allow to specify owner and group of newly created interface.
25//config: 340 bytes of pure bloat. Say no here.
Denys Vlasenko47367e12016-11-23 09:05:14 +010026
Denys Vlasenko9a58cc02017-08-06 12:28:00 +020027//applet:IF_TUNCTL(APPLET_NOEXEC(tunctl, tunctl, BB_DIR_SBIN, BB_SUID_DROP, tunctl))
Denys Vlasenko47367e12016-11-23 09:05:14 +010028
29//kbuild:lib-$(CONFIG_TUNCTL) += tunctl.o
Pere Orga5bc8c002011-04-11 03:29:49 +020030
31//usage:#define tunctl_trivial_usage
Denys Vlasenkoa2f18d92020-12-18 04:12:51 +010032//usage: "[-f DEVICE] [-t NAME | -d NAME]" IF_FEATURE_TUNCTL_UG(" [-u USER] [-g GRP] [-b]")
Pere Orga5bc8c002011-04-11 03:29:49 +020033//usage:#define tunctl_full_usage "\n\n"
Denys Vlasenkoa2f18d92020-12-18 04:12:51 +010034//usage: "Create or delete TUN/TAP interfaces\n"
35//usage: "\n -f DEV TUN device (default /dev/net/tun)"
36//usage: "\n -t NAME Create iface (default: tapN)"
37//usage: "\n -d NAME Delete iface"
Pere Orga5bc8c002011-04-11 03:29:49 +020038//usage: IF_FEATURE_TUNCTL_UG(
Denys Vlasenkoa2f18d92020-12-18 04:12:51 +010039//usage: "\n -u USER Set iface owner"
40//usage: "\n -g GRP Set iface group"
41//usage: "\n -b Brief output"
Pere Orga5bc8c002011-04-11 03:29:49 +020042//usage: )
43//usage:
44//usage:#define tunctl_example_usage
45//usage: "# tunctl\n"
46//usage: "# tunctl -d tun0\n"
47
Denis Vlasenko39b68132009-01-23 02:07:14 +000048#include <netinet/in.h>
49#include <net/if.h>
50#include <linux/if_tun.h>
51#include "libbb.h"
52
53/* TUNSETGROUP appeared in 2.6.23 */
54#ifndef TUNSETGROUP
55#define TUNSETGROUP _IOW('T', 206, int)
56#endif
57
58#define IOCTL(a, b, c) ioctl_or_perror_and_die(a, b, c, NULL)
59
60#if 1
61
62int tunctl_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
63int tunctl_main(int argc UNUSED_PARAM, char **argv)
64{
65 struct ifreq ifr;
66 int fd;
67 const char *opt_name = "tap%d";
68 const char *opt_device = "/dev/net/tun";
69#if ENABLE_FEATURE_TUNCTL_UG
70 const char *opt_user, *opt_group;
71 long user = -1, group = -1;
72#endif
73 unsigned opts;
74
75 enum {
76 OPT_f = 1 << 0, // control device name (/dev/net/tun)
77 OPT_t = 1 << 1, // create named interface
78 OPT_d = 1 << 2, // delete named interface
79#if ENABLE_FEATURE_TUNCTL_UG
80 OPT_u = 1 << 3, // set new interface owner
81 OPT_g = 1 << 4, // set new interface group
82 OPT_b = 1 << 5, // brief output
83#endif
84 };
85
Denys Vlasenko22542ec2017-08-08 21:55:02 +020086 opts = getopt32(argv, "^"
87 "f:t:d:" IF_FEATURE_TUNCTL_UG("u:g:b")
88 "\0"
89 "=0:t--d:d--t", // no arguments; t ^ d
Denis Vlasenko39b68132009-01-23 02:07:14 +000090 &opt_device, &opt_name, &opt_name
Denys Vlasenko22542ec2017-08-08 21:55:02 +020091 IF_FEATURE_TUNCTL_UG(, &opt_user, &opt_group)
92 );
Denis Vlasenko39b68132009-01-23 02:07:14 +000093
94 // select device
95 memset(&ifr, 0, sizeof(ifr));
96 ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
97 strncpy_IFNAMSIZ(ifr.ifr_name, opt_name);
98
99 // open device
100 fd = xopen(opt_device, O_RDWR);
101 IOCTL(fd, TUNSETIFF, (void *)&ifr);
102
103 // delete?
104 if (opts & OPT_d) {
105 IOCTL(fd, TUNSETPERSIST, (void *)(uintptr_t)0);
Denys Vlasenko066e76b2016-03-30 16:20:28 +0200106 printf("Set '%s' nonpersistent\n", ifr.ifr_name);
Denis Vlasenko39b68132009-01-23 02:07:14 +0000107 return EXIT_SUCCESS;
108 }
109
110 // create
111#if ENABLE_FEATURE_TUNCTL_UG
112 if (opts & OPT_g) {
113 group = xgroup2gid(opt_group);
114 IOCTL(fd, TUNSETGROUP, (void *)(uintptr_t)group);
115 } else
116 user = geteuid();
117 if (opts & OPT_u)
118 user = xuname2uid(opt_user);
119 IOCTL(fd, TUNSETOWNER, (void *)(uintptr_t)user);
120#endif
121 IOCTL(fd, TUNSETPERSIST, (void *)(uintptr_t)1);
122
123 // show info
124#if ENABLE_FEATURE_TUNCTL_UG
125 if (opts & OPT_b) {
126 puts(ifr.ifr_name);
127 } else {
128 printf("Set '%s' %spersistent", ifr.ifr_name, "");
129 printf(" and owned by uid %ld", user);
130 if (group != -1)
131 printf(" gid %ld", group);
132 bb_putchar('\n');
133 }
134#else
135 puts(ifr.ifr_name);
136#endif
137 return EXIT_SUCCESS;
138}
139
140#else
141
142/* -210 bytes: */
143
144int tunctl_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
145int tunctl_main(int argc UNUSED_PARAM, char **argv)
146{
147 struct ifreq ifr;
148 int fd;
149 const char *opt_name = "tap%d";
150 const char *opt_device = "/dev/net/tun";
151 unsigned opts;
152
153 enum {
154 OPT_f = 1 << 0, // control device name (/dev/net/tun)
155 OPT_t = 1 << 1, // create named interface
156 OPT_d = 1 << 2, // delete named interface
157 };
158
Denys Vlasenko22542ec2017-08-08 21:55:02 +0200159 opts = getopt32(argv, "^"
160 "f:t:d:u:g:b" // u, g, b accepted and ignored
161 "\0"
162 "=0:t--d:d--t", // no arguments; t ^ d
163 &opt_device, &opt_name, &opt_name, NULL, NULL
164 );
Denis Vlasenko39b68132009-01-23 02:07:14 +0000165
166 // set interface name
167 memset(&ifr, 0, sizeof(ifr));
168 ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
169 strncpy_IFNAMSIZ(ifr.ifr_name, opt_name);
170
171 // open device
172 fd = xopen(opt_device, O_RDWR);
173 IOCTL(fd, TUNSETIFF, (void *)&ifr);
174
175 // create or delete interface
176 IOCTL(fd, TUNSETPERSIST, (void *)(uintptr_t)(0 == (opts & OPT_d)));
177
178 return EXIT_SUCCESS;
179}
180
181#endif