print-ip6.c revision 1.6
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.6 2017/01/24 23:29:14 christos Exp $"); 25#endif 26 27#ifdef HAVE_CONFIG_H 28#include "config.h" 29#endif 30 31#include <netdissect-stdinc.h> 32 33#include <string.h> 34 35#include "netdissect.h" 36#include "addrtoname.h" 37#include "extract.h" 38 39#include "ip6.h" 40#include "ipproto.h" 41 42/* 43 * If routing headers are presend and valid, set dst to the final destination. 44 * Otherwise, set it to the IPv6 destination. 45 * 46 * This is used for UDP and TCP pseudo-header in the checksum 47 * calculation. 48 */ 49static void 50ip6_finddst(netdissect_options *ndo, struct in6_addr *dst, 51 const struct ip6_hdr *ip6) 52{ 53 const u_char *cp; 54 int advance; 55 u_int nh; 56 const struct in6_addr *dst_addr; 57 const struct ip6_rthdr *dp; 58 const struct ip6_rthdr0 *dp0; 59 const struct in6_addr *addr; 60 int i, len; 61 62 cp = (const u_char *)ip6; 63 advance = sizeof(struct ip6_hdr); 64 nh = ip6->ip6_nxt; 65 dst_addr = &ip6->ip6_dst; 66 67 while (cp < ndo->ndo_snapend) { 68 cp += advance; 69 70 switch (nh) { 71 72 case IPPROTO_HOPOPTS: 73 case IPPROTO_DSTOPTS: 74 case IPPROTO_MOBILITY_OLD: 75 case IPPROTO_MOBILITY: 76 /* 77 * These have a header length byte, following 78 * the next header byte, giving the length of 79 * the header, in units of 8 octets, excluding 80 * the first 8 octets. 81 */ 82 ND_TCHECK2(*cp, 2); 83 advance = (int)((*(cp + 1) + 1) << 3); 84 nh = *cp; 85 break; 86 87 case IPPROTO_FRAGMENT: 88 /* 89 * The byte following the next header byte is 90 * marked as reserved, and the header is always 91 * the same size. 92 */ 93 ND_TCHECK2(*cp, 1); 94 advance = sizeof(struct ip6_frag); 95 nh = *cp; 96 break; 97 98 case IPPROTO_ROUTING: 99 /* 100 * OK, we found it. 101 */ 102 dp = (const struct ip6_rthdr *)cp; 103 ND_TCHECK(*dp); 104 len = dp->ip6r_len; 105 switch (dp->ip6r_type) { 106 107 case IPV6_RTHDR_TYPE_0: 108 case IPV6_RTHDR_TYPE_2: /* Mobile IPv6 ID-20 */ 109 dp0 = (const struct ip6_rthdr0 *)dp; 110 if (len % 2 == 1) 111 goto trunc; 112 len >>= 1; 113 addr = &dp0->ip6r0_addr[0]; 114 for (i = 0; i < len; i++) { 115 if ((const u_char *)(addr + 1) > ndo->ndo_snapend) 116 goto trunc; 117 118 dst_addr = addr; 119 addr++; 120 } 121 break; 122 123 default: 124 break; 125 } 126 127 /* 128 * Only one routing header to a customer. 129 */ 130 goto done; 131 132 case IPPROTO_AH: 133 case IPPROTO_ESP: 134 case IPPROTO_IPCOMP: 135 default: 136 /* 137 * AH and ESP are, in the RFCs that describe them, 138 * described as being "viewed as an end-to-end 139 * payload" "in the IPv6 context, so that they 140 * "should appear after hop-by-hop, routing, and 141 * fragmentation extension headers". We assume 142 * that's the case, and stop as soon as we see 143 * one. (We can't handle an ESP header in 144 * the general case anyway, as its length depends 145 * on the encryption algorithm.) 146 * 147 * IPComp is also "viewed as an end-to-end 148 * payload" "in the IPv6 context". 149 * 150 * All other protocols are assumed to be the final 151 * protocol. 152 */ 153 goto done; 154 } 155 } 156 157done: 158trunc: 159 UNALIGNED_MEMCPY(dst, dst_addr, sizeof(struct in6_addr)); 160} 161 162/* 163 * Compute a V6-style checksum by building a pseudoheader. 164 */ 165int 166nextproto6_cksum(netdissect_options *ndo, 167 const struct ip6_hdr *ip6, const uint8_t *data, 168 u_int len, u_int covlen, u_int next_proto) 169{ 170 struct { 171 struct in6_addr ph_src; 172 struct in6_addr ph_dst; 173 uint32_t ph_len; 174 uint8_t ph_zero[3]; 175 uint8_t ph_nxt; 176 } ph; 177 struct cksum_vec vec[2]; 178 179 /* pseudo-header */ 180 memset(&ph, 0, sizeof(ph)); 181 UNALIGNED_MEMCPY(&ph.ph_src, &ip6->ip6_src, sizeof (struct in6_addr)); 182 switch (ip6->ip6_nxt) { 183 184 case IPPROTO_HOPOPTS: 185 case IPPROTO_DSTOPTS: 186 case IPPROTO_MOBILITY_OLD: 187 case IPPROTO_MOBILITY: 188 case IPPROTO_FRAGMENT: 189 case IPPROTO_ROUTING: 190 /* 191 * The next header is either a routing header or a header 192 * after which there might be a routing header, so scan 193 * for a routing header. 194 */ 195 ip6_finddst(ndo, &ph.ph_dst, ip6); 196 break; 197 198 default: 199 UNALIGNED_MEMCPY(&ph.ph_dst, &ip6->ip6_dst, sizeof (struct in6_addr)); 200 break; 201 } 202 ph.ph_len = htonl(len); 203 ph.ph_nxt = next_proto; 204 205 vec[0].ptr = (const uint8_t *)(void *)&ph; 206 vec[0].len = sizeof(ph); 207 vec[1].ptr = data; 208 vec[1].len = covlen; 209 210 return in_cksum(vec, 2); 211} 212 213/* 214 * print an IP6 datagram. 215 */ 216void 217ip6_print(netdissect_options *ndo, const u_char *bp, u_int length) 218{ 219 register const struct ip6_hdr *ip6; 220 register int advance; 221 u_int len; 222 const u_char *ipend; 223 register const u_char *cp; 224 register u_int payload_len; 225 int nh; 226 int fragmented = 0; 227 u_int flow; 228 229 ip6 = (const struct ip6_hdr *)bp; 230 231 ND_TCHECK(*ip6); 232 if (length < sizeof (struct ip6_hdr)) { 233 ND_PRINT((ndo, "truncated-ip6 %u", length)); 234 return; 235 } 236 237 if (!ndo->ndo_eflag) 238 ND_PRINT((ndo, "IP6 ")); 239 240 if (IP6_VERSION(ip6) != 6) { 241 ND_PRINT((ndo,"version error: %u != 6", IP6_VERSION(ip6))); 242 return; 243 } 244 245 payload_len = EXTRACT_16BITS(&ip6->ip6_plen); 246 len = payload_len + sizeof(struct ip6_hdr); 247 if (length < len) 248 ND_PRINT((ndo, "truncated-ip6 - %u bytes missing!", 249 len - length)); 250 251 if (ndo->ndo_vflag) { 252 flow = EXTRACT_32BITS(&ip6->ip6_flow); 253 ND_PRINT((ndo, "(")); 254#if 0 255 /* rfc1883 */ 256 if (flow & 0x0f000000) 257 ND_PRINT((ndo, "pri 0x%02x, ", (flow & 0x0f000000) >> 24)); 258 if (flow & 0x00ffffff) 259 ND_PRINT((ndo, "flowlabel 0x%06x, ", flow & 0x00ffffff)); 260#else 261 /* RFC 2460 */ 262 if (flow & 0x0ff00000) 263 ND_PRINT((ndo, "class 0x%02x, ", (flow & 0x0ff00000) >> 20)); 264 if (flow & 0x000fffff) 265 ND_PRINT((ndo, "flowlabel 0x%05x, ", flow & 0x000fffff)); 266#endif 267 268 ND_PRINT((ndo, "hlim %u, next-header %s (%u) payload length: %u) ", 269 ip6->ip6_hlim, 270 tok2str(ipproto_values,"unknown",ip6->ip6_nxt), 271 ip6->ip6_nxt, 272 payload_len)); 273 } 274 275 /* 276 * Cut off the snapshot length to the end of the IP payload. 277 */ 278 ipend = bp + len; 279 if (ipend < ndo->ndo_snapend) 280 ndo->ndo_snapend = ipend; 281 282 cp = (const u_char *)ip6; 283 advance = sizeof(struct ip6_hdr); 284 nh = ip6->ip6_nxt; 285 while (cp < ndo->ndo_snapend && advance > 0) { 286 cp += advance; 287 len -= advance; 288 289 if (cp == (const u_char *)(ip6 + 1) && 290 nh != IPPROTO_TCP && nh != IPPROTO_UDP && 291 nh != IPPROTO_DCCP && nh != IPPROTO_SCTP) { 292 ND_PRINT((ndo, "%s > %s: ", ip6addr_string(ndo, &ip6->ip6_src), 293 ip6addr_string(ndo, &ip6->ip6_dst))); 294 } 295 296 switch (nh) { 297 case IPPROTO_HOPOPTS: 298 advance = hbhopt_print(ndo, cp); 299 nh = *cp; 300 break; 301 case IPPROTO_DSTOPTS: 302 advance = dstopt_print(ndo, cp); 303 nh = *cp; 304 break; 305 case IPPROTO_FRAGMENT: 306 advance = frag6_print(ndo, cp, (const u_char *)ip6); 307 if (ndo->ndo_snapend <= cp + advance) 308 return; 309 nh = *cp; 310 fragmented = 1; 311 break; 312 313 case IPPROTO_MOBILITY_OLD: 314 case IPPROTO_MOBILITY: 315 /* 316 * XXX - we don't use "advance"; RFC 3775 says that 317 * the next header field in a mobility header 318 * should be IPPROTO_NONE, but speaks of 319 * the possiblity of a future extension in 320 * which payload can be piggybacked atop a 321 * mobility header. 322 */ 323 advance = mobility_print(ndo, cp, (const u_char *)ip6); 324 nh = *cp; 325 return; 326 case IPPROTO_ROUTING: 327 advance = rt6_print(ndo, cp, (const u_char *)ip6); 328 nh = *cp; 329 break; 330 case IPPROTO_SCTP: 331 sctp_print(ndo, cp, (const u_char *)ip6, len); 332 return; 333 case IPPROTO_DCCP: 334 dccp_print(ndo, cp, (const u_char *)ip6, len); 335 return; 336 case IPPROTO_TCP: 337 tcp_print(ndo, cp, len, (const u_char *)ip6, fragmented); 338 return; 339 case IPPROTO_UDP: 340 udp_print(ndo, cp, len, (const u_char *)ip6, fragmented); 341 return; 342 case IPPROTO_ICMPV6: 343 icmp6_print(ndo, cp, len, (const u_char *)ip6, fragmented); 344 return; 345 case IPPROTO_AH: 346 advance = ah_print(ndo, cp); 347 nh = *cp; 348 break; 349 case IPPROTO_ESP: 350 { 351 int enh, padlen; 352 advance = esp_print(ndo, cp, len, (const u_char *)ip6, &enh, &padlen); 353 nh = enh & 0xff; 354 len -= padlen; 355 break; 356 } 357 case IPPROTO_IPCOMP: 358 { 359 int enh; 360 advance = ipcomp_print(ndo, cp, &enh); 361 nh = enh & 0xff; 362 break; 363 } 364 365 case IPPROTO_PIM: 366 pim_print(ndo, cp, len, (const u_char *)ip6); 367 return; 368 369 case IPPROTO_OSPF: 370 ospf6_print(ndo, cp, len); 371 return; 372 373 case IPPROTO_IPV6: 374 ip6_print(ndo, cp, len); 375 return; 376 377 case IPPROTO_IPV4: 378 ip_print(ndo, cp, len); 379 return; 380 381 case IPPROTO_PGM: 382 pgm_print(ndo, cp, len, (const u_char *)ip6); 383 return; 384 385 case IPPROTO_GRE: 386 gre_print(ndo, cp, len); 387 return; 388 389 case IPPROTO_RSVP: 390 rsvp_print(ndo, cp, len); 391 return; 392 393 case IPPROTO_NONE: 394 ND_PRINT((ndo, "no next header")); 395 return; 396 397 default: 398 ND_PRINT((ndo, "ip-proto-%d %d", nh, len)); 399 return; 400 } 401 } 402 403 return; 404trunc: 405 ND_PRINT((ndo, "[|ip6]")); 406} 407