diff --git a/epan/dissectors/packet-frame.c b/epan/dissectors/packet-frame.c index cdbe5617bc..020c32a410 100644 --- a/epan/dissectors/packet-frame.c +++ b/epan/dissectors/packet-frame.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #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 = diff --git a/epan/frame_data.c b/epan/frame_data.c index 1900b6ac59..43dc081b74 100644 --- a/epan/frame_data.c +++ b/epan/frame_data.c @@ -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 */ diff --git a/epan/packet.c b/epan/packet.c index 0171d5c3a1..5315a28c15 100644 --- a/epan/packet.c +++ b/epan/packet.c @@ -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; diff --git a/wiretap/pcapng.c b/wiretap/pcapng.c index 6e9d5bd675..923ad242fe 100644 --- a/wiretap/pcapng.c +++ b/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 = { diff --git a/wiretap/pcapng_module.h b/wiretap/pcapng_module.h index 745a6985e3..8f3eeee2d9 100644 --- a/wiretap/pcapng_module.h +++ b/wiretap/pcapng_module.h @@ -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: diff --git a/wiretap/wtap.h b/wiretap/wtap.h index e79aa5ff84..70a4a219b0 100644 --- a/wiretap/wtap.h +++ b/wiretap/wtap.h @@ -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. diff --git a/wiretap/wtap_opttypes.h b/wiretap/wtap_opttypes.h index dfba1510f1..01e8fb495b 100644 --- a/wiretap/wtap_opttypes.h +++ b/wiretap/wtap_opttypes.h @@ -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;