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