tracert.c
来自「一个类似windows」· C语言 代码 · 共 720 行 · 第 1/2 页
C
720 行
else
{
_tprintf(_T("Unable to resolve target system name %s.\n"), cHostname);
WSACleanup();
exit(1);
}
}
else
{
dest.sin_addr.s_addr = addr;
dest.sin_family = AF_INET;
}
/* copy destination IP address into a string */
strcpy(cDestIP, inet_ntoa(dest.sin_addr));
}
/*
*
* Create our socket which will be used for sending and recieving,
* Socket Type is raw, Protocol is ICMP. Also set the TTL value which will be
* set in the outgoing IP packet.
*
*/
static INT Setup(INT iTTL)
{
INT iSockRet;
/* create raw socket */
icmpSock = WSASocket(AF_INET, SOCK_RAW, IPPROTO_ICMP, 0, 0, 0);
if (icmpSock == INVALID_SOCKET)
{
_tprintf(_T("Could not create socket : %d.\n"), WSAGetLastError());
if (WSAGetLastError() == WSAEACCES)
{
_tprintf(_T("\n\nYou must be an administrator to run this program!\n\n"));
WSACleanup();
exit(1);
}
return FALSE;
}
/* setup for TTL */
iSockRet = setsockopt(icmpSock, IPPROTO_IP, IP_TTL, (const char *)&iTTL, sizeof(iTTL));
if (iSockRet == SOCKET_ERROR)
{
_tprintf(_T("TTL setsockopt failed : %d. \n"), WSAGetLastError());
return FALSE;
}
return TRUE;
}
/*
* Prepare the ICMP echo request packet for sending.
* Calculate the packet checksum
*
*/
static VOID PreparePacket(INT iPacketSize, USHORT iSeqNum)
{
/* assemble ICMP echo request packet */
sendpacket.icmpheader.type = ECHO_REQUEST;
sendpacket.icmpheader.code = 0;
sendpacket.icmpheader.checksum = 0;
sendpacket.icmpheader.id = (USHORT)GetCurrentProcessId();
sendpacket.icmpheader.seq = iSeqNum;
/* calculate checksum of packet */
sendpacket.icmpheader.checksum = CheckSum((PUSHORT)&sendpacket, sizeof(ICMP_HEADER) + iPacketSize);
}
/*
*
* Get the system time and send the ICMP packet to the destination
* address.
*
*/
static INT SendPacket(INT datasize)
{
INT iSockRet;
INT iPacketSize;
iPacketSize = sizeof(ECHO_REPLY_HEADER) + datasize;
#ifdef DBG
_tprintf(_T("\nsending packet of %d bytes\n"), iPacketSize);
#endif /* DBG */
/* get time packet was sent */
lTimeStart = GetTime();
iSockRet = sendto(icmpSock, //socket
(char *)&sendpacket, //buffer
iPacketSize, //size of buffer
0, //flags
(SOCKADDR *)&dest, //destination
sizeof(dest)); //address length
if (iSockRet == SOCKET_ERROR)
{
if (WSAGetLastError() == WSAEACCES)
{
_tprintf(_T("\n\nYou must be an administrator to run this program!\n\n"));
WSACleanup();
exit(1);
}
else
{
#ifdef DBG
_tprintf(_T("sendto failed %d\n"), WSAGetLastError());
#endif /* DBG */
return FALSE;
}
}
#ifdef DBG
_tprintf(_T("sent %d bytes\n"), iSockRet);
#endif /* DBG */
/* return number of bytes sent */
return iSockRet;
}
/*
*
* Set up a timeout value and put the socket in a select poll.
* Wait until we recieve an IPv4 reply packet in reply to the ICMP
* echo request packet and get the time the packet was recieved.
* If we don't recieve a packet, do some checking to establish why.
*
*/
static INT ReceivePacket(INT datasize)
{
TIMEVAL timeVal;
FD_SET readFDS;
int iSockRet = 0, iSelRet;
int iFromLen;
int iPacketSize;
/* allow for a larger recv buffer to store ICMP TTL
* exceed, IP header and orginal ICMP request */
iPacketSize = MAX_REC_SIZE + datasize;
iFromLen = sizeof(source);
#ifdef DBG
_tprintf(_T("receiving packet. Available buffer, %d bytes\n"), iPacketSize);
#endif /* DBG */
/* monitor icmpSock for incomming connections */
FD_ZERO(&readFDS);
FD_SET(icmpSock, &readFDS);
/* set timeout values */
timeVal.tv_sec = iTimeOut / 1000;
timeVal.tv_usec = iTimeOut % 1000;
iSelRet = select(0, &readFDS, NULL, NULL, &timeVal);
if ((iSelRet != SOCKET_ERROR) && (iSelRet != 0))
{
iSockRet = recvfrom(icmpSock, //socket
(char *)&recvpacket, //buffer
iPacketSize, //size of buffer
0, //flags
(SOCKADDR *)&source, //source address
&iFromLen); //pointer to address length
/* get time packet was recieved */
lTimeEnd = GetTime();
/* if socket timed out */
}
else if (iSelRet == 0)
{
_tprintf(_T(" * "));
return 1;
}
else if (iSelRet == SOCKET_ERROR)
{
_tprintf(_T("select() failed in sendPacket() %d\n"), WSAGetLastError());
return -1;
}
if (iSockRet == SOCKET_ERROR)
{
_tprintf(_T("recvfrom failed: %d\n"), WSAGetLastError());
return -2;
}
#ifdef DBG
else
_tprintf(_T("reveived %d bytes\n"), iSockRet);
#endif /* DBG */
return 0;
}
/*
*
* Cast the IPv4 packet to an echo reply and to a TTL exceed.
* Check the 'type' field to establish what was recieved, and
* ensure the packet is related to the originating process.
* It all is well, print the time taken for the round trip.
*
*/
static INT DecodeResponse(INT iPacketSize, USHORT iSeqNum)
{
unsigned short header_len = recvpacket.h_len * 4;
/* cast the recieved packet into an ECHO reply and a TTL Exceed so we can check the ID*/
ECHO_REPLY_HEADER *IcmpHdr = (ECHO_REPLY_HEADER *)((char*)&recvpacket + header_len);
TTL_EXCEED_HEADER *TTLExceedHdr = (TTL_EXCEED_HEADER *)((char *)&recvpacket + header_len);
/* Make sure the reply is ok */
if (iPacketSize < header_len + ICMP_MIN_SIZE)
{
_tprintf(_T("too few bytes from %s\n"), inet_ntoa(dest.sin_addr));
return -2;
}
switch (IcmpHdr->icmpheader.type)
{
case TTL_EXCEEDED :
if (TTLExceedHdr->OrigIcmpHeader.id != (USHORT)GetCurrentProcessId())
{
/* FIXME */
/* we've picked up a packet not related to this process
* probably from another local program. We ignore it */
#ifdef DGB
_tprintf(_T("header id, process id %d"), TTLExceedHdr->OrigIcmpHeader.id, GetCurrentProcessId());
#endif /* DBG */
//_tprintf(_T("oops ");
return -1;
}
_tprintf(_T("%3Ld ms"), (lTimeEnd - lTimeStart) / TicksPerMs.QuadPart);
return 0;
case ECHO_REPLY :
if (IcmpHdr->icmpheader.id != (USHORT)GetCurrentProcessId())
{
/* FIXME */
/* we've picked up a packet not related to this process
* probably from another local program. We ignore it */
#ifdef DGB
_tprintf(_T("\nPicked up wrong packet. icmpheader.id = %d and process id = %d"), IcmpHdr->icmpheader.id, GetCurrentProcessId());
#endif /* DBG */
//_tprintf(_T("oops ");
return -1;
}
_tprintf(_T("%3Ld ms"), (lTimeEnd - lTimeStart) / TicksPerMs.QuadPart);
return 1;
case DEST_UNREACHABLE :
_tprintf(_T(" * "));
return 2;
default :
/* unknown ICMP packet */
return -3;
}
}
/*
*
* Get the system time using preformance counters if available,
* otherwise fall back to GetTickCount()
*
*/
static LONGLONG GetTime(VOID)
{
LARGE_INTEGER Time;
if (bUsePerformanceCounter)
{
if (QueryPerformanceCounter(&Time) == 0)
{
Time.u.LowPart = (DWORD)GetTickCount();
Time.u.HighPart = 0;
return (LONGLONG)Time.u.LowPart;
}
}
else
{
Time.u.LowPart = (DWORD)GetTickCount();
Time.u.HighPart = 0;
return (LONGLONG)Time.u.LowPart;
}
return Time.QuadPart;
}
/*
*
* Calculate packet checksum.
*
*/
static WORD CheckSum(PUSHORT data, UINT size)
{
DWORD dwSum = 0;
while (size > 1)
{
dwSum += *data++;
size -= sizeof(USHORT);
}
if (size)
dwSum += *(UCHAR*)data;
dwSum = (dwSum >> 16) + (dwSum & 0xFFFF);
dwSum += (dwSum >> 16);
return (USHORT)(~dwSum);
}
/*
*
* print program usage to screen
*
*/
static VOID Usage(VOID)
{
_tprintf(_T("\nUsage: tracert [-d] [-h maximum_hops] [-j host-list] [-w timeout] target_name\n\n"
"Options:\n"
" -d Do not resolve addresses to hostnames.\n"
" -h maximum_hops Maximum number of hops to search for target.\n"
" -j host-list Loose source route along host-list.\n"
" -w timeout Wait timeout milliseconds for each reply.\n\n"));
/* temp notes to stop user questions until getnameinfo/gethostbyaddr and getsockopt are implemented */
_tprintf(_T("NOTES\n-----\n"
"- Setting TTL values is not currently supported in ReactOS, so the trace will\n"
" jump straight to the destination. This feature will be implemented soon.\n"
"- Host info is not currently available in ReactOS and will fail with strange\n"
" results. Use -d to force it not to resolve IP's.\n"
"- For testing purposes, all should work as normal in a Windows environment\n\n"));
}
/*
*
* Program entry point
*
*/
int main(int argc, char* argv[])
{
if (!ParseCmdline(argc, argv)) return -1;
Driver();
return 0;
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?