📄 fping.c
字号:
/* * fping: fast-ping, file-ping, favorite-ping, funky-ping * * Ping a list of target hosts in a round robin fashion. * A better ping overall. * * VIEWING NOTES: * * This file was formatted with tab indents at a tab stop of 4. * * It is highly recommended that your editor is set to this * tab stop setting for viewing and editing. * * fping website: http://www.fping.com * * * * Current maintainers of fping: * * ZeroHype Technologies Inc. (http://www.zerohype.com) * Suggestions and patches, please email noc@zerohype.com * * * * Original author: Roland Schemers <schemers@stanford.edu> * * * * RCS header information no longer used. It has been moved to the * ChangeLog file. * * Redistribution and use in source and binary forms are permitted * provided that the above copyright notice and this paragraph are * duplicated in all such forms and that any documentation, * advertising materials, and other materials related to such * distribution and use acknowledge that the software was developed * by Stanford University. The name of the University may not be used * to endorse or promote products derived from this software without * specific prior written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. */#ifndef _NO_PROTO#if !__STDC__ && !defined( __cplusplus ) && !defined( FUNCPROTO ) \ && !defined( _POSIX_SOURCE )#define _NO_PROTO#endif /* __STDC__ */#endif /* _NO_PROTO */#ifdef __cplusplusextern "C"{#endif /* __cplusplus *//* if compiling for Windows, use this separate set (too difficult to ifdef all the autoconf defines) */#ifdef WIN32/*** Windows includes ***/#else/*** autoconf includes ***/#include <config.h>#include <stdio.h>#include <errno.h>#include <time.h>#include <signal.h>#ifdef HAVE_UNISTD_H#include <unistd.h>#endif /* HAVE_UNISTD_H */#ifdef HAVE_STDLIB_H#include <stdlib.h>#endif /* HAVE_STDLIB_H */#include <string.h>#include <stddef.h>#include <sys/types.h>#include <sys/time.h>#include <sys/socket.h>#if HAVE_SYS_FILE_H#include <sys/file.h>#endif /* HAVE_SYS_FILE_H */#include <netinet/in_systm.h>#include <netinet/in.h>/* Linux has bizarre ip.h and ip_icmp.h */#if defined( __linux__ )#include "linux.h"#else#include <netinet/ip.h>#include <netinet/ip_icmp.h>#endif /* defined(__linux__) */#include <arpa/inet.h>#include <netdb.h>/* RS6000 has sys/select.h */#ifdef HAVE_SYS_SELECT_H#include <sys/select.h>#endif /* HAVE_SYS_SELECT_H */#endif /* WIN32 */#include "options.h"/*** externals ***/extern char *optarg;extern int optind,opterr;extern int h_errno;#ifdef __cplusplus}#endif /* __cplusplus *//*** Constants ***/#define REV_DATE "2001/01/25 11:25:04"#define EMAIL "noc@zerohype.com"/*** Ping packet defines ***//* data added after ICMP header for our nefarious purposes */typedef struct ping_data{ int ping_count; /* counts up to -c count or 1 */ struct timeval ping_ts; /* time sent */} PING_DATA;#define MIN_PING_DATA sizeof( PING_DATA )#define MAX_IP_PACKET 65536 /* (theoretical) max IP packet size */#define SIZE_IP_HDR 20#define SIZE_ICMP_HDR ICMP_MINLEN /* from ip_icmp.h */#define MAX_PING_DATA ( MAX_IP_PACKET - SIZE_IP_HDR - SIZE_ICMP_HDR )/* sized so as to be like traditional ping */#define DEFAULT_PING_DATA_SIZE ( MIN_PING_DATA + 44 ) /* maxima and minima */#define MAX_COUNT 10000#define MIN_INTERVAL 10 /* in millisec */#define MIN_PERHOST_INTERVAL 20 /* in millisec */#define MIN_TIMEOUT 50 /* in millisec */#define MAX_RETRY 20/* response time array flags */#define RESP_WAITING -1#define RESP_UNUSED -2/* debugging flags */#if defined( DEBUG ) || defined( _DEBUG )#define DBG_TRACE 1#define DBG_SENT_TIMES 2#define DBG_RANDOM_LOSE_FEW 4#define DBG_RANDOM_LOSE_MANY 8#define DBG_PRINT_PER_SYSTEM 16#define DBG_REPORT_ALL_RTTS 32#endif /* DEBUG || _DEBUG *//* Long names for ICMP packet types */char *icmp_type_str[19] ={ "ICMP Echo Reply", /* 0 */ "", "", "ICMP Unreachable", /* 3 */ "ICMP Source Quench", /* 4 */ "ICMP Redirect", /* 5 */ "", "", "ICMP Echo", /* 8 */ "", "", "ICMP Time Exceeded", /* 11 */ "ICMP Paramter Problem", /* 12 */ "ICMP Timestamp Request", /* 13 */ "ICMP Timestamp Reply", /* 14 */ "ICMP Information Request", /* 15 */ "ICMP Information Reply", /* 16 */ "ICMP Mask Request", /* 17 */ "ICMP Mask Reply" /* 18 */};char *icmp_unreach_str[16] ={ "ICMP Network Unreachable", /* 0 */ "ICMP Host Unreachable", /* 1 */ "ICMP Protocol Unreachable", /* 2 */ "ICMP Port Unreachable", /* 3 */ "ICMP Unreachable (Fragmentation Needed)", /* 4 */ "ICMP Unreachable (Source Route Failed)", /* 5 */ "ICMP Unreachable (Destination Network Unknown)", /* 6 */ "ICMP Unreachable (Destination Host Unknown)", /* 7 */ "ICMP Unreachable (Source Host Isolated)", /* 8 */ "ICMP Unreachable (Communication with Network Prohibited)", /* 9 */ "ICMP Unreachable (Communication with Host Prohibited)", /* 10 */ "ICMP Unreachable (Network Unreachable For Type Of Service)", /* 11 */ "ICMP Unreachable (Host Unreachable For Type Of Service)", /* 12 */ "ICMP Unreachable (Communication Administratively Prohibited)", /* 13 */ "ICMP Unreachable (Host Precedence Violation)", /* 14 */ "ICMP Unreachable (Precedence cutoff in effect)" /* 15 */};#define ICMP_UNREACH_MAXTYPE 15/* entry used to keep track of each host we are pinging */typedef struct host_entry{ struct host_entry *prev,*next; /* doubly linked list */ int i; /* index into array */ char *name; /* name as given by user */ char *host; /* text description of host */ char *pad; /* pad to align print names */ struct sockaddr_in saddr; /* internet address */ int timeout; /* time to wait for response */ u_char running; /* unset when through sending */ u_char waiting; /* waiting for response */ struct timeval last_send_time; /* time of last packet sent */ int num_sent; /* number of ping packets sent */ int num_recv; /* number of pings received */ int max_reply; /* longest response time */ int min_reply; /* shortest response time */ int total_time; /* sum of response times */ int num_sent_i; /* number of ping packets sent */ int num_recv_i; /* number of pings received */ int max_reply_i; /* longest response time */ int min_reply_i; /* shortest response time */ int total_time_i; /* sum of response times */ int *resp_times; /* individual response times */#if defined( DEBUG ) || defined( _DEBUG ) int *sent_times; /* per-sent-ping timestamp */#endif /* DEBUG || _DEBUG */} HOST_ENTRY;/*** globals ***/HOST_ENTRY *rrlist = NULL; /* linked list of hosts be pinged */HOST_ENTRY **table = NULL; /* array of pointers to items in the list */HOST_ENTRY *cursor;char *prog;int ident; /* our pid */int s; /* socket */u_int debugging = 0;/* times get *100 because all times are calculated in 10 usec units, not ms */u_int retry = DEFAULT_RETRY;u_int timeout = DEFAULT_TIMEOUT * 100; u_int interval = DEFAULT_INTERVAL * 100;u_int perhost_interval = DEFAULT_PERHOST_INTERVAL * 100;float backoff = DEFAULT_BACKOFF_FACTOR;u_int select_time = DEFAULT_SELECT_TIME * 100;u_int ping_data_size = DEFAULT_PING_DATA_SIZE;u_int ping_pkt_size;u_int count = 1;u_int trials;u_int report_interval = 0;/* global stats */long max_reply = 0;long min_reply = 1000000;int total_replies = 0;double sum_replies = 0;int max_hostname_len = 0;int num_jobs = 0; /* number of hosts still to do */int num_hosts; /* total number of hosts */int num_alive = 0, /* total number alive */ num_unreachable = 0, /* total number unreachable */ num_noaddress = 0; /* total number of addresses not found */int num_timeout = 0, /* number of times select timed out */ num_pingsent = 0, /* total pings sent */ num_pingreceived = 0, /* total pings received */ num_othericmprcvd = 0; /* total non-echo-reply ICMP received */struct timeval current_time; /* current time (pseudo) */struct timeval start_time; struct timeval end_time;struct timeval last_send_time; /* time last ping was sent */struct timeval last_report_time; /* time last report was printed */struct timezone tz;/* switches */int generate_flag = 0; /* flag for IP list generation */int verbose_flag, quiet_flag, stats_flag, unreachable_flag, alive_flag;int elapsed_flag, version_flag, count_flag, loop_flag;int per_recv_flag, report_all_rtts_flag, name_flag, addr_flag, backoff_flag;int multif_flag;#if defined( DEBUG ) || defined( _DEBUG )int randomly_lose_flag, sent_times_flag, trace_flag, print_per_system_flag;int lose_factor;#endif /* DEBUG || _DEBUG */char *filename = NULL; /* file containing hosts to ping *//*** forward declarations ***/#ifdef _NO_PROTOvoid add_name();void add_addr();char *na_cat();char *cpystr();void crash_and_burn();void errno_crash_and_burn();char *get_host_by_address();int in_cksum();void u_sleep();int recvfrom_wto ();void remove_job();void send_ping();void usage();int wait_for_reply();long timeval_diff();void print_per_system_stats();void print_per_system_splits();void print_global_stats();void finish();int handle_random_icmp();char *sprint_tm();#elsevoid add_name( char *name );void add_addr( char *name, char *host, struct in_addr ipaddr );char *na_cat( char *name, struct in_addr ipaddr );char *cpystr( char *string );void crash_and_burn( char *message );void errno_crash_and_burn( char *message );char *get_host_by_address( struct in_addr in );int in_cksum( u_short *p, int n );void u_sleep( int u_sec );int recvfrom_wto ( int s, char *buf, int len, struct sockaddr *saddr, int timo );void remove_job( HOST_ENTRY *h );void send_ping( int s, HOST_ENTRY *h );long timeval_diff( struct timeval *a, struct timeval *b );void usage( void );int wait_for_reply( void );void print_per_system_stats( void );void print_per_system_splits( void );void print_global_stats( void );void finish();int handle_random_icmp( struct icmp *p, int psize, struct sockaddr_in *addr );char *sprint_tm( int t );#endif /* _NO_PROTO *//*** function definitions ***//************************************************************ Function: main************************************************************* Inputs: int argc, char** argv Description: Main program entry point************************************************************/#ifdef _NO_PROTOint main( argc, argv )int argc; char **argv;#elseint main( int argc, char **argv )#endif /* _NO_PROTO */{ int c, i, n; u_int lt, ht; int advance; struct protoent *proto; char *buf; uid_t uid; /* check if we are root */ if( geteuid() ) { fprintf( stderr, "This program can only be run by root, or it must be setuid root.\n" ); exit( 3 ); }/* IF */ /* confirm that ICMP is available on this machine */ if( ( proto = getprotobyname( "icmp" ) ) == NULL ) crash_and_burn( "icmp: unknown protocol" ); /* create raw socket for ICMP calls (ping) */ s = socket( AF_INET, SOCK_RAW, proto->p_proto ); if( s < 0 ) errno_crash_and_burn( "can't create raw socket" ); if( ( uid = getuid() ) ) { seteuid( getuid() ); }/* IF */ prog = argv[0]; ident = getpid() & 0xFFFF; verbose_flag = 1; backoff_flag = 1; opterr = 1; /* get command line options */ while( ( c = getopt( argc, argv, "gedhlmnqusaAvz:t:i:p:f:r:c:b:C:Q:B:" ) ) != EOF ) { switch( c ) { case 't': if( !( timeout = ( u_int )atoi( optarg ) * 100 ) ) usage(); break; case 'r': if( !( retry = ( u_int )atoi( optarg ) ) ) usage(); break; case 'i': if( !( interval = ( u_int )atoi( optarg ) * 100 ) ) usage(); break; case 'p': if( !( perhost_interval = ( u_int )atoi( optarg ) * 100 ) ) usage(); break; case 'c': if( !( count = ( u_int )atoi( optarg ) ) ) usage(); count_flag = 1; break; case 'C': if( !( count = ( u_int )atoi( optarg ) ) ) usage(); count_flag = 1; report_all_rtts_flag = 1; break; case 'b': if( !( ping_data_size = ( u_int )atoi( optarg ) ) ) usage(); break; case 'h': usage(); break; case 'q': verbose_flag = 0; quiet_flag = 1; break; case 'Q': verbose_flag = 0; quiet_flag = 1; if( !( report_interval = ( u_int )atoi( optarg ) * 100000 ) ) usage(); break; case 'e': elapsed_flag = 1; break; case 'm': multif_flag = 1; break; case 'd': case 'n': name_flag = 1; break; case 'A': addr_flag = 1; break; case 'B': if( !( backoff = atof( optarg ) ) ) usage(); break; case 's': stats_flag = 1; break; case 'l': loop_flag = 1; backoff_flag = 0; break; case 'u': unreachable_flag = 1; break; case 'a': alive_flag = 1; break;#if defined( DEBUG ) || defined( _DEBUG ) case 'z': if( ! ( debugging = ( u_int )atoi( optarg ) ) ) usage(); break;#endif /* DEBUG || _DEBUG */ case 'v': printf( "%s: Version %s $Date: %s $\n", argv[0], VERSION, REV_DATE ); printf( "%s: comments to %s\n", argv[0], EMAIL ); exit( 0 ); case 'f': #ifdef ENABLE_F_OPTION filename = optarg; generate_flag = 0; break;#else if( getuid() ) { printf( "%s: this option can only be used by root.\n", argv[0] ); printf( "%s: fping will read from stdin by default.\n", argv[0] ); exit( 3 ); }/* IF */ else { filename = optarg; generate_flag = 0; }/* ELSE */ break;#endif /* ENABLE_F_OPTION */ case 'g': /* use IP list generation */ /* mutually exclusive with using file input or command line targets */ generate_flag = 1; break; default: usage(); break; }/* SWITCH */ }/* WHILE */ /* validate various option settings */ if( unreachable_flag && alive_flag ) { fprintf( stderr, "%s: specify only one of a, u\n", argv[0] ); usage(); }/* IF */ if( count_flag && loop_flag ) { fprintf( stderr, "%s: specify only one of c, l\n", argv[0] ); usage(); }/* IF */ if( ( interval < MIN_INTERVAL * 100 || perhost_interval < MIN_PERHOST_INTERVAL * 100 || retry > MAX_RETRY || timeout < MIN_TIMEOUT * 100 ) && getuid() ) { fprintf( stderr, "%s: these options are too risky for mere mortals.\n", prog ); fprintf( stderr, "%s: You need i >= %u, p >= %u, r < %u, and t >= %u\n", prog, MIN_INTERVAL, MIN_PERHOST_INTERVAL, MAX_RETRY, MIN_TIMEOUT ); usage(); }/* IF */ if( ( ping_data_size > MAX_PING_DATA ) || ( ping_data_size < MIN_PING_DATA ) ) { fprintf( stderr, "%s: data size %u not valid, must be between %u and %u\n", prog, ping_data_size, MIN_PING_DATA, MAX_PING_DATA ); usage(); }/* IF */ if( ( backoff > MAX_BACKOFF_FACTOR ) || ( backoff < MIN_BACKOFF_FACTOR ) ) { fprintf( stderr, "%s: backoff factor %.1f not valid, must be between %.1f and %.1f\n", prog, backoff, MIN_BACKOFF_FACTOR, MAX_BACKOFF_FACTOR ); usage(); }/* IF */ if( count > MAX_COUNT ) { fprintf( stderr, "%s: count %u not valid, must be less than %u\n", prog, count, MAX_COUNT ); usage();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -