2 * Routines for SNMP (simple network management protocol)
5 * $Id: packet-snmp.c,v 1.29 2000/05/09 17:45:02 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 */
55 #if defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H)
59 # if defined(HAVE_UCD_SNMP_SNMP_H)
63 # include <ucd-snmp/asn1.h>
64 # include <ucd-snmp/snmp_api.h>
65 # include <ucd-snmp/snmp_impl.h>
66 # include <ucd-snmp/mib.h>
69 * Sigh. UCD SNMP 4.1[.x] makes "snmp_set_full_objid()" a macro
70 * that calls "ds_set_boolean()" with the first two arguments
71 * being DS_LIBRARY_ID and DS_LIB_PRINT_FULL_OID; this means that,
72 * when building with 4.1[.x], we need to arrange that
73 * <ucd-snmp/default_store.h> is included, to define those two values
74 * and to declare "ds_set_boolean()".
78 * 1) we can't include it on earlier versions (at least not 3.6.2),
79 * as it doesn't exist in those versions;
81 * 2) we don't want to include <ucd-snmp/ucd-snmp-includes.h>,
82 * as that includes <ucd-snmp/snmp.h>, and that defines a whole
83 * bunch of values that we also define ourselves.
85 * So we only include it if "snmp_set_full_objid" is defined as
88 # ifdef snmp_set_full_objid
89 # include <ucd-snmp/default_store.h>
93 * XXX - for now, we assume all versions of UCD SNMP have it.
95 # define HAVE_SPRINT_VALUE
98 * Define values "sprint_value()" expects.
100 # define VALTYPE_INTEGER ASN_INTEGER
101 # define VALTYPE_COUNTER ASN_COUNTER
102 # define VALTYPE_GAUGE ASN_GAUGE
103 # define VALTYPE_TIMETICKS ASN_TIMETICKS
104 # define VALTYPE_STRING ASN_OCTET_STR
105 # define VALTYPE_IPADDR ASN_IPADDRESS
106 # define VALTYPE_OPAQUE ASN_OPAQUE
107 # define VALTYPE_NSAP ASN_NSAP
108 # define VALTYPE_OBJECTID ASN_OBJECT_ID
109 # define VALTYPE_BITSTR ASN_BIT_STR
110 # define VALTYPE_COUNTER64 ASN_COUNTER64
111 # elif defined(HAVE_SNMP_SNMP_H)
115 # include <snmp/snmp.h>
118 * Some older versions of CMU SNMP may lack these values (e.g., the
119 * "libsnmp3.6" package for Debian, which is based on some old
120 * CMU SNMP, perhaps 1.0); for now, we assume they also lack
124 # define HAVE_SPRINT_VALUE
126 * Define values "sprint_value()" expects.
128 # define VALTYPE_INTEGER SMI_INTEGER
129 # define VALTYPE_COUNTER SMI_COUNTER32
130 # define VALTYPE_GAUGE SMI_GAUGE32
131 # define VALTYPE_TIMETICKS SMI_TIMETICKS
132 # define VALTYPE_STRING SMI_STRING
133 # define VALTYPE_IPADDR SMI_IPADDRESS
134 # define VALTYPE_OPAQUE SMI_OPAQUE
135 # define VALTYPE_NSAP SMI_STRING
136 # define VALTYPE_OBJECTID SMI_OBJID
137 # define VALTYPE_BITSTR ASN_BIT_STR
138 # define VALTYPE_COUNTER64 SMI_COUNTER64
141 * Now undo all the definitions they "helpfully" gave us, so we don't get
142 * complaints about redefining them.
144 * Why, oh why, is there no library that provides code to
148 * 2) translate object IDs into names;
150 * 3) let you find out, for a given object ID, what the type, enum
151 * values, display hint, etc. are;
153 * in a *simple* fashion, without assuming that your code is part of an
154 * SNMP agent or client that wants a pile of definitions of PDU types,
155 * etc.? Is it just that 99 44/100% of the code that uses an SNMP library
156 * *is* part of an agent or client, and really *does* need that stuff,
157 * and *doesn't* need the interfaces we want?
159 # undef SNMP_ERR_NOERROR
160 # undef SNMP_ERR_TOOBIG
161 # undef SNMP_ERR_NOSUCHNAME
162 # undef SNMP_ERR_BADVALUE
163 # undef SNMP_ERR_READONLY
164 # undef SNMP_ERR_NOACCESS
165 # undef SNMP_ERR_WRONGTYPE
166 # undef SNMP_ERR_WRONGLENGTH
167 # undef SNMP_ERR_WRONGENCODING
168 # undef SNMP_ERR_WRONGVALUE
169 # undef SNMP_ERR_NOCREATION
170 # undef SNMP_ERR_INCONSISTENTVALUE
171 # undef SNMP_ERR_RESOURCEUNAVAILABLE
172 # undef SNMP_ERR_COMMITFAILED
173 # undef SNMP_ERR_UNDOFAILED
174 # undef SNMP_ERR_AUTHORIZATIONERROR
175 # undef SNMP_ERR_NOTWRITABLE
176 # undef SNMP_ERR_INCONSISTENTNAME
177 # undef SNMP_TRAP_COLDSTART
178 # undef SNMP_TRAP_WARMSTART
179 # undef SNMP_TRAP_LINKDOWN
180 # undef SNMP_TRAP_LINKUP
181 # undef SNMP_TRAP_EGPNEIGHBORLOSS
182 # undef SNMP_TRAP_ENTERPRISESPECIFIC
188 #include "packet-snmp.h"
190 static int proto_snmp = -1;
192 static gint ett_snmp = -1;
194 #define UDP_PORT_SNMP 161
195 #define UDP_PORT_SNMP_TRAP 162
197 /* Protocol version numbers */
198 #define SNMP_VERSION_1 0
199 #define SNMP_VERSION_2c 1
200 #define SNMP_VERSION_2u 2
201 #define SNMP_VERSION_3 3
203 static const value_string versions[] = {
204 { SNMP_VERSION_1, "1" },
205 { SNMP_VERSION_2c, "2C" },
206 { SNMP_VERSION_2u, "2U" },
207 { SNMP_VERSION_3, "3" },
212 #define SNMP_MSG_GET 0
213 #define SNMP_MSG_GETNEXT 1
214 #define SNMP_MSG_RESPONSE 2
215 #define SNMP_MSG_SET 3
216 #define SNMP_MSG_TRAP 4
218 #define SNMP_MSG_GETBULK 5
219 #define SNMP_MSG_INFORM 6
220 #define SNMP_MSG_TRAP2 7
221 #define SNMP_MSG_REPORT 8
223 static const value_string pdu_types[] = {
224 { SNMP_MSG_GET, "GET" },
225 { SNMP_MSG_GETNEXT, "GET-NEXT" },
226 { SNMP_MSG_SET, "SET" },
227 { SNMP_MSG_RESPONSE, "RESPONSE" },
228 { SNMP_MSG_TRAP, "TRAP-V1" },
229 { SNMP_MSG_GETBULK, "GETBULK" },
230 { SNMP_MSG_INFORM, "INFORM" },
231 { SNMP_MSG_TRAP2, "TRAP-V2" },
232 { SNMP_MSG_REPORT, "REPORT" },
236 /* Error status values */
237 #define SNMP_ERR_NOERROR 0
238 #define SNMP_ERR_TOOBIG 1
239 #define SNMP_ERR_NOSUCHNAME 2
240 #define SNMP_ERR_BADVALUE 3
241 #define SNMP_ERR_READONLY 4
242 #define SNMP_ERR_GENERROR 5
244 #define SNMP_ERR_NOACCESS 6
245 #define SNMP_ERR_WRONGTYPE 7
246 #define SNMP_ERR_WRONGLENGTH 8
247 #define SNMP_ERR_WRONGENCODING 9
248 #define SNMP_ERR_WRONGVALUE 10
249 #define SNMP_ERR_NOCREATION 11
250 #define SNMP_ERR_INCONSISTENTVALUE 12
251 #define SNMP_ERR_RESOURCEUNAVAILABLE 13
252 #define SNMP_ERR_COMMITFAILED 14
253 #define SNMP_ERR_UNDOFAILED 15
254 #define SNMP_ERR_AUTHORIZATIONERROR 16
255 #define SNMP_ERR_NOTWRITABLE 17
256 #define SNMP_ERR_INCONSISTENTNAME 18
258 static const value_string error_statuses[] = {
259 { SNMP_ERR_NOERROR, "NO ERROR" },
260 { SNMP_ERR_TOOBIG, "TOOBIG" },
261 { SNMP_ERR_NOSUCHNAME, "NO SUCH NAME" },
262 { SNMP_ERR_BADVALUE, "BAD VALUE" },
263 { SNMP_ERR_READONLY, "READ ONLY" },
264 { SNMP_ERR_GENERROR, "GENERIC ERROR" },
265 { SNMP_ERR_NOACCESS, "NO ACCESS" },
266 { SNMP_ERR_WRONGTYPE, "WRONG TYPE" },
267 { SNMP_ERR_WRONGLENGTH, "WRONG LENGTH" },
268 { SNMP_ERR_WRONGENCODING, "WRONG ENCODING" },
269 { SNMP_ERR_WRONGVALUE, "WRONG VALUE" },
270 { SNMP_ERR_NOCREATION, "NO CREATION" },
271 { SNMP_ERR_INCONSISTENTVALUE, "INCONSISTENT VALUE" },
272 { SNMP_ERR_RESOURCEUNAVAILABLE, "RESOURCE UNAVAILABLE" },
273 { SNMP_ERR_COMMITFAILED, "COMMIT FAILED" },
274 { SNMP_ERR_UNDOFAILED, "UNDO FAILED" },
275 { SNMP_ERR_AUTHORIZATIONERROR, "AUTHORIZATION ERROR" },
276 { SNMP_ERR_NOTWRITABLE, "NOT WRITABLE" },
277 { SNMP_ERR_INCONSISTENTNAME, "INCONSISTENT NAME" },
281 /* General SNMP V1 Traps */
283 #define SNMP_TRAP_COLDSTART 0
284 #define SNMP_TRAP_WARMSTART 1
285 #define SNMP_TRAP_LINKDOWN 2
286 #define SNMP_TRAP_LINKUP 3
287 #define SNMP_TRAP_AUTHFAIL 4
288 #define SNMP_TRAP_EGPNEIGHBORLOSS 5
289 #define SNMP_TRAP_ENTERPRISESPECIFIC 6
291 static const value_string trap_types[] = {
292 { SNMP_TRAP_COLDSTART, "COLD START" },
293 { SNMP_TRAP_WARMSTART, "WARM START" },
294 { SNMP_TRAP_LINKDOWN, "LINK DOWN" },
295 { SNMP_TRAP_LINKUP, "LINK UP" },
296 { SNMP_TRAP_AUTHFAIL, "AUTHENTICATION FAILED" },
297 { SNMP_TRAP_EGPNEIGHBORLOSS, "EGP NEIGHBORLOSS" },
298 { SNMP_TRAP_ENTERPRISESPECIFIC, "ENTERPRISE SPECIFIC" },
304 #define SNMP_IPA 0 /* IP Address */
305 #define SNMP_CNT 1 /* Counter (Counter32) */
306 #define SNMP_GGE 2 /* Gauge (Gauge32) */
307 #define SNMP_TIT 3 /* TimeTicks */
308 #define SNMP_OPQ 4 /* Opaque */
309 #define SNMP_NSP 5 /* NsapAddress */
310 #define SNMP_C64 6 /* Counter64 */
311 #define SNMP_U32 7 /* Uinteger32 */
320 #define SNMP_INTEGER 1 /* l */
321 #define SNMP_OCTETSTR 2 /* c */
322 #define SNMP_DISPLAYSTR 2 /* c */
323 #define SNMP_OBJECTID 3 /* ul */
324 #define SNMP_IPADDR 4 /* uc */
325 #define SNMP_COUNTER 5 /* ul */
326 #define SNMP_GAUGE 6 /* ul */
327 #define SNMP_TIMETICKS 7 /* ul */
328 #define SNMP_OPAQUE 8 /* c */
330 /* additional SNMPv2 Types */
332 #define SNMP_UINTEGER 5 /* ul */
333 #define SNMP_BITSTR 9 /* uc */
334 #define SNMP_NSAP 10 /* uc */
335 #define SNMP_COUNTER64 11 /* ul */
336 #define SNMP_NOSUCHOBJECT 12
337 #define SNMP_NOSUCHINSTANCE 13
338 #define SNMP_ENDOFMIBVIEW 14
340 typedef struct _SNMP_CNV SNMP_CNV;
350 static SNMP_CNV SnmpCnv [] =
352 {ASN1_UNI, ASN1_NUL, SNMP_NULL, "NULL"},
353 {ASN1_UNI, ASN1_INT, SNMP_INTEGER, "INTEGER"},
354 {ASN1_UNI, ASN1_OTS, SNMP_OCTETSTR, "OCTET STRING"},
355 {ASN1_UNI, ASN1_OJI, SNMP_OBJECTID, "OBJECTID"},
356 {ASN1_APL, SNMP_IPA, SNMP_IPADDR, "IPADDR"},
357 {ASN1_APL, SNMP_CNT, SNMP_COUNTER, "COUNTER"}, /* Counter32 */
358 {ASN1_APL, SNMP_GGE, SNMP_GAUGE, "GAUGE"}, /* Gauge32 == Unsigned32 */
359 {ASN1_APL, SNMP_TIT, SNMP_TIMETICKS, "TIMETICKS"},
360 {ASN1_APL, SNMP_OPQ, SNMP_OPAQUE, "OPAQUE"},
362 /* SNMPv2 data types and errors */
364 {ASN1_UNI, ASN1_BTS, SNMP_BITSTR, "BITSTR"},
365 {ASN1_APL, SNMP_C64, SNMP_COUNTER64, "COUNTER64"},
366 {ASN1_CTX, SERR_NSO, SNMP_NOSUCHOBJECT, "NOSUCHOBJECT"},
367 {ASN1_CTX, SERR_NSI, SNMP_NOSUCHINSTANCE, "NOSUCHINSTANCE"},
368 {ASN1_CTX, SERR_EOM, SNMP_ENDOFMIBVIEW, "ENDOFMIBVIEW"},
373 * NAME: g_snmp_tag_cls2syntax
374 * SYNOPSIS: gboolean g_snmp_tag_cls2syntax
380 * DESCRIPTION: Converts ASN1 tag and class to Syntax tag and name.
381 * See SnmpCnv for conversion.
382 * RETURNS: name on success, NULL on failure
386 snmp_tag_cls2syntax ( guint tag, guint cls, gushort *syntax)
391 while (cnv->syntax != -1)
393 if (cnv->tag == tag && cnv->class == cls)
395 *syntax = cnv->syntax;
404 dissect_snmp_parse_error(const u_char *pd, int offset, frame_data *fd,
405 proto_tree *tree, const char *field_name, int ret)
409 if (check_col(fd, COL_INFO)) {
413 errstr = "Ran out of data";
416 case ASN1_ERR_EOC_MISMATCH:
417 errstr = "EOC mismatch";
420 case ASN1_ERR_WRONG_TYPE:
421 errstr = "Wrong type for that item";
424 case ASN1_ERR_LENGTH_NOT_DEFINITE:
425 errstr = "Length was indefinite";
428 case ASN1_ERR_LENGTH_MISMATCH:
429 errstr = "Length mismatch";
432 case ASN1_ERR_WRONG_LENGTH_FOR_TYPE:
433 errstr = "Wrong length for that item's type";
437 errstr = "Unknown error";
440 col_add_fstr(fd, COL_INFO,
441 "ERROR: Couldn't parse %s: %s", field_name, errstr);
444 dissect_data(pd, offset, fd, tree);
448 dissect_snmp_error(const u_char *pd, int offset, frame_data *fd,
449 proto_tree *tree, const char *message)
451 if (check_col(fd, COL_INFO))
452 col_add_str(fd, COL_INFO, message);
454 dissect_data(pd, offset, fd, tree);
458 format_oid(gchar *buf, subid_t *oid, guint oid_length)
463 len = sprintf(buf, "%lu", (unsigned long)oid[0]);
465 for (i = 1; i < oid_length;i++) {
466 len = sprintf(buf, ".%lu", (unsigned long)oid[i]);
471 #ifdef HAVE_SPRINT_VALUE
473 format_value(gchar *buf, struct variable_list *variable, subid_t *variable_oid,
474 guint variable_oid_length, gushort vb_type, guint vb_length)
476 variable->next_variable = NULL;
477 variable->name = variable_oid;
478 variable->name_length = variable_oid_length;
482 variable->type = VALTYPE_INTEGER;
486 variable->type = VALTYPE_COUNTER;
490 variable->type = VALTYPE_GAUGE;
494 variable->type = VALTYPE_TIMETICKS;
498 variable->type = VALTYPE_STRING;
502 variable->type = VALTYPE_IPADDR;
506 variable->type = VALTYPE_OPAQUE;
510 variable->type = VALTYPE_NSAP;
514 variable->type = VALTYPE_OBJECTID;
518 variable->type = VALTYPE_BITSTR;
522 variable->type = VALTYPE_COUNTER64;
525 variable->val_len = vb_length;
526 sprint_value(buf, variable_oid, variable_oid_length, variable);
531 snmp_variable_decode(proto_tree *snmp_tree, subid_t *variable_oid,
532 guint variable_oid_length, ASN1_SCK *asn1, int offset, guint *lengthp)
543 gint32 vb_integer_value;
544 guint32 vb_uinteger_value;
546 guint8 *vb_octet_string;
551 gchar vb_display_string[MAX_STRING_LEN]; /* TBC */
553 #ifdef HAVE_SPRINT_VALUE
554 struct variable_list variable;
555 #if defined(HAVE_UCD_SNMP_SNMP_H)
558 #else /* HAVE_SPRINT_VALUE */
562 #endif /* HAVE_SPRINT_VALUE */
564 /* parse the type of the object */
565 start = asn1->pointer;
566 ret = asn1_header_decode (asn1, &cls, &con, &tag, &def, &vb_length);
567 if (ret != ASN1_ERR_NOERROR)
570 return ASN1_ERR_LENGTH_NOT_DEFINITE;
572 /* Convert the class, constructed flag, and tag to a type. */
573 vb_type_name = snmp_tag_cls2syntax(tag, cls, &vb_type);
574 if (vb_type_name == NULL) {
577 * Dissect the value as an opaque string of octets.
579 vb_type_name = "unsupported type";
580 vb_type = SNMP_OPAQUE;
583 /* parse the value */
587 ret = asn1_int32_value_decode(asn1, vb_length,
589 if (ret != ASN1_ERR_NOERROR)
591 length = asn1->pointer - start;
593 #ifdef HAVE_SPRINT_VALUE
594 #if defined(HAVE_UCD_SNMP_SNMP_H)
595 value = vb_integer_value;
596 variable.val.integer = &value;
597 #elif defined(HAVE_SNMP_SNMP_H)
598 variable.val.integer = &vb_integer_value;
600 format_value(vb_display_string, &variable,
601 variable_oid, variable_oid_length, vb_type,
603 proto_tree_add_text(snmp_tree, offset, length,
604 "Value: %s", vb_display_string);
606 proto_tree_add_text(snmp_tree, offset, length,
607 "Value: %s: %d (%#x)", vb_type_name,
608 vb_integer_value, vb_integer_value);
616 ret = asn1_uint32_value_decode(asn1, vb_length,
618 if (ret != ASN1_ERR_NOERROR)
620 length = asn1->pointer - start;
622 #ifdef HAVE_SPRINT_VALUE
623 #if defined(HAVE_UCD_SNMP_SNMP_H)
624 value = vb_uinteger_value;
625 variable.val.integer = &value;
626 #elif defined(HAVE_SNMP_SNMP_H)
627 variable.val.integer = &vb_uinteger_value;
629 format_value(vb_display_string, &variable,
630 variable_oid, variable_oid_length, vb_type,
632 proto_tree_add_text(snmp_tree, offset, length,
633 "Value: %s", vb_display_string);
635 proto_tree_add_text(snmp_tree, offset, length,
636 "Value: %s: %u (%#x)", vb_type_name,
637 vb_uinteger_value, vb_uinteger_value);
648 ret = asn1_octet_string_value_decode (asn1, vb_length,
650 if (ret != ASN1_ERR_NOERROR)
652 length = asn1->pointer - start;
654 #ifdef HAVE_SPRINT_VALUE
655 variable.val.string = vb_octet_string;
656 format_value(vb_display_string, &variable,
657 variable_oid, variable_oid_length, vb_type,
659 proto_tree_add_text(snmp_tree, offset, length,
660 "Value: %s", vb_display_string);
663 * If some characters are not printable, display
664 * the string as bytes.
666 for (i = 0; i < vb_length; i++) {
667 if (!(isprint(vb_octet_string[i])
668 || isspace(vb_octet_string[i])))
673 * We stopped, due to a non-printable
674 * character, before we got to the end
677 buf = &vb_display_string[0];
678 len = sprintf(buf, "%03u", vb_octet_string[0]);
680 for (i = 1; i < vb_length; i++) {
681 len = sprintf(buf, ".%03u",
685 proto_tree_add_text(snmp_tree, offset, length,
686 "Value: %s: %s", vb_type_name,
689 proto_tree_add_text(snmp_tree, offset, length,
690 "Value: %s: %.*s", vb_type_name,
691 (int)vb_length, vb_octet_string);
695 g_free(vb_octet_string);
699 ret = asn1_null_decode (asn1, vb_length);
700 if (ret != ASN1_ERR_NOERROR)
702 length = asn1->pointer - start;
704 proto_tree_add_text(snmp_tree, offset, length,
705 "Value: %s", vb_type_name);
710 ret = asn1_oid_value_decode (asn1, vb_length, &vb_oid,
712 if (ret != ASN1_ERR_NOERROR)
714 length = asn1->pointer - start;
716 #ifdef HAVE_SPRINT_VALUE
717 variable.val.objid = vb_oid;
718 format_value(vb_display_string, &variable,
719 variable_oid, variable_oid_length, vb_type,
720 vb_length*sizeof (subid_t));
721 proto_tree_add_text(snmp_tree, offset, length,
722 "Value: %s", vb_display_string);
724 format_oid(vb_display_string, vb_oid, vb_oid_length);
725 proto_tree_add_text(snmp_tree, offset, length,
726 "Value: %s: %s", vb_type_name, vb_display_string);
732 case SNMP_NOSUCHOBJECT:
733 length = asn1->pointer - start;
735 proto_tree_add_text(snmp_tree, offset, length,
736 "Value: %s: no such object", vb_type_name);
740 case SNMP_NOSUCHINSTANCE:
741 length = asn1->pointer - start;
743 proto_tree_add_text(snmp_tree, offset, length,
744 "Value: %s: no such instance", vb_type_name);
748 case SNMP_ENDOFMIBVIEW:
749 length = asn1->pointer - start;
751 proto_tree_add_text(snmp_tree, offset, length,
752 "Value: %s: end of mib view", vb_type_name);
757 g_assert_not_reached();
758 return ASN1_ERR_WRONG_TYPE;
761 return ASN1_ERR_NOERROR;
765 dissect_snmp_pdu(const u_char *pd, int offset, frame_data *fd,
766 proto_tree *tree, char *proto_name, int proto, gint ett)
772 guint sequence_length;
774 guint message_length;
779 int community_length;
782 char *pdu_type_string;
787 guint32 error_status;
792 guint enterprise_length;
794 guint8 *agent_address;
795 guint agent_address_length;
799 guint32 specific_type;
802 guint timestamp_length;
804 gchar oid_string[MAX_STRING_LEN]; /* TBC */
806 guint variable_bindings_length;
809 guint variable_length;
810 subid_t *variable_oid;
811 guint variable_oid_length;
812 #if defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H)
813 gchar vb_oid_string[MAX_STRING_LEN]; /* TBC */
816 proto_tree *snmp_tree = NULL;
817 proto_item *item = NULL;
821 if (check_col(fd, COL_PROTOCOL))
822 col_add_str(fd, COL_PROTOCOL, proto_name);
825 item = proto_tree_add_item(tree, proto, offset, END_OF_FRAME, NULL);
826 snmp_tree = proto_item_add_subtree(item, ett);
829 /* NOTE: we have to parse the message piece by piece, since the
830 * capture length may be less than the message length: a 'global'
831 * parsing is likely to fail.
833 /* parse the SNMP header */
834 asn1_open(&asn1, &pd[offset], END_OF_FRAME);
835 ret = asn1_sequence_decode(&asn1, &message_length, &length);
836 if (ret != ASN1_ERR_NOERROR) {
837 dissect_snmp_parse_error(pd, offset, fd, tree,
838 "message header", ret);
843 ret = asn1_uint32_decode (&asn1, &version, &length);
844 if (ret != ASN1_ERR_NOERROR) {
845 dissect_snmp_parse_error(pd, offset, fd, tree, "version number",
850 proto_tree_add_text(snmp_tree, offset, length,
852 val_to_str(version, versions, "Unknown version %#x"));
856 ret = asn1_octet_string_decode (&asn1, &community, &community_length,
858 if (ret != ASN1_ERR_NOERROR) {
859 dissect_snmp_parse_error(pd, offset, fd, tree, "community",
864 proto_tree_add_text(snmp_tree, offset, length,
865 "Community: %.*s", community_length, community);
873 case SNMP_VERSION_2c:
874 case SNMP_VERSION_2u:
879 dissect_snmp_error(pd, offset, fd, tree,
880 "PDU for unknown version of SNMP");
884 start = asn1.pointer;
885 ret = asn1_header_decode (&asn1, &cls, &con, &pdu_type, &def,
887 if (ret != ASN1_ERR_NOERROR) {
888 dissect_snmp_parse_error(pd, offset, fd, tree,
892 if (cls != ASN1_CTX || con != ASN1_CON) {
893 dissect_snmp_parse_error(pd, offset, fd, tree,
894 "PDU type", ASN1_ERR_WRONG_TYPE);
897 pdu_type_string = val_to_str(pdu_type, pdu_types,
898 "Unknown PDU type %#x");
899 if (check_col(fd, COL_INFO))
900 col_add_str(fd, COL_INFO, pdu_type_string);
901 length = asn1.pointer - start;
903 proto_tree_add_text(snmp_tree, offset, length,
904 "PDU type: %s", pdu_type_string);
908 /* get the fields in the PDU preceeding the variable-bindings sequence */
912 case SNMP_MSG_GETNEXT:
913 case SNMP_MSG_RESPONSE:
915 case SNMP_MSG_GETBULK:
916 case SNMP_MSG_INFORM:
919 ret = asn1_uint32_decode (&asn1, &request_id, &length);
920 if (ret != ASN1_ERR_NOERROR) {
921 dissect_snmp_parse_error(pd, offset, fd, tree,
926 proto_tree_add_text(snmp_tree, offset, length,
927 "Request Id: %#x", request_id);
931 /* error status, or getbulk non-repeaters */
932 ret = asn1_uint32_decode (&asn1, &error_status, &length);
933 if (ret != ASN1_ERR_NOERROR) {
934 dissect_snmp_parse_error(pd, offset, fd, tree,
935 (pdu_type == SNMP_MSG_GETBULK) ? "non-repeaters"
941 if (pdu_type == SNMP_MSG_GETBULK) {
942 proto_tree_add_text(snmp_tree, offset, length,
943 "Non-repeaters: %u", error_status);
945 proto_tree_add_text(snmp_tree, offset, length,
947 val_to_str(error_status, error_statuses,
953 /* error index, or getbulk max-repetitions */
954 ret = asn1_uint32_decode (&asn1, &error_index, &length);
955 if (ret != ASN1_ERR_NOERROR) {
956 dissect_snmp_parse_error(pd, offset, fd, tree,
957 (pdu_type == SNMP_MSG_GETBULK) ? "max repetitions"
963 if (pdu_type == SNMP_MSG_GETBULK) {
964 proto_tree_add_text(snmp_tree, offset, length,
965 "Max repetitions: %u", error_index);
967 proto_tree_add_text(snmp_tree, offset, length,
968 "Error Index: %u", error_index);
976 ret = asn1_oid_decode (&asn1, &enterprise, &enterprise_length,
978 if (ret != ASN1_ERR_NOERROR) {
979 dissect_snmp_parse_error(pd, offset, fd, tree,
980 "enterprise OID", ret);
984 format_oid(oid_string, enterprise, enterprise_length);
985 proto_tree_add_text(snmp_tree, offset, length,
986 "Enterprise: %s", oid_string);
992 start = asn1.pointer;
993 ret = asn1_header_decode (&asn1, &cls, &con, &tag,
994 &def, &agent_address_length);
995 if (ret != ASN1_ERR_NOERROR) {
996 dissect_snmp_parse_error(pd, offset, fd, tree,
997 "agent address", ret);
1000 if (!((cls == ASN1_APL && con == ASN1_PRI && tag == SNMP_IPA) ||
1001 (cls == ASN1_UNI && con == ASN1_PRI && tag == ASN1_OTS))) {
1002 /* GXSNMP 0.0.15 says the latter is "needed for
1004 dissect_snmp_parse_error(pd, offset, fd, tree,
1005 "agent_address", ASN1_ERR_WRONG_TYPE);
1008 if (agent_address_length != 4) {
1009 dissect_snmp_parse_error(pd, offset, fd, tree,
1010 "agent_address", ASN1_ERR_WRONG_LENGTH_FOR_TYPE);
1013 ret = asn1_octet_string_value_decode (&asn1,
1014 agent_address_length, &agent_address);
1015 if (ret != ASN1_ERR_NOERROR) {
1016 dissect_snmp_parse_error(pd, offset, fd, tree,
1017 "agent address", ret);
1020 length = asn1.pointer - start;
1022 proto_tree_add_text(snmp_tree, offset, agent_address_length,
1023 "Agent address: %s", ip_to_str(agent_address));
1025 g_free(agent_address);
1028 /* generic trap type */
1029 ret = asn1_uint32_decode (&asn1, &trap_type, &length);
1030 if (ret != ASN1_ERR_NOERROR) {
1031 dissect_snmp_parse_error(pd, offset, fd, tree,
1032 "generic trap type", ret);
1036 proto_tree_add_text(snmp_tree, offset, length,
1038 val_to_str(trap_type, trap_types, "Unknown (%u)"));
1042 /* specific trap type */
1043 ret = asn1_uint32_decode (&asn1, &specific_type, &length);
1044 if (ret != ASN1_ERR_NOERROR) {
1045 dissect_snmp_parse_error(pd, offset, fd, tree,
1046 "specific trap type", ret);
1050 proto_tree_add_text(snmp_tree, offset, length,
1051 "Specific trap type: %u (%#x)",
1052 specific_type, specific_type);
1057 start = asn1.pointer;
1058 ret = asn1_header_decode (&asn1, &cls, &con, &tag,
1059 &def, ×tamp_length);
1060 if (ret != ASN1_ERR_NOERROR) {
1061 dissect_snmp_parse_error(pd, offset, fd, tree,
1065 if (!((cls == ASN1_APL && con == ASN1_PRI && tag == SNMP_TIT) ||
1066 (cls == ASN1_UNI && con == ASN1_PRI && tag == ASN1_INT))) {
1067 dissect_snmp_parse_error(pd, offset, fd, tree,
1068 "timestamp", ASN1_ERR_WRONG_TYPE);
1071 ret = asn1_uint32_value_decode(&asn1, timestamp_length,
1073 if (ret != ASN1_ERR_NOERROR) {
1074 dissect_snmp_parse_error(pd, offset, fd, tree,
1078 length = asn1.pointer - start;
1080 proto_tree_add_text(snmp_tree, offset, length,
1081 "Timestamp: %u", timestamp);
1087 /* variable bindings */
1088 /* get header for variable-bindings sequence */
1089 ret = asn1_sequence_decode(&asn1, &variable_bindings_length, &length);
1090 if (ret != ASN1_ERR_NOERROR) {
1091 dissect_snmp_parse_error(pd, offset, fd, tree,
1092 "variable bindings header", ret);
1097 /* loop on variable bindings */
1099 while (variable_bindings_length > 0) {
1101 sequence_length = 0;
1104 ret = asn1_sequence_decode(&asn1, &variable_length, &length);
1105 if (ret != ASN1_ERR_NOERROR) {
1106 dissect_snmp_parse_error(pd, offset, fd, tree,
1107 "variable binding header", ret);
1110 sequence_length += length;
1112 /* parse object identifier */
1113 ret = asn1_oid_decode (&asn1, &variable_oid,
1114 &variable_oid_length, &length);
1115 if (ret != ASN1_ERR_NOERROR) {
1116 dissect_snmp_parse_error(pd, offset, fd, tree,
1117 "variable binding OID", ret);
1120 sequence_length += length;
1123 format_oid(oid_string, variable_oid,
1124 variable_oid_length);
1126 #if defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H)
1127 sprint_objid(vb_oid_string, variable_oid,
1128 variable_oid_length);
1129 proto_tree_add_text(snmp_tree, offset, sequence_length,
1130 "Object identifier %d: %s (%s)", vb_index,
1131 oid_string, vb_oid_string);
1134 proto_tree_add_text(snmp_tree, offset, sequence_length,
1135 "Object identifier %d: %s", vb_index,
1139 offset += sequence_length;
1140 variable_bindings_length -= sequence_length;
1142 /* Parse the variable's value */
1143 ret = snmp_variable_decode(snmp_tree, variable_oid,
1144 variable_oid_length, &asn1, offset, &length);
1145 if (ret != ASN1_ERR_NOERROR) {
1146 dissect_snmp_parse_error(pd, offset, fd, tree,
1151 variable_bindings_length -= length;
1156 dissect_snmp(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
1158 dissect_snmp_pdu(pd, offset, fd, tree, "SNMP", proto_snmp, ett_snmp);
1162 proto_register_snmp(void)
1164 /* static hf_register_info hf[] = {
1166 { "Name", "snmp.abbreviation", TYPE, VALS_POINTER }},
1168 static gint *ett[] = {
1172 #if defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H)
1173 /* UCD or CMU SNMP */
1175 #ifdef HAVE_UCD_SNMP_SNMP_H
1176 snmp_set_full_objid(TRUE);
1179 proto_snmp = proto_register_protocol("Simple Network Management Protocol", "snmp");
1180 /* proto_register_field_array(proto_snmp, hf, array_length(hf));*/
1181 proto_register_subtree_array(ett, array_length(ett));
1185 proto_reg_handoff_snmp(void)
1187 dissector_add("udp.port", UDP_PORT_SNMP, dissect_snmp);
1188 dissector_add("udp.port", UDP_PORT_SNMP_TRAP, dissect_snmp);
1189 dissector_add("ethertype", ETHERTYPE_SNMP, dissect_snmp);