Created a new protocol tree implementation and a new display filter
[obnox/wireshark/wip.git] / follow.c
1 /* follow.c
2  *
3  * $Id: follow.c,v 1.10 1999/07/07 22:51:39 gram Exp $
4  *
5  * Copyright 1998 Mike Hall <mlh@io.com>
6  *
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@zing.org>
9  * Copyright 1998 Gerald Combs
10  *
11  * 
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * as published by the Free Software Foundation; either version 2
15  * of the License, or (at your option) any later version.
16  * 
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  * 
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
25  *
26  */
27
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include <gtk/gtk.h>
33 #include <stdlib.h>
34 #include <stdio.h>
35 #include <string.h>
36 #include <unistd.h>
37
38 #ifdef HAVE_SYS_TYPES_H
39 # include <sys/types.h>
40 #endif
41
42 #include <glib.h>
43 #include "ethereal.h"
44 #include "packet.h"
45 #include "follow.h"
46
47 extern FILE* data_out_file;
48
49 gboolean incomplete_tcp_stream = FALSE;
50
51 static int check_fragments( int );
52 static void write_packet_data( const u_char *, int );
53
54 /* this will build libpcap filter text that will only 
55    pass the packets related to the stream. There is a 
56    chance that two streams could intersect, but not a 
57    very good one */
58 char* 
59 build_follow_filter( packet_info *pi ) {
60   char* buf = malloc(1024);
61   if( pi->ipproto == 6 ) {
62     /* TCP */
63     sprintf( buf, "host %s and host %s and (ip proto \\tcp) and (port %d and port %d)",
64              pi->srcip, pi->destip, pi->srcport, pi->destport );
65   }
66   else { 
67     free( buf );
68     return NULL;
69   }
70   return buf;
71 }
72
73 /* here we are going to try and reconstruct the data portion of a TCP
74    session. We will try and handle duplicates, TCP fragments, and out 
75    of order packets in a smart way. */
76
77 static tcp_frag *frags[2] = { 0, 0};
78 static u_long seq[2];
79 static u_long src[2] = { 0, 0 };
80
81 void 
82 reassemble_tcp( u_long sequence, u_long length, const char* data, u_long data_length, int synflag, u_long srcx ) {
83   int src_index, j, first = 0;
84   u_long newseq;
85   tcp_frag *tmp_frag;
86   src_index = -1;
87   /* first we check to see if we have seen this src ip before. */
88   for( j=0; j<2; j++ ) {
89     if( src[j] == srcx ) {
90       src_index = j;
91     }
92   }
93   /* we didn't find it if src_index == -1 */
94   if( src_index < 0 ) {
95     /* assign it to a src_index and get going */
96     for( j=0; j<2; j++ ) {
97       if( src[j] == 0 ) {
98         src[j] = srcx;
99         src_index = j;
100         first = 1;
101         break;
102       }
103     }
104   }
105   if( src_index < 0 ) {
106     fprintf( stderr, "ERROR in reassemble_tcp: Too many addresses!\n");
107     return;
108   }
109
110   if( data_length < length ) {
111     incomplete_tcp_stream = TRUE;
112   }
113
114   /* now that we have filed away the srcs, lets get the sequence number stuff 
115      figured out */
116   if( first ) {
117     /* this is the first time we have seen this src's sequence number */
118     seq[src_index] = sequence + length;
119     if( synflag ) {
120       seq[src_index]++;
121     }
122     /* write out the packet data */
123     write_packet_data( data, data_length );
124     return;
125   }
126   /* if we are here, we have already seen this src, let's
127      try and figure out if this packet is in the right place */
128   if( sequence < seq[src_index] ) {
129     /* this sequence number seems dated, but 
130        check the end to make sure it has no more
131        info than we have already seen */
132     newseq = sequence + length;
133     if( newseq > seq[src_index] ) {
134       u_long new_len;
135
136       /* this one has more than we have seen. let's get the 
137          payload that we have not seen. */
138
139       new_len = seq[src_index] - sequence;
140
141       if ( data_length <= new_len ) {
142         data = NULL;
143         data_length = 0;
144         incomplete_tcp_stream = TRUE;
145       } else {
146         data += new_len;
147         data_length -= new_len;
148       }
149       sequence = seq[src_index];
150       length = newseq - seq[src_index];
151       
152       /* this will now appear to be right on time :) */
153     }
154   }
155   if ( sequence == seq[src_index] ) {
156     /* right on time */
157     seq[src_index] += length;
158     if( synflag ) seq[src_index]++;
159     if( data ) {
160       write_packet_data( data, data_length );
161     }
162     /* done with the packet, see if it caused a fragment to fit */
163     while( check_fragments( src_index ) )
164       ;
165   }
166   else {
167     /* out of order packet */
168     if( sequence > seq[src_index] ) {
169       tmp_frag = (tcp_frag *)malloc( sizeof( tcp_frag ) );
170       tmp_frag->data = (u_char *)malloc( data_length );
171       tmp_frag->seq = sequence;
172       tmp_frag->len = length;
173       tmp_frag->data_len = data_length;
174       memcpy( tmp_frag->data, data, data_length );
175       if( frags[src_index] ) {
176         tmp_frag->next = frags[src_index];
177       } else {
178         tmp_frag->next = NULL;
179       }
180       frags[src_index] = tmp_frag;
181     }
182   }
183 } /* end reassemble_tcp */
184
185 /* here we search through all the frag we have collected to see if
186    one fits */
187 static int 
188 check_fragments( int index ) {
189   tcp_frag *prev = NULL;
190   tcp_frag *current;
191   current = frags[index];
192   while( current ) {
193     if( current->seq == seq[index] ) {
194       /* this fragment fits the stream */
195       if( current->data ) {
196         write_packet_data( current->data, current->data_len );
197       }
198       seq[index] += current->len;
199       if( prev ) {
200         prev->next = current->next;
201       } else {
202         frags[index] = current->next;
203       }
204       free( current->data );
205       free( current );
206       return 1;
207     }
208     prev = current;
209     current = current->next;
210   }
211   return 0;
212 }
213
214 /* this should always be called before we start to reassemble a stream */
215 void 
216 reset_tcp_reassembly() {
217   tcp_frag *current, *next;
218   int i;
219   incomplete_tcp_stream = FALSE;
220   for( i=0; i<2; i++ ) {
221     seq[i] = 0;
222     src[i] = 0;
223     current = frags[i];
224     while( current ) {
225       next = current->next;
226       free( current->data ); 
227       free( current );
228       current = next;
229     }
230     frags[i] = NULL;
231   }
232 }
233
234 static void 
235 write_packet_data( const u_char* data, int length ) {
236   fwrite( data, 1, length, data_out_file );
237 }
238