HRESULT CTestMessageHandler::ValidateMappedAddress(CStunMessageReader& reader, const CSocketAddress& addrExpected, bool fLegacyOnly) { HRESULT hr = S_OK; CSocketAddress addrMapped; CSocketAddress addrXorMapped; HRESULT hrResult; hrResult = reader.GetXorMappedAddress(&addrXorMapped); if (SUCCEEDED(hrResult)) { ChkIfA(false == addrExpected.IsSameIP_and_Port(addrXorMapped), E_FAIL); ChkIfA(fLegacyOnly, E_FAIL); // legacy responses should not include XOR mapped } else { ChkIfA(fLegacyOnly==false, E_FAIL); // non-legacy responses should include XOR Mapped address } ChkA(reader.GetMappedAddress(&addrMapped)); ChkIfA(false == addrExpected.IsSameIP_and_Port(addrMapped), E_FAIL); Cleanup: return hr; }
HRESULT 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; }
int CGSocket::Connect( LPCTSTR pszHostName, WORD wPort ) { CSocketAddress SockAddr; SockAddr.SetHostStr( pszHostName ); SockAddr.SetPort( wPort ); return( Connect( SockAddr )); }
HRESULT CTestClientLogic::Test1() { HRESULT hr = S_OK; HRESULT hrTmp = 0; CStunClientLogic clientlogic; ::StunClientLogicConfig config; CRefCountedBuffer spMsgOut(new CBuffer(MAX_STUN_MESSAGE_SIZE)); CRefCountedBuffer spMsgIn(new CBuffer(MAX_STUN_MESSAGE_SIZE)); StunClientResults results; StunTransactionId transid; CSocketAddress addrDest; CSocketAddress addrServerPP = CSocketAddress(0xaaaaaaaa, 1001); CSocketAddress addrLocal = CSocketAddress(0xdddddddd, 4444); CSocketAddress addrMapped = CSocketAddress(0xeeeeeeee, 5555); config.addrServer = addrServerPP; config.fBehaviorTest = false; config.fFilteringTest = false; config.timeoutSeconds = 10; config.uMaxAttempts = 2; config.fTimeoutIsInstant = false; ChkA(clientlogic.Initialize(config)); ChkA(clientlogic.GetNextMessage(spMsgOut, &addrDest, 0)); // we expect to get back a message for the serverPP ChkIfA(addrDest.IsSameIP_and_Port(addrServerPP)==false, E_UNEXPECTED); // check to make sure out timeout logic appears to work hrTmp = clientlogic.GetNextMessage(spMsgOut, &addrDest, 1); ChkIfA(hrTmp != E_STUNCLIENT_STILL_WAITING, E_UNEXPECTED); // now we should get a dupe of what we had before ChkA(clientlogic.GetNextMessage(spMsgOut, &addrDest, 11000)); // the message should be a binding request ChkA(ValidateBindingRequest(spMsgOut, &transid)); // now let's generate a response ChkA(GenerateBindingResponseMessage(addrMapped, transid, spMsgIn)); ChkA(clientlogic.ProcessResponse(spMsgIn, addrServerPP, addrLocal)); // results should be ready hrTmp = clientlogic.GetNextMessage(spMsgOut, &addrDest, 12000); ChkIfA(hrTmp != E_STUNCLIENT_RESULTS_READY, E_UNEXPECTED); ChkA(clientlogic.GetResults(&results)); // results should have a successful binding result ChkIfA(results.fBindingTestSuccess==false, E_UNEXPECTED); ChkIfA(results.fIsDirect, E_UNEXPECTED); ChkIfA(results.addrMapped.IsSameIP_and_Port(addrMapped)==false, E_UNEXPECTED); ChkIfA(results.addrLocal.IsSameIP_and_Port(addrLocal)==false, E_UNEXPECTED); Cleanup: return hr; }
HRESULT CStunMessageBuilder::AddMappedAddressImpl(uint16_t attribute, const CSocketAddress& addr) { uint16_t port; size_t length; uint8_t ip[STUN_IPV6_LENGTH]; HRESULT hr = S_OK; uint8_t family = (addr.GetFamily()==AF_INET) ? STUN_ATTRIBUTE_FIELD_IPV4 :STUN_ATTRIBUTE_FIELD_IPV6; size_t attributeSize = (family == STUN_ATTRIBUTE_FIELD_IPV4) ? STUN_ATTRIBUTE_MAPPEDADDRESS_SIZE_IPV4 : STUN_ATTRIBUTE_MAPPEDADDRESS_SIZE_IPV6; Chk(AddAttributeHeader(attribute, attributeSize)); port = addr.GetPort_NBO(); length = addr.GetIP_NBO(ip, sizeof(ip)); // if we ever had a length that was not a multiple of 4, we'd need to add padding ASSERT((length == STUN_IPV4_LENGTH) || (length == STUN_IPV6_LENGTH)); Chk(_stream.WriteUint8(0)); Chk(_stream.WriteUint8(family)); Chk(_stream.WriteUint16(port)); Chk(_stream.Write(ip, length)); Cleanup: return hr; }
HRESULT CTestClientLogic::GetMappedAddressForDestinationAddress(const CSocketAddress& addrDest, CSocketAddress* pAddrMapped) { HRESULT hr = S_OK; if (addrDest.IsSameIP_and_Port(_addrServerPP)) { *pAddrMapped = _addrMappedPP; } else if (addrDest.IsSameIP_and_Port(_addrServerPA)) { *pAddrMapped = _addrMappedPA; } else if (addrDest.IsSameIP_and_Port(_addrServerAP)) { *pAddrMapped = _addrMappedAP; } else if (addrDest.IsSameIP_and_Port(_addrServerAA)) { *pAddrMapped = _addrMappedAA; } else { ASSERT(false); hr = E_FAIL; } return hr; }
void CSocket::Connect(const CSocketAddress& addr) { int ret=::connect(m_s,&addr.getImp(),addr.getImpSize()); if(ret<0)throw connect_failed(L"connect failed"); current_address=addr; }
int CGSocket::Bind( const CSocketAddress & SockAddr ) { struct sockaddr_in SockAddrIn = SockAddr.GetAddrPort(); if ( SockAddr.IsLocalAddr()) { SockAddrIn.sin_addr.s_addr = INADDR_ANY; // use all addresses. } return( Bind( &SockAddrIn )); }
HRESULT CBasicBindingTest::ProcessResponse(CRefCountedBuffer& spMsg, CSocketAddress& addrRemote, CSocketAddress& addrLocal) { HRESULT hr = S_OK; CStunMessageReader reader; CSocketAddress addrMapped; CSocketAddress addrOther; bool fHasOtherAddress = false; // todo - figure out a way to make buffering TCP fragments work Chk(BasicReaderValidation(spMsg, reader)); hr = reader.GetXorMappedAddress(&addrMapped); if (FAILED(hr)) { hr = reader.GetMappedAddress(&addrMapped); } Chk(hr); // again drop the message if we can't parse the binding response fHasOtherAddress = SUCCEEDED(reader.GetOtherAddress(&addrOther)); // ok, we got a response. So we are done _fCompleted = true; _pResults->fBindingTestSuccess = true; _pResults->fIsDirect = addrLocal.IsSameIP_and_Port(addrMapped); _pResults->addrLocal = addrLocal; _pResults->addrMapped = addrMapped; _pResults->fHasOtherAddress = fHasOtherAddress; if (fHasOtherAddress) { _pResults->addrAA = addrOther; _pResults->addrPA = _pConfig->addrServer; _pResults->addrPA.SetPort(addrOther.GetPort()); _pResults->addrAP = addrOther; _pResults->addrAP.SetPort(_pConfig->addrServer.GetPort()); if (Logging::GetLogLevel() >= LL_DEBUG) { char sz[100]; addrOther.ToStringBuffer(sz, 100); Logging::LogMsg(LL_DEBUG, "Other address is %s\n",sz); } } Cleanup: return hr; }
//打开文件 void LogRequest(LPVOID pParam, char* pch, CSocketAddress sa) { //pParam参数保存了CListBox对象的指针 CString strList; CListBox* pList=(CListBox*)pParam; CString strGmt=CTime::GetCurrentTime().FormatGmt("%m/%d/%y %H:%M:%S GMT"); strList.Format("服务器连接 # %d ",g_nConnection); pList->AddString(strList); strList.Format(" IP地址:%s 端口:%d",sa.DottedDecimal(), sa.Port()); pList->AddString(strList); strList.Format(" 时间:%s",strGmt); pList->AddString(strList); strList.Format(" 请求:%s",pch); pList->AddString(strList); }
SOCKET CGSocket::Accept( CSocketAddress & SockAddr ) const { // RETURN: Error = hSocketClient < 0 || hSocketClient == INVALID_SOCKET struct sockaddr_in SockAddrIn; SOCKET hSocket = Accept( &SockAddrIn ); SockAddr.SetAddrPort( SockAddrIn ); return( hSocket ); }
HRESULT CBehaviorTest::ProcessResponse(CRefCountedBuffer& spMsg, CSocketAddress& addrRemote, CSocketAddress& addrLocal) { HRESULT hr = S_OK; CStunMessageReader reader; CSocketAddress addrMapped; Chk(BasicReaderValidation(spMsg, reader)); hr = reader.GetXorMappedAddress(&addrMapped); if (FAILED(hr)) { hr = reader.GetMappedAddress(&addrMapped); } Chk(hr); // again drop the message if we can't parse the binding response _fCompleted = true; if (_fIsTest3) { _pResults->addrMappingAA = addrMapped; _pResults->fBehaviorTestSuccess = true; if (addrMapped.IsSameIP_and_Port(_pResults->addrMappingAP)) { _pResults->behavior = ::AddressDependentMapping; } else { _pResults->behavior = ::AddressAndPortDependentMapping; } } else { _pResults->addrMappingAP = addrMapped; if (addrMapped.IsSameIP_and_Port(_pResults->addrMapped)) { _pResults->fBehaviorTestSuccess = true; _pResults->behavior = ::EndpointIndependentMapping; } } 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; }
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; }
SocketRole CTestClientLogic::GetSocketRoleForDestinationAddress(const CSocketAddress& addrDest) { if (addrDest.IsSameIP_and_Port(_addrServerPP)) { return RolePP; } else if (addrDest.IsSameIP_and_Port(_addrServerPA)) { return RolePA; } else if (addrDest.IsSameIP_and_Port(_addrServerAP)) { return RoleAP; } else if (addrDest.IsSameIP_and_Port(_addrServerAA)) { return RoleAA; } ASSERT(false); return RolePP; }
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()); } } }
bool CSocketAddress::IsSameIP_and_Port(const CSocketAddress& other) const { return (IsSameIP(other) && (GetPort() == other.GetPort()) ); }
HRESULT CStunThreadMessageHandler::ProcessBindingRequest(CStunMessageReader& reader) { HRESULT hrTmp; bool fRequestHasPaddingAttribute = false; SocketRole socketOutput = _message.localSocket; StunChangeRequestAttribute changerequest = {}; bool fSendOtherAddress = false; bool fSendOriginAddress = false; SocketRole socketOther; CSocketAddress addrOrigin; CSocketAddress addrOther; CStunMessageBuilder builder; uint16_t paddingSize = 0; bool fLegacyFormat = false; // set to true if the client appears to be rfc3489 based instead of based on rfc 5789 _spResponseBuffer->SetSize(0); builder.GetStream().Attach(_spResponseBuffer, true); fLegacyFormat = reader.IsMessageLegacyFormat(); // check for an alternate response port // check for padding attribute (todo - figure out how to inject padding into the response) // check for a change request and validate we can do it. If so, set _socketOutput. If not, fill out _error and return. // determine if we have an "other" address to notify the caller about // did the request come with a padding request if (SUCCEEDED(reader.GetPaddingAttributeSize(&paddingSize))) { // todo - figure out how we're going to get the MTU size of the outgoing interface fRequestHasPaddingAttribute = true; } // as per 5780, section 6.1, If the Request contained a PADDING attribute... // "If the Request also contains the RESPONSE-PORT attribute the server MUST return an error response of type 400." if (_fRequestHasResponsePort && fRequestHasPaddingAttribute) { _error.errorcode = STUN_ERROR_BADREQUEST; return E_FAIL; } // handle change request logic and figure out what "other-address" attribute is going to be if (SUCCEEDED(reader.GetChangeRequest(&changerequest))) { if (changerequest.fChangeIP) { socketOutput = SocketRoleSwapIP(socketOutput); } if(changerequest.fChangePort) { socketOutput = SocketRoleSwapPort(socketOutput); } // IsValidSocketRole just validates the enum, not whether or not we can send on it ASSERT(IsValidSocketRole(socketOutput)); // now, make sure we have the ability to send from another socket if (_spStunResponder->HasAddress(socketOutput) == false) { // send back an error. We're being asked to respond using another address that we don't have a socket for _error.errorcode = STUN_ERROR_BADREQUEST; return E_FAIL; } } // If we're only working one socket, then that's ok, we just don't send back an "other address" unless we have all four sockets confgiured // now here's a problem. If we binded to "INADDR_ANY", all of the sockets will have "0.0.0.0" for an address (same for IPV6) // So we effectively can't send back "other address" if don't really know our own IP address // Fortunately, recvfromex and the ioctls on the socket allow address discovery a bit better fSendOtherAddress = (_spStunResponder->HasAddress(RolePP) && _spStunResponder->HasAddress(RolePA) && _spStunResponder->HasAddress(RoleAP) && _spStunResponder->HasAddress(RoleAA)); if (fSendOtherAddress) { socketOther = SocketRoleSwapIP(SocketRoleSwapPort(_message.localSocket)); hrTmp = _spStunResponder->GetSocketAddressForRole(socketOther, &addrOther); ASSERT(SUCCEEDED(hrTmp)); // so if our ip address is "0.0.0.0", disable this attribute fSendOtherAddress = (SUCCEEDED(hrTmp) && (addrOther.IsIPAddressZero()==false)); } // What's our address origin? VERIFY(SUCCEEDED(_spStunResponder->GetSocketAddressForRole(socketOutput, &addrOrigin))); if (addrOrigin.IsIPAddressZero()) { // Since we're sending back from the IP address we received on, we can just use the address the message came in on // Otherwise, we don't actually know it if (socketOutput == _message.localSocket) { addrOrigin = _message.localAddr; } } fSendOriginAddress = (false == addrOrigin.IsIPAddressZero()); // Success - we're all clear to build the response _socketOutput = socketOutput; _spResponseBuffer->SetSize(0); builder.GetStream().Attach(_spResponseBuffer, true); builder.AddHeader(StunMsgTypeBinding, StunMsgClassSuccessResponse); builder.AddTransactionId(_transid); builder.AddMappedAddress(_message.remoteAddr); if (fLegacyFormat == false) { builder.AddXorMappedAddress(_message.remoteAddr); } if (fSendOriginAddress) { builder.AddResponseOriginAddress(addrOrigin); } if (fSendOtherAddress) { builder.AddOtherAddress(addrOther, fLegacyFormat); // pass true to send back CHANGED-ADDRESS, otherwise, pass false to send back OTHER-ADDRESS } // finally - if we're supposed to have a message integrity attribute as a result of authorization, add it at the very end if (_integrity.fSendWithIntegrity) { if (_integrity.fUseLongTerm == false) { builder.AddMessageIntegrityShortTerm(_integrity.szPassword); } else { builder.AddMessageIntegrityLongTerm(_integrity.szUser, _integrity.szRealm, _integrity.szPassword); } } builder.FixLengthField(); return S_OK; }
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; }
// 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; }
// Test2 - 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; CRefCountedBuffer spBuffer, spBufferOut(new CBuffer(MAX_STUN_MESSAGE_SIZE)); CStunMessageReader reader; StunMessageIn msgIn; StunMessageOut msgOut; TransportAddressSet tas = {}; uint16_t responsePort = 2222; StunChangeRequestAttribute changereq; CStunMessageReader::ReaderParseState state; CSocketAddress addrDestExpected; InitTransportAddressSet(tas, true, true, true, true); InitBindingRequest(builder); builder.AddResponsePort(responsePort); changereq.fChangeIP = true; changereq.fChangePort = true; builder.AddChangeRequest(changereq); builder.AddResponsePort(responsePort); builder.GetResult(&spBuffer); ChkIfA(CStunMessageReader::BodyValidated != reader.AddBytes(spBuffer->GetData(), spBuffer->GetSize()), E_FAIL); msgIn.fConnectionOriented = false; msgIn.addrLocal = _addrServerPP; msgIn.pReader = &reader; msgIn.socketrole = RolePP; msgIn.addrRemote = _addrMapped; msgOut.socketrole = RolePP; // deliberate initialized wrong msgOut.spBufferOut = spBufferOut; ChkA(CStunRequestHandler::ProcessRequest(msgIn, msgOut, &tas, NULL)); // parse the response reader.Reset(); state = reader.AddBytes(spBufferOut->GetData(), spBufferOut->GetSize()); ChkIfA(state != CStunMessageReader::BodyValidated, E_FAIL); // validate that the message was sent back from the AA ChkIfA(msgOut.socketrole != RoleAA, E_FAIL); // validate that the server though it was sending back from the AA ChkA(ValidateResponseOriginAddress(reader, _addrServerAA)); // validate that the message was sent to the response port requested addrDestExpected = _addrMapped; addrDestExpected.SetPort(responsePort); ChkIfA(addrDestExpected.IsSameIP_and_Port(msgOut.addrDest)==false, E_FAIL); // validate that the binding response came back ChkA(ValidateMappedAddress(reader, _addrMapped, false)); // the "other" address is still AA (See RFC 3489 - section 8.1) ChkA(ValidateOtherAddress(reader, _addrServerAA)); Cleanup: return hr; }
bool CSocketAddress::operator==( const CSocketAddress & SockAddr ) const { return( GetAddrIP() == SockAddr.GetAddrIP() && GetPort() == SockAddr.GetPort() ); }
int CGSocket::Connect( const CSocketAddress & SockAddr ) { struct sockaddr_in SockAddrIn = SockAddr.GetAddrPort(); return( Connect( &SockAddrIn )); }
HRESULT UdpClientLoop(StunClientLogicConfig& config, const ClientSocketConfig& socketconfig) { HRESULT hr = S_OK; CRefCountedStunSocket spStunSocket; CStunSocket stunSocket;; CRefCountedBuffer spMsg(new CBuffer(MAX_STUN_MESSAGE_SIZE)); int sock = -1; CSocketAddress addrDest; // who we send to CSocketAddress addrRemote; // who we CSocketAddress addrLocal; int ret; fd_set set; timeval tv = {}; std::string strAddr; std::string strAddrLocal; StunClientResults results; CStunClientLogic clientlogic; hr = clientlogic.Initialize(config); if (FAILED(hr)) { Logging::LogMsg(LL_ALWAYS, "Unable to initialize client: (error = x%x)", hr); Chk(hr); } hr = stunSocket.UDPInit(socketconfig.addrLocal, RolePP); if (FAILED(hr)) { Logging::LogMsg(LL_ALWAYS, "Unable to create local socket: (error = x%x)", hr); Chk(hr); } stunSocket.EnablePktInfoOption(true); sock = stunSocket.GetSocketHandle(); // let's get a loop going! while (true) { HRESULT hrRet; spMsg->SetSize(0); hrRet = clientlogic.GetNextMessage(spMsg, &addrDest, GetMillisecondCounter()); if (SUCCEEDED(hrRet)) { addrDest.ToString(&strAddr); ASSERT(spMsg->GetSize() > 0); if (Logging::GetLogLevel() >= LL_DEBUG) { std::string strAddr; addrDest.ToString(&strAddr); Logging::LogMsg(LL_DEBUG, "Sending message to %s", strAddr.c_str()); } ret = ::sendto(sock, spMsg->GetData(), spMsg->GetSize(), 0, addrDest.GetSockAddr(), addrDest.GetSockAddrLength()); if (ret <= 0) { Logging::LogMsg(LL_DEBUG, "ERROR. sendto failed (errno = %d)", errno); } // there's not much we can do if "sendto" fails except time out and try again } else if (hrRet == E_STUNCLIENT_STILL_WAITING) { Logging::LogMsg(LL_DEBUG, "Continuing to wait for response..."); } else if (hrRet == E_STUNCLIENT_RESULTS_READY) { break; } else { Logging::LogMsg(LL_DEBUG, "Fatal error (hr == %x)", hrRet); Chk(hrRet); } // now wait for a response spMsg->SetSize(0); FD_ZERO(&set); FD_SET(sock, &set); tv.tv_usec = 500000; // half-second tv.tv_sec = config.timeoutSeconds; ret = select(sock+1, &set, NULL, NULL, &tv); if (ret > 0) { ret = ::recvfromex(sock, spMsg->GetData(), spMsg->GetAllocatedSize(), MSG_DONTWAIT, &addrRemote, &addrLocal); if (ret > 0) { addrRemote.ToString(&strAddr); addrLocal.ToString(&strAddrLocal); Logging::LogMsg(LL_DEBUG, "Got response (%d bytes) from %s on interface %s", ret, strAddr.c_str(), strAddrLocal.c_str()); spMsg->SetSize(ret); clientlogic.ProcessResponse(spMsg, addrRemote, addrLocal); } } } results.Init(); clientlogic.GetResults(&results); DumpResults(config, results); Cleanup: return hr; }
HRESULT CTestClientLogic::TestBehaviorAndFiltering(bool fBehaviorTest, NatBehavior behavior, bool fFilteringTest, NatFiltering filtering) { HRESULT hr = S_OK; StunClientLogicConfig config; HRESULT hrRet; uint32_t time = 0; CRefCountedBuffer spMsgOut(new CBuffer(MAX_STUN_MESSAGE_SIZE)); CRefCountedBuffer spMsgResponse(new CBuffer(MAX_STUN_MESSAGE_SIZE)); SocketRole outputRole; CSocketAddress addrDummy; StunMessageIn stunmsgIn; StunMessageOut stunmsgOut; CSocketAddress addrDest; CSocketAddress addrMapped; CSocketAddress addrServerResponse; // what address the fake server responded back on StunClientResults results; StunTransactionId transid= {}; //std::string strAddr; ChkA(CommonInit(behavior, filtering)); config.addrServer = _addrServerPP; config.fBehaviorTest = fBehaviorTest; config.fFilteringTest = fFilteringTest; config.timeoutSeconds = 5; config.uMaxAttempts = 10; ChkA(_spClientLogic->Initialize(config)); while (true) { CStunMessageReader reader; bool fDropMessage = false; time += 1000; hrRet = _spClientLogic->GetNextMessage(spMsgOut, &addrDest, time); if (hrRet == E_STUNCLIENT_STILL_WAITING) { //printf("GetNextMessage returned 'still waiting'\n"); continue; } if (hrRet == E_STUNCLIENT_RESULTS_READY) { //printf("GetNextMessage returned 'results ready'\n"); break; } //addrDest.ToString(&strAddr); //printf("Client is sending stun packet to %s\n", strAddr.c_str()); ChkA(GetMappedAddressForDestinationAddress(addrDest, &addrMapped)); //addrMapped.ToString(&strAddr); //printf("Server is receiving stun packet from %s\n", strAddr.c_str()); ChkA(ValidateBindingRequest(spMsgOut, &transid)); // -------------------------------------------------- reader.AddBytes(spMsgOut->GetData(), spMsgOut->GetSize()); ChkIfA(reader.GetState() != CStunMessageReader::BodyValidated, E_UNEXPECTED); // Simulate sending the binding request and getting a response back stunmsgIn.socketrole = GetSocketRoleForDestinationAddress(addrDest); stunmsgIn.addrLocal = addrDest; stunmsgIn.addrRemote = addrMapped; stunmsgIn.fConnectionOriented = false; stunmsgIn.pReader = &reader; stunmsgOut.socketrole = (SocketRole)-1; // intentionally setting it wrong stunmsgOut.addrDest = addrDummy; // we don't care what address the server sent back to stunmsgOut.spBufferOut = spMsgResponse; spMsgResponse->SetSize(0); ChkA(::CStunRequestHandler::ProcessRequest(stunmsgIn, stunmsgOut, &_tsa, NULL)); // simulate the message coming back // make sure we got something! outputRole = stunmsgOut.socketrole; ChkIfA(::IsValidSocketRole(outputRole)==false, E_FAIL); ChkIfA(spMsgResponse->GetSize() == 0, E_FAIL); addrServerResponse = _tsa.set[stunmsgOut.socketrole].addr; // -------------------------------------------------- //addrServerResponse.ToString(&strAddr); //printf("Server is sending back from %s\n", strAddr.c_str()); // if the request went to PP, but came back from AA or AP, then it's likely a filtering test // decide if we need to drop the response fDropMessage = ( addrDest.IsSameIP_and_Port(_addrServerPP) && ( ((outputRole == RoleAA) && (_fAllowChangeRequestAA==false)) || ((outputRole == RolePA) && (_fAllowChangeRequestPA==false)) ) ); //{ // CStunMessageReader::ReaderParseState state; // CStunMessageReader readerDebug; // state = readerDebug.AddBytes(spMsgResponse->GetData(), spMsgResponse->GetSize()); // if (state != CStunMessageReader::BodyValidated) // { // printf("Error - response from server doesn't look valid"); // } // else // { // CSocketAddress addr; // readerDebug.GetMappedAddress(&addr); // addr.ToString(&strAddr); // printf("Response from server indicates our mapped address is %s\n", strAddr.c_str()); // } //} if (fDropMessage == false) { ChkA(_spClientLogic->ProcessResponse(spMsgResponse, addrServerResponse, _addrLocal)); } } // now validate the results results.Init(); // zero it out _spClientLogic->GetResults(&results); ChkIfA(results.behavior != behavior, E_UNEXPECTED); 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; }