1 /* 2 * namespace.c 3 * 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. 8 */ 9 10 #include <fcntl.h> 11 #include <dirent.h> 12 #include <limits.h> 13 14 #include "utils.h" 15 #include "namespace.h" 16 17 static void bind_etc(const char *name) 18 { 19 char etc_netns_path[PATH_MAX]; 20 char netns_name[PATH_MAX]; 21 char etc_name[PATH_MAX]; 22 struct dirent *entry; 23 DIR *dir; 24 25 snprintf(etc_netns_path, sizeof(etc_netns_path), "%s/%s", NETNS_ETC_DIR, name); 26 dir = opendir(etc_netns_path); 27 if (!dir) 28 return; 29 30 while ((entry = readdir(dir)) != NULL) { 31 if (strcmp(entry->d_name, ".") == 0) 32 continue; 33 if (strcmp(entry->d_name, "..") == 0) 34 continue; 35 snprintf(netns_name, sizeof(netns_name), "%s/%s", etc_netns_path, entry->d_name); 36 snprintf(etc_name, sizeof(etc_name), "/etc/%s", entry->d_name); 37 if (mount(netns_name, etc_name, "none", MS_BIND, NULL) < 0) { 38 fprintf(stderr, "Bind %s -> %s failed: %s\n", 39 netns_name, etc_name, strerror(errno)); 40 } 41 } 42 closedir(dir); 43 } 44 45 int netns_switch(char *name) 46 { 47 char net_path[PATH_MAX]; 48 int netns; 49 50 snprintf(net_path, sizeof(net_path), "%s/%s", NETNS_RUN_DIR, name); 51 netns = open(net_path, O_RDONLY | O_CLOEXEC); 52 if (netns < 0) { 53 fprintf(stderr, "Cannot open network namespace \"%s\": %s\n", 54 name, strerror(errno)); 55 return -1; 56 } 57 58 if (setns(netns, CLONE_NEWNET) < 0) { 59 fprintf(stderr, "setting the network namespace \"%s\" failed: %s\n", 60 name, strerror(errno)); 61 close(netns); 62 return -1; 63 } 64 close(netns); 65 66 if (unshare(CLONE_NEWNS) < 0) { 67 fprintf(stderr, "unshare failed: %s\n", strerror(errno)); 68 return -1; 69 } 70 /* Don't let any mounts propagate back to the parent */ 71 if (mount("", "/", "none", MS_SLAVE | MS_REC, NULL)) { 72 fprintf(stderr, "\"mount --make-rslave /\" failed: %s\n", 73 strerror(errno)); 74 return -1; 75 } 76 /* Mount a version of /sys that describes the network namespace */ 77 if (umount2("/sys", MNT_DETACH) < 0) { 78 fprintf(stderr, "umount of /sys failed: %s\n", strerror(errno)); 79 return -1; 80 } 81 if (mount(name, "/sys", "sysfs", 0, NULL) < 0) { 82 fprintf(stderr, "mount of /sys failed: %s\n",strerror(errno)); 83 return -1; 84 } 85 86 /* Setup bind mounts for config files in /etc */ 87 bind_etc(name); 88 return 0; 89 } 90 91 int netns_get_fd(const char *name) 92 { 93 char pathbuf[PATH_MAX]; 94 const char *path, *ptr; 95 96 path = name; 97 ptr = strchr(name, '/'); 98 if (!ptr) { 99 snprintf(pathbuf, sizeof(pathbuf), "%s/%s", 100 NETNS_RUN_DIR, name ); 101 path = pathbuf; 102 } 103 return open(path, O_RDONLY); 104 } 105 106 int netns_foreach(int (*func)(char *nsname, void *arg), void *arg) 107 { 108 DIR *dir; 109 struct dirent *entry; 110 111 dir = opendir(NETNS_RUN_DIR); 112 if (!dir) 113 return -1; 114 115 while ((entry = readdir(dir)) != NULL) { 116 if (strcmp(entry->d_name, ".") == 0) 117 continue; 118 if (strcmp(entry->d_name, "..") == 0) 119 continue; 120 if (func(entry->d_name, arg)) 121 break; 122 } 123 124 closedir(dir); 125 return 0; 126 } 127