|
|
@@ -0,0 +1,1622 @@ |
|
|
|
|
|
# This is a shell archive. Remove anything before this line, then |
|
|
# unpack it by saving it in a file and typing "sh file". (Files |
|
|
# unpacked will be owned by you and have default permissions.) |
|
|
# |
|
|
# This archive contains: |
|
|
# Makefile ping.1 ping.c ping.shar newping.1 newping.c |
|
|
|
|
|
echo x - Makefile |
|
|
cat > "Makefile" << '//E*O*F Makefile//' |
|
|
# Revised to compile under SunOS 4.1.x (no longer necessary to install |
|
|
# kernel mods). 08/07/92 RJRJr This makefile is based on the original |
|
|
# makefiles supplied with tcpdump and traceroute. |
|
|
|
|
|
# Set DESTDIR to the directory in which the traceroute executable will be |
|
|
# installed. /usr/etc is a good place to put a network debugging tool such |
|
|
# as this. |
|
|
|
|
|
DESTDIR= /usr/brl/sbin |
|
|
MANDIR= /usr/brl/man/man1 |
|
|
|
|
|
# You shouldn't need to change anything below this line. |
|
|
|
|
|
CC= cc |
|
|
CFLAGS = -O |
|
|
|
|
|
# At the moment, the INCL variable isn't really needed for anything. |
|
|
INCL = -I. |
|
|
LIBS = |
|
|
|
|
|
# Script (or program) that returns the machine and os types, |
|
|
# or just edit in the name yourself. |
|
|
MD=`mdtype` |
|
|
OS=`ostype` |
|
|
|
|
|
# Explicitly define compiliation rule since SunOS 4's make doesn't like gcc. |
|
|
# Also, gcc does not remove the .o before forking 'as', which can be a |
|
|
# problem if you don't own the file but can write to the directory. |
|
|
.c.o: |
|
|
rm -f $@; $(CC) $(CFLAGS) -c $*.c |
|
|
|
|
|
all: submake |
|
|
|
|
|
ping: ping.o |
|
|
$(CC) $(CFLAGS) $(INCL) -o ping ping.o $(LIBS) |
|
|
|
|
|
submake: |
|
|
-@dir=$(MD)-$(OS); set -x; \ |
|
|
if [ ! -d $$dir ]; then ${MAKE} ${MFLAGS} config; fi; \ |
|
|
if [ -n "`find Makefile -newer $$dir/Makefile -print`" ]; \ |
|
|
then ${MAKE} ${MFLAGS} config; fi; \ |
|
|
cd $$dir; ${MAKE} ${MFLAGS} ping |
|
|
|
|
|
# N.B.- symbolic links are used in the subdirectory rather than VPATH |
|
|
# because at least one Sun cc compiler puts the .o in the wrong place |
|
|
# when using VPATH and it's almost impossible to get "make depend" to |
|
|
# do the right thing. |
|
|
|
|
|
config: |
|
|
-@dir=$(MD)-$(OS); set -x; \ |
|
|
mkdir $$dir; chmod ug+w $$dir; ln -s ../ping.c $$dir; \ |
|
|
sed -e "/^all:/d" Makefile >$$dir/Makefile; \ |
|
|
chmod ug+w $$dir/Makefile; \ |
|
|
cd $$dir; ${MAKE} ${MFLAGS} depend |
|
|
|
|
|
install: submake FRC |
|
|
-@dir=$(MD)-$(OS); set -x; \ |
|
|
install -c -o root -g bin -m 4755 $$dir/ping ${DESTDIR}; \ |
|
|
install -c -o root -g staff -m 664 ping.1 ${MANDIR} |
|
|
|
|
|
lint: |
|
|
lint -hbxn $(INCL) ping.c | \ |
|
|
grep -v 'possible pointer alignment problem' |
|
|
|
|
|
clean: |
|
|
-@dir=$(MD)-$(OS); set -x; rm -rf $$dir |
|
|
|
|
|
FRC: |
|
|
|
|
|
depend: |
|
|
cc -M ping.c | sed 's/\.o//' | \ |
|
|
awk ' { if ($$1 != prev) \ |
|
|
{ if (rec != "") print rec; rec = $$0; prev = $$1; } \ |
|
|
else { if (length(rec $$2) > 78) { print rec; rec = $$0; } \ |
|
|
else rec = rec " " $$2 } } \ |
|
|
END { print rec } ' >> makedep; |
|
|
echo '/^# DO NOT DELETE THIS LINE/+2,$$d' >eddep; |
|
|
echo '$$r makedep' >>eddep; |
|
|
echo 'w' >>eddep; |
|
|
cp Makefile Makefile.bak; |
|
|
ed - Makefile < eddep; |
|
|
rm eddep makedep; |
|
|
echo '# DEPENDENCIES MUST END AT END OF FILE' >> Makefile; |
|
|
echo '# IF YOU PUT STUFF HERE IT WILL GO AWAY' >> Makefile; |
|
|
echo '# see make depend above' >> Makefile; |
|
|
|
|
|
# DO NOT DELETE THIS LINE -- make depend uses it |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//E*O*F Makefile// |
|
|
|
|
|
echo x - ping.1 |
|
|
cat > "ping.1" << '//E*O*F ping.1//' |
|
|
.\" Copyright (c) 1985 Regents of the University of California. |
|
|
.\" All rights reserved. The Berkeley software License Agreement |
|
|
.\" specifies the terms and conditions for redistribution. |
|
|
.\" |
|
|
.\" @(#)ping.8 6.2 (Berkeley) 5/23/86 |
|
|
.\" |
|
|
.TH PING 8 "May 23, 1986" |
|
|
.UC 6 |
|
|
.SH NAME |
|
|
ping \- send ICMP ECHO_REQUEST packets to network hosts |
|
|
.SH SYNOPSIS |
|
|
.B /etc/ping |
|
|
[ |
|
|
.B \-dfqrv |
|
|
] |
|
|
.I host |
|
|
[ |
|
|
.I packetsize |
|
|
[ |
|
|
.I count |
|
|
[ |
|
|
.I preload |
|
|
]]] |
|
|
.SH DESCRIPTION |
|
|
The DARPA Internet is a large and complex aggregation of |
|
|
network hardware, connected together by gateways. |
|
|
Tracking a single-point hardware or software failure |
|
|
can often be difficult. |
|
|
.I Ping |
|
|
utilizes the |
|
|
ICMP protocol's mandatory ECHO_REQUEST datagram to elicit an |
|
|
ICMP ECHO_RESPONSE from a host or gateway. |
|
|
ECHO_REQUEST datagrams (``pings'') have an IP and ICMP header, |
|
|
followed by a \fBstruct timeval\fR, and then an arbitrary number |
|
|
of ``pad'' bytes used to fill out the packet. |
|
|
Default datagram length is 64 bytes, but this may be changed |
|
|
using the command-line option. |
|
|
Other options are: |
|
|
.TP |
|
|
.B \-v |
|
|
Verbose output. ICMP packets other than ECHO RESPONSE that are received |
|
|
are listed. |
|
|
.TP |
|
|
.B \-q |
|
|
Quiet output. Nothing is displayed except the summary line on termination. |
|
|
.TP |
|
|
.B \-f |
|
|
Flood ping. Outputs packets as fast as they come back or one hundred times |
|
|
per second, whichever is more. For every ECHO_REQUEST sent a period '.' |
|
|
is printed, while for ever ECHO_REPLY received a backspace is printed. |
|
|
This provides a rapid display of how many packets are being dropped. |
|
|
.TP |
|
|
.B \-r |
|
|
Bypass the normal routing tables and send directly to a host on an attached |
|
|
network. |
|
|
If the host is not on a directly-attached network, |
|
|
an error is returned. |
|
|
This option can be used to ping a local host through an interface |
|
|
that has no route through it (e.g., after the interface was dropped by |
|
|
.IR routed (8C)). |
|
|
.TP |
|
|
.B \-d |
|
|
Set the SO_DEBUG option on the socket being used. |
|
|
.PP |
|
|
When using \fIping\fR for fault isolation, |
|
|
it should first be run on the local |
|
|
host, to verify that the local network interface is up and |
|
|
running. |
|
|
Then, hosts and gateways further and further away |
|
|
should be ``pinged''. |
|
|
\fIPing\fR sends one datagram per second, and |
|
|
prints one line of output for every ECHO_RESPONSE returned. |
|
|
No output is produced if there is no response. |
|
|
If an optional |
|
|
.I count |
|
|
is given, only that number of requests is sent. |
|
|
Round-trip times and packet loss statistics are computed. |
|
|
When all responses have been received or the program times out (with a |
|
|
.I count |
|
|
specified), |
|
|
or if the program is terminated with a SIGINT, a brief |
|
|
summary is displayed. |
|
|
If |
|
|
.I preload |
|
|
is given, |
|
|
.I ping |
|
|
sends that many packets as rapidly as possible before |
|
|
falling into its normal mode of behavior. |
|
|
.PP |
|
|
This program is intended for use in network testing, measurement |
|
|
and management. |
|
|
It should be used primarily for manual fault isolation. |
|
|
Because of the load it could impose on the network, |
|
|
it is unwise to use |
|
|
.I ping |
|
|
during normal operations or from automated scripts. |
|
|
.SH DETAILS |
|
|
For those that care. An IP header without options in 20 bytes. |
|
|
An ICMP ECHO_REQUEST packet contains an additional 8 bytes worth |
|
|
of ICMP header followed by an arbitrary amount of data. When a |
|
|
.I packetsize |
|
|
is given, this indicated the size of this extra blob of data (the |
|
|
default is 56). Thus the amount of data received inside of an IP |
|
|
packet of type ICMP ECHO_REPLY will always be 8 bytes more than |
|
|
the requested data space (the ICMP header). |
|
|
.PP |
|
|
If the data space is at least eight bytes large, |
|
|
.I ping |
|
|
uses the first eight bytes of this space to include a timestamp which |
|
|
it uses in the computation of round trip times. This explains why if |
|
|
less than eight bytes of pad are requested, no round trip times are given. |
|
|
.SH BUGS |
|
|
Flood pinging the broadcast address is not recommended. |
|
|
.SH AUTHOR |
|
|
Mike Muuss |
|
|
.SH SEE ALSO |
|
|
netstat(1), |
|
|
ifconfig(8C) |
|
|
//E*O*F ping.1// |
|
|
|
|
|
echo x - ping.c |
|
|
cat > "ping.c" << '//E*O*F ping.c//' |
|
|
/* |
|
|
* P I N G . C |
|
|
* |
|
|
* Using the InterNet Control Message Protocol (ICMP) "ECHO" facility, |
|
|
* measure round-trip-delays and packet loss across network paths. |
|
|
* |
|
|
* Author - |
|
|
* Mike Muuss |
|
|
* U. S. Army Ballistic Research Laboratory |
|
|
* December, 1983 |
|
|
* Modified at Uc Berkeley |
|
|
* |
|
|
* Changed argument to inet_ntoa() to be struct in_addr instead of u_long |
|
|
* DFM BRL 1992 |
|
|
* |
|
|
* Status - |
|
|
* Public Domain. Distribution Unlimited. |
|
|
* |
|
|
* Bugs - |
|
|
* More statistics could always be gathered. |
|
|
* This program has to run SUID to ROOT to access the ICMP socket. |
|
|
*/ |
|
|
|
|
|
#include <stdio.h> |
|
|
#include <errno.h> |
|
|
#include <sys/time.h> |
|
|
|
|
|
#include <sys/param.h> |
|
|
#include <sys/types.h> |
|
|
#include <sys/socket.h> |
|
|
#include <sys/file.h> |
|
|
|
|
|
#include <netinet/in_systm.h> |
|
|
#include <netinet/in.h> |
|
|
#include <netinet/ip.h> |
|
|
#include <netinet/ip_icmp.h> |
|
|
#include <netdb.h> |
|
|
|
|
|
#define MAXWAIT 10 /* max time to wait for response, sec. */ |
|
|
#define MAXPACKET 4096 /* max packet size */ |
|
|
#define VERBOSE 1 /* verbose flag */ |
|
|
#define QUIET 2 /* quiet flag */ |
|
|
#define FLOOD 4 /* floodping flag */ |
|
|
#ifndef MAXHOSTNAMELEN |
|
|
#define MAXHOSTNAMELEN 64 |
|
|
#endif |
|
|
|
|
|
u_char packet[MAXPACKET]; |
|
|
int i, pingflags, options; |
|
|
extern int errno; |
|
|
|
|
|
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 [-dfqrv] host [packetsize [count [preload]]]\n"; |
|
|
|
|
|
char *hostname; |
|
|
char hnamebuf[MAXHOSTNAMELEN]; |
|
|
|
|
|
int npackets; |
|
|
int preload = 0; /* number of packets to "preload" */ |
|
|
int ntransmitted = 0; /* sequence # for outbound packets = #sent */ |
|
|
int ident; |
|
|
|
|
|
int nreceived = 0; /* # of packets we got back */ |
|
|
int timing = 0; |
|
|
int tmin = 999999999; |
|
|
int tmax = 0; |
|
|
int tsum = 0; /* sum of all times, for doing average */ |
|
|
int finish(), catcher(); |
|
|
char *inet_ntoa(); |
|
|
|
|
|
/* |
|
|
* M A I N |
|
|
*/ |
|
|
main(argc, argv) |
|
|
char *argv[]; |
|
|
{ |
|
|
struct sockaddr_in from; |
|
|
char **av = argv; |
|
|
struct sockaddr_in *to = (struct sockaddr_in *) &whereto; |
|
|
int on = 1; |
|
|
struct protoent *proto; |
|
|
|
|
|
argc--, av++; |
|
|
while (argc > 0 && *av[0] == '-') { |
|
|
while (*++av[0]) switch (*av[0]) { |
|
|
case 'd': |
|
|
options |= SO_DEBUG; |
|
|
break; |
|
|
case 'r': |
|
|
options |= SO_DONTROUTE; |
|
|
break; |
|
|
case 'v': |
|
|
pingflags |= VERBOSE; |
|
|
break; |
|
|
case 'q': |
|
|
pingflags |= QUIET; |
|
|
break; |
|
|
case 'f': |
|
|
pingflags |= FLOOD; |
|
|
break; |
|
|
} |
|
|
argc--, av++; |
|
|
} |
|
|
if(argc < 1 || argc > 4) { |
|
|
printf(usage); |
|
|
exit(1); |
|
|
} |
|
|
|
|
|
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 != (unsigned)-1) { |
|
|
strcpy(hnamebuf, av[0]); |
|
|
hostname = hnamebuf; |
|
|
} else { |
|
|
hp = gethostbyname(av[0]); |
|
|
if (hp) { |
|
|
to->sin_family = hp->h_addrtype; |
|
|
bcopy(hp->h_addr, (caddr_t)&to->sin_addr, hp->h_length); |
|
|
hostname = hp->h_name; |
|
|
} else { |
|
|
printf("%s: unknown host %s\n", argv[0], av[0]); |
|
|
exit(1); |
|
|
} |
|
|
} |
|
|
|
|
|
if( argc >= 2 ) |
|
|
datalen = atoi( av[1] ); |
|
|
else |
|
|
datalen = 64-8; |
|
|
if (datalen > MAXPACKET) { |
|
|
fprintf(stderr, "ping: packet size too large\n"); |
|
|
exit(1); |
|
|
} |
|
|
if (datalen >= sizeof(struct timeval)) /* can we time 'em? */ |
|
|
timing = 1; |
|
|
|
|
|
if (argc >= 3) |
|
|
npackets = atoi(av[2]); |
|
|
|
|
|
if (argc == 4) |
|
|
preload = atoi(av[3]); |
|
|
|
|
|
ident = getpid() & 0xFFFF; |
|
|
|
|
|
if ((proto = getprotobyname("icmp")) == NULL) { |
|
|
fprintf(stderr, "icmp: unknown protocol\n"); |
|
|
exit(10); |
|
|
} |
|
|
|
|
|
if ((s = socket(AF_INET, SOCK_RAW, proto->p_proto)) < 0) { |
|
|
perror("ping: socket"); |
|
|
exit(5); |
|
|
} |
|
|
if (options & SO_DEBUG) { |
|
|
if(pingflags & VERBOSE) |
|
|
printf("...debug on.\n"); |
|
|
setsockopt(s, SOL_SOCKET, SO_DEBUG, &on, sizeof(on)); |
|
|
} |
|
|
if (options & SO_DONTROUTE) { |
|
|
if(pingflags & VERBOSE) |
|
|
printf("...no routing.\n"); |
|
|
setsockopt(s, SOL_SOCKET, SO_DONTROUTE, &on, sizeof(on)); |
|
|
} |
|
|
|
|
|
if(to->sin_family == AF_INET) { |
|
|
printf("PING %s (%s): %d data bytes\n", hostname, |
|
|
inet_ntoa(to->sin_addr), datalen); /* DFM */ |
|
|
} else { |
|
|
printf("PING %s: %d data bytes\n", hostname, datalen ); |
|
|
} |
|
|
setlinebuf( stdout ); |
|
|
|
|
|
signal( SIGINT, finish ); |
|
|
signal(SIGALRM, catcher); |
|
|
|
|
|
/* fire off them quickies */ |
|
|
for(i=0; i < preload; i++) |
|
|
pinger(); |
|
|
|
|
|
if(!(pingflags & FLOOD)) |
|
|
catcher(); /* start things going */ |
|
|
|
|
|
for (;;) { |
|
|
int len = sizeof (packet); |
|
|
int fromlen = sizeof (from); |
|
|
int cc; |
|
|
struct timeval timeout; |
|
|
int fdmask = 1 << s; |
|
|
|
|
|
timeout.tv_sec = 0; |
|
|
timeout.tv_usec = 10000; |
|
|
|
|
|
if(pingflags & FLOOD) { |
|
|
pinger(); |
|
|
if( select(32, &fdmask, 0, 0, &timeout) == 0) |
|
|
continue; |
|
|
} |
|
|
if ( (cc=recvfrom(s, packet, len, 0, &from, &fromlen)) < 0) { |
|
|
if( errno == EINTR ) |
|
|
continue; |
|
|
perror("ping: recvfrom"); |
|
|
continue; |
|
|
} |
|
|
pr_pack( packet, cc, &from ); |
|
|
if (npackets && nreceived >= npackets) |
|
|
finish(); |
|
|
} |
|
|
/*NOTREACHED*/ |
|
|
} |
|
|
|
|
|
/* |
|
|
* C A T C H E R |
|
|
* |
|
|
* This routine causes another PING to be transmitted, and then |
|
|
* schedules another SIGALRM for 1 second from now. |
|
|
* |
|
|
* Bug - |
|
|
* 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. |
|
|
*/ |
|
|
catcher() |
|
|
{ |
|
|
int waittime; |
|
|
|
|
|
pinger(); |
|
|
if (npackets == 0 || ntransmitted < npackets) |
|
|
alarm(1); |
|
|
else { |
|
|
if (nreceived) { |
|
|
waittime = 2 * tmax / 1000; |
|
|
if (waittime == 0) |
|
|
waittime = 1; |
|
|
} else |
|
|
waittime = MAXWAIT; |
|
|
signal(SIGALRM, finish); |
|
|
alarm(waittime); |
|
|
} |
|
|
} |
|
|
|
|
|
/* |
|
|
* P I N G E R |
|
|
* |
|
|
* 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. |
|
|
*/ |
|
|
pinger() |
|
|
{ |
|
|
static u_char outpack[MAXPACKET]; |
|
|
register struct icmp *icp = (struct icmp *) outpack; |
|
|
int i, cc; |
|
|
register struct timeval *tp = (struct timeval *) &outpack[8]; |
|
|
register u_char *datap = &outpack[8+sizeof(struct timeval)]; |
|
|
|
|
|
icp->icmp_type = ICMP_ECHO; |
|
|
icp->icmp_code = 0; |
|
|
icp->icmp_cksum = 0; |
|
|
icp->icmp_seq = ntransmitted++; |
|
|
icp->icmp_id = ident; /* ID */ |
|
|
|
|
|
cc = datalen+8; /* skips ICMP portion */ |
|
|
|
|
|
if (timing) |
|
|
gettimeofday( tp, &tz ); |
|
|
|
|
|
for( i=8; i<datalen; i++) /* skip 8 for time */ |
|
|
*datap++ = i; |
|
|
|
|
|
/* 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 || i != cc ) { |
|
|
if( i<0 ) perror("sendto"); |
|
|
printf("ping: wrote %s %d chars, ret=%d\n", |
|
|
hostname, cc, i ); |
|
|
fflush(stdout); |
|
|
} |
|
|
if(pingflags == FLOOD) { |
|
|
putchar('.'); |
|
|
fflush(stdout); |
|
|
} |
|
|
} |
|
|
|
|
|
/* |
|
|
* P R _ T Y P E |
|
|
* |
|
|
* Convert an ICMP "type" field to a printable string. |
|
|
*/ |
|
|
char * |
|
|
pr_type( t ) |
|
|
register int t; |
|
|
{ |
|
|
static char *ttab[] = { |
|
|
"Echo Reply", |
|
|
"ICMP 1", |
|
|
"ICMP 2", |
|
|
"Dest Unreachable", |
|
|
"Source Quench", |
|
|
"Redirect", |
|
|
"ICMP 6", |
|
|
"ICMP 7", |
|
|
"Echo", |
|
|
"ICMP 9", |
|
|
"ICMP 10", |
|
|
"Time Exceeded", |
|
|
"Parameter Problem", |
|
|
"Timestamp", |
|
|
"Timestamp Reply", |
|
|
"Info Request", |
|
|
"Info Reply" |
|
|
}; |
|
|
|
|
|
if( t < 0 || t > 16 ) |
|
|
return("OUT-OF-RANGE"); |
|
|
|
|
|
return(ttab[t]); |
|
|
} |
|
|
|
|
|
/* |
|
|
* P R _ P A C K |
|
|
* |
|
|
* 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!). |
|
|
*/ |
|
|
pr_pack( buf, cc, from ) |
|
|
char *buf; |
|
|
int cc; |
|
|
struct sockaddr_in *from; |
|
|
{ |
|
|
struct ip *ip; |
|
|
register struct icmp *icp; |
|
|
register long *lp = (long *) packet; |
|
|
register int i; |
|
|
struct timeval tv; |
|
|
struct timeval *tp; |
|
|
int hlen, triptime; |
|
|
|
|
|
from->sin_addr.s_addr = ntohl( from->sin_addr.s_addr ); |
|
|
gettimeofday( &tv, &tz ); |
|
|
|
|
|
ip = (struct ip *) buf; |
|
|
hlen = ip->ip_hl << 2; |
|
|
if (cc < hlen + ICMP_MINLEN) { |
|
|
if (pingflags & VERBOSE) |
|
|
printf("packet too short (%d bytes) from %s\n", cc, |
|
|
inet_ntoa(ntohl(from->sin_addr))); /* DFM */ |
|
|
return; |
|
|
} |
|
|
cc -= hlen; |
|
|
icp = (struct icmp *)(buf + hlen); |
|
|
if( (!(pingflags & QUIET)) && icp->icmp_type != ICMP_ECHOREPLY ) { |
|
|
printf("%d bytes from %s: icmp_type=%d (%s) icmp_code=%d\n", |
|
|
cc, inet_ntoa(ntohl(from->sin_addr)), |
|
|
icp->icmp_type, pr_type(icp->icmp_type), icp->icmp_code);/*DFM*/ |
|
|
if (pingflags & VERBOSE) { |
|
|
for( i=0; i<12; i++) |
|
|
printf("x%2.2x: x%8.8x\n", i*sizeof(long), |
|
|
*lp++); |
|
|
} |
|
|
return; |
|
|
} |
|
|
if( icp->icmp_id != ident ) |
|
|
return; /* 'Twas not our ECHO */ |
|
|
|
|
|
if (timing) { |
|
|
tp = (struct timeval *)&icp->icmp_data[0]; |
|
|
tvsub( &tv, tp ); |
|
|
triptime = tv.tv_sec*1000+(tv.tv_usec/1000); |
|
|
tsum += triptime; |
|
|
if( triptime < tmin ) |
|
|
tmin = triptime; |
|
|
if( triptime > tmax ) |
|
|
tmax = triptime; |
|
|
} |
|
|
|
|
|
if(!(pingflags & QUIET)) { |
|
|
if(pingflags != FLOOD) { |
|
|
printf("%d bytes from %s: icmp_seq=%d", cc, |
|
|
inet_ntoa(from->sin_addr), |
|
|
icp->icmp_seq ); /* DFM */ |
|
|
if (timing) |
|
|
printf(" time=%d ms\n", triptime ); |
|
|
else |
|
|
putchar('\n'); |
|
|
} else { |
|
|
putchar('\b'); |
|
|
fflush(stdout); |
|
|
} |
|
|
} |
|
|
nreceived++; |
|
|
} |
|
|
|
|
|
|
|
|
/* |
|
|
* I N _ C K S U M |
|
|
* |
|
|
* Checksum routine for Internet Protocol family headers (C Version) |
|
|
* |
|
|
*/ |
|
|
in_cksum(addr, len) |
|
|
u_short *addr; |
|
|
int len; |
|
|
{ |
|
|
register int nleft = len; |
|
|
register u_short *w = addr; |
|
|
register u_short answer; |
|
|
register int sum = 0; |
|
|
|
|
|
/* |
|
|
* 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 |
|
|
* 16 bits. |
|
|
*/ |
|
|
while( nleft > 1 ) { |
|
|
sum += *w++; |
|
|
nleft -= 2; |
|
|
} |
|
|
|
|
|
/* mop up an odd byte, if necessary */ |
|
|
if( nleft == 1 ) { |
|
|
u_short u = 0; |
|
|
|
|
|
*(u_char *)(&u) = *(u_char *)w ; |
|
|
sum += u; |
|
|
} |
|
|
|
|
|
/* |
|
|
* 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 */ |
|
|
return (answer); |
|
|
} |
|
|
|
|
|
/* |
|
|
* T V S U B |
|
|
* |
|
|
* Subtract 2 timeval structs: out = out - in. |
|
|
* |
|
|
* Out is assumed to be >= in. |
|
|
*/ |
|
|
tvsub( out, in ) |
|
|
register struct timeval *out, *in; |
|
|
{ |
|
|
if( (out->tv_usec -= in->tv_usec) < 0 ) { |
|
|
out->tv_sec--; |
|
|
out->tv_usec += 1000000; |
|
|
} |
|
|
out->tv_sec -= in->tv_sec; |
|
|
} |
|
|
|
|
|
/* |
|
|
* F I N I S H |
|
|
* |
|
|
* 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. |
|
|
*/ |
|
|
finish() |
|
|
{ |
|
|
putchar('\n'); |
|
|
fflush(stdout); |
|
|
printf("\n----%s PING Statistics----\n", hostname ); |
|
|
printf("%d packets transmitted, ", ntransmitted ); |
|
|
printf("%d packets received, ", nreceived ); |
|
|
if (ntransmitted) |
|
|
if( nreceived > ntransmitted) |
|
|
printf("-- somebody's printing up packets!"); |
|
|
else |
|
|
printf("%d%% packet loss", |
|
|
(int) (((ntransmitted-nreceived)*100) / |
|
|
ntransmitted)); |
|
|
printf("\n"); |
|
|
if (nreceived && timing) |
|
|
printf("round-trip (ms) min/avg/max = %d/%d/%d\n", |
|
|
tmin, |
|
|
tsum / nreceived, |
|
|
tmax ); |
|
|
fflush(stdout); |
|
|
exit(0); |
|
|
} |
|
|
//E*O*F ping.c// |
|
|
|
|
|
echo x - ping.shar |
|
|
cat > "ping.shar" << '//E*O*F ping.shar//' |
|
|
//E*O*F ping.shar// |
|
|
|
|
|
echo x - newping.1 |
|
|
cat > "newping.1" << '//E*O*F newping.1//' |
|
|
.\" Copyright (c) 1985 Regents of the University of California. |
|
|
.\" All rights reserved. The Berkeley software License Agreement |
|
|
.\" specifies the terms and conditions for redistribution. |
|
|
.\" |
|
|
.\" @(#)ping.8 6.2 (Berkeley) 5/23/86 |
|
|
.\" |
|
|
.TH PING 8 "May 23, 1986" |
|
|
.UC 6 |
|
|
.SH NAME |
|
|
ping \- send ICMP ECHO_REQUEST packets to network hosts |
|
|
.SH SYNOPSIS |
|
|
.B /etc/ping |
|
|
[ |
|
|
.B \-dfnqrvR |
|
|
] |
|
|
.I host |
|
|
[ |
|
|
.I packetsize |
|
|
[ |
|
|
.I count |
|
|
[ |
|
|
.I preload |
|
|
]]] |
|
|
.SH DESCRIPTION |
|
|
The DARPA Internet is a large and complex aggregation of |
|
|
network hardware, connected together by gateways. |
|
|
Tracking a single-point hardware or software failure |
|
|
can often be difficult. |
|
|
.I Ping |
|
|
utilizes the |
|
|
ICMP protocol's mandatory ECHO_REQUEST datagram to elicit an |
|
|
ICMP ECHO_RESPONSE from a host or gateway. |
|
|
ECHO_REQUEST datagrams (``pings'') have an IP and ICMP header, |
|
|
followed by a \fBstruct timeval\fR, and then an arbitrary number |
|
|
of ``pad'' bytes used to fill out the packet. |
|
|
Default datagram length is 64 bytes, but this may be changed |
|
|
using the command-line option. |
|
|
Other options are: |
|
|
.TP |
|
|
.B \-v |
|
|
Verbose output. ICMP packets other than ECHO RESPONSE that are received |
|
|
are listed. |
|
|
.TP |
|
|
.B \-q |
|
|
Quiet output. Nothing is displayed except the summary line on termination. |
|
|
.TP |
|
|
.B \-n |
|
|
Numeric output only. No attempt will be made to lookup symbolic |
|
|
names for host addresses. Useful if your nameserver if flakey |
|
|
or for hosts not in the database. |
|
|
.TP |
|
|
.B \-f |
|
|
Flood ping. Outputs packets as fast as they come back or one hundred times |
|
|
per second, whichever is more. For every ECHO_REQUEST sent a period '.' |
|
|
is printed, while for ever ECHO_REPLY received a backspace is printed. |
|
|
This provides a rapid display of how many packets are being dropped. |
|
|
.TP |
|
|
.B \-R |
|
|
Record Route. Includes the RECORD_ROUTE option in the ECHO_REQUEST |
|
|
packet and displays the route buffer on returned packets. Note that |
|
|
the IP header is only large enough for six such routes. Many hosts |
|
|
ignore or discard this option. |
|
|
.TP |
|
|
.B \-r |
|
|
Bypass the normal routing tables and send directly to a host on an attached |
|
|
network. |
|
|
If the host is not on a directly-attached network, |
|
|
an error is returned. |
|
|
This option can be used to ping a local host through an interface |
|
|
that has no route through it (e.g., after the interface was dropped by |
|
|
.IR routed (8C)). |
|
|
.TP |
|
|
.B \-d |
|
|
Set the SO_DEBUG option on the socket being used. |
|
|
.PP |
|
|
When using \fIping\fR for fault isolation, |
|
|
it should first be run on the local |
|
|
host, to verify that the local network interface is up and |
|
|
running. |
|
|
Then, hosts and gateways further and further away |
|
|
should be ``pinged''. |
|
|
\fIPing\fR sends one datagram per second, and |
|
|
prints one line of output for every ECHO_RESPONSE returned. |
|
|
No output is produced if there is no response. |
|
|
If an optional |
|
|
.I count |
|
|
is given, only that number of requests is sent. |
|
|
Round-trip times and packet loss statistics are computed. |
|
|
When all responses have been received or the program times out (with a |
|
|
.I count |
|
|
specified), |
|
|
or if the program is terminated with a SIGINT, a brief |
|
|
summary is displayed. |
|
|
If |
|
|
.I preload |
|
|
is given, |
|
|
.I ping |
|
|
sends that many packets as fast as possible before |
|
|
falling into its normal mode of behavior. |
|
|
.PP |
|
|
This program is intended for use in network testing, measurement |
|
|
and management. |
|
|
It should be used primarily for manual fault isolation. |
|
|
Because of the load it could impose on the network, |
|
|
it is unwise to use |
|
|
.I ping |
|
|
during normal operations or from automated scripts. |
|
|
.SH DETAILS |
|
|
For those that care. An IP header without options in 20 bytes. |
|
|
An ICMP ECHO_REQUEST packet contains an additional 8 bytes worth |
|
|
of ICMP header followed by an arbitrary amount of data. When a |
|
|
.I packetsize |
|
|
is given, this indicated the size of this extra blob of data (the |
|
|
default is 56). Thus the amount of data received inside of an IP |
|
|
packet of type ICMP ECHO_REPLY will always be 8 bytes more than |
|
|
the requested data space (the ICMP header). |
|
|
.PP |
|
|
If the data space is at least eight bytes large, |
|
|
.I ping |
|
|
uses the first eight bytes of this space to include a timestamp which |
|
|
it uses in the computation of round trip times. This explains why if |
|
|
less than eight bytes of pad are requested, no round trip times are given. |
|
|
.SH BUGS |
|
|
Far too many Hosts and Gateways (including the core gateways) ignore the |
|
|
RECORD_ROUTE option. To quote RFC 791, "What is optional is their |
|
|
transmission in any particular datagram, not their implementation." |
|
|
.PP |
|
|
The maximum IP header length is too small for options like |
|
|
RECORD_ROUTE to be completely useful. There's not much that |
|
|
we can do about that however. |
|
|
.PP |
|
|
Flood pinging the broadcast address is not recommended. |
|
|
.SH AUTHOR |
|
|
Mike Muuss |
|
|
.SH SEE ALSO |
|
|
netstat(1), |
|
|
ifconfig(8C) |
|
|
//E*O*F newping.1// |
|
|
|
|
|
echo x - newping.c |
|
|
cat > "newping.c" << '//E*O*F newping.c//' |
|
|
/* |
|
|
* P I N G . C |
|
|
* |
|
|
* Using the InterNet Control Message Protocol (ICMP) "ECHO" facility, |
|
|
* measure round-trip-delays and packet loss across network paths. |
|
|
* |
|
|
* Author - |
|
|
* Mike Muuss |
|
|
* U. S. Army Ballistic Research Laboratory |
|
|
* December, 1983 |
|
|
* Modified at Uc Berkeley |
|
|
* Record Route and verbose headers - Phil Dykstra, BRL, March 1988. |
|
|
* |
|
|
* Status - |
|
|
* Public Domain. Distribution Unlimited. |
|
|
* |
|
|
* Bugs - |
|
|
* More statistics could always be gathered. |
|
|
* This program has to run SUID to ROOT to access the ICMP socket. |
|
|
*/ |
|
|
|
|
|
#include <stdio.h> |
|
|
#include <errno.h> |
|
|
#include <sys/time.h> |
|
|
|
|
|
#include <sys/param.h> |
|
|
#include <sys/socket.h> |
|
|
#include <sys/file.h> |
|
|
|
|
|
#include <netinet/in_systm.h> |
|
|
#include <netinet/in.h> |
|
|
#include <netinet/ip.h> |
|
|
#include <netinet/ip_icmp.h> |
|
|
#include <netdb.h> |
|
|
|
|
|
#define PING_MAXWAIT 10 /* max time to wait for response, sec. */ |
|
|
#define PING_MAXPACKET 4096 /* max packet size */ |
|
|
#define PING_NUMERIC 1 /* return dotted quads */ |
|
|
#define PING_VERBOSE 2 /* verbose flag */ |
|
|
#define PING_QUIET 4 /* quiet flag */ |
|
|
#define PING_DEBUG 8 /* turn on socket debugging */ |
|
|
#define PING_DONTROUTE 16 /* dont route pings*/ |
|
|
#define PING_RROUTE 32 /* record route flag */ |
|
|
#define PING_FLOOD 64 /* floodping flag */ |
|
|
#define PING_CISCO 128 /* cisco style ping */ |
|
|
#define PING_NROUTES 9 /* number of record route slots (9 max) */ |
|
|
#ifndef MAXHOSTNAMELEN |
|
|
#define MAXHOSTNAMELEN 64 |
|
|
#endif |
|
|
|
|
|
u_char packet[PING_MAXPACKET]; |
|
|
int i, pingflags; |
|
|
extern int errno; |
|
|
|
|
|
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 [-cdfnqrvR] host [packetsize [count [preload]]]\n"; |
|
|
|
|
|
char *hostname; |
|
|
char hnamebuf[MAXHOSTNAMELEN]; |
|
|
|
|
|
int npackets; |
|
|
int preload = 0; /* number of packets to "preload" */ |
|
|
int ntransmitted = 0; /* sequence # for outbound packets = #sent */ |
|
|
int ident; |
|
|
|
|
|
int nreceived = 0; /* # of packets we got back */ |
|
|
int timing = 0; |
|
|
int tmin = 999999999; |
|
|
int tmax = 0; |
|
|
int tsum = 0; /* sum of all times, for doing average */ |
|
|
int finish(), catcher(); |
|
|
char *inet_ntoa(); |
|
|
char *pr_addr(); |
|
|
|
|
|
char rspace[3+4*PING_NROUTES+1]; /* record route space */ |
|
|
|
|
|
/* |
|
|
* M A I N |
|
|
*/ |
|
|
main(argc, argv) |
|
|
char *argv[]; |
|
|
{ |
|
|
char **av = argv; |
|
|
int on = 1; |
|
|
|
|
|
struct sockaddr_in pktaddr; |
|
|
struct sockaddr_in *to = (struct sockaddr_in *) &whereto; |
|
|
struct protoent *proto; |
|
|
int maxpkt = sizeof (packet); |
|
|
int addrlen = sizeof (pktaddr); |
|
|
int rcvlen, nfds, fdmask; |
|
|
|
|
|
struct timeval timeout; |
|
|
timeout.tv_sec = 0; |
|
|
timeout.tv_usec = 10000; |
|
|
|
|
|
argc--, av++; |
|
|
while (argc > 0 && *av[0] == '-') { |
|
|
while (*++av[0]) switch (*av[0]) { |
|
|
case 'c': |
|
|
pingflags |= PING_CISCO; |
|
|
break; |
|
|
case 'd': |
|
|
pingflags |= PING_DEBUG; |
|
|
break; |
|
|
case 'f': |
|
|
pingflags |= PING_FLOOD; |
|
|
/* timeout.tv_usec = 0; */ |
|
|
break; |
|
|
case 'n': |
|
|
pingflags |= PING_NUMERIC; |
|
|
break; |
|
|
case 'q': |
|
|
pingflags |= PING_QUIET; |
|
|
break; |
|
|
case 'r': |
|
|
pingflags |= PING_DONTROUTE; |
|
|
break; |
|
|
case 'v': |
|
|
pingflags |= PING_VERBOSE; |
|
|
break; |
|
|
case 'R': |
|
|
pingflags |= PING_RROUTE; |
|
|
break; |
|
|
} |
|
|
argc--, av++; |
|
|
} |
|
|
if(argc < 1 || argc > 4) { |
|
|
printf(usage); |
|
|
exit(1); |
|
|
} |
|
|
|
|
|
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 != (unsigned)-1) { |
|
|
strcpy(hnamebuf, av[0]); |
|
|
hostname = hnamebuf; |
|
|
} else { |
|
|
hp = gethostbyname(av[0]); |
|
|
if (hp) { |
|
|
to->sin_family = hp->h_addrtype; |
|
|
bcopy(hp->h_addr, (caddr_t)&to->sin_addr, hp->h_length); |
|
|
strncpy( hnamebuf, hp->h_name, sizeof(hnamebuf)-1 ); |
|
|
hostname = hnamebuf; |
|
|
} else { |
|
|
printf("%s: unknown host %s\n", argv[0], av[0]); |
|
|
exit(1); |
|
|
} |
|
|
} |
|
|
|
|
|
if( argc >= 2 ) |
|
|
datalen = atoi( av[1] ); |
|
|
else |
|
|
datalen = 64-8; |
|
|
if (datalen > PING_MAXPACKET) { |
|
|
fprintf(stderr, "ping: packet size too large\n"); |
|
|
exit(1); |
|
|
} |
|
|
if (datalen >= sizeof(struct timeval)) /* can we time 'em? */ |
|
|
timing = 1; |
|
|
|
|
|
if (argc >= 3) |
|
|
npackets = atoi(av[2]); |
|
|
|
|
|
if (argc == 4) |
|
|
preload = atoi(av[3]); |
|
|
|
|
|
ident = getpid() & 0xFFFF; |
|
|
|
|
|
if ((proto = getprotobyname("icmp")) == NULL) { |
|
|
fprintf(stderr, "icmp: unknown protocol\n"); |
|
|
exit(10); |
|
|
} |
|
|
if ((s = socket(AF_INET, SOCK_RAW, proto->p_proto)) < 0) { |
|
|
perror("ping: socket"); |
|
|
exit(5); |
|
|
} |
|
|
fdmask = 1 << s; |
|
|
nfds = s + 1; |
|
|
|
|
|
if (pingflags & PING_DEBUG) { |
|
|
setsockopt(s, SOL_SOCKET, SO_DEBUG, &on, sizeof(on)); |
|
|
} |
|
|
if (pingflags & PING_DONTROUTE) { |
|
|
setsockopt(s, SOL_SOCKET, SO_DONTROUTE, &on, sizeof(on)); |
|
|
} |
|
|
/* Record Route option */ |
|
|
if( pingflags & PING_RROUTE ) { |
|
|
#ifdef IP_OPTIONS |
|
|
rspace[IPOPT_OPTVAL] = IPOPT_RR; |
|
|
rspace[IPOPT_OLEN] = sizeof(rspace)-1; |
|
|
rspace[IPOPT_OFFSET] = IPOPT_MINOFF; |
|
|
if( setsockopt(s, IPPROTO_IP, IP_OPTIONS, rspace, sizeof(rspace)) < 0 ) { |
|
|
perror( "Record route" ); |
|
|
exit( 42 ); |
|
|
} |
|
|
#else /* IP_OPTIONS */ |
|
|
fprintf( stderr, "ping: record route not available on this machine.\n" ); |
|
|
exit( 42 ); |
|
|
#endif /* IP_OPTIONS */ |
|
|
} |
|
|
|
|
|
if(to->sin_family == AF_INET) { |
|
|
printf("PING %s (%s): %d data bytes\n", hostname, |
|
|
inet_ntoa(to->sin_addr.s_addr), datalen); |
|
|
} else { |
|
|
printf("PING %s: %d data bytes\n", hostname, datalen ); |
|
|
} |
|
|
setlinebuf( stdout ); |
|
|
|
|
|
signal( SIGINT, finish ); |
|
|
signal(SIGALRM, catcher); |
|
|
|
|
|
/* fire off them quickies */ |
|
|
for(i=0; i < preload; i++) |
|
|
pinger(); |
|
|
|
|
|
if(pingflags & PING_FLOOD) { |
|
|
for (;;) { |
|
|
pinger(); |
|
|
if( select(32, &fdmask, 0, 0, &timeout) == 0) |
|
|
continue; |
|
|
if((rcvlen = recvfrom(s, packet, maxpkt, 0, |
|
|
&pktaddr, &addrlen)) < 0) { |
|
|
if( errno != EINTR ) |
|
|
perror("\nping: recvfrom"); |
|
|
continue; |
|
|
} |
|
|
pr_pack( packet, rcvlen, &pktaddr ); |
|
|
if (npackets && nreceived >= npackets) |
|
|
finish(); |
|
|
} |
|
|
} else if(pingflags & PING_CISCO) { |
|
|
for(;;) { |
|
|
alarm(1); |
|
|
pinger(); |
|
|
if((rcvlen = recvfrom(s, packet, maxpkt, 0, |
|
|
&pktaddr, &addrlen)) < 0) { |
|
|
if( errno != EINTR ) |
|
|
perror("\nping: recvfrom"); |
|
|
} |
|
|
pr_pack( packet, rcvlen, &pktaddr ); |
|
|
if (npackets && nreceived >= npackets) |
|
|
finish(); |
|
|
} |
|
|
} else { |
|
|
catcher(); /* start things going */ |
|
|
for (;;) { |
|
|
if((rcvlen = recvfrom(s, packet, maxpkt, 0, |
|
|
&pktaddr, &addrlen)) < 0) { |
|
|
if( errno == EINTR ) |
|
|
continue; |
|
|
perror("ping: recvfrom"); |
|
|
continue; |
|
|
} |
|
|
pr_pack( packet, rcvlen, &pktaddr ); |
|
|
if (npackets && nreceived >= npackets) |
|
|
finish(); |
|
|
} |
|
|
} |
|
|
/*NOTREACHED*/ |
|
|
} |
|
|
|
|
|
/* |
|
|
* C A T C H E R |
|
|
* |
|
|
* This routine causes another PING to be transmitted, and then |
|
|
* schedules another SIGALRM for 1 second from now. |
|
|
* |
|
|
* Bug - |
|
|
* 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. |
|
|
*/ |
|
|
catcher() |
|
|
{ |
|
|
int waittime; |
|
|
|
|
|
if(pingflags & PING_CISCO) { |
|
|
putchar('!'); |
|
|
fflush(stdout); |
|
|
} |
|
|
pinger(); |
|
|
if (npackets == 0 || ntransmitted < npackets) |
|
|
alarm(1); |
|
|
else { |
|
|
if (nreceived) { |
|
|
waittime = 2 * tmax / 1000; |
|
|
if (waittime == 0) |
|
|
waittime = 1; |
|
|
} else |
|
|
waittime = PING_MAXWAIT; |
|
|
signal(SIGALRM, finish); |
|
|
alarm(waittime); |
|
|
} |
|
|
} |
|
|
|
|
|
/* |
|
|
* P I N G E R |
|
|
* |
|
|
* 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. |
|
|
*/ |
|
|
pinger() |
|
|
{ |
|
|
static u_char outpack[PING_MAXPACKET]; |
|
|
register struct icmp *icp = (struct icmp *) outpack; |
|
|
int i, cc; |
|
|
register struct timeval *tp = (struct timeval *) &outpack[8]; |
|
|
register u_char *datap = &outpack[8+sizeof(struct timeval)]; |
|
|
|
|
|
icp->icmp_type = ICMP_ECHO; |
|
|
icp->icmp_code = 0; |
|
|
icp->icmp_cksum = 0; |
|
|
icp->icmp_seq = ntransmitted++; |
|
|
icp->icmp_id = ident; /* ID */ |
|
|
|
|
|
cc = datalen+8; /* skips ICMP portion */ |
|
|
|
|
|
if (timing) |
|
|
gettimeofday( tp, &tz ); |
|
|
|
|
|
for( i=8; i<datalen; i++) /* skip 8 for time */ |
|
|
*datap++ = i; |
|
|
|
|
|
/* 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 || i != cc ) { |
|
|
if( i<0 ) perror("sendto"); |
|
|
printf("ping: wrote %s %d chars, ret=%d\n", |
|
|
hostname, cc, i ); |
|
|
fflush(stdout); |
|
|
} |
|
|
if(pingflags & PING_FLOOD) { |
|
|
putchar('.'); |
|
|
fflush(stdout); |
|
|
} |
|
|
} |
|
|
|
|
|
/* |
|
|
* P R _ P A C K |
|
|
* |
|
|
* 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!). |
|
|
*/ |
|
|
pr_pack( buf, cc, from ) |
|
|
char *buf; |
|
|
int cc; |
|
|
struct sockaddr_in *from; |
|
|
{ |
|
|
struct ip *ip; |
|
|
register struct icmp *icp; |
|
|
register long *lp = (long *) packet; |
|
|
register int i; |
|
|
struct timeval tv; |
|
|
struct timeval *tp; |
|
|
int hlen, triptime; |
|
|
|
|
|
from->sin_addr.s_addr = ntohl( from->sin_addr.s_addr ); |
|
|
gettimeofday( &tv, &tz ); |
|
|
|
|
|
/* Check the IP header */ |
|
|
ip = (struct ip *) buf; |
|
|
hlen = ip->ip_hl << 2; |
|
|
if( cc < hlen + ICMP_MINLEN ) { |
|
|
if( pingflags & PING_VERBOSE ) |
|
|
printf("packet too short (%d bytes) from %s\n", cc, |
|
|
inet_ntoa(ntohl(from->sin_addr.s_addr))); |
|
|
return; |
|
|
} |
|
|
|
|
|
/* Now the ICMP part */ |
|
|
cc -= hlen; |
|
|
icp = (struct icmp *)(buf + hlen); |
|
|
if( icp->icmp_type == ICMP_ECHOREPLY ) { |
|
|
if( icp->icmp_id != ident ) |
|
|
return; /* 'Twas not our ECHO */ |
|
|
|
|
|
nreceived++; |
|
|
if (timing) { |
|
|
tp = (struct timeval *)&icp->icmp_data[0]; |
|
|
tvsub( &tv, tp ); |
|
|
triptime = tv.tv_sec*1000+(tv.tv_usec/1000); |
|
|
tsum += triptime; |
|
|
if( triptime < tmin ) |
|
|
tmin = triptime; |
|
|
if( triptime > tmax ) |
|
|
tmax = triptime; |
|
|
} |
|
|
|
|
|
if( pingflags & PING_QUIET) |
|
|
return; |
|
|
|
|
|
if( pingflags & PING_FLOOD) { |
|
|
putchar('\b'); |
|
|
fflush(stdout); |
|
|
} else if( pingflags & PING_CISCO) { |
|
|
putchar('.'); |
|
|
fflush(stdout); |
|
|
} else { |
|
|
printf("%d bytes from %s: icmp_seq=%d", cc, |
|
|
inet_ntoa(ntohl(from->sin_addr.s_addr)), |
|
|
icp->icmp_seq ); |
|
|
if (timing) |
|
|
printf(" time=%d ms\n", triptime ); |
|
|
else |
|
|
putchar('\n'); |
|
|
} |
|
|
} else { |
|
|
/* We've got something other than an ECHOREPLY */ |
|
|
if( !(pingflags & PING_VERBOSE) ) |
|
|
return; |
|
|
|
|
|
printf("%d bytes from %s: ", |
|
|
cc, pr_addr(ntohl(from->sin_addr.s_addr)) ); |
|
|
pr_icmph( icp ); |
|
|
} |
|
|
|
|
|
/* Display any IP options */ |
|
|
/* XXX - we should eventually do this for all packets with options */ |
|
|
if( hlen > 20 && icp->icmp_type == ICMP_ECHOREPLY ) { |
|
|
unsigned char *cp; |
|
|
/*printf("%d byte IP header:\n", hlen);*/ |
|
|
cp = (unsigned char *)buf + sizeof(struct ip) + 3; |
|
|
for( i = 0; i < PING_NROUTES; i++ ) { |
|
|
unsigned long l; |
|
|
l = (*cp<<24) | (*(cp+1)<<16) | (*(cp+2)<<8) | *(cp+3); |
|
|
/* give the nameserver a break! */ |
|
|
if( l == 0 ) |
|
|
printf("0.0.0.0\n"); |
|
|
else |
|
|
printf("%s\n", pr_addr(ntohl(l)) ); |
|
|
cp += 4; |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
/* |
|
|
* I N _ C K S U M |
|
|
* |
|
|
* Checksum routine for Internet Protocol family headers (C Version) |
|
|
* |
|
|
*/ |
|
|
in_cksum(addr, len) |
|
|
u_short *addr; |
|
|
int len; |
|
|
{ |
|
|
register int nleft = len; |
|
|
register u_short *w = addr; |
|
|
register int sum = 0; |
|
|
u_short answer = 0; |
|
|
|
|
|
/* |
|
|
* 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 |
|
|
* 16 bits. |
|
|
*/ |
|
|
while( nleft > 1 ) { |
|
|
sum += *w++; |
|
|
nleft -= 2; |
|
|
} |
|
|
|
|
|
/* mop up an odd byte, if necessary */ |
|
|
if( nleft == 1 ) { |
|
|
*(u_char *)(&answer) = *(u_char *)w ; |
|
|
sum += answer; |
|
|
} |
|
|
|
|
|
/* |
|
|
* 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 possible carry */ |
|
|
answer = ~sum; /* ones complement & truncate to 16 bits */ |
|
|
return (answer); |
|
|
} |
|
|
|
|
|
/* |
|
|
* T V S U B |
|
|
* |
|
|
* Subtract 2 timeval structs: out = out - in. |
|
|
* |
|
|
* Out is assumed to be >= in. |
|
|
*/ |
|
|
tvsub( out, in ) |
|
|
register struct timeval *out, *in; |
|
|
{ |
|
|
if( (out->tv_usec -= in->tv_usec) < 0 ) { |
|
|
out->tv_sec--; |
|
|
out->tv_usec += 1000000; |
|
|
} |
|
|
out->tv_sec -= in->tv_sec; |
|
|
} |
|
|
|
|
|
/* |
|
|
* F I N I S H |
|
|
* |
|
|
* 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. |
|
|
*/ |
|
|
finish() |
|
|
{ |
|
|
putchar('\n'); |
|
|
fflush(stdout); |
|
|
printf("\n----%s PING Statistics----\n", hostname ); |
|
|
printf("%d packets transmitted, %d packets received", |
|
|
ntransmitted, nreceived); |
|
|
if (ntransmitted) |
|
|
if( nreceived > ntransmitted) |
|
|
printf(" -- somebody's printing up packets!\n"); |
|
|
else |
|
|
printf(", %d%% packet loss\n", |
|
|
(int) (((ntransmitted-nreceived)*100) / |
|
|
ntransmitted)); |
|
|
if (nreceived && timing) |
|
|
printf("round-trip (ms) min/avg/max = %d/%d/%d\n", |
|
|
tmin, tsum / nreceived, tmax); |
|
|
fflush(stdout); |
|
|
if (nreceived) |
|
|
exit(0); |
|
|
else |
|
|
exit(1); |
|
|
} |
|
|
|
|
|
static char *ttab[] = { |
|
|
"Echo Reply", /* ip + seq + udata */ |
|
|
"Dest Unreachable", /* net, host, proto, port, frag, sr + IP */ |
|
|
"Source Quench", /* IP */ |
|
|
"Redirect", /* redirect type, gateway, + IP */ |
|
|
"Echo", |
|
|
"Time Exceeded", /* transit, frag reassem + IP */ |
|
|
"Parameter Problem", /* pointer + IP */ |
|
|
"Timestamp", /* id + seq + three timestamps */ |
|
|
"Timestamp Reply", /* " */ |
|
|
"Info Request", /* id + sq */ |
|
|
"Info Reply" /* " */ |
|
|
}; |
|
|
|
|
|
/* |
|
|
* Print a descriptive string about an ICMP header. |
|
|
*/ |
|
|
pr_icmph( icp ) |
|
|
struct icmp *icp; |
|
|
{ |
|
|
switch( icp->icmp_type ) { |
|
|
case ICMP_ECHOREPLY: |
|
|
printf("Echo Reply\n"); |
|
|
/* XXX ID + Seq + Data */ |
|
|
break; |
|
|
case ICMP_UNREACH: |
|
|
switch( icp->icmp_code ) { |
|
|
case ICMP_UNREACH_NET: |
|
|
printf("Destination Network Unreachable\n"); |
|
|
break; |
|
|
case ICMP_UNREACH_HOST: |
|
|
printf("Destination Host Unreachable\n"); |
|
|
break; |
|
|
case ICMP_UNREACH_PROTOCOL: |
|
|
printf("Destination Protocol Unreachable\n"); |
|
|
break; |
|
|
case ICMP_UNREACH_PORT: |
|
|
printf("Destination Port Unreachable\n"); |
|
|
break; |
|
|
case ICMP_UNREACH_NEEDFRAG: |
|
|
printf("Fragmentation needed and DF set\n"); |
|
|
break; |
|
|
case ICMP_UNREACH_SRCFAIL: |
|
|
printf("Source Route Failed\n"); |
|
|
break; |
|
|
default: |
|
|
printf("Dest Unreachable, Bad Code: 0x%x\n", icp->icmp_code ); |
|
|
break; |
|
|
} |
|
|
/* Print returned IP header information */ |
|
|
pr_retip( icp->icmp_data ); |
|
|
break; |
|
|
case ICMP_SOURCEQUENCH: |
|
|
printf("Source Quench\n"); |
|
|
pr_retip( icp->icmp_data ); |
|
|
break; |
|
|
case ICMP_REDIRECT: |
|
|
switch( icp->icmp_code ) { |
|
|
case ICMP_REDIRECT_NET: |
|
|
printf("Network Redirect"); |
|
|
break; |
|
|
case ICMP_REDIRECT_HOST: |
|
|
printf("Host Redirect"); |
|
|
break; |
|
|
case ICMP_REDIRECT_TOSNET: |
|
|
printf("Type of Service and Network Redirect"); |
|
|
break; |
|
|
case ICMP_REDIRECT_TOSHOST: |
|
|
printf("Type of Service and Host Redirect"); |
|
|
break; |
|
|
default: |
|
|
printf("Redirect, Bad Code: 0x%x", icp->icmp_code ); |
|
|
break; |
|
|
} |
|
|
printf(" (New addr: 0x%08x)\n", icp->icmp_hun.ih_gwaddr ); |
|
|
pr_retip( icp->icmp_data ); |
|
|
break; |
|
|
case ICMP_ECHO: |
|
|
printf("Echo Request\n"); |
|
|
/* XXX ID + Seq + Data */ |
|
|
break; |
|
|
case ICMP_TIMXCEED: |
|
|
switch( icp->icmp_code ) { |
|
|
case ICMP_TIMXCEED_INTRANS: |
|
|
printf("Time to live exceeded in transit\n"); |
|
|
break; |
|
|
case ICMP_TIMXCEED_REASS: |
|
|
printf("Fragment reassembly time exceeded\n"); |
|
|
break; |
|
|
default: |
|
|
printf("Time exceeded, Bad Code: 0x%x\n", icp->icmp_code ); |
|
|
break; |
|
|
} |
|
|
pr_retip( icp->icmp_data ); |
|
|
break; |
|
|
case ICMP_PARAMPROB: |
|
|
switch( icp->icmp_code ) { |
|
|
case 0: |
|
|
printf("Parameter problem: error detected at byte 0x%02x\n", |
|
|
icp->icmp_hun.ih_pptr ); |
|
|
default: |
|
|
printf("Unspecified parameter problem\n"); |
|
|
} |
|
|
pr_retip( icp->icmp_data ); |
|
|
break; |
|
|
case ICMP_TSTAMP: |
|
|
printf("Timestamp\n"); |
|
|
/* XXX ID + Seq + 3 timestamps */ |
|
|
break; |
|
|
case ICMP_TSTAMPREPLY: |
|
|
printf("Timestamp Reply\n"); |
|
|
/* XXX ID + Seq + 3 timestamps */ |
|
|
break; |
|
|
case ICMP_IREQ: |
|
|
printf("Information Request\n"); |
|
|
/* XXX ID + Seq */ |
|
|
break; |
|
|
case ICMP_IREQREPLY: |
|
|
printf("Information Reply\n"); |
|
|
/* XXX ID + Seq */ |
|
|
break; |
|
|
case ICMP_MASKREQ: |
|
|
printf("Address Mask Request\n"); |
|
|
break; |
|
|
case ICMP_MASKREPLY: |
|
|
printf("Address Mask Reply\n"); |
|
|
break; |
|
|
default: |
|
|
printf("Bad ICMP type: 0x%x\n", icp->icmp_type); |
|
|
} |
|
|
} |
|
|
|
|
|
/* |
|
|
* Print an IP header with options. |
|
|
*/ |
|
|
pr_iph( ip ) |
|
|
struct ip *ip; |
|
|
{ |
|
|
int hlen; |
|
|
unsigned char *cp; |
|
|
|
|
|
hlen = ip->ip_hl << 2; |
|
|
cp = (unsigned char *)ip + 20; /* point to options */ |
|
|
|
|
|
printf("Vr HL TOS Len ID Flg Off TTL Pro Cksm Src Dst Data\n"); |
|
|
printf("%1x %1x %02x %04x %04x %1x %04x %02x %02x %04x %08x %08x", |
|
|
ip->ip_v, ip->ip_hl, ip->ip_tos, ip->ip_len, ip->ip_id, |
|
|
((ip->ip_off)&0xe000)>>13, (ip->ip_off)&0x1fff, ip->ip_ttl, ip->ip_p, |
|
|
ip->ip_sum, ntohl(ip->ip_src.s_addr), ntohl(ip->ip_dst.s_addr)); |
|
|
/* dump and option bytes */ |
|
|
while( hlen-- > 20 ) { |
|
|
printf( "%02x", *cp++ ); |
|
|
} |
|
|
printf("\n"); |
|
|
} |
|
|
|
|
|
/* |
|
|
* Return an ascii host address |
|
|
* as a dotted quad and optionally with a hostname |
|
|
*/ |
|
|
char * |
|
|
pr_addr( l ) |
|
|
unsigned long l; |
|
|
{ |
|
|
struct hostent *hp; |
|
|
static char buf[80]; |
|
|
|
|
|
if((pingflags & PING_NUMERIC) || |
|
|
(hp = gethostbyaddr(&l, 4, AF_INET)) == NULL ) |
|
|
sprintf( buf, "%s", inet_ntoa(l) ); |
|
|
else |
|
|
sprintf( buf, "%s (%s)", hp->h_name, inet_ntoa(l) ); |
|
|
|
|
|
return( buf ); |
|
|
} |
|
|
|
|
|
/* |
|
|
* Dump some info on a returned (via ICMP) IP packet. |
|
|
*/ |
|
|
pr_retip( ip ) |
|
|
struct ip *ip; |
|
|
{ |
|
|
int hlen; |
|
|
unsigned char *cp; |
|
|
|
|
|
pr_iph( ip ); |
|
|
hlen = ip->ip_hl << 2; |
|
|
cp = (unsigned char *)ip + hlen; |
|
|
|
|
|
if( ip->ip_p == 6 ) { |
|
|
printf( "TCP: from port %d, to port %d (decimal)\n", |
|
|
(*cp*256+*(cp+1)), (*(cp+2)*256+*(cp+3)) ); |
|
|
} else if( ip->ip_p == 17 ) { |
|
|
printf( "UDP: from port %d, to port %d (decimal)\n", |
|
|
(*cp*256+*(cp+1)), (*(cp+2)*256+*(cp+3)) ); |
|
|
} |
|
|
} |
|
|
//E*O*F newping.c// |
|
|
|
|
|
exit 0 |