implement support to reassemble tcp sessions until the end of the session (FIN)

add required code to the http (and others) code in req_resp_hdrs.c to signal to tcp
when it wants a session to be reassembled to the FIN.

This is currently done for all HTTP packets where we have a Content-type in the header but no content-length.




svn path=/trunk/; revision=19185
This commit is contained in:
Ronnie Sahlberg 2006-09-10 14:03:08 +00:00
parent 9568b76a63
commit 6d3c94a53a
4 changed files with 109 additions and 12 deletions

View File

@ -246,6 +246,7 @@ get_tcp_conversation_data(packet_info *pinfo)
tcpd->flow1.nextseqframe=0;
tcpd->flow1.window=0;
tcpd->flow1.win_scale=-1;
tcpd->flow1.flags=0;
tcpd->flow1.multisegment_pdus=se_tree_create_non_persistent(EMEM_TREE_TYPE_RED_BLACK, "tcp_multisegment_pdus");
tcpd->flow2.segments=NULL;
tcpd->flow2.base_seq=0;
@ -259,6 +260,7 @@ get_tcp_conversation_data(packet_info *pinfo)
tcpd->flow2.nextseqframe=0;
tcpd->flow2.window=0;
tcpd->flow2.win_scale=-1;
tcpd->flow2.flags=0;
tcpd->flow2.multisegment_pdus=se_tree_create_non_persistent(EMEM_TREE_TYPE_RED_BLACK, "tcp_multisegment_pdus");
tcpd->acked_table=se_tree_create_non_persistent(EMEM_TREE_TYPE_RED_BLACK, "tcp_analyze_acked_table");
@ -1291,6 +1293,16 @@ again:
}
if (must_desegment) {
/* If the dissector requested "reassemble until FIN"
* just set this flag for the flow and let reassembly
* proceed at normal. We will check/pick up these
* reassembled PDUs later down in dissect_tcp() when checking
* for the FIN flag.
*/
if(pinfo->desegment_len==DESEGMENT_UNTIL_FIN){
tcpd->fwd->flags|=TCP_FLOW_REASSEMBLE_UNTIL_FIN;
}
/*
* The sequence number at which the stuff to be desegmented
* starts is the sequence number of the byte at an offset
@ -1303,19 +1315,18 @@ again:
*/
deseg_seq = seq + (deseg_offset - offset);
if ((nxtseq - deseg_seq) <= 1024*1024) {
if(!pinfo->fd->flags.visited){
msp = pdu_store_sequencenumber_of_next_pdu(pinfo, deseg_seq,
nxtseq + pinfo->desegment_len, tcpd);
if( ((nxtseq - deseg_seq) <= 1024*1024)
&& (!pinfo->fd->flags.visited) ){
msp = pdu_store_sequencenumber_of_next_pdu(pinfo, deseg_seq,
nxtseq + pinfo->desegment_len, tcpd);
/* add this segment as the first one for this new pdu */
fragment_add(tvb, deseg_offset, pinfo, msp->first_frame,
tcp_fragment_table,
0,
nxtseq - deseg_seq,
LT_SEQ(nxtseq, msp->nxtpdu));
/* add this segment as the first one for this new pdu */
fragment_add(tvb, deseg_offset, pinfo, msp->first_frame,
tcp_fragment_table,
0,
nxtseq - deseg_seq,
LT_SEQ(nxtseq, msp->nxtpdu));
}
}
}
if (!called_dissector || pinfo->desegment_len != 0) {
@ -2465,6 +2476,52 @@ dissect_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
}
tap_queue_packet(tcp_tap, pinfo, tcph);
/* A FIN packet might complete reassembly so we need to explicitely
* check for this here.
* If this segment completes reassembly we add the FIN as a final dummy
* byte to the reassembled PDU and check if reassembly completed successfully
*/
if( (tcph->th_flags & TH_FIN)
&& (tcpd->fwd->flags&TCP_FLOW_REASSEMBLE_UNTIL_FIN) ){
struct tcp_multisegment_pdu *msp;
/* find the most previous PDU starting before this sequence number */
msp=se_tree_lookup32_le(tcpd->fwd->multisegment_pdus, tcph->th_seq-1);
if(msp){
fragment_data *ipfd_head;
ipfd_head = fragment_add(tvb, offset-1, pinfo, msp->first_frame,
tcp_fragment_table,
tcph->th_seq - msp->seq,
1,
FALSE );
if(ipfd_head){
tvbuff_t *next_tvb;
/* create a new TVB structure for desegmented data
* datalen-1 to strip the dummy FIN byte off
*/
next_tvb = tvb_new_real_data(ipfd_head->data, ipfd_head->datalen-1, ipfd_head->datalen-1);
/* add this tvb as a child to the original one */
tvb_set_child_real_data_tvbuff(tvb, next_tvb);
/* add desegmented data to the data source list */
add_new_data_source(pinfo, next_tvb, "Reassembled TCP");
/* call the payload dissector
* but make sure we dont offer desegmentation any more
*/
pinfo->can_desegment = 0;
process_tcp_payload(next_tvb, 0, pinfo, tree, tcp_tree, tcph->th_sport, tcph->th_dport, tcph->th_seq, nxtseq, FALSE, tcpd);
return;
}
}
}
/*
* XXX - what, if any, of this should we do if this is included in an
* error packet? It might be nice to see the details of the packet

View File

@ -137,6 +137,11 @@ typedef struct _tcp_flow_t {
*/
guint32 window; /* last seen window */
gint16 win_scale; /* -1 is we dont know */
/* This tcp flow/session contains only one single PDU and should
* be reassembled until the final FIN segment.
*/
#define TCP_FLOW_REASSEMBLE_UNTIL_FIN 0x0001
guint16 flags;
guint32 lastsegmentflags;
/* This tree is indexed by sequence number and keeps track of all

View File

@ -85,7 +85,17 @@ typedef struct _packet_info {
finished setting things up, so the TCP
desegmentor can desegment its payload). */
int desegment_offset; /* offset to stuff needing desegmentation */
guint32 desegment_len; /* requested desegmentation additional length */
#define DESEGMENT_ONE_MORE_SEGMENT 0x0fffffff
#define DESEGMENT_UNTIL_FIN 0x0ffffffe
guint32 desegment_len; /* requested desegmentation additional length
or
DESEGMENT_ONE_MORE_SEGMENT:
Desegment one more full segment
(not yet implemented)
DESEGMENT_UNTIL_FIN:
Desgment all data for this tcp session
until the FIN segment.
*/
guint16 want_pdu_tracking; /* >0 if the subdissector has specified
a value in 'bytes_until_next_pdu'.
When a dissector detects that the next PDU

View File

@ -48,6 +48,7 @@ req_resp_hdrs_do_reassembly(tvbuff_t *tvb, int offset, packet_info *pinfo,
gchar *header_val;
long int content_length;
gboolean content_length_found = FALSE;
gboolean content_type_found = FALSE;
gboolean chunked_encoding = FALSE;
/*
@ -154,6 +155,9 @@ req_resp_hdrs_do_reassembly(tvbuff_t *tvb, int offset, packet_info *pinfo,
== 1)
content_length_found = TRUE;
g_free(header_val);
} else if (tvb_strncaseeql(tvb, next_offset_sav,
"Content-Type:", 13) == 0) {
content_type_found = TRUE;
} else if (tvb_strncaseeql(tvb,
next_offset_sav,
"Transfer-Encoding:", 18) == 0) {
@ -329,6 +333,27 @@ req_resp_hdrs_do_reassembly(tvbuff_t *tvb, int offset, packet_info *pinfo,
}
}
} else if (content_type_found && pinfo->can_desegment) {
/* We found a content-type but no content-length.
* This is probably a HTTP header for a session with
* only one HTTP PDU and where the content spans
* until the end of the tcp session.
* Set up tcp reassembly until the end of this session.
*/
length_remaining = tvb_length_remaining(tvb, next_offset);
reported_length_remaining = tvb_reported_length_remaining(tvb, next_offset);
if (length_remaining < reported_length_remaining) {
/*
* It's a waste of time asking for more
* data, because that data wasn't captured.
*/
return TRUE;
}
pinfo->desegment_offset = offset;
pinfo->desegment_len = DESEGMENT_UNTIL_FIN;
return FALSE;
}
}