2 * Routines for SNMP (simple network management protocol)
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.59 2001/01/30 07:16:28 guy Exp $
13 * Ethereal - Network traffic analyzer
14 * By Gerald Combs <gerald@zing.org>
15 * Copyright 1998 Didier Jorand
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 */
64 #include "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
124 # elif defined(HAVE_SNMP_SNMP_H)
128 # include <snmp/snmp.h>
131 * Some older versions of CMU SNMP may lack these values (e.g., the
132 * "libsnmp3.6" package for Debian, which is based on some old
133 * CMU SNMP, perhaps 1.0); for now, we assume they also lack
137 # define HAVE_SPRINT_VALUE
139 * Define values "sprint_value()" expects.
141 # define VALTYPE_INTEGER SMI_INTEGER
142 # define VALTYPE_COUNTER SMI_COUNTER32
143 # define VALTYPE_GAUGE SMI_GAUGE32
144 # define VALTYPE_TIMETICKS SMI_TIMETICKS
145 # define VALTYPE_STRING SMI_STRING
146 # define VALTYPE_IPADDR SMI_IPADDRESS
147 # define VALTYPE_OPAQUE SMI_OPAQUE
148 # define VALTYPE_NSAP SMI_STRING
149 # define VALTYPE_OBJECTID SMI_OBJID
150 # define VALTYPE_BITSTR ASN_BIT_STR
151 # define VALTYPE_COUNTER64 SMI_COUNTER64
154 * Now undo all the definitions they "helpfully" gave us, so we don't get
155 * complaints about redefining them.
157 * Why, oh why, is there no library that provides code to
161 * 2) translate object IDs into names;
163 * 3) let you find out, for a given object ID, what the type, enum
164 * values, display hint, etc. are;
166 * in a *simple* fashion, without assuming that your code is part of an
167 * SNMP agent or client that wants a pile of definitions of PDU types,
168 * etc.? Is it just that 99 44/100% of the code that uses an SNMP library
169 * *is* part of an agent or client, and really *does* need that stuff,
170 * and *doesn't* need the interfaces we want?
172 # undef SNMP_ERR_NOERROR
173 # undef SNMP_ERR_TOOBIG
174 # undef SNMP_ERR_NOSUCHNAME
175 # undef SNMP_ERR_BADVALUE
176 # undef SNMP_ERR_READONLY
177 # undef SNMP_ERR_NOACCESS
178 # undef SNMP_ERR_WRONGTYPE
179 # undef SNMP_ERR_WRONGLENGTH
180 # undef SNMP_ERR_WRONGENCODING
181 # undef SNMP_ERR_WRONGVALUE
182 # undef SNMP_ERR_NOCREATION
183 # undef SNMP_ERR_INCONSISTENTVALUE
184 # undef SNMP_ERR_RESOURCEUNAVAILABLE
185 # undef SNMP_ERR_COMMITFAILED
186 # undef SNMP_ERR_UNDOFAILED
187 # undef SNMP_ERR_AUTHORIZATIONERROR
188 # undef SNMP_ERR_NOTWRITABLE
189 # undef SNMP_ERR_INCONSISTENTNAME
190 # undef SNMP_TRAP_COLDSTART
191 # undef SNMP_TRAP_WARMSTART
192 # undef SNMP_TRAP_LINKDOWN
193 # undef SNMP_TRAP_LINKUP
194 # undef SNMP_TRAP_EGPNEIGHBORLOSS
195 # undef SNMP_TRAP_ENTERPRISESPECIFIC
201 #include "packet-snmp.h"
203 /* Null string of type "guchar[]". */
204 static const guchar nullstring[] = "";
206 /* Take a pointer that may be null and return a pointer that's not null
207 by turning null pointers into pointers to the above null string. */
208 #define SAFE_STRING(s) (((s) != NULL) ? (s) : nullstring)
210 static int proto_snmp = -1;
211 static int proto_smux = -1;
213 static gint ett_snmp = -1;
214 static gint ett_smux = -1;
215 static gint ett_parameters = -1;
216 static gint ett_parameters_qos = -1;
217 static gint ett_global = -1;
218 static gint ett_flags = -1;
219 static gint ett_secur = -1;
221 static int hf_snmpv3_flags = -1;
222 static int hf_snmpv3_flags_auth = -1;
223 static int hf_snmpv3_flags_crypt = -1;
224 static int hf_snmpv3_flags_report = -1;
227 #define TH_CRYPT 0x02
228 #define TH_REPORT 0x04
230 static const true_false_string flags_set_truth = {
235 #define UDP_PORT_SNMP 161
236 #define UDP_PORT_SNMP_TRAP 162
237 #define TCP_PORT_SMUX 199
239 /* Protocol version numbers */
240 #define SNMP_VERSION_1 0
241 #define SNMP_VERSION_2c 1
242 #define SNMP_VERSION_2u 2
243 #define SNMP_VERSION_3 3
245 static const value_string versions[] = {
246 { SNMP_VERSION_1, "1" },
247 { SNMP_VERSION_2c, "2C" },
248 { SNMP_VERSION_2u, "2U" },
249 { SNMP_VERSION_3, "3" },
254 #define SNMP_MSG_GET 0
255 #define SNMP_MSG_GETNEXT 1
256 #define SNMP_MSG_RESPONSE 2
257 #define SNMP_MSG_SET 3
258 #define SNMP_MSG_TRAP 4
260 #define SNMP_MSG_GETBULK 5
261 #define SNMP_MSG_INFORM 6
262 #define SNMP_MSG_TRAP2 7
263 #define SNMP_MSG_REPORT 8
265 static const value_string pdu_types[] = {
266 { SNMP_MSG_GET, "GET" },
267 { SNMP_MSG_GETNEXT, "GET-NEXT" },
268 { SNMP_MSG_SET, "SET" },
269 { SNMP_MSG_RESPONSE, "RESPONSE" },
270 { SNMP_MSG_TRAP, "TRAP-V1" },
271 { SNMP_MSG_GETBULK, "GETBULK" },
272 { SNMP_MSG_INFORM, "INFORM" },
273 { SNMP_MSG_TRAP2, "TRAP-V2" },
274 { SNMP_MSG_REPORT, "REPORT" },
279 #define SMUX_MSG_OPEN 0
280 #define SMUX_MSG_CLOSE 1
281 #define SMUX_MSG_RREQ 2
282 #define SMUX_MSG_RRSP 3
283 #define SMUX_MSG_SOUT 4
285 static const value_string smux_types[] = {
286 { SMUX_MSG_OPEN, "Open" },
287 { SMUX_MSG_CLOSE, "Close" },
288 { SMUX_MSG_RREQ, "Registration Request" },
289 { SMUX_MSG_RRSP, "Registration Response" },
290 { SMUX_MSG_SOUT, "Commit Or Rollback" },
294 /* SMUX Closing causes */
295 #define SMUX_CLOSE_DOWN 0
296 #define SMUX_CLOSE_VERSION 1
297 #define SMUX_CLOSE_PACKET 2
298 #define SMUX_CLOSE_PROTOCOL 3
299 #define SMUX_CLOSE_INTERNAL 4
300 #define SMUX_CLOSE_NOAUTH 5
302 static const value_string smux_close[] = {
303 { SMUX_CLOSE_DOWN, "Going down" },
304 { SMUX_CLOSE_VERSION, "Unsupported Version" },
305 { SMUX_CLOSE_PACKET, "Packet Format Error" },
306 { SMUX_CLOSE_PROTOCOL, "Protocol Error" },
307 { SMUX_CLOSE_INTERNAL, "Internal Error" },
308 { SMUX_CLOSE_NOAUTH, "Unauthorized" },
312 /* SMUX Request codes */
313 #define SMUX_RREQ_DELETE 0
314 #define SMUX_RREQ_READONLY 1
315 #define SMUX_RREQ_READWRITE 2
317 static const value_string smux_rreq[] = {
318 { SMUX_RREQ_DELETE, "Delete" },
319 { SMUX_RREQ_READONLY, "Read Only" },
320 { SMUX_RREQ_READWRITE, "Read Write" },
324 static const value_string smux_prio[] = {
329 /* SMUX SOut codes */
330 #define SMUX_SOUT_COMMIT 0
331 #define SMUX_SOUT_ROLLBACK 1
333 static const value_string smux_sout[] = {
334 { SMUX_SOUT_COMMIT, "Commit" },
335 { SMUX_SOUT_ROLLBACK, "Rollback" },
339 /* Error status values */
340 #define SNMP_ERR_NOERROR 0
341 #define SNMP_ERR_TOOBIG 1
342 #define SNMP_ERR_NOSUCHNAME 2
343 #define SNMP_ERR_BADVALUE 3
344 #define SNMP_ERR_READONLY 4
345 #define SNMP_ERR_GENERROR 5
347 #define SNMP_ERR_NOACCESS 6
348 #define SNMP_ERR_WRONGTYPE 7
349 #define SNMP_ERR_WRONGLENGTH 8
350 #define SNMP_ERR_WRONGENCODING 9
351 #define SNMP_ERR_WRONGVALUE 10
352 #define SNMP_ERR_NOCREATION 11
353 #define SNMP_ERR_INCONSISTENTVALUE 12
354 #define SNMP_ERR_RESOURCEUNAVAILABLE 13
355 #define SNMP_ERR_COMMITFAILED 14
356 #define SNMP_ERR_UNDOFAILED 15
357 #define SNMP_ERR_AUTHORIZATIONERROR 16
358 #define SNMP_ERR_NOTWRITABLE 17
359 #define SNMP_ERR_INCONSISTENTNAME 18
361 static const value_string error_statuses[] = {
362 { SNMP_ERR_NOERROR, "NO ERROR" },
363 { SNMP_ERR_TOOBIG, "TOOBIG" },
364 { SNMP_ERR_NOSUCHNAME, "NO SUCH NAME" },
365 { SNMP_ERR_BADVALUE, "BAD VALUE" },
366 { SNMP_ERR_READONLY, "READ ONLY" },
367 { SNMP_ERR_GENERROR, "GENERIC ERROR" },
368 { SNMP_ERR_NOACCESS, "NO ACCESS" },
369 { SNMP_ERR_WRONGTYPE, "WRONG TYPE" },
370 { SNMP_ERR_WRONGLENGTH, "WRONG LENGTH" },
371 { SNMP_ERR_WRONGENCODING, "WRONG ENCODING" },
372 { SNMP_ERR_WRONGVALUE, "WRONG VALUE" },
373 { SNMP_ERR_NOCREATION, "NO CREATION" },
374 { SNMP_ERR_INCONSISTENTVALUE, "INCONSISTENT VALUE" },
375 { SNMP_ERR_RESOURCEUNAVAILABLE, "RESOURCE UNAVAILABLE" },
376 { SNMP_ERR_COMMITFAILED, "COMMIT FAILED" },
377 { SNMP_ERR_UNDOFAILED, "UNDO FAILED" },
378 { SNMP_ERR_AUTHORIZATIONERROR, "AUTHORIZATION ERROR" },
379 { SNMP_ERR_NOTWRITABLE, "NOT WRITABLE" },
380 { SNMP_ERR_INCONSISTENTNAME, "INCONSISTENT NAME" },
384 /* General SNMP V1 Traps */
386 #define SNMP_TRAP_COLDSTART 0
387 #define SNMP_TRAP_WARMSTART 1
388 #define SNMP_TRAP_LINKDOWN 2
389 #define SNMP_TRAP_LINKUP 3
390 #define SNMP_TRAP_AUTHFAIL 4
391 #define SNMP_TRAP_EGPNEIGHBORLOSS 5
392 #define SNMP_TRAP_ENTERPRISESPECIFIC 6
394 static const value_string trap_types[] = {
395 { SNMP_TRAP_COLDSTART, "COLD START" },
396 { SNMP_TRAP_WARMSTART, "WARM START" },
397 { SNMP_TRAP_LINKDOWN, "LINK DOWN" },
398 { SNMP_TRAP_LINKUP, "LINK UP" },
399 { SNMP_TRAP_AUTHFAIL, "AUTHENTICATION FAILED" },
400 { SNMP_TRAP_EGPNEIGHBORLOSS, "EGP NEIGHBORLOSS" },
401 { SNMP_TRAP_ENTERPRISESPECIFIC, "ENTERPRISE SPECIFIC" },
405 /* Security Models */
407 #define SNMP_SEC_ANY 0
408 #define SNMP_SEC_V1 1
409 #define SNMP_SEC_V2C 2
410 #define SNMP_SEC_USM 3
412 static const value_string sec_models[] = {
413 { SNMP_SEC_ANY, "Any" },
414 { SNMP_SEC_V1, "V1" },
415 { SNMP_SEC_V2C, "V2C" },
416 { SNMP_SEC_USM, "USM" },
422 #define SNMP_IPA 0 /* IP Address */
423 #define SNMP_CNT 1 /* Counter (Counter32) */
424 #define SNMP_GGE 2 /* Gauge (Gauge32) */
425 #define SNMP_TIT 3 /* TimeTicks */
426 #define SNMP_OPQ 4 /* Opaque */
427 #define SNMP_NSP 5 /* NsapAddress */
428 #define SNMP_C64 6 /* Counter64 */
429 #define SNMP_U32 7 /* Uinteger32 */
438 #define SNMP_INTEGER 1 /* l */
439 #define SNMP_OCTETSTR 2 /* c */
440 #define SNMP_DISPLAYSTR 2 /* c */
441 #define SNMP_OBJECTID 3 /* ul */
442 #define SNMP_IPADDR 4 /* uc */
443 #define SNMP_COUNTER 5 /* ul */
444 #define SNMP_GAUGE 6 /* ul */
445 #define SNMP_TIMETICKS 7 /* ul */
446 #define SNMP_OPAQUE 8 /* c */
448 /* additional SNMPv2 Types */
450 #define SNMP_UINTEGER 5 /* ul */
451 #define SNMP_BITSTR 9 /* uc */
452 #define SNMP_NSAP 10 /* uc */
453 #define SNMP_COUNTER64 11 /* ul */
454 #define SNMP_NOSUCHOBJECT 12
455 #define SNMP_NOSUCHINSTANCE 13
456 #define SNMP_ENDOFMIBVIEW 14
458 typedef struct _SNMP_CNV SNMP_CNV;
468 static SNMP_CNV SnmpCnv [] =
470 {ASN1_UNI, ASN1_NUL, SNMP_NULL, "NULL"},
471 {ASN1_UNI, ASN1_INT, SNMP_INTEGER, "INTEGER"},
472 {ASN1_UNI, ASN1_OTS, SNMP_OCTETSTR, "OCTET STRING"},
473 {ASN1_UNI, ASN1_OJI, SNMP_OBJECTID, "OBJECTID"},
474 {ASN1_APL, SNMP_IPA, SNMP_IPADDR, "IPADDR"},
475 {ASN1_APL, SNMP_CNT, SNMP_COUNTER, "COUNTER"}, /* Counter32 */
476 {ASN1_APL, SNMP_GGE, SNMP_GAUGE, "GAUGE"}, /* Gauge32 == Unsigned32 */
477 {ASN1_APL, SNMP_TIT, SNMP_TIMETICKS, "TIMETICKS"},
478 {ASN1_APL, SNMP_OPQ, SNMP_OPAQUE, "OPAQUE"},
480 /* SNMPv2 data types and errors */
482 {ASN1_UNI, ASN1_BTS, SNMP_BITSTR, "BITSTR"},
483 {ASN1_APL, SNMP_C64, SNMP_COUNTER64, "COUNTER64"},
484 {ASN1_CTX, SERR_NSO, SNMP_NOSUCHOBJECT, "NOSUCHOBJECT"},
485 {ASN1_CTX, SERR_NSI, SNMP_NOSUCHINSTANCE, "NOSUCHINSTANCE"},
486 {ASN1_CTX, SERR_EOM, SNMP_ENDOFMIBVIEW, "ENDOFMIBVIEW"},
491 * NAME: g_snmp_tag_cls2syntax
492 * SYNOPSIS: gboolean g_snmp_tag_cls2syntax
498 * DESCRIPTION: Converts ASN1 tag and class to Syntax tag and name.
499 * See SnmpCnv for conversion.
500 * RETURNS: name on success, NULL on failure
504 snmp_tag_cls2syntax ( guint tag, guint cls, gushort *syntax)
509 while (cnv->syntax != -1)
511 if (cnv->tag == tag && cnv->class == cls)
513 *syntax = cnv->syntax;
522 dissect_snmp_parse_error(const u_char *pd, int offset, frame_data *fd,
523 proto_tree *tree, const char *field_name, int ret)
527 if (check_col(fd, COL_INFO)) {
531 errstr = "Ran out of data";
534 case ASN1_ERR_EOC_MISMATCH:
535 errstr = "EOC mismatch";
538 case ASN1_ERR_WRONG_TYPE:
539 errstr = "Wrong type for that item";
542 case ASN1_ERR_LENGTH_NOT_DEFINITE:
543 errstr = "Length was indefinite";
546 case ASN1_ERR_LENGTH_MISMATCH:
547 errstr = "Length mismatch";
550 case ASN1_ERR_WRONG_LENGTH_FOR_TYPE:
551 errstr = "Wrong length for that item's type";
555 errstr = "Unknown error";
558 col_add_fstr(fd, COL_INFO,
559 "ERROR: Couldn't parse %s: %s", field_name, errstr);
562 old_dissect_data(pd, offset, fd, tree);
566 dissect_snmp_error(const u_char *pd, int offset, frame_data *fd,
567 proto_tree *tree, const char *message)
569 if (check_col(fd, COL_INFO))
570 col_add_str(fd, COL_INFO, message);
572 old_dissect_data(pd, offset, fd, tree);
576 format_oid(subid_t *oid, guint oid_length)
583 result_len = oid_length * 22;
584 result = g_malloc(result_len + 1);
586 len = sprintf(buf, "%lu", (unsigned long)oid[0]);
588 for (i = 1; i < oid_length;i++) {
589 len = sprintf(buf, ".%lu", (unsigned long)oid[i]);
595 #ifdef HAVE_SPRINT_VALUE
597 format_var(struct variable_list *variable, subid_t *variable_oid,
598 guint variable_oid_length, gushort vb_type, guint vb_length)
608 /* We don't know how long this will be, but let's guess it
609 fits within 128 characters; that should be enough for an
610 integral value plus some sort of type indication. */
620 /* We don't know how long this will be, but let's guess it
621 fits within 128 characters plus 4 characters per octet. */
622 buf = g_malloc(128 + 4*vb_length);
626 /* We don't know how long this will be, but let's guess it
627 fits within 128 characters plus 32 characters per subid
628 (10 digits plus period, or a subid name). */
629 buf = g_malloc(1024 + 32*vb_length);
633 /* Should not happen. */
634 g_assert_not_reached();
639 variable->next_variable = NULL;
640 variable->name = variable_oid;
641 variable->name_length = variable_oid_length;
645 variable->type = VALTYPE_INTEGER;
649 variable->type = VALTYPE_COUNTER;
653 variable->type = VALTYPE_GAUGE;
657 variable->type = VALTYPE_TIMETICKS;
661 variable->type = VALTYPE_STRING;
665 variable->type = VALTYPE_IPADDR;
669 variable->type = VALTYPE_OPAQUE;
673 variable->type = VALTYPE_NSAP;
677 variable->type = VALTYPE_OBJECTID;
678 vb_length *= sizeof (subid_t); /* XXX - necessary? */
682 variable->type = VALTYPE_BITSTR;
686 variable->type = VALTYPE_COUNTER64;
689 variable->val_len = vb_length;
691 sprint_value(buf, variable_oid, variable_oid_length, variable);
697 snmp_variable_decode(proto_tree *snmp_tree, subid_t *variable_oid,
698 guint variable_oid_length, ASN1_SCK *asn1, int offset, guint *lengthp,
710 gint32 vb_integer_value;
711 guint32 vb_uinteger_value;
713 guint8 *vb_octet_string;
718 gchar *vb_display_string;
720 #ifdef HAVE_SPRINT_VALUE
721 struct variable_list variable;
722 #if defined(HAVE_UCD_SNMP_SNMP_H)
725 #endif /* HAVE_SPRINT_VALUE */
730 /* parse the type of the object */
731 start = asn1->pointer;
732 ret = asn1_header_decode (asn1, &cls, &con, &tag, &def, &vb_length);
733 if (ret != ASN1_ERR_NOERROR)
736 return ASN1_ERR_LENGTH_NOT_DEFINITE;
738 /* Convert the class, constructed flag, and tag to a type. */
739 vb_type_name = snmp_tag_cls2syntax(tag, cls, &vb_type);
740 if (vb_type_name == NULL) {
743 * Dissect the value as an opaque string of octets.
745 vb_type_name = "unsupported type";
746 vb_type = SNMP_OPAQUE;
749 /* parse the value */
753 ret = asn1_int32_value_decode(asn1, vb_length,
755 if (ret != ASN1_ERR_NOERROR)
757 length = asn1->pointer - start;
759 #ifdef HAVE_SPRINT_VALUE
761 #if defined(HAVE_UCD_SNMP_SNMP_H)
762 value = vb_integer_value;
763 variable.val.integer = &value;
764 #elif defined(HAVE_SNMP_SNMP_H)
765 variable.val.integer = &vb_integer_value;
767 vb_display_string = format_var(&variable,
768 variable_oid, variable_oid_length, vb_type,
770 proto_tree_add_text(snmp_tree, NullTVB, offset,
772 "Value: %s", vb_display_string);
773 g_free(vb_display_string);
774 break; /* we added formatted version to the tree */
776 #endif /* HAVE_SPRINT_VALUE */
777 proto_tree_add_text(snmp_tree, NullTVB, offset, length,
778 "Value: %s: %d (%#x)", vb_type_name,
779 vb_integer_value, vb_integer_value);
786 ret = asn1_uint32_value_decode(asn1, vb_length,
788 if (ret != ASN1_ERR_NOERROR)
790 length = asn1->pointer - start;
792 #ifdef HAVE_SPRINT_VALUE
794 #if defined(HAVE_UCD_SNMP_SNMP_H)
795 value = vb_uinteger_value;
796 variable.val.integer = &value;
797 #elif defined(HAVE_SNMP_SNMP_H)
798 variable.val.integer = &vb_uinteger_value;
800 vb_display_string = format_var(&variable,
801 variable_oid, variable_oid_length, vb_type,
803 proto_tree_add_text(snmp_tree, NullTVB, offset,
805 "Value: %s", vb_display_string);
806 g_free(vb_display_string);
807 break; /* we added formatted version to the tree */
809 #endif /* HAVE_SPRINT_VALUE */
810 proto_tree_add_text(snmp_tree, NullTVB, offset, length,
811 "Value: %s: %u (%#x)", vb_type_name,
812 vb_uinteger_value, vb_uinteger_value);
822 ret = asn1_string_value_decode (asn1, vb_length,
824 if (ret != ASN1_ERR_NOERROR)
826 length = asn1->pointer - start;
828 #ifdef HAVE_SPRINT_VALUE
830 variable.val.string = vb_octet_string;
831 vb_display_string = format_var(&variable,
832 variable_oid, variable_oid_length, vb_type,
834 proto_tree_add_text(snmp_tree, NullTVB, offset,
836 "Value: %s", vb_display_string);
837 g_free(vb_display_string);
838 break; /* we added formatted version to the tree */
840 #endif /* HAVE_SPRINT_VALUE */
842 * If some characters are not printable, display
843 * the string as bytes.
845 for (i = 0; i < vb_length; i++) {
846 if (!(isprint(vb_octet_string[i])
847 || isspace(vb_octet_string[i])))
852 * We stopped, due to a non-printable
853 * character, before we got to the end
856 vb_display_string = g_malloc(4*vb_length);
857 buf = &vb_display_string[0];
858 len = sprintf(buf, "%03u", vb_octet_string[0]);
860 for (i = 1; i < vb_length; i++) {
861 len = sprintf(buf, ".%03u",
865 proto_tree_add_text(snmp_tree, NullTVB, offset, length,
866 "Value: %s: %s", vb_type_name,
868 g_free(vb_display_string);
870 proto_tree_add_text(snmp_tree, NullTVB, offset, length,
871 "Value: %s: %.*s", vb_type_name,
872 (int)vb_length, vb_octet_string);
875 g_free(vb_octet_string);
879 ret = asn1_null_decode (asn1, vb_length);
880 if (ret != ASN1_ERR_NOERROR)
882 length = asn1->pointer - start;
884 proto_tree_add_text(snmp_tree, NullTVB, offset, length,
885 "Value: %s", vb_type_name);
890 ret = asn1_oid_value_decode (asn1, vb_length, &vb_oid,
892 if (ret != ASN1_ERR_NOERROR)
894 length = asn1->pointer - start;
896 #ifdef HAVE_SPRINT_VALUE
898 variable.val.objid = vb_oid;
899 vb_display_string = format_var(&variable,
900 variable_oid, variable_oid_length, vb_type,
902 proto_tree_add_text(snmp_tree, NullTVB, offset,
904 "Value: %s", vb_display_string);
905 break; /* we added formatted version to the tree */
907 #endif /* HAVE_SPRINT_VALUE */
908 vb_display_string = format_oid(vb_oid, vb_oid_length);
909 proto_tree_add_text(snmp_tree, NullTVB, offset, length,
910 "Value: %s: %s", vb_type_name, vb_display_string);
911 g_free(vb_display_string);
916 case SNMP_NOSUCHOBJECT:
917 length = asn1->pointer - start;
919 proto_tree_add_text(snmp_tree, NullTVB, offset, length,
920 "Value: %s: no such object", vb_type_name);
924 case SNMP_NOSUCHINSTANCE:
925 length = asn1->pointer - start;
927 proto_tree_add_text(snmp_tree, NullTVB, offset, length,
928 "Value: %s: no such instance", vb_type_name);
932 case SNMP_ENDOFMIBVIEW:
933 length = asn1->pointer - start;
935 proto_tree_add_text(snmp_tree, NullTVB, offset, length,
936 "Value: %s: end of mib view", vb_type_name);
941 g_assert_not_reached();
942 return ASN1_ERR_WRONG_TYPE;
945 return ASN1_ERR_NOERROR;
949 dissect_common_pdu(const u_char *pd, int offset, frame_data *fd,
950 proto_tree *tree, ASN1_SCK asn1, guint pdu_type, const guchar *start)
954 guint sequence_length;
958 guint32 error_status;
962 char *pdu_type_string;
965 guint enterprise_length;
967 guint8 *agent_address;
968 guint agent_address_length;
972 guint32 specific_type;
975 guint timestamp_length;
979 guint variable_bindings_length;
982 guint variable_length;
983 subid_t *variable_oid;
984 guint variable_oid_length;
985 #if defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H)
986 gchar vb_oid_string[MAX_STRING_LEN]; /* TBC */
993 pdu_type_string = val_to_str(pdu_type, pdu_types,
994 "Unknown PDU type %#x");
995 if (check_col(fd, COL_INFO))
996 col_add_str(fd, COL_INFO, pdu_type_string);
997 length = asn1.pointer - start;
999 proto_tree_add_text(tree, NullTVB, offset, length,
1000 "PDU type: %s", pdu_type_string);
1004 /* get the fields in the PDU preceeding the variable-bindings sequence */
1008 case SNMP_MSG_GETNEXT:
1009 case SNMP_MSG_RESPONSE:
1011 case SNMP_MSG_GETBULK:
1012 case SNMP_MSG_INFORM:
1013 case SNMP_MSG_TRAP2:
1014 case SNMP_MSG_REPORT:
1016 ret = asn1_uint32_decode (&asn1, &request_id, &length);
1017 if (ret != ASN1_ERR_NOERROR) {
1018 dissect_snmp_parse_error(pd, offset, fd, tree,
1023 proto_tree_add_text(tree, NullTVB, offset, length,
1024 "Request Id: %#x", request_id);
1028 /* error status, or getbulk non-repeaters */
1029 ret = asn1_uint32_decode (&asn1, &error_status, &length);
1030 if (ret != ASN1_ERR_NOERROR) {
1031 dissect_snmp_parse_error(pd, offset, fd, tree,
1032 (pdu_type == SNMP_MSG_GETBULK) ? "non-repeaters"
1038 if (pdu_type == SNMP_MSG_GETBULK) {
1039 proto_tree_add_text(tree, NullTVB, offset,
1040 length, "Non-repeaters: %u", error_status);
1042 proto_tree_add_text(tree, NullTVB, offset,
1043 length, "Error Status: %s",
1044 val_to_str(error_status, error_statuses,
1050 /* error index, or getbulk max-repetitions */
1051 ret = asn1_uint32_decode (&asn1, &error_index, &length);
1052 if (ret != ASN1_ERR_NOERROR) {
1053 dissect_snmp_parse_error(pd, offset, fd, tree,
1054 (pdu_type == SNMP_MSG_GETBULK) ? "max repetitions"
1060 if (pdu_type == SNMP_MSG_GETBULK) {
1061 proto_tree_add_text(tree, NullTVB, offset,
1062 length, "Max repetitions: %u", error_index);
1064 proto_tree_add_text(tree, NullTVB, offset,
1065 length, "Error Index: %u", error_index);
1073 ret = asn1_oid_decode (&asn1, &enterprise, &enterprise_length,
1075 if (ret != ASN1_ERR_NOERROR) {
1076 dissect_snmp_parse_error(pd, offset, fd, tree,
1077 "enterprise OID", ret);
1081 oid_string = format_oid(enterprise, enterprise_length);
1082 proto_tree_add_text(tree, NullTVB, offset, length,
1083 "Enterprise: %s", oid_string);
1090 start = asn1.pointer;
1091 ret = asn1_header_decode (&asn1, &cls, &con, &tag,
1092 &def, &agent_address_length);
1093 if (ret != ASN1_ERR_NOERROR) {
1094 dissect_snmp_parse_error(pd, offset, fd, tree,
1095 "agent address", ret);
1098 if (!((cls == ASN1_APL && con == ASN1_PRI && tag == SNMP_IPA) ||
1099 (cls == ASN1_UNI && con == ASN1_PRI && tag == ASN1_OTS))) {
1100 /* GXSNMP 0.0.15 says the latter is "needed for
1102 dissect_snmp_parse_error(pd, offset, fd, tree,
1103 "agent_address", ASN1_ERR_WRONG_TYPE);
1106 if (agent_address_length != 4) {
1107 dissect_snmp_parse_error(pd, offset, fd, tree,
1108 "agent_address", ASN1_ERR_WRONG_LENGTH_FOR_TYPE);
1111 ret = asn1_string_value_decode (&asn1,
1112 agent_address_length, &agent_address);
1113 if (ret != ASN1_ERR_NOERROR) {
1114 dissect_snmp_parse_error(pd, offset, fd, tree,
1115 "agent address", ret);
1118 length = asn1.pointer - start;
1120 proto_tree_add_text(tree, NullTVB, offset, length,
1121 "Agent address: %s", ip_to_str(agent_address));
1123 g_free(agent_address);
1126 /* generic trap type */
1127 ret = asn1_uint32_decode (&asn1, &trap_type, &length);
1128 if (ret != ASN1_ERR_NOERROR) {
1129 dissect_snmp_parse_error(pd, offset, fd, tree,
1130 "generic trap type", ret);
1134 proto_tree_add_text(tree, NullTVB, offset, length,
1136 val_to_str(trap_type, trap_types, "Unknown (%u)"));
1140 /* specific trap type */
1141 ret = asn1_uint32_decode (&asn1, &specific_type, &length);
1142 if (ret != ASN1_ERR_NOERROR) {
1143 dissect_snmp_parse_error(pd, offset, fd, tree,
1144 "specific trap type", ret);
1148 proto_tree_add_text(tree, NullTVB, offset, length,
1149 "Specific trap type: %u (%#x)",
1150 specific_type, specific_type);
1155 start = asn1.pointer;
1156 ret = asn1_header_decode (&asn1, &cls, &con, &tag,
1157 &def, ×tamp_length);
1158 if (ret != ASN1_ERR_NOERROR) {
1159 dissect_snmp_parse_error(pd, offset, fd, tree,
1163 if (!((cls == ASN1_APL && con == ASN1_PRI && tag == SNMP_TIT) ||
1164 (cls == ASN1_UNI && con == ASN1_PRI && tag == ASN1_INT))) {
1165 dissect_snmp_parse_error(pd, offset, fd, tree,
1166 "timestamp", ASN1_ERR_WRONG_TYPE);
1169 ret = asn1_uint32_value_decode(&asn1, timestamp_length,
1171 if (ret != ASN1_ERR_NOERROR) {
1172 dissect_snmp_parse_error(pd, offset, fd, tree,
1176 length = asn1.pointer - start;
1178 proto_tree_add_text(tree, NullTVB, offset, length,
1179 "Timestamp: %u", timestamp);
1185 /* variable bindings */
1186 /* get header for variable-bindings sequence */
1187 ret = asn1_sequence_decode(&asn1, &variable_bindings_length, &length);
1188 if (ret != ASN1_ERR_NOERROR) {
1189 dissect_snmp_parse_error(pd, offset, fd, tree,
1190 "variable bindings header", ret);
1195 /* loop on variable bindings */
1197 while (variable_bindings_length > 0) {
1199 sequence_length = 0;
1202 ret = asn1_sequence_decode(&asn1, &variable_length, &length);
1203 if (ret != ASN1_ERR_NOERROR) {
1204 dissect_snmp_parse_error(pd, offset, fd, tree,
1205 "variable binding header", ret);
1208 sequence_length += length;
1210 /* parse object identifier */
1211 ret = asn1_oid_decode (&asn1, &variable_oid,
1212 &variable_oid_length, &length);
1213 if (ret != ASN1_ERR_NOERROR) {
1214 dissect_snmp_parse_error(pd, offset, fd, tree,
1215 "variable binding OID", ret);
1218 sequence_length += length;
1222 oid_string = format_oid(variable_oid,
1223 variable_oid_length);
1225 #if defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H)
1226 sprint_objid(vb_oid_string, variable_oid,
1227 variable_oid_length);
1228 proto_tree_add_text(tree, NullTVB, offset, sequence_length,
1229 "Object identifier %d: %s (%s)", vb_index,
1230 oid_string, vb_oid_string);
1231 #ifdef HAVE_SNMP_SNMP_H
1233 * CMU SNMP has a bug wherein "sprint_value()"
1234 * calls "get_symbol()", passing it the
1235 * OID supplied, to get an information about the
1236 * variable, and blithely assumes that it will
1237 * never get a null pointer back and dereferences
1238 * the resulting pointer.
1240 * Not true. If there's nothing in the MIB
1241 * about *any* of the components of the OID,
1242 * it'll return a null pointer.
1244 * So we have to check for that, and pass
1245 * down to "snmp_variable_decode" a flag
1246 * saying "don't pass this to 'sprint_value()'.
1248 * We check for that by looking for a decoded
1249 * OID string beginning with "." followed by a
1250 * digit, meaning it couldn't even find any
1251 * symbolic representation for the very
1252 * beginning of the OID string.
1254 if (vb_oid_string[0] == '.' &&
1255 isdigit((guchar)vb_oid_string[1]))
1257 #endif /* HAVE_SNMP_SNMP_H */
1258 #else /* defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H) */
1259 proto_tree_add_text(tree, NullTVB, offset, sequence_length,
1260 "Object identifier %d: %s", vb_index,
1262 #endif /* defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H) */
1265 offset += sequence_length;
1266 variable_bindings_length -= sequence_length;
1268 /* Parse the variable's value */
1269 ret = snmp_variable_decode(tree, variable_oid,
1270 variable_oid_length, &asn1, offset, &length,
1272 if (ret != ASN1_ERR_NOERROR) {
1273 dissect_snmp_parse_error(pd, offset, fd, tree,
1278 variable_bindings_length -= length;
1282 static const value_string qos_vals[] = {
1283 { 0x0, "No authentication or privacy" },
1284 { 0x1, "Authentication, no privacy" },
1285 { 0x2, "Authentication and privacy" },
1286 { 0x3, "Authentication and privacy" },
1291 dissect_snmp2u_parameters(proto_tree *tree, int offset, int length,
1292 guchar *parameters, int parameters_length)
1295 proto_tree *parameters_tree;
1296 proto_tree *qos_tree;
1301 item = proto_tree_add_text(tree, NullTVB, offset, length,
1303 parameters_tree = proto_item_add_subtree(item, ett_parameters);
1304 offset += length - parameters_length;
1306 if (parameters_length < 1)
1308 model = *parameters;
1309 proto_tree_add_text(parameters_tree, NullTVB, offset, 1,
1310 "model: %u", model);
1313 parameters_length -= 1;
1315 /* Unknown model. */
1316 proto_tree_add_text(parameters_tree, NullTVB, offset,
1317 parameters_length, "parameters: %s",
1318 bytes_to_str(parameters, parameters_length));
1322 if (parameters_length < 1)
1325 item = proto_tree_add_text(parameters_tree, NullTVB, offset, 1,
1327 qos_tree = proto_item_add_subtree(item, ett_parameters_qos);
1328 proto_tree_add_text(qos_tree, NullTVB, offset, 1, "%s",
1329 decode_boolean_bitfield(qos, 0x04,
1330 8, "Generation of report PDU allowed",
1331 "Generation of report PDU not allowed"));
1332 proto_tree_add_text(qos_tree, NullTVB, offset, 1, "%s",
1333 decode_enumerated_bitfield(qos, 0x03,
1334 8, qos_vals, "%s"));
1337 parameters_length -= 1;
1339 if (parameters_length < 12)
1341 proto_tree_add_text(parameters_tree, NullTVB, offset, 12,
1342 "agentID: %s", bytes_to_str(parameters, 12));
1345 parameters_length -= 12;
1347 if (parameters_length < 4)
1349 proto_tree_add_text(parameters_tree, NullTVB, offset, 4,
1350 "agentBoots: %u", pntohl(parameters));
1353 parameters_length -= 4;
1355 if (parameters_length < 4)
1357 proto_tree_add_text(parameters_tree, NullTVB, offset, 4,
1358 "agentTime: %u", pntohl(parameters));
1361 parameters_length -= 4;
1363 if (parameters_length < 2)
1365 proto_tree_add_text(parameters_tree, NullTVB, offset, 2,
1366 "maxSize: %u", pntohs(parameters));
1369 parameters_length -= 2;
1371 if (parameters_length < 1)
1374 proto_tree_add_text(parameters_tree, NullTVB, offset, 1,
1375 "userLen: %u", len);
1378 parameters_length -= 1;
1380 if (parameters_length < len)
1382 proto_tree_add_text(parameters_tree, NullTVB, offset, len,
1383 "userName: %.*s", len, parameters);
1386 parameters_length -= len;
1388 if (parameters_length < 1)
1391 proto_tree_add_text(parameters_tree, NullTVB, offset, 1,
1392 "authLen: %u", len);
1395 parameters_length -= 1;
1397 if (parameters_length < len)
1399 proto_tree_add_text(parameters_tree, NullTVB, offset, len,
1400 "authDigest: %s", bytes_to_str(parameters, len));
1403 parameters_length -= len;
1405 if (parameters_length < 1)
1407 proto_tree_add_text(parameters_tree, NullTVB, offset, parameters_length,
1408 "contextSelector: %s", bytes_to_str(parameters, parameters_length));
1412 dissect_snmp_pdu(const u_char *pd, int offset, frame_data *fd,
1413 proto_tree *tree, char *proto_name, int proto, gint ett)
1416 const guchar *start;
1420 guint message_length;
1421 guint global_length;
1427 guint32 engineboots;
1440 int msgflags_length;
1441 int community_length;
1443 int cengineid_length;
1445 int cryptpdu_length;
1446 int aengineid_length;
1447 int username_length;
1454 proto_tree *snmp_tree = NULL;
1455 proto_tree *global_tree = NULL;
1456 proto_tree *flags_tree = NULL;
1457 proto_tree *secur_tree = NULL;
1458 proto_item *item = NULL;
1460 guint cls, con, tag;
1462 if (check_col(fd, COL_PROTOCOL))
1463 col_add_str(fd, COL_PROTOCOL, proto_name);
1466 item = proto_tree_add_item(tree, proto, NullTVB, offset,
1467 END_OF_FRAME, FALSE);
1468 snmp_tree = proto_item_add_subtree(item, ett);
1471 /* NOTE: we have to parse the message piece by piece, since the
1472 * capture length may be less than the message length: a 'global'
1473 * parsing is likely to fail.
1475 /* parse the SNMP header */
1476 asn1_open(&asn1, &pd[offset], END_OF_FRAME);
1477 ret = asn1_sequence_decode(&asn1, &message_length, &length);
1478 if (ret != ASN1_ERR_NOERROR) {
1479 dissect_snmp_parse_error(pd, offset, fd, tree,
1480 "message header", ret);
1485 ret = asn1_uint32_decode (&asn1, &version, &length);
1486 if (ret != ASN1_ERR_NOERROR) {
1487 dissect_snmp_parse_error(pd, offset, fd, tree, "version number",
1492 proto_tree_add_text(snmp_tree, NullTVB, offset, length,
1494 val_to_str(version, versions, "Unknown version %#x"));
1500 case SNMP_VERSION_1:
1501 case SNMP_VERSION_2c:
1502 ret = asn1_octet_string_decode (&asn1, &community,
1503 &community_length, &length);
1504 if (ret != ASN1_ERR_NOERROR) {
1505 dissect_snmp_parse_error(pd, offset, fd, tree,
1510 proto_tree_add_text(snmp_tree, NullTVB, offset, length,
1511 "Community: %.*s", community_length,
1512 SAFE_STRING(community));
1517 case SNMP_VERSION_2u:
1518 ret = asn1_octet_string_decode (&asn1, &community,
1519 &community_length, &length);
1521 dissect_snmp2u_parameters(snmp_tree, offset, length,
1522 community, community_length);
1527 case SNMP_VERSION_3:
1528 ret = asn1_sequence_decode(&asn1, &global_length, &length);
1529 if (ret != ASN1_ERR_NOERROR) {
1530 dissect_snmp_parse_error(pd, offset, fd, tree,
1531 "message global header", ret);
1535 item = proto_tree_add_text(snmp_tree, NullTVB, offset,
1536 global_length + length, "Message Global Header");
1537 global_tree = proto_item_add_subtree(item, ett_global);
1538 proto_tree_add_text(global_tree, NullTVB, offset,
1540 "Message Global Header Length: %d", global_length);
1543 ret = asn1_uint32_decode (&asn1, &msgid, &length);
1544 if (ret != ASN1_ERR_NOERROR) {
1545 dissect_snmp_parse_error(pd, offset, fd, tree,
1550 proto_tree_add_text(global_tree, NullTVB, offset,
1551 length, "Message ID: %d", msgid);
1554 ret = asn1_uint32_decode (&asn1, &msgmax, &length);
1555 if (ret != ASN1_ERR_NOERROR) {
1556 dissect_snmp_parse_error(pd, offset, fd, tree,
1557 "message max size", ret);
1561 proto_tree_add_text(global_tree, NullTVB, offset,
1562 length, "Message Max Size: %d", msgmax);
1565 ret = asn1_octet_string_decode (&asn1, &msgflags,
1566 &msgflags_length, &length);
1567 if (ret != ASN1_ERR_NOERROR) {
1568 dissect_snmp_parse_error(pd, offset, fd, tree,
1569 "message flags", ret);
1572 if (msgflags_length != 1) {
1573 dissect_snmp_parse_error(pd, offset, fd, tree,
1574 "message flags wrong length", ret);
1579 item = proto_tree_add_uint_format(global_tree,
1580 hf_snmpv3_flags, NullTVB, offset, length,
1581 msgflags[0], "Flags: 0x%02x", msgflags[0]);
1582 flags_tree = proto_item_add_subtree(item, ett_flags);
1583 proto_tree_add_boolean(flags_tree, hf_snmpv3_flags_report,
1584 NullTVB, offset, length, msgflags[0]);
1585 proto_tree_add_boolean(flags_tree, hf_snmpv3_flags_crypt,
1586 NullTVB, offset, length, msgflags[0]);
1587 proto_tree_add_boolean(flags_tree, hf_snmpv3_flags_auth,
1588 NullTVB, offset, length, msgflags[0]);
1590 encrypted = msgflags[0] & TH_CRYPT;
1593 ret = asn1_uint32_decode (&asn1, &msgsec, &length);
1594 if (ret != ASN1_ERR_NOERROR) {
1595 dissect_snmp_parse_error(pd, offset, fd, tree,
1596 "message security model", ret);
1600 proto_tree_add_text(global_tree, NullTVB, offset,
1601 length, "Message Security Model: %s",
1602 val_to_str(msgsec, sec_models,
1603 "Unknown model %#x"));
1608 start = asn1.pointer;
1609 ret = asn1_header_decode (&asn1, &cls, &con, &tag,
1610 &def, &secparm_length);
1611 length = asn1.pointer - start;
1612 if (cls != ASN1_UNI && con != ASN1_PRI &&
1614 dissect_snmp_parse_error(pd, offset, fd, tree,
1615 "Message Security Parameters",
1616 ASN1_ERR_WRONG_TYPE);
1620 item = proto_tree_add_text(snmp_tree, NullTVB,
1621 offset, secparm_length + length,
1622 "Message Security Parameters");
1623 secur_tree = proto_item_add_subtree(item,
1625 proto_tree_add_text(secur_tree, NullTVB, offset,
1627 "Message Security Parameters Length: %d",
1631 ret = asn1_sequence_decode(&asn1, &secparm_length,
1633 if (ret != ASN1_ERR_NOERROR) {
1634 dissect_snmp_parse_error(pd, offset, fd, tree,
1635 "USM sequence header", ret);
1639 ret = asn1_octet_string_decode (&asn1, &aengineid,
1640 &aengineid_length, &length);
1641 if (ret != ASN1_ERR_NOERROR) {
1642 dissect_snmp_parse_error(pd, offset, fd, tree,
1643 "authoritative engine id", ret);
1647 proto_tree_add_text(secur_tree, NullTVB, offset,
1648 length, "Authoritative Engine ID: %s",
1649 bytes_to_str(aengineid, aengineid_length));
1653 ret = asn1_uint32_decode (&asn1, &engineboots, &length);
1654 if (ret != ASN1_ERR_NOERROR) {
1655 dissect_snmp_parse_error(pd, offset, fd, tree,
1656 "engine boots", ret);
1660 proto_tree_add_text(secur_tree, NullTVB,
1661 offset, length, "Engine Boots: %d",
1665 ret = asn1_uint32_decode (&asn1, &enginetime, &length);
1666 if (ret != ASN1_ERR_NOERROR) {
1667 dissect_snmp_parse_error(pd, offset, fd, tree,
1668 "engine time", ret);
1672 proto_tree_add_text(secur_tree, NullTVB,
1673 offset, length, "Engine Time: %d",
1677 ret = asn1_octet_string_decode (&asn1, &username,
1678 &username_length, &length);
1679 if (ret != ASN1_ERR_NOERROR) {
1680 dissect_snmp_parse_error(pd, offset, fd, tree,
1685 proto_tree_add_text(secur_tree, NullTVB, offset,
1686 length, "User Name: %.*s",
1688 SAFE_STRING(username));
1692 ret = asn1_octet_string_decode (&asn1, &authpar,
1693 &authpar_length, &length);
1694 if (ret != ASN1_ERR_NOERROR) {
1695 dissect_snmp_parse_error(pd, offset, fd, tree,
1696 "authentication parameter", ret);
1700 proto_tree_add_text(secur_tree, NullTVB, offset,
1701 length, "Authentication Parameter: %s",
1702 bytes_to_str(authpar, authpar_length));
1706 ret = asn1_octet_string_decode (&asn1, &privpar,
1707 &privpar_length, &length);
1708 if (ret != ASN1_ERR_NOERROR) {
1709 dissect_snmp_parse_error(pd, offset, fd, tree,
1710 "privacy parameter", ret);
1714 proto_tree_add_text(secur_tree, NullTVB, offset,
1715 length, "Privacy Parameter: %s",
1716 bytes_to_str(privpar, privpar_length));
1722 ret = asn1_octet_string_decode (&asn1,
1723 &secparm, &secparm_length, &length);
1724 if (ret != ASN1_ERR_NOERROR) {
1725 dissect_snmp_parse_error(pd, offset, fd, tree,
1726 "Message Security Parameters", ret);
1730 proto_tree_add_text(snmp_tree, NullTVB, offset,
1732 "Message Security Parameters Data"
1733 " (%d bytes)", secparm_length);
1739 /* PDU starts here */
1741 ret = asn1_octet_string_decode (&asn1, &cryptpdu,
1742 &cryptpdu_length, &length);
1743 if (ret != ASN1_ERR_NOERROR) {
1744 dissect_snmp_parse_error(pd, offset, fd, tree,
1745 "encrypted PDU header", ret);
1748 proto_tree_add_text(snmp_tree, NullTVB, offset, length,
1749 "Encrypted PDU (%d bytes)", length);
1751 if (check_col(fd, COL_INFO))
1752 col_set_str(fd, COL_INFO, "Encrypted PDU");
1755 ret = asn1_sequence_decode(&asn1, &global_length, &length);
1756 if (ret != ASN1_ERR_NOERROR) {
1757 dissect_snmp_parse_error(pd, offset, fd, tree,
1762 ret = asn1_octet_string_decode (&asn1, &cengineid,
1763 &cengineid_length, &length);
1764 if (ret != ASN1_ERR_NOERROR) {
1765 dissect_snmp_parse_error(pd, offset, fd, tree,
1766 "context engine id", ret);
1770 proto_tree_add_text(snmp_tree, NullTVB, offset, length,
1771 "Context Engine ID: %s",
1772 bytes_to_str(cengineid, cengineid_length));
1776 ret = asn1_octet_string_decode (&asn1, &cname,
1777 &cname_length, &length);
1778 if (ret != ASN1_ERR_NOERROR) {
1779 dissect_snmp_parse_error(pd, offset, fd, tree,
1780 "context name", ret);
1784 proto_tree_add_text(snmp_tree, NullTVB, offset, length,
1785 "Context Name: %.*s", cname_length,
1786 SAFE_STRING(cname));
1792 dissect_snmp_error(pd, offset, fd, tree,
1793 "PDU for unknown version of SNMP");
1797 start = asn1.pointer;
1798 ret = asn1_header_decode (&asn1, &cls, &con, &pdu_type, &def,
1800 if (ret != ASN1_ERR_NOERROR) {
1801 dissect_snmp_parse_error(pd, offset, fd, tree,
1805 if (cls != ASN1_CTX || con != ASN1_CON) {
1806 dissect_snmp_parse_error(pd, offset, fd, tree,
1807 "PDU type", ASN1_ERR_WRONG_TYPE);
1810 dissect_common_pdu(pd, offset, fd, snmp_tree, asn1, pdu_type, start);
1814 dissect_smux_pdu(const u_char *pd, int offset, frame_data *fd,
1815 proto_tree *tree, int proto, gint ett)
1818 const guchar *start;
1823 char *pdu_type_string;
1833 int password_length;
1835 guchar *application;
1836 int application_length;
1843 proto_tree *smux_tree = NULL;
1844 proto_item *item = NULL;
1848 if (check_col(fd, COL_PROTOCOL))
1849 col_set_str(fd, COL_PROTOCOL, "SMUX");
1852 item = proto_tree_add_item(tree, proto, NullTVB, offset,
1853 END_OF_FRAME, FALSE);
1854 smux_tree = proto_item_add_subtree(item, ett);
1857 /* NOTE: we have to parse the message piece by piece, since the
1858 * capture length may be less than the message length: a 'global'
1859 * parsing is likely to fail.
1861 /* parse the SNMP header */
1862 asn1_open(&asn1, &pd[offset], END_OF_FRAME);
1863 start = asn1.pointer;
1864 ret = asn1_header_decode (&asn1, &cls, &con, &pdu_type, &def,
1866 if (ret != ASN1_ERR_NOERROR) {
1867 dissect_snmp_parse_error(pd, offset, fd, tree,
1872 /* Dissect SMUX here */
1873 if (cls == ASN1_APL && con == ASN1_CON && pdu_type == SMUX_MSG_OPEN) {
1874 pdu_type_string = val_to_str(pdu_type, smux_types,
1875 "Unknown PDU type %#x");
1876 if (check_col(fd, COL_INFO))
1877 col_add_str(fd, COL_INFO, pdu_type_string);
1878 length = asn1.pointer - start;
1880 proto_tree_add_text(smux_tree, NullTVB, offset, length,
1881 "PDU type: %s", pdu_type_string);
1884 ret = asn1_uint32_decode (&asn1, &version, &length);
1885 if (ret != ASN1_ERR_NOERROR) {
1886 dissect_snmp_parse_error(pd, offset, fd, tree,
1891 proto_tree_add_text(smux_tree, NullTVB, offset, length,
1892 "Version: %d", version);
1896 ret = asn1_oid_decode (&asn1, ®id, ®id_length, &length);
1897 if (ret != ASN1_ERR_NOERROR) {
1898 dissect_snmp_parse_error(pd, offset, fd, tree,
1899 "registration OID", ret);
1903 oid_string = format_oid(regid, regid_length);
1904 proto_tree_add_text(smux_tree, NullTVB, offset, length,
1905 "Registration: %s", oid_string);
1911 ret = asn1_octet_string_decode (&asn1, &application,
1912 &application_length, &length);
1913 if (ret != ASN1_ERR_NOERROR) {
1914 dissect_snmp_parse_error(pd, offset, fd, tree,
1915 "application", ret);
1919 proto_tree_add_text(smux_tree, NullTVB, offset, length,
1920 "Application: %.*s", application_length,
1921 SAFE_STRING(application));
1923 g_free(application);
1926 ret = asn1_octet_string_decode (&asn1, &password,
1927 &password_length, &length);
1928 if (ret != ASN1_ERR_NOERROR) {
1929 dissect_snmp_parse_error(pd, offset, fd, tree,
1934 proto_tree_add_text(smux_tree, NullTVB, offset, length,
1935 "Password: %.*s", password_length,
1936 SAFE_STRING(password));
1942 if (cls == ASN1_APL && con == ASN1_PRI && pdu_type == SMUX_MSG_CLOSE) {
1943 pdu_type_string = val_to_str(pdu_type, smux_types,
1944 "Unknown PDU type %#x");
1945 if (check_col(fd, COL_INFO))
1946 col_add_str(fd, COL_INFO, pdu_type_string);
1947 length = asn1.pointer - start;
1949 proto_tree_add_text(smux_tree, NullTVB, offset, length,
1950 "PDU type: %s", pdu_type_string);
1953 ret = asn1_uint32_value_decode (&asn1, pdu_length, &cause);
1954 if (ret != ASN1_ERR_NOERROR) {
1955 dissect_snmp_parse_error(pd, offset, fd, tree,
1960 proto_tree_add_text(smux_tree, NullTVB, offset,
1961 pdu_length, "Cause: %s",
1962 val_to_str(cause, smux_close,
1963 "Unknown cause %#x"));
1965 offset += pdu_length;
1968 if (cls == ASN1_APL && con == ASN1_CON && pdu_type == SMUX_MSG_RREQ) {
1969 pdu_type_string = val_to_str(pdu_type, smux_types,
1970 "Unknown PDU type %#x");
1971 if (check_col(fd, COL_INFO))
1972 col_add_str(fd, COL_INFO, pdu_type_string);
1973 length = asn1.pointer - start;
1975 proto_tree_add_text(smux_tree, NullTVB, offset, length,
1976 "PDU type: %s", pdu_type_string);
1979 ret = asn1_oid_decode (&asn1, ®id, ®id_length, &length);
1980 if (ret != ASN1_ERR_NOERROR) {
1981 dissect_snmp_parse_error(pd, offset, fd, tree,
1982 "registration subtree", ret);
1986 oid_string = format_oid(regid, regid_length);
1987 proto_tree_add_text(smux_tree, NullTVB, offset, length,
1988 "Registration: %s", oid_string);
1994 ret = asn1_uint32_decode (&asn1, &priority, &length);
1995 if (ret != ASN1_ERR_NOERROR) {
1996 dissect_snmp_parse_error(pd, offset, fd, tree,
2001 proto_tree_add_text(smux_tree, NullTVB, offset, length,
2002 "Priority: %d", priority);
2006 ret = asn1_uint32_decode (&asn1, &operation, &length);
2007 if (ret != ASN1_ERR_NOERROR) {
2008 dissect_snmp_parse_error(pd, offset, fd, tree,
2013 proto_tree_add_text(smux_tree, NullTVB, offset, length,
2015 val_to_str(operation, smux_rreq,
2016 "Unknown operation %#x"));
2021 if (cls == ASN1_APL && con == ASN1_PRI && pdu_type == SMUX_MSG_RRSP) {
2022 pdu_type_string = val_to_str(pdu_type, smux_types,
2023 "Unknown PDU type %#x");
2024 if (check_col(fd, COL_INFO))
2025 col_add_str(fd, COL_INFO, pdu_type_string);
2026 length = asn1.pointer - start;
2028 proto_tree_add_text(smux_tree, NullTVB, offset, length,
2029 "PDU type: %s", pdu_type_string);
2032 ret = asn1_uint32_value_decode (&asn1, pdu_length, &priority);
2033 if (ret != ASN1_ERR_NOERROR) {
2034 dissect_snmp_parse_error(pd, offset, fd, tree,
2039 proto_tree_add_text(smux_tree, NullTVB, offset,
2041 val_to_str(priority, smux_prio,
2044 offset += pdu_length;
2047 if (cls == ASN1_APL && con == ASN1_PRI && pdu_type == SMUX_MSG_SOUT) {
2048 pdu_type_string = val_to_str(pdu_type, smux_types,
2049 "Unknown PDU type %#x");
2050 if (check_col(fd, COL_INFO))
2051 col_add_str(fd, COL_INFO, pdu_type_string);
2052 length = asn1.pointer - start;
2054 proto_tree_add_text(smux_tree, NullTVB, offset, length,
2055 "PDU type: %s", pdu_type_string);
2058 ret = asn1_uint32_value_decode (&asn1, pdu_length, &commit);
2059 if (ret != ASN1_ERR_NOERROR) {
2060 dissect_snmp_parse_error(pd, offset, fd, tree,
2065 proto_tree_add_text(smux_tree, NullTVB, offset,
2067 val_to_str(commit, smux_sout,
2068 "Unknown SOUT Value: %#x"));
2070 offset += pdu_length;
2073 if (cls != ASN1_CTX || con != ASN1_CON) {
2074 dissect_snmp_parse_error(pd, offset, fd, tree,
2075 "PDU type", ASN1_ERR_WRONG_TYPE);
2078 dissect_common_pdu(pd, offset, fd, smux_tree, asn1, pdu_type, start);
2082 dissect_snmp(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
2084 conversation_t *conversation;
2086 OLD_CHECK_DISPLAY_AS_DATA(proto_snmp, pd, offset, fd, tree);
2089 * The first SNMP packet goes to the SNMP port; the second one
2090 * may come from some *other* port, but goes back to the same
2091 * IP address and port as the ones from which the first packet
2092 * came; all subsequent packets presumably go between those two
2093 * IP addresses and ports.
2095 * If this packet went to the SNMP port, we check to see if
2096 * there's already a conversation with the source IP address
2097 * and port of this packet, the destination IP address of this
2098 * packet, and any destination UDP port. If not, we create
2099 * one, with a wildcard UDP port, and give it the SNMP dissector
2102 if (pi.destport == UDP_PORT_SNMP) {
2103 conversation = find_conversation(&pi.src, &pi.dst, PT_UDP,
2104 pi.srcport, 0, NO_DST_PORT);
2105 if (conversation == NULL) {
2106 conversation = conversation_new(&pi.src, &pi.dst, PT_UDP,
2107 pi.srcport, 0, NULL,
2109 old_conversation_set_dissector(conversation, dissect_snmp);
2113 dissect_snmp_pdu(pd, offset, fd, tree, "SNMP", proto_snmp, ett_snmp);
2117 dissect_smux(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
2119 OLD_CHECK_DISPLAY_AS_DATA(proto_smux, pd, offset, fd, tree);
2120 dissect_smux_pdu(pd, offset, fd, tree, proto_smux, ett_smux);
2124 proto_register_snmp(void)
2127 void *libsnmp_handle;
2128 int (*snmp_set_suffix_only_p)(int);
2129 int (*ds_set_int_p)(int, int, int);
2132 static hf_register_info hf[] = {
2134 { "SNMPv3 Flags", "snmpv3.flags", FT_UINT8, BASE_HEX, NULL,
2136 { &hf_snmpv3_flags_auth,
2137 { "Authenticated", "snmpv3.flags.auth", FT_BOOLEAN, 8,
2138 TFS(&flags_set_truth), TH_AUTH, "" }},
2139 { &hf_snmpv3_flags_crypt,
2140 { "Encrypted", "snmpv3.flags.crypt", FT_BOOLEAN, 8,
2141 TFS(&flags_set_truth), TH_CRYPT, "" }},
2142 { &hf_snmpv3_flags_report,
2143 { "Reportable", "snmpv3.flags.report", FT_BOOLEAN, 8,
2144 TFS(&flags_set_truth), TH_REPORT, "" }},
2146 static gint *ett[] = {
2150 &ett_parameters_qos,
2156 #if defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H)
2157 /* UCD or CMU SNMP */
2159 #ifdef HAVE_UCD_SNMP_SNMP_H
2161 /* As per the comment near the beginning of the file, UCD SNMP 4.1.1
2162 changed "snmp_set_suffix_only()" from a function to a macro,
2163 removing "snmp_set_suffix_only()" from the library; this means
2164 that binaries that call "snmp_set_suffix_only()" and
2165 that are linked against shared libraries from earlier versions
2166 of the UCD SNMP library won't run with shared libraries from
2169 This is a problem on Red Hat Linux, as pre-6.2 releases
2170 came with pre-4.1.1 UCD SNMP, while 6.2 comes the 4.1.1.
2171 Versions of Ethereal built on pre-6.2 releases don't run
2172 on 6.2, and the current Ethereal RPMs are built on pre-6.2
2173 releases, causing problems when users running 6.2 download
2174 them and try to use them.
2176 Building the releases on 6.2 isn't necessarily the answer,
2177 as "snmp_set_suffix_only()" expands to a call to "ds_set_int()"
2178 with a second argument not supported by at least some pre-4.1.1
2179 versions of the library - it appears that the 4.0.1 library,
2180 at least, checks for invalid arguments and returns an error
2181 rather than stomping random memory, but that means that you
2182 won't get get OIDs displayed as module-name::sub-OID.
2184 So we use a trick similar to one I've seen mentioned as
2185 used in Windows applications to let you build binaries
2186 that run on many different versions of Windows 9x and
2187 Windows NT, that use features present on later versions
2188 if run on those later versions, but that avoid calling,
2189 when run on older versions, routines not present on those
2192 I.e., we load "libsnmp.so.0" with "dlopen()", and call
2193 "dlsym()" to try to find "snmp_set_suffix_only()"; if we
2194 don't find it, we make the appropriate call to
2195 "ds_set_int()" instead. (We load "libsnmp.so.0" rather
2196 than "libsnmp.so" because, at least on RH 6.2, "libsnmp.so"
2197 exists only if you've loaded the libsnmp development package,
2198 which makes "libsnmp.so" a symlink to "libsnmp.so.0"; we
2199 don't want to force users to install it or to make said
2202 We do this only on Linux, for now, as we've only seen the
2203 problem on Red Hat; it may show up on other OSes that bundle
2204 UCD SNMP, or on OSes where it's not bundled but for which
2205 binary packages are built that link against a shared version
2206 of the UCD SNMP library. If we run into one of those, we
2207 can do this under those OSes as well, *if* "dlopen()" makes
2208 the run-time linker use the same search rules as it uses when
2209 loading libraries with which the application is linked.
2211 (Perhaps we could use the GLib wrappers for run-time linking,
2212 *if* they're thin enough; however, as this code is currently
2213 used only on Linux, we don't worry about that for now.) */
2215 libsnmp_handle = dlopen("libsnmp.so.0", RTLD_LAZY|RTLD_GLOBAL);
2216 if (libsnmp_handle == NULL) {
2217 /* We didn't find "libsnmp.so.0".
2219 This could mean that there is no SNMP shared library
2220 on this system, in which case we were linked statically,
2221 in which case whatever call the following line of code
2222 makes will presumably work, as we have the routine it
2223 calls wired into our binary. (If we were linked
2224 dynamically with "-lsnmp", we would have failed to
2227 It could also mean that there is an SNMP shared library
2228 on this system, but it's called something other than
2229 "libsnmp.so.0"; so far, we've seen the problem we're
2230 working around only on systems where the SNMP shared
2231 library is called "libsnmp.so.0", so we assume for now
2232 that systems with shared SNMP libraries named something
2233 other than "libsnmp.so.0" have an SNMP library that's
2235 snmp_set_suffix_only(2);
2237 /* OK, we have it loaded. Do we have
2238 "snmp_set_suffix_only()"? */
2239 snmp_set_suffix_only_p = dlsym(libsnmp_handle,
2240 "snmp_set_suffix_only");
2241 if (snmp_set_suffix_only_p != NULL) {
2242 /* Yes - call it. */
2243 (*snmp_set_suffix_only_p)(2);
2245 /* No; do we have "ds_set_int()"? */
2246 ds_set_int_p = dlsym(libsnmp_handle, "ds_set_int");
2247 if (ds_set_int_p != NULL) {
2248 /* Yes - cal it with DS_LIBRARY_ID,
2249 DS_LIB_PRINT_SUFFIX_ONLY, and 2 as
2252 We do *not* use DS_LIBRARY_ID or
2253 DS_LIB_PRINT_SUFFIX_ONLY by name, so that
2254 we don't require that Ethereal be built
2255 with versions of UCD SNMP that include
2256 that value; instead, we use their values
2257 in UCD SNMP 4.1.1, which are 0 and 4,
2259 (*ds_set_int_p)(0, 4, 2);
2262 dlclose(libsnmp_handle);
2265 snmp_set_suffix_only(2);
2267 #endif /* HAVE_UCD_SNMP_SNMP_H */
2268 #endif /* defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H) */
2269 proto_snmp = proto_register_protocol("Simple Network Management Protocol",
2271 proto_smux = proto_register_protocol("SNMP Multiplex Protocol",
2273 proto_register_field_array(proto_snmp, hf, array_length(hf));
2274 proto_register_subtree_array(ett, array_length(ett));
2278 proto_reg_handoff_snmp(void)
2280 old_dissector_add("udp.port", UDP_PORT_SNMP, dissect_snmp,
2282 old_dissector_add("udp.port", UDP_PORT_SNMP_TRAP, dissect_snmp,
2284 old_dissector_add("tcp.port", TCP_PORT_SMUX, dissect_smux,
2286 old_dissector_add("ethertype", ETHERTYPE_SNMP, dissect_snmp,
2288 old_dissector_add("ipx.socket", IPX_SOCKET_SNMP_AGENT, dissect_snmp,
2290 old_dissector_add("ipx.socket", IPX_SOCKET_SNMP_SINK, dissect_snmp,