reSIProcate
SIP stack, Dialog Usage Manager and related libraries
Loading...
Searching...
No Matches
TurnManager.cxx
Go to the documentation of this file.
1#include <rutil/Lock.hxx>
2
3#include "TurnManager.hxx"
4#include "TurnAllocation.hxx"
5#include <rutil/Logger.hxx>
6#include "ReTurnSubsystem.hxx"
7
8#define RESIPROCATE_SUBSYSTEM ReTurnSubsystem::RETURN
9
10using namespace std;
11
12namespace reTurn {
13
14TurnManager::TurnManager(asio::io_context& ioService, const ReTurnConfig& config) :
15 mLastAllocatedUdpPort(config.mAllocationPortRangeMin-1),
16 mLastAllocatedTcpPort(config.mAllocationPortRangeMin-1),
17 mIOService(ioService),
18 mConfig(config)
19{
20 // Initialize Allocation Ports
21 for(unsigned short i = config.mAllocationPortRangeMin; i <= config.mAllocationPortRangeMax && i != 0; i++) // i != 0 catches case where we increment 65535 (as an unsigned short)
22 {
23 mUdpAllocationPorts[i] = PortStateUnallocated;
24 mTcpAllocationPorts[i] = PortStateUnallocated;
25 }
26}
27
29{
30 InfoLog(<< "Turn Manager destroyed.");
31}
32
33bool
35{
36 if(mConfig.mMaxAllocationsPerUser == 0)
37 {
38 return false;
39 }
40 std::map<resip::Data, unsigned long>::const_iterator it = mAllocationsPerUser.find(username);
41 return it != mAllocationsPerUser.end() && it->second >= mConfig.mMaxAllocationsPerUser;
42}
43
44void
46{
47 ++mAllocationsPerUser[username];
48}
49
50void
52{
53 std::map<resip::Data, unsigned long>::iterator it = mAllocationsPerUser.find(username);
54 if(it != mAllocationsPerUser.end() && --it->second == 0)
55 {
56 mAllocationsPerUser.erase(it);
57 }
58}
59
60bool
61TurnManager::addConnection(const asio::ip::address& address)
62{
63 unsigned long& count = mConnectionsPerIp[address];
64 if(mConfig.mMaxTcpConnectionsPerIp != 0 && count >= mConfig.mMaxTcpConnectionsPerIp)
65 {
66 // Logged once while the address is at the limit, as an attacker may keep trying
67 if(mConnectionLimitLogged.insert(address).second)
68 {
69 WarningLog(<< "Already " << count << " TCP/TLS connections from " << address.to_string() << " (MaxTcpConnectionsPerIp), closing new ones");
70 }
71 else
72 {
73 DebugLog(<< "Already " << count << " TCP/TLS connections from " << address.to_string() << ", closing a new one");
74 }
75 return false;
76 }
77 ++count;
78 return true;
79}
80
81void
82TurnManager::removeConnection(const asio::ip::address& address)
83{
84 std::map<asio::ip::address, unsigned long>::iterator it = mConnectionsPerIp.find(address);
85 if(it != mConnectionsPerIp.end())
86 {
87 if(--it->second < mConfig.mMaxTcpConnectionsPerIp)
88 {
89 mConnectionLimitLogged.erase(address);
90 }
91 if(it->second == 0)
92 {
93 mConnectionsPerIp.erase(it);
94 }
95 }
96}
97
98unsigned short
100{
101 PortAllocationMap& portAllocationMap = getPortAllocationMap(transport);
102 unsigned short startPortToCheck = advanceLastAllocatedPort(transport);
103 unsigned short portToCheck = startPortToCheck;
104 while(portAllocationMap[portToCheck] != PortStateUnallocated)
105 {
106 portToCheck = advanceLastAllocatedPort(transport);
107 if(portToCheck == startPortToCheck) return 0; // If we checked all available ports and none found - then return 0
108 }
109 portAllocationMap[portToCheck] = PortStateAllocated;
110 return portToCheck;
111}
112
113unsigned short
115{
116 PortAllocationMap& portAllocationMap = getPortAllocationMap(transport);
117 unsigned short startPortToCheck = advanceLastAllocatedPort(transport);
118 // Ensure start port is even
119 while(startPortToCheck % 2 != 0)
120 {
121 startPortToCheck = advanceLastAllocatedPort(transport);
122 }
123 unsigned short portToCheck = startPortToCheck;
124 while(portAllocationMap[portToCheck] != PortStateUnallocated)
125 {
126 portToCheck = advanceLastAllocatedPort(transport, 2);
127 if(portToCheck == startPortToCheck) return 0; // If we checked all available ports and none found - then return 0
128 }
129 portAllocationMap[portToCheck] = PortStateAllocated;
130 return portToCheck;
131}
132
133// Note: This is not used, since requesting an odd port was removed
134unsigned short
136{
137 PortAllocationMap& portAllocationMap = getPortAllocationMap(transport);
138 unsigned short startPortToCheck = advanceLastAllocatedPort(transport);
139 // Ensure start port is odd
140 while(startPortToCheck % 2 != 1)
141 {
142 startPortToCheck = advanceLastAllocatedPort(transport);
143 }
144 unsigned short portToCheck = startPortToCheck;
145 while(portAllocationMap[portToCheck] != PortStateUnallocated)
146 {
147 portToCheck = advanceLastAllocatedPort(transport, 2);
148 if(portToCheck == startPortToCheck) return 0; // If we checked all available ports and none found - then return 0
149 }
150 portAllocationMap[portToCheck] = PortStateAllocated;
151 return portToCheck;
152}
153
154unsigned short
156{
157 PortAllocationMap& portAllocationMap = getPortAllocationMap(transport);
158 unsigned short startPortToCheck = advanceLastAllocatedPort(transport);
159 // Ensure start port is even and that start port + 1 is in range
160 while(startPortToCheck % 2 != 0 ||
161 startPortToCheck + 1 == 0 ||
162 startPortToCheck + 1 > mConfig.mAllocationPortRangeMax )
163 {
164 startPortToCheck = advanceLastAllocatedPort(transport);
165 }
166 unsigned short portToCheck = startPortToCheck;
167 while(portAllocationMap[portToCheck] != PortStateUnallocated || portAllocationMap[portToCheck+1] != PortStateUnallocated)
168 {
169 portToCheck = advanceLastAllocatedPort(transport, 2);
170 if(portToCheck == startPortToCheck) return 0; // If we checked all available ports and none found - then return 0
171 }
172 portAllocationMap[portToCheck] = PortStateAllocated;
173 portAllocationMap[portToCheck+1] = PortStateReserved;
174 return portToCheck;
175}
176
177bool
178TurnManager::allocatePort(StunTuple::TransportType transport, unsigned short port, bool reserved)
179{
180 if(port >= mConfig.mAllocationPortRangeMin && port <= mConfig.mAllocationPortRangeMax)
181 {
182 PortAllocationMap& portAllocationMap = getPortAllocationMap(transport);
183 if(reserved)
184 {
185 if(portAllocationMap[port] == PortStateReserved)
186 {
187 portAllocationMap[port] = PortStateAllocated;
188 return true;
189 }
190 }
191 else
192 {
193 if(portAllocationMap[port] == PortStateUnallocated)
194 {
195 portAllocationMap[port] = PortStateAllocated;
196 return true;
197 }
198 }
199 }
200 return false;
201}
202
203void
205{
206 if(port >= mConfig.mAllocationPortRangeMin && port <= mConfig.mAllocationPortRangeMax)
207 {
208 PortAllocationMap& portAllocationMap = getPortAllocationMap(transport);
209 portAllocationMap[port] = PortStateUnallocated;
210
211 // If port is even - check if next higher port is reserved - if so unallocate it
212 if(port % 2 == 0 && portAllocationMap[port+1] == PortStateReserved)
213 {
214 portAllocationMap[port+1] = PortStateUnallocated;
215 }
216 }
217}
218
219TurnManager::PortAllocationMap&
220TurnManager::getPortAllocationMap(StunTuple::TransportType transport)
221{
222 switch(transport)
223 {
224 case StunTuple::TCP:
225 case StunTuple::TLS:
226 return mTcpAllocationPorts;
227 case StunTuple::UDP:
228 default:
229 return mUdpAllocationPorts;
230 }
231}
232
233unsigned short
234TurnManager::advanceLastAllocatedPort(StunTuple::TransportType transport, unsigned int numToAdvance)
235{
236 switch(transport)
237 {
238 case StunTuple::TCP:
239 case StunTuple::TLS:
240 mLastAllocatedTcpPort+=numToAdvance;
241 if(mLastAllocatedTcpPort > mConfig.mAllocationPortRangeMax)
242 {
243 mLastAllocatedTcpPort = mConfig.mAllocationPortRangeMin+(mLastAllocatedTcpPort-mConfig.mAllocationPortRangeMax-1);
244 }
245 else if(mLastAllocatedTcpPort == 0 /* Wrap around */)
246 {
247 mLastAllocatedTcpPort = mConfig.mAllocationPortRangeMin;
248 }
249 return mLastAllocatedTcpPort;
250 case StunTuple::UDP:
251 default:
252 mLastAllocatedUdpPort+=numToAdvance;
253 if(mLastAllocatedUdpPort > mConfig.mAllocationPortRangeMax)
254 {
255 mLastAllocatedUdpPort = mConfig.mAllocationPortRangeMin+(mLastAllocatedUdpPort-mConfig.mAllocationPortRangeMax-1);
256 }
257 else if(mLastAllocatedUdpPort == 0 /* Wrap around */)
258 {
259 mLastAllocatedUdpPort = mConfig.mAllocationPortRangeMin;
260 }
261 return mLastAllocatedUdpPort;
262 }
263}
264
265} // namespace
266
267
268/* ====================================================================
269
270 Copyright (c) 2008-2026 SIP Spectrum, Inc. https://www.sipspectrum.com
271 Copyright (c) 2007-2008, Plantronics, Inc.
272 All rights reserved.
273
274 Redistribution and use in source and binary forms, with or without
275 modification, are permitted provided that the following conditions are
276 met:
277
278 1. Redistributions of source code must retain the above copyright
279 notice, this list of conditions and the following disclaimer.
280
281 2. Redistributions in binary form must reproduce the above copyright
282 notice, this list of conditions and the following disclaimer in the
283 documentation and/or other materials provided with the distribution.
284
285 3. Neither the name of Plantronics nor the names of its contributors
286 may be used to endorse or promote products derived from this
287 software without specific prior written permission.
288
289 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
290 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
291 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
292 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
293 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
294 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
295 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
296 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
297 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
298 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
299 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
300
301 ==================================================================== */
#define DebugLog(args_)
Definition Logger.hxx:128
#define InfoLog(args_)
Definition Logger.hxx:131
#define WarningLog(args_)
Definition Logger.hxx:134
unsigned short mAllocationPortRangeMax
unsigned long mMaxTcpConnectionsPerIp
unsigned short mAllocationPortRangeMin
unsigned long mMaxAllocationsPerUser
unsigned short allocateEvenPort(StunTuple::TransportType transport)
bool allocatePort(StunTuple::TransportType transport, unsigned short port, bool reserved=false)
unsigned short allocateEvenPortPair(StunTuple::TransportType transport)
void removeAllocation(const resip::Data &username)
TurnManager(asio::io_context &ioService, const ReTurnConfig &config)
unsigned short allocateAnyPort(StunTuple::TransportType transport)
void removeConnection(const asio::ip::address &address)
void deallocatePort(StunTuple::TransportType transport, unsigned short port)
bool addConnection(const asio::ip::address &address)
TCP and TLS connections per client IP address (MaxTcpConnectionsPerIp): addConnection returns false,...
unsigned short allocateOddPort(StunTuple::TransportType transport)
void addAllocation(const resip::Data &username)
bool allocationQuotaReached(const resip::Data &username) const
Allocations per user, over all transports: TurnAllocation adds and removes its own (MaxAllocationsPer...
An alternative to std::string, encapsulates an arbitrary buffer of bytes.
Definition Data.hxx:90