diff --git a/debian/libwiretap0.symbols b/debian/libwiretap0.symbols index 50e4bd8590..da7dcc1381 100644 --- a/debian/libwiretap0.symbols +++ b/debian/libwiretap0.symbols @@ -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 diff --git a/editcap.c b/editcap.c index 9bdb0e9b9d..e06324ff83 100644 --- a/editcap.c +++ b/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); diff --git a/tshark.c b/tshark.c index f2b91b7b44..7e543d2b92 100644 --- a/tshark.c +++ b/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) { diff --git a/wiretap/file_access.c b/wiretap/file_access.c index 43193343a6..48d2ba9925 100644 --- a/wiretap/file_access.c +++ b/wiretap/file_access.c @@ -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) { diff --git a/wiretap/pcapng.c b/wiretap/pcapng.c index 7d4f3bf7d1..d5c7fde82a 100644 --- a/wiretap/pcapng.c +++ b/wiretap/pcapng.c @@ -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; diff --git a/wiretap/wtap-int.h b/wiretap/wtap-int.h index 14ab66d584..7c7efb428d 100644 --- a/wiretap/wtap-int.h +++ b/wiretap/wtap-int.h @@ -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) */ diff --git a/wiretap/wtap.c b/wiretap/wtap.c index 5424577c4d..85afd468ce 100644 --- a/wiretap/wtap.c +++ b/wiretap/wtap.c @@ -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 diff --git a/wiretap/wtap.h b/wiretap/wtap.h index e4925b4753..6c64dd5e57 100644 --- a/wiretap/wtap.h +++ b/wiretap/wtap.h @@ -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);