nexmon – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 /******************************************************************************
2 ** Copyright (C) 2006-2007 ascolab GmbH. All Rights Reserved.
3 ** Web: http://www.ascolab.com
4 **
5 ** This program is free software; you can redistribute it and/or
6 ** modify it under the terms of the GNU General Public License
7 ** as published by the Free Software Foundation; either version 2
8 ** of the License, or (at your option) any later version.
9 **
10 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
11 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
12 **
13 ** Project: OpcUa Wireshark Plugin
14 **
15 ** Description: OpcUa Protocol Decoder.
16 **
17 ** Author: Gerhard Gappmeier <gerhard.gappmeier@ascolab.com>
18 ******************************************************************************/
19  
20 #include "config.h"
21  
22 #include <epan/packet.h>
23 #include <epan/prefs.h>
24 #include <epan/reassemble.h>
25 #include <epan/dissectors/packet-tcp.h>
26 #include "opcua_transport_layer.h"
27 #include "opcua_security_layer.h"
28 #include "opcua_application_layer.h"
29 #include "opcua_complextypeparser.h"
30 #include "opcua_serviceparser.h"
31 #include "opcua_enumparser.h"
32 #include "opcua_simpletypes.h"
33 #include "opcua_hfindeces.h"
34  
35 void proto_register_opcua(void);
36  
37 extern const value_string g_requesttypes[];
38 extern const int g_NumServices;
39  
40 /* forward reference */
41 void proto_reg_handoff_opcua(void);
42 /* declare parse function pointer */
43 typedef int (*FctParse)(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, gint *pOffset);
44  
45 static int proto_opcua = -1;
46 static dissector_handle_t opcua_handle;
47 static range_t *global_tcp_ports_opcua;
48 /** Official IANA registered port for OPC UA Binary Protocol. */
49 #define OPCUA_PORT 4840
50  
51 /** subtree types used in opcua_transport_layer.c */
52 gint ett_opcua_extensionobject = -1;
53 gint ett_opcua_nodeid = -1;
54  
55 /** subtree types used locally */
56 static gint ett_opcua_transport = -1;
57 static gint ett_opcua_fragment = -1;
58 static gint ett_opcua_fragments = -1;
59  
60 static int hf_opcua_fragments = -1;
61 static int hf_opcua_fragment = -1;
62 static int hf_opcua_fragment_overlap = -1;
63 static int hf_opcua_fragment_overlap_conflicts = -1;
64 static int hf_opcua_fragment_multiple_tails = -1;
65 static int hf_opcua_fragment_too_long_fragment = -1;
66 static int hf_opcua_fragment_error = -1;
67 static int hf_opcua_fragment_count = -1;
68 static int hf_opcua_reassembled_in = -1;
69 static int hf_opcua_reassembled_length = -1;
70  
71 static const fragment_items opcua_frag_items = {
72 /* Fragment subtrees */
73 &ett_opcua_fragment,
74 &ett_opcua_fragments,
75 /* Fragment fields */
76 &hf_opcua_fragments,
77 &hf_opcua_fragment,
78 &hf_opcua_fragment_overlap,
79 &hf_opcua_fragment_overlap_conflicts,
80 &hf_opcua_fragment_multiple_tails,
81 &hf_opcua_fragment_too_long_fragment,
82 &hf_opcua_fragment_error,
83 &hf_opcua_fragment_count,
84 /* Reassembled in field */
85 &hf_opcua_reassembled_in,
86 /* Reassembled length field */
87 &hf_opcua_reassembled_length,
88 /* Reassembled data field */
89 NULL,
90 /* Tag */
91 "Message fragments"
92 };
93  
94  
95 static reassembly_table opcua_reassembly_table;
96  
97 /** OpcUa Transport Message Types */
98 enum MessageType
99 {
100 MSG_HELLO = 0,
101 MSG_ACKNOWLEDGE,
102 MSG_ERROR,
103 MSG_MESSAGE,
104 MSG_OPENSECURECHANNEL,
105 MSG_CLOSESECURECHANNEL,
106 MSG_INVALID
107 };
108  
109 /** OpcUa Transport Message Type Names */
110 static const char* g_szMessageTypes[] =
111 {
112 "Hello message",
113 "Acknowledge message",
114 "Error message",
115 "UA Secure Conversation Message",
116 "OpenSecureChannel message",
117 "CloseSecureChannel message",
118 "Invalid message"
119 };
120  
121  
122  
123  
124 /** header length that is needed to compute
125 * the pdu length.
126 * @see get_opcua_message_len
127 */
128 #define FRAME_HEADER_LEN 8
129  
130 /** returns the length of an OpcUa message.
131 * This function reads the length information from
132 * the transport header.
133 */
134 static guint get_opcua_message_len(packet_info *pinfo _U_, tvbuff_t *tvb,
135 int offset, void *data _U_)
136 {
137 gint32 plen;
138  
139 /* the message length starts at offset 4 */
140 plen = tvb_get_letohl(tvb, offset + 4);
141  
142 return plen;
143 }
144  
145 /** The OpcUa message dissector.
146 * This method dissects full OpcUa messages.
147 * It gets only called with reassembled data
148 * from tcp_dissect_pdus.
149 */
150 static int dissect_opcua_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
151 {
152 FctParse pfctParse = NULL;
153 enum MessageType msgtype = MSG_INVALID;
154  
155 col_set_str(pinfo->cinfo, COL_PROTOCOL, "OpcUa");
156  
157 /* parse message type */
158 if (tvb_memeql(tvb, 0, "HEL", 3) == 0)
159 {
160 msgtype = MSG_HELLO;
161 pfctParse = parseHello;
162 }
163 else if (tvb_memeql(tvb, 0, "ACK", 3) == 0)
164 {
165 msgtype = MSG_ACKNOWLEDGE;
166 pfctParse = parseAcknowledge;
167 }
168 else if (tvb_memeql(tvb, 0, "ERR", 3) == 0)
169 {
170 msgtype = MSG_ERROR;
171 pfctParse = parseError;
172 }
173 else if (tvb_memeql(tvb, 0, "MSG", 3) == 0)
174 {
175 msgtype = MSG_MESSAGE;
176 pfctParse = parseMessage;
177 }
178 else if (tvb_memeql(tvb, 0, "OPN", 3) == 0)
179 {
180 msgtype = MSG_OPENSECURECHANNEL;
181 pfctParse = parseOpenSecureChannel;
182 }
183 else if (tvb_memeql(tvb, 0, "CLO", 3) == 0)
184 {
185 msgtype = MSG_CLOSESECURECHANNEL;
186 pfctParse = parseCloseSecureChannel;
187 }
188 else
189 {
190 msgtype = MSG_INVALID;
191 }
192  
193 /* Clear out stuff in the info column */
194 col_set_str(pinfo->cinfo, COL_INFO, g_szMessageTypes[msgtype]);
195  
196 if (pfctParse)
197 {
198 gint offset = 0;
199 int iServiceId = -1;
200 tvbuff_t *next_tvb = tvb;
201 gboolean bParseService = TRUE;
202 gboolean bIsLastFragment = FALSE;
203  
204 /* we are being asked for details */
205 proto_item *ti = NULL;
206 proto_tree *transport_tree = NULL;
207  
208 ti = proto_tree_add_item(tree, proto_opcua, tvb, 0, -1, ENC_NA);
209 transport_tree = proto_item_add_subtree(ti, ett_opcua_transport);
210  
211 /* MSG_MESSAGE might be fragmented, check for that */
212 if (msgtype == MSG_MESSAGE)
213 {
214 guint8 chunkType = 0;
215 guint32 opcua_seqid = 0;
216 guint32 opcua_num = 0;
217 guint32 opcua_seqnum = 0;
218 fragment_head *frag_msg = NULL;
219  
220 offset = 3;
221  
222 chunkType = tvb_get_guint8(tvb, offset); offset += 1;
223  
224 offset += 4; /* Message Size */
225 offset += 4; /* SecureChannelId */
226 offset += 4; /* Security Token Id */
227  
228 opcua_num = tvb_get_letohl(tvb, offset); offset += 4; /* Security Sequence Number */
229 opcua_seqid = tvb_get_letohl(tvb, offset); offset += 4; /* Security RequestId */
230  
231 /* check if tvb is part of a chunked message:
232 the UA protocol does not tell us that, so we look into
233 opcua_reassembly_table if the opcua_seqid belongs to a
234 chunked message */
235 frag_msg = fragment_get(&opcua_reassembly_table, pinfo, opcua_seqid, NULL);
236 if (frag_msg == NULL)
237 {
238 frag_msg = fragment_get_reassembled_id(&opcua_reassembly_table, pinfo, opcua_seqid);
239 }
240  
241 if (frag_msg != NULL || chunkType != 'F')
242 {
243 gboolean bSaveFragmented = pinfo->fragmented;
244 gboolean bMoreFragments = TRUE;
245 tvbuff_t *new_tvb = NULL;
246  
247 pinfo->fragmented = TRUE;
248  
249 if (frag_msg == NULL)
250 {
251 /* first fragment */
252 opcua_seqnum = 0;
253 }
254 else
255 {
256 /* the UA protocol does not number the chunks beginning from 0 but from a
257 arbitrary value, so we have to fake the numbers in the stored fragments.
258 this way Wireshark reassembles the message, as it expects the fragment
259 sequence numbers to start at 0 */
260 while (frag_msg->next) {frag_msg = frag_msg->next;}
261 opcua_seqnum = frag_msg->offset + 1;
262  
263 if (chunkType == 'F')
264 {
265 bMoreFragments = FALSE;
266 }
267 }
268  
269 frag_msg = fragment_add_seq_check(&opcua_reassembly_table,
270 tvb,
271 offset,
272 pinfo,
273 opcua_seqid, /* ID for fragments belonging together */
274 NULL,
275 opcua_seqnum, /* fragment sequence number */
276 tvb_captured_length_remaining(tvb, offset), /* fragment length - to the end */
277 bMoreFragments); /* More fragments? */
278  
279 new_tvb = process_reassembled_data(tvb,
280 offset,
281 pinfo,
282 "Reassembled Message",
283 frag_msg,
284 &opcua_frag_items,
285 NULL,
286 transport_tree);
287  
288 if (new_tvb)
289 {
290 /* Reassembled */
291 bIsLastFragment = TRUE;
292 }
293 else
294 {
295 /* Not last packet of reassembled UA message */
296 col_append_fstr(pinfo->cinfo, COL_INFO, " (Message fragment %u)", opcua_num);
297 }
298  
299 if (new_tvb)
300 {
301 /* take it all */
302 next_tvb = new_tvb;
303 }
304 else
305 {
306 /* only show transport header */
307 bParseService = FALSE;
308 next_tvb = tvb_new_subset_remaining(tvb, 0);
309 }
310  
311 pinfo->fragmented = bSaveFragmented;
312 }
313 }
314  
315 offset = 0;
316  
317 /* call the transport message dissector */
318 iServiceId = (*pfctParse)(transport_tree, tvb, pinfo, &offset);
319  
320 /* parse the service if not chunked or last chunk */
321 if (msgtype == MSG_MESSAGE && bParseService)
322 {
323 if (bIsLastFragment != FALSE)
324 {
325 offset = 0;
326 }
327 iServiceId = parseService(transport_tree, next_tvb, pinfo, &offset);
328 }
329  
330 /* display the service type in addition to the message type */
331 if (iServiceId != -1)
332 {
333 const gchar *szServiceName = val_to_str((guint32)iServiceId, g_requesttypes, "ServiceId %d");
334  
335 if (bIsLastFragment == FALSE)
336 {
337 col_add_fstr(pinfo->cinfo, COL_INFO, "%s: %s", g_szMessageTypes[msgtype], szServiceName);
338 }
339 else
340 {
341 col_add_fstr(pinfo->cinfo, COL_INFO, "%s: %s (Message Reassembled)", g_szMessageTypes[msgtype], szServiceName);
342 }
343 }
344 }
345  
346 return tvb_reported_length(tvb);
347 }
348  
349 /** The main OpcUa dissector functions.
350 * It uses tcp_dissect_pdus from packet-tcp.h
351 * to reassemble the TCP data.
352 */
353 static int dissect_opcua(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
354 {
355 tcp_dissect_pdus(tvb, pinfo, tree, TRUE, FRAME_HEADER_LEN,
356 get_opcua_message_len, dissect_opcua_message, data);
357 return tvb_reported_length(tvb);
358 }
359  
360 static void register_tcp_port(guint32 port)
361 {
362 if (port != 0)
363 dissector_add_uint("tcp.port", port, opcua_handle);
364 }
365  
366 static void unregister_tcp_port(guint32 port)
367 {
368 if (port != 0)
369 dissector_delete_uint("tcp.port", port, opcua_handle);
370 }
371  
372 static void
373 init_opcua(void)
374 {
375 reassembly_table_init(&opcua_reassembly_table,
376 &addresses_reassembly_table_functions);
377 }
378  
379 static void
380 cleanup_opcua(void)
381 {
382 reassembly_table_destroy(&opcua_reassembly_table);
383 }
384  
385 /** plugin entry functions.
386 * This registers the OpcUa protocol.
387 */
388 void proto_register_opcua(void)
389 {
390 char *tmp;
391  
392 static hf_register_info hf[] =
393 {
394 /* id full name abbreviation type display strings bitmask blurb HFILL */
395 {&hf_opcua_fragments, {"Message fragments", "opcua.fragments", FT_NONE, BASE_NONE, NULL, 0x00, NULL, HFILL}},
396 {&hf_opcua_fragment, {"Message fragment", "opcua.fragment", FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL}},
397 {&hf_opcua_fragment_overlap, {"Message fragment overlap", "opcua.fragment.overlap", FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL}},
398 {&hf_opcua_fragment_overlap_conflicts, {"Message fragment overlapping with conflicting data", "opcua.fragment.overlap.conflicts", FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL}},
399 {&hf_opcua_fragment_multiple_tails, {"Message has multiple tail fragments", "opcua.fragment.multiple_tails", FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL}},
400 {&hf_opcua_fragment_too_long_fragment, {"Message fragment too long", "opcua.fragment.too_long_fragment", FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL}},
401 {&hf_opcua_fragment_error, {"Message defragmentation error", "opcua.fragment.error", FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL}},
402 {&hf_opcua_fragment_count, {"Message fragment count", "opcua.fragment.count", FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL}},
403 {&hf_opcua_reassembled_in, {"Reassembled in", "opcua.reassembled.in", FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL}},
404 {&hf_opcua_reassembled_length, {"Reassembled length", "opcua.reassembled.length", FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL}}
405 };
406  
407 /** Setup protocol subtree array */
408 static gint *ett[] =
409 {
410 &ett_opcua_extensionobject,
411 &ett_opcua_nodeid,
412 &ett_opcua_transport,
413 &ett_opcua_fragment,
414 &ett_opcua_fragments
415 };
416  
417 module_t *opcua_module;
418  
419 proto_opcua = proto_register_protocol(
420 "OpcUa Binary Protocol", /* name */
421 "OpcUa", /* short name */
422 "opcua" /* abbrev */
423 );
424  
425 registerTransportLayerTypes(proto_opcua);
426 registerSecurityLayerTypes(proto_opcua);
427 registerApplicationLayerTypes(proto_opcua);
428 registerSimpleTypes(proto_opcua);
429 registerEnumTypes(proto_opcua);
430 registerComplexTypes();
431 registerServiceTypes();
432 registerFieldTypes(proto_opcua);
433  
434 proto_register_subtree_array(ett, array_length(ett));
435  
436 tmp = g_strdup_printf("%d", OPCUA_PORT);
437 range_convert_str(&global_tcp_ports_opcua, tmp, 65535);
438 g_free(tmp);
439  
440 proto_register_field_array(proto_opcua, hf, array_length(hf));
441  
442 register_init_routine(&init_opcua);
443 register_cleanup_routine(&cleanup_opcua);
444  
445 /* register user preferences */
446 opcua_module = prefs_register_protocol(proto_opcua, proto_reg_handoff_opcua);
447 prefs_register_range_preference(opcua_module, "tcp_ports",
448 "OPC UA TCP Ports",
449 "The TCP ports for the OPC UA TCP Binary Protocol (comma separated list)",
450 &global_tcp_ports_opcua, 65535);
451  
452 }
453  
454 void proto_reg_handoff_opcua(void)
455 {
456 static gboolean opcua_initialized = FALSE;
457 static range_t *tcp_ports_opcua = NULL;
458  
459 if(!opcua_initialized)
460 {
461 opcua_handle = create_dissector_handle(dissect_opcua, proto_opcua);
462 opcua_initialized = TRUE;
463 }
464 else
465 {
466 /* clean up ports and their lists */
467 if (tcp_ports_opcua != NULL)
468 {
469 range_foreach(tcp_ports_opcua, unregister_tcp_port);
470 g_free(tcp_ports_opcua);
471 }
472 }
473  
474 /* If we now have a PDU tree, register for the port or ports we have */
475 tcp_ports_opcua = range_copy(global_tcp_ports_opcua);
476 range_foreach(tcp_ports_opcua, register_tcp_port);
477 }
478  
479 /*
480 * Editor modelines - http://www.wireshark.org/tools/modelines.html
481 *
482 * Local variables:
483 * c-basic-offset: 4
484 * tab-width: 8
485 * indent-tabs-mode: nil
486 * End:
487 *
488 * vi: set shiftwidth=4 tabstop=8 expandtab:
489 * :indentSize=4:tabSize=8:noTabs=true:
490 */