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::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;
}
void CStunThreadMessageHandler::ProcessRequest(StunMessageEnvelope& message)
{
    CStunMessageReader reader;
    CStunMessageReader::ReaderParseState state;
    uint16_t responsePort = 0;
    HRESULT hr = S_OK;


    ChkIfA(_spStunResponder == NULL, E_FAIL);

    _spReaderBuffer->SetSize(0);
    _spResponseBuffer->SetSize(0);
    _message = message;

    _addrResponse = message.remoteAddr;
    _socketOutput = message.localSocket;
    _fRequestHasResponsePort = false;
    
    // zero out _error without the overhead of zero'ing out every byte in the strings
    _error.errorcode = 0;
    _error.szNonce[0] = 0;
    _error.szRealm[0] = 0;
    _error.attribUnknown = 0;
    
    _integrity.fSendWithIntegrity = false;
    _integrity.szUser[0] = '\0';
    _integrity.szRealm[0] = '\0';
    _integrity.szPassword[0] = '\0';
    
    
    // attach the temp buffer to reader
    reader.GetStream().Attach(_spReaderBuffer, true);


    reader.SetAllowLegacyFormat(true);

    // parse the request
    state = reader.AddBytes(message.spBuffer->GetData(), message.spBuffer->GetSize());

    // If we get something that can't be validated as a stun message, don't send back a response
    // STUN RFC may suggest sending back a "500", but I think that's the wrong approach.
    ChkIf (state != CStunMessageReader::BodyValidated, E_FAIL);
    
    // Regardless of what we send back, let's always attempt to honor a response port request
    // Fix the destination port if the client asked for us to send back to another port
    if (SUCCEEDED(reader.GetResponsePort(&responsePort)))
    {
        _addrResponse.SetPort(responsePort);
        _fRequestHasResponsePort = true;
    }

    reader.GetTransactionId(&_transid);

    // ignore anything that is not a request (with no response)
    ChkIf(reader.GetMessageClass() != StunMsgClassRequest, E_FAIL);

    // pre-prep the error message in case we wind up needing to send it
    _error.msgtype = reader.GetMessageType();
    _error.msgclass = StunMsgClassFailureResponse;

    if (reader.GetMessageType() != StunMsgTypeBinding)
    {
        // we're going to send back an error response
        _error.errorcode = STUN_ERROR_BADREQUEST; // invalid request
    }
    else
    {
        // handle authentication - but only if an auth provider has been set
        hr = ValidateAuth(reader);

        // if auth succeeded, then carry on to handling the request
        if (SUCCEEDED(hr) && (_error.errorcode==0))
        {
            // handle the binding request
            hr = ProcessBindingRequest(reader);
        }

        // catch all for any case where an error occurred
        if (FAILED(hr) && (_error.errorcode==0))
        {
            _error.errorcode = STUN_ERROR_BADREQUEST;
        }
    }

    if (_error.errorcode != 0)
    {
        // if either ValidateAuth or ProcessBindingRequest set an errorcode, or a fatal error occurred
        SendErrorResponse();
    }
    else
    {
        SendResponse();
    }


Cleanup:
    return;
}
Esempio n. 4
0
void TcpClientLoop(StunClientLogicConfig& config, ClientSocketConfig& socketconfig)
{
    
    HRESULT hr = S_OK;
    CStunSocket stunsocket;
    CStunClientLogic clientlogic;
    int sock;
    CRefCountedBuffer spMsg(new CBuffer(1500));
    CRefCountedBuffer spMsgReader(new CBuffer(1500));
    CSocketAddress addrDest, addrLocal;
    HRESULT hrRet, hrResult;
    int ret;
    size_t bytes_sent, bytes_recv;
    size_t bytes_to_send, max_bytes_recv, remaining;
    uint8_t* pData=NULL;
    size_t readsize;
    CStunMessageReader reader;
    StunClientResults results;
    
   
    hr= clientlogic.Initialize(config);
    if (FAILED(hr))
    {
        Logging::LogMsg(LL_ALWAYS, "clientlogic.Initialize failed (hr == %x)", hr);
        Chk(hr);
    }
    
    
    while (true)
    {
    
        stunsocket.Close();
        hr = stunsocket.TCPInit(socketconfig.addrLocal, RolePP, true);
        if (FAILED(hr))
        {
            Logging::LogMsg(LL_ALWAYS, "Unable to create local socket for TCP connection (hr == %x)", hr);
            Chk(hr);
        }
        
        hrRet = clientlogic.GetNextMessage(spMsg, &addrDest, ::GetMillisecondCounter());
        
        if (hrRet == E_STUNCLIENT_RESULTS_READY)
        {
            // clean exit
            break;
        }

        // we should never get a "still waiting" return with TCP, because config.timeout is 0
        ASSERT(hrRet != E_STUNCLIENT_STILL_WAITING);
        
        if (FAILED(hrRet))
        {
            Chk(hrRet);
        }
        
        // connect to server
        sock = stunsocket.GetSocketHandle();
        
        ret = ::connect(sock, addrDest.GetSockAddr(), addrDest.GetSockAddrLength());
        
        if (ret == -1)
        {
            hrResult = ERRNOHR;
            Logging::LogMsg(LL_ALWAYS, "Can't connect to server (hr == %x)", hrResult);
            Chk(hrResult);
        }
        
        Logging::LogMsg(LL_DEBUG, "Connected to server");
        
        bytes_to_send = (int)(spMsg->GetSize());
        
        bytes_sent = 0;
        pData = spMsg->GetData();
        while (bytes_sent < bytes_to_send)
        {
            ret = ::send(sock, pData+bytes_sent, bytes_to_send-bytes_sent, 0);
            if (ret < 0)
            {
                hrResult = ERRNOHR;
                Logging::LogMsg(LL_ALWAYS, "Send failed (hr == %x)", hrResult);
                Chk(hrResult);
            }
            bytes_sent += ret;
        }
        
        Logging::LogMsg(LL_DEBUG, "Request sent - waiting for response");
        
        
        // consume the response
        reader.Reset();
        reader.GetStream().Attach(spMsgReader, true);
        pData = spMsg->GetData();
        bytes_recv = 0;
        max_bytes_recv = spMsg->GetAllocatedSize();
        remaining = max_bytes_recv;
        
        while (remaining > 0)
        {
            readsize = reader.HowManyBytesNeeded();
            
            if (readsize == 0)
            {
                break;
            }
            
            if (readsize > remaining)
            {
                // technically an error, but the client logic will figure it out
                ASSERT(false);
                break;
            }
            
            ret = ::recv(sock, pData+bytes_recv, readsize, 0);
            if (ret == 0)
            {
                // server cut us off before we got all the bytes we thought we were supposed to get?
                ASSERT(false);
                break;
            }
            if (ret < 0)
            {
                hrResult = ERRNOHR;
                Logging::LogMsg(LL_ALWAYS, "Recv failed (hr == %x)", hrResult);
                Chk(hrResult);
            }
            
            reader.AddBytes(pData+bytes_recv, ret);
            bytes_recv += ret;
            remaining = max_bytes_recv - bytes_recv;
            spMsg->SetSize(bytes_recv);
        }
        
        
        // now feed the response into the client logic
        stunsocket.UpdateAddresses();
        addrLocal = stunsocket.GetLocalAddress();
        clientlogic.ProcessResponse(spMsg, addrDest, addrLocal);
    }
    
    stunsocket.Close();

    results.Init();
    clientlogic.GetResults(&results);
    ::DumpResults(config, results);
    
Cleanup:
    return;
    
}