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 * Copyright (C) 2007 Luis E. Garcia Ontanon <luis.ontanon@gmail.com>
21 * Wireshark - Network traffic analyzer
22 * By Gerald Combs <gerald@wireshark.org>
23 * Copyright 1998 Gerald Combs
27 * GXSNMP -- An snmp mangament application
28 * Copyright (C) 1998 Gregory McLean & Jochen Friedrich
29 * Beholder RMON ethernet network monitor,Copyright (C) 1993 DNPAP group
31 * This program is free software; you can redistribute it and/or
32 * modify it under the terms of the GNU General Public License
33 * as published by the Free Software Foundation; either version 2
34 * of the License, or (at your option) any later version.
36 * This program is distributed in the hope that it will be useful,
37 * but WITHOUT ANY WARRANTY; without even the implied warranty of
38 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
39 * GNU General Public License for more details.
41 * You should have received a copy of the GNU General Public License
42 * along with this program; if not, write to the Free Software
43 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
56 #include <epan/packet.h>
57 #include <epan/strutil.h>
58 #include <epan/conversation.h>
60 #include <epan/prefs.h>
61 #include <epan/sminmpec.h>
62 #include <epan/emem.h>
63 #include <epan/next_tvb.h>
65 #include <epan/asn1.h>
66 #include "packet-ipx.h"
67 #include "packet-hpext.h"
70 #include "packet-ber.h"
73 # include <net-snmp/net-snmp-config.h>
74 # include <net-snmp/mib_api.h>
75 # include <net-snmp/library/default_store.h>
76 # include <net-snmp/config_api.h>
79 # include <epan/filesystem.h>
83 * Define values "sprint_realloc_value()" expects.
85 # define VALTYPE_INTEGER ASN_INTEGER
86 # define VALTYPE_COUNTER ASN_COUNTER
87 # define VALTYPE_GAUGE ASN_GAUGE
88 # define VALTYPE_TIMETICKS ASN_TIMETICKS
89 # define VALTYPE_STRING ASN_OCTET_STR
90 # define VALTYPE_IPADDR ASN_IPADDRESS
91 # define VALTYPE_OPAQUE ASN_OPAQUE
92 # define VALTYPE_NSAP ASN_NSAP
93 # define VALTYPE_OBJECTID ASN_OBJECT_ID
94 # define VALTYPE_BITSTR ASN_BIT_STR
95 # define VALTYPE_COUNTER64 ASN_COUNTER64
97 #endif /* HAVE_NET_SNMP */
98 #include "packet-snmp.h"
99 #include "format-oid.h"
101 #include <epan/crypt/crypt-sha1.h>
102 #include <epan/crypt/crypt-md5.h>
103 #include <epan/expert.h>
104 #include <epan/report_err.h>
107 #include <winposixtype.h>
110 #ifdef HAVE_LIBGCRYPT
115 /* Take a pointer that may be null and return a pointer that's not null
116 by turning null pointers into pointers to the above null string,
117 and, if the argument pointer wasn't null, make sure we handle
118 non-printable characters in the string by escaping them. */
119 #define SAFE_STRING(s, l) (((s) != NULL) ? format_text((s), (l)) : "")
121 #define PNAME "Simple Network Management Protocol"
122 #define PSNAME "SNMP"
123 #define PFNAME "snmp"
125 #define UDP_PORT_SNMP 161
126 #define UDP_PORT_SNMP_TRAP 162
127 #define TCP_PORT_SNMP 161
128 #define TCP_PORT_SNMP_TRAP 162
129 #define TCP_PORT_SMUX 199
131 /* Initialize the protocol and registered fields */
132 static int proto_snmp = -1;
133 static int proto_smux = -1;
135 /* Default MIB modules to load */
137 * XXX - According to Wes Hardaker, we shouldn't do this:
138 * http://www.ethereal.com/lists/ethereal-dev/200412/msg00222.html
141 # define DEF_MIB_MODULES "IP-MIB;IF-MIB;TCP-MIB;UDP-MIB;SNMPv2-MIB;RFC1213-MIB;UCD-SNMP-MIB"
142 # define IMPORT_SEPARATOR ":"
144 # define DEF_MIB_MODULES "IP-MIB:IF-MIB:TCP-MIB:UDP-MIB:SNMPv2-MIB:RFC1213-MIB:UCD-SNMP-MIB"
145 # define IMPORT_SEPARATOR ";"
148 static const gchar *mib_modules = DEF_MIB_MODULES;
149 static gboolean display_oid = TRUE;
150 static gboolean snmp_var_in_tree = TRUE;
153 static gboolean snmp_usm_auth_md5(snmp_usm_params_t* p, guint8**, guint*, gchar const**);
154 static gboolean snmp_usm_auth_sha1(snmp_usm_params_t* p, guint8**, guint*, gchar const**);
156 static tvbuff_t* snmp_usm_priv_des(snmp_usm_params_t*, tvbuff_t*, gchar const**);
157 static tvbuff_t* snmp_usm_priv_aes(snmp_usm_params_t*, tvbuff_t*, gchar const**);
160 static void snmp_usm_password_to_key_md5(const guint8 *password, guint passwordlen, const guint8 *engineID, guint engineLength, guint8 *key);
161 static void snmp_usm_password_to_key_sha1(const guint8 *password, guint passwordlen, const guint8 *engineID, guint engineLength, guint8 *key);
164 static snmp_usm_auth_model_t model_md5 = {snmp_usm_password_to_key_md5, snmp_usm_auth_md5, 16};
165 static snmp_usm_auth_model_t model_sha1 = {snmp_usm_password_to_key_sha1, snmp_usm_auth_sha1, 20};
167 static value_string auth_types[] = {
172 static snmp_usm_auth_model_t* auth_models[] = {&model_md5,&model_sha1};
175 static value_string priv_types[] = {
180 static snmp_usm_decoder_t priv_protos[] = {snmp_usm_priv_des, snmp_usm_priv_aes};
182 static snmp_ue_assoc_t* ueas = NULL;
183 static guint num_ueas = 0;
184 static uat_t* assocs_uat = NULL;
185 static snmp_ue_assoc_t* localized_ues = NULL;
186 static snmp_ue_assoc_t* unlocalized_ues = NULL;
191 static snmp_usm_params_t usm_p = {FALSE,FALSE,0,0,0,0,NULL,NULL,NULL,NULL,NULL,NULL,NULL,FALSE};
193 /* Subdissector tables */
194 static dissector_table_t variable_oid_dissector_table;
197 #define TH_CRYPT 0x02
198 #define TH_REPORT 0x04
200 /* desegmentation of SNMP-over-TCP */
201 static gboolean snmp_desegment = TRUE;
203 /* Global variables */
205 guint32 MsgSecurityModel;
206 tvbuff_t *oid_tvb=NULL;
207 tvbuff_t *value_tvb=NULL;
209 static dissector_handle_t snmp_handle;
210 static dissector_handle_t data_handle;
212 static next_tvb_list_t var_list;
214 static int hf_snmp_v3_flags_auth = -1;
215 static int hf_snmp_v3_flags_crypt = -1;
216 static int hf_snmp_v3_flags_report = -1;
218 static int hf_snmp_engineid_conform = -1;
219 static int hf_snmp_engineid_enterprise = -1;
220 static int hf_snmp_engineid_format = -1;
221 static int hf_snmp_engineid_ipv4 = -1;
222 static int hf_snmp_engineid_ipv6 = -1;
223 static int hf_snmp_engineid_mac = -1;
224 static int hf_snmp_engineid_text = -1;
225 static int hf_snmp_engineid_time = -1;
226 static int hf_snmp_engineid_data = -1;
227 static int hf_snmp_counter64 = -1;
228 static int hf_snmp_decryptedPDU = -1;
229 static int hf_snmp_msgAuthentication = -1;
230 static int hf_snmp_internet_ipv6 = -1;
231 static int hf_snmp_internet_other = -1;
233 #include "packet-snmp-hf.c"
235 static int hf_smux_version = -1;
236 static int hf_smux_pdutype = -1;
238 /* Initialize the subtree pointers */
239 static gint ett_smux = -1;
240 static gint ett_snmp = -1;
241 static gint ett_engineid = -1;
242 static gint ett_msgFlags = -1;
243 static gint ett_encryptedPDU = -1;
244 static gint ett_decrypted = -1;
245 static gint ett_authParameters = -1;
246 static gint ett_internet = -1;
248 #include "packet-snmp-ett.c"
251 static int dissect_snmp_IpAddressIpv6(gboolean, tvbuff_t* ,int , asn1_ctx_t* , proto_tree*, int);
252 static int dissect_snmp_IpAddressOther(gboolean, tvbuff_t* ,int , asn1_ctx_t* , proto_tree*, int);
254 static const true_false_string auth_flags = {
259 /* defined in net-SNMP; include/net-snmp/library/snmp.h */
262 #undef SNMP_MSG_GETNEXT
263 #undef SNMP_MSG_RESPONSE
265 #undef SNMP_MSG_GETBULK
266 #undef SNMP_MSG_INFORM
267 #undef SNMP_MSG_TRAP2
268 #undef SNMP_MSG_REPORT
269 #undef SNMP_NOSUCHOBJECT
270 #undef SNMP_NOSUCHINSTANCE
271 #undef SNMP_ENDOFMIBVIEW
273 /* Security Models */
275 #define SNMP_SEC_ANY 0
276 #define SNMP_SEC_V1 1
277 #define SNMP_SEC_V2C 2
278 #define SNMP_SEC_USM 3
280 static const value_string sec_models[] = {
281 { SNMP_SEC_ANY, "Any" },
282 { SNMP_SEC_V1, "V1" },
283 { SNMP_SEC_V2C, "V2C" },
284 { SNMP_SEC_USM, "USM" },
289 #define SMUX_MSG_OPEN 0
290 #define SMUX_MSG_CLOSE 1
291 #define SMUX_MSG_RREQ 2
292 #define SMUX_MSG_RRSP 3
293 #define SMUX_MSG_SOUT 4
295 static const value_string smux_types[] = {
296 { SMUX_MSG_OPEN, "Open" },
297 { SMUX_MSG_CLOSE, "Close" },
298 { SMUX_MSG_RREQ, "Registration Request" },
299 { SMUX_MSG_RRSP, "Registration Response" },
300 { SMUX_MSG_SOUT, "Commit Or Rollback" },
306 #define SNMP_IPA 0 /* IP Address */
307 #define SNMP_CNT 1 /* Counter (Counter32) */
308 #define SNMP_GGE 2 /* Gauge (Gauge32) */
309 #define SNMP_TIT 3 /* TimeTicks */
310 #define SNMP_OPQ 4 /* Opaque */
311 #define SNMP_NSP 5 /* NsapAddress */
312 #define SNMP_C64 6 /* Counter64 */
313 #define SNMP_U32 7 /* Uinteger32 */
322 #define SNMP_INTEGER 1 /* l */
323 #define SNMP_OCTETSTR 2 /* c */
324 #define SNMP_DISPLAYSTR 2 /* c */
325 #define SNMP_OBJECTID 3 /* ul */
326 #define SNMP_IPADDR 4 /* uc */
327 #define SNMP_COUNTER 5 /* ul */
328 #define SNMP_GAUGE 6 /* ul */
329 #define SNMP_TIMETICKS 7 /* ul */
330 #define SNMP_OPAQUE 8 /* c */
332 /* additional SNMPv2 Types */
334 #define SNMP_UINTEGER 5 /* ul */
335 #define SNMP_BITSTR 9 /* uc */
336 #define SNMP_NSAP 10 /* uc */
337 #define SNMP_COUNTER64 11 /* ul */
338 #define SNMP_NOSUCHOBJECT 12
339 #define SNMP_NOSUCHINSTANCE 13
340 #define SNMP_ENDOFMIBVIEW 14
343 typedef struct _SNMP_CNV SNMP_CNV;
353 static SNMP_CNV SnmpCnv [] =
355 {BER_CLASS_UNI, BER_UNI_TAG_NULL, SNMP_NULL, "NULL"},
356 {BER_CLASS_UNI, BER_UNI_TAG_INTEGER, SNMP_INTEGER, "INTEGER"},
357 {BER_CLASS_UNI, BER_UNI_TAG_OCTETSTRING, SNMP_OCTETSTR, "OCTET STRING"},
358 {BER_CLASS_UNI, BER_UNI_TAG_OID, SNMP_OBJECTID, "OBJECTID"},
359 {BER_CLASS_APP, SNMP_IPA, SNMP_IPADDR, "IPADDR"},
360 {BER_CLASS_APP, SNMP_CNT, SNMP_COUNTER, "COUNTER"}, /* Counter32 */
361 {BER_CLASS_APP, SNMP_GGE, SNMP_GAUGE, "GAUGE"}, /* Gauge32 == Unsigned32 */
362 {BER_CLASS_APP, SNMP_TIT, SNMP_TIMETICKS, "TIMETICKS"},
363 {BER_CLASS_APP, SNMP_OPQ, SNMP_OPAQUE, "OPAQUE"},
365 /* SNMPv2 data types and errors */
367 {BER_CLASS_UNI, BER_UNI_TAG_BITSTRING, SNMP_BITSTR, "BITSTR"},
368 {BER_CLASS_APP, SNMP_C64, SNMP_COUNTER64, "COUNTER64"},
369 {BER_CLASS_CON, SERR_NSO, SNMP_NOSUCHOBJECT, "NOSUCHOBJECT"},
370 {BER_CLASS_CON, SERR_NSI, SNMP_NOSUCHINSTANCE, "NOSUCHINSTANCE"},
371 {BER_CLASS_CON, SERR_EOM, SNMP_ENDOFMIBVIEW, "ENDOFMIBVIEW"},
376 * NAME: g_snmp_tag_cls2syntax
377 * SYNOPSIS: gboolean g_snmp_tag_cls2syntax
383 * DESCRIPTION: Converts ASN1 tag and class to Syntax tag and name.
384 * See SnmpCnv for conversion.
385 * RETURNS: name on success, NULL on failure
389 snmp_tag_cls2syntax ( guint tag, guint cls, gushort *syntax)
394 while (cnv->syntax != -1)
396 if (cnv->tag == tag && cnv->class == cls)
398 *syntax = cnv->syntax;
406 int oid_to_subid_buf(const guint8 *oid, gint oid_len, subid_t *buf, int buf_len) {
412 value=0; out_len = 0; byte =0; is_first = TRUE;
413 for (i=0; i<oid_len; i++){
414 if (out_len >= buf_len)
417 value = (value << 7) | (byte & 0x7F);
425 }else if ( value < 80 ){
435 buf[out_len++] = value;
444 format_oid(subid_t *oid, guint oid_length)
453 size_t oid_string_len;
457 result_len = oid_length * 22;
461 * Get the decoded form of the OID, and add its length to the
462 * length of the result string.
464 * XXX - check for "sprint_realloc_objid()" failure.
466 oid_string_len = 1024;
467 oid_string = ep_alloc(oid_string_len);
470 /* We pass an ep allocated block here, NOT a malloced block
471 * so we MUST NOT allow reallocation, hence the fourth
472 * parameter MUST be 0/FALSE
474 sprint_realloc_objid(&oid_string, &oid_string_len, &oid_out_len, FALSE,
476 result_len += strlen(oid_string) + 3;
479 result = ep_alloc(result_len + 1);
481 len = g_snprintf(buf, result_len + 1 - (buf-result), "%lu", (unsigned long)oid[0]);
483 for (i = 1; i < oid_length;i++) {
484 len = g_snprintf(buf, result_len + 1 - (buf-result), ".%lu", (unsigned long)oid[i]);
490 * Append the decoded form of the OID.
492 g_snprintf(buf, result_len + 1 -(buf-result), " (%s)", oid_string);
498 /* returns the decoded (can be NULL) and non_decoded OID strings */
500 new_format_oid(subid_t *oid, guint oid_length,
501 gchar **non_decoded, gchar **decoded)
509 size_t oid_string_len;
513 if (oid == NULL || oid_length < 1) {
520 * Get the decoded form of the OID, and add its length to the
521 * length of the result string.
525 * XXX - if we convert this to ep_alloc(), make sure the fourth
526 * argument to sprint_realloc_objid() is FALSE.
529 oid_string_len = 1024;
530 oid_string = ep_alloc(oid_string_len);
531 if (oid_string != NULL) {
534 /* We pass an ep allocated block here, NOT a malloced block
535 * so we MUST NOT allow reallocation, hence the fourth
536 * parameter MUST be 0/FALSE
538 sprint_realloc_objid(&oid_string, &oid_string_len, &oid_out_len, FALSE,
541 *decoded = oid_string;
546 non_decoded_len = oid_length * 22 + 1;
547 *non_decoded = ep_alloc(non_decoded_len);
549 len = g_snprintf(buf, non_decoded_len-(buf-*non_decoded), "%lu", (unsigned long)oid[0]);
551 for (i = 1; i < oid_length; i++) {
552 len = g_snprintf(buf, non_decoded_len-(buf-*non_decoded), ".%lu", (unsigned long)oid[i]);
559 check_var_length(guint vb_length, guint required_length, guchar **errmsg)
562 static const char badlen_fmt[] = "Length is %u, should be %u";
564 if (vb_length != required_length) {
565 /* Enough room for the largest "Length is XXX,
566 should be XXX" message - 10 digits for each
568 buf = ep_alloc(sizeof badlen_fmt + 10 + 10);
570 g_snprintf(buf, sizeof badlen_fmt + 10 + 10,
571 badlen_fmt, vb_length, required_length);
576 return TRUE; /* length is OK */
580 format_var(struct variable_list *variable, subid_t *variable_oid,
581 guint variable_oid_length, gushort vb_type, guint val_len)
587 if (variable_oid == NULL || variable_oid_length == 0)
593 /* Length has to be 4 bytes. */
594 if (!check_var_length(val_len, 4, &buf))
595 return buf; /* it's not 4 bytes */
599 /* not all counters are encoded as a full 64bit integer */
601 /* Length has to be 8 bytes. */
602 if (!check_var_length(val_len, 8, &buf))
603 return buf; /* it's not 8 bytes */
610 variable->next_variable = NULL;
611 variable->name = variable_oid;
612 variable->name_length = variable_oid_length;
616 variable->type = VALTYPE_INTEGER;
620 variable->type = VALTYPE_COUNTER;
624 variable->type = VALTYPE_GAUGE;
628 variable->type = VALTYPE_TIMETICKS;
632 variable->type = VALTYPE_STRING;
636 variable->type = VALTYPE_IPADDR;
640 variable->type = VALTYPE_OPAQUE;
644 variable->type = VALTYPE_NSAP;
648 variable->type = VALTYPE_OBJECTID;
652 variable->type = VALTYPE_BITSTR;
656 variable->type = VALTYPE_COUNTER64;
659 variable->val_len = val_len;
662 * XXX - check for "sprint_realloc_objid()" failure.
666 buf = ep_alloc(buf_len);
670 /* We pass an ep allocated block here, NOT a malloced block
671 * so we MUST NOT allow reallocation, hence the fourth
672 * parameter MUST be 0/FALSE
674 sprint_realloc_value(&buf, &buf_len, &out_len, FALSE,
675 variable_oid, variable_oid_length, variable);
682 #define F_SNMP_ENGINEID_CONFORM 0x80
683 #define SNMP_ENGINEID_RFC1910 0x00
684 #define SNMP_ENGINEID_RFC3411 0x01
686 static const true_false_string tfs_snmp_engineid_conform = {
688 "RFC1910 (Non-SNMPv3)"
691 #define SNMP_ENGINEID_FORMAT_IPV4 0x01
692 #define SNMP_ENGINEID_FORMAT_IPV6 0x02
693 #define SNMP_ENGINEID_FORMAT_MACADDRESS 0x03
694 #define SNMP_ENGINEID_FORMAT_TEXT 0x04
695 #define SNMP_ENGINEID_FORMAT_OCTETS 0x05
697 static const value_string snmp_engineid_format_vals[] = {
698 { SNMP_ENGINEID_FORMAT_IPV4, "IPv4 address" },
699 { SNMP_ENGINEID_FORMAT_IPV6, "IPv6 address" },
700 { SNMP_ENGINEID_FORMAT_MACADDRESS, "MAC address" },
701 { SNMP_ENGINEID_FORMAT_TEXT, "Text, administratively assigned" },
702 { SNMP_ENGINEID_FORMAT_OCTETS, "Octets, administratively assigned" },
707 * SNMP Engine ID dissection according to RFC 3411 (SnmpEngineID TC)
708 * or historic RFC 1910 (AgentID)
711 dissect_snmp_engineid(proto_tree *tree, tvbuff_t *tvb, int offset, int len)
713 proto_item *item = NULL;
714 guint8 conformance, format;
715 guint32 enterpriseid, seconds;
717 int len_remain = len;
719 /* first bit: engine id conformance */
720 if (len_remain<4) return offset;
721 conformance = ((tvb_get_guint8(tvb, offset)>>7) && 0x01);
722 proto_tree_add_item(tree, hf_snmp_engineid_conform, tvb, offset, 1, FALSE);
724 /* 4-byte enterprise number/name */
725 if (len_remain<4) return offset;
726 enterpriseid = tvb_get_ntohl(tvb, offset);
728 enterpriseid -= 0x80000000; /* ignore first bit */
729 proto_tree_add_uint(tree, hf_snmp_engineid_enterprise, tvb, offset, 4, enterpriseid);
733 switch(conformance) {
735 case SNMP_ENGINEID_RFC1910:
736 /* 12-byte AgentID w/ 8-byte trailer */
738 proto_tree_add_text(tree, tvb, offset, 8, "AgentID Trailer: 0x%s",
739 tvb_bytes_to_str(tvb, offset, 8));
743 proto_tree_add_text(tree, tvb, offset, len_remain, "<Data not conforming to RFC1910>");
748 case SNMP_ENGINEID_RFC3411: /* variable length: 5..32 */
750 /* 1-byte format specifier */
751 if (len_remain<1) return offset;
752 format = tvb_get_guint8(tvb, offset);
753 item = proto_tree_add_uint_format(tree, hf_snmp_engineid_format, tvb, offset, 1, format, "Engine ID Format: %s (%d)",
754 val_to_str(format, snmp_engineid_format_vals, "Reserved/Enterprise-specific"), format);
759 case SNMP_ENGINEID_FORMAT_IPV4:
760 /* 4-byte IPv4 address */
762 proto_tree_add_item(tree, hf_snmp_engineid_ipv4, tvb, offset, 4, FALSE);
767 case SNMP_ENGINEID_FORMAT_IPV6:
768 /* 16-byte IPv6 address */
769 if (len_remain==16) {
770 proto_tree_add_item(tree, hf_snmp_engineid_ipv6, tvb, offset, 16, FALSE);
775 case SNMP_ENGINEID_FORMAT_MACADDRESS:
776 /* 6-byte MAC address */
778 proto_tree_add_item(tree, hf_snmp_engineid_mac, tvb, offset, 6, FALSE);
783 case SNMP_ENGINEID_FORMAT_TEXT:
784 /* max. 27-byte string, administratively assigned */
785 if (len_remain<=27) {
786 proto_tree_add_item(tree, hf_snmp_engineid_text, tvb, offset, len_remain, FALSE);
792 /* most common enterprise-specific format: (ucd|net)-snmp random */
793 if ((enterpriseid==2021)||(enterpriseid==8072)) {
794 proto_item_append_text(item, (enterpriseid==2021) ? ": UCD-SNMP Random" : ": Net-SNMP Random");
795 /* demystify: 4B random, 4B epoch seconds */
797 proto_tree_add_item(tree, hf_snmp_engineid_data, tvb, offset, 4, FALSE);
798 seconds = tvb_get_letohl(tvb, offset+4);
800 proto_tree_add_time_format(tree, hf_snmp_engineid_time, tvb, offset+4, 4,
801 &ts, "Engine ID Data: Creation Time: %s",
802 abs_time_secs_to_str(seconds));
808 case SNMP_ENGINEID_FORMAT_OCTETS:
810 /* max. 27 bytes, administratively assigned or unknown format */
811 if (len_remain<=27) {
812 proto_tree_add_item(tree, hf_snmp_engineid_data, tvb, offset, len_remain, FALSE);
821 proto_tree_add_text(tree, tvb, offset, len_remain, "<Data not conforming to RFC3411>");
827 /* This code is copied from the original SNMP dissector with minor changes to adapt it to use packet-ber.c routines
829 * - Rewrite it completly as OID as subid_t could be returned from dissect_ber_objectidentifier
830 * - vb_type_name is known when calling this routine(?)
831 * - All branches not needed(?)
836 snmp_variable_decode(tvbuff_t *tvb, proto_tree *snmp_tree, packet_info *pinfo,tvbuff_t *oid_tvb,
837 int offset, guint *lengthp, tvbuff_t **out_tvb)
839 int start, vb_value_start;
843 const gchar *vb_type_name;
844 gint32 vb_integer_value;
845 guint32 vb_uinteger_value;
846 guint8 *vb_octet_string;
847 const guint8 *oid_buf;
850 gchar *vb_display_string = NULL;
851 subid_t *variable_oid = NULL;
853 guint variable_oid_length = 0;
854 const guint8 *var_oid_buf;
856 struct variable_list variable;
863 gboolean pc, ind = 0;
867 /* parse the type of the object */
868 offset = dissect_ber_identifier(pinfo, snmp_tree, tvb, start, &class, &pc, &ber_tag);
869 offset = dissect_ber_length(pinfo, snmp_tree, tvb, offset, &vb_length, &ind);
872 length = offset - start;
877 vb_value_start = offset;
879 /* Convert the class, constructed flag, and tag to a type. */
880 vb_type_name = snmp_tag_cls2syntax(ber_tag, class, &vb_type);
882 if (vb_type_name == NULL) {
885 * Dissect the value as an opaque string of octets.
887 vb_type_name = "unsupported type";
888 vb_type = SNMP_OPAQUE;
890 /* construct subid_t variable_oid from oid_tvb */
892 oid_len = tvb_length_remaining(oid_tvb,0);
893 var_oid_buf = tvb_get_ptr(oid_tvb, 0, oid_len);
894 variable_oid = ep_alloc((oid_len+1) * sizeof(gulong));
895 variable_oid_length = oid_to_subid_buf(var_oid_buf, oid_len, variable_oid, ((oid_len+1) * sizeof(gulong)));
897 /* parse the value */
901 offset = dissect_ber_integer(FALSE, pinfo, NULL, tvb, start, -1, (void*)&(vb_integer_value));
902 length = offset - vb_value_start;
905 value = vb_integer_value;
906 variable.val.integer = &value;
907 vb_display_string = format_var(&variable,
908 variable_oid, variable_oid_length, vb_type,
911 vb_display_string = NULL;
913 if (vb_display_string != NULL) {
914 proto_tree_add_text(snmp_tree, tvb,
915 vb_value_start, length,
916 "Value: %s", vb_display_string);
918 proto_tree_add_text(snmp_tree,tvb,
919 vb_value_start, length,
920 "Value: %s: %d (%#x)", vb_type_name,
921 vb_integer_value, vb_integer_value);
929 offset = dissect_ber_integer(FALSE, pinfo, NULL, tvb, start, -1, &vb_uinteger_value);
930 length = offset - vb_value_start;
933 value = vb_uinteger_value;
934 variable.val.integer = &value;
935 vb_display_string = format_var(&variable,
936 variable_oid, variable_oid_length, vb_type,
939 vb_display_string = NULL;
941 if (vb_display_string != NULL) {
942 proto_tree_add_text(snmp_tree, tvb,
943 vb_value_start, length,
944 "Value: %s", vb_display_string);
946 proto_tree_add_text(snmp_tree, tvb,
947 vb_value_start, length,
948 "Value: %s: %u (%#x)", vb_type_name,
949 vb_uinteger_value, vb_uinteger_value);
954 offset=dissect_ber_integer64(TRUE, pinfo, snmp_tree, tvb, offset, hf_snmp_counter64, NULL);
961 offset = dissect_ber_octet_string(FALSE, pinfo, NULL, tvb, start, -1, out_tvb);
962 vb_octet_string = ep_tvb_memdup(tvb, vb_value_start, vb_length);
964 length = offset - vb_value_start;
967 variable.val.string = vb_octet_string;
968 vb_display_string = format_var(&variable,
969 variable_oid, variable_oid_length, vb_type,
972 vb_display_string = NULL;
974 if (vb_display_string != NULL) {
975 proto_tree_add_text(snmp_tree, tvb,
976 vb_value_start, length,
977 "Value: %s", vb_display_string);
980 * If some characters are not printable,
981 * display the string as bytes.
983 for (i = 0; i < vb_length; i++) {
984 if (!(isprint(vb_octet_string[i])
985 || isspace(vb_octet_string[i])))
990 * We stopped, due to a non-printable
991 * character, before we got to the end
994 vb_display_string = ep_alloc(4*vb_length);
995 buf = vb_display_string;
996 len = g_snprintf(buf, 4*vb_length, "%03u", vb_octet_string[0]);
998 for (i = 1; i < vb_length; i++) {
999 len = g_snprintf(buf, 4*vb_length-(buf-vb_display_string), ".%03u",
1000 vb_octet_string[i]);
1003 proto_tree_add_text(snmp_tree, tvb, vb_value_start,
1005 "Value: %s: %s", vb_type_name,
1008 proto_tree_add_text(snmp_tree, tvb, vb_value_start,
1010 "Value: %s: %s", vb_type_name,
1011 SAFE_STRING(vb_octet_string, vb_length));
1018 dissect_ber_null(FALSE, pinfo, NULL, tvb, start, -1);
1019 length = offset - vb_value_start;
1021 proto_tree_add_text(snmp_tree, tvb, vb_value_start, length,
1022 "Value: %s", vb_type_name);
1027 /* XXX Redo this using dissect_ber_object_identifier when
1028 it returns tvb or some other binary form of an OID */
1029 oid_buf = tvb_get_ptr(tvb, vb_value_start, vb_length);
1030 vb_oid = ep_alloc((vb_length+1) * sizeof(gulong));
1031 vb_oid_length = oid_to_subid_buf(oid_buf, vb_length, vb_oid, ((vb_length+1) * sizeof(gulong)));
1033 offset = offset + vb_length;
1034 length = offset - vb_value_start;
1036 #ifdef HAVE_NET_SNMP
1037 variable.val.objid = vb_oid;
1038 vb_display_string = format_var(&variable,
1039 variable_oid, variable_oid_length, vb_type,
1040 vb_oid_length * sizeof (subid_t));
1041 if (vb_display_string != NULL) {
1042 proto_tree_add_text(snmp_tree, tvb,
1043 vb_value_start, length,
1044 "Value: %s", vb_display_string);
1046 proto_tree_add_text(snmp_tree, tvb,
1047 vb_value_start, length,
1048 "Value: %s: [Out of memory]", vb_type_name);
1050 #else /* HAVE_NET_SNMP */
1051 vb_display_string = format_oid(vb_oid, vb_oid_length);
1052 if (vb_display_string != NULL) {
1053 proto_tree_add_text(snmp_tree, tvb,
1054 vb_value_start, length,
1055 "Value: %s: %s", vb_type_name,
1058 proto_tree_add_text(snmp_tree, tvb,
1059 vb_value_start, length,
1060 "Value: %s: [Out of memory]", vb_type_name);
1062 #endif /* HAVE_NET_SNMP */
1066 case SNMP_NOSUCHOBJECT:
1067 length = offset - start;
1069 proto_tree_add_text(snmp_tree, tvb, offset, length,
1070 "Value: %s: no such object", vb_type_name);
1074 case SNMP_NOSUCHINSTANCE:
1075 length = offset - start;
1077 proto_tree_add_text(snmp_tree, tvb, offset, length,
1078 "Value: %s: no such instance", vb_type_name);
1082 case SNMP_ENDOFMIBVIEW:
1083 length = offset - start;
1085 proto_tree_add_text(snmp_tree, tvb, offset, length,
1086 "Value: %s: end of mib view", vb_type_name);
1091 DISSECTOR_ASSERT_NOT_REACHED();
1094 length = offset - start;
1101 static void set_ue_keys(snmp_ue_assoc_t* n ) {
1102 guint key_size = n->user.authModel->key_size;
1104 n->user.authKey.data = se_alloc(key_size);
1105 n->user.authKey.len = key_size;
1106 n->user.authModel->pass2key(n->user.authPassword.data,
1107 n->user.authPassword.len,
1110 n->user.authKey.data);
1112 n->user.privKey.data = se_alloc(key_size);
1113 n->user.privKey.len = key_size;
1114 n->user.authModel->pass2key(n->user.privPassword.data,
1115 n->user.privPassword.len,
1118 n->user.privKey.data);
1121 static snmp_ue_assoc_t* ue_se_dup(snmp_ue_assoc_t* o) {
1122 snmp_ue_assoc_t* d = se_memdup(o,sizeof(snmp_ue_assoc_t));
1124 d->user.authModel = o->user.authModel;
1126 d->user.privProtocol = o->user.privProtocol;
1128 d->user.userName.data = se_memdup(o->user.userName.data,o->user.userName.len);
1129 d->user.userName.len = o->user.userName.len;
1131 d->user.authPassword.data = o->user.authPassword.data ? se_memdup(o->user.authPassword.data,o->user.authPassword.len) : NULL;
1132 d->user.authPassword.len = o->user.authPassword.len;
1134 d->user.privPassword.data = o->user.privPassword.data ? se_memdup(o->user.privPassword.data,o->user.privPassword.len) : NULL;
1135 d->user.privPassword.len = o->user.privPassword.len;
1137 d->engine.len = o->engine.len;
1139 if (d->engine.len) {
1140 d->engine.data = se_memdup(o->engine.data,o->engine.len);
1149 #define CACHE_INSERT(c,a) if (c) { snmp_ue_assoc_t* t = c; c = a; c->next = t; } else { c = a; a->next = NULL; }
1151 static void renew_ue_cache(void) {
1155 localized_ues = NULL;
1156 unlocalized_ues = NULL;
1158 for(i = 0; i < num_ueas; i++) {
1159 snmp_ue_assoc_t* a = ue_se_dup(&(ueas[i]));
1161 if (a->engine.len) {
1162 CACHE_INSERT(localized_ues,a);
1165 CACHE_INSERT(unlocalized_ues,a);
1170 localized_ues = NULL;
1171 unlocalized_ues = NULL;
1176 static snmp_ue_assoc_t* localize_ue( snmp_ue_assoc_t* o, const guint8* engine, guint engine_len ) {
1177 snmp_ue_assoc_t* n = se_memdup(o,sizeof(snmp_ue_assoc_t));
1179 n->engine.data = se_memdup(engine,engine_len);
1180 n->engine.len = engine_len;
1188 #define localized_match(a,u,ul,e,el) \
1189 ( a->user.userName.len == ul \
1190 && a->engine.len == el \
1191 && memcmp( a->user.userName.data, u, (a->user.userName.len < ul) ? a->user.userName.len : ul ) == 0 \
1192 && memcmp( a->engine.data, e, (a->engine.len < el) ? a->engine.len : el ) == 0 )
1194 #define unlocalized_match(a,u,l) \
1195 ( a->user.userName.len == l && memcmp( a->user.userName.data, u, a->user.userName.len < l ? a->user.userName.len : l) == 0 )
1197 static snmp_ue_assoc_t* get_user_assoc(tvbuff_t* engine_tvb, tvbuff_t* user_tvb) {
1198 static snmp_ue_assoc_t* a;
1199 guint given_username_len;
1200 guint8* given_username;
1201 guint given_engine_len;
1202 guint8* given_engine;
1204 if ( ! (localized_ues || unlocalized_ues ) ) return NULL;
1206 if (! ( user_tvb && engine_tvb ) ) return NULL;
1208 given_username_len = tvb_length_remaining(user_tvb,0);
1209 given_username = ep_tvb_memdup(user_tvb,0,-1);
1210 given_engine_len = tvb_length_remaining(engine_tvb,0);
1211 given_engine = ep_tvb_memdup(engine_tvb,0,-1);
1213 for (a = localized_ues; a; a = a->next) {
1214 if ( localized_match(a, given_username, given_username_len, given_engine, given_engine_len) ) {
1219 for (a = unlocalized_ues; a; a = a->next) {
1220 if ( unlocalized_match(a, given_username, given_username_len) ) {
1221 snmp_ue_assoc_t* n = localize_ue( a, given_engine, given_engine_len );
1222 CACHE_INSERT(localized_ues,n);
1230 static gboolean snmp_usm_auth_md5(snmp_usm_params_t* p, guint8** calc_auth_p, guint* calc_auth_len_p, gchar const** error) {
1237 guint8 calc_auth[16];
1243 *error = "No Authenticator";
1247 key = p->user_assoc->user.authKey.data;
1248 key_len = p->user_assoc->user.authKey.len;
1251 *error = "User has no authKey";
1256 auth_len = tvb_length_remaining(p->auth_tvb,0);
1258 if (auth_len != 12) {
1259 *error = "Authenticator length wrong";
1263 msg_len = tvb_length_remaining(p->msg_tvb,0);
1264 msg = ep_tvb_memdup(p->msg_tvb,0,msg_len);
1267 auth = ep_tvb_memdup(p->auth_tvb,0,auth_len);
1269 start = p->auth_offset - p->start_offset;
1270 end = start + auth_len;
1272 /* fill the authenticator with zeros */
1273 for ( i = start ; i < end ; i++ ) {
1277 md5_hmac(msg, msg_len, key, key_len, calc_auth);
1279 if (calc_auth_p) *calc_auth_p = calc_auth;
1280 if (calc_auth_len_p) *calc_auth_len_p = 12;
1282 return ( memcmp(auth,calc_auth,12) != 0 ) ? FALSE : TRUE;
1286 static gboolean snmp_usm_auth_sha1(snmp_usm_params_t* p _U_, guint8** calc_auth_p, guint* calc_auth_len_p, gchar const** error _U_) {
1293 guint8 calc_auth[20];
1299 *error = "No Authenticator";
1303 key = p->user_assoc->user.authKey.data;
1304 key_len = p->user_assoc->user.authKey.len;
1307 *error = "User has no authKey";
1312 auth_len = tvb_length_remaining(p->auth_tvb,0);
1315 if (auth_len != 12) {
1316 *error = "Authenticator length wrong";
1320 msg_len = tvb_length_remaining(p->msg_tvb,0);
1321 msg = ep_tvb_memdup(p->msg_tvb,0,msg_len);
1323 auth = ep_tvb_memdup(p->auth_tvb,0,auth_len);
1325 start = p->auth_offset - p->start_offset;
1326 end = start + auth_len;
1328 /* fill the authenticator with zeros */
1329 for ( i = start ; i < end ; i++ ) {
1333 sha1_hmac(key, key_len, msg, msg_len, calc_auth);
1335 if (calc_auth_p) *calc_auth_p = calc_auth;
1336 if (calc_auth_len_p) *calc_auth_len_p = 12;
1338 return ( memcmp(auth,calc_auth,12) != 0 ) ? FALSE : TRUE;
1341 static tvbuff_t* snmp_usm_priv_des(snmp_usm_params_t* p _U_, tvbuff_t* encryptedData _U_, gchar const** error _U_) {
1342 #ifdef HAVE_LIBGCRYPT
1344 gcry_cipher_hd_t hd = NULL;
1347 guint8* des_key = p->user_assoc->user.privKey.data; /* first 8 bytes */
1348 guint8* pre_iv = &(p->user_assoc->user.privKey.data[8]); /* last 8 bytes */
1353 tvbuff_t* clear_tvb;
1358 salt_len = tvb_length_remaining(p->priv_tvb,0);
1360 if (salt_len != 8) {
1361 *error = "decryptionError: msgPrivacyParameters lenght != 8";
1365 salt = ep_tvb_memdup(p->priv_tvb,0,salt_len);
1368 The resulting "salt" is XOR-ed with the pre-IV to obtain the IV.
1370 for (i=0; i<8; i++) {
1371 iv[i] = pre_iv[i] ^ salt[i];
1374 cryptgrm_len = tvb_length_remaining(encryptedData,0);
1376 if (cryptgrm_len % 8) {
1377 *error = "decryptionError: the length of the encrypted data is not a mutiple of 8 octets";
1381 cryptgrm = ep_tvb_memdup(encryptedData,0,-1);
1383 cleartext = ep_alloc(cryptgrm_len);
1385 err = gcry_cipher_open(&hd, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_CBC, 0);
1386 if (err != GPG_ERR_NO_ERROR) goto on_gcry_error;
1388 err = gcry_cipher_setiv(hd, iv, 8);
1389 if (err != GPG_ERR_NO_ERROR) goto on_gcry_error;
1391 err = gcry_cipher_setkey(hd,des_key,8);
1392 if (err != GPG_ERR_NO_ERROR) goto on_gcry_error;
1394 err = gcry_cipher_decrypt(hd, cleartext, cryptgrm_len, cryptgrm, cryptgrm_len);
1395 if (err != GPG_ERR_NO_ERROR) goto on_gcry_error;
1397 gcry_cipher_close(hd);
1399 clear_tvb = tvb_new_real_data(cleartext, cryptgrm_len, cryptgrm_len);
1404 *error = (void*)gpg_strerror(err);
1405 if (hd) gcry_cipher_close(hd);
1408 *error = "libgcrypt not present, cannot decrypt";
1413 static tvbuff_t* snmp_usm_priv_aes(snmp_usm_params_t* p _U_, tvbuff_t* encryptedData _U_, gchar const** error _U_) {
1414 #ifdef HAVE_LIBGCRYPT
1416 gcry_cipher_hd_t hd = NULL;
1419 guint8* aes_key = p->user_assoc->user.privKey.data; /* first 16 bytes */
1424 tvbuff_t* clear_tvb;
1426 priv_len = tvb_length_remaining(p->priv_tvb,0);
1428 if (priv_len != 8) {
1429 *error = "decryptionError: msgPrivacyParameters lenght != 8";
1433 iv[0] = (p->boots & 0xff000000) >> 24;
1434 iv[1] = (p->boots & 0x00ff0000) >> 16;
1435 iv[2] = (p->boots & 0x0000ff00) >> 8;
1436 iv[3] = (p->boots & 0x000000ff);
1437 iv[4] = (p->time & 0xff000000) >> 24;
1438 iv[5] = (p->time & 0x00ff0000) >> 16;
1439 iv[6] = (p->time & 0x0000ff00) >> 8;
1440 iv[7] = (p->time & 0x000000ff);
1441 tvb_memcpy(p->priv_tvb,&(iv[8]),0,8);
1443 cryptgrm_len = tvb_length_remaining(encryptedData,0);
1444 cryptgrm = ep_tvb_memdup(encryptedData,0,-1);
1446 cleartext = ep_alloc(cryptgrm_len);
1448 err = gcry_cipher_open(&hd, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_CFB, 0);
1449 if (err != GPG_ERR_NO_ERROR) goto on_gcry_error;
1451 err = gcry_cipher_setiv(hd, iv, 16);
1452 if (err != GPG_ERR_NO_ERROR) goto on_gcry_error;
1454 err = gcry_cipher_setkey(hd,aes_key,16);
1455 if (err != GPG_ERR_NO_ERROR) goto on_gcry_error;
1457 err = gcry_cipher_decrypt(hd, cleartext, cryptgrm_len, cryptgrm, cryptgrm_len);
1458 if (err != GPG_ERR_NO_ERROR) goto on_gcry_error;
1460 gcry_cipher_close(hd);
1462 clear_tvb = tvb_new_real_data(cleartext, cryptgrm_len, cryptgrm_len);
1467 *error = (void*)gpg_strerror(err);
1468 if (hd) gcry_cipher_close(hd);
1471 *error = "libgcrypt not present, cannot decrypt";
1477 gboolean check_ScopedPdu(tvbuff_t* tvb) {
1482 int hoffset, eoffset;
1485 offset = get_ber_identifier(tvb, 0, &class, &pc, &tag);
1486 offset = get_ber_length(NULL, tvb, offset, NULL, NULL);
1488 if ( ! (((class!=BER_CLASS_APP) && (class!=BER_CLASS_PRI) )
1489 && ( (!pc) || (class!=BER_CLASS_UNI) || (tag!=BER_UNI_TAG_ENUMERATED) )
1492 if((tvb_get_guint8(tvb, offset)==0)&&(tvb_get_guint8(tvb, offset+1)==0))
1497 offset = get_ber_identifier(tvb, offset, &class, &pc, &tag);
1498 offset = get_ber_length(NULL, tvb, offset, &len, NULL);
1499 eoffset = offset + len;
1501 if (eoffset <= hoffset) return FALSE;
1503 if ((class!=BER_CLASS_APP)&&(class!=BER_CLASS_PRI))
1504 if( (class!=BER_CLASS_UNI)
1505 ||((tag<BER_UNI_TAG_NumericString)&&(tag!=BER_UNI_TAG_OCTETSTRING)&&(tag!=BER_UNI_TAG_UTF8String)) )
1512 #include "packet-snmp-fn.c"
1516 dissect_snmp_pdu(tvbuff_t *tvb, int offset, packet_info *pinfo,
1517 proto_tree *tree, int proto, gint ett, gboolean is_tcp)
1520 guint length_remaining;
1522 gboolean pc, ind = 0;
1525 guint message_length;
1526 int start_offset = offset;
1527 guint32 version = 0;
1529 proto_tree *snmp_tree = NULL;
1530 proto_item *item = NULL;
1531 asn1_ctx_t asn1_ctx;
1532 asn1_ctx_init(&asn1_ctx, ASN1_ENC_BER, TRUE, pinfo);
1535 usm_p.msg_tvb = tvb;
1536 usm_p.start_offset = offset_from_real_beginning(tvb,0) ;
1537 usm_p.engine_tvb = NULL;
1538 usm_p.user_tvb = NULL;
1539 usm_p.auth_item = NULL;
1540 usm_p.auth_tvb = NULL;
1541 usm_p.auth_offset = 0;
1542 usm_p.priv_tvb = NULL;
1543 usm_p.user_assoc = NULL;
1544 usm_p.authenticated = FALSE;
1545 usm_p.encrypted = FALSE;
1548 usm_p.authOK = FALSE;
1551 * This will throw an exception if we don't have any data left.
1552 * That's what we want. (See "tcp_dissect_pdus()", which is
1553 * similar, but doesn't have to deal with ASN.1.
1554 * XXX - can we make "tcp_dissect_pdus()" provide enough
1555 * information to the "get_pdu_len" routine so that we could
1556 * have that routine deal with ASN.1, and just use
1557 * "tcp_dissect_pdus()"?)
1559 length_remaining = tvb_ensure_length_remaining(tvb, offset);
1561 /* NOTE: we have to parse the message piece by piece, since the
1562 * capture length may be less than the message length: a 'global'
1563 * parsing is likely to fail.
1567 * If this is SNMP-over-TCP, we might have to do reassembly
1568 * in order to read the "Sequence Of" header.
1570 if (is_tcp && snmp_desegment && pinfo->can_desegment) {
1572 * This is TCP, and we should, and can, do reassembly.
1574 * Is the "Sequence Of" header split across segment
1575 * boundaries? We requre at least 6 bytes for the
1576 * header, which allows for a 4-byte length (ASN.1
1579 if (length_remaining < 6) {
1580 pinfo->desegment_offset = offset;
1581 pinfo->desegment_len = 6 - length_remaining;
1584 * Return 0, which means "I didn't dissect anything
1585 * because I don't have enough data - we need
1593 * OK, try to read the "Sequence Of" header; this gets the total
1594 * length of the SNMP message.
1596 /* Set tree to 0 to not display internakl BER fields if option used.*/
1597 offset = dissect_ber_identifier(pinfo, 0, tvb, offset, &class, &pc, &tag);
1598 offset = dissect_ber_length(pinfo, 0, tvb, offset, &len, &ind);
1600 message_length = len + 2;
1601 offset = dissect_ber_integer(FALSE, pinfo, 0, tvb, offset, -1, &version);
1605 * If this is SNMP-over-TCP, we might have to do reassembly
1606 * to get all of this message.
1608 if (is_tcp && snmp_desegment && pinfo->can_desegment) {
1610 * Yes - is the message split across segment boundaries?
1612 if (length_remaining < message_length) {
1614 * Yes. Tell the TCP dissector where the data
1615 * for this message starts in the data it handed
1616 * us, and how many more bytes we need, and
1619 pinfo->desegment_offset = start_offset;
1620 pinfo->desegment_len =
1621 message_length - length_remaining;
1624 * Return 0, which means "I didn't dissect anything
1625 * because I don't have enough data - we need
1632 next_tvb_init(&var_list);
1634 if (check_col(pinfo->cinfo, COL_PROTOCOL)) {
1635 col_set_str(pinfo->cinfo, COL_PROTOCOL,
1636 proto_get_protocol_short_name(find_protocol_by_id(proto)));
1640 item = proto_tree_add_item(tree, proto, tvb, offset,
1641 message_length, FALSE);
1642 snmp_tree = proto_item_add_subtree(item, ett);
1648 offset = dissect_snmp_Message(FALSE , tvb, start_offset, &asn1_ctx, snmp_tree, -1);
1651 offset = dissect_snmp_Messagev2u(FALSE , tvb, start_offset, &asn1_ctx, snmp_tree, -1);
1655 offset = dissect_snmp_SNMPv3Message(FALSE , tvb, start_offset, &asn1_ctx, snmp_tree, -1);
1659 * Return the length remaining in the tvbuff, so
1660 * if this is SNMP-over-TCP, our caller thinks there's
1661 * nothing left to dissect.
1663 proto_tree_add_text(snmp_tree, tvb, offset, -1,"Unknown version");
1664 return length_remaining;
1668 next_tvb_call(&var_list, pinfo, tree, NULL, data_handle);
1674 dissect_snmp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1676 conversation_t *conversation;
1685 * See if this looks like SNMP or not. if not, return 0 so
1686 * wireshark can try som other dissector instead.
1688 /* All SNMP packets are BER encoded and consist of a SEQUENCE
1689 * that spans the entire PDU. The first item is an INTEGER that
1690 * has the values 0-2 (version 1-3).
1691 * if not it is not snmp.
1693 /* SNMP starts with a SEQUENCE */
1694 offset = get_ber_identifier(tvb, 0, &tmp_class, &tmp_pc, &tmp_tag);
1695 if((tmp_class!=BER_CLASS_UNI)||(tmp_tag!=BER_UNI_TAG_SEQUENCE)){
1698 /* then comes a length which spans the rest of the tvb */
1699 offset = get_ber_length(NULL, tvb, offset, &tmp_length, &tmp_ind);
1700 if(tmp_length!=(guint32)tvb_reported_length_remaining(tvb, offset)){
1703 /* then comes an INTEGER (version)*/
1704 offset = get_ber_identifier(tvb, offset, &tmp_class, &tmp_pc, &tmp_tag);
1705 if((tmp_class!=BER_CLASS_UNI)||(tmp_tag!=BER_UNI_TAG_INTEGER)){
1708 /* do we need to test that version is 0 - 2 (version1-3) ? */
1712 * The first SNMP packet goes to the SNMP port; the second one
1713 * may come from some *other* port, but goes back to the same
1714 * IP address and port as the ones from which the first packet
1715 * came; all subsequent packets presumably go between those two
1716 * IP addresses and ports.
1718 * If this packet went to the SNMP port, we check to see if
1719 * there's already a conversation with one address/port pair
1720 * matching the source IP address and port of this packet,
1721 * the other address matching the destination IP address of this
1722 * packet, and any destination port.
1724 * If not, we create one, with its address 1/port 1 pair being
1725 * the source address/port of this packet, its address 2 being
1726 * the destination address of this packet, and its port 2 being
1727 * wildcarded, and give it the SNMP dissector as a dissector.
1729 if (pinfo->destport == UDP_PORT_SNMP) {
1730 conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, PT_UDP,
1731 pinfo->srcport, 0, NO_PORT_B);
1732 if( (conversation == NULL) || (conversation->dissector_handle!=snmp_handle) ){
1733 conversation = conversation_new(pinfo->fd->num, &pinfo->src, &pinfo->dst, PT_UDP,
1734 pinfo->srcport, 0, NO_PORT2);
1735 conversation_set_dissector(conversation, snmp_handle);
1739 return dissect_snmp_pdu(tvb, 0, pinfo, tree, proto_snmp, ett_snmp, FALSE);
1742 dissect_snmp_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1747 while (tvb_reported_length_remaining(tvb, offset) > 0) {
1748 message_len = dissect_snmp_pdu(tvb, 0, pinfo, tree,
1749 proto_snmp, ett_snmp, TRUE);
1750 if (message_len == 0) {
1752 * We don't have all the data for that message,
1753 * so we need to do desegmentation;
1754 * "dissect_snmp_pdu()" has set that up.
1758 offset += message_len;
1763 dissect_smux(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1765 proto_tree *smux_tree = NULL;
1766 proto_item *item = NULL;
1768 if (check_col(pinfo->cinfo, COL_PROTOCOL))
1769 col_set_str(pinfo->cinfo, COL_PROTOCOL, "SMUX");
1772 item = proto_tree_add_item(tree, proto_smux, tvb, 0, -1, FALSE);
1773 smux_tree = proto_item_add_subtree(item, ett_smux);
1776 dissect_SMUX_PDUs_PDU(tvb, pinfo, tree);
1781 MD5 Password to Key Algorithm
1784 static void snmp_usm_password_to_key_md5(const guint8 *password,
1786 const guint8 *engineID,
1790 guint8 *cp, password_buf[64];
1791 guint32 password_index = 0;
1792 guint32 count = 0, i;
1794 md5_init(&MD); /* initialize MD5 */
1796 /**********************************************/
1797 /* Use while loop until we've done 1 Megabyte */
1798 /**********************************************/
1799 while (count < 1048576) {
1801 for (i = 0; i < 64; i++) {
1802 /*************************************************/
1803 /* Take the next octet of the password, wrapping */
1804 /* to the beginning of the password as necessary.*/
1805 /*************************************************/
1806 *cp++ = password[password_index++ % passwordlen];
1808 md5_append(&MD, password_buf, 64);
1811 md5_finish(&MD, key1); /* tell MD5 we're done */
1813 /*****************************************************/
1814 /* Now localize the key with the engineID and pass */
1815 /* through MD5 to produce final key */
1816 /* May want to ensure that engineLength <= 32, */
1817 /* otherwise need to use a buffer larger than 64 */
1818 /*****************************************************/
1821 md5_append(&MD, key1, 16);
1822 md5_append(&MD, engineID, engineLength);
1823 md5_append(&MD, key1, 16);
1824 md5_finish(&MD, key);
1833 SHA1 Password to Key Algorithm COPIED from RFC 3414 A.2.2
1836 static void snmp_usm_password_to_key_sha1(const guint8 *password,
1838 const guint8 *engineID,
1842 guint8 *cp, password_buf[72];
1843 guint32 password_index = 0;
1844 guint32 count = 0, i;
1846 sha1_starts(&SH); /* initialize SHA */
1848 /**********************************************/
1849 /* Use while loop until we've done 1 Megabyte */
1850 /**********************************************/
1851 while (count < 1048576) {
1853 for (i = 0; i < 64; i++) {
1854 /*************************************************/
1855 /* Take the next octet of the password, wrapping */
1856 /* to the beginning of the password as necessary.*/
1857 /*************************************************/
1858 *cp++ = password[password_index++ % passwordlen];
1860 sha1_update (&SH, password_buf, 64);
1863 sha1_finish(&SH, key);
1865 /*****************************************************/
1866 /* Now localize the key with the engineID and pass */
1867 /* through SHA to produce final key */
1868 /* May want to ensure that engineLength <= 32, */
1869 /* otherwise need to use a buffer larger than 72 */
1870 /*****************************************************/
1871 memcpy(password_buf, key, 20);
1872 memcpy(password_buf+20, engineID, engineLength);
1873 memcpy(password_buf+20+engineLength, key, 20);
1876 sha1_update(&SH, password_buf, 40+engineLength);
1877 sha1_finish(&SH, key);
1885 #ifdef HAVE_NET_SNMP
1886 gchar *tmp_mib_modules;
1887 static gboolean mibs_loaded = FALSE;
1891 * Unload the MIBs, as we'll be reloading them based on
1892 * the current preference setting.
1894 shutdown_mib(); /* unload MIBs */
1898 * Cannot check if MIBS is already set, as it could be set by Wireshark.
1900 * If we have a list of modules to load, put that list in MIBS,
1901 * otherwise clear MIBS.
1903 if (mib_modules != NULL) {
1904 tmp_mib_modules = g_strconcat("MIBS=", mib_modules, NULL);
1906 * Try to be clever and replace colons for semicolons under
1907 * Windows. Do the converse on non-Windows systems. This
1908 * handles cases where we've copied a preferences file
1909 * between a non-Windows box and a Windows box or upgraded
1910 * from an older version of Wireshark under Windows.
1912 g_strdelimit(tmp_mib_modules, IMPORT_SEPARATOR, ENV_SEPARATOR_CHAR);
1915 _putenv(tmp_mib_modules);
1917 putenv(tmp_mib_modules);
1930 register_mib_handlers();
1931 read_premib_configs();
1935 #endif /* HAVE_NET_SNMP */
1939 static void* snmp_users_copy_cb(void* dest, const void* orig, unsigned len _U_) {
1940 const snmp_ue_assoc_t* o = orig;
1941 snmp_ue_assoc_t* d = dest;
1943 d->auth_model = o->auth_model;
1944 d->user.authModel = auth_models[o->auth_model];
1946 d->priv_proto = o->priv_proto;
1947 d->user.privProtocol = priv_protos[o->priv_proto];
1949 d->user.userName.data = g_memdup(o->user.userName.data,o->user.userName.len);
1950 d->user.userName.len = o->user.userName.len;
1952 d->user.authPassword.data = o->user.authPassword.data ? g_memdup(o->user.authPassword.data,o->user.authPassword.len) : NULL;
1953 d->user.authPassword.len = o->user.authPassword.len;
1955 d->user.privPassword.data = o->user.privPassword.data ? g_memdup(o->user.privPassword.data,o->user.privPassword.len) : NULL;
1956 d->user.privPassword.len = o->user.privPassword.len;
1958 d->engine.len = o->engine.len;
1959 if (o->engine.data) {
1960 d->engine.data = g_memdup(o->engine.data,o->engine.len);
1963 d->user.authKey.data = o->user.authKey.data ? g_memdup(o->user.authKey.data,o->user.authKey.len) : NULL;
1964 d->user.authKey.len = o->user.authKey.len;
1966 d->user.privKey.data = o->user.privKey.data ? g_memdup(o->user.privKey.data,o->user.privKey.len) : NULL;
1967 d->user.privKey.len = o->user.privKey.len;
1972 static void snmp_users_free_cb(void* p) {
1973 snmp_ue_assoc_t* ue = p;
1974 if (ue->user.userName.data) g_free(ue->user.userName.data);
1975 if (ue->user.authPassword.data) g_free(ue->user.authPassword.data);
1976 if (ue->user.privPassword.data) g_free(ue->user.privPassword.data);
1977 if (ue->user.authKey.data) g_free(ue->user.authKey.data);
1978 if (ue->user.privKey.data) g_free(ue->user.privKey.data);
1979 if (ue->engine.data) g_free(ue->engine.data);
1982 static void snmp_users_update_cb(void* p _U_, const char** err) {
1983 snmp_ue_assoc_t* ue = p;
1984 GString* es = g_string_new("");
1988 if (! ue->user.userName.len) g_string_append(es,"no userName, ");
1989 if (ue->user.authPassword.len < 8) g_string_sprintfa(es,"short authPassword (%d), ", ue->user.authPassword.len);
1990 if (ue->user.privPassword.len < 8) g_string_sprintfa(es,"short privPassword (%d), ", ue->user.privPassword.len);
1993 g_string_truncate(es,es->len-2);
1994 *err = ep_strdup(es->str);
1997 g_string_free(es,TRUE);
2002 UAT_LSTRING_CB_DEF(snmp_users,userName,snmp_ue_assoc_t,user.userName.data,user.userName.len)
2003 UAT_LSTRING_CB_DEF(snmp_users,authPassword,snmp_ue_assoc_t,user.authPassword.data,user.authPassword.len)
2004 UAT_LSTRING_CB_DEF(snmp_users,privPassword,snmp_ue_assoc_t,user.privPassword.data,user.privPassword.len)
2005 UAT_BUFFER_CB_DEF(snmp_users,engine_id,snmp_ue_assoc_t,engine.data,engine.len)
2006 UAT_VS_DEF(snmp_users,auth_model,snmp_ue_assoc_t,0,"MD5")
2007 UAT_VS_DEF(snmp_users,priv_proto,snmp_ue_assoc_t,0,"DES")
2010 /*--- proto_register_snmp -------------------------------------------*/
2011 void proto_register_snmp(void) {
2012 #if defined(_WIN32) && defined(HAVE_NET_SNMP)
2015 #define MIB_PATH_APPEND "snmp\\mibs"
2017 gchar *tmp_mib_modules;
2019 /* List of fields */
2020 static hf_register_info hf[] = {
2021 { &hf_snmp_v3_flags_auth,
2022 { "Authenticated", "snmp.v3.flags.auth", FT_BOOLEAN, 8,
2023 TFS(&flags_set_truth), TH_AUTH, "", HFILL }},
2024 { &hf_snmp_v3_flags_crypt,
2025 { "Encrypted", "snmp.v3.flags.crypt", FT_BOOLEAN, 8,
2026 TFS(&flags_set_truth), TH_CRYPT, "", HFILL }},
2027 { &hf_snmp_v3_flags_report,
2028 { "Reportable", "snmp.v3.flags.report", FT_BOOLEAN, 8,
2029 TFS(&flags_set_truth), TH_REPORT, "", HFILL }},
2030 { &hf_snmp_engineid_conform, {
2031 "Engine ID Conformance", "snmp.engineid.conform", FT_BOOLEAN, 8,
2032 TFS(&tfs_snmp_engineid_conform), F_SNMP_ENGINEID_CONFORM, "Engine ID RFC3411 Conformance", HFILL }},
2033 { &hf_snmp_engineid_enterprise, {
2034 "Engine Enterprise ID", "snmp.engineid.enterprise", FT_UINT32, BASE_DEC,
2035 VALS(sminmpec_values), 0, "Engine Enterprise ID", HFILL }},
2036 { &hf_snmp_engineid_format, {
2037 "Engine ID Format", "snmp.engineid.format", FT_UINT8, BASE_DEC,
2038 VALS(snmp_engineid_format_vals), 0, "Engine ID Format", HFILL }},
2039 { &hf_snmp_engineid_ipv4, {
2040 "Engine ID Data: IPv4 address", "snmp.engineid.ipv4", FT_IPv4, BASE_NONE,
2041 NULL, 0, "Engine ID Data: IPv4 address", HFILL }},
2042 { &hf_snmp_engineid_ipv6, {
2043 "Engine ID Data: IPv6 address", "snmp.engineid.ipv6", FT_IPv6, BASE_NONE,
2044 NULL, 0, "Engine ID Data: IPv6 address", HFILL }},
2045 { &hf_snmp_engineid_mac, {
2046 "Engine ID Data: MAC address", "snmp.engineid.mac", FT_ETHER, BASE_NONE,
2047 NULL, 0, "Engine ID Data: MAC address", HFILL }},
2048 { &hf_snmp_engineid_text, {
2049 "Engine ID Data: Text", "snmp.engineid.text", FT_STRING, BASE_NONE,
2050 NULL, 0, "Engine ID Data: Text", HFILL }},
2051 { &hf_snmp_engineid_time, {
2052 "Engine ID Data: Time", "snmp.engineid.time", FT_ABSOLUTE_TIME, BASE_NONE,
2053 NULL, 0, "Engine ID Data: Time", HFILL }},
2054 { &hf_snmp_engineid_data, {
2055 "Engine ID Data", "snmp.engineid.data", FT_BYTES, BASE_HEX,
2056 NULL, 0, "Engine ID Data", HFILL }},
2057 { &hf_snmp_counter64, {
2058 "Value", "snmp.counter64", FT_INT64, BASE_DEC,
2059 NULL, 0, "A counter64 value", HFILL }},
2060 { &hf_snmp_msgAuthentication,
2061 { "Authentication", "snmp.v3.auth", FT_BOOLEAN, 8,
2062 TFS(&auth_flags), 0, "", HFILL }},
2063 { &hf_snmp_decryptedPDU, {
2064 "Decrypted ScopedPDU", "snmp.decrypted_pdu", FT_BYTES, BASE_HEX,
2065 NULL, 0, "Decrypted PDU", HFILL }},
2066 { &hf_snmp_internet_ipv6, {
2067 "internet", "snmp.internet", FT_IPv6, BASE_NONE,
2068 NULL, 0, "", HFILL }},
2069 { &hf_snmp_internet_other, {
2070 "internet", "snmp.internet", FT_BYTES, BASE_NONE,
2071 NULL, 0, "", HFILL }},
2072 #include "packet-snmp-hfarr.c"
2075 /* List of subtrees */
2076 static gint *ett[] = {
2082 &ett_authParameters,
2085 #include "packet-snmp-ettarr.c"
2087 module_t *snmp_module;
2088 static uat_field_t fields[] = {
2089 UAT_FLD_BUFFER(snmp_users,engine_id,"Engine-id for this entry (empty = any)"),
2090 UAT_FLD_LSTRING(snmp_users,userName,"The username"),
2091 UAT_FLD_VS(snmp_users,auth_model,auth_types,"Algorithm to be used for authentication."),
2092 UAT_FLD_LSTRING(snmp_users,authPassword,"The password used for authenticating packets for this entry"),
2093 UAT_FLD_VS(snmp_users,priv_proto,priv_types,"Algorithm to be used for privacy."),
2094 UAT_FLD_LSTRING(snmp_users,privPassword,"The password used for encrypting packets for this entry"),
2098 assocs_uat = uat_new("SNMP Users",
2099 sizeof(snmp_ue_assoc_t),
2104 "ChSNMPUsersSection",
2106 snmp_users_update_cb,
2110 #ifdef HAVE_NET_SNMP
2113 /* Set MIBDIRS so that the SNMP library can find its mibs. */
2114 /* XXX - Should we set MIBS or MIBFILES as well? */
2115 mib_path_len=strlen(get_datafile_dir()) + strlen(MIB_PATH_APPEND) + 20;
2116 mib_path = ep_alloc (mib_path_len);
2117 g_snprintf (mib_path, mib_path_len, "MIBDIRS=%s\\%s", get_datafile_dir(), MIB_PATH_APPEND);
2118 /* Amazingly enough, Windows does not provide setenv(). */
2119 if (getenv("MIBDIRS") == NULL)
2125 * Suppress warnings about unknown tokens - we aren't initializing
2126 * Net-SNMP in its entirety, we're just initializing the
2127 * MIB-handling part because that's all we're using, which
2128 * means that entries in the configuration file for other
2129 * pars of the library will not be handled, and we don't want
2130 * the config file reading code to whine about that.
2132 netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID,
2133 NETSNMP_DS_LIB_NO_TOKEN_WARNINGS, TRUE);
2134 netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID,
2135 NETSNMP_DS_LIB_PRINT_SUFFIX_ONLY, 2);
2136 #endif /* HAVE_NET_SNMP */
2139 /* Register protocol */
2140 proto_snmp = proto_register_protocol(PNAME, PSNAME, PFNAME);
2141 new_register_dissector("snmp", dissect_snmp, proto_snmp);
2143 /* Register fields and subtrees */
2144 proto_register_field_array(proto_snmp, hf, array_length(hf));
2145 proto_register_subtree_array(ett, array_length(ett));
2148 /* Register configuration preferences */
2149 snmp_module = prefs_register_protocol(proto_snmp, process_prefs);
2150 prefs_register_bool_preference(snmp_module, "display_oid",
2151 "Show SNMP OID in info column",
2152 "Whether the SNMP OID should be shown in the info column",
2156 * Set the default value of "mib_modules".
2158 * If the MIBS environment variable is set, make its value
2159 * the value of "mib_modules", otherwise, set "mib_modules"
2160 * to DEF_MIB_MODULES.
2162 tmp_mib_modules = getenv("MIBS");
2163 if (tmp_mib_modules != NULL)
2164 mib_modules = tmp_mib_modules;
2165 prefs_register_string_preference(snmp_module, "mib_modules",
2166 "MIB modules to load",
2167 "List of MIB modules to load (the list is set to environment variable MIBS if the variable is not already set)"
2168 "The list must be separated by colons (:) on non-Windows systems and semicolons (;) on Windows systems",
2170 prefs_register_bool_preference(snmp_module, "desegment",
2171 "Reassemble SNMP-over-TCP messages\nspanning multiple TCP segments",
2172 "Whether the SNMP dissector should reassemble messages spanning multiple TCP segments."
2173 " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
2176 prefs_register_bool_preference(snmp_module, "var_in_tree",
2177 "Display dissected variables inside SNMP tree",
2178 "ON - display dissected variables inside SNMP tree, OFF - display dissected variables in root tree after SNMP",
2181 prefs_register_obsolete_preference(snmp_module, "users_file");
2183 prefs_register_uat_preference(snmp_module, "users_table",
2185 "Table of engine-user associations used for authentication and decryption",
2188 variable_oid_dissector_table =
2189 register_dissector_table("snmp.variable_oid",
2190 "SNMP Variable OID", FT_STRING, BASE_NONE);
2192 register_init_routine(renew_ue_cache);
2196 /*--- proto_reg_handoff_snmp ---------------------------------------*/
2197 void proto_reg_handoff_snmp(void) {
2198 dissector_handle_t snmp_tcp_handle;
2200 snmp_handle = find_dissector("snmp");
2202 dissector_add("udp.port", UDP_PORT_SNMP, snmp_handle);
2203 dissector_add("udp.port", UDP_PORT_SNMP_TRAP, snmp_handle);
2204 dissector_add("ethertype", ETHERTYPE_SNMP, snmp_handle);
2205 dissector_add("ipx.socket", IPX_SOCKET_SNMP_AGENT, snmp_handle);
2206 dissector_add("ipx.socket", IPX_SOCKET_SNMP_SINK, snmp_handle);
2207 dissector_add("hpext.dxsap", HPEXT_SNMP, snmp_handle);
2209 snmp_tcp_handle = create_dissector_handle(dissect_snmp_tcp, proto_snmp);
2210 dissector_add("tcp.port", TCP_PORT_SNMP, snmp_tcp_handle);
2211 dissector_add("tcp.port", TCP_PORT_SNMP_TRAP, snmp_tcp_handle);
2213 data_handle = find_dissector("data");
2216 * Process preference settings.
2218 * We can't do this in the register routine, as preferences aren't
2219 * read until all dissector register routines have been called (so
2220 * that all dissector preferences have been registered).
2227 proto_register_smux(void)
2229 static hf_register_info hf[] = {
2231 { "Version", "smux.version", FT_UINT8, BASE_DEC, NULL,
2234 { "PDU type", "smux.pdutype", FT_UINT8, BASE_DEC, VALS(smux_types),
2237 static gint *ett[] = {
2241 proto_smux = proto_register_protocol("SNMP Multiplex Protocol",
2243 proto_register_field_array(proto_smux, hf, array_length(hf));
2244 proto_register_subtree_array(ett, array_length(ett));
2249 proto_reg_handoff_smux(void)
2251 dissector_handle_t smux_handle;
2253 smux_handle = create_dissector_handle(dissect_smux, proto_smux);
2254 dissector_add("tcp.port", TCP_PORT_SMUX, smux_handle);