print-tcp.c revision 26180
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 23static const char rcsid[] = 24 "@(#) $Header: print-tcp.c,v 1.52 96/12/03 10:59:55 vern 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 75struct tha { 76 struct in_addr src; 77 struct in_addr dst; 78 u_int port; 79}; 80 81struct 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 93static struct tcp_seq_hash tcp_seq_hash[TSEQ_HASHSIZE]; 94 95 96void 97tcp_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 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 if (hlen > length) { 194 (void)printf(" [bad hdr length]"); 195 return; 196 } 197 length -= hlen; 198 if (length > 0 || flags & (TH_SYN | TH_FIN | TH_RST)) 199 (void)printf(" %u:%u(%d)", seq, seq + length, length); 200 if (flags & TH_ACK) 201 (void)printf(" ack %u", ack); 202 203 (void)printf(" win %d", win); 204 205 if (flags & TH_URG) 206 (void)printf(" urg %d", urp); 207 /* 208 * Handle any options. 209 */ 210 if ((hlen -= sizeof(*tp)) > 0) { 211 register const u_char *cp; 212 register int i, opt, len, datalen; 213 214 cp = (const u_char *)tp + sizeof(*tp); 215 putchar(' '); 216 ch = '<'; 217 while (hlen > 0) { 218 putchar(ch); 219 TCHECK(*cp); 220 opt = *cp++; 221 if (ZEROLENOPT(opt)) 222 len = 1; 223 else { 224 TCHECK(*cp); 225 len = *cp++; /* total including type, len */ 226 if (len < 2 || len > hlen) 227 goto bad; 228 --hlen; /* account for length byte */ 229 } 230 --hlen; /* account for type byte */ 231 datalen = 0; 232 233/* Bail if "l" bytes of data are not left or were not captured */ 234#define LENCHECK(l) { if ((l) > hlen) goto bad; TCHECK2(*cp, l); } 235 236 switch (opt) { 237 238 case TCPOPT_MAXSEG: 239 (void)printf("mss"); 240 datalen = 2; 241 LENCHECK(datalen); 242 (void)printf(" %u", EXTRACT_16BITS(cp)); 243 244 break; 245 246 case TCPOPT_EOL: 247 (void)printf("eol"); 248 break; 249 250 case TCPOPT_NOP: 251 (void)printf("nop"); 252 break; 253 254 case TCPOPT_WSCALE: 255 (void)printf("wscale"); 256 datalen = 1; 257 LENCHECK(datalen); 258 (void)printf(" %u", *cp); 259 break; 260 261 case TCPOPT_SACKOK: 262 (void)printf("sackOK"); 263 break; 264 265 case TCPOPT_SACK: 266 (void)printf("sack"); 267 datalen = len - 2; 268 for (i = 0; i < datalen; i += 4) { 269 LENCHECK(i + 4); 270 /* block-size@relative-origin */ 271 (void)printf(" %u@%u", 272 EXTRACT_16BITS(cp + i + 2), 273 EXTRACT_16BITS(cp + i)); 274 } 275 if (datalen % 4) 276 (void)printf("[len %d]", len); 277 break; 278 279 case TCPOPT_ECHO: 280 (void)printf("echo"); 281 datalen = 4; 282 LENCHECK(datalen); 283 (void)printf(" %u", EXTRACT_32BITS(cp)); 284 break; 285 286 case TCPOPT_ECHOREPLY: 287 (void)printf("echoreply"); 288 datalen = 4; 289 LENCHECK(datalen); 290 (void)printf(" %u", EXTRACT_32BITS(cp)); 291 break; 292 293 case TCPOPT_TIMESTAMP: 294 (void)printf("timestamp"); 295 datalen = 8; 296 LENCHECK(4); 297 (void)printf(" %u", EXTRACT_32BITS(cp)); 298 LENCHECK(datalen); 299 (void)printf(" %u", EXTRACT_32BITS(cp + 4)); 300 break; 301 302 case TCPOPT_CC: 303 (void)printf("cc"); 304 datalen = 4; 305 LENCHECK(datalen); 306 (void)printf(" %u", EXTRACT_32BITS(cp)); 307 break; 308 309 case TCPOPT_CCNEW: 310 (void)printf("ccnew"); 311 datalen = 4; 312 LENCHECK(datalen); 313 (void)printf(" %u", EXTRACT_32BITS(cp)); 314 break; 315 316 case TCPOPT_CCECHO: 317 (void)printf("ccecho"); 318 datalen = 4; 319 LENCHECK(datalen); 320 (void)printf(" %u", EXTRACT_32BITS(cp)); 321 break; 322 323 default: 324 (void)printf("opt-%d:", opt); 325 datalen = len - 2; 326 for (i = 0; i < datalen; ++i) { 327 LENCHECK(i); 328 (void)printf("%02x", cp[i]); 329 } 330 break; 331 } 332 333 /* Account for data printed */ 334 cp += datalen; 335 hlen -= datalen; 336 337 /* Check specification against observed length */ 338 ++datalen; /* option octet */ 339 if (!ZEROLENOPT(opt)) 340 ++datalen; /* size octet */ 341 if (datalen != len) 342 (void)printf("[len %d]", len); 343 ch = ','; 344 if (opt == TCPOPT_EOL) 345 break; 346 } 347 putchar('>'); 348 } 349 return; 350bad: 351 fputs("[bad opt]", stdout); 352 if (ch != '\0') 353 putchar('>'); 354 return; 355trunc: 356 fputs("[|tcp]", stdout); 357 if (ch != '\0') 358 putchar('>'); 359} 360 361