regenerate files adding new UA Specification 1.03 services and types
[metze/wireshark/wip.git] / plugins / opcua / opcua.c
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 = new_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  */