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