aboutsummaryrefslogtreecommitdiffstats
path: root/epan
diff options
context:
space:
mode:
Diffstat (limited to 'epan')
-rw-r--r--epan/CMakeLists.txt1
-rw-r--r--epan/Makefile.am2
-rw-r--r--epan/dissectors/packet-dcm.c35
-rw-r--r--epan/dissectors/packet-http.c31
-rw-r--r--epan/dissectors/packet-imf.c32
-rw-r--r--epan/dissectors/packet-smb.c423
-rw-r--r--epan/dissectors/packet-tftp.c91
-rw-r--r--epan/export_object.c206
-rw-r--r--epan/export_object.h155
9 files changed, 969 insertions, 7 deletions
diff --git a/epan/CMakeLists.txt b/epan/CMakeLists.txt
index 3bb415589c..f3c2f07fc4 100644
--- a/epan/CMakeLists.txt
+++ b/epan/CMakeLists.txt
@@ -112,6 +112,7 @@ set(LIBWIRESHARK_FILES
ex-opt.c
except.c
expert.c
+ export_object.c
exported_pdu.c
plugin_if.c
filter_expressions.c
diff --git a/epan/Makefile.am b/epan/Makefile.am
index 04965bb69e..de37f2fa53 100644
--- a/epan/Makefile.am
+++ b/epan/Makefile.am
@@ -75,6 +75,7 @@ LIBWIRESHARK_SRC = \
ex-opt.c \
except.c \
expert.c \
+ export_object.c \
exported_pdu.c \
plugin_if.c \
filter_expressions.c \
@@ -218,6 +219,7 @@ LIBWIRESHARK_INCLUDES = \
except.h \
exceptions.h \
expert.h \
+ export_object.h \
exported_pdu.h \
plugin_if.h \
filter_expressions.h \
diff --git a/epan/dissectors/packet-dcm.c b/epan/dissectors/packet-dcm.c
index ac501bf40f..fc7ee38fbd 100644
--- a/epan/dissectors/packet-dcm.c
+++ b/epan/dissectors/packet-dcm.c
@@ -221,6 +221,7 @@
#include <epan/expert.h>
#include <epan/tap.h>
#include <epan/reassemble.h>
+#include <epan/export_object.h>
#include "packet-tcp.h"
@@ -369,6 +370,38 @@ static const value_string dcm_assoc_item_type[] = {
{ 0, NULL }
};
+static gboolean
+dcm_eo_packet(void *tapdata, packet_info *pinfo, epan_dissect_t *edt _U_,
+ const void *data)
+{
+ export_object_list_t *object_list = (export_object_list_t *)tapdata;
+ const dicom_eo_t *eo_info = (const dicom_eo_t *)data;
+ export_object_entry_t *entry;
+
+ if (eo_info) { /* We have data waiting for us */
+ /*
+ Don't copy any data. dcm_export_create_object() is already g_malloc() the items
+ Still, the values will be freed when the export Object window is closed.
+ Therefore, strings and buffers must be copied
+ */
+ entry = g_new(export_object_entry_t, 1);
+
+ entry->pkt_num = pinfo->num;
+ entry->hostname = eo_info->hostname;
+ entry->content_type = eo_info->content_type;
+ entry->filename = g_path_get_basename(eo_info->filename);
+ entry->payload_len = eo_info->payload_len;
+ entry->payload_data = eo_info->payload_data;
+
+ object_list->add_entry(object_list->gui_data, entry);
+
+ return TRUE; /* State changed - window should be redrawn */
+ } else {
+ return FALSE; /* State unchanged - no window updates needed */
+ }
+}
+
+
/* ************************************************************************* */
/* Fragment items */
/* ************************************************************************* */
@@ -7175,7 +7208,7 @@ proto_register_dcm(void)
"When not set, the decoding may fail and the exports may become corrupt.",
&global_dcm_reassemble);
- dicom_eo_tap = register_tap("dicom_eo"); /* DICOM Export Object tap */
+ dicom_eo_tap = register_export_object(proto_dcm, dcm_eo_packet, NULL);
register_init_routine(&dcm_init);
register_cleanup_routine(&dcm_cleanup);
diff --git a/epan/dissectors/packet-http.c b/epan/dissectors/packet-http.c
index 839f562908..194e0eeec0 100644
--- a/epan/dissectors/packet-http.c
+++ b/epan/dissectors/packet-http.c
@@ -43,6 +43,7 @@
#include <epan/to_str.h>
#include <epan/req_resp_hdrs.h>
#include <epan/proto_data.h>
+#include <epan/export_object.h>
#include <wsutil/base64.h>
#include "packet-http.h"
@@ -350,6 +351,34 @@ static dissector_table_t port_subdissector_table;
static dissector_table_t media_type_subdissector_table;
static heur_dissector_list_t heur_subdissector_list;
+
+static gboolean
+http_eo_packet(void *tapdata, packet_info *pinfo, epan_dissect_t *edt _U_, const void *data)
+{
+ export_object_list_t *object_list = (export_object_list_t *)tapdata;
+ const http_eo_t *eo_info = (const http_eo_t *)data;
+ export_object_entry_t *entry;
+
+ if(eo_info) { /* We have data waiting for us */
+ /* These values will be freed when the Export Object window
+ * is closed. */
+ entry = g_new(export_object_entry_t, 1);
+
+ entry->pkt_num = pinfo->num;
+ entry->hostname = g_strdup(eo_info->hostname);
+ entry->content_type = g_strdup(eo_info->content_type);
+ entry->filename = g_path_get_basename(eo_info->filename);
+ entry->payload_len = eo_info->payload_len;
+ entry->payload_data = (guint8 *)g_memdup(eo_info->payload_data, eo_info->payload_len);
+
+ object_list->add_entry(object_list->gui_data, entry);
+
+ return TRUE; /* State changed - window should be redrawn */
+ } else {
+ return FALSE; /* State unchanged - no window updates needed */
+ }
+}
+
/* --- HTTP Status Codes */
/* Note: The reference for uncommented entries is RFC 2616 */
const value_string vals_http_status_code[] = {
@@ -3688,11 +3717,11 @@ proto_register_http(void)
* Register for tapping
*/
http_tap = register_tap("http"); /* HTTP statistics tap */
- http_eo_tap = register_tap("http_eo"); /* HTTP Export Object tap */
http_follow_tap = register_tap("http_follow"); /* HTTP Follow tap */
register_follow_stream(proto_http, "http_follow", tcp_follow_conv_filter, tcp_follow_index_filter, tcp_follow_address_filter,
tcp_port_to_display, follow_tvb_tap_listener);
+ http_eo_tap = register_export_object(proto_http, http_eo_packet, NULL);
}
/*
diff --git a/epan/dissectors/packet-imf.c b/epan/dissectors/packet-imf.c
index bb6aeb1ff4..0998eac672 100644
--- a/epan/dissectors/packet-imf.c
+++ b/epan/dissectors/packet-imf.c
@@ -31,6 +31,7 @@
#include <wsutil/str_util.h>
#include <epan/tap.h>
+#include <epan/export_object.h>
#include "packet-ber.h"
#include "packet-http.h"
@@ -154,6 +155,35 @@ static dissector_handle_t imf_handle;
static expert_field ei_imf_unknown_param = EI_INIT;
+
+static gboolean
+imf_eo_packet(void *tapdata, packet_info *pinfo, epan_dissect_t *edt _U_, const void *data)
+{
+ export_object_list_t *object_list = (export_object_list_t *)tapdata;
+ const imf_eo_t *eo_info = (const imf_eo_t *)data;
+ export_object_entry_t *entry;
+
+ if(eo_info) { /* We have data waiting for us */
+ /* These values will be freed when the Export Object window
+ * is closed. */
+ entry = g_new(export_object_entry_t, 1);
+
+ entry->pkt_num = pinfo->num;
+ entry->hostname = NULL;
+ entry->content_type = g_strdup("EML file");
+ entry->filename = g_strdup_printf("from_%s_subject_%s.eml", eo_info->sender_data, eo_info->subject_data);
+ entry->payload_len = eo_info->payload_len;
+ entry->payload_data = (guint8 *)g_memdup(eo_info->payload_data, eo_info->payload_len);
+
+ object_list->add_entry(object_list->gui_data, entry);
+
+ return TRUE; /* State changed - window should be redrawn */
+ } else {
+ return FALSE; /* State unchanged - no window updates needed */
+ }
+}
+
+
struct imf_field {
char *name; /* field name - in lower case for matching purposes */
int *hf_id; /* wireshark field */
@@ -1302,7 +1332,7 @@ proto_register_imf(void)
g_hash_table_insert(imf_field_table, (gpointer)f->name, (gpointer)f);
/* Register for tapping */
- imf_eo_tap = register_tap("imf_eo"); /* IMF Export Object tap */
+ imf_eo_tap = register_export_object(proto_imf, imf_eo_packet, NULL);
}
diff --git a/epan/dissectors/packet-smb.c b/epan/dissectors/packet-smb.c
index fe9a8a614b..1e16747571 100644
--- a/epan/dissectors/packet-smb.c
+++ b/epan/dissectors/packet-smb.c
@@ -35,6 +35,7 @@
#include <epan/srt_table.h>
#include <epan/expert.h>
#include <epan/to_str.h>
+#include <epan/export_object.h>
#include "packet-windows-common.h"
#include "packet-smb.h"
@@ -968,6 +969,423 @@ smbstat_packet(void *pss, packet_info *pinfo, epan_dissect_t *edt _U_, const voi
}
/*
+ * Export object functionality
+ */
+/* These flags show what kind of data the object contains
+ (designed to be or'ed) */
+#define SMB_EO_CONTAINS_NOTHING 0x00
+#define SMB_EO_CONTAINS_READS 0x01
+#define SMB_EO_CONTAINS_WRITES 0x02
+#define SMB_EO_CONTAINS_READSANDWRITES 0x03
+#define LEGAL_FILENAME_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_.- /\\{}[]=()&%$!,;.+&%$~#@"
+
+static const value_string smb_eo_contains_string[] = {
+ {SMB_EO_CONTAINS_NOTHING, "" },
+ {SMB_EO_CONTAINS_READS, "R" },
+ {SMB_EO_CONTAINS_WRITES, "W" },
+ {SMB_EO_CONTAINS_READSANDWRITES, "R&W"},
+ {0, NULL}
+};
+
+/* Strings that describes the SMB object type */
+static const value_string smb_fid_types[] = {
+ {SMB_FID_TYPE_UNKNOWN,"UNKNOWN"},
+ {SMB_FID_TYPE_FILE,"FILE"},
+ {SMB_FID_TYPE_DIR,"DIRECTORY (Not Implemented)"},
+ {SMB_FID_TYPE_PIPE,"PIPE (Not Implemented)"},
+ {0, NULL}
+};
+
+static const value_string smb2_fid_types[] = {
+ {SMB2_FID_TYPE_UNKNOWN,"UNKNOWN"},
+ {SMB2_FID_TYPE_FILE,"FILE"},
+ {SMB2_FID_TYPE_DIR,"DIRECTORY (Not Implemented)"},
+ {SMB2_FID_TYPE_PIPE,"PIPE (Not Implemented)"},
+ {SMB2_FID_TYPE_OTHER,"OTHER (Not Implemented)"},
+ {0, NULL}
+};
+
+
+/* This struct contains the relationship between
+ the row# in the export_object window and the file being captured;
+ the row# in this GSList will match the row# in the entry list */
+
+typedef struct _active_file {
+ guint16 tid, uid, fid;
+ guint64 file_length; /* The last free reported offset. We treat it as the file length */
+ guint64 data_gathered; /* The actual total of data gathered */
+ guint8 flag_contains; /* What kind of data it contains */
+ GSList *free_chunk_list; /* A list of virtual "holes" in the file stream stored in memory */
+ gboolean is_out_of_memory; /* TRUE if we cannot allocate memory for this file */
+} active_file ;
+
+/* This is the GSList that will contain all the files that we are tracking */
+static GSList *GSL_active_files = NULL;
+
+/* We define a free chunk in a file as an start offset and end offset
+ Consider a free chunk as a "hole" in a file that we are capturing */
+typedef struct _free_chunk {
+ guint64 start_offset;
+ guint64 end_offset;
+} free_chunk;
+
+/* insert_chunk function will recalculate the free_chunk_list, the data_size,
+ the end_of_file, and the data_gathered as appropriate.
+ It will also insert the data chunk that is coming in the right
+ place of the file in memory.
+ HINTS:
+ file->data_gathered contains the real data gathered independently from the file length
+ file->file_length contains the length of the file in memory, i.e.,
+ the last offset captured. In most cases, the real
+ file length would be different.
+*/
+static void
+insert_chunk(active_file *file, export_object_entry_t *entry, const smb_eo_t *eo_info)
+{
+ gint nfreechunks = g_slist_length(file->free_chunk_list);
+ gint i;
+ free_chunk *current_free_chunk;
+ free_chunk *new_free_chunk;
+ guint64 chunk_offset = eo_info->smb_file_offset;
+ guint64 chunk_length = eo_info->payload_len;
+ guint64 chunk_end_offset = chunk_offset + chunk_length-1;
+ /* Size of file in memory */
+ guint64 calculated_size = chunk_offset + chunk_length;
+ gpointer dest_memory_addr;
+
+ /* Let's recalculate the file length and data gathered */
+ if ((file->data_gathered == 0) && (nfreechunks == 0)) {
+ /* If this is the first entry for this file, we first create an initial free chunk */
+ new_free_chunk = g_new(free_chunk, 1);
+ new_free_chunk->start_offset = 0;
+ new_free_chunk->end_offset = MAX(file->file_length, chunk_end_offset+1) - 1;
+ file->free_chunk_list = NULL;
+ file->free_chunk_list = g_slist_append(file->free_chunk_list, new_free_chunk);
+ nfreechunks += 1;
+ } else {
+ if (chunk_end_offset > file->file_length-1) {
+ new_free_chunk = g_new(free_chunk, 1);
+ new_free_chunk->start_offset = file->file_length;
+ new_free_chunk->end_offset = chunk_end_offset;
+ file->free_chunk_list = g_slist_append(file->free_chunk_list, new_free_chunk);
+ nfreechunks += 1;
+ }
+ }
+ file->file_length = MAX(file->file_length, chunk_end_offset+1);
+
+ /* Recalculate each free chunk according with the incoming data chunk */
+ for (i=0; i<nfreechunks; i++) {
+ current_free_chunk = (free_chunk *)g_slist_nth_data(file->free_chunk_list, i);
+ /* 1. data chunk before the free chunk? */
+ /* -> free chunk is not altered and no new data gathered */
+ if (chunk_end_offset<current_free_chunk->start_offset) {
+ continue;
+ }
+ /* 2. data chunk overlaps the first part of free_chunk */
+ /* -> free chunk shrinks from the beginning */
+ if (chunk_offset<=current_free_chunk->start_offset && chunk_end_offset>=current_free_chunk->start_offset && chunk_end_offset<current_free_chunk->end_offset) {
+ file->data_gathered += chunk_end_offset-current_free_chunk->start_offset+1;
+ current_free_chunk->start_offset=chunk_end_offset+1;
+ continue;
+ }
+ /* 3. data chunk overlaps completely the free chunk */
+ /* -> free chunk is removed */
+ if (chunk_offset<=current_free_chunk->start_offset && chunk_end_offset>=current_free_chunk->end_offset) {
+ file->data_gathered += current_free_chunk->end_offset-current_free_chunk->start_offset+1;
+ file->free_chunk_list = g_slist_remove(file->free_chunk_list, current_free_chunk);
+ nfreechunks -= 1;
+ if (nfreechunks == 0) { /* The free chunk list is empty */
+ g_slist_free(file->free_chunk_list);
+ file->free_chunk_list = NULL;
+ break;
+ }
+ i--;
+ continue;
+ }
+ /* 4. data chunk is inside the free chunk */
+ /* -> free chunk is split into two */
+ if (chunk_offset>current_free_chunk->start_offset && chunk_end_offset<current_free_chunk->end_offset) {
+ new_free_chunk = g_new(free_chunk, 1);
+ new_free_chunk->start_offset = chunk_end_offset + 1;
+ new_free_chunk->end_offset = current_free_chunk->end_offset;
+ current_free_chunk->end_offset = chunk_offset-1;
+ file->free_chunk_list = g_slist_insert(file->free_chunk_list, new_free_chunk, i + 1);
+ file->data_gathered += chunk_length;
+ continue;
+ }
+ /* 5.- data chunk overlaps the end part of free chunk */
+ /* -> free chunk shrinks from the end */
+ if (chunk_offset>current_free_chunk->start_offset && chunk_offset<=current_free_chunk->end_offset && chunk_end_offset>=current_free_chunk->end_offset) {
+ file->data_gathered += current_free_chunk->end_offset-chunk_offset+1;
+ current_free_chunk->end_offset = chunk_offset-1;
+ continue;
+ }
+ /* 6.- data chunk is after the free chunk */
+ /* -> free chunk is not altered and no new data gathered */
+ if (chunk_offset>current_free_chunk->end_offset) {
+ continue;
+ }
+ }
+
+ /* Now, let's insert the data chunk into memory
+ ...first, we shall be able to allocate the memory */
+ if (!entry->payload_data) {
+ /* This is a New file */
+ if (calculated_size > G_MAXSIZE) {
+ /*
+ * The argument to g_try_malloc() is
+ * a gsize, the maximum value of which is
+ * G_MAXSIZE. If the calculated size is
+ * bigger than that, we just say the attempt
+ * to allocate memory failed.
+ */
+ entry->payload_data = NULL;
+ } else {
+ entry->payload_data = (guint8 *)g_try_malloc((gsize)calculated_size);
+ entry->payload_len = calculated_size;
+ }
+ if (!entry->payload_data) {
+ /* Memory error */
+ file->is_out_of_memory = TRUE;
+ }
+ } else {
+ /* This is an existing file in memory */
+ if (calculated_size > (guint64) entry->payload_len &&
+ !file->is_out_of_memory) {
+ /* We need more memory */
+ if (calculated_size > G_MAXSIZE) {
+ /*
+ * As for g_try_malloc(), so for
+ * g_try_realloc().
+ */
+ dest_memory_addr = NULL;
+ } else {
+ dest_memory_addr = g_try_realloc(
+ entry->payload_data,
+ (gsize)calculated_size);
+ }
+ if (!dest_memory_addr) {
+ /* Memory error */
+ file->is_out_of_memory = TRUE;
+ /* We don't have memory for this file.
+ Free the current file content from memory */
+ g_free(entry->payload_data);
+ entry->payload_data = NULL;
+ entry->payload_len = 0;
+ } else {
+ entry->payload_data = (guint8 *)dest_memory_addr;
+ entry->payload_len = calculated_size;
+ }
+ }
+ }
+ /* ...then, put the chunk of the file in the right place */
+ if (!file->is_out_of_memory) {
+ dest_memory_addr = entry->payload_data + chunk_offset;
+ memmove(dest_memory_addr, eo_info->payload_data, eo_info->payload_len);
+ }
+}
+
+/* We use this function to obtain the index in the GSL of a given file */
+static int
+find_incoming_file(GSList *GSL_active_files_p, active_file *incoming_file)
+{
+ int i, row, last;
+ active_file *in_list_file;
+
+ row = -1;
+ last = g_slist_length(GSL_active_files_p) - 1;
+
+ /* We lookup in reverse order because it is more likely that the file
+ is one of the latest */
+ for (i=last; i>=0; i--) {
+ in_list_file = (active_file *)g_slist_nth_data(GSL_active_files_p, i);
+ /* The best-working criteria of two identical files is that the file
+ that is the same of the file that we are analyzing is the last one
+ in the list that has the same tid and the same fid */
+ /* note that we have excluded in_list_file->uid == incoming_file->uid
+ from the comparison, because a file can be opened by different
+ SMB users and it is still the same file */
+ if (in_list_file->tid == incoming_file->tid &&
+ in_list_file->fid == incoming_file->fid) {
+ row = i;
+ break;
+ }
+ }
+
+ return row;
+}
+
+static gboolean
+smb_eo_packet(void *tapdata, packet_info *pinfo, epan_dissect_t *edt _U_, const void *data)
+{
+ export_object_list_t *object_list = (export_object_list_t *)tapdata;
+ const smb_eo_t *eo_info = (const smb_eo_t *)data;
+
+ export_object_entry_t *entry;
+ export_object_entry_t *current_entry;
+ active_file incoming_file;
+ gint active_row;
+ active_file *new_file;
+ active_file *current_file;
+ guint8 contains;
+ gboolean is_supported_filetype;
+ gfloat percent;
+
+ gchar *aux_smb_fid_type_string;
+
+ if (eo_info->smbversion==1) {
+ /* Is this an eo_smb supported file_type? (right now we only support FILE) */
+ is_supported_filetype = (eo_info->fid_type == SMB_FID_TYPE_FILE);
+ aux_smb_fid_type_string=g_strdup(try_val_to_str(eo_info->fid_type, smb_fid_types));
+
+ /* What kind of data this packet contains? */
+ switch(eo_info->cmd) {
+ case SMB_COM_READ_ANDX:
+ case SMB_COM_READ:
+ contains = SMB_EO_CONTAINS_READS;
+ break;
+ case SMB_COM_WRITE_ANDX:
+ case SMB_COM_WRITE:
+ contains = SMB_EO_CONTAINS_WRITES;
+ break;
+ default:
+ contains = SMB_EO_CONTAINS_NOTHING;
+ break;
+ }
+ } else {
+ /* Is this an eo_smb supported file_type? (right now we only support FILE) */
+ is_supported_filetype = (eo_info->fid_type == SMB2_FID_TYPE_FILE );
+ aux_smb_fid_type_string=g_strdup(try_val_to_str(eo_info->fid_type, smb2_fid_types));
+
+ /* What kind of data this packet contains? */
+ switch(eo_info->cmd) {
+ case SMB2_COM_READ:
+ contains = SMB_EO_CONTAINS_READS;
+ break;
+ case SMB2_COM_WRITE:
+ contains = SMB_EO_CONTAINS_WRITES;
+ break;
+ default:
+ contains = SMB_EO_CONTAINS_NOTHING;
+ break;
+ }
+ }
+
+
+ /* Is this data from an already tracked file or not? */
+ incoming_file.tid = eo_info->tid;
+ incoming_file.uid = eo_info->uid;
+ incoming_file.fid = eo_info->fid;
+ active_row = find_incoming_file(GSL_active_files, &incoming_file);
+
+ if (active_row == -1) { /* This is a new-tracked file */
+ /* Construct the entry in the list of active files */
+ entry = g_new(export_object_entry_t, 1);
+ entry->payload_data = NULL;
+ entry->payload_len = 0;
+ new_file = (active_file *)g_malloc(sizeof(active_file));
+ new_file->tid = incoming_file.tid;
+ new_file->uid = incoming_file.uid;
+ new_file->fid = incoming_file.fid;
+ new_file->file_length = eo_info->end_of_file;
+ new_file->flag_contains = contains;
+ new_file->free_chunk_list = NULL;
+ new_file->data_gathered = 0;
+ new_file->is_out_of_memory = FALSE;
+ entry->pkt_num = pinfo->num;
+
+ entry->hostname=g_filename_display_name(g_strcanon(eo_info->hostname,LEGAL_FILENAME_CHARS,'?'));
+ entry->filename=g_filename_display_name(g_strcanon(eo_info->filename,LEGAL_FILENAME_CHARS,'?'));
+
+ /* Insert the first chunk in the chunk list of this file */
+ if (is_supported_filetype) {
+ insert_chunk(new_file, entry, eo_info);
+ }
+
+ if (new_file->is_out_of_memory) {
+ entry->content_type =
+ g_strdup_printf("%s (%"G_GUINT64_FORMAT"?/%"G_GUINT64_FORMAT") %s [mem!!]",
+ aux_smb_fid_type_string,
+ new_file->data_gathered,
+ new_file->file_length,
+ try_val_to_str(contains, smb_eo_contains_string));
+ } else {
+ if (new_file->file_length > 0) {
+ percent = (gfloat) (100*new_file->data_gathered/new_file->file_length);
+ } else {
+ percent = 0.0f;
+ }
+
+ entry->content_type =
+ g_strdup_printf("%s (%"G_GUINT64_FORMAT"/%"G_GUINT64_FORMAT") %s [%5.2f%%]",
+ aux_smb_fid_type_string,
+ new_file->data_gathered,
+ new_file->file_length,
+ try_val_to_str(contains, smb_eo_contains_string),
+ percent);
+ }
+
+ object_list->add_entry(object_list->gui_data, entry);
+ GSL_active_files = g_slist_append(GSL_active_files, new_file);
+ }
+ else if (is_supported_filetype) {
+ current_file = (active_file *)g_slist_nth_data(GSL_active_files, active_row);
+ /* Recalculate the current file flags */
+ current_file->flag_contains = current_file->flag_contains|contains;
+ current_entry = object_list->get_entry(object_list->gui_data, active_row);
+
+ insert_chunk(current_file, current_entry, eo_info);
+
+ /* Modify the current_entry object_type string */
+ if (current_file->is_out_of_memory) {
+ current_entry->content_type =
+ g_strdup_printf("%s (%"G_GUINT64_FORMAT"?/%"G_GUINT64_FORMAT") %s [mem!!]",
+ aux_smb_fid_type_string,
+ current_file->data_gathered,
+ current_file->file_length,
+ try_val_to_str(current_file->flag_contains, smb_eo_contains_string));
+ } else {
+ percent = (gfloat) (100*current_file->data_gathered/current_file->file_length);
+ current_entry->content_type =
+ g_strdup_printf("%s (%"G_GUINT64_FORMAT"/%"G_GUINT64_FORMAT") %s [%5.2f%%]",
+ aux_smb_fid_type_string,
+ current_file->data_gathered,
+ current_file->file_length,
+ try_val_to_str(current_file->flag_contains, smb_eo_contains_string),
+ percent);
+ }
+ }
+
+ return TRUE; /* State changed - window should be redrawn */
+}
+
+/* This is the eo_reset_cb function that is used in the export_object module
+ to cleanup any previous private data of the export object functionality before perform
+ the eo_reset function or when the window closes */
+void
+smb_eo_cleanup(void)
+{
+ int i, last;
+ active_file *in_list_file;
+
+ /* Free any previous data structures used in previous invocation to the
+ export_object_smb function */
+ last = g_slist_length(GSL_active_files);
+ if (GSL_active_files) {
+ for (i=last-1; i>=0; i--) {
+ in_list_file = (active_file *)g_slist_nth_data(GSL_active_files, i);
+ if (in_list_file->free_chunk_list) {
+ g_slist_free(in_list_file->free_chunk_list);
+ in_list_file->free_chunk_list = NULL;
+ }
+ g_free(in_list_file);
+ }
+ g_slist_free(GSL_active_files);
+ GSL_active_files = NULL;
+ }
+}
+
+/*
* Macros for use in the main dissector routines for an SMB.
*/
@@ -20621,12 +21039,11 @@ proto_register_smb(void)
register_init_routine(smb_trans_reassembly_init);
smb_tap = register_tap("smb");
- /* Register the tap for the "Export Object" function */
- smb_eo_tap = register_tap("smb_eo"); /* SMB Export Object tap */
-
register_dissector("smb", dissect_smb, proto_smb);
register_srt_table(proto_smb, NULL, 3, smbstat_packet, smbstat_init, NULL);
+ /* Register the tap for the "Export Object" function */
+ smb_eo_tap = register_export_object(proto_smb, smb_eo_packet, smb_eo_cleanup);
}
void
diff --git a/epan/dissectors/packet-tftp.c b/epan/dissectors/packet-tftp.c
index b60c716222..ca108b0f57 100644
--- a/epan/dissectors/packet-tftp.c
+++ b/epan/dissectors/packet-tftp.c
@@ -46,6 +46,7 @@
#include <epan/expert.h>
#include <epan/prefs.h>
#include <epan/tap.h>
+#include <epan/export_object.h>
#include "packet-tftp.h"
@@ -140,6 +141,94 @@ static const value_string tftp_error_code_vals[] = {
static int tftp_eo_tap = -1;
+/* A list of block list entries to delete from cleanup callback when window is closed. */
+typedef struct eo_info_dynamic_t {
+ gchar *filename;
+ GSList *block_list;
+} eo_info_dynamic_t;
+static GSList *s_dynamic_info_list = NULL;
+
+/* Tap function */
+static gboolean
+tftp_eo_packet(void *tapdata, packet_info *pinfo, epan_dissect_t *edt _U_, const void *data)
+{
+ export_object_list_t *object_list = (export_object_list_t *)tapdata;
+ const tftp_eo_t *eo_info = (const tftp_eo_t *)data;
+ export_object_entry_t *entry;
+
+ GSList *block_iterator;
+ guint payload_data_offset = 0;
+ eo_info_dynamic_t *dynamic_info;
+
+ /* These values will be freed when the Export Object window is closed. */
+ entry = g_new(export_object_entry_t, 1);
+
+ /* Remember which frame had the last block of the file */
+ entry->pkt_num = pinfo->num;
+
+ /* Copy filename */
+ entry->filename = g_path_get_basename(eo_info->filename);
+
+ /* Iterate over list of blocks and concatenate into contiguous memory */
+ entry->payload_len = eo_info->payload_len;
+ entry->payload_data = (guint8 *)g_try_malloc((gsize)entry->payload_len);
+ for (block_iterator = eo_info->block_list; block_iterator; block_iterator = block_iterator->next) {
+ file_block_t *block = (file_block_t*)block_iterator->data;
+ memcpy(entry->payload_data + payload_data_offset,
+ block->data,
+ block->length);
+ payload_data_offset += block->length;
+ }
+
+ /* These 2 fields not used */
+ entry->hostname = NULL;
+ entry->content_type = NULL;
+
+ /* Add to list of entries to be cleaned up. eo_info is only packet scope, so
+ need to make list only of block list now */
+ dynamic_info = g_new(eo_info_dynamic_t, 1);
+ dynamic_info->filename = eo_info->filename;
+ dynamic_info->block_list = eo_info->block_list;
+ s_dynamic_info_list = g_slist_append(s_dynamic_info_list, (eo_info_dynamic_t*)dynamic_info);
+
+ /* Pass out entry to the GUI */
+ object_list->add_entry(object_list->gui_data, entry);
+
+ return TRUE; /* State changed - window should be redrawn */
+}
+
+/* Clean up the stored parts of a single tapped entry */
+static void cleanup_tftp_eo(eo_info_dynamic_t *dynamic_info)
+{
+ GSList *block_iterator;
+ /* Free the filename */
+ g_free(dynamic_info->filename);
+
+ /* Walk list of block items */
+ for (block_iterator = dynamic_info->block_list; block_iterator; block_iterator = block_iterator->next) {
+ file_block_t *block = (file_block_t*)(block_iterator->data);
+ /* Free block data */
+ wmem_free(NULL, block->data);
+
+ /* Free block itself */
+ g_free(block);
+ }
+}
+
+/* Callback for freeing up data supplied with taps. The taps themselves only have
+ packet scope, so only store/free dynamic memory pointers */
+void tftp_eo_cleanup(void)
+{
+ /* Cleanup each entry in the global list */
+ GSList *dynamic_iterator;
+ for (dynamic_iterator = s_dynamic_info_list; dynamic_iterator; dynamic_iterator = dynamic_iterator->next) {
+ eo_info_dynamic_t *dynamic_info = (eo_info_dynamic_t*)dynamic_iterator->data;
+ cleanup_tftp_eo(dynamic_info);
+ }
+ /* List is empty again */
+ s_dynamic_info_list = NULL;
+}
+
static void
tftp_dissect_options(tvbuff_t *tvb, packet_info *pinfo, int offset,
proto_tree *tree, guint16 opcode, tftp_conv_info_t *tftp_info)
@@ -684,7 +773,7 @@ proto_register_tftp(void)
prefs_register_protocol(proto_tftp, apply_tftp_prefs);
/* Register the tap for the "Export Object" function */
- tftp_eo_tap = register_tap("tftp_eo"); /* TFTP Export Object tap */
+ tftp_eo_tap = register_export_object(proto_tftp, tftp_eo_packet, tftp_eo_cleanup);
}
void
diff --git a/epan/export_object.c b/epan/export_object.c
new file mode 100644
index 0000000000..5c7d38fb6e
--- /dev/null
+++ b/epan/export_object.c
@@ -0,0 +1,206 @@
+/* export_object.c
+ * GUI independent helper routines common to all export object taps.
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include "proto.h"
+#include "packet_info.h"
+#include "export_object.h"
+
+struct register_eo {
+ int proto_id; /* protocol id (0-indexed) */
+ const char* tap_listen_str; /* string used in register_tap_listener (NULL to use protocol name) */
+ tap_packet_cb eo_func; /* function to be called for new incoming packets for SRT */
+ export_object_gui_reset_cb reset_cb; /* function to parse parameters of optional arguments of tap string */
+};
+
+static GSList *registered_eo_tables = NULL;
+
+static gint
+insert_sorted_by_table_name(gconstpointer aparam, gconstpointer bparam)
+{
+ const register_eo_t *a = (const register_eo_t *)aparam;
+ const register_eo_t *b = (const register_eo_t *)bparam;
+
+ return g_ascii_strcasecmp(proto_get_protocol_filter_name(a->proto_id), proto_get_protocol_filter_name(b->proto_id));
+}
+
+int
+register_export_object(const int proto_id, tap_packet_cb export_packet_func, export_object_gui_reset_cb reset_cb)
+{
+ register_eo_t *table;
+ DISSECTOR_ASSERT(export_packet_func);
+
+ table = g_new(register_eo_t,1);
+
+ table->proto_id = proto_id;
+ table->tap_listen_str = g_strdup_printf("%s_eo", proto_get_protocol_filter_name(proto_id));
+ table->eo_func = export_packet_func;
+ table->reset_cb = reset_cb;
+
+ registered_eo_tables = g_slist_insert_sorted(registered_eo_tables, table, insert_sorted_by_table_name);
+ return register_tap(table->tap_listen_str);
+}
+
+int get_eo_proto_id(register_eo_t* eo)
+{
+ if (!eo) {
+ return -1;
+ }
+ return eo->proto_id;
+}
+
+const char* get_eo_tap_listener_name(register_eo_t* eo)
+{
+ return eo->tap_listen_str;
+}
+
+tap_packet_cb get_eo_packet_func(register_eo_t* eo)
+{
+ return eo->eo_func;
+}
+
+export_object_gui_reset_cb get_eo_reset_func(register_eo_t* eo)
+{
+ return eo->reset_cb;
+}
+
+register_eo_t* get_eo_by_name(const char* name)
+{
+ guint i, size = g_slist_length(registered_eo_tables);
+ register_eo_t* eo;
+ GSList *slist;
+
+ for (i = 0; i < size; i++) {
+ slist = g_slist_nth(registered_eo_tables, i);
+ eo = (register_eo_t*)slist->data;
+
+ if (strcmp(name, proto_get_protocol_filter_name(eo->proto_id)) == 0)
+ return eo;
+ }
+
+ return NULL;
+}
+
+void eo_iterate_tables(GFunc func, gpointer user_data)
+{
+ g_slist_foreach(registered_eo_tables, func, user_data);
+}
+
+static GString *eo_rename(GString *gstr, int dupn)
+{
+ GString *gstr_tmp;
+ gchar *tmp_ptr;
+ GString *ext_str;
+
+ gstr_tmp = g_string_new("(");
+ g_string_append_printf (gstr_tmp, "%d)", dupn);
+ if ( (tmp_ptr = strrchr(gstr->str, '.')) != NULL ) {
+ /* Retain the extension */
+ ext_str = g_string_new(tmp_ptr);
+ gstr = g_string_truncate(gstr, gstr->len - ext_str->len);
+ if ( gstr->len >= (EXPORT_OBJECT_MAXFILELEN - (strlen(gstr_tmp->str) + ext_str->len)) )
+ gstr = g_string_truncate(gstr, EXPORT_OBJECT_MAXFILELEN - (strlen(gstr_tmp->str) + ext_str->len));
+ gstr = g_string_append(gstr, gstr_tmp->str);
+ gstr = g_string_append(gstr, ext_str->str);
+ g_string_free(ext_str, TRUE);
+ }
+ else {
+ if ( gstr->len >= (EXPORT_OBJECT_MAXFILELEN - strlen(gstr_tmp->str)) )
+ gstr = g_string_truncate(gstr, EXPORT_OBJECT_MAXFILELEN - strlen(gstr_tmp->str));
+ gstr = g_string_append(gstr, gstr_tmp->str);
+ }
+ g_string_free(gstr_tmp, TRUE);
+ return gstr;
+}
+
+GString *
+eo_massage_str(const gchar *in_str, gsize maxlen, int dupn)
+{
+ gchar *tmp_ptr;
+ /* The characters in "reject" come from:
+ * http://msdn.microsoft.com/en-us/library/aa365247%28VS.85%29.aspx.
+ * Add to the list as necessary for other OS's.
+ */
+ const gchar *reject = "<>:\"/\\|?*"
+ "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a"
+ "\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14"
+ "\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f";
+ GString *out_str;
+ GString *ext_str;
+
+ out_str = g_string_new("");
+
+ /* Find all disallowed characters/bytes and replace them with %xx */
+ while ( (tmp_ptr = strpbrk(in_str, reject)) != NULL ) {
+ out_str = g_string_append_len(out_str, in_str, tmp_ptr - in_str);
+ g_string_append_printf(out_str, "%%%02x", *tmp_ptr);
+ in_str = tmp_ptr + 1;
+ }
+ out_str = g_string_append(out_str, in_str);
+ if ( out_str->len > maxlen ) {
+ if ( (tmp_ptr = strrchr(out_str->str, '.')) != NULL ) {
+ /* Retain the extension */
+ ext_str = g_string_new(tmp_ptr);
+ out_str = g_string_truncate(out_str, maxlen - ext_str->len);
+ out_str = g_string_append(out_str, ext_str->str);
+ g_string_free(ext_str, TRUE);
+ }
+ else
+ out_str = g_string_truncate(out_str, maxlen);
+ }
+ if ( dupn != 0 )
+ out_str = eo_rename(out_str, dupn);
+ return out_str;
+}
+
+const char *
+eo_ct2ext(const char *content_type)
+{
+ /* TODO: Map the content type string to an extension string. If no match,
+ * return NULL. */
+ return content_type;
+}
+
+void eo_free_entry(export_object_entry_t *entry)
+{
+ g_free(entry->hostname);
+ g_free(entry->content_type);
+ g_free(entry->filename);
+ g_free(entry->payload_data);
+
+ g_free(entry);
+}
+/*
+ * Editor modelines
+ *
+ * Local Variables:
+ * c-basic-offset: 4
+ * tab-width: 8
+ * indent-tabs-mode: nil
+ * End:
+ *
+ * ex: set shiftwidth=4 tabstop=8 expandtab:
+ * :indentSize=4:tabSize=8:noTabs=true:
+ */
diff --git a/epan/export_object.h b/epan/export_object.h
new file mode 100644
index 0000000000..bd068e87c4
--- /dev/null
+++ b/epan/export_object.h
@@ -0,0 +1,155 @@
+/* export_object.h
+ * GUI independent helper routines common to all export object taps.
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef __EXPORT_OBJECT_H__
+#define __EXPORT_OBJECT_H__
+
+#include "tap.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+typedef struct _export_object_entry_t {
+ guint32 pkt_num;
+ gchar *hostname;
+ gchar *content_type;
+ gchar *filename;
+ /* We need to store a 64 bit integer to hold a file length
+ (was guint payload_len;) */
+ gint64 payload_len;
+ guint8 *payload_data;
+} export_object_entry_t;
+
+#define EXPORT_OBJECT_MAXFILELEN 255
+
+typedef void (*export_object_object_list_add_entry_cb)(void* gui_data, struct _export_object_entry_t *entry);
+typedef export_object_entry_t* (*export_object_object_list_get_entry_cb)(void* gui_data, int row);
+
+typedef struct _export_object_list_t {
+ export_object_object_list_add_entry_cb add_entry; //GUI specific handler for adding an object entry
+ export_object_object_list_get_entry_cb get_entry; //GUI specific handler for retrieving an object entry
+ void* gui_data; //GUI specific data (for UI representation)
+} export_object_list_t;
+
+/** Structure for information about a registered exported object */
+typedef struct register_eo register_eo_t;
+
+/* When a protocol needs intermediate data structures to construct the
+export objects, then it must specify a function that cleans up all
+those data structures. This function is passed to export_object_window
+and called when tap reset or windows closes occurs. If no function is needed
+a NULL value should be passed instead */
+typedef void (*export_object_gui_reset_cb)(void);
+
+/** Register the export object handler for the Export Object windows.
+ *
+ * @param proto_id is the protocol with objects to export
+ * @param export_packet_func the tap processing function
+ * @param reset_cb handles clearing intermediate data structures constructed
+ * for exporting objects. If no function is needed a NULL value should be passed instead
+ * @return Tap id registered for the Export Object
+ */
+WS_DLL_PUBLIC int register_export_object(const int proto_id, tap_packet_cb export_packet_func, export_object_gui_reset_cb reset_cb);
+
+/** Get protocol ID from Export Object
+ *
+ * @param eo Registered Export Object
+ * @return protocol id of Export Object
+ */
+WS_DLL_PUBLIC int get_eo_proto_id(register_eo_t* eo);
+
+/** Get string for register_tap_listener call. Typically of the form <dissector_name>_eo
+ *
+ * @param eo Registered Export Object
+ * @return string for register_tap_listener call
+ */
+WS_DLL_PUBLIC const char* get_eo_tap_listener_name(register_eo_t* eo);
+
+/** Get tap function handler from Export Object
+ *
+ * @param eo Registered Export Object
+ * @return tap function handler of Export Object
+ */
+WS_DLL_PUBLIC tap_packet_cb get_eo_packet_func(register_eo_t* eo);
+
+/** Get tap reset function handler from Export Object
+ *
+ * @param eo Registered Export Object
+ * @return tap function handler of Export Object
+ */
+WS_DLL_PUBLIC export_object_gui_reset_cb get_eo_reset_func(register_eo_t* eo);
+
+/** Get Export Object by its short protocol name
+ *
+ * @param name short protocol name to fetch.
+ * @return Export Object handler pointer or NULL.
+ */
+WS_DLL_PUBLIC register_eo_t* get_eo_by_name(const char* name);
+
+/** Iterator to walk Export Object list and execute func
+ *
+ * @param func action to be performed on all Export Objects
+ * @param user_data any data needed to help perform function
+ */
+WS_DLL_PUBLIC void eo_iterate_tables(GFunc func, gpointer user_data);
+
+/** Find all disallowed characters/bytes and replace them with %xx
+ *
+ * @param in_str string to massage
+ * @param maxlen maximum size a string can be post massage
+ * @param dup return a copy of the massaged string (?)
+ * @return massaged string
+ */
+WS_DLL_PUBLIC GString *eo_massage_str(const gchar *in_str, gsize maxlen, int dup);
+
+/** Map the content type string to an extension string
+ *
+ * @param content_type content type to match with extension string
+ * @return extension string for content type
+ */
+WS_DLL_PUBLIC const char *eo_ct2ext(const char *content_type);
+
+/** Free the contents of export_object_entry_t structure
+ *
+ * @param entry export_object_entry_t structure to be freed
+ */
+WS_DLL_PUBLIC void eo_free_entry(export_object_entry_t *entry);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __EXPORT_OBJECT_H__ */
+
+/*
+ * Editor modelines
+ *
+ * Local Variables:
+ * c-basic-offset: 4
+ * tab-width: 8
+ * indent-tabs-mode: nil
+ * End:
+ *
+ * ex: set shiftwidth=4 tabstop=8 expandtab:
+ * :indentSize=4:tabSize=8:noTabs=true:
+ */