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