Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-snmp.c
blobc9e2a3bbf02f54ca2ff7ad336d39dff7cd3fae5c
1 /* Do not modify this file. Changes will be overwritten. */
2 /* Generated automatically by the ASN.1 to Wireshark dissector compiler */
3 /* packet-snmp.c */
4 /* asn2wrs.py -b -q -L -p snmp -c ./snmp.cnf -s ./packet-snmp-template -D . -O ../.. snmp.asn */
6 /* packet-snmp.c
7 * Routines for SNMP (simple network management protocol)
8 * Copyright (C) 1998 Didier Jorand
10 * See RFC 1157 for SNMPv1.
12 * See RFCs 1901, 1905, and 1906 for SNMPv2c.
14 * See RFCs 1905, 1906, 1909, and 1910 for SNMPv2u [historic].
16 * See RFCs 2570-2576 for SNMPv3
17 * Updated to use the asn2wrs compiler made by Tomas Kukosa
18 * Copyright (C) 2005 - 2006 Anders Broman [AT] ericsson.com
20 * See RFC 3414 for User-based Security Model for SNMPv3
21 * See RFC 3826 for (AES) Cipher Algorithm in the SNMP USM
22 * See RFC 2578 for Structure of Management Information Version 2 (SMIv2)
23 * Copyright (C) 2007 Luis E. Garcia Ontanon <luis@ontanon.org>
25 * Wireshark - Network traffic analyzer
26 * By Gerald Combs <gerald@wireshark.org>
27 * Copyright 1998 Gerald Combs
29 * Some stuff from:
31 * GXSNMP -- An snmp mangament application
32 * Copyright (C) 1998 Gregory McLean & Jochen Friedrich
33 * Beholder RMON ethernet network monitor,Copyright (C) 1993 DNPAP group
35 * SPDX-License-Identifier: GPL-2.0-or-later
38 #if 0
39 #include <stdio.h>
40 #define D(args) do {printf args; fflush(stdout); } while(0)
41 #endif
43 #include "config.h"
45 #include <epan/packet.h>
46 #include <epan/strutil.h>
47 #include <epan/conversation.h>
48 #include <epan/etypes.h>
49 #include <epan/prefs.h>
50 #include <epan/addr_resolv.h>
51 #include <epan/next_tvb.h>
52 #include <epan/uat.h>
53 #include <epan/asn1.h>
54 #include <epan/expert.h>
55 #include <epan/oids.h>
56 #include <epan/srt_table.h>
57 #include <epan/tap.h>
58 #include <epan/tfs.h>
59 #include <wsutil/array.h>
60 #include "packet-ipx.h"
61 #include "packet-hpext.h"
62 #include "packet-ber.h"
63 #include "packet-snmp.h"
64 #include <wsutil/wsgcrypt.h>
66 #define PNAME "Simple Network Management Protocol"
67 #define PSNAME "SNMP"
68 #define PFNAME "snmp"
70 #define UDP_PORT_SNMP 161
71 #define UDP_PORT_SNMP_TRAP 162
72 #define TCP_PORT_SNMP 161
73 #define TCP_PORT_SNMP_TRAP 162
74 #define TCP_PORT_SMUX 199
75 #define UDP_PORT_SNMP_PATROL 8161
76 #define SNMP_NUM_PROCEDURES 8
78 /* Initialize the protocol and registered fields */
79 static int snmp_tap;
80 static int proto_snmp;
81 static int proto_smux;
83 static bool display_oid = true;
84 static bool snmp_var_in_tree = true;
86 void proto_register_snmp(void);
87 void proto_reg_handoff_snmp(void);
88 void proto_register_smux(void);
89 void proto_reg_handoff_smux(void);
91 static void snmp_usm_password_to_key(const snmp_usm_auth_model_t model, const uint8_t *password, unsigned passwordlen,
92 const uint8_t *engineID, unsigned engineLength, uint8_t *key);
94 static tvbuff_t* snmp_usm_priv_des(snmp_usm_params_t*, tvbuff_t*, packet_info *pinfo, char const**);
95 static tvbuff_t* snmp_usm_priv_aes128(snmp_usm_params_t*, tvbuff_t*, packet_info *pinfo, char const**);
96 static tvbuff_t* snmp_usm_priv_aes192(snmp_usm_params_t*, tvbuff_t*, packet_info *pinfo, char const**);
97 static tvbuff_t* snmp_usm_priv_aes256(snmp_usm_params_t*, tvbuff_t*, packet_info *pinfo, char const**);
99 static bool snmp_usm_auth(const packet_info *pinfo, const snmp_usm_auth_model_t model, snmp_usm_params_t* p, uint8_t**, unsigned*, char const**);
101 static const value_string auth_types[] = {
102 {SNMP_USM_AUTH_MD5,"MD5"},
103 {SNMP_USM_AUTH_SHA1,"SHA1"},
104 {SNMP_USM_AUTH_SHA2_224,"SHA2-224"},
105 {SNMP_USM_AUTH_SHA2_256,"SHA2-256"},
106 {SNMP_USM_AUTH_SHA2_384,"SHA2-384"},
107 {SNMP_USM_AUTH_SHA2_512,"SHA2-512"},
108 {0,NULL}
111 static const unsigned auth_hash_len[] = {
112 HASH_MD5_LENGTH,
113 HASH_SHA1_LENGTH,
114 HASH_SHA2_224_LENGTH,
115 HASH_SHA2_256_LENGTH,
116 HASH_SHA2_384_LENGTH,
117 HASH_SHA2_512_LENGTH
120 static const unsigned auth_tag_len[] = {
129 static const enum gcry_md_algos auth_hash_algo[] = {
130 GCRY_MD_MD5,
131 GCRY_MD_SHA1,
132 GCRY_MD_SHA224,
133 GCRY_MD_SHA256,
134 GCRY_MD_SHA384,
135 GCRY_MD_SHA512
138 #define PRIV_DES 0
139 #define PRIV_AES128 1
140 #define PRIV_AES192 2
141 #define PRIV_AES256 3
143 static const value_string priv_types[] = {
144 { PRIV_DES, "DES" },
145 { PRIV_AES128, "AES" },
146 { PRIV_AES192, "AES192" },
147 { PRIV_AES256, "AES256" },
148 { 0, NULL}
150 static snmp_usm_decoder_t priv_protos[] = {
151 snmp_usm_priv_des,
152 snmp_usm_priv_aes128,
153 snmp_usm_priv_aes192,
154 snmp_usm_priv_aes256
157 #define PRIVKEYEXP_USM_3DESDESEDE_00 0
158 #define PRIVKEYEXP_AGENTPP 1
160 static const value_string priv_key_exp_types[] = {
161 { PRIVKEYEXP_USM_3DESDESEDE_00, "draft-reeder-snmpv3-usm-3desede-00" },
162 { PRIVKEYEXP_AGENTPP, "AGENT++" },
163 { 0, NULL }
166 static snmp_ue_assoc_t* ueas;
167 static unsigned num_ueas;
168 static snmp_ue_assoc_t* localized_ues;
169 static snmp_ue_assoc_t* unlocalized_ues;
170 /****/
172 /* Variables used for handling enterprise specific trap types */
173 typedef struct _snmp_st_assoc_t {
174 char *enterprise;
175 unsigned trap;
176 char *desc;
177 } snmp_st_assoc_t;
178 static unsigned num_specific_traps;
179 static snmp_st_assoc_t *specific_traps;
180 static const char *enterprise_oid;
181 static unsigned generic_trap;
182 static uint32_t snmp_version;
183 static uint32_t RequestID = -1;
185 static snmp_usm_params_t usm_p;
187 #define TH_AUTH 0x01
188 #define TH_CRYPT 0x02
189 #define TH_REPORT 0x04
191 /* desegmentation of SNMP-over-TCP */
192 static bool snmp_desegment = true;
194 /* Global variables */
196 uint32_t MsgSecurityModel;
197 tvbuff_t *oid_tvb=NULL;
198 tvbuff_t *value_tvb=NULL;
200 static dissector_handle_t snmp_handle;
201 static dissector_handle_t snmp_tcp_handle;
202 static dissector_handle_t data_handle;
203 static dissector_handle_t smux_handle;
205 static next_tvb_list_t *var_list;
207 static int hf_snmp_response_in;
208 static int hf_snmp_response_to;
209 static int hf_snmp_time;
211 static int hf_snmp_v3_flags_auth;
212 static int hf_snmp_v3_flags_crypt;
213 static int hf_snmp_v3_flags_report;
215 static int hf_snmp_engineid_conform;
216 static int hf_snmp_engineid_enterprise;
217 static int hf_snmp_engineid_format;
218 static int hf_snmp_engineid_ipv4;
219 static int hf_snmp_engineid_ipv6;
220 static int hf_snmp_engineid_cisco_type;
221 static int hf_snmp_engineid_mac;
222 static int hf_snmp_engineid_text;
223 static int hf_snmp_engineid_time;
224 static int hf_snmp_engineid_data;
225 static int hf_snmp_decryptedPDU;
226 static int hf_snmp_msgAuthentication;
228 static int hf_snmp_noSuchObject;
229 static int hf_snmp_noSuchInstance;
230 static int hf_snmp_endOfMibView;
231 static int hf_snmp_unSpecified;
233 static int hf_snmp_integer32_value;
234 static int hf_snmp_octetstring_value;
235 static int hf_snmp_oid_value;
236 static int hf_snmp_null_value;
237 static int hf_snmp_ipv4_value;
238 static int hf_snmp_ipv6_value;
239 static int hf_snmp_anyaddress_value;
240 static int hf_snmp_unsigned32_value;
241 static int hf_snmp_unknown_value;
242 static int hf_snmp_opaque_value;
243 static int hf_snmp_nsap_value;
244 static int hf_snmp_counter_value;
245 static int hf_snmp_timeticks_value;
246 static int hf_snmp_big_counter_value;
247 static int hf_snmp_gauge32_value;
249 static int hf_snmp_objectname;
250 static int hf_snmp_scalar_instance_index;
252 static int hf_snmp_var_bind_str;
253 static int hf_snmp_agentid_trailer;
255 static int hf_snmp_SMUX_PDUs_PDU; /* SMUX_PDUs */
256 static int hf_snmp_version; /* Version */
257 static int hf_snmp_community; /* Community */
258 static int hf_snmp_data; /* PDUs */
259 static int hf_snmp_parameters; /* OCTET_STRING */
260 static int hf_snmp_datav2u; /* T_datav2u */
261 static int hf_snmp_v2u_plaintext; /* PDUs */
262 static int hf_snmp_encrypted; /* OCTET_STRING */
263 static int hf_snmp_msgAuthoritativeEngineID; /* T_msgAuthoritativeEngineID */
264 static int hf_snmp_msgAuthoritativeEngineBoots; /* T_msgAuthoritativeEngineBoots */
265 static int hf_snmp_msgAuthoritativeEngineTime; /* T_msgAuthoritativeEngineTime */
266 static int hf_snmp_msgUserName; /* T_msgUserName */
267 static int hf_snmp_msgAuthenticationParameters; /* T_msgAuthenticationParameters */
268 static int hf_snmp_msgPrivacyParameters; /* T_msgPrivacyParameters */
269 static int hf_snmp_msgVersion; /* Version */
270 static int hf_snmp_msgGlobalData; /* HeaderData */
271 static int hf_snmp_msgSecurityParameters; /* T_msgSecurityParameters */
272 static int hf_snmp_msgData; /* ScopedPduData */
273 static int hf_snmp_msgID; /* INTEGER_0_2147483647 */
274 static int hf_snmp_msgMaxSize; /* INTEGER_484_2147483647 */
275 static int hf_snmp_msgFlags; /* T_msgFlags */
276 static int hf_snmp_msgSecurityModel; /* T_msgSecurityModel */
277 static int hf_snmp_plaintext; /* ScopedPDU */
278 static int hf_snmp_encryptedPDU; /* T_encryptedPDU */
279 static int hf_snmp_contextEngineID; /* SnmpEngineID */
280 static int hf_snmp_contextName; /* OCTET_STRING */
281 static int hf_snmp_get_request; /* GetRequest_PDU */
282 static int hf_snmp_get_next_request; /* GetNextRequest_PDU */
283 static int hf_snmp_get_response; /* GetResponse_PDU */
284 static int hf_snmp_set_request; /* SetRequest_PDU */
285 static int hf_snmp_trap; /* Trap_PDU */
286 static int hf_snmp_getBulkRequest; /* GetBulkRequest_PDU */
287 static int hf_snmp_informRequest; /* InformRequest_PDU */
288 static int hf_snmp_snmpV2_trap; /* SNMPv2_Trap_PDU */
289 static int hf_snmp_report; /* Report_PDU */
290 static int hf_snmp_request_id; /* T_request_id */
291 static int hf_snmp_error_status; /* T_error_status */
292 static int hf_snmp_error_index; /* INTEGER */
293 static int hf_snmp_variable_bindings; /* VarBindList */
294 static int hf_snmp_bulkPDU_request_id; /* Integer32 */
295 static int hf_snmp_non_repeaters; /* INTEGER_0_2147483647 */
296 static int hf_snmp_max_repetitions; /* INTEGER_0_2147483647 */
297 static int hf_snmp_enterprise; /* EnterpriseOID */
298 static int hf_snmp_agent_addr; /* NetworkAddress */
299 static int hf_snmp_generic_trap; /* GenericTrap */
300 static int hf_snmp_specific_trap; /* SpecificTrap */
301 static int hf_snmp_time_stamp; /* TimeTicks */
302 static int hf_snmp_name; /* ObjectName */
303 static int hf_snmp_valueType; /* ValueType */
304 static int hf_snmp_VarBindList_item; /* VarBind */
305 static int hf_snmp_open; /* OpenPDU */
306 static int hf_snmp_close; /* ClosePDU */
307 static int hf_snmp_registerRequest; /* RReqPDU */
308 static int hf_snmp_registerResponse; /* RegisterResponse */
309 static int hf_snmp_commitOrRollback; /* SOutPDU */
310 static int hf_snmp_rRspPDU; /* RRspPDU */
311 static int hf_snmp_pDUs; /* PDUs */
312 static int hf_snmp_smux_simple; /* SimpleOpen */
313 static int hf_snmp_smux_version; /* T_smux_version */
314 static int hf_snmp_identity; /* OBJECT_IDENTIFIER */
315 static int hf_snmp_description; /* DisplayString */
316 static int hf_snmp_password; /* OCTET_STRING */
317 static int hf_snmp_subtree; /* ObjectName */
318 static int hf_snmp_priority; /* INTEGER_M1_2147483647 */
319 static int hf_snmp_operation; /* T_operation */
321 /* Initialize the subtree pointers */
322 static int ett_smux;
323 static int ett_snmp;
324 static int ett_engineid;
325 static int ett_msgFlags;
326 static int ett_encryptedPDU;
327 static int ett_decrypted;
328 static int ett_authParameters;
329 static int ett_internet;
330 static int ett_varbind;
331 static int ett_name;
332 static int ett_value;
333 static int ett_decoding_error;
335 static int ett_snmp_Message;
336 static int ett_snmp_Messagev2u;
337 static int ett_snmp_T_datav2u;
338 static int ett_snmp_UsmSecurityParameters;
339 static int ett_snmp_SNMPv3Message;
340 static int ett_snmp_HeaderData;
341 static int ett_snmp_ScopedPduData;
342 static int ett_snmp_ScopedPDU;
343 static int ett_snmp_PDUs;
344 static int ett_snmp_PDU;
345 static int ett_snmp_BulkPDU;
346 static int ett_snmp_Trap_PDU_U;
347 static int ett_snmp_VarBind;
348 static int ett_snmp_VarBindList;
349 static int ett_snmp_SMUX_PDUs;
350 static int ett_snmp_RegisterResponse;
351 static int ett_snmp_OpenPDU;
352 static int ett_snmp_SimpleOpen_U;
353 static int ett_snmp_RReqPDU_U;
355 static expert_field ei_snmp_failed_decrypted_data_pdu;
356 static expert_field ei_snmp_decrypted_data_bad_formatted;
357 static expert_field ei_snmp_verify_authentication_error;
358 static expert_field ei_snmp_authentication_ok;
359 static expert_field ei_snmp_authentication_error;
360 static expert_field ei_snmp_varbind_not_uni_class_seq;
361 static expert_field ei_snmp_varbind_has_indicator;
362 static expert_field ei_snmp_objectname_not_oid;
363 static expert_field ei_snmp_objectname_has_indicator;
364 static expert_field ei_snmp_value_not_primitive_encoding;
365 static expert_field ei_snmp_invalid_oid;
366 static expert_field ei_snmp_varbind_wrong_tag;
367 static expert_field ei_snmp_varbind_response;
368 static expert_field ei_snmp_no_instance_subid;
369 static expert_field ei_snmp_wrong_num_of_subids;
370 static expert_field ei_snmp_index_suboid_too_short;
371 static expert_field ei_snmp_unimplemented_instance_index;
372 static expert_field ei_snmp_index_suboid_len0;
373 static expert_field ei_snmp_index_suboid_too_long;
374 static expert_field ei_snmp_index_string_too_long;
375 static expert_field ei_snmp_column_parent_not_row;
376 static expert_field ei_snmp_uint_too_large;
377 static expert_field ei_snmp_int_too_large;
378 static expert_field ei_snmp_integral_value0;
379 static expert_field ei_snmp_missing_mib;
380 static expert_field ei_snmp_varbind_wrong_length_value;
381 static expert_field ei_snmp_varbind_wrong_class_tag;
382 static expert_field ei_snmp_rfc1910_non_conformant;
383 static expert_field ei_snmp_rfc3411_non_conformant;
384 static expert_field ei_snmp_version_unknown;
385 static expert_field ei_snmp_trap_pdu_obsolete;
387 static const true_false_string auth_flags = {
388 "OK",
389 "Failed"
392 /* Security Models */
394 #define SNMP_SEC_ANY 0
395 #define SNMP_SEC_V1 1
396 #define SNMP_SEC_V2C 2
397 #define SNMP_SEC_USM 3
399 static const value_string sec_models[] = {
400 { SNMP_SEC_ANY, "Any" },
401 { SNMP_SEC_V1, "V1" },
402 { SNMP_SEC_V2C, "V2C" },
403 { SNMP_SEC_USM, "USM" },
404 { 0, NULL }
407 #if 0
408 /* SMUX PDU types */
409 #define SMUX_MSG_OPEN 0
410 #define SMUX_MSG_CLOSE 1
411 #define SMUX_MSG_RREQ 2
412 #define SMUX_MSG_RRSP 3
413 #define SMUX_MSG_SOUT 4
415 static const value_string smux_types[] = {
416 { SMUX_MSG_OPEN, "Open" },
417 { SMUX_MSG_CLOSE, "Close" },
418 { SMUX_MSG_RREQ, "Registration Request" },
419 { SMUX_MSG_RRSP, "Registration Response" },
420 { SMUX_MSG_SOUT, "Commit Or Rollback" },
421 { 0, NULL }
423 #endif
425 /* Procedure names (used in Service Response Time) */
426 static const value_string snmp_procedure_names[] = {
427 { 0, "Get" },
428 { 1, "GetNext" },
429 { 3, "Set" },
430 { 4, "Register" },
431 { 5, "Bulk" },
432 { 6, "Inform" },
433 { 0, NULL }
436 #define SNMP_IPA 0 /* IP Address */
437 #define SNMP_CNT 1 /* Counter (Counter32) */
438 #define SNMP_GGE 2 /* Gauge (Gauge32) */
439 #define SNMP_TIT 3 /* TimeTicks */
440 #define SNMP_OPQ 4 /* Opaque */
441 #define SNMP_NSP 5 /* NsapAddress */
442 #define SNMP_C64 6 /* Counter64 */
443 #define SNMP_U32 7 /* Uinteger32 */
445 #define SERR_NSO 0
446 #define SERR_NSI 1
447 #define SERR_EOM 2
450 dissector_table_t value_sub_dissectors_table;
453 * Data structure attached to a conversation, request/response information
455 typedef struct snmp_conv_info_t {
456 wmem_map_t *request_response;
457 } snmp_conv_info_t;
459 static snmp_conv_info_t*
460 snmp_find_conversation_and_get_conv_data(packet_info *pinfo);
462 static snmp_request_response_t *
463 snmp_get_request_response_pointer(wmem_map_t *map, uint32_t requestId)
465 snmp_request_response_t *srrp=(snmp_request_response_t *)wmem_map_lookup(map, &requestId);
466 if (!srrp) {
467 srrp=wmem_new0(wmem_file_scope(), snmp_request_response_t);
468 srrp->requestId=requestId;
469 wmem_map_insert(map, &(srrp->requestId), (void *)srrp);
472 return srrp;
475 static snmp_request_response_t*
476 snmp_match_request_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, unsigned requestId, unsigned procedure_id, snmp_conv_info_t *snmp_info)
478 snmp_request_response_t *srrp=NULL;
480 DISSECTOR_ASSERT_HINT(snmp_info, "No SNMP info from ASN1 context");
482 /* get or create request/response pointer based on request id */
483 srrp=(snmp_request_response_t *)snmp_get_request_response_pointer(snmp_info->request_response, requestId);
485 // if not visited fill the request/response data
486 if (!PINFO_FD_VISITED(pinfo)) {
487 switch(procedure_id)
489 case SNMP_REQ_GET:
490 case SNMP_REQ_GETNEXT:
491 case SNMP_REQ_SET:
492 case SNMP_REQ_GETBULK:
493 case SNMP_REQ_INFORM:
494 srrp->request_frame_id=pinfo->fd->num;
495 srrp->response_frame_id=0;
496 srrp->request_time=pinfo->abs_ts;
497 srrp->request_procedure_id=procedure_id;
498 break;
499 case SNMP_RES_GET:
500 srrp->response_frame_id=pinfo->fd->num;
501 break;
502 default:
503 return NULL;
507 /* if request and response was matched */
508 if (srrp->request_frame_id!=0 && srrp->response_frame_id!=0)
510 proto_item *it;
512 // if it is the response
513 if (srrp->response_frame_id == pinfo->fd->num)
515 nstime_t ns;
516 it=proto_tree_add_uint(tree, hf_snmp_response_to, tvb, 0, 0, srrp->request_frame_id);
517 proto_item_set_generated(it);
518 nstime_delta(&ns, &pinfo->abs_ts, &srrp->request_time);
519 it=proto_tree_add_time(tree, hf_snmp_time, tvb, 0, 0, &ns);
520 proto_item_set_generated(it);
522 return srrp;
523 } else {
524 it=proto_tree_add_uint(tree, hf_snmp_response_in, tvb, 0, 0, srrp->response_frame_id);
525 proto_item_set_generated(it);
529 return NULL;
532 static void
533 snmpstat_init(struct register_srt* srt _U_, GArray* srt_array)
535 srt_stat_table *snmp_srt_table;
536 uint32_t i;
538 snmp_srt_table = init_srt_table("SNMP Commands", NULL, srt_array, SNMP_NUM_PROCEDURES, NULL, "snmp.data", NULL);
539 for (i = 0; i < SNMP_NUM_PROCEDURES; i++)
541 init_srt_table_row(snmp_srt_table, i, val_to_str_const(i, snmp_procedure_names, "<unknown>"));
545 /* This is called only if request and response was matched -> no need to return anything than TAP_PACKET_REDRAW */
546 static tap_packet_status
547 snmpstat_packet(void *psnmp, packet_info *pinfo, epan_dissect_t *edt _U_, const void *psi, tap_flags_t flags _U_)
549 unsigned i = 0;
550 srt_stat_table *snmp_srt_table;
551 const snmp_request_response_t *snmp=(const snmp_request_response_t *)psi;
552 srt_data_t *data = (srt_data_t *)psnmp;
554 snmp_srt_table = g_array_index(data->srt_array, srt_stat_table*, i);
556 add_srt_table_data(snmp_srt_table, snmp->request_procedure_id, &snmp->request_time, pinfo);
557 return TAP_PACKET_REDRAW;
560 static const char *
561 snmp_lookup_specific_trap (unsigned specific_trap)
563 unsigned i;
565 for (i = 0; i < num_specific_traps; i++) {
566 snmp_st_assoc_t *u = &(specific_traps[i]);
568 if ((u->trap == specific_trap) &&
569 (strcmp (u->enterprise, enterprise_oid) == 0))
571 return u->desc;
575 return NULL;
578 static int
579 dissect_snmp_variable_string(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void *data _U_)
582 proto_tree_add_item(tree, hf_snmp_var_bind_str, tvb, 0, -1, ENC_ASCII);
584 return tvb_captured_length(tvb);
588 DateAndTime ::= TEXTUAL-CONVENTION
589 DISPLAY-HINT "2d-1d-1d,1d:1d:1d.1d,1a1d:1d"
590 STATUS current
591 DESCRIPTION
592 "A date-time specification.
594 field octets contents range
595 ----- ------ -------- -----
596 1 1-2 year* 0..65536
597 2 3 month 1..12
598 3 4 day 1..31
599 4 5 hour 0..23
600 5 6 minutes 0..59
601 6 7 seconds 0..60
602 (use 60 for leap-second)
603 7 8 deci-seconds 0..9
604 8 9 direction from UTC '+' / '-'
605 9 10 hours from UTC* 0..13
606 10 11 minutes from UTC 0..59
608 * Notes:
609 - the value of year is in network-byte order
610 - daylight saving time in New Zealand is +13
612 For example, Tuesday May 26, 1992 at 1:30:15 PM EDT would be
613 displayed as:
615 1992-5-26,13:30:15.0,-4:0
617 Note that if only local time is known, then timezone
618 information (fields 8-10) is not present."
619 SYNTAX OCTET STRING (SIZE (8 | 11))
621 static proto_item *
622 dissect_snmp_variable_date_and_time(proto_tree *tree, packet_info *pinfo, int hfid, tvbuff_t *tvb, int offset, int length)
624 uint16_t year;
625 uint8_t month;
626 uint8_t day;
627 uint8_t hour;
628 uint8_t minutes;
629 uint8_t seconds;
630 uint8_t deci_seconds;
631 uint8_t hour_from_utc;
632 uint8_t min_from_utc;
633 char *str;
635 year = tvb_get_ntohs(tvb,offset);
636 month = tvb_get_uint8(tvb,offset+2);
637 day = tvb_get_uint8(tvb,offset+3);
638 hour = tvb_get_uint8(tvb,offset+4);
639 minutes = tvb_get_uint8(tvb,offset+5);
640 seconds = tvb_get_uint8(tvb,offset+6);
641 deci_seconds = tvb_get_uint8(tvb,offset+7);
642 if(length > 8){
643 hour_from_utc = tvb_get_uint8(tvb,offset+9);
644 min_from_utc = tvb_get_uint8(tvb,offset+10);
646 str = wmem_strdup_printf(pinfo->pool,
647 "%u-%u-%u, %u:%u:%u.%u UTC %s%u:%u",
648 year,
649 month,
650 day,
651 hour,
652 minutes,
653 seconds,
654 deci_seconds,
655 tvb_get_string_enc(pinfo->pool,tvb,offset+8,1,ENC_ASCII|ENC_NA),
656 hour_from_utc,
657 min_from_utc);
658 }else{
659 str = wmem_strdup_printf(pinfo->pool,
660 "%u-%u-%u, %u:%u:%u.%u",
661 year,
662 month,
663 day,
664 hour,
665 minutes,
666 seconds,
667 deci_seconds);
670 return proto_tree_add_string(tree, hfid, tvb, offset, length, str);
675 * dissect_snmp_VarBind
676 * this routine dissects variable bindings, looking for the oid information in our oid reporsitory
677 * to format and add the value adequatelly.
679 * The choice to handwrite this code instead of using the asn compiler is to avoid having tons
680 * of uses of global variables distributed in very different parts of the code.
681 * Other than that there's a cosmetic thing: the tree from ASN generated code would be so
682 * convoluted due to the nesting of CHOICEs in the definition of VarBind/value.
684 * XXX: the length of this function (~400 lines) is an aberration!
685 * oid_key_t:key_type could become a series of callbacks instead of an enum
686 * the (! oid_info_is_ok) switch could be made into an array (would be slower)
689 NetworkAddress ::= CHOICE { internet IpAddress }
690 IpAddress ::= [APPLICATION 0] IMPLICIT OCTET STRING (SIZE (4))
691 TimeTicks ::= [APPLICATION 3] IMPLICIT INTEGER (0..4294967295)
692 Integer32 ::= INTEGER (-2147483648..2147483647)
693 ObjectName ::= OBJECT IDENTIFIER
694 Counter32 ::= [APPLICATION 1] IMPLICIT INTEGER (0..4294967295)
695 Gauge32 ::= [APPLICATION 2] IMPLICIT INTEGER (0..4294967295)
696 Unsigned32 ::= [APPLICATION 2] IMPLICIT INTEGER (0..4294967295)
697 Integer-value ::= INTEGER (-2147483648..2147483647)
698 Integer32 ::= INTEGER (-2147483648..2147483647)
699 ObjectID-value ::= OBJECT IDENTIFIER
700 Empty ::= NULL
701 TimeTicks ::= [APPLICATION 3] IMPLICIT INTEGER (0..4294967295)
702 Opaque ::= [APPLICATION 4] IMPLICIT OCTET STRING
703 Counter64 ::= [APPLICATION 6] IMPLICIT INTEGER (0..18446744073709551615)
705 ObjectSyntax ::= CHOICE {
706 simple SimpleSyntax,
707 application-wide ApplicationSyntax
710 SimpleSyntax ::= CHOICE {
711 integer-value Integer-value,
712 string-value String-value,
713 objectID-value ObjectID-value,
714 empty Empty
717 ApplicationSyntax ::= CHOICE {
718 ipAddress-value IpAddress,
719 counter-value Counter32,
720 timeticks-value TimeTicks,
721 arbitrary-value Opaque,
722 big-counter-value Counter64,
723 unsigned-integer-value Unsigned32
726 ValueType ::= CHOICE {
727 value ObjectSyntax,
728 unSpecified NULL,
729 noSuchObject[0] IMPLICIT NULL,
730 noSuchInstance[1] IMPLICIT NULL,
731 endOfMibView[2] IMPLICIT NULL
734 VarBind ::= SEQUENCE {
735 name ObjectName,
736 valueType ValueType
741 static int
742 dissect_snmp_VarBind(bool implicit_tag _U_, tvbuff_t *tvb, int offset,
743 asn1_ctx_t *actx, proto_tree *tree, int hf_index _U_)
745 int seq_offset, name_offset, value_offset, value_start;
746 uint32_t seq_len, name_len, value_len;
747 int8_t ber_class;
748 bool pc;
749 int32_t tag;
750 bool ind;
751 uint32_t* subids;
752 uint8_t* oid_bytes;
753 oid_info_t* oid_info = NULL;
754 unsigned oid_matched, oid_left;
755 proto_item *pi_name, *pi_varbind, *pi_value = NULL;
756 proto_tree *pt, *pt_varbind, *pt_name, *pt_value;
757 char label[ITEM_LABEL_LENGTH];
758 const char* repr = NULL;
759 const char* info_oid = NULL;
760 char* valstr;
761 int hfid = -1;
762 int min_len = 0, max_len = 0;
763 bool oid_info_is_ok;
764 const char* oid_string = NULL;
765 enum {BER_NO_ERROR, BER_WRONG_LENGTH, BER_WRONG_TAG} format_error = BER_NO_ERROR;
767 seq_offset = offset;
769 /* first have the VarBind's sequence header */
770 offset = dissect_ber_identifier(actx->pinfo, tree, tvb, offset, &ber_class, &pc, &tag);
771 offset = dissect_ber_length(actx->pinfo, tree, tvb, offset, &seq_len, &ind);
773 if (!pc && ber_class==BER_CLASS_UNI && tag==BER_UNI_TAG_SEQUENCE) {
774 proto_item* pi;
775 pt = proto_tree_add_subtree(tree, tvb, seq_offset, seq_len + (offset - seq_offset),
776 ett_decoding_error, &pi, "VarBind must be an universal class sequence");
777 expert_add_info(actx->pinfo, pi, &ei_snmp_varbind_not_uni_class_seq);
778 return dissect_unknown_ber(actx->pinfo, tvb, seq_offset, pt);
781 if (ind) {
782 proto_item* pi;
783 pt = proto_tree_add_subtree(tree, tvb, seq_offset, seq_len + (offset - seq_offset),
784 ett_decoding_error, &pi, "Indicator must be clear in VarBind");
785 expert_add_info(actx->pinfo, pi, &ei_snmp_varbind_has_indicator);
786 return dissect_unknown_ber(actx->pinfo, tvb, seq_offset, pt);
789 /* we add the varbind tree root with a dummy label we'll fill later on */
790 pt_varbind = proto_tree_add_subtree(tree,tvb,offset,seq_len,ett_varbind,&pi_varbind,"VarBind");
791 *label = '\0';
793 seq_len += offset - seq_offset;
795 /* then we have the ObjectName's header */
797 offset = dissect_ber_identifier(actx->pinfo, pt_varbind, tvb, offset, &ber_class, &pc, &tag);
798 name_offset = offset = dissect_ber_length(actx->pinfo, pt_varbind, tvb, offset, &name_len, &ind);
800 if (! ( !pc && ber_class==BER_CLASS_UNI && tag==BER_UNI_TAG_OID) ) {
801 proto_item* pi;
802 pt = proto_tree_add_subtree(tree, tvb, seq_offset, seq_len,
803 ett_decoding_error, &pi, "ObjectName must be an OID in primitive encoding");
804 expert_add_info(actx->pinfo, pi, &ei_snmp_objectname_not_oid);
805 return dissect_unknown_ber(actx->pinfo, tvb, seq_offset, pt);
808 if (ind) {
809 proto_item* pi;
810 pt = proto_tree_add_subtree(tree, tvb, seq_offset, seq_len,
811 ett_decoding_error, &pi, "Indicator must be clear in ObjectName");
812 expert_add_info(actx->pinfo, pi, &ei_snmp_objectname_has_indicator);
813 return dissect_unknown_ber(actx->pinfo, tvb, seq_offset, pt);
816 pi_name = proto_tree_add_item(pt_varbind,hf_snmp_objectname,tvb,name_offset,name_len,ENC_NA);
817 pt_name = proto_item_add_subtree(pi_name,ett_name);
819 offset += name_len;
820 value_start = offset;
821 /* then we have the value's header */
822 offset = dissect_ber_identifier(actx->pinfo, pt_varbind, tvb, offset, &ber_class, &pc, &tag);
823 value_offset = dissect_ber_length(actx->pinfo, pt_varbind, tvb, offset, &value_len, &ind);
825 if (! (!pc) ) {
826 proto_item* pi;
827 pt = proto_tree_add_subtree(pt_varbind, tvb, value_start, value_len,
828 ett_decoding_error, &pi, "the value must be in primitive encoding");
829 expert_add_info(actx->pinfo, pi, &ei_snmp_value_not_primitive_encoding);
830 return dissect_unknown_ber(actx->pinfo, tvb, value_start, pt);
833 /* Now, we know where everything is */
835 /* fetch ObjectName and its relative oid_info */
836 oid_bytes = (uint8_t*)tvb_memdup(actx->pinfo->pool, tvb, name_offset, name_len);
837 oid_info = oid_get_from_encoded(actx->pinfo->pool, oid_bytes, name_len, &subids, &oid_matched, &oid_left);
839 add_oid_debug_subtree(oid_info,pt_name);
841 if (!subids) {
842 proto_item* pi;
844 repr = oid_encoded2string(actx->pinfo->pool, oid_bytes, name_len);
845 pt = proto_tree_add_subtree_format(pt_name,tvb, 0, 0, ett_decoding_error, &pi, "invalid oid: %s", repr);
846 expert_add_info_format(actx->pinfo, pi, &ei_snmp_invalid_oid, "invalid oid: %s", repr);
847 return dissect_unknown_ber(actx->pinfo, tvb, name_offset, pt);
850 if (oid_matched+oid_left) {
851 oid_string = oid_subid2string(actx->pinfo->pool, subids,oid_matched+oid_left);
854 if (ber_class == BER_CLASS_CON) {
855 /* if we have an error value just add it and get out the way ASAP */
856 proto_item* pi;
857 const char* note;
859 if (value_len != 0) {
860 min_len = max_len = 0;
861 format_error = BER_WRONG_LENGTH;
864 switch (tag) {
865 case SERR_NSO:
866 hfid = hf_snmp_noSuchObject;
867 note = "noSuchObject";
868 break;
869 case SERR_NSI:
870 hfid = hf_snmp_noSuchInstance;
871 note = "noSuchInstance";
872 break;
873 case SERR_EOM:
874 hfid = hf_snmp_endOfMibView;
875 note = "endOfMibView";
876 break;
877 default: {
878 pt = proto_tree_add_subtree_format(pt_varbind,tvb,0,0,ett_decoding_error,&pi,
879 "Wrong tag for Error Value: expected 0, 1, or 2 but got: %d",tag);
880 expert_add_info(actx->pinfo, pi, &ei_snmp_varbind_wrong_tag);
881 return dissect_unknown_ber(actx->pinfo, tvb, value_start, pt);
885 pi = proto_tree_add_item(pt_varbind,hfid,tvb,value_offset,value_len,ENC_BIG_ENDIAN);
886 expert_add_info_format(actx->pinfo, pi, &ei_snmp_varbind_response, "%s",note);
887 (void) g_strlcpy (label, note, ITEM_LABEL_LENGTH);
888 goto set_label;
891 /* now we'll try to figure out which are the indexing sub-oids and whether the oid we know about is the one oid we have to use */
892 switch (oid_info->kind) {
893 case OID_KIND_SCALAR:
894 if (oid_left == 1) {
895 /* OK: we got the instance sub-id */
896 proto_tree_add_uint64(pt_name,hf_snmp_scalar_instance_index,tvb,name_offset,name_len,subids[oid_matched]);
897 oid_info_is_ok = true;
898 goto indexing_done;
899 } else if (oid_left == 0) {
900 if (ber_class == BER_CLASS_UNI && tag == BER_UNI_TAG_NULL) {
901 /* unSpecified does not require an instance sub-id add the new value and get off the way! */
902 pi_value = proto_tree_add_item(pt_varbind,hf_snmp_unSpecified,tvb,value_offset,value_len,ENC_NA);
903 goto set_label;
904 } else {
905 proto_tree_add_expert(pt_name,actx->pinfo,&ei_snmp_no_instance_subid,tvb,0,0);
906 oid_info_is_ok = false;
907 goto indexing_done;
909 } else {
910 proto_tree_add_expert_format(pt_name,actx->pinfo,&ei_snmp_wrong_num_of_subids,tvb,0,0,"A scalar should have only one instance sub-id this has: %d",oid_left);
911 oid_info_is_ok = false;
912 goto indexing_done;
914 break;
915 case OID_KIND_COLUMN:
916 if ( oid_info->parent->kind == OID_KIND_ROW) {
917 oid_key_t* k = oid_info->parent->key;
918 unsigned key_start = oid_matched;
919 unsigned key_len = oid_left;
920 oid_info_is_ok = true;
922 if ( key_len == 0 && ber_class == BER_CLASS_UNI && tag == BER_UNI_TAG_NULL) {
923 /* unSpecified does not require an instance sub-id add the new value and get off the way! */
924 pi_value = proto_tree_add_item(pt_varbind,hf_snmp_unSpecified,tvb,value_offset,value_len,ENC_NA);
925 goto set_label;
928 if (k) {
929 for (;k;k = k->next) {
930 unsigned suboid_len;
932 if (key_start >= oid_matched+oid_left) {
933 proto_tree_add_expert(pt_name,actx->pinfo,&ei_snmp_index_suboid_too_short,tvb,0,0);
934 oid_info_is_ok = false;
935 goto indexing_done;
938 switch(k->key_type) {
939 case OID_KEY_TYPE_WRONG: {
940 proto_tree_add_expert(pt_name,actx->pinfo,&ei_snmp_unimplemented_instance_index,tvb,0,0);
941 oid_info_is_ok = false;
942 goto indexing_done;
944 case OID_KEY_TYPE_INTEGER: {
945 if (FT_IS_INT(k->ft_type)) {
946 proto_tree_add_int(pt_name,k->hfid,tvb,name_offset,name_len,(unsigned)subids[key_start]);
947 } else { /* if it's not an unsigned int let proto_tree_add_uint throw a warning */
948 proto_tree_add_uint64(pt_name,k->hfid,tvb,name_offset,name_len,(unsigned)subids[key_start]);
950 key_start++;
951 key_len--;
952 continue; /* k->next */
954 case OID_KEY_TYPE_IMPLIED_OID:
955 suboid_len = key_len;
957 goto show_oid_index;
959 case OID_KEY_TYPE_OID: {
960 uint8_t* suboid_buf;
961 unsigned suboid_buf_len;
962 uint32_t* suboid;
964 suboid_len = subids[key_start++];
965 key_len--;
967 show_oid_index:
968 suboid = &(subids[key_start]);
970 if( suboid_len == 0 ) {
971 proto_tree_add_expert(pt_name,actx->pinfo,&ei_snmp_index_suboid_len0,tvb,0,0);
972 oid_info_is_ok = false;
973 goto indexing_done;
976 if( key_len < suboid_len ) {
977 proto_tree_add_expert(pt_name,actx->pinfo,&ei_snmp_index_suboid_too_long,tvb,0,0);
978 oid_info_is_ok = false;
979 goto indexing_done;
982 suboid_buf_len = oid_subid2encoded(actx->pinfo->pool, suboid_len, suboid, &suboid_buf);
984 DISSECTOR_ASSERT(suboid_buf_len);
986 proto_tree_add_oid(pt_name,k->hfid,tvb,name_offset, suboid_buf_len, suboid_buf);
988 key_start += suboid_len;
989 key_len -= suboid_len + 1;
990 continue; /* k->next */
992 default: {
993 uint8_t* buf;
994 unsigned buf_len;
995 uint32_t* suboid;
996 unsigned i;
999 switch (k->key_type) {
1000 case OID_KEY_TYPE_IPADDR:
1001 suboid = &(subids[key_start]);
1002 buf_len = 4;
1003 break;
1004 case OID_KEY_TYPE_IMPLIED_STRING:
1005 case OID_KEY_TYPE_IMPLIED_BYTES:
1006 case OID_KEY_TYPE_ETHER:
1007 suboid = &(subids[key_start]);
1008 buf_len = key_len;
1009 break;
1010 default:
1011 buf_len = k->num_subids;
1012 suboid = &(subids[key_start]);
1014 if(!buf_len) {
1015 buf_len = *suboid++;
1016 key_len--;
1017 key_start++;
1019 break;
1022 if( key_len < buf_len ) {
1023 proto_tree_add_expert(pt_name,actx->pinfo,&ei_snmp_index_string_too_long,tvb,0,0);
1024 oid_info_is_ok = false;
1025 goto indexing_done;
1028 buf = (uint8_t*)wmem_alloc(actx->pinfo->pool, buf_len+1);
1029 for (i = 0; i < buf_len; i++)
1030 buf[i] = (uint8_t)suboid[i];
1031 buf[i] = '\0';
1033 switch(k->key_type) {
1034 case OID_KEY_TYPE_STRING:
1035 case OID_KEY_TYPE_IMPLIED_STRING:
1036 proto_tree_add_string(pt_name,k->hfid,tvb,name_offset,buf_len, buf);
1037 break;
1038 case OID_KEY_TYPE_BYTES:
1039 case OID_KEY_TYPE_NSAP:
1040 case OID_KEY_TYPE_IMPLIED_BYTES:
1041 proto_tree_add_bytes(pt_name,k->hfid,tvb,name_offset,buf_len, buf);
1042 break;
1043 case OID_KEY_TYPE_ETHER:
1044 proto_tree_add_ether(pt_name,k->hfid,tvb,name_offset,buf_len, buf);
1045 break;
1046 case OID_KEY_TYPE_IPADDR: {
1047 uint32_t* ipv4_p = (uint32_t*)buf;
1048 proto_tree_add_ipv4(pt_name,k->hfid,tvb,name_offset,buf_len, *ipv4_p);
1050 break;
1051 default:
1052 DISSECTOR_ASSERT_NOT_REACHED();
1053 break;
1056 key_start += buf_len;
1057 key_len -= buf_len;
1058 continue; /* k->next*/
1062 goto indexing_done;
1063 } else {
1064 proto_tree_add_expert(pt_name,actx->pinfo,&ei_snmp_unimplemented_instance_index,tvb,0,0);
1065 oid_info_is_ok = false;
1066 goto indexing_done;
1068 } else {
1069 proto_tree_add_expert(pt_name,actx->pinfo,&ei_snmp_column_parent_not_row,tvb,0,0);
1070 oid_info_is_ok = false;
1071 goto indexing_done;
1073 default: {
1074 /* proto_tree_add_expert (pt_name,actx->pinfo,PI_MALFORMED, PI_WARN,tvb,0,0,"This kind OID should have no value"); */
1075 oid_info_is_ok = false;
1076 goto indexing_done;
1079 indexing_done:
1081 if (oid_info_is_ok && oid_info->value_type) {
1082 if (ber_class == BER_CLASS_UNI && tag == BER_UNI_TAG_NULL) {
1083 pi_value = proto_tree_add_item(pt_varbind,hf_snmp_unSpecified,tvb,value_offset,value_len,ENC_NA);
1084 } else {
1085 /* Provide a tree_item to attach errors to, if needed. */
1086 pi_value = pi_name;
1088 if ((oid_info->value_type->ber_class != BER_CLASS_ANY) &&
1089 (ber_class != oid_info->value_type->ber_class))
1090 format_error = BER_WRONG_TAG;
1091 else if ((oid_info->value_type->ber_tag != BER_TAG_ANY) &&
1092 (tag != oid_info->value_type->ber_tag))
1093 format_error = BER_WRONG_TAG;
1094 else {
1095 max_len = oid_info->value_type->max_len == -1 ? 0xffffff : oid_info->value_type->max_len;
1096 min_len = oid_info->value_type->min_len;
1098 if ((int)value_len < min_len || (int)value_len > max_len)
1099 format_error = BER_WRONG_LENGTH;
1102 if (format_error == BER_NO_ERROR) {
1103 /* Special case DATE AND TIME */
1104 if((oid_info->value_type)&&(oid_info->value_type->keytype == OID_KEY_TYPE_DATE_AND_TIME)&&(value_len > 7)){
1105 pi_value = dissect_snmp_variable_date_and_time(pt_varbind, actx->pinfo, oid_info->value_hfid, tvb, value_offset, value_len);
1106 } else {
1107 pi_value = proto_tree_add_item(pt_varbind,oid_info->value_hfid,tvb,value_offset,value_len,ENC_BIG_ENDIAN);
1111 } else {
1112 switch(ber_class|(tag<<4)) {
1113 case BER_CLASS_UNI|(BER_UNI_TAG_INTEGER<<4):
1115 int64_t val=0;
1116 unsigned int int_val_offset = value_offset;
1117 unsigned int i;
1119 max_len = 4; min_len = 1;
1120 if (value_len > (unsigned)max_len || value_len < (unsigned)min_len) {
1121 hfid = hf_snmp_integer32_value;
1122 format_error = BER_WRONG_LENGTH;
1123 break;
1126 if(value_len > 0) {
1127 /* extend sign bit */
1128 if(tvb_get_uint8(tvb, int_val_offset)&0x80) {
1129 val=-1;
1131 for(i=0;i<value_len;i++) {
1132 val=(val<<8)|tvb_get_uint8(tvb, int_val_offset);
1133 int_val_offset++;
1136 pi_value = proto_tree_add_int64(pt_varbind, hf_snmp_integer32_value, tvb,value_offset,value_len, val);
1138 goto already_added;
1140 case BER_CLASS_UNI|(BER_UNI_TAG_OCTETSTRING<<4):
1141 if(oid_info->value_hfid> -1){
1142 hfid = oid_info->value_hfid;
1143 }else{
1144 hfid = hf_snmp_octetstring_value;
1146 break;
1147 case BER_CLASS_UNI|(BER_UNI_TAG_OID<<4):
1148 max_len = -1; min_len = 1;
1149 if (value_len < (unsigned)min_len) format_error = BER_WRONG_LENGTH;
1150 hfid = hf_snmp_oid_value;
1151 break;
1152 case BER_CLASS_UNI|(BER_UNI_TAG_NULL<<4):
1153 max_len = 0; min_len = 0;
1154 if (value_len != 0) format_error = BER_WRONG_LENGTH;
1155 hfid = hf_snmp_null_value;
1156 break;
1157 case BER_CLASS_APP: /* | (SNMP_IPA<<4)*/
1158 switch(value_len) {
1159 case 4: hfid = hf_snmp_ipv4_value; break;
1160 case 16: hfid = hf_snmp_ipv6_value; break;
1161 default: hfid = hf_snmp_anyaddress_value; break;
1163 break;
1164 case BER_CLASS_APP|(SNMP_U32<<4):
1165 hfid = hf_snmp_unsigned32_value;
1166 break;
1167 case BER_CLASS_APP|(SNMP_GGE<<4):
1168 hfid = hf_snmp_gauge32_value;
1169 break;
1170 case BER_CLASS_APP|(SNMP_CNT<<4):
1171 hfid = hf_snmp_counter_value;
1172 break;
1173 case BER_CLASS_APP|(SNMP_TIT<<4):
1174 hfid = hf_snmp_timeticks_value;
1175 break;
1176 case BER_CLASS_APP|(SNMP_OPQ<<4):
1177 hfid = hf_snmp_opaque_value;
1178 break;
1179 case BER_CLASS_APP|(SNMP_NSP<<4):
1180 hfid = hf_snmp_nsap_value;
1181 break;
1182 case BER_CLASS_APP|(SNMP_C64<<4):
1183 hfid = hf_snmp_big_counter_value;
1184 break;
1185 default:
1186 hfid = hf_snmp_unknown_value;
1187 break;
1189 if (value_len > 8) {
1191 * Too long for an FT_UINT64 or an FT_INT64.
1193 header_field_info *hfinfo = proto_registrar_get_nth(hfid);
1194 if (hfinfo->type == FT_UINT64) {
1196 * Check if this is an unsigned int64 with
1197 * a big value.
1199 if (value_len > 9 || tvb_get_uint8(tvb, value_offset) != 0) {
1200 /* It is. Fail. */
1201 proto_tree_add_expert_format(pt_varbind,actx->pinfo,&ei_snmp_uint_too_large,tvb,value_offset,value_len,"Integral value too large");
1202 goto already_added;
1204 /* Cheat and skip the leading 0 byte */
1205 value_len--;
1206 value_offset++;
1207 } else if (hfinfo->type == FT_INT64) {
1209 * For now, just reject these.
1211 proto_tree_add_expert_format(pt_varbind,actx->pinfo,&ei_snmp_int_too_large,tvb,value_offset,value_len,"Integral value too large or too small");
1212 goto already_added;
1214 } else if (value_len == 0) {
1216 * X.690 section 8.3.1 "Encoding of an integer value":
1217 * "The encoding of an integer value shall be
1218 * primitive. The contents octets shall consist of
1219 * one or more octets."
1221 * Zero is not "one or more".
1223 header_field_info *hfinfo = proto_registrar_get_nth(hfid);
1224 if (hfinfo->type == FT_UINT64 || hfinfo->type == FT_INT64) {
1225 proto_tree_add_expert_format(pt_varbind,actx->pinfo,&ei_snmp_integral_value0,tvb,value_offset,value_len,"Integral value is zero-length");
1226 goto already_added;
1229 /* Special case DATE AND TIME */
1230 if((oid_info->value_type)&&(oid_info->value_type->keytype == OID_KEY_TYPE_DATE_AND_TIME)&&(value_len > 7)){
1231 pi_value = dissect_snmp_variable_date_and_time(pt_varbind, actx->pinfo, hfid, tvb, value_offset, value_len);
1232 }else{
1233 pi_value = proto_tree_add_item(pt_varbind,hfid,tvb,value_offset,value_len,ENC_BIG_ENDIAN);
1235 if (format_error != BER_NO_ERROR) {
1236 expert_add_info(actx->pinfo, pi_value, &ei_snmp_missing_mib);
1240 already_added:
1241 pt_value = proto_item_add_subtree(pi_value,ett_value);
1243 if (value_len > 0 && oid_string) {
1244 tvbuff_t* sub_tvb = tvb_new_subset_length(tvb, value_offset, value_len);
1246 next_tvb_add_string(var_list, sub_tvb, (snmp_var_in_tree) ? pt_value : NULL, value_sub_dissectors_table, oid_string);
1250 set_label:
1251 if (pi_value) proto_item_fill_label(PITEM_FINFO(pi_value), label, NULL);
1253 if (oid_info && oid_info->name) {
1254 if (oid_left >= 1) {
1255 repr = wmem_strdup_printf(actx->pinfo->pool, "%s.%s (%s)", oid_info->name,
1256 oid_subid2string(actx->pinfo->pool, &(subids[oid_matched]),oid_left),
1257 oid_subid2string(actx->pinfo->pool, subids,oid_matched+oid_left));
1258 info_oid = wmem_strdup_printf(actx->pinfo->pool, "%s.%s", oid_info->name,
1259 oid_subid2string(actx->pinfo->pool, &(subids[oid_matched]),oid_left));
1260 } else {
1261 repr = wmem_strdup_printf(actx->pinfo->pool, "%s (%s)", oid_info->name,
1262 oid_subid2string(actx->pinfo->pool, subids,oid_matched));
1263 info_oid = oid_info->name;
1265 } else if (oid_string) {
1266 repr = wmem_strdup(actx->pinfo->pool, oid_string);
1267 info_oid = oid_string;
1268 } else {
1269 repr = wmem_strdup(actx->pinfo->pool, "[Bad OID]");
1272 valstr = strstr(label,": ");
1273 valstr = valstr ? valstr+2 : label;
1275 proto_item_set_text(pi_varbind,"%s: %s",repr,valstr);
1277 if (display_oid && info_oid) {
1278 col_append_fstr (actx->pinfo->cinfo, COL_INFO, " %s", info_oid);
1281 switch (format_error) {
1282 case BER_WRONG_LENGTH: {
1283 proto_item* pi;
1284 proto_tree* p_tree = proto_item_add_subtree(pi_value,ett_decoding_error);
1285 pt = proto_tree_add_subtree_format(p_tree,tvb,0,0,ett_decoding_error,&pi,
1286 "Wrong value length: %u expecting: %u <= len <= %u",
1287 value_len, min_len, max_len == -1 ? 0xFFFFFF : max_len);
1288 expert_add_info(actx->pinfo, pi, &ei_snmp_varbind_wrong_length_value);
1289 return dissect_unknown_ber(actx->pinfo, tvb, value_start, pt);
1291 case BER_WRONG_TAG: {
1292 proto_item* pi;
1293 proto_tree* p_tree = proto_item_add_subtree(pi_value,ett_decoding_error);
1294 pt = proto_tree_add_subtree_format(p_tree,tvb,0,0,ett_decoding_error,&pi,
1295 "Wrong class/tag for Value expected: %d,%d got: %d,%d",
1296 oid_info->value_type->ber_class, oid_info->value_type->ber_tag,
1297 ber_class, tag);
1298 expert_add_info(actx->pinfo, pi, &ei_snmp_varbind_wrong_class_tag);
1299 return dissect_unknown_ber(actx->pinfo, tvb, value_start, pt);
1301 default:
1302 break;
1305 return seq_offset + seq_len;
1309 #define F_SNMP_ENGINEID_CONFORM 0x80
1310 #define SNMP_ENGINEID_RFC1910 0x00
1311 #define SNMP_ENGINEID_RFC3411 0x01
1313 static const true_false_string tfs_snmp_engineid_conform = {
1314 "RFC3411 (SNMPv3)",
1315 "RFC1910 (Non-SNMPv3)"
1318 #define SNMP_ENGINEID_FORMAT_IPV4 0x01
1319 #define SNMP_ENGINEID_FORMAT_IPV6 0x02
1320 #define SNMP_ENGINEID_FORMAT_MACADDRESS 0x03
1321 #define SNMP_ENGINEID_FORMAT_TEXT 0x04
1322 #define SNMP_ENGINEID_FORMAT_OCTETS 0x05
1323 #define SNMP_ENGINEID_FORMAT_LOCAL 0x06
1325 static const value_string snmp_engineid_format_vals[] = {
1326 { SNMP_ENGINEID_FORMAT_IPV4, "IPv4 address" },
1327 { SNMP_ENGINEID_FORMAT_IPV6, "IPv6 address" },
1328 { SNMP_ENGINEID_FORMAT_MACADDRESS, "MAC address" },
1329 { SNMP_ENGINEID_FORMAT_TEXT, "Text, administratively assigned" },
1330 { SNMP_ENGINEID_FORMAT_OCTETS, "Octets, administratively assigned" },
1331 { SNMP_ENGINEID_FORMAT_LOCAL, "Local engine" },
1332 { 0, NULL }
1335 #define SNMP_ENGINEID_CISCO_AGENT 0x00
1336 #define SNMP_ENGINEID_CISCO_MANAGER 0x01
1338 static const value_string snmp_engineid_cisco_type_vals[] = {
1339 { SNMP_ENGINEID_CISCO_AGENT, "Agent" },
1340 { SNMP_ENGINEID_CISCO_MANAGER, "Manager" },
1341 { 0, NULL }
1345 * SNMP Engine ID dissection according to RFC 3411 (SnmpEngineID TC)
1346 * or historic RFC 1910 (AgentID)
1349 dissect_snmp_engineid(proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb, int offset, int len)
1351 proto_item *item = NULL;
1352 uint8_t conformance, format;
1353 uint32_t enterpriseid;
1354 time_t seconds;
1355 nstime_t ts;
1356 int len_remain = len;
1358 /* first bit: engine id conformance */
1359 if (len_remain<1) return offset;
1360 conformance = ((tvb_get_uint8(tvb, offset)>>7) & 0x01);
1361 proto_tree_add_item(tree, hf_snmp_engineid_conform, tvb, offset, 1, ENC_BIG_ENDIAN);
1363 /* 4-byte enterprise number/name */
1364 if (len_remain<4) return offset;
1365 enterpriseid = tvb_get_ntohl(tvb, offset);
1366 if (conformance)
1367 enterpriseid -= 0x80000000; /* ignore first bit */
1368 proto_tree_add_uint(tree, hf_snmp_engineid_enterprise, tvb, offset, 4, enterpriseid);
1369 offset+=4;
1370 len_remain-=4;
1372 switch(conformance) {
1374 case SNMP_ENGINEID_RFC1910:
1375 /* 12-byte AgentID w/ 8-byte trailer */
1376 if (len_remain==8) {
1377 proto_tree_add_item(tree, hf_snmp_agentid_trailer, tvb, offset, 8, ENC_NA);
1378 offset+=8;
1379 len_remain-=8;
1380 } else {
1381 proto_tree_add_expert(tree, pinfo, &ei_snmp_rfc1910_non_conformant, tvb, offset, len_remain);
1382 return offset;
1384 break;
1386 case SNMP_ENGINEID_RFC3411: /* variable length: 5..32 */
1388 /* 1-byte format specifier */
1389 if (len_remain<1) return offset;
1390 format = tvb_get_uint8(tvb, offset);
1391 item = proto_tree_add_uint_format(tree, hf_snmp_engineid_format, tvb, offset, 1, format, "Engine ID Format: %s (%d)",
1392 val_to_str_const(format, snmp_engineid_format_vals, "Reserved/Enterprise-specific"),
1393 format);
1394 offset+=1;
1395 len_remain-=1;
1397 switch(format) {
1398 case SNMP_ENGINEID_FORMAT_IPV4:
1399 /* 4-byte IPv4 address */
1400 if (len_remain==4) {
1401 proto_tree_add_item(tree, hf_snmp_engineid_ipv4, tvb, offset, 4, ENC_BIG_ENDIAN);
1402 offset+=4;
1403 len_remain=0;
1405 break;
1406 case SNMP_ENGINEID_FORMAT_IPV6:
1407 /* 16-byte IPv6 address */
1408 if (len_remain==16) {
1409 proto_tree_add_item(tree, hf_snmp_engineid_ipv6, tvb, offset, 16, ENC_NA);
1410 offset+=16;
1411 len_remain=0;
1413 break;
1414 case SNMP_ENGINEID_FORMAT_MACADDRESS:
1415 /* See: https://supportforums.cisco.com/message/3010617#3010617 for details. */
1416 if ((enterpriseid==9)&&(len_remain==7)) {
1417 proto_tree_add_item(tree, hf_snmp_engineid_cisco_type, tvb, offset, 1, ENC_BIG_ENDIAN);
1418 offset++;
1419 len_remain--;
1421 /* 6-byte MAC address */
1422 if (len_remain==6) {
1423 proto_tree_add_item(tree, hf_snmp_engineid_mac, tvb, offset, 6, ENC_NA);
1424 offset+=6;
1425 len_remain=0;
1427 break;
1428 case SNMP_ENGINEID_FORMAT_TEXT:
1429 /* max. 27-byte string, administratively assigned */
1430 if (len_remain<=27) {
1431 proto_tree_add_item(tree, hf_snmp_engineid_text, tvb, offset, len_remain, ENC_ASCII);
1432 offset+=len_remain;
1433 len_remain=0;
1435 break;
1436 case SNMP_ENGINEID_FORMAT_LOCAL:
1437 break;
1438 case 128:
1439 /* most common enterprise-specific format: (ucd|net)-snmp random */
1440 if ((enterpriseid==2021)||(enterpriseid==8072)) {
1441 proto_item_append_text(item, (enterpriseid==2021) ? ": UCD-SNMP Random" : ": Net-SNMP Random");
1442 /* demystify: 4B random, 4B/8B epoch seconds */
1443 if ((len_remain==8) || (len_remain==12)) {
1444 proto_tree_add_item(tree, hf_snmp_engineid_data, tvb, offset, 4, ENC_NA);
1445 if (len_remain==8) {
1446 seconds = (time_t)tvb_get_letohl(tvb, offset + 4);
1447 } else {
1448 seconds = (time_t)tvb_get_letohi64(tvb, offset + 4);
1450 ts.secs = seconds;
1451 ts.nsecs = 0;
1452 proto_tree_add_time_format_value(tree, hf_snmp_engineid_time, tvb, offset + 4, len_remain - 4,
1453 &ts, "%s",
1454 abs_time_secs_to_str(pinfo->pool, seconds, ABSOLUTE_TIME_LOCAL, true));
1455 offset+=len_remain;
1456 len_remain=0;
1458 break;
1460 /* fall through */
1461 case SNMP_ENGINEID_FORMAT_OCTETS:
1462 default:
1463 /* max. 27 bytes, administratively assigned or unknown format */
1464 if (len_remain>0 && len_remain<=27) {
1465 proto_tree_add_item(tree, hf_snmp_engineid_data, tvb, offset, len_remain, ENC_NA);
1466 offset+=len_remain;
1467 len_remain=0;
1469 break;
1473 if (len_remain>0) {
1474 proto_tree_add_expert(tree, pinfo, &ei_snmp_rfc3411_non_conformant, tvb, offset, len_remain);
1475 offset+=len_remain;
1477 return offset;
1481 static void set_ue_keys(snmp_ue_assoc_t* n ) {
1482 unsigned const key_size = auth_hash_len[n->user.authModel];
1484 n->user.authKey.data = (uint8_t *)g_malloc(key_size);
1485 n->user.authKey.len = key_size;
1486 snmp_usm_password_to_key(n->user.authModel,
1487 n->user.authPassword.data,
1488 n->user.authPassword.len,
1489 n->engine.data,
1490 n->engine.len,
1491 n->user.authKey.data);
1493 if (n->priv_proto == PRIV_AES128 || n->priv_proto == PRIV_AES192 || n->priv_proto == PRIV_AES256) {
1494 unsigned need_key_len =
1495 (n->priv_proto == PRIV_AES128) ? 16 :
1496 (n->priv_proto == PRIV_AES192) ? 24 :
1497 (n->priv_proto == PRIV_AES256) ? 32 :
1500 unsigned key_len = key_size;
1502 while (key_len < need_key_len)
1503 key_len += key_size;
1505 n->user.privKey.data = (uint8_t *)g_malloc(key_len);
1506 n->user.privKey.len = need_key_len;
1508 snmp_usm_password_to_key(n->user.authModel,
1509 n->user.privPassword.data,
1510 n->user.privPassword.len,
1511 n->engine.data,
1512 n->engine.len,
1513 n->user.privKey.data);
1515 key_len = key_size;
1517 /* extend key if needed */
1518 while (key_len < need_key_len) {
1519 switch (n->priv_key_exp) {
1520 /* Baed on draft-reeder-snmpv3-usm-3desede-00, section 2.1 */
1521 case PRIVKEYEXP_USM_3DESDESEDE_00:
1523 snmp_usm_password_to_key(n->user.authModel,
1524 n->user.privKey.data + (key_len - key_size),
1525 key_size,
1526 n->engine.data,
1527 n->engine.len,
1528 n->user.privKey.data + key_len);
1529 break;
1531 /* Based on snmp++ method PrivAES::extend_short_key in Agent++ */
1532 case PRIVKEYEXP_AGENTPP:
1534 /* Key expansion in Agent++
1535 * K1 = key
1536 * K2 = hash(K1)
1537 * K3 = hash(K1 | K2)
1538 * localized_key = K1 | K2 | K3
1540 gcry_md_hd_t hash_handle;
1542 if (gcry_md_open(&hash_handle, auth_hash_algo[n->user.authModel], 0)) {
1543 return;
1546 gcry_md_write(hash_handle, n->user.privKey.data, key_len);
1547 memcpy(n->user.privKey.data + key_len, gcry_md_read(hash_handle, 0), key_size);
1548 gcry_md_close(hash_handle);
1550 break;
1553 default:
1554 break;
1557 key_len += key_size;
1560 } else {
1561 n->user.privKey.data = (uint8_t *)g_malloc(key_size);
1562 n->user.privKey.len = key_size;
1563 snmp_usm_password_to_key(n->user.authModel,
1564 n->user.privPassword.data,
1565 n->user.privPassword.len,
1566 n->engine.data,
1567 n->engine.len,
1568 n->user.privKey.data);
1572 static snmp_ue_assoc_t*
1573 ue_dup(snmp_ue_assoc_t* o)
1575 snmp_ue_assoc_t* d = (snmp_ue_assoc_t*)g_memdup2(o,sizeof(snmp_ue_assoc_t));
1577 d->user.authModel = o->user.authModel;
1579 d->user.privProtocol = o->user.privProtocol;
1581 d->user.userName.data = (uint8_t *)g_memdup2(o->user.userName.data,o->user.userName.len);
1582 d->user.userName.len = o->user.userName.len;
1584 d->user.authPassword.data = o->user.authPassword.data ? (uint8_t *)g_memdup2(o->user.authPassword.data,o->user.authPassword.len) : NULL;
1585 d->user.authPassword.len = o->user.authPassword.len;
1587 d->user.privPassword.data = o->user.privPassword.data ? (uint8_t *)g_memdup2(o->user.privPassword.data,o->user.privPassword.len) : NULL;
1588 d->user.privPassword.len = o->user.privPassword.len;
1590 d->engine.len = o->engine.len;
1592 if (d->engine.len) {
1593 d->engine.data = (uint8_t *)g_memdup2(o->engine.data,o->engine.len);
1594 set_ue_keys(d);
1597 return d;
1601 static void*
1602 snmp_users_copy_cb(void* dest, const void* orig, size_t len _U_)
1604 const snmp_ue_assoc_t* o = (const snmp_ue_assoc_t*)orig;
1605 snmp_ue_assoc_t* d = (snmp_ue_assoc_t*)dest;
1607 d->auth_model = o->auth_model;
1608 d->user.authModel = (snmp_usm_auth_model_t) o->auth_model;
1610 d->priv_proto = o->priv_proto;
1611 d->user.privProtocol = priv_protos[o->priv_proto];
1613 d->user.userName.data = (uint8_t*)g_memdup2(o->user.userName.data,o->user.userName.len);
1614 d->user.userName.len = o->user.userName.len;
1616 d->user.authPassword.data = o->user.authPassword.data ? (uint8_t*)g_memdup2(o->user.authPassword.data,o->user.authPassword.len) : NULL;
1617 d->user.authPassword.len = o->user.authPassword.len;
1619 d->user.privPassword.data = o->user.privPassword.data ? (uint8_t*)g_memdup2(o->user.privPassword.data,o->user.privPassword.len) : NULL;
1620 d->user.privPassword.len = o->user.privPassword.len;
1622 d->engine.len = o->engine.len;
1623 if (o->engine.data) {
1624 d->engine.data = (uint8_t*)g_memdup2(o->engine.data,o->engine.len);
1627 d->user.authKey.data = o->user.authKey.data ? (uint8_t*)g_memdup2(o->user.authKey.data,o->user.authKey.len) : NULL;
1628 d->user.authKey.len = o->user.authKey.len;
1630 d->user.privKey.data = o->user.privKey.data ? (uint8_t*)g_memdup2(o->user.privKey.data,o->user.privKey.len) : NULL;
1631 d->user.privKey.len = o->user.privKey.len;
1633 return d;
1636 static void
1637 snmp_users_free_cb(void* p)
1639 snmp_ue_assoc_t* ue = (snmp_ue_assoc_t*)p;
1640 g_free(ue->user.userName.data);
1641 g_free(ue->user.authPassword.data);
1642 g_free(ue->user.privPassword.data);
1643 g_free(ue->user.authKey.data);
1644 g_free(ue->user.privKey.data);
1645 g_free(ue->engine.data);
1648 static bool
1649 snmp_users_update_cb(void* p _U_, char** err)
1651 snmp_ue_assoc_t* ue = (snmp_ue_assoc_t*)p;
1652 GString* es = g_string_new("");
1653 unsigned int i;
1655 *err = NULL;
1657 if (! ue->user.userName.len) {
1658 g_string_append_printf(es,"no userName\n");
1659 } else if ((ue->engine.len > 0) && (ue->engine.len < 5 || ue->engine.len > 32)) {
1660 /* RFC 3411 section 5 */
1661 g_string_append_printf(es, "Invalid engineId length (%u). Must be between 5 and 32 (10 and 64 hex digits)\n", ue->engine.len);
1662 } else if (num_ueas) {
1663 for (i=0; i<num_ueas-1; i++) {
1664 snmp_ue_assoc_t* u = &(ueas[i]);
1666 if ( u->user.userName.len == ue->user.userName.len
1667 && u->engine.len == ue->engine.len && (u != ue)) {
1669 if (u->engine.len > 0 && memcmp( u->engine.data, ue->engine.data, u->engine.len ) == 0) {
1670 if ( memcmp( u->user.userName.data, ue->user.userName.data, ue->user.userName.len ) == 0 ) {
1671 /* XXX: make a string for the engineId */
1672 g_string_append_printf(es,"Duplicate key (userName='%s')\n",ue->user.userName.data);
1673 break;
1677 if (u->engine.len == 0) {
1678 if ( memcmp( u->user.userName.data, ue->user.userName.data, ue->user.userName.len ) == 0 ) {
1679 g_string_append_printf(es,"Duplicate key (userName='%s' engineId=NONE)\n",ue->user.userName.data);
1680 break;
1687 if (es->len) {
1688 es = g_string_truncate(es,es->len-1);
1689 *err = g_string_free(es, FALSE);
1690 return false;
1693 g_string_free(es, TRUE);
1694 return true;
1697 static void
1698 free_ue_cache(snmp_ue_assoc_t **cache)
1700 static snmp_ue_assoc_t *a, *nxt;
1702 for (a = *cache; a; a = nxt) {
1703 nxt = a->next;
1704 snmp_users_free_cb(a);
1705 g_free(a);
1708 *cache = NULL;
1711 #define CACHE_INSERT(c,a) if (c) { snmp_ue_assoc_t* t = c; c = a; c->next = t; } else { c = a; a->next = NULL; }
1713 static void
1714 init_ue_cache(void)
1716 unsigned i;
1718 for (i = 0; i < num_ueas; i++) {
1719 snmp_ue_assoc_t* a = ue_dup(&(ueas[i]));
1721 if (a->engine.len) {
1722 CACHE_INSERT(localized_ues,a);
1724 } else {
1725 CACHE_INSERT(unlocalized_ues,a);
1731 static void
1732 cleanup_ue_cache(void)
1734 free_ue_cache(&localized_ues);
1735 free_ue_cache(&unlocalized_ues);
1738 /* Called when the user applies changes to UAT preferences. */
1739 static void
1740 renew_ue_cache(void)
1742 cleanup_ue_cache();
1743 init_ue_cache();
1747 static snmp_ue_assoc_t*
1748 localize_ue( snmp_ue_assoc_t* o, const uint8_t* engine, unsigned engine_len )
1750 snmp_ue_assoc_t* n = (snmp_ue_assoc_t*)g_memdup2(o,sizeof(snmp_ue_assoc_t));
1752 n->user.userName.data = (uint8_t*)g_memdup2(o->user.userName.data,o->user.userName.len);
1753 n->user.authModel = o->user.authModel;
1754 n->user.authPassword.data = (uint8_t*)g_memdup2(o->user.authPassword.data,o->user.authPassword.len);
1755 n->user.authPassword.len = o->user.authPassword.len;
1756 n->user.privPassword.data = (uint8_t*)g_memdup2(o->user.privPassword.data,o->user.privPassword.len);
1757 n->user.privPassword.len = o->user.privPassword.len;
1758 n->user.authKey.data = (uint8_t*)g_memdup2(o->user.authKey.data,o->user.authKey.len);
1759 n->user.privKey.data = (uint8_t*)g_memdup2(o->user.privKey.data,o->user.privKey.len);
1760 n->engine.data = (uint8_t*)g_memdup2(engine,engine_len);
1761 n->engine.len = engine_len;
1762 n->priv_proto = o->priv_proto;
1764 set_ue_keys(n);
1766 return n;
1770 #define localized_match(a,u,ul,e,el) \
1771 ( a->user.userName.len == ul \
1772 && a->engine.len == el \
1773 && memcmp( a->user.userName.data, u, ul ) == 0 \
1774 && memcmp( a->engine.data, e, el ) == 0 )
1776 #define unlocalized_match(a,u,l) \
1777 ( a->user.userName.len == l && memcmp( a->user.userName.data, u, l) == 0 )
1779 static snmp_ue_assoc_t*
1780 get_user_assoc(tvbuff_t* engine_tvb, tvbuff_t* user_tvb, packet_info *pinfo)
1782 static snmp_ue_assoc_t* a;
1783 unsigned given_username_len;
1784 uint8_t* given_username;
1785 unsigned given_engine_len = 0;
1786 uint8_t* given_engine = NULL;
1788 if ( ! (localized_ues || unlocalized_ues ) ) return NULL;
1790 if (! ( user_tvb && engine_tvb ) ) return NULL;
1792 given_username_len = tvb_captured_length(user_tvb);
1793 given_engine_len = tvb_captured_length(engine_tvb);
1794 if (! ( given_engine_len && given_username_len ) ) return NULL;
1795 given_username = (uint8_t*)tvb_memdup(pinfo->pool,user_tvb,0,-1);
1796 given_engine = (uint8_t*)tvb_memdup(pinfo->pool,engine_tvb,0,-1);
1798 for (a = localized_ues; a; a = a->next) {
1799 if ( localized_match(a, given_username, given_username_len, given_engine, given_engine_len) ) {
1800 return a;
1804 for (a = unlocalized_ues; a; a = a->next) {
1805 if ( unlocalized_match(a, given_username, given_username_len) ) {
1806 snmp_ue_assoc_t* n = localize_ue( a, given_engine, given_engine_len );
1807 CACHE_INSERT(localized_ues,n);
1808 return n;
1812 return NULL;
1815 static bool
1816 snmp_usm_auth(const packet_info *pinfo, const snmp_usm_auth_model_t model, snmp_usm_params_t* p, uint8_t** calc_auth_p,
1817 unsigned* calc_auth_len_p, char const** error)
1819 int msg_len;
1820 uint8_t* msg;
1821 unsigned auth_len;
1822 uint8_t* auth;
1823 uint8_t* key;
1824 unsigned key_len;
1825 uint8_t *calc_auth;
1826 unsigned start;
1827 unsigned end;
1828 unsigned i;
1830 if (!p->auth_tvb) {
1831 *error = "No Authenticator";
1832 return false;
1835 key = p->user_assoc->user.authKey.data;
1836 key_len = p->user_assoc->user.authKey.len;
1838 if (! key ) {
1839 *error = "User has no authKey";
1840 return false;
1843 auth_len = tvb_captured_length(p->auth_tvb);
1845 if (auth_len != auth_tag_len[model]) {
1846 *error = "Authenticator length wrong";
1847 return false;
1850 msg_len = tvb_captured_length(p->msg_tvb);
1851 if (msg_len <= 0) {
1852 *error = "Not enough data remaining";
1853 return false;
1855 msg = (uint8_t*)tvb_memdup(pinfo->pool,p->msg_tvb,0,msg_len);
1857 auth = (uint8_t*)tvb_memdup(pinfo->pool,p->auth_tvb,0,auth_len);
1859 start = p->auth_offset - p->start_offset;
1860 end = start + auth_len;
1862 /* fill the authenticator with zeros */
1863 for ( i = start ; i < end ; i++ ) {
1864 msg[i] = '\0';
1867 calc_auth = (uint8_t*)wmem_alloc(pinfo->pool, auth_hash_len[model]);
1869 if (ws_hmac_buffer(auth_hash_algo[model], calc_auth, msg, msg_len, key, key_len)) {
1870 return false;
1873 if (calc_auth_p) *calc_auth_p = calc_auth;
1874 if (calc_auth_len_p) *calc_auth_len_p = auth_len;
1876 return ( memcmp(auth,calc_auth,auth_len) != 0 ) ? false : true;
1879 static tvbuff_t*
1880 snmp_usm_priv_des(snmp_usm_params_t* p, tvbuff_t* encryptedData, packet_info *pinfo, char const** error)
1882 gcry_error_t err;
1883 gcry_cipher_hd_t hd = NULL;
1885 uint8_t* cleartext;
1886 uint8_t* des_key = p->user_assoc->user.privKey.data; /* first 8 bytes */
1887 uint8_t* pre_iv = &(p->user_assoc->user.privKey.data[8]); /* last 8 bytes */
1888 uint8_t* salt;
1889 int salt_len;
1890 int cryptgrm_len;
1891 uint8_t* cryptgrm;
1892 tvbuff_t* clear_tvb;
1893 uint8_t iv[8];
1894 unsigned i;
1897 salt_len = tvb_captured_length(p->priv_tvb);
1899 if (salt_len != 8) {
1900 *error = "decryptionError: msgPrivacyParameters length != 8";
1901 return NULL;
1904 salt = (uint8_t*)tvb_memdup(pinfo->pool,p->priv_tvb,0,salt_len);
1907 The resulting "salt" is XOR-ed with the pre-IV to obtain the IV.
1909 for (i=0; i<8; i++) {
1910 iv[i] = pre_iv[i] ^ salt[i];
1913 cryptgrm_len = tvb_captured_length(encryptedData);
1915 if ((cryptgrm_len <= 0) || (cryptgrm_len % 8)) {
1916 *error = "decryptionError: the length of the encrypted data is not a multiple of 8 octets";
1917 return NULL;
1920 cryptgrm = (uint8_t*)tvb_memdup(pinfo->pool,encryptedData,0,-1);
1922 cleartext = (uint8_t*)wmem_alloc(pinfo->pool, cryptgrm_len);
1924 err = gcry_cipher_open(&hd, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_CBC, 0);
1925 if (err != GPG_ERR_NO_ERROR) goto on_gcry_error;
1927 err = gcry_cipher_setiv(hd, iv, 8);
1928 if (err != GPG_ERR_NO_ERROR) goto on_gcry_error;
1930 err = gcry_cipher_setkey(hd,des_key,8);
1931 if (err != GPG_ERR_NO_ERROR) goto on_gcry_error;
1933 err = gcry_cipher_decrypt(hd, cleartext, cryptgrm_len, cryptgrm, cryptgrm_len);
1934 if (err != GPG_ERR_NO_ERROR) goto on_gcry_error;
1936 gcry_cipher_close(hd);
1938 clear_tvb = tvb_new_child_real_data(encryptedData, cleartext, cryptgrm_len, cryptgrm_len);
1940 return clear_tvb;
1942 on_gcry_error:
1943 *error = (const char *)gcry_strerror(err);
1944 if (hd) gcry_cipher_close(hd);
1945 return NULL;
1948 static tvbuff_t*
1949 snmp_usm_priv_aes_common(snmp_usm_params_t* p, tvbuff_t* encryptedData, packet_info *pinfo, char const** error, int algo)
1951 gcry_error_t err;
1952 gcry_cipher_hd_t hd = NULL;
1954 uint8_t* cleartext;
1955 uint8_t* aes_key = p->user_assoc->user.privKey.data;
1956 int aes_key_len = p->user_assoc->user.privKey.len;
1957 uint8_t iv[16];
1958 int priv_len;
1959 int cryptgrm_len;
1960 uint8_t* cryptgrm;
1961 tvbuff_t* clear_tvb;
1963 priv_len = tvb_captured_length(p->priv_tvb);
1965 if (priv_len != 8) {
1966 *error = "decryptionError: msgPrivacyParameters length != 8";
1967 return NULL;
1970 iv[0] = (p->boots & 0xff000000) >> 24;
1971 iv[1] = (p->boots & 0x00ff0000) >> 16;
1972 iv[2] = (p->boots & 0x0000ff00) >> 8;
1973 iv[3] = (p->boots & 0x000000ff);
1974 iv[4] = (p->snmp_time & 0xff000000) >> 24;
1975 iv[5] = (p->snmp_time & 0x00ff0000) >> 16;
1976 iv[6] = (p->snmp_time & 0x0000ff00) >> 8;
1977 iv[7] = (p->snmp_time & 0x000000ff);
1978 tvb_memcpy(p->priv_tvb,&(iv[8]),0,8);
1980 cryptgrm_len = tvb_captured_length(encryptedData);
1981 if (cryptgrm_len <= 0) {
1982 *error = "Not enough data remaining";
1983 return NULL;
1985 cryptgrm = (uint8_t*)tvb_memdup(pinfo->pool,encryptedData,0,-1);
1987 cleartext = (uint8_t*)wmem_alloc(pinfo->pool, cryptgrm_len);
1989 err = gcry_cipher_open(&hd, algo, GCRY_CIPHER_MODE_CFB, 0);
1990 if (err != GPG_ERR_NO_ERROR) goto on_gcry_error;
1992 err = gcry_cipher_setiv(hd, iv, 16);
1993 if (err != GPG_ERR_NO_ERROR) goto on_gcry_error;
1995 err = gcry_cipher_setkey(hd,aes_key,aes_key_len);
1996 if (err != GPG_ERR_NO_ERROR) goto on_gcry_error;
1998 err = gcry_cipher_decrypt(hd, cleartext, cryptgrm_len, cryptgrm, cryptgrm_len);
1999 if (err != GPG_ERR_NO_ERROR) goto on_gcry_error;
2001 gcry_cipher_close(hd);
2003 clear_tvb = tvb_new_child_real_data(encryptedData, cleartext, cryptgrm_len, cryptgrm_len);
2005 return clear_tvb;
2007 on_gcry_error:
2008 *error = (const char *)gcry_strerror(err);
2009 if (hd) gcry_cipher_close(hd);
2010 return NULL;
2013 static tvbuff_t*
2014 snmp_usm_priv_aes128(snmp_usm_params_t* p, tvbuff_t* encryptedData, packet_info *pinfo, char const** error)
2016 return snmp_usm_priv_aes_common(p, encryptedData, pinfo, error, GCRY_CIPHER_AES);
2019 static tvbuff_t*
2020 snmp_usm_priv_aes192(snmp_usm_params_t* p, tvbuff_t* encryptedData, packet_info *pinfo, char const** error)
2022 return snmp_usm_priv_aes_common(p, encryptedData, pinfo, error, GCRY_CIPHER_AES192);
2025 static tvbuff_t*
2026 snmp_usm_priv_aes256(snmp_usm_params_t* p, tvbuff_t* encryptedData, packet_info *pinfo, char const** error)
2028 return snmp_usm_priv_aes_common(p, encryptedData, pinfo, error, GCRY_CIPHER_AES256);
2031 static bool
2032 check_ScopedPdu(tvbuff_t* tvb)
2034 int offset;
2035 int8_t ber_class;
2036 bool pc;
2037 int32_t tag;
2038 int hoffset, eoffset;
2039 uint32_t len;
2041 offset = get_ber_identifier(tvb, 0, &ber_class, &pc, &tag);
2042 offset = get_ber_length(tvb, offset, NULL, NULL);
2044 if ( ! (((ber_class!=BER_CLASS_APP) && (ber_class!=BER_CLASS_PRI) )
2045 && ( (!pc) || (ber_class!=BER_CLASS_UNI) || (tag!=BER_UNI_TAG_ENUMERATED) )
2046 )) return false;
2048 if((tvb_get_uint8(tvb, offset)==0)&&(tvb_get_uint8(tvb, offset+1)==0))
2049 return true;
2051 hoffset = offset;
2053 offset = get_ber_identifier(tvb, offset, &ber_class, &pc, &tag);
2054 offset = get_ber_length(tvb, offset, &len, NULL);
2055 eoffset = offset + len;
2057 if (eoffset <= hoffset) return false;
2059 if ((ber_class!=BER_CLASS_APP)&&(ber_class!=BER_CLASS_PRI))
2060 if( (ber_class!=BER_CLASS_UNI)
2061 ||((tag<BER_UNI_TAG_NumericString)&&(tag!=BER_UNI_TAG_OCTETSTRING)&&(tag!=BER_UNI_TAG_UTF8String)) )
2062 return false;
2064 return true;
2071 static int
2072 dissect_snmp_EnterpriseOID(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
2073 const char* name;
2075 offset = dissect_ber_object_identifier_str(implicit_tag, actx, tree, tvb, offset, hf_index, &enterprise_oid);
2078 if (display_oid && enterprise_oid) {
2079 name = oid_resolved_from_string(actx->pinfo->pool, enterprise_oid);
2080 if (name) {
2081 col_append_fstr (actx->pinfo->cinfo, COL_INFO, " %s", name);
2086 return offset;
2091 static int
2092 dissect_snmp_OCTET_STRING_SIZE_4(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
2093 offset = dissect_ber_octet_string(implicit_tag, actx, tree, tvb, offset, hf_index,
2094 NULL);
2096 return offset;
2101 static int
2102 dissect_snmp_NetworkAddress(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
2103 offset = dissect_ber_tagged_type(implicit_tag, actx, tree, tvb, offset,
2104 hf_index, BER_CLASS_APP, 0, true, dissect_snmp_OCTET_STRING_SIZE_4);
2106 return offset;
2111 static int
2112 dissect_snmp_INTEGER_0_4294967295(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
2113 offset = dissect_ber_integer(implicit_tag, actx, tree, tvb, offset, hf_index,
2114 NULL);
2116 return offset;
2121 static int
2122 dissect_snmp_TimeTicks(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
2123 offset = dissect_ber_tagged_type(implicit_tag, actx, tree, tvb, offset,
2124 hf_index, BER_CLASS_APP, 3, true, dissect_snmp_INTEGER_0_4294967295);
2126 return offset;
2131 static int
2132 dissect_snmp_Integer32(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
2134 offset = dissect_ber_integer(implicit_tag, actx, tree, tvb, offset, hf_index,
2135 &RequestID);
2139 return offset;
2144 static int
2145 dissect_snmp_ObjectName(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
2146 offset = dissect_ber_object_identifier(implicit_tag, actx, tree, tvb, offset, hf_index, NULL);
2148 return offset;
2152 static const value_string snmp_Version_vals[] = {
2153 { 0, "version-1" },
2154 { 1, "v2c" },
2155 { 2, "v2u" },
2156 { 3, "snmpv3" },
2157 { 0, NULL }
2161 static int
2162 dissect_snmp_Version(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
2163 offset = dissect_ber_integer(implicit_tag, actx, tree, tvb, offset, hf_index,
2164 &snmp_version);
2166 return offset;
2171 static int
2172 dissect_snmp_Community(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
2173 offset = dissect_ber_octet_string(implicit_tag, actx, tree, tvb, offset, hf_index,
2174 NULL);
2176 return offset;
2181 static int
2182 dissect_snmp_T_request_id(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
2184 offset = dissect_ber_integer(implicit_tag, actx, tree, tvb, offset, hf_index,
2185 &RequestID);
2189 return offset;
2193 static const value_string snmp_T_error_status_vals[] = {
2194 { 0, "noError" },
2195 { 1, "tooBig" },
2196 { 2, "noSuchName" },
2197 { 3, "badValue" },
2198 { 4, "readOnly" },
2199 { 5, "genErr" },
2200 { 6, "noAccess" },
2201 { 7, "wrongType" },
2202 { 8, "wrongLength" },
2203 { 9, "wrongEncoding" },
2204 { 10, "wrongValue" },
2205 { 11, "noCreation" },
2206 { 12, "inconsistentValue" },
2207 { 13, "resourceUnavailable" },
2208 { 14, "commitFailed" },
2209 { 15, "undoFailed" },
2210 { 16, "authorizationError" },
2211 { 17, "notWritable" },
2212 { 18, "inconsistentName" },
2213 { 0, NULL }
2217 static int
2218 dissect_snmp_T_error_status(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
2219 offset = dissect_ber_integer(implicit_tag, actx, tree, tvb, offset, hf_index,
2220 NULL);
2222 return offset;
2227 static int
2228 dissect_snmp_INTEGER(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
2229 offset = dissect_ber_integer(implicit_tag, actx, tree, tvb, offset, hf_index,
2230 NULL);
2232 return offset;
2237 static const ber_sequence_t VarBindList_sequence_of[1] = {
2238 { &hf_snmp_VarBindList_item, BER_CLASS_UNI, BER_UNI_TAG_SEQUENCE, BER_FLAGS_NOOWNTAG, dissect_snmp_VarBind },
2241 static int
2242 dissect_snmp_VarBindList(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
2243 offset = dissect_ber_sequence_of(implicit_tag, actx, tree, tvb, offset,
2244 VarBindList_sequence_of, hf_index, ett_snmp_VarBindList);
2246 return offset;
2250 static const ber_sequence_t PDU_sequence[] = {
2251 { &hf_snmp_request_id , BER_CLASS_UNI, BER_UNI_TAG_INTEGER, BER_FLAGS_NOOWNTAG, dissect_snmp_T_request_id },
2252 { &hf_snmp_error_status , BER_CLASS_UNI, BER_UNI_TAG_INTEGER, BER_FLAGS_NOOWNTAG, dissect_snmp_T_error_status },
2253 { &hf_snmp_error_index , BER_CLASS_UNI, BER_UNI_TAG_INTEGER, BER_FLAGS_NOOWNTAG, dissect_snmp_INTEGER },
2254 { &hf_snmp_variable_bindings, BER_CLASS_UNI, BER_UNI_TAG_SEQUENCE, BER_FLAGS_NOOWNTAG, dissect_snmp_VarBindList },
2255 { NULL, 0, 0, 0, NULL }
2258 static int
2259 dissect_snmp_PDU(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
2260 offset = dissect_ber_sequence(implicit_tag, actx, tree, tvb, offset,
2261 PDU_sequence, hf_index, ett_snmp_PDU);
2263 return offset;
2268 static int
2269 dissect_snmp_GetRequest_PDU(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
2270 offset = dissect_ber_tagged_type(implicit_tag, actx, tree, tvb, offset,
2271 hf_index, BER_CLASS_CON, 0, true, dissect_snmp_PDU);
2273 return offset;
2278 static int
2279 dissect_snmp_GetNextRequest_PDU(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
2280 offset = dissect_ber_tagged_type(implicit_tag, actx, tree, tvb, offset,
2281 hf_index, BER_CLASS_CON, 1, true, dissect_snmp_PDU);
2283 return offset;
2288 static int
2289 dissect_snmp_GetResponse_PDU(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
2290 offset = dissect_ber_tagged_type(implicit_tag, actx, tree, tvb, offset,
2291 hf_index, BER_CLASS_CON, 2, true, dissect_snmp_PDU);
2293 return offset;
2298 static int
2299 dissect_snmp_SetRequest_PDU(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
2300 offset = dissect_ber_tagged_type(implicit_tag, actx, tree, tvb, offset,
2301 hf_index, BER_CLASS_CON, 3, true, dissect_snmp_PDU);
2303 return offset;
2307 static const value_string snmp_GenericTrap_vals[] = {
2308 { 0, "coldStart" },
2309 { 1, "warmStart" },
2310 { 2, "linkDown" },
2311 { 3, "linkUp" },
2312 { 4, "authenticationFailure" },
2313 { 5, "egpNeighborLoss" },
2314 { 6, "enterpriseSpecific" },
2315 { 0, NULL }
2319 static int
2320 dissect_snmp_GenericTrap(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
2321 offset = dissect_ber_integer(implicit_tag, actx, tree, tvb, offset, hf_index,
2322 &generic_trap);
2324 return offset;
2329 static int
2330 dissect_snmp_SpecificTrap(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
2331 unsigned specific_trap;
2333 offset = dissect_ber_integer(implicit_tag, actx, tree, tvb, offset, hf_index,
2334 &specific_trap);
2337 if (generic_trap == 6) { /* enterprise specific */
2338 const char *specific_str = snmp_lookup_specific_trap (specific_trap);
2339 if (specific_str) {
2340 proto_item_append_text(actx->created_item, " (%s)", specific_str);
2344 return offset;
2348 static const ber_sequence_t Trap_PDU_U_sequence[] = {
2349 { &hf_snmp_enterprise , BER_CLASS_UNI, BER_UNI_TAG_OID, BER_FLAGS_NOOWNTAG, dissect_snmp_EnterpriseOID },
2350 { &hf_snmp_agent_addr , BER_CLASS_APP, 0, BER_FLAGS_NOOWNTAG, dissect_snmp_NetworkAddress },
2351 { &hf_snmp_generic_trap , BER_CLASS_UNI, BER_UNI_TAG_INTEGER, BER_FLAGS_NOOWNTAG, dissect_snmp_GenericTrap },
2352 { &hf_snmp_specific_trap , BER_CLASS_UNI, BER_UNI_TAG_INTEGER, BER_FLAGS_NOOWNTAG, dissect_snmp_SpecificTrap },
2353 { &hf_snmp_time_stamp , BER_CLASS_APP, 3, BER_FLAGS_NOOWNTAG, dissect_snmp_TimeTicks },
2354 { &hf_snmp_variable_bindings, BER_CLASS_UNI, BER_UNI_TAG_SEQUENCE, BER_FLAGS_NOOWNTAG, dissect_snmp_VarBindList },
2355 { NULL, 0, 0, 0, NULL }
2358 static int
2359 dissect_snmp_Trap_PDU_U(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
2360 generic_trap = 0;
2361 enterprise_oid = NULL;
2363 offset = dissect_ber_sequence(implicit_tag, actx, tree, tvb, offset,
2364 Trap_PDU_U_sequence, hf_index, ett_snmp_Trap_PDU_U);
2367 if (snmp_version != 0) {
2368 expert_add_info(actx->pinfo, tree, &ei_snmp_trap_pdu_obsolete);
2372 return offset;
2377 static int
2378 dissect_snmp_Trap_PDU(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
2379 offset = dissect_ber_tagged_type(implicit_tag, actx, tree, tvb, offset,
2380 hf_index, BER_CLASS_CON, 4, true, dissect_snmp_Trap_PDU_U);
2382 return offset;
2387 static int
2388 dissect_snmp_INTEGER_0_2147483647(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
2389 offset = dissect_ber_integer(implicit_tag, actx, tree, tvb, offset, hf_index,
2390 NULL);
2392 return offset;
2396 static const ber_sequence_t BulkPDU_sequence[] = {
2397 { &hf_snmp_bulkPDU_request_id, BER_CLASS_UNI, BER_UNI_TAG_INTEGER, BER_FLAGS_NOOWNTAG, dissect_snmp_Integer32 },
2398 { &hf_snmp_non_repeaters , BER_CLASS_UNI, BER_UNI_TAG_INTEGER, BER_FLAGS_NOOWNTAG, dissect_snmp_INTEGER_0_2147483647 },
2399 { &hf_snmp_max_repetitions, BER_CLASS_UNI, BER_UNI_TAG_INTEGER, BER_FLAGS_NOOWNTAG, dissect_snmp_INTEGER_0_2147483647 },
2400 { &hf_snmp_variable_bindings, BER_CLASS_UNI, BER_UNI_TAG_SEQUENCE, BER_FLAGS_NOOWNTAG, dissect_snmp_VarBindList },
2401 { NULL, 0, 0, 0, NULL }
2404 static int
2405 dissect_snmp_BulkPDU(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
2406 offset = dissect_ber_sequence(implicit_tag, actx, tree, tvb, offset,
2407 BulkPDU_sequence, hf_index, ett_snmp_BulkPDU);
2409 return offset;
2414 static int
2415 dissect_snmp_GetBulkRequest_PDU(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
2416 offset = dissect_ber_tagged_type(implicit_tag, actx, tree, tvb, offset,
2417 hf_index, BER_CLASS_CON, 5, true, dissect_snmp_BulkPDU);
2419 return offset;
2424 static int
2425 dissect_snmp_InformRequest_PDU(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
2426 offset = dissect_ber_tagged_type(implicit_tag, actx, tree, tvb, offset,
2427 hf_index, BER_CLASS_CON, 6, true, dissect_snmp_PDU);
2429 return offset;
2434 static int
2435 dissect_snmp_SNMPv2_Trap_PDU(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
2436 offset = dissect_ber_tagged_type(implicit_tag, actx, tree, tvb, offset,
2437 hf_index, BER_CLASS_CON, 7, true, dissect_snmp_PDU);
2439 return offset;
2444 static int
2445 dissect_snmp_Report_PDU(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
2446 offset = dissect_ber_tagged_type(implicit_tag, actx, tree, tvb, offset,
2447 hf_index, BER_CLASS_CON, 8, true, dissect_snmp_PDU);
2449 return offset;
2453 static const value_string snmp_PDUs_vals[] = {
2454 { 0, "get-request" },
2455 { 1, "get-next-request" },
2456 { 2, "get-response" },
2457 { 3, "set-request" },
2458 { 4, "trap" },
2459 { 5, "getBulkRequest" },
2460 { 6, "informRequest" },
2461 { 7, "snmpV2-trap" },
2462 { 8, "report" },
2463 { 0, NULL }
2466 static const ber_choice_t PDUs_choice[] = {
2467 { 0, &hf_snmp_get_request , BER_CLASS_CON, 0, BER_FLAGS_NOOWNTAG, dissect_snmp_GetRequest_PDU },
2468 { 1, &hf_snmp_get_next_request, BER_CLASS_CON, 1, BER_FLAGS_NOOWNTAG, dissect_snmp_GetNextRequest_PDU },
2469 { 2, &hf_snmp_get_response , BER_CLASS_CON, 2, BER_FLAGS_NOOWNTAG, dissect_snmp_GetResponse_PDU },
2470 { 3, &hf_snmp_set_request , BER_CLASS_CON, 3, BER_FLAGS_NOOWNTAG, dissect_snmp_SetRequest_PDU },
2471 { 4, &hf_snmp_trap , BER_CLASS_CON, 4, BER_FLAGS_NOOWNTAG, dissect_snmp_Trap_PDU },
2472 { 5, &hf_snmp_getBulkRequest , BER_CLASS_CON, 5, BER_FLAGS_NOOWNTAG, dissect_snmp_GetBulkRequest_PDU },
2473 { 6, &hf_snmp_informRequest , BER_CLASS_CON, 6, BER_FLAGS_NOOWNTAG, dissect_snmp_InformRequest_PDU },
2474 { 7, &hf_snmp_snmpV2_trap , BER_CLASS_CON, 7, BER_FLAGS_NOOWNTAG, dissect_snmp_SNMPv2_Trap_PDU },
2475 { 8, &hf_snmp_report , BER_CLASS_CON, 8, BER_FLAGS_NOOWNTAG, dissect_snmp_Report_PDU },
2476 { 0, NULL, 0, 0, 0, NULL }
2479 static int
2480 dissect_snmp_PDUs(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
2481 int pdu_type=-1;
2483 snmp_request_response_t *srrp;
2484 snmp_conv_info_t *snmp_info = (snmp_conv_info_t *)actx->private_data;
2486 col_clear(actx->pinfo->cinfo, COL_INFO);
2488 offset = dissect_ber_choice(actx, tree, tvb, offset,
2489 PDUs_choice, hf_index, ett_snmp_PDUs,
2490 &pdu_type);
2492 if( (pdu_type!=-1) && snmp_PDUs_vals[pdu_type].strptr ){
2493 col_prepend_fstr(actx->pinfo->cinfo, COL_INFO, "%s", snmp_PDUs_vals[pdu_type].strptr);
2495 /* pdu_type is the index, not the tag so convert it to the tag value */
2496 pdu_type = snmp_PDUs_vals[pdu_type].value;
2498 srrp=snmp_match_request_response(tvb, actx->pinfo, tree, RequestID, pdu_type, snmp_info);
2499 if (srrp) {
2500 tap_queue_packet(snmp_tap, actx->pinfo, srrp);
2506 return offset;
2510 static const ber_sequence_t Message_sequence[] = {
2511 { &hf_snmp_version , BER_CLASS_UNI, BER_UNI_TAG_INTEGER, BER_FLAGS_NOOWNTAG, dissect_snmp_Version },
2512 { &hf_snmp_community , BER_CLASS_UNI, BER_UNI_TAG_OCTETSTRING, BER_FLAGS_NOOWNTAG, dissect_snmp_Community },
2513 { &hf_snmp_data , BER_CLASS_ANY/*choice*/, -1/*choice*/, BER_FLAGS_NOOWNTAG|BER_FLAGS_NOTCHKTAG, dissect_snmp_PDUs },
2514 { NULL, 0, 0, 0, NULL }
2517 static int
2518 dissect_snmp_Message(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
2519 offset = dissect_ber_sequence(implicit_tag, actx, tree, tvb, offset,
2520 Message_sequence, hf_index, ett_snmp_Message);
2522 return offset;
2527 static int
2528 dissect_snmp_OCTET_STRING(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
2529 offset = dissect_ber_octet_string(implicit_tag, actx, tree, tvb, offset, hf_index,
2530 NULL);
2532 return offset;
2536 static const value_string snmp_T_datav2u_vals[] = {
2537 { 0, "plaintext" },
2538 { 1, "encrypted" },
2539 { 0, NULL }
2542 static const ber_choice_t T_datav2u_choice[] = {
2543 { 0, &hf_snmp_v2u_plaintext , BER_CLASS_ANY/*choice*/, -1/*choice*/, BER_FLAGS_NOOWNTAG, dissect_snmp_PDUs },
2544 { 1, &hf_snmp_encrypted , BER_CLASS_UNI, BER_UNI_TAG_OCTETSTRING, BER_FLAGS_NOOWNTAG, dissect_snmp_OCTET_STRING },
2545 { 0, NULL, 0, 0, 0, NULL }
2548 static int
2549 dissect_snmp_T_datav2u(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
2550 offset = dissect_ber_choice(actx, tree, tvb, offset,
2551 T_datav2u_choice, hf_index, ett_snmp_T_datav2u,
2552 NULL);
2554 return offset;
2558 static const ber_sequence_t Messagev2u_sequence[] = {
2559 { &hf_snmp_version , BER_CLASS_UNI, BER_UNI_TAG_INTEGER, BER_FLAGS_NOOWNTAG, dissect_snmp_Version },
2560 { &hf_snmp_parameters , BER_CLASS_UNI, BER_UNI_TAG_OCTETSTRING, BER_FLAGS_NOOWNTAG, dissect_snmp_OCTET_STRING },
2561 { &hf_snmp_datav2u , BER_CLASS_ANY/*choice*/, -1/*choice*/, BER_FLAGS_NOOWNTAG|BER_FLAGS_NOTCHKTAG, dissect_snmp_T_datav2u },
2562 { NULL, 0, 0, 0, NULL }
2565 static int
2566 dissect_snmp_Messagev2u(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
2567 offset = dissect_ber_sequence(implicit_tag, actx, tree, tvb, offset,
2568 Messagev2u_sequence, hf_index, ett_snmp_Messagev2u);
2570 return offset;
2575 static int
2576 dissect_snmp_SnmpEngineID(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
2577 tvbuff_t* param_tvb = NULL;
2579 offset = dissect_ber_octet_string(implicit_tag, actx, tree, tvb, offset, hf_index, &param_tvb);
2580 if (param_tvb) {
2581 proto_tree* engine_tree = proto_item_add_subtree(actx->created_item,ett_engineid);
2582 dissect_snmp_engineid(engine_tree, actx->pinfo, param_tvb, 0, tvb_reported_length_remaining(param_tvb,0));
2586 return offset;
2591 static int
2592 dissect_snmp_T_msgAuthoritativeEngineID(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
2594 offset = dissect_ber_octet_string(implicit_tag, actx, tree, tvb, offset, hf_index, &usm_p.engine_tvb);
2595 if (usm_p.engine_tvb) {
2596 proto_tree* engine_tree = proto_item_add_subtree(actx->created_item,ett_engineid);
2597 dissect_snmp_engineid(engine_tree, actx->pinfo, usm_p.engine_tvb, 0, tvb_reported_length_remaining(usm_p.engine_tvb,0));
2601 return offset;
2606 static int
2607 dissect_snmp_T_msgAuthoritativeEngineBoots(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
2608 offset = dissect_ber_integer(implicit_tag, actx, tree, tvb, offset, hf_index,
2609 &usm_p.boots);
2611 return offset;
2616 static int
2617 dissect_snmp_T_msgAuthoritativeEngineTime(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
2618 offset = dissect_ber_integer(implicit_tag, actx, tree, tvb, offset, hf_index,
2619 &usm_p.snmp_time);
2621 return offset;
2626 static int
2627 dissect_snmp_T_msgUserName(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
2628 offset = dissect_ber_octet_string(implicit_tag, actx, tree, tvb, offset, hf_index,
2629 &usm_p.user_tvb);
2631 return offset;
2636 static int
2637 dissect_snmp_T_msgAuthenticationParameters(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
2638 offset = dissect_ber_octet_string(false, actx, tree, tvb, offset, hf_index, &usm_p.auth_tvb);
2639 if (usm_p.auth_tvb) {
2640 usm_p.auth_item = actx->created_item;
2641 usm_p.auth_offset = tvb_offset_from_real_beginning(usm_p.auth_tvb);
2644 return offset;
2649 static int
2650 dissect_snmp_T_msgPrivacyParameters(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
2651 offset = dissect_ber_octet_string(implicit_tag, actx, tree, tvb, offset, hf_index,
2652 &usm_p.priv_tvb);
2654 return offset;
2658 static const ber_sequence_t UsmSecurityParameters_sequence[] = {
2659 { &hf_snmp_msgAuthoritativeEngineID, BER_CLASS_UNI, BER_UNI_TAG_OCTETSTRING, BER_FLAGS_NOOWNTAG, dissect_snmp_T_msgAuthoritativeEngineID },
2660 { &hf_snmp_msgAuthoritativeEngineBoots, BER_CLASS_UNI, BER_UNI_TAG_INTEGER, BER_FLAGS_NOOWNTAG, dissect_snmp_T_msgAuthoritativeEngineBoots },
2661 { &hf_snmp_msgAuthoritativeEngineTime, BER_CLASS_UNI, BER_UNI_TAG_INTEGER, BER_FLAGS_NOOWNTAG, dissect_snmp_T_msgAuthoritativeEngineTime },
2662 { &hf_snmp_msgUserName , BER_CLASS_UNI, BER_UNI_TAG_OCTETSTRING, BER_FLAGS_NOOWNTAG, dissect_snmp_T_msgUserName },
2663 { &hf_snmp_msgAuthenticationParameters, BER_CLASS_UNI, BER_UNI_TAG_OCTETSTRING, BER_FLAGS_NOOWNTAG, dissect_snmp_T_msgAuthenticationParameters },
2664 { &hf_snmp_msgPrivacyParameters, BER_CLASS_UNI, BER_UNI_TAG_OCTETSTRING, BER_FLAGS_NOOWNTAG, dissect_snmp_T_msgPrivacyParameters },
2665 { NULL, 0, 0, 0, NULL }
2668 static int
2669 dissect_snmp_UsmSecurityParameters(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
2670 offset = dissect_ber_sequence(implicit_tag, actx, tree, tvb, offset,
2671 UsmSecurityParameters_sequence, hf_index, ett_snmp_UsmSecurityParameters);
2673 return offset;
2678 static int
2679 dissect_snmp_INTEGER_484_2147483647(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
2680 offset = dissect_ber_integer(implicit_tag, actx, tree, tvb, offset, hf_index,
2681 NULL);
2683 return offset;
2688 static int
2689 dissect_snmp_T_msgFlags(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
2690 tvbuff_t *parameter_tvb = NULL;
2692 offset = dissect_ber_octet_string(implicit_tag, actx, tree, tvb, offset, hf_index,
2693 &parameter_tvb);
2695 if (parameter_tvb){
2696 uint8_t v3_flags = tvb_get_uint8(parameter_tvb, 0);
2697 proto_tree* flags_tree = proto_item_add_subtree(actx->created_item,ett_msgFlags);
2699 proto_tree_add_item(flags_tree, hf_snmp_v3_flags_report, parameter_tvb, 0, 1, ENC_BIG_ENDIAN);
2700 proto_tree_add_item(flags_tree, hf_snmp_v3_flags_crypt, parameter_tvb, 0, 1, ENC_BIG_ENDIAN);
2701 proto_tree_add_item(flags_tree, hf_snmp_v3_flags_auth, parameter_tvb, 0, 1, ENC_BIG_ENDIAN);
2703 usm_p.encrypted = v3_flags & TH_CRYPT ? true : false;
2704 usm_p.authenticated = v3_flags & TH_AUTH ? true : false;
2709 return offset;
2714 static int
2715 dissect_snmp_T_msgSecurityModel(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
2716 offset = dissect_ber_integer(implicit_tag, actx, tree, tvb, offset, hf_index,
2717 &MsgSecurityModel);
2719 return offset;
2723 static const ber_sequence_t HeaderData_sequence[] = {
2724 { &hf_snmp_msgID , BER_CLASS_UNI, BER_UNI_TAG_INTEGER, BER_FLAGS_NOOWNTAG, dissect_snmp_INTEGER_0_2147483647 },
2725 { &hf_snmp_msgMaxSize , BER_CLASS_UNI, BER_UNI_TAG_INTEGER, BER_FLAGS_NOOWNTAG, dissect_snmp_INTEGER_484_2147483647 },
2726 { &hf_snmp_msgFlags , BER_CLASS_UNI, BER_UNI_TAG_OCTETSTRING, BER_FLAGS_NOOWNTAG, dissect_snmp_T_msgFlags },
2727 { &hf_snmp_msgSecurityModel, BER_CLASS_UNI, BER_UNI_TAG_INTEGER, BER_FLAGS_NOOWNTAG, dissect_snmp_T_msgSecurityModel },
2728 { NULL, 0, 0, 0, NULL }
2731 static int
2732 dissect_snmp_HeaderData(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
2733 offset = dissect_ber_sequence(implicit_tag, actx, tree, tvb, offset,
2734 HeaderData_sequence, hf_index, ett_snmp_HeaderData);
2736 return offset;
2741 static int
2742 dissect_snmp_T_msgSecurityParameters(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
2744 switch(MsgSecurityModel){
2745 case SNMP_SEC_USM: /* 3 */
2746 offset = get_ber_identifier(tvb, offset, NULL, NULL, NULL);
2747 offset = get_ber_length(tvb, offset, NULL, NULL);
2748 offset = dissect_snmp_UsmSecurityParameters(false, tvb, offset, actx, tree, -1);
2749 usm_p.user_assoc = get_user_assoc(usm_p.engine_tvb, usm_p.user_tvb, actx->pinfo);
2750 break;
2751 case SNMP_SEC_ANY: /* 0 */
2752 case SNMP_SEC_V1: /* 1 */
2753 case SNMP_SEC_V2C: /* 2 */
2754 default:
2755 offset = dissect_ber_octet_string(implicit_tag, actx, tree, tvb, offset, hf_index,
2756 NULL);
2758 break;
2762 return offset;
2766 static const ber_sequence_t ScopedPDU_sequence[] = {
2767 { &hf_snmp_contextEngineID, BER_CLASS_UNI, BER_UNI_TAG_OCTETSTRING, BER_FLAGS_NOOWNTAG, dissect_snmp_SnmpEngineID },
2768 { &hf_snmp_contextName , BER_CLASS_UNI, BER_UNI_TAG_OCTETSTRING, BER_FLAGS_NOOWNTAG, dissect_snmp_OCTET_STRING },
2769 { &hf_snmp_data , BER_CLASS_ANY/*choice*/, -1/*choice*/, BER_FLAGS_NOOWNTAG|BER_FLAGS_NOTCHKTAG, dissect_snmp_PDUs },
2770 { NULL, 0, 0, 0, NULL }
2773 static int
2774 dissect_snmp_ScopedPDU(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
2775 offset = dissect_ber_sequence(implicit_tag, actx, tree, tvb, offset,
2776 ScopedPDU_sequence, hf_index, ett_snmp_ScopedPDU);
2778 return offset;
2783 static int
2784 dissect_snmp_T_encryptedPDU(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
2785 tvbuff_t* crypt_tvb;
2786 offset = dissect_ber_octet_string(false, actx, tree, tvb, offset, hf_snmp_encryptedPDU, &crypt_tvb);
2788 if( usm_p.encrypted && crypt_tvb
2789 && usm_p.user_assoc
2790 && usm_p.user_assoc->user.privProtocol ) {
2792 const char* error = NULL;
2793 proto_tree* encryptedpdu_tree = proto_item_add_subtree(actx->created_item,ett_encryptedPDU);
2794 tvbuff_t* cleartext_tvb = usm_p.user_assoc->user.privProtocol(&usm_p, crypt_tvb, actx->pinfo, &error );
2796 if (! cleartext_tvb) {
2797 proto_tree_add_expert_format(encryptedpdu_tree, actx->pinfo, &ei_snmp_failed_decrypted_data_pdu,
2798 crypt_tvb, 0, -1, "Failed to decrypt encryptedPDU: %s", error);
2800 col_set_str(actx->pinfo->cinfo, COL_INFO, "encryptedPDU: Failed to decrypt");
2802 return offset;
2803 } else {
2804 proto_item* decrypted_item;
2805 proto_tree* decrypted_tree;
2807 if (! check_ScopedPdu(cleartext_tvb)) {
2808 proto_tree_add_expert(encryptedpdu_tree, actx->pinfo, &ei_snmp_decrypted_data_bad_formatted, cleartext_tvb, 0, -1);
2810 col_set_str(actx->pinfo->cinfo, COL_INFO, "encryptedPDU: Decrypted data not formatted as expected");
2812 return offset;
2816 add_new_data_source(actx->pinfo, cleartext_tvb, "Decrypted ScopedPDU");
2818 decrypted_item = proto_tree_add_item(encryptedpdu_tree, hf_snmp_decryptedPDU,cleartext_tvb,0,-1,ENC_NA);
2819 decrypted_tree = proto_item_add_subtree(decrypted_item,ett_decrypted);
2820 dissect_snmp_ScopedPDU(false, cleartext_tvb, 0, actx, decrypted_tree, -1);
2822 } else {
2823 col_set_str(actx->pinfo->cinfo, COL_INFO, "encryptedPDU: privKey Unknown");
2827 return offset;
2831 static const value_string snmp_ScopedPduData_vals[] = {
2832 { 0, "plaintext" },
2833 { 1, "encryptedPDU" },
2834 { 0, NULL }
2837 static const ber_choice_t ScopedPduData_choice[] = {
2838 { 0, &hf_snmp_plaintext , BER_CLASS_UNI, BER_UNI_TAG_SEQUENCE, BER_FLAGS_NOOWNTAG, dissect_snmp_ScopedPDU },
2839 { 1, &hf_snmp_encryptedPDU , BER_CLASS_UNI, BER_UNI_TAG_OCTETSTRING, BER_FLAGS_NOOWNTAG, dissect_snmp_T_encryptedPDU },
2840 { 0, NULL, 0, 0, 0, NULL }
2843 static int
2844 dissect_snmp_ScopedPduData(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
2845 offset = dissect_ber_choice(actx, tree, tvb, offset,
2846 ScopedPduData_choice, hf_index, ett_snmp_ScopedPduData,
2847 NULL);
2849 return offset;
2853 static const ber_sequence_t SNMPv3Message_sequence[] = {
2854 { &hf_snmp_msgVersion , BER_CLASS_UNI, BER_UNI_TAG_INTEGER, BER_FLAGS_NOOWNTAG, dissect_snmp_Version },
2855 { &hf_snmp_msgGlobalData , BER_CLASS_UNI, BER_UNI_TAG_SEQUENCE, BER_FLAGS_NOOWNTAG, dissect_snmp_HeaderData },
2856 { &hf_snmp_msgSecurityParameters, BER_CLASS_UNI, BER_UNI_TAG_OCTETSTRING, BER_FLAGS_NOOWNTAG, dissect_snmp_T_msgSecurityParameters },
2857 { &hf_snmp_msgData , BER_CLASS_ANY/*choice*/, -1/*choice*/, BER_FLAGS_NOOWNTAG|BER_FLAGS_NOTCHKTAG, dissect_snmp_ScopedPduData },
2858 { NULL, 0, 0, 0, NULL }
2861 static int
2862 dissect_snmp_SNMPv3Message(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
2863 offset = dissect_ber_sequence(implicit_tag, actx, tree, tvb, offset,
2864 SNMPv3Message_sequence, hf_index, ett_snmp_SNMPv3Message);
2867 if( usm_p.authenticated
2868 && usm_p.user_assoc ) {
2869 const char* error = NULL;
2870 proto_item* authen_item;
2871 proto_tree* authen_tree = proto_item_add_subtree(usm_p.auth_item,ett_authParameters);
2872 uint8_t* calc_auth = NULL;
2873 unsigned calc_auth_len = 0;
2875 usm_p.authOK = snmp_usm_auth(actx->pinfo, usm_p.user_assoc->user.authModel, &usm_p, &calc_auth, &calc_auth_len, &error );
2877 if (error) {
2878 expert_add_info_format( actx->pinfo, usm_p.auth_item, &ei_snmp_verify_authentication_error, "Error while verifying Message authenticity: %s", error );
2879 } else {
2880 expert_field* expert;
2882 authen_item = proto_tree_add_boolean(authen_tree, hf_snmp_msgAuthentication, tvb, 0, 0, usm_p.authOK);
2883 proto_item_set_generated(authen_item);
2885 if (usm_p.authOK) {
2886 expert = &ei_snmp_authentication_ok;
2887 } else {
2888 const char* calc_auth_str = bytes_to_str_punct(actx->pinfo->pool, calc_auth,calc_auth_len,' ');
2889 proto_item_append_text(authen_item, " calculated = %s", calc_auth_str);
2890 expert = &ei_snmp_authentication_error;
2893 expert_add_info( actx->pinfo, authen_item, expert);
2897 return offset;
2901 static const value_string snmp_T_smux_version_vals[] = {
2902 { 0, "version-1" },
2903 { 0, NULL }
2907 static int
2908 dissect_snmp_T_smux_version(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
2909 offset = dissect_ber_integer(implicit_tag, actx, tree, tvb, offset, hf_index,
2910 NULL);
2912 return offset;
2917 static int
2918 dissect_snmp_OBJECT_IDENTIFIER(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
2919 offset = dissect_ber_object_identifier(implicit_tag, actx, tree, tvb, offset, hf_index, NULL);
2921 return offset;
2926 static int
2927 dissect_snmp_DisplayString(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
2928 offset = dissect_ber_octet_string(implicit_tag, actx, tree, tvb, offset, hf_index,
2929 NULL);
2931 return offset;
2935 static const ber_sequence_t SimpleOpen_U_sequence[] = {
2936 { &hf_snmp_smux_version , BER_CLASS_UNI, BER_UNI_TAG_INTEGER, BER_FLAGS_NOOWNTAG, dissect_snmp_T_smux_version },
2937 { &hf_snmp_identity , BER_CLASS_UNI, BER_UNI_TAG_OID, BER_FLAGS_NOOWNTAG, dissect_snmp_OBJECT_IDENTIFIER },
2938 { &hf_snmp_description , BER_CLASS_UNI, BER_UNI_TAG_OCTETSTRING, BER_FLAGS_NOOWNTAG, dissect_snmp_DisplayString },
2939 { &hf_snmp_password , BER_CLASS_UNI, BER_UNI_TAG_OCTETSTRING, BER_FLAGS_NOOWNTAG, dissect_snmp_OCTET_STRING },
2940 { NULL, 0, 0, 0, NULL }
2943 static int
2944 dissect_snmp_SimpleOpen_U(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
2945 offset = dissect_ber_sequence(implicit_tag, actx, tree, tvb, offset,
2946 SimpleOpen_U_sequence, hf_index, ett_snmp_SimpleOpen_U);
2948 return offset;
2953 static int
2954 dissect_snmp_SimpleOpen(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
2955 offset = dissect_ber_tagged_type(implicit_tag, actx, tree, tvb, offset,
2956 hf_index, BER_CLASS_APP, 0, true, dissect_snmp_SimpleOpen_U);
2958 return offset;
2962 static const value_string snmp_OpenPDU_vals[] = {
2963 { 0, "smux-simple" },
2964 { 0, NULL }
2967 static const ber_choice_t OpenPDU_choice[] = {
2968 { 0, &hf_snmp_smux_simple , BER_CLASS_APP, 0, BER_FLAGS_NOOWNTAG, dissect_snmp_SimpleOpen },
2969 { 0, NULL, 0, 0, 0, NULL }
2972 static int
2973 dissect_snmp_OpenPDU(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
2974 offset = dissect_ber_choice(actx, tree, tvb, offset,
2975 OpenPDU_choice, hf_index, ett_snmp_OpenPDU,
2976 NULL);
2978 return offset;
2982 static const value_string snmp_ClosePDU_U_vals[] = {
2983 { 0, "goingDown" },
2984 { 1, "unsupportedVersion" },
2985 { 2, "packetFormat" },
2986 { 3, "protocolError" },
2987 { 4, "internalError" },
2988 { 5, "authenticationFailure" },
2989 { 0, NULL }
2993 static int
2994 dissect_snmp_ClosePDU_U(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
2995 offset = dissect_ber_integer(implicit_tag, actx, tree, tvb, offset, hf_index,
2996 NULL);
2998 return offset;
3003 static int
3004 dissect_snmp_ClosePDU(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
3005 offset = dissect_ber_tagged_type(implicit_tag, actx, tree, tvb, offset,
3006 hf_index, BER_CLASS_APP, 1, true, dissect_snmp_ClosePDU_U);
3008 return offset;
3013 static int
3014 dissect_snmp_INTEGER_M1_2147483647(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
3015 offset = dissect_ber_integer(implicit_tag, actx, tree, tvb, offset, hf_index,
3016 NULL);
3018 return offset;
3022 static const value_string snmp_T_operation_vals[] = {
3023 { 0, "delete" },
3024 { 1, "readOnly" },
3025 { 2, "readWrite" },
3026 { 0, NULL }
3030 static int
3031 dissect_snmp_T_operation(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
3032 offset = dissect_ber_integer(implicit_tag, actx, tree, tvb, offset, hf_index,
3033 NULL);
3035 return offset;
3039 static const ber_sequence_t RReqPDU_U_sequence[] = {
3040 { &hf_snmp_subtree , BER_CLASS_UNI, BER_UNI_TAG_OID, BER_FLAGS_NOOWNTAG, dissect_snmp_ObjectName },
3041 { &hf_snmp_priority , BER_CLASS_UNI, BER_UNI_TAG_INTEGER, BER_FLAGS_NOOWNTAG, dissect_snmp_INTEGER_M1_2147483647 },
3042 { &hf_snmp_operation , BER_CLASS_UNI, BER_UNI_TAG_INTEGER, BER_FLAGS_NOOWNTAG, dissect_snmp_T_operation },
3043 { NULL, 0, 0, 0, NULL }
3046 static int
3047 dissect_snmp_RReqPDU_U(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
3048 offset = dissect_ber_sequence(implicit_tag, actx, tree, tvb, offset,
3049 RReqPDU_U_sequence, hf_index, ett_snmp_RReqPDU_U);
3051 return offset;
3056 static int
3057 dissect_snmp_RReqPDU(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
3058 offset = dissect_ber_tagged_type(implicit_tag, actx, tree, tvb, offset,
3059 hf_index, BER_CLASS_APP, 2, true, dissect_snmp_RReqPDU_U);
3061 return offset;
3065 static const value_string snmp_RRspPDU_U_vals[] = {
3066 { -1, "failure" },
3067 { 0, NULL }
3071 static int
3072 dissect_snmp_RRspPDU_U(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
3073 offset = dissect_ber_integer(implicit_tag, actx, tree, tvb, offset, hf_index,
3074 NULL);
3076 return offset;
3081 static int
3082 dissect_snmp_RRspPDU(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
3083 offset = dissect_ber_tagged_type(implicit_tag, actx, tree, tvb, offset,
3084 hf_index, BER_CLASS_APP, 3, true, dissect_snmp_RRspPDU_U);
3086 return offset;
3090 static const value_string snmp_RegisterResponse_vals[] = {
3091 { 0, "rRspPDU" },
3092 { 1, "pDUs" },
3093 { 0, NULL }
3096 static const ber_choice_t RegisterResponse_choice[] = {
3097 { 0, &hf_snmp_rRspPDU , BER_CLASS_APP, 3, BER_FLAGS_NOOWNTAG, dissect_snmp_RRspPDU },
3098 { 1, &hf_snmp_pDUs , BER_CLASS_ANY/*choice*/, -1/*choice*/, BER_FLAGS_NOOWNTAG, dissect_snmp_PDUs },
3099 { 0, NULL, 0, 0, 0, NULL }
3102 static int
3103 dissect_snmp_RegisterResponse(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
3104 offset = dissect_ber_choice(actx, tree, tvb, offset,
3105 RegisterResponse_choice, hf_index, ett_snmp_RegisterResponse,
3106 NULL);
3108 return offset;
3112 static const value_string snmp_SOutPDU_U_vals[] = {
3113 { 0, "commit" },
3114 { 1, "rollback" },
3115 { 0, NULL }
3119 static int
3120 dissect_snmp_SOutPDU_U(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
3121 offset = dissect_ber_integer(implicit_tag, actx, tree, tvb, offset, hf_index,
3122 NULL);
3124 return offset;
3129 static int
3130 dissect_snmp_SOutPDU(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
3131 offset = dissect_ber_tagged_type(implicit_tag, actx, tree, tvb, offset,
3132 hf_index, BER_CLASS_APP, 4, true, dissect_snmp_SOutPDU_U);
3134 return offset;
3138 static const value_string snmp_SMUX_PDUs_vals[] = {
3139 { 0, "open" },
3140 { 1, "close" },
3141 { 2, "registerRequest" },
3142 { 3, "registerResponse" },
3143 { 4, "commitOrRollback" },
3144 { 0, NULL }
3147 static const ber_choice_t SMUX_PDUs_choice[] = {
3148 { 0, &hf_snmp_open , BER_CLASS_ANY/*choice*/, -1/*choice*/, BER_FLAGS_NOOWNTAG, dissect_snmp_OpenPDU },
3149 { 1, &hf_snmp_close , BER_CLASS_APP, 1, BER_FLAGS_NOOWNTAG, dissect_snmp_ClosePDU },
3150 { 2, &hf_snmp_registerRequest, BER_CLASS_APP, 2, BER_FLAGS_NOOWNTAG, dissect_snmp_RReqPDU },
3151 { 3, &hf_snmp_registerResponse, BER_CLASS_ANY/*choice*/, -1/*choice*/, BER_FLAGS_NOOWNTAG, dissect_snmp_RegisterResponse },
3152 { 4, &hf_snmp_commitOrRollback, BER_CLASS_APP, 4, BER_FLAGS_NOOWNTAG, dissect_snmp_SOutPDU },
3153 { 0, NULL, 0, 0, 0, NULL }
3156 static int
3157 dissect_snmp_SMUX_PDUs(bool implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {
3159 snmp_conv_info_t *snmp_info = snmp_find_conversation_and_get_conv_data(actx->pinfo);
3161 actx->private_data = snmp_info;
3163 offset = dissect_ber_choice(actx, tree, tvb, offset,
3164 SMUX_PDUs_choice, hf_index, ett_snmp_SMUX_PDUs,
3165 NULL);
3167 return offset;
3170 /*--- PDUs ---*/
3172 static int dissect_SMUX_PDUs_PDU(tvbuff_t *tvb _U_, packet_info *pinfo _U_, proto_tree *tree _U_, void *data _U_) {
3173 int offset = 0;
3174 asn1_ctx_t asn1_ctx;
3175 asn1_ctx_init(&asn1_ctx, ASN1_ENC_BER, true, pinfo);
3176 offset = dissect_snmp_SMUX_PDUs(false, tvb, offset, &asn1_ctx, tree, hf_snmp_SMUX_PDUs_PDU);
3177 return offset;
3181 static snmp_conv_info_t*
3182 snmp_find_conversation_and_get_conv_data(packet_info *pinfo) {
3184 conversation_t *conversation = NULL;
3185 snmp_conv_info_t *snmp_info = NULL;
3187 /* Get the conversation with the wildcarded port, if it exists
3188 * and is associated with SNMP, so that requests and responses
3189 * can be matched even if the response comes from a different,
3190 * ephemeral, source port, as originally done in OS/400.
3191 * On UDP, we do not automatically call conversation_set_port2()
3192 * and we do not want to do so. Possibly this should eventually
3193 * use find_conversation_full and separate the "SNMP conversation"
3194 * from "the transport layer conversation that carries SNMP."
3196 if (pinfo->destport == UDP_PORT_SNMP) {
3197 conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, conversation_pt_to_conversation_type(pinfo->ptype),
3198 pinfo->srcport, 0, NO_PORT_B);
3199 } else if (pinfo->srcport == UDP_PORT_SNMP) {
3200 conversation = find_conversation(pinfo->fd->num, &pinfo->dst, &pinfo->src, conversation_pt_to_conversation_type(pinfo->ptype),
3201 pinfo->destport, 0, NO_PORT_B);
3203 if ((conversation == NULL) || (conversation_get_dissector(conversation, pinfo->num) != snmp_handle)) {
3204 conversation = find_or_create_conversation(pinfo);
3207 snmp_info = (snmp_conv_info_t *)conversation_get_proto_data(conversation, proto_snmp);
3208 if (snmp_info == NULL) {
3209 snmp_info = wmem_new0(wmem_file_scope(), snmp_conv_info_t);
3210 snmp_info->request_response=wmem_map_new(wmem_file_scope(), g_int_hash, g_int_equal);
3212 conversation_add_proto_data(conversation, proto_snmp, snmp_info);
3214 return snmp_info;
3217 unsigned
3218 dissect_snmp_pdu(tvbuff_t *tvb, int offset, packet_info *pinfo,
3219 proto_tree *tree, int proto, int ett, bool is_tcp)
3222 unsigned length_remaining;
3223 int8_t ber_class;
3224 bool pc, ind = 0;
3225 int32_t tag;
3226 uint32_t len;
3227 unsigned message_length;
3228 int start_offset = offset;
3229 uint32_t version = 0;
3230 tvbuff_t *next_tvb;
3232 proto_tree *snmp_tree = NULL;
3233 proto_item *item = NULL;
3235 snmp_conv_info_t *snmp_info = snmp_find_conversation_and_get_conv_data(pinfo);
3237 asn1_ctx_t asn1_ctx;
3238 asn1_ctx_init(&asn1_ctx, ASN1_ENC_BER, true, pinfo);
3240 asn1_ctx.private_data = snmp_info;
3242 usm_p.msg_tvb = tvb;
3243 usm_p.start_offset = tvb_offset_from_real_beginning(tvb);
3244 usm_p.engine_tvb = NULL;
3245 usm_p.user_tvb = NULL;
3246 usm_p.auth_item = NULL;
3247 usm_p.auth_tvb = NULL;
3248 usm_p.auth_offset = 0;
3249 usm_p.priv_tvb = NULL;
3250 usm_p.user_assoc = NULL;
3251 usm_p.authenticated = false;
3252 usm_p.encrypted = false;
3253 usm_p.boots = 0;
3254 usm_p.snmp_time = 0;
3255 usm_p.authOK = false;
3258 * This will throw an exception if we don't have any data left.
3259 * That's what we want. (See "tcp_dissect_pdus()", which is
3260 * similar, but doesn't have to deal with ASN.1.
3261 * XXX - can we make "tcp_dissect_pdus()" provide enough
3262 * information to the "get_pdu_len" routine so that we could
3263 * have that routine deal with ASN.1, and just use
3264 * "tcp_dissect_pdus()"?)
3266 length_remaining = tvb_ensure_captured_length_remaining(tvb, offset);
3268 /* NOTE: we have to parse the message piece by piece, since the
3269 * capture length may be less than the message length: a 'global'
3270 * parsing is likely to fail.
3274 * If this is SNMP-over-TCP, we might have to do reassembly
3275 * in order to read the "Sequence Of" header.
3277 if (is_tcp && snmp_desegment && pinfo->can_desegment) {
3279 * This is TCP, and we should, and can, do reassembly.
3281 * Is the "Sequence Of" header split across segment
3282 * boundaries? We require at least 6 bytes for the
3283 * header, which allows for a 4-byte length (ASN.1
3284 * BER).
3286 if (length_remaining < 6) {
3288 * Yes. Tell the TCP dissector where the data
3289 * for this message starts in the data it handed
3290 * us and that we need "some more data." Don't tell
3291 * it exactly how many bytes we need because if/when
3292 * we ask for even more (after the header) that will
3293 * break reassembly.
3295 pinfo->desegment_offset = offset;
3296 pinfo->desegment_len = DESEGMENT_ONE_MORE_SEGMENT;
3297 return 0;
3302 * OK, try to read the "Sequence Of" header; this gets the total
3303 * length of the SNMP message.
3305 offset = get_ber_identifier(tvb, offset, &ber_class, &pc, &tag);
3306 /*Get the total octet length of the SNMP data*/
3307 offset = get_ber_length(tvb, offset, &len, &ind);
3308 message_length = len + offset;
3310 /*Get the SNMP version data*/
3311 /*offset =*/ dissect_ber_integer(false, &asn1_ctx, 0, tvb, offset, -1, &version);
3315 * If this is SNMP-over-TCP, we might have to do reassembly
3316 * to get all of this message.
3318 if (is_tcp && snmp_desegment && pinfo->can_desegment) {
3320 * Yes - is the message split across segment boundaries?
3322 if (length_remaining < message_length) {
3324 * Yes. Tell the TCP dissector where the data
3325 * for this message starts in the data it handed
3326 * us, and how many more bytes we need, and
3327 * return.
3329 pinfo->desegment_offset = start_offset;
3330 pinfo->desegment_len =
3331 message_length - length_remaining;
3334 * Return 0, which means "I didn't dissect anything
3335 * because I don't have enough data - we need
3336 * to desegment".
3338 return 0;
3342 var_list = next_tvb_list_new(pinfo->pool);
3344 col_set_str(pinfo->cinfo, COL_PROTOCOL, proto_get_protocol_short_name(find_protocol_by_id(proto)));
3346 item = proto_tree_add_item(tree, proto, tvb, start_offset, message_length, ENC_BIG_ENDIAN);
3347 snmp_tree = proto_item_add_subtree(item, ett);
3349 switch (version) {
3350 case 0: /* v1 */
3351 case 1: /* v2c */
3352 offset = dissect_snmp_Message(false , tvb, start_offset, &asn1_ctx, snmp_tree, -1);
3353 break;
3354 case 2: /* v2u */
3355 offset = dissect_snmp_Messagev2u(false , tvb, start_offset, &asn1_ctx, snmp_tree, -1);
3356 break;
3357 /* v3 */
3358 case 3:
3359 offset = dissect_snmp_SNMPv3Message(false , tvb, start_offset, &asn1_ctx, snmp_tree, -1);
3360 break;
3361 default:
3363 * Return the length remaining in the tvbuff, so
3364 * if this is SNMP-over-TCP, our caller thinks there's
3365 * nothing left to dissect.
3367 expert_add_info(pinfo, item, &ei_snmp_version_unknown);
3368 return length_remaining;
3371 /* There may be appended data after the SNMP data, so treat as raw
3372 * data which needs to be dissected in case of UDP as UDP is PDU oriented.
3374 if((!is_tcp) && (length_remaining > (unsigned)offset)) {
3375 next_tvb = tvb_new_subset_remaining(tvb, offset);
3376 call_dissector(data_handle, next_tvb, pinfo, tree);
3377 } else {
3378 next_tvb_call(var_list, pinfo, tree, NULL, data_handle);
3381 return offset;
3384 static int
3385 dissect_snmp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
3387 int offset;
3388 int8_t tmp_class;
3389 bool tmp_pc;
3390 int32_t tmp_tag;
3391 uint32_t tmp_length;
3392 bool tmp_ind;
3395 * See if this looks like SNMP or not. if not, return 0 so
3396 * wireshark can try some other dissector instead.
3398 /* All SNMP packets are BER encoded and consist of a SEQUENCE
3399 * that spans the entire PDU. The first item is an INTEGER that
3400 * has the values 0-2 (version 1-3).
3401 * if not it is not snmp.
3403 /* SNMP starts with a SEQUENCE */
3404 offset = get_ber_identifier(tvb, 0, &tmp_class, &tmp_pc, &tmp_tag);
3405 if((tmp_class!=BER_CLASS_UNI)||(tmp_tag!=BER_UNI_TAG_SEQUENCE)) {
3406 return 0;
3408 /* then comes a length which spans the rest of the tvb */
3409 offset = get_ber_length(tvb, offset, &tmp_length, &tmp_ind);
3410 /* Loosen the heuristic a bit to handle the case where data has intentionally
3411 * been added after the snmp PDU ( UDP case) (#3684)
3412 * If this is fragmented or carried in ICMP, we don't expect the tvb to
3413 * have the full legnth, so don't check.
3415 if (!pinfo->fragmented && !pinfo->flags.in_error_pkt) {
3416 if ( pinfo->ptype == PT_UDP ) {
3417 if(tmp_length>(uint32_t)tvb_reported_length_remaining(tvb, offset)) {
3418 return 0;
3420 }else{
3421 if(tmp_length!=(uint32_t)tvb_reported_length_remaining(tvb, offset)) {
3422 return 0;
3426 /* then comes an INTEGER (version)*/
3427 get_ber_identifier(tvb, offset, &tmp_class, &tmp_pc, &tmp_tag);
3428 if((tmp_class!=BER_CLASS_UNI)||(tmp_tag!=BER_UNI_TAG_INTEGER)) {
3429 return 0;
3431 /* do we need to test that version is 0 - 2 (version1-3) ? */
3435 * The IBM i (OS/400) SNMP agent, at least originally, would
3436 * send responses back from some *other* UDP port, an ephemeral
3437 * port above 5000, going back to the same IP address and port
3438 * from which the request came, similar to TFTP. This only happens
3439 * with the agent port, 161, not with the trap port, etc. As of
3440 * 2015 with the latest fixes applied, it no longer does this:
3441 * https://www.ibm.com/support/pages/ptf/SI55487
3442 * https://www.ibm.com/support/pages/ptf/SI55537
3444 * The SNMP RFCs are silent on this (cf. L2TP RFC 2661, which
3445 * supports using either the well-known port or an ephemeral
3446 * port as the source port for responses, while noting that
3447 * the latter can cause issues with firewalls and NATs.) so
3448 * possibly some other implementations could do this.
3450 * If this packet went to the SNMP port, we check to see if
3451 * there's already a conversation with one address/port pair
3452 * matching the source IP address and port of this packet,
3453 * the other address matching the destination IP address of this
3454 * packet, and any destination port.
3456 * If not, we create one, with its address 1/port 1 pair being
3457 * the source address/port of this packet, its address 2 being
3458 * the destination address of this packet, and its port 2 being
3459 * wildcarded, and give it the SNMP dissector as a dissector.
3462 if (pinfo->destport == UDP_PORT_SNMP) {
3463 conversation_t *conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, conversation_pt_to_conversation_type(pinfo->ptype),
3464 pinfo->srcport, 0, NO_PORT_B);
3466 if( (conversation == NULL) || (conversation_get_dissector(conversation, pinfo->num)!=snmp_handle) ) {
3467 conversation = conversation_new(pinfo->num, &pinfo->src, &pinfo->dst, conversation_pt_to_conversation_type(pinfo->ptype),
3468 pinfo->srcport, 0, NO_PORT2);
3469 conversation_set_dissector(conversation, snmp_handle);
3473 return dissect_snmp_pdu(tvb, 0, pinfo, tree, proto_snmp, ett_snmp, false);
3476 static int
3477 dissect_snmp_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
3479 int offset = 0;
3480 unsigned message_len;
3482 while (tvb_reported_length_remaining(tvb, offset) > 0) {
3483 message_len = dissect_snmp_pdu(tvb, offset, pinfo, tree, proto_snmp, ett_snmp, true);
3484 if (message_len == 0) {
3486 * We don't have all the data for that message,
3487 * so we need to do desegmentation;
3488 * "dissect_snmp_pdu()" has set that up.
3490 break;
3492 offset += message_len;
3494 return tvb_captured_length(tvb);
3497 static int
3498 dissect_smux(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
3500 proto_tree *smux_tree = NULL;
3501 proto_item *item = NULL;
3503 var_list = next_tvb_list_new(pinfo->pool);
3505 col_set_str(pinfo->cinfo, COL_PROTOCOL, "SMUX");
3507 item = proto_tree_add_item(tree, proto_smux, tvb, 0, -1, ENC_NA);
3508 smux_tree = proto_item_add_subtree(item, ett_smux);
3510 return dissect_SMUX_PDUs_PDU(tvb, pinfo, smux_tree, data);
3514 MD5 Password to Key Algorithm from RFC 3414 A.2.1
3515 SHA1 Password to Key Algorithm from RFC 3414 A.2.2
3516 SHA2 Password to Key Algorithm from RFC 7860 9.3
3518 static void
3519 snmp_usm_password_to_key(const snmp_usm_auth_model_t model, const uint8_t *password,
3520 unsigned passwordlen, const uint8_t *engineID, unsigned engineLength, uint8_t *key)
3522 gcry_md_hd_t hash_handle;
3523 uint8_t *cp, password_buf[64];
3524 uint32_t password_index = 0;
3525 uint32_t count = 0, i;
3526 unsigned hash_len;
3528 if (gcry_md_open(&hash_handle, auth_hash_algo[model], 0)) {
3529 return;
3532 hash_len = auth_hash_len[model];
3534 /**********************************************/
3535 /* Use while loop until we've done 1 Megabyte */
3536 /**********************************************/
3537 while (count < 1048576) {
3538 cp = password_buf;
3539 if (passwordlen != 0) {
3540 for (i = 0; i < 64; i++) {
3541 /*************************************************/
3542 /* Take the next octet of the password, wrapping */
3543 /* to the beginning of the password as necessary.*/
3544 /*************************************************/
3545 *cp++ = password[password_index++ % passwordlen];
3547 } else {
3548 *cp = 0;
3550 gcry_md_write(hash_handle, password_buf, 64);
3551 count += 64;
3553 memcpy(key, gcry_md_read(hash_handle, 0), hash_len);
3554 gcry_md_close(hash_handle);
3556 /*****************************************************/
3557 /* Now localise the key with the engineID and pass */
3558 /* through hash function to produce final key */
3559 /* We ignore invalid engineLengths here. More strict */
3560 /* checking is done in snmp_users_update_cb. */
3561 /*****************************************************/
3562 if (gcry_md_open(&hash_handle, auth_hash_algo[model], 0)) {
3563 return;
3565 gcry_md_write(hash_handle, key, hash_len);
3566 gcry_md_write(hash_handle, engineID, engineLength);
3567 gcry_md_write(hash_handle, key, hash_len);
3568 memcpy(key, gcry_md_read(hash_handle, 0), hash_len);
3569 gcry_md_close(hash_handle);
3570 return;
3573 static void
3574 process_prefs(void)
3578 UAT_LSTRING_CB_DEF(snmp_users,userName,snmp_ue_assoc_t,user.userName.data,user.userName.len)
3579 UAT_LSTRING_CB_DEF(snmp_users,authPassword,snmp_ue_assoc_t,user.authPassword.data,user.authPassword.len)
3580 UAT_LSTRING_CB_DEF(snmp_users,privPassword,snmp_ue_assoc_t,user.privPassword.data,user.privPassword.len)
3581 UAT_BUFFER_CB_DEF(snmp_users,engine_id,snmp_ue_assoc_t,engine.data,engine.len)
3582 UAT_VS_DEF(snmp_users,auth_model,snmp_ue_assoc_t,unsigned,0,"MD5")
3583 UAT_VS_DEF(snmp_users,priv_proto,snmp_ue_assoc_t,unsigned,0,"DES")
3584 UAT_VS_DEF(snmp_users,priv_key_exp,snmp_ue_assoc_t,unsigned,0,"draft-reeder-snmpv3-usm-3desede-00")
3586 static void *
3587 snmp_specific_trap_copy_cb(void *dest, const void *orig, size_t len _U_)
3589 snmp_st_assoc_t *u = (snmp_st_assoc_t *)dest;
3590 const snmp_st_assoc_t *o = (const snmp_st_assoc_t *)orig;
3592 u->enterprise = g_strdup(o->enterprise);
3593 u->trap = o->trap;
3594 u->desc = g_strdup(o->desc);
3596 return dest;
3599 static void
3600 snmp_specific_trap_free_cb(void *r)
3602 snmp_st_assoc_t *u = (snmp_st_assoc_t *)r;
3604 g_free(u->enterprise);
3605 g_free(u->desc);
3608 UAT_CSTRING_CB_DEF(specific_traps, enterprise, snmp_st_assoc_t)
3609 UAT_DEC_CB_DEF(specific_traps, trap, snmp_st_assoc_t)
3610 UAT_CSTRING_CB_DEF(specific_traps, desc, snmp_st_assoc_t)
3612 /*--- proto_register_snmp -------------------------------------------*/
3613 void proto_register_snmp(void) {
3614 /* List of fields */
3615 static hf_register_info hf[] = {
3616 { &hf_snmp_response_in,
3617 { "Response In", "snmp.response_in", FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_RESPONSE), 0x0,
3618 "The response to this SNMP request is in this frame", HFILL }},
3619 { &hf_snmp_response_to,
3620 { "Response To", "snmp.response_to", FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_REQUEST), 0x0,
3621 "This is a response to the SNMP request in this frame", HFILL }},
3622 { &hf_snmp_time,
3623 { "Time", "snmp.time", FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0,
3624 "The time between the Request and the Response", HFILL }},
3625 { &hf_snmp_v3_flags_auth,
3626 { "Authenticated", "snmp.v3.flags.auth", FT_BOOLEAN, 8,
3627 TFS(&tfs_set_notset), TH_AUTH, NULL, HFILL }},
3628 { &hf_snmp_v3_flags_crypt,
3629 { "Encrypted", "snmp.v3.flags.crypt", FT_BOOLEAN, 8,
3630 TFS(&tfs_set_notset), TH_CRYPT, NULL, HFILL }},
3631 { &hf_snmp_v3_flags_report,
3632 { "Reportable", "snmp.v3.flags.report", FT_BOOLEAN, 8,
3633 TFS(&tfs_set_notset), TH_REPORT, NULL, HFILL }},
3634 { &hf_snmp_engineid_conform, {
3635 "Engine ID Conformance", "snmp.engineid.conform", FT_BOOLEAN, 8,
3636 TFS(&tfs_snmp_engineid_conform), F_SNMP_ENGINEID_CONFORM, "Engine ID RFC3411 Conformance", HFILL }},
3637 { &hf_snmp_engineid_enterprise, {
3638 "Engine Enterprise ID", "snmp.engineid.enterprise", FT_UINT32, BASE_ENTERPRISES,
3639 STRINGS_ENTERPRISES, 0, NULL, HFILL }},
3640 { &hf_snmp_engineid_format, {
3641 "Engine ID Format", "snmp.engineid.format", FT_UINT8, BASE_DEC,
3642 VALS(snmp_engineid_format_vals), 0, NULL, HFILL }},
3643 { &hf_snmp_engineid_ipv4, {
3644 "Engine ID Data: IPv4 address", "snmp.engineid.ipv4", FT_IPv4, BASE_NONE,
3645 NULL, 0, NULL, HFILL }},
3646 { &hf_snmp_engineid_ipv6, {
3647 "Engine ID Data: IPv6 address", "snmp.engineid.ipv6", FT_IPv6, BASE_NONE,
3648 NULL, 0, NULL, HFILL }},
3649 { &hf_snmp_engineid_cisco_type, {
3650 "Engine ID Data: Cisco type", "snmp.engineid.cisco.type", FT_UINT8, BASE_HEX,
3651 VALS(snmp_engineid_cisco_type_vals), 0, NULL, HFILL }},
3652 { &hf_snmp_engineid_mac, {
3653 "Engine ID Data: MAC address", "snmp.engineid.mac", FT_ETHER, BASE_NONE,
3654 NULL, 0, NULL, HFILL }},
3655 { &hf_snmp_engineid_text, {
3656 "Engine ID Data: Text", "snmp.engineid.text", FT_STRING, BASE_NONE,
3657 NULL, 0, NULL, HFILL }},
3658 { &hf_snmp_engineid_time, {
3659 "Engine ID Data: Creation Time", "snmp.engineid.time", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL,
3660 NULL, 0, NULL, HFILL }},
3661 { &hf_snmp_engineid_data, {
3662 "Engine ID Data", "snmp.engineid.data", FT_BYTES, BASE_NONE,
3663 NULL, 0, NULL, HFILL }},
3664 { &hf_snmp_msgAuthentication, {
3665 "Authentication", "snmp.v3.auth", FT_BOOLEAN, BASE_NONE,
3666 TFS(&auth_flags), 0, NULL, HFILL }},
3667 { &hf_snmp_decryptedPDU, {
3668 "Decrypted ScopedPDU", "snmp.decrypted_pdu", FT_BYTES, BASE_NONE,
3669 NULL, 0, "Decrypted PDU", HFILL }},
3670 { &hf_snmp_noSuchObject, {
3671 "noSuchObject", "snmp.noSuchObject", FT_NONE, BASE_NONE,
3672 NULL, 0, NULL, HFILL }},
3673 { &hf_snmp_noSuchInstance, {
3674 "noSuchInstance", "snmp.noSuchInstance", FT_NONE, BASE_NONE,
3675 NULL, 0, NULL, HFILL }},
3676 { &hf_snmp_endOfMibView, {
3677 "endOfMibView", "snmp.endOfMibView", FT_NONE, BASE_NONE,
3678 NULL, 0, NULL, HFILL }},
3679 { &hf_snmp_unSpecified, {
3680 "unSpecified", "snmp.unSpecified", FT_NONE, BASE_NONE,
3681 NULL, 0, NULL, HFILL }},
3683 { &hf_snmp_integer32_value, {
3684 "Value (Integer32)", "snmp.value.int", FT_INT64, BASE_DEC,
3685 NULL, 0, NULL, HFILL }},
3686 { &hf_snmp_octetstring_value, {
3687 "Value (OctetString)", "snmp.value.octets", FT_BYTES, BASE_SHOW_ASCII_PRINTABLE,
3688 NULL, 0, NULL, HFILL }},
3689 { &hf_snmp_oid_value, {
3690 "Value (OID)", "snmp.value.oid", FT_OID, BASE_NONE,
3691 NULL, 0, NULL, HFILL }},
3692 { &hf_snmp_null_value, {
3693 "Value (Null)", "snmp.value.null", FT_NONE, BASE_NONE,
3694 NULL, 0, NULL, HFILL }},
3695 { &hf_snmp_ipv4_value, {
3696 "Value (IpAddress)", "snmp.value.ipv4", FT_IPv4, BASE_NONE,
3697 NULL, 0, NULL, HFILL }},
3698 { &hf_snmp_ipv6_value, {
3699 "Value (IpAddress)", "snmp.value.ipv6", FT_IPv6, BASE_NONE,
3700 NULL, 0, NULL, HFILL }},
3701 { &hf_snmp_anyaddress_value, {
3702 "Value (IpAddress)", "snmp.value.addr", FT_BYTES, BASE_NONE,
3703 NULL, 0, NULL, HFILL }},
3704 { &hf_snmp_unsigned32_value, {
3705 "Value (Unsigned32)", "snmp.value.u32", FT_INT64, BASE_DEC,
3706 NULL, 0, NULL, HFILL }},
3707 { &hf_snmp_gauge32_value, {
3708 "Value (Gauge32)", "snmp.value.g32", FT_INT64, BASE_DEC,
3709 NULL, 0, NULL, HFILL }},
3710 { &hf_snmp_unknown_value, {
3711 "Value (Unknown)", "snmp.value.unk", FT_BYTES, BASE_NONE,
3712 NULL, 0, NULL, HFILL }},
3713 { &hf_snmp_counter_value, {
3714 "Value (Counter32)", "snmp.value.counter", FT_UINT64, BASE_DEC,
3715 NULL, 0, NULL, HFILL }},
3716 { &hf_snmp_big_counter_value, {
3717 "Value (Counter64)", "snmp.value.counter", FT_UINT64, BASE_DEC,
3718 NULL, 0, NULL, HFILL }},
3719 { &hf_snmp_nsap_value, {
3720 "Value (NSAP)", "snmp.value.nsap", FT_UINT64, BASE_DEC,
3721 NULL, 0, NULL, HFILL }},
3722 { &hf_snmp_timeticks_value, {
3723 "Value (Timeticks)", "snmp.value.timeticks", FT_UINT64, BASE_DEC,
3724 NULL, 0, NULL, HFILL }},
3725 { &hf_snmp_opaque_value, {
3726 "Value (Opaque)", "snmp.value.opaque", FT_BYTES, BASE_NONE,
3727 NULL, 0, NULL, HFILL }},
3728 { &hf_snmp_objectname, {
3729 "Object Name", "snmp.name", FT_OID, BASE_NONE,
3730 NULL, 0, NULL, HFILL }},
3731 { &hf_snmp_scalar_instance_index, {
3732 "Scalar Instance Index", "snmp.name.index", FT_UINT64, BASE_DEC,
3733 NULL, 0, NULL, HFILL }},
3734 { &hf_snmp_var_bind_str, {
3735 "Variable-binding-string", "snmp.var-bind_str", FT_STRING, BASE_NONE,
3736 NULL, 0, NULL, HFILL }},
3737 { &hf_snmp_agentid_trailer, {
3738 "AgentID Trailer", "snmp.agentid_trailer", FT_BYTES, BASE_NONE,
3739 NULL, 0, NULL, HFILL }},
3742 { &hf_snmp_SMUX_PDUs_PDU,
3743 { "SMUX-PDUs", "snmp.SMUX_PDUs",
3744 FT_UINT32, BASE_DEC, VALS(snmp_SMUX_PDUs_vals), 0,
3745 NULL, HFILL }},
3746 { &hf_snmp_version,
3747 { "version", "snmp.version",
3748 FT_INT32, BASE_DEC, VALS(snmp_Version_vals), 0,
3749 NULL, HFILL }},
3750 { &hf_snmp_community,
3751 { "community", "snmp.community",
3752 FT_STRING, BASE_NONE, NULL, 0,
3753 NULL, HFILL }},
3754 { &hf_snmp_data,
3755 { "data", "snmp.data",
3756 FT_UINT32, BASE_DEC, VALS(snmp_PDUs_vals), 0,
3757 "PDUs", HFILL }},
3758 { &hf_snmp_parameters,
3759 { "parameters", "snmp.parameters",
3760 FT_BYTES, BASE_NONE, NULL, 0,
3761 "OCTET_STRING", HFILL }},
3762 { &hf_snmp_datav2u,
3763 { "datav2u", "snmp.datav2u",
3764 FT_UINT32, BASE_DEC, VALS(snmp_T_datav2u_vals), 0,
3765 NULL, HFILL }},
3766 { &hf_snmp_v2u_plaintext,
3767 { "plaintext", "snmp.plaintext",
3768 FT_UINT32, BASE_DEC, VALS(snmp_PDUs_vals), 0,
3769 "PDUs", HFILL }},
3770 { &hf_snmp_encrypted,
3771 { "encrypted", "snmp.encrypted",
3772 FT_BYTES, BASE_NONE, NULL, 0,
3773 "OCTET_STRING", HFILL }},
3774 { &hf_snmp_msgAuthoritativeEngineID,
3775 { "msgAuthoritativeEngineID", "snmp.msgAuthoritativeEngineID",
3776 FT_BYTES, BASE_NONE, NULL, 0,
3777 NULL, HFILL }},
3778 { &hf_snmp_msgAuthoritativeEngineBoots,
3779 { "msgAuthoritativeEngineBoots", "snmp.msgAuthoritativeEngineBoots",
3780 FT_UINT32, BASE_DEC, NULL, 0,
3781 NULL, HFILL }},
3782 { &hf_snmp_msgAuthoritativeEngineTime,
3783 { "msgAuthoritativeEngineTime", "snmp.msgAuthoritativeEngineTime",
3784 FT_UINT32, BASE_DEC, NULL, 0,
3785 NULL, HFILL }},
3786 { &hf_snmp_msgUserName,
3787 { "msgUserName", "snmp.msgUserName",
3788 FT_STRING, BASE_NONE, NULL, 0,
3789 NULL, HFILL }},
3790 { &hf_snmp_msgAuthenticationParameters,
3791 { "msgAuthenticationParameters", "snmp.msgAuthenticationParameters",
3792 FT_BYTES, BASE_NONE, NULL, 0,
3793 NULL, HFILL }},
3794 { &hf_snmp_msgPrivacyParameters,
3795 { "msgPrivacyParameters", "snmp.msgPrivacyParameters",
3796 FT_BYTES, BASE_NONE, NULL, 0,
3797 NULL, HFILL }},
3798 { &hf_snmp_msgVersion,
3799 { "msgVersion", "snmp.msgVersion",
3800 FT_INT32, BASE_DEC, VALS(snmp_Version_vals), 0,
3801 "Version", HFILL }},
3802 { &hf_snmp_msgGlobalData,
3803 { "msgGlobalData", "snmp.msgGlobalData_element",
3804 FT_NONE, BASE_NONE, NULL, 0,
3805 "HeaderData", HFILL }},
3806 { &hf_snmp_msgSecurityParameters,
3807 { "msgSecurityParameters", "snmp.msgSecurityParameters",
3808 FT_BYTES, BASE_NONE, NULL, 0,
3809 NULL, HFILL }},
3810 { &hf_snmp_msgData,
3811 { "msgData", "snmp.msgData",
3812 FT_UINT32, BASE_DEC, VALS(snmp_ScopedPduData_vals), 0,
3813 "ScopedPduData", HFILL }},
3814 { &hf_snmp_msgID,
3815 { "msgID", "snmp.msgID",
3816 FT_UINT32, BASE_DEC, NULL, 0,
3817 "INTEGER_0_2147483647", HFILL }},
3818 { &hf_snmp_msgMaxSize,
3819 { "msgMaxSize", "snmp.msgMaxSize",
3820 FT_UINT32, BASE_DEC, NULL, 0,
3821 "INTEGER_484_2147483647", HFILL }},
3822 { &hf_snmp_msgFlags,
3823 { "msgFlags", "snmp.msgFlags",
3824 FT_BYTES, BASE_NONE, NULL, 0,
3825 NULL, HFILL }},
3826 { &hf_snmp_msgSecurityModel,
3827 { "msgSecurityModel", "snmp.msgSecurityModel",
3828 FT_UINT32, BASE_DEC, VALS(sec_models), 0,
3829 NULL, HFILL }},
3830 { &hf_snmp_plaintext,
3831 { "plaintext", "snmp.plaintext_element",
3832 FT_NONE, BASE_NONE, NULL, 0,
3833 "ScopedPDU", HFILL }},
3834 { &hf_snmp_encryptedPDU,
3835 { "encryptedPDU", "snmp.encryptedPDU",
3836 FT_BYTES, BASE_NONE, NULL, 0,
3837 NULL, HFILL }},
3838 { &hf_snmp_contextEngineID,
3839 { "contextEngineID", "snmp.contextEngineID",
3840 FT_BYTES, BASE_NONE, NULL, 0,
3841 "SnmpEngineID", HFILL }},
3842 { &hf_snmp_contextName,
3843 { "contextName", "snmp.contextName",
3844 FT_STRING, BASE_NONE, NULL, 0,
3845 "OCTET_STRING", HFILL }},
3846 { &hf_snmp_get_request,
3847 { "get-request", "snmp.get_request_element",
3848 FT_NONE, BASE_NONE, NULL, 0,
3849 "GetRequest_PDU", HFILL }},
3850 { &hf_snmp_get_next_request,
3851 { "get-next-request", "snmp.get_next_request_element",
3852 FT_NONE, BASE_NONE, NULL, 0,
3853 "GetNextRequest_PDU", HFILL }},
3854 { &hf_snmp_get_response,
3855 { "get-response", "snmp.get_response_element",
3856 FT_NONE, BASE_NONE, NULL, 0,
3857 "GetResponse_PDU", HFILL }},
3858 { &hf_snmp_set_request,
3859 { "set-request", "snmp.set_request_element",
3860 FT_NONE, BASE_NONE, NULL, 0,
3861 "SetRequest_PDU", HFILL }},
3862 { &hf_snmp_trap,
3863 { "trap", "snmp.trap_element",
3864 FT_NONE, BASE_NONE, NULL, 0,
3865 "Trap_PDU", HFILL }},
3866 { &hf_snmp_getBulkRequest,
3867 { "getBulkRequest", "snmp.getBulkRequest_element",
3868 FT_NONE, BASE_NONE, NULL, 0,
3869 "GetBulkRequest_PDU", HFILL }},
3870 { &hf_snmp_informRequest,
3871 { "informRequest", "snmp.informRequest_element",
3872 FT_NONE, BASE_NONE, NULL, 0,
3873 "InformRequest_PDU", HFILL }},
3874 { &hf_snmp_snmpV2_trap,
3875 { "snmpV2-trap", "snmp.snmpV2_trap_element",
3876 FT_NONE, BASE_NONE, NULL, 0,
3877 "SNMPv2_Trap_PDU", HFILL }},
3878 { &hf_snmp_report,
3879 { "report", "snmp.report_element",
3880 FT_NONE, BASE_NONE, NULL, 0,
3881 "Report_PDU", HFILL }},
3882 { &hf_snmp_request_id,
3883 { "request-id", "snmp.request_id",
3884 FT_INT32, BASE_DEC, NULL, 0,
3885 "T_request_id", HFILL }},
3886 { &hf_snmp_error_status,
3887 { "error-status", "snmp.error_status",
3888 FT_INT32, BASE_DEC, VALS(snmp_T_error_status_vals), 0,
3889 NULL, HFILL }},
3890 { &hf_snmp_error_index,
3891 { "error-index", "snmp.error_index",
3892 FT_INT32, BASE_DEC, NULL, 0,
3893 "INTEGER", HFILL }},
3894 { &hf_snmp_variable_bindings,
3895 { "variable-bindings", "snmp.variable_bindings",
3896 FT_UINT32, BASE_DEC, NULL, 0,
3897 "VarBindList", HFILL }},
3898 { &hf_snmp_bulkPDU_request_id,
3899 { "request-id", "snmp.request_id",
3900 FT_INT32, BASE_DEC, NULL, 0,
3901 "Integer32", HFILL }},
3902 { &hf_snmp_non_repeaters,
3903 { "non-repeaters", "snmp.non_repeaters",
3904 FT_UINT32, BASE_DEC, NULL, 0,
3905 "INTEGER_0_2147483647", HFILL }},
3906 { &hf_snmp_max_repetitions,
3907 { "max-repetitions", "snmp.max_repetitions",
3908 FT_UINT32, BASE_DEC, NULL, 0,
3909 "INTEGER_0_2147483647", HFILL }},
3910 { &hf_snmp_enterprise,
3911 { "enterprise", "snmp.enterprise",
3912 FT_OID, BASE_NONE, NULL, 0,
3913 "EnterpriseOID", HFILL }},
3914 { &hf_snmp_agent_addr,
3915 { "agent-addr", "snmp.agent_addr",
3916 FT_IPv4, BASE_NONE, NULL, 0,
3917 "NetworkAddress", HFILL }},
3918 { &hf_snmp_generic_trap,
3919 { "generic-trap", "snmp.generic_trap",
3920 FT_INT32, BASE_DEC, VALS(snmp_GenericTrap_vals), 0,
3921 "GenericTrap", HFILL }},
3922 { &hf_snmp_specific_trap,
3923 { "specific-trap", "snmp.specific_trap",
3924 FT_INT32, BASE_DEC, NULL, 0,
3925 "SpecificTrap", HFILL }},
3926 { &hf_snmp_time_stamp,
3927 { "time-stamp", "snmp.time_stamp",
3928 FT_UINT32, BASE_DEC, NULL, 0,
3929 "TimeTicks", HFILL }},
3930 { &hf_snmp_name,
3931 { "name", "snmp.name",
3932 FT_OID, BASE_NONE, NULL, 0,
3933 "ObjectName", HFILL }},
3934 { &hf_snmp_valueType,
3935 { "valueType", "snmp.valueType_element",
3936 FT_NONE, BASE_NONE, NULL, 0,
3937 NULL, HFILL }},
3938 { &hf_snmp_VarBindList_item,
3939 { "VarBind", "snmp.VarBind_element",
3940 FT_NONE, BASE_NONE, NULL, 0,
3941 NULL, HFILL }},
3942 { &hf_snmp_open,
3943 { "open", "snmp.open",
3944 FT_UINT32, BASE_DEC, VALS(snmp_OpenPDU_vals), 0,
3945 "OpenPDU", HFILL }},
3946 { &hf_snmp_close,
3947 { "close", "snmp.close",
3948 FT_INT32, BASE_DEC, VALS(snmp_ClosePDU_U_vals), 0,
3949 "ClosePDU", HFILL }},
3950 { &hf_snmp_registerRequest,
3951 { "registerRequest", "snmp.registerRequest_element",
3952 FT_NONE, BASE_NONE, NULL, 0,
3953 "RReqPDU", HFILL }},
3954 { &hf_snmp_registerResponse,
3955 { "registerResponse", "snmp.registerResponse",
3956 FT_UINT32, BASE_DEC, VALS(snmp_RegisterResponse_vals), 0,
3957 NULL, HFILL }},
3958 { &hf_snmp_commitOrRollback,
3959 { "commitOrRollback", "snmp.commitOrRollback",
3960 FT_INT32, BASE_DEC, VALS(snmp_SOutPDU_U_vals), 0,
3961 "SOutPDU", HFILL }},
3962 { &hf_snmp_rRspPDU,
3963 { "rRspPDU", "snmp.rRspPDU",
3964 FT_INT32, BASE_DEC, VALS(snmp_RRspPDU_U_vals), 0,
3965 NULL, HFILL }},
3966 { &hf_snmp_pDUs,
3967 { "pDUs", "snmp.pDUs",
3968 FT_UINT32, BASE_DEC, VALS(snmp_PDUs_vals), 0,
3969 NULL, HFILL }},
3970 { &hf_snmp_smux_simple,
3971 { "smux-simple", "snmp.smux_simple_element",
3972 FT_NONE, BASE_NONE, NULL, 0,
3973 "SimpleOpen", HFILL }},
3974 { &hf_snmp_smux_version,
3975 { "smux-version", "snmp.smux_version",
3976 FT_INT32, BASE_DEC, VALS(snmp_T_smux_version_vals), 0,
3977 NULL, HFILL }},
3978 { &hf_snmp_identity,
3979 { "identity", "snmp.identity",
3980 FT_OID, BASE_NONE, NULL, 0,
3981 "OBJECT_IDENTIFIER", HFILL }},
3982 { &hf_snmp_description,
3983 { "description", "snmp.description",
3984 FT_BYTES, BASE_NONE, NULL, 0,
3985 "DisplayString", HFILL }},
3986 { &hf_snmp_password,
3987 { "password", "snmp.password",
3988 FT_BYTES, BASE_NONE, NULL, 0,
3989 "OCTET_STRING", HFILL }},
3990 { &hf_snmp_subtree,
3991 { "subtree", "snmp.subtree",
3992 FT_OID, BASE_NONE, NULL, 0,
3993 "ObjectName", HFILL }},
3994 { &hf_snmp_priority,
3995 { "priority", "snmp.priority",
3996 FT_INT32, BASE_DEC, NULL, 0,
3997 "INTEGER_M1_2147483647", HFILL }},
3998 { &hf_snmp_operation,
3999 { "operation", "snmp.operation",
4000 FT_INT32, BASE_DEC, VALS(snmp_T_operation_vals), 0,
4001 NULL, HFILL }},
4004 /* List of subtrees */
4005 static int *ett[] = {
4006 &ett_snmp,
4007 &ett_engineid,
4008 &ett_msgFlags,
4009 &ett_encryptedPDU,
4010 &ett_decrypted,
4011 &ett_authParameters,
4012 &ett_internet,
4013 &ett_varbind,
4014 &ett_name,
4015 &ett_value,
4016 &ett_decoding_error,
4017 &ett_snmp_Message,
4018 &ett_snmp_Messagev2u,
4019 &ett_snmp_T_datav2u,
4020 &ett_snmp_UsmSecurityParameters,
4021 &ett_snmp_SNMPv3Message,
4022 &ett_snmp_HeaderData,
4023 &ett_snmp_ScopedPduData,
4024 &ett_snmp_ScopedPDU,
4025 &ett_snmp_PDUs,
4026 &ett_snmp_PDU,
4027 &ett_snmp_BulkPDU,
4028 &ett_snmp_Trap_PDU_U,
4029 &ett_snmp_VarBind,
4030 &ett_snmp_VarBindList,
4031 &ett_snmp_SMUX_PDUs,
4032 &ett_snmp_RegisterResponse,
4033 &ett_snmp_OpenPDU,
4034 &ett_snmp_SimpleOpen_U,
4035 &ett_snmp_RReqPDU_U,
4037 static ei_register_info ei[] = {
4038 { &ei_snmp_failed_decrypted_data_pdu, { "snmp.failed_decrypted_data_pdu", PI_MALFORMED, PI_WARN, "Failed to decrypt encryptedPDU", EXPFILL }},
4039 { &ei_snmp_decrypted_data_bad_formatted, { "snmp.decrypted_data_bad_formatted", PI_MALFORMED, PI_WARN, "Decrypted data not formatted as expected, wrong key?", EXPFILL }},
4040 { &ei_snmp_verify_authentication_error, { "snmp.verify_authentication_error", PI_MALFORMED, PI_ERROR, "Error while verifying Message authenticity", EXPFILL }},
4041 { &ei_snmp_authentication_ok, { "snmp.authentication_ok", PI_CHECKSUM, PI_CHAT, "SNMP Authentication OK", EXPFILL }},
4042 { &ei_snmp_authentication_error, { "snmp.authentication_error", PI_CHECKSUM, PI_WARN, "SNMP Authentication Error", EXPFILL }},
4043 { &ei_snmp_varbind_not_uni_class_seq, { "snmp.varbind.not_uni_class_seq", PI_MALFORMED, PI_WARN, "VarBind is not an universal class sequence", EXPFILL }},
4044 { &ei_snmp_varbind_has_indicator, { "snmp.varbind.has_indicator", PI_MALFORMED, PI_WARN, "VarBind has indicator set", EXPFILL }},
4045 { &ei_snmp_objectname_not_oid, { "snmp.objectname_not_oid", PI_MALFORMED, PI_WARN, "ObjectName not an OID", EXPFILL }},
4046 { &ei_snmp_objectname_has_indicator, { "snmp.objectname_has_indicator", PI_MALFORMED, PI_WARN, "ObjectName has indicator set", EXPFILL }},
4047 { &ei_snmp_value_not_primitive_encoding, { "snmp.value_not_primitive_encoding", PI_MALFORMED, PI_WARN, "value not in primitive encoding", EXPFILL }},
4048 { &ei_snmp_invalid_oid, { "snmp.invalid_oid", PI_MALFORMED, PI_WARN, "invalid oid", EXPFILL }},
4049 { &ei_snmp_varbind_wrong_tag, { "snmp.varbind.wrong_tag", PI_MALFORMED, PI_WARN, "Wrong tag for SNMP VarBind error value", EXPFILL }},
4050 { &ei_snmp_varbind_response, { "snmp.varbind.response", PI_RESPONSE_CODE, PI_NOTE, "Response", EXPFILL }},
4051 { &ei_snmp_no_instance_subid, { "snmp.no_instance_subid", PI_MALFORMED, PI_WARN, "No instance sub-id in scalar value", EXPFILL }},
4052 { &ei_snmp_wrong_num_of_subids, { "snmp.wrong_num_of_subids", PI_MALFORMED, PI_WARN, "Wrong number of instance sub-ids in scalar value", EXPFILL }},
4053 { &ei_snmp_index_suboid_too_short, { "snmp.index_suboid_too_short", PI_MALFORMED, PI_WARN, "index sub-oid shorter than expected", EXPFILL }},
4054 { &ei_snmp_unimplemented_instance_index, { "snmp.unimplemented_instance_index", PI_UNDECODED, PI_WARN, "OID instances not handled, if you want this implemented please contact the wireshark developers", EXPFILL }},
4055 { &ei_snmp_index_suboid_len0, { "snmp.ndex_suboid_len0", PI_MALFORMED, PI_WARN, "an index sub-oid OID cannot be 0 bytes long!", EXPFILL }},
4056 { &ei_snmp_index_suboid_too_long, { "snmp.index_suboid_too_long", PI_MALFORMED, PI_WARN, "index sub-oid should not be longer than remaining oid size", EXPFILL }},
4057 { &ei_snmp_index_string_too_long, { "snmp.index_string_too_long", PI_MALFORMED, PI_WARN, "index string should not be longer than remaining oid size", EXPFILL }},
4058 { &ei_snmp_column_parent_not_row, { "snmp.column_parent_not_row", PI_MALFORMED, PI_ERROR, "COLUMNS's parent is not a ROW", EXPFILL }},
4059 { &ei_snmp_uint_too_large, { "snmp.uint_too_large", PI_UNDECODED, PI_NOTE, "Unsigned integer value > 2^64 - 1", EXPFILL }},
4060 { &ei_snmp_int_too_large, { "snmp.int_too_large", PI_UNDECODED, PI_NOTE, "Signed integer value > 2^63 - 1 or <= -2^63", EXPFILL }},
4061 { &ei_snmp_integral_value0, { "snmp.integral_value0", PI_UNDECODED, PI_NOTE, "Integral value is zero-length", EXPFILL }},
4062 { &ei_snmp_missing_mib, { "snmp.missing_mib", PI_UNDECODED, PI_NOTE, "Unresolved value, Missing MIB", EXPFILL }},
4063 { &ei_snmp_varbind_wrong_length_value, { "snmp.varbind.wrong_length_value", PI_MALFORMED, PI_WARN, "Wrong length for SNMP VarBind/value", EXPFILL }},
4064 { &ei_snmp_varbind_wrong_class_tag, { "snmp.varbind.wrong_class_tag", PI_MALFORMED, PI_WARN, "Wrong class/tag for SNMP VarBind/value", EXPFILL }},
4065 { &ei_snmp_rfc1910_non_conformant, { "snmp.rfc1910_non_conformant", PI_PROTOCOL, PI_WARN, "Data not conforming to RFC1910", EXPFILL }},
4066 { &ei_snmp_rfc3411_non_conformant, { "snmp.rfc3411_non_conformant", PI_PROTOCOL, PI_WARN, "Data not conforming to RFC3411", EXPFILL }},
4067 { &ei_snmp_version_unknown, { "snmp.version.unknown", PI_PROTOCOL, PI_WARN, "Unknown version", EXPFILL }},
4068 { &ei_snmp_trap_pdu_obsolete, { "snmp.trap_pdu_obsolete", PI_PROTOCOL, PI_WARN, "Trap-PDU is obsolete in this SNMP version", EXPFILL }},
4072 expert_module_t* expert_snmp;
4073 module_t *snmp_module;
4075 static uat_field_t users_fields[] = {
4076 UAT_FLD_BUFFER(snmp_users,engine_id,"Engine ID","Engine-id for this entry (empty = any)"),
4077 UAT_FLD_LSTRING(snmp_users,userName,"Username","The username"),
4078 UAT_FLD_VS(snmp_users,auth_model,"Authentication model",auth_types,"Algorithm to be used for authentication."),
4079 UAT_FLD_LSTRING(snmp_users,authPassword,"Password","The password used for authenticating packets for this entry"),
4080 UAT_FLD_VS(snmp_users,priv_proto,"Privacy protocol",priv_types,"Algorithm to be used for privacy."),
4081 UAT_FLD_LSTRING(snmp_users,privPassword,"Privacy password","The password used for encrypting packets for this entry"),
4082 UAT_FLD_VS(snmp_users,priv_key_exp,"Key expansion method",priv_key_exp_types,"Privacy protocol key expansion method"),
4083 UAT_END_FIELDS
4086 uat_t *assocs_uat = uat_new("SNMP Users",
4087 sizeof(snmp_ue_assoc_t),
4088 "snmp_users",
4089 true,
4090 &ueas,
4091 &num_ueas,
4092 UAT_AFFECTS_DISSECTION, /* affects dissection of packets, but not set of named fields */
4093 "ChSNMPUsersSection",
4094 snmp_users_copy_cb,
4095 snmp_users_update_cb,
4096 snmp_users_free_cb,
4097 renew_ue_cache,
4098 NULL,
4099 users_fields);
4101 static const char *assocs_uat_defaults[] = {
4102 NULL, NULL, NULL, NULL, NULL, NULL, "draft-reeder-snmpv3-usm-3desede-00"};
4103 uat_set_default_values(assocs_uat, assocs_uat_defaults);
4105 static uat_field_t specific_traps_flds[] = {
4106 UAT_FLD_CSTRING(specific_traps,enterprise,"Enterprise OID","Enterprise Object Identifier"),
4107 UAT_FLD_DEC(specific_traps,trap,"Trap Id","The specific-trap value"),
4108 UAT_FLD_CSTRING(specific_traps,desc,"Description","Trap type description"),
4109 UAT_END_FIELDS
4112 uat_t* specific_traps_uat = uat_new("SNMP Enterprise Specific Trap Types",
4113 sizeof(snmp_st_assoc_t),
4114 "snmp_specific_traps",
4115 true,
4116 &specific_traps,
4117 &num_specific_traps,
4118 UAT_AFFECTS_DISSECTION, /* affects dissection of packets, but not set of named fields */
4119 "ChSNMPEnterpriseSpecificTrapTypes",
4120 snmp_specific_trap_copy_cb,
4121 NULL,
4122 snmp_specific_trap_free_cb,
4123 NULL,
4124 NULL,
4125 specific_traps_flds);
4127 /* Register protocol */
4128 proto_snmp = proto_register_protocol(PNAME, PSNAME, PFNAME);
4129 snmp_handle = register_dissector("snmp", dissect_snmp, proto_snmp);
4131 /* Register fields and subtrees */
4132 proto_register_field_array(proto_snmp, hf, array_length(hf));
4133 proto_register_subtree_array(ett, array_length(ett));
4134 expert_snmp = expert_register_protocol(proto_snmp);
4135 expert_register_field_array(expert_snmp, ei, array_length(ei));
4137 /* Register dissector */
4138 snmp_tcp_handle = register_dissector("snmp.tcp", dissect_snmp_tcp, proto_snmp);
4140 /* Register configuration preferences */
4141 snmp_module = prefs_register_protocol(proto_snmp, process_prefs);
4142 prefs_register_bool_preference(snmp_module, "display_oid",
4143 "Show SNMP OID in info column",
4144 "Whether the SNMP OID should be shown in the info column",
4145 &display_oid);
4147 prefs_register_obsolete_preference(snmp_module, "mib_modules");
4148 prefs_register_obsolete_preference(snmp_module, "users_file");
4150 prefs_register_bool_preference(snmp_module, "desegment",
4151 "Reassemble SNMP-over-TCP messages spanning multiple TCP segments",
4152 "Whether the SNMP dissector should reassemble messages spanning multiple TCP segments."
4153 " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
4154 &snmp_desegment);
4156 prefs_register_bool_preference(snmp_module, "var_in_tree",
4157 "Display dissected variables inside SNMP tree",
4158 "ON - display dissected variables inside SNMP tree, OFF - display dissected variables in root tree after SNMP",
4159 &snmp_var_in_tree);
4161 prefs_register_uat_preference(snmp_module, "users_table",
4162 "Users Table",
4163 "Table of engine-user associations used for authentication and decryption",
4164 assocs_uat);
4166 prefs_register_uat_preference(snmp_module, "specific_traps_table",
4167 "Enterprise Specific Trap Types",
4168 "Table of enterprise specific-trap type descriptions",
4169 specific_traps_uat);
4171 #ifdef HAVE_LIBSMI
4172 prefs_register_static_text_preference(snmp_module, "info_mibs",
4173 "MIB settings can be changed in the Name Resolution preferences",
4174 "MIB settings can be changed in the Name Resolution preferences");
4175 #endif
4177 value_sub_dissectors_table = register_dissector_table("snmp.variable_oid","SNMP Variable OID", proto_snmp, FT_STRING, STRING_CASE_SENSITIVE);
4179 register_init_routine(init_ue_cache);
4180 register_cleanup_routine(cleanup_ue_cache);
4182 register_ber_syntax_dissector("SNMP", proto_snmp, dissect_snmp_tcp);
4184 snmp_tap=register_tap("snmp");
4186 register_srt_table(proto_snmp, NULL, 1, snmpstat_packet, snmpstat_init, NULL);
4190 /*--- proto_reg_handoff_snmp ---------------------------------------*/
4191 void proto_reg_handoff_snmp(void) {
4193 dissector_add_uint_with_preference("udp.port", UDP_PORT_SNMP, snmp_handle);
4194 dissector_add_uint("ethertype", ETHERTYPE_SNMP, snmp_handle);
4195 dissector_add_uint("ipx.socket", IPX_SOCKET_SNMP_AGENT, snmp_handle);
4196 dissector_add_uint("ipx.socket", IPX_SOCKET_SNMP_SINK, snmp_handle);
4197 dissector_add_uint("hpext.dxsap", HPEXT_SNMP, snmp_handle);
4199 dissector_add_uint_with_preference("tcp.port", TCP_PORT_SNMP, snmp_tcp_handle);
4200 /* Since "regular" SNMP port and "trap" SNMP port use the same handler,
4201 the "trap" port doesn't really need a separate preference. Just register
4202 normally */
4203 dissector_add_uint("tcp.port", TCP_PORT_SNMP_TRAP, snmp_tcp_handle);
4204 dissector_add_uint("udp.port", UDP_PORT_SNMP_TRAP, snmp_handle);
4205 dissector_add_uint("udp.port", UDP_PORT_SNMP_PATROL, snmp_handle);
4207 data_handle = find_dissector("data");
4209 /* SNMPv2-MIB sysDescr "1.3.6.1.2.1.1.1.0" */
4210 dissector_add_string("snmp.variable_oid", "1.3.6.1.2.1.1.1.0",
4211 create_dissector_handle(dissect_snmp_variable_string, proto_snmp));
4212 /* SNMPv2-MIB::sysName.0 (1.3.6.1.2.1.1.5.0) */
4213 dissector_add_string("snmp.variable_oid", "1.3.6.1.2.1.1.5.0",
4214 create_dissector_handle(dissect_snmp_variable_string, proto_snmp));
4217 * Process preference settings.
4219 * We can't do this in the register routine, as preferences aren't
4220 * read until all dissector register routines have been called (so
4221 * that all dissector preferences have been registered).
4223 process_prefs();
4227 void
4228 proto_register_smux(void)
4230 static int *ett[] = {
4231 &ett_smux,
4234 proto_smux = proto_register_protocol("SNMP Multiplex Protocol",
4235 "SMUX", "smux");
4237 proto_register_subtree_array(ett, array_length(ett));
4239 smux_handle = register_dissector("smux", dissect_smux, proto_smux);
4242 void
4243 proto_reg_handoff_smux(void)
4245 dissector_add_uint_with_preference("tcp.port", TCP_PORT_SMUX, smux_handle);
4249 * Editor modelines - https://www.wireshark.org/tools/modelines.html
4251 * Local variables:
4252 * c-basic-offset: 8
4253 * tab-width: 8
4254 * indent-tabs-mode: t
4255 * End:
4257 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
4258 * :indentSize=8:tabSize=8:noTabs=false: