2 * Routines for SNMP (simple network management protocol)
5 * $Id: packet-snmp.c,v 1.56 2001/01/03 16:41:07 gram Exp $
7 * Ethereal - Network traffic analyzer
8 * By Gerald Combs <gerald@zing.org>
9 * Copyright 1998 Didier Jorand
13 * GXSNMP -- An snmp mangament application
14 * Copyright (C) 1998 Gregory McLean & Jochen Friedrich
15 * Beholder RMON ethernet network monitor,Copyright (C) 1993 DNPAP group
17 * This program is free software; you can redistribute it and/or
18 * modify it under the terms of the GNU General Public License
19 * as published by the Free Software Foundation; either version 2
20 * of the License, or (at your option) any later version.
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
27 * You should have received a copy of the GNU General Public License
28 * along with this program; if not, write to the Free Software
29 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
40 #ifdef HAVE_SYS_TYPES_H
41 # include <sys/types.h>
44 #ifdef HAVE_NETINET_IN_H
45 # include <netinet/in.h>
48 #define MAX_STRING_LEN 2048 /* TBC */
58 #include "conversation.h"
60 #include "packet-ipx.h"
62 #if defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H)
66 # if defined(HAVE_UCD_SNMP_SNMP_H)
70 # include <ucd-snmp/asn1.h>
71 # include <ucd-snmp/snmp_api.h>
72 # include <ucd-snmp/snmp_impl.h>
73 # include <ucd-snmp/mib.h>
76 * Sigh. UCD SNMP 4.1.1 makes "snmp_set_suffix_only()" a macro
77 * that calls "ds_set_int()" with the first two arguments
78 * being DS_LIBRARY_ID and DS_LIB_PRINT_SUFFIX_ONLY; this means that,
79 * when building with 4.1.1, we need to arrange that
80 * <ucd-snmp/default_store.h> is included, to define those two values
81 * and to declare "ds_int()".
85 * 1) we can't include it on earlier versions (at least not 3.6.2),
86 * as it doesn't exist in those versions;
88 * 2) we don't want to include <ucd-snmp/ucd-snmp-includes.h>,
89 * as that includes <ucd-snmp/snmp.h>, and that defines a whole
90 * bunch of values that we also define ourselves.
92 * So we only include it if "snmp_set_suffix_only" is defined as
95 # ifdef snmp_set_suffix_only
96 # include <ucd-snmp/default_store.h>
100 * XXX - for now, we assume all versions of UCD SNMP have it.
102 # define HAVE_SPRINT_VALUE
105 * Define values "sprint_value()" expects.
107 # define VALTYPE_INTEGER ASN_INTEGER
108 # define VALTYPE_COUNTER ASN_COUNTER
109 # define VALTYPE_GAUGE ASN_GAUGE
110 # define VALTYPE_TIMETICKS ASN_TIMETICKS
111 # define VALTYPE_STRING ASN_OCTET_STR
112 # define VALTYPE_IPADDR ASN_IPADDRESS
113 # define VALTYPE_OPAQUE ASN_OPAQUE
114 # define VALTYPE_NSAP ASN_NSAP
115 # define VALTYPE_OBJECTID ASN_OBJECT_ID
116 # define VALTYPE_BITSTR ASN_BIT_STR
117 # define VALTYPE_COUNTER64 ASN_COUNTER64
118 # elif defined(HAVE_SNMP_SNMP_H)
122 # include <snmp/snmp.h>
125 * Some older versions of CMU SNMP may lack these values (e.g., the
126 * "libsnmp3.6" package for Debian, which is based on some old
127 * CMU SNMP, perhaps 1.0); for now, we assume they also lack
131 # define HAVE_SPRINT_VALUE
133 * Define values "sprint_value()" expects.
135 # define VALTYPE_INTEGER SMI_INTEGER
136 # define VALTYPE_COUNTER SMI_COUNTER32
137 # define VALTYPE_GAUGE SMI_GAUGE32
138 # define VALTYPE_TIMETICKS SMI_TIMETICKS
139 # define VALTYPE_STRING SMI_STRING
140 # define VALTYPE_IPADDR SMI_IPADDRESS
141 # define VALTYPE_OPAQUE SMI_OPAQUE
142 # define VALTYPE_NSAP SMI_STRING
143 # define VALTYPE_OBJECTID SMI_OBJID
144 # define VALTYPE_BITSTR ASN_BIT_STR
145 # define VALTYPE_COUNTER64 SMI_COUNTER64
148 * Now undo all the definitions they "helpfully" gave us, so we don't get
149 * complaints about redefining them.
151 * Why, oh why, is there no library that provides code to
155 * 2) translate object IDs into names;
157 * 3) let you find out, for a given object ID, what the type, enum
158 * values, display hint, etc. are;
160 * in a *simple* fashion, without assuming that your code is part of an
161 * SNMP agent or client that wants a pile of definitions of PDU types,
162 * etc.? Is it just that 99 44/100% of the code that uses an SNMP library
163 * *is* part of an agent or client, and really *does* need that stuff,
164 * and *doesn't* need the interfaces we want?
166 # undef SNMP_ERR_NOERROR
167 # undef SNMP_ERR_TOOBIG
168 # undef SNMP_ERR_NOSUCHNAME
169 # undef SNMP_ERR_BADVALUE
170 # undef SNMP_ERR_READONLY
171 # undef SNMP_ERR_NOACCESS
172 # undef SNMP_ERR_WRONGTYPE
173 # undef SNMP_ERR_WRONGLENGTH
174 # undef SNMP_ERR_WRONGENCODING
175 # undef SNMP_ERR_WRONGVALUE
176 # undef SNMP_ERR_NOCREATION
177 # undef SNMP_ERR_INCONSISTENTVALUE
178 # undef SNMP_ERR_RESOURCEUNAVAILABLE
179 # undef SNMP_ERR_COMMITFAILED
180 # undef SNMP_ERR_UNDOFAILED
181 # undef SNMP_ERR_AUTHORIZATIONERROR
182 # undef SNMP_ERR_NOTWRITABLE
183 # undef SNMP_ERR_INCONSISTENTNAME
184 # undef SNMP_TRAP_COLDSTART
185 # undef SNMP_TRAP_WARMSTART
186 # undef SNMP_TRAP_LINKDOWN
187 # undef SNMP_TRAP_LINKUP
188 # undef SNMP_TRAP_EGPNEIGHBORLOSS
189 # undef SNMP_TRAP_ENTERPRISESPECIFIC
195 #include "packet-snmp.h"
197 /* Null string of type "guchar[]". */
198 static const guchar nullstring[] = "";
200 /* Take a pointer that may be null and return a pointer that's not null
201 by turning null pointers into pointers to the above null string. */
202 #define SAFE_STRING(s) (((s) != NULL) ? (s) : nullstring)
204 static int proto_snmp = -1;
205 static int proto_smux = -1;
207 static gint ett_snmp = -1;
208 static gint ett_smux = -1;
209 static gint ett_global = -1;
210 static gint ett_flags = -1;
211 static gint ett_secur = -1;
213 static int hf_snmpv3_flags = -1;
214 static int hf_snmpv3_flags_auth = -1;
215 static int hf_snmpv3_flags_crypt = -1;
216 static int hf_snmpv3_flags_report = -1;
219 #define TH_CRYPT 0x02
220 #define TH_REPORT 0x04
222 static const true_false_string flags_set_truth = {
227 #define UDP_PORT_SNMP 161
228 #define UDP_PORT_SNMP_TRAP 162
229 #define TCP_PORT_SMUX 199
231 /* Protocol version numbers */
232 #define SNMP_VERSION_1 0
233 #define SNMP_VERSION_2c 1
234 #define SNMP_VERSION_2u 2
235 #define SNMP_VERSION_3 3
237 static const value_string versions[] = {
238 { SNMP_VERSION_1, "1" },
239 { SNMP_VERSION_2c, "2C" },
240 { SNMP_VERSION_2u, "2U" },
241 { SNMP_VERSION_3, "3" },
246 #define SNMP_MSG_GET 0
247 #define SNMP_MSG_GETNEXT 1
248 #define SNMP_MSG_RESPONSE 2
249 #define SNMP_MSG_SET 3
250 #define SNMP_MSG_TRAP 4
252 #define SNMP_MSG_GETBULK 5
253 #define SNMP_MSG_INFORM 6
254 #define SNMP_MSG_TRAP2 7
255 #define SNMP_MSG_REPORT 8
257 static const value_string pdu_types[] = {
258 { SNMP_MSG_GET, "GET" },
259 { SNMP_MSG_GETNEXT, "GET-NEXT" },
260 { SNMP_MSG_SET, "SET" },
261 { SNMP_MSG_RESPONSE, "RESPONSE" },
262 { SNMP_MSG_TRAP, "TRAP-V1" },
263 { SNMP_MSG_GETBULK, "GETBULK" },
264 { SNMP_MSG_INFORM, "INFORM" },
265 { SNMP_MSG_TRAP2, "TRAP-V2" },
266 { SNMP_MSG_REPORT, "REPORT" },
271 #define SMUX_MSG_OPEN 0
272 #define SMUX_MSG_CLOSE 1
273 #define SMUX_MSG_RREQ 2
274 #define SMUX_MSG_RRSP 3
275 #define SMUX_MSG_SOUT 4
277 static const value_string smux_types[] = {
278 { SMUX_MSG_OPEN, "Open" },
279 { SMUX_MSG_CLOSE, "Close" },
280 { SMUX_MSG_RREQ, "Registration Request" },
281 { SMUX_MSG_RRSP, "Registration Response" },
282 { SMUX_MSG_SOUT, "Commit Or Rollback" },
286 /* SMUX Closing causes */
287 #define SMUX_CLOSE_DOWN 0
288 #define SMUX_CLOSE_VERSION 1
289 #define SMUX_CLOSE_PACKET 2
290 #define SMUX_CLOSE_PROTOCOL 3
291 #define SMUX_CLOSE_INTERNAL 4
292 #define SMUX_CLOSE_NOAUTH 5
294 static const value_string smux_close[] = {
295 { SMUX_CLOSE_DOWN, "Going down" },
296 { SMUX_CLOSE_VERSION, "Unsupported Version" },
297 { SMUX_CLOSE_PACKET, "Packet Format Error" },
298 { SMUX_CLOSE_PROTOCOL, "Protocol Error" },
299 { SMUX_CLOSE_INTERNAL, "Internal Error" },
300 { SMUX_CLOSE_NOAUTH, "Unauthorized" },
304 /* SMUX Request codes */
305 #define SMUX_RREQ_DELETE 0
306 #define SMUX_RREQ_READONLY 1
307 #define SMUX_RREQ_READWRITE 2
309 static const value_string smux_rreq[] = {
310 { SMUX_RREQ_DELETE, "Delete" },
311 { SMUX_RREQ_READONLY, "Read Only" },
312 { SMUX_RREQ_READWRITE, "Read Write" },
316 static const value_string smux_prio[] = {
321 /* SMUX SOut codes */
322 #define SMUX_SOUT_COMMIT 0
323 #define SMUX_SOUT_ROLLBACK 1
325 static const value_string smux_sout[] = {
326 { SMUX_SOUT_COMMIT, "Commit" },
327 { SMUX_SOUT_ROLLBACK, "Rollback" },
331 /* Error status values */
332 #define SNMP_ERR_NOERROR 0
333 #define SNMP_ERR_TOOBIG 1
334 #define SNMP_ERR_NOSUCHNAME 2
335 #define SNMP_ERR_BADVALUE 3
336 #define SNMP_ERR_READONLY 4
337 #define SNMP_ERR_GENERROR 5
339 #define SNMP_ERR_NOACCESS 6
340 #define SNMP_ERR_WRONGTYPE 7
341 #define SNMP_ERR_WRONGLENGTH 8
342 #define SNMP_ERR_WRONGENCODING 9
343 #define SNMP_ERR_WRONGVALUE 10
344 #define SNMP_ERR_NOCREATION 11
345 #define SNMP_ERR_INCONSISTENTVALUE 12
346 #define SNMP_ERR_RESOURCEUNAVAILABLE 13
347 #define SNMP_ERR_COMMITFAILED 14
348 #define SNMP_ERR_UNDOFAILED 15
349 #define SNMP_ERR_AUTHORIZATIONERROR 16
350 #define SNMP_ERR_NOTWRITABLE 17
351 #define SNMP_ERR_INCONSISTENTNAME 18
353 static const value_string error_statuses[] = {
354 { SNMP_ERR_NOERROR, "NO ERROR" },
355 { SNMP_ERR_TOOBIG, "TOOBIG" },
356 { SNMP_ERR_NOSUCHNAME, "NO SUCH NAME" },
357 { SNMP_ERR_BADVALUE, "BAD VALUE" },
358 { SNMP_ERR_READONLY, "READ ONLY" },
359 { SNMP_ERR_GENERROR, "GENERIC ERROR" },
360 { SNMP_ERR_NOACCESS, "NO ACCESS" },
361 { SNMP_ERR_WRONGTYPE, "WRONG TYPE" },
362 { SNMP_ERR_WRONGLENGTH, "WRONG LENGTH" },
363 { SNMP_ERR_WRONGENCODING, "WRONG ENCODING" },
364 { SNMP_ERR_WRONGVALUE, "WRONG VALUE" },
365 { SNMP_ERR_NOCREATION, "NO CREATION" },
366 { SNMP_ERR_INCONSISTENTVALUE, "INCONSISTENT VALUE" },
367 { SNMP_ERR_RESOURCEUNAVAILABLE, "RESOURCE UNAVAILABLE" },
368 { SNMP_ERR_COMMITFAILED, "COMMIT FAILED" },
369 { SNMP_ERR_UNDOFAILED, "UNDO FAILED" },
370 { SNMP_ERR_AUTHORIZATIONERROR, "AUTHORIZATION ERROR" },
371 { SNMP_ERR_NOTWRITABLE, "NOT WRITABLE" },
372 { SNMP_ERR_INCONSISTENTNAME, "INCONSISTENT NAME" },
376 /* General SNMP V1 Traps */
378 #define SNMP_TRAP_COLDSTART 0
379 #define SNMP_TRAP_WARMSTART 1
380 #define SNMP_TRAP_LINKDOWN 2
381 #define SNMP_TRAP_LINKUP 3
382 #define SNMP_TRAP_AUTHFAIL 4
383 #define SNMP_TRAP_EGPNEIGHBORLOSS 5
384 #define SNMP_TRAP_ENTERPRISESPECIFIC 6
386 static const value_string trap_types[] = {
387 { SNMP_TRAP_COLDSTART, "COLD START" },
388 { SNMP_TRAP_WARMSTART, "WARM START" },
389 { SNMP_TRAP_LINKDOWN, "LINK DOWN" },
390 { SNMP_TRAP_LINKUP, "LINK UP" },
391 { SNMP_TRAP_AUTHFAIL, "AUTHENTICATION FAILED" },
392 { SNMP_TRAP_EGPNEIGHBORLOSS, "EGP NEIGHBORLOSS" },
393 { SNMP_TRAP_ENTERPRISESPECIFIC, "ENTERPRISE SPECIFIC" },
397 /* Security Models */
399 #define SNMP_SEC_ANY 0
400 #define SNMP_SEC_V1 1
401 #define SNMP_SEC_V2C 2
402 #define SNMP_SEC_USM 3
404 static const value_string sec_models[] = {
405 { SNMP_SEC_ANY, "Any" },
406 { SNMP_SEC_V1, "V1" },
407 { SNMP_SEC_V2C, "V2C" },
408 { SNMP_SEC_USM, "USM" },
414 #define SNMP_IPA 0 /* IP Address */
415 #define SNMP_CNT 1 /* Counter (Counter32) */
416 #define SNMP_GGE 2 /* Gauge (Gauge32) */
417 #define SNMP_TIT 3 /* TimeTicks */
418 #define SNMP_OPQ 4 /* Opaque */
419 #define SNMP_NSP 5 /* NsapAddress */
420 #define SNMP_C64 6 /* Counter64 */
421 #define SNMP_U32 7 /* Uinteger32 */
430 #define SNMP_INTEGER 1 /* l */
431 #define SNMP_OCTETSTR 2 /* c */
432 #define SNMP_DISPLAYSTR 2 /* c */
433 #define SNMP_OBJECTID 3 /* ul */
434 #define SNMP_IPADDR 4 /* uc */
435 #define SNMP_COUNTER 5 /* ul */
436 #define SNMP_GAUGE 6 /* ul */
437 #define SNMP_TIMETICKS 7 /* ul */
438 #define SNMP_OPAQUE 8 /* c */
440 /* additional SNMPv2 Types */
442 #define SNMP_UINTEGER 5 /* ul */
443 #define SNMP_BITSTR 9 /* uc */
444 #define SNMP_NSAP 10 /* uc */
445 #define SNMP_COUNTER64 11 /* ul */
446 #define SNMP_NOSUCHOBJECT 12
447 #define SNMP_NOSUCHINSTANCE 13
448 #define SNMP_ENDOFMIBVIEW 14
450 typedef struct _SNMP_CNV SNMP_CNV;
460 static SNMP_CNV SnmpCnv [] =
462 {ASN1_UNI, ASN1_NUL, SNMP_NULL, "NULL"},
463 {ASN1_UNI, ASN1_INT, SNMP_INTEGER, "INTEGER"},
464 {ASN1_UNI, ASN1_OTS, SNMP_OCTETSTR, "OCTET STRING"},
465 {ASN1_UNI, ASN1_OJI, SNMP_OBJECTID, "OBJECTID"},
466 {ASN1_APL, SNMP_IPA, SNMP_IPADDR, "IPADDR"},
467 {ASN1_APL, SNMP_CNT, SNMP_COUNTER, "COUNTER"}, /* Counter32 */
468 {ASN1_APL, SNMP_GGE, SNMP_GAUGE, "GAUGE"}, /* Gauge32 == Unsigned32 */
469 {ASN1_APL, SNMP_TIT, SNMP_TIMETICKS, "TIMETICKS"},
470 {ASN1_APL, SNMP_OPQ, SNMP_OPAQUE, "OPAQUE"},
472 /* SNMPv2 data types and errors */
474 {ASN1_UNI, ASN1_BTS, SNMP_BITSTR, "BITSTR"},
475 {ASN1_APL, SNMP_C64, SNMP_COUNTER64, "COUNTER64"},
476 {ASN1_CTX, SERR_NSO, SNMP_NOSUCHOBJECT, "NOSUCHOBJECT"},
477 {ASN1_CTX, SERR_NSI, SNMP_NOSUCHINSTANCE, "NOSUCHINSTANCE"},
478 {ASN1_CTX, SERR_EOM, SNMP_ENDOFMIBVIEW, "ENDOFMIBVIEW"},
483 * NAME: g_snmp_tag_cls2syntax
484 * SYNOPSIS: gboolean g_snmp_tag_cls2syntax
490 * DESCRIPTION: Converts ASN1 tag and class to Syntax tag and name.
491 * See SnmpCnv for conversion.
492 * RETURNS: name on success, NULL on failure
496 snmp_tag_cls2syntax ( guint tag, guint cls, gushort *syntax)
501 while (cnv->syntax != -1)
503 if (cnv->tag == tag && cnv->class == cls)
505 *syntax = cnv->syntax;
514 dissect_snmp_parse_error(const u_char *pd, int offset, frame_data *fd,
515 proto_tree *tree, const char *field_name, int ret)
519 if (check_col(fd, COL_INFO)) {
523 errstr = "Ran out of data";
526 case ASN1_ERR_EOC_MISMATCH:
527 errstr = "EOC mismatch";
530 case ASN1_ERR_WRONG_TYPE:
531 errstr = "Wrong type for that item";
534 case ASN1_ERR_LENGTH_NOT_DEFINITE:
535 errstr = "Length was indefinite";
538 case ASN1_ERR_LENGTH_MISMATCH:
539 errstr = "Length mismatch";
542 case ASN1_ERR_WRONG_LENGTH_FOR_TYPE:
543 errstr = "Wrong length for that item's type";
547 errstr = "Unknown error";
550 col_add_fstr(fd, COL_INFO,
551 "ERROR: Couldn't parse %s: %s", field_name, errstr);
554 old_dissect_data(pd, offset, fd, tree);
558 dissect_snmp_error(const u_char *pd, int offset, frame_data *fd,
559 proto_tree *tree, const char *message)
561 if (check_col(fd, COL_INFO))
562 col_add_str(fd, COL_INFO, message);
564 old_dissect_data(pd, offset, fd, tree);
568 format_oid(subid_t *oid, guint oid_length)
575 result_len = oid_length * 22;
576 result = g_malloc(result_len + 1);
578 len = sprintf(buf, "%lu", (unsigned long)oid[0]);
580 for (i = 1; i < oid_length;i++) {
581 len = sprintf(buf, ".%lu", (unsigned long)oid[i]);
587 #ifdef HAVE_SPRINT_VALUE
589 format_var(struct variable_list *variable, subid_t *variable_oid,
590 guint variable_oid_length, gushort vb_type, guint vb_length)
600 /* We don't know how long this will be, but let's guess it
601 fits within 128 characters; that should be enough for an
602 integral value plus some sort of type indication. */
612 /* We don't know how long this will be, but let's guess it
613 fits within 128 characters plus 4 characters per octet. */
614 buf = g_malloc(128 + 4*vb_length);
618 /* We don't know how long this will be, but let's guess it
619 fits within 128 characters plus 32 characters per subid
620 (10 digits plus period, or a subid name). */
621 buf = g_malloc(1024 + 32*vb_length);
625 /* Should not happen. */
626 g_assert_not_reached();
631 variable->next_variable = NULL;
632 variable->name = variable_oid;
633 variable->name_length = variable_oid_length;
637 variable->type = VALTYPE_INTEGER;
641 variable->type = VALTYPE_COUNTER;
645 variable->type = VALTYPE_GAUGE;
649 variable->type = VALTYPE_TIMETICKS;
653 variable->type = VALTYPE_STRING;
657 variable->type = VALTYPE_IPADDR;
661 variable->type = VALTYPE_OPAQUE;
665 variable->type = VALTYPE_NSAP;
669 variable->type = VALTYPE_OBJECTID;
670 vb_length *= sizeof (subid_t); /* XXX - necessary? */
674 variable->type = VALTYPE_BITSTR;
678 variable->type = VALTYPE_COUNTER64;
681 variable->val_len = vb_length;
683 sprint_value(buf, variable_oid, variable_oid_length, variable);
689 snmp_variable_decode(proto_tree *snmp_tree, subid_t *variable_oid,
690 guint variable_oid_length, ASN1_SCK *asn1, int offset, guint *lengthp)
701 gint32 vb_integer_value;
702 guint32 vb_uinteger_value;
704 guint8 *vb_octet_string;
709 gchar *vb_display_string;
711 #ifdef HAVE_SPRINT_VALUE
712 struct variable_list variable;
713 #if defined(HAVE_UCD_SNMP_SNMP_H)
716 #else /* HAVE_SPRINT_VALUE */
720 #endif /* HAVE_SPRINT_VALUE */
722 /* parse the type of the object */
723 start = asn1->pointer;
724 ret = asn1_header_decode (asn1, &cls, &con, &tag, &def, &vb_length);
725 if (ret != ASN1_ERR_NOERROR)
728 return ASN1_ERR_LENGTH_NOT_DEFINITE;
730 /* Convert the class, constructed flag, and tag to a type. */
731 vb_type_name = snmp_tag_cls2syntax(tag, cls, &vb_type);
732 if (vb_type_name == NULL) {
735 * Dissect the value as an opaque string of octets.
737 vb_type_name = "unsupported type";
738 vb_type = SNMP_OPAQUE;
741 /* parse the value */
745 ret = asn1_int32_value_decode(asn1, vb_length,
747 if (ret != ASN1_ERR_NOERROR)
749 length = asn1->pointer - start;
751 #ifdef HAVE_SPRINT_VALUE
752 #if defined(HAVE_UCD_SNMP_SNMP_H)
753 value = vb_integer_value;
754 variable.val.integer = &value;
755 #elif defined(HAVE_SNMP_SNMP_H)
756 variable.val.integer = &vb_integer_value;
758 vb_display_string = format_var(&variable,
759 variable_oid, variable_oid_length, vb_type,
761 proto_tree_add_text(snmp_tree, NullTVB, offset, length,
762 "Value: %s", vb_display_string);
763 g_free(vb_display_string);
765 proto_tree_add_text(snmp_tree, NullTVB, offset, length,
766 "Value: %s: %d (%#x)", vb_type_name,
767 vb_integer_value, vb_integer_value);
775 ret = asn1_uint32_value_decode(asn1, vb_length,
777 if (ret != ASN1_ERR_NOERROR)
779 length = asn1->pointer - start;
781 #ifdef HAVE_SPRINT_VALUE
782 #if defined(HAVE_UCD_SNMP_SNMP_H)
783 value = vb_uinteger_value;
784 variable.val.integer = &value;
785 #elif defined(HAVE_SNMP_SNMP_H)
786 variable.val.integer = &vb_uinteger_value;
788 vb_display_string = format_var(&variable,
789 variable_oid, variable_oid_length, vb_type,
791 proto_tree_add_text(snmp_tree, NullTVB, offset, length,
792 "Value: %s", vb_display_string);
793 g_free(vb_display_string);
795 proto_tree_add_text(snmp_tree, NullTVB, offset, length,
796 "Value: %s: %u (%#x)", vb_type_name,
797 vb_uinteger_value, vb_uinteger_value);
808 ret = asn1_string_value_decode (asn1, vb_length,
810 if (ret != ASN1_ERR_NOERROR)
812 length = asn1->pointer - start;
814 #ifdef HAVE_SPRINT_VALUE
815 variable.val.string = vb_octet_string;
816 vb_display_string = format_var(&variable,
817 variable_oid, variable_oid_length, vb_type,
819 proto_tree_add_text(snmp_tree, NullTVB, offset, length,
820 "Value: %s", vb_display_string);
821 g_free(vb_display_string);
824 * If some characters are not printable, display
825 * the string as bytes.
827 for (i = 0; i < vb_length; i++) {
828 if (!(isprint(vb_octet_string[i])
829 || isspace(vb_octet_string[i])))
834 * We stopped, due to a non-printable
835 * character, before we got to the end
838 vb_display_string = g_malloc(4*vb_length);
839 buf = &vb_display_string[0];
840 len = sprintf(buf, "%03u", vb_octet_string[0]);
842 for (i = 1; i < vb_length; i++) {
843 len = sprintf(buf, ".%03u",
847 proto_tree_add_text(snmp_tree, NullTVB, offset, length,
848 "Value: %s: %s", vb_type_name,
850 g_free(vb_display_string);
852 proto_tree_add_text(snmp_tree, NullTVB, offset, length,
853 "Value: %s: %.*s", vb_type_name,
854 (int)vb_length, vb_octet_string);
858 g_free(vb_octet_string);
862 ret = asn1_null_decode (asn1, vb_length);
863 if (ret != ASN1_ERR_NOERROR)
865 length = asn1->pointer - start;
867 proto_tree_add_text(snmp_tree, NullTVB, offset, length,
868 "Value: %s", vb_type_name);
873 ret = asn1_oid_value_decode (asn1, vb_length, &vb_oid,
875 if (ret != ASN1_ERR_NOERROR)
877 length = asn1->pointer - start;
879 #ifdef HAVE_SPRINT_VALUE
880 variable.val.objid = vb_oid;
881 vb_display_string = format_var(&variable,
882 variable_oid, variable_oid_length, vb_type,
884 proto_tree_add_text(snmp_tree, NullTVB, offset, length,
885 "Value: %s", vb_display_string);
887 vb_display_string = format_oid(vb_oid, vb_oid_length);
888 proto_tree_add_text(snmp_tree, NullTVB, offset, length,
889 "Value: %s: %s", vb_type_name, vb_display_string);
891 g_free(vb_display_string);
896 case SNMP_NOSUCHOBJECT:
897 length = asn1->pointer - start;
899 proto_tree_add_text(snmp_tree, NullTVB, offset, length,
900 "Value: %s: no such object", vb_type_name);
904 case SNMP_NOSUCHINSTANCE:
905 length = asn1->pointer - start;
907 proto_tree_add_text(snmp_tree, NullTVB, offset, length,
908 "Value: %s: no such instance", vb_type_name);
912 case SNMP_ENDOFMIBVIEW:
913 length = asn1->pointer - start;
915 proto_tree_add_text(snmp_tree, NullTVB, offset, length,
916 "Value: %s: end of mib view", vb_type_name);
921 g_assert_not_reached();
922 return ASN1_ERR_WRONG_TYPE;
925 return ASN1_ERR_NOERROR;
929 dissect_common_pdu(const u_char *pd, int offset, frame_data *fd,
930 proto_tree *tree, ASN1_SCK asn1, guint pdu_type, const guchar *start)
934 guint sequence_length;
938 guint32 error_status;
942 char *pdu_type_string;
945 guint enterprise_length;
947 guint8 *agent_address;
948 guint agent_address_length;
952 guint32 specific_type;
955 guint timestamp_length;
959 guint variable_bindings_length;
962 guint variable_length;
963 subid_t *variable_oid;
964 guint variable_oid_length;
965 #if defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H)
966 gchar vb_oid_string[MAX_STRING_LEN]; /* TBC */
972 pdu_type_string = val_to_str(pdu_type, pdu_types,
973 "Unknown PDU type %#x");
974 if (check_col(fd, COL_INFO))
975 col_add_str(fd, COL_INFO, pdu_type_string);
976 length = asn1.pointer - start;
978 proto_tree_add_text(tree, NullTVB, offset, length,
979 "PDU type: %s", pdu_type_string);
983 /* get the fields in the PDU preceeding the variable-bindings sequence */
987 case SNMP_MSG_GETNEXT:
988 case SNMP_MSG_RESPONSE:
990 case SNMP_MSG_GETBULK:
991 case SNMP_MSG_INFORM:
993 case SNMP_MSG_REPORT:
995 ret = asn1_uint32_decode (&asn1, &request_id, &length);
996 if (ret != ASN1_ERR_NOERROR) {
997 dissect_snmp_parse_error(pd, offset, fd, tree,
1002 proto_tree_add_text(tree, NullTVB, offset, length,
1003 "Request Id: %#x", request_id);
1007 /* error status, or getbulk non-repeaters */
1008 ret = asn1_uint32_decode (&asn1, &error_status, &length);
1009 if (ret != ASN1_ERR_NOERROR) {
1010 dissect_snmp_parse_error(pd, offset, fd, tree,
1011 (pdu_type == SNMP_MSG_GETBULK) ? "non-repeaters"
1017 if (pdu_type == SNMP_MSG_GETBULK) {
1018 proto_tree_add_text(tree, NullTVB, offset,
1019 length, "Non-repeaters: %u", error_status);
1021 proto_tree_add_text(tree, NullTVB, offset,
1022 length, "Error Status: %s",
1023 val_to_str(error_status, error_statuses,
1029 /* error index, or getbulk max-repetitions */
1030 ret = asn1_uint32_decode (&asn1, &error_index, &length);
1031 if (ret != ASN1_ERR_NOERROR) {
1032 dissect_snmp_parse_error(pd, offset, fd, tree,
1033 (pdu_type == SNMP_MSG_GETBULK) ? "max repetitions"
1039 if (pdu_type == SNMP_MSG_GETBULK) {
1040 proto_tree_add_text(tree, NullTVB, offset,
1041 length, "Max repetitions: %u", error_index);
1043 proto_tree_add_text(tree, NullTVB, offset,
1044 length, "Error Index: %u", error_index);
1052 ret = asn1_oid_decode (&asn1, &enterprise, &enterprise_length,
1054 if (ret != ASN1_ERR_NOERROR) {
1055 dissect_snmp_parse_error(pd, offset, fd, tree,
1056 "enterprise OID", ret);
1060 oid_string = format_oid(enterprise, enterprise_length);
1061 proto_tree_add_text(tree, NullTVB, offset, length,
1062 "Enterprise: %s", oid_string);
1069 start = asn1.pointer;
1070 ret = asn1_header_decode (&asn1, &cls, &con, &tag,
1071 &def, &agent_address_length);
1072 if (ret != ASN1_ERR_NOERROR) {
1073 dissect_snmp_parse_error(pd, offset, fd, tree,
1074 "agent address", ret);
1077 if (!((cls == ASN1_APL && con == ASN1_PRI && tag == SNMP_IPA) ||
1078 (cls == ASN1_UNI && con == ASN1_PRI && tag == ASN1_OTS))) {
1079 /* GXSNMP 0.0.15 says the latter is "needed for
1081 dissect_snmp_parse_error(pd, offset, fd, tree,
1082 "agent_address", ASN1_ERR_WRONG_TYPE);
1085 if (agent_address_length != 4) {
1086 dissect_snmp_parse_error(pd, offset, fd, tree,
1087 "agent_address", ASN1_ERR_WRONG_LENGTH_FOR_TYPE);
1090 ret = asn1_string_value_decode (&asn1,
1091 agent_address_length, &agent_address);
1092 if (ret != ASN1_ERR_NOERROR) {
1093 dissect_snmp_parse_error(pd, offset, fd, tree,
1094 "agent address", ret);
1097 length = asn1.pointer - start;
1099 proto_tree_add_text(tree, NullTVB, offset, length,
1100 "Agent address: %s", ip_to_str(agent_address));
1102 g_free(agent_address);
1105 /* generic trap type */
1106 ret = asn1_uint32_decode (&asn1, &trap_type, &length);
1107 if (ret != ASN1_ERR_NOERROR) {
1108 dissect_snmp_parse_error(pd, offset, fd, tree,
1109 "generic trap type", ret);
1113 proto_tree_add_text(tree, NullTVB, offset, length,
1115 val_to_str(trap_type, trap_types, "Unknown (%u)"));
1119 /* specific trap type */
1120 ret = asn1_uint32_decode (&asn1, &specific_type, &length);
1121 if (ret != ASN1_ERR_NOERROR) {
1122 dissect_snmp_parse_error(pd, offset, fd, tree,
1123 "specific trap type", ret);
1127 proto_tree_add_text(tree, NullTVB, offset, length,
1128 "Specific trap type: %u (%#x)",
1129 specific_type, specific_type);
1134 start = asn1.pointer;
1135 ret = asn1_header_decode (&asn1, &cls, &con, &tag,
1136 &def, ×tamp_length);
1137 if (ret != ASN1_ERR_NOERROR) {
1138 dissect_snmp_parse_error(pd, offset, fd, tree,
1142 if (!((cls == ASN1_APL && con == ASN1_PRI && tag == SNMP_TIT) ||
1143 (cls == ASN1_UNI && con == ASN1_PRI && tag == ASN1_INT))) {
1144 dissect_snmp_parse_error(pd, offset, fd, tree,
1145 "timestamp", ASN1_ERR_WRONG_TYPE);
1148 ret = asn1_uint32_value_decode(&asn1, timestamp_length,
1150 if (ret != ASN1_ERR_NOERROR) {
1151 dissect_snmp_parse_error(pd, offset, fd, tree,
1155 length = asn1.pointer - start;
1157 proto_tree_add_text(tree, NullTVB, offset, length,
1158 "Timestamp: %u", timestamp);
1164 /* variable bindings */
1165 /* get header for variable-bindings sequence */
1166 ret = asn1_sequence_decode(&asn1, &variable_bindings_length, &length);
1167 if (ret != ASN1_ERR_NOERROR) {
1168 dissect_snmp_parse_error(pd, offset, fd, tree,
1169 "variable bindings header", ret);
1174 /* loop on variable bindings */
1176 while (variable_bindings_length > 0) {
1178 sequence_length = 0;
1181 ret = asn1_sequence_decode(&asn1, &variable_length, &length);
1182 if (ret != ASN1_ERR_NOERROR) {
1183 dissect_snmp_parse_error(pd, offset, fd, tree,
1184 "variable binding header", ret);
1187 sequence_length += length;
1189 /* parse object identifier */
1190 ret = asn1_oid_decode (&asn1, &variable_oid,
1191 &variable_oid_length, &length);
1192 if (ret != ASN1_ERR_NOERROR) {
1193 dissect_snmp_parse_error(pd, offset, fd, tree,
1194 "variable binding OID", ret);
1197 sequence_length += length;
1200 oid_string = format_oid(variable_oid,
1201 variable_oid_length);
1203 #if defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H)
1204 sprint_objid(vb_oid_string, variable_oid,
1205 variable_oid_length);
1206 proto_tree_add_text(tree, NullTVB, offset, sequence_length,
1207 "Object identifier %d: %s (%s)", vb_index,
1208 oid_string, vb_oid_string);
1211 proto_tree_add_text(tree, NullTVB, offset, sequence_length,
1212 "Object identifier %d: %s", vb_index,
1217 offset += sequence_length;
1218 variable_bindings_length -= sequence_length;
1220 /* Parse the variable's value */
1221 ret = snmp_variable_decode(tree, variable_oid,
1222 variable_oid_length, &asn1, offset, &length);
1223 if (ret != ASN1_ERR_NOERROR) {
1224 dissect_snmp_parse_error(pd, offset, fd, tree,
1229 variable_bindings_length -= length;
1234 dissect_snmp_pdu(const u_char *pd, int offset, frame_data *fd,
1235 proto_tree *tree, char *proto_name, int proto, gint ett)
1238 const guchar *start;
1242 guint message_length;
1243 guint global_length;
1249 guint32 engineboots;
1262 int msgflags_length;
1263 int community_length;
1265 int cengineid_length;
1267 int cryptpdu_length;
1268 int aengineid_length;
1269 int username_length;
1276 proto_tree *snmp_tree = NULL;
1277 proto_tree *global_tree = NULL;
1278 proto_tree *flags_tree = NULL;
1279 proto_tree *secur_tree = NULL;
1280 proto_item *item = NULL;
1282 guint cls, con, tag;
1284 if (check_col(fd, COL_PROTOCOL))
1285 col_add_str(fd, COL_PROTOCOL, proto_name);
1288 item = proto_tree_add_item(tree, proto, NullTVB, offset,
1289 END_OF_FRAME, FALSE);
1290 snmp_tree = proto_item_add_subtree(item, ett);
1293 /* NOTE: we have to parse the message piece by piece, since the
1294 * capture length may be less than the message length: a 'global'
1295 * parsing is likely to fail.
1297 /* parse the SNMP header */
1298 asn1_open(&asn1, &pd[offset], END_OF_FRAME);
1299 ret = asn1_sequence_decode(&asn1, &message_length, &length);
1300 if (ret != ASN1_ERR_NOERROR) {
1301 dissect_snmp_parse_error(pd, offset, fd, tree,
1302 "message header", ret);
1307 ret = asn1_uint32_decode (&asn1, &version, &length);
1308 if (ret != ASN1_ERR_NOERROR) {
1309 dissect_snmp_parse_error(pd, offset, fd, tree, "version number",
1314 proto_tree_add_text(snmp_tree, NullTVB, offset, length,
1316 val_to_str(version, versions, "Unknown version %#x"));
1322 case SNMP_VERSION_1:
1323 case SNMP_VERSION_2c:
1324 ret = asn1_octet_string_decode (&asn1, &community,
1325 &community_length, &length);
1326 if (ret != ASN1_ERR_NOERROR) {
1327 dissect_snmp_parse_error(pd, offset, fd, tree,
1332 proto_tree_add_text(snmp_tree, NullTVB, offset, length,
1333 "Community: %.*s", community_length,
1334 SAFE_STRING(community));
1339 case SNMP_VERSION_2u:
1342 case SNMP_VERSION_3:
1343 ret = asn1_sequence_decode(&asn1, &global_length, &length);
1344 if (ret != ASN1_ERR_NOERROR) {
1345 dissect_snmp_parse_error(pd, offset, fd, tree,
1346 "message global header", ret);
1350 item = proto_tree_add_text(snmp_tree, NullTVB, offset,
1351 global_length + length, "Message Global Header");
1352 global_tree = proto_item_add_subtree(item, ett_global);
1353 proto_tree_add_text(global_tree, NullTVB, offset,
1355 "Message Global Header Length: %d", global_length);
1358 ret = asn1_uint32_decode (&asn1, &msgid, &length);
1359 if (ret != ASN1_ERR_NOERROR) {
1360 dissect_snmp_parse_error(pd, offset, fd, tree,
1365 proto_tree_add_text(global_tree, NullTVB, offset,
1366 length, "Message ID: %d", msgid);
1369 ret = asn1_uint32_decode (&asn1, &msgmax, &length);
1370 if (ret != ASN1_ERR_NOERROR) {
1371 dissect_snmp_parse_error(pd, offset, fd, tree,
1372 "message max size", ret);
1376 proto_tree_add_text(global_tree, NullTVB, offset,
1377 length, "Message Max Size: %d", msgmax);
1380 ret = asn1_octet_string_decode (&asn1, &msgflags,
1381 &msgflags_length, &length);
1382 if (ret != ASN1_ERR_NOERROR) {
1383 dissect_snmp_parse_error(pd, offset, fd, tree,
1384 "message flags", ret);
1387 if (msgflags_length != 1) {
1388 dissect_snmp_parse_error(pd, offset, fd, tree,
1389 "message flags wrong length", ret);
1394 item = proto_tree_add_uint_format(global_tree,
1395 hf_snmpv3_flags, NullTVB, offset, length,
1396 msgflags[0], "Flags: 0x%02x", msgflags[0]);
1397 flags_tree = proto_item_add_subtree(item, ett_flags);
1398 proto_tree_add_boolean(flags_tree, hf_snmpv3_flags_report,
1399 NullTVB, offset, length, msgflags[0]);
1400 proto_tree_add_boolean(flags_tree, hf_snmpv3_flags_crypt,
1401 NullTVB, offset, length, msgflags[0]);
1402 proto_tree_add_boolean(flags_tree, hf_snmpv3_flags_auth,
1403 NullTVB, offset, length, msgflags[0]);
1405 encrypted = msgflags[0] & TH_CRYPT;
1408 ret = asn1_uint32_decode (&asn1, &msgsec, &length);
1409 if (ret != ASN1_ERR_NOERROR) {
1410 dissect_snmp_parse_error(pd, offset, fd, tree,
1411 "message security model", ret);
1415 proto_tree_add_text(global_tree, NullTVB, offset,
1416 length, "Message Security Model: %s",
1417 val_to_str(msgsec, sec_models,
1418 "Unknown model %#x"));
1423 start = asn1.pointer;
1424 ret = asn1_header_decode (&asn1, &cls, &con, &tag,
1425 &def, &secparm_length);
1426 length = asn1.pointer - start;
1427 if (cls != ASN1_UNI && con != ASN1_PRI &&
1429 dissect_snmp_parse_error(pd, offset, fd, tree,
1430 "Message Security Parameters",
1431 ASN1_ERR_WRONG_TYPE);
1435 item = proto_tree_add_text(snmp_tree, NullTVB,
1436 offset, secparm_length + length,
1437 "Message Security Parameters");
1438 secur_tree = proto_item_add_subtree(item,
1440 proto_tree_add_text(secur_tree, NullTVB, offset,
1442 "Message Security Parameters Length: %d",
1446 ret = asn1_sequence_decode(&asn1, &secparm_length,
1448 if (ret != ASN1_ERR_NOERROR) {
1449 dissect_snmp_parse_error(pd, offset, fd, tree,
1450 "USM sequence header", ret);
1454 ret = asn1_octet_string_decode (&asn1, &aengineid,
1455 &aengineid_length, &length);
1456 if (ret != ASN1_ERR_NOERROR) {
1457 dissect_snmp_parse_error(pd, offset, fd, tree,
1458 "authoritative engine id", ret);
1462 proto_tree_add_text(secur_tree, NullTVB, offset,
1463 length, "Authoritative Engine ID: %s",
1464 bytes_to_str(aengineid, aengineid_length));
1468 ret = asn1_uint32_decode (&asn1, &engineboots, &length);
1469 if (ret != ASN1_ERR_NOERROR) {
1470 dissect_snmp_parse_error(pd, offset, fd, tree,
1471 "engine boots", ret);
1475 proto_tree_add_text(secur_tree, NullTVB,
1476 offset, length, "Engine Boots: %d",
1480 ret = asn1_uint32_decode (&asn1, &enginetime, &length);
1481 if (ret != ASN1_ERR_NOERROR) {
1482 dissect_snmp_parse_error(pd, offset, fd, tree,
1483 "engine time", ret);
1487 proto_tree_add_text(secur_tree, NullTVB,
1488 offset, length, "Engine Time: %d",
1492 ret = asn1_octet_string_decode (&asn1, &username,
1493 &username_length, &length);
1494 if (ret != ASN1_ERR_NOERROR) {
1495 dissect_snmp_parse_error(pd, offset, fd, tree,
1500 proto_tree_add_text(secur_tree, NullTVB, offset,
1501 length, "User Name: %.*s",
1503 SAFE_STRING(username));
1507 ret = asn1_octet_string_decode (&asn1, &authpar,
1508 &authpar_length, &length);
1509 if (ret != ASN1_ERR_NOERROR) {
1510 dissect_snmp_parse_error(pd, offset, fd, tree,
1511 "authentication parameter", ret);
1515 proto_tree_add_text(secur_tree, NullTVB, offset,
1516 length, "Authentication Parameter: %s",
1517 bytes_to_str(authpar, authpar_length));
1521 ret = asn1_octet_string_decode (&asn1, &privpar,
1522 &privpar_length, &length);
1523 if (ret != ASN1_ERR_NOERROR) {
1524 dissect_snmp_parse_error(pd, offset, fd, tree,
1525 "privacy parameter", ret);
1529 proto_tree_add_text(secur_tree, NullTVB, offset,
1530 length, "Privacy Parameter: %s",
1531 bytes_to_str(privpar, privpar_length));
1537 ret = asn1_octet_string_decode (&asn1,
1538 &secparm, &secparm_length, &length);
1539 if (ret != ASN1_ERR_NOERROR) {
1540 dissect_snmp_parse_error(pd, offset, fd, tree,
1541 "Message Security Parameters", ret);
1545 proto_tree_add_text(snmp_tree, NullTVB, offset,
1547 "Message Security Parameters Data"
1548 " (%d bytes)", secparm_length);
1554 /* PDU starts here */
1556 ret = asn1_octet_string_decode (&asn1, &cryptpdu,
1557 &cryptpdu_length, &length);
1558 if (ret != ASN1_ERR_NOERROR) {
1559 dissect_snmp_parse_error(pd, offset, fd, tree,
1560 "encrypted PDU header", ret);
1563 proto_tree_add_text(snmp_tree, NullTVB, offset, length,
1564 "Encrypted PDU (%d bytes)", length);
1566 if (check_col(fd, COL_INFO))
1567 col_set_str(fd, COL_INFO, "Encrypted PDU");
1570 ret = asn1_sequence_decode(&asn1, &global_length, &length);
1571 if (ret != ASN1_ERR_NOERROR) {
1572 dissect_snmp_parse_error(pd, offset, fd, tree,
1577 ret = asn1_octet_string_decode (&asn1, &cengineid,
1578 &cengineid_length, &length);
1579 if (ret != ASN1_ERR_NOERROR) {
1580 dissect_snmp_parse_error(pd, offset, fd, tree,
1581 "context engine id", ret);
1585 proto_tree_add_text(snmp_tree, NullTVB, offset, length,
1586 "Context Engine ID: %s",
1587 bytes_to_str(cengineid, cengineid_length));
1591 ret = asn1_octet_string_decode (&asn1, &cname,
1592 &cname_length, &length);
1593 if (ret != ASN1_ERR_NOERROR) {
1594 dissect_snmp_parse_error(pd, offset, fd, tree,
1595 "context name", ret);
1599 proto_tree_add_text(snmp_tree, NullTVB, offset, length,
1600 "Context Name: %.*s", cname_length,
1601 SAFE_STRING(cname));
1607 dissect_snmp_error(pd, offset, fd, tree,
1608 "PDU for unknown version of SNMP");
1612 start = asn1.pointer;
1613 ret = asn1_header_decode (&asn1, &cls, &con, &pdu_type, &def,
1615 if (ret != ASN1_ERR_NOERROR) {
1616 dissect_snmp_parse_error(pd, offset, fd, tree,
1620 if (cls != ASN1_CTX || con != ASN1_CON) {
1621 dissect_snmp_parse_error(pd, offset, fd, tree,
1622 "PDU type", ASN1_ERR_WRONG_TYPE);
1625 dissect_common_pdu(pd, offset, fd, snmp_tree, asn1, pdu_type, start);
1629 dissect_smux_pdu(const u_char *pd, int offset, frame_data *fd,
1630 proto_tree *tree, int proto, gint ett)
1633 const guchar *start;
1638 char *pdu_type_string;
1648 int password_length;
1650 guchar *application;
1651 int application_length;
1658 proto_tree *smux_tree = NULL;
1659 proto_item *item = NULL;
1663 if (check_col(fd, COL_PROTOCOL))
1664 col_set_str(fd, COL_PROTOCOL, "SMUX");
1667 item = proto_tree_add_item(tree, proto, NullTVB, offset,
1668 END_OF_FRAME, FALSE);
1669 smux_tree = proto_item_add_subtree(item, ett);
1672 /* NOTE: we have to parse the message piece by piece, since the
1673 * capture length may be less than the message length: a 'global'
1674 * parsing is likely to fail.
1676 /* parse the SNMP header */
1677 asn1_open(&asn1, &pd[offset], END_OF_FRAME);
1678 start = asn1.pointer;
1679 ret = asn1_header_decode (&asn1, &cls, &con, &pdu_type, &def,
1681 if (ret != ASN1_ERR_NOERROR) {
1682 dissect_snmp_parse_error(pd, offset, fd, tree,
1687 /* Dissect SMUX here */
1688 if (cls == ASN1_APL && con == ASN1_CON && pdu_type == SMUX_MSG_OPEN) {
1689 pdu_type_string = val_to_str(pdu_type, smux_types,
1690 "Unknown PDU type %#x");
1691 if (check_col(fd, COL_INFO))
1692 col_add_str(fd, COL_INFO, pdu_type_string);
1693 length = asn1.pointer - start;
1695 proto_tree_add_text(smux_tree, NullTVB, offset, length,
1696 "PDU type: %s", pdu_type_string);
1699 ret = asn1_uint32_decode (&asn1, &version, &length);
1700 if (ret != ASN1_ERR_NOERROR) {
1701 dissect_snmp_parse_error(pd, offset, fd, tree,
1706 proto_tree_add_text(smux_tree, NullTVB, offset, length,
1707 "Version: %d", version);
1711 ret = asn1_oid_decode (&asn1, ®id, ®id_length, &length);
1712 if (ret != ASN1_ERR_NOERROR) {
1713 dissect_snmp_parse_error(pd, offset, fd, tree,
1714 "registration OID", ret);
1718 oid_string = format_oid(regid, regid_length);
1719 proto_tree_add_text(smux_tree, NullTVB, offset, length,
1720 "Registration: %s", oid_string);
1726 ret = asn1_octet_string_decode (&asn1, &application,
1727 &application_length, &length);
1728 if (ret != ASN1_ERR_NOERROR) {
1729 dissect_snmp_parse_error(pd, offset, fd, tree,
1730 "application", ret);
1734 proto_tree_add_text(smux_tree, NullTVB, offset, length,
1735 "Application: %.*s", application_length,
1736 SAFE_STRING(application));
1738 g_free(application);
1741 ret = asn1_octet_string_decode (&asn1, &password,
1742 &password_length, &length);
1743 if (ret != ASN1_ERR_NOERROR) {
1744 dissect_snmp_parse_error(pd, offset, fd, tree,
1749 proto_tree_add_text(smux_tree, NullTVB, offset, length,
1750 "Password: %.*s", password_length,
1751 SAFE_STRING(password));
1757 if (cls == ASN1_APL && con == ASN1_PRI && pdu_type == SMUX_MSG_CLOSE) {
1758 pdu_type_string = val_to_str(pdu_type, smux_types,
1759 "Unknown PDU type %#x");
1760 if (check_col(fd, COL_INFO))
1761 col_add_str(fd, COL_INFO, pdu_type_string);
1762 length = asn1.pointer - start;
1764 proto_tree_add_text(smux_tree, NullTVB, offset, length,
1765 "PDU type: %s", pdu_type_string);
1768 ret = asn1_uint32_value_decode (&asn1, pdu_length, &cause);
1769 if (ret != ASN1_ERR_NOERROR) {
1770 dissect_snmp_parse_error(pd, offset, fd, tree,
1775 proto_tree_add_text(smux_tree, NullTVB, offset,
1776 pdu_length, "Cause: %s",
1777 val_to_str(cause, smux_close,
1778 "Unknown cause %#x"));
1780 offset += pdu_length;
1783 if (cls == ASN1_APL && con == ASN1_CON && pdu_type == SMUX_MSG_RREQ) {
1784 pdu_type_string = val_to_str(pdu_type, smux_types,
1785 "Unknown PDU type %#x");
1786 if (check_col(fd, COL_INFO))
1787 col_add_str(fd, COL_INFO, pdu_type_string);
1788 length = asn1.pointer - start;
1790 proto_tree_add_text(smux_tree, NullTVB, offset, length,
1791 "PDU type: %s", pdu_type_string);
1794 ret = asn1_oid_decode (&asn1, ®id, ®id_length, &length);
1795 if (ret != ASN1_ERR_NOERROR) {
1796 dissect_snmp_parse_error(pd, offset, fd, tree,
1797 "registration subtree", ret);
1801 oid_string = format_oid(regid, regid_length);
1802 proto_tree_add_text(smux_tree, NullTVB, offset, length,
1803 "Registration: %s", oid_string);
1809 ret = asn1_uint32_decode (&asn1, &priority, &length);
1810 if (ret != ASN1_ERR_NOERROR) {
1811 dissect_snmp_parse_error(pd, offset, fd, tree,
1816 proto_tree_add_text(smux_tree, NullTVB, offset, length,
1817 "Priority: %d", priority);
1821 ret = asn1_uint32_decode (&asn1, &operation, &length);
1822 if (ret != ASN1_ERR_NOERROR) {
1823 dissect_snmp_parse_error(pd, offset, fd, tree,
1828 proto_tree_add_text(smux_tree, NullTVB, offset, length,
1830 val_to_str(operation, smux_rreq,
1831 "Unknown operation %#x"));
1836 if (cls == ASN1_APL && con == ASN1_PRI && pdu_type == SMUX_MSG_RRSP) {
1837 pdu_type_string = val_to_str(pdu_type, smux_types,
1838 "Unknown PDU type %#x");
1839 if (check_col(fd, COL_INFO))
1840 col_add_str(fd, COL_INFO, pdu_type_string);
1841 length = asn1.pointer - start;
1843 proto_tree_add_text(smux_tree, NullTVB, offset, length,
1844 "PDU type: %s", pdu_type_string);
1847 ret = asn1_uint32_value_decode (&asn1, pdu_length, &priority);
1848 if (ret != ASN1_ERR_NOERROR) {
1849 dissect_snmp_parse_error(pd, offset, fd, tree,
1854 proto_tree_add_text(smux_tree, NullTVB, offset,
1856 val_to_str(priority, smux_prio,
1859 offset += pdu_length;
1862 if (cls == ASN1_APL && con == ASN1_PRI && pdu_type == SMUX_MSG_SOUT) {
1863 pdu_type_string = val_to_str(pdu_type, smux_types,
1864 "Unknown PDU type %#x");
1865 if (check_col(fd, COL_INFO))
1866 col_add_str(fd, COL_INFO, pdu_type_string);
1867 length = asn1.pointer - start;
1869 proto_tree_add_text(smux_tree, NullTVB, offset, length,
1870 "PDU type: %s", pdu_type_string);
1873 ret = asn1_uint32_value_decode (&asn1, pdu_length, &commit);
1874 if (ret != ASN1_ERR_NOERROR) {
1875 dissect_snmp_parse_error(pd, offset, fd, tree,
1880 proto_tree_add_text(smux_tree, NullTVB, offset,
1882 val_to_str(commit, smux_sout,
1883 "Unknown SOUT Value: %#x"));
1885 offset += pdu_length;
1888 if (cls != ASN1_CTX || con != ASN1_CON) {
1889 dissect_snmp_parse_error(pd, offset, fd, tree,
1890 "PDU type", ASN1_ERR_WRONG_TYPE);
1893 dissect_common_pdu(pd, offset, fd, smux_tree, asn1, pdu_type, start);
1897 dissect_snmp(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
1899 conversation_t *conversation;
1901 OLD_CHECK_DISPLAY_AS_DATA(proto_snmp, pd, offset, fd, tree);
1904 * The first SNMP packet goes to the SNMP port; the second one
1905 * may come from some *other* port, but goes back to the same
1906 * IP address and port as the ones from which the first packet
1907 * came; all subsequent packets presumably go between those two
1908 * IP addresses and ports.
1910 * If this packet went to the SNMP port, we check to see if
1911 * there's already a conversation with the source IP address
1912 * and port of this packet, the destination IP address of this
1913 * packet, and any destination UDP port. If not, we create
1914 * one, with a wildcard UDP port, and give it the SNMP dissector
1917 if (pi.destport == UDP_PORT_SNMP) {
1918 conversation = find_conversation(&pi.src, &pi.dst, PT_UDP,
1919 pi.srcport, 0, NO_DST_PORT);
1920 if (conversation == NULL) {
1921 conversation = conversation_new(&pi.src, &pi.dst, PT_UDP,
1922 pi.srcport, 0, NULL,
1924 old_conversation_set_dissector(conversation, dissect_snmp);
1928 dissect_snmp_pdu(pd, offset, fd, tree, "SNMP", proto_snmp, ett_snmp);
1932 dissect_smux(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
1934 OLD_CHECK_DISPLAY_AS_DATA(proto_smux, pd, offset, fd, tree);
1935 dissect_smux_pdu(pd, offset, fd, tree, proto_smux, ett_smux);
1939 proto_register_snmp(void)
1942 void *libsnmp_handle;
1943 int (*snmp_set_suffix_only_p)(int);
1944 int (*ds_set_int_p)(int, int, int);
1947 static hf_register_info hf[] = {
1949 { "SNMPv3 Flags", "snmpv3.flags", FT_UINT8, BASE_HEX, NULL,
1951 { &hf_snmpv3_flags_auth,
1952 { "Authenticated", "snmpv3.flags.auth", FT_BOOLEAN, 8,
1953 TFS(&flags_set_truth), TH_AUTH, "" }},
1954 { &hf_snmpv3_flags_crypt,
1955 { "Encrypted", "snmpv3.flags.crypt", FT_BOOLEAN, 8,
1956 TFS(&flags_set_truth), TH_CRYPT, "" }},
1957 { &hf_snmpv3_flags_report,
1958 { "Reportable", "snmpv3.flags.report", FT_BOOLEAN, 8,
1959 TFS(&flags_set_truth), TH_REPORT, "" }},
1961 static gint *ett[] = {
1969 #if defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H)
1970 /* UCD or CMU SNMP */
1972 #ifdef HAVE_UCD_SNMP_SNMP_H
1974 /* As per the comment near the beginning of the file, UCD SNMP 4.1.1
1975 changed "snmp_set_suffix_only()" from a function to a macro,
1976 removing "snmp_set_suffix_only()" from the library; this means
1977 that binaries that call "snmp_set_suffix_only()" and
1978 that are linked against shared libraries from earlier versions
1979 of the UCD SNMP library won't run with shared libraries from
1982 This is a problem on Red Hat Linux, as pre-6.2 releases
1983 came with pre-4.1.1 UCD SNMP, while 6.2 comes the 4.1.1.
1984 Versions of Ethereal built on pre-6.2 releases don't run
1985 on 6.2, and the current Ethereal RPMs are built on pre-6.2
1986 releases, causing problems when users running 6.2 download
1987 them and try to use them.
1989 Building the releases on 6.2 isn't necessarily the answer,
1990 as "snmp_set_suffix_only()" expands to a call to "ds_set_int()"
1991 with a second argument not supported by at least some pre-4.1.1
1992 versions of the library - it appears that the 4.0.1 library,
1993 at least, checks for invalid arguments and returns an error
1994 rather than stomping random memory, but that means that you
1995 won't get get OIDs displayed as module-name::sub-OID.
1997 So we use a trick similar to one I've seen mentioned as
1998 used in Windows applications to let you build binaries
1999 that run on many different versions of Windows 9x and
2000 Windows NT, that use features present on later versions
2001 if run on those later versions, but that avoid calling,
2002 when run on older versions, routines not present on those
2005 I.e., we load "libsnmp.so.0" with "dlopen()", and call
2006 "dlsym()" to try to find "snmp_set_suffix_only()"; if we
2007 don't find it, we make the appropriate call to
2008 "ds_set_int()" instead. (We load "libsnmp.so.0" rather
2009 than "libsnmp.so" because, at least on RH 6.2, "libsnmp.so"
2010 exists only if you've loaded the libsnmp development package,
2011 which makes "libsnmp.so" a symlink to "libsnmp.so.0"; we
2012 don't want to force users to install it or to make said
2015 We do this only on Linux, for now, as we've only seen the
2016 problem on Red Hat; it may show up on other OSes that bundle
2017 UCD SNMP, or on OSes where it's not bundled but for which
2018 binary packages are built that link against a shared version
2019 of the UCD SNMP library. If we run into one of those, we
2020 can do this under those OSes as well, *if* "dlopen()" makes
2021 the run-time linker use the same search rules as it uses when
2022 loading libraries with which the application is linked.
2024 (Perhaps we could use the GLib wrappers for run-time linking,
2025 *if* they're thin enough; however, as this code is currently
2026 used only on Linux, we don't worry about that for now.) */
2028 libsnmp_handle = dlopen("libsnmp.so.0", RTLD_LAZY|RTLD_GLOBAL);
2029 if (libsnmp_handle == NULL) {
2030 /* We didn't find "libsnmp.so.0".
2032 This could mean that there is no SNMP shared library
2033 on this system, in which case we were linked statically,
2034 in which case whatever call the following line of code
2035 makes will presumably work, as we have the routine it
2036 calls wired into our binary. (If we were linked
2037 dynamically with "-lsnmp", we would have failed to
2040 It could also mean that there is an SNMP shared library
2041 on this system, but it's called something other than
2042 "libsnmp.so.0"; so far, we've seen the problem we're
2043 working around only on systems where the SNMP shared
2044 library is called "libsnmp.so.0", so we assume for now
2045 that systems with shared SNMP libraries named something
2046 other than "libsnmp.so.0" have an SNMP library that's
2048 snmp_set_suffix_only(2);
2050 /* OK, we have it loaded. Do we have
2051 "snmp_set_suffix_only()"? */
2052 snmp_set_suffix_only_p = dlsym(libsnmp_handle,
2053 "snmp_set_suffix_only");
2054 if (snmp_set_suffix_only_p != NULL) {
2055 /* Yes - call it. */
2056 (*snmp_set_suffix_only_p)(2);
2058 /* No; do we have "ds_set_int()"? */
2059 ds_set_int_p = dlsym(libsnmp_handle, "ds_set_int");
2060 if (ds_set_int_p != NULL) {
2061 /* Yes - cal it with DS_LIBRARY_ID,
2062 DS_LIB_PRINT_SUFFIX_ONLY, and 2 as
2065 We do *not* use DS_LIBRARY_ID or
2066 DS_LIB_PRINT_SUFFIX_ONLY by name, so that
2067 we don't require that Ethereal be built
2068 with versions of UCD SNMP that include
2069 that value; instead, we use their values
2070 in UCD SNMP 4.1.1, which are 0 and 4,
2072 (*ds_set_int_p)(0, 4, 2);
2075 dlclose(libsnmp_handle);
2078 snmp_set_suffix_only(2);
2080 #endif /* HAVE_UCD_SNMP_SNMP_H */
2081 #endif /* defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H) */
2082 proto_snmp = proto_register_protocol("Simple Network Management Protocol",
2084 proto_smux = proto_register_protocol("SNMP Multiplex Protocol",
2086 proto_register_field_array(proto_snmp, hf, array_length(hf));
2087 proto_register_subtree_array(ett, array_length(ett));
2091 proto_reg_handoff_snmp(void)
2093 old_dissector_add("udp.port", UDP_PORT_SNMP, dissect_snmp);
2094 old_dissector_add("udp.port", UDP_PORT_SNMP_TRAP, dissect_snmp);
2095 old_dissector_add("tcp.port", TCP_PORT_SMUX, dissect_smux);
2096 old_dissector_add("ethertype", ETHERTYPE_SNMP, dissect_snmp);
2097 old_dissector_add("ipx.socket", IPX_SOCKET_SNMP_AGENT, dissect_snmp);
2098 old_dissector_add("ipx.socket", IPX_SOCKET_SNMP_SINK, dissect_snmp);