Esempio n. 1
0
// 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;
}
Esempio n. 2
0
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 CMockTransport::SendResponse(SocketRole roleOutput, const CSocketAddress& addr, CRefCountedBuffer& spResponse)
{
    m_outputRole = roleOutput;
    m_addrDestination = addr;
    m_outputstream.Write(spResponse->GetData(), spResponse->GetSize());

    return S_OK;
}
Esempio n. 4
0
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;
    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;
}
Esempio n. 7
0
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;
}
Esempio n. 8
0
CDataStream::CDataStream(CRefCountedBuffer& spBuffer) :
_spBuffer(spBuffer),
_pos(0),
_fNoGrow(false)
{
    _pBuffer = spBuffer.get();
}
Esempio n. 9
0
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;
}
Esempio n. 10
0
HRESULT CTestClientLogic::ValidateBindingRequest(CRefCountedBuffer& spMsg, StunTransactionId* pTransId)
{
    HRESULT hr = S_OK;
    CStunMessageReader reader;
    CStunMessageReader::ReaderParseState state;

    state = reader.AddBytes(spMsg->GetData(), spMsg->GetSize());
    ChkIfA(state != CStunMessageReader::BodyValidated, E_UNEXPECTED);

    ChkIfA(reader.GetMessageType() != StunMsgTypeBinding, E_UNEXPECTED);

    reader.GetTransactionId(pTransId);

    ChkIfA(false == IsTransactionIdValid(*pTransId), E_FAIL);

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 CStunClientTestBase::BasicReaderValidation(CRefCountedBuffer& spMsg, CStunMessageReader& reader)
{
    HRESULT hr = S_OK;
    CStunMessageReader::ReaderParseState readerstate;
    StunTransactionId transid;
    int cmp = 0;

    readerstate = reader.AddBytes(spMsg->GetData(), spMsg->GetSize());
    ChkIf(readerstate != CStunMessageReader::BodyValidated, E_FAIL);

    reader.GetTransactionId(&transid);

    cmp = memcmp(transid.id, _transid.id, sizeof(_transid));

    ChkIf(cmp!=0, E_FAIL);

Cleanup:
    return hr;
}
Esempio n. 13
0
HRESULT CStunMessageBuilder::AddFingerprintAttribute()
{
    boost::crc_32_type result;
    uint32_t value;
    CRefCountedBuffer spBuffer;
    void* pData = NULL;
    size_t length = 0;
    int offset;

    HRESULT hr = S_OK;

    Chk(_stream.WriteUint16(htons(STUN_ATTRIBUTE_FINGERPRINT)));
    Chk(_stream.WriteUint16(htons(sizeof(uint32_t)))); // field length is 4 bytes
    Chk(_stream.WriteUint32(0)); // dummy value for start

    Chk(FixLengthField());

    // now do a CRC-32 on everything but the last 8 bytes

    ChkA(_stream.GetBuffer(&spBuffer));
    pData = spBuffer->GetData();
    length = spBuffer->GetSize();

    ASSERT(length > 8);
    length = length-8;
    result.process_bytes(pData, length);

    value = result.checksum();
    value = value ^ STUN_FINGERPRINT_XOR;

    offset = -(int)(sizeof(value));

    Chk(_stream.SeekRelative(offset));

    Chk(_stream.WriteUint32(htonl(value)));

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 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;
}
Esempio n. 16
0
HRESULT CStunClientLogic::ProcessResponse(CRefCountedBuffer& spMsg, CSocketAddress& addrRemote, CSocketAddress& addrLocal)
{
    HRESULT hr = S_OK;
    IStunClientTest* pCurrentTest = NULL;

    ChkIfA(_fInitialized == false, E_FAIL);
    ChkIfA(spMsg->GetSize() == 0, E_INVALIDARG);
    ChkIf (_nTestIndex >= _testlist.size(), E_UNEXPECTED);

    pCurrentTest = _testlist[_nTestIndex];

    // passing a response to a test that is already completed ??
    ChkIfA(pCurrentTest->IsCompleted(), E_UNEXPECTED);

    hr = pCurrentTest->ProcessResponse(spMsg, addrRemote, addrLocal);
    // this likely puts the test into the completed state
    // A subsequent call to GetNextMessage will invoke the next tset

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;
}
Esempio n. 18
0
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;
}
Esempio n. 19
0
// 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;
}
// test long-credential authentication
HRESULT CTestMessageHandler::Test4()
{
    HRESULT hr=S_OK;
    CStunMessageBuilder builder1, builder2;
    CStunMessageReader reader1, reader2;
    CSocketAddress clientaddr(0x12345678, 9876);
    CSocketAddress addrMapped;
    CRefCountedBuffer spBuffer;
    CStunThreadMessageHandler handler;
    uint16_t errorcode = 0;
    char szNonce[MAX_STUN_AUTH_STRING_SIZE+1];
    char szRealm[MAX_STUN_AUTH_STRING_SIZE+1];
    
    CStunMessageReader::ReaderParseState state;
    StunMessageEnvelope message;
    
    _spTransport->Reset();
    _spTransport->AddPP(CSocketAddress(0xaaaaaaaa, 1234));
    
    handler.SetAuth(_spAuthLong);
    handler.SetResponder(_spTransport);

    // -----------------------------------------------------------------------
    // simulate a user making a request with no message integrity attribute (or username, or realm)
    InitBindingRequest(builder1);
    builder1.GetResult(&spBuffer);
    message.localSocket = RolePP;
    message.remoteAddr = clientaddr;
    message.spBuffer = spBuffer;
    _spTransport->GetSocketAddressForRole(message.localSocket, &(message.localAddr));
    
    handler.ProcessRequest(message);
    
    spBuffer.reset();
    _spTransport->m_outputstream.GetBuffer(&spBuffer);
    state = reader1.AddBytes(spBuffer->GetData(), spBuffer->GetSize());
    
    ChkIfA(state != CStunMessageReader::BodyValidated, E_FAIL);
    // we expect the response back will be a 401 with a provided nonce and realm
    Chk(reader1.GetErrorCode(&errorcode));
    
    ChkIfA(reader1.GetMessageClass() != ::StunMsgClassFailureResponse, E_UNEXPECTED);
    ChkIf(errorcode != ::STUN_ERROR_UNAUTHORIZED, E_UNEXPECTED);

    reader1.GetStringAttributeByType(STUN_ATTRIBUTE_REALM, szRealm, ARRAYSIZE(szRealm));
    reader1.GetStringAttributeByType(STUN_ATTRIBUTE_NONCE, szNonce, ARRAYSIZE(szNonce));
    
    
    // --------------------------------------------------------------------------------
    // now simulate the follow-up request
    _spTransport->ClearStream();
    spBuffer.reset();
    InitBindingRequest(builder2);
    builder2.AddNonce(szNonce);
    builder2.AddRealm(szRealm);
    builder2.AddUserName("AuthorizedUser");
    builder2.AddMessageIntegrityLongTerm("AuthorizedUser", szRealm, "password");
    builder2.GetResult(&spBuffer);
    
    message.localSocket = RolePP;
    message.remoteAddr = clientaddr;
    message.spBuffer = spBuffer;
    _spTransport->GetSocketAddressForRole(message.localSocket, &(message.localAddr));
    
    handler.ProcessRequest(message);
    
    spBuffer.reset();
    _spTransport->m_outputstream.GetBuffer(&spBuffer);
    
    state = reader2.AddBytes(spBuffer->GetData(), spBuffer->GetSize());
    ChkIfA(state != CStunMessageReader::BodyValidated, E_FAIL);
    ChkIfA(reader2.GetMessageClass() != ::StunMsgClassSuccessResponse, E_UNEXPECTED);
    
    // should have a mapped address
    ChkA(reader2.GetMappedAddress(&addrMapped));
    
    // and the message integrity field should be valid
    ChkA(reader2.ValidateMessageIntegrityLong("AuthorizedUser", szRealm, "password"));
    
    
Cleanup:
    return hr;
}
// test simple authentication
HRESULT CTestMessageHandler::Test3()
{
    HRESULT hr=S_OK;
    CStunMessageBuilder builder1, builder2, builder3;
    CStunMessageReader reader1, reader2, reader3;
    CSocketAddress clientaddr(0x12345678, 9876);
    CRefCountedBuffer spBuffer;
    CStunThreadMessageHandler handler;
    uint16_t errorcode = 0;
    
    CStunMessageReader::ReaderParseState state;
    StunMessageEnvelope message;
    
    _spTransport->Reset();
    _spTransport->AddPP(CSocketAddress(0xaaaaaaaa, 1234));
    
    handler.SetAuth(_spAuthShort);
    handler.SetResponder(_spTransport);

    // -----------------------------------------------------------------------
    // simulate an authorized user making a request with a valid password
    InitBindingRequest(builder1);
    builder1.AddStringAttribute(STUN_ATTRIBUTE_USERNAME, "AuthorizedUser");
    builder1.AddMessageIntegrityShortTerm("password");
    builder1.GetResult(&spBuffer);
    
    message.localSocket = RolePP;
    message.remoteAddr = clientaddr;
    message.spBuffer = spBuffer;
    _spTransport->GetSocketAddressForRole(message.localSocket, &(message.localAddr));
    
    handler.ProcessRequest(message);
    
    // we expect back a response with a valid message integrity field
    spBuffer.reset();
    _spTransport->m_outputstream.GetBuffer(&spBuffer);
    
    state = reader1.AddBytes(spBuffer->GetData(), spBuffer->GetSize());
    ChkIfA(state != CStunMessageReader::BodyValidated, E_FAIL);
    ChkA(reader1.ValidateMessageIntegrityShort("password"));
    

    // -----------------------------------------------------------------------
    // simulate a user with a bad password
    spBuffer.reset();
    InitBindingRequest(builder2);
    builder2.AddStringAttribute(STUN_ATTRIBUTE_USERNAME, "WrongUser");
    builder2.AddMessageIntegrityShortTerm("wrongpassword");
    builder2.GetResult(&spBuffer);
    
    message.localSocket = RolePP;
    message.remoteAddr = clientaddr;
    message.spBuffer = spBuffer;
    _spTransport->GetSocketAddressForRole(message.localSocket, &(message.localAddr));

    _spTransport->ClearStream();
    handler.ProcessRequest(message);
    
    spBuffer.reset();
    _spTransport->m_outputstream.GetBuffer(&spBuffer);
    
    state = reader2.AddBytes(spBuffer->GetData(), spBuffer->GetSize());
    ChkIfA(state != CStunMessageReader::BodyValidated, E_FAIL);
    errorcode = 0;
    ChkA(reader2.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
    spBuffer.reset();
    InitBindingRequest(builder3);
    builder3.GetResult(&spBuffer);
    
    message.localSocket = RolePP;
    message.remoteAddr = clientaddr;
    message.spBuffer = spBuffer;
    _spTransport->GetSocketAddressForRole(message.localSocket, &(message.localAddr));

    _spTransport->ClearStream();
    handler.ProcessRequest(message);
    
    spBuffer.reset();
    _spTransport->m_outputstream.GetBuffer(&spBuffer);
    
    
    state = reader3.AddBytes(spBuffer->GetData(), spBuffer->GetSize());
    ChkIfA(state != CStunMessageReader::BodyValidated, E_FAIL);
    errorcode = 0;
    ChkA(reader3.GetErrorCode(&errorcode));
    ChkIfA(errorcode != ::STUN_ERROR_BADREQUEST, 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;
}
Esempio n. 23
0
HRESULT CStunClientLogic::GetNextMessage(CRefCountedBuffer& spMsg, CSocketAddress* pAddrDest, uint32_t timeCurrentMilliseconds)
{
    HRESULT hr = S_OK;
    uint32_t diff = 0;
    IStunClientTest* pCurrentTest = NULL;
    bool fReadyToReturn = false;

    ChkIfA(_fInitialized == false, E_FAIL);
    ChkIfA(spMsg->GetAllocatedSize() == 0, E_INVALIDARG);
    ChkIfA(pAddrDest == NULL, E_INVALIDARG);

    // clients should pass in the expected size
    ChkIfA(spMsg->GetAllocatedSize() < MAX_STUN_MESSAGE_SIZE, E_INVALIDARG);


    while (fReadyToReturn==false)
    {
        if (_nTestIndex >= _testlist.size())
        {
            hr = E_STUNCLIENT_RESULTS_READY; // no more tests to run
            break;
        }

        pCurrentTest = _testlist[_nTestIndex];

        if (_fPreCheckRunOnTest==false)
        {
            // give the test an early chance to complete before sending a message (based on results of previous test)
            pCurrentTest->PreRunCheck();
            _fPreCheckRunOnTest = true;
        }


        // has this test completed or is it in a state in which it can't run?
        if (pCurrentTest->IsCompleted() || pCurrentTest->IsReadyToRun()==false)
        {
            // increment to the next test
            _nTestIndex++;
            _sendCount = 0;
            _fPreCheckRunOnTest = false;

            continue;
        }

        // Have we waited long enough for a response
        diff = (timeCurrentMilliseconds - _timeLastMessageSent) / 1000; // convert from milliseconds to seconds
        if ((diff < _config.timeoutSeconds) && (_sendCount != 0))
        {
            hr = E_STUNCLIENT_STILL_WAITING;
            break;
        }

        // have we exceeded the retry count
        if (_sendCount >= _config.uMaxAttempts)
        {
            // notify the test that it has timed out
            // this should put it in the completed state (and we increment to next test on next loop)
            pCurrentTest->NotifyTimeout();
            ASSERT(pCurrentTest->IsCompleted());
            continue;
        }

        // ok - we are ready to go fetch a message
        hr = pCurrentTest->GetMessage(spMsg, pAddrDest);
        ASSERT(SUCCEEDED(hr));
        if (FAILED(hr))
        {
            break;
        }

        // success
        _sendCount++;
        _timeLastMessageSent = timeCurrentMilliseconds;
        fReadyToReturn = true;
        hr = S_OK;
    }
Cleanup:
    return hr;
}