]>
git.saurik.com Git - apple/network_cmds.git/blob - ping.tproj/ping.c
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.0 (the 'License'). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
22 * @APPLE_LICENSE_HEADER_END@
25 * Copyright (c) 1989, 1993
26 * The Regents of the University of California. All rights reserved.
28 * This code is derived from software contributed to Berkeley by
31 * Redistribution and use in source and binary forms, with or without
32 * modification, are permitted provided that the following conditions
34 * 1. Redistributions of source code must retain the above copyright
35 * notice, this list of conditions and the following disclaimer.
36 * 2. Redistributions in binary form must reproduce the above copyright
37 * notice, this list of conditions and the following disclaimer in the
38 * documentation and/or other materials provided with the distribution.
39 * 3. All advertising materials mentioning features or use of this software
40 * must display the following acknowledgement:
41 * This product includes software developed by the University of
42 * California, Berkeley and its contributors.
43 * 4. Neither the name of the University nor the names of its contributors
44 * may be used to endorse or promote products derived from this software
45 * without specific prior written permission.
47 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
48 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
49 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
50 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
51 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
52 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
53 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
54 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
55 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
56 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
64 * Using the InterNet Control Message Protocol (ICMP) "ECHO" facility,
65 * measure round-trip-delays and packet loss across network paths.
69 * U. S. Army Ballistic Research Laboratory
73 * Public Domain. Distribution Unlimited.
75 * More statistics could always be gathered.
76 * This program has to run SUID to ROOT to access the ICMP socket.
79 #include <sys/param.h>
80 #include <sys/socket.h>
83 #include <sys/signal.h>
85 #include <netinet/in_systm.h>
86 #include <netinet/in.h>
87 #include <netinet/ip.h>
88 #include <netinet/ip_icmp.h>
89 #include <netinet/ip_var.h>
97 #define DEFDATALEN (64 - 8) /* default data length */
100 #define MAXPACKET (65536 - 60 - 8)/* max packet size */
101 #define MAXWAIT 10 /* max seconds to wait for response */
102 #define NROUTES 9 /* number of record route slots */
104 #define A(bit) rcvd_tbl[(bit)>>3] /* identify byte in array */
105 #define B(bit) (1 << ((bit) & 0x07)) /* identify bit in byte */
106 #define SET(bit) (A(bit) |= B(bit))
107 #define CLR(bit) (A(bit) &= (~B(bit)))
108 #define TST(bit) (A(bit) & B(bit))
110 /* various options */
112 #define F_FLOOD 0x001
113 #define F_INTERVAL 0x002
114 #define F_NUMERIC 0x004
115 #define F_PINGFILLED 0x008
116 #define F_QUIET 0x010
117 #define F_RROUTE 0x020
118 #define F_SO_DEBUG 0x040
119 #define F_SO_DONTROUTE 0x080
120 #define F_VERBOSE 0x100
123 * MAX_DUP_CHK is the number of bits in received table, i.e. the maximum
124 * number of received sequence numbers we can keep track of. Change 128
125 * to 8192 for complete accuracy...
127 #define MAX_DUP_CHK (8 * 128)
128 int mx_dup_ck
= MAX_DUP_CHK
;
129 char rcvd_tbl
[MAX_DUP_CHK
/ 8];
131 struct sockaddr whereto
; /* who to ping */
132 int datalen
= DEFDATALEN
;
133 int s
; /* socket file descriptor */
134 u_char outpack
[MAXPACKET
];
135 char BSPACE
= '\b'; /* characters written for flood */
138 int ident
; /* process id to identify our packets */
141 long npackets
; /* max packets to transmit */
142 long nreceived
; /* # of packets we got back */
143 long nrepeats
; /* number of duplicates */
144 long ntransmitted
; /* sequence # for outbound packets = #sent */
145 int interval
= 1; /* interval between packets */
148 int timing
; /* flag to do timing */
149 double tmin
= 999999999.0; /* minimum round trip time */
150 double tmax
= 0.0; /* maximum round trip time */
151 double tsum
= 0.0; /* sum of all times, for doing average */
154 void catcher(), finish();
160 extern int errno
, optind
;
162 struct timeval timeout
;
164 struct sockaddr_in
*to
;
165 struct protoent
*proto
;
167 int ch
, fdmask
, hold
, packlen
, preload
;
168 u_char
*datap
, *packet
;
169 char *target
, hnamebuf
[MAXHOSTNAMELEN
], *malloc();
171 char rspace
[3 + 4 * NROUTES
+ 1]; /* record route space */
175 datap
= &outpack
[8 + sizeof(struct timeval
)];
176 while ((ch
= getopt(argc
, argv
, "Rc:dfh:i:l:np:qrs:v")) != EOF
)
179 npackets
= atoi(optarg
);
181 (void)fprintf(stderr
,
182 "ping: bad number of packets to transmit.\n");
187 options
|= F_SO_DEBUG
;
191 (void)fprintf(stderr
,
192 "ping: %s\n", strerror(EPERM
));
196 setbuf(stdout
, (char *)NULL
);
198 case 'i': /* wait between sending packets */
199 interval
= atoi(optarg
);
201 (void)fprintf(stderr
,
202 "ping: bad timing interval.\n");
205 options
|= F_INTERVAL
;
209 (void)fprintf(stderr
,
210 "ping: %s\n", strerror(EPERM
));
213 preload
= atoi(optarg
);
215 (void)fprintf(stderr
,
216 "ping: bad preload value.\n");
221 options
|= F_NUMERIC
;
223 case 'p': /* fill buffer with user pattern */
224 options
|= F_PINGFILLED
;
225 fill((char *)datap
, optarg
);
234 options
|= F_SO_DONTROUTE
;
236 case 's': /* size of packet to send */
237 datalen
= atoi(optarg
);
238 if (datalen
> MAXPACKET
) {
239 (void)fprintf(stderr
,
240 "ping: packet size too large.\n");
244 (void)fprintf(stderr
,
245 "ping: illegal packet size.\n");
250 options
|= F_VERBOSE
;
262 memset(&whereto
, 0, sizeof(struct sockaddr
));
263 to
= (struct sockaddr_in
*)&whereto
;
264 to
->sin_family
= AF_INET
;
265 to
->sin_addr
.s_addr
= inet_addr(target
);
266 if (to
->sin_addr
.s_addr
!= (u_int
)-1)
269 hp
= gethostbyname(target
);
271 (void)fprintf(stderr
,
272 "ping: unknown host %s\n", target
);
275 to
->sin_family
= hp
->h_addrtype
;
276 memmove(&to
->sin_addr
, hp
->h_addr
, hp
->h_length
);
277 (void)strncpy(hnamebuf
, hp
->h_name
, sizeof(hnamebuf
) - 1);
281 if (options
& F_FLOOD
&& options
& F_INTERVAL
) {
282 (void)fprintf(stderr
,
283 "ping: -f and -i incompatible options.\n");
287 if (datalen
>= sizeof(struct timeval
)) /* can we time transfer */
289 packlen
= datalen
+ MAXIPLEN
+ MAXICMPLEN
;
290 if (!(packet
= (u_char
*)malloc((u_int
)packlen
))) {
291 (void)fprintf(stderr
, "ping: out of memory.\n");
294 if (!(options
& F_PINGFILLED
))
295 for (i
= 8; i
< datalen
; ++i
)
298 ident
= getpid() & 0xFFFF;
300 if (!(proto
= getprotobyname("icmp"))) {
301 (void)fprintf(stderr
, "ping: unknown protocol icmp.\n");
304 if ((s
= socket(AF_INET
, SOCK_RAW
, proto
->p_proto
)) < 0) {
305 perror("ping: socket");
309 if (options
& F_SO_DEBUG
)
310 (void)setsockopt(s
, SOL_SOCKET
, SO_DEBUG
, (char *)&hold
,
312 if (options
& F_SO_DONTROUTE
)
313 (void)setsockopt(s
, SOL_SOCKET
, SO_DONTROUTE
, (char *)&hold
,
316 /* record route option */
317 if (options
& F_RROUTE
) {
319 rspace
[IPOPT_OPTVAL
] = IPOPT_RR
;
320 rspace
[IPOPT_OLEN
] = sizeof(rspace
)-1;
321 rspace
[IPOPT_OFFSET
] = IPOPT_MINOFF
;
322 if (setsockopt(s
, IPPROTO_IP
, IP_OPTIONS
, rspace
,
323 sizeof(rspace
)) < 0) {
324 perror("ping: record route");
328 (void)fprintf(stderr
,
329 "ping: record route not available in this implementation.\n");
331 #endif /* IP_OPTIONS */
335 * When pinging the broadcast address, you can get a lot of answers.
336 * Doing something so evil is useful if you are trying to stress the
337 * ethernet, or just want to fill the arp cache to get some stuff for
340 (void)setsockopt(s
, SOL_SOCKET
, SO_RCVBUF
, &packlen
, sizeof(packlen
));
342 if (to
->sin_family
== AF_INET
)
343 (void)printf("PING %s (%s): %d data bytes\n", hostname
,
344 inet_ntoa(*(struct in_addr
*)&to
->sin_addr
.s_addr
),
347 (void)printf("PING %s: %d data bytes\n", hostname
, datalen
);
349 (void)signal(SIGINT
, finish
);
350 (void)signal(SIGALRM
, catcher
);
352 while (preload
--) /* fire off them quickies */
355 if ((options
& F_FLOOD
) == 0)
356 catcher(); /* start things going */
359 struct sockaddr_in from
;
362 sigset_t omask
, nmask
;
364 if (options
& F_FLOOD
) {
367 timeout
.tv_usec
= 10000;
369 if (select(s
+ 1, (fd_set
*)&fdmask
, (fd_set
*)NULL
,
370 (fd_set
*)NULL
, &timeout
) < 1)
373 fromlen
= sizeof(from
);
374 if ((cc
= recvfrom(s
, (char *)packet
, packlen
, 0,
375 (struct sockaddr
*)&from
, &fromlen
)) < 0) {
378 perror("ping: recvfrom");
382 sigaddset(&nmask
, SIGALRM
);
383 sigprocmask(SIG_BLOCK
, &nmask
, &omask
);
384 pr_pack((char *)packet
, cc
, &from
);
385 sigprocmask(SIG_SETMASK
, &omask
, NULL
);
386 if (npackets
&& nreceived
>= npackets
)
395 * This routine causes another PING to be transmitted, and then
396 * schedules another SIGALRM for 1 second from now.
399 * Our sense of time will slowly skew (i.e., packets will not be
400 * launched exactly at 1-second intervals). This does not affect the
401 * quality of the delay and loss statistics.
409 (void)signal(SIGALRM
, catcher
);
410 if (!npackets
|| ntransmitted
< npackets
)
411 alarm((u_int
)interval
);
414 waittime
= 2 * tmax
/ 1000;
419 (void)signal(SIGALRM
, finish
);
420 (void)alarm((u_int
)waittime
);
426 * Compose and transmit an ICMP ECHO REQUEST packet. The IP packet
427 * will be added on by the kernel. The ID field is our UNIX process ID,
428 * and the sequence number is an ascending integer. The first 8 bytes
429 * of the data portion are used to hold a UNIX "timeval" struct in VAX
430 * byte-order, to compute the round-trip time.
434 register struct icmp
*icp
;
438 icp
= (struct icmp
*)outpack
;
439 icp
->icmp_type
= ICMP_ECHO
;
442 icp
->icmp_seq
= ntransmitted
++;
443 icp
->icmp_id
= ident
; /* ID */
445 CLR(icp
->icmp_seq
% mx_dup_ck
);
448 (void)gettimeofday((struct timeval
*)&outpack
[8],
449 (struct timezone
*)NULL
);
451 cc
= datalen
+ 8; /* skips ICMP portion */
453 /* compute ICMP checksum here */
454 icp
->icmp_cksum
= in_cksum((u_short
*)icp
, cc
);
456 i
= sendto(s
, (char *)outpack
, cc
, 0, &whereto
,
457 sizeof(struct sockaddr
));
459 if (i
< 0 || i
!= cc
) {
461 perror("ping: sendto");
462 (void)printf("ping: wrote %s %d chars, ret=%d\n",
465 if (!(options
& F_QUIET
) && options
& F_FLOOD
)
466 (void)write(STDOUT_FILENO
, &DOT
, 1);
471 * Print out the packet, if it came from us. This logic is necessary
472 * because ALL readers of the ICMP socket get a copy of ALL ICMP packets
473 * which arrive ('tis only fair). This permits multiple copies of this
474 * program to be run without having intermingled output (or statistics!).
476 pr_pack(buf
, cc
, from
)
479 struct sockaddr_in
*from
;
481 register struct icmp
*icp
;
484 register u_char
*cp
,*dp
;
485 static int old_rrlen
;
486 static char old_rr
[MAX_IPOPTLEN
];
488 struct timeval tv
, *tp
;
492 (void)gettimeofday(&tv
, (struct timezone
*)NULL
);
494 /* Check the IP header */
495 ip
= (struct ip
*)buf
;
496 hlen
= ip
->ip_hl
<< 2;
497 if (cc
< hlen
+ ICMP_MINLEN
) {
498 if (options
& F_VERBOSE
)
499 (void)fprintf(stderr
,
500 "ping: packet too short (%d bytes) from %s\n", cc
,
501 inet_ntoa(*(struct in_addr
*)&from
->sin_addr
.s_addr
));
505 /* Now the ICMP part */
507 icp
= (struct icmp
*)(buf
+ hlen
);
508 if (icp
->icmp_type
== ICMP_ECHOREPLY
) {
509 if (icp
->icmp_id
!= ident
)
510 return; /* 'Twas not our ECHO */
514 tp
= (struct timeval
*)&icp
->icmp_ip
;
516 tp
= (struct timeval
*)icp
->icmp_data
;
519 triptime
= ((double)tv
.tv_sec
) * 1000.0 +
520 ((double)tv
.tv_usec
) / 1000.0;
528 if (TST(icp
->icmp_seq
% mx_dup_ck
)) {
533 SET(icp
->icmp_seq
% mx_dup_ck
);
537 if (options
& F_QUIET
)
540 if (options
& F_FLOOD
)
541 (void)write(STDOUT_FILENO
, &BSPACE
, 1);
543 (void)printf("%d bytes from %s: icmp_seq=%u", cc
,
544 inet_ntoa(*(struct in_addr
*)&from
->sin_addr
.s_addr
),
546 (void)printf(" ttl=%d", ip
->ip_ttl
);
548 (void)printf(" time=%g ms", triptime
);
550 (void)printf(" (DUP!)");
552 cp
= (u_char
*)&icp
->icmp_data
[8];
553 dp
= &outpack
[8 + sizeof(struct timeval
)];
554 for (i
= 8; i
< datalen
; ++i
, ++cp
, ++dp
) {
556 (void)printf("\nwrong data byte #%d should be 0x%x but was 0x%x",
558 cp
= (u_char
*)&icp
->icmp_data
[0];
559 for (i
= 8; i
< datalen
; ++i
, ++cp
) {
561 (void)printf("\n\t");
562 (void)printf("%x ", *cp
);
569 /* We've got something other than an ECHOREPLY */
570 if (!(options
& F_VERBOSE
))
572 (void)printf("%d bytes from %s: ", cc
,
573 pr_addr(from
->sin_addr
.s_addr
));
577 /* Display any IP options */
578 cp
= (u_char
*)buf
+ sizeof(struct ip
);
580 for (; hlen
> (int)sizeof(struct ip
); --hlen
, ++cp
)
586 (void)printf("\nLSRR: ");
590 if (j
> IPOPT_MINOFF
)
597 (void)printf("\t0.0.0.0");
599 (void)printf("\t%s", pr_addr(ntohl(l
)));
602 if (j
<= IPOPT_MINOFF
)
608 j
= *++cp
; /* get length */
609 i
= *++cp
; /* and pointer */
617 && cp
== (u_char
*)buf
+ sizeof(struct ip
) + 2
618 && !memcmp(cp
, old_rr
, i
)
619 && !(options
& F_FLOOD
)) {
620 (void)printf("\t(same route)");
621 i
= ((i
+ 3) / 4) * 4;
626 if (i
< MAX_IPOPTLEN
) {
628 memcpy(old_rr
, cp
, i
);
632 (void)printf("\nRR: ");
640 (void)printf("\t0.0.0.0");
642 (void)printf("\t%s", pr_addr(ntohl(l
)));
648 if (j
>= MAX_IPOPTLEN
) {
649 (void)printf("\t(truncated route)");
656 (void)printf("\nNOP");
659 (void)printf("\nunknown option %x", *cp
);
662 if (!(options
& F_FLOOD
)) {
664 (void)fflush(stdout
);
670 * Checksum routine for Internet Protocol family headers (C Version)
676 register int nleft
= len
;
677 register u_short
*w
= addr
;
678 register int sum
= 0;
682 * Our algorithm is simple, using a 32 bit accumulator (sum), we add
683 * sequential 16 bit words to it, and at the end, fold back all the
684 * carry bits from the top 16 bits into the lower 16 bits.
691 /* mop up an odd byte, if necessary */
693 *(u_char
*)(&answer
) = *(u_char
*)w
;
697 /* add back carry outs from top 16 bits to low 16 bits */
698 sum
= (sum
>> 16) + (sum
& 0xffff); /* add hi 16 to low 16 */
699 sum
+= (sum
>> 16); /* add carry */
700 answer
= ~sum
; /* truncate to 16 bits */
706 * Subtract 2 timeval structs: out = out - in. Out is assumed to
710 register struct timeval
*out
, *in
;
712 if ((out
->tv_usec
-= in
->tv_usec
) < 0) {
714 out
->tv_usec
+= 1000000;
716 out
->tv_sec
-= in
->tv_sec
;
721 * Print out statistics, and give up.
728 (void)signal(SIGINT
, SIG_IGN
);
730 (void)fflush(stdout
);
731 (void)printf("--- %s ping statistics ---\n", hostname
);
732 (void)printf("%ld packets transmitted, ", ntransmitted
);
733 (void)printf("%ld packets received, ", nreceived
);
735 (void)printf("+%ld duplicates, ", nrepeats
);
737 if (nreceived
> ntransmitted
)
738 (void)printf("-- somebody's printing up packets!");
740 (void)printf("%d%% packet loss",
741 (int) (((ntransmitted
- nreceived
) * 100) /
744 if (nreceived
&& timing
) {
745 /* Only display average to microseconds */
746 i
= 1000.0 * tsum
/ (nreceived
+ nrepeats
);
747 (void)printf("round-trip min/avg/max = %g/%g/%g ms\n",
748 tmin
, ((double)i
) / 1000.0, tmax
);
754 static char *ttab
[] = {
755 "Echo Reply", /* ip + seq + udata */
756 "Dest Unreachable", /* net, host, proto, port, frag, sr + IP */
757 "Source Quench", /* IP */
758 "Redirect", /* redirect type, gateway, + IP */
760 "Time Exceeded", /* transit, frag reassem + IP */
761 "Parameter Problem", /* pointer + IP */
762 "Timestamp", /* id + seq + three timestamps */
763 "Timestamp Reply", /* " */
764 "Info Request", /* id + sq */
771 * Print a descriptive string about an ICMP header.
776 switch(icp
->icmp_type
) {
778 (void)printf("Echo Reply\n");
779 /* XXX ID + Seq + Data */
782 switch(icp
->icmp_code
) {
783 case ICMP_UNREACH_NET
:
784 (void)printf("Destination Net Unreachable\n");
786 case ICMP_UNREACH_HOST
:
787 (void)printf("Destination Host Unreachable\n");
789 case ICMP_UNREACH_PROTOCOL
:
790 (void)printf("Destination Protocol Unreachable\n");
792 case ICMP_UNREACH_PORT
:
793 (void)printf("Destination Port Unreachable\n");
795 case ICMP_UNREACH_NEEDFRAG
:
796 (void)printf("frag needed and DF set\n");
798 case ICMP_UNREACH_SRCFAIL
:
799 (void)printf("Source Route Failed\n");
802 (void)printf("Dest Unreachable, Bad Code: %d\n",
806 /* Print returned IP header information */
808 pr_retip(&icp
->icmp_ip
);
810 pr_retip((struct ip
*)icp
->icmp_data
);
813 case ICMP_SOURCEQUENCH
:
814 (void)printf("Source Quench\n");
816 pr_retip(&icp
->icmp_ip
);
818 pr_retip((struct ip
*)icp
->icmp_data
);
822 switch(icp
->icmp_code
) {
823 case ICMP_REDIRECT_NET
:
824 (void)printf("Redirect Network");
826 case ICMP_REDIRECT_HOST
:
827 (void)printf("Redirect Host");
829 case ICMP_REDIRECT_TOSNET
:
830 (void)printf("Redirect Type of Service and Network");
832 case ICMP_REDIRECT_TOSHOST
:
833 (void)printf("Redirect Type of Service and Host");
836 (void)printf("Redirect, Bad Code: %d", icp
->icmp_code
);
839 (void)printf("(New addr: 0x%08lx)\n", icp
->icmp_gwaddr
.s_addr
);
841 pr_retip(&icp
->icmp_ip
);
843 pr_retip((struct ip
*)icp
->icmp_data
);
847 (void)printf("Echo Request\n");
848 /* XXX ID + Seq + Data */
851 switch(icp
->icmp_code
) {
852 case ICMP_TIMXCEED_INTRANS
:
853 (void)printf("Time to live exceeded\n");
855 case ICMP_TIMXCEED_REASS
:
856 (void)printf("Frag reassembly time exceeded\n");
859 (void)printf("Time exceeded, Bad Code: %d\n",
864 pr_retip(&icp
->icmp_ip
);
866 pr_retip((struct ip
*)icp
->icmp_data
);
870 (void)printf("Parameter problem: pointer = 0x%02x\n",
871 icp
->icmp_hun
.ih_pptr
);
873 pr_retip(&icp
->icmp_ip
);
875 pr_retip((struct ip
*)icp
->icmp_data
);
879 (void)printf("Timestamp\n");
880 /* XXX ID + Seq + 3 timestamps */
882 case ICMP_TSTAMPREPLY
:
883 (void)printf("Timestamp Reply\n");
884 /* XXX ID + Seq + 3 timestamps */
887 (void)printf("Information Request\n");
891 (void)printf("Information Reply\n");
896 (void)printf("Address Mask Request\n");
899 #ifdef ICMP_MASKREPLY
901 (void)printf("Address Mask Reply\n");
905 (void)printf("Bad ICMP type: %d\n", icp
->icmp_type
);
911 * Print an IP header with options.
919 hlen
= ip
->ip_hl
<< 2;
920 cp
= (u_char
*)ip
+ 20; /* point to options */
922 (void)printf("Vr HL TOS Len ID Flg off TTL Pro cks Src Dst Data\n");
923 (void)printf(" %1x %1x %02x %04x %04x",
924 ip
->ip_v
, ip
->ip_hl
, ip
->ip_tos
, ip
->ip_len
, ip
->ip_id
);
925 (void)printf(" %1x %04x", ((ip
->ip_off
) & 0xe000) >> 13,
926 (ip
->ip_off
) & 0x1fff);
927 (void)printf(" %02x %02x %04x", ip
->ip_ttl
, ip
->ip_p
, ip
->ip_sum
);
928 (void)printf(" %s ", inet_ntoa(*(struct in_addr
*)&ip
->ip_src
.s_addr
));
929 (void)printf(" %s ", inet_ntoa(*(struct in_addr
*)&ip
->ip_dst
.s_addr
));
930 /* dump and option bytes */
931 while (hlen
-- > 20) {
932 (void)printf("%02x", *cp
++);
939 * Return an ascii host address as a dotted quad and optionally with
949 if ((options
& F_NUMERIC
) ||
950 !(hp
= gethostbyaddr((char *)&l
, 4, AF_INET
)))
951 (void)sprintf(buf
, "%s", inet_ntoa(*(struct in_addr
*)&l
));
953 (void)sprintf(buf
, "%s (%s)", hp
->h_name
,
954 inet_ntoa(*(struct in_addr
*)&l
));
960 * Dump some info on a returned (via ICMP) IP packet.
969 hlen
= ip
->ip_hl
<< 2;
970 cp
= (u_char
*)ip
+ hlen
;
973 (void)printf("TCP: from port %u, to port %u (decimal)\n",
974 (*cp
* 256 + *(cp
+ 1)), (*(cp
+ 2) * 256 + *(cp
+ 3)));
975 else if (ip
->ip_p
== 17)
976 (void)printf("UDP: from port %u, to port %u (decimal)\n",
977 (*cp
* 256 + *(cp
+ 1)), (*(cp
+ 2) * 256 + *(cp
+ 3)));
983 register int ii
, jj
, kk
;
987 for (cp
= patp
; *cp
; cp
++)
988 if (!isxdigit(*cp
)) {
989 (void)fprintf(stderr
,
990 "ping: patterns must be specified as hex digits.\n");
994 "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x",
995 &pat
[0], &pat
[1], &pat
[2], &pat
[3], &pat
[4], &pat
[5], &pat
[6],
996 &pat
[7], &pat
[8], &pat
[9], &pat
[10], &pat
[11], &pat
[12],
997 &pat
[13], &pat
[14], &pat
[15]);
1001 kk
<= MAXPACKET
- (8 + sizeof(struct timeval
) + ii
);
1003 for (jj
= 0; jj
< ii
; ++jj
)
1004 bp
[jj
+ kk
] = pat
[jj
];
1005 if (!(options
& F_QUIET
)) {
1006 (void)printf("PATTERN: 0x");
1007 for (jj
= 0; jj
< ii
; ++jj
)
1008 (void)printf("%02x", bp
[jj
] & 0xFF);
1015 (void)fprintf(stderr
,
1016 "usage: ping [-Rdfnqrv] [-c count] [-i wait] [-l preload]\n\t[-p pattern] [-s packetsize] host\n");