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: Guy Harris <gharris@xxxxxxxxxxxx>
Date: Fri, 23 Jun 2000 23:38:12 -0700
On Fri, Jun 23, 2000 at 07:34:05PM +0200, Jochen Friedrich wrote: > 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 :) ). I've attached my current version - it goes back to your original scheme showing OIDs symbolically as <module>::<name>, as I've checked in code to display them that way with UCD SNMP; I think it may actually make it easier to find the variable in one of the MIB RFCs. That also gets rid of the recursive call in question. This is a patch to the current "packet-snmp.c" in the CVS tree. (It also gets rid of some left-over bits of the hack for UCD SNMP 4.1.1 that your patch left in; that hack isn't necessary for libsmi - and I hope it remains so, which is why I'm loath to cut over to libsmi unless either 1) the API and its resulting ABI are stable now or 2) if they're not, there won't be shared-library versions of libsmi commonly available until they are - and even then, API changes can get painful unless we can simply say "if you want symbolic dissection of OIDs and variable bindings, and don't want to have to manually tell 'configure' not to use libsmi, you'll have to fetch the latest version of libsmi and install it".)
Index: packet-snmp.c =================================================================== RCS file: /usr/local/cvsroot/ethereal/packet-snmp.c,v retrieving revision 1.37 diff -c -r1.37 packet-snmp.c *** packet-snmp.c 2000/06/17 05:56:22 1.37 --- packet-snmp.c 2000/06/24 06:34:43 *************** *** 47,193 **** #define MAX_STRING_LEN 1024 /* TBC */ - #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" --- 47,63 ---- #define MAX_STRING_LEN 1024 /* TBC */ #include <glib.h> + #ifdef HAVE_SMI_H + #include <smi.h> + #else + typedef void SmiNode; + #endif + #include "packet.h" #include "etypes.h" #include "packet-ipx.h" #include "asn1.h" #include "packet-snmp.h" *************** *** 554,635 **** dissect_data(pd, offset, fd, tree); } ! static void ! format_oid(gchar *buf, subid_t *oid, guint oid_length) { ! int i; ! int len; 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; } } ! #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) { ! variable->next_variable = NULL; ! variable->name = variable_oid; ! variable->name_length = variable_oid_length; switch (vb_type) { case SNMP_INTEGER: ! variable->type = VALTYPE_INTEGER; break; case SNMP_COUNTER: - variable->type = VALTYPE_COUNTER; - break; - case SNMP_GAUGE: - variable->type = VALTYPE_GAUGE; - break; - case SNMP_TIMETICKS: ! variable->type = VALTYPE_TIMETICKS; 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; break; ! case SNMP_COUNTER64: ! variable->type = VALTYPE_COUNTER64; break; } ! variable->val_len = vb_length; ! sprint_value(buf, variable_oid, variable_oid_length, variable); } - #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) { const guchar *start; guint length; --- 424,969 ---- dissect_data(pd, offset, fd, tree); } ! 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; + } + + static gchar * + format_oid(subid_t *oid, guint oid_length, SmiNode* node) + { + char *result; + int result_len; + int len, i; + char *buf; + #ifdef HAVE_SMI_H + SmiModule *module = NULL; + #endif + + result_len = oid_length * 22; + #ifdef HAVE_SMI_H + if (node) { + module = smiGetNodeModule(node); + result_len += 5 + strlen(module->name) + strlen(node->name); + result_len += (oid_length - node->oidlen)*22; + } + #endif + result = g_malloc(result_len + 1); + buf = result; 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; } + + #ifdef HAVE_SMI_H + if (node) { + len = sprintf(buf, " (%s::%s", module->name, node->name); + buf += len; + for (i = node->oidlen; i < oid_length; i++) { + len = sprintf(buf, ".%lu", (unsigned long)oid[i]); + buf += len; + } + strcpy(buf, ")"); + } + #endif + return result; } ! static gchar* ! format_var(gushort vb_type, guint8 *vb_octet_string, guint vb_length, ! SmiNode *node) { ! #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: ! 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: case SNMP_GAUGE: case SNMP_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: case SNMP_IPADDR: case SNMP_OPAQUE: case SNMP_NSAP: case SNMP_BITSTR: ! string = format_string(vb_octet_string, vb_length, format); break; ! default: ! string = NULL; break; } ! return string; } static int snmp_variable_decode(proto_tree *snmp_tree, subid_t *variable_oid, ! guint variable_oid_length, ASN1_SCK *asn1, int offset, guint *lengthp, ! SmiNode *node) { const guchar *start; guint length; *************** *** 640,665 **** 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 */ ! #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 */ /* parse the type of the object */ start = asn1->pointer; --- 974,988 ---- int ret; guint cls, con, tag; guint8 *vb_octet_string; subid_t *vb_oid; guint vb_oid_length; ! gchar *vb_display_string; ! SmiNode *oid_node; ! gchar *oid_string; /* parse the type of the object */ start = asn1->pointer; *************** *** 684,796 **** 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_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); 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 } g_free(vb_octet_string); break; --- 1007,1033 ---- switch (vb_type) { case SNMP_INTEGER: case SNMP_COUNTER: case SNMP_GAUGE: case SNMP_TIMETICKS: ! case SNMP_COUNTER64: case SNMP_OCTETSTR: case SNMP_IPADDR: case SNMP_OPAQUE: case SNMP_NSAP: case SNMP_BITSTR: 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) { ! vb_display_string = format_var(vb_type, vb_octet_string, ! vb_length, node); proto_tree_add_text(snmp_tree, NullTVB, offset, length, ! "Value: %s: %s", vb_type_name, ! vb_display_string); ! g_free(vb_display_string); } g_free(vb_octet_string); break; *************** *** 813,830 **** 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); #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 } g_free(vb_oid); break; --- 1050,1066 ---- return ret; length = asn1->pointer - start; if (snmp_tree) { ! #ifdef HAVE_SMI_H ! oid_node = smiGetNodeByOID(vb_oid_length, ! (SmiSubid *)vb_oid); #else ! 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; *************** *** 890,896 **** guint timestamp; guint timestamp_length; ! gchar oid_string[MAX_STRING_LEN]; /* TBC */ guint variable_bindings_length; --- 1126,1132 ---- guint timestamp; guint timestamp_length; ! gchar *oid_string; guint variable_bindings_length; *************** *** 898,910 **** 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; pdu_type_string = val_to_str(pdu_type, pdu_types, "Unknown PDU type %#x"); if (check_col(fd, COL_INFO)) --- 1134,1145 ---- guint variable_length; subid_t *variable_oid; guint variable_oid_length; 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,1001 **** return; } if (tree) { ! format_oid(oid_string, enterprise, enterprise_length); proto_tree_add_text(tree, NullTVB, offset, length, "Enterprise: %s", oid_string); } g_free(enterprise); offset += length; --- 1228,1244 ---- return; } if (tree) { ! #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,1160 **** } 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); #else ! ! proto_tree_add_text(tree, NullTVB, offset, sequence_length, ! "Object identifier %d: %s", vb_index, ! oid_string); #endif } 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); if (ret != ASN1_ERR_NOERROR) { dissect_snmp_parse_error(pd, offset, fd, tree, "variable", ret); --- 1375,1400 ---- } sequence_length += length; ! #ifdef HAVE_SMI_H ! node = smiGetNodeByOID(variable_oid_length, ! (SmiSubid *)variable_oid); #else ! 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, node); if (ret != ASN1_ERR_NOERROR) { dissect_snmp_parse_error(pd, offset, fd, tree, "variable", ret); *************** *** 1205,1210 **** --- 1445,1455 ---- 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,1418 **** return; } if (secur_tree) { proto_tree_add_text(secur_tree, NullTVB, offset, length, "Authoritative Engine ID: %s", ! bytes_to_str(aengineid, aengineid_length)); } g_free(aengineid); offset += length; --- 1655,1666 ---- 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; *************** *** 1462,1470 **** return; } if (secur_tree) { proto_tree_add_text(secur_tree, NullTVB, offset, length, "Authentication Parameter: %s", ! bytes_to_str(authpar, authpar_length)); } g_free(authpar); offset += length; --- 1710,1721 ---- 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; *************** *** 1476,1484 **** return; } if (secur_tree) { proto_tree_add_text(secur_tree, NullTVB, offset, length, "Privacy Parameter: %s", ! bytes_to_str(privpar, privpar_length)); } g_free(privpar); offset += length; --- 1727,1738 ---- 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; *************** *** 1532,1540 **** return; } if (snmp_tree) { proto_tree_add_text(snmp_tree, NullTVB, offset, length, ! "Context Engine ID: %s", ! bytes_to_str(cengineid, cengineid_length)); } g_free(cengineid); offset += length; --- 1786,1796 ---- 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; *************** *** 1602,1614 **** subid_t *regid; guint regid_length; ! gchar oid_string[MAX_STRING_LEN]; /* TBC */ proto_tree *smux_tree = NULL; proto_item *item = NULL; int ret; guint cls, con; if (check_col(fd, COL_PROTOCOL)) col_add_str(fd, COL_PROTOCOL, "SMUX"); --- 1858,1872 ---- 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, "SMUX"); *************** *** 1663,1671 **** return; } if (tree) { ! format_oid(oid_string, regid, regid_length); proto_tree_add_text(smux_tree, NullTVB, offset, length, "Registration: %s", oid_string); } g_free(regid); offset += length; --- 1921,1936 ---- return; } if (tree) { ! #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,1752 **** return; } if (tree) { ! format_oid(oid_string, regid, regid_length); proto_tree_add_text(smux_tree, NullTVB, offset, length, "Registration: %s", oid_string); } g_free(regid); offset += length; --- 2009,2024 ---- return; } if (tree) { ! #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; *************** *** 1853,1864 **** void proto_register_snmp(void) { - #ifdef linux - void *libsnmp_handle; - int (*snmp_set_suffix_only_p)(int); - int (*ds_set_int_p)(int, int, int); - #endif - static hf_register_info hf[] = { { &hf_snmpv3_flags, { "SNMPv3 Flags", "snmpv3.flags", FT_UINT8, BASE_HEX, NULL, --- 2125,2130 ---- *************** *** 1872,1877 **** --- 2138,2147 ---- { &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, *************** *** 1881,1979 **** &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) */ 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)); --- 2151,2159 ---- &ett_secur, }; ! #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
- From: Jochen Friedrich
- Re: [ethereal-dev] packet-snmp.c and libsmi
- Prev by Date: Re: [ethereal-dev] Re: Sniffer 3.50 file format
- Next by Date: Re: [ethereal-dev] packet-snmp.c and libsmi
- Previous by thread: Re: [ethereal-dev] packet-snmp.c and libsmi
- Next by thread: Re: [ethereal-dev] packet-snmp.c and libsmi
- Index(es):