1 /*
2 * Copyright (c) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
3 * 2002, 2003, 2004
4 * Ohio University.
5 *
6 * ---
7 *
8 * Starting with the release of tcptrace version 6 in 2001, tcptrace
9 * is licensed under the GNU General Public License (GPL). We believe
10 * that, among the available licenses, the GPL will do the best job of
11 * allowing tcptrace to continue to be a valuable, freely-available
12 * and well-maintained tool for the networking community.
13 *
14 * Previous versions of tcptrace were released under a license that
15 * was much less restrictive with respect to how tcptrace could be
16 * used in commercial products. Because of this, I am willing to
17 * consider alternate license arrangements as allowed in Section 10 of
18 * the GNU GPL. Before I would consider licensing tcptrace under an
19 * alternate agreement with a particular individual or company,
20 * however, I would have to be convinced that such an alternative
21 * would be to the greater benefit of the networking community.
22 *
23 * ---
24 *
25 * This file is part of Tcptrace.
26 *
27 * Tcptrace was originally written and continues to be maintained by
28 * Shawn Ostermann with the help of a group of devoted students and
29 * users (see the file 'THANKS'). The work on tcptrace has been made
30 * possible over the years through the generous support of NASA GRC,
31 * the National Science Foundation, and Sun Microsystems.
32 *
33 * Tcptrace is free software; you can redistribute it and/or modify it
34 * under the terms of the GNU General Public License as published by
35 * the Free Software Foundation; either version 2 of the License, or
36 * (at your option) any later version.
37 *
38 * Tcptrace is distributed in the hope that it will be useful, but
39 * WITHOUT ANY WARRANTY; without even the implied warranty of
40 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
41 * General Public License for more details.
42 *
43 * You should have received a copy of the GNU General Public License
44 * along with Tcptrace (in the file 'COPYING'); if not, write to the
45 * Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
46 * MA 02111-1307 USA
47 *
48 * Author: Shawn Ostermann
49 * School of Electrical Engineering and Computer Science
50 * Ohio University
51 * Athens, OH
52 * ostermann@cs.ohiou.edu
53 * http://www.tcptrace.org/
54 */
55 #include "tcptrace.h"
56 static char const GCC_UNUSED copyright[] =
57 "@(#)Copyright (c) 2004 -- Ohio University.\n";
58 static char const GCC_UNUSED rcsid[] =
59 "@(#)$Header$";
60
61
62 #include "gcache.h"
63
64
65 /* locally global variables */
66 static int tcp_packet_count = 0;
67 static int search_count = 0;
68 static int active_conn_count = 0;
69 static int closed_conn_count = 0;
70 static Bool *ignore_pairs = NULL;/* which ones will we ignore */
71 static Bool bottom_letters = 0; /* I don't use this anymore */
72 static Bool more_conns_ignored = FALSE;
73 static double sample_elapsed_time=0; /* to keep track of owin samples */
74 static double total_elapsed_time=0; /* to keep track of owin samples */
75 static int num_removed_tcp_pairs = 0;
76 static int tline_left = 0; /* left and right time lines for the time line charts */
77 static int tline_right = 0;
78
79 /* provided globals */
80 int num_tcp_pairs = -1; /* how many pairs we've allocated */
81 tcp_pair **ttp = NULL; /* array of pointers to allocated pairs */
82 int max_tcp_pairs = 64; /* initial value, automatically increases */
83 u_long tcp_trace_count = 0;
84
85
86 /* local routine definitions */
87 static tcp_pair *NewTTP(struct ip *, struct tcphdr *);
88 static tcp_pair *FindTTP(struct ip *, struct tcphdr *, int *, ptp_ptr **);
89 static void MoreTcpPairs(int num_needed);
90 static void ExtractContents(u_long seq, u_long tcp_data_bytes,
91 u_long saved_data_bytes, void *pdata, tcb *ptcb);
92 static Bool check_hw_dups(u_short id, seqnum seq, tcb *ptcb);
93 static u_long SeqRep(tcb *ptcb, u_long seq);
94 static void UpdateConnLists(ptp_ptr *tcp_ptr, struct tcphdr *ptcp);
95 static void UpdateConnList(ptp_ptr *tcp_ptr,
96 const Bool valid,
97 ptp_ptr **conn_list_head,
98 ptp_ptr **conn_list_tail);
99 static void RemoveOldConns(ptp_ptr **conn_list_head,
100 ptp_ptr **conn_list_tail,
101 const unsigned expire_interval,
102 const Bool num_conn_check,
103 int *conn_count);
104 static void RemoveConn(const ptp_ptr *tcp_ptr);
105 static void RemoveTcpPair(const ptp_ptr *tcp_ptr);
106 static Bool MissingData(tcp_pair *ptp);
107
108 /* options */
109 Bool show_zero_window = TRUE;
110 Bool show_rexmit = TRUE;
111 Bool show_out_order = TRUE;
112 Bool show_sacks = TRUE;
113 Bool show_rtt_dongles = FALSE;
114 Bool show_triple_dupack = TRUE;
115 Bool show_zwnd_probes = TRUE;
116 Bool nonames = FALSE;
117 Bool use_short_names = FALSE;
118 Bool show_urg = TRUE;
119 int thru_interval = 10; /* in segments */
120
121
122 /* what colors to use */
123 /* choose from: "green" "red" "blue" "yellow" "purple" "orange"
124 "magenta" "pink" */
125 char *window_color = "yellow";
126 char *ack_color = "green";
127 char *sack_color = "purple";
128 char *data_color = "white";
129 char *retrans_color = "red";
130 char *hw_dup_color = "blue";
131 char *out_order_color = "pink";
132 char *text_color = "magenta";
133 char *default_color = "white";
134 char *synfin_color = "orange";
135 char *push_color = "white"; /* top arrow for PUSHed segments */
136 char *ecn_color = "yellow";
137 char *urg_color = "red";
138 char *probe_color = "orange";
139 char *a2b_seg_color = "green"; /* colors for segments on the time line chart */
140 char *b2a_seg_color = "yellow";
141
142
143 /* ack diamond dongle colors */
144 char *ackdongle_nosample_color = "blue";
145 char *ackdongle_ambig_color = "red";
146
147
148
149 /*
150 * ipcopyaddr: copy an IPv4 or IPv6 address
151 */
IP_COPYADDR(ipaddr * ptoaddr,ipaddr * pfromaddr)152 static inline void IP_COPYADDR (ipaddr *ptoaddr, ipaddr *pfromaddr)
153 {
154 if (ADDR_ISV6(pfromaddr)) {
155 memcpy(ptoaddr->un.ip6.s6_addr, pfromaddr->un.ip6.s6_addr, 16);
156 ptoaddr->addr_vers = 6;
157 } else {
158 ptoaddr->un.ip4.s_addr = pfromaddr->un.ip4.s_addr;
159 ptoaddr->addr_vers = 4;
160 }
161 }
162
163
164
165 /*
166 * ipsameaddr: test for equality of two IPv4 or IPv6 addresses
167 */
IP_SAMEADDR(ipaddr * paddr1,ipaddr * paddr2)168 static inline int IP_SAMEADDR (ipaddr *paddr1, ipaddr *paddr2)
169 {
170 int ret = 0;
171 if (ADDR_ISV4(paddr1)) {
172 if (ADDR_ISV4(paddr2))
173 ret = (paddr1->un.ip4.s_addr == paddr2->un.ip4.s_addr);
174 } else {
175 /* already know ADDR_ISV6(paddr1) */
176 if (ADDR_ISV6(paddr2))
177 ret = (memcmp(paddr1->un.ip6.s6_addr,
178 paddr2->un.ip6.s6_addr,16) == 0);
179 }
180 if (debug > 3)
181 printf("SameAddr(%s(%d),%s(%d)) returns %d\n",
182 HostName(*paddr1), ADDR_VERSION(paddr1),
183 HostName(*paddr2), ADDR_VERSION(paddr2),
184 ret);
185 return ret;
186 }
187
188 /*
189 * iplowaddr: test if one IPv4 or IPv6 address is lower than the second one
190 */
IP_LOWADDR(ipaddr * paddr1,ipaddr * paddr2)191 static inline int IP_LOWADDR (ipaddr *paddr1, ipaddr *paddr2)
192 {
193 int ret = 0;
194 if (ADDR_ISV6(paddr1)) {
195 if (ADDR_ISV6(paddr2))
196 ret = (memcmp(paddr1->un.ip6.s6_addr,
197 paddr2->un.ip6.s6_addr,16) < 0);
198 } else {
199 /* already know ADDR_ISV4(paddr1) */
200 if (ADDR_ISV4(paddr2))
201 ret = (paddr1->un.ip4.s_addr < paddr2->un.ip4.s_addr);
202 }
203 if (debug > 3)
204 printf("LowAddr(%s(%d),%s(%d)) returns %d\n",
205 HostName(*paddr1), ADDR_VERSION(paddr1),
206 HostName(*paddr2), ADDR_VERSION(paddr2),
207 ret);
208 return ret;
209 }
210
211
212 /* return elapsed time in microseconds */
213 /* (time2 - time1) */
214 double
elapsed(struct timeval time1,struct timeval time2)215 elapsed(
216 struct timeval time1,
217 struct timeval time2)
218 {
219 struct timeval etime;
220
221 /*sanity check, some of the files have packets out of order */
222 if (tv_lt(time2,time1)) {
223 return(0.0);
224 }
225
226 if (0) {
227 fprintf(stderr,"elapsed(%s,", ts2ascii(&time1));
228 fprintf(stderr,"%s) is ", ts2ascii(&time2));
229 }
230
231 etime = time2;
232 tv_sub(&etime, time1);
233
234 if (0)
235 fprintf(stderr,"\n\t%s \n", ts2ascii(&etime));
236
237 return((double)etime.tv_sec * 1000000 + (double)etime.tv_usec);
238 }
239
240
241
242 /* subtract the rhs from the lhs, result in lhs */
243 void
tv_sub(struct timeval * plhs,struct timeval rhs)244 tv_sub(struct timeval *plhs, struct timeval rhs)
245 {
246 /* sanity check, lhs MUST BE more than rhs */
247 if (tv_lt(*plhs,rhs)) {
248 fprintf(stderr,"tvsub(%s,", ts2ascii(plhs));
249 fprintf(stderr,"%s) bad timestamp order!\n", ts2ascii(&rhs));
250 /* exit(-1); */
251 plhs->tv_sec = plhs->tv_usec = 0;
252 return;
253 }
254
255 if (plhs->tv_usec >= rhs.tv_usec) {
256 plhs->tv_usec -= rhs.tv_usec;
257 } else if (plhs->tv_usec < rhs.tv_usec) {
258 plhs->tv_usec += US_PER_SEC - rhs.tv_usec;
259 plhs->tv_sec -= 1;
260 }
261 plhs->tv_sec -= rhs.tv_sec;
262 }
263
264
265 /* add the RHS to the LHS, answer in *plhs */
266 void
tv_add(struct timeval * plhs,struct timeval rhs)267 tv_add(struct timeval *plhs, struct timeval rhs)
268 {
269 plhs->tv_sec += rhs.tv_sec;
270 plhs->tv_usec += rhs.tv_usec;
271
272 if (plhs->tv_usec >= US_PER_SEC) {
273 plhs->tv_usec -= US_PER_SEC;
274 plhs->tv_sec += 1;
275 }
276 }
277
278
279 /* are the 2 times the same? */
280 Bool
tv_same(struct timeval lhs,struct timeval rhs)281 tv_same(struct timeval lhs, struct timeval rhs)
282 {
283 return((lhs.tv_sec == rhs.tv_sec) &&
284 (lhs.tv_usec == rhs.tv_usec));
285 }
286
287
288 /* 1: lhs > rhs */
289 /* 0: lhs == rhs */
290 /* -1: lhs < rhs */
291 int
tv_cmp(struct timeval lhs,struct timeval rhs)292 tv_cmp(struct timeval lhs, struct timeval rhs)
293 {
294 if (lhs.tv_sec > rhs.tv_sec) {
295 return(1);
296 }
297
298 if (lhs.tv_sec < rhs.tv_sec) {
299 return(-1);
300 }
301
302 /* ... else, seconds are the same */
303 if (lhs.tv_usec > rhs.tv_usec)
304 return(1);
305 else if (lhs.tv_usec == rhs.tv_usec)
306 return(0);
307 else
308 return(-1);
309 }
310
311
312
313 /* copy the IP addresses and port numbers into an addrblock structure */
314 /* in addition to copying the address, we also create a HASH value */
315 /* which is based on BOTH IP addresses and port numbers. It allows */
316 /* faster comparisons most of the time */
317 void
CopyAddr(tcp_pair_addrblock * ptpa,struct ip * pip,portnum port1,portnum port2)318 CopyAddr(
319 tcp_pair_addrblock *ptpa,
320 struct ip *pip,
321 portnum port1,
322 portnum port2)
323 {
324 ptpa->a_port = port1;
325 ptpa->b_port = port2;
326
327 if (PIP_ISV4(pip)) { /* V4 */
328 IP_COPYADDR(&ptpa->a_address, IPV4ADDR2ADDR(&pip->ip_src));
329 IP_COPYADDR(&ptpa->b_address, IPV4ADDR2ADDR(&pip->ip_dst));
330 /* fill in the hashed address */
331 ptpa->hash = ptpa->a_address.un.ip4.s_addr
332 + ptpa->b_address.un.ip4.s_addr
333 + ptpa->a_port + ptpa->b_port;
334
335 } else { /* V6 */
336 int i;
337 struct ipv6 *pip6 = (struct ipv6 *)pip;
338 IP_COPYADDR(&ptpa->a_address, IPV6ADDR2ADDR(&pip6->ip6_saddr));
339 IP_COPYADDR(&ptpa->b_address, IPV6ADDR2ADDR(&pip6->ip6_daddr));
340 /* fill in the hashed address */
341 ptpa->hash = ptpa->a_port + ptpa->b_port;
342 for (i=0; i < 16; ++i) {
343 ptpa->hash += ptpa->a_address.un.ip6.s6_addr[i];
344 ptpa->hash += ptpa->b_address.un.ip6.s6_addr[i];
345 }
346 }
347
348 if (debug > 3)
349 printf("Hash of (%s:%d,%s:%d) is %d\n",
350 HostName(ptpa->a_address),
351 ptpa->a_port,
352 HostName(ptpa->b_address),
353 ptpa->b_port,
354 ptpa->hash);
355 }
356
357 /*
358 * This function tells us which way to go (Left or Right) in search for our
359 * matching 4-tuple {IP1:port1; IP2:port2} in the AVL tree hash-bucket.
360 *
361 * It returns LT or RT depending on if we had to go left or right in the AVL Tree to
362 * find our exact 4-tuple match, if it existed in the tree.
363 * If the exact 4-tuple is found, it returns 0.
364 */
365
366 int
AVL_WhichDir(tcp_pair_addrblock * ptpa1,tcp_pair_addrblock * ptpa2)367 AVL_WhichDir(
368 tcp_pair_addrblock *ptpa1,
369 tcp_pair_addrblock *ptpa2)
370 {
371
372 /*
373 * Here is our algorithm. If ptpa1={x1:p1; x2:p2} and ptpa2={y1:q1; y2:q2}
374 * we choose X1=min(x1,x2) and X2=max(x1,x2); Similarly for Y1, Y2.
375 * P1=port associated with X1, i.e. it is p1 if x1<x2 and it is p2 if not.
376 * P2=port associated with X2. Similarly Q1, Q2 are calculated based on Y1,Y2.
377 *
378 * Compare (X1, Y1)? ; X1<Y1 => LEFT; X1>Y1 => RIGHT; X1==Y1 => Continue down
379 *
380 * Compare (X2, Y2)? ; X2<Y2 => LEFT; X2>Y2 => RIGHT; X2==Y2 => Continue down
381 *
382 * Compare (P1, Q1)? ; P1<Q1 => LEFT; P1>Q1 => RIGHT; P1==Q1 => Continue down
383 *
384 * Compare (P2, Q2)? ; P2<Q2 => LEFT; P2>Q2 => RIGHT;
385 *
386 * If P2==Q2, then this connection should have matched the A2B or B2A catch
387 * from WhichDir()
388 */
389
390 ipaddr *X1, *X2, *Y1, *Y2;
391 int P1, P2, Q1, Q2;
392
393 if (IP_LOWADDR(&(ptpa1->a_address), &(ptpa1->b_address))) {
394 X1=&ptpa1->a_address;
395 P1=ptpa1->a_port;
396 X2=&ptpa1->b_address;
397 P2=ptpa1->b_port;
398 }
399 else {
400 X1=&ptpa1->b_address;
401 P1=ptpa1->b_port;
402 X2=&ptpa1->a_address;
403 P2=ptpa1->a_port;
404 }
405
406 if (IP_LOWADDR(&(ptpa2->a_address), &(ptpa2->b_address))) {
407 Y1=&ptpa2->a_address;
408 Q1=ptpa2->a_port;
409 Y2=&ptpa2->b_address;
410 Q2=ptpa2->b_port;
411 }
412 else {
413 Y1=&ptpa2->b_address;
414 Q1=ptpa2->b_port;
415 Y2=&ptpa2->a_address;
416 Q2=ptpa2->a_port;
417 }
418
419 // Optimization suggested by Dr.Ostermann. Check the ports first.
420 if (P1<Q1) return LT;
421 if (Q1<P1) return RT;
422
423 if (P2<Q2) return LT;
424 if (Q2<P2) return RT;
425
426
427 if (IP_LOWADDR(X1,Y1)) return LT;
428 if (IP_LOWADDR(Y1,X1)) return RT;
429
430 if (IP_LOWADDR(X2,Y2)) return LT;
431 if (IP_LOWADDR(Y2,X2)) return RT;
432
433 return 0;
434 }
435
436 int
WhichDir(tcp_pair_addrblock * ptpa1,tcp_pair_addrblock * ptpa2)437 WhichDir(
438 tcp_pair_addrblock *ptpa1,
439 tcp_pair_addrblock *ptpa2)
440 {
441 #ifdef BROKEN_COMPILER
442 /* sorry for the ugly nested 'if', but a 4-way conjunction broke my*/
443 /* Optimizer (under 'gcc version cygnus-2.0.2')*/
444
445 /* same as first packet */
446 if (IP_SAMEADDR(&(ptpa1->a_address), &(ptpa2->a_address)))
447 if (IP_SAMEADDR(&(ptpa1->b_address), &(ptpa2->b_address)))
448 if ((ptpa1->a_port == ptpa2->a_port))
449 if ((ptpa1->b_port == ptpa2->b_port))
450 return(A2B);
451
452 /* reverse of first packet */
453 if (IP_SAMEADDR(&(ptpa1->a_address), &(ptpa2->b_address)))
454 if (IP_SAMEADDR(&(ptpa1->b_address), &(ptpa2->a_address)))
455 if ((ptpa1->a_port == ptpa2->b_port))
456 if ((ptpa1->b_port == ptpa2->a_port))
457 return(B2A);
458 #else /* BROKEN_COMPILER */
459 /* same as first packet */
460 if (IP_SAMEADDR(&(ptpa1->a_address), &(ptpa2->a_address)) &&
461 IP_SAMEADDR(&(ptpa1->b_address), &(ptpa2->b_address)) &&
462 (ptpa1->a_port == ptpa2->a_port) &&
463 (ptpa1->b_port == ptpa2->b_port))
464 return(A2B);
465
466 /* reverse of first packet */
467 if (IP_SAMEADDR(&(ptpa1->a_address), &(ptpa2->b_address)) &&
468 IP_SAMEADDR(&(ptpa1->b_address), &(ptpa2->a_address)) &&
469 (ptpa1->a_port == ptpa2->b_port) &&
470 (ptpa1->b_port == ptpa2->a_port))
471 return(B2A);
472 #endif /* BROKEN_COMPILER */
473
474 /* different connection */
475 return(0);
476 }
477
478 int
SameConn(tcp_pair_addrblock * ptpa1,tcp_pair_addrblock * ptpa2,int * pdir)479 SameConn(
480 tcp_pair_addrblock *ptpa1,
481 tcp_pair_addrblock *ptpa2,
482 int *pdir)
483 {
484
485 /* if the hash values are different, they can't be the same */
486 if (ptpa1->hash != ptpa2->hash)
487 return(0);
488
489 /* OK, they hash the same, are they REALLY the same function */
490 *pdir = WhichDir(ptpa1,ptpa2);
491 return(*pdir != 0);
492 }
493
494
495
496 static tcp_pair *
NewTTP(struct ip * pip,struct tcphdr * ptcp)497 NewTTP(
498 struct ip *pip,
499 struct tcphdr *ptcp)
500 {
501 char title[210];
502 tcp_pair *ptp;
503
504 if (0) {
505 printf("trace.c:NewTTP() calling MakeTcpPair()\n");
506 }
507 ptp = MakeTcpPair();
508 ++num_tcp_pairs;
509
510 if (!run_continuously) {
511 /* make a new one, if possible */
512 if ((num_tcp_pairs+1) >= max_tcp_pairs) {
513 MoreTcpPairs(num_tcp_pairs+1);
514 }
515 /* create a new TCP pair record and remember where you put it */
516 ttp[num_tcp_pairs] = ptp;
517 ptp->ignore_pair = ignore_pairs[num_tcp_pairs];
518 }
519
520
521 /* grab the address from this packet */
522 CopyAddr(&ptp->addr_pair,
523 pip, ntohs(ptcp->th_sport), ntohs(ptcp->th_dport));
524
525 ptp->a2b.time.tv_sec = -1;
526 ptp->b2a.time.tv_sec = -1;
527
528 ptp->a2b.host_letter = strdup(NextHostLetter());
529 ptp->b2a.host_letter = strdup(NextHostLetter());
530
531 ptp->a2b.ptp = ptp;
532 ptp->b2a.ptp = ptp;
533 ptp->a2b.ptwin = &ptp->b2a;
534 ptp->b2a.ptwin = &ptp->a2b;
535
536 /* fill in connection name fields */
537 ptp->a_hostname = strdup(HostName(ptp->addr_pair.a_address));
538 ptp->a_portname = strdup(ServiceName(ptp->addr_pair.a_port));
539 ptp->a_endpoint =
540 strdup(EndpointName(ptp->addr_pair.a_address,
541 ptp->addr_pair.a_port));
542 ptp->b_hostname = strdup(HostName(ptp->addr_pair.b_address));
543 ptp->b_portname = strdup(ServiceName(ptp->addr_pair.b_port));
544 ptp->b_endpoint =
545 strdup(EndpointName(ptp->addr_pair.b_address,
546 ptp->addr_pair.b_port));
547
548 /* make the initial guess that each side is a reno tcp */
549 /* this might actually be a poor thing to do in the sense that
550 we could be looking at a Tahoe trace ... but the only side
551 effect for the moment is that the LEAST estimate may be
552 busted, although it very well may not be */
553 ptp->a2b.tcp_strain = TCP_RENO;
554 ptp->b2a.tcp_strain = TCP_RENO;
555
556 ptp->a2b.LEAST = ptp->b2a.LEAST = 0;
557 ptp->a2b.in_rto = ptp->b2a.in_rto = FALSE;
558
559 /* init time sequence graphs */
560 ptp->a2b.tsg_plotter = ptp->b2a.tsg_plotter = NO_PLOTTER;
561 if (graph_tsg && !ptp->ignore_pair) {
562 if (!ignore_non_comp || (SYN_SET(ptcp))) {
563 snprintf(title,sizeof(title),"%s_==>_%s (time sequence graph)",
564 ptp->a_endpoint, ptp->b_endpoint);
565 ptp->a2b.tsg_plotter =
566 new_plotter(&ptp->a2b,NULL,title,
567 graph_time_zero?"relative time":"time",
568 graph_seq_zero?"sequence offset":"sequence number",
569 PLOT_FILE_EXTENSION);
570 snprintf(title,sizeof(title),"%s_==>_%s (time sequence graph)",
571 ptp->b_endpoint, ptp->a_endpoint);
572 ptp->b2a.tsg_plotter =
573 new_plotter(&ptp->b2a,NULL,title,
574 graph_time_zero?"relative time":"time",
575 graph_seq_zero?"sequence offset":"sequence number",
576 PLOT_FILE_EXTENSION);
577 if (graph_time_zero) {
578 /* set graph zero points */
579 plotter_nothing(ptp->a2b.tsg_plotter, current_time);
580 plotter_nothing(ptp->b2a.tsg_plotter, current_time);
581 }
582 }
583 }
584
585 /* init owin graphs */
586 ptp->a2b.owin_plotter = ptp->b2a.owin_plotter = NO_PLOTTER;
587 if (graph_owin && !ptp->ignore_pair) {
588 if (!ignore_non_comp || (SYN_SET(ptcp))) {
589 snprintf(title,sizeof(title),"%s_==>_%s (outstanding data)",
590 ptp->a_endpoint, ptp->b_endpoint);
591 ptp->a2b.owin_plotter =
592 new_plotter(&ptp->a2b,NULL,title,
593 graph_time_zero?"relative time":"time",
594 "Outstanding Data (bytes)",
595 OWIN_FILE_EXTENSION);
596 snprintf(title,sizeof(title),"%s_==>_%s (outstanding data)",
597 ptp->b_endpoint, ptp->a_endpoint);
598 ptp->b2a.owin_plotter =
599 new_plotter(&ptp->b2a,NULL,title,
600 graph_time_zero?"relative time":"time",
601 "Outstanding Data (bytes)",
602 OWIN_FILE_EXTENSION);
603 if (graph_time_zero) {
604 /* set graph zero points */
605 plotter_nothing(ptp->a2b.owin_plotter, current_time);
606 plotter_nothing(ptp->b2a.owin_plotter, current_time);
607 }
608 ptp->a2b.owin_line =
609 new_line(ptp->a2b.owin_plotter, "owin", "red");
610 ptp->b2a.owin_line =
611 new_line(ptp->b2a.owin_plotter, "owin", "red");
612
613 if (show_rwinline) {
614 ptp->a2b.rwin_line =
615 new_line(ptp->a2b.owin_plotter, "rwin", "yellow");
616 ptp->b2a.rwin_line =
617 new_line(ptp->b2a.owin_plotter, "rwin", "yellow");
618 }
619
620 ptp->a2b.owin_avg_line =
621 new_line(ptp->a2b.owin_plotter, "avg owin", "blue");
622 ptp->b2a.owin_avg_line =
623 new_line(ptp->b2a.owin_plotter, "avg owin", "blue");
624 ptp->a2b.owin_wavg_line =
625 new_line(ptp->a2b.owin_plotter, "wavg owin", "green");
626 ptp->b2a.owin_wavg_line =
627 new_line(ptp->b2a.owin_plotter, "wavg owin", "green");
628 }
629 }
630
631 /* init time line graphs (Avinash, 2 July 2002) */
632 ptp->a2b.tline_plotter = ptp->b2a.tline_plotter = NO_PLOTTER;
633 if (graph_tline && !ptp->ignore_pair) {
634 if (!ignore_non_comp || (SYN_SET(ptcp))) {
635 /* We don't want the standard a2b type name so we will specify
636 * a filename of type a_b when we call new_plotter.
637 */
638 char filename[25];
639 snprintf(filename,sizeof(filename),"%s_%s",
640 ptp->a2b.host_letter, ptp->a2b.ptwin->host_letter);
641
642 snprintf(title,sizeof(title),"%s_==>_%s (time line graph)",
643 ptp->a_endpoint, ptp->b_endpoint);
644 /* We will keep both the plotters the same since we want all
645 * segments going in either direction to be plotted on the same
646 * graph
647 */
648 ptp->a2b.tline_plotter = ptp->b2a.tline_plotter =
649 new_plotter(&ptp->a2b,filename,title,
650 "segments",
651 "relative time",
652 TLINE_FILE_EXTENSION);
653
654 /* Switch the x & y axis types.
655 * The default is x - timeval, y - unsigned,
656 * we need x - unsigned, y - dtime.
657 * Both the plotters are the same so we will
658 * only call this function once.
659 */
660 plotter_switch_axis(ptp->a2b.tline_plotter, TRUE);
661
662 /* set graph zero points */
663 plotter_nothing(ptp->a2b.tline_plotter, current_time);
664 plotter_nothing(ptp->b2a.tline_plotter, current_time);
665
666 /* Some graph initializations
667 * Generating a drawing space between x=0-100.
668 * The time lines will be at x=40 for source, x=60 for destination.
669 * Rest of the area on either sides will be used to print segment
670 * information.
671 *
672 * seg info |----->|
673 * |<-----| seg info
674 */
675 tline_left = 40;
676 tline_right = 60;
677 plotter_invisible(ptp->a2b.tline_plotter, current_time, 0);
678 plotter_invisible(ptp->a2b.tline_plotter, current_time, 100);
679 }
680 }
681
682
683 /* init segment size graphs */
684 ptp->a2b.segsize_plotter = ptp->b2a.segsize_plotter = NO_PLOTTER;
685 if (graph_segsize && !ptp->ignore_pair) {
686 snprintf(title,sizeof(title),"%s_==>_%s (segment size graph)",
687 ptp->a_endpoint, ptp->b_endpoint);
688 ptp->a2b.segsize_plotter =
689 new_plotter(&ptp->a2b,NULL,title,
690 graph_time_zero?"relative time":"time",
691 "segment size (bytes)",
692 SEGSIZE_FILE_EXTENSION);
693 snprintf(title,sizeof(title),"%s_==>_%s (segment size graph)",
694 ptp->b_endpoint, ptp->a_endpoint);
695 ptp->b2a.segsize_plotter =
696 new_plotter(&ptp->b2a,NULL,title,
697 graph_time_zero?"relative time":"time",
698 "segment size (bytes)",
699 SEGSIZE_FILE_EXTENSION);
700 if (graph_time_zero) {
701 /* set graph zero points */
702 plotter_nothing(ptp->a2b.segsize_plotter, current_time);
703 plotter_nothing(ptp->b2a.segsize_plotter, current_time);
704 }
705 ptp->a2b.segsize_line =
706 new_line(ptp->a2b.segsize_plotter, "segsize", "red");
707 ptp->b2a.segsize_line =
708 new_line(ptp->b2a.segsize_plotter, "segsize", "red");
709 ptp->a2b.segsize_avg_line =
710 new_line(ptp->a2b.segsize_plotter, "avg segsize", "blue");
711 ptp->b2a.segsize_avg_line =
712 new_line(ptp->b2a.segsize_plotter, "avg segsize", "blue");
713 }
714
715 /* init RWIN graphs */
716 ptp->a2b.recvwin_plotter = ptp->b2a.recvwin_plotter = NO_PLOTTER;
717 if (graph_recvwin && !ptp->ignore_pair) {
718 snprintf(title,sizeof(title),"%s_==>_%s (advertised receive window graph)",
719 ptp->a_endpoint, ptp->b_endpoint);
720 ptp->a2b.recvwin_plotter =
721 new_plotter(&ptp->a2b,NULL,title,
722 graph_time_zero?"relative time":"time",
723 "advertised window (bytes)",
724 RECVWIN_FILE_EXTENSION);
725 snprintf(title,sizeof(title),"%s_==>_%s (advertised receive window graph)",
726 ptp->b_endpoint, ptp->a_endpoint);
727 ptp->b2a.recvwin_plotter =
728 new_plotter(&ptp->b2a,NULL,title,
729 graph_time_zero?"relative time":"time",
730 "advertised window (bytes)",
731 RECVWIN_FILE_EXTENSION);
732 if (graph_time_zero) {
733 /* set graph zero points */
734 plotter_nothing(ptp->a2b.recvwin_plotter, current_time);
735 plotter_nothing(ptp->b2a.recvwin_plotter, current_time);
736 }
737 ptp->a2b.recvwin_line =
738 new_line(ptp->a2b.recvwin_plotter, "recvwin", "red");
739 ptp->b2a.recvwin_line =
740 new_line(ptp->b2a.recvwin_plotter, "recvwin", "red");
741 }
742
743 /* init RTT graphs */
744 ptp->a2b.rtt_plotter = ptp->b2a.rtt_plotter = NO_PLOTTER;
745
746 ptp->a2b.ss = MakeSeqspace();
747 ptp->b2a.ss = MakeSeqspace();
748
749 ptp->filename = cur_filename;
750
751 return(ptp);
752 }
753
754
755
756 /* connection records are stored in a hash table. Buckets are linked */
757 /* lists sorted by most recent access. */
758 #ifdef SMALL_TABLE
759 #define HASH_TABLE_SIZE 1021 /* oughta be prime */
760 #else /* SMALL_TABLE */
761 #define HASH_TABLE_SIZE 4099 /* oughta be prime */
762 #endif /* SMALL_TABLE */
763 static ptp_snap *ptp_hashtable[HASH_TABLE_SIZE] = {NULL};
764
765
766 /* search efficiency data (optional) */
767 /* one entry per hash table bucket */
768 struct search_efficiency {
769 unsigned num_connections;
770 unsigned max_connections;
771 unsigned max_depth;
772 unsigned num_searches;
773 unsigned num_comparisons;
774 };
775 static struct search_efficiency hashtable_efficiency[HASH_TABLE_SIZE];
776
777
778 /* double linked-lists of live and closed connections */
779 static ptp_ptr *live_conn_list_head = NULL;
780 static ptp_ptr *live_conn_list_tail = NULL;
781 static ptp_ptr *closed_conn_list_head = NULL;
782 static ptp_ptr *closed_conn_list_tail = NULL;
783 static timeval last_update_time = {0, 0};
784
785 static tcp_pair *
FindTTP(struct ip * pip,struct tcphdr * ptcp,int * pdir,ptp_ptr ** tcp_ptr)786 FindTTP(
787 struct ip *pip,
788 struct tcphdr *ptcp,
789 int *pdir,
790 ptp_ptr **tcp_ptr)
791 {
792 ptp_snap **pptph_head = NULL;
793 ptp_snap *ptph;
794 tcp_pair_addrblock tp_in;
795 struct search_efficiency *pse = NULL;
796 unsigned depth = 0;
797 int dir, conn_status;
798 hash hval;
799 *tcp_ptr = NULL;
800
801 if (debug > 10) {
802 printf("trace.c: FindTTP() called\n");
803 }
804
805 /* grab the address from this packet */
806 CopyAddr(&tp_in, pip, ntohs(ptcp->th_sport), ntohs(ptcp->th_dport));
807
808 /* grab the hash value (already computed by CopyAddr) */
809 hval = tp_in.hash % HASH_TABLE_SIZE;
810
811 pptph_head = &ptp_hashtable[hval];
812
813 if (debug) {
814 /* search efficiency checking */
815 pse = &hashtable_efficiency[hval];
816 }
817
818 if (pse) {
819 /* search efficiency instrumentation */
820 depth = 0;
821 ++pse->num_searches;
822 }
823
824 for (ptph = *pptph_head; ptph; ) {
825 if (debug) {
826 /* search efficiency instrumentation */
827 ++search_count;
828 if (pse) {
829 ++depth;
830 ++pse->num_comparisons;
831 }
832 }
833
834 /* See if the current node in the AVL tree hash-bucket
835 * is the exact same connection as ourselves,
836 * either in A2B or B2A directions.
837 */
838
839 dir = WhichDir(&tp_in, &ptph->addr_pair);
840
841 if (dir == A2B || dir == B2A) {
842 /* OK, this looks good, suck it into memory */
843
844 tcb *thisdir;
845 tcb *otherdir;
846 tcp_pair *ptp;
847 if (run_continuously) {
848 ptp_ptr *ptr = (ptp_ptr *)ptph->ptp;
849 ptp = ptr->ptp;
850 }
851 else {
852 ptp = (tcp_pair *)ptph->ptp;
853 }
854
855 /* figure out which direction this packet is going */
856 if (dir == A2B) {
857 thisdir = &ptp->a2b;
858 otherdir = &ptp->b2a;
859 } else {
860 thisdir = &ptp->b2a;
861 otherdir = &ptp->a2b;
862 }
863
864 /* check for "inactive" */
865 /* (this shouldn't happen anymore, they aren't on the list */
866 if (ptp->inactive) {
867
868 if (!run_continuously)
869 continue;
870 else {
871 *tcp_ptr = (ptp_ptr *)ptph->ptp;
872 return ((*tcp_ptr)->ptp);
873 }
874 }
875
876
877 /* Fri Oct 16, 1998 */
878 /* note: original heuristic was not sufficient. Bugs */
879 /* were pointed out by Brian Utterback and later by */
880 /* myself and Mark Allman */
881
882 if (!run_continuously) {
883 /* check for NEW connection on these same endpoints */
884 /* 1) At least 4 minutes idle time */
885 /* OR */
886 /* 2) heuristic (we might miss some) either: */
887 /* this packet has a SYN */
888 /* last conn saw both FINs and/or RSTs */
889 /* SYN sequence number outside last window (rfc 1122) */
890 /* (or less than initial Sequence, */
891 /* for wrap around trouble) - Tue Nov 3, 1998*/
892 /* OR */
893 /* 3) this is a SYN, last had a SYN, seq numbers differ */
894 /* if so, mark it INACTIVE and skip from now on */
895 if (0 && SYN_SET(ptcp)) {
896 /* better keep this debugging around, it keeps breaking */
897 printf("elapsed: %f sec\n",
898 elapsed(ptp->last_time,current_time)/1000000);
899 printf("SYN_SET: %d\n", SYN_SET(ptcp));
900 printf("a2b.fin_count: %d\n", ptp->a2b.fin_count);
901 printf("b2a.fin_count: %d\n", ptp->b2a.fin_count);
902 printf("a2b.reset_count: %d\n", ptp->a2b.reset_count);
903 printf("b2a.reset_count: %d\n", ptp->b2a.reset_count);
904 printf("dir: %d (%s)\n", dir, dir==A2B?"A2B":"B2A");
905 printf("seq: %lu \n", (u_long)ntohl(ptcp->th_seq));
906 printf("winend: %lu \n", otherdir->windowend);
907 printf("syn: %lu \n", otherdir->syn);
908 printf("SEQ_GREATERTHAN winend: %d\n",
909 SEQ_GREATERTHAN(ntohl(ptcp->th_seq),otherdir->windowend));
910 printf("SEQ_LESSTHAN init syn: %d\n",
911 SEQ_LESSTHAN(ntohl(ptcp->th_seq),thisdir->syn));
912 }
913
914 if (/* rule 1 */
915 (elapsed(ptp->last_time,current_time)/1000000 > nonreal_live_conn_interval)//(4*60)) - Using nonreal_live_conn_interval instead of the 4 mins heuristic
916 || /* rule 2 */
917 ((SYN_SET(ptcp)) &&
918 (((thisdir->fin_count >= 1) ||
919 (otherdir->fin_count >= 1)) ||
920 ((thisdir->reset_count >= 1) ||
921 (otherdir->reset_count >= 1))) &&
922 (SEQ_GREATERTHAN(ntohl(ptcp->th_seq),otherdir->windowend) ||
923 SEQ_LESSTHAN(ntohl(ptcp->th_seq),thisdir->syn)))
924 || /* rule 3 */
925 (SYN_SET(ptcp) &&
926 (thisdir->syn_count > 1) &&
927 (thisdir->syn != ntohl(ptcp->th_seq)))) {
928
929 if (debug>1) {
930 printf("%s: Marking %p %s<->%s INACTIVE (idle: %f sec)\n",
931 ts2ascii(¤t_time),
932 ptp,
933 ptp->a_endpoint, ptp->b_endpoint,
934 elapsed(ptp->last_time,
935 current_time)/1000000);
936 if (debug > 3)
937 PrintTrace(ptp);
938 }
939
940 /* we won't need this one anymore, remove it from the */
941 /* hash table so we won't have to skip over it */
942 ptp->inactive = TRUE;
943
944 if (debug > 4)
945 printf("Removing connection from hashtable:\
946 FindTTP() calling SnapRemove()\n");
947
948 /* Removes connection snapshot from AVL tree */
949 SnapRemove(pptph_head, ptph->addr_pair);
950
951 break;
952 }
953 }
954
955 if (run_continuously)
956 (*tcp_ptr) = (ptp_ptr *)ptph->ptp;
957
958 *pdir = dir;
959 return (ptp);
960 } else { // WhichDir returned 0, meaning if it exists, it's deeper
961 conn_status = AVL_WhichDir(&tp_in,&ptph->addr_pair);
962 if (conn_status == LT)
963 ptph = ptph->left;
964 else if (conn_status == RT)
965 ptph = ptph->right;
966 else if (!conn_status) {
967 fprintf(stderr, "WARNING!! AVL_WhichDir() should not return 0 if\n"
968 "\tWhichDir() didn't return A2B or B2A previously\n");
969 break;
970 }
971 }
972 }
973
974
975 /* Didn't find it, make a new one, if possible */
976 if (0) {
977 printf("trace.c:FindTTP() calling MakePtpSnap()\n");
978 }
979 ptph = MakePtpSnap();
980
981 if (run_continuously) {
982 ptp_ptr *ptr = (ptp_ptr *)MakePtpPtr();
983 ptr->prev = NULL;
984
985 if (live_conn_list_head == NULL) {
986 ptr->next = NULL;
987 live_conn_list_head = ptr;
988 live_conn_list_tail = ptr;
989 }
990 else {
991 ptr->next = live_conn_list_head;
992 live_conn_list_head->prev = ptr;
993 live_conn_list_head = ptr;
994 }
995 ptr->from = ptph;
996 ptr->ptp = NewTTP(pip, ptcp);
997 ptph->addr_pair = ptr->ptp->addr_pair;
998 ptph->ptp = (void *)ptr;
999 if (conn_num_threshold) {
1000 active_conn_count++;
1001 if (active_conn_count > max_conn_num) {
1002 ptp_ptr *last_ptr = live_conn_list_tail;
1003 live_conn_list_tail = last_ptr->prev;
1004 live_conn_list_tail->next = NULL;
1005 RemoveConn(last_ptr);
1006 num_removed_tcp_pairs++;
1007 active_conn_count--;
1008 FreePtpPtr(last_ptr);
1009 }
1010 }
1011 }
1012 else {
1013 tcp_pair *tmp = NewTTP(pip,ptcp);
1014 ptph->addr_pair = tmp->addr_pair;
1015 ptph->ptp = tmp;
1016 }
1017
1018 /* To insert the new connection snapshot into the AVL tree */
1019
1020 if (debug > 4)
1021 printf("Inserting connection into hashtable:\
1022 FindTTP() calling SnapInsert() \n");
1023 SnapInsert(pptph_head, ptph);
1024
1025 if (pse) {
1026 /* search efficiency instrumentation */
1027 ++pse->num_connections;
1028 if (depth > pse->max_depth)
1029 pse->max_depth = depth;
1030 if (pse->num_connections > pse->max_connections)
1031 pse->max_connections = pse->num_connections;
1032 }
1033
1034
1035 *pdir = A2B;
1036 if (run_continuously) {
1037 *tcp_ptr = (ptp_ptr *)ptph->ptp;
1038 return ((*tcp_ptr)->ptp);
1039 }
1040 else
1041 return (tcp_pair *)(ptph->ptp);
1042 }
1043
1044 static void
UpdateConnLists(ptp_ptr * tcp_ptr,struct tcphdr * ptcp)1045 UpdateConnLists(
1046 ptp_ptr *tcp_ptr,
1047 struct tcphdr *ptcp)
1048 {
1049 time_t real_time;
1050 static int minutes = 0;
1051
1052 if (0) {
1053 printf("trace.c: UpdateConnLists() called\n");
1054 }
1055
1056 if ((FinCount(tcp_ptr->ptp) > 0) || (ConnReset(tcp_ptr->ptp))) {
1057 /* we have FIN or RST */
1058 if (!tcp_ptr->ptp->inactive) {
1059 /* this is the only FIN or new RST - remove from list of active conns */
1060 if (debug > 6) {
1061 printf("UpdateConnLists: removing conn from list of active conns\n");
1062 }
1063 UpdateConnList(tcp_ptr, FALSE,
1064 &live_conn_list_head,
1065 &live_conn_list_tail);
1066 tcp_ptr->ptp->inactive = TRUE;
1067
1068 if (conn_num_threshold) {
1069 active_conn_count--;
1070 closed_conn_count++;
1071 if (closed_conn_count > max_conn_num) {
1072 ptp_ptr *last_ptr = closed_conn_list_tail;
1073 closed_conn_list_tail = last_ptr->prev;
1074 closed_conn_list_tail->next = NULL;
1075 RemoveConn(last_ptr);
1076 num_removed_tcp_pairs++;
1077 closed_conn_count--;
1078 FreePtpPtr(last_ptr);
1079 }
1080 }
1081
1082 /* put entry into the list of inactive connections */
1083 if (closed_conn_list_head) {
1084 tcp_ptr->next = closed_conn_list_head;
1085 tcp_ptr->prev = NULL;
1086 closed_conn_list_head->prev = tcp_ptr;
1087 closed_conn_list_head = tcp_ptr;
1088 }
1089 else {
1090 tcp_ptr->next = NULL;
1091 tcp_ptr->prev = NULL;
1092 closed_conn_list_head = tcp_ptr;
1093 closed_conn_list_tail = tcp_ptr;
1094 }
1095 }
1096 else {
1097 /* update the list of closed connecitons */
1098 UpdateConnList(tcp_ptr, TRUE, &closed_conn_list_head,
1099 &closed_conn_list_tail);
1100 }
1101 }
1102 else {/* don't have FIN(s)/RST */
1103 /* update only list of active connections */
1104 if (tcp_ptr->ptp->inactive == TRUE) {
1105 printf("WARNING!!! con is inactive, ptr=%p, con=%p, fin=%i, rst=%i\n", tcp_ptr,
1106 tcp_ptr->ptp, FinCount(tcp_ptr->ptp), ConnReset(tcp_ptr->ptp));
1107 printf("a2b.reset_count=%i, b2a.reset_count=%i, RESET_SET(tcph)=%i\n",
1108 tcp_ptr->ptp->a2b.reset_count, tcp_ptr->ptp->b2a.reset_count,
1109 RESET_SET(ptcp));
1110 }
1111 UpdateConnList(tcp_ptr, TRUE, &live_conn_list_head, &live_conn_list_tail);
1112 }
1113
1114 /* if we haven't updated the structures for at least update_interval number
1115 * of seconds, update list of connections and hash table */
1116 if ((elapsed(last_update_time, current_time) / 1000000) >= update_interval) {
1117
1118 real_time = time(&real_time);
1119 if (debug > 10)
1120 fprintf(stderr, "%3i program time: %i\tcurrent time: %i\tdifference: %i\n",
1121 ++minutes, (int)current_time.tv_sec, (int)real_time,
1122 (int)(real_time - current_time.tv_sec));
1123 if (conn_num_threshold) {
1124 RemoveOldConns(&live_conn_list_head,
1125 &live_conn_list_tail,
1126 remove_live_conn_interval,
1127 TRUE,
1128 &active_conn_count);
1129 RemoveOldConns(&closed_conn_list_head,
1130 &closed_conn_list_tail,
1131 remove_closed_conn_interval,
1132 TRUE,
1133 &closed_conn_count);
1134 }
1135 else {
1136 RemoveOldConns(&live_conn_list_head,
1137 &live_conn_list_tail,
1138 remove_live_conn_interval,
1139 FALSE,
1140 0);
1141 RemoveOldConns(&closed_conn_list_head,
1142 &closed_conn_list_tail,
1143 remove_closed_conn_interval,
1144 FALSE,
1145 0);
1146 }
1147 last_update_time = current_time;
1148 }
1149 }
1150
1151
1152
1153 static void
UpdateConnList(ptp_ptr * tcp_ptr,const Bool valid,ptp_ptr ** conn_list_head,ptp_ptr ** conn_list_tail)1154 UpdateConnList(
1155 ptp_ptr *tcp_ptr,
1156 const Bool valid,
1157 ptp_ptr **conn_list_head,
1158 ptp_ptr **conn_list_tail)
1159 {
1160 ptp_ptr *ptr_prev;
1161 ptp_ptr *ptr_next;
1162
1163 if (0) {
1164 printf("UpdateConnList() called\n");
1165 }
1166 if (tcp_ptr == (*conn_list_head)) {
1167 if (valid) {
1168 return;
1169 }
1170 else {
1171 *conn_list_head = tcp_ptr->next;
1172 if ((*conn_list_tail) == tcp_ptr)
1173 *conn_list_tail = NULL;
1174 else
1175 (*conn_list_head)->prev = NULL;
1176 return;
1177 }
1178 }
1179
1180 ptr_prev = tcp_ptr->prev;
1181 ptr_next = tcp_ptr->next;
1182
1183 ptr_prev->next = ptr_next;
1184
1185 if (ptr_next)
1186 ptr_next->prev = ptr_prev;
1187 if (tcp_ptr == (*conn_list_tail))
1188 *conn_list_tail = ptr_prev;
1189
1190 if (valid) {
1191 tcp_ptr->next = (*conn_list_head);
1192 tcp_ptr->prev = NULL;
1193 (*conn_list_head)->prev = tcp_ptr;
1194 *conn_list_head = tcp_ptr;
1195 }
1196 return;
1197 }
1198
1199
1200
1201 static void
RemoveOldConns(ptp_ptr ** conn_list_head,ptp_ptr ** conn_list_tail,const unsigned expire_interval,const Bool num_conn_check,int * conn_count)1202 RemoveOldConns(
1203 ptp_ptr **conn_list_head,
1204 ptp_ptr **conn_list_tail,
1205 const unsigned expire_interval,
1206 const Bool num_conn_check,
1207 int *conn_count)
1208 {
1209 ptp_ptr *ptr;
1210 ptp_ptr *prev_ptr;
1211
1212 if (0) {
1213 printf("trace.c: RemoveOldConns() called\n");
1214 }
1215
1216 if ((*conn_list_tail) == NULL) {
1217 return;
1218 }
1219
1220 ptr = (*conn_list_tail);
1221 prev_ptr = ptr->prev;
1222 for (; prev_ptr != NULL; ptr = prev_ptr, prev_ptr = ptr->prev) {
1223 if ((elapsed(ptr->ptp->last_time, current_time) / 1000000) >=
1224 expire_interval) {
1225 /* if the connection is old enough, remove the snap from the linked-list
1226 and the hash_table */
1227 ptr->prev->next = NULL;
1228 *conn_list_tail = ptr->prev;
1229 RemoveConn(ptr);
1230 num_removed_tcp_pairs++;
1231 if (0) {
1232 printf("trace.c:RemoveOldConns() calling FreePtpSnap()\n");
1233 }
1234 FreePtpPtr(ptr);
1235 if (num_conn_check)
1236 --(*conn_count);
1237 }
1238 else {
1239 break;
1240 }
1241 }
1242
1243 if (((*conn_list_head)->ptp->last_time.tv_sec != 0) &&
1244 ((elapsed((*conn_list_head)->ptp->last_time, current_time) / 1000000) >=
1245 expire_interval)) {
1246 *conn_list_head = NULL;
1247 *conn_list_tail = NULL;
1248 RemoveConn(ptr);
1249 num_removed_tcp_pairs++;
1250 FreePtpPtr(ptr);
1251 if (num_conn_check)
1252 --(*conn_count);
1253 }
1254 }
1255
1256
1257
1258 /* remove tcp pair from the hash table */
1259 static void
RemoveConn(const ptp_ptr * tcp_ptr)1260 RemoveConn(
1261 const ptp_ptr *tcp_ptr)
1262 {
1263 hash hval;
1264
1265 if (0) {
1266 printf("trace.c: RemoveConn(%p %s<->%s) called\n",
1267 tcp_ptr->ptp, tcp_ptr->ptp->a_endpoint, tcp_ptr->ptp->b_endpoint);
1268 }
1269
1270 ModulesPerOldConn(tcp_ptr->ptp);
1271
1272 hval = tcp_ptr->ptp->addr_pair.hash % HASH_TABLE_SIZE;
1273
1274 /* Remove the connection snapshot from AVL tree */
1275 if (debug > 4)
1276 printf("Removing connection from hashtable:\
1277 RemoveConn() calling SnapRemove()\n");
1278
1279 SnapRemove(&ptp_hashtable[hval], tcp_ptr->ptp->addr_pair);
1280
1281 RemoveTcpPair(tcp_ptr);
1282 }
1283
1284
1285
1286 static void
RemoveTcpPair(const ptp_ptr * tcp_ptr)1287 RemoveTcpPair(
1288 const ptp_ptr *tcp_ptr)
1289 {
1290 int i = 0;
1291 tcp_pair *ptp = tcp_ptr->ptp;
1292
1293 if (0) {
1294 printf("trace.c: RemoveTcpPair(%p) called\n", tcp_ptr->ptp);
1295 }
1296
1297 free(ptp->a2b.host_letter);
1298 free(ptp->b2a.host_letter);
1299
1300 free(ptp->a_hostname);
1301 free(ptp->a_portname);
1302 free(ptp->a_endpoint);
1303
1304 free(ptp->b_hostname);
1305 free(ptp->b_portname);
1306 free(ptp->b_endpoint);
1307
1308 if (ptp->a2b.owin_line) {
1309 free(ptp->a2b.owin_line);
1310 }
1311
1312 if (show_rwinline) {
1313 if (ptp->a2b.rwin_line) {
1314 free(ptp->a2b.rwin_line);
1315 }
1316 }
1317
1318 if (ptp->a2b.owin_avg_line) {
1319 free(ptp->a2b.owin_avg_line);
1320 }
1321 if (ptp->a2b.owin_wavg_line) {
1322 free(ptp->a2b.owin_avg_line);
1323 }
1324 if (ptp->b2a.owin_line) {
1325 free(ptp->b2a.owin_line);
1326 }
1327
1328 if (show_rwinline) {
1329 if (ptp->b2a.rwin_line) {
1330 free(ptp->b2a.rwin_line);
1331 }
1332 }
1333
1334 if (ptp->b2a.owin_avg_line) {
1335 free(ptp->b2a.owin_avg_line);
1336 }
1337 if (ptp->b2a.owin_wavg_line) {
1338 free(ptp->b2a.owin_wavg_line);
1339 }
1340
1341 if (ptp->a2b.segsize_line) {
1342 free(ptp->a2b.segsize_line);
1343 }
1344 if (ptp->a2b.segsize_avg_line) {
1345 free(ptp->a2b.segsize_avg_line);
1346 }
1347 if (ptp->b2a.segsize_line) {
1348 free(ptp->b2a.segsize_line);
1349 }
1350 if (ptp->b2a.segsize_avg_line) {
1351 free(ptp->b2a.segsize_avg_line);
1352 }
1353
1354 if (ptp->a2b.recvwin_line) {
1355 free(ptp->a2b.recvwin_line);
1356 }
1357 if (ptp->b2a.recvwin_line) {
1358 free(ptp->b2a.recvwin_line);
1359 }
1360
1361 if (ptp->a2b.ss) {
1362 for (i = 0; i < 4; i++) {
1363 if (ptp->a2b.ss->pquad[i] != NULL) {
1364 freequad(&ptp->a2b.ss->pquad[i]);
1365 }
1366 }
1367 FreeSeqspace(ptp->a2b.ss);
1368 }
1369
1370 if (ptp->b2a.ss) {
1371 for (i = 0; i < 4; i++) {
1372 if (ptp->b2a.ss->pquad[i] != NULL) {
1373 freequad(&ptp->b2a.ss->pquad[i]);
1374 }
1375 }
1376 FreeSeqspace(ptp->b2a.ss);
1377 }
1378
1379 FreeTcpPair(ptp);
1380 }
1381
1382
1383
1384 tcp_pair *
dotrace(struct ip * pip,struct tcphdr * ptcp,void * plast)1385 dotrace(
1386 struct ip *pip,
1387 struct tcphdr *ptcp,
1388 void *plast)
1389 {
1390 struct tcp_options *ptcpo;
1391 tcp_pair *ptp_save;
1392 int tcp_length;
1393 int tcp_data_length;
1394 u_long start;
1395 u_long end;
1396 tcb *thisdir;
1397 tcb *otherdir;
1398 tcp_pair tp_in;
1399 PLOTTER to_tsgpl;
1400 PLOTTER from_tsgpl;
1401 PLOTTER tlinepl;
1402 int dir = A2B; /* initialize to default, always changed below */
1403 Bool retrans;
1404 Bool probe;
1405 Bool hw_dup = FALSE; /* duplicate at the hardware level */
1406 Bool ecn_ce = FALSE;
1407 Bool ecn_echo = FALSE;
1408 Bool cwr = FALSE;
1409 Bool urg = FALSE;
1410 int retrans_num_bytes;
1411 Bool out_order; /* out of order */
1412 u_short th_sport; /* source port */
1413 u_short th_dport; /* destination port */
1414 tcp_seq th_seq; /* sequence number */
1415 tcp_seq th_ack; /* acknowledgement number */
1416 u_short th_win; /* window */
1417 u_long eff_win; /* window after scaling */
1418 u_short th_urp; /* URGENT pointer */
1419 short ip_len; /* total length */
1420 enum t_ack ack_type=NORMAL; /* how should we draw the ACK */
1421 seqnum old_this_windowend; /* for graphing */
1422 ptp_ptr *tcp_ptr = NULL;
1423
1424 /* make sure we have enough of the packet */
1425 if ((char *)ptcp + sizeof(struct tcphdr)-1 > (char *)plast) {
1426 if (warn_printtrunc)
1427 fprintf(stderr,
1428 "TCP packet %lu truncated too short to trace, ignored\n",
1429 pnum);
1430 ++ctrunc;
1431 return(NULL);
1432 }
1433
1434
1435 /* convert interesting fields to local byte order */
1436 th_seq = ntohl(ptcp->th_seq);
1437 th_ack = ntohl(ptcp->th_ack);
1438 th_sport = ntohs(ptcp->th_sport);
1439 th_dport = ntohs(ptcp->th_dport);
1440 th_win = ntohs(ptcp->th_win);
1441 th_urp = ntohs(ptcp->th_urp);
1442 ip_len = gethdrlength(pip, plast) + getpayloadlength(pip,plast);
1443
1444 /* make sure this is one of the connections we want */
1445 ptp_save = FindTTP(pip,ptcp,&dir, &tcp_ptr);
1446
1447 ++tcp_packet_count;
1448
1449 if (ptp_save == NULL) {
1450 return(NULL);
1451 }
1452
1453 ++tcp_trace_count;
1454
1455 if (run_continuously && (tcp_ptr == NULL)) {
1456 fprintf(stderr, "Did not initialize tcp pair pointer\n");
1457 exit(1);
1458 }
1459
1460 /* do time stats */
1461 if (ZERO_TIME(&ptp_save->first_time)) {
1462 ptp_save->first_time = current_time;
1463 }
1464 ptp_save->last_time = current_time;
1465
1466
1467 /* bug fix: it's legal to have the same end points reused. The */
1468 /* program uses a heuristic of looking at the elapsed time from */
1469 /* the last packet on the previous instance and the number of FINs */
1470 /* in the last instance. If we don't increment the fin_count */
1471 /* before bailing out in "ignore_pair" below, this heuristic breaks */
1472
1473 /* figure out which direction this packet is going */
1474 if (dir == A2B) {
1475 thisdir = &ptp_save->a2b;
1476 otherdir = &ptp_save->b2a;
1477 } else {
1478 thisdir = &ptp_save->b2a;
1479 otherdir = &ptp_save->a2b;
1480 }
1481
1482 /* meta connection stats */
1483 if (SYN_SET(ptcp))
1484 ++thisdir->syn_count;
1485 if (RESET_SET(ptcp))
1486 ++thisdir->reset_count;
1487 if (FIN_SET(ptcp))
1488 ++thisdir->fin_count;
1489
1490 /* end bug fix */
1491
1492
1493 /* compute the "effective window", which is the advertised window */
1494 /* with scaling */
1495 if (ACK_SET(ptcp) || SYN_SET(ptcp)) {
1496 eff_win = (u_long) th_win;
1497
1498 /* N.B., the window_scale stored for the connection DURING 3way */
1499 /* handshaking is the REQUESTED scale. It's only valid if both */
1500 /* sides request scaling. AFTER we've seen both SYNs, that field */
1501 /* is reset (above) to contain zero. Note that if we */
1502 /* DIDN'T see the SYNs, the windows will be off. */
1503 /* Jamshid: Remember that the window is never scaled in SYN */
1504 /* packets, as per RFC 1323. */
1505 if (thisdir->f1323_ws && otherdir->f1323_ws && !SYN_SET(ptcp))
1506 eff_win <<= thisdir->window_scale;
1507 } else {
1508 eff_win = 0;
1509 }
1510
1511
1512 /* idle-time stats */
1513 if (!ZERO_TIME(&thisdir->last_time)) {
1514 u_llong itime = elapsed(thisdir->last_time,current_time);
1515 if (itime > thisdir->idle_max)
1516 thisdir->idle_max = itime;
1517 }
1518 thisdir->last_time = current_time;
1519
1520
1521 /* calculate data length */
1522 tcp_length = getpayloadlength(pip, plast);
1523 tcp_data_length = tcp_length - (4 * TH_OFF(ptcp));
1524
1525 /* calc. data range */
1526 start = th_seq;
1527 end = start + tcp_data_length;
1528
1529 /* seq. space wrap around stats */
1530 /* If all four quadrants have been visited and the current packet
1531 * is in the same quadrant as the syn, check if latest seq. num is
1532 * wrapping past the syn. If it is, increment wrap_count
1533 */
1534 if ((thisdir->quad1 && thisdir->quad2 && thisdir->quad3 && thisdir->quad4)) {
1535 if ((IN_Q1(thisdir->syn) && (IN_Q1(end))) || (IN_Q2(thisdir->syn) && (IN_Q2(end))) || ((IN_Q3(thisdir->syn) && (IN_Q3(end))) || ((IN_Q4(thisdir->syn) && (IN_Q4(end)))))) {
1536 if (end >= thisdir->syn) {
1537 if (debug>1)
1538 fprintf(stderr, "\nWARNING : sequence space wrapped around here \n");
1539 thisdir->seq_wrap_count++;
1540 thisdir->quad1=0;
1541 thisdir->quad2=0;
1542 thisdir->quad3=0;
1543 thisdir->quad4=0;
1544 }
1545 }
1546 }
1547
1548 /* Mark the visited quadrants */
1549 if (!thisdir->quad1) {
1550 if (IN_Q1(start) || IN_Q1(end))
1551 thisdir->quad1=1;
1552 }
1553 if (!thisdir->quad2) {
1554 if (IN_Q2(start) || IN_Q2(end))
1555 thisdir->quad2=1;
1556 }
1557 if (!thisdir->quad3) {
1558 if (IN_Q3(start) || IN_Q3(end))
1559 thisdir->quad3=1;
1560 }
1561 if (!thisdir->quad4) {
1562 if (IN_Q4(start) || IN_Q4(end))
1563 thisdir->quad4=1;
1564 }
1565
1566 /* record sequence limits */
1567 if (SYN_SET(ptcp)) {
1568 /* error checking - better not change! */
1569 if ((thisdir->syn_count > 1) && (thisdir->syn != start)) {
1570 /* it changed, that shouldn't happen! */
1571 if (warn_printbad_syn_fin_seq)
1572 fprintf(stderr, "\
1573 %s->%s: rexmitted SYN had diff. seqnum! (was %lu, now %lu, etime: %d sec)\n",
1574 thisdir->host_letter,thisdir->ptwin->host_letter,
1575 thisdir->syn, start,
1576 (int)(elapsed(ptp_save->first_time,current_time)/1000000));
1577 thisdir->bad_behavior = TRUE;
1578 }
1579 thisdir->syn = start;
1580 otherdir->ack = start;
1581 /* bug fix for Rob Austein <sra@epilogue.com> */
1582 }
1583 if (FIN_SET(ptcp)) {
1584 /* bug fix, if there's data here too, we need to bump up the FIN */
1585 /* (psc data file shows example) */
1586 u_long fin = start + tcp_data_length;
1587 /* error checking - better not change! */
1588 if ((thisdir->fin_count > 1) && (thisdir->fin != fin)) {
1589 /* it changed, that shouldn't happen! */
1590 if (warn_printbad_syn_fin_seq)
1591 fprintf(stderr, "\
1592 %s->%s: rexmitted FIN had diff. seqnum! (was %lu, now %lu, etime: %d sec)\n",
1593 thisdir->host_letter,thisdir->ptwin->host_letter,
1594 thisdir->fin, fin,
1595 (int)(elapsed(ptp_save->first_time,current_time)/1000000));
1596 thisdir->bad_behavior = TRUE;
1597 }
1598 thisdir->fin = fin;
1599 }
1600
1601 /* "ONLY" bug fix - Wed Feb 24, 1999 */
1602 /* the tcp-splicing heuristic needs "windowend", which was only being */
1603 /* calculated BELOW the "only" point below. Move that part of the */
1604 /* calculation up here! */
1605
1606 /* remember the OLD window end for graphing */
1607 /* (bug fix - Thu Aug 12, 1999) */
1608 old_this_windowend = thisdir->windowend;
1609
1610 if (ACK_SET(ptcp)) {
1611 thisdir->windowend = th_ack + eff_win;
1612 }
1613 /* end bugfix */
1614
1615
1616
1617 /***********************************************************************/
1618 /***********************************************************************/
1619 /* if we're ignoring this connection, do no further processing */
1620 /***********************************************************************/
1621 /***********************************************************************/
1622 if (ptp_save->ignore_pair) {
1623 return(ptp_save);
1624 }
1625
1626 /* save to a file if requested */
1627 if (output_filename) {
1628 PcapSavePacket(output_filename,pip,plast);
1629 }
1630
1631 /* now, print it if requested */
1632 if (printem && !printallofem) {
1633 printf("Packet %lu\n", pnum);
1634 printpacket(0, /* original length not available */
1635 (char *)plast - (char *)pip + 1,
1636 NULL,0, /* physical stuff not known here */
1637 pip,plast,thisdir);
1638 }
1639
1640 /* grab the address from this packet */
1641 CopyAddr(&tp_in.addr_pair, pip,
1642 th_sport, th_dport);
1643
1644
1645 /* simple bookkeeping */
1646 if (PIP_ISV6(pip)) {
1647 ++thisdir->ipv6_segments;
1648 }
1649
1650
1651 /* plotter shorthand */
1652 to_tsgpl = otherdir->tsg_plotter;
1653 from_tsgpl = thisdir->tsg_plotter;
1654
1655 /* plotter shorthand (NOTE: we are using one plotter for both directions) */
1656 tlinepl = thisdir->tline_plotter;
1657
1658 /* check the options */
1659 ptcpo = ParseOptions(ptcp,plast);
1660 if (ptcpo->mss != -1)
1661 thisdir->mss = ptcpo->mss;
1662 if (ptcpo->ws != -1) {
1663 thisdir->window_scale = ptcpo->ws;
1664 thisdir->f1323_ws = TRUE;
1665 }
1666 if (ptcpo->tsval != -1) {
1667 thisdir->f1323_ts = TRUE;
1668 }
1669 /* NOW, unless BOTH sides asked for window scaling in their SYN */
1670 /* segments, we aren't using window scaling */
1671 if (!SYN_SET(ptcp) &&
1672 ((!thisdir->f1323_ws) || (!otherdir->f1323_ws))) {
1673 thisdir->window_scale = otherdir->window_scale = 0;
1674 }
1675
1676 /* check sacks */
1677 if (ptcpo->sack_req) {
1678 thisdir->fsack_req = 1;
1679 }
1680 if (ptcpo->sack_count > 0) {
1681 ++thisdir->sacks_sent;
1682 }
1683
1684 /* unless both sides advertised sack, we shouldn't see them, otherwise
1685 we hope they actually send them */
1686 if (!SYN_SET(ptcp) && (thisdir->fsack_req && otherdir->fsack_req)) {
1687 thisdir->tcp_strain = otherdir->tcp_strain = TCP_SACK;
1688 }
1689
1690 /* do data stats */
1691 urg = FALSE;
1692 if (tcp_data_length > 0) {
1693 thisdir->data_pkts += 1;
1694 if (PUSH_SET(ptcp))
1695 thisdir->data_pkts_push += 1;
1696 thisdir->data_bytes += tcp_data_length;
1697 if (URGENT_SET(ptcp)) { /* Checking if URGENT bit is set */
1698 urg = TRUE;
1699 thisdir->urg_data_pkts += 1;
1700 thisdir->urg_data_bytes += th_urp;
1701 }
1702 if (tcp_data_length > thisdir->max_seg_size)
1703 thisdir->max_seg_size = tcp_data_length;
1704 if ((thisdir->min_seg_size == 0) ||
1705 (tcp_data_length < thisdir->min_seg_size))
1706 thisdir->min_seg_size = tcp_data_length;
1707 /* record first and last times for data (Mallman) */
1708 if (ZERO_TIME(&thisdir->first_data_time))
1709 thisdir->first_data_time = current_time;
1710 thisdir->last_data_time = current_time;
1711 }
1712
1713 /* total packets stats */
1714 ++ptp_save->packets;
1715 ++thisdir->packets;
1716
1717 /* If we are using window scaling, update the win_scaled_pkts counter */
1718 if (thisdir->window_stats_updated_for_scaling)
1719 ++thisdir->win_scaled_pkts;
1720
1721 /* instantaneous throughput stats */
1722 if (graph_tput) {
1723 DoThru(thisdir,tcp_data_length);
1724 }
1725
1726 /* segment size graphs */
1727 if ((tcp_data_length > 0) && (thisdir->segsize_plotter != NO_PLOTTER)) {
1728 extend_line(thisdir->segsize_line, current_time, tcp_data_length);
1729 extend_line(thisdir->segsize_avg_line, current_time,
1730 thisdir->data_bytes / thisdir->data_pkts);
1731 }
1732
1733 /* sequence number stats */
1734 if ((thisdir->min_seq == 0) && (start != 0)) {
1735 thisdir->min_seq = start; /* first byte in this segment */
1736 thisdir->max_seq = end; /* last byte in this segment */
1737 }
1738 if (SEQ_GREATERTHAN (end,thisdir->max_seq)) {
1739 thisdir->max_seq = end;
1740 }
1741 thisdir->latest_seq = end;
1742
1743
1744 /* check for hardware duplicates */
1745 /* only works for IPv4, IPv6 has no mandatory ID field */
1746 if (PIP_ISV4(pip) && docheck_hw_dups)
1747 hw_dup = check_hw_dups(pip->ip_id, th_seq, thisdir);
1748
1749
1750 /* Kevin Lahey's ECN code */
1751 /* only works for IPv4 */
1752 if (PIP_ISV4(pip)) {
1753 ecn_ce = IP_ECT(pip) && IP_CE(pip);
1754 }
1755 cwr = CWR_SET(ptcp);
1756 ecn_echo = ECN_ECHO_SET(ptcp);
1757
1758 /* save the stream contents, if requested */
1759 if (tcp_data_length > 0) {
1760 u_char *pdata = (u_char *)ptcp + TH_OFF(ptcp)*4;
1761 u_long saved;
1762 u_long missing;
1763
1764 saved = tcp_data_length;
1765 if ((char *)pdata + tcp_data_length > ((char *)plast+1))
1766 saved = (char *)plast - (char *)pdata + 1;
1767
1768 /* see what's missing */
1769 missing = tcp_data_length - saved;
1770 if (missing > 0) {
1771 thisdir->trunc_bytes += missing;
1772 ++thisdir->trunc_segs;
1773 }
1774
1775 if (save_tcp_data)
1776 ExtractContents(start,tcp_data_length,saved,pdata,thisdir);
1777 }
1778
1779 /* do rexmit stats */
1780 retrans = FALSE;
1781 probe = FALSE;
1782 out_order = FALSE;
1783 retrans_num_bytes = 0;
1784 if (SYN_SET(ptcp) || FIN_SET(ptcp) || tcp_data_length > 0) {
1785 int len = tcp_data_length;
1786 int retrans_cnt=0;
1787
1788 if (SYN_SET(ptcp)) ++len;
1789 if (FIN_SET(ptcp)) ++len;
1790
1791
1792 /* Don't consider for rexmit, if the send window is 0 */
1793 /* We are probably doing window probing.. */
1794 /* Patch from Ulisses Alonso Camaro : Not treat the SYN segments
1795 * as probes, even though a zero window was advertised from the
1796 * opposite direction */
1797 if( (otherdir->win_last==0) && (otherdir->packets > 0) &&
1798 /* Patch from Ulisses Alonso Camaro : Not treat the SYN segments
1799 * as probes, even though a zero window was advertised from the
1800 * opposite direction */
1801 (!SYN_SET(ptcp)) ) {
1802 probe=TRUE;
1803 thisdir->num_zwnd_probes++;
1804 thisdir->zwnd_probe_bytes += tcp_data_length;
1805 }
1806 else
1807 retrans_cnt = retrans_num_bytes = rexmit(thisdir,start, len, &out_order);
1808
1809 if (out_order)
1810 ++thisdir->out_order_pkts;
1811
1812 /* count anything NOT retransmitted as "unique" */
1813 /* exclude SYN and FIN */
1814 if (SYN_SET(ptcp)) {
1815 /* don't count the SYN as data */
1816 --len;
1817 /* if the SYN was rexmitted, then don't count it */
1818 if (thisdir->syn_count > 1)
1819 --retrans_cnt;
1820 }
1821 if (FIN_SET(ptcp)) {
1822 /* don't count the FIN as data */
1823 --len;
1824 /* if the FIN was rexmitted, then don't count it */
1825 if (thisdir->fin_count > 1)
1826 --retrans_cnt;
1827 }
1828 if (!probe){
1829 if(retrans_cnt < len)
1830 thisdir->unique_bytes += (len - retrans_cnt);
1831 }
1832 }
1833
1834
1835 /* do rtt stats */
1836 if (ACK_SET(ptcp)) {
1837 ack_type = ack_in(otherdir,th_ack,tcp_data_length,eff_win,0);
1838
1839 #ifdef EXPERIMENTAL_ONLY
1840 /* check first SACK block too to see if there's good rtt info in it */
1841 if (ptcpo->sack_count > 0) {
1842 tcp_seq sack = ptcpo->sacks[0].sack_right;
1843 if (sack > th_ack) {
1844 /* NOT a dsack, so this is ACKing new data */
1845 (void) ack_in(otherdir,sack,tcp_data_length,eff_win,1);
1846 }
1847 }
1848 #endif
1849
1850
1851 if ( (th_ack == (otherdir->syn+1)) &&
1852 (otherdir->syn_count == 1) )
1853 otherdir->rtt_3WHS=otherdir->rtt_last;
1854 /* otherdir->rtt_last was set in the call to ack_in() */
1855
1856 otherdir->lastackno = th_ack;
1857 }
1858
1859 /* LEAST */
1860 if (thisdir->tcp_strain == TCP_RENO) {
1861 if (thisdir->in_rto && tcp_data_length > 0) {
1862 if (retrans_num_bytes>0 && th_seq < thisdir->recovered)
1863 thisdir->event_retrans++;
1864 if (IsRTO(thisdir, th_seq)) {
1865 thisdir->recovered = thisdir->recovered_orig = thisdir->seq;
1866 thisdir->rto_segment = th_seq;
1867 }
1868 if (!(retrans_num_bytes>0) && thisdir->ack <= thisdir->recovered_orig)
1869 thisdir->recovered = th_seq;
1870 }
1871 if (otherdir->in_rto && ACK_SET(ptcp)) {
1872 if (th_ack > otherdir->recovered) {
1873 otherdir->LEAST -=
1874 (otherdir->event_dupacks < otherdir->event_retrans)?
1875 otherdir->event_dupacks:otherdir->event_retrans;
1876 otherdir->in_rto = FALSE;
1877 } else if (th_ack == otherdir->lastackno &&
1878 th_ack >= otherdir->rto_segment) otherdir->event_dupacks++;
1879 }
1880 }
1881
1882 /* plot out-of-order segments, if asked */
1883 if (out_order && (from_tsgpl != NO_PLOTTER) && show_out_order) {
1884 plotter_perm_color(from_tsgpl, out_order_color);
1885 plotter_text(from_tsgpl, current_time, SeqRep(thisdir,end),
1886 "a", "O");
1887 if (bottom_letters)
1888 plotter_text(from_tsgpl, current_time,
1889 SeqRep(thisdir,thisdir->min_seq)-1500,
1890 "c", "O");
1891 }
1892
1893 /* stats for rexmitted data */
1894 if (retrans_num_bytes>0) {
1895 retrans = TRUE;
1896 /* for reno LEAST estimate */
1897 if (thisdir->tcp_strain == TCP_RENO &&
1898 !thisdir->in_rto && IsRTO(thisdir, th_seq)) {
1899 thisdir->in_rto = TRUE;
1900 thisdir->recovered = thisdir->recovered_orig = thisdir->seq;
1901 thisdir->rto_segment = th_seq;
1902 thisdir->event_retrans = 1; thisdir->event_dupacks = 0;
1903 }
1904 thisdir->rexmit_pkts += 1;
1905 thisdir->LEAST++;
1906 thisdir->rexmit_bytes += retrans_num_bytes;
1907 /* don't color the SYNs and FINs, it's confusing, we'll do them */
1908 /* differently below... */
1909 if (!(FIN_SET(ptcp)||SYN_SET(ptcp)) &&
1910 from_tsgpl != NO_PLOTTER && show_rexmit) {
1911 plotter_perm_color(from_tsgpl, retrans_color);
1912 plotter_text(from_tsgpl, current_time, SeqRep(thisdir,end),
1913 "a", hw_dup?"HD":"R");
1914 if (bottom_letters)
1915 plotter_text(from_tsgpl, current_time,
1916 SeqRep(thisdir,thisdir->min_seq)-1500,
1917 "c", hw_dup?"HD":"R");
1918 }
1919 } else {
1920 thisdir->seq = end;
1921 }
1922
1923 if(probe) {
1924 if(from_tsgpl != NO_PLOTTER && show_zwnd_probes){
1925 plotter_perm_color(from_tsgpl,probe_color);
1926 plotter_text(from_tsgpl,current_time,SeqRep (thisdir,end),
1927 "b", "P");
1928 }
1929 }
1930
1931 /* draw the packet */
1932 if (from_tsgpl != NO_PLOTTER) {
1933 plotter_perm_color(from_tsgpl, data_color);
1934 if (SYN_SET(ptcp)) { /* SYN */
1935 /* if we're using time offsets from zero, it's easier if */
1936 /* both graphs (a2b and b2a) start at the same point. That */
1937 /* will only happen if the "left-most" graphic is in the */
1938 /* same place in both. To make sure, mark the SYNs */
1939 /* as a green dot in the other direction */
1940 if (ACK_SET(ptcp)) {
1941 plotter_temp_color(from_tsgpl, ack_color);
1942 plotter_dot(from_tsgpl,
1943 ptp_save->first_time, SeqRep(thisdir,start));
1944 }
1945 plotter_perm_color(from_tsgpl,
1946 hw_dup?hw_dup_color:
1947 retrans_num_bytes>0?retrans_color:
1948 synfin_color);
1949 plotter_diamond(from_tsgpl, current_time, SeqRep(thisdir,start));
1950 plotter_text(from_tsgpl, current_time,
1951 SeqRep(thisdir,start+1), "a",
1952 hw_dup?"HD SYN":
1953 retrans_num_bytes>0?"R SYN":
1954 "SYN");
1955 plotter_uarrow(from_tsgpl, current_time, SeqRep(thisdir,start+1));
1956 plotter_line(from_tsgpl,
1957 current_time, SeqRep(thisdir,start),
1958 current_time, SeqRep(thisdir,start+1));
1959 } else if (FIN_SET(ptcp)) { /* FIN */
1960 /* Wed Sep 18, 2002 - bugfix
1961 * Check if data is present in the last packet.
1962 * We will draw the data bytes with the normal color
1963 * and then change the color for the last byte of FIN.
1964 */
1965 if(tcp_data_length > 0) { /* DATA + FIN */
1966 /* Data - default color */
1967 plotter_darrow(from_tsgpl, current_time, SeqRep(thisdir,start));
1968 plotter_line(from_tsgpl,
1969 current_time, SeqRep(thisdir,start),
1970 current_time, SeqRep(thisdir,end));
1971 /* FIN - synfin color */
1972 plotter_perm_color(from_tsgpl,
1973 hw_dup?hw_dup_color:
1974 retrans_num_bytes>0?retrans_color:
1975 synfin_color);
1976 }
1977 else { /* Only FIN */
1978 /* FIN - synfin color */
1979 plotter_perm_color(from_tsgpl,
1980 hw_dup?hw_dup_color:
1981 retrans_num_bytes>0?retrans_color:
1982 synfin_color);
1983 plotter_darrow(from_tsgpl, current_time, SeqRep(thisdir,end));
1984 }
1985 plotter_line(from_tsgpl,
1986 current_time, SeqRep(thisdir,end),
1987 current_time, SeqRep(thisdir,end+1));
1988 plotter_box(from_tsgpl, current_time, SeqRep(thisdir,end+1));
1989 plotter_text(from_tsgpl, current_time,
1990 SeqRep(thisdir,end+1), "a",
1991 hw_dup?"HD FIN":
1992 retrans_num_bytes>0?"R FIN":
1993 "FIN");
1994
1995 } else if (tcp_data_length > 0) { /* DATA */
1996 if (hw_dup) {
1997 plotter_perm_color(from_tsgpl, hw_dup_color);
1998 } else if (retrans) {
1999 plotter_perm_color(from_tsgpl, retrans_color);
2000 }
2001 plotter_darrow(from_tsgpl, current_time, SeqRep(thisdir,start));
2002 if (PUSH_SET(ptcp)) {
2003 /* colored diamond is PUSH */
2004 plotter_temp_color(from_tsgpl, push_color);
2005 plotter_diamond(from_tsgpl,
2006 current_time, SeqRep(thisdir,end));
2007 plotter_temp_color(from_tsgpl, push_color);
2008 plotter_dot(from_tsgpl, current_time, SeqRep(thisdir,end));
2009 } else {
2010 plotter_uarrow(from_tsgpl, current_time, SeqRep(thisdir,end));
2011 }
2012 plotter_line(from_tsgpl,
2013 current_time, SeqRep(thisdir,start),
2014 current_time, SeqRep(thisdir,end));
2015 } else if (tcp_data_length == 0) {
2016 /* for Brian Utterback */
2017 if (graph_zero_len_pkts) {
2018 /* draw zero-length packets */
2019 /* shows up as an X, really two arrow heads */
2020 plotter_darrow(from_tsgpl,
2021 current_time, SeqRep(thisdir,start));
2022 plotter_uarrow(from_tsgpl,
2023 current_time, SeqRep(thisdir,start));
2024 }
2025 }
2026
2027 /* Kevin Lahey's code */
2028 /* XXX: can this overwrite other labels!? */
2029 if (cwr || ecn_ce) {
2030 plotter_perm_color(from_tsgpl, ecn_color);
2031 plotter_diamond(from_tsgpl,
2032 current_time, SeqRep(thisdir,start));
2033 plotter_text(from_tsgpl, current_time, SeqRep(thisdir, start), "a",
2034 cwr ? (ecn_ce ? "CWR CE" : "CWR") : "CE");
2035 }
2036
2037 }
2038
2039 /* Plotting URGENT data */
2040 if(urg) {
2041 if(from_tsgpl != NO_PLOTTER && show_urg){
2042 plotter_perm_color(from_tsgpl,urg_color);
2043 plotter_text(from_tsgpl,current_time,SeqRep (thisdir,end),
2044 "a", "U");
2045 }
2046 }
2047
2048 /* graph time line */
2049 /* Since the axis types have been switched specially for these graphs,
2050 * x is actually used as y and y as x
2051 * -Avinash.
2052 *
2053 * NOTE: This code is lacking about a 1000 lines of intellegence that is needed
2054 * ----- to draw these graphs correctly. I have left it in here as the starting
2055 * point to work on. Whoever is working on this project would want to clean
2056 * up this file trace.c (based on the patches in the README.tline_graphs
2057 * file), and continue development as a seperate module. We started this
2058 * project thinking it is easy to draw these graphs, and then realized that
2059 * it is infact quite a complicated task. All this works with a -L option at
2060 * command line.
2061 */
2062 if (tlinepl != NO_PLOTTER) {
2063 char buf1[200];
2064 char buf2[50];
2065 static seqnum a2b_first_seqnum = 0;
2066 static seqnum b2a_first_seqnum = 0;
2067 /* 1/3rd rtt. Since we have the timestamps only on one side, we calculate the
2068 * arrrival/departure time of the segments on the other side by adding/subtracting
2069 * 1/3rd rtt. We assume that it takes 1/3rd time for the segment to travel in
2070 * either direction, and 1/3rd time for processing.
2071 * We also skew the calculated times so that the acks are not seen before the
2072 * segments actually arrive.
2073 */
2074 struct timeval one3rd_rtt;
2075 struct timeval copy_current_time;
2076 /* Make a copy of the current time (Needed for calculations) */
2077 copy_current_time.tv_sec = current_time.tv_sec;
2078 copy_current_time.tv_usec = current_time.tv_usec;
2079 /* Compute 1/3rd rtt */
2080 one3rd_rtt.tv_sec = 0;
2081 one3rd_rtt.tv_usec = thisdir->rtt_last/3;
2082 /* Adjust seconds and microseconds */
2083 while(one3rd_rtt.tv_usec >= US_PER_SEC) {
2084 one3rd_rtt.tv_usec -= US_PER_SEC;
2085 one3rd_rtt.tv_sec += 1;
2086 }
2087
2088 /* Initializations */
2089 memset(&buf1, 0, sizeof(buf1));
2090 memset(&buf2, 0, sizeof(buf2));
2091
2092 /* Segment information */
2093 /* Check the flags */
2094 if(SYN_SET(ptcp))
2095 strncat(buf1, "SYN ", 4);
2096 if(FIN_SET(ptcp))
2097 strncat(buf1, "FIN ", 4);
2098 if(RESET_SET(ptcp))
2099 strncat(buf1, "RST ", 4);
2100 if(PUSH_SET(ptcp))
2101 strncat(buf1, "PSH ", 4);
2102 if(URGENT_SET(ptcp))
2103 strncat(buf1, "URG ", 4);
2104
2105
2106 /* Write the sequence numbers */
2107 if(dir == A2B) {
2108 /* Use relative sequence numbers after the first segment in either direction */
2109 snprintf(buf2, sizeof(buf2), "%lu:%lu(%lu) ", (start - a2b_first_seqnum),
2110 (end - a2b_first_seqnum), (end-start));
2111 strncat(buf1, buf2, strlen(buf2));
2112 if(a2b_first_seqnum == 0 && !SYN_SET(ptcp)) // Don't use relative sequence numbers until handshake is complete.
2113 a2b_first_seqnum = thisdir->min_seq;
2114 }else if(dir == B2A) {
2115 /* Use relative sequence numbers after the first segment in either direction */
2116 snprintf(buf2, sizeof(buf2), "%lu:%lu(%lu) ", (start - b2a_first_seqnum),
2117 (end - b2a_first_seqnum), (end-start));
2118 strncat(buf1, buf2, strlen(buf2));
2119 if(b2a_first_seqnum == 0 && !SYN_SET(ptcp))
2120 b2a_first_seqnum = thisdir->min_seq;
2121 }
2122
2123 /* Acknowledgements */
2124 if(ACK_SET(ptcp)) {
2125 memset(&buf2, 0, sizeof(buf2));
2126 if(dir == A2B)
2127 snprintf(buf2, sizeof(buf2), "ack %lu ", (th_ack - b2a_first_seqnum));
2128 else if(dir == B2A)
2129 snprintf(buf2, sizeof(buf2), "ack %lu ", (th_ack - a2b_first_seqnum));
2130 strncat(buf1, buf2, strlen(buf2));
2131 }
2132
2133 /* Advertised Window */
2134 memset(&buf2, 0, sizeof(buf2));
2135 snprintf(buf2, sizeof(buf2), "win %lu ", eff_win);
2136 strncat(buf1, buf2, strlen(buf2));
2137
2138 /* Retransmits */
2139 if(retrans) {
2140 memset(&buf2, 0, sizeof(buf2));
2141 snprintf(buf2, sizeof(buf2), "R ");
2142 strncat(buf1, buf2, strlen(buf2));
2143 }
2144
2145 /* Hardware Duplicates */
2146 if(hw_dup) {
2147 memset(&buf2, 0, sizeof(buf2));
2148 snprintf(buf2, sizeof(buf2), "HD ");
2149 strncat(buf1, buf2, strlen(buf2));
2150 }
2151
2152 /* Draw the segment ------>/<------- */
2153 if(dir == A2B) {
2154 tv_add(©_current_time, one3rd_rtt);
2155 plotter_line(tlinepl, ptp_save->first_time, tline_left, copy_current_time, tline_left);
2156 plotter_line(tlinepl, ptp_save->first_time, tline_right, copy_current_time, tline_right);
2157 if(SYN_SET(ptcp)|| FIN_SET(ptcp) || RESET_SET(ptcp))
2158 plotter_perm_color(tlinepl, synfin_color);
2159 else
2160 plotter_perm_color(tlinepl, a2b_seg_color);
2161 plotter_line(tlinepl, current_time, tline_left, copy_current_time, tline_right);
2162 plotter_rarrow(tlinepl, copy_current_time, tline_right);
2163 plotter_perm_color(tlinepl, default_color);
2164 plotter_text(tlinepl, current_time, tline_left, "l", buf1);
2165 }
2166 else if(dir == B2A) {
2167 tv_sub(©_current_time, one3rd_rtt);
2168 plotter_line(tlinepl, ptp_save->first_time, tline_left, copy_current_time, tline_left);
2169 plotter_line(tlinepl, ptp_save->first_time, tline_right, copy_current_time, tline_right);
2170 if(SYN_SET(ptcp)|| FIN_SET(ptcp) || RESET_SET(ptcp))
2171 plotter_perm_color(tlinepl, synfin_color);
2172 else
2173 plotter_perm_color(tlinepl, b2a_seg_color);
2174 plotter_line(tlinepl, copy_current_time, tline_right, current_time, tline_left);
2175 plotter_larrow(tlinepl, current_time, tline_left);
2176 plotter_perm_color(tlinepl, default_color);
2177 plotter_text(tlinepl, copy_current_time, tline_right, "r", buf1);
2178 }
2179
2180 }
2181
2182
2183 /* check for RESET */
2184 if (RESET_SET(ptcp)) {
2185 u_long plot_at;
2186
2187 /* if there's an ACK in this packet, plot it there */
2188 /* otherwise, plot it at the last valid ACK we have */
2189 if (ACK_SET(ptcp))
2190 plot_at = th_ack;
2191 else
2192 plot_at = thisdir->ack;
2193
2194 if (to_tsgpl != NO_PLOTTER) {
2195 plotter_temp_color(to_tsgpl, text_color);
2196 plotter_text(to_tsgpl,
2197 current_time, SeqRep(otherdir,plot_at),
2198 "a", "RST_IN");
2199 }
2200 if (from_tsgpl != NO_PLOTTER) {
2201 plotter_temp_color(from_tsgpl, text_color);
2202 plotter_text(from_tsgpl,
2203 current_time, SeqRep(thisdir,start),
2204 "a", "RST_OUT");
2205 }
2206 if (ACK_SET(ptcp))
2207 ++thisdir->ack_pkts;
2208
2209 if (run_continuously) {
2210 UpdateConnLists(tcp_ptr, ptcp);
2211 }
2212 return(ptp_save);
2213 }
2214
2215 /* do window stats (include first SYN too!) */
2216 thisdir->win_last=eff_win;
2217
2218 if (ACK_SET(ptcp) || SYN_SET(ptcp)) {
2219 if (eff_win > thisdir->win_max)
2220 thisdir->win_max = eff_win;
2221
2222 /* If we *are* going to use window scaling,
2223 * i.e., if we saw both SYN segments of the connection requesting
2224 * window scaling, we flush out all the window stats we gathered till
2225 * now from the SYN segments.
2226 *
2227 * o We set the flag window_stats_updated_for_scaling to TRUE
2228 * o Set win_min and win_max to the value found in this first
2229 * window-scaled segment
2230 * o Reset win_tot value too, as this is used to calculate the
2231 * average window advertisement seen in this direction at the end
2232 * o We also use the field win_scaled_pkts for this purpose, so that
2233 * in the end we calculate
2234 *
2235 * avg_win_adv = win_tot/win_scaled_pkts // Refer output.c
2236 *
2237 * Note : for a connection that doesn't use window scaling,
2238 *
2239 * avg_win_adv = win_tot/packets // Refer again to output.c
2240 */
2241
2242 if ( (eff_win>0) &&
2243 ( thisdir->f1323_ws && otherdir->f1323_ws && !SYN_SET(ptcp) &&
2244 !thisdir->window_stats_updated_for_scaling
2245 )
2246 ) {
2247 thisdir->window_stats_updated_for_scaling=TRUE;
2248 thisdir->win_min = thisdir->win_max = eff_win;
2249 thisdir->win_tot = 0;
2250 thisdir->win_scaled_pkts = 1;
2251 }
2252 else if ((eff_win > 0) &&
2253 ((thisdir->win_min == 0) ||
2254 (eff_win < thisdir->win_min)))
2255 thisdir->win_min = eff_win;
2256
2257 /* Add the window advertisement to win_tot */
2258 thisdir->win_tot += eff_win;
2259 }
2260
2261 /* draw the ack and win in the other plotter */
2262 if (ACK_SET(ptcp)) {
2263 seqnum ack = th_ack;
2264 u_long winend;
2265
2266 winend = ack + eff_win;
2267
2268 if (eff_win == 0) {
2269 ++thisdir->win_zero_ct;
2270 if (to_tsgpl != NO_PLOTTER && show_zero_window) {
2271 plotter_temp_color(to_tsgpl, text_color);
2272 plotter_text(to_tsgpl,
2273 current_time, SeqRep(otherdir,winend),
2274 "a", "Z");
2275 if (bottom_letters) {
2276 plotter_temp_color(to_tsgpl, text_color);
2277 plotter_text(to_tsgpl,
2278 current_time,
2279 SeqRep(otherdir,otherdir->min_seq)-1500,
2280 "a", "Z");
2281 }
2282 }
2283 }
2284
2285 ++thisdir->ack_pkts;
2286 if ((tcp_data_length == 0) &&
2287 !SYN_SET(ptcp) && !FIN_SET(ptcp) && !RESET_SET(ptcp)) {
2288 ++thisdir->pureack_pkts;
2289 }
2290
2291
2292 if (to_tsgpl != NO_PLOTTER && thisdir->time.tv_sec != -1) {
2293 plotter_perm_color(to_tsgpl, ack_color);
2294 plotter_line(to_tsgpl,
2295 thisdir->time, SeqRep(otherdir,thisdir->ack),
2296 current_time, SeqRep(otherdir,thisdir->ack));
2297 if (thisdir->ack != ack) {
2298 plotter_line(to_tsgpl,
2299 current_time, SeqRep(otherdir,thisdir->ack),
2300 current_time, SeqRep(otherdir,ack));
2301 if (show_rtt_dongles) {
2302 /* draw dongles for "interesting" acks */
2303 switch (ack_type) {
2304 case NORMAL: /* normal case */
2305 /* no dongle */
2306 break;
2307 case CUMUL: /* cumulative */
2308 /* won't happen, not plotted here */
2309 break;
2310 case TRIPLE: /* triple dupacks */
2311 /* won't happen, not plotted here */
2312 break;
2313 case AMBIG: /* ambiguous */
2314 plotter_temp_color(to_tsgpl, ackdongle_ambig_color);
2315 plotter_diamond(to_tsgpl, current_time,
2316 SeqRep(otherdir,ack));
2317 break;
2318 case NOSAMP: /* acks retransmitted stuff cumulatively */
2319 plotter_temp_color(to_tsgpl, ackdongle_nosample_color);
2320 plotter_diamond(to_tsgpl, current_time,
2321 SeqRep(otherdir,ack));
2322 break;
2323 }
2324 }
2325 } else {
2326 plotter_dtick(to_tsgpl, current_time, SeqRep(otherdir,ack));
2327 if (show_triple_dupack && (ack_type == TRIPLE)) {
2328 plotter_text(to_tsgpl, current_time,
2329 SeqRep(otherdir,ack),
2330 "a", "3"); /* '3' is for triple dupack */
2331 }
2332 }
2333
2334 /* Kevin Lahey's code */
2335 if (ecn_echo && !SYN_SET(ptcp)) {
2336 plotter_perm_color(to_tsgpl, ecn_color);
2337 plotter_diamond(to_tsgpl, current_time, SeqRep(otherdir, ack));
2338 }
2339
2340 plotter_perm_color(to_tsgpl, window_color);
2341 plotter_line(to_tsgpl,
2342 thisdir->time, SeqRep(otherdir,old_this_windowend),
2343 current_time, SeqRep(otherdir,old_this_windowend));
2344 if (old_this_windowend != winend) {
2345 plotter_line(to_tsgpl,
2346 current_time, SeqRep(otherdir,old_this_windowend),
2347 current_time, SeqRep(otherdir,winend));
2348 } else {
2349 plotter_utick(to_tsgpl, current_time, SeqRep(otherdir,winend));
2350 }
2351 }
2352
2353 /* track the most sack blocks in a single ack */
2354 if (ptcpo->sack_count > 0) {
2355 ++thisdir->num_sacks;
2356 if (ptcpo->sack_count > thisdir->max_sack_blocks)
2357 thisdir->max_sack_blocks = ptcpo->sack_count;
2358
2359 /* also see if any of them are DSACKS - weddy */
2360 /* eventually may come back and fix this, what if we+++++
2361 didn't see all the rexmits and so LEAST wesn't set
2362 high enough, now it's too low */
2363 /* case 1, first block under cumack */
2364 if (ptcpo->sacks[0].sack_right <= th_ack) {
2365 thisdir->num_dsacks++;
2366 if (otherdir->LEAST > 0) otherdir->LEAST--;
2367 /* case 2, first block inside second */
2368 } else if (ptcpo->sack_count > 1) {
2369 if (ptcpo->sacks[0].sack_right <= ptcpo->sacks[1].sack_right
2370 && ptcpo->sacks[0].sack_left >= ptcpo->sacks[1].sack_left)
2371 {
2372 thisdir->num_dsacks++;
2373 if (otherdir->LEAST > 0) otherdir->LEAST--;
2374 /* case 3, first and second block overlap */
2375 } else if ((ptcpo->sacks[0].sack_left <=
2376 ptcpo->sacks[1].sack_left &&
2377 ptcpo->sacks[0].sack_right >
2378 ptcpo->sacks[1].sack_left) ||
2379 (ptcpo->sacks[0].sack_right >=
2380 ptcpo->sacks[1].sack_right &&
2381 ptcpo->sacks[0].sack_left <
2382 ptcpo->sacks[1].sack_right)) {
2383 thisdir->num_dsacks++;
2384 if (otherdir->LEAST > 0) otherdir->LEAST--;
2385 }
2386 }
2387 /* if we saw any dsacks from the other guy, we'll assume he did
2388 it on purpose and is a dsack tcp */
2389 if (thisdir->num_dsacks > 0) thisdir->tcp_strain = TCP_DSACK;
2390 }
2391
2392 /* draw sacks, if appropriate */
2393 if (to_tsgpl != NO_PLOTTER && show_sacks
2394 && (ptcpo->sack_count > 0)) {
2395 int scount;
2396 seqnum sack_top = ptcpo->sacks[0].sack_right;
2397
2398 plotter_perm_color(to_tsgpl, sack_color);
2399 for (scount = 0; scount < ptcpo->sack_count; ++scount) {
2400 plotter_line(to_tsgpl,
2401 current_time,
2402 SeqRep(otherdir,ptcpo->sacks[scount].sack_left),
2403 current_time,
2404 SeqRep(otherdir,ptcpo->sacks[scount].sack_right));
2405 /* make it easier to read multiple sacks by making them look like
2406 |-----| (sideways)
2407 */
2408 plotter_htick(to_tsgpl,
2409 current_time,
2410 SeqRep(otherdir,ptcpo->sacks[scount].sack_left));
2411 plotter_htick(to_tsgpl,
2412 current_time,
2413 SeqRep(otherdir,ptcpo->sacks[scount].sack_right));
2414
2415 /* if there's more than one, label the order */
2416 /* purple number to the right of the top ("right" edge) */
2417 if (ptcpo->sack_count > 1) {
2418 char buf[5]; /* can't be more than 1 digit! */
2419 snprintf(buf,sizeof(buf),"%u",scount+1); /* 1-base, rather than 0-base */
2420 plotter_text(to_tsgpl,
2421 current_time,
2422 SeqRep(otherdir,ptcpo->sacks[scount].sack_right),
2423 "r", buf);
2424 }
2425
2426 /* maintain the highest SACK so we can label them all at once */
2427 if (SEQ_GREATERTHAN(ptcpo->sacks[scount].sack_right, sack_top))
2428 sack_top = ptcpo->sacks[scount].sack_right;
2429 }
2430 /* change - just draw the 'S' above the highest one */
2431 plotter_text(to_tsgpl, current_time,
2432 SeqRep(otherdir,sack_top),
2433 "a", "S"); /* 'S' is for Sack */
2434 }
2435 thisdir->time = current_time;
2436 thisdir->ack = ack;
2437
2438 /* thisdir->windowend = winend; (moved above "only" point) */
2439 } /* end ACK_SET(ptcp) */
2440
2441 /* do stats for initial window (first slow start) */
2442 /* (if there's data in this and we've NEVER seen */
2443 /* an ACK coming back from the other side) */
2444 /* this is for Mark Allman for slow start testing -- Mon Mar 10, 1997 */
2445 if (!otherdir->data_acked && ACK_SET(ptcp)
2446 && ((otherdir->syn+1) != th_ack)) {
2447 otherdir->data_acked = TRUE;
2448 }
2449 if ((tcp_data_length > 0) && (!thisdir->data_acked)) {
2450 if (!retrans) {
2451 /* don't count it if it was retransmitted */
2452 thisdir->initialwin_bytes += tcp_data_length;
2453 thisdir->initialwin_segs += 1;
2454 }
2455 }
2456
2457 /* do stats for congestion window (estimated) */
2458 /* estimate the congestion window as the number of outstanding */
2459 /* un-acked bytes */
2460 if (!SYN_SET(ptcp) && !out_order && !retrans) {
2461 u_long owin;
2462 /* If there has been no ack from the other direction, owin is just
2463 * bytes in this pkt.
2464 */
2465 if (otherdir->ack == 0){
2466 owin = end - start ;
2467 }
2468 else {
2469 /* ack always acks 'received + 1' bytes, so subtract 1
2470 * for owin */
2471 owin = end - (otherdir->ack - 1);
2472 }
2473
2474 if (owin > thisdir->owin_max)
2475 thisdir->owin_max = owin;
2476 if ((owin > 0) &&
2477 ((thisdir->owin_min == 0) ||
2478 (owin < thisdir->owin_min)))
2479 thisdir->owin_min = owin;
2480
2481 thisdir->owin_tot += owin;
2482 thisdir->owin_count++;
2483
2484 /* adding mark's suggestion of weighted owin */
2485 if (thisdir->previous_owin_sample_time.tv_sec == 0) {
2486 /* if this is first ever sample for thisdir */
2487 thisdir->previous_owin_sample_time = thisdir->last_time;
2488 thisdir->previous_owin_sample = owin;
2489 }
2490 else {
2491 /* weight each owin sample with the duration that it exists for */
2492 sample_elapsed_time = (elapsed(thisdir->previous_owin_sample_time, ptp_save->last_time))/1000000;
2493 total_elapsed_time = (elapsed(ptp_save->first_time, ptp_save->last_time))/1000000;
2494 thisdir->owin_wavg += (u_llong)((thisdir->previous_owin_sample) * sample_elapsed_time);
2495 /* graph owin_wavg */
2496 if (thisdir->owin_plotter != NO_PLOTTER) {
2497 extend_line(thisdir->owin_wavg_line, thisdir->previous_owin_sample_time,
2498 (total_elapsed_time)?((u_llong)((thisdir->owin_wavg)/total_elapsed_time)):0);
2499 }
2500 thisdir->previous_owin_sample_time = thisdir->last_time;
2501 thisdir->previous_owin_sample = owin;
2502 }
2503
2504 /* graph owin */
2505 if (thisdir->owin_plotter != NO_PLOTTER) {
2506 extend_line(thisdir->owin_line, current_time, owin);
2507 if (show_rwinline) {
2508 extend_line(thisdir->rwin_line, current_time,
2509 otherdir->win_last);
2510 }
2511 extend_line(thisdir->owin_avg_line, current_time,
2512 (thisdir->owin_count?(thisdir->owin_tot/thisdir->owin_count):0));
2513 }
2514
2515 /* add to rwin graph */
2516 if (thisdir->recvwin_plotter != NO_PLOTTER) {
2517 extend_line(thisdir->recvwin_line, current_time, otherdir->win_last);
2518 }
2519
2520 }
2521 if (run_continuously) {
2522 UpdateConnLists(tcp_ptr, ptcp);
2523 }
2524
2525 return(ptp_save);
2526 }
2527
2528
2529
2530 void
trace_done(void)2531 trace_done(void)
2532 {
2533 tcp_pair *ptp;
2534 FILE *f_passfilter = NULL;
2535 int ix;
2536 static int count = 0;
2537 Bool incomplete_pkt_capture = FALSE;
2538
2539 if (!run_continuously) {
2540 if (!printsuppress) {
2541 if (tcp_trace_count == 0) {
2542 fprintf(stdout,"%sno traced TCP packets\n", comment);
2543 return;
2544 } else {
2545 fprintf(stdout,"%sTCP connection info:\n", comment);
2546 }
2547 }
2548
2549 if (!printbrief)
2550 fprintf(stdout,"%s%d TCP %s traced:\n",
2551 comment,
2552 num_tcp_pairs + 1,
2553 num_tcp_pairs==0?"connection":"connections");
2554 if (ctrunc > 0) {
2555 fprintf(stdout,
2556 "%s*** %lu packets were too short to process at some point\n",
2557 comment,
2558 ctrunc);
2559 if (!warn_printtrunc)
2560 fprintf(stdout,"%s\t(use -w option to show details)\n", comment);
2561 }
2562
2563 /* generate statistics for data storage efficiency */
2564 if (debug>1) {
2565 int h;
2566 int occupied_buckets = 0;
2567 int max_bucket_occupancy = 0;
2568 int max_searches = 0;
2569 int max_depth = 0;
2570 int max_comparisons = 0;
2571 float max_searches_compare = 0.0;
2572 fprintf(stdout,"%sTotal searches: %u\n", comment, tcp_packet_count);
2573 fprintf(stdout,"%s Total comparisons: %u\n", comment, search_count);
2574 fprintf(stdout,"%s Average compares/search: %.2f\n",
2575 comment, (float)search_count / (float)tcp_packet_count);
2576 fprintf(stdout,"%sHash table size: %u\n", comment, HASH_TABLE_SIZE);
2577 for (h=0; h < HASH_TABLE_SIZE; ++h) {
2578 struct search_efficiency *pse = &hashtable_efficiency[h];
2579 float searches_compare;
2580 if (pse->num_connections > 0)
2581 ++occupied_buckets;
2582 if (pse->max_connections > max_bucket_occupancy)
2583 max_bucket_occupancy = pse->max_connections;
2584 if (pse->num_searches > max_searches)
2585 max_searches = pse->num_searches;
2586 if (pse->num_comparisons > max_comparisons)
2587 max_comparisons = pse->num_comparisons;
2588 if (pse->max_depth > max_depth)
2589 max_depth = pse->max_depth;
2590 searches_compare = (float) pse->num_comparisons / (float) pse->num_searches;
2591 if (searches_compare > max_searches_compare)
2592 max_searches_compare = searches_compare;
2593 }
2594 fprintf(stdout,"%s Occupied hash buckets: %u\n", comment, occupied_buckets);
2595 fprintf(stdout,"%s Max entries/bucket: %u\n", comment, max_bucket_occupancy);
2596 fprintf(stdout,"%s Max searches/bucket: %u\n", comment, max_searches);
2597 fprintf(stdout,"%s Max comparisons/bucket: %u\n", comment, max_comparisons);
2598 fprintf(stdout,"%s Max avg compares/search: %.2f\n", comment, max_searches_compare);
2599 fprintf(stdout,"%s Max tree depth: %u\n", comment, max_depth);
2600 }
2601
2602 /* complete the "idle time" calculations using NOW */
2603 for (ix = 0; ix <= num_tcp_pairs; ++ix) {
2604 tcp_pair *ptp = ttp[ix];
2605 tcb *thisdir;
2606 u_llong itime;
2607
2608 /* if it's CLOSED, skip it */
2609 if ((FinCount(ptp)>=2) || (ConnReset(ptp)))
2610 continue;
2611
2612 /* a2b direction */
2613 thisdir = &ptp->a2b;
2614 if (!ZERO_TIME(&thisdir->last_time)) {
2615 itime = elapsed(thisdir->last_time,current_time);
2616 if (itime > thisdir->idle_max)
2617 thisdir->idle_max = itime;
2618 }
2619
2620
2621 /* b2a direction */
2622 thisdir = &ptp->b2a;
2623 if (!ZERO_TIME(&thisdir->last_time)) {
2624 itime = elapsed(thisdir->last_time,current_time);
2625 if (itime > thisdir->idle_max)
2626 thisdir->idle_max = itime;
2627 }
2628 }
2629 }
2630
2631 /* if we're filtering, see which connections pass */
2632 if (filter_output || ignore_non_comp) {
2633
2634 /* file to dump matching connection numbers into */
2635 f_passfilter = fopen(PASS_FILTER_FILENAME,"w+");
2636 if (f_passfilter == NULL) {
2637 perror(PASS_FILTER_FILENAME);
2638 exit(-1);
2639 }
2640
2641 if (filter_output) {
2642 if (!run_continuously) {
2643 /* mark the connections to ignore */
2644 for (ix = 0; ix <= num_tcp_pairs; ++ix) {
2645 ptp = ttp[ix];
2646 if (PassesFilter(ptp)) {
2647 if (++count == 1)
2648 fprintf(f_passfilter,"%d", ix+1);
2649 else
2650 fprintf(f_passfilter,",%d", ix+1);
2651 } else {
2652 /* else ignore it */
2653 ptp->ignore_pair = TRUE;
2654 }
2655 }
2656 }
2657 }
2658 }
2659
2660 if (!run_continuously) {
2661 /* print each connection */
2662 if (!printsuppress) {
2663 Bool first = TRUE; /* Used with <SP>-separated-values
2664 * Keeps track of whether header has already
2665 * been printed */
2666 for (ix = 0; ix <= num_tcp_pairs; ++ix) {
2667 ptp = ttp[ix];
2668
2669 if (!ptp->ignore_pair) {
2670 if ((printbrief) && (!ignore_non_comp || ConnComplete(ptp))) {
2671 fprintf(stdout,"%3d: ", ix+1);
2672 PrintBrief(ptp);
2673 } else if (!ignore_non_comp || ConnComplete(ptp)) {
2674 if(csv || tsv || (sv != NULL)) {
2675 if(first) {
2676 PrintSVHeader();
2677 first = FALSE;
2678 }
2679 fprintf(stdout, "%d%s", ix+1, sp);
2680 }
2681 else {
2682 if (ix > 0)
2683 fprintf(stdout,"================================\n");
2684 fprintf(stdout,"TCP connection %d:\n", ix+1);
2685
2686 }
2687 PrintTrace(ptp);
2688 }
2689 /* This piece of code dumps PF file when filtered with '-c'
2690 option, this option says to select only complete connections.
2691 The PF file will contain the connection numbers which are
2692 selected to be complete */
2693 if (ignore_non_comp)
2694 if (ConnComplete(ptp)) {
2695 if (++count == 1)
2696 fprintf(f_passfilter, "%d", ix+1);
2697 else
2698 fprintf(f_passfilter, ",%d", ix+1);
2699 }
2700 /******************************/
2701
2702 /* If we are extracting packet contents (-e option), we shall check to
2703 * see if we missed segments during packet capture causing the
2704 * X2Y_contents.dat files that we drop to contain voids in them.
2705 * We shall emit a warning upon such an event below. */
2706 if (save_tcp_data && !incomplete_pkt_capture && MissingData(ptp))
2707 incomplete_pkt_capture = TRUE;
2708 }
2709 }
2710 }
2711 }
2712
2713 /* if we're filtering, close the file */
2714 if (filter_output || ignore_non_comp) {
2715 fprintf(f_passfilter,"\n");
2716 fclose(f_passfilter);
2717 }
2718
2719 if (incomplete_pkt_capture) {
2720 fprintf(stderr, "\nWarning : some extracted files are incomplete!\n");
2721 fprintf(stderr, " Please see -l output for more detail.\n");
2722 }
2723
2724 if ((debug>2) && !nonames)
2725 cadump();
2726 }
2727
2728 static void
MoreTcpPairs(int num_needed)2729 MoreTcpPairs(
2730 int num_needed)
2731 {
2732 int new_max_tcp_pairs;
2733 int i;
2734
2735 if (num_needed < max_tcp_pairs)
2736 return;
2737
2738 new_max_tcp_pairs = max_tcp_pairs * 4;
2739 while (new_max_tcp_pairs < num_needed)
2740 new_max_tcp_pairs *= 4;
2741
2742 if (debug)
2743 printf("trace: making more space for %d total TCP pairs\n",
2744 new_max_tcp_pairs);
2745
2746 /* enlarge array to hold any pairs that we might create */
2747 ttp = ReallocZ(ttp,
2748 max_tcp_pairs * sizeof(tcp_pair *),
2749 new_max_tcp_pairs * sizeof(tcp_pair *));
2750
2751 /* enlarge array to keep track of which ones to ignore */
2752 ignore_pairs = ReallocZ(ignore_pairs,
2753 max_tcp_pairs * sizeof(Bool),
2754 new_max_tcp_pairs * sizeof(Bool));
2755 if (more_conns_ignored)
2756 for (i=max_tcp_pairs; i < new_max_tcp_pairs;++i)
2757 ignore_pairs[i] = TRUE;
2758
2759 max_tcp_pairs = new_max_tcp_pairs;
2760 }
2761
2762
2763 void
trace_init(void)2764 trace_init(void)
2765 {
2766 static Bool initted = FALSE;
2767
2768 if (0) {
2769 printf("trace_init called\n");
2770 }
2771
2772 if (run_continuously) {
2773 if (ignore_pairs) {
2774 free(ignore_pairs);
2775 ignore_pairs = NULL;
2776 }
2777 if (ttp) {
2778 free(ttp);
2779 ttp = NULL;
2780 }
2781 more_conns_ignored = FALSE;
2782 }
2783
2784 if (initted)
2785 return;
2786
2787 initted = TRUE;
2788
2789 /* create an array to hold any pairs that we might create */
2790 ttp = (tcp_pair **) MallocZ(max_tcp_pairs * sizeof(tcp_pair *));
2791
2792 /* create an array to keep track of which ones to ignore */
2793 ignore_pairs = (Bool *) MallocZ(max_tcp_pairs * sizeof(Bool));
2794 if (!run_continuously) {
2795 /* create an array to hold any pairs that we might create */
2796 ttp = (tcp_pair **) MallocZ(max_tcp_pairs * sizeof(tcp_pair *));
2797
2798 /* create an array to keep track of which ones to ignore */
2799 ignore_pairs = (Bool *) MallocZ(max_tcp_pairs * sizeof(Bool));
2800 }
2801
2802 cainit();
2803 Minit();
2804 }
2805
2806
2807 void
IgnoreConn(int ix)2808 IgnoreConn(
2809 int ix)
2810 {
2811 if (debug) fprintf(stderr,"ignoring conn %d\n", ix);
2812
2813 // trace_init();
2814
2815 --ix;
2816
2817 MoreTcpPairs(ix);
2818
2819 more_conns_ignored = FALSE;
2820 ignore_pairs[ix] = TRUE;
2821 }
2822
2823
2824 void
OnlyConn(int ix_only)2825 OnlyConn(
2826 int ix_only)
2827 {
2828 int ix;
2829 static Bool cleared = FALSE;
2830
2831 if (debug) fprintf(stderr,"only printing conn %d\n", ix_only);
2832
2833 // trace_init();
2834
2835 --ix_only;
2836
2837 MoreTcpPairs(ix_only);
2838
2839 if (!cleared) {
2840 for (ix = 0; ix < max_tcp_pairs; ++ix) {
2841 ignore_pairs[ix] = TRUE;
2842 }
2843 cleared = TRUE;
2844 }
2845
2846 more_conns_ignored = TRUE;
2847 ignore_pairs[ix_only] = FALSE;
2848 }
2849
2850
2851 /* get a long (4 byte) option (to avoid address alignment problems) */
2852 static u_long
get_long_opt(void * ptr)2853 get_long_opt(
2854 void *ptr)
2855 {
2856 u_long l;
2857 memcpy(&l,ptr,sizeof(u_long));
2858 return(l);
2859 }
2860
2861
2862 /* get a short (2 byte) option (to avoid address alignment problems) */
2863 static u_short
get_short_opt(void * ptr)2864 get_short_opt(
2865 void *ptr)
2866 {
2867 u_short s;
2868 memcpy(&s,ptr,sizeof(u_short));
2869 return(s);
2870 }
2871
2872
2873 struct tcp_options *
ParseOptions(struct tcphdr * ptcp,void * plast)2874 ParseOptions(
2875 struct tcphdr *ptcp,
2876 void *plast)
2877 {
2878 static struct tcp_options tcpo;
2879 struct sack_block *psack;
2880 u_char *pdata;
2881 u_char *popt;
2882 u_char *plen;
2883
2884 popt = (u_char *)ptcp + sizeof(struct tcphdr);
2885 pdata = (u_char *)ptcp + TH_OFF(ptcp)*4;
2886
2887 /* init the options structure */
2888 memset(&tcpo,0,sizeof(tcpo));
2889 tcpo.mss = tcpo.ws = tcpo.tsval = tcpo.tsecr = -1;
2890 tcpo.sack_req = 0;
2891 tcpo.sack_count = -1;
2892 tcpo.echo_req = tcpo.echo_repl = -1;
2893 tcpo.cc = tcpo.ccnew = tcpo.ccecho = -1;
2894
2895 /* a quick sanity check, the unused (MBZ) bits must BZ! */
2896 if (warn_printbadmbz) {
2897 if (TH_X2(ptcp) != 0) {
2898 fprintf(stderr,
2899 "TCP packet %lu: 4 reserved bits are not zero (0x%01x)\n",
2900 pnum, TH_X2(ptcp));
2901 }
2902 if ((ptcp->th_flags & 0xc0) != 0) {
2903 fprintf(stderr,
2904 "TCP packet %lu: upper flag bits are not zero (0x%02x)\n",
2905 pnum, ptcp->th_flags);
2906 }
2907 } else {
2908 static int warned = 0;
2909 if (!warned &&
2910 ((TH_X2(ptcp) != 0) || ((ptcp->th_flags & 0xc0) != 0))) {
2911 warned = 1;
2912 fprintf(stderr, "\
2913 TCP packet %lu: reserved bits are not all zero. \n\
2914 \tFurther warnings disabled, use '-w' for more info\n",
2915 pnum);
2916 }
2917 }
2918
2919 /* looks good, now check each option in turn */
2920 while (popt < pdata) {
2921 plen = popt+1;
2922
2923 /* check for truncation error */
2924 if ((char *)popt > (char *)plast) {
2925 if (warn_printtrunc)
2926 fprintf(stderr,"\
2927 ParseOptions: packet %lu too short to parse remaining options\n", pnum);
2928 ++ctrunc;
2929 break;
2930 }
2931
2932 #define CHECK_O_LEN(opt) \
2933 if (*plen == 0) { \
2934 if (warn_printtrunc) fprintf(stderr, "\
2935 ParseOptions: packet %lu %s option has length 0, skipping other options\n", \
2936 pnum,opt); \
2937 popt = pdata; break;} \
2938 if ((char *)popt + *plen - 1 > (char *)(plast)) { \
2939 if (warn_printtrunc) \
2940 fprintf(stderr, "\
2941 ParseOptions: packet %lu %s option truncated, skipping other options\n", \
2942 pnum,opt); \
2943 ++ctrunc; \
2944 popt = pdata; break;} \
2945
2946
2947 switch (*popt) {
2948 case TCPOPT_EOL: ++popt; break;
2949 case TCPOPT_NOP: ++popt; break;
2950 case TCPOPT_MAXSEG:
2951 CHECK_O_LEN("TCPOPT_MAXSEG");
2952 tcpo.mss = ntohs(get_short_opt(popt+2));
2953 popt += *plen;
2954 break;
2955 case TCPOPT_WS:
2956 CHECK_O_LEN("TCPOPT_WS");
2957 tcpo.ws = *((u_char *)(popt+2));
2958 popt += *plen;
2959 break;
2960 case TCPOPT_TS:
2961 CHECK_O_LEN("TCPOPT_TS");
2962 tcpo.tsval = ntohl(get_long_opt(popt+2));
2963 tcpo.tsecr = ntohl(get_long_opt(popt+6));
2964 popt += *plen;
2965 break;
2966 case TCPOPT_ECHO:
2967 CHECK_O_LEN("TCPOPT_ECHO");
2968 tcpo.echo_req = ntohl(get_long_opt(popt+2));
2969 popt += *plen;
2970 break;
2971 case TCPOPT_ECHOREPLY:
2972 CHECK_O_LEN("TCPOPT_ECHOREPLY");
2973 tcpo.echo_repl = ntohl(get_long_opt(popt+2));
2974 popt += *plen;
2975 break;
2976 case TCPOPT_CC:
2977 CHECK_O_LEN("TCPOPT_CC");
2978 tcpo.cc = ntohl(get_long_opt(popt+2));
2979 popt += *plen;
2980 break;
2981 case TCPOPT_CCNEW:
2982 CHECK_O_LEN("TCPOPT_CCNEW");
2983 tcpo.ccnew = ntohl(get_long_opt(popt+2));
2984 popt += *plen;
2985 break;
2986 case TCPOPT_CCECHO:
2987 CHECK_O_LEN("TCPOPT_CCECHO");
2988 tcpo.ccecho = ntohl(get_long_opt(popt+2));
2989 popt += *plen;
2990 break;
2991 case TCPOPT_SACK_PERM:
2992 CHECK_O_LEN("TCPOPT_SACK_PERM");
2993 tcpo.sack_req = 1;
2994 popt += *plen;
2995 break;
2996 case TCPOPT_SACK:
2997 /* see which bytes are acked */
2998 CHECK_O_LEN("TCPOPT_SACK");
2999 tcpo.sack_count = 0;
3000 psack = (sack_block *)(popt+2); /* past the kind and length */
3001 popt += *plen;
3002 while ((char *)psack < (char *)popt) {
3003 struct sack_block *psack_local =
3004 &tcpo.sacks[(unsigned)tcpo.sack_count];
3005 /* warning, possible alignment problem here, so we'll
3006 use memcpy() and hope for the best */
3007 /* better use -fno-builtin to avoid gcc alignment error
3008 in GCC 2.7.2 */
3009 memcpy(psack_local, psack, sizeof(sack_block));
3010
3011 /* convert to local byte order (Jamshid Mahdavi) */
3012 psack_local->sack_left = ntohl(psack_local->sack_left);
3013 psack_local->sack_right = ntohl(psack_local->sack_right);
3014
3015 ++psack;
3016 if ((char *)psack > ((char *)plast+1)) {
3017 /* this SACK block isn't all here */
3018 if (warn_printtrunc)
3019 fprintf(stderr,
3020 "packet %lu: SACK block truncated\n",
3021 pnum);
3022 ++ctrunc;
3023 break;
3024 }
3025 ++tcpo.sack_count;
3026 if (tcpo.sack_count > MAX_SACKS) {
3027 /* this isn't supposed to be able to happen */
3028 fprintf(stderr,
3029 "Warning, internal error, too many sacks!!\n");
3030 tcpo.sack_count = MAX_SACKS;
3031 }
3032 }
3033 break;
3034 default:
3035 if (debug)
3036 fprintf(stderr,
3037 "Warning, ignoring unknown TCP option 0x%x\n",
3038 *popt);
3039 CHECK_O_LEN("TCPOPT_UNKNOWN");
3040
3041 /* record it anyway... */
3042 if (tcpo.unknown_count < MAX_UNKNOWN) {
3043 int ix = tcpo.unknown_count; /* make lint happy */
3044 tcpo.unknowns[ix].unkn_opt = *popt;
3045 tcpo.unknowns[ix].unkn_len = *plen;
3046 }
3047 ++tcpo.unknown_count;
3048
3049 popt += *plen;
3050 break;
3051 }
3052 }
3053
3054 return(&tcpo);
3055 }
3056
3057
3058
3059 static void
ExtractContents(u_long seq,u_long tcp_data_bytes,u_long saved_data_bytes,void * pdata,tcb * ptcb)3060 ExtractContents(
3061 u_long seq,
3062 u_long tcp_data_bytes,
3063 u_long saved_data_bytes,
3064 void *pdata,
3065 tcb *ptcb)
3066 {
3067 u_long missing;
3068 long offset;
3069 u_long fptr;
3070 /* Maximum filename could be :
3071 aaaaaaaa2bbbbbbbb_contents.dat which
3072 takes 8+1+8+ size of the extension */
3073 static char filename[MAX_HOSTLETTER_LEN
3074 +1 /* for "2" */
3075 +MAX_HOSTLETTER_LEN
3076 +sizeof(CONTENTS_FILE_EXTENSION)
3077 +1]; /* for terminating NULL. */
3078
3079 if (debug > 2)
3080 fprintf(stderr,
3081 "ExtractContents(seq:%ld bytes:%ld saved_bytes:%ld) called\n",
3082 seq, tcp_data_bytes, saved_data_bytes);
3083
3084 if (saved_data_bytes == 0)
3085 return;
3086
3087 /* how many bytes do we have? */
3088 missing = tcp_data_bytes - saved_data_bytes;
3089 if ((debug > 2) && (missing > 0)) {
3090 fprintf(stderr,"ExtractContents: missing %ld bytes (%ld-%ld)\n",
3091 missing,tcp_data_bytes,saved_data_bytes);
3092 }
3093
3094
3095 /* if the FILE is "-1", couldn't open file */
3096 if (ptcb->extr_contents_file == (MFILE *) -1) {
3097 return;
3098 }
3099
3100 /* if the FILE is NULL, open file */
3101 snprintf(filename,sizeof(filename),"%s2%s%s", ptcb->host_letter, ptcb->ptwin->host_letter,
3102 CONTENTS_FILE_EXTENSION);
3103 if (ptcb->extr_contents_file == (MFILE *) NULL) {
3104 MFILE *f;
3105
3106 if ((f = Mfopen(filename,"w")) == NULL) {
3107 perror(filename);
3108 ptcb->extr_contents_file = (MFILE *) -1;
3109 }
3110
3111 if (debug)
3112 fprintf(stderr,"TCP contents file is '%s'\n", filename);
3113
3114 ptcb->extr_contents_file = f;
3115
3116 if (ptcb->syn_count == 0) {
3117 /* we haven't seen the SYN. This is bad because we can't tell */
3118 /* if there is data BEFORE this, which makes it tough to store */
3119 /* the file. Let's be optimistic and hope we don't see */
3120 /* anything before this point. Otherwise, we're stuck */
3121 ptcb->extr_lastseq = seq;
3122 } else {
3123 /* beginning of the file is the data just past the SYN */
3124 ptcb->extr_lastseq = ptcb->syn+1;
3125 }
3126 /* in any case, anything before HERE is illegal (fails for very */
3127 /* long files - FIXME */
3128 ptcb->extr_initseq = ptcb->extr_lastseq;
3129 }
3130
3131 /* it's illegal for the bytes to be BEFORE extr_initseq unless the file */
3132 /* is "really long" (seq space has wrapped around) - FIXME(ugly) */
3133 if ((SEQCMP(seq,ptcb->extr_initseq) < 0) &&
3134 (ptcb->data_bytes < (0xffffffff/2))) {
3135 /* if we haven't (didn't) seen the SYN, then can't do this!! */
3136 if (debug>1) {
3137 fprintf(stderr,
3138 "ExtractContents: skipping data, preceeds first segment\n");
3139 fprintf(stderr,"\t and I didnt' see the SYN\n");
3140 }
3141 return;
3142 }
3143
3144 /* see where we should start writing */
3145 /* a little complicated, because we want to support really long files */
3146 offset = SEQCMP(seq,ptcb->extr_lastseq);
3147
3148
3149 if (debug>10)
3150 fprintf(stderr,
3151 "TRYING to save %ld bytes from stream '%s2%s' at offset %ld\n",
3152 saved_data_bytes,
3153 ptcb->host_letter, ptcb->ptwin->host_letter,
3154 offset);
3155
3156 /* seek to the correct place in the file */
3157 if (Mfseek(ptcb->extr_contents_file, offset, SEEK_CUR) == -1) {
3158 perror("fseek");
3159 exit(-1);
3160 }
3161
3162 /* see where we are */
3163 fptr = Mftell(ptcb->extr_contents_file);
3164
3165 if (debug>1)
3166 fprintf(stderr,
3167 "Saving %ld bytes from '%s2%s' at offset %ld in file '%s'\n",
3168 saved_data_bytes,
3169 ptcb->host_letter, ptcb->ptwin->host_letter,
3170 fptr, filename);
3171
3172 /* store the bytes */
3173 if (Mfwrite(pdata,1,saved_data_bytes,ptcb->extr_contents_file)
3174 != saved_data_bytes) {
3175 perror("fwrite");
3176 exit(-1);
3177 }
3178
3179 /* go back to where we started to not confuse the next write */
3180 ptcb->extr_lastseq = seq;
3181 if (Mfseek(ptcb->extr_contents_file, fptr, SEEK_SET) == -1) {
3182 perror("fseek 2");
3183 exit(-1);
3184 }
3185 }
3186
3187
3188 /* check for not-uncommon error of hardware-level duplicates
3189 (same IP ID and TCP sequence number) */
3190 static Bool
check_hw_dups(u_short id,seqnum seq,tcb * tcb)3191 check_hw_dups(
3192 u_short id,
3193 seqnum seq,
3194 tcb *tcb)
3195 {
3196 int i;
3197 struct str_hardware_dups *pshd;
3198
3199 /* see if we've seen this one before */
3200 for (i=0; i < SEGS_TO_REMEMBER; ++i) {
3201 pshd = &tcb->hardware_dups[i];
3202
3203 if ((pshd->hwdup_seq == seq) && (pshd->hwdup_id == id) &&
3204 (pshd->hwdup_seq != 0) && (pshd->hwdup_id != 0)) {
3205 /* count it */
3206 ++tcb->num_hardware_dups;
3207 if (warn_printhwdups) {
3208 printf("%s->%s: saw hardware duplicate of TCP seq %lu, IP ID %u (packet %lu == %lu)\n",
3209 tcb->host_letter,tcb->ptwin->host_letter,
3210 seq, id, pnum,pshd->hwdup_packnum);
3211 }
3212 return(TRUE);
3213 }
3214 }
3215
3216 /* remember it */
3217 pshd = &tcb->hardware_dups[tcb->hardware_dups_ix];
3218 pshd->hwdup_seq = seq;
3219 pshd->hwdup_id = id;
3220 pshd->hwdup_packnum = pnum;
3221 tcb->hardware_dups_ix = (tcb->hardware_dups_ix+1) % SEGS_TO_REMEMBER;
3222
3223 return(FALSE);
3224 }
3225
3226
3227 /* given a tcp_pair and a packet, tell me which tcb it is */
3228 struct tcb *
ptp2ptcb(tcp_pair * ptp,struct ip * pip,struct tcphdr * ptcp)3229 ptp2ptcb(
3230 tcp_pair *ptp,
3231 struct ip *pip,
3232 struct tcphdr *ptcp)
3233 {
3234 int dir = 0;
3235 tcp_pair tp_in;
3236
3237 /* grab the address from this packet */
3238 CopyAddr(&tp_in.addr_pair, pip,
3239 ntohs(ptcp->th_sport), ntohs(ptcp->th_dport));
3240
3241 /* check the direction */
3242 if (!SameConn(&tp_in.addr_pair,&ptp->addr_pair,&dir))
3243 return(NULL); /* not found, internal error */
3244
3245 if (dir == A2B)
3246 return(&ptp->a2b);
3247 else
3248 return(&ptp->b2a);
3249 }
3250
3251
3252 /* represent the sequence numbers absolute or relative to 0 */
3253 static u_long
SeqRep(tcb * ptcb,u_long seq)3254 SeqRep(
3255 tcb *ptcb,
3256 u_long seq)
3257 {
3258 if (graph_seq_zero) {
3259 return(seq - ptcb->min_seq);
3260 } else {
3261 return(seq);
3262 }
3263 }
3264
3265
3266 /*------------------------------------------------------------------------
3267 * cksum - Return 16-bit ones complement of 16-bit ones complement sum
3268 *------------------------------------------------------------------------
3269 */
3270 static u_short
cksum(void * pvoid,int nbytes)3271 cksum(
3272 void *pvoid, /* any alignment is legal */
3273 int nbytes)
3274 {
3275 u_char *pchar = pvoid;
3276 u_long sum = 0;
3277
3278 while (nbytes >= 2) {
3279 /* can't assume pointer alignment :-( */
3280 sum += (pchar[0]<<8);
3281 sum += pchar[1];
3282
3283 pchar+=2;
3284 nbytes -= 2;
3285 }
3286
3287 /* special check for odd length */
3288 if (nbytes == 1) {
3289 sum += (pchar[0]<<8);
3290 /* lower byte is assumed to be 0 */
3291 }
3292
3293 sum = (sum >> 16) + (sum & 0xffff); /* add in carry */
3294 sum += (sum >> 16); /* maybe one more */
3295
3296 return(sum);
3297 }
3298
3299 /* compute IP checksum */
3300 static u_short
ip_cksum(struct ip * pip,void * plast)3301 ip_cksum(
3302 struct ip *pip,
3303 void *plast)
3304 {
3305 u_short sum;
3306
3307 if (PIP_ISV6(pip))
3308 return(0); /* IPv6 has no header checksum */
3309 if (!PIP_ISV4(pip))
3310 return(1); /* I have no idea! */
3311
3312
3313 /* quick sanity check, if the packet is truncated, pretend it's valid */
3314 if ((char *)plast < (char *)((char *)pip+IP_HL(pip)*4-1)) {
3315 return(0);
3316 }
3317
3318 /* ... else IPv4 */
3319 sum = cksum(pip, IP_HL(pip)*4);
3320 return(sum);
3321 }
3322
3323
3324 /* is the IP checksum valid? */
3325 Bool
ip_cksum_valid(struct ip * pip,void * plast)3326 ip_cksum_valid(
3327 struct ip *pip,
3328 void *plast)
3329 {
3330 u_short sum;
3331 /* PrintRawDataHex("IP header",pip,plast); */
3332
3333 sum = ip_cksum(pip,plast);
3334
3335 return((sum == 0) || (sum == 0xffff));
3336 }
3337
3338
3339 /* compute the TCP checksum */
3340 static u_short
tcp_cksum(struct ip * pip,struct tcphdr * ptcp,void * plast)3341 tcp_cksum(
3342 struct ip *pip,
3343 struct tcphdr *ptcp,
3344 void *plast)
3345 {
3346 u_long sum = 0;
3347 unsigned tcp_length = 0;
3348
3349 /* verify version */
3350 if (!PIP_ISV4(pip) && !PIP_ISV6(pip)) {
3351 fprintf(stderr,"Internal error, tcp_cksum: neither IPv4 nor IPv6\n");
3352 exit(-1);
3353 }
3354
3355
3356 /* TCP checksum includes: */
3357 /* - IP source */
3358 /* - IP dest */
3359 /* - IP type */
3360 /* - TCP header length + TCP data length */
3361 /* - TCP header and data */
3362
3363 if (PIP_ISV4(pip)) {
3364 /* quick sanity check, if the packet is fragmented,
3365 pretend it's valid */
3366 /* Thu Jul 6, 2000 - bugfix, bad check */
3367 if (((ntohs(pip->ip_off) << 2) & 0xffff) != 0) {
3368 /* both the offset AND the MF bit must be 0 */
3369 /* (we shifted off the DF bit, which might be on) */
3370 return(0);
3371 }
3372
3373 /* 2 4-byte numbers, next to each other */
3374 sum += cksum(&pip->ip_src,4*2);
3375
3376 /* type */
3377 sum += (u_short) pip->ip_p;
3378
3379 /* length (TCP header length + TCP data length) */
3380 tcp_length = ntohs(pip->ip_len) - (4 * IP_HL(pip));
3381 sum += (u_short) tcp_length;
3382 } else /* if (PIP_ISV6(pip))*/ {
3383
3384 /* Support for IPv6 checksums has been added on Aug31, 2001
3385 * and has not been thoroughly tested. - Avinash
3386 */
3387
3388 int total_length = 0; /* Total length of the extension headers */
3389 struct ipv6 *pip6 = (struct ipv6 *)pip;
3390
3391 /* quick sanity check, it the packet is truncated,
3392 * pertend it is valid.
3393 */
3394 if(gettcp(pip, &ptcp, &plast) != 0)
3395 return(0);
3396
3397 /* Forming the pseudo-header */
3398 /* source address */
3399 sum += cksum(&pip6->ip6_saddr,16);
3400
3401 /* Looking for the destination address.
3402 * May be in the IPv6 header or the last address in the
3403 * routing header (if present)
3404 */
3405
3406 /* No extension headers, hence, routing header not present */
3407 if(pip6->ip6_nheader == IPPROTO_TCP) {
3408 sum += cksum(&pip6->ip6_daddr,16);
3409 }
3410 /* Some extension headers present. Searching for routing header */
3411 else {
3412 /* find the first header */
3413 struct ipv6_ext *pipv6_ext = (struct ipv6_ext *)(pip6+1);
3414
3415 /* Searching for the routing header */
3416 int ret = getroutingheader(pip, &pipv6_ext, &plast);
3417
3418 if(!ret) { /* Found the routing header */
3419 if(pipv6_ext->ip6ext_len >= 2) { /* Sanity check */
3420 char *daddr = (char *)((char *)pipv6_ext + 8 + ((pipv6_ext->ip6ext_len - 2) * 8));
3421 sum += cksum(&daddr,16);
3422 }
3423 else { /* Not a valid routing header */
3424 return(-1);
3425 }
3426 }
3427 else { /* Routing header not found */
3428 sum += cksum(&pip6->ip6_daddr,16);
3429 }
3430 }
3431
3432 /* Upper-Layer Packet Length */
3433 total_length = total_length_ext_headers(pip6);
3434 if(total_length >= 0)
3435 tcp_length = pip6->ip6_lngth - total_length;
3436 else /* Unknown extension header seen */
3437 return(-1);
3438 sum += (u_short) tcp_length;
3439
3440 /* Next Header (Type) */
3441 sum += (u_short) IPPROTO_TCP;
3442 }
3443
3444
3445 /* quick sanity check, if the packet is truncated, pretend it's valid */
3446 if ((char *)plast < (char *)((char *)ptcp+tcp_length-1)) {
3447 return(0);
3448 }
3449
3450 /* checksum the TCP header and data */
3451 sum += cksum(ptcp,tcp_length);
3452
3453 /* roll down into a 16-bit number */
3454 sum = (sum >> 16) + (sum & 0xffff);
3455 sum += (sum >> 16);
3456
3457 return (u_short)(~sum & 0xffff);
3458 }
3459
3460
3461
3462 /* compute the UDP checksum */
3463 static u_short
udp_cksum(struct ip * pip,struct udphdr * pudp,void * plast)3464 udp_cksum(
3465 struct ip *pip,
3466 struct udphdr *pudp,
3467 void *plast)
3468 {
3469 u_long sum = 0;
3470 unsigned udp_length;
3471
3472 /* WARNING -- this routine has not been extensively tested */
3473
3474 /* verify version */
3475 if (!PIP_ISV4(pip) && !PIP_ISV6(pip)) {
3476 fprintf(stderr,"Internal error, udp_cksum: neither IPv4 nor IPv6\n");
3477 exit(-1);
3478 }
3479
3480
3481 /* UDP checksum includes: */
3482 /* - IP source */
3483 /* - IP dest */
3484 /* - IP type */
3485 /* - UDP length field */
3486 /* - UDP header and data */
3487
3488 if (PIP_ISV4(pip)) {
3489 /* 2 4-byte numbers, next to each other */
3490 sum += cksum(&pip->ip_src,4*2);
3491
3492 /* type */
3493 sum += (u_short) pip->ip_p;
3494
3495 /* UDP length */
3496 udp_length = ntohs(pudp->uh_ulen);
3497 sum += htons(pudp->uh_ulen);
3498 } else /* if (PIP_ISV6(pip))*/ {
3499
3500 /* Support for IPv6 checksums has been added on Aug31, 2001
3501 * and has not been thoroughly tested. - Avinash
3502 */
3503
3504 struct ipv6 *pip6 = (struct ipv6 *)pip;
3505
3506 /* quick sanity check, it the packet is truncated,
3507 * pertend it is valid.
3508 */
3509 if(getudp(pip, &pudp, &plast) != 0)
3510 return(0);
3511
3512 /* Forming the pseudo-header */
3513 /* source address */
3514 sum += cksum(&pip6->ip6_saddr,16);
3515
3516 /* Looking for the destination address.
3517 * May be in the IPv6 header or the last address in the
3518 * routing header (if present)
3519 */
3520
3521 /* No extension headers, hence, routing header not present */
3522 if(pip6->ip6_nheader == IPPROTO_UDP) {
3523 sum += cksum(&pip6->ip6_daddr,16);
3524 }
3525 /* Some extension headers present. Searching for routing header */
3526 else {
3527 /* find the first header */
3528 struct ipv6_ext *pipv6_ext = (struct ipv6_ext *)(pip6+1);
3529
3530 /* Searching for the routing header */
3531 int ret = getroutingheader(pip, &pipv6_ext, &plast);
3532
3533 if(!ret) { /* Found the routing header */
3534 if(pipv6_ext->ip6ext_len >= 2) { /* Sanity check */
3535 char *daddr = (char *)((char *)pipv6_ext + 8 + ((pipv6_ext->ip6ext_len - 2) * 8));
3536 sum += cksum(&daddr,16);
3537 }
3538 else { /* Not a valid routing header */
3539 return(-1);
3540 }
3541 }
3542 else { /* Routing header not found */
3543 sum += cksum(&pip6->ip6_daddr,16);
3544 }
3545 }
3546
3547 /* Upper-Layer Packet Length */
3548 udp_length = ntohs(pudp->uh_ulen);
3549 sum += htons(pudp->uh_ulen);
3550
3551 /* Next Header (Type) */
3552 sum += (u_short) IPPROTO_UDP;
3553 }
3554
3555
3556 /* quick sanity check, if the packet is truncated, pretend it's valid */
3557 if ((char *)plast < (char *)((char *)pudp+udp_length-1)) {
3558 return(0);
3559 }
3560
3561 /* checksum the UDP header and data */
3562 sum += cksum(pudp,udp_length);
3563
3564 /* roll down into a 16-bit number */
3565 sum = (sum >> 16) + (sum & 0xffff);
3566 sum += (sum >> 16);
3567
3568 return (u_short)(~sum & 0xffff);
3569 }
3570
3571
3572 /* is the TCP checksum valid? */
3573 Bool
tcp_cksum_valid(struct ip * pip,struct tcphdr * ptcp,void * plast)3574 tcp_cksum_valid(
3575 struct ip *pip,
3576 struct tcphdr *ptcp,
3577 void *plast)
3578 {
3579 return(tcp_cksum(pip,ptcp,plast) == 0);
3580 }
3581
3582
3583 /* is the UDP checksum valid? */
3584 Bool
udp_cksum_valid(struct ip * pip,struct udphdr * pudp,void * plast)3585 udp_cksum_valid(
3586 struct ip *pip,
3587 struct udphdr *pudp,
3588 void *plast)
3589 {
3590 if (ntohs(pudp->uh_sum) == 0) {
3591 /* checksum not used */
3592 return(1); /* valid */
3593 }
3594
3595 return(udp_cksum(pip,pudp,plast) == 0);
3596 }
3597
3598 /* Did we miss any segment during packet capture? */
3599 static Bool
MissingData(tcp_pair * ptp)3600 MissingData(tcp_pair *ptp)
3601 {
3602 tcb *pab = &ptp->a2b;
3603 tcb *pba = &ptp->b2a;
3604
3605 u_llong stream_length_pab=0, stream_length_pba=0;
3606 u_long pab_last, pba_last;
3607
3608 /* If packets were truncated (due to shorter snaplen) we miss data */
3609 if ( (pab->trunc_bytes > 0) || (pba->trunc_bytes > 0) )
3610 return TRUE;
3611
3612 /* Also, if we missed whole segments (pcap dozing off) we miss data.
3613 * The following code yanked off from output.c handles seq-space
3614 * wrap around - Mani
3615 *
3616 * Compare to theoretical length of the stream (not just what
3617 * we saw) using the SYN and FIN
3618 * Seq. Space wrap around calculations:
3619 * Calculate stream length using last_seq_num seen, first_seq_num
3620 * seen and wrap_count.
3621 * first_seq_num = syn
3622 * If reset_set, last_seq_num = latest_seq
3623 * else last_seq_num = fin
3624 */
3625
3626 pab_last = (pab->reset_count>0)?pab->latest_seq:pab->fin;
3627 pba_last = (pba->reset_count>0)?pba->latest_seq:pba->fin;
3628
3629 /* calculating stream length for direction pab */
3630 if ((pab->syn_count > 0) && (pab->fin_count > 0)) {
3631 if (pab->seq_wrap_count > 0) {
3632 if (pab_last > pab->syn) {
3633 stream_length_pab = pab_last + (MAX_32 * pab->seq_wrap_count) - pab->syn - 1;
3634 }
3635 else {
3636 stream_length_pab = pab_last + (MAX_32 * (pab->seq_wrap_count+1)) - pab->syn - 1;
3637 }
3638 }
3639 else {
3640 if (pab_last > pab->syn) {
3641 stream_length_pab = pab_last - pab->syn - 1;
3642 }
3643 else {
3644 stream_length_pab = MAX_32 + pab_last - pab->syn - 1;
3645 }
3646 }
3647 }
3648
3649 /* calculating stream length for direction pba */
3650 if ((pba->syn_count > 0) && (pba->fin_count > 0)) {
3651 if (pba->seq_wrap_count > 0) {
3652 if (pba_last > pba->syn) {
3653 stream_length_pba = pba_last + (MAX_32 * pba->seq_wrap_count) - pba->syn - 1;
3654 }
3655 else {
3656 stream_length_pba = pba_last + (MAX_32 * (pba->seq_wrap_count+1)) - pba->syn - 1;
3657 }
3658 }
3659 else {
3660 if (pba_last > pba->syn) {
3661 stream_length_pba = pba_last - pba->syn - 1;
3662 }
3663 else {
3664 stream_length_pba = MAX_32 + pba_last - pba->syn - 1;
3665 }
3666 }
3667 }
3668
3669 /* Alright, now that we have the stream length in either direction,
3670 * if the stream length is not equal to the total unique bytes we
3671 * seen, we must have missed whole segments
3672 */
3673 if ( (stream_length_pab != pab->unique_bytes) ||
3674 (stream_length_pba != pba->unique_bytes) )
3675 return TRUE;
3676
3677 return FALSE;
3678 }
3679