Finally! Got rid of compilation warning about converting pointer to int
[obnox/wireshark/wip.git] / follow.c
1 /* follow.c
2  *
3  * $Id: follow.c,v 1.7 1999/06/23 20:09:58 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 "ethereal.h"
43 #include "packet.h"
44 #include "follow.h"
45
46 extern FILE* data_out_file;
47
48 gboolean incomplete_tcp_stream = FALSE;
49
50 /* this will build libpcap filter text that will only 
51    pass the packets related to the stream. There is a 
52    chance that two streams could intersect, but not a 
53    very good one */
54 char* 
55 build_follow_filter( packet_info *pi ) {
56   char* buf = malloc(1024);
57   if( pi->ipproto == 6 ) {
58     /* TCP */
59     sprintf( buf, "host %s and host %s and (ip proto \\tcp) and (port %d and port %d)",
60              pi->srcip, pi->destip, pi->srcport, pi->destport );
61   }
62   else { 
63     free( buf );
64     return NULL;
65   }
66   return buf;
67 }
68
69 /* here we are going to try and reconstruct the data portion of a TCP
70    session. We will try and handle duplicates, TCP fragments, and out 
71    of order packets in a smart way. */
72
73 static tcp_frag *frags[2] = { 0, 0};
74 static u_long seq[2];
75 static u_long src[2] = { 0, 0 };
76
77 void 
78 reassemble_tcp( u_long sequence, u_long length, const char* data, u_long data_length, int synflag, u_long srcx ) {
79   int src_index, j, first = 0;
80   u_long newseq;
81   tcp_frag *tmp_frag;
82   src_index = -1;
83   /* first we check to see if we have seen this src ip before. */
84   for( j=0; j<2; j++ ) {
85     if( src[j] == srcx ) {
86       src_index = j;
87     }
88   }
89   /* we didn't find it if src_index == -1 */
90   if( src_index < 0 ) {
91     /* assign it to a src_index and get going */
92     for( j=0; j<2; j++ ) {
93       if( src[j] == 0 ) {
94         src[j] = srcx;
95         src_index = j;
96         first = 1;
97         break;
98       }
99     }
100   }
101   if( src_index < 0 ) {
102     fprintf( stderr, "ERROR in reassemble_tcp: Too many addresses!\n");
103     return;
104   }
105
106   if( data_length < length ) {
107     incomplete_tcp_stream = TRUE;
108   }
109
110   /* now that we have filed away the srcs, lets get the sequence number stuff 
111      figured out */
112   if( first ) {
113     /* this is the first time we have seen this src's sequence number */
114     seq[src_index] = sequence + length;
115     if( synflag ) {
116       seq[src_index]++;
117     }
118     /* write out the packet data */
119     write_packet_data( data, data_length );
120     return;
121   }
122   /* if we are here, we have already seen this src, let's
123      try and figure out if this packet is in the right place */
124   if( sequence < seq[src_index] ) {
125     /* this sequence number seems dated, but 
126        check the end to make sure it has no more
127        info than we have already seen */
128     newseq = sequence + length;
129     if( newseq > seq[src_index] ) {
130       u_long new_len;
131
132       /* this one has more than we have seen. let's get the 
133          payload that we have not seen. */
134
135       new_len = seq[src_index] - sequence;
136
137       if ( data_length <= new_len ) {
138         data = NULL;
139         data_length = 0;
140         incomplete_tcp_stream = TRUE;
141       } else {
142         data += new_len;
143         data_length -= new_len;
144       }
145       sequence = seq[src_index];
146       length = newseq - seq[src_index];
147       
148       /* this will now appear to be right on time :) */
149     }
150   }
151   if ( sequence == seq[src_index] ) {
152     /* right on time */
153     seq[src_index] += length;
154     if( synflag ) seq[src_index]++;
155     if( data ) {
156       write_packet_data( data, data_length );
157     }
158     /* done with the packet, see if it caused a fragment to fit */
159     while( check_fragments( src_index ) )
160       ;
161   }
162   else {
163     /* out of order packet */
164     if( sequence > seq[src_index] ) {
165       tmp_frag = (tcp_frag *)malloc( sizeof( tcp_frag ) );
166       tmp_frag->data = (u_char *)malloc( data_length );
167       tmp_frag->seq = sequence;
168       tmp_frag->len = length;
169       tmp_frag->data_len = data_length;
170       memcpy( tmp_frag->data, data, data_length );
171       if( frags[src_index] ) {
172         tmp_frag->next = frags[src_index];
173       } else {
174         tmp_frag->next = NULL;
175       }
176       frags[src_index] = tmp_frag;
177     }
178   }
179 } /* end reassemble_tcp */
180
181 /* here we search through all the frag we have collected to see if
182    one fits */
183 int 
184 check_fragments( int index ) {
185   tcp_frag *prev = NULL;
186   tcp_frag *current;
187   current = frags[index];
188   while( current ) {
189     if( current->seq == seq[index] ) {
190       /* this fragment fits the stream */
191       if( current->data ) {
192         write_packet_data( current->data, current->data_len );
193       }
194       seq[index] += current->len;
195       if( prev ) {
196         prev->next = current->next;
197       } else {
198         src[index] = GPOINTER_TO_INT(current->next);
199       }
200       free( current->data );
201       free( current );
202       return 1;
203     }
204     prev = current;
205     current = current->next;
206   }
207   return 0;
208 }
209
210 /* this should always be called before we start to reassemble a stream */
211 void 
212 reset_tcp_reassembly() {
213   tcp_frag *current, *next;
214   int i;
215   incomplete_tcp_stream = FALSE;
216   for( i=0; i<2; i++ ) {
217     seq[i] = 0;
218     src[i] = 0;
219     current = frags[i];
220     while( current ) {
221       next = current->next;
222       free( current->data ); 
223       free( current );
224       current = next;
225     }
226     frags[i] = NULL;
227   }
228 }
229
230 void 
231 write_packet_data( const u_char* data, int length ) {
232   fwrite( data, 1, length, data_out_file );
233 }
234