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.
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>
43 #include <epan/conversation.h>
45 #define MAX_IPADDR_LEN 16
47 typedef struct _tcp_frag
{
52 struct _tcp_frag
*next
;
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
];
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 * );
71 follow_stats(follow_stats_t
* stats
)
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
88 build_follow_conv_filter( packet_info
*pi
) {
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
) {
100 tcpd
=get_tcp_conversation_data(conv
, pi
);
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
) {
115 else if( pi
->net_src
.type
== AT_IPv4
&& pi
->net_dst
.type
== AT_IPv4
116 && pi
->ipproto
== IP_PROTO_UDP
) {
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
);
126 else if( pi
->net_src
.type
== AT_IPv6
&& pi
->net_dst
.type
== AT_IPv6
127 && pi
->ipproto
== IP_PROTO_UDP
) {
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
);
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
;
147 static gboolean find_tcp_addr
;
148 static address tcp_addr
[2];
149 static gboolean find_tcp_index
;
152 build_follow_index_filter(void) {
155 find_tcp_addr
= TRUE
;
156 buf
= g_strdup_printf("tcp.stream eq %d", tcp_stream_to_follow
);
160 /* select a tcp stream to follow via it's address/port pairs */
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
) {
170 if (find_tcp_index
|| find_tcp_addr
) {
174 switch (addr0
->type
) {
179 is_ipv6
= addr0
->type
== AT_IPv6
;
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]);
189 memcpy(ip_address
[1], addr1
->data
, addr1
->len
);
190 SET_ADDRESS(&tcp_addr
[1], addr1
->type
, addr1
->len
, ip_address
[1]);
196 /* select a tcp stream to follow via its index */
198 follow_tcp_index(guint32 indx
)
200 if (find_tcp_index
|| find_tcp_addr
) {
204 if (indx
> get_tcp_stream_count()) {
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;
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 };
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
;
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
;
259 else if ( tcp_stream
!= tcp_stream_to_follow
)
262 if ((net_src
->type
!= AT_IPv4
&& net_src
->type
!= AT_IPv6
) ||
263 (net_dst
->type
!= AT_IPv4
&& net_dst
->type
!= AT_IPv6
))
266 if (net_src
->type
== AT_IPv4
)
271 memcpy(srcx
, net_src
->data
, len
);
272 memcpy(dstx
, net_dst
->data
, len
);
274 /* follow_tcp_index() needs to learn address/port pairs */
276 find_tcp_addr
= FALSE
;
277 memcpy(ip_address
[0], net_src
->data
, net_src
->len
);
279 memcpy(ip_address
[1], net_dst
->data
, net_dst
->len
);
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
) {
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
;
304 if( src_index
< 0 ) {
305 fprintf( stderr
, "ERROR in reassemble_tcp: Too many addresses!\n");
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
334 /* this is the first time we have seen this src's sequence number */
335 seq
[src_index
] = sequence
+ length
;
339 /* write out the packet data */
340 write_packet_data( src_index
, &sc
, data
);
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
] ) {
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
) {
361 incomplete_tcp_stream
= TRUE
;
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
] ) {
375 seq
[src_index
] += length
;
376 if( synflag
) seq
[src_index
]++;
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 ) )
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
];
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
406 check_fragments( int idx
, tcp_stream_chunk
*sc
, guint32 acknowledged
) {
407 tcp_frag
*prev
= NULL
;
412 current
= frags
[idx
];
414 lowest_seq
= current
->seq
;
416 if( GT_SEQ(lowest_seq
, current
->seq
) ) {
417 lowest_seq
= current
->seq
;
420 if( current
->seq
< seq
[idx
] ) {
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
] ) {
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
447 prev
->next
= current
->next
;
449 frags
[idx
] = current
->next
;
451 g_free( current
->data
);
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
;
464 prev
->next
= current
->next
;
466 frags
[idx
] = current
->next
;
468 g_free( current
->data
);
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
);
485 seq
[idx
] = lowest_seq
;
492 /* this should always be called before we start to reassemble a stream */
494 reset_tcp_reassembly(void)
496 tcp_frag
*current
, *next
;
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
++ ) {
505 memset(src_addr
[i
], '\0', MAX_IPADDR_LEN
);
507 memset(ip_address
[i
], '\0', MAX_IPADDR_LEN
);
509 bytes_written
[i
] = 0;
512 next
= current
->next
;
513 g_free( current
->data
);
522 write_packet_data( int idx
, tcp_stream_chunk
*sc
, const char *data
)
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
;