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"
25 #include <wsutil/ws_assert.h>
27 GList
*decode_as_list
;
29 void register_decode_as(decode_as_t
* reg
)
31 dissector_table_t decode_table
;
33 /* Ensure valid functions */
34 ws_assert(reg
->populate_list
);
35 ws_assert(reg
->reset_value
);
36 ws_assert(reg
->change_value
);
38 decode_table
= find_dissector_table(reg
->table_name
);
39 if (decode_table
!= NULL
)
41 dissector_table_allow_decode_as(decode_table
);
44 decode_as_list
= g_list_prepend(decode_as_list
, reg
);
47 static void next_proto_prompt(packet_info
*pinfo _U_
, char *result
)
49 snprintf(result
, MAX_DECODE_AS_PROMPT_LEN
, "Next level protocol as");
52 static void *next_proto_value(packet_info
*pinfo _U_
)
57 static build_valid_func next_proto_values
[] = { next_proto_value
};
58 static decode_as_value_t next_proto_da_values
=
59 { next_proto_prompt
, 1, next_proto_values
};
61 dissector_table_t
register_decode_as_next_proto(int proto
, const char *table_name
, const char *ui_name
, build_label_func label_func
)
65 dissector_table_t dt
= register_dissector_table(table_name
, ui_name
, proto
, FT_NONE
, BASE_NONE
);
67 da
= wmem_new0(wmem_epan_scope(), decode_as_t
);
68 da
->name
= wmem_strdup(wmem_epan_scope(), proto_get_protocol_filter_name(proto
));
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 char *table_name
, void *value
, void *user_data
)
99 struct decode_as_default_populate
* populate
= (struct decode_as_default_populate
*)user_data
;
100 const char *dissector_description
;
102 dissector_handle_t handle
;
105 handle
= (dissector_handle_t
)value
;
106 dissector_description
= dissector_handle_get_description(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
, dissector_description
, value
, populate
->ui_element
);
115 void decode_as_default_populate_list(const char *table_name
, decode_as_add_to_list_func add_to_list
, void *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 bool decode_as_default_reset(const char *name
, const void *pattern
)
127 switch (get_dissector_table_selector_type(name
)) {
132 dissector_reset_uint(name
, GPOINTER_TO_UINT(pattern
));
135 dissector_reset_payload(name
);
141 case FT_STRINGZTRUNC
:
142 dissector_reset_string(name
, (!pattern
)?"":(const char *) pattern
);
151 bool decode_as_default_change(const char *name
, const void *pattern
, const void *handle
, const char *list_name _U_
)
153 const dissector_handle_t dissector
= (const dissector_handle_t
)handle
;
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 case FT_STRINGZTRUNC
:
169 dissector_change_string(name
, (!pattern
)?"":(const char *) pattern
, dissector
);
178 /* Some useful utilities for Decode As */
181 * A list of dissectors that need to be reset.
183 static GSList
*dissector_reset_list
;
186 * A callback function to parse each "decode as" entry in the file and apply the change
188 static prefs_set_pref_e
189 read_set_decode_as_entries(char *key
, const char *value
,
191 bool return_range_errors _U_
)
193 char *values
[4] = {NULL
, NULL
, NULL
, NULL
};
194 char delimiter
[4] = {',', ',', ',','\0'};
197 GHashTable
* processed_entries
= (GHashTable
*)user_data
;
198 dissector_table_t sub_dissectors
;
199 prefs_set_pref_e retval
= PREFS_SET_OK
;
200 bool is_valid
= false;
202 if (strcmp(key
, DECODE_AS_ENTRY
) == 0) {
203 /* Parse csv into table, selector, initial, current */
204 for (i
= 0; i
< 4; i
++) {
205 pch
= strchr(value
, delimiter
[i
]);
207 for (j
= 0; j
< i
; j
++) {
210 return PREFS_SET_SYNTAX_ERR
;
212 values
[i
] = g_strndup(value
, pch
- value
);
215 sub_dissectors
= find_dissector_table(values
[0]);
216 if (sub_dissectors
!= NULL
) {
217 dissector_handle_t handle
;
218 ftenum_t selector_type
;
221 const char* proto_name
;
223 selector_type
= dissector_table_get_type(sub_dissectors
);
225 handle
= dissector_table_get_dissector_handle(sub_dissectors
, values
[3]);
226 if (handle
!= NULL
|| g_ascii_strcasecmp(values
[3], DECODE_AS_NONE
) == 0) {
231 if (FT_IS_STRING(selector_type
)) {
232 dissector_change_string(values
[0], values
[1], handle
);
237 long_value
= strtol(values
[1], &p
, 0);
238 if (p
== values
[0] || *p
!= '\0' || long_value
< 0 ||
239 (unsigned long)long_value
> UINT_MAX
) {
240 retval
= PREFS_SET_SYNTAX_ERR
;
243 dissector_change_uint(values
[0], (unsigned)long_value
, handle
);
246 /* Now apply the value data back to dissector table preference */
247 if (handle
!= NULL
) {
248 proto_name
= proto_get_protocol_filter_name(dissector_handle_get_protocol_index(handle
));
249 module
= prefs_find_module(proto_name
);
250 // values[0] is the dissector table
251 char *pref_name
= ws_strdup_printf("%s%s", values
[0], dissector_handle_get_pref_suffix(handle
));
252 pref_value
= prefs_find_preference(module
, pref_name
);
254 if (pref_value
!= NULL
) {
255 bool replace
= false;
256 if (g_hash_table_lookup(processed_entries
, proto_name
) == NULL
) {
257 /* First decode as entry for this protocol, ranges may be replaced */
260 /* Remember we've processed this protocol */
261 g_hash_table_insert(processed_entries
, (void *)proto_name
, (void *)proto_name
);
264 prefs_add_decode_as_value(pref_value
, (unsigned)long_value
, replace
);
265 module
->prefs_changed_flags
|= prefs_get_effect_flags(pref_value
);
271 decode_build_reset_list(values
[0], selector_type
, values
[1], NULL
, NULL
);
274 retval
= PREFS_SET_SYNTAX_ERR
;
278 retval
= PREFS_SET_NO_SUCH_PREF
;
281 for (i
= 0; i
< 4; i
++) {
288 load_decode_as_entries(void)
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 /* Make a sorted list of the entries as we are fetching them from a hash table. Then write it out from the sorted list */
309 decode_as_write_entry (const char *table_name
, ftenum_t selector_type
,
310 void *key
, void *value
, void *user_data
)
312 GList
**decode_as_rows_list
= (GList
**)user_data
;
313 dissector_handle_t current
, initial
;
314 const char *current_dissector_name
, *initial_dissector_name
, *decode_as_row
;
316 current
= dtbl_entry_get_handle((dtbl_entry_t
*)value
);
318 current_dissector_name
= DECODE_AS_NONE
;
320 current_dissector_name
= dissector_handle_get_description(current
);
321 initial
= dtbl_entry_get_initial_handle((dtbl_entry_t
*)value
);
323 initial_dissector_name
= DECODE_AS_NONE
;
325 initial_dissector_name
= dissector_handle_get_description(initial
);
327 switch (selector_type
) {
334 * XXX - write these in decimal, regardless of the base of
335 * the dissector table's selector, as older versions of
336 * Wireshark used atoi() when reading this file, and
337 * failed to handle hex or octal numbers.
339 * That will be fixed in future 1.10 and 1.12 releases,
340 * but pre-1.10 releases are at end-of-life and won't
343 decode_as_row
= ws_strdup_printf(
344 DECODE_AS_ENTRY
": %s,%u,%s,%s\n",
345 table_name
, GPOINTER_TO_UINT(key
), initial_dissector_name
,
346 current_dissector_name
);
350 * XXX - Just put a placeholder for the key value. Currently
351 * FT_NONE dissector table uses a single uint value for
354 decode_as_row
= ws_strdup_printf(
355 DECODE_AS_ENTRY
": %s,0,%s,%s\n",
356 table_name
, initial_dissector_name
,
357 current_dissector_name
);
364 case FT_STRINGZTRUNC
:
365 decode_as_row
= ws_strdup_printf(
366 DECODE_AS_ENTRY
": %s,%s,%s,%s\n",
367 table_name
, (char *)key
, initial_dissector_name
,
368 current_dissector_name
);
372 ws_assert_not_reached();
376 /* Do we need a better sort function ???*/
377 *decode_as_rows_list
= g_list_insert_sorted (*decode_as_rows_list
, (void *)decode_as_row
,
378 (GCompareFunc
)g_ascii_strcasecmp
);
382 /* Print the sorted rows to File */
384 decode_as_print_rows(void *data
, void *user_data
)
386 FILE *da_file
= (FILE *)user_data
;
387 const char *decode_as_row
= (const char *)data
;
389 fprintf(da_file
, "%s",decode_as_row
);
393 save_decode_as_entries(char** err
)
398 GList
*decode_as_rows_list
= NULL
;
400 if (create_persconffile_dir(&pf_dir_path
) == -1) {
401 *err
= ws_strdup_printf("Can't create directory\n\"%s\"\nfor recent file: %s.",
402 pf_dir_path
, g_strerror(errno
));
407 daf_path
= get_persconffile_path(DECODE_AS_ENTRIES_FILE_NAME
, true);
408 if ((da_file
= ws_fopen(daf_path
, "w")) == NULL
) {
409 *err
= ws_strdup_printf("Can't open decode_as_entries file\n\"%s\": %s.",
410 daf_path
, g_strerror(errno
));
415 fprintf(da_file
, "# \"Decode As\" entries file for %s " VERSION
".\n"
417 "# This file is regenerated each time \"Decode As\" preferences\n"
418 "# are saved within %s. Making manual changes should be safe,\n"
420 get_configuration_namespace(), get_configuration_namespace());
422 dissector_all_tables_foreach_changed(decode_as_write_entry
, &decode_as_rows_list
);
424 g_list_foreach(decode_as_rows_list
, decode_as_print_rows
, da_file
);
428 g_list_free_full(decode_as_rows_list
, g_free
);
434 * Data structure for tracking which dissector need to be reset. This
435 * structure is necessary as a hash table entry cannot be removed
436 * while a g_hash_table_foreach walk is in progress.
438 typedef struct dissector_delete_item
{
439 /* The name of the dissector table */
440 char *ddi_table_name
;
441 /* The type of the selector in that dissector table */
442 ftenum_t ddi_selector_type
;
443 /* The selector in the dissector table */
448 } dissector_delete_item_t
;
451 decode_build_reset_list (const char *table_name
, ftenum_t selector_type
,
452 void *key
, void *value _U_
,
455 dissector_delete_item_t
*item
;
457 item
= g_new(dissector_delete_item_t
,1);
458 item
->ddi_table_name
= g_strdup(table_name
);
459 item
->ddi_selector_type
= selector_type
;
460 switch (selector_type
) {
466 item
->ddi_selector
.sel_uint
= GPOINTER_TO_UINT(key
);
470 /* Not really needed, but prevents the assert */
471 item
->ddi_selector
.sel_uint
= 0;
478 case FT_STRINGZTRUNC
:
479 item
->ddi_selector
.sel_string
= g_strdup((char *)key
);
483 ws_assert_not_reached();
485 dissector_reset_list
= g_slist_prepend(dissector_reset_list
, item
);
488 /* clear all settings */
490 decode_clear_all(void)
492 dissector_delete_item_t
*item
;
495 dissector_all_tables_foreach_changed(decode_build_reset_list
, NULL
);
497 for (tmp
= dissector_reset_list
; tmp
; tmp
= g_slist_next(tmp
)) {
498 item
= (dissector_delete_item_t
*)tmp
->data
;
499 switch (item
->ddi_selector_type
) {
505 dissector_reset_uint(item
->ddi_table_name
,
506 item
->ddi_selector
.sel_uint
);
510 dissector_reset_payload(item
->ddi_table_name
);
517 case FT_STRINGZTRUNC
:
518 dissector_reset_string(item
->ddi_table_name
,
519 item
->ddi_selector
.sel_string
);
520 g_free(item
->ddi_selector
.sel_string
);
524 ws_assert_not_reached();
526 g_free(item
->ddi_table_name
);
529 g_slist_free(dissector_reset_list
);
530 dissector_reset_list
= NULL
;
532 decode_dcerpc_reset_all();
538 g_list_free(decode_as_list
);
539 decode_as_list
= NULL
;
548 * indent-tabs-mode: nil
551 * ex: set shiftwidth=4 tabstop=8 expandtab:
552 * :indentSize=4:tabSize=8:noTabs=true: