2 * Routines for dissector Decode As handlers
4 * Wireshark - Network traffic analyzer
5 * By Gerald Combs <gerald@wireshark.org>
6 * Copyright 1998 Gerald Combs
8 * SPDX-License-Identifier: GPL-2.0-or-later
15 #include "decode_as.h"
18 #include "prefs-int.h"
19 #include "wsutil/file_util.h"
20 #include "wsutil/filesystem.h"
21 #include "epan/dissectors/packet-dcerpc.h"
26 GList *decode_as_list = NULL;
28 void register_decode_as(decode_as_t* reg)
30 dissector_table_t decode_table;
32 /* Ensure valid functions */
33 g_assert(reg->populate_list);
34 g_assert(reg->reset_value);
35 g_assert(reg->change_value);
37 decode_table = find_dissector_table(reg->table_name);
38 if (decode_table != NULL)
40 dissector_table_allow_decode_as(decode_table);
43 decode_as_list = g_list_prepend(decode_as_list, reg);
46 static void next_proto_prompt(packet_info *pinfo _U_, gchar *result)
48 g_snprintf(result, MAX_DECODE_AS_PROMPT_LEN, "Next level protocol as");
51 static gpointer next_proto_value(packet_info *pinfo _U_)
56 static build_valid_func next_proto_values[] = { next_proto_value };
57 static decode_as_value_t next_proto_da_values =
58 { next_proto_prompt, 1, next_proto_values };
60 dissector_table_t register_decode_as_next_proto(int proto, const gchar *title, const gchar *table_name, const gchar *ui_name, build_label_func label_func)
64 dissector_table_t dt = register_dissector_table(table_name, ui_name, proto, FT_NONE, BASE_NONE);
66 da = wmem_new0(wmem_epan_scope(), decode_as_t);
67 da->name = wmem_strdup(wmem_epan_scope(), proto_get_protocol_filter_name(proto));
68 da->title = wmem_strdup(wmem_epan_scope(), title);
69 da->table_name = wmem_strdup(wmem_epan_scope(), table_name);
71 if (label_func == NULL)
73 da->values = &next_proto_da_values;
77 da->values = wmem_new(wmem_epan_scope(), decode_as_value_t);
78 da->values->label_func = label_func;
79 da->values->num_values = 1;
80 da->values->build_values = next_proto_values;
82 da->populate_list = decode_as_default_populate_list;
83 da->reset_value = decode_as_default_reset;
84 da->change_value = decode_as_default_change;
86 register_decode_as(da);
90 struct decode_as_default_populate
92 decode_as_add_to_list_func add_to_list;
97 decode_proto_add_to_list (const gchar *table_name, gpointer value, gpointer user_data)
99 struct decode_as_default_populate* populate = (struct decode_as_default_populate*)user_data;
100 const gchar *proto_name;
102 dissector_handle_t handle;
105 handle = (dissector_handle_t)value;
106 proto_name = dissector_handle_get_short_name(handle);
108 i = dissector_handle_get_protocol_index(handle);
109 if (i >= 0 && !proto_is_protocol_enabled(find_protocol_by_id(i)))
112 populate->add_to_list(table_name, proto_name, value, populate->ui_element);
115 void decode_as_default_populate_list(const gchar *table_name, decode_as_add_to_list_func add_to_list, gpointer ui_element)
117 struct decode_as_default_populate populate;
119 populate.add_to_list = add_to_list;
120 populate.ui_element = ui_element;
122 dissector_table_foreach_handle(table_name, decode_proto_add_to_list, &populate);
125 gboolean decode_as_default_reset(const gchar *name, gconstpointer pattern)
127 switch (get_dissector_table_selector_type(name)) {
132 dissector_reset_uint(name, GPOINTER_TO_UINT(pattern));
135 dissector_reset_payload(name);
141 dissector_reset_string(name, (!pattern)?"":(const gchar *) pattern);
150 gboolean decode_as_default_change(const gchar *name, gconstpointer pattern, gpointer handle, gchar *list_name _U_)
152 dissector_handle_t* dissector = (dissector_handle_t*)handle;
153 if (dissector != NULL) {
154 switch (get_dissector_table_selector_type(name)) {
159 dissector_change_uint(name, GPOINTER_TO_UINT(pattern), *dissector);
162 dissector_change_payload(name, *dissector);
168 dissector_change_string(name, (!pattern)?"":(const gchar *) pattern, *dissector);
180 /* Some useful utilities for Decode As */
183 * A list of dissectors that need to be reset.
185 static GSList *dissector_reset_list = NULL;
188 * A callback function to parse each "decode as" entry in the file and apply the change
190 static prefs_set_pref_e
191 read_set_decode_as_entries(gchar *key, const gchar *value,
193 gboolean return_range_errors _U_)
195 gchar *values[4] = {NULL, NULL, NULL, NULL};
196 gchar delimiter[4] = {',', ',', ',','\0'};
199 GHashTable* processed_entries = (GHashTable*)user_data;
200 dissector_table_t sub_dissectors;
201 prefs_set_pref_e retval = PREFS_SET_OK;
202 gboolean is_valid = FALSE;
204 if (strcmp(key, DECODE_AS_ENTRY) == 0) {
205 /* Parse csv into table, selector, initial, current */
206 for (i = 0; i < 4; i++) {
207 pch = strchr(value, delimiter[i]);
209 for (j = 0; j < i; j++) {
212 return PREFS_SET_SYNTAX_ERR;
214 values[i] = g_strndup(value, pch - value);
217 sub_dissectors = find_dissector_table(values[0]);
218 if (sub_dissectors != NULL) {
219 dissector_handle_t handle;
220 ftenum_t selector_type;
223 const char* proto_name;
225 selector_type = dissector_table_get_type(sub_dissectors);
227 handle = dissector_table_get_dissector_handle(sub_dissectors, values[3]);
228 if (handle != NULL || g_ascii_strcasecmp(values[3], DECODE_AS_NONE) == 0) {
233 if (IS_FT_STRING(selector_type)) {
234 dissector_change_string(values[0], values[1], handle);
239 long_value = strtol(values[1], &p, 0);
240 if (p == values[0] || *p != '\0' || long_value < 0 ||
241 (unsigned long)long_value > UINT_MAX) {
242 retval = PREFS_SET_SYNTAX_ERR;
245 dissector_change_uint(values[0], (guint)long_value, handle);
248 /* Now apply the value data back to dissector table preference */
249 proto_name = proto_get_protocol_filter_name(dissector_handle_get_protocol_index(handle));
250 module = prefs_find_module(proto_name);
251 pref_value = prefs_find_preference(module, values[0]);
252 if (pref_value != NULL) {
253 gboolean replace = FALSE;
254 if (g_hash_table_lookup(processed_entries, proto_name) == NULL) {
255 /* First decode as entry for this protocol, ranges may be replaced */
258 /* Remember we've processed this protocol */
259 g_hash_table_insert(processed_entries, (gpointer)proto_name, (gpointer)proto_name);
262 prefs_add_decode_as_value(pref_value, (guint)long_value, replace);
263 module->prefs_changed_flags |= prefs_get_effect_flags(pref_value);
269 decode_build_reset_list(values[0], selector_type, values[1], NULL, NULL);
272 retval = PREFS_SET_SYNTAX_ERR;
276 retval = PREFS_SET_NO_SUCH_PREF;
279 for (i = 0; i < 4; i++) {
286 load_decode_as_entries(void)
291 if (dissector_reset_list) {
295 daf_path = get_persconffile_path(DECODE_AS_ENTRIES_FILE_NAME, TRUE);
296 if ((daf = ws_fopen(daf_path, "r")) != NULL) {
297 /* Store saved entries for better range processing */
298 GHashTable* processed_entries = g_hash_table_new(g_str_hash, g_str_equal);
299 read_prefs_file(daf_path, daf, read_set_decode_as_entries, processed_entries);
300 g_hash_table_destroy(processed_entries);
307 decode_as_write_entry (const gchar *table_name, ftenum_t selector_type,
308 gpointer key, gpointer value, gpointer user_data)
310 FILE *da_file = (FILE *)user_data;
311 dissector_handle_t current, initial;
312 const gchar *current_proto_name, *initial_proto_name;
314 current = dtbl_entry_get_handle((dtbl_entry_t *)value);
316 current_proto_name = DECODE_AS_NONE;
318 current_proto_name = dissector_handle_get_short_name(current);
319 initial = dtbl_entry_get_initial_handle((dtbl_entry_t *)value);
321 initial_proto_name = DECODE_AS_NONE;
323 initial_proto_name = dissector_handle_get_short_name(initial);
325 switch (selector_type) {
332 * XXX - write these in decimal, regardless of the base of
333 * the dissector table's selector, as older versions of
334 * Wireshark used atoi() when reading this file, and
335 * failed to handle hex or octal numbers.
337 * That will be fixed in future 1.10 and 1.12 releases,
338 * but pre-1.10 releases are at end-of-life and won't
342 DECODE_AS_ENTRY ": %s,%u,%s,%s\n",
343 table_name, GPOINTER_TO_UINT(key), initial_proto_name,
348 * XXX - Just put a placeholder for the key value. Currently
349 * FT_NONE dissector table uses a single uint value for
353 DECODE_AS_ENTRY ": %s,0,%s,%s\n",
354 table_name, initial_proto_name,
363 DECODE_AS_ENTRY ": %s,%s,%s,%s\n",
364 table_name, (gchar *)key, initial_proto_name,
369 g_assert_not_reached();
375 save_decode_as_entries(gchar** err)
381 if (create_persconffile_dir(&pf_dir_path) == -1) {
382 *err = g_strdup_printf("Can't create directory\n\"%s\"\nfor recent file: %s.",
383 pf_dir_path, g_strerror(errno));
388 daf_path = get_persconffile_path(DECODE_AS_ENTRIES_FILE_NAME, TRUE);
389 if ((da_file = ws_fopen(daf_path, "w")) == NULL) {
390 *err = g_strdup_printf("Can't open decode_as_entries file\n\"%s\": %s.",
391 daf_path, g_strerror(errno));
396 fputs("# \"Decode As\" entries file for Wireshark " VERSION ".\n"
398 "# This file is regenerated each time \"Decode As\" preferences\n"
399 "# are saved within Wireshark. Making manual changes should be safe,\n"
400 "# however.\n", da_file);
402 dissector_all_tables_foreach_changed(decode_as_write_entry, da_file);
409 * Data structure for tracking which dissector need to be reset. This
410 * structure is necessary as a hash table entry cannot be removed
411 * while a g_hash_table_foreach walk is in progress.
413 typedef struct dissector_delete_item {
414 /* The name of the dissector table */
415 gchar *ddi_table_name;
416 /* The type of the selector in that dissector table */
417 ftenum_t ddi_selector_type;
418 /* The selector in the dissector table */
423 } dissector_delete_item_t;
426 decode_build_reset_list (const gchar *table_name, ftenum_t selector_type,
427 gpointer key, gpointer value _U_,
428 gpointer user_data _U_)
430 dissector_delete_item_t *item;
432 item = g_new(dissector_delete_item_t,1);
433 item->ddi_table_name = g_strdup(table_name);
434 item->ddi_selector_type = selector_type;
435 switch (selector_type) {
441 item->ddi_selector.sel_uint = GPOINTER_TO_UINT(key);
445 /* Not really needed, but prevents the assert */
446 item->ddi_selector.sel_uint = 0;
453 item->ddi_selector.sel_string = g_strdup((char *)key);
457 g_assert_not_reached();
459 dissector_reset_list = g_slist_prepend(dissector_reset_list, item);
462 /* clear all settings */
464 decode_clear_all(void)
466 dissector_delete_item_t *item;
469 dissector_all_tables_foreach_changed(decode_build_reset_list, NULL);
471 for (tmp = dissector_reset_list; tmp; tmp = g_slist_next(tmp)) {
472 item = (dissector_delete_item_t *)tmp->data;
473 switch (item->ddi_selector_type) {
479 dissector_reset_uint(item->ddi_table_name,
480 item->ddi_selector.sel_uint);
484 dissector_reset_payload(item->ddi_table_name);
491 dissector_reset_string(item->ddi_table_name,
492 item->ddi_selector.sel_string);
493 g_free(item->ddi_selector.sel_string);
497 g_assert_not_reached();
499 g_free(item->ddi_table_name);
502 g_slist_free(dissector_reset_list);
503 dissector_reset_list = NULL;
505 g_list_free(decode_as_list);
506 decode_as_list = NULL;
508 decode_dcerpc_reset_all();
517 * indent-tabs-mode: nil
520 * ex: set shiftwidth=4 tabstop=8 expandtab:
521 * :indentSize=4:tabSize=8:noTabs=true: