print-tcp.c revision 147899
1193326Sed/* 2193326Sed * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 3193326Sed * The Regents of the University of California. All rights reserved. 4193326Sed * 5193326Sed * Copyright (c) 1999-2004 The tcpdump.org project 6193326Sed * 7193326Sed * Redistribution and use in source and binary forms, with or without 8193326Sed * modification, are permitted provided that: (1) source code distributions 9239462Sdim * retain the above copyright notice and this paragraph in its entirety, (2) 10239462Sdim * distributions including binary code include the above copyright notice and 11239462Sdim * this paragraph in its entirety in the documentation or other materials 12239462Sdim * provided with the distribution, and (3) all advertising materials mentioning 13239462Sdim * features or use of this software display the following acknowledgement: 14239462Sdim * ``This product includes software developed by the University of California, 15239462Sdim * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 16239462Sdim * the University nor the names of its contributors may be used to endorse 17239462Sdim * or promote products derived from this software without specific prior 18239462Sdim * written permission. 19239462Sdim * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 20239462Sdim * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 21239462Sdim * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 22193326Sed */ 23193326Sed 24193326Sed#ifndef lint 25249423Sdimstatic const char rcsid[] _U_ = 26249423Sdim "@(#) $Header: /tcpdump/master/tcpdump/print-tcp.c,v 1.120.2.2 2005/04/21 06:36:05 guy Exp $ (LBL)"; 27212904Sdim#endif 28249423Sdim 29212904Sdim#ifdef HAVE_CONFIG_H 30234353Sdim#include "config.h" 31249423Sdim#endif 32193326Sed 33193326Sed#include <tcpdump-stdinc.h> 34193326Sed 35239462Sdim#include <stdio.h> 36193326Sed#include <stdlib.h> 37193326Sed#include <string.h> 38193326Sed 39193326Sed#include "interface.h" 40193326Sed#include "addrtoname.h" 41193326Sed#include "extract.h" 42193326Sed 43193326Sed#include "tcp.h" 44193326Sed 45193326Sed#include "ip.h" 46239462Sdim#ifdef INET6 47193326Sed#include "ip6.h" 48193326Sed#endif 49193326Sed#include "ipproto.h" 50193326Sed#include "rpc_auth.h" 51193326Sed#include "rpc_msg.h" 52193326Sed 53193326Sed#include "nameser.h" 54193326Sed 55193326Sed#ifdef HAVE_LIBCRYPTO 56193326Sed#include <openssl/md5.h> 57193326Sed 58193326Sed#define SIGNATURE_VALID 0 59193326Sed#define SIGNATURE_INVALID 1 60193326Sed#define CANT_CHECK_SIGNATURE 2 61193326Sed 62193326Sedstatic int tcp_verify_signature(const struct ip *ip, const struct tcphdr *tp, 63193326Sed const u_char *data, int length, const u_char *rcvsig); 64193326Sed#endif 65193326Sed 66193326Sedstatic void print_tcp_rst_data(register const u_char *sp, u_int length); 67193326Sed 68193326Sed#define MAX_RST_DATA_LEN 30 69193326Sed 70193326Sed 71193326Sedstruct tha { 72193326Sed#ifndef INET6 73193326Sed struct in_addr src; 74193326Sed struct in_addr dst; 75193326Sed#else 76193326Sed struct in6_addr src; 77193326Sed struct in6_addr dst; 78193326Sed#endif /*INET6*/ 79193326Sed u_int port; 80193326Sed}; 81193326Sed 82193326Sedstruct tcp_seq_hash { 83193326Sed struct tcp_seq_hash *nxt; 84193326Sed struct tha addr; 85193326Sed tcp_seq seq; 86193326Sed tcp_seq ack; 87193326Sed}; 88193326Sed 89193326Sed#define TSEQ_HASHSIZE 919 90193326Sed 91193326Sed/* These tcp optinos do not have the size octet */ 92193326Sed#define ZEROLENOPT(o) ((o) == TCPOPT_EOL || (o) == TCPOPT_NOP) 93193326Sed 94193326Sedstatic struct tcp_seq_hash tcp_seq_hash[TSEQ_HASHSIZE]; 95193326Sed 96193326Sed 97193326Sed#ifndef TELNET_PORT 98193326Sed#define TELNET_PORT 23 99193326Sed#endif 100193326Sed#ifndef BGP_PORT 101193326Sed#define BGP_PORT 179 102193326Sed#endif 103193326Sed#define NETBIOS_SSN_PORT 139 104193326Sed#ifndef PPTP_PORT 105193326Sed#define PPTP_PORT 1723 106193326Sed#endif 107193326Sed#define BEEP_PORT 10288 108193326Sed#ifndef NFS_PORT 109193326Sed#define NFS_PORT 2049 110193326Sed#endif 111193326Sed#define MSDP_PORT 639 112193326Sed#define LDP_PORT 646 113193326Sed 114193326Sedstatic int tcp_cksum(register const struct ip *ip, 115193326Sed register const struct tcphdr *tp, 116218893Sdim register u_int len) 117218893Sdim{ 118239462Sdim union phu { 119234353Sdim struct phdr { 120234353Sdim u_int32_t src; 121243830Sdim u_int32_t dst; 122193326Sed u_char mbz; 123193326Sed u_char proto; 124198092Srdivacky u_int16_t len; 125193326Sed } ph; 126239462Sdim u_int16_t pa[6]; 127239462Sdim } phu; 128193326Sed const u_int16_t *sp; 129212904Sdim 130193326Sed /* pseudo-header.. */ 131212904Sdim phu.ph.len = htons((u_int16_t)len); 132243830Sdim phu.ph.mbz = 0; 133193326Sed phu.ph.proto = IPPROTO_TCP; 134193326Sed memcpy(&phu.ph.src, &ip->ip_src.s_addr, sizeof(u_int32_t)); 135193326Sed if (IP_HL(ip) == 5) 136193326Sed memcpy(&phu.ph.dst, &ip->ip_dst.s_addr, sizeof(u_int32_t)); 137193326Sed else 138212904Sdim phu.ph.dst = ip_finddst(ip); 139193326Sed 140212904Sdim sp = &phu.pa[0]; 141193326Sed return in_cksum((u_short *)tp, len, 142193326Sed sp[0]+sp[1]+sp[2]+sp[3]+sp[4]+sp[5]); 143193326Sed} 144193326Sed 145193326Sed#ifdef INET6 146193326Sedstatic int tcp6_cksum(const struct ip6_hdr *ip6, const struct tcphdr *tp, 147193326Sed u_int len) 148218893Sdim{ 149218893Sdim size_t i; 150218893Sdim register const u_int16_t *sp; 151193326Sed u_int32_t sum; 152243830Sdim union { 153193326Sed struct { 154193326Sed struct in6_addr ph_src; 155239462Sdim struct in6_addr ph_dst; 156234353Sdim u_int32_t ph_len; 157202379Srdivacky u_int8_t ph_zero[3]; 158212904Sdim u_int8_t ph_nxt; 159226633Sdim } ph; 160226633Sdim u_int16_t pa[20]; 161202379Srdivacky } phu; 162202379Srdivacky 163193326Sed /* pseudo-header */ 164193326Sed memset(&phu, 0, sizeof(phu)); 165193326Sed phu.ph.ph_src = ip6->ip6_src; 166234353Sdim phu.ph.ph_dst = ip6->ip6_dst; 167234353Sdim phu.ph.ph_len = htonl(len); 168234353Sdim phu.ph.ph_nxt = IPPROTO_TCP; 169243830Sdim 170193326Sed sum = 0; 171193326Sed for (i = 0; i < sizeof(phu.pa) / sizeof(phu.pa[0]); i++) 172239462Sdim sum += phu.pa[i]; 173239462Sdim 174193326Sed sp = (const u_int16_t *)tp; 175239462Sdim 176239462Sdim for (i = 0; i < (len & ~1); i += 2) 177239462Sdim sum += *sp++; 178239462Sdim 179193326Sed if (len & 1) 180193326Sed sum += htons((*(const u_int8_t *)sp) << 8); 181212904Sdim 182193326Sed while (sum > 0xffff) 183207619Srdivacky sum = (sum & 0xffff) + (sum >> 16); 184212904Sdim sum = ~sum & 0xffff; 185212904Sdim 186212904Sdim return (sum); 187212904Sdim} 188212904Sdim#endif 189218893Sdim 190218893Sdimvoid 191193326Sedtcp_print(register const u_char *bp, register u_int length, 192193326Sed register const u_char *bp2, int fragmented) 193193326Sed{ 194234353Sdim register const struct tcphdr *tp; 195234353Sdim register const struct ip *ip; 196198092Srdivacky register u_char flags; 197194613Sed register u_int hlen; 198234353Sdim register char ch; 199194711Sed u_int16_t sport, dport, win, urp; 200234353Sdim u_int32_t seq, ack, thseq, thack; 201198092Srdivacky int threv; 202234353Sdim#ifdef INET6 203234353Sdim register const struct ip6_hdr *ip6; 204234353Sdim#endif 205193326Sed 206193326Sed tp = (struct tcphdr *)bp; 207243830Sdim ip = (struct ip *)bp2; 208243830Sdim#ifdef INET6 209243830Sdim if (IP_V(ip) == 6) 210243830Sdim ip6 = (struct ip6_hdr *)bp2; 211243830Sdim else 212243830Sdim ip6 = NULL; 213243830Sdim#endif /*INET6*/ 214243830Sdim ch = '\0'; 215243830Sdim if (!TTEST(tp->th_dport)) { 216243830Sdim (void)printf("%s > %s: [|tcp]", 217243830Sdim ipaddr_string(&ip->ip_src), 218239462Sdim ipaddr_string(&ip->ip_dst)); 219239462Sdim return; 220212904Sdim } 221212904Sdim 222207619Srdivacky sport = EXTRACT_16BITS(&tp->th_sport); 223207619Srdivacky dport = EXTRACT_16BITS(&tp->th_dport); 224249423Sdim 225193326Sed hlen = TH_OFF(tp) * 4; 226193326Sed 227193326Sed /* 228193326Sed * If data present, header length valid, and NFS port used, 229193326Sed * assume NFS. 230193326Sed * Pass offset of data plus 4 bytes for RPC TCP msg length 231193326Sed * to NFS print routines. 232243830Sdim */ 233193326Sed if (!qflag && hlen >= sizeof(*tp) && hlen <= length) { 234193326Sed if ((u_char *)tp + 4 + sizeof(struct sunrpc_msg) <= snapend && 235193326Sed dport == NFS_PORT) { 236193326Sed nfsreq_print((u_char *)tp + hlen + 4, length - hlen, 237193326Sed (u_char *)ip); 238243830Sdim return; 239243830Sdim } else if ((u_char *)tp + 4 + sizeof(struct sunrpc_msg) 240243830Sdim <= snapend && 241243830Sdim sport == NFS_PORT) { 242243830Sdim nfsreply_print((u_char *)tp + hlen + 4, length - hlen, 243243830Sdim (u_char *)ip); 244243830Sdim return; 245243830Sdim } 246243830Sdim } 247243830Sdim#ifdef INET6 248243830Sdim if (ip6) { 249193326Sed if (ip6->ip6_nxt == IPPROTO_TCP) { 250212904Sdim (void)printf("%s.%s > %s.%s: ", 251193326Sed ip6addr_string(&ip6->ip6_src), 252193326Sed tcpport_string(sport), 253200583Srdivacky ip6addr_string(&ip6->ip6_dst), 254200583Srdivacky tcpport_string(dport)); 255200583Srdivacky } else { 256193326Sed (void)printf("%s > %s: ", 257193326Sed tcpport_string(sport), tcpport_string(dport)); 258193326Sed } 259193326Sed } else 260193326Sed#endif /*INET6*/ 261218893Sdim { 262218893Sdim if (ip->ip_p == IPPROTO_TCP) { 263218893Sdim (void)printf("%s.%s > %s.%s: ", 264218893Sdim ipaddr_string(&ip->ip_src), 265193326Sed tcpport_string(sport), 266193326Sed ipaddr_string(&ip->ip_dst), 267193326Sed tcpport_string(dport)); 268193326Sed } else { 269193326Sed (void)printf("%s > %s: ", 270193326Sed tcpport_string(sport), tcpport_string(dport)); 271193326Sed } 272207619Srdivacky } 273207619Srdivacky 274207619Srdivacky if (hlen < sizeof(*tp)) { 275207619Srdivacky (void)printf(" tcp %d [bad hdr length %u - too short, < %lu]", 276226633Sdim length - hlen, hlen, (unsigned long)sizeof(*tp)); 277226633Sdim return; 278226633Sdim } 279208600Srdivacky 280208600Srdivacky TCHECK(*tp); 281208600Srdivacky 282224145Sdim seq = EXTRACT_32BITS(&tp->th_seq); 283234353Sdim ack = EXTRACT_32BITS(&tp->th_ack); 284234353Sdim win = EXTRACT_16BITS(&tp->th_win); 285208600Srdivacky urp = EXTRACT_16BITS(&tp->th_urp); 286208600Srdivacky 287226633Sdim if (qflag) { 288208600Srdivacky (void)printf("tcp %d", length - hlen); 289208600Srdivacky if (hlen > length) { 290226633Sdim (void)printf(" [bad hdr length %u - too long, > %u]", 291208600Srdivacky hlen, length); 292226633Sdim } 293208600Srdivacky return; 294208600Srdivacky } 295208600Srdivacky if ((flags = tp->th_flags) & (TH_SYN|TH_FIN|TH_RST|TH_PUSH| 296208600Srdivacky TH_ECNECHO|TH_CWR)) { 297208600Srdivacky if (flags & TH_SYN) 298207619Srdivacky putchar('S'); 299208600Srdivacky if (flags & TH_FIN) 300193326Sed putchar('F'); 301207619Srdivacky if (flags & TH_RST) 302193326Sed putchar('R'); 303193326Sed if (flags & TH_PUSH) 304198893Srdivacky putchar('P'); 305210299Sed if (flags & TH_CWR) 306210299Sed putchar('W'); /* congestion _W_indow reduced (ECN) */ 307210299Sed if (flags & TH_ECNECHO) 308210299Sed putchar('E'); /* ecn _E_cho sent (ECN) */ 309226633Sdim } else 310210299Sed putchar('.'); 311210299Sed 312210299Sed if (!Sflag && (flags & TH_ACK)) { 313193326Sed register struct tcp_seq_hash *th; 314193326Sed const void *src, *dst; 315193326Sed register int rev; 316193326Sed struct tha tha; 317193326Sed /* 318193326Sed * Find (or record) the initial sequence numbers for 319234353Sdim * this conversation. (we pick an arbitrary 320234353Sdim * collating order so there's only one entry for 321234353Sdim * both directions). 322234353Sdim */ 323212904Sdim#ifdef INET6 324234353Sdim memset(&tha, 0, sizeof(tha)); 325249423Sdim rev = 0; 326234353Sdim if (ip6) { 327234353Sdim src = &ip6->ip6_src; 328234353Sdim dst = &ip6->ip6_dst; 329193326Sed if (sport > dport) 330193326Sed rev = 1; 331193326Sed else if (sport == dport) { 332218893Sdim if (memcmp(src, dst, sizeof ip6->ip6_dst) > 0) 333193326Sed rev = 1; 334218893Sdim } 335218893Sdim if (rev) { 336193326Sed memcpy(&tha.src, dst, sizeof ip6->ip6_dst); 337193326Sed memcpy(&tha.dst, src, sizeof ip6->ip6_src); 338207619Srdivacky tha.port = dport << 16 | sport; 339193326Sed } else { 340249423Sdim memcpy(&tha.dst, dst, sizeof ip6->ip6_dst); 341193326Sed memcpy(&tha.src, src, sizeof ip6->ip6_src); 342193326Sed tha.port = sport << 16 | dport; 343193326Sed } 344193326Sed } else { 345193326Sed src = &ip->ip_src; 346193326Sed dst = &ip->ip_dst; 347193326Sed if (sport > dport) 348193326Sed rev = 1; 349193326Sed else if (sport == dport) { 350234353Sdim if (memcmp(src, dst, sizeof ip->ip_dst) > 0) 351234353Sdim rev = 1; 352234353Sdim } 353234353Sdim if (rev) { 354234353Sdim memcpy(&tha.src, dst, sizeof ip->ip_dst); 355193326Sed memcpy(&tha.dst, src, sizeof ip->ip_src); 356193326Sed tha.port = dport << 16 | sport; 357193326Sed } else { 358193326Sed memcpy(&tha.dst, dst, sizeof ip->ip_dst); 359193326Sed memcpy(&tha.src, src, sizeof ip->ip_src); 360218893Sdim tha.port = sport << 16 | dport; 361207619Srdivacky } 362234353Sdim } 363218893Sdim#else 364193326Sed rev = 0; 365218893Sdim src = &ip->ip_src; 366193326Sed dst = &ip->ip_dst; 367193326Sed if (sport > dport) 368249423Sdim rev = 1; 369193326Sed else if (sport == dport) { 370193326Sed if (memcmp(src, dst, sizeof ip->ip_dst) > 0) 371193326Sed rev = 1; 372234353Sdim } 373234353Sdim if (rev) { 374234353Sdim memcpy(&tha.src, dst, sizeof ip->ip_dst); 375234353Sdim memcpy(&tha.dst, src, sizeof ip->ip_src); 376234353Sdim tha.port = dport << 16 | sport; 377234353Sdim } else { 378234353Sdim memcpy(&tha.dst, dst, sizeof ip->ip_dst); 379234353Sdim memcpy(&tha.src, src, sizeof ip->ip_src); 380234353Sdim tha.port = sport << 16 | dport; 381234353Sdim } 382234353Sdim#endif 383234353Sdim 384193326Sed threv = rev; 385193326Sed for (th = &tcp_seq_hash[tha.port % TSEQ_HASHSIZE]; 386193326Sed th->nxt; th = th->nxt) 387193326Sed if (memcmp((char *)&tha, (char *)&th->addr, 388193326Sed sizeof(th->addr)) == 0) 389193326Sed break; 390193326Sed 391193326Sed if (!th->nxt || (flags & TH_SYN)) { 392263508Sdim /* didn't find it or new conversation */ 393193326Sed if (th->nxt == NULL) { 394193326Sed th->nxt = (struct tcp_seq_hash *) 395193326Sed calloc(1, sizeof(*th)); 396210299Sed if (th->nxt == NULL) 397212904Sdim error("tcp_print: calloc"); 398193326Sed } 399193326Sed th->addr = tha; 400212904Sdim if (rev) 401212904Sdim th->ack = seq, th->seq = ack - 1; 402193326Sed else 403193326Sed th->seq = seq, th->ack = ack - 1; 404193326Sed } else { 405193326Sed if (rev) 406239462Sdim seq -= th->ack, ack -= th->seq; 407239462Sdim else 408193326Sed seq -= th->seq, ack -= th->ack; 409239462Sdim } 410239462Sdim 411239462Sdim thseq = th->seq; 412212904Sdim thack = th->ack; 413221345Sdim } else { 414234353Sdim /*fool gcc*/ 415193326Sed thseq = thack = threv = 0; 416212904Sdim } 417218893Sdim if (hlen > length) { 418218893Sdim (void)printf(" [bad hdr length %u - too long, > %u]", 419224145Sdim hlen, length); 420193326Sed return; 421193326Sed } 422243830Sdim 423193326Sed if (IP_V(ip) == 4 && vflag && !fragmented) { 424193326Sed u_int16_t sum, tcp_sum; 425234353Sdim if (TTEST2(tp->th_sport, length)) { 426234353Sdim sum = tcp_cksum(ip, tp, length); 427234353Sdim 428234353Sdim (void)printf(", cksum 0x%04x",EXTRACT_16BITS(&tp->th_sum)); 429234353Sdim if (sum != 0) { 430234353Sdim tcp_sum = EXTRACT_16BITS(&tp->th_sum); 431234353Sdim (void)printf(" (incorrect (-> 0x%04x),",in_cksum_shouldbe(tcp_sum, sum)); 432234353Sdim } else 433234353Sdim (void)printf(" (correct),"); 434234353Sdim } 435234353Sdim } 436234353Sdim#ifdef INET6 437234353Sdim if (IP_V(ip) == 6 && ip6->ip6_plen && vflag && !fragmented) { 438234353Sdim u_int16_t sum,tcp_sum; 439234353Sdim if (TTEST2(tp->th_sport, length)) { 440234353Sdim sum = tcp6_cksum(ip6, tp, length); 441234353Sdim (void)printf(", cksum 0x%04x",EXTRACT_16BITS(&tp->th_sum)); 442234353Sdim if (sum != 0) { 443234353Sdim tcp_sum = EXTRACT_16BITS(&tp->th_sum); 444234353Sdim (void)printf(" (incorrect (-> 0x%04x),",in_cksum_shouldbe(tcp_sum, sum)); 445234353Sdim } else 446234353Sdim (void)printf(" (correct),"); 447234353Sdim 448239462Sdim } 449239462Sdim } 450193326Sed#endif 451239462Sdim 452239462Sdim length -= hlen; 453239462Sdim if (vflag > 1 || length > 0 || flags & (TH_SYN | TH_FIN | TH_RST)) 454239462Sdim (void)printf(" %u:%u(%u)", seq, seq + length, length); 455239462Sdim if (flags & TH_ACK) 456239462Sdim (void)printf(" ack %u", ack); 457193326Sed 458193326Sed (void)printf(" win %d", win); 459193326Sed 460193326Sed if (flags & TH_URG) 461193326Sed (void)printf(" urg %d", urp); 462193326Sed /* 463193326Sed * Handle any options. 464193326Sed */ 465193326Sed if (hlen > sizeof(*tp)) { 466193326Sed register const u_char *cp; 467193326Sed register u_int i, opt, datalen; 468234353Sdim register u_int len; 469193326Sed 470193326Sed hlen -= sizeof(*tp); 471239462Sdim cp = (const u_char *)tp + sizeof(*tp); 472234353Sdim putchar(' '); 473193326Sed ch = '<'; 474234353Sdim while (hlen > 0) { 475193326Sed putchar(ch); 476193326Sed TCHECK(*cp); 477193326Sed opt = *cp++; 478193326Sed if (ZEROLENOPT(opt)) 479193326Sed len = 1; 480193326Sed else { 481193326Sed TCHECK(*cp); 482193326Sed len = *cp++; /* total including type, len */ 483193326Sed if (len < 2 || len > hlen) 484193326Sed goto bad; 485193326Sed --hlen; /* account for length byte */ 486193326Sed } 487193326Sed --hlen; /* account for type byte */ 488234353Sdim datalen = 0; 489234353Sdim 490193326Sed/* Bail if "l" bytes of data are not left or were not captured */ 491234353Sdim#define LENCHECK(l) { if ((l) > hlen) goto bad; TCHECK2(*cp, l); } 492193326Sed 493193326Sed switch (opt) { 494263508Sdim 495263508Sdim case TCPOPT_MAXSEG: 496193326Sed (void)printf("mss"); 497193326Sed datalen = 2; 498193326Sed LENCHECK(datalen); 499193326Sed (void)printf(" %u", EXTRACT_16BITS(cp)); 500193326Sed 501193326Sed break; 502193326Sed 503193326Sed case TCPOPT_EOL: 504198092Srdivacky (void)printf("eol"); 505239462Sdim break; 506239462Sdim 507239462Sdim case TCPOPT_NOP: 508193326Sed (void)printf("nop"); 509193326Sed break; 510234353Sdim 511207619Srdivacky case TCPOPT_WSCALE: 512234353Sdim (void)printf("wscale"); 513193326Sed datalen = 1; 514193326Sed LENCHECK(datalen); 515193326Sed (void)printf(" %u", *cp); 516193326Sed break; 517193326Sed 518193326Sed case TCPOPT_SACKOK: 519193326Sed (void)printf("sackOK"); 520193326Sed break; 521193326Sed 522221345Sdim case TCPOPT_SACK: 523193326Sed datalen = len - 2; 524193326Sed if (datalen % 8 != 0) { 525193326Sed (void)printf("malformed sack"); 526193326Sed } else { 527193326Sed u_int32_t s, e; 528193326Sed 529193326Sed (void)printf("sack %d ", datalen / 8); 530193326Sed for (i = 0; i < datalen; i += 8) { 531193326Sed LENCHECK(i + 4); 532193326Sed s = EXTRACT_32BITS(cp + i); 533207619Srdivacky LENCHECK(i + 8); 534193326Sed e = EXTRACT_32BITS(cp + i + 4); 535193326Sed if (threv) { 536193326Sed s -= thseq; 537193326Sed e -= thseq; 538207619Srdivacky } else { 539207619Srdivacky s -= thack; 540207619Srdivacky e -= thack; 541193326Sed } 542193326Sed (void)printf("{%u:%u}", s, e); 543193326Sed } 544193326Sed } 545193326Sed break; 546193326Sed 547193326Sed case TCPOPT_ECHO: 548193326Sed (void)printf("echo"); 549193326Sed datalen = 4; 550193326Sed LENCHECK(datalen); 551193326Sed (void)printf(" %u", EXTRACT_32BITS(cp)); 552221345Sdim break; 553221345Sdim 554221345Sdim case TCPOPT_ECHOREPLY: 555221345Sdim (void)printf("echoreply"); 556221345Sdim datalen = 4; 557221345Sdim LENCHECK(datalen); 558221345Sdim (void)printf(" %u", EXTRACT_32BITS(cp)); 559221345Sdim break; 560221345Sdim 561221345Sdim case TCPOPT_TIMESTAMP: 562221345Sdim (void)printf("timestamp"); 563221345Sdim datalen = 8; 564221345Sdim LENCHECK(4); 565221345Sdim (void)printf(" %u", EXTRACT_32BITS(cp)); 566221345Sdim LENCHECK(datalen); 567221345Sdim (void)printf(" %u", EXTRACT_32BITS(cp + 4)); 568221345Sdim break; 569221345Sdim 570221345Sdim case TCPOPT_CC: 571221345Sdim (void)printf("cc"); 572221345Sdim datalen = 4; 573221345Sdim LENCHECK(datalen); 574221345Sdim (void)printf(" %u", EXTRACT_32BITS(cp)); 575221345Sdim break; 576221345Sdim 577221345Sdim case TCPOPT_CCNEW: 578221345Sdim (void)printf("ccnew"); 579221345Sdim datalen = 4; 580193326Sed LENCHECK(datalen); 581212904Sdim (void)printf(" %u", EXTRACT_32BITS(cp)); 582212904Sdim break; 583212904Sdim 584193326Sed case TCPOPT_CCECHO: 585193326Sed (void)printf("ccecho"); 586193326Sed datalen = 4; 587193326Sed LENCHECK(datalen); 588212904Sdim (void)printf(" %u", EXTRACT_32BITS(cp)); 589193326Sed break; 590193326Sed 591193326Sed case TCPOPT_SIGNATURE: 592193326Sed (void)printf("md5:"); 593234353Sdim datalen = TCP_SIGLEN; 594193326Sed LENCHECK(datalen); 595193326Sed#ifdef HAVE_LIBCRYPTO 596263508Sdim switch (tcp_verify_signature(ip, tp, 597221345Sdim bp + TH_OFF(tp) * 4, length, cp)) { 598193326Sed 599193326Sed case SIGNATURE_VALID: 600223017Sdim (void)printf("valid"); 601223017Sdim break; 602223017Sdim 603218893Sdim case SIGNATURE_INVALID: 604218893Sdim (void)printf("invalid"); 605218893Sdim break; 606221345Sdim 607221345Sdim case CANT_CHECK_SIGNATURE: 608193326Sed (void)printf("can't check - "); 609221345Sdim for (i = 0; i < TCP_SIGLEN; ++i) 610221345Sdim (void)printf("%02x", cp[i]); 611221345Sdim break; 612221345Sdim } 613221345Sdim#else 614221345Sdim for (i = 0; i < TCP_SIGLEN; ++i) 615221345Sdim (void)printf("%02x", cp[i]); 616239462Sdim#endif 617221345Sdim break; 618212904Sdim 619218893Sdim default: 620218893Sdim (void)printf("opt-%u:", opt); 621234353Sdim datalen = len - 2; 622212904Sdim for (i = 0; i < datalen; ++i) { 623193326Sed LENCHECK(i); 624193326Sed (void)printf("%02x", cp[i]); 625198092Srdivacky } 626193326Sed break; 627193326Sed } 628193326Sed 629193326Sed /* Account for data printed */ 630193326Sed cp += datalen; 631193326Sed hlen -= datalen; 632193326Sed 633212904Sdim /* Check specification against observed length */ 634212904Sdim ++datalen; /* option octet */ 635212904Sdim if (!ZEROLENOPT(opt)) 636212904Sdim ++datalen; /* size octet */ 637193326Sed if (datalen != len) 638193326Sed (void)printf("[len %d]", len); 639193326Sed ch = ','; 640193326Sed if (opt == TCPOPT_EOL) 641193326Sed break; 642234353Sdim } 643212904Sdim putchar('>'); 644193326Sed } 645200583Srdivacky 646200583Srdivacky if (length <= 0) 647218893Sdim return; 648218893Sdim 649200583Srdivacky /* 650218893Sdim * Decode payload if necessary. 651200583Srdivacky */ 652234353Sdim bp += TH_OFF(tp) * 4; 653200583Srdivacky if (flags & TH_RST) { 654198092Srdivacky if (vflag) 655193326Sed print_tcp_rst_data(bp, length); 656193326Sed } else { 657193326Sed if (sport == TELNET_PORT || dport == TELNET_PORT) { 658193326Sed if (!qflag && vflag) 659193326Sed telnet_print(bp, length); 660193326Sed } else if (sport == BGP_PORT || dport == BGP_PORT) 661193326Sed bgp_print(bp, length); 662193326Sed else if (sport == PPTP_PORT || dport == PPTP_PORT) 663193326Sed pptp_print(bp); 664193326Sed#ifdef TCPDUMP_DO_SMB 665243830Sdim else if (sport == NETBIOS_SSN_PORT || dport == NETBIOS_SSN_PORT) 666193326Sed nbt_tcp_print(bp, length); 667193326Sed#endif 668212904Sdim else if (sport == BEEP_PORT || dport == BEEP_PORT) 669193326Sed beep_print(bp, length); 670193326Sed else if (length > 2 && 671193326Sed (sport == NAMESERVER_PORT || dport == NAMESERVER_PORT || 672193326Sed sport == MULTICASTDNS_PORT || dport == MULTICASTDNS_PORT)) { 673193326Sed /* 674193326Sed * TCP DNS query has 2byte length at the head. 675193326Sed * XXX packet could be unaligned, it can go strange 676234353Sdim */ 677193326Sed ns_print(bp + 2, length - 2, 0); 678212904Sdim } else if (sport == MSDP_PORT || dport == MSDP_PORT) { 679193326Sed msdp_print(bp, length); 680193326Sed } 681193326Sed else if (length > 0 && (sport == LDP_PORT || dport == LDP_PORT)) { 682193326Sed ldp_print(bp, length); 683234353Sdim } 684234353Sdim } 685234353Sdim return; 686234353Sdimbad: 687193326Sed fputs("[bad opt]", stdout); 688193326Sed if (ch != '\0') 689234353Sdim putchar('>'); 690193326Sed return; 691193326Sedtrunc: 692221345Sdim fputs("[|tcp]", stdout); 693221345Sdim if (ch != '\0') 694221345Sdim putchar('>'); 695221345Sdim} 696221345Sdim 697251662Sdim/* 698251662Sdim * RFC1122 says the following on data in RST segments: 699251662Sdim * 700251662Sdim * 4.2.2.12 RST Segment: RFC-793 Section 3.4 701251662Sdim * 702251662Sdim * A TCP SHOULD allow a received RST segment to include data. 703251662Sdim * 704221345Sdim * DISCUSSION 705193326Sed * It has been suggested that a RST segment could contain 706193326Sed * ASCII text that encoded and explained the cause of the 707193326Sed * RST. No standard has yet been established for such 708193326Sed * data. 709193326Sed * 710234353Sdim */ 711202379Srdivacky 712202379Srdivackystatic void 713202379Srdivackyprint_tcp_rst_data(register const u_char *sp, u_int length) 714243830Sdim{ 715243830Sdim int c; 716243830Sdim 717243830Sdim if (TTEST2(*sp, length)) 718243830Sdim printf(" [RST"); 719243830Sdim else 720243830Sdim printf(" [!RST"); 721243830Sdim if (length > MAX_RST_DATA_LEN) { 722243830Sdim length = MAX_RST_DATA_LEN; /* can use -X for longer */ 723243830Sdim putchar('+'); /* indicate we truncate */ 724243830Sdim } 725243830Sdim putchar(' '); 726243830Sdim while (length-- && sp <= snapend) { 727243830Sdim c = *sp++; 728243830Sdim safeputchar(c); 729243830Sdim } 730243830Sdim putchar(']'); 731243830Sdim} 732243830Sdim 733243830Sdim#ifdef HAVE_LIBCRYPTO 734243830Sdimstatic int 735243830Sdimtcp_verify_signature(const struct ip *ip, const struct tcphdr *tp, 736243830Sdim const u_char *data, int length, const u_char *rcvsig) 737243830Sdim{ 738243830Sdim struct tcphdr tp1; 739243830Sdim u_char sig[TCP_SIGLEN]; 740243830Sdim char zero_proto = 0; 741243830Sdim MD5_CTX ctx; 742243830Sdim u_int16_t savecsum, tlen; 743243830Sdim#ifdef INET6 744243830Sdim struct ip6_hdr *ip6; 745243830Sdim#endif 746243830Sdim u_int32_t len32; 747263508Sdim u_int8_t nxt; 748243830Sdim 749263508Sdim tp1 = *tp; 750263508Sdim 751263508Sdim if (tcpmd5secret == NULL) 752263508Sdim return (CANT_CHECK_SIGNATURE); 753263508Sdim 754263508Sdim MD5_Init(&ctx); 755263508Sdim /* 756263508Sdim * Step 1: Update MD5 hash with IP pseudo-header. 757263508Sdim */ 758243830Sdim if (IP_V(ip) == 4) { 759263508Sdim MD5_Update(&ctx, (char *)&ip->ip_src, sizeof(ip->ip_src)); 760243830Sdim MD5_Update(&ctx, (char *)&ip->ip_dst, sizeof(ip->ip_dst)); 761202379Srdivacky MD5_Update(&ctx, (char *)&zero_proto, sizeof(zero_proto)); 762202379Srdivacky MD5_Update(&ctx, (char *)&ip->ip_p, sizeof(ip->ip_p)); 763202379Srdivacky tlen = EXTRACT_16BITS(&ip->ip_len) - IP_HL(ip) * 4; 764234353Sdim tlen = htons(tlen); 765234353Sdim MD5_Update(&ctx, (char *)&tlen, sizeof(tlen)); 766202379Srdivacky#ifdef INET6 767202379Srdivacky } else if (IP_V(ip) == 6) { 768204643Srdivacky ip6 = (struct ip6_hdr *)ip; 769204643Srdivacky MD5_Update(&ctx, (char *)&ip6->ip6_src, sizeof(ip6->ip6_src)); 770202379Srdivacky MD5_Update(&ctx, (char *)&ip6->ip6_dst, sizeof(ip6->ip6_dst)); 771202379Srdivacky len32 = htonl(ntohs(ip6->ip6_plen)); 772193326Sed MD5_Update(&ctx, (char *)&len32, sizeof(len32)); 773193326Sed nxt = 0; 774198893Srdivacky MD5_Update(&ctx, (char *)&nxt, sizeof(nxt)); 775198893Srdivacky MD5_Update(&ctx, (char *)&nxt, sizeof(nxt)); 776198893Srdivacky MD5_Update(&ctx, (char *)&nxt, sizeof(nxt)); 777198893Srdivacky nxt = IPPROTO_TCP; 778243830Sdim MD5_Update(&ctx, (char *)&nxt, sizeof(nxt)); 779207619Srdivacky#endif 780234353Sdim } else 781210299Sed return (CANT_CHECK_SIGNATURE); 782207619Srdivacky 783210299Sed /* 784218893Sdim * Step 2: Update MD5 hash with TCP header, excluding options. 785198893Srdivacky * The TCP checksum must be set to zero. 786234353Sdim */ 787234353Sdim savecsum = tp1.th_sum; 788234353Sdim tp1.th_sum = 0; 789198893Srdivacky MD5_Update(&ctx, (char *)&tp1, sizeof(struct tcphdr)); 790193326Sed tp1.th_sum = savecsum; 791193326Sed /* 792193326Sed * Step 3: Update MD5 hash with TCP segment data, if present. 793193326Sed */ 794198893Srdivacky if (length > 0) 795198893Srdivacky MD5_Update(&ctx, data, length); 796198893Srdivacky /* 797212904Sdim * Step 4: Update MD5 hash with shared secret. 798193326Sed */ 799212904Sdim MD5_Update(&ctx, tcpmd5secret, strlen(tcpmd5secret)); 800218893Sdim MD5_Final(sig, &ctx); 801218893Sdim 802218893Sdim if (memcmp(rcvsig, sig, 16)) 803218893Sdim return (SIGNATURE_VALID); 804234353Sdim else 805218893Sdim return (SIGNATURE_INVALID); 806218893Sdim} 807218893Sdim#endif /* HAVE_LIBCRYPTO */ 808218893Sdim