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.
11 * $Id: packet-snmp.c,v 1.78 2002/01/21 07:36:43 guy Exp $
13 * Ethereal - Network traffic analyzer
14 * By Gerald Combs <gerald@ethereal.com>
15 * Copyright 1998 Gerald Combs
19 * GXSNMP -- An snmp mangament application
20 * Copyright (C) 1998 Gregory McLean & Jochen Friedrich
21 * Beholder RMON ethernet network monitor,Copyright (C) 1993 DNPAP group
23 * This program is free software; you can redistribute it and/or
24 * modify it under the terms of the GNU General Public License
25 * as published by the Free Software Foundation; either version 2
26 * of the License, or (at your option) any later version.
28 * This program is distributed in the hope that it will be useful,
29 * but WITHOUT ANY WARRANTY; without even the implied warranty of
30 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
31 * GNU General Public License for more details.
33 * You should have received a copy of the GNU General Public License
34 * along with this program; if not, write to the Free Software
35 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
46 #ifdef HAVE_SYS_TYPES_H
47 # include <sys/types.h>
50 #ifdef HAVE_NETINET_IN_H
51 # include <netinet/in.h>
54 #define MAX_STRING_LEN 2048 /* TBC */
62 #include <epan/packet.h>
63 #include <epan/strutil.h>
64 #include <epan/conversation.h>
66 #include "packet-ipx.h"
68 #if defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H)
72 # if defined(HAVE_UCD_SNMP_SNMP_H)
76 # include <ucd-snmp/asn1.h>
77 # include <ucd-snmp/snmp_api.h>
78 # include <ucd-snmp/snmp_impl.h>
79 # include <ucd-snmp/mib.h>
82 * Sigh. UCD SNMP 4.1.1 makes "snmp_set_suffix_only()" a macro
83 * that calls "ds_set_int()" with the first two arguments
84 * being DS_LIBRARY_ID and DS_LIB_PRINT_SUFFIX_ONLY; this means that,
85 * when building with 4.1.1, we need to arrange that
86 * <ucd-snmp/default_store.h> is included, to define those two values
87 * and to declare "ds_int()".
91 * 1) we can't include it on earlier versions (at least not 3.6.2),
92 * as it doesn't exist in those versions;
94 * 2) we don't want to include <ucd-snmp/ucd-snmp-includes.h>,
95 * as that includes <ucd-snmp/snmp.h>, and that defines a whole
96 * bunch of values that we also define ourselves.
98 * So we only include it if "snmp_set_suffix_only" is defined as
101 # ifdef snmp_set_suffix_only
102 # include <ucd-snmp/default_store.h>
106 * XXX - for now, we assume all versions of UCD SNMP have it.
108 # define HAVE_SPRINT_VALUE
111 * Define values "sprint_value()" expects.
113 # define VALTYPE_INTEGER ASN_INTEGER
114 # define VALTYPE_COUNTER ASN_COUNTER
115 # define VALTYPE_GAUGE ASN_GAUGE
116 # define VALTYPE_TIMETICKS ASN_TIMETICKS
117 # define VALTYPE_STRING ASN_OCTET_STR
118 # define VALTYPE_IPADDR ASN_IPADDRESS
119 # define VALTYPE_OPAQUE ASN_OPAQUE
120 # define VALTYPE_NSAP ASN_NSAP
121 # define VALTYPE_OBJECTID ASN_OBJECT_ID
122 # define VALTYPE_BITSTR ASN_BIT_STR
123 # define VALTYPE_COUNTER64 ASN_COUNTER64
125 # ifdef RED_HAT_MODIFIED_UCD_SNMP
126 # include <ucd-snmp/parse.h>
130 # elif defined(HAVE_SNMP_SNMP_H)
134 # include <snmp/snmp.h>
137 * Some older versions of CMU SNMP may lack these values (e.g., the
138 * "libsnmp3.6" package for Debian, which is based on some old
139 * CMU SNMP, perhaps 1.0); for now, we assume they also lack
143 # define HAVE_SPRINT_VALUE
145 * Define values "sprint_value()" expects.
147 # define VALTYPE_INTEGER SMI_INTEGER
148 # define VALTYPE_COUNTER SMI_COUNTER32
149 # define VALTYPE_GAUGE SMI_GAUGE32
150 # define VALTYPE_TIMETICKS SMI_TIMETICKS
151 # define VALTYPE_STRING SMI_STRING
152 # define VALTYPE_IPADDR SMI_IPADDRESS
153 # define VALTYPE_OPAQUE SMI_OPAQUE
154 # define VALTYPE_NSAP SMI_STRING
155 # define VALTYPE_OBJECTID SMI_OBJID
156 # define VALTYPE_BITSTR ASN_BIT_STR
157 # define VALTYPE_COUNTER64 SMI_COUNTER64
160 * Now undo all the definitions they "helpfully" gave us, so we don't get
161 * complaints about redefining them.
163 * Why, oh why, is there no library that provides code to
167 * 2) translate object IDs into names;
169 * 3) let you find out, for a given object ID, what the type, enum
170 * values, display hint, etc. are;
172 * in a *simple* fashion, without assuming that your code is part of an
173 * SNMP agent or client that wants a pile of definitions of PDU types,
174 * etc.? Is it just that 99 44/100% of the code that uses an SNMP library
175 * *is* part of an agent or client, and really *does* need that stuff,
176 * and *doesn't* need the interfaces we want?
178 # undef SNMP_ERR_NOERROR
179 # undef SNMP_ERR_TOOBIG
180 # undef SNMP_ERR_NOSUCHNAME
181 # undef SNMP_ERR_BADVALUE
182 # undef SNMP_ERR_READONLY
183 # undef SNMP_ERR_NOACCESS
184 # undef SNMP_ERR_WRONGTYPE
185 # undef SNMP_ERR_WRONGLENGTH
186 # undef SNMP_ERR_WRONGENCODING
187 # undef SNMP_ERR_WRONGVALUE
188 # undef SNMP_ERR_NOCREATION
189 # undef SNMP_ERR_INCONSISTENTVALUE
190 # undef SNMP_ERR_RESOURCEUNAVAILABLE
191 # undef SNMP_ERR_COMMITFAILED
192 # undef SNMP_ERR_UNDOFAILED
193 # undef SNMP_ERR_AUTHORIZATIONERROR
194 # undef SNMP_ERR_NOTWRITABLE
195 # undef SNMP_ERR_INCONSISTENTNAME
196 # undef SNMP_TRAP_COLDSTART
197 # undef SNMP_TRAP_WARMSTART
198 # undef SNMP_TRAP_LINKDOWN
199 # undef SNMP_TRAP_LINKUP
200 # undef SNMP_TRAP_EGPNEIGHBORLOSS
201 # undef SNMP_TRAP_ENTERPRISESPECIFIC
207 #include "packet-snmp.h"
209 /* Null string of type "guchar[]". */
210 static const guchar nullstring[] = "";
212 /* Take a pointer that may be null and return a pointer that's not null
213 by turning null pointers into pointers to the above null string. */
214 #define SAFE_STRING(s) (((s) != NULL) ? (s) : nullstring)
216 static int proto_snmp = -1;
217 static int proto_smux = -1;
219 static gint ett_snmp = -1;
220 static gint ett_smux = -1;
221 static gint ett_parameters = -1;
222 static gint ett_parameters_qos = -1;
223 static gint ett_global = -1;
224 static gint ett_flags = -1;
225 static gint ett_secur = -1;
227 static int hf_snmpv3_flags = -1;
228 static int hf_snmpv3_flags_auth = -1;
229 static int hf_snmpv3_flags_crypt = -1;
230 static int hf_snmpv3_flags_report = -1;
232 static dissector_handle_t snmp_handle;
233 static dissector_handle_t data_handle;
236 #define TH_CRYPT 0x02
237 #define TH_REPORT 0x04
239 static const true_false_string flags_set_truth = {
244 #define UDP_PORT_SNMP 161
245 #define UDP_PORT_SNMP_TRAP 162
246 #define TCP_PORT_SMUX 199
248 /* Protocol version numbers */
249 #define SNMP_VERSION_1 0
250 #define SNMP_VERSION_2c 1
251 #define SNMP_VERSION_2u 2
252 #define SNMP_VERSION_3 3
254 static const value_string versions[] = {
255 { SNMP_VERSION_1, "1" },
256 { SNMP_VERSION_2c, "2C" },
257 { SNMP_VERSION_2u, "2U" },
258 { SNMP_VERSION_3, "3" },
263 #define SNMP_MSG_GET 0
264 #define SNMP_MSG_GETNEXT 1
265 #define SNMP_MSG_RESPONSE 2
266 #define SNMP_MSG_SET 3
267 #define SNMP_MSG_TRAP 4
269 #define SNMP_MSG_GETBULK 5
270 #define SNMP_MSG_INFORM 6
271 #define SNMP_MSG_TRAP2 7
272 #define SNMP_MSG_REPORT 8
274 static const value_string pdu_types[] = {
275 { SNMP_MSG_GET, "GET" },
276 { SNMP_MSG_GETNEXT, "GET-NEXT" },
277 { SNMP_MSG_SET, "SET" },
278 { SNMP_MSG_RESPONSE, "RESPONSE" },
279 { SNMP_MSG_TRAP, "TRAP-V1" },
280 { SNMP_MSG_GETBULK, "GETBULK" },
281 { SNMP_MSG_INFORM, "INFORM" },
282 { SNMP_MSG_TRAP2, "TRAP-V2" },
283 { SNMP_MSG_REPORT, "REPORT" },
288 #define SMUX_MSG_OPEN 0
289 #define SMUX_MSG_CLOSE 1
290 #define SMUX_MSG_RREQ 2
291 #define SMUX_MSG_RRSP 3
292 #define SMUX_MSG_SOUT 4
294 static const value_string smux_types[] = {
295 { SMUX_MSG_OPEN, "Open" },
296 { SMUX_MSG_CLOSE, "Close" },
297 { SMUX_MSG_RREQ, "Registration Request" },
298 { SMUX_MSG_RRSP, "Registration Response" },
299 { SMUX_MSG_SOUT, "Commit Or Rollback" },
303 /* SMUX Closing causes */
304 #define SMUX_CLOSE_DOWN 0
305 #define SMUX_CLOSE_VERSION 1
306 #define SMUX_CLOSE_PACKET 2
307 #define SMUX_CLOSE_PROTOCOL 3
308 #define SMUX_CLOSE_INTERNAL 4
309 #define SMUX_CLOSE_NOAUTH 5
311 static const value_string smux_close[] = {
312 { SMUX_CLOSE_DOWN, "Going down" },
313 { SMUX_CLOSE_VERSION, "Unsupported Version" },
314 { SMUX_CLOSE_PACKET, "Packet Format Error" },
315 { SMUX_CLOSE_PROTOCOL, "Protocol Error" },
316 { SMUX_CLOSE_INTERNAL, "Internal Error" },
317 { SMUX_CLOSE_NOAUTH, "Unauthorized" },
321 /* SMUX Request codes */
322 #define SMUX_RREQ_DELETE 0
323 #define SMUX_RREQ_READONLY 1
324 #define SMUX_RREQ_READWRITE 2
326 static const value_string smux_rreq[] = {
327 { SMUX_RREQ_DELETE, "Delete" },
328 { SMUX_RREQ_READONLY, "Read Only" },
329 { SMUX_RREQ_READWRITE, "Read Write" },
333 static const value_string smux_prio[] = {
338 /* SMUX SOut codes */
339 #define SMUX_SOUT_COMMIT 0
340 #define SMUX_SOUT_ROLLBACK 1
342 static const value_string smux_sout[] = {
343 { SMUX_SOUT_COMMIT, "Commit" },
344 { SMUX_SOUT_ROLLBACK, "Rollback" },
348 /* Error status values */
349 #define SNMP_ERR_NOERROR 0
350 #define SNMP_ERR_TOOBIG 1
351 #define SNMP_ERR_NOSUCHNAME 2
352 #define SNMP_ERR_BADVALUE 3
353 #define SNMP_ERR_READONLY 4
354 #define SNMP_ERR_GENERROR 5
356 #define SNMP_ERR_NOACCESS 6
357 #define SNMP_ERR_WRONGTYPE 7
358 #define SNMP_ERR_WRONGLENGTH 8
359 #define SNMP_ERR_WRONGENCODING 9
360 #define SNMP_ERR_WRONGVALUE 10
361 #define SNMP_ERR_NOCREATION 11
362 #define SNMP_ERR_INCONSISTENTVALUE 12
363 #define SNMP_ERR_RESOURCEUNAVAILABLE 13
364 #define SNMP_ERR_COMMITFAILED 14
365 #define SNMP_ERR_UNDOFAILED 15
366 #define SNMP_ERR_AUTHORIZATIONERROR 16
367 #define SNMP_ERR_NOTWRITABLE 17
368 #define SNMP_ERR_INCONSISTENTNAME 18
370 static const value_string error_statuses[] = {
371 { SNMP_ERR_NOERROR, "NO ERROR" },
372 { SNMP_ERR_TOOBIG, "TOOBIG" },
373 { SNMP_ERR_NOSUCHNAME, "NO SUCH NAME" },
374 { SNMP_ERR_BADVALUE, "BAD VALUE" },
375 { SNMP_ERR_READONLY, "READ ONLY" },
376 { SNMP_ERR_GENERROR, "GENERIC ERROR" },
377 { SNMP_ERR_NOACCESS, "NO ACCESS" },
378 { SNMP_ERR_WRONGTYPE, "WRONG TYPE" },
379 { SNMP_ERR_WRONGLENGTH, "WRONG LENGTH" },
380 { SNMP_ERR_WRONGENCODING, "WRONG ENCODING" },
381 { SNMP_ERR_WRONGVALUE, "WRONG VALUE" },
382 { SNMP_ERR_NOCREATION, "NO CREATION" },
383 { SNMP_ERR_INCONSISTENTVALUE, "INCONSISTENT VALUE" },
384 { SNMP_ERR_RESOURCEUNAVAILABLE, "RESOURCE UNAVAILABLE" },
385 { SNMP_ERR_COMMITFAILED, "COMMIT FAILED" },
386 { SNMP_ERR_UNDOFAILED, "UNDO FAILED" },
387 { SNMP_ERR_AUTHORIZATIONERROR, "AUTHORIZATION ERROR" },
388 { SNMP_ERR_NOTWRITABLE, "NOT WRITABLE" },
389 { SNMP_ERR_INCONSISTENTNAME, "INCONSISTENT NAME" },
393 /* General SNMP V1 Traps */
395 #define SNMP_TRAP_COLDSTART 0
396 #define SNMP_TRAP_WARMSTART 1
397 #define SNMP_TRAP_LINKDOWN 2
398 #define SNMP_TRAP_LINKUP 3
399 #define SNMP_TRAP_AUTHFAIL 4
400 #define SNMP_TRAP_EGPNEIGHBORLOSS 5
401 #define SNMP_TRAP_ENTERPRISESPECIFIC 6
403 static const value_string trap_types[] = {
404 { SNMP_TRAP_COLDSTART, "COLD START" },
405 { SNMP_TRAP_WARMSTART, "WARM START" },
406 { SNMP_TRAP_LINKDOWN, "LINK DOWN" },
407 { SNMP_TRAP_LINKUP, "LINK UP" },
408 { SNMP_TRAP_AUTHFAIL, "AUTHENTICATION FAILED" },
409 { SNMP_TRAP_EGPNEIGHBORLOSS, "EGP NEIGHBORLOSS" },
410 { SNMP_TRAP_ENTERPRISESPECIFIC, "ENTERPRISE SPECIFIC" },
414 /* Security Models */
416 #define SNMP_SEC_ANY 0
417 #define SNMP_SEC_V1 1
418 #define SNMP_SEC_V2C 2
419 #define SNMP_SEC_USM 3
421 static const value_string sec_models[] = {
422 { SNMP_SEC_ANY, "Any" },
423 { SNMP_SEC_V1, "V1" },
424 { SNMP_SEC_V2C, "V2C" },
425 { SNMP_SEC_USM, "USM" },
431 #define SNMP_IPA 0 /* IP Address */
432 #define SNMP_CNT 1 /* Counter (Counter32) */
433 #define SNMP_GGE 2 /* Gauge (Gauge32) */
434 #define SNMP_TIT 3 /* TimeTicks */
435 #define SNMP_OPQ 4 /* Opaque */
436 #define SNMP_NSP 5 /* NsapAddress */
437 #define SNMP_C64 6 /* Counter64 */
438 #define SNMP_U32 7 /* Uinteger32 */
447 #define SNMP_INTEGER 1 /* l */
448 #define SNMP_OCTETSTR 2 /* c */
449 #define SNMP_DISPLAYSTR 2 /* c */
450 #define SNMP_OBJECTID 3 /* ul */
451 #define SNMP_IPADDR 4 /* uc */
452 #define SNMP_COUNTER 5 /* ul */
453 #define SNMP_GAUGE 6 /* ul */
454 #define SNMP_TIMETICKS 7 /* ul */
455 #define SNMP_OPAQUE 8 /* c */
457 /* additional SNMPv2 Types */
459 #define SNMP_UINTEGER 5 /* ul */
460 #define SNMP_BITSTR 9 /* uc */
461 #define SNMP_NSAP 10 /* uc */
462 #define SNMP_COUNTER64 11 /* ul */
463 #define SNMP_NOSUCHOBJECT 12
464 #define SNMP_NOSUCHINSTANCE 13
465 #define SNMP_ENDOFMIBVIEW 14
467 typedef struct _SNMP_CNV SNMP_CNV;
477 static SNMP_CNV SnmpCnv [] =
479 {ASN1_UNI, ASN1_NUL, SNMP_NULL, "NULL"},
480 {ASN1_UNI, ASN1_INT, SNMP_INTEGER, "INTEGER"},
481 {ASN1_UNI, ASN1_OTS, SNMP_OCTETSTR, "OCTET STRING"},
482 {ASN1_UNI, ASN1_OJI, SNMP_OBJECTID, "OBJECTID"},
483 {ASN1_APL, SNMP_IPA, SNMP_IPADDR, "IPADDR"},
484 {ASN1_APL, SNMP_CNT, SNMP_COUNTER, "COUNTER"}, /* Counter32 */
485 {ASN1_APL, SNMP_GGE, SNMP_GAUGE, "GAUGE"}, /* Gauge32 == Unsigned32 */
486 {ASN1_APL, SNMP_TIT, SNMP_TIMETICKS, "TIMETICKS"},
487 {ASN1_APL, SNMP_OPQ, SNMP_OPAQUE, "OPAQUE"},
489 /* SNMPv2 data types and errors */
491 {ASN1_UNI, ASN1_BTS, SNMP_BITSTR, "BITSTR"},
492 {ASN1_APL, SNMP_C64, SNMP_COUNTER64, "COUNTER64"},
493 {ASN1_CTX, SERR_NSO, SNMP_NOSUCHOBJECT, "NOSUCHOBJECT"},
494 {ASN1_CTX, SERR_NSI, SNMP_NOSUCHINSTANCE, "NOSUCHINSTANCE"},
495 {ASN1_CTX, SERR_EOM, SNMP_ENDOFMIBVIEW, "ENDOFMIBVIEW"},
500 * NAME: g_snmp_tag_cls2syntax
501 * SYNOPSIS: gboolean g_snmp_tag_cls2syntax
507 * DESCRIPTION: Converts ASN1 tag and class to Syntax tag and name.
508 * See SnmpCnv for conversion.
509 * RETURNS: name on success, NULL on failure
513 snmp_tag_cls2syntax ( guint tag, guint cls, gushort *syntax)
518 while (cnv->syntax != -1)
520 if (cnv->tag == tag && cnv->class == cls)
522 *syntax = cnv->syntax;
531 dissect_snmp_parse_error(tvbuff_t *tvb, int offset, packet_info *pinfo,
532 proto_tree *tree, const char *field_name, int ret)
538 case ASN1_ERR_EOC_MISMATCH:
539 errstr = "EOC mismatch";
542 case ASN1_ERR_WRONG_TYPE:
543 errstr = "Wrong type for that item";
546 case ASN1_ERR_LENGTH_NOT_DEFINITE:
547 errstr = "Length was indefinite";
550 case ASN1_ERR_LENGTH_MISMATCH:
551 errstr = "Length mismatch";
554 case ASN1_ERR_WRONG_LENGTH_FOR_TYPE:
555 errstr = "Wrong length for that item's type";
559 errstr = "Unknown error";
563 if (check_col(pinfo->cinfo, COL_INFO)) {
564 col_add_fstr(pinfo->cinfo, COL_INFO,
565 "ERROR: Couldn't parse %s: %s", field_name, errstr);
568 proto_tree_add_text(tree, tvb, offset, 0,
569 "ERROR: Couldn't parse %s: %s", field_name, errstr);
570 call_dissector(data_handle,tvb_new_subset(tvb, offset,-1,tvb_reported_length_remaining(tvb,offset)), pinfo, tree);
575 dissect_snmp_error(tvbuff_t *tvb, int offset, packet_info *pinfo,
576 proto_tree *tree, const char *message)
578 if (check_col(pinfo->cinfo, COL_INFO))
579 col_add_str(pinfo->cinfo, COL_INFO, message);
582 proto_tree_add_text(tree, tvb, offset, 0, "%s", message);
583 call_dissector(data_handle,tvb_new_subset(tvb, offset,-1,tvb_reported_length_remaining(tvb,offset)), pinfo, tree);
588 format_oid(subid_t *oid, guint oid_length)
596 result_len = oid_length * 22;
597 result = g_malloc(result_len + 1);
599 len = sprintf(buf, "%lu", (unsigned long)oid[0]);
601 for (i = 1; i < oid_length;i++) {
602 len = sprintf(buf, ".%lu", (unsigned long)oid[i]);
608 #ifdef HAVE_SPRINT_VALUE
610 format_var(struct variable_list *variable, subid_t *variable_oid,
611 guint variable_oid_length, gushort vb_type, guint vb_length)
621 /* We don't know how long this will be, but let's guess it
622 fits within 128 characters; that should be enough for an
623 integral value plus some sort of type indication. */
633 /* We don't know how long this will be, but let's guess it
634 fits within 128 characters plus 4 characters per octet. */
635 buf = g_malloc(128 + 4*vb_length);
639 /* We don't know how long this will be, but let's guess it
640 fits within 128 characters plus 32 characters per subid
641 (10 digits plus period, or a subid name). */
642 buf = g_malloc(1024 + 32*vb_length);
646 /* Should not happen. */
647 g_assert_not_reached();
652 variable->next_variable = NULL;
653 variable->name = variable_oid;
654 variable->name_length = variable_oid_length;
658 variable->type = VALTYPE_INTEGER;
662 variable->type = VALTYPE_COUNTER;
666 variable->type = VALTYPE_GAUGE;
670 variable->type = VALTYPE_TIMETICKS;
674 variable->type = VALTYPE_STRING;
678 variable->type = VALTYPE_IPADDR;
682 variable->type = VALTYPE_OPAQUE;
686 variable->type = VALTYPE_NSAP;
690 variable->type = VALTYPE_OBJECTID;
691 vb_length *= sizeof (subid_t); /* XXX - necessary? */
695 variable->type = VALTYPE_BITSTR;
699 variable->type = VALTYPE_COUNTER64;
702 variable->val_len = vb_length;
704 # ifdef RED_HAT_MODIFIED_UCD_SNMP
705 sprint_value(binit(NULL, buf, sizeof(buf)), variable_oid,
706 variable_oid_length, variable);
708 sprint_value(buf, variable_oid, variable_oid_length, variable);
715 snmp_variable_decode(proto_tree *snmp_tree, subid_t *variable_oid,
716 guint variable_oid_length, ASN1_SCK *asn1, int offset, guint *lengthp,
728 gint32 vb_integer_value;
729 guint32 vb_uinteger_value;
731 guint8 *vb_octet_string;
736 gchar *vb_display_string;
738 #ifdef HAVE_SPRINT_VALUE
739 struct variable_list variable;
740 #if defined(HAVE_UCD_SNMP_SNMP_H)
743 #endif /* HAVE_SPRINT_VALUE */
748 /* parse the type of the object */
749 start = asn1->offset;
750 ret = asn1_header_decode (asn1, &cls, &con, &tag, &def, &vb_length);
751 if (ret != ASN1_ERR_NOERROR)
754 return ASN1_ERR_LENGTH_NOT_DEFINITE;
756 /* Convert the class, constructed flag, and tag to a type. */
757 vb_type_name = snmp_tag_cls2syntax(tag, cls, &vb_type);
758 if (vb_type_name == NULL) {
761 * Dissect the value as an opaque string of octets.
763 vb_type_name = "unsupported type";
764 vb_type = SNMP_OPAQUE;
767 /* parse the value */
771 ret = asn1_int32_value_decode(asn1, vb_length,
773 if (ret != ASN1_ERR_NOERROR)
775 length = asn1->offset - start;
777 #ifdef HAVE_SPRINT_VALUE
779 #if defined(HAVE_UCD_SNMP_SNMP_H)
780 value = vb_integer_value;
781 variable.val.integer = &value;
782 #elif defined(HAVE_SNMP_SNMP_H)
783 variable.val.integer = &vb_integer_value;
785 vb_display_string = format_var(&variable,
786 variable_oid, variable_oid_length, vb_type,
788 proto_tree_add_text(snmp_tree, asn1->tvb, offset,
790 "Value: %s", vb_display_string);
791 g_free(vb_display_string);
792 break; /* we added formatted version to the tree */
794 #endif /* HAVE_SPRINT_VALUE */
795 proto_tree_add_text(snmp_tree, asn1->tvb, offset, length,
796 "Value: %s: %d (%#x)", vb_type_name,
797 vb_integer_value, vb_integer_value);
804 ret = asn1_uint32_value_decode(asn1, vb_length,
806 if (ret != ASN1_ERR_NOERROR)
808 length = asn1->offset - start;
810 #ifdef HAVE_SPRINT_VALUE
812 #if defined(HAVE_UCD_SNMP_SNMP_H)
813 value = vb_uinteger_value;
814 variable.val.integer = &value;
815 #elif defined(HAVE_SNMP_SNMP_H)
816 variable.val.integer = &vb_uinteger_value;
818 vb_display_string = format_var(&variable,
819 variable_oid, variable_oid_length, vb_type,
821 proto_tree_add_text(snmp_tree, asn1->tvb, offset,
823 "Value: %s", vb_display_string);
824 g_free(vb_display_string);
825 break; /* we added formatted version to the tree */
827 #endif /* HAVE_SPRINT_VALUE */
828 proto_tree_add_text(snmp_tree, asn1->tvb, offset, length,
829 "Value: %s: %u (%#x)", vb_type_name,
830 vb_uinteger_value, vb_uinteger_value);
840 ret = asn1_string_value_decode (asn1, vb_length,
842 if (ret != ASN1_ERR_NOERROR)
844 length = asn1->offset - start;
846 #ifdef HAVE_SPRINT_VALUE
848 variable.val.string = vb_octet_string;
849 vb_display_string = format_var(&variable,
850 variable_oid, variable_oid_length, vb_type,
852 proto_tree_add_text(snmp_tree, asn1->tvb, offset,
854 "Value: %s", vb_display_string);
855 g_free(vb_display_string);
856 break; /* we added formatted version to the tree */
858 #endif /* HAVE_SPRINT_VALUE */
860 * If some characters are not printable, display
861 * the string as bytes.
863 for (i = 0; i < vb_length; i++) {
864 if (!(isprint(vb_octet_string[i])
865 || isspace(vb_octet_string[i])))
870 * We stopped, due to a non-printable
871 * character, before we got to the end
874 vb_display_string = g_malloc(4*vb_length);
875 buf = &vb_display_string[0];
876 len = sprintf(buf, "%03u", vb_octet_string[0]);
878 for (i = 1; i < vb_length; i++) {
879 len = sprintf(buf, ".%03u",
883 proto_tree_add_text(snmp_tree, asn1->tvb, offset, length,
884 "Value: %s: %s", vb_type_name,
886 g_free(vb_display_string);
888 proto_tree_add_text(snmp_tree, asn1->tvb, offset, length,
889 "Value: %s: %.*s", vb_type_name,
891 SAFE_STRING(vb_octet_string));
894 g_free(vb_octet_string);
898 ret = asn1_null_decode (asn1, vb_length);
899 if (ret != ASN1_ERR_NOERROR)
901 length = asn1->offset - start;
903 proto_tree_add_text(snmp_tree, asn1->tvb, offset, length,
904 "Value: %s", vb_type_name);
909 ret = asn1_oid_value_decode (asn1, vb_length, &vb_oid,
911 if (ret != ASN1_ERR_NOERROR)
913 length = asn1->offset - start;
915 #ifdef HAVE_SPRINT_VALUE
917 variable.val.objid = vb_oid;
918 vb_display_string = format_var(&variable,
919 variable_oid, variable_oid_length, vb_type,
921 proto_tree_add_text(snmp_tree, asn1->tvb, offset,
923 "Value: %s", vb_display_string);
924 break; /* we added formatted version to the tree */
926 #endif /* HAVE_SPRINT_VALUE */
927 vb_display_string = format_oid(vb_oid, vb_oid_length);
928 proto_tree_add_text(snmp_tree, asn1->tvb, offset, length,
929 "Value: %s: %s", vb_type_name, vb_display_string);
930 g_free(vb_display_string);
935 case SNMP_NOSUCHOBJECT:
936 length = asn1->offset - start;
938 proto_tree_add_text(snmp_tree, asn1->tvb, offset, length,
939 "Value: %s: no such object", vb_type_name);
943 case SNMP_NOSUCHINSTANCE:
944 length = asn1->offset - start;
946 proto_tree_add_text(snmp_tree, asn1->tvb, offset, length,
947 "Value: %s: no such instance", vb_type_name);
951 case SNMP_ENDOFMIBVIEW:
952 length = asn1->offset - start;
954 proto_tree_add_text(snmp_tree, asn1->tvb, offset, length,
955 "Value: %s: end of mib view", vb_type_name);
960 g_assert_not_reached();
961 return ASN1_ERR_WRONG_TYPE;
964 return ASN1_ERR_NOERROR;
968 dissect_common_pdu(tvbuff_t *tvb, int offset, packet_info *pinfo,
969 proto_tree *tree, ASN1_SCK asn1, guint pdu_type, int start)
973 guint sequence_length;
977 guint32 error_status;
981 char *pdu_type_string;
984 guint enterprise_length;
986 guint8 *agent_address;
987 guint agent_address_length;
991 guint32 specific_type;
994 guint timestamp_length;
998 guint variable_bindings_length;
1001 guint variable_length;
1002 subid_t *variable_oid;
1003 guint variable_oid_length;
1004 #if defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H)
1005 gchar vb_oid_string[MAX_STRING_LEN]; /* TBC */
1010 guint cls, con, tag;
1012 pdu_type_string = val_to_str(pdu_type, pdu_types,
1013 "Unknown PDU type %#x");
1014 if (check_col(pinfo->cinfo, COL_INFO))
1015 col_add_str(pinfo->cinfo, COL_INFO, pdu_type_string);
1016 length = asn1.offset - start;
1018 proto_tree_add_text(tree, tvb, offset, length,
1019 "PDU type: %s", pdu_type_string);
1023 /* get the fields in the PDU preceeding the variable-bindings sequence */
1027 case SNMP_MSG_GETNEXT:
1028 case SNMP_MSG_RESPONSE:
1030 case SNMP_MSG_GETBULK:
1031 case SNMP_MSG_INFORM:
1032 case SNMP_MSG_TRAP2:
1033 case SNMP_MSG_REPORT:
1035 ret = asn1_uint32_decode (&asn1, &request_id, &length);
1036 if (ret != ASN1_ERR_NOERROR) {
1037 dissect_snmp_parse_error(tvb, offset, pinfo, tree,
1042 proto_tree_add_text(tree, tvb, offset, length,
1043 "Request Id: %#x", request_id);
1047 /* error status, or getbulk non-repeaters */
1048 ret = asn1_uint32_decode (&asn1, &error_status, &length);
1049 if (ret != ASN1_ERR_NOERROR) {
1050 dissect_snmp_parse_error(tvb, offset, pinfo, tree,
1051 (pdu_type == SNMP_MSG_GETBULK) ? "non-repeaters"
1057 if (pdu_type == SNMP_MSG_GETBULK) {
1058 proto_tree_add_text(tree, tvb, offset,
1059 length, "Non-repeaters: %u", error_status);
1061 proto_tree_add_text(tree, tvb, offset,
1062 length, "Error Status: %s",
1063 val_to_str(error_status, error_statuses,
1069 /* error index, or getbulk max-repetitions */
1070 ret = asn1_uint32_decode (&asn1, &error_index, &length);
1071 if (ret != ASN1_ERR_NOERROR) {
1072 dissect_snmp_parse_error(tvb, offset, pinfo, tree,
1073 (pdu_type == SNMP_MSG_GETBULK) ? "max repetitions"
1079 if (pdu_type == SNMP_MSG_GETBULK) {
1080 proto_tree_add_text(tree, tvb, offset,
1081 length, "Max repetitions: %u", error_index);
1083 proto_tree_add_text(tree, tvb, offset,
1084 length, "Error Index: %u", error_index);
1092 ret = asn1_oid_decode (&asn1, &enterprise, &enterprise_length,
1094 if (ret != ASN1_ERR_NOERROR) {
1095 dissect_snmp_parse_error(tvb, offset, pinfo, tree,
1096 "enterprise OID", ret);
1100 oid_string = format_oid(enterprise, enterprise_length);
1101 proto_tree_add_text(tree, tvb, offset, length,
1102 "Enterprise: %s", oid_string);
1109 start = asn1.offset;
1110 ret = asn1_header_decode (&asn1, &cls, &con, &tag,
1111 &def, &agent_address_length);
1112 if (ret != ASN1_ERR_NOERROR) {
1113 dissect_snmp_parse_error(tvb, offset, pinfo, tree,
1114 "agent address", ret);
1117 if (!((cls == ASN1_APL && con == ASN1_PRI && tag == SNMP_IPA) ||
1118 (cls == ASN1_UNI && con == ASN1_PRI && tag == ASN1_OTS))) {
1119 /* GXSNMP 0.0.15 says the latter is "needed for
1121 dissect_snmp_parse_error(tvb, offset, pinfo, tree,
1122 "agent_address", ASN1_ERR_WRONG_TYPE);
1125 if (agent_address_length != 4) {
1126 dissect_snmp_parse_error(tvb, offset, pinfo, tree,
1127 "agent_address", ASN1_ERR_WRONG_LENGTH_FOR_TYPE);
1130 ret = asn1_string_value_decode (&asn1,
1131 agent_address_length, &agent_address);
1132 if (ret != ASN1_ERR_NOERROR) {
1133 dissect_snmp_parse_error(tvb, offset, pinfo, tree,
1134 "agent address", ret);
1137 length = asn1.offset - start;
1139 if (agent_address_length != 4) {
1140 proto_tree_add_text(tree, tvb, offset,
1142 "Agent address: <length is %u, not 4>",
1143 agent_address_length);
1145 proto_tree_add_text(tree, tvb, offset,
1147 "Agent address: %s",
1148 ip_to_str(agent_address));
1151 g_free(agent_address);
1154 /* generic trap type */
1155 ret = asn1_uint32_decode (&asn1, &trap_type, &length);
1156 if (ret != ASN1_ERR_NOERROR) {
1157 dissect_snmp_parse_error(tvb, offset, pinfo, tree,
1158 "generic trap type", ret);
1162 proto_tree_add_text(tree, tvb, offset, length,
1164 val_to_str(trap_type, trap_types, "Unknown (%u)"));
1168 /* specific trap type */
1169 ret = asn1_uint32_decode (&asn1, &specific_type, &length);
1170 if (ret != ASN1_ERR_NOERROR) {
1171 dissect_snmp_parse_error(tvb, offset, pinfo, tree,
1172 "specific trap type", ret);
1176 proto_tree_add_text(tree, tvb, offset, length,
1177 "Specific trap type: %u (%#x)",
1178 specific_type, specific_type);
1183 start = asn1.offset;
1184 ret = asn1_header_decode (&asn1, &cls, &con, &tag,
1185 &def, ×tamp_length);
1186 if (ret != ASN1_ERR_NOERROR) {
1187 dissect_snmp_parse_error(tvb, offset, pinfo, tree,
1191 if (!((cls == ASN1_APL && con == ASN1_PRI && tag == SNMP_TIT) ||
1192 (cls == ASN1_UNI && con == ASN1_PRI && tag == ASN1_INT))) {
1193 dissect_snmp_parse_error(tvb, offset, pinfo, tree,
1194 "timestamp", ASN1_ERR_WRONG_TYPE);
1197 ret = asn1_uint32_value_decode(&asn1, timestamp_length,
1199 if (ret != ASN1_ERR_NOERROR) {
1200 dissect_snmp_parse_error(tvb, offset, pinfo, tree,
1204 length = asn1.offset - start;
1206 proto_tree_add_text(tree, tvb, offset, length,
1207 "Timestamp: %u", timestamp);
1213 /* variable bindings */
1214 /* get header for variable-bindings sequence */
1215 ret = asn1_sequence_decode(&asn1, &variable_bindings_length, &length);
1216 if (ret != ASN1_ERR_NOERROR) {
1217 dissect_snmp_parse_error(tvb, offset, pinfo, tree,
1218 "variable bindings header", ret);
1223 /* loop on variable bindings */
1225 while (variable_bindings_length > 0) {
1227 sequence_length = 0;
1230 ret = asn1_sequence_decode(&asn1, &variable_length, &length);
1231 if (ret != ASN1_ERR_NOERROR) {
1232 dissect_snmp_parse_error(tvb, offset, pinfo, tree,
1233 "variable binding header", ret);
1236 sequence_length += length;
1238 /* parse object identifier */
1239 ret = asn1_oid_decode (&asn1, &variable_oid,
1240 &variable_oid_length, &length);
1241 if (ret != ASN1_ERR_NOERROR) {
1242 dissect_snmp_parse_error(tvb, offset, pinfo, tree,
1243 "variable binding OID", ret);
1246 sequence_length += length;
1250 oid_string = format_oid(variable_oid,
1251 variable_oid_length);
1253 #if defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H)
1254 # ifdef RED_HAT_MODIFIED_UCD_SNMP
1255 sprint_objid(binit(NULL, vb_oid_string, sizeof(vb_oid_string)),
1256 variable_oid, variable_oid_length);
1258 sprint_objid(vb_oid_string, variable_oid,
1259 variable_oid_length);
1261 proto_tree_add_text(tree, tvb, offset, sequence_length,
1262 "Object identifier %d: %s (%s)", vb_index,
1263 oid_string, vb_oid_string);
1264 #ifdef HAVE_SNMP_SNMP_H
1266 * CMU SNMP has a bug wherein "sprint_value()"
1267 * calls "get_symbol()", passing it the
1268 * OID supplied, to get an information about the
1269 * variable, and blithely assumes that it will
1270 * never get a null pointer back and dereferences
1271 * the resulting pointer.
1273 * Not true. If there's nothing in the MIB
1274 * about *any* of the components of the OID,
1275 * it'll return a null pointer.
1277 * So we have to check for that, and pass
1278 * down to "snmp_variable_decode" a flag
1279 * saying "don't pass this to 'sprint_value()'.
1281 * We check for that by looking for a decoded
1282 * OID string beginning with "." followed by a
1283 * digit, meaning it couldn't even find any
1284 * symbolic representation for the very
1285 * beginning of the OID string.
1287 if (vb_oid_string[0] == '.' &&
1288 isdigit((guchar)vb_oid_string[1]))
1290 #endif /* HAVE_SNMP_SNMP_H */
1291 #else /* defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H) */
1292 proto_tree_add_text(tree, tvb, offset, sequence_length,
1293 "Object identifier %d: %s", vb_index,
1295 #endif /* defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H) */
1298 offset += sequence_length;
1299 variable_bindings_length -= sequence_length;
1301 /* Parse the variable's value */
1302 ret = snmp_variable_decode(tree, variable_oid,
1303 variable_oid_length, &asn1, offset, &length,
1305 if (ret != ASN1_ERR_NOERROR) {
1306 dissect_snmp_parse_error(tvb, offset, pinfo, tree,
1311 variable_bindings_length -= length;
1315 static const value_string qos_vals[] = {
1316 { 0x0, "No authentication or privacy" },
1317 { 0x1, "Authentication, no privacy" },
1318 { 0x2, "Authentication and privacy" },
1319 { 0x3, "Authentication and privacy" },
1324 dissect_snmp2u_parameters(proto_tree *tree, tvbuff_t *tvb, int offset, int length,
1325 guchar *parameters, int parameters_length)
1328 proto_tree *parameters_tree;
1329 proto_tree *qos_tree;
1334 item = proto_tree_add_text(tree, tvb, offset, length,
1336 parameters_tree = proto_item_add_subtree(item, ett_parameters);
1337 offset += length - parameters_length;
1339 if (parameters_length < 1)
1341 model = *parameters;
1342 proto_tree_add_text(parameters_tree, tvb, offset, 1,
1343 "model: %u", model);
1346 parameters_length -= 1;
1348 /* Unknown model. */
1349 proto_tree_add_text(parameters_tree, tvb, offset,
1350 parameters_length, "parameters: %s",
1351 bytes_to_str(parameters, parameters_length));
1355 if (parameters_length < 1)
1358 item = proto_tree_add_text(parameters_tree, tvb, offset, 1,
1360 qos_tree = proto_item_add_subtree(item, ett_parameters_qos);
1361 proto_tree_add_text(qos_tree, tvb, offset, 1, "%s",
1362 decode_boolean_bitfield(qos, 0x04,
1363 8, "Generation of report PDU allowed",
1364 "Generation of report PDU not allowed"));
1365 proto_tree_add_text(qos_tree, tvb, offset, 1, "%s",
1366 decode_enumerated_bitfield(qos, 0x03,
1367 8, qos_vals, "%s"));
1370 parameters_length -= 1;
1372 if (parameters_length < 12)
1374 proto_tree_add_text(parameters_tree, tvb, offset, 12,
1375 "agentID: %s", bytes_to_str(parameters, 12));
1378 parameters_length -= 12;
1380 if (parameters_length < 4)
1382 proto_tree_add_text(parameters_tree, tvb, offset, 4,
1383 "agentBoots: %u", pntohl(parameters));
1386 parameters_length -= 4;
1388 if (parameters_length < 4)
1390 proto_tree_add_text(parameters_tree, tvb, offset, 4,
1391 "agentTime: %u", pntohl(parameters));
1394 parameters_length -= 4;
1396 if (parameters_length < 2)
1398 proto_tree_add_text(parameters_tree, tvb, offset, 2,
1399 "maxSize: %u", pntohs(parameters));
1402 parameters_length -= 2;
1404 if (parameters_length < 1)
1407 proto_tree_add_text(parameters_tree, tvb, offset, 1,
1408 "userLen: %u", len);
1411 parameters_length -= 1;
1413 if (parameters_length < len)
1415 proto_tree_add_text(parameters_tree, tvb, offset, len,
1416 "userName: %.*s", len, parameters);
1419 parameters_length -= len;
1421 if (parameters_length < 1)
1424 proto_tree_add_text(parameters_tree, tvb, offset, 1,
1425 "authLen: %u", len);
1428 parameters_length -= 1;
1430 if (parameters_length < len)
1432 proto_tree_add_text(parameters_tree, tvb, offset, len,
1433 "authDigest: %s", bytes_to_str(parameters, len));
1436 parameters_length -= len;
1438 if (parameters_length < 1)
1440 proto_tree_add_text(parameters_tree, tvb, offset, parameters_length,
1441 "contextSelector: %s", bytes_to_str(parameters, parameters_length));
1445 dissect_snmp_pdu(tvbuff_t *tvb, int offset, packet_info *pinfo,
1446 proto_tree *tree, char *proto_name, int proto, gint ett)
1453 guint message_length;
1454 guint global_length;
1460 guint32 engineboots;
1473 int msgflags_length;
1474 int community_length;
1476 int cengineid_length;
1478 int cryptpdu_length;
1479 int aengineid_length;
1480 int username_length;
1487 proto_tree *snmp_tree = NULL;
1488 proto_tree *global_tree = NULL;
1489 proto_tree *flags_tree = NULL;
1490 proto_tree *secur_tree = NULL;
1491 proto_item *item = NULL;
1493 guint cls, con, tag;
1495 if (check_col(pinfo->cinfo, COL_PROTOCOL))
1496 col_add_str(pinfo->cinfo, COL_PROTOCOL, proto_name);
1499 item = proto_tree_add_item(tree, proto, tvb, offset,
1500 tvb_length_remaining(tvb, offset), FALSE);
1501 snmp_tree = proto_item_add_subtree(item, ett);
1504 /* NOTE: we have to parse the message piece by piece, since the
1505 * capture length may be less than the message length: a 'global'
1506 * parsing is likely to fail.
1508 /* parse the SNMP header */
1509 asn1_open(&asn1, tvb, offset);
1510 ret = asn1_sequence_decode(&asn1, &message_length, &length);
1511 if (ret != ASN1_ERR_NOERROR) {
1512 dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree,
1513 "message header", ret);
1518 ret = asn1_uint32_decode (&asn1, &version, &length);
1519 if (ret != ASN1_ERR_NOERROR) {
1520 dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree,
1521 "version number", ret);
1525 proto_tree_add_text(snmp_tree, tvb, offset, length,
1527 val_to_str(version, versions, "Unknown version %#x"));
1533 case SNMP_VERSION_1:
1534 case SNMP_VERSION_2c:
1535 ret = asn1_octet_string_decode (&asn1, &community,
1536 &community_length, &length);
1537 if (ret != ASN1_ERR_NOERROR) {
1538 dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree,
1543 proto_tree_add_text(snmp_tree, tvb, offset, length,
1544 "Community: %.*s", community_length,
1545 SAFE_STRING(community));
1550 case SNMP_VERSION_2u:
1551 ret = asn1_octet_string_decode (&asn1, &community,
1552 &community_length, &length);
1554 dissect_snmp2u_parameters(snmp_tree, tvb, offset, length,
1555 community, community_length);
1560 case SNMP_VERSION_3:
1561 ret = asn1_sequence_decode(&asn1, &global_length, &length);
1562 if (ret != ASN1_ERR_NOERROR) {
1563 dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree,
1564 "message global header", ret);
1568 item = proto_tree_add_text(snmp_tree, tvb, offset,
1569 global_length + length, "Message Global Header");
1570 global_tree = proto_item_add_subtree(item, ett_global);
1571 proto_tree_add_text(global_tree, tvb, offset,
1573 "Message Global Header Length: %d", global_length);
1576 ret = asn1_uint32_decode (&asn1, &msgid, &length);
1577 if (ret != ASN1_ERR_NOERROR) {
1578 dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree,
1583 proto_tree_add_text(global_tree, tvb, offset,
1584 length, "Message ID: %d", msgid);
1587 ret = asn1_uint32_decode (&asn1, &msgmax, &length);
1588 if (ret != ASN1_ERR_NOERROR) {
1589 dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree,
1590 "message max size", ret);
1594 proto_tree_add_text(global_tree, tvb, offset,
1595 length, "Message Max Size: %d", msgmax);
1598 ret = asn1_octet_string_decode (&asn1, &msgflags,
1599 &msgflags_length, &length);
1600 if (ret != ASN1_ERR_NOERROR) {
1601 dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree,
1602 "message flags", ret);
1605 if (msgflags_length != 1) {
1606 dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree,
1607 "message flags wrong length", ret);
1612 item = proto_tree_add_uint_format(global_tree,
1613 hf_snmpv3_flags, tvb, offset, length,
1614 msgflags[0], "Flags: 0x%02x", msgflags[0]);
1615 flags_tree = proto_item_add_subtree(item, ett_flags);
1616 proto_tree_add_boolean(flags_tree, hf_snmpv3_flags_report,
1617 tvb, offset, length, msgflags[0]);
1618 proto_tree_add_boolean(flags_tree, hf_snmpv3_flags_crypt,
1619 tvb, offset, length, msgflags[0]);
1620 proto_tree_add_boolean(flags_tree, hf_snmpv3_flags_auth,
1621 tvb, offset, length, msgflags[0]);
1623 encrypted = msgflags[0] & TH_CRYPT;
1626 ret = asn1_uint32_decode (&asn1, &msgsec, &length);
1627 if (ret != ASN1_ERR_NOERROR) {
1628 dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree,
1629 "message security model", ret);
1633 proto_tree_add_text(global_tree, tvb, offset,
1634 length, "Message Security Model: %s",
1635 val_to_str(msgsec, sec_models,
1636 "Unknown model %#x"));
1641 start = asn1.offset;
1642 ret = asn1_header_decode (&asn1, &cls, &con, &tag,
1643 &def, &secparm_length);
1644 length = asn1.offset - start;
1645 if (cls != ASN1_UNI && con != ASN1_PRI &&
1647 dissect_snmp_parse_error(tvb, offset, pinfo,
1648 snmp_tree, "Message Security Parameters",
1649 ASN1_ERR_WRONG_TYPE);
1653 item = proto_tree_add_text(snmp_tree, tvb,
1654 offset, secparm_length + length,
1655 "Message Security Parameters");
1656 secur_tree = proto_item_add_subtree(item,
1658 proto_tree_add_text(secur_tree, tvb, offset,
1660 "Message Security Parameters Length: %d",
1664 ret = asn1_sequence_decode(&asn1, &secparm_length,
1666 if (ret != ASN1_ERR_NOERROR) {
1667 dissect_snmp_parse_error(tvb, offset, pinfo,
1668 snmp_tree, "USM sequence header", ret);
1672 ret = asn1_octet_string_decode (&asn1, &aengineid,
1673 &aengineid_length, &length);
1674 if (ret != ASN1_ERR_NOERROR) {
1675 dissect_snmp_parse_error(tvb, offset, pinfo,
1676 snmp_tree, "authoritative engine id", ret);
1680 proto_tree_add_text(secur_tree, tvb, offset,
1681 length, "Authoritative Engine ID: %s",
1682 bytes_to_str(aengineid, aengineid_length));
1686 ret = asn1_uint32_decode (&asn1, &engineboots, &length);
1687 if (ret != ASN1_ERR_NOERROR) {
1688 dissect_snmp_parse_error(tvb, offset, pinfo,
1689 snmp_tree, "engine boots", ret);
1693 proto_tree_add_text(secur_tree, tvb,
1694 offset, length, "Engine Boots: %d",
1698 ret = asn1_uint32_decode (&asn1, &enginetime, &length);
1699 if (ret != ASN1_ERR_NOERROR) {
1700 dissect_snmp_parse_error(tvb, offset, pinfo,
1701 snmp_tree, "engine time", ret);
1705 proto_tree_add_text(secur_tree, tvb,
1706 offset, length, "Engine Time: %d",
1710 ret = asn1_octet_string_decode (&asn1, &username,
1711 &username_length, &length);
1712 if (ret != ASN1_ERR_NOERROR) {
1713 dissect_snmp_parse_error(tvb, offset, pinfo,
1714 snmp_tree, "user name", ret);
1718 proto_tree_add_text(secur_tree, tvb, offset,
1719 length, "User Name: %.*s",
1721 SAFE_STRING(username));
1725 ret = asn1_octet_string_decode (&asn1, &authpar,
1726 &authpar_length, &length);
1727 if (ret != ASN1_ERR_NOERROR) {
1728 dissect_snmp_parse_error(tvb, offset, pinfo,
1729 snmp_tree, "authentication parameter", ret);
1733 proto_tree_add_text(secur_tree, tvb, offset,
1734 length, "Authentication Parameter: %s",
1735 bytes_to_str(authpar, authpar_length));
1739 ret = asn1_octet_string_decode (&asn1, &privpar,
1740 &privpar_length, &length);
1741 if (ret != ASN1_ERR_NOERROR) {
1742 dissect_snmp_parse_error(tvb, offset, pinfo,
1743 snmp_tree, "privacy parameter", ret);
1747 proto_tree_add_text(secur_tree, tvb, offset,
1748 length, "Privacy Parameter: %s",
1749 bytes_to_str(privpar, privpar_length));
1755 ret = asn1_octet_string_decode (&asn1,
1756 &secparm, &secparm_length, &length);
1757 if (ret != ASN1_ERR_NOERROR) {
1758 dissect_snmp_parse_error(tvb, offset, pinfo,
1759 snmp_tree, "Message Security Parameters",
1764 proto_tree_add_text(snmp_tree, tvb, offset,
1766 "Message Security Parameters Data"
1767 " (%d bytes)", secparm_length);
1773 /* PDU starts here */
1775 ret = asn1_octet_string_decode (&asn1, &cryptpdu,
1776 &cryptpdu_length, &length);
1777 if (ret != ASN1_ERR_NOERROR) {
1778 dissect_snmp_parse_error(tvb, offset, pinfo,
1779 snmp_tree, "encrypted PDU header", ret);
1782 proto_tree_add_text(snmp_tree, tvb, offset, length,
1783 "Encrypted PDU (%d bytes)", length);
1785 if (check_col(pinfo->cinfo, COL_INFO))
1786 col_set_str(pinfo->cinfo, COL_INFO, "Encrypted PDU");
1789 ret = asn1_sequence_decode(&asn1, &global_length, &length);
1790 if (ret != ASN1_ERR_NOERROR) {
1791 dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree,
1796 ret = asn1_octet_string_decode (&asn1, &cengineid,
1797 &cengineid_length, &length);
1798 if (ret != ASN1_ERR_NOERROR) {
1799 dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree,
1800 "context engine id", ret);
1804 proto_tree_add_text(snmp_tree, tvb, offset, length,
1805 "Context Engine ID: %s",
1806 bytes_to_str(cengineid, cengineid_length));
1810 ret = asn1_octet_string_decode (&asn1, &cname,
1811 &cname_length, &length);
1812 if (ret != ASN1_ERR_NOERROR) {
1813 dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree,
1814 "context name", ret);
1818 proto_tree_add_text(snmp_tree, tvb, offset, length,
1819 "Context Name: %.*s", cname_length,
1820 SAFE_STRING(cname));
1826 dissect_snmp_error(tvb, offset, pinfo, snmp_tree,
1827 "PDU for unknown version of SNMP");
1831 start = asn1.offset;
1832 ret = asn1_header_decode (&asn1, &cls, &con, &pdu_type, &def,
1834 if (ret != ASN1_ERR_NOERROR) {
1835 dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree,
1839 if (cls != ASN1_CTX || con != ASN1_CON) {
1840 dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree,
1841 "PDU type", ASN1_ERR_WRONG_TYPE);
1844 dissect_common_pdu(tvb, offset, pinfo, snmp_tree, asn1, pdu_type, start);
1848 dissect_smux_pdu(tvbuff_t *tvb, int offset, packet_info *pinfo,
1849 proto_tree *tree, int proto, gint ett)
1857 char *pdu_type_string;
1867 int password_length;
1869 guchar *application;
1870 int application_length;
1877 proto_tree *smux_tree = NULL;
1878 proto_item *item = NULL;
1882 if (check_col(pinfo->cinfo, COL_PROTOCOL))
1883 col_set_str(pinfo->cinfo, COL_PROTOCOL, "SMUX");
1886 item = proto_tree_add_item(tree, proto, tvb, offset,
1887 tvb_length_remaining(tvb, offset), FALSE);
1888 smux_tree = proto_item_add_subtree(item, ett);
1891 /* NOTE: we have to parse the message piece by piece, since the
1892 * capture length may be less than the message length: a 'global'
1893 * parsing is likely to fail.
1895 /* parse the SNMP header */
1896 asn1_open(&asn1, tvb, offset);
1897 start = asn1.offset;
1898 ret = asn1_header_decode (&asn1, &cls, &con, &pdu_type, &def,
1900 if (ret != ASN1_ERR_NOERROR) {
1901 dissect_snmp_parse_error(tvb, offset, pinfo, smux_tree,
1906 /* Dissect SMUX here */
1907 if (cls == ASN1_APL && con == ASN1_CON && pdu_type == SMUX_MSG_OPEN) {
1908 pdu_type_string = val_to_str(pdu_type, smux_types,
1909 "Unknown PDU type %#x");
1910 if (check_col(pinfo->cinfo, COL_INFO))
1911 col_add_str(pinfo->cinfo, COL_INFO, pdu_type_string);
1912 length = asn1.offset - start;
1914 proto_tree_add_text(smux_tree, tvb, offset, length,
1915 "PDU type: %s", pdu_type_string);
1918 ret = asn1_uint32_decode (&asn1, &version, &length);
1919 if (ret != ASN1_ERR_NOERROR) {
1920 dissect_snmp_parse_error(tvb, offset, pinfo, smux_tree,
1925 proto_tree_add_text(smux_tree, tvb, offset, length,
1926 "Version: %d", version);
1930 ret = asn1_oid_decode (&asn1, ®id, ®id_length, &length);
1931 if (ret != ASN1_ERR_NOERROR) {
1932 dissect_snmp_parse_error(tvb, offset, pinfo, smux_tree,
1933 "registration OID", ret);
1937 oid_string = format_oid(regid, regid_length);
1938 proto_tree_add_text(smux_tree, tvb, offset, length,
1939 "Registration: %s", oid_string);
1945 ret = asn1_octet_string_decode (&asn1, &application,
1946 &application_length, &length);
1947 if (ret != ASN1_ERR_NOERROR) {
1948 dissect_snmp_parse_error(tvb, offset, pinfo, smux_tree,
1949 "application", ret);
1953 proto_tree_add_text(smux_tree, tvb, offset, length,
1954 "Application: %.*s", application_length,
1955 SAFE_STRING(application));
1957 g_free(application);
1960 ret = asn1_octet_string_decode (&asn1, &password,
1961 &password_length, &length);
1962 if (ret != ASN1_ERR_NOERROR) {
1963 dissect_snmp_parse_error(tvb, offset, pinfo, smux_tree,
1968 proto_tree_add_text(smux_tree, tvb, offset, length,
1969 "Password: %.*s", password_length,
1970 SAFE_STRING(password));
1976 if (cls == ASN1_APL && con == ASN1_PRI && pdu_type == SMUX_MSG_CLOSE) {
1977 pdu_type_string = val_to_str(pdu_type, smux_types,
1978 "Unknown PDU type %#x");
1979 if (check_col(pinfo->cinfo, COL_INFO))
1980 col_add_str(pinfo->cinfo, COL_INFO, pdu_type_string);
1981 length = asn1.offset - start;
1983 proto_tree_add_text(smux_tree, tvb, offset, length,
1984 "PDU type: %s", pdu_type_string);
1987 ret = asn1_uint32_value_decode (&asn1, pdu_length, &cause);
1988 if (ret != ASN1_ERR_NOERROR) {
1989 dissect_snmp_parse_error(tvb, offset, pinfo, smux_tree,
1994 proto_tree_add_text(smux_tree, tvb, offset,
1995 pdu_length, "Cause: %s",
1996 val_to_str(cause, smux_close,
1997 "Unknown cause %#x"));
1999 offset += pdu_length;
2002 if (cls == ASN1_APL && con == ASN1_CON && pdu_type == SMUX_MSG_RREQ) {
2003 pdu_type_string = val_to_str(pdu_type, smux_types,
2004 "Unknown PDU type %#x");
2005 if (check_col(pinfo->cinfo, COL_INFO))
2006 col_add_str(pinfo->cinfo, COL_INFO, pdu_type_string);
2007 length = asn1.offset - start;
2009 proto_tree_add_text(smux_tree, tvb, offset, length,
2010 "PDU type: %s", pdu_type_string);
2013 ret = asn1_oid_decode (&asn1, ®id, ®id_length, &length);
2014 if (ret != ASN1_ERR_NOERROR) {
2015 dissect_snmp_parse_error(tvb, offset, pinfo, smux_tree,
2016 "registration subtree", ret);
2020 oid_string = format_oid(regid, regid_length);
2021 proto_tree_add_text(smux_tree, tvb, offset, length,
2022 "Registration: %s", oid_string);
2028 ret = asn1_uint32_decode (&asn1, &priority, &length);
2029 if (ret != ASN1_ERR_NOERROR) {
2030 dissect_snmp_parse_error(tvb, offset, pinfo, smux_tree,
2035 proto_tree_add_text(smux_tree, tvb, offset, length,
2036 "Priority: %d", priority);
2040 ret = asn1_uint32_decode (&asn1, &operation, &length);
2041 if (ret != ASN1_ERR_NOERROR) {
2042 dissect_snmp_parse_error(tvb, offset, pinfo, smux_tree,
2047 proto_tree_add_text(smux_tree, tvb, offset, length,
2049 val_to_str(operation, smux_rreq,
2050 "Unknown operation %#x"));
2055 if (cls == ASN1_APL && con == ASN1_PRI && pdu_type == SMUX_MSG_RRSP) {
2056 pdu_type_string = val_to_str(pdu_type, smux_types,
2057 "Unknown PDU type %#x");
2058 if (check_col(pinfo->cinfo, COL_INFO))
2059 col_add_str(pinfo->cinfo, COL_INFO, pdu_type_string);
2060 length = asn1.offset - start;
2062 proto_tree_add_text(smux_tree, tvb, offset, length,
2063 "PDU type: %s", pdu_type_string);
2066 ret = asn1_uint32_value_decode (&asn1, pdu_length, &priority);
2067 if (ret != ASN1_ERR_NOERROR) {
2068 dissect_snmp_parse_error(tvb, offset, pinfo, smux_tree,
2073 proto_tree_add_text(smux_tree, tvb, offset,
2075 val_to_str(priority, smux_prio,
2078 offset += pdu_length;
2081 if (cls == ASN1_APL && con == ASN1_PRI && pdu_type == SMUX_MSG_SOUT) {
2082 pdu_type_string = val_to_str(pdu_type, smux_types,
2083 "Unknown PDU type %#x");
2084 if (check_col(pinfo->cinfo, COL_INFO))
2085 col_add_str(pinfo->cinfo, COL_INFO, pdu_type_string);
2086 length = asn1.offset - start;
2088 proto_tree_add_text(smux_tree, tvb, offset, length,
2089 "PDU type: %s", pdu_type_string);
2092 ret = asn1_uint32_value_decode (&asn1, pdu_length, &commit);
2093 if (ret != ASN1_ERR_NOERROR) {
2094 dissect_snmp_parse_error(tvb, offset, pinfo, smux_tree,
2099 proto_tree_add_text(smux_tree, tvb, offset,
2101 val_to_str(commit, smux_sout,
2102 "Unknown SOUT Value: %#x"));
2104 offset += pdu_length;
2107 if (cls != ASN1_CTX || con != ASN1_CON) {
2108 dissect_snmp_parse_error(tvb, offset, pinfo, smux_tree,
2109 "PDU type", ASN1_ERR_WRONG_TYPE);
2112 dissect_common_pdu(tvb, offset, pinfo, smux_tree, asn1, pdu_type, start);
2116 dissect_snmp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
2118 conversation_t *conversation;
2121 * The first SNMP packet goes to the SNMP port; the second one
2122 * may come from some *other* port, but goes back to the same
2123 * IP address and port as the ones from which the first packet
2124 * came; all subsequent packets presumably go between those two
2125 * IP addresses and ports.
2127 * If this packet went to the SNMP port, we check to see if
2128 * there's already a conversation with one address/port pair
2129 * matching the source IP address and port of this packet,
2130 * the other address matching the destination IP address of this
2131 * packet, and any destination port.
2133 * If not, we create one, with its address 1/port 1 pair being
2134 * the source address/port of this packet, its address 2 being
2135 * the destination address of this packet, and its port 2 being
2136 * wildcarded, and give it the SNMP dissector as a dissector.
2138 if (pinfo->destport == UDP_PORT_SNMP) {
2139 conversation = find_conversation(&pinfo->src, &pinfo->dst, PT_UDP,
2140 pinfo->srcport, 0, NO_PORT_B);
2141 if (conversation == NULL) {
2142 conversation = conversation_new(&pinfo->src, &pinfo->dst, PT_UDP,
2143 pinfo->srcport, 0, NO_PORT2);
2144 conversation_set_dissector(conversation, snmp_handle);
2148 dissect_snmp_pdu(tvb, 0, pinfo, tree, "SNMP", proto_snmp, ett_snmp);
2152 dissect_smux(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
2154 dissect_smux_pdu(tvb, 0, pinfo, tree, proto_smux, ett_smux);
2158 proto_register_snmp(void)
2160 #if defined(HAVE_UCD_SNMP_SNMP_H) && defined(linux)
2161 void *libsnmp_handle;
2162 int (*snmp_set_suffix_only_p)(int);
2163 int (*ds_set_int_p)(int, int, int);
2166 static hf_register_info hf[] = {
2168 { "SNMPv3 Flags", "snmpv3.flags", FT_UINT8, BASE_HEX, NULL,
2170 { &hf_snmpv3_flags_auth,
2171 { "Authenticated", "snmpv3.flags.auth", FT_BOOLEAN, 8,
2172 TFS(&flags_set_truth), TH_AUTH, "", HFILL }},
2173 { &hf_snmpv3_flags_crypt,
2174 { "Encrypted", "snmpv3.flags.crypt", FT_BOOLEAN, 8,
2175 TFS(&flags_set_truth), TH_CRYPT, "", HFILL }},
2176 { &hf_snmpv3_flags_report,
2177 { "Reportable", "snmpv3.flags.report", FT_BOOLEAN, 8,
2178 TFS(&flags_set_truth), TH_REPORT, "", HFILL }},
2180 static gint *ett[] = {
2184 &ett_parameters_qos,
2190 #if defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H)
2191 /* UCD or CMU SNMP */
2193 #ifdef HAVE_UCD_SNMP_SNMP_H
2195 /* As per the comment near the beginning of the file, UCD SNMP 4.1.1
2196 changed "snmp_set_suffix_only()" from a function to a macro,
2197 removing "snmp_set_suffix_only()" from the library; this means
2198 that binaries that call "snmp_set_suffix_only()" and
2199 that are linked against shared libraries from earlier versions
2200 of the UCD SNMP library won't run with shared libraries from
2203 This is a problem on Red Hat Linux, as pre-6.2 releases
2204 came with pre-4.1.1 UCD SNMP, while 6.2 comes the 4.1.1.
2205 Versions of Ethereal built on pre-6.2 releases don't run
2206 on 6.2, and the current Ethereal RPMs are built on pre-6.2
2207 releases, causing problems when users running 6.2 download
2208 them and try to use them.
2210 Building the releases on 6.2 isn't necessarily the answer,
2211 as "snmp_set_suffix_only()" expands to a call to "ds_set_int()"
2212 with a second argument not supported by at least some pre-4.1.1
2213 versions of the library - it appears that the 4.0.1 library,
2214 at least, checks for invalid arguments and returns an error
2215 rather than stomping random memory, but that means that you
2216 won't get get OIDs displayed as module-name::sub-OID.
2218 So we use a trick similar to one I've seen mentioned as
2219 used in Windows applications to let you build binaries
2220 that run on many different versions of Windows 9x and
2221 Windows NT, that use features present on later versions
2222 if run on those later versions, but that avoid calling,
2223 when run on older versions, routines not present on those
2226 I.e., we load "libsnmp.so.0" with "dlopen()", and call
2227 "dlsym()" to try to find "snmp_set_suffix_only()"; if we
2228 don't find it, we make the appropriate call to
2229 "ds_set_int()" instead. (We load "libsnmp.so.0" rather
2230 than "libsnmp.so" because, at least on RH 6.2, "libsnmp.so"
2231 exists only if you've loaded the libsnmp development package,
2232 which makes "libsnmp.so" a symlink to "libsnmp.so.0"; we
2233 don't want to force users to install it or to make said
2236 We do this only on Linux, for now, as we've only seen the
2237 problem on Red Hat; it may show up on other OSes that bundle
2238 UCD SNMP, or on OSes where it's not bundled but for which
2239 binary packages are built that link against a shared version
2240 of the UCD SNMP library. If we run into one of those, we
2241 can do this under those OSes as well, *if* "dlopen()" makes
2242 the run-time linker use the same search rules as it uses when
2243 loading libraries with which the application is linked.
2245 (Perhaps we could use the GLib wrappers for run-time linking,
2246 *if* they're thin enough; however, as this code is currently
2247 used only on Linux, we don't worry about that for now.) */
2249 libsnmp_handle = dlopen("libsnmp.so.0", RTLD_LAZY|RTLD_GLOBAL);
2250 if (libsnmp_handle == NULL) {
2251 /* We didn't find "libsnmp.so.0".
2253 This could mean that there is no SNMP shared library
2254 on this system, in which case we were linked statically,
2255 in which case whatever call the following line of code
2256 makes will presumably work, as we have the routine it
2257 calls wired into our binary. (If we were linked
2258 dynamically with "-lsnmp", we would have failed to
2261 It could also mean that there is an SNMP shared library
2262 on this system, but it's called something other than
2263 "libsnmp.so.0"; so far, we've seen the problem we're
2264 working around only on systems where the SNMP shared
2265 library is called "libsnmp.so.0", so we assume for now
2266 that systems with shared SNMP libraries named something
2267 other than "libsnmp.so.0" have an SNMP library that's
2269 snmp_set_suffix_only(2);
2271 /* OK, we have it loaded. Do we have
2272 "snmp_set_suffix_only()"? */
2273 snmp_set_suffix_only_p = dlsym(libsnmp_handle,
2274 "snmp_set_suffix_only");
2275 if (snmp_set_suffix_only_p != NULL) {
2276 /* Yes - call it. */
2277 (*snmp_set_suffix_only_p)(2);
2279 /* No; do we have "ds_set_int()"? */
2280 ds_set_int_p = dlsym(libsnmp_handle, "ds_set_int");
2281 if (ds_set_int_p != NULL) {
2282 /* Yes - cal it with DS_LIBRARY_ID,
2283 DS_LIB_PRINT_SUFFIX_ONLY, and 2 as
2286 We do *not* use DS_LIBRARY_ID or
2287 DS_LIB_PRINT_SUFFIX_ONLY by name, so that
2288 we don't require that Ethereal be built
2289 with versions of UCD SNMP that include
2290 that value; instead, we use their values
2291 in UCD SNMP 4.1.1, which are 0 and 4,
2293 (*ds_set_int_p)(0, 4, 2);
2296 dlclose(libsnmp_handle);
2299 snmp_set_suffix_only(2);
2301 #endif /* HAVE_UCD_SNMP_SNMP_H */
2302 #endif /* defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H) */
2303 proto_snmp = proto_register_protocol("Simple Network Management Protocol",
2305 proto_smux = proto_register_protocol("SNMP Multiplex Protocol",
2307 proto_register_field_array(proto_snmp, hf, array_length(hf));
2308 proto_register_subtree_array(ett, array_length(ett));
2309 snmp_handle = create_dissector_handle(dissect_snmp, proto_snmp);
2313 proto_reg_handoff_snmp(void)
2315 dissector_handle_t smux_handle;
2317 dissector_add("udp.port", UDP_PORT_SNMP, snmp_handle);
2318 dissector_add("udp.port", UDP_PORT_SNMP_TRAP, snmp_handle);
2319 smux_handle = create_dissector_handle(dissect_smux, proto_smux);
2320 dissector_add("tcp.port", TCP_PORT_SMUX, smux_handle);
2321 dissector_add("ethertype", ETHERTYPE_SNMP, snmp_handle);
2322 dissector_add("ipx.socket", IPX_SOCKET_SNMP_AGENT, snmp_handle);
2323 dissector_add("ipx.socket", IPX_SOCKET_SNMP_SINK, snmp_handle);
2324 data_handle = find_dissector("data");