]> The Tcpdump Group git mirrors - tcpdump/blob - print-tcp.c
handle ECHO and re-do SACK. From [email protected]
[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.58 1999-11-21 03:50:02 assar 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
36 #ifdef HAVE_MEMORY_H
37 #include <memory.h>
38 #endif
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <unistd.h>
43
44 #ifdef INET6
45 #include <netinet/ip6.h>
46 #endif
47
48 #include "interface.h"
49 #include "addrtoname.h"
50 #include "extract.h"
51
52 /* Compatibility */
53 #ifndef TCPOPT_WSCALE
54 #define TCPOPT_WSCALE 3 /* window scale factor (rfc1072) */
55 #endif
56 #ifndef TCPOPT_SACKOK
57 #define TCPOPT_SACKOK 4 /* selective ack ok (rfc1072) */
58 #endif
59 #ifndef TCPOPT_SACK
60 #define TCPOPT_SACK 5 /* selective ack (rfc1072) */
61 #endif
62 #ifndef TCPOPT_ECHO
63 #define TCPOPT_ECHO 6 /* echo (rfc1072) */
64 #endif
65 #ifndef TCPOPT_ECHOREPLY
66 #define TCPOPT_ECHOREPLY 7 /* echo (rfc1072) */
67 #endif
68 #ifndef TCPOPT_TIMESTAMP
69 #define TCPOPT_TIMESTAMP 8 /* timestamps (rfc1323) */
70 #endif
71 #ifndef TCPOPT_CC
72 #define TCPOPT_CC 11 /* T/TCP CC options (rfc1644) */
73 #endif
74 #ifndef TCPOPT_CCNEW
75 #define TCPOPT_CCNEW 12 /* T/TCP CC options (rfc1644) */
76 #endif
77 #ifndef TCPOPT_CCECHO
78 #define TCPOPT_CCECHO 13 /* T/TCP CC options (rfc1644) */
79 #endif
80
81 struct tha {
82 #ifndef INET6
83 struct in_addr src;
84 struct in_addr dst;
85 #else
86 struct in6_addr src;
87 struct in6_addr dst;
88 #endif /*INET6*/
89 u_int port;
90 };
91
92 struct tcp_seq_hash {
93 struct tcp_seq_hash *nxt;
94 struct tha addr;
95 tcp_seq seq;
96 tcp_seq ack;
97 };
98
99 #define TSEQ_HASHSIZE 919
100
101 /* These tcp optinos do not have the size octet */
102 #define ZEROLENOPT(o) ((o) == TCPOPT_EOL || (o) == TCPOPT_NOP)
103
104 static struct tcp_seq_hash tcp_seq_hash[TSEQ_HASHSIZE];
105
106
107 void
108 tcp_print(register const u_char *bp, register u_int length,
109 register const u_char *bp2)
110 {
111 register const struct tcphdr *tp;
112 register const struct ip *ip;
113 register u_char flags;
114 register int hlen;
115 register char ch;
116 u_short sport, dport, win, urp;
117 u_int32_t seq, ack, thseq, thack;
118 int threv;
119 #ifdef INET6
120 register const struct ip6_hdr *ip6;
121 #endif
122
123 tp = (struct tcphdr *)bp;
124 ip = (struct ip *)bp2;
125 #ifdef INET6
126 if (ip->ip_v == 6)
127 ip6 = (struct ip6_hdr *)bp2;
128 else
129 ip6 = NULL;
130 #endif /*INET6*/
131 ch = '\0';
132 TCHECK(*tp);
133 if (length < sizeof(*tp)) {
134 (void)printf("truncated-tcp %d", length);
135 return;
136 }
137
138 sport = ntohs(tp->th_sport);
139 dport = ntohs(tp->th_dport);
140 seq = ntohl(tp->th_seq);
141 ack = ntohl(tp->th_ack);
142 win = ntohs(tp->th_win);
143 urp = ntohs(tp->th_urp);
144
145 #ifdef INET6
146 if (ip6) {
147 if (ip6->ip6_nxt == IPPROTO_TCP) {
148 (void)printf("%s.%s > %s.%s: ",
149 ip6addr_string(&ip6->ip6_src),
150 tcpport_string(sport),
151 ip6addr_string(&ip6->ip6_dst),
152 tcpport_string(dport));
153 } else {
154 (void)printf("%s > %s: ",
155 tcpport_string(sport), tcpport_string(dport));
156 }
157 } else
158 #endif /*INET6*/
159 {
160 if (ip->ip_p == IPPROTO_TCP) {
161 (void)printf("%s.%s > %s.%s: ",
162 ipaddr_string(&ip->ip_src),
163 tcpport_string(sport),
164 ipaddr_string(&ip->ip_dst),
165 tcpport_string(dport));
166 } else {
167 (void)printf("%s > %s: ",
168 tcpport_string(sport), tcpport_string(dport));
169 }
170 }
171
172 if (qflag) {
173 (void)printf("tcp %d", length - tp->th_off * 4);
174 return;
175 }
176 #ifdef TH_ECN
177 if ((flags = tp->th_flags) & (TH_SYN|TH_FIN|TH_RST|TH_PUSH|TH_ECN)) {
178 #else
179 if ((flags = tp->th_flags) & (TH_SYN|TH_FIN|TH_RST|TH_PUSH)) {
180 #endif
181 if (flags & TH_SYN)
182 putchar('S');
183 if (flags & TH_FIN)
184 putchar('F');
185 if (flags & TH_RST)
186 putchar('R');
187 if (flags & TH_PUSH)
188 putchar('P');
189 #ifdef TH_ECN
190 if (flags & TH_ECN)
191 putchar('C');
192 #endif
193 } else
194 putchar('.');
195
196 if (flags&0xc0) {
197 printf(" [");
198 if (flags&0x40)
199 printf("ECN-Echo");
200 if (flags&0x80)
201 printf("%sCWR", (flags&0x40) ? "," : "");
202 printf("]");
203 }
204
205 if (!Sflag && (flags & TH_ACK)) {
206 register struct tcp_seq_hash *th;
207 register int rev;
208 struct tha tha;
209 /*
210 * Find (or record) the initial sequence numbers for
211 * this conversation. (we pick an arbitrary
212 * collating order so there's only one entry for
213 * both directions).
214 */
215 #ifdef INET6
216 bzero(&tha, sizeof(tha));
217 rev = 0;
218 if (ip6) {
219 if (sport > dport) {
220 rev = 1;
221 } else if (sport == dport) {
222 int i;
223
224 for (i = 0; i < 4; i++) {
225 if (((u_int32_t *)(&ip6->ip6_src))[i] >
226 ((u_int32_t *)(&ip6->ip6_dst))[i]) {
227 rev = 1;
228 break;
229 }
230 }
231 }
232 if (rev) {
233 tha.src = ip6->ip6_dst;
234 tha.dst = ip6->ip6_src;
235 tha.port = dport << 16 | sport;
236 } else {
237 tha.dst = ip6->ip6_dst;
238 tha.src = ip6->ip6_src;
239 tha.port = sport << 16 | dport;
240 }
241 } else {
242 if (sport > dport ||
243 (sport == dport &&
244 ip->ip_src.s_addr > ip->ip_dst.s_addr)) {
245 rev = 1;
246 }
247 if (rev) {
248 *(struct in_addr *)&tha.src = ip->ip_dst;
249 *(struct in_addr *)&tha.dst = ip->ip_src;
250 tha.port = dport << 16 | sport;
251 } else {
252 *(struct in_addr *)&tha.dst = ip->ip_dst;
253 *(struct in_addr *)&tha.src = ip->ip_src;
254 tha.port = sport << 16 | dport;
255 }
256 }
257 #else
258 if (sport < dport ||
259 (sport == dport &&
260 ip->ip_src.s_addr < ip->ip_dst.s_addr)) {
261 tha.src = ip->ip_src, tha.dst = ip->ip_dst;
262 tha.port = sport << 16 | dport;
263 rev = 0;
264 } else {
265 tha.src = ip->ip_dst, tha.dst = ip->ip_src;
266 tha.port = dport << 16 | sport;
267 rev = 1;
268 }
269 #endif
270
271 threv = rev;
272 for (th = &tcp_seq_hash[tha.port % TSEQ_HASHSIZE];
273 th->nxt; th = th->nxt)
274 if (!memcmp((char *)&tha, (char *)&th->addr,
275 sizeof(th->addr)))
276 break;
277
278 if (!th->nxt || flags & TH_SYN) {
279 /* didn't find it or new conversation */
280 if (th->nxt == NULL) {
281 th->nxt = (struct tcp_seq_hash *)
282 calloc(1, sizeof(*th));
283 if (th->nxt == NULL)
284 error("tcp_print: calloc");
285 }
286 th->addr = tha;
287 if (rev)
288 th->ack = seq, th->seq = ack - 1;
289 else
290 th->seq = seq, th->ack = ack - 1;
291 } else {
292
293 thseq = th->seq;
294 thack = th->ack;
295
296 if (rev)
297 seq -= th->ack, ack -= th->seq;
298 else
299 seq -= th->seq, ack -= th->ack;
300 }
301 }
302 hlen = tp->th_off * 4;
303 if (hlen > length) {
304 (void)printf(" [bad hdr length]");
305 return;
306 }
307 length -= hlen;
308 if (length > 0 || flags & (TH_SYN | TH_FIN | TH_RST))
309 (void)printf(" %u:%u(%d)", seq, seq + length, length);
310 if (flags & TH_ACK)
311 (void)printf(" ack %u", ack);
312
313 (void)printf(" win %d", win);
314
315 if (flags & TH_URG)
316 (void)printf(" urg %d", urp);
317 /*
318 * Handle any options.
319 */
320 if ((hlen -= sizeof(*tp)) > 0) {
321 register const u_char *cp;
322 register int i, opt, len, datalen;
323
324 cp = (const u_char *)tp + sizeof(*tp);
325 putchar(' ');
326 ch = '<';
327 while (hlen > 0) {
328 putchar(ch);
329 TCHECK(*cp);
330 opt = *cp++;
331 if (ZEROLENOPT(opt))
332 len = 1;
333 else {
334 TCHECK(*cp);
335 len = *cp++; /* total including type, len */
336 if (len < 2 || len > hlen)
337 goto bad;
338 --hlen; /* account for length byte */
339 }
340 --hlen; /* account for type byte */
341 datalen = 0;
342
343 /* Bail if "l" bytes of data are not left or were not captured */
344 #define LENCHECK(l) { if ((l) > hlen) goto bad; TCHECK2(*cp, l); }
345
346 switch (opt) {
347
348 case TCPOPT_MAXSEG:
349 (void)printf("mss");
350 datalen = 2;
351 LENCHECK(datalen);
352 (void)printf(" %u", EXTRACT_16BITS(cp));
353
354 break;
355
356 case TCPOPT_EOL:
357 (void)printf("eol");
358 break;
359
360 case TCPOPT_NOP:
361 (void)printf("nop");
362 break;
363
364 case TCPOPT_WSCALE:
365 (void)printf("wscale");
366 datalen = 1;
367 LENCHECK(datalen);
368 (void)printf(" %u", *cp);
369 break;
370
371 case TCPOPT_SACKOK:
372 (void)printf("sackOK");
373 break;
374
375 case TCPOPT_SACK:
376 (void)printf("sack");
377 datalen = len - 2;
378 if (datalen % 8 != 0) {
379 (void)printf(" malformed sack ");
380 } else {
381 u_int32_t s, e;
382
383 (void)printf(" sack %d ", datalen / 8);
384 for (i = 0; i < datalen; i += 8) {
385 LENCHECK(i + 4);
386 s = EXTRACT_32BITS(cp + i);
387 LENCHECK(i + 8);
388 e = EXTRACT_32BITS(cp + i + 4);
389 if (threv) {
390 s -= thseq;
391 e -= thseq;
392 } else {
393 s -= thack;
394 e -= thack;
395 }
396 (void)printf("{%u:%u}", s, e);
397 }
398 (void)printf(" ");
399 }
400 break;
401
402 case TCPOPT_ECHO:
403 (void)printf("echo");
404 datalen = 4;
405 LENCHECK(datalen);
406 (void)printf(" %u", EXTRACT_32BITS(cp));
407 break;
408
409 case TCPOPT_ECHOREPLY:
410 (void)printf("echoreply");
411 datalen = 4;
412 LENCHECK(datalen);
413 (void)printf(" %u", EXTRACT_32BITS(cp));
414 break;
415
416 case TCPOPT_TIMESTAMP:
417 (void)printf("timestamp");
418 datalen = 8;
419 LENCHECK(4);
420 (void)printf(" %u", EXTRACT_32BITS(cp));
421 LENCHECK(datalen);
422 (void)printf(" %u", EXTRACT_32BITS(cp + 4));
423 break;
424
425 case TCPOPT_CC:
426 (void)printf("cc");
427 datalen = 4;
428 LENCHECK(datalen);
429 (void)printf(" %u", EXTRACT_32BITS(cp));
430 break;
431
432 case TCPOPT_CCNEW:
433 (void)printf("ccnew");
434 datalen = 4;
435 LENCHECK(datalen);
436 (void)printf(" %u", EXTRACT_32BITS(cp));
437 break;
438
439 case TCPOPT_CCECHO:
440 (void)printf("ccecho");
441 datalen = 4;
442 LENCHECK(datalen);
443 (void)printf(" %u", EXTRACT_32BITS(cp));
444 break;
445
446 default:
447 (void)printf("opt-%d:", opt);
448 datalen = len - 2;
449 for (i = 0; i < datalen; ++i) {
450 LENCHECK(i);
451 (void)printf("%02x", cp[i]);
452 }
453 break;
454 }
455
456 /* Account for data printed */
457 cp += datalen;
458 hlen -= datalen;
459
460 /* Check specification against observed length */
461 ++datalen; /* option octet */
462 if (!ZEROLENOPT(opt))
463 ++datalen; /* size octet */
464 if (datalen != len)
465 (void)printf("[len %d]", len);
466 ch = ',';
467 if (opt == TCPOPT_EOL)
468 break;
469 }
470 putchar('>');
471 }
472
473 if (length <= 0)
474 return;
475
476 /*
477 * Decode payload if necessary.
478 */
479 bp += (tp->th_off * 4);
480 if (sport == 179 || dport == 179)
481 bgp_print(bp, length);
482 return;
483 bad:
484 fputs("[bad opt]", stdout);
485 if (ch != '\0')
486 putchar('>');
487 return;
488 trunc:
489 fputs("[|tcp]", stdout);
490 if (ch != '\0')
491 putchar('>');
492 }
493