Ethereal-dev: Re: [ethereal-dev] packet-snmp.c and libsmi
Note: This archive is from the project's previous web site, ethereal.com. This list is no longer active.
From: Jochen Friedrich <jochen@xxxxxxxx>
Date: Fri, 23 Jun 2000 19:34:05 +0200 (CEST)
Hi Guy, Juergen, On Fri, 23 Jun 2000, Guy Harris wrote: > I don't know whether any performance work has been done on the > MIB-reading code; I haven't yet done a profiled run of Ethereal (or > Tethereal) linked with libsmi to see if there's any low-hanging fruit. In any case, i attach the current SMI code from my tree. Maybe Juergen can check, if there are any possibilities to speed things up. (Guy, it's still the same code that you sent me some time ago. This recursive call of format_oid_name has to go, i know :) ). Cheers, Jochen
Index: packet-snmp.c =================================================================== RCS file: /cvsroot/ethereal/packet-snmp.c,v retrieving revision 1.37 diff -u -r1.37 packet-snmp.c --- packet-snmp.c 2000/06/17 05:56:22 1.37 +++ packet-snmp.c 2000/06/23 18:27:47 @@ -47,147 +47,20 @@ #define MAX_STRING_LEN 1024 /* TBC */ +#include <glib.h> +#ifdef HAVE_SMI_H +#include <smi.h> +#else +typedef void SmiNode; +#endif + #ifdef linux #include <dlfcn.h> #endif -#include <glib.h> - #include "packet.h" #include "etypes.h" #include "packet-ipx.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.1 makes "snmp_set_suffix_only()" a macro - * that calls "ds_set_int()" with the first two arguments - * being DS_LIBRARY_ID and DS_LIB_PRINT_SUFFIX_ONLY; this means that, - * when building with 4.1.1, we need to arrange that - * <ucd-snmp/default_store.h> is included, to define those two values - * and to declare "ds_int()". - * - * 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_suffix_only -# 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" @@ -469,6 +342,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 @@ -555,11 +755,47 @@ } static void -format_oid(gchar *buf, subid_t *oid, guint oid_length) +format_oid_name(subid_t *oid, guint oid_length, char **name, guint name_length, + SmiNode *node) { - int i; - int len; +#ifdef HAVE_SMI_H + SmiNode *child; +#endif + int len, i; + char *buf; +#ifdef HAVE_SMI_H + 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; + } +#endif + *name = g_malloc(name_length); + buf = *name; len = sprintf(buf, "%lu", (unsigned long)oid[0]); buf += len; for (i = 1; i < oid_length;i++) { @@ -568,68 +804,200 @@ } } -#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; +#ifdef HAVE_SMI_H + int len, i; + char *buf; +#endif + + result = NULL; + format_oid_name(oid, oid_length, &result, oid_length * 22 + 5, node); +#ifdef HAVE_SMI_H + 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, ")"); + } +#endif + 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; +#ifdef HAVE_SMI_H + SmiType *typ; +#endif + gchar *string; + char *format; + int i; +#ifdef HAVE_SMI_H + SmiInteger32 integer32; + SmiUnsigned32 unsigned32; + SmiNamedNumber *named_number; + gchar *enumstring; +#endif + +#ifdef HAVE_SMI_H + typ = smiGetNodeType(node); + if (typ != NULL) + format = typ->format; + else + format = NULL; +#else + format = NULL; +#endif + + if (format == NULL) { + switch (vb_type) { + + case SNMP_INTEGER: + case SNMP_COUNTER: + case SNMP_GAUGE: + case SNMP_TIMETICKS: + /* XXX - display as "(X) N days, HH:MM:SS.SS"? */ + 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); +#ifdef HAVE_SMI_H + 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; + } + } +#endif 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); +#ifdef HAVE_SMI_H + 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; + } + } +#endif 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; @@ -640,26 +1008,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; @@ -684,113 +1041,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; @@ -813,18 +1084,17 @@ 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)); - proto_tree_add_text(snmp_tree, NullTVB, offset, length, - "Value: %s", vb_display_string); +#ifdef HAVE_SMI_H + oid_node = smiGetNodeByOID(vb_oid_length, + (SmiSubid *)vb_oid); #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); + oid_node = NULL; #endif + oid_string = format_oid(vb_oid, vb_oid_length, + oid_node); + proto_tree_add_text(snmp_tree, NullTVB, offset, length, + "Value: %s: %s", vb_type_name, oid_string); + g_free(oid_string); } g_free(vb_oid); break; @@ -861,7 +1131,7 @@ return ASN1_ERR_NOERROR; } -static void +void dissect_common_pdu(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, ASN1_SCK asn1, guint pdu_type, const guchar *start) { @@ -890,7 +1160,7 @@ guint timestamp; guint timestamp_length; - gchar oid_string[MAX_STRING_LEN]; /* TBC */ + gchar *oid_string; guint variable_bindings_length; @@ -898,13 +1168,12 @@ 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 int ret; guint cls, con, tag; + SmiNode *node; + pdu_type_string = val_to_str(pdu_type, pdu_types, "Unknown PDU type %#x"); if (check_col(fd, COL_INFO)) @@ -993,9 +1262,17 @@ return; } if (tree) { - format_oid(oid_string, enterprise, enterprise_length); +#ifdef HAVE_SMI_H + node = smiGetNodeByOID(enterprise_length, + (SmiSubid *)enterprise); +#else + node = NULL; +#endif + 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; @@ -1132,29 +1409,26 @@ } sequence_length += length; - 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(tree, NullTVB, offset, sequence_length, - "Object identifier %d: %s (%s)", vb_index, - oid_string, vb_oid_string); +#ifdef HAVE_SMI_H + node = smiGetNodeByOID(variable_oid_length, + (SmiSubid *)variable_oid); #else - - proto_tree_add_text(tree, NullTVB, offset, sequence_length, - "Object identifier %d: %s", vb_index, - oid_string); + node = NULL; #endif + if (tree) { + 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(tree, variable_oid, - variable_oid_length, &asn1, offset, &length); + variable_oid_length, &asn1, offset, &length, node); if (ret != ASN1_ERR_NOERROR) { dissect_snmp_parse_error(pd, offset, fd, tree, "variable", ret); @@ -1205,6 +1479,11 @@ int authpar_length; int privpar_length; + guchar *cengineid_string; + guchar *aengineid_string; + guchar *authpar_string; + guchar *privpar_string; + guint pdu_type; guint pdu_length; @@ -1410,9 +1689,12 @@ 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", - bytes_to_str(aengineid, aengineid_length)); + aengineid_string); + g_free(aengineid_string); } g_free(aengineid); offset += length; @@ -1462,9 +1744,12 @@ return; } if (secur_tree) { + authpar_string = format_string(authpar, + authpar_length, "1x "); proto_tree_add_text(secur_tree, NullTVB, offset, length, "Authentication Parameter: %s", - bytes_to_str(authpar, authpar_length)); + authpar_string); + g_free(authpar_string); } g_free(authpar); offset += length; @@ -1476,9 +1761,12 @@ return; } if (secur_tree) { + privpar_string = format_string(privpar, + privpar_length, "1x "); proto_tree_add_text(secur_tree, NullTVB, offset, length, "Privacy Parameter: %s", - bytes_to_str(privpar, privpar_length)); + privpar_string); + g_free(privpar_string); } g_free(privpar); offset += length; @@ -1532,9 +1820,11 @@ 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", - bytes_to_str(cengineid, cengineid_length)); + "Context Engine ID: %s", cengineid_string); + g_free(cengineid_string); } g_free(cengineid); offset += length; @@ -1602,13 +1892,15 @@ subid_t *regid; guint regid_length; - gchar oid_string[MAX_STRING_LEN]; /* TBC */ + 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, "SMUX"); @@ -1632,6 +1924,7 @@ "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, @@ -1663,9 +1956,16 @@ return; } if (tree) { - format_oid(oid_string, regid, regid_length); +#ifdef HAVE_SMI_H + node = smiGetNodeByOID(regid_length, + (SmiSubid *)regid); +#else + node = NULL; +#endif + 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; @@ -1744,9 +2044,16 @@ return; } if (tree) { - format_oid(oid_string, regid, regid_length); +#ifdef HAVE_SMI_H + node = smiGetNodeByOID(regid_length, + (SmiSubid *)regid); +#else + node = NULL; +#endif + 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; @@ -1881,99 +2188,9 @@ &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 -#ifdef linux - /* As per the comment near the beginning of the file, UCD SNMP 4.1.1 - changed "snmp_set_suffix_only()" from a function to a macro, - removing "snmp_set_suffix_only()" from the library; this means - that binaries that call "snmp_set_suffix_only()" and - that are linked against shared libraries from earlier versions - of the UCD SNMP library won't run with shared libraries from - 4.1.1. - - This is a problem on Red Hat Linux, as pre-6.2 releases - came with pre-4.1.1 UCD SNMP, while 6.2 comes the 4.1.1. - Versions of Ethereal built on pre-6.2 releases don't run - on 6.2, and the current Ethereal RPMs are built on pre-6.2 - releases, causing problems when users running 6.2 download - them and try to use them. - - Building the releases on 6.2 isn't necessarily the answer, - as "snmp_set_suffix_only()" expands to a call to "ds_set_int()" - with a second argument not supported by at least some pre-4.1.1 - versions of the library - it appears that the 4.0.1 library, - at least, checks for invalid arguments and returns an error - rather than stomping random memory, but that means that you - won't get get OIDs displayed as module-name::sub-OID. - - So we use a trick similar to one I've seen mentioned as - used in Windows applications to let you build binaries - that run on many different versions of Windows 9x and - Windows NT, that use features present on later versions - if run on those later versions, but that avoid calling, - when run on older versions, routines not present on those - older versions. - - I.e., we load "libsnmp.so" with "dlopen()", and call - "dlsym()" to try to find "snmp_set_suffix_only()"; if we - don't find it, we make the appropriate call to - "ds_set_int()" instead. - - We do this only on Linux, for now, as we've only seen the - problem on Red Hat; it may show up on other OSes that bundle - UCD SNMP, or on OSes where it's not bundled but for which - binary packages are built that link against a shared version - of the UCD SNMP library. If we run into one of those, we - can do this under those OSes as well, *if* "dlopen()" makes - the run-time linker use the same search rules as it uses when - loading libraries with which the application is linked. - - (Perhaps we could use the GLib wrappers for run-time linking, - *if* they're thin enough; however, as this code is currently - used only on Linux, we don't worry about that for now.) */ - - libsnmp_handle = dlopen("libsnmp.so", RTLD_LAZY|RTLD_GLOBAL); - if (libsnmp_handle == NULL) { - /* We didn't find "libsnmp.so"; we may be linked - statically, in which case whatever call the following - line of code makes will presumably work, as - we have the routine it calls wired into our binary. */ - snmp_set_suffix_only(2); - } else { - /* OK, we have it loaded. Do we have - "snmp_set_suffix_only()"? */ - snmp_set_suffix_only_p = dlsym(libsnmp_handle, - "snmp_set_suffix_only"); - if (snmp_set_suffix_only_p != NULL) { - /* Yes - call it. */ - (*snmp_set_suffix_only_p)(2); - } else { - /* No; do we have "ds_set_int()"? */ - ds_set_int_p = dlsym(libsnmp_handle, "ds_set_int"); - if (ds_set_int_p != NULL) { - /* Yes - cal it with DS_LIBRARY_ID, - DS_LIB_PRINT_SUFFIX_ONLY, and 2 as - arguments. - - We do *not* use DS_LIBRARY_ID or - DS_LIB_PRINT_SUFFIX_ONLY by name, so that - we don't require that Ethereal be built - with versions of UCD SNMP that include - that value; instead, we use their values - in UCD SNMP 4.1.1, which are 0 and 4, - respectively. */ - (*ds_set_int_p)(0, 4, 2); - } - } - } -#else /* linux */ - snmp_set_suffix_only(2); -#endif /* linux */ -#endif /* HAVE_UCD_SNMP_SNMP_H */ -#endif /* defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H) */ +#ifdef HAVE_SMI_H + smiInit("ethereal"); +#endif proto_snmp = proto_register_protocol("Simple Network Management Protocol", "snmp"); proto_smux = proto_register_protocol("SNMP Multiplex Protocol", "smux"); proto_register_field_array(proto_snmp, hf, array_length(hf));
- Follow-Ups:
- Re: [ethereal-dev] packet-snmp.c and libsmi
- From: Guy Harris
- Re: [ethereal-dev] packet-snmp.c and libsmi
- References:
- Re: [ethereal-dev] packet-snmp.c and libsmi
- From: Guy Harris
- Re: [ethereal-dev] packet-snmp.c and libsmi
- Prev by Date: Re: [ethereal-dev] packet-snmp.c and libsmi
- Next by Date: Re: [ethereal-dev] Re: Sniffer 3.50 file format
- Previous by thread: Re: [ethereal-dev] packet-snmp.c and libsmi
- Next by thread: Re: [ethereal-dev] packet-snmp.c and libsmi
- Index(es):