wireshark/wiretap/wtap_opttypes.c
Peter Wu 52a6671439 wiretap: add read/write support for Decryption Secrets Block (DSB)
Support reading and writing pcapng files with DSBs. A DSB may occur
multiple times but should appear before packets that need those
decryption secrets (so it cannot be moved to the end like NRB). The TLS
dissector will be updated in the future to make use of these secrets.
pcapng spec update: https://github.com/pcapng/pcapng/pull/54

As DSBs may be interleaved with packets, do not even try to read it in
pcapng_open (as is done for IDBs). Instead process them during the
sequential read, appending them to the 'wtap::dsbs' array.

Writing is more complicated, secrets may initially not be available when
'wtap_dumper' is created. As they may become available in 'wtap::dsbs'
as more packets are read, allow 'wtap_dumper::dsbs_growing' to reference
this array. This saves every user from checking/dumping DSBs.

If the wtap user needs to insert extra DSBs (while preserving existing
DSBs), they can set the 'wtap_dumper::dsbs_initial' field.

The test file was creating using a patched editcap (future patch) and
combined using mergecap (which required a change to preserve the DSBs).

Change-Id: I74e4ee3171bd852a89ea0f6fbae9e0f65ed6eda9
Ping-Bug: 15252
Reviewed-on: https://code.wireshark.org/review/30692
Reviewed-by: Peter Wu <peter@lekensteyn.nl>
Petri-Dish: Peter Wu <peter@lekensteyn.nl>
Tested-by: Petri Dish Buildbot
Reviewed-by: Anders Broman <a.broman58@gmail.com>
2018-11-20 05:12:37 +00:00

1280 lines
37 KiB
C

/* wtap_opttypes.c
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* Copyright 2001 Gerald Combs
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "config.h"
#include <glib.h>
#include <string.h>
#include "wtap.h"
#include "wtap_opttypes.h"
#include "wtap-int.h"
#include "pcapng.h"
#include "pcapng_module.h"
#if 0
#define wtap_debug(...) g_warning(__VA_ARGS__)
#else
#define wtap_debug(...)
#endif
/*
* Structure describing a type of block.
*/
typedef struct {
wtap_block_type_t block_type; /**< internal type code for block */
const char *name; /**< name of block */
const char *description; /**< human-readable description of block */
wtap_block_create_func create;
wtap_mand_free_func free_mand;
wtap_mand_copy_func copy_mand;
GArray *options; /**< array of known options */
} wtap_blocktype_t;
typedef void *(*wtap_opttype_dup_custom_func)(void* src);
typedef void (*wtap_opttype_free_custom_func)(void* data);
/*
* Structure describing a type of option.
*/
typedef struct {
const char *name; /**< name of option */
const char *description; /**< human-readable description of option */
wtap_opttype_e data_type; /**< data type of that option */
guint flags; /**< flags for the option */
wtap_opttype_dup_custom_func dup_func; /**< function to duplicate custom option data */
wtap_opttype_free_custom_func free_func; /**< function to free custom option data */
} wtap_opttype_t;
/* Flags */
#define WTAP_OPTTYPE_FLAG_MULTIPLE_ALLOWED 0x00000001 /* multiple instances allowed */
struct wtap_block
{
wtap_blocktype_t* info;
void* mandatory_data;
GArray* options;
};
#define MAX_WTAP_BLOCK_CUSTOM 10
#define MAX_WTAP_BLOCK_TYPE_VALUE (WTAP_BLOCK_END_OF_LIST+MAX_WTAP_BLOCK_CUSTOM)
/* Keep track of wtap_blocktype_t's via their id number */
static wtap_blocktype_t* blocktype_list[MAX_WTAP_BLOCK_TYPE_VALUE];
static guint num_custom_blocks;
static wtap_blocktype_t custom_blocktype_list[MAX_WTAP_BLOCK_CUSTOM];
static void wtap_opttype_block_register(wtap_block_type_t block_type, wtap_blocktype_t *blocktype)
{
static const wtap_opttype_t opt_comment = {
"opt_comment",
"Comment",
WTAP_OPTTYPE_STRING,
WTAP_OPTTYPE_FLAG_MULTIPLE_ALLOWED,
NULL,
NULL
};
/* Check input */
g_assert(block_type < WTAP_BLOCK_END_OF_LIST);
/* Don't re-register. */
g_assert(blocktype_list[block_type] == NULL);
/* Sanity check */
g_assert(blocktype->name);
g_assert(blocktype->description);
g_assert(blocktype->create);
blocktype->block_type = block_type;
/*
* Initialize the set of supported options.
* All blocks that support options at all support OPT_COMMENT.
*/
blocktype->options = g_array_sized_new(FALSE, TRUE, sizeof (wtap_opttype_t), OPT_COMMENT + 1);
if (OPT_COMMENT + 1 > blocktype->options->len)
g_array_set_size(blocktype->options, OPT_COMMENT + 1);
g_array_insert_val(blocktype->options, OPT_COMMENT, opt_comment);
blocktype_list[block_type] = blocktype;
}
int wtap_opttype_register_custom_block_type(const char* name, const char* description, wtap_block_create_func create,
wtap_mand_free_func free_mand, wtap_mand_copy_func copy_mand)
{
int block_type;
/* Ensure valid data/functions for required fields */
g_assert(name);
g_assert(description);
g_assert(create);
/* This shouldn't happen, so flag it for fixing */
g_assert(num_custom_blocks < MAX_WTAP_BLOCK_CUSTOM);
block_type = (wtap_block_type_t)(WTAP_BLOCK_END_OF_LIST+num_custom_blocks);
custom_blocktype_list[num_custom_blocks].name = name;
custom_blocktype_list[num_custom_blocks].description = description;
custom_blocktype_list[num_custom_blocks].create = create;
custom_blocktype_list[num_custom_blocks].free_mand = free_mand;
custom_blocktype_list[num_custom_blocks].copy_mand = copy_mand;
blocktype_list[block_type] = &custom_blocktype_list[num_custom_blocks];
num_custom_blocks++;
return block_type;
}
static void wtap_opttype_option_register(wtap_blocktype_t *blocktype, int opttype, wtap_opttype_t *option)
{
if ((guint)opttype + 1 > blocktype->options->len)
g_array_set_size(blocktype->options, opttype + 1);
g_array_insert_val(blocktype->options, opttype, *option);
}
void* wtap_block_get_mandatory_data(wtap_block_t block)
{
return block->mandatory_data;
}
static wtap_optval_t *
wtap_block_get_option(wtap_block_t block, guint option_id)
{
guint i;
wtap_option_t *opt;
for (i = 0; i < block->options->len; i++) {
opt = &g_array_index(block->options, wtap_option_t, i);
if (opt->option_id == option_id)
return &opt->value;
}
return NULL;
}
static wtap_optval_t *
wtap_block_get_nth_option(wtap_block_t block, guint option_id, guint idx)
{
guint i;
wtap_option_t *opt;
guint opt_idx;
opt_idx = 0;
for (i = 0; i < block->options->len; i++) {
opt = &g_array_index(block->options, wtap_option_t, i);
if (opt->option_id == option_id) {
if (opt_idx == idx)
return &opt->value;
opt_idx++;
}
}
return NULL;
}
wtap_block_t wtap_block_create(wtap_block_type_t block_type)
{
wtap_block_t block;
if (block_type >= (wtap_block_type_t)(WTAP_BLOCK_END_OF_LIST+num_custom_blocks))
return NULL;
block = g_new(struct wtap_block, 1);
block->info = blocktype_list[block_type];
block->options = g_array_new(FALSE, FALSE, sizeof(wtap_option_t));
block->info->create(block);
return block;
}
static void wtap_block_free_option(wtap_block_t block, wtap_option_t *opt)
{
wtap_opttype_t *opttype;
opttype = &g_array_index(block->info->options, wtap_opttype_t, opt->option_id);
switch (opttype->data_type) {
case WTAP_OPTTYPE_STRING:
g_free(opt->value.stringval);
break;
case WTAP_OPTTYPE_CUSTOM:
opttype->free_func(opt->value.customval.data);
g_free(opt->value.customval.data);
break;
default:
break;
}
}
static void wtap_block_free_options(wtap_block_t block)
{
guint i;
wtap_option_t *opt;
for (i = 0; i < block->options->len; i++) {
opt = &g_array_index(block->options, wtap_option_t, i);
wtap_block_free_option(block, opt);
}
}
void wtap_block_free(wtap_block_t block)
{
if (block != NULL)
{
if (block->info->free_mand != NULL)
block->info->free_mand(block);
g_free(block->mandatory_data);
wtap_block_free_options(block);
g_array_free(block->options, TRUE);
g_free(block);
}
}
void wtap_block_array_free(GArray* block_array)
{
guint block;
if (block_array == NULL)
return;
for (block = 0; block < block_array->len; block++) {
wtap_block_free(g_array_index(block_array, wtap_block_t, block));
}
g_array_free(block_array, TRUE);
}
/*
* Make a copy of a block.
*/
void
wtap_block_copy(wtap_block_t dest_block, wtap_block_t src_block)
{
guint i;
wtap_option_t *src_opt;
wtap_opttype_t *opttype;
/*
* Copy the mandatory data.
*/
if (dest_block->info->copy_mand != NULL)
dest_block->info->copy_mand(dest_block, src_block);
/* Copy the options. For now, don't remove any options that are in destination
* but not source.
*/
for (i = 0; i < src_block->options->len; i++)
{
src_opt = &g_array_index(src_block->options, wtap_option_t, i);
opttype = &g_array_index(src_block->info->options, wtap_opttype_t, src_opt->option_id);
switch(opttype->data_type) {
case WTAP_OPTTYPE_UINT8:
wtap_block_add_uint8_option(dest_block, src_opt->option_id, src_opt->value.uint8val);
break;
case WTAP_OPTTYPE_UINT64:
wtap_block_add_uint64_option(dest_block, src_opt->option_id, src_opt->value.uint64val);
break;
case WTAP_OPTTYPE_IPv4:
wtap_block_add_ipv4_option(dest_block, src_opt->option_id, src_opt->value.ipv4val);
break;
case WTAP_OPTTYPE_IPv6:
wtap_block_add_ipv6_option(dest_block, src_opt->option_id, &src_opt->value.ipv6val);
break;
case WTAP_OPTTYPE_STRING:
wtap_block_add_string_option(dest_block, src_opt->option_id, src_opt->value.stringval, strlen(src_opt->value.stringval));
break;
case WTAP_OPTTYPE_CUSTOM:
wtap_block_add_custom_option(dest_block, src_opt->option_id, src_opt->value.customval.data, src_opt->value.customval.size);
break;
}
}
}
void wtap_block_foreach_option(wtap_block_t block, wtap_block_foreach_func func, void* user_data)
{
guint i;
wtap_option_t *opt;
wtap_opttype_t *opttype;
for (i = 0; i < block->options->len; i++) {
opt = &g_array_index(block->options, wtap_option_t, i);
opttype = &g_array_index(block->info->options, wtap_opttype_t, opt->option_id);
func(block, opt->option_id, opttype->data_type, &opt->value, user_data);
}
}
static wtap_opttype_return_val
wtap_block_add_option_common(wtap_block_t block, guint option_id, wtap_opttype_e type, wtap_option_t **optp)
{
wtap_option_t *opt;
wtap_opttype_t *opttype;
guint i;
if (option_id >= block->info->options->len) {
/* There's no option for this block with that option ID */
return WTAP_OPTTYPE_NO_SUCH_OPTION;
}
opttype = &g_array_index(block->info->options, wtap_opttype_t, option_id);
/*
* Is this an option of the specified data type?
*/
if (opttype->data_type != type) {
/*
* No.
*/
return WTAP_OPTTYPE_TYPE_MISMATCH;
}
/*
* Can there be more than one instance of this option?
*/
if (!(opttype->flags & WTAP_OPTTYPE_FLAG_MULTIPLE_ALLOWED)) {
/*
* No. Is there already an instance of this option?
*/
if (wtap_block_get_option(block, option_id) != NULL) {
/*
* Yes. Fail.
*/
return WTAP_OPTTYPE_ALREADY_EXISTS;
}
}
/*
* Add an instance.
*/
i = block->options->len;
g_array_set_size(block->options, i + 1);
opt = &g_array_index(block->options, wtap_option_t, i);
opt->option_id = option_id;
*optp = opt;
return WTAP_OPTTYPE_SUCCESS;
}
static wtap_opttype_return_val
wtap_block_get_option_common(wtap_block_t block, guint option_id, wtap_opttype_e type, wtap_optval_t **optvalp)
{
wtap_opttype_t *opttype;
wtap_optval_t *optval;
if (option_id >= block->info->options->len) {
/* There's no option for this block with that option ID */
return WTAP_OPTTYPE_NO_SUCH_OPTION;
}
opttype = &g_array_index(block->info->options, wtap_opttype_t, option_id);
/*
* Is this an option of the specified data type?
*/
if (opttype->data_type != type) {
/*
* No.
*/
return WTAP_OPTTYPE_TYPE_MISMATCH;
}
/*
* Can there be more than one instance of this option?
*/
if (opttype->flags & WTAP_OPTTYPE_FLAG_MULTIPLE_ALLOWED) {
/*
* Yes. You can't ask for "the" value.
*/
return WTAP_OPTTYPE_NUMBER_MISMATCH;
}
optval = wtap_block_get_option(block, option_id);
if (optval == NULL) {
/* Didn't find the option */
return WTAP_OPTTYPE_NOT_FOUND;
}
*optvalp = optval;
return WTAP_OPTTYPE_SUCCESS;
}
static wtap_opttype_return_val
wtap_block_get_nth_option_common(wtap_block_t block, guint option_id, wtap_opttype_e type, guint idx, wtap_optval_t **optvalp)
{
wtap_opttype_t *opttype;
wtap_optval_t *optval;
if (option_id >= block->info->options->len) {
/* There's no option for this block with that option ID */
return WTAP_OPTTYPE_NO_SUCH_OPTION;
}
opttype = &g_array_index(block->info->options, wtap_opttype_t, option_id);
/*
* Is this an option of the specified data type?
*/
if (opttype->data_type != type) {
/*
* No.
*/
return WTAP_OPTTYPE_TYPE_MISMATCH;
}
/*
* Can there be more than one instance of this option?
*/
if (!(opttype->flags & WTAP_OPTTYPE_FLAG_MULTIPLE_ALLOWED)) {
/*
* No.
*/
return WTAP_OPTTYPE_NUMBER_MISMATCH;
}
optval = wtap_block_get_nth_option(block, option_id, idx);
if (optval == NULL) {
/* Didn't find the option */
return WTAP_OPTTYPE_NOT_FOUND;
}
*optvalp = optval;
return WTAP_OPTTYPE_SUCCESS;
}
wtap_opttype_return_val
wtap_block_add_uint8_option(wtap_block_t block, guint option_id, guint8 value)
{
wtap_opttype_return_val ret;
wtap_option_t *opt;
ret = wtap_block_add_option_common(block, option_id, WTAP_OPTTYPE_UINT8, &opt);
if (ret != WTAP_OPTTYPE_SUCCESS)
return ret;
opt->value.uint8val = value;
return WTAP_OPTTYPE_SUCCESS;
}
wtap_opttype_return_val
wtap_block_set_uint8_option_value(wtap_block_t block, guint option_id, guint8 value)
{
wtap_opttype_return_val ret;
wtap_optval_t *optval;
ret = wtap_block_get_option_common(block, option_id, WTAP_OPTTYPE_UINT8, &optval);
if (ret != WTAP_OPTTYPE_SUCCESS)
return ret;
optval->uint8val = value;
return WTAP_OPTTYPE_SUCCESS;
}
wtap_opttype_return_val
wtap_block_get_uint8_option_value(wtap_block_t block, guint option_id, guint8* value)
{
wtap_opttype_return_val ret;
wtap_optval_t *optval;
ret = wtap_block_get_option_common(block, option_id, WTAP_OPTTYPE_UINT8, &optval);
if (ret != WTAP_OPTTYPE_SUCCESS)
return ret;
*value = optval->uint8val;
return WTAP_OPTTYPE_SUCCESS;
}
wtap_opttype_return_val
wtap_block_add_uint64_option(wtap_block_t block, guint option_id, guint64 value)
{
wtap_opttype_return_val ret;
wtap_option_t *opt;
ret = wtap_block_add_option_common(block, option_id, WTAP_OPTTYPE_UINT64, &opt);
if (ret != WTAP_OPTTYPE_SUCCESS)
return ret;
opt->value.uint64val = value;
return WTAP_OPTTYPE_SUCCESS;
}
wtap_opttype_return_val
wtap_block_set_uint64_option_value(wtap_block_t block, guint option_id, guint64 value)
{
wtap_opttype_return_val ret;
wtap_optval_t *optval;
ret = wtap_block_get_option_common(block, option_id, WTAP_OPTTYPE_UINT64, &optval);
if (ret != WTAP_OPTTYPE_SUCCESS)
return ret;
optval->uint64val = value;
return WTAP_OPTTYPE_SUCCESS;
}
wtap_opttype_return_val
wtap_block_get_uint64_option_value(wtap_block_t block, guint option_id, guint64 *value)
{
wtap_opttype_return_val ret;
wtap_optval_t *optval;
ret = wtap_block_get_option_common(block, option_id, WTAP_OPTTYPE_UINT64, &optval);
if (ret != WTAP_OPTTYPE_SUCCESS)
return ret;
*value = optval->uint64val;
return WTAP_OPTTYPE_SUCCESS;
}
wtap_opttype_return_val
wtap_block_add_ipv4_option(wtap_block_t block, guint option_id, guint32 value)
{
wtap_opttype_return_val ret;
wtap_option_t *opt;
ret = wtap_block_add_option_common(block, option_id, WTAP_OPTTYPE_IPv4, &opt);
if (ret != WTAP_OPTTYPE_SUCCESS)
return ret;
opt->value.ipv4val = value;
return WTAP_OPTTYPE_SUCCESS;
}
wtap_opttype_return_val
wtap_block_set_ipv4_option_value(wtap_block_t block, guint option_id, guint32 value)
{
wtap_opttype_return_val ret;
wtap_optval_t *optval;
ret = wtap_block_get_option_common(block, option_id, WTAP_OPTTYPE_IPv4, &optval);
if (ret != WTAP_OPTTYPE_SUCCESS)
return ret;
optval->ipv4val = value;
return WTAP_OPTTYPE_SUCCESS;
}
wtap_opttype_return_val
wtap_block_get_ipv4_option_value(wtap_block_t block, guint option_id, guint32* value)
{
wtap_opttype_return_val ret;
wtap_optval_t *optval;
ret = wtap_block_get_option_common(block, option_id, WTAP_OPTTYPE_IPv4, &optval);
if (ret != WTAP_OPTTYPE_SUCCESS)
return ret;
*value = optval->ipv4val;
return WTAP_OPTTYPE_SUCCESS;
}
wtap_opttype_return_val
wtap_block_add_ipv6_option(wtap_block_t block, guint option_id, ws_in6_addr *value)
{
wtap_opttype_return_val ret;
wtap_option_t *opt;
ret = wtap_block_add_option_common(block, option_id, WTAP_OPTTYPE_IPv6, &opt);
if (ret != WTAP_OPTTYPE_SUCCESS)
return ret;
opt->value.ipv6val = *value;
return WTAP_OPTTYPE_SUCCESS;
}
wtap_opttype_return_val
wtap_block_set_ipv6_option_value(wtap_block_t block, guint option_id, ws_in6_addr *value)
{
wtap_opttype_return_val ret;
wtap_optval_t *optval;
ret = wtap_block_get_option_common(block, option_id, WTAP_OPTTYPE_IPv6, &optval);
if (ret != WTAP_OPTTYPE_SUCCESS)
return ret;
optval->ipv6val = *value;
return WTAP_OPTTYPE_SUCCESS;
}
wtap_opttype_return_val
wtap_block_get_ipv6_option_value(wtap_block_t block, guint option_id, ws_in6_addr* value)
{
wtap_opttype_return_val ret;
wtap_optval_t *optval;
ret = wtap_block_get_option_common(block, option_id, WTAP_OPTTYPE_IPv4, &optval);
if (ret != WTAP_OPTTYPE_SUCCESS)
return ret;
*value = optval->ipv6val;
return WTAP_OPTTYPE_SUCCESS;
}
wtap_opttype_return_val
wtap_block_add_string_option(wtap_block_t block, guint option_id, const char *value, gsize value_length)
{
wtap_opttype_return_val ret;
wtap_option_t *opt;
ret = wtap_block_add_option_common(block, option_id, WTAP_OPTTYPE_STRING, &opt);
if (ret != WTAP_OPTTYPE_SUCCESS)
return ret;
opt->value.stringval = g_strndup(value, value_length);
return WTAP_OPTTYPE_SUCCESS;
}
static wtap_opttype_return_val
wtap_block_add_string_option_vformat(wtap_block_t block, guint option_id, const char *format, va_list va)
{
wtap_opttype_return_val ret;
wtap_option_t *opt;
ret = wtap_block_add_option_common(block, option_id, WTAP_OPTTYPE_STRING, &opt);
if (ret != WTAP_OPTTYPE_SUCCESS)
return ret;
opt->value.stringval = g_strdup_vprintf(format, va);
return WTAP_OPTTYPE_SUCCESS;
}
wtap_opttype_return_val
wtap_block_add_string_option_format(wtap_block_t block, guint option_id, const char *format, ...)
{
wtap_opttype_return_val ret;
wtap_option_t *opt;
va_list va;
ret = wtap_block_add_option_common(block, option_id, WTAP_OPTTYPE_STRING, &opt);
if (ret != WTAP_OPTTYPE_SUCCESS)
return ret;
va_start(va, format);
opt->value.stringval = g_strdup_vprintf(format, va);
va_end(va);
return WTAP_OPTTYPE_SUCCESS;
}
wtap_opttype_return_val
wtap_block_set_string_option_value(wtap_block_t block, guint option_id, const char *value, size_t value_length)
{
wtap_opttype_return_val ret;
wtap_optval_t *optval;
ret = wtap_block_get_option_common(block, option_id, WTAP_OPTTYPE_STRING, &optval);
if (ret != WTAP_OPTTYPE_SUCCESS) {
if (ret == WTAP_OPTTYPE_NOT_FOUND) {
/*
* There's no instance to set, so just try to create a new one
* with the value.
*/
return wtap_block_add_string_option(block, option_id, value, value_length);
}
/* Otherwise fail. */
return ret;
}
g_free(optval->stringval);
optval->stringval = g_strndup(value, value_length);
return WTAP_OPTTYPE_SUCCESS;
}
wtap_opttype_return_val
wtap_block_set_nth_string_option_value(wtap_block_t block, guint option_id, guint idx, const char *value, size_t value_length)
{
wtap_opttype_return_val ret;
wtap_optval_t *optval;
ret = wtap_block_get_nth_option_common(block, option_id, WTAP_OPTTYPE_STRING, idx, &optval);
if (ret != WTAP_OPTTYPE_SUCCESS)
return ret;
g_free(optval->stringval);
optval->stringval = g_strndup(value, value_length);
return WTAP_OPTTYPE_SUCCESS;
}
wtap_opttype_return_val
wtap_block_set_string_option_value_format(wtap_block_t block, guint option_id, const char *format, ...)
{
wtap_opttype_return_val ret;
wtap_optval_t *optval;
va_list va;
ret = wtap_block_get_option_common(block, option_id, WTAP_OPTTYPE_STRING, &optval);
if (ret != WTAP_OPTTYPE_SUCCESS) {
if (ret == WTAP_OPTTYPE_NOT_FOUND) {
/*
* There's no instance to set, so just try to create a new one
* with the formatted string.
*/
va_start(va, format);
ret = wtap_block_add_string_option_vformat(block, option_id, format, va);
va_end(va);
return ret;
}
/* Otherwise fail. */
return ret;
}
g_free(optval->stringval);
va_start(va, format);
optval->stringval = g_strdup_vprintf(format, va);
va_end(va);
return WTAP_OPTTYPE_SUCCESS;
}
wtap_opttype_return_val
wtap_block_get_string_option_value(wtap_block_t block, guint option_id, char** value)
{
wtap_opttype_return_val ret;
wtap_optval_t *optval;
ret = wtap_block_get_option_common(block, option_id, WTAP_OPTTYPE_STRING, &optval);
if (ret != WTAP_OPTTYPE_SUCCESS)
return ret;
*value = optval->stringval;
return WTAP_OPTTYPE_SUCCESS;
}
wtap_opttype_return_val
wtap_block_get_nth_string_option_value(wtap_block_t block, guint option_id, guint idx, char** value)
{
wtap_opttype_return_val ret;
wtap_optval_t *optval;
ret = wtap_block_get_nth_option_common(block, option_id, WTAP_OPTTYPE_STRING, idx, &optval);
if (ret != WTAP_OPTTYPE_SUCCESS)
return ret;
*value = optval->stringval;
return WTAP_OPTTYPE_SUCCESS;
}
wtap_opttype_return_val
wtap_block_add_custom_option(wtap_block_t block, guint option_id, void *value, size_t value_size)
{
wtap_opttype_return_val ret;
wtap_option_t *opt;
wtap_opttype_t *opttype;
ret = wtap_block_add_option_common(block, option_id, WTAP_OPTTYPE_CUSTOM, &opt);
if (ret != WTAP_OPTTYPE_SUCCESS)
return ret;
opttype = &g_array_index(block->info->options, wtap_opttype_t, opt->option_id);
opt->value.customval.size = (guint)value_size;
opt->value.customval.data = opttype->dup_func(value);
return WTAP_OPTTYPE_SUCCESS;
}
wtap_opttype_return_val
wtap_block_get_custom_option_value(wtap_block_t block, guint option_id, void** value)
{
wtap_opttype_return_val ret;
wtap_optval_t *optval;
ret = wtap_block_get_option_common(block, option_id, WTAP_OPTTYPE_CUSTOM, &optval);
if (ret != WTAP_OPTTYPE_SUCCESS)
return ret;
*value = optval->customval.data;
return WTAP_OPTTYPE_SUCCESS;
}
wtap_opttype_return_val
wtap_block_set_custom_option_value(wtap_block_t block, guint option_id, void *value)
{
wtap_opttype_return_val ret;
wtap_optval_t *optval;
void *prev_value;
ret = wtap_block_get_option_common(block, option_id, WTAP_OPTTYPE_CUSTOM, &optval);
if (ret != WTAP_OPTTYPE_SUCCESS)
return ret;
prev_value = optval->customval.data;
/*
* XXX - a custom value can be a structure that points to other data,
* but we're doing a shallow copy here.
*/
optval->customval.data = g_memdup(value, optval->customval.size);
/* Free after memory is duplicated in case structure was manipulated with a "get then set" */
g_free(prev_value);
return WTAP_OPTTYPE_SUCCESS;
}
wtap_opttype_return_val
wtap_block_remove_option(wtap_block_t block, guint option_id)
{
wtap_opttype_t *opttype;
guint i;
wtap_option_t *opt;
if (option_id >= block->info->options->len) {
/* There's no option for this block with that option ID */
return WTAP_OPTTYPE_NO_SUCH_OPTION;
}
opttype = &g_array_index(block->info->options, wtap_opttype_t, option_id);
/*
* Can there be more than one instance of this option?
*/
if (opttype->flags & WTAP_OPTTYPE_FLAG_MULTIPLE_ALLOWED) {
/*
* Yes. You can't remove "the" value.
*/
return WTAP_OPTTYPE_NUMBER_MISMATCH;
}
for (i = 0; i < block->options->len; i++) {
opt = &g_array_index(block->options, wtap_option_t, i);
if (opt->option_id == option_id) {
/* Found it - free up the value */
wtap_block_free_option(block, opt);
/* Remove the option from the array of options */
g_array_remove_index(block->options, i);
return WTAP_OPTTYPE_SUCCESS;
}
}
/* Didn't find the option */
return WTAP_OPTTYPE_NOT_FOUND;
}
wtap_opttype_return_val
wtap_block_remove_nth_option_instance(wtap_block_t block, guint option_id,
guint idx)
{
wtap_opttype_t *opttype;
guint i;
wtap_option_t *opt;
guint opt_idx;
if (option_id >= block->info->options->len) {
/* There's no option for this block with that option ID */
return WTAP_OPTTYPE_NO_SUCH_OPTION;
}
opttype = &g_array_index(block->info->options, wtap_opttype_t, option_id);
/*
* Can there be more than one instance of this option?
*/
if (!(opttype->flags & WTAP_OPTTYPE_FLAG_MULTIPLE_ALLOWED)) {
/*
* No.
*/
return WTAP_OPTTYPE_NUMBER_MISMATCH;
}
opt_idx = 0;
for (i = 0; i < block->options->len; i++) {
opt = &g_array_index(block->options, wtap_option_t, i);
if (opt->option_id == option_id) {
if (opt_idx == idx) {
/* Found it - free up the value */
wtap_block_free_option(block, opt);
/* Remove the option from the array of options */
g_array_remove_index(block->options, i);
return WTAP_OPTTYPE_SUCCESS;
}
opt_idx++;
}
}
/* Didn't find the option */
return WTAP_OPTTYPE_NOT_FOUND;
}
static void shb_create(wtap_block_t block)
{
wtapng_mandatory_section_t* section_mand = g_new(wtapng_mandatory_section_t, 1);
section_mand->section_length = -1;
block->mandatory_data = section_mand;
}
static void shb_copy_mand(wtap_block_t dest_block, wtap_block_t src_block)
{
memcpy(dest_block->mandatory_data, src_block->mandatory_data, sizeof(wtapng_mandatory_section_t));
}
static void nrb_create(wtap_block_t block)
{
block->mandatory_data = NULL;
}
static void isb_create(wtap_block_t block)
{
block->mandatory_data = g_new0(wtapng_if_stats_mandatory_t, 1);
}
static void isb_copy_mand(wtap_block_t dest_block, wtap_block_t src_block)
{
memcpy(dest_block->mandatory_data, src_block->mandatory_data, sizeof(wtapng_if_stats_mandatory_t));
}
static void *idb_filter_dup(void* src)
{
wtapng_if_descr_filter_t* filter_src = (wtapng_if_descr_filter_t*)src;
wtapng_if_descr_filter_t* filter_dest;
/* Deep copy. */
filter_dest = g_new(wtapng_if_descr_filter_t, 1);
filter_dest->if_filter_str = g_strdup(filter_src->if_filter_str);
filter_dest->bpf_filter_len = filter_src->bpf_filter_len;
filter_dest->if_filter_bpf_bytes = (guint8 *)g_memdup(filter_src->if_filter_bpf_bytes, filter_src->bpf_filter_len);
return (void *)filter_dest;
}
static void idb_filter_free(void* data)
{
wtapng_if_descr_filter_t* filter = (wtapng_if_descr_filter_t*)data;
g_free(filter->if_filter_str);
g_free(filter->if_filter_bpf_bytes);
}
static void idb_create(wtap_block_t block)
{
block->mandatory_data = g_new0(wtapng_if_descr_mandatory_t, 1);
}
static void idb_free_mand(wtap_block_t block)
{
guint j;
wtap_block_t if_stats;
wtapng_if_descr_mandatory_t* mand = (wtapng_if_descr_mandatory_t*)block->mandatory_data;
for(j = 0; j < mand->num_stat_entries; j++) {
if_stats = g_array_index(mand->interface_statistics, wtap_block_t, j);
wtap_block_free(if_stats);
}
if (mand->interface_statistics)
g_array_free(mand->interface_statistics, TRUE);
}
static void idb_copy_mand(wtap_block_t dest_block, wtap_block_t src_block)
{
guint j;
wtap_block_t src_if_stats, dest_if_stats;
wtapng_if_descr_mandatory_t *src_mand = (wtapng_if_descr_mandatory_t*)src_block->mandatory_data,
*dest_mand = (wtapng_if_descr_mandatory_t*)dest_block->mandatory_data;
/* Need special consideration for copying of the interface_statistics member */
if (dest_mand->num_stat_entries != 0)
g_array_free(dest_mand->interface_statistics, TRUE);
memcpy(dest_mand, src_mand, sizeof(wtapng_if_descr_mandatory_t));
if (src_mand->num_stat_entries != 0)
{
dest_mand->interface_statistics = g_array_new(FALSE, FALSE, sizeof(wtap_block_t));
for (j = 0; j < src_mand->num_stat_entries; j++)
{
src_if_stats = g_array_index(src_mand->interface_statistics, wtap_block_t, j);
dest_if_stats = wtap_block_create(WTAP_BLOCK_IF_STATS);
wtap_block_copy(dest_if_stats, src_if_stats);
dest_mand->interface_statistics = g_array_append_val(dest_mand->interface_statistics, dest_if_stats);
}
}
}
static void dsb_create(wtap_block_t block)
{
block->mandatory_data = g_new0(wtapng_dsb_mandatory_t, 1);
}
static void dsb_free_mand(wtap_block_t block)
{
wtapng_dsb_mandatory_t *mand = (wtapng_dsb_mandatory_t *)block->mandatory_data;
g_free(mand->secrets_data);
}
static void dsb_copy_mand(wtap_block_t dest_block, wtap_block_t src_block)
{
wtapng_dsb_mandatory_t *src = (wtapng_dsb_mandatory_t *)src_block->mandatory_data;
wtapng_dsb_mandatory_t *dst = (wtapng_dsb_mandatory_t *)dest_block->mandatory_data;
dst->secrets_type = src->secrets_type;
dst->secrets_len = src->secrets_len;
g_free(dst->secrets_data);
dst->secrets_data = (guint8 *)g_memdup(src->secrets_data, src->secrets_len);
}
void wtap_opttypes_initialize(void)
{
static wtap_blocktype_t shb_block = {
WTAP_BLOCK_NG_SECTION, /* block_type */
"SHB", /* name */
"Section Header Block", /* description */
shb_create, /* create */
NULL, /* free_mand */
shb_copy_mand, /* copy_mand */
NULL /* options */
};
static wtap_opttype_t shb_hardware = {
"hardware",
"SHB Hardware",
WTAP_OPTTYPE_STRING,
0,
NULL,
NULL
};
static wtap_opttype_t shb_os = {
"os",
"SHB Operating System",
WTAP_OPTTYPE_STRING,
0,
NULL,
NULL
};
static wtap_opttype_t shb_userappl = {
"user_appl",
"SHB User Application",
WTAP_OPTTYPE_STRING,
0,
NULL,
NULL
};
static wtap_blocktype_t idb_block = {
WTAP_BLOCK_IF_DESCR, /* block_type */
"IDB", /* name */
"Interface Description Block", /* description */
idb_create, /* create */
idb_free_mand, /* free_mand */
idb_copy_mand, /* copy_mand */
NULL /* options */
};
static wtap_opttype_t if_name = {
"name",
"IDB Name",
WTAP_OPTTYPE_STRING,
0,
NULL,
NULL
};
static wtap_opttype_t if_description = {
"description",
"IDB Description",
WTAP_OPTTYPE_STRING,
0,
NULL,
NULL
};
static wtap_opttype_t if_speed = {
"speed",
"IDB Speed",
WTAP_OPTTYPE_UINT64,
0,
NULL,
NULL
};
static wtap_opttype_t if_tsresol = {
"tsresol",
"IDB Time Stamp Resolution",
WTAP_OPTTYPE_UINT8, /* XXX - signed? */
0,
NULL,
NULL
};
static wtap_opttype_t if_filter = {
"filter",
"IDB Filter",
WTAP_OPTTYPE_CUSTOM,
0,
idb_filter_dup,
idb_filter_free
};
static wtap_opttype_t if_os = {
"os",
"IDB Operating System",
WTAP_OPTTYPE_STRING,
0,
NULL,
NULL
};
static wtap_opttype_t if_fcslen = {
"fcslen",
"IDB FCS Length",
WTAP_OPTTYPE_UINT8,
0,
NULL,
NULL
};
static wtap_opttype_t if_hardware = {
"hardware",
"IDB Hardware",
WTAP_OPTTYPE_STRING,
0,
NULL,
NULL
};
static wtap_blocktype_t dsb_block = {
WTAP_BLOCK_DSB,
"DSB",
"Decryption Secrets Block",
dsb_create,
dsb_free_mand,
dsb_copy_mand,
NULL
};
static wtap_blocktype_t nrb_block = {
WTAP_BLOCK_NG_NRB, /* block_type */
"NRB", /* name */
"Name Resolution Block", /* description */
nrb_create, /* create */
NULL, /* free_mand */
NULL, /* copy_mand */
NULL /* options */
};
static wtap_opttype_t ns_dnsname = {
"dnsname",
"NRB DNS server name",
WTAP_OPTTYPE_STRING,
0,
NULL,
NULL
};
static wtap_opttype_t ns_dnsIP4addr = {
"dnsIP4addr",
"NRB DNS server IPv4 address",
WTAP_OPTTYPE_IPv4,
0,
NULL,
NULL
};
static wtap_opttype_t ns_dnsIP6addr = {
"dnsIP6addr",
"NRB DNS server IPv6 address",
WTAP_OPTTYPE_IPv6,
0,
NULL,
NULL
};
static wtap_blocktype_t isb_block = {
WTAP_BLOCK_IF_STATS, /* block_type */
"ISB", /* name */
"Interface Statistics Block", /* description */
isb_create, /* create */
NULL, /* free_mand */
isb_copy_mand, /* copy_mand */
NULL /* options */
};
static wtap_opttype_t isb_starttime = {
"starttime",
"ISB Start Time",
WTAP_OPTTYPE_UINT64,
0,
NULL,
NULL
};
static wtap_opttype_t isb_endtime = {
"endtime",
"ISB End Time",
WTAP_OPTTYPE_UINT64,
0,
NULL,
NULL
};
static wtap_opttype_t isb_ifrecv = {
"ifrecv",
"ISB Received Packets",
WTAP_OPTTYPE_UINT64,
0,
NULL,
NULL
};
static wtap_opttype_t isb_ifdrop = {
"ifdrop",
"ISB Dropped Packets",
WTAP_OPTTYPE_UINT64,
0,
NULL,
NULL
};
static wtap_opttype_t isb_filteraccept = {
"filteraccept",
"ISB Packets Accepted By Filter",
WTAP_OPTTYPE_UINT64,
0,
NULL,
NULL
};
static wtap_opttype_t isb_osdrop = {
"osdrop",
"ISB Packets Dropped By The OS",
WTAP_OPTTYPE_UINT64,
0,
NULL,
NULL
};
static wtap_opttype_t isb_usrdeliv = {
"usrdeliv",
"ISB Packets Delivered To The User",
WTAP_OPTTYPE_UINT64,
0,
NULL,
NULL
};
/* Initialize the custom block array. This is for future proofing
"outside registered" block types (for NULL checking) */
memset(blocktype_list, 0, MAX_WTAP_BLOCK_TYPE_VALUE*sizeof(wtap_blocktype_t*));
num_custom_blocks = 0;
/*
* Register the SHB and the options that can appear in it.
*/
wtap_opttype_block_register(WTAP_BLOCK_NG_SECTION, &shb_block);
wtap_opttype_option_register(&shb_block, OPT_SHB_HARDWARE, &shb_hardware);
wtap_opttype_option_register(&shb_block, OPT_SHB_OS, &shb_os);
wtap_opttype_option_register(&shb_block, OPT_SHB_USERAPPL, &shb_userappl);
/*
* Register the IDB and the options that can appear in it.
*/
wtap_opttype_block_register(WTAP_BLOCK_IF_DESCR, &idb_block);
wtap_opttype_option_register(&idb_block, OPT_IDB_NAME, &if_name);
wtap_opttype_option_register(&idb_block, OPT_IDB_DESCR, &if_description);
wtap_opttype_option_register(&idb_block, OPT_IDB_SPEED, &if_speed);
wtap_opttype_option_register(&idb_block, OPT_IDB_TSRESOL, &if_tsresol);
wtap_opttype_option_register(&idb_block, OPT_IDB_FILTER, &if_filter);
wtap_opttype_option_register(&idb_block, OPT_IDB_OS, &if_os);
wtap_opttype_option_register(&idb_block, OPT_IDB_FCSLEN, &if_fcslen);
wtap_opttype_option_register(&idb_block, OPT_IDB_HARDWARE, &if_hardware);
/*
* Register the NRB and the options that can appear in it.
*/
wtap_opttype_block_register(WTAP_BLOCK_NG_NRB, &nrb_block);
wtap_opttype_option_register(&nrb_block, OPT_NS_DNSNAME, &ns_dnsname);
wtap_opttype_option_register(&nrb_block, OPT_NS_DNSIP4ADDR, &ns_dnsIP4addr);
wtap_opttype_option_register(&nrb_block, OPT_NS_DNSIP6ADDR, &ns_dnsIP6addr);
/*
* Register the ISB and the options that can appear in it.
*/
wtap_opttype_block_register(WTAP_BLOCK_IF_STATS, &isb_block);
wtap_opttype_option_register(&isb_block, OPT_ISB_STARTTIME, &isb_starttime);
wtap_opttype_option_register(&isb_block, OPT_ISB_ENDTIME, &isb_endtime);
wtap_opttype_option_register(&isb_block, OPT_ISB_IFRECV, &isb_ifrecv);
wtap_opttype_option_register(&isb_block, OPT_ISB_IFDROP, &isb_ifdrop);
wtap_opttype_option_register(&isb_block, OPT_ISB_FILTERACCEPT, &isb_filteraccept);
wtap_opttype_option_register(&isb_block, OPT_ISB_OSDROP, &isb_osdrop);
wtap_opttype_option_register(&isb_block, OPT_ISB_USRDELIV, &isb_usrdeliv);
/*
* Register the DSB, currently no options are defined.
*/
wtap_opttype_block_register(WTAP_BLOCK_DSB, &dsb_block);
}
void wtap_opttypes_cleanup(void)
{
guint block_type;
for (block_type = 0; block_type < (WTAP_BLOCK_END_OF_LIST+num_custom_blocks); block_type++) {
if (blocktype_list[block_type]) {
if (blocktype_list[block_type]->options)
g_array_free(blocktype_list[block_type]->options, TRUE);
blocktype_list[block_type] = NULL;
}
}
}