summaryrefslogtreecommitdiff
path: root/asn1/snmp/packet-snmp-template.c
diff options
context:
space:
mode:
authorAnders Broman <anders.broman@ericsson.com>2005-12-04 21:45:38 +0000
committerAnders Broman <anders.broman@ericsson.com>2005-12-04 21:45:38 +0000
commit223506c53791f46282c03f4caba3bafbb64342f8 (patch)
tree5d7ba0a3a75e985c4387b6578bcdd21d683f3e33 /asn1/snmp/packet-snmp-template.c
parentd3970d3674861b5e08ee0e2b6b2d87718b3e482f (diff)
downloadwireshark-223506c53791f46282c03f4caba3bafbb64342f8.tar.gz
Work in progress an asn2eth generated snmp dissector.
svn path=/trunk/; revision=16674
Diffstat (limited to 'asn1/snmp/packet-snmp-template.c')
-rw-r--r--asn1/snmp/packet-snmp-template.c978
1 files changed, 978 insertions, 0 deletions
diff --git a/asn1/snmp/packet-snmp-template.c b/asn1/snmp/packet-snmp-template.c
new file mode 100644
index 0000000000..cfddea4a14
--- /dev/null
+++ b/asn1/snmp/packet-snmp-template.c
@@ -0,0 +1,978 @@
+/* packet-snmp.c
+ * Routines for SNMP (simple network management protocol)
+ * Copyright (C) 1998 Didier Jorand
+ *
+ * See RFC 1157 for SNMPv1.
+ *
+ * See RFCs 1901, 1905, and 1906 for SNMPv2c.
+ *
+ * See RFCs 1905, 1906, 1909, and 1910 for SNMPv2u [historic].
+ *
+ * See RFCs 2570-2576 for SNMPv3
+ * Updated to use the asn2eth compiler made by Tomas Kukosa
+ * Copyright (C) 2005 Anders Broman [AT] ericsson.com
+ *
+ *
+ * $Id$
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@ethereal.com>
+ * Copyright 1998 Gerald Combs
+ *
+ * Some stuff from:
+ *
+ * GXSNMP -- An snmp mangament application
+ * Copyright (C) 1998 Gregory McLean & Jochen Friedrich
+ * Beholder RMON ethernet network monitor,Copyright (C) 1993 DNPAP group
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdio.h>
+#include <string.h>
+
+#include <glib.h>
+
+#include <epan/packet.h>
+#include <epan/conversation.h>
+#include "etypes.h"
+#include <epan/prefs.h>
+#include <epan/sminmpec.h>
+#include <epan/emem.h>
+#include "packet-ipx.h"
+#include "packet-hpext.h"
+
+
+#include "packet-ber.h"
+
+#ifdef HAVE_SOME_SNMP
+
+#ifdef HAVE_NET_SNMP
+# include <net-snmp/net-snmp-config.h>
+# include <net-snmp/mib_api.h>
+# include <net-snmp/library/default_store.h>
+# include <net-snmp/config_api.h>
+#else /* HAVE_NET_SNMP */
+# include <ucd-snmp/ucd-snmp-config.h>
+# include <ucd-snmp/asn1.h>
+# include <ucd-snmp/snmp_api.h>
+# include <ucd-snmp/snmp_impl.h>
+# include <ucd-snmp/mib.h>
+# include <ucd-snmp/default_store.h>
+# include <ucd-snmp/read_config.h>
+# include <ucd-snmp/tools.h>
+#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
+# define netsnmp_ds_set_boolean ds_set_boolean
+# define netsnmp_ds_set_int ds_set_int
+#endif
+
+#ifdef _WIN32
+# include <epan/filesystem.h>
+#endif /* _WIN32 */
+
+ /*
+ * Define values "sprint_realloc_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
+
+#endif /* HAVE_SOME_SNMP */
+
+#include "packet-snmp.h"
+#include "format-oid.h"
+
+#define PNAME "Simple Network Management Protocol"
+#define PSNAME "SNMP"
+#define PFNAME "snmp"
+
+#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
+
+/* Initialize the protocol and registered fields */
+static int proto_snmp = -1;
+static int proto_smux = -1;
+
+/* Default MIB modules to load */
+/*
+ * XXX - According to Wes Hardaker, we shouldn't do this:
+ * http://www.ethereal.com/lists/ethereal-dev/200412/msg00222.html
+ */
+#ifdef _WIN32
+# define DEF_MIB_MODULES "IP-MIB;IF-MIB;TCP-MIB;UDP-MIB;SNMPv2-MIB;RFC1213-MIB;UCD-SNMP-MIB"
+# define IMPORT_SEPARATOR ":"
+#else
+# define DEF_MIB_MODULES "IP-MIB:IF-MIB:TCP-MIB:UDP-MIB:SNMPv2-MIB:RFC1213-MIB:UCD-SNMP-MIB"
+# define IMPORT_SEPARATOR ";"
+#endif /* _WIN32 */
+
+static const gchar *mib_modules = DEF_MIB_MODULES;
+static gboolean display_oid = TRUE;
+
+/* Subdissector tables */
+static dissector_table_t variable_oid_dissector_table;
+
+#define TH_AUTH 0x01
+#define TH_CRYPT 0x02
+#define TH_REPORT 0x04
+
+/* desegmentation of SNMP-over-TCP */
+static gboolean snmp_desegment = TRUE;
+
+/* Global variables */
+
+guint32 MsgSecurityModel;
+
+static dissector_handle_t snmp_handle;
+static dissector_handle_t data_handle;
+
+static int hf_snmp_v3_flags_auth = -1;
+static int hf_snmp_v3_flags_crypt = -1;
+static int hf_snmp_v3_flags_report = -1;
+
+static int hf_snmp_engineid_conform = -1;
+static int hf_snmp_engineid_enterprise = -1;
+static int hf_snmp_engineid_format = -1;
+static int hf_snmp_engineid_ipv4 = -1;
+static int hf_snmp_engineid_ipv6 = -1;
+static int hf_snmp_engineid_mac = -1;
+static int hf_snmp_engineid_text = -1;
+static int hf_snmp_engineid_time = -1;
+static int hf_snmp_engineid_data = -1;
+#include "packet-snmp-hf.c"
+
+static int hf_smux_version = -1;
+static int hf_smux_pdutype = -1;
+
+/* Initialize the subtree pointers */
+static gint ett_smux = -1;
+static gint ett_snmp = -1;
+static gint ett_engineid = -1;
+static gint ett_msgFlags = -1;
+
+#include "packet-snmp-ett.c"
+
+
+/* Security Models */
+
+#define SNMP_SEC_ANY 0
+#define SNMP_SEC_V1 1
+#define SNMP_SEC_V2C 2
+#define SNMP_SEC_USM 3
+
+static const value_string sec_models[] = {
+ { SNMP_SEC_ANY, "Any" },
+ { SNMP_SEC_V1, "V1" },
+ { SNMP_SEC_V2C, "V2C" },
+ { SNMP_SEC_USM, "USM" },
+ { 0, NULL }
+};
+
+/* SMUX PDU types */
+#define SMUX_MSG_OPEN 0
+#define SMUX_MSG_CLOSE 1
+#define SMUX_MSG_RREQ 2
+#define SMUX_MSG_RRSP 3
+#define SMUX_MSG_SOUT 4
+
+static const value_string smux_types[] = {
+ { SMUX_MSG_OPEN, "Open" },
+ { SMUX_MSG_CLOSE, "Close" },
+ { SMUX_MSG_RREQ, "Registration Request" },
+ { SMUX_MSG_RRSP, "Registration Response" },
+ { SMUX_MSG_SOUT, "Commit Or Rollback" },
+ { 0, NULL }
+};
+
+int oid_to_subid_buf(const guint8 *oid, gint oid_len, subid_t *buf, int buf_len) {
+ int i, out_len;
+ guint8 byte;
+ guint32 value;
+
+ value=0; out_len = 0;
+ for (i=0; i<oid_len; i++){
+ if (out_len >= buf_len) break;
+ byte = oid[i];
+ if (i == 0) {
+ buf[out_len++] = byte/40;
+ buf[out_len++] = byte%40;
+ continue;
+ }
+ value = (value << 7) | (byte & 0x7F);
+ if (byte & 0x80) {
+ continue;
+ }
+ buf[out_len++] = value;
+ value = 0;
+ }
+
+ return out_len;
+}
+
+gchar *
+format_oid(subid_t *oid, guint oid_length)
+{
+ char *result;
+ int result_len;
+ int len;
+ unsigned int i;
+ char *buf;
+#ifdef HAVE_SOME_SNMP
+ guchar *oid_string;
+ size_t oid_string_len;
+ size_t oid_out_len;
+#endif
+
+ result_len = oid_length * 22;
+
+#ifdef HAVE_SOME_SNMP
+ /*
+ * Get the decoded form of the OID, and add its length to the
+ * length of the result string.
+ *
+ * XXX - check for "sprint_realloc_objid()" failure.
+ */
+ oid_string_len = 256;
+ oid_string = malloc(oid_string_len);
+ if (oid_string == NULL)
+ return NULL;
+ *oid_string = '\0';
+ oid_out_len = 0;
+ sprint_realloc_objid(&oid_string, &oid_string_len, &oid_out_len, 1,
+ oid, oid_length);
+ result_len += strlen(oid_string) + 3;
+#endif
+
+ result = ep_alloc(result_len + 1);
+ buf = result;
+ len = g_snprintf(buf, result_len + 1 - (buf-result), "%lu", (unsigned long)oid[0]);
+ buf += len;
+ for (i = 1; i < oid_length;i++) {
+ len = g_snprintf(buf, result_len + 1 - (buf-result), ".%lu", (unsigned long)oid[i]);
+ buf += len;
+ }
+
+#ifdef HAVE_SOME_SNMP
+ /*
+ * Append the decoded form of the OID.
+ */
+ g_snprintf(buf, result_len + 1 -(buf-result), " (%s)", oid_string);
+ 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 non_decoded_len;
+ 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 = malloc(oid_string_len);
+ if (oid_string != NULL) {
+ *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_len = oid_length * 22 + 1;
+ *non_decoded = ep_alloc(non_decoded_len);
+ buf = *non_decoded;
+ len = g_snprintf(buf, non_decoded_len-(buf-*non_decoded), "%lu", (unsigned long)oid[0]);
+ buf += len;
+ for (i = 1; i < oid_length; i++) {
+ len = g_snprintf(buf, non_decoded_len-(buf-*non_decoded), ".%lu", (unsigned long)oid[i]);
+ buf += len;
+ }
+}
+
+
+#define F_SNMP_ENGINEID_CONFORM 0x80
+#define SNMP_ENGINEID_RFC1910 0x00
+#define SNMP_ENGINEID_RFC3411 0x01
+
+static const true_false_string tfs_snmp_engineid_conform = {
+ "RFC3411 (SNMPv3)",
+ "RFC1910 (Non-SNMPv3)"
+};
+
+#define SNMP_ENGINEID_FORMAT_IPV4 0x01
+#define SNMP_ENGINEID_FORMAT_IPV6 0x02
+#define SNMP_ENGINEID_FORMAT_MACADDRESS 0x03
+#define SNMP_ENGINEID_FORMAT_TEXT 0x04
+#define SNMP_ENGINEID_FORMAT_OCTETS 0x05
+
+static const value_string snmp_engineid_format_vals[] = {
+ { SNMP_ENGINEID_FORMAT_IPV4, "IPv4 address" },
+ { SNMP_ENGINEID_FORMAT_IPV6, "IPv6 address" },
+ { SNMP_ENGINEID_FORMAT_MACADDRESS, "MAC address" },
+ { SNMP_ENGINEID_FORMAT_TEXT, "Text, administratively assigned" },
+ { SNMP_ENGINEID_FORMAT_OCTETS, "Octets, administratively assigned" },
+ { 0, NULL }
+};
+
+/*
+ * SNMP Engine ID dissection according to RFC 3411 (SnmpEngineID TC)
+ * or historic RFC 1910 (AgentID)
+ */
+int
+dissect_snmp_engineid(proto_tree *tree, tvbuff_t *tvb, int offset, int len)
+{
+ proto_item *item = NULL;
+ guint8 conformance, format;
+ guint32 enterpriseid, seconds;
+ nstime_t ts;
+ int len_remain = len;
+
+ /* first bit: engine id conformance */
+ if (len_remain<4) return offset;
+ conformance = ((tvb_get_guint8(tvb, offset)>>7) && 0x01);
+ proto_tree_add_item(tree, hf_snmp_engineid_conform, tvb, offset, 1, FALSE);
+
+ /* 4-byte enterprise number/name */
+ if (len_remain<4) return offset;
+ enterpriseid = tvb_get_ntohl(tvb, offset);
+ if (conformance)
+ enterpriseid -= 0x80000000; /* ignore first bit */
+ proto_tree_add_uint(tree, hf_snmp_engineid_enterprise, tvb, offset, 4, enterpriseid);
+ offset+=4;
+ len_remain-=4;
+
+ switch(conformance) {
+
+ case SNMP_ENGINEID_RFC1910:
+ /* 12-byte AgentID w/ 8-byte trailer */
+ if (len_remain==8) {
+ proto_tree_add_text(tree, tvb, offset, 8, "AgentID Trailer: 0x%s",
+ tvb_bytes_to_str(tvb, offset, 8));
+ offset+=8;
+ len_remain-=8;
+ } else {
+ proto_tree_add_text(tree, tvb, offset, len_remain, "<Data not conforming to RFC1910>");
+ return offset;
+ }
+ break;
+
+ case SNMP_ENGINEID_RFC3411: /* variable length: 5..32 */
+
+ /* 1-byte format specifier */
+ if (len_remain<1) return offset;
+ format = tvb_get_guint8(tvb, offset);
+ item = proto_tree_add_uint_format(tree, hf_snmp_engineid_format, tvb, offset, 1, format, "Engine ID Format: %s (%d)",
+ val_to_str(format, snmp_engineid_format_vals, "Reserved/Enterprise-specific"), format);
+ offset+=1;
+ len_remain-=1;
+
+ switch(format) {
+ case SNMP_ENGINEID_FORMAT_IPV4:
+ /* 4-byte IPv4 address */
+ if (len_remain==4) {
+ proto_tree_add_item(tree, hf_snmp_engineid_ipv4, tvb, offset, 4, FALSE);
+ offset+=4;
+ len_remain=0;
+ }
+ break;
+ case SNMP_ENGINEID_FORMAT_IPV6:
+ /* 16-byte IPv6 address */
+ if (len_remain==16) {
+ proto_tree_add_item(tree, hf_snmp_engineid_ipv6, tvb, offset, 16, FALSE);
+ offset+=16;
+ len_remain=0;
+ }
+ break;
+ case SNMP_ENGINEID_FORMAT_MACADDRESS:
+ /* 6-byte MAC address */
+ if (len_remain==6) {
+ proto_tree_add_item(tree, hf_snmp_engineid_mac, tvb, offset, 6, FALSE);
+ offset+=6;
+ len_remain=0;
+ }
+ break;
+ case SNMP_ENGINEID_FORMAT_TEXT:
+ /* max. 27-byte string, administratively assigned */
+ if (len_remain<=27) {
+ proto_tree_add_item(tree, hf_snmp_engineid_text, tvb, offset, len_remain, FALSE);
+ offset+=len_remain;
+ len_remain=0;
+ }
+ break;
+ case 128:
+ /* most common enterprise-specific format: (ucd|net)-snmp random */
+ if ((enterpriseid==2021)||(enterpriseid==8072)) {
+ proto_item_append_text(item, (enterpriseid==2021) ? ": UCD-SNMP Random" : ": Net-SNMP Random");
+ /* demystify: 4B random, 4B epoch seconds */
+ if (len_remain==8) {
+ proto_tree_add_item(tree, hf_snmp_engineid_data, tvb, offset, 4, FALSE);
+ seconds = tvb_get_letohl(tvb, offset+4);
+ ts.secs = seconds;
+ proto_tree_add_time_format(tree, hf_snmp_engineid_time, tvb, offset+4, 4,
+ &ts, "Engine ID Data: Creation Time: %s",
+ abs_time_secs_to_str(seconds));
+ offset+=8;
+ len_remain=0;
+ }
+ }
+ break;
+ case SNMP_ENGINEID_FORMAT_OCTETS:
+ default:
+ /* max. 27 bytes, administratively assigned or unknown format */
+ if (len_remain<=27) {
+ proto_tree_add_item(tree, hf_snmp_engineid_data, tvb, offset, len_remain, FALSE);
+ offset+=len_remain;
+ len_remain=0;
+ }
+ break;
+ }
+ }
+
+ if (len_remain>0) {
+ proto_tree_add_text(tree, tvb, offset, len_remain, "<Data not conforming to RFC3411>");
+ offset+=len_remain;
+ }
+ return offset;
+}
+
+#include "packet-snmp-fn.c"
+
+guint
+dissect_snmp_pdu(tvbuff_t *tvb, int offset, packet_info *pinfo,
+ proto_tree *tree, int proto, gint ett, gboolean is_tcp)
+{
+
+ guint length_remaining;
+ gint8 class;
+ gboolean pc, ind = 0;
+ gint32 tag;
+ guint32 len;
+ guint message_length;
+ int start_offset = offset;
+ guint32 version = 0;
+
+ proto_tree *snmp_tree = NULL;
+ proto_item *item = NULL;
+
+ /*
+ * 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.
+ */
+
+ /*
+ * 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.
+ */
+ /* Set tree to 0 to not display internakl BER fields if option used.*/
+ offset = dissect_ber_identifier(pinfo, 0, tvb, offset, &class, &pc, &tag);
+ offset = dissect_ber_length(pinfo, 0, tvb, offset, &len, &ind);
+
+ message_length = len + 2;
+ offset = dissect_ber_integer(FALSE, pinfo, 0, tvb, offset, -1, &version);
+
+
+ /*
+ * 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 = start_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(find_protocol_by_id(proto)));
+ }
+
+ if (tree) {
+ item = proto_tree_add_item(tree, proto, tvb, offset,
+ message_length, FALSE);
+ snmp_tree = proto_item_add_subtree(item, ett);
+ }
+
+ switch (version){
+ case 0: /* v1 */
+ case 1: /* v2c */
+ offset = dissect_snmp_Message(FALSE , tvb, start_offset, pinfo, snmp_tree, -1);
+ break;
+ case 2: /* v2u */
+ offset = dissect_snmp_Messagev2u(FALSE , tvb, start_offset, pinfo, snmp_tree, -1);
+ break;
+ /* v3 */
+ case 3:
+ offset = dissect_snmp_SNMPv3Message(FALSE , tvb, start_offset, pinfo, snmp_tree, -1);
+ break;
+ default:
+ /*
+ * Return the length remaining in the tvbuff, so
+ * if this is SNMP-over-TCP, our caller thinks there's
+ * nothing left to dissect.
+ */
+ proto_tree_add_text(snmp_tree, tvb, offset, -1,"Unknown version");
+ return length_remaining;
+ break;
+ }
+ return offset;
+
+
+
+}
+
+static gint
+dissect_snmp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+ conversation_t *conversation;
+ int offset;
+ gint8 tmp_class;
+ gboolean tmp_pc;
+ gint32 tmp_tag;
+ guint32 tmp_length;
+ gboolean tmp_ind;
+
+ /*
+ * See if this looks like SNMP or not. if not, return 0 so
+ * ethereal can try som other dissector instead.
+ */
+ /* All SNMP packets are BER encoded and consist of a SEQUENCE
+ * that spans the entire PDU. The first item is an INTEGER that
+ * has the values 0-2 (version 1-3).
+ * if not it is not snmp.
+ */
+ /* SNMP starts with a SEQUENCE */
+ offset = get_ber_identifier(tvb, 0, &tmp_class, &tmp_pc, &tmp_tag);
+ if((tmp_class!=BER_CLASS_UNI)||(tmp_tag!=BER_UNI_TAG_SEQUENCE)){
+ return 0;
+ }
+ /* then comes a length which spans the rest of the tvb */
+ offset = get_ber_length(NULL, tvb, offset, &tmp_length, &tmp_ind);
+ if(tmp_length!=(guint32)tvb_reported_length_remaining(tvb, offset)){
+ return 0;
+ }
+ /* then comes an INTEGER (version)*/
+ offset = get_ber_identifier(tvb, offset, &tmp_class, &tmp_pc, &tmp_tag);
+ if((tmp_class!=BER_CLASS_UNI)||(tmp_tag!=BER_UNI_TAG_INTEGER)){
+ return 0;
+ }
+ /* do we need to test that version is 0 - 2 (version1-3) ? */
+
+
+ /*
+ * The first SNMP packet goes to the SNMP port; the second one
+ * may come from some *other* port, but goes back to the same
+ * IP address and port as the ones from which the first packet
+ * came; all subsequent packets presumably go between those two
+ * IP addresses and ports.
+ *
+ * If this packet went to the SNMP port, we check to see if
+ * there's already a conversation with one address/port pair
+ * matching the source IP address and port of this packet,
+ * the other address matching the destination IP address of this
+ * packet, and any destination port.
+ *
+ * If not, we create one, with its address 1/port 1 pair being
+ * the source address/port of this packet, its address 2 being
+ * the destination address of this packet, and its port 2 being
+ * wildcarded, and give it the SNMP dissector as a dissector.
+ */
+ if (pinfo->destport == UDP_PORT_SNMP) {
+ conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, PT_UDP,
+ pinfo->srcport, 0, NO_PORT_B);
+ if( (conversation == NULL) || (conversation->dissector_handle!=snmp_handle) ){
+ conversation = conversation_new(pinfo->fd->num, &pinfo->src, &pinfo->dst, PT_UDP,
+ pinfo->srcport, 0, NO_PORT2);
+ conversation_set_dissector(conversation, snmp_handle);
+ }
+ }
+
+ return 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
+dissect_smux_pdu(tvbuff_t *tvb, int offset, packet_info *pinfo,
+ proto_tree *tree, int proto, gint ett)
+{
+ /* FIX ME */
+}
+static void
+dissect_smux(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+ dissect_smux_pdu(tvb, 0, pinfo, tree, proto_smux, ett_smux);
+}
+static void
+process_prefs(void)
+{
+#ifdef HAVE_SOME_SNMP
+ gchar *tmp_mib_modules;
+ static gboolean mibs_loaded = FALSE;
+
+ if (mibs_loaded) {
+ /*
+ * Unload the MIBs, as we'll be reloading them based on
+ * the current preference setting.
+ */
+ shutdown_mib(); /* unload MIBs */
+ }
+
+ /*
+ * Cannot check if MIBS is already set, as it could be set by Ethereal.
+ *
+ * If we have a list of modules to load, put that list in MIBS,
+ * otherwise clear MIBS.
+ */
+ if (mib_modules != NULL) {
+ tmp_mib_modules = g_strconcat("MIBS=", mib_modules, NULL);
+ /*
+ * Try to be clever and replace colons for semicolons under
+ * Windows. Do the converse on non-Windows systems. This
+ * handles cases where we've copied a preferences file
+ * between a non-Windows box and a Windows box or upgraded
+ * from an older version of Ethereal under Windows.
+ */
+ g_strdelimit(tmp_mib_modules, IMPORT_SEPARATOR, ENV_SEPARATOR_CHAR);
+
+#ifdef _WIN32
+ _putenv(tmp_mib_modules);
+#else
+ putenv(tmp_mib_modules);
+#endif /*_WIN32*/
+ } else {
+#ifdef _WIN32
+ _putenv("MIBS");
+#else
+ putenv("MIBS");
+#endif /* _WIN32 */
+ }
+
+ /*
+ * Load the MIBs.
+ */
+ register_mib_handlers();
+ read_premib_configs();
+ init_mib();
+ read_configs();
+ mibs_loaded = TRUE;
+#endif /* HAVE_SOME_SNMP */
+}
+/*--- proto_register_snmp -------------------------------------------*/
+void proto_register_snmp(void) {
+
+#if defined(_WIN32) && defined(HAVE_SOME_SNMP)
+ char *mib_path;
+ int mib_path_len;
+#define MIB_PATH_APPEND "snmp\\mibs"
+#endif
+ gchar *tmp_mib_modules;
+
+ /* List of fields */
+ static hf_register_info hf[] = {
+ { &hf_snmp_v3_flags_auth,
+ { "Authenticated", "snmp.v3.flags.auth", FT_BOOLEAN, 8,
+ TFS(&flags_set_truth), TH_AUTH, "", HFILL }},
+ { &hf_snmp_v3_flags_crypt,
+ { "Encrypted", "snmp.v3.flags.crypt", FT_BOOLEAN, 8,
+ TFS(&flags_set_truth), TH_CRYPT, "", HFILL }},
+ { &hf_snmp_v3_flags_report,
+ { "Reportable", "snmp.v3.flags.report", FT_BOOLEAN, 8,
+ TFS(&flags_set_truth), TH_REPORT, "", HFILL }},
+ { &hf_snmp_engineid_conform, {
+ "Engine ID Conformance", "snmp.engineid.conform", FT_BOOLEAN, 8,
+ TFS(&tfs_snmp_engineid_conform), F_SNMP_ENGINEID_CONFORM, "Engine ID RFC3411 Conformance", HFILL }},
+ { &hf_snmp_engineid_enterprise, {
+ "Engine Enterprise ID", "snmp.engineid.enterprise", FT_UINT32, BASE_DEC,
+ VALS(sminmpec_values), 0, "Engine Enterprise ID", HFILL }},
+ { &hf_snmp_engineid_format, {
+ "Engine ID Format", "snmp.engineid.format", FT_UINT8, BASE_DEC,
+ VALS(snmp_engineid_format_vals), 0, "Engine ID Format", HFILL }},
+ { &hf_snmp_engineid_ipv4, {
+ "Engine ID Data: IPv4 address", "snmp.engineid.ipv4", FT_IPv4, BASE_NONE,
+ NULL, 0, "Engine ID Data: IPv4 address", HFILL }},
+ { &hf_snmp_engineid_ipv6, {
+ "Engine ID Data: IPv6 address", "snmp.engineid.ipv6", FT_IPv6, BASE_NONE,
+ NULL, 0, "Engine ID Data: IPv6 address", HFILL }},
+ { &hf_snmp_engineid_mac, {
+ "Engine ID Data: MAC address", "snmp.engineid.mac", FT_ETHER, BASE_NONE,
+ NULL, 0, "Engine ID Data: MAC address", HFILL }},
+ { &hf_snmp_engineid_text, {
+ "Engine ID Data: Text", "snmp.engineid.text", FT_STRING, BASE_NONE,
+ NULL, 0, "Engine ID Data: Text", HFILL }},
+ { &hf_snmp_engineid_time, {
+ "Engine ID Data: Time", "snmp.engineid.time", FT_ABSOLUTE_TIME, BASE_NONE,
+ NULL, 0, "Engine ID Data: Time", HFILL }},
+ { &hf_snmp_engineid_data, {
+ "Engine ID Data", "snmp.engineid.data", FT_BYTES, BASE_HEX,
+ NULL, 0, "Engine ID Data", HFILL }},
+
+#include "packet-snmp-hfarr.c"
+ };
+
+ /* List of subtrees */
+ static gint *ett[] = {
+ &ett_snmp,
+ &ett_engineid,
+ &ett_msgFlags,
+
+#include "packet-snmp-ettarr.c"
+ };
+ module_t *snmp_module;
+
+ #ifdef HAVE_SOME_SNMP
+
+#ifdef _WIN32
+ /* Set MIBDIRS so that the SNMP library can find its mibs. */
+ /* XXX - Should we set MIBS or MIBFILES as well? */
+ mib_path_len=strlen(get_datafile_dir()) + strlen(MIB_PATH_APPEND) + 20;
+ mib_path = ep_alloc (mib_path_len);
+ g_snprintf (mib_path, mib_path_len, "MIBDIRS=%s\\%s", get_datafile_dir(), MIB_PATH_APPEND);
+ /* Amazingly enough, Windows does not provide setenv(). */
+ if (getenv("MIBDIRS") == NULL)
+ _putenv(mib_path);
+
+#endif /* _WIN32 */
+
+ /*
+ * Suppress warnings about unknown tokens - we aren't initializing
+ * UCD SNMP in its entirety, we're just initializing the
+ * MIB-handling part because that's all we're using, which
+ * means that entries in the configuration file for other
+ * pars of the library will not be handled, and we don't want
+ * the config file reading code to whine about that.
+ */
+ netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID,
+ NETSNMP_DS_LIB_NO_TOKEN_WARNINGS, TRUE);
+ netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID,
+ NETSNMP_DS_LIB_PRINT_SUFFIX_ONLY, 2);
+#endif /* HAVE_SOME_SNMP */
+
+
+ /* Register protocol */
+ proto_snmp = proto_register_protocol(PNAME, PSNAME, PFNAME);
+ new_register_dissector("snmp", dissect_snmp, proto_snmp);
+
+ /* Register fields and subtrees */
+ proto_register_field_array(proto_snmp, hf, array_length(hf));
+ proto_register_subtree_array(ett, array_length(ett));
+
+
+ /* Register configuration preferences */
+ snmp_module = prefs_register_protocol(proto_snmp, process_prefs);
+ 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);
+
+ /*
+ * Set the default value of "mib_modules".
+ *
+ * If the MIBS environment variable is set, make its value
+ * the value of "mib_modules", otherwise, set "mib_modules"
+ * to DEF_MIB_MODULES.
+ */
+ tmp_mib_modules = getenv("MIBS");
+ if (tmp_mib_modules != NULL)
+ mib_modules = tmp_mib_modules;
+ prefs_register_string_preference(snmp_module, "mib_modules",
+ "MIB modules to load",
+ "List of MIB modules to load (the list is set to environment variable MIBS if the variable is not already set)"
+ "The list must be separated by colons (:) on non-Windows systems and semicolons (;) on Windows systems",
+ &mib_modules);
+ prefs_register_bool_preference(snmp_module, "desegment",
+ "Reassemble SNMP-over-TCP messages\nspanning multiple TCP segments",
+ "Whether the SNMP dissector should reassemble messages spanning multiple TCP segments."
+ " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
+ &snmp_desegment);
+
+}
+
+
+/*--- proto_reg_handoff_snmp ---------------------------------------*/
+void proto_reg_handoff_snmp(void) {
+ dissector_handle_t snmp_tcp_handle;
+
+ snmp_handle = find_dissector("snmp");
+
+ dissector_add("udp.port", UDP_PORT_SNMP, snmp_handle);
+ dissector_add("udp.port", UDP_PORT_SNMP_TRAP, snmp_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");
+
+ /*
+ * Process preference settings.
+ *
+ * We can't do this in the register routine, as preferences aren't
+ * read until all dissector register routines have been called (so
+ * that all dissector preferences have been registered).
+ */
+ process_prefs();
+
+}
+
+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));
+
+ variable_oid_dissector_table =
+ register_dissector_table("snmp.variable_oid",
+ "SNMP Variable OID", FT_STRING, BASE_NONE);
+}
+
+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);
+}
+
+