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 #ifndef lint 23 static const char rcsid[] = 24 "@(#) $Header: /tcpdump/master/tcpdump/print-tcp.c,v 1.63 1999/12/22 15:44:10 itojun Exp $ (LBL)"; 25 #endif 26 27 #ifdef HAVE_CONFIG_H 28 #include "config.h" 29 #endif 30 31 #include <sys/param.h> 32 #include <sys/time.h> 33 34 #include <netinet/in.h> 35 #include <netinet/in_systm.h> 36 #include <netinet/ip.h> 37 #include <netinet/ip_var.h> 38 #include <netinet/tcp.h> 39 40 #ifdef HAVE_MEMORY_H 41 #include <memory.h> 42 #endif 43 #include <stdio.h> 44 #include <stdlib.h> 45 #include <string.h> 46 #include <unistd.h> 47 48 #ifdef INET6 49 #include <netinet/ip6.h> 50 #endif 51 52 #include "interface.h" 53 #include "addrtoname.h" 54 #include "extract.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 (rfc1072) */ 62 #endif 63 #ifndef TCPOPT_SACK 64 #define TCPOPT_SACK 5 /* selective ack (rfc1072) */ 65 #endif 66 #ifndef TCPOPT_ECHO 67 #define TCPOPT_ECHO 6 /* echo (rfc1072) */ 68 #endif 69 #ifndef TCPOPT_ECHOREPLY 70 #define TCPOPT_ECHOREPLY 7 /* echo (rfc1072) */ 71 #endif 72 #ifndef TCPOPT_TIMESTAMP 73 #define TCPOPT_TIMESTAMP 8 /* timestamps (rfc1323) */ 74 #endif 75 #ifndef TCPOPT_CC 76 #define TCPOPT_CC 11 /* T/TCP CC options (rfc1644) */ 77 #endif 78 #ifndef TCPOPT_CCNEW 79 #define TCPOPT_CCNEW 12 /* T/TCP CC options (rfc1644) */ 80 #endif 81 #ifndef TCPOPT_CCECHO 82 #define TCPOPT_CCECHO 13 /* T/TCP CC options (rfc1644) */ 83 #endif 84 85 struct tha { 86 #ifndef INET6 87 struct in_addr src; 88 struct in_addr dst; 89 #else 90 struct in6_addr src; 91 struct in6_addr dst; 92 #endif /*INET6*/ 93 u_int port; 94 }; 95 96 struct tcp_seq_hash { 97 struct tcp_seq_hash *nxt; 98 struct tha addr; 99 tcp_seq seq; 100 tcp_seq ack; 101 }; 102 103 #define TSEQ_HASHSIZE 919 104 105 /* These tcp optinos do not have the size octet */ 106 #define ZEROLENOPT(o) ((o) == TCPOPT_EOL || (o) == TCPOPT_NOP) 107 108 static struct tcp_seq_hash tcp_seq_hash[TSEQ_HASHSIZE]; 109 110 111 #ifndef TELNET_PORT 112 #define TELNET_PORT 23 113 #endif 114 #ifndef BGP_PORT 115 #define BGP_PORT 179 116 #endif 117 #define NETBIOS_SSN_PORT 139 118 119 void 120 tcp_print(register const u_char *bp, register u_int length, 121 register const u_char *bp2) 122 { 123 register const struct tcphdr *tp; 124 register const struct ip *ip; 125 register u_char flags; 126 register int hlen; 127 register char ch; 128 u_short sport, dport, win, urp; 129 u_int32_t seq, ack, thseq, thack; 130 int threv; 131 #ifdef INET6 132 register const struct ip6_hdr *ip6; 133 #endif 134 135 tp = (struct tcphdr *)bp; 136 ip = (struct ip *)bp2; 137 #ifdef INET6 138 if (ip->ip_v == 6) 139 ip6 = (struct ip6_hdr *)bp2; 140 else 141 ip6 = NULL; 142 #endif /*INET6*/ 143 ch = '\0'; 144 if (!TTEST(tp->th_dport)) { 145 (void)printf("%s > %s: [|tcp]", 146 ipaddr_string(&ip->ip_src), 147 ipaddr_string(&ip->ip_dst)); 148 return; 149 } 150 151 sport = ntohs(tp->th_sport); 152 dport = ntohs(tp->th_dport); 153 154 #ifdef INET6 155 if (ip6) { 156 if (ip6->ip6_nxt == IPPROTO_TCP) { 157 (void)printf("%s.%s > %s.%s: ", 158 ip6addr_string(&ip6->ip6_src), 159 tcpport_string(sport), 160 ip6addr_string(&ip6->ip6_dst), 161 tcpport_string(dport)); 162 } else { 163 (void)printf("%s > %s: ", 164 tcpport_string(sport), tcpport_string(dport)); 165 } 166 } else 167 #endif /*INET6*/ 168 { 169 if (ip->ip_p == IPPROTO_TCP) { 170 (void)printf("%s.%s > %s.%s: ", 171 ipaddr_string(&ip->ip_src), 172 tcpport_string(sport), 173 ipaddr_string(&ip->ip_dst), 174 tcpport_string(dport)); 175 } else { 176 (void)printf("%s > %s: ", 177 tcpport_string(sport), tcpport_string(dport)); 178 } 179 } 180 181 TCHECK(*tp); 182 183 seq = ntohl(tp->th_seq); 184 ack = ntohl(tp->th_ack); 185 win = ntohs(tp->th_win); 186 urp = ntohs(tp->th_urp); 187 188 if (qflag) { 189 (void)printf("tcp %d", length - tp->th_off * 4); 190 return; 191 } 192 #ifdef TH_ECN 193 if ((flags = tp->th_flags) & (TH_SYN|TH_FIN|TH_RST|TH_PUSH|TH_ECN)) 194 #else 195 if ((flags = tp->th_flags) & (TH_SYN|TH_FIN|TH_RST|TH_PUSH)) 196 #endif 197 { 198 if (flags & TH_SYN) 199 putchar('S'); 200 if (flags & TH_FIN) 201 putchar('F'); 202 if (flags & TH_RST) 203 putchar('R'); 204 if (flags & TH_PUSH) 205 putchar('P'); 206 #ifdef TH_ECN 207 if (flags & TH_ECN) 208 putchar('C'); 209 #endif 210 } else 211 putchar('.'); 212 213 if (flags&0xc0) { 214 printf(" ["); 215 if (flags&0x40) 216 printf("ECN-Echo"); 217 if (flags&0x80) 218 printf("%sCWR", (flags&0x40) ? "," : ""); 219 printf("]"); 220 } 221 222 if (!Sflag && (flags & TH_ACK)) { 223 register struct tcp_seq_hash *th; 224 register int rev; 225 struct tha tha; 226 /* 227 * Find (or record) the initial sequence numbers for 228 * this conversation. (we pick an arbitrary 229 * collating order so there's only one entry for 230 * both directions). 231 */ 232 #ifdef INET6 233 bzero(&tha, sizeof(tha)); 234 rev = 0; 235 if (ip6) { 236 if (sport > dport) { 237 rev = 1; 238 } else if (sport == dport) { 239 int i; 240 241 for (i = 0; i < 4; i++) { 242 if (((u_int32_t *)(&ip6->ip6_src))[i] > 243 ((u_int32_t *)(&ip6->ip6_dst))[i]) { 244 rev = 1; 245 break; 246 } 247 } 248 } 249 if (rev) { 250 tha.src = ip6->ip6_dst; 251 tha.dst = ip6->ip6_src; 252 tha.port = dport << 16 | sport; 253 } else { 254 tha.dst = ip6->ip6_dst; 255 tha.src = ip6->ip6_src; 256 tha.port = sport << 16 | dport; 257 } 258 } else { 259 if (sport > dport || 260 (sport == dport && 261 ip->ip_src.s_addr > ip->ip_dst.s_addr)) { 262 rev = 1; 263 } 264 if (rev) { 265 *(struct in_addr *)&tha.src = ip->ip_dst; 266 *(struct in_addr *)&tha.dst = ip->ip_src; 267 tha.port = dport << 16 | sport; 268 } else { 269 *(struct in_addr *)&tha.dst = ip->ip_dst; 270 *(struct in_addr *)&tha.src = ip->ip_src; 271 tha.port = sport << 16 | dport; 272 } 273 } 274 #else 275 if (sport < dport || 276 (sport == dport && 277 ip->ip_src.s_addr < ip->ip_dst.s_addr)) { 278 tha.src = ip->ip_src, tha.dst = ip->ip_dst; 279 tha.port = sport << 16 | dport; 280 rev = 0; 281 } else { 282 tha.src = ip->ip_dst, tha.dst = ip->ip_src; 283 tha.port = dport << 16 | sport; 284 rev = 1; 285 } 286 #endif 287 288 threv = rev; 289 for (th = &tcp_seq_hash[tha.port % TSEQ_HASHSIZE]; 290 th->nxt; th = th->nxt) 291 if (!memcmp((char *)&tha, (char *)&th->addr, 292 sizeof(th->addr))) 293 break; 294 295 if (!th->nxt || flags & TH_SYN) { 296 /* didn't find it or new conversation */ 297 if (th->nxt == NULL) { 298 th->nxt = (struct tcp_seq_hash *) 299 calloc(1, sizeof(*th)); 300 if (th->nxt == NULL) 301 error("tcp_print: calloc"); 302 } 303 th->addr = tha; 304 if (rev) 305 th->ack = seq, th->seq = ack - 1; 306 else 307 th->seq = seq, th->ack = ack - 1; 308 } else { 309 310 thseq = th->seq; 311 thack = th->ack; 312 313 if (rev) 314 seq -= th->ack, ack -= th->seq; 315 else 316 seq -= th->seq, ack -= th->ack; 317 } 318 } 319 hlen = tp->th_off * 4; 320 if (hlen > length) { 321 (void)printf(" [bad hdr length]"); 322 return; 323 } 324 length -= hlen; 325 if (vflag > 1 || length > 0 || flags & (TH_SYN | TH_FIN | TH_RST)) 326 (void)printf(" %u:%u(%d)", seq, seq + length, length); 327 if (flags & TH_ACK) 328 (void)printf(" ack %u", ack); 329 330 (void)printf(" win %d", win); 331 332 if (flags & TH_URG) 333 (void)printf(" urg %d", urp); 334 /* 335 * Handle any options. 336 */ 337 if ((hlen -= sizeof(*tp)) > 0) { 338 register const u_char *cp; 339 register int i, opt, len, datalen; 340 341 cp = (const u_char *)tp + sizeof(*tp); 342 putchar(' '); 343 ch = '<'; 344 while (hlen > 0) { 345 putchar(ch); 346 TCHECK(*cp); 347 opt = *cp++; 348 if (ZEROLENOPT(opt)) 349 len = 1; 350 else { 351 TCHECK(*cp); 352 len = *cp++; /* total including type, len */ 353 if (len < 2 || len > hlen) 354 goto bad; 355 --hlen; /* account for length byte */ 356 } 357 --hlen; /* account for type byte */ 358 datalen = 0; 359 360 /* Bail if "l" bytes of data are not left or were not captured */ 361 #define LENCHECK(l) { if ((l) > hlen) goto bad; TCHECK2(*cp, l); } 362 363 switch (opt) { 364 365 case TCPOPT_MAXSEG: 366 (void)printf("mss"); 367 datalen = 2; 368 LENCHECK(datalen); 369 (void)printf(" %u", EXTRACT_16BITS(cp)); 370 371 break; 372 373 case TCPOPT_EOL: 374 (void)printf("eol"); 375 break; 376 377 case TCPOPT_NOP: 378 (void)printf("nop"); 379 break; 380 381 case TCPOPT_WSCALE: 382 (void)printf("wscale"); 383 datalen = 1; 384 LENCHECK(datalen); 385 (void)printf(" %u", *cp); 386 break; 387 388 case TCPOPT_SACKOK: 389 (void)printf("sackOK"); 390 break; 391 392 case TCPOPT_SACK: 393 (void)printf("sack"); 394 datalen = len - 2; 395 if (datalen % 8 != 0) { 396 (void)printf(" malformed sack "); 397 } else { 398 u_int32_t s, e; 399 400 (void)printf(" sack %d ", datalen / 8); 401 for (i = 0; i < datalen; i += 8) { 402 LENCHECK(i + 4); 403 s = EXTRACT_32BITS(cp + i); 404 LENCHECK(i + 8); 405 e = EXTRACT_32BITS(cp + i + 4); 406 if (threv) { 407 s -= thseq; 408 e -= thseq; 409 } else { 410 s -= thack; 411 e -= thack; 412 } 413 (void)printf("{%u:%u}", s, e); 414 } 415 (void)printf(" "); 416 } 417 break; 418 419 case TCPOPT_ECHO: 420 (void)printf("echo"); 421 datalen = 4; 422 LENCHECK(datalen); 423 (void)printf(" %u", EXTRACT_32BITS(cp)); 424 break; 425 426 case TCPOPT_ECHOREPLY: 427 (void)printf("echoreply"); 428 datalen = 4; 429 LENCHECK(datalen); 430 (void)printf(" %u", EXTRACT_32BITS(cp)); 431 break; 432 433 case TCPOPT_TIMESTAMP: 434 (void)printf("timestamp"); 435 datalen = 8; 436 LENCHECK(4); 437 (void)printf(" %u", EXTRACT_32BITS(cp)); 438 LENCHECK(datalen); 439 (void)printf(" %u", EXTRACT_32BITS(cp + 4)); 440 break; 441 442 case TCPOPT_CC: 443 (void)printf("cc"); 444 datalen = 4; 445 LENCHECK(datalen); 446 (void)printf(" %u", EXTRACT_32BITS(cp)); 447 break; 448 449 case TCPOPT_CCNEW: 450 (void)printf("ccnew"); 451 datalen = 4; 452 LENCHECK(datalen); 453 (void)printf(" %u", EXTRACT_32BITS(cp)); 454 break; 455 456 case TCPOPT_CCECHO: 457 (void)printf("ccecho"); 458 datalen = 4; 459 LENCHECK(datalen); 460 (void)printf(" %u", EXTRACT_32BITS(cp)); 461 break; 462 463 default: 464 (void)printf("opt-%d:", opt); 465 datalen = len - 2; 466 for (i = 0; i < datalen; ++i) { 467 LENCHECK(i); 468 (void)printf("%02x", cp[i]); 469 } 470 break; 471 } 472 473 /* Account for data printed */ 474 cp += datalen; 475 hlen -= datalen; 476 477 /* Check specification against observed length */ 478 ++datalen; /* option octet */ 479 if (!ZEROLENOPT(opt)) 480 ++datalen; /* size octet */ 481 if (datalen != len) 482 (void)printf("[len %d]", len); 483 ch = ','; 484 if (opt == TCPOPT_EOL) 485 break; 486 } 487 putchar('>'); 488 } 489 490 if (length <= 0) 491 return; 492 493 /* 494 * Decode payload if necessary. 495 */ 496 bp += (tp->th_off * 4); 497 if (!qflag && vflag && length > 0 498 && (sport == TELNET_PORT || dport == TELNET_PORT)) 499 telnet_print(bp, length); 500 else if (sport == BGP_PORT || dport == BGP_PORT) 501 bgp_print(bp, length); 502 else if (sport == NETBIOS_SSN_PORT || dport == NETBIOS_SSN_PORT) 503 nbt_tcp_print(bp, length); 504 return; 505 bad: 506 fputs("[bad opt]", stdout); 507 if (ch != '\0') 508 putchar('>'); 509 return; 510 trunc: 511 fputs("[|tcp]", stdout); 512 if (ch != '\0') 513 putchar('>'); 514 } 515 516