HRESULT CSocketAddress::GetLocalHost(uint16_t family, CSocketAddress* pAddr)
{
    
    if (  ((family != AF_INET) && (family != AF_INET6)) || 
          (pAddr == NULL))
    {
        ASSERT(false);
        return E_FAIL;
    }
    
    if (family == AF_INET)
    {
        uint32_t ip = 0x7f000001; // 127.0.0.1 in host byte order
        *pAddr = CSocketAddress(ip, 0);
    }
    else
    {
        sockaddr_in6 addr6 = {};
        COMPILE_TIME_ASSERT(sizeof(addr6.sin6_addr) == 16);
        
        // ::1
        uint8_t ip6[16] = {};
        ip6[15] = 1;

        addr6.sin6_family = AF_INET6;
        memcpy(&addr6.sin6_addr, ip6, 16);
        *pAddr = CSocketAddress(addr6);
    }
    
    return S_OK;
}
Example #2
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 #3
0
CSocketAddress CGSocket::GetPeerName( ) const
{
	struct sockaddr_in SockAddrIn;
	int iRet = GetPeerName( &SockAddrIn );
	if ( iRet )
	{
		return( CSocketAddress( INADDR_BROADCAST, 0 ));	// invalid.
	}
	else
	{
		return( CSocketAddress( SockAddrIn ));
	}
}
/**
 * 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;
}
Example #5
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;
}
void CStunSocket::Close()
{
    if (_sock != -1)
    {
        close(_sock);
        _addrlocal = CSocketAddress(0,0);
    }
}
HRESULT CMockTransport::ClearStream()

{
    m_outputstream.Reset();
    m_outputRole = (SocketRole)-1;
    m_addrDestination = CSocketAddress();
    return S_OK;
}
HRESULT CMockTransport::Reset()
{
    for (unsigned int index = 0; index < ARRAYSIZE(m_addrs); index++)
    {
        m_addrs[index] = CSocketAddress();
    }
    ClearStream();

    return S_OK;
}
Example #9
0
HRESULT GetMappedAddress(uint8_t* pData, size_t size, CSocketAddress* pAddr)
{
    uint16_t port;
    HRESULT hr = S_OK;
    uint8_t attributeid;
    uint8_t ip6[STUN_IPV6_LENGTH];
    uint32_t ip4;


    CRefCountedBuffer spBuffer(new CBuffer(pData, size, false));
    CDataStream stream(spBuffer);

    ChkIfA(pAddr==NULL, E_INVALIDARG);

    Chk(stream.SeekDirect(1)); // skip over the zero byte

    Chk(stream.ReadUint8(&attributeid));
    Chk(stream.ReadUint16(&port));
    port = ntohs(port);

    if (attributeid == STUN_ATTRIBUTE_FIELD_IPV4)
    {
        Chk(stream.ReadUint32(&ip4));
        ip4 = ntohl(ip4);
        *pAddr = CSocketAddress(ip4, port);
    }
    else
    {
        sockaddr_in6 addr6={};
        Chk(stream.Read(ip6, STUN_IPV6_LENGTH));
        addr6.sin6_family = AF_INET6;
        addr6.sin6_port = htons(port);
        memcpy(&addr6.sin6_addr, ip6, STUN_IPV6_LENGTH);
        *pAddr = CSocketAddress(addr6);
    }

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;
}
//static
HRESULT CStunSocket::Create(const CSocketAddress& addrlocal, SocketRole role, boost::shared_ptr<CStunSocket>* pStunSocketShared)
{
    int sock = -1;
    int ret;
    CStunSocket* pSocket = NULL;
    sockaddr_storage addrBind = {};
    socklen_t sizeaddrBind;
    HRESULT hr = S_OK;
    
    ChkIfA(pStunSocketShared == NULL, E_INVALIDARG);
    
    sock = socket(addrlocal.GetFamily(), SOCK_DGRAM, 0);
    ChkIf(sock < 0, ERRNOHR);
    
    ret = bind(sock, addrlocal.GetSockAddr(), addrlocal.GetSockAddrLength());
    ChkIf(ret < 0, ERRNOHR);
    
    // call get sockname to find out what port we just binded to.  (Useful for when addrLocal.port is 0)
    sizeaddrBind = sizeof(addrBind);
    ret = ::getsockname(sock, (sockaddr*)&addrBind, &sizeaddrBind);
    ChkIf(ret < 0, ERRNOHR);
    
    pSocket = new CStunSocket();
    pSocket->_sock = sock;
    pSocket->_addrlocal = CSocketAddress(*(sockaddr*)&addrBind);
    pSocket->_role = role;
    sock = -1;
    
    {
        boost::shared_ptr<CStunSocket> spTmp(pSocket);
        pStunSocketShared->swap(spTmp);
    }
    
    
Cleanup:

    if (sock != -1)
    {
        close(sock);
        sock = -1;
    }

    return hr;
}
Example #12
0
void CTCPServer::InitTSA(TransportAddressSet* pTSA, SocketRole role, bool fValid, const CSocketAddress& addrListen, const CSocketAddress& addrAdvertise)
{
    if (fValid == false)
    {
        pTSA->set[role].fValid = false;
        pTSA->set[role].addr = CSocketAddress();
    }
    else
    {
        pTSA->set[role].fValid = true;
        
        if (addrAdvertise.IsIPAddressZero())
        {
            pTSA->set[role].addr = addrListen;
        }
        else
        {
            pTSA->set[role].addr = addrAdvertise;
            pTSA->set[role].addr.SetPort(addrListen.GetPort());
        }
    }

}
Example #13
0
StunConnection* CTCPStunThread::AcceptConnection(CStunSocket* pListenSocket)
{
    int listensock = pListenSocket->GetSocketHandle();
    SocketRole role = pListenSocket->GetRole();
    int clientsock = -1;
    int socktmp = -1;
    sockaddr_storage addrClient;
    socklen_t socklen = sizeof(addrClient);
    StunConnection* pConn = NULL;
    HRESULT hr = S_OK;
    int insertresult;
    int err;
    
    ASSERT(listensock != -1);
    ASSERT(::IsValidSocketRole(role));

    socktmp = ::accept(listensock, (sockaddr*)&addrClient, &socklen);

    err = errno;
    Logging::LogMsg(LL_VERBOSE, "accept returns %d (errno == %d)", socktmp, (socktmp<0)?err:0);
    ChkIfA(socktmp == -1, E_FAIL);
    
    // --- rate limit check-------
    if (_spLimiter.get())
    {
        CSocketAddress addr = CSocketAddress(addrClient);
        bool allowed_to_pass = _spLimiter->RateCheck(addr);
        
        if (allowed_to_pass == false)
        {
            if (Logging::GetLogLevel() >= LL_VERBOSE)
            {
                char szIP[100];
                addr.ToStringBuffer(szIP, 100);
                Logging::LogMsg(LL_VERBOSE, "Rate Limiter has blocked incoming connection from IP %s", szIP);
            }
            ChkIf(false, E_FAIL); // this will trigger the socket to be immediately closed
        }
    }
    // --------------------------
    
    
    clientsock = socktmp;
    
    pConn = _connectionpool.GetConnection(clientsock, role);
    ChkIfA(pConn == NULL, E_FAIL); // Our connection pool has nothing left to give, only thing to do is abort this connection and close the socket
    socktmp = -1;
    
    ChkA(pConn->_stunsocket.SetNonBlocking(true));
    
    ChkA(_spPolling->Add(clientsock, EPOLL_CLIENT_READ_EVENT_SET));
    
    // add connection to our tracking tables
    pConn->_idHashTable = (_pNewConnList == &_hashConnections1) ? 1 : 2;
    insertresult = _pNewConnList->Insert(clientsock, pConn);
    
    // out of space in the lookup tables?
    ChkIfA(insertresult == -1, E_FAIL);
    
    if (Logging::GetLogLevel() >= LL_VERBOSE)
    {
        char szIPRemote[100];
        char szIPLocal[100];
        pConn->_stunsocket.GetLocalAddress().ToStringBuffer(szIPLocal, ARRAYSIZE(szIPLocal));
        pConn->_stunsocket.GetRemoteAddress().ToStringBuffer(szIPRemote, ARRAYSIZE(szIPRemote));
        Logging::LogMsg(LL_VERBOSE, "accepting new connection on socket %d from %s on interface %s", pConn->_stunsocket.GetSocketHandle(), szIPRemote, szIPLocal);
    }
    
    
Cleanup:
    
    if (FAILED(hr))
    {
        CloseConnection(pConn);
        pConn = NULL;
        if (socktmp != -1)
        {
            close(socktmp);
        }
    }

    return pConn;
}
Example #14
0
// This test validates that the EnablePktInfoOption set on a socket allows us to get at the destination IP address for incoming packets
// This is needed so that we can correctly insert an origin address into responses from the server
// Otherwise, the server doesn't have a way of knowing which interface a packet arrived on when it's listening on INADDR_ANY (all available addresses)
HRESULT CTestRecvFromEx::DoTest(bool fIPV6)
{
    // create a couple of sockets for send/recv
    HRESULT hr = S_OK;
    CSocketAddress addrAny(0,0); // INADDR_ANY, random port
    sockaddr_in6 addrAnyIPV6 = {};
    uint16_t portRecv = 0;
    CRefCountedStunSocket spSocketSend, spSocketRecv;
    fd_set set = {};
    CSocketAddress addrDestForSend;
    CSocketAddress addrDestOnRecv;
    CSocketAddress addrSrcOnRecv;
    
    CSocketAddress addrSrc;
    CSocketAddress addrDst;
    
    char ch = 'x';
    sockaddr_storage addrDummy;
    socklen_t addrlength;
    int ret;
    timeval tv = {};
    
    
    if (fIPV6)
    {
        addrAnyIPV6.sin6_family = AF_INET6;
        addrAny = CSocketAddress(addrAnyIPV6);
    }
    
    
    // create two sockets listening on INADDR_ANY.  One for sending and one for receiving
    ChkA(CStunSocket::Create(addrAny, RolePP, &spSocketSend));
    ChkA(CStunSocket::Create(addrAny, RolePP, &spSocketRecv));
    
    spSocketRecv->EnablePktInfoOption(true);
    
    portRecv = spSocketRecv->GetLocalAddress().GetPort();
    
    // now send to localhost
    if (fIPV6)
    {
        sockaddr_in6 addr6 = {};
        addr6.sin6_family = AF_INET6;
        ::inet_pton(AF_INET6, "::1", &(addr6.sin6_addr));
        addrDestForSend = CSocketAddress(addr6);
    }
    else
    {
        sockaddr_in addr4 = {};
        addr4.sin_family = AF_INET;
        ::inet_pton(AF_INET, "127.0.0.1", &(addr4.sin_addr));
        addrDestForSend = CSocketAddress(addr4);
    }
    addrDestForSend.SetPort(portRecv);
    
    // flush out any residual packets that might be buffered up on recv socket
    ret = -1;
    do
    {
        addrlength = sizeof(addrDummy);
        ret = ::recvfrom(spSocketRecv->GetSocketHandle(), &ch, sizeof(ch), MSG_DONTWAIT, (sockaddr*)&addrDummy, &addrlength);
    } while (ret >= 0);
    
    // now send some data to ourselves
    ret = sendto(spSocketSend->GetSocketHandle(), &ch, sizeof(ch), 0, addrDestForSend.GetSockAddr(), addrDestForSend.GetSockAddrLength());
    ChkIfA(ret <= 0, E_UNEXPECTED);
    
    // now wait for the data to arrive
    FD_ZERO(&set);
    FD_SET(spSocketRecv->GetSocketHandle(), &set);
    tv.tv_sec = 3;
    
    ret = select(spSocketRecv->GetSocketHandle()+1, &set, NULL, NULL, &tv);
    
    ChkIfA(ret <= 0, E_UNEXPECTED);
    
    ret = ::recvfromex(spSocketRecv->GetSocketHandle(), &ch, 1, MSG_DONTWAIT, &addrSrcOnRecv, &addrDestOnRecv);
    
    ChkIfA(ret <= 0, E_UNEXPECTED);    
    
    ChkIfA(addrSrcOnRecv.IsIPAddressZero(), E_UNEXPECTED);
    ChkIfA(addrDestOnRecv.IsIPAddressZero(), E_UNEXPECTED);
    
    
Cleanup:

    return hr;
}
Example #15
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;
}
HRESULT GetSocketAddressForAdapter(int family, const char* pszAdapterName, uint16_t port, CSocketAddress* pSocketAddr)
{
    HRESULT hr = S_OK;
    ifaddrs* pList = NULL;
    ifaddrs* pAdapter = NULL;
    ifaddrs* pAdapterFound = NULL;


    ChkIfA(pszAdapterName == NULL, E_INVALIDARG);
    ChkIfA(pszAdapterName[0] == '\0', E_INVALIDARG);
    ChkIfA(pSocketAddr == NULL, E_INVALIDARG);



    // what if the socket address is available, but not "up".  Well, just let this call succeed.  If the server errors out, it will get cleaned up then
    ChkIf(getifaddrs(&pList) < 0, ERRNOHR);
    pAdapter = pList;
    while (pAdapter)
    {
        if ((pAdapter->ifa_addr != NULL) && (pAdapter->ifa_name != NULL) && (family == pAdapter->ifa_addr->sa_family))
        {
            if (strcmp(pAdapter->ifa_name, pszAdapterName) == 0)
            {
                pAdapterFound = pAdapter;
                break;
            }
        }
        pAdapter = pAdapter->ifa_next;
    }


    // If pszAdapterName is an IP address, convert it into a sockaddr and compare the address field with that of the adapter
    // Note: an alternative approach would be to convert pAdapter->ifa_addr to a string and then do a string compare.
    // But then it would be difficult to match "::1" with "0:0:0:0:0:0:0:1" and other formats of IPV6 strings
    if ((pAdapterFound == NULL) && ((family == AF_INET) || (family == AF_INET6)) )
    {
        uint8_t addrbytes[sizeof(in6_addr)] = {};
        int comparesize = (family == AF_INET) ? sizeof(in_addr) : sizeof(in6_addr);
        void* pCmp = NULL;


        if (inet_pton(family, pszAdapterName, addrbytes) == 1)
        {
             pAdapter = pList;
             while (pAdapter)
             {
                 if ((pAdapter->ifa_addr != NULL) && (family == pAdapter->ifa_addr->sa_family))
                 {
                     // offsetof(sockaddr_in, sin_addr) != offsetof(sockaddr_in6, sin6_addr)
                     // so you really can't do too many casting tricks like you can with sockaddr and sockaddr_in

                     if (family == AF_INET)
                     {
                         sockaddr_in *pAddr4 = (sockaddr_in*)(pAdapter->ifa_addr);
                         pCmp = &(pAddr4->sin_addr);
                     }
                     else
                     {
                         sockaddr_in6 *pAddr6 = (sockaddr_in6*)(pAdapter->ifa_addr);
                         pCmp = &(pAddr6->sin6_addr);
                     }

                     if (memcmp(pCmp, addrbytes, comparesize) == 0)
                     {
                         // match on ip address string found
                         pAdapterFound = pAdapter;
                         break;
                     }
                 }
                 pAdapter = pAdapter->ifa_next;
             }
        }
    }

    ChkIf(pAdapterFound == NULL, E_FAIL);

    {
        *pSocketAddr = CSocketAddress(*(pAdapterFound->ifa_addr));
        pSocketAddr->SetPort(port);
    }

Cleanup:

    freeifaddrs(pList);
    return hr;

}
Example #17
0
HRESULT CTestClientLogic::CommonInit(NatBehavior behavior, NatFiltering filtering)
{
    HRESULT hr = S_OK;

    CSocketAddress addrMapped(0x22222222, 6000);

    _addrServerPP = CSocketAddress(0xaaaaaaaa, 1001);
    _addrServerPA = CSocketAddress(0xaaaaaaaa, 1002);
    _addrServerAP = CSocketAddress(0xbbbbbbbb, 1001);
    _addrServerAA = CSocketAddress(0xbbbbbbbb, 1002);

    _tsa.set[RolePP].fValid = true;
    _tsa.set[RolePP].addr = _addrServerPP;
    _tsa.set[RolePA].fValid = true;
    _tsa.set[RolePA].addr = _addrServerPA;
    _tsa.set[RoleAP].fValid = true;
    _tsa.set[RoleAP].addr = _addrServerAP;
    _tsa.set[RoleAA].fValid = true;
    _tsa.set[RoleAA].addr = _addrServerAA;


    _addrLocal = CSocketAddress(0x33333333, 7000);

    _addrMappedPP = addrMapped;
    _addrMappedPA = addrMapped;
    _addrMappedAP = addrMapped;
    _addrMappedAA = addrMapped;

    _spClientLogic = boost::shared_ptr<CStunClientLogic>(new CStunClientLogic());


    switch (behavior)
    {
    case DirectMapping:
    {
        _addrMappedPP = _addrLocal;
        _addrMappedPA = _addrLocal;
        _addrMappedAP = _addrLocal;
        _addrMappedAA = _addrLocal;
        break;
    }

    case EndpointIndependentMapping:
    {
        break;
    }

    case AddressDependentMapping:
    {
        _addrMappedAP.SetPort(6002);
        _addrMappedAA.SetPort(6002);
        break;
    }

    case AddressAndPortDependentMapping:
    {
        _addrMappedPA.SetPort(6001);
        _addrMappedAP.SetPort(6002);
        _addrMappedAA.SetPort(6003);
        break;
    }

    default:
    {
        ChkA(E_FAIL);
    }
    }

    switch (filtering)
    {
    case EndpointIndependentFiltering:
    case DirectConnectionFiltering:
    {
        _fAllowChangeRequestPA  = true;
        _fAllowChangeRequestAA = true;
        break;
    }

    case AddressDependentFiltering:
    {
        _fAllowChangeRequestPA  = true;
        _fAllowChangeRequestAA = false;
        break;
    }

    case AddressAndPortDependentFiltering:
    {
        _fAllowChangeRequestPA  = false;
        _fAllowChangeRequestAA = false;
        break;
    }
    default:
    {
        ChkA(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;
}
Example #19
0
HRESULT CreateConfigFromCommandLine(ClientCmdLineArgs& args, StunClientLogicConfig* pConfig, ClientSocketConfig* pSocketConfig)
{
    HRESULT hr = S_OK;
    StunClientLogicConfig& config = *pConfig;
    ClientSocketConfig& socketconfig = *pSocketConfig;
    int ret;
    uint16_t localport = 0;
    uint16_t remoteport = 0;
    int nPort = 0;
    char szIP[100];
    bool fTCP = false;


    config.fBehaviorTest = false;
    config.fFilteringTest = false;
    config.fTimeoutIsInstant = false;
    config.timeoutSeconds = 0; // use default
    config.uMaxAttempts = 0;

    socketconfig.family = AF_INET;
    socketconfig.socktype = SOCK_DGRAM;
    socketconfig.addrLocal = CSocketAddress(0, 0);

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


    // family (protocol type) ------------------------------------
    if (StringHelper::IsNullOrEmpty(args.strFamily.c_str())==false)
    {
        int optvalue = atoi(args.strFamily.c_str());
        switch (optvalue)
        {
            case 4: socketconfig.family = AF_INET; break;
            case 6: socketconfig.family = AF_INET6; break;
            default:
            {
                Logging::LogMsg(LL_ALWAYS, "Family option must be either 4 or 6");
                Chk(E_INVALIDARG);
            }
        }
    }
    
    // protocol --------------------------------------------
    StringHelper::ToLower(args.strProtocol);
    if (StringHelper::IsNullOrEmpty(args.strProtocol.c_str()) == false)
    {
        if ((args.strProtocol != "udp") && (args.strProtocol != "tcp"))
        {
            Logging::LogMsg(LL_ALWAYS, "Only udp and tcp are supported protocol versions");
            Chk(E_INVALIDARG);
        }
        
        if (args.strProtocol == "tcp")
        {
            fTCP = true;
            socketconfig.socktype = SOCK_STREAM;
            config.uMaxAttempts = 1;
        }
    }

    // remote port ---------------------------------------------
    if (StringHelper::IsNullOrEmpty(args.strRemotePort.c_str()) == false)
    {
        ret = StringHelper::ValidateNumberString(args.strRemotePort.c_str(), 1, 0xffff, &nPort);
        if (ret < 0)
        {
            Logging::LogMsg(LL_ALWAYS, "Remote port must be between 1 - 65535");
            Chk(E_INVALIDARG);
        }
        remoteport = (uint16_t)(unsigned int)nPort;
    }
    else
    {
        remoteport = DEFAULT_STUN_PORT;
    }


    // remote server -----------------------------------------
    if (StringHelper::IsNullOrEmpty(args.strRemoteServer.c_str()))
    {
        Logging::LogMsg(LL_ALWAYS, "No server address specified");
        Chk(E_INVALIDARG);
    }
    
    hr = ::ResolveHostName(args.strRemoteServer.c_str(), socketconfig.family, false, &config.addrServer);
    
    if (FAILED(hr))
    {
        Logging::LogMsg(LL_ALWAYS, "Unable to resolve hostname for %s", args.strRemoteServer.c_str());
        Chk(hr);
    }
    
    config.addrServer.ToStringBuffer(szIP, ARRAYSIZE(szIP));
    Logging::LogMsg(LL_DEBUG, "Resolved %s to %s", args.strRemoteServer.c_str(), szIP);
    config.addrServer.SetPort(remoteport);


    // local port --------------------------------------------
    if (StringHelper::IsNullOrEmpty(args.strLocalPort.c_str()) == false)
    {
        ret = StringHelper::ValidateNumberString(args.strLocalPort.c_str(), 1, 0xffff, &nPort);
        if (ret < 0)
        {
            Logging::LogMsg(LL_ALWAYS, "Local port must be between 1 - 65535");
            Chk(E_INVALIDARG);
        }
        localport = (uint16_t)(unsigned int)nPort;
    }

    // local address ------------------------------------------
    if (StringHelper::IsNullOrEmpty(args.strLocalAddr.c_str()) == false)
    {
        hr = GetSocketAddressForAdapter(socketconfig.family, args.strLocalAddr.c_str(), localport, &socketconfig.addrLocal);
        if (FAILED(hr))
        {
            Logging::LogMsg(LL_ALWAYS, "Unable to find matching adapter or interface for local address option");
            Chk(hr);
        }
    }
    else
    {
        if (socketconfig.family == AF_INET6)
        {
            sockaddr_in6 addr6 = {};
            addr6.sin6_family = AF_INET6;
            socketconfig.addrLocal = CSocketAddress(addr6);
            socketconfig.addrLocal.SetPort(localport);
        }
        else
        {
            socketconfig.addrLocal = CSocketAddress(0,localport);
        }
    }

    // mode ---------------------------------------------
    StringHelper::ToLower(args.strMode);
    if (StringHelper::IsNullOrEmpty(args.strMode.c_str()) == false)
    {
        if (args.strMode == "basic")
        {
            ;
        }
        else if (args.strMode == "full")
        {
            config.fBehaviorTest = true;
            config.fFilteringTest = (fTCP == false); // impossible to to a filtering test in TCP
        }
        else
        {
            Logging::LogMsg(LL_ALWAYS, "Mode option must be 'full' or 'basic'");
        }
    }



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;
}
Example #21
0
HRESULT CTCPServer::Initialize(const CStunServerConfig& config)
{
    HRESULT hr = S_OK;
    TransportAddressSet tsaListenAll;
    TransportAddressSet tsaHandler;
    boost::shared_ptr<RateLimiter> spLimiter;
    
    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 it can offer a CHANGED-ADDRESS attribute.
    
    InitTSA(&tsaHandler, RolePP, config.fHasPP, config.addrPP, config.addrPrimaryAdvertised);
    InitTSA(&tsaHandler, RolePA, config.fHasPA, config.addrPA, config.addrPrimaryAdvertised);
    InitTSA(&tsaHandler, RoleAP, config.fHasAP, config.addrAP, config.addrAlternateAdvertised);
    InitTSA(&tsaHandler, RoleAA, config.fHasAA, config.addrAA, config.addrAlternateAdvertised);
    
    InitTSA(&tsaListenAll, RolePP, config.fHasPP, config.addrPP, CSocketAddress());
    InitTSA(&tsaListenAll, RolePA, config.fHasPA, config.addrPA, CSocketAddress());
    InitTSA(&tsaListenAll, RoleAP, config.fHasAP, config.addrAP, CSocketAddress());
    InitTSA(&tsaListenAll, RoleAA, config.fHasAA, config.addrAA, CSocketAddress());
    
    if (config.fEnableDosProtection)
    {
        spLimiter = boost::shared_ptr<RateLimiter>(new RateLimiter(20000, config.fMultiThreadedMode));
    }
    
    if (config.fMultiThreadedMode == false)
    {
        _threads[0] = new CTCPStunThread();
        
        ChkA(_threads[0]->Init(tsaListenAll, tsaHandler, _spAuth, config.nMaxConnections, spLimiter));
    }
    else
    {
        for (int threadindex = 0; threadindex < 4; threadindex++)
        {
            
            if (tsaHandler.set[threadindex].fValid)
            {
                TransportAddressSet tsaListen = tsaListenAll;
                // Since we already initialized tsaListenAll above,
                // make a copy and uninit each one that isn't going to be managed
                // by the thread we are about to create
                for (int temp = 0; temp < 4; temp++)
                {
                    if (temp != threadindex)
                    {
                        tsaListen.set[temp].fValid = false;
                        tsaListen.set[temp].addr = CSocketAddress();
                    }
                }
               
                _threads[threadindex] = new CTCPStunThread();

                Chk(_threads[threadindex]->Init(tsaListen, tsaHandler, _spAuth, config.nMaxConnections, spLimiter));
            }
        }
    }
    
Cleanup:
    if (FAILED(hr))
    {
        Shutdown();
    }
    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;
    
}