blob: 6734b5da69069ad1da81f4c5b1a9bd41d8399d30 [file] [log] [blame]
Andreas Schultzb6292402018-10-05 13:58:45 +01001/*
2 * Copyright (C) 2014-2017, Travelping GmbH <info@travelping.com>
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU Affero General Public License as
6 * published by the Free Software Foundation, either version 3 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU Affero General Public License for more details.
13 *
14 * You should have received a copy of the GNU Affero General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 *
17 */
18
19#if defined(__linux__)
20
21#ifdef HAVE_CONFIG_H
22# include "config.h"
23#endif
24
25#ifndef _GNU_SOURCE
26# define _GNU_SOURCE
27#endif
28
29#include <errno.h>
30#include <stdio.h>
31#include <stdlib.h>
32#include <unistd.h>
33#include <sched.h>
34#include <signal.h>
35#include <sys/types.h>
36#include <sys/stat.h>
37#include <sys/socket.h>
38#include <sys/mount.h>
39#include <sys/param.h>
40#include <fcntl.h>
41#include <errno.h>
42
43#include "netns.h"
44
45#define NETNS_PATH "/var/run/netns"
46
47static int default_nsfd;
48
49int switch_ns(int nsfd, sigset_t *oldmask)
50{
51 sigset_t intmask;
52
53 sigfillset(&intmask);
54 sigprocmask(SIG_BLOCK, &intmask, oldmask);
55
56 return setns(nsfd, CLONE_NEWNET);
57}
58
59void restore_ns(sigset_t *oldmask)
60{
61 setns(default_nsfd, CLONE_NEWNET);
62
63 sigprocmask(SIG_SETMASK, oldmask, NULL);
64}
65
66int open_ns(int nsfd, const char *pathname, int flags)
67{
68 sigset_t intmask, oldmask;
69 int fd;
70 int errsv;
71
72 sigfillset(&intmask);
73 sigprocmask(SIG_BLOCK, &intmask, &oldmask);
74
75 setns(nsfd, CLONE_NEWNET);
76 fd = open(pathname, flags);
77 errsv = errno;
78 setns(default_nsfd, CLONE_NEWNET);
79
80 sigprocmask(SIG_SETMASK, &oldmask, NULL);
81
82 errno = errsv;
83 return fd;
84}
85
86int socket_ns(int nsfd, int domain, int type, int protocol)
87{
88 sigset_t intmask, oldmask;
89 int sk;
90 int errsv;
91
92 sigfillset(&intmask);
93 sigprocmask(SIG_BLOCK, &intmask, &oldmask);
94
95 setns(nsfd, CLONE_NEWNET);
96 sk = socket(domain, type, protocol);
97 errsv = errno;
98 setns(default_nsfd, CLONE_NEWNET);
99
100 sigprocmask(SIG_SETMASK, &oldmask, NULL);
101
102 errno = errsv;
103 return sk;
104}
105
106void init_netns()
107{
108 if ((default_nsfd = open("/proc/self/ns/net", O_RDONLY)) < 0) {
109 perror("init_netns");
110 exit(EXIT_FAILURE);
111 }
112}
113
114int get_nsfd(const char *name)
115{
116 int r;
117 sigset_t intmask, oldmask;
118 char path[MAXPATHLEN] = NETNS_PATH;
119
120 r = mkdir(path, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH);
121 if (r < 0 && errno != EEXIST)
122 return r;
123
124 snprintf(path, sizeof(path), "%s/%s", NETNS_PATH, name);
125 r = open(path, O_RDONLY|O_CREAT|O_EXCL, 0);
126 if (r < 0) {
127 if (errno == EEXIST)
128 return open(path, O_RDONLY);
129
130 return r;
131 }
132 close(r);
133
134 sigfillset(&intmask);
135 sigprocmask(SIG_BLOCK, &intmask, &oldmask);
136
137 unshare(CLONE_NEWNET);
138 mount("/proc/self/ns/net", path, "none", MS_BIND, NULL);
139
140 setns(default_nsfd, CLONE_NEWNET);
141
142 sigprocmask(SIG_SETMASK, &oldmask, NULL);
143
144 return open(path, O_RDONLY);
145}
146
147#endif