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