#define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* Opens the namespace and returns the FD or -1 in case of error * (check errno). */ static int open_named_namespace(const char *ns_name) { if (chunk_printf(&trash, "/var/run/netns/%s", ns_name) < 0) return -1; return open(trash.area, O_RDONLY | O_CLOEXEC); } static int default_namespace = -1; static int init_default_namespace() { if (chunk_printf(&trash, "/proc/%d/ns/net", getpid()) < 0) return -1; default_namespace = open(trash.area, O_RDONLY | O_CLOEXEC); return default_namespace; } static struct eb_root namespace_tree_root = EB_ROOT; static void netns_sig_stop(struct sig_handler *sh) { struct ebpt_node *node, *next; struct netns_entry *entry; /* close namespace file descriptors and remove registered namespaces from the * tree when stopping */ node = ebpt_first(&namespace_tree_root); while (node) { next = ebpt_next(node); ebpt_delete(node); entry = container_of(node, struct netns_entry, node); free(entry->node.key); close(entry->fd); free(entry); node = next; } } int netns_init(void) { int err_code = 0; /* if no namespaces have been defined in the config then * there is no point in trying to initialize anything: * my_socketat() will never be called with a valid namespace * structure and thus switching back to the default namespace * is not needed either */ if (!eb_is_empty(&namespace_tree_root)) { if (init_default_namespace() < 0) { ha_alert("Failed to open the default namespace.\n"); err_code |= ERR_ALERT | ERR_FATAL; } } signal_register_fct(0, netns_sig_stop, 0); return err_code; } struct netns_entry* netns_store_insert(const char *ns_name) { struct netns_entry *entry = NULL; int fd = open_named_namespace(ns_name); if (fd == -1) goto out; entry = calloc(1, sizeof(*entry)); if (!entry) goto out; entry->fd = fd; entry->node.key = strdup(ns_name); entry->name_len = strlen(ns_name); ebis_insert(&namespace_tree_root, &entry->node); out: return entry; } const struct netns_entry* netns_store_lookup(const char *ns_name, size_t ns_name_len) { struct ebpt_node *node; node = ebis_lookup_len(&namespace_tree_root, ns_name, ns_name_len); if (node) return ebpt_entry(node, struct netns_entry, node); else return NULL; } /* Opens a socket in the namespace described by with the parameters , * and and returns the FD or -1 in case of error (check errno). */ int my_socketat(const struct netns_entry *ns, int domain, int type, int protocol) { int sock; if (default_namespace >= 0 && ns && setns(ns->fd, CLONE_NEWNET) == -1) return -1; sock = socket(domain, type, protocol); if (default_namespace >= 0 && ns && setns(default_namespace, CLONE_NEWNET) == -1) { if (sock >= 0) close(sock); return -1; } return sock; } REGISTER_BUILD_OPTS("Built with network namespace support.");