]> The Tcpdump Group git mirrors - tcpdump/blob - print-tcp.c
(token_if_print): remove unused variable
[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.69 2000-07-29 09:06:23 guy Exp $ (LBL)";
25 #endif
26
27 #ifdef HAVE_CONFIG_H
28 #include "config.h"
29 #endif
30
31 #include <sys/param.h>
32 #include <sys/time.h>
33
34 #include <rpc/rpc.h>
35
36 #include <netinet/in.h>
37 #include <netinet/in_systm.h>
38 #include <netinet/ip.h>
39 #include <netinet/ip_var.h>
40 #include <netinet/tcp.h>
41
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <unistd.h>
46
47 #ifdef INET6
48 #include <netinet/ip6.h>
49 #endif
50
51 #include "interface.h"
52 #include "addrtoname.h"
53 #include "extract.h"
54
55 static void print_tcp_rst_data(register const u_char *sp, u_int length);
56
57 #define MAX_RST_DATA_LEN 30
58
59 /* Compatibility */
60 #ifndef TCPOPT_WSCALE
61 #define TCPOPT_WSCALE 3 /* window scale factor (rfc1072) */
62 #endif
63 #ifndef TCPOPT_SACKOK
64 #define TCPOPT_SACKOK 4 /* selective ack ok (rfc1072) */
65 #endif
66 #ifndef TCPOPT_SACK
67 #define TCPOPT_SACK 5 /* selective ack (rfc1072) */
68 #endif
69 #ifndef TCPOPT_ECHO
70 #define TCPOPT_ECHO 6 /* echo (rfc1072) */
71 #endif
72 #ifndef TCPOPT_ECHOREPLY
73 #define TCPOPT_ECHOREPLY 7 /* echo (rfc1072) */
74 #endif
75 #ifndef TCPOPT_TIMESTAMP
76 #define TCPOPT_TIMESTAMP 8 /* timestamps (rfc1323) */
77 #endif
78 #ifndef TCPOPT_CC
79 #define TCPOPT_CC 11 /* T/TCP CC options (rfc1644) */
80 #endif
81 #ifndef TCPOPT_CCNEW
82 #define TCPOPT_CCNEW 12 /* T/TCP CC options (rfc1644) */
83 #endif
84 #ifndef TCPOPT_CCECHO
85 #define TCPOPT_CCECHO 13 /* T/TCP CC options (rfc1644) */
86 #endif
87
88 /*
89 * Definitions required for ECN
90 * for use if the OS running tcpdump does not have ECN
91 */
92 #ifndef TH_ECNECHO
93 #define TH_ECNECHO 0x40 /* ECN Echo in tcp header */
94 #endif
95 #ifndef TH_CWR
96 #define TH_CWR 0x80 /* ECN Cwnd Reduced in tcp header*/
97 #endif
98
99 struct tha {
100 #ifndef INET6
101 struct in_addr src;
102 struct in_addr dst;
103 #else
104 struct in6_addr src;
105 struct in6_addr dst;
106 #endif /*INET6*/
107 u_int port;
108 };
109
110 struct tcp_seq_hash {
111 struct tcp_seq_hash *nxt;
112 struct tha addr;
113 tcp_seq seq;
114 tcp_seq ack;
115 };
116
117 #define TSEQ_HASHSIZE 919
118
119 /* These tcp optinos do not have the size octet */
120 #define ZEROLENOPT(o) ((o) == TCPOPT_EOL || (o) == TCPOPT_NOP)
121
122 static struct tcp_seq_hash tcp_seq_hash[TSEQ_HASHSIZE];
123
124
125 #ifndef TELNET_PORT
126 #define TELNET_PORT 23
127 #endif
128 #ifndef BGP_PORT
129 #define BGP_PORT 179
130 #endif
131 #define NETBIOS_SSN_PORT 139
132 #ifndef NFS_PORT
133 #define NFS_PORT 2049
134 #endif
135
136 void
137 tcp_print(register const u_char *bp, register u_int length,
138 register const u_char *bp2)
139 {
140 register const struct tcphdr *tp;
141 register const struct ip *ip;
142 register u_char flags;
143 register int hlen;
144 register char ch;
145 u_int16_t sport, dport, win, urp;
146 u_int32_t seq, ack, thseq, thack;
147 int threv;
148 #ifdef INET6
149 register const struct ip6_hdr *ip6;
150 #endif
151
152 tp = (struct tcphdr *)bp;
153 ip = (struct ip *)bp2;
154 #ifdef INET6
155 if (ip->ip_v == 6)
156 ip6 = (struct ip6_hdr *)bp2;
157 else
158 ip6 = NULL;
159 #endif /*INET6*/
160 ch = '\0';
161 if (!TTEST(tp->th_dport)) {
162 (void)printf("%s > %s: [|tcp]",
163 ipaddr_string(&ip->ip_src),
164 ipaddr_string(&ip->ip_dst));
165 return;
166 }
167
168 sport = ntohs(tp->th_sport);
169 dport = ntohs(tp->th_dport);
170
171
172 hlen = tp->th_off * 4;
173
174 /*
175 * If data present and NFS port used, assume NFS.
176 * Pass offset of data plus 4 bytes for RPC TCP msg length
177 * to NFS print routines.
178 */
179 if (!qflag) {
180 if ((u_char *)tp + 4 + sizeof(struct rpc_msg) <= snapend &&
181 dport == NFS_PORT) {
182 nfsreq_print((u_char *)tp + hlen + 4, length-hlen,
183 (u_char *)ip);
184 return;
185 } else if ((u_char *)tp + 4 + sizeof(struct rpc_msg)
186 <= snapend &&
187 sport == NFS_PORT) {
188 nfsreply_print((u_char *)tp + hlen + 4,length-hlen,
189 (u_char *)ip);
190 return;
191 }
192 }
193 #ifdef INET6
194 if (ip6) {
195 if (ip6->ip6_nxt == IPPROTO_TCP) {
196 (void)printf("%s.%s > %s.%s: ",
197 ip6addr_string(&ip6->ip6_src),
198 tcpport_string(sport),
199 ip6addr_string(&ip6->ip6_dst),
200 tcpport_string(dport));
201 } else {
202 (void)printf("%s > %s: ",
203 tcpport_string(sport), tcpport_string(dport));
204 }
205 } else
206 #endif /*INET6*/
207 {
208 if (ip->ip_p == IPPROTO_TCP) {
209 (void)printf("%s.%s > %s.%s: ",
210 ipaddr_string(&ip->ip_src),
211 tcpport_string(sport),
212 ipaddr_string(&ip->ip_dst),
213 tcpport_string(dport));
214 } else {
215 (void)printf("%s > %s: ",
216 tcpport_string(sport), tcpport_string(dport));
217 }
218 }
219
220 TCHECK(*tp);
221
222 seq = (u_int32_t)ntohl(tp->th_seq);
223 ack = (u_int32_t)ntohl(tp->th_ack);
224 win = ntohs(tp->th_win);
225 urp = ntohs(tp->th_urp);
226
227 if (qflag) {
228 (void)printf("tcp %d", length - tp->th_off * 4);
229 return;
230 }
231 if ((flags = tp->th_flags) & (TH_SYN|TH_FIN|TH_RST|TH_PUSH|
232 TH_ECNECHO|TH_CWR)) {
233 if (flags & TH_SYN)
234 putchar('S');
235 if (flags & TH_FIN)
236 putchar('F');
237 if (flags & TH_RST)
238 putchar('R');
239 if (flags & TH_PUSH)
240 putchar('P');
241 if (flags & TH_CWR)
242 putchar('W'); /* congestion _W_indow reduced (ECN) */
243 if (flags & TH_ECNECHO)
244 putchar('E'); /* ecn _E_cho sent (ECN) */
245 } else
246 putchar('.');
247
248 if (!Sflag && (flags & TH_ACK)) {
249 register struct tcp_seq_hash *th;
250 register int rev;
251 struct tha tha;
252 /*
253 * Find (or record) the initial sequence numbers for
254 * this conversation. (we pick an arbitrary
255 * collating order so there's only one entry for
256 * both directions).
257 */
258 #ifdef INET6
259 memset(&tha, 0, sizeof(tha));
260 rev = 0;
261 if (ip6) {
262 if (sport > dport) {
263 rev = 1;
264 } else if (sport == dport) {
265 int i;
266
267 for (i = 0; i < 4; i++) {
268 if (((u_int32_t *)(&ip6->ip6_src))[i] >
269 ((u_int32_t *)(&ip6->ip6_dst))[i]) {
270 rev = 1;
271 break;
272 }
273 }
274 }
275 if (rev) {
276 tha.src = ip6->ip6_dst;
277 tha.dst = ip6->ip6_src;
278 tha.port = dport << 16 | sport;
279 } else {
280 tha.dst = ip6->ip6_dst;
281 tha.src = ip6->ip6_src;
282 tha.port = sport << 16 | dport;
283 }
284 } else {
285 if (sport > dport ||
286 (sport == dport &&
287 ip->ip_src.s_addr > ip->ip_dst.s_addr)) {
288 rev = 1;
289 }
290 if (rev) {
291 *(struct in_addr *)&tha.src = ip->ip_dst;
292 *(struct in_addr *)&tha.dst = ip->ip_src;
293 tha.port = dport << 16 | sport;
294 } else {
295 *(struct in_addr *)&tha.dst = ip->ip_dst;
296 *(struct in_addr *)&tha.src = ip->ip_src;
297 tha.port = sport << 16 | dport;
298 }
299 }
300 #else
301 if (sport < dport ||
302 (sport == dport &&
303 ip->ip_src.s_addr < ip->ip_dst.s_addr)) {
304 tha.src = ip->ip_src, tha.dst = ip->ip_dst;
305 tha.port = sport << 16 | dport;
306 rev = 0;
307 } else {
308 tha.src = ip->ip_dst, tha.dst = ip->ip_src;
309 tha.port = dport << 16 | sport;
310 rev = 1;
311 }
312 #endif
313
314 threv = rev;
315 for (th = &tcp_seq_hash[tha.port % TSEQ_HASHSIZE];
316 th->nxt; th = th->nxt)
317 if (!memcmp((char *)&tha, (char *)&th->addr,
318 sizeof(th->addr)))
319 break;
320
321 if (!th->nxt || (flags & TH_SYN)) {
322 /* didn't find it or new conversation */
323 if (th->nxt == NULL) {
324 th->nxt = (struct tcp_seq_hash *)
325 calloc(1, sizeof(*th));
326 if (th->nxt == NULL)
327 error("tcp_print: calloc");
328 }
329 th->addr = tha;
330 if (rev)
331 th->ack = seq, th->seq = ack - 1;
332 else
333 th->seq = seq, th->ack = ack - 1;
334
335 } else {
336 if (rev)
337 seq -= th->ack, ack -= th->seq;
338 else
339 seq -= th->seq, ack -= th->ack;
340 }
341
342 thseq = th->seq;
343 thack = th->ack;
344 } else {
345 /*fool gcc*/
346 thseq = thack = threv = 0;
347 }
348 if (hlen > length) {
349 (void)printf(" [bad hdr length]");
350 return;
351 }
352 length -= hlen;
353 if (vflag > 1 || length > 0 || flags & (TH_SYN | TH_FIN | TH_RST))
354 (void)printf(" %u:%u(%d)", seq, seq + length, length);
355 if (flags & TH_ACK)
356 (void)printf(" ack %u", ack);
357
358 (void)printf(" win %d", win);
359
360 if (flags & TH_URG)
361 (void)printf(" urg %d", urp);
362 /*
363 * Handle any options.
364 */
365 if ((hlen -= sizeof(*tp)) > 0) {
366 register const u_char *cp;
367 register int i, opt, len, datalen;
368
369 cp = (const u_char *)tp + sizeof(*tp);
370 putchar(' ');
371 ch = '<';
372 while (hlen > 0) {
373 putchar(ch);
374 TCHECK(*cp);
375 opt = *cp++;
376 if (ZEROLENOPT(opt))
377 len = 1;
378 else {
379 TCHECK(*cp);
380 len = *cp++; /* total including type, len */
381 if (len < 2 || len > hlen)
382 goto bad;
383 --hlen; /* account for length byte */
384 }
385 --hlen; /* account for type byte */
386 datalen = 0;
387
388 /* Bail if "l" bytes of data are not left or were not captured */
389 #define LENCHECK(l) { if ((l) > hlen) goto bad; TCHECK2(*cp, l); }
390
391 switch (opt) {
392
393 case TCPOPT_MAXSEG:
394 (void)printf("mss");
395 datalen = 2;
396 LENCHECK(datalen);
397 (void)printf(" %u", EXTRACT_16BITS(cp));
398
399 break;
400
401 case TCPOPT_EOL:
402 (void)printf("eol");
403 break;
404
405 case TCPOPT_NOP:
406 (void)printf("nop");
407 break;
408
409 case TCPOPT_WSCALE:
410 (void)printf("wscale");
411 datalen = 1;
412 LENCHECK(datalen);
413 (void)printf(" %u", *cp);
414 break;
415
416 case TCPOPT_SACKOK:
417 (void)printf("sackOK");
418 break;
419
420 case TCPOPT_SACK:
421 (void)printf("sack");
422 datalen = len - 2;
423 if (datalen % 8 != 0) {
424 (void)printf(" malformed sack ");
425 } else {
426 u_int32_t s, e;
427
428 (void)printf(" sack %d ", datalen / 8);
429 for (i = 0; i < datalen; i += 8) {
430 LENCHECK(i + 4);
431 s = EXTRACT_32BITS(cp + i);
432 LENCHECK(i + 8);
433 e = EXTRACT_32BITS(cp + i + 4);
434 if (threv) {
435 s -= thseq;
436 e -= thseq;
437 } else {
438 s -= thack;
439 e -= thack;
440 }
441 (void)printf("{%u:%u}", s, e);
442 }
443 (void)printf(" ");
444 }
445 break;
446
447 case TCPOPT_ECHO:
448 (void)printf("echo");
449 datalen = 4;
450 LENCHECK(datalen);
451 (void)printf(" %u", EXTRACT_32BITS(cp));
452 break;
453
454 case TCPOPT_ECHOREPLY:
455 (void)printf("echoreply");
456 datalen = 4;
457 LENCHECK(datalen);
458 (void)printf(" %u", EXTRACT_32BITS(cp));
459 break;
460
461 case TCPOPT_TIMESTAMP:
462 (void)printf("timestamp");
463 datalen = 8;
464 LENCHECK(4);
465 (void)printf(" %u", EXTRACT_32BITS(cp));
466 LENCHECK(datalen);
467 (void)printf(" %u", EXTRACT_32BITS(cp + 4));
468 break;
469
470 case TCPOPT_CC:
471 (void)printf("cc");
472 datalen = 4;
473 LENCHECK(datalen);
474 (void)printf(" %u", EXTRACT_32BITS(cp));
475 break;
476
477 case TCPOPT_CCNEW:
478 (void)printf("ccnew");
479 datalen = 4;
480 LENCHECK(datalen);
481 (void)printf(" %u", EXTRACT_32BITS(cp));
482 break;
483
484 case TCPOPT_CCECHO:
485 (void)printf("ccecho");
486 datalen = 4;
487 LENCHECK(datalen);
488 (void)printf(" %u", EXTRACT_32BITS(cp));
489 break;
490
491 default:
492 (void)printf("opt-%d:", opt);
493 datalen = len - 2;
494 for (i = 0; i < datalen; ++i) {
495 LENCHECK(i);
496 (void)printf("%02x", cp[i]);
497 }
498 break;
499 }
500
501 /* Account for data printed */
502 cp += datalen;
503 hlen -= datalen;
504
505 /* Check specification against observed length */
506 ++datalen; /* option octet */
507 if (!ZEROLENOPT(opt))
508 ++datalen; /* size octet */
509 if (datalen != len)
510 (void)printf("[len %d]", len);
511 ch = ',';
512 if (opt == TCPOPT_EOL)
513 break;
514 }
515 putchar('>');
516 }
517
518 if (length <= 0)
519 return;
520
521 /*
522 * Decode payload if necessary.
523 */
524 bp += (tp->th_off * 4);
525 if (flags & TH_RST) {
526 if (vflag)
527 print_tcp_rst_data(bp, length);
528 } else {
529 if (sport == TELNET_PORT || dport == TELNET_PORT) {
530 if (!qflag && vflag)
531 telnet_print(bp, length);
532 } else if (sport == BGP_PORT || dport == BGP_PORT)
533 bgp_print(bp, length);
534 else if (sport == NETBIOS_SSN_PORT || dport == NETBIOS_SSN_PORT)
535 nbt_tcp_print(bp, length);
536 }
537 return;
538 bad:
539 fputs("[bad opt]", stdout);
540 if (ch != '\0')
541 putchar('>');
542 return;
543 trunc:
544 fputs("[|tcp]", stdout);
545 if (ch != '\0')
546 putchar('>');
547 }
548
549 /*
550 * RFC1122 says the following on data in RST segments:
551 *
552 * 4.2.2.12 RST Segment: RFC-793 Section 3.4
553 *
554 * A TCP SHOULD allow a received RST segment to include data.
555 *
556 * DISCUSSION
557 * It has been suggested that a RST segment could contain
558 * ASCII text that encoded and explained the cause of the
559 * RST. No standard has yet been established for such
560 * data.
561 *
562 */
563
564 static void
565 print_tcp_rst_data(register const u_char *sp, u_int length)
566 {
567 int c;
568
569 if (TTEST2(*sp, length))
570 printf(" [RST");
571 else
572 printf(" [!RST");
573 if (length > MAX_RST_DATA_LEN) {
574 length = MAX_RST_DATA_LEN; /* can use -X for longer */
575 putchar('+'); /* indicate we truncate */
576 }
577 putchar(' ');
578 while (length-- && sp <= snapend) {
579 c = *sp++;
580 if (isprint(c))
581 putchar(c);
582 else
583 putchar('.');
584 }
585 putchar(']');
586 }