blob: c8cec16eb82f264d429de86d149a82b1aae81e7e [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#ifdef CONFIG_HAP_NS
21
22/* Opens the namespace <ns_name> and returns the FD or -1 in case of error
23 * (check errno).
24 */
25static int open_named_namespace(const char *ns_name)
26{
27 if (chunk_printf(&trash, "/var/run/netns/%s", ns_name) < 0)
28 return -1;
29 return open(trash.str, O_RDONLY);
30}
31
32static int default_namespace = -1;
33
34static int init_default_namespace()
35{
36 if (chunk_printf(&trash, "/proc/%d/ns/net", getpid()) < 0)
37 return -1;
38 default_namespace = open(trash.str, O_RDONLY);
39 return default_namespace;
40}
41
42static struct eb_root namespace_tree_root = EB_ROOT;
43
44int netns_init(void)
45{
46 int err_code = 0;
47
48 /* if no namespaces have been defined in the config then
49 * there is no point in trying to initialize anything:
50 * my_socketat() will never be called with a valid namespace
51 * structure and thus switching back to the default namespace
52 * is not needed either */
53 if (!eb_is_empty(&namespace_tree_root)) {
54 if (init_default_namespace() < 0) {
Christopher Faulet767a84b2017-11-24 16:50:31 +010055 ha_alert("Failed to open the default namespace.\n");
KOVACS Krisztianb3e54fe2014-11-17 15:11:45 +010056 err_code |= ERR_ALERT | ERR_FATAL;
57 }
58 }
59
60 return err_code;
61}
62
63struct netns_entry* netns_store_insert(const char *ns_name)
64{
65 struct netns_entry *entry = NULL;
66 int fd = open_named_namespace(ns_name);
67 if (fd == -1)
68 goto out;
69
Vincent Bernat02779b62016-04-03 13:48:43 +020070 entry = calloc(1, sizeof(*entry));
KOVACS Krisztianb3e54fe2014-11-17 15:11:45 +010071 if (!entry)
72 goto out;
73 entry->fd = fd;
74 entry->node.key = strdup(ns_name);
75 entry->name_len = strlen(ns_name);
76 ebis_insert(&namespace_tree_root, &entry->node);
77out:
78 return entry;
79}
80
81const struct netns_entry* netns_store_lookup(const char *ns_name, size_t ns_name_len)
82{
83 struct ebpt_node *node;
84
85 node = ebis_lookup_len(&namespace_tree_root, ns_name, ns_name_len);
86 if (node)
87 return ebpt_entry(node, struct netns_entry, node);
88 else
89 return NULL;
90}
91#endif
92
93/* Opens a socket in the namespace described by <ns> with the parameters <domain>,
94 * <type> and <protocol> and returns the FD or -1 in case of error (check errno).
95 */
96int my_socketat(const struct netns_entry *ns, int domain, int type, int protocol)
97{
98 int sock;
99
100#ifdef CONFIG_HAP_NS
Willy Tarreau70f289c2015-10-20 15:14:07 +0200101 if (default_namespace >= 0 && ns && setns(ns->fd, CLONE_NEWNET) == -1)
KOVACS Krisztianb3e54fe2014-11-17 15:11:45 +0100102 return -1;
103#endif
104 sock = socket(domain, type, protocol);
105
106#ifdef CONFIG_HAP_NS
Willy Tarreau70f289c2015-10-20 15:14:07 +0200107 if (default_namespace >= 0 && ns && setns(default_namespace, CLONE_NEWNET) == -1) {
KOVACS Krisztianb3e54fe2014-11-17 15:11:45 +0100108 close(sock);
109 return -1;
110 }
111#endif
112
113 return sock;
114}
Willy Tarreaudba50022016-12-21 18:51:45 +0100115
116__attribute__((constructor))
117static void __ns_init(void)
118{
119 hap_register_build_opts("Built with network namespace support.", 0);
120}