blob: 8a2e5a7b121eb40ae5f77fcc69216106f4318417 [file] [log] [blame]
KOVACS Krisztianb3e54fe2014-11-17 15:11:45 +01001#define _GNU_SOURCE
2
KOVACS Krisztianb3e54fe2014-11-17 15:11:45 +01003#include <sched.h>
4#include <stdio.h>
5#include <sys/stat.h>
6#include <fcntl.h>
7#include <sys/types.h>
8#include <unistd.h>
9#include <sys/socket.h>
10
11#include <string.h>
Willy Tarreau3fa0e2a2016-03-17 05:39:53 +010012
13#include <common/namespace.h>
14#include <common/compiler.h>
15#include <common/hash.h>
16#include <common/errors.h>
17#include <proto/log.h>
18#include <types/global.h>
19
KOVACS Krisztianb3e54fe2014-11-17 15:11:45 +010020/* Opens the namespace <ns_name> and returns the FD or -1 in case of error
21 * (check errno).
22 */
23static int open_named_namespace(const char *ns_name)
24{
25 if (chunk_printf(&trash, "/var/run/netns/%s", ns_name) < 0)
26 return -1;
Willy Tarreau843b7cb2018-07-13 10:54:26 +020027 return open(trash.area, O_RDONLY);
KOVACS Krisztianb3e54fe2014-11-17 15:11:45 +010028}
29
30static int default_namespace = -1;
31
32static int init_default_namespace()
33{
34 if (chunk_printf(&trash, "/proc/%d/ns/net", getpid()) < 0)
35 return -1;
Willy Tarreau843b7cb2018-07-13 10:54:26 +020036 default_namespace = open(trash.area, O_RDONLY);
KOVACS Krisztianb3e54fe2014-11-17 15:11:45 +010037 return default_namespace;
38}
39
40static struct eb_root namespace_tree_root = EB_ROOT;
41
42int netns_init(void)
43{
44 int err_code = 0;
45
46 /* if no namespaces have been defined in the config then
47 * there is no point in trying to initialize anything:
48 * my_socketat() will never be called with a valid namespace
49 * structure and thus switching back to the default namespace
50 * is not needed either */
51 if (!eb_is_empty(&namespace_tree_root)) {
52 if (init_default_namespace() < 0) {
Christopher Faulet767a84b2017-11-24 16:50:31 +010053 ha_alert("Failed to open the default namespace.\n");
KOVACS Krisztianb3e54fe2014-11-17 15:11:45 +010054 err_code |= ERR_ALERT | ERR_FATAL;
55 }
56 }
57
58 return err_code;
59}
60
61struct netns_entry* netns_store_insert(const char *ns_name)
62{
63 struct netns_entry *entry = NULL;
64 int fd = open_named_namespace(ns_name);
65 if (fd == -1)
66 goto out;
67
Vincent Bernat02779b62016-04-03 13:48:43 +020068 entry = calloc(1, sizeof(*entry));
KOVACS Krisztianb3e54fe2014-11-17 15:11:45 +010069 if (!entry)
70 goto out;
71 entry->fd = fd;
72 entry->node.key = strdup(ns_name);
73 entry->name_len = strlen(ns_name);
74 ebis_insert(&namespace_tree_root, &entry->node);
75out:
76 return entry;
77}
78
79const struct netns_entry* netns_store_lookup(const char *ns_name, size_t ns_name_len)
80{
81 struct ebpt_node *node;
82
83 node = ebis_lookup_len(&namespace_tree_root, ns_name, ns_name_len);
84 if (node)
85 return ebpt_entry(node, struct netns_entry, node);
86 else
87 return NULL;
88}
KOVACS Krisztianb3e54fe2014-11-17 15:11:45 +010089
90/* Opens a socket in the namespace described by <ns> with the parameters <domain>,
91 * <type> and <protocol> and returns the FD or -1 in case of error (check errno).
92 */
93int my_socketat(const struct netns_entry *ns, int domain, int type, int protocol)
94{
95 int sock;
96
Willy Tarreau70f289c2015-10-20 15:14:07 +020097 if (default_namespace >= 0 && ns && setns(ns->fd, CLONE_NEWNET) == -1)
KOVACS Krisztianb3e54fe2014-11-17 15:11:45 +010098 return -1;
Willy Tarreau7520e4f2018-11-11 14:38:09 +010099
KOVACS Krisztianb3e54fe2014-11-17 15:11:45 +0100100 sock = socket(domain, type, protocol);
101
Willy Tarreau70f289c2015-10-20 15:14:07 +0200102 if (default_namespace >= 0 && ns && setns(default_namespace, CLONE_NEWNET) == -1) {
KOVACS Krisztianb3e54fe2014-11-17 15:11:45 +0100103 close(sock);
104 return -1;
105 }
KOVACS Krisztianb3e54fe2014-11-17 15:11:45 +0100106 return sock;
107}
Willy Tarreaudba50022016-12-21 18:51:45 +0100108
Willy Tarreau80713382018-11-26 10:19:54 +0100109REGISTER_BUILD_OPTS("Built with network namespace support.");