HACK: pinfo->private_data points to smb_info again
[wireshark-wip.git] / epan / follow.c
blobed930c12b49acbd219a2586e9f027b21a2f983e4
1 /* follow.c
3 * $Id$
5 * Copyright 1998 Mike Hall <mlh@io.com>
7 * Wireshark - Network traffic analyzer
8 * By Gerald Combs <gerald@wireshark.org>
9 * Copyright 1998 Gerald Combs
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version 2
14 * of the License, or (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 #include "config.h"
29 #include <stdlib.h>
30 #include <stdio.h>
31 #include <string.h>
32 #ifdef HAVE_UNISTD_H
33 #include <unistd.h>
34 #endif
36 #include <glib.h>
37 #include <epan/packet.h>
38 #include <epan/to_str.h>
39 #include <epan/emem.h>
40 #include <epan/ipproto.h>
41 #include <epan/dissectors/packet-tcp.h>
42 #include "follow.h"
43 #include <epan/conversation.h>
45 #define MAX_IPADDR_LEN 16
47 typedef struct _tcp_frag {
48 guint32 seq;
49 guint32 len;
50 guint32 data_len;
51 gchar *data;
52 struct _tcp_frag *next;
53 } tcp_frag;
55 WS_DLL_PUBLIC_DEF
56 FILE* data_out_file = NULL;
58 gboolean empty_tcp_stream;
59 gboolean incomplete_tcp_stream;
61 static guint32 tcp_stream_to_follow = 0;
62 static guint8 ip_address[2][MAX_IPADDR_LEN];
63 static guint port[2];
64 static guint bytes_written[2];
65 static gboolean is_ipv6 = FALSE;
67 static int check_fragments( int, tcp_stream_chunk *, guint32 );
68 static void write_packet_data( int, tcp_stream_chunk *, const char * );
70 void
71 follow_stats(follow_stats_t* stats)
73 int i;
75 for (i = 0; i < 2 ; i++) {
76 memcpy(stats->ip_address[i], ip_address[i], MAX_IPADDR_LEN);
77 stats->port[i] = port[i];
78 stats->bytes_written[i] = bytes_written[i];
79 stats->is_ipv6 = is_ipv6;
83 /* This will build a display filter text that will only
84 pass the packets related to the stream. There is a
85 chance that two streams could intersect, but not a
86 very good one */
87 gchar*
88 build_follow_conv_filter( packet_info *pi ) {
89 char* buf;
90 int len;
91 conversation_t *conv=NULL;
92 struct tcp_analysis *tcpd;
94 if( ((pi->net_src.type == AT_IPv4 && pi->net_dst.type == AT_IPv4) ||
95 (pi->net_src.type == AT_IPv6 && pi->net_dst.type == AT_IPv6))
96 && pi->ipproto == IP_PROTO_TCP
97 && (conv=find_conversation(pi->fd->num, &pi->src, &pi->dst, pi->ptype,
98 pi->srcport, pi->destport, 0)) != NULL ) {
99 /* TCP over IPv4 */
100 tcpd=get_tcp_conversation_data(conv, pi);
101 if (tcpd) {
102 buf = g_strdup_printf("tcp.stream eq %d", tcpd->stream);
103 tcp_stream_to_follow = tcpd->stream;
104 if (pi->net_src.type == AT_IPv4) {
105 len = 4;
106 is_ipv6 = FALSE;
107 } else {
108 len = 16;
109 is_ipv6 = TRUE;
111 } else {
112 return NULL;
115 else if( pi->net_src.type == AT_IPv4 && pi->net_dst.type == AT_IPv4
116 && pi->ipproto == IP_PROTO_UDP ) {
117 /* UDP over IPv4 */
118 buf = g_strdup_printf(
119 "(ip.addr eq %s and ip.addr eq %s) and (udp.port eq %d and udp.port eq %d)",
120 ip_to_str((guint8 *)pi->net_src.data),
121 ip_to_str((guint8 *)pi->net_dst.data),
122 pi->srcport, pi->destport );
123 len = 4;
124 is_ipv6 = FALSE;
126 else if( pi->net_src.type == AT_IPv6 && pi->net_dst.type == AT_IPv6
127 && pi->ipproto == IP_PROTO_UDP ) {
128 /* UDP over IPv6 */
129 buf = g_strdup_printf(
130 "(ipv6.addr eq %s and ipv6.addr eq %s) and (udp.port eq %d and udp.port eq %d)",
131 ip6_to_str((const struct e_in6_addr *)pi->net_src.data),
132 ip6_to_str((const struct e_in6_addr *)pi->net_dst.data),
133 pi->srcport, pi->destport );
134 len = 16;
135 is_ipv6 = TRUE;
137 else {
138 return NULL;
140 memcpy(ip_address[0], pi->net_src.data, len);
141 memcpy(ip_address[1], pi->net_dst.data, len);
142 port[0] = pi->srcport;
143 port[1] = pi->destport;
144 return buf;
147 static gboolean find_tcp_addr;
148 static address tcp_addr[2];
149 static gboolean find_tcp_index;
151 gchar*
152 build_follow_index_filter(void) {
153 gchar *buf;
155 find_tcp_addr = TRUE;
156 buf = g_strdup_printf("tcp.stream eq %d", tcp_stream_to_follow);
157 return buf;
160 /* select a tcp stream to follow via it's address/port pairs */
161 gboolean
162 follow_tcp_addr(const address *addr0, guint port0,
163 const address *addr1, guint port1)
165 if (addr0 == NULL || addr1 == NULL || addr0->type != addr1->type ||
166 port0 > G_MAXUINT16 || port1 > G_MAXUINT16 ) {
167 return FALSE;
170 if (find_tcp_index || find_tcp_addr) {
171 return FALSE;
174 switch (addr0->type) {
175 default:
176 return FALSE;
177 case AT_IPv4:
178 case AT_IPv6:
179 is_ipv6 = addr0->type == AT_IPv6;
180 break;
183 find_tcp_index = TRUE;
185 memcpy(ip_address[0], addr0->data, addr0->len);
186 SET_ADDRESS(&tcp_addr[0], addr0->type, addr0->len, ip_address[0]);
187 port[0] = port0;
189 memcpy(ip_address[1], addr1->data, addr1->len);
190 SET_ADDRESS(&tcp_addr[1], addr1->type, addr1->len, ip_address[1]);
191 port[1] = port1;
193 return TRUE;
196 /* select a tcp stream to follow via its index */
197 gboolean
198 follow_tcp_index(guint32 indx)
200 if (find_tcp_index || find_tcp_addr) {
201 return FALSE;
204 if (indx > get_tcp_stream_count()) {
205 return FALSE;
208 find_tcp_addr = TRUE;
209 tcp_stream_to_follow = indx;
210 memset(ip_address, 0, sizeof ip_address);
211 port[0] = port[1] = 0;
213 return TRUE;
216 guint32
217 get_follow_tcp_index(void) {
218 return tcp_stream_to_follow;
221 /* here we are going to try and reconstruct the data portion of a TCP
222 session. We will try and handle duplicates, TCP fragments, and out
223 of order packets in a smart way. */
225 static tcp_frag *frags[2] = { 0, 0 };
226 static guint32 seq[2];
227 static guint8 src_addr[2][MAX_IPADDR_LEN];
228 static guint src_port[2] = { 0, 0 };
230 void
231 reassemble_tcp( guint32 tcp_stream, guint32 sequence, guint32 acknowledgement,
232 guint32 length, const char* data, guint32 data_length,
233 int synflag, address *net_src, address *net_dst,
234 guint srcport, guint dstport) {
235 guint8 srcx[MAX_IPADDR_LEN], dstx[MAX_IPADDR_LEN];
236 int src_index, j, first = 0, len;
237 guint32 newseq;
238 tcp_frag *tmp_frag;
239 tcp_stream_chunk sc;
241 src_index = -1;
243 /* First, check if this packet should be processed. */
244 if (find_tcp_index) {
245 if ((port[0] == srcport && port[1] == dstport &&
246 ADDRESSES_EQUAL(&tcp_addr[0], net_src) &&
247 ADDRESSES_EQUAL(&tcp_addr[1], net_dst))
249 (port[1] == srcport && port[0] == dstport &&
250 ADDRESSES_EQUAL(&tcp_addr[1], net_src) &&
251 ADDRESSES_EQUAL(&tcp_addr[0], net_dst))) {
252 find_tcp_index = FALSE;
253 tcp_stream_to_follow = tcp_stream;
255 else {
256 return;
259 else if ( tcp_stream != tcp_stream_to_follow )
260 return;
262 if ((net_src->type != AT_IPv4 && net_src->type != AT_IPv6) ||
263 (net_dst->type != AT_IPv4 && net_dst->type != AT_IPv6))
264 return;
266 if (net_src->type == AT_IPv4)
267 len = 4;
268 else
269 len = 16;
271 memcpy(srcx, net_src->data, len);
272 memcpy(dstx, net_dst->data, len);
274 /* follow_tcp_index() needs to learn address/port pairs */
275 if (find_tcp_addr) {
276 find_tcp_addr = FALSE;
277 memcpy(ip_address[0], net_src->data, net_src->len);
278 port[0] = srcport;
279 memcpy(ip_address[1], net_dst->data, net_dst->len);
280 port[1] = dstport;
283 /* Check to see if we have seen this source IP and port before.
284 (Yes, we have to check both source IP and port; the connection
285 might be between two different ports on the same machine.) */
286 for( j=0; j<2; j++ ) {
287 if (memcmp(src_addr[j], srcx, len) == 0 && src_port[j] == srcport ) {
288 src_index = j;
291 /* we didn't find it if src_index == -1 */
292 if( src_index < 0 ) {
293 /* assign it to a src_index and get going */
294 for( j=0; j<2; j++ ) {
295 if( src_port[j] == 0 ) {
296 memcpy(src_addr[j], srcx, len);
297 src_port[j] = srcport;
298 src_index = j;
299 first = 1;
300 break;
304 if( src_index < 0 ) {
305 fprintf( stderr, "ERROR in reassemble_tcp: Too many addresses!\n");
306 return;
309 if( data_length < length ) {
310 incomplete_tcp_stream = TRUE;
313 /* Before adding data for this flow to the data_out_file, check whether
314 * this frame acks fragments that were already seen. This happens when
315 * frames are not in the capture file, but were actually seen by the
316 * receiving host (Fixes bug 592).
318 if( frags[1-src_index] ) {
319 memcpy(sc.src_addr, dstx, len);
320 sc.src_port = dstport;
321 sc.dlen = 0; /* Will be filled in in check_fragments */
322 while ( check_fragments( 1-src_index, &sc, acknowledgement ) )
326 /* Initialize our stream chunk. This data gets written to disk. */
327 memcpy(sc.src_addr, srcx, len);
328 sc.src_port = srcport;
329 sc.dlen = data_length;
331 /* now that we have filed away the srcs, lets get the sequence number stuff
332 figured out */
333 if( first ) {
334 /* this is the first time we have seen this src's sequence number */
335 seq[src_index] = sequence + length;
336 if( synflag ) {
337 seq[src_index]++;
339 /* write out the packet data */
340 write_packet_data( src_index, &sc, data );
341 return;
343 /* if we are here, we have already seen this src, let's
344 try and figure out if this packet is in the right place */
345 if( sequence < seq[src_index] ) {
346 /* this sequence number seems dated, but
347 check the end to make sure it has no more
348 info than we have already seen */
349 newseq = sequence + length;
350 if( newseq > seq[src_index] ) {
351 guint32 new_len;
353 /* this one has more than we have seen. let's get the
354 payload that we have not seen. */
356 new_len = seq[src_index] - sequence;
358 if ( data_length <= new_len ) {
359 data = NULL;
360 data_length = 0;
361 incomplete_tcp_stream = TRUE;
362 } else {
363 data += new_len;
364 data_length -= new_len;
366 sc.dlen = data_length;
367 sequence = seq[src_index];
368 length = newseq - seq[src_index];
370 /* this will now appear to be right on time :) */
373 if ( sequence == seq[src_index] ) {
374 /* right on time */
375 seq[src_index] += length;
376 if( synflag ) seq[src_index]++;
377 if( data ) {
378 write_packet_data( src_index, &sc, data );
380 /* done with the packet, see if it caused a fragment to fit */
381 while( check_fragments( src_index, &sc, 0 ) )
384 else {
385 /* out of order packet */
386 if(data_length > 0 && GT_SEQ(sequence, seq[src_index]) ) {
387 tmp_frag = (tcp_frag *)g_malloc( sizeof( tcp_frag ) );
388 tmp_frag->data = (gchar *)g_malloc( data_length );
389 tmp_frag->seq = sequence;
390 tmp_frag->len = length;
391 tmp_frag->data_len = data_length;
392 memcpy( tmp_frag->data, data, data_length );
393 if( frags[src_index] ) {
394 tmp_frag->next = frags[src_index];
395 } else {
396 tmp_frag->next = NULL;
398 frags[src_index] = tmp_frag;
401 } /* end reassemble_tcp */
403 /* here we search through all the frag we have collected to see if
404 one fits */
405 static int
406 check_fragments( int idx, tcp_stream_chunk *sc, guint32 acknowledged ) {
407 tcp_frag *prev = NULL;
408 tcp_frag *current;
409 guint32 lowest_seq;
410 gchar *dummy_str;
412 current = frags[idx];
413 if( current ) {
414 lowest_seq = current->seq;
415 while( current ) {
416 if( GT_SEQ(lowest_seq, current->seq) ) {
417 lowest_seq = current->seq;
420 if( current->seq < seq[idx] ) {
421 guint32 newseq;
422 /* this sequence number seems dated, but
423 check the end to make sure it has no more
424 info than we have already seen */
425 newseq = current->seq + current->len;
426 if( newseq > seq[idx] ) {
427 guint32 new_pos;
429 /* this one has more than we have seen. let's get the
430 payload that we have not seen. This happens when
431 part of this frame has been retransmitted */
433 new_pos = seq[idx] - current->seq;
435 if ( current->data_len > new_pos ) {
436 sc->dlen = current->data_len - new_pos;
437 write_packet_data( idx, sc, current->data + new_pos );
440 seq[idx] += (current->len - new_pos);
443 /* Remove the fragment from the list as the "new" part of it
444 * has been processed or its data has been seen already in
445 * another packet. */
446 if( prev ) {
447 prev->next = current->next;
448 } else {
449 frags[idx] = current->next;
451 g_free( current->data );
452 g_free( current );
453 return 1;
456 if( current->seq == seq[idx] ) {
457 /* this fragment fits the stream */
458 if( current->data ) {
459 sc->dlen = current->data_len;
460 write_packet_data( idx, sc, current->data );
462 seq[idx] += current->len;
463 if( prev ) {
464 prev->next = current->next;
465 } else {
466 frags[idx] = current->next;
468 g_free( current->data );
469 g_free( current );
470 return 1;
472 prev = current;
473 current = current->next;
475 if( GT_SEQ(acknowledged, lowest_seq) ) {
476 /* There are frames missing in the capture file that were seen
477 * by the receiving host. Add dummy stream chunk with the data
478 * "[xxx bytes missing in capture file]".
480 dummy_str = g_strdup_printf("[%d bytes missing in capture file]",
481 (int)(lowest_seq - seq[idx]) );
482 sc->dlen = (guint32) strlen(dummy_str);
483 write_packet_data( idx, sc, dummy_str );
484 g_free(dummy_str);
485 seq[idx] = lowest_seq;
486 return 1;
489 return 0;
492 /* this should always be called before we start to reassemble a stream */
493 void
494 reset_tcp_reassembly(void)
496 tcp_frag *current, *next;
497 int i;
499 empty_tcp_stream = TRUE;
500 incomplete_tcp_stream = FALSE;
501 find_tcp_addr = FALSE;
502 find_tcp_index = FALSE;
503 for( i=0; i<2; i++ ) {
504 seq[i] = 0;
505 memset(src_addr[i], '\0', MAX_IPADDR_LEN);
506 src_port[i] = 0;
507 memset(ip_address[i], '\0', MAX_IPADDR_LEN);
508 port[i] = 0;
509 bytes_written[i] = 0;
510 current = frags[i];
511 while( current ) {
512 next = current->next;
513 g_free( current->data );
514 g_free( current );
515 current = next;
517 frags[i] = NULL;
521 static void
522 write_packet_data( int idx, tcp_stream_chunk *sc, const char *data )
524 size_t ret;
526 ret = fwrite( sc, 1, sizeof(tcp_stream_chunk), data_out_file );
527 DISSECTOR_ASSERT(sizeof(tcp_stream_chunk) == ret);
529 ret = fwrite( data, 1, sc->dlen, data_out_file );
530 DISSECTOR_ASSERT(sc->dlen == ret);
532 bytes_written[idx] += sc->dlen;
533 empty_tcp_stream = FALSE;