1 /* $OpenBSD: print-tcp.c,v 1.19 2004/01/15 12:27:07 markus Exp $ */ 2 3 /* 4 * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that: (1) source code distributions 9 * retain the above copyright notice and this paragraph in its entirety, (2) 10 * distributions including binary code include the above copyright notice and 11 * this paragraph in its entirety in the documentation or other materials 12 * provided with the distribution, and (3) all advertising materials mentioning 13 * features or use of this software display the following acknowledgement: 14 * ``This product includes software developed by the University of California, 15 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 16 * the University nor the names of its contributors may be used to endorse 17 * or promote products derived from this software without specific prior 18 * written permission. 19 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 20 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 21 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 22 */ 23 24 #ifndef lint 25 static const char rcsid[] = 26 "@(#) $Header: /home/cvs/src/usr.sbin/tcpdump/print-tcp.c,v 1.19 2004/01/15 12:27:07 markus Exp $ (LBL)"; 27 #endif 28 29 #include <sys/param.h> 30 #include <sys/time.h> 31 #include <sys/socket.h> 32 33 #include <netinet/in.h> 34 #include <netinet/in_systm.h> 35 #include <netinet/ip.h> 36 #include <netinet/ip_var.h> 37 #include <netinet/tcp.h> 38 #include <netinet/tcpip.h> 39 #include <net/if.h> 40 #include <net/pfvar.h> 41 42 #include <rpc/rpc.h> 43 44 #include <stdio.h> 45 #include <stdlib.h> 46 #include <string.h> 47 #include <unistd.h> 48 49 #ifdef INET6 50 #include <netinet/ip6.h> 51 #endif 52 53 #include "interface.h" 54 #include "addrtoname.h" 55 #include "extract.h" 56 57 #include "nfs.h" 58 59 static void print_tcp_rst_data(register const u_char *sp, u_int length); 60 61 #define MAX_RST_DATA_LEN 30 62 63 /* Compatibility */ 64 #ifndef TCPOPT_WSCALE 65 #define TCPOPT_WSCALE 3 /* window scale factor (rfc1072) */ 66 #endif 67 #ifndef TCPOPT_SACKOK 68 #define TCPOPT_SACKOK 4 /* selective ack ok (rfc2018) */ 69 #endif 70 #ifndef TCPOPT_SACK 71 #define TCPOPT_SACK 5 /* selective ack (rfc2018) */ 72 #endif 73 #ifndef TCPOLEN_SACK 74 #define TCPOLEN_SACK 8 /* length of a SACK block */ 75 #endif 76 #ifndef TCPOPT_ECHO 77 #define TCPOPT_ECHO 6 /* echo (rfc1072) */ 78 #endif 79 #ifndef TCPOPT_ECHOREPLY 80 #define TCPOPT_ECHOREPLY 7 /* echo (rfc1072) */ 81 #endif 82 #ifndef TCPOPT_TIMESTAMP 83 #define TCPOPT_TIMESTAMP 8 /* timestamps (rfc1323) */ 84 #endif 85 #ifndef TCPOPT_CC 86 #define TCPOPT_CC 11 /* T/TCP CC options (rfc1644) */ 87 #endif 88 #ifndef TCPOPT_CCNEW 89 #define TCPOPT_CCNEW 12 /* T/TCP CC options (rfc1644) */ 90 #endif 91 #ifndef TCPOPT_CCECHO 92 #define TCPOPT_CCECHO 13 /* T/TCP CC options (rfc1644) */ 93 #endif 94 95 /* Definitions required for ECN 96 for use if the OS running tcpdump does not have ECN */ 97 #ifndef TH_ECNECHO 98 #define TH_ECNECHO 0x40 /* ECN Echo in tcp header */ 99 #endif 100 #ifndef TH_CWR 101 #define TH_CWR 0x80 /* ECN Cwnd Reduced in tcp header*/ 102 #endif 103 104 struct tha { 105 #ifndef INET6 106 struct in_addr src; 107 struct in_addr dst; 108 #else 109 struct in6_addr src; 110 struct in6_addr dst; 111 #endif /*INET6*/ 112 u_int port; 113 }; 114 115 struct tcp_seq_hash { 116 struct tcp_seq_hash *nxt; 117 struct tha addr; 118 tcp_seq seq; 119 tcp_seq ack; 120 }; 121 122 #define TSEQ_HASHSIZE 919 123 124 /* These tcp optinos do not have the size octet */ 125 #define ZEROLENOPT(o) ((o) == TCPOPT_EOL || (o) == TCPOPT_NOP) 126 127 static struct tcp_seq_hash tcp_seq_hash[TSEQ_HASHSIZE]; 128 129 #ifndef BGP_PORT 130 #define BGP_PORT 179 131 #endif 132 #define NETBIOS_SSN_PORT 139 133 134 static int tcp_cksum(register const struct ip *ip, 135 register const struct tcphdr *tp, 136 register int len) 137 { 138 int i, tlen; 139 union phu { 140 struct phdr { 141 u_int32_t src; 142 u_int32_t dst; 143 u_char mbz; 144 u_char proto; 145 u_int16_t len; 146 } ph; 147 u_int16_t pa[6]; 148 } phu; 149 register const u_int16_t *sp; 150 u_int32_t sum; 151 tlen = ntohs(ip->ip_len) - ((const char *)tp-(const char*)ip); 152 153 /* pseudo-header.. */ 154 phu.ph.len = htons(tlen); 155 phu.ph.mbz = 0; 156 phu.ph.proto = ip->ip_p; 157 memcpy(&phu.ph.src, &ip->ip_src.s_addr, sizeof(u_int32_t)); 158 memcpy(&phu.ph.dst, &ip->ip_dst.s_addr, sizeof(u_int32_t)); 159 160 sp = &phu.pa[0]; 161 sum = sp[0]+sp[1]+sp[2]+sp[3]+sp[4]+sp[5]; 162 163 sp = (const u_int16_t *)tp; 164 165 for (i=0; i<(tlen&~1); i+= 2) 166 sum += *sp++; 167 168 if (tlen & 1) { 169 sum += htons( (*(const char *)sp) << 8); 170 } 171 172 while (sum > 0xffff) 173 sum = (sum & 0xffff) + (sum >> 16); 174 sum = ~sum & 0xffff; 175 176 return (sum); 177 } 178 179 180 void 181 tcp_print(register const u_char *bp, register u_int length, 182 register const u_char *bp2) 183 { 184 register const struct tcphdr *tp; 185 register const struct ip *ip; 186 register u_char flags; 187 register int hlen; 188 register char ch; 189 register struct tcp_seq_hash *th = NULL; 190 register int rev = 0; 191 u_int16_t sport, dport, win, urp; 192 tcp_seq seq, ack; 193 #ifdef INET6 194 register const struct ip6_hdr *ip6; 195 #endif 196 197 tp = (struct tcphdr *)bp; 198 ip = (struct ip *)bp2; 199 #ifdef INET6 200 if (ip->ip_v == 6) 201 ip6 = (struct ip6_hdr *)bp2; 202 else 203 ip6 = NULL; 204 #endif /*INET6*/ 205 ch = '\0'; 206 TCHECK(*tp); 207 if (length < sizeof(*tp)) { 208 (void)printf("truncated-tcp %d", length); 209 return; 210 } 211 212 sport = ntohs(tp->th_sport); 213 dport = ntohs(tp->th_dport); 214 seq = ntohl(tp->th_seq); 215 ack = ntohl(tp->th_ack); 216 win = ntohs(tp->th_win); 217 urp = ntohs(tp->th_urp); 218 hlen = tp->th_off * 4; 219 220 221 #ifdef INET6 222 if (ip6) { 223 if (ip6->ip6_nxt == IPPROTO_TCP) { 224 (void)printf("%s.%s > %s.%s: ", 225 ip6addr_string(&ip6->ip6_src), 226 tcpport_string(sport), 227 ip6addr_string(&ip6->ip6_dst), 228 tcpport_string(dport)); 229 } else { 230 (void)printf("%s > %s: ", 231 tcpport_string(sport), tcpport_string(dport)); 232 } 233 } else 234 #endif /*INET6*/ 235 { 236 if (ip->ip_p == IPPROTO_TCP) { 237 (void)printf("%s.%s > %s.%s: ", 238 ipaddr_string(&ip->ip_src), 239 tcpport_string(sport), 240 ipaddr_string(&ip->ip_dst), 241 tcpport_string(dport)); 242 } else { 243 (void)printf("%s > %s: ", 244 tcpport_string(sport), tcpport_string(dport)); 245 } 246 } 247 248 if (qflag) { 249 (void)printf("tcp %d", length - tp->th_off * 4); 250 return; 251 } else { 252 /* 253 * If data present and NFS port used, assume NFS. 254 * Pass offset of data plus 4 bytes for RPC TCP msg length 255 * to NFS print routines. 256 */ 257 u_int len = length - hlen; 258 if ((u_char *)tp + 4 + sizeof(struct rpc_msg) <= snapend && 259 dport == NFS_PORT) { 260 nfsreq_print((u_char *)tp + hlen + 4, len, 261 (u_char *)ip); 262 return; 263 } else if ((u_char *)tp + 4 + 264 sizeof(struct rpc_msg) <= snapend && sport == NFS_PORT) { 265 nfsreply_print((u_char *)tp + hlen + 4, len, 266 (u_char *)ip); 267 return; 268 } 269 } 270 if ((flags = tp->th_flags) & (TH_SYN|TH_FIN|TH_RST|TH_PUSH| 271 TH_ECNECHO|TH_CWR)) { 272 if (flags & TH_SYN) 273 putchar('S'); 274 if (flags & TH_FIN) 275 putchar('F'); 276 if (flags & TH_RST) 277 putchar('R'); 278 if (flags & TH_PUSH) 279 putchar('P'); 280 if (flags & TH_CWR) 281 putchar('W'); /* congestion _W_indow reduced (ECN) */ 282 if (flags & TH_ECNECHO) 283 putchar('E'); /* ecn _E_cho sent (ECN) */ 284 } else 285 putchar('.'); 286 287 if (!Sflag && (flags & TH_ACK)) { 288 struct tha tha; 289 /* 290 * Find (or record) the initial sequence numbers for 291 * this conversation. (we pick an arbitrary 292 * collating order so there's only one entry for 293 * both directions). 294 */ 295 #ifdef INET6 296 bzero(&tha, sizeof(tha)); 297 rev = 0; 298 if (ip6) { 299 if (sport > dport) { 300 rev = 1; 301 } else if (sport == dport) { 302 int i; 303 304 for (i = 0; i < 4; i++) { 305 if (((u_int32_t *)(&ip6->ip6_src))[i] > 306 ((u_int32_t *)(&ip6->ip6_dst))[i]) { 307 rev = 1; 308 break; 309 } 310 } 311 } 312 if (rev) { 313 tha.src = ip6->ip6_dst; 314 tha.dst = ip6->ip6_src; 315 tha.port = dport << 16 | sport; 316 } else { 317 tha.dst = ip6->ip6_dst; 318 tha.src = ip6->ip6_src; 319 tha.port = sport << 16 | dport; 320 } 321 } else { 322 if (sport > dport || 323 (sport == dport && 324 ip->ip_src.s_addr > ip->ip_dst.s_addr)) { 325 rev = 1; 326 } 327 if (rev) { 328 *(struct in_addr *)&tha.src = ip->ip_dst; 329 *(struct in_addr *)&tha.dst = ip->ip_src; 330 tha.port = dport << 16 | sport; 331 } else { 332 *(struct in_addr *)&tha.dst = ip->ip_dst; 333 *(struct in_addr *)&tha.src = ip->ip_src; 334 tha.port = sport << 16 | dport; 335 } 336 } 337 #else 338 if (sport < dport || 339 (sport == dport && 340 ip->ip_src.s_addr < ip->ip_dst.s_addr)) { 341 tha.src = ip->ip_src, tha.dst = ip->ip_dst; 342 tha.port = sport << 16 | dport; 343 rev = 0; 344 } else { 345 tha.src = ip->ip_dst, tha.dst = ip->ip_src; 346 tha.port = dport << 16 | sport; 347 rev = 1; 348 } 349 #endif 350 351 for (th = &tcp_seq_hash[tha.port % TSEQ_HASHSIZE]; 352 th->nxt; th = th->nxt) 353 if (!memcmp((char *)&tha, (char *)&th->addr, 354 sizeof(th->addr))) 355 break; 356 357 if (!th->nxt || flags & TH_SYN) { 358 /* didn't find it or new conversation */ 359 if (th->nxt == NULL) { 360 th->nxt = (struct tcp_seq_hash *) 361 calloc(1, sizeof(*th)); 362 if (th->nxt == NULL) 363 error("tcp_print: calloc"); 364 } 365 th->addr = tha; 366 if (rev) 367 th->ack = seq, th->seq = ack - 1; 368 else 369 th->seq = seq, th->ack = ack - 1; 370 } else { 371 if (rev) 372 seq -= th->ack, ack -= th->seq; 373 else 374 seq -= th->seq, ack -= th->ack; 375 } 376 } 377 hlen = tp->th_off * 4; 378 if (hlen > length) { 379 (void)printf(" [bad hdr length]"); 380 return; 381 } 382 383 if (ip->ip_v == 4 && vflag) { 384 int sum; 385 if (TTEST2(tp->th_sport, length)) { 386 sum = tcp_cksum(ip, tp, length); 387 if (sum != 0) 388 (void)printf(" [bad tcp cksum %x!]", sum); 389 else 390 (void)printf(" [tcp sum ok]"); 391 } 392 } 393 394 /* OS Fingerprint */ 395 if (oflag && 396 #ifdef INET6 397 ip6 == NULL && 398 #endif 399 (flags & (TH_SYN|TH_ACK)) == TH_SYN) { 400 struct pf_osfp_enlist *head = NULL; 401 struct pf_osfp_entry *fp; 402 unsigned long left; 403 left = (unsigned long)(snapend - (const u_char *)tp); 404 405 if (left >= hlen) 406 head = pf_osfp_fingerprint_hdr(ip, tp); 407 if (head) { 408 int prev = 0; 409 printf(" (src OS:"); 410 SLIST_FOREACH(fp, head, fp_entry) { 411 if (fp->fp_enflags & PF_OSFP_EXPANDED) 412 continue; 413 if (prev) 414 printf(","); 415 printf(" %s", fp->fp_class_nm); 416 if (fp->fp_version_nm[0]) 417 printf(" %s", fp->fp_version_nm); 418 if (fp->fp_subtype_nm[0]) 419 printf(" %s", fp->fp_subtype_nm); 420 prev = 1; 421 } 422 printf(")"); 423 } else { 424 if (left < hlen) 425 printf(" (src OS: short-pkt)"); 426 else 427 printf(" (src OS: unknown)"); 428 } 429 } 430 431 length -= hlen; 432 if (length > 0 || flags & (TH_SYN | TH_FIN | TH_RST)) 433 (void)printf(" %lu:%lu(%d)", (long) seq, (long) (seq + length), 434 length); 435 if (flags & TH_ACK) 436 (void)printf(" ack %u", ack); 437 438 (void)printf(" win %d", win); 439 440 if (flags & TH_URG) 441 (void)printf(" urg %d", urp); 442 /* 443 * Handle any options. 444 */ 445 if ((hlen -= sizeof(*tp)) > 0) { 446 register const u_char *cp; 447 register int i, opt, len, datalen; 448 449 cp = (const u_char *)tp + sizeof(*tp); 450 putchar(' '); 451 ch = '<'; 452 while (hlen > 0) { 453 putchar(ch); 454 TCHECK(*cp); 455 opt = *cp++; 456 if (ZEROLENOPT(opt)) 457 len = 1; 458 else { 459 TCHECK(*cp); 460 len = *cp++; /* total including type, len */ 461 if (len < 2 || len > hlen) 462 goto bad; 463 --hlen; /* account for length byte */ 464 } 465 --hlen; /* account for type byte */ 466 datalen = 0; 467 468 /* Bail if "l" bytes of data are not left or were not captured */ 469 #define LENCHECK(l) { if ((l) > hlen) goto bad; TCHECK2(*cp, l); } 470 471 switch (opt) { 472 473 case TCPOPT_MAXSEG: 474 (void)printf("mss"); 475 datalen = 2; 476 LENCHECK(datalen); 477 (void)printf(" %u", EXTRACT_16BITS(cp)); 478 479 break; 480 481 case TCPOPT_EOL: 482 (void)printf("eol"); 483 break; 484 485 case TCPOPT_NOP: 486 (void)printf("nop"); 487 break; 488 489 case TCPOPT_WSCALE: 490 (void)printf("wscale"); 491 datalen = 1; 492 LENCHECK(datalen); 493 (void)printf(" %u", *cp); 494 break; 495 496 case TCPOPT_SACKOK: 497 (void)printf("sackOK"); 498 if (len != 2) 499 (void)printf("[len %d]", len); 500 break; 501 502 case TCPOPT_SACK: 503 { 504 u_long s, e; 505 506 datalen = len - 2; 507 if ((datalen % TCPOLEN_SACK) != 0 || 508 !(flags & TH_ACK)) { 509 (void)printf("malformed sack "); 510 (void)printf("[len %d] ", datalen); 511 break; 512 } 513 printf("sack %d ", datalen/TCPOLEN_SACK); 514 for (i = 0; i < datalen; i += TCPOLEN_SACK) { 515 LENCHECK (i + TCPOLEN_SACK); 516 s = EXTRACT_32BITS(cp + i); 517 e = EXTRACT_32BITS(cp + i + 4); 518 if (!Sflag) { 519 if (rev) { 520 s -= th->seq; 521 e -= th->seq; 522 } else { 523 s -= th->ack; 524 e -= th->ack; 525 } 526 } 527 (void) printf("{%lu:%lu} ", s, e); 528 } 529 break; 530 } 531 case TCPOPT_ECHO: 532 (void)printf("echo"); 533 datalen = 4; 534 LENCHECK(datalen); 535 (void)printf(" %u", EXTRACT_32BITS(cp)); 536 break; 537 538 case TCPOPT_ECHOREPLY: 539 (void)printf("echoreply"); 540 datalen = 4; 541 LENCHECK(datalen); 542 (void)printf(" %u", EXTRACT_32BITS(cp)); 543 break; 544 545 case TCPOPT_TIMESTAMP: 546 (void)printf("timestamp"); 547 datalen = 8; 548 LENCHECK(4); 549 (void)printf(" %u", EXTRACT_32BITS(cp)); 550 LENCHECK(datalen); 551 (void)printf(" %u", EXTRACT_32BITS(cp + 4)); 552 break; 553 554 case TCPOPT_CC: 555 (void)printf("cc"); 556 datalen = 4; 557 LENCHECK(datalen); 558 (void)printf(" %u", EXTRACT_32BITS(cp)); 559 break; 560 561 case TCPOPT_CCNEW: 562 (void)printf("ccnew"); 563 datalen = 4; 564 LENCHECK(datalen); 565 (void)printf(" %u", EXTRACT_32BITS(cp)); 566 break; 567 568 case TCPOPT_CCECHO: 569 (void)printf("ccecho"); 570 datalen = 4; 571 LENCHECK(datalen); 572 (void)printf(" %u", EXTRACT_32BITS(cp)); 573 break; 574 575 case TCPOPT_SIGNATURE: 576 (void)printf("tcpmd5:"); 577 datalen = len - 2; 578 for (i = 0; i < datalen; ++i) { 579 LENCHECK(i); 580 (void)printf("%02x", cp[i]); 581 } 582 break; 583 584 default: 585 (void)printf("opt-%d:", opt); 586 datalen = len - 2; 587 for (i = 0; i < datalen; ++i) { 588 LENCHECK(i); 589 (void)printf("%02x", cp[i]); 590 } 591 break; 592 } 593 594 /* Account for data printed */ 595 cp += datalen; 596 hlen -= datalen; 597 598 /* Check specification against observed length */ 599 ++datalen; /* option octet */ 600 if (!ZEROLENOPT(opt)) 601 ++datalen; /* size octet */ 602 if (datalen != len) 603 (void)printf("[len %d]", len); 604 ch = ','; 605 if (opt == TCPOPT_EOL) 606 break; 607 } 608 putchar('>'); 609 } 610 611 if (length <= 0) 612 return; 613 614 /* 615 * Decode payload if necessary. 616 */ 617 bp += (tp->th_off * 4); 618 if (flags & TH_RST) { 619 if (vflag) 620 print_tcp_rst_data(bp, length); 621 } else { 622 if (sport == BGP_PORT || dport == BGP_PORT) 623 bgp_print(bp, length); 624 #if 0 625 else if (sport == NETBIOS_SSN_PORT || dport == NETBIOS_SSN_PORT) 626 nbt_tcp_print(bp, length); 627 #endif 628 } 629 return; 630 bad: 631 fputs("[bad opt]", stdout); 632 if (ch != '\0') 633 putchar('>'); 634 return; 635 trunc: 636 fputs("[|tcp]", stdout); 637 if (ch != '\0') 638 putchar('>'); 639 } 640 641 642 /* 643 * RFC1122 says the following on data in RST segments: 644 * 645 * 4.2.2.12 RST Segment: RFC-793 Section 3.4 646 * 647 * A TCP SHOULD allow a received RST segment to include data. 648 * 649 * DISCUSSION 650 * It has been suggested that a RST segment could contain 651 * ASCII text that encoded and explained the cause of the 652 * RST. No standard has yet been established for such 653 * data. 654 * 655 */ 656 657 static void 658 print_tcp_rst_data(register const u_char *sp, u_int length) 659 { 660 int c; 661 662 if (TTEST2(*sp, length)) 663 printf(" [RST"); 664 else 665 printf(" [!RST"); 666 if (length > MAX_RST_DATA_LEN) { 667 length = MAX_RST_DATA_LEN; /* can use -X for longer */ 668 putchar('+'); /* indicate we truncate */ 669 } 670 putchar(' '); 671 while (length-- && sp <= snapend) { 672 c = *sp++; 673 safeputchar(c); 674 } 675 putchar(']'); 676 } 677