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.79 2002/01/24 09:20:51 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, -1, FALSE);
1500 snmp_tree = proto_item_add_subtree(item, ett);
1503 /* NOTE: we have to parse the message piece by piece, since the
1504 * capture length may be less than the message length: a 'global'
1505 * parsing is likely to fail.
1507 /* parse the SNMP header */
1508 asn1_open(&asn1, tvb, offset);
1509 ret = asn1_sequence_decode(&asn1, &message_length, &length);
1510 if (ret != ASN1_ERR_NOERROR) {
1511 dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree,
1512 "message header", ret);
1517 ret = asn1_uint32_decode (&asn1, &version, &length);
1518 if (ret != ASN1_ERR_NOERROR) {
1519 dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree,
1520 "version number", ret);
1524 proto_tree_add_text(snmp_tree, tvb, offset, length,
1526 val_to_str(version, versions, "Unknown version %#x"));
1532 case SNMP_VERSION_1:
1533 case SNMP_VERSION_2c:
1534 ret = asn1_octet_string_decode (&asn1, &community,
1535 &community_length, &length);
1536 if (ret != ASN1_ERR_NOERROR) {
1537 dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree,
1542 proto_tree_add_text(snmp_tree, tvb, offset, length,
1543 "Community: %.*s", community_length,
1544 SAFE_STRING(community));
1549 case SNMP_VERSION_2u:
1550 ret = asn1_octet_string_decode (&asn1, &community,
1551 &community_length, &length);
1553 dissect_snmp2u_parameters(snmp_tree, tvb, offset, length,
1554 community, community_length);
1559 case SNMP_VERSION_3:
1560 ret = asn1_sequence_decode(&asn1, &global_length, &length);
1561 if (ret != ASN1_ERR_NOERROR) {
1562 dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree,
1563 "message global header", ret);
1567 item = proto_tree_add_text(snmp_tree, tvb, offset,
1568 global_length + length, "Message Global Header");
1569 global_tree = proto_item_add_subtree(item, ett_global);
1570 proto_tree_add_text(global_tree, tvb, offset,
1572 "Message Global Header Length: %d", global_length);
1575 ret = asn1_uint32_decode (&asn1, &msgid, &length);
1576 if (ret != ASN1_ERR_NOERROR) {
1577 dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree,
1582 proto_tree_add_text(global_tree, tvb, offset,
1583 length, "Message ID: %d", msgid);
1586 ret = asn1_uint32_decode (&asn1, &msgmax, &length);
1587 if (ret != ASN1_ERR_NOERROR) {
1588 dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree,
1589 "message max size", ret);
1593 proto_tree_add_text(global_tree, tvb, offset,
1594 length, "Message Max Size: %d", msgmax);
1597 ret = asn1_octet_string_decode (&asn1, &msgflags,
1598 &msgflags_length, &length);
1599 if (ret != ASN1_ERR_NOERROR) {
1600 dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree,
1601 "message flags", ret);
1604 if (msgflags_length != 1) {
1605 dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree,
1606 "message flags wrong length", ret);
1611 item = proto_tree_add_uint_format(global_tree,
1612 hf_snmpv3_flags, tvb, offset, length,
1613 msgflags[0], "Flags: 0x%02x", msgflags[0]);
1614 flags_tree = proto_item_add_subtree(item, ett_flags);
1615 proto_tree_add_boolean(flags_tree, hf_snmpv3_flags_report,
1616 tvb, offset, length, msgflags[0]);
1617 proto_tree_add_boolean(flags_tree, hf_snmpv3_flags_crypt,
1618 tvb, offset, length, msgflags[0]);
1619 proto_tree_add_boolean(flags_tree, hf_snmpv3_flags_auth,
1620 tvb, offset, length, msgflags[0]);
1622 encrypted = msgflags[0] & TH_CRYPT;
1625 ret = asn1_uint32_decode (&asn1, &msgsec, &length);
1626 if (ret != ASN1_ERR_NOERROR) {
1627 dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree,
1628 "message security model", ret);
1632 proto_tree_add_text(global_tree, tvb, offset,
1633 length, "Message Security Model: %s",
1634 val_to_str(msgsec, sec_models,
1635 "Unknown model %#x"));
1640 start = asn1.offset;
1641 ret = asn1_header_decode (&asn1, &cls, &con, &tag,
1642 &def, &secparm_length);
1643 length = asn1.offset - start;
1644 if (cls != ASN1_UNI && con != ASN1_PRI &&
1646 dissect_snmp_parse_error(tvb, offset, pinfo,
1647 snmp_tree, "Message Security Parameters",
1648 ASN1_ERR_WRONG_TYPE);
1652 item = proto_tree_add_text(snmp_tree, tvb,
1653 offset, secparm_length + length,
1654 "Message Security Parameters");
1655 secur_tree = proto_item_add_subtree(item,
1657 proto_tree_add_text(secur_tree, tvb, offset,
1659 "Message Security Parameters Length: %d",
1663 ret = asn1_sequence_decode(&asn1, &secparm_length,
1665 if (ret != ASN1_ERR_NOERROR) {
1666 dissect_snmp_parse_error(tvb, offset, pinfo,
1667 snmp_tree, "USM sequence header", ret);
1671 ret = asn1_octet_string_decode (&asn1, &aengineid,
1672 &aengineid_length, &length);
1673 if (ret != ASN1_ERR_NOERROR) {
1674 dissect_snmp_parse_error(tvb, offset, pinfo,
1675 snmp_tree, "authoritative engine id", ret);
1679 proto_tree_add_text(secur_tree, tvb, offset,
1680 length, "Authoritative Engine ID: %s",
1681 bytes_to_str(aengineid, aengineid_length));
1685 ret = asn1_uint32_decode (&asn1, &engineboots, &length);
1686 if (ret != ASN1_ERR_NOERROR) {
1687 dissect_snmp_parse_error(tvb, offset, pinfo,
1688 snmp_tree, "engine boots", ret);
1692 proto_tree_add_text(secur_tree, tvb,
1693 offset, length, "Engine Boots: %d",
1697 ret = asn1_uint32_decode (&asn1, &enginetime, &length);
1698 if (ret != ASN1_ERR_NOERROR) {
1699 dissect_snmp_parse_error(tvb, offset, pinfo,
1700 snmp_tree, "engine time", ret);
1704 proto_tree_add_text(secur_tree, tvb,
1705 offset, length, "Engine Time: %d",
1709 ret = asn1_octet_string_decode (&asn1, &username,
1710 &username_length, &length);
1711 if (ret != ASN1_ERR_NOERROR) {
1712 dissect_snmp_parse_error(tvb, offset, pinfo,
1713 snmp_tree, "user name", ret);
1717 proto_tree_add_text(secur_tree, tvb, offset,
1718 length, "User Name: %.*s",
1720 SAFE_STRING(username));
1724 ret = asn1_octet_string_decode (&asn1, &authpar,
1725 &authpar_length, &length);
1726 if (ret != ASN1_ERR_NOERROR) {
1727 dissect_snmp_parse_error(tvb, offset, pinfo,
1728 snmp_tree, "authentication parameter", ret);
1732 proto_tree_add_text(secur_tree, tvb, offset,
1733 length, "Authentication Parameter: %s",
1734 bytes_to_str(authpar, authpar_length));
1738 ret = asn1_octet_string_decode (&asn1, &privpar,
1739 &privpar_length, &length);
1740 if (ret != ASN1_ERR_NOERROR) {
1741 dissect_snmp_parse_error(tvb, offset, pinfo,
1742 snmp_tree, "privacy parameter", ret);
1746 proto_tree_add_text(secur_tree, tvb, offset,
1747 length, "Privacy Parameter: %s",
1748 bytes_to_str(privpar, privpar_length));
1754 ret = asn1_octet_string_decode (&asn1,
1755 &secparm, &secparm_length, &length);
1756 if (ret != ASN1_ERR_NOERROR) {
1757 dissect_snmp_parse_error(tvb, offset, pinfo,
1758 snmp_tree, "Message Security Parameters",
1763 proto_tree_add_text(snmp_tree, tvb, offset,
1765 "Message Security Parameters Data"
1766 " (%d bytes)", secparm_length);
1772 /* PDU starts here */
1774 ret = asn1_octet_string_decode (&asn1, &cryptpdu,
1775 &cryptpdu_length, &length);
1776 if (ret != ASN1_ERR_NOERROR) {
1777 dissect_snmp_parse_error(tvb, offset, pinfo,
1778 snmp_tree, "encrypted PDU header", ret);
1781 proto_tree_add_text(snmp_tree, tvb, offset, length,
1782 "Encrypted PDU (%d bytes)", length);
1784 if (check_col(pinfo->cinfo, COL_INFO))
1785 col_set_str(pinfo->cinfo, COL_INFO, "Encrypted PDU");
1788 ret = asn1_sequence_decode(&asn1, &global_length, &length);
1789 if (ret != ASN1_ERR_NOERROR) {
1790 dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree,
1795 ret = asn1_octet_string_decode (&asn1, &cengineid,
1796 &cengineid_length, &length);
1797 if (ret != ASN1_ERR_NOERROR) {
1798 dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree,
1799 "context engine id", ret);
1803 proto_tree_add_text(snmp_tree, tvb, offset, length,
1804 "Context Engine ID: %s",
1805 bytes_to_str(cengineid, cengineid_length));
1809 ret = asn1_octet_string_decode (&asn1, &cname,
1810 &cname_length, &length);
1811 if (ret != ASN1_ERR_NOERROR) {
1812 dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree,
1813 "context name", ret);
1817 proto_tree_add_text(snmp_tree, tvb, offset, length,
1818 "Context Name: %.*s", cname_length,
1819 SAFE_STRING(cname));
1825 dissect_snmp_error(tvb, offset, pinfo, snmp_tree,
1826 "PDU for unknown version of SNMP");
1830 start = asn1.offset;
1831 ret = asn1_header_decode (&asn1, &cls, &con, &pdu_type, &def,
1833 if (ret != ASN1_ERR_NOERROR) {
1834 dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree,
1838 if (cls != ASN1_CTX || con != ASN1_CON) {
1839 dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree,
1840 "PDU type", ASN1_ERR_WRONG_TYPE);
1843 dissect_common_pdu(tvb, offset, pinfo, snmp_tree, asn1, pdu_type, start);
1847 dissect_smux_pdu(tvbuff_t *tvb, int offset, packet_info *pinfo,
1848 proto_tree *tree, int proto, gint ett)
1856 char *pdu_type_string;
1866 int password_length;
1868 guchar *application;
1869 int application_length;
1876 proto_tree *smux_tree = NULL;
1877 proto_item *item = NULL;
1881 if (check_col(pinfo->cinfo, COL_PROTOCOL))
1882 col_set_str(pinfo->cinfo, COL_PROTOCOL, "SMUX");
1885 item = proto_tree_add_item(tree, proto, tvb, offset, -1, FALSE);
1886 smux_tree = proto_item_add_subtree(item, ett);
1889 /* NOTE: we have to parse the message piece by piece, since the
1890 * capture length may be less than the message length: a 'global'
1891 * parsing is likely to fail.
1893 /* parse the SNMP header */
1894 asn1_open(&asn1, tvb, offset);
1895 start = asn1.offset;
1896 ret = asn1_header_decode (&asn1, &cls, &con, &pdu_type, &def,
1898 if (ret != ASN1_ERR_NOERROR) {
1899 dissect_snmp_parse_error(tvb, offset, pinfo, smux_tree,
1904 /* Dissect SMUX here */
1905 if (cls == ASN1_APL && con == ASN1_CON && pdu_type == SMUX_MSG_OPEN) {
1906 pdu_type_string = val_to_str(pdu_type, smux_types,
1907 "Unknown PDU type %#x");
1908 if (check_col(pinfo->cinfo, COL_INFO))
1909 col_add_str(pinfo->cinfo, COL_INFO, pdu_type_string);
1910 length = asn1.offset - start;
1912 proto_tree_add_text(smux_tree, tvb, offset, length,
1913 "PDU type: %s", pdu_type_string);
1916 ret = asn1_uint32_decode (&asn1, &version, &length);
1917 if (ret != ASN1_ERR_NOERROR) {
1918 dissect_snmp_parse_error(tvb, offset, pinfo, smux_tree,
1923 proto_tree_add_text(smux_tree, tvb, offset, length,
1924 "Version: %d", version);
1928 ret = asn1_oid_decode (&asn1, ®id, ®id_length, &length);
1929 if (ret != ASN1_ERR_NOERROR) {
1930 dissect_snmp_parse_error(tvb, offset, pinfo, smux_tree,
1931 "registration OID", ret);
1935 oid_string = format_oid(regid, regid_length);
1936 proto_tree_add_text(smux_tree, tvb, offset, length,
1937 "Registration: %s", oid_string);
1943 ret = asn1_octet_string_decode (&asn1, &application,
1944 &application_length, &length);
1945 if (ret != ASN1_ERR_NOERROR) {
1946 dissect_snmp_parse_error(tvb, offset, pinfo, smux_tree,
1947 "application", ret);
1951 proto_tree_add_text(smux_tree, tvb, offset, length,
1952 "Application: %.*s", application_length,
1953 SAFE_STRING(application));
1955 g_free(application);
1958 ret = asn1_octet_string_decode (&asn1, &password,
1959 &password_length, &length);
1960 if (ret != ASN1_ERR_NOERROR) {
1961 dissect_snmp_parse_error(tvb, offset, pinfo, smux_tree,
1966 proto_tree_add_text(smux_tree, tvb, offset, length,
1967 "Password: %.*s", password_length,
1968 SAFE_STRING(password));
1974 if (cls == ASN1_APL && con == ASN1_PRI && pdu_type == SMUX_MSG_CLOSE) {
1975 pdu_type_string = val_to_str(pdu_type, smux_types,
1976 "Unknown PDU type %#x");
1977 if (check_col(pinfo->cinfo, COL_INFO))
1978 col_add_str(pinfo->cinfo, COL_INFO, pdu_type_string);
1979 length = asn1.offset - start;
1981 proto_tree_add_text(smux_tree, tvb, offset, length,
1982 "PDU type: %s", pdu_type_string);
1985 ret = asn1_uint32_value_decode (&asn1, pdu_length, &cause);
1986 if (ret != ASN1_ERR_NOERROR) {
1987 dissect_snmp_parse_error(tvb, offset, pinfo, smux_tree,
1992 proto_tree_add_text(smux_tree, tvb, offset,
1993 pdu_length, "Cause: %s",
1994 val_to_str(cause, smux_close,
1995 "Unknown cause %#x"));
1997 offset += pdu_length;
2000 if (cls == ASN1_APL && con == ASN1_CON && pdu_type == SMUX_MSG_RREQ) {
2001 pdu_type_string = val_to_str(pdu_type, smux_types,
2002 "Unknown PDU type %#x");
2003 if (check_col(pinfo->cinfo, COL_INFO))
2004 col_add_str(pinfo->cinfo, COL_INFO, pdu_type_string);
2005 length = asn1.offset - start;
2007 proto_tree_add_text(smux_tree, tvb, offset, length,
2008 "PDU type: %s", pdu_type_string);
2011 ret = asn1_oid_decode (&asn1, ®id, ®id_length, &length);
2012 if (ret != ASN1_ERR_NOERROR) {
2013 dissect_snmp_parse_error(tvb, offset, pinfo, smux_tree,
2014 "registration subtree", ret);
2018 oid_string = format_oid(regid, regid_length);
2019 proto_tree_add_text(smux_tree, tvb, offset, length,
2020 "Registration: %s", oid_string);
2026 ret = asn1_uint32_decode (&asn1, &priority, &length);
2027 if (ret != ASN1_ERR_NOERROR) {
2028 dissect_snmp_parse_error(tvb, offset, pinfo, smux_tree,
2033 proto_tree_add_text(smux_tree, tvb, offset, length,
2034 "Priority: %d", priority);
2038 ret = asn1_uint32_decode (&asn1, &operation, &length);
2039 if (ret != ASN1_ERR_NOERROR) {
2040 dissect_snmp_parse_error(tvb, offset, pinfo, smux_tree,
2045 proto_tree_add_text(smux_tree, tvb, offset, length,
2047 val_to_str(operation, smux_rreq,
2048 "Unknown operation %#x"));
2053 if (cls == ASN1_APL && con == ASN1_PRI && pdu_type == SMUX_MSG_RRSP) {
2054 pdu_type_string = val_to_str(pdu_type, smux_types,
2055 "Unknown PDU type %#x");
2056 if (check_col(pinfo->cinfo, COL_INFO))
2057 col_add_str(pinfo->cinfo, COL_INFO, pdu_type_string);
2058 length = asn1.offset - start;
2060 proto_tree_add_text(smux_tree, tvb, offset, length,
2061 "PDU type: %s", pdu_type_string);
2064 ret = asn1_uint32_value_decode (&asn1, pdu_length, &priority);
2065 if (ret != ASN1_ERR_NOERROR) {
2066 dissect_snmp_parse_error(tvb, offset, pinfo, smux_tree,
2071 proto_tree_add_text(smux_tree, tvb, offset,
2073 val_to_str(priority, smux_prio,
2076 offset += pdu_length;
2079 if (cls == ASN1_APL && con == ASN1_PRI && pdu_type == SMUX_MSG_SOUT) {
2080 pdu_type_string = val_to_str(pdu_type, smux_types,
2081 "Unknown PDU type %#x");
2082 if (check_col(pinfo->cinfo, COL_INFO))
2083 col_add_str(pinfo->cinfo, COL_INFO, pdu_type_string);
2084 length = asn1.offset - start;
2086 proto_tree_add_text(smux_tree, tvb, offset, length,
2087 "PDU type: %s", pdu_type_string);
2090 ret = asn1_uint32_value_decode (&asn1, pdu_length, &commit);
2091 if (ret != ASN1_ERR_NOERROR) {
2092 dissect_snmp_parse_error(tvb, offset, pinfo, smux_tree,
2097 proto_tree_add_text(smux_tree, tvb, offset,
2099 val_to_str(commit, smux_sout,
2100 "Unknown SOUT Value: %#x"));
2102 offset += pdu_length;
2105 if (cls != ASN1_CTX || con != ASN1_CON) {
2106 dissect_snmp_parse_error(tvb, offset, pinfo, smux_tree,
2107 "PDU type", ASN1_ERR_WRONG_TYPE);
2110 dissect_common_pdu(tvb, offset, pinfo, smux_tree, asn1, pdu_type, start);
2114 dissect_snmp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
2116 conversation_t *conversation;
2119 * The first SNMP packet goes to the SNMP port; the second one
2120 * may come from some *other* port, but goes back to the same
2121 * IP address and port as the ones from which the first packet
2122 * came; all subsequent packets presumably go between those two
2123 * IP addresses and ports.
2125 * If this packet went to the SNMP port, we check to see if
2126 * there's already a conversation with one address/port pair
2127 * matching the source IP address and port of this packet,
2128 * the other address matching the destination IP address of this
2129 * packet, and any destination port.
2131 * If not, we create one, with its address 1/port 1 pair being
2132 * the source address/port of this packet, its address 2 being
2133 * the destination address of this packet, and its port 2 being
2134 * wildcarded, and give it the SNMP dissector as a dissector.
2136 if (pinfo->destport == UDP_PORT_SNMP) {
2137 conversation = find_conversation(&pinfo->src, &pinfo->dst, PT_UDP,
2138 pinfo->srcport, 0, NO_PORT_B);
2139 if (conversation == NULL) {
2140 conversation = conversation_new(&pinfo->src, &pinfo->dst, PT_UDP,
2141 pinfo->srcport, 0, NO_PORT2);
2142 conversation_set_dissector(conversation, snmp_handle);
2146 dissect_snmp_pdu(tvb, 0, pinfo, tree, "SNMP", proto_snmp, ett_snmp);
2150 dissect_smux(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
2152 dissect_smux_pdu(tvb, 0, pinfo, tree, proto_smux, ett_smux);
2156 proto_register_snmp(void)
2158 #if defined(HAVE_UCD_SNMP_SNMP_H) && defined(linux)
2159 void *libsnmp_handle;
2160 int (*snmp_set_suffix_only_p)(int);
2161 int (*ds_set_int_p)(int, int, int);
2164 static hf_register_info hf[] = {
2166 { "SNMPv3 Flags", "snmpv3.flags", FT_UINT8, BASE_HEX, NULL,
2168 { &hf_snmpv3_flags_auth,
2169 { "Authenticated", "snmpv3.flags.auth", FT_BOOLEAN, 8,
2170 TFS(&flags_set_truth), TH_AUTH, "", HFILL }},
2171 { &hf_snmpv3_flags_crypt,
2172 { "Encrypted", "snmpv3.flags.crypt", FT_BOOLEAN, 8,
2173 TFS(&flags_set_truth), TH_CRYPT, "", HFILL }},
2174 { &hf_snmpv3_flags_report,
2175 { "Reportable", "snmpv3.flags.report", FT_BOOLEAN, 8,
2176 TFS(&flags_set_truth), TH_REPORT, "", HFILL }},
2178 static gint *ett[] = {
2182 &ett_parameters_qos,
2188 #if defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H)
2189 /* UCD or CMU SNMP */
2191 #ifdef HAVE_UCD_SNMP_SNMP_H
2193 /* As per the comment near the beginning of the file, UCD SNMP 4.1.1
2194 changed "snmp_set_suffix_only()" from a function to a macro,
2195 removing "snmp_set_suffix_only()" from the library; this means
2196 that binaries that call "snmp_set_suffix_only()" and
2197 that are linked against shared libraries from earlier versions
2198 of the UCD SNMP library won't run with shared libraries from
2201 This is a problem on Red Hat Linux, as pre-6.2 releases
2202 came with pre-4.1.1 UCD SNMP, while 6.2 comes the 4.1.1.
2203 Versions of Ethereal built on pre-6.2 releases don't run
2204 on 6.2, and the current Ethereal RPMs are built on pre-6.2
2205 releases, causing problems when users running 6.2 download
2206 them and try to use them.
2208 Building the releases on 6.2 isn't necessarily the answer,
2209 as "snmp_set_suffix_only()" expands to a call to "ds_set_int()"
2210 with a second argument not supported by at least some pre-4.1.1
2211 versions of the library - it appears that the 4.0.1 library,
2212 at least, checks for invalid arguments and returns an error
2213 rather than stomping random memory, but that means that you
2214 won't get get OIDs displayed as module-name::sub-OID.
2216 So we use a trick similar to one I've seen mentioned as
2217 used in Windows applications to let you build binaries
2218 that run on many different versions of Windows 9x and
2219 Windows NT, that use features present on later versions
2220 if run on those later versions, but that avoid calling,
2221 when run on older versions, routines not present on those
2224 I.e., we load "libsnmp.so.0" with "dlopen()", and call
2225 "dlsym()" to try to find "snmp_set_suffix_only()"; if we
2226 don't find it, we make the appropriate call to
2227 "ds_set_int()" instead. (We load "libsnmp.so.0" rather
2228 than "libsnmp.so" because, at least on RH 6.2, "libsnmp.so"
2229 exists only if you've loaded the libsnmp development package,
2230 which makes "libsnmp.so" a symlink to "libsnmp.so.0"; we
2231 don't want to force users to install it or to make said
2234 We do this only on Linux, for now, as we've only seen the
2235 problem on Red Hat; it may show up on other OSes that bundle
2236 UCD SNMP, or on OSes where it's not bundled but for which
2237 binary packages are built that link against a shared version
2238 of the UCD SNMP library. If we run into one of those, we
2239 can do this under those OSes as well, *if* "dlopen()" makes
2240 the run-time linker use the same search rules as it uses when
2241 loading libraries with which the application is linked.
2243 (Perhaps we could use the GLib wrappers for run-time linking,
2244 *if* they're thin enough; however, as this code is currently
2245 used only on Linux, we don't worry about that for now.) */
2247 libsnmp_handle = dlopen("libsnmp.so.0", RTLD_LAZY|RTLD_GLOBAL);
2248 if (libsnmp_handle == NULL) {
2249 /* We didn't find "libsnmp.so.0".
2251 This could mean that there is no SNMP shared library
2252 on this system, in which case we were linked statically,
2253 in which case whatever call the following line of code
2254 makes will presumably work, as we have the routine it
2255 calls wired into our binary. (If we were linked
2256 dynamically with "-lsnmp", we would have failed to
2259 It could also mean that there is an SNMP shared library
2260 on this system, but it's called something other than
2261 "libsnmp.so.0"; so far, we've seen the problem we're
2262 working around only on systems where the SNMP shared
2263 library is called "libsnmp.so.0", so we assume for now
2264 that systems with shared SNMP libraries named something
2265 other than "libsnmp.so.0" have an SNMP library that's
2267 snmp_set_suffix_only(2);
2269 /* OK, we have it loaded. Do we have
2270 "snmp_set_suffix_only()"? */
2271 snmp_set_suffix_only_p = dlsym(libsnmp_handle,
2272 "snmp_set_suffix_only");
2273 if (snmp_set_suffix_only_p != NULL) {
2274 /* Yes - call it. */
2275 (*snmp_set_suffix_only_p)(2);
2277 /* No; do we have "ds_set_int()"? */
2278 ds_set_int_p = dlsym(libsnmp_handle, "ds_set_int");
2279 if (ds_set_int_p != NULL) {
2280 /* Yes - cal it with DS_LIBRARY_ID,
2281 DS_LIB_PRINT_SUFFIX_ONLY, and 2 as
2284 We do *not* use DS_LIBRARY_ID or
2285 DS_LIB_PRINT_SUFFIX_ONLY by name, so that
2286 we don't require that Ethereal be built
2287 with versions of UCD SNMP that include
2288 that value; instead, we use their values
2289 in UCD SNMP 4.1.1, which are 0 and 4,
2291 (*ds_set_int_p)(0, 4, 2);
2294 dlclose(libsnmp_handle);
2297 snmp_set_suffix_only(2);
2299 #endif /* HAVE_UCD_SNMP_SNMP_H */
2300 #endif /* defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H) */
2301 proto_snmp = proto_register_protocol("Simple Network Management Protocol",
2303 proto_smux = proto_register_protocol("SNMP Multiplex Protocol",
2305 proto_register_field_array(proto_snmp, hf, array_length(hf));
2306 proto_register_subtree_array(ett, array_length(ett));
2307 snmp_handle = create_dissector_handle(dissect_snmp, proto_snmp);
2311 proto_reg_handoff_snmp(void)
2313 dissector_handle_t smux_handle;
2315 dissector_add("udp.port", UDP_PORT_SNMP, snmp_handle);
2316 dissector_add("udp.port", UDP_PORT_SNMP_TRAP, snmp_handle);
2317 smux_handle = create_dissector_handle(dissect_smux, proto_smux);
2318 dissector_add("tcp.port", TCP_PORT_SMUX, smux_handle);
2319 dissector_add("ethertype", ETHERTYPE_SNMP, snmp_handle);
2320 dissector_add("ipx.socket", IPX_SOCKET_SNMP_AGENT, snmp_handle);
2321 dissector_add("ipx.socket", IPX_SOCKET_SNMP_SINK, snmp_handle);
2322 data_handle = find_dissector("data");