Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-etch.c
blobf2b026d5f74b081880d9018b09f58773a4a4d831
1 /* packet-etch.c
3 * Copyright (c) 2010, Holger Grandy, BMW Car IT GmbH (holger.grandy@bmw-carit.de)
5 * Apache Etch Protocol dissector
6 * http://incubator.apache.org/etch/
8 * This dissector reads configuration files (generated by Etch IDL compiler).
9 * Configuration file directory path is given in dissector options.
11 * Wireshark - Network traffic analyzer
12 * By Gerald Combs <gerald@wireshark.org>
13 * Copyright 1998 Gerald Combs
16 * SPDX-License-Identifier: GPL-2.0-or-later
19 #include "config.h"
21 #include <epan/packet.h>
22 #include <epan/prefs.h>
23 #include <wsutil/file_util.h>
24 #include <wsutil/report_message.h>
25 #include "packet-tcp.h"
27 void proto_register_etch(void);
28 void proto_reg_handoff_etch(void);
31 * maximum numbers for symbols from config files
33 #define ETCH_MAX_SYMBOL_LENGTH "256"
36 * Magic Number for Etch
38 static const uint8_t etch_magic[] = { 0xde, 0xad, 0xbe, 0xef };
41 * Typecodes in the Etch protocol, representing the field types
43 #define ETCH_TC_NULL 0x80
44 #define ETCH_TC_NONE 0x81
45 #define ETCH_TC_BOOLEAN_FALSE 0x82
46 #define ETCH_TC_BOOLEAN_TRUE 0x83
47 #define ETCH_TC_BYTE 0x84
48 #define ETCH_TC_SHORT 0x85
49 #define ETCH_TC_INT 0x86
50 #define ETCH_TC_LONG 0x87
51 #define ETCH_TC_FLOAT 0x88
52 #define ETCH_TC_DOUBLE 0x89
53 #define ETCH_TC_BYTES 0x8B
54 #define ETCH_TC_ARRAY 0x91
55 #define ETCH_TC_EMPTY_STRING 0x92
56 #define ETCH_TC_STRING 0x93
57 #define ETCH_TC_STRUCT 0x94
58 #define ETCH_TC_CUSTOM 0x95
59 #define ETCH_TC_ANY 0x96
60 #define ETCH_TC_MIN_TINY_INT 0xC0
61 #define ETCH_TC_MAX_TINY_INT 0x7F
63 /***************************************************************************/
64 /* Variables */
67 * String representation of all Type Codes
69 static const value_string tc_lookup_table[] = {
70 { ETCH_TC_NULL, "Etch TypeCode: NULL"},
71 { ETCH_TC_NONE, "Etch TypeCode: NONE"},
72 { ETCH_TC_BOOLEAN_FALSE, "Etch TypeCode: BOOLEAN_FALSE" },
73 { ETCH_TC_BOOLEAN_TRUE, "Etch TypeCode: BOOLEAN_TRUE"},
74 { ETCH_TC_BYTE, "Etch TypeCode: BYTE"},
75 { ETCH_TC_SHORT, "Etch TypeCode: SHORT"},
76 { ETCH_TC_INT, "Etch TypeCode: INT"},
77 { ETCH_TC_LONG, "Etch TypeCode: LONG"},
78 { ETCH_TC_FLOAT, "Etch TypeCode: FLOAT"},
79 { ETCH_TC_DOUBLE, "Etch TypeCode: DOUBLE"},
80 { ETCH_TC_BYTES, "Etch TypeCode: BYTES"},
81 { ETCH_TC_ARRAY, "Etch TypeCode: ARRAY"},
82 { ETCH_TC_EMPTY_STRING, "Etch TypeCode: EMPTY_STRING"},
83 { ETCH_TC_STRING, "Etch TypeCode: STRING"},
84 { ETCH_TC_STRUCT, "Etch TypeCode: STRUCT"},
85 { ETCH_TC_CUSTOM, "Etch TypeCode: CUSTOM"},
86 { ETCH_TC_ANY, "Etch TypeCode: ANY"},
87 { 0, NULL}
91 * Wireshark internal fields
93 static int proto_etch;
94 static int ett_etch;
95 static int ett_etch_struct;
96 static int ett_etch_keyvalue;
97 static int ett_etch_key;
98 static int ett_etch_value;
99 static int hf_etch_sig;
100 static int hf_etch_length;
101 static int hf_etch_version;
102 static int hf_etch_typecode;
103 static int hf_etch_value;
104 static int hf_etch_bytes;
105 static int hf_etch_byte;
106 static int hf_etch_short;
107 static int hf_etch_int;
108 static int hf_etch_long;
109 static int hf_etch_float;
110 static int hf_etch_double;
111 /* static int hf_etch_key; */
112 static int hf_etch_valuename;
113 static int hf_etch_keyname;
114 static int hf_etch_string;
115 static int hf_etch_keyvalue;
116 static int hf_etch_struct;
117 static int hf_etch_dim;
118 static int hf_etch_symbol;
120 static dissector_handle_t etch_handle;
123 * internal fields/defines for dissector
126 static const char *gbl_keytab_folder = "";
127 static char *gbl_current_keytab_folder;
129 static int gbl_pdu_counter;
130 static uint32_t gbl_old_frame_num;
132 static wmem_strbuf_t *gbl_symbol_buffer;
133 static bool gbl_have_symbol;
135 /***************************************************************************/
136 /* Methods */
139 * forward declared dissector methods
141 static void read_key_value(unsigned int *offset, tvbuff_t *tvb,
142 proto_tree *etch_tree, packet_info *pinfo);
143 static void read_struct(unsigned int *offset, tvbuff_t *tvb,
144 proto_tree *etch_tree, packet_info *pinfo, int add_type_field);
145 static int read_value(unsigned int *offset, tvbuff_t *tvb, proto_tree *etch_tree,
146 packet_info *pinfo, int asWhat);
148 /************************************************************************
149 * Symbol value-string functions
150 * Essentially: Build a value_string_ext at runtime:
151 * a. Upon startup & whenever symbol folder changed: Read from file(s)
152 * and add all hash/symbol pairs to a GArray;
153 * b. When file reads complete, sort the GArray and then create a
154 * value_string_ext from the array for use by try_val_to_str_ext & friends.
155 * (Code based upon code in packet-diameter.c)
157 static GArray *gbl_symbols_array;
158 static value_string_ext *gbl_symbols_vs_ext;
160 static void
161 gbl_symbols_new(void)
163 DISSECTOR_ASSERT(gbl_symbols_array == NULL);
164 gbl_symbols_array = g_array_new(true, true, sizeof(value_string));
167 static void
168 gbl_symbols_free(void)
170 value_string_ext_free(gbl_symbols_vs_ext);
171 gbl_symbols_vs_ext = NULL;
173 if (gbl_symbols_array != NULL) {
174 value_string *vs_p;
175 unsigned i;
176 vs_p = (value_string *)(void *)gbl_symbols_array->data;
177 for (i=0; i<gbl_symbols_array->len; i++) {
178 g_free((char *)vs_p[i].strptr);
180 g_array_free(gbl_symbols_array, true);
181 gbl_symbols_array = NULL;
185 static void
186 gbl_symbols_array_append(uint32_t hash, char *symbol)
188 value_string vs = {hash, symbol};
189 DISSECTOR_ASSERT(gbl_symbols_array != NULL);
190 g_array_append_val(gbl_symbols_array, vs);
193 static int
194 gbl_symbols_compare_vs(const void * a, const void * b)
196 const value_string *vsa = (const value_string *)a;
197 const value_string *vsb = (const value_string *)b;
199 if(vsa->value > vsb->value)
200 return 1;
201 if(vsa->value < vsb->value)
202 return -1;
204 return 0;
207 static void
208 gbl_symbols_vs_ext_new(void)
210 DISSECTOR_ASSERT(gbl_symbols_vs_ext == NULL);
211 DISSECTOR_ASSERT(gbl_symbols_array != NULL);
212 g_array_sort(gbl_symbols_array, gbl_symbols_compare_vs);
213 gbl_symbols_vs_ext = value_string_ext_new((value_string *)(void *)gbl_symbols_array->data,
214 gbl_symbols_array->len+1,
215 "etch-global-symbols" );
218 /*********************************************************************************/
219 /* Aux Functions */
222 * get the length of a given typecode in bytes, -1 if to be derived from message
224 static int32_t
225 get_byte_length(uint8_t typecode)
227 switch (typecode) {
228 case ETCH_TC_NULL:
229 case ETCH_TC_NONE:
230 case ETCH_TC_BOOLEAN_FALSE:
231 case ETCH_TC_BOOLEAN_TRUE:
232 case ETCH_TC_EMPTY_STRING:
233 case ETCH_TC_MIN_TINY_INT:
234 case ETCH_TC_MAX_TINY_INT:
235 return 0;
236 case ETCH_TC_BYTE:
237 return 1;
238 case ETCH_TC_SHORT:
239 return 2;
240 case ETCH_TC_INT:
241 case ETCH_TC_FLOAT:
242 return 4;
243 case ETCH_TC_LONG:
244 case ETCH_TC_DOUBLE:
245 return 8;
246 case ETCH_TC_BYTES:
247 case ETCH_TC_ARRAY:
248 case ETCH_TC_STRING:
249 case ETCH_TC_STRUCT:
250 case ETCH_TC_CUSTOM:
251 case ETCH_TC_ANY:
252 return -1;
253 default:
254 return 0;
259 * add all etch symbols from file to our symbol cache
261 static void
262 add_symbols_of_file(const char *filename)
264 FILE *pFile;
266 pFile = ws_fopen(filename, "r");
268 if (pFile != NULL) {
269 char line[256];
270 while (fgets(line, sizeof line, pFile) != NULL) {
271 unsigned int hash;
272 size_t length, pos;
274 length = strlen(line);
276 /* Must at least have a hash, else skip line */
277 if (length < 10)
278 continue;
280 pos = length - 1;
281 while (pos > 0 && (line[pos] == 0xD || line[pos] == 0xA)) {
282 pos--;
284 line[pos + 1] = '\0';
286 /* Parse the Hash */
287 if (sscanf(&line[0], "%x", &hash) != 1)
288 continue; /* didn't find a valid hex value at the beginning of the line */
290 /* And read the symbol */
291 pos = strcspn(line, ",");
292 if ((line[pos] != '\0') && (line[pos+1] !='\0')) /* require at least 1 char in symbol */
293 gbl_symbols_array_append(hash,
294 ws_strdup_printf("%." ETCH_MAX_SYMBOL_LENGTH "s", &line[pos+1]));
296 fclose(pFile);
301 * add all etch symbol from directory to our symbol cache
303 static void
304 read_hashed_symbols_from_dir(const char *dirname)
306 WS_DIR *dir;
307 WS_DIRENT *file;
308 const char *name;
309 char *filename;
310 GError *err_p = NULL;
312 if(gbl_current_keytab_folder != NULL) {
313 g_free(gbl_current_keytab_folder);
314 gbl_current_keytab_folder = NULL;
317 gbl_symbols_free();
319 if ((dirname == NULL) || (dirname[0] == '\0'))
320 return;
322 if ((dir = ws_dir_open(dirname, 0, &err_p)) != NULL) {
323 gbl_symbols_new();
325 gbl_current_keytab_folder = g_strdup(dirname);
326 while ((file = ws_dir_read_name(dir)) != NULL) {
327 name = ws_dir_get_name(file);
329 if (g_str_has_suffix(file, ".ewh")) {
330 filename =
331 ws_strdup_printf("%s" G_DIR_SEPARATOR_S "%s", dirname,
332 name);
333 add_symbols_of_file(filename);
334 g_free(filename);
337 ws_dir_close(dir);
338 gbl_symbols_vs_ext_new();
339 }else{
340 report_failure("etch: %s", err_p->message);
341 g_error_free(err_p);
345 /***********************************************************************************/
346 /* Etch Protocol Functions */
349 * read a type flag from tvb and add it to tree
351 static uint8_t
352 read_type(unsigned int *offset, tvbuff_t *tvb, proto_tree *etch_tree)
355 uint32_t type_code;
357 type_code = tvb_get_uint8(tvb, *offset);
358 proto_tree_add_item(etch_tree, hf_etch_typecode, tvb, *offset, 1, ENC_BIG_ENDIAN);
359 (*offset)++;
360 return type_code;
364 * read a array type flag and add it to tree
366 static void
367 read_array_type(unsigned int *offset, tvbuff_t *tvb, proto_tree *etch_tree)
369 uint32_t type_code;
371 type_code = tvb_get_uint8(tvb, *offset);
373 read_type(offset, tvb, etch_tree);
374 if (type_code == ETCH_TC_CUSTOM) {
375 read_type(offset, tvb, etch_tree);
376 proto_tree_add_item(etch_tree, hf_etch_value, tvb, *offset, 4,
377 ENC_BIG_ENDIAN);
378 (*offset) += 4;
384 * read the length of an array and add it to tree
386 static uint32_t
387 read_length(unsigned int *offset, tvbuff_t *tvb, proto_tree *etch_tree)
389 uint32_t length;
390 int length_of_array_length_type;
391 uint8_t tiny;
393 tiny = tvb_get_uint8(tvb, *offset);
395 /* Is this the value already? */
396 if ( tiny <= ETCH_TC_MAX_TINY_INT
397 || tiny >= ETCH_TC_MIN_TINY_INT) {
398 length = tiny;
399 length_of_array_length_type = 1;
400 } else {
401 uint8_t type_code;
402 type_code = read_type(offset, tvb, etch_tree);
403 length_of_array_length_type = get_byte_length(type_code);
405 switch (length_of_array_length_type) {
406 case 1:
407 length = tvb_get_uint8(tvb, *offset);
408 break;
409 case 2:
410 length = tvb_get_ntohs(tvb, *offset);
411 break;
412 case 4:
413 length = tvb_get_ntohl(tvb, *offset);
414 break;
415 default:
416 return 0; /* error! */
419 proto_tree_add_item(etch_tree, hf_etch_length, tvb, *offset,
420 length_of_array_length_type, ENC_BIG_ENDIAN);
421 (*offset) += length_of_array_length_type;
423 if (*offset + length < *offset) {
424 /* overflow case
425 * https://gitlab.com/wireshark/wireshark/-/issues/8464 */
426 length = tvb_reported_length_remaining(tvb, *offset);
428 return length;
433 * read an array from tvb and add it to tree
435 static void
436 // NOLINTNEXTLINE(misc-no-recursion)
437 read_array(unsigned int *offset, tvbuff_t *tvb, proto_tree *etch_tree, packet_info *pinfo)
439 int length;
441 /* array type */
442 read_type(offset, tvb, etch_tree);
444 /* Array of type: */
445 read_array_type(offset, tvb, etch_tree);
447 /* Array dim */
448 proto_tree_add_item(etch_tree, hf_etch_dim, tvb, *offset, 1, ENC_BIG_ENDIAN);
449 (*offset)++;
451 /* Array length */
452 length = read_length(offset, tvb, etch_tree);
454 for (; length > 0; length--) {
455 read_value(offset, tvb, etch_tree, pinfo, hf_etch_value);
457 /* termination */
458 read_type(offset, tvb, etch_tree);
463 * read a sequence of bytes and add them to tree
465 static void
466 read_bytes(unsigned int *offset, tvbuff_t *tvb, proto_tree *etch_tree)
468 int length;
470 read_type(offset, tvb, etch_tree);
471 length = read_length(offset, tvb, etch_tree);
472 proto_tree_add_item(etch_tree, hf_etch_bytes, tvb, *offset, length,
473 ENC_NA);
474 (*offset) += length;
478 * read a string and add it to tree
480 static void
481 read_string(unsigned int *offset, tvbuff_t *tvb, proto_tree *etch_tree)
483 int byteLength;
485 read_type(offset, tvb, etch_tree);
487 byteLength = read_length(offset, tvb, etch_tree);
489 proto_tree_add_item(etch_tree, hf_etch_string, tvb, *offset,
490 byteLength, ENC_ASCII);
491 (*offset) += byteLength;
495 * read a number and add it to tree
497 static void
498 read_number(unsigned int *offset, tvbuff_t *tvb, proto_tree *etch_tree,
499 int asWhat, uint8_t type_code)
501 int byteLength;
503 read_type(offset, tvb, etch_tree);
504 byteLength = get_byte_length(type_code);
505 if (byteLength > 0) {
506 proto_item *ti;
507 const char *symbol = NULL;
508 uint32_t hash = 0;
510 gbl_symbol_buffer = wmem_strbuf_create(wmem_packet_scope()); /* no symbol found yet */
511 if (byteLength == 4) {
512 hash = tvb_get_ntohl(tvb, *offset);
513 symbol = try_val_to_str_ext(hash, gbl_symbols_vs_ext);
514 if(symbol != NULL) {
515 asWhat = hf_etch_symbol;
516 gbl_have_symbol = true;
517 wmem_strbuf_append_printf(gbl_symbol_buffer,"%s",symbol);
520 ti = proto_tree_add_item(etch_tree, asWhat, tvb, *offset,
521 byteLength, ENC_BIG_ENDIAN);
522 *offset += byteLength;
523 if (symbol != NULL) {
524 proto_item_append_text(ti, " (0x%08x) %s", hash, symbol);
530 * read a value and add it to tree
532 static int
533 // NOLINTNEXTLINE(misc-no-recursion)
534 read_value(unsigned int *offset, tvbuff_t *tvb, proto_tree *etch_tree,
535 packet_info *pinfo, int asWhat)
537 uint8_t type_code;
539 type_code = tvb_get_uint8(tvb, *offset);
540 if (type_code <= ETCH_TC_MAX_TINY_INT ||
541 type_code >= ETCH_TC_MIN_TINY_INT) {
542 /* this is the value already */
543 proto_tree_add_item(etch_tree, asWhat, tvb, *offset, 1, ENC_BIG_ENDIAN);
544 (*offset)++;
545 return type_code;
548 increment_dissection_depth(pinfo);
549 switch(type_code) {
550 case ETCH_TC_CUSTOM:
551 read_struct(offset, tvb, etch_tree, pinfo, 1);
552 break;
553 case ETCH_TC_ARRAY:
554 read_array(offset, tvb, etch_tree, pinfo);
555 break;
556 case ETCH_TC_STRING:
557 read_string(offset, tvb, etch_tree);
558 break;
559 case ETCH_TC_FLOAT:
560 read_number(offset, tvb, etch_tree, hf_etch_float, type_code);
561 break;
562 case ETCH_TC_DOUBLE:
563 read_number(offset, tvb, etch_tree, hf_etch_double, type_code);
564 break;
565 case ETCH_TC_SHORT:
566 read_number(offset, tvb, etch_tree, hf_etch_short, type_code);
567 break;
568 case ETCH_TC_INT:
569 read_number(offset, tvb, etch_tree, hf_etch_int, type_code);
570 break;
571 case ETCH_TC_LONG:
572 read_number(offset, tvb, etch_tree, hf_etch_long, type_code);
573 break;
574 case ETCH_TC_BYTE:
575 read_number(offset, tvb, etch_tree, hf_etch_byte, type_code);
576 break;
577 case ETCH_TC_BYTES:
578 read_bytes(offset, tvb, etch_tree);
579 break;
580 default:
581 read_number(offset, tvb, etch_tree, asWhat, type_code);
583 decrement_dissection_depth(pinfo);
584 return 0;
588 * read a struct and add it to tree
590 static void
591 // NOLINTNEXTLINE(misc-no-recursion)
592 read_struct(unsigned int *offset, tvbuff_t *tvb, proto_tree *etch_tree,
593 packet_info *pinfo, int add_type_field)
595 proto_item *ti;
596 proto_tree *new_tree;
597 int length;
598 int i;
600 ti = proto_tree_add_item(etch_tree, hf_etch_struct, tvb, *offset,
601 tvb_captured_length(tvb) - *offset, ENC_NA);
602 new_tree = proto_item_add_subtree(ti, ett_etch_struct);
604 if (add_type_field) {
605 read_type(offset, tvb, new_tree);
607 /* struct type as hash */
608 read_value(offset, tvb, new_tree, pinfo, hf_etch_value);
610 /* struct length */
611 length = read_value(offset, tvb, new_tree, pinfo, hf_etch_length);
613 for (i = 0; i < length; i++) {
614 read_key_value(offset, tvb, new_tree, pinfo);
617 /* termination */
618 read_type(offset, tvb, new_tree);
622 * read a key value pair and add it to tree
624 static void
625 // NOLINTNEXTLINE(misc-no-recursion)
626 read_key_value(unsigned int *offset, tvbuff_t *tvb, proto_tree *etch_tree, packet_info *pinfo)
628 proto_tree *new_tree;
629 proto_tree *new_tree_bck;
630 proto_item *ti, *parent_ti;
632 gbl_have_symbol = false;
634 parent_ti =
635 proto_tree_add_item(etch_tree, hf_etch_keyvalue, tvb, *offset, 1,
636 ENC_NA);
637 new_tree_bck = new_tree =
638 proto_item_add_subtree(parent_ti, ett_etch_keyvalue);
640 ti = proto_tree_add_item(new_tree, hf_etch_keyname, tvb, *offset, 0,
641 ENC_NA);
642 new_tree = proto_item_add_subtree(ti, ett_etch_key);
643 read_value(offset, tvb, new_tree, pinfo, hf_etch_value);
645 /* append the symbol of the key */
646 if(gbl_have_symbol == true){
647 proto_item_append_text(parent_ti, " (%s)", wmem_strbuf_get_str(gbl_symbol_buffer));
650 ti = proto_tree_add_item(new_tree_bck, hf_etch_valuename, tvb, *offset,
651 0, ENC_NA);
652 new_tree = proto_item_add_subtree(ti, ett_etch_value);
653 read_value(offset, tvb, new_tree, pinfo, hf_etch_value);
656 /*************************************************************************/
658 * Preparse the message for the info column
660 static wmem_strbuf_t*
661 get_column_info(wmem_allocator_t *scope, tvbuff_t *tvb)
663 int byte_length;
664 uint8_t type_code;
665 wmem_strbuf_t *result_buf;
666 int my_offset = 0;
668 /* We've a full PDU: 8 bytes + pdu_packetlen bytes */
669 result_buf = wmem_strbuf_create(scope);
671 my_offset += (4 + 4 + 1); /* skip Magic, Length, Version */
673 type_code = tvb_get_uint8(tvb, my_offset);
674 byte_length = get_byte_length(type_code);
675 my_offset++;
677 if (byte_length == 4) {
678 const char *symbol;
679 uint32_t hash;
680 hash = tvb_get_ntohl(tvb, my_offset);
681 symbol = try_val_to_str_ext(hash, gbl_symbols_vs_ext);
682 if (symbol != NULL) {
683 wmem_strbuf_append_printf(result_buf, "%s()", symbol);
687 return result_buf;
691 /****************************************************************************************************/
693 * main dissector function for an etch message
695 static int
696 dissect_etch_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
698 /* We've a full PDU: 8 bytes + pdu_packetlen bytes */
699 wmem_strbuf_t *colInfo = NULL;
701 if (pinfo->cinfo || tree) {
702 colInfo = get_column_info(pinfo->pool, tvb); /* get current symbol */
705 if (pinfo->cinfo) {
706 col_set_str(pinfo->cinfo, COL_PROTOCOL, "ETCH");
707 gbl_pdu_counter++;
709 /* Switch to another frame? => Clear column */
710 if (pinfo->num != gbl_old_frame_num) {
711 col_clear(pinfo->cinfo, COL_INFO);
712 gbl_pdu_counter = 0;
714 gbl_old_frame_num = pinfo->num;
716 col_append_fstr(pinfo->cinfo, COL_INFO, "%s ", wmem_strbuf_get_str(colInfo));
719 if (tree) {
720 /* we are being asked for details */
721 unsigned int offset;
722 proto_item *ti;
723 proto_tree *etch_tree;
725 ti = proto_tree_add_protocol_format(tree, proto_etch, tvb, 0, -1,
726 "ETCH Protocol: %s", wmem_strbuf_get_str(colInfo));
728 offset = 9;
729 etch_tree = proto_item_add_subtree(ti, ett_etch);
730 proto_tree_add_item(etch_tree, hf_etch_sig, tvb, 0, 4, ENC_BIG_ENDIAN);
731 proto_tree_add_item(etch_tree, hf_etch_length, tvb, 4, 4, ENC_BIG_ENDIAN);
732 proto_tree_add_item(etch_tree, hf_etch_version, tvb, 8, 1, ENC_BIG_ENDIAN);
733 read_struct(&offset, tvb, etch_tree, pinfo, 0);
736 return tvb_captured_length(tvb);
740 * determine PDU length of protocol etch
742 static unsigned
743 get_etch_message_len(packet_info *pinfo _U_, tvbuff_t *tvb,
744 int offset, void *data _U_)
746 /* length is at offset 4. we add magic bytes length + length size */
747 return tvb_get_ntohl(tvb, offset + 4) + 8;
752 * main dissector function for the etch protocol
754 static int
755 dissect_etch(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
757 if (tvb_captured_length(tvb) < 4) {
758 /* Too small for an etch packet. */
759 return 0;
762 if (tvb_memeql(tvb, 0, etch_magic, 4) == -1) {
763 /* Not an etch packet. */
764 return 0;
767 tcp_dissect_pdus(tvb, pinfo, tree, true, 8, get_etch_message_len,
768 dissect_etch_message, data);
770 if (gbl_pdu_counter > 0) {
771 col_prepend_fstr(pinfo->cinfo, COL_INFO, "[%d] ", gbl_pdu_counter + 1);
774 return 1;
777 static bool
778 dissect_etch_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
780 return dissect_etch(tvb, pinfo, tree, data) > 0;
783 static void
784 etch_dissector_init(void)
786 gbl_pdu_counter = 0;
787 gbl_old_frame_num = 0xFFFFFFFF;
790 void proto_register_etch(void)
792 module_t *etch_module;
794 static hf_register_info hf[] = {
795 {&hf_etch_sig,
796 {"Etch Signature", "etch.signature",
797 FT_UINT32, BASE_HEX,
798 NULL, 0x0,
799 NULL, HFILL}
801 {&hf_etch_length,
802 {"Etch Length", "etch.msglength",
803 FT_UINT64, BASE_DEC,
804 NULL, 0x0,
805 NULL, HFILL}
807 {&hf_etch_dim,
808 {"Etch Dim", "etch.dim",
809 FT_UINT8, BASE_DEC,
810 NULL, 0x0,
811 NULL, HFILL}
813 {&hf_etch_version,
814 {"Etch Version", "etch.version",
815 FT_UINT8, BASE_DEC,
816 NULL, 0x0,
817 NULL, HFILL}
819 {&hf_etch_typecode,
820 {"Etch TypeCode", "etch.typecode",
821 FT_UINT8, BASE_HEX,
822 VALS(tc_lookup_table), 0x0,
823 NULL, HFILL}
825 {&hf_etch_value,
826 {"Etch Value", "etch.value",
827 FT_UINT64, BASE_DEC,
828 NULL, 0x0,
829 NULL, HFILL}
831 {&hf_etch_bytes,
832 {"Etch Bytes", "etch.bytes",
833 FT_BYTES, BASE_NONE,
834 NULL, 0x0,
835 NULL, HFILL}
837 {&hf_etch_byte,
838 {"Etch Byte", "etch.byte",
839 FT_INT8, BASE_DEC,
840 NULL, 0x0,
841 NULL, HFILL}
843 {&hf_etch_short,
844 {"Etch Short", "etch.short",
845 FT_INT16, BASE_DEC,
846 NULL, 0x0,
847 NULL, HFILL}
849 {&hf_etch_int,
850 {"Etch Int", "etch.int",
851 FT_INT32, BASE_DEC,
852 NULL, 0x0,
853 NULL, HFILL}
855 {&hf_etch_long,
856 {"Etch Long", "etch.long",
857 FT_INT64, BASE_DEC,
858 NULL, 0x0,
859 NULL, HFILL}
861 {&hf_etch_float,
862 {"Etch Float", "etch.float",
863 FT_FLOAT, BASE_NONE,
864 NULL, 0x0,
865 NULL, HFILL}
867 {&hf_etch_double,
868 {"Etch Double", "etch.double",
869 FT_DOUBLE, BASE_NONE,
870 NULL, 0x0,
871 NULL, HFILL}
873 {&hf_etch_keyvalue,
874 {"Etch keyValue", "etch.keyvalue",
875 FT_NONE, BASE_NONE,
876 NULL, 0x0,
877 NULL, HFILL}
879 #if 0
880 {&hf_etch_key,
881 {"Etch key", "etch.key",
882 FT_BYTES, BASE_NONE,
883 NULL, 0x0,
884 NULL, HFILL}
886 #endif
887 {&hf_etch_symbol,
888 {"Etch symbol", "etch.symbol",
889 FT_UINT32, BASE_HEX,
890 NULL, 0x0,
891 NULL, HFILL}
893 {&hf_etch_struct,
894 {"Etch Struct", "etch.struct",
895 FT_BYTES, BASE_NONE,
896 NULL, 0x0,
897 NULL, HFILL}
899 {&hf_etch_string,
900 {"Etch String", "etch.string",
901 FT_STRING, BASE_NONE,
902 NULL, 0x0,
903 NULL, HFILL}
905 {&hf_etch_keyname,
906 {"Etch key", "etch.keyname",
907 FT_NONE, BASE_NONE,
908 NULL, 0x0,
909 NULL, HFILL}
911 {&hf_etch_valuename,
912 {"Etch value", "etch.valuename",
913 FT_NONE, BASE_NONE,
914 NULL, 0x0,
915 NULL, HFILL}
919 /* Setup protocol subtree array */
920 static int *ett[] = {
921 &ett_etch,
922 &ett_etch_struct,
923 &ett_etch_keyvalue,
924 &ett_etch_key,
925 &ett_etch_value,
928 proto_etch = proto_register_protocol("Apache Etch Protocol", "Etch", "etch");
930 proto_register_field_array(proto_etch, hf, array_length(hf));
931 proto_register_subtree_array(ett, array_length(ett));
932 etch_handle = register_dissector("etch", dissect_etch, proto_etch);
934 register_init_routine(&etch_dissector_init);
936 etch_module = prefs_register_protocol(proto_etch, proto_reg_handoff_etch);
938 prefs_register_directory_preference(etch_module, "file",
939 "Apache Etch symbol folder",
940 "Place the hash/symbol files "
941 "(generated by the Apache Etch compiler) "
942 "ending with .ewh here",
943 &gbl_keytab_folder);
946 void proto_reg_handoff_etch(void)
948 static bool etch_prefs_initialized = false;
950 /* create dissector handle only once */
951 if(!etch_prefs_initialized) {
952 /* add heuristic dissector for tcp */
953 heur_dissector_add("tcp", dissect_etch_heur, "Etch over TCP", "etch_tcp", proto_etch, HEURISTIC_ENABLE);
954 dissector_add_for_decode_as_with_preference("tcp.port", etch_handle);
955 etch_prefs_initialized = true;
960 /* read config folder files, if filename has changed
961 * (while protecting strcmp() from NULLs)
963 if((gbl_keytab_folder == NULL) || (gbl_current_keytab_folder == NULL) ||
964 (strcmp(gbl_keytab_folder, gbl_current_keytab_folder) != 0)) {
965 read_hashed_symbols_from_dir(gbl_keytab_folder);
970 * Editor modelines - https://www.wireshark.org/tools/modelines.html
972 * Local variables:
973 * c-basic-offset: 2
974 * tab-width: 8
975 * indent-tabs-mode: nil
976 * End:
978 * vi: set shiftwidth=2 tabstop=8 expandtab:
979 * :indentSize=2:tabSize=8:noTabs=true: