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: Sat, 24 Jun 2000 13:14:06 -0700
On Fri, Jun 23, 2000 at 11:38:12PM -0700, Guy Harris wrote: > This is a patch to the current "packet-snmp.c" in the CVS tree. ...and this is a slightly better one (again, a patch to the code in the CVS tree), that doesn't reintroduce the no-longer-necessary commented-out examples of "hf_register_info" entries (no longer necessary because there are *real* entries now for some of the SNMP V3 stuff).
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 20:13:17 *************** *** 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 ---- *************** *** 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)); --- 2147,2155 ---- &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
- 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: [ethereal-dev] SNMP Bug Report
- Previous by thread: Re: [ethereal-dev] packet-snmp.c and libsmi
- Next by thread: Re: [ethereal-dev] packet-snmp.c and libsmi
- Index(es):