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 + -
显示快捷键?