aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRonnie Sahlberg <ronnie_sahlberg@ozemail.com.au>2006-09-10 14:03:08 +0000
committerRonnie Sahlberg <ronnie_sahlberg@ozemail.com.au>2006-09-10 14:03:08 +0000
commit6d3c94a53aa8deac5f524248c3dd89c54a92bf5a (patch)
tree3c7c1b9828872c00fd0d73a709701b6034ed820d
parent9568b76a63d8f52b35262d7953b2270c2e19f9a0 (diff)
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
-rw-r--r--epan/dissectors/packet-tcp.c81
-rw-r--r--epan/dissectors/packet-tcp.h5
-rw-r--r--epan/packet_info.h12
-rw-r--r--epan/req_resp_hdrs.c25
4 files changed, 110 insertions, 13 deletions
diff --git a/epan/dissectors/packet-tcp.c b/epan/dissectors/packet-tcp.c
index e081266f80..dcb8e2bcd0 100644
--- a/epan/dissectors/packet-tcp.c
+++ b/epan/dissectors/packet-tcp.c
@@ -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);
-
- /* 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( ((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));
}
- }
}
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
diff --git a/epan/dissectors/packet-tcp.h b/epan/dissectors/packet-tcp.h
index 3e75b26e01..bc9f87b136 100644
--- a/epan/dissectors/packet-tcp.h
+++ b/epan/dissectors/packet-tcp.h
@@ -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
diff --git a/epan/packet_info.h b/epan/packet_info.h
index 28b392ee10..21b35306a9 100644
--- a/epan/packet_info.h
+++ b/epan/packet_info.h
@@ -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
diff --git a/epan/req_resp_hdrs.c b/epan/req_resp_hdrs.c
index cbc861de3e..5696c51558 100644
--- a/epan/req_resp_hdrs.c
+++ b/epan/req_resp_hdrs.c
@@ -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;
}
}