editcap, tshark: process IDBs in the middle of input files.

Instead of grabbing the set of IDBs found at open time, have a loop
using wtap_get_next_interface_description() to read all unread IDBs run
after opening the input file, after reading a packet from the input
file, and after getting an EOF on the input file.

Add a routine wtap_uses_interface_ids() to check whether the file type
and subtype for a dump file uses interface IDs and requires IDBs.  If
so, in the aforementioned loop, add the IDBs to the dump stream.

Add a routine wtap_dump_add_idb() to add IDBs to a dump stream.  Have it
call a file-format-specific routine to add the IDBs; the only file type
that supports it is pcapng, and it 1) writes out the IDB and 2) adds it
to the set of IDBs for the stream.

Add a wtap_dump_params_init_no_idbs() routine that prevents the IDBs
from the input file from being used to initialize the output file; use
it in cases where we're using the aforementioned loop to copy over IDBs.

Don't require any IDBs to be present when opening a pcapng file for
writing; 1) the simplest pcapng file has just an SHB in it, 2) that
requirement causes dumps that don't provide IDBs at open time to fail,
and 3) the real issue is that we don't want packets with an interface ID
not corresponding to a known IDB, and we already have a check for that.

(There are some hacks here; eventually, when everything processes the
IDBs in such a loop, we may be able to get rid of the "two favors of
dump parameter initialization" hack.)

Fixes #15844.

Addresses the same issue in #15502, but there are other issues there
that also need to be addressed.

In addition, the merge code also needs to be changed to handle this.
This commit is contained in:
Guy Harris 2020-10-22 01:10:57 -07:00
parent e16ef82d7c
commit d0270415a9
8 changed files with 192 additions and 28 deletions

View File

@ -61,6 +61,7 @@ libwiretap.so.0 libwiretap0 #MINVER#
wtap_deregister_file_type_subtype@Base 1.12.0~rc1
wtap_deregister_open_info@Base 1.12.0~rc1
wtap_dump@Base 1.9.1
wtap_dump_add_idb@Base 3.3.2
wtap_dump_can_compress@Base 1.9.1
wtap_dump_can_open@Base 1.9.1
wtap_dump_can_write@Base 1.9.1
@ -70,6 +71,7 @@ libwiretap.so.0 libwiretap0 #MINVER#
wtap_dump_file_encap_type@Base 1.9.1
wtap_dump_file_seek@Base 1.12.0~rc1
wtap_dump_file_tell@Base 1.12.0~rc1
wtap_dump_file_type_subtype@Base 3.3.2
wtap_dump_file_write@Base 1.12.0~rc1
wtap_dump_flush@Base 1.9.1
wtap_dump_get_needs_reload@Base 2.5.0
@ -80,6 +82,7 @@ libwiretap.so.0 libwiretap0 #MINVER#
wtap_dump_params_cleanup@Base 2.9.0
wtap_dump_params_discard_decryption_secrets@Base 3.0.0
wtap_dump_params_init@Base 2.9.0
wtap_dump_params_init_no_idbs@Base 3.3.2
wtap_dump_set_addrinfo_list@Base 1.9.1
wtap_dump_supports_comment_types@Base 1.9.1
wtap_encap_description@Base 2.9.1

View File

@ -1012,6 +1012,24 @@ editcap_dump_open(const char *filename, const wtap_dump_params *params,
return pdh;
}
static gboolean
process_new_idbs(wtap *wth, wtap_dumper *pdh, int *err, gchar **err_info)
{
wtap_block_t if_data;
while ((if_data = wtap_get_next_interface_description(wth)) != NULL) {
/*
* Only add IDBs if the output file requires interface IDs;
* otherwise, it doesn't support writing IDBs.
*/
if (wtap_uses_interface_ids(wtap_dump_file_type_subtype(pdh))) {
if (!wtap_dump_add_idb(pdh, if_data, err, err_info))
return FALSE;
}
}
return TRUE;
}
int
main(int argc, char *argv[])
{
@ -1555,7 +1573,7 @@ invalid_time:
}
}
wtap_dump_params_init(&params, wth);
wtap_dump_params_init_no_idbs(&params, wth);
/*
* Discard any secrets we read in while opening the file.
@ -1669,6 +1687,12 @@ invalid_time:
wtap_rec_init(&read_rec);
ws_buffer_init(&read_buf, 1514);
while (wtap_read(wth, &read_rec, &read_buf, &read_err, &read_err_info, &data_offset)) {
/*
* XXX - what about non-packet records in the file after this?
* We can *probably* ignore IDBs after this point, as they
* presumably indicate that we weren't capturing on that
* interface at this point, but what about, for example, NRBs?
*/
if (max_packet_number <= read_count)
break;
@ -1707,6 +1731,18 @@ invalid_time:
}
} /* first packet only handling */
/*
* Process whatever IDBs we haven't seen yet.
*/
if (!process_new_idbs(wth, pdh, &write_err, &write_err_info)) {
cfile_write_failure_message("editcap", argv[optind],
filename,
write_err, write_err_info,
read_count,
out_file_type_subtype);
ret = DUMP_ERROR;
goto clean_exit;
}
buf = ws_buffer_start_ptr(&read_buf);

View File

@ -3235,6 +3235,26 @@ process_packet_second_pass(capture_file *cf, epan_dissect_t *edt,
return passed || fdata->dependent_of_displayed;
}
static gboolean
process_new_idbs(wtap *wth, wtap_dumper *pdh, int *err, gchar **err_info)
{
wtap_block_t if_data;
while ((if_data = wtap_get_next_interface_description(wth)) != NULL) {
/*
* Only add IDBs if we're writing to a file and the output file
* requires interface IDs; otherwise, it doesn't support writing IDBs.
*/
if (pdh != NULL) {
if (wtap_uses_interface_ids(wtap_dump_file_type_subtype(pdh))) {
if (!wtap_dump_add_idb(pdh, if_data, err, err_info))
return FALSE;
}
}
}
return TRUE;
}
static pass_status_t
process_cap_file_second_pass(capture_file *cf, wtap_dumper *pdh,
int *err, gchar **err_info,
@ -3249,6 +3269,16 @@ process_cap_file_second_pass(capture_file *cf, wtap_dumper *pdh,
epan_dissect_t *edt = NULL;
pass_status_t status = PASS_SUCCEEDED;
/*
* Process whatever IDBs we haven't seen yet. This will be all
* the IDBs in the file, as we've finished reading it; they'll
* all be at the beginning of the output file.
*/
if (!process_new_idbs(cf->provider.wth, pdh, err, err_info)) {
*err_framenum = 0;
return PASS_WRITE_ERROR;
}
wtap_rec_init(&rec);
ws_buffer_init(&buf, 1514);
@ -3409,6 +3439,15 @@ process_cap_file_single_pass(capture_file *cf, wtap_dumper *pdh,
}
framenum++;
/*
* Process whatever IDBs we haven't seen yet.
*/
if (!process_new_idbs(cf->provider.wth, pdh, err, err_info)) {
*err_framenum = framenum;
status = PASS_WRITE_ERROR;
break;
}
tshark_debug("tshark: processing packet #%d", framenum);
reset_epan_mem(cf, edt, create_proto_tree, print_packet_info && print_details);
@ -3472,7 +3511,7 @@ process_cap_file(capture_file *cf, char *save_file, int out_file_type,
if (save_file != NULL) {
/* Set up to write to the capture file. */
wtap_dump_params_init(&params, cf->provider.wth);
wtap_dump_params_init_no_idbs(&params, cf->provider.wth);
/* If we don't have an application name add Tshark */
if (wtap_block_get_string_option_value(g_array_index(params.shb_hdrs, wtap_block_t, 0), OPT_SHB_USERAPPL, &shb_user_appl) != WTAP_OPTTYPE_SUCCESS) {

View File

@ -2329,19 +2329,21 @@ wtap_dump_init_dumper(int file_type_subtype, wtap_compression_type compression_t
wdh->nrb_hdrs = params->nrb_hdrs;
/* Set Interface Description Block data */
if (interfaces && interfaces->len) {
guint itf_count;
if (!params->dont_copy_idbs) { /* XXX */
guint itf_count;
/* Note: this memory is owned by wtap_dumper and will become
* invalid after wtap_dump_close. */
for (itf_count = 0; itf_count < interfaces->len; itf_count++) {
file_int_data = g_array_index(interfaces, wtap_block_t, itf_count);
file_int_data_mand = (wtapng_if_descr_mandatory_t*)wtap_block_get_mandatory_data(file_int_data);
descr = wtap_block_make_copy(file_int_data);
if ((params->encap != WTAP_ENCAP_PER_PACKET) && (params->encap != file_int_data_mand->wtap_encap)) {
descr_mand = (wtapng_if_descr_mandatory_t*)wtap_block_get_mandatory_data(descr);
descr_mand->wtap_encap = params->encap;
/* Note: this memory is owned by wtap_dumper and will become
* invalid after wtap_dump_close. */
for (itf_count = 0; itf_count < interfaces->len; itf_count++) {
file_int_data = g_array_index(interfaces, wtap_block_t, itf_count);
file_int_data_mand = (wtapng_if_descr_mandatory_t*)wtap_block_get_mandatory_data(file_int_data);
descr = wtap_block_make_copy(file_int_data);
if ((params->encap != WTAP_ENCAP_PER_PACKET) && (params->encap != file_int_data_mand->wtap_encap)) {
descr_mand = (wtapng_if_descr_mandatory_t*)wtap_block_get_mandatory_data(descr);
descr_mand->wtap_encap = params->encap;
}
g_array_append_val(wdh->interface_data, descr);
}
g_array_append_val(wdh->interface_data, descr);
}
} else {
int snaplen;
@ -2692,6 +2694,21 @@ wtap_dump_open_finish(wtap_dumper *wdh, int file_type_subtype, int *err,
return TRUE; /* success! */
}
gboolean
wtap_dump_add_idb(wtap_dumper *wdh, wtap_block_t idb, int *err,
gchar **err_info)
{
if (wdh->subtype_add_idb == NULL) {
/* Not supported. */
*err = WTAP_ERR_UNWRITABLE_REC_TYPE;
*err_info = g_strdup("Adding IDBs isn't supported by this file type");
return FALSE;
}
*err = 0;
*err_info = NULL;
return (wdh->subtype_add_idb)(wdh, idb, err, err_info);
}
gboolean
wtap_dump(wtap_dumper *wdh, const wtap_rec *rec,
const guint8 *pd, int *err, gchar **err_info)
@ -2751,6 +2768,12 @@ wtap_dump_close(wtap_dumper *wdh, int *err, gchar **err_info)
return ret;
}
int
wtap_dump_file_type_subtype(wtap_dumper *wdh)
{
return wdh->file_type_subtype;
}
gint64
wtap_get_bytes_dumped(wtap_dumper *wdh)
{

View File

@ -4763,6 +4763,24 @@ pcapng_write_if_descr_block(wtap_dumper *wdh, wtap_block_t int_data, int *err)
return TRUE;
}
static gboolean pcapng_add_idb(wtap_dumper *wdh, wtap_block_t idb,
int *err, gchar **err_info _U_)
{
wtap_block_t idb_copy;
/*
* Add a copy of this IDB to our array of IDBs.
*/
idb_copy = wtap_block_create(WTAP_BLOCK_IF_DESCR);
wtap_block_copy(idb_copy, idb);
g_array_append_val(wdh->interface_data, idb_copy);
/*
* And write it to the output file.
*/
return pcapng_write_if_descr_block(wdh, idb_copy, err);
}
static gboolean pcapng_dump(wtap_dumper *wdh,
const wtap_rec *rec,
const guint8 *pd, int *err, gchar **err_info)
@ -4885,23 +4903,16 @@ static gboolean pcapng_dump_finish(wtap_dumper *wdh, int *err,
/* Returns TRUE on success, FALSE on failure; sets "*err" to an error code on
failure */
gboolean
pcapng_dump_open(wtap_dumper *wdh, int *err, gchar **err_info)
pcapng_dump_open(wtap_dumper *wdh, int *err, gchar **err_info _U_)
{
guint i;
pcapng_debug("pcapng_dump_open");
/* This is a pcapng file */
wdh->subtype_add_idb = pcapng_add_idb;
wdh->subtype_write = pcapng_dump;
wdh->subtype_finish = pcapng_dump_finish;
// XXX IDBs should be optional.
if (wdh->interface_data->len == 0) {
pcapng_debug("There are no interfaces. Can't handle that...");
*err = WTAP_ERR_INTERNAL;
*err_info = g_strdup("pcapng: there are no interfaces");
return FALSE;
}
/* write the section header block */
if (!pcapng_write_section_header_block(wdh, err)) {
return FALSE;

View File

@ -80,6 +80,9 @@ struct wtap_dumper;
*/
typedef void *WFILE_T;
typedef gboolean (*subtype_add_idb_func)(struct wtap_dumper*, wtap_block_t,
int *, gchar **);
typedef gboolean (*subtype_write_func)(struct wtap_dumper*,
const wtap_rec *rec,
const guint8*, int*, gchar**);
@ -91,18 +94,19 @@ struct wtap_dumper {
int snaplen;
int encap;
wtap_compression_type compression_type;
gboolean needs_reload; /* TRUE if the file requires re-loading after saving with wtap */
gboolean needs_reload; /* TRUE if the file requires re-loading after saving with wtap */
gint64 bytes_dumped;
void *priv; /* this one holds per-file state and is free'd automatically by wtap_dump_close() */
void *wslua_data; /* this one holds wslua state info and is not free'd */
void *priv; /* this one holds per-file state and is free'd automatically by wtap_dump_close() */
void *wslua_data; /* this one holds wslua state info and is not free'd */
subtype_write_func subtype_write; /* write out a record */
subtype_finish_func subtype_finish; /* write out information to finish writing file */
subtype_add_idb_func subtype_add_idb; /* add an IDB, writing it as necessary */
subtype_write_func subtype_write; /* write out a record */
subtype_finish_func subtype_finish; /* write out information to finish writing file */
addrinfo_lists_t *addrinfo_lists; /**< Struct containing lists of resolved addresses */
GArray *shb_hdrs;
GArray *nrb_hdrs; /**< name resolution comment/custom_opt, or NULL */
GArray *nrb_hdrs; /**< name resolution comment/custom_opt, or NULL */
GArray *interface_data; /**< An array holding the interface data from pcapng IDB:s or equivalent(?) NULL if not present.*/
GArray *dsbs_initial; /**< An array of initial DSBs (of type wtap_block_t) */

View File

@ -449,6 +449,31 @@ wtap_dump_params_init(wtap_dump_params *params, wtap *wth)
* Refer to the DSBs from the input file, wtap_dump will then copy DSBs
* as they become available. */
params->dsbs_growing = wth->dsbs;
params->dont_copy_idbs = FALSE;
}
/*
* XXX - eventually, we should make this wtap_dump_params_init(),
* and have everything copy IDBs as they're read.
*/
void
wtap_dump_params_init_no_idbs(wtap_dump_params *params, wtap *wth)
{
memset(params, 0, sizeof(*params));
if (wth == NULL)
return;
params->encap = wtap_file_encap(wth);
params->snaplen = wtap_snapshot_length(wth);
params->tsprec = wtap_file_tsprec(wth);
params->shb_hdrs = wtap_file_get_shb_for_new_file(wth);
params->idb_inf = wtap_file_get_idb_info(wth);
params->nrb_hdrs = wtap_file_get_nrb_for_new_file(wth);
/* Assume that the input handle remains open until the dumper is closed.
* Refer to the DSBs from the input file, wtap_dump will then copy DSBs
* as they become available. */
params->dsbs_growing = wth->dsbs;
params->dont_copy_idbs = TRUE;
}
void

View File

@ -1576,6 +1576,7 @@ typedef struct wtap_dump_params {
const GArray *dsbs_growing; /**< DSBs that will be written while writing packets, or NULL.
This array may grow since the dumper was opened and will subsequently
be written before newer packets are written in wtap_dump. */
gboolean dont_copy_idbs; /**< XXX - don't copy IDBs; this should eventually always be the case. */
} wtap_dump_params;
/* Zero-initializer for wtap_dump_params. */
@ -2102,6 +2103,23 @@ gboolean wtap_dump_supports_comment_types(int filetype, guint32 comment_types);
WS_DLL_PUBLIC
void wtap_dump_params_init(wtap_dump_params *params, wtap *wth);
/**
* Initialize the per-file information based on an existing file, but
* don't copy over the interface information. Its contents must be freed
* according to the requirements of wtap_dump_params.
* If wth does not remain valid for the duration of the session, dsbs_growing
* MUST be cleared after this function.
*
* XXX - this should eventually become wtap_dump_params_init(), with all
* programs writing capture files copying IDBs over by hand, so that they
* handle IDBs in the middle of the file.
*
* @param params The parameters for wtap_dump_* to initialize.
* @param wth The wiretap session.
*/
WS_DLL_PUBLIC
void wtap_dump_params_init_no_idbs(wtap_dump_params *params, wtap *wth);
/**
* Remove any decryption secret information from the per-file information;
* used if we're stripping decryption secrets as we write the file.
@ -2191,11 +2209,16 @@ wtap_dumper* wtap_dump_open_stdout(int file_type_subtype,
int *err, gchar **err_info);
WS_DLL_PUBLIC
gboolean wtap_dump_add_idb(wtap_dumper *wdh, wtap_block_t idb, int *err,
gchar **err_info);
WS_DLL_PUBLIC
gboolean wtap_dump(wtap_dumper *, const wtap_rec *, const guint8 *,
int *err, gchar **err_info);
WS_DLL_PUBLIC
gboolean wtap_dump_flush(wtap_dumper *, int *);
WS_DLL_PUBLIC
int wtap_dump_file_type_subtype(wtap_dumper *wdh);
WS_DLL_PUBLIC
gint64 wtap_get_bytes_dumped(wtap_dumper *);
WS_DLL_PUBLIC
void wtap_set_bytes_dumped(wtap_dumper *wdh, gint64 bytes_dumped);