aboutsummaryrefslogtreecommitdiffstats
path: root/epan/dissectors/asn1/snmp
diff options
context:
space:
mode:
authorLajos Olah <lajos.olah.jr@gmail.com>2019-11-05 22:32:50 +0000
committerAnders Broman <a.broman58@gmail.com>2019-11-07 13:49:15 +0000
commit14d398fe67c1da7b1554a52714b513d86f78e424 (patch)
treeccf45689e589aeda6f97275fb761f0d9af972053 /epan/dissectors/asn1/snmp
parent63e437c02021dc184e1ae29908b0b083b6425dcd (diff)
Implement service response time calculation for SNMP
Change-Id: I731b1971d404f44bf20b13496e0958057c2c94cc Reviewed-on: https://code.wireshark.org/review/34992 Petri-Dish: Anders Broman <a.broman58@gmail.com> Tested-by: Petri Dish Buildbot Reviewed-by: Anders Broman <a.broman58@gmail.com>
Diffstat (limited to 'epan/dissectors/asn1/snmp')
-rw-r--r--epan/dissectors/asn1/snmp/packet-snmp-template.c174
-rw-r--r--epan/dissectors/asn1/snmp/packet-snmp-template.h20
-rw-r--r--epan/dissectors/asn1/snmp/snmp.asn7
-rw-r--r--epan/dissectors/asn1/snmp/snmp.cnf19
4 files changed, 205 insertions, 15 deletions
diff --git a/epan/dissectors/asn1/snmp/packet-snmp-template.c b/epan/dissectors/asn1/snmp/packet-snmp-template.c
index acdb2acd9b..af5c67daab 100644
--- a/epan/dissectors/asn1/snmp/packet-snmp-template.c
+++ b/epan/dissectors/asn1/snmp/packet-snmp-template.c
@@ -48,6 +48,8 @@
#include <epan/asn1.h>
#include <epan/expert.h>
#include <epan/oids.h>
+#include <epan/srt_table.h>
+#include <epan/tap.h>
#include "packet-ipx.h"
#include "packet-hpext.h"
#include "packet-ber.h"
@@ -64,8 +66,10 @@
#define TCP_PORT_SNMP_TRAP 162
#define TCP_PORT_SMUX 199
#define UDP_PORT_SNMP_PATROL 8161
+#define SNMP_NUM_PROCEDURES 8
/* Initialize the protocol and registered fields */
+static int snmp_tap = -1;
static int proto_snmp = -1;
static int proto_smux = -1;
@@ -160,6 +164,7 @@ static snmp_st_assoc_t *specific_traps = NULL;
static const char *enterprise_oid = NULL;
static guint generic_trap = 0;
static guint32 snmp_version = 0;
+static guint32 RequestID = -1;
static snmp_usm_params_t usm_p = {FALSE,FALSE,0,0,0,0,NULL,NULL,NULL,NULL,NULL,NULL,NULL,FALSE};
@@ -181,6 +186,10 @@ static dissector_handle_t data_handle;
static next_tvb_list_t var_list;
+static int hf_snmp_response_in = -1;
+static int hf_snmp_response_to = -1;
+static int hf_snmp_time = -1;
+
static int hf_snmp_v3_flags_auth = -1;
static int hf_snmp_v3_flags_crypt = -1;
static int hf_snmp_v3_flags_report = -1;
@@ -313,6 +322,16 @@ static const value_string smux_types[] = {
};
#endif
+/* Procedure names (used in Service Response Time) */
+const value_string snmp_procedure_names[] = {
+ { 0, "Get" },
+ { 1, "GetNext" },
+ { 3, "Set" },
+ { 5, "Bulk" },
+ { 6, "Inform" },
+ { 4, "Register" },
+ { 0, NULL }
+};
#define SNMP_IPA 0 /* IP Address */
#define SNMP_CNT 1 /* Counter (Counter32) */
@@ -330,6 +349,110 @@ static const value_string smux_types[] = {
dissector_table_t value_sub_dissectors_table;
+/*
+ * Data structure attached to a conversation, request/response information
+ */
+typedef struct snmp_conv_info_t {
+ wmem_map_t *request_response;
+} snmp_conv_info_t;
+
+static snmp_request_response_t *
+snmp_get_request_response_pointer(wmem_map_t *map, guint32 requestId)
+{
+ snmp_request_response_t *srrp=(snmp_request_response_t *)wmem_map_lookup(map, &requestId);
+ if (!srrp) {
+ srrp=wmem_new0(wmem_file_scope(), snmp_request_response_t);
+ srrp->requestId=requestId;
+ wmem_map_insert(map, &(srrp->requestId), (void *)srrp);
+ }
+
+ return srrp;
+}
+
+static snmp_request_response_t*
+snmp_match_request_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint requestId, guint procedure_id, snmp_conv_info_t *snmp_info)
+{
+ snmp_request_response_t *srrp=NULL;
+
+ DISSECTOR_ASSERT_HINT(snmp_info, "No SNMP info from ASN1 context");
+
+ /* get or create request/response pointer based on request id */
+ srrp=(snmp_request_response_t *)snmp_get_request_response_pointer(snmp_info->request_response, requestId);
+
+ // if not visited fill the request/response data
+ if (!pinfo->fd->visited) {
+ switch(procedure_id)
+ {
+ case SNMP_REQ_GET:
+ case SNMP_REQ_GETNEXT:
+ case SNMP_REQ_SET:
+ case SNMP_REQ_GETBULK:
+ case SNMP_REQ_INFORM:
+ srrp->request_frame_id=pinfo->fd->num;
+ srrp->response_frame_id=0;
+ srrp->request_time=pinfo->abs_ts;
+ srrp->request_procedure_id=procedure_id;
+ break;
+ case SNMP_RES_GET:
+ srrp->response_frame_id=pinfo->fd->num;
+ break;
+ default:
+ return NULL;
+ }
+ }
+
+ /* if request and response was matched */
+ if (srrp->request_frame_id!=0 && srrp->response_frame_id!=0)
+ {
+ proto_item *it;
+
+ // if it is a request
+ if (srrp->request_frame_id == pinfo->fd->num)
+ {
+ it=proto_tree_add_uint(tree, hf_snmp_response_in, tvb, 0, 0, srrp->response_frame_id);
+ proto_item_set_generated(it);
+ } else {
+ nstime_t ns;
+ it=proto_tree_add_uint(tree, hf_snmp_response_to, tvb, 0, 0, srrp->request_frame_id);
+ proto_item_set_generated(it);
+ nstime_delta(&ns, &pinfo->abs_ts, &srrp->request_time);
+ it=proto_tree_add_time(tree, hf_snmp_time, tvb, 0, 0, &ns);
+ proto_item_set_generated(it);
+
+ return srrp;
+ }
+ }
+
+ return NULL;
+}
+
+static void
+snmpstat_init(struct register_srt* srt _U_, GArray* srt_array)
+{
+ srt_stat_table *snmp_srt_table;
+ guint32 i;
+
+ snmp_srt_table = init_srt_table("SNMP Commands", NULL, srt_array, SNMP_NUM_PROCEDURES, NULL, "snmp.data", NULL);
+ for (i = 0; i < SNMP_NUM_PROCEDURES; i++)
+ {
+ init_srt_table_row(snmp_srt_table, i, val_to_str_const(i, snmp_procedure_names, "<unknown>"));
+ }
+}
+
+/* This is called only if request and response was matched -> no need to return anything than TAP_PACKET_REDRAW */
+static tap_packet_status
+snmpstat_packet(void *psnmp, packet_info *pinfo, epan_dissect_t *edt _U_, const void *psi)
+{
+ guint i = 0;
+ srt_stat_table *snmp_srt_table;
+ const snmp_request_response_t *snmp=(const snmp_request_response_t *)psi;
+ srt_data_t *data = (srt_data_t *)psnmp;
+
+ snmp_srt_table = g_array_index(data->srt_array, srt_stat_table*, i);
+
+ add_srt_table_data(snmp_srt_table, snmp->request_procedure_id, &snmp->request_time, pinfo);
+ return TAP_PACKET_REDRAW;
+}
static const gchar *
snmp_lookup_specific_trap (guint specific_trap)
@@ -1798,6 +1921,30 @@ check_ScopedPdu(tvbuff_t* tvb)
#include "packet-snmp-fn.c"
+static snmp_conv_info_t*
+snmp_find_conversation_and_get_convo_data(packet_info *pinfo) {
+
+ conversation_t *conversation;
+ snmp_conv_info_t *snmp_info = NULL;
+
+ conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, conversation_pt_to_endpoint_type(pinfo->ptype),
+ pinfo->srcport, pinfo->destport, 0);
+
+ if( (conversation == NULL) || (conversation_get_dissector(conversation, pinfo->num)!=snmp_handle) ) {
+ conversation = conversation_new(pinfo->num, &pinfo->src, &pinfo->dst, conversation_pt_to_endpoint_type(pinfo->ptype),
+ pinfo->srcport, pinfo->destport, 0);
+ conversation_set_dissector(conversation, snmp_handle);
+ }
+
+ snmp_info = (snmp_conv_info_t *)conversation_get_proto_data(conversation, proto_snmp);
+ if (snmp_info == NULL) {
+ snmp_info = wmem_new0(wmem_file_scope(), snmp_conv_info_t);
+ snmp_info->request_response=wmem_map_new(wmem_file_scope(), g_int_hash, g_int_equal);
+
+ conversation_add_proto_data(conversation, proto_snmp, snmp_info);
+ }
+ return snmp_info;
+}
guint
dissect_snmp_pdu(tvbuff_t *tvb, int offset, packet_info *pinfo,
@@ -1816,9 +1963,13 @@ dissect_snmp_pdu(tvbuff_t *tvb, int offset, packet_info *pinfo,
proto_tree *snmp_tree = NULL;
proto_item *item = NULL;
+
+ snmp_conv_info_t *snmp_info = snmp_find_conversation_and_get_convo_data(pinfo);
+
asn1_ctx_t asn1_ctx;
asn1_ctx_init(&asn1_ctx, ASN1_ENC_BER, TRUE, pinfo);
+ asn1_ctx.private_data = snmp_info;
usm_p.msg_tvb = tvb;
usm_p.start_offset = tvb_offset_from_real_beginning(tvb);
@@ -1966,7 +2117,6 @@ dissect_snmp_pdu(tvbuff_t *tvb, int offset, packet_info *pinfo,
static gint
dissect_snmp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
{
- conversation_t *conversation;
int offset;
gint8 tmp_class;
gboolean tmp_pc;
@@ -2029,15 +2179,6 @@ dissect_snmp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_
* the destination address of this packet, and its port 2 being
* wildcarded, and give it the SNMP dissector as a dissector.
*/
- if (pinfo->destport == UDP_PORT_SNMP) {
- conversation = find_conversation(pinfo->num, &pinfo->src, &pinfo->dst, ENDPOINT_UDP,
- pinfo->srcport, 0, NO_PORT_B);
- if( (conversation == NULL) || (conversation_get_dissector(conversation, pinfo->num)!=snmp_handle) ) {
- conversation = conversation_new(pinfo->num, &pinfo->src, &pinfo->dst, ENDPOINT_UDP,
- pinfo->srcport, 0, NO_PORT2);
- conversation_set_dissector(conversation, snmp_handle);
- }
- }
return dissect_snmp_pdu(tvb, 0, pinfo, tree, proto_snmp, ett_snmp, FALSE);
}
@@ -2181,6 +2322,15 @@ UAT_CSTRING_CB_DEF(specific_traps, desc, snmp_st_assoc_t)
void proto_register_snmp(void) {
/* List of fields */
static hf_register_info hf[] = {
+ { &hf_snmp_response_in,
+ { "Response In", "snmp.response_in", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
+ "The response to this SNMP request is in this frame", HFILL }},
+ { &hf_snmp_response_to,
+ { "Response To", "snmp.response_to", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
+ "This is a response to the SNMP request in this frame", HFILL }},
+ { &hf_snmp_time,
+ { "Time", "snmp.time", FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0,
+ "The time between the Request and the Reply", HFILL }},
{ &hf_snmp_v3_flags_auth,
{ "Authenticated", "snmp.v3.flags.auth", FT_BOOLEAN, 8,
TFS(&tfs_set_notset), TH_AUTH, NULL, HFILL }},
@@ -2455,6 +2605,10 @@ void proto_register_snmp(void) {
register_cleanup_routine(cleanup_ue_cache);
register_ber_syntax_dissector("SNMP", proto_snmp, dissect_snmp_tcp);
+
+ snmp_tap=register_tap("snmp");
+
+ register_srt_table(proto_snmp, NULL, 1, snmpstat_packet, snmpstat_init, NULL);
}
diff --git a/epan/dissectors/asn1/snmp/packet-snmp-template.h b/epan/dissectors/asn1/snmp/packet-snmp-template.h
index 4a8b7b6014..362114d593 100644
--- a/epan/dissectors/asn1/snmp/packet-snmp-template.h
+++ b/epan/dissectors/asn1/snmp/packet-snmp-template.h
@@ -11,6 +11,18 @@
#ifndef PACKET_SNMP_H
#define PACKET_SNMP_H
+#define SNMP_REQ_GET 0
+#define SNMP_REQ_GETNEXT 1
+#define SNMP_REQ_SET 3
+#define SNMP_REQ_GETBULK 5
+#define SNMP_REQ_INFORM 6
+
+#define SNMP_RES_GET 2
+
+#define SNMP_TRAP 4
+#define SNMP_TRAPV2 7
+#define SNMP_REPORT 8
+
typedef struct _snmp_usm_key {
guint8* data;
guint len;
@@ -74,6 +86,14 @@ struct _snmp_usm_params_t {
gboolean authOK;
};
+typedef struct snmp_request_response {
+ guint32 request_frame_id;
+ guint32 response_frame_id;
+ nstime_t request_time;
+ guint requestId;
+ guint request_procedure_id;
+} snmp_request_response_t;
+
/*
* Guts of the SNMP dissector - exported for use by protocols such as
* ILMI.
diff --git a/epan/dissectors/asn1/snmp/snmp.asn b/epan/dissectors/asn1/snmp/snmp.asn
index 4abd119625..0361783a97 100644
--- a/epan/dissectors/asn1/snmp/snmp.asn
+++ b/epan/dissectors/asn1/snmp/snmp.asn
@@ -60,7 +60,6 @@ NotificationName ::= OBJECT IDENTIFIER
EnterpriseOID ::= OBJECT IDENTIFIER
NetworkAddress ::= [APPLICATION 0] IMPLICIT OCTET STRING (SIZE (4))
TimeTicks ::= [APPLICATION 3] IMPLICIT INTEGER (0..4294967295)
-Integer32 ::= INTEGER (-2147483648..2147483647)
ObjectName ::= OBJECT IDENTIFIER
--Counter32 ::= [APPLICATION 1] IMPLICIT INTEGER (0..4294967295)
--Gauge32 ::= [APPLICATION 2] IMPLICIT INTEGER (0..4294967295)
@@ -193,7 +192,7 @@ Report-PDU ::= [8] IMPLICIT PDU
PDU ::= SEQUENCE {
- request-id INTEGER,
+ request-id RequestID,
error-status INTEGER {
noError(0),
tooBig(1),
@@ -219,9 +218,11 @@ PDU ::= SEQUENCE {
variable-bindings VarBindList
}
+RequestID ::= INTEGER
+
-- v2
BulkPDU ::= SEQUENCE { -- MUST be identical in structure to PDU
- request-id Integer32,
+ request-id RequestID,
non-repeaters INTEGER (0..2147483647),
max-repetitions INTEGER (0..2147483647),
variable-bindings VarBindList
diff --git a/epan/dissectors/asn1/snmp/snmp.cnf b/epan/dissectors/asn1/snmp/snmp.cnf
index b9ba87b89f..a0f823f3d0 100644
--- a/epan/dissectors/asn1/snmp/snmp.cnf
+++ b/epan/dissectors/asn1/snmp/snmp.cnf
@@ -25,17 +25,32 @@ BulkPDU/request-id bulkPDU_request-id
VAL_PTR = &pdu_type
#.FN_BODY PDUs
-gint pdu_type=-1;
+ gint pdu_type=-1;
- col_clear(actx->pinfo->cinfo, COL_INFO);
+ snmp_request_response_t *srrp;
+ snmp_conv_info_t *snmp_info = (snmp_conv_info_t *)actx->private_data;
+
+ col_clear(actx->pinfo->cinfo, COL_INFO);
%(DEFAULT_BODY)s
if( (pdu_type!=-1) && snmp_PDUs_vals[pdu_type].strptr ){
col_prepend_fstr(actx->pinfo->cinfo, COL_INFO, "%%s", snmp_PDUs_vals[pdu_type].strptr);
}
+ /* pdu_type is the index, not the tag so convert it to the tag value */
+ pdu_type = snmp_PDUs_vals[pdu_type].value;
+
+ srrp=snmp_match_request_response(tvb, actx->pinfo, tree, RequestID, pdu_type, snmp_info);
+ if (srrp) {
+ tap_queue_packet(snmp_tap, actx->pinfo, srrp);
+ }
+
#.END
+#.FN_BODY RequestID VAL_PTR = &RequestID
+
+%(DEFAULT_BODY)s
+
#.FN_BODY Trap-PDU/_untag
generic_trap = 0;
enterprise_oid = NULL;