aboutsummaryrefslogtreecommitdiffstats
path: root/plugins/opcua/opcua.c
diff options
context:
space:
mode:
authorUlf Lamping <ulf.lamping@web.de>2007-05-14 13:58:54 +0000
committerUlf Lamping <ulf.lamping@web.de>2007-05-14 13:58:54 +0000
commitdd8feca5149d02330925f12ab269f869b4e4c360 (patch)
tree3abc54efcdcee8aaadf040b68ffb36c6b9f1c4f4 /plugins/opcua/opcua.c
parent013332de7f8fe9f4093d83521be8bfcfa7d17e76 (diff)
from Gerhard Gappmeier (ascolab):
new dissector for OPCUA protocol svn path=/trunk/; revision=21760
Diffstat (limited to 'plugins/opcua/opcua.c')
-rw-r--r--plugins/opcua/opcua.c255
1 files changed, 255 insertions, 0 deletions
diff --git a/plugins/opcua/opcua.c b/plugins/opcua/opcua.c
new file mode 100644
index 0000000000..76be7b1591
--- /dev/null
+++ b/plugins/opcua/opcua.c
@@ -0,0 +1,255 @@
+/******************************************************************************
+** $Id: opcua.c,v 1.5 2007/02/08 11:29:45 gergap Exp $
+**
+** Copyright (C) 2006-2007 ascolab GmbH. All Rights Reserved.
+** Web: http://www.ascolab.com
+**
+** 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 file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+** Project: OpcUa Wireshark Plugin
+**
+** Description: OpcUa Protocol Decoder.
+**
+** Author: Gerhard Gappmeier <gerhard.gappmeier@ascolab.com>
+** Last change by: $Author: gergap $
+**
+******************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <gmodule.h>
+#include <epan/packet.h>
+#include <epan/emem.h>
+#include <epan/dissectors/packet-tcp.h>
+#include <epan/prefs.h>
+#include "ua_transport_layer.h"
+#include "ua_security_layer.h"
+#include "ua_application_layer.h"
+#include "opcua_complextypeparser.h"
+#include "opcua_serviceparser.h"
+#include "opcua_enumparser.h"
+#include "opcua_simpletypes.h"
+#include "opcua_hfindeces.h"
+
+/* forward reference */
+void proto_register_opcua (void);
+void proto_reg_handoff_opcua (void);
+static void dissect_opcua(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
+static void dissect_opcua_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
+
+/* declare parse function pointer */
+typedef void (*FctParse)(proto_tree *tree, tvbuff_t *tvb, gint *pOffset);
+
+static int proto_opcua = -1;
+/** Official IANA registered port for OPC UA Binary Protocol. */
+static int global_opcua_port = 4840;
+static dissector_handle_t opcua_handle;
+
+/** subtree types */
+gint ett_opcua_transport = -1;
+gint ett_opcua_extensionobject = -1;
+gint ett_opcua_nodeid = -1;
+
+/** OpcUa Transport Message Types */
+enum MessageType
+{
+ MSG_HELLO = 0,
+ MSG_ACKNOWLEDGE,
+ MSG_DISCONNECT,
+ MSG_DATA_LAST_CHUNK,
+ MSG_DATA,
+ MSG_ABORT,
+ MSG_ERROR,
+ MSG_INVALID,
+ MSG_UNKNOWN
+};
+
+/** OpcUa Transport Message Type Names */
+static char* g_szMessageTypes[] =
+{
+ "Hello message",
+ "Acknowledge message",
+ "Disconnect message",
+ "Data message, last chunk in message.",
+ "Data message, further chunks must follow.",
+ "Abort message",
+ "Error message",
+ "Invalid message",
+ "Unknown message"
+};
+
+
+/** Setup protocol subtree array */
+static gint *ett[] =
+{
+ &ett_opcua_transport,
+ &ett_opcua_extensionobject,
+ &ett_opcua_nodeid,
+};
+
+/** plugin entry functions.
+ * This registers the OpcUa protocol.
+ */
+void proto_register_opcua(void)
+{
+ module_t *opcua_module;
+
+ if (proto_opcua == -1)
+ {
+ proto_opcua = proto_register_protocol(
+ "OpcUa Binary Protocol", /* name */
+ "OpcUa", /* short name */
+ "opcua" /* abbrev */
+ );
+ }
+ opcua_module = prefs_register_protocol(proto_opcua, proto_reg_handoff_opcua);
+
+ registerTransportLayerTypes(proto_opcua);
+ registerSecurityLayerTypes(proto_opcua);
+ registerApplicationLayerTypes(proto_opcua);
+ registerSimpleTypes(proto_opcua);
+ registerEnumTypes(proto_opcua);
+ registerComplexTypes();
+ registerServiceTypes();
+ registerFieldTypes(proto_opcua);
+
+ proto_register_subtree_array(ett, array_length(ett));
+}
+
+/** Register sub protocol.
+ * For TCP port 4840.
+ */
+void proto_reg_handoff_opcua(void)
+{
+ static int Initialized=FALSE;
+
+ if (!Initialized)
+ {
+ opcua_handle = create_dissector_handle(dissect_opcua, proto_opcua);
+ dissector_add("tcp.port", global_opcua_port, opcua_handle);
+ }
+}
+
+/** header length that is needed to compute
+ * the pdu length.
+ * @see get_opcua_message_len
+ */
+#define FRAME_HEADER_LEN 8
+
+/** returns the length of an OpcUa message.
+ * This function reads the length information from
+ * the transport header.
+ */
+static guint get_opcua_message_len(packet_info *pinfo, tvbuff_t *tvb, int offset)
+{
+ gint32 plen;
+
+ /* the message length starts at offset 4 */
+ plen = tvb_get_letohl(tvb, offset + 4);
+
+ return plen;
+}
+
+/** The main OpcUa dissector functions.
+ * It uses tcp_dissect_pdus from packet-tcp.h
+ * to reassemble the TCP data.
+ */
+static void dissect_opcua(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+ tcp_dissect_pdus(tvb, pinfo, tree, TRUE, FRAME_HEADER_LEN,
+ get_opcua_message_len, dissect_opcua_message);
+}
+
+/** The OpcUa message dissector.
+ * This method dissects full OpcUa messages.
+ * It gets only called with reassembled data
+ * from tcp_dissect_pdus.
+ */
+static void dissect_opcua_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+ FctParse pfctParse = NULL;
+ enum MessageType msgtype = MSG_INVALID;
+
+ if (check_col(pinfo->cinfo, COL_PROTOCOL))
+ {
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, "OpcUa");
+ }
+
+ /* parse message type */
+ if (tvb->real_data[0] == 'U' && tvb->real_data[1] == 'A')
+ {
+ if (tvb->real_data[2] == 'T')
+ {
+ switch(tvb->real_data[3])
+ {
+ case 'H': msgtype = MSG_HELLO;
+ pfctParse = parseHello;
+ break;
+ case 'A': msgtype = MSG_ACKNOWLEDGE;
+ pfctParse = parseAcknowledge;
+ break;
+ case 'D': msgtype = MSG_DISCONNECT;
+ pfctParse = parseDisconnect;
+ break;
+ default: msgtype = MSG_INVALID;
+ break;
+ }
+ }
+ else if (tvb->real_data[2] == 'M')
+ {
+ switch(tvb->real_data[3])
+ {
+ case 'G': msgtype = MSG_DATA_LAST_CHUNK;
+ pfctParse = parseData;
+ break;
+ case 'C': msgtype = MSG_DATA;
+ pfctParse = parseData;
+ break;
+ case 'A': msgtype = MSG_ABORT;
+ pfctParse = parseAbort;
+ break;
+ case 'E': msgtype = MSG_ERROR;
+ pfctParse = parseError;
+ break;
+ default: msgtype = MSG_INVALID;
+ break;
+ }
+ }
+ }
+ else
+ {
+ msgtype = MSG_UNKNOWN;
+ }
+
+ /* Clear out stuff in the info column */
+ if(check_col(pinfo->cinfo, COL_INFO))
+ {
+ col_set_str(pinfo->cinfo, COL_INFO, g_szMessageTypes[msgtype]);
+ }
+
+ if (tree && pfctParse)
+ {
+ gint offset = 0;
+
+ /* we are being asked for details */
+ proto_item *ti = NULL;
+ proto_tree *transport_tree = NULL;
+
+ ti = proto_tree_add_item(tree, proto_opcua, tvb, 0, -1, FALSE);
+ transport_tree = proto_item_add_subtree(ti, ett_opcua_transport);
+
+ /* call the transport message dissector */
+ (*pfctParse)(transport_tree, tvb, &offset);
+
+ }
+}
+
+