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