/**
 * Suggests a default adapter for a given stun server socket
 * @param fPrimary - true if the returned adapter is to be used for the primary socket in a stun server. Typically passing "true" means "return the first adapter enumerated", otherwise return the second adapter enumerated"
 * @param family - Either AF_INET or AF_INET6
 * @param pSocketAddr - OUT param.  On success, contains the address to bind to
 * @return S_OK on success.  Error code otherwise.
 */
HRESULT GetBestAddressForSocketBind(bool fPrimary, int family, uint16_t port, CSocketAddress* pSocketAddr)
{
    HRESULT hr = S_OK;
    ifaddrs* pList = NULL;
    ifaddrs* pAdapter = NULL;
    ifaddrs* pAdapter1 = NULL;
    ifaddrs* pAdapter2 = NULL;

    ChkIfA(pSocketAddr == NULL, E_INVALIDARG);

    ChkIf(getifaddrs(&pList) < 0, ERRNOHR);

    GetDefaultAdapters(family, pList, &pAdapter1, &pAdapter2);

    pAdapter = fPrimary ? pAdapter1 : pAdapter2;

    ChkIf(pAdapter==NULL, E_FAIL);
    ChkIfA(pAdapter->ifa_addr==NULL, E_UNEXPECTED);

    *pSocketAddr = CSocketAddress(*pAdapter->ifa_addr);
    pSocketAddr->SetPort(port);

Cleanup:
    freeifaddrs(pList);
    return hr;
}
HRESULT CTestMessageHandler::ValidateMappedAddress(CStunMessageReader& reader, const CSocketAddress& addrClient)
{
    HRESULT hr = S_OK;
    StunTransactionId transid;
    CSocketAddress mappedaddr;
    
    CRefCountedBuffer spBuffer;
    
    Chk(reader.GetStream().GetBuffer(&spBuffer));
    
    reader.GetTransactionId(&transid);

    //ChkA(reader.GetAttributeByType(STUN_ATTRIBUTE_XORMAPPEDADDRESS, &attrib));
    //ChkA(GetXorMappedAddress(spBuffer->GetData()+attrib.offset, attrib.size, transid, &mappedaddr));
    reader.GetXorMappedAddress(&mappedaddr);
    ChkIfA(false == addrClient.IsSameIP_and_Port(mappedaddr), E_FAIL);    
    
    //ChkA(reader.GetAttributeByType(STUN_ATTRIBUTE_MAPPEDADDRESS, &attrib));
    //ChkA(GetMappedAddress(spBuffer->GetData()+attrib.offset, attrib.size, &mappedaddr));
    
    reader.GetMappedAddress(&mappedaddr);
    ChkIfA(false == addrClient.IsSameIP_and_Port(mappedaddr), 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;
}
size_t CSocketAddress::GetIPImpl(void* pAddr, size_t length, bool fNBO) const
{
    HRESULT hr = S_OK;
    size_t bytescopied = 0;

    ChkIfA(pAddr == NULL, E_INVALIDARG);
    ChkIfA(length <= 0, E_INVALIDARG);
    ChkIfA(length < GetIPLength(), E_INVALIDARG);

    ASSERT((_address.addr.sa_family == AF_INET)||(_address.addr.sa_family == AF_INET6));

    if (_address.addr.sa_family == AF_INET)
    {
        uint32_t ip = _address.addr4.sin_addr.s_addr;
        if (fNBO==false)
        {
            ip = htonl(ip);
        }
        memcpy(pAddr, &ip, sizeof(ip));
        bytescopied = sizeof(ip);
        ASSERT(sizeof(ip) == STUN_IPV4_LENGTH);
    }
    else
    {
        // ipv6 addresses are the same in either byte ordering - just an array of 16 bytes
        ASSERT(sizeof(_address.addr6.sin6_addr.s6_addr) == STUN_IPV6_LENGTH);

        memcpy(pAddr, &_address.addr6.sin6_addr.s6_addr, sizeof(_address.addr6.sin6_addr.s6_addr));
        bytescopied = STUN_IPV6_LENGTH;
    }

Cleanup:
    return bytescopied;

}
// 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;
}
void CStunThreadMessageHandler::SendResponse()
{
    HRESULT hr = S_OK;

    ChkIfA(_spStunResponder == NULL, E_FAIL);
    ChkIfA(_spResponseBuffer->GetSize() <= 0, E_FAIL);

    Chk(_spStunResponder->SendResponse(_socketOutput, _addrResponse, _spResponseBuffer));

Cleanup:
    return;
}
// 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;
}
Example #8
0
HRESULT CTestPolling::WritePipe(PipePair* pPair)
{
    HRESULT hr = S_OK;
    char ch = 'x';
    int ret = -1;
    
    ret = write(pPair->writepipe, &ch, 1);
    ChkIfA(ret < 0, ERRNOHR);
    ChkIfA(ret == 0, E_UNEXPECTED);
    pPair->fDataPending = true;
    
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;
    
}
HRESULT CStunClientTestBase::Init(StunClientLogicConfig* pConfig, StunClientResults* pResults)
{
    HRESULT hr = S_OK;

    ChkIfA(pConfig == NULL, E_INVALIDARG);
    ChkIfA(pResults == NULL, E_INVALIDARG);

    _fInit = true;
    _pConfig = pConfig;
    _pResults = pResults;
    _fCompleted = false;
    memset(&_transid, 0, sizeof(_transid));

Cleanup:
    return hr;
}
Example #11
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;
}
Example #12
0
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;
}
Example #13
0
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;
}
Example #14
0
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;
}
Example #15
0
HRESULT CStunClientLogic::GetResults(StunClientResults* pResults)
{
    HRESULT hr=S_OK;
    ChkIfA(pResults == NULL, E_INVALIDARG);
    *pResults = _results;
Cleanup:
    return hr;
}
Example #16
0
HRESULT CStunMessageBuilder::AddMessageIntegrityLongTerm(const char* pszUserName, const char* pszRealm, const char* pszPassword)
{
    HRESULT hr = S_OK;
    const size_t MAX_KEY_SIZE = MAX_STUN_AUTH_STRING_SIZE*3 + 2;
    uint8_t key[MAX_KEY_SIZE + 1]; // long enough for 64-char strings and two semicolons and a null char for debugging

    uint8_t hash[MD5_DIGEST_LENGTH] = {};
    uint8_t* pResult = NULL;
    uint8_t* pDst = key;

    size_t lenUserName = pszUserName ? strlen(pszUserName) : 0;
    size_t lenRealm = pszRealm ? strlen(pszRealm) : 0;
    size_t lenPassword = pszPassword ? strlen(pszPassword) : 0;
    size_t lenTotal = lenUserName + lenRealm + lenPassword + 2; // +2 for the two colons

    UNREFERENCED_VARIABLE(pResult);

    ChkIfA(lenTotal > MAX_KEY_SIZE, E_INVALIDARG); // if we ever hit this limit, just increase MAX_STUN_AUTH_STRING_SIZE

    // too bad CDatastream really only works on refcounted buffers.  Otherwise, we wouldn't have to do all this messed up pointer math

    // We could create a refcounted buffer in this function, but that would mean a call to "new and delete", and we're trying to avoid memory allocations in
    // critical code paths because they are a proven perf hit

    // TODO - Fix CDataStream and CBuffer so that "ref counted buffers" are no longer needed

    pDst = key;

    memcpy(pDst, pszUserName, lenUserName);
    pDst += lenUserName;

    *pDst = ':';
    pDst++;

    memcpy(pDst, pszRealm, lenRealm);
    pDst += lenRealm;

    *pDst = ':';
    pDst++;

    memcpy(pDst, pszPassword, lenPassword);
    pDst += lenPassword;
    *pDst ='\0'; // null terminate for debugging (this char doesn not get hashed

    ASSERT((pDst-key) == lenTotal);

#ifndef __APPLE__
    pResult = MD5(key, lenTotal, hash);
#else
    pResult = CC_MD5(key, lenTotal, hash);
#endif

    ASSERT(pResult != NULL);
    hr= AddMessageIntegrityImpl(hash, MD5_DIGEST_LENGTH);

Cleanup:
    return hr;
}
Example #17
0
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;
}
Example #18
0
HRESULT CTCPStunThread::Start()
{
    int ret;
    HRESULT hr = S_OK;
    
    ChkIfA(_fThreadIsValid, E_FAIL);
    
    ChkIf(_pipe[0] == -1, E_UNEXPECTED); // Init hasn't been called
    
    _fNeedToExit = false;
    ret = ::pthread_create(&_pthread, NULL, ThreadFunction, this);
    ChkIfA(ret != 0, ERRNO_TO_HRESULT(ret));
    
    _fThreadIsValid = true;
    
Cleanup:
    return hr;
}
Example #19
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;
}
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;
}
Example #21
0
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;
}
Example #22
0
HRESULT CTestPolling::SetNonBlocking(int fd)
{
    HRESULT hr = S_OK;
    int result;
    int flags;
    
    flags = ::fcntl(fd, F_GETFL, 0);
    
    ChkIfA(flags == -1, ERRNOHR);
    
    flags |= O_NONBLOCK;
    
    result = fcntl(fd , F_SETFL , flags);
    
    ChkIfA(result == -1, ERRNOHR);
    
Cleanup:
    return hr;  
    
}
Example #23
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;
}
Example #24
0
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;
}
Example #25
0
HRESULT CStunMessageBuilder::AddStringAttribute(uint16_t attribType, const char* pstr)
{
    HRESULT hr = S_OK;
    // I can't think of a single string attribute that could be legitimately empty
    // AddNonce, AddRealm, AddUserName below depend on this check.  So if this check gets removed, add it back to everywhere else
    ChkIfA(StringHelper::IsNullOrEmpty(pstr), E_INVALIDARG);

    // AddAttribute allows empty attribute values, so if someone needs to add empty attribute values, do it with that call
    hr = AddAttribute(attribType, pstr, pstr?strlen(pstr):0);

Cleanup:
    return hr;
}
Example #26
0
// 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;
}
Example #28
0
// 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;
}
// 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;
}
Example #30
0
HRESULT CStunMessageBuilder::AddUnknownAttributes(const uint16_t* arr, size_t count)
{
    HRESULT hr = S_OK;
    uint16_t size = count * sizeof(uint16_t);
    uint16_t unpaddedsize = size;
    bool fPad = false;

    ChkIfA(arr == NULL, E_INVALIDARG);
    ChkIfA(count <= 0, E_INVALIDARG);

    // fix for RFC 3489. Since legacy clients can't understand implicit padding rules
    // of rfc 5389, then we do what rfc 3489 suggests.  If there are an odd number of attributes
    // that would make the length of the attribute not a multiple of 4, then repeat one
    // attribute.

    fPad = _fLegacyMode && (!!(count % 2));

    if (fPad)
    {
        size += sizeof(uint16_t);
    }

    Chk(AddAttributeHeader(STUN_ATTRIBUTE_UNKNOWNATTRIBUTES, size));

    Chk(_stream.Write(arr, unpaddedsize));

    if (fPad)
    {
        // repeat the last attribute in the array to get an even alignment of 4 bytes
        _stream.Write(&arr[count-1], sizeof(arr[0]));
    }


Cleanup:
    return hr;
}