Add tunctl.
[util-vserver.git] / src / tunctl.c
1 // $Id$    --*- c -*--
2
3 // Copyright (C) 2008 Daniel Hokka Zakrisson
4 //  
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; version 2 of the License.
8 //  
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // GNU General Public License for more details.
13 //  
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17
18
19 #ifdef HAVE_CONFIG_H
20 #  include <config.h>
21 #endif
22
23 #include "util.h"
24
25 #include <vserver.h>
26
27 #include <getopt.h>
28 #include <errno.h>
29 #include <fcntl.h>
30 #include <unistd.h>
31 #include <sys/ioctl.h>
32 #include <linux/if.h>
33 #include <linux/if_tun.h>
34
35 /* Make sure we have the necessary ioctls */
36 #ifndef TUNSETGROUP
37 #  define TUNSETGROUP           _IOW('T', 206, int)
38 #endif
39 #ifndef TUNSETNID
40 #  define TUNSETNID             _IOW('T', 215, int)
41 #endif
42
43 #define ENSC_WRAPPERS_PREFIX    "tunctl: "
44 #define ENSC_WRAPPERS_UNISTD    1
45 #define ENSC_WRAPPERS_VSERVER   1
46 #define ENSC_WRAPPERS_FCNTL     1
47 #define ENSC_WRAPPERS_IOCTL     1
48 #include <wrappers.h>
49
50
51 #define CMD_HELP                0x1000
52 #define CMD_VERSION             0x1001
53 #define CMD_NID                 0x0001
54 #define CMD_DEVICE              0x0002
55 #define CMD_PERSIST             0x0004
56 #define CMD_NOPERSIST           0x0008
57 #define CMD_CSUM                0x0010
58 #define CMD_NOCSUM              0x0020
59 #define CMD_UID                 0x0040
60 #define CMD_GID                 0x0080
61 #define CMD_LINKTYPE            0x0100
62 #define CMD_TUN                 0x0200
63 #define CMD_TAP                 0x0400
64
65 int             wrapper_exit_code  =  255;
66
67 struct option const
68 CMDLINE_OPTIONS[] = {
69   { "help",       no_argument,       0, CMD_HELP },
70   { "version",    no_argument,       0, CMD_VERSION },
71   { "nid",        required_argument, 0, CMD_NID },
72   { "device",     required_argument, 0, CMD_DEVICE },
73   { "persist",    no_argument,       0, CMD_PERSIST },
74   { "~persist",   no_argument,       0, CMD_NOPERSIST },
75   { "checksum",   no_argument,       0, CMD_CSUM },
76   { "~checksum",  no_argument,       0, CMD_NOCSUM },
77   { "uid",        required_argument, 0, CMD_UID },
78   { "gid",        required_argument, 0, CMD_GID },
79   { "linktype",   required_argument, 0, CMD_LINKTYPE },
80   { "tun",        no_argument,       0, CMD_TUN },
81   { "tap",        no_argument,       0, CMD_TAP },
82   {0,0,0,0}
83 };
84
85 struct Arguments {
86   unsigned int set;
87   nid_t nid;
88   char *device;
89   unsigned persist : 1;
90   unsigned checksum : 1;
91   uid_t uid;
92   gid_t gid;
93   int linktype;
94   int type;
95 };
96
97 static void
98 showHelp(int fd, char const *cmd, int res)
99 {
100   WRITE_MSG(fd, "Usage: ");
101   WRITE_STR(fd, cmd);
102   WRITE_MSG(fd,
103             " {--tun|--tap}\n"
104             "    [--persist|--~persist] [--checksum|--~checksum]\n"
105             "    [--nid <nid>] [--uid <uid>] [--gid <gid>] [--linktype <link type>]\n"
106             "    <interface(s)>...\n"
107             "\n"
108             "Please report bugs to " PACKAGE_BUGREPORT "\n");
109
110   exit(res);
111 }
112
113 static void
114 showVersion()
115 {
116   WRITE_MSG(1,
117             "tunctl " VERSION " -- controls TUN/TAP devices\n"
118             "This program is part of " PACKAGE_STRING "\n\n"
119             "Copyright (C) 2008 Daniel Hokka Zakrisson\n"
120             VERSION_COPYRIGHT_DISCLAIMER);
121   exit(0);
122 }
123
124 static void
125 doTunctl(struct Arguments *args, char *interface)
126 {
127   int fd;
128   struct ifreq ifr;
129
130   fd = EopenD(args->device, O_RDWR, 0);
131
132   strncpy(ifr.ifr_name, interface, IFNAMSIZ);
133   ifr.ifr_name[IFNAMSIZ-1] = '\0';
134   ifr.ifr_flags = args->type;
135   EioctlD(fd, TUNSETIFF, &ifr);
136
137   if (args->set & (CMD_PERSIST|CMD_NOPERSIST))
138     EioctlD(fd, TUNSETPERSIST, (void *) (long) args->persist);
139   if (args->set & (CMD_CSUM|CMD_NOCSUM))
140     EioctlD(fd, TUNSETNOCSUM, (void *) (long) !args->checksum);
141   if (args->set & CMD_UID)
142     EioctlD(fd, TUNSETOWNER, (void *) (long) args->uid);
143   if (args->set & CMD_GID)
144     EioctlD(fd, TUNSETGROUP, (void *) (long) args->gid);
145   if (args->set & CMD_NID)
146     EioctlD(fd, TUNSETNID, (void *) (long) args->nid);
147   if (args->set & CMD_LINKTYPE)
148     EioctlD(fd, TUNSETLINK, (void *) (long) args->linktype);
149
150   close(fd);
151 }
152
153 int main(int argc, char *argv[])
154 {
155   struct Arguments args = {
156     .set = 0,
157     .nid = VC_NOCTX,
158     .device = "/dev/net/tun",
159     .persist = 0,
160     .checksum = 0,
161     .uid = -1,
162     .gid = -1,
163     .linktype = -1,
164     .type = IFF_TUN,
165   };
166   char **interface;
167   
168   while (1) {
169     int         c = getopt_long(argc, argv, "+", CMDLINE_OPTIONS, 0);
170     signed long tmp = 0;
171     if (c==-1) break;
172
173     switch (c) {
174       case CMD_HELP     :  showHelp(1, argv[0], 0);
175       case CMD_VERSION  :  showVersion();
176
177       case CMD_NID      :  args.nid = Evc_nidopt2nid(optarg, true);     break;
178       case CMD_DEVICE   :  args.device = optarg;                        break;
179       case CMD_PERSIST  :  args.persist = 1;                            break;
180       case CMD_NOPERSIST:  args.persist = 0;                            break;
181       case CMD_CSUM     :  args.checksum = 1;                           break;
182       case CMD_NOCSUM   :  args.checksum = 0;                           break;
183       case CMD_TUN      :  args.type = IFF_TUN;                         break;
184       case CMD_TAP      :  args.type = IFF_TAP;                         break;
185       case CMD_UID      :
186         if (!isNumber(optarg, &tmp, true)) {
187           WRITE_MSG(2, "Uid '");
188           WRITE_STR(2, optarg);
189           WRITE_MSG(2, "' is not an integer.\n");
190         }
191         args.uid = (uid_t) tmp;
192         break;
193       case CMD_GID      :
194         if (!isNumber(optarg, &tmp, true)) {
195           WRITE_MSG(2, "Gid '");
196           WRITE_STR(2, optarg);
197           WRITE_MSG(2, "' is not an integer.\n");
198         }
199         args.gid = (gid_t) tmp;
200         break;
201       case CMD_LINKTYPE :
202         if (!isNumber(optarg, &tmp, true)) {
203           WRITE_MSG(2, "Link-type '");
204           WRITE_STR(2, optarg);
205           WRITE_STR(2, "' is not an integer.\n");
206         }
207         args.linktype = (int) tmp;
208         break;
209
210       default           :
211         WRITE_MSG(2, "Try '");
212         WRITE_STR(2, argv[0]);
213         WRITE_MSG(2, " --help' for more information.\n");
214         return 255;
215         break;
216     }
217
218     args.set |= c;
219   }
220
221   for (interface = argv + optind; *interface; interface++) {
222     doTunctl(&args, *interface);
223   }
224
225   return EXIT_SUCCESS;
226 }