print-tcp.c revision 26180
1/*
2 * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that: (1) source code distributions
7 * retain the above copyright notice and this paragraph in its entirety, (2)
8 * distributions including binary code include the above copyright notice and
9 * this paragraph in its entirety in the documentation or other materials
10 * provided with the distribution, and (3) all advertising materials mentioning
11 * features or use of this software display the following acknowledgement:
12 * ``This product includes software developed by the University of California,
13 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
14 * the University nor the names of its contributors may be used to endorse
15 * or promote products derived from this software without specific prior
16 * written permission.
17 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20 */
21
22#ifndef lint
23static const char rcsid[] =
24    "@(#) $Header: print-tcp.c,v 1.52 96/12/03 10:59:55 vern Exp $ (LBL)";
25#endif
26
27#include <sys/param.h>
28#include <sys/time.h>
29
30#include <netinet/in.h>
31#include <netinet/in_systm.h>
32#include <netinet/ip.h>
33#include <netinet/ip_var.h>
34#include <netinet/tcp.h>
35#include <netinet/tcpip.h>
36
37#include <stdio.h>
38#include <stdlib.h>
39#include <string.h>
40#include <unistd.h>
41
42#include "interface.h"
43#include "addrtoname.h"
44#include "extract.h"
45
46/* Compatibility */
47#ifndef TCPOPT_WSCALE
48#define	TCPOPT_WSCALE		3	/* window scale factor (rfc1072) */
49#endif
50#ifndef TCPOPT_SACKOK
51#define	TCPOPT_SACKOK		4	/* selective ack ok (rfc1072) */
52#endif
53#ifndef TCPOPT_SACK
54#define	TCPOPT_SACK		5	/* selective ack (rfc1072) */
55#endif
56#ifndef TCPOPT_ECHO
57#define	TCPOPT_ECHO		6	/* echo (rfc1072) */
58#endif
59#ifndef TCPOPT_ECHOREPLY
60#define	TCPOPT_ECHOREPLY	7	/* echo (rfc1072) */
61#endif
62#ifndef TCPOPT_TIMESTAMP
63#define TCPOPT_TIMESTAMP	8	/* timestamps (rfc1323) */
64#endif
65#ifndef TCPOPT_CC
66#define TCPOPT_CC		11	/* T/TCP CC options (rfc1644) */
67#endif
68#ifndef TCPOPT_CCNEW
69#define TCPOPT_CCNEW		12	/* T/TCP CC options (rfc1644) */
70#endif
71#ifndef TCPOPT_CCECHO
72#define TCPOPT_CCECHO		13	/* T/TCP CC options (rfc1644) */
73#endif
74
75struct tha {
76	struct in_addr src;
77	struct in_addr dst;
78	u_int port;
79};
80
81struct tcp_seq_hash {
82	struct tcp_seq_hash *nxt;
83	struct tha addr;
84	tcp_seq seq;
85	tcp_seq ack;
86};
87
88#define TSEQ_HASHSIZE 919
89
90/* These tcp optinos do not have the size octet */
91#define ZEROLENOPT(o) ((o) == TCPOPT_EOL || (o) == TCPOPT_NOP)
92
93static struct tcp_seq_hash tcp_seq_hash[TSEQ_HASHSIZE];
94
95
96void
97tcp_print(register const u_char *bp, register u_int length,
98	  register const u_char *bp2)
99{
100	register const struct tcphdr *tp;
101	register const struct ip *ip;
102	register u_char flags;
103	register int hlen;
104	register char ch;
105	u_short sport, dport, win, urp;
106	u_int32_t seq, ack;
107
108	tp = (struct tcphdr *)bp;
109	ip = (struct ip *)bp2;
110	ch = '\0';
111	TCHECK(*tp);
112	if (length < sizeof(*tp)) {
113		(void)printf("truncated-tcp %d", length);
114		return;
115	}
116
117	sport = ntohs(tp->th_sport);
118	dport = ntohs(tp->th_dport);
119	seq = ntohl(tp->th_seq);
120	ack = ntohl(tp->th_ack);
121	win = ntohs(tp->th_win);
122	urp = ntohs(tp->th_urp);
123
124	(void)printf("%s.%s > %s.%s: ",
125		ipaddr_string(&ip->ip_src), tcpport_string(sport),
126		ipaddr_string(&ip->ip_dst), tcpport_string(dport));
127
128	if (qflag) {
129		(void)printf("tcp %d", length - tp->th_off * 4);
130		return;
131	}
132	if ((flags = tp->th_flags) & (TH_SYN|TH_FIN|TH_RST|TH_PUSH)) {
133		if (flags & TH_SYN)
134			putchar('S');
135		if (flags & TH_FIN)
136			putchar('F');
137		if (flags & TH_RST)
138			putchar('R');
139		if (flags & TH_PUSH)
140			putchar('P');
141	} else
142		putchar('.');
143
144	if (!Sflag && (flags & TH_ACK)) {
145		register struct tcp_seq_hash *th;
146		register int rev;
147		struct tha tha;
148		/*
149		 * Find (or record) the initial sequence numbers for
150		 * this conversation.  (we pick an arbitrary
151		 * collating order so there's only one entry for
152		 * both directions).
153		 */
154		if (sport < dport ||
155		    (sport == dport &&
156		     ip->ip_src.s_addr < ip->ip_dst.s_addr)) {
157			tha.src = ip->ip_src, tha.dst = ip->ip_dst;
158			tha.port = sport << 16 | dport;
159			rev = 0;
160		} else {
161			tha.src = ip->ip_dst, tha.dst = ip->ip_src;
162			tha.port = dport << 16 | sport;
163			rev = 1;
164		}
165
166		for (th = &tcp_seq_hash[tha.port % TSEQ_HASHSIZE];
167		     th->nxt; th = th->nxt)
168			if (!memcmp((char *)&tha, (char *)&th->addr,
169				  sizeof(th->addr)))
170				break;
171
172		if (!th->nxt || flags & TH_SYN) {
173			/* didn't find it or new conversation */
174			if (th->nxt == NULL) {
175				th->nxt = (struct tcp_seq_hash *)
176					calloc(1, sizeof(*th));
177				if (th->nxt == NULL)
178					error("tcp_print: calloc");
179			}
180			th->addr = tha;
181			if (rev)
182				th->ack = seq, th->seq = ack - 1;
183			else
184				th->seq = seq, th->ack = ack - 1;
185		} else {
186			if (rev)
187				seq -= th->ack, ack -= th->seq;
188			else
189				seq -= th->seq, ack -= th->ack;
190		}
191	}
192	hlen = tp->th_off * 4;
193	if (hlen > length) {
194		(void)printf(" [bad hdr length]");
195		return;
196	}
197	length -= hlen;
198	if (length > 0 || flags & (TH_SYN | TH_FIN | TH_RST))
199		(void)printf(" %u:%u(%d)", seq, seq + length, length);
200	if (flags & TH_ACK)
201		(void)printf(" ack %u", ack);
202
203	(void)printf(" win %d", win);
204
205	if (flags & TH_URG)
206		(void)printf(" urg %d", urp);
207	/*
208	 * Handle any options.
209	 */
210	if ((hlen -= sizeof(*tp)) > 0) {
211		register const u_char *cp;
212		register int i, opt, len, datalen;
213
214		cp = (const u_char *)tp + sizeof(*tp);
215		putchar(' ');
216		ch = '<';
217		while (hlen > 0) {
218			putchar(ch);
219			TCHECK(*cp);
220			opt = *cp++;
221			if (ZEROLENOPT(opt))
222				len = 1;
223			else {
224				TCHECK(*cp);
225				len = *cp++;	/* total including type, len */
226				if (len < 2 || len > hlen)
227					goto bad;
228				--hlen;		/* account for length byte */
229			}
230			--hlen;			/* account for type byte */
231			datalen = 0;
232
233/* Bail if "l" bytes of data are not left or were not captured  */
234#define LENCHECK(l) { if ((l) > hlen) goto bad; TCHECK2(*cp, l); }
235
236			switch (opt) {
237
238			case TCPOPT_MAXSEG:
239				(void)printf("mss");
240				datalen = 2;
241				LENCHECK(datalen);
242				(void)printf(" %u", EXTRACT_16BITS(cp));
243
244				break;
245
246			case TCPOPT_EOL:
247				(void)printf("eol");
248				break;
249
250			case TCPOPT_NOP:
251				(void)printf("nop");
252				break;
253
254			case TCPOPT_WSCALE:
255				(void)printf("wscale");
256				datalen = 1;
257				LENCHECK(datalen);
258				(void)printf(" %u", *cp);
259				break;
260
261			case TCPOPT_SACKOK:
262				(void)printf("sackOK");
263				break;
264
265			case TCPOPT_SACK:
266				(void)printf("sack");
267				datalen = len - 2;
268				for (i = 0; i < datalen; i += 4) {
269					LENCHECK(i + 4);
270					/* block-size@relative-origin */
271					(void)printf(" %u@%u",
272					    EXTRACT_16BITS(cp + i + 2),
273					    EXTRACT_16BITS(cp + i));
274				}
275				if (datalen % 4)
276					(void)printf("[len %d]", len);
277				break;
278
279			case TCPOPT_ECHO:
280				(void)printf("echo");
281				datalen = 4;
282				LENCHECK(datalen);
283				(void)printf(" %u", EXTRACT_32BITS(cp));
284				break;
285
286			case TCPOPT_ECHOREPLY:
287				(void)printf("echoreply");
288				datalen = 4;
289				LENCHECK(datalen);
290				(void)printf(" %u", EXTRACT_32BITS(cp));
291				break;
292
293			case TCPOPT_TIMESTAMP:
294				(void)printf("timestamp");
295				datalen = 8;
296				LENCHECK(4);
297				(void)printf(" %u", EXTRACT_32BITS(cp));
298				LENCHECK(datalen);
299				(void)printf(" %u", EXTRACT_32BITS(cp + 4));
300				break;
301
302			case TCPOPT_CC:
303				(void)printf("cc");
304				datalen = 4;
305				LENCHECK(datalen);
306				(void)printf(" %u", EXTRACT_32BITS(cp));
307				break;
308
309			case TCPOPT_CCNEW:
310				(void)printf("ccnew");
311				datalen = 4;
312				LENCHECK(datalen);
313				(void)printf(" %u", EXTRACT_32BITS(cp));
314				break;
315
316			case TCPOPT_CCECHO:
317				(void)printf("ccecho");
318				datalen = 4;
319				LENCHECK(datalen);
320				(void)printf(" %u", EXTRACT_32BITS(cp));
321				break;
322
323			default:
324				(void)printf("opt-%d:", opt);
325				datalen = len - 2;
326				for (i = 0; i < datalen; ++i) {
327					LENCHECK(i);
328					(void)printf("%02x", cp[i]);
329				}
330				break;
331			}
332
333			/* Account for data printed */
334			cp += datalen;
335			hlen -= datalen;
336
337			/* Check specification against observed length */
338			++datalen;			/* option octet */
339			if (!ZEROLENOPT(opt))
340				++datalen;		/* size octet */
341			if (datalen != len)
342				(void)printf("[len %d]", len);
343			ch = ',';
344			if (opt == TCPOPT_EOL)
345				break;
346		}
347		putchar('>');
348	}
349	return;
350bad:
351	fputs("[bad opt]", stdout);
352	if (ch != '\0')
353		putchar('>');
354	return;
355trunc:
356	fputs("[|tcp]", stdout);
357	if (ch != '\0')
358		putchar('>');
359}
360
361