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: print-tcp.c,v 1.55 97/06/15 13:20:28 leres 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 #ifdef HAVE_MEMORY_H 38 #include <memory.h> 39 #endif 40 #include <stdio.h> 41 #include <stdlib.h> 42 #include <string.h> 43 #include <unistd.h> 44 45 #include "interface.h" 46 #include "addrtoname.h" 47 #include "extract.h" 48 49 /* Compatibility */ 50 #ifndef TCPOPT_WSCALE 51 #define TCPOPT_WSCALE 3 /* window scale factor (rfc1072) */ 52 #endif 53 #ifndef TCPOPT_SACKOK 54 #define TCPOPT_SACKOK 4 /* selective ack ok (rfc1072) */ 55 #endif 56 #ifndef TCPOPT_SACK 57 #define TCPOPT_SACK 5 /* selective ack (rfc1072) */ 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 u_short sport, dport, win, urp; 109 u_int32_t seq, ack; 110 111 tp = (struct tcphdr *)bp; 112 ip = (struct ip *)bp2; 113 ch = '\0'; 114 TCHECK(*tp); 115 if (length < sizeof(*tp)) { 116 (void)printf("truncated-tcp %d", length); 117 return; 118 } 119 120 sport = ntohs(tp->th_sport); 121 dport = ntohs(tp->th_dport); 122 seq = ntohl(tp->th_seq); 123 ack = ntohl(tp->th_ack); 124 win = ntohs(tp->th_win); 125 urp = ntohs(tp->th_urp); 126 127 (void)printf("%s.%s > %s.%s: ", 128 ipaddr_string(&ip->ip_src), tcpport_string(sport), 129 ipaddr_string(&ip->ip_dst), tcpport_string(dport)); 130 131 if (qflag) { 132 (void)printf("tcp %d", length - tp->th_off * 4); 133 return; 134 } 135 if ((flags = tp->th_flags) & (TH_SYN|TH_FIN|TH_RST|TH_PUSH)) { 136 if (flags & TH_SYN) 137 putchar('S'); 138 if (flags & TH_FIN) 139 putchar('F'); 140 if (flags & TH_RST) 141 putchar('R'); 142 if (flags & TH_PUSH) 143 putchar('P'); 144 } else 145 putchar('.'); 146 147 if (!Sflag && (flags & TH_ACK)) { 148 register struct tcp_seq_hash *th; 149 register int rev; 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 break; 267 268 case TCPOPT_SACK: 269 (void)printf("sack"); 270 datalen = len - 2; 271 for (i = 0; i < datalen; i += 4) { 272 LENCHECK(i + 4); 273 /* block-size@relative-origin */ 274 (void)printf(" %u@%u", 275 EXTRACT_16BITS(cp + i + 2), 276 EXTRACT_16BITS(cp + i)); 277 } 278 if (datalen % 4) 279 (void)printf("[len %d]", len); 280 break; 281 282 case TCPOPT_ECHO: 283 (void)printf("echo"); 284 datalen = 4; 285 LENCHECK(datalen); 286 (void)printf(" %u", EXTRACT_32BITS(cp)); 287 break; 288 289 case TCPOPT_ECHOREPLY: 290 (void)printf("echoreply"); 291 datalen = 4; 292 LENCHECK(datalen); 293 (void)printf(" %u", EXTRACT_32BITS(cp)); 294 break; 295 296 case TCPOPT_TIMESTAMP: 297 (void)printf("timestamp"); 298 datalen = 8; 299 LENCHECK(4); 300 (void)printf(" %u", EXTRACT_32BITS(cp)); 301 LENCHECK(datalen); 302 (void)printf(" %u", EXTRACT_32BITS(cp + 4)); 303 break; 304 305 case TCPOPT_CC: 306 (void)printf("cc"); 307 datalen = 4; 308 LENCHECK(datalen); 309 (void)printf(" %u", EXTRACT_32BITS(cp)); 310 break; 311 312 case TCPOPT_CCNEW: 313 (void)printf("ccnew"); 314 datalen = 4; 315 LENCHECK(datalen); 316 (void)printf(" %u", EXTRACT_32BITS(cp)); 317 break; 318 319 case TCPOPT_CCECHO: 320 (void)printf("ccecho"); 321 datalen = 4; 322 LENCHECK(datalen); 323 (void)printf(" %u", EXTRACT_32BITS(cp)); 324 break; 325 326 default: 327 (void)printf("opt-%d:", opt); 328 datalen = len - 2; 329 for (i = 0; i < datalen; ++i) { 330 LENCHECK(i); 331 (void)printf("%02x", cp[i]); 332 } 333 break; 334 } 335 336 /* Account for data printed */ 337 cp += datalen; 338 hlen -= datalen; 339 340 /* Check specification against observed length */ 341 ++datalen; /* option octet */ 342 if (!ZEROLENOPT(opt)) 343 ++datalen; /* size octet */ 344 if (datalen != len) 345 (void)printf("[len %d]", len); 346 ch = ','; 347 if (opt == TCPOPT_EOL) 348 break; 349 } 350 putchar('>'); 351 } 352 return; 353 bad: 354 fputs("[bad opt]", stdout); 355 if (ch != '\0') 356 putchar('>'); 357 return; 358 trunc: 359 fputs("[|tcp]", stdout); 360 if (ch != '\0') 361 putchar('>'); 362 } 363 364