156893Sfenner/* 256893Sfenner * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994 356893Sfenner * The Regents of the University of California. All rights reserved. 456893Sfenner * 556893Sfenner * Redistribution and use in source and binary forms, with or without 656893Sfenner * modification, are permitted provided that: (1) source code distributions 756893Sfenner * retain the above copyright notice and this paragraph in its entirety, (2) 856893Sfenner * distributions including binary code include the above copyright notice and 956893Sfenner * this paragraph in its entirety in the documentation or other materials 1056893Sfenner * provided with the distribution, and (3) all advertising materials mentioning 1156893Sfenner * features or use of this software display the following acknowledgement: 1256893Sfenner * ``This product includes software developed by the University of California, 1356893Sfenner * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 1456893Sfenner * the University nor the names of its contributors may be used to endorse 1556893Sfenner * or promote products derived from this software without specific prior 1656893Sfenner * written permission. 1756893Sfenner * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 1856893Sfenner * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 1956893Sfenner * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 2056893Sfenner */ 2156893Sfenner 22313537Sglebius/* \summary: IPv6 printer */ 23313537Sglebius 2456893Sfenner#ifdef HAVE_CONFIG_H 2556893Sfenner#include "config.h" 2656893Sfenner#endif 2756893Sfenner 28313537Sglebius#include <netdissect-stdinc.h> 2956893Sfenner 3075118Sfenner#include <string.h> 3156893Sfenner 32313537Sglebius#include "netdissect.h" 3356893Sfenner#include "addrtoname.h" 34127675Sbms#include "extract.h" 3556893Sfenner 3675118Sfenner#include "ip6.h" 37127675Sbms#include "ipproto.h" 3856893Sfenner 3956893Sfenner/* 40313537Sglebius * If routing headers are presend and valid, set dst to the final destination. 41313537Sglebius * Otherwise, set it to the IPv6 destination. 42313537Sglebius * 43313537Sglebius * This is used for UDP and TCP pseudo-header in the checksum 44313537Sglebius * calculation. 45313537Sglebius */ 46313537Sglebiusstatic void 47313537Sglebiusip6_finddst(netdissect_options *ndo, struct in6_addr *dst, 48313537Sglebius const struct ip6_hdr *ip6) 49313537Sglebius{ 50313537Sglebius const u_char *cp; 51313537Sglebius int advance; 52313537Sglebius u_int nh; 53313537Sglebius const struct in6_addr *dst_addr; 54313537Sglebius const struct ip6_rthdr *dp; 55313537Sglebius const struct ip6_rthdr0 *dp0; 56313537Sglebius const struct in6_addr *addr; 57313537Sglebius int i, len; 58313537Sglebius 59313537Sglebius cp = (const u_char *)ip6; 60313537Sglebius advance = sizeof(struct ip6_hdr); 61313537Sglebius nh = ip6->ip6_nxt; 62313537Sglebius dst_addr = &ip6->ip6_dst; 63313537Sglebius 64313537Sglebius while (cp < ndo->ndo_snapend) { 65313537Sglebius cp += advance; 66313537Sglebius 67313537Sglebius switch (nh) { 68313537Sglebius 69313537Sglebius case IPPROTO_HOPOPTS: 70313537Sglebius case IPPROTO_DSTOPTS: 71313537Sglebius case IPPROTO_MOBILITY_OLD: 72313537Sglebius case IPPROTO_MOBILITY: 73313537Sglebius /* 74313537Sglebius * These have a header length byte, following 75313537Sglebius * the next header byte, giving the length of 76313537Sglebius * the header, in units of 8 octets, excluding 77313537Sglebius * the first 8 octets. 78313537Sglebius */ 79313537Sglebius ND_TCHECK2(*cp, 2); 80313537Sglebius advance = (int)((*(cp + 1) + 1) << 3); 81313537Sglebius nh = *cp; 82313537Sglebius break; 83313537Sglebius 84313537Sglebius case IPPROTO_FRAGMENT: 85313537Sglebius /* 86313537Sglebius * The byte following the next header byte is 87313537Sglebius * marked as reserved, and the header is always 88313537Sglebius * the same size. 89313537Sglebius */ 90313537Sglebius ND_TCHECK2(*cp, 1); 91313537Sglebius advance = sizeof(struct ip6_frag); 92313537Sglebius nh = *cp; 93313537Sglebius break; 94313537Sglebius 95313537Sglebius case IPPROTO_ROUTING: 96313537Sglebius /* 97313537Sglebius * OK, we found it. 98313537Sglebius */ 99313537Sglebius dp = (const struct ip6_rthdr *)cp; 100313537Sglebius ND_TCHECK(*dp); 101313537Sglebius len = dp->ip6r_len; 102313537Sglebius switch (dp->ip6r_type) { 103313537Sglebius 104313537Sglebius case IPV6_RTHDR_TYPE_0: 105313537Sglebius case IPV6_RTHDR_TYPE_2: /* Mobile IPv6 ID-20 */ 106313537Sglebius dp0 = (const struct ip6_rthdr0 *)dp; 107313537Sglebius if (len % 2 == 1) 108313537Sglebius goto trunc; 109313537Sglebius len >>= 1; 110313537Sglebius addr = &dp0->ip6r0_addr[0]; 111313537Sglebius for (i = 0; i < len; i++) { 112313537Sglebius if ((const u_char *)(addr + 1) > ndo->ndo_snapend) 113313537Sglebius goto trunc; 114313537Sglebius 115313537Sglebius dst_addr = addr; 116313537Sglebius addr++; 117313537Sglebius } 118313537Sglebius break; 119313537Sglebius 120313537Sglebius default: 121313537Sglebius break; 122313537Sglebius } 123313537Sglebius 124313537Sglebius /* 125313537Sglebius * Only one routing header to a customer. 126313537Sglebius */ 127313537Sglebius goto done; 128313537Sglebius 129313537Sglebius case IPPROTO_AH: 130313537Sglebius case IPPROTO_ESP: 131313537Sglebius case IPPROTO_IPCOMP: 132313537Sglebius default: 133313537Sglebius /* 134313537Sglebius * AH and ESP are, in the RFCs that describe them, 135313537Sglebius * described as being "viewed as an end-to-end 136313537Sglebius * payload" "in the IPv6 context, so that they 137313537Sglebius * "should appear after hop-by-hop, routing, and 138313537Sglebius * fragmentation extension headers". We assume 139313537Sglebius * that's the case, and stop as soon as we see 140313537Sglebius * one. (We can't handle an ESP header in 141313537Sglebius * the general case anyway, as its length depends 142313537Sglebius * on the encryption algorithm.) 143313537Sglebius * 144313537Sglebius * IPComp is also "viewed as an end-to-end 145313537Sglebius * payload" "in the IPv6 context". 146313537Sglebius * 147313537Sglebius * All other protocols are assumed to be the final 148313537Sglebius * protocol. 149313537Sglebius */ 150313537Sglebius goto done; 151313537Sglebius } 152313537Sglebius } 153313537Sglebius 154313537Sglebiusdone: 155313537Sglebiustrunc: 156313537Sglebius UNALIGNED_MEMCPY(dst, dst_addr, sizeof(struct in6_addr)); 157313537Sglebius} 158313537Sglebius 159313537Sglebius/* 160214478Srpaulo * Compute a V6-style checksum by building a pseudoheader. 161214478Srpaulo */ 162214478Srpauloint 163313537Sglebiusnextproto6_cksum(netdissect_options *ndo, 164313537Sglebius const struct ip6_hdr *ip6, const uint8_t *data, 165276788Sdelphij u_int len, u_int covlen, u_int next_proto) 166214478Srpaulo{ 167235530Sdelphij struct { 168235530Sdelphij struct in6_addr ph_src; 169235530Sdelphij struct in6_addr ph_dst; 170276788Sdelphij uint32_t ph_len; 171276788Sdelphij uint8_t ph_zero[3]; 172276788Sdelphij uint8_t ph_nxt; 173235530Sdelphij } ph; 174235530Sdelphij struct cksum_vec vec[2]; 175214478Srpaulo 176214478Srpaulo /* pseudo-header */ 177235530Sdelphij memset(&ph, 0, sizeof(ph)); 178276788Sdelphij UNALIGNED_MEMCPY(&ph.ph_src, &ip6->ip6_src, sizeof (struct in6_addr)); 179313537Sglebius switch (ip6->ip6_nxt) { 180313537Sglebius 181313537Sglebius case IPPROTO_HOPOPTS: 182313537Sglebius case IPPROTO_DSTOPTS: 183313537Sglebius case IPPROTO_MOBILITY_OLD: 184313537Sglebius case IPPROTO_MOBILITY: 185313537Sglebius case IPPROTO_FRAGMENT: 186313537Sglebius case IPPROTO_ROUTING: 187313537Sglebius /* 188313537Sglebius * The next header is either a routing header or a header 189313537Sglebius * after which there might be a routing header, so scan 190313537Sglebius * for a routing header. 191313537Sglebius */ 192313537Sglebius ip6_finddst(ndo, &ph.ph_dst, ip6); 193313537Sglebius break; 194313537Sglebius 195313537Sglebius default: 196313537Sglebius UNALIGNED_MEMCPY(&ph.ph_dst, &ip6->ip6_dst, sizeof (struct in6_addr)); 197313537Sglebius break; 198313537Sglebius } 199235530Sdelphij ph.ph_len = htonl(len); 200235530Sdelphij ph.ph_nxt = next_proto; 201214478Srpaulo 202276788Sdelphij vec[0].ptr = (const uint8_t *)(void *)&ph; 203235530Sdelphij vec[0].len = sizeof(ph); 204235530Sdelphij vec[1].ptr = data; 205276788Sdelphij vec[1].len = covlen; 206214478Srpaulo 207235530Sdelphij return in_cksum(vec, 2); 208214478Srpaulo} 209214478Srpaulo 210214478Srpaulo/* 21156893Sfenner * print an IP6 datagram. 21256893Sfenner */ 21356893Sfennervoid 214235530Sdelphijip6_print(netdissect_options *ndo, const u_char *bp, u_int length) 21556893Sfenner{ 21656893Sfenner register const struct ip6_hdr *ip6; 21775118Sfenner register int advance; 218127675Sbms u_int len; 219127675Sbms const u_char *ipend; 22056893Sfenner register const u_char *cp; 221127675Sbms register u_int payload_len; 22256893Sfenner int nh; 22375118Sfenner int fragmented = 0; 22456893Sfenner u_int flow; 225127675Sbms 22656893Sfenner ip6 = (const struct ip6_hdr *)bp; 22756893Sfenner 228276788Sdelphij ND_TCHECK(*ip6); 22956893Sfenner if (length < sizeof (struct ip6_hdr)) { 230276788Sdelphij ND_PRINT((ndo, "truncated-ip6 %u", length)); 23156893Sfenner return; 23256893Sfenner } 23356893Sfenner 234235530Sdelphij if (!ndo->ndo_eflag) 235235530Sdelphij ND_PRINT((ndo, "IP6 ")); 236146778Ssam 237276788Sdelphij if (IP6_VERSION(ip6) != 6) { 238276788Sdelphij ND_PRINT((ndo,"version error: %u != 6", IP6_VERSION(ip6))); 239276788Sdelphij return; 240276788Sdelphij } 241276788Sdelphij 242127675Sbms payload_len = EXTRACT_16BITS(&ip6->ip6_plen); 243127675Sbms len = payload_len + sizeof(struct ip6_hdr); 244127675Sbms if (length < len) 245276788Sdelphij ND_PRINT((ndo, "truncated-ip6 - %u bytes missing!", 246235530Sdelphij len - length)); 24756893Sfenner 248235530Sdelphij if (ndo->ndo_vflag) { 249146778Ssam flow = EXTRACT_32BITS(&ip6->ip6_flow); 250235530Sdelphij ND_PRINT((ndo, "(")); 251146778Ssam#if 0 252146778Ssam /* rfc1883 */ 253146778Ssam if (flow & 0x0f000000) 254276788Sdelphij ND_PRINT((ndo, "pri 0x%02x, ", (flow & 0x0f000000) >> 24)); 255146778Ssam if (flow & 0x00ffffff) 256276788Sdelphij ND_PRINT((ndo, "flowlabel 0x%06x, ", flow & 0x00ffffff)); 257146778Ssam#else 258146778Ssam /* RFC 2460 */ 259146778Ssam if (flow & 0x0ff00000) 260276788Sdelphij ND_PRINT((ndo, "class 0x%02x, ", (flow & 0x0ff00000) >> 20)); 261146778Ssam if (flow & 0x000fffff) 262276788Sdelphij ND_PRINT((ndo, "flowlabel 0x%05x, ", flow & 0x000fffff)); 263146778Ssam#endif 264146778Ssam 265276788Sdelphij ND_PRINT((ndo, "hlim %u, next-header %s (%u) payload length: %u) ", 266146778Ssam ip6->ip6_hlim, 267146778Ssam tok2str(ipproto_values,"unknown",ip6->ip6_nxt), 268146778Ssam ip6->ip6_nxt, 269235530Sdelphij payload_len)); 270146778Ssam } 271146778Ssam 272127675Sbms /* 273127675Sbms * Cut off the snapshot length to the end of the IP payload. 274127675Sbms */ 275127675Sbms ipend = bp + len; 276235530Sdelphij if (ipend < ndo->ndo_snapend) 277235530Sdelphij ndo->ndo_snapend = ipend; 278127675Sbms 27956893Sfenner cp = (const u_char *)ip6; 280127675Sbms advance = sizeof(struct ip6_hdr); 28156893Sfenner nh = ip6->ip6_nxt; 282235530Sdelphij while (cp < ndo->ndo_snapend && advance > 0) { 283327234Semaste if (len < (u_int)advance) 284327234Semaste goto trunc; 28575118Sfenner cp += advance; 286127675Sbms len -= advance; 28756893Sfenner 288127675Sbms if (cp == (const u_char *)(ip6 + 1) && 289127675Sbms nh != IPPROTO_TCP && nh != IPPROTO_UDP && 290162021Ssam nh != IPPROTO_DCCP && nh != IPPROTO_SCTP) { 291276788Sdelphij ND_PRINT((ndo, "%s > %s: ", ip6addr_string(ndo, &ip6->ip6_src), 292276788Sdelphij ip6addr_string(ndo, &ip6->ip6_dst))); 29356893Sfenner } 29456893Sfenner 29556893Sfenner switch (nh) { 29656893Sfenner case IPPROTO_HOPOPTS: 297276788Sdelphij advance = hbhopt_print(ndo, cp); 298313537Sglebius if (advance < 0) 299313537Sglebius return; 30056893Sfenner nh = *cp; 30156893Sfenner break; 30256893Sfenner case IPPROTO_DSTOPTS: 303276788Sdelphij advance = dstopt_print(ndo, cp); 304313537Sglebius if (advance < 0) 305313537Sglebius return; 30656893Sfenner nh = *cp; 30756893Sfenner break; 30856893Sfenner case IPPROTO_FRAGMENT: 309276788Sdelphij advance = frag6_print(ndo, cp, (const u_char *)ip6); 310313537Sglebius if (advance < 0 || ndo->ndo_snapend <= cp + advance) 311146778Ssam return; 31256893Sfenner nh = *cp; 31375118Sfenner fragmented = 1; 31456893Sfenner break; 315127675Sbms 316127675Sbms case IPPROTO_MOBILITY_OLD: 317127675Sbms case IPPROTO_MOBILITY: 318127675Sbms /* 319313537Sglebius * XXX - we don't use "advance"; RFC 3775 says that 320127675Sbms * the next header field in a mobility header 321127675Sbms * should be IPPROTO_NONE, but speaks of 322127675Sbms * the possiblity of a future extension in 323127675Sbms * which payload can be piggybacked atop a 324127675Sbms * mobility header. 325127675Sbms */ 326276788Sdelphij advance = mobility_print(ndo, cp, (const u_char *)ip6); 327327234Semaste if (advance < 0) 328327234Semaste return; 329127675Sbms nh = *cp; 330146778Ssam return; 33156893Sfenner case IPPROTO_ROUTING: 332327234Semaste ND_TCHECK(*cp); 333276788Sdelphij advance = rt6_print(ndo, cp, (const u_char *)ip6); 334327234Semaste if (advance < 0) 335327234Semaste return; 33656893Sfenner nh = *cp; 33756893Sfenner break; 338127675Sbms case IPPROTO_SCTP: 339276788Sdelphij sctp_print(ndo, cp, (const u_char *)ip6, len); 340146778Ssam return; 341162021Ssam case IPPROTO_DCCP: 342276788Sdelphij dccp_print(ndo, cp, (const u_char *)ip6, len); 343162021Ssam return; 34456893Sfenner case IPPROTO_TCP: 345276788Sdelphij tcp_print(ndo, cp, len, (const u_char *)ip6, fragmented); 346146778Ssam return; 34756893Sfenner case IPPROTO_UDP: 348276788Sdelphij udp_print(ndo, cp, len, (const u_char *)ip6, fragmented); 349146778Ssam return; 35056893Sfenner case IPPROTO_ICMPV6: 351235530Sdelphij icmp6_print(ndo, cp, len, (const u_char *)ip6, fragmented); 352146778Ssam return; 35356893Sfenner case IPPROTO_AH: 354276788Sdelphij advance = ah_print(ndo, cp); 355327234Semaste if (advance < 0) 356327234Semaste return; 35756893Sfenner nh = *cp; 35856893Sfenner break; 35956893Sfenner case IPPROTO_ESP: 36056893Sfenner { 36198527Sfenner int enh, padlen; 362235530Sdelphij advance = esp_print(ndo, cp, len, (const u_char *)ip6, &enh, &padlen); 363327234Semaste if (advance < 0) 364327234Semaste return; 36556893Sfenner nh = enh & 0xff; 36698527Sfenner len -= padlen; 36756893Sfenner break; 36856893Sfenner } 36956893Sfenner case IPPROTO_IPCOMP: 37056893Sfenner { 371313537Sglebius ipcomp_print(ndo, cp); 372313537Sglebius /* 373313537Sglebius * Either this has decompressed the payload and 374313537Sglebius * printed it, in which case there's nothing more 375313537Sglebius * to do, or it hasn't, in which case there's 376313537Sglebius * nothing more to do. 377313537Sglebius */ 378313537Sglebius advance = -1; 37956893Sfenner break; 38056893Sfenner } 38175118Sfenner 38256893Sfenner case IPPROTO_PIM: 383313537Sglebius pim_print(ndo, cp, len, (const u_char *)ip6); 384146778Ssam return; 385147904Ssam 38656893Sfenner case IPPROTO_OSPF: 387276788Sdelphij ospf6_print(ndo, cp, len); 388146778Ssam return; 389127675Sbms 39056893Sfenner case IPPROTO_IPV6: 391235530Sdelphij ip6_print(ndo, cp, len); 392146778Ssam return; 393127675Sbms 39456893Sfenner case IPPROTO_IPV4: 395235530Sdelphij ip_print(ndo, cp, len); 396146778Ssam return; 397127675Sbms 398147904Ssam case IPPROTO_PGM: 399276788Sdelphij pgm_print(ndo, cp, len, (const u_char *)ip6); 400147904Ssam return; 401147904Ssam 402147904Ssam case IPPROTO_GRE: 403276788Sdelphij gre_print(ndo, cp, len); 404147904Ssam return; 405147904Ssam 406147904Ssam case IPPROTO_RSVP: 407276788Sdelphij rsvp_print(ndo, cp, len); 408147904Ssam return; 409147904Ssam 41056893Sfenner case IPPROTO_NONE: 411276788Sdelphij ND_PRINT((ndo, "no next header")); 412146778Ssam return; 41356893Sfenner 41456893Sfenner default: 415276788Sdelphij ND_PRINT((ndo, "ip-proto-%d %d", nh, len)); 416146778Ssam return; 41756893Sfenner } 41856893Sfenner } 41956893Sfenner 42098527Sfenner return; 42198527Sfennertrunc: 422276788Sdelphij ND_PRINT((ndo, "[|ip6]")); 42356893Sfenner} 424