diff options
Diffstat (limited to 'ip/ipnetns.c')
-rw-r--r-- | ip/ipnetns.c | 193 |
1 files changed, 103 insertions, 90 deletions
diff --git a/ip/ipnetns.c b/ip/ipnetns.c index 088096f6..bad79331 100644 --- a/ip/ipnetns.c +++ b/ip/ipnetns.c @@ -18,7 +18,7 @@ #include <linux/net_namespace.h> #include "utils.h" -#include "hlist.h" +#include "list.h" #include "ip_common.h" #include "namespace.h" @@ -61,20 +61,19 @@ static int ipnetns_have_nsid(void) struct nlmsghdr n; struct rtgenmsg g; char buf[1024]; - } req; + } req = { + .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)), + .n.nlmsg_flags = NLM_F_REQUEST, + .n.nlmsg_type = RTM_GETNSID, + .g.rtgen_family = AF_UNSPEC, + }; int fd; if (have_rtnl_getnsid < 0) { - memset(&req, 0, sizeof(req)); - req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)); - req.n.nlmsg_flags = NLM_F_REQUEST; - req.n.nlmsg_type = RTM_GETNSID; - req.g.rtgen_family = AF_UNSPEC; - fd = open("/proc/self/ns/net", O_RDONLY); if (fd < 0) { - perror("open(\"/proc/self/ns/net\")"); - exit(1); + have_rtnl_getnsid = 0; + return 0; } addattr32(&req.n, 1024, NETNSA_FD, fd); @@ -96,17 +95,16 @@ static int get_netnsid_from_name(const char *name) struct nlmsghdr n; struct rtgenmsg g; char buf[1024]; - } req, answer; + } answer, req = { + .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)), + .n.nlmsg_flags = NLM_F_REQUEST, + .n.nlmsg_type = RTM_GETNSID, + .g.rtgen_family = AF_UNSPEC, + }; struct rtattr *tb[NETNSA_MAX + 1]; struct rtgenmsg *rthdr; int len, fd; - memset(&req, 0, sizeof(req)); - req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)); - req.n.nlmsg_flags = NLM_F_REQUEST; - req.n.nlmsg_type = RTM_GETNSID; - req.g.rtgen_family = AF_UNSPEC; - fd = netns_get_fd(name); if (fd < 0) return fd; @@ -172,7 +170,7 @@ static int netns_map_add(int nsid, const char *name) if (netns_map_get_by_nsid(nsid) != NULL) return -EEXIST; - c = malloc(sizeof(*c) + strlen(name)); + c = malloc(sizeof(*c) + strlen(name) + 1); if (c == NULL) { perror("malloc"); return -ENOMEM; @@ -196,6 +194,18 @@ static void netns_map_del(struct nsid_cache *c) free(c); } +void netns_nsid_socket_init(void) +{ + if (rtnsh.fd > -1 || !ipnetns_have_nsid()) + return; + + if (rtnl_open(&rtnsh, 0) < 0) { + fprintf(stderr, "Cannot open rtnetlink\n"); + exit(1); + } + +} + void netns_map_init(void) { static int initialized; @@ -206,11 +216,6 @@ void netns_map_init(void) if (initialized || !ipnetns_have_nsid()) return; - if (rtnl_open(&rtnsh, 0) < 0) { - fprintf(stderr, "Cannot open rtnetlink\n"); - exit(1); - } - dir = opendir(NETNS_RUN_DIR); if (!dir) return; @@ -352,43 +357,10 @@ static int netns_list(int argc, char **argv) return 0; } -static int cmd_exec(const char *cmd, char **argv, bool do_fork) -{ - fflush(stdout); - if (do_fork) { - int status; - pid_t pid; - - pid = fork(); - if (pid < 0) { - perror("fork"); - exit(1); - } - - if (pid != 0) { - /* Parent */ - if (waitpid(pid, &status, 0) < 0) { - perror("waitpid"); - exit(1); - } - - if (WIFEXITED(status)) { - return WEXITSTATUS(status); - } - - exit(1); - } - } - - if (execvp(cmd, argv) < 0) - fprintf(stderr, "exec of \"%s\" failed: %s\n", - cmd, strerror(errno)); - _exit(1); -} - static int on_netns_exec(char *nsname, void *arg) { char **argv = arg; + cmd_exec(argv[1], argv + 1, true); return 0; } @@ -415,6 +387,11 @@ static int netns_exec(int argc, char **argv) if (netns_switch(argv[0])) return -1; + /* we just changed namespaces. clear any vrf association + * with prior namespace before exec'ing command + */ + vrf_reset(); + /* ip must return the status of the child, * but do_cmd() will add a minus to this, * so let's add another one here to cancel it. @@ -426,6 +403,7 @@ static int netns_exec(int argc, char **argv) static int is_pid(const char *str) { int ch; + for (; (ch = *str); str++) { if (!isdigit(ch)) return 0; @@ -470,9 +448,10 @@ static int netns_pids(int argc, char **argv) strerror(errno)); return -1; } - while((entry = readdir(dir))) { + while ((entry = readdir(dir))) { char pid_net_path[PATH_MAX]; struct stat st; + if (!is_pid(entry->d_name)) continue; snprintf(pid_net_path, sizeof(pid_net_path), "/proc/%s/ns/net", @@ -489,28 +468,15 @@ static int netns_pids(int argc, char **argv) } -static int netns_identify(int argc, char **argv) +int netns_identify_pid(const char *pidstr, char *name, int len) { - const char *pidstr; char net_path[PATH_MAX]; int netns; struct stat netst; DIR *dir; struct dirent *entry; - if (argc < 1) { - pidstr = "self"; - } else if (argc > 1) { - fprintf(stderr, "extra arguments specified\n"); - return -1; - } else { - pidstr = argv[0]; - if (!is_pid(pidstr)) { - fprintf(stderr, "Specified string '%s' is not a pid\n", - pidstr); - return -1; - } - } + name[0] = '\0'; snprintf(net_path, sizeof(net_path), "/proc/%s/ns/net", pidstr); netns = open(net_path, O_RDONLY); @@ -535,7 +501,7 @@ static int netns_identify(int argc, char **argv) return -1; } - while((entry = readdir(dir))) { + while ((entry = readdir(dir))) { char name_path[PATH_MAX]; struct stat st; @@ -552,7 +518,7 @@ static int netns_identify(int argc, char **argv) if ((st.st_dev == netst.st_dev) && (st.st_ino == netst.st_ino)) { - printf("%s\n", entry->d_name); + strlcpy(name, entry->d_name, len); } } closedir(dir); @@ -560,6 +526,33 @@ static int netns_identify(int argc, char **argv) } +static int netns_identify(int argc, char **argv) +{ + const char *pidstr; + char name[256]; + int rc; + + if (argc < 1) { + pidstr = "self"; + } else if (argc > 1) { + fprintf(stderr, "extra arguments specified\n"); + return -1; + } else { + pidstr = argv[0]; + if (!is_pid(pidstr)) { + fprintf(stderr, "Specified string '%s' is not a pid\n", + pidstr); + return -1; + } + } + + rc = netns_identify_pid(pidstr, name, sizeof(name)); + if (!rc) + printf("%s\n", name); + + return rc; +} + static int on_netns_del(char *nsname, void *arg) { char netns_path[PATH_MAX]; @@ -642,7 +635,7 @@ static int netns_add(int argc, char **argv) } /* Upgrade NETNS_RUN_DIR to a mount point */ - if (mount(NETNS_RUN_DIR, NETNS_RUN_DIR, "none", MS_BIND, NULL)) { + if (mount(NETNS_RUN_DIR, NETNS_RUN_DIR, "none", MS_BIND | MS_REC, NULL)) { fprintf(stderr, "mount --bind %s %s failed: %s\n", NETNS_RUN_DIR, NETNS_RUN_DIR, strerror(errno)); return -1; @@ -682,15 +675,14 @@ static int set_netnsid_from_name(const char *name, int nsid) struct nlmsghdr n; struct rtgenmsg g; char buf[1024]; - } req; + } req = { + .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)), + .n.nlmsg_flags = NLM_F_REQUEST, + .n.nlmsg_type = RTM_NEWNSID, + .g.rtgen_family = AF_UNSPEC, + }; int fd, err = 0; - memset(&req, 0, sizeof(req)); - req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)); - req.n.nlmsg_flags = NLM_F_REQUEST; - req.n.nlmsg_type = RTM_NEWNSID; - req.g.rtgen_family = AF_UNSPEC; - fd = netns_get_fd(name); if (fd < 0) return fd; @@ -708,7 +700,8 @@ static int netns_set(int argc, char **argv) { char netns_path[PATH_MAX]; const char *name; - int netns, nsid; + unsigned int nsid; + int netns; if (argc < 1) { fprintf(stderr, "No netns name specified\n"); @@ -719,7 +712,8 @@ static int netns_set(int argc, char **argv) return -1; } name = argv[0]; - nsid = atoi(argv[1]); + if (get_unsigned(&nsid, argv[1], 0)) + invarg("Invalid \"netnsid\" value\n", argv[1]); snprintf(netns_path, sizeof(netns_path), "%s/%s", NETNS_RUN_DIR, name); netns = open(netns_path, O_RDONLY | O_CLOEXEC); @@ -737,6 +731,7 @@ static int netns_monitor(int argc, char **argv) char buf[4096]; struct inotify_event *event; int fd; + fd = inotify_init(); if (fd < 0) { fprintf(stderr, "inotify_init failed: %s\n", @@ -752,8 +747,9 @@ static int netns_monitor(int argc, char **argv) strerror(errno)); return -1; } - for(;;) { + for (;;) { ssize_t len = read(fd, buf, sizeof(buf)); + if (len < 0) { fprintf(stderr, "read failed: %s\n", strerror(errno)); @@ -771,19 +767,36 @@ static int netns_monitor(int argc, char **argv) return 0; } +static int invalid_name(const char *name) +{ + return !*name || strlen(name) > NAME_MAX || + strchr(name, '/') || !strcmp(name, ".") || !strcmp(name, ".."); +} + int do_netns(int argc, char **argv) { - netns_map_init(); + netns_nsid_socket_init(); - if (argc < 1) + if (argc < 1) { + netns_map_init(); return netns_list(0, NULL); + } + + if (argc > 1 && invalid_name(argv[1])) { + fprintf(stderr, "Invalid netns name \"%s\"\n", argv[1]); + exit(-1); + } if ((matches(*argv, "list") == 0) || (matches(*argv, "show") == 0) || - (matches(*argv, "lst") == 0)) + (matches(*argv, "lst") == 0)) { + netns_map_init(); return netns_list(argc-1, argv+1); + } - if ((matches(*argv, "list-id") == 0)) + if ((matches(*argv, "list-id") == 0)) { + netns_map_init(); return netns_list_id(argc-1, argv+1); + } if (matches(*argv, "help") == 0) return usage(); |