HRESULT CFilteringTest::GetMessage(CRefCountedBuffer& spMsg, CSocketAddress* pAddrDest) { CStunMessageBuilder builder; StunChangeRequestAttribute change; builder.GetStream().Attach(spMsg, true); StartBindingRequest(builder); *pAddrDest = _pConfig->addrServer; if (_fIsTest3 == false) { change.fChangeIP = true; change.fChangePort = true; builder.AddChangeRequest(change); } else { change.fChangeIP = false; change.fChangePort = true; builder.AddChangeRequest(change); } builder.FixLengthField(); return S_OK; }
HRESULT CBehaviorTest::GetMessage(CRefCountedBuffer& spMsg, CSocketAddress* pAddrDest) { HRESULT hr = S_OK; ASSERT(spMsg->GetAllocatedSize() > 0); ASSERT(pAddrDest); StunChangeRequestAttribute attribChangeRequest = {}; CStunMessageBuilder builder; builder.GetStream().Attach(spMsg, true); StartBindingRequest(builder); builder.AddChangeRequest(attribChangeRequest); // adding a blank CHANGE-REQUEST, because a JSTUN server will not respond if the request doesn't have one builder.FixLengthField(); if (_fIsTest3 == false) { *pAddrDest = _pResults->addrAP; } else { *pAddrDest = _pResults->addrAA; } return hr; }
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; }
// Test1 - just do a basic binding request HRESULT CTestMessageHandler::Test1() { HRESULT hr=S_OK; CStunMessageBuilder builder; CSocketAddress clientaddr(0x12345678, 9876); CRefCountedBuffer spBuffer; CStunThreadMessageHandler handler; CStunMessageReader reader; CStunMessageReader::ReaderParseState state; StunMessageEnvelope message; _spTransport->Reset(); _spTransport->AddPP(CSocketAddress(0xaaaaaaaa, 1234)); InitBindingRequest(builder); builder.GetStream().GetBuffer(&spBuffer); handler.SetResponder(_spTransport); message.localSocket = RolePP; message.remoteAddr = clientaddr; message.spBuffer = spBuffer; _spTransport->GetSocketAddressForRole(message.localSocket, &(message.localAddr)); handler.ProcessRequest(message); spBuffer.reset(); _spTransport->GetOutputStream().GetBuffer(&spBuffer); state = reader.AddBytes(spBuffer->GetData(), spBuffer->GetSize()); ChkIfA(state != CStunMessageReader::BodyValidated, E_FAIL); // validate that the binding response matches our expectations ChkA(ValidateMappedAddress(reader, clientaddr)); // validate that it came from the server port we expected ChkA(ValidateOriginAddress(reader, RolePP)); // did we get back the binding request we expected ChkA(ValidateResponseAddress(clientaddr)); Cleanup: return hr; }
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 CBasicBindingTest::GetMessage(CRefCountedBuffer& spMsg, CSocketAddress* pAddrDest) { HRESULT hr = S_OK; ASSERT(spMsg->GetAllocatedSize() > 0); ASSERT(pAddrDest); ASSERT(_fInit); CStunMessageBuilder builder; builder.GetStream().Attach(spMsg, true); Chk(StartBindingRequest(builder)); builder.FixLengthField(); *pAddrDest = _pConfig->addrServer; Cleanup: return hr; }
HRESULT CBehaviorTest::GetMessage(CRefCountedBuffer& spMsg, CSocketAddress* pAddrDest) { HRESULT hr = S_OK; ASSERT(spMsg->GetAllocatedSize() > 0); ASSERT(pAddrDest); CStunMessageBuilder builder; builder.GetStream().Attach(spMsg, true); StartBindingRequest(builder); builder.FixLengthField(); if (_fIsTest3 == false) { *pAddrDest = _pResults->addrAP; } else { *pAddrDest = _pResults->addrAA; } return hr; }
HRESULT CBasicBindingTest::GetMessage(CRefCountedBuffer& spMsg, CSocketAddress* pAddrDest) { StunChangeRequestAttribute attribChangeRequest = {}; HRESULT hr = S_OK; ASSERT(spMsg->GetAllocatedSize() > 0); ASSERT(pAddrDest); ASSERT(_fInit); CStunMessageBuilder builder; builder.GetStream().Attach(spMsg, true); Chk(StartBindingRequest(builder)); builder.AddChangeRequest(attribChangeRequest); // adding a blank CHANGE-REQUEST, because a JSTUN server will not respond if the request doesn't have one builder.FixLengthField(); *pAddrDest = _pConfig->addrServer; Cleanup: return hr; }
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; }