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