forked from osmocom/wireshark
![Stephen Fisher](/assets/img/avatar_default.png)
- Split the HTTP tap into two taps: one for the HTTP statistics and the other for the export object function. This allows the HTTP statistics to work again (they seem to have been partially broken since SVN rev 18901). - Pass the conversation data (conv_data) between functions now instead of using the global variable stat_info (now only used for the HTTP stats) - Pass only pointers from the HTTP dissector to the Export Object tap, where we'll then copy the values and insert into the slist. - Make sure we free all memory allocated by this feature when we're done with it. - Various other minor improvements svn path=/trunk/; revision=21021
418 lines
12 KiB
C
418 lines
12 KiB
C
/* export_object.c
|
|
* Common routines for tracking & saving objects found in streams of data
|
|
* Copyright 2007, Stephen Fisher <stephentfisher@yahoo.com>
|
|
*
|
|
* $Id$
|
|
*
|
|
* 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.
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
# include "config.h"
|
|
#endif
|
|
|
|
#include <glib.h>
|
|
#include <gtk/gtk.h>
|
|
|
|
/* This feature has not been ported to GTK1 */
|
|
#if GTK_MAJOR_VERSION >= 2
|
|
|
|
#include <alert_box.h>
|
|
#include <simple_dialog.h>
|
|
|
|
#include <epan/packet_info.h>
|
|
#include <epan/prefs.h>
|
|
#include <epan/tap.h>
|
|
#include <gtk/compat_macros.h>
|
|
#include <gtk/dlg_utils.h>
|
|
#include <gtk/file_dlg.h>
|
|
#include <gtk/gui_utils.h>
|
|
#include <gtk/help_dlg.h>
|
|
#include <gtk/main.h>
|
|
#include <wiretap/file_util.h>
|
|
|
|
#ifdef HAVE_FCNTL_H
|
|
#include <fcntl.h>
|
|
#endif
|
|
|
|
#ifdef HAVE_UNISTD_H
|
|
#include <unistd.h>
|
|
#endif
|
|
|
|
#include "export_object.h"
|
|
|
|
enum {
|
|
EO_PKT_NUM_COLUMN,
|
|
EO_HOSTNAME_COLUMN,
|
|
EO_CONTENT_TYPE_COLUMN,
|
|
EO_BYTES_COLUMN,
|
|
EO_FILENAME_COLUMN,
|
|
EO_NUM_COLUMNS /* must be last */
|
|
};
|
|
|
|
|
|
static void
|
|
eo_remember_this_row(GtkTreeModel *model _U_, GtkTreePath *path,
|
|
GtkTreeIter *iter _U_, gpointer arg)
|
|
{
|
|
export_object_list_t *object_list = arg;
|
|
export_object_entry_t *entry;
|
|
|
|
gint *path_index;
|
|
|
|
if((path_index = gtk_tree_path_get_indices(path)) == NULL)
|
|
/* Row not found in tree - shouldn't happen */
|
|
return;
|
|
|
|
object_list->row_selected = path_index[0];
|
|
|
|
/* Select the corresponding packet in the packet list */
|
|
entry = g_slist_nth_data(object_list->entries,
|
|
object_list->row_selected);
|
|
cf_goto_frame(&cfile, entry->pkt_num);
|
|
}
|
|
|
|
static void
|
|
eo_remember_row_num(GtkTreeSelection *sel, gpointer data)
|
|
{
|
|
gtk_tree_selection_selected_foreach(sel, eo_remember_this_row, data);
|
|
}
|
|
|
|
|
|
/* Called when the Export Object window is closed in any way */
|
|
static void
|
|
eo_win_destroy_cb(GtkWindow *win _U_, gpointer data)
|
|
{
|
|
export_object_list_t *object_list = data;
|
|
export_object_entry_t *entry;
|
|
GSList *slist = object_list->entries;
|
|
|
|
protect_thread_critical_region();
|
|
remove_tap_listener(object_list);
|
|
unprotect_thread_critical_region();
|
|
|
|
while(slist) {
|
|
entry = slist->data;
|
|
|
|
g_free(entry->hostname);
|
|
g_free(entry->content_type);
|
|
g_free(entry->filename);
|
|
g_free(entry->payload_data);
|
|
|
|
slist = slist->next;
|
|
g_free(entry);
|
|
}
|
|
|
|
g_slist_free(object_list->entries);
|
|
g_free(object_list);
|
|
}
|
|
|
|
static void
|
|
eo_save_entry(gchar *save_as_filename, export_object_entry_t *entry)
|
|
{
|
|
int to_fd;
|
|
|
|
to_fd = eth_open(save_as_filename, O_WRONLY | O_CREAT | O_EXCL |
|
|
O_BINARY, 0644);
|
|
if(to_fd == -1) { /* An error occurred */
|
|
open_failure_alert_box(save_as_filename, errno, TRUE);
|
|
g_free(save_as_filename);
|
|
return;
|
|
}
|
|
|
|
if(eth_write(to_fd, entry->payload_data, entry->payload_len) < 0) {
|
|
write_failure_alert_box(save_as_filename, errno);
|
|
eth_close(to_fd);
|
|
g_free(save_as_filename);
|
|
return;
|
|
}
|
|
|
|
if (eth_close(to_fd) < 0) {
|
|
write_failure_alert_box(save_as_filename, errno);
|
|
g_free(save_as_filename);
|
|
return;
|
|
}
|
|
|
|
g_free(save_as_filename);
|
|
}
|
|
|
|
|
|
static void
|
|
eo_save_clicked_cb(GtkWidget *widget _U_, gpointer arg)
|
|
{
|
|
GtkWidget *save_as_w;
|
|
export_object_list_t *object_list = arg;
|
|
export_object_entry_t *entry = NULL;
|
|
|
|
entry = g_slist_nth_data(object_list->entries,
|
|
object_list->row_selected);
|
|
|
|
if(!entry) {
|
|
simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK, "No object was selected for saving. Please click on an object and click save again.");
|
|
return;
|
|
}
|
|
|
|
save_as_w = file_selection_new("Wireshark: Save Object As ...",
|
|
FILE_SELECTION_SAVE);
|
|
|
|
gtk_window_set_transient_for(GTK_WINDOW(save_as_w),
|
|
GTK_WINDOW(object_list->dlg));
|
|
|
|
gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(save_as_w),
|
|
entry->filename);
|
|
|
|
if(gtk_dialog_run(GTK_DIALOG(save_as_w)) == GTK_RESPONSE_ACCEPT)
|
|
eo_save_entry(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(save_as_w)), entry);
|
|
|
|
window_destroy(save_as_w);
|
|
}
|
|
|
|
static void
|
|
eo_save_all_clicked_cb(GtkWidget *widget _U_, gpointer arg)
|
|
{
|
|
gchar *save_as_fullpath;
|
|
export_object_list_t *object_list = arg;
|
|
export_object_entry_t *entry;
|
|
GtkWidget *save_in_w;
|
|
GSList *slist = object_list->entries;
|
|
|
|
save_in_w = file_selection_new("Wireshark: Save All Objects In ...",
|
|
FILE_SELECTION_CREATE_FOLDER);
|
|
|
|
gtk_window_set_transient_for(GTK_WINDOW(save_in_w),
|
|
GTK_WINDOW(object_list->dlg));
|
|
|
|
if(gtk_dialog_run(GTK_DIALOG(save_in_w)) == GTK_RESPONSE_ACCEPT) {
|
|
while(slist) {
|
|
entry = slist->data;
|
|
|
|
save_as_fullpath = g_build_filename(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(save_in_w)), entry->filename, NULL);
|
|
|
|
eo_save_entry(save_as_fullpath, entry);
|
|
|
|
slist = slist->next;
|
|
}
|
|
}
|
|
|
|
window_destroy(save_in_w);
|
|
}
|
|
|
|
/* Runs at the beginning of tapping only */
|
|
static void
|
|
eo_reset(void *tapdata)
|
|
{
|
|
export_object_list_t *object_list = tapdata;
|
|
|
|
object_list->entries = NULL;
|
|
object_list->iter = NULL;
|
|
object_list->row_selected = -1;
|
|
}
|
|
|
|
static void
|
|
eo_draw(void *tapdata)
|
|
{
|
|
export_object_list_t *object_list = tapdata;
|
|
export_object_entry_t *eo_entry;
|
|
|
|
GSList *slist = object_list->entries;
|
|
GtkTreeIter new_iter;
|
|
|
|
while(slist) {
|
|
eo_entry = slist->data;
|
|
|
|
gtk_tree_store_append(object_list->store, &new_iter,
|
|
object_list->iter);
|
|
|
|
gtk_tree_store_set(object_list->store, &new_iter,
|
|
EO_PKT_NUM_COLUMN, eo_entry->pkt_num,
|
|
EO_HOSTNAME_COLUMN, eo_entry->hostname,
|
|
EO_CONTENT_TYPE_COLUMN, eo_entry->content_type,
|
|
EO_BYTES_COLUMN, eo_entry->payload_len,
|
|
EO_FILENAME_COLUMN, eo_entry->filename,
|
|
-1);
|
|
|
|
slist = slist->next;
|
|
}
|
|
}
|
|
|
|
void
|
|
export_object_window(gchar *tapname, gchar *name, tap_packet_cb tap_packet)
|
|
{
|
|
GtkWidget *sw;
|
|
GtkCellRenderer *renderer;
|
|
GtkTreeViewColumn *column;
|
|
GtkTreeSelection *selection;
|
|
GtkWidget *vbox, *bbox, *help_bt, *close_bt, *save_bt, *save_all_bt;
|
|
GtkTooltips *button_bar_tips;
|
|
GString *error_msg;
|
|
export_object_list_t *object_list;
|
|
gchar *window_title;
|
|
|
|
/* Initialize our object list structure */
|
|
object_list = g_malloc0(sizeof(export_object_list_t));
|
|
|
|
/* Data will be gathered via a tap callback */
|
|
error_msg = register_tap_listener(tapname, object_list, NULL,
|
|
eo_reset,
|
|
tap_packet,
|
|
eo_draw);
|
|
|
|
if (error_msg) {
|
|
simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
|
|
"Can't register http tap: %s\n", error_msg->str);
|
|
g_string_free(error_msg, TRUE);
|
|
return;
|
|
}
|
|
|
|
/* Setup our GUI window */
|
|
button_bar_tips = gtk_tooltips_new();
|
|
|
|
window_title = g_strdup_printf("Wireshark: %s object list", name);
|
|
object_list->dlg = dlg_window_new(window_title);
|
|
g_free(window_title);
|
|
|
|
gtk_window_set_default_size(GTK_WINDOW(object_list->dlg),
|
|
DEF_WIDTH, DEF_HEIGHT);
|
|
|
|
vbox = gtk_vbox_new(FALSE, 5);
|
|
|
|
gtk_container_border_width(GTK_CONTAINER(vbox), 5);
|
|
gtk_container_add(GTK_CONTAINER(object_list->dlg), vbox);
|
|
|
|
sw = scrolled_window_new(NULL, NULL);
|
|
gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw),
|
|
GTK_SHADOW_IN);
|
|
|
|
gtk_container_add(GTK_CONTAINER(vbox), sw);
|
|
|
|
object_list->store = gtk_tree_store_new(EO_NUM_COLUMNS,
|
|
G_TYPE_INT, G_TYPE_STRING,
|
|
G_TYPE_STRING, G_TYPE_INT,
|
|
G_TYPE_STRING);
|
|
|
|
object_list->tree = tree_view_new(GTK_TREE_MODEL(object_list->store));
|
|
|
|
object_list->tree_view = GTK_TREE_VIEW(object_list->tree);
|
|
|
|
renderer = gtk_cell_renderer_text_new();
|
|
column = gtk_tree_view_column_new_with_attributes("Packet num",
|
|
renderer,
|
|
"text",
|
|
EO_PKT_NUM_COLUMN,
|
|
NULL);
|
|
gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
|
|
gtk_tree_view_append_column(object_list->tree_view, column);
|
|
|
|
renderer = gtk_cell_renderer_text_new();
|
|
column = gtk_tree_view_column_new_with_attributes("Hostname",
|
|
renderer,
|
|
"text",
|
|
EO_HOSTNAME_COLUMN,
|
|
NULL);
|
|
gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
|
|
gtk_tree_view_append_column(object_list->tree_view, column);
|
|
|
|
renderer = gtk_cell_renderer_text_new();
|
|
column = gtk_tree_view_column_new_with_attributes("Content Type",
|
|
renderer,
|
|
"text",
|
|
EO_CONTENT_TYPE_COLUMN,
|
|
NULL);
|
|
gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
|
|
gtk_tree_view_append_column(object_list->tree_view, column);
|
|
|
|
renderer = gtk_cell_renderer_text_new();
|
|
column = gtk_tree_view_column_new_with_attributes("Bytes",
|
|
renderer,
|
|
"text",
|
|
EO_BYTES_COLUMN,
|
|
NULL);
|
|
gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
|
|
gtk_tree_view_append_column(object_list->tree_view, column);
|
|
|
|
renderer = gtk_cell_renderer_text_new();
|
|
column = gtk_tree_view_column_new_with_attributes("Filename",
|
|
renderer,
|
|
"text",
|
|
EO_FILENAME_COLUMN,
|
|
NULL);
|
|
gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
|
|
gtk_tree_view_append_column(object_list->tree_view, column);
|
|
|
|
gtk_container_add(GTK_CONTAINER(sw), object_list->tree);
|
|
|
|
selection = gtk_tree_view_get_selection(object_list->tree_view);
|
|
SIGNAL_CONNECT(selection, "changed", eo_remember_row_num, object_list);
|
|
|
|
|
|
bbox = gtk_hbox_new(FALSE, 5);
|
|
|
|
/* Help button */
|
|
help_bt = BUTTON_NEW_FROM_STOCK(GTK_STOCK_HELP);
|
|
SIGNAL_CONNECT(help_bt, "clicked", topic_cb, HELP_EXPORT_OBJECT_LIST);
|
|
gtk_tooltips_set_tip(GTK_TOOLTIPS(button_bar_tips), help_bt,
|
|
"Show help for this dialog.", NULL);
|
|
gtk_box_pack_start(GTK_BOX(bbox), help_bt, FALSE, FALSE, 0);
|
|
|
|
/* Save All button */
|
|
save_all_bt = gtk_button_new_with_mnemonic("Save _All");
|
|
SIGNAL_CONNECT(save_all_bt, "clicked", eo_save_all_clicked_cb,
|
|
object_list);
|
|
gtk_tooltips_set_tip(GTK_TOOLTIPS(button_bar_tips), save_all_bt,
|
|
"Save all listed objects with their displayed "
|
|
"filenames.", NULL);
|
|
gtk_box_pack_end(GTK_BOX(bbox), save_all_bt, FALSE, FALSE, 0);
|
|
|
|
/* Save button */
|
|
save_bt = BUTTON_NEW_FROM_STOCK(GTK_STOCK_SAVE_AS);
|
|
SIGNAL_CONNECT(save_bt, "clicked", eo_save_clicked_cb, object_list);
|
|
gtk_tooltips_set_tip(GTK_TOOLTIPS(button_bar_tips), save_bt,
|
|
"Saves the currently selected content to a file.",
|
|
NULL);
|
|
gtk_box_pack_end(GTK_BOX(bbox), save_bt, FALSE, FALSE, 0);
|
|
|
|
/* Close button */
|
|
close_bt = BUTTON_NEW_FROM_STOCK(GTK_STOCK_CLOSE);
|
|
GTK_WIDGET_SET_FLAGS(close_bt, GTK_CAN_DEFAULT);
|
|
gtk_tooltips_set_tip(GTK_TOOLTIPS(button_bar_tips), close_bt,
|
|
"Close this dialog.", NULL);
|
|
gtk_box_pack_end(GTK_BOX(bbox), close_bt, FALSE, FALSE, 0);
|
|
|
|
/* Pack the buttons into the "button box" */
|
|
gtk_box_pack_end(GTK_BOX(vbox), bbox, FALSE, FALSE, 0);
|
|
gtk_widget_show(bbox);
|
|
|
|
/* Setup cancel/delete/destroy signal handlers */
|
|
SIGNAL_CONNECT(object_list->dlg, "delete_event",
|
|
window_delete_event_cb, NULL);
|
|
SIGNAL_CONNECT(object_list->dlg, "destroy",
|
|
eo_win_destroy_cb, object_list);
|
|
window_set_cancel_button(object_list->dlg, close_bt,
|
|
window_cancel_button_cb);
|
|
|
|
/* Show the window */
|
|
gtk_widget_show_all(object_list->dlg);
|
|
window_present(object_list->dlg);
|
|
|
|
cf_retap_packets(&cfile, FALSE);
|
|
}
|
|
|
|
#endif /* GTK_MAJOR_VERSION >= 2 */
|