HTTP Export Object updates:

- 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
This commit is contained in:
Stephen Fisher 2007-03-13 20:42:04 +00:00
parent e14e7fe455
commit eeea95ccbe
5 changed files with 145 additions and 93 deletions

View File

@ -62,6 +62,7 @@ typedef enum _http_type {
#include <epan/tap.h>
static int http_tap = -1;
static int http_eo_tap = -1;
static int proto_http = -1;
static int hf_http_notification = -1;
@ -165,7 +166,7 @@ typedef enum {
} http_proto_t;
typedef void (*ReqRespDissector)(tvbuff_t*, proto_tree*, int, const guchar*,
const guchar*);
const guchar*, http_conv_t *);
/*
* Structure holding information from headers needed by main
@ -181,13 +182,16 @@ typedef struct {
} headers_t;
static int is_http_request_or_reply(const gchar *data, int linelen,
http_type_t *type, ReqRespDissector *reqresp_dissector);
http_type_t *type, ReqRespDissector
*reqresp_dissector, http_conv_t *conv_data);
static int chunked_encoding_dissector(tvbuff_t **tvb_ptr, packet_info *pinfo,
proto_tree *tree, int offset);
static void http_payload_subdissector(tvbuff_t *next_tvb, proto_tree *tree, proto_tree *sub_tree, packet_info *pinfo);
static void http_payload_subdissector(tvbuff_t *next_tvb, proto_tree *tree,
proto_tree *sub_tree, packet_info *pinfo,
http_conv_t *conv_data);
static void process_header(tvbuff_t *tvb, int offset, int next_offset,
const guchar *line, int linelen, int colon_offset, packet_info *pinfo,
proto_tree *tree, headers_t *eh_ptr);
proto_tree *tree, headers_t *eh_ptr, http_conv_t *conv_data);
static gint find_header_hf_value(tvbuff_t *tvb, int offset, guint header_len);
static gboolean check_auth_ntlmssp(proto_item *hdr_item, tvbuff_t *tvb,
packet_info *pinfo, gchar *value);
@ -506,6 +510,31 @@ dissect_http_message(tvbuff_t *tvb, int offset, packet_info *pinfo,
/*guint i;*/
/*http_info_value_t *si;*/
conversation_t *conversation;
http_conv_t *conv_data;
http_eo_t *eo_info;
conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype, pinfo->srcport, pinfo->destport, 0);
if(!conversation) { /* Conversation does not exist yet - create it */
conversation = conversation_new(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype, pinfo->srcport, pinfo->destport, 0);
}
/* Retrieve information from conversation
* or add it if it isn't there yet
*/
conv_data = conversation_get_proto_data(conversation, proto_http);
if(!conv_data) {
/* Setup the conversation structure itself */
conv_data = se_alloc(sizeof(http_conv_t));
conv_data->response_code = 0;
conv_data->request_method = NULL;
conv_data->request_uri = NULL;
conversation_add_proto_data(conversation, proto_http,
conv_data);
}
/*
* Is this a request or response?
@ -523,7 +552,7 @@ dissect_http_message(tvbuff_t *tvb, int offset, packet_info *pinfo,
line = tvb_get_ptr(tvb, offset, first_linelen);
http_type = HTTP_OTHERS; /* type not known yet */
is_request_or_reply = is_http_request_or_reply((const gchar *)line,
first_linelen, &http_type, NULL);
first_linelen, &http_type, NULL, conv_data);
if (is_request_or_reply) {
/*
* Yes, it's a request or response.
@ -540,25 +569,12 @@ dissect_http_message(tvbuff_t *tvb, int offset, packet_info *pinfo,
}
}
conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype, pinfo->srcport, pinfo->destport, 0);
if(!conversation) { /* Conversation does not exist yet - create it */
conversation = conversation_new(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype, pinfo->srcport, pinfo->destport, 0);
}
/* Retrieve information from conversation
* or add it if it isn't there yet
*/
stat_info = conversation_get_proto_data(conversation, proto_http);
if(!stat_info) {
stat_info = se_alloc(sizeof(http_info_value_t));
stat_info->response_code = 0;
stat_info->request_method = NULL;
stat_info->request_uri = NULL;
stat_info->http_host = NULL;
conversation_add_proto_data(conversation, proto_http, stat_info);
}
stat_info = ep_alloc(sizeof(http_info_value_t));
stat_info->framenum = pinfo->fd->num;
stat_info->response_code = 0;
stat_info->request_method = NULL;
stat_info->request_uri = NULL;
stat_info->http_host = NULL;
switch (pinfo->match_port) {
@ -611,7 +627,6 @@ dissect_http_message(tvbuff_t *tvb, int offset, packet_info *pinfo,
*/
http_type = HTTP_OTHERS; /* type not known yet */
headers.content_type = NULL; /* content type not known yet */
stat_info->content_type = NULL; /* Reset for each packet */
headers.content_type_parameters = NULL; /* content type parameters too */
headers.have_content_length = FALSE; /* content length not known yet */
headers.content_encoding = NULL; /* content encoding not known yet */
@ -644,7 +659,7 @@ dissect_http_message(tvbuff_t *tvb, int offset, packet_info *pinfo,
reqresp_dissector = NULL;
is_request_or_reply =
is_http_request_or_reply((const gchar *)line,
linelen, &http_type, &reqresp_dissector);
linelen, &http_type, &reqresp_dissector, conv_data);
if (is_request_or_reply)
goto is_http;
@ -797,14 +812,16 @@ dissect_http_message(tvbuff_t *tvb, int offset, packet_info *pinfo,
if (tree) req_tree = proto_item_add_subtree(hdr_item, ett_http_request);
else req_tree = NULL;
reqresp_dissector(tvb, req_tree, offset, line, lineend);
reqresp_dissector(tvb, req_tree, offset, line,
lineend, conv_data);
}
} else {
/*
* Header.
*/
process_header(tvb, offset, next_offset, line, linelen,
colon_offset, pinfo, http_tree, &headers);
colon_offset, pinfo, http_tree, &headers, conv_data);
}
offset = next_offset;
}
@ -1074,13 +1091,17 @@ dissect_http_message(tvbuff_t *tvb, int offset, packet_info *pinfo,
/* Save values for the Export Object GUI feature if we have
* an active listener to process it (which happens when
* the export object window is open). These will be freed
* when the export object window is destroyed. */
if(have_tap_listener(http_tap)) {
stat_info->content_type = g_strdup(headers.content_type);
stat_info->payload_len = next_tvb->length;
stat_info->payload_data = g_memdup(next_tvb->real_data,
next_tvb->length);
* the export object window is open). */
if(have_tap_listener(http_eo_tap)) {
eo_info = ep_alloc(sizeof(http_eo_t));
eo_info->hostname = conv_data->http_host;
eo_info->filename = conv_data->request_uri;
eo_info->content_type = headers.content_type;
eo_info->payload_len = next_tvb->length;
eo_info->payload_data = next_tvb->real_data;
tap_queue_packet(http_eo_tap, pinfo, eo_info);
}
/*
@ -1146,7 +1167,9 @@ dissect_http_message(tvbuff_t *tvb, int offset, packet_info *pinfo,
call_dissector(media_handle, next_tvb, pinfo, tree);
} else {
/* Call the subdissector (defaults to data), otherwise. */
http_payload_subdissector(next_tvb, tree, http_tree, pinfo);
http_payload_subdissector(next_tvb, tree,
http_tree, pinfo,
conv_data);
}
}
@ -1177,9 +1200,11 @@ dissect_http_message(tvbuff_t *tvb, int offset, packet_info *pinfo,
*/
static void
basic_request_dissector(tvbuff_t *tvb, proto_tree *tree, int offset,
const guchar *line, const guchar *lineend)
const guchar *line, const guchar *lineend,
http_conv_t *conv_data)
{
const guchar *next_token;
gchar *request_uri;
int tokenlen;
/* The first token is the method. */
@ -1195,9 +1220,14 @@ basic_request_dissector(tvbuff_t *tvb, proto_tree *tree, int offset,
tokenlen = get_token_len(line, lineend, &next_token);
if (tokenlen == 0)
return;
stat_info->request_uri = se_strdup((gchar*) tvb_get_ephemeral_string(tvb, offset, tokenlen));
/* Save the request URI for various later uses */
request_uri = (gchar *)tvb_get_string(tvb, offset, tokenlen);
stat_info->request_uri = ep_strdup(request_uri);
conv_data->request_uri = se_strdup(request_uri);
proto_tree_add_string(tree, hf_http_request_uri, tvb, offset, tokenlen,
stat_info->request_uri);
request_uri);
offset += next_token - line;
line = next_token;
@ -1211,7 +1241,8 @@ basic_request_dissector(tvbuff_t *tvb, proto_tree *tree, int offset,
static void
basic_response_dissector(tvbuff_t *tvb, proto_tree *tree, int offset,
const guchar *line, const guchar *lineend)
const guchar *line, const guchar *lineend,
http_conv_t *conv_data _U_)
{
const guchar *next_token;
int tokenlen;
@ -1233,7 +1264,8 @@ basic_response_dissector(tvbuff_t *tvb, proto_tree *tree, int offset,
memcpy(response_chars, line, 3);
response_chars[3] = '\0';
stat_info->response_code = strtoul(response_chars,NULL,10);
stat_info->response_code = conv_data->response_code =
strtoul(response_chars, NULL, 10);
proto_tree_add_uint(tree, hf_http_response_code, tvb, offset, 3,
stat_info->response_code);
@ -1424,7 +1456,9 @@ chunked_encoding_dissector(tvbuff_t **tvb_ptr, packet_info *pinfo,
}
static void
http_payload_subdissector(tvbuff_t *next_tvb, proto_tree *tree, proto_tree *sub_tree, packet_info *pinfo)
http_payload_subdissector(tvbuff_t *next_tvb, proto_tree *tree,
proto_tree *sub_tree, packet_info *pinfo,
http_conv_t *conv_data)
{
/* tree = the main protocol tree that the subdissector would be listed in
* sub_tree = the http protocol tree
@ -1435,14 +1469,14 @@ http_payload_subdissector(tvbuff_t *next_tvb, proto_tree *tree, proto_tree *sub_
gchar **strings; /* An array for splitting the request URI into hostname and port */
/* Response code 200 means "OK" and strncmp() == 0 means the strings match exactly */
if(stat_info->request_uri && stat_info->response_code == 200 &&
stat_info->request_method && strncmp(stat_info->request_method, "CONNECT", 7) == 0) {
if(conv_data->response_code == 200 &&
strncmp(conv_data->request_method, "CONNECT", 7) == 0) {
/* Call a subdissector to handle HTTP CONNECT's traffic */
tcpd=get_tcp_conversation_data(pinfo);
/* Grab the destination port number from the request URI to find the right subdissector */
strings = g_strsplit(stat_info->request_uri, ":", 2);
strings = g_strsplit(conv_data->request_uri, ":", 2);
if(strings[0] != NULL && strings[1] != NULL) { /* The string was successfuly split in two */
proto_tree_add_text(sub_tree, next_tvb, 0, 0, "Proxy connect hostname: %s", strings[0]);
@ -1490,7 +1524,8 @@ http_payload_subdissector(tvbuff_t *next_tvb, proto_tree *tree, proto_tree *sub_
*/
static int
is_http_request_or_reply(const gchar *data, int linelen, http_type_t *type,
ReqRespDissector *reqresp_dissector)
ReqRespDissector *reqresp_dissector,
http_conv_t *conv_data)
{
int isHttpRequestOrReply = FALSE;
int prefix_len = 0;
@ -1659,9 +1694,13 @@ is_http_request_or_reply(const gchar *data, int linelen, http_type_t *type,
if (isHttpRequestOrReply && reqresp_dissector) {
*reqresp_dissector = basic_request_dissector;
if (!stat_info->request_method)
stat_info->request_method = se_strndup(data, index+1);
}
stat_info->request_method = ep_strndup(data, index+1);
conv_data->request_method = se_strndup(data, index+1);
}
}
return isHttpRequestOrReply;
@ -1714,7 +1753,8 @@ static const header_info headers[] = {
static void
process_header(tvbuff_t *tvb, int offset, int next_offset,
const guchar *line, int linelen, int colon_offset,
packet_info *pinfo, proto_tree *tree, headers_t *eh_ptr)
packet_info *pinfo, proto_tree *tree, headers_t *eh_ptr,
http_conv_t *conv_data)
{
int len;
int line_end_offset;
@ -1872,7 +1912,8 @@ process_header(tvbuff_t *tvb, int offset, int next_offset,
break;
case HDR_HOST:
stat_info->http_host = se_strndup(value, value_len);
stat_info->http_host = ep_strndup(value, value_len);
conv_data->http_host = se_strndup(value, value_len);
break;
}
@ -2217,7 +2258,8 @@ proto_register_http(void)
/*
* Register for tapping
*/
http_tap = register_tap("http");
http_tap = register_tap("http"); /* HTTP statistics tap */
http_eo_tap = register_tap("http_eo"); /* HTTP Export Object tap */
}
/*

View File

@ -28,15 +28,31 @@
void http_dissector_add(guint32 port, dissector_handle_t handle);
typedef struct _http_info_value_t
{
/* Used for HTTP statistics */
typedef struct _http_info_value_t {
guint32 framenum;
gchar *request_method;
guint response_code;
gchar *http_host;
gchar *request_uri;
gchar *content_type;
guint32 payload_len;
guint8 *payload_data;
} http_info_value_t;
#endif
/* Used for HTTP Export Object feature */
typedef struct _http_eo_t {
guint32 pkt_num;
gchar *hostname;
gchar *filename;
gchar *content_type;
guint32 payload_len;
const guint8 *payload_data;
} http_eo_t;
/* Conversation data - used for the http_payload_subdissector() function. */
typedef struct _http_conv_t {
guint response_code;
gchar *http_host;
gchar *request_method;
gchar *request_uri;
} http_conv_t;
#endif /* __PACKET_HTTP_H__ */

View File

@ -111,10 +111,13 @@ eo_win_destroy_cb(GtkWindow *win _U_, gpointer data)
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);
@ -230,40 +233,27 @@ eo_draw(void *tapdata)
GSList *slist = object_list->entries;
GtkTreeIter new_iter;
gchar *column_text[EO_NUM_COLUMNS];
while(slist) {
eo_entry = slist->data;
column_text[0] = g_strdup_printf("%u", eo_entry->pkt_num);
column_text[1] = g_strdup_printf("%s", eo_entry->hostname);
column_text[2] = g_strdup_printf("%s", eo_entry->content_type);
column_text[3] = g_strdup_printf("%u", eo_entry->payload_len);
column_text[4] = g_strdup_printf("%s", eo_entry->filename);
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, column_text[0],
EO_HOSTNAME_COLUMN, column_text[1],
EO_CONTENT_TYPE_COLUMN, column_text[2],
EO_BYTES_COLUMN, column_text[3],
EO_FILENAME_COLUMN, column_text[4],
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);
g_free(column_text[0]);
g_free(column_text[1]);
g_free(column_text[2]);
g_free(column_text[3]);
g_free(column_text[4]);
slist = slist->next;
}
}
void
export_object_window(gchar *tapname, tap_packet_cb tap_packet)
export_object_window(gchar *tapname, gchar *name, tap_packet_cb tap_packet)
{
GtkWidget *sw;
GtkCellRenderer *renderer;
@ -291,10 +281,10 @@ export_object_window(gchar *tapname, tap_packet_cb tap_packet)
return;
}
/* Set up our GUI window */
/* Setup our GUI window */
button_bar_tips = gtk_tooltips_new();
window_title = g_strdup_printf("Wireshark: %s object list", tapname);
window_title = g_strdup_printf("Wireshark: %s object list", name);
object_list->dlg = dlg_window_new(window_title);
g_free(window_title);
@ -313,8 +303,8 @@ export_object_window(gchar *tapname, tap_packet_cb tap_packet)
gtk_container_add(GTK_CONTAINER(vbox), sw);
object_list->store = gtk_tree_store_new(EO_NUM_COLUMNS,
G_TYPE_STRING, G_TYPE_STRING,
G_TYPE_STRING, G_TYPE_STRING,
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));

View File

@ -46,7 +46,8 @@ typedef struct _export_object_entry_t {
guint8 *payload_data;
} export_object_entry_t;
void export_object_window(gchar *tapname, tap_packet_cb tap_packet);
void export_object_window(gchar *tapname, gchar *name, tap_packet_cb
tap_packet);
/* Protocol specific */
void eo_http_cb(GtkWidget *widget _U_, gpointer data _U_);

View File

@ -47,22 +47,25 @@ eo_http_packet(void *tapdata, packet_info *pinfo, epan_dissect_t *edt _U_,
const void *data)
{
export_object_list_t *object_list = tapdata;
const http_info_value_t *stat_info = data;
const http_eo_t *eo_info = data;
export_object_entry_t *entry;
if(stat_info->content_type && /* We have data waiting for us */
g_ascii_strncasecmp(stat_info->content_type, "<NULL>", 6) != 0) {
entry = g_malloc(sizeof(export_object_entry_t));
if(eo_info) { /* We have data waiting for us */
/* These values will be freed when the Export Object window
* is closed. */
entry = g_malloc(sizeof(export_object_entry_t));
entry->pkt_num = pinfo->fd->num;
entry->hostname = stat_info->http_host;
entry->content_type = stat_info->content_type;
entry->filename = g_path_get_basename(stat_info->request_uri);
entry->payload_len = stat_info->payload_len;
entry->payload_data = stat_info->payload_data;
entry->hostname = g_strdup(eo_info->hostname);
entry->content_type = g_strdup(eo_info->content_type);
entry->filename = g_strdup(g_path_get_basename(eo_info->filename));
entry->payload_len = eo_info->payload_len;
entry->payload_data = g_memdup(eo_info->payload_data,
eo_info->payload_len);
object_list->entries =
g_slist_append(object_list->entries, entry);
return 1; /* State changed - window should be redrawn */
} else {
return 0; /* State unchanged - no window updates needed */
@ -72,7 +75,7 @@ eo_http_packet(void *tapdata, packet_info *pinfo, epan_dissect_t *edt _U_,
void
eo_http_cb(GtkWidget *widget _U_, gpointer data _U_)
{
export_object_window("http", eo_http_packet);
export_object_window("http_eo", "HTTP", eo_http_packet);
}
#endif /* GTK_MAJOR_VERSION >= 2 */