diff --git a/mc_dissector.c b/mc_dissector.c index 2bf7b96..25e02de 100644 --- a/mc_dissector.c +++ b/mc_dissector.c @@ -70,5 +70,4 @@ _U_ void plugin_register() { plugin.register_handoff = proto_reg_handoff; proto_register_plugin(&plugin); } - init_schema_data(); } \ No newline at end of file diff --git a/protocol/new_schema/schema.h b/protocol/new_schema/schema.h deleted file mode 100644 index b04a158..0000000 --- a/protocol/new_schema/schema.h +++ /dev/null @@ -1,18 +0,0 @@ -// -// Created by nickid2018 on 24-9-14. -// - -#ifndef MC_DISSECTOR_SCHEMA_H -#define MC_DISSECTOR_SCHEMA_H - -#include -#include - -typedef struct protocol_dissector_struct protocol_dissector; -typedef struct protocol_dissector_set_struct protocol_dissector_set; - -protocol_dissector_set *create_protocol(uint32_t protocol_version); - -void destroy_protocol(protocol_dissector_set *dissector_set); - -#endif //MC_DISSECTOR_SCHEMA_H diff --git a/protocol/protocol_data.c b/protocol/protocol_data.c index eb09c37..8862fe1 100644 --- a/protocol/protocol_data.c +++ b/protocol/protocol_data.c @@ -2,13 +2,14 @@ // Created by Nickid2018 on 2023/7/12. // +#include #include "protocol_data.h" char *STATE_NAME[] = {"Handshake", "Play", "Server List Ping", "Login", "Transfer", "Configuration", "Invalid"}; -gint read_var_int(tvbuff_t *tvb, gint offset, gint *result) { - guint8 read; - gint p = 0; +int32_t read_var_int(tvbuff_t *tvb, int32_t offset, int32_t *result) { + uint8_t read; + int32_t p = 0; *result = 0; do { if (p == 5) @@ -19,9 +20,9 @@ gint read_var_int(tvbuff_t *tvb, gint offset, gint *result) { return p; } -gint read_var_int_with_limit(tvbuff_t *tvb, gint offset, gint max_length, gint *result) { - guint8 read; - gint p = 0; +int32_t read_var_int_with_limit(tvbuff_t *tvb, int32_t offset, int32_t max_length, int32_t *result) { + uint8_t read; + int32_t p = 0; *result = 0; do { if (p == 5 || p >= max_length) @@ -32,10 +33,10 @@ gint read_var_int_with_limit(tvbuff_t *tvb, gint offset, gint max_length, gint * return p; } -gint read_var_long(tvbuff_t *tvb, gint offset, gint64 *result) { - gint p = 0; +int32_t read_var_long(tvbuff_t *tvb, int32_t offset, int64_t *result) { + int32_t p = 0; *result = 0; - guint8 read; + uint8_t read; do { if (p == 10) return INVALID_DATA; @@ -45,13 +46,19 @@ gint read_var_long(tvbuff_t *tvb, gint offset, gint64 *result) { return p; } -gint read_buffer(tvbuff_t *tvb, gint offset, guint8 **result, wmem_allocator_t *allocator) { - gint length; - gint read = read_var_int(tvb, offset, &length); +int32_t read_buffer(tvbuff_t *tvb, int32_t offset, uint8_t **result, wmem_allocator_t *allocator) { + int32_t length; + int32_t read = read_var_int(tvb, offset, &length); if (is_invalid(read)) return INVALID_DATA; *result = wmem_alloc(allocator, length + 1); tvb_memcpy(tvb, *result, offset + read, length); (*result)[length] = '\0'; return read + length; +} + +wmem_map_t *get_global_data(packet_info *pinfo) { + conversation_t *conv = find_or_create_conversation(pinfo); + mc_protocol_context *ctx = conversation_get_proto_data(conv, proto_mcje); + return ctx->global_data; } \ No newline at end of file diff --git a/protocol/protocol_data.h b/protocol/protocol_data.h index afc5dd2..9d0fcc6 100644 --- a/protocol/protocol_data.h +++ b/protocol/protocol_data.h @@ -8,6 +8,7 @@ #include #include #include "storage/storage.h" +#include "protocol/schema/schema.h" #define INVALID_DATA (-1) #define is_invalid(x) ((x) == INVALID_DATA) @@ -21,22 +22,22 @@ typedef struct { je_state client_state; je_state server_state; - guint32 server_port; + uint32_t server_port; address server_address; - guint32 protocol_version; - guint32 data_version; - protocol_je_set protocol_set; + uint32_t protocol_version; + uint32_t data_version; + protocol_dissector_set *dissector_set; - gint32 compression_threshold; + int32_t compression_threshold; bool encrypted; gcry_cipher_hd_t server_cipher; gcry_cipher_hd_t client_cipher; - gint server_last_segment_remaining; - gint client_last_segment_remaining; - guint8 *server_last_remains; - guint8 *client_last_remains; + int32_t server_last_segment_remaining; + int32_t client_last_segment_remaining; + uint8_t *server_last_remains; + uint8_t *client_last_remains; wmem_map_t *global_data; } mc_protocol_context; @@ -46,19 +47,21 @@ typedef struct { je_state server_state; bool encrypted; - guint8 *decrypted_data_head; - guint8 *decrypted_data_tail; - gint32 compression_threshold; + uint8_t *decrypted_data_head; + uint8_t *decrypted_data_tail; + int32_t compression_threshold; } mc_frame_data; extern char *STATE_NAME[]; -gint read_var_int(tvbuff_t *tvb, gint offset, gint *result); +wmem_map_t *get_global_data(packet_info *pinfo); -gint read_var_int_with_limit(tvbuff_t *tvb, gint offset, gint max_length, gint *result); +int32_t read_var_int(tvbuff_t *tvb, int32_t offset, int32_t *result); -gint read_var_long(tvbuff_t *tvb, gint offset, gint64 *result); +int32_t read_var_int_with_limit(tvbuff_t *tvb, int32_t offset, int32_t max_length, int32_t *result); -gint read_buffer(tvbuff_t *tvb, gint offset, guint8 **resul, wmem_allocator_t *allocator); +int32_t read_var_long(tvbuff_t *tvb, int32_t offset, int64_t *result); + +int32_t read_buffer(tvbuff_t *tvb, int32_t offset, uint8_t **resul, wmem_allocator_t *allocator); #endif //MC_DISSECTOR_PROTOCOL_DATA_H diff --git a/protocol/schema/functions.c b/protocol/schema/functions.c new file mode 100644 index 0000000..0cfebbd --- /dev/null +++ b/protocol/schema/functions.c @@ -0,0 +1,97 @@ +// +// Created by nickid2018 on 24-9-20. +// + +#include +#include "functions.h" +#include "protocol/storage/storage.h" +#include "protocol/protocol_data.h" + +extern int hf_generated; +extern int hf_invalid_data; + +DISSECT_PROTOCOL(record_entity_id) { + if (!get_settings_flag("registries") && !get_settings_flag("entities")) + return 0; + wmem_map_t *entity_id_record = wmem_map_lookup(get_global_data(pinfo), "#entity_id_record"); + if (entity_id_record == NULL) { + entity_id_record = wmem_map_new(wmem_file_scope(), g_str_hash, g_str_equal); + wmem_map_insert(get_global_data(pinfo), "#entity_id_record", entity_id_record); + } + gchar *entity_id = wmem_map_lookup(packet_saves, "entity_id"); + gchar *str_type = wmem_map_lookup(packet_saves, "entity_type"); + wmem_map_insert(entity_id_record, entity_id, str_type); + return 0; +} + +DISSECT_PROTOCOL(record_entity_id_player) { + if (!get_settings_flag("registries") && !get_settings_flag("entities")) + return 0; + wmem_map_t *entity_id_record = wmem_map_lookup(get_global_data(pinfo), "#entity_id_record"); + if (entity_id_record == NULL) { + entity_id_record = wmem_map_new(wmem_file_scope(), g_str_hash, g_str_equal); + wmem_map_insert(get_global_data(pinfo), "#entity_id_record", entity_id_record); + } + gchar *entity_id = wmem_map_lookup(packet_saves, "entity_id"); + wmem_map_insert(entity_id_record, entity_id, "player"); + return 0; +} + +DISSECT_PROTOCOL(record_entity_id_experience_orb) { + if (!get_settings_flag("registries") && !get_settings_flag("entities")) + return 0; + wmem_map_t *entity_id_record = wmem_map_lookup(get_global_data(pinfo), "#entity_id_record"); + if (entity_id_record == NULL) { + entity_id_record = wmem_map_new(wmem_file_scope(), g_str_hash, g_str_equal); + wmem_map_insert(get_global_data(pinfo), "#entity_id_record", entity_id_record); + } + gchar *entity_id = wmem_map_lookup(packet_saves, "entity_id"); + wmem_map_insert(entity_id_record, entity_id, "experience_orb"); + return 0; +} + +DISSECT_PROTOCOL(record_entity_id_painting) { + if (!get_settings_flag("registries") && !get_settings_flag("entities")) + return 0; + wmem_map_t *entity_id_record = wmem_map_lookup(get_global_data(pinfo), "#entity_id_record"); + if (entity_id_record == NULL) { + entity_id_record = wmem_map_new(wmem_file_scope(), g_str_hash, g_str_equal); + wmem_map_insert(get_global_data(pinfo), "#entity_id_record", entity_id_record); + } + gchar *entity_id = wmem_map_lookup(packet_saves, "entity_id"); + wmem_map_insert(entity_id_record, entity_id, "painting"); + return 0; +} + +DISSECT_PROTOCOL(sync_entity_data) { + if (!tree || !get_settings_flag("entity_sync_datas")) + return 0; + wmem_map_t *entity_id_record = wmem_map_lookup(get_global_data(pinfo), "#entity_id_record"); + if (entity_id_record == NULL) { + entity_id_record = wmem_map_new(wmem_file_scope(), g_str_hash, g_str_equal); + wmem_map_insert(get_global_data(pinfo), "#entity_id_record", entity_id_record); + } + gchar *entity_id = wmem_map_lookup(packet_saves, "entity_id"); + char *type = wmem_map_lookup(entity_id_record, entity_id); + if (type != NULL) { + proto_item *item = proto_tree_add_string(tree, hf_generated, tvb, 0, 0, type); + proto_item_set_generated(item); + proto_item_prepend_text(item, "Entity Type"); + } else { + proto_item *item = proto_tree_add_string(tree, hf_generated, tvb, 0, 0, "Unknown"); + proto_item_set_generated(item); + proto_item_prepend_text(item, "Entity Type"); + return 0; + } + gchar *sync_id = wmem_map_lookup(packet_saves, "sync_id"); + gchar *end; + int64_t sync = strtol(sync_id, &end, 10); + uint32_t protocol_version = (uint64_t) wmem_map_lookup(get_global_data(pinfo), "protocol_version"); + gchar *found_name = get_entity_sync_data_name(protocol_version, type, sync); + if (found_name == NULL) + found_name = "Unknown Sync Data!"; + proto_item *item = proto_tree_add_string(tree, hf_generated, tvb, 0, 0, found_name); + proto_item_set_generated(item); + proto_item_prepend_text(item, "Sync Data Type"); + return 0; +} \ No newline at end of file diff --git a/protocol/schema/functions.h b/protocol/schema/functions.h new file mode 100644 index 0000000..0553f88 --- /dev/null +++ b/protocol/schema/functions.h @@ -0,0 +1,26 @@ +// +// Created by nickid2018 on 24-9-20. +// + +#ifndef MC_DISSECTOR_FUNCTIONS_H +#define MC_DISSECTOR_FUNCTIONS_H + +#include "schema.h" + +#define DISSECT_PROTOCOL(fn) \ +int32_t dissect_##fn( \ + proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb, int offset, \ + protocol_dissector *dissector, gchar *name, wmem_map_t *packet_saves, gchar **value \ +) + +DISSECT_PROTOCOL(record_entity_id); + +DISSECT_PROTOCOL(record_entity_id_player); + +DISSECT_PROTOCOL(record_entity_id_experience_orb); + +DISSECT_PROTOCOL(record_entity_id_painting); + +DISSECT_PROTOCOL(sync_entity_data); + +#endif //MC_DISSECTOR_FUNCTIONS_H diff --git a/protocol/schema/protocol_functions.c b/protocol/schema/protocol_functions.c deleted file mode 100644 index 55db9ba..0000000 --- a/protocol/schema/protocol_functions.c +++ /dev/null @@ -1,142 +0,0 @@ -// -// Created by Nickid2018 on 2023/8/27. -// - -#include "protocol_functions.h" -#include "protocol/storage/storage.h" - -extern int hf_generated; - -FIELD_MAKE_TREE(record_entity_id) { - if (!get_settings_flag("registries") && !get_settings_flag("entities")) - return 0; - wmem_map_t *entity_id_record = wmem_map_lookup(extra, "entity_id_record"); - if (entity_id_record == NULL) { - entity_id_record = wmem_map_new(wmem_file_scope(), g_str_hash, g_str_equal); - wmem_map_insert(extra, "entity_id_record", entity_id_record); - } - char *id_path[] = {"entityId", NULL}; - gchar *id = record_query(recorder, id_path); - char *type_path[] = {"type", NULL}; - gchar *type = record_query(recorder, type_path); - guint protocol_version = GPOINTER_TO_UINT(wmem_map_lookup(extra, "protocol_version")); - guint type_uint = strtol(type, NULL, 10); - char *str_type = get_registry_data(protocol_version, "entity_type", type_uint); - wmem_map_insert(entity_id_record, id, str_type); - if (tree) { - proto_item *item = proto_tree_add_string(tree, hf_generated, tvb, 0, 0, str_type); - proto_item_set_generated(item); - proto_item_prepend_text(item, "Entity Type"); - } - return 0; -} - -FIELD_MAKE_TREE(record_entity_id_player) { - if (!get_settings_flag("registries") && !get_settings_flag("entities")) - return 0; - wmem_map_t *entity_id_record = wmem_map_lookup(extra, "entity_id_record"); - if (entity_id_record == NULL) { - entity_id_record = wmem_map_new(wmem_file_scope(), g_str_hash, g_str_equal); - wmem_map_insert(extra, "entity_id_record", entity_id_record); - } - char *id_path[] = {"entityId", NULL}; - gchar *id = record_query(recorder, id_path); - wmem_map_insert(entity_id_record, id, "player"); - return 0; -} - -FIELD_MAKE_TREE(record_entity_id_experience_orb) { - if (!get_settings_flag("registries") && !get_settings_flag("entities")) - return 0; - wmem_map_t *entity_id_record = wmem_map_lookup(extra, "entity_id_record"); - if (entity_id_record == NULL) { - entity_id_record = wmem_map_new(wmem_file_scope(), g_str_hash, g_str_equal); - wmem_map_insert(extra, "entity_id_record", entity_id_record); - } - char *id_path[] = {"entityId", NULL}; - gchar *id = record_query(recorder, id_path); - wmem_map_insert(entity_id_record, id, "experience_orb"); - return 0; -} - -FIELD_MAKE_TREE(record_entity_id_painting) { - if (!get_settings_flag("registries") && !get_settings_flag("entities")) - return 0; - wmem_map_t *entity_id_record = wmem_map_lookup(extra, "entity_id_record"); - if (entity_id_record == NULL) { - entity_id_record = wmem_map_new(wmem_file_scope(), g_str_hash, g_str_equal); - wmem_map_insert(extra, "entity_id_record", entity_id_record); - } - char *id_path[] = {"entityId", NULL}; - gchar *id = record_query(recorder, id_path); - wmem_map_insert(entity_id_record, id, "painting"); - return 0; -} - -FIELD_MAKE_TREE(sync_entity_data) { - if (!tree || !get_settings_flag("entity_sync_datas")) - return 0; - wmem_map_t *entity_id_record = wmem_map_lookup(extra, "entity_id_record"); - if (entity_id_record == NULL) { - entity_id_record = wmem_map_new(wmem_file_scope(), g_str_hash, g_str_equal); - wmem_map_insert(extra, "entity_id_record", entity_id_record); - } - char *id_path[] = {"..", "entityId", NULL}; - gchar *id = record_query(recorder, id_path); - char *key_path[] = {"key", NULL}; - gchar *key = record_query(recorder, key_path); - guint protocol_version = GPOINTER_TO_UINT(wmem_map_lookup(extra, "protocol_version")); - guint key_int = strtol(key, NULL, 10); - char *type = wmem_map_lookup(entity_id_record, id); - if (type != NULL) { - proto_item *item = proto_tree_add_string(tree, hf_generated, tvb, 0, 0, type); - proto_item_set_generated(item); - proto_item_prepend_text(item, "Entity Type"); - } else { - proto_item *item = proto_tree_add_string(tree, hf_generated, tvb, 0, 0, "Unknown"); - proto_item_set_generated(item); - proto_item_prepend_text(item, "Entity Type"); - return 0; - } - gchar *found_name = get_entity_sync_data_name(protocol_version, type, key_int); - if (found_name == NULL) - found_name = "Unknown Sync Data!"; - proto_item *item = proto_tree_add_string(tree, hf_generated, tvb, 0, 0, found_name); - proto_item_set_generated(item); - proto_item_prepend_text(item, "Sync Data Type"); - return 0; -} - -FIELD_MAKE_TREE(entity_event) { - if (!tree || !get_settings_flag("events")) - return 0; - char *event_id_path[] = {"entityStatus", NULL}; - gchar *event_id = record_query(recorder, event_id_path); - gchar *event_name = get_entity_event_data( - GPOINTER_TO_UINT(wmem_map_lookup(extra, "protocol_version")), - event_id - ); - if (event_name == NULL) - event_name = "Unknown"; - proto_item *item = proto_tree_add_string(tree, hf_generated, tvb, 0, 0, event_name); - proto_item_set_generated(item); - proto_item_prepend_text(item, "Entity Event Type"); - return 0; -} - -FIELD_MAKE_TREE(level_event) { - if (!tree || !get_settings_flag("events")) - return 0; - char *event_id_path[] = {"effectId", NULL}; - gchar *event_id = record_query(recorder, event_id_path); - gchar *event_name = get_level_event_data( - GPOINTER_TO_UINT(wmem_map_lookup(extra, "protocol_version")), - event_id - ); - if (event_name == NULL) - event_name = "Unknown"; - proto_item *item = proto_tree_add_string(tree, hf_generated, tvb, 0, 0, event_name); - proto_item_set_generated(item); - proto_item_prepend_text(item, "Level Event Type"); - return 0; -} \ No newline at end of file diff --git a/protocol/schema/protocol_functions.h b/protocol/schema/protocol_functions.h deleted file mode 100644 index d1b8e3b..0000000 --- a/protocol/schema/protocol_functions.h +++ /dev/null @@ -1,41 +0,0 @@ -// -// Created by Nickid2018 on 2023/8/27. -// - - -#ifndef MC_DISSECTOR_PROTOCOL_FUNCTIONS_H -#define MC_DISSECTOR_PROTOCOL_FUNCTIONS_H - -#include "protocol_schema.h" - -#define FIELD_MAKE_TREE(name) \ -gint make_tree_##name(proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb, wmem_map_t *extra, protocol_field field, gint offset, gint remaining, data_recorder recorder, bool is_je) - -#define SINGLE_LENGTH_FIELD_MAKE(id_name, hf, len, func_add, func_parse, record) \ - FIELD_MAKE_TREE(id_name) { \ - if (tree) \ - proto_item_prepend_text( \ - func_add(tree, hf, tvb, offset, len, record(recorder, func_parse(tvb, offset))), \ - "%s", \ - field->name \ - ); \ - else \ - record(recorder, func_parse(tvb, offset)); \ - return len; \ - } - -FIELD_MAKE_TREE(record_entity_id); - -FIELD_MAKE_TREE(record_entity_id_player); - -FIELD_MAKE_TREE(record_entity_id_experience_orb); - -FIELD_MAKE_TREE(record_entity_id_painting); - -FIELD_MAKE_TREE(sync_entity_data); - -FIELD_MAKE_TREE(entity_event); - -FIELD_MAKE_TREE(level_event); - -#endif //MC_DISSECTOR_PROTOCOL_FUNCTIONS_H diff --git a/protocol/schema/protocol_schema.c b/protocol/schema/protocol_schema.c deleted file mode 100644 index 0d1e862..0000000 --- a/protocol/schema/protocol_schema.c +++ /dev/null @@ -1,936 +0,0 @@ -// -// Created by Nickid2018 on 2023/7/13. -// - -#include -#include "protocol_schema.h" -#include "protocol/protocol_data.h" -#include "protocol_je/je_dissect.h" -#include "protocol_be/be_dissect.h" -#include "protocol_functions.h" -#include "utils/nbt.h" -#include "mc_dissector.h" - -#define BYTES_MAX_LENGTH 200 - -extern int hf_int8; -extern int hf_uint8; -extern int hf_int16; -extern int hf_uint16; -extern int hf_int32; -extern int hf_uint32; -extern int hf_int64; -extern int hf_uint64; -extern int hf_float; -extern int hf_double; -extern int hf_bytes; -extern int hf_string; -extern int hf_boolean; -extern int hf_uuid; -extern int hf_varint; -extern int hf_varlong; - -extern int hf_invalid_data; - -struct _protocol_set { - wmem_map_t *client_packet_map; - wmem_map_t *server_packet_map; - wmem_map_t *client_name_map; - wmem_map_t *server_name_map; -}; - -struct _protocol_entry { - guint id; - gchar *name; - bool is_je; - protocol_field field; -}; - -// ---------------------------------- Native Fields ---------------------------------- -FIELD_MAKE_TREE(var_int) { - gint result; - gint length = read_var_int(tvb, offset, &result); - guint record = record_uint(recorder, result); - if (tree) - proto_item_prepend_text( - proto_tree_add_uint(tree, hf_varint, tvb, offset, length, record), - "%s", - field->name - ); - return length; -} - -FIELD_MAKE_TREE(var_long) { - gint64 result; - gint length = read_var_long(tvb, offset, &result); - guint record = record_uint64(recorder, result); - if (tree) - proto_item_prepend_text( - proto_tree_add_uint64(tree, hf_varlong, tvb, offset, length, record), - "%s", - field->name - ); - return length; -} - -FIELD_MAKE_TREE(string) { - guint8 *str; - gint length = read_buffer(tvb, offset, &str, pinfo->pool); - char *record_str = record(recorder, str); - if (tree) - proto_item_prepend_text( - proto_tree_add_string(tree, hf_string, tvb, offset, length, record_str), - "%s", - field->name - ); - return length; -} - -FIELD_MAKE_TREE(var_buffer) { - gint length; - gint read = read_var_int(tvb, offset, &length); - if (tree) - proto_item_prepend_text( - proto_tree_add_bytes( - tree, hf_bytes, tvb, offset, length + read, - tvb_memdup( - pinfo->pool, tvb, offset + read, - length < BYTES_MAX_LENGTH ? length : BYTES_MAX_LENGTH - ) - ), - "%s", - field->name - ); - return read + length; -} - -SINGLE_LENGTH_FIELD_MAKE(u8, hf_uint8, 1, proto_tree_add_uint, tvb_get_uint8, record_uint) - -SINGLE_LENGTH_FIELD_MAKE(u16, hf_uint16, 2, proto_tree_add_uint, tvb_get_ntohs, record_uint) - -SINGLE_LENGTH_FIELD_MAKE(u32, hf_uint32, 4, proto_tree_add_uint, tvb_get_ntohl, record_uint) - -SINGLE_LENGTH_FIELD_MAKE(u64, hf_uint64, 8, proto_tree_add_uint64, tvb_get_ntoh64, record_uint64) - -SINGLE_LENGTH_FIELD_MAKE(i8, hf_int8, 1, proto_tree_add_int, tvb_get_int8, record_int) - -SINGLE_LENGTH_FIELD_MAKE(i16, hf_int16, 2, proto_tree_add_int, tvb_get_ntohis, record_int) - -SINGLE_LENGTH_FIELD_MAKE(i32, hf_int32, 4, proto_tree_add_int, tvb_get_ntohil, record_int) - -SINGLE_LENGTH_FIELD_MAKE(i64, hf_int64, 8, proto_tree_add_int64, tvb_get_ntohi64, record_int64) - -SINGLE_LENGTH_FIELD_MAKE(f32, hf_float, 4, proto_tree_add_float, tvb_get_ntohieee_float, record_float) - -SINGLE_LENGTH_FIELD_MAKE(f64, hf_double, 8, proto_tree_add_double, tvb_get_ntohieee_double, record_double) - -SINGLE_LENGTH_FIELD_MAKE(boolean, hf_boolean, 1, proto_tree_add_boolean, tvb_get_uint8, record_bool) - -FIELD_MAKE_TREE(rest_buffer) { - if (tree) { - proto_item_prepend_text( - proto_tree_add_bytes( - tree, hf_bytes, tvb, offset, remaining, - tvb_memdup( - pinfo->pool, tvb, offset, - remaining < BYTES_MAX_LENGTH ? remaining : BYTES_MAX_LENGTH - ) - ), - "%s", - field->name - ); - } - return remaining; -} - -FIELD_MAKE_TREE(uuid) { - e_guid_t *uuid = wmem_new(pinfo->pool, e_guid_t); - tvb_get_guid(tvb, offset, uuid, 0); - record(recorder, uuid); - if (tree) - proto_item_prepend_text( - proto_tree_add_guid(tree, hf_uuid, tvb, offset, 16, uuid), - "%s", - field->name - ); - return 16; -} - -FIELD_MAKE_TREE(void) { - return 0; -} - -FIELD_MAKE_TREE(nbt) { - if (pref_do_nbt_decode && is_je) - return do_nbt_tree(tree, pinfo, tvb, offset, field->name, true); - else { - gint length = count_nbt_length(tvb, offset); - if (tree) - proto_item_prepend_text( - proto_tree_add_bytes( - tree, hf_bytes, tvb, offset, length, - tvb_memdup( - pinfo->pool, tvb, offset, - length < BYTES_MAX_LENGTH ? length : BYTES_MAX_LENGTH - ) - ), - "%s", - field->name - ); - return length; - } -} - -FIELD_MAKE_TREE(optional_nbt) { - guint8 present = tvb_get_uint8(tvb, offset); - if (present != TAG_END) { - if (pref_do_nbt_decode && is_je) - return do_nbt_tree(tree, pinfo, tvb, offset, field->name, true); - else { - gint length = count_nbt_length(tvb, offset); - if (tree) - proto_item_prepend_text( - proto_tree_add_bytes( - tree, hf_bytes, tvb, offset, length, - tvb_memdup( - pinfo->pool, tvb, offset, - length < BYTES_MAX_LENGTH ? length : BYTES_MAX_LENGTH - ) - ), - "%s", - field->name - ); - return length; - } - } else { - if (tree) { - proto_item *text = proto_tree_add_boolean(tree, hf_boolean, tvb, offset, 1, false); - proto_item_set_text(text, "%s [optional nbt]: Not present", field->name); - } - return 1; - } -} - -FIELD_MAKE_TREE(nbt_any_type) { - guint8 present = tvb_get_uint8(tvb, offset); - if (present != TAG_END) { - if (pref_do_nbt_decode && is_je) - return do_nbt_tree(tree, pinfo, tvb, offset, field->name, false); - else { - gint length = count_nbt_length_with_type(tvb, offset + 1, present) + 1; - if (tree) - proto_item_prepend_text( - proto_tree_add_bytes( - tree, hf_bytes, tvb, offset, length, - tvb_memdup( - pinfo->pool, tvb, offset, - length < BYTES_MAX_LENGTH ? length : BYTES_MAX_LENGTH - ) - ), - "%s", - field->name - ); - return length; - } - } else { - if (tree) { - proto_item *text = proto_tree_add_boolean(tree, hf_boolean, tvb, offset, 1, false); - proto_item_set_text(text, "%s [optional nbt]: Not present", field->name); - } - return 1; - } -} - -FIELD_MAKE_TREE(container) { - bool not_top = wmem_map_lookup(field->additional_info, GINT_TO_POINTER(-1)) == NULL; - gchar *now_record = record_get_recording(recorder); - if (not_top) - record_push(recorder); - if (tree && not_top) - tree = proto_tree_add_subtree( - tree, tvb, offset, remaining, - is_je ? ett_sub : ett_sub_be, NULL, field->name - ); - gint length = GPOINTER_TO_UINT(wmem_map_lookup(field->additional_info, 0)); - gint total_length = 0; - for (guint i = 1; i <= length; i++) { - protocol_field sub_field = wmem_map_lookup(field->additional_info, GUINT_TO_POINTER(i)); - if (g_strcmp0(sub_field->name, "[unnamed]") == 0 && not_top) { - record_pop(recorder); - record_start(recorder, now_record); - sub_field->make_tree(NULL, pinfo, tvb, extra, sub_field, offset, remaining, recorder, is_je); - record_start(recorder, now_record); - record_push(recorder); - } - record_start(recorder, sub_field->name); - gint sub_length = sub_field->make_tree(tree, pinfo, tvb, extra, sub_field, offset, remaining, recorder, is_je); - offset += sub_length; - total_length += sub_length; - remaining -= sub_length; - } - if (not_top) { - if (tree) - proto_item_set_len(proto_tree_get_parent(tree), total_length); - record_pop(recorder); - } - return total_length; -} - -FIELD_MAKE_TREE(option) { - bool is_present = tvb_get_uint8(tvb, offset) != 0; - protocol_field sub_field = wmem_map_lookup(field->additional_info, 0); - sub_field->name = field->name; - if (is_present) - return sub_field->make_tree(tree, pinfo, tvb, extra, sub_field, offset + 1, remaining - 1, recorder, is_je) + 1; - else { - if (tree) { - proto_item *text = proto_tree_add_boolean(tree, hf_boolean, tvb, offset, 1, false); - proto_item_set_text(text, "%s [optional]: Not present", field->name); - } - return 1; - } -} - -FIELD_MAKE_TREE(buffer) { - gint length = GPOINTER_TO_UINT(wmem_map_lookup(field->additional_info, 0)); - if (tree) - proto_item_prepend_text( - proto_tree_add_bytes( - tree, hf_bytes, tvb, offset, length, - tvb_memdup( - pinfo->pool, tvb, offset, - length < BYTES_MAX_LENGTH ? length : BYTES_MAX_LENGTH - ) - ), - "%s", - field->name - ); - return length; -} - -FIELD_MAKE_TREE(mapper) { - protocol_field sub_field = wmem_map_lookup(field->additional_info, "__subfield"); - gchar *recording = record_get_recording(recorder); - record_start(recorder, "__mapperValue"); - gint length = sub_field->make_tree(NULL, pinfo, tvb, extra, sub_field, offset, remaining, recorder, is_je); - char *path[] = {"__mapperValue", NULL}; - gchar *map = record_query(recorder, path); - gchar *map_name = wmem_map_lookup(field->additional_info, map); - record_start(recorder, recording); - record(recorder, map_name); - if (tree) - proto_item_prepend_text( - proto_tree_add_string(tree, hf_string, tvb, offset, length, map_name), - "%s", - field->name - ); - return length; -} - -FIELD_MAKE_TREE(array) { - protocol_field sub_field = wmem_map_lookup(field->additional_info, GINT_TO_POINTER(1)); - char **len_data = wmem_map_lookup(field->additional_info, 0); - gint len = 0; - gint data_count = 0; - if (len_data == NULL) - len = read_var_int(tvb, offset, &data_count); - else { - char *end_ptr; - data_count = (gint) strtol(record_query(recorder, len_data), &end_ptr, 10); - } - proto_tree *sub_tree = NULL; - if (tree) { - sub_tree = proto_tree_add_subtree( - tree, tvb, offset, remaining, - is_je ? ett_sub : ett_sub_be, NULL, - g_strdup_printf("%s (%d entries)", field->name, data_count) - ); - } - offset += len; - remaining -= len; - gchar *recording = record_get_recording(recorder); - for (int i = 0; i < data_count; i++) { - record_start(recorder, g_strconcat(recording, "[", g_strdup_printf("%d", i), "]", NULL)); - sub_field->name = g_strdup_printf("%s[%d]", field->name, i); - gint sub_length = sub_field->make_tree( - sub_tree, pinfo, tvb, extra, sub_field, offset, remaining, recorder, - is_je - ); - offset += sub_length; - len += sub_length; - remaining -= sub_length; - } - if (tree) - proto_item_set_len(sub_tree, len); - return len; -} - -FIELD_MAKE_TREE(bitfield) { - int size = GPOINTER_TO_INT(wmem_map_lookup(field->additional_info, GINT_TO_POINTER(-1))); - record_push(recorder); - int offset_bit = 0; - for (int i = 0; i < size; i++) { - int len = GPOINTER_TO_INT(wmem_map_lookup(field->additional_info, GINT_TO_POINTER(i * 3))); - bool signed_number = GPOINTER_TO_INT(wmem_map_lookup(field->additional_info, GINT_TO_POINTER(i * 3 + 1))); - char *name = wmem_map_lookup(field->additional_info, GINT_TO_POINTER(i * 3 + 2)); - record_start(recorder, name); - if (len <= 32) { - guint read = tvb_get_bits(tvb, offset * 8 + offset_bit, len, ENC_BIG_ENDIAN); - if (signed_number) { - record_int(recorder, *(gint32 *) &read); - if (tree) - proto_item_append_text( - proto_tree_add_bits_item( - tree, hf_int32, tvb, - offset * 8 + offset_bit, len, - ENC_BIG_ENDIAN - ), - "%s", - g_strdup_printf(" ", name) - ); - } else { - record_uint(recorder, read); - if (tree) - proto_item_append_text( - proto_tree_add_bits_item( - tree, hf_uint32, tvb, - offset * 8 + offset_bit, len, - ENC_BIG_ENDIAN - ), - "%s", - g_strdup_printf(" ", name) - ); - } - } else { - guint64 read = tvb_get_bits64(tvb, offset * 8 + offset_bit, len, ENC_BIG_ENDIAN); - if (signed_number) { - record_int64(recorder, *(gint64 *) &read); - if (tree) - proto_item_append_text( - proto_tree_add_bits_item( - tree, hf_int64, tvb, - offset * 8 + offset_bit, len, - ENC_BIG_ENDIAN - ), - "%s", - g_strdup_printf(" ", name) - ); - } else { - record_uint64(recorder, read); - if (tree) - proto_item_append_text( - proto_tree_add_bits_item( - tree, hf_uint64, tvb, - offset * 8 + offset_bit, len, - ENC_BIG_ENDIAN - ), - "%s", - g_strdup_printf(" ", name) - ); - } - } - offset_bit += len; - } - record_pop(recorder); - return (offset_bit + 7) / 8; -} - -FIELD_MAKE_TREE(top_bit_set_terminated_array) { - protocol_field sub_field = wmem_map_lookup(field->additional_info, 0); - guint8 now; - gint len = 0; - gchar *recording = record_get_recording(recorder); - proto_tree *sub_tree = NULL; - if (tree) - sub_tree = proto_tree_add_subtree( - tree, tvb, offset, remaining, - is_je ? ett_sub : ett_sub_be, NULL, field->name - ); - do { - now = tvb_get_uint8(tvb, offset++); - len++; - guint ord = now & 0x7F; - record_start(recorder, g_strconcat(recording, "[", g_strdup_printf("%d", ord), "]", NULL)); - sub_field->name = g_strdup_printf("%s[%d]", field->name, ord); - gint sub_length = sub_field->make_tree( - sub_tree, pinfo, tvb, extra, sub_field, offset, remaining - len, - recorder, is_je - ); - offset += sub_length; - len += sub_length; - } while ((now & 0x80) != 0); - if (tree) - proto_item_set_len(sub_tree, len); - return len; -} - -FIELD_MAKE_TREE(switch) { - char **path = wmem_map_lookup(field->additional_info, "__path"); - void *key = record_query(recorder, path); - protocol_field sub_field_choose = wmem_map_lookup(field->additional_info, key); - if (sub_field_choose == NULL) // default - sub_field_choose = wmem_map_lookup(field->additional_info, "default"); - if (sub_field_choose == NULL) // no case matched - return 0; - sub_field_choose->name = field->name; - gint len = sub_field_choose->make_tree( - tree, pinfo, tvb, extra, sub_field_choose, offset, remaining, recorder, is_je - ); - return len; -} - -FIELD_MAKE_TREE(entity_metadata_loop) { - protocol_field sub_field = wmem_map_lookup(field->additional_info, GINT_TO_POINTER(0)); - int end_val_1 = GPOINTER_TO_INT(wmem_map_lookup(field->additional_info, GINT_TO_POINTER(1))); - guint8 end_val = *(guint8 *) &end_val_1; - int count = 0; - gint len = 0; - gchar *recording = record_get_recording(recorder); - proto_tree *sub_tree = NULL; - if (tree) - sub_tree = proto_tree_add_subtree( - tree, tvb, offset, remaining, - is_je ? ett_sub : ett_sub_be, NULL, field->name - ); - while (tvb_get_uint8(tvb, offset) != end_val) { - record_start(recorder, g_strconcat(recording, "[", g_strdup_printf("%d", count), "]", NULL)); - sub_field->name = g_strdup_printf("%s[%d]", field->name, count); - gint sub_length = sub_field->make_tree( - sub_tree, pinfo, tvb, extra, sub_field, offset, remaining - len, recorder, is_je - ); - offset += sub_length; - len += sub_length; - count++; - } - if (tree) - proto_item_set_len(sub_tree, len + 1); - return len + 1; -} - -FIELD_MAKE_TREE(basic_type) { - int len = GPOINTER_TO_INT(wmem_map_lookup(field->additional_info, GINT_TO_POINTER(-2))); - protocol_field sub_field = wmem_map_lookup(field->additional_info, GINT_TO_POINTER(-1)); - for (int i = 0; i < len; i++) { - gchar *name = wmem_map_lookup(field->additional_info, GINT_TO_POINTER(i * 2)); - gchar *value = wmem_map_lookup(field->additional_info, GINT_TO_POINTER(i * 2 + 1)); - record_add_alias(recorder, name, value); - } - sub_field->name = field->name; - gint sub_length = sub_field->make_tree(tree, pinfo, tvb, extra, sub_field, offset, remaining, recorder, is_je); - record_clear_alias(recorder); - return sub_length; -} - -// ------------------------------- End of Native Fields -------------------------------- - -wmem_map_t *native_make_tree_map = NULL; -wmem_map_t *native_types = NULL; - -wmem_map_t *function_make_tree = NULL; - -#define ADD_NATIVE(json_name, make_name, type_name) \ - wmem_map_insert(native_make_tree_map, #json_name, make_tree_##make_name); \ - wmem_map_insert(native_types, #json_name, #type_name); - -#define ADD_FUNCTION(json_name, func_name) \ - wmem_map_insert(function_make_tree, #json_name, make_tree_##func_name); - -void init_schema_data() { - native_make_tree_map = wmem_map_new(wmem_epan_scope(), g_str_hash, g_str_equal); - native_types = wmem_map_new(wmem_epan_scope(), g_str_hash, g_str_equal); - function_make_tree = wmem_map_new(wmem_epan_scope(), g_str_hash, g_str_equal); - - ADD_NATIVE(varint, var_int, u32) - ADD_NATIVE(optvarint, var_int, u32) - ADD_NATIVE(varlong, var_long, u64) - ADD_NATIVE(string, string, string) - ADD_NATIVE(u8, u8, u8) - ADD_NATIVE(u16, u16, u16) - ADD_NATIVE(u32, u32, u32) - ADD_NATIVE(u64, u64, u64) - ADD_NATIVE(i8, i8, i8) - ADD_NATIVE(i16, i16, i16) - ADD_NATIVE(i32, i32, i32) - ADD_NATIVE(i64, i64, i64) - ADD_NATIVE(bool, boolean, bool) - ADD_NATIVE(f32, f32, f32) - ADD_NATIVE(f64, f64, f64) - ADD_NATIVE(UUID, uuid, uuid) - ADD_NATIVE(restBuffer, rest_buffer, bytes) - ADD_NATIVE(void, void, u32) - ADD_NATIVE(nbt, nbt, bytes) - ADD_NATIVE(optionalNbt, optional_nbt, bytes) - - ADD_FUNCTION(sync_entity_data, sync_entity_data) - ADD_FUNCTION(record_entity_id, record_entity_id) - ADD_FUNCTION(record_entity_id_player, record_entity_id_player) - ADD_FUNCTION(record_entity_id_experience_orb, record_entity_id_experience_orb) - ADD_FUNCTION(record_entity_id_painting, record_entity_id_painting) - ADD_FUNCTION(entity_event, entity_event) - ADD_FUNCTION(level_event, level_event) -} - -// NOLINTNEXTLINE -protocol_field parse_protocol(wmem_map_t *basic_types, wmem_list_t *resolving_basics, - cJSON *data, cJSON *types, bool is_je, bool on_top, - protocol_settings settings) { - if (data == NULL) { - ws_log( - "MC-Dissector", - LOG_LEVEL_CRITICAL, - "Invalid protocol data - Data is NULL" - ); - return NULL; - } - - if (cJSON_IsString(data)) { - char *type = data->valuestring; - void *make_tree_func = wmem_map_lookup(native_make_tree_map, type); - if (make_tree_func != NULL) { - protocol_field field = wmem_new(wmem_epan_scope(), protocol_field_t); - field->name = ""; - field->additional_info = NULL; - field->make_tree = make_tree_func; - - if (settings.nbt_any_type && g_strcmp0(type, "nbt") == 0) - field->make_tree = make_tree_nbt_any_type; - - return field; - } - - protocol_field field = wmem_map_lookup(basic_types, type); - if (field != NULL) - return field; - - if (wmem_list_find(resolving_basics, type) != NULL) { // recursive loop - field = wmem_new(wmem_epan_scope(), protocol_field_t); - wmem_map_insert(basic_types, type, field); - protocol_field processed = parse_protocol( - basic_types, resolving_basics, - cJSON_GetObjectItem(types, data->valuestring), types, is_je, false, settings - ); - wmem_map_remove(basic_types, type); - if (processed == NULL) { - return NULL; - } - *field = *processed; - } else { - wmem_list_append(resolving_basics, type); - field = wmem_new(wmem_epan_scope(), protocol_field_t); - protocol_field processed = parse_protocol( - basic_types, resolving_basics, - cJSON_GetObjectItem(types, data->valuestring), types, is_je, false, settings - ); - wmem_list_remove(resolving_basics, type); - if (processed == NULL) { - return NULL; - } - *field = *processed; - } - - return field; - } - if (cJSON_GetArraySize(data) != 2) { - ws_log( - "MC-Dissector", - LOG_LEVEL_CRITICAL, - "Invalid protocol data - Argument size not matches 2: %s", - cJSON_Print(data) - ); - return NULL; - } - char *type = cJSON_GetArrayItem(data, 0)->valuestring; - cJSON *fields = cJSON_GetArrayItem(data, 1); - - protocol_field field = wmem_new(wmem_epan_scope(), protocol_field_t); - field->additional_info = wmem_map_new(wmem_epan_scope(), g_direct_hash, g_direct_equal); - field->make_tree = NULL; - field->name = "[unnamed]"; - - if (g_strcmp0(type, "function") == 0) { - field->make_tree = wmem_map_lookup(function_make_tree, fields->valuestring); - return field; - } else if (g_strcmp0(type, "container") == 0) { // container - field->make_tree = make_tree_container; - int size = cJSON_GetArraySize(fields); - wmem_map_insert(field->additional_info, 0, GINT_TO_POINTER(size)); - for (int i = 0; i < size; i++) { - cJSON *field_data = cJSON_GetArrayItem(fields, i); - cJSON *type_data = cJSON_GetObjectItem(field_data, "type"); - protocol_field sub_field = parse_protocol( - basic_types, resolving_basics, type_data, types, is_je, false, settings - ); - if (sub_field == NULL) - return NULL; - if (cJSON_HasObjectItem(field_data, "name")) - sub_field->name = g_strdup(cJSON_GetObjectItem(field_data, "name")->valuestring); - wmem_map_insert(field->additional_info, GINT_TO_POINTER(i + 1), sub_field); - } - if (on_top) - wmem_map_insert(field->additional_info, GINT_TO_POINTER(-1), GINT_TO_POINTER(1)); - return field; - } else if (g_strcmp0(type, "option") == 0) { // option - field->make_tree = make_tree_option; - protocol_field sub_field = parse_protocol( - basic_types, resolving_basics, fields, types, is_je, false, settings - ); - if (sub_field == NULL) - return NULL; - wmem_map_insert(field->additional_info, 0, sub_field); - return field; - } else if (g_strcmp0(type, "buffer") == 0) { // buffer - if (cJSON_HasObjectItem(fields, "count")) { - field->make_tree = make_tree_buffer; - cJSON *count = cJSON_GetObjectItem(fields, "count"); - wmem_map_insert(field->additional_info, 0, GINT_TO_POINTER(count->valueint)); - } else - field->make_tree = make_tree_var_buffer; - return field; - } else if (g_strcmp0(type, "mapper") == 0) { // mapper - field->additional_info = wmem_map_new(wmem_epan_scope(), g_str_hash, g_str_equal); - cJSON *type_data = cJSON_GetObjectItem(fields, "type"); - protocol_field sub_field = parse_protocol( - basic_types, resolving_basics, type_data, types, is_je, false, settings - ); - if (sub_field == NULL) - return NULL; - field->make_tree = make_tree_mapper; - wmem_map_insert(field->additional_info, "__subfield", sub_field); - cJSON *mappings = cJSON_GetObjectItem(fields, "mappings"); - cJSON *now = mappings->child; - while (now != NULL) { - char *key = now->string; - char *value = now->valuestring; - wmem_map_insert(field->additional_info, strdup(key), strdup(value)); - now = now->next; - } - return field; - } else if (g_strcmp0(type, "array") == 0) { // array - cJSON *count = cJSON_GetObjectItem(fields, "count"); - if (count != NULL) - wmem_map_insert( - field->additional_info, 0, - g_strsplit(count->valuestring, "/", 10) - ); - else { - cJSON *count_type = cJSON_GetObjectItem(fields, "countType"); - if (count_type == NULL || g_strcmp0(count_type->valuestring, "varint") != 0) { - ws_log( - "MC-Dissector", - LOG_LEVEL_CRITICAL, - "Invalid protocol data - Array count type is invalid: %s", - cJSON_Print(data) - ); - return NULL; - } - } - - cJSON *type_data = cJSON_GetObjectItem(fields, "type"); - protocol_field sub_field = parse_protocol( - basic_types, resolving_basics, type_data, types, is_je, false, settings - ); - if (sub_field == NULL) - return NULL; - field->make_tree = make_tree_array; - wmem_map_insert(field->additional_info, GINT_TO_POINTER(1), sub_field); - return field; - } else if (g_strcmp0(type, "bitfield") == 0) { - int size = cJSON_GetArraySize(fields); - wmem_map_insert(field->additional_info, GINT_TO_POINTER(-1), GINT_TO_POINTER(size)); - int total_bits = 0; - for (int i = 0; i < size; i++) { - cJSON *field_data = cJSON_GetArrayItem(fields, i); - bool signed_ = cJSON_GetObjectItem(field_data, "signed")->valueint; - int bits = cJSON_GetObjectItem(field_data, "size")->valueint; - char *name = cJSON_GetObjectItem(field_data, "name")->valuestring; - wmem_map_insert(field->additional_info, GINT_TO_POINTER(i * 3), GINT_TO_POINTER(bits)); - wmem_map_insert(field->additional_info, GINT_TO_POINTER(i * 3 + 1), GINT_TO_POINTER(signed_)); - wmem_map_insert(field->additional_info, GINT_TO_POINTER(i * 3 + 2), strdup(name)); - total_bits += bits; - } - field->make_tree = make_tree_bitfield; - return field; - } else if (g_strcmp0(type, "topBitSetTerminatedArray") == 0) { - protocol_field sub_field = parse_protocol( - basic_types, resolving_basics, cJSON_GetObjectItem(fields, "type"), types, is_je, false, settings - ); - if (sub_field == NULL) - return NULL; - wmem_map_insert(field->additional_info, 0, sub_field); - field->make_tree = make_tree_top_bit_set_terminated_array; - return field; - } else if (g_strcmp0(type, "switch") == 0) { - char *compare_data = cJSON_GetObjectItem(fields, "compareTo")->valuestring; - char **compare_data_split = g_strsplit(strdup(compare_data), "/", 10); - field->additional_info = wmem_map_new(wmem_epan_scope(), g_str_hash, g_str_equal); - wmem_map_insert(field->additional_info, strdup("__path"), compare_data_split); - if (cJSON_HasObjectItem(fields, "default")) { - cJSON *default_data = cJSON_GetObjectItem(fields, "default"); - protocol_field default_field = parse_protocol( - basic_types, resolving_basics, default_data, types, is_je, false, settings - ); - if (default_field == NULL) - return NULL; - wmem_map_insert(field->additional_info, strdup("default"), default_field); - } - cJSON *cases = cJSON_GetObjectItem(fields, "fields"); - if (cases == NULL) { - ws_log( - "MC-Dissector", - LOG_LEVEL_CRITICAL, - "Invalid protocol data - Switch cases not found: %s", - cJSON_Print(data) - ); - return NULL; - } - cJSON *now = cases->child; - while (now != NULL) { - char *key = now->string; - protocol_field value = parse_protocol( - basic_types, resolving_basics, now, types, is_je, false, settings - ); - if (value == NULL) - return NULL; - wmem_map_insert(field->additional_info, strdup(key), value); - now = now->next; - } - field->make_tree = make_tree_switch; - return field; - } else if (g_strcmp0(type, "entityMetadataLoop") == 0) { - protocol_field sub_field = parse_protocol( - basic_types, resolving_basics, cJSON_GetObjectItem(fields, "type"), types, is_je, false, settings - ); - if (sub_field == NULL) - return NULL; - int end_val = cJSON_GetObjectItem(fields, "endVal")->valueint; - wmem_map_insert(field->additional_info, GINT_TO_POINTER(0), sub_field); - wmem_map_insert(field->additional_info, GINT_TO_POINTER(1), GINT_TO_POINTER(end_val)); - field->make_tree = make_tree_entity_metadata_loop; - return field; - } else if (cJSON_HasObjectItem(types, type)) { - protocol_field_t *type_data = wmem_map_lookup(basic_types, type); - if (type_data == NULL) { - type_data = parse_protocol( - basic_types, resolving_basics, cJSON_GetObjectItem(types, type), types, is_je, false, settings - ); - } - if (type_data == NULL) - return NULL; - wmem_map_insert(field->additional_info, GINT_TO_POINTER(-1), type_data); - cJSON *now = fields->child; - int i = 0; - while (now != NULL) { - wmem_map_insert(field->additional_info, GINT_TO_POINTER(i * 2), g_strconcat("$", now->string, NULL)); - wmem_map_insert(field->additional_info, GINT_TO_POINTER(i * 2 + 1), strdup(now->valuestring)); - now = now->next; - i++; - } - wmem_map_insert(field->additional_info, GINT_TO_POINTER(-2), GINT_TO_POINTER(i)); - field->make_tree = make_tree_basic_type; - return field; - } - - ws_log( - "MC-Dissector", - LOG_LEVEL_ERROR, - "Invalid protocol data - Unknown type: %s", - cJSON_Print(data) - ); - return NULL; -} - -void make_simple_protocol(cJSON *data, cJSON *types, wmem_map_t *packet_map, wmem_map_t *name_map, bool is_je, - protocol_settings settings) { - cJSON *packets = cJSON_GetObjectItem(data, "packet"); - // Path: [1].[0].type.[1].mappings - cJSON *c1 = cJSON_GetArrayItem(packets, 1); - cJSON *c2 = cJSON_GetArrayItem(c1, 0); - cJSON *c3 = cJSON_GetObjectItem(c2, "type"); - cJSON *c4 = cJSON_GetArrayItem(c3, 1); - cJSON *mappings = cJSON_GetObjectItem(c4, "mappings"); - cJSON *now = mappings->child; - - wmem_map_t *basic_types = wmem_map_new(wmem_epan_scope(), g_str_hash, g_str_equal); - wmem_list_t *resolving_basics = wmem_list_new(wmem_epan_scope()); - while (now != NULL) { - char *packet_id_str = now->string; - gchar *packet_name = strdup(now->valuestring); - char *ptr; - guint packet_id = (guint) strtol(packet_id_str + 2, &ptr, 16); - wmem_map_insert(name_map, packet_name, GUINT_TO_POINTER(packet_id + 1)); - - protocol_entry entry = wmem_new(wmem_epan_scope(), protocol_entry_t); - entry->id = packet_id; - entry->name = packet_name; - entry->is_je = is_je; - wmem_map_insert(packet_map, GUINT_TO_POINTER(packet_id), entry); - - gchar *packet_definition = g_strconcat("packet_", packet_name, NULL); - cJSON *item = cJSON_GetObjectItem(data, packet_definition); - - if (item != NULL) { - entry->field = parse_protocol(basic_types, resolving_basics, item, types, is_je, true, settings); - } else { - protocol_field field = wmem_new(wmem_epan_scope(), protocol_field_t); - field->make_tree = make_tree_void; - entry->field = field; - } - g_free(packet_definition); - - now = now->next; - } - wmem_free(wmem_epan_scope(), basic_types); - wmem_destroy_list(resolving_basics); -} - -protocol_set create_protocol_set(cJSON *types, cJSON *data, bool is_je, protocol_settings settings) { - protocol_set set = wmem_new(wmem_epan_scope(), protocol_set_t); - set->client_packet_map = wmem_map_new(wmem_epan_scope(), g_direct_hash, g_direct_equal); - set->server_packet_map = wmem_map_new(wmem_epan_scope(), g_direct_hash, g_direct_equal); - set->client_name_map = wmem_map_new(wmem_epan_scope(), g_str_hash, g_str_equal); - set->server_name_map = wmem_map_new(wmem_epan_scope(), g_str_hash, g_str_equal); - - cJSON *to_client = cJSON_GetObjectItem(cJSON_GetObjectItem(data, "toClient"), "types"); - cJSON *to_server = cJSON_GetObjectItem(cJSON_GetObjectItem(data, "toServer"), "types"); - make_simple_protocol(to_client, types, set->client_packet_map, set->client_name_map, is_je, settings); - make_simple_protocol(to_server, types, set->server_packet_map, set->server_name_map, is_je, settings); - - return set; -} - -gchar *get_packet_name(protocol_entry entry) { - return entry == NULL ? "Unknown" : entry->name; -} - -gint get_packet_id_by_entry(protocol_entry entry) { - return entry == NULL ? -1 : (int) entry->id; -} - -gint get_packet_id(protocol_set set, gchar *name, bool is_client) { - wmem_map_t *name_map = is_client ? set->client_name_map : set->server_name_map; - return GPOINTER_TO_INT(wmem_map_lookup(name_map, name)) - 1; -} - -protocol_entry get_protocol_entry(protocol_set set, guint packet_id, bool is_client) { - wmem_map_t *packet_map = is_client ? set->client_packet_map : set->server_packet_map; - return wmem_map_lookup(packet_map, GUINT_TO_POINTER(packet_id)); -} - -bool make_tree(protocol_entry entry, proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb, wmem_map_t *extra, - gint remaining) { - if (entry->field != NULL) { - data_recorder recorder = create_data_recorder(pinfo->pool); - guint len = entry->field->make_tree( - tree, pinfo, tvb, extra, entry->field, 1, remaining - 1, recorder, - entry->is_je - ); - if (len != remaining - 1) - proto_tree_add_string_format_value( - tree, hf_invalid_data, tvb, 1, remaining - 1, - "length mismatch", "Packet length mismatch, expected %d, got %d", len, - remaining - 1 - ); - return true; - } - return false; -} \ No newline at end of file diff --git a/protocol/schema/protocol_schema.h b/protocol/schema/protocol_schema.h deleted file mode 100644 index 9623da5..0000000 --- a/protocol/schema/protocol_schema.h +++ /dev/null @@ -1,43 +0,0 @@ -// -// Created by Nickid2018 on 2023/7/13. -// - -#ifndef MC_DISSECTOR_PROTOCOL_SCHEMA_H -#define MC_DISSECTOR_PROTOCOL_SCHEMA_H - -#include -#include -#include "utils/data_recorder.h" - -typedef struct _protocol_set protocol_set_t, *protocol_set; -typedef struct _protocol_entry protocol_entry_t, *protocol_entry; -typedef struct _protocol_field protocol_field_t, *protocol_field; - -struct _protocol_field { - gchar *name; - wmem_map_t *additional_info; - - gint (*make_tree)(proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb, wmem_map_t *extra, protocol_field field, - gint offset, gint remaining, data_recorder recorder, bool is_je); -}; - -typedef struct { - bool nbt_any_type; -} protocol_settings; - -void init_schema_data(); - -protocol_set create_protocol_set(cJSON *types, cJSON *data, bool is_je, protocol_settings settings); - -gchar *get_packet_name(protocol_entry entry); - -gint get_packet_id_by_entry(protocol_entry entry); - -gint get_packet_id(protocol_set set, gchar *name, bool is_client); - -protocol_entry get_protocol_entry(protocol_set set, guint packet_id, bool is_client); - -bool -make_tree(protocol_entry entry, proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb, wmem_map_t *extra, gint remaining); - -#endif //MC_DISSECTOR_PROTOCOL_SCHEMA_H diff --git a/protocol/new_schema/schema.c b/protocol/schema/schema.c similarity index 73% rename from protocol/new_schema/schema.c rename to protocol/schema/schema.c index 9b5186f..a74448b 100644 --- a/protocol/new_schema/schema.c +++ b/protocol/schema/schema.c @@ -5,6 +5,7 @@ #include "schema.h" #include "protocol/protocol_data.h" #include "utils/nbt.h" +#include "functions.h" #include extern int hf_int8; @@ -34,24 +35,7 @@ extern int proto_mcje; extern int hf_invalid_data; extern bool pref_do_nbt_decode; - -#define DISSECT_FUNCTION_SIG(name) int32_t (*name)(proto_tree *,packet_info *,tvbuff_t *,int,protocol_dissector *,gchar *,wmem_map_t *,gchar **) - -struct protocol_dissector_struct { - wmem_map_t *dissect_arguments; - - DISSECT_FUNCTION_SIG(dissect_protocol); - - void (*destroy)(wmem_map_t *dissect_arguments); -}; - -struct protocol_dissector_set_struct { - wmem_map_t *dissectors_by_name; - wmem_map_t *dissectors_by_state; - wmem_map_t *count_by_state; - wmem_map_t *registry_keys; - wmem_map_t *readable_names; -}; +extern gchar *pref_protocol_data_dir; gboolean destroy_dissector(gpointer key _U_, gpointer value, gpointer user_data _U_) { protocol_dissector *dissector = value; @@ -88,8 +72,6 @@ int32_t dissect_##fn( \ #define DESTROY_DISSECTOR(fn) void destroy_##fn(wmem_map_t *dissect_arguments) -#define DISSECT_ERROR (1 << 31) - // SMALL UTILITY FUNCTIONS --------------------------------------------------------------------------------------------- void add_name(proto_item *item, gchar *name) { @@ -104,12 +86,6 @@ int32_t add_invalid_data(proto_tree *tree, tvbuff_t *tvb, int offset, gchar *nam return DISSECT_ERROR; } -wmem_map_t *get_global_data(packet_info *pinfo) { - conversation_t *conv = find_or_create_conversation(pinfo); - mc_protocol_context *ctx = conversation_get_proto_data(conv, proto_mcje); - return ctx->global_data; -} - // INTEGER SUB-DISSECTORS ---------------------------------------------------------------------------------------------- DISSECT_PROTOCOL(i8) { @@ -334,6 +310,10 @@ DISSECT_PROTOCOL(error) { ); } +DESTROY_DISSECTOR(error) { + g_free(wmem_map_remove(dissect_arguments, "e")); +} + typedef struct name_and_dissector_struct { gchar *name; protocol_dissector *dissector; @@ -575,7 +555,8 @@ DISSECT_PROTOCOL(registry) { int32_t len = read_var_int(tvb, offset, &index); gchar *key = get_registry_data(protocol_version, registry_name, index); if (value) *value = g_strdup(key); - if (tree) add_name(proto_tree_add_string(tree, hf_string, tvb, offset, len, key), name); + if (tree) + add_name(proto_tree_add_string_format(tree, hf_string, tvb, offset, len, key, "%s (%d)", key, index), name); return len; } @@ -583,10 +564,71 @@ DESTROY_DISSECTOR(registry) { g_free(wmem_map_remove(dissect_arguments, "n")); } +DISSECT_PROTOCOL(codec) { + protocol_dissector **list = wmem_map_lookup(dissector->dissect_arguments, "d"); + uint64_t count = (uint64_t) wmem_map_lookup(dissector->dissect_arguments, "c"); + gchar *registry_name = wmem_map_lookup(dissector->dissect_arguments, "n"); + uint32_t protocol_version = (uint64_t) wmem_map_lookup(get_global_data(pinfo), "protocol_version"); + int32_t index; + int32_t len = read_var_int(tvb, offset, &index); + if (index >= count) return DISSECT_ERROR; + gchar *key = get_registry_data(protocol_version, registry_name, index); + if (value) *value = g_strdup(key); + if (tree) + add_name(proto_tree_add_string_format(tree, hf_string, tvb, offset, len, key, "%s (%d)", key, index), name); + protocol_dissector *sub = list[index]; + int32_t sub_len = sub->dissect_protocol( + tree, pinfo, tvb, offset + len, sub, g_strdup_printf("%s Codec", registry_name), packet_saves, NULL + ); + if (sub_len == DISSECT_ERROR) return DISSECT_ERROR; + return len + sub_len; +} + +DESTROY_DISSECTOR(codec) { + wmem_free(wmem_epan_scope(), wmem_map_remove(dissect_arguments, "d")); + g_free(wmem_map_remove(dissect_arguments, "n")); +} + +DISSECT_PROTOCOL(top_bit_set_terminated_array) { + uint8_t now; + int32_t len = 0; + protocol_dissector *sub_dissector = wmem_map_lookup(dissector->dissect_arguments, "d"); + if (tree) tree = proto_tree_add_subtree(tree, tvb, offset, 0, ett_mc, NULL, name); + while (((now = tvb_get_uint8(tvb, offset + len)) & 0x80) != 0) { + uint32_t ord = now & 0x7F; + int32_t sub_len = sub_dissector->dissect_protocol( + tree, pinfo, tvb, offset + len, sub_dissector, g_strdup_printf("%s[%d]", name, ord), packet_saves, NULL + ); + if (sub_len == DISSECT_ERROR) return DISSECT_ERROR; + len += sub_len; + } + if (tree) proto_item_set_len(tree, len + 1); + return len + 1; +} + +DISSECT_PROTOCOL(entity_metadata_loop) { + uint8_t end_val = (uint64_t) wmem_map_lookup(dissector->dissect_arguments, "e"); + protocol_dissector *sub_dissector = wmem_map_lookup(dissector->dissect_arguments, "d"); + if (tree) tree = proto_tree_add_subtree(tree, tvb, offset, 0, ett_mc, NULL, name); + int32_t len = 0; + int ord = 0; + while (tvb_get_uint8(tvb, offset + len) != end_val) { + int32_t sub_len = sub_dissector->dissect_protocol( + tree, pinfo, tvb, offset + len, sub_dissector, g_strdup_printf("%s[%d]", name, ord), packet_saves, NULL + ); + if (sub_len == DISSECT_ERROR) return DISSECT_ERROR; + len += sub_len; + ord++; + } + if (tree) proto_item_set_len(tree, len + 1); + return len + 1; +} + // PARSING PROTOCOL SCHEMA --------------------------------------------------------------------------------------------- protocol_dissector *make_protocol_dissector( - cJSON *root, wmem_map_t *dissectors, protocol_dissector *recursive_root, bool put_dissectors + cJSON *root, wmem_map_t *dissectors, uint32_t protocol_version, protocol_dissector *recursive_root, + bool put_dissectors ); // PARSERS ------------------------------------------------------------------------------------------------------------- @@ -595,6 +637,7 @@ protocol_dissector *make_void() { protocol_dissector *simple_dissector = wmem_alloc(wmem_epan_scope(), sizeof(protocol_dissector)); simple_dissector->dissect_arguments = NULL; simple_dissector->dissect_protocol = dissect_void; + simple_dissector->destroy = NULL; return simple_dissector; } @@ -603,6 +646,7 @@ protocol_dissector *make_error(gchar *error_message) { error_dissector->dissect_arguments = wmem_map_new(wmem_epan_scope(), g_str_hash, g_str_equal); wmem_map_insert(error_dissector->dissect_arguments, "e", error_message); error_dissector->dissect_protocol = dissect_error; + error_dissector->destroy = destroy_error; return error_dissector; } @@ -617,15 +661,16 @@ protocol_dissector *make_simple(DISSECT_FUNCTION_SIG(func)) { protocol_dissector *simple_dissector = wmem_alloc(wmem_epan_scope(), sizeof(protocol_dissector)); simple_dissector->dissect_arguments = NULL; simple_dissector->dissect_protocol = func; + simple_dissector->destroy = NULL; return simple_dissector; } #define COMPOSITE_PROTOCOL_DEFINE(fn) \ -protocol_dissector *make_##fn(cJSON *params, wmem_map_t *dissectors, protocol_dissector *recursive_root) +protocol_dissector *make_##fn(cJSON *params, wmem_map_t *dissectors, uint32_t protocol_version, protocol_dissector *recursive_root) #define COMPOSITE_PROTOCOL(name, count) \ if (strcmp(type, #name) == 0 && args == count && composite_type) { \ - if (!put_dissectors) return make_##name(root, dissectors, recursive_root); \ - return wmem_map_insert(dissectors, g_uuid_string_random(), make_##name(root, dissectors, recursive_root)); \ + if (!put_dissectors) return make_##name(root, dissectors, protocol_version, recursive_root); \ + return wmem_map_insert(dissectors, g_uuid_string_random(), make_##name(root, dissectors, protocol_version, recursive_root)); \ } #define RECURSIVE_ROOT recursive_root == NULL ? this_dissector : recursive_root @@ -644,7 +689,9 @@ COMPOSITE_PROTOCOL_DEFINE(container) { gchar *name = g_strdup(name_node->valuestring); cJSON *type = cJSON_GetObjectItem(node, "type"); if (type == NULL) return make_error("Lack of type for container object"); - protocol_dissector *sub_dissector = make_protocol_dissector(type, dissectors, RECURSIVE_ROOT, true); + protocol_dissector *sub_dissector = make_protocol_dissector( + type, dissectors, protocol_version, RECURSIVE_ROOT, true + ); name_and_dissector *data = wmem_alloc(wmem_epan_scope(), sizeof(name_and_dissector)); data->name = name; data->dissector = sub_dissector; @@ -669,10 +716,14 @@ COMPOSITE_PROTOCOL_DEFINE(array) { if (count == NULL && count_type == NULL) return make_error("Lack of count/countType for array object"); protocol_dissector *this_dissector = wmem_alloc(wmem_epan_scope(), sizeof(protocol_dissector)); this_dissector->dissect_arguments = wmem_map_new(wmem_epan_scope(), g_str_hash, g_str_equal); - protocol_dissector *sub_dissector = make_protocol_dissector(type, dissectors, RECURSIVE_ROOT, true); + protocol_dissector *sub_dissector = make_protocol_dissector( + type, dissectors, protocol_version, RECURSIVE_ROOT, true + ); wmem_map_insert(this_dissector->dissect_arguments, "d", sub_dissector); if (count_type != NULL) { - protocol_dissector *count_type_dissect = make_protocol_dissector(count_type, dissectors, RECURSIVE_ROOT, true); + protocol_dissector *count_type_dissect = make_protocol_dissector( + count_type, dissectors, protocol_version, RECURSIVE_ROOT, true + ); wmem_map_insert(this_dissector->dissect_arguments, "c", count_type_dissect); } else { bool is_string = cJSON_IsString(count); @@ -693,7 +744,9 @@ COMPOSITE_PROTOCOL_DEFINE(option) { cJSON *type = cJSON_GetArrayItem(params, 1); protocol_dissector *this_dissector = wmem_alloc(wmem_epan_scope(), sizeof(protocol_dissector)); this_dissector->dissect_arguments = wmem_map_new(wmem_epan_scope(), g_str_hash, g_str_equal); - protocol_dissector *sub_dissector = make_protocol_dissector(type, dissectors, RECURSIVE_ROOT, true); + protocol_dissector *sub_dissector = make_protocol_dissector( + type, dissectors, protocol_version, RECURSIVE_ROOT, true + ); wmem_map_insert(this_dissector->dissect_arguments, "d", sub_dissector); this_dissector->dissect_protocol = dissect_option; return this_dissector; @@ -719,7 +772,9 @@ COMPOSITE_PROTOCOL_DEFINE(mapper) { } protocol_dissector *this_dissector = wmem_alloc(wmem_epan_scope(), sizeof(protocol_dissector)); this_dissector->dissect_arguments = wmem_map_new(wmem_epan_scope(), g_str_hash, g_str_equal); - protocol_dissector *sub_dissector = make_protocol_dissector(type, dissectors, RECURSIVE_ROOT, true); + protocol_dissector *sub_dissector = make_protocol_dissector( + type, dissectors, protocol_version, RECURSIVE_ROOT, true + ); wmem_map_insert(this_dissector->dissect_arguments, "d", sub_dissector); wmem_map_insert(this_dissector->dissect_arguments, "m", map); this_dissector->dissect_protocol = dissect_mapper; @@ -741,7 +796,9 @@ COMPOSITE_PROTOCOL_DEFINE(switch) { wmem_map_t *map = wmem_map_new(wmem_epan_scope(), g_str_hash, g_str_equal); cJSON *node = fields->child; while (node != NULL) { - protocol_dissector *sub_dissector = make_protocol_dissector(node, dissectors, RECURSIVE_ROOT, true); + protocol_dissector *sub_dissector = make_protocol_dissector( + node, dissectors, protocol_version, RECURSIVE_ROOT, true + ); wmem_map_insert(map, g_strdup(node->string), sub_dissector); } this_dissector->dissect_arguments = wmem_map_new(wmem_epan_scope(), g_str_hash, g_str_equal); @@ -749,7 +806,9 @@ COMPOSITE_PROTOCOL_DEFINE(switch) { wmem_map_insert(this_dissector->dissect_arguments, "m", map); if (cJSON_HasObjectItem(object, "default")) { cJSON *def = cJSON_GetObjectItem(node, "default"); - protocol_dissector *sub_dissector = make_protocol_dissector(def, dissectors, RECURSIVE_ROOT, true); + protocol_dissector *sub_dissector = make_protocol_dissector( + def, dissectors, protocol_version, RECURSIVE_ROOT, true + ); wmem_map_insert(this_dissector->dissect_arguments, "d", sub_dissector); } this_dissector->dissect_protocol = dissect_switch; @@ -803,7 +862,9 @@ COMPOSITE_PROTOCOL_DEFINE(save) { gchar *name = g_strdup(name_node->valuestring); protocol_dissector *this_dissector = wmem_alloc(wmem_epan_scope(), sizeof(protocol_dissector)); this_dissector->dissect_arguments = wmem_map_new(wmem_epan_scope(), g_str_hash, g_str_equal); - protocol_dissector *sub_dissector = make_protocol_dissector(type, dissectors, RECURSIVE_ROOT, true); + protocol_dissector *sub_dissector = make_protocol_dissector( + type, dissectors, protocol_version, RECURSIVE_ROOT, true + ); wmem_map_insert(this_dissector->dissect_arguments, "d", sub_dissector); wmem_map_insert(this_dissector->dissect_arguments, "s", name); this_dissector->dissect_protocol = dissect_save; @@ -819,7 +880,9 @@ COMPOSITE_PROTOCOL_DEFINE(global_save) { gchar *name = g_strdup(name_node->valuestring); protocol_dissector *this_dissector = wmem_alloc(wmem_epan_scope(), sizeof(protocol_dissector)); this_dissector->dissect_arguments = wmem_map_new(wmem_epan_scope(), g_str_hash, g_str_equal); - protocol_dissector *sub_dissector = make_protocol_dissector(type, dissectors, RECURSIVE_ROOT, true); + protocol_dissector *sub_dissector = make_protocol_dissector( + type, dissectors, protocol_version, RECURSIVE_ROOT, true + ); wmem_map_insert(this_dissector->dissect_arguments, "d", sub_dissector); wmem_map_insert(this_dissector->dissect_arguments, "s", name); this_dissector->dissect_protocol = dissect_global_save; @@ -840,11 +903,167 @@ COMPOSITE_PROTOCOL_DEFINE(registry) { return this_dissector; } +// NOLINTNEXTLINE +COMPOSITE_PROTOCOL_DEFINE(reference) { + cJSON *ref_node = cJSON_GetArrayItem(params, 1); + if (!cJSON_IsString(ref_node)) return make_error("Reference param needs to be a string"); + gchar *ref = ref_node->valuestring; + + if (!wmem_map_contains(dissectors, ref)) { + gchar *file = build_indexed_file_name("java_edition/structure", ref, protocol_version); + + gchar *content = NULL; + if (!g_file_get_contents(file, &content, NULL, NULL)) { + ws_log("MC-Dissector", LOG_LEVEL_WARNING, "Cannot read file %s", file); + g_free(file); + return make_error("Cannot read referenced file"); + } + + cJSON *json = cJSON_Parse(content); + g_free(content); + if (json == NULL) { + const gchar *error = cJSON_GetErrorPtr(); + ws_log("MC-Dissector", LOG_LEVEL_WARNING, "Cannot parse file %s: %s", file, error); + g_free(file); + return make_error(g_strdup_printf("Cannot parse referenced file: %s", error)); + } + g_free(file); + + protocol_dissector *dissector = make_protocol_dissector(json, dissectors, protocol_version, NULL, false); + return wmem_map_insert(dissectors, g_strdup(ref), dissector); + } else { + return wmem_map_lookup(dissectors, ref); + } +} + +// NOLINTNEXTLINE +COMPOSITE_PROTOCOL_DEFINE(codec) { + cJSON *ref_node = cJSON_GetArrayItem(params, 1); + if (!cJSON_IsString(ref_node)) return make_error("Codec param needs to be a string"); + gchar *ref = ref_node->valuestring; + + if (!wmem_map_contains(dissectors, ref)) { + gchar *file = build_indexed_file_name("java_edition/codec", ref, protocol_version); + + gchar *content = NULL; + if (!g_file_get_contents(file, &content, NULL, NULL)) { + ws_log("MC-Dissector", LOG_LEVEL_WARNING, "Cannot read file %s", file); + g_free(file); + return make_error("Cannot read codec file"); + } + + cJSON *json = cJSON_Parse(content); + g_free(content); + if (json == NULL) { + const gchar *error = cJSON_GetErrorPtr(); + ws_log("MC-Dissector", LOG_LEVEL_WARNING, "Cannot parse file %s: %s", file, error); + g_free(file); + return make_error(g_strdup_printf("Cannot parse codec file: %s", error)); + } + g_free(file); + + if (!cJSON_IsArray(json)) { + cJSON_free(json); + return make_error("Codec file is not an array"); + } + + int count = cJSON_GetArraySize(json); + protocol_dissector **dissector_list = wmem_alloc(wmem_epan_scope(), sizeof(protocol_dissector *) * count); + for (int i = 0; i < count; i++) { + cJSON *dissector_root = cJSON_GetArrayItem(json, i); + protocol_dissector *sub = make_protocol_dissector(dissector_root, dissectors, protocol_version, NULL, true); + dissector_list[i] = sub; + } + cJSON_free(json); + + protocol_dissector *this_dissector = wmem_alloc(wmem_epan_scope(), sizeof(protocol_dissector)); + this_dissector->dissect_arguments = wmem_map_new(wmem_epan_scope(), g_str_hash, g_str_equal); + wmem_map_insert(this_dissector->dissect_arguments, "d", dissector_list); + wmem_map_insert(this_dissector->dissect_arguments, "n", g_strdup(ref)); + wmem_map_insert(this_dissector->dissect_arguments, "c", (void *) (uint64_t) count); + this_dissector->dissect_protocol = dissect_registry; + this_dissector->destroy = destroy_registry; + return wmem_map_insert(dissectors, ref, this_dissector); + } else { + return wmem_map_lookup(dissectors, ref); + } +} + +#define FUNC_PROTOCOL(name, func) if (strcmp(ref, #name) == 0) this_dissector->dissect_protocol = func; + +// NOLINTNEXTLINE +COMPOSITE_PROTOCOL_DEFINE(func) { + cJSON *ref_node = cJSON_GetArrayItem(params, 1); + if (!cJSON_IsString(ref_node)) return make_error("Func name needs to be a string"); + gchar *ref = ref_node->valuestring; + + protocol_dissector *this_dissector = wmem_alloc(wmem_epan_scope(), sizeof(protocol_dissector)); + this_dissector->dissect_arguments = wmem_map_new(wmem_epan_scope(), g_direct_hash, g_direct_equal); + this_dissector->dissect_protocol = NULL; + this_dissector->destroy = NULL; + + FUNC_PROTOCOL(sync_entity_data, dissect_sync_entity_data) + FUNC_PROTOCOL(record_entity_id, dissect_record_entity_id) + FUNC_PROTOCOL(record_entity_id_player, dissect_record_entity_id_player) + FUNC_PROTOCOL(record_entity_id_experience_orb, dissect_record_entity_id_experience_orb) + FUNC_PROTOCOL(record_entity_id_painting, dissect_record_entity_id_painting) + + if (this_dissector->dissect_protocol == NULL) { + wmem_free(wmem_epan_scope(), this_dissector); + return make_error("Unknown func type"); + } + + int count = cJSON_GetArraySize(params); + for (int i = 2; i < count; i++) { + cJSON *node = cJSON_GetArrayItem(params, i); + if (!cJSON_IsString(node)) return make_error("Invalid func parameter"); + wmem_map_insert(this_dissector->dissect_arguments, (void *) (uint64_t) (i - 2), g_strdup(node->valuestring)); + } + + return this_dissector; +} + +// NOLINTNEXTLINE +COMPOSITE_PROTOCOL_DEFINE(top_bit_set_terminated_array) { + cJSON *object = cJSON_GetArrayItem(params, 1); + if (!cJSON_IsObject(object)) return make_error("top_bit_set_terminated_array param needs to be a object"); + cJSON *type = cJSON_GetObjectItem(object, "type"); + if (type == NULL) return make_error("Lack of type for top_bit_set_terminated_array object"); + protocol_dissector *this_dissector = wmem_alloc(wmem_epan_scope(), sizeof(protocol_dissector)); + this_dissector->dissect_arguments = wmem_map_new(wmem_epan_scope(), g_str_hash, g_str_equal); + protocol_dissector *sub = make_protocol_dissector(type, dissectors, protocol_version, RECURSIVE_ROOT, true); + wmem_map_insert(this_dissector->dissect_arguments, "d", sub); + this_dissector->dissect_protocol = dissect_top_bit_set_terminated_array; + this_dissector->destroy = NULL; + return this_dissector; +} + +// NOLINTNEXTLINE +COMPOSITE_PROTOCOL_DEFINE(entity_metadata_loop) { + cJSON *object = cJSON_GetArrayItem(params, 1); + if (!cJSON_IsObject(object)) return make_error("entity_metadata_loop param needs to be a object"); + cJSON *type = cJSON_GetObjectItem(object, "type"); + if (type == NULL) return make_error("Lack of type for entity_metadata_loop object"); + cJSON *end_val = cJSON_GetObjectItem(object, "endVal"); + if (end_val == NULL) return make_error("Lack of endVal for entity_metadata_loop object"); + if (!cJSON_IsNumber(end_val)) return make_error("Invalid endVal for entity_metadata_loop object"); + uint8_t end = (uint8_t) end_val->valuedouble; + protocol_dissector *this_dissector = wmem_alloc(wmem_epan_scope(), sizeof(protocol_dissector)); + this_dissector->dissect_arguments = wmem_map_new(wmem_epan_scope(), g_str_hash, g_str_equal); + protocol_dissector *sub = make_protocol_dissector(type, dissectors, protocol_version, RECURSIVE_ROOT, true); + wmem_map_insert(this_dissector->dissect_arguments, "d", sub); + wmem_map_insert(this_dissector->dissect_arguments, "e", (void *) (uint64_t) end); + this_dissector->dissect_protocol = dissect_entity_metadata_loop; + this_dissector->destroy = NULL; + return this_dissector; +} + // PROTOCOL PARSER ----------------------------------------------------------------------------------------------------- // NOLINTNEXTLINE protocol_dissector *make_protocol_dissector( - cJSON *root, wmem_map_t *dissectors, protocol_dissector *recursive_root, bool put_dissectors + cJSON *root, wmem_map_t *dissectors, uint32_t protocol_version, protocol_dissector *recursive_root, + bool put_dissectors ) { bool composite_type = cJSON_IsArray(root); if (!composite_type && !cJSON_IsString(root)) return make_error("Invalid protocol dissector type"); @@ -886,8 +1105,15 @@ protocol_dissector *make_protocol_dissector( COMPOSITE_PROTOCOL(global_save, 2) COMPOSITE_PROTOCOL(registry, 1) + if (strcmp(type, "reference") == 0 && composite_type && args == 1) + return make_reference(root, dissectors, protocol_version, recursive_root); + if (strcmp(type, "codec") == 0 && composite_type && args == 1) + return make_codec(root, dissectors, protocol_version, recursive_root); + if (strcmp(type, "func") == 0 && composite_type) + return make_func(root, dissectors, protocol_version, recursive_root); + return make_error( - g_strdup_printf("Invalid protocol dissector type: %s%s", type, composite_type ? "(composite)" : "") + g_strdup_printf("Invalid protocol dissector type: %s%s", type, composite_type ? " (composite)" : "") ); } @@ -896,10 +1122,16 @@ void make_state_protocol(cJSON *root, protocol_dissector_set *set, uint32_t stat protocol_dissector **dissectors = wmem_alloc(wmem_epan_scope(), sizeof(protocol_dissector *) * count); gchar **keys = wmem_alloc(wmem_epan_scope(), sizeof(gchar *) * count); gchar **names = wmem_alloc(wmem_epan_scope(), sizeof(gchar *) * count); + wmem_map_t *state_switch = wmem_map_new(wmem_epan_scope(), g_direct_hash, g_direct_equal); + wmem_map_t *state_side = wmem_map_new(wmem_epan_scope(), g_direct_hash, g_direct_equal); + wmem_map_t *special_mark = wmem_map_new(wmem_epan_scope(), g_direct_hash, g_direct_equal); wmem_map_insert(set->dissectors_by_state, (void *) (uint64_t) state, dissectors); wmem_map_insert(set->count_by_state, (void *) (uint64_t) state, (void *) (uint64_t) count); wmem_map_insert(set->registry_keys, (void *) (uint64_t) state, keys); wmem_map_insert(set->readable_names, (void *) (uint64_t) state, names); + wmem_map_insert(set->state_to_next, (void *) (uint64_t) state, state_switch); + wmem_map_insert(set->state_to_next_side, (void *) (uint64_t) state, state_side); + wmem_map_insert(set->special_mark, (void *) (uint64_t) state, special_mark); protocol_dissector *void_dissector; if (wmem_map_contains(set->dissectors_by_name, "void")) @@ -918,18 +1150,43 @@ void make_state_protocol(cJSON *root, protocol_dissector_set *set, uint32_t stat gchar *key = cJSON_GetObjectItem(dissector_data, "key")->valuestring; gchar *name = cJSON_GetObjectItem(dissector_data, "name")->valuestring; cJSON *type = cJSON_GetObjectItem(dissector_data, "type"); - protocol_dissector *dissector = make_protocol_dissector(type, set->dissectors_by_name, NULL, true); + protocol_dissector *dissector = make_protocol_dissector( + type, set->dissectors_by_name, set->protocol_version, NULL, true + ); dissectors[i] = dissector; keys[i] = key; names[i] = name; + if (cJSON_HasObjectItem(dissector_data, "stateNext")) { + cJSON *state_to_next = cJSON_GetObjectItem(dissector_data, "stateNext"); + if (!cJSON_IsString(state_to_next)) continue; + uint32_t next_state = map_name_to_state(state_to_next->valuestring) & 0xF; + if (next_state == ~0u) continue; + wmem_map_insert(state_switch, (void *) (uint64_t) i, (void *) (uint64_t) next_state); + cJSON *state_side_node = cJSON_GetObjectItem(dissector_data, "stateSide"); + if (!cJSON_IsString(state_side_node)) continue; + gchar *side = state_side_node->valuestring; + uint32_t side_int = 0; + if (strcmp(side, "client") == 0) side_int = 1; + if (strcmp(side, "server") == 0) side_int = 2; + if (strcmp(side, "all") == 0) side_int = 3; + wmem_map_insert(state_side, (void *) (uint64_t) i, (void *) (uint64_t) side_int); + } + if (cJSON_HasObjectItem(dissector_data, "specialMark")) { + cJSON *mark = cJSON_GetObjectItem(dissector_data, "specialMark"); + if (!cJSON_IsString(mark)) continue; + wmem_map_insert(special_mark, (void *) (uint64_t) i, g_strdup(mark->valuestring)); + } } } uint32_t map_name_to_state(gchar *name) { + if (strcmp(name, "play") == 0) return PLAY; if (strcmp(name, "play_client") == 0) return PLAY; if (strcmp(name, "play_server") == 0) return 16 + PLAY; + if (strcmp(name, "login") == 0) return LOGIN; if (strcmp(name, "login_client") == 0) return LOGIN; if (strcmp(name, "login_server") == 0) return 16 + LOGIN; + if (strcmp(name, "configuration") == 0) return CONFIGURATION; if (strcmp(name, "configuration_client") == 0) return CONFIGURATION; if (strcmp(name, "configuration_server") == 0) return 16 + CONFIGURATION; return ~0u; @@ -937,11 +1194,15 @@ uint32_t map_name_to_state(gchar *name) { protocol_dissector_set *create_protocol(uint32_t protocol_version) { protocol_dissector_set *set = wmem_alloc(wmem_epan_scope(), sizeof(protocol_dissector_set)); + set->protocol_version = protocol_version; set->dissectors_by_name = wmem_map_new(wmem_epan_scope(), g_str_hash, g_str_equal); set->dissectors_by_state = wmem_map_new(wmem_epan_scope(), g_direct_hash, g_direct_equal); set->count_by_state = wmem_map_new(wmem_epan_scope(), g_direct_hash, g_direct_equal); set->registry_keys = wmem_map_new(wmem_epan_scope(), g_direct_hash, g_direct_equal); set->readable_names = wmem_map_new(wmem_epan_scope(), g_direct_hash, g_direct_equal); + set->state_to_next = wmem_map_new(wmem_epan_scope(), g_direct_hash, g_direct_equal); + set->state_to_next_side = wmem_map_new(wmem_epan_scope(), g_direct_hash, g_direct_equal); + set->special_mark = wmem_map_new(wmem_epan_scope(), g_direct_hash, g_direct_equal); cJSON *protocol_source = get_protocol_source(protocol_version); cJSON *now = protocol_source->child; while (now != NULL) { diff --git a/protocol/schema/schema.h b/protocol/schema/schema.h new file mode 100644 index 0000000..d2f4991 --- /dev/null +++ b/protocol/schema/schema.h @@ -0,0 +1,44 @@ +// +// Created by nickid2018 on 24-9-14. +// + +#ifndef MC_DISSECTOR_SCHEMA_H +#define MC_DISSECTOR_SCHEMA_H + +#include +#include + +typedef struct protocol_dissector_struct protocol_dissector; +typedef struct protocol_dissector_set_struct protocol_dissector_set; + +#define DISSECT_FUNCTION_SIG(name) int32_t (*name)(proto_tree *,packet_info *,tvbuff_t *,int,protocol_dissector *,gchar *,wmem_map_t *,gchar **) + +struct protocol_dissector_struct { + wmem_map_t *dissect_arguments; + + DISSECT_FUNCTION_SIG(dissect_protocol); + + void (*destroy)(wmem_map_t *dissect_arguments); +}; + +struct protocol_dissector_set_struct { + uint32_t protocol_version; + wmem_map_t *state_to_next; + wmem_map_t *state_to_next_side; + wmem_map_t *special_mark; + wmem_map_t *dissectors_by_name; + wmem_map_t *dissectors_by_state; + wmem_map_t *count_by_state; + wmem_map_t *registry_keys; + wmem_map_t *readable_names; +}; + +#define DISSECT_ERROR (1 << 31) + +uint32_t map_name_to_state(gchar *name); + +protocol_dissector_set *create_protocol(uint32_t protocol_version); + +void destroy_protocol(protocol_dissector_set *dissector_set); + +#endif //MC_DISSECTOR_SCHEMA_H diff --git a/protocol/storage/storage.c b/protocol/storage/storage.c index b2729b1..136f4bd 100644 --- a/protocol/storage/storage.c +++ b/protocol/storage/storage.c @@ -3,8 +3,7 @@ // #include "storage.h" -#include "mc_dissector.h" -#include "protocol/new_schema/schema.h" +#include "protocol/schema/schema.h" extern gchar *pref_protocol_data_dir; @@ -17,6 +16,8 @@ void ensure_cached_##name() { \ if (g_file_get_contents(file, &content, NULL, NULL)) { \ cached_##name = cJSON_Parse(content); \ g_free(content); \ + if (cached_##name == NULL) \ + ws_log("MC-Dissector", LOG_LEVEL_WARNING, "Cannot parse file %s: %s", file, cJSON_GetErrorPtr()); \ } else { \ ws_log("MC-Dissector", LOG_LEVEL_WARNING, "Cannot read file %s", file); \ } \ @@ -115,6 +116,18 @@ gchar *get_index(uint32_t protocol_version, gchar *item) { return wmem_map_lookup(version_index, item); } +gchar *build_indexed_file_name(gchar *root, gchar *item, uint32_t protocol_version) { + gchar *index = get_index(protocol_version, item); + gchar *file_name = g_strdup_printf("%s.json", item); + gchar *path; + if (index == NULL) + path = g_build_filename(pref_protocol_data_dir, root, item, file_name, NULL); + else + path = g_build_filename(pref_protocol_data_dir, root, item, index, file_name, NULL); + g_free(file_name); + return path; +} + gboolean clean_json(gpointer key _U_, gpointer value, gpointer user_data _U_) { cJSON_Delete(value); return true; @@ -131,7 +144,7 @@ void clear_storage() { CLEAR_CACHED_DATA(registry_data, clean_json) } -gchar **get_mapped_java_versions(guint protocol_version) { +gchar **get_mapped_java_versions(uint32_t protocol_version) { ensure_cached_versions(); GStrvBuilder *builder = g_strv_builder_new(); for (int i = 0; i < cJSON_GetArraySize(cached_versions); i++) { @@ -147,7 +160,7 @@ gchar **get_mapped_java_versions(guint protocol_version) { return g_strv_builder_end(builder); } -gint get_data_version(gchar *java_version) { +int32_t get_data_version(gchar *java_version) { ensure_cached_versions(); for (int i = 0; i < cJSON_GetArraySize(cached_versions); i++) { cJSON *item = cJSON_GetArrayItem(cached_versions, i); @@ -162,17 +175,6 @@ gint get_data_version(gchar *java_version) { return -1; } -gchar *get_readable_packet_name(bool to_client, gchar *packet_name) { - ensure_cached_packet_names(); - cJSON *found = cJSON_GetObjectItem( - cJSON_GetObjectItem(cached_packet_names, to_client ? "toClient" : "toServer"), - packet_name - ); - if (found == NULL) - return packet_name; - return found->valuestring; -} - cJSON *get_protocol_source(uint32_t protocol_version) { cJSON *cached = get_cached_protocol(protocol_version); if (cached != NULL) @@ -194,53 +196,14 @@ cJSON *get_protocol_source(uint32_t protocol_version) { cJSON *json = cJSON_Parse(content); g_free(content); + if (json == NULL) + ws_log("MC-Dissector", LOG_LEVEL_WARNING, "Cannot parse file %s: %s", file, cJSON_GetErrorPtr()); + g_free(file); return json; } -protocol_je_set get_protocol_set_je(guint protocol_version, protocol_settings settings) { - protocol_je_set cached = get_cached_protocol(protocol_version); - if (cached != NULL) - return cached; - - gchar *file = g_build_filename( - pref_protocol_data_dir, - "java_edition/indexed_data", -// found->valuestring, - "protocol.json", - NULL - ); - gchar *content = NULL; - if (!g_file_get_contents(file, &content, NULL, NULL)) { - ws_log("MC-Dissector", LOG_LEVEL_WARNING, "Cannot read file %s", file); - g_free(file); - return NULL; - } - - cJSON *json = cJSON_Parse(content); - g_free(content); - - cJSON *types = cJSON_GetObjectItem(json, "types"); - cJSON *login = cJSON_GetObjectItem(json, "login"); - cJSON *play = cJSON_GetObjectItem(json, "play"); - cJSON *config = cJSON_GetObjectItem(json, "configuration"); - - protocol_je_set result = wmem_new(wmem_epan_scope(), struct _protocol_je_set); - protocol_set login_set = create_protocol_set(types, login, true, settings); - protocol_set play_set = create_protocol_set(types, play, true, settings); - result->login = login_set; - result->play = play_set; - if (config != NULL) { - protocol_set config_set = create_protocol_set(types, config, true, settings); - result->configuration = config_set; - } - - cJSON_Delete(json); - set_cached_protocol(protocol_version, result); - return result; -} - -gchar *get_entity_sync_data_name(guint protocol_version, gchar *entity_id, guint index) { +gchar *get_entity_sync_data_name(uint32_t protocol_version, gchar *entity_id, uint32_t index) { cJSON *cached = get_cached_entity_sync_data(protocol_version); if (cached == NULL) { gchar *file = g_build_filename( @@ -257,9 +220,9 @@ gchar *get_entity_sync_data_name(guint protocol_version, gchar *entity_id, guint return NULL; } - g_free(file); cached = cJSON_Parse(content); g_free(content); + g_free(file); set_cached_entity_sync_data(protocol_version, cached); } @@ -269,7 +232,7 @@ gchar *get_entity_sync_data_name(guint protocol_version, gchar *entity_id, guint return data->valuestring; } -gchar *get_registry_data(guint protocol_version, gchar *registry, guint index) { +gchar *get_registry_data(uint32_t protocol_version, gchar *registry, uint32_t index) { gchar *cache_key = g_strdup_printf("%s/%d", registry, protocol_version); cJSON *cached = get_cached_registry_data(cache_key); if (cached == NULL) { @@ -302,64 +265,6 @@ gchar *get_registry_data(guint protocol_version, gchar *registry, guint index) { return data->valuestring; } -gchar *get_level_event_data(guint protocol_version, gchar *index) { - cJSON *cached = get_cached_level_event(protocol_version); - if (cached == NULL) { - gchar *file = g_build_filename( - pref_protocol_data_dir, - "java_edition/indexed_data", - get_index(protocol_version, "level_event"), - "level_event.json", - NULL - ); - gchar *content = NULL; - if (!g_file_get_contents(file, &content, NULL, NULL)) { - ws_log("MC-Dissector", LOG_LEVEL_WARNING, "Cannot read file %s", file); - g_free(file); - return NULL; - } - - g_free(file); - cached = cJSON_Parse(content); - g_free(content); - set_cached_level_event(protocol_version, cached); - } - - cJSON *data = cJSON_GetObjectItem(cached, index); - if (data == NULL) - return NULL; - return data->valuestring; -} - -gchar *get_entity_event_data(guint protocol_version, gchar *index) { - cJSON *cached = get_cached_entity_event(protocol_version); - if (cached == NULL) { - gchar *file = g_build_filename( - pref_protocol_data_dir, - "java_edition/indexed_data", - get_index(protocol_version, "entity_event"), - "entity_event.json", - NULL - ); - gchar *content = NULL; - if (!g_file_get_contents(file, &content, NULL, NULL)) { - ws_log("MC-Dissector", LOG_LEVEL_WARNING, "Cannot read file %s", file); - g_free(file); - return NULL; - } - - g_free(file); - cached = cJSON_Parse(content); - g_free(content); - set_cached_entity_event(protocol_version, cached); - } - - cJSON *data = cJSON_GetObjectItem(cached, index); - if (data == NULL) - return NULL; - return data->valuestring; -} - bool get_settings_flag(gchar *name) { ensure_cached_settings(); cJSON *flag = cJSON_GetObjectItem(cached_settings, name); diff --git a/protocol/storage/storage.h b/protocol/storage/storage.h index 741e5e7..b71e6d7 100644 --- a/protocol/storage/storage.h +++ b/protocol/storage/storage.h @@ -5,35 +5,24 @@ #ifndef MC_DISSECTOR_STORAGE_H #define MC_DISSECTOR_STORAGE_H -#include "protocol/schema/protocol_schema.h" - -typedef struct _protocol_je_set { - protocol_set login; - protocol_set play; - protocol_set configuration; -} *protocol_je_set; +#include "cJSON.h" +#include "mc_dissector.h" void clear_storage(); -gchar **get_mapped_java_versions(guint protocol_version); - -gint get_data_version(gchar *java_version); +gchar **get_mapped_java_versions(uint32_t protocol_version); -gchar *get_readable_packet_name(bool to_client, gchar *packet_name); +int32_t get_data_version(gchar *java_version); gchar *get_index(uint32_t protocol_version, gchar *item); -cJSON *get_protocol_source(uint32_t protocol_version); - -protocol_je_set get_protocol_set_je(guint protocol_version, protocol_settings settings); - -gchar *get_entity_sync_data_name(guint protocol_version, gchar *entity_id, guint index); +gchar *build_indexed_file_name(gchar *root, gchar *item, uint32_t protocol_version); -gchar *get_registry_data(guint protocol_version, gchar *registry, guint index); +cJSON *get_protocol_source(uint32_t protocol_version); -gchar *get_level_event_data(guint protocol_version, gchar *index); +gchar *get_entity_sync_data_name(uint32_t protocol_version, gchar *entity_id, uint32_t index); -gchar *get_entity_event_data(guint protocol_version, gchar *index); +gchar *get_registry_data(uint32_t protocol_version, gchar *registry, uint32_t index); bool get_settings_flag(gchar *name); diff --git a/protocol_je/je_dissect.c b/protocol_je/je_dissect.c index c8ecb3c..b24adf9 100644 --- a/protocol_je/je_dissect.c +++ b/protocol_je/je_dissect.c @@ -35,22 +35,12 @@ void sub_dissect_je(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, mc_fram return; case LOGIN: case TRANSFER: - if (!visited && is_invalid(handle_server_login_switch(tvb, ctx))) - return; - if (tree) - handle_login(tree, pinfo, tvb, ctx, false); - return; case PLAY: - if (!visited && is_invalid(handle_server_play_switch(tvb, ctx))) - return; - if (tree) - handle_play(tree, pinfo, tvb, ctx, false); - return; case CONFIGURATION: - if (!visited && is_invalid(handle_server_configuration_switch(tvb, ctx))) + if (!visited && is_invalid(try_switch_state(tvb, ctx, false))) return; if (tree) - handle_configuration(tree, pinfo, tvb, ctx, false); + handle_protocol(tree, pinfo, tvb, ctx, false); return; default: col_add_str(pinfo->cinfo, COL_INFO, "[Invalid State]"); @@ -64,22 +54,12 @@ void sub_dissect_je(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, mc_fram return; case LOGIN: case TRANSFER: - if (!visited && is_invalid(handle_client_login_switch(tvb, ctx))) - return; - if (tree) - handle_login(tree, pinfo, tvb, ctx, true); - return; case PLAY: - if (!visited && is_invalid(handle_client_play_switch(tvb, ctx))) - return; - if (tree) - handle_play(tree, pinfo, tvb, ctx, true); - return; case CONFIGURATION: - if (!visited && is_invalid(handle_client_configuration_switch(tvb, ctx))) + if (!visited && is_invalid(try_switch_state(tvb, ctx, true))) return; if (tree) - handle_configuration(tree, pinfo, tvb, ctx, true); + handle_protocol(tree, pinfo, tvb, ctx, true); return; default: col_add_str(pinfo->cinfo, COL_INFO, "[Invalid State]"); @@ -91,11 +71,10 @@ void sub_dissect_je(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, mc_fram void mark_invalid(packet_info *pinfo) { conversation_t *conv = find_or_create_conversation(pinfo); mc_protocol_context *ctx = conversation_get_proto_data(conv, proto_mcje); - ctx->client_state = INVALID; - ctx->server_state = INVALID; + ctx->client_state = ctx->server_state = INVALID; } -void dissect_je_core(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint offset, gint packet_len_len, gint len) { +void dissect_je_core(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int32_t offset, int32_t packet_len_len, int32_t len) { conversation_t *conv = find_or_create_conversation(pinfo); mc_protocol_context *ctx = conversation_get_proto_data(conv, proto_mcje); mc_frame_data *frame_data = p_get_proto_data(wmem_file_scope(), pinfo, proto_mcje, 0); @@ -113,7 +92,7 @@ void dissect_je_core(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint o tvbuff_t *new_tvb; if (frame_data->compression_threshold > 0) { - gint uncompressed_length; + int32_t uncompressed_length; int var_len = read_var_int(tvb, offset, &uncompressed_length); if (is_invalid(var_len)) { col_set_str(pinfo->cinfo, COL_INFO, "[Invalid] Invalid Compression VarInt"); @@ -192,15 +171,15 @@ int dissect_je_conv(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree _U_, voi if (frame_data->client_state == NOT_COMPATIBLE || frame_data->server_state == NOT_COMPATIBLE) { col_set_str(pinfo->cinfo, COL_INFO, "[Invalid] Protocol data is not compatible with the current plugin version"); - return (gint) tvb_captured_length(tvb); + return (int32_t) tvb_captured_length(tvb); } if (frame_data->client_state == INVALID || frame_data->server_state == INVALID) { col_set_str(pinfo->cinfo, COL_INFO, "[Invalid] Data may be corrupted or meet a capturing failure"); - return (gint) tvb_captured_length(tvb); + return (int32_t) tvb_captured_length(tvb); } if (frame_data->client_state == PROTOCOL_NOT_FOUND || frame_data->server_state == PROTOCOL_NOT_FOUND) { col_set_str(pinfo->cinfo, COL_INFO, "[Invalid] Protocol data is not found or invalid"); - return (gint) tvb_captured_length(tvb); + return (int32_t) tvb_captured_length(tvb); } bool is_server = addresses_equal(&pinfo->dst, &ctx->server_address) && pinfo->destport == ctx->server_port; @@ -211,22 +190,22 @@ int dissect_je_conv(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree _U_, voi tvbuff_t *use_tvb = tvb; if (frame_data->encrypted) { - guint length = tvb_reported_length_remaining(tvb, 0); - gint length_remaining = is_server ? ctx->server_last_segment_remaining : ctx->client_last_segment_remaining; + uint32_t length = tvb_reported_length_remaining(tvb, 0); + int32_t length_remaining = is_server ? ctx->server_last_segment_remaining : ctx->client_last_segment_remaining; gcry_cipher_hd_t *cipher = is_server ? &ctx->server_cipher : &ctx->client_cipher; - guint8 **decrypt_data = pinfo->curr_proto_layer_num == 1 ? &frame_data->decrypted_data_head : &frame_data->decrypted_data_tail; + uint8_t **decrypt_data = pinfo->curr_proto_layer_num == 1 ? &frame_data->decrypted_data_head : &frame_data->decrypted_data_tail; if (*cipher == NULL) { gchar *secret_key_str = pref_secret_key; if (strlen(secret_key_str) != 32) { col_set_str(pinfo->cinfo, COL_INFO, "[Invalid] Decryption Error: Secret key is not set"); mark_invalid(pinfo); - return (gint) tvb_captured_length(tvb); + return (int32_t) tvb_captured_length(tvb); } - guint8 secret_key[16]; + uint8_t secret_key[16]; for (int i = 0; i < 16; i++) { gchar hex[3] = {secret_key_str[i * 2], secret_key_str[i * 2 + 1], '\0'}; - secret_key[i] = (guint8) strtol(hex, NULL, 16); + secret_key[i] = (uint8_t) strtol(hex, NULL, 16); } gcry_cipher_open(cipher, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CFB8, 0); gcry_cipher_setkey(*cipher, secret_key, sizeof(secret_key)); @@ -234,7 +213,7 @@ int dissect_je_conv(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree _U_, voi } if (!*decrypt_data) { - guint8 *decrypt = wmem_alloc(pinfo->pool, length - length_remaining); + uint8_t *decrypt = wmem_alloc(pinfo->pool, length - length_remaining); gcry_error_t err = gcry_cipher_decrypt( *cipher, decrypt, length - length_remaining, @@ -245,26 +224,26 @@ int dissect_je_conv(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree _U_, voi col_set_str(pinfo->cinfo, COL_INFO, "[Invalid] Decryption Error: Decryption failed with code "); col_append_fstr(pinfo->cinfo, COL_INFO, "%d", err); mark_invalid(pinfo); - return (gint) tvb_captured_length(tvb); + return (int32_t) tvb_captured_length(tvb); } - guint8 *merged = wmem_alloc(wmem_file_scope(), length); + uint8_t *merged = wmem_alloc(wmem_file_scope(), length); memcpy(merged, is_server ? ctx->server_last_remains : ctx->client_last_remains, length_remaining); memcpy(merged + length_remaining, decrypt, length - length_remaining); *decrypt_data = merged; } - use_tvb = tvb_new_real_data(*decrypt_data, length, (gint) length); + use_tvb = tvb_new_real_data(*decrypt_data, length, (int32_t) length); add_new_data_source(pinfo, use_tvb, "Decrypted packet"); } - gint offset = 0; - gint packet_count = 0; + int32_t offset = 0; + int32_t packet_count = 0; while (offset < tvb_reported_length(use_tvb)) { - gint available = tvb_reported_length_remaining(use_tvb, offset); - gint len = 0; - gint packet_len_len = read_var_int_with_limit(use_tvb, offset, available, &len); + int32_t available = tvb_reported_length_remaining(use_tvb, offset); + int32_t len = 0; + int32_t packet_len_len = read_var_int_with_limit(use_tvb, offset, available, &len); if (packet_len_len == INVALID_DATA) { col_append_fstr(pinfo->cinfo, COL_INFO, "[%d packet(s)]", packet_count); @@ -314,5 +293,5 @@ int dissect_je_conv(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree _U_, voi } } col_append_fstr(pinfo->cinfo, COL_INFO, "[%d packet(s)]", packet_count); - return (gint) tvb_captured_length(tvb); + return (int32_t) tvb_captured_length(tvb); } \ No newline at end of file diff --git a/protocol_je/je_protocol.c b/protocol_je/je_protocol.c index 0121ae9..531caa9 100644 --- a/protocol_je/je_protocol.c +++ b/protocol_je/je_protocol.c @@ -57,10 +57,8 @@ int handle_server_handshake_switch(tvbuff_t *tvb, mc_protocol_context *ctx) { ctx->data_version = get_data_version(java_versions[0]); wmem_map_insert(ctx->global_data, "data_version", GUINT_TO_POINTER(ctx->data_version)); - ctx->protocol_set = get_protocol_set_je(protocol_version, (protocol_settings) { - ctx->data_version >= 3567 - }); - if (ctx->protocol_set == NULL) + ctx->dissector_set = create_protocol(protocol_version); + if (ctx->dissector_set == NULL) ctx->client_state = ctx->server_state = PROTOCOL_NOT_FOUND; return 0; } else if (packet_id == PACKET_ID_LEGACY_SERVER_LIST_PING) @@ -182,175 +180,84 @@ void handle_client_slp(proto_tree *packet_tree, packet_info *pinfo, tvbuff_t *tv proto_tree_add_string(packet_tree, hf_packet_name_je, tvb, 0, read, "Unknown Packet ID"); } -int handle_client_login_switch(tvbuff_t *tvb, mc_protocol_context *ctx) { - if (ctx->protocol_set == NULL) { +void handle_protocol(proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb, mc_protocol_context *ctx, bool is_client) { + if (ctx->dissector_set == NULL) { + proto_tree_add_string(tree, hf_invalid_data, tvb, 0, 1, "Can't find protocol set for this version"); ctx->client_state = ctx->server_state = PROTOCOL_NOT_FOUND; - return -1; - } - gint packet_id; - gint read; - gint p = read_var_int(tvb, 0, &packet_id); - if (is_invalid(p)) - return INVALID_DATA; - if (packet_id == PACKET_ID_CLIENT_SUCCESS) { - if (ctx->data_version >= 3567) - ctx->client_state = CONFIGURATION; - else - ctx->client_state = ctx->server_state = PLAY; - } - if (packet_id == PACKET_ID_CLIENT_COMPRESS) { - gint threshold; - read = read_var_int(tvb, p, &threshold); - if (is_invalid(read)) - return INVALID_DATA; - ctx->compression_threshold = threshold; - } - return 0; -} - -int handle_server_login_switch(tvbuff_t *tvb, mc_protocol_context *ctx) { - if (ctx->protocol_set == NULL) { - ctx->client_state = ctx->server_state = PROTOCOL_NOT_FOUND; - return -1; - } - gint packet_id; - gint p = read_var_int(tvb, 0, &packet_id); - if (is_invalid(p)) - return INVALID_DATA; - if (packet_id == get_packet_id(ctx->protocol_set->login, "login_acknowledgement", false)) - ctx->server_state = CONFIGURATION; - if (packet_id == PACKET_ID_SERVER_ENCRYPTION_BEGIN) - ctx->encrypted = true; - return 0; -} - -void handle(proto_tree *packet_tree, packet_info *pinfo, tvbuff_t *tvb, mc_protocol_context *ctx, - protocol_set protocol_set, bool is_client) { - gint packet_id; - gint p; - gint read = p = read_var_int(tvb, 0, &packet_id); - if (is_invalid(read)) { - proto_tree_add_string(packet_tree, hf_packet_name_je, tvb, 0, 0, "Invalid Packet ID"); return; } - if (protocol_set == NULL) { - proto_tree_add_string(packet_tree, hf_invalid_data, tvb, 0, 1, "Can't find protocol set"); + + uint32_t now_state = is_client ? ctx->client_state : ctx->server_state + 16; + int32_t packet_id; + int32_t len = read_var_int(tvb, 0, &packet_id); + if (is_invalid(len)) { + proto_tree_add_string(tree, hf_packet_name_je, tvb, 0, 0, "Invalid Packet ID"); return; } - protocol_entry protocol = get_protocol_entry(protocol_set, packet_id, is_client); - proto_tree_add_uint(packet_tree, hf_packet_id_je, tvb, 0, read, packet_id); - if (protocol == NULL) { - proto_tree_add_string(packet_tree, hf_unknown_packet_je, tvb, 0, 1, "Unknown Packet ID"); + uint32_t count = (uint64_t) wmem_map_lookup(ctx->dissector_set->count_by_state, (void *) (uint64_t) now_state); + if (packet_id >= count) { + proto_tree_add_string(tree, hf_unknown_packet_je, tvb, 0, 1, "Unknown Packet ID"); return; } - gchar *packet_name = get_packet_name(protocol); - gchar *better_name = get_readable_packet_name(is_client, packet_name); + gchar **key = wmem_map_lookup(ctx->dissector_set->registry_keys, (void *) (uint64_t) now_state); + gchar **name = wmem_map_lookup(ctx->dissector_set->readable_names, (void *) (uint64_t) now_state); + protocol_dissector **d = wmem_map_lookup(ctx->dissector_set->dissectors_by_state, (void *) (uint64_t) now_state); proto_tree_add_string_format_value( - packet_tree, hf_packet_name_je, tvb, 0, read, packet_name, - "%s (%s)", better_name, packet_name + tree, hf_packet_name_je, tvb, 0, len, key[packet_id], + "%s (%s)", name[packet_id], key[packet_id] ); bool ignore = false; if (strlen(pref_ignore_packets_je) != 0) { - gchar *search_name = g_strdup_printf("%s:%s", is_client ? "c" : "s", packet_name); + gchar *search_name = g_strdup_printf("%s:%s", is_client ? "c" : "s", key[packet_id]); GList *list = prefs_get_string_list(pref_ignore_packets_je); ignore = g_list_find_custom(list, search_name, (GCompareFunc) g_strcmp0) != NULL; } - gint length = (gint) tvb_reported_length(tvb); + uint32_t length = tvb_reported_length(tvb); if (ignore) - proto_tree_add_string(packet_tree, hf_ignored_packet_je, tvb, p, length - p, "Ignored by user"); - else if (!make_tree(protocol, packet_tree, pinfo, tvb, ctx->global_data, length)) - proto_tree_add_string( - packet_tree, hf_ignored_packet_je, tvb, p, length - p, - "Protocol hasn't been implemented yet" + proto_tree_add_string(tree, hf_ignored_packet_je, tvb, len, (int32_t) length - len, "Ignored by user"); + else { + wmem_map_t *packet_save = wmem_map_new(pinfo->pool, g_str_hash, g_str_equal); + int32_t sub_len = d[packet_id]->dissect_protocol( + tree, pinfo, tvb, len, d[packet_id], "Packet Data", packet_save, NULL ); -} - -void handle_login(proto_tree *packet_tree, packet_info *pinfo, tvbuff_t *tvb, - mc_protocol_context *ctx, bool is_client) { - if (ctx->protocol_set == NULL) { - proto_tree_add_string(packet_tree, hf_invalid_data, tvb, 0, 1, "Can't find protocol set for this version"); - ctx->client_state = ctx->server_state = PROTOCOL_NOT_FOUND; - return; - } - handle(packet_tree, pinfo, tvb, ctx, ctx->protocol_set->login, is_client); -} - -int handle_client_play_switch(tvbuff_t *tvb, mc_protocol_context *ctx) { - if (ctx->protocol_set == NULL) { - ctx->client_state = ctx->server_state = PROTOCOL_NOT_FOUND; - return -1; - } - gint packet_id; - gint p = read_var_int(tvb, 0, &packet_id); - if (is_invalid(p)) - return INVALID_DATA; - if (packet_id == get_packet_id(ctx->protocol_set->play, "start_configuration", true)) - ctx->client_state = CONFIGURATION; - return 0; -} - -int handle_server_play_switch(tvbuff_t *tvb, mc_protocol_context *ctx) { - if (ctx->protocol_set == NULL) { - ctx->client_state = ctx->server_state = PROTOCOL_NOT_FOUND; - return -1; - } - gint packet_id; - gint p = read_var_int(tvb, 0, &packet_id); - if (is_invalid(p)) - return INVALID_DATA; - if (packet_id == get_packet_id(ctx->protocol_set->play, "configuration_acknowledgement", false)) - ctx->server_state = CONFIGURATION; - return 0; -} - -void handle_play(proto_tree *packet_tree, packet_info *pinfo, tvbuff_t *tvb, - mc_protocol_context *ctx, bool is_client) { - if (ctx->protocol_set == NULL) { - proto_tree_add_string(packet_tree, hf_invalid_data, tvb, 0, 1, "Can't find protocol set for this version"); - ctx->client_state = ctx->server_state = PROTOCOL_NOT_FOUND; - return; + if (sub_len + len != length) + proto_tree_add_string_format_value( + tree, hf_invalid_data, tvb, len, (int32_t) length - len, + "length mismatch", "Packet length mismatch, expected %d, got %d", length - len, + sub_len + ); } - handle(packet_tree, pinfo, tvb, ctx, ctx->protocol_set->play, is_client); } -int handle_client_configuration_switch(tvbuff_t *tvb, mc_protocol_context *ctx) { - if (ctx->protocol_set == NULL) { - ctx->client_state = ctx->server_state = PROTOCOL_NOT_FOUND; - return -1; +int try_switch_state(tvbuff_t *tvb, mc_protocol_context *ctx, bool is_client) { + if (ctx->dissector_set == NULL) return INVALID_DATA; + uint32_t now_state = is_client ? ctx->client_state : ctx->server_state + 16; + int32_t packet_id; + int32_t len = read_var_int(tvb, 0, &packet_id); + if (is_invalid(len)) return INVALID_DATA; + wmem_map_t *state_to_next = wmem_map_lookup(ctx->dissector_set->state_to_next, (void *) (uint64_t) now_state); + wmem_map_t *state_side = wmem_map_lookup(ctx->dissector_set->state_to_next_side, (void *) (uint64_t) now_state); + wmem_map_t *special_mark = wmem_map_lookup(ctx->dissector_set->special_mark, (void *) (uint64_t) now_state); + if (wmem_map_contains(state_to_next, (void *) (uint64_t) packet_id)) { + uint32_t state = (uint64_t) wmem_map_lookup(state_to_next, (void *) (uint64_t) packet_id); + uint32_t side = (uint64_t) wmem_map_lookup(state_side, (void *) (uint64_t) packet_id); + if ((side & 1) != 0) ctx->client_state = state; + if ((side & 2) != 0) ctx->server_state = state; } - gint packet_id; - gint p = read_var_int(tvb, 0, &packet_id); - if (is_invalid(p)) - return INVALID_DATA; - if (packet_id == get_packet_id(ctx->protocol_set->configuration, "finish_configuration", true)) - ctx->client_state = PLAY; - return 0; -} + if (wmem_map_contains(special_mark, (void *) (uint64_t) packet_id)) { + gchar *mark = wmem_map_lookup(special_mark, (void *) (uint64_t) packet_id); -int handle_server_configuration_switch(tvbuff_t *tvb, mc_protocol_context *ctx) { - if (ctx->protocol_set == NULL) { - ctx->client_state = ctx->server_state = PROTOCOL_NOT_FOUND; - return -1; + if (strcmp(mark, "encrypt") == 0) ctx->encrypted = true; + if (strcmp(mark, "compress") == 0) { + int32_t threshold; + len = read_var_int(tvb, len, &threshold); + if (is_invalid(len)) return INVALID_DATA; + ctx->compression_threshold = threshold; + } } - gint packet_id; - gint p = read_var_int(tvb, 0, &packet_id); - if (is_invalid(p)) - return INVALID_DATA; - if (packet_id == get_packet_id(ctx->protocol_set->configuration, "finish_configuration", false)) - ctx->server_state = PLAY; return 0; -} - -void handle_configuration(proto_tree *packet_tree, packet_info *pinfo, tvbuff_t *tvb, mc_protocol_context *ctx, - bool is_client) { - if (ctx->protocol_set == NULL) { - proto_tree_add_string(packet_tree, hf_invalid_data, tvb, 0, 1, "Can't find protocol set for this version"); - ctx->client_state = ctx->server_state = PROTOCOL_NOT_FOUND; - return; - } - handle(packet_tree, pinfo, tvb, ctx, ctx->protocol_set->configuration, is_client); } \ No newline at end of file diff --git a/protocol_je/je_protocol.h b/protocol_je/je_protocol.h index 8aa5e71..1fe25fe 100644 --- a/protocol_je/je_protocol.h +++ b/protocol_je/je_protocol.h @@ -14,9 +14,6 @@ #define PACKET_ID_SERVER_PING 0x01 #define PACKET_ID_CLIENT_SERVER_INFO 0x00 #define PACKET_ID_CLIENT_PING 0x01 -#define PACKET_ID_CLIENT_SUCCESS 0x02 -#define PACKET_ID_CLIENT_COMPRESS 0x03 -#define PACKET_ID_SERVER_ENCRYPTION_BEGIN 0x01 int handle_server_handshake_switch(tvbuff_t *tvb, mc_protocol_context *ctx); @@ -26,22 +23,8 @@ void handle_server_slp(proto_tree *packet_tree, tvbuff_t *tvb); void handle_client_slp(proto_tree *packet_tree, packet_info *pinfo, tvbuff_t *tvb); -int handle_client_login_switch(tvbuff_t *tvb, mc_protocol_context *ctx); +int try_switch_state(tvbuff_t *tvb, mc_protocol_context *ctx, bool is_client); -int handle_server_login_switch(tvbuff_t *tvb, mc_protocol_context *ctx); - -void handle_login(proto_tree *packet_tree, packet_info *pinfo, tvbuff_t *tvb, mc_protocol_context *ctx, bool is_client); - -int handle_client_play_switch(tvbuff_t *tvb, mc_protocol_context *ctx); - -int handle_server_play_switch(tvbuff_t *tvb, mc_protocol_context *ctx); - -void handle_play(proto_tree *packet_tree, packet_info *pinfo, tvbuff_t *tvb, mc_protocol_context *ctx, bool is_client); - -int handle_client_configuration_switch(tvbuff_t *tvb, mc_protocol_context *ctx); - -int handle_server_configuration_switch(tvbuff_t *tvb, mc_protocol_context *ctx); - -void handle_configuration(proto_tree *packet_tree, packet_info *pinfo, tvbuff_t *tvb, mc_protocol_context *ctx, bool is_client); +void handle_protocol(proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb, mc_protocol_context *ctx, bool is_client); #endif //MC_DISSECTOR_JE_PROTOCOL_H