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