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#define NETDISSECT_REWORKED 23#ifdef HAVE_CONFIG_H 24#include "config.h" 25#endif 26 27#include <tcpdump-stdinc.h> 28 29#include <string.h> 30 31#include "interface.h" 32#include "addrtoname.h" 33#include "extract.h" 34 35#ifdef INET6 36 37#include "ip6.h" 38#include "ipproto.h" 39 40/* 41 * Compute a V6-style checksum by building a pseudoheader. 42 */ 43int 44nextproto6_cksum(const struct ip6_hdr *ip6, const uint8_t *data, 45 u_int len, u_int covlen, u_int next_proto) 46{ 47 struct { 48 struct in6_addr ph_src; 49 struct in6_addr ph_dst; 50 uint32_t ph_len; 51 uint8_t ph_zero[3]; 52 uint8_t ph_nxt; 53 } ph; 54 struct cksum_vec vec[2]; 55 56 /* pseudo-header */ 57 memset(&ph, 0, sizeof(ph)); 58 UNALIGNED_MEMCPY(&ph.ph_src, &ip6->ip6_src, sizeof (struct in6_addr)); 59 UNALIGNED_MEMCPY(&ph.ph_dst, &ip6->ip6_dst, sizeof (struct in6_addr)); 60 ph.ph_len = htonl(len); 61 ph.ph_nxt = next_proto; 62 63 vec[0].ptr = (const uint8_t *)(void *)&ph; 64 vec[0].len = sizeof(ph); 65 vec[1].ptr = data; 66 vec[1].len = covlen; 67 68 return in_cksum(vec, 2); 69} 70 71/* 72 * print an IP6 datagram. 73 */ 74void 75ip6_print(netdissect_options *ndo, const u_char *bp, u_int length) 76{ 77 register const struct ip6_hdr *ip6; 78 register int advance; 79 u_int len; 80 const u_char *ipend; 81 register const u_char *cp; 82 register u_int payload_len; 83 int nh; 84 int fragmented = 0; 85 u_int flow; 86 87 ip6 = (const struct ip6_hdr *)bp; 88 89 ND_TCHECK(*ip6); 90 if (length < sizeof (struct ip6_hdr)) { 91 ND_PRINT((ndo, "truncated-ip6 %u", length)); 92 return; 93 } 94 95 if (!ndo->ndo_eflag) 96 ND_PRINT((ndo, "IP6 ")); 97 98 if (IP6_VERSION(ip6) != 6) { 99 ND_PRINT((ndo,"version error: %u != 6", IP6_VERSION(ip6))); 100 return; 101 } 102 103 payload_len = EXTRACT_16BITS(&ip6->ip6_plen); 104 len = payload_len + sizeof(struct ip6_hdr); 105 if (length < len) 106 ND_PRINT((ndo, "truncated-ip6 - %u bytes missing!", 107 len - length)); 108 109 if (ndo->ndo_vflag) { 110 flow = EXTRACT_32BITS(&ip6->ip6_flow); 111 ND_PRINT((ndo, "(")); 112#if 0 113 /* rfc1883 */ 114 if (flow & 0x0f000000) 115 ND_PRINT((ndo, "pri 0x%02x, ", (flow & 0x0f000000) >> 24)); 116 if (flow & 0x00ffffff) 117 ND_PRINT((ndo, "flowlabel 0x%06x, ", flow & 0x00ffffff)); 118#else 119 /* RFC 2460 */ 120 if (flow & 0x0ff00000) 121 ND_PRINT((ndo, "class 0x%02x, ", (flow & 0x0ff00000) >> 20)); 122 if (flow & 0x000fffff) 123 ND_PRINT((ndo, "flowlabel 0x%05x, ", flow & 0x000fffff)); 124#endif 125 126 ND_PRINT((ndo, "hlim %u, next-header %s (%u) payload length: %u) ", 127 ip6->ip6_hlim, 128 tok2str(ipproto_values,"unknown",ip6->ip6_nxt), 129 ip6->ip6_nxt, 130 payload_len)); 131 } 132 133 /* 134 * Cut off the snapshot length to the end of the IP payload. 135 */ 136 ipend = bp + len; 137 if (ipend < ndo->ndo_snapend) 138 ndo->ndo_snapend = ipend; 139 140 cp = (const u_char *)ip6; 141 advance = sizeof(struct ip6_hdr); 142 nh = ip6->ip6_nxt; 143 while (cp < ndo->ndo_snapend && advance > 0) { 144 cp += advance; 145 len -= advance; 146 147 if (cp == (const u_char *)(ip6 + 1) && 148 nh != IPPROTO_TCP && nh != IPPROTO_UDP && 149 nh != IPPROTO_DCCP && nh != IPPROTO_SCTP) { 150 ND_PRINT((ndo, "%s > %s: ", ip6addr_string(ndo, &ip6->ip6_src), 151 ip6addr_string(ndo, &ip6->ip6_dst))); 152 } 153 154 switch (nh) { 155 case IPPROTO_HOPOPTS: 156 advance = hbhopt_print(ndo, cp); 157 nh = *cp; 158 break; 159 case IPPROTO_DSTOPTS: 160 advance = dstopt_print(ndo, cp); 161 nh = *cp; 162 break; 163 case IPPROTO_FRAGMENT: 164 advance = frag6_print(ndo, cp, (const u_char *)ip6); 165 if (ndo->ndo_snapend <= cp + advance) 166 return; 167 nh = *cp; 168 fragmented = 1; 169 break; 170 171 case IPPROTO_MOBILITY_OLD: 172 case IPPROTO_MOBILITY: 173 /* 174 * XXX - we don't use "advance"; the current 175 * "Mobility Support in IPv6" draft 176 * (draft-ietf-mobileip-ipv6-24) says that 177 * the next header field in a mobility header 178 * should be IPPROTO_NONE, but speaks of 179 * the possiblity of a future extension in 180 * which payload can be piggybacked atop a 181 * mobility header. 182 */ 183 advance = mobility_print(ndo, cp, (const u_char *)ip6); 184 nh = *cp; 185 return; 186 case IPPROTO_ROUTING: 187 advance = rt6_print(ndo, cp, (const u_char *)ip6); 188 nh = *cp; 189 break; 190 case IPPROTO_SCTP: 191 sctp_print(ndo, cp, (const u_char *)ip6, len); 192 return; 193 case IPPROTO_DCCP: 194 dccp_print(ndo, cp, (const u_char *)ip6, len); 195 return; 196 case IPPROTO_TCP: 197 tcp_print(ndo, cp, len, (const u_char *)ip6, fragmented); 198 return; 199 case IPPROTO_UDP: 200 udp_print(ndo, cp, len, (const u_char *)ip6, fragmented); 201 return; 202 case IPPROTO_ICMPV6: 203 icmp6_print(ndo, cp, len, (const u_char *)ip6, fragmented); 204 return; 205 case IPPROTO_AH: 206 advance = ah_print(ndo, cp); 207 nh = *cp; 208 break; 209 case IPPROTO_ESP: 210 { 211 int enh, padlen; 212 advance = esp_print(ndo, cp, len, (const u_char *)ip6, &enh, &padlen); 213 nh = enh & 0xff; 214 len -= padlen; 215 break; 216 } 217 case IPPROTO_IPCOMP: 218 { 219 int enh; 220 advance = ipcomp_print(ndo, cp, &enh); 221 nh = enh & 0xff; 222 break; 223 } 224 225 case IPPROTO_PIM: 226 pim_print(ndo, cp, len, nextproto6_cksum(ip6, cp, len, len, 227 IPPROTO_PIM)); 228 return; 229 230 case IPPROTO_OSPF: 231 ospf6_print(ndo, cp, len); 232 return; 233 234 case IPPROTO_IPV6: 235 ip6_print(ndo, cp, len); 236 return; 237 238 case IPPROTO_IPV4: 239 ip_print(ndo, cp, len); 240 return; 241 242 case IPPROTO_PGM: 243 pgm_print(ndo, cp, len, (const u_char *)ip6); 244 return; 245 246 case IPPROTO_GRE: 247 gre_print(ndo, cp, len); 248 return; 249 250 case IPPROTO_RSVP: 251 rsvp_print(ndo, cp, len); 252 return; 253 254 case IPPROTO_NONE: 255 ND_PRINT((ndo, "no next header")); 256 return; 257 258 default: 259 ND_PRINT((ndo, "ip-proto-%d %d", nh, len)); 260 return; 261 } 262 } 263 264 return; 265trunc: 266 ND_PRINT((ndo, "[|ip6]")); 267} 268 269#else /* INET6 */ 270 271void 272ip6_print(netdissect_options *ndo, const u_char *bp _U_, u_int length) 273{ 274 ND_PRINT((ndo, "IP6, length: %u (printing not supported)", length)); 275} 276 277#endif /* INET6 */ 278