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