print-tcp.c revision 17680
1219393Sadrian/*
2219393Sadrian * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996
3219393Sadrian *	The Regents of the University of California.  All rights reserved.
4219393Sadrian *
5219393Sadrian * Redistribution and use in source and binary forms, with or without
6219393Sadrian * modification, are permitted provided that: (1) source code distributions
7219393Sadrian * retain the above copyright notice and this paragraph in its entirety, (2)
8219393Sadrian * distributions including binary code include the above copyright notice and
9219393Sadrian * this paragraph in its entirety in the documentation or other materials
10219393Sadrian * provided with the distribution, and (3) all advertising materials mentioning
11219393Sadrian * features or use of this software display the following acknowledgement:
12219393Sadrian * ``This product includes software developed by the University of California,
13219393Sadrian * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
14219393Sadrian * the University nor the names of its contributors may be used to endorse
15219393Sadrian * or promote products derived from this software without specific prior
16219393Sadrian * written permission.
17219393Sadrian * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18219393Sadrian * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19219393Sadrian * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20219393Sadrian */
21219393Sadrian
22219393Sadrian#ifndef lint
23219393Sadrianstatic char rcsid[] =
24219393Sadrian    "@(#) $Header: print-tcp.c,v 1.46 96/07/23 14:17:27 leres Exp $ (LBL)";
25219393Sadrian#endif
26219393Sadrian
27219393Sadrian#include <sys/param.h>
28219393Sadrian#include <sys/time.h>
29219393Sadrian
30219393Sadrian#include <netinet/in.h>
31219393Sadrian#include <netinet/in_systm.h>
32219393Sadrian#include <netinet/ip.h>
33219393Sadrian#include <netinet/ip_var.h>
34219393Sadrian#include <netinet/tcp.h>
35219393Sadrian#include <netinet/tcpip.h>
36219393Sadrian
37219393Sadrian#include <stdio.h>
38219393Sadrian#include <stdlib.h>
39219393Sadrian#include <string.h>
40219393Sadrian#include <unistd.h>
41219393Sadrian
42219393Sadrian#include "interface.h"
43219393Sadrian#include "addrtoname.h"
44219393Sadrian#include "extract.h"
45219393Sadrian
46219393Sadrian/* Compatibility */
47219393Sadrian#ifndef TCPOPT_WSCALE
48219393Sadrian#define	TCPOPT_WSCALE		3	/* window scale factor (rfc1072) */
49219393Sadrian#endif
50219393Sadrian#ifndef TCPOPT_SACKOK
51219393Sadrian#define	TCPOPT_SACKOK		4	/* selective ack ok (rfc1072) */
52219393Sadrian#endif
53219393Sadrian#ifndef TCPOPT_SACK
54219393Sadrian#define	TCPOPT_SACK		5	/* selective ack (rfc1072) */
55219393Sadrian#endif
56219393Sadrian#ifndef TCPOPT_ECHO
57219393Sadrian#define	TCPOPT_ECHO		6	/* echo (rfc1072) */
58219393Sadrian#endif
59219393Sadrian#ifndef TCPOPT_ECHOREPLY
60219393Sadrian#define	TCPOPT_ECHOREPLY	7	/* echo (rfc1072) */
61219393Sadrian#endif
62219393Sadrian#ifndef TCPOPT_TIMESTAMP
63219393Sadrian#define TCPOPT_TIMESTAMP	8	/* timestamps (rfc1323) */
64219393Sadrian#endif
65219393Sadrian#ifndef TCPOPT_CC
66219393Sadrian#define TCPOPT_CC		11	/* T/TCP CC options (rfc1644) */
67219393Sadrian#endif
68219393Sadrian#ifndef TCPOPT_CCNEW
69219393Sadrian#define TCPOPT_CCNEW		12	/* T/TCP CC options (rfc1644) */
70219393Sadrian#endif
71219393Sadrian#ifndef TCPOPT_CCECHO
72219393Sadrian#define TCPOPT_CCECHO		13	/* T/TCP CC options (rfc1644) */
73219393Sadrian#endif
74219393Sadrian
75219393Sadrianstruct tha {
76219393Sadrian	struct in_addr src;
77219393Sadrian	struct in_addr dst;
78219393Sadrian	u_int port;
79219393Sadrian};
80219393Sadrian
81219393Sadrianstruct tcp_seq_hash {
82219393Sadrian	struct tcp_seq_hash *nxt;
83219393Sadrian	struct tha addr;
84219393Sadrian	tcp_seq seq;
85219393Sadrian	tcp_seq ack;
86219393Sadrian};
87219393Sadrian
88219393Sadrian#define TSEQ_HASHSIZE 919
89219393Sadrian
90219393Sadrian/* These tcp optinos do not have the size octet */
91219393Sadrian#define ZEROLENOPT(o) ((o) == TCPOPT_EOL || (o) == TCPOPT_NOP)
92219393Sadrian
93219393Sadrianstatic struct tcp_seq_hash tcp_seq_hash[TSEQ_HASHSIZE];
94219393Sadrian
95219393Sadrian
96219393Sadrianvoid
97219393Sadriantcp_print(register const u_char *bp, register u_int length,
98219393Sadrian	  register const u_char *bp2)
99219393Sadrian{
100219393Sadrian	register const struct tcphdr *tp;
101219393Sadrian	register const struct ip *ip;
102219393Sadrian	register u_char flags;
103219393Sadrian	register u_int hlen;
104219393Sadrian	register char ch;
105219393Sadrian	u_short sport, dport, win, urp;
106219393Sadrian	u_int32_t seq, ack;
107219393Sadrian
108219393Sadrian	tp = (struct tcphdr *)bp;
109219393Sadrian	ip = (struct ip *)bp2;
110219393Sadrian	ch = '\0';
111219393Sadrian	TCHECK(*tp);
112219393Sadrian	if (length < sizeof(*tp)) {
113219393Sadrian		(void)printf("truncated-tcp %d", length);
114219393Sadrian		return;
115219393Sadrian	}
116219393Sadrian
117219393Sadrian	sport = ntohs(tp->th_sport);
118219393Sadrian	dport = ntohs(tp->th_dport);
119219393Sadrian	seq = ntohl(tp->th_seq);
120219393Sadrian	ack = ntohl(tp->th_ack);
121219393Sadrian	win = ntohs(tp->th_win);
122219393Sadrian	urp = ntohs(tp->th_urp);
123219393Sadrian
124219393Sadrian	(void)printf("%s.%s > %s.%s: ",
125219393Sadrian		ipaddr_string(&ip->ip_src), tcpport_string(sport),
126219393Sadrian		ipaddr_string(&ip->ip_dst), tcpport_string(dport));
127219393Sadrian
128219393Sadrian	if (qflag) {
129219393Sadrian		(void)printf("tcp %d", length - tp->th_off * 4);
130219393Sadrian		return;
131219393Sadrian	}
132219393Sadrian	if ((flags = tp->th_flags) & (TH_SYN|TH_FIN|TH_RST|TH_PUSH)) {
133219393Sadrian		if (flags & TH_SYN)
134219393Sadrian			putchar('S');
135219393Sadrian		if (flags & TH_FIN)
136219393Sadrian			putchar('F');
137219393Sadrian		if (flags & TH_RST)
138219393Sadrian			putchar('R');
139219393Sadrian		if (flags & TH_PUSH)
140219393Sadrian			putchar('P');
141219393Sadrian	} else
142219393Sadrian		putchar('.');
143219393Sadrian
144219393Sadrian	if (!Sflag && (flags & TH_ACK)) {
145219393Sadrian		register struct tcp_seq_hash *th;
146219393Sadrian		register int rev;
147219393Sadrian		struct tha tha;
148219393Sadrian		/*
149219393Sadrian		 * Find (or record) the initial sequence numbers for
150219393Sadrian		 * this conversation.  (we pick an arbitrary
151219393Sadrian		 * collating order so there's only one entry for
152219393Sadrian		 * both directions).
153219393Sadrian		 */
154219393Sadrian		if (sport < dport ||
155219393Sadrian		    (sport == dport &&
156219393Sadrian		     ip->ip_src.s_addr < ip->ip_dst.s_addr)) {
157219393Sadrian			tha.src = ip->ip_src, tha.dst = ip->ip_dst;
158219393Sadrian			tha.port = sport << 16 | dport;
159219393Sadrian			rev = 0;
160219393Sadrian		} else {
161219393Sadrian			tha.src = ip->ip_dst, tha.dst = ip->ip_src;
162219393Sadrian			tha.port = dport << 16 | sport;
163219393Sadrian			rev = 1;
164219393Sadrian		}
165219393Sadrian
166219393Sadrian		for (th = &tcp_seq_hash[tha.port % TSEQ_HASHSIZE];
167219393Sadrian		     th->nxt; th = th->nxt)
168219393Sadrian			if (!memcmp((char *)&tha, (char *)&th->addr,
169219393Sadrian				  sizeof(th->addr)))
170219393Sadrian				break;
171219393Sadrian
172219393Sadrian		if (!th->nxt || flags & TH_SYN) {
173219393Sadrian			/* didn't find it or new conversation */
174219393Sadrian			if (th->nxt == NULL) {
175219393Sadrian				th->nxt = (struct tcp_seq_hash *)
176219393Sadrian					calloc(1, sizeof(*th));
177219393Sadrian				if (th->nxt == NULL)
178219393Sadrian					error("tcp_print: calloc");
179219393Sadrian			}
180219393Sadrian			th->addr = tha;
181219393Sadrian			if (rev)
182219393Sadrian				th->ack = seq, th->seq = ack - 1;
183219393Sadrian			else
184219393Sadrian				th->seq = seq, th->ack = ack - 1;
185219393Sadrian		} else {
186219393Sadrian			if (rev)
187219393Sadrian				seq -= th->ack, ack -= th->seq;
188219393Sadrian			else
189219393Sadrian				seq -= th->seq, ack -= th->ack;
190219393Sadrian		}
191219393Sadrian	}
192219393Sadrian	hlen = tp->th_off * 4;
193219393Sadrian	length -= hlen;
194219393Sadrian	if (length > 0 || flags & (TH_SYN | TH_FIN | TH_RST))
195219393Sadrian		(void)printf(" %u:%u(%d)", seq, seq + length, length);
196219393Sadrian	if (flags & TH_ACK)
197219393Sadrian		(void)printf(" ack %u", ack);
198219393Sadrian
199219393Sadrian	(void)printf(" win %d", win);
200219393Sadrian
201219393Sadrian	if (flags & TH_URG)
202219393Sadrian		(void)printf(" urg %d", urp);
203219393Sadrian	/*
204219393Sadrian	 * Handle any options.
205219393Sadrian	 */
206219393Sadrian	if ((hlen -= sizeof(*tp)) > 0) {
207219393Sadrian		register const u_char *cp;
208219393Sadrian		register int i, opt, len, datalen;
209219393Sadrian
210219393Sadrian		cp = (const u_char *)tp + sizeof(*tp);
211219393Sadrian		putchar(' ');
212219393Sadrian		ch = '<';
213219393Sadrian		while (hlen > 0) {
214219393Sadrian			--hlen;
215219393Sadrian			putchar(ch);
216219393Sadrian			if (cp > snapend)
217219393Sadrian				goto trunc;
218219393Sadrian			opt = *cp++;
219219393Sadrian			if (ZEROLENOPT(opt))
220219393Sadrian				len = 1;
221219393Sadrian			else {
222219393Sadrian				if (cp > snapend)
223219393Sadrian					goto trunc;
224219393Sadrian				len = *cp++;
225219393Sadrian				--hlen;
226219393Sadrian			}
227219393Sadrian			datalen = 0;
228219393Sadrian			switch (opt) {
229219393Sadrian
230219393Sadrian			case TCPOPT_MAXSEG:
231219393Sadrian				(void)printf("mss");
232219393Sadrian				datalen = 2;
233219393Sadrian				if (cp + datalen > snapend)
234219393Sadrian					goto trunc;
235219393Sadrian				(void)printf(" %u", EXTRACT_16BITS(cp));
236219393Sadrian
237219393Sadrian				break;
238219393Sadrian
239219393Sadrian			case TCPOPT_EOL:
240219393Sadrian				(void)printf("eol");
241219393Sadrian				break;
242219393Sadrian
243219393Sadrian			case TCPOPT_NOP:
244219393Sadrian				(void)printf("nop");
245219393Sadrian				break;
246219393Sadrian
247219393Sadrian			case TCPOPT_WSCALE:
248219393Sadrian				(void)printf("wscale");
249219393Sadrian				datalen = 1;
250219393Sadrian				if (cp + datalen > snapend)
251219393Sadrian					goto trunc;
252219393Sadrian				(void)printf(" %u", *cp);
253219393Sadrian				break;
254219393Sadrian
255219393Sadrian			case TCPOPT_SACKOK:
256219393Sadrian				(void)printf("sackOK");
257219393Sadrian				break;
258219393Sadrian
259219393Sadrian			case TCPOPT_SACK:
260219393Sadrian				(void)printf("sack");
261219393Sadrian				datalen = len - 2;
262219393Sadrian				i = datalen;
263219393Sadrian				for (i = datalen; i > 0; i -= 4) {
264219393Sadrian					if (cp + i + 4 > snapend)
265219393Sadrian						goto trunc;
266219393Sadrian					/* block-size@relative-origin */
267219393Sadrian					(void)printf(" %u@%u",
268219393Sadrian					    EXTRACT_16BITS(cp + 2),
269219393Sadrian					    EXTRACT_16BITS(cp));
270219393Sadrian				}
271219393Sadrian				if (datalen % 4)
272219393Sadrian					(void)printf("[len %d]", len);
273219393Sadrian				break;
274219393Sadrian
275219393Sadrian			case TCPOPT_ECHO:
276219393Sadrian				(void)printf("echo");
277219393Sadrian				datalen = 4;
278219393Sadrian				if (cp + datalen > snapend)
279219393Sadrian					goto trunc;
280219393Sadrian				(void)printf(" %u", EXTRACT_32BITS(cp));
281219393Sadrian				break;
282219393Sadrian
283219393Sadrian			case TCPOPT_ECHOREPLY:
284219393Sadrian				(void)printf("echoreply");
285219393Sadrian				datalen = 4;
286219393Sadrian				if (cp + datalen > snapend)
287219393Sadrian					goto trunc;
288219393Sadrian				(void)printf(" %u", EXTRACT_32BITS(cp));
289219393Sadrian				break;
290219393Sadrian
291219393Sadrian			case TCPOPT_TIMESTAMP:
292219393Sadrian				(void)printf("timestamp");
293219393Sadrian				datalen = 4;
294219393Sadrian				if (cp + datalen > snapend)
295219393Sadrian					goto trunc;
296219393Sadrian				(void)printf(" %u", EXTRACT_32BITS(cp));
297219393Sadrian				datalen += 4;
298219393Sadrian				if (cp + datalen > snapend)
299219393Sadrian					goto trunc;
300219393Sadrian				(void)printf(" %u", EXTRACT_32BITS(cp + 4));
301219393Sadrian				break;
302219393Sadrian
303219393Sadrian			case TCPOPT_CC:
304219393Sadrian				(void)printf("cc");
305219393Sadrian				datalen = 4;
306219393Sadrian				if (cp + datalen > snapend)
307219393Sadrian					goto trunc;
308219393Sadrian				(void)printf(" %u", EXTRACT_32BITS(cp));
309219393Sadrian				break;
310219393Sadrian
311219393Sadrian			case TCPOPT_CCNEW:
312219393Sadrian				(void)printf("ccnew");
313219393Sadrian				datalen = 4;
314219393Sadrian				if (cp + datalen > snapend)
315219393Sadrian					goto trunc;
316219393Sadrian				(void)printf(" %u", EXTRACT_32BITS(cp));
317219393Sadrian				break;
318219393Sadrian
319			case TCPOPT_CCECHO:
320				(void)printf("ccecho");
321				datalen = 4;
322				if (cp + datalen > snapend)
323					goto trunc;
324				(void)printf(" %u", EXTRACT_32BITS(cp));
325				break;
326
327			default:
328				(void)printf("opt-%d:", opt);
329				datalen = len - 2;
330				if  (datalen < 0)
331					datalen = 0;
332				for (i = 0; i < datalen; ++i) {
333					if (cp + i > snapend)
334						goto trunc;
335					(void)printf("%02x", cp[i]);
336				}
337				break;
338			}
339
340			/* Account for data printed */
341			cp += datalen;
342			hlen -= datalen;
343
344			/* Check specification against observed length */
345			++datalen;			/* option octet */
346			if (!ZEROLENOPT(opt))
347				++datalen;		/* size octet */
348			if (datalen != len)
349				(void)printf("[len %d]", len);
350			ch = ',';
351		}
352		putchar('>');
353	}
354	return;
355trunc:
356	fputs("[|tcp]", stdout);
357	if (ch != '\0')
358		putchar('>');
359}
360
361