xref: /freebsd/contrib/tcpdump/print-tcp.c (revision d74e86d9e30043893d6b308468008b65640ddcae)
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
23 static 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 
78 struct tha {
79 	struct in_addr src;
80 	struct in_addr dst;
81 	u_int port;
82 };
83 
84 struct 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 
96 static struct tcp_seq_hash tcp_seq_hash[TSEQ_HASHSIZE];
97 
98 
99 void
100 tcp_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;
353 bad:
354 	fputs("[bad opt]", stdout);
355 	if (ch != '\0')
356 		putchar('>');
357 	return;
358 trunc:
359 	fputs("[|tcp]", stdout);
360 	if (ch != '\0')
361 		putchar('>');
362 }
363 
364