Ethereal-dev: [ethereal-dev] SNMP Patch
Note: This archive is from the project's previous web site, ethereal.com. This list is no longer active.
From: Jochen Friedrich <jochen@xxxxxx>
Date: Sun, 14 May 2000 23:04:58 +0200 (CEST)
Hi there, next version of the SNMP dissector (as patch against current CVS)... Now, SNMPv3 should be completed. USM and encrypted packets are dissected correctly. The attached trace file can be used to check the functionality. Cheers, Jochen
Attachment:
snmp.trace
Description: Binary data
Index: Makefile.am =================================================================== RCS file: /cvsroot/ethereal/Makefile.am,v retrieving revision 1.197 diff -u -r1.197 Makefile.am --- Makefile.am 2000/05/12 05:46:47 1.197 +++ Makefile.am 2000/05/14 21:53:59 @@ -355,14 +355,14 @@ ethereal_LDADD = \ $(ethereal_optional_objects) \ $(ethereal_additional_libs) \ - @SNMP_LIBS@ \ + @SMI_LIBS@ \ "-dlopen" self \ "-dlopen" plugins/gryphon/gryphon.la @PCAP_LIBS@ @GTK_LIBS@ ethereal_static_LDADD = \ $(ethereal_optional_objects) \ $(ethereal_additional_libs) \ - @SNMP_LIBS@ \ + @SMI_LIBS@ \ @PCAP_LIBS@ @GTK_LIBS@ ethereal_LDFLAGS = -export-dynamic @@ -387,7 +387,7 @@ tethereal_LDADD = wiretap/libwiretap.a \ $(ethereal_optional_objects) \ $(tethereal_additional_libs) \ - @SNMP_LIBS@ \ + @SMI_LIBS@ \ "-dlopen" self \ "-dlopen" plugins/gryphon/gryphon.la @GLIB_LIBS@ -lm \ @PCAP_LIBS@ @SOCKET_LIBS@ @NSL_LIBS@ Index: configure.in =================================================================== RCS file: /cvsroot/ethereal/configure.in,v retrieving revision 1.91 diff -u -r1.91 configure.in --- configure.in 2000/05/09 03:09:55 1.91 +++ configure.in 2000/05/14 21:53:59 @@ -72,7 +72,7 @@ # # Arrange that we search for header files in the source directory # and in its "wiretap" subdirectory, as well as in "/usr/local/include", -# as various packages we use ("libpcap", "zlib", an SNMP library) +# as various packages we use ("libpcap", "zlib", an SMI library) # may have been installed under "/usr/local/include". # CFLAGS="$CFLAGS -I\$(top_srcdir) -I\$(top_srcdir)/wiretap -I/usr/local/include" @@ -196,52 +196,21 @@ AC_CHECK_HEADERS(dlfcn.h) AC_CHECK_HEADERS(arpa/inet.h arpa/nameser.h) -dnl SNMP Check -AC_ARG_ENABLE(snmp, -[ --enable-snmp use SNMP library, if available. [default=yes]],,enable_snmp=yes) +dnl SMI Check +AC_ARG_ENABLE(smi, +[ --enable-smi use SMI library, if available. [default=yes]],,enable_smi=yes) SNMP_LIBS='' -AC_MSG_CHECKING(whether to use SNMP library if available) -if test "x$enable_snmp" = "xno" ; then +AC_MSG_CHECKING(whether to use SMI library if available) +if test "x$enable_smi" = "xno" ; then AC_MSG_RESULT(no) else AC_MSG_RESULT(yes) - AC_ETHEREAL_UCDSNMP_CHECK - AC_CHECK_HEADERS(ucd-snmp/snmp.h ucd-snmp/version.h snmp/snmp.h snmp/version.h) - - # - # This may require "-lkstat" on Solaris, sigh. - # - AC_CHECK_LIB(snmp, sprint_objid, - SNMP_LIBS=-lsnmp, - [ - # - # Throw away the cached "we didn't find it" answer. - # - unset ac_cv_lib_snmp_sprint_objid - AC_CHECK_LIB(snmp, sprint_objid, - [ - # - # Throw away the cached "we found it" answer, so that if - # we rerun "configure", we don't just blow off this check - # and blithely assume that we don't need "-lkstat". - # - # XXX - autoconf really needs a way to test for a given - # routine in a given library *and* to test whether additional - # "-L"/"-R"/whatever flags are needed *before* the "-l" - # flag for the library and to test whether additional libraries - # are needed after the library *and* to cache all that - # information. - # - unset ac_cv_lib_snmp_sprint_objid - SNMP_LIBS="-lsnmp -lkstat" - ],,$SOCKET_LIBS $NSL_LIBS -lkstat - ) - ], $SOCKET_LIBS $NSL_LIBS - ) + AC_CHECK_HEADERS(smi.h) + AC_CHECK_LIB(smi, smiInit, SMI_LIBS=-lsmi) fi -AC_SUBST(SNMP_LIBS) +AC_SUBST(SMI_LIBS) dnl Checks for typedefs, structures, and compiler characteristics. # AC_C_CONST Index: packet-snmp.c =================================================================== RCS file: /cvsroot/ethereal/packet-snmp.c,v retrieving revision 1.30 diff -u -r1.30 packet-snmp.c --- packet-snmp.c 2000/05/11 08:15:49 1.30 +++ packet-snmp.c 2000/05/14 21:53:59 @@ -48,151 +48,40 @@ #define MAX_STRING_LEN 1024 /* TBC */ #include <glib.h> +#include <smi.h> #include "packet.h" #include "etypes.h" - -#if defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H) - /* - * UCD or CMU SNMP? - */ -# if defined(HAVE_UCD_SNMP_SNMP_H) - /* - * UCD SNMP. - */ -# include <ucd-snmp/asn1.h> -# include <ucd-snmp/snmp_api.h> -# include <ucd-snmp/snmp_impl.h> -# include <ucd-snmp/mib.h> - - /* - * Sigh. UCD SNMP 4.1[.x] makes "snmp_set_full_objid()" a macro - * that calls "ds_set_boolean()" with the first two arguments - * being DS_LIBRARY_ID and DS_LIB_PRINT_FULL_OID; this means that, - * when building with 4.1[.x], we need to arrange that - * <ucd-snmp/default_store.h> is included, to define those two values - * and to declare "ds_set_boolean()". - * - * However: - * - * 1) we can't include it on earlier versions (at least not 3.6.2), - * as it doesn't exist in those versions; - * - * 2) we don't want to include <ucd-snmp/ucd-snmp-includes.h>, - * as that includes <ucd-snmp/snmp.h>, and that defines a whole - * bunch of values that we also define ourselves. - * - * So we only include it if "snmp_set_full_objid" is defined as - * a macro. - */ -# ifdef snmp_set_full_objid -# include <ucd-snmp/default_store.h> -# endif - - /* - * XXX - for now, we assume all versions of UCD SNMP have it. - */ -# define HAVE_SPRINT_VALUE - - /* - * Define values "sprint_value()" expects. - */ -# define VALTYPE_INTEGER ASN_INTEGER -# define VALTYPE_COUNTER ASN_COUNTER -# define VALTYPE_GAUGE ASN_GAUGE -# define VALTYPE_TIMETICKS ASN_TIMETICKS -# define VALTYPE_STRING ASN_OCTET_STR -# define VALTYPE_IPADDR ASN_IPADDRESS -# define VALTYPE_OPAQUE ASN_OPAQUE -# define VALTYPE_NSAP ASN_NSAP -# define VALTYPE_OBJECTID ASN_OBJECT_ID -# define VALTYPE_BITSTR ASN_BIT_STR -# define VALTYPE_COUNTER64 ASN_COUNTER64 -# elif defined(HAVE_SNMP_SNMP_H) - /* - * CMU SNMP. - */ -# include <snmp/snmp.h> - - /* - * Some older versions of CMU SNMP may lack these values (e.g., the - * "libsnmp3.6" package for Debian, which is based on some old - * CMU SNMP, perhaps 1.0); for now, we assume they also lack - * "sprint_value()". - */ -# ifdef SMI_INTEGER -# define HAVE_SPRINT_VALUE - /* - * Define values "sprint_value()" expects. - */ -# define VALTYPE_INTEGER SMI_INTEGER -# define VALTYPE_COUNTER SMI_COUNTER32 -# define VALTYPE_GAUGE SMI_GAUGE32 -# define VALTYPE_TIMETICKS SMI_TIMETICKS -# define VALTYPE_STRING SMI_STRING -# define VALTYPE_IPADDR SMI_IPADDRESS -# define VALTYPE_OPAQUE SMI_OPAQUE -# define VALTYPE_NSAP SMI_STRING -# define VALTYPE_OBJECTID SMI_OBJID -# define VALTYPE_BITSTR ASN_BIT_STR -# define VALTYPE_COUNTER64 SMI_COUNTER64 -# endif - /* - * Now undo all the definitions they "helpfully" gave us, so we don't get - * complaints about redefining them. - * - * Why, oh why, is there no library that provides code to - * - * 1) read MIB files; - * - * 2) translate object IDs into names; - * - * 3) let you find out, for a given object ID, what the type, enum - * values, display hint, etc. are; - * - * in a *simple* fashion, without assuming that your code is part of an - * SNMP agent or client that wants a pile of definitions of PDU types, - * etc.? Is it just that 99 44/100% of the code that uses an SNMP library - * *is* part of an agent or client, and really *does* need that stuff, - * and *doesn't* need the interfaces we want? - */ -# undef SNMP_ERR_NOERROR -# undef SNMP_ERR_TOOBIG -# undef SNMP_ERR_NOSUCHNAME -# undef SNMP_ERR_BADVALUE -# undef SNMP_ERR_READONLY -# undef SNMP_ERR_NOACCESS -# undef SNMP_ERR_WRONGTYPE -# undef SNMP_ERR_WRONGLENGTH -# undef SNMP_ERR_WRONGENCODING -# undef SNMP_ERR_WRONGVALUE -# undef SNMP_ERR_NOCREATION -# undef SNMP_ERR_INCONSISTENTVALUE -# undef SNMP_ERR_RESOURCEUNAVAILABLE -# undef SNMP_ERR_COMMITFAILED -# undef SNMP_ERR_UNDOFAILED -# undef SNMP_ERR_AUTHORIZATIONERROR -# undef SNMP_ERR_NOTWRITABLE -# undef SNMP_ERR_INCONSISTENTNAME -# undef SNMP_TRAP_COLDSTART -# undef SNMP_TRAP_WARMSTART -# undef SNMP_TRAP_LINKDOWN -# undef SNMP_TRAP_LINKUP -# undef SNMP_TRAP_EGPNEIGHBORLOSS -# undef SNMP_TRAP_ENTERPRISESPECIFIC -# endif -#endif - #include "asn1.h" #include "packet-snmp.h" static int proto_snmp = -1; +static int proto_smux = -1; static gint ett_snmp = -1; +static gint ett_smux = -1; +static gint ett_global = -1; +static gint ett_flags = -1; +static gint ett_secur = -1; + +static int hf_snmpv3_flags = -1; +static int hf_snmpv3_flags_auth = -1; +static int hf_snmpv3_flags_crypt = -1; +static int hf_snmpv3_flags_report = -1; + +#define TH_AUTH 0x01 +#define TH_CRYPT 0x02 +#define TH_REPORT 0x04 + +static const true_false_string flags_set_truth = { + "Set", + "Not set" +}; #define UDP_PORT_SNMP 161 #define UDP_PORT_SNMP_TRAP 162 +#define TCP_PORT_SMUX 199 /* Protocol version numbers */ #define SNMP_VERSION_1 0 @@ -233,6 +122,66 @@ { 0, NULL } }; +/* SMUX PDU types */ +#define SMUX_MSG_OPEN 0 +#define SMUX_MSG_CLOSE 1 +#define SMUX_MSG_RREQ 2 +#define SMUX_MSG_RRSP 3 +#define SMUX_MSG_SOUT 4 + +static const value_string smux_types[] = { + { SMUX_MSG_OPEN, "Open" }, + { SMUX_MSG_CLOSE, "Close" }, + { SMUX_MSG_RREQ, "Registration Request" }, + { SMUX_MSG_RRSP, "Registration Response" }, + { SMUX_MSG_SOUT, "Commit Or Rollback" }, + { 0, NULL } +}; + +/* SMUX Closing causes */ +#define SMUX_CLOSE_DOWN 0 +#define SMUX_CLOSE_VERSION 1 +#define SMUX_CLOSE_PACKET 2 +#define SMUX_CLOSE_PROTOCOL 3 +#define SMUX_CLOSE_INTERNAL 4 +#define SMUX_CLOSE_NOAUTH 5 + +static const value_string smux_close[] = { + { SMUX_CLOSE_DOWN, "Going down" }, + { SMUX_CLOSE_VERSION, "Unsupported Version" }, + { SMUX_CLOSE_PACKET, "Packet Format Error" }, + { SMUX_CLOSE_PROTOCOL, "Protocol Error" }, + { SMUX_CLOSE_INTERNAL, "Internal Error" }, + { SMUX_CLOSE_NOAUTH, "Unauthorized" }, + { 0, NULL } +}; + +/* SMUX Request codes */ +#define SMUX_RREQ_DELETE 0 +#define SMUX_RREQ_READONLY 1 +#define SMUX_RREQ_READWRITE 2 + +static const value_string smux_rreq[] = { + { SMUX_RREQ_DELETE, "Delete" }, + { SMUX_RREQ_READONLY, "Read Only" }, + { SMUX_RREQ_READWRITE, "Read Write" }, + { 0, NULL } +}; + +static const value_string smux_prio[] = { + { -1, "Failure" }, + { 0, NULL } +}; + +/* SMUX SOut codes */ +#define SMUX_SOUT_COMMIT 0 +#define SMUX_SOUT_ROLLBACK 1 + +static const value_string smux_sout[] = { + { SMUX_SOUT_COMMIT, "Commit" }, + { SMUX_SOUT_ROLLBACK, "Rollback" } +}; + /* Error status values */ #define SNMP_ERR_NOERROR 0 #define SNMP_ERR_TOOBIG 1 @@ -299,6 +248,21 @@ { 0, NULL } }; +/* Security Models */ + +#define SNMP_SEC_ANY 0 +#define SNMP_SEC_V1 1 +#define SNMP_SEC_V2C 2 +#define SNMP_SEC_USM 3 + +static const value_string sec_models[] = { + { SNMP_SEC_ANY, "Any" }, + { SNMP_SEC_V1, "V1" }, + { SNMP_SEC_V2C, "V2C" }, + { SNMP_SEC_USM, "USM" }, + { 0, NULL } +}; + /* SNMP Tags */ #define SNMP_IPA 0 /* IP Address */ @@ -369,6 +333,333 @@ {0, 0, -1, NULL} }; +static gint +int_div(guchar *buffer, gint radix, gint *len, gint *nul) +{ + gint dividend, i, mod; + + *nul = 1; + while (*len && (*buffer == 0)) + { + for (i=1; i<*len; i++) + buffer[i-1] = buffer[i]; + (*len)--; + } + if (!*len) + return 0; + + dividend = 0; + mod = 0; + for (i=0; i<*len; i++) + { + dividend = mod * 256 + buffer[i]; + mod = dividend % radix; + buffer[i] = dividend / radix; + } + while (*len && (*buffer == 0)) + { + for (i=1; i<*len; i++) + buffer[i-1] = buffer[i]; + (*len)--; + } + if (*len) *nul=0; + return mod; +} + +/** + * print_radix: + * @buffer: integer value + * @len: length of integer + * @radix: base + * @shift: decimal shift + * + */ +static gchar * +print_radix(gpointer buffer, gint len, gint radix, gboolean sign, gint shift) +{ + guchar *result, *temp; + gint size, neg, i, nul; + gchar digit[] = "0123456789ABCDEF"; + + if (radix<2) radix=2; + if (radix>16) radix=16; + + size = len*8 + 2; /* worst case + sign + trailing 0 */ + if (shift) size++; /* decimal point */ + if (size<shift+4) size=shift+4; /* additional leading 0 */ + + result = g_malloc(size+1); + temp = g_malloc(len); + + neg = 0; + + g_memmove(temp, buffer, len); + + if (sign && (temp[0] & 0x80)) + { + neg = 1; + for (i=0; i<len; i++) + temp[i] = ~temp[i]; + i=len-1; + while (i>=0) + { + temp[i]++; + if (temp[i]) break; + i--; + } + } + i=size; + result[i--] = '\0'; + nul=0; + while ((!nul || (shift && size-i-3 < shift)) && (i>=0)) + { + if ((shift == size-i-1) && shift) + result[i--] = '.'; + else + result[i--] = digit[int_div(temp, radix, &len, &nul)]; + } + if (i && neg) + result[i--] = '-'; + g_free(temp); + temp = g_strdup(result+i+1); + g_free(result); + return temp; +} +/** + * format_integer: + * @buffer: integer value as received from SNMP node + * @len: length of integer + * @format: Format as taken from DISPLAY HINT parameter of MIB file. + * + * Formats an INTEGER value according to a provided DISPLAY HINT. + * + * When the syntax has an underlying primitive type of INTEGER, the hint + * consists of an integer-format specification, containing two parts. + * The first part is a single character suggesting a display format, + * either: `x' for hexadecimal, or `d' for decimal, or `o' for octal, or + * `b' for binary. For all types, when rendering the value, leading + * zeros are omitted, and for negative values, a minus sign is rendered + * immediately before the digits. The second part is always omitted for + * `x', `o' and `b', and need not be present for `d'. If present, the + * second part starts with a hyphen and is followed by a decimal number, + * which defines the implied decimal point when rendering the value. + * + * Return value: Formatted string. + **/ +static gchar* +format_integer(gpointer buffer, gint len, gboolean sign, gchar *format) +{ + gint shift; + + shift = 0; + switch(format[0]) + { + case 'x': + return print_radix(buffer, len, 16, sign, 0); + break; + case 'o': + return print_radix(buffer, len, 8, sign, 0); + break; + case 'b': + return print_radix(buffer, len, 2, sign, 0); + break; + case 'd': + if (format[1] == '-') + shift = atoi(&(format[2])); + if (shift < 0) + shift = 0; + default: + return print_radix(buffer, len, 10, sign, shift); + } +} + +/** + * format_string: + * @buffer: octet string as received from SNMP node + * @len: length of octet string + * @format: Format as taken from DISPLAY HINT parameter of MIB file. + * + * Formats an OCTET STRING value according to a provided DISPLAY HINT. + * + * When the syntax has an underlying primitive type of OCTET STRING, the + * hint consists of one or more octet-format specifications. Each + * specification consists of five parts, with each part using and + * removing zero or more of the next octets from the value and producing + * the next zero or more characters to be displayed. The octets within + * the value are processed in order of significance, most significant + * first. + * + * The five parts of a octet-format specification are: + * + * (1) the (optional) repeat indicator; if present, this part is a `*', + * and indicates that the current octet of the value is to be used as + * the repeat count. The repeat count is an unsigned integer (which + * may be zero) which specifies how many times the remainder of this + * octet-format specification should be successively applied. If the + * repeat indicator is not present, the repeat count is one. + * + * (2) the octet length: one or more decimal digits specifying the number + * of octets of the value to be used and formatted by this octet- + * specification. Note that the octet length can be zero. If less + * than this number of octets remain in the value, then the lesser + * number of octets are used. + * + * (3) the display format, either: `x' for hexadecimal, `d' for decimal, + * `o' for octal, `a' for ascii, or `t' for UTF-8. If the octet + * length part is greater than one, and the display format part refers + * to a numeric format, then network-byte ordering (big-endian + * encoding) is used interpreting the octets in the value. The octets + * processed by the `t' display format do not necessarily form an + * integral number of UTF-8 characters. Trailing octets which do not + * form a valid UTF-8 encoded character are discarded. + * + * (4) the (optional) display separator character; if present, this part + * is a single character which is produced for display after each + * application of this octet-specification; however, this character is + * not produced for display if it would be immediately followed by the + * display of the repeat terminator character for this octet- + * specification. This character can be any character other than a + * decimal digit and a `*'. + * + * (5) the (optional) repeat terminator character, which can be present + * only if the display separator character is present and this octet- + * specification begins with a repeat indicator; if present, this part + * is a single character which is produced after all the zero or more + * repeated applications (as given by the repeat count) of this + * octet-specification. This character can be any character other + * than a decimal digit and a `*'. + * + * Output of a display separator character or a repeat terminator + * character is suppressed if it would occur as the last character of + * the display. + * + * If the octets of the value are exhausted before all the octet-format + * specification have been used, then the excess specifications are + * ignored. If additional octets remain in the value after interpreting + * all the octet-format specifications, then the last octet-format + * specification is re-interpreted to process the additional octets, + * until no octets remain in the value. + * + * Return value: Formatted string. + **/ +static gchar* +format_string(gpointer buffer, gint len, gchar *format) +{ + int repeat, count, size; + gchar seperator, terminator, formtype; + gchar *ptr; + guchar *bufptr; + gchar *result; + int pos; + gchar *numstr; + int numstrlen; + + if (!len) + return g_strdup("NULL"); + + ptr = format; + bufptr = (guchar *)buffer; + + size = len * 3 * strlen(format); + result = g_malloc(size); + + pos = 0; + + while (len) + { + /* Read format string */ + if (!*ptr) + ptr = format; + repeat = 1; + count = 0; + seperator = '\0'; + terminator = '\0'; + formtype = '\0'; + if (*ptr == '*') + { + repeat = *bufptr++; + len--; + ptr++; + } + while (*ptr >= '0' && *ptr <= '9') + { + count = 10 * count + (*ptr++ & 0xf); + } + if (count == 0) + count = 1; + + if (*ptr && (*ptr != '*') && ((*ptr < '0') || (*ptr > '9'))) + formtype = *ptr++; + if (*ptr && (*ptr != '*') && ((*ptr < '0') || (*ptr > '9'))) + seperator = *ptr++; + if (*ptr && (*ptr != '*') && ((*ptr < '0') || (*ptr > '9'))) + terminator = *ptr++; + + while(repeat && len) + { + if (count > len) count = len; + switch (formtype) + { + case 'x': + numstr = print_radix(bufptr, count, 16, FALSE, 0); + numstrlen = strlen(numstr); + g_assert(pos + numstrlen < size); + strcpy(result + pos, numstr); + pos += numstrlen; + g_free(numstr); + break; + case 'd': + numstr = print_radix(bufptr, count, 10, FALSE, 0); + numstrlen = strlen(numstr); + g_assert(pos + numstrlen < size); + strcpy(result + pos, numstr); + pos += numstrlen; + g_free(numstr); + break; + case 'o': + numstr = print_radix(bufptr, count, 8, FALSE, 0); + numstrlen = strlen(numstr); + g_assert(pos + numstrlen < size); + strcpy(result + pos, numstr); + pos += numstrlen; + g_free(numstr); + break; + case 'a': + g_assert(pos + count < size); + g_memmove(result + pos, bufptr, count); + pos += count; + break; + } + + len = len - count; + bufptr = bufptr + count; + repeat--; + if (!repeat && len) + { + if (terminator) + { + g_assert(pos + 1 < size); + result[pos++] = terminator; + } + else if (seperator) + { + g_assert(pos + 1 < size); + result[pos++] = seperator; + } + } + else if (seperator && len) + { + g_assert(pos + 1 < size); + result[pos++] = seperator; + } + } + } + result[pos] = 0; + ptr = g_strdup(result); + g_free(result); + return ptr; +} + /* * NAME: g_snmp_tag_cls2syntax * SYNOPSIS: gboolean g_snmp_tag_cls2syntax @@ -454,12 +745,44 @@ dissect_data(pd, offset, fd, tree); } -static void -format_oid(gchar *buf, subid_t *oid, guint oid_length) +void +format_oid_name(subid_t *oid, guint oid_length, char **name, guint name_length, + SmiNode *node) { - int i; - int len; - + SmiNode *child; + int len, i; + char *buf; + + if (node) { + if (node->oidlen > 1) { + child = smiGetParentNode(node); + name_length += strlen(node->name) +1; + format_oid_name(oid, oid_length, name, name_length, + child); + strcat (*name, "."); + if(node->name) + strcat (*name, node->name); + else + strcat (*name, "<unnamed>"); + return; + } + *name = g_malloc(name_length); + buf = *name; + len = sprintf(buf, "%lu", (unsigned long)oid[0]); + buf += len; + for (i = 1; i < oid_length;i++) { + len = sprintf(buf, ".%lu", (unsigned long)oid[i]); + buf += len; + } + strcat(*name, " ("); + if(node->name) + strcat (*name, node->name); + else + strcat (*name, "<unnamed>"); + return; + } + *name = g_malloc(name_length); + buf = *name; len = sprintf(buf, "%lu", (unsigned long)oid[0]); buf += len; for (i = 1; i < oid_length;i++) { @@ -468,68 +791,183 @@ } } -#ifdef HAVE_SPRINT_VALUE -static void -format_value(gchar *buf, struct variable_list *variable, subid_t *variable_oid, - guint variable_oid_length, gushort vb_type, guint vb_length) +gchar * +format_oid(subid_t *oid, guint oid_length, SmiNode* node) +{ + char *result; + int len, i; + char *buf; + + result = NULL; + format_oid_name(oid, oid_length, &result, oid_length * 22 + 5, node); + if (node) { + buf = result + strlen(result); + for (i = node->oidlen; i < oid_length;i++) { + len = sprintf(buf, ".%lu", (unsigned long)oid[i]); + buf += len; + } + strcat(result, ")"); + } + return result; +} + +static gchar* +format_var(gushort vb_type, guint8 *vb_octet_string, guint vb_length, + SmiNode *node) { - variable->next_variable = NULL; - variable->name = variable_oid; - variable->name_length = variable_oid_length; + SmiType *typ; + gchar *string; + char *format; + int i; + SmiInteger32 integer32; + SmiUnsigned32 unsigned32; + SmiNamedNumber *named_number; + gchar *enumstring; + + typ = smiGetNodeType(node); + if (typ != NULL) + format = typ->format; + else + format = NULL; + + if (format == NULL) { + switch (vb_type) { + + case SNMP_INTEGER: + case SNMP_COUNTER: + case SNMP_GAUGE: + case SNMP_TIMETICKS: + case SNMP_COUNTER64: + format = "d"; + break; + + case SNMP_OCTETSTR: + case SNMP_OPAQUE: + case SNMP_NSAP: + case SNMP_BITSTR: + format = "1a"; + for (i = 0; i < vb_length; i++) { + if (!(isprint(vb_octet_string[i]) + || isspace(vb_octet_string[i]))) { + /* + * Oh, dear, it's binary. + */ + format = "1x "; + break; + } + } + break; + + case SNMP_IPADDR: + format = "d."; + break; + + default: + format = NULL; + break; + } + } + switch (vb_type) { case SNMP_INTEGER: - variable->type = VALTYPE_INTEGER; + string = format_integer(vb_octet_string, vb_length, TRUE, + format); + if (typ != NULL && vb_length <= 4) { + /* + * OK, we have a module, and the number fits in + * an "SmiInteger32". Check if there's an enum + * for this. + * + * XXX - handle "SmiInteger64"? + */ + integer32 = 0; + i = 0; + while (vb_length != 0) { + integer32 = + (integer32 << 8) | vb_octet_string[i]; + i++; + vb_length--; + } + for (named_number = smiGetFirstNamedNumber(typ); + named_number != NULL; + named_number = smiGetNextNamedNumber(named_number)) { + if (named_number->value.basetype == SMI_BASETYPE_INTEGER32 + && named_number->value.value.integer32 == integer32) + break; + } + if (named_number != NULL) { + enumstring = g_malloc( + strlen(named_number->name) + 1 + + strlen(string) + 1 + 1); + sprintf(enumstring, "%s(%s)", + named_number->name, string); + g_free(string); + string = enumstring; + } + } break; case SNMP_COUNTER: - variable->type = VALTYPE_COUNTER; - break; - case SNMP_GAUGE: - variable->type = VALTYPE_GAUGE; - break; - case SNMP_TIMETICKS: - variable->type = VALTYPE_TIMETICKS; + case SNMP_COUNTER64: + string = format_integer(vb_octet_string, vb_length, FALSE, + format); + if (typ != NULL && vb_length <= 4) { + /* + * OK, we have a module, and the number fits in + * an "SmiUnsigned32". Check if there's an enum + * for this. + * + * XXX - handle "SmiUnsigned64"? + */ + unsigned32 = 0; + i = 0; + while (vb_length != 0) { + unsigned32 = + (unsigned32 << 8) | vb_octet_string[i]; + i++; + vb_length--; + } + for (named_number = smiGetFirstNamedNumber(typ); + named_number != NULL; + named_number = smiGetNextNamedNumber(named_number)) { + if (named_number->value.basetype == SMI_BASETYPE_UNSIGNED32 + && named_number->value.value.unsigned32 == unsigned32) + break; + } + if (named_number != NULL) { + enumstring = g_malloc( + strlen(named_number->name) + 1 + + strlen(string) + 1 + 1); + sprintf(enumstring, "%s(%s)", + named_number->name, string); + g_free(string); + string = enumstring; + } + } break; case SNMP_OCTETSTR: - variable->type = VALTYPE_STRING; - break; - case SNMP_IPADDR: - variable->type = VALTYPE_IPADDR; - break; - case SNMP_OPAQUE: - variable->type = VALTYPE_OPAQUE; - break; - case SNMP_NSAP: - variable->type = VALTYPE_NSAP; - break; - - case SNMP_OBJECTID: - variable->type = VALTYPE_OBJECTID; - break; - case SNMP_BITSTR: - variable->type = VALTYPE_BITSTR; + string = format_string(vb_octet_string, vb_length, format); break; - case SNMP_COUNTER64: - variable->type = VALTYPE_COUNTER64; + default: + string = NULL; break; } - variable->val_len = vb_length; - sprint_value(buf, variable_oid, variable_oid_length, variable); + return string; } -#endif static int snmp_variable_decode(proto_tree *snmp_tree, subid_t *variable_oid, - guint variable_oid_length, ASN1_SCK *asn1, int offset, guint *lengthp) + guint variable_oid_length, ASN1_SCK *asn1, int offset, guint *lengthp, + SmiNode *node) { const guchar *start; guint length; @@ -540,26 +978,15 @@ int ret; guint cls, con, tag; - gint32 vb_integer_value; - guint32 vb_uinteger_value; - guint8 *vb_octet_string; subid_t *vb_oid; guint vb_oid_length; - gchar vb_display_string[MAX_STRING_LEN]; /* TBC */ + gchar *vb_display_string; -#ifdef HAVE_SPRINT_VALUE - struct variable_list variable; -#if defined(HAVE_UCD_SNMP_SNMP_H) - long value; -#endif -#else /* HAVE_SPRINT_VALUE */ - int i; - gchar *buf; - int len; -#endif /* HAVE_SPRINT_VALUE */ + SmiNode *oid_node; + gchar *oid_string; /* parse the type of the object */ start = asn1->pointer; @@ -584,113 +1011,27 @@ switch (vb_type) { case SNMP_INTEGER: - ret = asn1_int32_value_decode(asn1, vb_length, - &vb_integer_value); - if (ret != ASN1_ERR_NOERROR) - return ret; - length = asn1->pointer - start; - if (snmp_tree) { -#ifdef HAVE_SPRINT_VALUE -#if defined(HAVE_UCD_SNMP_SNMP_H) - value = vb_integer_value; - variable.val.integer = &value; -#elif defined(HAVE_SNMP_SNMP_H) - variable.val.integer = &vb_integer_value; -#endif - format_value(vb_display_string, &variable, - variable_oid, variable_oid_length, vb_type, - vb_length); - proto_tree_add_text(snmp_tree, NullTVB, offset, length, - "Value: %s", vb_display_string); -#else - proto_tree_add_text(snmp_tree, NullTVB, offset, length, - "Value: %s: %d (%#x)", vb_type_name, - vb_integer_value, vb_integer_value); -#endif - } - break; - case SNMP_COUNTER: case SNMP_GAUGE: case SNMP_TIMETICKS: - ret = asn1_uint32_value_decode(asn1, vb_length, - &vb_uinteger_value); - if (ret != ASN1_ERR_NOERROR) - return ret; - length = asn1->pointer - start; - if (snmp_tree) { -#ifdef HAVE_SPRINT_VALUE -#if defined(HAVE_UCD_SNMP_SNMP_H) - value = vb_uinteger_value; - variable.val.integer = &value; -#elif defined(HAVE_SNMP_SNMP_H) - variable.val.integer = &vb_uinteger_value; -#endif - format_value(vb_display_string, &variable, - variable_oid, variable_oid_length, vb_type, - vb_length); - proto_tree_add_text(snmp_tree, NullTVB, offset, length, - "Value: %s", vb_display_string); -#else - proto_tree_add_text(snmp_tree, NullTVB, offset, length, - "Value: %s: %u (%#x)", vb_type_name, - vb_uinteger_value, vb_uinteger_value); -#endif - } - break; - + case SNMP_COUNTER64: case SNMP_OCTETSTR: case SNMP_IPADDR: case SNMP_OPAQUE: case SNMP_NSAP: case SNMP_BITSTR: - case SNMP_COUNTER64: ret = asn1_octet_string_value_decode (asn1, vb_length, &vb_octet_string); if (ret != ASN1_ERR_NOERROR) return ret; length = asn1->pointer - start; if (snmp_tree) { -#ifdef HAVE_SPRINT_VALUE - variable.val.string = vb_octet_string; - format_value(vb_display_string, &variable, - variable_oid, variable_oid_length, vb_type, - vb_length); + vb_display_string = format_var(vb_type, vb_octet_string, + vb_length, node); proto_tree_add_text(snmp_tree, NullTVB, offset, length, - "Value: %s", vb_display_string); -#else - /* - * If some characters are not printable, display - * the string as bytes. - */ - for (i = 0; i < vb_length; i++) { - if (!(isprint(vb_octet_string[i]) - || isspace(vb_octet_string[i]))) - break; - } - if (i < vb_length) { - /* - * We stopped, due to a non-printable - * character, before we got to the end - * of the string. - */ - buf = &vb_display_string[0]; - len = sprintf(buf, "%03u", vb_octet_string[0]); - buf += len; - for (i = 1; i < vb_length; i++) { - len = sprintf(buf, ".%03u", - vb_octet_string[i]); - buf += len; - } - proto_tree_add_text(snmp_tree, NullTVB, offset, length, - "Value: %s: %s", vb_type_name, - vb_display_string); - } else { - proto_tree_add_text(snmp_tree, NullTVB, offset, length, - "Value: %s: %.*s", vb_type_name, - (int)vb_length, vb_octet_string); - } -#endif + "Value: %s: %s", vb_type_name, + vb_display_string); + g_free(vb_display_string); } g_free(vb_octet_string); break; @@ -713,18 +1054,13 @@ return ret; length = asn1->pointer - start; if (snmp_tree) { -#ifdef HAVE_SPRINT_VALUE - variable.val.objid = vb_oid; - format_value(vb_display_string, &variable, - variable_oid, variable_oid_length, vb_type, - vb_length*sizeof (subid_t)); + oid_node = smiGetNodeByOID(vb_oid_length, + (SmiSubid *)vb_oid); + oid_string = format_oid(vb_oid, vb_oid_length, + oid_node); proto_tree_add_text(snmp_tree, NullTVB, offset, length, - "Value: %s", vb_display_string); -#else - format_oid(vb_display_string, vb_oid, vb_oid_length); - proto_tree_add_text(snmp_tree, NullTVB, offset, length, - "Value: %s: %s", vb_type_name, vb_display_string); -#endif + "Value: %s: %s", vb_type_name, oid_string); + g_free(oid_string); } g_free(vb_oid); break; @@ -762,32 +1098,21 @@ } void -dissect_snmp_pdu(const u_char *pd, int offset, frame_data *fd, - proto_tree *tree, char *proto_name, int proto, gint ett) +dissect_common_pdu(const u_char *pd, int offset, frame_data *fd, + proto_tree *tree, ASN1_SCK asn1, guint pdu_type, const guchar *start) { - ASN1_SCK asn1; - const guchar *start; gboolean def; guint length; guint sequence_length; - guint message_length; - - guint32 version; - - guchar *community; - int community_length; - - guint pdu_type; - char *pdu_type_string; - guint pdu_length; - guint32 request_id; guint32 error_status; guint32 error_index; + char *pdu_type_string; + subid_t *enterprise; guint enterprise_length; @@ -801,7 +1126,7 @@ guint timestamp; guint timestamp_length; - gchar oid_string[MAX_STRING_LEN]; /* TBC */ + gchar *oid_string; guint variable_bindings_length; @@ -809,98 +1134,19 @@ guint variable_length; subid_t *variable_oid; guint variable_oid_length; -#if defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H) - gchar vb_oid_string[MAX_STRING_LEN]; /* TBC */ -#endif - proto_tree *snmp_tree = NULL; - proto_item *item = NULL; int ret; guint cls, con, tag; - - if (check_col(fd, COL_PROTOCOL)) - col_add_str(fd, COL_PROTOCOL, proto_name); - - if (tree) { - item = proto_tree_add_item(tree, proto, NullTVB, offset, END_OF_FRAME, NULL); - snmp_tree = proto_item_add_subtree(item, ett); - } - - /* NOTE: we have to parse the message piece by piece, since the - * capture length may be less than the message length: a 'global' - * parsing is likely to fail. - */ - /* parse the SNMP header */ - asn1_open(&asn1, &pd[offset], END_OF_FRAME); - ret = asn1_sequence_decode(&asn1, &message_length, &length); - if (ret != ASN1_ERR_NOERROR) { - dissect_snmp_parse_error(pd, offset, fd, tree, - "message header", ret); - return; - } - offset += length; - - ret = asn1_uint32_decode (&asn1, &version, &length); - if (ret != ASN1_ERR_NOERROR) { - dissect_snmp_parse_error(pd, offset, fd, tree, "version number", - ret); - return; - } - if (tree) { - proto_tree_add_text(snmp_tree, NullTVB, offset, length, - "Version: %s", - val_to_str(version, versions, "Unknown version %#x")); - } - offset += length; - - ret = asn1_octet_string_decode (&asn1, &community, &community_length, - &length); - if (ret != ASN1_ERR_NOERROR) { - dissect_snmp_parse_error(pd, offset, fd, tree, "community", - ret); - return; - } - if (tree) { - proto_tree_add_text(snmp_tree, NullTVB, offset, length, - "Community: %.*s", community_length, community); - } - g_free(community); - offset += length; - - switch (version) { - - case SNMP_VERSION_1: - case SNMP_VERSION_2c: - case SNMP_VERSION_2u: - case SNMP_VERSION_3: - break; - default: - dissect_snmp_error(pd, offset, fd, tree, - "PDU for unknown version of SNMP"); - return; - } + SmiNode *node; - start = asn1.pointer; - ret = asn1_header_decode (&asn1, &cls, &con, &pdu_type, &def, - &pdu_length); - if (ret != ASN1_ERR_NOERROR) { - dissect_snmp_parse_error(pd, offset, fd, tree, - "PDU type", ret); - return; - } - if (cls != ASN1_CTX || con != ASN1_CON) { - dissect_snmp_parse_error(pd, offset, fd, tree, - "PDU type", ASN1_ERR_WRONG_TYPE); - return; - } pdu_type_string = val_to_str(pdu_type, pdu_types, "Unknown PDU type %#x"); if (check_col(fd, COL_INFO)) col_add_str(fd, COL_INFO, pdu_type_string); length = asn1.pointer - start; if (tree) { - proto_tree_add_text(snmp_tree, NullTVB, offset, length, + proto_tree_add_text(tree, NullTVB, offset, length, "PDU type: %s", pdu_type_string); } offset += length; @@ -915,6 +1161,7 @@ case SNMP_MSG_GETBULK: case SNMP_MSG_INFORM: case SNMP_MSG_TRAP2: + case SNMP_MSG_REPORT: /* request id */ ret = asn1_uint32_decode (&asn1, &request_id, &length); if (ret != ASN1_ERR_NOERROR) { @@ -923,7 +1170,7 @@ return; } if (tree) { - proto_tree_add_text(snmp_tree, NullTVB, offset, length, + proto_tree_add_text(tree, NullTVB, offset, length, "Request Id: %#x", request_id); } offset += length; @@ -939,11 +1186,11 @@ } if (tree) { if (pdu_type == SNMP_MSG_GETBULK) { - proto_tree_add_text(snmp_tree, NullTVB, offset, length, - "Non-repeaters: %u", error_status); + proto_tree_add_text(tree, NullTVB, offset, + length, "Non-repeaters: %u", error_status); } else { - proto_tree_add_text(snmp_tree, NullTVB, offset, length, - "Error Status: %s", + proto_tree_add_text(tree, NullTVB, offset, + length, "Error Status: %s", val_to_str(error_status, error_statuses, "Unknown (%d)")); } @@ -961,11 +1208,11 @@ } if (tree) { if (pdu_type == SNMP_MSG_GETBULK) { - proto_tree_add_text(snmp_tree, NullTVB, offset, length, - "Max repetitions: %u", error_index); + proto_tree_add_text(tree, NullTVB, offset, + length, "Max repetitions: %u", error_index); } else { - proto_tree_add_text(snmp_tree, NullTVB, offset, length, - "Error Index: %u", error_index); + proto_tree_add_text(tree, NullTVB, offset, + length, "Error Index: %u", error_index); } } offset += length; @@ -981,9 +1228,13 @@ return; } if (tree) { - format_oid(oid_string, enterprise, enterprise_length); - proto_tree_add_text(snmp_tree, NullTVB, offset, length, + node = smiGetNodeByOID(enterprise_length, + (SmiSubid *)enterprise); + oid_string = format_oid(enterprise, enterprise_length, + node); + proto_tree_add_text(tree, NullTVB, offset, length, "Enterprise: %s", oid_string); + g_free(oid_string); } g_free(enterprise); offset += length; @@ -1019,7 +1270,8 @@ } length = asn1.pointer - start; if (tree) { - proto_tree_add_text(snmp_tree, NullTVB, offset, agent_address_length, + proto_tree_add_text(tree, NullTVB, offset, + agent_address_length, "Agent address: %s", ip_to_str(agent_address)); } g_free(agent_address); @@ -1033,7 +1285,7 @@ return; } if (tree) { - proto_tree_add_text(snmp_tree, NullTVB, offset, length, + proto_tree_add_text(tree, NullTVB, offset, length, "Trap type: %s", val_to_str(trap_type, trap_types, "Unknown (%u)")); } @@ -1047,7 +1299,7 @@ return; } if (tree) { - proto_tree_add_text(snmp_tree, NullTVB, offset, length, + proto_tree_add_text(tree, NullTVB, offset, length, "Specific trap type: %u (%#x)", specific_type, specific_type); } @@ -1077,7 +1329,7 @@ } length = asn1.pointer - start; if (tree) { - proto_tree_add_text(snmp_tree, NullTVB, offset, length, + proto_tree_add_text(tree, NullTVB, offset, length, "Timestamp: %u", timestamp); } offset += length; @@ -1119,29 +1371,22 @@ } sequence_length += length; + node = smiGetNodeByOID(variable_oid_length, + (SmiSubid *)variable_oid); if (tree) { - format_oid(oid_string, variable_oid, - variable_oid_length); - -#if defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H) - sprint_objid(vb_oid_string, variable_oid, - variable_oid_length); - proto_tree_add_text(snmp_tree, NullTVB, offset, sequence_length, - "Object identifier %d: %s (%s)", vb_index, - oid_string, vb_oid_string); -#else - - proto_tree_add_text(snmp_tree, NullTVB, offset, sequence_length, - "Object identifier %d: %s", vb_index, - oid_string); -#endif + oid_string = format_oid(variable_oid, + variable_oid_length, node); + proto_tree_add_text(tree, NullTVB, offset, + sequence_length, + "Object identifier %d: %s", vb_index, oid_string); + g_free(oid_string); } offset += sequence_length; variable_bindings_length -= sequence_length; /* Parse the variable's value */ - ret = snmp_variable_decode(snmp_tree, variable_oid, - variable_oid_length, &asn1, offset, &length); + ret = snmp_variable_decode(tree, variable_oid, + variable_oid_length, &asn1, offset, &length, node); if (ret != ASN1_ERR_NOERROR) { dissect_snmp_parse_error(pd, offset, fd, tree, "variable", ret); @@ -1153,31 +1398,747 @@ } void +dissect_snmp_pdu(const u_char *pd, int offset, frame_data *fd, + proto_tree *tree, char *proto_name, int proto, gint ett) +{ + ASN1_SCK asn1; + const guchar *start; + gboolean def; + gboolean encrypted; + guint length; + guint message_length; + guint global_length; + + guint32 version; + guint32 msgid; + guint32 msgmax; + guint32 msgsec; + guint32 engineboots; + guint32 enginetime; + + guchar *msgflags; + guchar *community; + guchar *secparm; + guchar *cengineid; + guchar *cname; + guchar *cryptpdu; + guchar *aengineid; + guchar *username; + guchar *authpar; + guchar *privpar; + int msgflags_length; + int community_length; + int secparm_length; + int cengineid_length; + int cname_length; + int cryptpdu_length; + int aengineid_length; + int username_length; + int authpar_length; + int privpar_length; + + guchar *cengineid_string; + guchar *aengineid_string; + guchar *authpar_string; + guchar *privpar_string; + + guint pdu_type; + guint pdu_length; + + proto_tree *snmp_tree = NULL; + proto_tree *global_tree = NULL; + proto_tree *flags_tree = NULL; + proto_tree *secur_tree = NULL; + proto_item *item = NULL; + int ret; + guint cls, con, tag; + + if (check_col(fd, COL_PROTOCOL)) + col_add_str(fd, COL_PROTOCOL, proto_name); + + if (tree) { + item = proto_tree_add_item(tree, proto, NullTVB, offset, + END_OF_FRAME, NULL); + snmp_tree = proto_item_add_subtree(item, ett); + } + + /* NOTE: we have to parse the message piece by piece, since the + * capture length may be less than the message length: a 'global' + * parsing is likely to fail. + */ + /* parse the SNMP header */ + asn1_open(&asn1, &pd[offset], END_OF_FRAME); + ret = asn1_sequence_decode(&asn1, &message_length, &length); + if (ret != ASN1_ERR_NOERROR) { + dissect_snmp_parse_error(pd, offset, fd, tree, + "message header", ret); + return; + } + offset += length; + + ret = asn1_uint32_decode (&asn1, &version, &length); + if (ret != ASN1_ERR_NOERROR) { + dissect_snmp_parse_error(pd, offset, fd, tree, "version number", + ret); + return; + } + if (snmp_tree) { + proto_tree_add_text(snmp_tree, NullTVB, offset, length, + "Version: %s", + val_to_str(version, versions, "Unknown version %#x")); + } + offset += length; + + + switch (version) { + case SNMP_VERSION_1: + case SNMP_VERSION_2c: + ret = asn1_octet_string_decode (&asn1, &community, + &community_length, &length); + if (ret != ASN1_ERR_NOERROR) { + dissect_snmp_parse_error(pd, offset, fd, tree, + "community", ret); + return; + } + if (tree) { + proto_tree_add_text(snmp_tree, NullTVB, offset, length, + "Community: %.*s", community_length, community); + } + g_free(community); + offset += length; + break; + case SNMP_VERSION_2u: + /* FIXME */ + break; + case SNMP_VERSION_3: + ret = asn1_sequence_decode(&asn1, &global_length, &length); + if (ret != ASN1_ERR_NOERROR) { + dissect_snmp_parse_error(pd, offset, fd, tree, + "message global header", ret); + return; + } + if (snmp_tree) { + item = proto_tree_add_text(snmp_tree, NullTVB, offset, + global_length + length, "Message Global Header"); + global_tree = proto_item_add_subtree(item, ett_global); + proto_tree_add_text(global_tree, NullTVB, offset, + length, + "Message Global Header Length: %d", global_length); + } + offset += length; + ret = asn1_uint32_decode (&asn1, &msgid, &length); + if (ret != ASN1_ERR_NOERROR) { + dissect_snmp_parse_error(pd, offset, fd, tree, + "message id", ret); + return; + } + if (global_tree) { + proto_tree_add_text(global_tree, NullTVB, offset, + length, "Message ID: %d", msgid); + } + offset += length; + ret = asn1_uint32_decode (&asn1, &msgmax, &length); + if (ret != ASN1_ERR_NOERROR) { + dissect_snmp_parse_error(pd, offset, fd, tree, + "message max size", ret); + return; + } + if (global_tree) { + proto_tree_add_text(global_tree, NullTVB, offset, + length, "Message Max Size: %d", msgmax); + } + offset += length; + ret = asn1_octet_string_decode (&asn1, &msgflags, + &msgflags_length, &length); + if (ret != ASN1_ERR_NOERROR) { + dissect_snmp_parse_error(pd, offset, fd, tree, + "message flags", ret); + return; + } + if (msgflags_length != 1) { + dissect_snmp_parse_error(pd, offset, fd, tree, + "message flags wrong length", ret); + g_free(msgflags); + return; + } + if (global_tree) { + item = proto_tree_add_uint_format(global_tree, + hf_snmpv3_flags, NullTVB, offset, length, + msgflags[0], "Flags: 0x%02x", msgflags[0]); + flags_tree = proto_item_add_subtree(item, ett_flags); + proto_tree_add_item(flags_tree, hf_snmpv3_flags_report, + NullTVB, offset, length, msgflags[0]); + proto_tree_add_item(flags_tree, hf_snmpv3_flags_crypt, + NullTVB, offset, length, msgflags[0]); + proto_tree_add_item(flags_tree, hf_snmpv3_flags_auth, + NullTVB, offset, length, msgflags[0]); + } + encrypted = msgflags[0] & TH_CRYPT; + g_free(msgflags); + offset += length; + ret = asn1_uint32_decode (&asn1, &msgsec, &length); + if (ret != ASN1_ERR_NOERROR) { + dissect_snmp_parse_error(pd, offset, fd, tree, + "message security model", ret); + return; + } + if (global_tree) { + proto_tree_add_text(global_tree, NullTVB, offset, + length, "Message Security Model: %s", + val_to_str(msgsec, sec_models, + "Unknown model %#x")); + } + offset += length; + switch(msgsec) { + case SNMP_SEC_V1: + case SNMP_SEC_V2C: + ret = asn1_octet_string_decode (&asn1, + &secparm, &secparm_length, &length); + if (ret != ASN1_ERR_NOERROR) { + dissect_snmp_parse_error(pd, offset, fd, tree, + "Message Security Parameters", ret); + return; + } + if (snmp_tree) { + proto_tree_add_text(snmp_tree, NullTVB, offset, + length, "Message Security Parameters: %.*s", + secparm_length, secparm); + } + g_free(secparm); + offset += length; + break; + case SNMP_SEC_USM: + start = asn1.pointer; + ret = asn1_header_decode (&asn1, &cls, &con, &tag, + &def, &secparm_length); + length = asn1.pointer - start; + if (cls != ASN1_UNI && con != ASN1_PRI && + tag != ASN1_OTS) { + dissect_snmp_parse_error(pd, offset, fd, tree, + "Message Security Parameters", + ASN1_ERR_WRONG_TYPE); + return; + } + if (snmp_tree) { + item = proto_tree_add_text(snmp_tree, NullTVB, + offset, secparm_length + length, + "Message Security Parameters"); + secur_tree = proto_item_add_subtree(item, + ett_secur); + proto_tree_add_text(secur_tree, NullTVB, offset, + length, + "Message Security Parameters Length: %d", + secparm_length); + } + offset += length; + ret = asn1_sequence_decode(&asn1, &secparm_length, + &length); + if (ret != ASN1_ERR_NOERROR) { + dissect_snmp_parse_error(pd, offset, fd, tree, + "USM sequence header", ret); + return; + } + offset += length; + ret = asn1_octet_string_decode (&asn1, &aengineid, + &aengineid_length, &length); + if (ret != ASN1_ERR_NOERROR) { + dissect_snmp_parse_error(pd, offset, fd, tree, + "authoritative engine id", ret); + return; + } + if (secur_tree) { + aengineid_string = format_string(aengineid, + aengineid_length, "1x "); + proto_tree_add_text(secur_tree, NullTVB, offset, + length, "Authoritative Engine ID: %s", + aengineid_string); + g_free(aengineid_string); + } + g_free(aengineid); + offset += length; + ret = asn1_uint32_decode (&asn1, &engineboots, &length); + if (ret != ASN1_ERR_NOERROR) { + dissect_snmp_parse_error(pd, offset, fd, tree, + "engine boots", ret); + return; + } + if (secur_tree) { + proto_tree_add_text(secur_tree, NullTVB, + offset, length, "Engine Boots: %d", + engineboots); + } + offset += length; + ret = asn1_uint32_decode (&asn1, &enginetime, &length); + if (ret != ASN1_ERR_NOERROR) { + dissect_snmp_parse_error(pd, offset, fd, tree, + "engine time", ret); + return; + } + if (secur_tree) { + proto_tree_add_text(secur_tree, NullTVB, + offset, length, "Engine Time: %d", + enginetime); + } + offset += length; + ret = asn1_octet_string_decode (&asn1, &username, + &username_length, &length); + if (ret != ASN1_ERR_NOERROR) { + dissect_snmp_parse_error(pd, offset, fd, tree, + "user name", ret); + return; + } + if (secur_tree) { + proto_tree_add_text(secur_tree, NullTVB, offset, + length, "User Name: %.*s", + username_length, username); + } + g_free(username); + offset += length; + ret = asn1_octet_string_decode (&asn1, &authpar, + &authpar_length, &length); + if (ret != ASN1_ERR_NOERROR) { + dissect_snmp_parse_error(pd, offset, fd, tree, + "authentication parameter", ret); + return; + } + if (secur_tree) { + authpar_string = format_string(authpar, + authpar_length, "1x "); + proto_tree_add_text(secur_tree, NullTVB, offset, + length, "Authentication Parameter: %s", + authpar_string); + g_free(authpar_string); + } + g_free(authpar); + offset += length; + ret = asn1_octet_string_decode (&asn1, &privpar, + &privpar_length, &length); + if (ret != ASN1_ERR_NOERROR) { + dissect_snmp_parse_error(pd, offset, fd, tree, + "privacy parameter", ret); + return; + } + if (secur_tree) { + privpar_string = format_string(privpar, + privpar_length, "1x "); + proto_tree_add_text(secur_tree, NullTVB, offset, + length, "Privacy Parameter: %s", + privpar_string); + g_free(privpar_string); + } + g_free(privpar); + offset += length; + break; + default: + ret = asn1_octet_string_decode (&asn1, + &secparm, &secparm_length, &length); + if (ret != ASN1_ERR_NOERROR) { + dissect_snmp_parse_error(pd, offset, fd, tree, + "Message Security Parameters", ret); + return; + } + if (snmp_tree) { + proto_tree_add_text(snmp_tree, NullTVB, offset, + length, + "Message Security Parameters Data" + " (%d bytes)", secparm_length); + } + g_free(secparm); + offset += length; + break; + } + /* PDU starts here */ + if (encrypted) { + ret = asn1_octet_string_decode (&asn1, &cryptpdu, + &cryptpdu_length, &length); + if (ret != ASN1_ERR_NOERROR) { + dissect_snmp_parse_error(pd, offset, fd, tree, + "encrypted PDU header", ret); + return; + } + proto_tree_add_text(snmp_tree, NullTVB, offset, length, + "Encrypted PDU (%d bytes)", length); + g_free(cryptpdu); + if (check_col(fd, COL_INFO)) + col_add_str(fd, COL_INFO, "Encrypted PDU"); + return; + } + ret = asn1_sequence_decode(&asn1, &global_length, &length); + if (ret != ASN1_ERR_NOERROR) { + dissect_snmp_parse_error(pd, offset, fd, tree, + "PDU header", ret); + return; + } + offset += length; + ret = asn1_octet_string_decode (&asn1, &cengineid, + &cengineid_length, &length); + if (ret != ASN1_ERR_NOERROR) { + dissect_snmp_parse_error(pd, offset, fd, tree, + "context engine id", ret); + return; + } + if (snmp_tree) { + cengineid_string = format_string(cengineid, + cengineid_length, "1x "); + proto_tree_add_text(snmp_tree, NullTVB, offset, length, + "Context Engine ID: %s", cengineid_string); + g_free(cengineid_string); + } + g_free(cengineid); + offset += length; + ret = asn1_octet_string_decode (&asn1, &cname, + &cname_length, &length); + if (ret != ASN1_ERR_NOERROR) { + dissect_snmp_parse_error(pd, offset, fd, tree, + "context name", ret); + return; + } + if (snmp_tree) { + proto_tree_add_text(snmp_tree, NullTVB, offset, length, + "Context Name: %s", cname); + } + g_free(cname); + offset += length; + break; + default: + dissect_snmp_error(pd, offset, fd, tree, + "PDU for unknown version of SNMP"); + return; + } + + start = asn1.pointer; + ret = asn1_header_decode (&asn1, &cls, &con, &pdu_type, &def, + &pdu_length); + if (ret != ASN1_ERR_NOERROR) { + dissect_snmp_parse_error(pd, offset, fd, tree, + "PDU type", ret); + return; + } + if (cls != ASN1_CTX || con != ASN1_CON) { + dissect_snmp_parse_error(pd, offset, fd, tree, + "PDU type", ASN1_ERR_WRONG_TYPE); + return; + } + dissect_common_pdu(pd, offset, fd, snmp_tree, asn1, pdu_type, start); +} + +void +dissect_smux_pdu(const u_char *pd, int offset, frame_data *fd, + proto_tree *tree, char *proto_name, int proto, gint ett) +{ + ASN1_SCK asn1; + const guchar *start; + gboolean def; + guint length; + + guint pdu_type; + char *pdu_type_string; + guint pdu_length; + + guint32 version; + guint32 cause; + guint32 priority; + guint32 operation; + guint32 commit; + + guchar *password; + int password_length; + + guchar *application; + int application_length; + + subid_t *regid; + guint regid_length; + + gchar *oid_string; + + proto_tree *smux_tree = NULL; + proto_item *item = NULL; + int ret; + guint cls, con; + + SmiNode *node; + + if (check_col(fd, COL_PROTOCOL)) + col_add_str(fd, COL_PROTOCOL, proto_name); + + if (tree) { + item = proto_tree_add_item(tree, proto, NullTVB, offset, + END_OF_FRAME, NULL); + smux_tree = proto_item_add_subtree(item, ett); + } + + /* NOTE: we have to parse the message piece by piece, since the + * capture length may be less than the message length: a 'global' + * parsing is likely to fail. + */ + /* parse the SNMP header */ + asn1_open(&asn1, &pd[offset], END_OF_FRAME); + start = asn1.pointer; + ret = asn1_header_decode (&asn1, &cls, &con, &pdu_type, &def, + &pdu_length); + if (ret != ASN1_ERR_NOERROR) { + dissect_snmp_parse_error(pd, offset, fd, tree, + "PDU type", ret); + return; + } + /* Dissect SMUX here */ + if (cls == ASN1_APL && con == ASN1_CON && pdu_type == SMUX_MSG_OPEN) { + pdu_type_string = val_to_str(pdu_type, smux_types, + "Unknown PDU type %#x"); + if (check_col(fd, COL_INFO)) + col_add_str(fd, COL_INFO, pdu_type_string); + length = asn1.pointer - start; + if (tree) { + proto_tree_add_text(smux_tree, NullTVB, offset, length, + "PDU type: %s", pdu_type_string); + } + offset += length; + ret = asn1_uint32_decode (&asn1, &version, &length); + if (ret != ASN1_ERR_NOERROR) { + dissect_snmp_parse_error(pd, offset, fd, tree, + "version", ret); + return; + } + if (tree) { + proto_tree_add_text(smux_tree, NullTVB, offset, length, + "Version: %d", version); + } + offset += length; + + ret = asn1_oid_decode (&asn1, ®id, ®id_length, &length); + if (ret != ASN1_ERR_NOERROR) { + dissect_snmp_parse_error(pd, offset, fd, tree, + "registration OID", ret); + return; + } + if (tree) { + node = smiGetNodeByOID(regid_length, + (SmiSubid *)regid); + oid_string = format_oid(regid, regid_length, node); + proto_tree_add_text(smux_tree, NullTVB, offset, length, + "Registration: %s", oid_string); + g_free(oid_string); + } + g_free(regid); + offset += length; + + ret = asn1_octet_string_decode (&asn1, &application, + &application_length, &length); + if (ret != ASN1_ERR_NOERROR) { + dissect_snmp_parse_error(pd, offset, fd, tree, + "application", ret); + return; + } + if (tree) { + proto_tree_add_text(smux_tree, NullTVB, offset, length, + "Application: %.*s", application_length, + application); + } + g_free(application); + offset += length; + + ret = asn1_octet_string_decode (&asn1, &password, + &password_length, &length); + if (ret != ASN1_ERR_NOERROR) { + dissect_snmp_parse_error(pd, offset, fd, tree, + "password", ret); + return; + } + if (tree) { + proto_tree_add_text(smux_tree, NullTVB, offset, length, + "Password: %.*s", password_length, password); + } + g_free(password); + offset += length; + return; + } + if (cls == ASN1_APL && con == ASN1_PRI && pdu_type == SMUX_MSG_CLOSE) { + pdu_type_string = val_to_str(pdu_type, smux_types, + "Unknown PDU type %#x"); + if (check_col(fd, COL_INFO)) + col_add_str(fd, COL_INFO, pdu_type_string); + length = asn1.pointer - start; + if (tree) { + proto_tree_add_text(smux_tree, NullTVB, offset, length, + "PDU type: %s", pdu_type_string); + } + offset += length; + ret = asn1_uint32_value_decode (&asn1, pdu_length, &cause); + if (ret != ASN1_ERR_NOERROR) { + dissect_snmp_parse_error(pd, offset, fd, tree, + "cause", ret); + return; + } + if (tree) { + proto_tree_add_text(smux_tree, NullTVB, offset, + pdu_length, "Cause: %s", + val_to_str(cause, smux_close, + "Unknown cause %#x")); + } + offset += pdu_length; + return; + } + if (cls == ASN1_APL && con == ASN1_CON && pdu_type == SMUX_MSG_RREQ) { + pdu_type_string = val_to_str(pdu_type, smux_types, + "Unknown PDU type %#x"); + if (check_col(fd, COL_INFO)) + col_add_str(fd, COL_INFO, pdu_type_string); + length = asn1.pointer - start; + if (tree) { + proto_tree_add_text(smux_tree, NullTVB, offset, length, + "PDU type: %s", pdu_type_string); + } + offset += length; + ret = asn1_oid_decode (&asn1, ®id, ®id_length, &length); + if (ret != ASN1_ERR_NOERROR) { + dissect_snmp_parse_error(pd, offset, fd, tree, + "registration subtree", ret); + return; + } + if (tree) { + node = smiGetNodeByOID(regid_length, + (SmiSubid *)regid); + oid_string = format_oid(regid, regid_length, node); + proto_tree_add_text(smux_tree, NullTVB, offset, length, + "Registration: %s", oid_string); + g_free(oid_string); + } + g_free(regid); + offset += length; + + ret = asn1_uint32_decode (&asn1, &priority, &length); + if (ret != ASN1_ERR_NOERROR) { + dissect_snmp_parse_error(pd, offset, fd, tree, + "priority", ret); + return; + } + if (tree) { + proto_tree_add_text(smux_tree, NullTVB, offset, length, + "Priority: %d", priority); + } + offset += length; + + ret = asn1_uint32_decode (&asn1, &operation, &length); + if (ret != ASN1_ERR_NOERROR) { + dissect_snmp_parse_error(pd, offset, fd, tree, + "operation", ret); + return; + } + if (tree) { + proto_tree_add_text(smux_tree, NullTVB, offset, length, + "Operation: %s", + val_to_str(operation, smux_rreq, + "Unknown operation %#x")); + } + offset += length; + return; + } + if (cls == ASN1_APL && con == ASN1_PRI && pdu_type == SMUX_MSG_RRSP) { + pdu_type_string = val_to_str(pdu_type, smux_types, + "Unknown PDU type %#x"); + if (check_col(fd, COL_INFO)) + col_add_str(fd, COL_INFO, pdu_type_string); + length = asn1.pointer - start; + if (tree) { + proto_tree_add_text(smux_tree, NullTVB, offset, length, + "PDU type: %s", pdu_type_string); + } + offset += length; + ret = asn1_uint32_value_decode (&asn1, pdu_length, &priority); + if (ret != ASN1_ERR_NOERROR) { + dissect_snmp_parse_error(pd, offset, fd, tree, + "priority", ret); + return; + } + if (tree) { + proto_tree_add_text(smux_tree, NullTVB, offset, + pdu_length, "%s", + val_to_str(priority, smux_prio, + "Priority: %#x")); + } + offset += pdu_length; + return; + } + if (cls == ASN1_APL && con == ASN1_PRI && pdu_type == SMUX_MSG_SOUT) { + pdu_type_string = val_to_str(pdu_type, smux_types, + "Unknown PDU type %#x"); + if (check_col(fd, COL_INFO)) + col_add_str(fd, COL_INFO, pdu_type_string); + length = asn1.pointer - start; + if (tree) { + proto_tree_add_text(smux_tree, NullTVB, offset, length, + "PDU type: %s", pdu_type_string); + } + offset += length; + ret = asn1_uint32_value_decode (&asn1, pdu_length, &commit); + if (ret != ASN1_ERR_NOERROR) { + dissect_snmp_parse_error(pd, offset, fd, tree, + "commit", ret); + return; + } + if (tree) { + proto_tree_add_text(smux_tree, NullTVB, offset, + pdu_length, "%s", + val_to_str(commit, smux_sout, + "Unknown SOUT Value: %#x")); + } + offset += pdu_length; + return; + } + if (cls != ASN1_CTX || con != ASN1_CON) { + dissect_snmp_parse_error(pd, offset, fd, tree, + "PDU type", ASN1_ERR_WRONG_TYPE); + return; + } + dissect_common_pdu(pd, offset, fd, smux_tree, asn1, pdu_type, start); +} + +void dissect_snmp(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) { dissect_snmp_pdu(pd, offset, fd, tree, "SNMP", proto_snmp, ett_snmp); } void +dissect_smux(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) +{ + dissect_smux_pdu(pd, offset, fd, tree, "SMUX", proto_smux, ett_smux); +} + +void proto_register_snmp(void) { -/* static hf_register_info hf[] = { - { &variable, + static hf_register_info hf[] = { + { &hf_snmpv3_flags, + { "SNMPv3 Flags", "snmpv3.flags", FT_UINT8, BASE_HEX, NULL, + 0x0, "" }}, + { &hf_snmpv3_flags_auth, + { "Authenticated", "snmpv3.flags.auth", FT_BOOLEAN, 8, + TFS(&flags_set_truth), TH_AUTH, "" }}, + { &hf_snmpv3_flags_crypt, + { "Encrypted", "snmpv3.flags.crypt", FT_BOOLEAN, 8, + TFS(&flags_set_truth), TH_CRYPT, "" }}, + { &hf_snmpv3_flags_report, + { "Reportable", "snmpv3.flags.report", FT_BOOLEAN, 8, + TFS(&flags_set_truth), TH_REPORT, "" }}, +/* + { &hf_variable, { "Name", "snmp.abbreviation", TYPE, VALS_POINTER }}, - };*/ +*/ + }; static gint *ett[] = { &ett_snmp, + &ett_smux, + &ett_global, + &ett_flags, + &ett_secur, }; -#if defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H) - /* UCD or CMU SNMP */ - init_mib(); -#ifdef HAVE_UCD_SNMP_SNMP_H - snmp_set_full_objid(TRUE); -#endif -#endif + smiInit("ethereal"); proto_snmp = proto_register_protocol("Simple Network Management Protocol", "snmp"); - /* proto_register_field_array(proto_snmp, hf, array_length(hf));*/ + proto_smux = proto_register_protocol("SNMP Multiplex Protocol", "smux"); + proto_register_field_array(proto_snmp, hf, array_length(hf)); proto_register_subtree_array(ett, array_length(ett)); } @@ -1186,5 +2147,6 @@ { dissector_add("udp.port", UDP_PORT_SNMP, dissect_snmp); dissector_add("udp.port", UDP_PORT_SNMP_TRAP, dissect_snmp); + dissector_add("tcp.port", TCP_PORT_SMUX, dissect_smux); dissector_add("ethertype", ETHERTYPE_SNMP, dissect_snmp); } Index: packet-snmp.h =================================================================== RCS file: /cvsroot/ethereal/packet-snmp.h,v retrieving revision 1.3 diff -u -r1.3 packet-snmp.h --- packet-snmp.h 2000/02/15 21:03:10 1.3 +++ packet-snmp.h 2000/05/14 21:53:59 @@ -25,6 +25,7 @@ */ void dissect_snmp(const u_char *, int, frame_data *, proto_tree *); +void dissect_smux(const u_char *, int, frame_data *, proto_tree *); /* * Guts of the SNMP dissector - exported for use by protocols such as
- Follow-Ups:
- Re: [ethereal-dev] SNMP Patch
- From: Guy Harris
- Re: [ethereal-dev] SNMP Patch
- Prev by Date: Re: [ethereal-dev] Exception code checked in
- Next by Date: Re: [ethereal-dev] SNMP Patch
- Previous by thread: Re: [ethereal-dev] Getting rid of "proto_tree_add_item()"?
- Next by thread: Re: [ethereal-dev] SNMP Patch
- Index(es):