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 * Portions of this source code were derived from Berkeley 4.3 BSD
32 * under license from the Regents of the University of California.
33 */
34
35 #pragma ident "%Z%%M% %I% %E% SMI"
36
37 #include <stdio.h>
38 #include <string.h>
39 #include <strings.h>
40 #include <errno.h>
41 #include <fcntl.h>
42 #include <unistd.h>
43 #include <signal.h>
44
45 #include <sys/time.h>
46 #include <sys/param.h>
47 #include <sys/socket.h>
48 #include <sys/sockio.h>
49 #include <sys/stropts.h>
50 #include <sys/file.h>
51 #include <arpa/inet.h>
52 #include <net/if.h>
53 #include <netinet/in_systm.h>
54 #include <netinet/in.h>
55 #include <netinet/ip.h>
56 #include <netinet/ip_icmp.h>
57 #include <netinet/ip6.h>
58 #include <netinet/icmp6.h>
59 #include <netinet/udp.h>
60 #include <netdb.h>
61 #include <stdlib.h>
62
63 #include <libinetutil.h>
64 #include "ping.h"
65
66 void check_reply6(struct addrinfo *, struct msghdr *, int, ushort_t);
67 extern void find_dstaddr(ushort_t, union any_in_addr *);
68 static int IPv6_hdrlen(ip6_t *, int, uint8_t *);
69 extern boolean_t is_a_target(struct addrinfo *, union any_in_addr *);
70 static void pr_ext_headers(struct msghdr *);
71 extern char *pr_name(char *, int);
72 extern char *pr_protocol(int);
73 static void pr_rthdr(unsigned char *);
74 static char *pr_type6(uchar_t);
75 extern void schedule_sigalrm();
76 extern void send_scheduled_probe();
77 extern boolean_t seq_match(ushort_t, int, ushort_t);
78 void set_ancillary_data(struct msghdr *, int, union any_in_addr *, int, uint_t);
79 extern void sigalrm_handler();
80 extern void tvsub(struct timeval *, struct timeval *);
81
82
83 /*
84 * Initialize the msghdr for specifying the hoplimit, outgoing interface and
85 * routing header.
86 */
87 void
set_ancillary_data(struct msghdr * msgp,int hoplimit,union any_in_addr * gwIPlist,int gw_cnt,uint_t if_index)88 set_ancillary_data(struct msghdr *msgp, int hoplimit,
89 union any_in_addr *gwIPlist, int gw_cnt, uint_t if_index)
90 {
91 size_t hoplimit_space;
92 size_t rthdr_space;
93 size_t pktinfo_space;
94 size_t bufspace;
95 struct cmsghdr *cmsgp;
96 uchar_t *cmsg_datap;
97 static boolean_t first = _B_TRUE;
98 int i;
99
100 if (hoplimit == -1 && gw_cnt == 0 && if_index == 0)
101 return;
102
103 /*
104 * Need to figure out size of buffer needed for ancillary data
105 * containing routing header and packet info options.
106 *
107 * Portable heuristic to compute upper bound on space needed for
108 * N ancillary data options. It assumes up to _MAX_ALIGNMENT padding
109 * after both header and data as the worst possible upper bound on space
110 * consumed by padding.
111 * It also adds one extra "sizeof (struct cmsghdr)" for the last option.
112 * This is needed because we would like to use CMSG_NXTHDR() while
113 * composing the buffer. The CMSG_NXTHDR() macro is designed better for
114 * parsing than composing the buffer. It requires the pointer it returns
115 * to leave space in buffer for addressing a cmsghdr and we want to make
116 * sure it works for us while we skip beyond the last ancillary data
117 * option.
118 *
119 * bufspace[i] = sizeof(struct cmsghdr) + <pad after header> +
120 * <option[i] content length> + <pad after data>;
121 *
122 * total_bufspace = bufspace[0] + bufspace[1] + ...
123 * ... + bufspace[N-1] + sizeof (struct cmsghdr);
124 */
125
126 rthdr_space = 0;
127 pktinfo_space = 0;
128 hoplimit_space = 0;
129 bufspace = 0;
130
131 if (hoplimit != -1) {
132 hoplimit_space = sizeof (int);
133 bufspace += sizeof (struct cmsghdr) + _MAX_ALIGNMENT +
134 hoplimit_space + _MAX_ALIGNMENT;
135 }
136
137 if (gw_cnt > 0) {
138 rthdr_space = inet6_rth_space(IPV6_RTHDR_TYPE_0, gw_cnt);
139 bufspace += sizeof (struct cmsghdr) + _MAX_ALIGNMENT +
140 rthdr_space + _MAX_ALIGNMENT;
141 }
142
143 if (if_index != 0) {
144 pktinfo_space = sizeof (struct in6_pktinfo);
145 bufspace += sizeof (struct cmsghdr) + _MAX_ALIGNMENT +
146 pktinfo_space + _MAX_ALIGNMENT;
147 }
148
149 /*
150 * We need to temporarily set the msgp->msg_controllen to bufspace
151 * (we will later trim it to actual length used). This is needed because
152 * CMSG_NXTHDR() uses it to check we have not exceeded the bounds.
153 */
154 bufspace += sizeof (struct cmsghdr);
155 msgp->msg_controllen = bufspace;
156
157 /*
158 * This function is called more than once only if -l/-S used,
159 * since we need to modify the middle gateway. So, don't alloc
160 * new memory, just reuse what msg6 points to.
161 */
162 if (first) {
163 first = _B_FALSE;
164 msgp->msg_control = (struct cmsghdr *)malloc(bufspace);
165 if (msgp->msg_control == NULL) {
166 Fprintf(stderr, "%s: malloc %s\n",
167 progname, strerror(errno));
168 exit(EXIT_FAILURE);
169 }
170 };
171 cmsgp = CMSG_FIRSTHDR(msgp);
172
173 /*
174 * Fill ancillary data. First hoplimit, then rthdr and pktinfo.
175 */
176
177 /* set hoplimit ancillary data if needed */
178 if (hoplimit != -1) {
179 cmsgp->cmsg_level = IPPROTO_IPV6;
180 cmsgp->cmsg_type = IPV6_HOPLIMIT;
181 cmsg_datap = CMSG_DATA(cmsgp);
182 /* LINTED */
183 *(int *)cmsg_datap = hoplimit;
184 cmsgp->cmsg_len = cmsg_datap + hoplimit_space -
185 (uchar_t *)cmsgp;
186 cmsgp = CMSG_NXTHDR(msgp, cmsgp);
187 }
188
189 /* set rthdr ancillary data if needed */
190 if (gw_cnt > 0) {
191 struct ip6_rthdr0 *rthdr0p;
192
193 cmsgp->cmsg_level = IPPROTO_IPV6;
194 cmsgp->cmsg_type = IPV6_RTHDR;
195 cmsg_datap = CMSG_DATA(cmsgp);
196
197 /*
198 * Initialize rthdr structure
199 */
200 /* LINTED */
201 rthdr0p = (struct ip6_rthdr0 *)cmsg_datap;
202 if (inet6_rth_init(rthdr0p, rthdr_space,
203 IPV6_RTHDR_TYPE_0, gw_cnt) == NULL) {
204 Fprintf(stderr, "%s: inet6_rth_init failed\n",
205 progname);
206 exit(EXIT_FAILURE);
207 }
208
209 /*
210 * Stuff in gateway addresses
211 */
212 for (i = 0; i < gw_cnt; i++) {
213 if (inet6_rth_add(rthdr0p, &gwIPlist[i].addr6) == -1) {
214 Fprintf(stderr,
215 "%s: inet6_rth_add\n", progname);
216 exit(EXIT_FAILURE);
217 }
218 }
219
220 cmsgp->cmsg_len = cmsg_datap + rthdr_space - (uchar_t *)cmsgp;
221 cmsgp = CMSG_NXTHDR(msgp, cmsgp);
222 }
223
224 /* set pktinfo ancillary data if needed */
225 if (if_index != 0) {
226 struct in6_pktinfo *pktinfop;
227
228 cmsgp->cmsg_level = IPPROTO_IPV6;
229 cmsgp->cmsg_type = IPV6_PKTINFO;
230 cmsg_datap = CMSG_DATA(cmsgp);
231
232 /* LINTED */
233 pktinfop = (struct in6_pktinfo *)cmsg_datap;
234 /*
235 * We don't know if pktinfop->ipi6_addr is aligned properly,
236 * therefore let's use bcopy, instead of assignment.
237 */
238 (void) bcopy(&in6addr_any, &pktinfop->ipi6_addr,
239 sizeof (struct in6_addr));
240
241 /*
242 * We can assume pktinfop->ipi6_ifindex is 32 bit aligned.
243 */
244 pktinfop->ipi6_ifindex = if_index;
245 cmsgp->cmsg_len = cmsg_datap + pktinfo_space - (uchar_t *)cmsgp;
246 cmsgp = CMSG_NXTHDR(msgp, cmsgp);
247 }
248
249 msgp->msg_controllen = (char *)cmsgp - (char *)msgp->msg_control;
250 }
251
252 /*
253 * Check out the packet to see if it came from us. This logic is necessary
254 * because ALL readers of the ICMP socket get a copy of ALL ICMP packets
255 * which arrive ('tis only fair). This permits multiple copies of this
256 * program to be run without having intermingled output (or statistics!).
257 */
258 void
check_reply6(struct addrinfo * ai_dst,struct msghdr * msg,int cc,ushort_t udp_src_port)259 check_reply6(struct addrinfo *ai_dst, struct msghdr *msg, int cc,
260 ushort_t udp_src_port)
261 {
262 struct icmp6_hdr *icmp6;
263 ip6_t *ip6h;
264 nd_redirect_t *nd_rdrct;
265 struct udphdr *up;
266 union any_in_addr dst_addr;
267 uchar_t *buf;
268 int32_t *intp;
269 struct sockaddr_in6 *from6;
270 struct timeval tv;
271 struct timeval *tp;
272 int64_t triptime;
273 boolean_t valid_reply = _B_FALSE;
274 boolean_t reply_matched_current_target; /* Is the source address of */
275 /* this reply same as where */
276 /* we're sending currently? */
277 boolean_t last_reply_from_targetaddr = _B_FALSE; /* Is this stats, */
278 /* probe all with npackets>0 */
279 /* and we received reply for */
280 /* the last probe sent to */
281 /* targetaddr */
282 uint32_t ip6hdr_len;
283 uint8_t last_hdr;
284 int cc_left;
285 int i;
286 char tmp_buf[INET6_ADDRSTRLEN];
287 static char *unreach6[] = {
288 "No Route to Destination",
289 "Communication Administratively Prohibited",
290 "Not a Neighbor (obsoleted ICMPv6 code)",
291 "Address Unreachable",
292 "Port Unreachable"
293 };
294 static char *timexceed6[] = {
295 "Hop limit exceeded in transit",
296 "Fragment reassembly time exceeded"
297 };
298 static char *param_prob6[] = {
299 "Erroneous header field encountered",
300 "Unrecognized next header type encountered",
301 "Unrecognized IPv6 option encountered"
302 };
303 boolean_t print_newline = _B_FALSE;
304
305 /* decompose msghdr into useful pieces */
306 buf = (uchar_t *)msg->msg_iov->iov_base;
307 from6 = (struct sockaddr_in6 *)msg->msg_name;
308
309 /* LINTED */
310 intp = (int32_t *)buf;
311
312 /* get time now for most accurate time calculation */
313 (void) gettimeofday(&tv, (struct timezone *)NULL);
314
315 /* Ignore packets > 64k or control buffers that don't fit */
316 if (msg->msg_flags & (MSG_TRUNC|MSG_CTRUNC)) {
317 if (verbose) {
318 Printf("Truncated message: msg_flags 0x%x from %s\n",
319 msg->msg_flags,
320 pr_name((char *)&from6->sin6_addr, AF_INET6));
321 }
322 return;
323 }
324 if (cc < ICMP6_MINLEN) {
325 if (verbose) {
326 Printf("packet too short (%d bytes) from %s\n", cc,
327 pr_name((char *)&from6->sin6_addr, AF_INET6));
328 }
329 return;
330 }
331 /* LINTED */
332 icmp6 = (struct icmp6_hdr *)buf;
333 cc_left = cc - ICMP6_MINLEN;
334
335 switch (icmp6->icmp6_type) {
336 case ICMP6_DST_UNREACH:
337 /* LINTED */
338 ip6h = (ip6_t *)((char *)icmp6 + ICMP6_MINLEN);
339 if (cc_left < sizeof (ip6_t)) {
340 if (verbose) {
341 Printf("packet too short (%d bytes) from %s\n",
342 cc,
343 pr_name((char *)&from6->sin6_addr,
344 AF_INET6));
345 }
346 return;
347 }
348
349 /*
350 * Determine the total length of IPv6 header and extension
351 * headers, also the upper layer header (UDP, TCP, ICMP, etc.)
352 * following.
353 */
354 ip6hdr_len = IPv6_hdrlen(ip6h, cc_left, &last_hdr);
355
356 cc_left -= ip6hdr_len;
357
358 /* LINTED */
359 up = (struct udphdr *)((char *)ip6h + ip6hdr_len);
360 if (cc_left < sizeof (struct udphdr)) {
361 if (verbose) {
362 Printf("packet too short (%d bytes) from %s\n",
363 cc,
364 pr_name((char *)&from6->sin6_addr,
365 AF_INET6));
366 }
367 return;
368 }
369 cc_left -= sizeof (struct udphdr);
370
371 /* determine if this is *the* reply */
372 if (icmp6->icmp6_code == ICMP6_DST_UNREACH_NOPORT &&
373 last_hdr == IPPROTO_UDP &&
374 udp_src_port == up->uh_sport &&
375 use_udp) {
376 valid_reply = _B_TRUE;
377 } else {
378 valid_reply = _B_FALSE;
379 }
380
381 if (valid_reply) {
382 /*
383 * For this valid reply, if we are still sending to
384 * this target IP address, we'd like to do some
385 * updates to targetaddr, so hold SIGALRMs.
386 */
387 (void) sighold(SIGALRM);
388 is_alive = _B_TRUE;
389 nreceived++;
390 reply_matched_current_target =
391 seq_match(current_targetaddr->starting_seq_num,
392 current_targetaddr->num_sent,
393 ntohs(up->uh_dport));
394 if (reply_matched_current_target) {
395 current_targetaddr->got_reply = _B_TRUE;
396 nreceived_last_target++;
397 /*
398 * Determine if stats, probe-all, and
399 * npackets != 0, and this is the reply for
400 * the last probe we sent to current target
401 * address.
402 */
403 if (stats && probe_all && npackets > 0 &&
404 ((current_targetaddr->starting_seq_num +
405 current_targetaddr->num_probes - 1) %
406 (MAX_PORT + 1) == ntohs(up->uh_dport)) &&
407 (current_targetaddr->num_probes ==
408 current_targetaddr->num_sent))
409 last_reply_from_targetaddr = _B_TRUE;
410 } else {
411 /*
412 * If it's just probe_all and we just received
413 * a reply from a target address we were
414 * probing and had timed out (now we are probing
415 * some other target address), we ignore
416 * this reply.
417 */
418 if (probe_all && !stats) {
419 valid_reply = _B_FALSE;
420 /*
421 * Only if it's verbose, we get a
422 * message regarding this reply,
423 * otherwise we are done here.
424 */
425 if (!verbose) {
426 (void) sigrelse(SIGALRM);
427 return;
428 }
429 }
430 }
431 }
432
433 if (valid_reply && !stats) {
434 /*
435 * if we are still sending to the same target address,
436 * then stop it, because we know it's alive.
437 */
438 if (reply_matched_current_target) {
439 (void) alarm(0); /* cancel alarm */
440 (void) sigset(SIGALRM, SIG_IGN);
441 current_targetaddr->probing_done = _B_TRUE;
442 }
443 (void) sigrelse(SIGALRM);
444
445 if (!probe_all) {
446 Printf("%s is alive\n", targethost);
447 } else {
448 (void) inet_ntop(AF_INET6,
449 (void *)&ip6h->ip6_dst,
450 tmp_buf, sizeof (tmp_buf));
451 if (nflag) {
452 Printf("%s is alive\n", tmp_buf);
453 } else {
454 Printf("%s (%s) is alive\n",
455 targethost, tmp_buf);
456 }
457 }
458 if (reply_matched_current_target) {
459 /*
460 * Let's get things going again, but now
461 * ping will start sending to next target IP
462 * address.
463 */
464 send_scheduled_probe();
465 (void) sigset(SIGALRM, sigalrm_handler);
466 schedule_sigalrm();
467 }
468 return;
469 } else {
470 /*
471 * If we are not moving to next targetaddr, let's
472 * release the SIGALRM now. We don't want to stall in
473 * the middle of probing a targetaddr if the pr_name()
474 * call (see below) takes longer.
475 */
476 if (!last_reply_from_targetaddr)
477 (void) sigrelse(SIGALRM);
478 /* else, we'll release it later */
479 }
480
481 dst_addr.addr6 = ip6h->ip6_dst;
482 if (valid_reply) {
483 Printf("%d bytes from %s: ", cc,
484 pr_name((char *)&from6->sin6_addr, AF_INET6));
485 Printf("udp_port=%d. ", ntohs(up->uh_dport));
486 print_newline = _B_TRUE;
487 } else if (is_a_target(ai_dst, &dst_addr)|| verbose) {
488 if (icmp6->icmp6_code >= A_CNT(unreach6)) {
489 Printf("ICMPv6 %d Unreachable from gateway "
490 "%s\n", icmp6->icmp6_code,
491 pr_name((char *)&from6->sin6_addr,
492 AF_INET6));
493 } else {
494 Printf("ICMPv6 %s from gateway %s\n",
495 unreach6[icmp6->icmp6_code],
496 pr_name((char *)&from6->sin6_addr,
497 AF_INET6));
498 }
499 Printf(" for %s from %s", pr_protocol(last_hdr),
500 pr_name((char *)&ip6h->ip6_src, AF_INET6));
501 Printf(" to %s", pr_name((char *)&ip6h->ip6_dst,
502 AF_INET6));
503 if (last_hdr == IPPROTO_TCP || last_hdr == IPPROTO_UDP)
504 Printf(" port %d ", ntohs(up->uh_dport));
505 print_newline = _B_TRUE;
506 }
507
508 /*
509 * Update and print the stats, if it's a valid reply and
510 * contains a timestamp.
511 */
512 if (valid_reply && datalen >= sizeof (struct timeval) &&
513 cc_left >= sizeof (struct timeval)) {
514 /* LINTED */
515 tp = (struct timeval *)((char *)up +
516 sizeof (struct udphdr));
517 (void) tvsub(&tv, tp);
518 triptime = (int64_t)tv.tv_sec * MICROSEC + tv.tv_usec;
519 Printf("time=" TIMEFORMAT " ms", triptime/1000.0);
520 tsum += triptime;
521 tsum2 += triptime*triptime;
522 if (triptime < tmin)
523 tmin = triptime;
524 if (triptime > tmax)
525 tmax = triptime;
526 print_newline = _B_TRUE;
527 }
528 if (print_newline)
529 (void) putchar('\n');
530 /*
531 * If it's stats, probe-all, npackets > 0, and we received reply
532 * for the last probe sent to this target address, then we
533 * don't need to wait anymore, let's move on to next target
534 * address, now!
535 */
536 if (last_reply_from_targetaddr) {
537 (void) alarm(0); /* cancel alarm */
538 current_targetaddr->probing_done = _B_TRUE;
539 (void) sigrelse(SIGALRM);
540 send_scheduled_probe();
541 schedule_sigalrm();
542 }
543 break;
544
545 case ICMP6_PACKET_TOO_BIG:
546 /* LINTED */
547 ip6h = (ip6_t *)((char *)icmp6 + ICMP6_MINLEN);
548 if (cc_left < sizeof (ip6_t)) {
549 if (verbose) {
550 Printf("packet too short (%d bytes) from %s\n",
551 cc, pr_name((char *)&from6->sin6_addr,
552 AF_INET6));
553 }
554 return;
555 }
556 ip6hdr_len = IPv6_hdrlen(ip6h, cc_left, &last_hdr);
557
558 dst_addr.addr6 = ip6h->ip6_dst;
559 if (is_a_target(ai_dst, &dst_addr) || verbose) {
560 Printf("ICMPv6 packet too big from %s\n",
561 pr_name((char *)&from6->sin6_addr, AF_INET6));
562
563 Printf(" for %s from %s", pr_protocol(last_hdr),
564 pr_name((char *)&ip6h->ip6_src, AF_INET6));
565 Printf(" to %s", pr_name((char *)&ip6h->ip6_dst,
566 AF_INET6));
567 if ((last_hdr == IPPROTO_TCP ||
568 last_hdr == IPPROTO_UDP) &&
569 (cc_left >= (ip6hdr_len + 4))) {
570 /* LINTED */
571 up = (struct udphdr *)
572 ((char *)ip6h + ip6hdr_len);
573 Printf(" port %d ", ntohs(up->uh_dport));
574 }
575 Printf(" MTU = %d\n", ntohl(icmp6->icmp6_mtu));
576 }
577 break;
578
579 case ICMP6_TIME_EXCEEDED:
580 /* LINTED */
581 ip6h = (ip6_t *)((char *)icmp6 + ICMP6_MINLEN);
582 if (cc_left < sizeof (ip6_t)) {
583 if (verbose) {
584 Printf("packet too short (%d bytes) from %s\n",
585 cc,
586 pr_name((char *)&from6->sin6_addr,
587 AF_INET6));
588 }
589 return;
590 }
591 ip6hdr_len = IPv6_hdrlen(ip6h, cc_left, &last_hdr);
592
593 dst_addr.addr6 = ip6h->ip6_dst;
594 if (is_a_target(ai_dst, &dst_addr) || verbose) {
595 if (icmp6->icmp6_code >= A_CNT(timexceed6)) {
596 Printf("ICMPv6 %d time exceeded from %s\n",
597 icmp6->icmp6_code,
598 pr_name((char *)&from6->sin6_addr,
599 AF_INET6));
600 } else {
601 Printf("ICMPv6 %s from %s\n",
602 timexceed6[icmp6->icmp6_code],
603 pr_name((char *)&from6->sin6_addr,
604 AF_INET6));
605 }
606 Printf(" for %s from %s", pr_protocol(last_hdr),
607 pr_name((char *)&ip6h->ip6_src, AF_INET6));
608 Printf(" to %s", pr_name((char *)&ip6h->ip6_dst,
609 AF_INET6));
610 if ((last_hdr == IPPROTO_TCP ||
611 last_hdr == IPPROTO_UDP) &&
612 (cc_left >= (ip6hdr_len + 4))) {
613 /* LINTED */
614 up = (struct udphdr *)
615 ((char *)ip6h + ip6hdr_len);
616 Printf(" port %d", ntohs(up->uh_dport));
617 }
618 (void) putchar('\n');
619 }
620 break;
621
622 case ICMP6_PARAM_PROB:
623 /* LINTED */
624 ip6h = (ip6_t *)((char *)icmp6 + ICMP6_MINLEN);
625 if (cc_left < sizeof (ip6_t)) {
626 if (verbose) {
627 Printf("packet too short (%d bytes) from %s\n",
628 cc,
629 pr_name((char *)&from6->sin6_addr,
630 AF_INET6));
631 }
632 return;
633 }
634 ip6hdr_len = IPv6_hdrlen(ip6h, cc_left, &last_hdr);
635
636 dst_addr.addr6 = ip6h->ip6_dst;
637 if (is_a_target(ai_dst, &dst_addr) || verbose) {
638 if (icmp6->icmp6_code >= A_CNT(param_prob6)) {
639 Printf("ICMPv6 %d parameter problem from %s\n",
640 icmp6->icmp6_code,
641 pr_name((char *)&from6->sin6_addr,
642 AF_INET6));
643 } else {
644 Printf("ICMPv6 %s from %s\n",
645 param_prob6[icmp6->icmp6_code],
646 pr_name((char *)&from6->sin6_addr,
647 AF_INET6));
648 }
649 icmp6->icmp6_pptr = ntohl(icmp6->icmp6_pptr);
650 Printf(" in byte %d", icmp6->icmp6_pptr);
651 if (icmp6->icmp6_pptr <= ip6hdr_len) {
652 Printf(" (value 0x%x)",
653 *((uchar_t *)ip6h + icmp6->icmp6_pptr));
654 }
655 Printf(" for %s from %s", pr_protocol(last_hdr),
656 pr_name((char *)&ip6h->ip6_src, AF_INET6));
657 Printf(" to %s", pr_name((char *)&ip6h->ip6_dst,
658 AF_INET6));
659 if ((last_hdr == IPPROTO_TCP ||
660 last_hdr == IPPROTO_UDP) &&
661 (cc_left >= (ip6hdr_len + 4))) {
662 /* LINTED */
663 up = (struct udphdr *)
664 ((char *)ip6h + ip6hdr_len);
665 Printf(" port %d", ntohs(up->uh_dport));
666 }
667 (void) putchar('\n');
668 }
669 break;
670
671 case ICMP6_ECHO_REQUEST:
672 return;
673
674 case ICMP6_ECHO_REPLY:
675 if (ntohs(icmp6->icmp6_id) == ident) {
676 if (!use_udp)
677 valid_reply = _B_TRUE;
678 else
679 valid_reply = _B_FALSE;
680 } else {
681 return;
682 }
683
684 if (valid_reply) {
685 /*
686 * For this valid reply, if we are still sending to
687 * this target IP address, we'd like to do some
688 * updates to targetaddr, so hold SIGALRMs.
689 */
690 (void) sighold(SIGALRM);
691 is_alive = _B_TRUE;
692 nreceived++;
693 reply_matched_current_target =
694 seq_match(current_targetaddr->starting_seq_num,
695 current_targetaddr->num_sent,
696 ntohs(icmp6->icmp6_seq));
697 if (reply_matched_current_target) {
698 current_targetaddr->got_reply = _B_TRUE;
699 nreceived_last_target++;
700 /*
701 * Determine if stats, probe-all, and
702 * npackets != 0, and this is the reply for
703 * the last probe we sent to current target
704 * address.
705 */
706 if (stats && probe_all && npackets > 0 &&
707 ((current_targetaddr->starting_seq_num +
708 current_targetaddr->num_probes - 1) %
709 (MAX_ICMP_SEQ + 1) ==
710 ntohs(icmp6->icmp6_seq)) &&
711 (current_targetaddr->num_probes ==
712 current_targetaddr->num_sent))
713 last_reply_from_targetaddr = _B_TRUE;
714 } else {
715 /*
716 * If it's just probe_all and we just received
717 * a reply from a target address we were
718 * probing and had timed out (now we are probing
719 * some other target address), we ignore
720 * this reply.
721 */
722 if (probe_all && !stats) {
723 valid_reply = _B_FALSE;
724 /*
725 * Only if it's verbose, we get a
726 * message regarding this reply,
727 * otherwise we are done here.
728 */
729 if (!verbose) {
730 (void) sigrelse(SIGALRM);
731 return;
732 }
733 }
734 }
735 }
736
737 if (!stats && valid_reply) {
738 /*
739 * if we are still sending to the same target address,
740 * then stop it, because we know it's alive.
741 */
742 if (reply_matched_current_target) {
743 (void) alarm(0); /* cancel alarm */
744 (void) sigset(SIGALRM, SIG_IGN);
745 current_targetaddr->probing_done = _B_TRUE;
746 }
747 (void) sigrelse(SIGALRM);
748
749 if (!probe_all) {
750 Printf("%s is alive\n", targethost);
751 } else {
752 /*
753 * If we are using send_reply, the real
754 * target address is not the src address of the
755 * replies. Use icmp_seq to find out where this
756 * probe was sent to.
757 */
758 if (send_reply) {
759 (void) find_dstaddr(
760 ntohs(icmp6->icmp6_seq), &dst_addr);
761 (void) inet_ntop(AF_INET6,
762 (void *)&dst_addr.addr6,
763 tmp_buf, sizeof (tmp_buf));
764 } else {
765 (void) inet_ntop(AF_INET6,
766 (void *)&from6->sin6_addr,
767 tmp_buf, sizeof (tmp_buf));
768 }
769
770 if (nflag) {
771 Printf("%s is alive\n", tmp_buf);
772 } else {
773 Printf("%s (%s) is alive\n",
774 targethost, tmp_buf);
775 }
776 }
777 if (reply_matched_current_target) {
778 /*
779 * Let's get things going again, but now
780 * ping will start sending to next target IP
781 * address.
782 */
783 send_scheduled_probe();
784 (void) sigset(SIGALRM, sigalrm_handler);
785 schedule_sigalrm();
786 }
787 return;
788 } else {
789 /*
790 * If we are not moving to next targetaddr, let's
791 * release the SIGALRM now. We don't want to stall in
792 * the middle of probing a targetaddr if the pr_name()
793 * call (see below) takes longer.
794 */
795 if (!last_reply_from_targetaddr)
796 (void) sigrelse(SIGALRM);
797 /* else, we'll release it later */
798 }
799
800 /*
801 * If we are using send_reply, the real target address is
802 * not the src address of the replies. Use icmp_seq to find out
803 * where this probe was sent to.
804 */
805 if (send_reply) {
806 (void) find_dstaddr(ntohs(icmp6->icmp6_seq), &dst_addr);
807 Printf("%d bytes from %s: ", cc,
808 pr_name((char *)&dst_addr.addr6, AF_INET6));
809 } else {
810 Printf("%d bytes from %s: ", cc,
811 pr_name((char *)&from6->sin6_addr, AF_INET6));
812 }
813 Printf("icmp_seq=%d. ", ntohs(icmp6->icmp6_seq));
814
815 if (valid_reply && datalen >= sizeof (struct timeval) &&
816 cc_left >= sizeof (struct timeval)) {
817 /* LINTED */
818 tp = (struct timeval *)&icmp6->icmp6_data16[2];
819 (void) tvsub(&tv, tp);
820 triptime = (int64_t)tv.tv_sec * MICROSEC + tv.tv_usec;
821 Printf("time=" TIMEFORMAT " ms", triptime/1000.0);
822 tsum += triptime;
823 tsum2 += triptime*triptime;
824 if (triptime < tmin)
825 tmin = triptime;
826 if (triptime > tmax)
827 tmax = triptime;
828 }
829 (void) putchar('\n');
830 /*
831 * If it's stats, probe-all, npackets > 0, and we received reply
832 * for the last probe sent to this target address, then we
833 * don't need to wait anymore, let's move on to next target
834 * address, now!
835 */
836 if (last_reply_from_targetaddr) {
837 (void) alarm(0); /* cancel alarm */
838 current_targetaddr->probing_done = _B_TRUE;
839 (void) sigrelse(SIGALRM);
840 send_scheduled_probe();
841 schedule_sigalrm();
842 }
843 break;
844
845 case MLD_LISTENER_QUERY:
846 case MLD_LISTENER_REPORT:
847 case MLD_LISTENER_REDUCTION:
848 case ND_ROUTER_SOLICIT:
849 case ND_ROUTER_ADVERT:
850 case ND_NEIGHBOR_SOLICIT:
851 case ND_NEIGHBOR_ADVERT:
852 return;
853
854 case ND_REDIRECT:
855 nd_rdrct = (nd_redirect_t *)icmp6;
856
857 if (cc_left < sizeof (nd_redirect_t) - ICMP6_MINLEN) {
858 if (verbose) {
859 Printf("packet too short (%d bytes) from %s\n",
860 cc,
861 pr_name((char *)&from6->sin6_addr,
862 AF_INET6));
863 }
864 return;
865 }
866 dst_addr.addr6 = nd_rdrct->nd_rd_dst;
867 if (is_a_target(ai_dst, &dst_addr) || verbose) {
868 Printf("ICMPv6 redirect from gateway %s\n",
869 pr_name((char *)&from6->sin6_addr, AF_INET6));
870
871 Printf(" to %s",
872 pr_name((char *)&nd_rdrct->nd_rd_target, AF_INET6));
873 Printf(" for %s\n",
874 pr_name((char *)&nd_rdrct->nd_rd_dst, AF_INET6));
875 }
876 break;
877
878 default:
879 if (verbose) {
880 Printf("%d bytes from %s:\n", cc,
881 pr_name((char *)&from6->sin6_addr, AF_INET6));
882 Printf("icmp6_type=%d (%s) ", icmp6->icmp6_type,
883 pr_type6(icmp6->icmp6_type));
884 Printf("icmp6_code=%d\n", icmp6->icmp6_code);
885 for (i = 0; i < 12; i++) {
886 Printf("x%2.2x: x%8.8x\n",
887 i * sizeof (int32_t), *intp++);
888 }
889 }
890 break;
891 }
892
893 /*
894 * If it's verbose mode and we recv'd ancillary data, print extension
895 * headers.
896 */
897 if (verbose && msg->msg_controllen > 0)
898 pr_ext_headers(msg);
899 }
900
901 /*
902 * Convert an ICMP6 "type" field to a printable string.
903 */
904 static char *
pr_type6(uchar_t icmp6_type)905 pr_type6(uchar_t icmp6_type)
906 {
907 static struct icmptype_table ttab6[] = {
908 {ICMP6_DST_UNREACH, "Dest Unreachable"},
909 {ICMP6_PACKET_TOO_BIG, "Packet Too Big"},
910 {ICMP6_TIME_EXCEEDED, "Time Exceeded"},
911 {ICMP6_PARAM_PROB, "Parameter Problem"},
912 {ICMP6_ECHO_REQUEST, "Echo Request"},
913 {ICMP6_ECHO_REPLY, "Echo Reply"},
914 {MLD_LISTENER_QUERY, "Multicast Listener Query"},
915 {MLD_LISTENER_REPORT, "Multicast Listener Report"},
916 {MLD_LISTENER_REDUCTION, "Multicast Listener Done"},
917 {ND_ROUTER_SOLICIT, "Router Solicitation"},
918 {ND_ROUTER_ADVERT, "Router Advertisement"},
919 {ND_NEIGHBOR_SOLICIT, "Neighbor Solicitation"},
920 {ND_NEIGHBOR_ADVERT, "Neighbor Advertisement"},
921 {ND_REDIRECT, "Redirect Message"},
922 };
923 int i;
924
925 for (i = 0; i < A_CNT(ttab6); i++) {
926 if (ttab6[i].type == icmp6_type)
927 return (ttab6[i].message);
928
929 }
930
931 return ("OUT-OF-RANGE");
932 }
933
934 /*
935 * Return the length of the IPv6 related headers (including extension headers).
936 * It also sets the *last_hdr_rtrn to the first upper layer protocol header
937 * following IPv6 header and extension headers. If print_flag is _B_TRUE, it
938 * prints extension headers.
939 */
940 static int
IPv6_hdrlen(ip6_t * ip6h,int pkt_len,uint8_t * last_hdr_rtrn)941 IPv6_hdrlen(ip6_t *ip6h, int pkt_len, uint8_t *last_hdr_rtrn)
942 {
943 int length;
944 int exthdrlength;
945 uint8_t nexthdr;
946 uint8_t *whereptr;
947 ip6_hbh_t *hbhhdr;
948 ip6_dest_t *desthdr;
949 ip6_rthdr_t *rthdr;
950 ip6_frag_t *fraghdr;
951 uint8_t *endptr;
952
953 length = sizeof (ip6_t);
954
955 whereptr = ((uint8_t *)&ip6h[1]); /* point to next hdr */
956 endptr = ((uint8_t *)ip6h) + pkt_len;
957
958 nexthdr = ip6h->ip6_nxt;
959 *last_hdr_rtrn = IPPROTO_NONE;
960
961 if (whereptr >= endptr)
962 return (length);
963
964 while (whereptr < endptr) {
965 *last_hdr_rtrn = nexthdr;
966 switch (nexthdr) {
967 case IPPROTO_HOPOPTS:
968 hbhhdr = (ip6_hbh_t *)whereptr;
969 exthdrlength = 8 * (hbhhdr->ip6h_len + 1);
970 if ((uchar_t *)hbhhdr + exthdrlength > endptr)
971 return (length);
972 nexthdr = hbhhdr->ip6h_nxt;
973 length += exthdrlength;
974 break;
975
976 case IPPROTO_DSTOPTS:
977 desthdr = (ip6_dest_t *)whereptr;
978 exthdrlength = 8 * (desthdr->ip6d_len + 1);
979 if ((uchar_t *)desthdr + exthdrlength > endptr)
980 return (length);
981 nexthdr = desthdr->ip6d_nxt;
982 length += exthdrlength;
983 break;
984
985 case IPPROTO_ROUTING:
986 rthdr = (ip6_rthdr_t *)whereptr;
987 exthdrlength = 8 * (rthdr->ip6r_len + 1);
988 if ((uchar_t *)rthdr + exthdrlength > endptr)
989 return (length);
990 nexthdr = rthdr->ip6r_nxt;
991 length += exthdrlength;
992 break;
993
994 case IPPROTO_FRAGMENT:
995 /* LINTED */
996 fraghdr = (ip6_frag_t *)whereptr;
997 if ((uchar_t *)&fraghdr[1] > endptr)
998 return (length);
999 nexthdr = fraghdr->ip6f_nxt;
1000 length += sizeof (struct ip6_frag);
1001 break;
1002
1003 case IPPROTO_NONE:
1004 default:
1005 return (length);
1006 }
1007 whereptr = (uint8_t *)ip6h + length;
1008 }
1009 *last_hdr_rtrn = nexthdr;
1010
1011 return (length);
1012 }
1013
1014 /*
1015 * Print extension headers
1016 */
1017 static void
pr_ext_headers(struct msghdr * msg)1018 pr_ext_headers(struct msghdr *msg)
1019 {
1020 struct cmsghdr *cmsg;
1021
1022 Printf(" IPv6 extension headers: ");
1023
1024 for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL;
1025 cmsg = CMSG_NXTHDR(msg, cmsg)) {
1026 if (cmsg->cmsg_level == IPPROTO_IPV6) {
1027 switch (cmsg->cmsg_type) {
1028 case IPV6_HOPOPTS:
1029 Printf(" <hop-by-hop options>");
1030 break;
1031
1032 case IPV6_DSTOPTS:
1033 Printf(" <destination options (after routing"
1034 "header)>");
1035 break;
1036
1037 case IPV6_RTHDRDSTOPTS:
1038 Printf(" <destination options (before routing"
1039 "header)>");
1040 break;
1041
1042 case IPV6_RTHDR:
1043 pr_rthdr((uchar_t *)CMSG_DATA(cmsg));
1044 break;
1045
1046 default:
1047 Printf(" <option type %d>", cmsg->cmsg_type);
1048 break;
1049 }
1050 }
1051 }
1052 (void) putchar('\n');
1053 }
1054
1055 /*
1056 * Print the routing header 0 information
1057 */
1058 static void
pr_rthdr(uchar_t * buf)1059 pr_rthdr(uchar_t *buf)
1060 {
1061 ip6_rthdr_t *rthdr;
1062 ip6_rthdr0_t *rthdr0;
1063 struct in6_addr *gw_addr;
1064 int i, num_addr;
1065
1066 rthdr = (ip6_rthdr_t *)buf;
1067 Printf(" <type %d routing header, segleft %u> ",
1068 rthdr->ip6r_type, rthdr->ip6r_segleft);
1069
1070 if (rthdr->ip6r_type == 0) {
1071 /* LINTED */
1072 rthdr0 = (ip6_rthdr0_t *)buf;
1073 gw_addr = (struct in6_addr *)(rthdr0 + 1);
1074 num_addr = rthdr0->ip6r0_len / 2;
1075
1076 for (i = 0; i < num_addr; i++) {
1077 Printf("%s", pr_name((char *)gw_addr, AF_INET6));
1078 if (i == (num_addr - rthdr0->ip6r0_segleft))
1079 Printf("(Current)");
1080 gw_addr++;
1081 if (i != num_addr - 1)
1082 Printf(", ");
1083 }
1084 }
1085 }
1086