*
* See RFCs 2570-2576 for SNMPv3
*
- * $Id: packet-snmp.c,v 1.102 2002/11/11 17:34:22 guy Exp $
+ * $Id: packet-snmp.c,v 1.113 2003/09/06 01:21:00 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
#include <epan/strutil.h>
#include <epan/conversation.h>
#include "etypes.h"
+#include "prefs.h"
#include "packet-ipx.h"
+#include "packet-hpext.h"
+#include "packet-frame.h"
#ifdef HAVE_SOME_SNMP
# include <ucd-snmp/default_store.h>
# include <ucd-snmp/read_config.h>
# include <ucd-snmp/tools.h>
-# define netsnmp_ds_set_boolean ds_set_boolean
-# define netsnmp_ds_set_int ds_set_int
+#endif /* HAVE_NET_SNMP */
+
+#ifndef NETSNMP_DS_LIBRARY_ID
# define NETSNMP_DS_LIBRARY_ID DS_LIBRARY_ID
# define NETSNMP_DS_LIB_NO_TOKEN_WARNINGS DS_LIB_NO_TOKEN_WARNINGS
# define NETSNMP_DS_LIB_PRINT_SUFFIX_ONLY DS_LIB_PRINT_SUFFIX_ONLY
-#endif /* HAVE_NET_SNMP */
+# define netsnmp_ds_set_boolean ds_set_boolean
+# define netsnmp_ds_set_int ds_set_int
+#endif
#ifdef WIN32
# include <epan/filesystem.h>
#include "packet-snmp.h"
#include "format-oid.h"
-/* Null string of type "guchar[]". */
-static const guchar nullstring[] = "";
-
/* Take a pointer that may be null and return a pointer that's not null
- by turning null pointers into pointers to the above null string. */
-#define SAFE_STRING(s) (((s) != NULL) ? (s) : nullstring)
+ by turning null pointers into pointers to the above null string,
+ and, if the argument pointer wasn't null, make sure we handle
+ non-printable characters in the string by escaping them. */
+#define SAFE_STRING(s, l) (((s) != NULL) ? format_text((s), (l)) : "")
static int proto_snmp = -1;
-static int proto_smux = -1;
+
+static gboolean display_oid = TRUE;
static gint ett_snmp = -1;
-static gint ett_smux = -1;
static gint ett_parameters = -1;
static gint ett_parameters_qos = -1;
static gint ett_global = -1;
static gint ett_flags = -1;
static gint ett_secur = -1;
+static int hf_snmp_version = -1;
+static int hf_snmp_community = -1;
+static int hf_snmp_request_id = -1;
+static int hf_snmp_pdutype = -1;
+static int hf_snmp_agent = -1;
+static int hf_snmp_enterprise = -1;
+static int hf_snmp_error_status = -1;
+static int hf_snmp_oid = -1;
+static int hf_snmp_traptype = -1;
+static int hf_snmp_spectraptype = -1;
+static int hf_snmp_timestamp = -1;
static int hf_snmpv3_flags = -1;
static int hf_snmpv3_flags_auth = -1;
static int hf_snmpv3_flags_crypt = -1;
static int hf_snmpv3_flags_report = -1;
+static int proto_smux = -1;
+
+static gint ett_smux = -1;
+
+static int hf_smux_version = -1;
+static int hf_smux_pdutype = -1;
+
+/* desegmentation of SNMP-over-TCP */
+static gboolean snmp_desegment = TRUE;
+
static dissector_handle_t snmp_handle;
static dissector_handle_t data_handle;
#define UDP_PORT_SNMP 161
#define UDP_PORT_SNMP_TRAP 162
+#define TCP_PORT_SNMP 161
+#define TCP_PORT_SNMP_TRAP 162
#define TCP_PORT_SMUX 199
/* Protocol version numbers */
};
/* Error status values */
+#ifndef SNMP_ERR_NOERROR
#define SNMP_ERR_NOERROR 0
+#endif
+#ifndef SNMP_ERR_TOOBIG
#define SNMP_ERR_TOOBIG 1
+#endif
+#ifndef SNMP_ERR_NOSUCHNAME
#define SNMP_ERR_NOSUCHNAME 2
+#endif
+#ifndef SNMP_ERR_BADVALUE
#define SNMP_ERR_BADVALUE 3
+#endif
+#ifndef SNMP_ERR_READONLY
#define SNMP_ERR_READONLY 4
-#define SNMP_ERR_GENERROR 5
-
+#endif
+#ifndef SNMP_ERR_GENERR
+#define SNMP_ERR_GENERR 5
+#endif
+#ifndef SNMP_ERR_NOACCESS
#define SNMP_ERR_NOACCESS 6
+#endif
+#ifndef SNMP_ERR_WRONGTYPE
#define SNMP_ERR_WRONGTYPE 7
+#endif
+#ifndef SNMP_ERR_WRONGLENGTH
#define SNMP_ERR_WRONGLENGTH 8
+#endif
+#ifndef SNMP_ERR_WRONGENCODING
#define SNMP_ERR_WRONGENCODING 9
+#endif
+#ifndef SNMP_ERR_WRONGVALUE
#define SNMP_ERR_WRONGVALUE 10
+#endif
+#ifndef SNMP_ERR_NOCREATION
#define SNMP_ERR_NOCREATION 11
+#endif
+#ifndef SNMP_ERR_INCONSISTENTVALUE
#define SNMP_ERR_INCONSISTENTVALUE 12
+#endif
+#ifndef SNMP_ERR_RESOURCEUNAVAILABLE
#define SNMP_ERR_RESOURCEUNAVAILABLE 13
+#endif
+#ifndef SNMP_ERR_COMMITFAILED
#define SNMP_ERR_COMMITFAILED 14
+#endif
+#ifndef SNMP_ERR_UNDOFAILED
#define SNMP_ERR_UNDOFAILED 15
+#endif
+#ifndef SNMP_ERR_AUTHORIZATIONERROR
#define SNMP_ERR_AUTHORIZATIONERROR 16
+#endif
+#ifndef SNMP_ERR_NOTWRITABLE
#define SNMP_ERR_NOTWRITABLE 17
+#endif
+#ifndef SNMP_ERR_INCONSISTENTNAME
#define SNMP_ERR_INCONSISTENTNAME 18
+#endif
static const value_string error_statuses[] = {
{ SNMP_ERR_NOERROR, "NO ERROR" },
{ SNMP_ERR_NOSUCHNAME, "NO SUCH NAME" },
{ SNMP_ERR_BADVALUE, "BAD VALUE" },
{ SNMP_ERR_READONLY, "READ ONLY" },
- { SNMP_ERR_GENERROR, "GENERIC ERROR" },
+ { SNMP_ERR_GENERR, "GENERIC ERROR" },
{ SNMP_ERR_NOACCESS, "NO ACCESS" },
{ SNMP_ERR_WRONGTYPE, "WRONG TYPE" },
{ SNMP_ERR_WRONGLENGTH, "WRONG LENGTH" },
/* General SNMP V1 Traps */
+#ifndef SNMP_TRAP_COLDSTART
#define SNMP_TRAP_COLDSTART 0
+#endif
+#ifndef SNMP_TRAP_WARMSTART
#define SNMP_TRAP_WARMSTART 1
+#endif
+#ifndef SNMP_TRAP_LINKDOWN
#define SNMP_TRAP_LINKDOWN 2
+#endif
+#ifndef SNMP_TRAP_LINKUP
#define SNMP_TRAP_LINKUP 3
+#endif
+#ifndef SNMP_TRAP_AUTHFAIL
#define SNMP_TRAP_AUTHFAIL 4
+#endif
+#ifndef SNMP_TRAP_EGPNEIGHBORLOSS
#define SNMP_TRAP_EGPNEIGHBORLOSS 5
+#endif
+#ifndef SNMP_TRAP_ENTERPRISESPECIFIC
#define SNMP_TRAP_ENTERPRISESPECIFIC 6
+#endif
static const value_string trap_types[] = {
{ SNMP_TRAP_COLDSTART, "COLD START" },
* Get the decoded form of the OID, and add its length to the
* length of the result string.
*
- * XXX - check for "malloc" and "sprint_realloc_objid()" failure.
+ * XXX - check for "sprint_realloc_objid()" failure.
*/
oid_string_len = 256;
- oid_string = malloc(oid_string_len);
+ oid_string = g_malloc(oid_string_len);
*oid_string = '\0';
oid_out_len = 0;
sprint_realloc_objid(&oid_string, &oid_string_len, &oid_out_len, 1,
* Append the decoded form of the OID.
*/
sprintf(buf, " (%s)", oid_string);
- free(oid_string);
+ g_free(oid_string);
#endif
return result;
}
+/* returns the decoded (can be NULL) and non_decoded OID strings,
+ returned pointers shall be freed by the caller */
+void
+new_format_oid(subid_t *oid, guint oid_length,
+ gchar **non_decoded, gchar **decoded)
+{
+ int len;
+ unsigned int i;
+ char *buf;
+
+#ifdef HAVE_SOME_SNMP
+ guchar *oid_string;
+ size_t oid_string_len;
+ size_t oid_out_len;
+
+ /*
+ * Get the decoded form of the OID, and add its length to the
+ * length of the result string.
+ */
+
+ oid_string_len = 256;
+ oid_string = g_malloc(oid_string_len);
+ *oid_string = '\0';
+ oid_out_len = 0;
+ sprint_realloc_objid(&oid_string, &oid_string_len, &oid_out_len, 1,
+ oid, oid_length);
+ *decoded = oid_string;
+#else
+ *decoded = NULL;
+#endif
+
+ *non_decoded = g_malloc(oid_length * 22 + 1);
+ buf = *non_decoded;
+ 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_SOME_SNMP
static guchar *
check_var_length(guint vb_length, guint required_length)
/* Enough room for the largest "Length is XXX,
should be XXX" message - 10 digits for each
XXX. */
- buf = malloc(sizeof badlen_fmt + 10 + 10);
+ buf = g_malloc(sizeof badlen_fmt + 10 + 10);
sprintf(buf, badlen_fmt, vb_length, required_length);
return buf;
}
variable->val_len = val_len;
/*
- * XXX - check for "malloc" and "sprint_realloc_objid()" failure.
+ * XXX - check for "sprint_realloc_objid()" failure.
*/
buf_len = 256;
- buf = malloc(buf_len);
+ buf = g_malloc(buf_len);
*buf = '\0';
out_len = 0;
sprint_realloc_value(&buf, &buf_len, &out_len, 1, variable_oid,
proto_tree_add_text(snmp_tree, asn1->tvb, offset,
length,
"Value: %s", vb_display_string);
- free(vb_display_string);
+ g_free(vb_display_string);
#else /* HAVE_SOME_SNMP */
proto_tree_add_text(snmp_tree, asn1->tvb, offset,
length,
proto_tree_add_text(snmp_tree, asn1->tvb, offset,
length,
"Value: %s", vb_display_string);
- free(vb_display_string);
+ g_free(vb_display_string);
#else /* HAVE_SOME_SNMP */
proto_tree_add_text(snmp_tree, asn1->tvb, offset,
length,
proto_tree_add_text(snmp_tree, asn1->tvb, offset,
length,
"Value: %s", vb_display_string);
- free(vb_display_string);
+ g_free(vb_display_string);
#else /* HAVE_SOME_SNMP */
/*
* If some characters are not printable, display
} else {
proto_tree_add_text(snmp_tree, asn1->tvb, offset,
length,
- "Value: %s: %.*s", vb_type_name,
- (int)vb_length,
- SAFE_STRING(vb_octet_string));
+ "Value: %s: %s", vb_type_name,
+ SAFE_STRING(vb_octet_string, vb_length));
}
#endif /* HAVE_SOME_SNMP */
}
proto_tree_add_text(snmp_tree, asn1->tvb, offset,
length,
"Value: %s", vb_display_string);
- free(vb_display_string);
+ g_free(vb_display_string);
#else /* HAVE_SOME_SNMP */
vb_display_string = format_oid(vb_oid, vb_oid_length);
proto_tree_add_text(snmp_tree, asn1->tvb, offset,
subid_t *enterprise;
guint enterprise_length;
+ guint32 agent_ipaddr;
+
guint8 *agent_address;
guint agent_address_length;
col_add_str(pinfo->cinfo, COL_INFO, pdu_type_string);
length = asn1.offset - start;
if (tree) {
- proto_tree_add_text(tree, tvb, offset, length,
- "PDU type: %s", pdu_type_string);
+ proto_tree_add_uint(tree, hf_snmp_pdutype, tvb, offset, length,
+ pdu_type);
}
offset += length;
return;
}
if (tree) {
- proto_tree_add_text(tree, tvb, offset, length,
- "Request Id: %#x", request_id);
+ proto_tree_add_uint(tree, hf_snmp_request_id,
+ tvb, offset, length, request_id);
}
offset += length;
proto_tree_add_text(tree, tvb, offset,
length, "Non-repeaters: %u", error_status);
} else {
- proto_tree_add_text(tree, tvb, offset,
- length, "Error Status: %s",
- val_to_str(error_status, error_statuses,
- "Unknown (%d)"));
+ proto_tree_add_uint(tree,
+ hf_snmp_error_status,
+ tvb, offset,
+ length, error_status);
}
}
offset += length;
}
if (tree) {
oid_string = format_oid(enterprise, enterprise_length);
- proto_tree_add_text(tree, tvb, offset, length,
- "Enterprise: %s", oid_string);
+ proto_tree_add_string(tree, hf_snmp_enterprise, tvb,
+ offset, length, oid_string);
g_free(oid_string);
}
g_free(enterprise);
"Agent address: <length is %u, not 4>",
agent_address_length);
} else {
- proto_tree_add_text(tree, tvb, offset,
- length,
- "Agent address: %s",
- ip_to_str(agent_address));
+ memcpy((guint8 *)&agent_ipaddr, agent_address,
+ agent_address_length);
+ proto_tree_add_ipv4(tree, hf_snmp_agent, tvb,
+ offset, length, agent_ipaddr);
}
}
g_free(agent_address);
return;
}
if (tree) {
- proto_tree_add_text(tree, tvb, offset, length,
- "Trap type: %s",
- val_to_str(trap_type, trap_types, "Unknown (%u)"));
+ proto_tree_add_uint(tree, hf_snmp_traptype, tvb,
+ offset, length, trap_type);
}
offset += length;
return;
}
if (tree) {
- proto_tree_add_text(tree, tvb, offset, length,
- "Specific trap type: %u (%#x)",
- specific_type, specific_type);
+ proto_tree_add_uint(tree, hf_snmp_spectraptype, tvb,
+ offset, length, specific_type);
}
offset += length;
}
length = asn1.offset - start;
if (tree) {
- proto_tree_add_text(tree, tvb, offset, length,
- "Timestamp: %u", timestamp);
+ proto_tree_add_uint(tree, hf_snmp_timestamp, tvb,
+ offset, length, timestamp);
}
offset += length;
break;
}
sequence_length += length;
- if (tree) {
- oid_string = format_oid(variable_oid,
- variable_oid_length);
- proto_tree_add_text(tree, tvb, offset, sequence_length,
- "Object identifier %d: %s", vb_index, oid_string);
- g_free(oid_string);
+ if (display_oid || tree) {
+
+ gchar *decoded_oid;
+ gchar *non_decoded_oid;
+
+ new_format_oid(variable_oid, variable_oid_length,
+ &non_decoded_oid, &decoded_oid);
+
+ if (display_oid && check_col(pinfo->cinfo, COL_INFO)) {
+ col_append_fstr(pinfo->cinfo, COL_INFO,
+ " %s",
+ (decoded_oid == NULL) ? non_decoded_oid :
+ decoded_oid);
+ }
+
+ if (tree) {
+ if (decoded_oid) {
+ proto_tree_add_string_format(tree, hf_snmp_oid,
+ tvb, offset,
+ sequence_length,
+ decoded_oid,
+ "Object identifier %d: %s (%s)",
+ vb_index,
+ non_decoded_oid,
+ decoded_oid);
+ /* add also the non decoded oid string */
+ proto_tree_add_string_hidden(tree, hf_snmp_oid,
+ tvb, offset,
+ sequence_length,
+ non_decoded_oid);
+ } else {
+ proto_tree_add_string_format(tree, hf_snmp_oid,
+ tvb, offset,
+ sequence_length,
+ non_decoded_oid,
+ "Object identifier %d: %s",
+ vb_index,
+ non_decoded_oid);
+ }
+ }
+
+ if (decoded_oid) g_free(decoded_oid);
+ g_free(non_decoded_oid);
+
}
+
offset += sequence_length;
variable_bindings_length -= sequence_length;
parameters_length -= 1;
if (model != 1) {
/* Unknown model. */
- proto_tree_add_text(parameters_tree, tvb, offset,
- parameters_length, "parameters: %s",
+ proto_tree_add_text(parameters_tree, tvb, offset, parameters_length, "parameters: %s",
bytes_to_str(parameters, parameters_length));
return;
}
"contextSelector: %s", bytes_to_str(parameters, parameters_length));
}
-void
+guint
dissect_snmp_pdu(tvbuff_t *tvb, int offset, packet_info *pinfo,
- proto_tree *tree, char *proto_name, int proto, gint ett)
+ proto_tree *tree, int proto, gint ett, gboolean is_tcp)
{
+ guint length_remaining;
ASN1_SCK asn1;
int start;
gboolean def;
guint32 enginetime;
guchar *msgflags;
+ guchar *commustr;
guchar *community;
guchar *secparm;
guchar *cengineid;
int ret;
guint cls, con, tag;
- if (check_col(pinfo->cinfo, COL_PROTOCOL))
- col_add_str(pinfo->cinfo, COL_PROTOCOL, proto_name);
-
- if (tree) {
- item = proto_tree_add_item(tree, proto, tvb, offset, -1, FALSE);
- snmp_tree = proto_item_add_subtree(item, ett);
- }
+ /*
+ * This will throw an exception if we don't have any data left.
+ * That's what we want. (See "tcp_dissect_pdus()", which is
+ * similar, but doesn't have to deal with ASN.1.
+ * XXX - can we make "tcp_dissect_pdus()" provide enough
+ * information to the "get_pdu_len" routine so that we could
+ * have that routine deal with ASN.1, and just use
+ * "tcp_dissect_pdus()"?)
+ */
+ length_remaining = tvb_ensure_length_remaining(tvb, offset);
/* NOTE: we have to parse the message piece by piece, since the
* capture length may be less than the message length: a 'global'
* parsing is likely to fail.
*/
- /* parse the SNMP header */
+
+ /*
+ * If this is SNMP-over-TCP, we might have to do reassembly
+ * in order to read the "Sequence Of" header.
+ */
+ if (is_tcp && snmp_desegment && pinfo->can_desegment) {
+ /*
+ * This is TCP, and we should, and can, do reassembly.
+ *
+ * Is the "Sequence Of" header split across segment
+ * boundaries? We requre at least 6 bytes for the
+ * header, which allows for a 4-byte length (ASN.1
+ * BER).
+ */
+ if (length_remaining < 6) {
+ pinfo->desegment_offset = offset;
+ pinfo->desegment_len = 6 - length_remaining;
+
+ /*
+ * Return 0, which means "I didn't dissect anything
+ * because I don't have enough data - we need
+ * to desegment".
+ */
+ return 0;
+ }
+ }
+
+ /*
+ * OK, try to read the "Sequence Of" header; this gets the total
+ * length of the SNMP message.
+ */
asn1_open(&asn1, tvb, offset);
ret = asn1_sequence_decode(&asn1, &message_length, &length);
if (ret != ASN1_ERR_NOERROR) {
+ if (tree) {
+ item = proto_tree_add_item(tree, proto, tvb, offset,
+ -1, FALSE);
+ snmp_tree = proto_item_add_subtree(item, ett);
+ }
dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree,
"message header", ret);
- return;
+
+ /*
+ * Return the length remaining in the tvbuff, so
+ * if this is SNMP-over-TCP, our caller thinks there's
+ * nothing left to dissect.
+ */
+ return length_remaining;
+ }
+
+ /*
+ * Add the length of the "Sequence Of" header to the message
+ * length.
+ */
+ message_length += length;
+ if (message_length < length) {
+ /*
+ * The message length was probably so large that the
+ * total length overflowed.
+ *
+ * Report this as an error.
+ */
+ show_reported_bounds_error(tvb, pinfo, tree);
+
+ /*
+ * Return the length remaining in the tvbuff, so
+ * if this is SNMP-over-TCP, our caller thinks there's
+ * nothing left to dissect.
+ */
+ return length_remaining;
+ }
+
+ /*
+ * If this is SNMP-over-TCP, we might have to do reassembly
+ * to get all of this message.
+ */
+ if (is_tcp && snmp_desegment && pinfo->can_desegment) {
+ /*
+ * Yes - is the message split across segment boundaries?
+ */
+ if (length_remaining < message_length) {
+ /*
+ * Yes. Tell the TCP dissector where the data
+ * for this message starts in the data it handed
+ * us, and how many more bytes we need, and
+ * return.
+ */
+ pinfo->desegment_offset = offset;
+ pinfo->desegment_len =
+ message_length - length_remaining;
+
+ /*
+ * Return 0, which means "I didn't dissect anything
+ * because I don't have enough data - we need
+ * to desegment".
+ */
+ return 0;
+ }
+ }
+
+ if (check_col(pinfo->cinfo, COL_PROTOCOL)) {
+ col_set_str(pinfo->cinfo, COL_PROTOCOL,
+ proto_get_protocol_short_name(proto));
+ }
+
+ if (tree) {
+ item = proto_tree_add_item(tree, proto, tvb, offset,
+ message_length, FALSE);
+ snmp_tree = proto_item_add_subtree(item, ett);
}
offset += length;
if (ret != ASN1_ERR_NOERROR) {
dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree,
"version number", ret);
- return;
+ return message_length;
}
if (snmp_tree) {
- proto_tree_add_text(snmp_tree, tvb, offset, length,
- "Version: %s",
- val_to_str(version, versions, "Unknown version %#x"));
+ proto_tree_add_uint(snmp_tree, hf_snmp_version, tvb, offset,
+ length, version);
}
offset += length;
if (ret != ASN1_ERR_NOERROR) {
dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree,
"community", ret);
- return;
+ return message_length;
}
if (tree) {
- proto_tree_add_text(snmp_tree, tvb, offset, length,
- "Community: %.*s", community_length,
- SAFE_STRING(community));
+ commustr = g_malloc(community_length+1);
+ memcpy(commustr, community, community_length);
+ commustr[community_length] = '\0';
+
+ proto_tree_add_string(snmp_tree, hf_snmp_community,
+ tvb, offset, length, commustr);
+ g_free(commustr);
}
g_free(community);
offset += length;
if (ret != ASN1_ERR_NOERROR) {
dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree,
"message global header", ret);
- return;
+ return message_length;
}
if (snmp_tree) {
item = proto_tree_add_text(snmp_tree, tvb, offset,
if (ret != ASN1_ERR_NOERROR) {
dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree,
"message id", ret);
- return;
+ return message_length;
}
if (global_tree) {
proto_tree_add_text(global_tree, tvb, offset,
if (ret != ASN1_ERR_NOERROR) {
dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree,
"message max size", ret);
- return;
+ return message_length;
}
if (global_tree) {
proto_tree_add_text(global_tree, tvb, offset,
if (ret != ASN1_ERR_NOERROR) {
dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree,
"message flags", ret);
- return;
+ return message_length;
}
if (msgflags_length != 1) {
dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree,
"message flags wrong length", ret);
g_free(msgflags);
- return;
+ return message_length;
}
if (global_tree) {
item = proto_tree_add_uint_format(global_tree,
if (ret != ASN1_ERR_NOERROR) {
dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree,
"message security model", ret);
- return;
+ return message_length;
}
if (global_tree) {
proto_tree_add_text(global_tree, tvb, offset,
dissect_snmp_parse_error(tvb, offset, pinfo,
snmp_tree, "Message Security Parameters",
ASN1_ERR_WRONG_TYPE);
- return;
+ return message_length;
}
if (snmp_tree) {
item = proto_tree_add_text(snmp_tree, tvb,
if (ret != ASN1_ERR_NOERROR) {
dissect_snmp_parse_error(tvb, offset, pinfo,
snmp_tree, "USM sequence header", ret);
- return;
+ return message_length;
}
offset += length;
ret = asn1_octet_string_decode (&asn1, &aengineid,
if (ret != ASN1_ERR_NOERROR) {
dissect_snmp_parse_error(tvb, offset, pinfo,
snmp_tree, "authoritative engine id", ret);
- return;
+ return message_length;
}
if (secur_tree) {
proto_tree_add_text(secur_tree, tvb, offset,
if (ret != ASN1_ERR_NOERROR) {
dissect_snmp_parse_error(tvb, offset, pinfo,
snmp_tree, "engine boots", ret);
- return;
+ return message_length;
}
if (secur_tree) {
proto_tree_add_text(secur_tree, tvb,
if (ret != ASN1_ERR_NOERROR) {
dissect_snmp_parse_error(tvb, offset, pinfo,
snmp_tree, "engine time", ret);
- return;
+ return message_length;
}
if (secur_tree) {
proto_tree_add_text(secur_tree, tvb,
if (ret != ASN1_ERR_NOERROR) {
dissect_snmp_parse_error(tvb, offset, pinfo,
snmp_tree, "user name", ret);
- return;
+ return message_length;
}
if (secur_tree) {
proto_tree_add_text(secur_tree, tvb, offset,
- length, "User Name: %.*s",
- username_length,
- SAFE_STRING(username));
+ length, "User Name: %s",
+ SAFE_STRING(username, username_length));
}
g_free(username);
offset += length;
if (ret != ASN1_ERR_NOERROR) {
dissect_snmp_parse_error(tvb, offset, pinfo,
snmp_tree, "authentication parameter", ret);
- return;
+ return message_length;
}
if (secur_tree) {
proto_tree_add_text(secur_tree, tvb, offset,
if (ret != ASN1_ERR_NOERROR) {
dissect_snmp_parse_error(tvb, offset, pinfo,
snmp_tree, "privacy parameter", ret);
- return;
+ return message_length;
}
if (secur_tree) {
proto_tree_add_text(secur_tree, tvb, offset,
dissect_snmp_parse_error(tvb, offset, pinfo,
snmp_tree, "Message Security Parameters",
ret);
- return;
+ return message_length;
}
if (snmp_tree) {
proto_tree_add_text(snmp_tree, tvb, offset,
if (ret != ASN1_ERR_NOERROR) {
dissect_snmp_parse_error(tvb, offset, pinfo,
snmp_tree, "encrypted PDU header", ret);
- return;
+ return message_length;
}
proto_tree_add_text(snmp_tree, tvb, offset, length,
"Encrypted PDU (%d bytes)", length);
g_free(cryptpdu);
if (check_col(pinfo->cinfo, COL_INFO))
col_set_str(pinfo->cinfo, COL_INFO, "Encrypted PDU");
- return;
+ return message_length;
}
ret = asn1_sequence_decode(&asn1, &global_length, &length);
if (ret != ASN1_ERR_NOERROR) {
dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree,
"PDU header", ret);
- return;
+ return message_length;
}
offset += length;
ret = asn1_octet_string_decode (&asn1, &cengineid,
if (ret != ASN1_ERR_NOERROR) {
dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree,
"context engine id", ret);
- return;
+ return message_length;
}
if (snmp_tree) {
proto_tree_add_text(snmp_tree, tvb, offset, length,
if (ret != ASN1_ERR_NOERROR) {
dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree,
"context name", ret);
- return;
+ return message_length;
}
if (snmp_tree) {
proto_tree_add_text(snmp_tree, tvb, offset, length,
- "Context Name: %.*s", cname_length,
- SAFE_STRING(cname));
+ "Context Name: %s",
+ SAFE_STRING(cname, cname_length));
}
g_free(cname);
offset += length;
default:
dissect_snmp_error(tvb, offset, pinfo, snmp_tree,
"PDU for unknown version of SNMP");
- return;
+ return message_length;
}
start = asn1.offset;
if (ret != ASN1_ERR_NOERROR) {
dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree,
"PDU type", ret);
- return;
+ return message_length;
}
if (cls != ASN1_CTX || con != ASN1_CON) {
dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree,
"PDU type", ASN1_ERR_WRONG_TYPE);
- return;
+ return message_length;
}
dissect_common_pdu(tvb, offset, pinfo, snmp_tree, asn1, pdu_type, start);
+ return message_length;
}
static void
col_add_str(pinfo->cinfo, COL_INFO, pdu_type_string);
length = asn1.offset - start;
if (tree) {
- proto_tree_add_text(smux_tree, tvb, offset, length,
- "PDU type: %s", pdu_type_string);
+ proto_tree_add_uint(smux_tree, hf_smux_pdutype, tvb,
+ offset, length, pdu_type);
}
offset += length;
ret = asn1_uint32_decode (&asn1, &version, &length);
return;
}
if (tree) {
- proto_tree_add_text(smux_tree, tvb, offset, length,
- "Version: %d", version);
+ proto_tree_add_uint(smux_tree, hf_smux_version, tvb,
+ offset, length, version);
}
offset += length;
}
if (tree) {
proto_tree_add_text(smux_tree, tvb, offset, length,
- "Application: %.*s", application_length,
- SAFE_STRING(application));
+ "Application: %s",
+ SAFE_STRING(application, application_length));
}
g_free(application);
offset += length;
}
if (tree) {
proto_tree_add_text(smux_tree, tvb, offset, length,
- "Password: %.*s", password_length,
- SAFE_STRING(password));
+ "Password: %s",
+ SAFE_STRING(password, password_length));
}
g_free(password);
offset += length;
col_add_str(pinfo->cinfo, COL_INFO, pdu_type_string);
length = asn1.offset - start;
if (tree) {
- proto_tree_add_text(smux_tree, tvb, offset, length,
- "PDU type: %s", pdu_type_string);
+ proto_tree_add_uint(smux_tree, hf_smux_pdutype, tvb,
+ offset, length, pdu_type);
}
offset += length;
ret = asn1_uint32_value_decode (&asn1, pdu_length, &cause);
col_add_str(pinfo->cinfo, COL_INFO, pdu_type_string);
length = asn1.offset - start;
if (tree) {
- proto_tree_add_text(smux_tree, tvb, offset, length,
- "PDU type: %s", pdu_type_string);
+ proto_tree_add_uint(smux_tree, hf_smux_pdutype, tvb,
+ offset, length, pdu_type);
}
offset += length;
ret = asn1_oid_decode (&asn1, ®id, ®id_length, &length);
col_add_str(pinfo->cinfo, COL_INFO, pdu_type_string);
length = asn1.offset - start;
if (tree) {
- proto_tree_add_text(smux_tree, tvb, offset, length,
- "PDU type: %s", pdu_type_string);
+ proto_tree_add_uint(smux_tree, hf_smux_pdutype, tvb,
+ offset, length, pdu_type);
}
offset += length;
ret = asn1_uint32_value_decode (&asn1, pdu_length, &priority);
col_add_str(pinfo->cinfo, COL_INFO, pdu_type_string);
length = asn1.offset - start;
if (tree) {
- proto_tree_add_text(smux_tree, tvb, offset, length,
- "PDU type: %s", pdu_type_string);
+ proto_tree_add_uint(smux_tree, hf_smux_pdutype, tvb,
+ offset, length, pdu_type);
}
offset += length;
ret = asn1_uint32_value_decode (&asn1, pdu_length, &commit);
}
}
- dissect_snmp_pdu(tvb, 0, pinfo, tree, "SNMP", proto_snmp, ett_snmp);
+ dissect_snmp_pdu(tvb, 0, pinfo, tree, proto_snmp, ett_snmp, FALSE);
+}
+
+static void
+dissect_snmp_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+ int offset = 0;
+ guint message_len;
+
+ while (tvb_reported_length_remaining(tvb, offset) > 0) {
+ message_len = dissect_snmp_pdu(tvb, 0, pinfo, tree,
+ proto_snmp, ett_snmp, TRUE);
+ if (message_len == 0) {
+ /*
+ * We don't have all the data for that message,
+ * so we need to do desegmentation;
+ * "dissect_snmp_pdu()" has set that up.
+ */
+ break;
+ }
+ offset += message_len;
+ }
}
static void
#endif
static hf_register_info hf[] = {
+ { &hf_snmp_version,
+ { "Version", "snmp.version", FT_UINT8, BASE_DEC, VALS(versions),
+ 0x0, "", HFILL }},
+ { &hf_snmp_community,
+ { "Community", "snmp.community", FT_STRING, BASE_NONE, NULL,
+ 0x0, "", HFILL }},
+ { &hf_snmp_request_id,
+ { "Request Id", "snmp.id", FT_UINT32, BASE_HEX, NULL,
+ 0x0, "Id for this transaction", HFILL }},
+ { &hf_snmp_pdutype,
+ { "PDU type", "snmp.pdutype", FT_UINT8, BASE_DEC, VALS(pdu_types),
+ 0x0, "", HFILL }},
+ { &hf_snmp_agent,
+ { "Agent address", "snmp.agent", FT_IPv4, BASE_NONE, NULL,
+ 0x0, "", HFILL }},
+ { &hf_snmp_enterprise,
+ { "Enterprise", "snmp.enterprise", FT_STRING, BASE_NONE, NULL,
+ 0x0, "", HFILL }},
+ { &hf_snmp_error_status,
+ { "Error Status", "snmp.error", FT_UINT8, BASE_DEC, VALS(error_statuses),
+ 0x0, "", HFILL }},
+ { &hf_snmp_oid,
+ { "Object identifier", "snmp.oid", FT_STRING, BASE_NONE, NULL,
+ 0x0, "", HFILL }},
+ { &hf_snmp_traptype,
+ { "Trap type", "snmp.traptype", FT_UINT8, BASE_DEC, VALS(trap_types),
+ 0x0, "", HFILL }},
+ { &hf_snmp_spectraptype,
+ { "Specific trap type", "snmp.spectraptype", FT_UINT32, BASE_DEC, NULL,
+ 0x0, "", HFILL }},
+ { &hf_snmp_timestamp,
+ { "Timestamp", "snmp.timestamp", FT_UINT8, BASE_DEC, NULL,
+ 0x0, "", HFILL }},
{ &hf_snmpv3_flags,
{ "SNMPv3 Flags", "snmpv3.flags", FT_UINT8, BASE_HEX, NULL,
0x0, "", HFILL }},
{ &hf_snmpv3_flags_report,
{ "Reportable", "snmpv3.flags.report", FT_BOOLEAN, 8,
TFS(&flags_set_truth), TH_REPORT, "", HFILL }},
- };
+ };
static gint *ett[] = {
&ett_snmp,
- &ett_smux,
&ett_parameters,
&ett_parameters_qos,
&ett_global,
&ett_flags,
&ett_secur,
};
+ module_t *snmp_module;
#ifdef HAVE_SOME_SNMP
init_mib();
read_configs();
#endif /* HAVE_SOME_SNMP */
- proto_snmp = proto_register_protocol("Simple Network Management Protocol",
+ proto_snmp = proto_register_protocol("Simple Network Management Protocol",
"SNMP", "snmp");
- proto_smux = proto_register_protocol("SNMP Multiplex Protocol",
- "SMUX", "smux");
- proto_register_field_array(proto_snmp, hf, array_length(hf));
+ proto_register_field_array(proto_snmp, hf, array_length(hf));
proto_register_subtree_array(ett, array_length(ett));
snmp_handle = create_dissector_handle(dissect_snmp, proto_snmp);
+
+ /* Register configuration preferences */
+ snmp_module = prefs_register_protocol(proto_snmp, NULL);
+ prefs_register_bool_preference(snmp_module, "display_oid",
+ "Show SNMP OID in info column",
+ "Whether the SNMP OID should be shown in the info column",
+ &display_oid);
+ prefs_register_bool_preference(snmp_module, "desegment",
+ "Desegment all SNMP-over-TCP messages spanning multiple TCP segments",
+ "Whether the SNMP dissector should desegment all messages "
+ "spanning multiple TCP segments",
+ &snmp_desegment);
}
void
proto_reg_handoff_snmp(void)
{
- dissector_handle_t smux_handle;
+ dissector_handle_t snmp_tcp_handle;
dissector_add("udp.port", UDP_PORT_SNMP, snmp_handle);
dissector_add("udp.port", UDP_PORT_SNMP_TRAP, snmp_handle);
- smux_handle = create_dissector_handle(dissect_smux, proto_smux);
- dissector_add("tcp.port", TCP_PORT_SMUX, smux_handle);
dissector_add("ethertype", ETHERTYPE_SNMP, snmp_handle);
dissector_add("ipx.socket", IPX_SOCKET_SNMP_AGENT, snmp_handle);
dissector_add("ipx.socket", IPX_SOCKET_SNMP_SINK, snmp_handle);
+ dissector_add("hpext.dxsap", HPEXT_SNMP, snmp_handle);
+
+ snmp_tcp_handle = create_dissector_handle(dissect_snmp_tcp, proto_snmp);
+ dissector_add("tcp.port", TCP_PORT_SNMP, snmp_tcp_handle);
+ dissector_add("tcp.port", TCP_PORT_SNMP_TRAP, snmp_tcp_handle);
+
data_handle = find_dissector("data");
}
+
+void
+proto_register_smux(void)
+{
+ static hf_register_info hf[] = {
+ { &hf_smux_version,
+ { "Version", "smux.version", FT_UINT8, BASE_DEC, NULL,
+ 0x0, "", HFILL }},
+ { &hf_smux_pdutype,
+ { "PDU type", "smux.pdutype", FT_UINT8, BASE_DEC, VALS(smux_types),
+ 0x0, "", HFILL }},
+ };
+ static gint *ett[] = {
+ &ett_smux,
+ };
+
+ proto_smux = proto_register_protocol("SNMP Multiplex Protocol",
+ "SMUX", "smux");
+ proto_register_field_array(proto_smux, hf, array_length(hf));
+ proto_register_subtree_array(ett, array_length(ett));
+}
+
+void
+proto_reg_handoff_smux(void)
+{
+ dissector_handle_t smux_handle;
+
+ smux_handle = create_dissector_handle(dissect_smux, proto_smux);
+ dissector_add("tcp.port", TCP_PORT_SMUX, smux_handle);
+}