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 <aros/config.h>
240 #include <proto/socket.h>
242 #define ioctl IoctlSocket
244 #include <sys/param.h>
245 #include <sys/socket.h>
246 #include <sys/time.h>
250 #include <sys/file.h>
252 #include <netinet/in_systm.h>
253 #include <netinet/in.h>
254 #include <netinet/ip.h>
255 #include <netinet/ip_icmp.h>
256 #include <netinet/ip_var.h>
258 #include <arpa/inet.h>
262 #include <sys/errno.h>
266 #define DEFDATALEN (64 - 8) /* default data length */
268 #define MAXICMPLEN 76
269 #define MAXPACKET (65536 - 60 - 8)/* max packet size */
270 #define MAXWAIT 10 /* max seconds to wait for response */
271 #define NROUTES 9 /* number of record route slots */
273 #define A(bit) rcvd_tbl[(bit)>>3] /* identify byte in array */
274 #define B(bit) (1 << ((bit) & 0x07)) /* identify bit in byte */
275 #define SET(bit) (A(bit) |= B(bit))
276 #define CLR(bit) (A(bit) &= (~B(bit)))
277 #define TST(bit) (A(bit) & B(bit))
279 /* various options */
281 #define F_FLOOD 0x001
282 #define F_INTERVAL 0x002
283 #define F_NUMERIC 0x004
284 #define F_PINGFILLED 0x008
285 #define F_QUIET 0x010
286 #define F_RROUTE 0x020
287 #define F_SO_DEBUG 0x040
288 #define F_SO_DONTROUTE 0x080
289 #define F_VERBOSE 0x100
290 #define F_LOOSEROUTE 0x200
293 #define LONG_MAX 0xffffffff
297 * MAX_DUP_CHK is the number of bits in received table, i.e. the maximum
298 * number of received sequence numbers we can keep track of. Change 128
299 * to 8192 for complete accuracy...
301 #define MAX_DUP_CHK (8 * 128)
302 int mx_dup_ck
= MAX_DUP_CHK
;
303 char rcvd_tbl
[MAX_DUP_CHK
/ 8];
305 struct sockaddr whereto
; /* who to ping */
306 int datalen
= DEFDATALEN
;
307 int s
= -1; /* socket file descriptor */
309 char BSPACE
= '\b'; /* characters written for flood */
312 long ident
; /* process id to identify our packets */
315 long npackets
; /* max packets to transmit */
316 long nreceived
; /* # of packets we got back */
317 long nrepeats
; /* number of duplicates */
318 long ntransmitted
; /* sequence # for outbound packets = #sent */
319 int interval
= 1; /* interval between packets */
322 int timing
; /* flag to do timing */
323 unsigned long tmin
= LONG_MAX
; /* minimum round trip time */
324 unsigned long tmax
; /* maximum round trip time */
325 unsigned long tsum
; /* sum of all times, for doing average */
327 char *pr_addr(u_long l
);
328 void catcher(void), pinger(void), finish(void), usage(void);
329 void pr_pack(char *buf
, int cc
, struct sockaddr_in
*from
);
330 void pr_icmph(struct icmp
*icp
);
331 void pr_iph(struct ip
*ip
);
332 void pr_retip(struct ip
*ip
);
333 void fill(char *bp
, char *patp
);
334 int in_cksum(u_short
*addr
, int len
);
335 void tvsub(register struct timeval
*out
, register struct timeval
*in
);
336 VOID
CleanUpExit(LONG error
);
340 * Other Amiga dependent stuff
343 #include <clib/exec_protos.h>
344 #include <pragmas/exec_sysbase_pragmas.h>
345 extern struct ExecBase
*SysBase
;
347 /* Disable ^C signaling */
348 void __chkabort(void) {}
351 #include <devices/timer.h>
353 #include <proto/exec.h>
354 #include <proto/timer.h>
356 struct MsgPort
*timerport
= NULL
;
357 struct timerequest
*timermsg
= NULL
;
359 #define TimerBase (timermsg->tr_node.io_Device)
361 #define SOCKET_VERSION 3
362 struct Library
*SocketBase
;
363 const TEXT version
[] = "$VER: ping 3.10 (14.10.2005)";
364 const TEXT socket_name
[] = "bsdsocket.library";
371 if (!CheckIO((struct IORequest
*)timermsg
)) {
372 AbortIO((struct IORequest
*)timermsg
);
373 WaitIO((struct IORequest
*)timermsg
);
375 CloseDevice((struct IORequest
*)timermsg
);
378 DeleteIORequest((APTR
)timermsg
);
382 DeleteMsgPort(timerport
);
394 struct timeval timeout
;
396 struct sockaddr_in
*to
;
397 struct protoent
*proto
;
399 int ch
, fdmask
, hold
, packlen
, preload
;
400 u_char
*datap
, *packet
;
401 char *target
, hnamebuf
[MAXHOSTNAMELEN
];
403 u_char rspace
[3 + 4 * NROUTES
+ 1]; /* record route space */
409 SocketBase
= OpenLibrary(socket_name
, SOCKET_VERSION
);
410 if(SocketBase
== NULL
) {
411 fprintf(stderr
, "ping: cannot open bsdsocket.library version 3.\n");
414 SetErrnoPtr(&errno
, sizeof(errno
));
416 outpack
= malloc(MAXPACKET
);
417 if (outpack
== NULL
) {
422 datap
= &outpack
[8 + sizeof(struct timeval
)];
423 while ((ch
= getopt(argc
, argv
, "LRc:dfh:i:l:np:qrs:v")) != EOF
)
426 npackets
= atoi(optarg
);
428 (void)fprintf(stderr
, "ping: bad number of packets to transmit.\n");
433 options
|= F_SO_DEBUG
;
438 (void)fprintf(stderr
, "ping: %s\n", strerror(EPERM
));
443 setbuf(stdout
, (char *)NULL
);
445 case 'i': /* wait between sending packets */
446 interval
= atoi(optarg
);
448 (void)fprintf(stderr
, "ping: bad timing interval.\n");
451 options
|= F_INTERVAL
;
454 options
|= F_LOOSEROUTE
;
457 preload
= atoi(optarg
);
459 (void)fprintf(stderr
, "ping: bad preload value.\n");
464 options
|= F_NUMERIC
;
466 case 'p': /* fill buffer with user pattern */
467 options
|= F_PINGFILLED
;
468 fill((char *)datap
, optarg
);
477 options
|= F_SO_DONTROUTE
;
479 case 's': /* size of packet to send */
480 datalen
= atoi(optarg
);
481 if (datalen
> MAXPACKET
) {
482 (void)fprintf(stderr
, "ping: packet size too large.\n");
486 (void)fprintf(stderr
, "ping: illegal packet size.\n");
491 options
|= F_VERBOSE
;
499 if (argc
< 1 || (options
& F_LOOSEROUTE
) == 0 && argc
> 1)
502 if ((options
& (F_LOOSEROUTE
| F_RROUTE
)) == (F_LOOSEROUTE
| F_RROUTE
)) {
503 fprintf(stderr
, "ping: -L and -R options cannot be used concurrently\n");
510 if (options
& F_LOOSEROUTE
) {
512 rspace
[IPOPT_OPTVAL
] = IPOPT_LSRR
;
513 rspace
[IPOPT_OLEN
] = 3;
514 rspace
[IPOPT_OFFSET
] = IPOPT_MINOFF
;
515 cp
= rspace
+ IPOPT_OFFSET
+ 1;
517 (void)fprintf(stderr
, "ping: source routing not "
518 "available in this implementation.\n");
520 #endif /* IP_OPTIONS */
523 while (target
= *argv
++) {
524 bzero((char *)&whereto
, sizeof(struct sockaddr
));
525 to
= (struct sockaddr_in
*)&whereto
;
527 to
->sin_len
= sizeof(*to
);
529 to
->sin_family
= AF_INET
;
530 to
->sin_addr
.s_addr
= inet_addr(target
);
531 if (to
->sin_addr
.s_addr
!= (u_int
)-1)
534 hp
= gethostbyname(target
);
536 fprintf(stderr
, "ping: unknown host %s\n", target
);
539 to
->sin_family
= hp
->h_addrtype
;
540 bcopy(hp
->h_addr
, (caddr_t
)&to
->sin_addr
, hp
->h_length
);
541 (void)strncpy(hnamebuf
, hp
->h_name
, sizeof(hnamebuf
) - 1);
546 if (options
& F_LOOSEROUTE
) {
547 if (rspace
+ sizeof(rspace
) - 4 < cp
) {
548 fprintf(stderr
, "ping: too many hops for "
549 "source routing %s\n", target
);
552 *cp
++ = (to
->sin_addr
.s_addr
>> 24);
553 *cp
++ = (to
->sin_addr
.s_addr
>> 16);
554 *cp
++ = (to
->sin_addr
.s_addr
>> 8);
555 *cp
++ = (to
->sin_addr
.s_addr
>> 0);
556 rspace
[IPOPT_OLEN
] += 4;
562 if (options
& F_FLOOD
&& options
& F_INTERVAL
) {
563 (void)fprintf(stderr
, "ping: -f and -i incompatible options.\n");
567 if (datalen
>= sizeof(struct timeval
)) /* can we time transfer */
569 packlen
= datalen
+ MAXIPLEN
+ MAXICMPLEN
;
570 if (!(packet
= (u_char
*)malloc((u_int
)packlen
))) {
571 (void)fprintf(stderr
, "ping: out of memory.\n");
574 if (!(options
& F_PINGFILLED
))
575 for (i
= 8; i
< datalen
; ++i
)
578 ident
= getpid() & 0xFFFF;
580 if (!(proto
= getprotobyname("icmp"))) {
581 (void)fprintf(stderr
, "ping: unknown protocol icmp.\n");
588 timerport
= CreateMsgPort();
590 (void)fprintf(stderr
, "ping: could not create timer port.\n");
593 timermask
= 1<<timerport
->mp_SigBit
;
595 timermsg
= (APTR
)CreateIORequest(timerport
, sizeof(*timermsg
));
597 (void)fprintf(stderr
, "ping: could not create timer message.\n");
601 if (notopen
= OpenDevice("timer.device",
602 #if (AROS_FLAVOUR & AROS_FLAVOUR_EMULATION)
603 // UNIT_MICROHZ isn't available on AROS/hosted
608 (struct IORequest
*)timermsg
, 0)) {
609 (void)fprintf(stderr
, "ping: could not open timer device.\n");
613 timermsg
->tr_node
.io_Command
= TR_ADDREQUEST
;
614 timermsg
->tr_time
.tv_secs
= 1L;
615 timermsg
->tr_time
.tv_micro
= 0L;
616 /* don't confuse CheckIO */
617 timermsg
->tr_node
.io_Message
.mn_Node
.ln_Type
= NT_REPLYMSG
;
618 SetSocketSignals(timermask
| SIGBREAKF_CTRL_C
, 0L, 0L);
621 if ((s
= socket(AF_INET
, SOCK_RAW
, proto
->p_proto
)) < 0) {
622 perror("ping: socket");
626 if (options
& F_SO_DEBUG
)
627 (void)setsockopt(s
, SOL_SOCKET
, SO_DEBUG
, (char *)&hold
,
629 if (options
& F_SO_DONTROUTE
)
630 (void)setsockopt(s
, SOL_SOCKET
, SO_DONTROUTE
, (char *)&hold
,
634 if (options
& F_LOOSEROUTE
) {
635 /* pad to long word */
636 rspace
[rspace
[IPOPT_OLEN
]] = IPOPT_EOL
;
637 if (setsockopt(s
, IPPROTO_IP
, IP_OPTIONS
, rspace
,
638 rspace
[IPOPT_OLEN
] + 1) < 0) {
639 perror("ping: source routing");
645 /* record route option */
646 if (options
& F_RROUTE
) {
648 rspace
[IPOPT_OPTVAL
] = IPOPT_RR
;
649 rspace
[IPOPT_OLEN
] = sizeof(rspace
)-1;
650 rspace
[IPOPT_OFFSET
] = IPOPT_MINOFF
;
651 rspace
[rspace
[IPOPT_OLEN
]] = IPOPT_EOL
;
652 if (setsockopt(s
, IPPROTO_IP
, IP_OPTIONS
, rspace
,
653 sizeof(rspace
)) < 0) {
654 perror("ping: record route");
658 (void)fprintf(stderr
,
659 "ping: record route not available in this implementation.\n");
661 #endif /* IP_OPTIONS */
665 * When pinging the broadcast address, you can get a lot of answers.
666 * Doing something so evil is useful if you are trying to stress the
667 * ethernet, or just want to fill the arp cache to get some stuff for
671 (void)setsockopt(s
, SOL_SOCKET
, SO_RCVBUF
, (char *)&hold
,
674 if (to
->sin_family
== AF_INET
)
675 (void)printf("PING %s (%s): %d data bytes\n", hostname
,
676 inet_ntoa(*(struct in_addr
*)&to
->sin_addr
.s_addr
),
679 (void)printf("PING %s: %d data bytes\n", hostname
, datalen
);
682 (void)signal(SIGINT
, finish
);
683 (void)signal(SIGALRM
, catcher
);
686 while (preload
--) /* fire off them quickies */
689 if ((options
& F_FLOOD
) == 0)
690 catcher(); /* start things going */
693 struct sockaddr_in from
;
698 /* Check for special signals */
699 ULONG sm
= SetSignal(0L, timermask
| SIGBREAKF_CTRL_C
);
700 if (sm
& SIGBREAKF_CTRL_C
)
702 if (sm
& timermask
&& GetMsg(timerport
))
706 if (options
& F_FLOOD
) {
709 timeout
.tv_usec
= 10000;
711 if (select(s
+ 1, (fd_set
*)&fdmask
, (fd_set
*)NULL
,
712 (fd_set
*)NULL
, &timeout
) < 1)
715 fromlen
= sizeof(from
);
716 if ((cc
= recvfrom(s
, (char *)packet
, packlen
, 0,
717 (struct sockaddr
*)&from
, &fromlen
)) < 0) {
720 perror("ping: recvfrom");
723 pr_pack((char *)packet
, cc
, &from
);
724 if (npackets
&& nreceived
>= npackets
)
734 * This routine causes another PING to be transmitted, and then
735 * schedules another SIGALRM for 1 second from now.
738 * Our sense of time will slowly skew (i.e., packets will not be
739 * launched exactly at 1-second intervals). This does not affect the
740 * quality of the delay and loss statistics.
743 * This routine uses timer.device in Amiga implementation instead
750 static int waittime
= 0;
757 if (!npackets
|| ntransmitted
< npackets
) {
758 timermsg
->tr_time
.tv_sec
= interval
;
759 SendIO((struct IORequest
*)timermsg
);
762 waittime
= 2 * tmax
/ 1000;
767 timermsg
->tr_time
.tv_sec
= waittime
;
768 SendIO((struct IORequest
*)timermsg
);
774 (void)signal(SIGALRM
, catcher
);
775 if (!npackets
|| ntransmitted
< npackets
)
776 alarm((u_int
)interval
);
779 waittime
= 2 * tmax
/ 1000;
784 (void)signal(SIGALRM
, finish
);
785 (void)alarm((u_int
)waittime
);
792 * Compose and transmit an ICMP ECHO REQUEST packet. The IP packet
793 * will be added on by the kernel. The ID field is our process ID,
794 * and the sequence number is an ascending integer. The first 8 bytes
795 * of the data portion are used to hold a UNIX "timeval" struct in native
796 * byte-order, to compute the round-trip time.
801 register struct icmp
*icp
;
805 icp
= (struct icmp
*)outpack
;
806 icp
->icmp_type
= ICMP_ECHO
;
809 icp
->icmp_seq
= htons(ntransmitted
++);
810 icp
->icmp_id
= ident
; /* ID */
812 CLR(icp
->icmp_seq
% mx_dup_ck
);
816 /* (void)ReadEClock((struct EClockVal *)&outpack[8]);*/ /* NC */
817 (void)GetSysTime((struct timeval
*)&outpack
[8]);
819 (void)gettimeofday((struct timeval
*)&outpack
[8],
820 (struct timezone
*)NULL
);
822 cc
= datalen
+ 8; /* skips ICMP portion */
824 /* compute ICMP checksum here */
825 icp
->icmp_cksum
= in_cksum((u_short
*)icp
, cc
);
827 i
= sendto(s
, (char *)outpack
, cc
, 0, &whereto
,
828 sizeof(struct sockaddr
));
830 if (i
< 0 || i
!= cc
) {
832 perror("ping: sendto");
833 (void)printf("ping: wrote %s %d chars, ret=%d\n",
836 if (!(options
& F_QUIET
) && options
& F_FLOOD
)
837 (void)write(1, &DOT
, 1);
842 * Print out the packet, if it came from us. This logic is necessary
843 * because ALL readers of the ICMP socket get a copy of ALL ICMP packets
844 * which arrive ('tis only fair). This permits multiple copies of this
845 * program to be run without having intermingled output (or statistics!).
848 pr_pack(buf
, cc
, from
)
851 struct sockaddr_in
*from
;
853 register struct icmp
*icp
;
856 register u_char
*cp
,*dp
;
857 static int old_rrlen
;
858 static char old_rr
[MAX_IPOPTLEN
];
860 struct timeval tv
, *tp
;
865 /* ULONG efreq = ReadEClock((struct EClockVal *)&tv);*/ /* NC */
866 GetSysTime((struct timeval
*)&tv
);
868 (void)gettimeofday(&tv
, (struct timezone
*)NULL
);
870 /* Check the IP header */
871 ip
= (struct ip
*)buf
;
872 hlen
= ip
->ip_hl
<< 2;
873 if (cc
< hlen
+ ICMP_MINLEN
) {
874 if (options
& F_VERBOSE
)
875 (void)fprintf(stderr
,
876 "ping: packet too short (%d bytes) from %s\n", cc
,
877 inet_ntoa(*(struct in_addr
*)&from
->sin_addr
.s_addr
));
881 /* Now the ICMP part */
883 icp
= (struct icmp
*)(buf
+ hlen
);
884 if (icp
->icmp_type
== ICMP_ECHOREPLY
) {
885 if (icp
->icmp_id
!= ident
)
886 return; /* 'Twas not our ECHO */
890 tp
= (struct timeval
*)&icp
->icmp_ip
;
892 tp
= (struct timeval
*)icp
->icmp_data
;
894 #ifndef AMIGA /* NC */
895 /* EClockVal is actually an unsigned long long */
896 if (tv
.tv_micro
< tp
->tv_micro
)
898 tv
.tv_micro
-= tp
->tv_micro
;
899 tv
.tv_secs
-= tp
->tv_secs
;
900 triptime
= tv
.tv_micro
/ (efreq
/ 1000);
902 triptime
+= tv
.tv_sec
* 250 * ((1<<30) / efreq
);
905 triptime
= tv
.tv_sec
* 1000 + (tv
.tv_usec
/ 1000);
914 if (TST(icp
->icmp_seq
% mx_dup_ck
)) {
919 SET(icp
->icmp_seq
% mx_dup_ck
);
923 if (options
& F_QUIET
)
926 if (options
& F_FLOOD
)
927 (void)write(1, &BSPACE
, 1);
929 (void)printf("%d bytes from %s: icmp_seq=%u", cc
,
930 inet_ntoa(*(struct in_addr
*)&from
->sin_addr
.s_addr
),
931 ntohs(icp
->icmp_seq
));
932 (void)printf(" ttl=%d", ip
->ip_ttl
);
934 (void)printf(" time=%ld ms", triptime
);
936 (void)printf(" (DUP!)");
938 cp
= (u_char
*)&icp
->icmp_data
[8];
939 dp
= &outpack
[8 + sizeof(struct timeval
)];
940 for (i
= 8; i
< datalen
; ++i
, ++cp
, ++dp
) {
942 (void)printf("\nwrong data byte #%d should be 0x%x but was 0x%x",
944 cp
= (u_char
*)&icp
->icmp_data
[0];
945 for (i
= 8; i
< datalen
; ++i
, ++cp
) {
947 (void)printf("\n\t");
948 (void)printf("%x ", *cp
);
955 /* We've got something other than an ECHOREPLY */
956 if (!(options
& F_VERBOSE
))
958 (void)printf("%d bytes from %s: ", cc
,
959 pr_addr(from
->sin_addr
.s_addr
));
963 /* Display any IP options */
964 /* The LSRR and RR len handling was broken (?) //ppessi */
965 cp
= (u_char
*)buf
+ sizeof(struct ip
);
967 for (; hlen
> (int)sizeof(struct ip
); --hlen
, ++cp
)
974 (void)printf(*cp
== IPOPT_LSRR
?
975 "\nLSRR: " : "\nSSRR: ");
979 if (j
> IPOPT_MINOFF
)
986 (void)printf("\t0.0.0.0");
988 (void)printf("\t%s", pr_addr(ntohl(l
)));
990 if (j
< IPOPT_MINOFF
)
996 j
= *++cp
; /* get length */
997 i
= *++cp
; /* and pointer */
1005 && cp
== (u_char
*)buf
+ sizeof(struct ip
) + 2
1006 && !bcmp((char *)cp
, old_rr
, i
)
1007 && !(options
& F_FLOOD
)) {
1008 (void)printf("\t(same route)");
1009 i
= ((i
+ 3) / 4) * 4;
1014 bcopy((char *)cp
, old_rr
, i
);
1015 (void)printf("\nRR: ");
1022 (void)printf("\t0.0.0.0");
1024 (void)printf("\t%s", pr_addr(ntohl(l
)));
1028 (void)putchar('\n');
1032 (void)printf("\nNOP");
1035 (void)printf("\nunknown option %x", *cp
);
1038 if (!(options
& F_FLOOD
)) {
1039 (void)putchar('\n');
1040 (void)fflush(stdout
);
1046 * Checksum routine for Internet Protocol family headers (C Version)
1053 register int nleft
= len
;
1054 register u_short
*w
= addr
;
1055 register int sum
= 0;
1059 * Our algorithm is simple, using a 32 bit accumulator (sum), we add
1060 * sequential 16 bit words to it, and at the end, fold back all the
1061 * carry bits from the top 16 bits into the lower 16 bits.
1068 /* mop up an odd byte, if necessary */
1070 *(u_char
*)(&answer
) = *(u_char
*)w
;
1074 /* add back carry outs from top 16 bits to low 16 bits */
1075 sum
= (sum
>> 16) + (sum
& 0xffff); /* add hi 16 to low 16 */
1076 sum
+= (sum
>> 16); /* add carry */
1077 answer
= ~sum
; /* truncate to 16 bits */
1083 * Subtract 2 timeval structs: out = out - in. Out is assumed to
1088 register struct timeval
*out
, *in
;
1090 if ((out
->tv_usec
-= in
->tv_usec
) < 0) {
1092 out
->tv_usec
+= 1000000;
1094 out
->tv_sec
-= in
->tv_sec
;
1099 * Print out statistics, and give up.
1104 (void)signal(SIGINT
, SIG_IGN
);
1105 (void)putchar('\n');
1106 (void)fflush(stdout
);
1107 (void)printf("--- %s ping statistics ---\n", hostname
);
1108 (void)printf("%ld packets transmitted, ", ntransmitted
);
1109 (void)printf("%ld packets received, ", nreceived
);
1111 (void)printf("+%ld duplicates, ", nrepeats
);
1113 if (nreceived
> ntransmitted
)
1114 (void)printf("-- somebody's printing up packets!");
1116 (void)printf("%d%% packet loss",
1117 (int) (((ntransmitted
- nreceived
) * 100) /
1119 (void)putchar('\n');
1120 if (nreceived
&& timing
)
1121 (void)printf("round-trip min/avg/max = %ld/%lu/%ld ms\n",
1122 tmin
, tsum
/ (nreceived
+ nrepeats
), tmax
);
1127 static char *ttab
[] = {
1128 "Echo Reply", /* ip + seq + udata */
1129 "Dest Unreachable", /* net, host, proto, port, frag, sr + IP */
1130 "Source Quench", /* IP */
1131 "Redirect", /* redirect type, gateway, + IP */
1133 "Time Exceeded", /* transit, frag reassem + IP */
1134 "Parameter Problem", /* pointer + IP */
1135 "Timestamp", /* id + seq + three timestamps */
1136 "Timestamp Reply", /* " */
1137 "Info Request", /* id + sq */
1138 "Info Reply" /* " */
1144 * Print a descriptive string about an ICMP header.
1150 switch(icp
->icmp_type
) {
1151 case ICMP_ECHOREPLY
:
1152 (void)printf("Echo Reply\n");
1153 /* XXX ID + Seq + Data */
1156 switch(icp
->icmp_code
) {
1157 case ICMP_UNREACH_NET
:
1158 (void)printf("Destination Net Unreachable\n");
1160 case ICMP_UNREACH_HOST
:
1161 (void)printf("Destination Host Unreachable\n");
1163 case ICMP_UNREACH_PROTOCOL
:
1164 (void)printf("Destination Protocol Unreachable\n");
1166 case ICMP_UNREACH_PORT
:
1167 (void)printf("Destination Port Unreachable\n");
1169 case ICMP_UNREACH_NEEDFRAG
:
1170 (void)printf("frag needed and DF set\n");
1172 case ICMP_UNREACH_SRCFAIL
:
1173 (void)printf("Source Route Failed\n");
1176 (void)printf("Dest Unreachable, Bad Code: %d\n",
1180 /* Print returned IP header information */
1182 pr_retip(&icp
->icmp_ip
);
1184 pr_retip((struct ip
*)icp
->icmp_data
);
1187 case ICMP_SOURCEQUENCH
:
1188 (void)printf("Source Quench\n");
1190 pr_retip(&icp
->icmp_ip
);
1192 pr_retip((struct ip
*)icp
->icmp_data
);
1196 switch(icp
->icmp_code
) {
1197 case ICMP_REDIRECT_NET
:
1198 (void)printf("Redirect Network");
1200 case ICMP_REDIRECT_HOST
:
1201 (void)printf("Redirect Host");
1203 case ICMP_REDIRECT_TOSNET
:
1204 (void)printf("Redirect Type of Service and Network");
1206 case ICMP_REDIRECT_TOSHOST
:
1207 (void)printf("Redirect Type of Service and Host");
1210 (void)printf("Redirect, Bad Code: %d", icp
->icmp_code
);
1213 (void)printf("(New addr: 0x%08lx)\n",
1214 (long unsigned)icp
->icmp_gwaddr
.s_addr
);
1216 pr_retip(&icp
->icmp_ip
);
1218 pr_retip((struct ip
*)icp
->icmp_data
);
1222 (void)printf("Echo Request\n");
1223 /* XXX ID + Seq + Data */
1226 switch(icp
->icmp_code
) {
1227 case ICMP_TIMXCEED_INTRANS
:
1228 (void)printf("Time to live exceeded\n");
1230 case ICMP_TIMXCEED_REASS
:
1231 (void)printf("Frag reassembly time exceeded\n");
1234 (void)printf("Time exceeded, Bad Code: %d\n",
1239 pr_retip(&icp
->icmp_ip
);
1241 pr_retip((struct ip
*)icp
->icmp_data
);
1244 case ICMP_PARAMPROB
:
1245 (void)printf("Parameter problem: pointer = 0x%02x\n",
1246 icp
->icmp_hun
.ih_pptr
);
1248 pr_retip(&icp
->icmp_ip
);
1250 pr_retip((struct ip
*)icp
->icmp_data
);
1254 (void)printf("Timestamp\n");
1255 /* XXX ID + Seq + 3 timestamps */
1257 case ICMP_TSTAMPREPLY
:
1258 (void)printf("Timestamp Reply\n");
1259 /* XXX ID + Seq + 3 timestamps */
1262 (void)printf("Information Request\n");
1265 case ICMP_IREQREPLY
:
1266 (void)printf("Information Reply\n");
1271 (void)printf("Address Mask Request\n");
1274 #ifdef ICMP_MASKREPLY
1275 case ICMP_MASKREPLY
:
1276 (void)printf("Address Mask Reply\n");
1280 (void)printf("Bad ICMP type: %d\n", icp
->icmp_type
);
1286 * Print an IP header with options.
1295 hlen
= ip
->ip_hl
<< 2;
1296 cp
= (u_char
*)ip
+ 20; /* point to options */
1298 (void)printf("Vr HL TOS Len ID Flg off TTL Pro cks Src Dst Data\n");
1299 (void)printf(" %1x %1x %02x %04x %04x",
1300 ip
->ip_v
, ip
->ip_hl
, ip
->ip_tos
, ip
->ip_len
, ip
->ip_id
);
1301 (void)printf(" %1x %04x", ((ip
->ip_off
) & 0xe000) >> 13,
1302 (ip
->ip_off
) & 0x1fff);
1303 (void)printf(" %02x %02x %04x", ip
->ip_ttl
, ip
->ip_p
, ip
->ip_sum
);
1304 (void)printf(" %s ", inet_ntoa(*(struct in_addr
*)&ip
->ip_src
.s_addr
));
1305 (void)printf(" %s ", inet_ntoa(*(struct in_addr
*)&ip
->ip_dst
.s_addr
));
1306 /* dump and option bytes */
1307 while (hlen
-- > 20) {
1308 (void)printf("%02x", *cp
++);
1310 (void)putchar('\n');
1315 * Return an ascii host address as a dotted quad and optionally with
1323 static char buf
[80];
1325 struct in_addr addr
;
1331 if ((options
& F_NUMERIC
) ||
1332 !(hp
= gethostbyaddr((char *)&l
, 4, AF_INET
)))
1333 (void)sprintf(buf
, "%s", inet_ntoa(__tmp
.addr
));
1335 (void)sprintf(buf
, "%s (%s)", hp
->h_name
,
1336 inet_ntoa(__tmp
.addr
));
1342 * Dump some info on a returned (via ICMP) IP packet.
1352 hlen
= ip
->ip_hl
<< 2;
1353 cp
= (u_char
*)ip
+ hlen
;
1356 (void)printf("TCP: from port %u, to port %u (decimal)\n",
1357 (*cp
* 256 + *(cp
+ 1)), (*(cp
+ 2) * 256 + *(cp
+ 3)));
1358 else if (ip
->ip_p
== 17)
1359 (void)printf("UDP: from port %u, to port %u (decimal)\n",
1360 (*cp
* 256 + *(cp
+ 1)), (*(cp
+ 2) * 256 + *(cp
+ 3)));
1367 register int ii
, jj
, kk
;
1371 for (cp
= patp
; *cp
; cp
++)
1372 if (!isxdigit(*cp
)) {
1373 (void)fprintf(stderr
,
1374 "ping: patterns must be specified as hex digits.\n");
1378 "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x",
1379 &pat
[0], &pat
[1], &pat
[2], &pat
[3], &pat
[4], &pat
[5], &pat
[6],
1380 &pat
[7], &pat
[8], &pat
[9], &pat
[10], &pat
[11], &pat
[12],
1381 &pat
[13], &pat
[14], &pat
[15]);
1384 for (kk
= 0; kk
<= MAXPACKET
- (8 + ii
); kk
+= ii
)
1385 for (jj
= 0; jj
< ii
; ++jj
)
1386 bp
[jj
+ kk
] = pat
[jj
];
1387 if (!(options
& F_QUIET
)) {
1388 (void)printf("PATTERN: 0x");
1389 for (jj
= 0; jj
< ii
; ++jj
)
1390 (void)printf("%02x", bp
[jj
] & 0xFF);
1398 (void)fprintf(stderr
,
1399 "usage: ping [-Rdfnqrv] [-c count] [-i wait] [-l preload]\n"
1400 "\t[-p pattern] [-s packetsize] [-L [hosts]] host\n");
1404 VOID
CleanUpExit(LONG error
)
1406 CloseLibrary(SocketBase
);