diff options
Diffstat (limited to 'src/utils.c')
-rw-r--r-- | src/utils.c | 95 |
1 files changed, 93 insertions, 2 deletions
diff --git a/src/utils.c b/src/utils.c index 7bbdc1e..049e3d5 100644 --- a/src/utils.c +++ b/src/utils.c @@ -8,6 +8,7 @@ #include <signal.h> #include <pwd.h> #include <grp.h> +#include <sched.h> #include <sys/types.h> #include <sys/sysmacros.h> #include <sys/stat.h> @@ -19,6 +20,7 @@ #include "utils.h" #include "log.h" +#include "options.h" #define _POSIX_PATH_MAX 256 @@ -345,9 +347,9 @@ void chk_chroot(void) void mount_root(void) { int s; - s = mount("none", "/", "", MS_SLAVE|MS_REC, NULL); + s = mount("", "/", "none", MS_SLAVE|MS_REC, NULL); if (s) - s = mount("none", "/", "", MS_PRIVATE|MS_REC, NULL); + s = mount("", "/", "none", MS_PRIVATE|MS_REC, NULL); if (s) chk_chroot(); } @@ -399,6 +401,95 @@ int mount_proc(const char *mount_path) return 0; } +int setup_network_namespace(const char *name) +{ + int fd; + char netns_path[PATH_MAX]; + int made_netns_run_dir_mount = 0; + + snprintf(netns_path, sizeof netns_path, "%s/%s", + getopt_str(OPT_NETNS_RUN_DIR), name); + D2("Network Namespace path '%s'", netns_path); + + if (mkdir(getopt_str(OPT_NETNS_RUN_DIR), + S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)) + { + if (errno != EEXIST) { + E_STRERR("Create netns directory '%s'", + getopt_str(OPT_NETNS_RUN_DIR)); + return 1; + } + } + + while (mount("", getopt_str(OPT_NETNS_RUN_DIR), "none", + MS_SHARED|MS_REC, NULL)) + { + /* Fail unless we need to make the mount point */ + if (errno != EINVAL || made_netns_run_dir_mount) { + E_STRERR("Mount netns directory '%s' as shared", + getopt_str(OPT_NETNS_RUN_DIR)); + return 1; + } + + /* Upgrade NETNS_RUN_DIR to a mount point */ + if (mount(getopt_str(OPT_NETNS_RUN_DIR), getopt_str(OPT_NETNS_RUN_DIR), + "none", MS_BIND | MS_REC, NULL)) + { + E_STRERR("Bind mount netns directory '%s'", + getopt_str(OPT_NETNS_RUN_DIR)); + return 1; + } + made_netns_run_dir_mount = 1; + } + + /* Create the filesystem state */ + fd = open(netns_path, O_RDONLY|O_CREAT|O_EXCL, 0); + if (fd < 0 && errno != EEXIST) { + E_STRERR("Create namespace file '%s'", netns_path); + return 1; + } + close(fd); + + if (unshare(CLONE_NEWNET) < 0) { + E_STRERR("Create network namespace '%s'", name); + goto error; + } + + /* Bind the netns last so I can watch for it */ + if (mount("/proc/self/ns/net", netns_path, "none", MS_BIND, NULL) < 0) { + E_STRERR("Bind /proc/self/ns/net to '%s'", netns_path); + goto error; + } + + return 0; +error: + /* cleanup netns? */ + return 1; +} + +int switch_network_namespace(const char *name) +{ + char net_path[PATH_MAX]; + int netns; + + snprintf(net_path, sizeof(net_path), "%s/%s", + getopt_str(OPT_NETNS_RUN_DIR), name); + netns = open(net_path, O_RDONLY | O_CLOEXEC); + if (netns < 0) { + E_STRERR("Cannot open network namespace '%s'", name); + return 1; + } + + if (setns(netns, CLONE_NEWNET) < 0) { + E_STRERR("Setting the network namespace '%s'", name); + close(netns); + return 1; + } + close(netns); + + return 0; +} + int create_device_file_checked(const char *mount_path, const char *device_file, mode_t mode, int add_mode, dev_t dev) { |