Ethereal-dev: [ethereal-dev] Fix in TCP reassembly code

Note: This archive is from the project's previous web site, ethereal.com. This list is no longer active.

From: Laurent Deniel <deniel@xxxxxxxxxxx>
Date: Sat, 13 Feb 1999 12:28:31 +0100
 Hi,

 The attached file is a diff to current CVS tree that contains fixes to
 avoid the display of erroneous data (or even seg fault) when following
 the TCP stream if the caplen is less than the mtu.

 Laurent.

--
Laurent DENIEL            | E-mail: deniel@xxxxxxxxxxx
Paris, FRANCE             |         deniel@xxxxxxxxxxxxxxxxxxxxxxxxxxxx
                          | WWW   : http://www.worldnet.fr/~deniel
    All above opinions are personal, unless stated otherwise.
diff -u --recursive --new-file ethereal-cvs/ethereal/ethereal.c ethereal/ethereal.c
--- ethereal-cvs/ethereal/ethereal.c	Sat Feb 13 12:15:30 1999
+++ ethereal/ethereal.c	Sat Feb 13 12:13:08 1999
@@ -188,7 +188,13 @@
 			NULL, "WM destroy" );
     gtk_signal_connect( GTK_OBJECT(streamwindow), "destroy",
 			NULL, "WM destroy" );
-    gtk_window_set_title( GTK_WINDOW(streamwindow), "Contents of TCP stream" );
+    if( incomplete_tcp_stream ) {
+      gtk_window_set_title( GTK_WINDOW(streamwindow), 
+			    "Contents of TCP stream (incomplete)"  );
+    } else {
+      gtk_window_set_title( GTK_WINDOW(streamwindow), 
+			    "Contents of TCP stream"  );
+    }
     gtk_widget_set_usize( GTK_WIDGET(streamwindow), DEF_WIDTH, DEF_HEIGHT );
     gtk_container_border_width( GTK_CONTAINER(streamwindow), 2 );
     /* setup the container */
diff -u --recursive --new-file ethereal-cvs/ethereal/follow.c ethereal/follow.c
--- ethereal-cvs/ethereal/follow.c	Thu Dec 17 06:42:25 1998
+++ ethereal/follow.c	Sat Feb 13 12:04:45 1999
@@ -45,6 +45,8 @@
 
 extern FILE* data_out_file;
 
+gboolean incomplete_tcp_stream = FALSE;
+
 /* this will build libpcap filter text that will only 
    pass the packets related to the stream. There is a 
    chance that two streams could intersect, but not a 
@@ -73,7 +75,7 @@
 static u_long src[2] = { 0, 0 };
 
 void 
-reassemble_tcp( u_long sequence, u_long length, const char* data, int synflag, u_long srcx ) {
+reassemble_tcp( u_long sequence, u_long length, const char* data, u_long data_length, int synflag, u_long srcx ) {
   int src_index, j, first = 0;
   u_long newseq;
   tcp_frag *tmp_frag;
@@ -100,6 +102,11 @@
     fprintf( stderr, "ERROR in reassemble_tcp: Too many addresses!\n");
     return;
   }
+
+  if( data_length < length ) {
+    incomplete_tcp_stream = TRUE;
+  }
+
   /* now that we have filed away the srcs, lets get the sequence number stuff 
      figured out */
   if( first ) {
@@ -109,7 +116,7 @@
       seq[src_index]++;
     }
     /* write out the packet data */
-    write_packet_data( data, length );
+    write_packet_data( data, data_length );
     return;
   }
   /* if we are here, we have already seen this src, let's
@@ -120,11 +127,24 @@
        info than we have already seen */
     newseq = sequence + length;
     if( newseq > seq[src_index] ) {
+      u_long new_len;
+
       /* this one has more than we have seen. let's get the 
 	 payload that we have not seen. */
-      data += ( seq[src_index] - sequence );
+
+      new_len = seq[src_index] - sequence;
+
+      if ( data_length <= new_len ) {
+	data = NULL;
+	data_length = 0;
+	incomplete_tcp_stream = TRUE;
+      } else {
+	data += new_len;
+	data_length -= new_len;
+      }
       sequence = seq[src_index];
       length = newseq - seq[src_index];
+      
       /* this will now appear to be right on time :) */
     }
   }
@@ -132,7 +152,9 @@
     /* right on time */
     seq[src_index] += length;
     if( synflag ) seq[src_index]++;
-    write_packet_data( data, length );
+    if( data ) {
+      write_packet_data( data, data_length );
+    }
     /* done with the packet, see if it caused a fragment to fit */
     while( check_fragments( src_index ) )
       ;
@@ -141,10 +163,11 @@
     /* out of order packet */
     if( sequence > seq[src_index] ) {
       tmp_frag = (tcp_frag *)malloc( sizeof( tcp_frag ) );
-      tmp_frag->data = (u_char *)malloc( length );
+      tmp_frag->data = (u_char *)malloc( data_length );
       tmp_frag->seq = sequence;
       tmp_frag->len = length;
-      memcpy( tmp_frag->data, data, length );
+      tmp_frag->data_len = data_length;
+      memcpy( tmp_frag->data, data, data_length );
       if( frags[src_index] ) {
 	tmp_frag->next = frags[src_index];
       } else {
@@ -165,7 +188,9 @@
   while( current ) {
     if( current->seq == seq[index] ) {
       /* this fragment fits the stream */
-      write_packet_data( current->data, current->len );
+      if( current->data ) {
+	write_packet_data( current->data, current->data_len );
+      }
       seq[index] += current->len;
       if( prev ) {
 	prev->next = current->next;
@@ -187,6 +212,7 @@
 reset_tcp_reassembly() {
   tcp_frag *current, *next;
   int i;
+  incomplete_tcp_stream = FALSE;
   for( i=0; i<2; i++ ) {
     seq[i] = 0;
     src[i] = 0;
diff -u --recursive --new-file ethereal-cvs/ethereal/follow.h ethereal/follow.h
--- ethereal-cvs/ethereal/follow.h	Mon Sep 28 00:12:26 1998
+++ ethereal/follow.h	Sat Feb 13 12:19:58 1999
@@ -30,15 +30,18 @@
 
 #include "packet.h"
 
+extern gboolean incomplete_tcp_stream;
+
 typedef struct _tcp_frag {
   u_long              seq;
   u_long              len;
+  u_long              data_len;
   u_char             *data;
   struct _tcp_frag   *next;
 } tcp_frag;
 
 char* build_follow_filter( packet_info * );
-void reassemble_tcp( u_long, u_long, const char*, int, u_long );
+void reassemble_tcp( u_long, u_long, const char*, u_long, int, u_long );
 int check_fragments( int );
 void  reset_tcp_reassembly( void );
 void write_packet_data( const u_char *, int );
diff -u --recursive --new-file ethereal-cvs/ethereal/packet-tcp.c ethereal/packet-tcp.c
--- ethereal-cvs/ethereal/packet-tcp.c	Fri Feb 12 10:03:41 1999
+++ ethereal/packet-tcp.c	Fri Feb 12 23:35:31 1999
@@ -406,8 +406,9 @@
   
   if( data_out_file ) {
     reassemble_tcp( th.th_seq, /* sequence number */
-        ( pi.iplen -( pi.iphdrlen * 4 )-( hi_nibble(th.th_off_x2) * 4 ) ), /* length */
+	( pi.iplen -( pi.iphdrlen * 4 )-( hi_nibble(th.th_off_x2) * 4 ) ), /* length */
         ( pd+offset ), /* data */
+	( fd->cap_len - offset ), /* captured data length */
         ( th.th_flags & 0x02 ), /* is syn set? */
         pi.ip_src ); /* src ip */
   }