1 /* 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  *
10  * Licensed under GPLv2, see file LICENSE in this source tree.
11  */
12 //config:config TUNCTL
13 //config:	bool "tunctl (6.2 kb)"
14 //config:	default y
15 //config:	help
16 //config:	tunctl creates or deletes tun devices.
17 //config:
18 //config:config FEATURE_TUNCTL_UG
19 //config:	bool "Support owner:group assignment"
20 //config:	default y
21 //config:	depends on TUNCTL
22 //config:	help
23 //config:	Allow to specify owner and group of newly created interface.
24 //config:	340 bytes of pure bloat. Say no here.
25 
26 //applet:IF_TUNCTL(APPLET_NOEXEC(tunctl, tunctl, BB_DIR_SBIN, BB_SUID_DROP, tunctl))
27 
28 //kbuild:lib-$(CONFIG_TUNCTL) += tunctl.o
29 
30 //usage:#define tunctl_trivial_usage
31 //usage:       "[-f DEVICE] [-t NAME | -d NAME]" IF_FEATURE_TUNCTL_UG(" [-u USER] [-g GRP] [-b]")
32 //usage:#define tunctl_full_usage "\n\n"
33 //usage:       "Create or delete TUN/TAP interfaces\n"
34 //usage:     "\n	-f DEV	TUN device (default /dev/net/tun)"
35 //usage:     "\n	-t NAME	Create iface (default: tapN)"
36 //usage:     "\n	-d NAME	Delete iface"
37 //usage:	IF_FEATURE_TUNCTL_UG(
38 //usage:     "\n	-u USER	Set iface owner"
39 //usage:     "\n	-g GRP	Set iface group"
40 //usage:     "\n	-b	Brief output"
41 //usage:	)
42 //usage:
43 //usage:#define tunctl_example_usage
44 //usage:       "# tunctl\n"
45 //usage:       "# tunctl -d tun0\n"
46 
47 #include <netinet/in.h>
48 #include <net/if.h>
49 #include <linux/if_tun.h>
50 #include "libbb.h"
51 
52 /* TUNSETGROUP appeared in 2.6.23 */
53 #ifndef TUNSETGROUP
54 #define TUNSETGROUP _IOW('T', 206, int)
55 #endif
56 
57 #define IOCTL(a, b, c) ioctl_or_perror_and_die(a, b, c, NULL)
58 
59 #if 1
60 
61 int tunctl_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
tunctl_main(int argc UNUSED_PARAM,char ** argv)62 int tunctl_main(int argc UNUSED_PARAM, char **argv)
63 {
64 	struct ifreq ifr;
65 	int fd;
66 	const char *opt_name = "tap%d";
67 	const char *opt_device = "/dev/net/tun";
68 #if ENABLE_FEATURE_TUNCTL_UG
69 	const char *opt_user, *opt_group;
70 	long user = -1, group = -1;
71 #endif
72 	unsigned opts;
73 
74 	enum {
75 		OPT_f = 1 << 0, // control device name (/dev/net/tun)
76 		OPT_t = 1 << 1, // create named interface
77 		OPT_d = 1 << 2, // delete named interface
78 #if ENABLE_FEATURE_TUNCTL_UG
79 		OPT_u = 1 << 3, // set new interface owner
80 		OPT_g = 1 << 4, // set new interface group
81 		OPT_b = 1 << 5, // brief output
82 #endif
83 	};
84 
85 	opts = getopt32(argv, "^"
86 			"f:t:d:" IF_FEATURE_TUNCTL_UG("u:g:b")
87 			"\0"
88 			"=0:t--d:d--t", // no arguments; t ^ d
89 			&opt_device, &opt_name, &opt_name
90 			IF_FEATURE_TUNCTL_UG(, &opt_user, &opt_group)
91 	);
92 
93 	// select device
94 	memset(&ifr, 0, sizeof(ifr));
95 	ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
96 	strncpy_IFNAMSIZ(ifr.ifr_name, opt_name);
97 
98 	// open device
99 	fd = xopen(opt_device, O_RDWR);
100 	IOCTL(fd, TUNSETIFF, (void *)&ifr);
101 
102 	// delete?
103 	if (opts & OPT_d) {
104 		IOCTL(fd, TUNSETPERSIST, (void *)(uintptr_t)0);
105 		printf("Set '%s' nonpersistent\n", ifr.ifr_name);
106 		return EXIT_SUCCESS;
107 	}
108 
109 	// create
110 #if ENABLE_FEATURE_TUNCTL_UG
111 	if (opts & OPT_g) {
112 		group = xgroup2gid(opt_group);
113 		IOCTL(fd, TUNSETGROUP, (void *)(uintptr_t)group);
114 	} else
115 		user = geteuid();
116 	if (opts & OPT_u)
117 		user = xuname2uid(opt_user);
118 	IOCTL(fd, TUNSETOWNER, (void *)(uintptr_t)user);
119 #endif
120 	IOCTL(fd, TUNSETPERSIST, (void *)(uintptr_t)1);
121 
122 	// show info
123 #if ENABLE_FEATURE_TUNCTL_UG
124 	if (opts & OPT_b) {
125 		puts(ifr.ifr_name);
126 	} else {
127 		printf("Set '%s' %spersistent", ifr.ifr_name, "");
128 		printf(" and owned by uid %ld", user);
129 		if (group != -1)
130 			printf(" gid %ld", group);
131 		bb_putchar('\n');
132 	}
133 #else
134 	puts(ifr.ifr_name);
135 #endif
136 	return EXIT_SUCCESS;
137 }
138 
139 #else
140 
141 /* -210 bytes: */
142 
143 int tunctl_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
tunctl_main(int argc UNUSED_PARAM,char ** argv)144 int tunctl_main(int argc UNUSED_PARAM, char **argv)
145 {
146 	struct ifreq ifr;
147 	int fd;
148 	const char *opt_name = "tap%d";
149 	const char *opt_device = "/dev/net/tun";
150 	unsigned opts;
151 
152 	enum {
153 		OPT_f = 1 << 0, // control device name (/dev/net/tun)
154 		OPT_t = 1 << 1, // create named interface
155 		OPT_d = 1 << 2, // delete named interface
156 	};
157 
158 	opts = getopt32(argv, "^"
159 			"f:t:d:u:g:b" // u, g, b accepted and ignored
160 			"\0"
161 			"=0:t--d:d--t", // no arguments; t ^ d
162 			&opt_device, &opt_name, &opt_name, NULL, NULL
163 	);
164 
165 	// set interface name
166 	memset(&ifr, 0, sizeof(ifr));
167 	ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
168 	strncpy_IFNAMSIZ(ifr.ifr_name, opt_name);
169 
170 	// open device
171 	fd = xopen(opt_device, O_RDWR);
172 	IOCTL(fd, TUNSETIFF, (void *)&ifr);
173 
174 	// create or delete interface
175 	IOCTL(fd, TUNSETPERSIST, (void *)(uintptr_t)(0 == (opts & OPT_d)));
176 
177 	return EXIT_SUCCESS;
178 }
179 
180 #endif
181