summaryrefslogtreecommitdiff
path: root/wiretap/pcapng.c
diff options
context:
space:
mode:
Diffstat (limited to 'wiretap/pcapng.c')
-rw-r--r--wiretap/pcapng.c613
1 files changed, 606 insertions, 7 deletions
diff --git a/wiretap/pcapng.c b/wiretap/pcapng.c
index fa483367d1..19204952d1 100644
--- a/wiretap/pcapng.c
+++ b/wiretap/pcapng.c
@@ -2702,25 +2702,166 @@ pcapng_close(wtap *wth)
g_array_free(pcapng->interfaces, TRUE);
}
+typedef struct pcapng_optionblock_size_t
+{
+ guint32 size;
+} pcapng_optionblock_size_t;
+
+static guint32 pcapng_compute_option_string_size(char *str)
+{
+ guint32 size = 0, pad;
+
+ if (str == NULL)
+ return 0;
+
+ size = (guint32)strlen(str) & 0xffff;
+ if ((size % 4)) {
+ pad = 4 - (size % 4);
+ } else {
+ pad = 0;
+ }
+
+ size += pad;
+
+ return size;
+}
+
+static void compute_shb_option_size(wtap_optionblock_t block _U_, guint option_id, wtap_opttype_e option_type _U_, wtap_option_type* option, void* user_data)
+{
+ pcapng_optionblock_size_t* block_size = (pcapng_optionblock_size_t*)user_data;
+ guint32 size = 0;
+
+ switch(option_id)
+ {
+ case OPT_COMMENT:
+ case OPT_SHB_HARDWARE:
+ case OPT_SHB_OS:
+ case OPT_SHB_USERAPPL:
+ if (option != NULL)
+ size = pcapng_compute_option_string_size(option->stringval);
+ break;
+ default:
+ /* Unknown options - size by datatype? */
+ break;
+ }
+
+ block_size->size += size;
+ /* Add bytes for option header if option should be written */
+ if (size > 0) {
+ /* Add optional padding to 32 bits */
+ if ((block_size->size & 0x03) != 0)
+ {
+ block_size->size += 4 - (block_size->size & 0x03);
+ }
+ block_size->size += 4;
+ }
+}
+
+typedef struct pcapng_write_block_t
+{
+ wtap_dumper *wdh;
+ int *err;
+ gboolean success;
+}
+pcapng_write_block_t;
+
+static gboolean pcapng_write_option_string(wtap_dumper *wdh, guint option_id, char *str, int *err)
+{
+ struct pcapng_option_header option_hdr;
+ guint32 size = (guint32)strlen(str) & 0xffff;
+ const guint32 zero_pad = 0;
+ guint32 pad;
+
+ if (size == 0)
+ return TRUE;
+
+ /* String options don't consider pad bytes part of the length */
+ option_hdr.type = (guint16)option_id;
+ option_hdr.value_length = (guint16)size;
+ if (!wtap_dump_file_write(wdh, &option_hdr, 4, err))
+ return FALSE;
+ wdh->bytes_dumped += 4;
+ if (!wtap_dump_file_write(wdh, str, size, err))
+ return FALSE;
+ wdh->bytes_dumped += size;
+
+ if ((size % 4)) {
+ pad = 4 - (size % 4);
+ } else {
+ pad = 0;
+ }
+
+ /* write padding (if any) */
+ if (pad != 0) {
+ if (!wtap_dump_file_write(wdh, &zero_pad, pad, err))
+ return FALSE;
+
+ wdh->bytes_dumped += pad;
+ }
+
+ return TRUE;
+}
+
+static void write_wtap_shb_block(wtap_optionblock_t block _U_, guint option_id, wtap_opttype_e option_type _U_, wtap_option_type* option, void* user_data)
+{
+ pcapng_write_block_t* write_block = (pcapng_write_block_t*)user_data;
+
+ /* Don't continue if there has been an error */
+ if (!write_block->success)
+ return;
+
+ switch(option_id)
+ {
+ case OPT_COMMENT:
+ case OPT_SHB_HARDWARE:
+ case OPT_SHB_OS:
+ case OPT_SHB_USERAPPL:
+ if ((option != NULL) && (option->stringval != NULL)) {
+ if (!pcapng_write_option_string(write_block->wdh, option_id, option->stringval, write_block->err)) {
+ write_block->success = FALSE;
+ return;
+ }
+ }
+ break;
+ default:
+ /* Unknown options - write by datatype? */
+ break;
+ }
+}
+
+/* Write a section header block.
+ * If we don't have a section block header already, create a default
+ * one with no options.
+ */
static gboolean
pcapng_write_section_header_block(wtap_dumper *wdh, int *err)
{
pcapng_block_header_t bh;
pcapng_section_header_block_t shb;
+ pcapng_optionblock_size_t block_size;
+ struct pcapng_option_header option_hdr;
+ block_size.size = 0;
+ bh.block_total_length = (guint32)(sizeof(bh) + sizeof(shb) + 4);
if (wdh->shb_hdr) {
pcapng_debug("pcapng_write_section_header_block: Have shb_hdr");
- return wtap_optionblock_write(wdh, wdh->shb_hdr, err);
+ /* Compute block size */
+ wtap_optionblock_foreach_option(wdh->shb_hdr, compute_shb_option_size, &block_size);
+
+ if (block_size.size > 0) {
+ /* End-of-options tag */
+ block_size.size += 4;
+ }
+
+ bh.block_total_length += block_size.size;
}
- /* we don't have a section block header already, so create a default one with no options */
+ pcapng_debug("pcapng_write_section_header_block: Total len %u", bh.block_total_length);
/* write block header */
bh.block_type = BLOCK_TYPE_SHB;
- bh.block_total_length = (guint32)(sizeof(bh) + sizeof(shb) + 4);
- pcapng_debug("pcapng_write_section_header_block: Total len %u", bh.block_total_length);
if (!wtap_dump_file_write(wdh, &bh, sizeof bh, err))
return FALSE;
@@ -2730,12 +2871,39 @@ pcapng_write_section_header_block(wtap_dumper *wdh, int *err)
shb.magic = 0x1A2B3C4D;
shb.version_major = 1;
shb.version_minor = 0;
- shb.section_length = -1;
+ if (wdh->shb_hdr) {
+ wtapng_mandatory_section_t* section_data = (wtapng_mandatory_section_t*)wtap_optionblock_get_mandatory_data(wdh->shb_hdr);
+ shb.section_length = section_data->section_length;
+ } else {
+ shb.section_length = -1;
+ }
if (!wtap_dump_file_write(wdh, &shb, sizeof shb, err))
return FALSE;
wdh->bytes_dumped += sizeof shb;
+ if (wdh->shb_hdr) {
+ pcapng_write_block_t block_data;
+
+ if (block_size.size > 0) {
+ /* Write options */
+ block_data.wdh = wdh;
+ block_data.err = err;
+ block_data.success = TRUE;
+ wtap_optionblock_foreach_option(wdh->shb_hdr, write_wtap_shb_block, &block_data);
+
+ if (!block_data.success)
+ return FALSE;
+
+ /* Write end of options */
+ option_hdr.type = OPT_EOFOPT;
+ option_hdr.value_length = 0;
+ if (!wtap_dump_file_write(wdh, &option_hdr, 4, err))
+ return FALSE;
+ wdh->bytes_dumped += 4;
+ }
+ }
+
/* write block footer */
if (!wtap_dump_file_write(wdh, &bh.block_total_length,
sizeof bh.block_total_length, err))
@@ -3193,6 +3361,437 @@ pcapng_write_name_resolution_block(wtap_dumper *wdh, int *err)
return TRUE;
}
+static void compute_isb_option_size(wtap_optionblock_t block _U_, guint option_id, wtap_opttype_e option_type _U_, wtap_option_type* option, void* user_data)
+{
+ pcapng_optionblock_size_t* block_size = (pcapng_optionblock_size_t*)user_data;
+ guint32 size = 0;
+
+ switch(option_id)
+ {
+ case OPT_COMMENT:
+ if (option != NULL) {
+ size = pcapng_compute_option_string_size(option->stringval);
+ }
+ break;
+ case OPT_ISB_STARTTIME:
+ case OPT_ISB_ENDTIME:
+ if ((option != NULL) && (option->uint64val != 0)) {
+ size = 8;
+ }
+ break;
+ case OPT_ISB_IFRECV:
+ case OPT_ISB_IFDROP:
+ case OPT_ISB_FILTERACCEPT:
+ case OPT_ISB_OSDROP:
+ case OPT_ISB_USRDELIV:
+ if ((option != NULL) && (option->uint64val != G_GUINT64_CONSTANT(0xFFFFFFFFFFFFFFFF))) {
+ size = 8;
+ }
+ break;
+ default:
+ /* Unknown options - size by datatype? */
+ break;
+ }
+
+ block_size->size += size;
+ /* Add bytes for option header if option should be written */
+ if (size > 0) {
+ /* Add optional padding to 32 bits */
+ if ((block_size->size & 0x03) != 0)
+ {
+ block_size->size += 4 - (block_size->size & 0x03);
+ }
+ block_size->size += 4;
+ }
+}
+
+static void write_wtap_isb_block(wtap_optionblock_t block _U_, guint option_id, wtap_opttype_e option_type _U_, wtap_option_type* option, void* user_data)
+{
+ pcapng_write_block_t* write_block = (pcapng_write_block_t*)user_data;
+ struct pcapng_option_header option_hdr;
+
+ /* Don't continue if there has been an error */
+ if (!write_block->success)
+ return;
+
+ switch(option_id)
+ {
+ case OPT_COMMENT:
+ if ((option != NULL) && (option->stringval != NULL)) {
+ if (!pcapng_write_option_string(write_block->wdh, option_id, option->stringval, write_block->err)) {
+ write_block->success = FALSE;
+ return;
+ }
+ }
+ break;
+ case OPT_ISB_STARTTIME:
+ case OPT_ISB_ENDTIME:
+ if ((option != NULL) && (option->uint64val != 0)) {
+ guint32 high, low;
+
+ option_hdr.type = option_id;
+ option_hdr.value_length = 8;
+ if (!wtap_dump_file_write(write_block->wdh, &option_hdr, 4, write_block->err)) {
+ write_block->success = FALSE;
+ return;
+ }
+ write_block->wdh->bytes_dumped += 4;
+
+ high = (guint32)(option->uint64val >> 32);
+ low = (guint32)(option->uint64val >> 0);
+ if (!wtap_dump_file_write(write_block->wdh, &high, sizeof(guint32), write_block->err)) {
+ write_block->success = FALSE;
+ return;
+ }
+ write_block->wdh->bytes_dumped += 4;
+ if (!wtap_dump_file_write(write_block->wdh, &low, sizeof(guint32), write_block->err)) {
+ write_block->success = FALSE;
+ return;
+ }
+ write_block->wdh->bytes_dumped += 4;
+ }
+ break;
+ case OPT_ISB_IFRECV:
+ case OPT_ISB_IFDROP:
+ case OPT_ISB_FILTERACCEPT:
+ case OPT_ISB_OSDROP:
+ case OPT_ISB_USRDELIV:
+ if ((option != NULL) && (option->uint64val != G_GUINT64_CONSTANT(0xFFFFFFFFFFFFFFFF))) {
+ option_hdr.type = option_id;
+ option_hdr.value_length = 8;
+ if (!wtap_dump_file_write(write_block->wdh, &option_hdr, 4, write_block->err)) {
+ write_block->success = FALSE;
+ return;
+ }
+ write_block->wdh->bytes_dumped += 4;
+
+ if (!wtap_dump_file_write(write_block->wdh, &option->uint64val, sizeof(guint64), write_block->err)) {
+ write_block->success = FALSE;
+ return;
+ }
+ write_block->wdh->bytes_dumped += 8;
+ }
+ break;
+ default:
+ /* Unknown options - write by datatype? */
+ break;
+ }
+}
+
+static gboolean
+pcapng_write_interface_statistics_block(wtap_dumper *wdh, wtap_optionblock_t if_stats, int *err)
+{
+ pcapng_block_header_t bh;
+ pcapng_interface_statistics_block_t isb;
+ pcapng_optionblock_size_t block_size;
+ pcapng_write_block_t block_data;
+ struct pcapng_option_header option_hdr;
+ wtapng_if_stats_mandatory_t* mand_data = (wtapng_if_stats_mandatory_t*)wtap_optionblock_get_mandatory_data(if_stats);
+
+ pcapng_debug("pcapng_write_interface_statistics_block");
+
+ /* Compute block size */
+ block_size.size = 0;
+ wtap_optionblock_foreach_option(if_stats, compute_isb_option_size, &block_size);
+
+ if (block_size.size > 0) {
+ /* End-of-options tag */
+ block_size.size += 4;
+ }
+
+ /* write block header */
+ bh.block_type = BLOCK_TYPE_ISB;
+ bh.block_total_length = (guint32)(sizeof(bh) + sizeof(isb) + block_size.size + 4);
+ pcapng_debug("pcapng_write_interface_statistics_block: Total len %u", bh.block_total_length);
+
+ if (!wtap_dump_file_write(wdh, &bh, sizeof bh, err))
+ return FALSE;
+ wdh->bytes_dumped += sizeof bh;
+
+ /* write block fixed content */
+ isb.interface_id = mand_data->interface_id;
+ isb.timestamp_high = mand_data->ts_high;
+ isb.timestamp_low = mand_data->ts_low;
+
+ if (!wtap_dump_file_write(wdh, &isb, sizeof isb, err))
+ return FALSE;
+ wdh->bytes_dumped += sizeof isb;
+
+ /* Write options */
+ if (block_size.size > 0) {
+ block_data.wdh = wdh;
+ block_data.err = err;
+ block_data.success = TRUE;
+ wtap_optionblock_foreach_option(if_stats, write_wtap_isb_block, &block_data);
+
+ if (!block_data.success)
+ return FALSE;
+
+ /* Write end of options */
+ option_hdr.type = OPT_EOFOPT;
+ option_hdr.value_length = 0;
+ if (!wtap_dump_file_write(wdh, &option_hdr, 4, err))
+ return FALSE;
+ wdh->bytes_dumped += 4;
+ }
+
+ /* write block footer */
+ if (!wtap_dump_file_write(wdh, &bh.block_total_length,
+ sizeof bh.block_total_length, err))
+ return FALSE;
+ wdh->bytes_dumped += sizeof bh.block_total_length;
+ return TRUE;
+}
+
+static void compute_idb_option_size(wtap_optionblock_t block _U_, guint option_id, wtap_opttype_e option_type _U_, wtap_option_type* option, void* user_data)
+{
+ pcapng_optionblock_size_t* block_size = (pcapng_optionblock_size_t*)user_data;
+ guint32 size = 0;
+
+ switch(option_id)
+ {
+ case OPT_COMMENT:
+ case OPT_IDB_NAME:
+ case OPT_IDB_DESCR:
+ case OPT_IDB_OS:
+ if (option != NULL) {
+ size = pcapng_compute_option_string_size(option->stringval);
+ }
+ break;
+ case OPT_IDB_SPEED:
+ if ((option != NULL) && (option->uint64val != 0)) {
+ size = 8;
+ }
+ break;
+ case OPT_IDB_TSRESOL:
+ if ((option != NULL) && (option->uint8val != 0)) {
+ size = 1;
+ }
+ break;
+ case OPT_IDB_FILTER:
+ if (option != NULL) {
+ wtapng_if_descr_filter_t* filter = (wtapng_if_descr_filter_t*)option->customval.data;
+ guint32 pad;
+ if ((filter != NULL) && (filter->if_filter_str != NULL)) {
+ size = (guint32)(strlen(filter->if_filter_str) + 1) & 0xffff;
+ if ((size % 4)) {
+ pad = 4 - (size % 4);
+ } else {
+ pad = 0;
+ }
+
+ size += pad;
+ }
+ }
+ break;
+ case OPT_IDB_FCSLEN:
+ /* XXX - Not currently writing value */
+ break;
+ default:
+ /* Unknown options - size by datatype? */
+ break;
+ }
+
+ block_size->size += size;
+ /* Add bytes for option header if option should be written */
+ if (size > 0) {
+ /* Add optional padding to 32 bits */
+ if ((block_size->size & 0x03) != 0)
+ {
+ block_size->size += 4 - (block_size->size & 0x03);
+ }
+ block_size->size += 4;
+ }
+}
+
+static void write_wtap_idb_block(wtap_optionblock_t block _U_, guint option_id, wtap_opttype_e option_type _U_, wtap_option_type* option, void* user_data)
+{
+ pcapng_write_block_t* write_block = (pcapng_write_block_t*)user_data;
+ struct pcapng_option_header option_hdr;
+ const guint32 zero_pad = 0;
+
+ switch(option_id)
+ {
+ case OPT_COMMENT:
+ case OPT_IDB_NAME:
+ case OPT_IDB_DESCR:
+ case OPT_IDB_OS:
+ if ((option != NULL) && (option->stringval != NULL)) {
+ if (!pcapng_write_option_string(write_block->wdh, option_id, option->stringval, write_block->err)) {
+ write_block->success = FALSE;
+ return;
+ }
+ }
+ break;
+ case OPT_IDB_SPEED:
+ if ((option != NULL) && (option->uint64val != 0)) {
+ option_hdr.type = option_id;
+ option_hdr.value_length = 8;
+ if (!wtap_dump_file_write(write_block->wdh, &option_hdr, 4, write_block->err)) {
+ write_block->success = FALSE;
+ return;
+ }
+ write_block->wdh->bytes_dumped += 4;
+
+ if (!wtap_dump_file_write(write_block->wdh, &option->uint64val, sizeof(guint64), write_block->err)) {
+ write_block->success = FALSE;
+ return;
+ }
+ write_block->wdh->bytes_dumped += 8;
+ }
+ break;
+ case OPT_IDB_TSRESOL:
+ if ((option != NULL) && (option->uint8val != 0)) {
+ option_hdr.type = option_id;
+ option_hdr.value_length = 1;
+ if (!wtap_dump_file_write(write_block->wdh, &option_hdr, 4, write_block->err)) {
+ write_block->success = FALSE;
+ return;
+ }
+ write_block->wdh->bytes_dumped += 4;
+
+ if (!wtap_dump_file_write(write_block->wdh, &option->uint8val, 1, write_block->err)) {
+ write_block->success = FALSE;
+ return;
+ }
+ write_block->wdh->bytes_dumped += 1;
+
+ if (!wtap_dump_file_write(write_block->wdh, &zero_pad, 3, write_block->err)) {
+ write_block->success = FALSE;
+ return;
+ }
+ write_block->wdh->bytes_dumped += 3;
+ }
+ break;
+ case OPT_IDB_FILTER:
+ if (option != NULL) {
+ wtapng_if_descr_filter_t* filter = (wtapng_if_descr_filter_t*)option->customval.data;
+ guint32 size, pad;
+ if ((filter != NULL) && (filter->if_filter_str != NULL)) {
+ size = (guint32)(strlen(filter->if_filter_str) + 1) & 0xffff;
+ if ((size % 4)) {
+ pad = 4 - (size % 4);
+ } else {
+ pad = 0;
+ }
+
+ option_hdr.type = option_id;
+ option_hdr.value_length = size;
+ if (!wtap_dump_file_write(write_block->wdh, &option_hdr, 4, write_block->err)) {
+ write_block->success = FALSE;
+ return;
+ }
+ write_block->wdh->bytes_dumped += 4;
+
+ /* Write the zero indicating libpcap filter variant */
+ if (!wtap_dump_file_write(write_block->wdh, &zero_pad, 1, write_block->err)) {
+ write_block->success = FALSE;
+ return;
+ }
+ write_block->wdh->bytes_dumped += 1;
+
+ /* if_filter_str_len includes the leading byte indicating filter type (libpcap str or BPF code) */
+ if (!wtap_dump_file_write(write_block->wdh, filter->if_filter_str, size-1, write_block->err)) {
+ write_block->success = FALSE;
+ return;
+ }
+ write_block->wdh->bytes_dumped += size - 1;
+
+ /* write padding (if any) */
+ if (pad != 0) {
+ if (!wtap_dump_file_write(write_block->wdh, &zero_pad, pad, write_block->err)) {
+ write_block->success = FALSE;
+ return;
+ }
+ write_block->wdh->bytes_dumped += pad;
+ }
+
+ }
+ }
+ break;
+ case OPT_IDB_FCSLEN:
+ /* XXX - Not currently writing value */
+ break;
+ default:
+ /* Unknown options - size by datatype? */
+ break;
+ }
+}
+
+static gboolean
+pcapng_write_if_descr_block(wtap_dumper *wdh, wtap_optionblock_t int_data, int *err)
+{
+ pcapng_block_header_t bh;
+ pcapng_interface_description_block_t idb;
+ pcapng_optionblock_size_t block_size;
+ pcapng_write_block_t block_data;
+ struct pcapng_option_header option_hdr;
+ wtapng_if_descr_mandatory_t* mand_data = (wtapng_if_descr_mandatory_t*)wtap_optionblock_get_mandatory_data(int_data);
+
+ pcapng_debug("pcapng_write_if_descr_block: encap = %d (%s), snaplen = %d",
+ mand_data->link_type,
+ wtap_encap_string(wtap_pcap_encap_to_wtap_encap(mand_data->link_type)),
+ mand_data->snap_len);
+
+ if (mand_data->link_type == (guint16)-1) {
+ *err = WTAP_ERR_UNWRITABLE_ENCAP;
+ return FALSE;
+ }
+
+ /* Compute block size */
+ block_size.size = 0;
+ wtap_optionblock_foreach_option(int_data, compute_idb_option_size, &block_size);
+
+ if (block_size.size > 0) {
+ /* End-of-options tag */
+ block_size.size += 4;
+ }
+
+ /* write block header */
+ bh.block_type = BLOCK_TYPE_IDB;
+ bh.block_total_length = (guint32)(sizeof(bh) + sizeof(idb) + block_size.size + 4);
+ pcapng_debug("pcapng_write_if_descr_block: Total len %u", bh.block_total_length);
+
+ if (!wtap_dump_file_write(wdh, &bh, sizeof bh, err))
+ return FALSE;
+ wdh->bytes_dumped += sizeof bh;
+
+ /* write block fixed content */
+ idb.linktype = mand_data->link_type;
+ idb.reserved = 0;
+ idb.snaplen = mand_data->snap_len;
+
+ if (!wtap_dump_file_write(wdh, &idb, sizeof idb, err))
+ return FALSE;
+ wdh->bytes_dumped += sizeof idb;
+
+ if (block_size.size > 0) {
+ /* Write options */
+ block_data.wdh = wdh;
+ block_data.err = err;
+ block_data.success = TRUE;
+ wtap_optionblock_foreach_option(int_data, write_wtap_idb_block, &block_data);
+
+ if (!block_data.success)
+ return FALSE;
+
+ /* Write end of options */
+ option_hdr.type = OPT_EOFOPT;
+ option_hdr.value_length = 0;
+ if (!wtap_dump_file_write(wdh, &option_hdr, 4, err))
+ return FALSE;
+ wdh->bytes_dumped += 4;
+ }
+
+ /* write block footer */
+ if (!wtap_dump_file_write(wdh, &bh.block_total_length,
+ sizeof bh.block_total_length, err))
+ return FALSE;
+
+ wdh->bytes_dumped += sizeof bh.block_total_length;
+ return TRUE;
+}
+
static gboolean pcapng_dump(wtap_dumper *wdh,
const struct wtap_pkthdr *phdr,
const guint8 *pd, int *err, gchar **err_info _U_)
@@ -3268,7 +3867,7 @@ static gboolean pcapng_dump_finish(wtap_dumper *wdh, int *err)
if_stats = g_array_index(int_data_mand->interface_statistics, wtap_optionblock_t, j);
pcapng_debug("pcapng_dump_finish: write ISB for interface %u", ((wtapng_if_stats_mandatory_t*)wtap_optionblock_get_mandatory_data(if_stats))->interface_id);
- if (!wtap_optionblock_write(wdh, if_stats, err)) {
+ if (!pcapng_write_interface_statistics_block(wdh, if_stats, err)) {
return FALSE;
}
}
@@ -3314,7 +3913,7 @@ pcapng_dump_open(wtap_dumper *wdh, int *err)
idb = g_array_index(wdh->interface_data, wtap_optionblock_t, i);
- if (!wtap_optionblock_write(wdh, idb, err)) {
+ if (!pcapng_write_if_descr_block(wdh, idb, err)) {
return FALSE;
}