2014-05-09 05:18:49 +00:00
/*
2007-10-08 11:41:21 +00:00
* Copyright ( c ) 2003 Endace Technology Ltd , Hamilton , New Zealand .
* All rights reserved .
*
* This software and documentation has been developed by Endace Technology Ltd .
* along with the DAG PCI network capture cards . For further information please
* visit http : //www.endace.com/.
*
2018-03-07 14:28:51 +00:00
* SPDX - License - Identifier : BSD - 3 - Clause
2014-03-04 16:36:59 +00:00
*/
2003-08-26 07:10:39 +00:00
2007-11-19 19:09:01 +00:00
/*
2003-08-26 07:10:39 +00:00
* erf - Endace ERF ( Extensible Record Format )
2005-02-03 02:26:20 +00:00
*
* See
*
2019-07-28 04:20:27 +00:00
* https : //www.endace.com/erf-extensible-record-format-types.pdf
*
* Version 8 :
2020-10-03 14:54:12 +00:00
* https : //gitlab.com/wireshark/wireshark/uploads/f694bfee494784425b6545892180a8b2/Endace_ERF_Types.pdf
* ( bug # 4484 )
2003-08-26 07:10:39 +00:00
*/
# include "config.h"
# include <stdlib.h>
# include <string.h>
2012-03-02 00:31:30 +00:00
# include <glib.h>
# include <wsutil/crc32.h>
2016-09-07 12:18:06 +00:00
# include <wsutil/strtoi.h>
2021-03-23 15:41:54 +00:00
# include <wsutil/glib-compat.h>
2011-08-31 20:50:15 +00:00
2003-08-26 07:10:39 +00:00
# include "wtap-int.h"
# include "file_wrappers.h"
# include "erf.h"
2020-05-02 04:02:00 +00:00
# include "erf_record.h"
# include "erf-common.h"
2003-08-26 07:10:39 +00:00
2017-06-01 08:34:25 +00:00
struct erf_anchor_mapping {
guint64 host_id ;
guint64 anchor_id ;
guint64 gen_time ;
gchar * comment ;
} ;
2017-12-27 21:17:51 +00:00
static const guint erf_header_size = ( guint ) sizeof ( erf_header_t ) ;
static const guint erf_mc_header_size = ( guint ) sizeof ( erf_mc_header_t ) ;
static const guint erf_eth_hdr_size = ( guint ) sizeof ( erf_eth_header_t ) ;
2016-03-11 03:44:16 +00:00
static gboolean erf_read_header ( wtap * wth , FILE_T fh ,
2018-02-09 00:19:12 +00:00
wtap_rec * rec ,
Add some higher-level file-read APIs and use them.
Add wtap_read_bytes(), which takes a FILE_T, a pointer, a byte count, an
error number pointer, and an error string pointer as arguments, and that
treats a short read of any sort, including a read that returns 0 bytes,
as a WTAP_ERR_SHORT_READ error, and that returns the error number and
string through its last two arguments.
Add wtap_read_bytes_or_eof(), which is similar, but that treats a read
that returns 0 bytes as an EOF, supplying an error number of 0 as an EOF
indication.
Use those in file readers; that simplifies the code and makes it less
likely that somebody will fail to supply the error number and error
string on a file read error.
Change-Id: Ia5dba2a6f81151e87b614461349d611cffc16210
Reviewed-on: https://code.wireshark.org/review/4512
Reviewed-by: Guy Harris <guy@alum.mit.edu>
2014-10-07 01:00:57 +00:00
erf_header_t * erf_header ,
int * err ,
gchar * * err_info ,
guint32 * bytes_read ,
2017-06-01 08:34:25 +00:00
guint32 * packet_size ,
GPtrArray * anchor_mappings_to_update ) ;
2019-04-05 01:56:27 +00:00
static gboolean erf_read ( wtap * wth , wtap_rec * rec , Buffer * buf ,
int * err , gchar * * err_info , gint64 * data_offset ) ;
2014-05-23 10:50:02 +00:00
static gboolean erf_seek_read ( wtap * wth , gint64 seek_off ,
2018-02-09 00:19:12 +00:00
wtap_rec * rec , Buffer * buf ,
2014-05-23 10:50:02 +00:00
int * err , gchar * * err_info ) ;
2016-03-11 03:44:16 +00:00
static void erf_close ( wtap * wth ) ;
2017-06-01 08:34:25 +00:00
2021-06-18 23:22:54 +00:00
static int populate_summary_info ( erf_t * erf_priv , wtap * wth , union wtap_pseudo_header * pseudo_header , Buffer * buf , guint32 packet_size , GPtrArray * anchor_mappings_to_update , int * err , gchar * * err_info ) ;
2018-02-09 00:19:12 +00:00
static int erf_update_anchors_from_header ( erf_t * erf_priv , wtap_rec * rec , union wtap_pseudo_header * pseudo_header , guint64 host_id , GPtrArray * anchor_mappings_to_update ) ;
2020-05-02 04:02:00 +00:00
static int erf_get_source_from_header ( union wtap_pseudo_header * pseudo_header , guint64 * host_id , guint8 * source_id ) ;
2021-06-18 23:22:54 +00:00
static int erf_populate_interface ( erf_t * erf_priv , wtap * wth , union wtap_pseudo_header * pseudo_header , guint64 host_id , guint8 source_id , guint8 if_num , int * err , gchar * * err_info ) ;
2017-06-01 08:34:25 +00:00
typedef struct {
gboolean write_next_extra_meta ;
gboolean last_meta_periodic ;
guint64 host_id ;
guint64 implicit_host_id ;
guint64 prev_frame_ts ;
guint8 prev_erf_type ;
guint64 gen_time ;
2017-07-17 16:52:53 +00:00
time_t first_frame_time_sec ;
time_t prev_inserted_time_sec ;
2017-06-01 08:34:25 +00:00
gchar * user_comment_ptr ;
GPtrArray * periodic_sections ;
GArray * periodic_extra_ehdrs ;
GRand * rand ;
} erf_dump_t ;
2020-05-02 04:02:00 +00:00
static erf_dump_t * erf_dump_priv_create ( void ) ;
2017-06-01 08:34:25 +00:00
static void erf_dump_priv_free ( erf_dump_t * dump_priv ) ;
static gboolean erf_dump_priv_compare_capture_comment ( wtap_dumper * wdh , erf_dump_t * dump_priv , const union wtap_pseudo_header * pseudo_header , const guint8 * pd ) ;
static gboolean erf_comment_to_sections ( wtap_dumper * wdh , guint16 section_type , guint16 section_id , gchar * comment , GPtrArray * sections ) ;
static gboolean erf_wtap_info_to_sections ( wtap_dumper * wdh , GPtrArray * sections ) ;
static gboolean get_user_comment_string ( wtap_dumper * wdh , gchar * * user_comment_ptr ) ;
static gboolean erf_write_meta_record ( wtap_dumper * wdh , erf_dump_t * dump_priv , guint64 timestamp , GPtrArray * sections , GArray * extra_ehdrs , int * err ) ;
2007-11-19 19:09:01 +00:00
2011-08-31 20:50:15 +00:00
static const struct {
int erf_encap_value ;
int wtap_encap_value ;
} erf_to_wtap_map [ ] = {
{ ERF_TYPE_HDLC_POS , WTAP_ENCAP_CHDLC } ,
{ ERF_TYPE_HDLC_POS , WTAP_ENCAP_HHDLC } ,
{ ERF_TYPE_HDLC_POS , WTAP_ENCAP_CHDLC_WITH_PHDR } ,
{ ERF_TYPE_HDLC_POS , WTAP_ENCAP_PPP } ,
{ ERF_TYPE_HDLC_POS , WTAP_ENCAP_FRELAY } ,
{ ERF_TYPE_HDLC_POS , WTAP_ENCAP_MTP2 } ,
{ ERF_TYPE_ETH , WTAP_ENCAP_ETHERNET } ,
{ 99 , WTAP_ENCAP_ERF } , /*this type added so WTAP_ENCAP_ERF will work and then be treated at ERF->ERF*/
} ;
# define NUM_ERF_ENCAPS (sizeof erf_to_wtap_map / sizeof erf_to_wtap_map[0])
2016-03-11 03:44:16 +00:00
# define ERF_META_TAG_HEADERLEN 4
2017-06-01 08:34:25 +00:00
# define ERF_META_TAG_TOTAL_ALIGNED_LENGTH(taglength) ((((guint32)taglength + 0x3U) & ~0x3U) + ERF_META_TAG_HEADERLEN)
# define ERF_META_TAG_ALIGNED_LENGTH(taglength) ((((guint32)taglength + 0x3U) & ~0x3U))
# define ERF_PADDING_TO_8(len) ((8 - len % 8) % 8)
2016-03-11 03:44:16 +00:00
struct erf_if_info {
int if_index ;
gchar * name ;
gchar * descr ;
int stream_num ;
struct {
guint filter : 1 ;
guint fcs_len : 1 ;
guint snaplen : 1 ;
} set_flags ;
} ;
struct erf_if_mapping {
guint64 host_id ;
guint8 source_id ;
struct erf_if_info interfaces [ 4 ] ;
gchar * module_filter_str ;
2017-06-01 08:34:25 +00:00
/*here because we could have captures from multiple hosts in the file*/
gchar * capture_filter_str ;
2016-03-11 03:44:16 +00:00
gint8 module_fcs_len ;
guint32 module_snaplen ;
int interface_metadata ;
2017-06-01 08:34:25 +00:00
guint64 interface_gentime ;
guint64 module_gentime ;
} ;
struct erf_meta_section {
guint16 type ;
guint16 section_id ;
guint16 section_length ;
GPtrArray * tags ;
2016-03-11 03:44:16 +00:00
} ;
struct erf_meta_tag {
guint16 type ;
guint16 length ;
guint8 * value ;
} ;
struct erf_meta_read_state {
guint8 * tag_ptr ;
guint32 remaining_len ;
struct erf_if_mapping * if_map ;
guint16 sectiontype ;
guint16 sectionid ;
guint16 parentsectiontype ;
guint16 parentsectionid ;
2017-06-01 08:34:25 +00:00
guint64 gen_time ;
2016-03-11 03:44:16 +00:00
int interface_metadata ;
} ;
2017-06-01 08:34:25 +00:00
static gboolean erf_wtap_blocks_to_erf_sections ( wtap_block_t block , GPtrArray * sections , guint16 section_type , guint16 section_id , wtap_block_foreach_func func ) ;
static guint32 erf_meta_read_tag ( struct erf_meta_tag * , guint8 * , guint32 ) ;
2021-02-19 22:46:42 +00:00
static int erf_file_type_subtype = - 1 ;
void register_erf ( void ) ;
2017-06-01 08:34:25 +00:00
static guint erf_anchor_mapping_hash ( gconstpointer key ) {
const struct erf_anchor_mapping * anchor_map = ( const struct erf_anchor_mapping * ) key ;
return ( ( guint32 ) anchor_map - > host_id ^ ( guint32 ) anchor_map - > anchor_id ) ;
}
static gboolean erf_anchor_mapping_equal ( gconstpointer a , gconstpointer b ) {
const struct erf_anchor_mapping * anchor_map_a = ( const struct erf_anchor_mapping * ) a ;
const struct erf_anchor_mapping * anchor_map_b = ( const struct erf_anchor_mapping * ) b ;
return ( anchor_map_a - > host_id ) = = ( anchor_map_b - > host_id ) & &
( anchor_map_a - > anchor_id & ERF_EXT_HDR_TYPE_ANCHOR_ID ) = = ( anchor_map_b - > anchor_id & ERF_EXT_HDR_TYPE_ANCHOR_ID ) ;
}
static void erf_anchor_mapping_destroy ( gpointer key ) {
struct erf_anchor_mapping * anchor_map = ( struct erf_anchor_mapping * ) key ;
if ( anchor_map - > comment ! = NULL ) {
g_free ( anchor_map - > comment ) ;
anchor_map - > comment = NULL ;
}
g_free ( anchor_map ) ;
anchor_map = NULL ;
}
2016-03-11 03:44:16 +00:00
static gboolean erf_if_mapping_equal ( gconstpointer a , gconstpointer b )
{
const struct erf_if_mapping * if_map_a = ( const struct erf_if_mapping * ) a ;
const struct erf_if_mapping * if_map_b = ( const struct erf_if_mapping * ) b ;
return if_map_a - > source_id = = if_map_b - > source_id & & if_map_a - > host_id = = if_map_b - > host_id ;
}
static guint erf_if_mapping_hash ( gconstpointer key )
{
const struct erf_if_mapping * if_map = ( const struct erf_if_mapping * ) key ;
return ( ( ( guint ) if_map - > host_id ) < < 16 ) | if_map - > source_id ;
}
static void erf_if_mapping_destroy ( gpointer key )
{
int i = 0 ;
struct erf_if_mapping * if_map = ( struct erf_if_mapping * ) key ;
for ( i = 0 ; i < 4 ; i + + ) {
g_free ( if_map - > interfaces [ i ] . name ) ;
g_free ( if_map - > interfaces [ i ] . descr ) ;
}
g_free ( if_map - > module_filter_str ) ;
g_free ( if_map ) ;
}
static struct erf_if_mapping * erf_if_mapping_create ( guint64 host_id , guint8 source_id )
{
int i = 0 ;
struct erf_if_mapping * if_map = NULL ;
2020-12-21 02:30:28 +00:00
if_map = g_new0 ( struct erf_if_mapping , 1 ) ;
2016-03-11 03:44:16 +00:00
if_map - > host_id = host_id ;
if_map - > source_id = source_id ;
for ( i = 0 ; i < 4 ; i + + ) {
if_map - > interfaces [ i ] . if_index = - 1 ;
if_map - > interfaces [ i ] . stream_num = - 1 ;
}
if_map - > module_fcs_len = - 1 ;
if_map - > module_snaplen = ( guint32 ) - 1 ;
2017-06-01 08:34:25 +00:00
/* everything else 0 by g_malloc0*/
2016-03-11 03:44:16 +00:00
return if_map ;
}
2017-06-01 08:34:25 +00:00
2016-03-11 03:44:16 +00:00
erf_t * erf_priv_create ( void )
{
erf_t * erf_priv ;
2020-12-21 02:30:28 +00:00
erf_priv = g_new ( erf_t , 1 ) ;
2017-06-01 08:34:25 +00:00
erf_priv - > anchor_map = g_hash_table_new_full ( erf_anchor_mapping_hash , erf_anchor_mapping_equal , erf_anchor_mapping_destroy , NULL ) ;
2016-03-11 03:44:16 +00:00
erf_priv - > if_map = g_hash_table_new_full ( erf_if_mapping_hash , erf_if_mapping_equal , erf_if_mapping_destroy , NULL ) ;
2016-10-13 23:46:29 +00:00
erf_priv - > implicit_host_id = ERF_META_HOST_ID_IMPLICIT ;
2017-06-01 08:34:25 +00:00
erf_priv - > capture_gentime = 0 ;
erf_priv - > host_gentime = 0 ;
2016-03-11 03:44:16 +00:00
return erf_priv ;
}
erf_t * erf_priv_free ( erf_t * erf_priv )
{
if ( erf_priv )
{
2017-06-01 08:34:25 +00:00
g_hash_table_destroy ( erf_priv - > anchor_map ) ;
2016-03-11 03:44:16 +00:00
g_hash_table_destroy ( erf_priv - > if_map ) ;
g_free ( erf_priv ) ;
}
return NULL ;
}
2017-06-01 08:34:25 +00:00
static void erf_dump_priv_free ( erf_dump_t * dump_priv ) {
if ( dump_priv ) {
if ( dump_priv - > periodic_sections ) {
g_ptr_array_free ( dump_priv - > periodic_sections , TRUE ) ;
}
if ( dump_priv - > periodic_extra_ehdrs ) {
g_array_free ( dump_priv - > periodic_extra_ehdrs , TRUE ) ;
}
if ( dump_priv - > user_comment_ptr ) {
g_free ( dump_priv - > user_comment_ptr ) ;
}
g_free ( dump_priv - > rand ) ;
g_free ( dump_priv ) ;
}
}
static void erf_meta_section_free ( gpointer data ) {
struct erf_meta_section * section_ptr = ( struct erf_meta_section * ) data ;
if ( section_ptr ) {
g_ptr_array_free ( section_ptr - > tags , TRUE ) ;
section_ptr - > tags = NULL ;
}
g_free ( section_ptr ) ;
}
static void erf_meta_tag_free ( gpointer data ) {
struct erf_meta_tag * tag_ptr = ( struct erf_meta_tag * ) data ;
if ( tag_ptr ) {
g_free ( tag_ptr - > value ) ;
tag_ptr - > value = NULL ;
}
g_free ( tag_ptr ) ;
}
2020-10-14 01:48:46 +00:00
static gboolean erf_dump_finish ( struct wtap_dumper * wdh , int * err , gchar * * err_info _U_ ) {
2017-06-01 08:34:25 +00:00
erf_dump_t * dump_priv = ( erf_dump_t * ) wdh - > priv ;
gboolean ret = TRUE ;
/* Write final metadata record. There are some corner cases where we should
* do this ( file < 1 second , last record was ERF_TYPE_META with an out of date
* comment ) and there is no harm doing this always if we have already written
* some metadata . */
if ( dump_priv - > write_next_extra_meta ) {
if ( ! dump_priv - > periodic_sections ) {
dump_priv - > periodic_sections = g_ptr_array_new_with_free_func ( erf_meta_section_free ) ;
if ( dump_priv - > prev_erf_type = = ERF_TYPE_META & & dump_priv - > last_meta_periodic ) {
erf_comment_to_sections ( wdh , ERF_META_SECTION_CAPTURE , 0 , dump_priv - > user_comment_ptr , dump_priv - > periodic_sections ) ;
} else {
/* If we get here, metadata record was not found in the first ~1 sec
* but we have either a capture comment or a non - ERF file ( see
* erf_dump_open ) */
erf_wtap_info_to_sections ( wdh , dump_priv - > periodic_sections ) ;
}
}
if ( ! erf_write_meta_record ( wdh , dump_priv , dump_priv - > prev_frame_ts , dump_priv - > periodic_sections , dump_priv - > periodic_extra_ehdrs , err ) ) ret = FALSE ;
}
/* Clean up */
erf_dump_priv_free ( dump_priv ) ;
/* Avoid double freeing by setting it to NULL*/
wdh - > priv = NULL ;
return ret ;
}
2016-04-05 13:32:56 +00:00
static void
erf_free_data ( gpointer data , gpointer user_data _U_ )
{
g_free ( data ) ;
}
2014-10-09 23:44:15 +00:00
extern wtap_open_return_val erf_open ( wtap * wth , int * err , gchar * * err_info )
2003-08-26 07:10:39 +00:00
{
2012-03-02 00:31:30 +00:00
int i , n , records_for_erf_check = RECORDS_FOR_ERF_CHECK ;
int valid_prev = 0 ;
char * s ;
erf_timestamp_t prevts , ts ;
erf_header_t header ;
guint32 mc_hdr ;
2016-01-13 08:10:48 +00:00
struct erf_eth_hdr eth_hdr ;
2012-03-02 00:31:30 +00:00
guint32 packet_size ;
guint16 rlen ;
guint64 erf_ext_header ;
2017-12-27 21:17:51 +00:00
guint erf_ext_header_size = ( guint ) sizeof ( erf_ext_header ) ;
2012-03-02 00:31:30 +00:00
guint8 type ;
2007-10-08 11:41:21 +00:00
2019-03-17 16:19:12 +00:00
prevts = 0 ;
2007-10-08 11:41:21 +00:00
2008-01-09 22:58:34 +00:00
/* number of records to scan before deciding if this really is ERF */
2007-10-08 11:41:21 +00:00
if ( ( s = getenv ( " ERF_RECORDS_TO_CHECK " ) ) ! = NULL ) {
2016-09-07 12:18:06 +00:00
if ( ws_strtoi32 ( s , NULL , & n ) & & n > = 0 & & n < 101 ) {
2007-10-08 11:41:21 +00:00
records_for_erf_check = n ;
}
}
2008-01-10 08:49:11 +00:00
/*
* ERF is a little hard because there ' s no magic number ; we look at
* the first few records and see if they look enough like ERF
* records .
*/
2007-10-08 11:41:21 +00:00
for ( i = 0 ; i < records_for_erf_check ; i + + ) { /* records_for_erf_check */
2017-12-27 21:17:51 +00:00
if ( ! wtap_read_bytes_or_eof ( wth - > fh , & header , erf_header_size , err , err_info ) ) {
Add some higher-level file-read APIs and use them.
Add wtap_read_bytes(), which takes a FILE_T, a pointer, a byte count, an
error number pointer, and an error string pointer as arguments, and that
treats a short read of any sort, including a read that returns 0 bytes,
as a WTAP_ERR_SHORT_READ error, and that returns the error number and
string through its last two arguments.
Add wtap_read_bytes_or_eof(), which is similar, but that treats a read
that returns 0 bytes as an EOF, supplying an error number of 0 as an EOF
indication.
Use those in file readers; that simplifies the code and makes it less
likely that somebody will fail to supply the error number and error
string on a file read error.
Change-Id: Ia5dba2a6f81151e87b614461349d611cffc16210
Reviewed-on: https://code.wireshark.org/review/4512
Reviewed-by: Guy Harris <guy@alum.mit.edu>
2014-10-07 01:00:57 +00:00
if ( * err = = 0 ) {
2014-10-07 07:30:35 +00:00
/* EOF - all records have been successfully checked, accept the file */
Add some higher-level file-read APIs and use them.
Add wtap_read_bytes(), which takes a FILE_T, a pointer, a byte count, an
error number pointer, and an error string pointer as arguments, and that
treats a short read of any sort, including a read that returns 0 bytes,
as a WTAP_ERR_SHORT_READ error, and that returns the error number and
string through its last two arguments.
Add wtap_read_bytes_or_eof(), which is similar, but that treats a read
that returns 0 bytes as an EOF, supplying an error number of 0 as an EOF
indication.
Use those in file readers; that simplifies the code and makes it less
likely that somebody will fail to supply the error number and error
string on a file read error.
Change-Id: Ia5dba2a6f81151e87b614461349d611cffc16210
Reviewed-on: https://code.wireshark.org/review/4512
Reviewed-by: Guy Harris <guy@alum.mit.edu>
2014-10-07 01:00:57 +00:00
break ;
}
if ( * err = = WTAP_ERR_SHORT_READ ) {
2012-03-02 00:31:30 +00:00
/* ERF header too short accept the file,
only if the very first records have been successfully checked */
if ( i < MIN_RECORDS_FOR_ERF_CHECK ) {
2014-10-09 23:44:15 +00:00
return WTAP_OPEN_NOT_MINE ;
2012-03-02 00:31:30 +00:00
} else {
/* BREAK, the last record is too short, and will be ignored */
break ;
}
Add some higher-level file-read APIs and use them.
Add wtap_read_bytes(), which takes a FILE_T, a pointer, a byte count, an
error number pointer, and an error string pointer as arguments, and that
treats a short read of any sort, including a read that returns 0 bytes,
as a WTAP_ERR_SHORT_READ error, and that returns the error number and
string through its last two arguments.
Add wtap_read_bytes_or_eof(), which is similar, but that treats a read
that returns 0 bytes as an EOF, supplying an error number of 0 as an EOF
indication.
Use those in file readers; that simplifies the code and makes it less
likely that somebody will fail to supply the error number and error
string on a file read error.
Change-Id: Ia5dba2a6f81151e87b614461349d611cffc16210
Reviewed-on: https://code.wireshark.org/review/4512
Reviewed-by: Guy Harris <guy@alum.mit.edu>
2014-10-07 01:00:57 +00:00
} else {
2014-10-09 23:44:15 +00:00
return WTAP_OPEN_ERROR ;
2007-10-08 11:41:21 +00:00
}
}
2007-11-19 19:09:01 +00:00
2008-01-09 22:58:34 +00:00
rlen = g_ntohs ( header . rlen ) ;
2007-10-08 11:41:21 +00:00
2008-04-12 10:21:51 +00:00
/* fail on invalid record type, invalid rlen, timestamps decreasing, or incrementing too far */
2012-03-02 00:31:30 +00:00
2008-04-12 10:21:51 +00:00
/* Test valid rlen >= 16 */
if ( rlen < 16 ) {
2014-10-09 23:44:15 +00:00
return WTAP_OPEN_NOT_MINE ;
2008-04-12 10:21:51 +00:00
}
2012-03-02 00:31:30 +00:00
2017-12-27 21:17:51 +00:00
packet_size = rlen - erf_header_size ;
Allow bigger snapshot lengths for D-Bus captures.
Use WTAP_MAX_PACKET_SIZE_STANDARD, set to 256KB, for everything except
for D-Bus captures. Use WTAP_MAX_PACKET_SIZE_DBUS, set to 128MB, for
them, because that's the largest possible D-Bus message size. See
https://bugs.freedesktop.org/show_bug.cgi?id=100220
for an example of the problems caused by limiting the snapshot length to
256KB for D-Bus.
Have a snapshot length of 0 in a capture_file structure mean "there is
no snapshot length for the file"; we don't need the has_snap field in
that case, a value of 0 mean "no, we don't have a snapshot length".
In dumpcap, start out with a pipe buffer size of 2KB, and grow it as
necessary. When checking for a too-big packet from a pipe, check
against the appropriate maximum - 128MB for DLT_DBUS, 256KB for
everything else.
Change-Id: Ib2ce7a0cf37b971fbc0318024fd011e18add8b20
Reviewed-on: https://code.wireshark.org/review/21952
Petri-Dish: Guy Harris <guy@alum.mit.edu>
Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org>
Reviewed-by: Guy Harris <guy@alum.mit.edu>
2017-06-05 01:58:40 +00:00
if ( packet_size > WTAP_MAX_PACKET_SIZE_STANDARD ) {
2007-11-05 20:43:25 +00:00
/*
2009-08-10 18:22:05 +00:00
* Probably a corrupt capture file or a file that ' s not an ERF file
2014-01-22 00:26:36 +00:00
* but that passed earlier tests .
2007-11-05 20:43:25 +00:00
*/
2014-10-09 23:44:15 +00:00
return WTAP_OPEN_NOT_MINE ;
2007-11-05 20:43:25 +00:00
}
2007-11-19 19:09:01 +00:00
2007-10-08 11:41:21 +00:00
/* Skip PAD records, timestamps may not be set */
2008-09-29 16:20:24 +00:00
if ( ( header . type & 0x7F ) = = ERF_TYPE_PAD ) {
2016-09-28 23:45:23 +00:00
if ( ! wtap_read_bytes ( wth - > fh , NULL , packet_size , err , err_info ) ) {
if ( * err ! = WTAP_ERR_SHORT_READ ) {
/* A real error */
return WTAP_OPEN_ERROR ;
}
/* ERF record too short, accept the file,
only if the very first records have been successfully checked */
if ( i < MIN_RECORDS_FOR_ERF_CHECK ) {
return WTAP_OPEN_NOT_MINE ;
}
2007-10-08 11:41:21 +00:00
}
continue ;
}
2016-03-21 04:32:13 +00:00
/* ERF Type 0 is reserved for ancient legacy records which are not supported, probably not ERF */
if ( ( header . type & 0x7F ) = = 0 ) {
2014-10-09 23:44:15 +00:00
return WTAP_OPEN_NOT_MINE ;
2007-11-06 19:22:51 +00:00
}
2012-03-02 00:31:30 +00:00
2016-03-21 04:32:13 +00:00
/* fail on decreasing timestamps */
2013-12-03 20:35:50 +00:00
if ( ( ts = pletoh64 ( & header . ts ) ) < prevts ) {
2008-04-12 10:21:51 +00:00
/* reassembled AALx records may not be in time order, also records are not in strict time order between physical interfaces, so allow 1 sec fudge */
if ( ( ( prevts - ts ) > > 32 ) > 1 ) {
2014-10-09 23:44:15 +00:00
return WTAP_OPEN_NOT_MINE ;
2007-10-08 11:41:21 +00:00
}
}
2012-03-02 00:31:30 +00:00
2018-07-30 23:50:43 +00:00
/* Check to see if timestamp increment is > 1 year */
if ( ( valid_prev ) & & ( ts > prevts ) & & ( ( ( ts - prevts ) > > 32 ) > 3600 * 24 * 365 ) ) {
2014-10-09 23:44:15 +00:00
return WTAP_OPEN_NOT_MINE ;
2008-04-12 10:21:51 +00:00
}
2012-03-02 00:31:30 +00:00
2019-03-17 16:19:12 +00:00
prevts = ts ;
2007-10-08 11:41:21 +00:00
2008-09-29 16:20:24 +00:00
/* Read over the extension headers */
type = header . type ;
while ( type & 0x80 ) {
2017-12-27 21:17:51 +00:00
if ( ! wtap_read_bytes ( wth - > fh , & erf_ext_header , erf_ext_header_size , err , err_info ) ) {
Add some higher-level file-read APIs and use them.
Add wtap_read_bytes(), which takes a FILE_T, a pointer, a byte count, an
error number pointer, and an error string pointer as arguments, and that
treats a short read of any sort, including a read that returns 0 bytes,
as a WTAP_ERR_SHORT_READ error, and that returns the error number and
string through its last two arguments.
Add wtap_read_bytes_or_eof(), which is similar, but that treats a read
that returns 0 bytes as an EOF, supplying an error number of 0 as an EOF
indication.
Use those in file readers; that simplifies the code and makes it less
likely that somebody will fail to supply the error number and error
string on a file read error.
Change-Id: Ia5dba2a6f81151e87b614461349d611cffc16210
Reviewed-on: https://code.wireshark.org/review/4512
Reviewed-by: Guy Harris <guy@alum.mit.edu>
2014-10-07 01:00:57 +00:00
if ( * err = = WTAP_ERR_SHORT_READ ) {
/* Extension header missing, not an ERF file */
2014-10-09 23:44:15 +00:00
return WTAP_OPEN_NOT_MINE ;
Add some higher-level file-read APIs and use them.
Add wtap_read_bytes(), which takes a FILE_T, a pointer, a byte count, an
error number pointer, and an error string pointer as arguments, and that
treats a short read of any sort, including a read that returns 0 bytes,
as a WTAP_ERR_SHORT_READ error, and that returns the error number and
string through its last two arguments.
Add wtap_read_bytes_or_eof(), which is similar, but that treats a read
that returns 0 bytes as an EOF, supplying an error number of 0 as an EOF
indication.
Use those in file readers; that simplifies the code and makes it less
likely that somebody will fail to supply the error number and error
string on a file read error.
Change-Id: Ia5dba2a6f81151e87b614461349d611cffc16210
Reviewed-on: https://code.wireshark.org/review/4512
Reviewed-by: Guy Harris <guy@alum.mit.edu>
2014-10-07 01:00:57 +00:00
}
2014-10-09 23:44:15 +00:00
return WTAP_OPEN_ERROR ;
2012-03-02 00:31:30 +00:00
}
2017-12-27 21:17:51 +00:00
if ( packet_size < erf_ext_header_size )
return WTAP_OPEN_NOT_MINE ;
packet_size - = erf_ext_header_size ;
2012-03-02 00:31:30 +00:00
memcpy ( & type , & erf_ext_header , sizeof ( type ) ) ;
2008-09-29 16:20:24 +00:00
}
2012-03-02 00:31:30 +00:00
2008-09-29 16:20:24 +00:00
2007-10-08 11:41:21 +00:00
/* Read over MC or ETH subheader */
2008-09-29 16:20:24 +00:00
switch ( header . type & 0x7F ) {
2012-03-02 00:31:30 +00:00
case ERF_TYPE_MC_HDLC :
case ERF_TYPE_MC_RAW :
case ERF_TYPE_MC_ATM :
case ERF_TYPE_MC_RAW_CHANNEL :
case ERF_TYPE_MC_AAL5 :
case ERF_TYPE_MC_AAL2 :
case ERF_TYPE_COLOR_MC_HDLC_POS :
case ERF_TYPE_AAL2 : /* not an MC type but has a similar 'AAL2 ext' header */
2017-12-27 21:17:51 +00:00
if ( ! wtap_read_bytes ( wth - > fh , & mc_hdr , erf_mc_header_size , err , err_info ) ) {
Add some higher-level file-read APIs and use them.
Add wtap_read_bytes(), which takes a FILE_T, a pointer, a byte count, an
error number pointer, and an error string pointer as arguments, and that
treats a short read of any sort, including a read that returns 0 bytes,
as a WTAP_ERR_SHORT_READ error, and that returns the error number and
string through its last two arguments.
Add wtap_read_bytes_or_eof(), which is similar, but that treats a read
that returns 0 bytes as an EOF, supplying an error number of 0 as an EOF
indication.
Use those in file readers; that simplifies the code and makes it less
likely that somebody will fail to supply the error number and error
string on a file read error.
Change-Id: Ia5dba2a6f81151e87b614461349d611cffc16210
Reviewed-on: https://code.wireshark.org/review/4512
Reviewed-by: Guy Harris <guy@alum.mit.edu>
2014-10-07 01:00:57 +00:00
if ( * err = = WTAP_ERR_SHORT_READ ) {
/* Subheader missing, not an ERF file */
2014-10-09 23:44:15 +00:00
return WTAP_OPEN_NOT_MINE ;
Add some higher-level file-read APIs and use them.
Add wtap_read_bytes(), which takes a FILE_T, a pointer, a byte count, an
error number pointer, and an error string pointer as arguments, and that
treats a short read of any sort, including a read that returns 0 bytes,
as a WTAP_ERR_SHORT_READ error, and that returns the error number and
string through its last two arguments.
Add wtap_read_bytes_or_eof(), which is similar, but that treats a read
that returns 0 bytes as an EOF, supplying an error number of 0 as an EOF
indication.
Use those in file readers; that simplifies the code and makes it less
likely that somebody will fail to supply the error number and error
string on a file read error.
Change-Id: Ia5dba2a6f81151e87b614461349d611cffc16210
Reviewed-on: https://code.wireshark.org/review/4512
Reviewed-by: Guy Harris <guy@alum.mit.edu>
2014-10-07 01:00:57 +00:00
}
2014-10-09 23:44:15 +00:00
return WTAP_OPEN_ERROR ;
2012-03-02 00:31:30 +00:00
}
2017-12-27 21:17:51 +00:00
if ( packet_size < erf_mc_header_size )
return WTAP_OPEN_NOT_MINE ;
packet_size - = erf_mc_header_size ;
2012-03-02 00:31:30 +00:00
break ;
case ERF_TYPE_ETH :
case ERF_TYPE_COLOR_ETH :
case ERF_TYPE_DSM_COLOR_ETH :
2015-12-19 18:24:47 +00:00
case ERF_TYPE_COLOR_HASH_ETH :
2018-01-22 04:38:44 +00:00
if ( ! wtap_read_bytes ( wth - > fh , & eth_hdr , erf_eth_hdr_size , err , err_info ) ) {
Add some higher-level file-read APIs and use them.
Add wtap_read_bytes(), which takes a FILE_T, a pointer, a byte count, an
error number pointer, and an error string pointer as arguments, and that
treats a short read of any sort, including a read that returns 0 bytes,
as a WTAP_ERR_SHORT_READ error, and that returns the error number and
string through its last two arguments.
Add wtap_read_bytes_or_eof(), which is similar, but that treats a read
that returns 0 bytes as an EOF, supplying an error number of 0 as an EOF
indication.
Use those in file readers; that simplifies the code and makes it less
likely that somebody will fail to supply the error number and error
string on a file read error.
Change-Id: Ia5dba2a6f81151e87b614461349d611cffc16210
Reviewed-on: https://code.wireshark.org/review/4512
Reviewed-by: Guy Harris <guy@alum.mit.edu>
2014-10-07 01:00:57 +00:00
if ( * err = = WTAP_ERR_SHORT_READ ) {
/* Subheader missing, not an ERF file */
2014-10-09 23:44:15 +00:00
return WTAP_OPEN_NOT_MINE ;
Add some higher-level file-read APIs and use them.
Add wtap_read_bytes(), which takes a FILE_T, a pointer, a byte count, an
error number pointer, and an error string pointer as arguments, and that
treats a short read of any sort, including a read that returns 0 bytes,
as a WTAP_ERR_SHORT_READ error, and that returns the error number and
string through its last two arguments.
Add wtap_read_bytes_or_eof(), which is similar, but that treats a read
that returns 0 bytes as an EOF, supplying an error number of 0 as an EOF
indication.
Use those in file readers; that simplifies the code and makes it less
likely that somebody will fail to supply the error number and error
string on a file read error.
Change-Id: Ia5dba2a6f81151e87b614461349d611cffc16210
Reviewed-on: https://code.wireshark.org/review/4512
Reviewed-by: Guy Harris <guy@alum.mit.edu>
2014-10-07 01:00:57 +00:00
}
2014-10-09 23:44:15 +00:00
return WTAP_OPEN_ERROR ;
2012-03-02 00:31:30 +00:00
}
2018-01-22 04:38:44 +00:00
if ( packet_size < erf_eth_hdr_size )
2017-12-27 21:17:51 +00:00
return WTAP_OPEN_NOT_MINE ;
2018-01-22 04:38:44 +00:00
packet_size - = erf_eth_hdr_size ;
2012-03-02 00:31:30 +00:00
break ;
default :
break ;
2007-10-08 11:41:21 +00:00
}
2007-11-19 19:09:01 +00:00
2016-09-28 23:45:23 +00:00
if ( ! wtap_read_bytes ( wth - > fh , NULL , packet_size , err , err_info ) ) {
Add some higher-level file-read APIs and use them.
Add wtap_read_bytes(), which takes a FILE_T, a pointer, a byte count, an
error number pointer, and an error string pointer as arguments, and that
treats a short read of any sort, including a read that returns 0 bytes,
as a WTAP_ERR_SHORT_READ error, and that returns the error number and
string through its last two arguments.
Add wtap_read_bytes_or_eof(), which is similar, but that treats a read
that returns 0 bytes as an EOF, supplying an error number of 0 as an EOF
indication.
Use those in file readers; that simplifies the code and makes it less
likely that somebody will fail to supply the error number and error
string on a file read error.
Change-Id: Ia5dba2a6f81151e87b614461349d611cffc16210
Reviewed-on: https://code.wireshark.org/review/4512
Reviewed-by: Guy Harris <guy@alum.mit.edu>
2014-10-07 01:00:57 +00:00
if ( * err ! = WTAP_ERR_SHORT_READ ) {
2014-10-07 05:01:12 +00:00
/* A real error */
2014-10-09 23:44:15 +00:00
return WTAP_OPEN_ERROR ;
Add some higher-level file-read APIs and use them.
Add wtap_read_bytes(), which takes a FILE_T, a pointer, a byte count, an
error number pointer, and an error string pointer as arguments, and that
treats a short read of any sort, including a read that returns 0 bytes,
as a WTAP_ERR_SHORT_READ error, and that returns the error number and
string through its last two arguments.
Add wtap_read_bytes_or_eof(), which is similar, but that treats a read
that returns 0 bytes as an EOF, supplying an error number of 0 as an EOF
indication.
Use those in file readers; that simplifies the code and makes it less
likely that somebody will fail to supply the error number and error
string on a file read error.
Change-Id: Ia5dba2a6f81151e87b614461349d611cffc16210
Reviewed-on: https://code.wireshark.org/review/4512
Reviewed-by: Guy Harris <guy@alum.mit.edu>
2014-10-07 01:00:57 +00:00
}
2008-01-09 22:58:34 +00:00
/* ERF record too short, accept the file,
2012-03-02 00:31:30 +00:00
only if the very first records have been successfully checked */
2008-01-09 22:58:34 +00:00
if ( i < MIN_RECORDS_FOR_ERF_CHECK ) {
2014-10-09 23:44:15 +00:00
return WTAP_OPEN_NOT_MINE ;
2008-01-09 22:58:34 +00:00
}
2007-10-08 11:41:21 +00:00
}
2010-10-28 14:33:55 +00:00
valid_prev = 1 ;
2007-10-08 11:41:21 +00:00
} /* records_for_erf_check */
2007-11-19 19:09:01 +00:00
2014-05-09 05:18:49 +00:00
if ( file_seek ( wth - > fh , 0L , SEEK_SET , err ) = = - 1 ) { /* rewind */
2014-10-09 23:44:15 +00:00
return WTAP_OPEN_ERROR ;
2007-10-08 11:41:21 +00:00
}
2007-11-19 19:09:01 +00:00
2007-10-08 11:41:21 +00:00
/* This is an ERF file */
2021-02-19 22:46:42 +00:00
wth - > file_type_subtype = erf_file_type_subtype ;
2014-05-09 05:18:49 +00:00
wth - > snapshot_length = 0 ; /* not available in header, only in frame */
2007-10-08 11:41:21 +00:00
/*
2008-01-10 08:49:11 +00:00
* Use the encapsulation for ERF records .
2007-10-08 11:41:21 +00:00
*/
2014-05-09 05:18:49 +00:00
wth - > file_encap = WTAP_ENCAP_ERF ;
2007-10-08 11:41:21 +00:00
2014-05-09 05:18:49 +00:00
wth - > subtype_read = erf_read ;
wth - > subtype_seek_read = erf_seek_read ;
2016-03-11 03:44:16 +00:00
wth - > subtype_close = erf_close ;
2014-09-28 18:37:06 +00:00
wth - > file_tsprec = WTAP_TSPREC_NSEC ;
2007-10-08 11:41:21 +00:00
2016-03-11 03:44:16 +00:00
wth - > priv = erf_priv_create ( ) ;
2012-05-23 06:41:37 +00:00
2014-10-09 23:44:15 +00:00
return WTAP_OPEN_MINE ;
2003-08-26 07:10:39 +00:00
}
/* Read the next packet */
2019-04-05 01:56:27 +00:00
static gboolean erf_read ( wtap * wth , wtap_rec * rec , Buffer * buf ,
int * err , gchar * * err_info , gint64 * data_offset )
2003-08-26 07:10:39 +00:00
{
2007-10-08 11:41:21 +00:00
erf_header_t erf_header ;
2012-03-02 00:31:30 +00:00
guint32 packet_size , bytes_read ;
2017-06-01 08:34:25 +00:00
GPtrArray * anchor_mappings_to_update ;
2007-10-08 11:41:21 +00:00
2014-05-09 05:18:49 +00:00
* data_offset = file_tell ( wth - > fh ) ;
2007-11-19 19:09:01 +00:00
2017-06-01 08:34:25 +00:00
anchor_mappings_to_update = g_ptr_array_new_with_free_func ( erf_anchor_mapping_destroy ) ;
2007-10-08 11:41:21 +00:00
do {
2019-04-05 01:56:27 +00:00
if ( ! erf_read_header ( wth , wth - > fh , rec , & erf_header ,
2017-06-01 08:34:25 +00:00
err , err_info , & bytes_read , & packet_size ,
anchor_mappings_to_update ) ) {
g_ptr_array_free ( anchor_mappings_to_update , TRUE ) ;
2014-05-23 10:50:02 +00:00
return FALSE ;
2007-10-08 11:41:21 +00:00
}
2007-11-19 19:09:01 +00:00
2019-04-05 01:56:27 +00:00
if ( ! wtap_read_packet_bytes ( wth - > fh , buf , packet_size , err , err_info ) ) {
2017-06-01 08:34:25 +00:00
g_ptr_array_free ( anchor_mappings_to_update , TRUE ) ;
2014-05-23 10:50:02 +00:00
return FALSE ;
2017-06-01 08:34:25 +00:00
}
2010-10-28 14:33:55 +00:00
2016-03-11 03:44:16 +00:00
/*
2017-06-01 08:34:25 +00:00
* If Provenance metadata record , frame buffer could hold the meta erf tags .
* It can also contain per packet comments which can be associated to another
* frame .
2016-03-11 03:44:16 +00:00
*/
if ( ( erf_header . type & 0x7F ) = = ERF_TYPE_META & & packet_size > 0 )
{
2021-06-18 23:22:54 +00:00
if ( populate_summary_info ( ( erf_t * ) wth - > priv , wth , & rec - > rec_header . packet_header . pseudo_header , buf , packet_size , anchor_mappings_to_update , err , err_info ) < 0 ) {
g_ptr_array_free ( anchor_mappings_to_update , TRUE ) ;
return FALSE ;
}
2016-03-11 03:44:16 +00:00
}
2010-10-28 14:33:55 +00:00
} while ( erf_header . type = = ERF_TYPE_PAD ) ;
2007-10-08 11:41:21 +00:00
2017-06-01 08:34:25 +00:00
g_ptr_array_free ( anchor_mappings_to_update , TRUE ) ;
2014-05-23 10:50:02 +00:00
return TRUE ;
2003-08-26 07:10:39 +00:00
}
2014-05-23 10:50:02 +00:00
static gboolean erf_seek_read ( wtap * wth , gint64 seek_off ,
2018-02-09 00:19:12 +00:00
wtap_rec * rec , Buffer * buf ,
2014-05-23 10:50:02 +00:00
int * err , gchar * * err_info )
2003-08-26 07:10:39 +00:00
{
2007-10-08 11:41:21 +00:00
erf_header_t erf_header ;
2012-03-02 00:31:30 +00:00
guint32 packet_size ;
2017-06-01 08:34:25 +00:00
GPtrArray * anchor_mappings_to_update ;
2003-08-26 07:10:39 +00:00
2014-05-09 05:18:49 +00:00
if ( file_seek ( wth - > random_fh , seek_off , SEEK_SET , err ) = = - 1 )
2014-05-23 10:50:02 +00:00
return FALSE ;
2007-11-19 19:09:01 +00:00
2017-06-01 08:34:25 +00:00
anchor_mappings_to_update = g_ptr_array_new_with_free_func ( erf_anchor_mapping_destroy ) ;
2008-07-14 05:46:09 +00:00
do {
2018-02-09 00:19:12 +00:00
if ( ! erf_read_header ( wth , wth - > random_fh , rec , & erf_header ,
2017-06-01 08:34:25 +00:00
err , err_info , NULL , & packet_size , anchor_mappings_to_update ) ) {
g_ptr_array_free ( anchor_mappings_to_update , TRUE ) ;
2014-05-23 10:50:02 +00:00
return FALSE ;
2017-06-01 08:34:25 +00:00
}
2008-07-14 05:46:09 +00:00
} while ( erf_header . type = = ERF_TYPE_PAD ) ;
2003-08-26 07:10:39 +00:00
2017-06-01 08:34:25 +00:00
g_ptr_array_free ( anchor_mappings_to_update , TRUE ) ;
2014-05-23 10:50:02 +00:00
return wtap_read_packet_bytes ( wth - > random_fh , buf , packet_size ,
err , err_info ) ;
2003-08-26 07:10:39 +00:00
}
2017-06-01 08:34:25 +00:00
static struct erf_anchor_mapping * erf_find_anchor_mapping ( erf_t * priv ,
guint64 host_id ,
guint64 anchor_id )
{
struct erf_anchor_mapping mapping = {
host_id ,
anchor_id ,
0 ,
NULL
} ;
if ( ! priv ) {
return NULL ;
}
return ( struct erf_anchor_mapping * ) g_hash_table_lookup ( priv - > anchor_map , & mapping ) ;
}
2016-03-11 03:44:16 +00:00
static gboolean erf_read_header ( wtap * wth , FILE_T fh ,
2018-02-09 00:19:12 +00:00
wtap_rec * rec ,
Add some higher-level file-read APIs and use them.
Add wtap_read_bytes(), which takes a FILE_T, a pointer, a byte count, an
error number pointer, and an error string pointer as arguments, and that
treats a short read of any sort, including a read that returns 0 bytes,
as a WTAP_ERR_SHORT_READ error, and that returns the error number and
string through its last two arguments.
Add wtap_read_bytes_or_eof(), which is similar, but that treats a read
that returns 0 bytes as an EOF, supplying an error number of 0 as an EOF
indication.
Use those in file readers; that simplifies the code and makes it less
likely that somebody will fail to supply the error number and error
string on a file read error.
Change-Id: Ia5dba2a6f81151e87b614461349d611cffc16210
Reviewed-on: https://code.wireshark.org/review/4512
Reviewed-by: Guy Harris <guy@alum.mit.edu>
2014-10-07 01:00:57 +00:00
erf_header_t * erf_header ,
int * err ,
gchar * * err_info ,
guint32 * bytes_read ,
2017-06-01 08:34:25 +00:00
guint32 * packet_size ,
GPtrArray * anchor_mappings_to_update )
2003-08-26 07:10:39 +00:00
{
2018-02-09 00:19:12 +00:00
union wtap_pseudo_header * pseudo_header = & rec - > rec_header . packet_header . pseudo_header ;
2012-03-02 00:31:30 +00:00
guint8 erf_exhdr [ 8 ] ;
2008-09-29 16:20:24 +00:00
guint64 erf_exhdr_sw ;
2012-03-02 00:31:30 +00:00
guint8 type = 0 ;
2016-01-13 08:10:48 +00:00
guint32 mc_hdr ;
guint32 aal2_hdr ;
struct wtap_erf_eth_hdr eth_hdr ;
2012-03-02 00:31:30 +00:00
guint32 skiplen = 0 ;
int i = 0 ;
int max = sizeof ( pseudo_header - > erf . ehdr_list ) / sizeof ( struct erf_ehdr ) ;
2017-06-01 08:34:25 +00:00
erf_t * priv = ( erf_t * ) wth - > priv ;
2021-06-18 23:22:54 +00:00
int interface_id ;
2007-10-08 11:41:21 +00:00
2016-10-13 23:46:29 +00:00
guint64 host_id = ERF_META_HOST_ID_IMPLICIT ;
2016-03-11 03:44:16 +00:00
guint8 source_id = 0 ;
guint8 if_num = 0 ;
gboolean host_id_found = FALSE ;
Add some higher-level file-read APIs and use them.
Add wtap_read_bytes(), which takes a FILE_T, a pointer, a byte count, an
error number pointer, and an error string pointer as arguments, and that
treats a short read of any sort, including a read that returns 0 bytes,
as a WTAP_ERR_SHORT_READ error, and that returns the error number and
string through its last two arguments.
Add wtap_read_bytes_or_eof(), which is similar, but that treats a read
that returns 0 bytes as an EOF, supplying an error number of 0 as an EOF
indication.
Use those in file readers; that simplifies the code and makes it less
likely that somebody will fail to supply the error number and error
string on a file read error.
Change-Id: Ia5dba2a6f81151e87b614461349d611cffc16210
Reviewed-on: https://code.wireshark.org/review/4512
Reviewed-by: Guy Harris <guy@alum.mit.edu>
2014-10-07 01:00:57 +00:00
if ( ! wtap_read_bytes_or_eof ( fh , erf_header , sizeof ( * erf_header ) , err , err_info ) ) {
return FALSE ;
}
2007-10-08 11:41:21 +00:00
if ( bytes_read ! = NULL ) {
* bytes_read = sizeof ( * erf_header ) ;
}
2007-11-19 19:09:01 +00:00
2009-04-22 03:07:37 +00:00
* packet_size = g_ntohs ( erf_header - > rlen ) - ( guint32 ) sizeof ( * erf_header ) ;
2007-11-19 19:09:01 +00:00
Allow bigger snapshot lengths for D-Bus captures.
Use WTAP_MAX_PACKET_SIZE_STANDARD, set to 256KB, for everything except
for D-Bus captures. Use WTAP_MAX_PACKET_SIZE_DBUS, set to 128MB, for
them, because that's the largest possible D-Bus message size. See
https://bugs.freedesktop.org/show_bug.cgi?id=100220
for an example of the problems caused by limiting the snapshot length to
256KB for D-Bus.
Have a snapshot length of 0 in a capture_file structure mean "there is
no snapshot length for the file"; we don't need the has_snap field in
that case, a value of 0 mean "no, we don't have a snapshot length".
In dumpcap, start out with a pipe buffer size of 2KB, and grow it as
necessary. When checking for a too-big packet from a pipe, check
against the appropriate maximum - 128MB for DLT_DBUS, 256KB for
everything else.
Change-Id: Ib2ce7a0cf37b971fbc0318024fd011e18add8b20
Reviewed-on: https://code.wireshark.org/review/21952
Petri-Dish: Guy Harris <guy@alum.mit.edu>
Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org>
Reviewed-by: Guy Harris <guy@alum.mit.edu>
2017-06-05 01:58:40 +00:00
if ( * packet_size > WTAP_MAX_PACKET_SIZE_STANDARD ) {
2007-10-08 11:41:21 +00:00
/*
* Probably a corrupt capture file ; don ' t blow up trying
* to allocate space for an immensely - large packet .
*/
2011-12-13 09:53:50 +00:00
* err = WTAP_ERR_BAD_FILE ;
2007-10-08 11:41:21 +00:00
* err_info = g_strdup_printf ( " erf: File has %u-byte packet, bigger than maximum of %u " ,
Allow bigger snapshot lengths for D-Bus captures.
Use WTAP_MAX_PACKET_SIZE_STANDARD, set to 256KB, for everything except
for D-Bus captures. Use WTAP_MAX_PACKET_SIZE_DBUS, set to 128MB, for
them, because that's the largest possible D-Bus message size. See
https://bugs.freedesktop.org/show_bug.cgi?id=100220
for an example of the problems caused by limiting the snapshot length to
256KB for D-Bus.
Have a snapshot length of 0 in a capture_file structure mean "there is
no snapshot length for the file"; we don't need the has_snap field in
that case, a value of 0 mean "no, we don't have a snapshot length".
In dumpcap, start out with a pipe buffer size of 2KB, and grow it as
necessary. When checking for a too-big packet from a pipe, check
against the appropriate maximum - 128MB for DLT_DBUS, 256KB for
everything else.
Change-Id: Ib2ce7a0cf37b971fbc0318024fd011e18add8b20
Reviewed-on: https://code.wireshark.org/review/21952
Petri-Dish: Guy Harris <guy@alum.mit.edu>
Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org>
Reviewed-by: Guy Harris <guy@alum.mit.edu>
2017-06-05 01:58:40 +00:00
* packet_size , WTAP_MAX_PACKET_SIZE_STANDARD ) ;
2007-10-08 11:41:21 +00:00
return FALSE ;
}
2007-11-19 19:09:01 +00:00
2011-10-21 19:07:42 +00:00
if ( * packet_size = = 0 ) {
2012-02-14 22:31:33 +00:00
/* If this isn't a pad record, it's a corrupt packet; bail out */
if ( ( erf_header - > type & 0x7F ) ! = ERF_TYPE_PAD ) {
* err = WTAP_ERR_BAD_FILE ;
2016-06-06 02:24:47 +00:00
* err_info = g_strdup ( " erf: File has 0 byte packet " ) ;
2011-10-21 19:07:42 +00:00
2012-02-14 22:31:33 +00:00
return FALSE ;
}
2011-10-21 19:07:42 +00:00
}
2012-10-17 20:28:22 +00:00
{
2013-12-03 20:35:50 +00:00
guint64 ts = pletoh64 ( & erf_header - > ts ) ;
2007-11-19 19:09:01 +00:00
2021-02-19 22:46:42 +00:00
/*if ((erf_header->type & 0x7f) != ERF_TYPE_META || wth->file_type_subtype != file_type_subtype_erf) {*/
2018-02-09 00:19:12 +00:00
rec - > rec_type = REC_TYPE_PACKET ;
2016-03-11 03:44:16 +00:00
/*
* XXX : ERF_TYPE_META records should ideally be FT_SPECIFIC for display
* purposes , but currently ft_specific_record_phdr clashes with erf_mc_phdr
2018-01-09 00:38:10 +00:00
* and the pcapng dumper assumes it is a pcapng block type . Ideally we
* would register a block handler with pcapng and write out the closest
* pcapng block , or a custom block / Provenance record .
2016-03-11 03:44:16 +00:00
*
*/
#if 0
} else {
/*
* TODO : how to identify , distinguish and timestamp events ?
2018-01-09 00:38:10 +00:00
* What to do about ENCAP_ERF in pcap / pcapng ? Filetype dissector is
2016-03-11 03:44:16 +00:00
* chosen by wth - > file_type_subtype ?
*/
2017-06-01 08:34:25 +00:00
/* For now just treat all Provenance records as reports */
2018-02-09 00:19:12 +00:00
rec - > rec_type = REC_TYPE_FT_SPECIFIC_REPORT ;
2016-03-11 03:44:16 +00:00
/* XXX: phdr ft_specific_record_phdr? */
}
# endif
2018-02-09 00:19:12 +00:00
rec - > presence_flags = WTAP_HAS_TS | WTAP_HAS_CAP_LEN | WTAP_HAS_INTERFACE_ID ;
rec - > ts . secs = ( long ) ( ts > > 32 ) ;
2012-03-02 00:31:30 +00:00
ts = ( ( ts & 0xffffffff ) * 1000 * 1000 * 1000 ) ;
2007-10-08 11:41:21 +00:00
ts + = ( ts & 0x80000000 ) < < 1 ; /* rounding */
2018-02-09 00:19:12 +00:00
rec - > ts . nsecs = ( ( int ) ( ts > > 32 ) ) ;
if ( rec - > ts . nsecs > = 1000000000 ) {
rec - > ts . nsecs - = 1000000000 ;
rec - > ts . secs + = 1 ;
2007-10-08 11:41:21 +00:00
}
2016-03-11 03:44:16 +00:00
if_num = erf_header - > flags & 0x03 ;
2007-10-08 11:41:21 +00:00
}
2007-11-19 19:09:01 +00:00
2007-10-08 11:41:21 +00:00
/* Copy the ERF pseudo header */
2010-02-02 04:56:39 +00:00
memset ( & pseudo_header - > erf , 0 , sizeof ( pseudo_header - > erf ) ) ;
2013-12-03 20:35:50 +00:00
pseudo_header - > erf . phdr . ts = pletoh64 ( & erf_header - > ts ) ;
2007-10-08 11:41:21 +00:00
pseudo_header - > erf . phdr . type = erf_header - > type ;
pseudo_header - > erf . phdr . flags = erf_header - > flags ;
pseudo_header - > erf . phdr . rlen = g_ntohs ( erf_header - > rlen ) ;
pseudo_header - > erf . phdr . lctr = g_ntohs ( erf_header - > lctr ) ;
pseudo_header - > erf . phdr . wlen = g_ntohs ( erf_header - > wlen ) ;
2008-09-29 16:20:24 +00:00
/* Copy the ERF extension header into the pseudo header */
type = erf_header - > type ;
while ( type & 0x80 ) {
Add some higher-level file-read APIs and use them.
Add wtap_read_bytes(), which takes a FILE_T, a pointer, a byte count, an
error number pointer, and an error string pointer as arguments, and that
treats a short read of any sort, including a read that returns 0 bytes,
as a WTAP_ERR_SHORT_READ error, and that returns the error number and
string through its last two arguments.
Add wtap_read_bytes_or_eof(), which is similar, but that treats a read
that returns 0 bytes as an EOF, supplying an error number of 0 as an EOF
indication.
Use those in file readers; that simplifies the code and makes it less
likely that somebody will fail to supply the error number and error
string on a file read error.
Change-Id: Ia5dba2a6f81151e87b614461349d611cffc16210
Reviewed-on: https://code.wireshark.org/review/4512
Reviewed-by: Guy Harris <guy@alum.mit.edu>
2014-10-07 01:00:57 +00:00
if ( ! wtap_read_bytes ( fh , & erf_exhdr , sizeof ( erf_exhdr ) ,
2014-10-07 07:30:35 +00:00
err , err_info ) )
Add some higher-level file-read APIs and use them.
Add wtap_read_bytes(), which takes a FILE_T, a pointer, a byte count, an
error number pointer, and an error string pointer as arguments, and that
treats a short read of any sort, including a read that returns 0 bytes,
as a WTAP_ERR_SHORT_READ error, and that returns the error number and
string through its last two arguments.
Add wtap_read_bytes_or_eof(), which is similar, but that treats a read
that returns 0 bytes as an EOF, supplying an error number of 0 as an EOF
indication.
Use those in file readers; that simplifies the code and makes it less
likely that somebody will fail to supply the error number and error
string on a file read error.
Change-Id: Ia5dba2a6f81151e87b614461349d611cffc16210
Reviewed-on: https://code.wireshark.org/review/4512
Reviewed-by: Guy Harris <guy@alum.mit.edu>
2014-10-07 01:00:57 +00:00
return FALSE ;
2012-03-02 00:31:30 +00:00
if ( bytes_read ! = NULL )
* bytes_read + = ( guint32 ) sizeof ( erf_exhdr ) ;
* packet_size - = ( guint32 ) sizeof ( erf_exhdr ) ;
skiplen + = ( guint32 ) sizeof ( erf_exhdr ) ;
2013-12-03 20:35:50 +00:00
erf_exhdr_sw = pntoh64 ( erf_exhdr ) ;
2012-03-02 00:31:30 +00:00
if ( i < max )
memcpy ( & pseudo_header - > erf . ehdr_list [ i ] . ehdr , & erf_exhdr_sw , sizeof ( erf_exhdr_sw ) ) ;
type = erf_exhdr [ 0 ] ;
2016-03-11 03:44:16 +00:00
/*
* XXX : Only want first Source ID and Host ID , and want to preserve HID n SID 0 ( see
* erf_populate_interface )
*/
2017-06-01 08:34:25 +00:00
switch ( type & 0x7FU ) {
2016-03-11 03:44:16 +00:00
case ERF_EXT_HDR_TYPE_HOST_ID :
if ( ! host_id_found )
host_id = erf_exhdr_sw & ERF_EHDR_HOST_ID_MASK ;
host_id_found = TRUE ;
/* Fall through */
case ERF_EXT_HDR_TYPE_FLOW_ID :
2017-06-01 08:34:25 +00:00
/* Source ID is present in both Flow ID and Host ID extension headers */
2016-03-11 03:44:16 +00:00
if ( ! source_id )
source_id = ( erf_exhdr_sw > > 48 ) & 0xff ;
break ;
2017-06-01 08:34:25 +00:00
case ERF_EXT_HDR_TYPE_ANCHOR_ID :
/* handled below*/
break ;
2016-03-11 03:44:16 +00:00
}
2012-03-02 00:31:30 +00:00
i + + ;
2008-09-29 16:20:24 +00:00
}
2021-06-18 23:22:54 +00:00
interface_id = erf_populate_interface ( ( erf_t * ) wth - > priv , wth , pseudo_header , host_id , source_id , if_num , err , err_info ) ;
if ( interface_id < 0 ) {
return FALSE ;
}
rec - > rec_header . packet_header . interface_id = ( guint ) interface_id ;
2016-03-11 03:44:16 +00:00
2017-06-01 08:34:25 +00:00
/* Try to find comment links using Anchor ID. Done here after we found the first Host ID and have updated the implicit Host ID. */
2018-02-09 00:19:12 +00:00
erf_update_anchors_from_header ( priv , rec , pseudo_header , host_id , anchor_mappings_to_update ) ;
2017-06-01 08:34:25 +00:00
2008-09-29 16:20:24 +00:00
switch ( erf_header - > type & 0x7F ) {
2012-03-02 00:31:30 +00:00
case ERF_TYPE_IPV4 :
case ERF_TYPE_IPV6 :
case ERF_TYPE_RAW_LINK :
case ERF_TYPE_INFINIBAND :
case ERF_TYPE_INFINIBAND_LINK :
2015-11-19 03:23:53 +00:00
case ERF_TYPE_META :
2016-02-04 15:10:28 +00:00
case ERF_TYPE_OPA_SNC :
case ERF_TYPE_OPA_9B :
2012-03-02 00:31:30 +00:00
#if 0
2012-10-17 20:28:22 +00:00
{
2018-02-09 00:19:12 +00:00
rec - > rec_header . packet_header . len = g_htons ( erf_header - > wlen ) ;
rec - > rec_header . packet_header . caplen = g_htons ( erf_header - > wlen ) ;
2012-03-02 00:31:30 +00:00
}
return TRUE ;
# endif
break ;
case ERF_TYPE_PAD :
case ERF_TYPE_HDLC_POS :
case ERF_TYPE_COLOR_HDLC_POS :
case ERF_TYPE_DSM_COLOR_HDLC_POS :
2015-12-19 18:24:47 +00:00
case ERF_TYPE_COLOR_HASH_POS :
2012-03-02 00:31:30 +00:00
case ERF_TYPE_ATM :
case ERF_TYPE_AAL5 :
break ;
case ERF_TYPE_ETH :
case ERF_TYPE_COLOR_ETH :
case ERF_TYPE_DSM_COLOR_ETH :
2015-12-19 18:24:47 +00:00
case ERF_TYPE_COLOR_HASH_ETH :
Add some higher-level file-read APIs and use them.
Add wtap_read_bytes(), which takes a FILE_T, a pointer, a byte count, an
error number pointer, and an error string pointer as arguments, and that
treats a short read of any sort, including a read that returns 0 bytes,
as a WTAP_ERR_SHORT_READ error, and that returns the error number and
string through its last two arguments.
Add wtap_read_bytes_or_eof(), which is similar, but that treats a read
that returns 0 bytes as an EOF, supplying an error number of 0 as an EOF
indication.
Use those in file readers; that simplifies the code and makes it less
likely that somebody will fail to supply the error number and error
string on a file read error.
Change-Id: Ia5dba2a6f81151e87b614461349d611cffc16210
Reviewed-on: https://code.wireshark.org/review/4512
Reviewed-by: Guy Harris <guy@alum.mit.edu>
2014-10-07 01:00:57 +00:00
if ( ! wtap_read_bytes ( fh , & eth_hdr , sizeof ( eth_hdr ) , err , err_info ) )
return FALSE ;
2012-03-02 00:31:30 +00:00
if ( bytes_read ! = NULL )
* bytes_read + = ( guint32 ) sizeof ( eth_hdr ) ;
* packet_size - = ( guint32 ) sizeof ( eth_hdr ) ;
skiplen + = ( guint32 ) sizeof ( eth_hdr ) ;
2016-01-13 08:10:48 +00:00
pseudo_header - > erf . subhdr . eth_hdr = eth_hdr ;
2012-03-02 00:31:30 +00:00
break ;
case ERF_TYPE_MC_HDLC :
case ERF_TYPE_MC_RAW :
case ERF_TYPE_MC_ATM :
case ERF_TYPE_MC_RAW_CHANNEL :
case ERF_TYPE_MC_AAL5 :
case ERF_TYPE_MC_AAL2 :
case ERF_TYPE_COLOR_MC_HDLC_POS :
Add some higher-level file-read APIs and use them.
Add wtap_read_bytes(), which takes a FILE_T, a pointer, a byte count, an
error number pointer, and an error string pointer as arguments, and that
treats a short read of any sort, including a read that returns 0 bytes,
as a WTAP_ERR_SHORT_READ error, and that returns the error number and
string through its last two arguments.
Add wtap_read_bytes_or_eof(), which is similar, but that treats a read
that returns 0 bytes as an EOF, supplying an error number of 0 as an EOF
indication.
Use those in file readers; that simplifies the code and makes it less
likely that somebody will fail to supply the error number and error
string on a file read error.
Change-Id: Ia5dba2a6f81151e87b614461349d611cffc16210
Reviewed-on: https://code.wireshark.org/review/4512
Reviewed-by: Guy Harris <guy@alum.mit.edu>
2014-10-07 01:00:57 +00:00
if ( ! wtap_read_bytes ( fh , & mc_hdr , sizeof ( mc_hdr ) , err , err_info ) )
return FALSE ;
2012-03-02 00:31:30 +00:00
if ( bytes_read ! = NULL )
* bytes_read + = ( guint32 ) sizeof ( mc_hdr ) ;
* packet_size - = ( guint32 ) sizeof ( mc_hdr ) ;
skiplen + = ( guint32 ) sizeof ( mc_hdr ) ;
2016-01-13 03:05:15 +00:00
pseudo_header - > erf . subhdr . mc_hdr = g_ntohl ( mc_hdr ) ;
2012-03-02 00:31:30 +00:00
break ;
2016-01-13 05:21:42 +00:00
case ERF_TYPE_AAL2 :
if ( ! wtap_read_bytes ( fh , & aal2_hdr , sizeof ( aal2_hdr ) , err , err_info ) )
return FALSE ;
if ( bytes_read ! = NULL )
* bytes_read + = ( guint32 ) sizeof ( aal2_hdr ) ;
* packet_size - = ( guint32 ) sizeof ( aal2_hdr ) ;
skiplen + = ( guint32 ) sizeof ( aal2_hdr ) ;
pseudo_header - > erf . subhdr . aal2_hdr = g_ntohl ( aal2_hdr ) ;
break ;
2012-03-02 00:31:30 +00:00
case ERF_TYPE_IP_COUNTER :
case ERF_TYPE_TCP_FLOW_COUNTER :
/* unsupported, continue with default: */
default :
2016-03-21 04:32:13 +00:00
/* let the dissector dissect as unknown record type for forwards compatibility */
break ;
2007-10-08 11:41:21 +00:00
}
2007-11-19 19:09:01 +00:00
2012-10-17 20:28:22 +00:00
{
2018-02-09 00:19:12 +00:00
rec - > rec_header . packet_header . len = g_ntohs ( erf_header - > wlen ) ;
rec - > rec_header . packet_header . caplen = MIN ( g_ntohs ( erf_header - > wlen ) ,
2016-01-13 03:05:15 +00:00
g_ntohs ( erf_header - > rlen ) - ( guint32 ) sizeof ( * erf_header ) - skiplen ) ;
2007-10-08 11:41:21 +00:00
}
2011-10-21 19:07:42 +00:00
Allow bigger snapshot lengths for D-Bus captures.
Use WTAP_MAX_PACKET_SIZE_STANDARD, set to 256KB, for everything except
for D-Bus captures. Use WTAP_MAX_PACKET_SIZE_DBUS, set to 128MB, for
them, because that's the largest possible D-Bus message size. See
https://bugs.freedesktop.org/show_bug.cgi?id=100220
for an example of the problems caused by limiting the snapshot length to
256KB for D-Bus.
Have a snapshot length of 0 in a capture_file structure mean "there is
no snapshot length for the file"; we don't need the has_snap field in
that case, a value of 0 mean "no, we don't have a snapshot length".
In dumpcap, start out with a pipe buffer size of 2KB, and grow it as
necessary. When checking for a too-big packet from a pipe, check
against the appropriate maximum - 128MB for DLT_DBUS, 256KB for
everything else.
Change-Id: Ib2ce7a0cf37b971fbc0318024fd011e18add8b20
Reviewed-on: https://code.wireshark.org/review/21952
Petri-Dish: Guy Harris <guy@alum.mit.edu>
Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org>
Reviewed-by: Guy Harris <guy@alum.mit.edu>
2017-06-05 01:58:40 +00:00
if ( * packet_size > WTAP_MAX_PACKET_SIZE_STANDARD ) {
2011-10-21 19:07:42 +00:00
/*
* Probably a corrupt capture file ; don ' t blow up trying
* to allocate space for an immensely - large packet .
*/
2011-12-13 09:53:50 +00:00
* err = WTAP_ERR_BAD_FILE ;
2011-10-21 19:07:42 +00:00
* err_info = g_strdup_printf ( " erf: File has %u-byte packet, bigger than maximum of %u " ,
Allow bigger snapshot lengths for D-Bus captures.
Use WTAP_MAX_PACKET_SIZE_STANDARD, set to 256KB, for everything except
for D-Bus captures. Use WTAP_MAX_PACKET_SIZE_DBUS, set to 128MB, for
them, because that's the largest possible D-Bus message size. See
https://bugs.freedesktop.org/show_bug.cgi?id=100220
for an example of the problems caused by limiting the snapshot length to
256KB for D-Bus.
Have a snapshot length of 0 in a capture_file structure mean "there is
no snapshot length for the file"; we don't need the has_snap field in
that case, a value of 0 mean "no, we don't have a snapshot length".
In dumpcap, start out with a pipe buffer size of 2KB, and grow it as
necessary. When checking for a too-big packet from a pipe, check
against the appropriate maximum - 128MB for DLT_DBUS, 256KB for
everything else.
Change-Id: Ib2ce7a0cf37b971fbc0318024fd011e18add8b20
Reviewed-on: https://code.wireshark.org/review/21952
Petri-Dish: Guy Harris <guy@alum.mit.edu>
Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org>
Reviewed-by: Guy Harris <guy@alum.mit.edu>
2017-06-05 01:58:40 +00:00
* packet_size , WTAP_MAX_PACKET_SIZE_STANDARD ) ;
2011-10-21 19:07:42 +00:00
return FALSE ;
}
2007-10-08 11:41:21 +00:00
return TRUE ;
2003-08-26 07:10:39 +00:00
}
2011-08-31 20:50:15 +00:00
static int wtap_wtap_encap_to_erf_encap ( int encap )
{
unsigned int i ;
for ( i = 0 ; i < NUM_ERF_ENCAPS ; i + + ) {
if ( erf_to_wtap_map [ i ] . wtap_encap_value = = encap )
return erf_to_wtap_map [ i ] . erf_encap_value ;
}
return - 1 ;
}
2014-05-09 05:18:49 +00:00
static gboolean erf_write_phdr ( wtap_dumper * wdh , int encap , const union wtap_pseudo_header * pseudo_header , int * err )
2011-08-31 20:50:15 +00:00
{
guint8 erf_hdr [ sizeof ( struct erf_mc_phdr ) ] ;
2016-01-13 08:10:48 +00:00
guint8 erf_subhdr [ sizeof ( union erf_subhdr ) ] ;
2011-08-31 20:50:15 +00:00
guint8 ehdr [ 8 * MAX_ERF_EHDR ] ;
2012-03-02 00:31:30 +00:00
size_t size = 0 ;
2011-08-31 20:50:15 +00:00
size_t subhdr_size = 0 ;
2012-03-02 00:31:30 +00:00
int i = 0 ;
2013-06-04 04:00:59 +00:00
guint8 has_more = 0 ;
2011-08-31 20:50:15 +00:00
switch ( encap ) {
case WTAP_ENCAP_ERF :
memset ( & erf_hdr , 0 , sizeof ( erf_hdr ) ) ;
2011-11-17 09:24:15 +00:00
phtolell ( & erf_hdr [ 0 ] , pseudo_header - > erf . phdr . ts ) ;
2011-08-31 20:50:15 +00:00
erf_hdr [ 8 ] = pseudo_header - > erf . phdr . type ;
erf_hdr [ 9 ] = pseudo_header - > erf . phdr . flags ;
phtons ( & erf_hdr [ 10 ] , pseudo_header - > erf . phdr . rlen ) ;
phtons ( & erf_hdr [ 12 ] , pseudo_header - > erf . phdr . lctr ) ;
phtons ( & erf_hdr [ 14 ] , pseudo_header - > erf . phdr . wlen ) ;
size = sizeof ( struct erf_phdr ) ;
switch ( pseudo_header - > erf . phdr . type & 0x7F ) {
case ERF_TYPE_MC_HDLC :
case ERF_TYPE_MC_RAW :
case ERF_TYPE_MC_ATM :
case ERF_TYPE_MC_RAW_CHANNEL :
case ERF_TYPE_MC_AAL5 :
case ERF_TYPE_MC_AAL2 :
case ERF_TYPE_COLOR_MC_HDLC_POS :
phtonl ( & erf_subhdr [ 0 ] , pseudo_header - > erf . subhdr . mc_hdr ) ;
subhdr_size + = ( int ) sizeof ( struct erf_mc_hdr ) ;
break ;
2016-01-13 05:21:42 +00:00
case ERF_TYPE_AAL2 :
phtonl ( & erf_subhdr [ 0 ] , pseudo_header - > erf . subhdr . aal2_hdr ) ;
subhdr_size + = ( int ) sizeof ( struct erf_aal2_hdr ) ;
break ;
2011-08-31 20:50:15 +00:00
case ERF_TYPE_ETH :
case ERF_TYPE_COLOR_ETH :
case ERF_TYPE_DSM_COLOR_ETH :
2015-12-19 18:24:47 +00:00
case ERF_TYPE_COLOR_HASH_ETH :
2016-01-13 08:10:48 +00:00
memcpy ( & erf_subhdr [ 0 ] , & pseudo_header - > erf . subhdr . eth_hdr , sizeof pseudo_header - > erf . subhdr . eth_hdr ) ;
2017-12-27 21:17:51 +00:00
subhdr_size + = erf_eth_hdr_size ;
2011-08-31 20:50:15 +00:00
break ;
default :
break ;
}
break ;
default :
return FALSE ;
}
2014-05-09 05:18:49 +00:00
if ( ! wtap_dump_file_write ( wdh , erf_hdr , size , err ) )
2011-08-31 20:50:15 +00:00
return FALSE ;
wdh - > bytes_dumped + = size ;
/*write out up to MAX_ERF_EHDR extension headers*/
2013-06-04 04:00:59 +00:00
has_more = pseudo_header - > erf . phdr . type & 0x80 ;
if ( has_more ) { /*we have extension headers*/
2011-08-31 20:50:15 +00:00
do {
phtonll ( ehdr + ( i * 8 ) , pseudo_header - > erf . ehdr_list [ i ] . ehdr ) ;
if ( i = = MAX_ERF_EHDR - 1 ) ehdr [ i * 8 ] = ehdr [ i * 8 ] & 0x7F ;
2013-06-04 04:00:59 +00:00
has_more = ehdr [ i * 8 ] & 0x80 ;
2011-08-31 20:50:15 +00:00
i + + ;
2013-06-04 04:00:59 +00:00
} while ( has_more & & i < MAX_ERF_EHDR ) ;
2014-05-09 05:18:49 +00:00
if ( ! wtap_dump_file_write ( wdh , ehdr , 8 * i , err ) )
2011-09-03 20:47:58 +00:00
return FALSE ;
2013-06-04 04:00:59 +00:00
wdh - > bytes_dumped + = 8 * i ;
2011-08-31 20:50:15 +00:00
}
2017-06-01 08:34:25 +00:00
if ( ! wtap_dump_file_write ( wdh , erf_subhdr , subhdr_size , err ) )
return FALSE ;
wdh - > bytes_dumped + = subhdr_size ;
return TRUE ;
}
static void erf_dump_priv_init_gen_time ( erf_dump_t * dump_priv ) {
2019-09-07 10:20:54 +00:00
gint64 real_time ;
2017-06-01 08:34:25 +00:00
2019-09-07 10:20:54 +00:00
real_time = g_get_real_time ( ) ;
2017-06-01 08:34:25 +00:00
/* Convert TimeVal to ERF timestamp */
2019-09-07 10:20:54 +00:00
dump_priv - > gen_time = ( ( real_time / G_USEC_PER_SEC ) < < 32 ) + ( ( real_time % G_USEC_PER_SEC ) < < 32 ) / 1000 / 1000 ;
2017-06-01 08:34:25 +00:00
}
2021-06-27 20:25:16 +00:00
static gboolean erf_write_wtap_option_to_capture_tag ( wtap_block_t block _U_ ,
2017-06-01 08:34:25 +00:00
guint option_id ,
wtap_opttype_e option_type _U_ ,
wtap_optval_t * optval ,
void * user_data ) {
struct erf_meta_section * section_ptr = ( struct erf_meta_section * ) user_data ;
struct erf_meta_tag * tag_ptr = NULL ;
2020-12-21 02:30:28 +00:00
tag_ptr = g_new0 ( struct erf_meta_tag , 1 ) ;
2017-06-01 08:34:25 +00:00
switch ( option_id ) {
case OPT_SHB_USERAPPL :
tag_ptr - > type = ERF_META_TAG_app_name ;
tag_ptr - > value = ( guint8 * ) g_strdup ( optval - > stringval ) ;
tag_ptr - > length = ( guint16 ) strlen ( ( char * ) tag_ptr - > value ) ;
break ;
case OPT_COMMENT :
tag_ptr - > type = ERF_META_TAG_comment ;
tag_ptr - > value = ( guint8 * ) g_strdup ( optval - > stringval ) ;
tag_ptr - > length = ( guint16 ) strlen ( ( char * ) tag_ptr - > value ) ;
break ;
default :
erf_meta_tag_free ( tag_ptr ) ;
2017-07-18 04:34:11 +00:00
tag_ptr = NULL ;
break ;
2017-06-01 08:34:25 +00:00
}
2017-07-18 04:34:11 +00:00
if ( tag_ptr )
g_ptr_array_add ( section_ptr - > tags , tag_ptr ) ;
2021-06-27 20:25:16 +00:00
return TRUE ; /* we always succeed */
2017-06-01 08:34:25 +00:00
}
2021-06-27 20:25:16 +00:00
static gboolean erf_write_wtap_option_to_host_tag ( wtap_block_t block _U_ ,
2017-06-01 08:34:25 +00:00
guint option_id ,
wtap_opttype_e option_type _U_ ,
wtap_optval_t * optval ,
void * user_data ) {
struct erf_meta_section * section_ptr = ( struct erf_meta_section * ) user_data ;
struct erf_meta_tag * tag_ptr = NULL ;
2020-12-21 02:30:28 +00:00
tag_ptr = g_new0 ( struct erf_meta_tag , 1 ) ;
2017-06-01 08:34:25 +00:00
switch ( option_id ) {
case OPT_SHB_HARDWARE :
tag_ptr - > type = ERF_META_TAG_cpu ;
tag_ptr - > value = ( guint8 * ) g_strdup ( optval - > stringval ) ;
tag_ptr - > length = ( guint16 ) strlen ( ( char * ) tag_ptr - > value ) ;
break ;
case OPT_SHB_OS :
tag_ptr - > type = ERF_META_TAG_os ;
tag_ptr - > value = ( guint8 * ) g_strdup ( optval - > stringval ) ;
tag_ptr - > length = ( guint16 ) strlen ( ( char * ) tag_ptr - > value ) ;
break ;
default :
erf_meta_tag_free ( tag_ptr ) ;
2017-07-18 04:34:11 +00:00
tag_ptr = NULL ;
break ;
2017-06-01 08:34:25 +00:00
}
2017-07-18 04:34:11 +00:00
if ( tag_ptr )
g_ptr_array_add ( section_ptr - > tags , tag_ptr ) ;
2021-06-27 20:25:16 +00:00
return TRUE ; /* we always succeed */
2017-06-01 08:34:25 +00:00
}
2021-06-27 20:25:16 +00:00
static gboolean erf_write_wtap_option_to_interface_tag ( wtap_block_t block _U_ ,
2017-06-01 08:34:25 +00:00
guint option_id ,
wtap_opttype_e option_type _U_ ,
wtap_optval_t * optval ,
void * user_data ) {
struct erf_meta_section * section_ptr = ( struct erf_meta_section * ) user_data ;
struct erf_meta_tag * tag_ptr = NULL ;
2020-12-21 02:30:28 +00:00
tag_ptr = g_new0 ( struct erf_meta_tag , 1 ) ;
2017-06-01 08:34:25 +00:00
switch ( option_id ) {
case OPT_COMMENT :
tag_ptr - > type = ERF_META_TAG_comment ;
tag_ptr - > value = ( guint8 * ) g_strdup ( optval - > stringval ) ;
tag_ptr - > length = ( guint16 ) strlen ( ( char * ) tag_ptr - > value ) ;
break ;
case OPT_IDB_NAME :
tag_ptr - > type = ERF_META_TAG_name ;
tag_ptr - > value = ( guint8 * ) g_strdup ( optval - > stringval ) ;
tag_ptr - > length = ( guint16 ) strlen ( ( char * ) tag_ptr - > value ) ;
break ;
2021-07-14 06:48:19 +00:00
case OPT_IDB_DESCRIPTION :
2017-06-01 08:34:25 +00:00
tag_ptr - > type = ERF_META_TAG_descr ;
tag_ptr - > value = ( guint8 * ) g_strdup ( optval - > stringval ) ;
tag_ptr - > length = ( guint16 ) strlen ( ( char * ) tag_ptr - > value ) ;
break ;
case OPT_IDB_OS :
tag_ptr - > type = ERF_META_TAG_os ;
tag_ptr - > value = ( guint8 * ) g_strdup ( optval - > stringval ) ;
tag_ptr - > length = ( guint16 ) strlen ( ( char * ) tag_ptr - > value ) ;
break ;
case OPT_IDB_TSOFFSET :
tag_ptr - > type = ERF_META_TAG_ts_offset ;
tag_ptr - > length = 8 ;
tag_ptr - > value = ( guint8 * ) g_malloc ( sizeof ( optval - > uint64val ) ) ;
/* convert to relative ERF timestamp */
phtolell ( tag_ptr - > value , optval - > uint64val < < 32 ) ;
break ;
case OPT_IDB_SPEED :
tag_ptr - > type = ERF_META_TAG_if_speed ;
tag_ptr - > length = 8 ;
tag_ptr - > value = ( guint8 * ) g_malloc ( sizeof ( optval - > uint64val ) ) ;
phtonll ( tag_ptr - > value , optval - > uint64val ) ;
break ;
case OPT_IDB_IP4ADDR :
tag_ptr - > type = ERF_META_TAG_if_ipv4 ;
tag_ptr - > length = 4 ;
tag_ptr - > value = ( guint8 * ) g_malloc ( sizeof ( optval - > ipv4val ) ) ;
memcpy ( tag_ptr - > value , & optval - > ipv4val , sizeof ( optval - > ipv4val ) ) ;
break ;
case OPT_IDB_IP6ADDR :
tag_ptr - > type = ERF_META_TAG_if_ipv6 ;
tag_ptr - > length = 16 ;
tag_ptr - > value = ( guint8 * ) g_malloc ( sizeof ( optval - > ipv6val ) ) ;
memcpy ( tag_ptr - > value , & optval - > ipv6val , sizeof ( optval - > ipv6val ) ) ;
break ;
case OPT_IDB_FILTER :
{
2021-02-01 23:56:47 +00:00
if_filter_opt_t * filter ;
filter = & optval - > if_filterval ;
2017-06-01 08:34:25 +00:00
tag_ptr - > type = 0xF800 ;
2021-02-01 23:56:47 +00:00
if ( filter - > type = = if_filter_pcap ) {
2017-06-01 08:34:25 +00:00
tag_ptr - > type = ERF_META_TAG_filter ;
2021-02-01 23:56:47 +00:00
tag_ptr - > value = ( guint8 * ) g_strdup ( filter - > data . filter_str ) ;
2017-06-01 08:34:25 +00:00
tag_ptr - > length = ( guint16 ) strlen ( ( char * ) tag_ptr - > value ) ;
}
}
break ;
case OPT_IDB_FCSLEN :
tag_ptr - > type = ERF_META_TAG_fcs_len ;
tag_ptr - > length = 4 ;
tag_ptr - > value = ( guint8 * ) g_malloc ( tag_ptr - > length ) ;
2017-07-18 04:27:53 +00:00
phtonl ( tag_ptr - > value , ( guint32 ) optval - > uint8val ) ;
2017-06-01 08:34:25 +00:00
break ;
/* TODO: Don't know what to do with these yet */
case OPT_IDB_EUIADDR :
#if 0
tag_ptr - > type = ERF_META_TAG_if_eui ;
tag_ptr - > length = 8 ;
tag_ptr - > value = ( guint8 * ) g_malloc ( sizeof ( optval - > eui64val ) ) ;
memcpy ( tag_ptr - > value , & optval - > euival , sizeof ( optval - > eui64val ) ) ;
break ;
# endif
case OPT_IDB_MACADDR :
#if 0
tag_ptr - > type = ERF_META_TAG_if_mac ;
tag_ptr - > length = 6 ;
2018-01-09 00:38:10 +00:00
/*value same format as pcapng (6-byte canonical, padded by write
2017-06-01 08:34:25 +00:00
* function automatically to 32 - bit boundary ) */
tag_ptr - > value = ( guint8 * ) g_malloc ( sizeof ( optval - > macval ) ) ;
memcpy ( tag_ptr - > value , & optval - > macval , sizeof ( optval - > macval ) ) ;
break ;
# endif
case OPT_IDB_TSRESOL :
case OPT_IDB_TZONE :
/* Fall through */
default :
erf_meta_tag_free ( tag_ptr ) ;
tag_ptr = NULL ;
break ;
}
if ( tag_ptr )
g_ptr_array_add ( section_ptr - > tags , tag_ptr ) ;
2021-06-27 20:25:16 +00:00
return TRUE ; /* we always succeed */
2017-06-01 08:34:25 +00:00
}
static void erf_populate_section_length_by_tags ( struct erf_meta_section * section_ptr ) {
guint i = 0 ;
struct erf_meta_tag * tag_ptr ;
section_ptr - > section_length = 8 ;
for ( ; i < section_ptr - > tags - > len ; i + + ) {
tag_ptr = ( struct erf_meta_tag * ) g_ptr_array_index ( section_ptr - > tags , i ) ;
section_ptr - > section_length + = ERF_META_TAG_TOTAL_ALIGNED_LENGTH ( tag_ptr - > length ) ;
}
}
/**
* @ brief Converts a wtap_block_t block to ERF metadata sections
* @ param block a wtap_block_t block
* @ param sections pointer to a GPtrArray containing pointers to sections
* @ param section_type the pre - specified section_type
* @ param section_id Section ID to assign
* @ param func a wtap_block_foreach_func call back function to specify
* what needs to be done on the block
* @ return TRUE if success , FALSE if failed
*/
static gboolean erf_wtap_blocks_to_erf_sections ( wtap_block_t block , GPtrArray * sections , guint16 section_type , guint16 section_id , wtap_block_foreach_func func ) {
if ( ! block | | ! sections | | ! func ) {
return FALSE ;
}
struct erf_meta_section * section_ptr ;
2020-12-21 02:30:28 +00:00
section_ptr = g_new ( struct erf_meta_section , 1 ) ;
2017-06-01 08:34:25 +00:00
section_ptr - > tags = g_ptr_array_new_with_free_func ( erf_meta_tag_free ) ;
section_ptr - > type = section_type ;
section_ptr - > section_id = section_id ;
wtap_block_foreach_option ( block , func , ( void * ) section_ptr ) ;
erf_populate_section_length_by_tags ( section_ptr ) ;
g_ptr_array_add ( sections , section_ptr ) ;
return TRUE ;
}
static gboolean erf_meta_write_tag ( wtap_dumper * wdh , struct erf_meta_tag * tag_ptr , int * err ) {
guint16 data [ 2 ] ;
guint pad = 0 ;
/* we only need to pad up to 32 bits*/
guint32 padbuf = 0 ;
pad = ERF_META_TAG_ALIGNED_LENGTH ( tag_ptr - > length ) - tag_ptr - > length ;
data [ 0 ] = g_htons ( tag_ptr - > type ) ;
data [ 1 ] = g_htons ( tag_ptr - > length ) ;
if ( ! wtap_dump_file_write ( wdh , data , sizeof ( data ) , err ) ) return FALSE ;
wdh - > bytes_dumped + = sizeof ( data ) ;
if ( ! wtap_dump_file_write ( wdh , tag_ptr - > value , tag_ptr - > length , err ) ) return FALSE ;
wdh - > bytes_dumped + = tag_ptr - > length ;
if ( pad ) {
if ( ! wtap_dump_file_write ( wdh , & padbuf , pad , err ) ) return FALSE ;
wdh - > bytes_dumped + = pad ;
}
return TRUE ;
}
static gboolean erf_meta_write_section ( wtap_dumper * wdh , struct erf_meta_section * section_ptr , int * err ) {
struct erf_meta_tag * tag_ptr ;
guint i ;
guint16 data [ 4 ] ;
data [ 0 ] = g_htons ( section_ptr - > type ) ;
data [ 1 ] = g_htons ( 4 ) ; /*section header length*/
data [ 2 ] = g_htons ( section_ptr - > section_id ) ;
data [ 3 ] = g_htons ( section_ptr - > section_length ) ;
if ( ! wtap_dump_file_write ( wdh , data , sizeof ( data ) , err ) ) return FALSE ;
wdh - > bytes_dumped + = sizeof ( data ) ;
for ( i = 0 ; i < section_ptr - > tags - > len ; i + + ) {
tag_ptr = ( struct erf_meta_tag * ) g_ptr_array_index ( section_ptr - > tags , i ) ;
if ( ! erf_meta_write_tag ( wdh , tag_ptr , err ) ) return FALSE ;
}
return TRUE ;
}
static gboolean erf_wtap_info_to_sections ( wtap_dumper * wdh , GPtrArray * sections ) {
wtap_block_t block ;
guint i = 0 ;
block = g_array_index ( wdh - > shb_hdrs , wtap_block_t , 0 ) ;
erf_wtap_blocks_to_erf_sections ( block , sections , ERF_META_SECTION_CAPTURE , 0 , erf_write_wtap_option_to_capture_tag ) ;
block = g_array_index ( wdh - > shb_hdrs , wtap_block_t , 0 ) ;
erf_wtap_blocks_to_erf_sections ( block , sections , ERF_META_SECTION_HOST , 0 , erf_write_wtap_option_to_host_tag ) ;
/*TODO: support >4 interfaces by using more Source IDs. Affects more than this
* function as need more metadata records . Just dump them all out for now . */
for ( i = 0 ; i < wdh - > interface_data - > len ; i + + ) {
block = g_array_index ( wdh - > interface_data , wtap_block_t , i ) ;
erf_wtap_blocks_to_erf_sections ( block , sections , ERF_META_SECTION_INTERFACE , ( gint16 ) i + 1 , erf_write_wtap_option_to_interface_tag ) ;
}
return TRUE ;
}
static gboolean erf_comment_to_sections ( wtap_dumper * wdh _U_ , guint16 section_type , guint16 section_id , gchar * comment , GPtrArray * sections ) {
struct erf_meta_section * section_ptr ;
struct erf_meta_tag * comment_tag_ptr = NULL ;
struct erf_meta_tag * user_tag_ptr = NULL ;
const gchar * user = NULL ;
/* Generate the section */
2020-12-21 02:30:28 +00:00
section_ptr = g_new ( struct erf_meta_section , 1 ) ;
2017-06-01 08:34:25 +00:00
section_ptr - > type = section_type ;
section_ptr - > section_id = section_id ;
section_ptr - > tags = g_ptr_array_new_with_free_func ( erf_meta_tag_free ) ;
/* Generate the comment tag */
2020-12-21 02:30:28 +00:00
comment_tag_ptr = g_new ( struct erf_meta_tag , 1 ) ;
2017-06-01 08:34:25 +00:00
comment_tag_ptr - > type = ERF_META_TAG_comment ;
/* XXX: if the comment has been cleared write the empty string (which
* conveniently is all a zero length tag which means the value is
* invalidated ) */
comment_tag_ptr - > value = ( guint8 * ) g_strdup ( comment ? comment : " " ) ;
comment_tag_ptr - > length = ( guint16 ) strlen ( ( char * ) comment_tag_ptr - > value ) ;
g_ptr_array_add ( section_ptr - > tags , comment_tag_ptr ) ;
user = g_get_user_name ( ) ;
if ( user ) {
/* Generate username tag */
2020-12-21 02:30:28 +00:00
user_tag_ptr = g_new ( struct erf_meta_tag , 1 ) ;
2017-06-01 08:34:25 +00:00
user_tag_ptr - > type = ERF_META_TAG_user ;
user_tag_ptr - > value = ( guint8 * ) g_strdup ( user ) ;
user_tag_ptr - > length = ( guint16 ) strlen ( ( char * ) user_tag_ptr - > value ) ;
g_ptr_array_add ( section_ptr - > tags , user_tag_ptr ) ;
}
erf_populate_section_length_by_tags ( section_ptr ) ;
g_ptr_array_add ( sections , section_ptr ) ;
return TRUE ;
}
static guint64 erf_get_random_anchor_id ( erf_dump_t * dump_priv ) {
return ( ( ( guint64 ) g_rand_int ( dump_priv - > rand ) < < 32 ) | ( guint64 ) g_rand_int ( dump_priv - > rand ) ) > > 16 ;
}
static guint64 erf_metaid_ext_hdr ( guint8 exthdr_type , guint64 id , guint8 srcid_flags ) {
guint64 ext_hdr ;
ext_hdr = id & ERF_EHDR_HOST_ID_MASK ;
ext_hdr | = ( ( guint64 ) srcid_flags ) < < 48 ;
ext_hdr | = ( ( guint64 ) exthdr_type ) < < 56 ;
return ext_hdr ;
}
# define erf_host_id_ext_hdr(host_id, source_id) erf_metaid_ext_hdr(ERF_EXT_HDR_TYPE_HOST_ID, host_id, source_id)
# define erf_anchor_id_ext_hdr(anchor_id, flags) erf_metaid_ext_hdr(ERF_EXT_HDR_TYPE_ANCHOR_ID, anchor_id, flags)
static inline gboolean erf_add_ext_hdr_to_list ( guint64 ext_hdr , guint64 comparison_mask , GArray * extra_ehdrs ) {
/* check for existing Host ID in set and add */
guint i = 0 ;
struct erf_ehdr ehdr_tmp ;
struct erf_ehdr * ehdr_ptr = NULL ;
if ( ! extra_ehdrs )
return FALSE ;
ext_hdr = ext_hdr & ~ ERF_EHDR_MORE_EXTHDR_MASK ;
if ( comparison_mask = = 0 )
comparison_mask = G_MAXUINT64 ;
comparison_mask & = ~ ERF_EHDR_MORE_EXTHDR_MASK ;
for ( i = 0 ; i < extra_ehdrs - > len ; i + + ) {
ehdr_ptr = & g_array_index ( extra_ehdrs , struct erf_ehdr , i ) ;
/* Check if we already have this Host ID extension header */
if ( ext_hdr = = ( ehdr_ptr - > ehdr & comparison_mask ) ) {
return TRUE ;
}
}
/* set more flag on last extension header */
if ( ehdr_ptr ) {
ehdr_ptr - > ehdr | = ERF_EHDR_MORE_EXTHDR_MASK ;
}
ehdr_tmp . ehdr = ext_hdr ; /*more flag already cleared above*/
g_array_append_val ( extra_ehdrs , ehdr_tmp ) ;
return TRUE ;
}
static inline gboolean erf_append_ext_hdr_to_list ( guint64 ext_hdr , GArray * extra_ehdrs ) {
struct erf_ehdr ehdr_tmp ;
if ( ! extra_ehdrs )
return FALSE ;
ehdr_tmp . ehdr = ext_hdr & ~ ERF_EHDR_MORE_EXTHDR_MASK ;
/* set more flag on last extension header */
if ( extra_ehdrs - > len ) {
g_array_index ( extra_ehdrs , struct erf_ehdr , extra_ehdrs - > len - 1 ) . ehdr | = ERF_EHDR_MORE_EXTHDR_MASK ;
}
g_array_append_val ( extra_ehdrs , ehdr_tmp ) ;
return TRUE ;
}
static gboolean erf_update_host_id_ext_hdrs_list ( erf_dump_t * dump_priv , const union wtap_pseudo_header * pseudo_header , GArray * extra_ehdrs ) {
guint8 type ;
guint8 erf_type ;
int has_more ;
guint64 hdr ;
int i = 0 ;
guint8 source_id = 0 ;
guint64 host_id = 0 ;
gboolean host_id_found = FALSE ;
if ( ! extra_ehdrs )
return FALSE ;
erf_type = pseudo_header - > erf . phdr . type & 0x7f ;
has_more = pseudo_header - > erf . phdr . type & 0x80 ;
while ( has_more & & i < MAX_ERF_EHDR ) {
hdr = pseudo_header - > erf . ehdr_list [ i ] . ehdr ;
type = ( guint8 ) ( hdr > > 56 ) ;
switch ( type & 0x7f ) {
case ERF_EXT_HDR_TYPE_HOST_ID :
host_id = hdr & ERF_EHDR_HOST_ID_MASK ;
source_id = ( hdr > > 48 ) & 0xff ;
/* Don't add the wireshark Host ID Source ID 0 twice since we already add it to metadata records */
if ( host_id ! = dump_priv - > host_id | | source_id ! = 0 )
if ( ! erf_add_ext_hdr_to_list ( hdr , 0 , extra_ehdrs ) ) return FALSE ;
if ( ! host_id_found ) {
/* XXX: Take the opportunity to update the implicit Host ID if we
* don ' t know it yet . Ideally we should pass this through from the
* reader as a custom option or similar . */
if ( erf_type = = ERF_TYPE_META & & ( ( hdr > > 48 ) & 0xff ) > 0 ) {
if ( dump_priv - > implicit_host_id = = ERF_META_HOST_ID_IMPLICIT ) {
dump_priv - > implicit_host_id = host_id ;
}
}
}
host_id_found = TRUE ;
break ;
case ERF_EXT_HDR_TYPE_FLOW_ID :
if ( source_id = = 0 ) /* If no Host ID extension header use the first Source ID only */
source_id = ( hdr > > 48 ) & 0xff ;
break ;
}
has_more = type & 0x80 ;
i + + ;
}
/* Add Source ID with implicit Host ID if not found */
if ( ! host_id_found ) {
guint64 implicit_host_id = dump_priv - > implicit_host_id = = ERF_META_HOST_ID_IMPLICIT ? 0 : dump_priv - > implicit_host_id ;
/* Don't add the wireshark Host ID Source ID 0 twice since we already add it to metadata records */
if ( implicit_host_id ! = dump_priv - > host_id | | source_id ! = 0 )
if ( ! erf_add_ext_hdr_to_list ( erf_host_id_ext_hdr ( implicit_host_id , source_id ) , 0 , extra_ehdrs ) ) return FALSE ;
}
return TRUE ;
}
/**
* Writes a metadata record with a randomly generated Anchor ID with the
* user comment attached to its comment section , also updates the
* modified frame header to include a Host ID extension header and
* a Anchor ID extension header to link the records together .
* @ param wdh the wtap_dumper structure
2018-02-17 19:03:32 +00:00
* @ param dump_priv private data for the dump stream
* @ param rec record metadata from which to get user comment
2017-06-01 08:34:25 +00:00
* @ param mutable_hdr pseudo_header to update with Anchor ID for comment record
* @ param err the error value
* @ return A gboolean value to indicate whether the dump was successful
*/
2018-02-09 00:19:12 +00:00
static gboolean erf_write_anchor_meta_update_phdr ( wtap_dumper * wdh , erf_dump_t * dump_priv , const wtap_rec * rec , union wtap_pseudo_header * mutable_hdr , int * err ) {
2017-06-01 08:34:25 +00:00
GArray * meta_ehdrs ;
GPtrArray * sections = NULL ;
guint8 has_more ;
guint8 i = 0 ;
guint8 ext_hdr_count = 0 ;
guint8 j = 0 ;
guint64 host_id_src_hdr = ERF_META_HOST_ID_IMPLICIT ;
guint64 host_id_own_hdr = erf_host_id_ext_hdr ( dump_priv - > host_id , 0 ) ;
guint64 flow_id_hdr = 0 ;
guint64 anchor_id_hdr = 0 ;
gboolean found_host_id = FALSE ;
gboolean found_own_host_id = FALSE ;
gboolean found_flow_id = FALSE ;
gint new_ext_hdrs = 0 ;
guint8 insert_idx = 0 ;
guint8 source_id = 0 ;
gboolean ret = FALSE ;
guint64 implicit_host_id = dump_priv - > implicit_host_id = = ERF_META_HOST_ID_IMPLICIT ? 0 : dump_priv - > implicit_host_id ;
2021-04-29 11:23:21 +00:00
gchar * pkt_comment ;
2017-06-01 08:34:25 +00:00
/*
* There are 3 possible scenarios :
* a . The record has a source Host ID but not our Host ID . We need to add our
* Host ID extension header then our Anchor ID extension header .
* b . The record already has our Host ID extension header on it . We should
* insert the Anchor ID at the end of the list for that Host ID just
* before the next Host ID extension header .
* c . The record has no Host ID extension header at all . We need to add the Host ID
* extension header making the Implicit Host ID explicit before we add our
* one to avoid claiming the packet was captured by us .
*/
/*
* Extract information from the packet extension header stack
* 1. original source Host ID extension header .
* 2. Anchor ID extension header insertion point ( see b . , above ) .
* 3. Flow ID extension header so we can add it for reference to the metadata
* record .
* 4. Enough information to generate an explicit Host ID extension header if
* there wasn ' t one ( see erf_get_source_from_header ) .
*/
has_more = mutable_hdr - > erf . phdr . type & 0x80 ;
while ( has_more & & ( i < MAX_ERF_EHDR ) ) {
guint64 hdr = mutable_hdr - > erf . ehdr_list [ i ] . ehdr ;
guint8 type = ( guint8 ) ( hdr > > 56 ) ;
switch ( type & 0x7f ) {
case ERF_EXT_HDR_TYPE_HOST_ID :
/* Set insertion point of anchor ID to be at end of Host ID list (i.e.
* just before the next one ) . */
if ( found_own_host_id & & ! insert_idx )
insert_idx = i ;
if ( ( hdr & ERF_EHDR_HOST_ID_MASK ) = = dump_priv - > host_id ) {
found_own_host_id = TRUE ;
}
if ( ! found_host_id )
host_id_src_hdr = hdr ;
found_host_id = TRUE ;
break ;
case ERF_EXT_HDR_TYPE_FLOW_ID :
/*XXX: we only use this when making the implicit host id explicit,
* otherwise we ' d need to check the one in Host ID header too */
if ( source_id = = 0 )
source_id = ( guint8 ) ( hdr > > 48 ) ;
if ( ! found_flow_id )
flow_id_hdr = hdr ;
found_flow_id = TRUE ;
break ;
}
has_more = type & 0x80 ;
i + = 1 ;
}
ext_hdr_count = i ;
if ( ! insert_idx )
insert_idx = i ;
/* Don't need to add our own Host ID twice if it is the same as the implicit*/
if ( ! found_host_id & & implicit_host_id = = dump_priv - > host_id ) {
found_own_host_id = TRUE ;
}
/*
* Update the packet record pseudo_header with Anchor ID and extension header ( s )
*/
new_ext_hdrs = 1 /*anchor id*/ + ( found_own_host_id ? 0 : 1 ) + ( found_host_id ? 0 : 1 ) ;
if ( ext_hdr_count + new_ext_hdrs > MAX_ERF_EHDR
| | mutable_hdr - > erf . phdr . rlen + new_ext_hdrs * 8 > 65535 ) {
/* Not enough extension header slots to add Anchor ID */
* err = WTAP_ERR_PACKET_TOO_LARGE ;
return FALSE ;
}
mutable_hdr - > erf . phdr . rlen + = new_ext_hdrs * 8 ;
/* Set the more extension headers flag */
mutable_hdr - > erf . phdr . type | = 0x80 ;
if ( insert_idx > 0 ) {
mutable_hdr - > erf . ehdr_list [ insert_idx - 1 ] . ehdr | = ERF_EHDR_MORE_EXTHDR_MASK ;
}
/* Generate the Anchor ID extension header */
anchor_id_hdr = erf_anchor_id_ext_hdr ( erf_get_random_anchor_id ( dump_priv ) , 0 ) ;
/* Either we can insert Anchor ID at the end of the list for our Host ID or we
* need to append the Host ID ( s ) and Anchor ID */
if ( insert_idx < ext_hdr_count ) {
/* shuffle up any following extension headers FIRST - we know we have room now */
for ( j = ext_hdr_count ; j > insert_idx ; j - - ) {
mutable_hdr - > erf . ehdr_list [ j ] . ehdr = mutable_hdr - > erf . ehdr_list [ j - 1 ] . ehdr ;
}
/* copy more extension headers bit from previous extension header */
anchor_id_hdr | = ERF_EHDR_MORE_EXTHDR_MASK ;
}
if ( ! found_host_id ) {
/* No Host ID extension header found and we have an implicit Host ID which
* we want to make explicit */
/* XXX: it is important that we know the implicit Host ID here or we end
* up semi - permentantly associating the packet with Host 0 ( unknown ) , we should
* pass it through from the reader . In theory we should be on the
* original capture machine if we have no Host ID extension headers . */
host_id_src_hdr = erf_host_id_ext_hdr ( implicit_host_id , source_id ) ;
mutable_hdr - > erf . ehdr_list [ insert_idx + + ] . ehdr = ERF_EHDR_SET_MORE_EXTHDR ( host_id_src_hdr ) ;
}
if ( ! found_own_host_id ) {
/* Add our Host ID extension header */
mutable_hdr - > erf . ehdr_list [ insert_idx + + ] . ehdr = ERF_EHDR_SET_MORE_EXTHDR ( host_id_own_hdr ) ;
}
/*Add the Anchor ID extension header */
mutable_hdr - > erf . ehdr_list [ insert_idx ] . ehdr = anchor_id_hdr ;
/*
* Now construct the metadata Anchor record with the same Anchor ID
*/
meta_ehdrs = g_array_new ( FALSE , FALSE , sizeof ( struct erf_ehdr ) ) ;
/* We need up to 4 extension headers on the Provenance metadata record */
/*Required*/
/* 1. Added by erf_write_meta_record: HostID exthdr to indicate this Anchor
* record was generated by this host . Source ID 0 to avoid changing the
* implicit Host ID . */
/* 2. AnchorID exthdr with 'unique' per-host Anchor ID assigned by this host
2020-10-10 23:42:05 +00:00
* ( in this case Wireshark ) . Anchor definition flag set to 1 to indicate this
* record contains a definition of the ID , in this case a comment on a single
2017-06-01 08:34:25 +00:00
* packet . Tied to above extension header by ordering like a list */
erf_append_ext_hdr_to_list ( anchor_id_hdr | ERF_EHDR_ANCHOR_ID_DEFINITION_MASK , meta_ehdrs ) ;
/*Helpful for indexing*/
/* 3. HostID exthdr with the original Source (first Host ID extension header) of the packet record */
erf_append_ext_hdr_to_list ( host_id_src_hdr , meta_ehdrs ) ;
/* Flow ID extension header from the packet record if we have one */
if ( found_flow_id ) {
/* 4. FlowID exthdr with Flow ID from the packet so a flow search will find the comment
* record too . Must come here so the ( redundant here ) Source ID is scoped to the
* correct Host ID . */
/* Clear the stack type just in case something tries to assume we're an IP
* packet without looking at the ERF type . Clear Source ID too just in case
* we ' re trying to associate with the wrong Host ID . */
erf_append_ext_hdr_to_list ( flow_id_hdr & ~ ( ERF_EHDR_FLOW_ID_STACK_TYPE_MASK | ERF_EHDR_FLOW_ID_SOURCE_ID_MASK ) , meta_ehdrs ) ;
}
/* Generate the metadata payload with the packet comment */
2021-04-29 11:23:21 +00:00
/* XXX - can ERF have more than one comment? */
2017-06-01 08:34:25 +00:00
sections = g_ptr_array_new_with_free_func ( erf_meta_section_free ) ;
2021-04-29 11:23:21 +00:00
if ( WTAP_OPTTYPE_SUCCESS ! = wtap_block_get_nth_string_option_value ( rec - > block , OPT_COMMENT , 0 , & pkt_comment ) ) {
pkt_comment = NULL ;
}
erf_comment_to_sections ( wdh , ERF_META_SECTION_INFO , 0x8000 /*local to record*/ , pkt_comment , sections ) ;
2017-06-01 08:34:25 +00:00
/* Write the metadata record, but not the packet record as what we do depends
* on the WTAP_ENCAP */
ret = erf_write_meta_record ( wdh , dump_priv , mutable_hdr - > erf . phdr . ts , sections , meta_ehdrs , err ) ;
g_ptr_array_free ( sections , TRUE ) ;
g_array_free ( meta_ehdrs , TRUE ) ;
return ret ;
}
static gboolean erf_write_meta_record ( wtap_dumper * wdh , erf_dump_t * dump_priv , guint64 timestamp , GPtrArray * sections , GArray * extra_ehdrs , int * err ) {
union wtap_pseudo_header other_header ;
struct erf_meta_tag gen_time_tag ;
struct erf_meta_section * section_ptr ;
guint total_wlen = 0 ;
guint total_rlen = 0 ;
gint64 alignbytes = 0 ;
guint i ;
guint num_extra_ehdrs = 0 ;
if ( ! sections | | sections - > len < = 0 )
return FALSE ;
for ( i = 0 ; i < sections - > len ; i + + ) {
section_ptr = ( struct erf_meta_section * ) g_ptr_array_index ( sections , i ) ;
total_wlen + = section_ptr - > section_length ;
}
gen_time_tag . type = ERF_META_TAG_gen_time ;
gen_time_tag . length = 8U ;
gen_time_tag . value = ( guint8 * ) & dump_priv - > gen_time ;
total_wlen + = gen_time_tag . length + 4 ;
total_rlen = total_wlen + 24 ; /* 24 is the header + extension header length */
if ( extra_ehdrs ) {
2017-07-18 01:22:53 +00:00
/*
* These will be appended to the first extension header in
* other_header . erf . ehdr_list . There are a total of MAX_ERF_EHDR
* extension headers in that array , so we can append no more than
* MAX_ERF_EHDR - 1 extension headeers .
*/
num_extra_ehdrs = MIN ( extra_ehdrs - > len , MAX_ERF_EHDR - 1 ) ;
2017-06-01 08:34:25 +00:00
total_rlen + = num_extra_ehdrs * 8 ;
}
/*padding to 8 byte alignment*/
total_rlen + = ERF_PADDING_TO_8 ( total_rlen ) ;
if ( total_rlen > 65535 ) {
* err = WTAP_ERR_PACKET_TOO_LARGE ;
return FALSE ;
}
other_header . erf . phdr . ts = timestamp ;
other_header . erf . phdr . type = ERF_TYPE_META | 0x80 ;
other_header . erf . phdr . flags = 0x04 ; /* Varying record length */
other_header . erf . phdr . lctr = 0 ;
other_header . erf . phdr . wlen = ( guint16 ) total_wlen ;
other_header . erf . phdr . rlen = ( guint16 ) total_rlen ;
/*Add our Host ID in Host ID extension header indicating we generated this
* record . Source ID 0 to avoid affecting implicit Host ID . */
other_header . erf . ehdr_list [ 0 ] . ehdr = erf_host_id_ext_hdr ( dump_priv - > host_id , 0 ) ;
/*Additional extension headers*/
/*XXX: If we end up cutting the list short, erf_write_phdr will correct the
* unterminated extension header list */
if ( num_extra_ehdrs > 0 ) {
other_header . erf . ehdr_list [ 0 ] . ehdr | = ERF_EHDR_MORE_EXTHDR_MASK ;
memcpy ( & other_header . erf . ehdr_list [ 1 ] , extra_ehdrs - > data , sizeof ( struct erf_ehdr ) * num_extra_ehdrs ) ;
}
/* Make sure we always write out rlen, regardless of what happens */
alignbytes = wdh - > bytes_dumped + other_header . erf . phdr . rlen ;
if ( ! erf_write_phdr ( wdh , WTAP_ENCAP_ERF , & other_header , err ) ) return FALSE ;
/* Generation time */
erf_meta_write_tag ( wdh , & gen_time_tag , err ) ;
/* Section(s) */
for ( i = 0 ; i < sections - > len ; i + + ) {
section_ptr = ( struct erf_meta_section * ) g_ptr_array_index ( sections , i ) ;
erf_meta_write_section ( wdh , section_ptr , err ) ;
}
while ( wdh - > bytes_dumped < alignbytes ) {
if ( ! wtap_dump_file_write ( wdh , " " , 1 , err ) ) return FALSE ;
wdh - > bytes_dumped + + ;
}
/* We wrote new packets, reloading is required */
wdh - > needs_reload = TRUE ;
2011-08-31 20:50:15 +00:00
return TRUE ;
2017-06-01 08:34:25 +00:00
}
2020-05-02 04:02:00 +00:00
static erf_dump_t * erf_dump_priv_create ( void ) {
2017-06-01 08:34:25 +00:00
erf_dump_t * dump_priv ;
2020-12-21 02:30:28 +00:00
dump_priv = g_new ( erf_dump_t , 1 ) ;
2017-06-01 08:34:25 +00:00
dump_priv - > write_next_extra_meta = FALSE ;
dump_priv - > last_meta_periodic = FALSE ;
dump_priv - > gen_time = 0 ;
dump_priv - > host_id = ERF_WS_DEFAULT_HOST_ID ;
dump_priv - > implicit_host_id = ERF_META_HOST_ID_IMPLICIT ;
dump_priv - > first_frame_time_sec = 0 ;
dump_priv - > prev_inserted_time_sec = 0 ;
dump_priv - > prev_frame_ts = 0 ;
dump_priv - > prev_erf_type = 0 ;
dump_priv - > user_comment_ptr = NULL ;
dump_priv - > periodic_sections = NULL ;
dump_priv - > periodic_extra_ehdrs = g_array_new ( FALSE , FALSE , sizeof ( struct erf_ehdr ) ) ;
dump_priv - > rand = g_rand_new ( ) ;
return dump_priv ;
2011-08-31 20:50:15 +00:00
}
static gboolean erf_dump (
2014-05-09 05:18:49 +00:00
wtap_dumper * wdh ,
2018-02-09 00:19:12 +00:00
const wtap_rec * rec ,
2012-03-02 00:31:30 +00:00
const guint8 * pd ,
2014-12-18 00:02:50 +00:00
int * err ,
gchar * * err_info _U_ )
2011-08-31 20:50:15 +00:00
{
2018-02-09 00:19:12 +00:00
const union wtap_pseudo_header * pseudo_header = & rec - > rec_header . packet_header . pseudo_header ;
2011-08-31 20:50:15 +00:00
union wtap_pseudo_header other_phdr ;
2012-03-02 00:31:30 +00:00
int encap ;
2017-06-01 08:34:25 +00:00
int erf_type ;
2012-03-02 00:31:30 +00:00
gint64 alignbytes = 0 ;
2017-06-01 08:34:25 +00:00
guint padbytes = 0 ;
2012-03-02 00:31:30 +00:00
int round_down = 0 ;
2011-09-06 23:36:18 +00:00
gboolean must_add_crc = FALSE ;
2012-03-02 00:31:30 +00:00
guint32 crc32 = 0x00000000 ;
2017-06-01 08:34:25 +00:00
erf_dump_t * dump_priv = ( erf_dump_t * ) wdh - > priv ;
/* Host ID extension header with Host ID 0 (unknown). For now use Source ID 1. */
/* TODO: How to know if record was captured by this Wireshark? */
guint64 non_erf_host_id_ehdr = erf_host_id_ext_hdr ( 0 , 1 ) ;
2011-08-31 20:50:15 +00:00
2014-01-22 00:26:36 +00:00
/* Don't write anything bigger than we're willing to read. */
2018-02-09 00:19:12 +00:00
if ( rec - > rec_header . packet_header . caplen > WTAP_MAX_PACKET_SIZE_STANDARD ) {
2014-01-22 00:26:36 +00:00
* err = WTAP_ERR_PACKET_TOO_LARGE ;
return FALSE ;
}
2011-08-31 20:50:15 +00:00
if ( wdh - > encap = = WTAP_ENCAP_PER_PACKET ) {
2018-02-09 00:19:12 +00:00
encap = rec - > rec_header . packet_header . pkt_encap ;
2011-08-31 20:50:15 +00:00
} else {
encap = wdh - > encap ;
}
2017-06-01 08:34:25 +00:00
if ( ! dump_priv - > gen_time ) {
erf_dump_priv_init_gen_time ( dump_priv ) ;
2018-02-09 00:19:12 +00:00
dump_priv - > first_frame_time_sec = rec - > ts . secs ;
2017-06-01 08:34:25 +00:00
}
if ( encap ! = WTAP_ENCAP_ERF ) {
unsigned int total_rlen ; ;
unsigned int total_wlen ;
2011-08-31 20:50:15 +00:00
2017-06-01 08:34:25 +00:00
/*Non-ERF*/
2011-08-31 20:50:15 +00:00
2018-02-09 00:19:12 +00:00
total_rlen = rec - > rec_header . packet_header . caplen + 16 ;
total_wlen = rec - > rec_header . packet_header . len ;
2011-08-31 20:50:15 +00:00
2017-06-01 08:34:25 +00:00
/* We can only convert packet records. */
2018-02-09 00:19:12 +00:00
if ( rec - > rec_type ! = REC_TYPE_PACKET ) {
2017-06-01 08:34:25 +00:00
* err = WTAP_ERR_UNWRITABLE_REC_TYPE ;
return FALSE ;
2013-01-06 20:44:49 +00:00
}
2017-06-01 08:34:25 +00:00
if ( ( erf_type = wtap_wtap_encap_to_erf_encap ( encap ) ) = = - 1 ) {
* err = WTAP_ERR_UNWRITABLE_ENCAP ;
return FALSE ;
}
2016-03-11 03:44:16 +00:00
2017-06-01 08:34:25 +00:00
/* Generate a fake header in other_phdr using data that we know*/
memset ( & other_phdr , 0 , sizeof ( union wtap_pseudo_header ) ) ;
/* Convert time erf timestamp format*/
2018-02-09 00:19:12 +00:00
other_phdr . erf . phdr . ts = ( ( guint64 ) rec - > ts . secs < < 32 ) + ( ( ( guint64 ) rec - > ts . nsecs < < 32 ) / 1000 / 1000 / 1000 ) ;
2017-06-01 08:34:25 +00:00
other_phdr . erf . phdr . type = ( guint8 ) erf_type ;
/* Support up to 4 interfaces */
/* TODO: use multiple Source IDs and metadata records to support >4 interfaces */
2018-02-09 00:19:12 +00:00
other_phdr . erf . phdr . flags = rec - > rec_header . packet_header . interface_id % ERF_MAX_INTERFACES ;
2017-06-01 08:34:25 +00:00
other_phdr . erf . phdr . flags | = 0x4 ; /*vlen flag set because we're creating variable length records*/
other_phdr . erf . phdr . lctr = 0 ;
/*now we work out rlen, accounting for all the different headers and missing fcs(eth)*/
switch ( other_phdr . erf . phdr . type & 0x7F ) {
case ERF_TYPE_ETH :
total_rlen + = 2 ; /*2 bytes for erf eth_type*/
if ( pseudo_header - > eth . fcs_len ! = 4 ) {
/* Either this packet doesn't include the FCS
( pseudo_header - > eth . fcs_len = 0 ) , or we don ' t
know whether it has an FCS ( = - 1 ) . We have to
synthesize an FCS . */
2018-02-09 00:19:12 +00:00
if ( ! ( rec - > rec_header . packet_header . caplen < rec - > rec_header . packet_header . len ) ) { /*don't add FCS if packet has been snapped off*/
crc32 = crc32_ccitt_seed ( pd , rec - > rec_header . packet_header . caplen , 0xFFFFFFFF ) ;
2017-06-01 08:34:25 +00:00
total_rlen + = 4 ; /*4 bytes for added checksum*/
total_wlen + = 4 ;
must_add_crc = TRUE ;
}
}
break ;
case ERF_TYPE_HDLC_POS :
/*we assume that it's missing a FCS checksum, make one up*/
2018-02-09 00:19:12 +00:00
if ( ! ( rec - > rec_header . packet_header . caplen < rec - > rec_header . packet_header . len ) ) { /*unless of course, the packet has been snapped off*/
crc32 = crc32_ccitt_seed ( pd , rec - > rec_header . packet_header . caplen , 0xFFFFFFFF ) ;
2017-06-01 08:34:25 +00:00
total_rlen + = 4 ; /*4 bytes for added checksum*/
total_wlen + = 4 ;
must_add_crc = TRUE ; /* XXX - these never have an FCS? */
}
break ;
default :
break ;
}
/* Add Host ID extension header with Host ID 0 (unknown). For now use Source ID 1. */
other_phdr . erf . phdr . type | = 0x80 ;
other_phdr . erf . ehdr_list [ 0 ] . ehdr = non_erf_host_id_ehdr ;
total_rlen + = 8 ;
padbytes = ERF_PADDING_TO_8 ( total_rlen ) ; /*calculate how much padding will be required */
2018-02-09 00:19:12 +00:00
if ( rec - > rec_header . packet_header . caplen < rec - > rec_header . packet_header . len ) { /*if packet has been snapped, we need to round down what we output*/
2017-06-01 08:34:25 +00:00
round_down = ( 8 - padbytes ) % 8 ;
total_rlen - = round_down ;
} else {
total_rlen + = padbytes ;
}
if ( total_rlen > G_MAXUINT16 | | total_wlen > G_MAXUINT16 ) {
* err = WTAP_ERR_PACKET_TOO_LARGE ;
return FALSE ;
}
other_phdr . erf . phdr . rlen = ( guint16 ) total_rlen ;
other_phdr . erf . phdr . wlen = ( guint16 ) total_wlen ;
pseudo_header = & other_phdr ;
2020-05-25 02:35:09 +00:00
} else if ( rec - > presence_flags & WTAP_HAS_TS ) {
// Update timestamp if changed.
time_t secs ;
int nsecs ;
guint64 ts = pseudo_header - > erf . phdr . ts ;
secs = ( long ) ( ts > > 32 ) ;
ts = ( ( ts & 0xffffffff ) * 1000 * 1000 * 1000 ) ;
ts + = ( ts & 0x80000000 ) < < 1 ; /* rounding */
nsecs = ( ( int ) ( ts > > 32 ) ) ;
if ( nsecs > = 1000000000 ) {
nsecs - = 1000000000 ;
secs + = 1 ;
}
if ( secs ! = rec - > ts . secs | | nsecs ! = rec - > ts . nsecs ) {
other_phdr = * pseudo_header ;
other_phdr . erf . phdr . ts = ( ( guint64 ) rec - > ts . secs < < 32 ) + ( ( ( guint64 ) rec - > ts . nsecs < < 32 ) / 1000 / 1000 / 1000 ) ;
pseudo_header = & other_phdr ;
}
2017-06-01 08:34:25 +00:00
}
/* We now have a (real or fake) ERF record */
erf_type = pseudo_header - > erf . phdr . type & 0x7FU ;
/* Accumulate Host ID/Source ID to put in updated periodic metadata */
/* TODO: pass these through from read interface list instead? */
/* Note: this includes the one we made for the fake ERF header */
erf_update_host_id_ext_hdrs_list ( dump_priv , pseudo_header , dump_priv - > periodic_extra_ehdrs ) ;
/* Insert new metadata record depending on whether the capture comment has
* changed . Write metadata each second at boundaries . If there is metadata
* write at the end of each of metadata records so we update the metadata . */
if ( erf_type = = ERF_TYPE_META ) {
/* Check whether the capture comment string has changed */
/* Updates write_next_extra_meta */
dump_priv - > last_meta_periodic = erf_dump_priv_compare_capture_comment ( wdh , dump_priv , pseudo_header , pd ) ;
} else { /* don't want to insert a new metadata record while looking at another */
if ( dump_priv - > prev_erf_type = = ERF_TYPE_META & & dump_priv - > last_meta_periodic ) {
/* Last frame was a periodic (non-comment) metadata record (and this frame is not), check if we
2020-10-10 23:42:05 +00:00
* need to insert one to update metadata . */
2017-06-01 08:34:25 +00:00
if ( dump_priv - > write_next_extra_meta ) {
if ( ! dump_priv - > periodic_sections ) {
/* If we've seen metadata just insert the capture comment and not the
* rest of the metadata */
dump_priv - > periodic_sections = g_ptr_array_new_with_free_func ( erf_meta_section_free ) ;
erf_comment_to_sections ( wdh , ERF_META_SECTION_CAPTURE , 0 , dump_priv - > user_comment_ptr , dump_priv - > periodic_sections ) ;
2013-01-06 20:44:49 +00:00
}
2017-06-01 08:34:25 +00:00
if ( ! erf_write_meta_record ( wdh , dump_priv , dump_priv - > prev_frame_ts , dump_priv - > periodic_sections , dump_priv - > periodic_extra_ehdrs , err ) ) return FALSE ;
2018-02-09 00:19:12 +00:00
dump_priv - > prev_inserted_time_sec = rec - > ts . secs ;
2017-06-01 08:34:25 +00:00
/*TODO: clear accumulated existing extension headers here?*/
2011-08-31 20:50:15 +00:00
}
2017-06-01 08:34:25 +00:00
/* If we have seen a metadata record in the first ~1 second it
* means that we are dealing with an ERF file with metadata already in them .
* We dont want to write extra metadata if nothing has changed . We can ' t
* trust the Wireshark representation since we massage the fields on
* read . */
/* restart searching for next meta record to update capture comment at */
dump_priv - > write_next_extra_meta = FALSE ;
2018-02-09 00:19:12 +00:00
} else if ( rec - > ts . secs > dump_priv - > first_frame_time_sec + 1
& & dump_priv - > prev_inserted_time_sec ! = rec - > ts . secs ) {
2017-06-01 08:34:25 +00:00
/* For compatibility, don't insert metadata for older ERF files with no changed metadata */
if ( dump_priv - > write_next_extra_meta ) {
if ( ! dump_priv - > periodic_sections ) {
/* If we get here, metadata record was not found in the first ~1 sec
* but we have either a capture comment or a non - ERF file ( see
* erf_dump_open ) */
/* Start inserting metadata records from wtap data at second boundaries */
dump_priv - > periodic_sections = g_ptr_array_new_with_free_func ( erf_meta_section_free ) ;
erf_wtap_info_to_sections ( wdh , dump_priv - > periodic_sections ) ;
}
2011-10-04 05:27:14 +00:00
}
2017-06-01 08:34:25 +00:00
/* At second boundaries insert either the updated comment (if we've seen some metadata records
* already ) or the full metadata */
if ( dump_priv - > periodic_sections ) {
2018-02-09 00:19:12 +00:00
if ( ! erf_write_meta_record ( wdh , dump_priv , ( guint64 ) ( rec - > ts . secs ) < < 32 , dump_priv - > periodic_sections , dump_priv - > periodic_extra_ehdrs , err ) ) return FALSE ;
dump_priv - > prev_inserted_time_sec = rec - > ts . secs ;
2017-06-01 08:34:25 +00:00
}
}
2013-01-06 20:44:49 +00:00
}
2011-08-31 20:50:15 +00:00
2017-06-01 08:34:25 +00:00
/* If the packet user comment has changed, we need to
* construct a new header with additional Host ID and Anchor ID
* and insert a metadata record before that frame */
/*XXX: The user may have changed the comment to cleared! */
2021-07-08 05:43:29 +00:00
if ( rec - > block_was_modified ) {
2017-06-01 08:34:25 +00:00
if ( encap = = WTAP_ENCAP_ERF ) {
2018-01-09 00:38:10 +00:00
/* XXX: What about ERF-in-pcapng with existing comment (that wasn't
2017-06-01 08:34:25 +00:00
* modified ) ? */
2021-07-08 05:43:29 +00:00
if ( rec - > block_was_modified ) {
2020-12-07 22:00:19 +00:00
memmove ( & other_phdr , pseudo_header , sizeof ( union wtap_pseudo_header ) ) ;
2018-02-09 00:19:12 +00:00
if ( ! erf_write_anchor_meta_update_phdr ( wdh , dump_priv , rec , & other_phdr , err ) ) return FALSE ;
2017-06-01 08:34:25 +00:00
pseudo_header = & other_phdr ;
}
} else {
/* Always write the comment if non-ERF */
2018-02-09 00:19:12 +00:00
if ( ! erf_write_anchor_meta_update_phdr ( wdh , dump_priv , rec , & other_phdr , err ) ) return FALSE ;
2017-06-01 08:34:25 +00:00
}
2013-01-06 20:44:49 +00:00
}
2011-08-31 20:50:15 +00:00
2017-06-01 08:34:25 +00:00
/* Make sure we always write out rlen, regardless of what happens */
alignbytes = wdh - > bytes_dumped + pseudo_header - > erf . phdr . rlen ;
if ( ! erf_write_phdr ( wdh , WTAP_ENCAP_ERF , pseudo_header , err ) ) return FALSE ;
2018-02-09 00:19:12 +00:00
if ( ! wtap_dump_file_write ( wdh , pd , rec - > rec_header . packet_header . caplen - round_down , err ) ) return FALSE ;
wdh - > bytes_dumped + = rec - > rec_header . packet_header . caplen - round_down ;
2011-08-31 20:50:15 +00:00
2013-01-06 20:44:49 +00:00
/*add the 4 byte CRC if necessary*/
if ( must_add_crc ) {
2014-05-09 05:18:49 +00:00
if ( ! wtap_dump_file_write ( wdh , & crc32 , 4 , err ) ) return FALSE ;
2013-01-06 20:44:49 +00:00
wdh - > bytes_dumped + = 4 ;
}
2017-06-01 08:34:25 +00:00
/*XXX: In the case of ENCAP_ERF, this pads the record to its original length, which is fine in most
* cases . However with > MAX_ERF_EHDR unnecessary padding will be added , and
* if the record was truncated this will be incorrectly treated as payload .
* More than 8 extension headers is unusual though , only the first 8 are
* written out anyway and fixing properly would require major refactor . */
/*records should be 8byte aligned, so we add padding to our calculated rlen */
while ( wdh - > bytes_dumped < alignbytes ) {
if ( ! wtap_dump_file_write ( wdh , " " , 1 , err ) ) return FALSE ;
wdh - > bytes_dumped + + ;
2011-08-31 20:50:15 +00:00
}
2017-06-01 08:34:25 +00:00
dump_priv - > prev_erf_type = pseudo_header - > erf . phdr . type & 0x7FU ;
dump_priv - > prev_frame_ts = pseudo_header - > erf . phdr . ts ;
2011-08-31 20:50:15 +00:00
return TRUE ;
}
2021-04-16 18:24:52 +00:00
static int erf_dump_can_write_encap ( int encap )
2011-08-31 20:50:15 +00:00
{
if ( encap = = WTAP_ENCAP_PER_PACKET )
return 0 ;
if ( wtap_wtap_encap_to_erf_encap ( encap ) = = - 1 )
2014-12-17 06:40:45 +00:00
return WTAP_ERR_UNWRITABLE_ENCAP ;
2011-08-31 20:50:15 +00:00
return 0 ;
}
2021-04-16 18:24:52 +00:00
static int erf_dump_open ( wtap_dumper * wdh , int * err _U_ , gchar * * err_info _U_ )
2011-08-31 20:50:15 +00:00
{
2017-06-01 08:34:25 +00:00
erf_dump_t * dump_priv ;
gchar * s ;
guint64 host_id ;
dump_priv = erf_dump_priv_create ( ) ;
2011-08-31 20:50:15 +00:00
wdh - > subtype_write = erf_dump ;
2017-06-01 08:34:25 +00:00
wdh - > priv = dump_priv ;
wdh - > subtype_finish = erf_dump_finish ;
/* Get the capture comment string */
get_user_comment_string ( wdh , & dump_priv - > user_comment_ptr ) ;
/* XXX: If we have a capture comment or a non-ERF file assume we need to
* write metadata unless we see existing metadata in the first second . */
if ( dump_priv - > user_comment_ptr | | wdh - > encap ! = WTAP_ENCAP_ERF )
dump_priv - > write_next_extra_meta = TRUE ;
/* Read Host ID from environment variable */
/* TODO: generate one from MAC address? */
if ( ( s = getenv ( " ERF_HOST_ID " ) ) ! = NULL ) {
/* TODO: support both decimal and hex strings (base 0)? */
if ( ws_hexstrtou64 ( s , NULL , & host_id ) ) {
dump_priv - > host_id = host_id & ERF_EHDR_HOST_ID_MASK ;
}
}
2011-08-31 20:50:15 +00:00
return TRUE ;
}
2012-05-24 09:24:05 +00:00
2020-05-02 04:02:00 +00:00
static int erf_get_source_from_header ( union wtap_pseudo_header * pseudo_header , guint64 * host_id , guint8 * source_id )
2016-03-11 03:44:16 +00:00
{
guint8 type ;
guint8 has_more ;
guint64 hdr ;
int i = 0 ;
gboolean host_id_found = FALSE ;
if ( ! pseudo_header | | ! host_id | | ! source_id )
return - 1 ;
2016-10-13 23:46:29 +00:00
* host_id = ERF_META_HOST_ID_IMPLICIT ;
2016-03-11 03:44:16 +00:00
* source_id = 0 ;
has_more = pseudo_header - > erf . phdr . type & 0x80 ;
while ( has_more & & ( i < MAX_ERF_EHDR ) ) {
hdr = pseudo_header - > erf . ehdr_list [ i ] . ehdr ;
type = ( guint8 ) ( hdr > > 56 ) ;
/*
* XXX : Only want first Source ID and Host ID , and want to preserve HID n SID 0 ( see
* erf_populate_interface )
*/
switch ( type & 0x7f ) {
case ERF_EXT_HDR_TYPE_HOST_ID :
if ( ! host_id_found )
* host_id = hdr & ERF_EHDR_HOST_ID_MASK ;
host_id_found = TRUE ;
/* Fall through */
case ERF_EXT_HDR_TYPE_FLOW_ID :
if ( * source_id = = 0 )
* source_id = ( hdr > > 48 ) & 0xff ;
break ;
}
if ( host_id_found )
break ;
has_more = type & 0x80 ;
i + = 1 ;
}
return 0 ;
}
2021-06-18 23:22:54 +00:00
int erf_populate_interface_from_header ( erf_t * erf_priv , wtap * wth , union wtap_pseudo_header * pseudo_header , int * err , gchar * * err_info )
2016-03-11 03:44:16 +00:00
{
guint64 host_id ;
guint8 source_id ;
guint8 if_num ;
if ( ! pseudo_header )
return - 1 ;
if_num = pseudo_header - > erf . phdr . flags & 0x03 ;
erf_get_source_from_header ( pseudo_header , & host_id , & source_id ) ;
2021-06-18 23:22:54 +00:00
return erf_populate_interface ( erf_priv , wth , pseudo_header , host_id , source_id , if_num , err , err_info ) ;
2016-03-11 03:44:16 +00:00
}
static struct erf_if_mapping * erf_find_interface_mapping ( erf_t * erf_priv , guint64 host_id , guint8 source_id )
{
struct erf_if_mapping if_map_lookup ;
2017-06-01 08:34:25 +00:00
/* XXX: erf_priv should never be NULL here */
2016-03-11 03:44:16 +00:00
if ( ! erf_priv )
return NULL ;
if_map_lookup . host_id = host_id ;
if_map_lookup . source_id = source_id ;
return ( struct erf_if_mapping * ) g_hash_table_lookup ( erf_priv - > if_map , & if_map_lookup ) ;
}
2016-07-14 23:01:57 +00:00
static void erf_set_interface_descr ( wtap_block_t block , guint option_id , guint64 host_id , guint8 source_id , guint8 if_num , const gchar * descr )
2016-03-11 03:44:16 +00:00
{
/* Source XXX,*/
char sourceid_buf [ 16 ] ;
/* Host XXXXXXXXXXXX,*/
char hostid_buf [ 24 ] ;
sourceid_buf [ 0 ] = ' \0 ' ;
hostid_buf [ 0 ] = ' \0 ' ;
2016-10-13 23:46:29 +00:00
/* Implicit Host ID defaults to 0 */
if ( host_id = = ERF_META_HOST_ID_IMPLICIT ) {
host_id = 0 ;
}
2016-03-11 03:44:16 +00:00
if ( host_id > 0 ) {
g_snprintf ( hostid_buf , sizeof ( hostid_buf ) , " Host %012 " G_GINT64_MODIFIER " x, " , host_id ) ;
}
if ( source_id > 0 ) {
g_snprintf ( sourceid_buf , sizeof ( sourceid_buf ) , " Source %u, " , source_id ) ;
}
if ( descr ) {
2016-07-14 23:01:57 +00:00
wtap_block_set_string_option_value_format ( block , option_id , " %s (ERF%s%s Interface %d) " , descr , hostid_buf , sourceid_buf , if_num ) ;
2016-03-11 03:44:16 +00:00
} else {
2016-07-14 23:01:57 +00:00
wtap_block_set_string_option_value_format ( block , option_id , " Port %c (ERF%s%s Interface %d) " , ' A ' + if_num , hostid_buf , sourceid_buf , if_num ) ;
2016-03-11 03:44:16 +00:00
}
}
2018-02-09 00:19:12 +00:00
static int erf_update_anchors_from_header ( erf_t * erf_priv , wtap_rec * rec , union wtap_pseudo_header * pseudo_header , guint64 host_id , GPtrArray * anchor_mappings_to_update )
2017-06-01 08:34:25 +00:00
{
guint8 type ;
guint8 has_more ;
guint64 hdr ;
guint64 comment_gen_time = 0 ;
guint64 host_id_current ;
guint64 anchor_id_current = 0 ;
int i = 0 ;
gchar * comment = NULL ;
2018-02-09 00:19:12 +00:00
if ( ! rec | | ! pseudo_header )
2017-06-01 08:34:25 +00:00
return - 1 ;
/* Start with the first Host ID that was found on the record
* as the Anchor ID isn ' t required to be the first extension header ' */
host_id_current = host_id = = ERF_META_HOST_ID_IMPLICIT ? erf_priv - > implicit_host_id : host_id ;
has_more = pseudo_header - > erf . phdr . type & 0x80 ;
while ( has_more & & ( i < MAX_ERF_EHDR ) ) {
hdr = pseudo_header - > erf . ehdr_list [ i ] . ehdr ;
type = ( guint8 ) ( hdr > > 56 ) ;
switch ( type & 0x7f ) {
case ERF_EXT_HDR_TYPE_HOST_ID :
host_id_current = hdr & ERF_EHDR_HOST_ID_MASK ;
break ;
case ERF_EXT_HDR_TYPE_ANCHOR_ID :
{
anchor_id_current = hdr & ERF_EHDR_ANCHOR_ID_MASK ;
if ( ! ( ERF_ANCHOR_ID_IS_DEFINITION ( hdr ) ) ) {
/*
2020-10-10 23:42:05 +00:00
* Anchor definition flag is 0 , attempt to associate a comment with this record
2017-06-01 08:34:25 +00:00
* XXX : currently the comment count may be wrong on the first pass !
*/
/* We may not have found the implicit Host ID yet, if so we are unlikely to find anything */
struct erf_anchor_mapping * lookup_result ;
lookup_result = erf_find_anchor_mapping ( erf_priv , host_id_current , anchor_id_current ) ;
if ( lookup_result ) {
if ( lookup_result - > gen_time > comment_gen_time ) {
/* XXX: we might have a comment that clears the comment (i.e.
* empty string ) ! */
if ( lookup_result - > comment & & lookup_result - > comment [ 0 ] ! = ' \0 ' ) {
comment = lookup_result - > comment ;
}
comment_gen_time = lookup_result - > gen_time ;
}
}
}
else {
if ( anchor_mappings_to_update & & ( pseudo_header - > erf . phdr . type & 0x7f ) = = ERF_TYPE_META ) {
/*
* Anchor definition flag is 1 , put the mapping in an array
* which we will later update when we walk through
* the metadata tags
*/
/* Only Provenance record can contain the information we need */
struct erf_anchor_mapping * mapping_ptr =
2020-12-21 02:30:28 +00:00
g_new0 ( struct erf_anchor_mapping , 1 ) ;
2017-06-01 08:34:25 +00:00
/* May be ERF_META_HOST_ID_IMPLICIT */
mapping_ptr - > host_id = host_id_current ;
mapping_ptr - > anchor_id = anchor_id_current ;
g_ptr_array_add ( anchor_mappings_to_update , mapping_ptr ) ;
}
}
break ;
}
}
has_more = type & 0x80 ;
i + = 1 ;
}
if ( comment ) {
2019-01-24 11:08:57 +00:00
/* Will be freed by either wtap_sequential_close (for rec = &wth->rec) or by
* the caller of wtap_seek_read . See wtap_rec_cleanup . */
2021-04-29 11:23:21 +00:00
rec - > block = wtap_block_create ( WTAP_BLOCK_PACKET ) ;
wtap_block_add_string_option ( rec - > block , OPT_COMMENT , comment , strlen ( comment ) ) ;
2017-06-01 08:34:25 +00:00
}
return 0 ;
}
/**
* @ brief Update the implicit Host ID and Anchor Mapping information
*/
2016-03-11 03:44:16 +00:00
static int erf_update_implicit_host_id ( erf_t * erf_priv , wtap * wth , guint64 implicit_host_id )
{
GHashTableIter iter ;
gpointer iter_value ;
GList * implicit_list = NULL ;
GList * item = NULL ;
2016-07-14 23:01:57 +00:00
wtap_block_t int_data ;
2016-03-11 03:44:16 +00:00
struct erf_if_mapping * if_map = NULL ;
2016-10-13 23:46:29 +00:00
struct erf_if_mapping * if_map_other = NULL ;
struct erf_if_info * if_info = NULL ;
2017-06-01 08:34:25 +00:00
struct erf_anchor_mapping * anchor_mapping = NULL ;
struct erf_anchor_mapping * anchor_mapping_other = NULL ;
2016-10-13 23:46:29 +00:00
gchar * oldstr = NULL ;
char portstr_buf [ 16 ] ;
2016-03-11 03:44:16 +00:00
int i ;
if ( ! erf_priv )
return - 1 ;
erf_priv - > implicit_host_id = implicit_host_id ;
/*
* We need to update the descriptions of all the interfaces with no Host
* ID to the correct Host ID .
*/
g_hash_table_iter_init ( & iter , erf_priv - > if_map ) ;
/* Remove the implicit mappings from the mapping table */
while ( g_hash_table_iter_next ( & iter , & iter_value , NULL ) ) {
if_map = ( struct erf_if_mapping * ) iter_value ;
2016-10-13 23:46:29 +00:00
if ( if_map - > host_id = = ERF_META_HOST_ID_IMPLICIT ) {
/* Check we don't have an existing interface that matches */
if_map_other = erf_find_interface_mapping ( erf_priv , implicit_host_id , if_map - > source_id ) ;
if ( ! if_map_other ) {
/* Pull mapping for update */
/* XXX: Can't add while iterating hash table so use list instead */
g_hash_table_iter_steal ( & iter ) ;
2017-06-01 08:34:25 +00:00
implicit_list = g_list_prepend ( implicit_list , if_map ) ;
2016-10-13 23:46:29 +00:00
} else {
/*
* XXX : We have duplicate interfaces in this case , but not much else we
* can do since we have already dissected the earlier packets . Expected
* to be unusual as it reqires a mix of explicit and implicit Host ID
* ( e . g . FlowID extension header only ) packets with the same effective
* Host ID before the first ERF_TYPE_META record .
*/
/*
* Update the description of the ERF_META_HOST_ID_IMPLICIT interface ( s )
* for the first records in one pass mode . In 2 pass mode ( Wireshark
* initial open , TShark in 2 pass mode ) we will update the interface
* mapping for the frames on the second pass . Relatively consistent
* with the dissector behaviour .
*
* TODO : Can we delete this interface on the second ( or even first )
* pass ? Should we try to merge in other metadata ?
* Needs a wtap_block_copy ( ) that supports overwriting and / or expose
* custom option copy and do with wtap_block_foreach_option ( ) .
*/
for ( i = 0 ; i < 4 ; i + + ) {
if_info = & if_map - > interfaces [ i ] ;
if ( if_info - > if_index > = 0 ) {
/* XXX: this is a pointer! */
int_data = g_array_index ( wth - > interface_data , wtap_block_t , if_info - > if_index ) ;
g_snprintf ( portstr_buf , sizeof ( portstr_buf ) , " Port %c " , ' A ' + i ) ;
oldstr = if_info - > name ;
if_info - > name = g_strconcat ( oldstr ? oldstr : portstr_buf , " [unmatched implicit] " , NULL ) ;
g_free ( oldstr ) ; /* probably null, but g_free doesn't care */
oldstr = if_info - > descr ;
if_info - > descr = g_strconcat ( oldstr ? oldstr : portstr_buf , " [unmatched implicit] " , NULL ) ;
g_free ( oldstr ) ;
erf_set_interface_descr ( int_data , OPT_IDB_NAME , implicit_host_id , if_map - > source_id , ( guint8 ) i , if_info - > name ) ;
2021-07-14 06:48:19 +00:00
erf_set_interface_descr ( int_data , OPT_IDB_DESCRIPTION , implicit_host_id , if_map - > source_id , ( guint8 ) i , if_info - > descr ) ;
2016-10-13 23:46:29 +00:00
}
}
}
2016-03-11 03:44:16 +00:00
}
}
2016-10-13 23:46:29 +00:00
/* Re-add the non-clashing items under the real implicit Host ID */
2016-03-11 03:44:16 +00:00
if ( implicit_list ) {
item = implicit_list ;
do {
if_map = ( struct erf_if_mapping * ) item - > data ;
2016-10-13 23:46:29 +00:00
2016-03-11 03:44:16 +00:00
for ( i = 0 ; i < 4 ; i + + ) {
2016-10-13 23:46:29 +00:00
if_info = & if_map - > interfaces [ i ] ;
if ( if_info - > if_index > = 0 ) {
2016-03-11 03:44:16 +00:00
/* XXX: this is a pointer! */
2016-10-13 23:46:29 +00:00
int_data = g_array_index ( wth - > interface_data , wtap_block_t , if_info - > if_index ) ;
erf_set_interface_descr ( int_data , OPT_IDB_NAME , implicit_host_id , if_map - > source_id , ( guint8 ) i , if_info - > name ) ;
2021-07-14 06:48:19 +00:00
erf_set_interface_descr ( int_data , OPT_IDB_DESCRIPTION , implicit_host_id , if_map - > source_id , ( guint8 ) i , if_info - > descr ) ;
2016-03-11 03:44:16 +00:00
}
}
2016-10-13 23:46:29 +00:00
2016-03-11 03:44:16 +00:00
if_map - > host_id = implicit_host_id ;
2016-04-05 13:32:56 +00:00
/* g_hash_table_add() only exists since 2.32. */
g_hash_table_replace ( erf_priv - > if_map , if_map , if_map ) ;
2016-03-11 03:44:16 +00:00
} while ( ( item = g_list_next ( item ) ) ) ;
g_list_free ( implicit_list ) ;
2017-06-01 08:34:25 +00:00
implicit_list = NULL ;
}
/*
* We also need to update the anchor comment mappings
* to the correct Host ID .
*/
g_hash_table_iter_init ( & iter , erf_priv - > anchor_map ) ;
/* Remove the implicit mappings from the mapping table */
while ( g_hash_table_iter_next ( & iter , & iter_value , NULL ) ) {
anchor_mapping = ( struct erf_anchor_mapping * ) iter_value ;
if ( anchor_mapping - > host_id = = ERF_META_HOST_ID_IMPLICIT ) {
/* Check we don't have an existing anchor that matches */
anchor_mapping_other = erf_find_anchor_mapping ( erf_priv , implicit_host_id ,
anchor_mapping - > anchor_id ) ;
if ( anchor_mapping_other & & anchor_mapping_other - > gen_time > = anchor_mapping - > gen_time ) {
/*
* XXX : Duplicate entry of anchor mapping , keep the one with newer
* gen_time .
*/
g_hash_table_iter_remove ( & iter ) ;
} else {
/* Pull mapping for update */
/* XXX: Can't add while iterating hash table so use list instead */
g_hash_table_iter_steal ( & iter ) ;
implicit_list = g_list_prepend ( implicit_list , anchor_mapping ) ;
/* existing entry (if any) will be removed by g_hash_table_replace */
}
}
}
/* Re-add the non-clashing items under the real implicit Host ID */
if ( implicit_list ) {
item = implicit_list ;
do {
anchor_mapping = ( struct erf_anchor_mapping * ) item - > data ;
anchor_mapping - > host_id = implicit_host_id ;
g_hash_table_replace ( erf_priv - > anchor_map , anchor_mapping , anchor_mapping ) ;
} while ( ( item = g_list_next ( item ) ) ) ;
g_list_free ( implicit_list ) ;
implicit_list = NULL ;
2016-03-11 03:44:16 +00:00
}
return 0 ;
}
2021-06-18 23:22:54 +00:00
static int erf_populate_interface ( erf_t * erf_priv , wtap * wth , union wtap_pseudo_header * pseudo_header , guint64 host_id , guint8 source_id , guint8 if_num , int * err , gchar * * err_info )
2016-03-11 03:44:16 +00:00
{
2016-07-14 23:01:57 +00:00
wtap_block_t int_data ;
2016-03-11 03:44:16 +00:00
wtapng_if_descr_mandatory_t * int_data_mand ;
struct erf_if_mapping * if_map = NULL ;
2021-06-18 23:22:54 +00:00
if ( ! wth ) {
* err = WTAP_ERR_INTERNAL ;
* err_info = g_strdup_printf ( " erf: erf_populate_interface called with wth NULL " ) ;
2016-03-11 03:44:16 +00:00
return - 1 ;
2021-06-18 23:22:54 +00:00
}
if ( ! pseudo_header ) {
* err = WTAP_ERR_INTERNAL ;
* err_info = g_strdup_printf ( " erf: erf_populate_interface called with pseudo_header NULL " ) ;
return - 1 ;
}
if ( ! erf_priv ) {
* err = WTAP_ERR_INTERNAL ;
* err_info = g_strdup_printf ( " erf: erf_populate_interface called with erf_priv NULL " ) ;
return - 1 ;
}
if ( if_num > 3 ) {
* err = WTAP_ERR_INTERNAL ;
* err_info = g_strdup_printf ( " erf: erf_populate_interface called with if_num %u > 3 " ,
if_num ) ;
return - 1 ;
}
2016-03-11 03:44:16 +00:00
2016-10-13 23:46:29 +00:00
if ( host_id = = ERF_META_HOST_ID_IMPLICIT ) {
/* Defaults to ERF_META_HOST_ID_IMPLICIT so we can update mapping later */
host_id = erf_priv - > implicit_host_id ;
} else if ( ( pseudo_header - > erf . phdr . type & 0x7f ) = = ERF_TYPE_META ) {
2016-03-11 03:44:16 +00:00
/*
* XXX : We assume there is only one Implicit Host ID . As a special case a first
* Host ID extension header with Source ID 0 on a record does not change
* the implicit Host ID . We respect this even though we support only one
* Implicit Host ID .
*/
2016-10-13 23:46:29 +00:00
if ( erf_priv - > implicit_host_id = = ERF_META_HOST_ID_IMPLICIT & & source_id > 0 ) {
2016-03-11 03:44:16 +00:00
erf_update_implicit_host_id ( erf_priv , wth , host_id ) ;
}
}
if_map = erf_find_interface_mapping ( erf_priv , host_id , source_id ) ;
if ( ! if_map ) {
if_map = erf_if_mapping_create ( host_id , source_id ) ;
2016-04-05 13:32:56 +00:00
/* g_hash_table_add() only exists since 2.32. */
g_hash_table_replace ( erf_priv - > if_map , if_map , if_map ) ;
2016-03-11 03:44:16 +00:00
}
/* Return the existing interface if we have it */
if ( if_map - > interfaces [ if_num ] . if_index > = 0 ) {
return if_map - > interfaces [ if_num ] . if_index ;
}
wiretap: have file handlers advertise blocks and options supported.
Instead of a "supports name resolution" Boolean and bitflags for types of
comments supported, provide a list of block types that the file
type/subtype supports, with each block type having a list of options
supported. Indicate whether "supported" means "one instance" or
"multiple instances".
"Supports" doesn't just mean "can be written", it also means "could be
read".
Rename WTAP_BLOCK_IF_DESCRIPTION to WTAP_BLOCK_IF_ID_AND_INFO, to
indicate that it provides, in addition to information about the
interface, an ID (implicitly, in pcapng files, by its ordinal number)
that is associated with every packet in the file. Emphasize that in
comments - just because your capture file format can list the interfaces
on which a capture was done, that doesn't mean it supports this; it
doesn't do so if the file doesn't indicate, for every packet, on which
of those interfaces it was captured (I'm looking at *you*, Microsoft
Network Monitor...).
Use APIs to query that information to do what the "does this file
type/subtype support name resolution information", "does this file
type/subtype support all of these comment types", and "does this file
type/subtype support - and require - interface IDs" APIs did.
Provide backwards compatibility for Lua.
This allows us to eliminate the WTAP_FILE_TYPE_SUBTYPE_ values for IBM's
iptrace; do so.
2021-02-21 22:18:04 +00:00
int_data = wtap_block_create ( WTAP_BLOCK_IF_ID_AND_INFO ) ;
2016-07-14 23:01:57 +00:00
int_data_mand = ( wtapng_if_descr_mandatory_t * ) wtap_block_get_mandatory_data ( int_data ) ;
2016-03-11 03:44:16 +00:00
int_data_mand - > wtap_encap = WTAP_ENCAP_ERF ;
/* int_data.time_units_per_second = (1LL<<32); ERF format resolution is 2^-32, capture resolution is unknown */
int_data_mand - > time_units_per_second = 1000000000 ; /* XXX Since Wireshark only supports down to nanosecond resolution we have to dilute to this */
2021-06-18 08:24:41 +00:00
int_data_mand - > tsprecision = WTAP_TSPREC_NSEC ;
2016-03-11 03:44:16 +00:00
int_data_mand - > snap_len = 65535 ; /* ERF max length */
/* XXX: if_IPv4addr opt 4 Interface network address and netmask.*/
/* XXX: if_IPv6addr opt 5 Interface network address and prefix length (stored in the last byte).*/
/* XXX: if_MACaddr opt 6 Interface Hardware MAC address (48 bits).*/
/* XXX: if_EUIaddr opt 7 Interface Hardware EUI address (64 bits)*/
2016-07-14 23:01:57 +00:00
/* XXX: if_speed opt 8 Interface speed (in bits per second)*/
2016-03-11 03:44:16 +00:00
/* int_data.if_tsresol = 0xa0; ERF format resolution is 2^-32 = 0xa0, capture resolution is unknown */
2016-07-14 23:01:57 +00:00
wtap_block_add_uint8_option ( int_data , OPT_IDB_TSRESOL , 0x09 ) ; /* XXX Since Wireshark only supports down to nanosecond resolution we have to dilute to this */
2016-03-11 03:44:16 +00:00
/* XXX: if_tzone 10 Time zone for GMT support (TODO: specify better). */
/* XXX if_tsoffset; opt 14 A 64 bits integer value that specifies an offset (in seconds)...*/
/* Interface statistics */
int_data_mand - > num_stat_entries = 0 ;
int_data_mand - > interface_statistics = NULL ;
2016-05-20 02:28:43 +00:00
erf_set_interface_descr ( int_data , OPT_IDB_NAME , host_id , source_id , if_num , NULL ) ;
2021-07-14 06:48:19 +00:00
erf_set_interface_descr ( int_data , OPT_IDB_DESCRIPTION , host_id , source_id , if_num , NULL ) ;
2016-03-11 03:44:16 +00:00
if_map - > interfaces [ if_num ] . if_index = ( int ) wth - > interface_data - > len ;
2020-05-02 01:19:00 +00:00
wtap_add_idb ( wth , int_data ) ;
2016-03-11 03:44:16 +00:00
return if_map - > interfaces [ if_num ] . if_index ;
}
static guint32 erf_meta_read_tag ( struct erf_meta_tag * tag , guint8 * tag_ptr , guint32 remaining_len )
{
guint16 tagtype ;
guint16 taglength ;
2016-05-05 07:40:57 +00:00
guint32 tagtotallength ;
2016-03-11 03:44:16 +00:00
if ( ! tag_ptr | | ! tag | | remaining_len < ERF_META_TAG_HEADERLEN )
return 0 ;
/* tagtype (2 bytes) */
tagtype = pntoh16 ( & tag_ptr [ 0 ] ) ;
/* length (2 bytes) */
taglength = pntoh16 ( & tag_ptr [ 2 ] ) ;
2017-06-01 08:34:25 +00:00
tagtotallength = ERF_META_TAG_TOTAL_ALIGNED_LENGTH ( taglength ) ;
2016-05-05 07:40:57 +00:00
if ( remaining_len < tagtotallength ) {
2016-03-11 03:44:16 +00:00
return 0 ;
}
tag - > type = tagtype ;
tag - > length = taglength ;
tag - > value = & tag_ptr [ 4 ] ;
2016-05-05 07:40:57 +00:00
return tagtotallength ;
2016-03-11 03:44:16 +00:00
}
2021-06-18 23:22:54 +00:00
static int populate_capture_host_info ( erf_t * erf_priv , wtap * wth , union wtap_pseudo_header * pseudo_header _U_ , struct erf_meta_read_state * state , int * err , gchar * * err_info )
2016-03-11 03:44:16 +00:00
{
struct erf_meta_tag tag = { 0 , 0 , NULL } ;
2016-07-14 23:01:57 +00:00
wtap_block_t shb_hdr ;
2016-03-11 03:44:16 +00:00
char * tmp ;
gchar * app_name = NULL ;
gchar * app_version = NULL ;
gchar * model = NULL ;
gchar * descr = NULL ;
gchar * cpu = NULL ;
gchar * modelcpu = NULL ;
guint32 tagtotallength ;
2021-06-18 23:22:54 +00:00
if ( ! wth ) {
* err = WTAP_ERR_INTERNAL ;
* err_info = g_strdup_printf ( " erf: populate_capture_host_info called with wth NULL " ) ;
return - 1 ;
}
if ( ! state ) {
* err = WTAP_ERR_INTERNAL ;
* err_info = g_strdup_printf ( " erf: populate_capture_host_info called with state NULL " ) ;
2016-03-11 03:44:16 +00:00
return - 1 ;
2021-06-18 23:22:54 +00:00
}
if ( ! wth - > shb_hdrs ) {
* err = WTAP_ERR_INTERNAL ;
* err_info = g_strdup_printf ( " erf: populate_capture_host_info called with wth->shb_hdrs NULL " ) ;
return - 1 ;
}
if ( wth - > shb_hdrs - > len = = 0 ) {
* err = WTAP_ERR_INTERNAL ;
* err_info = g_strdup_printf ( " erf: populate_capture_host_info called with wth->shb_hdrs->len 0 " ) ;
return - 1 ;
}
2016-03-11 03:44:16 +00:00
/* XXX: wth->shb_hdr is already created by different layer, using directly for now. */
2016-05-31 03:42:41 +00:00
/* XXX: Only one section header is supported at this time */
2016-07-14 23:01:57 +00:00
shb_hdr = g_array_index ( wth - > shb_hdrs , wtap_block_t , 0 ) ;
2016-03-11 03:44:16 +00:00
while ( ( tagtotallength = erf_meta_read_tag ( & tag , state - > tag_ptr , state - > remaining_len ) ) & & ! ERF_META_IS_SECTION ( tag . type ) ) {
switch ( state - > sectiontype ) {
case ERF_META_SECTION_CAPTURE :
{
2017-06-01 08:34:25 +00:00
if ( erf_priv - > capture_gentime > state - > gen_time ) {
2016-03-11 03:44:16 +00:00
return 0 ;
}
switch ( tag . type ) {
case ERF_META_TAG_comment :
2017-06-01 08:34:25 +00:00
{
gchar * existing_comment = NULL ;
/*XXX: hack to make changing capture comment work since Wireshark only
* displays one . For now just overwrite the comment as we won ' t
* pick up all of them yet due to the gen_time check above */
if ( wtap_block_get_nth_string_option_value ( shb_hdr , OPT_COMMENT , 0 , & existing_comment ) = = WTAP_OPTTYPE_SUCCESS ) {
wtap_block_set_nth_string_option_value ( shb_hdr , OPT_COMMENT , 0 , tag . value , tag . length ) ;
} else {
wtap_block_add_string_option ( shb_hdr , OPT_COMMENT , tag . value , tag . length ) ;
}
2016-03-11 03:44:16 +00:00
break ;
2017-06-01 08:34:25 +00:00
}
2016-03-11 03:44:16 +00:00
}
}
2018-05-02 16:44:43 +00:00
/* Fall through */
2016-03-11 03:44:16 +00:00
case ERF_META_SECTION_HOST :
{
2017-06-01 08:34:25 +00:00
if ( erf_priv - > host_gentime > state - > gen_time ) {
2016-03-11 03:44:16 +00:00
return 0 ;
}
switch ( tag . type ) {
case ERF_META_TAG_model :
g_free ( model ) ;
model = g_strndup ( ( gchar * ) tag . value , tag . length ) ;
break ;
case ERF_META_TAG_cpu :
g_free ( cpu ) ;
cpu = g_strndup ( ( gchar * ) tag . value , tag . length ) ;
break ;
case ERF_META_TAG_descr :
g_free ( descr ) ;
descr = g_strndup ( ( gchar * ) tag . value , tag . length ) ;
break ;
case ERF_META_TAG_os :
2016-07-14 23:01:57 +00:00
wtap_block_set_string_option_value ( shb_hdr , OPT_SHB_OS , tag . value , tag . length ) ;
2016-03-11 03:44:16 +00:00
break ;
case ERF_META_TAG_app_name :
g_free ( app_name ) ;
app_name = g_strndup ( ( gchar * ) tag . value , tag . length ) ;
break ;
case ERF_META_TAG_app_version :
g_free ( app_version ) ;
app_version = g_strndup ( ( gchar * ) tag . value , tag . length ) ;
break ;
/* TODO: dag_version? */
/* TODO: could concatenate comment(s)? */
2017-06-01 08:34:25 +00:00
case ERF_META_TAG_filter :
g_free ( state - > if_map - > capture_filter_str ) ;
state - > if_map - > capture_filter_str = g_strndup ( ( gchar * ) tag . value , tag . length ) ;
break ;
2016-03-11 03:44:16 +00:00
default :
break ;
}
}
break ;
}
state - > tag_ptr + = tagtotallength ;
state - > remaining_len - = tagtotallength ;
}
/* Post processing */
2021-05-24 02:37:09 +00:00
if ( app_name | | app_version ) {
/*
* If we have no app_name , we use " (Unknown applicaton) " .
*
* If we have no app_version , this will just use app_name .
*/
tmp = g_strjoin ( " " , app_name ? app_name : " (Unknown application) " , app_version , NULL ) ;
2016-07-14 23:01:57 +00:00
wtap_block_set_string_option_value ( shb_hdr , OPT_SHB_USERAPPL , tmp , strlen ( tmp ) ) ;
2016-03-11 03:44:16 +00:00
g_free ( tmp ) ;
g_free ( app_name ) ;
g_free ( app_version ) ;
app_name = NULL ;
app_version = NULL ;
}
/* For the hardware field show description followed by (model; cpu) */
/* Build "Model; CPU" part */
if ( model | | cpu ) {
/* g_strjoin() would be nice to use here if the API didn't stop on the first NULL... */
if ( model & & cpu ) {
modelcpu = g_strconcat ( model , " ; " , cpu , NULL ) ;
} else if ( cpu ) {
modelcpu = cpu ;
/* avoid double-free */
cpu = NULL ;
} else {
modelcpu = model ;
/* avoid double-free */
model = NULL ;
}
}
/* Combine into "Description (Model; CPU)" */
if ( state - > sectiontype = = ERF_META_SECTION_HOST & & descr ) {
if ( modelcpu ) {
2016-07-14 23:01:57 +00:00
wtap_block_set_string_option_value_format ( shb_hdr , OPT_SHB_HARDWARE , " %s (%s) " , descr , modelcpu ) ;
2016-03-11 03:44:16 +00:00
} else {
2016-07-14 23:01:57 +00:00
wtap_block_set_string_option_value ( shb_hdr , OPT_SHB_HARDWARE , descr , strlen ( descr ) ) ;
2016-03-11 03:44:16 +00:00
/*descr = NULL;*/
}
2016-05-20 02:28:43 +00:00
} else if ( modelcpu ) {
2016-07-14 23:01:57 +00:00
wtap_block_set_string_option_value ( shb_hdr , OPT_SHB_HARDWARE , modelcpu , strlen ( modelcpu ) ) ;
2016-03-11 03:44:16 +00:00
/*modelcpu = NULL;*/
}
/* Free the fields we didn't end up using */
g_free ( modelcpu ) ;
g_free ( model ) ;
g_free ( descr ) ;
g_free ( cpu ) ;
if ( state - > sectiontype = = ERF_META_SECTION_CAPTURE ) {
2017-06-01 08:34:25 +00:00
erf_priv - > capture_gentime = state - > gen_time ;
2016-03-11 03:44:16 +00:00
} else {
2017-06-01 08:34:25 +00:00
erf_priv - > host_gentime = state - > gen_time ;
2016-03-11 03:44:16 +00:00
}
return 1 ;
}
2021-06-18 23:22:54 +00:00
static int populate_module_info ( erf_t * erf_priv _U_ , wtap * wth , union wtap_pseudo_header * pseudo_header _U_ , struct erf_meta_read_state * state , int * err , gchar * * err_info )
2016-03-11 03:44:16 +00:00
{
struct erf_meta_tag tag = { 0 , 0 , NULL } ;
guint32 tagtotallength ;
2021-06-18 23:22:54 +00:00
if ( ! wth ) {
* err = WTAP_ERR_INTERNAL ;
* err_info = g_strdup_printf ( " erf: populate_module_info called with wth NULL " ) ;
return - 1 ;
}
if ( ! state ) {
* err = WTAP_ERR_INTERNAL ;
* err_info = g_strdup_printf ( " erf: populate_module_info called with stat NULL " ) ;
2016-03-11 03:44:16 +00:00
return - 1 ;
2021-06-18 23:22:54 +00:00
}
2016-03-11 03:44:16 +00:00
2017-06-01 08:34:25 +00:00
if ( state - > if_map - > module_gentime > state - > gen_time ) {
2016-03-11 03:44:16 +00:00
return 0 ;
}
while ( ( tagtotallength = erf_meta_read_tag ( & tag , state - > tag_ptr , state - > remaining_len ) ) & & ! ERF_META_IS_SECTION ( tag . type ) ) {
2017-06-01 08:34:25 +00:00
switch ( tag . type ) {
case ERF_META_TAG_fcs_len :
if ( tag . length > = 4 ) {
state - > if_map - > module_fcs_len = ( gint8 ) pntoh32 ( tag . value ) ;
}
break ;
case ERF_META_TAG_snaplen :
/* XXX: this is generally per stream */
if ( tag . length > = 4 ) {
state - > if_map - > module_snaplen = pntoh32 ( tag . value ) ;
}
break ;
case ERF_META_TAG_filter :
g_free ( state - > if_map - > module_filter_str ) ;
state - > if_map - > module_filter_str = g_strndup ( ( gchar * ) tag . value , tag . length ) ;
break ;
}
2016-03-11 03:44:16 +00:00
state - > tag_ptr + = tagtotallength ;
state - > remaining_len - = tagtotallength ;
}
2017-06-01 08:34:25 +00:00
state - > if_map - > module_gentime = state - > gen_time ;
2016-03-11 03:44:16 +00:00
return 1 ;
}
2021-06-18 23:22:54 +00:00
static int populate_interface_info ( erf_t * erf_priv , wtap * wth , union wtap_pseudo_header * pseudo_header , struct erf_meta_read_state * state , int * err , gchar * * err_info )
2016-03-11 03:44:16 +00:00
{
struct erf_meta_tag tag = { 0 , 0 , NULL } ;
guint32 tagtotallength ;
int interface_index = - 1 ;
2016-07-14 23:01:57 +00:00
wtap_block_t int_data = NULL ;
2016-03-11 03:44:16 +00:00
wtapng_if_descr_mandatory_t * int_data_mand = NULL ;
2021-02-01 23:56:47 +00:00
if_filter_opt_t if_filter ;
2016-03-11 03:44:16 +00:00
guint32 if_num = 0 ;
struct erf_if_info * if_info = NULL ;
2021-06-18 23:22:54 +00:00
if ( ! wth ) {
* err = WTAP_ERR_INTERNAL ;
* err_info = g_strdup_printf ( " erf: populate_interface_info called with wth NULL " ) ;
return - 1 ;
}
if ( ! state ) {
* err = WTAP_ERR_INTERNAL ;
* err_info = g_strdup_printf ( " erf: populate_interface_info called with state NULL " ) ;
2016-03-11 03:44:16 +00:00
return - 1 ;
2021-06-18 23:22:54 +00:00
}
if ( ! pseudo_header ) {
* err = WTAP_ERR_INTERNAL ;
* err_info = g_strdup_printf ( " erf: populate_interface_info called with pseudo_header NULL " ) ;
return - 1 ;
}
if ( ! state - > if_map ) {
* err = WTAP_ERR_INTERNAL ;
* err_info = g_strdup_printf ( " erf: populate_interface_info called with state->if_map NULL " ) ;
return - 1 ;
}
2016-03-11 03:44:16 +00:00
/* Section ID of interface is defined to match ERF interface id. */
if_num = state - > sectionid - 1 ;
/*
* Get or create the interface ( there can be multiple interfaces in
2017-06-01 08:34:25 +00:00
* a Provenance record ) .
2016-03-11 03:44:16 +00:00
*/
if ( if_num < 4 ) { /* Note: -1u > 4*/
if_info = & state - > if_map - > interfaces [ if_num ] ;
interface_index = if_info - > if_index ;
/* Check if the interface information is still uninitialized */
if ( interface_index = = - 1 ) {
guint8 * tag_ptr_tmp = state - > tag_ptr ;
guint32 remaining_len_tmp = state - > remaining_len ;
/* First iterate tags, checking we aren't looking at a timing port */
/*
* XXX : we deliberately only do this logic here rather than the per - packet
* population function so that if somehow we do see packets for an
* ' invalid ' port the interface will be created at that time .
*/
while ( ( tagtotallength = erf_meta_read_tag ( & tag , tag_ptr_tmp , remaining_len_tmp ) ) & & ! ERF_META_IS_SECTION ( tag . type ) ) {
if ( tag . type = = ERF_META_TAG_if_port_type ) {
if ( tag . length > = 4 & & pntoh32 ( tag . value ) = = 2 ) {
/* This is a timing port, skip it from now on */
/* XXX: should we skip all non-capture ports instead? */
if_info - > if_index = - 2 ;
interface_index = - 2 ;
}
} else if ( tag . type = = ERF_META_TAG_stream_num ) {
if ( tag . length > = 4 ) {
if_info - > stream_num = ( gint32 ) pntoh32 ( tag . value ) ;
}
}
tag_ptr_tmp + = tagtotallength ;
remaining_len_tmp - = tagtotallength ;
}
/* If the interface is valid but uninitialized, create it */
if ( interface_index = = - 1 ) {
2021-06-18 23:22:54 +00:00
interface_index = erf_populate_interface ( erf_priv , wth , pseudo_header , state - > if_map - > host_id , state - > if_map - > source_id , ( guint8 ) if_num , err , err_info ) ;
if ( interface_index = = - 1 ) {
return - 1 ;
}
2016-03-11 03:44:16 +00:00
}
}
/* Get the wiretap interface metadata */
if ( interface_index > = 0 ) {
2016-07-14 23:01:57 +00:00
int_data = g_array_index ( wth - > interface_data , wtap_block_t , interface_index ) ;
int_data_mand = ( wtapng_if_descr_mandatory_t * ) wtap_block_get_mandatory_data ( int_data ) ;
2016-03-11 03:44:16 +00:00
} else if ( interface_index = = - 2 ) {
/* timing/unknown port */
return 0 ;
} else {
2021-06-18 23:22:54 +00:00
* err = WTAP_ERR_INTERNAL ;
* err_info = g_strdup_printf ( " erf: populate_interface_info got interface_index %d < 0 and != -2 " , interface_index ) ;
2016-03-11 03:44:16 +00:00
return - 1 ;
}
}
/*
* Bail if already have interface metadata or no interface to associate with .
* We also don ' t support metadata for > 4 interfaces per Host + Source
* as we only use interface ID .
*/
2017-06-01 08:34:25 +00:00
if ( ! int_data )
return 0 ;
if ( state - > if_map - > interface_gentime > state - > gen_time & & state - > if_map - > interface_metadata & ( 1 < < if_num ) )
2016-03-11 03:44:16 +00:00
return 0 ;
while ( ( tagtotallength = erf_meta_read_tag ( & tag , state - > tag_ptr , state - > remaining_len ) ) & & ! ERF_META_IS_SECTION ( tag . type ) ) {
switch ( tag . type ) {
case ERF_META_TAG_name :
/* TODO: fall back to module "dev_name Port N"? */
if ( ! if_info - > name ) {
if_info - > name = g_strndup ( ( gchar * ) tag . value , tag . length ) ;
2016-05-20 02:28:43 +00:00
erf_set_interface_descr ( int_data , OPT_IDB_NAME , state - > if_map - > host_id , state - > if_map - > source_id , ( guint8 ) if_num , if_info - > name ) ;
2016-03-11 03:44:16 +00:00
/* If we have no description, also copy to wtap if_description */
if ( ! if_info - > descr ) {
2021-07-14 06:48:19 +00:00
erf_set_interface_descr ( int_data , OPT_IDB_DESCRIPTION , state - > if_map - > host_id , state - > if_map - > source_id , ( guint8 ) if_num , if_info - > name ) ;
2016-03-11 03:44:16 +00:00
}
}
break ;
case ERF_META_TAG_descr :
if ( ! if_info - > descr ) {
if_info - > descr = g_strndup ( ( gchar * ) tag . value , tag . length ) ;
2021-07-14 06:48:19 +00:00
erf_set_interface_descr ( int_data , OPT_IDB_DESCRIPTION , state - > if_map - > host_id , state - > if_map - > source_id , ( guint8 ) if_num , if_info - > descr ) ;
2016-03-11 03:44:16 +00:00
/* If we have no name, also copy to wtap if_name */
if ( ! if_info - > name ) {
2016-05-20 02:28:43 +00:00
erf_set_interface_descr ( int_data , OPT_IDB_NAME , state - > if_map - > host_id , state - > if_map - > source_id , ( guint8 ) if_num , if_info - > descr ) ;
2016-03-11 03:44:16 +00:00
}
}
break ;
case ERF_META_TAG_if_speed :
if ( tag . length > = 8 )
2016-07-14 23:01:57 +00:00
wtap_block_add_uint64_option ( int_data , OPT_IDB_SPEED , pntoh64 ( tag . value ) ) ;
2016-03-11 03:44:16 +00:00
break ;
case ERF_META_TAG_if_num :
/*
* XXX : We ignore this as Section ID must match the ERF ifid and
* that is all we care about / have space for at the moment . if_num
* is only really useful with > 4 interfaces .
*/
/* TODO: might want to put this number in description */
break ;
case ERF_META_TAG_fcs_len :
if ( tag . length > = 4 ) {
2016-07-14 23:01:57 +00:00
wtap_block_add_uint8_option ( int_data , OPT_IDB_FCSLEN , ( guint8 ) pntoh32 ( tag . value ) ) ;
2016-03-11 03:44:16 +00:00
if_info - > set_flags . fcs_len = 1 ;
}
break ;
case ERF_META_TAG_snaplen :
/* XXX: this generally per stream */
if ( tag . length > = 4 ) {
int_data_mand - > snap_len = pntoh32 ( tag . value ) ;
if_info - > set_flags . snaplen = 1 ;
}
break ;
case ERF_META_TAG_comment :
2016-07-14 23:01:57 +00:00
wtap_block_add_string_option ( int_data , OPT_COMMENT , tag . value , tag . length ) ;
2016-03-11 03:44:16 +00:00
break ;
case ERF_META_TAG_filter :
2021-02-01 23:56:47 +00:00
if_filter . type = if_filter_pcap ;
if_filter . data . filter_str = g_strndup ( ( gchar * ) tag . value , tag . length ) ;
wtap_block_add_if_filter_option ( int_data , OPT_IDB_FILTER , & if_filter ) ;
g_free ( if_filter . data . filter_str ) ;
2016-03-11 03:44:16 +00:00
if_info - > set_flags . filter = 1 ;
break ;
default :
break ;
}
state - > tag_ptr + = tagtotallength ;
state - > remaining_len - = tagtotallength ;
}
/* Post processing */
/*
* XXX : Assumes module defined first . It is higher in hierarchy so only set
* if not already .
*/
/*
* XXX : Missing exposed existence / type - check . No way currently to check if
* been set in the optionblock .
*/
2017-06-01 08:34:25 +00:00
if ( ! if_info - > set_flags . filter ) {
if ( state - > if_map - > module_filter_str ) {
/* Duplicate because might use with multiple interfaces */
2021-02-01 23:56:47 +00:00
if_filter . type = if_filter_pcap ;
if_filter . data . filter_str = state - > if_map - > module_filter_str ;
wtap_block_add_if_filter_option ( int_data , OPT_IDB_FILTER , & if_filter ) ;
2017-06-01 08:34:25 +00:00
/*
* Don ' t set flag because stream is more specific than module .
*/
} else if ( state - > if_map - > capture_filter_str ) {
/* TODO: display separately? Note that we could have multiple captures
* from multiple hosts in the file */
2021-02-01 23:56:47 +00:00
if_filter . type = if_filter_pcap ;
if_filter . data . filter_str = state - > if_map - > capture_filter_str ;
wtap_block_add_if_filter_option ( int_data , OPT_IDB_FILTER , & if_filter ) ;
2017-06-01 08:34:25 +00:00
}
2016-03-11 03:44:16 +00:00
}
if ( state - > if_map - > module_fcs_len ! = - 1 & & ! if_info - > set_flags . fcs_len ) {
2016-07-14 23:01:57 +00:00
wtap_block_add_uint8_option ( int_data , OPT_IDB_FCSLEN , ( guint8 ) state - > if_map - > module_fcs_len ) ;
2016-03-11 03:44:16 +00:00
if_info - > set_flags . fcs_len = 1 ;
}
if ( state - > if_map - > module_snaplen ! = ( guint32 ) - 1 & & ! if_info - > set_flags . snaplen ) {
int_data_mand - > snap_len = pntoh32 ( tag . value ) ;
if_info - > set_flags . snaplen = 1 ;
}
state - > interface_metadata | = 1 < < if_num ;
return 1 ;
}
2021-06-18 23:22:54 +00:00
static int populate_stream_info ( erf_t * erf_priv _U_ , wtap * wth , union wtap_pseudo_header * pseudo_header , struct erf_meta_read_state * state , int * err , gchar * * err_info )
2016-03-11 03:44:16 +00:00
{
struct erf_meta_tag tag = { 0 , 0 , NULL } ;
guint32 tagtotallength ;
int interface_index = - 1 ;
2016-07-14 23:01:57 +00:00
wtap_block_t int_data = NULL ;
2016-03-11 03:44:16 +00:00
wtapng_if_descr_mandatory_t * int_data_mand = NULL ;
2021-02-01 23:56:47 +00:00
if_filter_opt_t if_filter ;
2016-03-11 03:44:16 +00:00
guint32 if_num = 0 ;
gint32 stream_num = - 1 ;
2016-04-02 11:13:23 +00:00
guint8 * tag_ptr_tmp ;
guint32 remaining_len_tmp ;
2016-03-11 03:44:16 +00:00
struct erf_if_info * if_info = NULL ;
2021-06-18 23:22:54 +00:00
if ( ! wth ) {
* err = WTAP_ERR_INTERNAL ;
* err_info = g_strdup_printf ( " erf: populate_stream_info called with wth NULL " ) ;
return - 1 ;
}
if ( ! pseudo_header ) {
* err = WTAP_ERR_INTERNAL ;
* err_info = g_strdup_printf ( " erf: populate_stream_info called with pseudo_header NULL " ) ;
return - 1 ;
}
if ( ! state ) {
* err = WTAP_ERR_INTERNAL ;
* err_info = g_strdup_printf ( " erf: populate_stream_info called with state NULL " ) ;
2016-03-11 03:44:16 +00:00
return - 1 ;
2021-06-18 23:22:54 +00:00
}
if ( ! state - > if_map ) {
* err = WTAP_ERR_INTERNAL ;
* err_info = g_strdup_printf ( " erf: populate_stream_info called with state->if_map NULL " ) ;
return - 1 ;
}
2016-03-11 03:44:16 +00:00
2016-04-02 11:13:23 +00:00
tag_ptr_tmp = state - > tag_ptr ;
remaining_len_tmp = state - > remaining_len ;
2016-03-11 03:44:16 +00:00
/*
* XXX : We ignore parent section ID because it doesn ' t represent the
* many - to - many relationship of interfaces and streams very well . The stream is
* associated with all interfaces in the record that don ' t have a stream_num
* that says otherwise .
*/
if ( state - > sectionid > 0 & & state - > sectionid ! = 0x7fff ) {
/* Section ID of stream is supposed to match stream_num. */
stream_num = state - > sectionid - 1 ;
} else {
/* First iterate tags, looking for the stream number interfaces might associate with. */
while ( ( tagtotallength = erf_meta_read_tag ( & tag , tag_ptr_tmp , remaining_len_tmp ) ) & & ! ERF_META_IS_SECTION ( tag . type ) ) {
if ( tag . type = = ERF_META_TAG_stream_num ) {
if ( tag . length > = 4 ) {
stream_num = ( gint32 ) pntoh32 ( tag . value ) ;
}
}
tag_ptr_tmp + = tagtotallength ;
remaining_len_tmp - = tagtotallength ;
}
}
/* Otherwise assume the stream applies to all interfaces in the record */
for ( if_num = 0 ; if_num < 4 ; if_num + + ) {
tag_ptr_tmp = state - > tag_ptr ;
remaining_len_tmp = state - > remaining_len ;
if_info = & state - > if_map - > interfaces [ if_num ] ;
/* Check if we should be handling this interface */
/* XXX: currently skips interfaces that are not in the record. */
if ( state - > if_map - > interface_metadata & ( 1 < < if_num )
| | ! ( state - > interface_metadata & ( 1 < < if_num ) ) ) {
continue ;
}
if ( if_info - > stream_num ! = - 1
& & if_info - > stream_num ! = stream_num ) {
continue ;
}
interface_index = if_info - > if_index ;
/* Get the wiretap interface metadata */
if ( interface_index > = 0 ) {
2016-07-14 23:01:57 +00:00
int_data = g_array_index ( wth - > interface_data , wtap_block_t , interface_index ) ;
int_data_mand = ( wtapng_if_descr_mandatory_t * ) wtap_block_get_mandatory_data ( int_data ) ;
2016-03-11 03:44:16 +00:00
}
if ( ! int_data ) {
continue ;
}
while ( ( tagtotallength = erf_meta_read_tag ( & tag , tag_ptr_tmp , remaining_len_tmp ) ) & & ! ERF_META_IS_SECTION ( tag . type ) ) {
switch ( tag . type ) {
case ERF_META_TAG_fcs_len :
if ( tag . length > = 4 ) {
/* Use the largest fcslen of matching streams */
gint8 fcs_len = ( gint8 ) pntoh32 ( tag . value ) ;
guint8 old_fcs_len = 0 ;
2016-07-14 23:01:57 +00:00
switch ( wtap_block_get_uint8_option_value ( int_data , OPT_IDB_FCSLEN , & old_fcs_len ) ) {
case WTAP_OPTTYPE_SUCCESS :
/* We already have an FCS length option; update it. */
if ( fcs_len > old_fcs_len | | ! if_info - > set_flags . fcs_len ) {
wtap_block_set_uint8_option_value ( int_data , OPT_IDB_FCSLEN , ( guint8 ) pntoh32 ( tag . value ) ) ;
if_info - > set_flags . fcs_len = 1 ;
}
break ;
case WTAP_OPTTYPE_NOT_FOUND :
/* We don't have an FCS length option; add it. */
wtap_block_add_uint8_option ( int_data , OPT_IDB_FCSLEN , ( guint8 ) pntoh32 ( tag . value ) ) ;
if_info - > set_flags . fcs_len = 1 ;
break ;
default :
/* "shouldn't happen" */
break ;
2016-03-11 03:44:16 +00:00
}
}
break ;
case ERF_META_TAG_snaplen :
if ( tag . length > = 4 ) {
/* Use the largest snaplen of matching streams */
guint32 snaplen = pntoh32 ( tag . value ) ;
if ( snaplen > int_data_mand - > snap_len | | ! if_info - > set_flags . snaplen ) {
int_data_mand - > snap_len = pntoh32 ( tag . value ) ;
if_info - > set_flags . snaplen = 1 ;
}
}
break ;
case ERF_META_TAG_filter :
/* Override only if not set */
if ( ! if_info - > set_flags . filter ) {
2021-02-01 23:56:47 +00:00
if_filter . type = if_filter_pcap ;
if_filter . data . filter_str = g_strndup ( ( gchar * ) tag . value , tag . length ) ;
wtap_block_add_if_filter_option ( int_data , OPT_IDB_FILTER , & if_filter ) ;
g_free ( if_filter . data . filter_str ) ;
2016-03-11 03:44:16 +00:00
if_info - > set_flags . filter = 1 ;
}
break ;
default :
break ;
}
tag_ptr_tmp + = tagtotallength ;
remaining_len_tmp - = tagtotallength ;
}
}
state - > tag_ptr = tag_ptr_tmp ;
state - > remaining_len = remaining_len_tmp ;
return 1 ;
}
2021-06-18 23:22:54 +00:00
static int populate_anchor_info ( erf_t * erf_priv , wtap * wth , union wtap_pseudo_header * pseudo_header , struct erf_meta_read_state * state , GPtrArray * anchor_mappings_to_update , int * err , gchar * * err_info ) {
2017-06-01 08:34:25 +00:00
struct erf_meta_tag tag = { 0 , 0 , NULL } ;
guint32 tagtotallength ;
gchar * comment_ptr = NULL ;
guint i = 0 ;
2021-06-18 23:22:54 +00:00
if ( ! wth ) {
* err = WTAP_ERR_INTERNAL ;
* err_info = g_strdup_printf ( " erf: populate_anchor_info called with wth NULL " ) ;
2017-06-01 08:34:25 +00:00
return - 1 ;
2021-06-18 23:22:54 +00:00
}
if ( ! state ) {
* err = WTAP_ERR_INTERNAL ;
* err_info = g_strdup_printf ( " erf: populate_anchor_info called with state NULL " ) ;
return - 1 ;
}
if ( ! pseudo_header ) {
* err = WTAP_ERR_INTERNAL ;
* err_info = g_strdup_printf ( " erf: populate_anchor_info called with pseudo_header NULL " ) ;
return - 1 ;
}
2017-06-01 08:34:25 +00:00
if ( ! anchor_mappings_to_update | | anchor_mappings_to_update - > len = = 0 )
return 0 ;
while ( ( tagtotallength = erf_meta_read_tag ( & tag , state - > tag_ptr , state - > remaining_len ) ) & & ! ERF_META_IS_SECTION ( tag . type ) ) {
/* XXX:Always gets the first comment tag in the section */
switch ( tag . type ) {
case ERF_META_TAG_comment :
if ( ! comment_ptr ) {
comment_ptr = g_strndup ( ( gchar * ) tag . value , tag . length ) ;
}
break ;
default :
break ;
}
state - > tag_ptr + = tagtotallength ;
state - > remaining_len - = tagtotallength ;
}
if ( comment_ptr ) {
for ( i = 0 ; i < anchor_mappings_to_update - > len ; i + + ) {
struct erf_anchor_mapping * mapping ;
struct erf_anchor_mapping * lookup_result ;
mapping = ( struct erf_anchor_mapping * ) g_ptr_array_index ( anchor_mappings_to_update , i ) ;
lookup_result = ( struct erf_anchor_mapping * ) g_hash_table_lookup ( erf_priv - > anchor_map , mapping ) ;
/* Use the most recent comment, across all anchors associated with the
* record . */
if ( lookup_result ) {
if ( lookup_result - > gen_time < state - > gen_time ) {
lookup_result - > gen_time = state - > gen_time ;
g_free ( lookup_result - > comment ) ;
lookup_result - > comment = g_strdup ( comment_ptr ) ;
}
}
else {
/* !lookup_result */
struct erf_anchor_mapping * new_mapping ;
2020-12-21 02:30:28 +00:00
new_mapping = g_new0 ( struct erf_anchor_mapping , 1 ) ;
2017-06-01 08:34:25 +00:00
new_mapping - > anchor_id = mapping - > anchor_id ;
new_mapping - > host_id = mapping - > host_id ;
new_mapping - > gen_time = state - > gen_time ;
new_mapping - > comment = g_strdup ( comment_ptr ) ;
g_hash_table_replace ( erf_priv - > anchor_map , new_mapping , new_mapping ) ;
}
}
}
g_free ( comment_ptr ) ;
return 1 ;
}
2016-03-11 03:44:16 +00:00
/* Populates the capture and interface information for display on the Capture File Properties */
2021-06-18 23:22:54 +00:00
static int populate_summary_info ( erf_t * erf_priv , wtap * wth , union wtap_pseudo_header * pseudo_header , Buffer * buf , guint32 packet_size , GPtrArray * anchor_mappings_to_update , int * err , gchar * * err_info )
2016-03-11 03:44:16 +00:00
{
2020-04-13 21:39:32 +00:00
struct erf_meta_read_state state = { 0 } ;
2016-03-11 03:44:16 +00:00
struct erf_meta_read_state * state_post = NULL ;
guint64 host_id ;
guint8 source_id ;
GList * post_list = NULL ;
GList * item = NULL ;
struct erf_meta_tag tag = { 0 , 0 , NULL } ;
guint32 tagtotallength ;
2021-06-18 23:22:54 +00:00
if ( ! wth ) {
* err = WTAP_ERR_INTERNAL ;
* err_info = g_strdup_printf ( " erf: populate_summary_info called with wth NULL " ) ;
return - 1 ;
}
if ( ! pseudo_header ) {
* err = WTAP_ERR_INTERNAL ;
* err_info = g_strdup_printf ( " erf: populate_summary_info called with pseudo_header NULL " ) ;
return - 1 ;
}
if ( ! erf_priv ) {
* err = WTAP_ERR_INTERNAL ;
* err_info = g_strdup_printf ( " erf: populate_summary_info called with erf_priv NULL " ) ;
2016-03-11 03:44:16 +00:00
return - 1 ;
2021-06-18 23:22:54 +00:00
}
2016-03-11 03:44:16 +00:00
erf_get_source_from_header ( pseudo_header , & host_id , & source_id ) ;
if ( host_id = = 0 ) {
host_id = erf_priv - > implicit_host_id ;
}
state . if_map = erf_find_interface_mapping ( erf_priv , host_id , source_id ) ;
if ( ! state . if_map ) {
state . if_map = erf_if_mapping_create ( host_id , source_id ) ;
2016-04-05 13:32:56 +00:00
/* g_hash_table_add() only exists since 2.32. */
g_hash_table_replace ( erf_priv - > if_map , state . if_map , state . if_map ) ;
2016-03-11 03:44:16 +00:00
}
2019-04-05 01:56:27 +00:00
state . tag_ptr = buf - > data ;
2016-03-11 03:44:16 +00:00
state . remaining_len = packet_size ;
/* Read until see next section tag */
while ( ( tagtotallength = erf_meta_read_tag ( & tag , state . tag_ptr , state . remaining_len ) ) ) {
/*
2017-06-01 08:34:25 +00:00
* Obtain the gen_time from the non - section at the beginning of the record
2016-03-11 03:44:16 +00:00
*/
if ( ! ERF_META_IS_SECTION ( tag . type ) ) {
2017-06-01 08:34:25 +00:00
if ( state . gen_time = = 0U
& & tag . type = = ERF_META_TAG_gen_time
) {
memcpy ( & state . gen_time , tag . value , sizeof ( state . gen_time ) ) ;
/*
* Since wireshark doesn ' t have a concept of different summary metadata
* over time , skip the record if metadata is older than what we already have .
*/
2021-06-19 22:30:21 +00:00
/* TODO: This doesn't work very well for some tags that map to
* pcapng options where the pcapng specification only allows one
* instance per block , which is the case for most options . The
* only current exxceptions are :
*
* comments ;
* IPv4 and IPv6 addresses for an interface ;
* hash values for a packet ;
* custom options .
*
* For options where only one instance is allowed per block ,
* wtap_block_add_XXX_option ( ) is currently used to add a new
* instance of an option to a block that has no instance ( it
* fails if there ' s already an instance ) , and
* wtap_block_set_XXX_optin ( ) is currently used to change the
* value of an option in a block that has one instance ( it fails
* if there isn ' t already an instance ) .
*
* For options where more than one instance is allowed per block ,
* wtap_block_add_XXX_option ( ) is used to add a new instance to
* a block , no matter how many instances it currently has , and
* wtap_block_set_nth_XXX_option ( ) is used to change the value
* of the Nth instance of an option in a block ( the block must
* * have * an Nth instance ) .
*
2017-06-01 08:34:25 +00:00
* Currently we only particularly care about updating the capture comment
* and a few counters anyway .
*/
if ( ( state . if_map - > interface_metadata & 0x03 )
& & state . gen_time < erf_priv - > host_gentime & & state . gen_time < erf_priv - > capture_gentime
& & ( ! anchor_mappings_to_update | | ! anchor_mappings_to_update - > len ) ) {
return 0 ;
}
}
/*
* Skip until we get to the next section tag ( which could be the current tag
* after an empty section or successful parsing ) .
*/
2016-03-11 03:44:16 +00:00
/* adjust offset */
state . tag_ptr + = tagtotallength ;
state . remaining_len - = tagtotallength ;
continue ;
}
/*
* We are now looking at the next section ( and would have exited the loop
* if we reached the end ) .
*/
/* Update parent section. Implicit grouping is by a change in section except Interface and Stream. */
if ( tag . type ! = state . sectiontype ) {
if ( ( tag . type = = ERF_META_SECTION_STREAM & & state . sectiontype = = ERF_META_SECTION_INTERFACE ) | |
2017-06-01 08:34:25 +00:00
( tag . type = = ERF_META_SECTION_INTERFACE & & state . sectiontype = = ERF_META_SECTION_STREAM ) ) {
2016-03-11 03:44:16 +00:00
/* do nothing */
} else {
state . parentsectiontype = state . sectiontype ;
state . parentsectionid = state . sectionid ;
}
}
/* Update with new sectiontype */
state . sectiontype = tag . type ;
if ( tag . length > = 4 ) {
state . sectionid = pntoh16 ( tag . value ) ;
} else {
state . sectionid = 0 ;
}
/* Adjust offset to that of first tag in section */
state . tag_ptr + = tagtotallength ;
state . remaining_len - = tagtotallength ;
if ( ( tagtotallength = erf_meta_read_tag ( & tag , state . tag_ptr , state . remaining_len ) ) ) {
/*
* Process parent section tag if present ( which must be the first tag in
* the section ) .
*/
if ( tag . type = = ERF_META_TAG_parent_section & & tag . length > = 4 ) {
state . parentsectiontype = pntoh16 ( tag . value ) ;
state . parentsectionid = pntoh16 ( & tag . value [ 2 ] ) ;
}
}
/* Skip empty sections (includes if above read fails) */
if ( ERF_META_IS_SECTION ( tag . type ) ) {
continue ;
}
/*
* Skip sections that don ' t apply to the general set of records
* ( extension point for per - packet / event metadata ) .
2017-06-01 08:34:25 +00:00
* Unless we need to update the anchor info
* in which case , read into it
2016-03-11 03:44:16 +00:00
*/
if ( state . sectionid & 0x8000 ) {
2017-06-01 08:34:25 +00:00
if ( state . sectiontype & ( ERF_META_SECTION_INFO ) ) {
2021-06-18 23:22:54 +00:00
/* TODO: do we care if it returns 0 or 1? */
if ( populate_anchor_info ( erf_priv , wth , pseudo_header , & state , anchor_mappings_to_update , err , err_info ) < 0 ) {
return - 1 ;
}
2017-06-01 08:34:25 +00:00
}
2016-03-11 03:44:16 +00:00
continue ;
}
/*
* Start at first tag in section , makes loop
* simpler in called functions too . Also makes iterating after failure
* much simpler .
*/
switch ( state . sectiontype ) {
case ERF_META_SECTION_CAPTURE :
case ERF_META_SECTION_HOST :
2021-06-18 23:22:54 +00:00
/* TODO: do we care if it returns 0 or 1? */
if ( populate_capture_host_info ( erf_priv , wth , pseudo_header , & state , err , err_info ) < 0 ) {
return - 1 ;
}
2016-03-11 03:44:16 +00:00
break ;
case ERF_META_SECTION_MODULE :
2021-06-18 23:22:54 +00:00
/* TODO: do we care if it returns 0 or 1? */
if ( populate_module_info ( erf_priv , wth , pseudo_header , & state , err , err_info ) < 0 ) {
return - 1 ;
}
2016-03-11 03:44:16 +00:00
break ;
case ERF_META_SECTION_INTERFACE :
2021-06-18 23:22:54 +00:00
/* TODO: do we care if it returns 0 or 1? */
if ( populate_interface_info ( erf_priv , wth , pseudo_header , & state , err , err_info ) < 0 ) {
return - 1 ;
}
2016-03-11 03:44:16 +00:00
break ;
case ERF_META_SECTION_STREAM :
/*
* XXX : Treat streams specially in case the stream information appears
* before the interface information , as we associate them to interface
* data .
*/
2021-03-23 15:41:54 +00:00
post_list = g_list_append ( post_list , g_memdup2 ( & state , sizeof ( struct erf_meta_read_state ) ) ) ;
2016-03-11 03:44:16 +00:00
break ;
case ERF_META_SECTION_SOURCE :
case ERF_META_SECTION_DNS :
default :
/* TODO: Not yet implemented */
break ;
}
}
/* Process streams last */
if ( post_list ) {
item = post_list ;
do {
state_post = ( struct erf_meta_read_state * ) item - > data ;
switch ( state_post - > sectiontype ) {
case ERF_META_SECTION_STREAM :
2021-06-18 23:22:54 +00:00
if ( populate_stream_info ( erf_priv , wth , pseudo_header , state_post , err , err_info ) < 0 ) {
g_list_foreach ( post_list , erf_free_data , NULL ) ;
g_list_free ( post_list ) ;
return - 1 ;
}
2016-03-11 03:44:16 +00:00
break ;
}
} while ( ( item = g_list_next ( item ) ) ) ;
2016-04-05 13:32:56 +00:00
/* g_list_free_full() only exists since 2.28. */
g_list_foreach ( post_list , erf_free_data , NULL ) ;
g_list_free ( post_list ) ;
2016-03-11 03:44:16 +00:00
}
/*
* Update known metadata so we only examine the first set of metadata . Need to
* do this here so can have interface and stream in same record .
*/
2017-06-01 08:34:25 +00:00
if ( state . interface_metadata ) {
state . if_map - > interface_metadata | = state . interface_metadata ;
state . if_map - > interface_gentime = state . gen_time ;
}
2016-03-11 03:44:16 +00:00
return 0 ;
}
2017-06-01 08:34:25 +00:00
static gboolean get_user_comment_string ( wtap_dumper * wdh , gchar * * user_comment_ptr ) {
wtap_block_t wtap_block ;
2021-05-25 06:23:16 +00:00
wtap_opttype_return_val ret ;
2017-06-01 08:34:25 +00:00
wtap_block = NULL ;
if ( wdh - > shb_hdrs & & ( wdh - > shb_hdrs - > len > 0 ) ) {
wtap_block = g_array_index ( wdh - > shb_hdrs , wtap_block_t , 0 ) ;
}
if ( wtap_block ! = NULL ) {
ret = wtap_block_get_nth_string_option_value ( wtap_block , OPT_COMMENT , 0 , user_comment_ptr ) ;
2021-05-25 06:23:16 +00:00
if ( ret ! = WTAP_OPTTYPE_SUCCESS ) {
2017-06-01 08:34:25 +00:00
return FALSE ;
}
}
return TRUE ;
}
static gboolean erf_dump_priv_compare_capture_comment ( wtap_dumper * wdh _U_ , erf_dump_t * dump_priv , const union wtap_pseudo_header * pseudo_header , const guint8 * pd ) {
2020-04-13 21:39:32 +00:00
struct erf_meta_read_state state = { 0 } ;
2017-06-01 08:34:25 +00:00
struct erf_meta_tag tag = { 0 , 0 , NULL } ;
guint32 tagtotallength ;
gboolean found_capture_section = FALSE ;
gboolean found_normal_section = FALSE ;
gchar * comment_ptr = NULL ;
state . remaining_len = pseudo_header - > erf . phdr . wlen ;
memcpy ( & ( state . tag_ptr ) , & pd , sizeof ( pd ) ) ;
while ( ( tagtotallength = erf_meta_read_tag ( & tag , state . tag_ptr , state . remaining_len ) ) ) {
if ( ERF_META_IS_SECTION ( tag . type ) ) {
state . sectiontype = tag . type ;
if ( tag . length > = 4 ) {
state . sectionid = pntoh16 ( tag . value ) ;
} else {
state . sectionid = 0 ;
}
/* Skip sections that don't apply to the general set of records */
if ( ! ( state . sectionid & 0x8000 ) ) {
found_normal_section = TRUE ;
if ( tag . type = = ERF_META_SECTION_CAPTURE ) {
/* Found the Capture Section */
found_capture_section = TRUE ;
}
}
} else {
if ( state . sectiontype = = ERF_META_SECTION_CAPTURE & & ! ( state . sectionid & 0x8000 ) ) {
if ( tag . type = = ERF_META_TAG_comment ) {
/* XXX: Only compare the first comment tag */
if ( ! comment_ptr ) {
comment_ptr = g_strndup ( ( char * ) tag . value , tag . length ) ;
}
break ;
}
}
}
/* Read until we have the Capture section */
state . tag_ptr + = tagtotallength ;
state . remaining_len - = tagtotallength ;
}
if ( found_capture_section & & ( comment_ptr | | dump_priv - > user_comment_ptr ) ) {
if ( g_strcmp0 ( comment_ptr , dump_priv - > user_comment_ptr )
& & ! ( dump_priv - > user_comment_ptr = = NULL & & comment_ptr & & comment_ptr [ 0 ] = = ' \0 ' ) ) {
/* Also treat "" in ERF as equivalent to NULL as that is how we clear the comment on write. */
/* Comments are different, we should write extra metadata record at the end of the list */
dump_priv - > write_next_extra_meta = TRUE ;
g_free ( comment_ptr ) ;
return TRUE ;
} else {
/* We have a capture comment but there is no change, we don't
* need to insert the ' changed ' comment . This most likely happened
* because we were looking at list of periodic records and got up to the
* one where the comment was last set . */
dump_priv - > write_next_extra_meta = FALSE ;
}
/* Otherwise no effect on whether we need to write extra metadata record */
}
/* We didn't find a capture section (e.g. looking at a comment Anchor
* record ) , or the comment hadn ' t changed . */
g_free ( comment_ptr ) ;
/* Return whether we found any non-local metadata (i.e. whether the record has
* metadata that is more than just packet ' comments ' ) */
return found_normal_section ;
}
2016-03-11 03:44:16 +00:00
static void erf_close ( wtap * wth )
{
erf_t * erf_priv = ( erf_t * ) wth - > priv ;
erf_priv_free ( erf_priv ) ;
/* XXX: Prevent double free by wtap_close() */
wth - > priv = NULL ;
}
wiretap: have file handlers advertise blocks and options supported.
Instead of a "supports name resolution" Boolean and bitflags for types of
comments supported, provide a list of block types that the file
type/subtype supports, with each block type having a list of options
supported. Indicate whether "supported" means "one instance" or
"multiple instances".
"Supports" doesn't just mean "can be written", it also means "could be
read".
Rename WTAP_BLOCK_IF_DESCRIPTION to WTAP_BLOCK_IF_ID_AND_INFO, to
indicate that it provides, in addition to information about the
interface, an ID (implicitly, in pcapng files, by its ordinal number)
that is associated with every packet in the file. Emphasize that in
comments - just because your capture file format can list the interfaces
on which a capture was done, that doesn't mean it supports this; it
doesn't do so if the file doesn't indicate, for every packet, on which
of those interfaces it was captured (I'm looking at *you*, Microsoft
Network Monitor...).
Use APIs to query that information to do what the "does this file
type/subtype support name resolution information", "does this file
type/subtype support all of these comment types", and "does this file
type/subtype support - and require - interface IDs" APIs did.
Provide backwards compatibility for Lua.
This allows us to eliminate the WTAP_FILE_TYPE_SUBTYPE_ values for IBM's
iptrace; do so.
2021-02-21 22:18:04 +00:00
static const struct supported_option_type section_block_options_supported [ ] = {
{ OPT_COMMENT , ONE_OPTION_SUPPORTED } , /* XXX - multiple? */
{ OPT_SHB_USERAPPL , ONE_OPTION_SUPPORTED }
} ;
static const struct supported_option_type interface_block_options_supported [ ] = {
{ OPT_COMMENT , ONE_OPTION_SUPPORTED } , /* XXX - multiple? */
{ OPT_IDB_NAME , ONE_OPTION_SUPPORTED } ,
2021-07-14 06:48:19 +00:00
{ OPT_IDB_DESCRIPTION , ONE_OPTION_SUPPORTED } ,
wiretap: have file handlers advertise blocks and options supported.
Instead of a "supports name resolution" Boolean and bitflags for types of
comments supported, provide a list of block types that the file
type/subtype supports, with each block type having a list of options
supported. Indicate whether "supported" means "one instance" or
"multiple instances".
"Supports" doesn't just mean "can be written", it also means "could be
read".
Rename WTAP_BLOCK_IF_DESCRIPTION to WTAP_BLOCK_IF_ID_AND_INFO, to
indicate that it provides, in addition to information about the
interface, an ID (implicitly, in pcapng files, by its ordinal number)
that is associated with every packet in the file. Emphasize that in
comments - just because your capture file format can list the interfaces
on which a capture was done, that doesn't mean it supports this; it
doesn't do so if the file doesn't indicate, for every packet, on which
of those interfaces it was captured (I'm looking at *you*, Microsoft
Network Monitor...).
Use APIs to query that information to do what the "does this file
type/subtype support name resolution information", "does this file
type/subtype support all of these comment types", and "does this file
type/subtype support - and require - interface IDs" APIs did.
Provide backwards compatibility for Lua.
This allows us to eliminate the WTAP_FILE_TYPE_SUBTYPE_ values for IBM's
iptrace; do so.
2021-02-21 22:18:04 +00:00
{ OPT_IDB_OS , ONE_OPTION_SUPPORTED } ,
{ OPT_IDB_TSOFFSET , ONE_OPTION_SUPPORTED } ,
{ OPT_IDB_SPEED , ONE_OPTION_SUPPORTED } ,
{ OPT_IDB_IP4ADDR , ONE_OPTION_SUPPORTED } , /* XXX - multiple? */
{ OPT_IDB_IP6ADDR , ONE_OPTION_SUPPORTED } , /* XXX - multiple? */
{ OPT_IDB_FILTER , ONE_OPTION_SUPPORTED } ,
{ OPT_IDB_FCSLEN , ONE_OPTION_SUPPORTED }
} ;
static const struct supported_option_type packet_block_options_supported [ ] = {
{ OPT_COMMENT , ONE_OPTION_SUPPORTED } /* XXX - multiple? */
} ;
static const struct supported_block_type erf_blocks_supported [ ] = {
/*
* Per - file comments and application supported ; section blocks
* are used for that .
* ERF files have only one section . ( XXX - true ? )
*/
{ WTAP_BLOCK_SECTION , ONE_BLOCK_SUPPORTED , OPTION_TYPES_SUPPORTED ( section_block_options_supported ) } ,
/*
* ERF supports multiple interfaces , with information , and
* supports associating packets with interfaces . Interface
* description blocks are used for that .
*/
{ WTAP_BLOCK_IF_ID_AND_INFO , MULTIPLE_BLOCKS_SUPPORTED , OPTION_TYPES_SUPPORTED ( interface_block_options_supported ) } ,
/*
* Name resolution is supported , but we don ' t support comments .
*/
{ WTAP_BLOCK_NAME_RESOLUTION , ONE_BLOCK_SUPPORTED , NO_OPTIONS_SUPPORTED } ,
/*
* ERF is a capture format , so it obviously supports packets .
*/
{ WTAP_BLOCK_PACKET , MULTIPLE_BLOCKS_SUPPORTED , OPTION_TYPES_SUPPORTED ( packet_block_options_supported ) }
} ;
2021-02-19 22:46:42 +00:00
static const struct file_type_subtype_info erf_info = {
" Endace ERF capture " , " erf " , " erf " , NULL ,
wiretap: have file handlers advertise blocks and options supported.
Instead of a "supports name resolution" Boolean and bitflags for types of
comments supported, provide a list of block types that the file
type/subtype supports, with each block type having a list of options
supported. Indicate whether "supported" means "one instance" or
"multiple instances".
"Supports" doesn't just mean "can be written", it also means "could be
read".
Rename WTAP_BLOCK_IF_DESCRIPTION to WTAP_BLOCK_IF_ID_AND_INFO, to
indicate that it provides, in addition to information about the
interface, an ID (implicitly, in pcapng files, by its ordinal number)
that is associated with every packet in the file. Emphasize that in
comments - just because your capture file format can list the interfaces
on which a capture was done, that doesn't mean it supports this; it
doesn't do so if the file doesn't indicate, for every packet, on which
of those interfaces it was captured (I'm looking at *you*, Microsoft
Network Monitor...).
Use APIs to query that information to do what the "does this file
type/subtype support name resolution information", "does this file
type/subtype support all of these comment types", and "does this file
type/subtype support - and require - interface IDs" APIs did.
Provide backwards compatibility for Lua.
This allows us to eliminate the WTAP_FILE_TYPE_SUBTYPE_ values for IBM's
iptrace; do so.
2021-02-21 22:18:04 +00:00
FALSE , BLOCKS_SUPPORTED ( erf_blocks_supported ) ,
2021-02-19 22:46:42 +00:00
erf_dump_can_write_encap , erf_dump_open , NULL
} ;
void register_erf ( void )
{
2021-02-24 03:10:35 +00:00
erf_file_type_subtype = wtap_register_file_type_subtype ( & erf_info ) ;
2021-02-19 22:46:42 +00:00
/*
* Register name for backwards compatibility with the
* wtap_filetypes table in Lua .
*/
wtap_register_backwards_compatibility_lua_name ( " ERF " , erf_file_type_subtype ) ;
}
2015-01-02 00:45:22 +00:00
/*
2019-07-26 18:43:17 +00:00
* Editor modelines - https : //www.wireshark.org/tools/modelines.html
2015-01-02 00:45:22 +00:00
*
* Local Variables :
* c - basic - offset : 2
* tab - width : 8
* indent - tabs - mode : nil
* End :
*
* vi : set shiftwidth = 2 tabstop = 8 expandtab :
* : indentSize = 2 : tabSize = 8 : noTabs = true :
*/