print-tcp.c revision 17680
1219393Sadrian/* 2219393Sadrian * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996 3219393Sadrian * The Regents of the University of California. All rights reserved. 4219393Sadrian * 5219393Sadrian * Redistribution and use in source and binary forms, with or without 6219393Sadrian * modification, are permitted provided that: (1) source code distributions 7219393Sadrian * retain the above copyright notice and this paragraph in its entirety, (2) 8219393Sadrian * distributions including binary code include the above copyright notice and 9219393Sadrian * this paragraph in its entirety in the documentation or other materials 10219393Sadrian * provided with the distribution, and (3) all advertising materials mentioning 11219393Sadrian * features or use of this software display the following acknowledgement: 12219393Sadrian * ``This product includes software developed by the University of California, 13219393Sadrian * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 14219393Sadrian * the University nor the names of its contributors may be used to endorse 15219393Sadrian * or promote products derived from this software without specific prior 16219393Sadrian * written permission. 17219393Sadrian * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 18219393Sadrian * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 19219393Sadrian * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 20219393Sadrian */ 21219393Sadrian 22219393Sadrian#ifndef lint 23219393Sadrianstatic char rcsid[] = 24219393Sadrian "@(#) $Header: print-tcp.c,v 1.46 96/07/23 14:17:27 leres Exp $ (LBL)"; 25219393Sadrian#endif 26219393Sadrian 27219393Sadrian#include <sys/param.h> 28219393Sadrian#include <sys/time.h> 29219393Sadrian 30219393Sadrian#include <netinet/in.h> 31219393Sadrian#include <netinet/in_systm.h> 32219393Sadrian#include <netinet/ip.h> 33219393Sadrian#include <netinet/ip_var.h> 34219393Sadrian#include <netinet/tcp.h> 35219393Sadrian#include <netinet/tcpip.h> 36219393Sadrian 37219393Sadrian#include <stdio.h> 38219393Sadrian#include <stdlib.h> 39219393Sadrian#include <string.h> 40219393Sadrian#include <unistd.h> 41219393Sadrian 42219393Sadrian#include "interface.h" 43219393Sadrian#include "addrtoname.h" 44219393Sadrian#include "extract.h" 45219393Sadrian 46219393Sadrian/* Compatibility */ 47219393Sadrian#ifndef TCPOPT_WSCALE 48219393Sadrian#define TCPOPT_WSCALE 3 /* window scale factor (rfc1072) */ 49219393Sadrian#endif 50219393Sadrian#ifndef TCPOPT_SACKOK 51219393Sadrian#define TCPOPT_SACKOK 4 /* selective ack ok (rfc1072) */ 52219393Sadrian#endif 53219393Sadrian#ifndef TCPOPT_SACK 54219393Sadrian#define TCPOPT_SACK 5 /* selective ack (rfc1072) */ 55219393Sadrian#endif 56219393Sadrian#ifndef TCPOPT_ECHO 57219393Sadrian#define TCPOPT_ECHO 6 /* echo (rfc1072) */ 58219393Sadrian#endif 59219393Sadrian#ifndef TCPOPT_ECHOREPLY 60219393Sadrian#define TCPOPT_ECHOREPLY 7 /* echo (rfc1072) */ 61219393Sadrian#endif 62219393Sadrian#ifndef TCPOPT_TIMESTAMP 63219393Sadrian#define TCPOPT_TIMESTAMP 8 /* timestamps (rfc1323) */ 64219393Sadrian#endif 65219393Sadrian#ifndef TCPOPT_CC 66219393Sadrian#define TCPOPT_CC 11 /* T/TCP CC options (rfc1644) */ 67219393Sadrian#endif 68219393Sadrian#ifndef TCPOPT_CCNEW 69219393Sadrian#define TCPOPT_CCNEW 12 /* T/TCP CC options (rfc1644) */ 70219393Sadrian#endif 71219393Sadrian#ifndef TCPOPT_CCECHO 72219393Sadrian#define TCPOPT_CCECHO 13 /* T/TCP CC options (rfc1644) */ 73219393Sadrian#endif 74219393Sadrian 75219393Sadrianstruct tha { 76219393Sadrian struct in_addr src; 77219393Sadrian struct in_addr dst; 78219393Sadrian u_int port; 79219393Sadrian}; 80219393Sadrian 81219393Sadrianstruct tcp_seq_hash { 82219393Sadrian struct tcp_seq_hash *nxt; 83219393Sadrian struct tha addr; 84219393Sadrian tcp_seq seq; 85219393Sadrian tcp_seq ack; 86219393Sadrian}; 87219393Sadrian 88219393Sadrian#define TSEQ_HASHSIZE 919 89219393Sadrian 90219393Sadrian/* These tcp optinos do not have the size octet */ 91219393Sadrian#define ZEROLENOPT(o) ((o) == TCPOPT_EOL || (o) == TCPOPT_NOP) 92219393Sadrian 93219393Sadrianstatic struct tcp_seq_hash tcp_seq_hash[TSEQ_HASHSIZE]; 94219393Sadrian 95219393Sadrian 96219393Sadrianvoid 97219393Sadriantcp_print(register const u_char *bp, register u_int length, 98219393Sadrian register const u_char *bp2) 99219393Sadrian{ 100219393Sadrian register const struct tcphdr *tp; 101219393Sadrian register const struct ip *ip; 102219393Sadrian register u_char flags; 103219393Sadrian register u_int hlen; 104219393Sadrian register char ch; 105219393Sadrian u_short sport, dport, win, urp; 106219393Sadrian u_int32_t seq, ack; 107219393Sadrian 108219393Sadrian tp = (struct tcphdr *)bp; 109219393Sadrian ip = (struct ip *)bp2; 110219393Sadrian ch = '\0'; 111219393Sadrian TCHECK(*tp); 112219393Sadrian if (length < sizeof(*tp)) { 113219393Sadrian (void)printf("truncated-tcp %d", length); 114219393Sadrian return; 115219393Sadrian } 116219393Sadrian 117219393Sadrian sport = ntohs(tp->th_sport); 118219393Sadrian dport = ntohs(tp->th_dport); 119219393Sadrian seq = ntohl(tp->th_seq); 120219393Sadrian ack = ntohl(tp->th_ack); 121219393Sadrian win = ntohs(tp->th_win); 122219393Sadrian urp = ntohs(tp->th_urp); 123219393Sadrian 124219393Sadrian (void)printf("%s.%s > %s.%s: ", 125219393Sadrian ipaddr_string(&ip->ip_src), tcpport_string(sport), 126219393Sadrian ipaddr_string(&ip->ip_dst), tcpport_string(dport)); 127219393Sadrian 128219393Sadrian if (qflag) { 129219393Sadrian (void)printf("tcp %d", length - tp->th_off * 4); 130219393Sadrian return; 131219393Sadrian } 132219393Sadrian if ((flags = tp->th_flags) & (TH_SYN|TH_FIN|TH_RST|TH_PUSH)) { 133219393Sadrian if (flags & TH_SYN) 134219393Sadrian putchar('S'); 135219393Sadrian if (flags & TH_FIN) 136219393Sadrian putchar('F'); 137219393Sadrian if (flags & TH_RST) 138219393Sadrian putchar('R'); 139219393Sadrian if (flags & TH_PUSH) 140219393Sadrian putchar('P'); 141219393Sadrian } else 142219393Sadrian putchar('.'); 143219393Sadrian 144219393Sadrian if (!Sflag && (flags & TH_ACK)) { 145219393Sadrian register struct tcp_seq_hash *th; 146219393Sadrian register int rev; 147219393Sadrian struct tha tha; 148219393Sadrian /* 149219393Sadrian * Find (or record) the initial sequence numbers for 150219393Sadrian * this conversation. (we pick an arbitrary 151219393Sadrian * collating order so there's only one entry for 152219393Sadrian * both directions). 153219393Sadrian */ 154219393Sadrian if (sport < dport || 155219393Sadrian (sport == dport && 156219393Sadrian ip->ip_src.s_addr < ip->ip_dst.s_addr)) { 157219393Sadrian tha.src = ip->ip_src, tha.dst = ip->ip_dst; 158219393Sadrian tha.port = sport << 16 | dport; 159219393Sadrian rev = 0; 160219393Sadrian } else { 161219393Sadrian tha.src = ip->ip_dst, tha.dst = ip->ip_src; 162219393Sadrian tha.port = dport << 16 | sport; 163219393Sadrian rev = 1; 164219393Sadrian } 165219393Sadrian 166219393Sadrian for (th = &tcp_seq_hash[tha.port % TSEQ_HASHSIZE]; 167219393Sadrian th->nxt; th = th->nxt) 168219393Sadrian if (!memcmp((char *)&tha, (char *)&th->addr, 169219393Sadrian sizeof(th->addr))) 170219393Sadrian break; 171219393Sadrian 172219393Sadrian if (!th->nxt || flags & TH_SYN) { 173219393Sadrian /* didn't find it or new conversation */ 174219393Sadrian if (th->nxt == NULL) { 175219393Sadrian th->nxt = (struct tcp_seq_hash *) 176219393Sadrian calloc(1, sizeof(*th)); 177219393Sadrian if (th->nxt == NULL) 178219393Sadrian error("tcp_print: calloc"); 179219393Sadrian } 180219393Sadrian th->addr = tha; 181219393Sadrian if (rev) 182219393Sadrian th->ack = seq, th->seq = ack - 1; 183219393Sadrian else 184219393Sadrian th->seq = seq, th->ack = ack - 1; 185219393Sadrian } else { 186219393Sadrian if (rev) 187219393Sadrian seq -= th->ack, ack -= th->seq; 188219393Sadrian else 189219393Sadrian seq -= th->seq, ack -= th->ack; 190219393Sadrian } 191219393Sadrian } 192219393Sadrian hlen = tp->th_off * 4; 193219393Sadrian length -= hlen; 194219393Sadrian if (length > 0 || flags & (TH_SYN | TH_FIN | TH_RST)) 195219393Sadrian (void)printf(" %u:%u(%d)", seq, seq + length, length); 196219393Sadrian if (flags & TH_ACK) 197219393Sadrian (void)printf(" ack %u", ack); 198219393Sadrian 199219393Sadrian (void)printf(" win %d", win); 200219393Sadrian 201219393Sadrian if (flags & TH_URG) 202219393Sadrian (void)printf(" urg %d", urp); 203219393Sadrian /* 204219393Sadrian * Handle any options. 205219393Sadrian */ 206219393Sadrian if ((hlen -= sizeof(*tp)) > 0) { 207219393Sadrian register const u_char *cp; 208219393Sadrian register int i, opt, len, datalen; 209219393Sadrian 210219393Sadrian cp = (const u_char *)tp + sizeof(*tp); 211219393Sadrian putchar(' '); 212219393Sadrian ch = '<'; 213219393Sadrian while (hlen > 0) { 214219393Sadrian --hlen; 215219393Sadrian putchar(ch); 216219393Sadrian if (cp > snapend) 217219393Sadrian goto trunc; 218219393Sadrian opt = *cp++; 219219393Sadrian if (ZEROLENOPT(opt)) 220219393Sadrian len = 1; 221219393Sadrian else { 222219393Sadrian if (cp > snapend) 223219393Sadrian goto trunc; 224219393Sadrian len = *cp++; 225219393Sadrian --hlen; 226219393Sadrian } 227219393Sadrian datalen = 0; 228219393Sadrian switch (opt) { 229219393Sadrian 230219393Sadrian case TCPOPT_MAXSEG: 231219393Sadrian (void)printf("mss"); 232219393Sadrian datalen = 2; 233219393Sadrian if (cp + datalen > snapend) 234219393Sadrian goto trunc; 235219393Sadrian (void)printf(" %u", EXTRACT_16BITS(cp)); 236219393Sadrian 237219393Sadrian break; 238219393Sadrian 239219393Sadrian case TCPOPT_EOL: 240219393Sadrian (void)printf("eol"); 241219393Sadrian break; 242219393Sadrian 243219393Sadrian case TCPOPT_NOP: 244219393Sadrian (void)printf("nop"); 245219393Sadrian break; 246219393Sadrian 247219393Sadrian case TCPOPT_WSCALE: 248219393Sadrian (void)printf("wscale"); 249219393Sadrian datalen = 1; 250219393Sadrian if (cp + datalen > snapend) 251219393Sadrian goto trunc; 252219393Sadrian (void)printf(" %u", *cp); 253219393Sadrian break; 254219393Sadrian 255219393Sadrian case TCPOPT_SACKOK: 256219393Sadrian (void)printf("sackOK"); 257219393Sadrian break; 258219393Sadrian 259219393Sadrian case TCPOPT_SACK: 260219393Sadrian (void)printf("sack"); 261219393Sadrian datalen = len - 2; 262219393Sadrian i = datalen; 263219393Sadrian for (i = datalen; i > 0; i -= 4) { 264219393Sadrian if (cp + i + 4 > snapend) 265219393Sadrian goto trunc; 266219393Sadrian /* block-size@relative-origin */ 267219393Sadrian (void)printf(" %u@%u", 268219393Sadrian EXTRACT_16BITS(cp + 2), 269219393Sadrian EXTRACT_16BITS(cp)); 270219393Sadrian } 271219393Sadrian if (datalen % 4) 272219393Sadrian (void)printf("[len %d]", len); 273219393Sadrian break; 274219393Sadrian 275219393Sadrian case TCPOPT_ECHO: 276219393Sadrian (void)printf("echo"); 277219393Sadrian datalen = 4; 278219393Sadrian if (cp + datalen > snapend) 279219393Sadrian goto trunc; 280219393Sadrian (void)printf(" %u", EXTRACT_32BITS(cp)); 281219393Sadrian break; 282219393Sadrian 283219393Sadrian case TCPOPT_ECHOREPLY: 284219393Sadrian (void)printf("echoreply"); 285219393Sadrian datalen = 4; 286219393Sadrian if (cp + datalen > snapend) 287219393Sadrian goto trunc; 288219393Sadrian (void)printf(" %u", EXTRACT_32BITS(cp)); 289219393Sadrian break; 290219393Sadrian 291219393Sadrian case TCPOPT_TIMESTAMP: 292219393Sadrian (void)printf("timestamp"); 293219393Sadrian datalen = 4; 294219393Sadrian if (cp + datalen > snapend) 295219393Sadrian goto trunc; 296219393Sadrian (void)printf(" %u", EXTRACT_32BITS(cp)); 297219393Sadrian datalen += 4; 298219393Sadrian if (cp + datalen > snapend) 299219393Sadrian goto trunc; 300219393Sadrian (void)printf(" %u", EXTRACT_32BITS(cp + 4)); 301219393Sadrian break; 302219393Sadrian 303219393Sadrian case TCPOPT_CC: 304219393Sadrian (void)printf("cc"); 305219393Sadrian datalen = 4; 306219393Sadrian if (cp + datalen > snapend) 307219393Sadrian goto trunc; 308219393Sadrian (void)printf(" %u", EXTRACT_32BITS(cp)); 309219393Sadrian break; 310219393Sadrian 311219393Sadrian case TCPOPT_CCNEW: 312219393Sadrian (void)printf("ccnew"); 313219393Sadrian datalen = 4; 314219393Sadrian if (cp + datalen > snapend) 315219393Sadrian goto trunc; 316219393Sadrian (void)printf(" %u", EXTRACT_32BITS(cp)); 317219393Sadrian break; 318219393Sadrian 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; 355trunc: 356 fputs("[|tcp]", stdout); 357 if (ch != '\0') 358 putchar('>'); 359} 360 361