print-tcp.c revision 75115
1179186Sjb/*
2179186Sjb * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997
3179186Sjb *	The Regents of the University of California.  All rights reserved.
4179186Sjb *
5210688Srpaulo * Redistribution and use in source and binary forms, with or without
6179186Sjb * modification, are permitted provided that: (1) source code distributions
7210688Srpaulo * retain the above copyright notice and this paragraph in its entirety, (2)
8179186Sjb * distributions including binary code include the above copyright notice and
9210688Srpaulo * this paragraph in its entirety in the documentation or other materials
10179186Sjb * provided with the distribution, and (3) all advertising materials mentioning
11179186Sjb * features or use of this software display the following acknowledgement:
12179186Sjb * ``This product includes software developed by the University of California,
13179186Sjb * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
14204338Sru * the University nor the names of its contributors may be used to endorse
15179186Sjb * or promote products derived from this software without specific prior
16210694Srpaulo * written permission.
17179186Sjb * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18204338Sru * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19179186Sjb * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20179186Sjb */
21
22#ifndef lint
23static const char rcsid[] =
24    "@(#) $Header: /tcpdump/master/tcpdump/print-tcp.c,v 1.81 2000/12/23 20:55:22 guy Exp $ (LBL)";
25#endif
26
27#ifdef HAVE_CONFIG_H
28#include "config.h"
29#endif
30
31#include <sys/param.h>
32#include <sys/time.h>
33
34#include <rpc/rpc.h>
35
36#include <netinet/in.h>
37
38#include <stdio.h>
39#include <stdlib.h>
40#include <string.h>
41#include <ctype.h>
42#include <unistd.h>
43
44#include "interface.h"
45#include "addrtoname.h"
46#include "extract.h"
47
48#include "tcp.h"
49
50#include "ip.h"
51#ifdef INET6
52#include "ip6.h"
53#endif
54
55static void print_tcp_rst_data(register const u_char *sp, u_int length);
56
57#define MAX_RST_DATA_LEN	30
58
59/* Compatibility */
60#ifndef TCPOPT_WSCALE
61#define	TCPOPT_WSCALE		3	/* window scale factor (rfc1072) */
62#endif
63#ifndef TCPOPT_SACKOK
64#define	TCPOPT_SACKOK		4	/* selective ack ok (rfc1072) */
65#endif
66#ifndef TCPOPT_SACK
67#define	TCPOPT_SACK		5	/* selective ack (rfc1072) */
68#endif
69#ifndef TCPOPT_ECHO
70#define	TCPOPT_ECHO		6	/* echo (rfc1072) */
71#endif
72#ifndef TCPOPT_ECHOREPLY
73#define	TCPOPT_ECHOREPLY	7	/* echo (rfc1072) */
74#endif
75#ifndef TCPOPT_TIMESTAMP
76#define TCPOPT_TIMESTAMP	8	/* timestamps (rfc1323) */
77#endif
78#ifndef TCPOPT_CC
79#define TCPOPT_CC		11	/* T/TCP CC options (rfc1644) */
80#endif
81#ifndef TCPOPT_CCNEW
82#define TCPOPT_CCNEW		12	/* T/TCP CC options (rfc1644) */
83#endif
84#ifndef TCPOPT_CCECHO
85#define TCPOPT_CCECHO		13	/* T/TCP CC options (rfc1644) */
86#endif
87
88/*
89 * Definitions required for ECN
90 * for use if the OS running tcpdump does not have ECN
91 */
92#ifndef TH_ECNECHO
93#define TH_ECNECHO		0x40	/* ECN Echo in tcp header */
94#endif
95#ifndef TH_CWR
96#define TH_CWR			0x80	/* ECN Cwnd Reduced in tcp header*/
97#endif
98
99struct tha {
100#ifndef INET6
101	struct in_addr src;
102	struct in_addr dst;
103#else
104	struct in6_addr src;
105	struct in6_addr dst;
106#endif /*INET6*/
107	u_int port;
108};
109
110struct tcp_seq_hash {
111	struct tcp_seq_hash *nxt;
112	struct tha addr;
113	tcp_seq seq;
114	tcp_seq ack;
115};
116
117#define TSEQ_HASHSIZE 919
118
119/* These tcp optinos do not have the size octet */
120#define ZEROLENOPT(o) ((o) == TCPOPT_EOL || (o) == TCPOPT_NOP)
121
122static struct tcp_seq_hash tcp_seq_hash[TSEQ_HASHSIZE];
123
124
125#ifndef TELNET_PORT
126#define TELNET_PORT	23
127#endif
128#ifndef BGP_PORT
129#define BGP_PORT	179
130#endif
131#define NETBIOS_SSN_PORT 139
132#define BXXP_PORT        10288
133#ifndef NFS_PORT
134#define NFS_PORT	2049
135#endif
136
137static int tcp_cksum(register const struct ip *ip,
138		     register const struct tcphdr *tp,
139		     register int len)
140{
141	int i, tlen;
142	union phu {
143		struct phdr {
144			u_int32_t src;
145			u_int32_t dst;
146			u_char mbz;
147			u_char proto;
148			u_int16_t len;
149		} ph;
150		u_int16_t pa[6];
151	} phu;
152	register const u_int16_t *sp;
153	u_int32_t sum;
154	tlen = ntohs(ip->ip_len) - ((const char *)tp-(const char*)ip);
155
156	/* pseudo-header.. */
157	phu.ph.len = htons(tlen);
158	phu.ph.mbz = 0;
159	phu.ph.proto = IPPROTO_TCP;
160	memcpy(&phu.ph.src, &ip->ip_src.s_addr, sizeof(u_int32_t));
161	memcpy(&phu.ph.dst, &ip->ip_dst.s_addr, sizeof(u_int32_t));
162
163	sp = &phu.pa[0];
164	sum = sp[0]+sp[1]+sp[2]+sp[3]+sp[4]+sp[5];
165
166	sp = (const u_int16_t *)tp;
167
168	for (i=0; i<(tlen&~1); i+= 2)
169		sum += *sp++;
170
171	if (tlen & 1) {
172		sum += htons( (*(const u_int8_t *)sp) << 8);
173	}
174
175	while (sum > 0xffff)
176		sum = (sum & 0xffff) + (sum >> 16);
177	sum = ~sum & 0xffff;
178
179	return (sum);
180}
181
182#ifdef INET6
183static int tcp6_cksum(const struct ip6_hdr *ip6, const struct tcphdr *tp,
184	int len)
185{
186	int i, tlen;
187	register const u_int16_t *sp;
188	u_int32_t sum;
189	union {
190		struct {
191			struct in6_addr ph_src;
192			struct in6_addr ph_dst;
193			u_int32_t	ph_len;
194			u_int8_t	ph_zero[3];
195			u_int8_t	ph_nxt;
196		} ph;
197		u_int16_t pa[20];
198	} phu;
199
200	tlen = ntohs(ip6->ip6_plen) + sizeof(struct ip6_hdr) -
201	    ((const char *)tp - (const char*)ip6);
202
203	/* pseudo-header */
204	memset(&phu, 0, sizeof(phu));
205	phu.ph.ph_src = ip6->ip6_src;
206	phu.ph.ph_dst = ip6->ip6_dst;
207	phu.ph.ph_len = htonl(tlen);
208	phu.ph.ph_nxt = IPPROTO_TCP;
209
210	sum = 0;
211	for (i = 0; i < sizeof(phu.pa) / sizeof(phu.pa[0]); i++)
212		sum += phu.pa[i];
213
214	sp = (const u_int16_t *)tp;
215
216	for (i = 0; i < (tlen & ~1); i += 2)
217		sum += *sp++;
218
219	if (tlen & 1)
220		sum += htons((*(const u_int8_t *)sp) << 8);
221
222	while (sum > 0xffff)
223		sum = (sum & 0xffff) + (sum >> 16);
224	sum = ~sum & 0xffff;
225
226	return (sum);
227}
228#endif
229
230void
231tcp_print(register const u_char *bp, register u_int length,
232	  register const u_char *bp2, int fragmented)
233{
234	register const struct tcphdr *tp;
235	register const struct ip *ip;
236	register u_char flags;
237	register int hlen;
238	register char ch;
239	u_int16_t sport, dport, win, urp;
240	u_int32_t seq, ack, thseq, thack;
241	int threv;
242#ifdef INET6
243	register const struct ip6_hdr *ip6;
244#endif
245
246	tp = (struct tcphdr *)bp;
247	ip = (struct ip *)bp2;
248#ifdef INET6
249	if (IP_V(ip) == 6)
250		ip6 = (struct ip6_hdr *)bp2;
251	else
252		ip6 = NULL;
253#endif /*INET6*/
254	ch = '\0';
255	if (!TTEST(tp->th_dport)) {
256		(void)printf("%s > %s: [|tcp]",
257			ipaddr_string(&ip->ip_src),
258			ipaddr_string(&ip->ip_dst));
259		return;
260	}
261
262	sport = ntohs(tp->th_sport);
263	dport = ntohs(tp->th_dport);
264
265
266	hlen = TH_OFF(tp) * 4;
267
268	/*
269	 * If data present and NFS port used, assume NFS.
270	 * Pass offset of data plus 4 bytes for RPC TCP msg length
271	 * to NFS print routines.
272	 */
273	if (!qflag) {
274		if ((u_char *)tp + 4 + sizeof(struct rpc_msg) <= snapend &&
275		    dport == NFS_PORT) {
276			nfsreq_print((u_char *)tp + hlen + 4, length-hlen,
277				     (u_char *)ip);
278			return;
279		} else if ((u_char *)tp + 4 + sizeof(struct rpc_msg)
280			   <= snapend &&
281			   sport == NFS_PORT) {
282			nfsreply_print((u_char *)tp + hlen + 4,length-hlen,
283				       (u_char *)ip);
284			return;
285		}
286	}
287#ifdef INET6
288	if (ip6) {
289		if (ip6->ip6_nxt == IPPROTO_TCP) {
290			(void)printf("%s.%s > %s.%s: ",
291				ip6addr_string(&ip6->ip6_src),
292				tcpport_string(sport),
293				ip6addr_string(&ip6->ip6_dst),
294				tcpport_string(dport));
295		} else {
296			(void)printf("%s > %s: ",
297				tcpport_string(sport), tcpport_string(dport));
298		}
299	} else
300#endif /*INET6*/
301	{
302		if (ip->ip_p == IPPROTO_TCP) {
303			(void)printf("%s.%s > %s.%s: ",
304				ipaddr_string(&ip->ip_src),
305				tcpport_string(sport),
306				ipaddr_string(&ip->ip_dst),
307				tcpport_string(dport));
308		} else {
309			(void)printf("%s > %s: ",
310				tcpport_string(sport), tcpport_string(dport));
311		}
312	}
313
314	TCHECK(*tp);
315
316	seq = (u_int32_t)ntohl(tp->th_seq);
317	ack = (u_int32_t)ntohl(tp->th_ack);
318	win = ntohs(tp->th_win);
319	urp = ntohs(tp->th_urp);
320
321	if (qflag) {
322		(void)printf("tcp %d", length - TH_OFF(tp) * 4);
323		return;
324	}
325	if ((flags = tp->th_flags) & (TH_SYN|TH_FIN|TH_RST|TH_PUSH|
326				      TH_ECNECHO|TH_CWR)) {
327		if (flags & TH_SYN)
328			putchar('S');
329		if (flags & TH_FIN)
330			putchar('F');
331		if (flags & TH_RST)
332			putchar('R');
333		if (flags & TH_PUSH)
334			putchar('P');
335		if (flags & TH_CWR)
336			putchar('W');	/* congestion _W_indow reduced (ECN) */
337		if (flags & TH_ECNECHO)
338			putchar('E');	/* ecn _E_cho sent (ECN) */
339	} else
340		putchar('.');
341
342	if (!Sflag && (flags & TH_ACK)) {
343		register struct tcp_seq_hash *th;
344		register int rev;
345		struct tha tha;
346		/*
347		 * Find (or record) the initial sequence numbers for
348		 * this conversation.  (we pick an arbitrary
349		 * collating order so there's only one entry for
350		 * both directions).
351		 */
352#ifdef INET6
353		memset(&tha, 0, sizeof(tha));
354		rev = 0;
355		if (ip6) {
356			if (sport > dport) {
357				rev = 1;
358			} else if (sport == dport) {
359			    int i;
360
361			    for (i = 0; i < 4; i++) {
362				if (((u_int32_t *)(&ip6->ip6_src))[i] >
363				    ((u_int32_t *)(&ip6->ip6_dst))[i]) {
364					rev = 1;
365					break;
366				}
367			    }
368			}
369			if (rev) {
370				tha.src = ip6->ip6_dst;
371				tha.dst = ip6->ip6_src;
372				tha.port = dport << 16 | sport;
373			} else {
374				tha.dst = ip6->ip6_dst;
375				tha.src = ip6->ip6_src;
376				tha.port = sport << 16 | dport;
377			}
378		} else {
379			if (sport > dport ||
380			    (sport == dport &&
381			     ip->ip_src.s_addr > ip->ip_dst.s_addr)) {
382				rev = 1;
383			}
384			if (rev) {
385				*(struct in_addr *)&tha.src = ip->ip_dst;
386				*(struct in_addr *)&tha.dst = ip->ip_src;
387				tha.port = dport << 16 | sport;
388			} else {
389				*(struct in_addr *)&tha.dst = ip->ip_dst;
390				*(struct in_addr *)&tha.src = ip->ip_src;
391				tha.port = sport << 16 | dport;
392			}
393		}
394#else
395		if (sport < dport ||
396		    (sport == dport &&
397		     ip->ip_src.s_addr < ip->ip_dst.s_addr)) {
398			tha.src = ip->ip_src, tha.dst = ip->ip_dst;
399			tha.port = sport << 16 | dport;
400			rev = 0;
401		} else {
402			tha.src = ip->ip_dst, tha.dst = ip->ip_src;
403			tha.port = dport << 16 | sport;
404			rev = 1;
405		}
406#endif
407
408		threv = rev;
409		for (th = &tcp_seq_hash[tha.port % TSEQ_HASHSIZE];
410		     th->nxt; th = th->nxt)
411			if (!memcmp((char *)&tha, (char *)&th->addr,
412				  sizeof(th->addr)))
413				break;
414
415		if (!th->nxt || (flags & TH_SYN)) {
416			/* didn't find it or new conversation */
417			if (th->nxt == NULL) {
418				th->nxt = (struct tcp_seq_hash *)
419					calloc(1, sizeof(*th));
420				if (th->nxt == NULL)
421					error("tcp_print: calloc");
422			}
423			th->addr = tha;
424			if (rev)
425				th->ack = seq, th->seq = ack - 1;
426			else
427				th->seq = seq, th->ack = ack - 1;
428
429		} else {
430			if (rev)
431				seq -= th->ack, ack -= th->seq;
432			else
433				seq -= th->seq, ack -= th->ack;
434		}
435
436		thseq = th->seq;
437		thack = th->ack;
438	} else {
439		/*fool gcc*/
440		thseq = thack = threv = 0;
441	}
442	if (hlen > length) {
443		(void)printf(" [bad hdr length]");
444		return;
445	}
446
447	if (IP_V(ip) == 4 && vflag && !fragmented) {
448		int sum;
449		if (TTEST2(tp->th_sport, length)) {
450			sum = tcp_cksum(ip, tp, length);
451			if (sum != 0)
452				(void)printf(" [bad tcp cksum %x!]", sum);
453			else
454				(void)printf(" [tcp sum ok]");
455		}
456	}
457#ifdef INET6
458	if (IP_V(ip) == 6 && ip6->ip6_plen && vflag && !fragmented) {
459		int sum;
460		if (TTEST2(tp->th_sport, length)) {
461			sum = tcp6_cksum(ip6, tp, length);
462			if (sum != 0)
463				(void)printf(" [bad tcp cksum %x!]", sum);
464			else
465				(void)printf(" [tcp sum ok]");
466		}
467	}
468#endif
469
470	length -= hlen;
471	if (vflag > 1 || length > 0 || flags & (TH_SYN | TH_FIN | TH_RST))
472		(void)printf(" %u:%u(%d)", seq, seq + length, length);
473	if (flags & TH_ACK)
474		(void)printf(" ack %u", ack);
475
476	(void)printf(" win %d", win);
477
478	if (flags & TH_URG)
479		(void)printf(" urg %d", urp);
480	/*
481	 * Handle any options.
482	 */
483	if ((hlen -= sizeof(*tp)) > 0) {
484		register const u_char *cp;
485		register int i, opt, len, datalen;
486
487		cp = (const u_char *)tp + sizeof(*tp);
488		putchar(' ');
489		ch = '<';
490		while (hlen > 0) {
491			putchar(ch);
492			TCHECK(*cp);
493			opt = *cp++;
494			if (ZEROLENOPT(opt))
495				len = 1;
496			else {
497				TCHECK(*cp);
498				len = *cp++;	/* total including type, len */
499				if (len < 2 || len > hlen)
500					goto bad;
501				--hlen;		/* account for length byte */
502			}
503			--hlen;			/* account for type byte */
504			datalen = 0;
505
506/* Bail if "l" bytes of data are not left or were not captured  */
507#define LENCHECK(l) { if ((l) > hlen) goto bad; TCHECK2(*cp, l); }
508
509			switch (opt) {
510
511			case TCPOPT_MAXSEG:
512				(void)printf("mss");
513				datalen = 2;
514				LENCHECK(datalen);
515				(void)printf(" %u", EXTRACT_16BITS(cp));
516
517				break;
518
519			case TCPOPT_EOL:
520				(void)printf("eol");
521				break;
522
523			case TCPOPT_NOP:
524				(void)printf("nop");
525				break;
526
527			case TCPOPT_WSCALE:
528				(void)printf("wscale");
529				datalen = 1;
530				LENCHECK(datalen);
531				(void)printf(" %u", *cp);
532				break;
533
534			case TCPOPT_SACKOK:
535				(void)printf("sackOK");
536				break;
537
538			case TCPOPT_SACK:
539				(void)printf("sack");
540				datalen = len - 2;
541				if (datalen % 8 != 0) {
542					(void)printf(" malformed sack ");
543				} else {
544					u_int32_t s, e;
545
546					(void)printf(" sack %d ", datalen / 8);
547					for (i = 0; i < datalen; i += 8) {
548						LENCHECK(i + 4);
549						s = EXTRACT_32BITS(cp + i);
550						LENCHECK(i + 8);
551						e = EXTRACT_32BITS(cp + i + 4);
552						if (threv) {
553							s -= thseq;
554							e -= thseq;
555						} else {
556							s -= thack;
557							e -= thack;
558						}
559						(void)printf("{%u:%u}", s, e);
560					}
561					(void)printf(" ");
562				}
563				break;
564
565			case TCPOPT_ECHO:
566				(void)printf("echo");
567				datalen = 4;
568				LENCHECK(datalen);
569				(void)printf(" %u", EXTRACT_32BITS(cp));
570				break;
571
572			case TCPOPT_ECHOREPLY:
573				(void)printf("echoreply");
574				datalen = 4;
575				LENCHECK(datalen);
576				(void)printf(" %u", EXTRACT_32BITS(cp));
577				break;
578
579			case TCPOPT_TIMESTAMP:
580				(void)printf("timestamp");
581				datalen = 8;
582				LENCHECK(4);
583				(void)printf(" %u", EXTRACT_32BITS(cp));
584				LENCHECK(datalen);
585				(void)printf(" %u", EXTRACT_32BITS(cp + 4));
586				break;
587
588			case TCPOPT_CC:
589				(void)printf("cc");
590				datalen = 4;
591				LENCHECK(datalen);
592				(void)printf(" %u", EXTRACT_32BITS(cp));
593				break;
594
595			case TCPOPT_CCNEW:
596				(void)printf("ccnew");
597				datalen = 4;
598				LENCHECK(datalen);
599				(void)printf(" %u", EXTRACT_32BITS(cp));
600				break;
601
602			case TCPOPT_CCECHO:
603				(void)printf("ccecho");
604				datalen = 4;
605				LENCHECK(datalen);
606				(void)printf(" %u", EXTRACT_32BITS(cp));
607				break;
608
609			default:
610				(void)printf("opt-%d:", opt);
611				datalen = len - 2;
612				for (i = 0; i < datalen; ++i) {
613					LENCHECK(i);
614					(void)printf("%02x", cp[i]);
615				}
616				break;
617			}
618
619			/* Account for data printed */
620			cp += datalen;
621			hlen -= datalen;
622
623			/* Check specification against observed length */
624			++datalen;			/* option octet */
625			if (!ZEROLENOPT(opt))
626				++datalen;		/* size octet */
627			if (datalen != len)
628				(void)printf("[len %d]", len);
629			ch = ',';
630			if (opt == TCPOPT_EOL)
631				break;
632		}
633		putchar('>');
634	}
635
636	if (length <= 0)
637		return;
638
639	/*
640	 * Decode payload if necessary.
641	 */
642	bp += TH_OFF(tp) * 4;
643	if (flags & TH_RST) {
644		if (vflag)
645			print_tcp_rst_data(bp, length);
646	} else {
647		if (sport == TELNET_PORT || dport == TELNET_PORT) {
648			if (!qflag && vflag)
649				telnet_print(bp, length);
650		} else if (sport == BGP_PORT || dport == BGP_PORT)
651			bgp_print(bp, length);
652		else if (sport == NETBIOS_SSN_PORT || dport == NETBIOS_SSN_PORT)
653			nbt_tcp_print(bp, length);
654		else if (sport == BXXP_PORT || dport == BXXP_PORT)
655			bxxp_print(bp, length);
656	}
657	return;
658bad:
659	fputs("[bad opt]", stdout);
660	if (ch != '\0')
661		putchar('>');
662	return;
663trunc:
664	fputs("[|tcp]", stdout);
665	if (ch != '\0')
666		putchar('>');
667}
668
669/*
670 * RFC1122 says the following on data in RST segments:
671 *
672 *         4.2.2.12  RST Segment: RFC-793 Section 3.4
673 *
674 *            A TCP SHOULD allow a received RST segment to include data.
675 *
676 *            DISCUSSION
677 *                 It has been suggested that a RST segment could contain
678 *                 ASCII text that encoded and explained the cause of the
679 *                 RST.  No standard has yet been established for such
680 *                 data.
681 *
682 */
683
684static void
685print_tcp_rst_data(register const u_char *sp, u_int length)
686{
687	int c;
688
689	if (TTEST2(*sp, length))
690		printf(" [RST");
691	else
692		printf(" [!RST");
693	if (length > MAX_RST_DATA_LEN) {
694		length = MAX_RST_DATA_LEN;	/* can use -X for longer */
695		putchar('+');			/* indicate we truncate */
696	}
697	putchar(' ');
698	while (length-- && sp <= snapend) {
699		c = *sp++;
700		if (isprint(c))
701			putchar(c);
702		else
703			putchar('.');
704	}
705	putchar(']');
706}
707