2 * Routines for SNMP (simple network management protocol)
5 * $Id: packet-snmp.c,v 1.54 2000/12/24 09:10:12 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 2048 /* TBC */
58 #include "conversation.h"
60 #include "packet-ipx.h"
62 #if defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H)
66 # if defined(HAVE_UCD_SNMP_SNMP_H)
70 # include <ucd-snmp/asn1.h>
71 # include <ucd-snmp/snmp_api.h>
72 # include <ucd-snmp/snmp_impl.h>
73 # include <ucd-snmp/mib.h>
76 * Sigh. UCD SNMP 4.1.1 makes "snmp_set_suffix_only()" a macro
77 * that calls "ds_set_int()" with the first two arguments
78 * being DS_LIBRARY_ID and DS_LIB_PRINT_SUFFIX_ONLY; this means that,
79 * when building with 4.1.1, we need to arrange that
80 * <ucd-snmp/default_store.h> is included, to define those two values
81 * and to declare "ds_int()".
85 * 1) we can't include it on earlier versions (at least not 3.6.2),
86 * as it doesn't exist in those versions;
88 * 2) we don't want to include <ucd-snmp/ucd-snmp-includes.h>,
89 * as that includes <ucd-snmp/snmp.h>, and that defines a whole
90 * bunch of values that we also define ourselves.
92 * So we only include it if "snmp_set_suffix_only" is defined as
95 # ifdef snmp_set_suffix_only
96 # include <ucd-snmp/default_store.h>
100 * XXX - for now, we assume all versions of UCD SNMP have it.
102 # define HAVE_SPRINT_VALUE
105 * Define values "sprint_value()" expects.
107 # define VALTYPE_INTEGER ASN_INTEGER
108 # define VALTYPE_COUNTER ASN_COUNTER
109 # define VALTYPE_GAUGE ASN_GAUGE
110 # define VALTYPE_TIMETICKS ASN_TIMETICKS
111 # define VALTYPE_STRING ASN_OCTET_STR
112 # define VALTYPE_IPADDR ASN_IPADDRESS
113 # define VALTYPE_OPAQUE ASN_OPAQUE
114 # define VALTYPE_NSAP ASN_NSAP
115 # define VALTYPE_OBJECTID ASN_OBJECT_ID
116 # define VALTYPE_BITSTR ASN_BIT_STR
117 # define VALTYPE_COUNTER64 ASN_COUNTER64
118 # elif defined(HAVE_SNMP_SNMP_H)
122 # include <snmp/snmp.h>
125 * Some older versions of CMU SNMP may lack these values (e.g., the
126 * "libsnmp3.6" package for Debian, which is based on some old
127 * CMU SNMP, perhaps 1.0); for now, we assume they also lack
131 # define HAVE_SPRINT_VALUE
133 * Define values "sprint_value()" expects.
135 # define VALTYPE_INTEGER SMI_INTEGER
136 # define VALTYPE_COUNTER SMI_COUNTER32
137 # define VALTYPE_GAUGE SMI_GAUGE32
138 # define VALTYPE_TIMETICKS SMI_TIMETICKS
139 # define VALTYPE_STRING SMI_STRING
140 # define VALTYPE_IPADDR SMI_IPADDRESS
141 # define VALTYPE_OPAQUE SMI_OPAQUE
142 # define VALTYPE_NSAP SMI_STRING
143 # define VALTYPE_OBJECTID SMI_OBJID
144 # define VALTYPE_BITSTR ASN_BIT_STR
145 # define VALTYPE_COUNTER64 SMI_COUNTER64
148 * Now undo all the definitions they "helpfully" gave us, so we don't get
149 * complaints about redefining them.
151 * Why, oh why, is there no library that provides code to
155 * 2) translate object IDs into names;
157 * 3) let you find out, for a given object ID, what the type, enum
158 * values, display hint, etc. are;
160 * in a *simple* fashion, without assuming that your code is part of an
161 * SNMP agent or client that wants a pile of definitions of PDU types,
162 * etc.? Is it just that 99 44/100% of the code that uses an SNMP library
163 * *is* part of an agent or client, and really *does* need that stuff,
164 * and *doesn't* need the interfaces we want?
166 # undef SNMP_ERR_NOERROR
167 # undef SNMP_ERR_TOOBIG
168 # undef SNMP_ERR_NOSUCHNAME
169 # undef SNMP_ERR_BADVALUE
170 # undef SNMP_ERR_READONLY
171 # undef SNMP_ERR_NOACCESS
172 # undef SNMP_ERR_WRONGTYPE
173 # undef SNMP_ERR_WRONGLENGTH
174 # undef SNMP_ERR_WRONGENCODING
175 # undef SNMP_ERR_WRONGVALUE
176 # undef SNMP_ERR_NOCREATION
177 # undef SNMP_ERR_INCONSISTENTVALUE
178 # undef SNMP_ERR_RESOURCEUNAVAILABLE
179 # undef SNMP_ERR_COMMITFAILED
180 # undef SNMP_ERR_UNDOFAILED
181 # undef SNMP_ERR_AUTHORIZATIONERROR
182 # undef SNMP_ERR_NOTWRITABLE
183 # undef SNMP_ERR_INCONSISTENTNAME
184 # undef SNMP_TRAP_COLDSTART
185 # undef SNMP_TRAP_WARMSTART
186 # undef SNMP_TRAP_LINKDOWN
187 # undef SNMP_TRAP_LINKUP
188 # undef SNMP_TRAP_EGPNEIGHBORLOSS
189 # undef SNMP_TRAP_ENTERPRISESPECIFIC
195 #include "packet-snmp.h"
197 /* Null string of type "guchar[]". */
198 static const guchar nullstring[] = "";
200 /* Take a pointer that may be null and return a pointer that's not null
201 by turning null pointers into pointers to the above null string. */
202 #define SAFE_STRING(s) (((s) != NULL) ? (s) : nullstring)
204 static int proto_snmp = -1;
205 static int proto_smux = -1;
207 static gint ett_snmp = -1;
208 static gint ett_smux = -1;
209 static gint ett_global = -1;
210 static gint ett_flags = -1;
211 static gint ett_secur = -1;
213 static int hf_snmpv3_flags = -1;
214 static int hf_snmpv3_flags_auth = -1;
215 static int hf_snmpv3_flags_crypt = -1;
216 static int hf_snmpv3_flags_report = -1;
219 #define TH_CRYPT 0x02
220 #define TH_REPORT 0x04
222 static const true_false_string flags_set_truth = {
227 #define UDP_PORT_SNMP 161
228 #define UDP_PORT_SNMP_TRAP 162
229 #define TCP_PORT_SMUX 199
231 /* Protocol version numbers */
232 #define SNMP_VERSION_1 0
233 #define SNMP_VERSION_2c 1
234 #define SNMP_VERSION_2u 2
235 #define SNMP_VERSION_3 3
237 static const value_string versions[] = {
238 { SNMP_VERSION_1, "1" },
239 { SNMP_VERSION_2c, "2C" },
240 { SNMP_VERSION_2u, "2U" },
241 { SNMP_VERSION_3, "3" },
246 #define SNMP_MSG_GET 0
247 #define SNMP_MSG_GETNEXT 1
248 #define SNMP_MSG_RESPONSE 2
249 #define SNMP_MSG_SET 3
250 #define SNMP_MSG_TRAP 4
252 #define SNMP_MSG_GETBULK 5
253 #define SNMP_MSG_INFORM 6
254 #define SNMP_MSG_TRAP2 7
255 #define SNMP_MSG_REPORT 8
257 static const value_string pdu_types[] = {
258 { SNMP_MSG_GET, "GET" },
259 { SNMP_MSG_GETNEXT, "GET-NEXT" },
260 { SNMP_MSG_SET, "SET" },
261 { SNMP_MSG_RESPONSE, "RESPONSE" },
262 { SNMP_MSG_TRAP, "TRAP-V1" },
263 { SNMP_MSG_GETBULK, "GETBULK" },
264 { SNMP_MSG_INFORM, "INFORM" },
265 { SNMP_MSG_TRAP2, "TRAP-V2" },
266 { SNMP_MSG_REPORT, "REPORT" },
271 #define SMUX_MSG_OPEN 0
272 #define SMUX_MSG_CLOSE 1
273 #define SMUX_MSG_RREQ 2
274 #define SMUX_MSG_RRSP 3
275 #define SMUX_MSG_SOUT 4
277 static const value_string smux_types[] = {
278 { SMUX_MSG_OPEN, "Open" },
279 { SMUX_MSG_CLOSE, "Close" },
280 { SMUX_MSG_RREQ, "Registration Request" },
281 { SMUX_MSG_RRSP, "Registration Response" },
282 { SMUX_MSG_SOUT, "Commit Or Rollback" },
286 /* SMUX Closing causes */
287 #define SMUX_CLOSE_DOWN 0
288 #define SMUX_CLOSE_VERSION 1
289 #define SMUX_CLOSE_PACKET 2
290 #define SMUX_CLOSE_PROTOCOL 3
291 #define SMUX_CLOSE_INTERNAL 4
292 #define SMUX_CLOSE_NOAUTH 5
294 static const value_string smux_close[] = {
295 { SMUX_CLOSE_DOWN, "Going down" },
296 { SMUX_CLOSE_VERSION, "Unsupported Version" },
297 { SMUX_CLOSE_PACKET, "Packet Format Error" },
298 { SMUX_CLOSE_PROTOCOL, "Protocol Error" },
299 { SMUX_CLOSE_INTERNAL, "Internal Error" },
300 { SMUX_CLOSE_NOAUTH, "Unauthorized" },
304 /* SMUX Request codes */
305 #define SMUX_RREQ_DELETE 0
306 #define SMUX_RREQ_READONLY 1
307 #define SMUX_RREQ_READWRITE 2
309 static const value_string smux_rreq[] = {
310 { SMUX_RREQ_DELETE, "Delete" },
311 { SMUX_RREQ_READONLY, "Read Only" },
312 { SMUX_RREQ_READWRITE, "Read Write" },
316 static const value_string smux_prio[] = {
321 /* SMUX SOut codes */
322 #define SMUX_SOUT_COMMIT 0
323 #define SMUX_SOUT_ROLLBACK 1
325 static const value_string smux_sout[] = {
326 { SMUX_SOUT_COMMIT, "Commit" },
327 { SMUX_SOUT_ROLLBACK, "Rollback" }
330 /* Error status values */
331 #define SNMP_ERR_NOERROR 0
332 #define SNMP_ERR_TOOBIG 1
333 #define SNMP_ERR_NOSUCHNAME 2
334 #define SNMP_ERR_BADVALUE 3
335 #define SNMP_ERR_READONLY 4
336 #define SNMP_ERR_GENERROR 5
338 #define SNMP_ERR_NOACCESS 6
339 #define SNMP_ERR_WRONGTYPE 7
340 #define SNMP_ERR_WRONGLENGTH 8
341 #define SNMP_ERR_WRONGENCODING 9
342 #define SNMP_ERR_WRONGVALUE 10
343 #define SNMP_ERR_NOCREATION 11
344 #define SNMP_ERR_INCONSISTENTVALUE 12
345 #define SNMP_ERR_RESOURCEUNAVAILABLE 13
346 #define SNMP_ERR_COMMITFAILED 14
347 #define SNMP_ERR_UNDOFAILED 15
348 #define SNMP_ERR_AUTHORIZATIONERROR 16
349 #define SNMP_ERR_NOTWRITABLE 17
350 #define SNMP_ERR_INCONSISTENTNAME 18
352 static const value_string error_statuses[] = {
353 { SNMP_ERR_NOERROR, "NO ERROR" },
354 { SNMP_ERR_TOOBIG, "TOOBIG" },
355 { SNMP_ERR_NOSUCHNAME, "NO SUCH NAME" },
356 { SNMP_ERR_BADVALUE, "BAD VALUE" },
357 { SNMP_ERR_READONLY, "READ ONLY" },
358 { SNMP_ERR_GENERROR, "GENERIC ERROR" },
359 { SNMP_ERR_NOACCESS, "NO ACCESS" },
360 { SNMP_ERR_WRONGTYPE, "WRONG TYPE" },
361 { SNMP_ERR_WRONGLENGTH, "WRONG LENGTH" },
362 { SNMP_ERR_WRONGENCODING, "WRONG ENCODING" },
363 { SNMP_ERR_WRONGVALUE, "WRONG VALUE" },
364 { SNMP_ERR_NOCREATION, "NO CREATION" },
365 { SNMP_ERR_INCONSISTENTVALUE, "INCONSISTENT VALUE" },
366 { SNMP_ERR_RESOURCEUNAVAILABLE, "RESOURCE UNAVAILABLE" },
367 { SNMP_ERR_COMMITFAILED, "COMMIT FAILED" },
368 { SNMP_ERR_UNDOFAILED, "UNDO FAILED" },
369 { SNMP_ERR_AUTHORIZATIONERROR, "AUTHORIZATION ERROR" },
370 { SNMP_ERR_NOTWRITABLE, "NOT WRITABLE" },
371 { SNMP_ERR_INCONSISTENTNAME, "INCONSISTENT NAME" },
375 /* General SNMP V1 Traps */
377 #define SNMP_TRAP_COLDSTART 0
378 #define SNMP_TRAP_WARMSTART 1
379 #define SNMP_TRAP_LINKDOWN 2
380 #define SNMP_TRAP_LINKUP 3
381 #define SNMP_TRAP_AUTHFAIL 4
382 #define SNMP_TRAP_EGPNEIGHBORLOSS 5
383 #define SNMP_TRAP_ENTERPRISESPECIFIC 6
385 static const value_string trap_types[] = {
386 { SNMP_TRAP_COLDSTART, "COLD START" },
387 { SNMP_TRAP_WARMSTART, "WARM START" },
388 { SNMP_TRAP_LINKDOWN, "LINK DOWN" },
389 { SNMP_TRAP_LINKUP, "LINK UP" },
390 { SNMP_TRAP_AUTHFAIL, "AUTHENTICATION FAILED" },
391 { SNMP_TRAP_EGPNEIGHBORLOSS, "EGP NEIGHBORLOSS" },
392 { SNMP_TRAP_ENTERPRISESPECIFIC, "ENTERPRISE SPECIFIC" },
396 /* Security Models */
398 #define SNMP_SEC_ANY 0
399 #define SNMP_SEC_V1 1
400 #define SNMP_SEC_V2C 2
401 #define SNMP_SEC_USM 3
403 static const value_string sec_models[] = {
404 { SNMP_SEC_ANY, "Any" },
405 { SNMP_SEC_V1, "V1" },
406 { SNMP_SEC_V2C, "V2C" },
407 { SNMP_SEC_USM, "USM" },
413 #define SNMP_IPA 0 /* IP Address */
414 #define SNMP_CNT 1 /* Counter (Counter32) */
415 #define SNMP_GGE 2 /* Gauge (Gauge32) */
416 #define SNMP_TIT 3 /* TimeTicks */
417 #define SNMP_OPQ 4 /* Opaque */
418 #define SNMP_NSP 5 /* NsapAddress */
419 #define SNMP_C64 6 /* Counter64 */
420 #define SNMP_U32 7 /* Uinteger32 */
429 #define SNMP_INTEGER 1 /* l */
430 #define SNMP_OCTETSTR 2 /* c */
431 #define SNMP_DISPLAYSTR 2 /* c */
432 #define SNMP_OBJECTID 3 /* ul */
433 #define SNMP_IPADDR 4 /* uc */
434 #define SNMP_COUNTER 5 /* ul */
435 #define SNMP_GAUGE 6 /* ul */
436 #define SNMP_TIMETICKS 7 /* ul */
437 #define SNMP_OPAQUE 8 /* c */
439 /* additional SNMPv2 Types */
441 #define SNMP_UINTEGER 5 /* ul */
442 #define SNMP_BITSTR 9 /* uc */
443 #define SNMP_NSAP 10 /* uc */
444 #define SNMP_COUNTER64 11 /* ul */
445 #define SNMP_NOSUCHOBJECT 12
446 #define SNMP_NOSUCHINSTANCE 13
447 #define SNMP_ENDOFMIBVIEW 14
449 typedef struct _SNMP_CNV SNMP_CNV;
459 static SNMP_CNV SnmpCnv [] =
461 {ASN1_UNI, ASN1_NUL, SNMP_NULL, "NULL"},
462 {ASN1_UNI, ASN1_INT, SNMP_INTEGER, "INTEGER"},
463 {ASN1_UNI, ASN1_OTS, SNMP_OCTETSTR, "OCTET STRING"},
464 {ASN1_UNI, ASN1_OJI, SNMP_OBJECTID, "OBJECTID"},
465 {ASN1_APL, SNMP_IPA, SNMP_IPADDR, "IPADDR"},
466 {ASN1_APL, SNMP_CNT, SNMP_COUNTER, "COUNTER"}, /* Counter32 */
467 {ASN1_APL, SNMP_GGE, SNMP_GAUGE, "GAUGE"}, /* Gauge32 == Unsigned32 */
468 {ASN1_APL, SNMP_TIT, SNMP_TIMETICKS, "TIMETICKS"},
469 {ASN1_APL, SNMP_OPQ, SNMP_OPAQUE, "OPAQUE"},
471 /* SNMPv2 data types and errors */
473 {ASN1_UNI, ASN1_BTS, SNMP_BITSTR, "BITSTR"},
474 {ASN1_APL, SNMP_C64, SNMP_COUNTER64, "COUNTER64"},
475 {ASN1_CTX, SERR_NSO, SNMP_NOSUCHOBJECT, "NOSUCHOBJECT"},
476 {ASN1_CTX, SERR_NSI, SNMP_NOSUCHINSTANCE, "NOSUCHINSTANCE"},
477 {ASN1_CTX, SERR_EOM, SNMP_ENDOFMIBVIEW, "ENDOFMIBVIEW"},
482 * NAME: g_snmp_tag_cls2syntax
483 * SYNOPSIS: gboolean g_snmp_tag_cls2syntax
489 * DESCRIPTION: Converts ASN1 tag and class to Syntax tag and name.
490 * See SnmpCnv for conversion.
491 * RETURNS: name on success, NULL on failure
495 snmp_tag_cls2syntax ( guint tag, guint cls, gushort *syntax)
500 while (cnv->syntax != -1)
502 if (cnv->tag == tag && cnv->class == cls)
504 *syntax = cnv->syntax;
513 dissect_snmp_parse_error(const u_char *pd, int offset, frame_data *fd,
514 proto_tree *tree, const char *field_name, int ret)
518 if (check_col(fd, COL_INFO)) {
522 errstr = "Ran out of data";
525 case ASN1_ERR_EOC_MISMATCH:
526 errstr = "EOC mismatch";
529 case ASN1_ERR_WRONG_TYPE:
530 errstr = "Wrong type for that item";
533 case ASN1_ERR_LENGTH_NOT_DEFINITE:
534 errstr = "Length was indefinite";
537 case ASN1_ERR_LENGTH_MISMATCH:
538 errstr = "Length mismatch";
541 case ASN1_ERR_WRONG_LENGTH_FOR_TYPE:
542 errstr = "Wrong length for that item's type";
546 errstr = "Unknown error";
549 col_add_fstr(fd, COL_INFO,
550 "ERROR: Couldn't parse %s: %s", field_name, errstr);
553 old_dissect_data(pd, offset, fd, tree);
557 dissect_snmp_error(const u_char *pd, int offset, frame_data *fd,
558 proto_tree *tree, const char *message)
560 if (check_col(fd, COL_INFO))
561 col_add_str(fd, COL_INFO, message);
563 old_dissect_data(pd, offset, fd, tree);
567 format_oid(subid_t *oid, guint oid_length)
574 result_len = oid_length * 22;
575 result = g_malloc(result_len + 1);
577 len = sprintf(buf, "%lu", (unsigned long)oid[0]);
579 for (i = 1; i < oid_length;i++) {
580 len = sprintf(buf, ".%lu", (unsigned long)oid[i]);
586 #ifdef HAVE_SPRINT_VALUE
588 format_var(struct variable_list *variable, subid_t *variable_oid,
589 guint variable_oid_length, gushort vb_type, guint vb_length)
599 /* We don't know how long this will be, but let's guess it
600 fits within 128 characters; that should be enough for an
601 integral value plus some sort of type indication. */
611 /* We don't know how long this will be, but let's guess it
612 fits within 128 characters plus 4 characters per octet. */
613 buf = g_malloc(128 + 4*vb_length);
617 /* We don't know how long this will be, but let's guess it
618 fits within 128 characters plus 32 characters per subid
619 (10 digits plus period, or a subid name). */
620 buf = g_malloc(1024 + 32*vb_length);
624 /* Should not happen. */
625 g_assert_not_reached();
630 variable->next_variable = NULL;
631 variable->name = variable_oid;
632 variable->name_length = variable_oid_length;
636 variable->type = VALTYPE_INTEGER;
640 variable->type = VALTYPE_COUNTER;
644 variable->type = VALTYPE_GAUGE;
648 variable->type = VALTYPE_TIMETICKS;
652 variable->type = VALTYPE_STRING;
656 variable->type = VALTYPE_IPADDR;
660 variable->type = VALTYPE_OPAQUE;
664 variable->type = VALTYPE_NSAP;
668 variable->type = VALTYPE_OBJECTID;
669 vb_length *= sizeof (subid_t); /* XXX - necessary? */
673 variable->type = VALTYPE_BITSTR;
677 variable->type = VALTYPE_COUNTER64;
680 variable->val_len = vb_length;
682 sprint_value(buf, variable_oid, variable_oid_length, variable);
688 snmp_variable_decode(proto_tree *snmp_tree, subid_t *variable_oid,
689 guint variable_oid_length, ASN1_SCK *asn1, int offset, guint *lengthp)
700 gint32 vb_integer_value;
701 guint32 vb_uinteger_value;
703 guint8 *vb_octet_string;
708 gchar *vb_display_string;
710 #ifdef HAVE_SPRINT_VALUE
711 struct variable_list variable;
712 #if defined(HAVE_UCD_SNMP_SNMP_H)
715 #else /* HAVE_SPRINT_VALUE */
719 #endif /* HAVE_SPRINT_VALUE */
721 /* parse the type of the object */
722 start = asn1->pointer;
723 ret = asn1_header_decode (asn1, &cls, &con, &tag, &def, &vb_length);
724 if (ret != ASN1_ERR_NOERROR)
727 return ASN1_ERR_LENGTH_NOT_DEFINITE;
729 /* Convert the class, constructed flag, and tag to a type. */
730 vb_type_name = snmp_tag_cls2syntax(tag, cls, &vb_type);
731 if (vb_type_name == NULL) {
734 * Dissect the value as an opaque string of octets.
736 vb_type_name = "unsupported type";
737 vb_type = SNMP_OPAQUE;
740 /* parse the value */
744 ret = asn1_int32_value_decode(asn1, vb_length,
746 if (ret != ASN1_ERR_NOERROR)
748 length = asn1->pointer - start;
750 #ifdef HAVE_SPRINT_VALUE
751 #if defined(HAVE_UCD_SNMP_SNMP_H)
752 value = vb_integer_value;
753 variable.val.integer = &value;
754 #elif defined(HAVE_SNMP_SNMP_H)
755 variable.val.integer = &vb_integer_value;
757 vb_display_string = format_var(&variable,
758 variable_oid, variable_oid_length, vb_type,
760 proto_tree_add_text(snmp_tree, NullTVB, offset, length,
761 "Value: %s", vb_display_string);
762 g_free(vb_display_string);
764 proto_tree_add_text(snmp_tree, NullTVB, offset, length,
765 "Value: %s: %d (%#x)", vb_type_name,
766 vb_integer_value, vb_integer_value);
774 ret = asn1_uint32_value_decode(asn1, vb_length,
776 if (ret != ASN1_ERR_NOERROR)
778 length = asn1->pointer - start;
780 #ifdef HAVE_SPRINT_VALUE
781 #if defined(HAVE_UCD_SNMP_SNMP_H)
782 value = vb_uinteger_value;
783 variable.val.integer = &value;
784 #elif defined(HAVE_SNMP_SNMP_H)
785 variable.val.integer = &vb_uinteger_value;
787 vb_display_string = format_var(&variable,
788 variable_oid, variable_oid_length, vb_type,
790 proto_tree_add_text(snmp_tree, NullTVB, offset, length,
791 "Value: %s", vb_display_string);
792 g_free(vb_display_string);
794 proto_tree_add_text(snmp_tree, NullTVB, offset, length,
795 "Value: %s: %u (%#x)", vb_type_name,
796 vb_uinteger_value, vb_uinteger_value);
807 ret = asn1_string_value_decode (asn1, vb_length,
809 if (ret != ASN1_ERR_NOERROR)
811 length = asn1->pointer - start;
813 #ifdef HAVE_SPRINT_VALUE
814 variable.val.string = vb_octet_string;
815 vb_display_string = format_var(&variable,
816 variable_oid, variable_oid_length, vb_type,
818 proto_tree_add_text(snmp_tree, NullTVB, offset, length,
819 "Value: %s", vb_display_string);
820 g_free(vb_display_string);
823 * If some characters are not printable, display
824 * the string as bytes.
826 for (i = 0; i < vb_length; i++) {
827 if (!(isprint(vb_octet_string[i])
828 || isspace(vb_octet_string[i])))
833 * We stopped, due to a non-printable
834 * character, before we got to the end
837 vb_display_string = g_malloc(4*vb_length);
838 buf = &vb_display_string[0];
839 len = sprintf(buf, "%03u", vb_octet_string[0]);
841 for (i = 1; i < vb_length; i++) {
842 len = sprintf(buf, ".%03u",
846 proto_tree_add_text(snmp_tree, NullTVB, offset, length,
847 "Value: %s: %s", vb_type_name,
849 g_free(vb_display_string);
851 proto_tree_add_text(snmp_tree, NullTVB, offset, length,
852 "Value: %s: %.*s", vb_type_name,
853 (int)vb_length, vb_octet_string);
857 g_free(vb_octet_string);
861 ret = asn1_null_decode (asn1, vb_length);
862 if (ret != ASN1_ERR_NOERROR)
864 length = asn1->pointer - start;
866 proto_tree_add_text(snmp_tree, NullTVB, offset, length,
867 "Value: %s", vb_type_name);
872 ret = asn1_oid_value_decode (asn1, vb_length, &vb_oid,
874 if (ret != ASN1_ERR_NOERROR)
876 length = asn1->pointer - start;
878 #ifdef HAVE_SPRINT_VALUE
879 variable.val.objid = vb_oid;
880 vb_display_string = format_var(&variable,
881 variable_oid, variable_oid_length, vb_type,
883 proto_tree_add_text(snmp_tree, NullTVB, offset, length,
884 "Value: %s", vb_display_string);
886 vb_display_string = format_oid(vb_oid, vb_oid_length);
887 proto_tree_add_text(snmp_tree, NullTVB, offset, length,
888 "Value: %s: %s", vb_type_name, vb_display_string);
890 g_free(vb_display_string);
895 case SNMP_NOSUCHOBJECT:
896 length = asn1->pointer - start;
898 proto_tree_add_text(snmp_tree, NullTVB, offset, length,
899 "Value: %s: no such object", vb_type_name);
903 case SNMP_NOSUCHINSTANCE:
904 length = asn1->pointer - start;
906 proto_tree_add_text(snmp_tree, NullTVB, offset, length,
907 "Value: %s: no such instance", vb_type_name);
911 case SNMP_ENDOFMIBVIEW:
912 length = asn1->pointer - start;
914 proto_tree_add_text(snmp_tree, NullTVB, offset, length,
915 "Value: %s: end of mib view", vb_type_name);
920 g_assert_not_reached();
921 return ASN1_ERR_WRONG_TYPE;
924 return ASN1_ERR_NOERROR;
928 dissect_common_pdu(const u_char *pd, int offset, frame_data *fd,
929 proto_tree *tree, ASN1_SCK asn1, guint pdu_type, const guchar *start)
933 guint sequence_length;
937 guint32 error_status;
941 char *pdu_type_string;
944 guint enterprise_length;
946 guint8 *agent_address;
947 guint agent_address_length;
951 guint32 specific_type;
954 guint timestamp_length;
958 guint variable_bindings_length;
961 guint variable_length;
962 subid_t *variable_oid;
963 guint variable_oid_length;
964 #if defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H)
965 gchar vb_oid_string[MAX_STRING_LEN]; /* TBC */
971 pdu_type_string = val_to_str(pdu_type, pdu_types,
972 "Unknown PDU type %#x");
973 if (check_col(fd, COL_INFO))
974 col_add_str(fd, COL_INFO, pdu_type_string);
975 length = asn1.pointer - start;
977 proto_tree_add_text(tree, NullTVB, offset, length,
978 "PDU type: %s", pdu_type_string);
982 /* get the fields in the PDU preceeding the variable-bindings sequence */
986 case SNMP_MSG_GETNEXT:
987 case SNMP_MSG_RESPONSE:
989 case SNMP_MSG_GETBULK:
990 case SNMP_MSG_INFORM:
992 case SNMP_MSG_REPORT:
994 ret = asn1_uint32_decode (&asn1, &request_id, &length);
995 if (ret != ASN1_ERR_NOERROR) {
996 dissect_snmp_parse_error(pd, offset, fd, tree,
1001 proto_tree_add_text(tree, NullTVB, offset, length,
1002 "Request Id: %#x", request_id);
1006 /* error status, or getbulk non-repeaters */
1007 ret = asn1_uint32_decode (&asn1, &error_status, &length);
1008 if (ret != ASN1_ERR_NOERROR) {
1009 dissect_snmp_parse_error(pd, offset, fd, tree,
1010 (pdu_type == SNMP_MSG_GETBULK) ? "non-repeaters"
1016 if (pdu_type == SNMP_MSG_GETBULK) {
1017 proto_tree_add_text(tree, NullTVB, offset,
1018 length, "Non-repeaters: %u", error_status);
1020 proto_tree_add_text(tree, NullTVB, offset,
1021 length, "Error Status: %s",
1022 val_to_str(error_status, error_statuses,
1028 /* error index, or getbulk max-repetitions */
1029 ret = asn1_uint32_decode (&asn1, &error_index, &length);
1030 if (ret != ASN1_ERR_NOERROR) {
1031 dissect_snmp_parse_error(pd, offset, fd, tree,
1032 (pdu_type == SNMP_MSG_GETBULK) ? "max repetitions"
1038 if (pdu_type == SNMP_MSG_GETBULK) {
1039 proto_tree_add_text(tree, NullTVB, offset,
1040 length, "Max repetitions: %u", error_index);
1042 proto_tree_add_text(tree, NullTVB, offset,
1043 length, "Error Index: %u", error_index);
1051 ret = asn1_oid_decode (&asn1, &enterprise, &enterprise_length,
1053 if (ret != ASN1_ERR_NOERROR) {
1054 dissect_snmp_parse_error(pd, offset, fd, tree,
1055 "enterprise OID", ret);
1059 oid_string = format_oid(enterprise, enterprise_length);
1060 proto_tree_add_text(tree, NullTVB, offset, length,
1061 "Enterprise: %s", oid_string);
1068 start = asn1.pointer;
1069 ret = asn1_header_decode (&asn1, &cls, &con, &tag,
1070 &def, &agent_address_length);
1071 if (ret != ASN1_ERR_NOERROR) {
1072 dissect_snmp_parse_error(pd, offset, fd, tree,
1073 "agent address", ret);
1076 if (!((cls == ASN1_APL && con == ASN1_PRI && tag == SNMP_IPA) ||
1077 (cls == ASN1_UNI && con == ASN1_PRI && tag == ASN1_OTS))) {
1078 /* GXSNMP 0.0.15 says the latter is "needed for
1080 dissect_snmp_parse_error(pd, offset, fd, tree,
1081 "agent_address", ASN1_ERR_WRONG_TYPE);
1084 if (agent_address_length != 4) {
1085 dissect_snmp_parse_error(pd, offset, fd, tree,
1086 "agent_address", ASN1_ERR_WRONG_LENGTH_FOR_TYPE);
1089 ret = asn1_string_value_decode (&asn1,
1090 agent_address_length, &agent_address);
1091 if (ret != ASN1_ERR_NOERROR) {
1092 dissect_snmp_parse_error(pd, offset, fd, tree,
1093 "agent address", ret);
1096 length = asn1.pointer - start;
1098 proto_tree_add_text(tree, NullTVB, offset, length,
1099 "Agent address: %s", ip_to_str(agent_address));
1101 g_free(agent_address);
1104 /* generic trap type */
1105 ret = asn1_uint32_decode (&asn1, &trap_type, &length);
1106 if (ret != ASN1_ERR_NOERROR) {
1107 dissect_snmp_parse_error(pd, offset, fd, tree,
1108 "generic trap type", ret);
1112 proto_tree_add_text(tree, NullTVB, offset, length,
1114 val_to_str(trap_type, trap_types, "Unknown (%u)"));
1118 /* specific trap type */
1119 ret = asn1_uint32_decode (&asn1, &specific_type, &length);
1120 if (ret != ASN1_ERR_NOERROR) {
1121 dissect_snmp_parse_error(pd, offset, fd, tree,
1122 "specific trap type", ret);
1126 proto_tree_add_text(tree, NullTVB, offset, length,
1127 "Specific trap type: %u (%#x)",
1128 specific_type, specific_type);
1133 start = asn1.pointer;
1134 ret = asn1_header_decode (&asn1, &cls, &con, &tag,
1135 &def, ×tamp_length);
1136 if (ret != ASN1_ERR_NOERROR) {
1137 dissect_snmp_parse_error(pd, offset, fd, tree,
1141 if (!((cls == ASN1_APL && con == ASN1_PRI && tag == SNMP_TIT) ||
1142 (cls == ASN1_UNI && con == ASN1_PRI && tag == ASN1_INT))) {
1143 dissect_snmp_parse_error(pd, offset, fd, tree,
1144 "timestamp", ASN1_ERR_WRONG_TYPE);
1147 ret = asn1_uint32_value_decode(&asn1, timestamp_length,
1149 if (ret != ASN1_ERR_NOERROR) {
1150 dissect_snmp_parse_error(pd, offset, fd, tree,
1154 length = asn1.pointer - start;
1156 proto_tree_add_text(tree, NullTVB, offset, length,
1157 "Timestamp: %u", timestamp);
1163 /* variable bindings */
1164 /* get header for variable-bindings sequence */
1165 ret = asn1_sequence_decode(&asn1, &variable_bindings_length, &length);
1166 if (ret != ASN1_ERR_NOERROR) {
1167 dissect_snmp_parse_error(pd, offset, fd, tree,
1168 "variable bindings header", ret);
1173 /* loop on variable bindings */
1175 while (variable_bindings_length > 0) {
1177 sequence_length = 0;
1180 ret = asn1_sequence_decode(&asn1, &variable_length, &length);
1181 if (ret != ASN1_ERR_NOERROR) {
1182 dissect_snmp_parse_error(pd, offset, fd, tree,
1183 "variable binding header", ret);
1186 sequence_length += length;
1188 /* parse object identifier */
1189 ret = asn1_oid_decode (&asn1, &variable_oid,
1190 &variable_oid_length, &length);
1191 if (ret != ASN1_ERR_NOERROR) {
1192 dissect_snmp_parse_error(pd, offset, fd, tree,
1193 "variable binding OID", ret);
1196 sequence_length += length;
1199 oid_string = format_oid(variable_oid,
1200 variable_oid_length);
1202 #if defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H)
1203 sprint_objid(vb_oid_string, variable_oid,
1204 variable_oid_length);
1205 proto_tree_add_text(tree, NullTVB, offset, sequence_length,
1206 "Object identifier %d: %s (%s)", vb_index,
1207 oid_string, vb_oid_string);
1210 proto_tree_add_text(tree, NullTVB, offset, sequence_length,
1211 "Object identifier %d: %s", vb_index,
1216 offset += sequence_length;
1217 variable_bindings_length -= sequence_length;
1219 /* Parse the variable's value */
1220 ret = snmp_variable_decode(tree, variable_oid,
1221 variable_oid_length, &asn1, offset, &length);
1222 if (ret != ASN1_ERR_NOERROR) {
1223 dissect_snmp_parse_error(pd, offset, fd, tree,
1228 variable_bindings_length -= length;
1233 dissect_snmp_pdu(const u_char *pd, int offset, frame_data *fd,
1234 proto_tree *tree, char *proto_name, int proto, gint ett)
1237 const guchar *start;
1241 guint message_length;
1242 guint global_length;
1248 guint32 engineboots;
1261 int msgflags_length;
1262 int community_length;
1264 int cengineid_length;
1266 int cryptpdu_length;
1267 int aengineid_length;
1268 int username_length;
1275 proto_tree *snmp_tree = NULL;
1276 proto_tree *global_tree = NULL;
1277 proto_tree *flags_tree = NULL;
1278 proto_tree *secur_tree = NULL;
1279 proto_item *item = NULL;
1281 guint cls, con, tag;
1283 if (check_col(fd, COL_PROTOCOL))
1284 col_add_str(fd, COL_PROTOCOL, proto_name);
1287 item = proto_tree_add_item(tree, proto, NullTVB, offset,
1288 END_OF_FRAME, FALSE);
1289 snmp_tree = proto_item_add_subtree(item, ett);
1292 /* NOTE: we have to parse the message piece by piece, since the
1293 * capture length may be less than the message length: a 'global'
1294 * parsing is likely to fail.
1296 /* parse the SNMP header */
1297 asn1_open(&asn1, &pd[offset], END_OF_FRAME);
1298 ret = asn1_sequence_decode(&asn1, &message_length, &length);
1299 if (ret != ASN1_ERR_NOERROR) {
1300 dissect_snmp_parse_error(pd, offset, fd, tree,
1301 "message header", ret);
1306 ret = asn1_uint32_decode (&asn1, &version, &length);
1307 if (ret != ASN1_ERR_NOERROR) {
1308 dissect_snmp_parse_error(pd, offset, fd, tree, "version number",
1313 proto_tree_add_text(snmp_tree, NullTVB, offset, length,
1315 val_to_str(version, versions, "Unknown version %#x"));
1321 case SNMP_VERSION_1:
1322 case SNMP_VERSION_2c:
1323 ret = asn1_octet_string_decode (&asn1, &community,
1324 &community_length, &length);
1325 if (ret != ASN1_ERR_NOERROR) {
1326 dissect_snmp_parse_error(pd, offset, fd, tree,
1331 proto_tree_add_text(snmp_tree, NullTVB, offset, length,
1332 "Community: %.*s", community_length,
1333 SAFE_STRING(community));
1338 case SNMP_VERSION_2u:
1341 case SNMP_VERSION_3:
1342 ret = asn1_sequence_decode(&asn1, &global_length, &length);
1343 if (ret != ASN1_ERR_NOERROR) {
1344 dissect_snmp_parse_error(pd, offset, fd, tree,
1345 "message global header", ret);
1349 item = proto_tree_add_text(snmp_tree, NullTVB, offset,
1350 global_length + length, "Message Global Header");
1351 global_tree = proto_item_add_subtree(item, ett_global);
1352 proto_tree_add_text(global_tree, NullTVB, offset,
1354 "Message Global Header Length: %d", global_length);
1357 ret = asn1_uint32_decode (&asn1, &msgid, &length);
1358 if (ret != ASN1_ERR_NOERROR) {
1359 dissect_snmp_parse_error(pd, offset, fd, tree,
1364 proto_tree_add_text(global_tree, NullTVB, offset,
1365 length, "Message ID: %d", msgid);
1368 ret = asn1_uint32_decode (&asn1, &msgmax, &length);
1369 if (ret != ASN1_ERR_NOERROR) {
1370 dissect_snmp_parse_error(pd, offset, fd, tree,
1371 "message max size", ret);
1375 proto_tree_add_text(global_tree, NullTVB, offset,
1376 length, "Message Max Size: %d", msgmax);
1379 ret = asn1_octet_string_decode (&asn1, &msgflags,
1380 &msgflags_length, &length);
1381 if (ret != ASN1_ERR_NOERROR) {
1382 dissect_snmp_parse_error(pd, offset, fd, tree,
1383 "message flags", ret);
1386 if (msgflags_length != 1) {
1387 dissect_snmp_parse_error(pd, offset, fd, tree,
1388 "message flags wrong length", ret);
1393 item = proto_tree_add_uint_format(global_tree,
1394 hf_snmpv3_flags, NullTVB, offset, length,
1395 msgflags[0], "Flags: 0x%02x", msgflags[0]);
1396 flags_tree = proto_item_add_subtree(item, ett_flags);
1397 proto_tree_add_boolean(flags_tree, hf_snmpv3_flags_report,
1398 NullTVB, offset, length, msgflags[0]);
1399 proto_tree_add_boolean(flags_tree, hf_snmpv3_flags_crypt,
1400 NullTVB, offset, length, msgflags[0]);
1401 proto_tree_add_boolean(flags_tree, hf_snmpv3_flags_auth,
1402 NullTVB, offset, length, msgflags[0]);
1404 encrypted = msgflags[0] & TH_CRYPT;
1407 ret = asn1_uint32_decode (&asn1, &msgsec, &length);
1408 if (ret != ASN1_ERR_NOERROR) {
1409 dissect_snmp_parse_error(pd, offset, fd, tree,
1410 "message security model", ret);
1414 proto_tree_add_text(global_tree, NullTVB, offset,
1415 length, "Message Security Model: %s",
1416 val_to_str(msgsec, sec_models,
1417 "Unknown model %#x"));
1422 start = asn1.pointer;
1423 ret = asn1_header_decode (&asn1, &cls, &con, &tag,
1424 &def, &secparm_length);
1425 length = asn1.pointer - start;
1426 if (cls != ASN1_UNI && con != ASN1_PRI &&
1428 dissect_snmp_parse_error(pd, offset, fd, tree,
1429 "Message Security Parameters",
1430 ASN1_ERR_WRONG_TYPE);
1434 item = proto_tree_add_text(snmp_tree, NullTVB,
1435 offset, secparm_length + length,
1436 "Message Security Parameters");
1437 secur_tree = proto_item_add_subtree(item,
1439 proto_tree_add_text(secur_tree, NullTVB, offset,
1441 "Message Security Parameters Length: %d",
1445 ret = asn1_sequence_decode(&asn1, &secparm_length,
1447 if (ret != ASN1_ERR_NOERROR) {
1448 dissect_snmp_parse_error(pd, offset, fd, tree,
1449 "USM sequence header", ret);
1453 ret = asn1_octet_string_decode (&asn1, &aengineid,
1454 &aengineid_length, &length);
1455 if (ret != ASN1_ERR_NOERROR) {
1456 dissect_snmp_parse_error(pd, offset, fd, tree,
1457 "authoritative engine id", ret);
1461 proto_tree_add_text(secur_tree, NullTVB, offset,
1462 length, "Authoritative Engine ID: %s",
1463 bytes_to_str(aengineid, aengineid_length));
1467 ret = asn1_uint32_decode (&asn1, &engineboots, &length);
1468 if (ret != ASN1_ERR_NOERROR) {
1469 dissect_snmp_parse_error(pd, offset, fd, tree,
1470 "engine boots", ret);
1474 proto_tree_add_text(secur_tree, NullTVB,
1475 offset, length, "Engine Boots: %d",
1479 ret = asn1_uint32_decode (&asn1, &enginetime, &length);
1480 if (ret != ASN1_ERR_NOERROR) {
1481 dissect_snmp_parse_error(pd, offset, fd, tree,
1482 "engine time", ret);
1486 proto_tree_add_text(secur_tree, NullTVB,
1487 offset, length, "Engine Time: %d",
1491 ret = asn1_octet_string_decode (&asn1, &username,
1492 &username_length, &length);
1493 if (ret != ASN1_ERR_NOERROR) {
1494 dissect_snmp_parse_error(pd, offset, fd, tree,
1499 proto_tree_add_text(secur_tree, NullTVB, offset,
1500 length, "User Name: %.*s",
1502 SAFE_STRING(username));
1506 ret = asn1_octet_string_decode (&asn1, &authpar,
1507 &authpar_length, &length);
1508 if (ret != ASN1_ERR_NOERROR) {
1509 dissect_snmp_parse_error(pd, offset, fd, tree,
1510 "authentication parameter", ret);
1514 proto_tree_add_text(secur_tree, NullTVB, offset,
1515 length, "Authentication Parameter: %s",
1516 bytes_to_str(authpar, authpar_length));
1520 ret = asn1_octet_string_decode (&asn1, &privpar,
1521 &privpar_length, &length);
1522 if (ret != ASN1_ERR_NOERROR) {
1523 dissect_snmp_parse_error(pd, offset, fd, tree,
1524 "privacy parameter", ret);
1528 proto_tree_add_text(secur_tree, NullTVB, offset,
1529 length, "Privacy Parameter: %s",
1530 bytes_to_str(privpar, privpar_length));
1536 ret = asn1_octet_string_decode (&asn1,
1537 &secparm, &secparm_length, &length);
1538 if (ret != ASN1_ERR_NOERROR) {
1539 dissect_snmp_parse_error(pd, offset, fd, tree,
1540 "Message Security Parameters", ret);
1544 proto_tree_add_text(snmp_tree, NullTVB, offset,
1546 "Message Security Parameters Data"
1547 " (%d bytes)", secparm_length);
1553 /* PDU starts here */
1555 ret = asn1_octet_string_decode (&asn1, &cryptpdu,
1556 &cryptpdu_length, &length);
1557 if (ret != ASN1_ERR_NOERROR) {
1558 dissect_snmp_parse_error(pd, offset, fd, tree,
1559 "encrypted PDU header", ret);
1562 proto_tree_add_text(snmp_tree, NullTVB, offset, length,
1563 "Encrypted PDU (%d bytes)", length);
1565 if (check_col(fd, COL_INFO))
1566 col_set_str(fd, COL_INFO, "Encrypted PDU");
1569 ret = asn1_sequence_decode(&asn1, &global_length, &length);
1570 if (ret != ASN1_ERR_NOERROR) {
1571 dissect_snmp_parse_error(pd, offset, fd, tree,
1576 ret = asn1_octet_string_decode (&asn1, &cengineid,
1577 &cengineid_length, &length);
1578 if (ret != ASN1_ERR_NOERROR) {
1579 dissect_snmp_parse_error(pd, offset, fd, tree,
1580 "context engine id", ret);
1584 proto_tree_add_text(snmp_tree, NullTVB, offset, length,
1585 "Context Engine ID: %s",
1586 bytes_to_str(cengineid, cengineid_length));
1590 ret = asn1_octet_string_decode (&asn1, &cname,
1591 &cname_length, &length);
1592 if (ret != ASN1_ERR_NOERROR) {
1593 dissect_snmp_parse_error(pd, offset, fd, tree,
1594 "context name", ret);
1598 proto_tree_add_text(snmp_tree, NullTVB, offset, length,
1599 "Context Name: %.*s", cname_length,
1600 SAFE_STRING(cname));
1606 dissect_snmp_error(pd, offset, fd, tree,
1607 "PDU for unknown version of SNMP");
1611 start = asn1.pointer;
1612 ret = asn1_header_decode (&asn1, &cls, &con, &pdu_type, &def,
1614 if (ret != ASN1_ERR_NOERROR) {
1615 dissect_snmp_parse_error(pd, offset, fd, tree,
1619 if (cls != ASN1_CTX || con != ASN1_CON) {
1620 dissect_snmp_parse_error(pd, offset, fd, tree,
1621 "PDU type", ASN1_ERR_WRONG_TYPE);
1624 dissect_common_pdu(pd, offset, fd, snmp_tree, asn1, pdu_type, start);
1628 dissect_smux_pdu(const u_char *pd, int offset, frame_data *fd,
1629 proto_tree *tree, int proto, gint ett)
1632 const guchar *start;
1637 char *pdu_type_string;
1647 int password_length;
1649 guchar *application;
1650 int application_length;
1657 proto_tree *smux_tree = NULL;
1658 proto_item *item = NULL;
1662 if (check_col(fd, COL_PROTOCOL))
1663 col_set_str(fd, COL_PROTOCOL, "SMUX");
1666 item = proto_tree_add_item(tree, proto, NullTVB, offset,
1667 END_OF_FRAME, FALSE);
1668 smux_tree = proto_item_add_subtree(item, ett);
1671 /* NOTE: we have to parse the message piece by piece, since the
1672 * capture length may be less than the message length: a 'global'
1673 * parsing is likely to fail.
1675 /* parse the SNMP header */
1676 asn1_open(&asn1, &pd[offset], END_OF_FRAME);
1677 start = asn1.pointer;
1678 ret = asn1_header_decode (&asn1, &cls, &con, &pdu_type, &def,
1680 if (ret != ASN1_ERR_NOERROR) {
1681 dissect_snmp_parse_error(pd, offset, fd, tree,
1686 /* Dissect SMUX here */
1687 if (cls == ASN1_APL && con == ASN1_CON && pdu_type == SMUX_MSG_OPEN) {
1688 pdu_type_string = val_to_str(pdu_type, smux_types,
1689 "Unknown PDU type %#x");
1690 if (check_col(fd, COL_INFO))
1691 col_add_str(fd, COL_INFO, pdu_type_string);
1692 length = asn1.pointer - start;
1694 proto_tree_add_text(smux_tree, NullTVB, offset, length,
1695 "PDU type: %s", pdu_type_string);
1698 ret = asn1_uint32_decode (&asn1, &version, &length);
1699 if (ret != ASN1_ERR_NOERROR) {
1700 dissect_snmp_parse_error(pd, offset, fd, tree,
1705 proto_tree_add_text(smux_tree, NullTVB, offset, length,
1706 "Version: %d", version);
1710 ret = asn1_oid_decode (&asn1, ®id, ®id_length, &length);
1711 if (ret != ASN1_ERR_NOERROR) {
1712 dissect_snmp_parse_error(pd, offset, fd, tree,
1713 "registration OID", ret);
1717 oid_string = format_oid(regid, regid_length);
1718 proto_tree_add_text(smux_tree, NullTVB, offset, length,
1719 "Registration: %s", oid_string);
1725 ret = asn1_octet_string_decode (&asn1, &application,
1726 &application_length, &length);
1727 if (ret != ASN1_ERR_NOERROR) {
1728 dissect_snmp_parse_error(pd, offset, fd, tree,
1729 "application", ret);
1733 proto_tree_add_text(smux_tree, NullTVB, offset, length,
1734 "Application: %.*s", application_length,
1735 SAFE_STRING(application));
1737 g_free(application);
1740 ret = asn1_octet_string_decode (&asn1, &password,
1741 &password_length, &length);
1742 if (ret != ASN1_ERR_NOERROR) {
1743 dissect_snmp_parse_error(pd, offset, fd, tree,
1748 proto_tree_add_text(smux_tree, NullTVB, offset, length,
1749 "Password: %.*s", password_length,
1750 SAFE_STRING(password));
1756 if (cls == ASN1_APL && con == ASN1_PRI && pdu_type == SMUX_MSG_CLOSE) {
1757 pdu_type_string = val_to_str(pdu_type, smux_types,
1758 "Unknown PDU type %#x");
1759 if (check_col(fd, COL_INFO))
1760 col_add_str(fd, COL_INFO, pdu_type_string);
1761 length = asn1.pointer - start;
1763 proto_tree_add_text(smux_tree, NullTVB, offset, length,
1764 "PDU type: %s", pdu_type_string);
1767 ret = asn1_uint32_value_decode (&asn1, pdu_length, &cause);
1768 if (ret != ASN1_ERR_NOERROR) {
1769 dissect_snmp_parse_error(pd, offset, fd, tree,
1774 proto_tree_add_text(smux_tree, NullTVB, offset,
1775 pdu_length, "Cause: %s",
1776 val_to_str(cause, smux_close,
1777 "Unknown cause %#x"));
1779 offset += pdu_length;
1782 if (cls == ASN1_APL && con == ASN1_CON && pdu_type == SMUX_MSG_RREQ) {
1783 pdu_type_string = val_to_str(pdu_type, smux_types,
1784 "Unknown PDU type %#x");
1785 if (check_col(fd, COL_INFO))
1786 col_add_str(fd, COL_INFO, pdu_type_string);
1787 length = asn1.pointer - start;
1789 proto_tree_add_text(smux_tree, NullTVB, offset, length,
1790 "PDU type: %s", pdu_type_string);
1793 ret = asn1_oid_decode (&asn1, ®id, ®id_length, &length);
1794 if (ret != ASN1_ERR_NOERROR) {
1795 dissect_snmp_parse_error(pd, offset, fd, tree,
1796 "registration subtree", ret);
1800 oid_string = format_oid(regid, regid_length);
1801 proto_tree_add_text(smux_tree, NullTVB, offset, length,
1802 "Registration: %s", oid_string);
1808 ret = asn1_uint32_decode (&asn1, &priority, &length);
1809 if (ret != ASN1_ERR_NOERROR) {
1810 dissect_snmp_parse_error(pd, offset, fd, tree,
1815 proto_tree_add_text(smux_tree, NullTVB, offset, length,
1816 "Priority: %d", priority);
1820 ret = asn1_uint32_decode (&asn1, &operation, &length);
1821 if (ret != ASN1_ERR_NOERROR) {
1822 dissect_snmp_parse_error(pd, offset, fd, tree,
1827 proto_tree_add_text(smux_tree, NullTVB, offset, length,
1829 val_to_str(operation, smux_rreq,
1830 "Unknown operation %#x"));
1835 if (cls == ASN1_APL && con == ASN1_PRI && pdu_type == SMUX_MSG_RRSP) {
1836 pdu_type_string = val_to_str(pdu_type, smux_types,
1837 "Unknown PDU type %#x");
1838 if (check_col(fd, COL_INFO))
1839 col_add_str(fd, COL_INFO, pdu_type_string);
1840 length = asn1.pointer - start;
1842 proto_tree_add_text(smux_tree, NullTVB, offset, length,
1843 "PDU type: %s", pdu_type_string);
1846 ret = asn1_uint32_value_decode (&asn1, pdu_length, &priority);
1847 if (ret != ASN1_ERR_NOERROR) {
1848 dissect_snmp_parse_error(pd, offset, fd, tree,
1853 proto_tree_add_text(smux_tree, NullTVB, offset,
1855 val_to_str(priority, smux_prio,
1858 offset += pdu_length;
1861 if (cls == ASN1_APL && con == ASN1_PRI && pdu_type == SMUX_MSG_SOUT) {
1862 pdu_type_string = val_to_str(pdu_type, smux_types,
1863 "Unknown PDU type %#x");
1864 if (check_col(fd, COL_INFO))
1865 col_add_str(fd, COL_INFO, pdu_type_string);
1866 length = asn1.pointer - start;
1868 proto_tree_add_text(smux_tree, NullTVB, offset, length,
1869 "PDU type: %s", pdu_type_string);
1872 ret = asn1_uint32_value_decode (&asn1, pdu_length, &commit);
1873 if (ret != ASN1_ERR_NOERROR) {
1874 dissect_snmp_parse_error(pd, offset, fd, tree,
1879 proto_tree_add_text(smux_tree, NullTVB, offset,
1881 val_to_str(commit, smux_sout,
1882 "Unknown SOUT Value: %#x"));
1884 offset += pdu_length;
1887 if (cls != ASN1_CTX || con != ASN1_CON) {
1888 dissect_snmp_parse_error(pd, offset, fd, tree,
1889 "PDU type", ASN1_ERR_WRONG_TYPE);
1892 dissect_common_pdu(pd, offset, fd, smux_tree, asn1, pdu_type, start);
1896 dissect_snmp(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
1898 conversation_t *conversation;
1900 OLD_CHECK_DISPLAY_AS_DATA(proto_snmp, pd, offset, fd, tree);
1903 * The first SNMP packet goes to the SNMP port; the second one
1904 * may come from some *other* port, but goes back to the same
1905 * IP address and port as the ones from which the first packet
1906 * came; all subsequent packets presumably go between those two
1907 * IP addresses and ports.
1909 * If this packet went to the SNMP port, we check to see if
1910 * there's already a conversation with the source IP address
1911 * and port of this packet, the destination IP address of this
1912 * packet, and any destination UDP port. If not, we create
1913 * one, with a wildcard UDP port, and give it the SNMP dissector
1916 if (pi.destport == UDP_PORT_SNMP) {
1917 conversation = find_conversation(&pi.src, &pi.dst, PT_UDP,
1918 pi.srcport, 0, NO_DST_PORT);
1919 if (conversation == NULL) {
1920 conversation = conversation_new(&pi.src, &pi.dst, PT_UDP,
1921 pi.srcport, 0, NULL,
1923 old_conversation_set_dissector(conversation, dissect_snmp);
1927 dissect_snmp_pdu(pd, offset, fd, tree, "SNMP", proto_snmp, ett_snmp);
1931 dissect_smux(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
1933 OLD_CHECK_DISPLAY_AS_DATA(proto_smux, pd, offset, fd, tree);
1934 dissect_smux_pdu(pd, offset, fd, tree, proto_smux, ett_smux);
1938 proto_register_snmp(void)
1941 void *libsnmp_handle;
1942 int (*snmp_set_suffix_only_p)(int);
1943 int (*ds_set_int_p)(int, int, int);
1946 static hf_register_info hf[] = {
1948 { "SNMPv3 Flags", "snmpv3.flags", FT_UINT8, BASE_HEX, NULL,
1950 { &hf_snmpv3_flags_auth,
1951 { "Authenticated", "snmpv3.flags.auth", FT_BOOLEAN, 8,
1952 TFS(&flags_set_truth), TH_AUTH, "" }},
1953 { &hf_snmpv3_flags_crypt,
1954 { "Encrypted", "snmpv3.flags.crypt", FT_BOOLEAN, 8,
1955 TFS(&flags_set_truth), TH_CRYPT, "" }},
1956 { &hf_snmpv3_flags_report,
1957 { "Reportable", "snmpv3.flags.report", FT_BOOLEAN, 8,
1958 TFS(&flags_set_truth), TH_REPORT, "" }},
1960 static gint *ett[] = {
1968 #if defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H)
1969 /* UCD or CMU SNMP */
1971 #ifdef HAVE_UCD_SNMP_SNMP_H
1973 /* As per the comment near the beginning of the file, UCD SNMP 4.1.1
1974 changed "snmp_set_suffix_only()" from a function to a macro,
1975 removing "snmp_set_suffix_only()" from the library; this means
1976 that binaries that call "snmp_set_suffix_only()" and
1977 that are linked against shared libraries from earlier versions
1978 of the UCD SNMP library won't run with shared libraries from
1981 This is a problem on Red Hat Linux, as pre-6.2 releases
1982 came with pre-4.1.1 UCD SNMP, while 6.2 comes the 4.1.1.
1983 Versions of Ethereal built on pre-6.2 releases don't run
1984 on 6.2, and the current Ethereal RPMs are built on pre-6.2
1985 releases, causing problems when users running 6.2 download
1986 them and try to use them.
1988 Building the releases on 6.2 isn't necessarily the answer,
1989 as "snmp_set_suffix_only()" expands to a call to "ds_set_int()"
1990 with a second argument not supported by at least some pre-4.1.1
1991 versions of the library - it appears that the 4.0.1 library,
1992 at least, checks for invalid arguments and returns an error
1993 rather than stomping random memory, but that means that you
1994 won't get get OIDs displayed as module-name::sub-OID.
1996 So we use a trick similar to one I've seen mentioned as
1997 used in Windows applications to let you build binaries
1998 that run on many different versions of Windows 9x and
1999 Windows NT, that use features present on later versions
2000 if run on those later versions, but that avoid calling,
2001 when run on older versions, routines not present on those
2004 I.e., we load "libsnmp.so.0" with "dlopen()", and call
2005 "dlsym()" to try to find "snmp_set_suffix_only()"; if we
2006 don't find it, we make the appropriate call to
2007 "ds_set_int()" instead. (We load "libsnmp.so.0" rather
2008 than "libsnmp.so" because, at least on RH 6.2, "libsnmp.so"
2009 exists only if you've loaded the libsnmp development package,
2010 which makes "libsnmp.so" a symlink to "libsnmp.so.0"; we
2011 don't want to force users to install it or to make said
2014 We do this only on Linux, for now, as we've only seen the
2015 problem on Red Hat; it may show up on other OSes that bundle
2016 UCD SNMP, or on OSes where it's not bundled but for which
2017 binary packages are built that link against a shared version
2018 of the UCD SNMP library. If we run into one of those, we
2019 can do this under those OSes as well, *if* "dlopen()" makes
2020 the run-time linker use the same search rules as it uses when
2021 loading libraries with which the application is linked.
2023 (Perhaps we could use the GLib wrappers for run-time linking,
2024 *if* they're thin enough; however, as this code is currently
2025 used only on Linux, we don't worry about that for now.) */
2027 libsnmp_handle = dlopen("libsnmp.so.0", RTLD_LAZY|RTLD_GLOBAL);
2028 if (libsnmp_handle == NULL) {
2029 /* We didn't find "libsnmp.so.0".
2031 This could mean that there is no SNMP shared library
2032 on this system, in which case we were linked statically,
2033 in which case whatever call the following line of code
2034 makes will presumably work, as we have the routine it
2035 calls wired into our binary. (If we were linked
2036 dynamically with "-lsnmp", we would have failed to
2039 It could also mean that there is an SNMP shared library
2040 on this system, but it's called something other than
2041 "libsnmp.so.0"; so far, we've seen the problem we're
2042 working around only on systems where the SNMP shared
2043 library is called "libsnmp.so.0", so we assume for now
2044 that systems with shared SNMP libraries named something
2045 other than "libsnmp.so.0" have an SNMP library that's
2047 snmp_set_suffix_only(2);
2049 /* OK, we have it loaded. Do we have
2050 "snmp_set_suffix_only()"? */
2051 snmp_set_suffix_only_p = dlsym(libsnmp_handle,
2052 "snmp_set_suffix_only");
2053 if (snmp_set_suffix_only_p != NULL) {
2054 /* Yes - call it. */
2055 (*snmp_set_suffix_only_p)(2);
2057 /* No; do we have "ds_set_int()"? */
2058 ds_set_int_p = dlsym(libsnmp_handle, "ds_set_int");
2059 if (ds_set_int_p != NULL) {
2060 /* Yes - cal it with DS_LIBRARY_ID,
2061 DS_LIB_PRINT_SUFFIX_ONLY, and 2 as
2064 We do *not* use DS_LIBRARY_ID or
2065 DS_LIB_PRINT_SUFFIX_ONLY by name, so that
2066 we don't require that Ethereal be built
2067 with versions of UCD SNMP that include
2068 that value; instead, we use their values
2069 in UCD SNMP 4.1.1, which are 0 and 4,
2071 (*ds_set_int_p)(0, 4, 2);
2074 dlclose(libsnmp_handle);
2077 snmp_set_suffix_only(2);
2079 #endif /* HAVE_UCD_SNMP_SNMP_H */
2080 #endif /* defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H) */
2081 proto_snmp = proto_register_protocol("Simple Network Management Protocol", "snmp");
2082 proto_smux = proto_register_protocol("SNMP Multiplex Protocol", "smux");
2083 proto_register_field_array(proto_snmp, hf, array_length(hf));
2084 proto_register_subtree_array(ett, array_length(ett));
2088 proto_reg_handoff_snmp(void)
2090 old_dissector_add("udp.port", UDP_PORT_SNMP, dissect_snmp);
2091 old_dissector_add("udp.port", UDP_PORT_SNMP_TRAP, dissect_snmp);
2092 old_dissector_add("tcp.port", TCP_PORT_SMUX, dissect_smux);
2093 old_dissector_add("ethertype", ETHERTYPE_SNMP, dissect_snmp);
2094 old_dissector_add("ipx.socket", IPX_SOCKET_SNMP_AGENT, dissect_snmp);
2095 old_dissector_add("ipx.socket", IPX_SOCKET_SNMP_SINK, dissect_snmp);