]> The Tcpdump Group git mirrors - tcpdump/blob - print-tcp.c
patches to help build on Linux 2.2
[tcpdump] / print-tcp.c
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: /tcpdump/master/tcpdump/print-tcp.c,v 1.56 1999-10-17 21:37:16 mcr Exp $ (LBL)";
25 #endif
26
27 #include <sys/param.h>
28 #include <sys/time.h>
29
30 #define __FAVOR_BSD
31
32 #include <netinet/in.h>
33 #include <netinet/in_systm.h>
34 #include <netinet/ip.h>
35 #include <netinet/tcp.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