2 * Routines for SNMP (simple network management protocol)
3 * Copyright (C) 1998 Didier Jorand
5 * See RFC 1157 for SNMPv1.
7 * See RFCs 1901, 1905, and 1906 for SNMPv2c.
9 * See RFCs 1905, 1906, 1909, and 1910 for SNMPv2u [historic].
11 * See RFCs 2570-2576 for SNMPv3
12 * Updated to use the asn2wrs compiler made by Tomas Kukosa
13 * Copyright (C) 2005 - 2006 Anders Broman [AT] ericsson.com
15 * See RFC 3414 for User-based Security Model for SNMPv3
16 * See RFC 3826 for (AES) Cipher Algorithm in the SNMP USM
17 * See RFC 2578 for Structure of Management Information Version 2 (SMIv2)
18 * Copyright (C) 2007 Luis E. Garcia Ontanon <luis@ontanon.org>
20 * Wireshark - Network traffic analyzer
21 * By Gerald Combs <gerald@wireshark.org>
22 * Copyright 1998 Gerald Combs
26 * GXSNMP -- An snmp mangament application
27 * Copyright (C) 1998 Gregory McLean & Jochen Friedrich
28 * Beholder RMON ethernet network monitor,Copyright (C) 1993 DNPAP group
30 * SPDX-License-Identifier: GPL-2.0-or-later
35 #define D(args) do {printf args; fflush(stdout); } while(0)
40 #include <epan/packet.h>
41 #include <epan/strutil.h>
42 #include <epan/conversation.h>
43 #include <epan/etypes.h>
44 #include <epan/prefs.h>
45 #include <epan/addr_resolv.h>
46 #include <epan/next_tvb.h>
48 #include <epan/asn1.h>
49 #include <epan/expert.h>
50 #include <epan/oids.h>
51 #include "packet-ipx.h"
52 #include "packet-hpext.h"
53 #include "packet-ber.h"
54 #include "packet-snmp.h"
55 #include <wsutil/wsgcrypt.h>
57 #define PNAME "Simple Network Management Protocol"
61 #define UDP_PORT_SNMP 161
62 #define UDP_PORT_SNMP_TRAP 162
63 #define TCP_PORT_SNMP 161
64 #define TCP_PORT_SNMP_TRAP 162
65 #define TCP_PORT_SMUX 199
66 #define UDP_PORT_SNMP_PATROL 8161
68 /* Initialize the protocol and registered fields */
69 static int proto_snmp = -1;
70 static int proto_smux = -1;
72 static gboolean display_oid = TRUE;
73 static gboolean snmp_var_in_tree = TRUE;
75 void proto_register_snmp(void);
76 void proto_reg_handoff_snmp(void);
77 void proto_register_smux(void);
78 void proto_reg_handoff_smux(void);
80 static void snmp_usm_password_to_key(const snmp_usm_auth_model_t model, const guint8 *password, guint passwordlen,
81 const guint8 *engineID, guint engineLength, guint8 *key);
83 static tvbuff_t* snmp_usm_priv_des(snmp_usm_params_t*, tvbuff_t*, packet_info *pinfo, gchar const**);
84 static tvbuff_t* snmp_usm_priv_aes128(snmp_usm_params_t*, tvbuff_t*, packet_info *pinfo, gchar const**);
85 static tvbuff_t* snmp_usm_priv_aes192(snmp_usm_params_t*, tvbuff_t*, packet_info *pinfo, gchar const**);
86 static tvbuff_t* snmp_usm_priv_aes256(snmp_usm_params_t*, tvbuff_t*, packet_info *pinfo, gchar const**);
88 static gboolean snmp_usm_auth(const snmp_usm_auth_model_t model, snmp_usm_params_t* p, guint8**, guint*, gchar const**);
90 static const value_string auth_types[] = {
91 {SNMP_USM_AUTH_MD5,"MD5"},
92 {SNMP_USM_AUTH_SHA1,"SHA1"},
93 {SNMP_USM_AUTH_SHA2_224,"SHA2-224"},
94 {SNMP_USM_AUTH_SHA2_256,"SHA2-256"},
95 {SNMP_USM_AUTH_SHA2_384,"SHA2-384"},
96 {SNMP_USM_AUTH_SHA2_512,"SHA2-512"},
100 static const guint auth_hash_len[] = {
103 HASH_SHA2_224_LENGTH,
104 HASH_SHA2_256_LENGTH,
105 HASH_SHA2_384_LENGTH,
109 static const guint auth_tag_len[] = {
118 static const enum gcry_md_algos auth_hash_algo[] = {
128 #define PRIV_AES128 1
129 #define PRIV_AES192 2
130 #define PRIV_AES256 3
132 static const value_string priv_types[] = {
134 { PRIV_AES128, "AES" },
135 { PRIV_AES192, "AES192" },
136 { PRIV_AES256, "AES256" },
139 static snmp_usm_decoder_t priv_protos[] = {
141 snmp_usm_priv_aes128,
142 snmp_usm_priv_aes192,
146 static snmp_ue_assoc_t* ueas = NULL;
147 static guint num_ueas = 0;
148 static snmp_ue_assoc_t* localized_ues = NULL;
149 static snmp_ue_assoc_t* unlocalized_ues = NULL;
152 /* Variables used for handling enterprise specific trap types */
153 typedef struct _snmp_st_assoc_t {
158 static guint num_specific_traps = 0;
159 static snmp_st_assoc_t *specific_traps = NULL;
160 static const char *enterprise_oid = NULL;
161 static guint generic_trap = 0;
162 static guint32 snmp_version = 0;
164 static snmp_usm_params_t usm_p = {FALSE,FALSE,0,0,0,0,NULL,NULL,NULL,NULL,NULL,NULL,NULL,FALSE};
167 #define TH_CRYPT 0x02
168 #define TH_REPORT 0x04
170 /* desegmentation of SNMP-over-TCP */
171 static gboolean snmp_desegment = TRUE;
173 /* Global variables */
175 guint32 MsgSecurityModel;
176 tvbuff_t *oid_tvb=NULL;
177 tvbuff_t *value_tvb=NULL;
179 static dissector_handle_t snmp_handle;
180 static dissector_handle_t data_handle;
182 static next_tvb_list_t var_list;
184 static int hf_snmp_v3_flags_auth = -1;
185 static int hf_snmp_v3_flags_crypt = -1;
186 static int hf_snmp_v3_flags_report = -1;
188 static int hf_snmp_engineid_conform = -1;
189 static int hf_snmp_engineid_enterprise = -1;
190 static int hf_snmp_engineid_format = -1;
191 static int hf_snmp_engineid_ipv4 = -1;
192 static int hf_snmp_engineid_ipv6 = -1;
193 static int hf_snmp_engineid_cisco_type = -1;
194 static int hf_snmp_engineid_mac = -1;
195 static int hf_snmp_engineid_text = -1;
196 static int hf_snmp_engineid_time = -1;
197 static int hf_snmp_engineid_data = -1;
198 static int hf_snmp_decryptedPDU = -1;
199 static int hf_snmp_msgAuthentication = -1;
201 static int hf_snmp_noSuchObject = -1;
202 static int hf_snmp_noSuchInstance = -1;
203 static int hf_snmp_endOfMibView = -1;
204 static int hf_snmp_unSpecified = -1;
206 static int hf_snmp_integer32_value = -1;
207 static int hf_snmp_octetstring_value = -1;
208 static int hf_snmp_oid_value = -1;
209 static int hf_snmp_null_value = -1;
210 static int hf_snmp_ipv4_value = -1;
211 static int hf_snmp_ipv6_value = -1;
212 static int hf_snmp_anyaddress_value = -1;
213 static int hf_snmp_unsigned32_value = -1;
214 static int hf_snmp_unknown_value = -1;
215 static int hf_snmp_opaque_value = -1;
216 static int hf_snmp_nsap_value = -1;
217 static int hf_snmp_counter_value = -1;
218 static int hf_snmp_timeticks_value = -1;
219 static int hf_snmp_big_counter_value = -1;
220 static int hf_snmp_gauge32_value = -1;
222 static int hf_snmp_objectname = -1;
223 static int hf_snmp_scalar_instance_index = -1;
225 static int hf_snmp_var_bind_str = -1;
226 static int hf_snmp_agentid_trailer = -1;
228 #include "packet-snmp-hf.c"
230 /* Initialize the subtree pointers */
231 static gint ett_smux = -1;
232 static gint ett_snmp = -1;
233 static gint ett_engineid = -1;
234 static gint ett_msgFlags = -1;
235 static gint ett_encryptedPDU = -1;
236 static gint ett_decrypted = -1;
237 static gint ett_authParameters = -1;
238 static gint ett_internet = -1;
239 static gint ett_varbind = -1;
240 static gint ett_name = -1;
241 static gint ett_value = -1;
242 static gint ett_decoding_error = -1;
244 #include "packet-snmp-ett.c"
246 static expert_field ei_snmp_failed_decrypted_data_pdu = EI_INIT;
247 static expert_field ei_snmp_decrypted_data_bad_formatted = EI_INIT;
248 static expert_field ei_snmp_verify_authentication_error = EI_INIT;
249 static expert_field ei_snmp_authentication_ok = EI_INIT;
250 static expert_field ei_snmp_authentication_error = EI_INIT;
251 static expert_field ei_snmp_varbind_not_uni_class_seq = EI_INIT;
252 static expert_field ei_snmp_varbind_has_indicator = EI_INIT;
253 static expert_field ei_snmp_objectname_not_oid = EI_INIT;
254 static expert_field ei_snmp_objectname_has_indicator = EI_INIT;
255 static expert_field ei_snmp_value_not_primitive_encoding = EI_INIT;
256 static expert_field ei_snmp_invalid_oid = EI_INIT;
257 static expert_field ei_snmp_varbind_wrong_tag = EI_INIT;
258 static expert_field ei_snmp_varbind_response = EI_INIT;
259 static expert_field ei_snmp_no_instance_subid = EI_INIT;
260 static expert_field ei_snmp_wrong_num_of_subids = EI_INIT;
261 static expert_field ei_snmp_index_suboid_too_short = EI_INIT;
262 static expert_field ei_snmp_unimplemented_instance_index = EI_INIT;
263 static expert_field ei_snmp_index_suboid_len0 = EI_INIT;
264 static expert_field ei_snmp_index_suboid_too_long = EI_INIT;
265 static expert_field ei_snmp_index_string_too_long = EI_INIT;
266 static expert_field ei_snmp_column_parent_not_row = EI_INIT;
267 static expert_field ei_snmp_uint_too_large = EI_INIT;
268 static expert_field ei_snmp_int_too_large = EI_INIT;
269 static expert_field ei_snmp_integral_value0 = EI_INIT;
270 static expert_field ei_snmp_missing_mib = EI_INIT;
271 static expert_field ei_snmp_varbind_wrong_length_value = EI_INIT;
272 static expert_field ei_snmp_varbind_wrong_class_tag = EI_INIT;
273 static expert_field ei_snmp_rfc1910_non_conformant = EI_INIT;
274 static expert_field ei_snmp_rfc3411_non_conformant = EI_INIT;
275 static expert_field ei_snmp_version_unknown = EI_INIT;
276 static expert_field ei_snmp_trap_pdu_obsolete = EI_INIT;
278 static const true_false_string auth_flags = {
283 /* Security Models */
285 #define SNMP_SEC_ANY 0
286 #define SNMP_SEC_V1 1
287 #define SNMP_SEC_V2C 2
288 #define SNMP_SEC_USM 3
290 static const value_string sec_models[] = {
291 { SNMP_SEC_ANY, "Any" },
292 { SNMP_SEC_V1, "V1" },
293 { SNMP_SEC_V2C, "V2C" },
294 { SNMP_SEC_USM, "USM" },
300 #define SMUX_MSG_OPEN 0
301 #define SMUX_MSG_CLOSE 1
302 #define SMUX_MSG_RREQ 2
303 #define SMUX_MSG_RRSP 3
304 #define SMUX_MSG_SOUT 4
306 static const value_string smux_types[] = {
307 { SMUX_MSG_OPEN, "Open" },
308 { SMUX_MSG_CLOSE, "Close" },
309 { SMUX_MSG_RREQ, "Registration Request" },
310 { SMUX_MSG_RRSP, "Registration Response" },
311 { SMUX_MSG_SOUT, "Commit Or Rollback" },
317 #define SNMP_IPA 0 /* IP Address */
318 #define SNMP_CNT 1 /* Counter (Counter32) */
319 #define SNMP_GGE 2 /* Gauge (Gauge32) */
320 #define SNMP_TIT 3 /* TimeTicks */
321 #define SNMP_OPQ 4 /* Opaque */
322 #define SNMP_NSP 5 /* NsapAddress */
323 #define SNMP_C64 6 /* Counter64 */
324 #define SNMP_U32 7 /* Uinteger32 */
331 dissector_table_t value_sub_dissectors_table;
335 snmp_lookup_specific_trap (guint specific_trap)
339 for (i = 0; i < num_specific_traps; i++) {
340 snmp_st_assoc_t *u = &(specific_traps[i]);
342 if ((u->trap == specific_trap) &&
343 (strcmp (u->enterprise, enterprise_oid) == 0))
353 dissect_snmp_variable_string(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void *data _U_)
356 proto_tree_add_item(tree, hf_snmp_var_bind_str, tvb, 0, -1, ENC_ASCII|ENC_NA);
358 return tvb_captured_length(tvb);
362 DateAndTime ::= TEXTUAL-CONVENTION
363 DISPLAY-HINT "2d-1d-1d,1d:1d:1d.1d,1a1d:1d"
366 "A date-time specification.
368 field octets contents range
369 ----- ------ -------- -----
376 (use 60 for leap-second)
377 7 8 deci-seconds 0..9
378 8 9 direction from UTC '+' / '-'
379 9 10 hours from UTC* 0..13
380 10 11 minutes from UTC 0..59
383 - the value of year is in network-byte order
384 - daylight saving time in New Zealand is +13
386 For example, Tuesday May 26, 1992 at 1:30:15 PM EDT would be
389 1992-5-26,13:30:15.0,-4:0
391 Note that if only local time is known, then timezone
392 information (fields 8-10) is not present."
393 SYNTAX OCTET STRING (SIZE (8 | 11))
396 dissect_snmp_variable_date_and_time(proto_tree *tree,int hfid, tvbuff_t *tvb, int offset, int length)
405 guint8 hour_from_utc;
409 year = tvb_get_ntohs(tvb,offset);
410 month = tvb_get_guint8(tvb,offset+2);
411 day = tvb_get_guint8(tvb,offset+3);
412 hour = tvb_get_guint8(tvb,offset+4);
413 minutes = tvb_get_guint8(tvb,offset+5);
414 seconds = tvb_get_guint8(tvb,offset+6);
415 deci_seconds = tvb_get_guint8(tvb,offset+7);
417 hour_from_utc = tvb_get_guint8(tvb,offset+9);
418 min_from_utc = tvb_get_guint8(tvb,offset+10);
420 str = wmem_strdup_printf(wmem_packet_scope(),
421 "%u-%u-%u, %u:%u:%u.%u UTC %s%u:%u",
429 tvb_get_string_enc(wmem_packet_scope(),tvb,offset+8,1,ENC_ASCII|ENC_NA),
433 str = wmem_strdup_printf(wmem_packet_scope(),
434 "%u-%u-%u, %u:%u:%u.%u",
444 return proto_tree_add_string(tree, hfid, tvb, offset, length, str);
449 * dissect_snmp_VarBind
450 * this routine dissects variable bindings, looking for the oid information in our oid reporsitory
451 * to format and add the value adequatelly.
453 * The choice to handwrite this code instead of using the asn compiler is to avoid having tons
454 * of uses of global variables distributed in very different parts of the code.
455 * Other than that there's a cosmetic thing: the tree from ASN generated code would be so
456 * convoluted due to the nesting of CHOICEs in the definition of VarBind/value.
458 * XXX: the length of this function (~400 lines) is an aberration!
459 * oid_key_t:key_type could become a series of callbacks instead of an enum
460 * the (! oid_info_is_ok) switch could be made into an array (would be slower)
463 NetworkAddress ::= CHOICE { internet IpAddress }
464 IpAddress ::= [APPLICATION 0] IMPLICIT OCTET STRING (SIZE (4))
465 TimeTicks ::= [APPLICATION 3] IMPLICIT INTEGER (0..4294967295)
466 Integer32 ::= INTEGER (-2147483648..2147483647)
467 ObjectName ::= OBJECT IDENTIFIER
468 Counter32 ::= [APPLICATION 1] IMPLICIT INTEGER (0..4294967295)
469 Gauge32 ::= [APPLICATION 2] IMPLICIT INTEGER (0..4294967295)
470 Unsigned32 ::= [APPLICATION 2] IMPLICIT INTEGER (0..4294967295)
471 Integer-value ::= INTEGER (-2147483648..2147483647)
472 Integer32 ::= INTEGER (-2147483648..2147483647)
473 ObjectID-value ::= OBJECT IDENTIFIER
475 TimeTicks ::= [APPLICATION 3] IMPLICIT INTEGER (0..4294967295)
476 Opaque ::= [APPLICATION 4] IMPLICIT OCTET STRING
477 Counter64 ::= [APPLICATION 6] IMPLICIT INTEGER (0..18446744073709551615)
479 ObjectSyntax ::= CHOICE {
481 application-wide ApplicationSyntax
484 SimpleSyntax ::= CHOICE {
485 integer-value Integer-value,
486 string-value String-value,
487 objectID-value ObjectID-value,
491 ApplicationSyntax ::= CHOICE {
492 ipAddress-value IpAddress,
493 counter-value Counter32,
494 timeticks-value TimeTicks,
495 arbitrary-value Opaque,
496 big-counter-value Counter64,
497 unsigned-integer-value Unsigned32
500 ValueType ::= CHOICE {
503 noSuchObject[0] IMPLICIT NULL,
504 noSuchInstance[1] IMPLICIT NULL,
505 endOfMibView[2] IMPLICIT NULL
508 VarBind ::= SEQUENCE {
516 dissect_snmp_VarBind(gboolean implicit_tag _U_, tvbuff_t *tvb, int offset,
517 asn1_ctx_t *actx, proto_tree *tree, int hf_index _U_)
519 int seq_offset, name_offset, value_offset, value_start;
520 guint32 seq_len, name_len, value_len;
527 oid_info_t* oid_info = NULL;
528 guint oid_matched, oid_left;
529 proto_item *pi_name, *pi_varbind, *pi_value = NULL;
530 proto_tree *pt, *pt_varbind, *pt_name, *pt_value;
531 char label[ITEM_LABEL_LENGTH];
532 const char* repr = NULL;
533 const char* info_oid = NULL;
536 int min_len = 0, max_len = 0;
537 gboolean oid_info_is_ok;
538 const char* oid_string = NULL;
539 enum {BER_NO_ERROR, BER_WRONG_LENGTH, BER_WRONG_TAG} format_error = BER_NO_ERROR;
543 /* first have the VarBind's sequence header */
544 offset = dissect_ber_identifier(actx->pinfo, tree, tvb, offset, &ber_class, &pc, &tag);
545 offset = dissect_ber_length(actx->pinfo, tree, tvb, offset, &seq_len, &ind);
547 if (!pc && ber_class==BER_CLASS_UNI && tag==BER_UNI_TAG_SEQUENCE) {
549 pt = proto_tree_add_subtree(tree, tvb, seq_offset, seq_len + (offset - seq_offset),
550 ett_decoding_error, &pi, "VarBind must be an universal class sequence");
551 expert_add_info(actx->pinfo, pi, &ei_snmp_varbind_not_uni_class_seq);
552 return dissect_unknown_ber(actx->pinfo, tvb, seq_offset, pt);
557 pt = proto_tree_add_subtree(tree, tvb, seq_offset, seq_len + (offset - seq_offset),
558 ett_decoding_error, &pi, "Indicator must be clear in VarBind");
559 expert_add_info(actx->pinfo, pi, &ei_snmp_varbind_has_indicator);
560 return dissect_unknown_ber(actx->pinfo, tvb, seq_offset, pt);
563 /* we add the varbind tree root with a dummy label we'll fill later on */
564 pt_varbind = proto_tree_add_subtree(tree,tvb,offset,seq_len,ett_varbind,&pi_varbind,"VarBind");
567 seq_len += offset - seq_offset;
569 /* then we have the ObjectName's header */
571 offset = dissect_ber_identifier(actx->pinfo, pt_varbind, tvb, offset, &ber_class, &pc, &tag);
572 name_offset = offset = dissect_ber_length(actx->pinfo, pt_varbind, tvb, offset, &name_len, &ind);
574 if (! ( !pc && ber_class==BER_CLASS_UNI && tag==BER_UNI_TAG_OID) ) {
576 pt = proto_tree_add_subtree(tree, tvb, seq_offset, seq_len,
577 ett_decoding_error, &pi, "ObjectName must be an OID in primitive encoding");
578 expert_add_info(actx->pinfo, pi, &ei_snmp_objectname_not_oid);
579 return dissect_unknown_ber(actx->pinfo, tvb, seq_offset, pt);
584 pt = proto_tree_add_subtree(tree, tvb, seq_offset, seq_len,
585 ett_decoding_error, &pi, "Indicator must be clear in ObjectName");
586 expert_add_info(actx->pinfo, pi, &ei_snmp_objectname_has_indicator);
587 return dissect_unknown_ber(actx->pinfo, tvb, seq_offset, pt);
590 pi_name = proto_tree_add_item(pt_varbind,hf_snmp_objectname,tvb,name_offset,name_len,ENC_NA);
591 pt_name = proto_item_add_subtree(pi_name,ett_name);
594 value_start = offset;
595 /* then we have the value's header */
596 offset = dissect_ber_identifier(actx->pinfo, pt_varbind, tvb, offset, &ber_class, &pc, &tag);
597 value_offset = dissect_ber_length(actx->pinfo, pt_varbind, tvb, offset, &value_len, &ind);
601 pt = proto_tree_add_subtree(pt_varbind, tvb, value_start, value_len,
602 ett_decoding_error, &pi, "the value must be in primitive encoding");
603 expert_add_info(actx->pinfo, pi, &ei_snmp_value_not_primitive_encoding);
604 return dissect_unknown_ber(actx->pinfo, tvb, value_start, pt);
607 /* Now, we know where everithing is */
609 /* fetch ObjectName and its relative oid_info */
610 oid_bytes = (guint8*)tvb_memdup(wmem_packet_scope(), tvb, name_offset, name_len);
611 oid_info = oid_get_from_encoded(wmem_packet_scope(), oid_bytes, name_len, &subids, &oid_matched, &oid_left);
613 add_oid_debug_subtree(oid_info,pt_name);
618 repr = oid_encoded2string(wmem_packet_scope(), oid_bytes, name_len);
619 pt = proto_tree_add_subtree_format(pt_name,tvb, 0, 0, ett_decoding_error, &pi, "invalid oid: %s", repr);
620 expert_add_info_format(actx->pinfo, pi, &ei_snmp_invalid_oid, "invalid oid: %s", repr);
621 return dissect_unknown_ber(actx->pinfo, tvb, name_offset, pt);
624 if (oid_matched+oid_left) {
625 oid_string = oid_subid2string(wmem_packet_scope(), subids,oid_matched+oid_left);
628 if (ber_class == BER_CLASS_CON) {
629 /* if we have an error value just add it and get out the way ASAP */
633 if (value_len != 0) {
634 min_len = max_len = 0;
635 format_error = BER_WRONG_LENGTH;
640 hfid = hf_snmp_noSuchObject;
641 note = "noSuchObject";
644 hfid = hf_snmp_noSuchInstance;
645 note = "noSuchInstance";
648 hfid = hf_snmp_endOfMibView;
649 note = "endOfMibView";
652 pt = proto_tree_add_subtree_format(pt_varbind,tvb,0,0,ett_decoding_error,&pi,
653 "Wrong tag for Error Value: expected 0, 1, or 2 but got: %d",tag);
654 expert_add_info(actx->pinfo, pi, &ei_snmp_varbind_wrong_tag);
655 return dissect_unknown_ber(actx->pinfo, tvb, value_start, pt);
659 pi = proto_tree_add_item(pt_varbind,hfid,tvb,value_offset,value_len,ENC_BIG_ENDIAN);
660 expert_add_info_format(actx->pinfo, pi, &ei_snmp_varbind_response, "%s",note);
661 g_strlcpy (label, note, ITEM_LABEL_LENGTH);
665 /* 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 */
666 switch (oid_info->kind) {
667 case OID_KIND_SCALAR:
669 /* OK: we got the instance sub-id */
670 proto_tree_add_uint64(pt_name,hf_snmp_scalar_instance_index,tvb,name_offset,name_len,subids[oid_matched]);
671 oid_info_is_ok = TRUE;
673 } else if (oid_left == 0) {
674 if (ber_class == BER_CLASS_UNI && tag == BER_UNI_TAG_NULL) {
675 /* unSpecified does not require an instance sub-id add the new value and get off the way! */
676 pi_value = proto_tree_add_item(pt_varbind,hf_snmp_unSpecified,tvb,value_offset,value_len,ENC_NA);
679 proto_tree_add_expert(pt_name,actx->pinfo,&ei_snmp_no_instance_subid,tvb,0,0);
680 oid_info_is_ok = FALSE;
684 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);
685 oid_info_is_ok = FALSE;
689 case OID_KIND_COLUMN:
690 if ( oid_info->parent->kind == OID_KIND_ROW) {
691 oid_key_t* k = oid_info->parent->key;
692 guint key_start = oid_matched;
693 guint key_len = oid_left;
694 oid_info_is_ok = TRUE;
696 if ( key_len == 0 && ber_class == BER_CLASS_UNI && tag == BER_UNI_TAG_NULL) {
697 /* unSpecified does not require an instance sub-id add the new value and get off the way! */
698 pi_value = proto_tree_add_item(pt_varbind,hf_snmp_unSpecified,tvb,value_offset,value_len,ENC_NA);
703 for (;k;k = k->next) {
706 if (key_start >= oid_matched+oid_left) {
707 proto_tree_add_expert(pt_name,actx->pinfo,&ei_snmp_index_suboid_too_short,tvb,0,0);
708 oid_info_is_ok = FALSE;
712 switch(k->key_type) {
713 case OID_KEY_TYPE_WRONG: {
714 proto_tree_add_expert(pt_name,actx->pinfo,&ei_snmp_unimplemented_instance_index,tvb,0,0);
715 oid_info_is_ok = FALSE;
718 case OID_KEY_TYPE_INTEGER: {
719 if (IS_FT_INT(k->ft_type)) {
720 proto_tree_add_int(pt_name,k->hfid,tvb,name_offset,name_len,(guint)subids[key_start]);
721 } else { /* if it's not an unsigned int let proto_tree_add_uint throw a warning */
722 proto_tree_add_uint64(pt_name,k->hfid,tvb,name_offset,name_len,(guint)subids[key_start]);
726 continue; /* k->next */
728 case OID_KEY_TYPE_IMPLIED_OID:
729 suboid_len = key_len;
733 case OID_KEY_TYPE_OID: {
735 guint suboid_buf_len;
738 suboid_len = subids[key_start++];
742 suboid = &(subids[key_start]);
744 if( suboid_len == 0 ) {
745 proto_tree_add_expert(pt_name,actx->pinfo,&ei_snmp_index_suboid_len0,tvb,0,0);
746 oid_info_is_ok = FALSE;
750 if( key_len < suboid_len ) {
751 proto_tree_add_expert(pt_name,actx->pinfo,&ei_snmp_index_suboid_too_long,tvb,0,0);
752 oid_info_is_ok = FALSE;
756 suboid_buf_len = oid_subid2encoded(wmem_packet_scope(), suboid_len, suboid, &suboid_buf);
758 DISSECTOR_ASSERT(suboid_buf_len);
760 proto_tree_add_oid(pt_name,k->hfid,tvb,name_offset, suboid_buf_len, suboid_buf);
762 key_start += suboid_len;
763 key_len -= suboid_len + 1;
764 continue; /* k->next */
773 switch (k->key_type) {
774 case OID_KEY_TYPE_IPADDR:
775 suboid = &(subids[key_start]);
778 case OID_KEY_TYPE_IMPLIED_STRING:
779 case OID_KEY_TYPE_IMPLIED_BYTES:
780 case OID_KEY_TYPE_ETHER:
781 suboid = &(subids[key_start]);
785 buf_len = k->num_subids;
786 suboid = &(subids[key_start]);
796 if( key_len < buf_len ) {
797 proto_tree_add_expert(pt_name,actx->pinfo,&ei_snmp_index_string_too_long,tvb,0,0);
798 oid_info_is_ok = FALSE;
802 buf = (guint8*)wmem_alloc(wmem_packet_scope(), buf_len+1);
803 for (i = 0; i < buf_len; i++)
804 buf[i] = (guint8)suboid[i];
807 switch(k->key_type) {
808 case OID_KEY_TYPE_STRING:
809 case OID_KEY_TYPE_IMPLIED_STRING:
810 proto_tree_add_string(pt_name,k->hfid,tvb,name_offset,buf_len, buf);
812 case OID_KEY_TYPE_BYTES:
813 case OID_KEY_TYPE_NSAP:
814 case OID_KEY_TYPE_IMPLIED_BYTES:
815 proto_tree_add_bytes(pt_name,k->hfid,tvb,name_offset,buf_len, buf);
817 case OID_KEY_TYPE_ETHER:
818 proto_tree_add_ether(pt_name,k->hfid,tvb,name_offset,buf_len, buf);
820 case OID_KEY_TYPE_IPADDR: {
821 guint32* ipv4_p = (guint32*)buf;
822 proto_tree_add_ipv4(pt_name,k->hfid,tvb,name_offset,buf_len, *ipv4_p);
826 DISSECTOR_ASSERT_NOT_REACHED();
830 key_start += buf_len;
832 continue; /* k->next*/
838 proto_tree_add_expert(pt_name,actx->pinfo,&ei_snmp_unimplemented_instance_index,tvb,0,0);
839 oid_info_is_ok = FALSE;
843 proto_tree_add_expert(pt_name,actx->pinfo,&ei_snmp_column_parent_not_row,tvb,0,0);
844 oid_info_is_ok = FALSE;
848 /* proto_tree_add_expert (pt_name,actx->pinfo,PI_MALFORMED, PI_WARN,tvb,0,0,"This kind OID should have no value"); */
849 oid_info_is_ok = FALSE;
855 if (oid_info_is_ok && oid_info->value_type) {
856 if (ber_class == BER_CLASS_UNI && tag == BER_UNI_TAG_NULL) {
857 pi_value = proto_tree_add_item(pt_varbind,hf_snmp_unSpecified,tvb,value_offset,value_len,ENC_NA);
859 /* Provide a tree_item to attach errors to, if needed. */
862 if ((oid_info->value_type->ber_class != BER_CLASS_ANY) &&
863 (ber_class != oid_info->value_type->ber_class))
864 format_error = BER_WRONG_TAG;
865 else if ((oid_info->value_type->ber_tag != BER_TAG_ANY) &&
866 (tag != oid_info->value_type->ber_tag))
867 format_error = BER_WRONG_TAG;
869 max_len = oid_info->value_type->max_len == -1 ? 0xffffff : oid_info->value_type->max_len;
870 min_len = oid_info->value_type->min_len;
872 if ((int)value_len < min_len || (int)value_len > max_len)
873 format_error = BER_WRONG_LENGTH;
876 if (format_error == BER_NO_ERROR)
877 pi_value = proto_tree_add_item(pt_varbind,oid_info->value_hfid,tvb,value_offset,value_len,ENC_BIG_ENDIAN);
880 switch(ber_class|(tag<<4)) {
881 case BER_CLASS_UNI|(BER_UNI_TAG_INTEGER<<4):
884 unsigned int int_val_offset = value_offset;
887 max_len = 4; min_len = 1;
888 if (value_len > (guint)max_len || value_len < (guint)min_len) {
889 hfid = hf_snmp_integer32_value;
890 format_error = BER_WRONG_LENGTH;
895 /* extend sign bit */
896 if(tvb_get_guint8(tvb, int_val_offset)&0x80) {
899 for(i=0;i<value_len;i++) {
900 val=(val<<8)|tvb_get_guint8(tvb, int_val_offset);
904 pi_value = proto_tree_add_int64(pt_varbind, hf_snmp_integer32_value, tvb,value_offset,value_len, val);
908 case BER_CLASS_UNI|(BER_UNI_TAG_OCTETSTRING<<4):
909 if(oid_info->value_hfid> -1){
910 hfid = oid_info->value_hfid;
912 hfid = hf_snmp_octetstring_value;
915 case BER_CLASS_UNI|(BER_UNI_TAG_OID<<4):
916 max_len = -1; min_len = 1;
917 if (value_len < (guint)min_len) format_error = BER_WRONG_LENGTH;
918 hfid = hf_snmp_oid_value;
920 case BER_CLASS_UNI|(BER_UNI_TAG_NULL<<4):
921 max_len = 0; min_len = 0;
922 if (value_len != 0) format_error = BER_WRONG_LENGTH;
923 hfid = hf_snmp_null_value;
925 case BER_CLASS_APP: /* | (SNMP_IPA<<4)*/
927 case 4: hfid = hf_snmp_ipv4_value; break;
928 case 16: hfid = hf_snmp_ipv6_value; break;
929 default: hfid = hf_snmp_anyaddress_value; break;
932 case BER_CLASS_APP|(SNMP_U32<<4):
933 hfid = hf_snmp_unsigned32_value;
935 case BER_CLASS_APP|(SNMP_GGE<<4):
936 hfid = hf_snmp_gauge32_value;
938 case BER_CLASS_APP|(SNMP_CNT<<4):
939 hfid = hf_snmp_counter_value;
941 case BER_CLASS_APP|(SNMP_TIT<<4):
942 hfid = hf_snmp_timeticks_value;
944 case BER_CLASS_APP|(SNMP_OPQ<<4):
945 hfid = hf_snmp_opaque_value;
947 case BER_CLASS_APP|(SNMP_NSP<<4):
948 hfid = hf_snmp_nsap_value;
950 case BER_CLASS_APP|(SNMP_C64<<4):
951 hfid = hf_snmp_big_counter_value;
954 hfid = hf_snmp_unknown_value;
959 * Too long for an FT_UINT64 or an FT_INT64.
961 header_field_info *hfinfo = proto_registrar_get_nth(hfid);
962 if (hfinfo->type == FT_UINT64) {
964 * Check if this is an unsigned int64 with
967 if (value_len > 9 || tvb_get_guint8(tvb, value_offset) != 0) {
969 proto_tree_add_expert_format(pt_varbind,actx->pinfo,&ei_snmp_uint_too_large,tvb,value_offset,value_len,"Integral value too large");
972 /* Cheat and skip the leading 0 byte */
975 } else if (hfinfo->type == FT_INT64) {
977 * For now, just reject these.
979 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");
982 } else if (value_len == 0) {
984 * X.690 section 8.3.1 "Encoding of an integer value":
985 * "The encoding of an integer value shall be
986 * primitive. The contents octets shall consist of
987 * one or more octets."
989 * Zero is not "one or more".
991 header_field_info *hfinfo = proto_registrar_get_nth(hfid);
992 if (hfinfo->type == FT_UINT64 || hfinfo->type == FT_INT64) {
993 proto_tree_add_expert_format(pt_varbind,actx->pinfo,&ei_snmp_integral_value0,tvb,value_offset,value_len,"Integral value is zero-length");
997 /* Special case DATE AND TIME */
998 if((oid_info->value_type)&&(oid_info->value_type->keytype == OID_KEY_TYPE_DATE_AND_TIME)&&(value_len > 7)){
999 pi_value = dissect_snmp_variable_date_and_time(pt_varbind, hfid, tvb, value_offset, value_len);
1001 pi_value = proto_tree_add_item(pt_varbind,hfid,tvb,value_offset,value_len,ENC_BIG_ENDIAN);
1003 if (format_error != BER_NO_ERROR) {
1004 expert_add_info(actx->pinfo, pi_value, &ei_snmp_missing_mib);
1009 pt_value = proto_item_add_subtree(pi_value,ett_value);
1011 if (value_len > 0 && oid_string) {
1012 tvbuff_t* sub_tvb = tvb_new_subset_length(tvb, value_offset, value_len);
1014 next_tvb_add_string(&var_list, sub_tvb, (snmp_var_in_tree) ? pt_value : NULL, value_sub_dissectors_table, oid_string);
1019 if (pi_value) proto_item_fill_label(PITEM_FINFO(pi_value), label);
1021 if (oid_info && oid_info->name) {
1022 if (oid_left >= 1) {
1023 repr = wmem_strdup_printf(wmem_packet_scope(), "%s.%s (%s)", oid_info->name,
1024 oid_subid2string(wmem_packet_scope(), &(subids[oid_matched]),oid_left),
1025 oid_subid2string(wmem_packet_scope(), subids,oid_matched+oid_left));
1026 info_oid = wmem_strdup_printf(wmem_packet_scope(), "%s.%s", oid_info->name,
1027 oid_subid2string(wmem_packet_scope(), &(subids[oid_matched]),oid_left));
1029 repr = wmem_strdup_printf(wmem_packet_scope(), "%s (%s)", oid_info->name,
1030 oid_subid2string(wmem_packet_scope(), subids,oid_matched));
1031 info_oid = oid_info->name;
1033 } else if (oid_string) {
1034 repr = wmem_strdup(wmem_packet_scope(), oid_string);
1035 info_oid = oid_string;
1037 repr = wmem_strdup(wmem_packet_scope(), "[Bad OID]");
1040 valstr = strstr(label,": ");
1041 valstr = valstr ? valstr+2 : label;
1043 proto_item_set_text(pi_varbind,"%s: %s",repr,valstr);
1045 if (display_oid && info_oid) {
1046 col_append_fstr (actx->pinfo->cinfo, COL_INFO, " %s", info_oid);
1049 switch (format_error) {
1050 case BER_WRONG_LENGTH: {
1052 proto_tree* p_tree = proto_item_add_subtree(pi_value,ett_decoding_error);
1053 pt = proto_tree_add_subtree_format(p_tree,tvb,0,0,ett_decoding_error,&pi,
1054 "Wrong value length: %u expecting: %u <= len <= %u",
1055 value_len, min_len, max_len == -1 ? 0xFFFFFF : max_len);
1056 expert_add_info(actx->pinfo, pi, &ei_snmp_varbind_wrong_length_value);
1057 return dissect_unknown_ber(actx->pinfo, tvb, value_start, pt);
1059 case BER_WRONG_TAG: {
1061 proto_tree* p_tree = proto_item_add_subtree(pi_value,ett_decoding_error);
1062 pt = proto_tree_add_subtree_format(p_tree,tvb,0,0,ett_decoding_error,&pi,
1063 "Wrong class/tag for Value expected: %d,%d got: %d,%d",
1064 oid_info->value_type->ber_class, oid_info->value_type->ber_tag,
1066 expert_add_info(actx->pinfo, pi, &ei_snmp_varbind_wrong_class_tag);
1067 return dissect_unknown_ber(actx->pinfo, tvb, value_start, pt);
1073 return seq_offset + seq_len;
1077 #define F_SNMP_ENGINEID_CONFORM 0x80
1078 #define SNMP_ENGINEID_RFC1910 0x00
1079 #define SNMP_ENGINEID_RFC3411 0x01
1081 static const true_false_string tfs_snmp_engineid_conform = {
1083 "RFC1910 (Non-SNMPv3)"
1086 #define SNMP_ENGINEID_FORMAT_IPV4 0x01
1087 #define SNMP_ENGINEID_FORMAT_IPV6 0x02
1088 #define SNMP_ENGINEID_FORMAT_MACADDRESS 0x03
1089 #define SNMP_ENGINEID_FORMAT_TEXT 0x04
1090 #define SNMP_ENGINEID_FORMAT_OCTETS 0x05
1092 static const value_string snmp_engineid_format_vals[] = {
1093 { SNMP_ENGINEID_FORMAT_IPV4, "IPv4 address" },
1094 { SNMP_ENGINEID_FORMAT_IPV6, "IPv6 address" },
1095 { SNMP_ENGINEID_FORMAT_MACADDRESS, "MAC address" },
1096 { SNMP_ENGINEID_FORMAT_TEXT, "Text, administratively assigned" },
1097 { SNMP_ENGINEID_FORMAT_OCTETS, "Octets, administratively assigned" },
1101 #define SNMP_ENGINEID_CISCO_AGENT 0x00
1102 #define SNMP_ENGINEID_CISCO_MANAGER 0x01
1104 static const value_string snmp_engineid_cisco_type_vals[] = {
1105 { SNMP_ENGINEID_CISCO_AGENT, "Agent" },
1106 { SNMP_ENGINEID_CISCO_MANAGER, "Manager" },
1111 * SNMP Engine ID dissection according to RFC 3411 (SnmpEngineID TC)
1112 * or historic RFC 1910 (AgentID)
1115 dissect_snmp_engineid(proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb, int offset, int len)
1117 proto_item *item = NULL;
1118 guint8 conformance, format;
1119 guint32 enterpriseid, seconds;
1121 int len_remain = len;
1123 /* first bit: engine id conformance */
1124 if (len_remain<1) return offset;
1125 conformance = ((tvb_get_guint8(tvb, offset)>>7) & 0x01);
1126 proto_tree_add_item(tree, hf_snmp_engineid_conform, tvb, offset, 1, ENC_BIG_ENDIAN);
1128 /* 4-byte enterprise number/name */
1129 if (len_remain<4) return offset;
1130 enterpriseid = tvb_get_ntohl(tvb, offset);
1132 enterpriseid -= 0x80000000; /* ignore first bit */
1133 proto_tree_add_uint(tree, hf_snmp_engineid_enterprise, tvb, offset, 4, enterpriseid);
1137 switch(conformance) {
1139 case SNMP_ENGINEID_RFC1910:
1140 /* 12-byte AgentID w/ 8-byte trailer */
1141 if (len_remain==8) {
1142 proto_tree_add_item(tree, hf_snmp_agentid_trailer, tvb, offset, 8, ENC_NA);
1146 proto_tree_add_expert(tree, pinfo, &ei_snmp_rfc1910_non_conformant, tvb, offset, len_remain);
1151 case SNMP_ENGINEID_RFC3411: /* variable length: 5..32 */
1153 /* 1-byte format specifier */
1154 if (len_remain<1) return offset;
1155 format = tvb_get_guint8(tvb, offset);
1156 item = proto_tree_add_uint_format(tree, hf_snmp_engineid_format, tvb, offset, 1, format, "Engine ID Format: %s (%d)",
1157 val_to_str(format, snmp_engineid_format_vals, "Reserved/Enterprise-specific"), format);
1162 case SNMP_ENGINEID_FORMAT_IPV4:
1163 /* 4-byte IPv4 address */
1164 if (len_remain==4) {
1165 proto_tree_add_item(tree, hf_snmp_engineid_ipv4, tvb, offset, 4, ENC_BIG_ENDIAN);
1170 case SNMP_ENGINEID_FORMAT_IPV6:
1171 /* 16-byte IPv6 address */
1172 if (len_remain==16) {
1173 proto_tree_add_item(tree, hf_snmp_engineid_ipv6, tvb, offset, 16, ENC_NA);
1178 case SNMP_ENGINEID_FORMAT_MACADDRESS:
1179 /* See: https://supportforums.cisco.com/message/3010617#3010617 for details. */
1180 if ((enterpriseid==9)&&(len_remain==7)) {
1181 proto_tree_add_item(tree, hf_snmp_engineid_cisco_type, tvb, offset, 1, ENC_BIG_ENDIAN);
1185 /* 6-byte MAC address */
1186 if (len_remain==6) {
1187 proto_tree_add_item(tree, hf_snmp_engineid_mac, tvb, offset, 6, ENC_NA);
1192 case SNMP_ENGINEID_FORMAT_TEXT:
1193 /* max. 27-byte string, administratively assigned */
1194 if (len_remain<=27) {
1195 proto_tree_add_item(tree, hf_snmp_engineid_text, tvb, offset, len_remain, ENC_ASCII|ENC_NA);
1201 /* most common enterprise-specific format: (ucd|net)-snmp random */
1202 if ((enterpriseid==2021)||(enterpriseid==8072)) {
1203 proto_item_append_text(item, (enterpriseid==2021) ? ": UCD-SNMP Random" : ": Net-SNMP Random");
1204 /* demystify: 4B random, 4B epoch seconds */
1205 if (len_remain==8) {
1206 proto_tree_add_item(tree, hf_snmp_engineid_data, tvb, offset, 4, ENC_NA);
1207 seconds = tvb_get_letohl(tvb, offset+4);
1210 proto_tree_add_time_format_value(tree, hf_snmp_engineid_time, tvb, offset+4, 4,
1212 abs_time_secs_to_str(wmem_packet_scope(), seconds, ABSOLUTE_TIME_LOCAL, TRUE));
1219 case SNMP_ENGINEID_FORMAT_OCTETS:
1221 /* max. 27 bytes, administratively assigned or unknown format */
1222 if (len_remain<=27) {
1223 proto_tree_add_item(tree, hf_snmp_engineid_data, tvb, offset, len_remain, ENC_NA);
1232 proto_tree_add_expert(tree, pinfo, &ei_snmp_rfc3411_non_conformant, tvb, offset, len_remain);
1239 static void set_ue_keys(snmp_ue_assoc_t* n ) {
1240 guint key_size = auth_hash_len[n->user.authModel];
1242 n->user.authKey.data = (guint8 *)g_malloc(key_size);
1243 n->user.authKey.len = key_size;
1244 snmp_usm_password_to_key(n->user.authModel,
1245 n->user.authPassword.data,
1246 n->user.authPassword.len,
1249 n->user.authKey.data);
1251 if (n->priv_proto == PRIV_AES128 || n->priv_proto == PRIV_AES192 || n->priv_proto == PRIV_AES256) {
1252 guint need_key_len =
1253 (n->priv_proto == PRIV_AES128) ? 16 :
1254 (n->priv_proto == PRIV_AES192) ? 24 :
1255 (n->priv_proto == PRIV_AES256) ? 32 :
1258 guint key_len = key_size;
1260 while (key_len < need_key_len)
1261 key_len += key_size;
1263 n->user.privKey.data = (guint8 *)g_malloc(key_len);
1264 n->user.privKey.len = need_key_len;
1266 snmp_usm_password_to_key(n->user.authModel,
1267 n->user.privPassword.data,
1268 n->user.privPassword.len,
1271 n->user.privKey.data);
1275 /* extend key if needed */
1276 while (key_len < need_key_len) {
1277 snmp_usm_password_to_key(n->user.authModel,
1278 n->user.privKey.data,
1282 n->user.privKey.data + key_len);
1284 key_len += key_size;
1288 n->user.privKey.data = (guint8 *)g_malloc(key_size);
1289 n->user.privKey.len = key_size;
1290 snmp_usm_password_to_key(n->user.authModel,
1291 n->user.privPassword.data,
1292 n->user.privPassword.len,
1295 n->user.privKey.data);
1299 static snmp_ue_assoc_t*
1300 ue_dup(snmp_ue_assoc_t* o)
1302 snmp_ue_assoc_t* d = (snmp_ue_assoc_t*)g_memdup(o,sizeof(snmp_ue_assoc_t));
1304 d->user.authModel = o->user.authModel;
1306 d->user.privProtocol = o->user.privProtocol;
1308 d->user.userName.data = (guint8 *)g_memdup(o->user.userName.data,o->user.userName.len);
1309 d->user.userName.len = o->user.userName.len;
1311 d->user.authPassword.data = o->user.authPassword.data ? (guint8 *)g_memdup(o->user.authPassword.data,o->user.authPassword.len) : NULL;
1312 d->user.authPassword.len = o->user.authPassword.len;
1314 d->user.privPassword.data = o->user.privPassword.data ? (guint8 *)g_memdup(o->user.privPassword.data,o->user.privPassword.len) : NULL;
1315 d->user.privPassword.len = o->user.privPassword.len;
1317 d->engine.len = o->engine.len;
1319 if (d->engine.len) {
1320 d->engine.data = (guint8 *)g_memdup(o->engine.data,o->engine.len);
1329 snmp_users_copy_cb(void* dest, const void* orig, size_t len _U_)
1331 const snmp_ue_assoc_t* o = (const snmp_ue_assoc_t*)orig;
1332 snmp_ue_assoc_t* d = (snmp_ue_assoc_t*)dest;
1334 d->auth_model = o->auth_model;
1335 d->user.authModel = (snmp_usm_auth_model_t) o->auth_model;
1337 d->priv_proto = o->priv_proto;
1338 d->user.privProtocol = priv_protos[o->priv_proto];
1340 d->user.userName.data = (guint8*)g_memdup(o->user.userName.data,o->user.userName.len);
1341 d->user.userName.len = o->user.userName.len;
1343 d->user.authPassword.data = o->user.authPassword.data ? (guint8*)g_memdup(o->user.authPassword.data,o->user.authPassword.len) : NULL;
1344 d->user.authPassword.len = o->user.authPassword.len;
1346 d->user.privPassword.data = o->user.privPassword.data ? (guint8*)g_memdup(o->user.privPassword.data,o->user.privPassword.len) : NULL;
1347 d->user.privPassword.len = o->user.privPassword.len;
1349 d->engine.len = o->engine.len;
1350 if (o->engine.data) {
1351 d->engine.data = (guint8*)g_memdup(o->engine.data,o->engine.len);
1354 d->user.authKey.data = o->user.authKey.data ? (guint8*)g_memdup(o->user.authKey.data,o->user.authKey.len) : NULL;
1355 d->user.authKey.len = o->user.authKey.len;
1357 d->user.privKey.data = o->user.privKey.data ? (guint8*)g_memdup(o->user.privKey.data,o->user.privKey.len) : NULL;
1358 d->user.privKey.len = o->user.privKey.len;
1364 snmp_users_free_cb(void* p)
1366 snmp_ue_assoc_t* ue = (snmp_ue_assoc_t*)p;
1367 g_free(ue->user.userName.data);
1368 g_free(ue->user.authPassword.data);
1369 g_free(ue->user.privPassword.data);
1370 g_free(ue->user.authKey.data);
1371 g_free(ue->user.privKey.data);
1372 g_free(ue->engine.data);
1376 snmp_users_update_cb(void* p _U_, char** err)
1378 snmp_ue_assoc_t* ue = (snmp_ue_assoc_t*)p;
1379 GString* es = g_string_new("");
1384 if (! ue->user.userName.len) {
1385 g_string_append_printf(es,"no userName\n");
1386 } else if ((ue->engine.len > 0) && (ue->engine.len < 5 || ue->engine.len > 32)) {
1387 /* RFC 3411 section 5 */
1388 g_string_append_printf(es, "Invalid engineId length (%u). Must be between 5 and 32 (10 and 64 hex digits)\n", ue->engine.len);
1389 } else if (num_ueas) {
1390 for (i=0; i<num_ueas-1; i++) {
1391 snmp_ue_assoc_t* u = &(ueas[i]);
1393 if ( u->user.userName.len == ue->user.userName.len
1394 && u->engine.len == ue->engine.len && (u != ue)) {
1396 if (u->engine.len > 0 && memcmp( u->engine.data, ue->engine.data, u->engine.len ) == 0) {
1397 if ( memcmp( u->user.userName.data, ue->user.userName.data, ue->user.userName.len ) == 0 ) {
1398 /* XXX: make a string for the engineId */
1399 g_string_append_printf(es,"Duplicate key (userName='%s')\n",ue->user.userName.data);
1404 if (u->engine.len == 0) {
1405 if ( memcmp( u->user.userName.data, ue->user.userName.data, ue->user.userName.len ) == 0 ) {
1406 g_string_append_printf(es,"Duplicate key (userName='%s' engineId=NONE)\n",ue->user.userName.data);
1415 es = g_string_truncate(es,es->len-1);
1416 *err = g_string_free(es, FALSE);
1424 free_ue_cache(snmp_ue_assoc_t **cache)
1426 static snmp_ue_assoc_t *a, *nxt;
1428 for (a = *cache; a; a = nxt) {
1430 snmp_users_free_cb(a);
1437 #define CACHE_INSERT(c,a) if (c) { snmp_ue_assoc_t* t = c; c = a; c->next = t; } else { c = a; a->next = NULL; }
1444 for (i = 0; i < num_ueas; i++) {
1445 snmp_ue_assoc_t* a = ue_dup(&(ueas[i]));
1447 if (a->engine.len) {
1448 CACHE_INSERT(localized_ues,a);
1451 CACHE_INSERT(unlocalized_ues,a);
1458 cleanup_ue_cache(void)
1460 free_ue_cache(&localized_ues);
1461 free_ue_cache(&unlocalized_ues);
1464 /* Called when the user applies changes to UAT preferences. */
1466 renew_ue_cache(void)
1473 static snmp_ue_assoc_t*
1474 localize_ue( snmp_ue_assoc_t* o, const guint8* engine, guint engine_len )
1476 snmp_ue_assoc_t* n = (snmp_ue_assoc_t*)g_memdup(o,sizeof(snmp_ue_assoc_t));
1478 n->user.userName.data = (guint8*)g_memdup(o->user.userName.data,o->user.userName.len);
1479 n->user.authModel = o->user.authModel;
1480 n->user.authPassword.data = (guint8*)g_memdup(o->user.authPassword.data,o->user.authPassword.len);
1481 n->user.authPassword.len = o->user.authPassword.len;
1482 n->user.privPassword.data = (guint8*)g_memdup(o->user.privPassword.data,o->user.privPassword.len);
1483 n->user.privPassword.len = o->user.privPassword.len;
1484 n->user.authKey.data = (guint8*)g_memdup(o->user.authKey.data,o->user.authKey.len);
1485 n->user.privKey.data = (guint8*)g_memdup(o->user.privKey.data,o->user.privKey.len);
1486 n->engine.data = (guint8*)g_memdup(engine,engine_len);
1487 n->engine.len = engine_len;
1488 n->priv_proto = o->priv_proto;
1496 #define localized_match(a,u,ul,e,el) \
1497 ( a->user.userName.len == ul \
1498 && a->engine.len == el \
1499 && memcmp( a->user.userName.data, u, ul ) == 0 \
1500 && memcmp( a->engine.data, e, el ) == 0 )
1502 #define unlocalized_match(a,u,l) \
1503 ( a->user.userName.len == l && memcmp( a->user.userName.data, u, l) == 0 )
1505 static snmp_ue_assoc_t*
1506 get_user_assoc(tvbuff_t* engine_tvb, tvbuff_t* user_tvb)
1508 static snmp_ue_assoc_t* a;
1509 guint given_username_len;
1510 guint8* given_username;
1511 guint given_engine_len = 0;
1512 guint8* given_engine = NULL;
1514 if ( ! (localized_ues || unlocalized_ues ) ) return NULL;
1516 if (! ( user_tvb && engine_tvb ) ) return NULL;
1518 given_username_len = tvb_captured_length(user_tvb);
1519 given_engine_len = tvb_captured_length(engine_tvb);
1520 if (! ( given_engine_len && given_username_len ) ) return NULL;
1521 given_username = (guint8*)tvb_memdup(wmem_packet_scope(),user_tvb,0,-1);
1522 given_engine = (guint8*)tvb_memdup(wmem_packet_scope(),engine_tvb,0,-1);
1524 for (a = localized_ues; a; a = a->next) {
1525 if ( localized_match(a, given_username, given_username_len, given_engine, given_engine_len) ) {
1530 for (a = unlocalized_ues; a; a = a->next) {
1531 if ( unlocalized_match(a, given_username, given_username_len) ) {
1532 snmp_ue_assoc_t* n = localize_ue( a, given_engine, given_engine_len );
1533 CACHE_INSERT(localized_ues,n);
1542 snmp_usm_auth(const snmp_usm_auth_model_t model, snmp_usm_params_t* p, guint8** calc_auth_p,
1543 guint* calc_auth_len_p, gchar const** error)
1557 *error = "No Authenticator";
1561 key = p->user_assoc->user.authKey.data;
1562 key_len = p->user_assoc->user.authKey.len;
1565 *error = "User has no authKey";
1569 auth_len = tvb_captured_length(p->auth_tvb);
1571 if (auth_len != auth_tag_len[model]) {
1572 *error = "Authenticator length wrong";
1576 msg_len = tvb_captured_length(p->msg_tvb);
1578 *error = "Not enough data remaining";
1581 msg = (guint8*)tvb_memdup(wmem_packet_scope(),p->msg_tvb,0,msg_len);
1583 auth = (guint8*)tvb_memdup(wmem_packet_scope(),p->auth_tvb,0,auth_len);
1585 start = p->auth_offset - p->start_offset;
1586 end = start + auth_len;
1588 /* fill the authenticator with zeros */
1589 for ( i = start ; i < end ; i++ ) {
1593 calc_auth = (guint8*)wmem_alloc(wmem_packet_scope(), auth_hash_len[model]);
1595 if (ws_hmac_buffer(auth_hash_algo[model], calc_auth, msg, msg_len, key, key_len)) {
1599 if (calc_auth_p) *calc_auth_p = calc_auth;
1600 if (calc_auth_len_p) *calc_auth_len_p = auth_len;
1602 return ( memcmp(auth,calc_auth,auth_len) != 0 ) ? FALSE : TRUE;
1606 snmp_usm_priv_des(snmp_usm_params_t* p, tvbuff_t* encryptedData, packet_info *pinfo, gchar const** error)
1609 gcry_cipher_hd_t hd = NULL;
1612 guint8* des_key = p->user_assoc->user.privKey.data; /* first 8 bytes */
1613 guint8* pre_iv = &(p->user_assoc->user.privKey.data[8]); /* last 8 bytes */
1618 tvbuff_t* clear_tvb;
1623 salt_len = tvb_captured_length(p->priv_tvb);
1625 if (salt_len != 8) {
1626 *error = "decryptionError: msgPrivacyParameters length != 8";
1630 salt = (guint8*)tvb_memdup(wmem_packet_scope(),p->priv_tvb,0,salt_len);
1633 The resulting "salt" is XOR-ed with the pre-IV to obtain the IV.
1635 for (i=0; i<8; i++) {
1636 iv[i] = pre_iv[i] ^ salt[i];
1639 cryptgrm_len = tvb_captured_length(encryptedData);
1641 if ((cryptgrm_len <= 0) || (cryptgrm_len % 8)) {
1642 *error = "decryptionError: the length of the encrypted data is not a multiple of 8 octets";
1646 cryptgrm = (guint8*)tvb_memdup(wmem_packet_scope(),encryptedData,0,-1);
1648 cleartext = (guint8*)wmem_alloc(pinfo->pool, cryptgrm_len);
1650 err = gcry_cipher_open(&hd, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_CBC, 0);
1651 if (err != GPG_ERR_NO_ERROR) goto on_gcry_error;
1653 err = gcry_cipher_setiv(hd, iv, 8);
1654 if (err != GPG_ERR_NO_ERROR) goto on_gcry_error;
1656 err = gcry_cipher_setkey(hd,des_key,8);
1657 if (err != GPG_ERR_NO_ERROR) goto on_gcry_error;
1659 err = gcry_cipher_decrypt(hd, cleartext, cryptgrm_len, cryptgrm, cryptgrm_len);
1660 if (err != GPG_ERR_NO_ERROR) goto on_gcry_error;
1662 gcry_cipher_close(hd);
1664 clear_tvb = tvb_new_child_real_data(encryptedData, cleartext, cryptgrm_len, cryptgrm_len);
1669 *error = (const gchar *)gcry_strerror(err);
1670 if (hd) gcry_cipher_close(hd);
1675 snmp_usm_priv_aes_common(snmp_usm_params_t* p, tvbuff_t* encryptedData, packet_info *pinfo, gchar const** error, int algo)
1678 gcry_cipher_hd_t hd = NULL;
1681 guint8* aes_key = p->user_assoc->user.privKey.data;
1682 int aes_key_len = p->user_assoc->user.privKey.len;
1687 tvbuff_t* clear_tvb;
1689 priv_len = tvb_captured_length(p->priv_tvb);
1691 if (priv_len != 8) {
1692 *error = "decryptionError: msgPrivacyParameters length != 8";
1696 iv[0] = (p->boots & 0xff000000) >> 24;
1697 iv[1] = (p->boots & 0x00ff0000) >> 16;
1698 iv[2] = (p->boots & 0x0000ff00) >> 8;
1699 iv[3] = (p->boots & 0x000000ff);
1700 iv[4] = (p->snmp_time & 0xff000000) >> 24;
1701 iv[5] = (p->snmp_time & 0x00ff0000) >> 16;
1702 iv[6] = (p->snmp_time & 0x0000ff00) >> 8;
1703 iv[7] = (p->snmp_time & 0x000000ff);
1704 tvb_memcpy(p->priv_tvb,&(iv[8]),0,8);
1706 cryptgrm_len = tvb_captured_length(encryptedData);
1707 if (cryptgrm_len <= 0) {
1708 *error = "Not enough data remaining";
1711 cryptgrm = (guint8*)tvb_memdup(wmem_packet_scope(),encryptedData,0,-1);
1713 cleartext = (guint8*)wmem_alloc(pinfo->pool, cryptgrm_len);
1715 err = gcry_cipher_open(&hd, algo, GCRY_CIPHER_MODE_CFB, 0);
1716 if (err != GPG_ERR_NO_ERROR) goto on_gcry_error;
1718 err = gcry_cipher_setiv(hd, iv, 16);
1719 if (err != GPG_ERR_NO_ERROR) goto on_gcry_error;
1721 err = gcry_cipher_setkey(hd,aes_key,aes_key_len);
1722 if (err != GPG_ERR_NO_ERROR) goto on_gcry_error;
1724 err = gcry_cipher_decrypt(hd, cleartext, cryptgrm_len, cryptgrm, cryptgrm_len);
1725 if (err != GPG_ERR_NO_ERROR) goto on_gcry_error;
1727 gcry_cipher_close(hd);
1729 clear_tvb = tvb_new_child_real_data(encryptedData, cleartext, cryptgrm_len, cryptgrm_len);
1734 *error = (const gchar *)gcry_strerror(err);
1735 if (hd) gcry_cipher_close(hd);
1740 snmp_usm_priv_aes128(snmp_usm_params_t* p, tvbuff_t* encryptedData, packet_info *pinfo, gchar const** error)
1742 return snmp_usm_priv_aes_common(p, encryptedData, pinfo, error, GCRY_CIPHER_AES);
1746 snmp_usm_priv_aes192(snmp_usm_params_t* p, tvbuff_t* encryptedData, packet_info *pinfo, gchar const** error)
1748 return snmp_usm_priv_aes_common(p, encryptedData, pinfo, error, GCRY_CIPHER_AES192);
1752 snmp_usm_priv_aes256(snmp_usm_params_t* p, tvbuff_t* encryptedData, packet_info *pinfo, gchar const** error)
1754 return snmp_usm_priv_aes_common(p, encryptedData, pinfo, error, GCRY_CIPHER_AES256);
1758 check_ScopedPdu(tvbuff_t* tvb)
1764 int hoffset, eoffset;
1767 offset = get_ber_identifier(tvb, 0, &ber_class, &pc, &tag);
1768 offset = get_ber_length(tvb, offset, NULL, NULL);
1770 if ( ! (((ber_class!=BER_CLASS_APP) && (ber_class!=BER_CLASS_PRI) )
1771 && ( (!pc) || (ber_class!=BER_CLASS_UNI) || (tag!=BER_UNI_TAG_ENUMERATED) )
1774 if((tvb_get_guint8(tvb, offset)==0)&&(tvb_get_guint8(tvb, offset+1)==0))
1779 offset = get_ber_identifier(tvb, offset, &ber_class, &pc, &tag);
1780 offset = get_ber_length(tvb, offset, &len, NULL);
1781 eoffset = offset + len;
1783 if (eoffset <= hoffset) return FALSE;
1785 if ((ber_class!=BER_CLASS_APP)&&(ber_class!=BER_CLASS_PRI))
1786 if( (ber_class!=BER_CLASS_UNI)
1787 ||((tag<BER_UNI_TAG_NumericString)&&(tag!=BER_UNI_TAG_OCTETSTRING)&&(tag!=BER_UNI_TAG_UTF8String)) )
1794 #include "packet-snmp-fn.c"
1798 dissect_snmp_pdu(tvbuff_t *tvb, int offset, packet_info *pinfo,
1799 proto_tree *tree, int proto, gint ett, gboolean is_tcp)
1802 guint length_remaining;
1804 gboolean pc, ind = 0;
1807 guint message_length;
1808 int start_offset = offset;
1809 guint32 version = 0;
1812 proto_tree *snmp_tree = NULL;
1813 proto_item *item = NULL;
1814 asn1_ctx_t asn1_ctx;
1815 asn1_ctx_init(&asn1_ctx, ASN1_ENC_BER, TRUE, pinfo);
1818 usm_p.msg_tvb = tvb;
1819 usm_p.start_offset = tvb_offset_from_real_beginning(tvb);
1820 usm_p.engine_tvb = NULL;
1821 usm_p.user_tvb = NULL;
1822 usm_p.auth_item = NULL;
1823 usm_p.auth_tvb = NULL;
1824 usm_p.auth_offset = 0;
1825 usm_p.priv_tvb = NULL;
1826 usm_p.user_assoc = NULL;
1827 usm_p.authenticated = FALSE;
1828 usm_p.encrypted = FALSE;
1830 usm_p.snmp_time = 0;
1831 usm_p.authOK = FALSE;
1834 * This will throw an exception if we don't have any data left.
1835 * That's what we want. (See "tcp_dissect_pdus()", which is
1836 * similar, but doesn't have to deal with ASN.1.
1837 * XXX - can we make "tcp_dissect_pdus()" provide enough
1838 * information to the "get_pdu_len" routine so that we could
1839 * have that routine deal with ASN.1, and just use
1840 * "tcp_dissect_pdus()"?)
1842 length_remaining = tvb_ensure_captured_length_remaining(tvb, offset);
1844 /* NOTE: we have to parse the message piece by piece, since the
1845 * capture length may be less than the message length: a 'global'
1846 * parsing is likely to fail.
1850 * If this is SNMP-over-TCP, we might have to do reassembly
1851 * in order to read the "Sequence Of" header.
1853 if (is_tcp && snmp_desegment && pinfo->can_desegment) {
1855 * This is TCP, and we should, and can, do reassembly.
1857 * Is the "Sequence Of" header split across segment
1858 * boundaries? We require at least 6 bytes for the
1859 * header, which allows for a 4-byte length (ASN.1
1862 if (length_remaining < 6) {
1864 * Yes. Tell the TCP dissector where the data
1865 * for this message starts in the data it handed
1866 * us and that we need "some more data." Don't tell
1867 * it exactly how many bytes we need because if/when
1868 * we ask for even more (after the header) that will
1871 pinfo->desegment_offset = offset;
1872 pinfo->desegment_len = DESEGMENT_ONE_MORE_SEGMENT;
1878 * OK, try to read the "Sequence Of" header; this gets the total
1879 * length of the SNMP message.
1881 offset = get_ber_identifier(tvb, offset, &ber_class, &pc, &tag);
1882 /*Get the total octet length of the SNMP data*/
1883 offset = get_ber_length(tvb, offset, &len, &ind);
1884 message_length = len + offset;
1886 /*Get the SNMP version data*/
1887 /*offset =*/ dissect_ber_integer(FALSE, &asn1_ctx, 0, tvb, offset, -1, &version);
1891 * If this is SNMP-over-TCP, we might have to do reassembly
1892 * to get all of this message.
1894 if (is_tcp && snmp_desegment && pinfo->can_desegment) {
1896 * Yes - is the message split across segment boundaries?
1898 if (length_remaining < message_length) {
1900 * Yes. Tell the TCP dissector where the data
1901 * for this message starts in the data it handed
1902 * us, and how many more bytes we need, and
1905 pinfo->desegment_offset = start_offset;
1906 pinfo->desegment_len =
1907 message_length - length_remaining;
1910 * Return 0, which means "I didn't dissect anything
1911 * because I don't have enough data - we need
1918 next_tvb_init(&var_list);
1920 col_set_str(pinfo->cinfo, COL_PROTOCOL, proto_get_protocol_short_name(find_protocol_by_id(proto)));
1922 item = proto_tree_add_item(tree, proto, tvb, start_offset, message_length, ENC_BIG_ENDIAN);
1923 snmp_tree = proto_item_add_subtree(item, ett);
1928 offset = dissect_snmp_Message(FALSE , tvb, start_offset, &asn1_ctx, snmp_tree, -1);
1931 offset = dissect_snmp_Messagev2u(FALSE , tvb, start_offset, &asn1_ctx, snmp_tree, -1);
1935 offset = dissect_snmp_SNMPv3Message(FALSE , tvb, start_offset, &asn1_ctx, snmp_tree, -1);
1939 * Return the length remaining in the tvbuff, so
1940 * if this is SNMP-over-TCP, our caller thinks there's
1941 * nothing left to dissect.
1943 expert_add_info(pinfo, item, &ei_snmp_version_unknown);
1944 return length_remaining;
1948 /* There may be appended data after the SNMP data, so treat as raw
1949 * data which needs to be dissected in case of UDP as UDP is PDU oriented.
1951 if((!is_tcp) && (length_remaining > (guint)offset)) {
1952 next_tvb = tvb_new_subset_remaining(tvb, offset);
1953 call_dissector(data_handle, next_tvb, pinfo, tree);
1955 next_tvb_call(&var_list, pinfo, tree, NULL, data_handle);
1962 dissect_snmp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
1964 conversation_t *conversation;
1973 * See if this looks like SNMP or not. if not, return 0 so
1974 * wireshark can try some other dissector instead.
1976 /* All SNMP packets are BER encoded and consist of a SEQUENCE
1977 * that spans the entire PDU. The first item is an INTEGER that
1978 * has the values 0-2 (version 1-3).
1979 * if not it is not snmp.
1981 /* SNMP starts with a SEQUENCE */
1982 offset = get_ber_identifier(tvb, 0, &tmp_class, &tmp_pc, &tmp_tag);
1983 if((tmp_class!=BER_CLASS_UNI)||(tmp_tag!=BER_UNI_TAG_SEQUENCE)) {
1986 /* then comes a length which spans the rest of the tvb */
1987 offset = get_ber_length(tvb, offset, &tmp_length, &tmp_ind);
1988 /* if(tmp_length!=(guint32)tvb_reported_length_remaining(tvb, offset)) {
1989 * Loosen the heuristic a bit to handle the case where data has intentionally
1990 * been added after the snmp PDU ( UDP case)
1992 if ( pinfo->ptype == PT_UDP ) {
1993 if(tmp_length>(guint32)tvb_reported_length_remaining(tvb, offset)) {
1997 if(tmp_length!=(guint32)tvb_reported_length_remaining(tvb, offset)) {
2001 /* then comes an INTEGER (version)*/
2002 get_ber_identifier(tvb, offset, &tmp_class, &tmp_pc, &tmp_tag);
2003 if((tmp_class!=BER_CLASS_UNI)||(tmp_tag!=BER_UNI_TAG_INTEGER)) {
2006 /* do we need to test that version is 0 - 2 (version1-3) ? */
2010 * The first SNMP packet goes to the SNMP port; the second one
2011 * may come from some *other* port, but goes back to the same
2012 * IP address and port as the ones from which the first packet
2013 * came; all subsequent packets presumably go between those two
2014 * IP addresses and ports.
2016 * If this packet went to the SNMP port, we check to see if
2017 * there's already a conversation with one address/port pair
2018 * matching the source IP address and port of this packet,
2019 * the other address matching the destination IP address of this
2020 * packet, and any destination port.
2022 * If not, we create one, with its address 1/port 1 pair being
2023 * the source address/port of this packet, its address 2 being
2024 * the destination address of this packet, and its port 2 being
2025 * wildcarded, and give it the SNMP dissector as a dissector.
2027 if (pinfo->destport == UDP_PORT_SNMP) {
2028 conversation = find_conversation(pinfo->num, &pinfo->src, &pinfo->dst, ENDPOINT_UDP,
2029 pinfo->srcport, 0, NO_PORT_B);
2030 if( (conversation == NULL) || (conversation_get_dissector(conversation, pinfo->num)!=snmp_handle) ) {
2031 conversation = conversation_new(pinfo->num, &pinfo->src, &pinfo->dst, ENDPOINT_UDP,
2032 pinfo->srcport, 0, NO_PORT2);
2033 conversation_set_dissector(conversation, snmp_handle);
2037 return dissect_snmp_pdu(tvb, 0, pinfo, tree, proto_snmp, ett_snmp, FALSE);
2041 dissect_snmp_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
2046 while (tvb_reported_length_remaining(tvb, offset) > 0) {
2047 message_len = dissect_snmp_pdu(tvb, 0, pinfo, tree, proto_snmp, ett_snmp, TRUE);
2048 if (message_len == 0) {
2050 * We don't have all the data for that message,
2051 * so we need to do desegmentation;
2052 * "dissect_snmp_pdu()" has set that up.
2056 offset += message_len;
2058 return tvb_captured_length(tvb);
2062 dissect_smux(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
2064 proto_tree *smux_tree = NULL;
2065 proto_item *item = NULL;
2067 next_tvb_init(&var_list);
2069 col_set_str(pinfo->cinfo, COL_PROTOCOL, "SMUX");
2071 item = proto_tree_add_item(tree, proto_smux, tvb, 0, -1, ENC_NA);
2072 smux_tree = proto_item_add_subtree(item, ett_smux);
2074 return dissect_SMUX_PDUs_PDU(tvb, pinfo, smux_tree, data);
2078 MD5 Password to Key Algorithm from RFC 3414 A.2.1
2079 SHA1 Password to Key Algorithm from RFC 3414 A.2.2
2080 SHA2 Password to Key Algorithm from RFC 7860 9.3
2083 snmp_usm_password_to_key(const snmp_usm_auth_model_t model, const guint8 *password,
2084 guint passwordlen, const guint8 *engineID, guint engineLength, guint8 *key)
2086 gcry_md_hd_t hash_handle;
2087 guint8 *cp, password_buf[64];
2088 guint32 password_index = 0;
2089 guint32 count = 0, i;
2092 if (gcry_md_open(&hash_handle, auth_hash_algo[model], 0)) {
2096 hash_len = auth_hash_len[model];
2098 /**********************************************/
2099 /* Use while loop until we've done 1 Megabyte */
2100 /**********************************************/
2101 while (count < 1048576) {
2103 if (passwordlen != 0) {
2104 for (i = 0; i < 64; i++) {
2105 /*************************************************/
2106 /* Take the next octet of the password, wrapping */
2107 /* to the beginning of the password as necessary.*/
2108 /*************************************************/
2109 *cp++ = password[password_index++ % passwordlen];
2114 gcry_md_write(hash_handle, password_buf, 64);
2117 memcpy(key, gcry_md_read(hash_handle, 0), hash_len);
2118 gcry_md_close(hash_handle);
2120 /*****************************************************/
2121 /* Now localise the key with the engineID and pass */
2122 /* through hash function to produce final key */
2123 /* We ignore invalid engineLengths here. More strict */
2124 /* checking is done in snmp_users_update_cb. */
2125 /*****************************************************/
2126 if (gcry_md_open(&hash_handle, auth_hash_algo[model], 0)) {
2129 gcry_md_write(hash_handle, key, hash_len);
2130 gcry_md_write(hash_handle, engineID, engineLength);
2131 gcry_md_write(hash_handle, key, hash_len);
2132 memcpy(key, gcry_md_read(hash_handle, 0), hash_len);
2133 gcry_md_close(hash_handle);
2142 UAT_LSTRING_CB_DEF(snmp_users,userName,snmp_ue_assoc_t,user.userName.data,user.userName.len)
2143 UAT_LSTRING_CB_DEF(snmp_users,authPassword,snmp_ue_assoc_t,user.authPassword.data,user.authPassword.len)
2144 UAT_LSTRING_CB_DEF(snmp_users,privPassword,snmp_ue_assoc_t,user.privPassword.data,user.privPassword.len)
2145 UAT_BUFFER_CB_DEF(snmp_users,engine_id,snmp_ue_assoc_t,engine.data,engine.len)
2146 UAT_VS_DEF(snmp_users,auth_model,snmp_ue_assoc_t,guint,0,"MD5")
2147 UAT_VS_DEF(snmp_users,priv_proto,snmp_ue_assoc_t,guint,0,"DES")
2150 snmp_specific_trap_copy_cb(void *dest, const void *orig, size_t len _U_)
2152 snmp_st_assoc_t *u = (snmp_st_assoc_t *)dest;
2153 const snmp_st_assoc_t *o = (const snmp_st_assoc_t *)orig;
2155 u->enterprise = g_strdup(o->enterprise);
2157 u->desc = g_strdup(o->desc);
2163 snmp_specific_trap_free_cb(void *r)
2165 snmp_st_assoc_t *u = (snmp_st_assoc_t *)r;
2167 g_free(u->enterprise);
2171 UAT_CSTRING_CB_DEF(specific_traps, enterprise, snmp_st_assoc_t)
2172 UAT_DEC_CB_DEF(specific_traps, trap, snmp_st_assoc_t)
2173 UAT_CSTRING_CB_DEF(specific_traps, desc, snmp_st_assoc_t)
2175 /*--- proto_register_snmp -------------------------------------------*/
2176 void proto_register_snmp(void) {
2177 /* List of fields */
2178 static hf_register_info hf[] = {
2179 { &hf_snmp_v3_flags_auth,
2180 { "Authenticated", "snmp.v3.flags.auth", FT_BOOLEAN, 8,
2181 TFS(&tfs_set_notset), TH_AUTH, NULL, HFILL }},
2182 { &hf_snmp_v3_flags_crypt,
2183 { "Encrypted", "snmp.v3.flags.crypt", FT_BOOLEAN, 8,
2184 TFS(&tfs_set_notset), TH_CRYPT, NULL, HFILL }},
2185 { &hf_snmp_v3_flags_report,
2186 { "Reportable", "snmp.v3.flags.report", FT_BOOLEAN, 8,
2187 TFS(&tfs_set_notset), TH_REPORT, NULL, HFILL }},
2188 { &hf_snmp_engineid_conform, {
2189 "Engine ID Conformance", "snmp.engineid.conform", FT_BOOLEAN, 8,
2190 TFS(&tfs_snmp_engineid_conform), F_SNMP_ENGINEID_CONFORM, "Engine ID RFC3411 Conformance", HFILL }},
2191 { &hf_snmp_engineid_enterprise, {
2192 "Engine Enterprise ID", "snmp.engineid.enterprise", FT_UINT32, BASE_ENTERPRISES,
2193 STRINGS_ENTERPRISES, 0, NULL, HFILL }},
2194 { &hf_snmp_engineid_format, {
2195 "Engine ID Format", "snmp.engineid.format", FT_UINT8, BASE_DEC,
2196 VALS(snmp_engineid_format_vals), 0, NULL, HFILL }},
2197 { &hf_snmp_engineid_ipv4, {
2198 "Engine ID Data: IPv4 address", "snmp.engineid.ipv4", FT_IPv4, BASE_NONE,
2199 NULL, 0, NULL, HFILL }},
2200 { &hf_snmp_engineid_ipv6, {
2201 "Engine ID Data: IPv6 address", "snmp.engineid.ipv6", FT_IPv6, BASE_NONE,
2202 NULL, 0, NULL, HFILL }},
2203 { &hf_snmp_engineid_cisco_type, {
2204 "Engine ID Data: Cisco type", "snmp.engineid.cisco.type", FT_UINT8, BASE_HEX,
2205 VALS(snmp_engineid_cisco_type_vals), 0, NULL, HFILL }},
2206 { &hf_snmp_engineid_mac, {
2207 "Engine ID Data: MAC address", "snmp.engineid.mac", FT_ETHER, BASE_NONE,
2208 NULL, 0, NULL, HFILL }},
2209 { &hf_snmp_engineid_text, {
2210 "Engine ID Data: Text", "snmp.engineid.text", FT_STRING, BASE_NONE,
2211 NULL, 0, NULL, HFILL }},
2212 { &hf_snmp_engineid_time, {
2213 "Engine ID Data: Creation Time", "snmp.engineid.time", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL,
2214 NULL, 0, NULL, HFILL }},
2215 { &hf_snmp_engineid_data, {
2216 "Engine ID Data", "snmp.engineid.data", FT_BYTES, BASE_NONE,
2217 NULL, 0, NULL, HFILL }},
2218 { &hf_snmp_msgAuthentication, {
2219 "Authentication", "snmp.v3.auth", FT_BOOLEAN, BASE_NONE,
2220 TFS(&auth_flags), 0, NULL, HFILL }},
2221 { &hf_snmp_decryptedPDU, {
2222 "Decrypted ScopedPDU", "snmp.decrypted_pdu", FT_BYTES, BASE_NONE,
2223 NULL, 0, "Decrypted PDU", HFILL }},
2224 { &hf_snmp_noSuchObject, {
2225 "noSuchObject", "snmp.noSuchObject", FT_NONE, BASE_NONE,
2226 NULL, 0, NULL, HFILL }},
2227 { &hf_snmp_noSuchInstance, {
2228 "noSuchInstance", "snmp.noSuchInstance", FT_NONE, BASE_NONE,
2229 NULL, 0, NULL, HFILL }},
2230 { &hf_snmp_endOfMibView, {
2231 "endOfMibView", "snmp.endOfMibView", FT_NONE, BASE_NONE,
2232 NULL, 0, NULL, HFILL }},
2233 { &hf_snmp_unSpecified, {
2234 "unSpecified", "snmp.unSpecified", FT_NONE, BASE_NONE,
2235 NULL, 0, NULL, HFILL }},
2237 { &hf_snmp_integer32_value, {
2238 "Value (Integer32)", "snmp.value.int", FT_INT64, BASE_DEC,
2239 NULL, 0, NULL, HFILL }},
2240 { &hf_snmp_octetstring_value, {
2241 "Value (OctetString)", "snmp.value.octets", FT_BYTES, BASE_NONE,
2242 NULL, 0, NULL, HFILL }},
2243 { &hf_snmp_oid_value, {
2244 "Value (OID)", "snmp.value.oid", FT_OID, BASE_NONE,
2245 NULL, 0, NULL, HFILL }},
2246 { &hf_snmp_null_value, {
2247 "Value (Null)", "snmp.value.null", FT_NONE, BASE_NONE,
2248 NULL, 0, NULL, HFILL }},
2249 { &hf_snmp_ipv4_value, {
2250 "Value (IpAddress)", "snmp.value.ipv4", FT_IPv4, BASE_NONE,
2251 NULL, 0, NULL, HFILL }},
2252 { &hf_snmp_ipv6_value, {
2253 "Value (IpAddress)", "snmp.value.ipv6", FT_IPv6, BASE_NONE,
2254 NULL, 0, NULL, HFILL }},
2255 { &hf_snmp_anyaddress_value, {
2256 "Value (IpAddress)", "snmp.value.addr", FT_BYTES, BASE_NONE,
2257 NULL, 0, NULL, HFILL }},
2258 { &hf_snmp_unsigned32_value, {
2259 "Value (Unsigned32)", "snmp.value.u32", FT_INT64, BASE_DEC,
2260 NULL, 0, NULL, HFILL }},
2261 { &hf_snmp_gauge32_value, {
2262 "Value (Gauge32)", "snmp.value.g32", FT_INT64, BASE_DEC,
2263 NULL, 0, NULL, HFILL }},
2264 { &hf_snmp_unknown_value, {
2265 "Value (Unknown)", "snmp.value.unk", FT_BYTES, BASE_NONE,
2266 NULL, 0, NULL, HFILL }},
2267 { &hf_snmp_counter_value, {
2268 "Value (Counter32)", "snmp.value.counter", FT_UINT64, BASE_DEC,
2269 NULL, 0, NULL, HFILL }},
2270 { &hf_snmp_big_counter_value, {
2271 "Value (Counter64)", "snmp.value.counter", FT_UINT64, BASE_DEC,
2272 NULL, 0, NULL, HFILL }},
2273 { &hf_snmp_nsap_value, {
2274 "Value (NSAP)", "snmp.value.nsap", FT_UINT64, BASE_DEC,
2275 NULL, 0, NULL, HFILL }},
2276 { &hf_snmp_timeticks_value, {
2277 "Value (Timeticks)", "snmp.value.timeticks", FT_UINT64, BASE_DEC,
2278 NULL, 0, NULL, HFILL }},
2279 { &hf_snmp_opaque_value, {
2280 "Value (Opaque)", "snmp.value.opaque", FT_BYTES, BASE_NONE,
2281 NULL, 0, NULL, HFILL }},
2282 { &hf_snmp_objectname, {
2283 "Object Name", "snmp.name", FT_OID, BASE_NONE,
2284 NULL, 0, NULL, HFILL }},
2285 { &hf_snmp_scalar_instance_index, {
2286 "Scalar Instance Index", "snmp.name.index", FT_UINT64, BASE_DEC,
2287 NULL, 0, NULL, HFILL }},
2288 { &hf_snmp_var_bind_str, {
2289 "Variable-binding-string", "snmp.var-bind_str", FT_STRING, BASE_NONE,
2290 NULL, 0, NULL, HFILL }},
2291 { &hf_snmp_agentid_trailer, {
2292 "AgentID Trailer", "snmp.agentid_trailer", FT_BYTES, BASE_NONE,
2293 NULL, 0, NULL, HFILL }},
2296 #include "packet-snmp-hfarr.c"
2299 /* List of subtrees */
2300 static gint *ett[] = {
2306 &ett_authParameters,
2311 &ett_decoding_error,
2312 #include "packet-snmp-ettarr.c"
2314 static ei_register_info ei[] = {
2315 { &ei_snmp_failed_decrypted_data_pdu, { "snmp.failed_decrypted_data_pdu", PI_MALFORMED, PI_WARN, "Failed to decrypt encryptedPDU", EXPFILL }},
2316 { &ei_snmp_decrypted_data_bad_formatted, { "snmp.decrypted_data_bad_formatted", PI_MALFORMED, PI_WARN, "Decrypted data not formatted as expected, wrong key?", EXPFILL }},
2317 { &ei_snmp_verify_authentication_error, { "snmp.verify_authentication_error", PI_MALFORMED, PI_ERROR, "Error while verifying Message authenticity", EXPFILL }},
2318 { &ei_snmp_authentication_ok, { "snmp.authentication_ok", PI_CHECKSUM, PI_CHAT, "SNMP Authentication OK", EXPFILL }},
2319 { &ei_snmp_authentication_error, { "snmp.authentication_error", PI_CHECKSUM, PI_WARN, "SNMP Authentication Error", EXPFILL }},
2320 { &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 }},
2321 { &ei_snmp_varbind_has_indicator, { "snmp.varbind.has_indicator", PI_MALFORMED, PI_WARN, "VarBind has indicator set", EXPFILL }},
2322 { &ei_snmp_objectname_not_oid, { "snmp.objectname_not_oid", PI_MALFORMED, PI_WARN, "ObjectName not an OID", EXPFILL }},
2323 { &ei_snmp_objectname_has_indicator, { "snmp.objectname_has_indicator", PI_MALFORMED, PI_WARN, "ObjectName has indicator set", EXPFILL }},
2324 { &ei_snmp_value_not_primitive_encoding, { "snmp.value_not_primitive_encoding", PI_MALFORMED, PI_WARN, "value not in primitive encoding", EXPFILL }},
2325 { &ei_snmp_invalid_oid, { "snmp.invalid_oid", PI_MALFORMED, PI_WARN, "invalid oid", EXPFILL }},
2326 { &ei_snmp_varbind_wrong_tag, { "snmp.varbind.wrong_tag", PI_MALFORMED, PI_WARN, "Wrong tag for SNMP VarBind error value", EXPFILL }},
2327 { &ei_snmp_varbind_response, { "snmp.varbind.response", PI_RESPONSE_CODE, PI_NOTE, "Response", EXPFILL }},
2328 { &ei_snmp_no_instance_subid, { "snmp.no_instance_subid", PI_MALFORMED, PI_WARN, "No instance sub-id in scalar value", EXPFILL }},
2329 { &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 }},
2330 { &ei_snmp_index_suboid_too_short, { "snmp.index_suboid_too_short", PI_MALFORMED, PI_WARN, "index sub-oid shorter than expected", EXPFILL }},
2331 { &ei_snmp_unimplemented_instance_index, { "snmp.unimplemented_instance_index", PI_UNDECODED, PI_WARN, "OID instaces not handled, if you want this implemented please contact the wireshark developers", EXPFILL }},
2332 { &ei_snmp_index_suboid_len0, { "snmp.ndex_suboid_len0", PI_MALFORMED, PI_WARN, "an index sub-oid OID cannot be 0 bytes long!", EXPFILL }},
2333 { &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 }},
2334 { &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 }},
2335 { &ei_snmp_column_parent_not_row, { "snmp.column_parent_not_row", PI_MALFORMED, PI_ERROR, "COLUMS's parent is not a ROW", EXPFILL }},
2336 { &ei_snmp_uint_too_large, { "snmp.uint_too_large", PI_UNDECODED, PI_NOTE, "Unsigned integer value > 2^64 - 1", EXPFILL }},
2337 { &ei_snmp_int_too_large, { "snmp.int_too_large", PI_UNDECODED, PI_NOTE, "Signed integer value > 2^63 - 1 or <= -2^63", EXPFILL }},
2338 { &ei_snmp_integral_value0, { "snmp.integral_value0", PI_UNDECODED, PI_NOTE, "Integral value is zero-length", EXPFILL }},
2339 { &ei_snmp_missing_mib, { "snmp.missing_mib", PI_UNDECODED, PI_NOTE, "Unresolved value, Missing MIB", EXPFILL }},
2340 { &ei_snmp_varbind_wrong_length_value, { "snmp.varbind.wrong_length_value", PI_MALFORMED, PI_WARN, "Wrong length for SNMP VarBind/value", EXPFILL }},
2341 { &ei_snmp_varbind_wrong_class_tag, { "snmp.varbind.wrong_class_tag", PI_MALFORMED, PI_WARN, "Wrong class/tag for SNMP VarBind/value", EXPFILL }},
2342 { &ei_snmp_rfc1910_non_conformant, { "snmp.rfc1910_non_conformant", PI_PROTOCOL, PI_WARN, "Data not conforming to RFC1910", EXPFILL }},
2343 { &ei_snmp_rfc3411_non_conformant, { "snmp.rfc3411_non_conformant", PI_PROTOCOL, PI_WARN, "Data not conforming to RFC3411", EXPFILL }},
2344 { &ei_snmp_version_unknown, { "snmp.version.unknown", PI_PROTOCOL, PI_WARN, "Unknown version", EXPFILL }},
2345 { &ei_snmp_trap_pdu_obsolete, { "snmp.trap_pdu_obsolete", PI_PROTOCOL, PI_WARN, "Trap-PDU is obsolete in this SNMP version", EXPFILL }},
2349 expert_module_t* expert_snmp;
2350 module_t *snmp_module;
2352 static uat_field_t users_fields[] = {
2353 UAT_FLD_BUFFER(snmp_users,engine_id,"Engine ID","Engine-id for this entry (empty = any)"),
2354 UAT_FLD_LSTRING(snmp_users,userName,"Username","The username"),
2355 UAT_FLD_VS(snmp_users,auth_model,"Authentication model",auth_types,"Algorithm to be used for authentication."),
2356 UAT_FLD_LSTRING(snmp_users,authPassword,"Password","The password used for authenticating packets for this entry"),
2357 UAT_FLD_VS(snmp_users,priv_proto,"Privacy protocol",priv_types,"Algorithm to be used for privacy."),
2358 UAT_FLD_LSTRING(snmp_users,privPassword,"Privacy password","The password used for encrypting packets for this entry"),
2362 uat_t *assocs_uat = uat_new("SNMP Users",
2363 sizeof(snmp_ue_assoc_t),
2368 UAT_AFFECTS_DISSECTION, /* affects dissection of packets, but not set of named fields */
2369 "ChSNMPUsersSection",
2371 snmp_users_update_cb,
2377 static uat_field_t specific_traps_flds[] = {
2378 UAT_FLD_CSTRING(specific_traps,enterprise,"Enterprise OID","Enterprise Object Identifier"),
2379 UAT_FLD_DEC(specific_traps,trap,"Trap Id","The specific-trap value"),
2380 UAT_FLD_CSTRING(specific_traps,desc,"Description","Trap type description"),
2384 uat_t* specific_traps_uat = uat_new("SNMP Enterprise Specific Trap Types",
2385 sizeof(snmp_st_assoc_t),
2386 "snmp_specific_traps",
2389 &num_specific_traps,
2390 UAT_AFFECTS_DISSECTION, /* affects dissection of packets, but not set of named fields */
2391 "ChSNMPEnterpriseSpecificTrapTypes",
2392 snmp_specific_trap_copy_cb,
2394 snmp_specific_trap_free_cb,
2397 specific_traps_flds);
2399 /* Register protocol */
2400 proto_snmp = proto_register_protocol(PNAME, PSNAME, PFNAME);
2401 snmp_handle = register_dissector("snmp", dissect_snmp, proto_snmp);
2403 /* Register fields and subtrees */
2404 proto_register_field_array(proto_snmp, hf, array_length(hf));
2405 proto_register_subtree_array(ett, array_length(ett));
2406 expert_snmp = expert_register_protocol(proto_snmp);
2407 expert_register_field_array(expert_snmp, ei, array_length(ei));
2410 /* Register configuration preferences */
2411 snmp_module = prefs_register_protocol(proto_snmp, process_prefs);
2412 prefs_register_bool_preference(snmp_module, "display_oid",
2413 "Show SNMP OID in info column",
2414 "Whether the SNMP OID should be shown in the info column",
2417 prefs_register_obsolete_preference(snmp_module, "mib_modules");
2418 prefs_register_obsolete_preference(snmp_module, "users_file");
2420 prefs_register_bool_preference(snmp_module, "desegment",
2421 "Reassemble SNMP-over-TCP messages spanning multiple TCP segments",
2422 "Whether the SNMP dissector should reassemble messages spanning multiple TCP segments."
2423 " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
2426 prefs_register_bool_preference(snmp_module, "var_in_tree",
2427 "Display dissected variables inside SNMP tree",
2428 "ON - display dissected variables inside SNMP tree, OFF - display dissected variables in root tree after SNMP",
2431 prefs_register_uat_preference(snmp_module, "users_table",
2433 "Table of engine-user associations used for authentication and decryption",
2436 prefs_register_uat_preference(snmp_module, "specific_traps_table",
2437 "Enterprise Specific Trap Types",
2438 "Table of enterprise specific-trap type descriptions",
2439 specific_traps_uat);
2442 prefs_register_static_text_preference(snmp_module, "info_mibs",
2443 "MIB settings can be changed in the Name Resolution preferences",
2444 "MIB settings can be changed in the Name Resolution preferences");
2447 value_sub_dissectors_table = register_dissector_table("snmp.variable_oid","SNMP Variable OID", proto_snmp, FT_STRING, BASE_NONE);
2449 register_init_routine(init_ue_cache);
2450 register_cleanup_routine(cleanup_ue_cache);
2452 register_ber_syntax_dissector("SNMP", proto_snmp, dissect_snmp_tcp);
2456 /*--- proto_reg_handoff_snmp ---------------------------------------*/
2457 void proto_reg_handoff_snmp(void) {
2458 dissector_handle_t snmp_tcp_handle;
2460 dissector_add_uint_with_preference("udp.port", UDP_PORT_SNMP, snmp_handle);
2461 dissector_add_uint("ethertype", ETHERTYPE_SNMP, snmp_handle);
2462 dissector_add_uint("ipx.socket", IPX_SOCKET_SNMP_AGENT, snmp_handle);
2463 dissector_add_uint("ipx.socket", IPX_SOCKET_SNMP_SINK, snmp_handle);
2464 dissector_add_uint("hpext.dxsap", HPEXT_SNMP, snmp_handle);
2466 snmp_tcp_handle = create_dissector_handle(dissect_snmp_tcp, proto_snmp);
2467 dissector_add_uint_with_preference("tcp.port", TCP_PORT_SNMP, snmp_tcp_handle);
2468 /* Since "regular" SNMP port and "trap" SNMP port use the same handler,
2469 the "trap" port doesn't really need a separate preference. Just register
2471 dissector_add_uint("tcp.port", TCP_PORT_SNMP_TRAP, snmp_tcp_handle);
2472 dissector_add_uint("udp.port", UDP_PORT_SNMP_TRAP, snmp_handle);
2473 dissector_add_uint("udp.port", UDP_PORT_SNMP_PATROL, snmp_handle);
2475 data_handle = find_dissector("data");
2477 /* SNMPv2-MIB sysDescr "1.3.6.1.2.1.1.1.0" */
2478 dissector_add_string("snmp.variable_oid", "1.3.6.1.2.1.1.1.0",
2479 create_dissector_handle(dissect_snmp_variable_string, proto_snmp));
2480 /* SNMPv2-MIB::sysName.0 (1.3.6.1.2.1.1.5.0) */
2481 dissector_add_string("snmp.variable_oid", "1.3.6.1.2.1.1.5.0",
2482 create_dissector_handle(dissect_snmp_variable_string, proto_snmp));
2485 * Process preference settings.
2487 * We can't do this in the register routine, as preferences aren't
2488 * read until all dissector register routines have been called (so
2489 * that all dissector preferences have been registered).
2496 proto_register_smux(void)
2498 static gint *ett[] = {
2502 proto_smux = proto_register_protocol("SNMP Multiplex Protocol",
2505 proto_register_subtree_array(ett, array_length(ett));
2510 proto_reg_handoff_smux(void)
2512 dissector_handle_t smux_handle;
2514 smux_handle = create_dissector_handle(dissect_smux, proto_smux);
2515 dissector_add_uint_with_preference("tcp.port", TCP_PORT_SMUX, smux_handle);
2519 * Editor modelines - https://www.wireshark.org/tools/modelines.html
2524 * indent-tabs-mode: t
2527 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
2528 * :indentSize=8:tabSize=8:noTabs=false: