Código-fonte do Ping para UNIX escrito por Mike Muuss (http://ftp.arl.army.mil/pub/ping.shar)
# 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 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment