summaryrefslogtreecommitdiffstats
path: root/lib/libpcap/libpcap/pcapng.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libpcap/libpcap/pcapng.c')
-rw-r--r--lib/libpcap/libpcap/pcapng.c1405
1 files changed, 1405 insertions, 0 deletions
diff --git a/lib/libpcap/libpcap/pcapng.c b/lib/libpcap/libpcap/pcapng.c
new file mode 100644
index 0000000..1f1dfd0
--- /dev/null
+++ b/lib/libpcap/libpcap/pcapng.c
@@ -0,0 +1,1405 @@
+/*
+ * Copyright (c) 2012-2015 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <err.h>
+#include <sysexits.h>
+#include <unistd.h>
+#include <sys/uio.h>
+#include "pcapng-private.h"
+
+#include "pcap-int.h"
+#include "pcap-common.h"
+#include "sf-pcapng.h"
+#include "pcap-util.h"
+
+/*
+ * Block cursor - used when processing the contents of a block.
+ * Contains a pointer into the data being processed and a count
+ * of bytes remaining in the block.
+ */
+struct block_cursor {
+ u_char *data;
+ size_t data_remaining;
+ bpf_u_int32 block_type;
+};
+
+
+#define PAD_32BIT(x) ((x + 3) & ~3)
+#define PAD_64BIT(x) ((x + 7) & ~7)
+#define PADDED_OPTION_LEN(x) ((x) ? PAD_32BIT(x) + sizeof(struct pcapng_option_header) : 0)
+
+
+void *
+pcap_ng_block_header_ptr(pcapng_block_t block)
+{
+ return (block->pcapng_bufptr);
+}
+
+void *
+pcap_ng_block_fields_ptr(pcapng_block_t block)
+{
+ return (block->pcapng_bufptr +
+ sizeof(struct pcapng_block_header));
+}
+
+void *
+pcap_ng_block_data_ptr(pcapng_block_t block)
+{
+ if (block->pcapng_data_is_external)
+ return (block->pcapng_data_ptr);
+ else
+ return (block->pcapng_bufptr +
+ sizeof(struct pcapng_block_header) +
+ block->pcapng_fields_len);
+}
+
+void *
+pcap_ng_block_records_ptr(pcapng_block_t block)
+{
+ if (block->pcapng_block_type != PCAPNG_BT_NRB)
+ return (NULL);
+
+ if (block->pcapng_data_is_external)
+ return (block->pcapng_bufptr +
+ sizeof(struct pcapng_block_header) +
+ block->pcapng_fields_len);
+ else
+ return (block->pcapng_bufptr +
+ sizeof(struct pcapng_block_header) +
+ block->pcapng_fields_len +
+ block->pcapng_data_len);
+}
+
+void *
+pcap_ng_block_options_ptr(pcapng_block_t block)
+{
+ if (block->pcapng_block_type == PCAPNG_BT_SPB)
+ return (NULL);
+
+ if (block->pcapng_data_is_external)
+ return (block->pcapng_bufptr +
+ sizeof(struct pcapng_block_header) +
+ block->pcapng_fields_len +
+ block->pcapng_records_len);
+ else
+ return (block->pcapng_bufptr +
+ sizeof(struct pcapng_block_header) +
+ block->pcapng_fields_len +
+ block->pcapng_data_len +
+ block->pcapng_records_len);
+}
+
+void *
+pcap_ng_block_trailer_ptr(pcapng_block_t block)
+{
+ if (block->pcapng_data_is_external)
+ return (block->pcapng_bufptr +
+ sizeof(struct pcapng_block_header) +
+ block->pcapng_fields_len +
+ block->pcapng_records_len +
+ block->pcapng_options_len);
+ else
+ return (block->pcapng_bufptr +
+ sizeof(struct pcapng_block_header) +
+ block->pcapng_fields_len +
+ block->pcapng_data_len +
+ block->pcapng_records_len +
+ block->pcapng_options_len);
+}
+
+pcapng_block_t
+pcap_ng_block_alloc(size_t len)
+{
+ size_t totallen;
+ u_char *ptr;
+ struct pcapng_block *block;
+
+ if (len > pcap_ng_block_size_max())
+ return (NULL);
+
+ /*
+ * The internal block structure is prepended
+ */
+ totallen = PAD_64BIT(sizeof(struct pcapng_block)) + len;
+ ptr = malloc(totallen);
+ if (ptr == NULL)
+ return (NULL);
+
+ block = (struct pcapng_block *)ptr;
+ bzero(block, sizeof(struct pcapng_block));
+
+ block->pcapng_bufptr = ptr + PAD_64BIT(sizeof(struct pcapng_block));
+ block->pcapng_buflen = len;
+
+ return (block);
+}
+
+size_t
+pcap_ng_block_size_max()
+{
+ return (2 * MAXIMUM_SNAPLEN);
+}
+
+void
+pcap_ng_free_block(pcapng_block_t block)
+{
+ free(block);
+}
+
+bpf_u_int32
+pcap_ng_block_get_type(pcapng_block_t block)
+{
+ return (block->pcapng_block_type);
+}
+
+bpf_u_int32
+pcap_ng_block_get_len(pcapng_block_t block)
+{
+ return ((bpf_u_int32)block->pcapng_block_len);
+}
+
+int
+pcap_ng_block_is_swapped(pcapng_block_t block)
+{
+ return (block->pcapng_block_swapped);
+}
+
+int
+pcapng_update_block_length(pcapng_block_t block)
+{
+ block->pcapng_block_len = sizeof(struct pcapng_block_header) +
+ block->pcapng_fields_len +
+ block->pcapng_data_len +
+ block->pcapng_records_len +
+ block->pcapng_options_len +
+ sizeof(struct pcapng_block_trailer);
+
+ if (block->pcapng_block_len > block->pcapng_buflen) {
+ errx(EX_SOFTWARE, "%s block len %lu greater than buffer size %lu",
+ __func__, block->pcapng_block_len, block->pcapng_buflen);
+ }
+
+ return (0);
+}
+
+int
+pcap_ng_block_reset(pcapng_block_t block, bpf_u_int32 type)
+{
+ bzero(&block->block_fields_, sizeof(block->block_fields_));
+
+ switch (type) {
+ case PCAPNG_BT_SHB:
+ block->pcapng_block_type = type;
+ block->pcapng_fields_len = sizeof(struct pcapng_section_header_fields);
+
+ block->pcap_ng_shb_fields.byte_order_magic = PCAPNG_BYTE_ORDER_MAGIC;
+ block->pcap_ng_shb_fields.major_version = PCAPNG_VERSION_MAJOR;
+ block->pcap_ng_shb_fields.minor_version = PCAPNG_VERSION_MINOR;
+ block->pcap_ng_shb_fields.section_length = (uint64_t)-1;
+ break;
+
+ case PCAPNG_BT_IDB:
+ block->pcapng_block_type = type;
+ block->pcapng_fields_len = sizeof(struct pcapng_interface_description_fields);
+ break;
+
+ case PCAPNG_BT_PB:
+ block->pcapng_block_type = type;
+ block->pcapng_fields_len = sizeof(struct pcapng_packet_fields);
+ break;
+
+ case PCAPNG_BT_SPB:
+ block->pcapng_block_type = type;
+ block->pcapng_fields_len = sizeof(struct pcapng_simple_packet_fields);
+ break;
+
+ case PCAPNG_BT_NRB:
+ block->pcapng_block_type = type;
+ block->pcapng_fields_len = 0;
+ break;
+
+ case PCAPNG_BT_ISB:
+ block->pcapng_block_type = type;
+ block->pcapng_fields_len = sizeof(struct pcapng_interface_statistics_fields);
+ break;
+
+ case PCAPNG_BT_EPB:
+ block->pcapng_block_type = type;
+ block->pcapng_fields_len = sizeof(struct pcapng_enhanced_packet_fields);
+ break;
+
+ case PCAPNG_BT_PIB:
+ block->pcapng_block_type = type;
+ block->pcapng_fields_len = sizeof(struct pcapng_process_information_fields);
+ break;
+
+ case PCAPNG_BT_OSEV:
+ block->pcapng_block_type = type;
+ block->pcapng_fields_len = sizeof(struct pcapng_os_event_fields);
+ break;
+
+ case PCAPNG_BT_DSB:
+ block->pcapng_block_type = PCAPNG_BT_DSB;
+ block->pcapng_fields_len = sizeof(struct pcapng_decryption_secrets_fields);
+ break;
+
+ default:
+ return (PCAP_ERROR);
+ }
+
+ block->pcapng_data_ptr = NULL;
+ block->pcapng_data_len = 0;
+ block->pcapng_cap_len = 0;
+ block->pcapng_data_is_external = 0;
+
+ block->pcapng_records_len = 0;
+
+ block->pcapng_options_len = 0;
+
+ pcapng_update_block_length(block);
+
+ return (0);
+}
+
+struct pcapng_section_header_fields *
+pcap_ng_get_section_header_fields(pcapng_block_t block)
+{
+ if (block != NULL && block->pcapng_block_type == PCAPNG_BT_SHB)
+ return &block->pcap_ng_shb_fields;
+ else
+ return NULL;
+}
+
+struct pcapng_interface_description_fields *
+pcap_ng_get_interface_description_fields(pcapng_block_t block)
+{
+ if (block != NULL && block->pcapng_block_type == PCAPNG_BT_IDB)
+ return &block->pcap_ng_idb_fields;
+ else
+ return NULL;
+}
+
+struct pcapng_enhanced_packet_fields *
+pcap_ng_get_enhanced_packet_fields(pcapng_block_t block)
+{
+ if (block != NULL && block->pcapng_block_type == PCAPNG_BT_EPB)
+ return &block->pcap_ng_epb_fields;
+ else
+ return NULL;
+}
+
+struct pcapng_simple_packet_fields *
+pcap_ng_get_simple_packet_fields(pcapng_block_t block)
+{
+ if (block != NULL && block->pcapng_block_type == PCAPNG_BT_SPB)
+ return &block->pcap_ng_spb_fields;
+ else
+ return NULL;
+}
+
+struct pcapng_packet_fields *
+pcap_ng_get_packet_fields(pcapng_block_t block)
+{
+ if (block != NULL && block->pcapng_block_type == PCAPNG_BT_PB)
+ return &block->pcap_ng_opb_fields;
+ else
+ return NULL;
+}
+
+struct pcapng_interface_statistics_fields *
+pcap_ng_get_interface_statistics_fields(pcapng_block_t block)
+{
+ if (block != NULL && block->pcapng_block_type == PCAPNG_BT_ISB)
+ return &block->pcap_ng_isb_fields;
+ else
+ return NULL;
+}
+
+struct pcapng_process_information_fields *
+pcap_ng_get_process_information_fields(pcapng_block_t block)
+{
+ if (block != NULL && block->pcapng_block_type == PCAPNG_BT_PIB)
+ return &block->pcap_ng_pib_fields;
+ else
+ return NULL;
+}
+
+struct pcapng_os_event_fields *
+pcap_ng_get_os_event_fields(pcapng_block_t block)
+{
+ if (block != NULL && block->pcapng_block_type == PCAPNG_BT_OSEV)
+ return &block->pcap_ng_osev_fields;
+ else
+ return NULL;
+}
+
+struct pcapng_decryption_secrets_fields *
+pcap_ng_get_decryption_secrets_fields(pcapng_block_t block)
+{
+ if (block != NULL && block->pcapng_block_type == PCAPNG_BT_DSB)
+ return &block->pcap_ng_dsb_fields;
+ else
+ return NULL;
+}
+
+int
+pcap_ng_block_does_support_data(pcapng_block_t block)
+{
+ switch (block->pcapng_block_type) {
+ case PCAPNG_BT_PB:
+ case PCAPNG_BT_SPB:
+ case PCAPNG_BT_EPB:
+ case PCAPNG_BT_OSEV:
+ case PCAPNG_BT_DSB:
+ return (1);
+ /* NOT REACHED */
+
+ default:
+ break;
+ }
+ return (0);
+}
+
+void *
+pcap_ng_block_packet_get_data_ptr(pcapng_block_t block)
+{
+ if (pcap_ng_block_does_support_data(block) == 0)
+ return (NULL);
+
+ return (block->pcapng_data_ptr);
+}
+
+bpf_u_int32
+pcap_ng_block_packet_get_data_len(pcapng_block_t block)
+{
+ if (pcap_ng_block_does_support_data(block) == 0)
+ return (0);
+
+ return (block->pcapng_cap_len);
+}
+
+bpf_u_int32
+pcap_ng_block_packet_copy_data(pcapng_block_t block, const void *ptr,
+ bpf_u_int32 caplen)
+{
+ bpf_u_int32 padding_len = PAD_32BIT(caplen) - caplen;
+
+ if (pcap_ng_block_does_support_data(block) == 0)
+ return (PCAP_ERROR);
+
+ if (block->pcapng_block_len + PAD_32BIT(caplen) > block->pcapng_buflen) {
+ warnx("%s block len %lu greater than buffer size %lu",
+ __func__, block->pcapng_block_len, block->pcapng_buflen);
+ return (PCAP_ERROR);
+ }
+ /*
+ * Move the name records and options if necessary
+ */
+ if (block->pcapng_records_len > 0 || block->pcapng_options_len > 0) {
+ u_char *tmp = pcap_ng_block_records_ptr(block) ?
+ pcap_ng_block_records_ptr(block) :
+ pcap_ng_block_options_ptr(block);
+ size_t len = block->pcapng_records_len + block->pcapng_options_len;
+ int32_t offset = PAD_32BIT(caplen) - (int32_t)block->pcapng_data_len;
+
+ bcopy(tmp, tmp + offset, len);
+ }
+
+ /*
+ * TBD: if records or options exist, should move them or error out
+ */
+ block->pcapng_data_is_external = 0;
+ block->pcapng_data_ptr = pcap_ng_block_data_ptr(block);
+ bcopy(ptr, block->pcapng_data_ptr, caplen);
+ if (padding_len > 0)
+ bzero(block->pcapng_data_ptr + caplen, padding_len);
+ block->pcapng_cap_len = caplen;
+ block->pcapng_data_len = PAD_32BIT(caplen);
+
+ pcapng_update_block_length(block);
+
+ return (0);
+}
+
+bpf_u_int32
+pcap_ng_block_packet_set_data(pcapng_block_t block, const void *ptr,
+ bpf_u_int32 caplen)
+{
+ if (pcap_ng_block_does_support_data(block) == 0)
+ return (PCAP_ERROR);
+
+ block->pcapng_data_is_external = 1;
+ block->pcapng_data_ptr = (u_char *)ptr;
+ block->pcapng_cap_len = caplen;
+ block->pcapng_data_len = PAD_32BIT(caplen);
+
+ pcapng_update_block_length(block);
+
+ return (0);
+}
+
+int
+pcap_ng_block_add_option_with_value(pcapng_block_t block, u_short code,
+ const void *value, u_short value_len)
+{
+ size_t optlen = sizeof(struct pcapng_option_header) + PAD_32BIT(value_len);
+ struct pcapng_option_header *opt_header;
+ bpf_u_int32 padding_len = PAD_32BIT(value_len) - value_len;
+ u_char *buffer;
+ u_char *block_option_ptr = pcap_ng_block_options_ptr(block);
+
+ if (block_option_ptr == NULL) {
+ warnx("%s options not supported for block type %u",
+ __func__, block->pcapng_block_type);
+ return (PCAP_ERROR);
+ }
+
+ if (optlen + block->pcapng_block_len > block->pcapng_buflen) {
+ warnx("%s block len %lu greater than buffer size %lu",
+ __func__, block->pcapng_block_len, block->pcapng_buflen);
+ return (PCAP_ERROR);
+ }
+
+ opt_header = (struct pcapng_option_header *)(block_option_ptr + block->pcapng_options_len);
+ /* Insert before the end of option */
+ if (block->pcapng_options_len > 0)
+ opt_header -= 1;
+ opt_header->option_code = code;
+ opt_header->option_length = value_len;
+
+ buffer = (u_char *)(opt_header + 1);
+
+ bcopy(value, buffer, value_len);
+
+ if (padding_len > 0)
+ bzero(buffer + value_len, padding_len);
+
+ /* Add end of option when first option added */
+ if (block->pcapng_options_len == 0)
+ block->pcapng_options_len = sizeof(struct pcapng_option_header);
+
+ block->pcapng_options_len += optlen;
+
+ /* Set the end of option at the end of the options */
+ opt_header = (struct pcapng_option_header *)(block_option_ptr + block->pcapng_options_len);
+ opt_header -= 1;
+ opt_header->option_code = PCAPNG_OPT_ENDOFOPT;
+ opt_header->option_length = 0;
+
+ pcapng_update_block_length(block);
+
+ return (0);
+}
+
+int
+pcap_ng_block_add_option_with_string(pcapng_block_t block, u_short code, const char *str)
+{
+ return (pcap_ng_block_add_option_with_value(block, code, str, strlen(str) + 1));
+}
+
+int
+pcap_ng_block_add_option_with_uuid(pcapng_block_t block, u_short code, const uuid_t uu)
+{
+ return (pcap_ng_block_add_option_with_value(block, code, uu, sizeof(uuid_t)));
+}
+
+
+static struct pcapng_option_header *
+get_opthdr_from_block_data(struct pcapng_option_header *opthdr, int swapped,
+ struct block_cursor *cursor, char *errbuf)
+{
+ struct pcapng_option_header *optp;
+
+ optp = get_from_block_data(cursor, sizeof(*opthdr), errbuf);
+ if (optp == NULL) {
+ /*
+ * Option header is cut short.
+ */
+ return (NULL);
+ }
+ *opthdr = *optp;
+ /*
+ * Byte-swap it if necessary.
+ */
+ if (swapped) {
+ opthdr->option_code = SWAPSHORT(opthdr->option_code);
+ opthdr->option_length = SWAPSHORT(opthdr->option_length);
+ }
+
+ return (opthdr);
+}
+
+static void *
+get_optvalue_from_block_data(struct block_cursor *cursor,
+ struct pcapng_option_header *opthdr, char *errbuf)
+{
+ size_t padded_option_len;
+ void *optvalue;
+
+ /* Pad option length to 4-byte boundary */
+ padded_option_len = opthdr->option_length;
+ padded_option_len = ((padded_option_len + 3)/4)*4;
+
+ optvalue = get_from_block_data(cursor, padded_option_len, errbuf);
+ if (optvalue == NULL) {
+ /*
+ * Option value is cut short.
+ */
+ return (NULL);
+ }
+
+ return (optvalue);
+}
+
+
+int
+pcap_ng_block_get_option(pcapng_block_t block, u_short code, struct pcapng_option_info *option_info)
+{
+ struct pcapng_option_header opthdr;
+ int swapped;
+ int num_of_options = 0;
+ struct block_cursor cursor;
+ static char errbuf[PCAP_ERRBUF_SIZE + 1];
+
+ if (option_info == NULL)
+ return (PCAP_ERROR);
+ if (block->pcapng_options_len == 0)
+ goto done;
+
+ swapped = block->pcapng_block_swapped;
+
+ cursor.block_type = block->pcapng_block_type;
+ cursor.data = pcap_ng_block_options_ptr(block);
+ cursor.data_remaining = block->pcapng_options_len;
+
+ while (get_opthdr_from_block_data(&opthdr, swapped, &cursor, errbuf)) {
+ void *value = get_optvalue_from_block_data(&cursor, &opthdr, errbuf);
+
+ /*
+ * If option is cut short we cannot parse it, give up
+ */
+ if (opthdr.option_length != 0 && value == NULL)
+ break;
+
+ if (code == opthdr.option_code) {
+ option_info->code = opthdr.option_code;
+ option_info->length = opthdr.option_length;
+ option_info->value = value;
+
+ num_of_options = 1;
+ break;
+ }
+ /*
+ * Detect end of option delimiter
+ */
+ if (opthdr.option_code == PCAPNG_OPT_ENDOFOPT)
+ break;
+ }
+
+done:
+ return (num_of_options);
+}
+
+int
+pcnapng_block_iterate_options(pcapng_block_t block,
+ pcapng_option_iterator_func opt_iterator_func,
+ void *context)
+{
+ struct pcapng_option_header opthdr;
+ int swapped;
+ int num_of_options = 0;
+ struct block_cursor cursor;
+ static char errbuf[PCAP_ERRBUF_SIZE + 1];
+
+ if (block == NULL || opt_iterator_func == NULL)
+ return (PCAP_ERROR);
+ swapped = block->pcapng_block_swapped;
+
+ cursor.block_type = block->pcapng_block_type;
+ cursor.data = pcap_ng_block_options_ptr(block);
+ cursor.data_remaining = block->pcapng_options_len;
+
+ while (get_opthdr_from_block_data(&opthdr, swapped, &cursor, errbuf)) {
+ void *value = get_optvalue_from_block_data(&cursor, &opthdr, errbuf);
+ struct pcapng_option_info option_info;
+
+ /*
+ * If option is cut short we cannot parse it, give up
+ */
+ if (opthdr.option_length != 0 && value == NULL)
+ break;
+
+ option_info.code = opthdr.option_code;
+ option_info.length = opthdr.option_length;
+ option_info.value = value;
+
+ num_of_options++;
+
+ opt_iterator_func(block, &option_info, context);
+
+ /*
+ * Detect end of option delimiter
+ */
+ if (opthdr.option_code == PCAPNG_OPT_ENDOFOPT)
+ break;
+ }
+
+done:
+ return (num_of_options);
+}
+
+int
+pcnapng_block_iterate_name_records(pcapng_block_t block,
+ pcapng_name_record_iterator_func record_iterator_func,
+ void *context)
+{
+ struct pcapng_record_header recordhdr;
+ int swapped;
+ int num_of_records = 0;
+ struct block_cursor cursor;
+ static char errbuf[PCAP_ERRBUF_SIZE + 1];
+
+ if (block == NULL || record_iterator_func == NULL)
+ return (PCAP_ERROR);
+ swapped = block->pcapng_block_swapped;
+
+ cursor.block_type = block->pcapng_block_type;
+ cursor.data = pcap_ng_block_records_ptr(block);
+ cursor.data_remaining = block->pcapng_records_len;
+
+ /*
+ * Note that we take advantage of the fact that name record headers
+ * have the same layout as option headers
+ */
+ while (get_opthdr_from_block_data((struct pcapng_option_header *)&recordhdr,
+ swapped, &cursor, errbuf)) {
+ struct pcapng_name_record_info record_info;
+ void *value =
+ get_optvalue_from_block_data(&cursor,
+ (struct pcapng_option_header *)&recordhdr,
+ errbuf);
+
+ /*
+ * If record is cut short we cannot parse it, give up
+ */
+ if (recordhdr.record_length != 0 && value == NULL)
+ break;
+
+ record_info.code = recordhdr.record_type;
+ record_info.length = recordhdr.record_length;
+ record_info.value = value;
+
+ num_of_records++;
+
+ /*
+ * Detect end of option delimiter
+ */
+ if (record_info.code == PCAPNG_NRES_ENDOFRECORD)
+ break;
+ }
+
+done:
+ return (num_of_records);
+}
+
+int
+pcap_ng_block_add_name_record_common(pcapng_block_t block, uint32_t type,
+ size_t addrlen, void *addr, const char **names)
+{
+ size_t names_len = 0;
+ int i;
+ const char *p;
+ size_t record_len = 0;
+ struct pcapng_record_header *record_hdr;
+ size_t padding_len;
+ u_char *buffer;
+ size_t offset;
+ u_char *block_records_ptr = pcap_ng_block_records_ptr(block);
+
+ if (block_records_ptr == NULL)
+ return (PCAP_ERROR);
+
+ for (i = 0; ; i++) {
+ p = names[i];
+ if (p == NULL || *p == 0)
+ break;
+ names_len += strlen(p) + 1;
+ }
+
+ record_len = sizeof(struct pcapng_record_header) + addrlen + PAD_32BIT(names_len);
+ if (record_len + block->pcapng_block_len > block->pcapng_buflen) {
+ warnx("%s block len %lu greater than buffer size %lu",
+ __func__, block->pcapng_block_len, block->pcapng_buflen);
+ return (PCAP_ERROR);
+ }
+
+ /*
+ * Move the options if necessary
+ */
+ if (block->pcapng_options_len > 0) {
+ u_char *tmp = pcap_ng_block_options_ptr(block);
+
+ bcopy(tmp, tmp + record_len, block->pcapng_options_len);
+ }
+
+ padding_len = PAD_32BIT(names_len) - names_len;
+
+ record_hdr = (struct pcapng_record_header*)(block_records_ptr + block->pcapng_records_len);
+ if (block->pcapng_records_len > 0)
+ record_hdr -= 1;
+ record_hdr->record_type = type;
+ record_hdr->record_length = addrlen + PAD_32BIT(names_len);
+
+ buffer = (u_char *)(record_hdr + 1);
+ bcopy(addr, buffer, addrlen);
+ offset = addrlen;
+ for (i = 0; ; i++) {
+ p = names[i];
+ if (p == NULL || *p == 0)
+ break;
+ u_short slen = strlen(p) + 1;
+ bcopy(p, buffer, slen);
+ offset += slen;
+ }
+ if (padding_len > 0)
+ bzero(buffer + offset, padding_len);
+
+ block->pcapng_records_len += record_len;
+
+ pcapng_update_block_length(block);
+
+ return (0);
+}
+
+int
+pcap_ng_block_add_name_record_with_ip4(pcapng_block_t block,
+ struct in_addr *in4,
+ const char **names)
+{
+ if (block->pcapng_block_type != PCAPNG_BT_NRB)
+ return (PCAP_ERROR);
+
+ return pcap_ng_block_add_name_record_common(block,
+ PCAPNG_NRES_IP4RECORD,
+ sizeof(struct in_addr),
+ in4,
+ names);
+}
+
+int
+pcap_ng_block_add_name_record_with_ip6(pcapng_block_t block,
+ struct in6_addr *in6,
+ const char **names)
+{
+ if (block->pcapng_block_type != PCAPNG_BT_NRB)
+ return (PCAP_ERROR);
+
+ return pcap_ng_block_add_name_record_common(block,
+ PCAPNG_NRES_IP4RECORD,
+ sizeof(struct in6_addr),
+ in6,
+ names);
+}
+
+bpf_u_int32
+pcap_ng_externalize_block(void *buffer, size_t buflen, pcapng_block_t block)
+{
+ struct pcapng_block_header block_header;
+ struct pcapng_block_trailer block_trailer;
+ bpf_u_int32 bytes_written = 0;
+ u_char *ptr;
+
+ if (buffer == NULL || buflen < block->pcapng_block_len)
+ return (0);
+
+ ptr = buffer;
+ block_header.block_type = block->pcapng_block_type;
+ block_header.total_length = (bpf_u_int32)block->pcapng_block_len;
+ bcopy(&block_header, ptr + bytes_written, sizeof(struct pcapng_block_header));
+ bytes_written += sizeof(struct pcapng_block_header);
+
+ switch (block->pcapng_block_type) {
+ case PCAPNG_BT_SHB:
+ case PCAPNG_BT_IDB:
+ case PCAPNG_BT_PB:
+ case PCAPNG_BT_SPB:
+ case PCAPNG_BT_NRB:
+ case PCAPNG_BT_ISB:
+ case PCAPNG_BT_EPB:
+ case PCAPNG_BT_PIB:
+ case PCAPNG_BT_OSEV:
+ if (block->pcapng_block_type == PCAPNG_BT_PB) {
+ if(block->pcap_ng_opb_fields.caplen == 0)
+ block->pcap_ng_opb_fields.caplen = block->pcapng_cap_len;
+ if(block->pcap_ng_opb_fields.len == 0)
+ block->pcap_ng_opb_fields.len = block->pcapng_cap_len;
+ }
+ if (block->pcapng_block_type == PCAPNG_BT_SPB) {
+ if(block->pcap_ng_spb_fields.len == 0)
+ block->pcap_ng_spb_fields.len = block->pcapng_cap_len;
+ }
+ if (block->pcapng_block_type == PCAPNG_BT_EPB) {
+ if(block->pcap_ng_epb_fields.caplen == 0)
+ block->pcap_ng_epb_fields.caplen = block->pcapng_cap_len;
+ if(block->pcap_ng_epb_fields.len == 0)
+ block->pcap_ng_epb_fields.len = block->pcapng_cap_len;
+ }
+ if (block->pcapng_block_type == PCAPNG_BT_OSEV) {
+ if(block->pcap_ng_osev_fields.len == 0)
+ block->pcap_ng_osev_fields.len = block->pcapng_cap_len;
+ }
+
+ if (block->pcapng_fields_len > 0) {
+ bcopy(&block->pcap_ng_shb_fields, ptr + bytes_written, block->pcapng_fields_len);
+ bytes_written += block->pcapng_fields_len;
+ }
+ break;
+ default:
+ /* Unknown block */
+ return (0);
+ break;
+ }
+
+
+ if (block->pcapng_data_len > 0) {
+ bpf_u_int32 padding_len = PAD_32BIT(block->pcapng_cap_len) - block->pcapng_cap_len;
+
+ bcopy(block->pcapng_data_ptr, ptr + bytes_written, block->pcapng_cap_len);
+ bytes_written += block->pcapng_cap_len;
+
+ if (padding_len > 0) {
+ bzero(ptr + bytes_written, padding_len);
+ bytes_written += padding_len;
+ }
+ }
+
+ if (block->pcapng_records_len > 0) {
+ bcopy(pcap_ng_block_records_ptr(block), ptr + bytes_written, block->pcapng_records_len);
+ bytes_written += block->pcapng_records_len;
+ }
+ if (block->pcapng_options_len > 0) {
+ bcopy(pcap_ng_block_options_ptr(block), ptr + bytes_written, block->pcapng_options_len);
+ bytes_written += block->pcapng_options_len;
+ }
+
+ block_trailer.total_length = (bpf_u_int32)block->pcapng_block_len;
+ bcopy(&block_trailer, ptr + bytes_written, bytes_written);
+ bytes_written += sizeof(struct pcapng_block_trailer);
+
+ return (bytes_written);
+}
+
+bpf_u_int32
+pcap_ng_dump_block(pcap_dumper_t *p, pcapng_block_t block)
+{
+ struct pcapng_block_header *block_header;
+ struct pcapng_block_trailer *block_trailer;
+ bpf_u_int32 bytes_written = 0;
+ struct iovec iov[4];
+ int iovcnt;
+ char data_padding[3] = { 0, 0, 0 };
+
+ block_header = (struct pcapng_block_header *)pcap_ng_block_header_ptr(block);
+ block_header->block_type = block->pcapng_block_type;
+ block_header->total_length = (bpf_u_int32)block->pcapng_block_len;
+
+ switch (block->pcapng_block_type) {
+ case PCAPNG_BT_SHB:
+ case PCAPNG_BT_IDB:
+ case PCAPNG_BT_PB:
+ case PCAPNG_BT_NRB:
+ case PCAPNG_BT_ISB:
+ case PCAPNG_BT_EPB:
+ case PCAPNG_BT_PIB:
+ case PCAPNG_BT_OSEV:
+ case PCAPNG_BT_DSB:
+ if (block->pcapng_block_type == PCAPNG_BT_PB) {
+ if (block->pcap_ng_opb_fields.caplen == 0)
+ block->pcap_ng_opb_fields.caplen = block->pcapng_cap_len;
+ if (block->pcap_ng_opb_fields.len == 0)
+ block->pcap_ng_opb_fields.len = block->pcapng_cap_len;
+ }
+ if (block->pcapng_block_type == PCAPNG_BT_SPB) {
+ if (block->pcap_ng_spb_fields.len == 0)
+ block->pcap_ng_spb_fields.len = block->pcapng_cap_len;
+ }
+ if (block->pcapng_block_type == PCAPNG_BT_EPB) {
+ if (block->pcap_ng_epb_fields.caplen == 0)
+ block->pcap_ng_epb_fields.caplen = block->pcapng_cap_len;
+ if (block->pcap_ng_epb_fields.len == 0)
+ block->pcap_ng_epb_fields.len = block->pcapng_cap_len;
+ }
+
+ // Copy the fixed fields if any
+ if (block->pcapng_fields_len > 0) {
+ bcopy(&block->pcap_ng_shb_fields, pcap_ng_block_fields_ptr(block), block->pcapng_fields_len);
+ }
+ break;
+ default:
+ /* Unknown block */
+ return (0);
+ break;
+ }
+
+ block_trailer = pcap_ng_block_trailer_ptr(block);
+ block_trailer->total_length = block_header->total_length;
+
+ iovcnt = 0;
+ iov[iovcnt].iov_len = sizeof(struct pcapng_block_header) + block->pcapng_fields_len;
+ iov[iovcnt].iov_base = block->pcapng_bufptr;
+ iovcnt++;
+
+ if (block->pcapng_data_len > 0) {
+ bpf_u_int32 padding_len = PAD_32BIT(block->pcapng_cap_len) - block->pcapng_cap_len;
+
+ iov[iovcnt].iov_len = block->pcapng_cap_len;
+ iov[iovcnt].iov_base = block->pcapng_data_ptr;
+ iovcnt++;
+
+ /* This is suboptimal... */
+ if (padding_len > 0) {
+ iov[iovcnt].iov_len = padding_len;
+ iov[iovcnt].iov_base = data_padding;
+ iovcnt++;
+ }
+ }
+ /*
+ * The name records, options and block trailer are contiguous
+ */
+ iov[iovcnt].iov_len = block->pcapng_records_len +
+ block->pcapng_options_len +
+ sizeof(struct pcapng_block_trailer);
+ if (block->pcapng_records_len > 0)
+ iov[iovcnt].iov_base = pcap_ng_block_records_ptr(block);
+ else if (block->pcapng_options_len > 0)
+ iov[iovcnt].iov_base = pcap_ng_block_options_ptr(block);
+ else
+ iov[iovcnt].iov_base = block_trailer;
+ iovcnt++;
+
+ bytes_written += writev(p->f->_file, iov, iovcnt);
+
+ return (bytes_written);
+}
+
+int
+pcap_ng_block_internalize_common(pcapng_block_t *pblock, pcap_t *p, u_char *raw_block)
+{
+ pcapng_block_t block = NULL;
+ struct pcapng_block_header bh = *(struct pcapng_block_header *)raw_block;
+ struct block_cursor cursor;
+ int swapped = 0;
+
+ if (pblock == NULL || raw_block == NULL)
+ return (PCAP_ERROR);
+
+ if (p != NULL)
+ swapped = p->swapped;
+
+ if (swapped) {
+ bh.block_type = SWAPLONG(bh.block_type);
+ bh.total_length = SWAPLONG(bh.total_length);
+ }
+
+ switch (bh.block_type) {
+ case PCAPNG_BT_SHB:
+ pcap_ng_init_section_info(p);
+ break;
+ case PCAPNG_BT_IDB:
+ case PCAPNG_BT_PB:
+ case PCAPNG_BT_SPB:
+ case PCAPNG_BT_NRB:
+ case PCAPNG_BT_ISB:
+ case PCAPNG_BT_EPB:
+ case PCAPNG_BT_PIB:
+ case PCAPNG_BT_OSEV:
+ case PCAPNG_BT_DSB:
+ break;
+ default:
+ (void) snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "%s: Unknown block type length %u",
+ __func__, bh.block_type);
+ goto fail;
+ }
+ /* Check the length is reasonable, limit to 1 MBytes */
+ if (bh.total_length > 1024 * 1024) {
+ (void) snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "%s: Block total length %u is greater than 16 MB",
+ __func__, bh.total_length);
+ goto fail;
+ }
+
+ /*
+ * Some ntar files from wireshark.org do not round up the total block length to
+ * a multiple of 4 bytes -- they must ignore the 32 bit alignment of the block body!
+ */
+ bh.total_length = PAD_32BIT(bh.total_length);
+
+ if (*pblock == NULL) {
+ block = pcap_ng_block_alloc(bh.total_length);
+ if (block == NULL) {
+ (void) snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "%s: Unknown block type %u",
+ __func__, bh.block_type);
+ goto fail;
+ }
+ } else {
+ block = *pblock;
+ }
+ block->pcapng_bufptr = raw_block;
+ block->pcapng_buflen = bh.total_length;
+ block->pcapng_buf_is_external = 1;
+ pcap_ng_block_reset(block, bh.block_type);
+ block->pcapng_block_len = bh.total_length;
+ block->pcapng_block_swapped = swapped;
+
+ cursor.data = raw_block + sizeof(struct pcapng_block_header);
+ cursor.data_remaining = bh.total_length -
+ sizeof(struct pcapng_block_header) -
+ sizeof(struct pcapng_block_trailer);
+ cursor.block_type = bh.block_type;
+
+ switch (bh.block_type) {
+ case PCAPNG_BT_SHB: {
+ struct pcapng_section_header_fields *shbp = pcap_ng_get_section_header_fields(block);
+ struct pcapng_section_header_fields *rawshb;
+
+ rawshb = get_from_block_data(&cursor, sizeof(struct pcapng_section_header_fields), p->errbuf);
+ if (rawshb == NULL)
+ goto fail;
+
+ shbp->byte_order_magic = rawshb->byte_order_magic;
+ shbp->major_version = rawshb->major_version;
+ shbp->minor_version = rawshb->minor_version;
+ shbp->section_length = rawshb->section_length;
+ if (swapped) {
+ shbp->byte_order_magic = SWAPLONG(shbp->byte_order_magic);
+ shbp->major_version = SWAPSHORT(shbp->major_version);
+ shbp->minor_version = SWAPSHORT(shbp->minor_version);
+ shbp->section_length = SWAPLONGLONG(shbp->section_length);
+ }
+
+ break;
+ }
+ case PCAPNG_BT_IDB: {
+ struct pcapng_interface_description_fields *idbp = pcap_ng_get_interface_description_fields(block);
+ struct pcapng_interface_description_fields *rawidb;
+
+ rawidb = get_from_block_data(&cursor, sizeof(struct pcapng_interface_description_fields), p->errbuf);
+ if (rawidb == NULL)
+ goto fail;
+
+ idbp->idb_linktype = rawidb->idb_linktype;
+ idbp->idb_reserved = rawidb->idb_reserved;
+ idbp->idb_snaplen = rawidb->idb_snaplen;
+ if (swapped) {
+ idbp->idb_linktype = SWAPSHORT(idbp->idb_linktype);
+ idbp->idb_reserved = SWAPSHORT(idbp->idb_reserved);
+ idbp->idb_snaplen = SWAPLONG(idbp->idb_snaplen);
+ }
+
+ break;
+ }
+ case PCAPNG_BT_ISB: {
+ struct pcapng_interface_statistics_fields *isbp = pcap_ng_get_interface_statistics_fields(block);
+ struct pcapng_interface_statistics_fields *rawisb;
+
+ rawisb = get_from_block_data(&cursor, sizeof(struct pcapng_interface_statistics_fields), p->errbuf);
+ if (rawisb == NULL)
+ goto fail;
+
+ isbp->interface_id = rawisb->interface_id;
+ isbp->timestamp_high = rawisb->timestamp_high;
+ isbp->timestamp_low = rawisb->timestamp_low;
+ if (swapped) {
+ isbp->interface_id = SWAPSHORT(isbp->interface_id);
+ isbp->timestamp_high = SWAPLONG(isbp->timestamp_high);
+ isbp->timestamp_low = SWAPLONG(isbp->timestamp_low);
+ }
+
+ break;
+ }
+ case PCAPNG_BT_EPB: {
+ struct pcapng_enhanced_packet_fields *epbp = pcap_ng_get_enhanced_packet_fields(block);
+ struct pcapng_enhanced_packet_fields *rawepb;
+ void *data;
+
+ rawepb = get_from_block_data(&cursor, sizeof(struct pcapng_enhanced_packet_fields), p->errbuf);
+ if (rawepb == NULL)
+ goto fail;
+
+ epbp->interface_id = rawepb->interface_id;
+ epbp->timestamp_high = rawepb->timestamp_high;
+ epbp->timestamp_low = rawepb->timestamp_low;
+ epbp->caplen = rawepb->caplen;
+ epbp->len = rawepb->len;
+ if (swapped) {
+ epbp->interface_id = SWAPLONG(epbp->interface_id);
+ epbp->timestamp_high = SWAPLONG(epbp->timestamp_high);
+ epbp->timestamp_low = SWAPLONG(epbp->timestamp_low);
+ epbp->caplen = SWAPLONG(epbp->caplen);
+ epbp->len = SWAPLONG(epbp->len);
+ }
+ data = get_from_block_data(&cursor, PAD_32BIT(epbp->caplen), p->errbuf);
+ if (data == NULL)
+ goto fail;
+ block->pcapng_data_is_external = 0;
+ block->pcapng_data_ptr = (u_char *)data;
+ block->pcapng_cap_len = epbp->caplen;
+ block->pcapng_data_len = PAD_32BIT(epbp->caplen);
+
+ break;
+ }
+ case PCAPNG_BT_SPB: {
+ struct pcapng_simple_packet_fields *spbp = pcap_ng_get_simple_packet_fields(block);
+ struct pcapng_simple_packet_fields *rawspb;
+ void *data;
+ uint32_t caplen;
+
+ rawspb = get_from_block_data(&cursor, sizeof(struct pcapng_simple_packet_fields), p->errbuf);
+ if (rawspb == NULL)
+ goto fail;
+
+ spbp->len = rawspb->len;
+ if (swapped) {
+ spbp->len = SWAPLONG(spbp->len);
+ }
+ caplen = bh.total_length - sizeof(struct pcapng_simple_packet_fields) -
+ sizeof(struct pcapng_block_header) - sizeof(struct pcapng_block_trailer);
+ if (caplen > spbp->len)
+ caplen = spbp->len;
+ data = get_from_block_data(&cursor, PAD_32BIT(caplen), p->errbuf);
+ if (data == NULL)
+ goto fail;
+ block->pcapng_data_is_external = 0;
+ block->pcapng_data_ptr = (u_char *)data;
+ block->pcapng_cap_len = caplen;
+ block->pcapng_data_len = PAD_32BIT(caplen);
+
+ break;
+ }
+ case PCAPNG_BT_PB: {
+ struct pcapng_packet_fields *pbp = pcap_ng_get_packet_fields(block);
+ struct pcapng_packet_fields *rawpb;
+ void *data;
+
+ rawpb = get_from_block_data(&cursor, sizeof(struct pcapng_packet_fields), p->errbuf);
+ if (rawpb == NULL)
+ goto fail;
+
+ pbp->interface_id = rawpb->interface_id;
+ pbp->drops_count = rawpb->drops_count;
+ pbp->timestamp_high = rawpb->timestamp_high;
+ pbp->timestamp_low = rawpb->timestamp_low;
+ pbp->caplen = rawpb->caplen;
+ pbp->len = rawpb->len;
+ if (swapped) {
+ /* these were written in opposite byte order */
+ pbp->interface_id = SWAPSHORT(pbp->interface_id);
+ pbp->drops_count = SWAPSHORT(pbp->drops_count);
+ pbp->timestamp_high = SWAPLONG(pbp->timestamp_high);
+ pbp->timestamp_low = SWAPLONG(pbp->timestamp_low);
+ pbp->caplen = SWAPLONG(pbp->caplen);
+ pbp->len = SWAPLONG(pbp->len);
+ }
+
+ data = get_from_block_data(&cursor, PAD_32BIT(pbp->caplen), p->errbuf);
+ if (data == NULL)
+ goto fail;
+ block->pcapng_data_is_external = 0;
+ block->pcapng_data_ptr = (u_char *)data;
+ block->pcapng_cap_len = pbp->caplen;
+ block->pcapng_data_len = PAD_32BIT(pbp->caplen);
+
+ break;
+ }
+ case PCAPNG_BT_PIB: {
+ struct pcapng_process_information_fields *pibp = pcap_ng_get_process_information_fields(block);
+ struct pcapng_process_information_fields *rawpib;
+
+ rawpib = get_from_block_data(&cursor, sizeof(struct pcapng_process_information_fields), p->errbuf);
+ if (rawpib == NULL)
+ goto fail;
+
+ pibp->process_id = rawpib->process_id;
+ if (swapped) {
+ pibp->process_id = SWAPSHORT(rawpib->process_id);
+ }
+ break;
+ }
+ case PCAPNG_BT_NRB: {
+ struct pcapng_record_header *rh;
+
+ while (1) {
+ size_t record_len;
+
+ rh = get_from_block_data(&cursor, sizeof(struct pcapng_record_header), p->errbuf);
+ if (rh == NULL)
+ goto fail;
+
+ if (swapped)
+ record_len = SWAPSHORT(rh->record_length);
+ else
+ record_len = rh->record_length;
+
+ if (get_from_block_data(&cursor, PCAPNG_ROUNDUP32(record_len), p->errbuf) == NULL)
+ goto fail;
+
+ block->pcapng_records_len += sizeof(struct pcapng_record_header) +
+ PCAPNG_ROUNDUP32(record_len);
+
+ if (rh->record_type == PCAPNG_NRES_ENDOFRECORD)
+ break;
+ }
+ break;
+ }
+ case PCAPNG_BT_OSEV: {
+ struct pcapng_os_event_fields *osevp = pcap_ng_get_os_event_fields(block);
+ struct pcapng_os_event_fields *rawosevp;
+ void *data;
+ uint32_t caplen;
+
+ rawosevp = get_from_block_data(&cursor, sizeof(struct pcapng_os_event_fields), p->errbuf);
+ if (rawosevp == NULL)
+ goto fail;
+
+ osevp->type = rawosevp->type;
+ osevp->timestamp_high = rawosevp->timestamp_high;
+ osevp->timestamp_low = rawosevp->timestamp_low;
+ osevp->len = rawosevp->len;
+ if (swapped) {
+ osevp->type = SWAPLONG(osevp->type);
+ osevp->timestamp_high = SWAPLONG(osevp->timestamp_high);
+ osevp->timestamp_low = SWAPLONG(osevp->timestamp_low);
+ osevp->len = SWAPLONG(osevp->len);
+ }
+ caplen = bh.total_length - sizeof(struct pcapng_os_event_fields) -
+ sizeof(struct pcapng_block_header) - sizeof(struct pcapng_block_trailer);
+ if (caplen > osevp->len)
+ caplen = osevp->len;
+ data = get_from_block_data(&cursor, PAD_32BIT(caplen), p->errbuf);
+ if (data == NULL)
+ goto fail;
+ block->pcapng_data_is_external = 0;
+ block->pcapng_data_ptr = (u_char *)data;
+ block->pcapng_cap_len = caplen;
+ block->pcapng_data_len = PAD_32BIT(caplen);
+ break;
+ }
+ case PCAPNG_BT_DSB: {
+ struct pcapng_decryption_secrets_fields *dsp = pcap_ng_get_decryption_secrets_fields(block);
+ struct pcapng_decryption_secrets_fields *rawdsp;
+ void *data;
+ uint32_t caplen;
+
+ rawdsp = get_from_block_data(&cursor, sizeof(struct pcapng_decryption_secrets_fields), p->errbuf);
+ if (rawdsp == NULL)
+ goto fail;
+ dsp->secrets_type = rawdsp->secrets_type;
+ dsp->secrets_length = rawdsp->secrets_length;
+ if (swapped) {
+ dsp->secrets_type = SWAPLONG(dsp->secrets_type);
+ dsp->secrets_length = SWAPLONG(dsp->secrets_length);
+ }
+
+ caplen = bh.total_length - sizeof(struct pcapng_decryption_secrets_fields) -
+ sizeof(struct pcapng_block_header) - sizeof(struct pcapng_block_trailer);
+ if (caplen > dsp->secrets_length)
+ caplen = dsp->secrets_length;
+ data = get_from_block_data(&cursor, PAD_32BIT(caplen), p->errbuf);
+ if (data == NULL)
+ goto fail;
+ block->pcapng_data_is_external = 0;
+ block->pcapng_data_ptr = (u_char *)data;
+ block->pcapng_cap_len = caplen;
+ block->pcapng_data_len = PAD_32BIT(caplen);
+ break;
+ }
+ default:
+ goto fail;
+ }
+
+ /*
+ * Finally compute the length of the options as options come last in blocks
+ */
+ while (1) {
+ size_t optlen;
+ struct pcapng_option_header *opt;
+
+ opt = get_from_block_data(&cursor, sizeof(struct pcapng_option_header), p->errbuf);
+ /*
+ * No, or no more options
+ */
+ if (opt == NULL)
+ break;
+
+ if (swapped)
+ optlen = SWAPSHORT(opt->option_length);
+ else
+ optlen = opt->option_length;
+
+ if (get_from_block_data(&cursor, PCAPNG_ROUNDUP32(optlen), p->errbuf) == NULL)
+ goto fail;
+
+ block->pcapng_options_len += sizeof(struct pcapng_option_header) + PCAPNG_ROUNDUP32(optlen);
+
+ if (opt->option_code == PCAPNG_OPT_ENDOFOPT)
+ break;
+ }
+
+ /* Success */
+ if (*pblock == NULL)
+ *pblock = block;
+ return (0);
+
+fail:
+ if (*pblock == NULL && block != NULL)
+ pcap_ng_free_block(block);
+ return (PCAP_ERROR);
+}
+
+int
+pcap_ng_block_init_with_raw_block(pcapng_block_t block, pcap_t *p, u_char *raw_block)
+{
+ return pcap_ng_block_internalize_common(&block, p, raw_block);
+}
+
+pcapng_block_t
+pcap_ng_block_alloc_with_raw_block(pcap_t *p, u_char *raw_block)
+{
+ pcapng_block_t block = NULL;
+
+ if (pcap_ng_block_internalize_common(&block, p, raw_block) == 0)
+ return (block);
+ else
+ return (NULL);
+}