print-tcp.c revision 39297
117680Spst/* 239297Sfenner * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 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[] = 2439297Sfenner "@(#) $Header: print-tcp.c,v 1.55 97/06/15 13:20:28 leres 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 3739297Sfenner#ifdef HAVE_MEMORY_H 3839297Sfenner#include <memory.h> 3939297Sfenner#endif 4017680Spst#include <stdio.h> 4117680Spst#include <stdlib.h> 4217680Spst#include <string.h> 4317680Spst#include <unistd.h> 4417680Spst 4517680Spst#include "interface.h" 4617680Spst#include "addrtoname.h" 4717680Spst#include "extract.h" 4817680Spst 4917680Spst/* Compatibility */ 5017680Spst#ifndef TCPOPT_WSCALE 5117680Spst#define TCPOPT_WSCALE 3 /* window scale factor (rfc1072) */ 5217680Spst#endif 5317680Spst#ifndef TCPOPT_SACKOK 5417680Spst#define TCPOPT_SACKOK 4 /* selective ack ok (rfc1072) */ 5517680Spst#endif 5617680Spst#ifndef TCPOPT_SACK 5717680Spst#define TCPOPT_SACK 5 /* selective ack (rfc1072) */ 5817680Spst#endif 5917680Spst#ifndef TCPOPT_ECHO 6017680Spst#define TCPOPT_ECHO 6 /* echo (rfc1072) */ 6117680Spst#endif 6217680Spst#ifndef TCPOPT_ECHOREPLY 6317680Spst#define TCPOPT_ECHOREPLY 7 /* echo (rfc1072) */ 6417680Spst#endif 6517680Spst#ifndef TCPOPT_TIMESTAMP 6617680Spst#define TCPOPT_TIMESTAMP 8 /* timestamps (rfc1323) */ 6717680Spst#endif 6817680Spst#ifndef TCPOPT_CC 6917680Spst#define TCPOPT_CC 11 /* T/TCP CC options (rfc1644) */ 7017680Spst#endif 7117680Spst#ifndef TCPOPT_CCNEW 7217680Spst#define TCPOPT_CCNEW 12 /* T/TCP CC options (rfc1644) */ 7317680Spst#endif 7417680Spst#ifndef TCPOPT_CCECHO 7517680Spst#define TCPOPT_CCECHO 13 /* T/TCP CC options (rfc1644) */ 7617680Spst#endif 7717680Spst 7817680Spststruct tha { 7917680Spst struct in_addr src; 8017680Spst struct in_addr dst; 8117680Spst u_int port; 8217680Spst}; 8317680Spst 8417680Spststruct tcp_seq_hash { 8517680Spst struct tcp_seq_hash *nxt; 8617680Spst struct tha addr; 8717680Spst tcp_seq seq; 8817680Spst tcp_seq ack; 8917680Spst}; 9017680Spst 9117680Spst#define TSEQ_HASHSIZE 919 9217680Spst 9317680Spst/* These tcp optinos do not have the size octet */ 9417680Spst#define ZEROLENOPT(o) ((o) == TCPOPT_EOL || (o) == TCPOPT_NOP) 9517680Spst 9617680Spststatic struct tcp_seq_hash tcp_seq_hash[TSEQ_HASHSIZE]; 9717680Spst 9817680Spst 9917680Spstvoid 10017680Spsttcp_print(register const u_char *bp, register u_int length, 10117680Spst register const u_char *bp2) 10217680Spst{ 10317680Spst register const struct tcphdr *tp; 10417680Spst register const struct ip *ip; 10517680Spst register u_char flags; 10626180Sfenner register int hlen; 10717680Spst register char ch; 10817680Spst u_short sport, dport, win, urp; 10917680Spst u_int32_t seq, ack; 11017680Spst 11117680Spst tp = (struct tcphdr *)bp; 11217680Spst ip = (struct ip *)bp2; 11317680Spst ch = '\0'; 11417680Spst TCHECK(*tp); 11517680Spst if (length < sizeof(*tp)) { 11617680Spst (void)printf("truncated-tcp %d", length); 11717680Spst return; 11817680Spst } 11917680Spst 12017680Spst sport = ntohs(tp->th_sport); 12117680Spst dport = ntohs(tp->th_dport); 12217680Spst seq = ntohl(tp->th_seq); 12317680Spst ack = ntohl(tp->th_ack); 12417680Spst win = ntohs(tp->th_win); 12517680Spst urp = ntohs(tp->th_urp); 12617680Spst 12717680Spst (void)printf("%s.%s > %s.%s: ", 12817680Spst ipaddr_string(&ip->ip_src), tcpport_string(sport), 12917680Spst ipaddr_string(&ip->ip_dst), tcpport_string(dport)); 13017680Spst 13117680Spst if (qflag) { 13217680Spst (void)printf("tcp %d", length - tp->th_off * 4); 13317680Spst return; 13417680Spst } 13517680Spst if ((flags = tp->th_flags) & (TH_SYN|TH_FIN|TH_RST|TH_PUSH)) { 13617680Spst if (flags & TH_SYN) 13717680Spst putchar('S'); 13817680Spst if (flags & TH_FIN) 13917680Spst putchar('F'); 14017680Spst if (flags & TH_RST) 14117680Spst putchar('R'); 14217680Spst if (flags & TH_PUSH) 14317680Spst putchar('P'); 14417680Spst } else 14517680Spst putchar('.'); 14617680Spst 14717680Spst if (!Sflag && (flags & TH_ACK)) { 14817680Spst register struct tcp_seq_hash *th; 14917680Spst register int rev; 15017680Spst struct tha tha; 15117680Spst /* 15217680Spst * Find (or record) the initial sequence numbers for 15317680Spst * this conversation. (we pick an arbitrary 15417680Spst * collating order so there's only one entry for 15517680Spst * both directions). 15617680Spst */ 15717680Spst if (sport < dport || 15817680Spst (sport == dport && 15917680Spst ip->ip_src.s_addr < ip->ip_dst.s_addr)) { 16017680Spst tha.src = ip->ip_src, tha.dst = ip->ip_dst; 16117680Spst tha.port = sport << 16 | dport; 16217680Spst rev = 0; 16317680Spst } else { 16417680Spst tha.src = ip->ip_dst, tha.dst = ip->ip_src; 16517680Spst tha.port = dport << 16 | sport; 16617680Spst rev = 1; 16717680Spst } 16817680Spst 16917680Spst for (th = &tcp_seq_hash[tha.port % TSEQ_HASHSIZE]; 17017680Spst th->nxt; th = th->nxt) 17117680Spst if (!memcmp((char *)&tha, (char *)&th->addr, 17217680Spst sizeof(th->addr))) 17317680Spst break; 17417680Spst 17517680Spst if (!th->nxt || flags & TH_SYN) { 17617680Spst /* didn't find it or new conversation */ 17717680Spst if (th->nxt == NULL) { 17817680Spst th->nxt = (struct tcp_seq_hash *) 17917680Spst calloc(1, sizeof(*th)); 18017680Spst if (th->nxt == NULL) 18117680Spst error("tcp_print: calloc"); 18217680Spst } 18317680Spst th->addr = tha; 18417680Spst if (rev) 18517680Spst th->ack = seq, th->seq = ack - 1; 18617680Spst else 18717680Spst th->seq = seq, th->ack = ack - 1; 18817680Spst } else { 18917680Spst if (rev) 19017680Spst seq -= th->ack, ack -= th->seq; 19117680Spst else 19217680Spst seq -= th->seq, ack -= th->ack; 19317680Spst } 19417680Spst } 19517680Spst hlen = tp->th_off * 4; 19626180Sfenner if (hlen > length) { 19726180Sfenner (void)printf(" [bad hdr length]"); 19826180Sfenner return; 19926180Sfenner } 20017680Spst length -= hlen; 20117680Spst if (length > 0 || flags & (TH_SYN | TH_FIN | TH_RST)) 20217680Spst (void)printf(" %u:%u(%d)", seq, seq + length, length); 20317680Spst if (flags & TH_ACK) 20417680Spst (void)printf(" ack %u", ack); 20517680Spst 20617680Spst (void)printf(" win %d", win); 20717680Spst 20817680Spst if (flags & TH_URG) 20917680Spst (void)printf(" urg %d", urp); 21017680Spst /* 21117680Spst * Handle any options. 21217680Spst */ 21317680Spst if ((hlen -= sizeof(*tp)) > 0) { 21417680Spst register const u_char *cp; 21517680Spst register int i, opt, len, datalen; 21617680Spst 21717680Spst cp = (const u_char *)tp + sizeof(*tp); 21817680Spst putchar(' '); 21917680Spst ch = '<'; 22017680Spst while (hlen > 0) { 22117680Spst putchar(ch); 22226180Sfenner TCHECK(*cp); 22317680Spst opt = *cp++; 22417680Spst if (ZEROLENOPT(opt)) 22517680Spst len = 1; 22617680Spst else { 22726180Sfenner TCHECK(*cp); 22826180Sfenner len = *cp++; /* total including type, len */ 22926180Sfenner if (len < 2 || len > hlen) 23026180Sfenner goto bad; 23126180Sfenner --hlen; /* account for length byte */ 23217680Spst } 23326180Sfenner --hlen; /* account for type byte */ 23417680Spst datalen = 0; 23526180Sfenner 23626180Sfenner/* Bail if "l" bytes of data are not left or were not captured */ 23726180Sfenner#define LENCHECK(l) { if ((l) > hlen) goto bad; TCHECK2(*cp, l); } 23826180Sfenner 23917680Spst switch (opt) { 24017680Spst 24117680Spst case TCPOPT_MAXSEG: 24217680Spst (void)printf("mss"); 24317680Spst datalen = 2; 24426180Sfenner LENCHECK(datalen); 24517680Spst (void)printf(" %u", EXTRACT_16BITS(cp)); 24617680Spst 24717680Spst break; 24817680Spst 24917680Spst case TCPOPT_EOL: 25017680Spst (void)printf("eol"); 25117680Spst break; 25217680Spst 25317680Spst case TCPOPT_NOP: 25417680Spst (void)printf("nop"); 25517680Spst break; 25617680Spst 25717680Spst case TCPOPT_WSCALE: 25817680Spst (void)printf("wscale"); 25917680Spst datalen = 1; 26026180Sfenner LENCHECK(datalen); 26117680Spst (void)printf(" %u", *cp); 26217680Spst break; 26317680Spst 26417680Spst case TCPOPT_SACKOK: 26517680Spst (void)printf("sackOK"); 26617680Spst break; 26717680Spst 26817680Spst case TCPOPT_SACK: 26917680Spst (void)printf("sack"); 27017680Spst datalen = len - 2; 27126180Sfenner for (i = 0; i < datalen; i += 4) { 27226180Sfenner LENCHECK(i + 4); 27317680Spst /* block-size@relative-origin */ 27417680Spst (void)printf(" %u@%u", 27526180Sfenner EXTRACT_16BITS(cp + i + 2), 27626180Sfenner EXTRACT_16BITS(cp + i)); 27717680Spst } 27817680Spst if (datalen % 4) 27917680Spst (void)printf("[len %d]", len); 28017680Spst break; 28117680Spst 28217680Spst case TCPOPT_ECHO: 28317680Spst (void)printf("echo"); 28417680Spst datalen = 4; 28526180Sfenner LENCHECK(datalen); 28617680Spst (void)printf(" %u", EXTRACT_32BITS(cp)); 28717680Spst break; 28817680Spst 28917680Spst case TCPOPT_ECHOREPLY: 29017680Spst (void)printf("echoreply"); 29117680Spst datalen = 4; 29226180Sfenner LENCHECK(datalen); 29317680Spst (void)printf(" %u", EXTRACT_32BITS(cp)); 29417680Spst break; 29517680Spst 29617680Spst case TCPOPT_TIMESTAMP: 29717680Spst (void)printf("timestamp"); 29826180Sfenner datalen = 8; 29926180Sfenner LENCHECK(4); 30017680Spst (void)printf(" %u", EXTRACT_32BITS(cp)); 30126180Sfenner LENCHECK(datalen); 30217680Spst (void)printf(" %u", EXTRACT_32BITS(cp + 4)); 30317680Spst break; 30417680Spst 30517680Spst case TCPOPT_CC: 30617680Spst (void)printf("cc"); 30717680Spst datalen = 4; 30826180Sfenner LENCHECK(datalen); 30917680Spst (void)printf(" %u", EXTRACT_32BITS(cp)); 31017680Spst break; 31117680Spst 31217680Spst case TCPOPT_CCNEW: 31317680Spst (void)printf("ccnew"); 31417680Spst datalen = 4; 31526180Sfenner LENCHECK(datalen); 31617680Spst (void)printf(" %u", EXTRACT_32BITS(cp)); 31717680Spst break; 31817680Spst 31917680Spst case TCPOPT_CCECHO: 32017680Spst (void)printf("ccecho"); 32117680Spst datalen = 4; 32226180Sfenner LENCHECK(datalen); 32317680Spst (void)printf(" %u", EXTRACT_32BITS(cp)); 32417680Spst break; 32517680Spst 32617680Spst default: 32717680Spst (void)printf("opt-%d:", opt); 32817680Spst datalen = len - 2; 32917680Spst for (i = 0; i < datalen; ++i) { 33026180Sfenner LENCHECK(i); 33117680Spst (void)printf("%02x", cp[i]); 33217680Spst } 33317680Spst break; 33417680Spst } 33517680Spst 33617680Spst /* Account for data printed */ 33717680Spst cp += datalen; 33817680Spst hlen -= datalen; 33917680Spst 34017680Spst /* Check specification against observed length */ 34117680Spst ++datalen; /* option octet */ 34217680Spst if (!ZEROLENOPT(opt)) 34317680Spst ++datalen; /* size octet */ 34417680Spst if (datalen != len) 34517680Spst (void)printf("[len %d]", len); 34617680Spst ch = ','; 34726180Sfenner if (opt == TCPOPT_EOL) 34826180Sfenner break; 34917680Spst } 35017680Spst putchar('>'); 35117680Spst } 35217680Spst return; 35326180Sfennerbad: 35426180Sfenner fputs("[bad opt]", stdout); 35526180Sfenner if (ch != '\0') 35626180Sfenner putchar('>'); 35726180Sfenner return; 35817680Spsttrunc: 35917680Spst fputs("[|tcp]", stdout); 36017680Spst if (ch != '\0') 36117680Spst putchar('>'); 36217680Spst} 36317680Spst 364