1 0 stevel /* 2 0 stevel * CDDL HEADER START 3 0 stevel * 4 0 stevel * The contents of this file are subject to the terms of the 5 4564 wy83408 * Common Development and Distribution License (the "License"). 6 4564 wy83408 * You may not use this file except in compliance with the License. 7 0 stevel * 8 0 stevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 0 stevel * or http://www.opensolaris.org/os/licensing. 10 0 stevel * See the License for the specific language governing permissions 11 0 stevel * and limitations under the License. 12 0 stevel * 13 0 stevel * When distributing Covered Code, include this CDDL HEADER in each 14 0 stevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 0 stevel * If applicable, add the following below this CDDL HEADER, with the 16 0 stevel * fields enclosed by brackets "[]" replaced with your own identifying 17 0 stevel * information: Portions Copyright [yyyy] [name of copyright owner] 18 0 stevel * 19 0 stevel * CDDL HEADER END 20 0 stevel */ 21 0 stevel /* 22 10495 Erik * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 0 stevel * Use is subject to license terms. 24 0 stevel */ 25 0 stevel 26 0 stevel #include <stdio.h> 27 0 stevel #include <string.h> 28 0 stevel #include <sys/types.h> 29 0 stevel #include <sys/socket.h> 30 0 stevel #include <net/if.h> 31 0 stevel #include <sys/stropts.h> 32 0 stevel #include <sys/sysmacros.h> 33 0 stevel #include <netinet/in_systm.h> 34 0 stevel #include <netinet/in.h> 35 0 stevel #include <netinet/ip.h> 36 0 stevel #include <netinet/ip_icmp.h> 37 0 stevel #include <netinet/udp.h> 38 0 stevel #include <netinet/tcp.h> 39 0 stevel #include <netinet/icmp6.h> 40 0 stevel #include <netinet/ip6.h> 41 0 stevel #include <inet/ip.h> 42 0 stevel #include <inet/ip6.h> 43 0 stevel #include <arpa/inet.h> 44 0 stevel #include <netdb.h> 45 0 stevel #include "snoop.h" 46 0 stevel #include "snoop_mip.h" 47 0 stevel 48 0 stevel static void interpret_options(char *, int); 49 0 stevel static void interpret_mldv2qry(icmp6_t *, int); 50 0 stevel static void interpret_mldv2rpt(icmp6_t *, int); 51 0 stevel 52 0 stevel 53 0 stevel /* Mobile-IP routines from snoop_mip.c */ 54 0 stevel extern void interpret_icmp_mip_ext(uchar_t *, int); 55 0 stevel extern const char *get_mip_adv_desc(uint8_t); 56 0 stevel 57 0 stevel /* Router advertisement message structure. */ 58 0 stevel struct icmp_ra_addr { 59 0 stevel uint32_t addr; 60 0 stevel uint32_t preference; 61 0 stevel }; 62 0 stevel 63 0 stevel /*ARGSUSED*/ 64 0 stevel void 65 0 stevel interpret_icmp(int flags, struct icmp *icmp, int iplen, int ilen) 66 0 stevel { 67 0 stevel char *pt, *pc, *px; 68 0 stevel char *line; 69 0 stevel char buff[67627]; /* Router adv. can have 256 routers .... */ 70 0 stevel /* Each router has a name 256 char long .. */ 71 0 stevel char extbuff[MAXHOSTNAMELEN + 1]; 72 0 stevel struct udphdr *orig_uhdr; 73 0 stevel int num_rtr_addrs = 0; 74 0 stevel extern char *prot_nest_prefix; 75 0 stevel 76 0 stevel if (ilen < ICMP_MINLEN) 77 0 stevel return; /* incomplete header */ 78 0 stevel 79 0 stevel pt = "Unknown"; 80 0 stevel pc = ""; 81 0 stevel px = ""; 82 0 stevel 83 0 stevel switch (icmp->icmp_type) { 84 0 stevel case ICMP_ECHOREPLY: 85 0 stevel pt = "Echo reply"; 86 0 stevel (void) sprintf(buff, "ID: %d Sequence number: %d", 87 0 stevel ntohs(icmp->icmp_id), ntohs(icmp->icmp_seq)); 88 0 stevel pc = buff; 89 0 stevel break; 90 0 stevel case ICMP_UNREACH: 91 0 stevel pt = "Destination unreachable"; 92 0 stevel switch (icmp->icmp_code) { 93 0 stevel case ICMP_UNREACH_NET: 94 0 stevel if (ilen >= ICMP_ADVLENMIN) { 95 0 stevel (void) sprintf(buff, "Net %s unreachable", 96 0 stevel addrtoname(AF_INET, 97 0 stevel &icmp->icmp_ip.ip_dst)); 98 0 stevel pc = buff; 99 0 stevel } else { 100 0 stevel pc = "Bad net"; 101 0 stevel } 102 0 stevel break; 103 0 stevel case ICMP_UNREACH_HOST: 104 0 stevel if (ilen >= ICMP_ADVLENMIN) { 105 0 stevel (void) sprintf(buff, "Host %s unreachable", 106 0 stevel addrtoname(AF_INET, 107 0 stevel &icmp->icmp_ip.ip_dst)); 108 0 stevel pc = buff; 109 0 stevel } else { 110 0 stevel pc = "Bad host"; 111 0 stevel } 112 0 stevel break; 113 0 stevel case ICMP_UNREACH_PROTOCOL: 114 0 stevel if (ilen >= ICMP_ADVLENMIN) { 115 0 stevel (void) sprintf(buff, "Bad protocol %d", 116 0 stevel icmp->icmp_ip.ip_p); 117 0 stevel pc = buff; 118 0 stevel } else { 119 0 stevel pc = "Bad protocol"; 120 0 stevel } 121 0 stevel break; 122 0 stevel case ICMP_UNREACH_PORT: 123 0 stevel if (ilen >= ICMP_ADVLENMIN) { 124 0 stevel orig_uhdr = (struct udphdr *)((uchar_t *)icmp + 125 0 stevel ICMP_MINLEN + icmp->icmp_ip.ip_hl * 4); 126 0 stevel switch (icmp->icmp_ip.ip_p) { 127 0 stevel case IPPROTO_TCP: 128 0 stevel (void) sprintf(buff, "TCP port %d" 129 0 stevel " unreachable", 130 0 stevel ntohs(orig_uhdr->uh_dport)); 131 0 stevel pc = buff; 132 0 stevel break; 133 0 stevel case IPPROTO_UDP: 134 0 stevel (void) sprintf(buff, "UDP port %d" 135 0 stevel " unreachable", 136 0 stevel ntohs(orig_uhdr->uh_dport)); 137 0 stevel pc = buff; 138 0 stevel break; 139 0 stevel default: 140 0 stevel pc = "Port unreachable"; 141 0 stevel break; 142 0 stevel } 143 0 stevel } else { 144 0 stevel pc = "Bad port"; 145 0 stevel } 146 0 stevel break; 147 0 stevel case ICMP_UNREACH_NEEDFRAG: 148 0 stevel if (ntohs(icmp->icmp_nextmtu) != 0) { 149 0 stevel (void) sprintf(buff, "Needed to fragment:" 150 0 stevel " next hop MTU = %d", 151 0 stevel ntohs(icmp->icmp_nextmtu)); 152 0 stevel pc = buff; 153 0 stevel } else { 154 0 stevel pc = "Needed to fragment"; 155 0 stevel } 156 0 stevel break; 157 0 stevel case ICMP_UNREACH_SRCFAIL: 158 0 stevel pc = "Source route failed"; 159 0 stevel break; 160 0 stevel case ICMP_UNREACH_NET_UNKNOWN: 161 0 stevel pc = "Unknown network"; 162 0 stevel break; 163 0 stevel case ICMP_UNREACH_HOST_UNKNOWN: 164 0 stevel pc = "Unknown host"; 165 0 stevel break; 166 0 stevel case ICMP_UNREACH_ISOLATED: 167 0 stevel pc = "Source host isolated"; 168 0 stevel break; 169 0 stevel case ICMP_UNREACH_NET_PROHIB: 170 0 stevel pc = "Net administratively prohibited"; 171 0 stevel break; 172 0 stevel case ICMP_UNREACH_HOST_PROHIB: 173 0 stevel pc = "Host administratively prohibited"; 174 0 stevel break; 175 0 stevel case ICMP_UNREACH_TOSNET: 176 0 stevel pc = "Net unreachable for this TOS"; 177 0 stevel break; 178 0 stevel case ICMP_UNREACH_TOSHOST: 179 0 stevel pc = "Host unreachable for this TOS"; 180 0 stevel break; 181 0 stevel case ICMP_UNREACH_FILTER_PROHIB: 182 0 stevel pc = "Communication administratively prohibited"; 183 0 stevel break; 184 0 stevel case ICMP_UNREACH_HOST_PRECEDENCE: 185 0 stevel pc = "Host precedence violation"; 186 0 stevel break; 187 0 stevel case ICMP_UNREACH_PRECEDENCE_CUTOFF: 188 0 stevel pc = "Precedence cutoff in effect"; 189 0 stevel break; 190 0 stevel default: 191 0 stevel break; 192 0 stevel } 193 0 stevel break; 194 0 stevel case ICMP_SOURCEQUENCH: 195 0 stevel pt = "Packet lost, slow down"; 196 0 stevel break; 197 0 stevel case ICMP_REDIRECT: 198 0 stevel pt = "Redirect"; 199 0 stevel switch (icmp->icmp_code) { 200 0 stevel case ICMP_REDIRECT_NET: 201 0 stevel pc = "for network"; 202 0 stevel break; 203 0 stevel case ICMP_REDIRECT_HOST: 204 0 stevel pc = "for host"; 205 0 stevel break; 206 0 stevel case ICMP_REDIRECT_TOSNET: 207 0 stevel pc = "for tos and net"; 208 0 stevel break; 209 0 stevel case ICMP_REDIRECT_TOSHOST: 210 0 stevel pc = "for tos and host"; 211 0 stevel break; 212 0 stevel default: 213 0 stevel break; 214 0 stevel } 215 0 stevel (void) sprintf(buff, "%s %s to %s", 216 0 stevel pc, addrtoname(AF_INET, &icmp->icmp_ip.ip_dst), 217 0 stevel addrtoname(AF_INET, &icmp->icmp_gwaddr)); 218 0 stevel pc = buff; 219 0 stevel break; 220 0 stevel case ICMP_ECHO: 221 0 stevel pt = "Echo request"; 222 0 stevel (void) sprintf(buff, "ID: %d Sequence number: %d", 223 0 stevel ntohs(icmp->icmp_id), ntohs(icmp->icmp_seq)); 224 0 stevel pc = buff; 225 0 stevel break; 226 0 stevel case ICMP_ROUTERADVERT: 227 0 stevel 228 0 stevel #define icmp_num_addrs icmp_hun.ih_rtradv.irt_num_addrs 229 0 stevel #define icmp_wpa icmp_hun.ih_rtradv.irt_wpa 230 0 stevel #define icmp_lifetime icmp_hun.ih_rtradv.irt_lifetime 231 0 stevel 232 0 stevel pt = "Router advertisement"; 233 0 stevel (void) sprintf(buff, "Lifetime %ds [%d]:", 234 0 stevel ntohs(icmp->icmp_lifetime), icmp->icmp_num_addrs); 235 0 stevel if (icmp->icmp_wpa == 2) { 236 0 stevel struct icmp_ra_addr *ra; 237 0 stevel char ra_buf[MAXHOSTNAMELEN + 32]; 238 0 stevel char ra_ext_buf[50]; 239 0 stevel struct in_addr sin; 240 0 stevel int icmp_ra_len; 241 0 stevel int i; 242 0 stevel 243 0 stevel /* Cannot trust anything from the network... */ 244 0 stevel num_rtr_addrs = MIN((ilen - ICMP_MINLEN) / 8, 245 0 stevel icmp->icmp_num_addrs); 246 0 stevel 247 0 stevel ra = (struct icmp_ra_addr *)icmp->icmp_data; 248 0 stevel for (i = 0; i < num_rtr_addrs; i++) { 249 0 stevel sin.s_addr = ra->addr; 250 0 stevel (void) snprintf(ra_buf, sizeof (ra_buf), 251 0 stevel " {%s %u}", 252 0 stevel addrtoname(AF_INET, &sin), 253 0 stevel ntohl(ra->preference)); 254 0 stevel if (strlcat(buff, ra_buf, sizeof (buff)) >= 255 0 stevel sizeof (buff)) { 256 0 stevel buff[sizeof (buff) - 257 0 stevel strlen("<Too Long>)")] = '\0'; 258 0 stevel (void) strlcat(buff, "<Too Long>", 259 0 stevel sizeof (buff)); 260 0 stevel break; 261 0 stevel } 262 0 stevel ra++; 263 0 stevel } 264 0 stevel 265 0 stevel icmp_ra_len = ICMP_MINLEN + num_rtr_addrs * 266 0 stevel sizeof (struct icmp_ra_addr); 267 0 stevel if (ilen > icmp_ra_len) { 268 0 stevel int curr_len = ilen - icmp_ra_len; 269 0 stevel int ocurr_len; 270 0 stevel exthdr_t *exthdr = (exthdr_t *)ra; 271 0 stevel 272 0 stevel extbuff[0] = '\0'; 273 0 stevel 274 0 stevel while (curr_len > 0) { 275 0 stevel /* Append Mobile-IP description */ 276 0 stevel (void) snprintf(ra_ext_buf, 277 0 stevel sizeof (ra_ext_buf), ", %s", 278 0 stevel get_mip_adv_desc(exthdr->type)); 279 0 stevel (void) strlcat(extbuff, ra_ext_buf, 280 0 stevel sizeof (extbuff)); 281 0 stevel 282 0 stevel /* Special case for padding */ 283 0 stevel if (exthdr->type == 284 0 stevel ICMP_ADV_MSG_PADDING_EXT) { 285 0 stevel 286 0 stevel curr_len--; 287 0 stevel exthdr = (exthdr_t *) 288 0 stevel ((char *)exthdr + 1); 289 0 stevel continue; 290 0 stevel } 291 0 stevel 292 0 stevel /* else normal extension */ 293 0 stevel ocurr_len = curr_len; 294 0 stevel curr_len -= sizeof (*exthdr) + 295 0 stevel exthdr->length; 296 0 stevel /* detect bad length */ 297 0 stevel if (ocurr_len < curr_len) 298 0 stevel break; 299 0 stevel exthdr = (exthdr_t *) 300 0 stevel ((char *)exthdr + 301 0 stevel sizeof (*exthdr) + 302 0 stevel exthdr->length); 303 0 stevel } 304 0 stevel px = extbuff; 305 0 stevel } 306 0 stevel pc = buff; 307 0 stevel } 308 0 stevel break; 309 0 stevel case ICMP_ROUTERSOLICIT: 310 0 stevel pt = "Router solicitation"; 311 0 stevel break; 312 0 stevel case ICMP_TIMXCEED: 313 0 stevel pt = "Time exceeded"; 314 0 stevel switch (icmp->icmp_code) { 315 0 stevel case ICMP_TIMXCEED_INTRANS: 316 0 stevel pc = "in transit"; 317 0 stevel break; 318 0 stevel case ICMP_TIMXCEED_REASS: 319 0 stevel pc = "in reassembly"; 320 0 stevel break; 321 0 stevel default: 322 0 stevel break; 323 0 stevel } 324 0 stevel break; 325 0 stevel case ICMP_PARAMPROB: 326 0 stevel pt = "IP parameter problem"; 327 0 stevel switch (icmp->icmp_code) { 328 0 stevel case ICMP_PARAMPROB_OPTABSENT: 329 0 stevel pc = "Required option missing"; 330 0 stevel break; 331 0 stevel case ICMP_PARAMPROB_BADLENGTH: 332 0 stevel pc = "Bad length"; 333 0 stevel break; 334 0 stevel case 0: /* Should this be the default? */ 335 0 stevel (void) sprintf(buff, "Problem at octet %d\n", 336 0 stevel icmp->icmp_pptr); 337 0 stevel pc = buff; 338 0 stevel default: 339 0 stevel break; 340 0 stevel } 341 0 stevel break; 342 0 stevel case ICMP_TSTAMP: 343 0 stevel pt = "Timestamp request"; 344 0 stevel break; 345 0 stevel case ICMP_TSTAMPREPLY: 346 0 stevel pt = "Timestamp reply"; 347 0 stevel break; 348 0 stevel case ICMP_IREQ: 349 0 stevel pt = "Information request"; 350 0 stevel break; 351 0 stevel case ICMP_IREQREPLY: 352 0 stevel pt = "Information reply"; 353 0 stevel break; 354 0 stevel case ICMP_MASKREQ: 355 0 stevel pt = "Address mask request"; 356 0 stevel break; 357 0 stevel case ICMP_MASKREPLY: 358 0 stevel pt = "Address mask reply"; 359 0 stevel (void) sprintf(buff, "Mask = 0x%x", ntohl(icmp->icmp_mask)); 360 0 stevel pc = buff; 361 0 stevel break; 362 0 stevel default: 363 0 stevel break; 364 0 stevel } 365 0 stevel 366 0 stevel if (flags & F_SUM) { 367 0 stevel line = get_sum_line(); 368 0 stevel if (*pc) { 369 0 stevel if (*px) { 370 0 stevel (void) sprintf(line, "ICMP %s (%s)%s", 371 0 stevel pt, pc, px); 372 0 stevel } else { 373 0 stevel (void) sprintf(line, "ICMP %s (%s)", pt, pc); 374 0 stevel } 375 0 stevel } else { 376 0 stevel (void) sprintf(line, "ICMP %s", pt); 377 0 stevel } 378 0 stevel } 379 0 stevel 380 0 stevel if (flags & F_DTAIL) { 381 0 stevel show_header("ICMP: ", "ICMP Header", ilen); 382 0 stevel show_space(); 383 0 stevel (void) sprintf(get_line(0, 0), "Type = %d (%s)", 384 0 stevel icmp->icmp_type, pt); 385 0 stevel if (*pc) { 386 0 stevel (void) sprintf(get_line(0, 0), "Code = %d (%s)", 387 0 stevel icmp->icmp_code, pc); 388 0 stevel } else { 389 0 stevel (void) sprintf(get_line(0, 0), "Code = %d", 390 0 stevel icmp->icmp_code); 391 0 stevel } 392 0 stevel (void) sprintf(get_line(0, 0), "Checksum = %x", 393 0 stevel ntohs(icmp->icmp_cksum)); 394 0 stevel 395 0 stevel if (icmp->icmp_type == ICMP_UNREACH || 396 0 stevel icmp->icmp_type == ICMP_REDIRECT) { 397 0 stevel if (ilen > 28) { 398 0 stevel show_space(); 399 0 stevel (void) sprintf(get_line(0, 0), 400 0 stevel "[ subject header follows ]"); 401 0 stevel show_space(); 402 0 stevel prot_nest_prefix = "ICMP:"; 403 0 stevel (void) interpret_ip(flags, 404 0 stevel (struct ip *)icmp->icmp_data, 28); 405 0 stevel prot_nest_prefix = ""; 406 0 stevel } 407 0 stevel } else if (icmp->icmp_type == ICMP_PARAMPROB) { 408 0 stevel if (ilen > 28) { 409 0 stevel show_space(); 410 0 stevel (void) sprintf(get_line(0, 0), 411 0 stevel "[ subject header follows ]"); 412 0 stevel show_space(); 413 0 stevel prot_nest_prefix = "ICMP:"; 414 0 stevel (void) interpret_ip(flags, 415 0 stevel (struct ip *)icmp->icmp_data, 28); 416 0 stevel prot_nest_prefix = ""; 417 0 stevel } 418 0 stevel } else if (icmp->icmp_type == ICMP_ROUTERADVERT) { 419 0 stevel if (icmp->icmp_wpa == 2) { 420 0 stevel int icmp_ra_len; 421 0 stevel 422 0 stevel show_space(); 423 0 stevel icmp_ra_len = ICMP_MINLEN + 424 0 stevel num_rtr_addrs * 425 0 stevel sizeof (struct icmp_ra_addr); 426 0 stevel prot_nest_prefix = ""; 427 0 stevel if (ilen > icmp_ra_len) { 428 0 stevel interpret_icmp_mip_ext( 429 0 stevel (uchar_t *)icmp + icmp_ra_len, 430 0 stevel ilen - icmp_ra_len); 431 0 stevel } 432 0 stevel } 433 0 stevel } 434 0 stevel show_space(); 435 0 stevel } 436 0 stevel } 437 0 stevel 438 0 stevel /*ARGSUSED*/ 439 0 stevel void 440 0 stevel interpret_icmpv6(flags, icmp6, iplen, ilen) 441 0 stevel int flags; 442 0 stevel icmp6_t *icmp6; 443 0 stevel int iplen, ilen; 444 0 stevel { 445 0 stevel char *pt, *pc; 446 0 stevel char *line; 447 0 stevel extern char *prot_nest_prefix; 448 0 stevel char addrstr[INET6_ADDRSTRLEN]; 449 0 stevel char buff[2048]; 450 0 stevel 451 0 stevel if (ilen < ICMP6_MINLEN) 452 0 stevel return; /* incomplete header */ 453 0 stevel 454 0 stevel pt = "Unknown"; 455 0 stevel pc = ""; 456 0 stevel 457 0 stevel switch (icmp6->icmp6_type) { 458 0 stevel case ICMP6_DST_UNREACH: 459 0 stevel pt = "Destination unreachable"; 460 0 stevel switch (icmp6->icmp6_code) { 461 0 stevel case ICMP6_DST_UNREACH_NOROUTE: 462 0 stevel pc = "No route to destination"; 463 0 stevel break; 464 0 stevel case ICMP6_DST_UNREACH_ADMIN: 465 0 stevel pc = "Communication administratively prohibited"; 466 0 stevel break; 467 0 stevel case ICMP6_DST_UNREACH_ADDR: 468 0 stevel pc = "Address unreachable"; 469 0 stevel break; 470 0 stevel case ICMP6_DST_UNREACH_NOPORT: 471 0 stevel if (ilen >= ICMP6_MINLEN + IPV6_HDR_LEN + 472 0 stevel sizeof (struct udphdr)) { 473 0 stevel 474 0 stevel ip6_t *orig_ip6hdr = (ip6_t *)&icmp6[1]; 475 0 stevel 476 0 stevel switch (orig_ip6hdr->ip6_nxt) { 477 0 stevel case IPPROTO_TCP: { 478 0 stevel struct tcphdr *orig_thdr = 479 0 stevel (struct tcphdr *)&orig_ip6hdr[1]; 480 0 stevel 481 0 stevel (void) sprintf(buff, "TCP port %hu" 482 0 stevel " unreachable", 483 0 stevel ntohs(orig_thdr->th_dport)); 484 0 stevel pc = buff; 485 0 stevel break; 486 0 stevel } 487 0 stevel case IPPROTO_UDP: { 488 0 stevel struct udphdr *orig_uhdr = 489 0 stevel (struct udphdr *)&orig_ip6hdr[1]; 490 0 stevel 491 0 stevel (void) sprintf(buff, "UDP port %hu" 492 0 stevel " unreachable", 493 0 stevel ntohs(orig_uhdr->uh_dport)); 494 0 stevel pc = buff; 495 0 stevel break; 496 0 stevel } 497 0 stevel default: 498 0 stevel pc = "Port unreachable"; 499 0 stevel break; 500 0 stevel } 501 0 stevel } else { 502 0 stevel pc = "Bad port"; 503 0 stevel } 504 0 stevel break; 505 0 stevel default: 506 0 stevel break; 507 0 stevel } 508 0 stevel break; 509 0 stevel case ICMP6_PACKET_TOO_BIG: 510 0 stevel pt = "Packet too big"; 511 0 stevel break; 512 0 stevel case ND_REDIRECT: 513 0 stevel pt = "Redirect"; 514 0 stevel break; 515 0 stevel case ICMP6_TIME_EXCEEDED: 516 0 stevel pt = "Time exceeded"; 517 0 stevel switch (icmp6->icmp6_code) { 518 0 stevel case ICMP6_TIME_EXCEED_TRANSIT: 519 0 stevel pc = "Hop limit exceeded in transit"; 520 0 stevel break; 521 0 stevel case ICMP6_TIME_EXCEED_REASSEMBLY: 522 0 stevel pc = "Fragment reassembly time exceeded"; 523 0 stevel break; 524 0 stevel default: 525 0 stevel break; 526 0 stevel } 527 0 stevel break; 528 0 stevel case ICMP6_PARAM_PROB: 529 0 stevel pt = "Parameter problem"; 530 0 stevel switch (icmp6->icmp6_code) { 531 0 stevel case ICMP6_PARAMPROB_HEADER: 532 0 stevel pc = "Erroneous header field"; 533 0 stevel break; 534 0 stevel case ICMP6_PARAMPROB_NEXTHEADER: 535 0 stevel pc = "Unrecognized next header type"; 536 0 stevel break; 537 0 stevel case ICMP6_PARAMPROB_OPTION: 538 0 stevel pc = "Unrecognized IPv6 option"; 539 0 stevel break; 540 0 stevel } 541 0 stevel break; 542 0 stevel case ICMP6_ECHO_REQUEST: 543 0 stevel pt = "Echo request"; 544 0 stevel (void) sprintf(buff, "ID: %d Sequence number: %d", 545 0 stevel ntohs(icmp6->icmp6_id), ntohs(icmp6->icmp6_seq)); 546 0 stevel pc = buff; 547 0 stevel break; 548 0 stevel case ICMP6_ECHO_REPLY: 549 0 stevel pt = "Echo reply"; 550 0 stevel (void) sprintf(buff, "ID: %d Sequence number: %d", 551 0 stevel ntohs(icmp6->icmp6_id), ntohs(icmp6->icmp6_seq)); 552 0 stevel pc = buff; 553 0 stevel break; 554 0 stevel case MLD_LISTENER_QUERY: 555 0 stevel if (ilen == MLD_MINLEN) 556 0 stevel pt = "Group membership query - MLDv1"; 557 0 stevel else if (ilen >= MLD_V2_QUERY_MINLEN) 558 0 stevel pt = "Group membership query - MLDv2"; 559 0 stevel else 560 0 stevel pt = "Unknown membership query"; 561 0 stevel break; 562 0 stevel case MLD_LISTENER_REPORT: 563 0 stevel pt = "Group membership report - MLDv1"; 564 0 stevel break; 565 0 stevel case MLD_LISTENER_REDUCTION: 566 0 stevel pt = "Group membership termination - MLDv1"; 567 0 stevel break; 568 0 stevel case MLD_V2_LISTENER_REPORT: 569 0 stevel pt = "Group membership report - MLDv2"; 570 0 stevel break; 571 0 stevel case ND_ROUTER_SOLICIT: 572 0 stevel pt = "Router solicitation"; 573 0 stevel break; 574 0 stevel case ND_ROUTER_ADVERT: 575 0 stevel pt = "Router advertisement"; 576 0 stevel break; 577 0 stevel case ND_NEIGHBOR_SOLICIT: 578 0 stevel pt = "Neighbor solicitation"; 579 0 stevel break; 580 0 stevel case ND_NEIGHBOR_ADVERT: 581 0 stevel pt = "Neighbor advertisement"; 582 0 stevel break; 583 0 stevel default: 584 0 stevel break; 585 0 stevel } 586 0 stevel 587 0 stevel if (flags & F_SUM) { 588 0 stevel line = get_sum_line(); 589 0 stevel if (*pc) 590 0 stevel (void) sprintf(line, "ICMPv6 %s (%s)", pt, pc); 591 0 stevel else 592 0 stevel (void) sprintf(line, "ICMPv6 %s", pt); 593 0 stevel } 594 0 stevel 595 0 stevel if (flags & F_DTAIL) { 596 0 stevel show_header("ICMPv6: ", "ICMPv6 Header", ilen); 597 0 stevel show_space(); 598 0 stevel (void) sprintf(get_line(0, 0), "Type = %d (%s)", 599 0 stevel icmp6->icmp6_type, pt); 600 0 stevel if (*pc) 601 0 stevel (void) sprintf(get_line(0, 0), "Code = %d (%s)", 602 0 stevel icmp6->icmp6_code, pc); 603 0 stevel else 604 0 stevel (void) sprintf(get_line(0, 0), "Code = %d", 605 0 stevel icmp6->icmp6_code); 606 0 stevel (void) sprintf(get_line(0, 0), "Checksum = %x", 607 0 stevel ntohs(icmp6->icmp6_cksum)); 608 0 stevel 609 0 stevel switch (icmp6->icmp6_type) { 610 0 stevel case ICMP6_DST_UNREACH: 611 0 stevel if (ilen > ICMP6_MINLEN + IPV6_HDR_LEN) { 612 0 stevel show_space(); 613 0 stevel (void) sprintf(get_line(0, 0), 614 0 stevel "[ subject header follows ]"); 615 0 stevel show_space(); 616 0 stevel prot_nest_prefix = "ICMPv6:"; 617 0 stevel (void) interpret_ipv6(flags, (ip6_t *)&icmp6[1], 618 0 stevel ICMP6_MINLEN + IPV6_HDR_LEN); 619 0 stevel prot_nest_prefix = ""; 620 0 stevel } 621 0 stevel break; 622 0 stevel case ICMP6_PACKET_TOO_BIG: 623 0 stevel show_space(); 624 0 stevel (void) sprintf(get_line(0, 0), 625 4564 wy83408 " Packet too big MTU = %d", 626 4564 wy83408 ntohl(icmp6->icmp6_mtu)); 627 0 stevel show_space(); 628 0 stevel break; 629 0 stevel case ND_REDIRECT: { 630 0 stevel nd_redirect_t *rd = (nd_redirect_t *)icmp6; 631 0 stevel 632 0 stevel (void) sprintf(get_line(0, 0), "Target address= %s", 633 0 stevel inet_ntop(AF_INET6, (char *)&rd->nd_rd_target, 634 0 stevel addrstr, INET6_ADDRSTRLEN)); 635 0 stevel 636 0 stevel (void) sprintf(get_line(0, 0), 637 0 stevel "Destination address= %s", 638 0 stevel inet_ntop(AF_INET6, (char *)&rd->nd_rd_dst, 639 0 stevel addrstr, INET6_ADDRSTRLEN)); 640 0 stevel show_space(); 641 0 stevel interpret_options((char *)icmp6 + sizeof (*rd), 642 0 stevel ilen - sizeof (*rd)); 643 0 stevel break; 644 0 stevel } 645 0 stevel case ND_NEIGHBOR_SOLICIT: { 646 0 stevel struct nd_neighbor_solicit *ns; 647 0 stevel if (ilen < sizeof (*ns)) 648 0 stevel break; 649 0 stevel ns = (struct nd_neighbor_solicit *)icmp6; 650 0 stevel (void) sprintf(get_line(0, 0), "Target node = %s, %s", 651 0 stevel inet_ntop(AF_INET6, (char *)&ns->nd_ns_target, 652 0 stevel addrstr, INET6_ADDRSTRLEN), 653 0 stevel addrtoname(AF_INET6, &ns->nd_ns_target)); 654 0 stevel show_space(); 655 0 stevel interpret_options((char *)icmp6 + sizeof (*ns), 656 0 stevel ilen - sizeof (*ns)); 657 0 stevel break; 658 0 stevel } 659 0 stevel 660 0 stevel case ND_NEIGHBOR_ADVERT: { 661 0 stevel struct nd_neighbor_advert *na; 662 0 stevel 663 0 stevel if (ilen < sizeof (*na)) 664 0 stevel break; 665 0 stevel na = (struct nd_neighbor_advert *)icmp6; 666 0 stevel (void) sprintf(get_line(0, 0), "Target node = %s, %s", 667 0 stevel inet_ntop(AF_INET6, (char *)&na->nd_na_target, 668 0 stevel addrstr, INET6_ADDRSTRLEN), 669 0 stevel addrtoname(AF_INET6, &na->nd_na_target)); 670 0 stevel (void) sprintf(get_line(0, 0), 671 0 stevel "Router flag: %s, Solicited flag: %s, " 672 0 stevel "Override flag: %s", 673 0 stevel na->nd_na_flags_reserved & ND_NA_FLAG_ROUTER ? 674 0 stevel "SET" : "NOT SET", 675 0 stevel na->nd_na_flags_reserved & ND_NA_FLAG_SOLICITED ? 676 0 stevel "SET" : "NOT SET", 677 0 stevel na->nd_na_flags_reserved & ND_NA_FLAG_OVERRIDE ? 678 0 stevel "SET" : "NOT SET"); 679 0 stevel 680 0 stevel show_space(); 681 0 stevel interpret_options((char *)icmp6 + sizeof (*na), 682 0 stevel ilen - sizeof (*na)); 683 0 stevel } 684 0 stevel break; 685 0 stevel 686 0 stevel case ND_ROUTER_SOLICIT: { 687 0 stevel if (ilen < sizeof (struct nd_router_solicit)) 688 0 stevel break; 689 0 stevel interpret_options( 690 0 stevel (char *)icmp6 + sizeof (struct nd_router_solicit), 691 0 stevel ilen - sizeof (struct nd_router_solicit)); 692 0 stevel break; 693 0 stevel } 694 0 stevel 695 0 stevel case ND_ROUTER_ADVERT: { 696 0 stevel struct nd_router_advert *ra; 697 0 stevel 698 0 stevel if (ilen < sizeof (*ra)) 699 0 stevel break; 700 0 stevel ra = (struct nd_router_advert *)icmp6; 701 0 stevel (void) sprintf(get_line(0, 0), 702 0 stevel "Max hops= %d, Router lifetime= %d", 703 0 stevel ra->nd_ra_curhoplimit, 704 0 stevel ntohs(ra->nd_ra_router_lifetime)); 705 0 stevel 706 0 stevel (void) sprintf(get_line(0, 0), 707 0 stevel "Managed addr conf flag: %s, Other conf flag: %s", 708 0 stevel ra->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED ? 709 0 stevel "SET" : "NOT SET", 710 0 stevel ra->nd_ra_flags_reserved & ND_RA_FLAG_OTHER ? 711 0 stevel "SET" : "NOT SET"); 712 0 stevel 713 0 stevel (void) sprintf(get_line(0, 0), 714 0 stevel "Reachable time: %u, Reachable retrans time %u", 715 0 stevel ntohl(ra->nd_ra_reachable), 716 0 stevel ntohl(ra->nd_ra_retransmit)); 717 0 stevel show_space(); 718 0 stevel 719 0 stevel interpret_options((char *)icmp6 + sizeof (*ra), 720 0 stevel ilen - sizeof (*ra)); 721 0 stevel break; 722 0 stevel } 723 0 stevel case ICMP6_PARAM_PROB: 724 0 stevel if (ilen < sizeof (*icmp6)) 725 0 stevel break; 726 0 stevel (void) sprintf(get_line(0, 0), "Ptr = %u", 727 0 stevel ntohl(icmp6->icmp6_pptr)); 728 0 stevel show_space(); 729 0 stevel break; 730 0 stevel 731 0 stevel case MLD_LISTENER_QUERY: { 732 0 stevel struct mld_hdr *mldg = (struct mld_hdr *)icmp6; 733 0 stevel 734 0 stevel if (ilen < MLD_MINLEN) 735 0 stevel break; 736 0 stevel 737 0 stevel if (ilen >= MLD_V2_QUERY_MINLEN) { 738 0 stevel interpret_mldv2qry(icmp6, ilen); 739 0 stevel } else { 740 0 stevel (void) snprintf(get_line(0, 0), 741 0 stevel get_line_remain(), 742 0 stevel "Multicast address= %s", 743 0 stevel inet_ntop(AF_INET6, mldg->mld_addr.s6_addr, 744 0 stevel addrstr, INET6_ADDRSTRLEN)); 745 0 stevel } 746 0 stevel show_space(); 747 0 stevel break; 748 0 stevel } 749 0 stevel 750 0 stevel case MLD_LISTENER_REPORT: 751 0 stevel case MLD_LISTENER_REDUCTION: { 752 0 stevel struct mld_hdr *mldg; 753 0 stevel 754 0 stevel if (ilen < sizeof (*mldg)) 755 0 stevel break; 756 0 stevel mldg = (struct mld_hdr *)icmp6; 757 0 stevel (void) snprintf(get_line(0, 0), get_line_remain(), 758 0 stevel "Multicast address= %s", inet_ntop(AF_INET6, 759 0 stevel mldg->mld_addr.s6_addr, addrstr, INET6_ADDRSTRLEN)); 760 0 stevel show_space(); 761 0 stevel break; 762 0 stevel } 763 0 stevel 764 0 stevel case MLD_V2_LISTENER_REPORT: { 765 0 stevel interpret_mldv2rpt(icmp6, ilen); 766 0 stevel show_space(); 767 0 stevel break; 768 0 stevel } 769 0 stevel 770 0 stevel default: 771 0 stevel break; 772 0 stevel } 773 0 stevel } 774 0 stevel } 775 0 stevel 776 0 stevel static void 777 0 stevel interpret_options(optc, ilen) 778 0 stevel char *optc; 779 0 stevel int ilen; 780 0 stevel { 781 0 stevel #define PREFIX_OPTION_LENGTH 4 782 0 stevel #define MTU_OPTION_LENGTH 1 783 0 stevel 784 0 stevel #define PREFIX_INFINITY 0xffffffffUL 785 0 stevel 786 0 stevel struct nd_opt_hdr *opt; 787 0 stevel 788 0 stevel for (; ilen >= sizeof (*opt); ) { 789 0 stevel opt = (struct nd_opt_hdr *)optc; 790 0 stevel if (opt->nd_opt_len == 0) 791 0 stevel return; 792 0 stevel switch (opt->nd_opt_type) { 793 0 stevel case ND_OPT_SOURCE_LINKADDR: 794 0 stevel case ND_OPT_TARGET_LINKADDR: 795 0 stevel { 796 0 stevel struct nd_opt_lla *lopt; 797 0 stevel char *buf, chbuf[128]; 798 0 stevel uint_t addr_len; 799 0 stevel int i; 800 0 stevel 801 0 stevel if (ilen < (int)opt->nd_opt_len * 8) 802 0 stevel break; 803 0 stevel 804 0 stevel buf = chbuf; 805 0 stevel 806 0 stevel lopt = (struct nd_opt_lla *)opt; 807 0 stevel if (lopt->nd_opt_lla_type == ND_OPT_SOURCE_LINKADDR) { 808 0 stevel (void) sprintf(get_line(0, 0), 809 0 stevel "+++ ICMPv6 Source LL Addr option +++"); 810 0 stevel } else { 811 0 stevel (void) sprintf(get_line(0, 0), 812 0 stevel "+++ ICMPv6 Target LL Addr option +++"); 813 0 stevel } 814 0 stevel 815 0 stevel /* 816 0 stevel * The option length is in 8 octet units, and 817 0 stevel * includes the first two bytes (the type and 818 0 stevel * lenght fields) of the option. 819 0 stevel */ 820 0 stevel addr_len = lopt->nd_opt_lla_len * 8 - 2; 821 0 stevel for (i = 0; i < addr_len; i++) { 822 0 stevel snprintf(buf, sizeof (chbuf) - (buf - chbuf), 823 0 stevel "%x:", lopt->nd_opt_lla_hdw_addr[i]); 824 0 stevel buf += strlen(buf); 825 0 stevel if (buf >= &chbuf[sizeof (chbuf)]) { 826 0 stevel buf = NULL; 827 0 stevel chbuf[sizeof (chbuf) - 828 0 stevel strlen("<Too Long>)")] = '\0'; 829 0 stevel (void) strlcat(chbuf, "<Too Long>", 830 0 stevel sizeof (chbuf)); 831 0 stevel break; 832 0 stevel } 833 0 stevel } 834 0 stevel if (buf) 835 0 stevel *(buf - 1) = '\0'; /* Erase last colon */ 836 0 stevel (void) sprintf(get_line(0, 0), 837 0 stevel "Link Layer address: %s", chbuf); 838 0 stevel show_space(); 839 0 stevel break; 840 0 stevel } 841 0 stevel case ND_OPT_MTU: { 842 0 stevel struct nd_opt_mtu *mopt; 843 0 stevel if (opt->nd_opt_len != MTU_OPTION_LENGTH || 844 0 stevel ilen < sizeof (struct nd_opt_mtu)) 845 0 stevel break; 846 0 stevel (void) sprintf(get_line(0, 0), 847 0 stevel "+++ ICMPv6 MTU option +++"); 848 0 stevel mopt = (struct nd_opt_mtu *)opt; 849 0 stevel (void) sprintf(get_line(0, 0), 850 10495 Erik "MTU = %u ", ntohl(mopt->nd_opt_mtu_mtu)); 851 0 stevel show_space(); 852 0 stevel break; 853 0 stevel } 854 0 stevel case ND_OPT_PREFIX_INFORMATION: { 855 0 stevel struct nd_opt_prefix_info *popt; 856 0 stevel char validstr[30]; 857 0 stevel char preferredstr[30]; 858 0 stevel char prefixstr[INET6_ADDRSTRLEN]; 859 0 stevel 860 0 stevel if (opt->nd_opt_len != PREFIX_OPTION_LENGTH || 861 0 stevel ilen < sizeof (struct nd_opt_prefix_info)) 862 0 stevel break; 863 0 stevel popt = (struct nd_opt_prefix_info *)opt; 864 0 stevel (void) sprintf(get_line(0, 0), 865 0 stevel "+++ ICMPv6 Prefix option +++"); 866 0 stevel (void) sprintf(get_line(0, 0), 867 0 stevel "Prefix length = %d ", popt->nd_opt_pi_prefix_len); 868 0 stevel (void) sprintf(get_line(0, 0), 869 0 stevel "Onlink flag: %s, Autonomous addr conf flag: %s", 870 0 stevel popt->nd_opt_pi_flags_reserved & 871 0 stevel ND_OPT_PI_FLAG_ONLINK ? "SET" : "NOT SET", 872 0 stevel popt->nd_opt_pi_flags_reserved & 873 0 stevel ND_OPT_PI_FLAG_AUTO ? "SET" : "NOT SET"); 874 0 stevel 875 0 stevel if (ntohl(popt->nd_opt_pi_valid_time) == 876 0 stevel PREFIX_INFINITY) 877 0 stevel sprintf(validstr, "INFINITY"); 878 0 stevel else 879 0 stevel sprintf(validstr, "%lu", 880 0 stevel ntohl(popt->nd_opt_pi_valid_time)); 881 0 stevel 882 0 stevel if (ntohl(popt->nd_opt_pi_preferred_time) == 883 0 stevel PREFIX_INFINITY) 884 0 stevel sprintf(preferredstr, "INFINITY"); 885 0 stevel else 886 0 stevel sprintf(preferredstr, "%lu", 887 0 stevel ntohl(popt->nd_opt_pi_preferred_time)); 888 0 stevel 889 0 stevel (void) sprintf(get_line(0, 0), 890 0 stevel "Valid Lifetime %s, Preferred Lifetime %s", 891 0 stevel validstr, preferredstr); 892 0 stevel (void) sprintf(get_line(0, 0), "Prefix %s", 893 0 stevel inet_ntop(AF_INET6, 894 0 stevel (char *)&popt->nd_opt_pi_prefix, prefixstr, 895 0 stevel INET6_ADDRSTRLEN)); 896 0 stevel show_space(); 897 0 stevel } 898 0 stevel default: 899 0 stevel break; 900 0 stevel } 901 0 stevel optc += opt->nd_opt_len * 8; 902 0 stevel ilen -= opt->nd_opt_len * 8; 903 0 stevel } 904 0 stevel } 905 0 stevel 906 0 stevel static void 907 0 stevel interpret_mldv2qry(icmp6_t *icmp6, int ilen) 908 0 stevel { 909 0 stevel mld2q_t *qry; 910 0 stevel in6_addr_t *src; 911 0 stevel int rem = ilen; 912 0 stevel int srccnt; 913 0 stevel char addrstr[INET6_ADDRSTRLEN]; 914 0 stevel 915 0 stevel if (ilen < sizeof (*qry)) { 916 0 stevel (void) snprintf(get_line(0, 0), get_line_remain(), 917 0 stevel "Malformed MLD Query"); 918 0 stevel return; 919 0 stevel } 920 0 stevel qry = (mld2q_t *)icmp6; 921 0 stevel rem -= sizeof (*qry); 922 0 stevel srccnt = ntohs(qry->mld2q_numsrc); 923 0 stevel (void) snprintf(get_line(0, 0), get_line_remain(), 924 0 stevel "Multicast address= %s", inet_ntop(AF_INET6, 925 0 stevel &qry->mld2q_addr.s6_addr, addrstr, INET6_ADDRSTRLEN)); 926 0 stevel (void) snprintf(get_line(0, 0), get_line_remain(), 927 0 stevel "%d Source Address%s:", srccnt, (srccnt == 1) ? "" : "es"); 928 0 stevel 929 0 stevel src = (in6_addr_t *)&qry[1]; 930 0 stevel while (srccnt > 0 && rem >= sizeof (*src)) { 931 0 stevel rem -= sizeof (*src); 932 0 stevel 933 0 stevel (void) snprintf(get_line(0, 0), get_line_remain(), " %s", 934 0 stevel inet_ntop(AF_INET6, src, addrstr, INET6_ADDRSTRLEN)); 935 0 stevel 936 0 stevel srccnt--; 937 0 stevel src++; 938 0 stevel } 939 0 stevel } 940 0 stevel 941 0 stevel #define MAX_MLDV2_REPORT_TYPE 6 942 0 stevel 943 0 stevel const char *mldv2rpt_types[] = { 944 0 stevel "<unknown>", 945 0 stevel "MODE_IS_INCLUDE", 946 0 stevel "MODE_IS_EXCLUDE", 947 0 stevel "CHANGE_TO_INCLUDE", 948 0 stevel "CHANGE_TO_EXCLUDE", 949 0 stevel "ALLOW_NEW_SOURCES", 950 0 stevel "BLOCK_OLD_SOURCES", 951 0 stevel }; 952 0 stevel 953 0 stevel static void 954 0 stevel interpret_mldv2rpt(icmp6_t *icmp6, int ilen) 955 0 stevel { 956 0 stevel mld2r_t *rpt; 957 0 stevel mld2mar_t *mar; 958 0 stevel in6_addr_t *src; 959 0 stevel int rem = ilen, auxlen; 960 0 stevel uint16_t marcnt, srccnt; 961 0 stevel char addrstr[INET6_ADDRSTRLEN]; 962 0 stevel 963 0 stevel if (ilen < sizeof (*rpt)) { 964 0 stevel (void) snprintf(get_line(0, 0), get_line_remain(), 965 0 stevel "Malformed MLDv2 Report"); 966 0 stevel return; 967 0 stevel } 968 0 stevel rpt = (mld2r_t *)icmp6; 969 0 stevel mar = (mld2mar_t *)&rpt[1]; 970 0 stevel marcnt = ntohs(rpt->mld2r_nummar); 971 0 stevel (void) snprintf(get_line(0, 0), get_line_remain(), 972 0 stevel "%d Multicast Address Record%s:", marcnt, (marcnt == 1) ? "" : "s"); 973 0 stevel rem -= sizeof (*rpt); 974 0 stevel while (marcnt > 0 && rem >= sizeof (*mar)) { 975 0 stevel rem -= sizeof (*mar); 976 0 stevel 977 0 stevel (void) snprintf(get_line(0, 0), get_line_remain(), 978 0 stevel "Multicast address= %s type = %s", inet_ntop(AF_INET6, 979 0 stevel &mar->mld2mar_group.s6_addr, addrstr, INET6_ADDRSTRLEN), 980 0 stevel (mar->mld2mar_type > MAX_MLDV2_REPORT_TYPE) ? 981 0 stevel "<unknown>" : mldv2rpt_types[mar->mld2mar_type]); 982 0 stevel srccnt = ntohs(mar->mld2mar_numsrc); 983 0 stevel (void) snprintf(get_line(0, 0), get_line_remain(), 984 0 stevel "%d Source Address%s:", srccnt, (srccnt == 1) ? "" : "es"); 985 0 stevel 986 0 stevel src = (in6_addr_t *)&mar[1]; 987 0 stevel while (srccnt > 0 && rem >= sizeof (*src)) { 988 0 stevel rem -= sizeof (*src); 989 0 stevel 990 0 stevel (void) snprintf(get_line(0, 0), get_line_remain(), 991 0 stevel " %s", inet_ntop(AF_INET6, src, addrstr, 992 0 stevel INET6_ADDRSTRLEN)); 993 0 stevel 994 0 stevel srccnt--; 995 0 stevel src++; 996 0 stevel } 997 0 stevel 998 0 stevel marcnt--; 999 0 stevel auxlen = mar->mld2mar_auxlen * 4; 1000 0 stevel rem -= auxlen; 1001 0 stevel mar = (mld2mar_t *)((uint8_t *)src + auxlen); 1002 0 stevel } 1003 0 stevel } 1004