tracert.c
来自「一个类似windows」· C语言 代码 · 共 720 行 · 第 1/2 页
C
720 行
/*
* ReactOS Win32 Applications
* Copyright (C) 2005 ReactOS Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS traceroute utility
* FILE: apps/utils/net/tracert/tracert.c
* PURPOSE: trace a packets route through a network
* PROGRAMMERS: Ged Murphy (gedmurphy@gmail.com)
* REVISIONS:
* GM 03/05/05 Created
*
*/
#include <winsock2.h>
#include <tchar.h>
#include <stdio.h>
#include <stdlib.h>
#include <ws2tcpip.h>
#include <string.h>
#include <time.h>
#include "tracert.h"
#define WIN32_LEAN_AND_MEAN
#ifdef DBG
#undef DBG
#endif
/*
* globals
*/
SOCKET icmpSock; // socket descriptor
SOCKADDR_IN source, dest; // source and destination address info
ECHO_REPLY_HEADER sendpacket; // ICMP echo packet
IPv4_HEADER recvpacket; // return reveive packet
BOOL bUsePerformanceCounter; // whether to use the high res performance counter
LARGE_INTEGER TicksPerMs; // number of millisecs in relation to proc freq
LARGE_INTEGER TicksPerUs; // number of microsecs in relation to proc freq
LONGLONG lTimeStart; // send packet, timer start
LONGLONG lTimeEnd; // receive packet, timer end
CHAR cHostname[256]; // target hostname
CHAR cDestIP[18]; // target IP
/*
* command line options
*/
BOOL bResolveAddresses = TRUE; // -d MS ping defaults to true.
INT iMaxHops = 30; // -h Max number of hops before trace ends
INT iHostList; // -j @UNIMPLEMENTED@
INT iTimeOut = 2000; // -w time before packet times out
/*
*
* Parse command line parameters and set any options
*
*/
static BOOL ParseCmdline(int argc, char* argv[])
{
int i;
if (argc < 2)
{
Usage();
return FALSE;
}
for (i = 1; i < argc; i++)
{
if (argv[i][0] == '-')
{
switch (argv[i][1])
{
case 'd': bResolveAddresses = FALSE;
break;
case 'h': sscanf(argv[i+1], "%d", &iMaxHops);
break;
case 'j': break; /* @unimplemented@ */
case 'w': sscanf(argv[i+1], "%d", &iTimeOut);
break;
default:
_tprintf(_T("%s is not a valid option.\n"), argv[i]);
Usage();
return FALSE;
}
}
else
/* copy target address */
strncpy(cHostname, argv[i], 255);
}
return TRUE;
}
/*
*
* Driver function, controls the traceroute program
*
*/
static INT Driver(VOID)
{
INT iHopCount = 1; // hop counter. default max is 30
USHORT iSeqNum = 0; // initialise packet sequence number
INT iTTL = 1; // set initial packet TTL to 1
BOOL bFoundTarget = FALSE; // Have we reached our destination yet
BOOL bAwaitPacket; // indicates whether we have recieved a good packet
INT iDecRes; // DecodeResponse return value
INT iRecieveReturn; // RecieveReturn return value
INT iNameInfoRet; // getnameinfo return value
INT iPacketSize = PACKET_SIZE; // packet size
WORD wHeaderLen; // header length
PECHO_REPLY_HEADER icmphdr;
//temps for getting host name
CHAR cHost[256];
CHAR cServ[256];
CHAR *ip;
/* setup winsock */
WSADATA wsaData;
/* check for winsock 2 */
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
{
#ifdef DBG
_tprintf(_T("WSAStartup failed.\n"));
#endif /* DBG */
exit(1);
}
/* establish what timing method we can use */
SetupTimingMethod();
/* setup target info */
ResolveHostname();
/* print standard tracing info to screen */
_tprintf(_T("\nTracing route to %s [%s]\n"), cHostname, cDestIP);
_tprintf(_T("over a maximum of %d hop"), iMaxHops);
iMaxHops > 1 ? _tprintf(_T("s:\n\n")) : _tprintf(_T(":\n\n"));
/* run until we hit either max hops, or we recieve 3 echo replys */
while ((iHopCount <= iMaxHops) && (bFoundTarget != TRUE))
{
INT i;
_tprintf(_T("%3d "), iHopCount);
/* run 3 pings for each hop */
for (i=0; i<3; i++)
{
if (Setup(iTTL) != TRUE)
{
#ifdef DBG
_tprintf(_T("error in Setup()\n"));
#endif /* DBG */
WSACleanup();
exit(1);
}
PreparePacket(iPacketSize, iSeqNum);
if (SendPacket(iPacketSize) != SOCKET_ERROR)
{
/* loop until we get a good packet */
bAwaitPacket = TRUE;
while (bAwaitPacket)
{
/* Receive replies until we either get a successful
* read, or a fatal error occurs. */
if ((iRecieveReturn = ReceivePacket(iPacketSize)) < 0)
{
/* check the sequence number in the packet
* if it's bad, complain and wait for another packet
* , otherwise break */
wHeaderLen = recvpacket.h_len * 4;
icmphdr = (ECHO_REPLY_HEADER *)((char*)&recvpacket + wHeaderLen);
if (icmphdr->icmpheader.seq != iSeqNum)
{
_tprintf(_T("bad sequence number!\n"));
continue;
}
else
break;
}
/* if RecievePacket timed out we don't bother decoding */
if (iRecieveReturn != 1)
{
iDecRes = DecodeResponse(iPacketSize, iSeqNum);
switch (iDecRes)
{
case 0 : bAwaitPacket = FALSE; /* time exceeded */
break;
case 1 : bAwaitPacket = FALSE; /* echo reply */
break;
case 2 : bAwaitPacket = FALSE; /* destination unreachable */
break;
#ifdef DBG
case -1 :
_tprintf(_T("recieved foreign packet\n"));
break;
case -2 :
_tprintf(_T("error in DecodeResponse\n"));
break;
case -3 :
_tprintf(_T("unknown ICMP packet\n"));
break;
#endif /* DBG */
default : break;
}
}
else
/* packet timed out. Don't wait for it again */
bAwaitPacket = FALSE;
}
}
iSeqNum++;
_tprintf(_T(" "));
}
if(bResolveAddresses)
{
/* gethostbyaddr() and getnameinfo() are
* unimplemented in ROS at present.
* Alex has advised he will be implementing getnameinfo.
* I've used that for the time being for testing in Windows*/
//ip = inet_addr(inet_ntoa(source.sin_addr));
//host = gethostbyaddr((char *)&ip, 4, 0);
ip = inet_ntoa(source.sin_addr);
iNameInfoRet = getnameinfo((SOCKADDR *)&source,
sizeof(SOCKADDR),
cHost,
256,
cServ,
256,
NI_NUMERICSERV);
if (iNameInfoRet == 0)
{
/* if IP address resolved to a hostname,
* print the IP address after it */
if (lstrcmpA(cHost, ip) != 0)
_tprintf(_T("%s [%s]"), cHost, ip);
else
_tprintf(_T("%s"), cHost);
}
else
{
_tprintf(_T("error: %d"), WSAGetLastError());
#ifdef DBG
_tprintf(_T(" getnameinfo failed: %d"), iNameInfoRet);
#endif /* DBG */
}
}
else
_tprintf(_T("%s"), inet_ntoa(source.sin_addr));
_tprintf(_T("\n"));
/* check if we've arrived at the target */
if (strcmp(cDestIP, inet_ntoa(source.sin_addr)) == 0)
bFoundTarget = TRUE;
else
{
iTTL++;
iHopCount++;
Sleep(500);
}
}
_tprintf(_T("\nTrace complete.\n"));
WSACleanup();
return 0;
}
/*
* Establish if performance counters are available and
* set up timing figures in relation to processor frequency.
* If performance counters are not available, we'll be using
* gettickcount, so set the figures to 1
*
*/
static VOID SetupTimingMethod(VOID)
{
LARGE_INTEGER PerformanceCounterFrequency;
/* check if performance counters are available */
bUsePerformanceCounter = QueryPerformanceFrequency(&PerformanceCounterFrequency);
if (bUsePerformanceCounter)
{
/* restrict execution to first processor on SMP systems */
if (SetThreadAffinityMask(GetCurrentThread(), 1) == 0)
bUsePerformanceCounter = FALSE;
TicksPerMs.QuadPart = PerformanceCounterFrequency.QuadPart / 1000;
TicksPerUs.QuadPart = PerformanceCounterFrequency.QuadPart / 1000000;
}
if (!bUsePerformanceCounter)
{
TicksPerMs.QuadPart = 1;
TicksPerUs.QuadPart = 1;
}
}
/*
*
* Check for a hostname or dotted deciamal for our target.
* If we have a hostname, resolve to an IP and store it, else
* just store the target IP address. Also set up other key
* SOCKADDR_IN members needed for the connection.
*
*/
static VOID ResolveHostname(VOID)
{
HOSTENT *hp;
ULONG addr;
memset(&dest, 0, sizeof(dest));
addr = inet_addr(cHostname);
/* if address is not a dotted decimal */
if (addr == INADDR_NONE)
{
hp = gethostbyname(cHostname);
if (hp != 0)
{
memcpy(&dest.sin_addr, hp->h_addr, hp->h_length);
//dest.sin_addr = *((struct in_addr *)hp->h_addr);
dest.sin_family = hp->h_addrtype;
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?