1/* 2 * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that: (1) source code distributions 7 * retain the above copyright notice and this paragraph in its entirety, (2) 8 * distributions including binary code include the above copyright notice and 9 * this paragraph in its entirety in the documentation or other materials 10 * provided with the distribution, and (3) all advertising materials mentioning 11 * features or use of this software display the following acknowledgement: 12 * ``This product includes software developed by the University of California, 13 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 14 * the University nor the names of its contributors may be used to endorse 15 * or promote products derived from this software without specific prior 16 * written permission. 17 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 18 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 20 */ 21 22#include <sys/cdefs.h> 23#ifndef lint 24__RCSID("$NetBSD: print-ip6.c,v 1.9 2023/08/17 20:19:40 christos Exp $"); 25#endif 26 27/* \summary: IPv6 printer */ 28 29#ifdef HAVE_CONFIG_H 30#include <config.h> 31#endif 32 33#include "netdissect-stdinc.h" 34 35#include <string.h> 36 37#include "netdissect.h" 38#include "addrtoname.h" 39#include "extract.h" 40 41#include "ip6.h" 42#include "ipproto.h" 43 44/* 45 * If routing headers are presend and valid, set dst to the final destination. 46 * Otherwise, set it to the IPv6 destination. 47 * 48 * This is used for UDP and TCP pseudo-header in the checksum 49 * calculation. 50 */ 51static void 52ip6_finddst(netdissect_options *ndo, nd_ipv6 *dst, 53 const struct ip6_hdr *ip6) 54{ 55 const u_char *cp; 56 u_int advance; 57 u_int nh; 58 const void *dst_addr; 59 const struct ip6_rthdr *dp; 60 const struct ip6_rthdr0 *dp0; 61 const struct ip6_srh *srh; 62 const u_char *p; 63 int i, len; 64 65 cp = (const u_char *)ip6; 66 advance = sizeof(struct ip6_hdr); 67 nh = GET_U_1(ip6->ip6_nxt); 68 dst_addr = (const void *)ip6->ip6_dst; 69 70 while (cp < ndo->ndo_snapend) { 71 cp += advance; 72 73 switch (nh) { 74 75 case IPPROTO_HOPOPTS: 76 case IPPROTO_DSTOPTS: 77 case IPPROTO_MOBILITY_OLD: 78 case IPPROTO_MOBILITY: 79 /* 80 * These have a header length byte, following 81 * the next header byte, giving the length of 82 * the header, in units of 8 octets, excluding 83 * the first 8 octets. 84 */ 85 advance = (GET_U_1(cp + 1) + 1) << 3; 86 nh = GET_U_1(cp); 87 break; 88 89 case IPPROTO_FRAGMENT: 90 /* 91 * The byte following the next header byte is 92 * marked as reserved, and the header is always 93 * the same size. 94 */ 95 advance = sizeof(struct ip6_frag); 96 nh = GET_U_1(cp); 97 break; 98 99 case IPPROTO_ROUTING: 100 /* 101 * OK, we found it. 102 */ 103 dp = (const struct ip6_rthdr *)cp; 104 ND_TCHECK_SIZE(dp); 105 len = GET_U_1(dp->ip6r_len); 106 switch (GET_U_1(dp->ip6r_type)) { 107 108 case IPV6_RTHDR_TYPE_0: 109 case IPV6_RTHDR_TYPE_2: /* Mobile IPv6 ID-20 */ 110 dp0 = (const struct ip6_rthdr0 *)dp; 111 if (len % 2 == 1) 112 goto trunc; 113 len >>= 1; 114 p = (const u_char *) dp0->ip6r0_addr; 115 for (i = 0; i < len; i++) { 116 ND_TCHECK_16(p); 117 dst_addr = (const void *)p; 118 p += 16; 119 } 120 break; 121 case IPV6_RTHDR_TYPE_4: 122 /* IPv6 Segment Routing Header (SRH) */ 123 srh = (const struct ip6_srh *)dp; 124 if (len % 2 == 1) 125 goto trunc; 126 p = (const u_char *) srh->srh_segments; 127 /* 128 * The list of segments are encoded in the reverse order. 129 * Accordingly, the final DA is encoded in srh_segments[0] 130 */ 131 ND_TCHECK_16(p); 132 dst_addr = (const void *)p; 133 break; 134 135 default: 136 break; 137 } 138 139 /* 140 * Only one routing header to a customer. 141 */ 142 goto done; 143 144 case IPPROTO_AH: 145 case IPPROTO_ESP: 146 case IPPROTO_IPCOMP: 147 default: 148 /* 149 * AH and ESP are, in the RFCs that describe them, 150 * described as being "viewed as an end-to-end 151 * payload" "in the IPv6 context, so that they 152 * "should appear after hop-by-hop, routing, and 153 * fragmentation extension headers". We assume 154 * that's the case, and stop as soon as we see 155 * one. (We can't handle an ESP header in 156 * the general case anyway, as its length depends 157 * on the encryption algorithm.) 158 * 159 * IPComp is also "viewed as an end-to-end 160 * payload" "in the IPv6 context". 161 * 162 * All other protocols are assumed to be the final 163 * protocol. 164 */ 165 goto done; 166 } 167 } 168 169done: 170trunc: 171 GET_CPY_BYTES(dst, dst_addr, sizeof(nd_ipv6)); 172} 173 174/* 175 * Compute a V6-style checksum by building a pseudoheader. 176 */ 177uint16_t 178nextproto6_cksum(netdissect_options *ndo, 179 const struct ip6_hdr *ip6, const uint8_t *data, 180 u_int len, u_int covlen, uint8_t next_proto) 181{ 182 struct { 183 nd_ipv6 ph_src; 184 nd_ipv6 ph_dst; 185 uint32_t ph_len; 186 uint8_t ph_zero[3]; 187 uint8_t ph_nxt; 188 } ph; 189 struct cksum_vec vec[2]; 190 u_int nh; 191 192 /* pseudo-header */ 193 memset(&ph, 0, sizeof(ph)); 194 GET_CPY_BYTES(&ph.ph_src, ip6->ip6_src, sizeof(nd_ipv6)); 195 nh = GET_U_1(ip6->ip6_nxt); 196 switch (nh) { 197 198 case IPPROTO_HOPOPTS: 199 case IPPROTO_DSTOPTS: 200 case IPPROTO_MOBILITY_OLD: 201 case IPPROTO_MOBILITY: 202 case IPPROTO_FRAGMENT: 203 case IPPROTO_ROUTING: 204 /* 205 * The next header is either a routing header or a header 206 * after which there might be a routing header, so scan 207 * for a routing header. 208 */ 209 ip6_finddst(ndo, &ph.ph_dst, ip6); 210 break; 211 212 default: 213 GET_CPY_BYTES(&ph.ph_dst, ip6->ip6_dst, sizeof(nd_ipv6)); 214 break; 215 } 216 ph.ph_len = htonl(len); 217 ph.ph_nxt = next_proto; 218 219 vec[0].ptr = (const uint8_t *)(void *)&ph; 220 vec[0].len = sizeof(ph); 221 vec[1].ptr = data; 222 vec[1].len = covlen; 223 224 return in_cksum(vec, 2); 225} 226 227/* 228 * print an IP6 datagram. 229 */ 230void 231ip6_print(netdissect_options *ndo, const u_char *bp, u_int length) 232{ 233 const struct ip6_hdr *ip6; 234 int advance; 235 u_int len; 236 u_int total_advance; 237 const u_char *cp; 238 uint32_t payload_len; 239 uint8_t ph, nh; 240 int fragmented = 0; 241 u_int flow; 242 int found_extension_header; 243 int found_jumbo; 244 int found_hbh; 245 246 ndo->ndo_protocol = "ip6"; 247 ip6 = (const struct ip6_hdr *)bp; 248 249 ND_TCHECK_SIZE(ip6); 250 if (length < sizeof (struct ip6_hdr)) { 251 ND_PRINT("truncated-ip6 %u", length); 252 return; 253 } 254 255 if (!ndo->ndo_eflag) 256 ND_PRINT("IP6 "); 257 258 if (IP6_VERSION(ip6) != 6) { 259 ND_PRINT("version error: %u != 6", IP6_VERSION(ip6)); 260 return; 261 } 262 263 payload_len = GET_BE_U_2(ip6->ip6_plen); 264 /* 265 * RFC 1883 says: 266 * 267 * The Payload Length field in the IPv6 header must be set to zero 268 * in every packet that carries the Jumbo Payload option. If a 269 * packet is received with a valid Jumbo Payload option present and 270 * a non-zero IPv6 Payload Length field, an ICMP Parameter Problem 271 * message, Code 0, should be sent to the packet's source, pointing 272 * to the Option Type field of the Jumbo Payload option. 273 * 274 * Later versions of the IPv6 spec don't discuss the Jumbo Payload 275 * option. 276 * 277 * If the payload length is 0, we temporarily just set the total 278 * length to the remaining data in the packet (which, for Ethernet, 279 * could include frame padding, but if it's a Jumbo Payload frame, 280 * it shouldn't even be sendable over Ethernet, so we don't worry 281 * about that), so we can process the extension headers in order 282 * to *find* a Jumbo Payload hop-by-hop option and, when we've 283 * processed all the extension headers, check whether we found 284 * a Jumbo Payload option, and fail if we haven't. 285 */ 286 if (payload_len != 0) { 287 len = payload_len + sizeof(struct ip6_hdr); 288 if (length < len) 289 ND_PRINT("truncated-ip6 - %u bytes missing!", 290 len - length); 291 } else 292 len = length + sizeof(struct ip6_hdr); 293 294 ph = 255; 295 nh = GET_U_1(ip6->ip6_nxt); 296 if (ndo->ndo_vflag) { 297 flow = GET_BE_U_4(ip6->ip6_flow); 298 ND_PRINT("("); 299 /* RFC 2460 */ 300 if (flow & 0x0ff00000) 301 ND_PRINT("class 0x%02x, ", (flow & 0x0ff00000) >> 20); 302 if (flow & 0x000fffff) 303 ND_PRINT("flowlabel 0x%05x, ", flow & 0x000fffff); 304 305 ND_PRINT("hlim %u, next-header %s (%u) payload length: %u) ", 306 GET_U_1(ip6->ip6_hlim), 307 tok2str(ipproto_values,"unknown",nh), 308 nh, 309 payload_len); 310 } 311 312 /* 313 * Cut off the snapshot length to the end of the IP payload. 314 */ 315 if (!nd_push_snaplen(ndo, bp, len)) { 316 (*ndo->ndo_error)(ndo, S_ERR_ND_MEM_ALLOC, 317 "%s: can't push snaplen on buffer stack", __func__); 318 } 319 320 cp = (const u_char *)ip6; 321 advance = sizeof(struct ip6_hdr); 322 total_advance = 0; 323 /* Process extension headers */ 324 found_extension_header = 0; 325 found_jumbo = 0; 326 found_hbh = 0; 327 while (cp < ndo->ndo_snapend && advance > 0) { 328 if (len < (u_int)advance) 329 goto trunc; 330 cp += advance; 331 len -= advance; 332 total_advance += advance; 333 334 if (cp == (const u_char *)(ip6 + 1) && 335 nh != IPPROTO_TCP && nh != IPPROTO_UDP && 336 nh != IPPROTO_DCCP && nh != IPPROTO_SCTP) { 337 ND_PRINT("%s > %s: ", GET_IP6ADDR_STRING(ip6->ip6_src), 338 GET_IP6ADDR_STRING(ip6->ip6_dst)); 339 } 340 341 switch (nh) { 342 343 case IPPROTO_HOPOPTS: 344 /* 345 * The Hop-by-Hop Options header, when present, 346 * must immediately follow the IPv6 header (RFC 8200) 347 */ 348 if (found_hbh == 1) { 349 ND_PRINT("[The Hop-by-Hop Options header was already found]"); 350 nd_print_invalid(ndo); 351 return; 352 } 353 if (ph != 255) { 354 ND_PRINT("[The Hop-by-Hop Options header don't follow the IPv6 header]"); 355 nd_print_invalid(ndo); 356 return; 357 } 358 advance = hbhopt_process(ndo, cp, &found_jumbo, &payload_len); 359 if (payload_len == 0 && found_jumbo == 0) { 360 ND_PRINT("[No valid Jumbo Payload Hop-by-Hop option found]"); 361 nd_print_invalid(ndo); 362 return; 363 } 364 if (advance < 0) { 365 nd_pop_packet_info(ndo); 366 return; 367 } 368 found_extension_header = 1; 369 found_hbh = 1; 370 nh = GET_U_1(cp); 371 break; 372 373 case IPPROTO_DSTOPTS: 374 advance = dstopt_process(ndo, cp); 375 if (advance < 0) { 376 nd_pop_packet_info(ndo); 377 return; 378 } 379 found_extension_header = 1; 380 nh = GET_U_1(cp); 381 break; 382 383 case IPPROTO_FRAGMENT: 384 advance = frag6_print(ndo, cp, (const u_char *)ip6); 385 if (advance < 0 || ndo->ndo_snapend <= cp + advance) { 386 nd_pop_packet_info(ndo); 387 return; 388 } 389 found_extension_header = 1; 390 nh = GET_U_1(cp); 391 fragmented = 1; 392 break; 393 394 case IPPROTO_MOBILITY_OLD: 395 case IPPROTO_MOBILITY: 396 /* 397 * XXX - we don't use "advance"; RFC 3775 says that 398 * the next header field in a mobility header 399 * should be IPPROTO_NONE, but speaks of 400 * the possibility of a future extension in 401 * which payload can be piggybacked atop a 402 * mobility header. 403 */ 404 advance = mobility_print(ndo, cp, (const u_char *)ip6); 405 if (advance < 0) { 406 nd_pop_packet_info(ndo); 407 return; 408 } 409 found_extension_header = 1; 410 nh = GET_U_1(cp); 411 nd_pop_packet_info(ndo); 412 return; 413 414 case IPPROTO_ROUTING: 415 ND_TCHECK_1(cp); 416 advance = rt6_print(ndo, cp, (const u_char *)ip6); 417 if (advance < 0) { 418 nd_pop_packet_info(ndo); 419 return; 420 } 421 found_extension_header = 1; 422 nh = GET_U_1(cp); 423 break; 424 425 default: 426 /* 427 * Not an extension header; hand off to the 428 * IP protocol demuxer. 429 */ 430 if (found_jumbo) { 431 /* 432 * We saw a Jumbo Payload option. 433 * Set the length to the payload length 434 * plus the IPv6 header length, and 435 * change the snapshot length accordingly. 436 * 437 * But make sure it's not shorter than 438 * the total number of bytes we've 439 * processed so far. 440 */ 441 len = payload_len + sizeof(struct ip6_hdr); 442 if (len < total_advance) 443 goto trunc; 444 if (length < len) 445 ND_PRINT("truncated-ip6 - %u bytes missing!", 446 len - length); 447 nd_change_snaplen(ndo, bp, len); 448 449 /* 450 * Now subtract the length of the IPv6 451 * header plus extension headers to get 452 * the payload length. 453 */ 454 len -= total_advance; 455 } else { 456 /* 457 * We didn't see a Jumbo Payload option; 458 * was the payload length zero? 459 */ 460 if (payload_len == 0) { 461 /* 462 * Yes. If we found an extension 463 * header, treat that as a truncated 464 * packet header, as there was 465 * no payload to contain an 466 * extension header. 467 */ 468 if (found_extension_header) 469 goto trunc; 470 471 /* 472 * OK, we didn't see any extension 473 * header, but that means we have 474 * no payload, so set the length 475 * to the IPv6 header length, 476 * and change the snapshot length 477 * accordingly. 478 */ 479 len = sizeof(struct ip6_hdr); 480 nd_change_snaplen(ndo, bp, len); 481 482 /* 483 * Now subtract the length of 484 * the IPv6 header plus extension 485 * headers (there weren't any, so 486 * that's just the IPv6 header 487 * length) to get the payload length. 488 */ 489 len -= total_advance; 490 } 491 } 492 ip_demux_print(ndo, cp, len, 6, fragmented, 493 GET_U_1(ip6->ip6_hlim), nh, bp); 494 nd_pop_packet_info(ndo); 495 return; 496 } 497 ph = nh; 498 499 /* ndo_protocol reassignment after xxx_print() calls */ 500 ndo->ndo_protocol = "ip6"; 501 } 502 503 nd_pop_packet_info(ndo); 504 return; 505trunc: 506 nd_print_trunc(ndo); 507} 508