📄 client.cpp
字号:
readtimeout(sCtrl, Socks, nTimeoutSec, LAB_ERR_TIMEOUT);
log_on_Xread_error(sCtrl, &AddrPeer.sin_addr.s_addr, sizeof(AddrPeer.sin_addr.s_addr), "Receiving address", LAB_ERR_RECEIVE);
readtimeout(sCtrl, Socks, nTimeoutSec, LAB_ERR_TIMEOUT);
log_on_Xread_error(sCtrl, &AddrPeer.sin_port, sizeof(AddrPeer.sin_port), "Receiving port", LAB_ERR_RECEIVE);
strncpy(errbuf, "HOLE", 128);
log_on_error(-1 == XTryConnect(sServerLog, sAuxServer, (struct sockaddr *)&AddrPeer, sizeof(AddrPeer), 1000) ? 0 : -1, "Opening hole", LAB_ERR_TRYCONNECT);
strncpy(errbuf, "OTHER", 128);
close2(sAuxServer);
log_on_error(sAuxServer = socket(PF_INET, SOCK_STREAM, 0), "Creating new socket", LAB_ERR_CREATE_SOCKET);
log_on_error(setsockopt(sAuxServer, SOL_SOCKET, SO_REUSEADDR, (char *)&nOne, sizeof(nOne)), "Setting REUSEADDR", LAB_ERR_SETSOCKOPT);
log_on_error(bind(sAuxServer, (struct sockaddr *)&AddrClient, sizeof(AddrClient)), "Binding to local address", LAB_ERR_BIND);
log_on_error(listen(sAuxServer, 1), "Listening on socket", LAB_ERR_LISTEN);
strncpy(errbuf, "CONTROL", 128);
log_on_Xwrite_error(sCtrl, &nOne, sizeof(nOne), "Ready", LAB_ERR_SEND);
//HairPin Problem: do not process
if (AddrGlobal.sin_addr.s_addr == AddrPeer.sin_addr.s_addr)
{
close2(sAuxServer);
return ERR_HAIRPIN;
}
//waiting for connection from XAsmServer: timeout MUST be the same as XAsmServer
readtimeout(sAuxServer, Socks, nTimeoutSec, LAB_ERR_ASYM_TIMEOUT);
strncpy(errbuf, "ACCEPT", 128);
log_on_error(*psConnect = accept(sAuxServer, (struct sockaddr *)&AddrPeer, &nAddrLen), "Accepting client", LAB_ERR_ACCEPT);
if (pAddrPeer != NULL)
{
pAddrPeer->sin_addr.s_addr = AddrPeer.sin_addr.s_addr;
pAddrPeer->sin_port = AddrPeer.sin_port;
}
close2(sAuxServer);
return ERR_NONE;
LAB_ERR_PREDICT:
close2(sAuxServer);
return ERR_PREDICT;
LAB_ERR_SEND:
close2(sAuxServer);
*pnErrCode = XGetErrno();
return ERR_SEND;
LAB_ERR_TIMEOUT:
close2(sAuxServer);
*pnErrCode = XGetErrno();
return ERR_TIMEOUT;
LAB_ERR_RECEIVE:
close2(sAuxServer);
*pnErrCode = XGetErrno();
return ERR_RECEIVE;
LAB_ERR_TRYCONNECT:
close2(sAuxServer);
*pnErrCode = XGetErrno();
return ERR_TRYCONNECT;
LAB_ERR_CREATE_SOCKET:
close2(sAuxServer);
*pnErrCode = XGetErrno();
return ERR_CREATE_SOCKET;
LAB_ERR_SETSOCKOPT:
close2(sAuxServer);
*pnErrCode = XGetErrno();
return ERR_SETSOCKOPT;
LAB_ERR_BIND:
close2(sAuxServer);
*pnErrCode = XGetErrno();
return ERR_SETSOCKOPT;
LAB_ERR_LISTEN:
close2(sAuxServer);
*pnErrCode = XGetErrno();
return ERR_LISTEN;
LAB_ERR_ASYM_TIMEOUT:
close2(sAuxServer);
*pnErrCode = XGetErrno();
return ERR_ASYM_TIMEOUT;
LAB_ERR_ACCEPT:
close2(sAuxServer);
*pnErrCode = XGetErrno();
return ERR_ACCEPT;
}
/***********************************************************************
* FUNCTION: XPredict()
* DESCRIPTION: This function predicts the global port that will be used in the next connection
* and return the socket with that global port number on NAT.
* PARAMETERS:
* -> sServerLog The STUNT server socket. This socket must be gotten from XInit()
* and be valid.
* <-> psAux A socket descriptor. It will be set to a valid socket bound on the
* local address: pAddrLocal and with a predicted port: pAddrGlobal on NAT.
* <-> pAddrGlobal The function will write the address with global predicted port for
* next connection.
* <-> pAddrLocal The function will randomly assign an address to this variable
* and bind it on psAux.
* RETURNED:
* ERR_NONE Successful.
* ERR_FAIL Failed in this function.
* REVISION HISTORY:
***********************************************************************/
INT32 XPredict(SOCKET sServerLog, SOCKET *psAux, struct sockaddr_in *pAddrGlobal, struct sockaddr_in *pAddrLocal)
{
SOCKET sEcho = (SOCKET) -1;
INT32 nOne = 1;
#ifdef _WIN32
INT32 nAddrLen = sizeof(struct sockaddr_in);
#else
socklen_t nAddrLen = sizeof(struct sockaddr_in);
#endif
UINT16 usGlobalPort = 0;
char chBuf[256];
#ifdef _WIN32
INT32 nStart = GetTickCount();
#else
struct timeb tStart, tCurrent;
INT32 nTimeInterval = 0;
ftime(&tStart);
#endif
//Using in macro by Saikat:
SOCKET sock_logr = sServerLog;
/////////////////////////////////////////////////////////////
pAddrLocal->sin_family = AF_INET;
pAddrLocal->sin_addr.s_addr = INADDR_ANY;
pAddrLocal->sin_port = 0;
log_on_error(sEcho = socket(PF_INET, SOCK_STREAM, 0), "Crearing prediction socket", LAB_ERR);
log_on_error(setsockopt(sEcho,SOL_SOCKET,SO_REUSEADDR,(char *)&nOne,sizeof(nOne)), "Setting SO_REUSEADDR", LAB_ERR);
log_on_error(bind(sEcho,(struct sockaddr *)pAddrLocal, sizeof(struct sockaddr_in)), "Binding to local address", LAB_ERR);
log_on_error(getsockname(sEcho,(struct sockaddr *)pAddrLocal, &nAddrLen), "Retreiving local address", LAB_ERR);
XCheckConeTCPProbe(sServerLog, sEcho, 1, (UINT32 *)&pAddrGlobal->sin_addr.s_addr, &usGlobalPort);
close2(sEcho);
log_on_error(sEcho = socket(PF_INET, SOCK_STREAM, 0), "Creating actual socket", LAB_ERR);
log_on_error(setsockopt(sEcho,SOL_SOCKET,SO_REUSEADDR,(char *)&nOne,sizeof(nOne)), "Setting SO_REUSEADDR", LAB_ERR);
log_on_error(bind(sEcho,(struct sockaddr *)pAddrLocal, sizeof(struct sockaddr_in)), "Binding to local address", LAB_ERR);
if (g_Fingerprint.TCP.nIncrement != RANDOM_INCREMENT)
{
usGlobalPort = (UINT16) (usGlobalPort + g_Fingerprint.TCP.nIncrement);
} else
{
// random. 1 is as good a random number as any
usGlobalPort = (UINT16) (usGlobalPort + 1);
}
pAddrGlobal->sin_port = ntohs(usGlobalPort);
#ifdef _WIN32
_snprintf(chBuf, 256, "PREDICT: %d.%d.%d.%d:%d -> %d.%d.%d.%d:%d [%dms]",
IPPORT(pAddrLocal->sin_addr.s_addr, pAddrLocal->sin_port),
IPPORT(pAddrGlobal->sin_addr.s_addr, pAddrGlobal->sin_port),
GetTickCount()-nStart
);
#else
ftime(&tCurrent);
nTimeInterval = (int) (1000.0 * (tCurrent.time - tStart.time)
+ (tCurrent.millitm - tStart.millitm));
snprintf(chBuf, 256, "PREDICT: %d.%d.%d.%d:%d -> %d.%d.%d.%d:%d [%dms]",
IPPORT(pAddrLocal->sin_addr.s_addr, pAddrLocal->sin_port),
IPPORT(pAddrGlobal->sin_addr.s_addr, pAddrGlobal->sin_port),
nTimeInterval
);
#endif
log1(sServerLog, "%s", chBuf);
*psAux = sEcho;
return ERR_NONE;
LAB_ERR:
close2(sEcho);
return ERR_FAIL;
}
/***********************************************************************
* FUNCTION: XTryConnect()
* DESCRIPTION: This function tries to make a connection to the destination peer.
* PARAMETERS:
* -> sServerLog The STUNT server socket. This socket must be gotten from XInit()
* and be valid.
* -> sAuxServer The socket for creating this connection.
* -> pAddrPeer Destination peer address.
* -> pAddPeerLen Length of pAddrPeer
* -> pMiliSec Timeout of this non-blocking connection
* RETURNED:
* ERR_NONE Successful.
* ERR_FAIL Failed in this function.
* REVISION HISTORY:
***********************************************************************/
INT32 XTryConnect(SOCKET sServerLog, SOCKET sAuxServer, struct sockaddr *pAddrPeer, INT32 nAddrPeerLen, INT32 nMiliSec)
{
struct sockaddr_in AnyAddr;
INT32 nRetVal = 0;
#ifdef _WIN32
OVERLAPPED OverLapped;
DWORD dwErr = 0;
DWORD dwBytes = 0;
LPFN_CONNECTEX lpfnConnectEx = NULL;
GUID GuidConnectEx = WSAID_CONNECTEX;
#else
fd_set Socks;
struct timeval Timeout;
#endif
//Using in macro by Saikat:
SOCKET sock_logr = sServerLog;
/////////////////////////////////////////////////////////////
AnyAddr.sin_family = AF_INET;
AnyAddr.sin_addr.s_addr = INADDR_ANY;
AnyAddr.sin_port = 0;
#ifdef _WIN32
memset(&OverLapped, 0, sizeof(OverLapped));
OverLapped.hEvent = CreateEvent(NULL, true, true, NULL);
dwErr = WSAIoctl(sAuxServer,
SIO_GET_EXTENSION_FUNCTION_POINTER,
&GuidConnectEx,
sizeof(GuidConnectEx),
&lpfnConnectEx,
sizeof(lpfnConnectEx),
&dwBytes,
NULL,
NULL);
if (dwErr == -1)
goto LAB_ERR;
bind(sAuxServer, (struct sockaddr *)&AnyAddr, sizeof(struct sockaddr_in));
dwErr = lpfnConnectEx(sAuxServer, pAddrPeer, nAddrPeerLen, NULL, 0, &dwBytes, &OverLapped);
if (dwErr == -1)
{
goto LAB_ERR;
}
if (WaitForSingleObject(OverLapped.hEvent, nMiliSec) == WAIT_TIMEOUT)
{
close2(sAuxServer);
WSASetLastError(WSAETIMEDOUT);
goto LAB_ERR;
}
nRetVal = GetOverlappedResult(OverLapped.hEvent, &OverLapped, &dwBytes, false);
if (!nRetVal)
{
switch(WSAGetLastError())
{
case 121: WSASetLastError(WSAETIMEDOUT); break;
case 1225: WSASetLastError(WSAECONNREFUSED); break;
default: log_on_error(-1, "GetOverlappedResult", LAB_ERR);
}
goto LAB_ERR;
}
return ERR_NONE;
#else
bind(sAuxServer, (struct sockaddr *)&AnyAddr, sizeof(struct sockaddr_in));
fcntl(sAuxServer, F_SETFL, O_NONBLOCK);
if (-1 == connect(sAuxServer, pAddrPeer, nAddrPeerLen))
{
if (errno != 115) //would block
goto LAB_ERR;
}
FD_ZERO(&Socks);
FD_SET(sAuxServer, &Socks);
Timeout.tv_sec = 1;
Timeout.tv_usec = 0;
nRetVal = select(((INT32)sAuxServer) + 1, NULL, &Socks, NULL, &Timeout);
if (nRetVal == 0 || nRetVal == -1) //Timeout or SOCKET_ERROR
goto LAB_ERR;
else
{
return ERR_NONE;
}
#endif
LAB_ERR:
return ERR_FAIL;
}
/***********************************************************************
* FUNCTION: XProbe()
* DESCRIPTION: This function will fetch the OS type, probe the NAT type of the client,
* generate/write the fingerprint, and send the result to the STUNT server.
* PARAMETERS: -> sServerLog: The STUNT server socket. This must be a valid socket connecting
* with STUNT server.
* RETURNED: ERR_NONE: successful
* ERR_FAIL: failed
* REVISION HISTORY:
***********************************************************************/
INT32 XProbe(SOCKET sServerLog)
{
#ifdef _WIN32
OSVERSIONINFOEX OSVer;
#endif
char chBuf[128];
char chPrint[MAX_FINGERPRINT_LEN];
INT32 nErr = ERR_FAIL;
#ifdef _WIN32
ZeroMemory(&OSVer, sizeof(OSVERSIONINFOEX));
OSVer.dwOSVersionInfoSize = sizeof (OSVERSIONINFOEX);
if( !GetVersionEx((OSVERSIONINFO *)&OSVer))
{
OSVer.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
if (!GetVersionEx((OSVERSIONINFO *)&OSVer))
{
//set all zeros
OSVer.dwPlatformId = 0;
OSVer.dwMajorVersion = 0;
OSVer.dwMinorVersion = 0;
OSVer.wServicePackMajor = 0;
OSVer.wServicePackMinor = 0;
}
}
_snprintf(chBuf, 128, "START %s: WIN32 %d.%d.%d.%d.%d, %s",
g_chClientID,
OSVer.dwPlatformId,
OSVer.dwMajorVersion,
OSVer.dwMinorVersion,
OSVer.wServicePackMajor,
OSVer.wServicePackMinor,
BUILD);
#else
snprintf(chBuf, 128, "START %s: NON_WIN32, %s", g_chClientID, BUILD);
#endif
log1(sServerLog, "%s", chBuf);
if (XProbeNAT(sServerLog) == ERR_FAIL)
{
nErr = ERR_FAIL;
}
else
{
g_Fingerprint.nServerVer = g_nServerVersion;
g_Fingerprint.nClientVer = BUILD_VER;
strcpy(g_Fingerprint.chID, g_chClientID);
g_Fingerprint.nDone = true;
XGenFingerprint(chPrint,MAX_FINGERPRINT_LEN);
log1(sServerLog, "FINGERPRINT: %s", chPrint);
g_Fingerprint.nGAddr = g_nClientIP;
if (XWriteFingerprint(sServerLog) == ERR_FAIL)
nErr = ERR_FAIL;
else
nErr = ERR_NONE;
}
if (nErr == ERR_FAIL)
{
g_Fingerprint.nDone = false;
}
return nErr;
}
/***********************************************************************
* FUNCTION: XProbeNAT()
* DESCRIPTION: This is a wrap of XCheckConeTCP(). It just controls the retry times and sleeping time.
* PARAMETERS: -> sServerLog: The STUNT server socket. This must be a valid socket connecting
* with STUNT server.
* RETURNED: ERR_NONE: successful
* ERR_FAIL: failed after all retries
* REVISION HISTORY:
***********************************************************************/
INT32 XProbeNAT(SOCKET sServerLog)
{
INT32 nRetry = 0;
if (XCheckConeTCP(sServerLog) == ERR_FAIL)
{
nRetry++;
#ifdef _WIN32
Sleep(PROBE_FAIL_SLEEP_SEC * 1000);
#else
XSleep(0, PROBE_FAIL_SLEEP_SEC * 1000);
#endif
if (nRetry == PROBE_RETRY_TIMES)
return ERR_FAIL;
}
return ERR_NONE;
}
/***********************************************************************
* FUNCTION: XCheckConeTCP()
* DESCRIPTION: This function check NAT's TCP port mapping characteristics. It's a wrap of
* XCheckConeTCPProbe() and XAnalyzeNature().
* PARAMETERS: -> sServerLog: The STUNT server socket. This must be a valid socket connecting
* with STUNT server.
* RETURNED: ERR_NONE: successful
* ERR_FAIL: failed
* REVISION HISTORY:
***********************************************************************/
INT32 XCheckConeTCP(SOCKET sServerLog)
{
SOCKET sEcho;
struct sockaddr_in AddrLocal;
INT32 nOne = 1;
INT32 i = 0;
INT32 nAddrLocalLen = sizeof(AddrLocal);
UINT16 uwTryBindPort = 1024;
UINT32 unAddrGlobal[4];
UINT16 uwPortLocal[4];
UINT16 uwPortGlobal[4];
INT32 nErr = ERR_FAIL;
//Using in macro by Saikat:
SOCKET sock_logr = sServerLog;
/////////////////////////////////////////////////////////////
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -