static char sccsid
[] = "@(#)ping.c 4.5 (Berkeley) %G%";
* Using the InterNet Control Message Protocol (ICMP) "ECHO" facility,
* measure round-trip-delays and packet loss across network paths.
* U. S. Army Ballistic Research Laboratory
* Modified at Uc Berkeley
* Public Domain. Distribution Unlimited.
* More statistics could always be gathered.
* This program has to run SUID to ROOT to access the ICMP socket.
#include <netinet/in_systm.h>
#include <netinet/ip_icmp.h>
#define MAXWAIT 10 /* max time to wait for response, sec. */
#define MAXPACKET 4096 /* max packet size */
#define MAXHOSTNAMELEN 64
u_char packet
[MAXPACKET
];
int s
; /* Socket file descriptor */
struct hostent
*hp
; /* Pointer to host info */
struct timezone tz
; /* leftover */
struct sockaddr whereto
;/* Who to ping */
int datalen
; /* How much data */
char usage
[] = "Usage: ping [-drv] host [data size] [npackets]\n";
char hnamebuf
[MAXHOSTNAMELEN
];
int ntransmitted
= 0; /* sequence # for outbound packets = #sent */
int nreceived
= 0; /* # of packets we got back */
int tsum
= 0; /* sum of all times, for doing average */
struct sockaddr_in
*to
= (struct sockaddr_in
*) &whereto
;
while (argc
> 0 && *av
[0] == '-') {
while (*++av
[0]) switch (*av
[0]) {
bzero( (char *)&whereto
, sizeof(struct sockaddr
) );
to
->sin_family
= AF_INET
;
to
->sin_addr
.s_addr
= inet_addr(av
[0]);
if (to
->sin_addr
.s_addr
!= -1) {
hp
= gethostbyname(av
[0]);
to
->sin_family
= hp
->h_addrtype
;
bcopy(hp
->h_addr
, (caddr_t
)&to
->sin_addr
, hp
->h_length
);
printf("%s: unknown host %s\n", argv
[0], av
[0]);
if (datalen
> MAXPACKET
) {
fprintf(stderr
, "ping: packet size too large\n");
if (datalen
>= sizeof(struct timeval
))
ident
= getpid() & 0xFFFF;
if ((proto
= getprotobyname("icmp")) == NULL
) {
fprintf(stderr
, "icmp: unknown protocol\n");
if ((s
= socket(AF_INET
, SOCK_RAW
, proto
->p_proto
)) < 0) {
setsockopt(s
, SOL_SOCKET
, SO_DEBUG
, &on
, sizeof(on
));
if (options
& SO_DONTROUTE
)
setsockopt(s
, SOL_SOCKET
, SO_DONTROUTE
, &on
, sizeof(on
));
printf("PING %s: %d data bytes\n", hostname
, datalen
);
signal( SIGINT
, finish
);
signal(SIGALRM
, catcher
);
catcher(); /* start things going */
int len
= sizeof (packet
);
int fromlen
= sizeof (from
);
if ( (cc
=recvfrom(s
, packet
, len
, 0, &from
, &fromlen
)) < 0) {
perror("ping: recvfrom");
pr_pack( packet
, cc
, &from
);
if (npackets
&& nreceived
>= npackets
)
* This routine causes another PING to be transmitted, and then
* schedules another SIGALRM for 1 second from now.
* Our sense of time will slowly skew (ie, packets will not be launched
* exactly at 1-second intervals). This does not affect the quality
* of the delay and loss statistics.
if (npackets
== 0 || ntransmitted
< npackets
)
waittime
= 2 * tmax
/ 1000;
* Compose and transmit an ICMP ECHO REQUEST packet. The IP packet
* will be added on by the kernel. The ID field is our UNIX process ID,
* and the sequence number is an ascending integer. The first 8 bytes
* of the data portion are used to hold a UNIX "timeval" struct in VAX
* byte-order, to compute the round-trip time.
static u_char outpack
[MAXPACKET
];
register struct icmp
*icp
= (struct icmp
*) outpack
;
register struct timeval
*tp
= (struct timeval
*) &outpack
[8];
register u_char
*datap
= &outpack
[8+sizeof(struct timeval
)];
icp
->icmp_type
= ICMP_ECHO
;
icp
->icmp_seq
= ntransmitted
++;
icp
->icmp_id
= ident
; /* ID */
cc
= datalen
+8; /* skips ICMP portion */
for( i
=8; i
<datalen
; i
++) /* skip 8 for time */
/* Compute ICMP checksum here */
icp
->icmp_cksum
= in_cksum( icp
, cc
);
/* cc = sendto(s, msg, len, flags, to, tolen) */
i
= sendto( s
, outpack
, cc
, 0, &whereto
, sizeof(struct sockaddr
) );
if( i
<0 ) perror("sendto");
printf("ping: wrote %s %d chars, ret=%d\n",
* Convert an ICMP "type" field to a printable string.
* Print out the packet, if it came from us. This logic is necessary
* because ALL readers of the ICMP socket get a copy of ALL ICMP packets
* which arrive ('tis only fair). This permits multiple copies of this
* program to be run without having intermingled output (or statistics!).
struct sockaddr_in
*from
;
register struct icmp
*icp
;
register long *lp
= (long *) packet
;
from
->sin_addr
.s_addr
= ntohl( from
->sin_addr
.s_addr
);
gettimeofday( &tv
, &tz
);
if (cc
< hlen
+ ICMP_MINLEN
) {
printf("packet too short (%d bytes) from %s\n", cc
,
inet_ntoa(ntohl(from
->sin_addr
.s_addr
)));
icp
= (struct icmp
*)(buf
+ hlen
);
if( icp
->icmp_type
!= ICMP_ECHOREPLY
) {
printf("%d bytes from %s: ", cc
,
inet_ntoa(ntohl(from
->sin_addr
.s_addr
)));
printf("icmp_type=%d (%s)\n",
icp
->icmp_type
, pr_type(icp
->icmp_type
) );
printf("x%2.2x: x%8.8x\n", i
*sizeof(long), *lp
++ );
printf("icmp_code=%d\n", icp
->icmp_code
);
if( icp
->icmp_id
!= ident
)
return; /* 'Twas not our ECHO */
tp
= (struct timeval
*)&icp
->icmp_data
[0];
printf("%d bytes from %s: ", cc
,
inet_ntoa(ntohl(from
->sin_addr
.s_addr
)));
printf("icmp_seq=%d. ", icp
->icmp_seq
);
triptime
= tv
.tv_sec
*1000+(tv
.tv_usec
/1000);
printf("time=%d. ms\n", triptime
);
* Checksum routine for Internet Protocol family headers (C Version)
register int nleft
= len
;
register u_short
*w
= addr
;
* Our algorithm is simple, using a 32 bit accumulator (sum),
* we add sequential 16 bit words to it, and at the end, fold
* back all the carry bits from the top 16 bits into the lower
/* mop up an odd byte, if necessary */
* add back carry outs from top 16 bits to low 16 bits
sum
= (sum
>> 16) + (sum
& 0xffff); /* add hi 16 to low 16 */
sum
+= (sum
>> 16); /* add carry */
answer
= ~sum
; /* truncate to 16 bits */
* Subtract 2 timeval structs: out = out - in.
* Out is assumed to be >= in.
register struct timeval
*out
, *in
;
if( (out
->tv_usec
-= in
->tv_usec
) < 0 ) {
out
->tv_sec
-= in
->tv_sec
;
* Print out statistics, and give up.
* Heavily buffered STDIO is used here, so that all the statistics
* will be written with 1 sys-write call. This is nice when more
* than one copy of the program is running on a terminal; it prevents
* the statistics output from becomming intermingled.
printf("\n----%s PING Statistics----\n", hostname
);
printf("%d packets transmitted, ", ntransmitted
);
printf("%d packets received, ", nreceived
);
printf("%d%% packet loss",
(int) (((ntransmitted
-nreceived
)*100) / ntransmitted
) );
printf("round-trip (ms) min/avg/max = %d/%d/%d\n",