1409 lines
49 KiB
C
1409 lines
49 KiB
C
/* packet-transum.c
|
|
* Routines for the TRANSUM response time analyzer post-dissector
|
|
* By Paul Offord <paul.offord@advance7.com>
|
|
* Copyright 2016 Advance Seven Limited
|
|
*
|
|
* 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.
|
|
*/
|
|
|
|
/* ToDo: Test handling of multiple SMB2 messages within a packet */
|
|
/* ToDo: Rework the Summarizer code (future release) */
|
|
|
|
#include "config.h"
|
|
|
|
#include <wiretap/wtap.h>
|
|
#include <epan/proto.h>
|
|
#include <epan/packet.h>
|
|
#include <epan/prefs.h>
|
|
#include <epan/dissectors/packet-tcp.h>
|
|
#include <tap.h>
|
|
#include <wsutil/report_err.h>
|
|
#include "packet-transum.h"
|
|
#include "preferences.h"
|
|
#include "extractors.h"
|
|
#include "decoders.h"
|
|
|
|
void proto_reg_handoff_transum(void);
|
|
|
|
|
|
#define CAPTURE_CLIENT 0
|
|
#define CAPTURE_INTERMEDIATE 1
|
|
#define CAPTURE_SERVICE 2
|
|
|
|
#define RTE_TIME_SEC 1
|
|
#define RTE_TIME_MSEC 1000
|
|
#define RTE_TIME_USEC 1000000
|
|
|
|
#define CONTINUE_PROCESSING TRUE
|
|
|
|
#define RRPD_REQUIRES_SUFFIX TRUE
|
|
#define RRPD_NEEDS_NO_SUFFIX FALSE;
|
|
|
|
#define SMB2_CMD_SESSION_SETUP 1
|
|
|
|
#define SIZEOF_TEMP_STRING 512
|
|
#define SIZEOF_SUMMARY 1024
|
|
|
|
/* The following are the field ids for the protocol values used by TRANSUM */
|
|
HF_OF_INTEREST hf_of_interest;
|
|
|
|
range_t *tcp_svc_port_range_values;
|
|
|
|
range_t *udp_svc_port_range_values;
|
|
|
|
TSUM_PREFERENCES preferences;
|
|
|
|
|
|
gboolean *detected_tcp_svc = NULL; /* this array is used to track services detected during the syn/syn-ack process */
|
|
|
|
PKT_INFO *sub_packet = NULL;
|
|
|
|
gboolean *dcerpc_req_pkt_type = NULL; /* used to indicate if a DCE-RPC pkt_type is a request */
|
|
|
|
/*
|
|
This array contains calls and returns that have no TRUE context_id
|
|
This is needed to overcome an apparent bug in Wireshark where
|
|
the field name of context id in parameters is the same as context id
|
|
in a message header
|
|
*/
|
|
gboolean *dcerpc_context_zero= NULL;
|
|
|
|
/* rrpd-related globals */
|
|
|
|
guint32 rrpd_suffix = 0;
|
|
guint32 dummy_msgid = 0xa7; /* This value is used for protocols that don't have msg_id such as GTCP, GUDP and SYN */
|
|
|
|
/*
|
|
The rrpd_list is the master array that holds information about all of the APDU Request-Response Pairs seen in the
|
|
trace. Each time an entry is added to this list the next_free_rrpd index is incremented. This index is used to
|
|
accelerate appending entries to the rrpd_list and also as the start point for find operations as these start from the
|
|
end of the list and search backwards through the list.
|
|
*/
|
|
RRPD *rrpd_list;
|
|
int next_free_rrpd = 0;
|
|
|
|
/*
|
|
output_rrpd is an array of pointers to RRPDs on the rrpd_list. The index into the array is frame number. This array is
|
|
used during Wireshark's second scan. As each packet is processed, TRANSUM uses the packet's frame number to index into
|
|
this array to determine if we have RTE data for this particular packet, and if so the write_rte function is called.
|
|
*/
|
|
RRPD *output_rrpd[MAX_PACKETS];
|
|
|
|
/*
|
|
The temp_rsp_rrpd_list holds RRPDs for APDUs where we have not yet seen the header information and so we can't
|
|
fully qualify the identification of the RRPD (the identification being ip_proto:stream_no:session_id:msg_id:suffix).
|
|
This only occurs when a) we are using one of the decode_based calculations (such as SMB2), and b) when we have
|
|
TCP Reassembly enabled. Once we receive a header packet for an APDU we migrate the entry from this array to the
|
|
main rrpd_list.
|
|
*/
|
|
RRPD *temp_rsp_rrpd_list; /* Reuse these for speed and efficient memory use - issue a warning if we run out */
|
|
|
|
|
|
static gint ett_transum = -1;
|
|
static gint ett_transum_header = -1;
|
|
static gint ett_transum_data = -1;
|
|
|
|
int proto_transum = -1;
|
|
|
|
int hf_tsum = -1;
|
|
int hf_tsum_status = -1;
|
|
int hf_tsum_time_units = -1;
|
|
int hf_tsum_req_first_seg = -1;
|
|
int hf_tsum_req_last_seg = -1;
|
|
int hf_tsum_rsp_first_seg = -1;
|
|
int hf_tsum_rsp_last_seg = -1;
|
|
int hf_tsum_apdu_rsp_time = -1;
|
|
int hf_tsum_service_time = -1;
|
|
int hf_tsum_req_spread = -1;
|
|
int hf_tsum_rsp_spread = -1;
|
|
int hf_tsum_clip_filter = -1;
|
|
int hf_tsum_calculation = -1;
|
|
int hf_tsum_summary = -1;
|
|
|
|
static const enum_val_t capture_position_vals[] = {
|
|
{ "TRACE_CAP_CLIENT", "Client", TRACE_CAP_CLIENT },
|
|
{ "TRACE_CAP_INTERMEDIATE", "Intermediate", TRACE_CAP_INTERMEDIATE },
|
|
{ "TRACE_CAP_SERVICE", "Service", TRACE_CAP_SERVICE },
|
|
{ NULL, NULL, 0}
|
|
};
|
|
|
|
static const enum_val_t time_multiplier_vals[] = {
|
|
{ "RTE_TIME_SEC", "seconds", RTE_TIME_SEC },
|
|
{ "RTE_TIME_MSEC", "milliseconds", RTE_TIME_MSEC },
|
|
{ "RTE_TIME_USEC", "microseconds", RTE_TIME_USEC },
|
|
{ NULL, NULL, 0}
|
|
};
|
|
|
|
static int fake_tap = 0xa7a7a7a7;
|
|
|
|
|
|
void init_detected_tcp_svc()
|
|
{
|
|
for (int i = 0; i < 64 * 1024; i++)
|
|
detected_tcp_svc[i] = FALSE;
|
|
}
|
|
|
|
void add_detected_tcp_svc(guint16 port)
|
|
{
|
|
detected_tcp_svc[port] = TRUE;
|
|
}
|
|
|
|
|
|
void init_dcerpc_data()
|
|
{
|
|
for (int i = 0; i < 256; i++)
|
|
dcerpc_req_pkt_type[i] = FALSE;
|
|
|
|
dcerpc_req_pkt_type[0] = TRUE;
|
|
dcerpc_req_pkt_type[11] = TRUE;
|
|
dcerpc_req_pkt_type[14] = TRUE;
|
|
|
|
for (int i = 0; i < 256; i++)
|
|
dcerpc_context_zero[i] = FALSE;
|
|
|
|
dcerpc_context_zero[11] = TRUE;
|
|
dcerpc_context_zero[12] = TRUE;
|
|
dcerpc_context_zero[14] = TRUE;
|
|
dcerpc_context_zero[15] = TRUE;
|
|
|
|
return;
|
|
}
|
|
|
|
void clear_rrpd(RRPD *rrpd)
|
|
{
|
|
memset(rrpd, 0x00, sizeof(RRPD));
|
|
}
|
|
|
|
void init_rrpd_data()
|
|
{
|
|
for (int i = 0; i < MAX_PACKETS; i++)
|
|
output_rrpd[i] = NULL;
|
|
|
|
return;
|
|
}
|
|
|
|
/* This function should be called before any change to RTE data. */
|
|
void null_output_rrpd_entries(RRPD *in_rrpd)
|
|
{
|
|
output_rrpd[in_rrpd->req_first_frame] = NULL;
|
|
output_rrpd[in_rrpd->req_last_frame] = NULL;
|
|
output_rrpd[in_rrpd->rsp_first_frame] = NULL;
|
|
output_rrpd[in_rrpd->rsp_last_frame] = NULL;
|
|
}
|
|
|
|
/* This function should be called after any change to RTE data. */
|
|
void update_output_rrpd(RRPD *in_rrpd)
|
|
{
|
|
if (preferences.rte_on_first_req)
|
|
output_rrpd[in_rrpd->req_first_frame] = in_rrpd;
|
|
|
|
if (preferences.rte_on_last_req)
|
|
output_rrpd[in_rrpd->req_last_frame] = in_rrpd;
|
|
|
|
if (preferences.rte_on_first_rsp)
|
|
output_rrpd[in_rrpd->rsp_first_frame] = in_rrpd;
|
|
|
|
if (preferences.rte_on_last_rsp)
|
|
output_rrpd[in_rrpd->rsp_last_frame] = in_rrpd;
|
|
}
|
|
|
|
/* Return the index of the RRPD that has been appended */
|
|
int append_to_rrpd_list(RRPD *in_rrpd)
|
|
{
|
|
if (next_free_rrpd > MAX_RRPDS)
|
|
next_free_rrpd = 0;
|
|
|
|
memcpy(&(rrpd_list[next_free_rrpd]), in_rrpd, sizeof(RRPD));
|
|
|
|
if (preferences.reassembly)
|
|
{
|
|
if (rrpd_list[next_free_rrpd].msg_id)
|
|
rrpd_list[next_free_rrpd].state = RRPD_STATE_3;
|
|
else
|
|
rrpd_list[next_free_rrpd].state = RRPD_STATE_1;
|
|
}
|
|
else
|
|
{
|
|
if (rrpd_list[next_free_rrpd].msg_id)
|
|
rrpd_list[next_free_rrpd].state = RRPD_STATE_4;
|
|
else
|
|
rrpd_list[next_free_rrpd].state = RRPD_STATE_2;
|
|
}
|
|
|
|
update_output_rrpd(&rrpd_list[next_free_rrpd]);
|
|
|
|
next_free_rrpd++;
|
|
|
|
return (next_free_rrpd - 1);
|
|
}
|
|
|
|
/*
|
|
This function finds the latest entry in the rrpd_list that matches the
|
|
ip_proto and stream_no values. If is_struct os true it will only match
|
|
if the session_id, msg_id and suffix are all zero or all ones.
|
|
|
|
/*
|
|
This function finds the latest entry in the rrpd_list that matches the
|
|
ip_proto, stream_no, session_id, msg_id and suffix values.
|
|
|
|
An input state value of 0 means that we don't care about state.
|
|
|
|
Returns the rrpd_list index value of the match or -1 if no match is found.
|
|
*/
|
|
int find_latest_rrpd(RRPD *in_rrpd, int state)
|
|
{
|
|
int i;
|
|
int rrpd_index = -1;
|
|
|
|
for (i = next_free_rrpd; i >= 0; i--)
|
|
{
|
|
if (rrpd_list[i].ip_proto == in_rrpd->ip_proto && rrpd_list[i].stream_no == in_rrpd->stream_no)
|
|
{
|
|
if (in_rrpd->decode_based)
|
|
{
|
|
/* If this is decode-based and we are checking for entries in RRPD_STATE_1 we need to match on ip_proto and stream_no alone. */
|
|
if (state == RRPD_STATE_1)
|
|
{
|
|
if (rrpd_list[i].session_id == 0 && rrpd_list[i].msg_id == 0 && rrpd_list[i].suffix == 1)
|
|
{
|
|
rrpd_index = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* if this stream is decode_based we need to take into account the session_id, msg_id and suffix */
|
|
if (rrpd_list[i].session_id == in_rrpd->session_id && rrpd_list[i].msg_id == in_rrpd->msg_id && rrpd_list[i].suffix == in_rrpd->suffix)
|
|
{
|
|
if (state == RRPD_STATE_DONT_CARE || rrpd_list[i].state == state)
|
|
{
|
|
rrpd_index = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* if this stream is not decode_based we don't need to take into account the session_id, msg_id and suffix */
|
|
if (state == RRPD_STATE_DONT_CARE || rrpd_list[i].state == state)
|
|
{
|
|
rrpd_index = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return rrpd_index;
|
|
}
|
|
|
|
void update_rrpd_list_entry(int match_index, RRPD *in_rrpd)
|
|
{
|
|
null_output_rrpd_entries(&rrpd_list[match_index]);
|
|
|
|
switch (rrpd_list[match_index].state)
|
|
{
|
|
case RRPD_STATE_1:
|
|
if (in_rrpd->c2s)
|
|
{
|
|
rrpd_list[match_index].req_last_frame = in_rrpd->req_last_frame;
|
|
rrpd_list[match_index].req_last_rtime = in_rrpd->req_last_rtime;
|
|
if (in_rrpd->msg_id)
|
|
{
|
|
rrpd_list[match_index].session_id = in_rrpd->session_id;
|
|
rrpd_list[match_index].msg_id = in_rrpd->msg_id;
|
|
rrpd_list[match_index].suffix = in_rrpd->suffix;
|
|
rrpd_list[match_index].state = RRPD_STATE_3;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
rrpd_list[match_index].rsp_first_frame = in_rrpd->rsp_first_frame;
|
|
rrpd_list[match_index].rsp_first_rtime = in_rrpd->rsp_first_rtime;
|
|
rrpd_list[match_index].rsp_last_frame = in_rrpd->rsp_last_frame;
|
|
rrpd_list[match_index].rsp_last_rtime = in_rrpd->rsp_last_rtime;
|
|
if (in_rrpd->msg_id)
|
|
rrpd_list[match_index].state = RRPD_STATE_7;
|
|
else
|
|
rrpd_list[match_index].state = RRPD_STATE_5;
|
|
}
|
|
break;
|
|
|
|
case RRPD_STATE_2:
|
|
if (in_rrpd->c2s)
|
|
{
|
|
rrpd_list[match_index].req_last_frame = in_rrpd->req_last_frame;
|
|
rrpd_list[match_index].req_last_rtime = in_rrpd->req_last_rtime;
|
|
if (in_rrpd->msg_id)
|
|
{
|
|
rrpd_list[match_index].session_id = in_rrpd->session_id;
|
|
rrpd_list[match_index].msg_id = in_rrpd->msg_id;
|
|
rrpd_list[match_index].suffix = in_rrpd->suffix;
|
|
rrpd_list[match_index].state = RRPD_STATE_4;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
rrpd_list[match_index].rsp_first_frame = in_rrpd->rsp_first_frame;
|
|
rrpd_list[match_index].rsp_first_rtime = in_rrpd->rsp_first_rtime;
|
|
rrpd_list[match_index].rsp_last_frame = in_rrpd->rsp_last_frame;
|
|
rrpd_list[match_index].rsp_last_rtime = in_rrpd->rsp_last_rtime;
|
|
if (in_rrpd->msg_id)
|
|
rrpd_list[match_index].state = RRPD_STATE_8;
|
|
else
|
|
rrpd_list[match_index].state = RRPD_STATE_6;
|
|
}
|
|
break;
|
|
|
|
case RRPD_STATE_3:
|
|
if (in_rrpd->c2s)
|
|
{
|
|
rrpd_list[match_index].req_last_frame = in_rrpd->req_last_frame;
|
|
rrpd_list[match_index].req_last_rtime = in_rrpd->req_last_rtime;
|
|
if (in_rrpd->msg_id)
|
|
{
|
|
rrpd_list[match_index].session_id = in_rrpd->session_id;
|
|
rrpd_list[match_index].msg_id = in_rrpd->msg_id;
|
|
rrpd_list[match_index].suffix = in_rrpd->suffix;
|
|
rrpd_list[match_index].state = RRPD_STATE_3;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
rrpd_list[match_index].rsp_first_frame = in_rrpd->rsp_first_frame;
|
|
rrpd_list[match_index].rsp_first_rtime = in_rrpd->rsp_first_rtime;
|
|
rrpd_list[match_index].rsp_last_frame = in_rrpd->rsp_last_frame;
|
|
rrpd_list[match_index].rsp_last_rtime = in_rrpd->rsp_last_rtime;
|
|
if (in_rrpd->msg_id)
|
|
rrpd_list[match_index].state = RRPD_STATE_7;
|
|
else
|
|
rrpd_list[match_index].state = RRPD_STATE_5;
|
|
}
|
|
break;
|
|
|
|
case RRPD_STATE_4:
|
|
if (in_rrpd->c2s)
|
|
{
|
|
rrpd_list[match_index].req_last_frame = in_rrpd->req_last_frame;
|
|
rrpd_list[match_index].req_last_rtime = in_rrpd->req_last_rtime;
|
|
if (in_rrpd->msg_id)
|
|
{
|
|
rrpd_list[match_index].session_id = in_rrpd->session_id;
|
|
rrpd_list[match_index].msg_id = in_rrpd->msg_id;
|
|
rrpd_list[match_index].suffix = in_rrpd->suffix;
|
|
rrpd_list[match_index].state = RRPD_STATE_4;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
rrpd_list[match_index].rsp_first_frame = in_rrpd->rsp_first_frame;
|
|
rrpd_list[match_index].rsp_first_rtime = in_rrpd->rsp_first_rtime;
|
|
rrpd_list[match_index].rsp_last_frame = in_rrpd->rsp_last_frame;
|
|
rrpd_list[match_index].rsp_last_rtime = in_rrpd->rsp_last_rtime;
|
|
if (in_rrpd->msg_id)
|
|
rrpd_list[match_index].state = RRPD_STATE_8;
|
|
else
|
|
rrpd_list[match_index].state = RRPD_STATE_6;
|
|
}
|
|
break;
|
|
|
|
case RRPD_STATE_5:
|
|
if (in_rrpd->c2s)
|
|
{
|
|
/* we've change direction */
|
|
;
|
|
}
|
|
else
|
|
{
|
|
rrpd_list[match_index].rsp_last_frame = in_rrpd->rsp_last_frame;
|
|
rrpd_list[match_index].rsp_last_rtime = in_rrpd->rsp_last_rtime;
|
|
if (in_rrpd->msg_id)
|
|
rrpd_list[match_index].state = RRPD_STATE_7;
|
|
else
|
|
rrpd_list[match_index].state = RRPD_STATE_5;
|
|
}
|
|
break;
|
|
|
|
case RRPD_STATE_6:
|
|
if (in_rrpd->c2s)
|
|
{
|
|
/* we've change direction */
|
|
;
|
|
}
|
|
else
|
|
{
|
|
rrpd_list[match_index].rsp_last_frame = in_rrpd->rsp_last_frame;
|
|
rrpd_list[match_index].rsp_last_rtime = in_rrpd->rsp_last_rtime;
|
|
if (in_rrpd->msg_id)
|
|
rrpd_list[match_index].state = RRPD_STATE_8;
|
|
else
|
|
rrpd_list[match_index].state = RRPD_STATE_6;
|
|
}
|
|
break;
|
|
|
|
case RRPD_STATE_7:
|
|
if (in_rrpd->c2s)
|
|
{
|
|
/* we've change direction */
|
|
;
|
|
}
|
|
else
|
|
{
|
|
rrpd_list[match_index].rsp_last_frame = in_rrpd->rsp_last_frame;
|
|
rrpd_list[match_index].rsp_last_rtime = in_rrpd->rsp_last_rtime;
|
|
}
|
|
break;
|
|
|
|
case RRPD_STATE_8:
|
|
if (in_rrpd->c2s)
|
|
{
|
|
/* we've change direction */
|
|
;
|
|
}
|
|
else
|
|
{
|
|
rrpd_list[match_index].rsp_last_frame = in_rrpd->rsp_last_frame;
|
|
rrpd_list[match_index].rsp_last_rtime = in_rrpd->rsp_last_rtime;
|
|
}
|
|
break;
|
|
}
|
|
|
|
update_output_rrpd(&rrpd_list[match_index]);
|
|
}
|
|
|
|
/*
|
|
This function processes a sub-packet that is going from client-to-service.
|
|
*/
|
|
void update_rrpd_list_entry_req(RRPD *in_rrpd)
|
|
{
|
|
int match_index = -1;
|
|
|
|
if (in_rrpd->decode_based)
|
|
{
|
|
while (TRUE)
|
|
{
|
|
match_index = find_latest_rrpd(in_rrpd, RRPD_STATE_1);
|
|
if (match_index >= 0) /* Check to cover TCP Reassembly enabled */
|
|
{
|
|
update_rrpd_list_entry(match_index, in_rrpd);
|
|
break;
|
|
}
|
|
|
|
match_index = find_latest_rrpd(in_rrpd, RRPD_STATE_4);
|
|
if (match_index >= 0)
|
|
{
|
|
update_rrpd_list_entry(match_index, in_rrpd);
|
|
break;
|
|
}
|
|
|
|
/* No entries and so add one */
|
|
append_to_rrpd_list(in_rrpd);
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
This is not a decode_based calculation and so a change from s2c to c2s
|
|
means that this packets starts of a new APDU RR pair.
|
|
*/
|
|
match_index = find_latest_rrpd(in_rrpd, RRPD_STATE_DONT_CARE);
|
|
if (match_index >= 0)
|
|
{
|
|
if (rrpd_list[match_index].state > RRPD_STATE_4 && in_rrpd->c2s)
|
|
{
|
|
append_to_rrpd_list(in_rrpd);
|
|
}
|
|
else
|
|
/* no change of direction so just update the RTE data */
|
|
update_rrpd_list_entry(match_index, in_rrpd);
|
|
}
|
|
else
|
|
{
|
|
append_to_rrpd_list(in_rrpd);
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/*
|
|
This function inserts an RRPD into the temp_rsp_rrpd_list. If this is
|
|
successful return the index of the entry. If there is no space return -1.
|
|
*/
|
|
int insert_into_temp_rsp_rrpd_list(RRPD *in_rrpd)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < SIZE_OF_TEMP_RSP_RRPD_LIST; i++)
|
|
{
|
|
if (temp_rsp_rrpd_list[i].ip_proto == 0)
|
|
break;
|
|
}
|
|
|
|
if (temp_rsp_rrpd_list[i].ip_proto)
|
|
{
|
|
temp_rsp_rrpd_list[i] = *in_rrpd;
|
|
return i;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
int find_temp_rsp_rrpd(RRPD *in_rrpd)
|
|
{
|
|
int entry_index = -1;
|
|
|
|
for (int i = 0; i < SIZE_OF_TEMP_RSP_RRPD_LIST; i++)
|
|
{
|
|
if (temp_rsp_rrpd_list[i].ip_proto == in_rrpd->ip_proto && temp_rsp_rrpd_list[i].stream_no == in_rrpd->stream_no)
|
|
{
|
|
entry_index = i;
|
|
break;
|
|
}
|
|
}
|
|
return entry_index;
|
|
}
|
|
|
|
void update_temp_rsp_rrpd(int temp_list_index, RRPD *in_rrpd)
|
|
{
|
|
temp_rsp_rrpd_list[temp_list_index].rsp_last_frame = in_rrpd->rsp_last_frame;
|
|
temp_rsp_rrpd_list[temp_list_index].rsp_last_rtime = in_rrpd->rsp_last_rtime;
|
|
}
|
|
|
|
/* This function migrates an entry from the temp_rsp_rrpd_list to the main rrpd_list. */
|
|
void migrate_temp_rsp_rrpd(int main_list_index, int temp_list_index)
|
|
{
|
|
update_rrpd_list_entry(main_list_index, &(temp_rsp_rrpd_list[temp_list_index]));
|
|
|
|
clear_rrpd(&temp_rsp_rrpd_list[temp_list_index]);
|
|
|
|
/* Update the state to 7 or 8 based on reassembly */
|
|
if (preferences.reassembly)
|
|
rrpd_list[main_list_index].state = RRPD_STATE_7;
|
|
else
|
|
rrpd_list[main_list_index].state = RRPD_STATE_8;
|
|
|
|
return;
|
|
}
|
|
|
|
void update_rrpd_list_entry_rsp(RRPD *in_rrpd)
|
|
{
|
|
int match_index = -1;
|
|
|
|
if (in_rrpd->decode_based)
|
|
{
|
|
if (preferences.reassembly)
|
|
{
|
|
if (in_rrpd->msg_id)
|
|
{
|
|
/* If we have a msg_id in the input RRPD we must have header information. */
|
|
int temp_list_index = find_temp_rsp_rrpd(in_rrpd);
|
|
|
|
if (temp_list_index >= 0)
|
|
{
|
|
update_temp_rsp_rrpd(temp_list_index, in_rrpd);
|
|
|
|
/* Migrate the temp_rsp_rrpd_list entry to the main rrpd_list */
|
|
match_index = find_latest_rrpd(in_rrpd, RRPD_STATE_3);
|
|
if (match_index >= 0)
|
|
migrate_temp_rsp_rrpd(match_index, temp_list_index);
|
|
}
|
|
else
|
|
{
|
|
match_index = find_latest_rrpd(in_rrpd, RRPD_STATE_3);
|
|
/* There isn't an entry in the temp_rsp_rrpd_list so update the master rrpd_list entry */
|
|
if (match_index >= 0)
|
|
update_rrpd_list_entry(match_index, in_rrpd);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Update an existing entry to the temp_rsp_rrpd_list or add a new one. */
|
|
int temp_list_index = find_temp_rsp_rrpd(in_rrpd);
|
|
|
|
if (temp_list_index >= 0)
|
|
update_temp_rsp_rrpd(temp_list_index, in_rrpd);
|
|
else
|
|
insert_into_temp_rsp_rrpd_list(in_rrpd);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Reassembly isn't set and so just go ahead and use the list function */
|
|
match_index = find_latest_rrpd(in_rrpd, RRPD_STATE_8);
|
|
if (match_index >= 0)
|
|
update_rrpd_list_entry(match_index, in_rrpd);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* if this isn't decode_based then just go ahead and update the RTE data */
|
|
match_index = find_latest_rrpd(in_rrpd, RRPD_STATE_DONT_CARE);
|
|
update_rrpd_list_entry(match_index, in_rrpd);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
/*
|
|
This function updates the RTE data of an RRPD on the rrpd_list. The
|
|
frame_no values in the input RRPD double up as a mask. If the frame_no
|
|
is > 0 then the frame_no value and rtime values are updated. If the
|
|
frame_no is 0 then that particular frame_no and rtime value is not updated.
|
|
*/
|
|
void update_rrpd_rte_data(RRPD *in_rrpd)
|
|
{
|
|
if (in_rrpd->c2s)
|
|
update_rrpd_list_entry_req(in_rrpd);
|
|
else
|
|
update_rrpd_list_entry_rsp(in_rrpd);
|
|
}
|
|
|
|
/* This function initialises all of the sub_packets in the sub_packet array. */
|
|
void init_sub_packet()
|
|
{
|
|
for (int i = 0; i < MAX_SUBPKTS_PER_PACKET; i++)
|
|
{
|
|
sub_packet[i].frame_number = 0;
|
|
sub_packet[i].relative_time.secs = 0;
|
|
sub_packet[i].relative_time.nsecs = 0;
|
|
|
|
sub_packet[i].tcp_retran = FALSE;
|
|
sub_packet[i].tcp_keep_alive = FALSE;
|
|
sub_packet[i].tcp_flags_syn = FALSE;
|
|
sub_packet[i].tcp_flags_ack = FALSE;
|
|
sub_packet[i].tcp_flags_reset = FALSE;
|
|
sub_packet[i].tcp_flags_urg = FALSE;
|
|
sub_packet[i].tcp_seq = 0;
|
|
|
|
sub_packet[i].srcport = 0;
|
|
sub_packet[i].dstport = 0;
|
|
sub_packet[i].len = 0;
|
|
|
|
sub_packet[i].tds_type = 0;
|
|
sub_packet[i].tds_length = 0;
|
|
|
|
sub_packet[i].smb2_msg_id = 0;
|
|
sub_packet[i].smb2_sesid = 0;
|
|
sub_packet[i].smb2_cmd = 0;
|
|
|
|
sub_packet[i].smb_mid = 0;
|
|
|
|
sub_packet[i].dcerpc_ver = 0;
|
|
sub_packet[i].dcerpc_pkt_type = 0;
|
|
sub_packet[i].dcerpc_cn_call_id = 0;
|
|
sub_packet[i].dcerpc_cn_ctx_id = 0;
|
|
|
|
sub_packet[i].dns_id = 0;
|
|
|
|
sub_packet[i].pkt_of_interest = FALSE;
|
|
sub_packet[i].rrpd.c2s = FALSE;
|
|
sub_packet[i].rrpd.state = RRPD_STATE_INIT;
|
|
|
|
clear_rrpd(&sub_packet[i].rrpd);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
void set_pkt_rrpd(PKT_INFO *current_pkt, guint8 ip_proto, guint32 stream_no, guint64 session_id, guint64 msg_id, gboolean requires_suffix)
|
|
{
|
|
current_pkt->rrpd.ip_proto = ip_proto;
|
|
current_pkt->rrpd.stream_no = stream_no;
|
|
current_pkt->rrpd.session_id = session_id;
|
|
current_pkt->rrpd.msg_id = msg_id;
|
|
|
|
if (requires_suffix)
|
|
current_pkt->rrpd.suffix = ++rrpd_suffix;
|
|
else
|
|
current_pkt->rrpd.suffix = 0;
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
/*
|
|
This function initialises the global variables and populates the
|
|
tcp_svc_port table with information from the preference settings
|
|
*/
|
|
void init_globals(void)
|
|
{
|
|
/* The following achives two things; a) we avoid double registering the fake tap
|
|
and b) we discard the fake tap when the "TRANSUM enabled" preference is changed.
|
|
|
|
We remove the tap when it is not needed as it has a performance impact.
|
|
|
|
It's safe to call remove_tap_listener even if the tap listener doesn't exist.
|
|
If it doesn't find &fake_tap on the queue of listeners it calls the actual freeing
|
|
function with a pointer of NULL and the called function just returns. */
|
|
remove_tap_listener(&fake_tap);
|
|
|
|
if (!preferences.tsumenabled) return;
|
|
|
|
/* Create and initialise some dynamic memory areas */
|
|
detected_tcp_svc = (gboolean *)wmem_alloc(wmem_file_scope(), (64 * 1024 * sizeof(gboolean)));
|
|
sub_packet = (PKT_INFO *)wmem_alloc(wmem_file_scope(), (MAX_SUBPKTS_PER_PACKET * sizeof(PKT_INFO)));
|
|
rrpd_list = (RRPD *)wmem_alloc(wmem_file_scope(), (MAX_RRPDS * sizeof(RRPD)));
|
|
temp_rsp_rrpd_list = (RRPD *)wmem_alloc(wmem_file_scope(), (SIZE_OF_TEMP_RSP_RRPD_LIST * sizeof(RRPD)));
|
|
|
|
memset(detected_tcp_svc, 0x00, (64 * 1024 * sizeof(gboolean)));
|
|
memset(sub_packet, 0x00, (MAX_SUBPKTS_PER_PACKET * sizeof(PKT_INFO)));
|
|
memset(rrpd_list, 0x00, (MAX_RRPDS * sizeof(RRPD)));
|
|
memset(temp_rsp_rrpd_list, 0x00, (SIZE_OF_TEMP_RSP_RRPD_LIST * sizeof(RRPD)));
|
|
|
|
next_free_rrpd = 0;
|
|
|
|
GString* fake_tap_filter = g_string_new("frame");
|
|
|
|
/* ToDo: the following and the hf_of_interest mechanism above should be replaced by something array-based so that
|
|
it is easier to extend. */
|
|
g_string_append_printf(fake_tap_filter, " || eth.type");
|
|
g_string_append_printf(fake_tap_filter, " || ip.proto");
|
|
g_string_append_printf(fake_tap_filter, " || ipv6.nxt");
|
|
g_string_append_printf(fake_tap_filter, " || tcp.srcport");
|
|
g_string_append_printf(fake_tap_filter, " || tcp.dstport");
|
|
g_string_append_printf(fake_tap_filter, " || tcp.stream");
|
|
g_string_append_printf(fake_tap_filter, " || tcp.analysis.retransmission");
|
|
g_string_append_printf(fake_tap_filter, " || tcp.analysis.keep_alive");
|
|
g_string_append_printf(fake_tap_filter, " || tcp.len");
|
|
g_string_append_printf(fake_tap_filter, " || tcp.flags.syn");
|
|
g_string_append_printf(fake_tap_filter, " || tcp.flags.ack");
|
|
g_string_append_printf(fake_tap_filter, " || tcp.flags.reset");
|
|
g_string_append_printf(fake_tap_filter, " || tcp.urgent_pointer");
|
|
g_string_append_printf(fake_tap_filter, " || tcp.seq");
|
|
|
|
g_string_append_printf(fake_tap_filter, " || tds.type");
|
|
g_string_append_printf(fake_tap_filter, " || tds.length");
|
|
|
|
g_string_append_printf(fake_tap_filter, " || udp.srcport");
|
|
g_string_append_printf(fake_tap_filter, " || udp.dstport");
|
|
g_string_append_printf(fake_tap_filter, " || udp.stream");
|
|
g_string_append_printf(fake_tap_filter, " || udp.length");
|
|
|
|
g_string_append_printf(fake_tap_filter, " || smb2.msg_id");
|
|
g_string_append_printf(fake_tap_filter, " || smb2.sesid");
|
|
g_string_append_printf(fake_tap_filter, " || smb2.cmd");
|
|
|
|
g_string_append_printf(fake_tap_filter, " || smb.mid");
|
|
|
|
g_string_append_printf(fake_tap_filter, " || dcerpc.ver");
|
|
g_string_append_printf(fake_tap_filter, " || dcerpc.pkt_type");
|
|
g_string_append_printf(fake_tap_filter, " || dcerpc.cn_ctx_id");
|
|
g_string_append_printf(fake_tap_filter, " || dcerpc.cn_call_id");
|
|
|
|
g_string_append_printf(fake_tap_filter, " || dns.id");
|
|
|
|
/* this fake tap is needed to force WS to pass a tree to the dissectors on
|
|
the first scan which causes the dissectors to create display filter values
|
|
which are then available to TRANSUM during the first scan */
|
|
GString* error = register_tap_listener("frame",
|
|
&fake_tap,
|
|
fake_tap_filter->str,
|
|
TL_REQUIRES_NOTHING,
|
|
NULL, NULL, NULL); /* NULL pointers as this is a fake tap */
|
|
|
|
if (error)
|
|
{
|
|
report_failure("register_tap_listener() failed");
|
|
return;
|
|
}
|
|
|
|
g_string_free(fake_tap_filter, TRUE);
|
|
|
|
/* use the range values to populate the tcp_svc_port list*/
|
|
for (guint i = 0; i < tcp_svc_port_range_values->nranges; i++)
|
|
{
|
|
for (guint32 j = tcp_svc_port_range_values->ranges[i].low; j <= tcp_svc_port_range_values->ranges[i].high; j++)
|
|
{
|
|
preferences.tcp_svc_port[j] = RTE_CALC_GTCP;
|
|
}
|
|
}
|
|
|
|
/* use the range values to populate the tcp_svc_port list*/
|
|
for (guint i = 0; i < udp_svc_port_range_values->nranges; i++)
|
|
{
|
|
for (guint32 j = udp_svc_port_range_values->ranges[i].low; j <= udp_svc_port_range_values->ranges[i].high; j++)
|
|
{
|
|
preferences.udp_svc_port[j] = RTE_CALC_GUDP;
|
|
}
|
|
}
|
|
|
|
init_detected_tcp_svc();
|
|
init_dcerpc_data();
|
|
|
|
preferences.tcp_svc_port[445] = RTE_CALC_SMB2;
|
|
preferences.udp_svc_port[53] = RTE_CALC_DNS;
|
|
|
|
init_rrpd_data();
|
|
|
|
}
|
|
|
|
/* This function adds the RTE data to the tree. The summary ptr is currently
|
|
not used but will be used for summariser information once this feature has
|
|
been ported from the LUA code. */
|
|
void write_rte(RRPD *in_rrpd, tvbuff_t *tvb, proto_tree *tree, char *summary)
|
|
{
|
|
nstime_t rte_art;
|
|
nstime_t rte_st;
|
|
nstime_t rte_reqspread;
|
|
nstime_t rte_rspspread;
|
|
proto_tree *rte_tree;
|
|
proto_item *pi;
|
|
|
|
char *temp_string;
|
|
temp_string = wmem_alloc(wmem_packet_scope(), SIZEOF_TEMP_STRING);
|
|
|
|
if (in_rrpd->req_first_frame)
|
|
{
|
|
nstime_delta(&rte_reqspread, &(in_rrpd->req_last_rtime), &(in_rrpd->req_first_rtime));
|
|
|
|
if (in_rrpd->rsp_first_frame)
|
|
{
|
|
/* calculate the RTE times */
|
|
nstime_delta(&rte_art, &(in_rrpd->rsp_last_rtime), &(in_rrpd->req_first_rtime));
|
|
nstime_delta(&rte_st, &(in_rrpd->rsp_first_rtime), &(in_rrpd->req_last_rtime));
|
|
nstime_delta(&rte_rspspread, &(in_rrpd->rsp_last_rtime), &(in_rrpd->rsp_first_rtime));
|
|
|
|
g_snprintf(temp_string, SIZEOF_TEMP_STRING, "OK");
|
|
}
|
|
else
|
|
g_snprintf(temp_string, SIZEOF_TEMP_STRING, "Response missing");
|
|
|
|
pi = proto_tree_add_item(tree, proto_transum, tvb, 0, -1, ENC_NA);
|
|
rte_tree = proto_item_add_subtree(pi, ett_transum);
|
|
|
|
pi = proto_tree_add_string(rte_tree, hf_tsum_status, tvb, 0, 0, temp_string);
|
|
PROTO_ITEM_SET_GENERATED(pi);
|
|
|
|
pi = proto_tree_add_uint(rte_tree, hf_tsum_req_first_seg, tvb, 0, 0, in_rrpd->req_first_frame);
|
|
PROTO_ITEM_SET_GENERATED(pi);
|
|
pi = proto_tree_add_uint(rte_tree, hf_tsum_req_last_seg, tvb, 0, 0, in_rrpd->req_last_frame);
|
|
PROTO_ITEM_SET_GENERATED(pi);
|
|
|
|
if (in_rrpd->rsp_first_frame)
|
|
{
|
|
pi = proto_tree_add_uint(rte_tree, hf_tsum_rsp_first_seg, tvb, 0, 0, in_rrpd->rsp_first_frame);
|
|
PROTO_ITEM_SET_GENERATED(pi);
|
|
pi = proto_tree_add_uint(rte_tree, hf_tsum_rsp_last_seg, tvb, 0, 0, in_rrpd->rsp_last_frame);
|
|
PROTO_ITEM_SET_GENERATED(pi);
|
|
|
|
pi = proto_tree_add_time(rte_tree, hf_tsum_apdu_rsp_time, tvb, 0, 0, &rte_art);
|
|
PROTO_ITEM_SET_GENERATED(pi);
|
|
pi = proto_tree_add_time(rte_tree, hf_tsum_service_time, tvb, 0, 0, &rte_st);
|
|
PROTO_ITEM_SET_GENERATED(pi);
|
|
}
|
|
|
|
pi = proto_tree_add_time(rte_tree, hf_tsum_req_spread, tvb, 0, 0, &rte_reqspread);
|
|
PROTO_ITEM_SET_GENERATED(pi);
|
|
|
|
if (in_rrpd->rsp_first_frame)
|
|
{
|
|
pi = proto_tree_add_time(rte_tree, hf_tsum_rsp_spread, tvb, 0, 0, &rte_rspspread);
|
|
PROTO_ITEM_SET_GENERATED(pi);
|
|
}
|
|
|
|
if (in_rrpd->ip_proto == IP_PROTO_TCP)
|
|
g_snprintf(temp_string, SIZEOF_TEMP_STRING, "tcp.stream==%d", in_rrpd->stream_no);
|
|
else if (in_rrpd->ip_proto == IP_PROTO_UDP)
|
|
g_snprintf(temp_string, SIZEOF_TEMP_STRING, "udp.stream==%d", in_rrpd->stream_no);
|
|
|
|
if (in_rrpd->rsp_first_frame)
|
|
g_snprintf(temp_string, SIZEOF_TEMP_STRING, "%s && frame.number>=%d && frame.number<=%d", temp_string, in_rrpd->req_first_frame, in_rrpd->rsp_last_frame);
|
|
else
|
|
g_snprintf(temp_string, SIZEOF_TEMP_STRING, "%s && frame.number>=%d && frame.number<=%d", temp_string, in_rrpd->req_first_frame, in_rrpd->req_last_frame);
|
|
|
|
if (in_rrpd->calculation == RTE_CALC_GTCP)
|
|
g_snprintf(temp_string, SIZEOF_TEMP_STRING, "%s && tcp.len>0", temp_string);
|
|
|
|
pi = proto_tree_add_string(rte_tree, hf_tsum_clip_filter, tvb, 0, 0, temp_string);
|
|
PROTO_ITEM_SET_GENERATED(pi);
|
|
|
|
switch (in_rrpd->calculation)
|
|
{
|
|
case RTE_CALC_GTCP:
|
|
g_snprintf(temp_string, SIZEOF_TEMP_STRING, "Generic TCP");
|
|
break;
|
|
|
|
case RTE_CALC_SYN:
|
|
g_snprintf(temp_string, SIZEOF_TEMP_STRING, "SYN and SYN/ACK");
|
|
break;
|
|
|
|
case RTE_CALC_DCERPC:
|
|
g_snprintf(temp_string, SIZEOF_TEMP_STRING, "DCE-RPC");
|
|
break;
|
|
|
|
case RTE_CALC_SMB2:
|
|
g_snprintf(temp_string, SIZEOF_TEMP_STRING, "SMB2");
|
|
break;
|
|
|
|
case RTE_CALC_GUDP:
|
|
g_snprintf(temp_string, SIZEOF_TEMP_STRING, "Generic UDP");
|
|
break;
|
|
|
|
case RTE_CALC_DNS:
|
|
g_snprintf(temp_string, SIZEOF_TEMP_STRING, "DNS");
|
|
break;
|
|
|
|
default:
|
|
g_snprintf(temp_string, SIZEOF_TEMP_STRING, "Unknown calculation type: %d", in_rrpd->calculation);
|
|
break;
|
|
}
|
|
pi = proto_tree_add_string(rte_tree, hf_tsum_calculation, tvb, 0, 0, temp_string);
|
|
PROTO_ITEM_SET_GENERATED(pi);
|
|
|
|
if (in_rrpd->rsp_first_frame)
|
|
{
|
|
if (preferences.summarisers_enabled)
|
|
{
|
|
if (summary)
|
|
{
|
|
pi = proto_tree_add_string(tree, hf_tsum_summary, tvb, 0, 0, summary);
|
|
PROTO_ITEM_SET_GENERATED(pi);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
This function sets initial values in the current_pkt structure and checks
|
|
the xxx_svc_port arrays to see if they conatin a match for the source or
|
|
destination port. This function also adds tcp_svc_port entries when it
|
|
discovers DCE-RPC traffic.
|
|
|
|
Returns the number of sub-packets to be processed.
|
|
*/
|
|
void set_proto_values(packet_info *pinfo, proto_tree *tree)
|
|
{
|
|
guint32 field_uint[MAX_RETURNED_ELEMENTS]; /* An extracted field array for unsigned integers */
|
|
size_t field_value_count; /* How many entries are there in the extracted field array */
|
|
|
|
sub_packet[0].frame_number = pinfo->fd->num; /* easy access to frame number */
|
|
sub_packet[0].relative_time = pinfo->rel_ts;
|
|
|
|
int number_sub_pkts_of_interest = 0; /* default */
|
|
|
|
if (pinfo->ptype == PT_TCP)
|
|
sub_packet[0].rrpd.ip_proto = IP_PROTO_TCP;
|
|
else if (pinfo->ptype == PT_UDP)
|
|
sub_packet[0].rrpd.ip_proto = IP_PROTO_UDP;
|
|
|
|
if (sub_packet[0].rrpd.ip_proto == IP_PROTO_TCP)
|
|
{
|
|
number_sub_pkts_of_interest = decode_gtcp(pinfo, tree);
|
|
/* decode_gtcp may return 0 but we need to keep processing because we
|
|
calculate RTE figures for all SYNs and also we may detect DCE-RPC later
|
|
(even though we don't currently have an entry in the tcp_svc_port list). */
|
|
|
|
if (sub_packet[0].tcp_retran)
|
|
{
|
|
/* we may not want to continue with this packet if it's a retransmission */
|
|
|
|
/* If this is a server-side trace we need to ignore client-to-service TCP retransmissions
|
|
the rationale being that if we saw the original in the trace the service process saw it too */
|
|
if (sub_packet[0].rrpd.c2s && preferences.capture_position == CAPTURE_SERVICE)
|
|
{
|
|
sub_packet[0].pkt_of_interest = FALSE;
|
|
return;
|
|
}
|
|
|
|
/* If this is a client-side trace we need to ignore service-to-client TCP retransmissions
|
|
the rationale being that if we saw the original in the trace the client process saw it too */
|
|
else if (!sub_packet[0].rrpd.c2s && preferences.capture_position == CAPTURE_CLIENT)
|
|
{
|
|
sub_packet[0].pkt_of_interest = FALSE;
|
|
return;
|
|
}
|
|
}
|
|
|
|
/* We are not interested in TCP Keep-Alive */
|
|
if (sub_packet[0].tcp_keep_alive)
|
|
{
|
|
sub_packet[0].pkt_of_interest = FALSE;
|
|
return;
|
|
}
|
|
|
|
if (sub_packet[0].len == 1)
|
|
{
|
|
if (preferences.orphan_ka_discard && sub_packet[0].tcp_flags_ack && sub_packet[0].rrpd.c2s)
|
|
{
|
|
sub_packet[0].pkt_of_interest = FALSE;
|
|
return; /* It's a KEEP-ALIVE -> stop processing this packet */
|
|
}
|
|
}
|
|
|
|
/* check if SYN */
|
|
if (sub_packet[0].tcp_flags_syn)
|
|
number_sub_pkts_of_interest = decode_syn(pinfo, tree);
|
|
|
|
if (sub_packet[0].len > 0)
|
|
{
|
|
/* check if SMB2 */
|
|
if (sub_packet[0].dstport == 445 || sub_packet[0].srcport == 445)
|
|
number_sub_pkts_of_interest = decode_smb(pinfo, tree);
|
|
|
|
/* check if DCE-RPC */
|
|
else if (!extract_uint(tree, hf_of_interest.dcerpc_ver, field_uint, &field_value_count))
|
|
{
|
|
if (field_value_count)
|
|
number_sub_pkts_of_interest = decode_dcerpc(pinfo, tree);
|
|
}
|
|
}
|
|
|
|
}
|
|
else if (sub_packet[0].rrpd.ip_proto == IP_PROTO_UDP)
|
|
{
|
|
/* It's UDP */
|
|
number_sub_pkts_of_interest = decode_gudp(pinfo, tree);
|
|
|
|
if (sub_packet[0].srcport == 53 || sub_packet[0].dstport == 53)
|
|
number_sub_pkts_of_interest = decode_dns(pinfo, tree);
|
|
}
|
|
|
|
/* Set appropriate RTE values in the sub-packets */
|
|
for (int i = 0; i < number_sub_pkts_of_interest; i++)
|
|
{
|
|
if (sub_packet[0].rrpd.c2s)
|
|
{
|
|
sub_packet[i].rrpd.req_first_frame = sub_packet[0].frame_number;
|
|
sub_packet[i].rrpd.req_first_rtime = sub_packet[0].relative_time;
|
|
sub_packet[i].rrpd.req_last_frame = sub_packet[0].frame_number;
|
|
sub_packet[i].rrpd.req_last_rtime = sub_packet[0].relative_time;
|
|
|
|
sub_packet[i].frame_number = sub_packet[0].frame_number; /* this acts as a switch later */
|
|
}
|
|
else
|
|
{
|
|
sub_packet[i].rrpd.rsp_first_frame = sub_packet[0].frame_number;
|
|
sub_packet[i].rrpd.rsp_first_rtime = sub_packet[0].relative_time;
|
|
sub_packet[i].rrpd.rsp_last_frame = sub_packet[0].frame_number;
|
|
sub_packet[i].rrpd.rsp_last_rtime = sub_packet[0].relative_time;
|
|
|
|
sub_packet[i].frame_number = sub_packet[0].frame_number; /* this acts as a switch later */
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* This function is called for each packet
|
|
* Wireshark scans all the packets once and then once again as they are displayed
|
|
* The pinfo.visited boolean is set to FALSE; on the first scan
|
|
*/
|
|
static int dissect_transum(tvbuff_t *buffer, packet_info *pinfo, proto_tree *tree _U_)
|
|
{
|
|
if (!preferences.tsumenabled) return 0;
|
|
|
|
/* if (there is RTE info associated with this packet we need to output it */
|
|
if (PINFO_FD_VISITED(pinfo))
|
|
{
|
|
RRPD *rrpd = output_rrpd[pinfo->num];
|
|
|
|
if (rrpd)
|
|
/* Add the RTE data to the protocol decode tree if we output_flag is set */
|
|
write_rte(rrpd, buffer, tree, NULL);
|
|
}
|
|
else
|
|
{
|
|
init_sub_packet();
|
|
|
|
set_proto_values(pinfo, tree);
|
|
|
|
if (sub_packet[0].pkt_of_interest)
|
|
{
|
|
/* Loop to process each sub_packet and update the related RTE data */
|
|
for (int i = 0; i < MAX_SUBPKTS_PER_PACKET; i++)
|
|
{
|
|
if (!sub_packet[i].frame_number)
|
|
break;
|
|
|
|
update_rrpd_rte_data(&(sub_packet[i].rrpd));
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
proto_register_transum(void)
|
|
{
|
|
module_t *transum_module;
|
|
dissector_handle_t transum_handle;
|
|
|
|
static hf_register_info hf[] = {
|
|
{ &hf_tsum,
|
|
{ "TRANSUM", "transum",
|
|
FT_NONE, BASE_NONE, NULL, 0x0,
|
|
"Post-dissector to generate RTE information", HFILL } },
|
|
|
|
{ &hf_tsum_status,
|
|
{ "RTE Status", "transum.status",
|
|
FT_STRING, BASE_NONE, NULL, 0x0,
|
|
"Indication of completeness of the RTE information", HFILL } },
|
|
|
|
{ &hf_tsum_time_units,
|
|
{ "RTE Time Units", "transum.time_units",
|
|
FT_STRING, BASE_NONE, NULL, 0x0,
|
|
"Time units used (s, ms or us) for the RTE values", HFILL }
|
|
},
|
|
|
|
{ &hf_tsum_req_first_seg,
|
|
{ "Req First Seg", "transum.firstreq",
|
|
FT_FRAMENUM, BASE_NONE, NULL, 0x0,
|
|
"First Segment of an APDU Request", HFILL }
|
|
},
|
|
|
|
{ &hf_tsum_req_last_seg,
|
|
{ "Req Last Seg", "transum.lastreq",
|
|
FT_FRAMENUM, BASE_NONE, NULL, 0x0,
|
|
"Last Segment of an APDU Request", HFILL }
|
|
},
|
|
|
|
{ &hf_tsum_rsp_first_seg,
|
|
{ "Rsp First Seg", "transum.firstrsp",
|
|
FT_FRAMENUM, BASE_NONE, NULL, 0x0,
|
|
"First Segment of an APDU Response", HFILL }
|
|
},
|
|
|
|
{ &hf_tsum_rsp_last_seg,
|
|
{ "Rsp Last Seg", "transum.lastrsp",
|
|
FT_FRAMENUM, BASE_NONE, NULL, 0x0,
|
|
"Last Segment of an APDU Response", HFILL }
|
|
},
|
|
|
|
{ &hf_tsum_apdu_rsp_time,
|
|
{ "APDU Rsp Time", "transum.art",
|
|
FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0,
|
|
"RTE APDU Response Time", HFILL }
|
|
},
|
|
|
|
{ &hf_tsum_service_time,
|
|
{ "Service Time", "transum.st",
|
|
FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0,
|
|
"RTE Service Time", HFILL }
|
|
},
|
|
|
|
{ &hf_tsum_req_spread,
|
|
{ "Req Spread", "transum.reqspread",
|
|
FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0,
|
|
"RTE Request Spread", HFILL }
|
|
},
|
|
|
|
{ &hf_tsum_rsp_spread,
|
|
{ "Rsp Spread", "transum.rspspread",
|
|
FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0,
|
|
"RTE Response Spread", HFILL }
|
|
},
|
|
|
|
{ &hf_tsum_clip_filter,
|
|
{ "Trace clip filter", "transum.clip_filter",
|
|
FT_STRING, BASE_NONE, NULL, 0x0,
|
|
"Filter expression to select the APDU Reqest-Response pair", HFILL }
|
|
},
|
|
|
|
{ &hf_tsum_calculation,
|
|
{ "Calculation", "transum.calculation",
|
|
FT_STRING, BASE_NONE, NULL, 0x0,
|
|
"Basis of the RTE calculation", HFILL }
|
|
},
|
|
|
|
{ &hf_tsum_summary,
|
|
{ "Summary", "transum.summary",
|
|
FT_STRING, BASE_NONE, NULL, 0x0,
|
|
"Summarizer information", HFILL }
|
|
}
|
|
};
|
|
|
|
/* Setup protocol subtree array */
|
|
static gint *ett[] = {
|
|
&ett_transum,
|
|
&ett_transum_header,
|
|
&ett_transum_data
|
|
};
|
|
|
|
proto_transum = proto_register_protocol(
|
|
"TRANSUM RTE Data", /* name */
|
|
"TRANSUM", /* short name */
|
|
"transum" /* abbrev */
|
|
);
|
|
|
|
/* Set User Preferences defaults */
|
|
preferences.tsumenabled = FALSE;
|
|
preferences.capture_position = TRACE_CAP_CLIENT;
|
|
preferences.reassembly = TRUE;
|
|
|
|
tcp_svc_port_range_values = (range_t *)g_malloc((sizeof(guint) + (4 * sizeof(range_admin_t))));
|
|
tcp_svc_port_range_values->nranges = 4;
|
|
tcp_svc_port_range_values->ranges[0].low = 25;
|
|
tcp_svc_port_range_values->ranges[0].high = 25;
|
|
tcp_svc_port_range_values->ranges[1].low = 80;
|
|
tcp_svc_port_range_values->ranges[1].high = 80;
|
|
tcp_svc_port_range_values->ranges[2].low = 443;
|
|
tcp_svc_port_range_values->ranges[2].high = 443;
|
|
tcp_svc_port_range_values->ranges[3].low = 1433;
|
|
tcp_svc_port_range_values->ranges[3].high = 1433;
|
|
|
|
udp_svc_port_range_values = (range_t *)g_malloc((sizeof(guint) + (1 * sizeof(range_admin_t))));
|
|
udp_svc_port_range_values->nranges = 1;
|
|
udp_svc_port_range_values->ranges[0].low = 137;
|
|
udp_svc_port_range_values->ranges[0].high = 139;
|
|
|
|
preferences.orphan_ka_discard = FALSE;
|
|
preferences.time_multiplier = RTE_TIME_SEC;
|
|
preferences.rte_on_first_req = FALSE;
|
|
preferences.rte_on_last_req = TRUE;
|
|
preferences.rte_on_first_rsp = FALSE;
|
|
preferences.rte_on_last_rsp = FALSE;
|
|
|
|
/* create arrays to hold some DCE-RPC values */
|
|
dcerpc_req_pkt_type = (gboolean *)wmem_alloc(wmem_epan_scope(), (256 * sizeof(gboolean)));
|
|
dcerpc_context_zero = (gboolean *)wmem_alloc(wmem_epan_scope(), (256 * sizeof(gboolean)));
|
|
|
|
/* no start registering stuff */
|
|
proto_register_field_array(proto_transum, hf, array_length(hf));
|
|
proto_register_subtree_array(ett, array_length(ett));
|
|
|
|
transum_module = prefs_register_protocol(proto_transum, NULL); /* ToDo: We need to rethink the NULL pointer so that a preference change causes a rescan */
|
|
|
|
/* Register the preferences */
|
|
prefs_register_bool_preference(transum_module, "tsumenabled",
|
|
"TRANSUM enabled",
|
|
"Uncheck to bypass TRANSUM",
|
|
&preferences.tsumenabled);
|
|
|
|
prefs_register_enum_preference(transum_module,
|
|
"capture_position",
|
|
"Capture position",
|
|
"Position of the capture unit that produced this trace. This setting affects the way TRANSUM handles TCP Retransmissions. See the manual for details.",
|
|
&preferences.capture_position,
|
|
capture_position_vals,
|
|
FALSE);
|
|
|
|
prefs_register_bool_preference(transum_module,
|
|
"reassembly",
|
|
"Subdissector reassembly enabled",
|
|
"Set this to match to the TCP subdissector reassembly setting",
|
|
&preferences.reassembly);
|
|
|
|
prefs_register_range_preference(transum_module,
|
|
"tcp_port_ranges",
|
|
"Output RTE data for these TCP service ports",
|
|
"Add and remove ports numbers separated by commas\nRanges are supported e.g. 25,80,2000-3000,5432",
|
|
&tcp_svc_port_range_values,
|
|
65536);
|
|
|
|
prefs_register_range_preference(transum_module,
|
|
"udp_port_ranges",
|
|
"Output RTE data for these UDP service ports",
|
|
"Add and remove ports numbers separated by commas\nRanges are supported e.g. 123,137-139,520-521,2049",
|
|
&udp_svc_port_range_values,
|
|
65536);
|
|
|
|
prefs_register_bool_preference(transum_module,
|
|
"orphan_ka_discard",
|
|
"Discard orphaned TCP Keep-Alives",
|
|
"Set this to discard any packet in the direction client to service,\nwith a 1-byte payload of 0x00 and the ACK flag set",
|
|
&preferences.orphan_ka_discard);
|
|
|
|
/* removed from this release
|
|
prefs_register_enum_preference(transum_module,
|
|
"time_multiplier",
|
|
"Time units for RTE values",
|
|
"Unit of time used for APDU Response Time, Service Time and Spread Time values.",
|
|
&preferences.time_multiplier,
|
|
time_multiplier_vals,
|
|
FALSE);
|
|
*/
|
|
|
|
prefs_register_bool_preference(transum_module,
|
|
"rte_on_first_req",
|
|
"Add RTE data to the first request segment",
|
|
"RTE data will be added to the first request packet",
|
|
&preferences.rte_on_first_req);
|
|
|
|
prefs_register_bool_preference(transum_module,
|
|
"rte_on_last_req",
|
|
"Add RTE data to the last request segment",
|
|
"RTE data will be added to the last request packet",
|
|
&preferences.rte_on_last_req);
|
|
|
|
prefs_register_bool_preference(transum_module,
|
|
"rte_on_first_rsp",
|
|
"Add RTE data to the first response segment",
|
|
"RTE data will be added to the first response packet",
|
|
&preferences.rte_on_first_rsp);
|
|
|
|
prefs_register_bool_preference(transum_module,
|
|
"rte_on_last_rsp",
|
|
"Add RTE data to the last response segment",
|
|
"RTE data will be added to the last response packet",
|
|
&preferences.rte_on_last_rsp);
|
|
|
|
transum_handle = register_dissector("transum", dissect_transum, proto_transum);
|
|
|
|
transum_module = prefs_register_protocol(proto_transum, proto_reg_handoff_transum);
|
|
register_init_routine(init_globals);
|
|
|
|
register_postdissector(transum_handle);
|
|
}
|
|
|
|
void proto_reg_handoff_transum(void)
|
|
{
|
|
/* Get the field id for each field we will need */
|
|
hf_of_interest.ip_proto = proto_registrar_get_id_byname("ip.proto");
|
|
hf_of_interest.ipv6_nxt = proto_registrar_get_id_byname("ipv6.nxt");
|
|
hf_of_interest.tcp_retran = proto_registrar_get_id_byname("tcp.analysis.retransmission");
|
|
hf_of_interest.tcp_keep_alive = proto_registrar_get_id_byname("tcp.analysis.keep_alive");
|
|
hf_of_interest.tcp_flags_syn = proto_registrar_get_id_byname("tcp.flags.syn");
|
|
hf_of_interest.tcp_flags_ack = proto_registrar_get_id_byname("tcp.flags.ack");
|
|
hf_of_interest.tcp_flags_reset = proto_registrar_get_id_byname("tcp.flags.reset");
|
|
hf_of_interest.tcp_flags_urg = proto_registrar_get_id_byname("tcp.flags.urg");
|
|
hf_of_interest.tcp_seq = proto_registrar_get_id_byname("tcp.seq");
|
|
hf_of_interest.tcp_srcport = proto_registrar_get_id_byname("tcp.srcport");
|
|
hf_of_interest.tcp_dstport = proto_registrar_get_id_byname("tcp.dstport");
|
|
hf_of_interest.tcp_stream = proto_registrar_get_id_byname("tcp.stream");
|
|
hf_of_interest.tcp_len = proto_registrar_get_id_byname("tcp.len");
|
|
|
|
hf_of_interest.udp_srcport = proto_registrar_get_id_byname("udp.srcport");
|
|
hf_of_interest.udp_dstport = proto_registrar_get_id_byname("udp.dstport");
|
|
hf_of_interest.udp_stream = proto_registrar_get_id_byname("udp.stream");
|
|
hf_of_interest.udp_length = proto_registrar_get_id_byname("udp.length");
|
|
|
|
hf_of_interest.tds_type = proto_registrar_get_id_byname("tds.type");
|
|
hf_of_interest.tds_length = proto_registrar_get_id_byname("tds.length");
|
|
|
|
hf_of_interest.smb_mid = proto_registrar_get_id_byname("smb.mid");
|
|
|
|
hf_of_interest.smb2_ses_id = proto_registrar_get_id_byname("smb2.sesid");
|
|
hf_of_interest.smb2_msg_id = proto_registrar_get_id_byname("smb2.msg_id");
|
|
hf_of_interest.smb2_cmd = proto_registrar_get_id_byname("smb2.msg_cmd");
|
|
|
|
hf_of_interest.dcerpc_ver = proto_registrar_get_id_byname("dcerpc.ver");
|
|
hf_of_interest.dcerpc_pkt_type = proto_registrar_get_id_byname("dcerpc.pkt_type");
|
|
hf_of_interest.dcerpc_cn_call_id = proto_registrar_get_id_byname("dcerpc.cn_call_id");
|
|
hf_of_interest.dcerpc_cn_ctx_id = proto_registrar_get_id_byname("dcerpc.cn_ctx_id");
|
|
|
|
hf_of_interest.dns_id = proto_registrar_get_id_byname("dns.id");
|
|
|
|
if (!preferences.tsumenabled)
|
|
proto_disable_by_default(proto_transum);
|
|
proto_set_decoding(proto_transum, preferences.tsumenabled);
|
|
}
|