1 /* 2 * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996 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: /home/cvs/src/usr.sbin/tcpdump/print-tcp.c,v 1.6 1998/09/22 22:03:01 provos Exp $ (LBL)"; 25 #endif 26 27 #include <sys/param.h> 28 #include <sys/time.h> 29 30 #include <netinet/in.h> 31 #include <netinet/in_systm.h> 32 #include <netinet/ip.h> 33 #include <netinet/ip_var.h> 34 #include <netinet/tcp.h> 35 #include <netinet/tcpip.h> 36 37 #include <stdio.h> 38 #include <stdlib.h> 39 #include <string.h> 40 #include <unistd.h> 41 42 #include "interface.h" 43 #include "addrtoname.h" 44 #include "extract.h" 45 46 /* Compatibility */ 47 #ifndef TCPOPT_WSCALE 48 #define TCPOPT_WSCALE 3 /* window scale factor (rfc1072) */ 49 #endif 50 #ifndef TCPOPT_SACKOK 51 #define TCPOPT_SACKOK 4 /* selective ack ok (rfc2018) */ 52 #endif 53 #ifndef TCPOPT_SACK 54 #define TCPOPT_SACK 5 /* selective ack (rfc2018) */ 55 #endif 56 #ifndef TCPOLEN_SACK 57 #define TCPOLEN_SACK 8 /* length of a SACK block */ 58 #endif 59 #ifndef TCPOPT_ECHO 60 #define TCPOPT_ECHO 6 /* echo (rfc1072) */ 61 #endif 62 #ifndef TCPOPT_ECHOREPLY 63 #define TCPOPT_ECHOREPLY 7 /* echo (rfc1072) */ 64 #endif 65 #ifndef TCPOPT_TIMESTAMP 66 #define TCPOPT_TIMESTAMP 8 /* timestamps (rfc1323) */ 67 #endif 68 #ifndef TCPOPT_CC 69 #define TCPOPT_CC 11 /* T/TCP CC options (rfc1644) */ 70 #endif 71 #ifndef TCPOPT_CCNEW 72 #define TCPOPT_CCNEW 12 /* T/TCP CC options (rfc1644) */ 73 #endif 74 #ifndef TCPOPT_CCECHO 75 #define TCPOPT_CCECHO 13 /* T/TCP CC options (rfc1644) */ 76 #endif 77 78 struct tha { 79 struct in_addr src; 80 struct in_addr dst; 81 u_int port; 82 }; 83 84 struct tcp_seq_hash { 85 struct tcp_seq_hash *nxt; 86 struct tha addr; 87 tcp_seq seq; 88 tcp_seq ack; 89 }; 90 91 #define TSEQ_HASHSIZE 919 92 93 /* These tcp optinos do not have the size octet */ 94 #define ZEROLENOPT(o) ((o) == TCPOPT_EOL || (o) == TCPOPT_NOP) 95 96 static struct tcp_seq_hash tcp_seq_hash[TSEQ_HASHSIZE]; 97 98 99 void 100 tcp_print(register const u_char *bp, register u_int length, 101 register const u_char *bp2) 102 { 103 register const struct tcphdr *tp; 104 register const struct ip *ip; 105 register u_char flags; 106 register int hlen; 107 register char ch; 108 register struct tcp_seq_hash *th; 109 register int rev; 110 u_short sport, dport, win, urp; 111 u_int32_t seq, ack; 112 113 tp = (struct tcphdr *)bp; 114 ip = (struct ip *)bp2; 115 ch = '\0'; 116 TCHECK(*tp); 117 if (length < sizeof(*tp)) { 118 (void)printf("truncated-tcp %d", length); 119 return; 120 } 121 122 sport = ntohs(tp->th_sport); 123 dport = ntohs(tp->th_dport); 124 seq = ntohl(tp->th_seq); 125 ack = ntohl(tp->th_ack); 126 win = ntohs(tp->th_win); 127 urp = ntohs(tp->th_urp); 128 129 (void)printf("%s.%s > %s.%s: ", 130 ipaddr_string(&ip->ip_src), tcpport_string(sport), 131 ipaddr_string(&ip->ip_dst), tcpport_string(dport)); 132 133 if (qflag) { 134 (void)printf("tcp %d", length - tp->th_off * 4); 135 return; 136 } 137 if ((flags = tp->th_flags) & (TH_SYN|TH_FIN|TH_RST|TH_PUSH)) { 138 if (flags & TH_SYN) 139 putchar('S'); 140 if (flags & TH_FIN) 141 putchar('F'); 142 if (flags & TH_RST) 143 putchar('R'); 144 if (flags & TH_PUSH) 145 putchar('P'); 146 } else 147 putchar('.'); 148 149 if (!Sflag && (flags & TH_ACK)) { 150 struct tha tha; 151 /* 152 * Find (or record) the initial sequence numbers for 153 * this conversation. (we pick an arbitrary 154 * collating order so there's only one entry for 155 * both directions). 156 */ 157 if (sport < dport || 158 (sport == dport && 159 ip->ip_src.s_addr < ip->ip_dst.s_addr)) { 160 tha.src = ip->ip_src, tha.dst = ip->ip_dst; 161 tha.port = sport << 16 | dport; 162 rev = 0; 163 } else { 164 tha.src = ip->ip_dst, tha.dst = ip->ip_src; 165 tha.port = dport << 16 | sport; 166 rev = 1; 167 } 168 169 for (th = &tcp_seq_hash[tha.port % TSEQ_HASHSIZE]; 170 th->nxt; th = th->nxt) 171 if (!memcmp((char *)&tha, (char *)&th->addr, 172 sizeof(th->addr))) 173 break; 174 175 if (!th->nxt || flags & TH_SYN) { 176 /* didn't find it or new conversation */ 177 if (th->nxt == NULL) { 178 th->nxt = (struct tcp_seq_hash *) 179 calloc(1, sizeof(*th)); 180 if (th->nxt == NULL) 181 error("tcp_print: calloc"); 182 } 183 th->addr = tha; 184 if (rev) 185 th->ack = seq, th->seq = ack - 1; 186 else 187 th->seq = seq, th->ack = ack - 1; 188 } else { 189 if (rev) 190 seq -= th->ack, ack -= th->seq; 191 else 192 seq -= th->seq, ack -= th->ack; 193 } 194 } 195 hlen = tp->th_off * 4; 196 if (hlen > length) { 197 (void)printf(" [bad hdr length]"); 198 return; 199 } 200 length -= hlen; 201 if (length > 0 || flags & (TH_SYN | TH_FIN | TH_RST)) 202 (void)printf(" %u:%u(%d)", seq, seq + length, length); 203 if (flags & TH_ACK) 204 (void)printf(" ack %u", ack); 205 206 (void)printf(" win %d", win); 207 208 if (flags & TH_URG) 209 (void)printf(" urg %d", urp); 210 /* 211 * Handle any options. 212 */ 213 if ((hlen -= sizeof(*tp)) > 0) { 214 register const u_char *cp; 215 register int i, opt, len, datalen; 216 217 cp = (const u_char *)tp + sizeof(*tp); 218 putchar(' '); 219 ch = '<'; 220 while (hlen > 0) { 221 putchar(ch); 222 TCHECK(*cp); 223 opt = *cp++; 224 if (ZEROLENOPT(opt)) 225 len = 1; 226 else { 227 TCHECK(*cp); 228 len = *cp++; /* total including type, len */ 229 if (len < 2 || len > hlen) 230 goto bad; 231 --hlen; /* account for length byte */ 232 } 233 --hlen; /* account for type byte */ 234 datalen = 0; 235 236 /* Bail if "l" bytes of data are not left or were not captured */ 237 #define LENCHECK(l) { if ((l) > hlen) goto bad; TCHECK2(*cp, l); } 238 239 switch (opt) { 240 241 case TCPOPT_MAXSEG: 242 (void)printf("mss"); 243 datalen = 2; 244 LENCHECK(datalen); 245 (void)printf(" %u", EXTRACT_16BITS(cp)); 246 247 break; 248 249 case TCPOPT_EOL: 250 (void)printf("eol"); 251 break; 252 253 case TCPOPT_NOP: 254 (void)printf("nop"); 255 break; 256 257 case TCPOPT_WSCALE: 258 (void)printf("wscale"); 259 datalen = 1; 260 LENCHECK(datalen); 261 (void)printf(" %u", *cp); 262 break; 263 264 case TCPOPT_SACKOK: 265 (void)printf("sackOK"); 266 if (len != 2) 267 (void)printf("[len %d]", len); 268 break; 269 270 case TCPOPT_SACK: 271 { 272 u_long s, e; 273 274 datalen = len - 2; 275 if ((datalen % TCPOLEN_SACK) != 0 || 276 !(flags & TH_ACK)) { 277 (void)printf("malformed sack "); 278 (void)printf("[len %d] ", datalen); 279 break; 280 } 281 printf("sack %d ", datalen/TCPOLEN_SACK); 282 for (i = 0; i < datalen; i += TCPOLEN_SACK) { 283 LENCHECK (i + TCPOLEN_SACK); 284 s = EXTRACT_32BITS(cp + i); 285 e = EXTRACT_32BITS(cp + i + 4); 286 if (!Sflag) 287 if (rev) { 288 s -= th->seq; 289 e -= th->seq; 290 } else { 291 s -= th->ack; 292 e -= th->ack; 293 } 294 (void) printf("{%u:%u} ", s, e); 295 } 296 break; 297 } 298 case TCPOPT_ECHO: 299 (void)printf("echo"); 300 datalen = 4; 301 LENCHECK(datalen); 302 (void)printf(" %u", EXTRACT_32BITS(cp)); 303 break; 304 305 case TCPOPT_ECHOREPLY: 306 (void)printf("echoreply"); 307 datalen = 4; 308 LENCHECK(datalen); 309 (void)printf(" %u", EXTRACT_32BITS(cp)); 310 break; 311 312 case TCPOPT_TIMESTAMP: 313 (void)printf("timestamp"); 314 datalen = 8; 315 LENCHECK(4); 316 (void)printf(" %u", EXTRACT_32BITS(cp)); 317 LENCHECK(datalen); 318 (void)printf(" %u", EXTRACT_32BITS(cp + 4)); 319 break; 320 321 case TCPOPT_CC: 322 (void)printf("cc"); 323 datalen = 4; 324 LENCHECK(datalen); 325 (void)printf(" %u", EXTRACT_32BITS(cp)); 326 break; 327 328 case TCPOPT_CCNEW: 329 (void)printf("ccnew"); 330 datalen = 4; 331 LENCHECK(datalen); 332 (void)printf(" %u", EXTRACT_32BITS(cp)); 333 break; 334 335 case TCPOPT_CCECHO: 336 (void)printf("ccecho"); 337 datalen = 4; 338 LENCHECK(datalen); 339 (void)printf(" %u", EXTRACT_32BITS(cp)); 340 break; 341 342 default: 343 (void)printf("opt-%d:", opt); 344 datalen = len - 2; 345 for (i = 0; i < datalen; ++i) { 346 LENCHECK(i); 347 (void)printf("%02x", cp[i]); 348 } 349 break; 350 } 351 352 /* Account for data printed */ 353 cp += datalen; 354 hlen -= datalen; 355 356 /* Check specification against observed length */ 357 ++datalen; /* option octet */ 358 if (!ZEROLENOPT(opt)) 359 ++datalen; /* size octet */ 360 if (datalen != len) 361 (void)printf("[len %d]", len); 362 ch = ','; 363 if (opt == TCPOPT_EOL) 364 break; 365 } 366 putchar('>'); 367 } 368 return; 369 bad: 370 fputs("[bad opt]", stdout); 371 if (ch != '\0') 372 putchar('>'); 373 return; 374 trunc: 375 fputs("[|tcp]", stdout); 376 if (ch != '\0') 377 putchar('>'); 378 } 379 380