dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / cmd-inet / usr.sbin / ping / ping_aux.c
blob9db03cc7a07375aaca2b3a2ff52d94c4d008a24a
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
20 * CDDL HEADER END
23 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
31 * Copyright 2015, Joyent, Inc.
35 * Portions of this source code were derived from Berkeley 4.3 BSD
36 * under license from the Regents of the University of California.
39 #include <stdio.h>
40 #include <string.h>
41 #include <strings.h>
42 #include <errno.h>
43 #include <fcntl.h>
44 #include <unistd.h>
45 #include <signal.h>
47 #include <sys/time.h>
48 #include <sys/param.h>
49 #include <sys/socket.h>
50 #include <sys/sockio.h>
51 #include <sys/stropts.h>
52 #include <sys/file.h>
53 #include <arpa/inet.h>
54 #include <net/if.h>
55 #include <netinet/in_systm.h>
56 #include <netinet/in.h>
57 #include <netinet/ip.h>
58 #include <netinet/ip_icmp.h>
59 #include <netinet/udp.h>
60 #include <netdb.h>
61 #include <stdlib.h>
63 #include <libinetutil.h>
64 #include "ping.h"
68 * IPv4 source routing option.
69 * In order to avoid padding for the alignment of IPv4 addresses, ipsr_addrs
70 * is defined as a 2-D array of uint8_t, instead of 1-D array of struct in_addr.
72 struct ip_sourceroute {
73 uint8_t ipsr_code;
74 uint8_t ipsr_len;
75 uint8_t ipsr_ptr;
76 /* up to 9 IPv4 addresses */
77 uint8_t ipsr_addrs[1][sizeof (struct in_addr)];
80 void check_reply(struct addrinfo *, struct msghdr *, int, ushort_t);
81 extern void find_dstaddr(ushort_t, union any_in_addr *);
82 extern boolean_t is_a_target(struct addrinfo *, union any_in_addr *);
83 extern char *pr_name(char *, int);
84 static void pr_options(uchar_t *, int);
85 extern char *pr_protocol(int);
86 static void pr_rropt(uchar_t *, int, boolean_t);
87 static void pr_tsopt(uchar_t *, int);
88 static char *pr_type(int);
89 extern void schedule_sigalrm();
90 extern void send_scheduled_probe();
91 extern boolean_t seq_match(ushort_t, int, ushort_t);
92 extern void sigalrm_handler();
93 void set_IPv4_options(int, union any_in_addr *, int, struct in_addr *,
94 struct in_addr *);
95 extern void tvsub(struct timeval *, struct timeval *);
98 * Set IPv4 options
100 void
101 set_IPv4_options(int sock, union any_in_addr *gw_IP_list, int gw_count,
102 struct in_addr *src, struct in_addr *dst)
104 int req_size;
105 char srr[ROUTE_SIZE + 1];
106 char *bufp;
107 int optsize = ROUTE_SIZE;
108 struct ip_sourceroute *srp;
109 struct ip_timestamp *tsp;
110 int i;
112 if (rr_option || ts_option || gw_count > 0) {
113 bzero(srr, sizeof (srr));
114 bufp = srr;
116 if (gw_count > 0) {
117 /* 3 = 1 (code) + 1 (len) + 1 (ptr) of src route opt. */
118 req_size = 3 + (sizeof (struct in_addr)) * gw_count;
120 if (optsize < req_size) {
121 Fprintf(stderr, "%s: too many IPv4 gateways\n",
122 progname);
123 exit(EXIT_FAILURE);
126 srp = (struct ip_sourceroute *)bufp;
127 srp->ipsr_code = strict ? IPOPT_SSRR : IPOPT_LSRR;
128 srp->ipsr_len = req_size;
129 srp->ipsr_ptr = IPOPT_MINOFF;
131 for (i = 0; i < gw_count; i++) {
132 bcopy((char *)&gw_IP_list[i].addr,
133 &srp->ipsr_addrs[i],
134 sizeof (struct in_addr));
136 optsize -= srp->ipsr_len;
137 bufp += srp->ipsr_len;
139 /* do we send a timestamp option? */
140 if (ts_option) {
141 if (optsize < IPOPT_MINOFF) {
142 Fprintf(stderr,
143 "%s: no room for timestamp option\n",
144 progname);
145 exit(EXIT_FAILURE);
147 /* LINTED */
148 tsp = (struct ip_timestamp *)bufp;
149 tsp->ipt_code = IPOPT_TS;
150 tsp->ipt_len = optsize;
151 tsp->ipt_ptr = IPOPT_MINOFF + 1;
152 tsp->ipt_flg = ts_flag & 0x0f;
154 if (tsp->ipt_flg > IPOPT_TS_TSANDADDR) {
155 req_size = IPOPT_MINOFF +
156 2 * sizeof (struct ipt_ta);
158 * Note: BSD/4.X is broken in their check so we
159 * have to bump up this number by at least one.
161 req_size++;
163 if (optsize < req_size) {
164 Fprintf(stderr, "%s: no room for "
165 "timestamp option\n", progname);
166 exit(EXIT_FAILURE);
169 bcopy((char *)dst,
170 &tsp->ipt_timestamp.ipt_ta[0].ipt_addr,
171 sizeof (struct in_addr));
173 bcopy((char *)src,
174 &tsp->ipt_timestamp.ipt_ta[1].ipt_addr,
175 sizeof (struct in_addr));
176 tsp->ipt_len = req_size;
179 optsize -= tsp->ipt_len;
180 bufp += tsp->ipt_len;
182 /* do we send a record route option? */
183 if (rr_option) {
184 if (optsize < IPOPT_MINOFF) {
185 Fprintf(stderr,
186 "%s: no room for record route option\n",
187 progname);
188 exit(EXIT_FAILURE);
192 * Format of record route option is same as source
193 * route option.
195 srp = (struct ip_sourceroute *)bufp;
196 srp->ipsr_code = IPOPT_RR;
197 srp->ipsr_len = optsize;
198 srp->ipsr_ptr = IPOPT_MINOFF;
200 optsize -= srp->ipsr_len;
201 bufp += srp->ipsr_len;
203 optsize = bufp - srr;
204 /* Round up to 4 byte boundary */
205 if (optsize & 0x3)
206 optsize = (optsize & ~0x3) + 4;
207 if (setsockopt(sock, IPPROTO_IP, IP_OPTIONS, srr, optsize) <
208 0) {
209 Fprintf(stderr, "%s: setsockopt IP_OPTIONS %s\n",
210 progname, strerror(errno));
211 exit(EXIT_FAILURE);
217 * Check out the packet to see if it came from us. This logic is necessary
218 * because ALL readers of the ICMP socket get a copy of ALL ICMP packets
219 * which arrive ('tis only fair). This permits multiple copies of this
220 * program to be run without having intermingled output (or statistics!).
222 void
223 check_reply(struct addrinfo *ai_dst, struct msghdr *msg, int cc,
224 ushort_t udp_src_port)
226 struct ip *ip;
227 struct icmp *icp;
228 struct udphdr *up;
229 union any_in_addr dst_addr;
230 uchar_t *buf;
231 int32_t *intp;
232 struct sockaddr_in *from;
233 struct timeval *tp;
234 struct timeval tv;
235 int hlen, hlen1;
236 int64_t triptime;
237 boolean_t valid_reply = _B_FALSE;
238 boolean_t reply_matched_current_target = _B_FALSE; /* Is the source */
239 /* address of this reply same */
240 /* as where we're sending */
241 /* currently? */
242 boolean_t last_reply_from_targetaddr = _B_FALSE; /* Is this stats, */
243 /* probe all with npackets>0 */
244 /* and we received reply for */
245 /* the last probe sent to */
246 /* targetaddr */
247 int cc_left;
248 char tmp_buf[INET6_ADDRSTRLEN];
249 static char *unreach[] = {
250 "Net Unreachable",
251 "Host Unreachable",
252 "Protocol Unreachable",
253 "Port Unreachable",
254 "Fragmentation needed and DF set",
255 "Source Route Failed",
256 /* The following are from RFC1700 */
257 "Net Unknown",
258 "Host Unknown",
259 "Source Host Isolated",
260 "Dest Net Prohibited",
261 "Dest Host Prohibited",
262 "Net Unreachable for TOS",
263 "Host Unreachable for TOS",
264 "Communication Administratively Prohibited",
265 "Host Precedence Violation",
266 "Precedence Cutoff in Effect"
268 static char *redirect[] = {
269 "Net",
270 "Host",
271 "TOS Net",
272 "TOS Host"
274 static char *timexceed[] = {
275 "Time exceeded in transit",
276 "Time exceeded during reassembly"
278 boolean_t print_newline = _B_FALSE;
279 int i;
281 /* decompose msghdr into useful pieces */
282 buf = (uchar_t *)msg->msg_iov->iov_base;
283 from = (struct sockaddr_in *)msg->msg_name;
285 /* LINTED */
286 intp = (int32_t *)buf;
288 ping_gettime(msg, &tv);
290 /* LINTED */
291 ip = (struct ip *)buf;
292 hlen = ip->ip_hl << 2;
294 if ((cc < sizeof (struct ip)) || (cc < hlen + ICMP_MINLEN)) {
295 if (verbose) {
296 Printf("packet too short (%d bytes) from %s\n", cc,
297 pr_name((char *)&from->sin_addr, AF_INET));
299 return;
302 cc -= hlen;
303 /* LINTED */
304 icp = (struct icmp *)(buf + hlen);
306 if (ip->ip_p == 0) {
308 * Assume that we are running on a pre-4.3BSD system
309 * such as SunOS before 4.0
311 /* LINTED */
312 icp = (struct icmp *)buf;
314 cc_left = cc - ICMP_MINLEN;
316 switch (icp->icmp_type) {
317 case ICMP_UNREACH:
318 ip = &icp->icmp_ip;
319 hlen1 = ip->ip_hl << 2;
321 /* check if we have enough of the packet to work on */
322 if ((cc_left < sizeof (struct ip)) ||
323 (cc_left < hlen1 + sizeof (struct udphdr))) {
324 if (verbose) {
325 Printf("packet too short (%d bytes) from %s\n",
326 cc, pr_name((char *)&from->sin_addr,
327 AF_INET));
329 return;
332 /* get the UDP packet */
333 cc_left -= hlen1 + sizeof (struct udphdr);
334 /* LINTED */
335 up = (struct udphdr *)((uchar_t *)ip + hlen1);
337 /* check to see if this is what we sent */
338 if (icp->icmp_code == ICMP_UNREACH_PORT &&
339 ip->ip_p == IPPROTO_UDP &&
340 udp_src_port == up->uh_sport &&
341 use_udp) {
342 valid_reply = _B_TRUE;
343 } else {
344 valid_reply = _B_FALSE;
347 if (valid_reply) {
349 * For this valid reply, if we are still sending to
350 * this target IP address, we'd like to do some
351 * updates to targetaddr, so hold SIGALRMs.
353 (void) sighold(SIGALRM);
354 is_alive = _B_TRUE;
355 nreceived++;
356 reply_matched_current_target =
357 seq_match(current_targetaddr->starting_seq_num,
358 current_targetaddr->num_sent,
359 ntohs(up->uh_dport));
360 if (reply_matched_current_target) {
361 current_targetaddr->got_reply = _B_TRUE;
362 nreceived_last_target++;
364 * Determine if stats, probe-all, and
365 * npackets != 0, and this is the reply for
366 * the last probe we sent to current target
367 * address.
369 if (stats && probe_all && npackets > 0 &&
370 ((current_targetaddr->starting_seq_num +
371 current_targetaddr->num_probes - 1) %
372 (MAX_PORT + 1) == ntohs(up->uh_dport)) &&
373 (current_targetaddr->num_probes ==
374 current_targetaddr->num_sent))
375 last_reply_from_targetaddr = _B_TRUE;
376 } else {
378 * If it's just probe_all and we just received
379 * a reply from a target address we were
380 * probing and had timed out (now we are probing
381 * some other target address), we ignore
382 * this reply.
384 if (probe_all && !stats) {
385 valid_reply = _B_FALSE;
387 * Only if it's verbose, we get a
388 * message regarding this reply,
389 * otherwise we are done here.
391 if (!verbose) {
392 (void) sigrelse(SIGALRM);
393 return;
399 /* stats mode doesn't print 'alive' messages */
400 if (valid_reply && !stats) {
402 * if we are still sending to the same target address,
403 * then stop it, because we know it's alive.
405 if (reply_matched_current_target) {
406 (void) alarm(0); /* cancel alarm */
407 (void) sigset(SIGALRM, SIG_IGN);
408 current_targetaddr->probing_done = _B_TRUE;
410 (void) sigrelse(SIGALRM);
412 if (!probe_all) {
413 Printf("%s is alive\n", targethost);
414 } else {
415 (void) inet_ntop(AF_INET, (void *)&ip->ip_dst,
416 tmp_buf, sizeof (tmp_buf));
418 if (nflag) {
419 Printf("%s is alive\n", tmp_buf);
420 } else {
421 Printf("%s (%s) is alive\n",
422 targethost, tmp_buf);
425 if (reply_matched_current_target) {
427 * Let's get things going again, but now
428 * ping will start sending to next target IP
429 * address.
431 send_scheduled_probe();
432 (void) sigset(SIGALRM, sigalrm_handler);
433 schedule_sigalrm();
435 return;
436 } else {
438 * If we are not moving to next targetaddr, let's
439 * release the SIGALRM now. We don't want to stall in
440 * the middle of probing a targetaddr if the pr_name()
441 * call (see below) takes longer.
443 if (!last_reply_from_targetaddr)
444 (void) sigrelse(SIGALRM);
445 /* else, we'll release it later */
448 dst_addr.addr = ip->ip_dst;
449 if (valid_reply) {
450 Printf("%d bytes from %s: ", cc,
451 pr_name((char *)&from->sin_addr, AF_INET));
452 Printf("udp_port=%d. ", ntohs(up->uh_dport));
453 print_newline = _B_TRUE;
454 } else if (is_a_target(ai_dst, &dst_addr) || verbose) {
455 if (icp->icmp_code >= A_CNT(unreach)) {
456 Printf("ICMP %d Unreachable from gateway %s\n",
457 icp->icmp_code,
458 pr_name((char *)&from->sin_addr, AF_INET));
459 } else {
460 Printf("ICMP %s from gateway %s\n",
461 unreach[icp->icmp_code],
462 pr_name((char *)&from->sin_addr, AF_INET));
464 Printf(" for %s from %s", pr_protocol(ip->ip_p),
465 pr_name((char *)&ip->ip_src, AF_INET));
466 Printf(" to %s", pr_name((char *)&ip->ip_dst, AF_INET));
467 if (ip->ip_p == IPPROTO_TCP ||
468 ip->ip_p == IPPROTO_UDP) {
469 Printf(" port %d ", ntohs(up->uh_dport));
471 print_newline = _B_TRUE;
474 /* if we are timing and the reply has a timeval */
475 if (valid_reply && datalen >= sizeof (struct timeval) &&
476 cc_left >= sizeof (struct timeval)) {
477 /* LINTED */
478 tp = (struct timeval *)((char *)up +
479 sizeof (struct udphdr));
480 (void) tvsub(&tv, tp);
481 triptime = (int64_t)tv.tv_sec * MICROSEC + tv.tv_usec;
482 Printf("time=" TIMEFORMAT " ms", triptime/1000.0);
483 tsum += triptime;
484 tsum2 += triptime*triptime;
485 if (triptime < tmin)
486 tmin = triptime;
487 if (triptime > tmax)
488 tmax = triptime;
489 print_newline = _B_TRUE;
491 if (print_newline)
492 (void) putchar('\n');
494 * If it's stats, probe-all, npackets > 0, and we received reply
495 * for the last probe sent to this target address, then we
496 * don't need to wait anymore, let's move on to next target
497 * address, now!
499 if (last_reply_from_targetaddr) {
500 (void) alarm(0); /* cancel alarm */
501 current_targetaddr->probing_done = _B_TRUE;
502 (void) sigrelse(SIGALRM);
503 send_scheduled_probe();
504 schedule_sigalrm();
506 break;
508 case ICMP_REDIRECT:
509 if (cc_left < sizeof (struct ip)) {
510 if (verbose) {
511 Printf("packet too short (%d bytes) from %s\n",
512 cc, pr_name((char *)&from->sin_addr,
513 AF_INET));
515 return;
518 ip = &icp->icmp_ip;
519 dst_addr.addr = ip->ip_dst;
520 if (is_a_target(ai_dst, &dst_addr) || verbose) {
521 if (icp->icmp_code >= A_CNT(redirect)) {
522 Printf("ICMP %d redirect from gateway %s\n",
523 icp->icmp_code,
524 pr_name((char *)&from->sin_addr, AF_INET));
525 } else {
526 Printf("ICMP %s redirect from gateway %s\n",
527 redirect[icp->icmp_code],
528 pr_name((char *)&from->sin_addr, AF_INET));
530 Printf(" to %s",
531 pr_name((char *)&icp->icmp_gwaddr, AF_INET));
532 Printf(" for %s\n",
533 pr_name((char *)&ip->ip_dst, AF_INET));
535 break;
537 case ICMP_ECHOREPLY:
538 if (ntohs(icp->icmp_id) == ident) {
539 if (!use_udp && !use_icmp_ts)
540 valid_reply = _B_TRUE;
541 else
542 valid_reply = _B_FALSE;
543 } else {
544 return;
547 if (valid_reply) {
549 * For this valid reply, if we are still sending to
550 * this target IP address, we'd like to do some
551 * updates to targetaddr, so hold SIGALRMs.
553 (void) sighold(SIGALRM);
554 is_alive = _B_TRUE;
555 nreceived++;
556 reply_matched_current_target =
557 seq_match(current_targetaddr->starting_seq_num,
558 current_targetaddr->num_sent,
559 ntohs(icp->icmp_seq));
560 if (reply_matched_current_target) {
561 current_targetaddr->got_reply = _B_TRUE;
562 nreceived_last_target++;
564 * Determine if stats, probe-all, and
565 * npackets != 0, and this is the reply for
566 * the last probe we sent to current target
567 * address.
569 if (stats && probe_all && npackets > 0 &&
570 ((current_targetaddr->starting_seq_num +
571 current_targetaddr->num_probes - 1) %
572 (MAX_ICMP_SEQ + 1) ==
573 ntohs(icp->icmp_seq)) &&
574 (current_targetaddr->num_probes ==
575 current_targetaddr->num_sent))
576 last_reply_from_targetaddr = _B_TRUE;
577 } else {
579 * If it's just probe_all and we just received
580 * a reply from a target address we were
581 * probing and had timed out (now we are probing
582 * some other target address), we ignore
583 * this reply.
585 if (probe_all && !stats) {
586 valid_reply = _B_FALSE;
588 * Only if it's verbose, we get a
589 * message regarding this reply,
590 * otherwise we are done here.
592 if (!verbose) {
593 (void) sigrelse(SIGALRM);
594 return;
600 if (!stats && valid_reply) {
602 * if we are still sending to the same target address,
603 * then stop it, because we know it's alive.
605 if (reply_matched_current_target) {
606 (void) alarm(0); /* cancel alarm */
607 (void) sigset(SIGALRM, SIG_IGN);
608 current_targetaddr->probing_done = _B_TRUE;
610 (void) sigrelse(SIGALRM);
612 if (!probe_all) {
613 Printf("%s is alive\n", targethost);
614 } else {
616 * If we are using send_reply, the real
617 * target address is not the src address of the
618 * replies. Use icmp_seq to find out where this
619 * probe was sent to.
621 if (send_reply) {
622 (void) find_dstaddr(
623 ntohs(icp->icmp_seq), &dst_addr);
624 (void) inet_ntop(AF_INET,
625 (void *)&dst_addr.addr,
626 tmp_buf, sizeof (tmp_buf));
627 } else {
628 (void) inet_ntop(AF_INET,
629 (void *)&from->sin_addr,
630 tmp_buf, sizeof (tmp_buf));
632 if (nflag) {
633 Printf("%s is alive\n", tmp_buf);
634 } else {
635 Printf("%s (%s) is alive\n",
636 targethost, tmp_buf);
639 if (reply_matched_current_target) {
641 * Let's get things going again, but now
642 * ping will start sending to next target IP
643 * address.
645 send_scheduled_probe();
646 (void) sigset(SIGALRM, sigalrm_handler);
647 schedule_sigalrm();
649 return;
650 } else {
652 * If we are not moving to next targetaddr, let's
653 * release the SIGALRM now. We don't want to stall in
654 * the middle of probing a targetaddr if the pr_name()
655 * call (see below) takes longer.
657 if (!last_reply_from_targetaddr)
658 (void) sigrelse(SIGALRM);
659 /* else, we'll release it later */
662 * If we are using send_reply, the real target address is
663 * not the src address of the replies. Use icmp_seq to find out
664 * where this probe was sent to.
666 if (send_reply) {
667 (void) find_dstaddr(ntohs(icp->icmp_seq), &dst_addr);
668 Printf("%d bytes from %s: ", cc,
669 pr_name((char *)&dst_addr.addr, AF_INET));
670 } else {
671 Printf("%d bytes from %s: ", cc,
672 pr_name((char *)&from->sin_addr, AF_INET));
674 Printf("icmp_seq=%d. ", ntohs(icp->icmp_seq));
676 if (valid_reply && datalen >= sizeof (struct timeval) &&
677 cc_left >= sizeof (struct timeval)) {
678 /* LINTED */
679 tp = (struct timeval *)&icp->icmp_data[0];
680 (void) tvsub(&tv, tp);
681 triptime = (int64_t)tv.tv_sec * MICROSEC + tv.tv_usec;
682 Printf("time=" TIMEFORMAT " ms", triptime/1000.0);
683 tsum += triptime;
684 tsum2 += triptime*triptime;
685 if (triptime < tmin)
686 tmin = triptime;
687 if (triptime > tmax)
688 tmax = triptime;
690 (void) putchar('\n');
693 * If it's stats, probe-all, npackets > 0, and we received reply
694 * for the last probe sent to this target address, then we
695 * don't need to wait anymore, let's move on to next target
696 * address, now!
698 if (last_reply_from_targetaddr) {
699 (void) alarm(0); /* cancel alarm */
700 current_targetaddr->probing_done = _B_TRUE;
701 (void) sigrelse(SIGALRM);
702 send_scheduled_probe();
703 schedule_sigalrm();
705 break;
707 case ICMP_SOURCEQUENCH:
708 if (cc_left < sizeof (struct ip)) {
709 if (verbose) {
710 Printf("packet too short (%d bytes) from %s\n",
711 cc, pr_name((char *)&from->sin_addr,
712 AF_INET));
714 return;
716 ip = &icp->icmp_ip;
717 hlen1 = ip->ip_hl << 2;
718 dst_addr.addr = ip->ip_dst;
719 if (is_a_target(ai_dst, &dst_addr) || verbose) {
720 Printf("ICMP Source Quench from %s\n",
721 pr_name((char *)&from->sin_addr, AF_INET));
722 Printf(" for %s from %s", pr_protocol(ip->ip_p),
723 pr_name((char *)&ip->ip_src, AF_INET));
724 Printf(" to %s", pr_name((char *)&ip->ip_dst, AF_INET));
727 * if it's a UDP or TCP packet, we need at least first
728 * 4 bytes of it to see the src/dst ports
730 if ((ip->ip_p == IPPROTO_TCP ||
731 ip->ip_p == IPPROTO_UDP) &&
732 (cc_left >= hlen1 + 4)) {
733 /* LINTED */
734 up = (struct udphdr *)((uchar_t *)ip + hlen1);
735 Printf(" port %d", ntohs(up->uh_dport));
737 (void) putchar('\n');
739 break;
741 case ICMP_PARAMPROB:
742 if (cc_left < sizeof (struct ip)) {
743 if (verbose) {
744 Printf("packet too short (%d bytes) from %s\n",
745 cc, pr_name((char *)&from->sin_addr,
746 AF_INET));
748 return;
750 ip = &icp->icmp_ip;
751 hlen1 = ip->ip_hl << 2;
752 dst_addr.addr = ip->ip_dst;
753 if (is_a_target(ai_dst, &dst_addr) || verbose) {
754 switch (icp->icmp_code) {
755 case ICMP_PARAMPROB_OPTABSENT:
756 Printf("ICMP Missing a Required Option "
757 "parameter problem from %s\n",
758 pr_name((char *)&from->sin_addr, AF_INET));
759 Printf(" option type = %d", icp->icmp_pptr);
760 break;
761 case ICMP_PARAMPROB_BADLENGTH:
762 Printf("ICMP Bad Length parameter problem "
763 "from %s\n",
764 pr_name((char *)&from->sin_addr, AF_INET));
765 Printf(" in byte %d", icp->icmp_pptr);
766 if (icp->icmp_pptr <= hlen1) {
767 Printf(" (value 0x%x)",
768 *((char *)ip + icp->icmp_pptr));
770 break;
771 case 0:
772 default:
773 Printf("ICMP Parameter Problem from %s\n",
774 pr_name((char *)&from->sin_addr, AF_INET));
775 Printf(" in byte %d", icp->icmp_pptr);
776 if (icp->icmp_pptr <= hlen1) {
777 Printf(" (value 0x%x)",
778 *((char *)ip + icp->icmp_pptr));
780 break;
783 Printf(" for %s from %s", pr_protocol(ip->ip_p),
784 pr_name((char *)&ip->ip_src, AF_INET));
785 Printf(" to %s", pr_name((char *)&ip->ip_dst, AF_INET));
788 * if it's a UDP or TCP packet, we need at least first
789 * 4 bytes of it to see the src/dst ports
791 if ((ip->ip_p == IPPROTO_TCP ||
792 ip->ip_p == IPPROTO_UDP) &&
793 (cc_left >= hlen1 + 4)) {
794 /* LINTED */
795 up = (struct udphdr *)((uchar_t *)ip + hlen1);
796 Printf(" port %d", ntohs(up->uh_dport));
798 (void) putchar('\n');
800 break;
802 case ICMP_TIMXCEED:
803 if (cc_left < sizeof (struct ip)) {
804 if (verbose) {
805 Printf("packet too short (%d bytes) from %s\n",
806 cc, pr_name((char *)&from->sin_addr,
807 AF_INET));
809 return;
811 ip = &icp->icmp_ip;
812 hlen1 = ip->ip_hl << 2;
813 dst_addr.addr = ip->ip_dst;
814 if (is_a_target(ai_dst, &dst_addr) || verbose) {
815 if (icp->icmp_code >= A_CNT(timexceed)) {
816 Printf("ICMP %d time exceeded from %s\n",
817 icp->icmp_code,
818 pr_name((char *)&from->sin_addr, AF_INET));
819 } else {
820 Printf("ICMP %s from %s\n",
821 timexceed[icp->icmp_code],
822 pr_name((char *)&from->sin_addr, AF_INET));
824 Printf(" for %s from %s", pr_protocol(ip->ip_p),
825 pr_name((char *)&ip->ip_src, AF_INET));
826 Printf(" to %s", pr_name((char *)&ip->ip_dst, AF_INET));
827 if ((ip->ip_p == IPPROTO_TCP ||
828 ip->ip_p == IPPROTO_UDP) &&
829 (cc_left >= hlen1 + 4)) {
830 /* LINTED */
831 up = (struct udphdr *)((uchar_t *)ip + hlen1);
832 Printf(" port %d", ntohs(up->uh_dport));
834 (void) putchar('\n');
836 break;
838 case ICMP_TSTAMPREPLY:
839 /* the packet should have enough space to store timestamps */
840 if (cc_left < sizeof (struct id_ts)) {
841 if (verbose) {
842 Printf("packet too short (%d bytes) from %s\n",
843 cc, pr_name((char *)&from->sin_addr,
844 AF_INET));
846 return;
849 if (ntohs(icp->icmp_id) == ident) {
850 if (use_icmp_ts)
851 valid_reply = _B_TRUE;
852 else
853 valid_reply = _B_FALSE;
854 } else {
855 return;
858 if (valid_reply) {
860 * For this valid reply, if we are still sending to
861 * this target IP address, we'd like to do some
862 * updates to targetaddr, so hold SIGALRMs.
864 (void) sighold(SIGALRM);
865 is_alive = _B_TRUE;
866 nreceived++;
867 reply_matched_current_target =
868 seq_match(current_targetaddr->starting_seq_num,
869 current_targetaddr->num_sent,
870 ntohs(icp->icmp_seq));
871 if (reply_matched_current_target) {
872 current_targetaddr->got_reply = _B_TRUE;
873 nreceived_last_target++;
875 * Determine if stats, probe-all, and
876 * npackets != 0, and this is the reply for
877 * the last probe we sent to current target
878 * address.
880 if (stats && probe_all && npackets > 0 &&
881 ((current_targetaddr->starting_seq_num +
882 current_targetaddr->num_probes - 1) %
883 (MAX_ICMP_SEQ + 1) ==
884 ntohs(icp->icmp_seq)) &&
885 (current_targetaddr->num_probes ==
886 current_targetaddr->num_sent))
887 last_reply_from_targetaddr = _B_TRUE;
888 } else {
890 * If it's just probe_all and we just received
891 * a reply from a target address we were
892 * probing and had timed out (now we are probing
893 * some other target address), we ignore
894 * this reply.
896 if (probe_all && !stats) {
897 valid_reply = _B_FALSE;
899 * Only if it's verbose, we get a
900 * message regarding this reply,
901 * otherwise we are done here.
903 if (!verbose) {
904 (void) sigrelse(SIGALRM);
905 return;
911 if (!stats && valid_reply) {
913 * if we are still sending to the same target address,
914 * then stop it, because we know it's alive.
916 if (reply_matched_current_target) {
917 (void) alarm(0); /* cancel alarm */
918 (void) sigset(SIGALRM, SIG_IGN);
919 current_targetaddr->probing_done = _B_TRUE;
921 (void) sigrelse(SIGALRM);
923 if (!probe_all) {
924 Printf("%s is alive\n", targethost);
925 } else {
927 * If we are using send_reply, the real
928 * target address is not the src address of the
929 * replies. Use icmp_seq to find out where this
930 * probe was sent to.
932 if (send_reply) {
933 (void) find_dstaddr(
934 ntohs(icp->icmp_seq), &dst_addr);
935 (void) inet_ntop(AF_INET,
936 (void *)&dst_addr.addr,
937 tmp_buf, sizeof (tmp_buf));
938 } else {
939 (void) inet_ntop(AF_INET,
940 (void *)&from->sin_addr,
941 tmp_buf, sizeof (tmp_buf));
943 if (nflag) {
944 Printf("%s is alive\n", tmp_buf);
945 } else {
946 Printf("%s (%s) is alive\n",
947 targethost, tmp_buf);
950 if (reply_matched_current_target) {
952 * Let's get things going again, but now
953 * ping will start sending to next target IP
954 * address.
956 send_scheduled_probe();
957 (void) sigset(SIGALRM, sigalrm_handler);
958 schedule_sigalrm();
960 return;
961 } else {
963 * If we are not moving to next targetaddr, let's
964 * release the SIGALRM now. We don't want to stall in
965 * the middle of probing a targetaddr if the pr_name()
966 * call (see below) takes longer.
968 if (!last_reply_from_targetaddr)
969 (void) sigrelse(SIGALRM);
970 /* else, we'll release it later */
974 * If we are using send_reply, the real target address is
975 * not the src address of the replies. Use icmp_seq to find out
976 * where this probe was sent to.
978 if (send_reply) {
979 (void) find_dstaddr(ntohs(icp->icmp_seq), &dst_addr);
980 Printf("%d bytes from %s: ", cc,
981 pr_name((char *)&dst_addr.addr, AF_INET));
982 } else {
983 Printf("%d bytes from %s: ", cc,
984 pr_name((char *)&from->sin_addr, AF_INET));
986 Printf("icmp_seq=%d. ", ntohs(icp->icmp_seq));
987 Printf("orig = %lu, recv = %lu, xmit = %lu ",
988 (ulong_t)ntohl(icp->icmp_otime),
989 (ulong_t)ntohl(icp->icmp_rtime),
990 (ulong_t)ntohl(icp->icmp_ttime));
992 if (valid_reply) {
994 * icp->icmp_otime is the time passed since midnight.
995 * Therefore we need to adjust tv value, which is
996 * the time passed since Jan 1, 1970.
998 triptime = (tv.tv_sec % (24LL * 60 * 60)) * MILLISEC +
999 (tv.tv_usec / (MICROSEC/MILLISEC));
1000 triptime -= ntohl(icp->icmp_otime);
1001 if (triptime < 0)
1002 triptime += 24LL * 60 * 60 * MILLISEC;
1004 Printf("time=%d. ms", (int)triptime);
1005 triptime *= (MICROSEC/MILLISEC);
1006 tsum += triptime;
1007 tsum2 += triptime*triptime;
1008 if (triptime < tmin)
1009 tmin = triptime;
1010 if (triptime > tmax)
1011 tmax = triptime;
1013 (void) putchar('\n');
1015 * If it's stats, probe-all, npackets > 0, and we received reply
1016 * for the last probe sent to this target address, then we
1017 * don't need to wait anymore, let's move on to next target
1018 * address, now!
1020 if (last_reply_from_targetaddr) {
1021 (void) alarm(0); /* cancel alarm */
1022 current_targetaddr->probing_done = _B_TRUE;
1023 (void) sigrelse(SIGALRM);
1024 send_scheduled_probe();
1025 schedule_sigalrm();
1027 break;
1028 case ICMP_ROUTERADVERT:
1029 case ICMP_ROUTERSOLICIT:
1030 /* Router discovery messages */
1031 return;
1033 case ICMP_ECHO:
1034 case ICMP_TSTAMP:
1035 case ICMP_IREQ:
1036 case ICMP_MASKREQ:
1037 /* These were never passed out from the SunOS 4.X kernel. */
1038 return;
1040 case ICMP_IREQREPLY:
1041 case ICMP_MASKREPLY:
1042 /* Replies for information and address mask requests */
1043 return;
1045 default:
1046 if (verbose) {
1047 Printf("%d bytes from %s:\n", cc,
1048 pr_name((char *)&from->sin_addr, AF_INET));
1049 Printf("icmp_type=%d (%s) ",
1050 icp->icmp_type, pr_type(icp->icmp_type));
1051 Printf("icmp_code=%d\n", icp->icmp_code);
1052 for (i = 0; i < 12; i++) {
1053 Printf("x%2.2x: x%8.8x\n",
1054 i * sizeof (int32_t), *intp++);
1057 break;
1060 buf += sizeof (struct ip);
1061 hlen -= sizeof (struct ip);
1063 /* if verbose and there exists IP options */
1064 if (verbose && hlen > 0)
1065 pr_options((uchar_t *)buf, hlen);
1069 * Print out the ip options.
1071 static void
1072 pr_options(uchar_t *opt, int optlength)
1074 int curlength;
1076 Printf(" IP options: ");
1077 while (optlength > 0) {
1078 curlength = opt[1];
1079 switch (*opt) {
1080 case IPOPT_EOL:
1081 optlength = 0;
1082 break;
1084 case IPOPT_NOP:
1085 opt++;
1086 optlength--;
1087 continue;
1089 case IPOPT_RR:
1090 Printf(" <record route> ");
1091 pr_rropt(opt, curlength, _B_TRUE);
1092 break;
1094 case IPOPT_TS:
1095 Printf(" <time stamp> ");
1096 pr_tsopt(opt, curlength);
1097 break;
1099 case IPOPT_SECURITY:
1100 Printf(" <security>");
1101 break;
1103 case IPOPT_LSRR:
1104 Printf(" <loose source route> ");
1105 pr_rropt(opt, curlength, _B_FALSE);
1106 break;
1108 case IPOPT_SATID:
1109 Printf(" <stream id>");
1110 break;
1112 case IPOPT_SSRR:
1113 Printf(" <strict source route> ");
1114 pr_rropt(opt, curlength, _B_FALSE);
1115 break;
1117 default:
1118 Printf(" <option %d, len %d>", *opt, curlength);
1119 break;
1122 * Following most options comes a length field
1124 opt += curlength;
1125 optlength -= curlength;
1127 (void) putchar('\n');
1131 * Print out a recorded route option. If rrflag is _B_TRUE, it prints record
1132 * route option, otherwise LSRR/SSRR.
1134 static void
1135 pr_rropt(uchar_t *opt, int length, boolean_t rrflag)
1137 struct ip_sourceroute *rrp;
1138 int sr_index = 0;
1139 struct in_addr addr;
1141 rrp = (struct ip_sourceroute *)opt;
1143 /* data starts at offset 3 */
1144 length -= 3;
1145 while (length > 0) {
1147 * Let's see if we are examining the addr pointed by ipsr_ptr
1149 if ((rrp->ipsr_ptr == (sr_index + 1) * sizeof (addr)) &&
1150 rrflag) {
1151 Printf(" (End of record)");
1152 break;
1155 bcopy(&rrp->ipsr_addrs[sr_index], &addr, sizeof (addr));
1156 Printf("%s", pr_name((char *)&addr, AF_INET));
1158 if (rrp->ipsr_ptr == (sr_index + 1) * sizeof (addr)) {
1159 Printf("(Current)");
1162 sr_index++;
1164 length -= sizeof (addr);
1165 if (length > 0)
1166 Printf(", ");
1171 * Print out a timestamp option.
1173 static void
1174 pr_tsopt(uchar_t *opt, int length)
1176 boolean_t address_present;
1177 boolean_t rrflag; /* End at current entry? */
1178 struct ip_timestamp *tsp;
1179 int ts_index = 0;
1180 struct in_addr addr;
1181 size_t data_len;
1182 int32_t time;
1184 /* LINTED */
1185 tsp = (struct ip_timestamp *)opt;
1187 switch (tsp->ipt_flg) {
1188 case IPOPT_TS_TSONLY:
1189 address_present = _B_FALSE;
1190 data_len = sizeof (tsp->ipt_timestamp.ipt_time[0]);
1191 rrflag = _B_TRUE;
1192 break;
1193 case IPOPT_TS_TSANDADDR:
1194 address_present = _B_TRUE;
1195 data_len = sizeof (tsp->ipt_timestamp.ipt_ta[0]);
1196 rrflag = _B_TRUE;
1197 break;
1198 case IPOPT_TS_PRESPEC:
1199 case 3:
1200 address_present = _B_TRUE;
1201 data_len = sizeof (tsp->ipt_timestamp.ipt_ta[0]);
1202 rrflag = _B_FALSE;
1203 break;
1204 default:
1205 Printf("(Bad flag value: 0x%x)", tsp->ipt_flg);
1206 return;
1208 if (tsp->ipt_oflw > 0)
1209 Printf("(Overflow: %d) ", tsp->ipt_oflw);
1211 /* data starts at offset 4 */
1212 length -= 4;
1214 while (length > 0) {
1215 if (length < data_len)
1216 break;
1218 /* the minimum value of ipt_ptr is 5 */
1219 if ((tsp->ipt_ptr == ts_index * data_len + 5) && rrflag) {
1220 Printf(" (End of record)");
1221 break;
1223 if (address_present) {
1224 bcopy(&tsp->ipt_timestamp.ipt_ta[ts_index].ipt_addr,
1225 &addr, sizeof (addr));
1226 Printf("%s: ", pr_name((char *)&addr, AF_INET));
1227 bcopy(&tsp->ipt_timestamp.ipt_ta[ts_index].ipt_time,
1228 &time, sizeof (time));
1229 } else {
1230 bcopy(&tsp->ipt_timestamp.ipt_time[ts_index],
1231 &time, sizeof (time));
1233 Printf("%d", ntohl(time));
1235 if (tsp->ipt_ptr == ts_index * data_len + 5)
1236 Printf("(Current)");
1238 ts_index++;
1239 length -= data_len;
1240 if (length > 0)
1241 Printf(", ");
1246 * Convert an ICMP "type" field to a printable string.
1248 static char *
1249 pr_type(int icmp_type)
1251 static struct icmptype_table ttab[] = {
1252 {ICMP_ECHOREPLY, "Echo Reply"},
1253 {1, "ICMP 1"},
1254 {2, "ICMP 2"},
1255 {ICMP_UNREACH, "Dest Unreachable"},
1256 {ICMP_SOURCEQUENCH, "Source Quench"},
1257 {ICMP_REDIRECT, "Redirect"},
1258 {6, "ICMP 6"},
1259 {7, "ICMP 7"},
1260 {ICMP_ECHO, "Echo"},
1261 {ICMP_ROUTERADVERT, "Router Advertisement"},
1262 {ICMP_ROUTERSOLICIT, "Router Solicitation"},
1263 {ICMP_TIMXCEED, "Time Exceeded"},
1264 {ICMP_PARAMPROB, "Parameter Problem"},
1265 {ICMP_TSTAMP, "Timestamp"},
1266 {ICMP_TSTAMPREPLY, "Timestamp Reply"},
1267 {ICMP_IREQ, "Info Request"},
1268 {ICMP_IREQREPLY, "Info Reply"},
1269 {ICMP_MASKREQ, "Netmask Request"},
1270 {ICMP_MASKREPLY, "Netmask Reply"}
1272 int i;
1274 for (i = 0; i < A_CNT(ttab); i++) {
1275 if (ttab[i].type == icmp_type)
1276 return (ttab[i].message);
1279 return ("OUT-OF-RANGE");