1 /******************************************************************************
4 ** Copyright (C) 2006-2007 ascolab GmbH. All Rights Reserved.
5 ** Web: http://www.ascolab.com
7 ** This program is free software; you can redistribute it and/or
8 ** modify it under the terms of the GNU General Public License
9 ** as published by the Free Software Foundation; either version 2
10 ** of the License, or (at your option) any later version.
12 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
13 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
15 ** Project: OpcUa Wireshark Plugin
17 ** Description: OpcUa Protocol Decoder.
19 ** Author: Gerhard Gappmeier <gerhard.gappmeier@ascolab.com>
20 ** Last change by: $Author: gergap $
22 ******************************************************************************/
29 #include <epan/prefs.h>
30 #include <epan/packet.h>
31 #include <epan/dissectors/packet-tcp.h>
32 #include "opcua_transport_layer.h"
33 #include "opcua_security_layer.h"
34 #include "opcua_application_layer.h"
35 #include "opcua_complextypeparser.h"
36 #include "opcua_serviceparser.h"
37 #include "opcua_enumparser.h"
38 #include "opcua_simpletypes.h"
39 #include "opcua_hfindeces.h"
41 /* forward reference */
42 static void dissect_opcua(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
43 static void dissect_opcua_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
44 void proto_reg_handoff_opcua(void);
46 /* declare parse function pointer */
47 typedef void (*FctParse)(proto_tree *tree, tvbuff_t *tvb, gint *pOffset);
49 static int proto_opcua = -1;
50 static dissector_handle_t opcua_handle;
51 static range_t *global_tcp_ports_opcua;
52 /** Official IANA registered port for OPC UA Binary Protocol. */
53 #define OPCUA_PORT 4840
56 gint ett_opcua_transport = -1;
57 gint ett_opcua_extensionobject = -1;
58 gint ett_opcua_nodeid = -1;
60 /** OpcUa Transport Message Types */
67 MSG_OPENSECURECHANNEL,
68 MSG_CLOSESECURECHANNEL,
72 /** OpcUa Transport Message Type Names */
73 static char* g_szMessageTypes[] =
76 "Acknowledge message",
78 "UA Secure Conversation Message",
79 "OpenSecureChannel message",
80 "CloseSecureChannel message",
85 /** Setup protocol subtree array */
89 &ett_opcua_extensionobject,
93 /** plugin entry functions.
94 * This registers the OpcUa protocol.
96 void proto_register_opcua(void)
98 module_t *opcua_module;
100 proto_opcua = proto_register_protocol(
101 "OpcUa Binary Protocol", /* name */
102 "OpcUa", /* short name */
106 registerTransportLayerTypes(proto_opcua);
107 registerSecurityLayerTypes(proto_opcua);
108 registerApplicationLayerTypes(proto_opcua);
109 registerSimpleTypes(proto_opcua);
110 registerEnumTypes(proto_opcua);
111 registerComplexTypes();
112 registerServiceTypes();
113 registerFieldTypes(proto_opcua);
115 proto_register_subtree_array(ett, array_length(ett));
117 range_convert_str(&global_tcp_ports_opcua, ep_strdup_printf("%u", OPCUA_PORT), 65535);
119 /* register user preferences */
120 opcua_module = prefs_register_protocol(proto_opcua, proto_reg_handoff_opcua);
121 prefs_register_range_preference(opcua_module, "tcp_ports",
123 "The TCP ports for the OPC UA TCP Binary Protocol",
124 &global_tcp_ports_opcua, 65535);
127 /** header length that is needed to compute
129 * @see get_opcua_message_len
131 #define FRAME_HEADER_LEN 8
133 /** returns the length of an OpcUa message.
134 * This function reads the length information from
135 * the transport header.
137 static guint get_opcua_message_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset)
141 /* the message length starts at offset 4 */
142 plen = tvb_get_letohl(tvb, offset + 4);
147 /** The main OpcUa dissector functions.
148 * It uses tcp_dissect_pdus from packet-tcp.h
149 * to reassemble the TCP data.
151 static void dissect_opcua(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
153 tcp_dissect_pdus(tvb, pinfo, tree, TRUE, FRAME_HEADER_LEN,
154 get_opcua_message_len, dissect_opcua_message);
157 /** The OpcUa message dissector.
158 * This method dissects full OpcUa messages.
159 * It gets only called with reassembled data
160 * from tcp_dissect_pdus.
162 static void dissect_opcua_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
164 FctParse pfctParse = NULL;
165 enum MessageType msgtype = MSG_INVALID;
167 if (check_col(pinfo->cinfo, COL_PROTOCOL))
169 col_set_str(pinfo->cinfo, COL_PROTOCOL, "OpcUa");
172 /* parse message type */
173 if (tvb->real_data[0] == 'H' && tvb->real_data[1] == 'E' && tvb->real_data[2] == 'L')
176 pfctParse = parseHello;
178 else if (tvb->real_data[0] == 'A' && tvb->real_data[1] == 'C' && tvb->real_data[2] == 'K')
180 msgtype = MSG_ACKNOWLEDGE;
181 pfctParse = parseAcknowledge;
183 else if (tvb->real_data[0] == 'E' && tvb->real_data[1] == 'R' && tvb->real_data[2] == 'R')
186 pfctParse = parseError;
188 else if (tvb->real_data[0] == 'M' && tvb->real_data[1] == 'S' && tvb->real_data[2] == 'G')
190 msgtype = MSG_MESSAGE;
191 pfctParse = parseMessage;
193 else if (tvb->real_data[0] == 'O' && tvb->real_data[1] == 'P' && tvb->real_data[2] == 'N')
195 msgtype = MSG_OPENSECURECHANNEL;
196 pfctParse = parseOpenSecureChannel;
198 else if (tvb->real_data[0] == 'C' && tvb->real_data[1] == 'L' && tvb->real_data[2] == 'O')
200 msgtype = MSG_CLOSESECURECHANNEL;
201 pfctParse = parseCloseSecureChannel;
205 msgtype = MSG_INVALID;
208 /* Clear out stuff in the info column */
209 if(check_col(pinfo->cinfo, COL_INFO))
211 col_set_str(pinfo->cinfo, COL_INFO, g_szMessageTypes[msgtype]);
214 if (tree && pfctParse)
218 /* we are being asked for details */
219 proto_item *ti = NULL;
220 proto_tree *transport_tree = NULL;
222 ti = proto_tree_add_item(tree, proto_opcua, tvb, 0, -1, FALSE);
223 transport_tree = proto_item_add_subtree(ti, ett_opcua_transport);
225 /* call the transport message dissector */
226 (*pfctParse)(transport_tree, tvb, &offset);
230 static void register_tcp_port(guint32 port)
233 dissector_add("tcp.port", port, opcua_handle);
236 static void unregister_tcp_port(guint32 port)
239 dissector_delete("tcp.port", port, opcua_handle);
242 void proto_reg_handoff_opcua(void)
244 static gboolean opcua_initialized = FALSE;
245 static range_t *tcp_ports_opcua = NULL;
247 if(!opcua_initialized)
249 opcua_handle = create_dissector_handle(dissect_opcua, proto_opcua);
250 opcua_initialized = TRUE;
254 /* clean up ports and their lists */
255 if (tcp_ports_opcua != NULL)
257 range_foreach(tcp_ports_opcua, unregister_tcp_port);
258 g_free(tcp_ports_opcua);
262 /* If we now have a PDU tree, register for the port or ports we have */
263 tcp_ports_opcua = range_copy(global_tcp_ports_opcua);
264 range_foreach(tcp_ports_opcua, register_tcp_port);