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 if (!nd_push_snaplen(ndo, bp, len)) { 381 (*ndo->ndo_error)(ndo, S_ERR_ND_MEM_ALLOC, 382 "%s: can't push snaplen on buffer stack", __func__); 383 } 384 385 len -= hlen; 386 387 off = GET_BE_U_2(ip->ip_off); 388 389 ip_proto = GET_U_1(ip->ip_p); 390 391 if (ndo->ndo_vflag) { 392 ip_tos = GET_U_1(ip->ip_tos); 393 ND_PRINT("(tos 0x%x", ip_tos); 394 /* ECN bits */ 395 switch (ip_tos & 0x03) { 396 397 case 0: 398 break; 399 400 case 1: 401 ND_PRINT(",ECT(1)"); 402 break; 403 404 case 2: 405 ND_PRINT(",ECT(0)"); 406 break; 407 408 case 3: 409 ND_PRINT(",CE"); 410 break; 411 } 412 413 ip_ttl = GET_U_1(ip->ip_ttl); 414 if (ip_ttl >= 1) 415 ND_PRINT(", ttl %u", ip_ttl); 416 417 /* 418 * for the firewall guys, print id, offset. 419 * On all but the last stick a "+" in the flags portion. 420 * For unfragmented datagrams, note the don't fragment flag. 421 */ 422 ND_PRINT(", id %u, offset %u, flags [%s], proto %s (%u)", 423 GET_BE_U_2(ip->ip_id), 424 (off & IP_OFFMASK) * 8, 425 bittok2str(ip_frag_values, "none", off & (IP_RES|IP_DF|IP_MF)), 426 tok2str(ipproto_values, "unknown", ip_proto), 427 ip_proto); 428 429 ND_PRINT(", length %u", GET_BE_U_2(ip->ip_len)); 430 431 if ((hlen - sizeof(struct ip)) > 0) { 432 ND_PRINT(", options ("); 433 if (ip_optprint(ndo, (const u_char *)(ip + 1), 434 hlen - sizeof(struct ip)) == -1) { 435 ND_PRINT(" [truncated-option]"); 436 truncated = 1; 437 } 438 ND_PRINT(")"); 439 } 440 441 if (!ndo->ndo_Kflag && (const u_char *)ip + hlen <= ndo->ndo_snapend) { 442 vec[0].ptr = (const uint8_t *)(const void *)ip; 443 vec[0].len = hlen; 444 sum = in_cksum(vec, 1); 445 if (sum != 0) { 446 ip_sum = GET_BE_U_2(ip->ip_sum); 447 ND_PRINT(", bad cksum %x (->%x)!", ip_sum, 448 in_cksum_shouldbe(ip_sum, sum)); 449 } 450 } 451 452 ND_PRINT(")\n "); 453 if (truncated) { 454 ND_PRINT("%s > %s: ", 455 GET_IPADDR_STRING(ip->ip_src), 456 GET_IPADDR_STRING(ip->ip_dst)); 457 nd_print_trunc(ndo); 458 nd_pop_packet_info(ndo); 459 return; 460 } 461 } 462 463 /* 464 * If this is fragment zero, hand it to the next higher 465 * level protocol. Let them know whether there are more 466 * fragments. 467 */ 468 if ((off & IP_OFFMASK) == 0) { 469 uint8_t nh = GET_U_1(ip->ip_p); 470 471 if (nh != IPPROTO_TCP && nh != IPPROTO_UDP && 472 nh != IPPROTO_SCTP && nh != IPPROTO_DCCP) { 473 ND_PRINT("%s > %s: ", 474 GET_IPADDR_STRING(ip->ip_src), 475 GET_IPADDR_STRING(ip->ip_dst)); 476 } 477 /* 478 * Do a bounds check before calling ip_demux_print(). 479 * At least the header data is required. 480 */ 481 if (!ND_TTEST_LEN((const u_char *)ip, hlen)) { 482 ND_PRINT(" [remaining caplen(%u) < header length(%u)]", 483 ND_BYTES_AVAILABLE_AFTER((const u_char *)ip), 484 hlen); 485 nd_trunc_longjmp(ndo); 486 } 487 ip_demux_print(ndo, (const u_char *)ip + hlen, len, 4, 488 off & IP_MF, GET_U_1(ip->ip_ttl), nh, bp); 489 } else { 490 /* 491 * Ultra quiet now means that all this stuff should be 492 * suppressed. 493 */ 494 if (ndo->ndo_qflag > 1) { 495 nd_pop_packet_info(ndo); 496 return; 497 } 498 499 /* 500 * This isn't the first frag, so we're missing the 501 * next level protocol header. print the ip addr 502 * and the protocol. 503 */ 504 ND_PRINT("%s > %s:", GET_IPADDR_STRING(ip->ip_src), 505 GET_IPADDR_STRING(ip->ip_dst)); 506 if (!ndo->ndo_nflag && (p_name = netdb_protoname(ip_proto)) != NULL) 507 ND_PRINT(" %s", p_name); 508 else 509 ND_PRINT(" ip-proto-%u", ip_proto); 510 } 511 nd_pop_packet_info(ndo); 512 return; 513 514 trunc: 515 nd_print_trunc(ndo); 516 } 517 518 void 519 ipN_print(netdissect_options *ndo, const u_char *bp, u_int length) 520 { 521 ndo->ndo_protocol = "ipn"; 522 if (length < 1) { 523 ND_PRINT("truncated-ip %u", length); 524 return; 525 } 526 527 switch (GET_U_1(bp) & 0xF0) { 528 case 0x40: 529 ip_print(ndo, bp, length); 530 break; 531 case 0x60: 532 ip6_print(ndo, bp, length); 533 break; 534 default: 535 ND_PRINT("unknown ip %u", (GET_U_1(bp) & 0xF0) >> 4); 536 break; 537 } 538 } 539