diff options
Diffstat (limited to 'epan/dissectors')
-rw-r--r-- | epan/dissectors/packet-dcm.c | 35 | ||||
-rw-r--r-- | epan/dissectors/packet-http.c | 31 | ||||
-rw-r--r-- | epan/dissectors/packet-imf.c | 32 | ||||
-rw-r--r-- | epan/dissectors/packet-smb.c | 423 | ||||
-rw-r--r-- | epan/dissectors/packet-tftp.c | 91 |
5 files changed, 605 insertions, 7 deletions
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 |