pcapng: add support for custom blocks
This commit is contained in:
parent
4aff36d501
commit
4ddae68508
|
@ -30,6 +30,7 @@
|
|||
#include <wsutil/wsgcrypt.h>
|
||||
#include <wsutil/str_util.h>
|
||||
#include <epan/proto_data.h>
|
||||
#include <epan/addr_resolv.h>
|
||||
#include <wmem/wmem.h>
|
||||
|
||||
#include "packet-frame.h"
|
||||
|
@ -90,6 +91,8 @@ static int hf_frame_pack_start_frame_delimiter_error = -1;
|
|||
static int hf_frame_pack_preamble_error = -1;
|
||||
static int hf_frame_pack_symbol_error = -1;
|
||||
static int hf_frame_wtap_encap = -1;
|
||||
static int hf_frame_cb_pen = -1;
|
||||
static int hf_frame_cb_copy_allowed = -1;
|
||||
static int hf_comments_text = -1;
|
||||
|
||||
static gint ett_frame = -1;
|
||||
|
@ -385,6 +388,10 @@ dissect_frame(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, void*
|
|||
pinfo->current_proto = "Systemd Journal";
|
||||
break;
|
||||
|
||||
case REC_TYPE_CUSTOM_BLOCK:
|
||||
pinfo->current_proto = "PCAPNG Custom Block";
|
||||
break;
|
||||
|
||||
default:
|
||||
DISSECTOR_ASSERT_NOT_REACHED();
|
||||
break;
|
||||
|
@ -512,6 +519,20 @@ dissect_frame(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, void*
|
|||
"Systemd Journal Entry %u: %u byte%s",
|
||||
pinfo->num, frame_len, frame_plurality);
|
||||
break;
|
||||
|
||||
case REC_TYPE_CUSTOM_BLOCK:
|
||||
ti = proto_tree_add_protocol_format(tree, proto_frame, tvb, 0, tvb_captured_length(tvb),
|
||||
"PCAPNG Custom Block %u: %u byte%s",
|
||||
pinfo->num, frame_len, frame_plurality);
|
||||
if (generate_bits_field) {
|
||||
proto_item_append_text(ti, " (%u bits)", frame_len * 8);
|
||||
}
|
||||
proto_item_append_text(ti, " of custom data and options, PEN %s (%u)",
|
||||
enterprises_lookup(pinfo->rec->rec_header.custom_block_header.pen, "Unknown"),
|
||||
pinfo->rec->rec_header.custom_block_header.pen);
|
||||
proto_item_append_text(ti, ", copying%s allowed",
|
||||
pinfo->rec->rec_header.custom_block_header.copy_allowed ? "" : " not");
|
||||
break;
|
||||
}
|
||||
|
||||
fh_tree = proto_item_add_subtree(ti, ett_frame);
|
||||
|
@ -830,6 +851,21 @@ dissect_frame(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, void*
|
|||
(void *)pinfo->pseudo_header);
|
||||
}
|
||||
break;
|
||||
|
||||
case REC_TYPE_CUSTOM_BLOCK:
|
||||
col_set_str(pinfo->cinfo, COL_PROTOCOL, "PCAPNG");
|
||||
proto_tree_add_uint_format_value(fh_tree, hf_frame_cb_pen, tvb, 0, 0,
|
||||
pinfo->rec->rec_header.custom_block_header.pen,
|
||||
"%s (%u)",
|
||||
enterprises_lookup(pinfo->rec->rec_header.custom_block_header.pen, "Unknown"),
|
||||
pinfo->rec->rec_header.custom_block_header.pen);
|
||||
proto_tree_add_boolean(fh_tree, hf_frame_cb_copy_allowed, tvb, 0, 0, pinfo->rec->rec_header.custom_block_header.copy_allowed);
|
||||
col_add_fstr(pinfo->cinfo, COL_INFO, "Custom Block: PEN = %s (%d), will%s be copied",
|
||||
enterprises_lookup(pinfo->rec->rec_header.custom_block_header.pen, "Unknown"),
|
||||
pinfo->rec->rec_header.custom_block_header.pen,
|
||||
pinfo->rec->rec_header.custom_block_header.copy_allowed ? "" : " not");
|
||||
call_data_dissector(tvb, pinfo, parent_tree);
|
||||
break;
|
||||
}
|
||||
#ifdef _MSC_VER
|
||||
} __except(EXCEPTION_EXECUTE_HANDLER /* handle all exceptions */) {
|
||||
|
@ -1216,6 +1252,16 @@ proto_register_frame(void)
|
|||
{ "Drop Count", "frame.drop_count",
|
||||
FT_UINT64, BASE_DEC, NULL, 0x0,
|
||||
"Number of frames lost between this frame and the preceding one on the same interface", HFILL }},
|
||||
|
||||
{ &hf_frame_cb_pen,
|
||||
{ "Private Enterprise Number", "frame.cb_pen",
|
||||
FT_UINT32, BASE_DEC, NULL, 0x0,
|
||||
"IANA assigned private enterprise number (PEN)", HFILL }},
|
||||
|
||||
{ &hf_frame_cb_copy_allowed,
|
||||
{ "Copying", "frame.cb_copy",
|
||||
FT_BOOLEAN, BASE_DEC, TFS(&tfs_allowed_not_allowed), 0x0,
|
||||
"Whether the custom block will be written or not", HFILL }},
|
||||
};
|
||||
|
||||
static hf_register_info hf_encap =
|
||||
|
|
|
@ -201,6 +201,16 @@ frame_data_init(frame_data *fdata, guint32 num, const wtap_rec *rec,
|
|||
fdata->cum_bytes = cum_bytes + rec->rec_header.systemd_journal_header.record_len;
|
||||
fdata->cap_len = rec->rec_header.systemd_journal_header.record_len;
|
||||
break;
|
||||
|
||||
case REC_TYPE_CUSTOM_BLOCK:
|
||||
/*
|
||||
* XXX - is cum_bytes supposed to count non-packet bytes?
|
||||
*/
|
||||
fdata->pkt_len = rec->rec_header.custom_block_header.length;
|
||||
fdata->cum_bytes = cum_bytes + rec->rec_header.custom_block_header.length;
|
||||
fdata->cap_len = rec->rec_header.custom_block_header.length;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
/* To save some memory, we coerce it into 4 bits */
|
||||
|
|
|
@ -504,6 +504,10 @@ dissect_record(epan_dissect_t *edt, int file_type_subtype,
|
|||
record_type = "Systemd Journal Entry";
|
||||
break;
|
||||
|
||||
case REC_TYPE_CUSTOM_BLOCK:
|
||||
record_type = "PCAPNG Custom Block";
|
||||
break;
|
||||
|
||||
default:
|
||||
/*
|
||||
* XXX - if we add record types that shouldn't be
|
||||
|
@ -551,6 +555,10 @@ dissect_record(epan_dissect_t *edt, int file_type_subtype,
|
|||
case REC_TYPE_SYSTEMD_JOURNAL:
|
||||
edt->pi.pseudo_header = NULL;
|
||||
break;
|
||||
|
||||
case REC_TYPE_CUSTOM_BLOCK:
|
||||
edt->pi.pseudo_header = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
edt->pi.fd = fd;
|
||||
|
|
168
wiretap/pcapng.c
168
wiretap/pcapng.c
|
@ -121,6 +121,18 @@ typedef struct pcapng_name_resolution_block_s {
|
|||
*/
|
||||
#define MIN_NRB_SIZE ((guint32)(MIN_BLOCK_SIZE + sizeof(pcapng_name_resolution_block_t)))
|
||||
|
||||
/* pcapng: custom block file encoding */
|
||||
typedef struct pcapng_custom_block_s {
|
||||
guint32 pen;
|
||||
/* Custom data and options */
|
||||
} pcapng_custom_block_t;
|
||||
|
||||
/*
|
||||
* Minimum CB size = minimum block size + size of fixed length portion of CB.
|
||||
*/
|
||||
|
||||
#define MIN_CB_SIZE ((guint32)(MIN_BLOCK_SIZE + sizeof(pcapng_custom_block_t)))
|
||||
|
||||
/*
|
||||
* Minimum ISB size = minimum block size + size of fixed length portion of ISB.
|
||||
*/
|
||||
|
@ -281,6 +293,8 @@ register_pcapng_block_type_handler(guint block_type, block_reader reader,
|
|||
case BLOCK_TYPE_ISB:
|
||||
case BLOCK_TYPE_EPB:
|
||||
case BLOCK_TYPE_DSB:
|
||||
case BLOCK_TYPE_CB_COPY:
|
||||
case BLOCK_TYPE_CB_NO_COPY:
|
||||
case BLOCK_TYPE_SYSDIG_EVENT:
|
||||
case BLOCK_TYPE_SYSDIG_EVENT_V2:
|
||||
case BLOCK_TYPE_SYSTEMD_JOURNAL:
|
||||
|
@ -2364,6 +2378,77 @@ pcapng_read_interface_statistics_block(FILE_T fh, pcapng_block_header_t *bh,
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pcapng_handle_generic_custom_block(FILE_T fh, pcapng_block_header_t *bh,
|
||||
guint32 pen, wtapng_block_t *wblock,
|
||||
int *err, gchar **err_info)
|
||||
{
|
||||
guint to_read;
|
||||
|
||||
ws_debug("unknown pen %u", pen);
|
||||
if (bh->block_total_length % 4) {
|
||||
to_read = bh->block_total_length + 4 - (bh->block_total_length % 4);
|
||||
} else {
|
||||
to_read = bh->block_total_length;
|
||||
}
|
||||
to_read -= MIN_CB_SIZE;
|
||||
wblock->rec->rec_type = REC_TYPE_CUSTOM_BLOCK;
|
||||
wblock->rec->presence_flags = 0;
|
||||
wblock->rec->rec_header.custom_block_header.length = bh->block_total_length - MIN_CB_SIZE;
|
||||
wblock->rec->rec_header.custom_block_header.pen = pen;
|
||||
wblock->rec->rec_header.custom_block_header.copy_allowed = (bh->block_type == BLOCK_TYPE_CB_COPY);
|
||||
if (!wtap_read_packet_bytes(fh, wblock->frame_buffer, to_read, err, err_info)) {
|
||||
return FALSE;
|
||||
}
|
||||
/*
|
||||
* We return these to the caller in pcapng_read().
|
||||
*/
|
||||
wblock->internal = FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
static gboolean
|
||||
pcapng_read_custom_block(FILE_T fh, pcapng_block_header_t *bh,
|
||||
const section_info_t *section_info,
|
||||
wtapng_block_t *wblock,
|
||||
int *err, gchar **err_info)
|
||||
{
|
||||
pcapng_custom_block_t cb;
|
||||
guint32 pen;
|
||||
|
||||
/* Is this block long enough to be an CB? */
|
||||
if (bh->block_total_length < MIN_CB_SIZE) {
|
||||
/*
|
||||
* No.
|
||||
*/
|
||||
*err = WTAP_ERR_BAD_FILE;
|
||||
*err_info = g_strdup_printf("pcapng_read_custom_block: total block length %u is too small (< %u)",
|
||||
bh->block_total_length, MIN_CB_SIZE);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Custom block read fixed part */
|
||||
if (!wtap_read_bytes(fh, &cb, sizeof cb, err, err_info)) {
|
||||
ws_debug("failed to read pen");
|
||||
return FALSE;
|
||||
}
|
||||
if (section_info->byte_swapped) {
|
||||
pen = GUINT32_SWAP_LE_BE(cb.pen);
|
||||
} else {
|
||||
pen = cb.pen;
|
||||
}
|
||||
ws_debug("pen %u, custom data and option length %u", pen, bh->block_total_length - MIN_CB_SIZE);
|
||||
|
||||
switch (pen) {
|
||||
default:
|
||||
if (!pcapng_handle_generic_custom_block(fh, bh, pen, wblock, err, err_info)) {
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pcapng_read_sysdig_event_block(FILE_T fh, pcapng_block_header_t *bh,
|
||||
const section_info_t *section_info,
|
||||
|
@ -2794,6 +2879,11 @@ pcapng_read_block(wtap *wth, FILE_T fh, pcapng_t *pn,
|
|||
if (!pcapng_read_decryption_secrets_block(fh, &bh, section_info, wblock, err, err_info))
|
||||
return FALSE;
|
||||
break;
|
||||
case(BLOCK_TYPE_CB_COPY):
|
||||
case(BLOCK_TYPE_CB_NO_COPY):
|
||||
if (!pcapng_read_custom_block(fh, &bh, section_info, wblock, err, err_info))
|
||||
return FALSE;
|
||||
break;
|
||||
case(BLOCK_TYPE_SYSDIG_EVENT):
|
||||
case(BLOCK_TYPE_SYSDIG_EVENT_V2):
|
||||
/* case(BLOCK_TYPE_SYSDIG_EVF): */
|
||||
|
@ -3113,7 +3203,7 @@ pcapng_read(wtap *wth, wtap_rec *rec, Buffer *buf, int *err,
|
|||
* Read the next block.
|
||||
*/
|
||||
if (!pcapng_read_block(wth, wth->fh, pcapng, current_section,
|
||||
&new_section, &wblock, err, err_info)) {
|
||||
&new_section, &wblock, err, err_info)) {
|
||||
ws_debug("data_offset is finally %" G_GINT64_MODIFIER "d", *data_offset);
|
||||
ws_debug("couldn't read packet block");
|
||||
wtap_block_free(wblock.block);
|
||||
|
@ -4086,6 +4176,73 @@ pcapng_write_systemd_journal_export_block(wtap_dumper *wdh, const wtap_rec *rec,
|
|||
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pcapng_write_custom_block(wtap_dumper *wdh, const wtap_rec *rec,
|
||||
const guint8 *pd, int *err)
|
||||
{
|
||||
pcapng_block_header_t bh;
|
||||
pcapng_custom_block_t cb;
|
||||
const guint32 zero_pad = 0;
|
||||
guint32 pad_len;
|
||||
|
||||
/* Don't write anything we are not supposed to. */
|
||||
if (!rec->rec_header.custom_block_header.copy_allowed) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Don't write anything we're not willing to read. */
|
||||
if (rec->rec_header.custom_block_header.length > WTAP_MAX_PACKET_SIZE_STANDARD) {
|
||||
*err = WTAP_ERR_PACKET_TOO_LARGE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (rec->rec_header.custom_block_header.length % 4) {
|
||||
pad_len = 4 - (rec->rec_header.custom_block_header.length % 4);
|
||||
} else {
|
||||
pad_len = 0;
|
||||
}
|
||||
|
||||
/* write block header */
|
||||
bh.block_type = BLOCK_TYPE_CB_COPY;
|
||||
bh.block_total_length = (guint32)sizeof(bh) + (guint32)sizeof(cb) + rec->rec_header.custom_block_header.length + pad_len + 4;
|
||||
ws_debug("writing %u bytes, %u padded",
|
||||
rec->rec_header.custom_block_header.length,
|
||||
bh.block_total_length);
|
||||
if (!wtap_dump_file_write(wdh, &bh, sizeof bh, err)) {
|
||||
return FALSE;
|
||||
}
|
||||
wdh->bytes_dumped += sizeof bh;
|
||||
|
||||
/* write custom block header */
|
||||
cb.pen = rec->rec_header.custom_block_header.pen;
|
||||
if (!wtap_dump_file_write(wdh, &cb, sizeof cb, err)) {
|
||||
return FALSE;
|
||||
}
|
||||
wdh->bytes_dumped += sizeof cb;
|
||||
|
||||
/* write custom data */
|
||||
if (!wtap_dump_file_write(wdh, pd, rec->rec_header.custom_block_header.length, err)) {
|
||||
return FALSE;
|
||||
}
|
||||
wdh->bytes_dumped += rec->rec_header.custom_block_header.length;
|
||||
|
||||
/* write padding (if any) */
|
||||
if (pad_len > 0) {
|
||||
if (!wtap_dump_file_write(wdh, &zero_pad, pad_len, err)) {
|
||||
return FALSE;
|
||||
}
|
||||
wdh->bytes_dumped += pad_len;
|
||||
}
|
||||
|
||||
/* write block footer */
|
||||
if (!wtap_dump_file_write(wdh, &bh.block_total_length,
|
||||
sizeof bh.block_total_length, err)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pcapng_write_decryption_secrets_block(wtap_dumper *wdh, wtap_block_t sdata, int *err)
|
||||
{
|
||||
|
@ -5041,6 +5198,12 @@ static gboolean pcapng_dump(wtap_dumper *wdh,
|
|||
}
|
||||
break;
|
||||
|
||||
case REC_TYPE_CUSTOM_BLOCK:
|
||||
if (!pcapng_write_custom_block(wdh, rec, pd, err)) {
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
/* We don't support writing this record type. */
|
||||
*err = WTAP_ERR_UNWRITABLE_REC_TYPE;
|
||||
|
@ -5281,6 +5444,9 @@ static const struct supported_block_type pcapng_blocks_supported[] = {
|
|||
|
||||
/* Multiple systemd journal records. */
|
||||
{ WTAP_BLOCK_SYSTEMD_JOURNAL, MULTIPLE_BLOCKS_SUPPORTED, OPTION_TYPES_SUPPORTED(systemd_journal_block_options_supported) },
|
||||
|
||||
/* Multiple custom blocks. */
|
||||
{ WTAP_BLOCK_CUSTOM_BLOCK, MULTIPLE_BLOCKS_SUPPORTED, NO_OPTIONS_SUPPORTED },
|
||||
};
|
||||
|
||||
static const struct file_type_subtype_info pcapng_info = {
|
||||
|
|
|
@ -30,6 +30,8 @@
|
|||
#define BLOCK_TYPE_SYSDIG_EVF 0x00000208 /* Sysdig Event Block with flags */
|
||||
#define BLOCK_TYPE_SYSDIG_EVENT_V2 0x00000216 /* Sysdig Event Block version 2 */
|
||||
#define BLOCK_TYPE_SYSDIG_EVF_V2 0x00000217 /* Sysdig Event Block with flags version 2 */
|
||||
#define BLOCK_TYPE_CB_COPY 0x00000BAD /* Custom Block which can be copied */
|
||||
#define BLOCK_TYPE_CB_NO_COPY 0x40000BAD /* Custom Block which should not be copied */
|
||||
|
||||
/* TODO: the following are not yet well defined in the draft spec,
|
||||
* and do not yet have block type values assigned to them:
|
||||
|
|
|
@ -1212,6 +1212,7 @@ union wtap_pseudo_header {
|
|||
#define REC_TYPE_FT_SPECIFIC_REPORT 2 /**< file-type-specific report */
|
||||
#define REC_TYPE_SYSCALL 3 /**< system call */
|
||||
#define REC_TYPE_SYSTEMD_JOURNAL 4 /**< systemd journal entry */
|
||||
#define REC_TYPE_CUSTOM_BLOCK 5 /**< pcapng custom block */
|
||||
|
||||
typedef struct {
|
||||
guint32 caplen; /* data length in the file */
|
||||
|
@ -1323,6 +1324,12 @@ typedef struct {
|
|||
guint32 record_len; /* length of the record */
|
||||
} wtap_systemd_journal_header;
|
||||
|
||||
typedef struct {
|
||||
guint32 length; /* length of the record */
|
||||
guint32 pen; /* private enterprise number */
|
||||
gboolean copy_allowed; /* CB can be written */
|
||||
} wtap_custom_block_header;
|
||||
|
||||
typedef struct {
|
||||
guint rec_type; /* what type of record is this? */
|
||||
guint32 presence_flags; /* what stuff do we have? */
|
||||
|
@ -1333,6 +1340,7 @@ typedef struct {
|
|||
wtap_ft_specific_header ft_specific_header;
|
||||
wtap_syscall_header syscall_header;
|
||||
wtap_systemd_journal_header systemd_journal_header;
|
||||
wtap_custom_block_header custom_block_header;
|
||||
} rec_header;
|
||||
/*
|
||||
* XXX - this should become a full set of options.
|
||||
|
|
|
@ -168,6 +168,7 @@ typedef enum {
|
|||
WTAP_BLOCK_FT_SPECIFIC_REPORT,
|
||||
WTAP_BLOCK_FT_SPECIFIC_EVENT,
|
||||
WTAP_BLOCK_SYSTEMD_JOURNAL,
|
||||
WTAP_BLOCK_CUSTOM_BLOCK,
|
||||
MAX_WTAP_BLOCK_TYPE_VALUE
|
||||
} wtap_block_type_t;
|
||||
|
||||
|
|
Loading…
Reference in New Issue