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:
parent
9568b76a63
commit
6d3c94a53a
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue