wiretap: Generate IDBs from packets when necessary

Add a routine to generate a dummy IDB from a packet record.

When pcapng is writing enhanced packet blocks and the source
doesn't provide an interface id, search through the list of
intereface ids for a match. If there isn't one, generate a new
one and use it.

This allows pcapng to write per-packet encapsulation when the
source doesn't provide IDBs.
This commit is contained in:
John Thacker 2023-06-03 11:48:37 -04:00
parent 9d6b2f5d8a
commit f4723eeb7e
4 changed files with 86 additions and 18 deletions

View File

@ -2337,11 +2337,13 @@ wtap_dump_init_dumper(int file_type_subtype, wtap_compression_type compression_t
* means that there are no interfaces, or they will be
* provided later when reading the file in single-pass mode.)
*
* For WTAP_ENCAP_PER_PACKET, we'll have to generate IDBs
* from packet records as they come in. (pcapng does this now.)
*
* XXX File types should provide their own IDBs (possibly
* fake ones generated by wtap_add_generated_idb()), in
* order to support being used as inputs for mergecap where
* pcapng is the output. This doesn't work for files with
* WTAP_ENCAP_PER_PACKET.
* pcapng is the output.
*/
descr = wtap_dump_params_generate_idb(params);
g_array_append_val(wdh->interface_data, descr);

View File

@ -53,6 +53,9 @@ pcapng_close(wtap *wth);
static gboolean
pcapng_encap_is_ft_specific(int encap);
static gboolean
pcapng_write_if_descr_block(wtap_dumper *wdh, wtap_block_t int_data, int *err);
/*
* Minimum block size = size of block header + size of block trailer.
*/
@ -4944,28 +4947,39 @@ pcapng_write_enhanced_packet_block(wtap_dumper *wdh, const wtap_rec *rec,
options_size = compute_options_size(rec->block, compute_epb_option_size);
}
/* write (enhanced) packet block header */
bh.block_type = BLOCK_TYPE_EPB;
bh.block_total_length = (guint32)sizeof(bh) + (guint32)sizeof(epb) + phdr_len + rec->rec_header.packet_header.caplen + pad_len + options_total_length + options_size + 4;
if (!wtap_dump_file_write(wdh, &bh, sizeof bh, err))
return FALSE;
/* write block fixed content */
/*
* Check the interface ID. Do this before writing the header,
* in case we need to add a new IDB.
*/
if (rec->presence_flags & WTAP_HAS_INTERFACE_ID)
epb.interface_id = rec->rec_header.packet_header.interface_id;
else {
/*
* XXX - we should support writing WTAP_ENCAP_PER_PACKET
* data to pcapng files even if we *don't* have interface
* IDs.
* The source isn't sending us IDBs. See if we already have a
* matching interface, and use it if so.
*/
epb.interface_id = 0;
for (epb.interface_id = 0; epb.interface_id < wdh->interface_data->len; ++epb.interface_id) {
int_data = g_array_index(wdh->interface_data, wtap_block_t,
epb.interface_id);
int_data_mand = (wtapng_if_descr_mandatory_t*)wtap_block_get_mandatory_data(int_data);
if (int_data_mand->wtap_encap == rec->rec_header.packet_header.pkt_encap) {
if (int_data_mand->tsprecision == rec->tsprec || (!(rec->presence_flags & WTAP_HAS_TS))) {
break;
}
}
}
if (epb.interface_id == wdh->interface_data->len) {
/*
* We don't have a matching IDB. Generate a new one
* and write it to the file.
*/
int_data = wtap_rec_generate_idb(rec);
g_array_append_val(wdh->interface_data, int_data);
if (!pcapng_write_if_descr_block(wdh, int_data, err)) {
return FALSE;
}
}
}
/*
* Split the 64-bit timestamp into two 32-bit pieces, using
* the time stamp resolution for the interface.
*/
if (epb.interface_id >= wdh->interface_data->len) {
/*
* Our caller is doing something bad.
@ -4989,6 +5003,19 @@ pcapng_write_enhanced_packet_block(wtap_dumper *wdh, const wtap_rec *rec,
rec->rec_header.packet_header.pkt_encap);
return FALSE;
}
/* write (enhanced) packet block header */
bh.block_type = BLOCK_TYPE_EPB;
bh.block_total_length = (guint32)sizeof(bh) + (guint32)sizeof(epb) + phdr_len + rec->rec_header.packet_header.caplen + pad_len + options_total_length + options_size + 4;
if (!wtap_dump_file_write(wdh, &bh, sizeof bh, err))
return FALSE;
/* write block fixed content */
/*
* Split the 64-bit timestamp into two 32-bit pieces, using
* the time stamp resolution for the interface.
*/
ts = ((guint64)rec->ts.secs) * int_data_mand->time_units_per_second +
(((guint64)rec->ts.nsecs) * int_data_mand->time_units_per_second) / 1000000000;
epb.timestamp_high = (guint32)(ts >> 32);

View File

@ -402,8 +402,33 @@ GArray* wtap_file_get_shb_for_new_file(wtap *wth);
WS_DLL_PUBLIC
void wtap_add_generated_idb(wtap *wth);
/**
* @brief Generate an IDB, given a set of dump parameters, using the
* parameters' encapsulation type, snapshot length, and time stamp
* resolution. For use when a dump file has a given encapsulation type,
* and the source is not passing IDBs.
* @note This requires that the encapsulation type and time stamp
* resolution not be per-packet; it will terminate the process
* if either of them are.
*
* @param params The wtap dump parameters.
*/
wtap_block_t wtap_dump_params_generate_idb(const wtap_dump_params *params);
/**
* @brief Generate an IDB, given a packet record, using the records's
* encapsulation type and time stamp resolution, and the default
* snap length for the encapsulation type. For use when a file has
* per-packet encapsulation, and the source is not passing along IDBs.
* @note This requires that the record type be REC_TYPE_PACKET, and the
* encapsulation type and time stamp resolution not be per-packet;
* it will terminate the process if any of them are.
*
* @param rec The packet record.
*/
wtap_block_t wtap_rec_generate_idb(const wtap_rec *rec);
/**
* @brief Gets new name resolution info for new file, based on existing info.
* @details Creates a new wtap_block_t of name resolution info and only

View File

@ -1822,6 +1822,20 @@ wtap_rec_cleanup(wtap_rec *rec)
ws_buffer_free(&rec->options_buf);
}
wtap_block_t
wtap_rec_generate_idb(const wtap_rec *rec)
{
int tsprec;
ws_assert(rec->rec_type == REC_TYPE_PACKET);
if (rec->presence_flags & WTAP_HAS_TS) {
tsprec = rec->tsprec;
} else {
tsprec = WTAP_TSPREC_USEC;
/* The default */
}
return wtap_generate_idb(rec->rec_header.packet_header.pkt_encap, tsprec, 0);
}
gboolean
wtap_seek_read(wtap *wth, gint64 seek_off, wtap_rec *rec, Buffer *buf,
int *err, gchar **err_info)