forked from osmocom/wireshark
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:
parent
e16ef82d7c
commit
d0270415a9
|
@ -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
|
||||
|
|
38
editcap.c
38
editcap.c
|
@ -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(¶ms, wth);
|
||||
wtap_dump_params_init_no_idbs(¶ms, 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);
|
||||
|
||||
|
|
41
tshark.c
41
tshark.c
|
@ -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(¶ms, cf->provider.wth);
|
||||
wtap_dump_params_init_no_idbs(¶ms, 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) {
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) */
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue