]>
git.proxmox.com Git - mirror_iproute2.git/blob - ip/iptuntap.c
2 * iptunnel.c "ip tuntap"
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
9 * Authors: David Woodhouse <David.Woodhouse@intel.com>
17 #include <sys/types.h>
18 #include <sys/socket.h>
19 #include <arpa/inet.h>
20 #include <sys/ioctl.h>
22 #include <linux/if_tun.h>
31 #include "ip_common.h"
33 #define TUNDEV "/dev/net/tun"
35 static void usage(void) __attribute__((noreturn
));
37 static void usage(void)
39 fprintf(stderr
, "Usage: ip tuntap { add | del } [ dev PHYS_DEV ] \n");
40 fprintf(stderr
, " [ mode { tun | tap } ] [ user USER ] [ group GROUP ]\n");
41 fprintf(stderr
, " [ one_queue ] [ pi ] [ vnet_hdr ]\n");
42 fprintf(stderr
, "\n");
43 fprintf(stderr
, "Where: USER := { STRING | NUMBER }\n");
44 fprintf(stderr
, " GROUP := { STRING | NUMBER }\n");
48 static int tap_add_ioctl(struct ifreq
*ifr
, uid_t uid
, gid_t gid
)
54 ifr
->ifr_flags
|= IFF_TUN_EXCL
;
57 fd
= open(TUNDEV
, O_RDWR
);
62 if (ioctl(fd
, TUNSETIFF
, ifr
)) {
63 perror("ioctl(TUNSETIFF)");
66 if (uid
!= -1 && ioctl(fd
, TUNSETOWNER
, uid
)) {
67 perror("ioctl(TUNSETOWNER)");
70 if (gid
!= -1 && ioctl(fd
, TUNSETGROUP
, gid
)) {
71 perror("ioctl(TUNSETGROUP)");
74 if (ioctl(fd
, TUNSETPERSIST
, 1)) {
75 perror("ioctl(TUNSETPERSIST)");
84 static int tap_del_ioctl(struct ifreq
*ifr
)
86 int fd
= open(TUNDEV
, O_RDWR
);
93 if (ioctl(fd
, TUNSETIFF
, ifr
)) {
94 perror("ioctl(TUNSETIFF)");
97 if (ioctl(fd
, TUNSETPERSIST
, 0)) {
98 perror("ioctl(TUNSETPERSIST)");
107 static int parse_args(int argc
, char **argv
, struct ifreq
*ifr
, uid_t
*uid
, gid_t
*gid
)
111 memset(ifr
, 0, sizeof(*ifr
));
113 ifr
->ifr_flags
|= IFF_NO_PI
;
116 if (matches(*argv
, "mode") == 0) {
118 if (matches(*argv
, "tun") == 0) {
119 if (ifr
->ifr_flags
& IFF_TAP
) {
120 fprintf(stderr
,"You managed to ask for more than one tunnel mode.\n");
123 ifr
->ifr_flags
|= IFF_TUN
;
124 } else if (matches(*argv
, "tap") == 0) {
125 if (ifr
->ifr_flags
& IFF_TUN
) {
126 fprintf(stderr
,"You managed to ask for more than one tunnel mode.\n");
129 ifr
->ifr_flags
|= IFF_TAP
;
131 fprintf(stderr
,"Cannot guess tunnel mode.\n");
134 } else if (uid
&& matches(*argv
, "user") == 0) {
139 if (**argv
&& ((user
= strtol(*argv
, &end
, 10)), !*end
))
142 struct passwd
*pw
= getpwnam(*argv
);
144 fprintf(stderr
, "invalid user \"%s\"\n", *argv
);
149 } else if (gid
&& matches(*argv
, "group") == 0) {
155 if (**argv
&& ((group
= strtol(*argv
, &end
, 10)), !*end
))
158 struct group
*gr
= getgrnam(*argv
);
160 fprintf(stderr
, "invalid group \"%s\"\n", *argv
);
165 } else if (matches(*argv
, "pi") == 0) {
166 ifr
->ifr_flags
&= ~IFF_NO_PI
;
167 } else if (matches(*argv
, "one_queue") == 0) {
168 ifr
->ifr_flags
|= IFF_ONE_QUEUE
;
169 } else if (matches(*argv
, "vnet_hdr") == 0) {
170 ifr
->ifr_flags
|= IFF_VNET_HDR
;
171 } else if (matches(*argv
, "dev") == 0) {
173 strncpy(ifr
->ifr_name
, *argv
, IFNAMSIZ
-1);
175 if (matches(*argv
, "name") == 0) {
177 } else if (matches(*argv
, "help") == 0)
179 if (ifr
->ifr_name
[0])
180 duparg2("name", *argv
);
181 strncpy(ifr
->ifr_name
, *argv
, IFNAMSIZ
);
191 static int do_add(int argc
, char **argv
)
197 if (parse_args(argc
, argv
, &ifr
, &uid
, &gid
) < 0)
200 if (!(ifr
.ifr_flags
& TUN_TYPE_MASK
)) {
201 fprintf(stderr
, "You failed to specify a tunnel mode\n");
204 return tap_add_ioctl(&ifr
, uid
, gid
);
207 static int do_del(int argc
, char **argv
)
211 if (parse_args(argc
, argv
, &ifr
, NULL
, NULL
) < 0)
214 return tap_del_ioctl(&ifr
);
217 static int read_prop(char *dev
, char *prop
, long *value
)
219 char fname
[IFNAMSIZ
+25], buf
[80], *endp
;
224 sprintf(fname
, "/sys/class/net/%s/%s", dev
, prop
);
225 fd
= open(fname
, O_RDONLY
);
227 if (strcmp(prop
, "tun_flags"))
228 fprintf(stderr
, "open %s: %s\n", fname
,
232 len
= read(fd
, buf
, sizeof(buf
)-1);
235 fprintf(stderr
, "read %s: %s", fname
, strerror(errno
));
240 result
= strtol(buf
, &endp
, 0);
242 fprintf(stderr
, "Failed to parse %s\n", fname
);
249 static void print_flags(long flags
)
257 if (!(flags
& IFF_NO_PI
))
260 if (flags
& IFF_ONE_QUEUE
)
261 printf(" one_queue");
263 if (flags
& IFF_VNET_HDR
)
266 flags
&= ~(IFF_TUN
|IFF_TAP
|IFF_NO_PI
|IFF_ONE_QUEUE
|IFF_VNET_HDR
);
268 printf(" UNKNOWN_FLAGS:%lx", flags
);
271 static int do_show(int argc
, char **argv
)
275 long flags
, owner
= -1, group
= -1;
277 dir
= opendir("/sys/class/net");
282 while ((d
= readdir(dir
))) {
283 if (d
->d_name
[0] == '.' &&
284 (d
->d_name
[1] == 0 || d
->d_name
[1] == '.'))
287 if (read_prop(d
->d_name
, "tun_flags", &flags
))
290 read_prop(d
->d_name
, "owner", &owner
);
291 read_prop(d
->d_name
, "group", &group
);
293 printf("%s:", d
->d_name
);
296 printf(" user %ld", owner
);
298 printf(" group %ld", group
);
305 int do_iptuntap(int argc
, char **argv
)
308 if (matches(*argv
, "add") == 0)
309 return do_add(argc
-1, argv
+1);
310 if (matches(*argv
, "del") == 0)
311 return do_del(argc
-1, argv
+1);
312 if (matches(*argv
, "show") == 0 ||
313 matches(*argv
, "lst") == 0 ||
314 matches(*argv
, "list") == 0)
315 return do_show(argc
-1, argv
+1);
316 if (matches(*argv
, "help") == 0)
319 return do_show(0, NULL
);
321 fprintf(stderr
, "Command \"%s\" is unknown, try \"ip tuntap help\".\n",