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>
This commit is contained in:
Guy Harris 2014-11-30 16:30:19 -08:00
parent 35b1bc5ec6
commit 846bb53948
12 changed files with 254 additions and 79 deletions

19
file.c
View File

@ -310,6 +310,9 @@ cf_open(capture_file *cf, const char *fname, unsigned int type, gboolean is_temp
and fill in the information for this file. */
cf_close(cf);
/* Initialize the packet header. */
wtap_phdr_init(&cf->phdr);
/* XXX - we really want to initialize this after we've read all
the packets, so we know how much we'll ultimately need. */
ws_buffer_init(&cf->buf, 1500);
@ -436,6 +439,9 @@ cf_close(capture_file *cf)
/* no open_routine type */
cf->open_type = WTAP_TYPE_AUTO;
/* Clean up the packet header. */
wtap_phdr_cleanup(&cf->phdr);
/* Free up the packet buffer. */
ws_buffer_free(&cf->buf);
@ -2192,7 +2198,7 @@ process_specified_records(capture_file *cf, packet_range_t *range,
range_process_e process_this;
struct wtap_pkthdr phdr;
memset(&phdr, 0, sizeof(struct wtap_pkthdr));
wtap_phdr_init(&phdr);
ws_buffer_init(&buf, 1500);
/* Update the progress bar when it gets to this value. */
@ -2290,6 +2296,7 @@ process_specified_records(capture_file *cf, packet_range_t *range,
if (progbar != NULL)
destroy_progress_dlg(progbar);
wtap_phdr_cleanup(&phdr);
ws_buffer_free(&buf);
return ret;
@ -3942,6 +3949,8 @@ cf_get_user_packet_comment(capture_file *cf, const frame_data *fd)
char *
cf_get_comment(capture_file *cf, const frame_data *fd)
{
char *comment;
/* fetch user comment */
if (fd->flags.has_user_comment)
return g_strdup(cf_get_user_packet_comment(cf, fd));
@ -3951,14 +3960,16 @@ cf_get_comment(capture_file *cf, const frame_data *fd)
struct wtap_pkthdr phdr; /* Packet header */
Buffer buf; /* Packet data */
memset(&phdr, 0, sizeof(struct wtap_pkthdr));
wtap_phdr_init(&phdr);
ws_buffer_init(&buf, 1500);
if (!cf_read_record_r(cf, fd, &phdr, &buf))
{ /* XXX, what we can do here? */ }
comment = phdr.opt_comment;
wtap_phdr_cleanup(&phdr);
ws_buffer_free(&buf);
return phdr.opt_comment;
return comment;
}
return NULL;
}

View File

@ -74,7 +74,7 @@ frame_cache(struct tvb_frame *frame_tvb)
{
struct wtap_pkthdr phdr; /* Packet header */
memset(&phdr, 0, sizeof(struct wtap_pkthdr));
wtap_phdr_init(&phdr);
if (frame_tvb->buf == NULL) {
frame_tvb->buf = (struct Buffer *) g_malloc(sizeof(struct Buffer));
@ -87,6 +87,8 @@ frame_cache(struct tvb_frame *frame_tvb)
}
frame_tvb->tvb.real_data = ws_buffer_start_ptr(frame_tvb->buf) + frame_tvb->offset;
wtap_phdr_cleanup(&phdr);
}
static void

View File

@ -990,7 +990,7 @@ load_cap_file(capture_file *cf)
struct wtap_pkthdr phdr;
epan_dissect_t edt;
memset(&phdr, 0, sizeof(phdr));
wtap_phdr_init(&phdr);
epan_dissect_init(&edt, cf->epan, TRUE, FALSE);
@ -1000,6 +1000,8 @@ load_cap_file(capture_file *cf)
epan_dissect_cleanup(&edt);
wtap_phdr_cleanup(&phdr);
if (err != 0) {
/* Print a message noting that the read failed somewhere along the line. */
switch (err) {

View File

@ -104,21 +104,18 @@ typedef struct FrameRecord_t {
static void
frame_write(FrameRecord_t *frame, wtap *wth, wtap_dumper *pdh, Buffer *buf,
const char *infile)
frame_write(FrameRecord_t *frame, wtap *wth, wtap_dumper *pdh,
struct wtap_pkthdr *phdr, Buffer *buf, const char *infile)
{
int err;
gchar *err_info;
struct wtap_pkthdr phdr;
memset(&phdr, 0, sizeof(struct wtap_pkthdr));
DEBUG_PRINT("\nDumping frame (offset=%" G_GINT64_MODIFIER "u)\n",
frame->offset);
/* Re-read the first frame from the stored location */
if (!wtap_seek_read(wth, frame->offset, &phdr, buf, &err, &err_info)) {
/* Re-read the frame from the stored location */
if (!wtap_seek_read(wth, frame->offset, phdr, buf, &err, &err_info)) {
if (err != 0) {
/* Print a message noting that the read failed somewhere along the line. */
fprintf(stderr,
@ -138,11 +135,12 @@ frame_write(FrameRecord_t *frame, wtap *wth, wtap_dumper *pdh, Buffer *buf,
}
/* Copy, and set length and timestamp from item. */
/* TODO: remove when wtap_seek_read() will read phdr */
phdr.ts = frame->time;
/* TODO: remove when wtap_seek_read() fills in phdr,
including time stamps, for all file types */
phdr->ts = frame->time;
/* Dump frame to outfile */
if (!wtap_dump(pdh, &phdr, ws_buffer_start_ptr(buf), &err)) {
if (!wtap_dump(pdh, phdr, ws_buffer_start_ptr(buf), &err)) {
fprintf(stderr, "reordercap: Error (%s) writing frame to outfile\n",
wtap_strerror(err));
exit(1);
@ -202,6 +200,7 @@ main(int argc, char *argv[])
GString *runtime_info_str;
wtap *wth = NULL;
wtap_dumper *pdh = NULL;
struct wtap_pkthdr dump_phdr;
Buffer buf;
int err;
gchar *err_info;
@ -360,16 +359,18 @@ main(int argc, char *argv[])
}
/* Write out each sorted frame in turn */
wtap_phdr_init(&dump_phdr);
ws_buffer_init(&buf, 1500);
for (i = 0; i < frames->len; i++) {
FrameRecord_t *frame = (FrameRecord_t *)frames->pdata[i];
/* Avoid writing if already sorted and configured to */
if (write_output_regardless || (wrong_order_count > 0)) {
frame_write(frame, wth, pdh, &buf, infile);
frame_write(frame, wth, pdh, &dump_phdr, &buf, infile);
}
g_slice_free(FrameRecord_t, frame);
}
wtap_phdr_cleanup(&dump_phdr);
ws_buffer_free(&buf);
if (!write_output_regardless && (wrong_order_count == 0)) {

View File

@ -1810,7 +1810,7 @@ load_cap_file(capture_file *cf, int max_packet_count, gint64 max_byte_count)
/* Get the union of the flags for all tap listeners. */
tap_flags = union_of_tap_listener_flags();
memset(&file_phdr, 0, sizeof(file_phdr));
wtap_phdr_init(&file_phdr);
/* XXX - TEMPORARY HACK TO ELF DISSECTOR */
file_phdr.pkt_encap = 1234;
@ -1945,6 +1945,8 @@ load_cap_file(capture_file *cf, int max_packet_count, gint64 max_byte_count)
}
}
wtap_phdr_cleanup(&phdr);
if (err != 0) {
/*
* Print a message noting that the read failed somewhere along the line.

View File

@ -3072,7 +3072,7 @@ load_cap_file(capture_file *cf, char *save_file, int out_file_type,
Buffer buf;
epan_dissect_t *edt = NULL;
memset(&phdr, 0, sizeof(struct wtap_pkthdr));
wtap_phdr_init(&phdr);
shb_hdr = wtap_file_get_shb_info(cf->wth);
idb_inf = wtap_file_get_idb_info(cf->wth);
@ -3376,6 +3376,8 @@ load_cap_file(capture_file *cf, char *save_file, int out_file_type,
}
}
wtap_phdr_cleanup(&phdr);
if (err != 0) {
/*
* Print a message noting that the read failed somewhere along the line.

View File

@ -1104,7 +1104,7 @@ packet_list_dissect_and_cache_record(PacketList *packet_list, PacketListRecord *
g_return_if_fail(packet_list);
g_return_if_fail(PACKETLIST_IS_LIST(packet_list));
memset(&phdr, 0, sizeof(struct wtap_pkthdr));
wtap_phdr_init(&phdr);
fdata = record->fdata;
@ -1175,6 +1175,7 @@ packet_list_dissect_and_cache_record(PacketList *packet_list, PacketListRecord *
record->colorized = TRUE;
epan_dissect_cleanup(&edt);
wtap_phdr_cleanup(&phdr);
ws_buffer_free(&buf);
}

View File

@ -143,7 +143,7 @@ process_record(frame_data *frame, column_info *cinfo, ph_stats_t* ps)
Buffer buf;
double cur_time;
memset(&phdr, 0, sizeof(struct wtap_pkthdr));
wtap_phdr_init(&phdr);
/* Load the record from the capture file */
ws_buffer_init(&buf, 1500);
@ -170,6 +170,7 @@ process_record(frame_data *frame, column_info *cinfo, ph_stats_t* ps)
/* Free our memory. */
epan_dissect_cleanup(&edt);
wtap_phdr_cleanup(&phdr);
ws_buffer_free(&buf);
return TRUE; /* success */

View File

@ -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);

View File

@ -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__ */

View File

@ -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)

View File

@ -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