diff options
author | guy <guy@f5534014-38df-0310-8fa8-9805f1628bb7> | 2001-06-08 06:27:16 +0000 |
---|---|---|
committer | guy <guy@f5534014-38df-0310-8fa8-9805f1628bb7> | 2001-06-08 06:27:16 +0000 |
commit | b26ff6207728b7b02cd8b29fc5310b983fe9b53e (patch) | |
tree | 7c0357f6cc77b6e5400dce6519619e41c1a8388d | |
parent | afebf3bcc2db298607a5d728559b5a8c7c9a927d (diff) |
Move the fragment reassembly code into "reassemble.c" and
"reassemble.h", and remove IPv4 dependencies from it.
Use it for OSI CLNP segment reassembly as well.
git-svn-id: http://anonsvn.wireshark.org/wireshark/trunk@3525 f5534014-38df-0310-8fa8-9805f1628bb7
-rw-r--r-- | Makefile.am | 5 | ||||
-rw-r--r-- | Makefile.nmake | 3 | ||||
-rw-r--r-- | file.c | 15 | ||||
-rw-r--r-- | packet-clnp.c | 224 | ||||
-rw-r--r-- | packet-ip.c | 345 | ||||
-rw-r--r-- | reassemble.c | 371 | ||||
-rw-r--r-- | reassemble.h | 77 | ||||
-rw-r--r-- | tethereal.c | 15 |
8 files changed, 718 insertions, 337 deletions
diff --git a/Makefile.am b/Makefile.am index e82836bc7d..4389706492 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,12 +1,11 @@ # Makefile.am # Automake file for Ethereal # -# $Id: Makefile.am,v 1.332 2001/06/06 01:30:28 guy Exp $ +# $Id: Makefile.am,v 1.333 2001/06/08 06:27:15 guy Exp $ # # Ethereal - Network traffic analyzer # By Gerald Combs <gerald@ethereal.com> # Copyright 1998 Gerald Combs -# # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -373,6 +372,8 @@ ETHEREAL_COMMON_SRC = \ ps.h \ ptvcursor.c \ ptvcursor.h \ + reassemble.c \ + reassemble.h \ register.c \ register.h \ smb.h \ diff --git a/Makefile.nmake b/Makefile.nmake index 889eca633e..3cc8355879 100644 --- a/Makefile.nmake +++ b/Makefile.nmake @@ -1,7 +1,7 @@ ## Makefile for building ethereal.exe with Microsoft C and nmake ## Use: $(MAKE) /$(MAKEFLAGS) -f makefile.nmake # -# $Id: Makefile.nmake,v 1.114 2001/06/06 01:30:28 guy Exp $ +# $Id: Makefile.nmake,v 1.115 2001/06/08 06:27:15 guy Exp $ include config.nmake include <win32.mak> @@ -220,6 +220,7 @@ ETHEREAL_COMMON_OBJECTS = \ print.obj \ ps.obj \ ptvcursor.obj \ + reassemble.obj \ register.obj \ util.obj \ xdlc.obj \ @@ -1,7 +1,7 @@ /* file.c * File I/O routines * - * $Id: file.c,v 1.238 2001/06/05 07:38:33 guy Exp $ + * $Id: file.c,v 1.239 2001/06/08 06:27:15 guy Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs <gerald@ethereal.com> @@ -88,6 +88,7 @@ #include "gtk/packet_win.h" #include "dfilter/dfilter.h" #include "conversation.h" +#include "reassemble.h" #include "globals.h" #include "gtk/colors.h" @@ -149,6 +150,12 @@ open_cap_file(char *fname, gboolean is_tempfile, capture_file *cf) /* Initialize protocol-specific variables */ init_all_protocols(); + /* Initialize the common data structures for fragment reassembly. + Must be done *after* "init_all_protocols()", as "init_all_protocols()" + may free up space for fragments, which it finds by using the + data structures that "reassemble_init()" frees. */ + reassemble_init(); + /* We're about to start reading the file. */ cf->state = FILE_READ_IN_PROGRESS; @@ -912,6 +919,12 @@ rescan_packets(capture_file *cf, const char *action, gboolean refilter, /* Initialize protocol-specific variables */ init_all_protocols(); + + /* Initialize the common data structures for fragment reassembly. + Must be done *after* "init_all_protocols()", as "init_all_protocols()" + may free up space for fragments, which it finds by using the + data structures that "reassemble_init()" frees. */ + reassemble_init(); } /* Freeze the packet list while we redo it, so we don't get any diff --git a/packet-clnp.c b/packet-clnp.c index 78ec69e43d..9d0ba98a99 100644 --- a/packet-clnp.c +++ b/packet-clnp.c @@ -1,7 +1,7 @@ /* packet-clnp.c * Routines for ISO/OSI network and transport protocol packet disassembly * - * $Id: packet-clnp.c,v 1.29 2001/06/05 09:06:19 guy Exp $ + * $Id: packet-clnp.c,v 1.30 2001/06/08 06:27:15 guy Exp $ * Laurent Deniel <deniel@worldnet.fr> * Ralf Schneider <Ralf.Schneider@t-online.de> * @@ -39,6 +39,7 @@ #include <glib.h> #include "prefs.h" #include "packet.h" +#include "reassemble.h" #include "packet-osi.h" #include "packet-osi-options.h" #include "packet-isis.h" @@ -50,6 +51,8 @@ static int proto_clnp = -1; static gint ett_clnp = -1; static gint ett_clnp_type = -1; +static gint ett_clnp_segments = -1; +static gint ett_clnp_segment = -1; static gint ett_clnp_disc_pdu = -1; static int proto_cotp = -1; static gint ett_cotp = -1; @@ -67,6 +70,13 @@ static int hf_clnp_dest_length = -1; static int hf_clnp_dest = -1; static int hf_clnp_src_length = -1; static int hf_clnp_src = -1; +static int hf_clnp_segments = -1; +static int hf_clnp_segment = -1; +static int hf_clnp_segment_overlap = -1; +static int hf_clnp_segment_overlap_conflict = -1; +static int hf_clnp_segment_multiple_tails = -1; +static int hf_clnp_segment_too_long_segment = -1; +static int hf_clnp_segment_error = -1; /* * ISO 8473 OSI CLNP definition (see RFC994) @@ -259,9 +269,15 @@ static u_short dst_ref; Subset of CLNP. */ static heur_dissector_list_t cotp_is_heur_subdissector_list; +/* + * Reassembly of CLNP. + */ +static GHashTable *clnp_segment_table = NULL; + /* options */ static guint tp_nsap_selector = NSEL_TP; static gboolean always_decode_transport = FALSE; +static gboolean clnp_reassemble = FALSE; /* function definitions */ @@ -1560,8 +1576,10 @@ static void dissect_clnp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) char *pdu_type_string; proto_tree *type_tree; guint16 segment_length; + guint16 du_id = 0; guint16 segment_offset = 0; guint16 cnf_cksum; + cksum_status_t cksum_status; int offset; u_char src_len, dst_len, nsel, opt_len = 0; const guint8 *dst_addr, *src_addr; @@ -1574,7 +1592,11 @@ static void dissect_clnp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) address save_net_dst; address save_src; address save_dst; + fragment_data *fd_head; tvbuff_t *next_tvb; + packet_info save_pi; + gboolean must_restore_pi = FALSE; + gboolean update_col_info = TRUE; if (check_col(pinfo->fd, COL_PROTOCOL)) col_set_str(pinfo->fd, COL_PROTOCOL, "CLNP"); @@ -1670,11 +1692,12 @@ static void dissect_clnp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) } segment_length = tvb_get_ntohs(tvb, P_CLNP_SEGLEN); + cnf_cksum = tvb_get_ntohs(tvb, P_CLNP_CKSUM); + cksum_status = calc_checksum(tvb, 0, cnf_hdr_len, cnf_cksum); if (tree) { proto_tree_add_uint(clnp_tree, hf_clnp_pdu_length, tvb, P_CLNP_SEGLEN, 2, segment_length); - cnf_cksum = tvb_get_ntohs(tvb, P_CLNP_CKSUM); - switch (calc_checksum(tvb, 0, cnf_hdr_len, cnf_cksum)) { + switch (cksum_status) { default: /* @@ -1754,10 +1777,11 @@ static void dissect_clnp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) tvb_memcpy(tvb, (guint8 *)&seg, offset, sizeof(seg)); /* XXX - not used */ segment_offset = tvb_get_ntohs(tvb, offset + 2); + du_id = tvb_get_ntohs(tvb, offset); if (tree) { proto_tree_add_text(clnp_tree, tvb, offset, 2, "Data unit identifier: %06u", - tvb_get_ntohs(tvb, offset)); + du_id); proto_tree_add_text(clnp_tree, tvb, offset + 2 , 2, "Segment offset : %6u", segment_offset); @@ -1803,10 +1827,156 @@ static void dissect_clnp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) fragment in a fragmented IP datagram; in the future, we will probably reassemble fragments for IP, and may reassemble segments for CLNP. */ - if ((cnf_type & CNF_SEG_OK) && segment_offset != 0) { + /* If clnp_reassemble is on and this is a segment, then just add the segment + * to the hashtable. + */ + if (clnp_reassemble && (cnf_type & CNF_SEG_OK) && + ((cnf_type & CNF_MORE_SEGS) || segment_offset != 0)) { + /* We're reassembling, and this is part of a segmented datagram. + Add the segment to the hash table if the checksum is ok + and the frame isn't truncated. */ + if (cksum_status != CKSUM_NOT_OK && + (tvb_reported_length(tvb) <= tvb_length(tvb))) { + fd_head = fragment_add(tvb, offset, pinfo, du_id, clnp_segment_table, + segment_offset, segment_length - cnf_hdr_len, + cnf_type & CNF_MORE_SEGS); + } else { + fd_head=NULL; + } + + if (fd_head != NULL) { + fragment_data *fd; + proto_tree *ft=NULL; + proto_item *fi=NULL; + + /* OK, we have the complete reassembled payload. */ + /* show all segments */ + fi = proto_tree_add_item(clnp_tree, hf_clnp_segments, + tvb, 0, 0, FALSE); + ft = proto_item_add_subtree(fi, ett_clnp_segments); + for (fd = fd_head->next; fd != NULL; fd = fd->next){ + if (fd->flags & (FD_OVERLAP|FD_OVERLAPCONFLICT + |FD_MULTIPLETAILS|FD_TOOLONGFRAGMENT) ) { + /* this segment has some flags set, create a subtree + * for it and display the flags. + */ + proto_tree *fet = NULL; + proto_item *fei = NULL; + int hf; + + if (fd->flags & (FD_OVERLAPCONFLICT + |FD_MULTIPLETAILS|FD_TOOLONGFRAGMENT) ) { + hf = hf_clnp_segment_error; + } else { + hf = hf_clnp_segment; + } + fei = proto_tree_add_none_format(ft, hf, + tvb, 0, 0, + "Frame:%d payload:%d-%d", + fd->frame, + fd->offset, + fd->offset+fd->len-1 + ); + fet = proto_item_add_subtree(fei, ett_clnp_segment); + if (fd->flags&FD_OVERLAP) { + proto_tree_add_boolean(fet, + hf_clnp_segment_overlap, tvb, 0, 0, + TRUE); + } + if (fd->flags&FD_OVERLAPCONFLICT) { + proto_tree_add_boolean(fet, + hf_clnp_segment_overlap_conflict, tvb, 0, 0, + TRUE); + } + if (fd->flags&FD_MULTIPLETAILS) { + proto_tree_add_boolean(fet, + hf_clnp_segment_multiple_tails, tvb, 0, 0, + TRUE); + } + if (fd->flags&FD_TOOLONGFRAGMENT) { + proto_tree_add_boolean(fet, + hf_clnp_segment_too_long_segment, tvb, 0, 0, + TRUE); + } + } else { + /* nothing of interest for this segment */ + proto_tree_add_none_format(ft, hf_clnp_segment, + tvb, 0, 0, + "Frame:%d payload:%d-%d", + fd->frame, + fd->offset, + fd->offset+fd->len-1 + ); + } + } + if (fd_head->flags & (FD_OVERLAPCONFLICT + |FD_MULTIPLETAILS|FD_TOOLONGFRAGMENT) ) { + if (check_col(pinfo->fd, COL_INFO)) { + col_set_str(pinfo->fd, COL_INFO, "[Illegal segments]"); + update_col_info = FALSE; + } + } + + /* Allocate a new tvbuff, referring to the reassembled payload. */ + next_tvb = tvb_new_real_data(fd_head->data, fd_head->datalen, + fd_head->datalen, "Reassembled"); + + /* Add the tvbuff to the list of tvbuffs to which the tvbuff we + were handed refers, so it'll get cleaned up when that tvbuff + is cleaned up. */ + tvb_set_child_real_data_tvbuff(tvb, next_tvb); + + /* Add the defragmented data to the data source list. */ + pinfo->fd->data_src = g_slist_append(pinfo->fd->data_src, next_tvb); + + /* It's not fragmented. */ + pinfo->fragmented = FALSE; + + /* Save the current value of "pi", and adjust certain fields to + reflect the new tvbuff. */ + save_pi = pi; + pi.compat_top_tvb = next_tvb; + pi.len = tvb_reported_length(next_tvb); + pi.captured_len = tvb_length(next_tvb); + must_restore_pi = TRUE; + } else { + /* We don't have the complete reassembled payload. */ + next_tvb = NULL; + } + } else { + /* If this is the first segment, dissect its contents, otherwise + just show it as a segment. + + XXX - if we eventually don't save the reassembled contents of all + segmented datagrams, we may want to always reassemble. */ + if ((cnf_type & CNF_SEG_OK) && segment_offset != 0) { + /* Not the first segment - don't dissect it. */ + next_tvb = NULL; + } else { + /* First segment, or not segmented. Dissect what we have here. */ + + /* Get a tvbuff for the payload. */ + next_tvb = tvb_new_subset(tvb, offset, -1, -1); + + /* + * If this is the first segment, but not the only segment, + * tell the next protocol that. + */ + if ((cnf_type & (CNF_SEG_OK|CNF_MORE_SEGS)) == (CNF_SEG_OK|CNF_MORE_SEGS)) + pinfo->fragmented = TRUE; + else + pinfo->fragmented = FALSE; + } + } + + if (next_tvb == NULL) { + /* Just show this as a segment. */ if (check_col(pinfo->fd, COL_INFO)) col_add_fstr(pinfo->fd, COL_INFO, "Fragmented %s NPDU %s(off=%u)", pdu_type_string, flag_string, segment_offset); + + /* As we haven't reassembled anything, we haven't changed "pi", so + we don't have to restore it. */ dissect_data(tvb, offset, pinfo, tree); return; } @@ -1821,7 +1991,6 @@ static void dissect_clnp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) PDU, skip that? */ if (nsel == (char)tp_nsap_selector || always_decode_transport) { - next_tvb = tvb_new_subset(tvb, offset, -1, -1); if (dissect_ositp_internal(next_tvb, pinfo, tree, FALSE)) return; /* yes, it appears to be COTP or CLTP */ } @@ -1855,7 +2024,6 @@ static void dissect_clnp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) ti = proto_tree_add_text(clnp_tree, tvb, offset, next_length, "Discarded PDU"); discpdu_tree = proto_item_add_subtree(ti, ett_clnp_disc_pdu); - next_tvb = tvb_new_subset(tvb, offset, -1, -1); dissect_clnp(next_tvb, pinfo, discpdu_tree); /* Restore the addresses. */ @@ -1879,11 +2047,15 @@ static void dissect_clnp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) } if (check_col(pinfo->fd, COL_INFO)) col_add_fstr(pinfo->fd, COL_INFO, "%s NPDU %s", pdu_type_string, flag_string); - next_tvb = tvb_new_subset(tvb, offset, -1, -1); dissect_data(next_tvb, 0, pinfo, tree); } /* dissect_clnp */ +static void +clnp_reassemble_init(void) +{ + fragment_table_init(&clnp_segment_table); +} void proto_register_clnp(void) { @@ -1921,10 +2093,40 @@ void proto_register_clnp(void) { &hf_clnp_src, { " SA ", "clnp.ssap", FT_BYTES, BASE_NONE, NULL, 0x0, "" }}, + + { &hf_clnp_segment_overlap, + { "Segment overlap", "clnp.segment.overlap", FT_BOOLEAN, BASE_NONE, NULL, 0x0, + "Segment overlaps with other segments" }}, + + { &hf_clnp_segment_overlap_conflict, + { "Conflicting data in segment overlap", "clnp.segment.overlap.conflict", FT_BOOLEAN, BASE_NONE, NULL, 0x0, + "Overlapping segments contained conflicting data" }}, + + { &hf_clnp_segment_multiple_tails, + { "Multiple tail segments found", "clnp.segment.multipletails", FT_BOOLEAN, BASE_NONE, NULL, 0x0, + "Several tails were found when reassembling the packet" }}, + + { &hf_clnp_segment_too_long_segment, + { "Segment too long", "clnp.segment.toolongsegment", FT_BOOLEAN, BASE_NONE, NULL, 0x0, + "Segment contained data past end of packet" }}, + + { &hf_clnp_segment_error, + { "Reassembly error", "clnp.segment.error", FT_NONE, BASE_DEC, NULL, 0x0, + "Reassembly error due to illegal segments" }}, + + { &hf_clnp_segment, + { "CLNP Segment", "clnp.segment", FT_NONE, BASE_DEC, NULL, 0x0, + "CLNP Segment" }}, + + { &hf_clnp_segments, + { "CLNP Segments", "clnp.segments", FT_NONE, BASE_DEC, NULL, 0x0, + "CLNP Segments" }}, }; static gint *ett[] = { &ett_clnp, &ett_clnp_type, + &ett_clnp_segments, + &ett_clnp_segment, &ett_clnp_disc_pdu, }; @@ -1943,7 +2145,10 @@ void proto_register_clnp(void) "Always try to decode NSDU as transport PDUs", "Always try to decode NSDU as transport PDUs", &always_decode_transport); - + prefs_register_bool_preference(clnp_module, "reassemble", + "Reassemble segmented CLNP datagrams", + "Whether segmented CLNP datagrams should be reassembled", + &clnp_reassemble); } void proto_register_cotp(void) @@ -1980,6 +2185,7 @@ void proto_register_cltp(void) proto_cltp = proto_register_protocol(PROTO_STRING_CLTP, "CLTP", "cltp"); /* proto_register_field_array(proto_cotp, hf, array_length(hf));*/ proto_register_subtree_array(ett, array_length(ett)); + register_init_routine(clnp_reassemble_init); } void diff --git a/packet-ip.c b/packet-ip.c index 557efc3a55..1e2e937677 100644 --- a/packet-ip.c +++ b/packet-ip.c @@ -1,12 +1,11 @@ /* packet-ip.c * Routines for IP and miscellaneous IP protocol packet disassembly * - * $Id: packet-ip.c,v 1.134 2001/06/05 05:54:14 guy Exp $ + * $Id: packet-ip.c,v 1.135 2001/06/08 06:27:15 guy Exp $ * * Ethereal - Network traffic analyzer - * By Gerald Combs <gerald@zing.org> + * By Gerald Combs <gerald@ethereal.com> * Copyright 1998 Gerald Combs - * * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -47,6 +46,7 @@ #include "resolv.h" #include "ipproto.h" #include "prefs.h" +#include "reassemble.h" #include "etypes.h" #include "greproto.h" #include "ppptypes.h" @@ -301,319 +301,14 @@ typedef struct _e_ip /* * defragmentation of IPv4 */ -static GHashTable *ip_fragment_table=NULL; - -typedef struct _ip_fragment_key { - guint32 srcip; - guint32 dstip; - guint32 id; -} ip_fragment_key; - -/* make sure that all flags that are set in a fragment entry is also set for - * the flags field of ipfd_head !!! - */ -/* only in ipfd_head: packet is defragmented */ -#define IPD_DEFRAGMENTED 0x0001 -/* there are overlapping fragments */ -#define IPD_OVERLAP 0x0002 -/* overlapping fragments contain different data */ -#define IPD_OVERLAPCONFLICT 0x0004 -/* more than one fragment which indicates end-of data */ -#define IPD_MULTIPLETAILS 0x0008 -/* fragment contains data past the end of the datagram */ -#define IPD_TOOLONGFRAGMENT 0x0010 -typedef struct _ip_fragment_data { - struct _ip_fragment_data *next; - guint32 frame; - guint32 offset; - guint32 len; - guint32 datalen; /*Only valid in first item of list */ - guint32 flags; - unsigned char *data; -} ip_fragment_data; - -#define LINK_FRAG(ipfd_head,ipfd) \ - { ip_fragment_data *ipfd_i; \ - /* add fragment to list, keep list sorted */ \ - for(ipfd_i=ipfd_head;ipfd_i->next;ipfd_i=ipfd_i->next){ \ - if( (ipfd->offset) < (ipfd_i->next->offset) ) \ - break; \ - } \ - ipfd->next=ipfd_i->next; \ - ipfd_i->next=ipfd; \ - } - - -static gint -ip_fragment_equal(gconstpointer k1, gconstpointer k2) -{ - ip_fragment_key* key1 = (ip_fragment_key*) k1; - ip_fragment_key* key2 = (ip_fragment_key*) k2; - - return ( ( (key1->srcip == key2->srcip) && - (key1->dstip == key2->dstip) && - (key1->id == key2->id) - ) ? - TRUE : FALSE); -} - -static guint -ip_fragment_hash(gconstpointer k) -{ - ip_fragment_key* key = (ip_fragment_key*) k; - - return (key->srcip ^ key->dstip ^ key->id); -} - -static gboolean -free_all_fragments(gpointer key, gpointer value, gpointer user_data) -{ - ip_fragment_data *ipfd_head; - ip_fragment_data *ipfd_i; - - ipfd_head=value; - while(ipfd_head){ - ipfd_i=ipfd_head->next; - if(ipfd_head->data){ - g_free(ipfd_head->data); - } - g_free(ipfd_head); - ipfd_head=ipfd_i; - } - - g_free(key); - return TRUE; -} +static GHashTable *ip_fragment_table = NULL; static void ip_defragment_init(void) { - if( ip_fragment_table != NULL ){ - /* The fragment hash table exists. - * - * Remove all entries and free all memory. - */ - g_hash_table_foreach_remove(ip_fragment_table,free_all_fragments,NULL); - } else { - /* The fragment table does not exist. Create it */ - ip_fragment_table = g_hash_table_new(ip_fragment_hash, - ip_fragment_equal); - } -} - -/* This function adds a new fragment to the fragment hash table - * If this is the first fragment seen in for this ip packet, - * a new entry is created in the hash table, otherwise - * This fragment is just added to the linked list of - * fragments for this packet. - * The list of fragments for a specific ip-packet is kept sorted for - * easier handling. - * tvb had better contain an IPv4 packet, or BAD things will probably happen. - * - * Returns a pointer to the head of the fragment data list if we have all the - * fragments, NULL otherwise. - */ -static ip_fragment_data * -ip_fragment_add(tvbuff_t *tvb, int offset, packet_info *pinfo, guint32 id, - guint32 floff) -{ - ip_fragment_key *ipfk; - ip_fragment_data *ipfd_head; - ip_fragment_data *ipfd; - ip_fragment_data *ipfd_i; - guint32 frag_offset; - guint32 max,dfpos; - - - /* create key to search hash with */ - ipfk=g_malloc(sizeof(ip_fragment_key)); - memcpy(&ipfk->srcip, pinfo->src.data, sizeof(ipfk->srcip)); - memcpy(&ipfk->dstip, pinfo->dst.data, sizeof(ipfk->dstip)); - ipfk->id = id; - - ipfd_head=g_hash_table_lookup(ip_fragment_table, ipfk); - - - /* have we already seen this frame ?*/ - if( pinfo->fd->flags.visited ){ - g_free(ipfk); - if (ipfd_head != NULL && ipfd_head->flags & IPD_DEFRAGMENTED) { - return ipfd_head; - } else { - return NULL; - } - } - - - - frag_offset = (floff & IP_OFFSET)*8; - - if (ipfd_head==NULL){ - /* not found, this must be the first snooped fragment for this - * ip packet. Create list-head. - */ - ipfd_head=g_malloc(sizeof(ip_fragment_data)); - /* head/first structure in list only holds no other data than - * 'datalen' then we dont have to change the head of the list - * even if we want to keep it sorted - */ - ipfd_head->next=NULL; - ipfd_head->datalen=0; - ipfd_head->offset=0; - ipfd_head->len=0; - ipfd_head->flags=0; - ipfd_head->data=NULL; - g_hash_table_insert(ip_fragment_table, ipfk, ipfd_head); - } else { - /* this was not the first fragment, so we can throw ipfk - * away, only used for the first fragment, 3 lines up - */ - g_free(ipfk); - } - - - /* create new ipfd describing this fragment */ - ipfd = g_malloc(sizeof(ip_fragment_data)); - ipfd->next = NULL; - ipfd->flags = 0; - ipfd->frame = pinfo->fd->num; - ipfd->offset = frag_offset; - ipfd->len = pinfo->iplen; - ipfd->len -= (pinfo->iphdrlen*4); - ipfd->data = NULL; - - - - if( !(floff&IP_MF) ){ - /* this is a tail fragment */ - if (ipfd_head->datalen) { - /* ok we have already seen other tails for this packet - * it might be a duplicate. - */ - if (ipfd_head->datalen != (ipfd->offset + ipfd->len) ){ - /* Oops, this tail indicates a different packet - * len than the previous ones. Somethings wrong - */ - ipfd->flags |= IPD_MULTIPLETAILS; - ipfd_head->flags |= IPD_MULTIPLETAILS; - } - } else { - /* this was the first tail fragment, now we know the - * length of the packet - */ - ipfd_head->datalen = ipfd->offset + ipfd->len; - } - } - - - - - /* If the packet is already defragmented, this MUST be an overlap. - * The entire defragmented packet is in ipfd_head->data - * Even if we have previously defragmented this packet, we still check - * check it. Someone might play overlap and TTL games. - */ - if (ipfd_head->flags & IPD_DEFRAGMENTED) { - ipfd->flags |= IPD_OVERLAP; - ipfd_head->flags |= IPD_OVERLAP; - /* make sure its not too long */ - if (ipfd->offset + ipfd->len > ipfd_head->datalen) { - ipfd->flags |= IPD_TOOLONGFRAGMENT; - ipfd_head->flags |= IPD_TOOLONGFRAGMENT; - LINK_FRAG(ipfd_head,ipfd); - return (ipfd_head); - } - /* make sure it doesnt conflict with previous data */ - if ( memcmp(ipfd_head->data+ipfd->offset, - tvb_get_ptr(tvb,offset,ipfd->len),ipfd->len) ){ - ipfd->flags |= IPD_OVERLAPCONFLICT; - ipfd_head->flags |= IPD_OVERLAPCONFLICT; - LINK_FRAG(ipfd_head,ipfd); - return (ipfd_head); - } - /* it was just an overlap, link it and return */ - LINK_FRAG(ipfd_head,ipfd); - return (ipfd_head); - } - - - - /* If we have reached this point, the packet is not defragmented yet. - * Save all payload in a buffer until we can defragment. - */ - ipfd->data = g_malloc(ipfd->len); - tvb_memcpy(tvb, ipfd->data, offset, ipfd->len); - LINK_FRAG(ipfd_head,ipfd); - - - if( !(ipfd_head->datalen) ){ - /* if we dont know the datalen, there are still missing - * packets. Cheaper than the check below. - */ - return NULL; - } - - - /* check if we have received the entire fragment - * this is easy since the list is sorted and the head is faked. - */ - max = 0; - for (ipfd_i=ipfd_head->next;ipfd_i;ipfd_i=ipfd_i->next) { - if ( ((ipfd_i->offset)<=max) && - ((ipfd_i->offset+ipfd_i->len)>max) ){ - max = ipfd_i->offset+ipfd_i->len; - } - } - - if (max < (ipfd_head->datalen)) { - /* we have not received all packets yet */ - return NULL; - } - - - if (max > (ipfd_head->datalen)) { - /* oops, too long fragment detected */ - ipfd->flags |= IPD_TOOLONGFRAGMENT; - ipfd_head->flags |= IPD_TOOLONGFRAGMENT; - } - - - /* we have received an entire packet, defragment it and - * free all fragments - */ - ipfd_head->data = g_malloc(max); - - /* add all data fragments */ - for (dfpos=0,ipfd_i=ipfd_head;ipfd_i;ipfd_i=ipfd_i->next) { - if (ipfd_i->len) { - if (ipfd_i->offset < dfpos) { - ipfd_i->flags |= IPD_OVERLAP; - ipfd_head->flags |= IPD_OVERLAP; - if ( memcmp(ipfd_head->data+ipfd_i->offset, - ipfd_i->data, - MIN(ipfd_i->len,(dfpos-ipfd_i->offset)) - ) ){ - ipfd_i->flags |= IPD_OVERLAPCONFLICT; - ipfd_head->flags |= IPD_OVERLAPCONFLICT; - } - } - memcpy(ipfd_head->data+ipfd_i->offset,ipfd_i->data,ipfd_i->len); - g_free(ipfd_i->data); - ipfd_i->data=NULL; - - dfpos=MAX(dfpos,(ipfd_i->offset+ipfd_i->len)); - } - } - - /* mark this packet as defragmented. - allows us to skip any trailing fragments */ - ipfd_head->flags |= IPD_DEFRAGMENTED; - - return ipfd_head; + fragment_table_init(&ip_fragment_table); } - - void capture_ip(const u_char *pd, int offset, packet_counts *ld) { if (!BYTES_ARE_IN_FRAME(offset, IPH_MIN_LEN)) { @@ -1101,7 +796,7 @@ dissect_ip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) guint16 flags; guint8 nxt; guint16 ipsum; - ip_fragment_data *ipfd_head; + fragment_data *ipfd_head; tvbuff_t *next_tvb; packet_info save_pi; gboolean must_restore_pi = FALSE; @@ -1273,13 +968,17 @@ dissect_ip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) Add the fragment to the hash table if the checksum is ok and the frame isn't truncated. */ if ((ipsum==0) && (tvb_reported_length(tvb) <= tvb_length(tvb))) { - ipfd_head = ip_fragment_add(tvb, offset, pinfo, iph.ip_id, iph.ip_off); + ipfd_head = fragment_add(tvb, offset, pinfo, iph.ip_id, + ip_fragment_table, + (iph.ip_off & IP_OFFSET)*8, + pinfo->iplen - (pinfo->iphdrlen*4), + iph.ip_off & IP_MF); } else { ipfd_head=NULL; } if (ipfd_head != NULL) { - ip_fragment_data *ipfd; + fragment_data *ipfd; proto_tree *ft=NULL; proto_item *fi=NULL; @@ -1289,8 +988,8 @@ dissect_ip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) tvb, 0, 0, FALSE); ft = proto_item_add_subtree(fi, ett_ip_fragments); for (ipfd=ipfd_head->next; ipfd; ipfd=ipfd->next){ - if (ipfd->flags & (IPD_OVERLAP|IPD_OVERLAPCONFLICT - |IPD_MULTIPLETAILS|IPD_TOOLONGFRAGMENT) ) { + if (ipfd->flags & (FD_OVERLAP|FD_OVERLAPCONFLICT + |FD_MULTIPLETAILS|FD_TOOLONGFRAGMENT) ) { /* this fragment has some flags set, create a subtree * for it and display the flags. */ @@ -1298,8 +997,8 @@ dissect_ip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) proto_item *fei=NULL; int hf; - if (ipfd->flags & (IPD_OVERLAPCONFLICT - |IPD_MULTIPLETAILS|IPD_TOOLONGFRAGMENT) ) { + if (ipfd->flags & (FD_OVERLAPCONFLICT + |FD_MULTIPLETAILS|FD_TOOLONGFRAGMENT) ) { hf = hf_ip_fragment_error; } else { hf = hf_ip_fragment; @@ -1312,22 +1011,22 @@ dissect_ip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) ipfd->offset+ipfd->len-1 ); fet = proto_item_add_subtree(fei, ett_ip_fragment); - if (ipfd->flags&IPD_OVERLAP) { + if (ipfd->flags&FD_OVERLAP) { proto_tree_add_boolean(fet, hf_ip_fragment_overlap, tvb, 0, 0, TRUE); } - if (ipfd->flags&IPD_OVERLAPCONFLICT) { + if (ipfd->flags&FD_OVERLAPCONFLICT) { proto_tree_add_boolean(fet, hf_ip_fragment_overlap_conflict, tvb, 0, 0, TRUE); } - if (ipfd->flags&IPD_MULTIPLETAILS) { + if (ipfd->flags&FD_MULTIPLETAILS) { proto_tree_add_boolean(fet, hf_ip_fragment_multiple_tails, tvb, 0, 0, TRUE); } - if (ipfd->flags&IPD_TOOLONGFRAGMENT) { + if (ipfd->flags&FD_TOOLONGFRAGMENT) { proto_tree_add_boolean(fet, hf_ip_fragment_too_long_fragment, tvb, 0, 0, TRUE); @@ -1343,8 +1042,8 @@ dissect_ip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) ); } } - if (ipfd_head->flags & (IPD_OVERLAPCONFLICT - |IPD_MULTIPLETAILS|IPD_TOOLONGFRAGMENT) ) { + if (ipfd_head->flags & (FD_OVERLAPCONFLICT + |FD_MULTIPLETAILS|FD_TOOLONGFRAGMENT) ) { if (check_col(pinfo->fd, COL_INFO)) { col_set_str(pinfo->fd, COL_INFO, "[Illegal fragments]"); update_col_info = FALSE; diff --git a/reassemble.c b/reassemble.c new file mode 100644 index 0000000000..30dad7024b --- /dev/null +++ b/reassemble.c @@ -0,0 +1,371 @@ +/* reassemble.c + * Routines for {fragment,segment} reassembly + * + * $Id: reassemble.c,v 1.1 2001/06/08 06:27:16 guy Exp $ + * + * Ethereal - Network traffic analyzer + * By Gerald Combs <gerald@ethereal.com> + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "packet.h" + +#include "reassemble.h" + +typedef struct _fragment_key { + address src; + address dst; + guint32 id; +} fragment_key; + +static GMemChunk *fragment_key_chunk = NULL; +static GMemChunk *fragment_data_chunk = NULL; +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) ) \ + break; \ + } \ + fd->next=fd_i->next; \ + fd_i->next=fd; \ + } + + +static gint +fragment_equal(gconstpointer k1, gconstpointer k2) +{ + fragment_key* key1 = (fragment_key*) k1; + fragment_key* key2 = (fragment_key*) k2; + + return ( ( (ADDRESSES_EQUAL(&key1->src, &key2->src)) && + (ADDRESSES_EQUAL(&key1->dst, &key2->dst)) && + (key1->id == key2->id) + ) ? + TRUE : FALSE); +} + +static guint +fragment_hash(gconstpointer k) +{ + fragment_key* key = (fragment_key*) k; + guint hash_val; + int i; + + hash_val = 0; + for (i = 0; i < key->src.len; i++) + hash_val += key->src.data[i]; + for (i = 0; i < key->dst.len; i++) + hash_val += key->dst.data[i]; + hash_val += key->id; + + return hash_val; +} + +/* + * For a hash table entry, free the address data to which the key refers + * and the fragment data to which the value refers. + * (The actual key and value structures get freed by "reassemble_init()".) + */ +static gboolean +free_all_fragments(gpointer key_arg, gpointer value, gpointer user_data) +{ + fragment_key *key = key_arg; + fragment_data *fd_head; + + /* + * Grr. I guess the theory here is that freeing + * something sure as heck modifies it, so you + * want to ban attempts to free it, but, alas, + * if we make the "data" field of an "address" + * structure not a "const", the compiler whines if + * we try to make it point into the data for a packet, + * as that's a "const" array (and should be, as dissectors + * shouldn't trash it). + * + * So we cast the complaint into oblivion, and rely on + * the fact that these addresses are known to have had + * their data mallocated, i.e. they don't point into, + * say, the middle of the data for a packet. + */ + g_free((gpointer)key->src.data); + g_free((gpointer)key->dst.data); + + for (fd_head = value; fd_head != NULL; fd_head = fd_head->next) { + if (fd_head->data) + g_free(fd_head->data); + } + + return TRUE; +} + +/* + * Initialize a fragment table. + */ +void +fragment_table_init(GHashTable **fragment_table) +{ + if (*fragment_table != NULL) { + /* + * The fragment hash table exists. + * + * Remove all entries and free fragment data for + * each entry. (The key and value data is freed + * by "reassemble_init()".) + */ + g_hash_table_foreach_remove(*fragment_table, + free_all_fragments, NULL); + } else { + /* The fragment table does not exist. Create it */ + *fragment_table = g_hash_table_new(fragment_hash, + fragment_equal); + } +} + +/* + * Free up all space allocated for fragment keys and data. + */ +void +reassemble_init(void) +{ + if (fragment_key_chunk != NULL) + g_mem_chunk_destroy(fragment_key_chunk); + if (fragment_data_chunk != NULL) + g_mem_chunk_destroy(fragment_data_chunk); + fragment_key_chunk = g_mem_chunk_new("fragment_key_chunk", + sizeof(fragment_key), + fragment_init_count * sizeof(fragment_key), + G_ALLOC_ONLY); + fragment_data_chunk = g_mem_chunk_new("fragment_data_chunk", + sizeof(fragment_data), + fragment_init_count * sizeof(fragment_data), + G_ALLOC_ONLY); +} + +/* + * This function adds a new fragment to the fragment hash table. + * If this is the first fragment seen for this datagram, a new entry + * is created in the hash table, otherwise this fragment is just added + * to the linked list of fragments for this packet. + * The list of fragments for a specific datagram is kept sorted for + * easier handling. + * + * Returns a pointer to the head of the fragment data list if we have all the + * fragments, NULL otherwise. + */ +fragment_data * +fragment_add(tvbuff_t *tvb, int offset, packet_info *pinfo, guint32 id, + GHashTable *fragment_table, guint32 frag_offset, + guint32 frag_data_len, gboolean more_frags) +{ + fragment_key key, *new_key; + fragment_data *fd_head; + fragment_data *fd; + fragment_data *fd_i; + guint32 max, dfpos; + + /* 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); + + /* have we already seen this frame ?*/ + if (pinfo->fd->flags.visited) { + if (fd_head != NULL && fd_head->flags & FD_DEFRAGMENTED) { + return fd_head; + } else { + return NULL; + } + } + + if (fd_head==NULL){ + /* not found, this must be the first snooped fragment for this + * packet. Create list-head. + */ + fd_head=g_mem_chunk_alloc(fragment_data_chunk); + /* head/first structure in list only holds no other data than + * 'datalen' then we don't have to change the head of the list + * even if we want to keep it sorted + */ + fd_head->next=NULL; + fd_head->datalen=0; + fd_head->offset=0; + fd_head->len=0; + fd_head->flags=0; + fd_head->data=NULL; + + /* + * We're going to use the key to insert the fragment, + * so allocate a structure for it, and copy the + * addresses, allocating new buffers for the address + * data. + */ + new_key = g_mem_chunk_alloc(fragment_key_chunk); + COPY_ADDRESS(&new_key->src, &key.src); + COPY_ADDRESS(&new_key->dst, &key.dst); + new_key->id = key.id; + g_hash_table_insert(fragment_table, new_key, fd_head); + } + + /* create new fd describing this fragment */ + fd = g_mem_chunk_alloc(fragment_data_chunk); + fd->next = NULL; + fd->flags = 0; + fd->frame = pinfo->fd->num; + fd->offset = frag_offset; + fd->len = frag_data_len; + fd->data = NULL; + + if (!more_frags) { + /* + * This is the tail fragment in the sequence. + */ + if (fd_head->datalen) { + /* ok we have already seen other tails for this packet + * it might be a duplicate. + */ + if (fd_head->datalen != (fd->offset + fd->len) ){ + /* Oops, this tail indicates a different packet + * len than the previous ones. Somethings wrong + */ + fd->flags |= FD_MULTIPLETAILS; + fd_head->flags |= FD_MULTIPLETAILS; + } + } else { + /* this was the first tail fragment, now we know the + * length of the packet + */ + fd_head->datalen = fd->offset + fd->len; + } + } + + + + + /* If the packet is already defragmented, this MUST be an overlap. + * The entire defragmented packet is in fd_head->data + * Even if we have previously defragmented this packet, we still check + * check it. Someone might play overlap and TTL games. + */ + if (fd_head->flags & FD_DEFRAGMENTED) { + fd->flags |= FD_OVERLAP; + fd_head->flags |= FD_OVERLAP; + /* make sure its not too long */ + if (fd->offset + fd->len > fd_head->datalen) { + fd->flags |= FD_TOOLONGFRAGMENT; + fd_head->flags |= FD_TOOLONGFRAGMENT; + LINK_FRAG(fd_head,fd); + return (fd_head); + } + /* make sure it doesnt conflict with previous data */ + if ( memcmp(fd_head->data+fd->offset, + tvb_get_ptr(tvb,offset,fd->len),fd->len) ){ + fd->flags |= FD_OVERLAPCONFLICT; + fd_head->flags |= FD_OVERLAPCONFLICT; + LINK_FRAG(fd_head,fd); + return (fd_head); + } + /* it was just an overlap, link it and return */ + LINK_FRAG(fd_head,fd); + return (fd_head); + } + + + + /* If we have reached this point, the packet is not defragmented yet. + * Save all payload in a buffer until we can defragment. + * XXX - what if we didn't capture the entire fragment due + * to a too-short snapshot length? + */ + fd->data = g_malloc(fd->len); + tvb_memcpy(tvb, fd->data, offset, fd->len); + LINK_FRAG(fd_head,fd); + + + if( !(fd_head->datalen) ){ + /* if we dont know the datalen, there are still missing + * packets. Cheaper than the check below. + */ + return NULL; + } + + + /* check if we have received the entire fragment + * this is easy since the list is sorted and the head is faked. + */ + max = 0; + for (fd_i=fd_head->next;fd_i;fd_i=fd_i->next) { + if ( ((fd_i->offset)<=max) && + ((fd_i->offset+fd_i->len)>max) ){ + max = fd_i->offset+fd_i->len; + } + } + + if (max < (fd_head->datalen)) { + /* we have not received all packets yet */ + return NULL; + } + + + if (max > (fd_head->datalen)) { + /* oops, too long fragment detected */ + fd->flags |= FD_TOOLONGFRAGMENT; + fd_head->flags |= FD_TOOLONGFRAGMENT; + } + + + /* we have received an entire packet, defragment it and + * free all fragments + */ + fd_head->data = g_malloc(max); + + /* add all data fragments */ + for (dfpos=0,fd_i=fd_head;fd_i;fd_i=fd_i->next) { + if (fd_i->len) { + if (fd_i->offset < dfpos) { + fd_i->flags |= FD_OVERLAP; + fd_head->flags |= FD_OVERLAP; + if ( memcmp(fd_head->data+fd_i->offset, + fd_i->data, + MIN(fd_i->len,(dfpos-fd_i->offset)) + ) ){ + 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); + fd_i->data=NULL; + + dfpos=MAX(dfpos,(fd_i->offset+fd_i->len)); + } + } + + /* mark this packet as defragmented. + allows us to skip any trailing fragments */ + fd_head->flags |= FD_DEFRAGMENTED; + + return fd_head; +} diff --git a/reassemble.h b/reassemble.h new file mode 100644 index 0000000000..8b96e72d1a --- /dev/null +++ b/reassemble.h @@ -0,0 +1,77 @@ +/* reassemble.h + * Declarations of outines for {fragment,segment} reassembly + * + * $Id: reassemble.h,v 1.1 2001/06/08 06:27:16 guy Exp $ + * + * Ethereal - Network traffic analyzer + * By Gerald Combs <gerald@ethereal.com> + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* make sure that all flags that are set in a fragment entry is also set for + * the flags field of fd_head !!! + */ + +/* only in fd_head: packet is defragmented */ +#define FD_DEFRAGMENTED 0x0001 + +/* there are overlapping fragments */ +#define FD_OVERLAP 0x0002 + +/* overlapping fragments contain different data */ +#define FD_OVERLAPCONFLICT 0x0004 + +/* more than one fragment which indicates end-of data */ +#define FD_MULTIPLETAILS 0x0008 + +/* fragment contains data past the end of the datagram */ +#define FD_TOOLONGFRAGMENT 0x0010 + +typedef struct _fragment_data { + struct _fragment_data *next; + guint32 frame; + guint32 offset; + guint32 len; + guint32 datalen; /*Only valid in first item of list */ + guint32 flags; + unsigned char *data; +} fragment_data; + +/* + * Initialize a fragment table. + */ +void fragment_table_init(GHashTable **fragment_table); + +/* + * Free up all space allocated for fragment keys and data. + */ +void reassemble_init(void); + +/* + * This function adds a new fragment to the fragment hash table. + * If this is the first fragment seen for this datagram, a new entry + * is created in the hash table, otherwise this fragment is just added + * to the linked list of fragments for this packet. + * The list of fragments for a specific datagram is kept sorted for + * easier handling. + * + * Returns a pointer to the head of the fragment data list if we have all the + * fragments, NULL otherwise. + */ +fragment_data *fragment_add(tvbuff_t *tvb, int offset, packet_info *pinfo, + guint32 id, GHashTable *fragment_table, guint32 frag_offset, + guint32 frag_data_len, gboolean more_frags); diff --git a/tethereal.c b/tethereal.c index e4f9df5ba6..ba0b089831 100644 --- a/tethereal.c +++ b/tethereal.c @@ -1,6 +1,6 @@ /* tethereal.c * - * $Id: tethereal.c,v 1.84 2001/06/05 07:38:33 guy Exp $ + * $Id: tethereal.c,v 1.85 2001/06/08 06:27:16 guy Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs <gerald@ethereal.com> @@ -93,6 +93,7 @@ #include "resolv.h" #include "util.h" #include "conversation.h" +#include "reassemble.h" #include "plugins.h" #include "register.h" @@ -651,6 +652,12 @@ capture(int packet_count, int out_file_type) /* Initialize protocol-specific variables */ init_all_protocols(); + /* Initialize the common data structures for fragment reassembly. + Must be done *after* "init_all_protocols()", as "init_all_protocols()" + may free up space for fragments, which it finds by using the + data structures that "reassemble_init()" frees. */ + reassemble_init(); + ld.linktype = WTAP_ENCAP_UNKNOWN; ld.pdh = NULL; @@ -1501,6 +1508,12 @@ open_cap_file(char *fname, gboolean is_tempfile, capture_file *cf) /* Initialize protocol-specific variables */ init_all_protocols(); + /* Initialize the common data structures for fragment reassembly. + Must be done *after* "init_all_protocols()", as "init_all_protocols()" + may free up space for fragments, which it finds by using the + data structures that "reassemble_init()" frees. */ + reassemble_init(); + cf->wth = wth; cf->filed = fd; cf->f_len = cf_stat.st_size; |