From d2bdbc297ce4bd3f2c58f90157aebf7313efec3f Mon Sep 17 00:00:00 2001 From: Alyssa Ross Date: Sun, 15 Dec 2019 16:20:15 +0000 Subject: Support both TUN and TAP devices --- .gitignore | 2 +- Makefile | 8 ++-- README | 12 +++--- TODO | 2 - mktap.8 | 59 ------------------------- mktap.c | 141 ------------------------------------------------------------ mktuntap.8 | 69 ++++++++++++++++++++++++++++++ mktuntap.c | 142 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 222 insertions(+), 213 deletions(-) delete mode 100644 mktap.8 delete mode 100644 mktap.c create mode 100644 mktuntap.8 create mode 100644 mktuntap.c diff --git a/.gitignore b/.gitignore index 39ca1ef..7e27746 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ result result-* *.o -/mktap \ No newline at end of file +/mktuntap \ No newline at end of file diff --git a/Makefile b/Makefile index 054b56f..ff52ac4 100644 --- a/Makefile +++ b/Makefile @@ -15,7 +15,7 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -all: mktap +all: mktuntap .PHONY: all prefix = /usr/local @@ -36,7 +36,7 @@ install-dirs: $(MKDIR_P) $(DESTDIR)$(bindir) $(DESTDIR)$(man8dir) .PHONY: install-dirs -install: mktap install-dirs - $(INSTALL_PROGRAM) mktap $(DESTDIR)$(bindir)/ - $(INSTALL_DATA) mktap.8 $(DESTDIR)$(man8dir)/ +install: mktuntap install-dirs + $(INSTALL_PROGRAM) mktuntap $(DESTDIR)$(bindir)/ + $(INSTALL_DATA) mktuntap.8 $(DESTDIR)$(man8dir)/ .PHONY: install diff --git a/README b/README index 8b71fee..84769aa 100644 --- a/README +++ b/README @@ -1,13 +1,13 @@ -mktap ------ +mktuntap +-------- -creates a tap device on a specified file descriptor, and then execs -into the rest of argv. +creates a tun or tap device on a specified file descriptor, and then +execs into the rest of argv. -mktap makes use of example code from the Linux kernel, and as such is +mktuntap makes use of example code from the Linux kernel, and as such is licensed under (only) version 2 of the GNU General Public License as published by the Free Software Foundation. Other source files are licensed under the GNU General Public License, either version 2 of the License, or (at your option) any later -version. \ No newline at end of file +version. diff --git a/TODO b/TODO index 3cc51c7..7c9b18a 100644 --- a/TODO +++ b/TODO @@ -1,4 +1,2 @@ -* Give choice between tun/tap with -n | -p (like tunctl), and rename - to mktuntap * Reimplement tap_alloc for compatibility with newer GPLs * Refer to % formats available for ifr_name diff --git a/mktap.8 b/mktap.8 deleted file mode 100644 index 6e7815e..0000000 --- a/mktap.8 +++ /dev/null @@ -1,59 +0,0 @@ -.\" SPDX-License-Identifier: GPL-2.0-or-later -.\" -.\" Copyright 2019 Alyssa Ross -.\" -.\" This program is free software: you can redistribute it and/or modify -.\" it under the terms of the GNU General Public License as published by -.\" the Free Software Foundation, either version 2 of the License, or -.\" (at your option) any later version. -.\" -.\" This program is distributed in the hope that it will be useful, -.\" but WITHOUT ANY WARRANTY; without even the implied warranty of -.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -.\" GNU General Public License for more details. -.\" -.\" You should have received a copy of the GNU General Public License -.\" along with this program. If not, see . -.Dd December 15, 2019 -.Dt MKTAP 8 -.Os Linux -.Sh NAME -.Nm mktap -.Nd create and open a tap device on a file descriptor, then exec -.Sh SYNOPSIS -.Nm -.Op Fl E -.Op Fl i Ar ifr_name -.Ar fd -.Ar prog... -.Sh DESCRIPTION -Create a tap device named with format -.Ar ifr_name , -open it on file descriptor -.Ar fd , -set the TUNTAP_NAME variable in the environment to the name of the -opened device, and then exec into -.Ar prog . -.Pp -The arguments are as follows: -.Bl -tag -width Ds -.It Fl E -Don't set the TUNTAP_NAME environment variable. Caution: if you use -this without using -.Fl i -to set a static device name, it will be difficult to determine the -device name later. -.It Fl i -Set the name for the device. If present, the character sequence -.Dq %d -will be replaced with a number to create a unique name. Default: -.Dq tap%d . -.El -.Sh EXIT STATUS -.Ex -std -See -.Xr sysexits 3 -for further details. -.Sh SEE ALSO -.Xr tunctl 8 , -.Xr ip 8 diff --git a/mktap.c b/mktap.c deleted file mode 100644 index 8e0b5bf..0000000 --- a/mktap.c +++ /dev/null @@ -1,141 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only - -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -// Adapted 2019-12-14 from Documentation/networking/tuntap.txt in Linux. -int tap_alloc(char *dev) -{ - struct ifreq ifr; - int fd, err; - - if ((fd = open("/dev/net/tun", O_RDWR)) < 0) - return -1; - - memset(&ifr, 0, sizeof(ifr)); - - /* Flags: IFF_TUN - TUN device (no Ethernet headers) - * IFF_TAP - TAP device - * - * IFF_NO_PI - Do not provide packet information - */ - ifr.ifr_flags = IFF_TAP; - if (*dev) - strncpy(ifr.ifr_name, dev, IFNAMSIZ); - - if ((err = ioctl(fd, TUNSETIFF, (void *) &ifr)) < 0) { - close(fd); - return err; - } - strcpy(dev, ifr.ifr_name); - return fd; -} - -void ex_usage() -{ - fputs("mktap: usage: mktap [-E] [-i ifr_name] fd prog...\n", stderr); - exit(EX_USAGE); -} - -int main(int argc, char **argv) -{ - char *ifr_name_in = NULL; - bool name_env = true; - - int c; - while ((c = getopt(argc, argv, "+Ei:")) != -1) { - switch (c) { - case 'E': - name_env = false; - break; - case 'i': - ifr_name_in = optarg; - break; - default: - ex_usage(); - } - } - - if (argc - optind < 2) - ex_usage(); - - // ifr_name is a macro, so add a trailing _. - char *ifr_name_ = calloc(IFNAMSIZ, sizeof(char)); - if (ifr_name_in) { - if (strlen(ifr_name_in) > IFNAMSIZ - 1) { - fprintf(stderr, "mktap: ifr_name too long (max %i)\n", IFNAMSIZ - 1); - return EX_USAGE; - } - strcpy(ifr_name_, ifr_name_in); - } - - errno = 0; - char *target_fd_end; - long int target_fd_l = strtol(argv[optind], &target_fd_end, 10); - if (errno) { - fprintf(stderr, "mktap: %s\n", strerror(errno)); - return EX_USAGE; - } - if (argv[optind][0] == '\0' || target_fd_end[0] != '\0') { - fprintf(stderr, "mktap: invalid integer: `%s'\n", argv[optind]); - return EX_USAGE; - } - if (target_fd_l < INT_MIN || target_fd_l > INT_MAX) { - fprintf(stderr, "mktap: out of range for file descriptor: `%li'\n", target_fd_l); - return EX_USAGE; - } - int target_fd = (int)target_fd_l; - - int tap_fd = tap_alloc(ifr_name_); - if (tap_fd < 0) { - fprintf(stderr, "mktap: failed to open tap device: %s\n", strerror(errno)); - return EX_IOERR; - } - - if (dup2(tap_fd, target_fd) == -1) { - fprintf(stderr, "mktap: %s\n", strerror(errno)); - return EX_IOERR; - } - if (close(tap_fd) == -1) { - fprintf(stderr, "mktap: %s\n", strerror(errno)); - return EX_IOERR; - } - - if (name_env) { - if (setenv("TUNTAP_NAME", ifr_name_, 1) == -1) { - fprintf(stderr, "mktap: %s\n", strerror(errno)); - return EX_OSERR; - } - } - - execvp(argv[optind + 1], &argv[optind + 1]); - - fprintf(stderr, "failed to exec: %s\n", strerror(errno)); - return EX_OSERR; -} diff --git a/mktuntap.8 b/mktuntap.8 new file mode 100644 index 0000000..7e6414d --- /dev/null +++ b/mktuntap.8 @@ -0,0 +1,69 @@ +.\" SPDX-License-Identifier: GPL-2.0-or-later +.\" +.\" Copyright 2019 Alyssa Ross +.\" +.\" This program is free software: you can redistribute it and/or modify +.\" it under the terms of the GNU General Public License as published by +.\" the Free Software Foundation, either version 2 of the License, or +.\" (at your option) any later version. +.\" +.\" This program is distributed in the hope that it will be useful, +.\" but WITHOUT ANY WARRANTY; without even the implied warranty of +.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +.\" GNU General Public License for more details. +.\" +.\" You should have received a copy of the GNU General Public License +.\" along with this program. If not, see . +.Dd December 15, 2019 +.Dt MKTUNTAP 8 +.Os Linux +.Sh NAME +.Nm mktuntap +.Nd create and open a TUN or TAP device on a file descriptor, then exec +.Sh SYNOPSIS +.Nm +.Fl ( n | p ) +.Op Fl E +.Op Fl i Ar ifr_name +.Ar fd +.Ar prog... +.Sh DESCRIPTION +Create a TUN or TAP device named with format +.Ar ifr_name , +open it on file descriptor +.Ar fd , +set the TUNTAP_NAME variable in the environment to the name of the +opened device, and then exec into +.Ar prog . +.Pp +The arguments are as follows: +.Bl -tag -width Ds +.It Fl p +Create a TAP device. Mutually exclusive with +.Fl n . +.It Fl n +Create a TUN device. Mutually exclusive with +.Fl p . +.It Fl E +Don't set the TUNTAP_NAME environment variable. Caution: if you use +this without using +.Fl i +to set a static device name, it will be difficult to determine the +device name later. +.It Fl i +Set the name for the device. If present, the character sequence +.Dq %d +will be replaced with a number to create a unique name. Default: +.Dq tap%d +or +.Dq tun%d , +as appropriate. +.El +.Sh EXIT STATUS +.Ex -std +See +.Xr sysexits 3 +for further details. +.Sh SEE ALSO +.Xr tunctl 8 , +.Xr ip 8 diff --git a/mktuntap.c b/mktuntap.c new file mode 100644 index 0000000..cae3f5a --- /dev/null +++ b/mktuntap.c @@ -0,0 +1,142 @@ +// SPDX-License-Identifier: GPL-2.0-only + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +// Adapted 2019-12-14 from Documentation/networking/tuntuntap.txt in Linux. +int tuntap_alloc(char *dev, short flags) +{ + struct ifreq ifr; + int fd, err; + + if ((fd = open("/dev/net/tun", O_RDWR)) < 0) + return -1; + + memset(&ifr, 0, sizeof(ifr)); + + ifr.ifr_flags = flags; + if (*dev) + strncpy(ifr.ifr_name, dev, IFNAMSIZ); + + if ((err = ioctl(fd, TUNSETIFF, (void *) &ifr)) < 0) { + close(fd); + return err; + } + strcpy(dev, ifr.ifr_name); + return fd; +} + +void ex_usage() +{ + fputs("mktuntap: usage: mktuntap (-n | -p) [-E] [-i ifr_name] fd prog...\n", stderr); + exit(EX_USAGE); +} + +int main(int argc, char **argv) +{ + char *ifr_name_in = NULL; + bool name_env = true, tap = false, tun = false; + + int c; + while ((c = getopt(argc, argv, "+npEi:")) != -1) { + switch (c) { + case 'n': + tun = true; + break; + case 'p': + tap = true; + break; + case 'E': + name_env = false; + break; + case 'i': + ifr_name_in = optarg; + break; + default: + ex_usage(); + } + } + + if (argc - optind < 2 || !(tap ^ tun)) + ex_usage(); + + // ifr_name is a macro, so add a trailing _. + char *ifr_name_ = calloc(IFNAMSIZ, sizeof(char)); + if (ifr_name_in) { + if (strlen(ifr_name_in) > IFNAMSIZ - 1) { + fprintf(stderr, "mktuntap: ifr_name too long (max %i)\n", IFNAMSIZ - 1); + return EX_USAGE; + } + strcpy(ifr_name_, ifr_name_in); + } + + errno = 0; + char *target_fd_end; + long int target_fd_l = strtol(argv[optind], &target_fd_end, 10); + if (errno) { + fprintf(stderr, "mktuntap: %s\n", strerror(errno)); + return EX_USAGE; + } + if (argv[optind][0] == '\0' || target_fd_end[0] != '\0') { + fprintf(stderr, "mktuntap: invalid integer: `%s'\n", argv[optind]); + return EX_USAGE; + } + if (target_fd_l < INT_MIN || target_fd_l > INT_MAX) { + fprintf(stderr, "mktuntap: out of range for file descriptor: `%li'\n", target_fd_l); + return EX_USAGE; + } + int target_fd = (int)target_fd_l; + + int tuntap_fd = tuntap_alloc(ifr_name_, tap ? IFF_TAP : IFF_TUN); + if (tuntap_fd < 0) { + fprintf(stderr, "mktuntap: failed to open tuntap device: %s\n", strerror(errno)); + return EX_IOERR; + } + + if (dup2(tuntap_fd, target_fd) == -1) { + fprintf(stderr, "mktuntap: %s\n", strerror(errno)); + return EX_IOERR; + } + if (close(tuntap_fd) == -1) { + fprintf(stderr, "mktuntap: %s\n", strerror(errno)); + return EX_IOERR; + } + + if (name_env) { + if (setenv("TUNTAP_NAME", ifr_name_, 1) == -1) { + fprintf(stderr, "mktuntap: %s\n", strerror(errno)); + return EX_OSERR; + } + } + + execvp(argv[optind + 1], &argv[optind + 1]); + + fprintf(stderr, "failed to exec: %s\n", strerror(errno)); + return EX_OSERR; +} -- cgit 1.4.1