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