📄 client.cpp
字号:
AddrLocal.sin_family = AF_INET;
AddrLocal.sin_addr.s_addr = INADDR_ANY;
AddrLocal.sin_port = 0;
//Bind 1 valid port and try to detect NAT characteristics.
for(i = 0; i < 4; i++)
{
log_on_error(sEcho = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP), "Creating echo socket", LAB_DONE);
log_on_error(setsockopt(sEcho,SOL_SOCKET,SO_REUSEADDR,(char *)&nOne,sizeof(nOne)), "Setting SO_REUSEADDR", LAB_DONE);
LAB_TRY_BIND:
if (AddrLocal.sin_port == 0)
{
AddrLocal.sin_port = htons(uwTryBindPort);
uwTryBindPort++;
}
log_on_error(bind(sEcho,(struct sockaddr *)&AddrLocal, nAddrLocalLen), "Binding to local address", LAB_BIND_ERR);
goto LAB_SOCK_READY;
LAB_BIND_ERR:
AddrLocal.sin_port = 0;
goto LAB_TRY_BIND;
LAB_SOCK_READY:
uwPortLocal[i] = ntohs(AddrLocal.sin_port);
XCheckConeTCPProbe(sServerLog, sEcho, i, &unAddrGlobal[i], &uwPortGlobal[i]);
#ifdef _WIN32
Sleep(50);
#else
XSleep(0, 50);
#endif
}
XAnalyzeNature(unAddrGlobal, uwPortGlobal, uwPortLocal, 4, PRO_TCP);
nErr = ERR_NONE;
LAB_DONE:
return nErr;
}
/***********************************************************************
* FUNCTION: XCheckConeTCPProbe()
* DESCRIPTION: This function try to connect to the echo service with different IP-PORT combinations and
* then get the public IP and port of the client.
* PARAMETERS: -> sServerLog: The STUNT server socket. This must be a valid socket connecting
* with STUNT server.
* -> sEcho: A echo socket created in XCheckConeTCP(). It will be used to connect to the
* echo service of STUNT server.
* -> nSeq: Test sequence number (0 ~ 4).
* <-> *punResAddr: The public address of the client returned from the STUNT server.
* <-> *puwResPort: The public port of the client returned from the STUNT server.
* RETURNED: N/A
* REVISION HISTORY:
***********************************************************************/
void XCheckConeTCPProbe(SOCKET sServerLog, SOCKET sEcho, INT32 nSeq, UINT32 *punResAddr, UINT16 *puwResPort)
{
struct sockaddr_in AddrEcho;
struct sockaddr_in AddrLocal;
#ifdef _WIN32
INT32 nAddrLocalLen = sizeof(AddrLocal);
#else
socklen_t nAddrLocalLen = sizeof(AddrLocal);
#endif
char chBuf[256];
Echo Rep;
//Using in macro by Saikat:
SOCKET sock_logr = sServerLog;
/////////////////////////////////////////////////////////////
//try 4 combinations of the echo service - IP1:Port1, IP1:Port2, IP2:Port1, IP2:Port2
AddrEcho.sin_family = AF_INET;
AddrEcho.sin_addr.s_addr = nSeq / 2 == 0 ? g_ServerInfo.nIP1 : g_ServerInfo.nIP2;
AddrEcho.sin_port = nSeq % 2 == 0 ? g_ServerInfo.wPort1 : g_ServerInfo.wPort2;
log_on_error(getsockname(sEcho,(struct sockaddr *)&AddrLocal, &nAddrLocalLen), "Resolving local address", LAB_DONE);
#ifdef _WIN32
_snprintf(chBuf, 256, "Sending TCP probe %d: %d.%d.%d.%d:%d => %d.%d.%d.%d:%d",
nSeq + 1,
IPPORT(AddrLocal.sin_addr.s_addr, AddrLocal.sin_port),
IPPORT(AddrEcho.sin_addr.s_addr, AddrEcho.sin_port)
);
#else
snprintf(chBuf, 256, "Sending TCP probe %d: %d.%d.%d.%d:%d => %d.%d.%d.%d:%d",
nSeq + 1,
IPPORT(AddrLocal.sin_addr.s_addr, AddrLocal.sin_port),
IPPORT(AddrEcho.sin_addr.s_addr, AddrEcho.sin_port)
);
#endif
log_on_error(connect(sEcho, (struct sockaddr *)&AddrEcho, sizeof(AddrEcho)), chBuf, LAB_DONE);
log_on_read_error(sEcho, &Rep, sizeof(Rep), "Reading server response", LAB_DONE);
#ifdef _WIN32
_snprintf(chBuf, 256, "PROBE TCP %d: %d.%d.%d.%d:%d (%d.%d.%d.%d:%d) => %d.%d.%d.%d:%d",
nSeq,
IPPORT(AddrLocal.sin_addr.s_addr, AddrLocal.sin_port),
IPPORT(Rep.nIP, Rep.wPort),
IPPORT(AddrEcho.sin_addr.s_addr, AddrEcho.sin_port)
);
#else
snprintf(chBuf, 256, "PROBE TCP %d: %d.%d.%d.%d:%d (%d.%d.%d.%d:%d) => %d.%d.%d.%d:%d",
nSeq,
IPPORT(AddrLocal.sin_addr.s_addr, AddrLocal.sin_port),
IPPORT(Rep.nIP, Rep.wPort),
IPPORT(AddrEcho.sin_addr.s_addr, AddrEcho.sin_port)
);
#endif
//Log the procedure on STUNT server
log1(sServerLog, "%s", chBuf);
//Return the result
*punResAddr = Rep.nIP;
*puwResPort = ntohs(Rep.wPort);
LAB_DONE:
close2(sEcho);
return;
}
/***********************************************************************
* FUNCTION: XAnalyzeNature()
* DESCRIPTION: This function analyzes the passed in IP:Port data and write the result on fingerprint
* PARAMETERS:
* -> *punAddrGlobal The pointer which points to a global (public) IP array.
* -> *puwPortGlobal The pointer which points to a global (public) Port array
* -> *puwPortLocal The pointer which points to a local (private) Port array
* <-> nTimes Test times. The value is also the size of the above arrays
* <-> nProtocol Always PRO_TCP in this library.
* RETURNED: N/A
* REVISION HISTORY:
***********************************************************************/
void XAnalyzeNature(UINT32 *punAddrGlobal, UINT16 *puwPortGlobal, UINT16 *puwPortLocal, INT32 nTimes, E_Protocol nProtocol)
{
INT32 nTmp = 0,
nTmp2[2][4],
i = 0,
nDelta = 0;
for (i = 0; i < nTimes; i++)
{
//?? seems impossible to be equal zero
if (g_Fingerprint.nGAddr == 0)
g_Fingerprint.nGAddr = punAddrGlobal[i];
// an abnormal result
if (punAddrGlobal[i] != g_Fingerprint.nGAddr)
{
g_Fingerprint.nGAddr = 0xFFFFFFFF;
break;
}
}
//Port Preserving : If Ports on local and NAT are the same in different connections
nTmp = 0;
for (i = 0; i < nTimes; i++)
{
if (puwPortLocal[i] == puwPortGlobal[i])
nTmp++;
}
if (nTmp > 1)
{
switch(nProtocol)
{
case PRO_TCP:
g_Fingerprint.TCP.bPortPreserving = 1;
break;
}
}
//NAT type: Cone or Symmetric is determined by the global port status.
for (i = 0; i < 4; i++)
{
INT32 j = 0;
for(j = 0; j < 2; j++)
{
nTmp2[j][i] = 0;
}
}
for (i = 1; i < nTimes; i++)
{
INT32 j = 0;
nTmp = puwPortGlobal[i] - puwPortGlobal[i-1];
if (nTmp < 0)
nTmp += 65536;
for(j = 0; j < 4; j++)
{
if (nTmp2[0][j] == nTmp)
{
nTmp2[1][j]++;
break;
}
}
if (j == 4)
{
for(j = 0; j < 4; j++)
{
if (nTmp2[1][j] == 0)
{
nTmp2[1][j]++;
nTmp2[0][j] = nTmp;
break;
}
}
}
}
nTmp = 0;
nDelta = 0xFFFFFFFF;
for(i = 0; i < 4; i++)
{
if (nTmp2[1][i] >= nTmp)
{
nTmp = nTmp2[1][i];
nDelta = nTmp2[0][i];
}
}
switch(nProtocol)
{
case PRO_TCP:
g_Fingerprint.TCP.nIncrement = (nTmp == 1) ? RANDOM_INCREMENT : nDelta;
break;
}
}
/***********************************************************************
* FUNCTION: XGenFingerprint()
* DESCRIPTION: This function interprets the binary fingerprint data to a readable string.
* PARAMETERS:
* <-> *pchPrint A buffer for storing the readable fingerprint string.
* -> nSize Size of the above string
* RETURNED: N/A
* REVISION HISTORY:
***********************************************************************/
void XGenFingerprint(CHAR *pchPrint, INT32 nSize)
{
strncpy(pchPrint, "", nSize);
strncat(pchPrint, "TCP ", nSize);
strncat(pchPrint, g_Fingerprint.TCP.bPortPreserving?"PORT-PRESERVING ":"NON-PORT-PRESERVING ", nSize);
if (g_Fingerprint.TCP.nIncrement == 0)
strncat(pchPrint, "CONE ",nSize);
else if (g_Fingerprint.TCP.nIncrement == RANDOM_INCREMENT)
strncat(pchPrint, "RANDOM-SYMMETRIC ",nSize);
else
#ifdef _WIN32
_snprintf(pchPrint+strlen(pchPrint), nSize-strlen(pchPrint), "DELTA-%d-SYMMETRIC ", g_Fingerprint.TCP.nIncrement);
#else
snprintf(pchPrint+strlen(pchPrint), nSize-strlen(pchPrint), "DELTA-%d-SYMMETRIC ", g_Fingerprint.TCP.nIncrement);
#endif
}
/***********************************************************************
* FUNCTION: XWriteFingerprint()
* DESCRIPTION: This function writes the NAT fingerprint to specified file on the local machine.
* 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 XWriteFingerprint(SOCKET sServerLog)
{
INT32 nFD = 0;
unlink(FINGERPRINT_FILE);
//Using in macro by Saikat:
SOCKET sock_logr = sServerLog;
/////////////////////////////////////////////////////////////
#ifdef _WIN32
log_on_error(nFD = _open(FINGERPRINT_FILE, O_WRONLY | O_BINARY | O_CREAT | O_TRUNC, S_IREAD | S_IWRITE), "Opening fingerprint file", LAB_DONE);
#else
log_on_error(nFD = open(FINGERPRINT_FILE, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR), "Opening fingerprint file", LAB_DONE);
#endif
log_on_error(write(nFD, &g_Fingerprint, sizeof(g_Fingerprint)) == sizeof(g_Fingerprint) ? 0 : -1, "Dumpting fingerprint to file", LAB_ERR);
LAB_DONE:
close(nFD);
return ERR_NONE;
LAB_ERR:
close(nFD);
return ERR_FAIL;
}
/***********************************************************************
* FUNCTION: XReadFingerprint()
* DESCRIPTION: This function read fingerprint file and write the data on the global
* fingerprint variable.
* PARAMETERS: N/A
* RETURNED: ERR_NONE: successful
* ERR_FAIL: failed
* REVISION HISTORY:
***********************************************************************/
INT32 XReadFingerprint(void)
{
INT32 nFD = 0;
INT32 nErr = ERR_NONE;
g_Fingerprint.chID[0] = '\0';
#ifdef _WIN32
nFD = _open(FINGERPRINT_FILE, O_RDONLY | O_BINARY);
#else
nFD = open(FINGERPRINT_FILE, O_RDONLY, S_IRUSR | S_IWUSR);
#endif
if (nFD == -1)
nErr = ERR_FAIL;
if (read(nFD, &g_Fingerprint, sizeof(g_Fingerprint)) != sizeof(g_Fingerprint))
nErr = ERR_FAIL;
//check build version
if (g_Fingerprint.nClientVer != BUILD_VER)
nErr = ERR_FAIL;
//check client ID
if (g_Fingerprint.chID[0] == '\0')
nErr = ERR_FAIL;
close(nFD);
if (nErr == ERR_FAIL)
{
unlink(FINGERPRINT_FILE);
strcpy(g_chClientID, g_Fingerprint.chID);
memset(&g_Fingerprint, 0, sizeof(g_Fingerprint));
}
return nErr;
}
/////////////////////////////////////////////////////////////////////////
//Utilities
/////////////////////////////////////////////////////////////////////////
/***********************************************************************
* FUNCTION: XInitSockAddr()
* DESCRIPTION: Initialize socket address.
* PARAMETERS: <-> *SockAddr: The socket address object needed to set.
* -> wfamily: Net family
* -> pchAddr: Socket address in string. Pass NULL if pass in converted data
* -> uwPort: Socket port
* -> unConvertedAddr: converted address
* -> uwConvertedPort: converted port
* RETURNED: always ERR_NONE
* REVISION HISTORY:
***********************************************************************/
INT32 XInitSockAddr(struct sockaddr_in *pSockAddr, INT16 wFamily, const CHAR * pchAddr, UINT16 uwPort, UINT32 unConvertedAddr, UINT16 uwConvertedPort)
{
if (pchAddr != NULL)
{
pSockAddr->sin_family = wFamily;
pSockAddr->sin_addr.s_addr = inet_addr(pchAddr);
pSockAddr->sin_port = htons(uwPort);
}
else
{
pSockAddr->sin_family = wFamily;
pSockAddr->sin_addr.s_addr = unConvertedAddr;
pSockAddr->sin_port = uwConvertedPort;
}
return ERR_NONE;
}
/***********************************************************************
* FUNCTION: XSleep()
* DESCRIPTION: A delay function.
* PARAMETERS: -> nSec: Time value, in seconds.
* -> nUsec: Time value, in microseconds
* RETURNED: N/A
* REVISION HISTORY:
***********************************************************************/
void XSleep(INT32 nSec, INT32 nUSec)
{
struct timeval tv;
fd_set s;
FD_ZERO(&s);
tv.tv_sec = nSec;
tv.tv_usec = nUSec;
select(0, NULL, NULL, NULL, &tv);
}
/***********************************************************************
* FUNCTION: XGetErrno()
* DESCRIPTION: Get errno in windows and lunux.
* PARAMETERS: N/A
* RETURNED: WIN_32: window socket error code
* o/w: errno
* REVISION HISTORY:
***********************************************************************/
INT32 XGetErrno(void)
{
#ifdef _WIN32
return (WSAGetLastError());
#else
return errno;
#endif
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -