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