HRESULT CTCPStunThread::CreateListenSockets() { HRESULT hr = S_OK; int ret; for (int r = (int)RolePP; r <= (int)RoleAA; r++) { if (_tsaListen.set[r].fValid) { ChkA(_socketListenArray[r].TCPInit(_tsaListen.set[r].addr, (SocketRole)r, true)); _socketTable[r] = _socketListenArray[r].GetSocketHandle(); ChkA(_socketListenArray[r].SetNonBlocking(true)); ret = listen(_socketTable[r], 128); // 128 - large backlog. ChkIfA(ret == -1, ERRNOHR); _countSocks++; } else { _socketTable[r] = -1; } } _fListenSocketsOnEpoll = false; Cleanup: return hr; }
HRESULT CTCPStunThread::SetListenSocketsOnEpoll(bool fEnable) { HRESULT hr = S_OK; if (fEnable != _fListenSocketsOnEpoll) { for (int role = 0; role < 4; role++) { int sock = _socketTable[role]; if (sock == -1) { continue; } if (fEnable) { ChkA(_spPolling->Add(sock, EPOLL_LISTEN_SOCKET_EVENT_SET)); } else { ChkA(_spPolling->Remove(sock)); } } _fListenSocketsOnEpoll = fEnable; } Cleanup: return hr; }
HRESULT CTestReader::Test1() { HRESULT hr = S_OK; StunAttribute attrib; const char* pszExpectedSoftwareAttribute = "STUN test client"; const char* pszExpectedUserName = "******"; CRefCountedBuffer spBuffer; char szStringValue[100]; const unsigned char *req = c_requestbytes; size_t requestsize = sizeof(c_requestbytes)-1; // -1 to get rid of the trailing null CStunMessageReader reader; CStunMessageReader::ReaderParseState state; // reader is expecting at least enough bytes to fill the header ChkIfA(reader.AddBytes(NULL, 0) != CStunMessageReader::HeaderNotRead, E_FAIL); ChkIfA(reader.HowManyBytesNeeded() != STUN_HEADER_SIZE, E_FAIL); state = reader.AddBytes(req, requestsize); ChkIfA(state != CStunMessageReader::BodyValidated, E_FAIL); ChkIfA(reader.HowManyBytesNeeded() != 0, E_FAIL); ChkA(reader.GetBuffer(&spBuffer)); ChkIfA(reader.GetMessageClass() != StunMsgClassRequest, E_FAIL); ChkIfA(reader.GetMessageType() != StunMsgTypeBinding, E_FAIL); ChkA(reader.GetAttributeByType(STUN_ATTRIBUTE_SOFTWARE, &attrib)); ChkIfA(attrib.attributeType != STUN_ATTRIBUTE_SOFTWARE, E_FAIL); ChkIfA(0 != ::strncmp(pszExpectedSoftwareAttribute, (const char*)(spBuffer->GetData() + attrib.offset), attrib.size), E_FAIL); ChkA(reader.GetAttributeByType(STUN_ATTRIBUTE_USERNAME, &attrib)); ChkIfA(attrib.attributeType != STUN_ATTRIBUTE_USERNAME, E_FAIL); ChkIfA(0 != ::strncmp(pszExpectedUserName, (const char*)(spBuffer->GetData() + attrib.offset), attrib.size), E_FAIL); ChkA(reader.GetStringAttributeByType(STUN_ATTRIBUTE_SOFTWARE, szStringValue, ARRAYSIZE(szStringValue))); ChkIfA(0 != ::strcmp(pszExpectedSoftwareAttribute, szStringValue), E_FAIL); ChkIfA(reader.HasFingerprintAttribute() == false, E_FAIL); ChkIfA(reader.IsFingerprintAttributeValid() == false, E_FAIL); ChkIfA(reader.HasMessageIntegrityAttribute() == false, E_FAIL); ChkA(reader.ValidateMessageIntegrityShort(c_password)); 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; }
HRESULT CTestClientLogic::Run() { HRESULT hr = S_OK; ChkA(Test1()); printf("Testing detection for DirectMapping\n"); ChkA(TestBehaviorAndFiltering(true, DirectMapping, false, EndpointIndependentFiltering)); printf("Testing detection for EndpointIndependent mapping\n"); ChkA(TestBehaviorAndFiltering(true, EndpointIndependentMapping, false, EndpointIndependentFiltering)); printf("Testing detection for AddressDependentMapping\n"); ChkA(TestBehaviorAndFiltering(true, AddressDependentMapping, false, EndpointIndependentFiltering)); printf("Testing detection for AddressAndPortDependentMapping\n"); ChkA(TestBehaviorAndFiltering(true, AddressAndPortDependentMapping, false, EndpointIndependentFiltering)); printf("Testing detection for EndpointIndependentFiltering\n"); ChkA(TestBehaviorAndFiltering(true, EndpointIndependentMapping, true, EndpointIndependentFiltering)); printf("Testing detection for AddressDependentFiltering\n"); ChkA(TestBehaviorAndFiltering(true, EndpointIndependentMapping, true, AddressDependentFiltering)); printf("Testing detection for AddressAndPortDependentFiltering\n"); ChkA(TestBehaviorAndFiltering(true, EndpointIndependentMapping, true, AddressAndPortDependentFiltering)); Cleanup: 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; }
HRESULT CTestIntegrity::Run() { HRESULT hr = S_OK; Chk(TestMessageIntegrity(false, false)); ChkA(TestMessageIntegrity(true, false)); Chk(TestMessageIntegrity(false, true)); ChkA(TestMessageIntegrity(true, true)); Cleanup: return hr; }
// test long-credential authentication HRESULT CTestMessageHandler::Test4() { HRESULT hr=S_OK; CStunMessageBuilder builder1, builder2; CStunMessageReader readerResponse; CSocketAddress addrMapped; uint16_t errorcode = 0; char szNonce[MAX_STUN_AUTH_STRING_SIZE+1]; char szRealm[MAX_STUN_AUTH_STRING_SIZE+1]; // ----------------------------------------------------------------------- // simulate a user making a request with no message integrity attribute (or username, or realm) InitBindingRequest(builder1); builder1.FixLengthField(); ChkA(SendHelper(builder1, &readerResponse, _spAuthLong)); Chk(readerResponse.GetErrorCode(&errorcode)); ChkIfA(readerResponse.GetMessageClass() != ::StunMsgClassFailureResponse, E_UNEXPECTED); ChkIf(errorcode != ::STUN_ERROR_UNAUTHORIZED, E_UNEXPECTED); readerResponse.GetStringAttributeByType(STUN_ATTRIBUTE_REALM, szRealm, ARRAYSIZE(szRealm)); readerResponse.GetStringAttributeByType(STUN_ATTRIBUTE_NONCE, szNonce, ARRAYSIZE(szNonce)); // -------------------------------------------------------------------------------- // now simulate the follow-up request readerResponse.Reset(); InitBindingRequest(builder2); builder2.AddNonce(szNonce); builder2.AddRealm(szRealm); builder2.AddUserName("AuthorizedUser"); builder2.AddMessageIntegrityLongTerm("AuthorizedUser", szRealm, "password"); builder2.FixLengthField(); ChkA(SendHelper(builder2, &readerResponse, _spAuthLong)); ChkIfA(readerResponse.GetMessageClass() != ::StunMsgClassSuccessResponse, E_UNEXPECTED); // should have a mapped address ChkA(readerResponse.GetMappedAddress(&addrMapped)); // and the message integrity field should be valid ChkA(readerResponse.ValidateMessageIntegrityLong("AuthorizedUser", szRealm, "password")); 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; }
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; }
HRESULT CTestMessageHandler::ValidateMappedAddress(CStunMessageReader& reader, const CSocketAddress& addrExpected, bool fLegacyOnly) { HRESULT hr = S_OK; CSocketAddress addrMapped; CSocketAddress addrXorMapped; HRESULT hrResult; hrResult = reader.GetXorMappedAddress(&addrXorMapped); if (SUCCEEDED(hrResult)) { ChkIfA(false == addrExpected.IsSameIP_and_Port(addrXorMapped), E_FAIL); ChkIfA(fLegacyOnly, E_FAIL); // legacy responses should not include XOR mapped } else { ChkIfA(fLegacyOnly==false, E_FAIL); // non-legacy responses should include XOR Mapped address } ChkA(reader.GetMappedAddress(&addrMapped)); ChkIfA(false == addrExpected.IsSameIP_and_Port(addrMapped), E_FAIL); Cleanup: return hr; }
HRESULT CTestPolling::TestInit(size_t sizePolling, size_t sizePipeArray) { HRESULT hr = S_OK; TestUnInit(); ChkA(CreatePollingInstance(_polltype, sizePolling, _spPolling.GetPointerPointer())); for (size_t index = 0; index < sizePipeArray; index++) { ChkA(CreateAndAddPipe()); } Cleanup: return hr; }
HRESULT CTCPServer::Initialize(const CStunServerConfig& config) { HRESULT hr = S_OK; TransportAddressSet tsaListen; TransportAddressSet tsaHandler; ChkIfA(_threads[0] != NULL, E_UNEXPECTED); // we can't already be initialized, right? // optional code: create an authentication provider and initialize it here (if you want authentication) // set the _spAuth member to reference it // Chk(CYourAuthProvider::CreateInstanceNoInit(&_spAuth)); // tsaHandler is sort of a hack for TCP. It's really just a glorified indication to the the // CStunRequestHandler code to figure out if can offer a CHANGED-ADDRESS attribute. tsaHandler.set[RolePP].fValid = config.fHasPP; tsaHandler.set[RolePP].addr = config.addrPP; tsaHandler.set[RolePA].fValid = config.fHasPA; tsaHandler.set[RolePA].addr = config.addrPA; tsaHandler.set[RoleAP].fValid = config.fHasAP; tsaHandler.set[RoleAP].addr = config.addrAP; tsaHandler.set[RoleAA].fValid = config.fHasAA; tsaHandler.set[RoleAA].addr = config.addrAA; if (config.fMultiThreadedMode == false) { tsaListen = tsaHandler; _threads[0] = new CTCPStunThread(); ChkA(_threads[0]->Init(tsaListen, tsaHandler, _spAuth, config.nMaxConnections)); } else { for (int threadindex = 0; threadindex < 4; threadindex++) { memset(&tsaListen, '\0', sizeof(tsaListen)); if (tsaHandler.set[threadindex].fValid) { tsaListen.set[threadindex] = tsaHandler.set[threadindex]; _threads[threadindex] = new CTCPStunThread(); Chk(_threads[threadindex]->Init(tsaListen, tsaHandler, _spAuth, config.nMaxConnections)); } } } Cleanup: if (FAILED(hr)) { Shutdown(); } return hr; }
HRESULT CTestPolling::Run() { HRESULT hr = S_OK; #ifdef HAS_EPOLL _polltype = IPOLLING_TYPE_EPOLL; ChkA(Test1()); ChkA(Test2()); #endif _polltype = IPOLLING_TYPE_POLL; ChkA(Test1()); ChkA(Test2()); ChkA(Test3()); Cleanup: return hr; }
HRESULT CTestClientLogic::Test1() { HRESULT hr = S_OK; HRESULT hrTmp = 0; CStunClientLogic clientlogic; ::StunClientLogicConfig config; CRefCountedBuffer spMsgOut(new CBuffer(MAX_STUN_MESSAGE_SIZE)); CRefCountedBuffer spMsgIn(new CBuffer(MAX_STUN_MESSAGE_SIZE)); StunClientResults results; StunTransactionId transid; CSocketAddress addrDest; CSocketAddress addrServerPP = CSocketAddress(0xaaaaaaaa, 1001); CSocketAddress addrLocal = CSocketAddress(0xdddddddd, 4444); CSocketAddress addrMapped = CSocketAddress(0xeeeeeeee, 5555); config.addrServer = addrServerPP; config.fBehaviorTest = false; config.fFilteringTest = false; config.timeoutSeconds = 10; config.uMaxAttempts = 2; config.fTimeoutIsInstant = false; ChkA(clientlogic.Initialize(config)); ChkA(clientlogic.GetNextMessage(spMsgOut, &addrDest, 0)); // we expect to get back a message for the serverPP ChkIfA(addrDest.IsSameIP_and_Port(addrServerPP)==false, E_UNEXPECTED); // check to make sure out timeout logic appears to work hrTmp = clientlogic.GetNextMessage(spMsgOut, &addrDest, 1); ChkIfA(hrTmp != E_STUNCLIENT_STILL_WAITING, E_UNEXPECTED); // now we should get a dupe of what we had before ChkA(clientlogic.GetNextMessage(spMsgOut, &addrDest, 11000)); // the message should be a binding request ChkA(ValidateBindingRequest(spMsgOut, &transid)); // now let's generate a response ChkA(GenerateBindingResponseMessage(addrMapped, transid, spMsgIn)); ChkA(clientlogic.ProcessResponse(spMsgIn, addrServerPP, addrLocal)); // results should be ready hrTmp = clientlogic.GetNextMessage(spMsgOut, &addrDest, 12000); ChkIfA(hrTmp != E_STUNCLIENT_RESULTS_READY, E_UNEXPECTED); ChkA(clientlogic.GetResults(&results)); // results should have a successful binding result ChkIfA(results.fBindingTestSuccess==false, E_UNEXPECTED); ChkIfA(results.fIsDirect, E_UNEXPECTED); ChkIfA(results.addrMapped.IsSameIP_and_Port(addrMapped)==false, E_UNEXPECTED); ChkIfA(results.addrLocal.IsSameIP_and_Port(addrLocal)==false, E_UNEXPECTED); Cleanup: return hr; }
HRESULT CStunMessageBuilder::AddHeader(StunMessageType msgType, StunMessageClass msgClass) { uint16_t msgTypeField=0; HRESULT hr = S_OK; ChkA(_stream.SetSizeHint(200)); // merge the _msgType and _msgClass, and the leading zero bits into a 16-bit field msgTypeField = (msgType & 0x0f80) << 2; msgTypeField |= (msgType & 0x0070) << 1; msgTypeField |= (msgType & 0x000f); msgTypeField |= (msgClass & 0x02) << 7; msgTypeField |= (msgClass & 0x01) << 4; ChkA(_stream.WriteUint16(htons(msgTypeField))); // htons for big-endian ChkA(_stream.WriteUint16(0)); // place holder for length Cleanup: return hr; }
HRESULT CTestMessageHandler::ValidateOtherAddress(CStunMessageReader& reader, const CSocketAddress& addrExpected) { HRESULT hr = S_OK; CSocketAddress addr; ChkA(reader.GetOtherAddress(&addr)); ChkIfA(false == addrExpected.IsSameIP_and_Port(addr), E_FAIL); Cleanup: return hr; }
HRESULT CTestReader::TestFixedReadSizes(size_t chunksize) { HRESULT hr = S_OK; CStunMessageReader reader; CStunMessageReader::ReaderParseState prevState, state; size_t bytesread = 0; bool fRandomChunkSizing = (chunksize==0); prevState = CStunMessageReader::HeaderNotRead; state = prevState; size_t msgSize = sizeof(c_requestbytes)-1; // c_requestbytes is a string, hence the -1 while (bytesread < msgSize) { size_t remaining, toread; if (fRandomChunkSizing) { chunksize = (rand() % 17) + 1; } remaining = msgSize - bytesread; toread = (remaining > chunksize) ? chunksize : remaining; state = reader.AddBytes(&c_requestbytes[bytesread], toread); bytesread += toread; ChkIfA(state == CStunMessageReader::ParseError, E_UNEXPECTED); if ((state == CStunMessageReader::HeaderValidated) && (prevState != CStunMessageReader::HeaderValidated)) { ChkIfA(bytesread < STUN_HEADER_SIZE, E_UNEXPECTED); } if ((state == CStunMessageReader::BodyValidated) && (prevState != CStunMessageReader::BodyValidated)) { ChkIfA(prevState != CStunMessageReader::HeaderValidated, E_UNEXPECTED); ChkIfA(bytesread != msgSize, E_UNEXPECTED); } prevState = state; } ChkIfA(reader.GetState() != CStunMessageReader::BodyValidated, E_UNEXPECTED); // just validate the integrity and fingerprint, that should cover all the attributes ChkA(reader.ValidateMessageIntegrityShort(c_password)); ChkIfA(reader.IsFingerprintAttributeValid() == false, E_FAIL); Cleanup: return hr; }
// 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; }
// test simple authentication HRESULT CTestMessageHandler::Test3() { CStunMessageBuilder builder1, builder2, builder3; CStunMessageReader readerResponse; uint16_t errorcode = 0; HRESULT hr = S_OK; // ----------------------------------------------------------------------- // simulate an authorized user making a request with a valid password ChkA(InitBindingRequest(builder1)); builder1.AddStringAttribute(STUN_ATTRIBUTE_USERNAME, "AuthorizedUser"); builder1.AddMessageIntegrityShortTerm("password"); builder1.FixLengthField(); ChkA(SendHelper(builder1, &readerResponse, _spAuthShort)); ChkA(readerResponse.ValidateMessageIntegrityShort("password")); // ----------------------------------------------------------------------- // simulate a user with a bad password readerResponse.Reset(); InitBindingRequest(builder2); builder2.AddStringAttribute(STUN_ATTRIBUTE_USERNAME, "WrongUser"); builder2.AddMessageIntegrityShortTerm("wrongpassword"); builder2.FixLengthField(); ChkA(SendHelper(builder2, &readerResponse, _spAuthShort)) errorcode = 0; ChkA(readerResponse.GetErrorCode(&errorcode)); ChkIfA(errorcode != ::STUN_ERROR_UNAUTHORIZED, E_FAIL); // ----------------------------------------------------------------------- // simulate a client sending no credentials - we expect it to fire back with a 400/bad-request readerResponse.Reset(); ChkA(InitBindingRequest(builder3)); ChkA(SendHelper(builder3, &readerResponse, _spAuthShort)); errorcode = 0; ChkA(readerResponse.GetErrorCode(&errorcode)); ChkIfA(errorcode != ::STUN_ERROR_BADREQUEST, E_FAIL); Cleanup: return hr; }
// simplest of all tests. Just set a file descriptor and see that it's available // repeat many times HRESULT CTestPolling::Test1() { HRESULT hr = S_OK; HRESULT hrResult; size_t size; PollEvent event; int fd; int count = 0; srand(100); ChkA(TestInit(10, 10)); size = _pipes.size(); hrResult = _spPolling->WaitForNextEvent(&event, 0); ChkIfA(hrResult != S_FALSE, E_UNEXPECTED); // one event at a time model for (int index = 0; index < 100; index++) { size_t item = rand() % size; ChkA(WritePipe(&_pipes[item])); ConsumeEvent(&fd, &count); ChkIfA(fd != _pipes[item].readpipe, E_UNEXPECTED); ChkIfA(count != 1, E_UNEXPECTED); } hrResult = _spPolling->WaitForNextEvent(&event, 0); ChkIfA(hrResult != S_FALSE, E_UNEXPECTED); Cleanup: return hr; }
HRESULT CTestMessageHandler::ValidateOriginAddress(CStunMessageReader& reader, SocketRole socketExpected) { HRESULT hr = S_OK; StunAttribute attrib; CSocketAddress addrExpected, mappedaddr; CRefCountedBuffer spBuffer; Chk(reader.GetStream().GetBuffer(&spBuffer)); Chk(_spTransport->GetSocketAddressForRole(socketExpected, &addrExpected)); ChkA(reader.GetAttributeByType(STUN_ATTRIBUTE_RESPONSE_ORIGIN, &attrib)); ChkA(GetMappedAddress(spBuffer->GetData()+attrib.offset, attrib.size, &mappedaddr)); ChkIfA(false == addrExpected.IsSameIP_and_Port(mappedaddr), E_FAIL); ChkIfA(socketExpected != _spTransport->m_outputRole, E_FAIL); Cleanup: return hr; }
HRESULT CTCPServer::Start() { HRESULT hr = S_OK; for (int role = (int)RolePP; role <= (int)RoleAA; role++) { if (_threads[role]) { ChkA(_threads[role]->Start()); } } Cleanup: return hr; }
HRESULT CStunMessageBuilder::FixLengthField() { size_t size = _stream.GetSize(); size_t currentPos = _stream.GetPos(); HRESULT hr = S_OK; ChkIfA(size < STUN_HEADER_SIZE, E_UNEXPECTED); if (size < STUN_HEADER_SIZE) { size = 0; } else { size = size - STUN_HEADER_SIZE; } ChkA(_stream.SeekDirect(2)); // 2 bytes into the stream is the length ChkA(_stream.WriteUint16(ntohs(size))); ChkA(_stream.SeekDirect(currentPos)); Cleanup: return hr; }
HRESULT CTestPolling::CreateAndAddPipe() { HRESULT hr = S_OK; PipePair pp = {}; int ret = -1; int fds[2]; ret = ::pipe(fds); ChkIfA(ret == -1, ERRNOHR); pp.readpipe = fds[0]; pp.writepipe = fds[1]; pp.fDataPending = false; ChkA(SetNonBlocking(pp.readpipe)); ChkA(SetNonBlocking(pp.writepipe)); _pipes.push_back(pp); ChkA(_spPolling->Add(fds[0], IPOLLING_READ)); Cleanup: return hr; }
HRESULT CTestPolling::ConsumeEvent(int* pFD, int* pCount) { HRESULT hr = S_OK; HRESULT hrResult = S_OK; PollEvent event; char ch; int result; int count = 0; int fd = -1; int pipesindex = -1; hrResult = _spPolling->WaitForNextEvent(&event, 0); ChkA(hrResult); ChkIfA(hrResult == S_FALSE, S_FALSE); fd = event.fd; while (true) { result = ::read(fd, &ch, 1); if (result <= 0) { break; } count++; } pipesindex = FindPipePairIndex(fd); ChkIfA(pipesindex == -1, E_UNEXPECTED); ChkIfA(count == 0, E_UNEXPECTED); ChkIfA(_pipes[pipesindex].fDataPending == false, E_UNEXPECTED); _pipes[pipesindex].fDataPending = false; Cleanup: if (pFD) { *pFD = fd; } if (pCount) { *pCount = count; } return hr; }
HRESULT CStunMessageBuilder::AddMessageIntegrityImpl(uint8_t* key, size_t keysize) { HRESULT hr = S_OK; const size_t c_hmacsize = 20; uint8_t hmacvaluedummy[c_hmacsize] = {}; // zero-init unsigned int resultlength = c_hmacsize; uint8_t* pDstBuf = NULL; CRefCountedBuffer spBuffer; void* pData = NULL; size_t length = 0; unsigned char* pHashResult = NULL; UNREFERENCED_VARIABLE(pHashResult); ChkIfA(key==NULL || keysize <= 0, E_INVALIDARG); // add in a "zero-init" HMAC value. This adds 24 bytes to the length Chk(AddAttribute(STUN_ATTRIBUTE_MESSAGEINTEGRITY, hmacvaluedummy, ARRAYSIZE(hmacvaluedummy))); Chk(FixLengthField()); // now do a SHA1 on everything but the last 24 bytes (4 bytes of the attribute header and 20 bytes for the dummy content) ChkA(_stream.GetBuffer(&spBuffer)); pData = spBuffer->GetData(); length = spBuffer->GetSize(); ASSERT(length > 24); length = length-24; // now do a little pointer math so that HMAC can write exactly to where the hash bytes will appear pDstBuf = ((uint8_t*)pData) + length + 4; #ifndef __APPLE__ pHashResult = HMAC(EVP_sha1(), key, keysize, (uint8_t*)pData, length, pDstBuf, &resultlength); ASSERT(resultlength == 20); ASSERT(pHashResult != NULL); #else CCHmac(kCCHmacAlgSHA1, key, keysize,(uint8_t*)pData, length, pDstBuf); UNREFERENCED_VARIABLE(resultlength); #endif Cleanup: return hr; }
HRESULT CSocketAddress::ToStringBuffer(char* pszAddrBytes, size_t length) const { HRESULT hr = S_OK; int family = GetFamily(); const void *pAddrBytes = NULL; const char* pszResult = NULL; const size_t portLength = 6; // colon plus 5 digit string e.g. ":55555" char szPort[portLength+1]; ChkIfA(pszAddrBytes == NULL, E_INVALIDARG); ChkIf(length <= 0, E_INVALIDARG); pszAddrBytes[0] = 0; if (family == AF_INET) { pAddrBytes = &(_address.addr4.sin_addr); ChkIf(length < (INET_ADDRSTRLEN+portLength), E_INVALIDARG); } else if (family == AF_INET6) { pAddrBytes = &(_address.addr6.sin6_addr); ChkIf(length < (INET6_ADDRSTRLEN+portLength), E_INVALIDARG); } else { ChkA(E_FAIL); } pszResult = ::inet_ntop(family, pAddrBytes, pszAddrBytes, length); ChkIf(pszResult == NULL, ERRNOHR); sprintf(szPort, ":%d", GetPort()); #if DEBUG ChkIfA(strlen(szPort) > portLength, E_FAIL); #endif strcat(pszAddrBytes, szPort); Cleanup: return hr; }
HRESULT CTestPolling::RemovePipe(int pipeindex) { HRESULT hr = S_OK; size_t size = _pipes.size(); ChkIfA(pipeindex < 0, E_FAIL); ChkIfA(pipeindex >= (int)size, E_FAIL); ChkA(_spPolling->Remove(_pipes[pipeindex].readpipe)); close(_pipes[pipeindex].readpipe); _pipes[pipeindex].readpipe = -1; close(_pipes[pipeindex].writepipe); _pipes[pipeindex].writepipe = -1; _pipes.erase(_pipes.begin()+pipeindex); Cleanup: return hr; }