1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 3*0Sstevel@tonic-gate * Use is subject to license terms. 4*0Sstevel@tonic-gate */ 5*0Sstevel@tonic-gate 6*0Sstevel@tonic-gate 7*0Sstevel@tonic-gate /* 8*0Sstevel@tonic-gate * Copyright (c) 1988, 1989, 1991, 1994, 1995, 1996, 1997 9*0Sstevel@tonic-gate * The Regents of the University of California. All rights reserved. 10*0Sstevel@tonic-gate * 11*0Sstevel@tonic-gate * Redistribution and use in source and binary forms, with or without 12*0Sstevel@tonic-gate * modification, are permitted provided that: (1) source code distributions 13*0Sstevel@tonic-gate * retain the above copyright notice and this paragraph in its entirety, (2) 14*0Sstevel@tonic-gate * distributions including binary code include the above copyright notice and 15*0Sstevel@tonic-gate * this paragraph in its entirety in the documentation or other materials 16*0Sstevel@tonic-gate * provided with the distribution, and (3) all advertising materials mentioning 17*0Sstevel@tonic-gate * features or use of this software display the following acknowledgement: 18*0Sstevel@tonic-gate * ``This product includes software developed by the University of California, 19*0Sstevel@tonic-gate * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 20*0Sstevel@tonic-gate * the University nor the names of its contributors may be used to endorse 21*0Sstevel@tonic-gate * or promote products derived from this software without specific prior 22*0Sstevel@tonic-gate * written permission. 23*0Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 24*0Sstevel@tonic-gate * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 25*0Sstevel@tonic-gate * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 26*0Sstevel@tonic-gate * 27*0Sstevel@tonic-gate * 28*0Sstevel@tonic-gate * @(#)$Header: traceroute.c,v 1.49 97/06/13 02:30:23 leres Exp $ (LBL) 29*0Sstevel@tonic-gate */ 30*0Sstevel@tonic-gate 31*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 32*0Sstevel@tonic-gate 33*0Sstevel@tonic-gate #include <sys/socket.h> 34*0Sstevel@tonic-gate 35*0Sstevel@tonic-gate #include <stdio.h> 36*0Sstevel@tonic-gate #include <stdlib.h> 37*0Sstevel@tonic-gate #include <ctype.h> 38*0Sstevel@tonic-gate #include <strings.h> 39*0Sstevel@tonic-gate #include <libintl.h> 40*0Sstevel@tonic-gate #include <errno.h> 41*0Sstevel@tonic-gate #include <netdb.h> 42*0Sstevel@tonic-gate 43*0Sstevel@tonic-gate #include <netinet/in_systm.h> 44*0Sstevel@tonic-gate #include <netinet/in.h> 45*0Sstevel@tonic-gate #include <netinet/ip.h> 46*0Sstevel@tonic-gate #include <netinet/ip_var.h> 47*0Sstevel@tonic-gate #include <netinet/ip_icmp.h> 48*0Sstevel@tonic-gate #include <netinet/udp.h> 49*0Sstevel@tonic-gate #include <netinet/udp_var.h> 50*0Sstevel@tonic-gate #include <netinet/ip6.h> 51*0Sstevel@tonic-gate #include <netinet/icmp6.h> 52*0Sstevel@tonic-gate 53*0Sstevel@tonic-gate #include <arpa/inet.h> 54*0Sstevel@tonic-gate 55*0Sstevel@tonic-gate #include <ifaddrlist.h> 56*0Sstevel@tonic-gate #include "traceroute.h" 57*0Sstevel@tonic-gate 58*0Sstevel@tonic-gate int check_reply6(struct msghdr *, int, int, uchar_t *, uchar_t *); 59*0Sstevel@tonic-gate void *find_ancillary_data(struct msghdr *, int, int); 60*0Sstevel@tonic-gate extern char *inet_name(union any_in_addr *, int); 61*0Sstevel@tonic-gate static int IPv6_hdrlen(ip6_t *, int, uint8_t *); 62*0Sstevel@tonic-gate static char *pr_type6(uchar_t); 63*0Sstevel@tonic-gate void print_addr6(uchar_t *, int, struct sockaddr *); 64*0Sstevel@tonic-gate boolean_t print_icmp_other6(uchar_t, uchar_t); 65*0Sstevel@tonic-gate void send_probe6(int, struct msghdr *, struct ip *, int, int, 66*0Sstevel@tonic-gate struct timeval *, int); 67*0Sstevel@tonic-gate void set_ancillary_data(struct msghdr *, int, union any_in_addr *, int, uint_t); 68*0Sstevel@tonic-gate struct ip *set_buffers6(int); 69*0Sstevel@tonic-gate static boolean_t update_hoplimit_ancillary_data(struct msghdr *, int); 70*0Sstevel@tonic-gate 71*0Sstevel@tonic-gate /* 72*0Sstevel@tonic-gate * prepares the buffer to be sent as an IP datagram 73*0Sstevel@tonic-gate */ 74*0Sstevel@tonic-gate struct ip * 75*0Sstevel@tonic-gate set_buffers6(int plen) 76*0Sstevel@tonic-gate { 77*0Sstevel@tonic-gate struct ip *outip; 78*0Sstevel@tonic-gate uchar_t *outp; 79*0Sstevel@tonic-gate struct udphdr *outudp; 80*0Sstevel@tonic-gate struct icmp *outicmp; 81*0Sstevel@tonic-gate int optlen = 0; 82*0Sstevel@tonic-gate 83*0Sstevel@tonic-gate outip = (struct ip *)malloc((size_t)plen); 84*0Sstevel@tonic-gate if (outip == NULL) { 85*0Sstevel@tonic-gate Fprintf(stderr, "%s: malloc: %s\n", prog, strerror(errno)); 86*0Sstevel@tonic-gate exit(EXIT_FAILURE); 87*0Sstevel@tonic-gate } 88*0Sstevel@tonic-gate 89*0Sstevel@tonic-gate if (gw_count > 0) { 90*0Sstevel@tonic-gate /* ip6_rthdr0 structure includes one gateway address */ 91*0Sstevel@tonic-gate optlen = sizeof (struct ip6_rthdr0) + 92*0Sstevel@tonic-gate gw_count * sizeof (struct in6_addr); 93*0Sstevel@tonic-gate } 94*0Sstevel@tonic-gate 95*0Sstevel@tonic-gate (void) memset((char *)outip, 0, (size_t)plen); 96*0Sstevel@tonic-gate outp = (uchar_t *)(outip + 1); 97*0Sstevel@tonic-gate 98*0Sstevel@tonic-gate if (useicmp) { 99*0Sstevel@tonic-gate /* LINTED E_BAD_PTR_CAST_ALIGN */ 100*0Sstevel@tonic-gate outicmp = (struct icmp *)outp; 101*0Sstevel@tonic-gate outicmp->icmp_type = ICMP6_ECHO_REQUEST; 102*0Sstevel@tonic-gate outicmp->icmp_id = htons(ident); 103*0Sstevel@tonic-gate } else { 104*0Sstevel@tonic-gate /* LINTED E_BAD_PTR_CAST_ALIGN */ 105*0Sstevel@tonic-gate outudp = (struct udphdr *)outp; 106*0Sstevel@tonic-gate /* 107*0Sstevel@tonic-gate * "source port" is set at bind() call, so we don't do it 108*0Sstevel@tonic-gate * again 109*0Sstevel@tonic-gate */ 110*0Sstevel@tonic-gate outudp->uh_ulen = htons((ushort_t)(plen - 111*0Sstevel@tonic-gate (sizeof (struct ip6_hdr) + optlen))); 112*0Sstevel@tonic-gate } 113*0Sstevel@tonic-gate 114*0Sstevel@tonic-gate return (outip); 115*0Sstevel@tonic-gate } 116*0Sstevel@tonic-gate 117*0Sstevel@tonic-gate /* 118*0Sstevel@tonic-gate * Initialize the msghdr for specifying hoplimit, outgoing interface and routing 119*0Sstevel@tonic-gate * header for the probe packets. 120*0Sstevel@tonic-gate */ 121*0Sstevel@tonic-gate void 122*0Sstevel@tonic-gate set_ancillary_data(struct msghdr *msgp, int hoplimit, 123*0Sstevel@tonic-gate union any_in_addr *gwIPlist, int gw_cnt, uint_t if_index) 124*0Sstevel@tonic-gate { 125*0Sstevel@tonic-gate size_t hoplimit_space; 126*0Sstevel@tonic-gate size_t rthdr_space; 127*0Sstevel@tonic-gate size_t pktinfo_space; 128*0Sstevel@tonic-gate size_t bufspace; 129*0Sstevel@tonic-gate struct cmsghdr *cmsgp; 130*0Sstevel@tonic-gate uchar_t *cmsg_datap; 131*0Sstevel@tonic-gate int i; 132*0Sstevel@tonic-gate 133*0Sstevel@tonic-gate msgp->msg_control = NULL; 134*0Sstevel@tonic-gate msgp->msg_controllen = 0; 135*0Sstevel@tonic-gate 136*0Sstevel@tonic-gate /* 137*0Sstevel@tonic-gate * Need to figure out size of buffer needed for ancillary data 138*0Sstevel@tonic-gate * containing routing header and packet info options. 139*0Sstevel@tonic-gate * 140*0Sstevel@tonic-gate * Portable heuristic to compute upper bound on space needed for 141*0Sstevel@tonic-gate * N ancillary data options. It assumes up to _MAX_ALIGNMENT padding 142*0Sstevel@tonic-gate * after both header and data as the worst possible upper bound on space 143*0Sstevel@tonic-gate * consumed by padding. 144*0Sstevel@tonic-gate * It also adds one extra "sizeof (struct cmsghdr)" for the last option. 145*0Sstevel@tonic-gate * This is needed because we would like to use CMSG_NXTHDR() while 146*0Sstevel@tonic-gate * composing the buffer. The CMSG_NXTHDR() macro is designed better for 147*0Sstevel@tonic-gate * parsing than composing the buffer. It requires the pointer it returns 148*0Sstevel@tonic-gate * to leave space in buffer for addressing a cmsghdr and we want to make 149*0Sstevel@tonic-gate * sure it works for us while we skip beyond the last ancillary data 150*0Sstevel@tonic-gate * option. 151*0Sstevel@tonic-gate * 152*0Sstevel@tonic-gate * bufspace[i] = sizeof(struct cmsghdr) + <pad after header> + 153*0Sstevel@tonic-gate * <option[i] content length> + <pad after data>; 154*0Sstevel@tonic-gate * 155*0Sstevel@tonic-gate * total_bufspace = bufspace[0] + bufspace[1] + ... 156*0Sstevel@tonic-gate * ... + bufspace[N-1] + sizeof (struct cmsghdr); 157*0Sstevel@tonic-gate */ 158*0Sstevel@tonic-gate 159*0Sstevel@tonic-gate rthdr_space = 0; 160*0Sstevel@tonic-gate pktinfo_space = 0; 161*0Sstevel@tonic-gate /* We'll always set the hoplimit of the outgoing packets */ 162*0Sstevel@tonic-gate hoplimit_space = sizeof (int); 163*0Sstevel@tonic-gate bufspace = sizeof (struct cmsghdr) + _MAX_ALIGNMENT + 164*0Sstevel@tonic-gate hoplimit_space + _MAX_ALIGNMENT; 165*0Sstevel@tonic-gate 166*0Sstevel@tonic-gate if (gw_cnt > 0) { 167*0Sstevel@tonic-gate rthdr_space = inet6_rth_space(IPV6_RTHDR_TYPE_0, gw_cnt); 168*0Sstevel@tonic-gate bufspace += sizeof (struct cmsghdr) + _MAX_ALIGNMENT + 169*0Sstevel@tonic-gate rthdr_space + _MAX_ALIGNMENT; 170*0Sstevel@tonic-gate } 171*0Sstevel@tonic-gate 172*0Sstevel@tonic-gate if (if_index != 0) { 173*0Sstevel@tonic-gate pktinfo_space = sizeof (struct in6_pktinfo); 174*0Sstevel@tonic-gate bufspace += sizeof (struct cmsghdr) + _MAX_ALIGNMENT + 175*0Sstevel@tonic-gate pktinfo_space + _MAX_ALIGNMENT; 176*0Sstevel@tonic-gate } 177*0Sstevel@tonic-gate 178*0Sstevel@tonic-gate /* 179*0Sstevel@tonic-gate * We need to temporarily set the msgp->msg_controllen to bufspace 180*0Sstevel@tonic-gate * (we will later trim it to actual length used). This is needed because 181*0Sstevel@tonic-gate * CMSG_NXTHDR() uses it to check we have not exceeded the bounds. 182*0Sstevel@tonic-gate */ 183*0Sstevel@tonic-gate bufspace += sizeof (struct cmsghdr); 184*0Sstevel@tonic-gate msgp->msg_controllen = bufspace; 185*0Sstevel@tonic-gate 186*0Sstevel@tonic-gate msgp->msg_control = (struct cmsghdr *)malloc(bufspace); 187*0Sstevel@tonic-gate if (msgp->msg_control == NULL) { 188*0Sstevel@tonic-gate Fprintf(stderr, "%s: malloc %s\n", prog, strerror(errno)); 189*0Sstevel@tonic-gate exit(EXIT_FAILURE); 190*0Sstevel@tonic-gate } 191*0Sstevel@tonic-gate cmsgp = CMSG_FIRSTHDR(msgp); 192*0Sstevel@tonic-gate 193*0Sstevel@tonic-gate /* 194*0Sstevel@tonic-gate * Fill ancillary data. First hoplimit, then rthdr and pktinfo if 195*0Sstevel@tonic-gate * needed. 196*0Sstevel@tonic-gate */ 197*0Sstevel@tonic-gate 198*0Sstevel@tonic-gate /* set hoplimit ancillary data */ 199*0Sstevel@tonic-gate cmsgp->cmsg_level = IPPROTO_IPV6; 200*0Sstevel@tonic-gate cmsgp->cmsg_type = IPV6_HOPLIMIT; 201*0Sstevel@tonic-gate cmsg_datap = CMSG_DATA(cmsgp); 202*0Sstevel@tonic-gate /* LINTED E_BAD_PTR_CAST_ALIGN */ 203*0Sstevel@tonic-gate *(int *)cmsg_datap = hoplimit; 204*0Sstevel@tonic-gate cmsgp->cmsg_len = cmsg_datap + hoplimit_space - (uchar_t *)cmsgp; 205*0Sstevel@tonic-gate cmsgp = CMSG_NXTHDR(msgp, cmsgp); 206*0Sstevel@tonic-gate 207*0Sstevel@tonic-gate /* set rthdr ancillary data if needed */ 208*0Sstevel@tonic-gate if (gw_cnt > 0) { 209*0Sstevel@tonic-gate struct ip6_rthdr0 *rthdr0p; 210*0Sstevel@tonic-gate 211*0Sstevel@tonic-gate cmsgp->cmsg_level = IPPROTO_IPV6; 212*0Sstevel@tonic-gate cmsgp->cmsg_type = IPV6_RTHDR; 213*0Sstevel@tonic-gate cmsg_datap = CMSG_DATA(cmsgp); 214*0Sstevel@tonic-gate 215*0Sstevel@tonic-gate /* 216*0Sstevel@tonic-gate * Initialize rthdr structure 217*0Sstevel@tonic-gate */ 218*0Sstevel@tonic-gate /* LINTED E_BAD_PTR_CAST_ALIGN */ 219*0Sstevel@tonic-gate rthdr0p = (struct ip6_rthdr0 *)cmsg_datap; 220*0Sstevel@tonic-gate if (inet6_rth_init(rthdr0p, rthdr_space, 221*0Sstevel@tonic-gate IPV6_RTHDR_TYPE_0, gw_cnt) == NULL) { 222*0Sstevel@tonic-gate Fprintf(stderr, "%s: inet6_rth_init failed\n", 223*0Sstevel@tonic-gate prog); 224*0Sstevel@tonic-gate exit(EXIT_FAILURE); 225*0Sstevel@tonic-gate } 226*0Sstevel@tonic-gate 227*0Sstevel@tonic-gate /* 228*0Sstevel@tonic-gate * Stuff in gateway addresses 229*0Sstevel@tonic-gate */ 230*0Sstevel@tonic-gate for (i = 0; i < gw_cnt; i++) { 231*0Sstevel@tonic-gate if (inet6_rth_add(rthdr0p, 232*0Sstevel@tonic-gate &gwIPlist[i].addr6) == -1) { 233*0Sstevel@tonic-gate Fprintf(stderr, 234*0Sstevel@tonic-gate "%s: inet6_rth_add\n", prog); 235*0Sstevel@tonic-gate exit(EXIT_FAILURE); 236*0Sstevel@tonic-gate } 237*0Sstevel@tonic-gate } 238*0Sstevel@tonic-gate 239*0Sstevel@tonic-gate cmsgp->cmsg_len = cmsg_datap + rthdr_space - (uchar_t *)cmsgp; 240*0Sstevel@tonic-gate cmsgp = CMSG_NXTHDR(msgp, cmsgp); 241*0Sstevel@tonic-gate } 242*0Sstevel@tonic-gate 243*0Sstevel@tonic-gate /* set pktinfo ancillary data if needed */ 244*0Sstevel@tonic-gate if (if_index != 0) { 245*0Sstevel@tonic-gate struct in6_pktinfo *pktinfop; 246*0Sstevel@tonic-gate 247*0Sstevel@tonic-gate cmsgp->cmsg_level = IPPROTO_IPV6; 248*0Sstevel@tonic-gate cmsgp->cmsg_type = IPV6_PKTINFO; 249*0Sstevel@tonic-gate cmsg_datap = CMSG_DATA(cmsgp); 250*0Sstevel@tonic-gate 251*0Sstevel@tonic-gate /* LINTED E_BAD_PTR_CAST_ALIGN */ 252*0Sstevel@tonic-gate pktinfop = (struct in6_pktinfo *)cmsg_datap; 253*0Sstevel@tonic-gate /* 254*0Sstevel@tonic-gate * We don't know if pktinfop->ipi6_addr is aligned properly, 255*0Sstevel@tonic-gate * therefore let's use bcopy, instead of assignment. 256*0Sstevel@tonic-gate */ 257*0Sstevel@tonic-gate (void) bcopy(&in6addr_any, &pktinfop->ipi6_addr, 258*0Sstevel@tonic-gate sizeof (struct in6_addr)); 259*0Sstevel@tonic-gate 260*0Sstevel@tonic-gate /* 261*0Sstevel@tonic-gate * We can assume pktinfop->ipi6_ifindex is 32 bit aligned. 262*0Sstevel@tonic-gate */ 263*0Sstevel@tonic-gate pktinfop->ipi6_ifindex = if_index; 264*0Sstevel@tonic-gate cmsgp->cmsg_len = cmsg_datap + pktinfo_space - (uchar_t *)cmsgp; 265*0Sstevel@tonic-gate cmsgp = CMSG_NXTHDR(msgp, cmsgp); 266*0Sstevel@tonic-gate } 267*0Sstevel@tonic-gate 268*0Sstevel@tonic-gate msgp->msg_controllen = (char *)cmsgp - (char *)msgp->msg_control; 269*0Sstevel@tonic-gate } 270*0Sstevel@tonic-gate 271*0Sstevel@tonic-gate /* 272*0Sstevel@tonic-gate * Parses the given msg->msg_control to find the IPV6_HOPLIMIT ancillary data 273*0Sstevel@tonic-gate * and update the hoplimit. 274*0Sstevel@tonic-gate * Returns _B_FALSE if it can't find IPV6_HOPLIMIT ancillary data, _B_TRUE 275*0Sstevel@tonic-gate * otherwise. 276*0Sstevel@tonic-gate */ 277*0Sstevel@tonic-gate static boolean_t 278*0Sstevel@tonic-gate update_hoplimit_ancillary_data(struct msghdr *msg, int hoplimit) 279*0Sstevel@tonic-gate { 280*0Sstevel@tonic-gate struct cmsghdr *cmsg; 281*0Sstevel@tonic-gate int *intp; 282*0Sstevel@tonic-gate 283*0Sstevel@tonic-gate for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL; 284*0Sstevel@tonic-gate cmsg = CMSG_NXTHDR(msg, cmsg)) { 285*0Sstevel@tonic-gate if (cmsg->cmsg_level == IPPROTO_IPV6 && 286*0Sstevel@tonic-gate cmsg->cmsg_type == IPV6_HOPLIMIT) { 287*0Sstevel@tonic-gate /* LINTED E_BAD_PTR_CAST_ALIGN */ 288*0Sstevel@tonic-gate intp = (int *)(CMSG_DATA(cmsg)); 289*0Sstevel@tonic-gate *intp = hoplimit; 290*0Sstevel@tonic-gate return (_B_TRUE); 291*0Sstevel@tonic-gate } 292*0Sstevel@tonic-gate } 293*0Sstevel@tonic-gate 294*0Sstevel@tonic-gate return (_B_FALSE); 295*0Sstevel@tonic-gate } 296*0Sstevel@tonic-gate 297*0Sstevel@tonic-gate /* 298*0Sstevel@tonic-gate * send a probe packet to the destination 299*0Sstevel@tonic-gate */ 300*0Sstevel@tonic-gate void 301*0Sstevel@tonic-gate send_probe6(int sndsock, struct msghdr *msg6, struct ip *outip, int seq, 302*0Sstevel@tonic-gate int ttl, struct timeval *tp, int packlen) 303*0Sstevel@tonic-gate { 304*0Sstevel@tonic-gate uchar_t *outp; 305*0Sstevel@tonic-gate struct icmp *outicmp; 306*0Sstevel@tonic-gate struct outdata *outdata; 307*0Sstevel@tonic-gate struct iovec iov; 308*0Sstevel@tonic-gate int cc; 309*0Sstevel@tonic-gate int optlen = 0; 310*0Sstevel@tonic-gate int send_size; 311*0Sstevel@tonic-gate struct sockaddr_in6 *to6; 312*0Sstevel@tonic-gate 313*0Sstevel@tonic-gate if (gw_count > 0) { 314*0Sstevel@tonic-gate /* ip6_rthdr0 structure includes one gateway address */ 315*0Sstevel@tonic-gate optlen = sizeof (struct ip6_rthdr0) + 316*0Sstevel@tonic-gate gw_count * sizeof (struct in6_addr); 317*0Sstevel@tonic-gate } 318*0Sstevel@tonic-gate 319*0Sstevel@tonic-gate send_size = packlen - sizeof (struct ip6_hdr) - optlen; 320*0Sstevel@tonic-gate 321*0Sstevel@tonic-gate /* if using UDP, further discount UDP header size */ 322*0Sstevel@tonic-gate if (!useicmp) 323*0Sstevel@tonic-gate send_size -= sizeof (struct udphdr); 324*0Sstevel@tonic-gate 325*0Sstevel@tonic-gate /* initialize buffer pointers */ 326*0Sstevel@tonic-gate outp = (uchar_t *)(outip + 1); 327*0Sstevel@tonic-gate /* LINTED E_BAD_PTR_CAST_ALIGN */ 328*0Sstevel@tonic-gate outicmp = (struct icmp *)outp; 329*0Sstevel@tonic-gate /* LINTED E_BAD_PTR_CAST_ALIGN */ 330*0Sstevel@tonic-gate outdata = (struct outdata *)(outp + ICMP6_MINLEN); 331*0Sstevel@tonic-gate 332*0Sstevel@tonic-gate if (!update_hoplimit_ancillary_data(msg6, ttl)) { 333*0Sstevel@tonic-gate Fprintf(stderr, 334*0Sstevel@tonic-gate "%s: can't find IPV6_HOPLIMIT ancillary data\n", prog); 335*0Sstevel@tonic-gate exit(EXIT_FAILURE); 336*0Sstevel@tonic-gate } 337*0Sstevel@tonic-gate 338*0Sstevel@tonic-gate /* Payload */ 339*0Sstevel@tonic-gate outdata->seq = seq; 340*0Sstevel@tonic-gate outdata->ttl = ttl; 341*0Sstevel@tonic-gate outdata->tv = *tp; 342*0Sstevel@tonic-gate 343*0Sstevel@tonic-gate if (useicmp) { 344*0Sstevel@tonic-gate outicmp->icmp_seq = htons(seq); 345*0Sstevel@tonic-gate } else { 346*0Sstevel@tonic-gate to6 = (struct sockaddr_in6 *)msg6->msg_name; 347*0Sstevel@tonic-gate to6->sin6_port = htons((port + seq) % (MAX_PORT + 1)); 348*0Sstevel@tonic-gate } 349*0Sstevel@tonic-gate 350*0Sstevel@tonic-gate iov.iov_base = outp; 351*0Sstevel@tonic-gate iov.iov_len = send_size; 352*0Sstevel@tonic-gate 353*0Sstevel@tonic-gate msg6->msg_iov = &iov; 354*0Sstevel@tonic-gate msg6->msg_iovlen = 1; 355*0Sstevel@tonic-gate 356*0Sstevel@tonic-gate cc = sendmsg(sndsock, msg6, 0); 357*0Sstevel@tonic-gate 358*0Sstevel@tonic-gate if (cc < 0 || cc != send_size) { 359*0Sstevel@tonic-gate if (cc < 0) { 360*0Sstevel@tonic-gate Fprintf(stderr, "%s: sendmsg: %s\n", prog, 361*0Sstevel@tonic-gate strerror(errno)); 362*0Sstevel@tonic-gate } 363*0Sstevel@tonic-gate Printf("%s: wrote %s %d chars, ret=%d\n", 364*0Sstevel@tonic-gate prog, hostname, send_size, cc); 365*0Sstevel@tonic-gate (void) fflush(stdout); 366*0Sstevel@tonic-gate } 367*0Sstevel@tonic-gate } 368*0Sstevel@tonic-gate 369*0Sstevel@tonic-gate /* 370*0Sstevel@tonic-gate * Return a pointer to the ancillary data for the given cmsg_level and 371*0Sstevel@tonic-gate * cmsg_type. 372*0Sstevel@tonic-gate * If not found return NULL. 373*0Sstevel@tonic-gate */ 374*0Sstevel@tonic-gate void * 375*0Sstevel@tonic-gate find_ancillary_data(struct msghdr *msg, int cmsg_level, int cmsg_type) 376*0Sstevel@tonic-gate { 377*0Sstevel@tonic-gate struct cmsghdr *cmsg; 378*0Sstevel@tonic-gate 379*0Sstevel@tonic-gate for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL; 380*0Sstevel@tonic-gate cmsg = CMSG_NXTHDR(msg, cmsg)) { 381*0Sstevel@tonic-gate if (cmsg->cmsg_level == cmsg_level && 382*0Sstevel@tonic-gate cmsg->cmsg_type == cmsg_type) { 383*0Sstevel@tonic-gate return (CMSG_DATA(cmsg)); 384*0Sstevel@tonic-gate } 385*0Sstevel@tonic-gate } 386*0Sstevel@tonic-gate return (NULL); 387*0Sstevel@tonic-gate } 388*0Sstevel@tonic-gate 389*0Sstevel@tonic-gate /* 390*0Sstevel@tonic-gate * Check out the reply packet to see if it's what we were expecting. 391*0Sstevel@tonic-gate * Returns REPLY_GOT_TARGET if the reply comes from the target 392*0Sstevel@tonic-gate * REPLY_GOT_GATEWAY if an intermediate gateway sends TIME_EXCEEDED 393*0Sstevel@tonic-gate * REPLY_GOT_OTHER for other kinds of unreachables indicating none of 394*0Sstevel@tonic-gate * the above two cases 395*0Sstevel@tonic-gate * 396*0Sstevel@tonic-gate * It also sets the icmp type and icmp code values 397*0Sstevel@tonic-gate */ 398*0Sstevel@tonic-gate int 399*0Sstevel@tonic-gate check_reply6(struct msghdr *msg, int cc, int seq, uchar_t *type, uchar_t *code) 400*0Sstevel@tonic-gate { 401*0Sstevel@tonic-gate uchar_t *buf = msg->msg_iov->iov_base; 402*0Sstevel@tonic-gate struct sockaddr_in6 *from_in6 = (struct sockaddr_in6 *)msg->msg_name; 403*0Sstevel@tonic-gate icmp6_t *icp6; 404*0Sstevel@tonic-gate ulong_t ip6hdr_len; 405*0Sstevel@tonic-gate uint8_t last_hdr; 406*0Sstevel@tonic-gate int save_cc = cc; 407*0Sstevel@tonic-gate char temp_buf[INET6_ADDRSTRLEN]; /* use for inet_ntop() */ 408*0Sstevel@tonic-gate 409*0Sstevel@tonic-gate /* Ignore packets > 64k or control buffers that don't fit */ 410*0Sstevel@tonic-gate if (msg->msg_flags & (MSG_TRUNC|MSG_CTRUNC)) { 411*0Sstevel@tonic-gate if (verbose) { 412*0Sstevel@tonic-gate Printf("Truncated message: msg_flags 0x%x from %s\n", 413*0Sstevel@tonic-gate msg->msg_flags, 414*0Sstevel@tonic-gate inet_ntop(AF_INET6, 415*0Sstevel@tonic-gate (void *)&(from_in6->sin6_addr), 416*0Sstevel@tonic-gate temp_buf, sizeof (temp_buf))); 417*0Sstevel@tonic-gate } 418*0Sstevel@tonic-gate return (REPLY_SHORT_PKT); 419*0Sstevel@tonic-gate } 420*0Sstevel@tonic-gate if (cc < ICMP6_MINLEN) { 421*0Sstevel@tonic-gate if (verbose) { 422*0Sstevel@tonic-gate Printf("packet too short (%d bytes) from %s\n", 423*0Sstevel@tonic-gate cc, 424*0Sstevel@tonic-gate inet_ntop(AF_INET6, 425*0Sstevel@tonic-gate (void *)&(from_in6->sin6_addr), 426*0Sstevel@tonic-gate temp_buf, sizeof (temp_buf))); 427*0Sstevel@tonic-gate } 428*0Sstevel@tonic-gate return (REPLY_SHORT_PKT); 429*0Sstevel@tonic-gate } 430*0Sstevel@tonic-gate /* LINTED E_BAD_PTR_CAST_ALIGN */ 431*0Sstevel@tonic-gate icp6 = (icmp6_t *)buf; 432*0Sstevel@tonic-gate *type = icp6->icmp6_type; 433*0Sstevel@tonic-gate *code = icp6->icmp6_code; 434*0Sstevel@tonic-gate 435*0Sstevel@tonic-gate /* 436*0Sstevel@tonic-gate * traceroute interprets only ICMP6_TIME_EXCEED_TRANSIT, 437*0Sstevel@tonic-gate * ICMP6_DST_UNREACH, ICMP6_ECHO_REPLY, ICMP6_PACKET_TOO_BIG and 438*0Sstevel@tonic-gate * ICMP6_PARAMPROB_NEXTHEADER, ignores others 439*0Sstevel@tonic-gate */ 440*0Sstevel@tonic-gate if ((*type == ICMP6_TIME_EXCEEDED && 441*0Sstevel@tonic-gate *code == ICMP6_TIME_EXCEED_TRANSIT) || 442*0Sstevel@tonic-gate *type == ICMP6_DST_UNREACH || *type == ICMP6_ECHO_REPLY || 443*0Sstevel@tonic-gate *type == ICMP6_PACKET_TOO_BIG || 444*0Sstevel@tonic-gate (*type == ICMP6_PARAM_PROB && 445*0Sstevel@tonic-gate *code == ICMP6_PARAMPROB_NEXTHEADER)) { 446*0Sstevel@tonic-gate ip6_t *hip6; 447*0Sstevel@tonic-gate struct udphdr *up; 448*0Sstevel@tonic-gate icmp6_t *hicmp6; 449*0Sstevel@tonic-gate 450*0Sstevel@tonic-gate cc -= ICMP6_MINLEN; 451*0Sstevel@tonic-gate hip6 = (ip6_t *)&(icp6->icmp6_data32[1]); 452*0Sstevel@tonic-gate last_hdr = hip6->ip6_nxt; 453*0Sstevel@tonic-gate ip6hdr_len = IPv6_hdrlen(hip6, cc, &last_hdr); 454*0Sstevel@tonic-gate 455*0Sstevel@tonic-gate cc -= ip6hdr_len; 456*0Sstevel@tonic-gate if (useicmp) { 457*0Sstevel@tonic-gate if (*type == ICMP6_ECHO_REPLY && 458*0Sstevel@tonic-gate icp6->icmp6_id == htons(ident) && 459*0Sstevel@tonic-gate icp6->icmp6_seq == htons(seq)) { 460*0Sstevel@tonic-gate return (REPLY_GOT_TARGET); 461*0Sstevel@tonic-gate } 462*0Sstevel@tonic-gate 463*0Sstevel@tonic-gate /* LINTED E_BAD_PTR_CAST_ALIGN */ 464*0Sstevel@tonic-gate hicmp6 = (icmp6_t *)((uchar_t *)hip6 + ip6hdr_len); 465*0Sstevel@tonic-gate 466*0Sstevel@tonic-gate if (ICMP6_MINLEN <= cc && 467*0Sstevel@tonic-gate last_hdr == IPPROTO_ICMPV6 && 468*0Sstevel@tonic-gate hicmp6->icmp6_id == htons(ident) && 469*0Sstevel@tonic-gate hicmp6->icmp6_seq == htons(seq)) { 470*0Sstevel@tonic-gate if (*type == ICMP6_TIME_EXCEEDED) { 471*0Sstevel@tonic-gate return (REPLY_GOT_GATEWAY); 472*0Sstevel@tonic-gate } else { 473*0Sstevel@tonic-gate return (REPLY_GOT_OTHER); 474*0Sstevel@tonic-gate } 475*0Sstevel@tonic-gate } 476*0Sstevel@tonic-gate } else { 477*0Sstevel@tonic-gate /* LINTED E_BAD_PTR_CAST_ALIGN */ 478*0Sstevel@tonic-gate up = (struct udphdr *)((uchar_t *)hip6 + ip6hdr_len); 479*0Sstevel@tonic-gate /* 480*0Sstevel@tonic-gate * at least 4 bytes of UDP header is required for this 481*0Sstevel@tonic-gate * check 482*0Sstevel@tonic-gate */ 483*0Sstevel@tonic-gate if (4 <= cc && 484*0Sstevel@tonic-gate last_hdr == IPPROTO_UDP && 485*0Sstevel@tonic-gate up->uh_sport == htons(ident) && 486*0Sstevel@tonic-gate up->uh_dport == htons((port + seq) % 487*0Sstevel@tonic-gate (MAX_PORT + 1))) { 488*0Sstevel@tonic-gate if (*type == ICMP6_DST_UNREACH && 489*0Sstevel@tonic-gate *code == ICMP6_DST_UNREACH_NOPORT) { 490*0Sstevel@tonic-gate return (REPLY_GOT_TARGET); 491*0Sstevel@tonic-gate } else if (*type == ICMP6_TIME_EXCEEDED) { 492*0Sstevel@tonic-gate return (REPLY_GOT_GATEWAY); 493*0Sstevel@tonic-gate } else { 494*0Sstevel@tonic-gate return (REPLY_GOT_OTHER); 495*0Sstevel@tonic-gate } 496*0Sstevel@tonic-gate } 497*0Sstevel@tonic-gate } 498*0Sstevel@tonic-gate } 499*0Sstevel@tonic-gate 500*0Sstevel@tonic-gate if (verbose) { 501*0Sstevel@tonic-gate int i, j; 502*0Sstevel@tonic-gate uchar_t *lp = (uchar_t *)icp6; 503*0Sstevel@tonic-gate struct in6_addr *dst; 504*0Sstevel@tonic-gate struct in6_pktinfo *pkti; 505*0Sstevel@tonic-gate 506*0Sstevel@tonic-gate pkti = (struct in6_pktinfo *)find_ancillary_data(msg, 507*0Sstevel@tonic-gate IPPROTO_IPV6, IPV6_PKTINFO); 508*0Sstevel@tonic-gate if (pkti == NULL) { 509*0Sstevel@tonic-gate Fprintf(stderr, 510*0Sstevel@tonic-gate "%s: can't find IPV6_PKTINFO ancillary data\n", 511*0Sstevel@tonic-gate prog); 512*0Sstevel@tonic-gate exit(EXIT_FAILURE); 513*0Sstevel@tonic-gate } 514*0Sstevel@tonic-gate dst = &pkti->ipi6_addr; 515*0Sstevel@tonic-gate cc = save_cc; 516*0Sstevel@tonic-gate Printf("\n%d bytes from %s to ", cc, 517*0Sstevel@tonic-gate inet_ntop(AF_INET6, (const void *)&(from_in6->sin6_addr), 518*0Sstevel@tonic-gate temp_buf, sizeof (temp_buf))); 519*0Sstevel@tonic-gate Printf("%s: icmp type %d (%s) code %d\n", 520*0Sstevel@tonic-gate inet_ntop(AF_INET6, (const void *)dst, 521*0Sstevel@tonic-gate temp_buf, sizeof (temp_buf)), 522*0Sstevel@tonic-gate *type, pr_type6(*type), *code); 523*0Sstevel@tonic-gate for (i = 0; i < cc; i += 4) { 524*0Sstevel@tonic-gate Printf("%2d: x", i); 525*0Sstevel@tonic-gate for (j = 0; ((j < 4) && ((i + j) < cc)); j++) 526*0Sstevel@tonic-gate Printf("%2.2x", *lp++); 527*0Sstevel@tonic-gate (void) putchar('\n'); 528*0Sstevel@tonic-gate } 529*0Sstevel@tonic-gate } 530*0Sstevel@tonic-gate 531*0Sstevel@tonic-gate return (REPLY_SHORT_PKT); 532*0Sstevel@tonic-gate } 533*0Sstevel@tonic-gate 534*0Sstevel@tonic-gate /* 535*0Sstevel@tonic-gate * Return the length of the IPv6 related headers (including extension headers) 536*0Sstevel@tonic-gate */ 537*0Sstevel@tonic-gate static int 538*0Sstevel@tonic-gate IPv6_hdrlen(ip6_t *ip6h, int pkt_len, uint8_t *last_hdr_rtrn) 539*0Sstevel@tonic-gate { 540*0Sstevel@tonic-gate int length; 541*0Sstevel@tonic-gate int exthdrlength; 542*0Sstevel@tonic-gate uint8_t nexthdr; 543*0Sstevel@tonic-gate uint8_t *whereptr; 544*0Sstevel@tonic-gate ip6_hbh_t *hbhhdr; 545*0Sstevel@tonic-gate ip6_dest_t *desthdr; 546*0Sstevel@tonic-gate ip6_rthdr_t *rthdr; 547*0Sstevel@tonic-gate ip6_frag_t *fraghdr; 548*0Sstevel@tonic-gate uint8_t *endptr; 549*0Sstevel@tonic-gate 550*0Sstevel@tonic-gate length = sizeof (ip6_t); 551*0Sstevel@tonic-gate 552*0Sstevel@tonic-gate whereptr = ((uint8_t *)&ip6h[1]); /* point to next hdr */ 553*0Sstevel@tonic-gate endptr = ((uint8_t *)ip6h) + pkt_len; 554*0Sstevel@tonic-gate 555*0Sstevel@tonic-gate nexthdr = ip6h->ip6_nxt; 556*0Sstevel@tonic-gate *last_hdr_rtrn = IPPROTO_NONE; 557*0Sstevel@tonic-gate 558*0Sstevel@tonic-gate if (whereptr >= endptr) 559*0Sstevel@tonic-gate return (length); 560*0Sstevel@tonic-gate 561*0Sstevel@tonic-gate while (whereptr < endptr) { 562*0Sstevel@tonic-gate *last_hdr_rtrn = nexthdr; 563*0Sstevel@tonic-gate switch (nexthdr) { 564*0Sstevel@tonic-gate case IPPROTO_HOPOPTS: 565*0Sstevel@tonic-gate hbhhdr = (ip6_hbh_t *)whereptr; 566*0Sstevel@tonic-gate exthdrlength = 8 * (hbhhdr->ip6h_len + 1); 567*0Sstevel@tonic-gate if ((uchar_t *)hbhhdr + exthdrlength > endptr) 568*0Sstevel@tonic-gate return (length); 569*0Sstevel@tonic-gate nexthdr = hbhhdr->ip6h_nxt; 570*0Sstevel@tonic-gate length += exthdrlength; 571*0Sstevel@tonic-gate break; 572*0Sstevel@tonic-gate 573*0Sstevel@tonic-gate case IPPROTO_DSTOPTS: 574*0Sstevel@tonic-gate desthdr = (ip6_dest_t *)whereptr; 575*0Sstevel@tonic-gate exthdrlength = 8 * (desthdr->ip6d_len + 1); 576*0Sstevel@tonic-gate if ((uchar_t *)desthdr + exthdrlength > endptr) 577*0Sstevel@tonic-gate return (length); 578*0Sstevel@tonic-gate nexthdr = desthdr->ip6d_nxt; 579*0Sstevel@tonic-gate length += exthdrlength; 580*0Sstevel@tonic-gate break; 581*0Sstevel@tonic-gate 582*0Sstevel@tonic-gate case IPPROTO_ROUTING: 583*0Sstevel@tonic-gate rthdr = (ip6_rthdr_t *)whereptr; 584*0Sstevel@tonic-gate exthdrlength = 8 * (rthdr->ip6r_len + 1); 585*0Sstevel@tonic-gate if ((uchar_t *)rthdr + exthdrlength > endptr) 586*0Sstevel@tonic-gate return (length); 587*0Sstevel@tonic-gate nexthdr = rthdr->ip6r_nxt; 588*0Sstevel@tonic-gate length += exthdrlength; 589*0Sstevel@tonic-gate break; 590*0Sstevel@tonic-gate 591*0Sstevel@tonic-gate case IPPROTO_FRAGMENT: 592*0Sstevel@tonic-gate /* LINTED E_BAD_PTR_CAST_ALIGN */ 593*0Sstevel@tonic-gate fraghdr = (ip6_frag_t *)whereptr; 594*0Sstevel@tonic-gate if ((uchar_t *)&fraghdr[1] > endptr) 595*0Sstevel@tonic-gate return (length); 596*0Sstevel@tonic-gate nexthdr = fraghdr->ip6f_nxt; 597*0Sstevel@tonic-gate length += sizeof (struct ip6_frag); 598*0Sstevel@tonic-gate break; 599*0Sstevel@tonic-gate 600*0Sstevel@tonic-gate case IPPROTO_NONE: 601*0Sstevel@tonic-gate default: 602*0Sstevel@tonic-gate return (length); 603*0Sstevel@tonic-gate } 604*0Sstevel@tonic-gate whereptr = (uint8_t *)ip6h + length; 605*0Sstevel@tonic-gate } 606*0Sstevel@tonic-gate *last_hdr_rtrn = nexthdr; 607*0Sstevel@tonic-gate 608*0Sstevel@tonic-gate return (length); 609*0Sstevel@tonic-gate } 610*0Sstevel@tonic-gate 611*0Sstevel@tonic-gate /* 612*0Sstevel@tonic-gate * convert an ICMP6 "type" field to a printable string. 613*0Sstevel@tonic-gate */ 614*0Sstevel@tonic-gate static char * 615*0Sstevel@tonic-gate pr_type6(uchar_t type) 616*0Sstevel@tonic-gate { 617*0Sstevel@tonic-gate static struct icmptype_table ttab6[] = { 618*0Sstevel@tonic-gate {ICMP6_DST_UNREACH, "Dest Unreachable"}, 619*0Sstevel@tonic-gate {ICMP6_PACKET_TOO_BIG, "Packet Too Big"}, 620*0Sstevel@tonic-gate {ICMP6_TIME_EXCEEDED, "Time Exceeded"}, 621*0Sstevel@tonic-gate {ICMP6_PARAM_PROB, "Param Problem"}, 622*0Sstevel@tonic-gate {ICMP6_ECHO_REQUEST, "Echo Request"}, 623*0Sstevel@tonic-gate {ICMP6_ECHO_REPLY, "Echo Reply"}, 624*0Sstevel@tonic-gate {MLD_LISTENER_QUERY, "Multicast Listener Query"}, 625*0Sstevel@tonic-gate {MLD_LISTENER_REPORT, "Multicast Listener Report"}, 626*0Sstevel@tonic-gate {MLD_LISTENER_REDUCTION, "Multicast Listener Done"}, 627*0Sstevel@tonic-gate {ND_ROUTER_SOLICIT, "Router Solicitation"}, 628*0Sstevel@tonic-gate {ND_ROUTER_ADVERT, "Router Advertisement"}, 629*0Sstevel@tonic-gate {ND_NEIGHBOR_SOLICIT, "Neighbor Solicitation"}, 630*0Sstevel@tonic-gate {ND_NEIGHBOR_ADVERT, "Neighbor Advertisement"}, 631*0Sstevel@tonic-gate {ND_REDIRECT, "Redirect Message"} 632*0Sstevel@tonic-gate }; 633*0Sstevel@tonic-gate int i = 0; 634*0Sstevel@tonic-gate 635*0Sstevel@tonic-gate for (i = 0; i < A_CNT(ttab6); i++) { 636*0Sstevel@tonic-gate if (ttab6[i].type == type) 637*0Sstevel@tonic-gate return (ttab6[i].message); 638*0Sstevel@tonic-gate } 639*0Sstevel@tonic-gate 640*0Sstevel@tonic-gate return ("OUT-OF-RANGE"); 641*0Sstevel@tonic-gate } 642*0Sstevel@tonic-gate 643*0Sstevel@tonic-gate 644*0Sstevel@tonic-gate /* 645*0Sstevel@tonic-gate * print the IPv6 src address of the reply packet 646*0Sstevel@tonic-gate */ 647*0Sstevel@tonic-gate void 648*0Sstevel@tonic-gate print_addr6(uchar_t *buf, int cc, struct sockaddr *from) 649*0Sstevel@tonic-gate { 650*0Sstevel@tonic-gate /* LINTED E_BAD_PTR_CAST_ALIGN */ 651*0Sstevel@tonic-gate struct sockaddr_in6 *from_in6 = (struct sockaddr_in6 *)from; 652*0Sstevel@tonic-gate ip6_t *ip; 653*0Sstevel@tonic-gate union any_in_addr ip_addr; 654*0Sstevel@tonic-gate char *resolved_name; 655*0Sstevel@tonic-gate char temp_buf[INET6_ADDRSTRLEN]; /* use for inet_ntop() */ 656*0Sstevel@tonic-gate 657*0Sstevel@tonic-gate ip_addr.addr6 = from_in6->sin6_addr; 658*0Sstevel@tonic-gate 659*0Sstevel@tonic-gate /* LINTED E_BAD_PTR_CAST_ALIGN */ 660*0Sstevel@tonic-gate ip = (ip6_t *)buf; 661*0Sstevel@tonic-gate 662*0Sstevel@tonic-gate (void) inet_ntop(AF_INET6, &(from_in6->sin6_addr), temp_buf, 663*0Sstevel@tonic-gate sizeof (temp_buf)); 664*0Sstevel@tonic-gate if (!nflag) 665*0Sstevel@tonic-gate resolved_name = inet_name(&ip_addr, AF_INET6); 666*0Sstevel@tonic-gate /* 667*0Sstevel@tonic-gate * If the IPv6 address cannot be resolved to hostname, inet_name() 668*0Sstevel@tonic-gate * returns the IPv6 address as a string. In that case, we choose not 669*0Sstevel@tonic-gate * to print it twice. This saves us space on display. 670*0Sstevel@tonic-gate */ 671*0Sstevel@tonic-gate if (nflag || (strcmp(temp_buf, resolved_name) == 0)) 672*0Sstevel@tonic-gate Printf(" %s", temp_buf); 673*0Sstevel@tonic-gate else 674*0Sstevel@tonic-gate Printf(" %s (%s)", resolved_name, temp_buf); 675*0Sstevel@tonic-gate 676*0Sstevel@tonic-gate if (verbose) { 677*0Sstevel@tonic-gate Printf(" %d bytes to %s", cc, inet_ntop(AF_INET6, 678*0Sstevel@tonic-gate (const void *) &(ip->ip6_dst), temp_buf, 679*0Sstevel@tonic-gate sizeof (temp_buf))); 680*0Sstevel@tonic-gate } 681*0Sstevel@tonic-gate } 682*0Sstevel@tonic-gate 683*0Sstevel@tonic-gate /* 684*0Sstevel@tonic-gate * ICMP6 messages which doesn't mean we got the target, or we got a gateway, are 685*0Sstevel@tonic-gate * processed here. It returns _B_TRUE if it's some sort of 'unreachable'. 686*0Sstevel@tonic-gate */ 687*0Sstevel@tonic-gate boolean_t 688*0Sstevel@tonic-gate print_icmp_other6(uchar_t type, uchar_t code) 689*0Sstevel@tonic-gate { 690*0Sstevel@tonic-gate boolean_t unreach = _B_FALSE; 691*0Sstevel@tonic-gate 692*0Sstevel@tonic-gate switch (type) { 693*0Sstevel@tonic-gate 694*0Sstevel@tonic-gate /* this corresponds to "ICMP_UNREACH_NEEDFRAG" in ICMP */ 695*0Sstevel@tonic-gate case ICMP6_PACKET_TOO_BIG: 696*0Sstevel@tonic-gate unreach = _B_TRUE; 697*0Sstevel@tonic-gate Printf(" !B"); 698*0Sstevel@tonic-gate break; 699*0Sstevel@tonic-gate 700*0Sstevel@tonic-gate case ICMP6_PARAM_PROB: 701*0Sstevel@tonic-gate /* this corresponds to "ICMP_UNREACH_PROTOCOL" in ICMP */ 702*0Sstevel@tonic-gate if (code == ICMP6_PARAMPROB_NEXTHEADER) { 703*0Sstevel@tonic-gate unreach = _B_TRUE; 704*0Sstevel@tonic-gate Printf(" !R"); 705*0Sstevel@tonic-gate } 706*0Sstevel@tonic-gate break; 707*0Sstevel@tonic-gate 708*0Sstevel@tonic-gate case ICMP6_DST_UNREACH: 709*0Sstevel@tonic-gate switch (code) { 710*0Sstevel@tonic-gate case ICMP6_DST_UNREACH_NOPORT: 711*0Sstevel@tonic-gate break; 712*0Sstevel@tonic-gate 713*0Sstevel@tonic-gate case ICMP6_DST_UNREACH_NOROUTE: 714*0Sstevel@tonic-gate unreach = _B_TRUE; 715*0Sstevel@tonic-gate Printf(" !H"); 716*0Sstevel@tonic-gate break; 717*0Sstevel@tonic-gate 718*0Sstevel@tonic-gate case ICMP6_DST_UNREACH_ADMIN: 719*0Sstevel@tonic-gate unreach = _B_TRUE; 720*0Sstevel@tonic-gate Printf(" !X"); 721*0Sstevel@tonic-gate break; 722*0Sstevel@tonic-gate 723*0Sstevel@tonic-gate case ICMP6_DST_UNREACH_ADDR: 724*0Sstevel@tonic-gate unreach = _B_TRUE; 725*0Sstevel@tonic-gate Printf(" !A"); 726*0Sstevel@tonic-gate break; 727*0Sstevel@tonic-gate 728*0Sstevel@tonic-gate case ICMP6_DST_UNREACH_NOTNEIGHBOR: 729*0Sstevel@tonic-gate unreach = _B_TRUE; 730*0Sstevel@tonic-gate Printf(" !E"); 731*0Sstevel@tonic-gate break; 732*0Sstevel@tonic-gate 733*0Sstevel@tonic-gate default: 734*0Sstevel@tonic-gate unreach = _B_TRUE; 735*0Sstevel@tonic-gate Printf(" !<%d>", code); 736*0Sstevel@tonic-gate break; 737*0Sstevel@tonic-gate } 738*0Sstevel@tonic-gate break; 739*0Sstevel@tonic-gate default: 740*0Sstevel@tonic-gate break; 741*0Sstevel@tonic-gate } 742*0Sstevel@tonic-gate 743*0Sstevel@tonic-gate return (unreach); 744*0Sstevel@tonic-gate } 745