reSIProcate
SIP stack, Dialog Usage Manager and related libraries
Loading...
Searching...
No Matches
NetNs.cxx
Go to the documentation of this file.
1#ifdef USE_NETNS
2
3#define _GNU_SOURCE
4#include <sched.h>
5#include <sys/types.h>
6#include <sys/stat.h>
7#include <fcntl.h>
8#include <errno.h>
9
11// Note: valgrind v3.7.0 does not support the setns() call, so we use the
12// following to check for valgrind and do a crude fix-up.
14#ifdef BUILD_FOR_VALGRIND
15#include <valgrind/valgrind.h>
16#endif
17#ifndef RUNNING_ON_VALGRIND
18#define RUNNING_ON_VALGRIND 0
19#warning Defaulting RUNNING_ON_VALGRIND to 0
20#endif
21
22#ifndef HAVE_SETNS
23# include <linux/unistd.h>
24#endif
25
26#include "rutil/NetNs.hxx"
27#include "rutil/FileSystem.hxx"
28#include "rutil/Logger.hxx"
29
30#define RESIPROCATE_SUBSYSTEM Subsystem::TRANSPORT
31#define DEFAULT_NET_NAMESPACE "/proc/1/ns/net"
32#define NET_NAMESPACE_DIR "/var/run/netns/"
33
34using namespace resip;
35
36// Static declarations
37HashMap<int, Data> NetNs::sIdDictionaryToNetNs;
38HashMap<Data, int> NetNs::sNetNsDictionaryToId;
39
40// Methods
41int NetNs::setNs(const Data& netNs)
42{
43 int netNsFd = openNetNs(netNs);
44 if(netNsFd < 0)
45 {
48
49 if(errno == EACCES)
50 {
51 // This is a bit heuristic, but let it go if we did not have permission to open the global
52 // netns. This is probably because we are not running as root/privileged user and cannot
53 // open the global net namespace file. If thats the case, odds are that we were also not
54 // able to change to a non-global/default net namespaces. So we should still be in the
55 // global net namespace. Let this be a no-op
56 if(netNs.empty())
57 {
58 WarningLog(<< "Permission denied opening global netns. Assuming already using global netns.");
59 }
60 else
61 {
62 throw Exception("Permission denied opening \"" + deviceName + "\" to set setns, may need to run as root",
64 }
65 }
66 else
67 {
68 throw Exception("Can't open name space \"" + deviceName + "\" errno: " + Data((int) errno), __FILE__,__LINE__);
69 }
70 }
71
72 // Should only get here with an invalid netNsFd when we don't have permission
73 // to open global netns file. As described above. So no-op if we have an invalid netNsFd for
74 // the global netns namespace
75 if(netNsFd >= 0)
76 {
77 DebugLog(<< "setns(\"" << netNs << "\"(" << netNsFd << "))");
78 int error;
79
80#ifdef HAVE_SETNS
81#define DO_SETNS(fd, flag) setns(fd, flag)
82#else
83// Make system call directly
84#define DO_SETNS(fd, flag) syscall(__NR_setns, fd, flag)
85#endif
86
88 // Note: valgrind v3.7.0 does not support the setns() call. In order to work
89 // around this, we make the syscall to setns, indicate that an "error" occurred, and
90 // then suppress throwing the exception. It's kind of an ugly hack, but it
91 // does let us run valgrind on our code.
93
95
96 if(error)
97 {
98 // setns normally closes the file descriptor when it is done, but because
99 // it failed close the FD here just in case.
100 close(netNsFd);
101
102 if (!(RUNNING_ON_VALGRIND)) {
103 throw Exception("Can't change to name space \"" + netNs + "\"(fd:" +
104 Data((int) netNsFd) + "), error: " + Data((int) error) +
105 " errno: " + Data((int) errno), __FILE__,__LINE__);
106 }
107 }
108
109 // Add name to the dictionary if it is not already in there
110 }
111 return(getNetNsId(netNs, true));
112}
113
114int NetNs::getPublicNetNs(std::vector<Data>& netNsNames)
115{
116 // Add global netns name
117 int nameCount = 1;
118 netNsNames.push_back("");
119
122 {
123 if(!dirItr.is_directory())
124 {
125 netNsNames.push_back(*dirItr);
126 nameCount++;
127 }
128 }
129 return(nameCount);
130}
131
132void NetNs::makeNetNsDeviceName(const Data& netNs, Data& netNsDeviceName)
133{
134 if(netNs.empty())
135 {
136 // empty string means the global namespace. As it does not
137 // have a name, we instead open and switch to the namespace used
138 // by process 1 which should be the global namespace
140 }
141 else
142 {
144 netNsDeviceName += netNs;
145 }
146}
147
148int NetNs::openNetNs(const Data& netNs)
149{
152 int netNsFd = open(nameSpacePath.c_str(), O_RDONLY);
153
154 if(netNsFd >= 0)
155 {
156 DebugLog(<< "Opened netns: " << nameSpacePath << " fd: " << Data((int) netNsFd));
157 }
158
159 return(netNsFd);
160}
161
162bool NetNs::netNsExists(const Data& netNs)
163{
164 int netNsFd = openNetNs(netNs);
165 if(netNsFd >= 0 )
166 {
167 DebugLog(<< "Closing netns fd: " << Data((int) netNsFd));
168 close(netNsFd);
169 }
170
171 return(netNsFd >= 0);
172}
173
174int NetNs::getNetNsId(const Data& netNsName, bool shouldAdd)
175{
177
178 int netNsId = -1;
179
180 HashMap<Data, int>::iterator netNsIterator = sNetNsDictionaryToId.find(netNsName);
182 {
183 netNsId = netNsIterator->second;
184 }
185 else if(shouldAdd)
186 {
187 netNsId = netNsName.caseInsensitiveTokenHash();
188 int originalId = netNsId;
189 // If hash is not unique, find the next available id
191 {
192 netNsId++;
193 }
194
195 // This means another netns name had the same hash (i.e. the hash is
196 // not unique. So there is a likelyhood that in another instance
197 // of resip::SipStack (e.g. configured for replicating this instance)
198 // we could get a different id for this netns name.
199 // That could cause problems if the Tuple binary token was generated on
200 // on instance of resip:SipStack for the Record-Route and another instance
201 // of resip::SipStack recieved that Route as its Route to pop off.
202 if(originalId != netNsId)
203 {
204 WarningLog(<< "Non-unique netns hashes. " << netNsName << ": " << netNsId
206 }
207
208 DebugLog(<< "Adding netns to dictionary: " << netNsName << ": " << netNsId);
211 }
212
213 return(netNsId);
214}
215
216const Data& NetNs::getNetNsName(int netNsId)
217{
219
220 HashMap<int, Data>::iterator idIterator = sIdDictionaryToNetNs.find(netNsId);
222 {
223 throw Exception("netns id: " + Data(netNsId) + " does not exist",
225 }
226 return(idIterator->second);
227}
228
229void NetNs::initDictionary()
230{
231 // Make sure there is an entry in the dictionary for the
232 // global namespace "" (empty string)
233 if(sIdDictionaryToNetNs.size() == 0 &&
234 sNetNsDictionaryToId.size() == 0)
235 {
236 Data defaultNetNs("");
237 sIdDictionaryToNetNs[defaultNetNs.caseInsensitiveTokenHash()] = defaultNetNs;
238 sNetNsDictionaryToId[""] = 0;
239
240 // No locking, so test no one else touched
241 // the dictionary
244 }
245}
246
247#endif
248
249/* ====================================================================
250 *
251 * Copyright (c) Daniel Petrie, SIPez LLC. All rights reserved.
252 *
253 * Redistribution and use in source and binary forms, with or without
254 * modification, are permitted provided that the following conditions
255 * are met:
256 *
257 * 1. Redistributions of source code must retain the above copyright
258 * notice, this list of conditions and the following disclaimer.
259 *
260 * 2. Redistributions in binary form must reproduce the above copyright
261 * notice, this list of conditions and the following disclaimer in
262 * the documentation and/or other materials provided with the
263 * distribution.
264 *
265 * 3. Neither the name of the author(s) nor the names of any contributors
266 * may be used to endorse or promote products derived from this software
267 * without specific prior written permission.
268 *
269 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTORS "AS IS" AND
270 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
271 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
272 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTORS BE LIABLE
273 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
274 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
275 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
276 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
277 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
278 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
279 * SUCH DAMAGE.
280 *
281 * vi: set shiftwidth=3 expandtab:
282 */
#define DebugLog(args_)
Definition Logger.hxx:128
#define WarningLog(args_)
Definition Logger.hxx:134
#define resip_assert(x)
This file needs to work for both C and C++ code.
An alternative to std::string, encapsulates an arbitrary buffer of bytes.
Definition Data.hxx:90
bool empty() const noexcept
Checks whether the Data is empty.
Definition Data.hxx:591
dcm! – add UnusedChecking(_enum) below;
void list()
Definition userAdmin.cxx:66