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