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