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