summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristopher Kilgour <techie@whiterocker.com>2014-02-23 17:30:57 -0800
committerAnders Broman <a.broman58@gmail.com>2014-03-20 09:54:01 +0000
commit7b13a3b0f6a5617e0e352f87cc5a20afea226aa8 (patch)
tree774432cd1876744b5038ea291f10b012bd7f8288
parentf65513291333b5912a16b45bfa09eed05eee3a6d (diff)
downloadwireshark-7b13a3b0f6a5617e0e352f87cc5a20afea226aa8.tar.gz
Allow pcapng interface options to be available to dissectors.
Interface options[1], and more generally pcapng options[2], are useful information that can provide improved dissector output. Prior to this change, only certain pcapng interface options were interpreted and made available to dissectors, e.g. the interface name or description. This change augments the situation by providing epan_get_interface_option( ), which returns an array of byte arrays if the option code exists (otherwise NULL). Each element of the array is a byte buffer containing the raw data of the option. An array-of-buffers is used because pcapng allows for multiple instances of the same option to be present in the file. All interface options found in a pcapng file are thus made available to the dissector. The implementation also provides infrastructure to collect options from other pcapng blocks such as the section header. Currently these options are discarded, but could be retained in the future to support more features. [1] http://www.winpcap.org/ntar/draft/PCAP-DumpFileFormat.html#sectionidb [2] http://www.winpcap.org/ntar/draft/PCAP-DumpFileFormat.html#sectionopt Change-Id: I944b6f0f03dde9b8e7d1348b76acde6f9d312f37 Reviewed-on: https://code.wireshark.org/review/331 Reviewed-by: Anders Broman <a.broman58@gmail.com>
-rw-r--r--cfile.c23
-rw-r--r--cfile.h2
-rw-r--r--epan/epan-int.h2
-rw-r--r--epan/epan.c9
-rw-r--r--epan/epan.h5
-rw-r--r--file.c1
-rw-r--r--wiretap/pcapng.c106
-rw-r--r--wiretap/wtap.c3
-rw-r--r--wiretap/wtap.h1
9 files changed, 148 insertions, 4 deletions
diff --git a/cfile.c b/cfile.c
index a689b2e11c..830e871593 100644
--- a/cfile.c
+++ b/cfile.c
@@ -29,8 +29,8 @@
#include "cfile.h"
-const char *
-cap_file_get_interface_name(void *data, guint32 interface_id)
+static const wtapng_if_descr_t *
+cap_file_get_interface_desc(void *data, guint32 interface_id)
{
capture_file *cf = (capture_file *) data;
wtapng_iface_descriptions_t *idb_info;
@@ -42,6 +42,13 @@ cap_file_get_interface_name(void *data, guint32 interface_id)
wtapng_if_descr = &g_array_index(idb_info->interface_data, wtapng_if_descr_t, interface_id);
g_free(idb_info);
+ return wtapng_if_descr;
+}
+
+const char *
+cap_file_get_interface_name(void *data, guint32 interface_id)
+{
+ const wtapng_if_descr_t *wtapng_if_descr = cap_file_get_interface_desc(data, interface_id);
if (wtapng_if_descr) {
if (wtapng_if_descr->if_name)
@@ -52,6 +59,18 @@ cap_file_get_interface_name(void *data, guint32 interface_id)
return "unknown";
}
+const GArray *
+cap_file_get_interface_option(void *data, guint32 interface_id, guint16 option_code)
+{
+ const wtapng_if_descr_t *wtapng_if_descr = cap_file_get_interface_desc(data, interface_id);
+
+ if (wtapng_if_descr && wtapng_if_descr->if_options) {
+ gint code = (gint) option_code;
+ return (const GArray *) g_hash_table_lookup(wtapng_if_descr->if_options, &code);
+ }
+ return NULL;
+}
+
void
cap_file_init(capture_file *cf)
{
diff --git a/cfile.h b/cfile.h
index f34c34ee14..f164303f18 100644
--- a/cfile.h
+++ b/cfile.h
@@ -133,6 +133,8 @@ extern void cap_file_init(capture_file *cf);
extern const char *cap_file_get_interface_name(void *data, guint32 interface_id);
+extern const GArray *cap_file_get_interface_option(void *data, guint32 interface_id, guint16 option_code);
+
#ifdef __cplusplus
}
#endif /* __cplusplus */
diff --git a/epan/epan-int.h b/epan/epan-int.h
index 35e91975be..5089025c30 100644
--- a/epan/epan-int.h
+++ b/epan/epan-int.h
@@ -31,6 +31,8 @@ struct epan_session {
const nstime_t *(*get_frame_ts)(void *data, guint32 frame_num);
const char *(*get_interface_name)(void *data, guint32 interface_id);
const char *(*get_user_comment)(void *data, const frame_data *fd);
+ const GArray *(*get_interface_option)(void *data, guint32 interface_id,
+ guint16 option_code);
};
#endif
diff --git a/epan/epan.c b/epan/epan.c
index e83864121d..4426981b2f 100644
--- a/epan/epan.c
+++ b/epan/epan.c
@@ -178,6 +178,15 @@ epan_get_interface_name(const epan_t *session, guint32 interface_id)
return NULL;
}
+const GArray *
+epan_get_interface_option(const epan_t *session, guint32 interface_id, guint16 option_code)
+{
+ if (session->get_interface_option)
+ return session->get_interface_option(session->data, interface_id, option_code);
+
+ return NULL;
+}
+
const nstime_t *
epan_get_frame_ts(const epan_t *session, guint32 frame_num)
{
diff --git a/epan/epan.h b/epan/epan.h
index faf8e3a448..da00026bb7 100644
--- a/epan/epan.h
+++ b/epan/epan.h
@@ -18,7 +18,6 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-
#ifndef __EPAN_H__
#define __EPAN_H__
@@ -124,7 +123,7 @@ void epan_circuit_cleanup(void);
/** A client will create one epan_t for an entire dissection session.
* A single epan_t will be used to analyze the entire sequence of packets,
* sequentially, in a single session. A session corresponds to a single
- * packet trace file. The reaons epan_t exists is that some packets in
+ * packet trace file. The reason epan_t exists is that some packets in
* some protocols cannot be decoded without knowledge of previous packets.
* This inter-packet "state" is stored in the epan_t.
*/
@@ -136,6 +135,8 @@ const char *epan_get_user_comment(const epan_t *session, const frame_data *fd);
const char *epan_get_interface_name(const epan_t *session, guint32 interface_id);
+const GArray *epan_get_interface_option(const epan_t *session, guint32 interface_id, guint16 option_code);
+
const nstime_t *epan_get_frame_ts(const epan_t *session, guint32 frame_num);
WS_DLL_PUBLIC void epan_free(epan_t *session);
diff --git a/file.c b/file.c
index d57e0a9b8b..2eaecf5cc0 100644
--- a/file.c
+++ b/file.c
@@ -329,6 +329,7 @@ ws_epan_new(capture_file *cf)
epan->get_frame_ts = ws_get_frame_ts;
epan->get_interface_name = cap_file_get_interface_name;
epan->get_user_comment = ws_get_user_comment;
+ epan->get_interface_option = cap_file_get_interface_option;
return epan;
}
diff --git a/wiretap/pcapng.c b/wiretap/pcapng.c
index c350532b3f..875571866d 100644
--- a/wiretap/pcapng.c
+++ b/wiretap/pcapng.c
@@ -344,6 +344,9 @@ typedef struct wtapng_block_s {
wtapng_if_stats_t if_stats;
} data;
+ /* keys are (pointers to) gint, vals are (pointers to) arrays of GByteArray */
+ GHashTable * pcapng_options;
+
/*
* XXX - currently don't know how to handle these!
*
@@ -357,6 +360,69 @@ typedef struct wtapng_block_s {
int *file_encap;
} wtapng_block_t;
+static void
+pcapng_destroy_option_key(gpointer data)
+{
+ g_free(data);
+}
+
+static void
+pcapng_destroy_option_value(gpointer data)
+{
+ GArray * pval = (GArray *) data;
+ if (pval) {
+ guint i;
+ for(i=0; i<pval->len; i++) {
+ GByteArray * element = g_array_index(pval, GByteArray *, i);
+ g_byte_array_unref(element);
+ }
+ g_array_unref(pval);
+ }
+}
+
+static void
+pcapng_init_block_options(wtapng_block_t *wblock)
+{
+ wblock->pcapng_options = g_hash_table_new_full(g_int_hash,
+ g_int_equal,
+ pcapng_destroy_option_key,
+ pcapng_destroy_option_value);
+}
+
+static void
+pcapng_unref_block_options(wtapng_block_t *wblock)
+{
+ if (wblock->pcapng_options) {
+ g_hash_table_destroy(wblock->pcapng_options);
+ wblock->pcapng_options = NULL;
+ }
+}
+
+static void
+pcapng_collect_block_option(wtapng_block_t *wblock, guint16 code,
+ const guint8 *data, gsize len)
+{
+ if (wblock->pcapng_options) {
+ gint tempkey = (gint) code;
+ GArray * pval = (GArray *) g_hash_table_lookup(wblock->pcapng_options, &tempkey);
+ if(!pval) {
+ /* this key does not yet exist, so create a
+ new key and new array for its first value,
+ and insert it into the hash table */
+ gpointer pkey = g_try_malloc(sizeof(gint));
+ if (pkey) {
+ pval = g_array_new(FALSE, TRUE, sizeof(GByteArray *));
+ g_hash_table_insert(wblock->pcapng_options, pkey, pval);
+ }
+ }
+ if (pval) {
+ GByteArray * optionbuf = g_byte_array_new_take(g_strndup(data, len), len);
+ g_array_append_val(pval, optionbuf);
+ }
+ }
+}
+
+
/* Interface data in private struct */
typedef struct interface_data_s {
int wtap_encap;
@@ -607,6 +673,11 @@ pcapng_read_section_header_block(FILE_T fh, gboolean first_block,
block_read += bytes_read;
to_read -= bytes_read;
+ if (oh.option_code) {
+ /* collect the raw option information */
+ pcapng_collect_block_option(wblock, oh.option_code, option_content, oh.option_length);
+ }
+
/* handle option content */
switch (oh.option_code) {
case(OPT_EOFOPT):
@@ -779,6 +850,11 @@ pcapng_read_if_descr_block(FILE_T fh, pcapng_block_header_t *bh, pcapng_t *pn,
block_read += bytes_read;
to_read -= bytes_read;
+ if (oh.option_code) {
+ /* collect the raw option information */
+ pcapng_collect_block_option(wblock, oh.option_code, option_content, oh.option_length);
+ }
+
/* handle option content */
switch (oh.option_code) {
case(0): /* opt_endofopt */
@@ -1206,6 +1282,11 @@ pcapng_read_packet_block(FILE_T fh, pcapng_block_header_t *bh, pcapng_t *pn, wta
block_read += bytes_read;
to_read -= bytes_read;
+ if (oh.option_code) {
+ /* collect the raw option information */
+ pcapng_collect_block_option(wblock, oh.option_code, option_content, oh.option_length);
+ }
+
/* handle option content */
switch (oh.option_code) {
case(OPT_EOFOPT):
@@ -1827,6 +1908,11 @@ pcapng_read_interface_statistics_block(FILE_T fh, pcapng_block_header_t *bh, pca
block_read += bytes_read;
to_read -= bytes_read;
+ if (oh.option_code) {
+ /* collect the raw option information */
+ pcapng_collect_block_option(wblock, oh.option_code, option_content, oh.option_length);
+ }
+
/* handle option content */
switch (oh.option_code) {
case(0): /* opt_endofopt */
@@ -2131,6 +2217,9 @@ pcapng_process_idb(wtap *wth, pcapng_t *pcapng, wtapng_block_t *wblock)
/* Interface statistics */
int_data.num_stat_entries = 0;
int_data.interface_statistics = NULL;
+ /* move the options over */
+ int_data.if_options = wblock->pcapng_options;
+ wblock->pcapng_options = NULL;
g_array_append_val(wth->interface_data, int_data);
wth->number_of_interfaces++;
@@ -2154,6 +2243,8 @@ pcapng_open(wtap *wth, int *err, gchar **err_info)
pcapng_block_header_t bh;
gint64 saved_offset;
+ pcapng_init_block_options(&wblock);
+
pn.shb_read = FALSE;
/* we don't know the byte swapping of the file yet */
pn.byte_swapped = FALSE;
@@ -2174,6 +2265,7 @@ pcapng_open(wtap *wth, int *err, gchar **err_info)
bytes_read = pcapng_read_block(wth->fh, TRUE, &pn, &wblock, err, err_info);
if (bytes_read <= 0) {
pcapng_debug0("pcapng_open: couldn't read first SHB");
+ pcapng_unref_block_options(&wblock);
*err = file_error(wth->fh, err_info);
if (*err != 0 && *err != WTAP_ERR_SHORT_READ)
return -1;
@@ -2188,6 +2280,7 @@ pcapng_open(wtap *wth, int *err, gchar **err_info)
* binary data?
*/
pcapng_debug1("pcapng_open: first block type %u not SHB", wblock.type);
+ pcapng_unref_block_options(&wblock);
return 0;
}
pn.shb_read = TRUE;
@@ -2233,6 +2326,7 @@ pcapng_open(wtap *wth, int *err, gchar **err_info)
if (bytes_read != sizeof bh) {
*err = file_error(wth->fh, err_info);
pcapng_debug3("pcapng_open: Check for more IDB:s, file_read() returned %d instead of %u, err = %d.", bytes_read, (unsigned int)sizeof bh, *err);
+ pcapng_unref_block_options(&wblock);
if (*err == 0)
*err = WTAP_ERR_SHORT_READ;
return -1;
@@ -2258,6 +2352,7 @@ pcapng_open(wtap *wth, int *err, gchar **err_info)
if (bytes_read <= 0) {
pcapng_debug0("pcapng_open: couldn't read IDB");
*err = file_error(wth->fh, err_info);
+ pcapng_unref_block_options(&wblock);
if (*err == 0)
*err = WTAP_ERR_SHORT_READ;
return -1;
@@ -2265,6 +2360,7 @@ pcapng_open(wtap *wth, int *err, gchar **err_info)
pcapng_process_idb(wth, pcapng, &wblock);
pcapng_debug2("pcapng_open: Read IDB number_of_interfaces %u, wtap_encap %i", wth->number_of_interfaces, *wblock.file_encap);
}
+ pcapng_unref_block_options(&wblock);
return 1;
}
@@ -2279,6 +2375,8 @@ pcapng_read(wtap *wth, int *err, gchar **err_info, gint64 *data_offset)
wtapng_if_descr_t *wtapng_if_descr;
wtapng_if_stats_t if_stats;
+ pcapng_init_block_options(&wblock);
+
*data_offset = file_tell(wth->fh);
pcapng_debug1("pcapng_read: data_offset is initially %" G_GINT64_MODIFIER "d", *data_offset);
@@ -2295,6 +2393,7 @@ pcapng_read(wtap *wth, int *err, gchar **err_info, gint64 *data_offset)
if (bytes_read <= 0) {
pcapng_debug1("pcapng_read: data_offset is finally %" G_GINT64_MODIFIER "d", *data_offset);
pcapng_debug0("pcapng_read: couldn't read packet block");
+ pcapng_unref_block_options(&wblock);
return FALSE;
}
@@ -2305,6 +2404,7 @@ pcapng_read(wtap *wth, int *err, gchar **err_info, gint64 *data_offset)
wth->phdr.pkt_encap = WTAP_ENCAP_UNKNOWN;
*err = WTAP_ERR_UNSUPPORTED;
*err_info = g_strdup_printf("pcapng: multi-section files not currently supported");
+ pcapng_unref_block_options(&wblock);
return FALSE;
case(BLOCK_TYPE_PB):
@@ -2373,6 +2473,7 @@ got_packet:
/*pcapng_debug2("Read length: %u Packet length: %u", bytes_read, wth->phdr.caplen);*/
pcapng_debug1("pcapng_read: data_offset is finally %" G_GINT64_MODIFIER "d", *data_offset + bytes_read);
+ pcapng_unref_block_options(&wblock);
return TRUE;
}
@@ -2389,10 +2490,12 @@ pcapng_seek_read(wtap *wth, gint64 seek_off,
int bytes_read;
wtapng_block_t wblock;
+ pcapng_init_block_options(&wblock);
/* seek to the right file position */
bytes_read64 = file_seek(wth->random_fh, seek_off, SEEK_SET, err);
if (bytes_read64 <= 0) {
+ pcapng_unref_block_options(&wblock);
return FALSE; /* Seek error */
}
pcapng_debug1("pcapng_seek_read: reading at offset %" G_GINT64_MODIFIER "u", seek_off);
@@ -2406,6 +2509,7 @@ pcapng_seek_read(wtap *wth, gint64 seek_off,
if (bytes_read <= 0) {
pcapng_debug3("pcapng_seek_read: couldn't read packet block (err=%d, errno=%d, bytes_read=%d).",
*err, errno, bytes_read);
+ pcapng_unref_block_options(&wblock);
return FALSE;
}
@@ -2414,9 +2518,11 @@ pcapng_seek_read(wtap *wth, gint64 seek_off,
if (wblock.type != BLOCK_TYPE_PB && wblock.type != BLOCK_TYPE_EPB &&
wblock.type != BLOCK_TYPE_SPB) {
pcapng_debug1("pcapng_seek_read: block type %u not PB/EPB/SPB", wblock.type);
+ pcapng_unref_block_options(&wblock);
return FALSE;
}
+ pcapng_unref_block_options(&wblock);
return TRUE;
}
diff --git a/wiretap/wtap.c b/wiretap/wtap.c
index 8774f35e1f..d8bbdbb65f 100644
--- a/wiretap/wtap.c
+++ b/wiretap/wtap.c
@@ -925,6 +925,9 @@ wtap_close(wtap *wth)
if(wtapng_if_descr->num_stat_entries != 0){
g_array_free(wtapng_if_descr->interface_statistics, TRUE);
}
+ if(wtapng_if_descr->if_options){
+ g_hash_table_destroy(wtapng_if_descr->if_options);
+ }
}
if(wth->number_of_interfaces != 0){
g_array_free(wth->interface_data, TRUE);
diff --git a/wiretap/wtap.h b/wiretap/wtap.h
index db18a2f3af..bd6e6e8b42 100644
--- a/wiretap/wtap.h
+++ b/wiretap/wtap.h
@@ -1118,6 +1118,7 @@ typedef struct wtapng_if_descr_s {
guint8 num_stat_entries;
GArray *interface_statistics; /**< An array holding the interface statistics from
* pcapng ISB:s or equivalent(?)*/
+ GHashTable *if_options;
} wtapng_if_descr_t;