HRESULT CTestClientLogic::GenerateBindingResponseMessage(const CSocketAddress& addrMapped, const StunTransactionId& transid, CRefCountedBuffer& spMsg) { HRESULT hr = S_OK; CStunMessageBuilder builder; builder.GetStream().Attach(spMsg, true); ChkA(builder.AddBindingResponseHeader(true)); ChkA(builder.AddTransactionId(transid)); ChkA(builder.AddXorMappedAddress(addrMapped)); ChkA(builder.FixLengthField()); Cleanup: return hr; }
HRESULT CStunClientTestBase::StartBindingRequest(CStunMessageBuilder& builder) { builder.AddBindingRequestHeader(); if (IsTransactionIdValid(_transid)) { builder.AddTransactionId(_transid); } else { builder.AddRandomTransactionId(&_transid); } return S_OK; }
void CStunThreadMessageHandler::SendErrorResponse() { HRESULT hr = S_OK; CStunMessageBuilder builder; CRefCountedBuffer spBuffer; _spResponseBuffer->SetSize(0); builder.GetStream().Attach(_spResponseBuffer, true); builder.AddHeader((StunMessageType)_error.msgtype, _error.msgclass); builder.AddTransactionId(_transid); builder.AddErrorCode(_error.errorcode, "FAILED"); if ((_error.errorcode == ::STUN_ERROR_UNKNOWNATTRIB) && (_error.attribUnknown != 0)) { builder.AddUnknownAttributes(&_error.attribUnknown, 1); } else if ((_error.errorcode == ::STUN_ERROR_STALENONCE) || (_error.errorcode == ::STUN_ERROR_UNAUTHORIZED)) { if (_error.szNonce[0]) { builder.AddStringAttribute(STUN_ATTRIBUTE_NONCE, _error.szNonce); } if (_error.szRealm[0]) { builder.AddStringAttribute(STUN_ATTRIBUTE_REALM, _error.szRealm); } } ChkIfA(_spStunResponder == NULL, E_FAIL); builder.GetResult(&spBuffer); ASSERT(spBuffer->GetSize() != 0); ASSERT(spBuffer == _spResponseBuffer); _spStunResponder->SendResponse(_socketOutput, _addrResponse, spBuffer); Cleanup: return; }
HRESULT CStunThreadMessageHandler::ProcessBindingRequest(CStunMessageReader& reader) { HRESULT hrTmp; bool fRequestHasPaddingAttribute = false; SocketRole socketOutput = _message.localSocket; StunChangeRequestAttribute changerequest = {}; bool fSendOtherAddress = false; bool fSendOriginAddress = false; SocketRole socketOther; CSocketAddress addrOrigin; CSocketAddress addrOther; CStunMessageBuilder builder; uint16_t paddingSize = 0; bool fLegacyFormat = false; // set to true if the client appears to be rfc3489 based instead of based on rfc 5789 _spResponseBuffer->SetSize(0); builder.GetStream().Attach(_spResponseBuffer, true); fLegacyFormat = reader.IsMessageLegacyFormat(); // check for an alternate response port // check for padding attribute (todo - figure out how to inject padding into the response) // check for a change request and validate we can do it. If so, set _socketOutput. If not, fill out _error and return. // determine if we have an "other" address to notify the caller about // did the request come with a padding request if (SUCCEEDED(reader.GetPaddingAttributeSize(&paddingSize))) { // todo - figure out how we're going to get the MTU size of the outgoing interface fRequestHasPaddingAttribute = true; } // as per 5780, section 6.1, If the Request contained a PADDING attribute... // "If the Request also contains the RESPONSE-PORT attribute the server MUST return an error response of type 400." if (_fRequestHasResponsePort && fRequestHasPaddingAttribute) { _error.errorcode = STUN_ERROR_BADREQUEST; return E_FAIL; } // handle change request logic and figure out what "other-address" attribute is going to be if (SUCCEEDED(reader.GetChangeRequest(&changerequest))) { if (changerequest.fChangeIP) { socketOutput = SocketRoleSwapIP(socketOutput); } if(changerequest.fChangePort) { socketOutput = SocketRoleSwapPort(socketOutput); } // IsValidSocketRole just validates the enum, not whether or not we can send on it ASSERT(IsValidSocketRole(socketOutput)); // now, make sure we have the ability to send from another socket if (_spStunResponder->HasAddress(socketOutput) == false) { // send back an error. We're being asked to respond using another address that we don't have a socket for _error.errorcode = STUN_ERROR_BADREQUEST; return E_FAIL; } } // If we're only working one socket, then that's ok, we just don't send back an "other address" unless we have all four sockets confgiured // now here's a problem. If we binded to "INADDR_ANY", all of the sockets will have "0.0.0.0" for an address (same for IPV6) // So we effectively can't send back "other address" if don't really know our own IP address // Fortunately, recvfromex and the ioctls on the socket allow address discovery a bit better fSendOtherAddress = (_spStunResponder->HasAddress(RolePP) && _spStunResponder->HasAddress(RolePA) && _spStunResponder->HasAddress(RoleAP) && _spStunResponder->HasAddress(RoleAA)); if (fSendOtherAddress) { socketOther = SocketRoleSwapIP(SocketRoleSwapPort(_message.localSocket)); hrTmp = _spStunResponder->GetSocketAddressForRole(socketOther, &addrOther); ASSERT(SUCCEEDED(hrTmp)); // so if our ip address is "0.0.0.0", disable this attribute fSendOtherAddress = (SUCCEEDED(hrTmp) && (addrOther.IsIPAddressZero()==false)); } // What's our address origin? VERIFY(SUCCEEDED(_spStunResponder->GetSocketAddressForRole(socketOutput, &addrOrigin))); if (addrOrigin.IsIPAddressZero()) { // Since we're sending back from the IP address we received on, we can just use the address the message came in on // Otherwise, we don't actually know it if (socketOutput == _message.localSocket) { addrOrigin = _message.localAddr; } } fSendOriginAddress = (false == addrOrigin.IsIPAddressZero()); // Success - we're all clear to build the response _socketOutput = socketOutput; _spResponseBuffer->SetSize(0); builder.GetStream().Attach(_spResponseBuffer, true); builder.AddHeader(StunMsgTypeBinding, StunMsgClassSuccessResponse); builder.AddTransactionId(_transid); builder.AddMappedAddress(_message.remoteAddr); if (fLegacyFormat == false) { builder.AddXorMappedAddress(_message.remoteAddr); } if (fSendOriginAddress) { builder.AddResponseOriginAddress(addrOrigin); } if (fSendOtherAddress) { builder.AddOtherAddress(addrOther, fLegacyFormat); // pass true to send back CHANGED-ADDRESS, otherwise, pass false to send back OTHER-ADDRESS } // finally - if we're supposed to have a message integrity attribute as a result of authorization, add it at the very end if (_integrity.fSendWithIntegrity) { if (_integrity.fUseLongTerm == false) { builder.AddMessageIntegrityShortTerm(_integrity.szPassword); } else { builder.AddMessageIntegrityLongTerm(_integrity.szUser, _integrity.szRealm, _integrity.szPassword); } } builder.FixLengthField(); return S_OK; }