17#define RESIPROCATE_SUBSYSTEM ReTurnSubsystem::RETURN
25#define DEFAULT_BANDWIDTH 100
28 const asio::ip::address* prim3489Address,
unsigned short* prim3489Port,
29 const asio::ip::address* alt3489Address,
unsigned short* alt3489Port)
30 : mTurnManager(turnManager)
32 if(prim3489Address && prim3489Port && alt3489Address && alt3489Port)
34 mRFC3489SupportEnabled =
true;
35 mPrim3489Address = *prim3489Address;
36 mPrim3489Port = *prim3489Port;
37 mAlt3489Address = *alt3489Address;
38 mAlt3489Port = *alt3489Port;
42 mRFC3489SupportEnabled =
false;
54 if(handleAuthentication(request, response))
59 InfoLog(<<
"Received Request with unknown comprehension-required attributes. Sending 420. Sender=" << request.
mRemoteTuple);
60 buildErrorResponse(response, 420,
"Unknown attribute");
73 result = processStunBindingRequest(request, response, isRFC3489BackwardsCompatServer);
77 result = processStunSharedSecretRequest(request, response);
81 result = processTurnAllocateRequest(turnSocket, turnAllocationManager, request, response);
91 result = processTurnRefreshRequest(turnAllocationManager, request, response);
95 result = processTurnCreatePermissionRequest(turnAllocationManager, request, response);
99 result = processTurnChannelBindRequest(turnAllocationManager, request, response);
103 buildErrorResponse(response, 400,
"Invalid Request Method");
113 processTurnSendIndication(turnAllocationManager, request);
161RequestHandler::buildErrorResponse(
StunMessage& response,
unsigned short errorCode,
const char* msg)
168RequestHandler::buildErrorResponseWithRealmAndNonce(
StunMessage& response,
unsigned short errorCode,
const char* msg,
const Data& realm,
const StunMessage& request)
171 response.setErrorCode(errorCode, msg);
172 response.setRealm(realm.
c_str());
176 generateNonce(timestamp, nonce, request);
177 response.setNonce(nonce.c_str());
181RequestHandler::generateNonce(
const Data& timestamp,
Data& nonce,
const StunMessage& request)
189 <<
":" << request.getRemoteTuple()
190 <<
":" << mPrivateNonceKey;
192 nonce += noncePrivate.
md5();
195RequestHandler::CheckNonceResult
196RequestHandler::checkNonce(
const Data& nonce,
const StunMessage& request)
199 if (!pb.eof() && !isdigit(
static_cast< unsigned char >(*pb.position())))
201 DebugLog(<<
"Invalid nonce. Expected timestamp.");
204 const char* anchor = pb.position();
208 DebugLog(<<
"Invalid nonce. Expected timestamp terminator.");
212 Data creationTimeData;
214 pb.
data(creationTimeData, anchor);
216 if((now-creationTime) <=
getConfig().mNonceLifetime)
220 generateNonce(creationTimeData, nonceToMatch, request);
221 if(nonceToMatch == nonce)
227 DebugLog(<<
"Invalid nonce. Not generated by this server.");
233 DebugLog(<<
"Invalid nonce. Expired.");
249 if (!request.mHasMessageIntegrity)
251 InfoLog(<<
"Received Request with no Message Integrity. Sending 401. Sender=" << request.mRemoteTuple);
252 buildErrorResponseWithRealmAndNonce(response, 401,
"Unauthorized (no MessageIntegrity)",
getConfig().mAuthenticationRealm, request);
257 if (!request.mHasUsername)
259 WarningLog(<<
"No Username and contains MessageIntegrity. Sending 400. Sender=" << request.mRemoteTuple);
260 buildErrorResponse(response, 400,
"Bad Request (no Username and contains MessageIntegrity)");
264 if(!request.mHasRealm)
266 WarningLog(<<
"No Realm. Sending 400. Sender=" << request.mRemoteTuple);
267 buildErrorResponse(response, 400,
"Bad Request (No Realm)");
270 if(!request.mHasNonce)
272 WarningLog(<<
"No Nonce and contains realm. Sending 400. Sender=" << request.mRemoteTuple);
273 buildErrorResponse(response, 400,
"Bad Request (No Nonce and contains Realm)");
276 switch(checkNonce(*request.mNonce, request))
282 WarningLog(<<
"Nonce expired. Sending 438. Sender=" << request.mRemoteTuple);
283 buildErrorResponseWithRealmAndNonce(response, 438,
"Stale Nonce",
getConfig().mAuthenticationRealm, request);
288 WarningLog(<<
"Invalid Nonce. Sending 400. Sender=" << request.mRemoteTuple);
289 buildErrorResponse(response, 400,
"BadRequest (Invalid Nonce)");
294 StackLog(<<
"Validating username: " << *request.mUsername);
298 if (!
getConfig().isUserNameValid(*request.mUsername, *request.mRealm))
300 WarningLog(<<
"Invalid username '" << *request.mUsername <<
"' or realm '" << *request.mRealm <<
"' (username unknown or potential AuthorizationRealm mismatch). Sending 401. Sender=" << request.mRemoteTuple);
301 buildErrorResponseWithRealmAndNonce(response, 401,
"Unauthorized",
getConfig().mAuthenticationRealm, request);
305 StackLog(<<
"Validating MessageIntegrity");
312 request.calculateHmacKeyForHa1(hmacKey,
getConfig().getHa1ForUsername(*request.mUsername, *request.mRealm));
314 if(!request.checkMessageIntegrity(hmacKey))
316 WarningLog(<<
"MessageIntegrity is bad. Sending 401. Sender=" << request.mRemoteTuple);
317 buildErrorResponseWithRealmAndNonce(response, 401,
"Unauthorized",
getConfig().mAuthenticationRealm, request);
322 response.mHasMessageIntegrity =
true;
323 response.mHmacKey = hmacKey;
330RequestHandler::processStunBindingRequest(
StunMessage& request,
StunMessage& response,
bool isRFC3489BackwardsCompatServer)
338 if(request.hasMagicCookie())
340 response.mHasXorMappedAddress =
true;
346 response.mHasMappedAddress =
true;
351 response.mHasXorMappedAddress =
true;
357 if(mRFC3489SupportEnabled && isRFC3489BackwardsCompatServer)
359 StunTuple sendFromTuple;
360 StunTuple changeTuple;
362 sendFromTuple.setTransportType(request.mLocalTuple.getTransportType());
363 changeTuple.setTransportType(request.mLocalTuple.getTransportType());
364 changeTuple.setAddress(request.mLocalTuple.getAddress() == mPrim3489Address ? mAlt3489Address : mPrim3489Address);
365 changeTuple.setPort(request.mLocalTuple.getPort() == mPrim3489Port ? mAlt3489Port : mPrim3489Port);
366 uint32_t changeRequest = request.mHasChangeRequest ? request.mChangeRequest : 0;
371 sendFromTuple.setAddress(changeTuple.getAddress());
372 sendFromTuple.setPort(changeTuple.getPort());
377 sendFromTuple.setAddress(request.mLocalTuple.getAddress());
378 sendFromTuple.setPort(changeTuple.getPort());
383 sendFromTuple.setAddress(changeTuple.getAddress());
384 sendFromTuple.setPort(request.mLocalTuple.getPort());
389 sendFromTuple.setAddress(request.mLocalTuple.getAddress());
390 sendFromTuple.setPort(request.mLocalTuple.getPort());
394 response.mHasSourceAddress =
true;
398 response.mHasChangedAddress =
true;
403 if(request.mHasResponseAddress)
409 if (request.mHasUsername && (request.mUsername->size() >= 92 ) )
412 StunTuple responseTuple;
413 request.getTupleFromUsername(responseTuple);
415 response.mHasReflectedFrom =
true;
420 response.mHasReflectedFrom =
true;
435 WarningLog(<<
"Invalid transport for shared secret request. TLS required. Sending 433. Sender=" << request.mRemoteTuple);
436 buildErrorResponse(response, 433,
"Invalid transport. TLS required.");
444 response.createUsernameAndPassword();
450RequestHandler::processTurnAllocateRequest(AsyncSocketBase* turnSocket, TurnAllocationManager& turnAllocationManager,
StunMessage& request,
StunMessage& response)
454 if(!request.mHasMessageIntegrity)
456 WarningLog(<<
"Turn allocate request without authentication. Sending 401. Sender=" << request.mRemoteTuple);
457 buildErrorResponseWithRealmAndNonce(response, 401,
"Missing Message Integrity",
getConfig().mAuthenticationRealm, request);
461 DebugLog(<<
"Allocation request received: localTuple=" << request.mLocalTuple <<
", remoteTuple=" << request.mRemoteTuple);
463 TurnAllocation* allocation = turnAllocationManager.findTurnAllocation(TurnAllocationKey(request.mLocalTuple, request.mRemoteTuple));
468 WarningLog(<<
"Allocation requested but already exists. Sending 437. Sender=" << request.mRemoteTuple);
469 buildErrorResponse(response, 437,
"Allocation Mismatch");
476 WarningLog(<<
"User " << *request.mUsername <<
" already has " <<
getConfig().mMaxAllocationsPerUser <<
" allocations. Sending 486. Sender=" << request.mRemoteTuple);
477 buildErrorResponse(response, 486,
"Allocation Quota Reached");
482 StunTuple allocationTuple(request.mLocalTuple.getTransportType(),
483 request.mLocalTuple.getAddress(),
487 if(request.mHasTurnRequestedTransport)
491 WarningLog(<<
"Invalid transport requested. Sending 442. Sender=" << request.mRemoteTuple);
492 buildErrorResponse(response, 442,
"Unsupported Transport Protocol");
499 WarningLog(<<
"Missing requested transport header. Sending 400. Sender=" << request.mRemoteTuple);
500 buildErrorResponse(response, 400,
"Bad Request - Missing requested transport");
505 if(request.mHasTurnDontFragment)
507 WarningLog(<<
"Turn allocate request with Don't Fragment requested, not yet implemented. Sending 420. Sender=" << request.mRemoteTuple);
508 buildErrorResponse(response, 420,
"Don't Fragment not yet implemented");
513 if(request.mHasTurnBandwidth)
518 if(request.mHasTurnEvenPort && request.mHasTurnReservationToken)
520 WarningLog(<<
"Both Even Port and Reservation Token attributes are present. Sending 400. Sender=" << request.mRemoteTuple);
521 buildErrorResponse(response, 400,
"Bad request - both Even Port and Reservation Token present");
526 if(request.mHasTurnLifetime)
529 if(request.mTurnLifetime >
getConfig().mMaxAllocationLifetime)
534 else if(request.mTurnLifetime >
getConfig().mDefaultAllocationLifetime)
536 lifetime = request.mTurnLifetime;
544 for(
unsigned int attempt = 1; ; ++attempt)
546 unsigned short port = 0;
547 if(request.mHasTurnEvenPort)
560 response.mHasTurnReservationToken = port != 0;
561 response.mTurnReservationToken = port + 1;
565 WarningLog(<<
"Unable to allocate requested port. Sending 508. Sender=" << request.mRemoteTuple);
566 buildErrorResponse(response, 508,
"Insufficient Port Capacity");
571 if(request.mHasTurnReservationToken)
574 port = (
unsigned short)request.mTurnReservationToken;
575 if(!mTurnManager.
allocatePort(allocationTuple.getTransportType(), port,
true ))
577 WarningLog(<<
"Unable to allocate requested port - bad reservation token. Sending 508. Sender=" << request.mRemoteTuple);
578 buildErrorResponse(response, 508,
"Insufficient Port Capacity");
586 port = mTurnManager.
allocateAnyPort(allocationTuple.getTransportType());
589 WarningLog(<<
"Unable to allocate port. Sending 508. Sender=" << request.mRemoteTuple);
590 buildErrorResponse(response, 508,
"Insufficient Port Capacity");
595 allocationTuple.setPort(port);
600 allocation =
new TurnAllocation(mTurnManager,
601 turnAllocationManager,
604 request.mRemoteTuple,
605 StunAuth(*request.mUsername, response.mHmacKey),
609 catch (
const asio::system_error&)
611 mTurnManager.
deallocatePort(allocationTuple.getTransportType(), port);
612 ErrLog(<<
"Error allocating socket for allocation. Sending 500. Sender=" << request.mRemoteTuple);
613 response.mHasTurnReservationToken =
false;
614 buildErrorResponse(response, 500,
"Server Error");
618 if(allocation->startRelay())
624 if(request.mHasTurnReservationToken || attempt >= portsInRange)
626 ErrLog(<<
"Unable to start an allocation relay. Sending 508. Sender=" << request.mRemoteTuple);
627 response.mHasTurnReservationToken =
false;
628 buildErrorResponse(response, 508,
"Insufficient Port Capacity");
631 WarningLog(<<
"Unable to start an allocation relay on port " << port <<
", trying another. Sender=" << request.mRemoteTuple);
635 turnAllocationManager.addTurnAllocation(allocation);
640 response.mHasTurnLifetime =
true;
641 response.mTurnLifetime = lifetime;
643 response.mHasTurnXorRelayedAddress =
true;
658RequestHandler::processTurnRefreshRequest(TurnAllocationManager& turnAllocationManager,
StunMessage& request,
StunMessage& response)
662 if(!request.mHasMessageIntegrity)
664 WarningLog(<<
"Turn refresh request without authentication. Sending 401. Sender=" << request.mRemoteTuple);
665 buildErrorResponseWithRealmAndNonce(response, 401,
"Missing Message Integrity",
getConfig().mAuthenticationRealm, request);
669 TurnAllocation* allocation = turnAllocationManager.findTurnAllocation(TurnAllocationKey(request.mLocalTuple, request.mRemoteTuple));
673 WarningLog(<<
"Refresh requested with non-matching allocation. Sending 437. Sender=" << request.mRemoteTuple);
674 buildErrorResponse(response, 437,
"Allocation Mismatch");
679 if(allocation->getClientAuth().getClientUsername() != *request.mUsername)
681 WarningLog(<<
"Refresh requested with username not matching allocation. Sending 441. Sender=" << request.mRemoteTuple);
682 buildErrorResponse(response, 441,
"Wrong Credentials");
685 if(allocation->getClientAuth().getClientSharedSecret() != response.mHmacKey)
687 WarningLog(<<
"Refresh requested with shared secret not matching allocation. Sending 441. Sender=" << request.mRemoteTuple);
688 buildErrorResponse(response, 441,
"Wrong Credentials");
693 if(request.mHasTurnLifetime && request.mTurnLifetime == 0)
698 response.mHasTurnLifetime =
true;
699 response.mTurnLifetime = 0;
704 turnAllocationManager.removeTurnAllocation(allocation->getKey());
711 if(request.mHasTurnLifetime)
714 if(request.mTurnLifetime >
getConfig().mMaxAllocationLifetime)
719 else if(request.mTurnLifetime >
getConfig().mDefaultAllocationLifetime)
721 lifetime = request.mTurnLifetime;
726 allocation->refresh(lifetime);
731 response.mHasTurnLifetime =
true;
732 response.mTurnLifetime = lifetime;
744RequestHandler::processTurnCreatePermissionRequest(TurnAllocationManager& turnAllocationManager,
StunMessage& request,
StunMessage& response)
747 if(!request.mHasMessageIntegrity)
749 WarningLog(<<
"Turn create permission request without authentication. Send 401. Sender=" << request.mRemoteTuple);
750 buildErrorResponseWithRealmAndNonce(response, 401,
"Missing Message Integrity",
getConfig().mAuthenticationRealm, request);
754 TurnAllocation* allocation = turnAllocationManager.findTurnAllocation(TurnAllocationKey(request.mLocalTuple, request.mRemoteTuple));
758 WarningLog(<<
"Turn create permission request for non-existing allocation. Send 437. Sender=" << request.mRemoteTuple);
759 buildErrorResponse(response, 437,
"No Allocation");
764 if(allocation->getClientAuth().getClientUsername() != *request.mUsername)
766 WarningLog(<<
"Create permission requested with username not matching allocation. Sending 441. Sender=" << request.mRemoteTuple);
767 buildErrorResponse(response, 441,
"Wrong Credentials");
770 if(allocation->getClientAuth().getClientSharedSecret() != response.mHmacKey)
772 WarningLog(<<
"Create permission requested with shared secret not matching allocation. Sending 441. Sender=" << request.mRemoteTuple);
773 buildErrorResponse(response, 441,
"Wrong Credentials");
777 if(request.mCntTurnXorPeerAddress > 0)
779 StunTuple remoteAddress;
780 remoteAddress.setTransportType(allocation->getRequestedTuple().getTransportType());
781 for (
int i = 0; i < request.mCntTurnXorPeerAddress; i++)
784 allocation->refreshPermission(remoteAddress.getAddress());
789 WarningLog(<<
"Create permission request missing peer address. Sending 400. Sender=" << request.mRemoteTuple);
790 buildErrorResponse(response, 400,
"Bad Request - missing attribute");
803RequestHandler::processTurnChannelBindRequest(TurnAllocationManager& turnAllocationManager,
StunMessage& request,
StunMessage& response)
806 if(!request.mHasMessageIntegrity)
808 WarningLog(<<
"Turn channel bind request without authentication. Send 401. Sender=" << request.mRemoteTuple);
809 buildErrorResponseWithRealmAndNonce(response, 401,
"Missing Message Integrity",
getConfig().mAuthenticationRealm, request);
813 TurnAllocation* allocation = turnAllocationManager.findTurnAllocation(TurnAllocationKey(request.mLocalTuple, request.mRemoteTuple));
817 WarningLog(<<
"Turn channel bind request for non-existing allocation. Send 437. Sender=" << request.mRemoteTuple);
818 buildErrorResponse(response, 437,
"No Allocation");
823 if(allocation->getClientAuth().getClientUsername() != *request.mUsername)
825 WarningLog(<<
"Channel bind requested with username not matching allocation. Sending 441. Sender=" << request.mRemoteTuple);
826 buildErrorResponse(response, 441,
"Wrong Credentials");
829 if(allocation->getClientAuth().getClientSharedSecret() != response.mHmacKey)
831 WarningLog(<<
"Channel bind requested with shared secret not matching allocation. Sending 441. Sender=" << request.mRemoteTuple);
832 buildErrorResponse(response, 441,
"Wrong Credentials");
836 if(request.mCntTurnXorPeerAddress > 0 && request.mHasTurnChannelNumber)
841 WarningLog(<<
"Channel bind requested with an out of range channel number=" << request.mTurnChannelNumber <<
". Sending 400. Sender=" << request.mRemoteTuple);
842 buildErrorResponse(response, 400,
"Bad Request - channel number out of range");
846 StunTuple remoteAddress;
847 remoteAddress.setTransportType(allocation->getRequestedTuple().getTransportType());
851 if(!allocation->addChannelBinding(remoteAddress, request.mTurnChannelNumber))
853 WarningLog(<<
"Channel bind request invalid. Sending 400. Sender=" << request.mRemoteTuple);
854 buildErrorResponse(response, 400,
"Bad Request");
860 WarningLog(<<
"Channel bind request missing peer address and/or channel number. Sending 400. Sender=" << request.mRemoteTuple);
861 buildErrorResponse(response, 400,
"Bad Request - missing attribute");
878RequestHandler::processTurnSendIndication(TurnAllocationManager& turnAllocationManager,
StunMessage& request)
880 TurnAllocation* allocation = turnAllocationManager.findTurnAllocation(TurnAllocationKey(request.mLocalTuple, request.mRemoteTuple));
884 DebugLog(<<
"Turn SendIndication for non existing allocation (Local=" << request.mLocalTuple <<
", remote=" << request.mRemoteTuple <<
"). Dropping.");
888 if(request.mCntTurnXorPeerAddress == 0 || !request.mHasTurnData)
890 DebugLog(<<
"Turn send indication with no peer address or data (Local=" << request.mLocalTuple <<
", remote=" << request.mRemoteTuple <<
"). Dropping.");
895 if(request.mHasTurnDontFragment)
897 DebugLog(<<
"Turn send indication with Don't Fragment requested, not yet implemented. Dropping. Sender=" << request.mRemoteTuple);
901 StunTuple remoteAddress;
902 remoteAddress.setTransportType(allocation->getRequestedTuple().getTransportType());
906 const auto data = std::make_shared<DataBuffer>(request.mTurnData->data(), request.mTurnData->size());
907 allocation->sendDataToPeer(remoteAddress, data,
false );
917 DebugLog(<<
"Turn channel data for non existing allocation. Dropping. Sender=" << remoteTuple);
#define WarningLog(args_)
#define resip_assert(x)
This file needs to work for both C and C++ code.
unsigned short mAllocationPortRangeMax
unsigned short mAllocationPortRangeMin
unsigned long mDefaultAllocationLifetime
unsigned long mMaxAllocationLifetime
void processTurnData(TurnAllocationManager &turnAllocationManager, unsigned short channelNumber, const StunTuple &localTuple, const StunTuple &remoteTuple, const std::shared_ptr< DataBuffer > &data)
const ReTurnConfig & getConfig()
RequestHandler(TurnManager &turnManager, const asio::ip::address *prim3489Address=0, unsigned short *prim3489Port=0, const asio::ip::address *alt3489Address=0, unsigned short *alt3489Port=0)
ProcessResult processStunMessage(AsyncSocketBase *turnSocket, TurnAllocationManager &turnAllocationManager, StunMessage &request, StunMessage &response, bool isRFC3489BackwardsCompatServer=false)
Process a received StunMessage, and produce a reply Returns true if the response message is to be sen...
@ RespondFromAlternateIpPort
@ RespondFromAlternatePort
static const uint16_t StunClassSuccessResponse
static const uint16_t SharedSecretMethod
static const uint16_t BindMethod
bool mHasUnknownAttributes
static const uint16_t TurnSendMethod
StunAtrUnknown mUnknownAttributes
static const uint32_t ChangeIpFlag
StunAtrUnknown mUnknownRequiredAttributes
static const uint16_t StunClassErrorResponse
static const uint16_t TurnCreatePermissionMethod
static const uint16_t StunClassRequest
static const uint16_t TurnAllocateMethod
StunAtrAddress mXorMappedAddress
void setSoftware(const char *software)
static const uint32_t ChangePortFlag
void setErrorCode(unsigned short errorCode, const char *reason)
static const uint16_t TurnDataMethod
static void setStunAtrAddressFromTuple(StunAtrAddress &address, const StunTuple &tuple)
static const uint8_t PropsPortEven
static const uint16_t TurnRefreshMethod
static const uint8_t PropsPortPair
static const uint32_t RequestedTransportUdp
static const uint16_t TurnChannelBindMethod
static const uint16_t StunClassIndication
bool mHasXorMappedAddress
static void setTupleFromStunAtrAddress(StunTuple &tuple, const StunAtrAddress &address)
TurnAllocation * findTurnAllocation(const TurnAllocationKey &turnAllocationKey)
void sendDataToPeer(unsigned short channelNumber, const std::shared_ptr< DataBuffer > &data, bool isFramed)
unsigned short allocateEvenPort(StunTuple::TransportType transport)
bool allocatePort(StunTuple::TransportType transport, unsigned short port, bool reserved=false)
unsigned short allocateEvenPortPair(StunTuple::TransportType transport)
unsigned short allocateAnyPort(StunTuple::TransportType transport)
void deallocatePort(StunTuple::TransportType transport, unsigned short port)
bool allocationQuotaReached(const resip::Data &username) const
Allocations per user, over all transports: TurnAllocation adds and removes its own (MaxAllocationsPer...
An iostream that operates on an existing Data.
An alternative to std::string, encapsulates an arbitrary buffer of bytes.
const char * c_str() const
Returns a null-terminated string representing.
uint64_t convertUInt64() const
Takes the contents of the Data and converts them to an unsigned 64-bit integer.
static const PreallocateType Preallocate
used only to disambiguate constructors
size_type size() const noexcept
Returns the number of bytes in this Data.
Data md5(EncodingType type=HEX) const
Computes the MD5 hash of the current data.
const char * data() const noexcept
Returns a pointer to the contents of this Data.
Provides string-parsing functionality with protection from buffer overflow.
static Data getCryptoRandomHex(unsigned int numBytes)
static uint64_t getTimeMs()
Returns the current clock time in milliseconds.
dcm! – add UnusedChecking(_enum) below;
unsigned __int64 uint64_t
UInt128 magicCookieAndTid