print-tcp.c revision 98524
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[] = 2498524Sfenner "@(#) $Header: /tcpdump/master/tcpdump/print-tcp.c,v 1.95 2001/12/10 08:21:24 guy 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 3475115Sfenner#include <rpc/rpc.h> 3575115Sfenner 3617680Spst#include <netinet/in.h> 3717680Spst 3817680Spst#include <stdio.h> 3917680Spst#include <stdlib.h> 4017680Spst#include <string.h> 4175115Sfenner#include <ctype.h> 4217680Spst#include <unistd.h> 4317680Spst 4417680Spst#include "interface.h" 4517680Spst#include "addrtoname.h" 4617680Spst#include "extract.h" 4717680Spst 4875115Sfenner#include "tcp.h" 4975115Sfenner 5075115Sfenner#include "ip.h" 5175115Sfenner#ifdef INET6 5275115Sfenner#include "ip6.h" 5375115Sfenner#endif 5475115Sfenner 5598524Sfenner#include "nameser.h" 5698524Sfenner 5775115Sfennerstatic void print_tcp_rst_data(register const u_char *sp, u_int length); 5875115Sfenner 5975115Sfenner#define MAX_RST_DATA_LEN 30 6075115Sfenner 6117680Spst 6217680Spststruct tha { 6356893Sfenner#ifndef INET6 6417680Spst struct in_addr src; 6517680Spst struct in_addr dst; 6656893Sfenner#else 6756893Sfenner struct in6_addr src; 6856893Sfenner struct in6_addr dst; 6956893Sfenner#endif /*INET6*/ 7017680Spst u_int port; 7117680Spst}; 7217680Spst 7317680Spststruct tcp_seq_hash { 7417680Spst struct tcp_seq_hash *nxt; 7517680Spst struct tha addr; 7617680Spst tcp_seq seq; 7717680Spst tcp_seq ack; 7817680Spst}; 7917680Spst 8017680Spst#define TSEQ_HASHSIZE 919 8117680Spst 8217680Spst/* These tcp optinos do not have the size octet */ 8317680Spst#define ZEROLENOPT(o) ((o) == TCPOPT_EOL || (o) == TCPOPT_NOP) 8417680Spst 8517680Spststatic struct tcp_seq_hash tcp_seq_hash[TSEQ_HASHSIZE]; 8617680Spst 8717680Spst 8856893Sfenner#ifndef TELNET_PORT 8956893Sfenner#define TELNET_PORT 23 9056893Sfenner#endif 9156893Sfenner#ifndef BGP_PORT 9256893Sfenner#define BGP_PORT 179 9356893Sfenner#endif 9456893Sfenner#define NETBIOS_SSN_PORT 139 9598524Sfenner#ifndef PPTP_PORT 9698524Sfenner#define PPTP_PORT 1723 9798524Sfenner#endif 9898524Sfenner#define BEEP_PORT 10288 9975115Sfenner#ifndef NFS_PORT 10075115Sfenner#define NFS_PORT 2049 10175115Sfenner#endif 10298524Sfenner#define MSDP_PORT 639 10356893Sfenner 10475115Sfennerstatic int tcp_cksum(register const struct ip *ip, 10575115Sfenner register const struct tcphdr *tp, 10675115Sfenner register int len) 10775115Sfenner{ 10875115Sfenner union phu { 10975115Sfenner struct phdr { 11075115Sfenner u_int32_t src; 11175115Sfenner u_int32_t dst; 11275115Sfenner u_char mbz; 11375115Sfenner u_char proto; 11475115Sfenner u_int16_t len; 11575115Sfenner } ph; 11675115Sfenner u_int16_t pa[6]; 11775115Sfenner } phu; 11898524Sfenner const u_int16_t *sp; 11975115Sfenner 12075115Sfenner /* pseudo-header.. */ 12198524Sfenner phu.ph.len = htons(len); /* XXX */ 12275115Sfenner phu.ph.mbz = 0; 12375115Sfenner phu.ph.proto = IPPROTO_TCP; 12475115Sfenner memcpy(&phu.ph.src, &ip->ip_src.s_addr, sizeof(u_int32_t)); 12575115Sfenner memcpy(&phu.ph.dst, &ip->ip_dst.s_addr, sizeof(u_int32_t)); 12675115Sfenner 12775115Sfenner sp = &phu.pa[0]; 12898524Sfenner return in_cksum((u_short *)tp, len, 12998524Sfenner sp[0]+sp[1]+sp[2]+sp[3]+sp[4]+sp[5]); 13075115Sfenner} 13175115Sfenner 13275115Sfenner#ifdef INET6 13375115Sfennerstatic int tcp6_cksum(const struct ip6_hdr *ip6, const struct tcphdr *tp, 13475115Sfenner int len) 13575115Sfenner{ 13675115Sfenner int i, tlen; 13775115Sfenner register const u_int16_t *sp; 13875115Sfenner u_int32_t sum; 13975115Sfenner union { 14075115Sfenner struct { 14175115Sfenner struct in6_addr ph_src; 14275115Sfenner struct in6_addr ph_dst; 14375115Sfenner u_int32_t ph_len; 14475115Sfenner u_int8_t ph_zero[3]; 14575115Sfenner u_int8_t ph_nxt; 14675115Sfenner } ph; 14775115Sfenner u_int16_t pa[20]; 14875115Sfenner } phu; 14975115Sfenner 15075115Sfenner tlen = ntohs(ip6->ip6_plen) + sizeof(struct ip6_hdr) - 15175115Sfenner ((const char *)tp - (const char*)ip6); 15275115Sfenner 15375115Sfenner /* pseudo-header */ 15475115Sfenner memset(&phu, 0, sizeof(phu)); 15575115Sfenner phu.ph.ph_src = ip6->ip6_src; 15675115Sfenner phu.ph.ph_dst = ip6->ip6_dst; 15775115Sfenner phu.ph.ph_len = htonl(tlen); 15875115Sfenner phu.ph.ph_nxt = IPPROTO_TCP; 15975115Sfenner 16075115Sfenner sum = 0; 16175115Sfenner for (i = 0; i < sizeof(phu.pa) / sizeof(phu.pa[0]); i++) 16275115Sfenner sum += phu.pa[i]; 16375115Sfenner 16475115Sfenner sp = (const u_int16_t *)tp; 16575115Sfenner 16675115Sfenner for (i = 0; i < (tlen & ~1); i += 2) 16775115Sfenner sum += *sp++; 16875115Sfenner 16975115Sfenner if (tlen & 1) 17075115Sfenner sum += htons((*(const u_int8_t *)sp) << 8); 17175115Sfenner 17275115Sfenner while (sum > 0xffff) 17375115Sfenner sum = (sum & 0xffff) + (sum >> 16); 17475115Sfenner sum = ~sum & 0xffff; 17575115Sfenner 17675115Sfenner return (sum); 17775115Sfenner} 17875115Sfenner#endif 17975115Sfenner 18017680Spstvoid 18117680Spsttcp_print(register const u_char *bp, register u_int length, 18275115Sfenner register const u_char *bp2, int fragmented) 18317680Spst{ 18417680Spst register const struct tcphdr *tp; 18517680Spst register const struct ip *ip; 18617680Spst register u_char flags; 18726180Sfenner register int hlen; 18817680Spst register char ch; 18975115Sfenner u_int16_t sport, dport, win, urp; 19056893Sfenner u_int32_t seq, ack, thseq, thack; 19156893Sfenner int threv; 19256893Sfenner#ifdef INET6 19356893Sfenner register const struct ip6_hdr *ip6; 19456893Sfenner#endif 19517680Spst 19617680Spst tp = (struct tcphdr *)bp; 19717680Spst ip = (struct ip *)bp2; 19856893Sfenner#ifdef INET6 19975115Sfenner if (IP_V(ip) == 6) 20056893Sfenner ip6 = (struct ip6_hdr *)bp2; 20156893Sfenner else 20256893Sfenner ip6 = NULL; 20356893Sfenner#endif /*INET6*/ 20417680Spst ch = '\0'; 20556893Sfenner if (!TTEST(tp->th_dport)) { 20656893Sfenner (void)printf("%s > %s: [|tcp]", 20756893Sfenner ipaddr_string(&ip->ip_src), 20856893Sfenner ipaddr_string(&ip->ip_dst)); 20917680Spst return; 21017680Spst } 21117680Spst 21217680Spst sport = ntohs(tp->th_sport); 21317680Spst dport = ntohs(tp->th_dport); 21456893Sfenner 21575115Sfenner hlen = TH_OFF(tp) * 4; 21675115Sfenner 21775115Sfenner /* 21875115Sfenner * If data present and NFS port used, assume NFS. 21975115Sfenner * Pass offset of data plus 4 bytes for RPC TCP msg length 22075115Sfenner * to NFS print routines. 22175115Sfenner */ 22275115Sfenner if (!qflag) { 22375115Sfenner if ((u_char *)tp + 4 + sizeof(struct rpc_msg) <= snapend && 22475115Sfenner dport == NFS_PORT) { 22598524Sfenner nfsreq_print((u_char *)tp + hlen + 4, length - hlen, 22675115Sfenner (u_char *)ip); 22775115Sfenner return; 22875115Sfenner } else if ((u_char *)tp + 4 + sizeof(struct rpc_msg) 22975115Sfenner <= snapend && 23075115Sfenner sport == NFS_PORT) { 23198524Sfenner nfsreply_print((u_char *)tp + hlen + 4, length - hlen, 23275115Sfenner (u_char *)ip); 23375115Sfenner return; 23475115Sfenner } 23575115Sfenner } 23656893Sfenner#ifdef INET6 23756893Sfenner if (ip6) { 23856893Sfenner if (ip6->ip6_nxt == IPPROTO_TCP) { 23956893Sfenner (void)printf("%s.%s > %s.%s: ", 24056893Sfenner ip6addr_string(&ip6->ip6_src), 24156893Sfenner tcpport_string(sport), 24256893Sfenner ip6addr_string(&ip6->ip6_dst), 24356893Sfenner tcpport_string(dport)); 24456893Sfenner } else { 24556893Sfenner (void)printf("%s > %s: ", 24656893Sfenner tcpport_string(sport), tcpport_string(dport)); 24756893Sfenner } 24856893Sfenner } else 24956893Sfenner#endif /*INET6*/ 25056893Sfenner { 25156893Sfenner if (ip->ip_p == IPPROTO_TCP) { 25256893Sfenner (void)printf("%s.%s > %s.%s: ", 25356893Sfenner ipaddr_string(&ip->ip_src), 25456893Sfenner tcpport_string(sport), 25556893Sfenner ipaddr_string(&ip->ip_dst), 25656893Sfenner tcpport_string(dport)); 25756893Sfenner } else { 25856893Sfenner (void)printf("%s > %s: ", 25956893Sfenner tcpport_string(sport), tcpport_string(dport)); 26056893Sfenner } 26156893Sfenner } 26256893Sfenner 26356893Sfenner TCHECK(*tp); 26456893Sfenner 26575115Sfenner seq = (u_int32_t)ntohl(tp->th_seq); 26675115Sfenner ack = (u_int32_t)ntohl(tp->th_ack); 26717680Spst win = ntohs(tp->th_win); 26817680Spst urp = ntohs(tp->th_urp); 26917680Spst 27017680Spst if (qflag) { 27175115Sfenner (void)printf("tcp %d", length - TH_OFF(tp) * 4); 27217680Spst return; 27317680Spst } 27475115Sfenner if ((flags = tp->th_flags) & (TH_SYN|TH_FIN|TH_RST|TH_PUSH| 27575115Sfenner TH_ECNECHO|TH_CWR)) { 27617680Spst if (flags & TH_SYN) 27717680Spst putchar('S'); 27817680Spst if (flags & TH_FIN) 27917680Spst putchar('F'); 28017680Spst if (flags & TH_RST) 28117680Spst putchar('R'); 28217680Spst if (flags & TH_PUSH) 28317680Spst putchar('P'); 28475115Sfenner if (flags & TH_CWR) 28575115Sfenner putchar('W'); /* congestion _W_indow reduced (ECN) */ 28675115Sfenner if (flags & TH_ECNECHO) 28775115Sfenner putchar('E'); /* ecn _E_cho sent (ECN) */ 28817680Spst } else 28917680Spst putchar('.'); 29017680Spst 29117680Spst if (!Sflag && (flags & TH_ACK)) { 29217680Spst register struct tcp_seq_hash *th; 29317680Spst register int rev; 29417680Spst struct tha tha; 29517680Spst /* 29617680Spst * Find (or record) the initial sequence numbers for 29717680Spst * this conversation. (we pick an arbitrary 29817680Spst * collating order so there's only one entry for 29917680Spst * both directions). 30017680Spst */ 30156893Sfenner#ifdef INET6 30275115Sfenner memset(&tha, 0, sizeof(tha)); 30356893Sfenner rev = 0; 30456893Sfenner if (ip6) { 30598524Sfenner if (sport > dport) 30656893Sfenner rev = 1; 30798524Sfenner else if (sport == dport) { 30898524Sfenner int i; 30956893Sfenner 31098524Sfenner for (i = 0; i < 4; i++) { 31198524Sfenner if (((u_int32_t *)(&ip6->ip6_src))[i] > 31298524Sfenner ((u_int32_t *)(&ip6->ip6_dst))[i]) { 31398524Sfenner rev = 1; 31498524Sfenner break; 31598524Sfenner } 31656893Sfenner } 31756893Sfenner } 31856893Sfenner if (rev) { 31956893Sfenner tha.src = ip6->ip6_dst; 32056893Sfenner tha.dst = ip6->ip6_src; 32156893Sfenner tha.port = dport << 16 | sport; 32256893Sfenner } else { 32356893Sfenner tha.dst = ip6->ip6_dst; 32456893Sfenner tha.src = ip6->ip6_src; 32556893Sfenner tha.port = sport << 16 | dport; 32656893Sfenner } 32756893Sfenner } else { 32856893Sfenner if (sport > dport || 32956893Sfenner (sport == dport && 33056893Sfenner ip->ip_src.s_addr > ip->ip_dst.s_addr)) { 33156893Sfenner rev = 1; 33256893Sfenner } 33356893Sfenner if (rev) { 33456893Sfenner *(struct in_addr *)&tha.src = ip->ip_dst; 33556893Sfenner *(struct in_addr *)&tha.dst = ip->ip_src; 33656893Sfenner tha.port = dport << 16 | sport; 33756893Sfenner } else { 33856893Sfenner *(struct in_addr *)&tha.dst = ip->ip_dst; 33956893Sfenner *(struct in_addr *)&tha.src = ip->ip_src; 34056893Sfenner tha.port = sport << 16 | dport; 34156893Sfenner } 34256893Sfenner } 34356893Sfenner#else 34417680Spst if (sport < dport || 34517680Spst (sport == dport && 34617680Spst ip->ip_src.s_addr < ip->ip_dst.s_addr)) { 34717680Spst tha.src = ip->ip_src, tha.dst = ip->ip_dst; 34817680Spst tha.port = sport << 16 | dport; 34917680Spst rev = 0; 35017680Spst } else { 35117680Spst tha.src = ip->ip_dst, tha.dst = ip->ip_src; 35217680Spst tha.port = dport << 16 | sport; 35317680Spst rev = 1; 35417680Spst } 35556893Sfenner#endif 35617680Spst 35756893Sfenner threv = rev; 35817680Spst for (th = &tcp_seq_hash[tha.port % TSEQ_HASHSIZE]; 35917680Spst th->nxt; th = th->nxt) 36017680Spst if (!memcmp((char *)&tha, (char *)&th->addr, 36117680Spst sizeof(th->addr))) 36217680Spst break; 36317680Spst 36475115Sfenner if (!th->nxt || (flags & TH_SYN)) { 36517680Spst /* didn't find it or new conversation */ 36617680Spst if (th->nxt == NULL) { 36717680Spst th->nxt = (struct tcp_seq_hash *) 36817680Spst calloc(1, sizeof(*th)); 36917680Spst if (th->nxt == NULL) 37017680Spst error("tcp_print: calloc"); 37117680Spst } 37217680Spst th->addr = tha; 37317680Spst if (rev) 37417680Spst th->ack = seq, th->seq = ack - 1; 37517680Spst else 37617680Spst th->seq = seq, th->ack = ack - 1; 37717680Spst } else { 37817680Spst if (rev) 37917680Spst seq -= th->ack, ack -= th->seq; 38017680Spst else 38117680Spst seq -= th->seq, ack -= th->ack; 38217680Spst } 38375115Sfenner 38475115Sfenner thseq = th->seq; 38575115Sfenner thack = th->ack; 38675115Sfenner } else { 38775115Sfenner /*fool gcc*/ 38875115Sfenner thseq = thack = threv = 0; 38917680Spst } 39026180Sfenner if (hlen > length) { 39126180Sfenner (void)printf(" [bad hdr length]"); 39226180Sfenner return; 39326180Sfenner } 39475115Sfenner 39575115Sfenner if (IP_V(ip) == 4 && vflag && !fragmented) { 39675115Sfenner int sum; 39775115Sfenner if (TTEST2(tp->th_sport, length)) { 39875115Sfenner sum = tcp_cksum(ip, tp, length); 39975115Sfenner if (sum != 0) 40075115Sfenner (void)printf(" [bad tcp cksum %x!]", sum); 40175115Sfenner else 40275115Sfenner (void)printf(" [tcp sum ok]"); 40375115Sfenner } 40475115Sfenner } 40575115Sfenner#ifdef INET6 40675115Sfenner if (IP_V(ip) == 6 && ip6->ip6_plen && vflag && !fragmented) { 40775115Sfenner int sum; 40875115Sfenner if (TTEST2(tp->th_sport, length)) { 40975115Sfenner sum = tcp6_cksum(ip6, tp, length); 41075115Sfenner if (sum != 0) 41175115Sfenner (void)printf(" [bad tcp cksum %x!]", sum); 41275115Sfenner else 41375115Sfenner (void)printf(" [tcp sum ok]"); 41475115Sfenner } 41575115Sfenner } 41675115Sfenner#endif 41775115Sfenner 41817680Spst length -= hlen; 41956893Sfenner if (vflag > 1 || length > 0 || flags & (TH_SYN | TH_FIN | TH_RST)) 42098524Sfenner (void)printf(" %u:%u(%u)", seq, seq + length, length); 42117680Spst if (flags & TH_ACK) 42217680Spst (void)printf(" ack %u", ack); 42317680Spst 42417680Spst (void)printf(" win %d", win); 42517680Spst 42617680Spst if (flags & TH_URG) 42717680Spst (void)printf(" urg %d", urp); 42817680Spst /* 42917680Spst * Handle any options. 43017680Spst */ 43117680Spst if ((hlen -= sizeof(*tp)) > 0) { 43217680Spst register const u_char *cp; 43317680Spst register int i, opt, len, datalen; 43417680Spst 43517680Spst cp = (const u_char *)tp + sizeof(*tp); 43617680Spst putchar(' '); 43717680Spst ch = '<'; 43817680Spst while (hlen > 0) { 43917680Spst putchar(ch); 44026180Sfenner TCHECK(*cp); 44117680Spst opt = *cp++; 44217680Spst if (ZEROLENOPT(opt)) 44317680Spst len = 1; 44417680Spst else { 44526180Sfenner TCHECK(*cp); 44626180Sfenner len = *cp++; /* total including type, len */ 44726180Sfenner if (len < 2 || len > hlen) 44826180Sfenner goto bad; 44926180Sfenner --hlen; /* account for length byte */ 45017680Spst } 45126180Sfenner --hlen; /* account for type byte */ 45217680Spst datalen = 0; 45326180Sfenner 45426180Sfenner/* Bail if "l" bytes of data are not left or were not captured */ 45526180Sfenner#define LENCHECK(l) { if ((l) > hlen) goto bad; TCHECK2(*cp, l); } 45626180Sfenner 45717680Spst switch (opt) { 45817680Spst 45917680Spst case TCPOPT_MAXSEG: 46017680Spst (void)printf("mss"); 46117680Spst datalen = 2; 46226180Sfenner LENCHECK(datalen); 46317680Spst (void)printf(" %u", EXTRACT_16BITS(cp)); 46417680Spst 46517680Spst break; 46617680Spst 46717680Spst case TCPOPT_EOL: 46817680Spst (void)printf("eol"); 46917680Spst break; 47017680Spst 47117680Spst case TCPOPT_NOP: 47217680Spst (void)printf("nop"); 47317680Spst break; 47417680Spst 47517680Spst case TCPOPT_WSCALE: 47617680Spst (void)printf("wscale"); 47717680Spst datalen = 1; 47826180Sfenner LENCHECK(datalen); 47917680Spst (void)printf(" %u", *cp); 48017680Spst break; 48117680Spst 48217680Spst case TCPOPT_SACKOK: 48317680Spst (void)printf("sackOK"); 48417680Spst break; 48517680Spst 48617680Spst case TCPOPT_SACK: 48717680Spst (void)printf("sack"); 48817680Spst datalen = len - 2; 48956893Sfenner if (datalen % 8 != 0) { 49056893Sfenner (void)printf(" malformed sack "); 49156893Sfenner } else { 49256893Sfenner u_int32_t s, e; 49356893Sfenner 49456893Sfenner (void)printf(" sack %d ", datalen / 8); 49556893Sfenner for (i = 0; i < datalen; i += 8) { 49656893Sfenner LENCHECK(i + 4); 49756893Sfenner s = EXTRACT_32BITS(cp + i); 49856893Sfenner LENCHECK(i + 8); 49956893Sfenner e = EXTRACT_32BITS(cp + i + 4); 50056893Sfenner if (threv) { 50156893Sfenner s -= thseq; 50256893Sfenner e -= thseq; 50356893Sfenner } else { 50456893Sfenner s -= thack; 50556893Sfenner e -= thack; 50656893Sfenner } 50756893Sfenner (void)printf("{%u:%u}", s, e); 50856893Sfenner } 50956893Sfenner (void)printf(" "); 51017680Spst } 51117680Spst break; 51217680Spst 51317680Spst case TCPOPT_ECHO: 51417680Spst (void)printf("echo"); 51517680Spst datalen = 4; 51626180Sfenner LENCHECK(datalen); 51717680Spst (void)printf(" %u", EXTRACT_32BITS(cp)); 51817680Spst break; 51917680Spst 52017680Spst case TCPOPT_ECHOREPLY: 52117680Spst (void)printf("echoreply"); 52217680Spst datalen = 4; 52326180Sfenner LENCHECK(datalen); 52417680Spst (void)printf(" %u", EXTRACT_32BITS(cp)); 52517680Spst break; 52617680Spst 52717680Spst case TCPOPT_TIMESTAMP: 52817680Spst (void)printf("timestamp"); 52926180Sfenner datalen = 8; 53026180Sfenner LENCHECK(4); 53117680Spst (void)printf(" %u", EXTRACT_32BITS(cp)); 53226180Sfenner LENCHECK(datalen); 53317680Spst (void)printf(" %u", EXTRACT_32BITS(cp + 4)); 53417680Spst break; 53517680Spst 53617680Spst case TCPOPT_CC: 53717680Spst (void)printf("cc"); 53817680Spst datalen = 4; 53926180Sfenner LENCHECK(datalen); 54017680Spst (void)printf(" %u", EXTRACT_32BITS(cp)); 54117680Spst break; 54217680Spst 54317680Spst case TCPOPT_CCNEW: 54417680Spst (void)printf("ccnew"); 54517680Spst datalen = 4; 54626180Sfenner LENCHECK(datalen); 54717680Spst (void)printf(" %u", EXTRACT_32BITS(cp)); 54817680Spst break; 54917680Spst 55017680Spst case TCPOPT_CCECHO: 55117680Spst (void)printf("ccecho"); 55217680Spst datalen = 4; 55326180Sfenner LENCHECK(datalen); 55417680Spst (void)printf(" %u", EXTRACT_32BITS(cp)); 55517680Spst break; 55617680Spst 55717680Spst default: 55817680Spst (void)printf("opt-%d:", opt); 55917680Spst datalen = len - 2; 56017680Spst for (i = 0; i < datalen; ++i) { 56126180Sfenner LENCHECK(i); 56217680Spst (void)printf("%02x", cp[i]); 56317680Spst } 56417680Spst break; 56517680Spst } 56617680Spst 56717680Spst /* Account for data printed */ 56817680Spst cp += datalen; 56917680Spst hlen -= datalen; 57017680Spst 57117680Spst /* Check specification against observed length */ 57217680Spst ++datalen; /* option octet */ 57317680Spst if (!ZEROLENOPT(opt)) 57417680Spst ++datalen; /* size octet */ 57517680Spst if (datalen != len) 57617680Spst (void)printf("[len %d]", len); 57717680Spst ch = ','; 57826180Sfenner if (opt == TCPOPT_EOL) 57926180Sfenner break; 58017680Spst } 58117680Spst putchar('>'); 58217680Spst } 58356893Sfenner 58456893Sfenner if (length <= 0) 58556893Sfenner return; 58656893Sfenner 58756893Sfenner /* 58856893Sfenner * Decode payload if necessary. 58956893Sfenner */ 59075115Sfenner bp += TH_OFF(tp) * 4; 59175115Sfenner if (flags & TH_RST) { 59275115Sfenner if (vflag) 59375115Sfenner print_tcp_rst_data(bp, length); 59475115Sfenner } else { 59575115Sfenner if (sport == TELNET_PORT || dport == TELNET_PORT) { 59675115Sfenner if (!qflag && vflag) 59775115Sfenner telnet_print(bp, length); 59875115Sfenner } else if (sport == BGP_PORT || dport == BGP_PORT) 59975115Sfenner bgp_print(bp, length); 60098524Sfenner else if (sport == PPTP_PORT || dport == PPTP_PORT) 60198524Sfenner pptp_print(bp, length); 60298524Sfenner#ifdef TCPDUMP_DO_SMB 60375115Sfenner else if (sport == NETBIOS_SSN_PORT || dport == NETBIOS_SSN_PORT) 60475115Sfenner nbt_tcp_print(bp, length); 60598524Sfenner#endif 60698524Sfenner else if (sport == BEEP_PORT || dport == BEEP_PORT) 60798524Sfenner beep_print(bp, length); 60898524Sfenner else if (length > 2 && 60998524Sfenner (sport == NAMESERVER_PORT || dport == NAMESERVER_PORT)) { 61098524Sfenner /* 61198524Sfenner * TCP DNS query has 2byte length at the head. 61298524Sfenner * XXX packet could be unaligned, it can go strange 61398524Sfenner */ 61498524Sfenner ns_print(bp + 2, length - 2); 61598524Sfenner } else if (sport == MSDP_PORT || dport == MSDP_PORT) { 61698524Sfenner msdp_print(bp, length); 61798524Sfenner } 61875115Sfenner } 61917680Spst return; 62026180Sfennerbad: 62126180Sfenner fputs("[bad opt]", stdout); 62226180Sfenner if (ch != '\0') 62326180Sfenner putchar('>'); 62426180Sfenner return; 62517680Spsttrunc: 62617680Spst fputs("[|tcp]", stdout); 62717680Spst if (ch != '\0') 62817680Spst putchar('>'); 62917680Spst} 63017680Spst 63175115Sfenner/* 63275115Sfenner * RFC1122 says the following on data in RST segments: 63375115Sfenner * 63475115Sfenner * 4.2.2.12 RST Segment: RFC-793 Section 3.4 63575115Sfenner * 63675115Sfenner * A TCP SHOULD allow a received RST segment to include data. 63775115Sfenner * 63875115Sfenner * DISCUSSION 63975115Sfenner * It has been suggested that a RST segment could contain 64075115Sfenner * ASCII text that encoded and explained the cause of the 64175115Sfenner * RST. No standard has yet been established for such 64275115Sfenner * data. 64375115Sfenner * 64475115Sfenner */ 64575115Sfenner 64675115Sfennerstatic void 64775115Sfennerprint_tcp_rst_data(register const u_char *sp, u_int length) 64875115Sfenner{ 64975115Sfenner int c; 65075115Sfenner 65175115Sfenner if (TTEST2(*sp, length)) 65275115Sfenner printf(" [RST"); 65375115Sfenner else 65475115Sfenner printf(" [!RST"); 65575115Sfenner if (length > MAX_RST_DATA_LEN) { 65675115Sfenner length = MAX_RST_DATA_LEN; /* can use -X for longer */ 65775115Sfenner putchar('+'); /* indicate we truncate */ 65875115Sfenner } 65975115Sfenner putchar(' '); 66075115Sfenner while (length-- && sp <= snapend) { 66175115Sfenner c = *sp++; 66298524Sfenner safeputchar(c); 66375115Sfenner } 66475115Sfenner putchar(']'); 66575115Sfenner} 666