diff options
-rw-r--r-- | epan/dissectors/packet-tftp.c | 134 | ||||
-rw-r--r-- | epan/dissectors/packet-tftp.h | 42 | ||||
-rw-r--r-- | ui/Makefile.common | 1 | ||||
-rw-r--r-- | ui/export_object.h | 3 | ||||
-rw-r--r-- | ui/export_object_tftp.c | 139 | ||||
-rw-r--r-- | ui/gtk/export_object_dlg.c | 7 | ||||
-rw-r--r-- | ui/gtk/export_object_dlg.h | 1 | ||||
-rw-r--r-- | ui/gtk/main_menubar.c | 3 |
8 files changed, 326 insertions, 4 deletions
diff --git a/epan/dissectors/packet-tftp.c b/epan/dissectors/packet-tftp.c index 4e3eee15b7..60e94bb64b 100644 --- a/epan/dissectors/packet-tftp.c +++ b/epan/dissectors/packet-tftp.c @@ -48,6 +48,9 @@ #include <epan/expert.h> #include <epan/range.h> #include <epan/prefs.h> +#include <epan/tap.h> + +#include "packet-tftp.h" void proto_register_tftp(void); @@ -55,6 +58,15 @@ void proto_register_tftp(void); typedef struct _tftp_conv_info_t { guint16 blocksize; gchar *source_file, *destination_file; + + /* Sequence analysis */ + guint next_block_num; + gboolean blocks_missing; + + /* When exporting file object, build up list of data blocks here */ + guint next_tap_block_num; + GSList *block_list; + guint file_length; } tftp_conv_info_t; @@ -116,6 +128,8 @@ static const value_string tftp_error_code_vals[] = { { 0, NULL } }; +static int tftp_eo_tap = -1; + static void tftp_dissect_options(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *tree, guint16 opcode, tftp_conv_info_t *tftp_info) @@ -160,6 +174,24 @@ tftp_dissect_options(tvbuff_t *tvb, packet_info *pinfo, int offset, } } +static void cleanup_tftp_blocks(tftp_conv_info_t *conv) +{ + GSList *block_iterator; + + /* Walk list of block items */ + for (block_iterator = conv->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); + } + conv->block_list = NULL; + conv->file_length = 0; +} + + static void dissect_tftp_message(tftp_conv_info_t *tftp_info, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) @@ -172,6 +204,7 @@ static void dissect_tftp_message(tftp_conv_info_t *tftp_info, guint16 blocknum; guint i1; guint16 error; + tvbuff_t *data_tvb; col_set_str(pinfo->cinfo, COL_PROTOCOL, "TFTP"); @@ -264,18 +297,99 @@ static void dissect_tftp_message(tftp_conv_info_t *tftp_info, proto_tree_add_uint(tftp_tree, hf_tftp_blocknum, tvb, offset, 2, blocknum); + /* Sequence analysis on blocknums (first pass only) */ + if (!pinfo->fd->flags.visited) { + if (blocknum > tftp_info->next_block_num) { + /* There is a gap. Don't try to recover from this. */ + tftp_info->next_block_num = blocknum + 1; + tftp_info->blocks_missing = TRUE; + /* TODO: add info to a result table for showing expert info in later passes */ + } + else if (blocknum == tftp_info->next_block_num) { + /* OK, inc what we expect next */ + tftp_info->next_block_num++; + } + } offset += 2; + /* Show number of bytes in this block, and whether it is the end of the file */ bytes = tvb_reported_length_remaining(tvb, offset); - col_append_fstr(pinfo->cinfo, COL_INFO, ", Block: %i%s", blocknum, (bytes < tftp_info->blocksize)?" (last)":"" ); - if (bytes != 0) { - tvbuff_t *data_tvb = tvb_new_subset(tvb, offset, -1, bytes); + /* Show data in tree */ + if (bytes > 0) { + data_tvb = tvb_new_subset(tvb, offset, -1, bytes); call_dissector(data_handle, data_tvb, pinfo, tree); } + + /* If Export Object tap is listening, need to accumulate blocks info list + to send to tap. But if already know there are blocks missing, there is no + point in trying. */ + if (have_tap_listener(tftp_eo_tap) && !tftp_info->blocks_missing) { + file_block_t *block; + + if (blocknum == 1) { + /* Reset data for this conversation, freeing any accumulated blocks! */ + cleanup_tftp_blocks(tftp_info); + tftp_info->next_tap_block_num = 1; + } + + if (blocknum != tftp_info->next_tap_block_num) { + /* Ignore. Could be missing frames, or just clicking previous frame */ + return; + } + + if (bytes > 0) { + /* Create a block for this block */ + block = (file_block_t*)g_malloc(sizeof(file_block_t)); + block->length = bytes; + block->data = tvb_memdup(NULL, data_tvb, 0, bytes); + + /* Add to the end of the list (does involve traversing whole list..) */ + tftp_info->block_list = g_slist_append(tftp_info->block_list, block); + tftp_info->file_length += bytes; + + /* Look for next blocknum next time */ + tftp_info->next_tap_block_num++; + } + + /* Tap export object only when reach end of file */ + if (bytes < tftp_info->blocksize) { + tftp_eo_t *eo_info; + + /* If don't have a filename, won't tap file info */ + if ((tftp_info->source_file == NULL) && (tftp_info->destination_file == NULL)) { + cleanup_tftp_blocks(tftp_info); + return; + } + + /* Create the eo_info to pass to the listener */ + eo_info = wmem_new(wmem_packet_scope(), tftp_eo_t); + + /* Set filename */ + if (tftp_info->source_file) { + eo_info->filename = g_strdup(tftp_info->source_file); + } + else if (tftp_info->destination_file) { + eo_info->filename = g_strdup(tftp_info->destination_file); + } + + /* Send block list, which will be combined and freed at tap. */ + eo_info->payload_len = tftp_info->file_length; + eo_info->pkt_num = blocknum; + eo_info->block_list = tftp_info->block_list; + + /* Send to tap */ + tap_queue_packet(tftp_eo_tap, pinfo, eo_info); + + /* Have sent, so forget list of blocks, and only pay attention if we + get back to the first block again. */ + tftp_info->block_list = NULL; + tftp_info->next_tap_block_num = 1; + } + } break; case TFTP_ACK: @@ -340,6 +454,12 @@ dissect_embeddedtftp_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, v tftp_info->blocksize = 512; /* TFTP default block size */ tftp_info->source_file = NULL; tftp_info->destination_file = NULL; + tftp_info->next_block_num = 1; + tftp_info->blocks_missing = FALSE; + tftp_info->next_tap_block_num = 1; + tftp_info->block_list = NULL; + tftp_info->file_length = 0; + conversation_add_proto_data(conversation, proto_tftp, tftp_info); } @@ -412,6 +532,11 @@ dissect_tftp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) tftp_info->blocksize = 512; /* TFTP default block size */ tftp_info->source_file = NULL; tftp_info->destination_file = NULL; + tftp_info->next_block_num = 1; + tftp_info->blocks_missing = FALSE; + tftp_info->next_tap_block_num = 1; + tftp_info->block_list = NULL; + tftp_info->file_length = 0; conversation_add_proto_data(conversation, proto_tftp, tftp_info); } @@ -501,6 +626,9 @@ proto_register_tftp(void) "Port numbers used for TFTP traffic " "(default " UDP_PORT_TFTP_RANGE ")", &global_tftp_port_range, MAX_UDP_PORT); + + /* Register the tap for the "Export Object" function */ + tftp_eo_tap = register_tap("tftp_eo"); /* TFTP Export Object tap */ } void diff --git a/epan/dissectors/packet-tftp.h b/epan/dissectors/packet-tftp.h new file mode 100644 index 0000000000..d8c78ad0f7 --- /dev/null +++ b/epan/dissectors/packet-tftp.h @@ -0,0 +1,42 @@ +/* packet-tftp.h + * + * 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 __PACKET_TFTP_H__ +#define __PACKET_TFTP_H__ + +#include <epan/packet.h> + +/* When export file data, store list of separate blocks */ +typedef struct file_block_t { + void *data; + guint length; +} file_block_t; + +/* Used for TFTP Export Object feature */ +typedef struct _tftp_eo_t { + guint32 pkt_num; + gchar *filename; + guint32 payload_len; + GSList *block_list; +} tftp_eo_t; + + +#endif /* __PACKET_TFTP_H__ */ diff --git a/ui/Makefile.common b/ui/Makefile.common index a8a5531804..3e1f209a33 100644 --- a/ui/Makefile.common +++ b/ui/Makefile.common @@ -48,6 +48,7 @@ WIRESHARK_UI_SRC = \ export_object_dicom.c \ export_object_http.c \ export_object_smb.c \ + export_object_tftp.c \ follow.c \ iface_lists.c \ io_graph_item.c \ diff --git a/ui/export_object.h b/ui/export_object.h index 1767773124..44120a2573 100644 --- a/ui/export_object.h +++ b/ui/export_object.h @@ -60,8 +60,11 @@ gboolean eo_http_packet(void *tapdata, packet_info *pinfo, epan_dissect_t *edt _ const void *data); gboolean eo_smb_packet(void *tapdata, packet_info *pinfo, epan_dissect_t *edt _U_, const void *data); +gboolean eo_tftp_packet(void *tapdata, packet_info *pinfo, epan_dissect_t *edt _U_, + const void *data); void eo_smb_cleanup(void); +void eo_tftp_cleanup(void); #ifdef __cplusplus diff --git a/ui/export_object_tftp.c b/ui/export_object_tftp.c new file mode 100644 index 0000000000..34055e0d22 --- /dev/null +++ b/ui/export_object_tftp.c @@ -0,0 +1,139 @@ +/* export_object_tftp.c + * Routines for aving objects (files) found in TFTP sessions + * See also: export_object.c / export_object.h for common code + * Initial file, prototypes and general structure initially copied + * from export_object_smb.c + * + * Martin Mathieson + * + * 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 <glib.h> + +#include <epan/packet.h> +#include <epan/dissectors/packet-tftp.h> +#include <epan/tap.h> + +#include "export_object.h" + +/* 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 */ +gboolean +eo_tftp_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 = (export_object_entry_t*)g_malloc(sizeof(export_object_entry_t)); + + /* Remember which frame had the last block of the file */ + entry->pkt_num = pinfo->fd->num; + + /* Copy filename */ + entry->filename = g_strdup(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 = (eo_info_dynamic_t*)g_malloc(sizeof(eo_info_dynamic_t)); + 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, 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 eo_tftp_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; +} + +/* + * 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/ui/gtk/export_object_dlg.c b/ui/gtk/export_object_dlg.c index 7e6fd68fd5..2b72edbcc2 100644 --- a/ui/gtk/export_object_dlg.c +++ b/ui/gtk/export_object_dlg.c @@ -509,3 +509,10 @@ eo_smb_cb(GtkWidget *widget _U_, gpointer data _U_) /* Call the export_object window */ export_object_window("smb_eo", "SMB", eo_smb_packet, eo_smb_cleanup); } + +void +eo_tftp_cb(GtkWidget *widget _U_, gpointer data _U_) +{ + /* Call the export_object window */ + export_object_window("tftp_eo", "TFTP", eo_tftp_packet, eo_tftp_cleanup); +} diff --git a/ui/gtk/export_object_dlg.h b/ui/gtk/export_object_dlg.h index 803dee30e3..73fae69a34 100644 --- a/ui/gtk/export_object_dlg.h +++ b/ui/gtk/export_object_dlg.h @@ -29,5 +29,6 @@ void eo_dicom_cb(GtkWidget *widget _U_, gpointer data _U_); void eo_http_cb(GtkWidget *widget _U_, gpointer data _U_); void eo_smb_cb(GtkWidget *widget _U_, gpointer data _U_); +void eo_tftp_cb(GtkWidget *widget _U_, gpointer data _U_); #endif /* __EXPORT_OBJECT_DLG_H__ */ diff --git a/ui/gtk/main_menubar.c b/ui/gtk/main_menubar.c index 463311f93c..8966e99634 100644 --- a/ui/gtk/main_menubar.c +++ b/ui/gtk/main_menubar.c @@ -994,6 +994,7 @@ static const char *ui_desc_menubar = " <menuitem name='HTTP' action='/File/ExportObjects/HTTP'/>\n" " <menuitem name='DICOM' action='/File/ExportObjects/DICOM'/>\n" " <menuitem name='SMB' action='/File/ExportObjects/SMB'/>\n" +" <menuitem name='TFTP' action='/File/ExportObjects/TFTP'/>\n" " </menu>\n" " <separator/>\n" " <menuitem name='Print' action='/File/Print'/>\n" @@ -1468,7 +1469,7 @@ static const GtkActionEntry main_menu_bar_entries[] = { { "/File/ExportObjects/HTTP", NULL, "_HTTP", NULL, NULL, G_CALLBACK(eo_http_cb) }, { "/File/ExportObjects/DICOM", NULL, "_DICOM", NULL, NULL, G_CALLBACK(eo_dicom_cb) }, { "/File/ExportObjects/SMB", NULL, "_SMB/SMB2", NULL, NULL, G_CALLBACK(eo_smb_cb) }, - + { "/File/ExportObjects/TFTP", NULL, "_TFTP", NULL, NULL, G_CALLBACK(eo_tftp_cb) }, { "/Edit/Copy", NULL, "Copy", NULL, NULL, NULL }, |