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