]>
git.saurik.com Git - apple/network_cmds.git/blob - ping.tproj/ping.c
c152f095adb3a2eec8faa9553e68b6420d86e750
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
26 * Copyright (c) 1989, 1993
27 * The Regents of the University of California. All rights reserved.
29 * This code is derived from software contributed to Berkeley by
32 * Redistribution and use in source and binary forms, with or without
33 * modification, are permitted provided that the following conditions
35 * 1. Redistributions of source code must retain the above copyright
36 * notice, this list of conditions and the following disclaimer.
37 * 2. Redistributions in binary form must reproduce the above copyright
38 * notice, this list of conditions and the following disclaimer in the
39 * documentation and/or other materials provided with the distribution.
40 * 3. All advertising materials mentioning features or use of this software
41 * must display the following acknowledgement:
42 * This product includes software developed by the University of
43 * California, Berkeley and its contributors.
44 * 4. Neither the name of the University nor the names of its contributors
45 * may be used to endorse or promote products derived from this software
46 * without specific prior written permission.
48 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
65 * Using the InterNet Control Message Protocol (ICMP) "ECHO" facility,
66 * measure round-trip-delays and packet loss across network paths.
70 * U. S. Army Ballistic Research Laboratory
74 * Public Domain. Distribution Unlimited.
76 * More statistics could always be gathered.
77 * This program has to run SUID to ROOT to access the ICMP socket.
80 #include <sys/param.h>
81 #include <sys/socket.h>
84 #include <sys/signal.h>
86 #include <netinet/in_systm.h>
87 #include <netinet/in.h>
88 #include <netinet/ip.h>
89 #include <netinet/ip_icmp.h>
90 #include <netinet/ip_var.h>
98 #define DEFDATALEN (64 - 8) /* default data length */
100 #define MAXICMPLEN 76
101 #define MAXPACKET (65536 - 60 - 8)/* max packet size */
102 #define MAXWAIT 10 /* max seconds to wait for response */
103 #define NROUTES 9 /* number of record route slots */
105 #define A(bit) rcvd_tbl[(bit)>>3] /* identify byte in array */
106 #define B(bit) (1 << ((bit) & 0x07)) /* identify bit in byte */
107 #define SET(bit) (A(bit) |= B(bit))
108 #define CLR(bit) (A(bit) &= (~B(bit)))
109 #define TST(bit) (A(bit) & B(bit))
111 /* various options */
113 #define F_FLOOD 0x001
114 #define F_INTERVAL 0x002
115 #define F_NUMERIC 0x004
116 #define F_PINGFILLED 0x008
117 #define F_QUIET 0x010
118 #define F_RROUTE 0x020
119 #define F_SO_DEBUG 0x040
120 #define F_SO_DONTROUTE 0x080
121 #define F_VERBOSE 0x100
124 * MAX_DUP_CHK is the number of bits in received table, i.e. the maximum
125 * number of received sequence numbers we can keep track of. Change 128
126 * to 8192 for complete accuracy...
128 #define MAX_DUP_CHK (8 * 128)
129 int mx_dup_ck
= MAX_DUP_CHK
;
130 char rcvd_tbl
[MAX_DUP_CHK
/ 8];
132 struct sockaddr whereto
; /* who to ping */
133 int datalen
= DEFDATALEN
;
134 int s
; /* socket file descriptor */
135 u_char outpack
[MAXPACKET
];
136 char BSPACE
= '\b'; /* characters written for flood */
139 int ident
; /* process id to identify our packets */
142 long npackets
; /* max packets to transmit */
143 long nreceived
; /* # of packets we got back */
144 long nrepeats
; /* number of duplicates */
145 long ntransmitted
; /* sequence # for outbound packets = #sent */
146 int interval
= 1; /* interval between packets */
149 int timing
; /* flag to do timing */
150 double tmin
= 999999999.0; /* minimum round trip time */
151 double tmax
= 0.0; /* maximum round trip time */
152 double tsum
= 0.0; /* sum of all times, for doing average */
155 void catcher(), finish();
161 extern int errno
, optind
;
163 struct timeval timeout
;
165 struct sockaddr_in
*to
;
166 struct protoent
*proto
;
168 int ch
, fdmask
, hold
, packlen
, preload
;
169 u_char
*datap
, *packet
;
170 char *target
, hnamebuf
[MAXHOSTNAMELEN
], *malloc();
172 char rspace
[3 + 4 * NROUTES
+ 1]; /* record route space */
176 datap
= &outpack
[8 + sizeof(struct timeval
)];
177 while ((ch
= getopt(argc
, argv
, "Rc:dfh:i:l:np:qrs:v")) != EOF
)
180 npackets
= atoi(optarg
);
182 (void)fprintf(stderr
,
183 "ping: bad number of packets to transmit.\n");
188 options
|= F_SO_DEBUG
;
192 (void)fprintf(stderr
,
193 "ping: %s\n", strerror(EPERM
));
197 setbuf(stdout
, (char *)NULL
);
199 case 'i': /* wait between sending packets */
200 interval
= atoi(optarg
);
202 (void)fprintf(stderr
,
203 "ping: bad timing interval.\n");
206 options
|= F_INTERVAL
;
210 (void)fprintf(stderr
,
211 "ping: %s\n", strerror(EPERM
));
214 preload
= atoi(optarg
);
216 (void)fprintf(stderr
,
217 "ping: bad preload value.\n");
222 options
|= F_NUMERIC
;
224 case 'p': /* fill buffer with user pattern */
225 options
|= F_PINGFILLED
;
226 fill((char *)datap
, optarg
);
235 options
|= F_SO_DONTROUTE
;
237 case 's': /* size of packet to send */
238 datalen
= atoi(optarg
);
239 if (datalen
> MAXPACKET
) {
240 (void)fprintf(stderr
,
241 "ping: packet size too large.\n");
245 (void)fprintf(stderr
,
246 "ping: illegal packet size.\n");
251 options
|= F_VERBOSE
;
263 memset(&whereto
, 0, sizeof(struct sockaddr
));
264 to
= (struct sockaddr_in
*)&whereto
;
265 to
->sin_family
= AF_INET
;
266 to
->sin_addr
.s_addr
= inet_addr(target
);
267 if (to
->sin_addr
.s_addr
!= (u_int
)-1)
270 hp
= gethostbyname(target
);
272 (void)fprintf(stderr
,
273 "ping: unknown host %s\n", target
);
276 to
->sin_family
= hp
->h_addrtype
;
277 memmove(&to
->sin_addr
, hp
->h_addr
, hp
->h_length
);
278 (void)strncpy(hnamebuf
, hp
->h_name
, sizeof(hnamebuf
) - 1);
282 if (options
& F_FLOOD
&& options
& F_INTERVAL
) {
283 (void)fprintf(stderr
,
284 "ping: -f and -i incompatible options.\n");
288 if (datalen
>= sizeof(struct timeval
)) /* can we time transfer */
290 packlen
= datalen
+ MAXIPLEN
+ MAXICMPLEN
;
291 if (!(packet
= (u_char
*)malloc((u_int
)packlen
))) {
292 (void)fprintf(stderr
, "ping: out of memory.\n");
295 if (!(options
& F_PINGFILLED
))
296 for (i
= 8; i
< datalen
; ++i
)
299 ident
= getpid() & 0xFFFF;
301 if (!(proto
= getprotobyname("icmp"))) {
302 (void)fprintf(stderr
, "ping: unknown protocol icmp.\n");
305 if ((s
= socket(AF_INET
, SOCK_RAW
, proto
->p_proto
)) < 0) {
306 perror("ping: socket");
310 if (options
& F_SO_DEBUG
)
311 (void)setsockopt(s
, SOL_SOCKET
, SO_DEBUG
, (char *)&hold
,
313 if (options
& F_SO_DONTROUTE
)
314 (void)setsockopt(s
, SOL_SOCKET
, SO_DONTROUTE
, (char *)&hold
,
317 /* record route option */
318 if (options
& F_RROUTE
) {
320 rspace
[IPOPT_OPTVAL
] = IPOPT_RR
;
321 rspace
[IPOPT_OLEN
] = sizeof(rspace
)-1;
322 rspace
[IPOPT_OFFSET
] = IPOPT_MINOFF
;
323 if (setsockopt(s
, IPPROTO_IP
, IP_OPTIONS
, rspace
,
324 sizeof(rspace
)) < 0) {
325 perror("ping: record route");
329 (void)fprintf(stderr
,
330 "ping: record route not available in this implementation.\n");
332 #endif /* IP_OPTIONS */
336 * When pinging the broadcast address, you can get a lot of answers.
337 * Doing something so evil is useful if you are trying to stress the
338 * ethernet, or just want to fill the arp cache to get some stuff for
341 (void)setsockopt(s
, SOL_SOCKET
, SO_RCVBUF
, &packlen
, sizeof(packlen
));
343 if (to
->sin_family
== AF_INET
)
344 (void)printf("PING %s (%s): %d data bytes\n", hostname
,
345 inet_ntoa(*(struct in_addr
*)&to
->sin_addr
.s_addr
),
348 (void)printf("PING %s: %d data bytes\n", hostname
, datalen
);
350 (void)signal(SIGINT
, finish
);
351 (void)signal(SIGALRM
, catcher
);
353 while (preload
--) /* fire off them quickies */
356 if ((options
& F_FLOOD
) == 0)
357 catcher(); /* start things going */
360 struct sockaddr_in from
;
363 sigset_t omask
, nmask
;
365 if (options
& F_FLOOD
) {
368 timeout
.tv_usec
= 10000;
370 if (select(s
+ 1, (fd_set
*)&fdmask
, (fd_set
*)NULL
,
371 (fd_set
*)NULL
, &timeout
) < 1)
374 fromlen
= sizeof(from
);
375 if ((cc
= recvfrom(s
, (char *)packet
, packlen
, 0,
376 (struct sockaddr
*)&from
, &fromlen
)) < 0) {
379 perror("ping: recvfrom");
383 sigaddset(&nmask
, SIGALRM
);
384 sigprocmask(SIG_BLOCK
, &nmask
, &omask
);
385 pr_pack((char *)packet
, cc
, &from
);
386 sigprocmask(SIG_SETMASK
, &omask
, NULL
);
387 if (npackets
&& nreceived
>= npackets
)
396 * This routine causes another PING to be transmitted, and then
397 * schedules another SIGALRM for 1 second from now.
400 * Our sense of time will slowly skew (i.e., packets will not be
401 * launched exactly at 1-second intervals). This does not affect the
402 * quality of the delay and loss statistics.
410 (void)signal(SIGALRM
, catcher
);
411 if (!npackets
|| ntransmitted
< npackets
)
412 alarm((u_int
)interval
);
415 waittime
= 2 * tmax
/ 1000;
420 (void)signal(SIGALRM
, finish
);
421 (void)alarm((u_int
)waittime
);
427 * Compose and transmit an ICMP ECHO REQUEST packet. The IP packet
428 * will be added on by the kernel. The ID field is our UNIX process ID,
429 * and the sequence number is an ascending integer. The first 8 bytes
430 * of the data portion are used to hold a UNIX "timeval" struct in VAX
431 * byte-order, to compute the round-trip time.
435 register struct icmp
*icp
;
439 icp
= (struct icmp
*)outpack
;
440 icp
->icmp_type
= ICMP_ECHO
;
443 icp
->icmp_seq
= ntransmitted
++;
444 icp
->icmp_id
= ident
; /* ID */
446 CLR(icp
->icmp_seq
% mx_dup_ck
);
449 (void)gettimeofday((struct timeval
*)&outpack
[8],
450 (struct timezone
*)NULL
);
452 cc
= datalen
+ 8; /* skips ICMP portion */
454 /* compute ICMP checksum here */
455 icp
->icmp_cksum
= in_cksum((u_short
*)icp
, cc
);
457 i
= sendto(s
, (char *)outpack
, cc
, 0, &whereto
,
458 sizeof(struct sockaddr
));
460 if (i
< 0 || i
!= cc
) {
462 perror("ping: sendto");
463 (void)printf("ping: wrote %s %d chars, ret=%d\n",
466 if (!(options
& F_QUIET
) && options
& F_FLOOD
)
467 (void)write(STDOUT_FILENO
, &DOT
, 1);
472 * Print out the packet, if it came from us. This logic is necessary
473 * because ALL readers of the ICMP socket get a copy of ALL ICMP packets
474 * which arrive ('tis only fair). This permits multiple copies of this
475 * program to be run without having intermingled output (or statistics!).
477 pr_pack(buf
, cc
, from
)
480 struct sockaddr_in
*from
;
482 register struct icmp
*icp
;
485 register u_char
*cp
,*dp
;
486 static int old_rrlen
;
487 static char old_rr
[MAX_IPOPTLEN
];
489 struct timeval tv
, *tp
;
493 (void)gettimeofday(&tv
, (struct timezone
*)NULL
);
495 /* Check the IP header */
496 ip
= (struct ip
*)buf
;
497 hlen
= ip
->ip_hl
<< 2;
498 if (cc
< hlen
+ ICMP_MINLEN
) {
499 if (options
& F_VERBOSE
)
500 (void)fprintf(stderr
,
501 "ping: packet too short (%d bytes) from %s\n", cc
,
502 inet_ntoa(*(struct in_addr
*)&from
->sin_addr
.s_addr
));
506 /* Now the ICMP part */
508 icp
= (struct icmp
*)(buf
+ hlen
);
509 if (icp
->icmp_type
== ICMP_ECHOREPLY
) {
510 if (icp
->icmp_id
!= ident
)
511 return; /* 'Twas not our ECHO */
515 tp
= (struct timeval
*)&icp
->icmp_ip
;
517 tp
= (struct timeval
*)icp
->icmp_data
;
520 triptime
= ((double)tv
.tv_sec
) * 1000.0 +
521 ((double)tv
.tv_usec
) / 1000.0;
529 if (TST(icp
->icmp_seq
% mx_dup_ck
)) {
534 SET(icp
->icmp_seq
% mx_dup_ck
);
538 if (options
& F_QUIET
)
541 if (options
& F_FLOOD
)
542 (void)write(STDOUT_FILENO
, &BSPACE
, 1);
544 (void)printf("%d bytes from %s: icmp_seq=%u", cc
,
545 inet_ntoa(*(struct in_addr
*)&from
->sin_addr
.s_addr
),
547 (void)printf(" ttl=%d", ip
->ip_ttl
);
549 (void)printf(" time=%g ms", triptime
);
551 (void)printf(" (DUP!)");
553 cp
= (u_char
*)&icp
->icmp_data
[8];
554 dp
= &outpack
[8 + sizeof(struct timeval
)];
555 for (i
= 8; i
< datalen
; ++i
, ++cp
, ++dp
) {
557 (void)printf("\nwrong data byte #%d should be 0x%x but was 0x%x",
559 cp
= (u_char
*)&icp
->icmp_data
[0];
560 for (i
= 8; i
< datalen
; ++i
, ++cp
) {
562 (void)printf("\n\t");
563 (void)printf("%x ", *cp
);
570 /* We've got something other than an ECHOREPLY */
571 if (!(options
& F_VERBOSE
))
573 (void)printf("%d bytes from %s: ", cc
,
574 pr_addr(from
->sin_addr
.s_addr
));
578 /* Display any IP options */
579 cp
= (u_char
*)buf
+ sizeof(struct ip
);
581 for (; hlen
> (int)sizeof(struct ip
); --hlen
, ++cp
)
587 (void)printf("\nLSRR: ");
591 if (j
> IPOPT_MINOFF
)
598 (void)printf("\t0.0.0.0");
600 (void)printf("\t%s", pr_addr(ntohl(l
)));
603 if (j
<= IPOPT_MINOFF
)
609 j
= *++cp
; /* get length */
610 i
= *++cp
; /* and pointer */
618 && cp
== (u_char
*)buf
+ sizeof(struct ip
) + 2
619 && !memcmp(cp
, old_rr
, i
)
620 && !(options
& F_FLOOD
)) {
621 (void)printf("\t(same route)");
622 i
= ((i
+ 3) / 4) * 4;
627 if (i
< MAX_IPOPTLEN
) {
629 memcpy(old_rr
, cp
, i
);
633 (void)printf("\nRR: ");
641 (void)printf("\t0.0.0.0");
643 (void)printf("\t%s", pr_addr(ntohl(l
)));
649 if (j
>= MAX_IPOPTLEN
) {
650 (void)printf("\t(truncated route)");
657 (void)printf("\nNOP");
660 (void)printf("\nunknown option %x", *cp
);
663 if (!(options
& F_FLOOD
)) {
665 (void)fflush(stdout
);
671 * Checksum routine for Internet Protocol family headers (C Version)
677 register int nleft
= len
;
678 register u_short
*w
= addr
;
679 register int sum
= 0;
683 * Our algorithm is simple, using a 32 bit accumulator (sum), we add
684 * sequential 16 bit words to it, and at the end, fold back all the
685 * carry bits from the top 16 bits into the lower 16 bits.
692 /* mop up an odd byte, if necessary */
694 *(u_char
*)(&answer
) = *(u_char
*)w
;
698 /* add back carry outs from top 16 bits to low 16 bits */
699 sum
= (sum
>> 16) + (sum
& 0xffff); /* add hi 16 to low 16 */
700 sum
+= (sum
>> 16); /* add carry */
701 answer
= ~sum
; /* truncate to 16 bits */
707 * Subtract 2 timeval structs: out = out - in. Out is assumed to
711 register struct timeval
*out
, *in
;
713 if ((out
->tv_usec
-= in
->tv_usec
) < 0) {
715 out
->tv_usec
+= 1000000;
717 out
->tv_sec
-= in
->tv_sec
;
722 * Print out statistics, and give up.
729 (void)signal(SIGINT
, SIG_IGN
);
731 (void)fflush(stdout
);
732 (void)printf("--- %s ping statistics ---\n", hostname
);
733 (void)printf("%ld packets transmitted, ", ntransmitted
);
734 (void)printf("%ld packets received, ", nreceived
);
736 (void)printf("+%ld duplicates, ", nrepeats
);
738 if (nreceived
> ntransmitted
)
739 (void)printf("-- somebody's printing up packets!");
741 (void)printf("%d%% packet loss",
742 (int) (((ntransmitted
- nreceived
) * 100) /
745 if (nreceived
&& timing
) {
746 /* Only display average to microseconds */
747 i
= 1000.0 * tsum
/ (nreceived
+ nrepeats
);
748 (void)printf("round-trip min/avg/max = %g/%g/%g ms\n",
749 tmin
, ((double)i
) / 1000.0, tmax
);
755 static char *ttab
[] = {
756 "Echo Reply", /* ip + seq + udata */
757 "Dest Unreachable", /* net, host, proto, port, frag, sr + IP */
758 "Source Quench", /* IP */
759 "Redirect", /* redirect type, gateway, + IP */
761 "Time Exceeded", /* transit, frag reassem + IP */
762 "Parameter Problem", /* pointer + IP */
763 "Timestamp", /* id + seq + three timestamps */
764 "Timestamp Reply", /* " */
765 "Info Request", /* id + sq */
772 * Print a descriptive string about an ICMP header.
777 switch(icp
->icmp_type
) {
779 (void)printf("Echo Reply\n");
780 /* XXX ID + Seq + Data */
783 switch(icp
->icmp_code
) {
784 case ICMP_UNREACH_NET
:
785 (void)printf("Destination Net Unreachable\n");
787 case ICMP_UNREACH_HOST
:
788 (void)printf("Destination Host Unreachable\n");
790 case ICMP_UNREACH_PROTOCOL
:
791 (void)printf("Destination Protocol Unreachable\n");
793 case ICMP_UNREACH_PORT
:
794 (void)printf("Destination Port Unreachable\n");
796 case ICMP_UNREACH_NEEDFRAG
:
797 (void)printf("frag needed and DF set\n");
799 case ICMP_UNREACH_SRCFAIL
:
800 (void)printf("Source Route Failed\n");
803 (void)printf("Dest Unreachable, Bad Code: %d\n",
807 /* Print returned IP header information */
809 pr_retip(&icp
->icmp_ip
);
811 pr_retip((struct ip
*)icp
->icmp_data
);
814 case ICMP_SOURCEQUENCH
:
815 (void)printf("Source Quench\n");
817 pr_retip(&icp
->icmp_ip
);
819 pr_retip((struct ip
*)icp
->icmp_data
);
823 switch(icp
->icmp_code
) {
824 case ICMP_REDIRECT_NET
:
825 (void)printf("Redirect Network");
827 case ICMP_REDIRECT_HOST
:
828 (void)printf("Redirect Host");
830 case ICMP_REDIRECT_TOSNET
:
831 (void)printf("Redirect Type of Service and Network");
833 case ICMP_REDIRECT_TOSHOST
:
834 (void)printf("Redirect Type of Service and Host");
837 (void)printf("Redirect, Bad Code: %d", icp
->icmp_code
);
840 (void)printf("(New addr: 0x%08lx)\n", icp
->icmp_gwaddr
.s_addr
);
842 pr_retip(&icp
->icmp_ip
);
844 pr_retip((struct ip
*)icp
->icmp_data
);
848 (void)printf("Echo Request\n");
849 /* XXX ID + Seq + Data */
852 switch(icp
->icmp_code
) {
853 case ICMP_TIMXCEED_INTRANS
:
854 (void)printf("Time to live exceeded\n");
856 case ICMP_TIMXCEED_REASS
:
857 (void)printf("Frag reassembly time exceeded\n");
860 (void)printf("Time exceeded, Bad Code: %d\n",
865 pr_retip(&icp
->icmp_ip
);
867 pr_retip((struct ip
*)icp
->icmp_data
);
871 (void)printf("Parameter problem: pointer = 0x%02x\n",
872 icp
->icmp_hun
.ih_pptr
);
874 pr_retip(&icp
->icmp_ip
);
876 pr_retip((struct ip
*)icp
->icmp_data
);
880 (void)printf("Timestamp\n");
881 /* XXX ID + Seq + 3 timestamps */
883 case ICMP_TSTAMPREPLY
:
884 (void)printf("Timestamp Reply\n");
885 /* XXX ID + Seq + 3 timestamps */
888 (void)printf("Information Request\n");
892 (void)printf("Information Reply\n");
897 (void)printf("Address Mask Request\n");
900 #ifdef ICMP_MASKREPLY
902 (void)printf("Address Mask Reply\n");
906 (void)printf("Bad ICMP type: %d\n", icp
->icmp_type
);
912 * Print an IP header with options.
920 hlen
= ip
->ip_hl
<< 2;
921 cp
= (u_char
*)ip
+ 20; /* point to options */
923 (void)printf("Vr HL TOS Len ID Flg off TTL Pro cks Src Dst Data\n");
924 (void)printf(" %1x %1x %02x %04x %04x",
925 ip
->ip_v
, ip
->ip_hl
, ip
->ip_tos
, ip
->ip_len
, ip
->ip_id
);
926 (void)printf(" %1x %04x", ((ip
->ip_off
) & 0xe000) >> 13,
927 (ip
->ip_off
) & 0x1fff);
928 (void)printf(" %02x %02x %04x", ip
->ip_ttl
, ip
->ip_p
, ip
->ip_sum
);
929 (void)printf(" %s ", inet_ntoa(*(struct in_addr
*)&ip
->ip_src
.s_addr
));
930 (void)printf(" %s ", inet_ntoa(*(struct in_addr
*)&ip
->ip_dst
.s_addr
));
931 /* dump and option bytes */
932 while (hlen
-- > 20) {
933 (void)printf("%02x", *cp
++);
940 * Return an ascii host address as a dotted quad and optionally with
950 if ((options
& F_NUMERIC
) ||
951 !(hp
= gethostbyaddr((char *)&l
, 4, AF_INET
)))
952 (void)sprintf(buf
, "%s", inet_ntoa(*(struct in_addr
*)&l
));
954 (void)sprintf(buf
, "%s (%s)", hp
->h_name
,
955 inet_ntoa(*(struct in_addr
*)&l
));
961 * Dump some info on a returned (via ICMP) IP packet.
970 hlen
= ip
->ip_hl
<< 2;
971 cp
= (u_char
*)ip
+ hlen
;
974 (void)printf("TCP: from port %u, to port %u (decimal)\n",
975 (*cp
* 256 + *(cp
+ 1)), (*(cp
+ 2) * 256 + *(cp
+ 3)));
976 else if (ip
->ip_p
== 17)
977 (void)printf("UDP: from port %u, to port %u (decimal)\n",
978 (*cp
* 256 + *(cp
+ 1)), (*(cp
+ 2) * 256 + *(cp
+ 3)));
984 register int ii
, jj
, kk
;
988 for (cp
= patp
; *cp
; cp
++)
989 if (!isxdigit(*cp
)) {
990 (void)fprintf(stderr
,
991 "ping: patterns must be specified as hex digits.\n");
995 "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x",
996 &pat
[0], &pat
[1], &pat
[2], &pat
[3], &pat
[4], &pat
[5], &pat
[6],
997 &pat
[7], &pat
[8], &pat
[9], &pat
[10], &pat
[11], &pat
[12],
998 &pat
[13], &pat
[14], &pat
[15]);
1002 kk
<= MAXPACKET
- (8 + sizeof(struct timeval
) + ii
);
1004 for (jj
= 0; jj
< ii
; ++jj
)
1005 bp
[jj
+ kk
] = pat
[jj
];
1006 if (!(options
& F_QUIET
)) {
1007 (void)printf("PATTERN: 0x");
1008 for (jj
= 0; jj
< ii
; ++jj
)
1009 (void)printf("%02x", bp
[jj
] & 0xFF);
1016 (void)fprintf(stderr
,
1017 "usage: ping [-Rdfnqrv] [-c count] [-i wait] [-l preload]\n\t[-p pattern] [-s packetsize] host\n");