print-tcp.c revision 56893
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[] = 2456893Sfenner "@(#) $Header: /tcpdump/master/tcpdump/print-tcp.c,v 1.63 1999/12/22 15:44:10 itojun Exp $ (LBL)"; 2517680Spst#endif 2617680Spst 2756893Sfenner#ifdef HAVE_CONFIG_H 2856893Sfenner#include "config.h" 2956893Sfenner#endif 3056893Sfenner 3117680Spst#include <sys/param.h> 3217680Spst#include <sys/time.h> 3317680Spst 3417680Spst#include <netinet/in.h> 3517680Spst#include <netinet/in_systm.h> 3617680Spst#include <netinet/ip.h> 3717680Spst#include <netinet/ip_var.h> 3817680Spst#include <netinet/tcp.h> 3917680Spst 4039297Sfenner#ifdef HAVE_MEMORY_H 4139297Sfenner#include <memory.h> 4239297Sfenner#endif 4317680Spst#include <stdio.h> 4417680Spst#include <stdlib.h> 4517680Spst#include <string.h> 4617680Spst#include <unistd.h> 4717680Spst 4856893Sfenner#ifdef INET6 4956893Sfenner#include <netinet/ip6.h> 5056893Sfenner#endif 5156893Sfenner 5217680Spst#include "interface.h" 5317680Spst#include "addrtoname.h" 5417680Spst#include "extract.h" 5517680Spst 5617680Spst/* Compatibility */ 5717680Spst#ifndef TCPOPT_WSCALE 5817680Spst#define TCPOPT_WSCALE 3 /* window scale factor (rfc1072) */ 5917680Spst#endif 6017680Spst#ifndef TCPOPT_SACKOK 6117680Spst#define TCPOPT_SACKOK 4 /* selective ack ok (rfc1072) */ 6217680Spst#endif 6317680Spst#ifndef TCPOPT_SACK 6417680Spst#define TCPOPT_SACK 5 /* selective ack (rfc1072) */ 6517680Spst#endif 6617680Spst#ifndef TCPOPT_ECHO 6717680Spst#define TCPOPT_ECHO 6 /* echo (rfc1072) */ 6817680Spst#endif 6917680Spst#ifndef TCPOPT_ECHOREPLY 7017680Spst#define TCPOPT_ECHOREPLY 7 /* echo (rfc1072) */ 7117680Spst#endif 7217680Spst#ifndef TCPOPT_TIMESTAMP 7317680Spst#define TCPOPT_TIMESTAMP 8 /* timestamps (rfc1323) */ 7417680Spst#endif 7517680Spst#ifndef TCPOPT_CC 7617680Spst#define TCPOPT_CC 11 /* T/TCP CC options (rfc1644) */ 7717680Spst#endif 7817680Spst#ifndef TCPOPT_CCNEW 7917680Spst#define TCPOPT_CCNEW 12 /* T/TCP CC options (rfc1644) */ 8017680Spst#endif 8117680Spst#ifndef TCPOPT_CCECHO 8217680Spst#define TCPOPT_CCECHO 13 /* T/TCP CC options (rfc1644) */ 8317680Spst#endif 8417680Spst 8517680Spststruct tha { 8656893Sfenner#ifndef INET6 8717680Spst struct in_addr src; 8817680Spst struct in_addr dst; 8956893Sfenner#else 9056893Sfenner struct in6_addr src; 9156893Sfenner struct in6_addr dst; 9256893Sfenner#endif /*INET6*/ 9317680Spst u_int port; 9417680Spst}; 9517680Spst 9617680Spststruct tcp_seq_hash { 9717680Spst struct tcp_seq_hash *nxt; 9817680Spst struct tha addr; 9917680Spst tcp_seq seq; 10017680Spst tcp_seq ack; 10117680Spst}; 10217680Spst 10317680Spst#define TSEQ_HASHSIZE 919 10417680Spst 10517680Spst/* These tcp optinos do not have the size octet */ 10617680Spst#define ZEROLENOPT(o) ((o) == TCPOPT_EOL || (o) == TCPOPT_NOP) 10717680Spst 10817680Spststatic struct tcp_seq_hash tcp_seq_hash[TSEQ_HASHSIZE]; 10917680Spst 11017680Spst 11156893Sfenner#ifndef TELNET_PORT 11256893Sfenner#define TELNET_PORT 23 11356893Sfenner#endif 11456893Sfenner#ifndef BGP_PORT 11556893Sfenner#define BGP_PORT 179 11656893Sfenner#endif 11756893Sfenner#define NETBIOS_SSN_PORT 139 11856893Sfenner 11917680Spstvoid 12017680Spsttcp_print(register const u_char *bp, register u_int length, 12117680Spst register const u_char *bp2) 12217680Spst{ 12317680Spst register const struct tcphdr *tp; 12417680Spst register const struct ip *ip; 12517680Spst register u_char flags; 12626180Sfenner register int hlen; 12717680Spst register char ch; 12817680Spst u_short sport, dport, win, urp; 12956893Sfenner u_int32_t seq, ack, thseq, thack; 13056893Sfenner int threv; 13156893Sfenner#ifdef INET6 13256893Sfenner register const struct ip6_hdr *ip6; 13356893Sfenner#endif 13417680Spst 13517680Spst tp = (struct tcphdr *)bp; 13617680Spst ip = (struct ip *)bp2; 13756893Sfenner#ifdef INET6 13856893Sfenner if (ip->ip_v == 6) 13956893Sfenner ip6 = (struct ip6_hdr *)bp2; 14056893Sfenner else 14156893Sfenner ip6 = NULL; 14256893Sfenner#endif /*INET6*/ 14317680Spst ch = '\0'; 14456893Sfenner if (!TTEST(tp->th_dport)) { 14556893Sfenner (void)printf("%s > %s: [|tcp]", 14656893Sfenner ipaddr_string(&ip->ip_src), 14756893Sfenner ipaddr_string(&ip->ip_dst)); 14817680Spst return; 14917680Spst } 15017680Spst 15117680Spst sport = ntohs(tp->th_sport); 15217680Spst dport = ntohs(tp->th_dport); 15356893Sfenner 15456893Sfenner#ifdef INET6 15556893Sfenner if (ip6) { 15656893Sfenner if (ip6->ip6_nxt == IPPROTO_TCP) { 15756893Sfenner (void)printf("%s.%s > %s.%s: ", 15856893Sfenner ip6addr_string(&ip6->ip6_src), 15956893Sfenner tcpport_string(sport), 16056893Sfenner ip6addr_string(&ip6->ip6_dst), 16156893Sfenner tcpport_string(dport)); 16256893Sfenner } else { 16356893Sfenner (void)printf("%s > %s: ", 16456893Sfenner tcpport_string(sport), tcpport_string(dport)); 16556893Sfenner } 16656893Sfenner } else 16756893Sfenner#endif /*INET6*/ 16856893Sfenner { 16956893Sfenner if (ip->ip_p == IPPROTO_TCP) { 17056893Sfenner (void)printf("%s.%s > %s.%s: ", 17156893Sfenner ipaddr_string(&ip->ip_src), 17256893Sfenner tcpport_string(sport), 17356893Sfenner ipaddr_string(&ip->ip_dst), 17456893Sfenner tcpport_string(dport)); 17556893Sfenner } else { 17656893Sfenner (void)printf("%s > %s: ", 17756893Sfenner tcpport_string(sport), tcpport_string(dport)); 17856893Sfenner } 17956893Sfenner } 18056893Sfenner 18156893Sfenner TCHECK(*tp); 18256893Sfenner 18317680Spst seq = ntohl(tp->th_seq); 18417680Spst ack = ntohl(tp->th_ack); 18517680Spst win = ntohs(tp->th_win); 18617680Spst urp = ntohs(tp->th_urp); 18717680Spst 18817680Spst if (qflag) { 18917680Spst (void)printf("tcp %d", length - tp->th_off * 4); 19017680Spst return; 19117680Spst } 19256893Sfenner#ifdef TH_ECN 19356893Sfenner if ((flags = tp->th_flags) & (TH_SYN|TH_FIN|TH_RST|TH_PUSH|TH_ECN)) 19456893Sfenner#else 19556893Sfenner if ((flags = tp->th_flags) & (TH_SYN|TH_FIN|TH_RST|TH_PUSH)) 19656893Sfenner#endif 19756893Sfenner { 19817680Spst if (flags & TH_SYN) 19917680Spst putchar('S'); 20017680Spst if (flags & TH_FIN) 20117680Spst putchar('F'); 20217680Spst if (flags & TH_RST) 20317680Spst putchar('R'); 20417680Spst if (flags & TH_PUSH) 20517680Spst putchar('P'); 20656893Sfenner#ifdef TH_ECN 20756893Sfenner if (flags & TH_ECN) 20856893Sfenner putchar('C'); 20956893Sfenner#endif 21017680Spst } else 21117680Spst putchar('.'); 21217680Spst 21356893Sfenner if (flags&0xc0) { 21456893Sfenner printf(" ["); 21556893Sfenner if (flags&0x40) 21656893Sfenner printf("ECN-Echo"); 21756893Sfenner if (flags&0x80) 21856893Sfenner printf("%sCWR", (flags&0x40) ? "," : ""); 21956893Sfenner printf("]"); 22056893Sfenner } 22156893Sfenner 22217680Spst if (!Sflag && (flags & TH_ACK)) { 22317680Spst register struct tcp_seq_hash *th; 22417680Spst register int rev; 22517680Spst struct tha tha; 22617680Spst /* 22717680Spst * Find (or record) the initial sequence numbers for 22817680Spst * this conversation. (we pick an arbitrary 22917680Spst * collating order so there's only one entry for 23017680Spst * both directions). 23117680Spst */ 23256893Sfenner#ifdef INET6 23356893Sfenner bzero(&tha, sizeof(tha)); 23456893Sfenner rev = 0; 23556893Sfenner if (ip6) { 23656893Sfenner if (sport > dport) { 23756893Sfenner rev = 1; 23856893Sfenner } else if (sport == dport) { 23956893Sfenner int i; 24056893Sfenner 24156893Sfenner for (i = 0; i < 4; i++) { 24256893Sfenner if (((u_int32_t *)(&ip6->ip6_src))[i] > 24356893Sfenner ((u_int32_t *)(&ip6->ip6_dst))[i]) { 24456893Sfenner rev = 1; 24556893Sfenner break; 24656893Sfenner } 24756893Sfenner } 24856893Sfenner } 24956893Sfenner if (rev) { 25056893Sfenner tha.src = ip6->ip6_dst; 25156893Sfenner tha.dst = ip6->ip6_src; 25256893Sfenner tha.port = dport << 16 | sport; 25356893Sfenner } else { 25456893Sfenner tha.dst = ip6->ip6_dst; 25556893Sfenner tha.src = ip6->ip6_src; 25656893Sfenner tha.port = sport << 16 | dport; 25756893Sfenner } 25856893Sfenner } else { 25956893Sfenner if (sport > dport || 26056893Sfenner (sport == dport && 26156893Sfenner ip->ip_src.s_addr > ip->ip_dst.s_addr)) { 26256893Sfenner rev = 1; 26356893Sfenner } 26456893Sfenner if (rev) { 26556893Sfenner *(struct in_addr *)&tha.src = ip->ip_dst; 26656893Sfenner *(struct in_addr *)&tha.dst = ip->ip_src; 26756893Sfenner tha.port = dport << 16 | sport; 26856893Sfenner } else { 26956893Sfenner *(struct in_addr *)&tha.dst = ip->ip_dst; 27056893Sfenner *(struct in_addr *)&tha.src = ip->ip_src; 27156893Sfenner tha.port = sport << 16 | dport; 27256893Sfenner } 27356893Sfenner } 27456893Sfenner#else 27517680Spst if (sport < dport || 27617680Spst (sport == dport && 27717680Spst ip->ip_src.s_addr < ip->ip_dst.s_addr)) { 27817680Spst tha.src = ip->ip_src, tha.dst = ip->ip_dst; 27917680Spst tha.port = sport << 16 | dport; 28017680Spst rev = 0; 28117680Spst } else { 28217680Spst tha.src = ip->ip_dst, tha.dst = ip->ip_src; 28317680Spst tha.port = dport << 16 | sport; 28417680Spst rev = 1; 28517680Spst } 28656893Sfenner#endif 28717680Spst 28856893Sfenner threv = rev; 28917680Spst for (th = &tcp_seq_hash[tha.port % TSEQ_HASHSIZE]; 29017680Spst th->nxt; th = th->nxt) 29117680Spst if (!memcmp((char *)&tha, (char *)&th->addr, 29217680Spst sizeof(th->addr))) 29317680Spst break; 29417680Spst 29517680Spst if (!th->nxt || flags & TH_SYN) { 29617680Spst /* didn't find it or new conversation */ 29717680Spst if (th->nxt == NULL) { 29817680Spst th->nxt = (struct tcp_seq_hash *) 29917680Spst calloc(1, sizeof(*th)); 30017680Spst if (th->nxt == NULL) 30117680Spst error("tcp_print: calloc"); 30217680Spst } 30317680Spst th->addr = tha; 30417680Spst if (rev) 30517680Spst th->ack = seq, th->seq = ack - 1; 30617680Spst else 30717680Spst th->seq = seq, th->ack = ack - 1; 30817680Spst } else { 30956893Sfenner 31056893Sfenner thseq = th->seq; 31156893Sfenner thack = th->ack; 31256893Sfenner 31317680Spst if (rev) 31417680Spst seq -= th->ack, ack -= th->seq; 31517680Spst else 31617680Spst seq -= th->seq, ack -= th->ack; 31717680Spst } 31817680Spst } 31917680Spst hlen = tp->th_off * 4; 32026180Sfenner if (hlen > length) { 32126180Sfenner (void)printf(" [bad hdr length]"); 32226180Sfenner return; 32326180Sfenner } 32417680Spst length -= hlen; 32556893Sfenner if (vflag > 1 || length > 0 || flags & (TH_SYN | TH_FIN | TH_RST)) 32617680Spst (void)printf(" %u:%u(%d)", seq, seq + length, length); 32717680Spst if (flags & TH_ACK) 32817680Spst (void)printf(" ack %u", ack); 32917680Spst 33017680Spst (void)printf(" win %d", win); 33117680Spst 33217680Spst if (flags & TH_URG) 33317680Spst (void)printf(" urg %d", urp); 33417680Spst /* 33517680Spst * Handle any options. 33617680Spst */ 33717680Spst if ((hlen -= sizeof(*tp)) > 0) { 33817680Spst register const u_char *cp; 33917680Spst register int i, opt, len, datalen; 34017680Spst 34117680Spst cp = (const u_char *)tp + sizeof(*tp); 34217680Spst putchar(' '); 34317680Spst ch = '<'; 34417680Spst while (hlen > 0) { 34517680Spst putchar(ch); 34626180Sfenner TCHECK(*cp); 34717680Spst opt = *cp++; 34817680Spst if (ZEROLENOPT(opt)) 34917680Spst len = 1; 35017680Spst else { 35126180Sfenner TCHECK(*cp); 35226180Sfenner len = *cp++; /* total including type, len */ 35326180Sfenner if (len < 2 || len > hlen) 35426180Sfenner goto bad; 35526180Sfenner --hlen; /* account for length byte */ 35617680Spst } 35726180Sfenner --hlen; /* account for type byte */ 35817680Spst datalen = 0; 35926180Sfenner 36026180Sfenner/* Bail if "l" bytes of data are not left or were not captured */ 36126180Sfenner#define LENCHECK(l) { if ((l) > hlen) goto bad; TCHECK2(*cp, l); } 36226180Sfenner 36317680Spst switch (opt) { 36417680Spst 36517680Spst case TCPOPT_MAXSEG: 36617680Spst (void)printf("mss"); 36717680Spst datalen = 2; 36826180Sfenner LENCHECK(datalen); 36917680Spst (void)printf(" %u", EXTRACT_16BITS(cp)); 37017680Spst 37117680Spst break; 37217680Spst 37317680Spst case TCPOPT_EOL: 37417680Spst (void)printf("eol"); 37517680Spst break; 37617680Spst 37717680Spst case TCPOPT_NOP: 37817680Spst (void)printf("nop"); 37917680Spst break; 38017680Spst 38117680Spst case TCPOPT_WSCALE: 38217680Spst (void)printf("wscale"); 38317680Spst datalen = 1; 38426180Sfenner LENCHECK(datalen); 38517680Spst (void)printf(" %u", *cp); 38617680Spst break; 38717680Spst 38817680Spst case TCPOPT_SACKOK: 38917680Spst (void)printf("sackOK"); 39017680Spst break; 39117680Spst 39217680Spst case TCPOPT_SACK: 39317680Spst (void)printf("sack"); 39417680Spst datalen = len - 2; 39556893Sfenner if (datalen % 8 != 0) { 39656893Sfenner (void)printf(" malformed sack "); 39756893Sfenner } else { 39856893Sfenner u_int32_t s, e; 39956893Sfenner 40056893Sfenner (void)printf(" sack %d ", datalen / 8); 40156893Sfenner for (i = 0; i < datalen; i += 8) { 40256893Sfenner LENCHECK(i + 4); 40356893Sfenner s = EXTRACT_32BITS(cp + i); 40456893Sfenner LENCHECK(i + 8); 40556893Sfenner e = EXTRACT_32BITS(cp + i + 4); 40656893Sfenner if (threv) { 40756893Sfenner s -= thseq; 40856893Sfenner e -= thseq; 40956893Sfenner } else { 41056893Sfenner s -= thack; 41156893Sfenner e -= thack; 41256893Sfenner } 41356893Sfenner (void)printf("{%u:%u}", s, e); 41456893Sfenner } 41556893Sfenner (void)printf(" "); 41617680Spst } 41717680Spst break; 41817680Spst 41917680Spst case TCPOPT_ECHO: 42017680Spst (void)printf("echo"); 42117680Spst datalen = 4; 42226180Sfenner LENCHECK(datalen); 42317680Spst (void)printf(" %u", EXTRACT_32BITS(cp)); 42417680Spst break; 42517680Spst 42617680Spst case TCPOPT_ECHOREPLY: 42717680Spst (void)printf("echoreply"); 42817680Spst datalen = 4; 42926180Sfenner LENCHECK(datalen); 43017680Spst (void)printf(" %u", EXTRACT_32BITS(cp)); 43117680Spst break; 43217680Spst 43317680Spst case TCPOPT_TIMESTAMP: 43417680Spst (void)printf("timestamp"); 43526180Sfenner datalen = 8; 43626180Sfenner LENCHECK(4); 43717680Spst (void)printf(" %u", EXTRACT_32BITS(cp)); 43826180Sfenner LENCHECK(datalen); 43917680Spst (void)printf(" %u", EXTRACT_32BITS(cp + 4)); 44017680Spst break; 44117680Spst 44217680Spst case TCPOPT_CC: 44317680Spst (void)printf("cc"); 44417680Spst datalen = 4; 44526180Sfenner LENCHECK(datalen); 44617680Spst (void)printf(" %u", EXTRACT_32BITS(cp)); 44717680Spst break; 44817680Spst 44917680Spst case TCPOPT_CCNEW: 45017680Spst (void)printf("ccnew"); 45117680Spst datalen = 4; 45226180Sfenner LENCHECK(datalen); 45317680Spst (void)printf(" %u", EXTRACT_32BITS(cp)); 45417680Spst break; 45517680Spst 45617680Spst case TCPOPT_CCECHO: 45717680Spst (void)printf("ccecho"); 45817680Spst datalen = 4; 45926180Sfenner LENCHECK(datalen); 46017680Spst (void)printf(" %u", EXTRACT_32BITS(cp)); 46117680Spst break; 46217680Spst 46317680Spst default: 46417680Spst (void)printf("opt-%d:", opt); 46517680Spst datalen = len - 2; 46617680Spst for (i = 0; i < datalen; ++i) { 46726180Sfenner LENCHECK(i); 46817680Spst (void)printf("%02x", cp[i]); 46917680Spst } 47017680Spst break; 47117680Spst } 47217680Spst 47317680Spst /* Account for data printed */ 47417680Spst cp += datalen; 47517680Spst hlen -= datalen; 47617680Spst 47717680Spst /* Check specification against observed length */ 47817680Spst ++datalen; /* option octet */ 47917680Spst if (!ZEROLENOPT(opt)) 48017680Spst ++datalen; /* size octet */ 48117680Spst if (datalen != len) 48217680Spst (void)printf("[len %d]", len); 48317680Spst ch = ','; 48426180Sfenner if (opt == TCPOPT_EOL) 48526180Sfenner break; 48617680Spst } 48717680Spst putchar('>'); 48817680Spst } 48956893Sfenner 49056893Sfenner if (length <= 0) 49156893Sfenner return; 49256893Sfenner 49356893Sfenner /* 49456893Sfenner * Decode payload if necessary. 49556893Sfenner */ 49656893Sfenner bp += (tp->th_off * 4); 49756893Sfenner if (!qflag && vflag && length > 0 49856893Sfenner && (sport == TELNET_PORT || dport == TELNET_PORT)) 49956893Sfenner telnet_print(bp, length); 50056893Sfenner else if (sport == BGP_PORT || dport == BGP_PORT) 50156893Sfenner bgp_print(bp, length); 50256893Sfenner else if (sport == NETBIOS_SSN_PORT || dport == NETBIOS_SSN_PORT) 50356893Sfenner nbt_tcp_print(bp, length); 50417680Spst return; 50526180Sfennerbad: 50626180Sfenner fputs("[bad opt]", stdout); 50726180Sfenner if (ch != '\0') 50826180Sfenner putchar('>'); 50926180Sfenner return; 51017680Spsttrunc: 51117680Spst fputs("[|tcp]", stdout); 51217680Spst if (ch != '\0') 51317680Spst putchar('>'); 51417680Spst} 51517680Spst 516