pcapng: add support for custom blocks

This commit is contained in:
Michael Tuexen 2021-06-06 21:15:35 +00:00 committed by Wireshark GitLab Utility
parent 4aff36d501
commit 4ddae68508
7 changed files with 242 additions and 1 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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