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/application_flavor.h"
20 #include "wsutil/file_util.h"
21 #include "wsutil/filesystem.h"
22 #include "epan/dissectors/packet-dcerpc.h"
26 #include <wsutil/ws_assert.h>
28 GList
*decode_as_list
;
30 void register_decode_as(decode_as_t
* reg
)
32 dissector_table_t decode_table
;
34 /* Ensure valid functions */
35 ws_assert(reg
->populate_list
);
36 ws_assert(reg
->reset_value
);
37 ws_assert(reg
->change_value
);
39 decode_table
= find_dissector_table(reg
->table_name
);
40 if (decode_table
!= NULL
)
42 dissector_table_allow_decode_as(decode_table
);
45 decode_as_list
= g_list_prepend(decode_as_list
, reg
);
48 static void next_proto_prompt(packet_info
*pinfo _U_
, char *result
)
50 snprintf(result
, MAX_DECODE_AS_PROMPT_LEN
, "Next level protocol as");
53 static void *next_proto_value(packet_info
*pinfo _U_
)
58 static build_valid_func next_proto_values
[] = { next_proto_value
};
59 static decode_as_value_t next_proto_da_values
=
60 { next_proto_prompt
, 1, next_proto_values
};
62 dissector_table_t
register_decode_as_next_proto(int proto
, const char *table_name
, const char *ui_name
, build_label_func label_func
)
66 dissector_table_t dt
= register_dissector_table(table_name
, ui_name
, proto
, FT_NONE
, BASE_NONE
);
68 da
= wmem_new0(wmem_epan_scope(), decode_as_t
);
69 da
->name
= wmem_strdup(wmem_epan_scope(), proto_get_protocol_filter_name(proto
));
70 da
->table_name
= wmem_strdup(wmem_epan_scope(), table_name
);
72 if (label_func
== NULL
)
74 da
->values
= &next_proto_da_values
;
78 da
->values
= wmem_new(wmem_epan_scope(), decode_as_value_t
);
79 da
->values
->label_func
= label_func
;
80 da
->values
->num_values
= 1;
81 da
->values
->build_values
= next_proto_values
;
83 da
->populate_list
= decode_as_default_populate_list
;
84 da
->reset_value
= decode_as_default_reset
;
85 da
->change_value
= decode_as_default_change
;
87 register_decode_as(da
);
91 struct decode_as_default_populate
93 decode_as_add_to_list_func add_to_list
;
98 decode_proto_add_to_list (const char *table_name
, void *value
, void *user_data
)
100 struct decode_as_default_populate
* populate
= (struct decode_as_default_populate
*)user_data
;
101 const char *dissector_description
;
103 dissector_handle_t handle
;
106 handle
= (dissector_handle_t
)value
;
107 dissector_description
= dissector_handle_get_description(handle
);
109 i
= dissector_handle_get_protocol_index(handle
);
110 if (i
>= 0 && !proto_is_protocol_enabled(find_protocol_by_id(i
)))
113 populate
->add_to_list(table_name
, dissector_description
, value
, populate
->ui_element
);
116 void decode_as_default_populate_list(const char *table_name
, decode_as_add_to_list_func add_to_list
, void *ui_element
)
118 struct decode_as_default_populate populate
;
120 populate
.add_to_list
= add_to_list
;
121 populate
.ui_element
= ui_element
;
123 dissector_table_foreach_handle(table_name
, decode_proto_add_to_list
, &populate
);
126 bool decode_as_default_reset(const char *name
, const void *pattern
)
128 switch (get_dissector_table_selector_type(name
)) {
133 dissector_reset_uint(name
, GPOINTER_TO_UINT(pattern
));
136 dissector_reset_payload(name
);
142 case FT_STRINGZTRUNC
:
143 dissector_reset_string(name
, (!pattern
)?"":(const char *) pattern
);
152 bool decode_as_default_change(const char *name
, const void *pattern
, const void *handle
, const char *list_name _U_
)
154 const dissector_handle_t dissector
= (const dissector_handle_t
)handle
;
155 switch (get_dissector_table_selector_type(name
)) {
160 dissector_change_uint(name
, GPOINTER_TO_UINT(pattern
), dissector
);
163 dissector_change_payload(name
, dissector
);
169 case FT_STRINGZTRUNC
:
170 dissector_change_string(name
, (!pattern
)?"":(const char *) pattern
, dissector
);
179 /* Some useful utilities for Decode As */
182 * A list of dissectors that need to be reset.
184 static GSList
*dissector_reset_list
;
187 * A callback function to parse each "decode as" entry in the file and apply the change
189 static prefs_set_pref_e
190 read_set_decode_as_entries(char *key
, const char *value
,
192 bool return_range_errors _U_
)
194 char *values
[4] = {NULL
, NULL
, NULL
, NULL
};
195 char delimiter
[4] = {',', ',', ',','\0'};
198 GHashTable
* processed_entries
= (GHashTable
*)user_data
;
199 dissector_table_t sub_dissectors
;
200 prefs_set_pref_e retval
= PREFS_SET_OK
;
201 bool is_valid
= false;
203 if (strcmp(key
, DECODE_AS_ENTRY
) == 0) {
204 /* Parse csv into table, selector, initial, current */
205 for (i
= 0; i
< 4; i
++) {
206 pch
= strchr(value
, delimiter
[i
]);
208 for (j
= 0; j
< i
; j
++) {
211 return PREFS_SET_SYNTAX_ERR
;
213 values
[i
] = g_strndup(value
, pch
- value
);
216 sub_dissectors
= find_dissector_table(values
[0]);
217 if (sub_dissectors
!= NULL
) {
218 dissector_handle_t handle
;
219 ftenum_t selector_type
;
222 const char* proto_name
;
224 selector_type
= dissector_table_get_type(sub_dissectors
);
226 handle
= dissector_table_get_dissector_handle(sub_dissectors
, values
[3]);
227 if (handle
!= NULL
|| g_ascii_strcasecmp(values
[3], DECODE_AS_NONE
) == 0) {
232 if (FT_IS_STRING(selector_type
)) {
233 dissector_change_string(values
[0], values
[1], handle
);
238 long_value
= strtol(values
[1], &p
, 0);
239 if (p
== values
[0] || *p
!= '\0' || long_value
< 0 ||
240 (unsigned long)long_value
> UINT_MAX
) {
241 retval
= PREFS_SET_SYNTAX_ERR
;
244 dissector_change_uint(values
[0], (unsigned)long_value
, handle
);
247 /* Now apply the value data back to dissector table preference */
248 if (handle
!= NULL
) {
249 proto_name
= proto_get_protocol_filter_name(dissector_handle_get_protocol_index(handle
));
250 module
= prefs_find_module(proto_name
);
251 // values[0] is the dissector table
252 char *pref_name
= ws_strdup_printf("%s%s", values
[0], dissector_handle_get_pref_suffix(handle
));
253 pref_value
= prefs_find_preference(module
, pref_name
);
255 if (pref_value
!= NULL
) {
256 bool replace
= false;
257 if (g_hash_table_lookup(processed_entries
, proto_name
) == NULL
) {
258 /* First decode as entry for this protocol, ranges may be replaced */
261 /* Remember we've processed this protocol */
262 g_hash_table_insert(processed_entries
, (void *)proto_name
, (void *)proto_name
);
265 prefs_add_decode_as_value(pref_value
, (unsigned)long_value
, replace
);
266 module
->prefs_changed_flags
|= prefs_get_effect_flags(pref_value
);
272 decode_build_reset_list(values
[0], selector_type
, values
[1], NULL
, NULL
);
275 retval
= PREFS_SET_SYNTAX_ERR
;
279 retval
= PREFS_SET_NO_SUCH_PREF
;
282 for (i
= 0; i
< 4; i
++) {
289 load_decode_as_entries(void)
296 daf_path
= get_persconffile_path(DECODE_AS_ENTRIES_FILE_NAME
, true);
297 if ((daf
= ws_fopen(daf_path
, "r")) != NULL
) {
298 /* Store saved entries for better range processing */
299 GHashTable
* processed_entries
= g_hash_table_new(g_str_hash
, g_str_equal
);
300 read_prefs_file(daf_path
, daf
, read_set_decode_as_entries
, processed_entries
);
301 g_hash_table_destroy(processed_entries
);
308 /* Make a sorted list of the entries as we are fetching them from a hash table. Then write it out from the sorted list */
310 decode_as_write_entry (const char *table_name
, ftenum_t selector_type
,
311 void *key
, void *value
, void *user_data
)
313 GList
**decode_as_rows_list
= (GList
**)user_data
;
314 dissector_handle_t current
, initial
;
315 const char *current_dissector_name
, *initial_dissector_name
, *decode_as_row
;
317 current
= dtbl_entry_get_handle((dtbl_entry_t
*)value
);
319 current_dissector_name
= DECODE_AS_NONE
;
321 current_dissector_name
= dissector_handle_get_description(current
);
322 initial
= dtbl_entry_get_initial_handle((dtbl_entry_t
*)value
);
324 initial_dissector_name
= DECODE_AS_NONE
;
326 initial_dissector_name
= dissector_handle_get_description(initial
);
328 switch (selector_type
) {
335 * XXX - write these in decimal, regardless of the base of
336 * the dissector table's selector, as older versions of
337 * Wireshark used atoi() when reading this file, and
338 * failed to handle hex or octal numbers.
340 * That will be fixed in future 1.10 and 1.12 releases,
341 * but pre-1.10 releases are at end-of-life and won't
344 decode_as_row
= ws_strdup_printf(
345 DECODE_AS_ENTRY
": %s,%u,%s,%s\n",
346 table_name
, GPOINTER_TO_UINT(key
), initial_dissector_name
,
347 current_dissector_name
);
351 * XXX - Just put a placeholder for the key value. Currently
352 * FT_NONE dissector table uses a single uint value for
355 decode_as_row
= ws_strdup_printf(
356 DECODE_AS_ENTRY
": %s,0,%s,%s\n",
357 table_name
, initial_dissector_name
,
358 current_dissector_name
);
365 case FT_STRINGZTRUNC
:
366 decode_as_row
= ws_strdup_printf(
367 DECODE_AS_ENTRY
": %s,%s,%s,%s\n",
368 table_name
, (char *)key
, initial_dissector_name
,
369 current_dissector_name
);
373 ws_assert_not_reached();
377 /* Do we need a better sort function ???*/
378 *decode_as_rows_list
= g_list_insert_sorted (*decode_as_rows_list
, (void *)decode_as_row
,
379 (GCompareFunc
)g_ascii_strcasecmp
);
383 /* Print the sorted rows to File */
385 decode_as_print_rows(void *data
, void *user_data
)
387 FILE *da_file
= (FILE *)user_data
;
388 const char *decode_as_row
= (const char *)data
;
390 fprintf(da_file
, "%s",decode_as_row
);
394 save_decode_as_entries(char** err
)
399 GList
*decode_as_rows_list
= NULL
;
401 if (create_persconffile_dir(&pf_dir_path
) == -1) {
402 *err
= ws_strdup_printf("Can't create directory\n\"%s\"\nfor recent file: %s.",
403 pf_dir_path
, g_strerror(errno
));
408 daf_path
= get_persconffile_path(DECODE_AS_ENTRIES_FILE_NAME
, true);
409 if ((da_file
= ws_fopen(daf_path
, "w")) == NULL
) {
410 *err
= ws_strdup_printf("Can't open decode_as_entries file\n\"%s\": %s.",
411 daf_path
, g_strerror(errno
));
416 fprintf(da_file
, "# \"Decode As\" entries file for %s " VERSION
".\n"
418 "# This file is regenerated each time \"Decode As\" preferences\n"
419 "# are saved within %s. Making manual changes should be safe,\n"
421 application_flavor_name_proper(), application_flavor_name_proper());
423 dissector_all_tables_foreach_changed(decode_as_write_entry
, &decode_as_rows_list
);
425 g_list_foreach(decode_as_rows_list
, decode_as_print_rows
, da_file
);
429 g_list_free_full(decode_as_rows_list
, g_free
);
435 * Data structure for tracking which dissector need to be reset. This
436 * structure is necessary as a hash table entry cannot be removed
437 * while a g_hash_table_foreach walk is in progress.
439 typedef struct dissector_delete_item
{
440 /* The name of the dissector table */
441 char *ddi_table_name
;
442 /* The type of the selector in that dissector table */
443 ftenum_t ddi_selector_type
;
444 /* The selector in the dissector table */
449 } dissector_delete_item_t
;
452 decode_build_reset_list (const char *table_name
, ftenum_t selector_type
,
453 void *key
, void *value _U_
,
456 dissector_delete_item_t
*item
;
458 item
= g_new(dissector_delete_item_t
,1);
459 item
->ddi_table_name
= g_strdup(table_name
);
460 item
->ddi_selector_type
= selector_type
;
461 switch (selector_type
) {
467 item
->ddi_selector
.sel_uint
= GPOINTER_TO_UINT(key
);
471 /* Not really needed, but prevents the assert */
472 item
->ddi_selector
.sel_uint
= 0;
479 case FT_STRINGZTRUNC
:
480 item
->ddi_selector
.sel_string
= g_strdup((char *)key
);
484 ws_assert_not_reached();
486 dissector_reset_list
= g_slist_prepend(dissector_reset_list
, item
);
489 /* clear all settings */
491 decode_clear_all(void)
493 dissector_delete_item_t
*item
;
496 dissector_all_tables_foreach_changed(decode_build_reset_list
, NULL
);
498 for (tmp
= dissector_reset_list
; tmp
; tmp
= g_slist_next(tmp
)) {
499 item
= (dissector_delete_item_t
*)tmp
->data
;
500 switch (item
->ddi_selector_type
) {
506 dissector_reset_uint(item
->ddi_table_name
,
507 item
->ddi_selector
.sel_uint
);
511 dissector_reset_payload(item
->ddi_table_name
);
518 case FT_STRINGZTRUNC
:
519 dissector_reset_string(item
->ddi_table_name
,
520 item
->ddi_selector
.sel_string
);
521 g_free(item
->ddi_selector
.sel_string
);
525 ws_assert_not_reached();
527 g_free(item
->ddi_table_name
);
530 g_slist_free(dissector_reset_list
);
531 dissector_reset_list
= NULL
;
533 decode_dcerpc_reset_all();
539 g_list_free(decode_as_list
);
540 decode_as_list
= NULL
;
549 * indent-tabs-mode: nil
552 * ex: set shiftwidth=4 tabstop=8 expandtab:
553 * :indentSize=4:tabSize=8:noTabs=true: