]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/tcpdump/print-tcp.c
This commit was generated by cvs2svn to compensate for changes in r97049,
[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.81 2000/12/23 20:55:22 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
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <ctype.h>
42 #include <unistd.h>
43
44 #include "interface.h"
45 #include "addrtoname.h"
46 #include "extract.h"
47
48 #include "tcp.h"
49
50 #include "ip.h"
51 #ifdef INET6
52 #include "ip6.h"
53 #endif
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 #define BXXP_PORT        10288
133 #ifndef NFS_PORT
134 #define NFS_PORT        2049
135 #endif
136
137 static int tcp_cksum(register const struct ip *ip,
138                      register const struct tcphdr *tp,
139                      register int len)
140 {
141         int i, tlen;
142         union phu {
143                 struct phdr {
144                         u_int32_t src;
145                         u_int32_t dst;
146                         u_char mbz;
147                         u_char proto;
148                         u_int16_t len;
149                 } ph;
150                 u_int16_t pa[6];
151         } phu;
152         register const u_int16_t *sp;
153         u_int32_t sum;
154         tlen = ntohs(ip->ip_len) - ((const char *)tp-(const char*)ip);
155
156         /* pseudo-header.. */
157         phu.ph.len = htons(tlen);
158         phu.ph.mbz = 0;
159         phu.ph.proto = IPPROTO_TCP;
160         memcpy(&phu.ph.src, &ip->ip_src.s_addr, sizeof(u_int32_t));
161         memcpy(&phu.ph.dst, &ip->ip_dst.s_addr, sizeof(u_int32_t));
162
163         sp = &phu.pa[0];
164         sum = sp[0]+sp[1]+sp[2]+sp[3]+sp[4]+sp[5];
165
166         sp = (const u_int16_t *)tp;
167
168         for (i=0; i<(tlen&~1); i+= 2)
169                 sum += *sp++;
170
171         if (tlen & 1) {
172                 sum += htons( (*(const u_int8_t *)sp) << 8);
173         }
174
175         while (sum > 0xffff)
176                 sum = (sum & 0xffff) + (sum >> 16);
177         sum = ~sum & 0xffff;
178
179         return (sum);
180 }
181
182 #ifdef INET6
183 static int tcp6_cksum(const struct ip6_hdr *ip6, const struct tcphdr *tp,
184         int len)
185 {
186         int i, tlen;
187         register const u_int16_t *sp;
188         u_int32_t sum;
189         union {
190                 struct {
191                         struct in6_addr ph_src;
192                         struct in6_addr ph_dst;
193                         u_int32_t       ph_len;
194                         u_int8_t        ph_zero[3];
195                         u_int8_t        ph_nxt;
196                 } ph;
197                 u_int16_t pa[20];
198         } phu;
199
200         tlen = ntohs(ip6->ip6_plen) + sizeof(struct ip6_hdr) -
201             ((const char *)tp - (const char*)ip6);
202
203         /* pseudo-header */
204         memset(&phu, 0, sizeof(phu));
205         phu.ph.ph_src = ip6->ip6_src;
206         phu.ph.ph_dst = ip6->ip6_dst;
207         phu.ph.ph_len = htonl(tlen);
208         phu.ph.ph_nxt = IPPROTO_TCP;
209
210         sum = 0;
211         for (i = 0; i < sizeof(phu.pa) / sizeof(phu.pa[0]); i++)
212                 sum += phu.pa[i];
213
214         sp = (const u_int16_t *)tp;
215
216         for (i = 0; i < (tlen & ~1); i += 2)
217                 sum += *sp++;
218
219         if (tlen & 1)
220                 sum += htons((*(const u_int8_t *)sp) << 8);
221
222         while (sum > 0xffff)
223                 sum = (sum & 0xffff) + (sum >> 16);
224         sum = ~sum & 0xffff;
225
226         return (sum);
227 }
228 #endif
229
230 void
231 tcp_print(register const u_char *bp, register u_int length,
232           register const u_char *bp2, int fragmented)
233 {
234         register const struct tcphdr *tp;
235         register const struct ip *ip;
236         register u_char flags;
237         register int hlen;
238         register char ch;
239         u_int16_t sport, dport, win, urp;
240         u_int32_t seq, ack, thseq, thack;
241         int threv;
242 #ifdef INET6
243         register const struct ip6_hdr *ip6;
244 #endif
245
246         tp = (struct tcphdr *)bp;
247         ip = (struct ip *)bp2;
248 #ifdef INET6
249         if (IP_V(ip) == 6)
250                 ip6 = (struct ip6_hdr *)bp2;
251         else
252                 ip6 = NULL;
253 #endif /*INET6*/
254         ch = '\0';
255         if (!TTEST(tp->th_dport)) {
256                 (void)printf("%s > %s: [|tcp]",
257                         ipaddr_string(&ip->ip_src),
258                         ipaddr_string(&ip->ip_dst));
259                 return;
260         }
261
262         sport = ntohs(tp->th_sport);
263         dport = ntohs(tp->th_dport);
264
265
266         hlen = TH_OFF(tp) * 4;
267
268         /*
269          * If data present and NFS port used, assume NFS.
270          * Pass offset of data plus 4 bytes for RPC TCP msg length
271          * to NFS print routines.
272          */
273         if (!qflag) {
274                 if ((u_char *)tp + 4 + sizeof(struct rpc_msg) <= snapend &&
275                     dport == NFS_PORT) {
276                         nfsreq_print((u_char *)tp + hlen + 4, length-hlen,
277                                      (u_char *)ip);
278                         return;
279                 } else if ((u_char *)tp + 4 + sizeof(struct rpc_msg)
280                            <= snapend &&
281                            sport == NFS_PORT) {
282                         nfsreply_print((u_char *)tp + hlen + 4,length-hlen,
283                                        (u_char *)ip);
284                         return;
285                 }
286         }
287 #ifdef INET6
288         if (ip6) {
289                 if (ip6->ip6_nxt == IPPROTO_TCP) {
290                         (void)printf("%s.%s > %s.%s: ",
291                                 ip6addr_string(&ip6->ip6_src),
292                                 tcpport_string(sport),
293                                 ip6addr_string(&ip6->ip6_dst),
294                                 tcpport_string(dport));
295                 } else {
296                         (void)printf("%s > %s: ",
297                                 tcpport_string(sport), tcpport_string(dport));
298                 }
299         } else
300 #endif /*INET6*/
301         {
302                 if (ip->ip_p == IPPROTO_TCP) {
303                         (void)printf("%s.%s > %s.%s: ",
304                                 ipaddr_string(&ip->ip_src),
305                                 tcpport_string(sport),
306                                 ipaddr_string(&ip->ip_dst),
307                                 tcpport_string(dport));
308                 } else {
309                         (void)printf("%s > %s: ",
310                                 tcpport_string(sport), tcpport_string(dport));
311                 }
312         }
313
314         TCHECK(*tp);
315
316         seq = (u_int32_t)ntohl(tp->th_seq);
317         ack = (u_int32_t)ntohl(tp->th_ack);
318         win = ntohs(tp->th_win);
319         urp = ntohs(tp->th_urp);
320
321         if (qflag) {
322                 (void)printf("tcp %d", length - TH_OFF(tp) * 4);
323                 return;
324         }
325         if ((flags = tp->th_flags) & (TH_SYN|TH_FIN|TH_RST|TH_PUSH|
326                                       TH_ECNECHO|TH_CWR)) {
327                 if (flags & TH_SYN)
328                         putchar('S');
329                 if (flags & TH_FIN)
330                         putchar('F');
331                 if (flags & TH_RST)
332                         putchar('R');
333                 if (flags & TH_PUSH)
334                         putchar('P');
335                 if (flags & TH_CWR)
336                         putchar('W');   /* congestion _W_indow reduced (ECN) */
337                 if (flags & TH_ECNECHO)
338                         putchar('E');   /* ecn _E_cho sent (ECN) */
339         } else
340                 putchar('.');
341
342         if (!Sflag && (flags & TH_ACK)) {
343                 register struct tcp_seq_hash *th;
344                 register int rev;
345                 struct tha tha;
346                 /*
347                  * Find (or record) the initial sequence numbers for
348                  * this conversation.  (we pick an arbitrary
349                  * collating order so there's only one entry for
350                  * both directions).
351                  */
352 #ifdef INET6
353                 memset(&tha, 0, sizeof(tha));
354                 rev = 0;
355                 if (ip6) {
356                         if (sport > dport) {
357                                 rev = 1;
358                         } else if (sport == dport) {
359                             int i;
360
361                             for (i = 0; i < 4; i++) {
362                                 if (((u_int32_t *)(&ip6->ip6_src))[i] >
363                                     ((u_int32_t *)(&ip6->ip6_dst))[i]) {
364                                         rev = 1;
365                                         break;
366                                 }
367                             }
368                         }
369                         if (rev) {
370                                 tha.src = ip6->ip6_dst;
371                                 tha.dst = ip6->ip6_src;
372                                 tha.port = dport << 16 | sport;
373                         } else {
374                                 tha.dst = ip6->ip6_dst;
375                                 tha.src = ip6->ip6_src;
376                                 tha.port = sport << 16 | dport;
377                         }
378                 } else {
379                         if (sport > dport ||
380                             (sport == dport &&
381                              ip->ip_src.s_addr > ip->ip_dst.s_addr)) {
382                                 rev = 1;
383                         }
384                         if (rev) {
385                                 *(struct in_addr *)&tha.src = ip->ip_dst;
386                                 *(struct in_addr *)&tha.dst = ip->ip_src;
387                                 tha.port = dport << 16 | sport;
388                         } else {
389                                 *(struct in_addr *)&tha.dst = ip->ip_dst;
390                                 *(struct in_addr *)&tha.src = ip->ip_src;
391                                 tha.port = sport << 16 | dport;
392                         }
393                 }
394 #else
395                 if (sport < dport ||
396                     (sport == dport &&
397                      ip->ip_src.s_addr < ip->ip_dst.s_addr)) {
398                         tha.src = ip->ip_src, tha.dst = ip->ip_dst;
399                         tha.port = sport << 16 | dport;
400                         rev = 0;
401                 } else {
402                         tha.src = ip->ip_dst, tha.dst = ip->ip_src;
403                         tha.port = dport << 16 | sport;
404                         rev = 1;
405                 }
406 #endif
407
408                 threv = rev;
409                 for (th = &tcp_seq_hash[tha.port % TSEQ_HASHSIZE];
410                      th->nxt; th = th->nxt)
411                         if (!memcmp((char *)&tha, (char *)&th->addr,
412                                   sizeof(th->addr)))
413                                 break;
414
415                 if (!th->nxt || (flags & TH_SYN)) {
416                         /* didn't find it or new conversation */
417                         if (th->nxt == NULL) {
418                                 th->nxt = (struct tcp_seq_hash *)
419                                         calloc(1, sizeof(*th));
420                                 if (th->nxt == NULL)
421                                         error("tcp_print: calloc");
422                         }
423                         th->addr = tha;
424                         if (rev)
425                                 th->ack = seq, th->seq = ack - 1;
426                         else
427                                 th->seq = seq, th->ack = ack - 1;
428
429                 } else {
430                         if (rev)
431                                 seq -= th->ack, ack -= th->seq;
432                         else
433                                 seq -= th->seq, ack -= th->ack;
434                 }
435
436                 thseq = th->seq;
437                 thack = th->ack;
438         } else {
439                 /*fool gcc*/
440                 thseq = thack = threv = 0;
441         }
442         if (hlen > length) {
443                 (void)printf(" [bad hdr length]");
444                 return;
445         }
446
447         if (IP_V(ip) == 4 && vflag && !fragmented) {
448                 int sum;
449                 if (TTEST2(tp->th_sport, length)) {
450                         sum = tcp_cksum(ip, tp, length);
451                         if (sum != 0)
452                                 (void)printf(" [bad tcp cksum %x!]", sum);
453                         else
454                                 (void)printf(" [tcp sum ok]");
455                 }
456         }
457 #ifdef INET6
458         if (IP_V(ip) == 6 && ip6->ip6_plen && vflag && !fragmented) {
459                 int sum;
460                 if (TTEST2(tp->th_sport, length)) {
461                         sum = tcp6_cksum(ip6, tp, length);
462                         if (sum != 0)
463                                 (void)printf(" [bad tcp cksum %x!]", sum);
464                         else
465                                 (void)printf(" [tcp sum ok]");
466                 }
467         }
468 #endif
469
470         length -= hlen;
471         if (vflag > 1 || length > 0 || flags & (TH_SYN | TH_FIN | TH_RST))
472                 (void)printf(" %u:%u(%d)", seq, seq + length, length);
473         if (flags & TH_ACK)
474                 (void)printf(" ack %u", ack);
475
476         (void)printf(" win %d", win);
477
478         if (flags & TH_URG)
479                 (void)printf(" urg %d", urp);
480         /*
481          * Handle any options.
482          */
483         if ((hlen -= sizeof(*tp)) > 0) {
484                 register const u_char *cp;
485                 register int i, opt, len, datalen;
486
487                 cp = (const u_char *)tp + sizeof(*tp);
488                 putchar(' ');
489                 ch = '<';
490                 while (hlen > 0) {
491                         putchar(ch);
492                         TCHECK(*cp);
493                         opt = *cp++;
494                         if (ZEROLENOPT(opt))
495                                 len = 1;
496                         else {
497                                 TCHECK(*cp);
498                                 len = *cp++;    /* total including type, len */
499                                 if (len < 2 || len > hlen)
500                                         goto bad;
501                                 --hlen;         /* account for length byte */
502                         }
503                         --hlen;                 /* account for type byte */
504                         datalen = 0;
505
506 /* Bail if "l" bytes of data are not left or were not captured  */
507 #define LENCHECK(l) { if ((l) > hlen) goto bad; TCHECK2(*cp, l); }
508
509                         switch (opt) {
510
511                         case TCPOPT_MAXSEG:
512                                 (void)printf("mss");
513                                 datalen = 2;
514                                 LENCHECK(datalen);
515                                 (void)printf(" %u", EXTRACT_16BITS(cp));
516
517                                 break;
518
519                         case TCPOPT_EOL:
520                                 (void)printf("eol");
521                                 break;
522
523                         case TCPOPT_NOP:
524                                 (void)printf("nop");
525                                 break;
526
527                         case TCPOPT_WSCALE:
528                                 (void)printf("wscale");
529                                 datalen = 1;
530                                 LENCHECK(datalen);
531                                 (void)printf(" %u", *cp);
532                                 break;
533
534                         case TCPOPT_SACKOK:
535                                 (void)printf("sackOK");
536                                 break;
537
538                         case TCPOPT_SACK:
539                                 (void)printf("sack");
540                                 datalen = len - 2;
541                                 if (datalen % 8 != 0) {
542                                         (void)printf(" malformed sack ");
543                                 } else {
544                                         u_int32_t s, e;
545
546                                         (void)printf(" sack %d ", datalen / 8);
547                                         for (i = 0; i < datalen; i += 8) {
548                                                 LENCHECK(i + 4);
549                                                 s = EXTRACT_32BITS(cp + i);
550                                                 LENCHECK(i + 8);
551                                                 e = EXTRACT_32BITS(cp + i + 4);
552                                                 if (threv) {
553                                                         s -= thseq;
554                                                         e -= thseq;
555                                                 } else {
556                                                         s -= thack;
557                                                         e -= thack;
558                                                 }
559                                                 (void)printf("{%u:%u}", s, e);
560                                         }
561                                         (void)printf(" ");
562                                 }
563                                 break;
564
565                         case TCPOPT_ECHO:
566                                 (void)printf("echo");
567                                 datalen = 4;
568                                 LENCHECK(datalen);
569                                 (void)printf(" %u", EXTRACT_32BITS(cp));
570                                 break;
571
572                         case TCPOPT_ECHOREPLY:
573                                 (void)printf("echoreply");
574                                 datalen = 4;
575                                 LENCHECK(datalen);
576                                 (void)printf(" %u", EXTRACT_32BITS(cp));
577                                 break;
578
579                         case TCPOPT_TIMESTAMP:
580                                 (void)printf("timestamp");
581                                 datalen = 8;
582                                 LENCHECK(4);
583                                 (void)printf(" %u", EXTRACT_32BITS(cp));
584                                 LENCHECK(datalen);
585                                 (void)printf(" %u", EXTRACT_32BITS(cp + 4));
586                                 break;
587
588                         case TCPOPT_CC:
589                                 (void)printf("cc");
590                                 datalen = 4;
591                                 LENCHECK(datalen);
592                                 (void)printf(" %u", EXTRACT_32BITS(cp));
593                                 break;
594
595                         case TCPOPT_CCNEW:
596                                 (void)printf("ccnew");
597                                 datalen = 4;
598                                 LENCHECK(datalen);
599                                 (void)printf(" %u", EXTRACT_32BITS(cp));
600                                 break;
601
602                         case TCPOPT_CCECHO:
603                                 (void)printf("ccecho");
604                                 datalen = 4;
605                                 LENCHECK(datalen);
606                                 (void)printf(" %u", EXTRACT_32BITS(cp));
607                                 break;
608
609                         default:
610                                 (void)printf("opt-%d:", opt);
611                                 datalen = len - 2;
612                                 for (i = 0; i < datalen; ++i) {
613                                         LENCHECK(i);
614                                         (void)printf("%02x", cp[i]);
615                                 }
616                                 break;
617                         }
618
619                         /* Account for data printed */
620                         cp += datalen;
621                         hlen -= datalen;
622
623                         /* Check specification against observed length */
624                         ++datalen;                      /* option octet */
625                         if (!ZEROLENOPT(opt))
626                                 ++datalen;              /* size octet */
627                         if (datalen != len)
628                                 (void)printf("[len %d]", len);
629                         ch = ',';
630                         if (opt == TCPOPT_EOL)
631                                 break;
632                 }
633                 putchar('>');
634         }
635
636         if (length <= 0)
637                 return;
638
639         /*
640          * Decode payload if necessary.
641          */
642         bp += TH_OFF(tp) * 4;
643         if (flags & TH_RST) {
644                 if (vflag)
645                         print_tcp_rst_data(bp, length);
646         } else {
647                 if (sport == TELNET_PORT || dport == TELNET_PORT) {
648                         if (!qflag && vflag)
649                                 telnet_print(bp, length);
650                 } else if (sport == BGP_PORT || dport == BGP_PORT)
651                         bgp_print(bp, length);
652                 else if (sport == NETBIOS_SSN_PORT || dport == NETBIOS_SSN_PORT)
653                         nbt_tcp_print(bp, length);
654                 else if (sport == BXXP_PORT || dport == BXXP_PORT)
655                         bxxp_print(bp, length);
656         }
657         return;
658 bad:
659         fputs("[bad opt]", stdout);
660         if (ch != '\0')
661                 putchar('>');
662         return;
663 trunc:
664         fputs("[|tcp]", stdout);
665         if (ch != '\0')
666                 putchar('>');
667 }
668
669 /*
670  * RFC1122 says the following on data in RST segments:
671  *
672  *         4.2.2.12  RST Segment: RFC-793 Section 3.4
673  *
674  *            A TCP SHOULD allow a received RST segment to include data.
675  *
676  *            DISCUSSION
677  *                 It has been suggested that a RST segment could contain
678  *                 ASCII text that encoded and explained the cause of the
679  *                 RST.  No standard has yet been established for such
680  *                 data.
681  *
682  */
683
684 static void
685 print_tcp_rst_data(register const u_char *sp, u_int length)
686 {
687         int c;
688
689         if (TTEST2(*sp, length))
690                 printf(" [RST");
691         else
692                 printf(" [!RST");
693         if (length > MAX_RST_DATA_LEN) {
694                 length = MAX_RST_DATA_LEN;      /* can use -X for longer */
695                 putchar('+');                   /* indicate we truncate */
696         }
697         putchar(' ');
698         while (length-- && sp <= snapend) {
699                 c = *sp++;
700                 if (isprint(c))
701                         putchar(c);
702                 else
703                         putchar('.');
704         }
705         putchar(']');
706 }