From 1f0a16e4724ebe57efa3af8ae74b94e8d4198641 Mon Sep 17 00:00:00 2001 From: Michael Tuexen Date: Mon, 21 Jun 2021 16:56:58 +0200 Subject: [PATCH] pcapng: add support for custom options --- debian/libwiretap0.symbols | 1 + wiretap/pcapng.c | 388 ++++++++++++++++++++++++++++++++----- wiretap/wtap.c | 12 ++ wiretap/wtap.h | 1 + wiretap/wtap_opttypes.c | 40 +++- wiretap/wtap_opttypes.h | 193 ++++++++++-------- 6 files changed, 501 insertions(+), 134 deletions(-) diff --git a/debian/libwiretap0.symbols b/debian/libwiretap0.symbols index c5e0520270..a89446a2a0 100644 --- a/debian/libwiretap0.symbols +++ b/debian/libwiretap0.symbols @@ -22,6 +22,7 @@ libwiretap.so.0 libwiretap0 #MINVER# register_pcapng_option_handler@Base 1.99.2 wtap_add_generated_idb@Base 3.3.0 wtap_addrinfo_list_empty@Base 2.5.0 + wtap_block_add_custom_option@Base 3.5.0 wtap_block_add_if_filter_option@Base 3.5.0 wtap_block_add_ipv4_option@Base 2.1.2 wtap_block_add_ipv6_option@Base 2.1.2 diff --git a/wiretap/pcapng.c b/wiretap/pcapng.c index 3fc6ee2989..ccd921cc02 100644 --- a/wiretap/pcapng.c +++ b/wiretap/pcapng.c @@ -589,6 +589,59 @@ pcapng_process_uint64_option(wtapng_block_t *wblock, } } +static gboolean +pcap_process_generic_custom_option(wtapng_block_t *wblock, + guint16 option_code, guint16 option_length, + guint32 pen, + const guint8 *option_content) +{ + wtap_option_t option; + + if (wblock->type == BLOCK_TYPE_EPB) { + if (wblock->rec->custom_options == NULL) { + wblock->rec->custom_options = g_array_new (FALSE, FALSE, sizeof(wtap_option_t)); + } + option.option_id = option_code; + option.value.custom_opt.pen = pen; + option.value.custom_opt.custom_data_len = option_length - 4; + option.value.custom_opt.custom_data = g_memdup2(option_content + 4, option_length - 4); + g_array_append_val(wblock->rec->custom_options, option); + } else { + wtap_block_add_custom_option(wblock->block, option_code, pen, option_content + 4, option_length - 4); + } + return TRUE; +} + +static gboolean +pcapng_process_custom_option(wtapng_block_t *wblock, + const section_info_t *section_info, + guint16 option_code, guint16 option_length, + const guint8 *option_content, + int *err, gchar **err_info) +{ + guint32 pen; + + if (option_length < 4) { + *err = WTAP_ERR_BAD_FILE; + *err_info = g_strdup_printf("pcapng: option length (%d) too small for custom option", + option_length); + return FALSE; + } + memcpy(&pen, option_content, sizeof(guint32)); + if (section_info->byte_swapped) { + pen = GUINT32_SWAP_LE_BE(pen); + } + switch (pen) { + default: + ws_debug("Custom option type 0x%04x with unknown pen %u with custom data of length %u", option_code, pen, option_length - 4); + if (!pcap_process_generic_custom_option(wblock, option_code, option_length, pen, option_content)) { + return FALSE; + } + break; + } + return TRUE; +} + #ifdef HAVE_PLUGINS static gboolean pcapng_process_unhandled_option(wtapng_block_t *wblock, @@ -712,6 +765,19 @@ pcapng_process_options(FILE_T fh, wtapng_block_t *wblock, /* padding should be ok here, just get out of this */ opt_bytes_remaining = 0; break; + case(OPT_CUSTOM_STR_COPY): + case(OPT_CUSTOM_BIN_COPY): + case(OPT_CUSTOM_STR_NO_COPY): + case(OPT_CUSTOM_BIN_NO_COPY): + if (!pcapng_process_custom_option(wblock, section_info, + option_code, option_length, + option_ptr, + err, err_info)) { + g_free(option_content); + return FALSE; + } + break; + default: if (!(*process_option)(wblock, section_info, option_code, option_length, option_ptr, @@ -1553,6 +1619,8 @@ pcapng_read_packet_block(FILE_T fh, pcapng_block_header_t *bh, guint64 ts; int pseudo_header_len; int fcslen; + wtap_option_t option; + guint i; /* "(Enhanced) Packet Block" read fixed part */ if (enhanced) { @@ -1742,6 +1810,15 @@ pcapng_read_packet_block(FILE_T fh, pcapng_block_header_t *bh, g_ptr_array_free(wblock->rec->packet_verdict, TRUE); wblock->rec->packet_verdict = NULL; } + if (wblock->rec->custom_options != NULL) { + for (i = 0; i < wblock->rec->custom_options->len; i++) { + option = g_array_index(wblock->rec->custom_options, wtap_option_t, i); + g_free(option.value.custom_opt.custom_data); + option.value.custom_opt.custom_data = NULL; + } + g_array_free(wblock->rec->custom_options, TRUE); + wblock->rec->custom_options = NULL; + } /* FCS length default */ fcslen = iface_info.fcslen; @@ -1790,6 +1867,8 @@ pcapng_read_simple_packet_block(FILE_T fh, pcapng_block_header_t *bh, wtapng_simple_packet_t simple_packet; guint32 padding; int pseudo_header_len; + wtap_option_t option; + guint i; /* * Is this block long enough to be an SPB? @@ -1889,6 +1968,15 @@ pcapng_read_simple_packet_block(FILE_T fh, pcapng_block_header_t *bh, g_ptr_array_free(wblock->rec->packet_verdict, TRUE); wblock->rec->packet_verdict = NULL; } + if (wblock->rec->custom_options != NULL) { + for (i = 0; i < wblock->rec->custom_options->len; i++) { + option = g_array_index(wblock->rec->custom_options, wtap_option_t, i); + g_free(option.value.custom_opt.custom_data); + option.value.custom_opt.custom_data = NULL; + } + g_array_free(wblock->rec->custom_options, TRUE); + wblock->rec->custom_options = NULL; + } memset((void *)&wblock->rec->rec_header.packet_header.pseudo_header, 0, sizeof(union wtap_pseudo_header)); pseudo_header_len = pcap_process_pseudo_header(fh, @@ -3466,6 +3554,25 @@ static guint32 pcapng_compute_option_string_size(char *str) return size; } +static guint32 pcapng_compute_custom_option_size(size_t custom_data_len) +{ + size_t size, pad; + + size = custom_data_len + sizeof(guint32); + if (size > 65535) { + size = 65535; + } + if ((size % 4)) { + pad = 4 - (size % 4); + } else { + pad = 0; + } + + size += pad; + + return (guint32)size; +} + static void compute_shb_option_size(wtap_block_t block _U_, guint option_id, wtap_opttype_e option_type _U_, wtap_optval_t* optval, void* user_data) { pcapng_block_size_t* block_size = (pcapng_block_size_t*)user_data; @@ -3479,6 +3586,10 @@ static void compute_shb_option_size(wtap_block_t block _U_, guint option_id, wta case OPT_SHB_USERAPPL: size = pcapng_compute_option_string_size(optval->stringval); break; + case OPT_CUSTOM_STR_COPY: + case OPT_CUSTOM_BIN_COPY: + size = pcapng_compute_custom_option_size(optval->custom_opt.custom_data_len); + break; default: /* Unknown options - size by datatype? */ break; @@ -3504,6 +3615,59 @@ typedef struct pcapng_write_block_t } pcapng_write_block_t; +static gboolean pcapng_write_custom_option(wtap_dumper *wdh, guint option_id, custom_opt_t *custom_option, int *err) +{ + struct pcapng_option_header option_hdr; + const guint32 zero_pad = 0; + size_t pad; + + if ((option_id == OPT_CUSTOM_STR_NO_COPY) || + (option_id == OPT_CUSTOM_BIN_NO_COPY)) + return TRUE; + if (custom_option->custom_data_len + sizeof(guint32) > 65535) { + /* + * Too big to fit in the option. + * Don't write anything. + * + * XXX - truncate it? Report an error? + */ + return TRUE; + } + + /* write option header */ + option_hdr.type = (guint16)option_id; + option_hdr.value_length = (guint16)(custom_option->custom_data_len + sizeof(guint32)); + if (!wtap_dump_file_write(wdh, &option_hdr, sizeof(struct pcapng_option_header), err)) + return FALSE; + wdh->bytes_dumped += sizeof(struct pcapng_option_header); + + /* write PEN */ + if (!wtap_dump_file_write(wdh, &custom_option->pen, sizeof(guint32), err)) + return FALSE; + wdh->bytes_dumped += sizeof(guint32); + + /* write custom data */ + if (!wtap_dump_file_write(wdh, custom_option->custom_data, custom_option->custom_data_len, err)) + return FALSE; + wdh->bytes_dumped += custom_option->custom_data_len; + + /* write padding (if any) */ + if ((custom_option->custom_data_len % 4)) { + pad = 4 - (custom_option->custom_data_len % 4); + } else { + pad = 0; + } + if (pad != 0) { + if (!wtap_dump_file_write(wdh, &zero_pad, pad, err)) + return FALSE; + wdh->bytes_dumped += pad; + } + ws_debug("Wrote custom option: type %u, length %u", option_hdr.type, option_hdr.value_length); + + return TRUE; +} + + static gboolean pcapng_write_option_string(wtap_dumper *wdh, guint option_id, char *str, int *err) { struct pcapng_option_header option_hdr; @@ -3632,6 +3796,13 @@ static void write_wtap_shb_option(wtap_block_t block _U_, guint option_id, wtap_ return; } break; + case OPT_CUSTOM_STR_COPY: + case OPT_CUSTOM_BIN_COPY: + if (!pcapng_write_custom_option(write_block->wdh, option_id, &optval->custom_opt, write_block->err)) { + write_block->success = FALSE; + return; + } + break; default: /* Unknown options - write by datatype? */ break; @@ -3768,6 +3939,18 @@ pcapng_write_enhanced_packet_block(wtap_dumper *wdh, const wtap_rec *rec, } options_total_length = options_total_length + comment_len + comment_pad_len + 4 /* comment options tag */ ; } + if (rec->custom_options != NULL) { + have_options = TRUE; + for (guint i = 0; i < rec->custom_options->len; i++) { + wtap_option_t option; + + option = g_array_index(rec->custom_options, wtap_option_t, i); + if ((option.option_id == OPT_CUSTOM_STR_COPY) || + (option.option_id == OPT_CUSTOM_BIN_COPY)) { + options_total_length += pcapng_compute_custom_option_size(option.value.custom_opt.custom_data_len) + 4; + } + } + } if (rec->presence_flags & WTAP_HAS_PACK_FLAGS) { have_options = TRUE; options_total_length = options_total_length + 8; @@ -3877,53 +4060,56 @@ pcapng_write_enhanced_packet_block(wtap_dumper *wdh, const wtap_rec *rec, /* XXX - write (optional) block options */ /* options defined in Section 2.5 (Options) - * Name Code Length Description - * opt_comment 1 variable A UTF-8 string containing a comment that is associated to the current block. - * + * Name Code Length Description + * opt_comment 1 variable A UTF-8 string containing a comment that is associated to the current block. + * opt_custom 2988 variable A UTF-8 string which can be copied. + * opt_custom 2989 variable Binary octets which can be copied. + * opt_custom 19372 variable A UTF-8 string which should not be copied. + * opt_custom 19373 variable Binary octets which should not be copied. * Enhanced Packet Block options - * epb_flags 2 4 A flags word containing link-layer information. A complete specification of - * the allowed flags can be found in Appendix A (Packet Block Flags Word). - * epb_hash 3 variable This option contains a hash of the packet. The first byte specifies the hashing algorithm, - * while the following bytes contain the actual hash, whose size depends on the hashing algorithm, - * and hence from the value in the first bit. The hashing algorithm can be: 2s complement - * (algorithm byte = 0, size=XXX), XOR (algorithm byte = 1, size=XXX), CRC32 (algorithm byte = 2, size = 4), - * MD-5 (algorithm byte = 3, size=XXX), SHA-1 (algorithm byte = 4, size=XXX). - * The hash covers only the packet, not the header added by the capture driver: - * this gives the possibility to calculate it inside the network card. - * The hash allows easier comparison/merging of different capture files, and reliable data transfer between the - * data acquisition system and the capture library. - * epb_dropcount 4 8 A 64bit integer value specifying the number of packets lost (by the interface and the operating system) - * between this packet and the preceding one. - * epb_packetid 5 8 The epb_packetid option is a 64-bit unsigned integer that - * uniquely identifies the packet. If the same packet is seen - * by multiple interfaces and there is a way for the capture - * application to correlate them, the same epb_packetid value - * must be used. An example could be a router that captures - * packets on all its interfaces in both directions. When a - * packet hits interface A on ingress, an EPB entry gets - * created, TTL gets decremented, and right before it egresses - * on interface B another EPB entry gets created in the trace - * file. In this case, two packets are in the capture file, - * which are not identical but the epb_packetid can be used to - * correlate them. - * epb_queue 6 4 The epb_queue option is a 32-bit unsigned integer that - * identifies on which queue of the interface the specific - * packet was received. - * epb_verdict 7 variable The epb_verdict option stores a verdict of the packet. The - * verdict indicates what would be done with the packet after - * processing it. For example, a firewall could drop the - * packet. This verdict can be set by various components, i.e. - * Hardware, Linux's eBPF TC or XDP framework, etc. etc. The - * first octet specifies the verdict type, while the following - * octets contain the actual verdict data, whose size depends on - * the verdict type, and hence from the value in the first - * octet. The verdict type can be: Hardware (type octet = 0, - * size = variable), Linux_eBPF_TC (type octet = 1, size = 8 - * (64-bit unsigned integer), value = TC_ACT_* as defined in the - * Linux pck_cls.h include), Linux_eBPF_XDP (type octet = 2, - * size = 8 (64-bit unsigned integer), value = xdp_action as - * defined in the Linux pbf.h include). - * opt_endofopt 0 0 It delimits the end of the optional fields. This block cannot be repeated within a given list of options. + * epb_flags 2 4 A flags word containing link-layer information. A complete specification of + * the allowed flags can be found in Appendix A (Packet Block Flags Word). + * epb_hash 3 variable This option contains a hash of the packet. The first byte specifies the hashing algorithm, + * while the following bytes contain the actual hash, whose size depends on the hashing algorithm, + * and hence from the value in the first bit. The hashing algorithm can be: 2s complement + * (algorithm byte = 0, size=XXX), XOR (algorithm byte = 1, size=XXX), CRC32 (algorithm byte = 2, size = 4), + * MD-5 (algorithm byte = 3, size=XXX), SHA-1 (algorithm byte = 4, size=XXX). + * The hash covers only the packet, not the header added by the capture driver: + * this gives the possibility to calculate it inside the network card. + * The hash allows easier comparison/merging of different capture files, and reliable data transfer between the + * data acquisition system and the capture library. + * epb_dropcount 4 8 A 64bit integer value specifying the number of packets lost (by the interface and the operating system) + * between this packet and the preceding one. + * epb_packetid 5 8 The epb_packetid option is a 64-bit unsigned integer that + * uniquely identifies the packet. If the same packet is seen + * by multiple interfaces and there is a way for the capture + * application to correlate them, the same epb_packetid value + * must be used. An example could be a router that captures + * packets on all its interfaces in both directions. When a + * packet hits interface A on ingress, an EPB entry gets + * created, TTL gets decremented, and right before it egresses + * on interface B another EPB entry gets created in the trace + * file. In this case, two packets are in the capture file, + * which are not identical but the epb_packetid can be used to + * correlate them. + * epb_queue 6 4 The epb_queue option is a 32-bit unsigned integer that + * identifies on which queue of the interface the specific + * packet was received. + * epb_verdict 7 variable The epb_verdict option stores a verdict of the packet. The + * verdict indicates what would be done with the packet after + * processing it. For example, a firewall could drop the + * packet. This verdict can be set by various components, i.e. + * Hardware, Linux's eBPF TC or XDP framework, etc. etc. The + * first octet specifies the verdict type, while the following + * octets contain the actual verdict data, whose size depends on + * the verdict type, and hence from the value in the first + * octet. The verdict type can be: Hardware (type octet = 0, + * size = variable), Linux_eBPF_TC (type octet = 1, size = 8 + * (64-bit unsigned integer), value = TC_ACT_* as defined in the + * Linux pck_cls.h include), Linux_eBPF_XDP (type octet = 2, + * size = 8 (64-bit unsigned integer), value = xdp_action as + * defined in the Linux pbf.h include). + * opt_endofopt 0 0 It delimits the end of the optional fields. This block cannot be repeated within a given list of options. */ if (rec->opt_comment) { option_hdr.type = OPT_COMMENT; @@ -3949,6 +4135,17 @@ pcapng_write_enhanced_packet_block(wtap_dumper *wdh, const wtap_rec *rec, ws_debug("Wrote Options comments: comment_len %u, comment_pad_len %u", comment_len, comment_pad_len); } + if (rec->custom_options != NULL) { + for (guint i = 0; i < rec->custom_options->len; i++) { + wtap_option_t option; + + option = g_array_index(rec->custom_options, wtap_option_t, i); + if ((option.option_id == OPT_CUSTOM_STR_COPY) || + (option.option_id == OPT_CUSTOM_BIN_COPY)) { + pcapng_write_custom_option(wdh, option.option_id, &option.value.custom_opt, err); + } + } + } if (rec->presence_flags & WTAP_HAS_PACK_FLAGS) { option_hdr.type = OPT_EPB_FLAGS; option_hdr.value_length = 4; @@ -4346,6 +4543,10 @@ compute_nrb_option_size(wtap_block_t block _U_, guint option_id, wtap_opttype_e case OPT_NS_DNSNAME: size = pcapng_compute_option_string_size(optval->stringval); break; + case OPT_CUSTOM_STR_COPY: + case OPT_CUSTOM_BIN_COPY: + size = pcapng_compute_custom_option_size(optval->custom_opt.custom_data_len); + break; case OPT_NS_DNSIP4ADDR: size = 4; break; @@ -4397,6 +4598,33 @@ put_nrb_option(wtap_block_t block _U_, guint option_id, wtap_opttype_e option_ty pad = 0; } + /* put padding (if any) */ + if (pad != 0) { + memset(*opt_ptrp, 0, pad); + *opt_ptrp += pad; + } + break; + case OPT_CUSTOM_STR_COPY: + case OPT_CUSTOM_BIN_COPY: + /* Custom options don't consider pad bytes part of the length */ + size = (guint32)(optval->custom_opt.custom_data_len + sizeof(guint32)) & 0xffff; + option_hdr.type = (guint16)option_id; + option_hdr.value_length = (guint16)size; + memcpy(*opt_ptrp, &option_hdr, 4); + *opt_ptrp += 4; + + memcpy(*opt_ptrp, &optval->custom_opt.pen, sizeof(guint32)); + *opt_ptrp += sizeof(guint32); + + memcpy(*opt_ptrp, optval->custom_opt.custom_data, size); + *opt_ptrp += size; + + if ((size % 4)) { + pad = 4 - (size % 4); + } else { + pad = 0; + } + /* put padding (if any) */ if (pad != 0) { memset(*opt_ptrp, 0, pad); @@ -4726,6 +4954,10 @@ static void compute_isb_option_size(wtap_block_t block _U_, guint option_id, wta case OPT_COMMENT: size = pcapng_compute_option_string_size(optval->stringval); break; + case OPT_CUSTOM_STR_COPY: + case OPT_CUSTOM_BIN_COPY: + size = pcapng_compute_custom_option_size(optval->custom_opt.custom_data_len); + break; case OPT_ISB_STARTTIME: case OPT_ISB_ENDTIME: size = 8; @@ -4770,6 +5002,13 @@ static void write_wtap_isb_option(wtap_block_t block _U_, guint option_id, wtap_ return; } break; + case OPT_CUSTOM_STR_COPY: + case OPT_CUSTOM_BIN_COPY: + if (!pcapng_write_custom_option(write_block->wdh, option_id, &optval->custom_opt, write_block->err)) { + write_block->success = FALSE; + return; + } + break; case OPT_ISB_STARTTIME: case OPT_ISB_ENDTIME: if (!pcapng_write_option_timestamp(write_block->wdh, option_id, optval->uint64val, write_block->err)) { @@ -4872,6 +5111,10 @@ static void compute_idb_option_size(wtap_block_t block _U_, guint option_id, wta case OPT_IDB_HARDWARE: size = pcapng_compute_option_string_size(optval->stringval); break; + case OPT_CUSTOM_STR_COPY: + case OPT_CUSTOM_BIN_COPY: + size = pcapng_compute_custom_option_size(optval->custom_opt.custom_data_len); + break; case OPT_IDB_SPEED: size = 8; break; @@ -4936,6 +5179,13 @@ static void write_wtap_idb_option(wtap_block_t block _U_, guint option_id, wtap_ return; } break; + case OPT_CUSTOM_STR_COPY: + case OPT_CUSTOM_BIN_COPY: + if (!pcapng_write_custom_option(write_block->wdh, option_id, &optval->custom_opt, write_block->err)) { + write_block->success = FALSE; + return; + } + break; case OPT_IDB_SPEED: if (!pcapng_write_option_uint64(write_block->wdh, option_id, optval->uint64val, write_block->err)) { write_block->success = FALSE; @@ -5377,6 +5627,10 @@ gboolean pcapng_encap_is_ft_specific(int encap) /* Options for section blocks. */ static const struct supported_option_type section_block_options_supported[] = { { OPT_COMMENT, MULTIPLE_OPTIONS_SUPPORTED }, + { OPT_CUSTOM_STR_COPY, MULTIPLE_OPTIONS_SUPPORTED }, + { OPT_CUSTOM_BIN_COPY, MULTIPLE_OPTIONS_SUPPORTED }, + { OPT_CUSTOM_STR_NO_COPY, MULTIPLE_OPTIONS_SUPPORTED }, + { OPT_CUSTOM_BIN_NO_COPY, MULTIPLE_OPTIONS_SUPPORTED }, { OPT_SHB_HARDWARE, ONE_OPTION_SUPPORTED }, { OPT_SHB_USERAPPL, ONE_OPTION_SUPPORTED } }; @@ -5384,6 +5638,10 @@ static const struct supported_option_type section_block_options_supported[] = { /* Options for interface blocks. */ static const struct supported_option_type interface_block_options_supported[] = { { OPT_COMMENT, MULTIPLE_OPTIONS_SUPPORTED }, + { OPT_CUSTOM_STR_COPY, MULTIPLE_OPTIONS_SUPPORTED }, + { OPT_CUSTOM_BIN_COPY, MULTIPLE_OPTIONS_SUPPORTED }, + { OPT_CUSTOM_STR_NO_COPY, MULTIPLE_OPTIONS_SUPPORTED }, + { OPT_CUSTOM_BIN_NO_COPY, MULTIPLE_OPTIONS_SUPPORTED }, { OPT_IDB_NAME, ONE_OPTION_SUPPORTED }, { OPT_IDB_DESCR, ONE_OPTION_SUPPORTED }, { OPT_IDB_IP4ADDR, MULTIPLE_OPTIONS_SUPPORTED }, @@ -5403,6 +5661,10 @@ static const struct supported_option_type interface_block_options_supported[] = /* Options for name resolution blocks. */ static const struct supported_option_type name_resolution_block_options_supported[] = { { OPT_COMMENT, MULTIPLE_OPTIONS_SUPPORTED }, + { OPT_CUSTOM_STR_COPY, MULTIPLE_OPTIONS_SUPPORTED }, + { OPT_CUSTOM_BIN_COPY, MULTIPLE_OPTIONS_SUPPORTED }, + { OPT_CUSTOM_STR_NO_COPY, MULTIPLE_OPTIONS_SUPPORTED }, + { OPT_CUSTOM_BIN_NO_COPY, MULTIPLE_OPTIONS_SUPPORTED }, { OPT_NS_DNSNAME, ONE_OPTION_SUPPORTED }, { OPT_NS_DNSIP4ADDR, ONE_OPTION_SUPPORTED }, { OPT_NS_DNSIP6ADDR, ONE_OPTION_SUPPORTED } @@ -5411,6 +5673,10 @@ static const struct supported_option_type name_resolution_block_options_supporte /* Options for interface statistics blocks. */ static const struct supported_option_type interface_statistics_block_options_supported[] = { { OPT_COMMENT, MULTIPLE_OPTIONS_SUPPORTED }, + { OPT_CUSTOM_STR_COPY, MULTIPLE_OPTIONS_SUPPORTED }, + { OPT_CUSTOM_BIN_COPY, MULTIPLE_OPTIONS_SUPPORTED }, + { OPT_CUSTOM_STR_NO_COPY, MULTIPLE_OPTIONS_SUPPORTED }, + { OPT_CUSTOM_BIN_NO_COPY, MULTIPLE_OPTIONS_SUPPORTED }, { OPT_ISB_STARTTIME, ONE_OPTION_SUPPORTED }, { OPT_ISB_ENDTIME, ONE_OPTION_SUPPORTED }, { OPT_ISB_IFRECV, ONE_OPTION_SUPPORTED }, @@ -5422,28 +5688,48 @@ static const struct supported_option_type interface_statistics_block_options_sup /* Options for decryption secrets blocks. */ static const struct supported_option_type decryption_secrets_block_options_supported[] = { - { OPT_COMMENT, MULTIPLE_OPTIONS_SUPPORTED } + { OPT_COMMENT, MULTIPLE_OPTIONS_SUPPORTED }, + { OPT_CUSTOM_STR_COPY, MULTIPLE_OPTIONS_SUPPORTED }, + { OPT_CUSTOM_BIN_COPY, MULTIPLE_OPTIONS_SUPPORTED }, + { OPT_CUSTOM_STR_NO_COPY, MULTIPLE_OPTIONS_SUPPORTED }, + { OPT_CUSTOM_BIN_NO_COPY, MULTIPLE_OPTIONS_SUPPORTED } }; /* Options for packet blocks. */ static const struct supported_option_type packet_block_options_supported[] = { /* XXX - pending use of wtap_block_t's for packets */ - { OPT_COMMENT, MULTIPLE_OPTIONS_SUPPORTED } + { OPT_COMMENT, MULTIPLE_OPTIONS_SUPPORTED }, + { OPT_CUSTOM_STR_COPY, MULTIPLE_OPTIONS_SUPPORTED }, + { OPT_CUSTOM_BIN_COPY, MULTIPLE_OPTIONS_SUPPORTED }, + { OPT_CUSTOM_STR_NO_COPY, MULTIPLE_OPTIONS_SUPPORTED }, + { OPT_CUSTOM_BIN_NO_COPY, MULTIPLE_OPTIONS_SUPPORTED } }; /* Options for file-type-sepcific reports. */ static const struct supported_option_type ft_specific_report_block_options_supported[] = { - { OPT_COMMENT, MULTIPLE_OPTIONS_SUPPORTED } + { OPT_COMMENT, MULTIPLE_OPTIONS_SUPPORTED }, + { OPT_CUSTOM_STR_COPY, MULTIPLE_OPTIONS_SUPPORTED }, + { OPT_CUSTOM_BIN_COPY, MULTIPLE_OPTIONS_SUPPORTED }, + { OPT_CUSTOM_STR_NO_COPY, MULTIPLE_OPTIONS_SUPPORTED }, + { OPT_CUSTOM_BIN_NO_COPY, MULTIPLE_OPTIONS_SUPPORTED } }; /* Options for file-type-sepcific event. */ static const struct supported_option_type ft_specific_event_block_options_supported[] = { - { OPT_COMMENT, MULTIPLE_OPTIONS_SUPPORTED } + { OPT_COMMENT, MULTIPLE_OPTIONS_SUPPORTED }, + { OPT_CUSTOM_STR_COPY, MULTIPLE_OPTIONS_SUPPORTED }, + { OPT_CUSTOM_BIN_COPY, MULTIPLE_OPTIONS_SUPPORTED }, + { OPT_CUSTOM_STR_NO_COPY, MULTIPLE_OPTIONS_SUPPORTED }, + { OPT_CUSTOM_BIN_NO_COPY, MULTIPLE_OPTIONS_SUPPORTED } }; /* Options for systemd journal entry. */ static const struct supported_option_type systemd_journal_export_block_options_supported[] = { - { OPT_COMMENT, MULTIPLE_OPTIONS_SUPPORTED } + { OPT_COMMENT, MULTIPLE_OPTIONS_SUPPORTED }, + { OPT_CUSTOM_STR_COPY, MULTIPLE_OPTIONS_SUPPORTED }, + { OPT_CUSTOM_BIN_COPY, MULTIPLE_OPTIONS_SUPPORTED }, + { OPT_CUSTOM_STR_NO_COPY, MULTIPLE_OPTIONS_SUPPORTED }, + { OPT_CUSTOM_BIN_NO_COPY, MULTIPLE_OPTIONS_SUPPORTED } }; static const struct supported_block_type pcapng_blocks_supported[] = { diff --git a/wiretap/wtap.c b/wiretap/wtap.c index a0bc68e0fb..51e1e7547a 100644 --- a/wiretap/wtap.c +++ b/wiretap/wtap.c @@ -1664,6 +1664,9 @@ wtap_rec_init(wtap_rec *rec) void wtap_rec_cleanup(wtap_rec *rec) { + wtap_option_t option; + guint i; + g_free(rec->opt_comment); rec->opt_comment = NULL; ws_buffer_free(&rec->options_buf); @@ -1671,6 +1674,15 @@ wtap_rec_cleanup(wtap_rec *rec) g_ptr_array_free(rec->packet_verdict, TRUE); rec->packet_verdict = NULL; } + if (rec->custom_options != NULL) { + for (i = 0; i < rec->custom_options->len; i++) { + option = g_array_index(rec->custom_options, wtap_option_t, i); + g_free(option.value.custom_opt.custom_data); + option.value.custom_opt.custom_data = NULL; + } + g_array_free(rec->custom_options, TRUE); + rec->custom_options = NULL; + } } gboolean diff --git a/wiretap/wtap.h b/wiretap/wtap.h index afb99ff37d..fd0e548ab8 100644 --- a/wiretap/wtap.h +++ b/wiretap/wtap.h @@ -1352,6 +1352,7 @@ typedef struct { but due to the way the current code is reusing the wtap_rec structure, it's impossible to nicely clean it up. */ + GArray *custom_options; /* Array of generic custom options of EPBs */ /* * We use a Buffer so that we don't have to allocate and free * a buffer for the options for each record. diff --git a/wiretap/wtap_opttypes.c b/wiretap/wtap_opttypes.c index 6c8c0ff5ab..65c83e054c 100644 --- a/wiretap/wtap_opttypes.c +++ b/wiretap/wtap_opttypes.c @@ -117,6 +117,12 @@ static void wtap_opttype_block_register(wtap_blocktype_t *blocktype) WTAP_OPTTYPE_STRING, WTAP_OPTTYPE_FLAG_MULTIPLE_ALLOWED }; + static const wtap_opttype_t opt_custom = { + "opt_custom", + "Custom Option", + WTAP_OPTTYPE_CUSTOM, + WTAP_OPTTYPE_FLAG_MULTIPLE_ALLOWED + }; block_type = blocktype->block_type; @@ -133,7 +139,8 @@ static void wtap_opttype_block_register(wtap_blocktype_t *blocktype) /* * Initialize the set of supported options. - * All blocks that support options at all support OPT_COMMENT. + * All blocks that support options at all support + * OPT_COMMENT and OPT_CUSTOM. * * XXX - there's no "g_uint_hash()" or "g_uint_equal()", * so we use "g_direct_hash()" and "g_direct_equal()". @@ -141,6 +148,14 @@ static void wtap_opttype_block_register(wtap_blocktype_t *blocktype) blocktype->options = g_hash_table_new(g_direct_hash, g_direct_equal); g_hash_table_insert(blocktype->options, GUINT_TO_POINTER(OPT_COMMENT), (gpointer)&opt_comment); + g_hash_table_insert(blocktype->options, GUINT_TO_POINTER(OPT_CUSTOM_STR_COPY), + (gpointer)&opt_custom); + g_hash_table_insert(blocktype->options, GUINT_TO_POINTER(OPT_CUSTOM_BIN_COPY), + (gpointer)&opt_custom); + g_hash_table_insert(blocktype->options, GUINT_TO_POINTER(OPT_CUSTOM_STR_NO_COPY), + (gpointer)&opt_custom); + g_hash_table_insert(blocktype->options, GUINT_TO_POINTER(OPT_CUSTOM_BIN_NO_COPY), + (gpointer)&opt_custom); blocktype_list[block_type] = blocktype; } @@ -226,6 +241,10 @@ static void wtap_block_free_option(wtap_block_t block, wtap_option_t *opt) if_filter_free(&opt->value.if_filterval); break; + case WTAP_OPTTYPE_CUSTOM: + g_free(opt->value.custom_opt.custom_data); + break; + default: break; } @@ -318,6 +337,10 @@ wtap_block_copy(wtap_block_t dest_block, wtap_block_t src_block) case WTAP_OPTTYPE_IF_FILTER: wtap_block_add_if_filter_option(dest_block, src_opt->option_id, &src_opt->value.if_filterval); break; + + case WTAP_OPTTYPE_CUSTOM: + wtap_block_add_custom_option(dest_block, src_opt->option_id, src_opt->value.custom_opt.pen, src_opt->value.custom_opt.custom_data, src_opt->value.custom_opt.custom_data_len); + break; } } } @@ -828,6 +851,21 @@ wtap_block_get_if_filter_option_value(wtap_block_t block, guint option_id, if_fi return WTAP_OPTTYPE_SUCCESS; } +wtap_opttype_return_val +wtap_block_add_custom_option(wtap_block_t block, guint option_id, guint32 pen, const char *custom_data, gsize custom_data_len) +{ + wtap_opttype_return_val ret; + wtap_option_t *opt; + + ret = wtap_block_add_option_common(block, option_id, WTAP_OPTTYPE_CUSTOM, &opt); + if (ret != WTAP_OPTTYPE_SUCCESS) + return ret; + opt->value.custom_opt.pen = pen; + opt->value.custom_opt.custom_data_len = custom_data_len; + opt->value.custom_opt.custom_data = g_memdup2(custom_data, custom_data_len); + return WTAP_OPTTYPE_SUCCESS; +} + wtap_opttype_return_val wtap_block_remove_option(wtap_block_t block, guint option_id) { diff --git a/wiretap/wtap_opttypes.h b/wiretap/wtap_opttypes.h index 2f21f9c1d1..0a1ac09f2b 100644 --- a/wiretap/wtap_opttypes.h +++ b/wiretap/wtap_opttypes.h @@ -23,90 +23,94 @@ extern "C" { */ /* Options for all blocks */ -#define OPT_EOFOPT 0 /**< Appears in pcapng files, but not in blocks. */ -#define OPT_COMMENT 1 /**< A UTF-8 string containing a human-readable comment. */ - +#define OPT_EOFOPT 0 /**< Appears in pcapng files, but not in blocks. */ +#define OPT_COMMENT 1 /**< A UTF-8 string containing a human-readable comment. */ +#define OPT_CUSTOM_STR_COPY 2988 /**< A custom option containing a string, copying allowed. */ +#define OPT_CUSTOM_BIN_COPY 2989 /**< A custom option containing binary data, copying allowed. */ +#define OPT_CUSTOM_STR_NO_COPY 19372 /**< A custom option containing binary data, copying not allowed. */ +#define OPT_CUSTOM_BIN_NO_COPY 19373 /**< A custom option containing binary data, copying not allowed. */ /* Section Header block (SHB) */ -#define OPT_SHB_HARDWARE 2 /**< A UTF-8 string containing the description of the - * hardware used to create this section. - */ -#define OPT_SHB_OS 3 /**< A UTF-8 string containing the - * name of the operating system used to create this section. - */ -#define OPT_SHB_USERAPPL 4 /**< A UTF-8 string containing the - * name of the application used to create this section. - */ +#define OPT_SHB_HARDWARE 2 /**< A UTF-8 string containing the description of the + * hardware used to create this section. + */ +#define OPT_SHB_OS 3 /**< A UTF-8 string containing the + * name of the operating system used to create this section. + */ +#define OPT_SHB_USERAPPL 4 /**< A UTF-8 string containing the + * name of the application used to create this section. + */ /* Interface Description block (IDB) */ -#define OPT_IDB_NAME 2 /**< A UTF-8 string containing the name - * of the device used to capture data. - * "eth0" / "\Device\NPF_{AD1CE675-96D0-47C5-ADD0-2504B9126B68}" - */ -#define OPT_IDB_DESCR 3 /**< A UTF-8 string containing the description - * of the device used to capture data. - * "Wi-Fi" / "Local Area Connection" / - * "Wireless Network Connection" / - * "First Ethernet Interface" - */ -#define OPT_IDB_IP4ADDR 4 /**< XXX: if_IPv4addr Interface network address and netmask. - * This option can be repeated multiple times within the same Interface Description Block - * when multiple IPv4 addresses are assigned to the interface. - * 192 168 1 1 255 255 255 0 - */ -#define OPT_IDB_IP6ADDR 5 /* XXX: if_IPv6addr Interface network address and prefix length (stored in the last byte). - * This option can be repeated multiple times within the same Interface - * Description Block when multiple IPv6 addresses are assigned to the interface. - * 2001:0db8:85a3:08d3:1319:8a2e:0370:7344/64 is written (in hex) as - * "20 01 0d b8 85 a3 08 d3 13 19 8a 2e 03 70 73 44 40"*/ -#define OPT_IDB_MACADDR 6 /* XXX: if_MACaddr Interface Hardware MAC address (48 bits). */ -#define OPT_IDB_EUIADDR 7 /* XXX: if_EUIaddr Interface Hardware EUI address (64 bits) */ -#define OPT_IDB_SPEED 8 /**< Interface speed (in bps). 100000000 for 100Mbps - */ -#define OPT_IDB_TSRESOL 9 /**< Resolution of timestamps. If the Most Significant Bit is equal to zero, - * the remaining bits indicates the resolution of the timestamp as as a - * negative power of 10 (e.g. 6 means microsecond resolution, timestamps - * are the number of microseconds since 1/1/1970). If the Most Significant Bit - * is equal to one, the remaining bits indicates the resolution has a - * negative power of 2 (e.g. 10 means 1/1024 of second). - * If this option is not present, a resolution of 10^-6 is assumed - * (i.e. timestamps have the same resolution of the standard 'libpcap' timestamps). - */ -#define OPT_IDB_TZONE 10 /* XXX: if_tzone Time zone for GMT support (TODO: specify better). */ -#define OPT_IDB_FILTER 11 /**< The filter (e.g. "capture only TCP traffic") used to capture traffic. - * The first byte of the Option Data keeps a code of the filter used - * (e.g. if this is a libpcap string, or BPF bytecode, and more). - * More details about this format will be presented in Appendix XXX (TODO). - * (TODO: better use different options for different fields? - * e.g. if_filter_pcap, if_filter_bpf, ...) 00 "tcp port 23 and host 10.0.0.5" - */ -#define OPT_IDB_OS 12 /**< A UTF-8 string containing the name of the operating system of the - * machine in which this interface is installed. - * This can be different from the same information that can be - * contained by the Section Header Block - * (Section 3.1 (Section Header Block (mandatory))) because - * the capture can have been done on a remote machine. - * "Windows XP SP2" / "openSUSE 10.2" - */ -#define OPT_IDB_FCSLEN 13 /**< An integer value that specified the length of the - * Frame Check Sequence (in bits) for this interface. - * For link layers whose FCS length can change during time, - * the Packet Block Flags Word can be used (see Appendix A (Packet Block Flags Word)) - */ -#define OPT_IDB_TSOFFSET 14 /**< XXX: A 64 bits integer value that specifies an offset (in seconds) - * that must be added to the timestamp of each packet to obtain - * the absolute timestamp of a packet. If the option is missing, - * the timestamps stored in the packet must be considered absolute - * timestamps. The time zone of the offset can be specified with the - * option if_tzone. TODO: won't a if_tsoffset_low for fractional - * second offsets be useful for highly synchronized capture systems? - */ -#define OPT_IDB_HARDWARE 15 /**< A UTF-8 string containing the description - * of the hardware of the device used - * to capture data. - * "Broadcom NetXtreme" / - * "Intel(R) PRO/1000 MT Network Connection" / - * "NETGEAR WNA1000Mv2 N150 Wireless USB Micro Adapter" - */ +#define OPT_IDB_NAME 2 /**< A UTF-8 string containing the name + * of the device used to capture data. + * "eth0" / "\Device\NPF_{AD1CE675-96D0-47C5-ADD0-2504B9126B68}" + */ +#define OPT_IDB_DESCR 3 /**< A UTF-8 string containing the description + * of the device used to capture data. + * "Wi-Fi" / "Local Area Connection" / + * "Wireless Network Connection" / + * "First Ethernet Interface" + */ +#define OPT_IDB_IP4ADDR 4 /**< XXX: if_IPv4addr Interface network address and netmask. + * This option can be repeated multiple times within the same Interface Description Block + * when multiple IPv4 addresses are assigned to the interface. + * 192 168 1 1 255 255 255 0 + */ +#define OPT_IDB_IP6ADDR 5 /**< XXX: if_IPv6addr Interface network address and prefix length (stored in the last byte). + * This option can be repeated multiple times within the same Interface + * Description Block when multiple IPv6 addresses are assigned to the interface. + * 2001:0db8:85a3:08d3:1319:8a2e:0370:7344/64 is written (in hex) as + * "20 01 0d b8 85 a3 08 d3 13 19 8a 2e 03 70 73 44 40" + */ +#define OPT_IDB_MACADDR 6 /**< XXX: if_MACaddr Interface Hardware MAC address (48 bits). */ +#define OPT_IDB_EUIADDR 7 /**< XXX: if_EUIaddr Interface Hardware EUI address (64 bits) */ +#define OPT_IDB_SPEED 8 /**< Interface speed (in bps). 100000000 for 100Mbps + */ +#define OPT_IDB_TSRESOL 9 /**< Resolution of timestamps. If the Most Significant Bit is equal to zero, + * the remaining bits indicates the resolution of the timestamp as as a + * negative power of 10 (e.g. 6 means microsecond resolution, timestamps + * are the number of microseconds since 1/1/1970). If the Most Significant Bit + * is equal to one, the remaining bits indicates the resolution has a + * negative power of 2 (e.g. 10 means 1/1024 of second). + * If this option is not present, a resolution of 10^-6 is assumed + * (i.e. timestamps have the same resolution of the standard 'libpcap' timestamps). + */ +#define OPT_IDB_TZONE 10 /**< XXX: if_tzone Time zone for GMT support (TODO: specify better). */ +#define OPT_IDB_FILTER 11 /**< The filter (e.g. "capture only TCP traffic") used to capture traffic. + * The first byte of the Option Data keeps a code of the filter used + * (e.g. if this is a libpcap string, or BPF bytecode, and more). + * More details about this format will be presented in Appendix XXX (TODO). + * (TODO: better use different options for different fields? + * e.g. if_filter_pcap, if_filter_bpf, ...) 00 "tcp port 23 and host 10.0.0.5" + */ +#define OPT_IDB_OS 12 /**< A UTF-8 string containing the name of the operating system of the + * machine in which this interface is installed. + * This can be different from the same information that can be + * contained by the Section Header Block + * (Section 3.1 (Section Header Block (mandatory))) because + * the capture can have been done on a remote machine. + * "Windows XP SP2" / "openSUSE 10.2" + */ +#define OPT_IDB_FCSLEN 13 /**< An integer value that specified the length of the + * Frame Check Sequence (in bits) for this interface. + * For link layers whose FCS length can change during time, + * the Packet Block Flags Word can be used (see Appendix A (Packet Block Flags Word)) + */ +#define OPT_IDB_TSOFFSET 14 /**< XXX: A 64 bits integer value that specifies an offset (in seconds) + * that must be added to the timestamp of each packet to obtain + * the absolute timestamp of a packet. If the option is missing, + * the timestamps stored in the packet must be considered absolute + * timestamps. The time zone of the offset can be specified with the + * option if_tzone. TODO: won't a if_tsoffset_low for fractional + * second offsets be useful for highly synchronized capture systems? + */ +#define OPT_IDB_HARDWARE 15 /**< A UTF-8 string containing the description + * of the hardware of the device used + * to capture data. + * "Broadcom NetXtreme" / + * "Intel(R) PRO/1000 MT Network Connection" / + * "NETGEAR WNA1000Mv2 N150 Wireless USB Micro Adapter" + */ #define OPT_NS_DNSNAME 2 @@ -241,7 +245,8 @@ typedef enum { WTAP_OPTTYPE_STRING, WTAP_OPTTYPE_IPv4, WTAP_OPTTYPE_IPv6, - WTAP_OPTTYPE_IF_FILTER + WTAP_OPTTYPE_IF_FILTER, + WTAP_OPTTYPE_CUSTOM } wtap_opttype_e; typedef enum { @@ -282,6 +287,16 @@ typedef struct if_filter_opt_s { } data; } if_filter_opt_t; +/* + * Structure describing a custom option. + */ + +typedef struct custom_opt_s { + guint32 pen; + gsize custom_data_len; + gchar *custom_data; +} custom_opt_t; + /* * Structure describing a value of an option. */ @@ -292,6 +307,7 @@ typedef union { ws_in6_addr ipv6val; char *stringval; if_filter_opt_t if_filterval; + custom_opt_t custom_opt; } wtap_optval_t; /* @@ -620,6 +636,19 @@ wtap_block_set_if_filter_option_value(wtap_block_t block, guint option_id, if_fi WS_DLL_PUBLIC wtap_opttype_return_val wtap_block_get_if_filter_option_value(wtap_block_t block, guint option_id, if_filter_opt_t* value) G_GNUC_WARN_UNUSED_RESULT; +/** Add an custom option to a block + * + * @param[in] block Block to which to add the option + * @param[in] option_id Identifier value for option + * @param[in] pen PEN + * @param[in] custom_data pointer to the data + * @param[in] custom_data_len length of custom_data + * @return wtap_opttype_return_val - WTAP_OPTTYPE_SUCCESS if successful, + * error code otherwise + */ +WS_DLL_PUBLIC wtap_opttype_return_val +wtap_block_add_custom_option(wtap_block_t block, guint option_id, guint32 pen, const char *custom_data, gsize custom_data_len); + /** Remove an option from a block * * @param[in] block Block from which to remove the option