wiretap, pcapng: Distinguish WTAP_ENCAP_UNKNOWN and _NONE

WTAP_ENCAP_UNKNOWN is used for two different cases:
1. Encapsulation type values that are unsupported by libwiretap or
bogus values (and thus "unknown" to libwiretap).

2. An initial state where the encapsulation type is "not yet" known
for a file type like pcapng without a single encapsulation type in the
header, before any packets or interfaces that set the encapsulation type
have been read. (If the file has no packets, this may be the value after
the file is entirely read in.) This can be the value when an output file
is written out simultaneously with reading an input file, rather than
reading the entire input file first, and, e.g., there is a custom block
before any IDBs.

The first case can never be handled when writing out a file, but the
second case can possibly be handled, so long as (for pcapng) IDBs
are available to write when they become necessary, or (for file
types like pcap with a single link-layer type in the header) the
writer waits until a link-layer type is seen to create the output
header. (It is possible, of course, that writing would fail in the
middle if an unsupported encapsulation type appears, or if the
encapsulation becomes per-packet for file types that don't support that,
but that is an unavoidable risk when writing without reading the entire
input file(s).)

Introduce WTAP_ENCAP_NONE for the second case, and use it for pcapng,
where we guarantee that any necessary IDBs will be passed along.
Continue to use WTAP_ENCAP_UNKNOWN for the first case.

Allow pcapng files to open a file for writing with WTAP_ENCAP_NONE.

There are some other file types that support per-packet link-types,
and could also use WTAP_ENCAP_NONE, but they require more work to
generate IDBs. (Note that all of them currently are impossible to
write to pcapng when they have multiple encapsulations, even if
the encapsulations are all supported by pcapng, because they don't
properly generate IDBs.)

Remove the workaround in ef43fd48b4
for tshark writing to pcapng when the source file is WTAP_ENCAP_UNKNOWN,
since now such files will be WTAP_ENCAP_NONE and work properly (and
also work in editcap, mergcap, etc.)

Along with 8cddc32d35, fix #18449.
This commit is contained in:
John Thacker 2023-02-04 13:49:10 -05:00
parent e8db896c62
commit ca230a59e0
7 changed files with 44 additions and 27 deletions

View File

@ -77,6 +77,7 @@ class BackTrace:
# Some values from wiretap; wiretap should be a shared
# libray and a Python module should be created for it so
# this program could just write a libpcap file directly.
WTAP_ENCAP_NONE = -2
WTAP_ENCAP_PER_PACKET = -1
WTAP_ENCAP_UNKNOWN = 0
WTAP_ENCAP_ETHERNET = 1
@ -133,6 +134,7 @@ wtap_to_pcap_map = {
wtap_name = {
WTAP_ENCAP_NONE : "None",
WTAP_ENCAP_UNKNOWN : "Unknown",
WTAP_ENCAP_ETHERNET : "Ethernet",
WTAP_ENCAP_TOKEN_RING : "Token-Ring",

View File

@ -3623,24 +3623,11 @@ process_cap_file(capture_file *cf, char *save_file, int out_file_type,
wtap_dump_params params = WTAP_DUMP_PARAMS_INIT;
char *shb_user_appl;
pass_status_t first_pass_status, second_pass_status;
gboolean pcapng_pcapng_workaround = false;
wtapng_iface_descriptions_t if_tmp;
if (save_file != NULL) {
/* Set up to write to the capture file. */
wtap_dump_params_init_no_idbs(&params, cf->provider.wth);
/* workaround for pcapng -> pcapng (e.g., when pcapng starts with a custom block) */
if (out_file_type == wtap_pcapng_file_type_subtype() && params.encap == WTAP_ENCAP_UNKNOWN) {
pcapng_pcapng_workaround = true;
params.encap = WTAP_ENCAP_PER_PACKET;
params.dont_copy_idbs = true; /* make sure this stay true */
if (params.idb_inf->interface_data != NULL) {
/* lets fake an interface, which is not copied anyway */
g_array_insert_val(params.idb_inf->interface_data, 0, if_tmp);
}
}
/* 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) {
/* this is free'd by wtap_block_unref() later */
@ -3664,11 +3651,6 @@ process_cap_file(capture_file *cf, char *save_file, int out_file_type,
&err, &err_info);
}
if (pcapng_pcapng_workaround) {
/* remove the fake interface before it will be used */
g_array_remove_index((params.idb_inf->interface_data), 0);
}
g_free(params.idb_inf);
params.idb_inf = NULL;

View File

@ -2291,10 +2291,19 @@ wtap_dump_init_dumper(int file_type_subtype, wtap_compression_type compression_t
g_array_append_val(wdh->interface_data, descr);
}
}
} else {
} else if (params->encap != WTAP_ENCAP_NONE) {
int snaplen;
// XXX IDBs should be optional.
// Generate a fake IDB if we don't have one, unless the
// file encapsulation is none. (WTAP_ENCAP_NONE either
// means that there are no interfaces, or they will be
// provided later when reading the file in single-pass mode.)
//
// 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.
descr = wtap_block_create(WTAP_BLOCK_IF_ID_AND_INFO);
descr_mand = (wtapng_if_descr_mandatory_t*)wtap_block_get_mandatory_data(descr);
descr_mand->wtap_encap = params->encap;

View File

@ -269,6 +269,7 @@ static ws_enum_t all_enums[] = {
ENUM(WTAP_ENCAP_ATM_PDUS),
ENUM(WTAP_ENCAP_ATM_PDUS_UNTRUNCATED),
ENUM(WTAP_ENCAP_ATM_RFC1483),
ENUM(WTAP_ENCAP_ATSC_ALP),
ENUM(WTAP_ENCAP_AUERSWALD_LOG),
ENUM(WTAP_ENCAP_AUTOSAR_DLT),
ENUM(WTAP_ENCAP_AX25),
@ -408,6 +409,7 @@ static ws_enum_t all_enums[] = {
ENUM(WTAP_ENCAP_NETTL_X25),
ENUM(WTAP_ENCAP_NFC_LLCP),
ENUM(WTAP_ENCAP_NFLOG),
ENUM(WTAP_ENCAP_NONE),
ENUM(WTAP_ENCAP_NORDIC_BLE),
ENUM(WTAP_ENCAP_NSTRACE_1_0),
ENUM(WTAP_ENCAP_NSTRACE_2_0),

View File

@ -1621,7 +1621,7 @@ pcapng_read_if_descr_block(wtap *wth, FILE_T fh, pcapng_block_header_t *bh,
* so it probably doesn't have a single encapsulation for all
* packets in the file.
*/
if (wth->file_encap == WTAP_ENCAP_UNKNOWN) {
if (wth->file_encap == WTAP_ENCAP_NONE) {
wth->file_encap = if_descr_mand->wtap_encap;
} else {
if (wth->file_encap != if_descr_mand->wtap_encap) {
@ -3097,7 +3097,7 @@ pcapng_read_systemd_journal_export_block(wtap *wth, FILE_T fh, pcapng_block_head
*/
wblock->internal = FALSE;
if (wth->file_encap == WTAP_ENCAP_UNKNOWN) {
if (wth->file_encap == WTAP_ENCAP_NONE) {
/*
* Nothing (most notably an IDB) has set a file encap at this point.
* Do so here.
@ -3666,7 +3666,7 @@ pcapng_open(wtap *wth, int *err, gchar **err_info)
wtap_block_unref(wblock.block);
wblock.block = NULL;
wth->file_encap = WTAP_ENCAP_UNKNOWN;
wth->file_encap = WTAP_ENCAP_NONE;
wth->snapshot_length = 0;
wth->file_tsprec = WTAP_TSPREC_UNKNOWN;
pcapng = g_new(pcapng_t, 1);
@ -6323,6 +6323,10 @@ static int pcapng_dump_can_write_encap(int wtap_encap)
if (wtap_encap == WTAP_ENCAP_PER_PACKET)
return 0;
/* No encapsulation type (yet) is supported. */
if (wtap_encap == WTAP_ENCAP_NONE)
return 0;
/* Is it a filetype-specific encapsulation that we support? */
if (pcapng_encap_is_ft_specific(wtap_encap)) {
return 0;

View File

@ -212,7 +212,8 @@ wtap_add_generated_idb(wtap *wth)
int snaplen;
ws_assert(wth->file_encap != WTAP_ENCAP_UNKNOWN &&
wth->file_encap != WTAP_ENCAP_PER_PACKET);
wth->file_encap != WTAP_ENCAP_PER_PACKET &&
wth->file_encap != WTAP_ENCAP_NONE);
ws_assert(wth->file_tsprec != WTAP_TSPREC_UNKNOWN &&
wth->file_tsprec != WTAP_TSPREC_PER_PACKET);
@ -1249,8 +1250,10 @@ wtap_register_encap_type(const char *description, const char *name)
const char *
wtap_encap_name(int encap)
{
if (encap < WTAP_ENCAP_PER_PACKET || encap >= WTAP_NUM_ENCAP_TYPES)
if (encap < WTAP_ENCAP_NONE || encap >= WTAP_NUM_ENCAP_TYPES)
return "illegal";
else if (encap == WTAP_ENCAP_NONE)
return "none";
else if (encap == WTAP_ENCAP_PER_PACKET)
return "per-packet";
else
@ -1261,8 +1264,10 @@ wtap_encap_name(int encap)
const char *
wtap_encap_description(int encap)
{
if (encap < WTAP_ENCAP_PER_PACKET || encap >= WTAP_NUM_ENCAP_TYPES)
if (encap < WTAP_ENCAP_NONE || encap >= WTAP_NUM_ENCAP_TYPES)
return "Illegal";
else if (encap == WTAP_ENCAP_NONE)
return "None";
else if (encap == WTAP_ENCAP_PER_PACKET)
return "Per packet";
else
@ -1665,6 +1670,7 @@ wtap_read(wtap *wth, wtap_rec *rec, Buffer *buf, int *err,
* encapsulation type.
*/
ws_assert(rec->rec_header.packet_header.pkt_encap != WTAP_ENCAP_PER_PACKET);
ws_assert(rec->rec_header.packet_header.pkt_encap != WTAP_ENCAP_NONE);
}
return TRUE; /* success */
@ -1821,6 +1827,7 @@ wtap_seek_read(wtap *wth, gint64 seek_off, wtap_rec *rec, Buffer *buf,
* encapsulation type.
*/
ws_assert(rec->rec_header.packet_header.pkt_encap != WTAP_ENCAP_PER_PACKET);
ws_assert(rec->rec_header.packet_header.pkt_encap != WTAP_ENCAP_NONE);
}
return TRUE;

View File

@ -31,7 +31,17 @@ extern "C" {
* don't have a single encapsulation type for all packets in the file.
*
* WTAP_ENCAP_UNKNOWN is returned by "wtap_pcap_encap_to_wtap_encap()"
* if it's handed an unknown encapsulation.
* if it's handed an unknown encapsulation. It is also used by file
* types for encapsulations which are unsupported by libwiretap.
*
* WTAP_ENCAP_NONE is an initial value used by file types like pcapng
* that do not have a single file level encapsulation type. If and when
* something that indicate encapsulation is read, the encapsulation will
* change (possibly to WTAP_ENCAP_PER_PACKET) and appropriate IDBs will
* be generated. If a file type uses this value, it MUST provide IDBs
* (possibly fake) when the encapsulation changes; otherwise, it should
* return WTAP_ENCAP_UNKNOWN so that attempts to write an output file
* without reading the entire input file first fail gracefully.
*
* WTAP_ENCAP_FDDI_BITSWAPPED is for FDDI captures on systems where the
* MAC addresses you get from the hardware are bit-swapped. Ideally,
@ -74,6 +84,7 @@ extern "C" {
* what older versions of "libpcap" on Linux turn the Ethernet
* header for loopback interfaces into (0.6.0 and later versions
* leave the Ethernet header alone and make it DLT_EN10MB). */
#define WTAP_ENCAP_NONE -2
#define WTAP_ENCAP_PER_PACKET -1
#define WTAP_ENCAP_UNKNOWN 0
#define WTAP_ENCAP_ETHERNET 1