]> git.saurik.com Git - apple/network_cmds.git/blob - tcpdump.tproj/print-tcp.c
2c0d1e30e43e02de3829ee999b78eb4c2390074e
[apple/network_cmds.git] / tcpdump.tproj / print-tcp.c
1 /*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.0 (the 'License'). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
12 * this file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
20 * under the License."
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24 /*
25 * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996
26 * The Regents of the University of California. All rights reserved.
27 *
28 * Redistribution and use in source and binary forms, with or without
29 * modification, are permitted provided that: (1) source code distributions
30 * retain the above copyright notice and this paragraph in its entirety, (2)
31 * distributions including binary code include the above copyright notice and
32 * this paragraph in its entirety in the documentation or other materials
33 * provided with the distribution, and (3) all advertising materials mentioning
34 * features or use of this software display the following acknowledgement:
35 * ``This product includes software developed by the University of California,
36 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
37 * the University nor the names of its contributors may be used to endorse
38 * or promote products derived from this software without specific prior
39 * written permission.
40 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
41 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
42 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
43 */
44
45 #ifndef lint
46 static const char rcsid[] =
47 "@(#) $Header: /cvs/Darwin/Commands/NeXT/network_cmds/tcpdump.tproj/print-tcp.c,v 1.1.1.1 1999/05/02 03:58:34 wsanchez Exp $ (LBL)";
48 #endif
49
50 #include <sys/param.h>
51 #include <sys/time.h>
52
53 #include <netinet/in.h>
54 #include <netinet/in_systm.h>
55 #include <netinet/ip.h>
56 #include <netinet/ip_var.h>
57 #include <netinet/tcp.h>
58 #include <netinet/tcpip.h>
59
60 #include <stdio.h>
61 #include <stdlib.h>
62 #include <string.h>
63 #include <unistd.h>
64
65 #include "interface.h"
66 #include "addrtoname.h"
67 #include "extract.h"
68
69 /* Compatibility */
70 #ifndef TCPOPT_WSCALE
71 #define TCPOPT_WSCALE 3 /* window scale factor (rfc1072) */
72 #endif
73 #ifndef TCPOPT_SACKOK
74 #define TCPOPT_SACKOK 4 /* selective ack ok (rfc1072) */
75 #endif
76 #ifndef TCPOPT_SACK
77 #define TCPOPT_SACK 5 /* selective ack (rfc1072) */
78 #endif
79 #ifndef TCPOPT_ECHO
80 #define TCPOPT_ECHO 6 /* echo (rfc1072) */
81 #endif
82 #ifndef TCPOPT_ECHOREPLY
83 #define TCPOPT_ECHOREPLY 7 /* echo (rfc1072) */
84 #endif
85 #ifndef TCPOPT_TIMESTAMP
86 #define TCPOPT_TIMESTAMP 8 /* timestamps (rfc1323) */
87 #endif
88 #ifndef TCPOPT_CC
89 #define TCPOPT_CC 11 /* T/TCP CC options (rfc1644) */
90 #endif
91 #ifndef TCPOPT_CCNEW
92 #define TCPOPT_CCNEW 12 /* T/TCP CC options (rfc1644) */
93 #endif
94 #ifndef TCPOPT_CCECHO
95 #define TCPOPT_CCECHO 13 /* T/TCP CC options (rfc1644) */
96 #endif
97
98 struct tha {
99 struct in_addr src;
100 struct in_addr dst;
101 u_int port;
102 };
103
104 struct tcp_seq_hash {
105 struct tcp_seq_hash *nxt;
106 struct tha addr;
107 tcp_seq seq;
108 tcp_seq ack;
109 };
110
111 #define TSEQ_HASHSIZE 919
112
113 /* These tcp optinos do not have the size octet */
114 #define ZEROLENOPT(o) ((o) == TCPOPT_EOL || (o) == TCPOPT_NOP)
115
116 static struct tcp_seq_hash tcp_seq_hash[TSEQ_HASHSIZE];
117
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;
130
131 tp = (struct tcphdr *)bp;
132 ip = (struct ip *)bp2;
133 ch = '\0';
134 TCHECK(*tp);
135 if (length < sizeof(*tp)) {
136 (void)printf("truncated-tcp %d", length);
137 return;
138 }
139
140 sport = ntohs(tp->th_sport);
141 dport = ntohs(tp->th_dport);
142 seq = ntohl(tp->th_seq);
143 ack = ntohl(tp->th_ack);
144 win = ntohs(tp->th_win);
145 urp = ntohs(tp->th_urp);
146
147 (void)printf("%s.%s > %s.%s: ",
148 ipaddr_string(&ip->ip_src), tcpport_string(sport),
149 ipaddr_string(&ip->ip_dst), tcpport_string(dport));
150
151 if (qflag) {
152 (void)printf("tcp %d", length - tp->th_off * 4);
153 return;
154 }
155 if ((flags = tp->th_flags) & (TH_SYN|TH_FIN|TH_RST|TH_PUSH)) {
156 if (flags & TH_SYN)
157 putchar('S');
158 if (flags & TH_FIN)
159 putchar('F');
160 if (flags & TH_RST)
161 putchar('R');
162 if (flags & TH_PUSH)
163 putchar('P');
164 } else
165 putchar('.');
166
167 if (!Sflag && (flags & TH_ACK)) {
168 register struct tcp_seq_hash *th;
169 register int rev;
170 struct tha tha;
171 /*
172 * Find (or record) the initial sequence numbers for
173 * this conversation. (we pick an arbitrary
174 * collating order so there's only one entry for
175 * both directions).
176 */
177 if (sport < dport ||
178 (sport == dport &&
179 ip->ip_src.s_addr < ip->ip_dst.s_addr)) {
180 tha.src = ip->ip_src, tha.dst = ip->ip_dst;
181 tha.port = sport << 16 | dport;
182 rev = 0;
183 } else {
184 tha.src = ip->ip_dst, tha.dst = ip->ip_src;
185 tha.port = dport << 16 | sport;
186 rev = 1;
187 }
188
189 for (th = &tcp_seq_hash[tha.port % TSEQ_HASHSIZE];
190 th->nxt; th = th->nxt)
191 if (!memcmp((char *)&tha, (char *)&th->addr,
192 sizeof(th->addr)))
193 break;
194
195 if (!th->nxt || flags & TH_SYN) {
196 /* didn't find it or new conversation */
197 if (th->nxt == NULL) {
198 th->nxt = (struct tcp_seq_hash *)
199 calloc(1, sizeof(*th));
200 if (th->nxt == NULL)
201 error("tcp_print: calloc");
202 }
203 th->addr = tha;
204 if (rev)
205 th->ack = seq, th->seq = ack - 1;
206 else
207 th->seq = seq, th->ack = ack - 1;
208 } else {
209 if (rev)
210 seq -= th->ack, ack -= th->seq;
211 else
212 seq -= th->seq, ack -= th->ack;
213 }
214 }
215 hlen = tp->th_off * 4;
216 if (hlen > length) {
217 (void)printf(" [bad hdr length]");
218 return;
219 }
220 length -= hlen;
221 if (length > 0 || flags & (TH_SYN | TH_FIN | TH_RST))
222 (void)printf(" %u:%u(%d)", seq, seq + length, length);
223 if (flags & TH_ACK)
224 (void)printf(" ack %u", ack);
225
226 (void)printf(" win %d", win);
227
228 if (flags & TH_URG)
229 (void)printf(" urg %d", urp);
230 /*
231 * Handle any options.
232 */
233 if ((hlen -= sizeof(*tp)) > 0) {
234 register const u_char *cp;
235 register int i, opt, len, datalen;
236
237 cp = (const u_char *)tp + sizeof(*tp);
238 putchar(' ');
239 ch = '<';
240 while (hlen > 0) {
241 putchar(ch);
242 TCHECK(*cp);
243 opt = *cp++;
244 if (ZEROLENOPT(opt))
245 len = 1;
246 else {
247 TCHECK(*cp);
248 len = *cp++; /* total including type, len */
249 if (len < 2 || len > hlen)
250 goto bad;
251 --hlen; /* account for length byte */
252 }
253 --hlen; /* account for type byte */
254 datalen = 0;
255
256 /* Bail if "l" bytes of data are not left or were not captured */
257 #define LENCHECK(l) { if ((l) > hlen) goto bad; TCHECK2(*cp, l); }
258
259 switch (opt) {
260
261 case TCPOPT_MAXSEG:
262 (void)printf("mss");
263 datalen = 2;
264 LENCHECK(datalen);
265 (void)printf(" %u", EXTRACT_16BITS(cp));
266
267 break;
268
269 case TCPOPT_EOL:
270 (void)printf("eol");
271 break;
272
273 case TCPOPT_NOP:
274 (void)printf("nop");
275 break;
276
277 case TCPOPT_WSCALE:
278 (void)printf("wscale");
279 datalen = 1;
280 LENCHECK(datalen);
281 (void)printf(" %u", *cp);
282 break;
283
284 case TCPOPT_SACKOK:
285 (void)printf("sackOK");
286 break;
287
288 case TCPOPT_SACK:
289 (void)printf("sack");
290 datalen = len - 2;
291 for (i = 0; i < datalen; i += 4) {
292 LENCHECK(i + 4);
293 /* block-size@relative-origin */
294 (void)printf(" %u@%u",
295 EXTRACT_16BITS(cp + i + 2),
296 EXTRACT_16BITS(cp + i));
297 }
298 if (datalen % 4)
299 (void)printf("[len %d]", len);
300 break;
301
302 case TCPOPT_ECHO:
303 (void)printf("echo");
304 datalen = 4;
305 LENCHECK(datalen);
306 (void)printf(" %u", EXTRACT_32BITS(cp));
307 break;
308
309 case TCPOPT_ECHOREPLY:
310 (void)printf("echoreply");
311 datalen = 4;
312 LENCHECK(datalen);
313 (void)printf(" %u", EXTRACT_32BITS(cp));
314 break;
315
316 case TCPOPT_TIMESTAMP:
317 (void)printf("timestamp");
318 datalen = 8;
319 LENCHECK(4);
320 (void)printf(" %u", EXTRACT_32BITS(cp));
321 LENCHECK(datalen);
322 (void)printf(" %u", EXTRACT_32BITS(cp + 4));
323 break;
324
325 case TCPOPT_CC:
326 (void)printf("cc");
327 datalen = 4;
328 LENCHECK(datalen);
329 (void)printf(" %u", EXTRACT_32BITS(cp));
330 break;
331
332 case TCPOPT_CCNEW:
333 (void)printf("ccnew");
334 datalen = 4;
335 LENCHECK(datalen);
336 (void)printf(" %u", EXTRACT_32BITS(cp));
337 break;
338
339 case TCPOPT_CCECHO:
340 (void)printf("ccecho");
341 datalen = 4;
342 LENCHECK(datalen);
343 (void)printf(" %u", EXTRACT_32BITS(cp));
344 break;
345
346 default:
347 (void)printf("opt-%d:", opt);
348 datalen = len - 2;
349 for (i = 0; i < datalen; ++i) {
350 LENCHECK(i);
351 (void)printf("%02x", cp[i]);
352 }
353 break;
354 }
355
356 /* Account for data printed */
357 cp += datalen;
358 hlen -= datalen;
359
360 /* Check specification against observed length */
361 ++datalen; /* option octet */
362 if (!ZEROLENOPT(opt))
363 ++datalen; /* size octet */
364 if (datalen != len)
365 (void)printf("[len %d]", len);
366 ch = ',';
367 if (opt == TCPOPT_EOL)
368 break;
369 }
370 putchar('>');
371 }
372 return;
373 bad:
374 fputs("[bad opt]", stdout);
375 if (ch != '\0')
376 putchar('>');
377 return;
378 trunc:
379 fputs("[|tcp]", stdout);
380 if (ch != '\0')
381 putchar('>');
382 }
383