summaryrefslogtreecommitdiff
path: root/wiretap
diff options
context:
space:
mode:
authorGuy Harris <guy@alum.mit.edu>2014-11-30 16:30:19 -0800
committerGuy Harris <guy@alum.mit.edu>2014-12-01 00:31:03 +0000
commit846bb5394812c39359dfdbbf7e8755a7e3cf5326 (patch)
tree70dcf5a08a04abe66c1ef766ce15c634e87a6cf2 /wiretap
parent35b1bc5ec61260bc1890a2c991cdb7218946ae1f (diff)
downloadwireshark-846bb5394812c39359dfdbbf7e8755a7e3cf5326.tar.gz
Add a Buffer to wtap_pkthdr to hold file-type-specific packet metadata.
For example, this can be used for pcap-ng options not mapped to file-type-independent metadata values. Change-Id: I398b324c62c1cc1cc61eb5e9631de00481b4aadc Reviewed-on: https://code.wireshark.org/review/5549 Reviewed-by: Guy Harris <guy@alum.mit.edu>
Diffstat (limited to 'wiretap')
-rw-r--r--wiretap/pcapng.c206
-rw-r--r--wiretap/pcapng_module.h13
-rw-r--r--wiretap/wtap.c13
-rw-r--r--wiretap/wtap.h37
4 files changed, 211 insertions, 58 deletions
diff --git a/wiretap/pcapng.c b/wiretap/pcapng.c
index c8d44b3592..3571ca2f74 100644
--- a/wiretap/pcapng.c
+++ b/wiretap/pcapng.c
@@ -418,6 +418,98 @@ register_pcapng_block_type_handler(guint block_type, block_reader read,
(void)g_hash_table_insert(block_handlers, GUINT_TO_POINTER(block_type),
handler);
}
+
+/*
+ * Tables for plugins to handle particular options for particular block
+ * types.
+ *
+ * An option has a handler routine, which is passed an indication of
+ * whether this section of the file is byte-swapped, the length of the
+ * option, the data of the option, a pointer to an error code, and a
+ * pointer to a pointer variable for an error string.
+ *
+ * It checks whether the length and option are valid, and, if they aren't,
+ * returns FALSE, setting the error code to the appropriate error (normally
+ * WTAP_ERR_BAD_FILE) and the error string to an appropriate string
+ * indicating the problem.
+ *
+ * Otherwise, if this section of the file is byte-swapped, it byte-swaps
+ * multi-byte numerical values, so that it's in the host byte order.
+ */
+
+/*
+ * Block types indices in the table of tables of option handlers.
+ *
+ * Block types are not guaranteed to be sequential, so we map the
+ * block types we support to a sequential set. Furthermore, all
+ * packet block types have the same set of options.
+ */
+#define BT_INDEX_SHB 0
+#define BT_INDEX_IDB 1
+#define BT_INDEX_PBS 2 /* all packet blocks */
+#define BT_INDEX_NRB 3
+#define BT_INDEX_ISB 4
+
+#define NUM_BT_INDICES 5
+
+static GHashTable *option_handlers[NUM_BT_INDICES];
+
+void
+register_pcapng_option_handler(guint block_type, guint option_code,
+ option_handler handler)
+{
+ guint bt_index;
+
+ switch (block_type) {
+
+ case BLOCK_TYPE_SHB:
+ bt_index = BT_INDEX_SHB;
+ break;
+
+ case BLOCK_TYPE_IDB:
+ bt_index = BT_INDEX_IDB;
+ break;
+
+ case BLOCK_TYPE_PB:
+ case BLOCK_TYPE_EPB:
+ case BLOCK_TYPE_SPB:
+ bt_index = BT_INDEX_PBS;
+ break;
+
+ case BLOCK_TYPE_NRB:
+ bt_index = BT_INDEX_NRB;
+ break;
+
+ case BLOCK_TYPE_ISB:
+ bt_index = BT_INDEX_ISB;
+ break;
+
+ default:
+ /*
+ * This is a block type we don't process; either we ignore it,
+ * in which case the options don't get processed, or there's
+ * a plugin routine to handle it, in which case that routine
+ * will do the option processing itself.
+ *
+ * XXX - report an error?
+ */
+ return;
+ }
+
+ if (option_handlers[bt_index] == NULL) {
+ /*
+ * Create the table of option handlers for this block type.
+ *
+ * XXX - there's no "g_uint_hash()" or "g_uint_equal()",
+ * so we use "g_direct_hash()" and "g_direct_equal()".
+ */
+ option_handlers[bt_index] = g_hash_table_new_full(g_direct_hash,
+ g_direct_equal,
+ NULL, g_free);
+ }
+ (void)g_hash_table_insert(option_handlers[bt_index],
+ GUINT_TO_POINTER(option_code), handler);
+}
#endif /* HAVE_PLUGINS */
static int
@@ -1003,10 +1095,14 @@ pcapng_read_packet_block(FILE_T fh, pcapng_block_header_t *bh, pcapng_t *pn, wta
guint32 padding;
interface_info_t iface_info;
guint64 ts;
- pcapng_option_header_t oh;
+ guint8 *opt_ptr;
+ pcapng_option_header_t *oh;
+ guint8 *option_content;
int pseudo_header_len;
- char *option_content = NULL; /* Allocate as large as the options block */
int fcslen;
+#ifdef HAVE_PLUGINS
+ option_handler handler;
+#endif
/* Don't try to allocate memory for a huge number of options, as
that might fail and, even if it succeeds, it might not leave
@@ -1232,24 +1328,24 @@ pcapng_read_packet_block(FILE_T fh, pcapng_block_header_t *bh, pcapng_t *pn, wta
/* Allocate enough memory to hold all options */
opt_cont_buf_len = to_read;
- option_content = (char *)g_try_malloc(opt_cont_buf_len);
- if (opt_cont_buf_len != 0 && option_content == NULL) {
- *err = ENOMEM; /* we assume we're out of memory */
- return FALSE;
- }
+ ws_buffer_assure_space(&wblock->packet_header->ft_specific_data, opt_cont_buf_len);
+ opt_ptr = ws_buffer_start_ptr(&wblock->packet_header->ft_specific_data);
while (to_read != 0) {
/* read option */
- bytes_read = pcapng_read_option(fh, pn, &oh, option_content, opt_cont_buf_len, to_read, err, err_info);
+ oh = (pcapng_option_header_t *)(void *)opt_ptr;
+ option_content = opt_ptr + sizeof (pcapng_option_header_t);
+ bytes_read = pcapng_read_option(fh, pn, oh, option_content, opt_cont_buf_len, to_read, err, err_info);
if (bytes_read <= 0) {
pcapng_debug0("pcapng_read_packet_block: failed to read option");
+ /* XXX - free anything? */
return FALSE;
}
block_read += bytes_read;
to_read -= bytes_read;
/* handle option content */
- switch (oh.option_code) {
+ switch (oh->option_code) {
case(OPT_EOFOPT):
if (to_read != 0) {
pcapng_debug1("pcapng_read_packet_block: %u bytes after opt_endofopt", to_read);
@@ -1258,59 +1354,81 @@ pcapng_read_packet_block(FILE_T fh, pcapng_block_header_t *bh, pcapng_t *pn, wta
to_read = 0;
break;
case(OPT_COMMENT):
- if (oh.option_length > 0 && oh.option_length < opt_cont_buf_len) {
+ if (oh->option_length > 0 && oh->option_length < opt_cont_buf_len) {
wblock->packet_header->presence_flags |= WTAP_HAS_COMMENTS;
- wblock->packet_header->opt_comment = g_strndup(option_content, oh.option_length);
- pcapng_debug2("pcapng_read_packet_block: length %u opt_comment '%s'", oh.option_length, wblock->packet_header->opt_comment);
+ wblock->packet_header->opt_comment = g_strndup(option_content, oh->option_length);
+ pcapng_debug2("pcapng_read_packet_block: length %u opt_comment '%s'", oh->option_length, wblock->packet_header->opt_comment);
} else {
- pcapng_debug1("pcapng_read_packet_block: opt_comment length %u seems strange", oh.option_length);
+ pcapng_debug1("pcapng_read_packet_block: opt_comment length %u seems strange", oh->option_length);
}
break;
case(OPT_EPB_FLAGS):
- if (oh.option_length == 4) {
- /* Don't cast a char[] into a guint32--the
- * char[] may not be aligned correctly.
- */
- wblock->packet_header->presence_flags |= WTAP_HAS_PACK_FLAGS;
- memcpy(&wblock->packet_header->pack_flags, option_content, sizeof(guint32));
- if (pn->byte_swapped)
- wblock->packet_header->pack_flags = GUINT32_SWAP_LE_BE(wblock->packet_header->pack_flags);
- if (wblock->packet_header->pack_flags & 0x000001E0) {
- /* The FCS length is present */
- fcslen = (wblock->packet_header->pack_flags & 0x000001E0) >> 5;
- }
- pcapng_debug1("pcapng_read_packet_block: pack_flags %u (ignored)", wblock->packet_header->pack_flags);
- } else {
- pcapng_debug1("pcapng_read_packet_block: pack_flags length %u not 4 as expected", oh.option_length);
+ if (oh->option_length != 4) {
+ *err = WTAP_ERR_BAD_FILE;
+ *err_info = g_strdup_printf("pcapng: packet block flags option length %u is not 4",
+ oh->option_length);
+ /* XXX - free anything? */
+ return FALSE;
+ }
+ /* Don't cast a char[] into a guint32--the
+ * char[] may not be aligned correctly.
+ */
+ wblock->packet_header->presence_flags |= WTAP_HAS_PACK_FLAGS;
+ memcpy(&wblock->packet_header->pack_flags, option_content, sizeof(guint32));
+ if (pn->byte_swapped) {
+ wblock->packet_header->pack_flags = GUINT32_SWAP_LE_BE(wblock->packet_header->pack_flags);
+ memcpy(option_content, &wblock->packet_header->pack_flags, sizeof(guint32));
+ }
+ if (wblock->packet_header->pack_flags & 0x000001E0) {
+ /* The FCS length is present */
+ fcslen = (wblock->packet_header->pack_flags & 0x000001E0) >> 5;
}
+ pcapng_debug1("pcapng_read_packet_block: pack_flags %u (ignored)", wblock->packet_header->pack_flags);
break;
case(OPT_EPB_HASH):
pcapng_debug2("pcapng_read_packet_block: epb_hash %u currently not handled - ignoring %u bytes",
- oh.option_code, oh.option_length);
+ oh->option_code, oh->option_length);
break;
case(OPT_EPB_DROPCOUNT):
- if (oh.option_length == 8) {
- /* Don't cast a char[] into a guint32--the
- * char[] may not be aligned correctly.
- */
- wblock->packet_header->presence_flags |= WTAP_HAS_DROP_COUNT;
- memcpy(&wblock->packet_header->drop_count, option_content, sizeof(guint64));
- if (pn->byte_swapped)
- wblock->packet_header->drop_count = GUINT64_SWAP_LE_BE(wblock->packet_header->drop_count);
-
- pcapng_debug1("pcapng_read_packet_block: drop_count %" G_GINT64_MODIFIER "u", wblock->packet_header->drop_count);
- } else {
- pcapng_debug1("pcapng_read_packet_block: drop_count length %u not 8 as expected", oh.option_length);
+ if (oh->option_length != 8) {
+ *err = WTAP_ERR_BAD_FILE;
+ *err_info = g_strdup_printf("pcapng: packet block drop count option length %u is not 8",
+ oh->option_length);
+ /* XXX - free anything? */
+ return FALSE;
}
+ /* Don't cast a char[] into a guint64--the
+ * char[] may not be aligned correctly.
+ */
+ wblock->packet_header->presence_flags |= WTAP_HAS_DROP_COUNT;
+ memcpy(&wblock->packet_header->drop_count, option_content, sizeof(guint64));
+ if (pn->byte_swapped) {
+ wblock->packet_header->drop_count = GUINT64_SWAP_LE_BE(wblock->packet_header->drop_count);
+ memcpy(option_content, &wblock->packet_header->drop_count, sizeof(guint64));
+ }
+
+ pcapng_debug1("pcapng_read_packet_block: drop_count %" G_GINT64_MODIFIER "u", wblock->packet_header->drop_count);
break;
default:
+#ifdef HAVE_PLUGINS
+ /*
+ * Do we have a handler for this packet block option code?
+ */
+ handler = (option_handler)g_hash_table_lookup(option_handlers[BT_INDEX_PBS],
+ GUINT_TO_POINTER(oh->option_code));
+ if (handler != NULL) {
+ /* Yes - call the handler. */
+ if (!handler(pn->byte_swapped, oh->option_length,
+ option_content, err, err_info))
+ /* XXX - free anything? */
+ return FALSE;
+ } else
+#endif
pcapng_debug2("pcapng_read_packet_block: unknown option %u - ignoring %u bytes",
- oh.option_code, oh.option_length);
+ oh->option_code, oh->option_length);
}
}
- g_free(option_content);
-
pcap_read_post_process(WTAP_FILE_TYPE_SUBTYPE_PCAPNG, iface_info.wtap_encap,
wblock->packet_header, ws_buffer_start_ptr(wblock->frame_buffer),
pn->byte_swapped, fcslen);
diff --git a/wiretap/pcapng_module.h b/wiretap/pcapng_module.h
index 226a8dd7b1..ef5701678b 100644
--- a/wiretap/pcapng_module.h
+++ b/wiretap/pcapng_module.h
@@ -36,5 +36,18 @@ WS_DLL_PUBLIC
void register_pcapng_block_type_handler(guint block_type, block_reader read,
block_writer write);
+/*
+ * Handler routine for pcap-ng option type.
+ */
+typedef gboolean (*option_handler)(gboolean, guint, guint8 *, int *, gchar **);
+
+/*
+ * Register a handler for a pcap-ng option code for a particular block
+ * type.
+ */
+WS_DLL_PUBLIC
+void register_pcapng_option_handler(guint block_type, guint option_code,
+ option_handler handle);
+
#endif /* __PCAP_MODULE_H__ */
diff --git a/wiretap/wtap.c b/wiretap/wtap.c
index 88b587e12a..e8726e280d 100644
--- a/wiretap/wtap.c
+++ b/wiretap/wtap.c
@@ -1179,6 +1179,19 @@ wtap_buf_ptr(wtap *wth)
return ws_buffer_start_ptr(wth->frame_buffer);
}
+void
+wtap_phdr_init(struct wtap_pkthdr *phdr)
+{
+ memset(phdr, 0, sizeof(struct wtap_pkthdr));
+ ws_buffer_init(&phdr->ft_specific_data, 0);
+}
+
+void
+wtap_phdr_cleanup(struct wtap_pkthdr *phdr)
+{
+ ws_buffer_free(&phdr->ft_specific_data);
+}
+
gboolean
wtap_seek_read(wtap *wth, gint64 seek_off,
struct wtap_pkthdr *phdr, Buffer *buf, int *err, gchar **err_info)
diff --git a/wiretap/wtap.h b/wiretap/wtap.h
index 26c6c9e477..55b35448c3 100644
--- a/wiretap/wtap.h
+++ b/wiretap/wtap.h
@@ -1007,20 +1007,21 @@ union wtap_pseudo_header {
#define REC_TYPE_FT_SPECIFIC_REPORT 2 /**< file-type-specific report */
struct wtap_pkthdr {
- guint rec_type; /* what type of record is this? */
- guint32 presence_flags; /* what stuff do we have? */
- nstime_t ts;
- guint32 caplen; /* data length in the file */
- guint32 len; /* data length on the wire */
- int pkt_encap; /* WTAP_ENCAP_ value for this packet */
- int pkt_tsprec; /* WTAP_TSPREC_ value for this packet */
- /* pcapng variables */
- guint32 interface_id; /* identifier of the interface. */
- /* options */
- gchar *opt_comment; /* NULL if not available */
- guint64 drop_count; /* number of packets lost (by the interface and the
- operating system) between this packet and the preceding one. */
- guint32 pack_flags; /* XXX - 0 for now (any value for "we don't have it"?) */
+ guint rec_type; /* what type of record is this? */
+ guint32 presence_flags; /* what stuff do we have? */
+ nstime_t ts; /* time stamp */
+ guint32 caplen; /* data length in the file */
+ guint32 len; /* data length on the wire */
+ int pkt_encap; /* WTAP_ENCAP_ value for this packet */
+ int pkt_tsprec; /* WTAP_TSPREC_ value for this packet */
+ /* pcapng variables */
+ guint32 interface_id; /* identifier of the interface. */
+ /* options */
+ gchar *opt_comment; /* NULL if not available */
+ guint64 drop_count; /* number of packets lost (by the interface and the
+ operating system) between this packet and the preceding one. */
+ guint32 pack_flags; /* XXX - 0 for now (any value for "we don't have it"?) */
+ Buffer ft_specific_data; /* file-type specific data */
union wtap_pseudo_header pseudo_header;
};
@@ -1464,6 +1465,14 @@ struct wtap_pkthdr *wtap_phdr(wtap *wth);
WS_DLL_PUBLIC
guint8 *wtap_buf_ptr(wtap *wth);
+/*** initialize a wtap_pkthdr structure ***/
+WS_DLL_PUBLIC
+void wtap_phdr_init(struct wtap_pkthdr *phdr);
+
+/*** clean up a wtap_pkthdr structure, freeing what wtap_phdr_init() allocated */
+WS_DLL_PUBLIC
+void wtap_phdr_cleanup(struct wtap_pkthdr *phdr);
+
/*** get various information snippets about the current file ***/
/** Return an approximation of the amount of data we've read sequentially