diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 20:34:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 20:34:10 +0000 |
commit | e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc (patch) | |
tree | 68cb5ef9081156392f1dd62a00c6ccc1451b93df /plugins/epan/mate | |
parent | Initial commit. (diff) | |
download | wireshark-e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc.tar.xz wireshark-e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc.zip |
Adding upstream version 4.2.2.upstream/4.2.2
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'plugins/epan/mate')
24 files changed, 5803 insertions, 0 deletions
diff --git a/plugins/epan/mate/.editorconfig b/plugins/epan/mate/.editorconfig new file mode 100644 index 00000000..2ee8bf0b --- /dev/null +++ b/plugins/epan/mate/.editorconfig @@ -0,0 +1,3 @@ +[mate_grammar.lemon] +indent_style = tab +indent_size = tab diff --git a/plugins/epan/mate/AUTHORS b/plugins/epan/mate/AUTHORS new file mode 100644 index 00000000..e37df0dd --- /dev/null +++ b/plugins/epan/mate/AUTHORS @@ -0,0 +1,3 @@ +Author: +Luis E. Garcia Ontanon <luis.ontanon [AT] gmail.com> + diff --git a/plugins/epan/mate/CMakeLists.txt b/plugins/epan/mate/CMakeLists.txt new file mode 100644 index 00000000..62b6c090 --- /dev/null +++ b/plugins/epan/mate/CMakeLists.txt @@ -0,0 +1,85 @@ +# CMakeLists.txt +# +# Wireshark - Network traffic analyzer +# By Gerald Combs <gerald@wireshark.org> +# Copyright 1998 Gerald Combs +# +# SPDX-License-Identifier: GPL-2.0-or-later +# + +include(WiresharkPlugin) + +# Plugin name and version info (major minor micro extra) +set_module_info(mate 1 0 1 0) + +set(DISSECTOR_SRC + packet-mate.c +) + +set(DISSECTOR_SUPPORT_SRC + mate_setup.c + mate_runtime.c + mate_util.c +) + +add_lemon_files(LEMON_FILES GENERATED_FILES + mate_grammar.lemon +) +add_lex_files(LEX_FILES GENERATED_FILES + mate_parser.l +) + +set(PLUGIN_FILES + plugin.c + ${DISSECTOR_SRC} + ${DISSECTOR_SUPPORT_SRC} + ${GENERATED_FILES} +) + +set_source_files_properties( + ${DISSECTOR_SRC} + ${DISSECTOR_SUPPORT_SRC} + PROPERTIES + COMPILE_FLAGS "${WERROR_COMMON_FLAGS}" +) + +register_plugin_files(plugin.c + plugin + ${DISSECTOR_SRC} + ${DISSECTOR_SUPPORT_SRC} +) + +add_wireshark_plugin_library(mate epan) + +target_link_libraries(mate epan) + +install_plugin(mate epan) + +file(GLOB DISSECTOR_HEADERS RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "*.h") +CHECKAPI( + NAME + mate + SWITCHES + --group dissectors-prohibited + --group dissectors-restricted + SOURCES + ${DISSECTOR_SRC} + ${DISSECTOR_SUPPORT_SRC} + ${DISSECTOR_HEADERS} +# LEX files commented out due to use of malloc, free etc. +# ${LEX_FILES} + ${LEMON_FILES} +) + +# +# Editor modelines - https://www.wireshark.org/tools/modelines.html +# +# Local variables: +# c-basic-offset: 8 +# tab-width: 8 +# indent-tabs-mode: t +# End: +# +# vi: set shiftwidth=8 tabstop=8 noexpandtab: +# :indentSize=8:tabSize=8:noTabs=false: +# diff --git a/plugins/epan/mate/examples/call.mate b/plugins/epan/mate/examples/call.mate new file mode 100644 index 00000000..0dbbb45e --- /dev/null +++ b/plugins/epan/mate/examples/call.mate @@ -0,0 +1,34 @@ +# call.mate + +Action=Settings; DiscardPduData=TRUE; ShowGopTimes=FALSE; ShowPduTree=FALSE; + +Action=PduDef; Name=q931_pdu; Proto=q931; Stop=TRUE; Transport=tcp/ip; addr=ip.addr; call_ref=q931.call_ref; q931_msg=q931.message_type; +Action=PduDef; Name=ras_pdu; Proto=h225.RasMessage; Transport=udp/ip; addr=ip.addr; ras_sn=h225.requestSeqNum; ras_msg=h225.RasMessage; +Action=PduDef; Name=isup_pdu; Proto=isup; Transport=mtp3; m3pc=mtp3.dpc; m3pc=mtp3.opc; cic=isup.cic; isup_msg=isup.message_type; + +Action=PduExtra; For=q931_pdu; guid=h225.guid; calling=q931.calling_party_number.digits; q931_cause=q931.cause_value; +Action=PduExtra; For=isup_pdu; calling=isup.calling; isup_cause=isup.cause_indicator; +Action=PduExtra; For=ras_pdu; guid=h225.guid; + +Action=GopDef; Name=q931_leg; On=q931_pdu; addr; addr; call_ref; +Action=GopStart; For=q931_leg; q931_msg=5; +Action=GopStop; For=q931_leg; q931_msg=90; +Action=GopExtra; For=q931_leg; calling; q931_cause; guid; + +Action=GopDef; Name=isup_leg; On=isup_pdu; ShowPduTree=TRUE; ShowGopTimes=TRUE; m3pc; m3pc; cic; +Action=GopStart; For=isup_leg; isup_msg=1; +Action=GopStop; For=isup_leg; isup_msg=16; +Action=GopExtra; For=isup_leg; calling; isup_cause; + +Action=GopDef; Name=ras_leg; On=ras_pdu; addr; addr; ras_sn; +Action=GopStart; For=ras_leg; ras_msg|0|3|6|9|12|15|18|21|26|30; +Action=GopStop; For=ras_leg; ras_msg|1|2|4|5|7|8|10|11|13|14|16|17|19|20|22|24|27|28|29|31; +Action=GopExtra; For=ras_leg; guid; + +Action=GogDef; Name=call; GogExpiration=0.75; +Action=GogKey; For=call; On=isup_leg; calling; +Action=GogKey; For=call; On=q931_leg; calling; +Action=GogKey; For=call; On=q931_leg; guid; +Action=GogKey; For=call; On=ras_leg; guid; +Action=GogExtra; For=call; isup_cause; +Action=GogExtra; For=call; q931_cause; diff --git a/plugins/epan/mate/examples/mms.mate b/plugins/epan/mate/examples/mms.mate new file mode 100644 index 00000000..7554b119 --- /dev/null +++ b/plugins/epan/mate/examples/mms.mate @@ -0,0 +1,40 @@ +# mms.mate + +# MMSE over HTTP +Action=PduDef; Name=mmse_over_http_pdu; Proto=http; Transport=tcp/ip; Payload=mmse; addr=ip.addr; port=tcp.port; http_rq=http.request; content=http.content_type; +Action=PduExtra; For=mmse_over_http_pdu; resp=http.response.code; method=http.request.method; host=http.host; content=http.content_type; +Action=PduExtra; For=mmse_over_http_pdu; method=http.request.method; host=http.host; +Action=PduExtra; For=mmse_over_http_pdu; trx=mmse.transaction_id; msg_type=mmse.message_type; notify_status=mmse.status; send_status=mmse.response_status; + +Action=Transform; Name=rm_client_from_http_resp1; Mode=Insert; Match=Strict; http_rq; +Action=Transform; Name=rm_client_from_http_resp1; Mode=Insert; Match=Every; addr; .not_rq; + +Action=Transform; Name=rm_client_from_http_resp2; Mode=Replace; Match=Strict; not_rq; ue; + +Action=PduTransform; For=mmse_over_http_pdu; Name=rm_client_from_http_resp1; +Action=PduTransform; For=mmse_over_http_pdu; Name=rm_client_from_http_resp2; + +Action=GopDef; Name=mmse_over_http; On=mmse_over_http_pdu; addr; addr; port; port; +Action=GopStart; For=mmse_over_http; http_rq; +Action=GopStop; For=mmse_over_http; http_rs; + +Action=GopExtra; For=mmse_over_http; host; ue; resp; notify_status; send_status; trx; + +# MMSE over WSP +Action=PduDef; Name=mmse_over_wsp_pdu; Proto=wsp; Payload=mmse; Transport=ip; trx=mmse.transaction_id; msg_type=mmse.message_type; notify_status=mmse.status; send_status=mmse.response_status; + +Action=Transform; Name=mms_start; Match=Loose; .mms_start; + +Action=PduTransform; Name=mms_start; For=mmse_over_wsp_pdu; + +Action=GopDef; Name=mmse_over_wsp; On=mmse_over_wsp_pdu; trx; +Action=GopStart; For=mmse_over_wsp; mms_start; +Action=GopStop; For=mmse_over_wsp; never; + +Action=GopExtra; For=mmse_over_wsp; ue; notify_status; send_status; + +# the MMS GoG +Action=GogDef; Name=mms; GogExpiration=60.0; +Action=GogKey; For=mms; On=mmse_over_http; trx; +Action=GogKey; For=mms; On=mmse_over_wsp; trx; +Action=GogExtra; For=mms; ue; notify_status; send_status; resp; host; trx; diff --git a/plugins/epan/mate/examples/pasv_ftp.mate b/plugins/epan/mate/examples/pasv_ftp.mate new file mode 100644 index 00000000..24ef7ab4 --- /dev/null +++ b/plugins/epan/mate/examples/pasv_ftp.mate @@ -0,0 +1,18 @@ +# pasv_ftp.mate + +Action=PduDef; Name=ftp_pdu; Proto=ftp; Transport=tcp/ip; Stop=TRUE; ftp_addr=ip.addr; ftp_port=tcp.port; ftp_resp=ftp.response.code; ftp_req=ftp.request.command; server_addr=ftp.passive.ip; server_port=ftp.passive.port; + +Action=PduDef; Name=ftp_data_pdu; Proto=ftp-data; Transport=tcp/ip; server_addr=ip.src; server_port=tcp.srcport; + +Action=GopDef; Name=ftp_data; On=ftp_data_pdu; server_addr; server_port; +Action=GopStart; For=ftp_data; server_addr; + +Action=GopDef; Name=ftp_ctl; On=ftp_pdu; ftp_addr; ftp_addr; ftp_port; ftp_port; +Action=GopStart; For=ftp_ctl; ftp_resp=220; +Action=GopStop; For=ftp_ctl; ftp_resp=221; +Action=GopExtra; For=ftp_ctl; server_addr; server_port; + +Action=GogDef; Name=ftp_ses; +Action=GogKey; For=ftp_ses; On=ftp_ctl; ftp_addr; ftp_addr; ftp_port; ftp_port; +Action=GogKey; For=ftp_ses; On=ftp_data; server_addr; server_port; + diff --git a/plugins/epan/mate/examples/tcp.mate b/plugins/epan/mate/examples/tcp.mate new file mode 100644 index 00000000..2abe3e88 --- /dev/null +++ b/plugins/epan/mate/examples/tcp.mate @@ -0,0 +1,7 @@ +# tcp.mate + + Action=PduDef; Name=tcp_pdu; Proto=tcp; Transport=ip; addr=ip.addr; port=tcp.port; tcp_start=tcp.flags.syn; tcp_stop=tcp.flags.fin; tcp_stop=tcp.flags.reset; + Action=GopDef; Name=tcp_session; On=tcp_pdu; addr; addr; port; port; + Action=GopStart; For=tcp_session; tcp_start=1; + Action=GopStop; For=tcp_session; tcp_stop=1; + diff --git a/plugins/epan/mate/examples/web.mate b/plugins/epan/mate/examples/web.mate new file mode 100644 index 00000000..fd00c651 --- /dev/null +++ b/plugins/epan/mate/examples/web.mate @@ -0,0 +1,27 @@ +# web.mate + +Action=PduDef; Name=dns_pdu; Proto=dns; Transport=ip; addr=ip.addr; dns_resp=dns.flags.response; host=dns.qry.name; client_addr=ip.src; dns_id=dns.id; +Action=PduDef; Name=http_pdu; Proto=http; Transport=tcp/ip; addr=ip.addr; port=tcp.port; http_rq=http.request.method; http_rs=http.response; host=http.host; client_addr=ip.src; + +Action=GopDef; Name=dns_req; On=dns_pdu; addr; addr; dns_id; +Action=GopStart; For=dns_req; dns_resp=0; +Action=GopStop; For=dns_req; dns_resp=1; + +Action=GopDef; Name=http_req; On=http_pdu; addr; addr; port; port; +Action=GopStart; For=http_req; http_rq; +Action=GopStop; For=http_req; http_rs; + +Action=Transform; Name=rm_client_from_dns_resp; Mode=Replace; Match=Every; dns_resp=1; client_addr; .dns_resp=1; +Action=PduTransform; For=dns_pdu; Name=rm_client_from_dns_resp; + +Action=Transform; Name=rm_client_from_http_resp; Mode=Replace; Match=Every; http_rs; client_addr; .http_rs=; +Action=PduTransform; For=http_pdu; Name=rm_client_from_http_resp; + +Action=GopExtra; For=http_req; host; client_addr; +Action=GopExtra; For=dns_req; host; client_addr; + +Action=GogDef; Name=http_use; GogExpiration=0.75; +Action=GogKey; For=http_use; On=http_req; host; client_addr; +Action=GogKey; For=http_use; On=dns_req; host;client_addr; + +Action=GogExtra; For=http_use; host; client_addr; diff --git a/plugins/epan/mate/mate.h b/plugins/epan/mate/mate.h new file mode 100644 index 00000000..79f46af8 --- /dev/null +++ b/plugins/epan/mate/mate.h @@ -0,0 +1,373 @@ +/* mate.h + * MATE -- Meta Analysis and Tracing Engine + * + * Copyright 2004, Luis E. Garcia Ontanon <luis@ontanon.org> + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1998 Gerald Combs + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + + +#ifndef __MATE_H_ +#define __MATE_H_ + +#define WS_LOG_DOMAIN "MATE" +#include <wireshark.h> + +#include <gmodule.h> + +#include <stdio.h> +#include <string.h> + +#include <wsutil/report_message.h> +#include <wsutil/wslog.h> + +#include <epan/packet.h> +#include <epan/exceptions.h> +#include <epan/strutil.h> +#include <epan/prefs.h> +#include <epan/proto.h> +#include <epan/epan_dissect.h> +#include <wsutil/filesystem.h> + +#include "mate_util.h" + +/* defaults */ + +#define DEFAULT_GOG_EXPIRATION 2.0 + +#ifdef _WIN32 +#define DIR_SEP '\\' +#else +#define DIR_SEP '/' +#endif + +#define DEFAULT_MATE_LIB_PATH "matelib" + +#define MATE_ITEM_ID_SIZE 24 + +#define VALUE_TOO ((void*)1) + +#define MateConfigError 65535 + +typedef enum _gop_tree_mode_t { + GOP_NULL_TREE, + GOP_BASIC_TREE, + GOP_FULL_TREE +} gop_tree_mode_t; + +typedef enum _gop_pdu_tree { + GOP_NO_TREE, + GOP_PDU_TREE, + GOP_FRAME_TREE, + GOP_BASIC_PDU_TREE +} gop_pdu_tree_t; + +typedef enum _accept_mode_t { + ACCEPT_MODE, + REJECT_MODE +} accept_mode_t; + + +typedef struct _mate_cfg_pdu { + gchar* name; + guint last_id; /* keeps the last id given to an item of this kind */ + + GHashTable* items; /* all the items of this type */ + GPtrArray* transforms; /* transformations to be applied */ + + int hfid; + + int hfid_proto; + int hfid_pdu_rel_time; + int hfid_pdu_time_in_gop; + + GHashTable* my_hfids; /* for creating register info */ + + gint ett; + gint ett_attr; + + GHashTable* hfids_attr; /* k=hfid v=avp_name */ + + gboolean discard; + gboolean last_extracted; + gboolean drop_unassigned; + + GPtrArray* transport_ranges; /* hfids of candidate transport ranges from which to extract attributes */ + GPtrArray* payload_ranges; /* hfids of candidate payload ranges from which to extract attributes */ + + avpl_match_mode criterium_match_mode; + accept_mode_t criterium_accept_mode; + AVPL* criterium; +} mate_cfg_pdu; + + +typedef struct _mate_cfg_gop { + gchar* name; + guint last_id; /* keeps the last id given to an item of this kind */ + GHashTable* items; /* all the items of this type */ + + GPtrArray* transforms; /* transformations to be applied */ + gchar* on_pdu; + + AVPL* key; /* key candidate avpl */ + AVPL* start; /* start candidate avpl */ + AVPL* stop; /* stop candidate avpl */ + AVPL* extra; /* attributes to be added */ + + float expiration; + float idle_timeout; + float lifetime; + + gboolean drop_unassigned; + gop_pdu_tree_t pdu_tree_mode; + gboolean show_times; + + GHashTable* my_hfids; /* for creating register info */ + int hfid; + int hfid_start_time; + int hfid_stop_time; + int hfid_last_time; + int hfid_gop_pdu; + int hfid_gop_num_pdus; + + gint ett; + gint ett_attr; + gint ett_times; + gint ett_children; + + GHashTable* gop_index; + GHashTable* gog_index; +} mate_cfg_gop; + + +typedef struct _mate_cfg_gog { + gchar* name; + + GHashTable* items; /* all the items of this type */ + guint last_id; /* keeps the last id given to an item of this kind */ + + GPtrArray* transforms; /* transformations to be applied */ + + LoAL* keys; + AVPL* extra; /* attributes to be added */ + + float expiration; + gop_tree_mode_t gop_tree_mode; + gboolean show_times; + + GHashTable* my_hfids; /* for creating register info */ + int hfid; + int hfid_gog_num_of_gops; + int hfid_gog_gop; + int hfid_gog_gopstart; + int hfid_gog_gopstop; + int hfid_start_time; + int hfid_stop_time; + int hfid_last_time; + gint ett; + gint ett_attr; + gint ett_times; + gint ett_children; + gint ett_gog_gop; +} mate_cfg_gog; + +typedef struct _mate_config { + gchar* mate_config_file; /* name of the config file */ + + int hfid_mate; + + GArray *wanted_hfids; /* hfids of protocols and fields MATE needs */ + guint num_fields_wanted; /* number of fields MATE will look at */ + + FILE* dbg_facility; /* where to dump dbgprint output ws_message if null */ + + gchar* mate_lib_path; /* where to look for "Include" files first */ + + GHashTable* pducfgs; /* k=pducfg->name v=pducfg */ + GHashTable* gopcfgs; /* k=gopcfg->name v=gopcfg */ + GHashTable* gogcfgs; /* k=gogcfg->name v=gogcfg */ + GHashTable* transfs; /* k=transform->name v=transform */ + + GPtrArray* pducfglist; /* pducfgs in order of "execution" */ + GHashTable* gops_by_pduname; /* k=pducfg->name v=gopcfg */ + GHashTable* gogs_by_gopname; /* k=gopname v=loal where avpl->name == matchedgop->name */ + + GArray* hfrs; + gint ett_root; + GArray* ett; + + /* defaults */ + struct _mate_cfg_defaults { + struct _pdu_defaults { + avpl_match_mode match_mode; + avpl_replace_mode replace_mode; + gboolean last_extracted; + + gboolean drop_unassigned; + gboolean discard; + } pdu; + + struct _gop_defaults { + float expiration; + float idle_timeout; + float lifetime; + + gop_pdu_tree_t pdu_tree_mode; + gboolean show_times; + gboolean drop_unassigned; + + } gop; + + struct _gog_defaults { + float expiration; + gboolean show_times; + gop_tree_mode_t gop_tree_mode; + } gog; + } defaults; + + /* what to dbgprint */ + int dbg_lvl; + int dbg_pdu_lvl; + int dbg_gop_lvl; + int dbg_gog_lvl; + + GPtrArray* config_stack; + GString* config_error; + +} mate_config; + + +typedef struct _mate_config_frame { + gchar* filename; + guint linenum; +} mate_config_frame; + + +typedef struct _mate_runtime_data { + guint current_items; /* a count of items */ + float now; + guint highest_analyzed_frame; + + GHashTable* frames; /* k=frame.num v=pdus */ + +} mate_runtime_data; + +typedef struct _mate_pdu mate_pdu; +typedef struct _mate_gop mate_gop; +typedef struct _mate_gog mate_gog; + +/* these are used to contain information regarding pdus, gops and gogs */ +struct _mate_pdu { + guint32 id; /* 1:1 -> saving a g_malloc */ + mate_cfg_pdu* cfg; /* the type of this item */ + + AVPL* avpl; + + guint32 frame; /* wich frame I belog to? */ + mate_pdu* next_in_frame; /* points to the next pdu in this frame */ + float rel_time; /* time since start of capture */ + + mate_gop* gop; /* the gop the pdu belongs to (if any) */ + mate_pdu* next; /* next in gop */ + float time_in_gop; /* time since gop start */ + + gboolean first; /* is this the first pdu in this frame? */ + gboolean is_start; /* this is the start pdu for this gop */ + gboolean is_stop; /* this is the stop pdu for this gop */ + gboolean after_release; /* this pdu comes after the stop */ + +}; + + +struct _mate_gop { + guint32 id; + mate_cfg_gop* cfg; + + gchar* gop_key; + AVPL* avpl; /* the attributes of the pdu/gop/gog */ + guint last_n; + + mate_gog* gog; /* the gog of a gop */ + mate_gop* next; /* next in gog; */ + + float expiration; /* when will it expire after release (all gops releases if gog)? */ + float idle_expiration; /* when will it expire if no new pdus are assigned to it */ + float time_to_die; + float time_to_timeout; + + float start_time; /* time of start */ + float release_time; /* when this gop/gog was released */ + float last_time; /* the rel_time at which the last pdu has been added (to gop or gog's gop) */ + + + int num_of_pdus; /* how many gops a gog has? */ + int num_of_after_release_pdus; /* how many pdus have arrived since it's been released */ + mate_pdu* pdus; /* pdus that belong to a gop (NULL in gog) */ + mate_pdu* last_pdu; /* last pdu in pdu's list */ + + gboolean released; /* has this gop been released? */ +}; + + +struct _mate_gog { + guint32 id; + mate_cfg_gog* cfg; + + AVPL* avpl; /* the attributes of the pdu/gop/gog */ + guint last_n; /* the number of attributes the avpl had the last time we checked */ + + gboolean released; /* has this gop been released? */ + + float expiration; /* when will it expire after release (all gops releases if gog)? */ + float idle_expiration; /* when will it expire if no new pdus are assigned to it */ + + /* on gop and gog: */ + float start_time; /* time of start */ + float release_time; /* when this gog was released */ + float last_time; /* the rel_time at which the last pdu has been added */ + + mate_gop* gops; /* gops that belong to a gog (NULL in gop) */ + mate_gop* last_gop; /* last gop in gop's list */ + + int num_of_gops; /* how many gops a gog has? */ + int num_of_counting_gops; /* how many of them count for gog release */ + int num_of_released_gops; /* how many of them have already been released */ + GPtrArray* gog_keys; /* the keys under which this gog is stored in the gogs hash */ +}; + +typedef union _mate_max_size { + mate_pdu pdu; + mate_gop gop; + mate_gog gog; +} mate_max_size; + +/* from mate_runtime.c */ +extern void initialize_mate_runtime(mate_config* mc); +extern mate_pdu* mate_get_pdus(guint32 framenum); +extern void mate_analyze_frame(mate_config *mc, packet_info *pinfo, proto_tree* tree); + +/* from mate_setup.c */ +extern mate_config* mate_make_config(const gchar* filename, int mate_hfid); + +extern mate_cfg_pdu* new_pducfg(mate_config* mc, gchar* name); +extern mate_cfg_gop* new_gopcfg(mate_config* mc, gchar* name); +extern mate_cfg_gog* new_gogcfg(mate_config* mc, gchar* name); + +extern gboolean add_hfid(mate_config* mc, header_field_info* hfi, gchar* as, GHashTable* where); +extern gchar* add_ranges(gchar* range, GPtrArray* range_ptr_arr); + + +/* from mate_parser.l */ +extern gboolean mate_load_config(const gchar* filename, mate_config* mc); + +/* Constructor/Destructor prototypes for Lemon Parser */ +#define YYMALLOCARGTYPE gsize +void *MateParserAlloc(void* (*)(YYMALLOCARGTYPE)); +void MateParserFree(void*, void (*)(void *)); +void MateParser(void*, int, gchar*, mate_config*); + +#endif diff --git a/plugins/epan/mate/mate_grammar.lemon b/plugins/epan/mate/mate_grammar.lemon new file mode 100644 index 00000000..57f291fe --- /dev/null +++ b/plugins/epan/mate/mate_grammar.lemon @@ -0,0 +1,729 @@ +%include { + +/* mate_grammar.lemon + * MATE's configuration language grammar + * + * Copyright 2005, Luis E. Garcia Ontanon <luis@ontanon.org> + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1998 Gerald Combs + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +/* + * XXX - there's a Lemon bug where this grammar produces a parser that + * fails assertions; to work around it, we disable assert() failures. + */ +#ifndef NDEBUG +#define NDEBUG +#endif +#include "config.h" + +#include <errno.h> + +#include "mate.h" +#include "mate_grammar.h" +#include <wsutil/file_util.h> +#include <wsutil/str_util.h> + +#define DUMMY void* + +typedef struct _extraction { + gchar* as; + header_field_info* hfi; + struct _extraction* next; + struct _extraction* last; +} extraction_t; + +typedef struct _pdu_criteria_t { + AVPL* criterium_avpl; + avpl_match_mode criterium_match_mode; + accept_mode_t criterium_accept_mode; +} pdu_criteria_t; + +typedef struct _gop_options { + gop_tree_mode_t pdu_tree_mode; + gboolean drop_unassigned; + gboolean show_times; + float expiration; + float idle_timeout; + float lifetime; + AVPL* start; + AVPL* stop; + AVPL* extras; +} gop_options_t; + +typedef struct _gog_statements { + float expiration; + gop_tree_mode_t gop_tree_mode; + GPtrArray* transform_list; + AVPL* extras; + LoAL* current_gogkeys; +} gog_statement_t; + +typedef struct _transf_match_t { + avpl_match_mode match_mode; + AVPL* avpl; +} transf_match_t; + +typedef struct _transf_action_t { + avpl_replace_mode replace_mode; + AVPL* avpl; +} transf_action_t; + +static void configuration_error(mate_config* mc, const gchar* fmt, ...) { + static gchar error_buffer[256]; + const gchar* incl; + gint i; + mate_config_frame* current_frame; + va_list list; + + va_start( list, fmt ); + vsnprintf(error_buffer,sizeof(error_buffer),fmt,list); + va_end( list ); + + i = (gint) mc->config_stack->len; + + while (i--) { + + if (i>0) { + incl = "\n included from: "; + } else { + incl = " "; + } + + current_frame = (mate_config_frame *)g_ptr_array_index(mc->config_stack,(guint)i); + + g_string_append_printf(mc->config_error,"%s%s at line %u",incl, current_frame->filename, current_frame->linenum); + } + + g_string_append_printf(mc->config_error,": %s\n",error_buffer); + + THROW(MateConfigError); + +} + +static AVPL_Transf* new_transform_elem(AVPL* match, AVPL* replace, avpl_match_mode match_mode, avpl_replace_mode replace_mode) { + AVPL_Transf* t = (AVPL_Transf *)g_malloc(sizeof(AVPL_Transf)); + + t->name = NULL; + t->match = match; + t->replace = replace; + t->match_mode = match_mode; + t->replace_mode = replace_mode; + + t->map = NULL; + t->next = NULL; + + return t; +} + +static gchar* recolonize(mate_config* mc, gchar* s) { + GString* str = g_string_new(""); + gchar** vec; + gchar* r; + guint i,v; + gchar c; + + vec = g_strsplit(s,":",0); + + for (i = 0; vec[i]; i++) { + ascii_strdown_inplace(vec[i]); + + v = 0; + switch ( strlen(vec[i]) ) { + case 2: + c = vec[i][1]; + vec[i][1] = vec[i][0]; + vec[i][0] = c; + if (vec[i][0] >= '0' && vec[i][0] <= '9') { + v += (vec[i][1] - '0' )*16; + } else { + v += (vec[i][1] - 'a' + 10)*16; + } + /* FALL THROUGH */ + case 1: + if (vec[i][0] >= '0' && vec[i][0] <= '9') { + v += (vec[i][0] - '0' ); + } else { + v += (vec[i][0] - 'a' + 10); + } + case 0: + break; + default: + configuration_error(mc,"bad token %s",s); + } + + g_string_append_printf(str,":%.2X",v); + } + + g_strfreev(vec); + + g_string_erase(str,0,1); + + r = str->str; + + g_string_free(str,FALSE); + + return r; +} + +DIAG_OFF_LEMON() +} /* end of %include */ + +%code { +DIAG_ON_LEMON() +} + +%name MateParser + +%token_prefix TOKEN_ + +%token_type { gchar* } +%token_destructor { + (void) mc; /* Mark unused, similar to Q_UNUSED */ + g_free($$); +} + +%extra_argument { mate_config* mc } + +%syntax_error { + configuration_error(mc,"Syntax Error before %s",yyminor); +} + +%parse_failure { + configuration_error(mc,"Parse Error"); +} + +%type transform_decl { AVPL_Transf* } +%type transform_body { AVPL_Transf* } +%type transform_statements { AVPL_Transf* } +%type transform_statement { AVPL_Transf* } +%type transform_match { transf_match_t* } +%type transform_action { transf_action_t* } +%type match_mode { avpl_match_mode } +%type action_mode { avpl_replace_mode } + +%type gop_name { gchar* } +%type time_value { float } +%type pdu_name { gchar* } +%type gop_tree_mode { gop_tree_mode_t } +%type true_false { gboolean } + +%type criteria_statement { pdu_criteria_t* } +%type accept_mode { accept_mode_t } +%type pdu_drop_unassigned_statement { gboolean } +%type discard_pdu_data_statement { gboolean } +%type last_extracted_statement { gboolean } + +%type extraction_statement {extraction_t*} +%type extraction_statements {extraction_t*} + +%type gop_options { gop_options_t* } + +%type gop_start_statement { AVPL* } +%type gop_stop_statement { AVPL* } +%type extra_statement { AVPL* } +%type gop_drop_unassigned_statement { gboolean } +%type show_goptree_statement { gop_tree_mode_t } +%type show_times_statement { gboolean } +%type gop_expiration_statement { float } +%type idle_timeout_statement { float } +%type lifetime_statement { float } + +%type gog_statements { gog_statement_t* } +%type gog_expiration_statement { float } +%type gog_goptree_statement { gop_tree_mode_t } +%type gog_key_statements { LoAL* } +%type gog_key_statement { AVPL* } +%type transform_list_statement { GPtrArray* } +%type transform { AVPL_Transf* } +%type gop_tree_type { gop_tree_mode_t } + +%type payload_statement { GPtrArray* } +%type proto_stack { GPtrArray* } +%type field { header_field_info* } +%type transform_list { GPtrArray* } +%type avpl { AVPL* } +%type avps { AVPL* } +%type avp { AVP* } +%type value { gchar* } +%type avp_oneoff { gchar* } + + +mate_config ::= decls. + +decls ::= decls decl. +decls ::= . + +decl ::= pdu_decl. +decl ::= gop_decl. +decl ::= gog_decl. +decl ::= transform_decl. +decl ::= defaults_decl. +decl ::= debug_decl. +decl ::= DONE_KW SEMICOLON. + +/************* DEBUG +*/ + +debug_decl ::= DEBUG_KW OPEN_BRACE dbgfile_default dbglevel_default pdu_dbglevel_default gop_dbglevel_default gog_dbglevel_default CLOSE_BRACE SEMICOLON. + +dbgfile_default ::= FILENAME_KW QUOTED(Filename) SEMICOLON. { mc->dbg_facility = ws_fopen(Filename,"w"); if (mc->dbg_facility == NULL) report_open_failure(Filename,errno,TRUE); } +dbgfile_default ::= FILENAME_KW NAME(Filename) SEMICOLON. { mc->dbg_facility = ws_fopen(Filename,"w"); if (mc->dbg_facility == NULL) report_open_failure(Filename,errno,TRUE); } +dbgfile_default ::= . + +dbglevel_default ::= LEVEL_KW INTEGER(LevelString) SEMICOLON. { mc->dbg_lvl = (int) strtol(LevelString,NULL,10); } +dbglevel_default ::= . + +pdu_dbglevel_default ::= PDU_KW LEVEL_KW INTEGER(LevelString) SEMICOLON. { mc->dbg_pdu_lvl = (int) strtol(LevelString,NULL,10); } +pdu_dbglevel_default ::= . + +gop_dbglevel_default ::= GOP_KW LEVEL_KW INTEGER(LevelString) SEMICOLON. { mc->dbg_gop_lvl = (int) strtol(LevelString,NULL,10); } +gop_dbglevel_default ::= . + +gog_dbglevel_default ::= GOG_KW LEVEL_KW INTEGER(LevelString) SEMICOLON. { mc->dbg_gog_lvl = (int) strtol(LevelString,NULL,10); } +gog_dbglevel_default ::= . + + +/************* DEFAULTS +*/ + +defaults_decl ::= DEFAULT_KW OPEN_BRACE pdu_defaults gop_defaults gog_defaults CLOSE_BRACE SEMICOLON. + +pdu_defaults ::= PDU_KW OPEN_BRACE pdu_last_extracted_default pdu_drop_unassigned_default pdu_discard_default CLOSE_BRACE SEMICOLON. +pdu_defaults ::= . + +pdu_last_extracted_default ::= LAST_EXTRACTED_KW true_false(Flag) SEMICOLON. { mc->defaults.pdu.last_extracted = Flag; } +pdu_last_extracted_default ::= . + +pdu_drop_unassigned_default ::= DROP_UNASSIGNED_KW true_false(Flag) SEMICOLON. { mc->defaults.pdu.drop_unassigned = Flag; } +pdu_drop_unassigned_default ::= . + +pdu_discard_default ::= DISCARD_PDU_DATA_KW true_false(Flag) SEMICOLON. { mc->defaults.pdu.discard = Flag; } +pdu_discard_default ::= . + +gop_defaults ::= GOP_KW OPEN_BRACE gop_expiration_default gop_idle_timeout_default gop_lifetime_default gop_drop_unassigned_default gop_tree_mode_default gop_show_times_default CLOSE_BRACE SEMICOLON. +gop_defaults ::= . + +gop_expiration_default ::= EXPIRATION_KW time_value(B) SEMICOLON. { mc->defaults.gop.expiration = B; } +gop_expiration_default ::= . + +gop_idle_timeout_default ::= IDLE_TIMEOUT_KW time_value(B) SEMICOLON. { mc->defaults.gop.idle_timeout = B; } +gop_idle_timeout_default ::= . + +gop_lifetime_default ::= LIFETIME_KW time_value(B) SEMICOLON. { mc->defaults.gop.lifetime = B; } +gop_lifetime_default ::= . + +gop_drop_unassigned_default ::= DROP_UNASSIGNED_KW true_false(B) SEMICOLON. { mc->defaults.gop.drop_unassigned = B; } +gop_drop_unassigned_default ::= . + +gop_tree_mode_default ::= SHOW_TREE_KW gop_tree_mode(B) SEMICOLON. { mc->defaults.gop.pdu_tree_mode = (gop_pdu_tree_t)B; } +gop_tree_mode_default ::= . + +gop_show_times_default ::= SHOW_TIMES_KW true_false(B) SEMICOLON. { mc->defaults.gop.show_times = B; } +gop_show_times_default ::= . + +gog_defaults ::= GOG_KW OPEN_BRACE gog_expiration_default gop_tree_mode_default gog_goptree_default gog_show_times_default CLOSE_BRACE SEMICOLON. +gog_defaults ::= . + +gog_expiration_default ::= EXPIRATION_KW time_value(B) SEMICOLON. { mc->defaults.gop.expiration = B; } +gog_expiration_default ::= . + +gog_goptree_default ::= GOP_TREE_KW gop_tree_type(B) SEMICOLON. { mc->defaults.gog.gop_tree_mode = B; } +gog_goptree_default ::= . + +gog_show_times_default ::= SHOW_TIMES_KW true_false(B) SEMICOLON. { mc->defaults.gog.show_times = B; } +gog_show_times_default ::= . + + +/******************************************* TRANSFORM +*/ + +transform_decl(A) ::= TRANSFORM_KW NAME(B) transform_body(C) SEMICOLON. { + AVPL_Transf* c; + + if ( g_hash_table_lookup(mc->transfs,B) ) { + configuration_error(mc,"A transformation called '%s' exists already",B); + } + + for ( c = C; c; c = c->next ) + c->name = g_strdup(B); + + g_hash_table_insert(mc->transfs,C->name,C); + + A = NULL; +} + +transform_body(A) ::= OPEN_BRACE transform_statements(B) CLOSE_BRACE. { A = B; } + +transform_statements(A) ::= transform_statements(C) transform_statement(B). { + AVPL_Transf* c; + + for ( c = C; c->next; c = c->next ) ; + c->next = B; + A = C; +} + +transform_statements(A) ::= transform_statement(B). { A = B; } + +transform_statement(A) ::= transform_match(Match) transform_action(Action) SEMICOLON. { + A = new_transform_elem(Match->avpl,Action->avpl,Match->match_mode,Action->replace_mode); +} + +transform_match(A) ::= MATCH_KW match_mode(Mode) avpl(Avpl). { + A = (transf_match_t *)g_malloc(sizeof(transf_match_t)); + A->match_mode = Mode; + A->avpl = Avpl; +} + +transform_match(A) ::= . { + A = (transf_match_t *)g_malloc(sizeof(transf_match_t)); + A->match_mode = AVPL_STRICT; + A->avpl = new_avpl(""); + +} + +transform_action(A) ::= . { + A = (transf_action_t *)g_malloc(sizeof(transf_action_t)); + A->replace_mode = AVPL_INSERT; + A->avpl = new_avpl(""); +} +transform_action(A) ::= action_mode(Mode) avpl(Avpl). { + A = (transf_action_t *)g_malloc(sizeof(transf_action_t)); + A->replace_mode = Mode; + A->avpl = Avpl; +} + +match_mode(A) ::= . { A = AVPL_STRICT; } +match_mode(A) ::= STRICT_KW. { A = AVPL_STRICT; } +match_mode(A) ::= EVERY_KW. { A = AVPL_EVERY; } +match_mode(A) ::= LOOSE_KW. { A = AVPL_LOOSE; } + +action_mode(A) ::= REPLACE_KW. { A = AVPL_REPLACE; } +action_mode(A) ::= INSERT_KW. { A = AVPL_INSERT; } +action_mode(A) ::= . { A = AVPL_INSERT; } + +/******************************************* PDU +*/ + +pdu_decl ::= + PDU_KW NAME(Name) PROTO_KW field(Field) TRANSPORT_KW proto_stack(Stack) + OPEN_BRACE + payload_statement(Payload) + extraction_statements(Extraction) + transform_list_statement(Transform) + criteria_statement(Criteria) + pdu_drop_unassigned_statement(DropUnassigned) + discard_pdu_data_statement(DistcardPduData) + last_extracted_statement(LastExtracted) + CLOSE_BRACE SEMICOLON. +{ + + mate_cfg_pdu* cfg = new_pducfg(mc, Name); + extraction_t *extraction, *next_extraction; + GPtrArray* transport_stack = g_ptr_array_new(); + int i; + + if (! cfg ) configuration_error(mc,"could not create Pdu %s.",Name); + + cfg->hfid_proto = Field->id; + + cfg->last_extracted = LastExtracted; + cfg->discard = DistcardPduData; + cfg->drop_unassigned = DropUnassigned; + + /* + * Add this protocol to our table of wanted hfids. + */ + mc->wanted_hfids = g_array_append_val(mc->wanted_hfids, Field->id); + + /* flip the transport_stack */ + for (i = Stack->len - 1; Stack->len; i--) { + g_ptr_array_add(transport_stack,g_ptr_array_remove_index(Stack,i)); + } + + g_ptr_array_free(Stack, TRUE); + + cfg->transport_ranges = transport_stack; + cfg->payload_ranges = Payload; + + if (Criteria) { + cfg->criterium = Criteria->criterium_avpl; + cfg->criterium_match_mode = Criteria->criterium_match_mode; + cfg->criterium_accept_mode = Criteria->criterium_accept_mode; + } + + cfg->transforms = Transform; + + for (extraction = Extraction; extraction; extraction = next_extraction) { + next_extraction = extraction->next; + + if ( ! add_hfid(mc, extraction->hfi, extraction->as, cfg->hfids_attr) ) { + configuration_error(mc,"MATE: failed to create extraction rule '%s'",extraction->as); + } + + g_free(extraction); + } +} + +payload_statement(A) ::= . { A = NULL; } +payload_statement(A) ::= PAYLOAD_KW proto_stack(B) SEMICOLON. { A = B; } + +criteria_statement(A) ::= . { A = NULL; } +criteria_statement(A) ::= CRITERIA_KW accept_mode(B) match_mode(C) avpl(D) SEMICOLON. { + A = g_new(pdu_criteria_t, 1); + A->criterium_avpl = D; + A->criterium_match_mode = C; + A->criterium_accept_mode = B; +} + +accept_mode(A) ::= . { A = ACCEPT_MODE; } +accept_mode(A) ::= ACCEPT_KW. { A = ACCEPT_MODE; } +accept_mode(A) ::= REJECT_KW. { A = REJECT_MODE; } + +extraction_statements(A) ::= extraction_statements(B) extraction_statement(C). { A = B; A->last = A->last->next = C; } +extraction_statements(A) ::= extraction_statement(B). { A = B; A->last = A; } + +extraction_statement(A) ::= EXTRACT_KW NAME(NAME) FROM_KW field(FIELD) SEMICOLON. { + A = g_new(extraction_t, 1); + A->as = NAME; + A->hfi = FIELD; + A->next = A->last = NULL; +} + + +pdu_drop_unassigned_statement(A) ::= DROP_UNASSIGNED_KW true_false(B) SEMICOLON. { A = B; } +pdu_drop_unassigned_statement(A) ::= . { A = mc->defaults.pdu.drop_unassigned; } + +discard_pdu_data_statement(A) ::= DISCARD_PDU_DATA_KW true_false(B) SEMICOLON. { A = B; } +discard_pdu_data_statement(A) ::= . { A = mc->defaults.pdu.discard; } + +last_extracted_statement(A) ::= LAST_PDU_KW true_false(B) SEMICOLON. { A = B; } +last_extracted_statement(A) ::= . { A = mc->defaults.pdu.last_extracted; } + +proto_stack(A) ::= proto_stack(B) SLASH field(C). { + int* hfidp = g_new(int, 1); + + *hfidp = C->id; + g_ptr_array_add(B,hfidp); + A = B; +} + +proto_stack(A) ::= field(B). { + int* hfidp = g_new(int, 1); + *hfidp = B->id; + + A = g_ptr_array_new(); + g_ptr_array_add(A,hfidp); +} + +field(A) ::= NAME(B). { + A = proto_registrar_get_byname(B); +} + +/******************************************* GOP +*/ + +gop_decl(A) ::= GOP_KW NAME(Name) ON_KW pdu_name(PduName) MATCH_KW avpl(Key) OPEN_BRACE + gop_start_statement(Start) + gop_stop_statement(Stop) + extra_statement(Extra) + transform_list_statement(Transform) + gop_expiration_statement(Expiration) + idle_timeout_statement(IdleTimeout) + lifetime_statement(Lifetime) + gop_drop_unassigned_statement(DropUnassigned) + show_goptree_statement(TreeMode) + show_times_statement(ShowTimes) + CLOSE_BRACE SEMICOLON. { + mate_cfg_gop* cfg; + + if (g_hash_table_lookup(mc->gopcfgs,Name)) configuration_error(mc,"A Gop Named '%s' exists already.",Name); + if (g_hash_table_lookup(mc->gops_by_pduname,PduName) ) configuration_error(mc,"Gop for Pdu '%s' exists already",PduName); + + cfg = new_gopcfg(mc, Name); + g_hash_table_insert(mc->gops_by_pduname,PduName,cfg); + g_hash_table_insert(mc->gopcfgs,cfg->name,cfg); + + cfg->on_pdu = PduName; + cfg->key = Key; + cfg->drop_unassigned = DropUnassigned; + cfg->show_times = ShowTimes; + cfg->pdu_tree_mode = (gop_pdu_tree_t)TreeMode; + cfg->expiration = Expiration; + cfg->idle_timeout = IdleTimeout; + cfg->lifetime = Lifetime; + cfg->start = Start; + cfg->stop = Stop; + cfg->transforms = Transform; + + merge_avpl(cfg->extra,Extra,TRUE); + delete_avpl(Extra,TRUE); +} + +gop_drop_unassigned_statement(A) ::= DROP_UNASSIGNED_KW true_false(B) SEMICOLON. { A = B; } +gop_drop_unassigned_statement(A) ::= . { A = mc->defaults.gop.drop_unassigned; } + +gop_start_statement(A) ::= START_KW avpl(B) SEMICOLON. { A = B; } +gop_start_statement(A) ::= . { A = NULL; } + +gop_stop_statement(A) ::= STOP_KW avpl(B) SEMICOLON. { A = B; } +gop_stop_statement(A) ::= . { A = NULL; } + +show_goptree_statement(A) ::= SHOW_TREE_KW gop_tree_mode(B) SEMICOLON. { A = B; } +show_goptree_statement(A) ::= . { A = (gop_tree_mode_t)mc->defaults.gop.pdu_tree_mode; } + +show_times_statement(A) ::= SHOW_TIMES_KW true_false(B) SEMICOLON. { A = B; } +show_times_statement(A) ::= . { A = mc->defaults.gop.show_times; } + +gop_expiration_statement(A) ::= EXPIRATION_KW time_value(B) SEMICOLON. { A = B; } +gop_expiration_statement(A) ::= . { A = mc->defaults.gop.lifetime; } + +idle_timeout_statement(A) ::= IDLE_TIMEOUT_KW time_value(B) SEMICOLON. { A = B; } +idle_timeout_statement(A) ::= . { A = mc->defaults.gop.lifetime; } + +lifetime_statement(A) ::= LIFETIME_KW time_value(B) SEMICOLON. { A = B; } +lifetime_statement(A) ::= . { A = mc->defaults.gop.lifetime; } + +gop_tree_mode(A) ::= NO_TREE_KW. { A = (gop_tree_mode_t)GOP_NO_TREE; } +gop_tree_mode(A) ::= PDU_TREE_KW. { A = (gop_tree_mode_t)GOP_PDU_TREE; } +gop_tree_mode(A) ::= FRAME_TREE_KW. { A = (gop_tree_mode_t)GOP_FRAME_TREE; } +gop_tree_mode(A) ::= BASIC_TREE_KW. { A = (gop_tree_mode_t)GOP_BASIC_PDU_TREE; } + +true_false(A) ::= TRUE_KW. { A = TRUE; } +true_false(A) ::= FALSE_KW. { A = FALSE; } + +pdu_name(A) ::= NAME(B). { + mate_cfg_pdu* c; + if (( c = (mate_cfg_pdu *)g_hash_table_lookup(mc->pducfgs,B) )) { + A = c->name; + } else { + configuration_error(mc,"No such Pdu: '%s'",B); + } +} + + +time_value(A) ::= FLOATING(B). { + A = (float) g_ascii_strtod(B,NULL); +} + +time_value(A) ::= INTEGER(B). { + A = (float) g_ascii_strtod(B,NULL); +} + +/************* GOG +*/ + +gog_decl ::= GOG_KW NAME(Name) OPEN_BRACE + gog_key_statements(Keys) + extra_statement(Extra) + transform_list_statement(Transforms) + gog_expiration_statement(Expiration) + gog_goptree_statement(Tree) + show_times_statement(ShowTimes) + CLOSE_BRACE SEMICOLON. { + mate_cfg_gog* cfg = NULL; + + if ( g_hash_table_lookup(mc->gogcfgs,Name) ) { + configuration_error(mc,"Gog '%s' exists already ",Name); + } + + cfg = new_gogcfg(mc, Name); + + cfg->expiration = Expiration; + cfg->gop_tree_mode = Tree; + cfg->transforms = Transforms; + cfg->keys = Keys; + cfg->show_times = ShowTimes; + + merge_avpl(cfg->extra,Extra,TRUE); + delete_avpl(Extra,TRUE); +} + +gog_goptree_statement(A) ::= GOP_TREE_KW gop_tree_type(B) SEMICOLON. { A = B; } +gog_goptree_statement(A) ::= . { A = mc->defaults.gog.gop_tree_mode; } + +gog_expiration_statement(A) ::= EXPIRATION_KW time_value(B) SEMICOLON. { A = B; } +gog_expiration_statement(A) ::= . { A = mc->defaults.gog.expiration; } + +gop_tree_type(A) ::= NULL_TREE_KW. { A = GOP_NULL_TREE; } +gop_tree_type(A) ::= FULL_TREE_KW. { A = GOP_FULL_TREE; } +gop_tree_type(A) ::= BASIC_TREE_KW. { A = GOP_BASIC_TREE; } + +gog_key_statements(A) ::= gog_key_statements(B) gog_key_statement(C). { + loal_append(B,C); + A = B; +} + +gog_key_statements(A) ::= gog_key_statement(B). { + A = new_loal(""); + loal_append(A,B); +} + + +gog_key_statement(A) ::= MEMBER_KW gop_name(B) avpl(C) SEMICOLON. { + rename_avpl(C,B); + A = C; +} + +gop_name(A) ::= NAME(B). { + mate_cfg_gop* c; + if (( c = (mate_cfg_gop *)g_hash_table_lookup(mc->gopcfgs,B) )) { + A = c->name; + } else { + configuration_error(mc,"No Gop called '%s' has been already declared",B); + } +} +/******************************************** GENERAL +*/ + + +extra_statement(A) ::= EXTRA_KW avpl(B) SEMICOLON. { A = B; } +extra_statement(A) ::= . { A = new_avpl(""); } + +transform_list_statement(A) ::= TRANSFORM_KW transform_list(B) SEMICOLON. { A = B; } +transform_list_statement(A) ::= . { A = g_ptr_array_new(); } + +transform_list(A) ::= transform_list(B) COMMA transform(C). { + A = B; + g_ptr_array_add(B,C); +} + +transform_list(A) ::= transform(B). { + A = g_ptr_array_new(); + g_ptr_array_add(A,B); +} + +transform(A) ::= NAME(B). { + AVPL_Transf* t; + + if (( t = (AVPL_Transf *)g_hash_table_lookup(mc->transfs,B) )) { + A = t; + } else { + configuration_error(mc,"There's no such Transformation: %s",B); + } +} + +avpl(A) ::= OPEN_PARENS avps(B) CLOSE_PARENS. { A = B; } +avpl(A) ::= OPEN_PARENS CLOSE_PARENS. { A = new_avpl(""); } + +avps(A) ::= avps(B) COMMA avp(C). { A = B; if ( ! insert_avp(B,C) ) delete_avp(C); } +avps(A) ::= avp(B). { A = new_avpl(""); if ( ! insert_avp(A,B) ) delete_avp(B); } + +avp(A) ::= NAME(B) AVP_OPERATOR(C) value(D). { A = new_avp(B,D,*C); } +avp(A) ::= NAME(B). { A = new_avp(B,"",'?'); } +avp(A) ::= NAME(B) OPEN_BRACE avp_oneoff(C) CLOSE_BRACE. { A = new_avp(B,C,'|'); } + +avp_oneoff(A) ::= avp_oneoff(B) PIPE value(C). { A = ws_strdup_printf("%s|%s",B,C); } +avp_oneoff(A) ::= value(B). { A = g_strdup(B); } + +value(A) ::= QUOTED(B). { A = g_strdup(B); } +value(A) ::= NAME(B). { A = g_strdup(B); } +value(A) ::= FLOATING(B). { A = g_strdup(B); } +value(A) ::= INTEGER(B). { A = g_strdup(B); } +value(A) ::= DOTED_IP(B). { A = g_strdup(B); } +value(A) ::= COLONIZED(B). { A = recolonize(mc,B); } + diff --git a/plugins/epan/mate/mate_parser.l b/plugins/epan/mate/mate_parser.l new file mode 100644 index 00000000..6e423abc --- /dev/null +++ b/plugins/epan/mate/mate_parser.l @@ -0,0 +1,409 @@ +%top { +/* Include this before everything else, for various large-file definitions */ +#include "config.h" +/* Include this before everything else, as it declares functions used here. */ +#include "mate.h" +} + +/* + * We want a reentrant scanner. + */ +%option reentrant + +/* + * We don't use input, so don't generate code for it. + */ +%option noinput + +/* + * We don't use unput, so don't generate code for it. + */ +%option nounput + +/* + * We don't read interactively from the terminal. + */ +%option never-interactive + +/* + * We want to stop processing when we get to the end of the input. + */ +%option noyywrap + +/* + * The type for the state we keep for a scanner. + */ +%option extra-type="Mate_scanner_state_t *" + +/* + * We have to override the memory allocators so that we don't get + * "unused argument" warnings from the yyscanner argument (which + * we don't use, as we have a global memory allocator). + * + * We provide, as macros, our own versions of the routines generated by Flex, + * which just call malloc()/realloc()/free() (as the Flex versions do), + * discarding the extra argument. + */ +%option noyyalloc +%option noyyrealloc +%option noyyfree + +/* + * Prefix scanner routines with "Mate_" rather than "yy", so this scanner + * can coexist with other scanners. + */ +%option prefix="Mate_" + +%{ + + /* mate_parser.l + * lexical analyzer for MATE configuration files + * + * Copyright 2004, Luis E. Garcia Ontanon <luis@ontanon.org> + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "mate_grammar.h" + +#include <wsutil/file_util.h> + +/* + * Disable diagnostics in the code generated by Flex. + */ +DIAG_OFF_FLEX() + + void MateParseTrace(FILE*,char*); + +#define MAX_INCLUDE_DEPTH 10 +typedef struct { + mate_config* mc; + + mate_config_frame* current_frame; + + void* pParser; + + YY_BUFFER_STATE include_stack[MAX_INCLUDE_DEPTH]; + int include_stack_ptr; +} Mate_scanner_state_t; + +#define MATE_PARSE(token_type) MateParser(yyextra->pParser, (token_type), g_strdup(yytext), yyextra->mc); + +/* + * Flex (v 2.5.35) uses this symbol to "exclude" unistd.h + */ +#ifdef _WIN32 +#define YY_NO_UNISTD_H +#endif + +static void free_config_frame(mate_config_frame *frame) { + g_free(frame->filename); + g_free(frame); +} + +#define YY_USER_INIT BEGIN OUTSIDE; + +/* + * Sleazy hack to suppress compiler warnings in yy_fatal_error(). + */ +#define YY_EXIT_FAILURE ((void)yyscanner, 2) + +/* + * Macros for the allocators, to discard the extra argument. + */ +#define Mate_alloc(size, yyscanner) (void *)malloc(size) +#define Mate_realloc(ptr, size, yyscanner) (void *)realloc((char *)(ptr), (size)) +#define Mate_free(ptr, yyscanner) free((char *)ptr) + +%} + +pdu_kw Pdu +gop_kw Gop +gog_kw Gog +transform_kw Transform +match_kw Match +always_kw Always +strict_kw Strict +every_kw Every +loose_kw Loose +replace_kw Replace +insert_kw Insert +gop_tree_kw GopTree +member_kw Member +on_kw On +start_kw Start +stop_kw Stop +extra_kw Extra +show_tree_kw ShowTree +show_times_kw ShowTimes +expiration_kw Expiration +idle_timeout_kw IdleTimeout +lifetime_kw Lifetime +no_tree_kw NoTree +pdu_tree_kw PduTree +frame_tree_kw FrameTree +basic_tree_kw BasicTree +true_kw [Tt][Rr][Uu][Ee] +false_kw [Ff][Aa][Ll][Ss][Ee] +proto_kw Proto +payload_kw Payload +transport_kw Transport +criteria_kw Criteria +accept_kw Accept +reject_kw Reject +extract_kw Extract +from_kw From +drop_unassigned_kw DropUnassigned +discard_pdu_data_kw DiscardPduData +last_pdu_kw LastPdu +done_kw Done +filename_kw Filename +debug_kw Debug +level_kw Level +default_kw Default + + +open_parens "(" +close_parens ")" +open_brace "{" +close_brace "}" +comma "," +semicolon ";" +slash "/" +pipe "|" + +integer [0-9]+ +floating ([0-9]+\.[0-9]+) +doted_ip [0-9][0-9]?[0-9]?\.[0-9][0-9]?[0-9]?\.[0-9][0-9]?[0-9]?\.[0-9][0-9]?[0-9]? +colonized [0-9A-Fa-f:]*[:][0-9A-Fa-f:]* + +name [a-z][-\.a-zA-Z0-9_]* +avp_operator [$^~=<>!] +quote ["] +not_quoted [^"]* + +include "#include" +filename [-A-Za-z0-9_/.]+ + +whitespace [[:blank:]\r]+ +newline \n + +comment "//"[^\n]*\n + +blk_cmnt_start "/*" +cmnt_char . +blk_cmnt_stop "*/" + +%START OUTSIDE QUOTED INCLUDING COMMENT +%% + +{newline} yyextra->current_frame->linenum++; +{whitespace} ; + +<OUTSIDE>{include} BEGIN INCLUDING; + +<INCLUDING>{filename} { + if ( yyextra->include_stack_ptr >= MAX_INCLUDE_DEPTH ) + ws_error("dtd_preparse: include files nested too deeply"); + + yyextra->include_stack[yyextra->include_stack_ptr++] = YY_CURRENT_BUFFER; + yyin = ws_fopen( yytext, "r" ); + + if (!yyin) { + Mate__delete_buffer(YY_CURRENT_BUFFER, yyscanner); + + /* coverity[negative_sink] */ + Mate__switch_to_buffer(yyextra->include_stack[--yyextra->include_stack_ptr], yyscanner); + + if (errno) + g_string_append_printf(yyextra->mc->config_error, "Mate parser: Could not open file: '%s': %s", yytext, g_strerror(errno) ); + + } else { + + yyextra->current_frame = g_new(mate_config_frame, 1); + yyextra->current_frame->filename = g_strdup(yytext); + yyextra->current_frame->linenum = 1; + + g_ptr_array_add(yyextra->mc->config_stack,yyextra->current_frame); + + Mate__switch_to_buffer(Mate__create_buffer(yyin, YY_BUF_SIZE, yyscanner), yyscanner); + } + + BEGIN OUTSIDE; +} + +<<EOF>> { + /* coverity[check_after_sink] */ + if ( --yyextra->include_stack_ptr < 0 ) { + yyterminate(); + } else { + Mate__delete_buffer(YY_CURRENT_BUFFER, yyscanner); + Mate__switch_to_buffer(yyextra->include_stack[yyextra->include_stack_ptr], yyscanner); + + free_config_frame(yyextra->current_frame); + yyextra->current_frame = (mate_config_frame *)g_ptr_array_remove_index(yyextra->mc->config_stack,yyextra->mc->config_stack->len-1); + } +} + +<OUTSIDE>{comment} ; + +<OUTSIDE>{blk_cmnt_start} BEGIN COMMENT; +<COMMENT>{cmnt_char} ; +<COMMENT>{blk_cmnt_stop} BEGIN OUTSIDE; + +<OUTSIDE>{pdu_kw} MATE_PARSE(TOKEN_PDU_KW); +<OUTSIDE>{gop_kw} MATE_PARSE(TOKEN_GOP_KW); +<OUTSIDE>{gog_kw} MATE_PARSE(TOKEN_GOG_KW); +<OUTSIDE>{transform_kw} MATE_PARSE(TOKEN_TRANSFORM_KW); +<OUTSIDE>{match_kw} MATE_PARSE(TOKEN_MATCH_KW); +<OUTSIDE>{strict_kw} MATE_PARSE(TOKEN_STRICT_KW); +<OUTSIDE>{every_kw} MATE_PARSE(TOKEN_EVERY_KW); +<OUTSIDE>{loose_kw} MATE_PARSE(TOKEN_LOOSE_KW); +<OUTSIDE>{replace_kw} MATE_PARSE(TOKEN_REPLACE_KW); +<OUTSIDE>{insert_kw} MATE_PARSE(TOKEN_INSERT_KW); +<OUTSIDE>{gop_tree_kw} MATE_PARSE(TOKEN_GOP_TREE_KW); +<OUTSIDE>{member_kw} MATE_PARSE(TOKEN_MEMBER_KW); +<OUTSIDE>{on_kw} MATE_PARSE(TOKEN_ON_KW); +<OUTSIDE>{start_kw} MATE_PARSE(TOKEN_START_KW); +<OUTSIDE>{stop_kw} MATE_PARSE(TOKEN_STOP_KW); +<OUTSIDE>{extra_kw} MATE_PARSE(TOKEN_EXTRA_KW); +<OUTSIDE>{show_tree_kw} MATE_PARSE(TOKEN_SHOW_TREE_KW); +<OUTSIDE>{show_times_kw} MATE_PARSE(TOKEN_SHOW_TIMES_KW); +<OUTSIDE>{expiration_kw} MATE_PARSE(TOKEN_EXPIRATION_KW); +<OUTSIDE>{idle_timeout_kw} MATE_PARSE(TOKEN_IDLE_TIMEOUT_KW); +<OUTSIDE>{lifetime_kw} MATE_PARSE(TOKEN_LIFETIME_KW); +<OUTSIDE>{no_tree_kw} MATE_PARSE(TOKEN_NO_TREE_KW); +<OUTSIDE>{pdu_tree_kw} MATE_PARSE(TOKEN_PDU_TREE_KW); +<OUTSIDE>{frame_tree_kw} MATE_PARSE(TOKEN_FRAME_TREE_KW); +<OUTSIDE>{basic_tree_kw} MATE_PARSE(TOKEN_BASIC_TREE_KW); +<OUTSIDE>{true_kw} MATE_PARSE(TOKEN_TRUE_KW); +<OUTSIDE>{false_kw} MATE_PARSE(TOKEN_FALSE_KW); +<OUTSIDE>{proto_kw} MATE_PARSE(TOKEN_PROTO_KW); +<OUTSIDE>{payload_kw} MATE_PARSE(TOKEN_PAYLOAD_KW); +<OUTSIDE>{transport_kw} MATE_PARSE(TOKEN_TRANSPORT_KW); +<OUTSIDE>{criteria_kw} MATE_PARSE(TOKEN_CRITERIA_KW); +<OUTSIDE>{accept_kw} MATE_PARSE(TOKEN_ACCEPT_KW); +<OUTSIDE>{reject_kw} MATE_PARSE(TOKEN_REJECT_KW); +<OUTSIDE>{extract_kw} MATE_PARSE(TOKEN_EXTRACT_KW); +<OUTSIDE>{from_kw} MATE_PARSE(TOKEN_FROM_KW); +<OUTSIDE>{drop_unassigned_kw} MATE_PARSE(TOKEN_DROP_UNASSIGNED_KW); +<OUTSIDE>{discard_pdu_data_kw} MATE_PARSE(TOKEN_DISCARD_PDU_DATA_KW); +<OUTSIDE>{last_pdu_kw} MATE_PARSE(TOKEN_LAST_PDU_KW); +<OUTSIDE>{done_kw} MATE_PARSE(TOKEN_DONE_KW); +<OUTSIDE>{filename_kw} MATE_PARSE(TOKEN_FILENAME_KW); +<OUTSIDE>{debug_kw} MATE_PARSE(TOKEN_DEBUG_KW); +<OUTSIDE>{level_kw} MATE_PARSE(TOKEN_LEVEL_KW); +<OUTSIDE>{default_kw} MATE_PARSE(TOKEN_DEFAULT_KW); + +<OUTSIDE>{open_parens} MATE_PARSE(TOKEN_OPEN_PARENS); +<OUTSIDE>{close_parens} MATE_PARSE(TOKEN_CLOSE_PARENS); +<OUTSIDE>{open_brace} MATE_PARSE(TOKEN_OPEN_BRACE); +<OUTSIDE>{close_brace} MATE_PARSE(TOKEN_CLOSE_BRACE); +<OUTSIDE>{comma} MATE_PARSE(TOKEN_COMMA); +<OUTSIDE>{semicolon} MATE_PARSE(TOKEN_SEMICOLON); +<OUTSIDE>{slash} MATE_PARSE(TOKEN_SLASH); +<OUTSIDE>{pipe} MATE_PARSE(TOKEN_PIPE); + +<OUTSIDE>{integer} MATE_PARSE(TOKEN_INTEGER); +<OUTSIDE>{floating} MATE_PARSE(TOKEN_FLOATING); +<OUTSIDE>{doted_ip} MATE_PARSE(TOKEN_DOTED_IP); +<OUTSIDE>{colonized} MATE_PARSE(TOKEN_COLONIZED); +<OUTSIDE>{name} MATE_PARSE(TOKEN_NAME); +<OUTSIDE>{avp_operator} MATE_PARSE(TOKEN_AVP_OPERATOR); + + +<OUTSIDE>{quote} BEGIN QUOTED; +<QUOTED>{not_quoted} MATE_PARSE(TOKEN_QUOTED); +<QUOTED>{quote} BEGIN OUTSIDE; + +%% + +/* + * Turn diagnostics back on, so we check the code that we've written. + */ +DIAG_ON_FLEX() + +static void ptr_array_free(gpointer data, gpointer user_data _U_) +{ + free_config_frame((mate_config_frame *)data); +} + +extern gboolean mate_load_config(const gchar* filename, mate_config* mc) { + FILE *in; + yyscan_t scanner; + Mate_scanner_state_t state; + volatile gboolean status = TRUE; + + in = ws_fopen(filename,"r"); + + if (!in) { + g_string_append_printf(mc->config_error,"Mate parser: Could not open file: '%s', error: %s", filename, g_strerror(errno) ); + return FALSE; + } + + if (Mate_lex_init(&scanner) != 0) { + g_string_append_printf(mc->config_error, "Mate parse: Could not initialize scanner: %s", g_strerror(errno)); + fclose(in); + return FALSE; + } + + Mate_set_in(in, scanner); + + mc->config_stack = g_ptr_array_new(); + + state.mc = mc; + + state.current_frame = g_new(mate_config_frame, 1); + state.current_frame->filename = g_strdup(filename); + state.current_frame->linenum = 1; + + g_ptr_array_add(mc->config_stack,state.current_frame); + + state.pParser = MateParserAlloc(g_malloc); + + state.include_stack_ptr = 0; + + /* Associate the state with the scanner */ + Mate_set_extra(&state, scanner); + + /* MateParserTrace(stdout,""); */ + + TRY { + Mate_lex(scanner); + + /* Inform parser that end of input has reached. */ + MateParser(state.pParser, 0, NULL, mc); + + MateParserFree(state.pParser, g_free); + } CATCH(MateConfigError) { + status = FALSE; + } CATCH_ALL { + status = FALSE; + g_string_append_printf(mc->config_error,"An unexpected error occurred"); + } + ENDTRY; + + Mate_lex_destroy(scanner); + fclose(in); + + g_ptr_array_foreach(mc->config_stack, ptr_array_free, NULL); + g_ptr_array_free(mc->config_stack, TRUE); + + return status; +} diff --git a/plugins/epan/mate/mate_runtime.c b/plugins/epan/mate/mate_runtime.c new file mode 100644 index 00000000..41d9c0de --- /dev/null +++ b/plugins/epan/mate/mate_runtime.c @@ -0,0 +1,930 @@ +/* mate_runtime.c + * MATE -- Meta Analysis Tracing Engine + * + * Copyright 2004, Luis E. Garcia Ontanon <luis@ontanon.org> + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1998 Gerald Combs + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "config.h" + +#include "mate.h" +#include <wsutil/ws_assert.h> + +typedef struct _mate_range mate_range; + +struct _mate_range { + guint start; + guint end; +}; + + +typedef struct _tmp_pdu_data { + GPtrArray* ranges; + proto_tree* tree; + mate_pdu* pdu; +} tmp_pdu_data; + + +typedef struct _gogkey { + gchar* key; + mate_cfg_gop* cfg; +} gogkey; + + +static mate_runtime_data* rd = NULL; + +static int zero = 5; + +static int* dbg = &zero; +static int* dbg_pdu = &zero; +static int* dbg_gop = &zero; +static int* dbg_gog = &zero; +static FILE* dbg_facility = NULL; + +static gboolean destroy_mate_pdus(gpointer k _U_, gpointer v, gpointer p _U_) { + mate_pdu* pdu = (mate_pdu*) v; + if (pdu->avpl) delete_avpl(pdu->avpl,TRUE); + g_slice_free(mate_max_size, (mate_max_size *)pdu); + return TRUE; +} + +static gboolean destroy_mate_gops(gpointer k _U_, gpointer v, gpointer p _U_) { + mate_gop* gop = (mate_gop*) v; + + if (gop->avpl) delete_avpl(gop->avpl,TRUE); + + if (gop->gop_key) { + if (g_hash_table_lookup(gop->cfg->gop_index,gop->gop_key) == gop) { + g_hash_table_remove(gop->cfg->gop_index,gop->gop_key); + } + + g_free(gop->gop_key); + } + + g_slice_free(mate_max_size,(mate_max_size*)gop); + + return TRUE; +} + + +static void gog_remove_keys (mate_gog* gog); + +static gboolean destroy_mate_gogs(gpointer k _U_, gpointer v, gpointer p _U_) { + mate_gog* gog = (mate_gog*) v; + + if (gog->avpl) delete_avpl(gog->avpl,TRUE); + + if (gog->gog_keys) { + gog_remove_keys(gog); + g_ptr_array_free(gog->gog_keys, TRUE); + } + + g_slice_free(mate_max_size,(mate_max_size*)gog); + + return TRUE; +} + +static gboolean return_true(gpointer k _U_, gpointer v _U_, gpointer p _U_) { + return TRUE; +} + +static void destroy_pdus_in_cfg(gpointer k _U_, gpointer v, gpointer p _U_) { + mate_cfg_pdu* c = (mate_cfg_pdu *)v; + g_hash_table_foreach_remove(c->items,destroy_mate_pdus,NULL); + c->last_id = 0; +} + + +static void destroy_gops_in_cfg(gpointer k _U_, gpointer v, gpointer p _U_) { + mate_cfg_gop* c = (mate_cfg_gop *)v; + + g_hash_table_foreach_remove(c->gop_index,return_true,NULL); + g_hash_table_destroy(c->gop_index); + c->gop_index = g_hash_table_new(g_str_hash,g_str_equal); + + g_hash_table_foreach_remove(c->gog_index,return_true,NULL); + g_hash_table_destroy(c->gog_index); + c->gog_index = g_hash_table_new(g_str_hash,g_str_equal); + + g_hash_table_foreach_remove(c->items,destroy_mate_gops,NULL); + c->last_id = 0; +} + +static void destroy_gogs_in_cfg(gpointer k _U_, gpointer v, gpointer p _U_) { + mate_cfg_gog* c = (mate_cfg_gog *)v; + g_hash_table_foreach_remove(c->items,destroy_mate_gogs,NULL); + c->last_id = 0; +} + +void initialize_mate_runtime(mate_config* mc) { + + dbg_print (dbg,5,dbg_facility,"initialize_mate: entering"); + + if (mc) { + if (rd == NULL ) { + rd = g_new(mate_runtime_data, 1); + } else { + g_hash_table_foreach(mc->pducfgs,destroy_pdus_in_cfg,NULL); + g_hash_table_foreach(mc->gopcfgs,destroy_gops_in_cfg,NULL); + g_hash_table_foreach(mc->gogcfgs,destroy_gogs_in_cfg,NULL); + + g_hash_table_destroy(rd->frames); + } + + rd->current_items = 0; + rd->now = -1.0f; + rd->highest_analyzed_frame = 0; + rd->frames = g_hash_table_new(g_direct_hash,g_direct_equal); + + + /*mc->dbg_gop_lvl = 5; + mc->dbg_gog_lvl = 5; + */ + dbg_pdu = &(mc->dbg_pdu_lvl); + dbg_gop = &(mc->dbg_gop_lvl); + dbg_gog = &(mc->dbg_gog_lvl); + dbg = &(mc->dbg_lvl); + dbg_facility = mc->dbg_facility; + + dbg_print(dbg, 1, dbg_facility, "starting mate"); + + } else { + rd = NULL; + } +} + + +static mate_gop* new_gop(mate_cfg_gop* cfg, mate_pdu* pdu, gchar* key) { + mate_gop* gop = (mate_gop*)g_slice_new(mate_max_size); + + gop->id = ++(cfg->last_id); + gop->cfg = cfg; + + dbg_print(dbg_gop, 1, dbg_facility, "new_gop: %s: ``%s:%d''", key, gop->cfg->name, gop->id); + + gop->gop_key = key; + gop->avpl = new_avpl(cfg->name); + gop->last_n = 0; + + gop->gog = NULL; + gop->next = NULL; + + gop->expiration = cfg->expiration > 0.0 ? cfg->expiration + rd->now : (float) -1.0 ; + gop->idle_expiration = cfg->idle_timeout > 0.0 ? cfg->idle_timeout + rd->now : (float) -1.0 ; + gop->time_to_die = cfg->lifetime > 0.0 ? cfg->lifetime + rd->now : (float) -1.0 ; + gop->time_to_timeout = 0.0f; + + gop->last_time = gop->start_time = rd->now; + gop->release_time = 0.0f; + + gop->num_of_pdus = 0; + gop->num_of_after_release_pdus = 0; + + gop->pdus = pdu; + gop->last_pdu = pdu; + + gop->released = FALSE; + + pdu->gop = gop; + pdu->next = NULL; + pdu->is_start = TRUE; + pdu->time_in_gop = 0.0f; + + g_hash_table_insert(cfg->gop_index,gop->gop_key,gop); + return gop; +} + +static void adopt_gop(mate_gog* gog, mate_gop* gop) { + dbg_print (dbg_gog,5,dbg_facility,"adopt_gop: gog=%p gop=%p",(void*)gog,(void*)gop); + + gop->gog = gog; + gop->next = NULL; + + if (gop->cfg->start) { + gog->num_of_counting_gops++; + } + + gog->num_of_gops++; + + if (gog->last_gop) { + gog->last_gop->next = gop; + } + + gog->last_gop = gop; + + if (! gog->gops ) { + gog->gops = gop; + } + +} + +static mate_gog* new_gog(mate_cfg_gog* cfg, mate_gop* gop) { + mate_gog* gog = (mate_gog*)g_slice_new(mate_max_size); + gog->id = ++(cfg->last_id); + gog->cfg = cfg; + + dbg_print (dbg_gog,1,dbg_facility,"new_gog: %s:%u for %s:%u",gog->cfg->name,gog->id,gop->cfg->name,gop->id); + + gog->avpl = new_avpl(cfg->name); + gog->last_n = 0; + + gog->expiration = 0.0f; + gog->idle_expiration = 0.0f; + + gog->start_time = rd->now; + gog->release_time = 0.0f; + gog->last_time = 0.0f; + + gog->gops = NULL; + gog->last_gop = NULL; + + gog->num_of_gops = 0; + gog->num_of_counting_gops = 0; + gog->num_of_released_gops = 0; + + gog->gog_keys = g_ptr_array_new(); + + adopt_gop(gog,gop); + + return gog; +} + +static void apply_transforms(GPtrArray* transforms, AVPL* avpl) { + AVPL_Transf* transform = NULL; + guint i; + + for (i = 0; i < transforms->len; i++) { + transform = (AVPL_Transf *)g_ptr_array_index(transforms,i); + avpl_transform(avpl, transform); + } +} + + +/* applies the extras for which type to what avpl */ +static void apply_extras(AVPL* from, AVPL* to, AVPL* extras) { + AVPL* our_extras = new_avpl_loose_match("",from, extras, FALSE) ; + + if (our_extras) { + merge_avpl(to,our_extras,TRUE); + delete_avpl(our_extras,FALSE); + } +} + +static void gog_remove_keys (mate_gog* gog) { + gogkey* gog_key; + + while (gog->gog_keys->len) { + gog_key = (gogkey *)g_ptr_array_remove_index_fast(gog->gog_keys,0); + + if (g_hash_table_lookup(gog_key->cfg->gog_index,gog_key->key) == gog) { + g_hash_table_remove(gog_key->cfg->gog_index,gog_key->key); + } + + g_free(gog_key->key); + g_free(gog_key); + } + +} + +static void reanalyze_gop(mate_config* mc, mate_gop* gop) { + LoAL* gog_keys = NULL; + AVPL* curr_gogkey = NULL; + mate_cfg_gop* gop_cfg = NULL; + void* cookie = NULL; + AVPL* gogkey_match = NULL; + mate_gog* gog = gop->gog; + gogkey* gog_key; + + if ( ! gog ) return; + + gog->last_time = rd->now; + + dbg_print (dbg_gog,1,dbg_facility,"reanalyze_gop: %s:%d",gop->cfg->name,gop->id); + + apply_extras(gop->avpl,gog->avpl,gog->cfg->extra); + + /* XXX: Instead of using the length of the avpl to check if an avpl has changed, + which is not accurate at all, we should have apply_extras, + apply_transformations and other functions that can modify the avpl + to flag the avpl if it has changed, then we'll check for the flag + and clear it after analysis */ + + if (gog->last_n != gog->avpl->len) { + + dbg_print (dbg_gog,2,dbg_facility,"reanalyze_gop: gog has new attributes let's look for new keys"); + + gog_keys = gog->cfg->keys; + + while (( curr_gogkey = get_next_avpl(gog_keys,&cookie) )) { + gop_cfg = (mate_cfg_gop *)g_hash_table_lookup(mc->gopcfgs,curr_gogkey->name); + + if (( gogkey_match = new_avpl_pairs_match(gop_cfg->name, gog->avpl, curr_gogkey, TRUE, FALSE) )) { + + gog_key = g_new(gogkey, 1); + + gog_key->key = avpl_to_str(gogkey_match); + delete_avpl(gogkey_match,FALSE); + + gog_key->cfg = gop_cfg; + + if (g_hash_table_lookup(gop_cfg->gog_index,gog_key->key)) { + g_free(gog_key->key); + g_free(gog_key); + gog_key = NULL; + } + + if (! gog_key ) { + /* XXX: since these gogs actually share key info + we should try to merge (non released) gogs + that happen to have equal keys */ + } else { + dbg_print (dbg_gog,1,dbg_facility,"analyze_gop: new key for gog=%s:%d : %s",gog->cfg->name,gog->id,gog_key->key); + g_ptr_array_add(gog->gog_keys,gog_key); + g_hash_table_insert(gog_key->cfg->gog_index,gog_key->key,gog); + } + + } + } + + gog->last_n = gog->avpl->len; + } + + if (gog->num_of_released_gops == gog->num_of_counting_gops) { + gog->released = TRUE; + gog->expiration = gog->cfg->expiration + rd->now; + } else { + gog->released = FALSE; + } +} + +static void analyze_gop(mate_config* mc, mate_gop* gop) { + mate_cfg_gog* cfg = NULL; + LoAL* gog_keys = NULL; + AVPL* curr_gogkey = NULL; + void* cookie = NULL; + AVPL* gogkey_match = NULL; + mate_gog* gog = NULL; + gchar* key = NULL; + + if ( ! gop->gog ) { + /* no gog, let's either find one or create it if due */ + dbg_print (dbg_gog,1,dbg_facility,"analyze_gop: no gog"); + + gog_keys = (LoAL *)g_hash_table_lookup(mc->gogs_by_gopname,gop->cfg->name); + + if ( ! gog_keys ) { + dbg_print (dbg_gog,1,dbg_facility,"analyze_gop: no gog_keys for this gop"); + return; + } + + /* We have gog_keys! look for matching gogkeys */ + + dbg_print (dbg_gog,1,dbg_facility,"analyze_gop: got gog_keys: %s",gog_keys->name) ; + + while (( curr_gogkey = get_next_avpl(gog_keys,&cookie) )) { + if (( gogkey_match = new_avpl_pairs_match(gop->cfg->name, gop->avpl, curr_gogkey, TRUE, TRUE) )) { + + key = avpl_to_str(gogkey_match); + + dbg_print (dbg_gog,1,dbg_facility,"analyze_gop: got gogkey_match: %s",key); + + if (( gog = (mate_gog *)g_hash_table_lookup(gop->cfg->gog_index,key) )) { + dbg_print (dbg_gog,1,dbg_facility,"analyze_gop: got already a matching gog"); + + if (gog->num_of_counting_gops == gog->num_of_released_gops && gog->expiration < rd->now) { + dbg_print (dbg_gog,1,dbg_facility,"analyze_gop: this is a new gog, not the old one, let's create it"); + + gog_remove_keys(gog); + + new_gog(gog->cfg,gop); + + break; + } else { + dbg_print (dbg_gog,1,dbg_facility,"analyze_gop: this is our gog"); + + if (! gop->gog ) adopt_gop(gog,gop); + + break; + } + } else { + dbg_print (dbg_gog,1,dbg_facility,"analyze_gop: no such gog in hash, let's create a new %s",curr_gogkey->name); + + cfg = (mate_cfg_gog *)g_hash_table_lookup(mc->gogcfgs,curr_gogkey->name); + + if (cfg) { + gog = new_gog(cfg,gop); + gog->num_of_gops = 1; + + if (gop->cfg->start) { + gog->num_of_counting_gops = 1; + } + + } else { + dbg_print (dbg_gog,0,dbg_facility,"analyze_gop: no such gog_cfg: %s",curr_gogkey->name); + } + + break; + } + + /** Can't get here because of "breaks" above */ + ws_assert_not_reached(); + } + } /* while */ + + g_free(key); + key = NULL; + + if (gogkey_match) delete_avpl(gogkey_match,TRUE); + + reanalyze_gop(mc, gop); + } +} + + + +static void analyze_pdu(mate_config* mc, mate_pdu* pdu) { + /* TODO: + return a g_boolean to tell we've destroyed the pdu when the pdu is unnassigned + destroy the unassigned pdu + */ + mate_cfg_gop* cfg = NULL; + mate_gop* gop = NULL; + gchar* gop_key; + gchar* orig_gop_key = NULL; + AVPL* candidate_start = NULL; + AVPL* candidate_stop = NULL; + AVPL* is_start = NULL; + AVPL* is_stop = NULL; + AVPL* gopkey_match = NULL; + LoAL* gog_keys = NULL; + AVPL* curr_gogkey = NULL; + void* cookie = NULL; + AVPL* gogkey_match = NULL; + gchar* gogkey_str = NULL; + + dbg_print (dbg_gop,1,dbg_facility,"analyze_pdu: %s",pdu->cfg->name); + + if (! (cfg = (mate_cfg_gop *)g_hash_table_lookup(mc->gops_by_pduname,pdu->cfg->name)) ) + return; + + if ((gopkey_match = new_avpl_pairs_match("gop_key_match", pdu->avpl, cfg->key, TRUE, TRUE))) { + gop_key = avpl_to_str(gopkey_match); + + g_hash_table_lookup_extended(cfg->gop_index,(gconstpointer)gop_key,(gpointer *)&orig_gop_key,(gpointer *)&gop); + + if ( gop ) { + g_free(gop_key); + + /* is the gop dead ? */ + if ( ! gop->released && + ( ( gop->cfg->lifetime > 0.0 && gop->time_to_die >= rd->now) || + ( gop->cfg->idle_timeout > 0.0 && gop->time_to_timeout >= rd->now) ) ) { + dbg_print (dbg_gop,4,dbg_facility,"analyze_pdu: expiring released gop"); + gop->released = TRUE; + + if (gop->gog && gop->cfg->start) gop->gog->num_of_released_gops++; + } + + /* TODO: is the gop expired? */ + + gop_key = orig_gop_key; + + dbg_print (dbg_gop,2,dbg_facility,"analyze_pdu: got gop: %s",gop_key); + + if (( candidate_start = cfg->start )) { + + dbg_print (dbg_gop,2,dbg_facility,"analyze_pdu: got candidate start"); + + if (( is_start = new_avpl_pairs_match("", pdu->avpl, candidate_start, TRUE, FALSE) )) { + delete_avpl(is_start,FALSE); + if ( gop->released ) { + dbg_print (dbg_gop,3,dbg_facility,"analyze_pdu: start on released gop, let's create a new gop"); + + g_hash_table_remove(cfg->gop_index,gop_key); + gop->gop_key = NULL; + gop = new_gop(cfg,pdu,gop_key); + g_hash_table_insert(cfg->gop_index,gop_key,gop); + } else { + dbg_print (dbg_gop,1,dbg_facility,"analyze_pdu: duplicate start on gop"); + } + } + } + + pdu->gop = gop; + + if (gop->last_pdu) gop->last_pdu->next = pdu; + gop->last_pdu = pdu; + pdu->next = NULL; + pdu->time_in_gop = rd->now - gop->start_time; + + if (gop->released) pdu->after_release = TRUE; + + } else { + + dbg_print (dbg_gop,1,dbg_facility,"analyze_pdu: no gop already"); + + if ( ! cfg->start ) { + /* there is no GopStart, we'll check for matching GogKeys + if we have one we'll create the Gop */ + + apply_extras(pdu->avpl,gopkey_match,cfg->extra); + + gog_keys = (LoAL *)g_hash_table_lookup(mc->gogs_by_gopname,cfg->name); + + if (gog_keys) { + + while (( curr_gogkey = get_next_avpl(gog_keys,&cookie) )) { + if (( gogkey_match = new_avpl_pairs_match(cfg->name, gopkey_match, curr_gogkey, TRUE, FALSE) )) { + gogkey_str = avpl_to_str(gogkey_match); + + if (g_hash_table_lookup(cfg->gog_index,gogkey_str)) { + gop = new_gop(cfg,pdu,gop_key); + g_hash_table_insert(cfg->gop_index,gop_key,gop); + delete_avpl(gogkey_match,FALSE); + g_free(gogkey_str); + break; + } else { + delete_avpl(gogkey_match,FALSE); + g_free(gogkey_str); + } + } + } + + if ( ! gop ) { + g_free(gop_key); + delete_avpl(gopkey_match,TRUE); + return; + } + + } else { + g_free(gop_key); + delete_avpl(gopkey_match,TRUE); + return; + } + + } else { + candidate_start = cfg->start; + + if (( is_start = new_avpl_pairs_match("", pdu->avpl, candidate_start, TRUE, FALSE) )) { + delete_avpl(is_start,FALSE); + gop = new_gop(cfg,pdu,gop_key); + } else { + g_free(gop_key); + return; + } + + pdu->gop = gop; + } + } + + if (gop->last_pdu) gop->last_pdu->next = pdu; + gop->last_pdu = pdu; + pdu->next = NULL; + + pdu->time_in_gop = rd->now - gop->start_time; + + gop->num_of_pdus++; + gop->time_to_timeout = cfg->idle_timeout > 0.0 ? cfg->idle_timeout + rd->now : (float) -1.0 ; + + dbg_print (dbg_gop,4,dbg_facility,"analyze_pdu: merge with key"); + + merge_avpl(gop->avpl,gopkey_match,TRUE); + delete_avpl(gopkey_match,TRUE); + + dbg_print (dbg_gop,4,dbg_facility,"analyze_pdu: apply extras"); + + apply_extras(pdu->avpl,gop->avpl,gop->cfg->extra); + + gop->last_time = pdu->rel_time; + + if ( ! gop->released) { + candidate_stop = cfg->stop; + + if (candidate_stop) { + is_stop = new_avpl_pairs_match("", pdu->avpl, candidate_stop, TRUE, FALSE); + } else { + is_stop = new_avpl(""); + } + + if(is_stop) { + dbg_print (dbg_gop,1,dbg_facility,"analyze_pdu: is a `stop"); + delete_avpl(is_stop,FALSE); + + if (! gop->released) { + gop->released = TRUE; + gop->release_time = pdu->rel_time; + if (gop->gog && gop->cfg->start) gop->gog->num_of_released_gops++; + } + + pdu->is_stop = TRUE; + + } + } + + if (gop->last_n != gop->avpl->len) apply_transforms(gop->cfg->transforms,gop->avpl); + + gop->last_n = gop->avpl->len; + + if (gop->gog) { + reanalyze_gop(mc, gop); + } else { + analyze_gop(mc, gop); + } + + } else { + dbg_print (dbg_gop,4,dbg_facility,"analyze_pdu: no match for this pdu"); + + pdu->gop = NULL; + } +} + +static void get_pdu_fields(gpointer k, gpointer v, gpointer p) { + int hfid = *((int*) k); + gchar* name = (gchar*) v; + tmp_pdu_data* data = (tmp_pdu_data*) p; + GPtrArray* fis; + field_info* fi; + guint i,j; + mate_range* curr_range; + guint start; + guint end; + AVP* avp; + gchar* s; + + + fis = proto_get_finfo_ptr_array(data->tree, hfid); + + if (fis) { + for (i = 0; i < fis->len; i++) { + fi = (field_info*) g_ptr_array_index(fis,i); + + + start = fi->start; + end = fi->start + fi->length; + + dbg_print(dbg_pdu,5,dbg_facility,"get_pdu_fields: found field %s, %i-%i, length %i", fi->hfinfo->abbrev, start, end, fi->length); + + for (j = 0; j < data->ranges->len; j++) { + + curr_range = (mate_range*) g_ptr_array_index(data->ranges,j); + + if (curr_range->end >= end && curr_range->start <= start) { + avp = new_avp_from_finfo(name, fi); + + if (*dbg_pdu > 4) { + s = avp_to_str(avp); + dbg_print(dbg_pdu,0,dbg_facility,"get_pdu_fields: got %s",s); + g_free(s); + } + + if (! insert_avp(data->pdu->avpl,avp) ) { + delete_avp(avp); + } + + } + } + } + } +} + +static void ptr_array_free(gpointer data, gpointer user_data _U_) +{ + g_free(data); +} + +static mate_pdu* new_pdu(mate_cfg_pdu* cfg, guint32 framenum, field_info* proto, proto_tree* tree) { + mate_pdu* pdu = (mate_pdu*)g_slice_new(mate_max_size); + field_info* cfi; + GPtrArray* ptrs; + mate_range* range; + mate_range* proto_range; + tmp_pdu_data data; + guint i,j; + gint min_dist; + field_info* range_fi; + gint32 last_start; + gint32 first_end; + gint32 curr_end; + int hfid; + + dbg_print (dbg_pdu,1,dbg_facility,"new_pdu: type=%s framenum=%i",cfg->name,framenum); + + pdu->id = ++(cfg->last_id); + pdu->cfg = cfg; + + pdu->avpl = new_avpl(cfg->name); + + pdu->frame = framenum; + pdu->next_in_frame = NULL; + pdu->rel_time = rd->now; + + pdu->gop = NULL; + pdu->next = NULL; + pdu->time_in_gop = -1.0f; + + pdu->first = FALSE; + pdu->is_start = FALSE; + pdu->is_stop = FALSE; + pdu->after_release = FALSE; + + data.ranges = g_ptr_array_new(); + data.pdu = pdu; + data.tree = tree; + + /* first we create the proto range */ + proto_range = g_new(mate_range, 1); + proto_range->start = proto->start; + proto_range->end = proto->start + proto->length; + g_ptr_array_add(data.ranges,proto_range); + + dbg_print(dbg_pdu,3,dbg_facility,"new_pdu: proto range %u-%u",proto_range->start,proto_range->end); + + last_start = proto_range->start; + + /* we move forward in the tranport */ + for (i = cfg->transport_ranges->len; i--; ) { + hfid = *((int*)g_ptr_array_index(cfg->transport_ranges,i)); + ptrs = proto_get_finfo_ptr_array(tree, hfid); + min_dist = 99999; + range_fi = NULL; + + if (ptrs) { + for (j=0; j < ptrs->len; j++) { + cfi = (field_info*) g_ptr_array_index(ptrs,j); + if (cfi->start < last_start && min_dist >= (last_start - cfi->start) ) { + range_fi = cfi; + min_dist = last_start - cfi->start; + } + } + + if ( range_fi ) { + range = (mate_range *)g_malloc(sizeof(*range)); + range->start = range_fi->start; + range->end = range_fi->start + range_fi->length; + g_ptr_array_add(data.ranges,range); + + last_start = range_fi->start; + + dbg_print(dbg_pdu,3,dbg_facility,"new_pdu: transport(%i) range %i-%i",hfid,range->start,range->end); + } else { + /* we missed a range */ + dbg_print(dbg_pdu,6,dbg_facility,"new_pdu: transport(%i) missed",hfid); + } + + } + } + + if (cfg->payload_ranges) { + + first_end = proto_range->end; + + for (i = 0 ; i < cfg->payload_ranges->len; i++) { + hfid = *((int*)g_ptr_array_index(cfg->payload_ranges,i)); + ptrs = proto_get_finfo_ptr_array(tree, hfid); + min_dist = 99999; + range_fi = NULL; + + if (ptrs) { + for (j=0; j < ptrs->len; j++) { + cfi = (field_info*) g_ptr_array_index(ptrs,j); + curr_end = cfi->start + cfi->length; + if (curr_end > first_end && min_dist >= (curr_end - first_end) ) { + range_fi = cfi; + min_dist = curr_end - first_end; + } + } + + if ( range_fi ) { + range = (mate_range *)g_malloc(sizeof(*range)); + range->start = range_fi->start; + range->end = range_fi->start + range_fi->length; + g_ptr_array_add(data.ranges,range); + + dbg_print(dbg_pdu,3,dbg_facility,"new_pdu: payload(%i) range %i-%i",hfid,range->start,range->end); + } else { + /* we missed a range */ + dbg_print(dbg_pdu,5,dbg_facility,"new_pdu: payload(%i) missed",hfid); + } + + } + } + } + + g_hash_table_foreach(cfg->hfids_attr,get_pdu_fields,&data); + + apply_transforms(pdu->cfg->transforms,pdu->avpl); + + g_ptr_array_foreach(data.ranges, ptr_array_free, NULL); + g_ptr_array_free(data.ranges,TRUE); + + return pdu; +} + + +extern void mate_analyze_frame(mate_config *mc, packet_info *pinfo, proto_tree* tree) { + mate_cfg_pdu* cfg; + GPtrArray* protos; + field_info* proto; + guint i,j; + AVPL* criterium_match; + + mate_pdu* pdu = NULL; + mate_pdu* last = NULL; + + rd->now = (float) nstime_to_sec(&pinfo->rel_ts); + + if ( proto_tracking_interesting_fields(tree) + && rd->highest_analyzed_frame < pinfo->num ) { + for ( i = 0; i < mc->pducfglist->len; i++ ) { + + cfg = (mate_cfg_pdu *)g_ptr_array_index(mc->pducfglist,i); + + dbg_print (dbg_pdu,4,dbg_facility,"mate_analyze_frame: trying to extract: %s",cfg->name); + protos = proto_get_finfo_ptr_array(tree, cfg->hfid_proto); + + if (protos) { + pdu = NULL; + + for (j = 0; j < protos->len; j++) { + + dbg_print (dbg_pdu,3,dbg_facility,"mate_analyze_frame: found matching proto, extracting: %s",cfg->name); + + proto = (field_info*) g_ptr_array_index(protos,j); + pdu = new_pdu(cfg, pinfo->num, proto, tree); + + if (cfg->criterium) { + criterium_match = new_avpl_from_match(cfg->criterium_match_mode,"",pdu->avpl,cfg->criterium,FALSE); + + if (criterium_match) { + delete_avpl(criterium_match,FALSE); + } + + if ( (criterium_match && cfg->criterium_accept_mode == REJECT_MODE ) + || ( ! criterium_match && cfg->criterium_accept_mode == ACCEPT_MODE )) { + + delete_avpl(pdu->avpl,TRUE); + g_slice_free(mate_max_size,(mate_max_size*)pdu); + pdu = NULL; + + continue; + } + } + + analyze_pdu(mc, pdu); + + if ( ! pdu->gop && cfg->drop_unassigned) { + delete_avpl(pdu->avpl,TRUE); + g_slice_free(mate_max_size,(mate_max_size*)pdu); + pdu = NULL; + continue; + } + + if ( cfg->discard ) { + delete_avpl(pdu->avpl,TRUE); + pdu->avpl = NULL; + } + + if (!last) { + g_hash_table_insert(rd->frames,GINT_TO_POINTER(pinfo->num),pdu); + last = pdu; + } else { + last->next_in_frame = pdu; + last = pdu; + } + + } + + if ( pdu && cfg->last_extracted ) break; + } + } + + rd->highest_analyzed_frame = pinfo->num; + } +} + +extern mate_pdu* mate_get_pdus(guint32 framenum) { + + if (rd) { + return (mate_pdu*) g_hash_table_lookup(rd->frames,GUINT_TO_POINTER(framenum)); + } else { + return NULL; + } +} + +/* + * Editor modelines - https://www.wireshark.org/tools/modelines.html + * + * Local variables: + * c-basic-offset: 8 + * tab-width: 8 + * indent-tabs-mode: t + * End: + * + * vi: set shiftwidth=8 tabstop=8 noexpandtab: + * :indentSize=8:tabSize=8:noTabs=false: + */ diff --git a/plugins/epan/mate/mate_setup.c b/plugins/epan/mate/mate_setup.c new file mode 100644 index 00000000..eef97643 --- /dev/null +++ b/plugins/epan/mate/mate_setup.c @@ -0,0 +1,667 @@ +/* mate_setup.c + * MATE -- Meta Analysis Tracing Engine + * + * Copyright 2004, Luis E. Garcia Ontanon <luis@ontanon.org> + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1998 Gerald Combs + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "config.h" + +#include "mate.h" + +/* appends the formatted string to the current error log */ +static void report_error(mate_config* mc, const gchar* fmt, ...) { + static gchar error_buffer[DEBUG_BUFFER_SIZE]; + + va_list list; + + va_start( list, fmt ); + vsnprintf(error_buffer,DEBUG_BUFFER_SIZE,fmt,list); + va_end( list ); + + g_string_append(mc->config_error,error_buffer); + g_string_append_c(mc->config_error,'\n'); + +} + +/* creates a blank pdu config + is going to be called only by the grammar + which will set all those elements that aren't set here */ +extern mate_cfg_pdu* new_pducfg(mate_config* mc, gchar* name) { + mate_cfg_pdu* cfg = g_new(mate_cfg_pdu, 1); + + cfg->name = g_strdup(name); + cfg->last_id = 0; + + cfg->items = g_hash_table_new(g_direct_hash,g_direct_equal); + cfg->transforms = NULL; + + cfg->hfid = -1; + + cfg->hfid_pdu_rel_time = -1; + cfg->hfid_pdu_time_in_gop = -1; + + cfg->my_hfids = g_hash_table_new(g_str_hash,g_str_equal); + + cfg->ett = -1; + cfg->ett_attr = -1; + + cfg->criterium = NULL; + cfg->criterium_match_mode = AVPL_NO_MATCH; + cfg->criterium_accept_mode = ACCEPT_MODE; + + g_ptr_array_add(mc->pducfglist,(gpointer) cfg); + g_hash_table_insert(mc->pducfgs,(gpointer) cfg->name,(gpointer) cfg); + + cfg->hfids_attr = g_hash_table_new(g_int_hash,g_int_equal); + + return cfg; +} + +extern mate_cfg_gop* new_gopcfg(mate_config* mc, gchar* name) { + mate_cfg_gop* cfg = g_new(mate_cfg_gop, 1); + + cfg->name = g_strdup(name); + cfg->last_id = 0; + + cfg->items = g_hash_table_new(g_direct_hash,g_direct_equal); + cfg->transforms = NULL; + + cfg->extra = new_avpl("extra"); + + cfg->hfid = -1; + + cfg->ett = -1; + cfg->ett_attr = -1; + cfg->ett_times = -1; + cfg->ett_children = -1; + + cfg->hfid_start_time = -1; + cfg->hfid_stop_time = -1; + cfg->hfid_last_time = -1; + + cfg->hfid_gop_pdu = -1; + cfg->hfid_gop_num_pdus = -1; + + cfg->my_hfids = g_hash_table_new(g_str_hash,g_str_equal); + + cfg->gop_index = g_hash_table_new(g_str_hash,g_str_equal); + cfg->gog_index = g_hash_table_new(g_str_hash,g_str_equal); + + g_hash_table_insert(mc->gopcfgs,(gpointer) cfg->name, (gpointer) cfg); + + return cfg; +} + +extern mate_cfg_gog* new_gogcfg(mate_config* mc, gchar* name) { + mate_cfg_gog* cfg = g_new(mate_cfg_gog, 1); + + cfg->name = g_strdup(name); + cfg->last_id = 0; + + cfg->items = g_hash_table_new(g_direct_hash,g_direct_equal); + cfg->transforms = NULL; + + cfg->extra = new_avpl("extra"); + + cfg->my_hfids = g_hash_table_new(g_str_hash,g_str_equal); + cfg->hfid = -1; + + cfg->ett = -1; + cfg->ett_attr = -1; + cfg->ett_times = -1; + cfg->ett_children = -1; + cfg->ett_gog_gop = -1; + + cfg->hfid_gog_num_of_gops = -1; + cfg->hfid_gog_gop = -1; + cfg->hfid_gog_gopstart = -1; + cfg->hfid_gog_gopstop = -1; + + cfg->hfid_start_time = -1; + cfg->hfid_stop_time = -1; + cfg->hfid_last_time = -1; + + g_hash_table_insert(mc->gogcfgs,(gpointer) cfg->name, (gpointer) cfg); + + return cfg; +} + +extern gboolean add_hfid(mate_config* mc, header_field_info* hfi, gchar* how, GHashTable* where) { + header_field_info* first_hfi = NULL; + gboolean exists = FALSE; + gchar* as; + gchar* h; + int* ip; + + while(hfi) { + first_hfi = hfi; + hfi = (hfi->same_name_prev_id != -1) ? proto_registrar_get_nth(hfi->same_name_prev_id) : NULL; + } + + hfi = first_hfi; + + while (hfi) { + exists = TRUE; + ip = g_new(int, 1); + + *ip = hfi->id; + + if (( as = (gchar *)g_hash_table_lookup(where,ip) )) { + g_free(ip); + if (! g_str_equal(as,how)) { + report_error(mc, + "MATE Error: add field to Pdu: attempt to add %s(%i) as %s" + " failed: field already added as '%s'",hfi->abbrev,hfi->id,how,as); + return FALSE; + } + } else { + h = g_strdup(how); + g_hash_table_insert(where,ip,h); + } + + hfi = hfi->same_name_next; + + } + + if (! exists) { + report_error(mc, "MATE Error: cannot find field for attribute %s",how); + } + return exists; +} + +#if 0 +/* + * XXX - where is this suposed to be used? + */ +extern gchar* add_ranges(mate_config* mc, gchar* range,GPtrArray* range_ptr_arr) { + gchar** ranges; + guint i; + header_field_info* hfi; + int* hfidp; + + ranges = g_strsplit(range,"/",0); + + if (ranges) { + for (i=0; ranges[i]; i++) { + hfi = proto_registrar_get_byname(ranges[i]); + if (hfi) { + hfidp = g_new(int, 1); + *hfidp = hfi->id; + g_ptr_array_add(range_ptr_arr,(gpointer)hfidp); + } else { + g_strfreev(ranges); + return ws_strdup_printf("no such proto: '%s'",ranges[i]); + } + } + + g_strfreev(ranges); + } + + return NULL; +} +#endif + +static void new_attr_hfri(mate_config* mc, gchar* item_name, GHashTable* hfids, gchar* name) { + int* p_id = g_new(int, 1); + hf_register_info hfri; + + memset(&hfri, 0, sizeof hfri); + *p_id = -1; + hfri.p_id = p_id; + hfri.hfinfo.name = g_strdup(name); + hfri.hfinfo.abbrev = ws_strdup_printf("mate.%s.%s",item_name,name); + hfri.hfinfo.type = FT_STRING; + hfri.hfinfo.display = BASE_NONE; + hfri.hfinfo.strings = NULL; + hfri.hfinfo.bitmask = 0; + hfri.hfinfo.blurb = ws_strdup_printf("%s attribute of %s",name,item_name); + + *p_id = -1; + g_hash_table_insert(hfids,name,p_id); + g_array_append_val(mc->hfrs,hfri); + +} + +typedef struct { + mate_config* mc; + mate_cfg_pdu* cfg; +} analyze_pdu_hfids_arg; + +static void analyze_pdu_hfids(gpointer k, gpointer v, gpointer p) { + analyze_pdu_hfids_arg* argp = (analyze_pdu_hfids_arg*)p; + mate_config* mc = argp->mc; + mate_cfg_pdu* cfg = argp->cfg; + new_attr_hfri(mc, cfg->name,cfg->my_hfids,(gchar*) v); + + /* + * Add this hfid to our table of wanted hfids. + */ + mc->wanted_hfids = g_array_append_val(mc->wanted_hfids, *(int *)k); + mc->num_fields_wanted++; +} + +static void analyze_transform_hfrs(mate_config* mc, gchar* name, GPtrArray* transforms, GHashTable* hfids) { + guint i; + void* cookie = NULL; + AVPL_Transf* t; + AVP* avp; + + for (i=0; i < transforms->len;i++) { + for (t = (AVPL_Transf *)g_ptr_array_index(transforms,i); t; t=t->next ) { + cookie = NULL; + while(( avp = get_next_avp(t->replace,&cookie) )) { + if (! g_hash_table_lookup(hfids,avp->n)) { + new_attr_hfri(mc, name,hfids,avp->n); + } + } + } + } +} + +static void analyze_pdu_config(mate_config* mc, mate_cfg_pdu* cfg) { + hf_register_info hfri = { NULL, {NULL, NULL, FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL}}; + gint* ett; + analyze_pdu_hfids_arg arg; + + hfri.p_id = &(cfg->hfid); + hfri.hfinfo.name = g_strdup(cfg->name); + hfri.hfinfo.abbrev = ws_strdup_printf("mate.%s",cfg->name); + hfri.hfinfo.blurb = ws_strdup_printf("%s id",cfg->name); + hfri.hfinfo.type = FT_UINT32; + hfri.hfinfo.display = BASE_DEC; + + g_array_append_val(mc->hfrs,hfri); + + hfri.p_id = &(cfg->hfid_pdu_rel_time); + hfri.hfinfo.name = ws_strdup_printf("%s time",cfg->name); + hfri.hfinfo.abbrev = ws_strdup_printf("mate.%s.RelativeTime",cfg->name); + hfri.hfinfo.type = FT_FLOAT; + hfri.hfinfo.display = BASE_NONE; + hfri.hfinfo.blurb = "Seconds passed since the start of capture"; + + g_array_append_val(mc->hfrs,hfri); + + hfri.p_id = &(cfg->hfid_pdu_time_in_gop); + hfri.hfinfo.name = ws_strdup_printf("%s time since beginning of Gop",cfg->name); + hfri.hfinfo.abbrev = ws_strdup_printf("mate.%s.TimeInGop",cfg->name); + hfri.hfinfo.type = FT_FLOAT; + hfri.hfinfo.display = BASE_NONE; + hfri.hfinfo.blurb = "Seconds passed since the start of the GOP"; + + g_array_append_val(mc->hfrs,hfri); + + arg.mc = mc; + arg.cfg = cfg; + g_hash_table_foreach(cfg->hfids_attr,analyze_pdu_hfids,&arg); + + /* Add the hfids of transport protocols as wanted hfids */ + for (guint i = 0; i < cfg->transport_ranges->len; i++) { + int hfid = *((int*)g_ptr_array_index(cfg->transport_ranges,i)); + mc->wanted_hfids = g_array_append_val(mc->wanted_hfids, hfid); + mc->num_fields_wanted++; + } + + ett = &cfg->ett; + g_array_append_val(mc->ett,ett); + + ett = &cfg->ett_attr; + g_array_append_val(mc->ett,ett); + + analyze_transform_hfrs(mc, cfg->name,cfg->transforms,cfg->my_hfids); +} + +static void analyze_gop_config(gpointer k _U_, gpointer v, gpointer p) { + mate_config* mc = (mate_config*)p; + mate_cfg_gop* cfg = (mate_cfg_gop *)v; + void* cookie = NULL; + AVP* avp; + gint* ett; + hf_register_info hfri = { NULL, {NULL, NULL, FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL}}; + + hfri.p_id = &(cfg->hfid); + hfri.hfinfo.name = g_strdup(cfg->name); + hfri.hfinfo.abbrev = ws_strdup_printf("mate.%s",cfg->name); + hfri.hfinfo.blurb = ws_strdup_printf("%s id",cfg->name); + hfri.hfinfo.type = FT_UINT32; + hfri.hfinfo.display = BASE_DEC; + + g_array_append_val(mc->hfrs,hfri); + + hfri.p_id = &(cfg->hfid_start_time); + hfri.hfinfo.name = ws_strdup_printf("%s start time",cfg->name); + hfri.hfinfo.abbrev = ws_strdup_printf("mate.%s.StartTime",cfg->name); + hfri.hfinfo.type = FT_FLOAT; + hfri.hfinfo.display = BASE_NONE; + hfri.hfinfo.blurb = ws_strdup_printf("Seconds passed since the beginning of capture to the start of this %s",cfg->name); + + g_array_append_val(mc->hfrs,hfri); + + hfri.p_id = &(cfg->hfid_stop_time); + hfri.hfinfo.name = ws_strdup_printf("%s hold time",cfg->name); + hfri.hfinfo.abbrev = ws_strdup_printf("mate.%s.Time",cfg->name); + hfri.hfinfo.blurb = ws_strdup_printf("Duration in seconds from start to stop of this %s",cfg->name); + + g_array_append_val(mc->hfrs,hfri); + + hfri.p_id = &(cfg->hfid_last_time); + hfri.hfinfo.name = ws_strdup_printf("%s duration",cfg->name); + hfri.hfinfo.abbrev = ws_strdup_printf("mate.%s.Duration",cfg->name); + hfri.hfinfo.blurb = ws_strdup_printf("Time passed between the start of this %s and the last pdu assigned to it",cfg->name); + + g_array_append_val(mc->hfrs,hfri); + + hfri.p_id = &(cfg->hfid_gop_num_pdus); + hfri.hfinfo.name = ws_strdup_printf("%s number of PDUs",cfg->name); + hfri.hfinfo.abbrev = ws_strdup_printf("mate.%s.NumOfPdus",cfg->name); + hfri.hfinfo.blurb = ws_strdup_printf("Number of PDUs assigned to this %s",cfg->name); + hfri.hfinfo.type = FT_UINT32; + hfri.hfinfo.display = BASE_DEC; + + g_array_append_val(mc->hfrs,hfri); + + hfri.p_id = &(cfg->hfid_gop_pdu); + hfri.hfinfo.name = ws_strdup_printf("A PDU of %s",cfg->name); + hfri.hfinfo.abbrev = ws_strdup_printf("mate.%s.Pdu",cfg->name); + hfri.hfinfo.blurb = ws_strdup_printf("A PDU assigned to this %s",cfg->name); + + if (cfg->pdu_tree_mode == GOP_FRAME_TREE) { + hfri.hfinfo.type = FT_FRAMENUM; + hfri.hfinfo.display = BASE_NONE; + g_array_append_val(mc->hfrs,hfri); + } else if (cfg->pdu_tree_mode == GOP_PDU_TREE) { + hfri.hfinfo.type = FT_UINT32; + g_array_append_val(mc->hfrs,hfri); + } else { + cfg->pdu_tree_mode = GOP_NO_TREE; + } + + while(( avp = get_next_avp(cfg->key,&cookie) )) { + if (! g_hash_table_lookup(cfg->my_hfids,avp->n)) { + new_attr_hfri(mc, cfg->name,cfg->my_hfids,avp->n); + } + } + + if(cfg->start) { + cookie = NULL; + while(( avp = get_next_avp(cfg->start,&cookie) )) { + if (! g_hash_table_lookup(cfg->my_hfids,avp->n)) { + new_attr_hfri(mc, cfg->name,cfg->my_hfids,avp->n); + } + } + } + + if (cfg->stop) { + cookie = NULL; + while(( avp = get_next_avp(cfg->stop,&cookie) )) { + if (! g_hash_table_lookup(cfg->my_hfids,avp->n)) { + new_attr_hfri(mc, cfg->name,cfg->my_hfids,avp->n); + } + } + } + + cookie = NULL; + while(( avp = get_next_avp(cfg->extra,&cookie) )) { + if (! g_hash_table_lookup(cfg->my_hfids,avp->n)) { + new_attr_hfri(mc, cfg->name,cfg->my_hfids,avp->n); + } + } + + analyze_transform_hfrs(mc, cfg->name,cfg->transforms,cfg->my_hfids); + + ett = &cfg->ett; + g_array_append_val(mc->ett,ett); + + ett = &cfg->ett_attr; + g_array_append_val(mc->ett,ett); + + ett = &cfg->ett_times; + g_array_append_val(mc->ett,ett); + + ett = &cfg->ett_children; + g_array_append_val(mc->ett,ett); + + g_hash_table_insert(mc->gops_by_pduname,cfg->name,cfg); +} + +static void analyze_gog_config(gpointer k _U_, gpointer v, gpointer p) { + mate_config* mc = (mate_config*)p; + mate_cfg_gog* cfg = (mate_cfg_gog *)v; + void* avp_cookie; + void* avpl_cookie; + AVP* avp; + AVPL* avpl; + AVPL* gopkey_avpl; + AVPL* key_avps; + LoAL* gog_keys = NULL; + hf_register_info hfri = { NULL, {NULL, NULL, FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL}}; + gint* ett; + + /* create the hf array for this gog */ + hfri.p_id = &(cfg->hfid); + hfri.hfinfo.name = g_strdup(cfg->name); + hfri.hfinfo.abbrev = ws_strdup_printf("mate.%s",cfg->name); + hfri.hfinfo.blurb = ws_strdup_printf("%s Id",cfg->name); + hfri.hfinfo.type = FT_UINT32; + hfri.hfinfo.display = BASE_DEC; + + g_array_append_val(mc->hfrs,hfri); + + hfri.p_id = &(cfg->hfid_gog_num_of_gops); + hfri.hfinfo.name = "number of GOPs"; + hfri.hfinfo.abbrev = ws_strdup_printf("mate.%s.NumOfGops",cfg->name); + hfri.hfinfo.type = FT_UINT32; + hfri.hfinfo.display = BASE_DEC; + hfri.hfinfo.blurb = ws_strdup_printf("Number of GOPs assigned to this %s",cfg->name); + + g_array_append_val(mc->hfrs,hfri); + + hfri.p_id = &(cfg->hfid_gog_gopstart); + hfri.hfinfo.name = "GopStart frame"; + hfri.hfinfo.abbrev = ws_strdup_printf("mate.%s.GopStart",cfg->name); + hfri.hfinfo.type = FT_FRAMENUM; + hfri.hfinfo.display = BASE_NONE; + hfri.hfinfo.blurb = g_strdup("The start frame of a GOP"); + + g_array_append_val(mc->hfrs,hfri); + + hfri.p_id = &(cfg->hfid_gog_gopstop); + hfri.hfinfo.name = "GopStop frame"; + hfri.hfinfo.abbrev = ws_strdup_printf("mate.%s.GopStop",cfg->name); + hfri.hfinfo.type = FT_FRAMENUM; + hfri.hfinfo.display = BASE_NONE; + hfri.hfinfo.blurb = g_strdup("The stop frame of a GOP"); + + g_array_append_val(mc->hfrs,hfri); + + hfri.p_id = &(cfg->hfid_start_time); + hfri.hfinfo.name = ws_strdup_printf("%s start time",cfg->name); + hfri.hfinfo.abbrev = ws_strdup_printf("mate.%s.StartTime",cfg->name); + hfri.hfinfo.type = FT_FLOAT; + hfri.hfinfo.blurb = ws_strdup_printf("Seconds passed since the beginning of capture to the start of this %s",cfg->name); + + g_array_append_val(mc->hfrs,hfri); + + hfri.p_id = &(cfg->hfid_last_time); + hfri.hfinfo.name = ws_strdup_printf("%s duration",cfg->name); + hfri.hfinfo.abbrev = ws_strdup_printf("mate.%s.Duration",cfg->name); + hfri.hfinfo.blurb = ws_strdup_printf("Time passed between the start of this %s and the last pdu assigned to it",cfg->name); + + g_array_append_val(mc->hfrs,hfri); + + /* this might become mate.gogname.gopname */ + hfri.p_id = &(cfg->hfid_gog_gop); + hfri.hfinfo.name = "a GOP"; + hfri.hfinfo.abbrev = ws_strdup_printf("mate.%s.Gop",cfg->name); + hfri.hfinfo.type = FT_STRING; + hfri.hfinfo.display = BASE_NONE; + hfri.hfinfo.blurb = ws_strdup_printf("a GOPs assigned to this %s",cfg->name); + + g_array_append_val(mc->hfrs,hfri); + + /* index the keys of gog for every gop + and insert the avps of the keys to the hfarray */ + key_avps = new_avpl(""); + + avpl_cookie = NULL; + while (( avpl = get_next_avpl(cfg->keys,&avpl_cookie) )) { + + if (! ( gog_keys = (LoAL *)g_hash_table_lookup(mc->gogs_by_gopname,avpl->name))) { + gog_keys = new_loal(avpl->name); + g_hash_table_insert(mc->gogs_by_gopname,gog_keys->name,gog_keys); + } + + gopkey_avpl = new_avpl_from_avpl(cfg->name, avpl, TRUE); + loal_append(gog_keys,gopkey_avpl); + + avp_cookie = NULL; + while (( avp = get_next_avp(avpl,&avp_cookie) )) { + if (! g_hash_table_lookup(cfg->my_hfids,avp->n)) { + new_attr_hfri(mc, cfg->name,cfg->my_hfids,avp->n); + insert_avp(key_avps,avp); + } + } + } + + /* insert the extra avps to the hfarray */ + avp_cookie = NULL; + while (( avp = get_next_avp(cfg->extra,&avp_cookie) )) { + if (! g_hash_table_lookup(cfg->my_hfids,avp->n)) { + new_attr_hfri(mc, cfg->name,cfg->my_hfids,avp->n); + } + } + + /* every key_avp ios an extra as well. + one day every Member will have its own extras */ + merge_avpl(cfg->extra,key_avps,TRUE); + + + analyze_transform_hfrs(mc, cfg->name,cfg->transforms,cfg->my_hfids); + + ett = &cfg->ett; + g_array_append_val(mc->ett,ett); + + ett = &cfg->ett_attr; + g_array_append_val(mc->ett,ett); + + ett = &cfg->ett_children; + g_array_append_val(mc->ett,ett); + + ett = &cfg->ett_times; + g_array_append_val(mc->ett,ett); + + ett = &cfg->ett_gog_gop; + g_array_append_val(mc->ett,ett); + +} + +static void analyze_config(mate_config* mc) { + guint i; + + for (i=0; i < mc->pducfglist->len; i++) { + analyze_pdu_config(mc, (mate_cfg_pdu*) g_ptr_array_index(mc->pducfglist,i)); + } + + g_hash_table_foreach(mc->gopcfgs,analyze_gop_config,mc); + g_hash_table_foreach(mc->gogcfgs,analyze_gog_config,mc); + +} + +extern mate_config* mate_make_config(const gchar* filename, int mate_hfid) { + mate_config* mc; + gint* ett; + avp_init(); + + mc = g_new(mate_config, 1); + + mc->hfid_mate = mate_hfid; + + mc->wanted_hfids = g_array_new(FALSE, FALSE, (guint)sizeof(int)); + mc->num_fields_wanted = 0; + + mc->dbg_facility = NULL; + + mc->mate_lib_path = ws_strdup_printf("%s%c%s%c",get_datafile_dir(),DIR_SEP,DEFAULT_MATE_LIB_PATH,DIR_SEP); + + mc->pducfgs = g_hash_table_new(g_str_hash,g_str_equal); + mc->gopcfgs = g_hash_table_new(g_str_hash,g_str_equal); + mc->gogcfgs = g_hash_table_new(g_str_hash,g_str_equal); + mc->transfs = g_hash_table_new(g_str_hash,g_str_equal); + + mc->pducfglist = g_ptr_array_new(); + mc->gops_by_pduname = g_hash_table_new(g_str_hash,g_str_equal); + mc->gogs_by_gopname = g_hash_table_new(g_str_hash,g_str_equal); + + mc->ett_root = -1; + + mc->hfrs = g_array_new(FALSE,FALSE,sizeof(hf_register_info)); + mc->ett = g_array_new(FALSE,FALSE,sizeof(gint*)); + + mc->defaults.pdu.drop_unassigned = FALSE; + mc->defaults.pdu.discard = FALSE; + mc->defaults.pdu.last_extracted = FALSE; + mc->defaults.pdu.match_mode = AVPL_STRICT; + mc->defaults.pdu.replace_mode = AVPL_INSERT; + + /* gop prefs */ + mc->defaults.gop.expiration = -1.0f; + mc->defaults.gop.idle_timeout = -1.0f; + mc->defaults.gop.lifetime = -1.0f; + mc->defaults.gop.pdu_tree_mode = GOP_FRAME_TREE; + mc->defaults.gop.show_times = TRUE; + mc->defaults.gop.drop_unassigned = FALSE; + + /* gog prefs */ + mc->defaults.gog.expiration = 5.0f; + mc->defaults.gog.show_times = TRUE; + mc->defaults.gog.gop_tree_mode = GOP_BASIC_TREE; + + /* what to dbgprint */ + mc->dbg_lvl = 0; + mc->dbg_pdu_lvl = 0; + mc->dbg_gop_lvl = 0; + mc->dbg_gog_lvl = 0; + + mc->config_error = g_string_new(""); + + ett = &mc->ett_root; + g_array_append_val(mc->ett,ett); + + if ( mate_load_config(filename,mc) ) { + analyze_config(mc); + } else { + report_failure("MATE failed to configure!\n" + "It is recommended that you fix your config and restart Wireshark.\n" + "The reported error is:\n%s\n",mc->config_error->str); + + /* if (mc) destroy_mate_config(mc,FALSE); */ + return NULL; + } + + if (mc->num_fields_wanted == 0) { + /* We have no interest in any fields, so we have no + work to do. */ + /*destroy_mate_config(mc,FALSE);*/ + return NULL; + } + + return mc; +} + +/* + * Editor modelines - https://www.wireshark.org/tools/modelines.html + * + * Local variables: + * c-basic-offset: 8 + * tab-width: 8 + * indent-tabs-mode: t + * End: + * + * vi: set shiftwidth=8 tabstop=8 noexpandtab: + * :indentSize=8:tabSize=8:noTabs=false: + */ diff --git a/plugins/epan/mate/mate_util.c b/plugins/epan/mate/mate_util.c new file mode 100644 index 00000000..5b4d0780 --- /dev/null +++ b/plugins/epan/mate/mate_util.c @@ -0,0 +1,1690 @@ +/* mate_util.c + * MATE -- Meta Analysis Tracing Engine + * Utility Library: Single Copy Strings and Attribute Value Pairs + * + * Copyright 2004, Luis E. Garcia Ontanon <luis@ontanon.org> + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1998 Gerald Combs + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "config.h" + +#include "mate.h" +#include "mate_util.h" + +#include <errno.h> +#include <wsutil/file_util.h> + + +/*************************************************************************** +* dbg_print +*************************************************************************** +* This is the debug facility of the thing. +***************************************************************************/ + +/* dbg_print: + * which: a pointer to the current level of debugging for a feature + * how: the level over which this message should be printed out + * where: the file on which to print (ws_message if null) + * fmt, ...: what to print + */ + +void dbg_print(const gint* which, gint how, FILE* where, const gchar* fmt, ... ) { + static gchar debug_buffer[DEBUG_BUFFER_SIZE]; + va_list list; + + if ( ! which || *which < how ) return; + + va_start( list, fmt ); + vsnprintf(debug_buffer,DEBUG_BUFFER_SIZE,fmt,list); + va_end( list ); + + if (! where) { + ws_message("%s", debug_buffer); + } else { + fputs(debug_buffer,where); + fputs("\n",where); + } + +} + +/*************************************************************************** + * single copy strings + *************************************************************************** + * Strings repeat more often than don't. In order to save memory + * we'll keep only one copy of each as key to a hash with a count of + * subscribers as value. + ***************************************************************************/ + +/** + * scs_init: + * + * Initializes the scs hash. + **/ + +struct _scs_collection { + GHashTable* hash; /* key: a string value: guint number of subscribers */ +}; + +/* ToDo? free any string,ctr entries pointed to by the hash table ?? + * XXX: AFAIKT destroy_scs_collection() might be called only when reading a + * mate config file. Since reading a new config file can apparently currently + * only be done once after starting Wireshark, in theory this fcn + * currently should never be called since there will never be an existing + * scs_collection to be destroyed. + */ +static void destroy_scs_collection(SCS_collection* c) { + if (c->hash) g_hash_table_destroy(c->hash); +} + +static SCS_collection* scs_init(void) { + SCS_collection* c = g_new(SCS_collection, 1); + + c->hash = g_hash_table_new(g_str_hash,g_str_equal); + + return c; +} + + +/** + * subscribe: + * @param c the scs hash + * @param s a string + * + * Checks if the given string exists already and if so it increases the count of + * subsscribers and returns a pointer to the stored string. If not It will copy + * the given string store it in the hash and return the pointer to the copy. + * Remember, containment is handled internally, take care of your own strings. + * + * Return value: a pointer to the subscribed string. + **/ +gchar* scs_subscribe(SCS_collection* c, const gchar* s) { + gchar* orig = NULL; + guint* ip = NULL; + size_t len = 0; + + g_hash_table_lookup_extended(c->hash,(gconstpointer)s,(gpointer *)&orig,(gpointer *)&ip); + + if (ip) { + (*ip)++; + } else { + ip = g_slice_new(guint); + *ip = 0; + + len = strlen(s) + 1; + + if (len <= SCS_SMALL_SIZE) { + len = SCS_SMALL_SIZE; + } else if (len <= SCS_MEDIUM_SIZE) { + len = SCS_MEDIUM_SIZE; + } else if (len <= SCS_LARGE_SIZE) { + len = SCS_LARGE_SIZE; + } else if (len < SCS_HUGE_SIZE) { + len = SCS_HUGE_SIZE; + } else { + len = SCS_HUGE_SIZE; + ws_warning("mate SCS: string truncated due to huge size"); + } + + orig = (gchar *)g_slice_alloc(len); + (void) g_strlcpy(orig,s,len); + + g_hash_table_insert(c->hash,orig,ip); + } + + return orig; +} + +/** + * unsubscribe: + * @param c the scs hash + * @param s a string. + * + * decreases the count of subscribers, if zero frees the internal copy of + * the string. + **/ +void scs_unsubscribe(SCS_collection* c, gchar* s) { + gchar* orig = NULL; + guint* ip = NULL; + size_t len = 0xffff; + + g_hash_table_lookup_extended(c->hash,(gconstpointer)s,(gpointer *)&orig,(gpointer *)&ip); + + if (ip) { + if (*ip == 0) { + g_hash_table_remove(c->hash,orig); + + len = strlen(orig); + + if (len < SCS_SMALL_SIZE) { + len = SCS_SMALL_SIZE; + } else if (len < SCS_MEDIUM_SIZE) { + len = SCS_MEDIUM_SIZE; + } else if (len < SCS_LARGE_SIZE) { + len = SCS_LARGE_SIZE; + } else { + len = SCS_HUGE_SIZE; + } + + g_slice_free1(len, orig); + g_slice_free(guint,ip); + } + else { + (*ip)--; + } + } else { + ws_warning("unsubscribe: not subscribed"); + } +} + +/** + * scs_subscribe_printf: + * @param fmt a format string ... + * + * Formats the input and subscribes it. + * + * Return value: the stored copy of the formated string. + * + **/ +gchar* scs_subscribe_printf(SCS_collection* c, gchar* fmt, ...) { + va_list list; + static gchar buf[SCS_HUGE_SIZE]; + + va_start( list, fmt ); + vsnprintf(buf, SCS_HUGE_SIZE, fmt, list); + va_end( list ); + + return scs_subscribe(c,buf); +} + +/*************************************************************************** +* AVPs & Co. +*************************************************************************** +* The Thing operates mainly on avps, avpls and loals +* - attribute value pairs (two strings: the name and the value and an operator) +* - avp lists a somehow sorted list of avps +* - loal (list of avp lists) an arbitrarily sorted list of avpls +* +* +***************************************************************************/ + + +typedef union _any_avp_type { + AVP avp; + AVPN avpn; + AVPL avpl; + LoAL loal; + LoALnode loaln; +} any_avp_type; + + +static SCS_collection* avp_strings = NULL; + +#ifdef _AVP_DEBUGGING +static FILE* dbg_fp = NULL; + +static int dbg_level = 0; +static int* dbg = &dbg_level; + +static int dbg_avp_level = 0; +static int* dbg_avp = &dbg_avp_level; + +static int dbg_avp_op_level = 0; +static int* dbg_avp_op = &dbg_avp_op_level; + +static int dbg_avpl_level = 0; +static int* dbg_avpl = &dbg_avpl_level; + +static int dbg_avpl_op_level = 0; +static int* dbg_avpl_op = &dbg_avpl_op_level; + +/** + * setup_avp_debug: + * @param fp the file in which to send debugging output. + * @param general a pointer to the level of debugging of facility "general" + * @param avp a pointer to the level of debugging of facility "avp" + * @param avp_op a pointer to the level of debugging of facility "avp_op" + * @param avpl a pointer to the level of debugging of facility "avpl" + * @param avpl_op a pointer to the level of debugging of facility "avpl_op" + * + * If enabled sets up the debug facilities for the avp library. + * + **/ +extern void setup_avp_debug(FILE* fp, int* general, int* avp, int* avp_op, int* avpl, int* avpl_op) { + dbg_fp = fp; + dbg = general; + dbg_avp = avp; + dbg_avp_op = avp_op; + dbg_avpl = avpl; + dbg_avpl_op = avpl_op; +} + +#endif /* _AVP_DEBUGGING */ + +/** + * avp_init: + * + * (Re)Initializes the avp library. + * + **/ +extern void avp_init(void) { + + if (avp_strings) destroy_scs_collection(avp_strings); + avp_strings = scs_init(); + +} + +/** + * new_avp_from_finfo: + * @param name the name the avp will have. + * @param finfo the field_info from which to fetch the data. + * + * Creates an avp from a field_info record. + * + * Return value: a pointer to the newly created avp. + * + **/ +extern AVP* new_avp_from_finfo(const gchar* name, field_info* finfo) { + AVP* new_avp_val = (AVP*)g_slice_new(any_avp_type); + gchar* value; + gchar* repr; + + new_avp_val->n = scs_subscribe(avp_strings, name); + + repr = fvalue_to_string_repr(NULL, finfo->value, FTREPR_DISPLAY, finfo->hfinfo->display); + + if (repr) { + value = scs_subscribe(avp_strings, repr); + wmem_free(NULL, repr); +#ifdef _AVP_DEBUGGING + dbg_print (dbg_avp,2,dbg_fp,"new_avp_from_finfo: from string: %s",value); +#endif + } else { +#ifdef _AVP_DEBUGGING + dbg_print (dbg_avp,2,dbg_fp,"new_avp_from_finfo: a proto: %s",finfo->hfinfo->abbrev); +#endif + value = scs_subscribe(avp_strings, ""); + } + + new_avp_val->v = value; + + new_avp_val->o = '='; + +#ifdef _AVP_DEBUGGING + dbg_print (dbg_avp,1,dbg_fp,"new_avp_from_finfo: %p %s%c%s;",new_avp_val,new_avp_val->n,new_avp_val->o,new_avp_val->v); +#endif + + return new_avp_val; +} + + +/** + * new_avp: + * @param name the name the avp will have. + * @param value the value the avp will have. + * @param o the operator of this avp. + * + * Creates an avp given every parameter. + * + * Return value: a pointer to the newly created avp. + * + **/ +extern AVP* new_avp(const gchar* name, const gchar* value, gchar o) { + AVP* new_avp_val = (AVP*)g_slice_new(any_avp_type); + + new_avp_val->n = scs_subscribe(avp_strings, name); + new_avp_val->v = scs_subscribe(avp_strings, value); + new_avp_val->o = o; + +#ifdef _AVP_DEBUGGING + dbg_print(dbg_avp,1,dbg_fp,"new_avp_val: %p %s%c%s;",new_avp_val,new_avp_val->n,new_avp_val->o,new_avp_val->v); +#endif + return new_avp_val; +} + + +/** +* delete_avp: + * @param avp the avp to delete. + * + * Destroys an avp and releases the resources it uses. + * + **/ +extern void delete_avp(AVP* avp) { +#ifdef _AVP_DEBUGGING + dbg_print(dbg_avp,1,dbg_fp,"delete_avp: %p %s%c%s;",avp,avp->n,avp->o,avp->v); +#endif + + scs_unsubscribe(avp_strings, avp->n); + scs_unsubscribe(avp_strings, avp->v); + g_slice_free(any_avp_type,(any_avp_type*)avp); +} + + +/** +* avp_copy: + * @param from the avp to be copied. + * + * Creates an avp whose name op and value are copies of the given one. + * + * Return value: a pointer to the newly created avp. + * + **/ +extern AVP* avp_copy(AVP* from) { + AVP* new_avp_val = (AVP*)g_slice_new(any_avp_type); + + new_avp_val->n = scs_subscribe(avp_strings, from->n); + new_avp_val->v = scs_subscribe(avp_strings, from->v); + new_avp_val->o = from->o; + +#ifdef _AVP_DEBUGGING + dbg_print(dbg_avp,1,dbg_fp,"copy_avp: %p %s%c%s;",new_avp_val,new_avp_val->n,new_avp_val->o,new_avp_val->v); +#endif + + return new_avp_val; +} + +/** + * new_avpl: + * @param name the name the avpl will have. + * + * Creates an empty avpl. + * + * Return value: a pointer to the newly created avpl. + * + **/ +extern AVPL* new_avpl(const gchar* name) { + AVPL* new_avpl_p = (AVPL*)g_slice_new(any_avp_type); + +#ifdef _AVP_DEBUGGING + dbg_print(dbg_avpl_op,7,dbg_fp,"new_avpl_p: %p name=%s",new_avpl_p,name); +#endif + + new_avpl_p->name = name ? scs_subscribe(avp_strings, name) : scs_subscribe(avp_strings, ""); + new_avpl_p->len = 0; + new_avpl_p->null.avp = NULL; + new_avpl_p->null.next = &new_avpl_p->null; + new_avpl_p->null.prev = &new_avpl_p->null; + + + return new_avpl_p; +} + +extern void rename_avpl(AVPL* avpl, gchar* name) { + scs_unsubscribe(avp_strings,avpl->name); + avpl->name = scs_subscribe(avp_strings,name); +} + +/** + * insert_avp_before_node: + * @param avpl the avpl in which to insert. + * @param next_node the next node before which the new avpn has to be inserted. + * @param avp the avp to be inserted. + * @param copy_avp whether the original AVP or a copy thereof must be inserted. + * + * Pre-condition: the avp is sorted before before_avp and does not already exist + * in the avpl. + */ +static void insert_avp_before_node(AVPL* avpl, AVPN* next_node, AVP *avp, gboolean copy_avp) { + AVPN* new_avp_val = (AVPN*)g_slice_new(any_avp_type); + + new_avp_val->avp = copy_avp ? avp_copy(avp) : avp; + +#ifdef _AVP_DEBUGGING + dbg_print(dbg_avpl_op,7,dbg_fp,"new_avpn: %p",new_avp_val); + dbg_print(dbg_avpl,5,dbg_fp,"insert_avp: inserting %p in %p before %p;",avp,avpl,next_node); +#endif + + new_avp_val->next = next_node; + new_avp_val->prev = next_node->prev; + next_node->prev->next = new_avp_val; + next_node->prev = new_avp_val; + + avpl->len++; + +#ifdef _AVP_DEBUGGING + dbg_print(dbg_avpl,4,dbg_fp,"avpl: %p new len: %i",avpl,avpl->len); +#endif +} + +/** + * insert_avp: + * @param avpl the avpl in which to insert. + * @param avp the avp to be inserted. + * + * Inserts the given AVP into the given AVPL if an identical one isn't yet there. + * + * Return value: whether it was inserted or not. + * + * BEWARE: Check the return value, you might need to delete the avp if + * it is not inserted. + **/ +extern gboolean insert_avp(AVPL* avpl, AVP* avp) { + AVPN* c; + +#ifdef _AVP_DEBUGGING + dbg_print(dbg_avpl_op,4,dbg_fp,"insert_avp: %p %p %s%c%s;",avpl,avp,avp->n,avp->o,avp->v); +#endif + + /* get to the insertion point */ + for (c=avpl->null.next; c->avp; c = c->next) { + int name_diff = strcmp(avp->n, c->avp->n); + + if (name_diff == 0) { + int value_diff = strcmp(avp->v, c->avp->v); + + if (value_diff < 0) { + break; + } + + if (value_diff == 0) { + // ignore duplicate values, prevents (a=1, a=1) + // note that this is also used to insert + // conditions AVPs, so really check if the name, + // value and operator are all equal. + if (c->avp->o == avp->o && avp->o == AVP_OP_EQUAL) { + return FALSE; + } + } + } + + if (name_diff < 0) { + break; + } + } + + insert_avp_before_node(avpl, c, avp, FALSE); + + return TRUE; +} + +/** + * get_avp_by_name: + * @param avpl the avpl from which to try to get the avp. + * @param name the name of the avp we are looking for. + * @param cookie variable in which to store the state between calls. + * + * Gets pointer to the next avp whose name is given; uses cookie to store its + * state between calls. + * + * Return value: a pointer to the next matching avp if there's one, else NULL. + * + **/ +extern AVP* get_avp_by_name(AVPL* avpl, gchar* name, void** cookie) { + AVPN* curr; + AVPN* start = (AVPN*) *cookie; + +#ifdef _AVP_DEBUGGING + dbg_print(dbg_avpl_op,7,dbg_fp,"get_avp_by_name: entering: %p %s %p",avpl,name,*cookie); +#endif + + name = scs_subscribe(avp_strings, name); + + if (!start) start = avpl->null.next; + + for ( curr = start; curr->avp; curr = curr->next ) { + if ( curr->avp->n == name ) { + break; + } + } + + *cookie = curr; + +#ifdef _AVP_DEBUGGING + dbg_print(dbg_avpl_op,5,dbg_fp,"get_avp_by_name: got avp: %p",curr); +#endif + + scs_unsubscribe(avp_strings, name); + + return curr->avp; +} + +/** + * extract_avp_by_name: + * @param avpl the avpl from which to try to extract the avp. + * @param name the name of the avp we are looking for. + * + * Extracts from the avpl the next avp whose name is given; + * + * Return value: a pointer to extracted avp if there's one, else NULL. + * + **/ +extern AVP* extract_avp_by_name(AVPL* avpl, gchar* name) { + AVPN* curr; + AVP* avp = NULL; + +#ifdef _AVP_DEBUGGING + dbg_print(dbg_avpl_op,7,dbg_fp,"extract_avp_by_name: entering: %p %s",avpl,name); +#endif + + name = scs_subscribe(avp_strings, name); + + for ( curr = avpl->null.next; curr->avp; curr = curr->next ) { + if ( curr->avp->n == name ) { + break; + } + } + + scs_unsubscribe(avp_strings, name); + + if( ! curr->avp ) return NULL; + + curr->next->prev = curr->prev; + curr->prev->next = curr->next; + + avp = curr->avp; + + g_slice_free(any_avp_type,(any_avp_type*)curr); + + (avpl->len)--; + +#ifdef _AVP_DEBUGGING + dbg_print(dbg_avpl,4,dbg_fp,"avpl: %p new len: %i",avpl,avpl->len); +#endif + +#ifdef _AVP_DEBUGGING + dbg_print(dbg_avpl_op,5,dbg_fp,"extract_avp_by_name: got avp: %p",avp); +#endif + + return avp; +} + + +/** + * extract_first_avp: + * @param avpl the avpl from which to try to extract the avp. + * + * Extracts the fisrt avp from the avpl. + * + * Return value: a pointer to extracted avp if there's one, else NULL. + * + **/ +extern AVP* extract_first_avp(AVPL* avpl) { + AVP* avp; + AVPN* node; + +#ifdef _AVP_DEBUGGING + dbg_print(dbg_avpl_op,7,dbg_fp,"extract_first_avp: %p",avpl); +#endif + + node = avpl->null.next; + + avpl->null.next->prev = &avpl->null; + avpl->null.next = node->next; + + avp = node->avp; + + if (avp) { + g_slice_free(any_avp_type,(any_avp_type*)node); + (avpl->len)--; +#ifdef _AVP_DEBUGGING + dbg_print(dbg_avpl,4,dbg_fp,"avpl: %p new len: %i",avpl,avpl->len); +#endif + } + +#ifdef _AVP_DEBUGGING + dbg_print(dbg_avpl_op,5,dbg_fp,"extract_first_avp: got avp: %p",avp); +#endif + + return avp; + +} + + +/** + * extract_last_avp: + * @param avpl the avpl from which to try to extract the avp. + * + * Extracts the last avp from the avpl. + * + * Return value: a pointer to extracted avp if there's one, else NULL. + * + **/ +extern AVP* extract_last_avp(AVPL* avpl) { + AVP* avp; + AVPN* node; + + node = avpl->null.prev; + + avpl->null.prev->next = &avpl->null; + avpl->null.prev = node->prev; + + avp = node->avp; + + if (avp) { + g_slice_free(any_avp_type,(any_avp_type*)node); + (avpl->len)--; +#ifdef _AVP_DEBUGGING + dbg_print(dbg_avpl,4,dbg_fp,"avpl: %p new len: %i",avpl,avpl->len); +#endif + } + +#ifdef _AVP_DEBUGGING + dbg_print(dbg_avpl_op,5,dbg_fp,"extract_last_avp: got avp: %p",avp); +#endif + + return avp; + +} + + +/** + * delete_avpl: + * @param avpl the avpl from which to try to extract the avp. + * @param avps_too whether or not it should delete the avps as well. + * + * Destroys an avpl and releases the resources it uses. If told to do + * so releases the avps as well. + * + **/ +extern void delete_avpl(AVPL* avpl, gboolean avps_too) { + AVP* avp; +#ifdef _AVP_DEBUGGING + dbg_print(dbg_avpl,3,dbg_fp,"delete_avpl: %p",avpl); +#endif + + while(( avp = extract_last_avp(avpl))) { + if (avps_too) { + delete_avp(avp); + } + } + + scs_unsubscribe(avp_strings,avpl->name); + g_slice_free(any_avp_type,(any_avp_type*)avpl); +} + + + +/** + * get_next_avp: + * @param avpl the avpl from which to try to get the avps. + * @param cookie variable in which to store the state between calls. + * + * Iterates on an avpl to get its avps. + * + * Return value: a pointer to the next avp if there's one, else NULL. + * + **/ +extern AVP* get_next_avp(AVPL* avpl, void** cookie) { + AVPN* node; + +#ifdef _AVP_DEBUGGING + dbg_print(dbg_avpl_op,5,dbg_fp,"get_next_avp: avpl: %p avpn: %p",avpl,*cookie); +#endif + + if (*cookie) { + node = (AVPN*) *cookie; + } else { + node = avpl->null.next; + } + + *cookie = node->next; + +#ifdef _AVP_DEBUGGING + dbg_print(dbg_avpl_op,5,dbg_fp,"extract_last_avp: got avp: %p",node->avp); +#endif + + return node->avp; +} + +/** + * avpl_to_str: + * @param avpl the avpl to represent. + * + * Creates a newly allocated string containing a representation of an avpl. + * + * Return value: a pointer to the newly allocated string. + * + **/ +gchar* avpl_to_str(AVPL* avpl) { + AVPN* c; + GString* s = g_string_new(""); + gchar* avp_s; + gchar* r; + + for(c=avpl->null.next; c->avp; c = c->next) { + avp_s = avp_to_str(c->avp); + g_string_append_printf(s," %s;",avp_s); + g_free(avp_s); + } + + r = g_string_free(s,FALSE); + + /* g_strchug(r); ? */ + return r; +} + +extern gchar* avpl_to_dotstr(AVPL* avpl) { + AVPN* c; + GString* s = g_string_new(""); + gchar* avp_s; + gchar* r; + + for(c=avpl->null.next; c->avp; c = c->next) { + avp_s = avp_to_str(c->avp); + g_string_append_printf(s," .%s;",avp_s); + g_free(avp_s); + } + + r = g_string_free(s,FALSE); + + /* g_strchug(r); ? */ + return r; +} + +/** +* merge_avpl: + * @param dst the avpl in which to merge the avps. + * @param src the avpl from which to get the avps. + * @param copy_avps whether avps should be copied instead of referenced. + * + * Adds the avps of src that are not existent in dst into dst. + * + **/ +extern void merge_avpl(AVPL* dst, AVPL* src, gboolean copy_avps) { + AVPN* cd = NULL; + AVPN* cs = NULL; + +#ifdef _AVP_DEBUGGING + dbg_print(dbg_avpl_op,3,dbg_fp,"merge_avpl: %p %p",dst,src); +#endif + + cs = src->null.next; + cd = dst->null.next; + + while (cs->avp && cd->avp) { + + int name_diff = strcmp(cd->avp->n, cs->avp->n); + + if (name_diff < 0) { + // dest < source, advance dest to find a better place to insert + cd = cd->next; + } else if (name_diff > 0) { + // dest > source, so it can be definitely inserted here. + insert_avp_before_node(dst, cd, cs->avp, copy_avps); + cs = cs->next; + } else { + // attribute names are equal. Ignore duplicate values but ensure that other values are sorted. + int value_diff = strcmp(cd->avp->v, cs->avp->v); + + if (value_diff < 0) { + // dest < source, do not insert it yet + cd = cd->next; + } else if (value_diff > 0) { + // dest > source, insert AVP before the current dest AVP + insert_avp_before_node(dst, cd, cs->avp, copy_avps); + cs = cs->next; + } else { + // identical AVPs, do not create a duplicate. + cs = cs->next; + } + } + } + + // if there are remaing source AVPs while there are no more destination + // AVPs (cd now represents the NULL item, after the last item), append + // all remaining source AVPs to the end + while (cs->avp) { + insert_avp_before_node(dst, cd, cs->avp, copy_avps); + cs = cs->next; + } + +#ifdef _AVP_DEBUGGING + dbg_print(dbg_avpl_op,8,dbg_fp,"merge_avpl: done"); +#endif + + return; +} + + +/** + * new_avpl_from_avpl: + * @param name the name of the new avpl. + * @param avpl the avpl from which to get the avps. + * @param copy_avps whether avps should be copied instead of referenced. + * + * Creates a new avpl containing the same avps as the given avpl + * It will either reference or copie the avps. + * + * Return value: a pointer to the newly allocated string. + * + **/ +extern AVPL* new_avpl_from_avpl(const gchar* name, AVPL* avpl, gboolean copy_avps) { + AVPL* newavpl = new_avpl(name); + void* cookie = NULL; + AVP* avp; + AVP* copy; + +#ifdef _AVP_DEBUGGING + dbg_print(dbg_avpl_op,3,dbg_fp,"new_avpl_from_avpl: %p from=%p name='%s'",newavpl,avpl,name); +#endif + + while(( avp = get_next_avp(avpl,&cookie) )) { + if (copy_avps) { + copy = avp_copy(avp); + if ( ! insert_avp(newavpl,copy) ) { + delete_avp(copy); + } + } else { + insert_avp(newavpl,avp); + } + } + +#ifdef _AVP_DEBUGGING + dbg_print(dbg_avpl_op,8,dbg_fp,"new_avpl_from_avpl: done"); +#endif + + return newavpl; +} + +/** +* match_avp: + * @param src an src to be compared agains an "op" avp + * @param op the "op" avp that will be matched against the src avp + * + * Checks whether or not two avp's match. + * + * Return value: a pointer to the src avp if there's a match. + * + **/ +extern AVP* match_avp(AVP* src, AVP* op) { + gchar** splited; + int i; + gchar* p; + guint ls; + guint lo; + float fs = 0.0f; + float fo = 0.0f; + gboolean lower = FALSE; + +#ifdef _AVP_DEBUGGING + dbg_print(dbg_avpl_op,3,dbg_fp,"match_avp: %s%c%s; vs. %s%c%s;",src->n,src->o,src->v,op->n,op->o,op->v); +#endif + + if ( src->n != op->n ) { + return NULL; + } + + switch (op->o) { + case AVP_OP_EXISTS: + return src; + case AVP_OP_EQUAL: + return src->v == op->v ? src : NULL; + case AVP_OP_NOTEQUAL: + return !( src->v == op->v) ? src : NULL; + case AVP_OP_STARTS: + return strncmp(src->v,op->v,strlen(op->v)) == 0 ? src : NULL; + case AVP_OP_ONEOFF: + splited = g_strsplit(op->v,"|",0); + if (splited) { + for (i=0;splited[i];i++) { + if(g_str_equal(splited[i],src->v)) { + g_strfreev(splited); + return src; + } + } + g_strfreev(splited); + } + return NULL; + + case AVP_OP_LOWER: + lower = TRUE; + /* FALLTHRU */ + case AVP_OP_HIGHER: + + fs = (float) g_ascii_strtod(src->v, NULL); + fo = (float) g_ascii_strtod(op->v, NULL); + + if (lower) { + if (fs<fo) return src; + else return NULL; + } else { + if (fs>fo) return src; + else return NULL; + } + case AVP_OP_ENDS: + /* does this work? */ + ls = (guint) strlen(src->v); + lo = (guint) strlen(op->v); + + if ( ls < lo ) { + return NULL; + } else { + p = src->v + ( ls - lo ); + return g_str_equal(p,op->v) ? src : NULL; + } + + /* case AVP_OP_TRANSF: */ + /* return do_transform(src,op); */ + case AVP_OP_CONTAINS: + return g_strrstr(src->v, op->v) ? src : NULL;; + } + /* will never get here */ + return NULL; +} + + + +/** + * new_avpl_loose_match: + * @param name the name of the resulting avpl + * @param src the data AVPL to be matched against a condition AVPL + * @param op the conditions AVPL that will be matched against the data AVPL + * @param copy_avps whether the avps in the resulting avpl should be copied + * + * Creates a new AVP list containing all data AVPs that matched any of the + * conditions AVPs. If there are no matches, an empty list will be returned. + * + * Note: Loose will always be considered a successful match, it matches zero or + * more conditions. + */ +extern AVPL* new_avpl_loose_match(const gchar* name, + AVPL* src, + AVPL* op, + gboolean copy_avps) { + + AVPL* newavpl = new_avpl(scs_subscribe(avp_strings, name)); + AVPN* co = NULL; + AVPN* cs = NULL; + +#ifdef _AVP_DEBUGGING + dbg_print(dbg_avpl_op,3,dbg_fp,"new_avpl_loose_match: %p src=%p op=%p name='%s'",newavpl,src,op,name); +#endif + + + cs = src->null.next; + co = op->null.next; + while (cs->avp && co->avp) { + int name_diff = strcmp(co->avp->n, cs->avp->n); + + if (name_diff < 0) { + // op < source, op is not matching + co = co->next; + } else if (name_diff > 0) { + // op > source, source is not matching + cs = cs->next; + } else { + // attribute match found, let's see if there is any condition (op) that accepts this data AVP. + AVPN *cond = co; + do { + if (match_avp(cs->avp, cond->avp)) { + insert_avp_before_node(newavpl, newavpl->null.prev, cs->avp, copy_avps); + break; + } + cond = cond->next; + } while (cond->avp && cond->avp->n == cs->avp->n); + cs = cs->next; + } + } + + // return matches (possible none) + return newavpl; +} + +/** +* new_avpl_pairs_match: + * @param name the name of the resulting avpl + * @param src the data AVPL to be matched against a condition AVPL + * @param op the conditions AVPL that will be matched against the data AVPL + * @param strict TRUE if every condition must have a matching data AVP, FALSE if + * it is also acceptable that only one of the condition AVPs for the same + * attribute is matching. + * @param copy_avps whether the avps in the resulting avpl should be copied + * + * Creates an AVP list by matching pairs of conditions and data AVPs, returning + * the data AVPs. If strict is TRUE, then each condition must be paired with a + * matching data AVP. If strict is FALSE, then some conditions are allowed to + * fail when other conditions for the same attribute do have a match. Note that + * if the condition AVPL is empty, the result will be a match (an empty list). + * + * Return value: a pointer to the newly created avpl containing the + * matching avps or NULL if there is no match. + */ +extern AVPL* new_avpl_pairs_match(const gchar* name, AVPL* src, AVPL* op, gboolean strict, gboolean copy_avps) { + AVPL* newavpl; + AVPN* co = NULL; + AVPN* cs = NULL; + const gchar *last_match = NULL; + gboolean matched = TRUE; + + newavpl = new_avpl(scs_subscribe(avp_strings, name)); + +#ifdef _AVP_DEBUGGING + dbg_print(dbg_avpl_op,3,dbg_fp,"%s: %p src=%p op=%p name='%s'",G_STRFUNC,newavpl,src,op,name); +#endif + + cs = src->null.next; + co = op->null.next; + while (cs->avp && co->avp) { + int name_diff = g_strcmp0(co->avp->n, cs->avp->n); + const gchar *failed_match = NULL; + + if (name_diff < 0) { + // op < source, op has no data avp with same attribute. + failed_match = co->avp->n; + co = co->next; + } else if (name_diff > 0) { + // op > source, the source avp is not matched by any condition + cs = cs->next; + } else { + // Matching attributes found, now try to find a matching data AVP for the condition. + if (match_avp(cs->avp, co->avp)) { + insert_avp_before_node(newavpl, newavpl->null.prev, cs->avp, copy_avps); + last_match = co->avp->n; + cs = cs->next; + } else { + failed_match = co->avp->n; + } + co = co->next; + } + + // condition did not match, check if we can continue matching. + if (failed_match) { + if (strict) { + matched = FALSE; + break; + } else if (last_match != failed_match) { + // None of the conditions so far matched the attribute, check for other candidates + if (!co->avp || co->avp->n != last_match) { + matched = FALSE; + break; + } + } + } + } + + // if there are any conditions remaining, then those could not be matched + if (matched && strict && co->avp) { + matched = FALSE; + } + + if (matched) { + // there was a match, accept it + return newavpl; + } else { + // no match, only delete AVPs too if they were copied + delete_avpl(newavpl, copy_avps); + return NULL; + } +} + + +/** + * new_avpl_from_match: + * @param mode The matching method, one of AVPL_STRICT, AVPL_LOOSE, AVPL_EVERY. + * @param name the name of the resulting avpl + * @param src the data AVPL to be matched agains a condition AVPL + * @param op the conditions AVPL that will be matched against the data AVPL + * + * Matches the conditions AVPL against the original AVPL according to the mode. + * If there is no match, NULL is returned. If there is actually a match, then + * the matching AVPs (a subset of the data) are returned. + */ +extern AVPL* new_avpl_from_match(avpl_match_mode mode, const gchar* name,AVPL* src, AVPL* op, gboolean copy_avps) { + AVPL* avpl = NULL; + + switch (mode) { + case AVPL_STRICT: + avpl = new_avpl_pairs_match(name, src, op, TRUE, copy_avps); + break; + case AVPL_LOOSE: + avpl = new_avpl_loose_match(name,src,op,copy_avps); + break; + case AVPL_EVERY: + avpl = new_avpl_pairs_match(name, src, op, FALSE, copy_avps); + break; + case AVPL_NO_MATCH: + // XXX this seems unused + avpl = new_avpl_from_avpl(name,src,copy_avps); + merge_avpl(avpl, op, copy_avps); + break; + } + + return avpl; +} + +/** + * delete_avpl_transform: + * @param op a pointer to the avpl transformation object + * + * Destroys an avpl transformation object and releases all the resources it + * uses. + * + **/ +extern void delete_avpl_transform(AVPL_Transf* op) { + AVPL_Transf* next; + + for (; op ; op = next) { + next = op->next; + + g_free(op->name); + + if (op->match) { + delete_avpl(op->match,TRUE); + } + + if (op->replace) { + delete_avpl(op->replace,TRUE); + } + + g_free(op); + } + +} + + +/** + * avpl_transform: + * @param src the source avpl for the transform operation. + * @param op a pointer to the avpl transformation object to apply. + * + * Applies the "op" transformation to an avpl, matches it and eventually + * replaces or inserts the transformed avps. + * + * Return value: whether the transformation was performed or not. + **/ +extern void avpl_transform(AVPL* src, AVPL_Transf* op) { + AVPL* avpl = NULL; + AVPN* cs; + AVPN* cm; + AVPN* n; + +#ifdef _AVP_DEBUGGING + dbg_print(dbg_avpl_op,3,dbg_fp,"avpl_transform: src=%p op=%p",src,op); +#endif + + for ( ; op ; op = op->next) { + + avpl = new_avpl_from_match(op->match_mode, src->name,src, op->match, TRUE); + + if (avpl) { + switch (op->replace_mode) { + case AVPL_NO_REPLACE: + delete_avpl(avpl,TRUE); + return; + case AVPL_INSERT: + merge_avpl(src,op->replace,TRUE); + delete_avpl(avpl,TRUE); + return; + case AVPL_REPLACE: + cs = src->null.next; + cm = avpl->null.next; + // Removes AVPs from the source which are in the matched data. + // Assume that the matched set is a subset of the source. + while (cs->avp && cm->avp) { + if (cs->avp->n == cm->avp->n && cs->avp->v == cm->avp->v) { + n = cs->next; + + cs->prev->next = cs->next; + cs->next->prev = cs->prev; + g_slice_free(any_avp_type,(any_avp_type*)cs); + + cs = n; + cm = cm->next; + } else { + // Current matched AVP is not equal to the current + // source AVP. Since there must be a source AVP for + // each matched AVP, advance current source and not + // the match AVP. + cs = cs->next; + } + } + + merge_avpl(src,op->replace,TRUE); + delete_avpl(avpl,TRUE); + return; + } + } + } +} + + +/** + * new_loal: + * @param name the name the loal will take. + * + * Creates an empty list of avp lists. + * + * Return value: a pointer to the newly created loal. + **/ +extern LoAL* new_loal(const gchar* name) { + LoAL* new_loal_p = (LoAL*)g_slice_new(any_avp_type); + + if (! name) { + name = "anonymous"; + } + +#ifdef _AVP_DEBUGGING + dbg_print(dbg_avpl_op,3,dbg_fp,"new_loal_p: %p name=%s",new_loal_p,name); +#endif + + new_loal_p->name = scs_subscribe(avp_strings,name); + new_loal_p->null.avpl = NULL; + new_loal_p->null.next = &new_loal_p->null; + new_loal_p->null.prev = &new_loal_p->null; + new_loal_p->len = 0; + return new_loal_p; +} + +/** + * loal_append: + * @param loal the loal on which to operate. + * @param avpl the avpl to append. + * + * Appends an avpl to a loal. + * + **/ +extern void loal_append(LoAL* loal, AVPL* avpl) { + LoALnode* node = (LoALnode*)g_slice_new(any_avp_type); + +#ifdef _AVP_DEBUGGING + dbg_print(dbg_avpl_op,3,dbg_fp,"new_loal_node: %p",node); +#endif + + node->avpl = avpl; + node->next = &loal->null; + node->prev = loal->null.prev; + + loal->null.prev->next = node; + loal->null.prev = node; + loal->len++; +} + + +/** + * extract_first_avpl: + * @param loal the loal on which to operate. + * + * Extracts the first avpl contained in a loal. + * + * Return value: a pointer to the extracted avpl. + * + **/ +extern AVPL* extract_first_avpl(LoAL* loal) { + LoALnode* node; + AVPL* avpl; + +#ifdef _AVP_DEBUGGING + dbg_print(dbg_avpl_op,3,dbg_fp,"extract_first_avpl: from: %s",loal->name); +#endif + + node = loal->null.next; + + loal->null.next->next->prev = &loal->null; + loal->null.next = node->next; + + loal->len--; + + avpl = node->avpl; + + if ( avpl ) { + g_slice_free(any_avp_type,(any_avp_type*)node); + +#ifdef _AVP_DEBUGGING + dbg_print(dbg_avpl_op,3,dbg_fp,"extract_first_avpl: got %s",avpl->name); + dbg_print(dbg_avpl_op,3,dbg_fp,"delete_loal_node: %p",node); +#endif + } + + return avpl; +} + +/** +* extract_first_avpl: + * @param loal the loal on which to operate. + * + * Extracts the last avpl contained in a loal. + * + * Return value: a pointer to the extracted avpl. + * + **/ +extern AVPL* extract_last_avpl(LoAL* loal){ + LoALnode* node; + AVPL* avpl; + + node = loal->null.prev; + + loal->null.prev->prev->next = &loal->null; + loal->null.prev = node->prev; + + loal->len--; + + avpl = node->avpl; + + if ( avpl ) { + g_slice_free(any_avp_type,(any_avp_type*)node); +#ifdef _AVP_DEBUGGING + dbg_print(dbg_avpl_op,3,dbg_fp,"delete_loal_node: %p",node); +#endif + } + + return avpl; +} + +/** + * extract_first_avpl: + * @param loal the loal on which to operate. + * @param cookie pointer to the pointer variable to contain the state between calls + * + * At each call will return the following avpl from a loal. The given cookie + * will be used to manatain the state between calls. + * + * Return value: a pointer to the next avpl. + * + **/ +extern AVPL* get_next_avpl(LoAL* loal,void** cookie) { + LoALnode* node; + +#ifdef _AVP_DEBUGGING + dbg_print(dbg_avpl_op,3,dbg_fp,"get_next_avpl: loal=%p node=%p",loal,*cookie); +#endif + + if (*cookie) { + node = (LoALnode*) *cookie; + } else { + node = loal->null.next; + } + + *cookie = node->next; + + return node->avpl; +} + +/** + * delete_loal: + * @param loal the loal to be deleted. + * @param avpls_too whether avpls contained by the loal should be deleted as well + * @param avps_too whether avps contained by the avpls should be also deleted + * + * Destroys a loal and eventually desstroys avpls and avps. + * + **/ +extern void delete_loal(LoAL* loal, gboolean avpls_too, gboolean avps_too) { + AVPL* avpl; + +#ifdef _AVP_DEBUGGING + dbg_print(dbg_avpl_op,3,dbg_fp,"delete_loal: %p",loal); +#endif + + while(( avpl = extract_last_avpl(loal) )) { + if (avpls_too) { + delete_avpl(avpl,avps_too); + } + } + + scs_unsubscribe(avp_strings,loal->name); + g_slice_free(any_avp_type,(any_avp_type*)loal); +} + + + +/**************************************************************************** + ******************* the following are used in load_loal_from_file + ****************************************************************************/ + +/** + * load_loal_error: + * Used by loal_from_file to handle errors while loading. + **/ +static LoAL* load_loal_error(FILE* fp, LoAL* loal, AVPL* curr, int linenum, const gchar* fmt, ...) { + va_list list; + gchar* desc; + LoAL* ret = NULL; + gchar* err; + + va_start( list, fmt ); + desc = ws_strdup_vprintf(fmt, list); + va_end( list ); + + if (loal) { + err = ws_strdup_printf("Error Loading LoAL from file: in %s at line: %i, %s",loal->name,linenum,desc); + } else { + err = ws_strdup_printf("Error Loading LoAL at line: %i, %s",linenum,desc); + } + ret = new_loal(err); + + g_free(desc); + g_free(err); + + if (fp) fclose(fp); + if (loal) delete_loal(loal,TRUE,TRUE); + if (curr) delete_avpl(curr,TRUE); + + return ret; +} + + +/* the maximum length allowed for a line */ +#define MAX_ITEM_LEN 8192 + +/* this two ugly things are used for tokenizing */ +#define AVP_OP_CHAR '=': case '^': case '$': case '~': case '<': case '>': case '?': case '|': case '&' : case '!' + +#define AVP_NAME_CHAR 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J':\ +case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T':\ +case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case 'a': case 'b': case 'c': case 'd':\ +case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':\ +case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x':\ +case 'y': case 'z': case '_': case '0': case '1': case '2': case '3': case '4': case '5': case '6':\ +case '7': case '8': case '9': case '.' + + +/** + * loal_from_file: + * @param filename the file containing a loals text representation. + * + * Given a filename it will attempt to load a loal containing a copy of + * the avpls represented in the file. + * + * Return value: if successful a pointer to the new populated loal, else NULL. + * + **/ +extern LoAL* loal_from_file(gchar* filename) { + FILE *fp = NULL; + gchar c; + int i = 0; + guint32 linenum = 1; + gchar *linenum_buf; + gchar *name; + gchar *value; + gchar op = '?'; + LoAL *loal_error, *loal = new_loal(filename); + AVPL* curr = NULL; + AVP* avp; + + enum _load_loal_states { + START, + BEFORE_NAME, + IN_NAME, + IN_VALUE, + MY_IGNORE + } state; + + linenum_buf = (gchar*)g_malloc(MAX_ITEM_LEN); + name = (gchar*)g_malloc(MAX_ITEM_LEN); + value = (gchar*)g_malloc(MAX_ITEM_LEN); +#ifndef _WIN32 + if (! getuid()) { + loal_error = load_loal_error(fp,loal,curr,linenum,"MATE Will not run as root"); + goto error; + } +#endif + + state = START; + + if (( fp = ws_fopen(filename,"r") )) { + while(( c = (gchar) fgetc(fp) )){ + + if ( feof(fp) ) { + if ( ferror(fp) ) { + report_read_failure(filename,errno); + loal_error = load_loal_error(fp,loal,curr,linenum,"Error while reading '%f'",filename); + goto error; + } + break; + } + + if ( c == '\n' ) { + linenum++; + } + + if ( i >= MAX_ITEM_LEN - 1 ) { + loal_error = load_loal_error(fp,loal,curr,linenum,"Maximum item length exceeded"); + goto error; + } + + switch(state) { + case MY_IGNORE: + switch (c) { + case '\n': + state = START; + i = 0; + continue; + default: + continue; + } + case START: + switch (c) { + case ' ': case '\t': + /* ignore whitespace at line start */ + continue; + case '\n': + /* ignore empty lines */ + i = 0; + continue; + case AVP_NAME_CHAR: + state = IN_NAME; + i = 0; + name[i++] = c; + name[i] = '\0'; + snprintf(linenum_buf,MAX_ITEM_LEN,"%s:%u",filename,linenum); + curr = new_avpl(linenum_buf); + continue; + case '#': + state = MY_IGNORE; + continue; + default: + loal_error = load_loal_error(fp,loal,curr,linenum,"expecting name got: '%c'",c); + goto error; + } + case BEFORE_NAME: + i = 0; + name[0] = '\0'; + switch (c) { + case '\\': + c = (gchar) fgetc(fp); + if (c != '\n') ungetc(c,fp); + continue; + case ' ': + case '\t': + continue; + case AVP_NAME_CHAR: + state = IN_NAME; + + name[i++] = c; + name[i] = '\0'; + continue; + case '\n': + loal_append(loal,curr); + state = START; + continue; + default: + loal_error = load_loal_error(fp,loal,curr,linenum,"expecting name got: '%c'",c); + goto error; + } + case IN_NAME: + switch (c) { + case ';': + state = BEFORE_NAME; + + op = '?'; + name[i] = '\0'; + value[0] = '\0'; + i = 0; + + avp = new_avp(name,value,op); + + if (! insert_avp(curr,avp) ) { + delete_avp(avp); + } + + continue; + case AVP_OP_CHAR: + name[i] = '\0'; + i = 0; + op = c; + state = IN_VALUE; + continue; + case AVP_NAME_CHAR: + name[i++] = c; + continue; + case '\n': + loal_error = load_loal_error(fp,loal,curr,linenum,"operator expected found new line"); + goto error; + default: + loal_error = load_loal_error(fp,loal,curr,linenum,"name or match operator expected found '%c'",c); + goto error; + } + case IN_VALUE: + switch (c) { + case '\\': + value[i++] = (gchar) fgetc(fp); + continue; + case ';': + state = BEFORE_NAME; + + value[i] = '\0'; + i = 0; + + avp = new_avp(name,value,op); + + if (! insert_avp(curr,avp) ) { + delete_avp(avp); + } + continue; + case '\n': + loal_error = load_loal_error(fp,loal,curr,linenum,"';' expected found new line"); + goto error; + default: + value[i++] = c; + continue; + } + } + } + fclose (fp); + + g_free(linenum_buf); + g_free(name); + g_free(value); + + return loal; + + } else { + report_open_failure(filename,errno,FALSE); + loal_error = load_loal_error(NULL,loal,NULL,0,"Cannot Open file '%s'",filename); + } + +error: + g_free(linenum_buf); + g_free(name); + g_free(value); + + return loal_error; +} + +/* + * Editor modelines - https://www.wireshark.org/tools/modelines.html + * + * Local variables: + * c-basic-offset: 8 + * tab-width: 8 + * indent-tabs-mode: t + * End: + * + * vi: set shiftwidth=8 tabstop=8 noexpandtab: + * :indentSize=8:tabSize=8:noTabs=false: + */ diff --git a/plugins/epan/mate/mate_util.h b/plugins/epan/mate/mate_util.h new file mode 100644 index 00000000..0764ea5e --- /dev/null +++ b/plugins/epan/mate/mate_util.h @@ -0,0 +1,249 @@ +/* mate_util.h + * + * Copyright 2004, Luis E. Garcia Ontanon <luis@ontanon.org> + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1998 Gerald Combs + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + + +#ifndef __AVP_H_ +#define __AVP_H_ +#include "epan/proto.h" +#include <sys/types.h> + +/* #define _AVP_DEBUGGING */ + + +/******* dbg_print *********/ +#define DEBUG_BUFFER_SIZE 4096 +extern void dbg_print(const gint* which, gint how, FILE* where, + const gchar* fmt, ... ) G_GNUC_PRINTF(4, 5); + + +/******* single copy strings *********/ +typedef struct _scs_collection SCS_collection; + +#define SCS_SMALL_SIZE 16 +#define SCS_MEDIUM_SIZE 256 +#define SCS_LARGE_SIZE 4096 +#define SCS_HUGE_SIZE 65536 + +extern gchar* scs_subscribe(SCS_collection* collection, const gchar* s); +extern void scs_unsubscribe(SCS_collection* collection, gchar* s); +extern gchar* scs_subscribe_printf(SCS_collection* collection, gchar* fmt, ...) + G_GNUC_PRINTF(2, 3); + +/******* AVPs & Co. *********/ + +/* these are the defined oreators of avps */ +#define AVP_OP_EQUAL '=' +#define AVP_OP_NOTEQUAL '!' +#define AVP_OP_STARTS '^' +#define AVP_OP_ENDS '$' +#define AVP_OP_CONTAINS '~' +#define AVP_OP_LOWER '<' +#define AVP_OP_HIGHER '>' +#define AVP_OP_EXISTS '?' +#define AVP_OP_ONEOFF '|' +#define AVP_OP_TRANSF '&' + + +/* an avp is an object made of a name a value and an operator */ +typedef struct _avp { + gchar* n; + gchar* v; + gchar o; +} AVP; + +/* avp nodes are used in avp lists */ +typedef struct _avp_node { + AVP* avp; + struct _avp_node* next; + struct _avp_node* prev; +} AVPN; + +/* an avp list is a sorted set of avps */ +typedef struct _avp_list { + gchar* name; + guint32 len; + AVPN null; +} AVPL; + + + +/* an avpl transformation operation */ +typedef enum _avpl_match_mode { + AVPL_NO_MATCH, + AVPL_STRICT, + AVPL_LOOSE, + AVPL_EVERY +} avpl_match_mode; + +typedef enum _avpl_replace_mode { + AVPL_NO_REPLACE, + AVPL_INSERT, + AVPL_REPLACE +} avpl_replace_mode; + +typedef struct _avpl_transf AVPL_Transf; + +struct _avpl_transf { + gchar* name; + + AVPL* match; + AVPL* replace; + + avpl_match_mode match_mode; + avpl_replace_mode replace_mode; + + GHashTable* map; + AVPL_Transf* next; +}; + +/* loalnodes are used in LoALs */ +typedef struct _loal_node { + AVPL* avpl; + struct _loal_node *next; + struct _loal_node *prev; +} LoALnode; + + +/* a loal is a list of avp lists */ +typedef struct _loal { + gchar* name; + guint len; + LoALnode null; +} LoAL; + + +/* avp library (re)initialization */ +extern void avp_init(void); + +/* If enabled set's up the debug facilities for the avp library */ +#ifdef _AVP_DEBUGGING +extern void setup_avp_debug(FILE* fp, int* general, int* avp, int* avp_op, int* avpl, int* avpl_op); +#endif /* _AVP_DEBUGGING */ + +/* + * avp constructors + */ + +/* creates a new avp */ +extern AVP* new_avp(const gchar* name, const gchar* value, gchar op); + +/* creates a copy od an avp */ +extern AVP* avp_copy(AVP* from); + +/* creates an avp from a field_info record */ +extern AVP* new_avp_from_finfo(const gchar* name, field_info* finfo); + +/* + * avp destructor + */ +extern void delete_avp(AVP* avp); + +/* + * avp methods + */ +/* returns a newly allocated string containing a representation of the avp */ +#define avp_to_str(avp) (ws_strdup_printf("%s%c%s",avp->n,avp->o,avp->v)) + +/* returns the src avp if the src avp matches(*) the op avp or NULL if it doesn't */ +extern AVP* match_avp(AVP* src, AVP* op); + + +/* + * avplist constructors + */ + +/* creates an empty avp list */ +extern AVPL* new_avpl(const gchar* name); + + +/* creates a copy of an avp list */ +extern AVPL* new_avpl_from_avpl(const gchar* name, AVPL* avpl, gboolean copy_avps); + +extern AVPL* new_avpl_loose_match(const gchar* name, AVPL* src, AVPL* op, gboolean copy_avps); + +extern AVPL* new_avpl_pairs_match(const gchar* name, AVPL* src, AVPL* op, gboolean strict, gboolean copy_avps); + +/* uses mode to call one of the former matches. NO_MATCH = merge(merge(copy(src),op)) */ +extern AVPL* new_avpl_from_match(avpl_match_mode mode, const gchar* name,AVPL* src, AVPL* op, gboolean copy_avps); + + +/* + * functions on avpls + */ + +/* it will insert an avp to an avpl */ +extern gboolean insert_avp(AVPL* avpl, AVP* avp); + +/* renames an avpl */ +extern void rename_avpl(AVPL* avpl, gchar* name); + +/* it will add all the avps in src which don't match(*) any attribute in dest */ +extern void merge_avpl(AVPL* dest, AVPL* src, gboolean copy); + +/* it will return the first avp in an avpl whose name matches the given name. + will return NULL if there is not anyone matching */ +extern AVP* get_avp_by_name(AVPL* avpl, gchar* name, void** cookie); + +/* it will get the next avp from an avpl, using cookie to keep state */ +extern AVP* get_next_avp(AVPL* avpl, void** cookie); + +/* it will extract the first avp from an avp list */ +extern AVP* extract_first_avp(AVPL* avpl); + +/* it will extract the last avp from an avp list */ +extern AVP* extract_last_avp(AVPL* avpl); + +/* it will extract the first avp in an avpl whose name matches the given name. + it will not extract any and return NULL if there is not anyone matching */ +extern AVP* extract_avp_by_name(AVPL* avpl, gchar* name); + +/* returns a newly allocated string containing a representation of the avp list */ +extern gchar* avpl_to_str(AVPL* avpl); +extern gchar* avpl_to_dotstr(AVPL*); + +/* deletes an avp list and eventually its contents */ +extern void delete_avpl(AVPL* avpl, gboolean avps_too); + +/* + * AVPL transformations + */ +extern void delete_avpl_transform(AVPL_Transf* it); +extern void avpl_transform(AVPL* src, AVPL_Transf* op); + + +/* + * Lists of AVP lists + */ + +/* creates an empty list of avp lists */ +extern LoAL* new_loal(const gchar* name); + +/* given a file loads all the avpls contained in it + every line is formatted as it is the output of avplist_to_string */ +extern LoAL* loal_from_file(gchar* filename); + +/* inserts an avplist into a LoAL */ +extern void loal_append(LoAL* loal, AVPL* avpl); + +/* extracts the first avp list from the loal */ +extern AVPL* extract_first_avpl(LoAL* loal); + +/* extracts the last avp list from the loal */ +extern AVPL* extract_last_avpl(LoAL* loal); + +/* it will get the next avp list from a LoAL, using cookie to keep state */ +extern AVPL* get_next_avpl(LoAL* loal,void** cookie); + +/* deletes a loal and eventually its contents */ +extern void delete_loal(LoAL* loal, gboolean avpls_too, gboolean avps_too); + + +#endif diff --git a/plugins/epan/mate/matelib/dns.mate b/plugins/epan/mate/matelib/dns.mate new file mode 100644 index 00000000..be426bc5 --- /dev/null +++ b/plugins/epan/mate/matelib/dns.mate @@ -0,0 +1,6 @@ +# dns.mate + +Action=PduDef; Name=dns_pdu; Proto=dns; Transport=udp/ip; addr=ip.addr; port=udp.port; dns_id=dns.id; dns_rsp=dns.flags.response; +Action=GopDef; Name=dns_req; On=dns_pdu; addr; addr; port!53; dns_id; +Action=GopStart; For=dns_req; dns_rsp=0; +Action=GopStop; For=dns_req; dns_rsp=1; diff --git a/plugins/epan/mate/matelib/h225_ras.mate b/plugins/epan/mate/matelib/h225_ras.mate new file mode 100644 index 00000000..7c6698ef --- /dev/null +++ b/plugins/epan/mate/matelib/h225_ras.mate @@ -0,0 +1,9 @@ +# h225_ras.mate + +Action=PduDef; Name=ras_pdu; Proto=h225.RasMessage; Transport=udp/ip; ras_sn=h225.requestSeqNum; ras_msg=h225.RasMessage; addr=ip.addr; +Action=GopDef; Name=ras_leg; On=ras_pdu; addr; addr; ras_sn; +Action=GopStart; For=ras_leg; ras_msg|0|3|6|9|12|15|18|21|26|30; +Action=GopStop; For=ras_leg; ras_msg|1|2|4|5|7|8|10|11|13|14|16|17|19|20|22|24|27|28|29|31; + +Action=PduExtra; For=ras_pdu; guid=h225.guid; +Action=GopExtra; For=ras_leg; guid; diff --git a/plugins/epan/mate/matelib/isup.mate b/plugins/epan/mate/matelib/isup.mate new file mode 100644 index 00000000..8ff6d309 --- /dev/null +++ b/plugins/epan/mate/matelib/isup.mate @@ -0,0 +1,23 @@ +# isup.mate + +#Action=Transform; Name=isup_msg_type; Mode=Insert; Match=Strict; isup_msg=1; .isup_IAM=; +#Action=Transform; Name=isup_msg_type; Mode=Insert; Match=Strict; isup_msg=2; .isup_SAM=; +#Action=Transform; Name=isup_msg_type; Mode=Insert; Match=Strict; isup_msg=3; .isup_INR=; +#Action=Transform; Name=isup_msg_type; Mode=Insert; Match=Strict; isup_msg=4; .isup_INF=; +#Action=Transform; Name=isup_msg_type; Mode=Insert; Match=Strict; isup_msg=5; .isup_COT=; +#Action=Transform; Name=isup_msg_type; Mode=Insert; Match=Strict; isup_msg=6; .isup_ACM=; +#Action=Transform; Name=isup_msg_type; Mode=Insert; Match=Strict; isup_msg=7; .isup_CON=; +#Action=Transform; Name=isup_msg_type; Mode=Insert; Match=Strict; isup_msg=8; .isup_FOT=; +#Action=Transform; Name=isup_msg_type; Mode=Insert; Match=Strict; isup_msg=9; .isup_ANM=; +#Action=Transform; Name=isup_msg_type; Mode=Insert; Match=Strict; isup_msg=12; .isup_REL=; +#Action=Transform; Name=isup_msg_type; Mode=Insert; Match=Strict; isup_msg=13; .isup_SUS=; +#Action=Transform; Name=isup_msg_type; Mode=Insert; Match=Strict; isup_msg=14; .isup_RES=; +#Action=Transform; Name=isup_msg_type; Mode=Insert; Match=Strict; isup_msg=16; .isup_RLC=; + +Action=PduDef; Name=isup_pdu; Proto=isup; Transport=mtp3; mtp3pc=mtp3.dpc; mtp3pc=mtp3.opc; cic=isup.cic; isup_msg=isup.message_type; +#Action=PduTransform; For=isup_pdu; Name=isup_msg_type; + +Action=GopDef; Name=isup_leg; On=isup_pdu; ShowPduTree=TRUE; mtp3pc; mtp3pc; cic; +Action=GopStart; For=isup_leg; isup_msg=1; +Action=GopStop; For=isup_leg; isup_msg=16; + diff --git a/plugins/epan/mate/matelib/megaco.mate b/plugins/epan/mate/matelib/megaco.mate new file mode 100644 index 00000000..044aba78 --- /dev/null +++ b/plugins/epan/mate/matelib/megaco.mate @@ -0,0 +1,8 @@ +# megaco.mate + +Action=PduDef; Name=mgc_pdu; Proto=megaco; Transport=ip; addr=ip.addr; megaco_ctx=megaco.context; megaco_trx=megaco.transid; megaco_msg=megaco.transaction; term=megaco.termid; + +Action=GopDef; Name=mgc_tr; On=mgc_pdu; addr; addr; megaco_trx; +Action=GopStart; For=mgc_tr; megaco_msg|Request|Notify; +Action=GopStop; For=mgc_tr; megaco_msg=Reply; +Action=GopExtra; For=mgc_tr; term^DS1; megaco_ctx!Choose one; diff --git a/plugins/epan/mate/matelib/q931.mate b/plugins/epan/mate/matelib/q931.mate new file mode 100644 index 00000000..5bea5b1a --- /dev/null +++ b/plugins/epan/mate/matelib/q931.mate @@ -0,0 +1,6 @@ +# q931.thing + +Action=PduDef; Name=q931_pdu; Proto=q931; Stop=TRUE; Transport=tcp/ip; addr=ip.addr; call_ref=q931.call_ref; q931_msg=q931.message_type; +Action=GopDef; Name=q931_leg; On=q931_pdu; addr; addr; call_ref; +Action=GopStart; For=q931_leg; q931_msg=5; +Action=GopStop; For=q931_leg; q931_msg=90; diff --git a/plugins/epan/mate/matelib/radius.mate b/plugins/epan/mate/matelib/radius.mate new file mode 100644 index 00000000..66a910b8 --- /dev/null +++ b/plugins/epan/mate/matelib/radius.mate @@ -0,0 +1,12 @@ +# radius.mate + +Action=Transform; Name=radius_same_port; Mode=Insert; Match=Strict; radius_port; radius_port; +Action=Transform; Name=radius_same_port; Mode=Insert; Match=Every; radius_port; .radius_port=0; + +Action=PduDef; Name=radius_pdu; Proto=radius; Transport=udp/ip; radius_addr=ip.addr; radius_port=udp.port; radius_id=radius.id; radius_code=radius.code; +Action=PduTransform; For=radius_pdu; Name=radius_same_port; + +Action=GopDef; Name=radius_req; On=radius_pdu; radius_id; radius_addr; radius_addr; radius_port; radius_port; +Action=GopStart; For=radius_req; radius_code|1|4|7; +Action=GopStop; For=radius_req; radius_code|2|3|5|8|9; + diff --git a/plugins/epan/mate/matelib/rtsp.mate b/plugins/epan/mate/matelib/rtsp.mate new file mode 100644 index 00000000..35f25ab2 --- /dev/null +++ b/plugins/epan/mate/matelib/rtsp.mate @@ -0,0 +1,10 @@ +# rtsp.mate + +Action=PduDef; Name=rtsp_pdu; Proto=rtsp; Transport=tcp/ip; addr=ip.addr; port=tcp.port; rtsp_method=rtsp.method; +Action=PduExtra; For=rtsp_pdu; rtsp_ses=rtsp.session; rtsp_url=rtsp.url; + +Action=GopDef; Name=rtsp_ses; On=rtsp_pdu; addr; addr; port; port; +Action=GopStart; For=rtsp_ses; rtsp_method=DESCRIBE; +Action=GopStop; For=rtsp_ses; rtsp_method=TEARDOWN; +Action=GopExtra; For=rtsp_ses; rtsp_ses; rtsp_url; + diff --git a/plugins/epan/mate/matelib/sip.mate b/plugins/epan/mate/matelib/sip.mate new file mode 100644 index 00000000..593c915b --- /dev/null +++ b/plugins/epan/mate/matelib/sip.mate @@ -0,0 +1,12 @@ +# sip.mate + +Action=PduDef; Name=sip_pdu; Proto=sip; Transport=tcp/ip; addr=ip.addr; port=tcp.port; sip_method=sip.Method; sip_callid=sip.Call-ID; calling=sdp.owner.username; +Action=GopDef; Name=sip_leg; On=sip_pdu; addr; addr; port; port; +Action=GopStart; For=sip_leg; sip_method=INVITE; +Action=GopStop; For=sip_leg; sip_method=BYE; + +Action=PduDef; Name=sip_trunk_pdu; Proto=sip; Transport=udp/ip; addr=ip.addr; port=udp.port; sip_method=sip.Method; sip_callid=sip.Call-ID; calling=sdp.owner.username; +Action=GopDef; Name=sip_trunk_leg; On=sip_trunk_pdu; addr; addr; sip_callid; +Action=GopStart; For=sip_trunk_leg; sip_method=INVITE; +Action=GopStop; For=sip_trunk_leg; sip_method=BYE; + diff --git a/plugins/epan/mate/packet-mate.c b/plugins/epan/mate/packet-mate.c new file mode 100644 index 00000000..97774cd1 --- /dev/null +++ b/plugins/epan/mate/packet-mate.c @@ -0,0 +1,453 @@ +/* packet-mate.c + * Routines for the mate Facility's Pseudo-Protocol dissection + * + * Copyright 2004, Luis E. Garcia Ontanon <gopo@webflies.org> + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1998 Gerald Combs + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + + +/************************************************************************** + * This is the pseudo protocol dissector for the mate module. *** + * It is intended for this to be just the user interface to the module. *** + **************************************************************************/ + +#include "config.h" + +#include "mate.h" +#include <epan/expert.h> + +void proto_register_mate(void); +void proto_reg_handoff_mate(void); + +static mate_config* mc = NULL; + +static int proto_mate = -1; + +static int hf_mate_released_time = -1; +static int hf_mate_duration = -1; +static int hf_mate_number_of_pdus = -1; +static int hf_mate_started_at = -1; +static int hf_mate_gop_key = -1; + +static expert_field ei_mate_undefined_attribute = EI_INIT; + +static const gchar* pref_mate_config_filename = ""; +static const gchar* current_mate_config_filename = NULL; + +#ifdef _AVP_DEBUGGING +static int pref_avp_debug_general = 0; +static int pref_avp_debug_avp = 0; +static int pref_avp_debug_avp_op = 0; +static int pref_avp_debug_avpl = 0; +static int pref_avp_debug_avpl_op = 0; +#endif + +static dissector_handle_t mate_handle; + +static void +pdu_attrs_tree(proto_tree* tree, packet_info *pinfo, tvbuff_t *tvb, mate_pdu* pdu) +{ + AVPN* c; + proto_tree *avpl_t; + int* hfi_p; + + avpl_t = proto_tree_add_subtree_format(tree,tvb,0,0,pdu->cfg->ett_attr,NULL,"%s Attributes",pdu->cfg->name); + + for ( c = pdu->avpl->null.next; c->avp; c = c->next) { + hfi_p = (int *)g_hash_table_lookup(pdu->cfg->my_hfids,(char*)c->avp->n); + + if (hfi_p) { + proto_tree_add_string(avpl_t,*hfi_p,tvb,0,0,c->avp->v); + } else { + proto_tree_add_expert_format(avpl_t,pinfo,&ei_mate_undefined_attribute,tvb,0,0,"Undefined attribute: %s=%s",c->avp->n, c->avp->v); + } + } +} + +static void +gop_attrs_tree(proto_tree* tree, packet_info *pinfo, tvbuff_t *tvb, mate_gop* gop) +{ + AVPN* c; + proto_tree *avpl_t; + int* hfi_p; + + avpl_t = proto_tree_add_subtree_format(tree,tvb,0,0,gop->cfg->ett_attr,NULL,"%s Attributes",gop->cfg->name); + + for ( c = gop->avpl->null.next; c->avp; c = c->next) { + hfi_p = (int *)g_hash_table_lookup(gop->cfg->my_hfids,(char*)c->avp->n); + + if (hfi_p) { + proto_tree_add_string(avpl_t,*hfi_p,tvb,0,0,c->avp->v); + } else { + proto_tree_add_expert_format(avpl_t,pinfo,&ei_mate_undefined_attribute,tvb,0,0,"Undefined attribute: %s=%s",c->avp->n, c->avp->v); + } + } +} + +static void +gog_attrs_tree(proto_tree* tree, packet_info *pinfo, tvbuff_t *tvb, mate_gog* gog) +{ + AVPN* c; + proto_tree *avpl_t; + int* hfi_p; + + avpl_t = proto_tree_add_subtree_format(tree,tvb,0,0,gog->cfg->ett_attr,NULL,"%s Attributes",gog->cfg->name); + + for ( c = gog->avpl->null.next; c->avp; c = c->next) { + hfi_p = (int *)g_hash_table_lookup(gog->cfg->my_hfids,(char*)c->avp->n); + + if (hfi_p) { + proto_tree_add_string(avpl_t,*hfi_p,tvb,0,0,c->avp->v); + } else { + proto_tree_add_expert_format(avpl_t,pinfo,&ei_mate_undefined_attribute,tvb,0,0,"Undefined attribute: %s=%s",c->avp->n, c->avp->v); + } + } +} + +static void mate_gop_tree(proto_tree* pdu_tree, packet_info *pinfo, tvbuff_t *tvb, mate_gop* gop); + +static void +mate_gog_tree(proto_tree* tree, packet_info *pinfo, tvbuff_t *tvb, mate_gog* gog, mate_gop* gop) +{ + proto_item *gog_item; + proto_tree *gog_tree; + proto_tree *gog_time_tree; + proto_item *gog_gops_item; + proto_tree *gog_gops_tree; + mate_gop* gog_gops; + proto_item *gog_gop_item; + proto_tree *gog_gop_tree; + mate_pdu* pdu; + + gog_item = proto_tree_add_uint(tree,gog->cfg->hfid,tvb,0,0,gog->id); + gog_tree = proto_item_add_subtree(gog_item,gog->cfg->ett); + + gog_attrs_tree(gog_tree,pinfo,tvb,gog); + + if (gog->cfg->show_times) { + gog_time_tree = proto_tree_add_subtree_format(gog_tree,tvb,0,0,gog->cfg->ett_times,NULL,"%s Times",gog->cfg->name); + + proto_tree_add_float(gog_time_tree, gog->cfg->hfid_start_time, tvb, 0, 0, gog->start_time); + proto_tree_add_float(gog_time_tree, gog->cfg->hfid_last_time, tvb, 0, 0, gog->last_time - gog->start_time); + } + + gog_gops_item = proto_tree_add_uint(gog_tree, gog->cfg->hfid_gog_num_of_gops, tvb, 0, 0, gog->num_of_gops); + + gog_gops_tree = proto_item_add_subtree(gog_gops_item, gog->cfg->ett_children); + + for (gog_gops = gog->gops; gog_gops; gog_gops = gog_gops->next) { + + if (gop != gog_gops) { + if (gog->cfg->gop_tree_mode == GOP_FULL_TREE) { + mate_gop_tree(gog_gops_tree, pinfo, tvb, gog_gops); + } else { + gog_gop_item = proto_tree_add_uint(gog_gops_tree,gog_gops->cfg->hfid,tvb,0,0,gog_gops->id); + + if (gog->cfg->gop_tree_mode == GOP_BASIC_TREE) { + gog_gop_tree = proto_item_add_subtree(gog_gop_item, gog->cfg->ett_gog_gop); + + proto_tree_add_float(gog_gop_tree, hf_mate_started_at, tvb,0,0,gog_gops->start_time); + + proto_tree_add_float_format(gog_gop_tree, hf_mate_duration, tvb,0,0, gog_gops->last_time - gog_gops->start_time, + "%s Duration: %f", gog_gops->cfg->name, gog_gops->last_time - gog_gops->start_time); + + if (gog_gops->released) + proto_tree_add_float_format(gog_gop_tree, hf_mate_released_time, tvb,0,0, gog_gops->release_time - gog_gops->start_time, + "%s has been released, Time: %f", gog_gops->cfg->name, gog_gops->release_time - gog_gops->start_time); + + proto_tree_add_uint(gog_gop_tree, hf_mate_number_of_pdus, tvb,0,0, gog_gops->num_of_pdus); + + if (gop->pdus && gop->cfg->pdu_tree_mode != GOP_NO_TREE) { + proto_tree_add_uint(gog_gop_tree,gog->cfg->hfid_gog_gopstart,tvb,0,0,gog_gops->pdus->frame); + + for (pdu = gog_gops->pdus->next ; pdu; pdu = pdu->next) { + if (pdu->is_stop) { + proto_tree_add_uint(gog_gop_tree,gog->cfg->hfid_gog_gopstop,tvb,0,0,pdu->frame); + break; + } + } + } + } + + } + } else { + proto_tree_add_uint_format(gog_gops_tree,gop->cfg->hfid,tvb,0,0,gop->id,"current %s Gop: %d",gop->cfg->name,gop->id); + } + } +} + +static void +mate_gop_tree(proto_tree* tree, packet_info *pinfo, tvbuff_t *tvb, mate_gop* gop) +{ + proto_item *gop_item; + proto_tree *gop_time_tree; + proto_tree *gop_tree; + proto_item *gop_pdu_item; + proto_tree *gop_pdu_tree; + mate_pdu* gop_pdus; + float rel_time; + float pdu_rel_time; + const gchar* pdu_str; + const gchar* type_str; + guint32 pdu_item; + + gop_item = proto_tree_add_uint(tree,gop->cfg->hfid,tvb,0,0,gop->id); + gop_tree = proto_item_add_subtree(gop_item, gop->cfg->ett); + + if (gop->gop_key) proto_tree_add_string(gop_tree,hf_mate_gop_key,tvb,0,0,gop->gop_key); + + gop_attrs_tree(gop_tree,pinfo,tvb,gop); + + if (gop->cfg->show_times) { + gop_time_tree = proto_tree_add_subtree_format(gop_tree,tvb,0,0,gop->cfg->ett_times,NULL,"%s Times",gop->cfg->name); + + proto_tree_add_float(gop_time_tree, gop->cfg->hfid_start_time, tvb, 0, 0, gop->start_time); + + if (gop->released) { + proto_tree_add_float(gop_time_tree, gop->cfg->hfid_stop_time, tvb, 0, 0, gop->release_time - gop->start_time); + proto_tree_add_float(gop_time_tree, gop->cfg->hfid_last_time, tvb, 0, 0, gop->last_time - gop->start_time); + } else { + proto_tree_add_float(gop_time_tree, gop->cfg->hfid_last_time, tvb, 0, 0, gop->last_time - gop->start_time); + } + } + + gop_pdu_item = proto_tree_add_uint(gop_tree, gop->cfg->hfid_gop_num_pdus, tvb, 0, 0,gop->num_of_pdus); + + if (gop->cfg->pdu_tree_mode != GOP_NO_TREE) { + + gop_pdu_tree = proto_item_add_subtree(gop_pdu_item, gop->cfg->ett_children); + + rel_time = gop->start_time; + + type_str = (gop->cfg->pdu_tree_mode == GOP_FRAME_TREE ) ? "in frame:" : "id:"; + + for (gop_pdus = gop->pdus; gop_pdus; gop_pdus = gop_pdus->next) { + + pdu_item = (gop->cfg->pdu_tree_mode == GOP_FRAME_TREE ) ? gop_pdus->frame : gop_pdus->id; + + if (gop_pdus->is_start) { + pdu_str = "Start "; + } else if (gop_pdus->is_stop) { + pdu_str = "Stop "; + } else if (gop_pdus->after_release) { + pdu_str = "After stop "; + } else { + pdu_str = ""; + } + + pdu_rel_time = gop_pdus->time_in_gop != 0.0 ? gop_pdus->time_in_gop - rel_time : (float) 0.0; + + proto_tree_add_uint_format(gop_pdu_tree,gop->cfg->hfid_gop_pdu,tvb,0,0,pdu_item, + "%sPDU: %s %i (%f : %f)",pdu_str, type_str, + pdu_item, gop_pdus->time_in_gop, + pdu_rel_time); + + rel_time = gop_pdus->time_in_gop; + + } + } +} + + +static void +mate_pdu_tree(mate_pdu *pdu, packet_info *pinfo, tvbuff_t *tvb, proto_item *item, proto_tree* tree) +{ + proto_item *pdu_item; + proto_tree *pdu_tree; + + if ( ! pdu ) return; + + if (pdu->gop && pdu->gop->gog) { + proto_item_append_text(item," %s:%d->%s:%d->%s:%d", + pdu->cfg->name,pdu->id, + pdu->gop->cfg->name,pdu->gop->id, + pdu->gop->gog->cfg->name,pdu->gop->gog->id); + } else if (pdu->gop) { + proto_item_append_text(item," %s:%d->%s:%d", + pdu->cfg->name,pdu->id, + pdu->gop->cfg->name,pdu->gop->id); + } else { + proto_item_append_text(item," %s:%d",pdu->cfg->name,pdu->id); + } + + pdu_item = proto_tree_add_uint(tree,pdu->cfg->hfid,tvb,0,0,pdu->id); + pdu_tree = proto_item_add_subtree(pdu_item, pdu->cfg->ett); + proto_tree_add_float(pdu_tree,pdu->cfg->hfid_pdu_rel_time, tvb, 0, 0, pdu->rel_time); + + if (pdu->gop) { + proto_tree_add_float(pdu_tree,pdu->cfg->hfid_pdu_time_in_gop, tvb, 0, 0, pdu->time_in_gop); + mate_gop_tree(tree,pinfo,tvb,pdu->gop); + + if (pdu->gop->gog) + mate_gog_tree(tree,pinfo,tvb,pdu->gop->gog,pdu->gop); + } + + if (pdu->avpl) { + pdu_attrs_tree(pdu_tree,pinfo,tvb,pdu); + } +} + +static int +mate_tree(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_) +{ + mate_pdu* pdus; + proto_item *mate_i; + proto_tree *mate_t; + + /* If there is no MATE configuration, don't claim the packet */ + if ( mc == NULL) + return 0; + + /* There is a MATE configuration, just no tree, so there's nothing to do */ + if ( tree == NULL) + return tvb_captured_length(tvb); + + mate_analyze_frame(mc, pinfo,tree); + + if (( pdus = mate_get_pdus(pinfo->num) )) { + for ( ; pdus; pdus = pdus->next_in_frame) { + mate_i = proto_tree_add_protocol_format(tree,mc->hfid_mate,tvb,0,0,"MATE"); + mate_t = proto_item_add_subtree(mate_i, mc->ett_root); + mate_pdu_tree(pdus,pinfo,tvb,mate_i,mate_t); + } + } + return tvb_captured_length(tvb); +} + +static void +initialize_mate(void) +{ + initialize_mate_runtime(mc); +#ifdef _AVP_DEBUGGING + setup_avp_debug(mc->dbg_facility, + &pref_avp_debug_general, + &pref_avp_debug_avp, + &pref_avp_debug_avp_op, + &pref_avp_debug_avpl, + &pref_avp_debug_avpl_op); +#endif +} + +static void +flush_mate_debug(void) +{ + /* Flush debug information */ + if (mc->dbg_facility) + fflush(mc->dbg_facility); +} + +extern +void +proto_reg_handoff_mate(void) +{ + if ( *pref_mate_config_filename != '\0' ) { + + if (current_mate_config_filename) { + report_failure("MATE cannot reconfigure itself.\n" + "For changes to be applied you have to restart Wireshark\n"); + return; + } + + if (!mc) { + mc = mate_make_config(pref_mate_config_filename,proto_mate); + + if (mc) { + /* XXX: alignment warnings, what do they mean? */ + proto_register_field_array(proto_mate, (hf_register_info*)(void *)mc->hfrs->data, mc->hfrs->len ); + proto_register_subtree_array((gint**)(void*)mc->ett->data, mc->ett->len); + register_init_routine(initialize_mate); + register_postseq_cleanup_routine(flush_mate_debug); + + /* + * Set the list of hfids we want. + */ + set_postdissector_wanted_hfids(mate_handle, + mc->wanted_hfids); + + initialize_mate_runtime(mc); + } + + current_mate_config_filename = pref_mate_config_filename; + + } + } +} + +extern +void +proto_register_mate(void) +{ + static hf_register_info hf[] = { + { &hf_mate_started_at, { "Started at", "mate.started_at", FT_FLOAT, BASE_NONE, NULL, 0x0, NULL, HFILL }}, + { &hf_mate_duration, { "Duration", "mate.duration", FT_FLOAT, BASE_NONE, NULL, 0x0, NULL, HFILL }}, + { &hf_mate_released_time, { "Release time", "mate.released_time", FT_FLOAT, BASE_NONE, NULL, 0x0, NULL, HFILL }}, + { &hf_mate_number_of_pdus, { "Number of Pdus", "mate.number_of_pdus", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }}, + { &hf_mate_gop_key, { "GOP Key", "mate.gop_key", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, + }; + + static ei_register_info ei[] = { + { &ei_mate_undefined_attribute, { "mate.undefined_attribute", PI_PROTOCOL, PI_ERROR, "Undefined attribute", EXPFILL }}, + }; + + expert_module_t* expert_mate; + module_t *mate_module; + + proto_mate = proto_register_protocol("Meta Analysis Tracing Engine", "MATE", "mate"); + proto_register_field_array(proto_mate, hf, array_length(hf)); + expert_mate = expert_register_protocol(proto_mate); + expert_register_field_array(expert_mate, ei, array_length(ei)); + + mate_handle = register_dissector("mate",mate_tree,proto_mate); + mate_module = prefs_register_protocol(proto_mate, proto_reg_handoff_mate); + prefs_register_filename_preference(mate_module, "config", + "Configuration Filename", + "The name of the file containing the mate module's configuration", + &pref_mate_config_filename, FALSE); +#ifdef _AVP_DEBUGGING + prefs_register_uint_preference(mate_module, "avp_debug_general", + "AVP Debug general", + "General debugging level (0..5)", + 10, + &pref_avp_debug_general); + prefs_register_uint_preference(mate_module, "avp_debug_avp", + "Debug AVP", + "Attribute Value Pairs debugging level (0..5)", + 10, + &pref_avp_debug_avp); + prefs_register_uint_preference(mate_module, "avp_debug_avp_op", + "Debug AVP operations", + "Attribute Value Pairs operations debugging level (0..5)", + 10, + &pref_avp_debug_avp_op); + prefs_register_uint_preference(mate_module, "avp_debug_avpl", + "Debug AVP list", + "Attribute Value Pairs list debugging level (0..5)", + 10, + &pref_avp_debug_avpl); + prefs_register_uint_preference(mate_module, "avp_debug_avpl_op", + "Debug AVP list operations", + "Attribute Value Pairs list operations debugging level (0..5)", + 10, + &pref_avp_debug_avpl_op); +#endif + + register_postdissector(mate_handle); +} + +/* + * Editor modelines - https://www.wireshark.org/tools/modelines.html + * + * Local variables: + * c-basic-offset: 8 + * tab-width: 8 + * indent-tabs-mode: t + * End: + * + * vi: set shiftwidth=8 tabstop=8 noexpandtab: + * :indentSize=8:tabSize=8:noTabs=false: + */ |