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