From 9f2939b4825122d89d2c3f74bf818101347dcf8c Mon Sep 17 00:00:00 2001 From: Pekka Ekman Date: Wed, 8 Jun 2016 00:15:00 +0300 Subject: [PATCH] Initial commit --- .gitignore | 2 + .gitmodules | 3 ++ Makefile | 48 ++++++++++++++++++++++++ iproute2 | 1 + netns-exec.c | 102 +++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 156 insertions(+) create mode 100644 .gitignore create mode 100644 .gitmodules create mode 100644 Makefile create mode 160000 iproute2 create mode 100644 netns-exec.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..95b9e91 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/*.o +/netns-exec diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..e63efa5 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "iproute2"] + path = iproute2 + url = git://git.kernel.org/pub/scm/linux/kernel/git/shemminger/iproute2.git diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..2363115 --- /dev/null +++ b/Makefile @@ -0,0 +1,48 @@ +PREFIX = /usr/local +EXEC_PREFIX = $(PREFIX) +BINDIR = $(EXEC_PREFIX)/bin + +CC = gcc +CFLAGS = -O2 -Wall +PROG = netns-exec + +IPROUTE2_DIR = iproute2 +IPROUTE2_OBJS = namespace.o +IPROUTE2_OBJS_FULL = $(addprefix $(IPROUTE2_DIR)/lib/, $(IPROUTE2_OBJS)) +IPROUTE2_INCLUDES = -iquote $(IPROUTE2_DIR)/include +IPROUTE2_CFLAGS = $(CFLAGS) + +CPPFLAGS += $(IPROUTE2_INCLUDES) + +OBJS = $(PROG).o $(IPROUTE2_OBJS_FULL) + + +all: $(PROG) + +$(PROG): $(OBJS) + +install: $(PROG) + install -D -m4755 -t$(BINDIR) $(PROG) + +uninstall: + rm -fv $(BINDIR)/$(PROG) + +localclean: + rm -fv $(PROG) $(PROG).o + +clean: localclean + $(MAKE) clean -C $(IPROUTE2_DIR) + +distclean: localclean + $(MAKE) distclean -C $(IPROUTE2_DIR) + + +# rule for building files in iproute2 subdirectory: +# (This is a bit of a hack. Set some variables to make iproute2's +# Makefile only build what we need and set all needed options.) +$(IPROUTE2_OBJS_FULL): + $(MAKE) -C $(IPROUTE2_DIR) \ + SUBDIRS='lib' MFLAGS='$(IPROUTE2_OBJS)' \ + EXTRA_CFLAGS='$(IPROUTE2_CFLAGS)' + +MAKEOVERRIDES := $(filter-out CFLAGS=% CPPFLAGS=%,$(MAKEOVERRIDES)) diff --git a/iproute2 b/iproute2 new file mode 160000 index 0000000..ead954c --- /dev/null +++ b/iproute2 @@ -0,0 +1 @@ +Subproject commit ead954cbd40a2a9e3756d2010c6bfb1d80c340ed diff --git a/netns-exec.c b/netns-exec.c new file mode 100644 index 0000000..1236847 --- /dev/null +++ b/netns-exec.c @@ -0,0 +1,102 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "namespace.h" + + +#define EXIT_INVALID_ARGS 2 +#define EXIT_NOT_FOUND 127 +#define EXIT_CANNOT_EXEC 126 +#define EXIT_OTHER_ERROR 125 + + +static void usage(const char *argv0, bool is_error) +{ + fprintf( + stderr, + "\n" + "usage:\n" + "\n" + "run command in netns:\n" + " %1$s [-h | --help] [--] [ ...]\n" + "\n" + "run shell in netns:\n" + " %1$s [-h | --help] [--] \n" + "\n", + argv0); + + exit(is_error ? EXIT_INVALID_ARGS : 0); +} + + +static void drop_root_privileges(void) +{ + if (setuid(getuid()) < 0) { + perror("error setting user id"); + exit(EXIT_OTHER_ERROR); + } + if (setgid(getgid()) < 0) { + perror("error setting group id"); + exit(EXIT_OTHER_ERROR); + } +} + + +int main(int argc, char *argv[]) +{ + // parse arguments + if (argc < 2 || (argc == 2 && strcmp(argv[1], "--") == 0)) + // no netns given + usage(argv[0], true); + if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-h") == 0) + usage(argv[0], false); + + if (strcmp(argv[1], "--") == 0) { + argv++; + argc--; + } + else if (argv[1][0] == '-') { + // invalid command line option + fprintf(stderr, "Unknown option: %s\n", argv[1]); + usage(argv[0], true); + } + + + // switch network namespace using iproute2's function + if (netns_switch(argv[1]) < 0) + return EXIT_OTHER_ERROR; + + + drop_root_privileges(); + + + char **command_argv; + + // if no command given, start shell + if (argc == 2) { + static char *shell_argv[] = { "/bin/sh", NULL }; + char *shell = getenv("SHELL"); + if (shell != NULL) + shell_argv[0] = shell; + command_argv = shell_argv; + } + else { + command_argv = &argv[2]; + } + + + // execute the command + execvp(command_argv[0], command_argv); + + fprintf(stderr, "error executing \"%s\": %s", + command_argv[0], strerror(errno)); + if (errno == ENOENT) + return EXIT_NOT_FOUND; + else + return EXIT_CANNOT_EXEC; +}