1 /* 2 * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 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 /* \summary: IP printer */ 23 24 #ifdef HAVE_CONFIG_H 25 #include <config.h> 26 #endif 27 28 #include "netdissect-stdinc.h" 29 30 #include "netdissect.h" 31 #include "addrtoname.h" 32 #include "extract.h" 33 34 #include "ip.h" 35 #include "ipproto.h" 36 37 38 static const struct tok ip_option_values[] = { 39 { IPOPT_EOL, "EOL" }, 40 { IPOPT_NOP, "NOP" }, 41 { IPOPT_TS, "timestamp" }, 42 { IPOPT_SECURITY, "security" }, 43 { IPOPT_RR, "RR" }, 44 { IPOPT_SSRR, "SSRR" }, 45 { IPOPT_LSRR, "LSRR" }, 46 { IPOPT_RA, "RA" }, 47 { IPOPT_RFC1393, "traceroute" }, 48 { 0, NULL } 49 }; 50 51 /* 52 * print the recorded route in an IP RR, LSRR or SSRR option. 53 */ 54 static int 55 ip_printroute(netdissect_options *ndo, 56 const u_char *cp, u_int length) 57 { 58 u_int ptr; 59 u_int len; 60 61 if (length < 3) { 62 ND_PRINT(" [bad length %u]", length); 63 return (0); 64 } 65 if ((length + 1) & 3) 66 ND_PRINT(" [bad length %u]", length); 67 ptr = GET_U_1(cp + 2) - 1; 68 if (ptr < 3 || ((ptr + 1) & 3) || ptr > length + 1) 69 ND_PRINT(" [bad ptr %u]", GET_U_1(cp + 2)); 70 71 for (len = 3; len < length; len += 4) { 72 ND_TCHECK_4(cp + len); /* Needed to print the IP addresses */ 73 ND_PRINT(" %s", GET_IPADDR_STRING(cp + len)); 74 if (ptr > len) 75 ND_PRINT(","); 76 } 77 return (0); 78 79 trunc: 80 return (-1); 81 } 82 83 /* 84 * If source-routing is present and valid, return the final destination. 85 * Otherwise, return IP destination. 86 * 87 * This is used for UDP and TCP pseudo-header in the checksum 88 * calculation. 89 */ 90 static uint32_t 91 ip_finddst(netdissect_options *ndo, 92 const struct ip *ip) 93 { 94 u_int length; 95 u_int len; 96 const u_char *cp; 97 98 cp = (const u_char *)(ip + 1); 99 length = IP_HL(ip) * 4; 100 if (length < sizeof(struct ip)) 101 goto trunc; 102 length -= sizeof(struct ip); 103 104 for (; length != 0; cp += len, length -= len) { 105 int tt; 106 107 tt = GET_U_1(cp); 108 if (tt == IPOPT_EOL) 109 break; 110 else if (tt == IPOPT_NOP) 111 len = 1; 112 else { 113 len = GET_U_1(cp + 1); 114 if (len < 2) 115 break; 116 } 117 if (length < len) 118 goto trunc; 119 ND_TCHECK_LEN(cp, len); 120 switch (tt) { 121 122 case IPOPT_SSRR: 123 case IPOPT_LSRR: 124 if (len < 7) 125 break; 126 return (GET_IPV4_TO_NETWORK_ORDER(cp + len - 4)); 127 } 128 } 129 trunc: 130 return (GET_IPV4_TO_NETWORK_ORDER(ip->ip_dst)); 131 } 132 133 /* 134 * Compute a V4-style checksum by building a pseudoheader. 135 */ 136 uint16_t 137 nextproto4_cksum(netdissect_options *ndo, 138 const struct ip *ip, const uint8_t *data, 139 u_int len, u_int covlen, uint8_t next_proto) 140 { 141 struct phdr { 142 uint32_t src; 143 uint32_t dst; 144 uint8_t mbz; 145 uint8_t proto; 146 uint16_t len; 147 } ph; 148 struct cksum_vec vec[2]; 149 150 /* pseudo-header.. */ 151 ph.len = htons((uint16_t)len); 152 ph.mbz = 0; 153 ph.proto = next_proto; 154 ph.src = GET_IPV4_TO_NETWORK_ORDER(ip->ip_src); 155 if (IP_HL(ip) == 5) 156 ph.dst = GET_IPV4_TO_NETWORK_ORDER(ip->ip_dst); 157 else 158 ph.dst = ip_finddst(ndo, ip); 159 160 vec[0].ptr = (const uint8_t *)(void *)&ph; 161 vec[0].len = sizeof(ph); 162 vec[1].ptr = data; 163 vec[1].len = covlen; 164 return (in_cksum(vec, 2)); 165 } 166 167 static int 168 ip_printts(netdissect_options *ndo, 169 const u_char *cp, u_int length) 170 { 171 u_int ptr; 172 u_int len; 173 u_int hoplen; 174 const char *type; 175 176 if (length < 4) { 177 ND_PRINT("[bad length %u]", length); 178 return (0); 179 } 180 ND_PRINT(" TS{"); 181 hoplen = ((GET_U_1(cp + 3) & 0xF) != IPOPT_TS_TSONLY) ? 8 : 4; 182 if ((length - 4) & (hoplen-1)) 183 ND_PRINT("[bad length %u]", length); 184 ptr = GET_U_1(cp + 2) - 1; 185 len = 0; 186 if (ptr < 4 || ((ptr - 4) & (hoplen-1)) || ptr > length + 1) 187 ND_PRINT("[bad ptr %u]", GET_U_1(cp + 2)); 188 switch (GET_U_1(cp + 3)&0xF) { 189 case IPOPT_TS_TSONLY: 190 ND_PRINT("TSONLY"); 191 break; 192 case IPOPT_TS_TSANDADDR: 193 ND_PRINT("TS+ADDR"); 194 break; 195 case IPOPT_TS_PRESPEC: 196 ND_PRINT("PRESPEC"); 197 break; 198 default: 199 ND_PRINT("[bad ts type %u]", GET_U_1(cp + 3)&0xF); 200 goto done; 201 } 202 203 type = " "; 204 for (len = 4; len < length; len += hoplen) { 205 if (ptr == len) 206 type = " ^ "; 207 ND_TCHECK_LEN(cp + len, hoplen); 208 ND_PRINT("%s%u@%s", type, GET_BE_U_4(cp + len + hoplen - 4), 209 hoplen!=8 ? "" : GET_IPADDR_STRING(cp + len)); 210 type = " "; 211 } 212 213 done: 214 ND_PRINT("%s", ptr == len ? " ^ " : ""); 215 216 if (GET_U_1(cp + 3) >> 4) 217 ND_PRINT(" [%u hops not recorded]} ", GET_U_1(cp + 3)>>4); 218 else 219 ND_PRINT("}"); 220 return (0); 221 222 trunc: 223 return (-1); 224 } 225 226 /* 227 * print IP options. 228 If truncated return -1, else 0. 229 */ 230 static int 231 ip_optprint(netdissect_options *ndo, 232 const u_char *cp, u_int length) 233 { 234 u_int option_len; 235 const char *sep = ""; 236 237 for (; length > 0; cp += option_len, length -= option_len) { 238 u_int option_code; 239 240 ND_PRINT("%s", sep); 241 sep = ","; 242 243 option_code = GET_U_1(cp); 244 245 ND_PRINT("%s", 246 tok2str(ip_option_values,"unknown %u",option_code)); 247 248 if (option_code == IPOPT_NOP || 249 option_code == IPOPT_EOL) 250 option_len = 1; 251 252 else { 253 option_len = GET_U_1(cp + 1); 254 if (option_len < 2) { 255 ND_PRINT(" [bad length %u]", option_len); 256 return 0; 257 } 258 } 259 260 if (option_len > length) { 261 ND_PRINT(" [bad length %u]", option_len); 262 return 0; 263 } 264 265 ND_TCHECK_LEN(cp, option_len); 266 267 switch (option_code) { 268 case IPOPT_EOL: 269 return 0; 270 271 case IPOPT_TS: 272 if (ip_printts(ndo, cp, option_len) == -1) 273 goto trunc; 274 break; 275 276 case IPOPT_RR: /* fall through */ 277 case IPOPT_SSRR: 278 case IPOPT_LSRR: 279 if (ip_printroute(ndo, cp, option_len) == -1) 280 goto trunc; 281 break; 282 283 case IPOPT_RA: 284 if (option_len < 4) { 285 ND_PRINT(" [bad length %u]", option_len); 286 break; 287 } 288 ND_TCHECK_1(cp + 3); 289 if (GET_BE_U_2(cp + 2) != 0) 290 ND_PRINT(" value %u", GET_BE_U_2(cp + 2)); 291 break; 292 293 case IPOPT_NOP: /* nothing to print - fall through */ 294 case IPOPT_SECURITY: 295 default: 296 break; 297 } 298 } 299 return 0; 300 301 trunc: 302 return -1; 303 } 304 305 #define IP_RES 0x8000 306 307 static const struct tok ip_frag_values[] = { 308 { IP_MF, "+" }, 309 { IP_DF, "DF" }, 310 { IP_RES, "rsvd" }, /* The RFC3514 evil ;-) bit */ 311 { 0, NULL } 312 }; 313 314 315 /* 316 * print an IP datagram. 317 */ 318 void 319 ip_print(netdissect_options *ndo, 320 const u_char *bp, 321 u_int length) 322 { 323 const struct ip *ip; 324 u_int off; 325 u_int hlen; 326 u_int len; 327 struct cksum_vec vec[1]; 328 uint8_t ip_tos, ip_ttl, ip_proto; 329 uint16_t sum, ip_sum; 330 const char *p_name; 331 int truncated = 0; 332 333 ndo->ndo_protocol = "ip"; 334 ip = (const struct ip *)bp; 335 if (IP_V(ip) != 4) { /* print version and fail if != 4 */ 336 if (IP_V(ip) == 6) 337 ND_PRINT("IP6, wrong link-layer encapsulation"); 338 else 339 ND_PRINT("IP%u", IP_V(ip)); 340 nd_print_invalid(ndo); 341 return; 342 } 343 if (!ndo->ndo_eflag) 344 ND_PRINT("IP "); 345 346 ND_TCHECK_SIZE(ip); 347 if (length < sizeof (struct ip)) { 348 ND_PRINT("truncated-ip %u", length); 349 return; 350 } 351 hlen = IP_HL(ip) * 4; 352 if (hlen < sizeof (struct ip)) { 353 ND_PRINT("bad-hlen %u", hlen); 354 return; 355 } 356 357 len = GET_BE_U_2(ip->ip_len); 358 if (length < len) 359 ND_PRINT("truncated-ip - %u bytes missing! ", 360 len - length); 361 if (len < hlen) { 362 #ifdef GUESS_TSO 363 if (len) { 364 ND_PRINT("bad-len %u", len); 365 return; 366 } 367 else { 368 /* we guess that it is a TSO send */ 369 len = length; 370 } 371 #else 372 ND_PRINT("bad-len %u", len); 373 return; 374 #endif /* GUESS_TSO */ 375 } 376 377 /* 378 * Cut off the snapshot length to the end of the IP payload. 379 */ 380 nd_push_snapend(ndo, bp + len); 381 382 len -= hlen; 383 384 off = GET_BE_U_2(ip->ip_off); 385 386 ip_proto = GET_U_1(ip->ip_p); 387 388 if (ndo->ndo_vflag) { 389 ip_tos = GET_U_1(ip->ip_tos); 390 ND_PRINT("(tos 0x%x", ip_tos); 391 /* ECN bits */ 392 switch (ip_tos & 0x03) { 393 394 case 0: 395 break; 396 397 case 1: 398 ND_PRINT(",ECT(1)"); 399 break; 400 401 case 2: 402 ND_PRINT(",ECT(0)"); 403 break; 404 405 case 3: 406 ND_PRINT(",CE"); 407 break; 408 } 409 410 ip_ttl = GET_U_1(ip->ip_ttl); 411 if (ip_ttl >= 1) 412 ND_PRINT(", ttl %u", ip_ttl); 413 414 /* 415 * for the firewall guys, print id, offset. 416 * On all but the last stick a "+" in the flags portion. 417 * For unfragmented datagrams, note the don't fragment flag. 418 */ 419 ND_PRINT(", id %u, offset %u, flags [%s], proto %s (%u)", 420 GET_BE_U_2(ip->ip_id), 421 (off & IP_OFFMASK) * 8, 422 bittok2str(ip_frag_values, "none", off & (IP_RES|IP_DF|IP_MF)), 423 tok2str(ipproto_values, "unknown", ip_proto), 424 ip_proto); 425 426 ND_PRINT(", length %u", GET_BE_U_2(ip->ip_len)); 427 428 if ((hlen - sizeof(struct ip)) > 0) { 429 ND_PRINT(", options ("); 430 if (ip_optprint(ndo, (const u_char *)(ip + 1), 431 hlen - sizeof(struct ip)) == -1) { 432 ND_PRINT(" [truncated-option]"); 433 truncated = 1; 434 } 435 ND_PRINT(")"); 436 } 437 438 if (!ndo->ndo_Kflag && (const u_char *)ip + hlen <= ndo->ndo_snapend) { 439 vec[0].ptr = (const uint8_t *)(const void *)ip; 440 vec[0].len = hlen; 441 sum = in_cksum(vec, 1); 442 if (sum != 0) { 443 ip_sum = GET_BE_U_2(ip->ip_sum); 444 ND_PRINT(", bad cksum %x (->%x)!", ip_sum, 445 in_cksum_shouldbe(ip_sum, sum)); 446 } 447 } 448 449 ND_PRINT(")\n "); 450 if (truncated) { 451 ND_PRINT("%s > %s: ", 452 GET_IPADDR_STRING(ip->ip_src), 453 GET_IPADDR_STRING(ip->ip_dst)); 454 nd_print_trunc(ndo); 455 nd_pop_packet_info(ndo); 456 return; 457 } 458 } 459 460 /* 461 * If this is fragment zero, hand it to the next higher 462 * level protocol. Let them know whether there are more 463 * fragments. 464 */ 465 if ((off & IP_OFFMASK) == 0) { 466 uint8_t nh = GET_U_1(ip->ip_p); 467 468 if (nh != IPPROTO_TCP && nh != IPPROTO_UDP && 469 nh != IPPROTO_SCTP && nh != IPPROTO_DCCP) { 470 ND_PRINT("%s > %s: ", 471 GET_IPADDR_STRING(ip->ip_src), 472 GET_IPADDR_STRING(ip->ip_dst)); 473 } 474 /* 475 * Do a bounds check before calling ip_demux_print(). 476 * At least the header data is required. 477 */ 478 if (!ND_TTEST_LEN((const u_char *)ip, hlen)) { 479 ND_PRINT(" [remaining caplen(%u) < header length(%u)]", 480 ND_BYTES_AVAILABLE_AFTER((const u_char *)ip), 481 hlen); 482 nd_trunc_longjmp(ndo); 483 } 484 ip_demux_print(ndo, (const u_char *)ip + hlen, len, 4, 485 off & IP_MF, GET_U_1(ip->ip_ttl), nh, bp); 486 } else { 487 /* 488 * Ultra quiet now means that all this stuff should be 489 * suppressed. 490 */ 491 if (ndo->ndo_qflag > 1) { 492 nd_pop_packet_info(ndo); 493 return; 494 } 495 496 /* 497 * This isn't the first frag, so we're missing the 498 * next level protocol header. print the ip addr 499 * and the protocol. 500 */ 501 ND_PRINT("%s > %s:", GET_IPADDR_STRING(ip->ip_src), 502 GET_IPADDR_STRING(ip->ip_dst)); 503 if (!ndo->ndo_nflag && (p_name = netdb_protoname(ip_proto)) != NULL) 504 ND_PRINT(" %s", p_name); 505 else 506 ND_PRINT(" ip-proto-%u", ip_proto); 507 } 508 nd_pop_packet_info(ndo); 509 return; 510 511 trunc: 512 nd_print_trunc(ndo); 513 } 514 515 void 516 ipN_print(netdissect_options *ndo, const u_char *bp, u_int length) 517 { 518 ndo->ndo_protocol = "ipn"; 519 if (length < 1) { 520 ND_PRINT("truncated-ip %u", length); 521 return; 522 } 523 524 switch (GET_U_1(bp) & 0xF0) { 525 case 0x40: 526 ip_print(ndo, bp, length); 527 break; 528 case 0x60: 529 ip6_print(ndo, bp, length); 530 break; 531 default: 532 ND_PRINT("unknown ip %u", (GET_U_1(bp) & 0xF0) >> 4); 533 break; 534 } 535 } 536