diff options
author | Paul Offord <paul.offord@advance7.com> | 2017-11-20 09:49:38 +0000 |
---|---|---|
committer | Michael Mann <mmann78@netscape.net> | 2017-11-22 14:37:01 +0000 |
commit | 36372a2465c94784240ba8c38b53b4eedb234868 (patch) | |
tree | 9a832c902b3183606286508128e2ca5124aecb8b /plugins | |
parent | 871f75ce85b7c3d0c58e05e90d34791042a8d5b8 (diff) |
TRANSUM: Fix DNS-related bug and improve performance
These changes significantly improve the speed and accuracy of TRANSUM.
I have removed the concept of rrpd status as it wasn't being used in any
significant way and created unnecessary code.
The find_latest_rrpd(...) function was becoming very complex which made it
difficult to optimise performance for certain protocols. To overcome
this, I have introduced an equivalent function for each protocol e.g.
find_latest_rrpd_smb2(...). each of these new functions has a loop that
steps through the rrpd_list. I could have placed this loop one level up
in the nested call and so had one loop in the code that calls the new
function. However, I have found that this area is the prime cause of
delays in TRANSUM execution and so I want to avoid calling these new
functions with each step through the rrpd_list.
Finally, I have added code to improve the handling of retransmissions.
Bug: 14210
Change-Id: I038097f22a45ee74173aad1ae5732347f769b9bd
Reviewed-on: https://code.wireshark.org/review/24506
Petri-Dish: Anders Broman <a.broman58@gmail.com>
Tested-by: Petri Dish Buildbot
Reviewed-by: Michael Mann <mmann78@netscape.net>
Diffstat (limited to 'plugins')
-rw-r--r-- | plugins/transum/decoders.c | 37 | ||||
-rw-r--r-- | plugins/transum/packet-transum.c | 694 | ||||
-rw-r--r-- | plugins/transum/packet-transum.h | 22 | ||||
-rw-r--r-- | plugins/transum/preferences.h | 1 |
4 files changed, 446 insertions, 308 deletions
diff --git a/plugins/transum/decoders.c b/plugins/transum/decoders.c index 77d647d54c..e47539e5ac 100644 --- a/plugins/transum/decoders.c +++ b/plugins/transum/decoders.c @@ -44,13 +44,11 @@ int decode_syn(packet_info *pinfo _U_, proto_tree *tree _U_, PKT_INFO* pkt_info) else { pkt_info->rrpd.c2s = TRUE; - pkt_info->rrpd.state = RRPD_STATE_4; add_detected_tcp_svc(pkt_info->dstport); } - pkt_info->rrpd.session_id = 1; - pkt_info->rrpd.msg_id = 1; - pkt_info->rrpd.suffix = 1; + pkt_info->rrpd.session_id = 1; /* Fake session ID */ + pkt_info->rrpd.msg_id = 1; /* Fake message ID */ pkt_info->rrpd.decode_based = TRUE; pkt_info->rrpd.calculation = RTE_CALC_SYN; pkt_info->pkt_of_interest = TRUE; @@ -132,7 +130,6 @@ int decode_dcerpc(packet_info *pinfo _U_, proto_tree *tree, PKT_INFO* pkt_info) wmem_map_insert(preferences.tcp_svc_ports, GUINT_TO_POINTER(pkt_info->srcport), GUINT_TO_POINTER(RTE_CALC_DCERPC)); /* make sure we have this DCE-RPC service port set */ } - pkt_info->rrpd.suffix = 1; pkt_info->rrpd.decode_based = TRUE; pkt_info->rrpd.calculation = RTE_CALC_DCERPC; pkt_info->pkt_of_interest = TRUE; @@ -169,7 +166,6 @@ int decode_smb(packet_info *pinfo _U_, proto_tree *tree, PKT_INFO* pkt_info, PKT /* Default in case we don't have header information */ pkt_info->rrpd.session_id = 0; pkt_info->rrpd.msg_id = 0; - pkt_info->rrpd.suffix = 1; pkt_info->rrpd.decode_based = TRUE; pkt_info->rrpd.calculation = RTE_CALC_SMB2; pkt_info->pkt_of_interest = TRUE; @@ -187,7 +183,6 @@ int decode_smb(packet_info *pinfo _U_, proto_tree *tree, PKT_INFO* pkt_info, PKT subpackets[i].rrpd.session_id = ses_id[i]; subpackets[i].rrpd.msg_id = msg_id[i]; - subpackets[i].rrpd.suffix = 1; subpackets[i].rrpd.decode_based = TRUE; subpackets[i].rrpd.calculation = RTE_CALC_SMB2; @@ -244,18 +239,28 @@ int decode_gtcp(packet_info *pinfo, proto_tree *tree, PKT_INFO* pkt_info) pkt_info->tcp_keep_alive = field_bool[0]; } - if (((wmem_map_lookup(preferences.tcp_svc_ports, GUINT_TO_POINTER(pkt_info->dstport)) != NULL) || - (wmem_map_lookup(preferences.tcp_svc_ports, GUINT_TO_POINTER(pkt_info->srcport)) != NULL)) && - (pkt_info->len > 0)) + /* we use the SSL Content Type to detect SSL Alerts */ + if (!extract_uint(tree, hf_of_interest[HF_INTEREST_SSL_CONTENT_TYPE].hf, field_uint, &field_value_count)) + { + if (field_value_count) + pkt_info->ssl_content_type = field_uint[0]; + else + pkt_info->ssl_content_type = 0; + } + + if (wmem_map_lookup(preferences.tcp_svc_ports, GUINT_TO_POINTER(pkt_info->dstport)) != NULL || + wmem_map_lookup(preferences.tcp_svc_ports, GUINT_TO_POINTER(pkt_info->srcport)) != NULL) { if (wmem_map_lookup(preferences.tcp_svc_ports, GUINT_TO_POINTER(pkt_info->dstport)) != NULL) pkt_info->rrpd.c2s = TRUE; - pkt_info->rrpd.session_id = 1; - pkt_info->rrpd.msg_id = 1; + pkt_info->rrpd.is_retrans = pkt_info->tcp_retran; + pkt_info->rrpd.session_id = 0; + pkt_info->rrpd.msg_id = 0; pkt_info->rrpd.calculation = RTE_CALC_GTCP; pkt_info->rrpd.decode_based = FALSE; - pkt_info->pkt_of_interest = TRUE; + if (pkt_info->len > 0) + pkt_info->pkt_of_interest = TRUE; return 1; } @@ -275,7 +280,6 @@ int decode_dns(packet_info *pinfo _U_, proto_tree *tree, PKT_INFO* pkt_info) } pkt_info->rrpd.session_id = 1; - pkt_info->rrpd.suffix = 1; /* need to do something tricky here as dns.id gets reused */ pkt_info->rrpd.decode_based = TRUE; pkt_info->rrpd.calculation = RTE_CALC_DNS; pkt_info->pkt_of_interest = TRUE; @@ -308,9 +312,8 @@ int decode_gudp(packet_info *pinfo, proto_tree *tree, PKT_INFO* pkt_info) if (wmem_map_lookup(preferences.udp_svc_ports, GUINT_TO_POINTER(pkt_info->dstport)) != NULL) pkt_info->rrpd.c2s = TRUE; - pkt_info->rrpd.session_id = 1; - pkt_info->rrpd.msg_id = 1; - pkt_info->rrpd.suffix = 1; + pkt_info->rrpd.session_id = 0; + pkt_info->rrpd.msg_id = 0; pkt_info->rrpd.decode_based = FALSE; pkt_info->rrpd.calculation = RTE_CALC_GUDP; pkt_info->pkt_of_interest = TRUE; diff --git a/plugins/transum/packet-transum.c b/plugins/transum/packet-transum.c index 0d08d722dc..7c4e0065ab 100644 --- a/plugins/transum/packet-transum.c +++ b/plugins/transum/packet-transum.c @@ -48,13 +48,6 @@ static dissector_handle_t transum_handle; #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 - /* The following are the field ids for the protocol values used by TRANSUM. Make sure they line up with ehf_of_interest order */ HF_OF_INTEREST_INFO hf_of_interest[HF_INTEREST_END_OF_LIST] = { @@ -78,6 +71,8 @@ HF_OF_INTEREST_INFO hf_of_interest[HF_INTEREST_END_OF_LIST] = { { -1, "udp.stream" }, { -1, "udp.length" }, + { -1, "ssl.record.content_type" }, + { -1, "tds.type" }, { -1, "tds.length" }, @@ -107,6 +102,8 @@ static wmem_map_t *detected_tcp_svc; /* this array is used to track services de static wmem_map_t *dcerpc_req_pkt_type; /* used to indicate if a DCE-RPC pkt_type is a request */ +static wmem_map_t *dcerpc_streams = NULL; /* used to record TCP stream numbers that are carrying DCE-RPC data */ + /* This array contains calls and returns that have no TRUE context_id This is needed to overcome an apparent bug in Wireshark where @@ -115,11 +112,6 @@ in a message header */ static wmem_map_t *dcerpc_context_zero; -#if 0 -/* rrpd-related globals */ -guint32 rrpd_suffix = 0; -#endif - /* The rrpd_list holds information about all of the APDU Request-Response Pairs seen in the trace. */ @@ -134,13 +126,19 @@ static wmem_map_t *output_rrpd; /* 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). + fully qualify the identification of the RRPD (the identification being ip_proto:stream_no:session_id:msg_id). 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. */ static wmem_list_t *temp_rsp_rrpd_list = NULL; /* Reuse these for speed and efficient memory use - issue a warning if we run out */ +/* Optimisation data - the following is used for various optimisation measures */ +static int highest_tcp_stream_no; +static int highest_udp_stream_no; +wmem_map_t *tcp_stream_exceptions; + + static gint ett_transum = -1; static gint ett_transum_header = -1; static gint ett_transum_data = -1; @@ -160,6 +158,8 @@ static int hf_tsum_rsp_spread = -1; static int hf_tsum_clip_filter = -1; static int hf_tsum_calculation = -1; static int hf_tsum_summary = -1; +static int hf_tsum_req_search = -1; +static int hf_tsum_rsp_search = -1; static const enum_val_t capture_position_vals[] = { { "TRACE_CAP_CLIENT", "Client", TRACE_CAP_CLIENT }, @@ -204,6 +204,11 @@ static void init_dcerpc_data(void) wmem_map_insert(dcerpc_context_zero, GUINT_TO_POINTER(15), GUINT_TO_POINTER(15)); } +static void register_dcerpc_stream(guint32 stream_no) +{ + wmem_map_insert(dcerpc_streams, GUINT_TO_POINTER(stream_no), GUINT_TO_POINTER(1)); +} + /* This function should be called before any change to RTE data. */ static void null_output_rrpd_entries(RRPD *in_rrpd) { @@ -234,21 +239,6 @@ static RRPD* append_to_rrpd_list(RRPD *in_rrpd) { RRPD *next_rrpd = (RRPD*)wmem_memdup(wmem_file_scope(), in_rrpd, sizeof(RRPD)); - if (preferences.reassembly) - { - if (next_rrpd->msg_id) - next_rrpd->state = RRPD_STATE_3; - else - next_rrpd->state = RRPD_STATE_1; - } - else - { - if (next_rrpd->msg_id) - next_rrpd->state = RRPD_STATE_4; - else - next_rrpd->state = RRPD_STATE_2; - } - update_output_rrpd(next_rrpd); wmem_list_append(rrpd_list, next_rrpd); @@ -256,233 +246,352 @@ static RRPD* append_to_rrpd_list(RRPD *in_rrpd) return next_rrpd; } -/* -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. -*/ -static RRPD *find_latest_rrpd(RRPD *in_rrpd, int state) +static RRPD *find_latest_rrpd_dcerpc(RRPD *in_rrpd) { - RRPD *rrpd_index = NULL, *rrpd; + RRPD *rrpd; wmem_list_frame_t* i; - /* If this is a SYN from C2S there is no point searching the list */ - if (in_rrpd->c2s && in_rrpd->calculation == RTE_CALC_SYN) - return NULL; - for (i = wmem_list_tail(rrpd_list); i != NULL; i = wmem_list_frame_prev(i)) { rrpd = (RRPD*)wmem_list_frame_data(i); + + if (rrpd->calculation != RTE_CALC_DCERPC && rrpd->calculation != RTE_CALC_SYN) + continue; + + /* if the input 5-tuple doesn't match the rrpd_list_entry 5-tuple -> go find the next list entry */ if (rrpd->ip_proto == in_rrpd->ip_proto && rrpd->stream_no == in_rrpd->stream_no) { - if (in_rrpd->decode_based) + /* if we can match on session_id and msg_id must be a retransmission of the last request packet or the response */ + /* this logic works whether or not we are using reassembly */ + if (rrpd->session_id == in_rrpd->session_id && rrpd->msg_id == in_rrpd->msg_id) + return rrpd; + + /* If this is a retransmission, we assume it relates to this rrpd_list entry. + This is a bit of a kludge and not ideal but a compromise.*/ + /* ToDo: look at using TCP sequence number to allocate a retransmission to the correct APDU */ + if (in_rrpd->is_retrans) + return rrpd; + + if (preferences.reassembly) { - /* 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 (in_rrpd->c2s) { - if (rrpd->session_id == 0 && rrpd->msg_id == 0 && rrpd->suffix == 1) - { - rrpd_index = rrpd; - break; - } + /* if the input rrpd is for c2s and the one we have found already has response information, then the + in_rrpd represents a new RR Pair. */ + if (rrpd->rsp_first_frame) + return NULL; + + /* If the current rrpd_list entry doesn't have a msg_id then we assume we are mid Request APDU and so we have a match. */ + if (!rrpd->msg_id) + return rrpd; } - - /* if this stream is decode_based we need to take into account the session_id, msg_id and suffix */ - if (rrpd->session_id == in_rrpd->session_id && rrpd->msg_id == in_rrpd->msg_id && rrpd->suffix == in_rrpd->suffix) + else /* The in_rrpd relates to a packet going s2c */ { - if (state == RRPD_STATE_DONT_CARE || rrpd->state == state) - { - rrpd_index = rrpd; - break; - } + /* When reassembly is enabled, multi-packet response information is actually migrated from the temp_rsp_rrpd_list + to the rrpd_list and so we won't come through here. */ + ; } } - else + else /* we are not using reassembly */ { - /* 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->state == state) + if (in_rrpd->c2s) { - rrpd_index = rrpd; - break; + if (in_rrpd->msg_id) + /* if we have a message id this is a new Request APDU */ + return NULL; + else /* No msg_id */ + { + return rrpd; /* add this packet to the matching stream */ + } + } + else /* this packet is going s2c */ + { + if (!in_rrpd->msg_id && rrpd->rsp_first_frame) + /* we need to add this frame to the response APDU of the most recent rrpd_list entry that has already had response packets */ + return rrpd; } } - } - } - return rrpd_index; + } /* this is the end of the 5-tuple check */ + + if (in_rrpd->c2s) + in_rrpd->req_search_total++; + else + in_rrpd->rsp_search_total++; + } /* end of the for loop */ + + return NULL; } -static void update_rrpd_list_entry(RRPD *match, RRPD *in_rrpd) +static RRPD *find_latest_rrpd_dns(RRPD *in_rrpd) { - null_output_rrpd_entries(match); + RRPD *rrpd; + wmem_list_frame_t* i; - switch (match->state) + for (i = wmem_list_tail(rrpd_list); i != NULL; i = wmem_list_frame_prev(i)) { - case RRPD_STATE_1: - if (in_rrpd->c2s) + rrpd = (RRPD*)wmem_list_frame_data(i); + + if (rrpd->calculation != RTE_CALC_DNS) + continue; + + /* if the input 5-tuple doesn't match the rrpd_list_entry 5-tuple -> go find the next list entry */ + if (rrpd->ip_proto == in_rrpd->ip_proto && rrpd->stream_no == in_rrpd->stream_no) { - match->req_last_frame = in_rrpd->req_last_frame; - match->req_last_rtime = in_rrpd->req_last_rtime; - if (in_rrpd->msg_id) + if (rrpd->session_id == in_rrpd->session_id && rrpd->msg_id == in_rrpd->msg_id) { - match->session_id = in_rrpd->session_id; - match->msg_id = in_rrpd->msg_id; - match->suffix = in_rrpd->suffix; - match->state = RRPD_STATE_3; + if (in_rrpd->c2s && rrpd->rsp_first_frame) + return NULL; /* this is new */ + else + return rrpd; } - } - else - { - match->rsp_first_frame = in_rrpd->rsp_first_frame; - match->rsp_first_rtime = in_rrpd->rsp_first_rtime; - match->rsp_last_frame = in_rrpd->rsp_last_frame; - match->rsp_last_rtime = in_rrpd->rsp_last_rtime; - if (in_rrpd->msg_id) - match->state = RRPD_STATE_7; - else - match->state = RRPD_STATE_5; - } - break; + } /* this is the end of the 5-tuple check */ - case RRPD_STATE_2: if (in_rrpd->c2s) - { - match->req_last_frame = in_rrpd->req_last_frame; - match->req_last_rtime = in_rrpd->req_last_rtime; - if (in_rrpd->msg_id) - { - match->session_id = in_rrpd->session_id; - match->msg_id = in_rrpd->msg_id; - match->suffix = in_rrpd->suffix; - match->state = RRPD_STATE_4; - } - } + in_rrpd->req_search_total++; else + in_rrpd->rsp_search_total++; + } /* this is the end of the for loop */ + + return NULL; +} + +static RRPD *find_latest_rrpd_gtcp(RRPD *in_rrpd) +{ + RRPD *rrpd; + wmem_list_frame_t* i; + + for (i = wmem_list_tail(rrpd_list); i != NULL; i = wmem_list_frame_prev(i)) + { + rrpd = (RRPD*)wmem_list_frame_data(i); + + if (rrpd->calculation != RTE_CALC_GTCP && rrpd->calculation != RTE_CALC_SYN) + continue; + + /* if the input 5-tuple doesn't match the rrpd_list_entry 5-tuple -> go find the next list entry */ + if (rrpd->ip_proto == in_rrpd->ip_proto && rrpd->stream_no == in_rrpd->stream_no) { - match->rsp_first_frame = in_rrpd->rsp_first_frame; - match->rsp_first_rtime = in_rrpd->rsp_first_rtime; - match->rsp_last_frame = in_rrpd->rsp_last_frame; - match->rsp_last_rtime = in_rrpd->rsp_last_rtime; - if (in_rrpd->msg_id) - match->state = RRPD_STATE_8; + if (in_rrpd->c2s && rrpd->rsp_first_frame) + return NULL; /* this is new */ else - match->state = RRPD_STATE_6; - } - break; + return rrpd; + } /* this is the end of the 5-tuple check */ - case RRPD_STATE_3: if (in_rrpd->c2s) - { - match->req_last_frame = in_rrpd->req_last_frame; - match->req_last_rtime = in_rrpd->req_last_rtime; - if (in_rrpd->msg_id) - { - match->session_id = in_rrpd->session_id; - match->msg_id = in_rrpd->msg_id; - match->suffix = in_rrpd->suffix; - match->state = RRPD_STATE_3; - } - } + in_rrpd->req_search_total++; else + in_rrpd->rsp_search_total++; + } /* this is the end of the for loop */ + + return NULL; +} + +static RRPD *find_latest_rrpd_gudp(RRPD *in_rrpd) +{ + RRPD *rrpd; + wmem_list_frame_t* i; + + for (i = wmem_list_tail(rrpd_list); i != NULL; i = wmem_list_frame_prev(i)) + { + rrpd = (RRPD*)wmem_list_frame_data(i); + + if (rrpd->calculation != RTE_CALC_GUDP) + continue; + + /* if the input 5-tuple doesn't match the rrpd_list_entry 5-tuple -> go find the next list entry */ + if (rrpd->ip_proto == in_rrpd->ip_proto && rrpd->stream_no == in_rrpd->stream_no) { - match->rsp_first_frame = in_rrpd->rsp_first_frame; - match->rsp_first_rtime = in_rrpd->rsp_first_rtime; - match->rsp_last_frame = in_rrpd->rsp_last_frame; - match->rsp_last_rtime = in_rrpd->rsp_last_rtime; - if (in_rrpd->msg_id) - match->state = RRPD_STATE_7; + if (in_rrpd->c2s && rrpd->rsp_first_frame) + return NULL; /* this is new */ else - match->state = RRPD_STATE_5; - } - break; + return rrpd; + } /* this is the end of the 5-tuple check */ - case RRPD_STATE_4: if (in_rrpd->c2s) + in_rrpd->req_search_total++; + else + in_rrpd->rsp_search_total++; + } /* this is the end of the for loop */ + + return NULL; +} + +static RRPD *find_latest_rrpd_smb2(RRPD *in_rrpd) +{ + RRPD *rrpd; + wmem_list_frame_t* i; + + for (i = wmem_list_tail(rrpd_list); i != NULL; i = wmem_list_frame_prev(i)) + { + rrpd = (RRPD*)wmem_list_frame_data(i); + + if (rrpd->calculation != RTE_CALC_SMB2 && rrpd->calculation != RTE_CALC_SYN) + continue; + + /* if the input 5-tuple doesn't match the rrpd_list_entry 5-tuple -> go find the next list entry */ + if (rrpd->ip_proto == in_rrpd->ip_proto && rrpd->stream_no == in_rrpd->stream_no) { - match->req_last_frame = in_rrpd->req_last_frame; - match->req_last_rtime = in_rrpd->req_last_rtime; - if (in_rrpd->msg_id) + /* if we can match on session_id and msg_id must be a retransmission of the last request packet or the response */ + /* this logic works whether or not we are using reassembly */ + if (rrpd->session_id == in_rrpd->session_id && rrpd->msg_id == in_rrpd->msg_id) + return rrpd; + + /* If this is a retransmission, we assume it relates to this rrpd_list entry. + This is a bit of a kludge and not ideal but a compromise.*/ + /* ToDo: look at using TCP sequence number to allocate a retransmission to the correct APDU */ + if (in_rrpd->is_retrans) + return rrpd; + + if (preferences.reassembly) { - match->session_id = in_rrpd->session_id; - match->msg_id = in_rrpd->msg_id; - match->suffix = in_rrpd->suffix; - match->state = RRPD_STATE_4; + if (in_rrpd->c2s) + { + /* if the input rrpd is for c2s and the one we have found already has response information, then the + in_rrpd represents a new RR Pair. */ + if (rrpd->rsp_first_frame) + return NULL; + + /* If the current rrpd_list entry doesn't have a msg_id then we assume we are mid Request APDU and so we have a match. */ + if (!rrpd->msg_id) + return rrpd; + } + else /* The in_rrpd relates to a packet going s2c */ + { + /* When reassembly is enabled, multi-packet response information is actually migrated from the temp_rsp_rrpd_list + to the rrpd_list and so we won't come through here. */ + ; + } } - } - else - { - match->rsp_first_frame = in_rrpd->rsp_first_frame; - match->rsp_first_rtime = in_rrpd->rsp_first_rtime; - match->rsp_last_frame = in_rrpd->rsp_last_frame; - match->rsp_last_rtime = in_rrpd->rsp_last_rtime; - if (in_rrpd->msg_id) - match->state = RRPD_STATE_8; - else - match->state = RRPD_STATE_6; - } - break; + else /* we are not using reassembly */ + { + if (in_rrpd->c2s) + { + if (in_rrpd->msg_id) + /* if we have a message id this is a new Request APDU */ + return NULL; + else /* No msg_id */ + { + return rrpd; /* add this packet to the matching stream */ + } + } + else /* this packet is going s2c */ + { + if (!in_rrpd->msg_id && rrpd->rsp_first_frame) + /* we need to add this frame to the response APDU of the most recent rrpd_list entry that has already had response packets */ + return rrpd; + } + } + } /* this is the end of the 5-tuple check */ - case RRPD_STATE_5: if (in_rrpd->c2s) - { - /* we've change direction */ - ; - } + in_rrpd->req_search_total++; else + in_rrpd->rsp_search_total++; + } /* end of the for loop */ + + return NULL; +} + +static RRPD *find_latest_rrpd_syn(RRPD *in_rrpd) +{ + RRPD *rrpd; + wmem_list_frame_t* i; + + for (i = wmem_list_tail(rrpd_list); i != NULL; i = wmem_list_frame_prev(i)) + { + rrpd = (RRPD*)wmem_list_frame_data(i); + + if (rrpd->calculation != RTE_CALC_SYN) + continue; + + /* if the input 5-tuple doesn't match the rrpd_list_entry 5-tuple -> go find the next list entry */ + if (rrpd->ip_proto == in_rrpd->ip_proto && rrpd->stream_no == in_rrpd->stream_no) { - match->rsp_last_frame = in_rrpd->rsp_last_frame; - match->rsp_last_rtime = in_rrpd->rsp_last_rtime; - if (in_rrpd->msg_id) - match->state = RRPD_STATE_7; - else - match->state = RRPD_STATE_5; - } - break; + return rrpd; + } /* this is the end of the 5-tuple check */ - case RRPD_STATE_6: if (in_rrpd->c2s) - { - /* we've change direction */ - ; - } + in_rrpd->req_search_total++; else - { - match->rsp_last_frame = in_rrpd->rsp_last_frame; - match->rsp_last_rtime = in_rrpd->rsp_last_rtime; - if (in_rrpd->msg_id) - match->state = RRPD_STATE_8; - else - match->state = RRPD_STATE_6; - } + in_rrpd->rsp_search_total++; + } /* this is the end of the for loop */ + + return NULL; +} + +static RRPD *find_latest_rrpd(RRPD *in_rrpd) +{ + /* Optimisation Code */ + if (in_rrpd->ip_proto == IP_PROTO_TCP && (int)in_rrpd->stream_no > highest_tcp_stream_no) + { + highest_tcp_stream_no = in_rrpd->stream_no; + return NULL; + } + else if (in_rrpd->ip_proto == IP_PROTO_UDP && (int)in_rrpd->stream_no > highest_udp_stream_no) + { + highest_udp_stream_no = in_rrpd->stream_no; + return NULL; + } + /* End of Optimisation Code */ + + switch (in_rrpd->calculation) + { + case RTE_CALC_DCERPC: + return find_latest_rrpd_dcerpc(in_rrpd); break; - case RRPD_STATE_7: - if (in_rrpd->c2s) - { - /* we've change direction */ - ; - } - else - { - match->rsp_last_frame = in_rrpd->rsp_last_frame; - match->rsp_last_rtime = in_rrpd->rsp_last_rtime; - } + case RTE_CALC_DNS: + return find_latest_rrpd_dns(in_rrpd); break; - case RRPD_STATE_8: - if (in_rrpd->c2s) + case RTE_CALC_GTCP: + return find_latest_rrpd_gtcp(in_rrpd); + break; + + case RTE_CALC_GUDP: + return find_latest_rrpd_gudp(in_rrpd); + break; + + case RTE_CALC_SMB2: + return find_latest_rrpd_smb2(in_rrpd); + break; + + case RTE_CALC_SYN: + return find_latest_rrpd_syn(in_rrpd); + break; + } + + return NULL; +} + +static void update_rrpd_list_entry(RRPD *match, RRPD *in_rrpd) +{ + null_output_rrpd_entries(match); + + if (preferences.debug_enabled) + { + match->req_search_total += in_rrpd->req_search_total; + match->rsp_search_total += in_rrpd->rsp_search_total; + } + + if (in_rrpd->c2s) + { + match->req_last_frame = in_rrpd->req_last_frame; + match->req_last_rtime = in_rrpd->req_last_rtime; + if (in_rrpd->msg_id) { - /* we've change direction */ - ; + match->session_id = in_rrpd->session_id; + match->msg_id = in_rrpd->msg_id; } - else + } + else + { + if (!match->rsp_first_frame) { - match->rsp_last_frame = in_rrpd->rsp_last_frame; - match->rsp_last_rtime = in_rrpd->rsp_last_rtime; + match->rsp_first_frame = in_rrpd->rsp_first_frame; + match->rsp_first_rtime = in_rrpd->rsp_first_rtime; } - break; + match->rsp_last_frame = in_rrpd->rsp_last_frame; + match->rsp_last_rtime = in_rrpd->rsp_last_rtime; } update_output_rrpd(match); @@ -495,61 +604,17 @@ static void update_rrpd_list_entry_req(RRPD *in_rrpd) { RRPD *match; - if (in_rrpd->decode_based) - { - while (TRUE) - { - if (preferences.reassembly) - { - match = find_latest_rrpd(in_rrpd, RRPD_STATE_1); - if (match != NULL) /* Check to cover TCP Reassembly enabled */ - { - update_rrpd_list_entry(match, in_rrpd); - break; - } - } - else - { - match = find_latest_rrpd(in_rrpd, RRPD_STATE_4); - if (match != NULL) - { - update_rrpd_list_entry(match, in_rrpd); - break; - } - } + match = find_latest_rrpd(in_rrpd); - /* No entries and so add one */ - append_to_rrpd_list(in_rrpd); - break; - } - } + if (match != NULL) + update_rrpd_list_entry(match, in_rrpd); 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 = find_latest_rrpd(in_rrpd, RRPD_STATE_DONT_CARE); - if (match != NULL) - { - if (match->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, in_rrpd); - } - else - { - append_to_rrpd_list(in_rrpd); - } - } + append_to_rrpd_list(in_rrpd); } /* 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. + successful return a pointer to the entry, else return NULL. */ static RRPD* insert_into_temp_rsp_rrpd_list(RRPD *in_rrpd) { @@ -587,12 +652,6 @@ static void migrate_temp_rsp_rrpd(RRPD *main_list, RRPD *temp_list) update_rrpd_list_entry(main_list, temp_list); wmem_list_remove(temp_rsp_rrpd_list, temp_list); - - /* Update the state to 7 or 8 based on reassembly */ - if (preferences.reassembly) - main_list->state = RRPD_STATE_7; - else - main_list->state = RRPD_STATE_8; } static void update_rrpd_list_entry_rsp(RRPD *in_rrpd) @@ -613,13 +672,13 @@ static void update_rrpd_list_entry_rsp(RRPD *in_rrpd) update_temp_rsp_rrpd(temp_list, in_rrpd); /* Migrate the temp_rsp_rrpd_list entry to the main rrpd_list */ - match = find_latest_rrpd(in_rrpd, RRPD_STATE_3); + match = find_latest_rrpd(in_rrpd); if (match != NULL) migrate_temp_rsp_rrpd(match, temp_list); } else { - match = find_latest_rrpd(in_rrpd, RRPD_STATE_3); + match = find_latest_rrpd(in_rrpd); /* There isn't an entry in the temp_rsp_rrpd_list so update the master rrpd_list entry */ if (match != NULL) update_rrpd_list_entry(match, in_rrpd); @@ -633,13 +692,27 @@ static void update_rrpd_list_entry_rsp(RRPD *in_rrpd) if (temp_list != NULL) update_temp_rsp_rrpd(temp_list, in_rrpd); else - insert_into_temp_rsp_rrpd_list(in_rrpd); + { + /* If this is a retransmission we need to add it to the last completed rrpd_list entry for this stream */ + if (in_rrpd->is_retrans) + { + match = find_latest_rrpd(in_rrpd); + + if (match != NULL) + update_rrpd_list_entry(match, in_rrpd); + else + insert_into_temp_rsp_rrpd_list(in_rrpd); + } + else + /* As it's not a retransmission, just create a new entry on the temp list */ + insert_into_temp_rsp_rrpd_list(in_rrpd); + } } } else { /* Reassembly isn't set and so just go ahead and use the list function */ - match = find_latest_rrpd(in_rrpd, RRPD_STATE_8); + match = find_latest_rrpd(in_rrpd); if (match != NULL) update_rrpd_list_entry(match, in_rrpd); } @@ -647,7 +720,7 @@ static void update_rrpd_list_entry_rsp(RRPD *in_rrpd) else { /* if this isn't decode_based then just go ahead and update the RTE data */ - match = find_latest_rrpd(in_rrpd, RRPD_STATE_DONT_CARE); + match = find_latest_rrpd(in_rrpd); if (match != NULL) update_rrpd_list_entry(match, in_rrpd); } @@ -670,21 +743,6 @@ static void update_rrpd_rte_data(RRPD *in_rrpd) update_rrpd_list_entry_rsp(in_rrpd); } -#if 0 -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; -} -#endif - gboolean is_dcerpc_context_zero(guint32 pkt_type) { return (wmem_map_lookup(dcerpc_context_zero, GUINT_TO_POINTER(pkt_type)) != NULL); @@ -695,6 +753,10 @@ gboolean is_dcerpc_req_pkt_type(guint32 pkt_type) return (wmem_map_lookup(dcerpc_req_pkt_type, GUINT_TO_POINTER(pkt_type)) != NULL); } +gboolean is_dcerpc_stream(guint32 stream_no) +{ + return (wmem_map_lookup(dcerpc_streams, GUINT_TO_POINTER(stream_no)) != NULL); +} /* This function initialises the global variables and populates the @@ -705,7 +767,11 @@ static void init_globals(void) if (!proto_is_protocol_enabled(find_protocol_by_id(proto_transum))) return; + highest_tcp_stream_no = -1; + highest_udp_stream_no = -1; + /* Create and initialise some dynamic memory areas */ + tcp_stream_exceptions = wmem_map_new(wmem_file_scope(), g_direct_hash, g_direct_equal); detected_tcp_svc = wmem_map_new(wmem_file_scope(), g_direct_hash, g_direct_equal); rrpd_list = wmem_list_new(wmem_file_scope()); temp_rsp_rrpd_list = wmem_list_new(wmem_file_scope()); @@ -742,6 +808,7 @@ static void init_globals(void) /* create arrays to hold some DCE-RPC values */ dcerpc_context_zero = wmem_map_new(wmem_file_scope(), g_direct_hash, g_direct_equal); dcerpc_req_pkt_type = wmem_map_new(wmem_file_scope(), g_direct_hash, g_direct_equal); + dcerpc_streams = wmem_map_new(wmem_file_scope(), g_direct_hash, g_direct_equal); init_dcerpc_data(); wmem_map_insert(preferences.tcp_svc_ports, GUINT_TO_POINTER(445), GUINT_TO_POINTER(RTE_CALC_SMB2)); @@ -849,6 +916,14 @@ static void write_rte(RRPD *in_rrpd, tvbuff_t *tvb, proto_tree *tree, char *summ } } } + + if (preferences.debug_enabled) + { + pi = proto_tree_add_uint(rte_tree, hf_tsum_req_search, tvb, 0, 0, in_rrpd->req_search_total); + PROTO_ITEM_SET_GENERATED(pi); + pi = proto_tree_add_uint(rte_tree, hf_tsum_rsp_search, tvb, 0, 0, in_rrpd->rsp_search_total); + PROTO_ITEM_SET_GENERATED(pi); + } } } @@ -882,6 +957,32 @@ static void set_proto_values(packet_info *pinfo, proto_tree *tree, PKT_INFO* pkt 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_ports list). */ + /* Optimisation code */ + if (pkt_info->len || pkt_info->tcp_flags_syn) + { + if (pkt_info->ssl_content_type == 21) /* this is an SSL Alert */ + { + pkt_info->pkt_of_interest = FALSE; + return; + } + + if ((int)pkt_info->rrpd.stream_no > highest_tcp_stream_no && !pkt_info->rrpd.c2s) + { + /* first packet on the stream is s2c and so add to exception list */ + if (wmem_map_lookup(tcp_stream_exceptions, GUINT_TO_POINTER(pkt_info->rrpd.stream_no)) == NULL) + wmem_map_insert(tcp_stream_exceptions, GUINT_TO_POINTER(pkt_info->rrpd.stream_no), GUINT_TO_POINTER(1)); + } + + if (wmem_map_lookup(tcp_stream_exceptions, GUINT_TO_POINTER(pkt_info->rrpd.stream_no)) != NULL) + { + if (pkt_info->rrpd.c2s) + wmem_map_remove(tcp_stream_exceptions, GUINT_TO_POINTER(pkt_info->rrpd.stream_no)); + else + pkt_info->pkt_of_interest = FALSE; + } + } + /* End of Optimisation Code */ + if (pkt_info->tcp_retran) { /* we may not want to continue with this packet if it's a retransmission */ @@ -929,11 +1030,27 @@ static void set_proto_values(packet_info *pinfo, proto_tree *tree, PKT_INFO* pkt if (pkt_info->dstport == 445 || pkt_info->srcport == 445) number_sub_pkts_of_interest = decode_smb(pinfo, tree, pkt_info, subpackets); - /* check if DCE-RPC */ - else if (!extract_uint(tree, hf_of_interest[HF_INTEREST_DCERPC_VER].hf, field_uint, &field_value_count)) + else { - if (field_value_count) - number_sub_pkts_of_interest = decode_dcerpc(pinfo, tree, pkt_info); + /* check if DCE-RPC */ + /* We need to set RTE_CALC_DCERPC even when we don't have header info. */ + if (is_dcerpc_stream(pkt_info->rrpd.stream_no)) + { + pkt_info->rrpd.calculation = RTE_CALC_DCERPC; + pkt_info->rrpd.decode_based = TRUE; + pkt_info->pkt_of_interest = TRUE; + } + + if (!extract_uint(tree, hf_of_interest[HF_INTEREST_DCERPC_VER].hf, field_uint, &field_value_count)) + { + if (field_value_count) + { + if (pkt_info->rrpd.calculation != RTE_CALC_DCERPC) + register_dcerpc_stream(pkt_info->rrpd.stream_no); + + number_sub_pkts_of_interest = decode_dcerpc(pinfo, tree, pkt_info); + } + } } } @@ -1096,7 +1213,20 @@ proto_register_transum(void) { "Summary", "transum.summary", FT_STRING, BASE_NONE, NULL, 0x0, "Summarizer information", HFILL } + }, + + { &hf_tsum_req_search, + { "Req Search Count", "transum.req_search", + FT_UINT32, BASE_DEC, NULL, 0x0, + "rrpd_list search total for the request packets", HFILL } + }, + + { &hf_tsum_rsp_search, + { "Rsp Search Counts", "transum.rsp_search", + FT_UINT32, BASE_DEC, NULL, 0x0, + "rrpd_list search total for the reponse packets", HFILL } } + }; /* Setup protocol subtree array */ @@ -1126,6 +1256,8 @@ proto_register_transum(void) preferences.rte_on_first_rsp = FALSE; preferences.rte_on_last_rsp = FALSE; + preferences.debug_enabled = FALSE; + /* no start registering stuff */ proto_register_field_array(proto_transum, hf, array_length(hf)); proto_register_subtree_array(ett, array_length(ett)); @@ -1203,6 +1335,12 @@ proto_register_transum(void) "RTE data will be added to the last response packet", &preferences.rte_on_last_rsp); + prefs_register_bool_preference(transum_module, + "debug_enabled", + "Enable debug info", + "Set this only to troubleshoot problems", + &preferences.debug_enabled); + transum_handle = register_dissector("transum", dissect_transum, proto_transum); register_init_routine(init_globals); diff --git a/plugins/transum/packet-transum.h b/plugins/transum/packet-transum.h index ed3665069e..f633e80b9a 100644 --- a/plugins/transum/packet-transum.h +++ b/plugins/transum/packet-transum.h @@ -28,17 +28,6 @@ #define IP_PROTO_TCP 6 #define IP_PROTO_UDP 17 -#define RRPD_STATE_DONT_CARE 0 -#define RRPD_STATE_INIT 0 -#define RRPD_STATE_1 1 -#define RRPD_STATE_2 2 -#define RRPD_STATE_3 3 -#define RRPD_STATE_4 4 -#define RRPD_STATE_5 5 -#define RRPD_STATE_6 6 -#define RRPD_STATE_7 7 -#define RRPD_STATE_8 8 - #define RTE_CALC_SYN 1 #define RTE_CALC_GTCP 2 #define RTE_CALC_GUDP 3 @@ -68,7 +57,6 @@ typedef struct _RRPD guint32 stream_no; guint64 session_id; guint64 msg_id; - guint32 suffix; /* Some request-response pairs are demarked simple by a change in direction on a @@ -79,7 +67,7 @@ typedef struct _RRPD */ gboolean decode_based; - int state; + gboolean is_retrans; guint32 req_first_frame; nstime_t req_first_rtime; @@ -92,6 +80,10 @@ typedef struct _RRPD nstime_t rsp_last_rtime; guint calculation; + + /* The following numbers are for tuning purposes */ + guint32 req_search_total; /* The total number of steps back through the rrpd_list when matching requests to this entry */ + guint32 rsp_search_total; /* The total number of steps back through the rrpd_list when matching responses to this entry */ } RRPD; typedef struct _PKT_INFO @@ -112,6 +104,8 @@ typedef struct _PKT_INFO guint16 dstport; /* tcp.dstport or udp.dstport*/ guint16 len; /* tcp.len or udp.len */ + guint8 ssl_content_type; /*ssl.record.content_type */ + guint8 tds_type; /*tds.type */ guint16 tds_length; /* tds.length */ @@ -158,6 +152,8 @@ typedef enum { HF_INTEREST_UDP_STREAM, HF_INTEREST_UDP_LENGTH, + HF_INTEREST_SSL_CONTENT_TYPE, + HF_INTEREST_TDS_TYPE, HF_INTEREST_TDS_LENGTH, diff --git a/plugins/transum/preferences.h b/plugins/transum/preferences.h index 6cde8ad8ae..50b68419c9 100644 --- a/plugins/transum/preferences.h +++ b/plugins/transum/preferences.h @@ -50,4 +50,5 @@ typedef struct _TSUM_PREFERENCES gboolean summarisers_enabled; gboolean summarise_tds; gboolean summarisers_escape_quotes; + gboolean debug_enabled; } TSUM_PREFERENCES; |