2 * Routines for SNMP (simple network management protocol)
5 * $Id: packet-snmp.c,v 1.27 2000/04/08 07:07:36 guy 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 1024 /* TBC */
54 #if defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H)
58 # if defined(HAVE_UCD_SNMP_SNMP_H)
62 # include <ucd-snmp/asn1.h>
63 # include <ucd-snmp/snmp_api.h>
64 # include <ucd-snmp/snmp_impl.h>
65 # include <ucd-snmp/mib.h>
68 * Sigh. UCD SNMP 4.1[.x] makes "snmp_set_full_objid()" a macro
69 * that calls "ds_set_boolean()" with the first two arguments
70 * being DS_LIBRARY_ID and DS_LIB_PRINT_FULL_OID; this means that,
71 * when building with 4.1[.x], we need to arrange that
72 * <ucd-snmp/default_store.h> is included, to define those two values
73 * and to declare "ds_set_boolean()".
77 * 1) we can't include it on earlier versions (at least not 3.6.2),
78 * as it doesn't exist in those versions;
80 * 2) we don't want to include <ucd-snmp/ucd-snmp-includes.h>,
81 * as that includes <ucd-snmp/snmp.h>, and that defines a whole
82 * bunch of values that we also define ourselves.
84 * So we only include it if "snmp_set_full_objid" is defined as
87 # ifdef snmp_set_full_objid
88 # include <ucd-snmp/default_store.h>
92 * XXX - for now, we assume all versions of UCD SNMP have it.
94 # define HAVE_SPRINT_VALUE
97 * Define values "sprint_value()" expects.
99 # define VALTYPE_INTEGER ASN_INTEGER
100 # define VALTYPE_COUNTER ASN_COUNTER
101 # define VALTYPE_GAUGE ASN_GAUGE
102 # define VALTYPE_TIMETICKS ASN_TIMETICKS
103 # define VALTYPE_STRING ASN_OCTET_STR
104 # define VALTYPE_IPADDR ASN_IPADDRESS
105 # define VALTYPE_OPAQUE ASN_OPAQUE
106 # define VALTYPE_NSAP ASN_NSAP
107 # define VALTYPE_OBJECTID ASN_OBJECT_ID
108 # define VALTYPE_BITSTR ASN_BIT_STR
109 # define VALTYPE_COUNTER64 ASN_COUNTER64
110 # elif defined(HAVE_SNMP_SNMP_H)
114 # include <snmp/snmp.h>
117 * Some older versions of CMU SNMP may lack these values (e.g., the
118 * "libsnmp3.6" package for Debian, which is based on some old
119 * CMU SNMP, perhaps 1.0); for now, we assume they also lack
123 # define HAVE_SPRINT_VALUE
125 * Define values "sprint_value()" expects.
127 # define VALTYPE_INTEGER SMI_INTEGER
128 # define VALTYPE_COUNTER SMI_COUNTER32
129 # define VALTYPE_GAUGE SMI_GAUGE32
130 # define VALTYPE_TIMETICKS SMI_TIMETICKS
131 # define VALTYPE_STRING SMI_STRING
132 # define VALTYPE_IPADDR SMI_IPADDRESS
133 # define VALTYPE_OPAQUE SMI_OPAQUE
134 # define VALTYPE_NSAP SMI_STRING
135 # define VALTYPE_OBJECTID SMI_OBJID
136 # define VALTYPE_BITSTR ASN_BIT_STR
137 # define VALTYPE_COUNTER64 SMI_COUNTER64
140 * Now undo all the definitions they "helpfully" gave us, so we don't get
141 * complaints about redefining them.
143 * Why, oh why, is there no library that provides code to
147 * 2) translate object IDs into names;
149 * 3) let you find out, for a given object ID, what the type, enum
150 * values, display hint, etc. are;
152 * in a *simple* fashion, without assuming that your code is part of an
153 * SNMP agent or client that wants a pile of definitions of PDU types,
154 * etc.? Is it just that 99 44/100% of the code that uses an SNMP library
155 * *is* part of an agent or client, and really *does* need that stuff,
156 * and *doesn't* need the interfaces we want?
158 # undef SNMP_ERR_NOERROR
159 # undef SNMP_ERR_TOOBIG
160 # undef SNMP_ERR_NOSUCHNAME
161 # undef SNMP_ERR_BADVALUE
162 # undef SNMP_ERR_READONLY
163 # undef SNMP_ERR_NOACCESS
164 # undef SNMP_ERR_WRONGTYPE
165 # undef SNMP_ERR_WRONGLENGTH
166 # undef SNMP_ERR_WRONGENCODING
167 # undef SNMP_ERR_WRONGVALUE
168 # undef SNMP_ERR_NOCREATION
169 # undef SNMP_ERR_INCONSISTENTVALUE
170 # undef SNMP_ERR_RESOURCEUNAVAILABLE
171 # undef SNMP_ERR_COMMITFAILED
172 # undef SNMP_ERR_UNDOFAILED
173 # undef SNMP_ERR_AUTHORIZATIONERROR
174 # undef SNMP_ERR_NOTWRITABLE
175 # undef SNMP_ERR_INCONSISTENTNAME
176 # undef SNMP_TRAP_COLDSTART
177 # undef SNMP_TRAP_WARMSTART
178 # undef SNMP_TRAP_LINKDOWN
179 # undef SNMP_TRAP_LINKUP
180 # undef SNMP_TRAP_EGPNEIGHBORLOSS
181 # undef SNMP_TRAP_ENTERPRISESPECIFIC
187 #include "packet-snmp.h"
189 static int proto_snmp = -1;
191 static gint ett_snmp = -1;
193 #define UDP_PORT_SNMP 161
194 #define UDP_PORT_SNMP_TRAP 162
196 /* Protocol version numbers */
197 #define SNMP_VERSION_1 0
198 #define SNMP_VERSION_2c 1
199 #define SNMP_VERSION_2u 2
200 #define SNMP_VERSION_3 3
202 static const value_string versions[] = {
203 { SNMP_VERSION_1, "1" },
204 { SNMP_VERSION_2c, "2C" },
205 { SNMP_VERSION_2u, "2U" },
206 { SNMP_VERSION_3, "3" },
211 #define SNMP_MSG_GET 0
212 #define SNMP_MSG_GETNEXT 1
213 #define SNMP_MSG_RESPONSE 2
214 #define SNMP_MSG_SET 3
215 #define SNMP_MSG_TRAP 4
217 #define SNMP_MSG_GETBULK 5
218 #define SNMP_MSG_INFORM 6
219 #define SNMP_MSG_TRAP2 7
220 #define SNMP_MSG_REPORT 8
222 static const value_string pdu_types[] = {
223 { SNMP_MSG_GET, "GET" },
224 { SNMP_MSG_GETNEXT, "GET-NEXT" },
225 { SNMP_MSG_SET, "SET" },
226 { SNMP_MSG_RESPONSE, "RESPONSE" },
227 { SNMP_MSG_TRAP, "TRAP-V1" },
228 { SNMP_MSG_GETBULK, "GETBULK" },
229 { SNMP_MSG_INFORM, "INFORM" },
230 { SNMP_MSG_TRAP2, "TRAP-V2" },
231 { SNMP_MSG_REPORT, "REPORT" },
235 /* Error status values */
236 #define SNMP_ERR_NOERROR 0
237 #define SNMP_ERR_TOOBIG 1
238 #define SNMP_ERR_NOSUCHNAME 2
239 #define SNMP_ERR_BADVALUE 3
240 #define SNMP_ERR_READONLY 4
241 #define SNMP_ERR_GENERROR 5
243 #define SNMP_ERR_NOACCESS 6
244 #define SNMP_ERR_WRONGTYPE 7
245 #define SNMP_ERR_WRONGLENGTH 8
246 #define SNMP_ERR_WRONGENCODING 9
247 #define SNMP_ERR_WRONGVALUE 10
248 #define SNMP_ERR_NOCREATION 11
249 #define SNMP_ERR_INCONSISTENTVALUE 12
250 #define SNMP_ERR_RESOURCEUNAVAILABLE 13
251 #define SNMP_ERR_COMMITFAILED 14
252 #define SNMP_ERR_UNDOFAILED 15
253 #define SNMP_ERR_AUTHORIZATIONERROR 16
254 #define SNMP_ERR_NOTWRITABLE 17
255 #define SNMP_ERR_INCONSISTENTNAME 18
257 static const value_string error_statuses[] = {
258 { SNMP_ERR_NOERROR, "NO ERROR" },
259 { SNMP_ERR_TOOBIG, "TOOBIG" },
260 { SNMP_ERR_NOSUCHNAME, "NO SUCH NAME" },
261 { SNMP_ERR_BADVALUE, "BAD VALUE" },
262 { SNMP_ERR_READONLY, "READ ONLY" },
263 { SNMP_ERR_GENERROR, "GENERIC ERROR" },
264 { SNMP_ERR_NOACCESS, "NO ACCESS" },
265 { SNMP_ERR_WRONGTYPE, "WRONG TYPE" },
266 { SNMP_ERR_WRONGLENGTH, "WRONG LENGTH" },
267 { SNMP_ERR_WRONGENCODING, "WRONG ENCODING" },
268 { SNMP_ERR_WRONGVALUE, "WRONG VALUE" },
269 { SNMP_ERR_NOCREATION, "NO CREATION" },
270 { SNMP_ERR_INCONSISTENTVALUE, "INCONSISTENT VALUE" },
271 { SNMP_ERR_RESOURCEUNAVAILABLE, "RESOURCE UNAVAILABLE" },
272 { SNMP_ERR_COMMITFAILED, "COMMIT FAILED" },
273 { SNMP_ERR_UNDOFAILED, "UNDO FAILED" },
274 { SNMP_ERR_AUTHORIZATIONERROR, "AUTHORIZATION ERROR" },
275 { SNMP_ERR_NOTWRITABLE, "NOT WRITABLE" },
276 { SNMP_ERR_INCONSISTENTNAME, "INCONSISTENT NAME" },
280 /* General SNMP V1 Traps */
282 #define SNMP_TRAP_COLDSTART 0
283 #define SNMP_TRAP_WARMSTART 1
284 #define SNMP_TRAP_LINKDOWN 2
285 #define SNMP_TRAP_LINKUP 3
286 #define SNMP_TRAP_AUTHFAIL 4
287 #define SNMP_TRAP_EGPNEIGHBORLOSS 5
288 #define SNMP_TRAP_ENTERPRISESPECIFIC 6
290 static const value_string trap_types[] = {
291 { SNMP_TRAP_COLDSTART, "COLD START" },
292 { SNMP_TRAP_WARMSTART, "WARM START" },
293 { SNMP_TRAP_LINKDOWN, "LINK DOWN" },
294 { SNMP_TRAP_LINKUP, "LINK UP" },
295 { SNMP_TRAP_AUTHFAIL, "AUTHENTICATION FAILED" },
296 { SNMP_TRAP_EGPNEIGHBORLOSS, "EGP NEIGHBORLOSS" },
297 { SNMP_TRAP_ENTERPRISESPECIFIC, "ENTERPRISE SPECIFIC" },
303 #define SNMP_IPA 0 /* IP Address */
304 #define SNMP_CNT 1 /* Counter (Counter32) */
305 #define SNMP_GGE 2 /* Gauge (Gauge32) */
306 #define SNMP_TIT 3 /* TimeTicks */
307 #define SNMP_OPQ 4 /* Opaque */
308 #define SNMP_NSP 5 /* NsapAddress */
309 #define SNMP_C64 6 /* Counter64 */
310 #define SNMP_U32 7 /* Uinteger32 */
319 #define SNMP_INTEGER 1 /* l */
320 #define SNMP_OCTETSTR 2 /* c */
321 #define SNMP_DISPLAYSTR 2 /* c */
322 #define SNMP_OBJECTID 3 /* ul */
323 #define SNMP_IPADDR 4 /* uc */
324 #define SNMP_COUNTER 5 /* ul */
325 #define SNMP_GAUGE 6 /* ul */
326 #define SNMP_TIMETICKS 7 /* ul */
327 #define SNMP_OPAQUE 8 /* c */
329 /* additional SNMPv2 Types */
331 #define SNMP_UINTEGER 5 /* ul */
332 #define SNMP_BITSTR 9 /* uc */
333 #define SNMP_NSAP 10 /* uc */
334 #define SNMP_COUNTER64 11 /* ul */
335 #define SNMP_NOSUCHOBJECT 12
336 #define SNMP_NOSUCHINSTANCE 13
337 #define SNMP_ENDOFMIBVIEW 14
339 typedef struct _SNMP_CNV SNMP_CNV;
349 static SNMP_CNV SnmpCnv [] =
351 {ASN1_UNI, ASN1_NUL, SNMP_NULL, "NULL"},
352 {ASN1_UNI, ASN1_INT, SNMP_INTEGER, "INTEGER"},
353 {ASN1_UNI, ASN1_OTS, SNMP_OCTETSTR, "OCTET STRING"},
354 {ASN1_UNI, ASN1_OJI, SNMP_OBJECTID, "OBJECTID"},
355 {ASN1_APL, SNMP_IPA, SNMP_IPADDR, "IPADDR"},
356 {ASN1_APL, SNMP_CNT, SNMP_COUNTER, "COUNTER"}, /* Counter32 */
357 {ASN1_APL, SNMP_GGE, SNMP_GAUGE, "GAUGE"}, /* Gauge32 == Unsigned32 */
358 {ASN1_APL, SNMP_TIT, SNMP_TIMETICKS, "TIMETICKS"},
359 {ASN1_APL, SNMP_OPQ, SNMP_OPAQUE, "OPAQUE"},
361 /* SNMPv2 data types and errors */
363 {ASN1_UNI, ASN1_BTS, SNMP_BITSTR, "BITSTR"},
364 {ASN1_APL, SNMP_C64, SNMP_COUNTER64, "COUNTER64"},
365 {ASN1_CTX, SERR_NSO, SNMP_NOSUCHOBJECT, "NOSUCHOBJECT"},
366 {ASN1_CTX, SERR_NSI, SNMP_NOSUCHINSTANCE, "NOSUCHINSTANCE"},
367 {ASN1_CTX, SERR_EOM, SNMP_ENDOFMIBVIEW, "ENDOFMIBVIEW"},
372 * NAME: g_snmp_tag_cls2syntax
373 * SYNOPSIS: gboolean g_snmp_tag_cls2syntax
379 * DESCRIPTION: Converts ASN1 tag and class to Syntax tag and name.
380 * See SnmpCnv for conversion.
381 * RETURNS: name on success, NULL on failure
385 snmp_tag_cls2syntax ( guint tag, guint cls, gushort *syntax)
390 while (cnv->syntax != -1)
392 if (cnv->tag == tag && cnv->class == cls)
394 *syntax = cnv->syntax;
403 dissect_snmp_parse_error(const u_char *pd, int offset, frame_data *fd,
404 proto_tree *tree, const char *field_name, int ret)
408 if (check_col(fd, COL_INFO)) {
412 errstr = "Ran out of data";
415 case ASN1_ERR_EOC_MISMATCH:
416 errstr = "EOC mismatch";
419 case ASN1_ERR_WRONG_TYPE:
420 errstr = "Wrong type for that item";
423 case ASN1_ERR_LENGTH_NOT_DEFINITE:
424 errstr = "Length was indefinite";
427 case ASN1_ERR_LENGTH_MISMATCH:
428 errstr = "Length mismatch";
431 case ASN1_ERR_WRONG_LENGTH_FOR_TYPE:
432 errstr = "Wrong length for that item's type";
436 errstr = "Unknown error";
439 col_add_fstr(fd, COL_INFO,
440 "ERROR: Couldn't parse %s: %s", field_name, errstr);
443 dissect_data(pd, offset, fd, tree);
447 dissect_snmp_error(const u_char *pd, int offset, frame_data *fd,
448 proto_tree *tree, const char *message)
450 if (check_col(fd, COL_INFO))
451 col_add_str(fd, COL_INFO, message);
453 dissect_data(pd, offset, fd, tree);
457 format_oid(gchar *buf, subid_t *oid, guint oid_length)
462 len = sprintf(buf, "%lu", (unsigned long)oid[0]);
464 for (i = 1; i < oid_length;i++) {
465 len = sprintf(buf, ".%lu", (unsigned long)oid[i]);
470 #ifdef HAVE_SPRINT_VALUE
472 format_value(gchar *buf, struct variable_list *variable, subid_t *variable_oid,
473 guint variable_oid_length, gushort vb_type, guint vb_length)
475 variable->next_variable = NULL;
476 variable->name = variable_oid;
477 variable->name_length = variable_oid_length;
481 variable->type = VALTYPE_INTEGER;
485 variable->type = VALTYPE_COUNTER;
489 variable->type = VALTYPE_GAUGE;
493 variable->type = VALTYPE_TIMETICKS;
497 variable->type = VALTYPE_STRING;
501 variable->type = VALTYPE_IPADDR;
505 variable->type = VALTYPE_OPAQUE;
509 variable->type = VALTYPE_NSAP;
513 variable->type = VALTYPE_OBJECTID;
517 variable->type = VALTYPE_BITSTR;
521 variable->type = VALTYPE_COUNTER64;
524 variable->val_len = vb_length;
525 sprint_value(buf, variable_oid, variable_oid_length, variable);
530 snmp_variable_decode(proto_tree *snmp_tree, subid_t *variable_oid,
531 guint variable_oid_length, ASN1_SCK *asn1, int offset, guint *lengthp)
542 gint32 vb_integer_value;
543 guint32 vb_uinteger_value;
545 guint8 *vb_octet_string;
550 gchar vb_display_string[MAX_STRING_LEN]; /* TBC */
552 #ifdef HAVE_SPRINT_VALUE
553 struct variable_list variable;
554 #if defined(HAVE_UCD_SNMP_SNMP_H)
557 #else /* HAVE_SPRINT_VALUE */
561 #endif /* HAVE_SPRINT_VALUE */
563 /* parse the type of the object */
564 start = asn1->pointer;
565 ret = asn1_header_decode (asn1, &cls, &con, &tag, &def, &vb_length);
566 if (ret != ASN1_ERR_NOERROR)
569 return ASN1_ERR_LENGTH_NOT_DEFINITE;
571 /* Convert the class, constructed flag, and tag to a type. */
572 vb_type_name = snmp_tag_cls2syntax(tag, cls, &vb_type);
573 if (vb_type_name == NULL) {
576 * Dissect the value as an opaque string of octets.
578 vb_type_name = "unsupported type";
579 vb_type = SNMP_OPAQUE;
582 /* parse the value */
586 ret = asn1_int32_value_decode(asn1, vb_length,
588 if (ret != ASN1_ERR_NOERROR)
590 length = asn1->pointer - start;
592 #ifdef HAVE_SPRINT_VALUE
593 #if defined(HAVE_UCD_SNMP_SNMP_H)
594 value = vb_integer_value;
595 variable.val.integer = &value;
596 #elif defined(HAVE_SNMP_SNMP_H)
597 variable.val.integer = &vb_integer_value;
599 format_value(vb_display_string, &variable,
600 variable_oid, variable_oid_length, vb_type,
602 proto_tree_add_text(snmp_tree, offset, length,
603 "Value: %s", vb_display_string);
605 proto_tree_add_text(snmp_tree, offset, length,
606 "Value: %s: %d (%#x)", vb_type_name,
607 vb_integer_value, vb_integer_value);
615 ret = asn1_uint32_value_decode(asn1, vb_length,
617 if (ret != ASN1_ERR_NOERROR)
619 length = asn1->pointer - start;
621 #ifdef HAVE_SPRINT_VALUE
622 #if defined(HAVE_UCD_SNMP_SNMP_H)
623 value = vb_uinteger_value;
624 variable.val.integer = &value;
625 #elif defined(HAVE_SNMP_SNMP_H)
626 variable.val.integer = &vb_uinteger_value;
628 format_value(vb_display_string, &variable,
629 variable_oid, variable_oid_length, vb_type,
631 proto_tree_add_text(snmp_tree, offset, length,
632 "Value: %s", vb_display_string);
634 proto_tree_add_text(snmp_tree, offset, length,
635 "Value: %s: %u (%#x)", vb_type_name,
636 vb_uinteger_value, vb_uinteger_value);
647 ret = asn1_octet_string_value_decode (asn1, vb_length,
649 if (ret != ASN1_ERR_NOERROR)
651 length = asn1->pointer - start;
653 #ifdef HAVE_SPRINT_VALUE
654 variable.val.string = vb_octet_string;
655 format_value(vb_display_string, &variable,
656 variable_oid, variable_oid_length, vb_type,
658 proto_tree_add_text(snmp_tree, offset, length,
659 "Value: %s", vb_display_string);
662 * If some characters are not printable, display
663 * the string as bytes.
665 for (i = 0; i < vb_length; i++) {
666 if (!(isprint(vb_octet_string[i])
667 || isspace(vb_octet_string[i])))
672 * We stopped, due to a non-printable
673 * character, before we got to the end
676 buf = &vb_display_string[0];
677 len = sprintf(buf, "%03u", vb_octet_string[0]);
679 for (i = 1; i < vb_length; i++) {
680 len = sprintf(buf, ".%03u",
684 proto_tree_add_text(snmp_tree, offset, length,
685 "Value: %s: %s", vb_type_name,
688 proto_tree_add_text(snmp_tree, offset, length,
689 "Value: %s: %.*s", vb_type_name, vb_length,
694 g_free(vb_octet_string);
698 ret = asn1_null_decode (asn1, vb_length);
699 if (ret != ASN1_ERR_NOERROR)
701 length = asn1->pointer - start;
703 proto_tree_add_text(snmp_tree, offset, length,
704 "Value: %s", vb_type_name);
709 ret = asn1_oid_value_decode (asn1, vb_length, &vb_oid,
711 if (ret != ASN1_ERR_NOERROR)
713 length = asn1->pointer - start;
715 #ifdef HAVE_SPRINT_VALUE
716 variable.val.objid = vb_oid;
717 format_value(vb_display_string, &variable,
718 variable_oid, variable_oid_length, vb_type,
719 vb_length*sizeof (subid_t));
720 proto_tree_add_text(snmp_tree, offset, length,
721 "Value: %s", vb_display_string);
723 format_oid(vb_display_string, vb_oid, vb_oid_length);
724 proto_tree_add_text(snmp_tree, offset, length,
725 "Value: %s: %s", vb_type_name, vb_display_string);
731 case SNMP_NOSUCHOBJECT:
732 length = asn1->pointer - start;
734 proto_tree_add_text(snmp_tree, offset, length,
735 "Value: %s: no such object", vb_type_name);
739 case SNMP_NOSUCHINSTANCE:
740 length = asn1->pointer - start;
742 proto_tree_add_text(snmp_tree, offset, length,
743 "Value: %s: no such instance", vb_type_name);
747 case SNMP_ENDOFMIBVIEW:
748 length = asn1->pointer - start;
750 proto_tree_add_text(snmp_tree, offset, length,
751 "Value: %s: end of mib view", vb_type_name);
756 g_assert_not_reached();
757 return ASN1_ERR_WRONG_TYPE;
760 return ASN1_ERR_NOERROR;
764 dissect_snmp_pdu(const u_char *pd, int offset, frame_data *fd,
765 proto_tree *tree, char *proto_name, int proto, gint ett)
771 guint sequence_length;
773 guint message_length;
778 int community_length;
781 char *pdu_type_string;
786 guint32 error_status;
791 guint enterprise_length;
793 guint8 *agent_address;
794 guint agent_address_length;
798 guint32 specific_type;
801 guint timestamp_length;
803 gchar oid_string[MAX_STRING_LEN]; /* TBC */
805 guint variable_bindings_length;
808 guint variable_length;
809 subid_t *variable_oid;
810 guint variable_oid_length;
811 #if defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H)
812 gchar vb_oid_string[MAX_STRING_LEN]; /* TBC */
815 proto_tree *snmp_tree = NULL;
816 proto_item *item = NULL;
820 if (check_col(fd, COL_PROTOCOL))
821 col_add_str(fd, COL_PROTOCOL, proto_name);
824 item = proto_tree_add_item(tree, proto, offset, END_OF_FRAME, NULL);
825 snmp_tree = proto_item_add_subtree(item, ett);
828 /* NOTE: we have to parse the message piece by piece, since the
829 * capture length may be less than the message length: a 'global'
830 * parsing is likely to fail.
832 /* parse the SNMP header */
833 asn1_open(&asn1, &pd[offset], END_OF_FRAME);
834 ret = asn1_sequence_decode(&asn1, &message_length, &length);
835 if (ret != ASN1_ERR_NOERROR) {
836 dissect_snmp_parse_error(pd, offset, fd, tree,
837 "message header", ret);
842 ret = asn1_uint32_decode (&asn1, &version, &length);
843 if (ret != ASN1_ERR_NOERROR) {
844 dissect_snmp_parse_error(pd, offset, fd, tree, "version number",
849 proto_tree_add_text(snmp_tree, offset, length,
851 val_to_str(version, versions, "Unknown version %#x"));
855 ret = asn1_octet_string_decode (&asn1, &community, &community_length,
857 if (ret != ASN1_ERR_NOERROR) {
858 dissect_snmp_parse_error(pd, offset, fd, tree, "community",
863 proto_tree_add_text(snmp_tree, offset, length,
864 "Community: %.*s", community_length, community);
872 case SNMP_VERSION_2c:
873 case SNMP_VERSION_2u:
878 dissect_snmp_error(pd, offset, fd, tree,
879 "PDU for unknown version of SNMP");
883 start = asn1.pointer;
884 ret = asn1_header_decode (&asn1, &cls, &con, &pdu_type, &def,
886 if (ret != ASN1_ERR_NOERROR) {
887 dissect_snmp_parse_error(pd, offset, fd, tree,
891 if (cls != ASN1_CTX || con != ASN1_CON) {
892 dissect_snmp_parse_error(pd, offset, fd, tree,
893 "PDU type", ASN1_ERR_WRONG_TYPE);
896 pdu_type_string = val_to_str(pdu_type, pdu_types,
897 "Unknown PDU type %#x");
898 if (check_col(fd, COL_INFO))
899 col_add_str(fd, COL_INFO, pdu_type_string);
900 length = asn1.pointer - start;
902 proto_tree_add_text(snmp_tree, offset, length,
903 "PDU type: %s", pdu_type_string);
907 /* get the fields in the PDU preceeding the variable-bindings sequence */
911 case SNMP_MSG_GETNEXT:
912 case SNMP_MSG_RESPONSE:
914 case SNMP_MSG_GETBULK:
915 case SNMP_MSG_INFORM:
918 ret = asn1_uint32_decode (&asn1, &request_id, &length);
919 if (ret != ASN1_ERR_NOERROR) {
920 dissect_snmp_parse_error(pd, offset, fd, tree,
925 proto_tree_add_text(snmp_tree, offset, length,
926 "Request Id: %#x", request_id);
930 /* error status, or getbulk non-repeaters */
931 ret = asn1_uint32_decode (&asn1, &error_status, &length);
932 if (ret != ASN1_ERR_NOERROR) {
933 dissect_snmp_parse_error(pd, offset, fd, tree,
934 (pdu_type == SNMP_MSG_GETBULK) ? "non-repeaters"
940 if (pdu_type == SNMP_MSG_GETBULK) {
941 proto_tree_add_text(snmp_tree, offset, length,
942 "Non-repeaters: %u", error_status);
944 proto_tree_add_text(snmp_tree, offset, length,
946 val_to_str(error_status, error_statuses,
952 /* error index, or getbulk max-repetitions */
953 ret = asn1_uint32_decode (&asn1, &error_index, &length);
954 if (ret != ASN1_ERR_NOERROR) {
955 dissect_snmp_parse_error(pd, offset, fd, tree,
956 (pdu_type == SNMP_MSG_GETBULK) ? "max repetitions"
962 if (pdu_type == SNMP_MSG_GETBULK) {
963 proto_tree_add_text(snmp_tree, offset, length,
964 "Max repetitions: %u", error_index);
966 proto_tree_add_text(snmp_tree, offset, length,
967 "Error Index: %u", error_index);
975 ret = asn1_oid_decode (&asn1, &enterprise, &enterprise_length,
977 if (ret != ASN1_ERR_NOERROR) {
978 dissect_snmp_parse_error(pd, offset, fd, tree,
979 "enterprise OID", ret);
983 format_oid(oid_string, enterprise, enterprise_length);
984 proto_tree_add_text(snmp_tree, offset, length,
985 "Enterprise: %s", oid_string);
991 start = asn1.pointer;
992 ret = asn1_header_decode (&asn1, &cls, &con, &tag,
993 &def, &agent_address_length);
994 if (ret != ASN1_ERR_NOERROR) {
995 dissect_snmp_parse_error(pd, offset, fd, tree,
996 "agent address", ret);
999 if (!((cls == ASN1_APL && con == ASN1_PRI && tag == SNMP_IPA) ||
1000 (cls == ASN1_UNI && con == ASN1_PRI && tag == ASN1_OTS))) {
1001 /* GXSNMP 0.0.15 says the latter is "needed for
1003 dissect_snmp_parse_error(pd, offset, fd, tree,
1004 "agent_address", ASN1_ERR_WRONG_TYPE);
1007 if (agent_address_length != 4) {
1008 dissect_snmp_parse_error(pd, offset, fd, tree,
1009 "agent_address", ASN1_ERR_WRONG_LENGTH_FOR_TYPE);
1012 ret = asn1_octet_string_value_decode (&asn1,
1013 agent_address_length, &agent_address);
1014 if (ret != ASN1_ERR_NOERROR) {
1015 dissect_snmp_parse_error(pd, offset, fd, tree,
1016 "agent address", ret);
1019 length = asn1.pointer - start;
1021 proto_tree_add_text(snmp_tree, offset, agent_address_length,
1022 "Agent address: %s", ip_to_str(agent_address));
1024 g_free(agent_address);
1027 /* generic trap type */
1028 ret = asn1_uint32_decode (&asn1, &trap_type, &length);
1029 if (ret != ASN1_ERR_NOERROR) {
1030 dissect_snmp_parse_error(pd, offset, fd, tree,
1031 "generic trap type", ret);
1035 proto_tree_add_text(snmp_tree, offset, length,
1037 val_to_str(trap_type, trap_types, "Unknown (%u)"));
1041 /* specific trap type */
1042 ret = asn1_uint32_decode (&asn1, &specific_type, &length);
1043 if (ret != ASN1_ERR_NOERROR) {
1044 dissect_snmp_parse_error(pd, offset, fd, tree,
1045 "specific trap type", ret);
1049 proto_tree_add_text(snmp_tree, offset, length,
1050 "Specific trap type: %u (%#x)",
1051 specific_type, specific_type);
1056 start = asn1.pointer;
1057 ret = asn1_header_decode (&asn1, &cls, &con, &tag,
1058 &def, ×tamp_length);
1059 if (ret != ASN1_ERR_NOERROR) {
1060 dissect_snmp_parse_error(pd, offset, fd, tree,
1064 if (!((cls == ASN1_APL && con == ASN1_PRI && tag == SNMP_TIT) ||
1065 (cls == ASN1_UNI && con == ASN1_PRI && tag == ASN1_INT))) {
1066 dissect_snmp_parse_error(pd, offset, fd, tree,
1067 "timestamp", ASN1_ERR_WRONG_TYPE);
1070 ret = asn1_uint32_value_decode(&asn1, timestamp_length,
1072 if (ret != ASN1_ERR_NOERROR) {
1073 dissect_snmp_parse_error(pd, offset, fd, tree,
1077 length = asn1.pointer - start;
1079 proto_tree_add_text(snmp_tree, offset, length,
1080 "Timestamp: %u", timestamp);
1086 /* variable bindings */
1087 /* get header for variable-bindings sequence */
1088 ret = asn1_sequence_decode(&asn1, &variable_bindings_length, &length);
1089 if (ret != ASN1_ERR_NOERROR) {
1090 dissect_snmp_parse_error(pd, offset, fd, tree,
1091 "variable bindings header", ret);
1096 /* loop on variable bindings */
1098 while (variable_bindings_length > 0) {
1100 sequence_length = 0;
1103 ret = asn1_sequence_decode(&asn1, &variable_length, &length);
1104 if (ret != ASN1_ERR_NOERROR) {
1105 dissect_snmp_parse_error(pd, offset, fd, tree,
1106 "variable binding header", ret);
1109 sequence_length += length;
1111 /* parse object identifier */
1112 ret = asn1_oid_decode (&asn1, &variable_oid,
1113 &variable_oid_length, &length);
1114 if (ret != ASN1_ERR_NOERROR) {
1115 dissect_snmp_parse_error(pd, offset, fd, tree,
1116 "variable binding OID", ret);
1119 sequence_length += length;
1122 format_oid(oid_string, variable_oid,
1123 variable_oid_length);
1125 #if defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H)
1126 sprint_objid(vb_oid_string, variable_oid,
1127 variable_oid_length);
1128 proto_tree_add_text(snmp_tree, offset, sequence_length,
1129 "Object identifier %d: %s (%s)", vb_index,
1130 oid_string, vb_oid_string);
1133 proto_tree_add_text(snmp_tree, offset, sequence_length,
1134 "Object identifier %d: %s", vb_index,
1138 offset += sequence_length;
1139 variable_bindings_length -= sequence_length;
1141 /* Parse the variable's value */
1142 ret = snmp_variable_decode(snmp_tree, variable_oid,
1143 variable_oid_length, &asn1, offset, &length);
1144 if (ret != ASN1_ERR_NOERROR) {
1145 dissect_snmp_parse_error(pd, offset, fd, tree,
1150 variable_bindings_length -= length;
1155 dissect_snmp(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
1157 dissect_snmp_pdu(pd, offset, fd, tree, "SNMP", proto_snmp, ett_snmp);
1161 proto_register_snmp(void)
1163 /* static hf_register_info hf[] = {
1165 { "Name", "snmp.abbreviation", TYPE, VALS_POINTER }},
1167 static gint *ett[] = {
1171 #if defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H)
1172 /* UCD or CMU SNMP */
1174 #ifdef HAVE_UCD_SNMP_SNMP_H
1175 snmp_set_full_objid(TRUE);
1178 proto_snmp = proto_register_protocol("Simple Network Management Protocol", "snmp");
1179 /* proto_register_field_array(proto_snmp, hf, array_length(hf));*/
1180 proto_register_subtree_array(ett, array_length(ett));
1184 proto_reg_handoff_snmp(void)
1186 dissector_add("udp.port", UDP_PORT_SNMP, dissect_snmp);
1187 dissector_add("udp.port", UDP_PORT_SNMP_TRAP, dissect_snmp);