// this test validates that IPV6 addresses work fine with CStunMessageBuilder and CStunMessageReader HRESULT CTestBuilder::Test2() { HRESULT hr = S_OK; CSocketAddress addr(0,0); CSocketAddress addrValidate(0,0); const char* ip6addr = "ABCDEFGHIJKLMNOP"; sockaddr_in6 addr6 = {}; CStunMessageReader reader; StunTransactionId transid; CStunMessageBuilder builder; CRefCountedBuffer spBuffer; addr6.sin6_family = AF_INET6; addr6.sin6_port = htons(9999); memcpy(addr6.sin6_addr.s6_addr, ip6addr, 16); addr = CSocketAddress(addr6); ChkA(builder.AddHeader(StunMsgTypeBinding, StunMsgClassRequest)); ChkA(builder.AddRandomTransactionId(&transid)); ChkA(builder.AddMappedAddress(addr)); ChkA(builder.AddXorMappedAddress(addr)); ChkA(builder.GetResult(&spBuffer)); ChkIfA(CStunMessageReader::BodyValidated != reader.AddBytes(spBuffer->GetData(), spBuffer->GetSize()), E_FAIL); ChkA(reader.GetXorMappedAddress(&addrValidate)); ChkIf(addrValidate.IsSameIP_and_Port(addr) == false, E_FAIL); Cleanup: return hr; }
HRESULT CTestMessageHandler::SendHelper(CStunMessageBuilder& builderRequest, CStunMessageReader* pReaderResponse, IStunAuth* pAuth) { CRefCountedBuffer spBufferRequest; CRefCountedBuffer spBufferResponse(new CBuffer(MAX_STUN_MESSAGE_SIZE)); StunMessageIn msgIn; StunMessageOut msgOut; CStunMessageReader reader; CSocketAddress addrDest; TransportAddressSet tas; HRESULT hr = S_OK; InitTransportAddressSet(tas, true, true, true, true); builderRequest.GetResult(&spBufferRequest); ChkIf(CStunMessageReader::BodyValidated != reader.AddBytes(spBufferRequest->GetData(), spBufferRequest->GetSize()), E_FAIL); msgIn.fConnectionOriented = false; msgIn.addrLocal = _addrServerPP; msgIn.pReader = &reader; msgIn.socketrole = RolePP; msgIn.addrRemote = _addrMapped; msgOut.spBufferOut = spBufferResponse; ChkA(CStunRequestHandler::ProcessRequest(msgIn, msgOut, &tas, pAuth)); ChkIf(CStunMessageReader::BodyValidated != pReaderResponse->AddBytes(spBufferResponse->GetData(), spBufferResponse->GetSize()), E_FAIL); Cleanup: return hr; }
// This test validates that the construction and parsing of the message integrity attribute in a stun message works as expected // The test also validates both short term and long term credential modes with or without the presence of a fingerprint attribute HRESULT CTestIntegrity::TestMessageIntegrity(bool fWithFingerprint, bool fLongCredentials) { HRESULT hr = S_OK; const char* pszUserName = "******"; const char* pszRealm = "stunrealm"; const char* pszPassword = "******"; CStunMessageBuilder builder; CStunMessageReader reader; uint8_t *pMsg = NULL; size_t sizeMsg = 0; CStunMessageReader::ReaderParseState state; CRefCountedBuffer spBuffer; builder.AddBindingRequestHeader(); builder.AddRandomTransactionId(NULL); builder.AddUserName(pszUserName); builder.AddRealm(pszRealm); if (fLongCredentials == false) { Chk(builder.AddMessageIntegrityShortTerm(pszPassword)); } else { Chk(builder.AddMessageIntegrityLongTerm(pszUserName, pszRealm, pszPassword)); } if (fWithFingerprint) { builder.AddFingerprintAttribute(); } Chk(builder.GetResult(&spBuffer)); pMsg = spBuffer->GetData(); sizeMsg = spBuffer->GetSize(); state = reader.AddBytes(pMsg, sizeMsg); ChkIfA(state != CStunMessageReader::BodyValidated, E_FAIL); ChkIfA(reader.HasMessageIntegrityAttribute()==false, E_FAIL); if (fLongCredentials == false) { ChkA(reader.ValidateMessageIntegrityShort(pszPassword)); } else { ChkA(reader.ValidateMessageIntegrityLong(pszUserName, pszRealm, pszPassword)); } Cleanup: return hr; }
// Test1 - just do a basic binding request HRESULT CTestMessageHandler::Test1() { HRESULT hr = S_OK; CStunMessageBuilder builder; CRefCountedBuffer spBuffer, spBufferOut(new CBuffer(MAX_STUN_MESSAGE_SIZE)); CStunMessageReader reader; StunMessageIn msgIn; StunMessageOut msgOut; TransportAddressSet tas = {}; InitTransportAddressSet(tas, true, true, true, true); ChkA(InitBindingRequest(builder)); Chk(builder.GetResult(&spBuffer)); ChkIfA(CStunMessageReader::BodyValidated != reader.AddBytes(spBuffer->GetData(), spBuffer->GetSize()), E_FAIL); // a message send to the PP socket on the server from the msgIn.socketrole = RolePP; msgIn.addrRemote = _addrMapped; msgIn.pReader = &reader; msgIn.addrLocal = _addrServerPP; msgIn.fConnectionOriented = false; spBuffer.reset(); msgOut.spBufferOut = spBufferOut; msgOut.socketrole = RoleAA; // deliberately wrong - so we can validate if it got changed to RolePP ChkA(CStunRequestHandler::ProcessRequest(msgIn, msgOut, &tas, NULL)); reader.Reset(); ChkIfA(CStunMessageReader::BodyValidated != reader.AddBytes(spBufferOut->GetData(), spBufferOut->GetSize()), E_FAIL); // validate that the message returned is a success response for a binding request ChkIfA(reader.GetMessageClass() != StunMsgClassSuccessResponse, E_FAIL); ChkIfA(reader.GetMessageType() != (uint16_t)StunMsgTypeBinding, E_FAIL); // Validate that the message came from the server port we expected // and that it's the same address the server set for the origin address ChkIfA(msgOut.socketrole != RolePP, E_FAIL); ChkA(ValidateResponseOriginAddress(reader, _addrServerPP)); ChkIfA(msgOut.addrDest.IsSameIP_and_Port(_addrMapped)==false, E_FAIL); // validate that the mapping was done correctly ChkA(ValidateMappedAddress(reader, _addrMapped, false)); ChkA(ValidateOtherAddress(reader, _addrServerAA)); 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; }
// The goal of this test is to just validate that we can create a message from CStunMessageBuilder and have it's output parsed correctly by CStunMessageReader // Also helps validate CSocketAddress HRESULT CTestBuilder::Test1() { HRESULT hr = S_OK; CStunMessageBuilder builder; CStunMessageReader reader; StunAttribute attrib; CRefCountedBuffer spBuffer; CRefCountedBuffer spBufferReader; CSocketAddress addrValidate(0,0); StunTransactionId transid = {}; uint32_t ipvalidate = 0; CSocketAddress addr(0x7f000001, 9999); CSocketAddress addrOrigin(0xAABBCCDD, 8888); CSocketAddress addrOther(0x11223344, 7777); ChkA(builder.AddBindingRequestHeader()); ChkA(builder.AddRandomTransactionId(&transid)); ChkA(builder.AddStringAttribute(STUN_ATTRIBUTE_SOFTWARE, "FOOBAR")); ChkA(builder.AddMappedAddress(addr)); ChkA(builder.AddXorMappedAddress(addr)); ChkA(builder.AddOtherAddress(addrOther)); ChkA(builder.AddResponseOriginAddress(addrOrigin)); ChkA(builder.AddFingerprintAttribute()); ChkA(builder.GetResult(&spBuffer)); ChkIfA(CStunMessageReader::BodyValidated != reader.AddBytes(spBuffer->GetData(), spBuffer->GetSize()), E_FAIL); ChkIfA(reader.HasFingerprintAttribute() == false, E_FAIL); ChkIfA(reader.IsFingerprintAttributeValid() == false, E_FAIL); ChkIfA(reader.GetMessageClass() != StunMsgClassRequest, E_FAIL); ChkIfA(reader.GetMessageType() != StunMsgTypeBinding, E_FAIL); ChkA(reader.GetBuffer(&spBufferReader)); ChkA(reader.GetAttributeByType(STUN_ATTRIBUTE_SOFTWARE, &attrib)); ChkIfA(attrib.attributeType != STUN_ATTRIBUTE_SOFTWARE, E_FAIL); ChkIfA(0 != ::strncmp("FOOBAR", (const char*)(spBufferReader->GetData() + attrib.offset), attrib.size), E_FAIL); ChkA(reader.GetXorMappedAddress(&addrValidate)); ChkIf(addrValidate.IsSameIP_and_Port(addr) == false, E_FAIL); ChkIfA(addrValidate.GetIPLength() != 4, E_FAIL); addrValidate = CSocketAddress(0,0); ChkA(reader.GetMappedAddress(&addrValidate)); ChkIfA(addrValidate.GetPort() != 9999, E_FAIL); ChkIfA(addrValidate.GetIPLength() != 4, E_FAIL); ChkIfA(4 != addrValidate.GetIP(&ipvalidate, 4), E_FAIL); ChkIfA(ipvalidate != 0x7f000001, E_FAIL); addrValidate = CSocketAddress(0,0); ipvalidate = 0; reader.GetOtherAddress(&addrValidate); ChkIfA(addrValidate.GetPort() != 7777, E_FAIL); ChkIfA(addrValidate.GetIPLength() != 4, E_FAIL); ChkIfA(4 != addrValidate.GetIP(&ipvalidate, 4), E_FAIL); ChkIf(ipvalidate != 0x11223344, E_FAIL); Cleanup: return hr; }
// send a binding request to a duplex server instructing it to send back on it's alternate port and alternate IP to an alternate client port HRESULT CTestMessageHandler::Test2() { HRESULT hr=S_OK; CStunMessageBuilder builder; CSocketAddress clientaddr(0x12345678, 9876); CSocketAddress recvaddr; uint16_t responsePort = 2222; CRefCountedBuffer spBuffer; CStunThreadMessageHandler handler; CStunMessageReader reader; CStunMessageReader::ReaderParseState state; ::StunChangeRequestAttribute changereq; StunMessageEnvelope message; _spTransport->Reset(); _spTransport->AddPP(CSocketAddress(0xaaaaaaaa, 1234)); _spTransport->AddPA(CSocketAddress(0xaaaaaaaa, 1235)); _spTransport->AddAP(CSocketAddress(0xbbbbbbbb, 1234)); _spTransport->AddAA(CSocketAddress(0xbbbbbbbb, 1235)); InitBindingRequest(builder); builder.AddResponsePort(responsePort); changereq.fChangeIP = true; changereq.fChangePort = true; builder.AddChangeRequest(changereq); builder.AddResponsePort(responsePort); builder.GetResult(&spBuffer); message.localSocket = RolePP; message.remoteAddr = clientaddr; message.spBuffer = spBuffer; _spTransport->GetSocketAddressForRole(RolePP, &(message.localAddr)); handler.SetResponder(_spTransport); handler.ProcessRequest(message); spBuffer->Reset(); _spTransport->GetOutputStream().GetBuffer(&spBuffer); // parse the response 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)); ChkA(ValidateOriginAddress(reader, RoleAA)); // did it get sent back to where we thought it was recvaddr = clientaddr; recvaddr.SetPort(responsePort); ChkA(ValidateResponseAddress(recvaddr)); Cleanup: return hr; }
// Test2 - send a binding request to a duplex server instructing it to send back on it's alternate port and alternate IP to an alternate client port HRESULT CTestMessageHandler::Test2() { HRESULT hr = S_OK; CStunMessageBuilder builder; CRefCountedBuffer spBuffer, spBufferOut(new CBuffer(MAX_STUN_MESSAGE_SIZE)); CStunMessageReader reader; StunMessageIn msgIn; StunMessageOut msgOut; TransportAddressSet tas = {}; uint16_t responsePort = 2222; StunChangeRequestAttribute changereq; CStunMessageReader::ReaderParseState state; CSocketAddress addrDestExpected; InitTransportAddressSet(tas, true, true, true, true); InitBindingRequest(builder); builder.AddResponsePort(responsePort); changereq.fChangeIP = true; changereq.fChangePort = true; builder.AddChangeRequest(changereq); builder.AddResponsePort(responsePort); builder.GetResult(&spBuffer); ChkIfA(CStunMessageReader::BodyValidated != reader.AddBytes(spBuffer->GetData(), spBuffer->GetSize()), E_FAIL); msgIn.fConnectionOriented = false; msgIn.addrLocal = _addrServerPP; msgIn.pReader = &reader; msgIn.socketrole = RolePP; msgIn.addrRemote = _addrMapped; msgOut.socketrole = RolePP; // deliberate initialized wrong msgOut.spBufferOut = spBufferOut; ChkA(CStunRequestHandler::ProcessRequest(msgIn, msgOut, &tas, NULL)); // parse the response reader.Reset(); state = reader.AddBytes(spBufferOut->GetData(), spBufferOut->GetSize()); ChkIfA(state != CStunMessageReader::BodyValidated, E_FAIL); // validate that the message was sent back from the AA ChkIfA(msgOut.socketrole != RoleAA, E_FAIL); // validate that the server though it was sending back from the AA ChkA(ValidateResponseOriginAddress(reader, _addrServerAA)); // validate that the message was sent to the response port requested addrDestExpected = _addrMapped; addrDestExpected.SetPort(responsePort); ChkIfA(addrDestExpected.IsSameIP_and_Port(msgOut.addrDest)==false, E_FAIL); // validate that the binding response came back ChkA(ValidateMappedAddress(reader, _addrMapped, false)); // the "other" address is still AA (See RFC 3489 - section 8.1) ChkA(ValidateOtherAddress(reader, _addrServerAA)); Cleanup: return hr; }