print-tcp.c revision 26180
117680Spst/* 217680Spst * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996 317680Spst * The Regents of the University of California. All rights reserved. 417680Spst * 517680Spst * Redistribution and use in source and binary forms, with or without 617680Spst * modification, are permitted provided that: (1) source code distributions 717680Spst * retain the above copyright notice and this paragraph in its entirety, (2) 817680Spst * distributions including binary code include the above copyright notice and 917680Spst * this paragraph in its entirety in the documentation or other materials 1017680Spst * provided with the distribution, and (3) all advertising materials mentioning 1117680Spst * features or use of this software display the following acknowledgement: 1217680Spst * ``This product includes software developed by the University of California, 1317680Spst * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 1417680Spst * the University nor the names of its contributors may be used to endorse 1517680Spst * or promote products derived from this software without specific prior 1617680Spst * written permission. 1717680Spst * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 1817680Spst * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 1917680Spst * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 2017680Spst */ 2117680Spst 2217680Spst#ifndef lint 2326180Sfennerstatic const char rcsid[] = 2426180Sfenner "@(#) $Header: print-tcp.c,v 1.52 96/12/03 10:59:55 vern Exp $ (LBL)"; 2517680Spst#endif 2617680Spst 2717680Spst#include <sys/param.h> 2817680Spst#include <sys/time.h> 2917680Spst 3017680Spst#include <netinet/in.h> 3117680Spst#include <netinet/in_systm.h> 3217680Spst#include <netinet/ip.h> 3317680Spst#include <netinet/ip_var.h> 3417680Spst#include <netinet/tcp.h> 3517680Spst#include <netinet/tcpip.h> 3617680Spst 3717680Spst#include <stdio.h> 3817680Spst#include <stdlib.h> 3917680Spst#include <string.h> 4017680Spst#include <unistd.h> 4117680Spst 4217680Spst#include "interface.h" 4317680Spst#include "addrtoname.h" 4417680Spst#include "extract.h" 4517680Spst 4617680Spst/* Compatibility */ 4717680Spst#ifndef TCPOPT_WSCALE 4817680Spst#define TCPOPT_WSCALE 3 /* window scale factor (rfc1072) */ 4917680Spst#endif 5017680Spst#ifndef TCPOPT_SACKOK 5117680Spst#define TCPOPT_SACKOK 4 /* selective ack ok (rfc1072) */ 5217680Spst#endif 5317680Spst#ifndef TCPOPT_SACK 5417680Spst#define TCPOPT_SACK 5 /* selective ack (rfc1072) */ 5517680Spst#endif 5617680Spst#ifndef TCPOPT_ECHO 5717680Spst#define TCPOPT_ECHO 6 /* echo (rfc1072) */ 5817680Spst#endif 5917680Spst#ifndef TCPOPT_ECHOREPLY 6017680Spst#define TCPOPT_ECHOREPLY 7 /* echo (rfc1072) */ 6117680Spst#endif 6217680Spst#ifndef TCPOPT_TIMESTAMP 6317680Spst#define TCPOPT_TIMESTAMP 8 /* timestamps (rfc1323) */ 6417680Spst#endif 6517680Spst#ifndef TCPOPT_CC 6617680Spst#define TCPOPT_CC 11 /* T/TCP CC options (rfc1644) */ 6717680Spst#endif 6817680Spst#ifndef TCPOPT_CCNEW 6917680Spst#define TCPOPT_CCNEW 12 /* T/TCP CC options (rfc1644) */ 7017680Spst#endif 7117680Spst#ifndef TCPOPT_CCECHO 7217680Spst#define TCPOPT_CCECHO 13 /* T/TCP CC options (rfc1644) */ 7317680Spst#endif 7417680Spst 7517680Spststruct tha { 7617680Spst struct in_addr src; 7717680Spst struct in_addr dst; 7817680Spst u_int port; 7917680Spst}; 8017680Spst 8117680Spststruct tcp_seq_hash { 8217680Spst struct tcp_seq_hash *nxt; 8317680Spst struct tha addr; 8417680Spst tcp_seq seq; 8517680Spst tcp_seq ack; 8617680Spst}; 8717680Spst 8817680Spst#define TSEQ_HASHSIZE 919 8917680Spst 9017680Spst/* These tcp optinos do not have the size octet */ 9117680Spst#define ZEROLENOPT(o) ((o) == TCPOPT_EOL || (o) == TCPOPT_NOP) 9217680Spst 9317680Spststatic struct tcp_seq_hash tcp_seq_hash[TSEQ_HASHSIZE]; 9417680Spst 9517680Spst 9617680Spstvoid 9717680Spsttcp_print(register const u_char *bp, register u_int length, 9817680Spst register const u_char *bp2) 9917680Spst{ 10017680Spst register const struct tcphdr *tp; 10117680Spst register const struct ip *ip; 10217680Spst register u_char flags; 10326180Sfenner register int hlen; 10417680Spst register char ch; 10517680Spst u_short sport, dport, win, urp; 10617680Spst u_int32_t seq, ack; 10717680Spst 10817680Spst tp = (struct tcphdr *)bp; 10917680Spst ip = (struct ip *)bp2; 11017680Spst ch = '\0'; 11117680Spst TCHECK(*tp); 11217680Spst if (length < sizeof(*tp)) { 11317680Spst (void)printf("truncated-tcp %d", length); 11417680Spst return; 11517680Spst } 11617680Spst 11717680Spst sport = ntohs(tp->th_sport); 11817680Spst dport = ntohs(tp->th_dport); 11917680Spst seq = ntohl(tp->th_seq); 12017680Spst ack = ntohl(tp->th_ack); 12117680Spst win = ntohs(tp->th_win); 12217680Spst urp = ntohs(tp->th_urp); 12317680Spst 12417680Spst (void)printf("%s.%s > %s.%s: ", 12517680Spst ipaddr_string(&ip->ip_src), tcpport_string(sport), 12617680Spst ipaddr_string(&ip->ip_dst), tcpport_string(dport)); 12717680Spst 12817680Spst if (qflag) { 12917680Spst (void)printf("tcp %d", length - tp->th_off * 4); 13017680Spst return; 13117680Spst } 13217680Spst if ((flags = tp->th_flags) & (TH_SYN|TH_FIN|TH_RST|TH_PUSH)) { 13317680Spst if (flags & TH_SYN) 13417680Spst putchar('S'); 13517680Spst if (flags & TH_FIN) 13617680Spst putchar('F'); 13717680Spst if (flags & TH_RST) 13817680Spst putchar('R'); 13917680Spst if (flags & TH_PUSH) 14017680Spst putchar('P'); 14117680Spst } else 14217680Spst putchar('.'); 14317680Spst 14417680Spst if (!Sflag && (flags & TH_ACK)) { 14517680Spst register struct tcp_seq_hash *th; 14617680Spst register int rev; 14717680Spst struct tha tha; 14817680Spst /* 14917680Spst * Find (or record) the initial sequence numbers for 15017680Spst * this conversation. (we pick an arbitrary 15117680Spst * collating order so there's only one entry for 15217680Spst * both directions). 15317680Spst */ 15417680Spst if (sport < dport || 15517680Spst (sport == dport && 15617680Spst ip->ip_src.s_addr < ip->ip_dst.s_addr)) { 15717680Spst tha.src = ip->ip_src, tha.dst = ip->ip_dst; 15817680Spst tha.port = sport << 16 | dport; 15917680Spst rev = 0; 16017680Spst } else { 16117680Spst tha.src = ip->ip_dst, tha.dst = ip->ip_src; 16217680Spst tha.port = dport << 16 | sport; 16317680Spst rev = 1; 16417680Spst } 16517680Spst 16617680Spst for (th = &tcp_seq_hash[tha.port % TSEQ_HASHSIZE]; 16717680Spst th->nxt; th = th->nxt) 16817680Spst if (!memcmp((char *)&tha, (char *)&th->addr, 16917680Spst sizeof(th->addr))) 17017680Spst break; 17117680Spst 17217680Spst if (!th->nxt || flags & TH_SYN) { 17317680Spst /* didn't find it or new conversation */ 17417680Spst if (th->nxt == NULL) { 17517680Spst th->nxt = (struct tcp_seq_hash *) 17617680Spst calloc(1, sizeof(*th)); 17717680Spst if (th->nxt == NULL) 17817680Spst error("tcp_print: calloc"); 17917680Spst } 18017680Spst th->addr = tha; 18117680Spst if (rev) 18217680Spst th->ack = seq, th->seq = ack - 1; 18317680Spst else 18417680Spst th->seq = seq, th->ack = ack - 1; 18517680Spst } else { 18617680Spst if (rev) 18717680Spst seq -= th->ack, ack -= th->seq; 18817680Spst else 18917680Spst seq -= th->seq, ack -= th->ack; 19017680Spst } 19117680Spst } 19217680Spst hlen = tp->th_off * 4; 19326180Sfenner if (hlen > length) { 19426180Sfenner (void)printf(" [bad hdr length]"); 19526180Sfenner return; 19626180Sfenner } 19717680Spst length -= hlen; 19817680Spst if (length > 0 || flags & (TH_SYN | TH_FIN | TH_RST)) 19917680Spst (void)printf(" %u:%u(%d)", seq, seq + length, length); 20017680Spst if (flags & TH_ACK) 20117680Spst (void)printf(" ack %u", ack); 20217680Spst 20317680Spst (void)printf(" win %d", win); 20417680Spst 20517680Spst if (flags & TH_URG) 20617680Spst (void)printf(" urg %d", urp); 20717680Spst /* 20817680Spst * Handle any options. 20917680Spst */ 21017680Spst if ((hlen -= sizeof(*tp)) > 0) { 21117680Spst register const u_char *cp; 21217680Spst register int i, opt, len, datalen; 21317680Spst 21417680Spst cp = (const u_char *)tp + sizeof(*tp); 21517680Spst putchar(' '); 21617680Spst ch = '<'; 21717680Spst while (hlen > 0) { 21817680Spst putchar(ch); 21926180Sfenner TCHECK(*cp); 22017680Spst opt = *cp++; 22117680Spst if (ZEROLENOPT(opt)) 22217680Spst len = 1; 22317680Spst else { 22426180Sfenner TCHECK(*cp); 22526180Sfenner len = *cp++; /* total including type, len */ 22626180Sfenner if (len < 2 || len > hlen) 22726180Sfenner goto bad; 22826180Sfenner --hlen; /* account for length byte */ 22917680Spst } 23026180Sfenner --hlen; /* account for type byte */ 23117680Spst datalen = 0; 23226180Sfenner 23326180Sfenner/* Bail if "l" bytes of data are not left or were not captured */ 23426180Sfenner#define LENCHECK(l) { if ((l) > hlen) goto bad; TCHECK2(*cp, l); } 23526180Sfenner 23617680Spst switch (opt) { 23717680Spst 23817680Spst case TCPOPT_MAXSEG: 23917680Spst (void)printf("mss"); 24017680Spst datalen = 2; 24126180Sfenner LENCHECK(datalen); 24217680Spst (void)printf(" %u", EXTRACT_16BITS(cp)); 24317680Spst 24417680Spst break; 24517680Spst 24617680Spst case TCPOPT_EOL: 24717680Spst (void)printf("eol"); 24817680Spst break; 24917680Spst 25017680Spst case TCPOPT_NOP: 25117680Spst (void)printf("nop"); 25217680Spst break; 25317680Spst 25417680Spst case TCPOPT_WSCALE: 25517680Spst (void)printf("wscale"); 25617680Spst datalen = 1; 25726180Sfenner LENCHECK(datalen); 25817680Spst (void)printf(" %u", *cp); 25917680Spst break; 26017680Spst 26117680Spst case TCPOPT_SACKOK: 26217680Spst (void)printf("sackOK"); 26317680Spst break; 26417680Spst 26517680Spst case TCPOPT_SACK: 26617680Spst (void)printf("sack"); 26717680Spst datalen = len - 2; 26826180Sfenner for (i = 0; i < datalen; i += 4) { 26926180Sfenner LENCHECK(i + 4); 27017680Spst /* block-size@relative-origin */ 27117680Spst (void)printf(" %u@%u", 27226180Sfenner EXTRACT_16BITS(cp + i + 2), 27326180Sfenner EXTRACT_16BITS(cp + i)); 27417680Spst } 27517680Spst if (datalen % 4) 27617680Spst (void)printf("[len %d]", len); 27717680Spst break; 27817680Spst 27917680Spst case TCPOPT_ECHO: 28017680Spst (void)printf("echo"); 28117680Spst datalen = 4; 28226180Sfenner LENCHECK(datalen); 28317680Spst (void)printf(" %u", EXTRACT_32BITS(cp)); 28417680Spst break; 28517680Spst 28617680Spst case TCPOPT_ECHOREPLY: 28717680Spst (void)printf("echoreply"); 28817680Spst datalen = 4; 28926180Sfenner LENCHECK(datalen); 29017680Spst (void)printf(" %u", EXTRACT_32BITS(cp)); 29117680Spst break; 29217680Spst 29317680Spst case TCPOPT_TIMESTAMP: 29417680Spst (void)printf("timestamp"); 29526180Sfenner datalen = 8; 29626180Sfenner LENCHECK(4); 29717680Spst (void)printf(" %u", EXTRACT_32BITS(cp)); 29826180Sfenner LENCHECK(datalen); 29917680Spst (void)printf(" %u", EXTRACT_32BITS(cp + 4)); 30017680Spst break; 30117680Spst 30217680Spst case TCPOPT_CC: 30317680Spst (void)printf("cc"); 30417680Spst datalen = 4; 30526180Sfenner LENCHECK(datalen); 30617680Spst (void)printf(" %u", EXTRACT_32BITS(cp)); 30717680Spst break; 30817680Spst 30917680Spst case TCPOPT_CCNEW: 31017680Spst (void)printf("ccnew"); 31117680Spst datalen = 4; 31226180Sfenner LENCHECK(datalen); 31317680Spst (void)printf(" %u", EXTRACT_32BITS(cp)); 31417680Spst break; 31517680Spst 31617680Spst case TCPOPT_CCECHO: 31717680Spst (void)printf("ccecho"); 31817680Spst datalen = 4; 31926180Sfenner LENCHECK(datalen); 32017680Spst (void)printf(" %u", EXTRACT_32BITS(cp)); 32117680Spst break; 32217680Spst 32317680Spst default: 32417680Spst (void)printf("opt-%d:", opt); 32517680Spst datalen = len - 2; 32617680Spst for (i = 0; i < datalen; ++i) { 32726180Sfenner LENCHECK(i); 32817680Spst (void)printf("%02x", cp[i]); 32917680Spst } 33017680Spst break; 33117680Spst } 33217680Spst 33317680Spst /* Account for data printed */ 33417680Spst cp += datalen; 33517680Spst hlen -= datalen; 33617680Spst 33717680Spst /* Check specification against observed length */ 33817680Spst ++datalen; /* option octet */ 33917680Spst if (!ZEROLENOPT(opt)) 34017680Spst ++datalen; /* size octet */ 34117680Spst if (datalen != len) 34217680Spst (void)printf("[len %d]", len); 34317680Spst ch = ','; 34426180Sfenner if (opt == TCPOPT_EOL) 34526180Sfenner break; 34617680Spst } 34717680Spst putchar('>'); 34817680Spst } 34917680Spst return; 35026180Sfennerbad: 35126180Sfenner fputs("[bad opt]", stdout); 35226180Sfenner if (ch != '\0') 35326180Sfenner putchar('>'); 35426180Sfenner return; 35517680Spsttrunc: 35617680Spst fputs("[|tcp]", stdout); 35717680Spst if (ch != '\0') 35817680Spst putchar('>'); 35917680Spst} 36017680Spst 361