]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/tcpdump/print-tcp.c
This commit was generated by cvs2svn to compensate for changes in r55839,
[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: print-tcp.c,v 1.55 97/06/15 13:20:28 leres Exp $ (LBL)";
25 #endif
26
27 #include <sys/param.h>
28 #include <sys/time.h>
29
30 #include <netinet/in.h>
31 #include <netinet/in_systm.h>
32 #include <netinet/ip.h>
33 #include <netinet/ip_var.h>
34 #include <netinet/tcp.h>
35 #include <netinet/tcpip.h>
36
37 #ifdef HAVE_MEMORY_H
38 #include <memory.h>
39 #endif
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <unistd.h>
44
45 #include "interface.h"
46 #include "addrtoname.h"
47 #include "extract.h"
48
49 /* Compatibility */
50 #ifndef TCPOPT_WSCALE
51 #define TCPOPT_WSCALE           3       /* window scale factor (rfc1072) */
52 #endif
53 #ifndef TCPOPT_SACKOK
54 #define TCPOPT_SACKOK           4       /* selective ack ok (rfc1072) */
55 #endif
56 #ifndef TCPOPT_SACK
57 #define TCPOPT_SACK             5       /* selective ack (rfc1072) */
58 #endif
59 #ifndef TCPOPT_ECHO
60 #define TCPOPT_ECHO             6       /* echo (rfc1072) */
61 #endif
62 #ifndef TCPOPT_ECHOREPLY
63 #define TCPOPT_ECHOREPLY        7       /* echo (rfc1072) */
64 #endif
65 #ifndef TCPOPT_TIMESTAMP
66 #define TCPOPT_TIMESTAMP        8       /* timestamps (rfc1323) */
67 #endif
68 #ifndef TCPOPT_CC
69 #define TCPOPT_CC               11      /* T/TCP CC options (rfc1644) */
70 #endif
71 #ifndef TCPOPT_CCNEW
72 #define TCPOPT_CCNEW            12      /* T/TCP CC options (rfc1644) */
73 #endif
74 #ifndef TCPOPT_CCECHO
75 #define TCPOPT_CCECHO           13      /* T/TCP CC options (rfc1644) */
76 #endif
77
78 struct tha {
79         struct in_addr src;
80         struct in_addr dst;
81         u_int port;
82 };
83
84 struct tcp_seq_hash {
85         struct tcp_seq_hash *nxt;
86         struct tha addr;
87         tcp_seq seq;
88         tcp_seq ack;
89 };
90
91 #define TSEQ_HASHSIZE 919
92
93 /* These tcp optinos do not have the size octet */
94 #define ZEROLENOPT(o) ((o) == TCPOPT_EOL || (o) == TCPOPT_NOP)
95
96 static struct tcp_seq_hash tcp_seq_hash[TSEQ_HASHSIZE];
97
98
99 void
100 tcp_print(register const u_char *bp, register u_int length,
101           register const u_char *bp2)
102 {
103         register const struct tcphdr *tp;
104         register const struct ip *ip;
105         register u_char flags;
106         register int hlen;
107         register char ch;
108         u_short sport, dport, win, urp;
109         u_int32_t seq, ack;
110
111         tp = (struct tcphdr *)bp;
112         ip = (struct ip *)bp2;
113         ch = '\0';
114         TCHECK(*tp);
115         if (length < sizeof(*tp)) {
116                 (void)printf("truncated-tcp %d", length);
117                 return;
118         }
119
120         sport = ntohs(tp->th_sport);
121         dport = ntohs(tp->th_dport);
122         seq = ntohl(tp->th_seq);
123         ack = ntohl(tp->th_ack);
124         win = ntohs(tp->th_win);
125         urp = ntohs(tp->th_urp);
126
127         (void)printf("%s.%s > %s.%s: ",
128                 ipaddr_string(&ip->ip_src), tcpport_string(sport),
129                 ipaddr_string(&ip->ip_dst), tcpport_string(dport));
130
131         if (qflag) {
132                 (void)printf("tcp %d", length - tp->th_off * 4);
133                 return;
134         }
135         if ((flags = tp->th_flags) & (TH_SYN|TH_FIN|TH_RST|TH_PUSH)) {
136                 if (flags & TH_SYN)
137                         putchar('S');
138                 if (flags & TH_FIN)
139                         putchar('F');
140                 if (flags & TH_RST)
141                         putchar('R');
142                 if (flags & TH_PUSH)
143                         putchar('P');
144         } else
145                 putchar('.');
146
147         if (!Sflag && (flags & TH_ACK)) {
148                 register struct tcp_seq_hash *th;
149                 register int rev;
150                 struct tha tha;
151                 /*
152                  * Find (or record) the initial sequence numbers for
153                  * this conversation.  (we pick an arbitrary
154                  * collating order so there's only one entry for
155                  * both directions).
156                  */
157                 if (sport < dport ||
158                     (sport == dport &&
159                      ip->ip_src.s_addr < ip->ip_dst.s_addr)) {
160                         tha.src = ip->ip_src, tha.dst = ip->ip_dst;
161                         tha.port = sport << 16 | dport;
162                         rev = 0;
163                 } else {
164                         tha.src = ip->ip_dst, tha.dst = ip->ip_src;
165                         tha.port = dport << 16 | sport;
166                         rev = 1;
167                 }
168
169                 for (th = &tcp_seq_hash[tha.port % TSEQ_HASHSIZE];
170                      th->nxt; th = th->nxt)
171                         if (!memcmp((char *)&tha, (char *)&th->addr,
172                                   sizeof(th->addr)))
173                                 break;
174
175                 if (!th->nxt || flags & TH_SYN) {
176                         /* didn't find it or new conversation */
177                         if (th->nxt == NULL) {
178                                 th->nxt = (struct tcp_seq_hash *)
179                                         calloc(1, sizeof(*th));
180                                 if (th->nxt == NULL)
181                                         error("tcp_print: calloc");
182                         }
183                         th->addr = tha;
184                         if (rev)
185                                 th->ack = seq, th->seq = ack - 1;
186                         else
187                                 th->seq = seq, th->ack = ack - 1;
188                 } else {
189                         if (rev)
190                                 seq -= th->ack, ack -= th->seq;
191                         else
192                                 seq -= th->seq, ack -= th->ack;
193                 }
194         }
195         hlen = tp->th_off * 4;
196         if (hlen > length) {
197                 (void)printf(" [bad hdr length]");
198                 return;
199         }
200         length -= hlen;
201         if (length > 0 || flags & (TH_SYN | TH_FIN | TH_RST))
202                 (void)printf(" %u:%u(%d)", seq, seq + length, length);
203         if (flags & TH_ACK)
204                 (void)printf(" ack %u", ack);
205
206         (void)printf(" win %d", win);
207
208         if (flags & TH_URG)
209                 (void)printf(" urg %d", urp);
210         /*
211          * Handle any options.
212          */
213         if ((hlen -= sizeof(*tp)) > 0) {
214                 register const u_char *cp;
215                 register int i, opt, len, datalen;
216
217                 cp = (const u_char *)tp + sizeof(*tp);
218                 putchar(' ');
219                 ch = '<';
220                 while (hlen > 0) {
221                         putchar(ch);
222                         TCHECK(*cp);
223                         opt = *cp++;
224                         if (ZEROLENOPT(opt))
225                                 len = 1;
226                         else {
227                                 TCHECK(*cp);
228                                 len = *cp++;    /* total including type, len */
229                                 if (len < 2 || len > hlen)
230                                         goto bad;
231                                 --hlen;         /* account for length byte */
232                         }
233                         --hlen;                 /* account for type byte */
234                         datalen = 0;
235
236 /* Bail if "l" bytes of data are not left or were not captured  */
237 #define LENCHECK(l) { if ((l) > hlen) goto bad; TCHECK2(*cp, l); }
238
239                         switch (opt) {
240
241                         case TCPOPT_MAXSEG:
242                                 (void)printf("mss");
243                                 datalen = 2;
244                                 LENCHECK(datalen);
245                                 (void)printf(" %u", EXTRACT_16BITS(cp));
246
247                                 break;
248
249                         case TCPOPT_EOL:
250                                 (void)printf("eol");
251                                 break;
252
253                         case TCPOPT_NOP:
254                                 (void)printf("nop");
255                                 break;
256
257                         case TCPOPT_WSCALE:
258                                 (void)printf("wscale");
259                                 datalen = 1;
260                                 LENCHECK(datalen);
261                                 (void)printf(" %u", *cp);
262                                 break;
263
264                         case TCPOPT_SACKOK:
265                                 (void)printf("sackOK");
266                                 break;
267
268                         case TCPOPT_SACK:
269                                 (void)printf("sack");
270                                 datalen = len - 2;
271                                 for (i = 0; i < datalen; i += 4) {
272                                         LENCHECK(i + 4);
273                                         /* block-size@relative-origin */
274                                         (void)printf(" %u@%u",
275                                             EXTRACT_16BITS(cp + i + 2),
276                                             EXTRACT_16BITS(cp + i));
277                                 }
278                                 if (datalen % 4)
279                                         (void)printf("[len %d]", len);
280                                 break;
281
282                         case TCPOPT_ECHO:
283                                 (void)printf("echo");
284                                 datalen = 4;
285                                 LENCHECK(datalen);
286                                 (void)printf(" %u", EXTRACT_32BITS(cp));
287                                 break;
288
289                         case TCPOPT_ECHOREPLY:
290                                 (void)printf("echoreply");
291                                 datalen = 4;
292                                 LENCHECK(datalen);
293                                 (void)printf(" %u", EXTRACT_32BITS(cp));
294                                 break;
295
296                         case TCPOPT_TIMESTAMP:
297                                 (void)printf("timestamp");
298                                 datalen = 8;
299                                 LENCHECK(4);
300                                 (void)printf(" %u", EXTRACT_32BITS(cp));
301                                 LENCHECK(datalen);
302                                 (void)printf(" %u", EXTRACT_32BITS(cp + 4));
303                                 break;
304
305                         case TCPOPT_CC:
306                                 (void)printf("cc");
307                                 datalen = 4;
308                                 LENCHECK(datalen);
309                                 (void)printf(" %u", EXTRACT_32BITS(cp));
310                                 break;
311
312                         case TCPOPT_CCNEW:
313                                 (void)printf("ccnew");
314                                 datalen = 4;
315                                 LENCHECK(datalen);
316                                 (void)printf(" %u", EXTRACT_32BITS(cp));
317                                 break;
318
319                         case TCPOPT_CCECHO:
320                                 (void)printf("ccecho");
321                                 datalen = 4;
322                                 LENCHECK(datalen);
323                                 (void)printf(" %u", EXTRACT_32BITS(cp));
324                                 break;
325
326                         default:
327                                 (void)printf("opt-%d:", opt);
328                                 datalen = len - 2;
329                                 for (i = 0; i < datalen; ++i) {
330                                         LENCHECK(i);
331                                         (void)printf("%02x", cp[i]);
332                                 }
333                                 break;
334                         }
335
336                         /* Account for data printed */
337                         cp += datalen;
338                         hlen -= datalen;
339
340                         /* Check specification against observed length */
341                         ++datalen;                      /* option octet */
342                         if (!ZEROLENOPT(opt))
343                                 ++datalen;              /* size octet */
344                         if (datalen != len)
345                                 (void)printf("[len %d]", len);
346                         ch = ',';
347                         if (opt == TCPOPT_EOL)
348                                 break;
349                 }
350                 putchar('>');
351         }
352         return;
353 bad:
354         fputs("[bad opt]", stdout);
355         if (ch != '\0')
356                 putchar('>');
357         return;
358 trunc:
359         fputs("[|tcp]", stdout);
360         if (ch != '\0')
361                 putchar('>');
362 }
363