4 * Using the InterNet Control Message Protocol (ICMP) "ECHO" facility,
5 * measure round-trip-delays and packet loss across network paths.
9 * U. S. Army Ballistic Research Laboratory
15 * Public Domain. Distribution Unlimited.
17 * More statistics could always be gathered.
20 /****** netutil.doc/ping ****************************************************
23 ping - send ICMP ECHO_REQUEST packets to network hosts
26 ping [-dfnqrvR] [-c count] [-i wait] [-l preload] [-p pattern]
27 [-s packetsize] [-L [ hosts ]] host
30 Ping uses the ICMP protocol's mandatory ECHO_REQUEST datagram to
31 elicit an ICMP ECHO_RESPONSE from a host or gateway. ECHO_REQUEST
32 datagrams (``pings'') have an IP and ICMP header, followed by a
33 ``struct timeval'' and then an arbitrary number of ``pad'' bytes
34 used to fill out the packet. The options are as follows: Other
38 Stop after sending (and receiving) count ECHO_RESPONSE
41 -d Set the SO_DEBUG option on the socket being used.
43 -f Flood ping. Outputs packets as fast as they come back or
44 one hundred times per second, whichever is more. For every
45 ECHO_REQUEST sent a period ``.'' is printed, while for ever
46 ECHO_REPLY received a backspace is printed. This provides a
47 rapid display of how many packets are being dropped. Only
48 the super-user may use this option. This can be very hard
49 on a network and should be used with caution.
52 Wait wait seconds between sending each packet. The default
53 is to wait for one second between each packet. This option
54 is incompatible with the -f option.
57 Use loose routing IP option. Includes IPOPT_LSRR option in
58 the ECHO_REQUEST packet with all specified hosts in the
59 route. Many hosts wont support loose routing, such a host
60 can either ignore or return the loose routed ICMP packet in
61 the middle of the route.
64 If preload is specified, ping sends that many packets as
65 fast as possible before falling into its normal mode of
68 -n Numeric output only. No attempt will be made to lookup
69 symbolic names for host addresses.
72 You may specify up to 16 ``pad'' bytes to fill out the
73 packet you send. This is useful for diagnosing
74 data-dependent problems in a network. For example, ``-p
75 ff'' will cause the sent packet to be filled with all ones.
77 -q Quiet output. Nothing is displayed except the summary lines
78 at startup time and when finished.
80 -R Record route. Includes the RECORD_ROUTE option in the
81 ECHO_REQUEST packet and displays the route buffer on
82 returned packets. Note that the IP header is only large
83 enough for nine such routes. Many hosts ignore or discard
86 -r Bypass the normal routing tables and send directly to a host
87 on an attached network. If the host is not on a
88 directly-attached network, an error is returned. This
89 option can be used to ping a local host through an interface
90 that has no route through it.
93 Specifies the number of data bytes to be sent. The default
94 is 56, which translates into 64 ICMP data bytes when
95 combined with the 8 bytes of ICMP header data.
97 -v Verbose output. ICMP packets other than ECHO_RESPONSE that
98 are received are listed.
100 When using ping for fault isolation, it should first be run on the
101 local host, to verify that the local network interface is up and
102 running. Then, hosts and gateways further and further away should
103 be ``pinged''. Round-trip times and packet loss statistics are
104 computed. If duplicate packets are received, they are not included
105 in the packet loss calculation, although the round trip time of
106 these packets is used in calculating the minimum/average/maximum
107 round-trip time numbers. When the specified number of packets have
108 been sent (and received) or if the program is terminated with a
109 SIGINT, a brief summary is displayed.
111 This program is intended for use in network testing, measurement and
112 management. Because of the load it can impose on the network, it is
113 unwise to use ping during normal operations or from automated
117 An IP header without options is 20 bytes. An ICMP ECHO_REQUEST
118 packet contains an additional 8 bytes worth of ICMP header followed
119 by an arbitrary amount of data. When a packetsize is given, this
120 indicated the size of this extra piece of data (the default is 56).
121 Thus the amount of data received inside of an IP packet of type ICMP
122 ECHO_REPLY will always be 8 bytes more than the requested data space
125 If the data space is at least eight bytes large, ping uses the first
126 eight bytes of this space to include a timestamp which it uses in
127 the computation of round trip times. If less than eight bytes of
128 pad are specified, no round trip times are given.
130 DUPLICATE AND DAMAGED PACKETS
131 Ping will report duplicate and damaged packets. Duplicate packets
132 should never occur, and seem to be caused by inappropriate
133 link-level retransmissions. Duplicates may occur in many situations
134 and are rarely (if ever) a good sign, although the presence of low
135 levels of duplicates may not always be cause for alarm.
137 Damaged packets are obviously serious cause for alarm and often
138 indicate broken hardware somewhere in the ping packet's path (in the
139 network or in the hosts).
141 TRYING DIFFERENT DATA PATTERNS
142 The (inter)network layer should never treat packets differently
143 depending on the data contained in the data portion. Unfortunately,
144 data-dependent problems have been known to sneak into networks and
145 remain undetected for long periods of time. In many cases the
146 particular pattern that will have problems is something that doesn't
147 have sufficient ``transitions'', such as all ones or all zeros, or a
148 pattern right at the edge, such as almost all zeros. It isn't
149 necessarily enough to specify a data pattern of all zeros (for
150 example) on the command line because the pattern that is of interest
151 is at the data link level, and the relationship between what you
152 type and what the controllers transmit can be complicated.
154 This means that if you have a data-dependent problem you will
155 probably have to do a lot of testing to find it. If you are lucky,
156 you may manage to find a file that either can't be sent across your
157 network or that takes much longer to transfer than other similar
158 length files. You can then examine this file for repeated patterns
159 that you can test using the -p option of ping.
162 The TTL value of an IP packet represents the maximum number of IP
163 routers that the packet can go through before being thrown away. In
164 current practice you can expect each router in the Internet to
165 decrement the TTL field by exactly one.
167 The TCP/IP specification states that the TTL field for TCP packets
168 should be set to 60, but many systems use smaller values (4.3 BSD
169 uses 30, 4.2 used 15). AROSTCP normally uses TTL value 30.
171 The maximum possible value of this field is 255, and most systems
172 set the TTL field of ICMP ECHO_REQUEST packets to 255. This is why
173 you will find you can ``ping'' some hosts, but not reach them with
176 In normal operation ping prints the ttl value from the packet it re-
177 ceives. When a remote system receives a ping packet, it can do one
178 of three things with the TTL field in its response:
180 · Not change it; this is what Berkeley Unix systems did before the
181 4.3BSD-Tahoe release. In this case the TTL value in the
182 received packet will be 255 minus the number of routers in the
185 · Set it to 255; this is what AROSTCP and current (as of 1994)
186 Berkeley Unix systems do. In this case the TTL value in the
187 received packet will be 255 minus the number of routers in the
188 path from the remote system to the pinging host.
190 · Set it to some other value. Some machines use the same value
191 for ICMP packets that they use for TCP packets, for example
192 either 30 or 60. Others may use completely wild values.
194 LOOSE SOURCE ROUTING DETAILS
195 When a packet is routed with loose routing in IP, the destination
196 address of datagram is originally set to the first address in the
197 routing list. When the datagram reaches its destination, the
198 destination address is changed to the next address in the list and
199 the datagram is routed to that destination. After the whole routing
200 list is exhausted, the datagram is handled to upper-level protocols.
202 The loose routing options can be ignored by hosts between the
203 gateways in the loose routing list. However, if the host in the
204 list don't understand loose routing, it may think that the datagram
205 is destined to it and respond to it. Also, many hosts simply drop
206 the packets with IP options.
209 Many Hosts and Gateways ignore the RECORD_ROUTE and
210 LOOSE_SOURCE_ROUTING options.
212 The maximum IP header length is too small for options like
213 RECORD_ROUTE to be completely useful. There's not much that that
214 can be done about this, however.
216 Flood pinging is not recommended in general, and flood pinging the
217 broadcast address should only be done under very controlled
224 Mike Muuss, U. S. Army Ballistic Research Laboratory, December, 1983
226 The ping command appeared in 4.3BSD.
228 The loose routing and working record route options were added by
229 Pekka Pessi, AmiTCP/IP Group, Helsinki Univ. of Technology.
231 *****************************************************************************
238 #include <proto/socket.h>
240 #define ioctl IoctlSocket
242 #include <sys/param.h>
243 #include <sys/socket.h>
244 #include <sys/time.h>
251 /*#include <sys/file.h>*/
252 /*#include <sys/signal.h>*/
255 #include <netinet/in_systm.h>
256 #include <netinet/in.h>
257 #include <netinet/ip.h>
258 #include <netinet/ip_icmp.h>
259 #include <netinet/ip_var.h>
261 #include <arpa/inet.h>
265 #include <sys/errno.h>
269 #define DEFDATALEN (64 - 8) /* default data length */
271 #define MAXICMPLEN 76
272 #define MAXPACKET (65536 - 60 - 8)/* max packet size */
273 #define MAXWAIT 10 /* max seconds to wait for response */
274 #define NROUTES 9 /* number of record route slots */
276 #define A(bit) rcvd_tbl[(bit)>>3] /* identify byte in array */
277 #define B(bit) (1 << ((bit) & 0x07)) /* identify bit in byte */
278 #define SET(bit) (A(bit) |= B(bit))
279 #define CLR(bit) (A(bit) &= (~B(bit)))
280 #define TST(bit) (A(bit) & B(bit))
282 /* various options */
284 #define F_FLOOD 0x001
285 #define F_INTERVAL 0x002
286 #define F_NUMERIC 0x004
287 #define F_PINGFILLED 0x008
288 #define F_QUIET 0x010
289 #define F_RROUTE 0x020
290 #define F_SO_DEBUG 0x040
291 #define F_SO_DONTROUTE 0x080
292 #define F_VERBOSE 0x100
293 #define F_LOOSEROUTE 0x200
296 #define LONG_MAX 0xffffffff
300 * MAX_DUP_CHK is the number of bits in received table, i.e. the maximum
301 * number of received sequence numbers we can keep track of. Change 128
302 * to 8192 for complete accuracy...
304 #define MAX_DUP_CHK (8 * 128)
305 int mx_dup_ck
= MAX_DUP_CHK
;
306 char rcvd_tbl
[MAX_DUP_CHK
/ 8];
308 struct sockaddr whereto
; /* who to ping */
309 int datalen
= DEFDATALEN
;
310 int s
= -1; /* socket file descriptor */
312 char BSPACE
= '\b'; /* characters written for flood */
315 long ident
; /* process id to identify our packets */
318 long npackets
; /* max packets to transmit */
319 long nreceived
; /* # of packets we got back */
320 long nrepeats
; /* number of duplicates */
321 long ntransmitted
; /* sequence # for outbound packets = #sent */
322 int interval
= 1; /* interval between packets */
325 int timing
; /* flag to do timing */
326 unsigned long tmin
= LONG_MAX
; /* minimum round trip time */
327 unsigned long tmax
; /* maximum round trip time */
328 unsigned long tsum
; /* sum of all times, for doing average */
330 char *pr_addr(u_long l
);
331 void catcher(void), pinger(void), finish(void), usage(void);
332 void pr_pack(char *buf
, int cc
, struct sockaddr_in
*from
);
333 void pr_icmph(struct icmp
*icp
);
334 void pr_iph(struct ip
*ip
);
335 void pr_retip(struct ip
*ip
);
336 void fill(char *bp
, char *patp
);
337 int in_cksum(u_short
*addr
, int len
);
338 void tvsub(register struct timeval
*out
, register struct timeval
*in
);
339 VOID
CleanUpExit(LONG error
);
343 * Other Amiga dependent stuff
346 #include <clib/exec_protos.h>
347 #include <pragmas/exec_sysbase_pragmas.h>
348 extern struct ExecBase
*SysBase
;
350 /* Disable ^C signaling */
351 void __chkabort(void) {}
354 #include <devices/timer.h>
356 #include <proto/exec.h>
357 #include <proto/timer.h>
359 struct MsgPort
*timerport
= NULL
;
360 struct timerequest
*timermsg
= NULL
;
362 #define TimerBase (timermsg->tr_node.io_Device)
364 #define SOCKET_VERSION 3
365 struct Library
*SocketBase
;
366 const TEXT version
[] = "$VER: ping 3.10 (14.10.2005)";
367 const TEXT socket_name
[] = "bsdsocket.library";
374 if (!CheckIO((struct IORequest
*)timermsg
)) {
375 AbortIO((struct IORequest
*)timermsg
);
376 WaitIO((struct IORequest
*)timermsg
);
378 CloseDevice((struct IORequest
*)timermsg
);
381 DeleteIORequest((APTR
)timermsg
);
385 DeleteMsgPort(timerport
);
395 extern int errno
, optind
;
397 struct timeval timeout
;
399 struct sockaddr_in
*to
;
400 struct protoent
*proto
;
402 int ch
, fdmask
, hold
, packlen
, preload
;
403 u_char
*datap
, *packet
;
404 char *target
, hnamebuf
[MAXHOSTNAMELEN
];
406 u_char rspace
[3 + 4 * NROUTES
+ 1]; /* record route space */
412 SocketBase
= OpenLibrary(socket_name
, SOCKET_VERSION
);
413 if(SocketBase
== NULL
) {
414 fprintf(stderr
, "ping: cannot open bsdsocket.library version 3.\n");
417 SetErrnoPtr(&errno
, sizeof(errno
));
419 outpack
= malloc(MAXPACKET
);
420 if (outpack
== NULL
) {
425 datap
= &outpack
[8 + sizeof(struct timeval
)];
426 while ((ch
= getopt(argc
, argv
, "LRc:dfh:i:l:np:qrs:v")) != EOF
)
429 npackets
= atoi(optarg
);
431 (void)fprintf(stderr
, "ping: bad number of packets to transmit.\n");
436 options
|= F_SO_DEBUG
;
441 (void)fprintf(stderr
, "ping: %s\n", strerror(EPERM
));
446 setbuf(stdout
, (char *)NULL
);
448 case 'i': /* wait between sending packets */
449 interval
= atoi(optarg
);
451 (void)fprintf(stderr
, "ping: bad timing interval.\n");
454 options
|= F_INTERVAL
;
457 options
|= F_LOOSEROUTE
;
460 preload
= atoi(optarg
);
462 (void)fprintf(stderr
, "ping: bad preload value.\n");
467 options
|= F_NUMERIC
;
469 case 'p': /* fill buffer with user pattern */
470 options
|= F_PINGFILLED
;
471 fill((char *)datap
, optarg
);
480 options
|= F_SO_DONTROUTE
;
482 case 's': /* size of packet to send */
483 datalen
= atoi(optarg
);
484 if (datalen
> MAXPACKET
) {
485 (void)fprintf(stderr
, "ping: packet size too large.\n");
489 (void)fprintf(stderr
, "ping: illegal packet size.\n");
494 options
|= F_VERBOSE
;
502 if (argc
< 1 || (options
& F_LOOSEROUTE
) == 0 && argc
> 1)
505 if ((options
& (F_LOOSEROUTE
| F_RROUTE
)) == (F_LOOSEROUTE
| F_RROUTE
)) {
506 fprintf(stderr
, "ping: -L and -R options cannot be used concurrently\n");
513 if (options
& F_LOOSEROUTE
) {
515 rspace
[IPOPT_OPTVAL
] = IPOPT_LSRR
;
516 rspace
[IPOPT_OLEN
] = 3;
517 rspace
[IPOPT_OFFSET
] = IPOPT_MINOFF
;
518 cp
= rspace
+ IPOPT_OFFSET
+ 1;
520 (void)fprintf(stderr
, "ping: source routing not "
521 "available in this implementation.\n");
523 #endif /* IP_OPTIONS */
526 while (target
= *argv
++) {
527 bzero((char *)&whereto
, sizeof(struct sockaddr
));
528 to
= (struct sockaddr_in
*)&whereto
;
530 to
->sin_len
= sizeof(*to
);
532 to
->sin_family
= AF_INET
;
533 to
->sin_addr
.s_addr
= inet_addr(target
);
534 if (to
->sin_addr
.s_addr
!= (u_int
)-1)
537 hp
= gethostbyname(target
);
539 fprintf(stderr
, "ping: unknown host %s\n", target
);
542 to
->sin_family
= hp
->h_addrtype
;
543 bcopy(hp
->h_addr
, (caddr_t
)&to
->sin_addr
, hp
->h_length
);
544 (void)strncpy(hnamebuf
, hp
->h_name
, sizeof(hnamebuf
) - 1);
549 if (options
& F_LOOSEROUTE
) {
550 if (rspace
+ sizeof(rspace
) - 4 < cp
) {
551 fprintf(stderr
, "ping: too many hops for "
552 "source routing %s\n", target
);
555 *cp
++ = (to
->sin_addr
.s_addr
>> 24);
556 *cp
++ = (to
->sin_addr
.s_addr
>> 16);
557 *cp
++ = (to
->sin_addr
.s_addr
>> 8);
558 *cp
++ = (to
->sin_addr
.s_addr
>> 0);
559 rspace
[IPOPT_OLEN
] += 4;
565 if (options
& F_FLOOD
&& options
& F_INTERVAL
) {
566 (void)fprintf(stderr
, "ping: -f and -i incompatible options.\n");
570 if (datalen
>= sizeof(struct timeval
)) /* can we time transfer */
572 packlen
= datalen
+ MAXIPLEN
+ MAXICMPLEN
;
573 if (!(packet
= (u_char
*)malloc((u_int
)packlen
))) {
574 (void)fprintf(stderr
, "ping: out of memory.\n");
577 if (!(options
& F_PINGFILLED
))
578 for (i
= 8; i
< datalen
; ++i
)
581 ident
= getpid() & 0xFFFF;
583 if (!(proto
= getprotobyname("icmp"))) {
584 (void)fprintf(stderr
, "ping: unknown protocol icmp.\n");
591 timerport
= CreateMsgPort();
593 (void)fprintf(stderr
, "ping: could not create timer port.\n");
596 timermask
= 1<<timerport
->mp_SigBit
;
598 timermsg
= (APTR
)CreateIORequest(timerport
, sizeof(*timermsg
));
600 (void)fprintf(stderr
, "ping: could not create timer message.\n");
604 if (notopen
= OpenDevice("timer.device",
605 #if (AROS_FLAVOUR & AROS_FLAVOUR_EMULATION)
606 // UNIT_MICROHZ isn't available on AROS/hosted
611 (struct IORequest
*)timermsg
, 0)) {
612 (void)fprintf(stderr
, "ping: could not open timer device.\n");
616 timermsg
->tr_node
.io_Command
= TR_ADDREQUEST
;
617 timermsg
->tr_time
.tv_secs
= 1L;
618 timermsg
->tr_time
.tv_micro
= 0L;
619 /* don't confuse CheckIO */
620 timermsg
->tr_node
.io_Message
.mn_Node
.ln_Type
= NT_REPLYMSG
;
621 SetSocketSignals(timermask
| SIGBREAKF_CTRL_C
, 0L, 0L);
624 if ((s
= socket(AF_INET
, SOCK_RAW
, proto
->p_proto
)) < 0) {
625 perror("ping: socket");
629 if (options
& F_SO_DEBUG
)
630 (void)setsockopt(s
, SOL_SOCKET
, SO_DEBUG
, (char *)&hold
,
632 if (options
& F_SO_DONTROUTE
)
633 (void)setsockopt(s
, SOL_SOCKET
, SO_DONTROUTE
, (char *)&hold
,
637 if (options
& F_LOOSEROUTE
) {
638 /* pad to long word */
639 rspace
[rspace
[IPOPT_OLEN
]] = IPOPT_EOL
;
640 if (setsockopt(s
, IPPROTO_IP
, IP_OPTIONS
, rspace
,
641 rspace
[IPOPT_OLEN
] + 1) < 0) {
642 perror("ping: source routing");
648 /* record route option */
649 if (options
& F_RROUTE
) {
651 rspace
[IPOPT_OPTVAL
] = IPOPT_RR
;
652 rspace
[IPOPT_OLEN
] = sizeof(rspace
)-1;
653 rspace
[IPOPT_OFFSET
] = IPOPT_MINOFF
;
654 rspace
[rspace
[IPOPT_OLEN
]] = IPOPT_EOL
;
655 if (setsockopt(s
, IPPROTO_IP
, IP_OPTIONS
, rspace
,
656 sizeof(rspace
)) < 0) {
657 perror("ping: record route");
661 (void)fprintf(stderr
,
662 "ping: record route not available in this implementation.\n");
664 #endif /* IP_OPTIONS */
668 * When pinging the broadcast address, you can get a lot of answers.
669 * Doing something so evil is useful if you are trying to stress the
670 * ethernet, or just want to fill the arp cache to get some stuff for
674 (void)setsockopt(s
, SOL_SOCKET
, SO_RCVBUF
, (char *)&hold
,
677 if (to
->sin_family
== AF_INET
)
678 (void)printf("PING %s (%s): %d data bytes\n", hostname
,
679 inet_ntoa(*(struct in_addr
*)&to
->sin_addr
.s_addr
),
682 (void)printf("PING %s: %d data bytes\n", hostname
, datalen
);
685 (void)signal(SIGINT
, finish
);
686 (void)signal(SIGALRM
, catcher
);
689 while (preload
--) /* fire off them quickies */
692 if ((options
& F_FLOOD
) == 0)
693 catcher(); /* start things going */
696 struct sockaddr_in from
;
701 /* Check for special signals */
702 ULONG sm
= SetSignal(0L, timermask
| SIGBREAKF_CTRL_C
);
703 if (sm
& SIGBREAKF_CTRL_C
)
705 if (sm
& timermask
&& GetMsg(timerport
))
709 if (options
& F_FLOOD
) {
712 timeout
.tv_usec
= 10000;
714 if (select(s
+ 1, (fd_set
*)&fdmask
, (fd_set
*)NULL
,
715 (fd_set
*)NULL
, &timeout
) < 1)
718 fromlen
= sizeof(from
);
719 if ((cc
= recvfrom(s
, (char *)packet
, packlen
, 0,
720 (struct sockaddr
*)&from
, &fromlen
)) < 0) {
723 perror("ping: recvfrom");
726 pr_pack((char *)packet
, cc
, &from
);
727 if (npackets
&& nreceived
>= npackets
)
737 * This routine causes another PING to be transmitted, and then
738 * schedules another SIGALRM for 1 second from now.
741 * Our sense of time will slowly skew (i.e., packets will not be
742 * launched exactly at 1-second intervals). This does not affect the
743 * quality of the delay and loss statistics.
746 * This routine uses timer.device in Amiga implementation instead
753 static int waittime
= 0;
760 if (!npackets
|| ntransmitted
< npackets
) {
761 timermsg
->tr_time
.tv_sec
= interval
;
762 SendIO((struct IORequest
*)timermsg
);
765 waittime
= 2 * tmax
/ 1000;
770 timermsg
->tr_time
.tv_sec
= waittime
;
771 SendIO((struct IORequest
*)timermsg
);
777 (void)signal(SIGALRM
, catcher
);
778 if (!npackets
|| ntransmitted
< npackets
)
779 alarm((u_int
)interval
);
782 waittime
= 2 * tmax
/ 1000;
787 (void)signal(SIGALRM
, finish
);
788 (void)alarm((u_int
)waittime
);
795 * Compose and transmit an ICMP ECHO REQUEST packet. The IP packet
796 * will be added on by the kernel. The ID field is our process ID,
797 * and the sequence number is an ascending integer. The first 8 bytes
798 * of the data portion are used to hold a UNIX "timeval" struct in native
799 * byte-order, to compute the round-trip time.
804 register struct icmp
*icp
;
808 icp
= (struct icmp
*)outpack
;
809 icp
->icmp_type
= ICMP_ECHO
;
812 icp
->icmp_seq
= ntransmitted
++;
813 icp
->icmp_id
= ident
; /* ID */
815 CLR(icp
->icmp_seq
% mx_dup_ck
);
819 /* (void)ReadEClock((struct EClockVal *)&outpack[8]);*/ /* NC */
820 (void)GetSysTime((struct timeval
*)&outpack
[8]);
822 (void)gettimeofday((struct timeval
*)&outpack
[8],
823 (struct timezone
*)NULL
);
825 cc
= datalen
+ 8; /* skips ICMP portion */
827 /* compute ICMP checksum here */
828 icp
->icmp_cksum
= in_cksum((u_short
*)icp
, cc
);
830 i
= sendto(s
, (char *)outpack
, cc
, 0, &whereto
,
831 sizeof(struct sockaddr
));
833 if (i
< 0 || i
!= cc
) {
835 perror("ping: sendto");
836 (void)printf("ping: wrote %s %d chars, ret=%d\n",
839 if (!(options
& F_QUIET
) && options
& F_FLOOD
)
840 (void)write(1, &DOT
, 1);
845 * Print out the packet, if it came from us. This logic is necessary
846 * because ALL readers of the ICMP socket get a copy of ALL ICMP packets
847 * which arrive ('tis only fair). This permits multiple copies of this
848 * program to be run without having intermingled output (or statistics!).
851 pr_pack(buf
, cc
, from
)
854 struct sockaddr_in
*from
;
856 register struct icmp
*icp
;
859 register u_char
*cp
,*dp
;
860 static int old_rrlen
;
861 static char old_rr
[MAX_IPOPTLEN
];
863 struct timeval tv
, *tp
;
868 /* ULONG efreq = ReadEClock((struct EClockVal *)&tv);*/ /* NC */
869 GetSysTime((struct timeval
*)&tv
);
871 (void)gettimeofday(&tv
, (struct timezone
*)NULL
);
873 /* Check the IP header */
874 ip
= (struct ip
*)buf
;
875 hlen
= ip
->ip_hl
<< 2;
876 if (cc
< hlen
+ ICMP_MINLEN
) {
877 if (options
& F_VERBOSE
)
878 (void)fprintf(stderr
,
879 "ping: packet too short (%d bytes) from %s\n", cc
,
880 inet_ntoa(*(struct in_addr
*)&from
->sin_addr
.s_addr
));
884 /* Now the ICMP part */
886 icp
= (struct icmp
*)(buf
+ hlen
);
887 if (icp
->icmp_type
== ICMP_ECHOREPLY
) {
888 if (icp
->icmp_id
!= ident
)
889 return; /* 'Twas not our ECHO */
893 tp
= (struct timeval
*)&icp
->icmp_ip
;
895 tp
= (struct timeval
*)icp
->icmp_data
;
897 #ifndef AMIGA /* NC */
898 /* EClockVal is actually an unsigned long long */
899 if (tv
.tv_micro
< tp
->tv_micro
)
901 tv
.tv_micro
-= tp
->tv_micro
;
902 tv
.tv_secs
-= tp
->tv_secs
;
903 triptime
= tv
.tv_micro
/ (efreq
/ 1000);
905 triptime
+= tv
.tv_sec
* 250 * ((1<<30) / efreq
);
908 triptime
= tv
.tv_sec
* 1000 + (tv
.tv_usec
/ 1000);
917 if (TST(icp
->icmp_seq
% mx_dup_ck
)) {
922 SET(icp
->icmp_seq
% mx_dup_ck
);
926 if (options
& F_QUIET
)
929 if (options
& F_FLOOD
)
930 (void)write(1, &BSPACE
, 1);
932 (void)printf("%d bytes from %s: icmp_seq=%u", cc
,
933 inet_ntoa(*(struct in_addr
*)&from
->sin_addr
.s_addr
),
935 (void)printf(" ttl=%d", ip
->ip_ttl
);
937 (void)printf(" time=%ld ms", triptime
);
939 (void)printf(" (DUP!)");
941 cp
= (u_char
*)&icp
->icmp_data
[8];
942 dp
= &outpack
[8 + sizeof(struct timeval
)];
943 for (i
= 8; i
< datalen
; ++i
, ++cp
, ++dp
) {
945 (void)printf("\nwrong data byte #%d should be 0x%x but was 0x%x",
947 cp
= (u_char
*)&icp
->icmp_data
[0];
948 for (i
= 8; i
< datalen
; ++i
, ++cp
) {
950 (void)printf("\n\t");
951 (void)printf("%x ", *cp
);
958 /* We've got something other than an ECHOREPLY */
959 if (!(options
& F_VERBOSE
))
961 (void)printf("%d bytes from %s: ", cc
,
962 pr_addr(from
->sin_addr
.s_addr
));
966 /* Display any IP options */
967 /* The LSRR and RR len handling was broken (?) //ppessi */
968 cp
= (u_char
*)buf
+ sizeof(struct ip
);
970 for (; hlen
> (int)sizeof(struct ip
); --hlen
, ++cp
)
977 (void)printf(*cp
== IPOPT_LSRR
?
978 "\nLSRR: " : "\nSSRR: ");
982 if (j
> IPOPT_MINOFF
)
989 (void)printf("\t0.0.0.0");
991 (void)printf("\t%s", pr_addr(ntohl(l
)));
993 if (j
< IPOPT_MINOFF
)
999 j
= *++cp
; /* get length */
1000 i
= *++cp
; /* and pointer */
1008 && cp
== (u_char
*)buf
+ sizeof(struct ip
) + 2
1009 && !bcmp((char *)cp
, old_rr
, i
)
1010 && !(options
& F_FLOOD
)) {
1011 (void)printf("\t(same route)");
1012 i
= ((i
+ 3) / 4) * 4;
1017 bcopy((char *)cp
, old_rr
, i
);
1018 (void)printf("\nRR: ");
1025 (void)printf("\t0.0.0.0");
1027 (void)printf("\t%s", pr_addr(ntohl(l
)));
1031 (void)putchar('\n');
1035 (void)printf("\nNOP");
1038 (void)printf("\nunknown option %x", *cp
);
1041 if (!(options
& F_FLOOD
)) {
1042 (void)putchar('\n');
1043 (void)fflush(stdout
);
1049 * Checksum routine for Internet Protocol family headers (C Version)
1056 register int nleft
= len
;
1057 register u_short
*w
= addr
;
1058 register int sum
= 0;
1062 * Our algorithm is simple, using a 32 bit accumulator (sum), we add
1063 * sequential 16 bit words to it, and at the end, fold back all the
1064 * carry bits from the top 16 bits into the lower 16 bits.
1071 /* mop up an odd byte, if necessary */
1073 *(u_char
*)(&answer
) = *(u_char
*)w
;
1077 /* add back carry outs from top 16 bits to low 16 bits */
1078 sum
= (sum
>> 16) + (sum
& 0xffff); /* add hi 16 to low 16 */
1079 sum
+= (sum
>> 16); /* add carry */
1080 answer
= ~sum
; /* truncate to 16 bits */
1086 * Subtract 2 timeval structs: out = out - in. Out is assumed to
1091 register struct timeval
*out
, *in
;
1093 if ((out
->tv_usec
-= in
->tv_usec
) < 0) {
1095 out
->tv_usec
+= 1000000;
1097 out
->tv_sec
-= in
->tv_sec
;
1102 * Print out statistics, and give up.
1107 (void)signal(SIGINT
, SIG_IGN
);
1108 (void)putchar('\n');
1109 (void)fflush(stdout
);
1110 (void)printf("--- %s ping statistics ---\n", hostname
);
1111 (void)printf("%ld packets transmitted, ", ntransmitted
);
1112 (void)printf("%ld packets received, ", nreceived
);
1114 (void)printf("+%ld duplicates, ", nrepeats
);
1116 if (nreceived
> ntransmitted
)
1117 (void)printf("-- somebody's printing up packets!");
1119 (void)printf("%d%% packet loss",
1120 (int) (((ntransmitted
- nreceived
) * 100) /
1122 (void)putchar('\n');
1123 if (nreceived
&& timing
)
1124 (void)printf("round-trip min/avg/max = %ld/%lu/%ld ms\n",
1125 tmin
, tsum
/ (nreceived
+ nrepeats
), tmax
);
1130 static char *ttab
[] = {
1131 "Echo Reply", /* ip + seq + udata */
1132 "Dest Unreachable", /* net, host, proto, port, frag, sr + IP */
1133 "Source Quench", /* IP */
1134 "Redirect", /* redirect type, gateway, + IP */
1136 "Time Exceeded", /* transit, frag reassem + IP */
1137 "Parameter Problem", /* pointer + IP */
1138 "Timestamp", /* id + seq + three timestamps */
1139 "Timestamp Reply", /* " */
1140 "Info Request", /* id + sq */
1141 "Info Reply" /* " */
1147 * Print a descriptive string about an ICMP header.
1153 switch(icp
->icmp_type
) {
1154 case ICMP_ECHOREPLY
:
1155 (void)printf("Echo Reply\n");
1156 /* XXX ID + Seq + Data */
1159 switch(icp
->icmp_code
) {
1160 case ICMP_UNREACH_NET
:
1161 (void)printf("Destination Net Unreachable\n");
1163 case ICMP_UNREACH_HOST
:
1164 (void)printf("Destination Host Unreachable\n");
1166 case ICMP_UNREACH_PROTOCOL
:
1167 (void)printf("Destination Protocol Unreachable\n");
1169 case ICMP_UNREACH_PORT
:
1170 (void)printf("Destination Port Unreachable\n");
1172 case ICMP_UNREACH_NEEDFRAG
:
1173 (void)printf("frag needed and DF set\n");
1175 case ICMP_UNREACH_SRCFAIL
:
1176 (void)printf("Source Route Failed\n");
1179 (void)printf("Dest Unreachable, Bad Code: %d\n",
1183 /* Print returned IP header information */
1185 pr_retip(&icp
->icmp_ip
);
1187 pr_retip((struct ip
*)icp
->icmp_data
);
1190 case ICMP_SOURCEQUENCH
:
1191 (void)printf("Source Quench\n");
1193 pr_retip(&icp
->icmp_ip
);
1195 pr_retip((struct ip
*)icp
->icmp_data
);
1199 switch(icp
->icmp_code
) {
1200 case ICMP_REDIRECT_NET
:
1201 (void)printf("Redirect Network");
1203 case ICMP_REDIRECT_HOST
:
1204 (void)printf("Redirect Host");
1206 case ICMP_REDIRECT_TOSNET
:
1207 (void)printf("Redirect Type of Service and Network");
1209 case ICMP_REDIRECT_TOSHOST
:
1210 (void)printf("Redirect Type of Service and Host");
1213 (void)printf("Redirect, Bad Code: %d", icp
->icmp_code
);
1216 (void)printf("(New addr: 0x%08lx)\n", icp
->icmp_gwaddr
.s_addr
);
1218 pr_retip(&icp
->icmp_ip
);
1220 pr_retip((struct ip
*)icp
->icmp_data
);
1224 (void)printf("Echo Request\n");
1225 /* XXX ID + Seq + Data */
1228 switch(icp
->icmp_code
) {
1229 case ICMP_TIMXCEED_INTRANS
:
1230 (void)printf("Time to live exceeded\n");
1232 case ICMP_TIMXCEED_REASS
:
1233 (void)printf("Frag reassembly time exceeded\n");
1236 (void)printf("Time exceeded, Bad Code: %d\n",
1241 pr_retip(&icp
->icmp_ip
);
1243 pr_retip((struct ip
*)icp
->icmp_data
);
1246 case ICMP_PARAMPROB
:
1247 (void)printf("Parameter problem: pointer = 0x%02x\n",
1248 icp
->icmp_hun
.ih_pptr
);
1250 pr_retip(&icp
->icmp_ip
);
1252 pr_retip((struct ip
*)icp
->icmp_data
);
1256 (void)printf("Timestamp\n");
1257 /* XXX ID + Seq + 3 timestamps */
1259 case ICMP_TSTAMPREPLY
:
1260 (void)printf("Timestamp Reply\n");
1261 /* XXX ID + Seq + 3 timestamps */
1264 (void)printf("Information Request\n");
1267 case ICMP_IREQREPLY
:
1268 (void)printf("Information Reply\n");
1273 (void)printf("Address Mask Request\n");
1276 #ifdef ICMP_MASKREPLY
1277 case ICMP_MASKREPLY
:
1278 (void)printf("Address Mask Reply\n");
1282 (void)printf("Bad ICMP type: %d\n", icp
->icmp_type
);
1288 * Print an IP header with options.
1297 hlen
= ip
->ip_hl
<< 2;
1298 cp
= (u_char
*)ip
+ 20; /* point to options */
1300 (void)printf("Vr HL TOS Len ID Flg off TTL Pro cks Src Dst Data\n");
1301 (void)printf(" %1x %1x %02x %04x %04x",
1302 ip
->ip_v
, ip
->ip_hl
, ip
->ip_tos
, ip
->ip_len
, ip
->ip_id
);
1303 (void)printf(" %1x %04x", ((ip
->ip_off
) & 0xe000) >> 13,
1304 (ip
->ip_off
) & 0x1fff);
1305 (void)printf(" %02x %02x %04x", ip
->ip_ttl
, ip
->ip_p
, ip
->ip_sum
);
1306 (void)printf(" %s ", inet_ntoa(*(struct in_addr
*)&ip
->ip_src
.s_addr
));
1307 (void)printf(" %s ", inet_ntoa(*(struct in_addr
*)&ip
->ip_dst
.s_addr
));
1308 /* dump and option bytes */
1309 while (hlen
-- > 20) {
1310 (void)printf("%02x", *cp
++);
1312 (void)putchar('\n');
1317 * Return an ascii host address as a dotted quad and optionally with
1325 static char buf
[80];
1327 struct in_addr addr
;
1333 if ((options
& F_NUMERIC
) ||
1334 !(hp
= gethostbyaddr((char *)&l
, 4, AF_INET
)))
1335 (void)sprintf(buf
, "%s", inet_ntoa(__tmp
.addr
));
1337 (void)sprintf(buf
, "%s (%s)", hp
->h_name
,
1338 inet_ntoa(__tmp
.addr
));
1344 * Dump some info on a returned (via ICMP) IP packet.
1354 hlen
= ip
->ip_hl
<< 2;
1355 cp
= (u_char
*)ip
+ hlen
;
1358 (void)printf("TCP: from port %u, to port %u (decimal)\n",
1359 (*cp
* 256 + *(cp
+ 1)), (*(cp
+ 2) * 256 + *(cp
+ 3)));
1360 else if (ip
->ip_p
== 17)
1361 (void)printf("UDP: from port %u, to port %u (decimal)\n",
1362 (*cp
* 256 + *(cp
+ 1)), (*(cp
+ 2) * 256 + *(cp
+ 3)));
1369 register int ii
, jj
, kk
;
1373 for (cp
= patp
; *cp
; cp
++)
1374 if (!isxdigit(*cp
)) {
1375 (void)fprintf(stderr
,
1376 "ping: patterns must be specified as hex digits.\n");
1380 "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x",
1381 &pat
[0], &pat
[1], &pat
[2], &pat
[3], &pat
[4], &pat
[5], &pat
[6],
1382 &pat
[7], &pat
[8], &pat
[9], &pat
[10], &pat
[11], &pat
[12],
1383 &pat
[13], &pat
[14], &pat
[15]);
1386 for (kk
= 0; kk
<= MAXPACKET
- (8 + ii
); kk
+= ii
)
1387 for (jj
= 0; jj
< ii
; ++jj
)
1388 bp
[jj
+ kk
] = pat
[jj
];
1389 if (!(options
& F_QUIET
)) {
1390 (void)printf("PATTERN: 0x");
1391 for (jj
= 0; jj
< ii
; ++jj
)
1392 (void)printf("%02x", bp
[jj
] & 0xFF);
1400 (void)fprintf(stderr
,
1401 "usage: ping [-Rdfnqrv] [-c count] [-i wait] [-l preload]\n"
1402 "\t[-p pattern] [-s packetsize] [-L [hosts]] host\n");
1406 VOID
CleanUpExit(LONG error
)
1408 CloseLibrary(SocketBase
);