aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--AUTHORS3
-rw-r--r--packet-tcp.c175
-rw-r--r--reassemble.c86
-rw-r--r--reassemble.h18
4 files changed, 211 insertions, 71 deletions
diff --git a/AUTHORS b/AUTHORS
index 9a79273a33..fce8b22824 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -1010,6 +1010,9 @@ Jirka Novak <j.novak[AT]netsystem.cz> {
Ricardo Barroetaveña <rbarroetavena[AT]veufort.com> {
Enhanced LDP support
+ Support TCP reassembly requiring multiple steps (e.g.,
+ reassemble the PDU header to get the length of the PDU, then
+ reassemble the PDU based on that length)
}
Alan Harrison <alanharrison[AT]mail.com> {
diff --git a/packet-tcp.c b/packet-tcp.c
index 89cbca6892..59e9626b76 100644
--- a/packet-tcp.c
+++ b/packet-tcp.c
@@ -1,7 +1,7 @@
/* packet-tcp.c
* Routines for TCP packet disassembly
*
- * $Id: packet-tcp.c,v 1.129 2002/02/03 21:44:52 guy Exp $
+ * $Id: packet-tcp.c,v 1.130 2002/02/03 23:28:38 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
@@ -365,28 +365,20 @@ desegment_tcp(tvbuff_t *tvb, packet_info *pinfo, int offset,
proto_tree *st = NULL;
proto_item *si = NULL;
- /* first we show a tree with all segments */
- si = proto_tree_add_text(tcp_tree, tvb, 0, 0,
- "Segments");
- st = proto_item_add_subtree(si, ett_tcp_segments);
- for(ipfd=ipfd_head->next; ipfd; ipfd=ipfd->next){
- proto_tree_add_text(st, tvb, 0, 0,
- "Frame:%u seq#:%u-%u [%u-%u]",
- ipfd->frame,
- tsk->start_seq + ipfd->offset,
- tsk->start_seq + ipfd->offset + ipfd->len - 1,
- ipfd->offset,
- ipfd->offset + ipfd->len - 1);
- }
-
/*
+ * Yes, we think it is.
* We only call subdissector for the last segment.
* Note that the last segment may include more than what
* we needed.
*/
if(nxtseq >= (tsk->start_seq + tsk->tot_len)){
- /* ok, lest call subdissector with desegmented data */
+ /*
+ * OK, this is the last segment.
+ * Let's call the subdissector with the desegmented
+ * data.
+ */
tvbuff_t *next_tvb;
+ int old_len;
/* create a new TVB structure for desegmented data */
next_tvb = tvb_new_real_data(ipfd_head->data,
@@ -407,56 +399,119 @@ desegment_tcp(tvbuff_t *tvb, packet_info *pinfo, int offset,
sport, dport);
called_dissector = TRUE;
- /* Did the subdissector ask us to desegment some more
- data? This means that the data at the beginning
- of this segment completed a higher-level PDU,
- but the data at the end of this segment started
- a higher-level PDU but didn't complete it.
-
- If so we have to create some structures in our
- table but this is something we only do the first
- time we see this packet.
- */
- if(pinfo->desegment_len) {
- if (!pinfo->fd->flags.visited)
- must_desegment = TRUE;
+ /*
+ * OK, did the subdissector think it was completely
+ * desegmented, or does it think we need even more
+ * data?
+ */
+ old_len=(int)(tvb_reported_length(next_tvb)-tvb_reported_length_remaining(tvb, offset));
+ if(pinfo->desegment_len &&
+ pinfo->desegment_offset<=old_len){
+ tcp_segment_key *new_tsk;
/*
- * The stuff we couldn't dissect must have
- * come from this segment, so it's all in
- * "tvb".
- *
- * "pinfo->desegment_offset" is relative
- * to the beginning of "next_tvb";
- * we want an offset relative to the
- * beginning of "tvb".
- *
- * First, compute the offset relative to
- * the *end* of "next_tvb" - i.e., the number
- * of bytes before the end of "next_tvb"
- * at which the subdissector stopped.
- * That's the length of "next_tvb" minus
- * the offset, relative to the beginning
- * of "next_tvb, at which the subdissector
- * stopped.
+ * "desegment_len" isn't 0, so it needs more
+ * data for something - and "desegment_offset"
+ * is before "old_len", so it needs more data
+ * to dissect the stuff we thought was
+ * completely desegmented (as opposed to the
+ * stuff at the beginning being completely
+ * desegmented, but the stuff at the end
+ * being a new higher-level PDU that also
+ * needs desegmentation).
*/
- deseg_offset =
- ipfd_head->datalen - pinfo->desegment_offset;
+ fragment_set_partial_reassembly(pinfo,tsk->start_seq,tcp_fragment_table);
+ tsk->tot_len = tvb_reported_length(next_tvb) + pinfo->desegment_len;
/*
- * "tvb" and "next_tvb" end at the same byte
- * of data, so the offset relative to the
- * end of "next_tvb" of the byte at which
- * we stopped is also the offset relative
- * to the end of "tvb" of the byte at which
- * we stopped.
- *
- * Convert that back into an offset relative
- * to the beginninng of "tvb", by taking
- * the length of "tvb" and subtracting the
- * offset relative to the end.
+ * Update tsk structure.
+ * Can ask ->next->next because at least there's a hdr and one
+ * entry in fragment_add()
+ */
+ for(ipfd=ipfd_head->next; ipfd->next; ipfd=ipfd->next){
+ old_tsk.seq = tsk->start_seq + ipfd->offset;
+ new_tsk = g_hash_table_lookup(tcp_segment_table, &old_tsk);
+ new_tsk->tot_len = tsk->tot_len;
+ }
+
+ /* this is the next segment in the sequence we want */
+ new_tsk = g_mem_chunk_alloc(tcp_segment_key_chunk);
+ memcpy(new_tsk, tsk, sizeof(tcp_segment_key));
+ new_tsk->seq = nxtseq;
+ g_hash_table_insert(tcp_segment_table,new_tsk,new_tsk);
+ } else {
+ /*
+ * The subdissector thought it was completely
+ * desegmented (although the stuff at the
+ * end may, in turn, require desegmentation),
+ * so we show a tree with all segments.
*/
- deseg_offset = tvb_length(tvb) - deseg_offset;
+ si = proto_tree_add_text(tcp_tree, tvb, 0, 0,
+ "Segments");
+ st = proto_item_add_subtree(si, ett_tcp_segments);
+ for(ipfd=ipfd_head->next; ipfd; ipfd=ipfd->next){
+ proto_tree_add_text(st, tvb, 0, 0,
+ "Frame:%u seq#:%u-%u [%u-%u]",
+ ipfd->frame,
+ tsk->start_seq + ipfd->offset,
+ tsk->start_seq + ipfd->offset + ipfd->len-1,
+ ipfd->offset,
+ ipfd->offset + ipfd->len - 1);
+ }
+
+ /* Did the subdissector ask us to desegment
+ some more data? This means that the data
+ at the beginning of this segment completed
+ a higher-level PDU, but the data at the
+ end of this segment started a higher-level
+ PDU but didn't complete it.
+
+ If so, we have to create some structures
+ in our table, but this is something we
+ only do the first time we see this packet.
+ */
+ if(pinfo->desegment_len) {
+ if (!pinfo->fd->flags.visited)
+ must_desegment = TRUE;
+
+ /* The stuff we couldn't dissect
+ must have come from this segment,
+ so it's all in "tvb".
+
+ "pinfo->desegment_offset" is
+ relative to the beginning of
+ "next_tvb"; we want an offset
+ relative to the beginning of "tvb".
+
+ First, compute the offset relative
+ to the *end* of "next_tvb" - i.e.,
+ the number of bytes before the end
+ of "next_tvb" at which the
+ subdissector stopped. That's the
+ length of "next_tvb" minus the
+ offset, relative to the beginning
+ of "next_tvb, at which the
+ subdissector stopped.
+ */
+ deseg_offset =
+ ipfd_head->datalen - pinfo->desegment_offset;
+
+ /* "tvb" and "next_tvb" end at the
+ same byte of data, so the offset
+ relative to the end of "next_tvb"
+ of the byte at which we stopped
+ is also the offset relative to
+ the end of "tvb" of the byte at
+ which we stopped.
+
+ Convert that back into an offset
+ relative to the beginninng of
+ "tvb", by taking the length of
+ "tvb" and subtracting the offset
+ relative to the end.
+ */
+ deseg_offset=tvb_reported_length(tvb) - deseg_offset;
+ }
}
}
}
diff --git a/reassemble.c b/reassemble.c
index 40a919f507..b043c524e7 100644
--- a/reassemble.c
+++ b/reassemble.c
@@ -1,7 +1,7 @@
/* reassemble.c
* Routines for {fragment,segment} reassembly
*
- * $Id: reassemble.c,v 1.8 2002/01/21 07:36:48 guy Exp $
+ * $Id: reassemble.c,v 1.9 2002/02/03 23:28:38 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
@@ -45,12 +45,12 @@ static int fragment_init_count = 200;
#define LINK_FRAG(fd_head,fd) \
{ fragment_data *fd_i; \
/* add fragment to list, keep list sorted */ \
- for(fd_i=fd_head;fd_i->next;fd_i=fd_i->next){ \
- if( (fd->offset) < (fd_i->next->offset) ) \
+ for(fd_i=(fd_head);fd_i->next;fd_i=fd_i->next){ \
+ if( ((fd)->offset) < (fd_i->next->offset) ) \
break; \
} \
- fd->next=fd_i->next; \
- fd_i->next=fd; \
+ (fd)->next=fd_i->next; \
+ fd_i->next=(fd); \
}
static gint
@@ -126,7 +126,7 @@ free_all_fragments(gpointer key_arg, gpointer value, gpointer user_data)
g_free((gpointer)key->dst.data);
for (fd_head = value; fd_head != NULL; fd_head = fd_head->next) {
- if (fd_head->data)
+ if(fd_head->data && !(fd_head->flags&FD_NOT_MALLOCED))
g_free(fd_head->data);
}
@@ -213,7 +213,8 @@ fragment_delete(packet_info *pinfo, guint32 id, GHashTable *fragment_table)
fragment_data *tmp_fd;
tmp_fd=fd->next;
- g_free(fd->data);
+ if( !(fd->flags&FD_NOT_MALLOCED) )
+ g_free(fd->data);
g_mem_chunk_free(fragment_data_chunk, fd);
fd=tmp_fd;
}
@@ -277,6 +278,32 @@ fragment_set_tot_len(packet_info *pinfo, guint32 id, GHashTable *fragment_table,
return;
}
+
+/* This function will set the partial reassembly flag for a fh.
+ When this function is called, the fh MUST already exist, i.e.
+ the fh MUST be created by the initial call to fragment_add() before
+ this function is called.
+ Also note that this function MUST be called to indicate a fh will be
+ extended (increase the already stored data)
+*/
+
+void
+fragment_set_partial_reassembly(packet_info *pinfo, guint32 id, GHashTable *fragment_table)
+{
+ fragment_data *fd_head;
+ fragment_key key;
+
+ /* create key to search hash with */
+ key.src = pinfo->src;
+ key.dst = pinfo->dst;
+ key.id = id;
+
+ fd_head = g_hash_table_lookup(fragment_table, &key);
+
+ if(fd_head){
+ fd_head->flags |= FD_PARTIAL_REASSEMBLY;
+ }
+}
/*
* This function adds a new fragment to the fragment hash table.
* If this is the first fragment seen for this datagram, a new entry
@@ -290,6 +317,13 @@ fragment_set_tot_len(packet_info *pinfo, guint32 id, GHashTable *fragment_table,
*
* This function assumes frag_offset being a byte offset into the defragment
* packet.
+ *
+ * 01-2002
+ * Once the fh is defragmented (= FD_DEFRAGMENTED set), it can be
+ * extended using the FD_PARTIAL_REASSEMBLY flag. This flag should be set
+ * using fragment_set_partial_reassembly() before calling fragment_add
+ * with the new fragment. FD_TOOLONGFRAGMENT and FD_MULTIPLETAILS flags
+ * are lowered when a new extension process is started.
*/
fragment_data *
fragment_add(tvbuff_t *tvb, int offset, packet_info *pinfo, guint32 id,
@@ -301,6 +335,7 @@ fragment_add(tvbuff_t *tvb, int offset, packet_info *pinfo, guint32 id,
fragment_data *fd;
fragment_data *fd_i;
guint32 max, dfpos;
+ unsigned char *old_data;
/* create key to search hash with */
key.src = pinfo->src;
@@ -356,6 +391,24 @@ fragment_add(tvbuff_t *tvb, int offset, packet_info *pinfo, guint32 id,
fd->len = frag_data_len;
fd->data = NULL;
+ /*
+ * If it was already defragmented and this new fragment goes beyond
+ * data limits, set flag in already empty fds & point old fds to malloc'ed data.
+ */
+ if(fd_head->flags & FD_DEFRAGMENTED && (frag_offset+frag_data_len) >= fd_head->datalen &&
+ fd_head->flags & FD_PARTIAL_REASSEMBLY){
+ for(fd_i=fd_head->next; fd_i; fd_i=fd_i->next){
+ if( !fd_i->data ) {
+ fd_i->data = fd_head->data + fd_i->offset;
+ fd_i->flags |= FD_NOT_MALLOCED;
+ }
+ fd_i->flags &= (~FD_TOOLONGFRAGMENT) & (~FD_MULTIPLETAILS);
+ }
+ fd_head->flags ^= FD_DEFRAGMENTED|FD_PARTIAL_REASSEMBLY;
+ fd_head->flags &= (~FD_TOOLONGFRAGMENT) & (~FD_MULTIPLETAILS);
+ fd_head->datalen=0;
+ }
+
if (!more_frags) {
/*
* This is the tail fragment in the sequence.
@@ -448,6 +501,8 @@ fragment_add(tvbuff_t *tvb, int offset, packet_info *pinfo, guint32 id,
if (max > (fd_head->datalen)) {
+ /*XXX not sure if current fd was the TOOLONG*/
+ /*XXX is it fair to flag current fd*/
/* oops, too long fragment detected */
fd->flags |= FD_TOOLONGFRAGMENT;
fd_head->flags |= FD_TOOLONGFRAGMENT;
@@ -457,6 +512,8 @@ fragment_add(tvbuff_t *tvb, int offset, packet_info *pinfo, guint32 id,
/* we have received an entire packet, defragment it and
* free all fragments
*/
+ /* store old data just in case */
+ old_data=fd_head->data;
fd_head->data = g_malloc(max);
/* add all data fragments */
@@ -472,15 +529,24 @@ fragment_add(tvbuff_t *tvb, int offset, packet_info *pinfo, guint32 id,
fd_i->flags |= FD_OVERLAPCONFLICT;
fd_head->flags |= FD_OVERLAPCONFLICT;
}
- }
- memcpy(fd_head->data+fd_i->offset,fd_i->data,fd_i->len);
- g_free(fd_i->data);
+ }
+ /* dfpos is always >= than fd_i->offset */
+ /* No gaps can exist here, max_loop(above) does this */
+ if( fd_i->offset+fd_i->len > dfpos )
+ memcpy(fd_head->data+dfpos, fd_i->data+(dfpos-fd_i->offset),
+ fd_i->len-(dfpos-fd_i->offset));
+ if( fd_i->flags & FD_NOT_MALLOCED )
+ fd_i->flags ^= FD_NOT_MALLOCED;
+ else
+ g_free(fd_i->data);
fd_i->data=NULL;
dfpos=MAX(dfpos,(fd_i->offset+fd_i->len));
}
}
+ if( old_data )
+ g_free(old_data);
/* mark this packet as defragmented.
allows us to skip any trailing fragments */
fd_head->flags |= FD_DEFRAGMENTED;
diff --git a/reassemble.h b/reassemble.h
index cdfd15b07c..15f95195e9 100644
--- a/reassemble.h
+++ b/reassemble.h
@@ -1,7 +1,7 @@
/* reassemble.h
* Declarations of outines for {fragment,segment} reassembly
*
- * $Id: reassemble.h,v 1.3 2001/12/15 05:40:32 guy Exp $
+ * $Id: reassemble.h,v 1.4 2002/02/03 23:28:38 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
@@ -41,6 +41,12 @@
/* fragment contains data past the end of the datagram */
#define FD_TOOLONGFRAGMENT 0x0010
+/* fragment data not alloced, fd->data pointing to fd_head->data+fd->offset */
+#define FD_NOT_MALLOCED 0x0020
+
+/* this flag is used to request fragment_add to continue the reassembly process */
+#define FD_PARTIAL_REASSEMBLY 0x0040
+
/* fragment offset is indicated by sequence number and not byte offset
into the defragmented packet */
#define FD_BLOCKSEQUENCE 0x0100
@@ -96,6 +102,16 @@ fragment_data *fragment_add_seq(tvbuff_t *tvb, int offset, packet_info *pinfo,
void
fragment_set_tot_len(packet_info *pinfo, guint32 id, GHashTable *fragment_table,
guint32 tot_len);
+/*
+ * This function will set the partial reassembly flag(FD_PARTIAL_REASSEMBLY) for a fh.
+ * When this function is called, the fh MUST already exist, i.e.
+ * the fh MUST be created by the initial call to fragment_add() before
+ * this function is called. Also note that this function MUST be called to indicate
+ * a fh will be extended (increase the already stored data). After calling this function,
+ * and if FD_DEFRAGMENTED is set, the reassembly process will be continued.
+ */
+void
+fragment_set_partial_reassembly(packet_info *pinfo, guint32 id, GHashTable *fragment_table);
/* This function is used to check if there is partial or completed reassembly state
* matching this packet. I.e. Are there reassembly going on or not for this packet?