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