tracer.cpp
来自「用ICMP.DLL发送TCP/IP控制信息」· C++ 代码 · 共 291 行
CPP
291 行
///////////////////////////////////////////////////////////////////
// TRACER.CPP - implements the TRACER route trace utility.
// Author - Arnab Bhaduri
///////////////////////////////////////////////////////////////////
// Defines ////////////////////////////////////////////////////////
#define STRICT
#define NOGDI
// Includes ///////////////////////////////////////////////////////
#include <windows.h>
#include <stdio.h>
extern "C"
{
#include "ipexport.h"
#include "icmpapi.h"
}
// Data structures ////////////////////////////////////////////////
typedef struct PING_INFO
{
IPAddr addr; // target IP address
unsigned long avgRTT; // average round-trip time in ms
unsigned long status; // ICMP reply status
} PING_INFO, *PPING_INFO;
typedef struct PING_REPLY
{
ICMP_ECHO_REPLY icmpReply;
unsigned char msgData[8];
} PING_REPLY, *PPING_REPLY;
// Static data ////////////////////////////////////////////////////
static char gszBanner[] =
{ "\nTracer (IP route trace)\nAuthor - Arnab Bhaduri\n" };
static char gszUsage[] =
{
"Usage: %s [-d] [-g] [-h maximum_hops] [-w timeout] target_name\n\
\n\
-d do not resolve addresses to hostnames\n\
-g graph inter-node transmission times\n\
-h maximum_hops maximum number of hops to search for target\n\
-w timeout wait timeout in milliseconds for each reply\n"
};
static IPAddr addr = 0x00000000;
///////////////////////////////////////////////////////////////////
// SendEcho - implements the ICMP echo send/receive (ping)
///////////////////////////////////////////////////////////////////
DWORD SendEcho( IPAddr ipAddr, int nHops, DWORD dwTimeout,
PPING_INFO pInfo )
{
PING_REPLY reply;
IP_OPTION_INFORMATION info = { 0, 0, 0, 0, NULL };
int nCnt = 0;
HANDLE h = IcmpCreateFile();
if( h == INVALID_HANDLE_VALUE )
return GetLastError();
memset( &reply, 0, sizeof(reply) );
pInfo->avgRTT = 0;
// average 5 attempts to reduce fluctuation effects
for( int i = 0; i < 5; i++ )
{
info.Ttl = nHops;
DWORD dwRet = IcmpSendEcho( h, ipAddr, NULL, 0, &info, &reply,
sizeof(PING_REPLY), dwTimeout );
pInfo->addr = reply.icmpReply.Address;
pInfo->status = reply.icmpReply.Status;
// we use the data only if the request succeeded or expired
// in transit
if( (dwRet > 0) )
{
if( (reply.icmpReply.Status == IP_SUCCESS) ||
(reply.icmpReply.Status == IP_TTL_EXPIRED_TRANSIT) )
{
pInfo->avgRTT += reply.icmpReply.RoundTripTime;
nCnt++;
}
}
}
// compute the average round-trip time
if( nCnt > 0 )
pInfo->avgRTT /= nCnt;
else
pInfo->avgRTT = 0;
IcmpCloseHandle( h );
return nCnt;
}
///////////////////////////////////////////////////////////////////
// Main function for TRACER. Command-line processing and formatted
// output comprise most of the code.
///////////////////////////////////////////////////////////////////
int main( int argc, char *argv[] )
{
// set up defaults
BOOL bGraphTimes = FALSE;
BOOL bResolveAddrs = TRUE;
int nHops = 30;
DWORD dwTimeout = 5000;
printf( gszBanner );
if( argc < 2 )
{
printf( gszUsage, argv[0] );
return -1;
}
// init WinSock
WSADATA wsaData;
WORD wVersionRequested = MAKEWORD( 1, 1 );
if( WSAStartup(wVersionRequested, &wsaData) )
{
printf( "\nUnable to init network library.\n" );
return -1;
}
// process command line arguments
for( int i = 1; i < argc; i++ )
{
if( *argv[i] == '-' )
{
switch( toupper(*(argv[i] + 1)) )
{
case 'D':
bResolveAddrs = FALSE;
break;
case 'G':
bGraphTimes = TRUE;
break;
case 'H':
if( ++i == argc )
{
printf( "\nNumber of hops not specified.\n" );
return -2;
}
if( (sscanf(argv[i], "%d", &nHops) == 0) ||
nHops == 0 || nHops > 100 )
{
printf( "\nHops must be between 1 and 100\n" );
return -2;
}
break;
case 'W':
if( ++i == argc )
{
printf( "\nTimeout value not specified.\n" );
return -2;
}
if( sscanf(argv[i], "%d", &dwTimeout) == 0 ||
dwTimeout < 1000 || dwTimeout > 15000 )
{
printf( "\nTimeout must be 1000 - 15000 ms.\n" );
return -2;
}
break;
default:
printf( "\nInvalid option.\n" );
printf( gszUsage, argv[0] );
return -2;
}
continue;
}
// assume host name specified, get address
struct hostent *ph = gethostbyname( argv[i] );
if( ph )
addr = *( (IPAddr *)ph->h_addr_list[0] );
else
{
// assume host address specified
unsigned long a = inet_addr( argv[1] );
ph = gethostbyaddr( (char *)&a, 4, PF_INET );
if( ph )
addr = *( (IPAddr *) ph->h_addr_list[0] );
else
{
printf( "\nUnable to resolve target %s.\n", argv[i] );
return -3;
}
}
}
if( addr == 0 )
{
printf( "No target name specified." );
return -4;
}
// send an initial echo to estimate the total round-trip time
PING_INFO info;
unsigned long lastRTT = 0;
DWORD dwRet = SendEcho( addr, nHops, dwTimeout, &info );
if( dwRet == 0 )
{
printf( "Unable to contact target.\n" );
return -5;
}
// figure out the divisor to use for the "graph"
unsigned div = max( info.avgRTT / 50, 1 );
// print header
if( bGraphTimes )
printf( "\nHop Host IP Address RTT(ms)\n" );
else
printf( "\nHop Host IP Address RTT(ms)\tHost Name\n" );
// start route trace
for( i = 1; i <= nHops; i++ )
{
memset( &info, 0, sizeof(info) );
dwRet = SendEcho( addr, i, dwTimeout, &info );
if( bGraphTimes )
{
int cnt = info.avgRTT > lastRTT ?
(info.avgRTT - lastRTT)/(2*div) : 0;
printf( "\n--------------------------- " );
for( int j = 0; j < cnt; j++ )
printf( "X" );
if( cnt == 0 )
printf( "I" );
lastRTT = info.avgRTT;
}
unsigned char *pp = (unsigned char *) &info.addr;
char buffer[16];
if( *pp == 0 )
{
printf( "\n[%2.d] %-16.16s %4.4s", i, "*", "*" );
printf( "\t%s", "<request timed out>" );
}
else
{
sprintf( buffer, "%u.%u.%u.%u", pp[0], pp[1], pp[2], pp[3] );
printf( "\n[%2.d] %-16.16s ", i, buffer );
if( dwRet == 0 )
printf( "*" );
else if( info.avgRTT == 0 )
printf( "%4.4s", "<1" );
else printf( "%4.d", info.avgRTT );
if( !bGraphTimes && bResolveAddrs )
{
struct hostent *ph =
gethostbyaddr( (char *)&info.addr, 4, PF_INET );
printf( "\t%s", ph ? ph->h_name : "<unknown>" );
}
}
// if we reached the target then stop
if( addr == info.addr )
break;
}
WSACleanup();
return 0;
}
// End of file //
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?