diff options
author | Lajos Olah <lajos.olah.jr@gmail.com> | 2019-11-05 22:32:50 +0000 |
---|---|---|
committer | Anders Broman <a.broman58@gmail.com> | 2019-11-07 13:49:15 +0000 |
commit | 14d398fe67c1da7b1554a52714b513d86f78e424 (patch) | |
tree | ccf45689e589aeda6f97275fb761f0d9af972053 /epan/dissectors | |
parent | 63e437c02021dc184e1ae29908b0b083b6425dcd (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')
-rw-r--r-- | epan/dissectors/asn1/snmp/packet-snmp-template.c | 174 | ||||
-rw-r--r-- | epan/dissectors/asn1/snmp/packet-snmp-template.h | 20 | ||||
-rw-r--r-- | epan/dissectors/asn1/snmp/snmp.asn | 7 | ||||
-rw-r--r-- | epan/dissectors/asn1/snmp/snmp.cnf | 19 | ||||
-rw-r--r-- | epan/dissectors/packet-snmp.c | 260 | ||||
-rw-r--r-- | epan/dissectors/packet-snmp.h | 20 |
6 files changed, 440 insertions, 60 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; diff --git a/epan/dissectors/packet-snmp.c b/epan/dissectors/packet-snmp.c index c084f2cf0a..718785fd79 100644 --- a/epan/dissectors/packet-snmp.c +++ b/epan/dissectors/packet-snmp.c @@ -56,6 +56,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" @@ -72,8 +74,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; @@ -168,6 +172,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}; @@ -189,6 +194,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; @@ -271,11 +280,11 @@ static int hf_snmp_getBulkRequest = -1; /* GetBulkRequest_PDU */ static int hf_snmp_informRequest = -1; /* InformRequest_PDU */ static int hf_snmp_snmpV2_trap = -1; /* SNMPv2_Trap_PDU */ static int hf_snmp_report = -1; /* Report_PDU */ -static int hf_snmp_request_id = -1; /* INTEGER */ +static int hf_snmp_request_id = -1; /* RequestID */ static int hf_snmp_error_status = -1; /* T_error_status */ static int hf_snmp_error_index = -1; /* INTEGER */ static int hf_snmp_variable_bindings = -1; /* VarBindList */ -static int hf_snmp_bulkPDU_request_id = -1; /* Integer32 */ +static int hf_snmp_bulkPDU_request_id = -1; /* RequestID */ static int hf_snmp_non_repeaters = -1; /* INTEGER_0_2147483647 */ static int hf_snmp_max_repetitions = -1; /* INTEGER_0_2147483647 */ static int hf_snmp_enterprise = -1; /* EnterpriseOID */ @@ -303,7 +312,7 @@ static int hf_snmp_priority = -1; /* INTEGER_M1_2147483647 */ static int hf_snmp_operation = -1; /* T_operation */ /*--- End of included file: packet-snmp-hf.c ---*/ -#line 229 "./asn1/snmp/packet-snmp-template.c" +#line 238 "./asn1/snmp/packet-snmp-template.c" /* Initialize the subtree pointers */ static gint ett_smux = -1; @@ -343,7 +352,7 @@ static gint ett_snmp_SimpleOpen_U = -1; static gint ett_snmp_RReqPDU_U = -1; /*--- End of included file: packet-snmp-ett.c ---*/ -#line 245 "./asn1/snmp/packet-snmp-template.c" +#line 254 "./asn1/snmp/packet-snmp-template.c" static expert_field ei_snmp_failed_decrypted_data_pdu = EI_INIT; static expert_field ei_snmp_decrypted_data_bad_formatted = EI_INIT; @@ -415,6 +424,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) */ @@ -432,6 +451,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) @@ -1906,7 +2029,7 @@ check_ScopedPdu(tvbuff_t* tvb) static int dissect_snmp_EnterpriseOID(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) { -#line 68 "./asn1/snmp/snmp.cnf" +#line 83 "./asn1/snmp/snmp.cnf" const gchar* name; offset = dissect_ber_object_identifier_str(implicit_tag, actx, tree, tvb, offset, hf_index, &enterprise_oid); @@ -1967,16 +2090,6 @@ dissect_snmp_TimeTicks(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset static int -dissect_snmp_Integer32(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) { - offset = dissect_ber_integer(implicit_tag, actx, tree, tvb, offset, hf_index, - NULL); - - return offset; -} - - - -static int dissect_snmp_ObjectName(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) { offset = dissect_ber_object_identifier(implicit_tag, actx, tree, tvb, offset, hf_index, NULL); @@ -2014,9 +2127,14 @@ dissect_snmp_Community(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset static int -dissect_snmp_INTEGER(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) { +dissect_snmp_RequestID(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) { +#line 51 "./asn1/snmp/snmp.cnf" + offset = dissect_ber_integer(implicit_tag, actx, tree, tvb, offset, hf_index, - NULL); + &RequestID); + + + return offset; } @@ -2056,6 +2174,16 @@ dissect_snmp_T_error_status(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int of +static int +dissect_snmp_INTEGER(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) { + offset = dissect_ber_integer(implicit_tag, actx, tree, tvb, offset, hf_index, + NULL); + + return offset; +} + + + static const ber_sequence_t VarBindList_sequence_of[1] = { { &hf_snmp_VarBindList_item, BER_CLASS_UNI, BER_UNI_TAG_SEQUENCE, BER_FLAGS_NOOWNTAG, dissect_snmp_VarBind }, }; @@ -2070,7 +2198,7 @@ dissect_snmp_VarBindList(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offse static const ber_sequence_t PDU_sequence[] = { - { &hf_snmp_request_id , BER_CLASS_UNI, BER_UNI_TAG_INTEGER, BER_FLAGS_NOOWNTAG, dissect_snmp_INTEGER }, + { &hf_snmp_request_id , BER_CLASS_UNI, BER_UNI_TAG_INTEGER, BER_FLAGS_NOOWNTAG, dissect_snmp_RequestID }, { &hf_snmp_error_status , BER_CLASS_UNI, BER_UNI_TAG_INTEGER, BER_FLAGS_NOOWNTAG, dissect_snmp_T_error_status }, { &hf_snmp_error_index , BER_CLASS_UNI, BER_UNI_TAG_INTEGER, BER_FLAGS_NOOWNTAG, dissect_snmp_INTEGER }, { &hf_snmp_variable_bindings, BER_CLASS_UNI, BER_UNI_TAG_SEQUENCE, BER_FLAGS_NOOWNTAG, dissect_snmp_VarBindList }, @@ -2150,7 +2278,7 @@ dissect_snmp_GenericTrap(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offse static int dissect_snmp_SpecificTrap(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) { -#line 52 "./asn1/snmp/snmp.cnf" +#line 67 "./asn1/snmp/snmp.cnf" guint specific_trap; offset = dissect_ber_integer(implicit_tag, actx, tree, tvb, offset, hf_index, @@ -2181,7 +2309,7 @@ static const ber_sequence_t Trap_PDU_U_sequence[] = { static int dissect_snmp_Trap_PDU_U(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) { -#line 40 "./asn1/snmp/snmp.cnf" +#line 55 "./asn1/snmp/snmp.cnf" generic_trap = 0; enterprise_oid = NULL; @@ -2220,7 +2348,7 @@ dissect_snmp_INTEGER_0_2147483647(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, static const ber_sequence_t BulkPDU_sequence[] = { - { &hf_snmp_bulkPDU_request_id, BER_CLASS_UNI, BER_UNI_TAG_INTEGER, BER_FLAGS_NOOWNTAG, dissect_snmp_Integer32 }, + { &hf_snmp_bulkPDU_request_id, BER_CLASS_UNI, BER_UNI_TAG_INTEGER, BER_FLAGS_NOOWNTAG, dissect_snmp_RequestID }, { &hf_snmp_non_repeaters , BER_CLASS_UNI, BER_UNI_TAG_INTEGER, BER_FLAGS_NOOWNTAG, dissect_snmp_INTEGER_0_2147483647 }, { &hf_snmp_max_repetitions, BER_CLASS_UNI, BER_UNI_TAG_INTEGER, BER_FLAGS_NOOWNTAG, dissect_snmp_INTEGER_0_2147483647 }, { &hf_snmp_variable_bindings, BER_CLASS_UNI, BER_UNI_TAG_SEQUENCE, BER_FLAGS_NOOWNTAG, dissect_snmp_VarBindList }, @@ -2305,9 +2433,12 @@ static const ber_choice_t PDUs_choice[] = { static int dissect_snmp_PDUs(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) { #line 28 "./asn1/snmp/snmp.cnf" -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); offset = dissect_ber_choice(actx, tree, tvb, offset, PDUs_choice, hf_index, ett_snmp_PDUs, @@ -2317,6 +2448,14 @@ gint pdu_type=-1; 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); + } + return offset; @@ -2390,7 +2529,7 @@ dissect_snmp_Messagev2u(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset static int dissect_snmp_SnmpEngineID(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) { -#line 102 "./asn1/snmp/snmp.cnf" +#line 117 "./asn1/snmp/snmp.cnf" tvbuff_t* param_tvb = NULL; offset = dissect_ber_octet_string(implicit_tag, actx, tree, tvb, offset, hf_index, ¶m_tvb); @@ -2408,7 +2547,7 @@ dissect_snmp_SnmpEngineID(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offs static int dissect_snmp_T_msgAuthoritativeEngineID(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) { -#line 94 "./asn1/snmp/snmp.cnf" +#line 109 "./asn1/snmp/snmp.cnf" offset = dissect_ber_octet_string(implicit_tag, actx, tree, tvb, offset, hf_index, &usm_p.engine_tvb); if (usm_p.engine_tvb) { @@ -2455,7 +2594,7 @@ dissect_snmp_T_msgUserName(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int off static int dissect_snmp_T_msgAuthenticationParameters(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) { -#line 114 "./asn1/snmp/snmp.cnf" +#line 129 "./asn1/snmp/snmp.cnf" offset = dissect_ber_octet_string(FALSE, actx, tree, tvb, offset, hf_index, &usm_p.auth_tvb); if (usm_p.auth_tvb) { usm_p.auth_item = actx->created_item; @@ -2509,7 +2648,7 @@ dissect_snmp_INTEGER_484_2147483647(gboolean implicit_tag _U_, tvbuff_t *tvb _U_ static int dissect_snmp_T_msgFlags(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) { -#line 219 "./asn1/snmp/snmp.cnf" +#line 234 "./asn1/snmp/snmp.cnf" tvbuff_t *parameter_tvb = NULL; offset = dissect_ber_octet_string(implicit_tag, actx, tree, tvb, offset, hf_index, @@ -2564,7 +2703,7 @@ dissect_snmp_HeaderData(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset static int dissect_snmp_T_msgSecurityParameters(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) { -#line 165 "./asn1/snmp/snmp.cnf" +#line 180 "./asn1/snmp/snmp.cnf" switch(MsgSecurityModel){ case SNMP_SEC_USM: /* 3 */ @@ -2608,7 +2747,7 @@ dissect_snmp_ScopedPDU(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset static int dissect_snmp_T_encryptedPDU(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) { -#line 123 "./asn1/snmp/snmp.cnf" +#line 138 "./asn1/snmp/snmp.cnf" tvbuff_t* crypt_tvb; offset = dissect_ber_octet_string(FALSE, actx, tree, tvb, offset, hf_snmp_encryptedPDU, &crypt_tvb); @@ -2691,7 +2830,7 @@ dissect_snmp_SNMPv3Message(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int off offset = dissect_ber_sequence(implicit_tag, actx, tree, tvb, offset, SNMPv3Message_sequence, hf_index, ett_snmp_SNMPv3Message); -#line 182 "./asn1/snmp/snmp.cnf" +#line 197 "./asn1/snmp/snmp.cnf" if( usm_p.authenticated && usm_p.user_assoc @@ -3005,8 +3144,32 @@ static int dissect_SMUX_PDUs_PDU(tvbuff_t *tvb _U_, packet_info *pinfo _U_, prot /*--- End of included file: packet-snmp-fn.c ---*/ -#line 1800 "./asn1/snmp/packet-snmp-template.c" +#line 1923 "./asn1/snmp/packet-snmp-template.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, @@ -3025,9 +3188,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); @@ -3175,7 +3342,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; @@ -3238,15 +3404,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); } @@ -3390,6 +3547,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 }}, @@ -3653,7 +3819,7 @@ void proto_register_snmp(void) { { &hf_snmp_request_id, { "request-id", "snmp.request_id", FT_INT32, BASE_DEC, NULL, 0, - "INTEGER", HFILL }}, + "RequestID", HFILL }}, { &hf_snmp_error_status, { "error-status", "snmp.error_status", FT_INT32, BASE_DEC, VALS(snmp_T_error_status_vals), 0, @@ -3669,7 +3835,7 @@ void proto_register_snmp(void) { { &hf_snmp_bulkPDU_request_id, { "request-id", "snmp.request_id", FT_INT32, BASE_DEC, NULL, 0, - "Integer32", HFILL }}, + "RequestID", HFILL }}, { &hf_snmp_non_repeaters, { "non-repeaters", "snmp.non_repeaters", FT_UINT32, BASE_DEC, NULL, 0, @@ -3772,7 +3938,7 @@ void proto_register_snmp(void) { NULL, HFILL }}, /*--- End of included file: packet-snmp-hfarr.c ---*/ -#line 2302 "./asn1/snmp/packet-snmp-template.c" +#line 2452 "./asn1/snmp/packet-snmp-template.c" }; /* List of subtrees */ @@ -3812,7 +3978,7 @@ void proto_register_snmp(void) { &ett_snmp_RReqPDU_U, /*--- End of included file: packet-snmp-ettarr.c ---*/ -#line 2318 "./asn1/snmp/packet-snmp-template.c" +#line 2468 "./asn1/snmp/packet-snmp-template.c" }; static ei_register_info ei[] = { { &ei_snmp_failed_decrypted_data_pdu, { "snmp.failed_decrypted_data_pdu", PI_MALFORMED, PI_WARN, "Failed to decrypt encryptedPDU", EXPFILL }}, @@ -3953,6 +4119,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/packet-snmp.h b/epan/dissectors/packet-snmp.h index 189743d49c..48796511ab 100644 --- a/epan/dissectors/packet-snmp.h +++ b/epan/dissectors/packet-snmp.h @@ -19,6 +19,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; @@ -82,6 +94,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. |