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