blob: fa904c2a947208cfae67cf5646028830fdeed32b
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" |
14 | //config: default y |
15 | //config: select PLATFORM_LINUX |
16 | //config: help |
17 | //config: tunctl creates or deletes tun devices. |
18 | //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 |
24 | //config: Allow to specify owner and group of newly created interface. |
25 | //config: 340 bytes of pure bloat. Say no here. |
26 | |
27 | //applet:IF_TUNCTL(APPLET(tunctl, BB_DIR_SBIN, BB_SUID_DROP)) |
28 | |
29 | //kbuild:lib-$(CONFIG_TUNCTL) += tunctl.o |
30 | |
31 | //usage:#define tunctl_trivial_usage |
32 | //usage: "[-f device] ([-t name] | -d name)" IF_FEATURE_TUNCTL_UG(" [-u owner] [-g group] [-b]") |
33 | //usage:#define tunctl_full_usage "\n\n" |
34 | //usage: "Create or delete tun interfaces\n" |
35 | //usage: "\n -f name tun device (/dev/net/tun)" |
36 | //usage: "\n -t name Create iface 'name'" |
37 | //usage: "\n -d name Delete iface 'name'" |
38 | //usage: IF_FEATURE_TUNCTL_UG( |
39 | //usage: "\n -u owner Set iface owner" |
40 | //usage: "\n -g group Set iface group" |
41 | //usage: "\n -b Brief output" |
42 | //usage: ) |
43 | //usage: |
44 | //usage:#define tunctl_example_usage |
45 | //usage: "# tunctl\n" |
46 | //usage: "# tunctl -d tun0\n" |
47 | |
48 | #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 | |
62 | int tunctl_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
63 | int 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 | |
86 | opt_complementary = "=0:t--d:d--t"; // no arguments; t ^ d |
87 | opts = getopt32(argv, "f:t:d:" IF_FEATURE_TUNCTL_UG("u:g:b"), |
88 | &opt_device, &opt_name, &opt_name |
89 | IF_FEATURE_TUNCTL_UG(, &opt_user, &opt_group)); |
90 | |
91 | // select device |
92 | memset(&ifr, 0, sizeof(ifr)); |
93 | ifr.ifr_flags = IFF_TAP | IFF_NO_PI; |
94 | strncpy_IFNAMSIZ(ifr.ifr_name, opt_name); |
95 | |
96 | // open device |
97 | fd = xopen(opt_device, O_RDWR); |
98 | IOCTL(fd, TUNSETIFF, (void *)&ifr); |
99 | |
100 | // delete? |
101 | if (opts & OPT_d) { |
102 | IOCTL(fd, TUNSETPERSIST, (void *)(uintptr_t)0); |
103 | printf("Set '%s' nonpersistent\n", ifr.ifr_name); |
104 | return EXIT_SUCCESS; |
105 | } |
106 | |
107 | // create |
108 | #if ENABLE_FEATURE_TUNCTL_UG |
109 | if (opts & OPT_g) { |
110 | group = xgroup2gid(opt_group); |
111 | IOCTL(fd, TUNSETGROUP, (void *)(uintptr_t)group); |
112 | } else |
113 | user = geteuid(); |
114 | if (opts & OPT_u) |
115 | user = xuname2uid(opt_user); |
116 | IOCTL(fd, TUNSETOWNER, (void *)(uintptr_t)user); |
117 | #endif |
118 | IOCTL(fd, TUNSETPERSIST, (void *)(uintptr_t)1); |
119 | |
120 | // show info |
121 | #if ENABLE_FEATURE_TUNCTL_UG |
122 | if (opts & OPT_b) { |
123 | puts(ifr.ifr_name); |
124 | } else { |
125 | printf("Set '%s' %spersistent", ifr.ifr_name, ""); |
126 | printf(" and owned by uid %ld", user); |
127 | if (group != -1) |
128 | printf(" gid %ld", group); |
129 | bb_putchar('\n'); |
130 | } |
131 | #else |
132 | puts(ifr.ifr_name); |
133 | #endif |
134 | return EXIT_SUCCESS; |
135 | } |
136 | |
137 | #else |
138 | |
139 | /* -210 bytes: */ |
140 | |
141 | int tunctl_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
142 | int tunctl_main(int argc UNUSED_PARAM, char **argv) |
143 | { |
144 | struct ifreq ifr; |
145 | int fd; |
146 | const char *opt_name = "tap%d"; |
147 | const char *opt_device = "/dev/net/tun"; |
148 | unsigned opts; |
149 | |
150 | enum { |
151 | OPT_f = 1 << 0, // control device name (/dev/net/tun) |
152 | OPT_t = 1 << 1, // create named interface |
153 | OPT_d = 1 << 2, // delete named interface |
154 | }; |
155 | |
156 | opt_complementary = "=0:t--d:d--t"; // no arguments; t ^ d |
157 | opts = getopt32(argv, "f:t:d:u:g:b", // u, g, b accepted and ignored |
158 | &opt_device, &opt_name, &opt_name, NULL, NULL); |
159 | |
160 | // set interface name |
161 | memset(&ifr, 0, sizeof(ifr)); |
162 | ifr.ifr_flags = IFF_TAP | IFF_NO_PI; |
163 | strncpy_IFNAMSIZ(ifr.ifr_name, opt_name); |
164 | |
165 | // open device |
166 | fd = xopen(opt_device, O_RDWR); |
167 | IOCTL(fd, TUNSETIFF, (void *)&ifr); |
168 | |
169 | // create or delete interface |
170 | IOCTL(fd, TUNSETPERSIST, (void *)(uintptr_t)(0 == (opts & OPT_d))); |
171 | |
172 | return EXIT_SUCCESS; |
173 | } |
174 | |
175 | #endif |
176 |