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