|
|
1.1 root 1: /*
2: * Copyright (c) 1989 The Regents of the University of California.
3: * All rights reserved.
4: *
5: * This code is derived from software contributed to Berkeley by
6: * Mike Muuss.
7: *
8: * Redistribution and use in source and binary forms are permitted
9: * provided that: (1) source distributions retain this entire copyright
10: * notice and comment, and (2) distributions including binaries display
11: * the following acknowledgement: ``This product includes software
12: * developed by the University of California, Berkeley and its contributors''
13: * in the documentation or other materials provided with the distribution
14: * and in all advertising materials mentioning features or use of this
15: * software. Neither the name of the University nor the names of its
16: * contributors may be used to endorse or promote products derived
17: * from this software without specific prior written permission.
18: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
19: * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
20: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
21: */
22:
23: #ifndef lint
24: char copyright[] =
25: "@(#) Copyright (c) 1989 The Regents of the University of California.\n\
26: All rights reserved.\n";
27: #endif /* not lint */
28:
29: #ifndef lint
30: static char sccsid[] = "@(#)ping.c 5.6 (Berkeley) 6/1/90";
31: #endif /* not lint */
32:
33: /*
34: * P I N G . C
35: *
36: * Using the InterNet Control Message Protocol (ICMP) "ECHO" facility,
37: * measure round-trip-delays and packet loss across network paths.
38: *
39: * Author -
40: * Mike Muuss
41: * U. S. Army Ballistic Research Laboratory
42: * December, 1983
43: *
44: * Status -
45: * Public Domain. Distribution Unlimited.
46: * Bugs -
47: * More statistics could always be gathered.
48: * This program has to run SUID to ROOT to access the ICMP socket.
49: */
50:
51: #include <sys/param.h>
52: #include <sys/socket.h>
53: #include <sys/file.h>
54: #include <sys/time.h>
55: #include <sys/signal.h>
56:
57: #include <netinet/in_systm.h>
58: #include <netinet/in.h>
59: #include <netinet/ip.h>
60: #include <netinet/ip_icmp.h>
61: #include <netinet/ip_var.h>
62: #include <netdb.h>
63: #include <unistd.h>
64: #include <stdio.h>
65: #include <ctype.h>
66: #include <errno.h>
67: #include <string.h>
68:
69: #define DEFDATALEN (64 - 8) /* default data length */
70: #define MAXIPLEN 60
71: #define MAXICMPLEN 76
72: #define MAXPACKET (65536 - 60 - 8)/* max packet size */
73: #define MAXWAIT 10 /* max seconds to wait for response */
74: #define NROUTES 9 /* number of record route slots */
75:
76: #define A(bit) rcvd_tbl[(bit)>>3] /* identify byte in array */
77: #define B(bit) (1 << ((bit) & 0x07)) /* identify bit in byte */
78: #define SET(bit) (A(bit) |= B(bit))
79: #define CLR(bit) (A(bit) &= (~B(bit)))
80: #define TST(bit) (A(bit) & B(bit))
81:
82: /* various options */
83: int options;
84: #define F_FLOOD 0x001
85: #define F_INTERVAL 0x002
86: #define F_NUMERIC 0x004
87: #define F_PINGFILLED 0x008
88: #define F_QUIET 0x010
89: #define F_RROUTE 0x020
90: #define F_SO_DEBUG 0x040
91: #define F_SO_DONTROUTE 0x080
92: #define F_VERBOSE 0x100
93:
94: /*
95: * MAX_DUP_CHK is the number of bits in received table, i.e. the maximum
96: * number of received sequence numbers we can keep track of. Change 128
97: * to 8192 for complete accuracy...
98: */
99: #define MAX_DUP_CHK (8 * 128)
100: int mx_dup_ck = MAX_DUP_CHK;
101: char rcvd_tbl[MAX_DUP_CHK / 8];
102:
103: struct sockaddr whereto; /* who to ping */
104: int datalen = DEFDATALEN;
105: int s; /* socket file descriptor */
106: u_char outpack[MAXPACKET];
107: char BSPACE = '\b'; /* characters written for flood */
108: char DOT = '.';
109: char *hostname;
110: int ident; /* process id to identify our packets */
111:
112: /* counters */
113: long npackets; /* max packets to transmit */
114: long nreceived; /* # of packets we got back */
115: long nrepeats; /* number of duplicates */
116: long ntransmitted; /* sequence # for outbound packets = #sent */
117: int interval = 1; /* interval between packets */
118:
119: /* timing */
120: int timing; /* flag to do timing */
121: long tmin = LONG_MAX; /* minimum round trip time */
122: long tmax; /* maximum round trip time */
123: u_long tsum; /* sum of all times, for doing average */
124:
125: u_long inet_addr();
126: char *inet_ntoa(), *pr_addr();
127: int catcher(), finish();
128:
129: main(argc, argv)
130: int argc;
131: char **argv;
132: {
133: extern int errno, optind;
134: extern char *optarg;
135: struct timeval timeout;
136: struct hostent *hp;
137: struct sockaddr_in *to;
138: struct protoent *proto;
139: register int i;
140: int ch, fdmask, hold, packlen, preload;
141: u_char *datap, *packet;
142: char *target, hnamebuf[MAXHOSTNAMELEN], *malloc();
143: #ifdef IP_OPTIONS
144: char rspace[3 + 4 * NROUTES + 1]; /* record route space */
145: #endif
146:
147: preload = 0;
148: datap = &outpack[8 + sizeof(struct timeval)];
149: while ((ch = getopt(argc, argv, "Rc:dfh:i:l:np:qrs:v")) != EOF)
150: switch(ch) {
151: case 'c':
152: npackets = atoi(optarg);
153: if (npackets <= 0) {
154: (void)fprintf(stderr,
155: "ping: bad number of packets to transmit.\n");
156: exit(1);
157: }
158: break;
159: case 'd':
160: options |= F_SO_DEBUG;
161: break;
162: case 'f':
163: if (getuid()) {
164: (void)fprintf(stderr,
165: "ping: you must be root to use the -f option.\n");
166: exit(1);
167: }
168: options |= F_FLOOD;
169: setbuf(stdout, (char *)NULL);
170: break;
171: case 'i': /* wait between sending packets */
172: interval = atoi(optarg);
173: if (interval <= 0) {
174: (void)fprintf(stderr,
175: "ping: bad timing interval.\n");
176: exit(1);
177: }
178: options |= F_INTERVAL;
179: break;
180: case 'l':
181: preload = atoi(optarg);
182: if (preload < 0) {
183: (void)fprintf(stderr,
184: "ping: bad preload value.\n");
185: exit(1);
186: }
187: break;
188: case 'n':
189: options |= F_NUMERIC;
190: break;
191: case 'p': /* fill buffer with user pattern */
192: options |= F_PINGFILLED;
193: fill((char *)datap, optarg);
194: break;
195: case 'q':
196: options |= F_QUIET;
197: break;
198: case 'R':
199: options |= F_RROUTE;
200: break;
201: case 'r':
202: options |= F_SO_DONTROUTE;
203: break;
204: case 's': /* size of packet to send */
205: datalen = atoi(optarg);
206: if (datalen > MAXPACKET) {
207: (void)fprintf(stderr,
208: "ping: packet size too large.\n");
209: exit(1);
210: }
211: if (datalen <= 0) {
212: (void)fprintf(stderr,
213: "ping: illegal packet size.\n");
214: exit(1);
215: }
216: break;
217: case 'v':
218: options |= F_VERBOSE;
219: break;
220: default:
221: usage();
222: }
223: argc -= optind;
224: argv += optind;
225:
226: if (argc != 1)
227: usage();
228: target = *argv;
229:
230: bzero((char *)&whereto, sizeof(struct sockaddr));
231: to = (struct sockaddr_in *)&whereto;
232: to->sin_family = AF_INET;
233: to->sin_addr.s_addr = inet_addr(target);
234: if (to->sin_addr.s_addr != (u_int)-1)
235: hostname = target;
236: else {
237: hp = gethostbyname(target);
238: if (!hp) {
239: (void)fprintf(stderr,
240: "ping: unknown host %s\n", target);
241: exit(1);
242: }
243: to->sin_family = hp->h_addrtype;
244: bcopy(hp->h_addr, (caddr_t)&to->sin_addr, hp->h_length);
245: (void)strncpy(hnamebuf, hp->h_name, sizeof(hnamebuf) - 1);
246: hostname = hnamebuf;
247: }
248:
249: if (options & F_FLOOD && options & F_INTERVAL) {
250: (void)fprintf(stderr,
251: "ping: -f and -i incompatible options.\n");
252: exit(1);
253: }
254:
255: if (datalen >= sizeof(struct timeval)) /* can we time transfer */
256: timing = 1;
257: packlen = datalen + MAXIPLEN + MAXICMPLEN;
258: if (!(packet = (u_char *)malloc((u_int)packlen))) {
259: (void)fprintf(stderr, "ping: out of memory.\n");
260: exit(1);
261: }
262: if (!(options & F_PINGFILLED))
263: for (i = 8; i < datalen; ++i)
264: *datap++ = i;
265:
266: ident = getpid() & 0xFFFF;
267:
268: if (!(proto = getprotobyname("icmp"))) {
269: (void)fprintf(stderr, "ping: unknown protocol icmp.\n");
270: exit(1);
271: }
272: if ((s = socket(AF_INET, SOCK_RAW, proto->p_proto)) < 0) {
273: perror("ping: socket");
274: exit(1);
275: }
276: hold = 1;
277: if (options & F_SO_DEBUG)
278: (void)setsockopt(s, SOL_SOCKET, SO_DEBUG, (char *)&hold,
279: sizeof(hold));
280: if (options & F_SO_DONTROUTE)
281: (void)setsockopt(s, SOL_SOCKET, SO_DONTROUTE, (char *)&hold,
282: sizeof(hold));
283:
284: /* record route option */
285: if (options & F_RROUTE) {
286: #ifdef IP_OPTIONS
287: rspace[IPOPT_OPTVAL] = IPOPT_RR;
288: rspace[IPOPT_OLEN] = sizeof(rspace)-1;
289: rspace[IPOPT_OFFSET] = IPOPT_MINOFF;
290: if (setsockopt(s, IPPROTO_IP, IP_OPTIONS, rspace,
291: sizeof(rspace)) < 0) {
292: perror("ping: record route");
293: exit(1);
294: }
295: #else
296: (void)fprintf(stderr,
297: "ping: record route not available in this implementation.\n");
298: exit(1);
299: #endif /* IP_OPTIONS */
300: }
301:
302: /*
303: * When pinging the broadcast address, you can get a lot of answers.
304: * Doing something so evil is useful if you are trying to stress the
305: * ethernet, or just want to fill the arp cache to get some stuff for
306: * /etc/ethers.
307: */
308: hold = 48 * 1024;
309: (void)setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *)&hold,
310: sizeof(hold));
311:
312: if (to->sin_family == AF_INET)
313: (void)printf("PING %s (%s): %d data bytes\n", hostname,
314: inet_ntoa(*(struct in_addr *)&to->sin_addr.s_addr),
315: datalen);
316: else
317: (void)printf("PING %s: %d data bytes\n", hostname, datalen);
318:
319: (void)signal(SIGINT, finish);
320: (void)signal(SIGALRM, catcher);
321:
322: while (preload--) /* fire off them quickies */
323: pinger();
324:
325: if ((options & F_FLOOD) == 0)
326: catcher(); /* start things going */
327:
328: for (;;) {
329: struct sockaddr_in from;
330: register int cc;
331: int fromlen;
332:
333: if (options & F_FLOOD) {
334: pinger();
335: timeout.tv_sec = 0;
336: timeout.tv_usec = 10000;
337: fdmask = 1 << s;
338: if (select(s + 1, (fd_set *)&fdmask, (fd_set *)NULL,
339: (fd_set *)NULL, &timeout) < 1)
340: continue;
341: }
342: fromlen = sizeof(from);
343: if ((cc = recvfrom(s, (char *)packet, packlen, 0,
344: (struct sockaddr *)&from, &fromlen)) < 0) {
345: if (errno == EINTR)
346: continue;
347: perror("ping: recvfrom");
348: continue;
349: }
350: pr_pack((char *)packet, cc, &from);
351: if (npackets && nreceived >= npackets)
352: break;
353: }
354: finish();
355: /* NOTREACHED */
356: }
357:
358: /*
359: * catcher --
360: * This routine causes another PING to be transmitted, and then
361: * schedules another SIGALRM for 1 second from now.
362: *
363: * bug --
364: * Our sense of time will slowly skew (i.e., packets will not be
365: * launched exactly at 1-second intervals). This does not affect the
366: * quality of the delay and loss statistics.
367: */
368: catcher()
369: {
370: int waittime;
371:
372: pinger();
373: (void)signal(SIGALRM, catcher);
374: if (!npackets || ntransmitted < npackets)
375: alarm((u_int)interval);
376: else {
377: if (nreceived) {
378: waittime = 2 * tmax / 1000;
379: if (!waittime)
380: waittime = 1;
381: } else
382: waittime = MAXWAIT;
383: (void)signal(SIGALRM, finish);
384: (void)alarm((u_int)waittime);
385: }
386: }
387:
388: /*
389: * pinger --
390: * Compose and transmit an ICMP ECHO REQUEST packet. The IP packet
391: * will be added on by the kernel. The ID field is our UNIX process ID,
392: * and the sequence number is an ascending integer. The first 8 bytes
393: * of the data portion are used to hold a UNIX "timeval" struct in VAX
394: * byte-order, to compute the round-trip time.
395: */
396: pinger()
397: {
398: register struct icmp *icp;
399: register int cc;
400: int i;
401:
402: icp = (struct icmp *)outpack;
403: icp->icmp_type = ICMP_ECHO;
404: icp->icmp_code = 0;
405: icp->icmp_cksum = 0;
406: icp->icmp_seq = ntransmitted++;
407: icp->icmp_id = ident; /* ID */
408:
409: CLR(icp->icmp_seq % mx_dup_ck);
410:
411: if (timing)
412: (void)gettimeofday((struct timeval *)&outpack[8],
413: (struct timezone *)NULL);
414:
415: cc = datalen + 8; /* skips ICMP portion */
416:
417: /* compute ICMP checksum here */
418: icp->icmp_cksum = in_cksum((u_short *)icp, cc);
419:
420: i = sendto(s, (char *)outpack, cc, 0, &whereto,
421: sizeof(struct sockaddr));
422:
423: if (i < 0 || i != cc) {
424: if (i < 0)
425: perror("ping: sendto");
426: (void)printf("ping: wrote %s %d chars, ret=%d\n",
427: hostname, cc, i);
428: }
429: if (options & F_FLOOD)
430: (void)write(STDOUT_FILENO, &DOT, 1);
431: }
432:
433: /*
434: * pr_pack --
435: * Print out the packet, if it came from us. This logic is necessary
436: * because ALL readers of the ICMP socket get a copy of ALL ICMP packets
437: * which arrive ('tis only fair). This permits multiple copies of this
438: * program to be run without having intermingled output (or statistics!).
439: */
440: pr_pack(buf, cc, from)
441: char *buf;
442: int cc;
443: struct sockaddr_in *from;
444: {
445: register struct icmp *icp;
446: register u_long l;
447: register int i, j;
448: register u_char *cp,*dp;
449: static int old_rrlen;
450: static char old_rr[MAX_IPOPTLEN];
451: struct ip *ip;
452: struct timeval tv, *tp;
453: long triptime;
454: int hlen, dupflag;
455:
456: (void)gettimeofday(&tv, (struct timezone *)NULL);
457:
458: /* Check the IP header */
459: ip = (struct ip *)buf;
460: hlen = ip->ip_hl << 2;
461: if (cc < hlen + ICMP_MINLEN) {
462: if (options & F_VERBOSE)
463: (void)fprintf(stderr,
464: "ping: packet too short (%d bytes) from %s\n", cc,
465: inet_ntoa(*(struct in_addr *)&from->sin_addr.s_addr));
466: return;
467: }
468:
469: /* Now the ICMP part */
470: cc -= hlen;
471: icp = (struct icmp *)(buf + hlen);
472: if (icp->icmp_type == ICMP_ECHOREPLY) {
473: if (icp->icmp_id != ident)
474: return; /* 'Twas not our ECHO */
475: ++nreceived;
476: if (timing) {
477: #ifndef icmp_data
478: tp = (struct timeval *)&icp->icmp_ip;
479: #else
480: tp = (struct timeval *)icp->icmp_data;
481: #endif
482: tvsub(&tv, tp);
483: triptime = tv.tv_sec * 1000 + (tv.tv_usec / 1000);
484: tsum += triptime;
485: if (triptime < tmin)
486: tmin = triptime;
487: if (triptime > tmax)
488: tmax = triptime;
489: }
490:
491: if (TST(icp->icmp_seq % mx_dup_ck)) {
492: ++nrepeats;
493: --nreceived;
494: dupflag = 1;
495: } else {
496: SET(icp->icmp_seq % mx_dup_ck);
497: dupflag = 0;
498: }
499:
500: if (options & F_QUIET)
501: return;
502:
503: if (options & F_FLOOD)
504: (void)write(STDOUT_FILENO, &BSPACE, 1);
505: else {
506: (void)printf("%d bytes from %s: icmp_seq=%u", cc,
507: inet_ntoa(*(struct in_addr *)&from->sin_addr.s_addr),
508: icp->icmp_seq);
509: (void)printf(" ttl=%d", ip->ip_ttl);
510: if (timing)
511: (void)printf(" time=%ld ms", triptime);
512: if (dupflag)
513: (void)printf(" (DUP!)");
514: /* check the data */
515: cp = (u_char*)&icp->icmp_data[8];
516: dp = &outpack[8 + sizeof(struct timeval)];
517: for (i = 8; i < datalen; ++i, ++cp, ++dp) {
518: if (*cp != *dp) {
519: (void)printf("\nwrong data byte #%d should be 0x%x but was 0x%x",
520: i, *dp, *cp);
521: cp = (u_char*)&icp->icmp_data[0];
522: for (i = 8; i < datalen; ++i, ++cp) {
523: if ((i % 32) == 8)
524: (void)printf("\n\t");
525: (void)printf("%x ", *cp);
526: }
527: break;
528: }
529: }
530: }
531: } else {
532: /* We've got something other than an ECHOREPLY */
533: if (!(options & F_VERBOSE))
534: return;
535: (void)printf("%d bytes from %s: ", cc,
536: pr_addr(from->sin_addr.s_addr));
537: pr_icmph(icp);
538: }
539:
540: /* Display any IP options */
541: cp = (u_char *)buf + sizeof(struct ip);
542:
543: /* ANSI C will force hlen to unsigned! */
544: for (; hlen > sizeof(struct ip); --hlen, ++cp)
545: switch (*cp) {
546: case IPOPT_EOL:
547: hlen = 0;
548: break;
549: case IPOPT_LSRR:
550: (void)printf("\nLSRR: ");
551: hlen -= 2;
552: j = *++cp;
553: ++cp;
554: if (j > IPOPT_MINOFF)
555: for (;;) {
556: l = *++cp;
557: l = (l<<8) + *++cp;
558: l = (l<<8) + *++cp;
559: l = (l<<8) + *++cp;
560: if (l == 0)
561: (void)printf("\t0.0.0.0");
562: else
563: (void)printf("\t%s", pr_addr(ntohl(l)));
564: hlen -= 4;
565: j -= 4;
566: if (j <= IPOPT_MINOFF)
567: break;
568: (void)putchar('\n');
569: }
570: break;
571: case IPOPT_RR:
572: j = *++cp; /* get length */
573: i = *++cp; /* and pointer */
574: hlen -= 2;
575: if (i > j)
576: i = j;
577: i -= IPOPT_MINOFF;
578: if (i <= 0)
579: continue;
580: if (i == old_rrlen
581: && cp == (u_char *)buf + sizeof(struct ip) + 2
582: && !bcmp((char *)cp, old_rr, i)
583: && !(options & F_FLOOD)) {
584: (void)printf("\t(same route)");
585: i = ((i + 3) / 4) * 4;
586: hlen -= i;
587: cp += i;
588: break;
589: }
590: old_rrlen = i;
591: bcopy((char *)cp, old_rr, i);
592: (void)printf("\nRR: ");
593: for (;;) {
594: l = *++cp;
595: l = (l<<8) + *++cp;
596: l = (l<<8) + *++cp;
597: l = (l<<8) + *++cp;
598: if (l == 0)
599: (void)printf("\t0.0.0.0");
600: else
601: (void)printf("\t%s", pr_addr(ntohl(l)));
602: hlen -= 4;
603: i -= 4;
604: if (i <= 0)
605: break;
606: (void)putchar('\n');
607: }
608: break;
609: case IPOPT_NOP:
610: (void)printf("\nNOP");
611: break;
612: default:
613: (void)printf("\nunknown option %x", *cp);
614: break;
615: }
616: if (!(options & F_FLOOD)) {
617: (void)putchar('\n');
618: (void)fflush(stdout);
619: }
620: }
621:
622: /*
623: * in_cksum --
624: * Checksum routine for Internet Protocol family headers (C Version)
625: */
626: in_cksum(addr, len)
627: u_short *addr;
628: int len;
629: {
630: register int nleft = len;
631: register u_short *w = addr;
632: register int sum = 0;
633: u_short answer = 0;
634:
635: /*
636: * Our algorithm is simple, using a 32 bit accumulator (sum), we add
637: * sequential 16 bit words to it, and at the end, fold back all the
638: * carry bits from the top 16 bits into the lower 16 bits.
639: */
640: while (nleft > 1) {
641: sum += *w++;
642: nleft -= 2;
643: }
644:
645: /* mop up an odd byte, if necessary */
646: if (nleft == 1) {
647: *(u_char *)(&answer) = *(u_char *)w ;
648: sum += answer;
649: }
650:
651: /* add back carry outs from top 16 bits to low 16 bits */
652: sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
653: sum += (sum >> 16); /* add carry */
654: answer = ~sum; /* truncate to 16 bits */
655: return(answer);
656: }
657:
658: /*
659: * tvsub --
660: * Subtract 2 timeval structs: out = out - in. Out is assumed to
661: * be >= in.
662: */
663: tvsub(out, in)
664: register struct timeval *out, *in;
665: {
666: if ((out->tv_usec -= in->tv_usec) < 0) {
667: --out->tv_sec;
668: out->tv_usec += 1000000;
669: }
670: out->tv_sec -= in->tv_sec;
671: }
672:
673: /*
674: * finish --
675: * Print out statistics, and give up.
676: */
677: finish()
678: {
679: (void)signal(SIGINT, SIG_IGN);
680: (void)putchar('\n');
681: (void)fflush(stdout);
682: (void)printf("--- %s ping statistics ---\n", hostname);
683: (void)printf("%ld packets transmitted, ", ntransmitted);
684: (void)printf("%ld packets received, ", nreceived);
685: if (nrepeats)
686: (void)printf("+%ld duplicates, ", nrepeats);
687: if (ntransmitted)
688: if (nreceived > ntransmitted)
689: (void)printf("-- somebody's printing up packets!");
690: else
691: (void)printf("%d%% packet loss",
692: (int) (((ntransmitted - nreceived) * 100) /
693: ntransmitted));
694: (void)putchar('\n');
695: if (nreceived && timing)
696: (void)printf("round-trip min/avg/max = %ld/%lu/%ld ms\n",
697: tmin, tsum / (nreceived + nrepeats), tmax);
698: exit(0);
699: }
700:
701: #ifdef notdef
702: static char *ttab[] = {
703: "Echo Reply", /* ip + seq + udata */
704: "Dest Unreachable", /* net, host, proto, port, frag, sr + IP */
705: "Source Quench", /* IP */
706: "Redirect", /* redirect type, gateway, + IP */
707: "Echo",
708: "Time Exceeded", /* transit, frag reassem + IP */
709: "Parameter Problem", /* pointer + IP */
710: "Timestamp", /* id + seq + three timestamps */
711: "Timestamp Reply", /* " */
712: "Info Request", /* id + sq */
713: "Info Reply" /* " */
714: };
715: #endif
716:
717: /*
718: * pr_icmph --
719: * Print a descriptive string about an ICMP header.
720: */
721: pr_icmph(icp)
722: struct icmp *icp;
723: {
724: switch(icp->icmp_type) {
725: case ICMP_ECHOREPLY:
726: (void)printf("Echo Reply\n");
727: /* XXX ID + Seq + Data */
728: break;
729: case ICMP_UNREACH:
730: switch(icp->icmp_code) {
731: case ICMP_UNREACH_NET:
732: (void)printf("Destination Net Unreachable\n");
733: break;
734: case ICMP_UNREACH_HOST:
735: (void)printf("Destination Host Unreachable\n");
736: break;
737: case ICMP_UNREACH_PROTOCOL:
738: (void)printf("Destination Protocol Unreachable\n");
739: break;
740: case ICMP_UNREACH_PORT:
741: (void)printf("Destination Port Unreachable\n");
742: break;
743: case ICMP_UNREACH_NEEDFRAG:
744: (void)printf("frag needed and DF set\n");
745: break;
746: case ICMP_UNREACH_SRCFAIL:
747: (void)printf("Source Route Failed\n");
748: break;
749: default:
750: (void)printf("Dest Unreachable, Bad Code: %d\n",
751: icp->icmp_code);
752: break;
753: }
754: /* Print returned IP header information */
755: #ifndef icmp_data
756: pr_retip(&icp->icmp_ip);
757: #else
758: pr_retip((struct ip *)icp->icmp_data);
759: #endif
760: break;
761: case ICMP_SOURCEQUENCH:
762: (void)printf("Source Quench\n");
763: #ifndef icmp_data
764: pr_retip(&icp->icmp_ip);
765: #else
766: pr_retip((struct ip *)icp->icmp_data);
767: #endif
768: break;
769: case ICMP_REDIRECT:
770: switch(icp->icmp_code) {
771: case ICMP_REDIRECT_NET:
772: (void)printf("Redirect Network");
773: break;
774: case ICMP_REDIRECT_HOST:
775: (void)printf("Redirect Host");
776: break;
777: case ICMP_REDIRECT_TOSNET:
778: (void)printf("Redirect Type of Service and Network");
779: break;
780: case ICMP_REDIRECT_TOSHOST:
781: (void)printf("Redirect Type of Service and Host");
782: break;
783: default:
784: (void)printf("Redirect, Bad Code: %d", icp->icmp_code);
785: break;
786: }
787: (void)printf("(New addr: 0x%08lx)\n", icp->icmp_gwaddr.s_addr);
788: #ifndef icmp_data
789: pr_retip(&icp->icmp_ip);
790: #else
791: pr_retip((struct ip *)icp->icmp_data);
792: #endif
793: break;
794: case ICMP_ECHO:
795: (void)printf("Echo Request\n");
796: /* XXX ID + Seq + Data */
797: break;
798: case ICMP_TIMXCEED:
799: switch(icp->icmp_code) {
800: case ICMP_TIMXCEED_INTRANS:
801: (void)printf("Time to live exceeded\n");
802: break;
803: case ICMP_TIMXCEED_REASS:
804: (void)printf("Frag reassembly time exceeded\n");
805: break;
806: default:
807: (void)printf("Time exceeded, Bad Code: %d\n",
808: icp->icmp_code);
809: break;
810: }
811: #ifndef icmp_data
812: pr_retip(&icp->icmp_ip);
813: #else
814: pr_retip((struct ip *)icp->icmp_data);
815: #endif
816: break;
817: case ICMP_PARAMPROB:
818: (void)printf("Parameter problem: pointer = 0x%02x\n",
819: icp->icmp_hun.ih_pptr);
820: #ifndef icmp_data
821: pr_retip(&icp->icmp_ip);
822: #else
823: pr_retip((struct ip *)icp->icmp_data);
824: #endif
825: break;
826: case ICMP_TSTAMP:
827: (void)printf("Timestamp\n");
828: /* XXX ID + Seq + 3 timestamps */
829: break;
830: case ICMP_TSTAMPREPLY:
831: (void)printf("Timestamp Reply\n");
832: /* XXX ID + Seq + 3 timestamps */
833: break;
834: case ICMP_IREQ:
835: (void)printf("Information Request\n");
836: /* XXX ID + Seq */
837: break;
838: case ICMP_IREQREPLY:
839: (void)printf("Information Reply\n");
840: /* XXX ID + Seq */
841: break;
842: #ifdef ICMP_MASKREQ
843: case ICMP_MASKREQ:
844: (void)printf("Address Mask Request\n");
845: break;
846: #endif
847: #ifdef ICMP_MASKREPLY
848: case ICMP_MASKREPLY:
849: (void)printf("Address Mask Reply\n");
850: break;
851: #endif
852: default:
853: (void)printf("Bad ICMP type: %d\n", icp->icmp_type);
854: }
855: }
856:
857: /*
858: * pr_iph --
859: * Print an IP header with options.
860: */
861: pr_iph(ip)
862: struct ip *ip;
863: {
864: int hlen;
865: u_char *cp;
866:
867: hlen = ip->ip_hl << 2;
868: cp = (u_char *)ip + 20; /* point to options */
869:
870: (void)printf("Vr HL TOS Len ID Flg off TTL Pro cks Src Dst Data\n");
871: (void)printf(" %1x %1x %02x %04x %04x",
872: ip->ip_v, ip->ip_hl, ip->ip_tos, ip->ip_len, ip->ip_id);
873: (void)printf(" %1x %04x", ((ip->ip_off) & 0xe000) >> 13,
874: (ip->ip_off) & 0x1fff);
875: (void)printf(" %02x %02x %04x", ip->ip_ttl, ip->ip_p, ip->ip_sum);
876: (void)printf(" %s ", inet_ntoa(*(struct in_addr *)&ip->ip_src.s_addr));
877: (void)printf(" %s ", inet_ntoa(*(struct in_addr *)&ip->ip_dst.s_addr));
878: /* dump and option bytes */
879: while (hlen-- > 20) {
880: (void)printf("%02x", *cp++);
881: }
882: (void)putchar('\n');
883: }
884:
885: /*
886: * pr_addr --
887: * Return an ascii host address as a dotted quad and optionally with
888: * a hostname.
889: */
890: char *
891: pr_addr(l)
892: u_long l;
893: {
894: struct hostent *hp;
895: static char buf[80];
896:
897: if ((options & F_NUMERIC) ||
898: !(hp = gethostbyaddr((char *)&l, 4, AF_INET)))
899: (void)sprintf(buf, "%s", inet_ntoa(*(struct in_addr *)&l));
900: else
901: (void)sprintf(buf, "%s (%s)", hp->h_name,
902: inet_ntoa(*(struct in_addr *)&l));
903: return(buf);
904: }
905:
906: /*
907: * pr_retip --
908: * Dump some info on a returned (via ICMP) IP packet.
909: */
910: pr_retip(ip)
911: struct ip *ip;
912: {
913: int hlen;
914: u_char *cp;
915:
916: pr_iph(ip);
917: hlen = ip->ip_hl << 2;
918: cp = (u_char *)ip + hlen;
919:
920: if (ip->ip_p == 6)
921: (void)printf("TCP: from port %u, to port %u (decimal)\n",
922: (*cp * 256 + *(cp + 1)), (*(cp + 2) * 256 + *(cp + 3)));
923: else if (ip->ip_p == 17)
924: (void)printf("UDP: from port %u, to port %u (decimal)\n",
925: (*cp * 256 + *(cp + 1)), (*(cp + 2) * 256 + *(cp + 3)));
926: }
927:
928: fill(bp, patp)
929: char *bp, *patp;
930: {
931: register int ii, jj, kk;
932: int pat[16];
933: char *cp;
934:
935: for (cp = patp; *cp; cp++)
936: if (!isxdigit(*cp)) {
937: (void)fprintf(stderr,
938: "ping: patterns must be specified as hex digits.\n");
939: exit(1);
940: }
941: ii = sscanf(patp,
942: "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x",
943: &pat[0], &pat[1], &pat[2], &pat[3], &pat[4], &pat[5], &pat[6],
944: &pat[7], &pat[8], &pat[9], &pat[10], &pat[11], &pat[12],
945: &pat[13], &pat[14], &pat[15]);
946:
947: if (ii > 0)
948: for (kk = 0; kk <= MAXPACKET - (8 + ii); kk += ii)
949: for (jj = 0; jj < ii; ++jj)
950: bp[jj + kk] = pat[jj];
951: if (!(options & F_QUIET)) {
952: (void)printf("PATTERN: 0x");
953: for (jj = 0; jj < ii; ++jj)
954: (void)printf("%02x", bp[jj] & 0xFF);
955: (void)printf("\n");
956: }
957: }
958:
959: usage()
960: {
961: (void)fprintf(stderr,
962: "usage: ping [-Rdfnqrv] [-c count] [-i wait] [-l preload]\n\t[-p pattern] [-s packetsize] host\n");
963: exit(1);
964: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.