From 5936d506707ff2c57b1aa93c4e26d0e3c516fd97 Mon Sep 17 00:00:00 2001 From: nickid2018 Date: Wed, 2 Oct 2024 22:17:52 +0800 Subject: [PATCH] Add initial packets, update schema version to 2.1 --- mc_dissector.h | 2 +- protocol/protocol_data.c | 8 +- protocol/protocol_data.h | 4 +- protocol/schema/functions.c | 37 +++-- protocol/schema/functions.h | 2 + protocol/schema/schema.c | 16 +- protocol/schema/schema.h | 4 + protocol/storage/storage.c | 51 ++++++- protocol/storage/storage.h | 5 + protocol_je/je_dissect.c | 75 ++++------ protocol_je/je_protocol.c | 287 +++++++++++++----------------------- protocol_je/je_protocol.h | 19 +-- protocol_je/je_registers.c | 28 +--- 13 files changed, 253 insertions(+), 285 deletions(-) diff --git a/mc_dissector.h b/mc_dissector.h index 1282932..1271283 100644 --- a/mc_dissector.h +++ b/mc_dissector.h @@ -16,7 +16,7 @@ #define MCJE_FILTER "mcje" #define MCBE_FILTER "mcbe" -#define PROTOCOL_DATA_VERSION "2.0" +#define PROTOCOL_DATA_VERSION "2.1" #if defined(DEBUG) #define WS_LOG(format, ...) ws_log("", LOG_LEVEL_CRITICAL, format, ##__VA_ARGS__) diff --git a/protocol/protocol_data.c b/protocol/protocol_data.c index a1a7bf3..660ec57 100644 --- a/protocol/protocol_data.c +++ b/protocol/protocol_data.c @@ -5,7 +5,7 @@ #include #include "protocol_data.h" -char *STATE_NAME[] = {"Handshake", "Play", "Server List Ping", "Login", "Transfer", "Configuration", "Invalid"}; +char *STATE_NAME[] = {"Handshake", "Play", "Status", "Login", "Transfer", "Configuration", "Invalid"}; int32_t read_var_int(tvbuff_t *tvb, int32_t offset, int32_t *result) { uint8_t read; @@ -59,4 +59,10 @@ 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; +} + +uint32_t je_state_to_protocol_set_state(je_state state, bool is_client) { + if (state == TRANSFER) + state = LOGIN; + return is_client ? state : 16 + state; } \ No newline at end of file diff --git a/protocol/protocol_data.h b/protocol/protocol_data.h index 9d0fcc6..879c802 100644 --- a/protocol/protocol_data.h +++ b/protocol/protocol_data.h @@ -14,7 +14,7 @@ #define is_invalid(x) ((x) == INVALID_DATA) typedef enum { - HANDSHAKE, PLAY, PING, LOGIN, TRANSFER, CONFIGURATION, // Normal states + HANDSHAKE, PLAY, STATUS, LOGIN, TRANSFER, CONFIGURATION, // Normal states INVALID, NOT_COMPATIBLE, PROTOCOL_NOT_FOUND // Special states } je_state; @@ -56,6 +56,8 @@ extern char *STATE_NAME[]; wmem_map_t *get_global_data(packet_info *pinfo); +uint32_t je_state_to_protocol_set_state(je_state state, bool is_client); + int32_t read_var_int(tvbuff_t *tvb, int32_t offset, int32_t *result); int32_t read_var_int_with_limit(tvbuff_t *tvb, int32_t offset, int32_t max_length, int32_t *result); diff --git a/protocol/schema/functions.c b/protocol/schema/functions.c index bbea5c0..cc517f1 100644 --- a/protocol/schema/functions.c +++ b/protocol/schema/functions.c @@ -18,8 +18,8 @@ DISSECT_PROTOCOL(record_entity_id) { 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"); + char *entity_id = wmem_map_lookup(packet_saves, "entity_id"); + char *str_type = wmem_map_lookup(packet_saves, "entity_type"); wmem_map_insert(entity_id_record, entity_id, str_type); return 0; } @@ -32,7 +32,7 @@ DISSECT_PROTOCOL(record_entity_id_player) { 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 *entity_id = wmem_map_lookup(packet_saves, "entity_id"); wmem_map_insert(entity_id_record, entity_id, "player"); return 0; } @@ -45,7 +45,7 @@ DISSECT_PROTOCOL(record_entity_id_experience_orb) { 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 *entity_id = wmem_map_lookup(packet_saves, "entity_id"); wmem_map_insert(entity_id_record, entity_id, "experience_orb"); return 0; } @@ -58,7 +58,7 @@ DISSECT_PROTOCOL(record_entity_id_painting) { 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 *entity_id = wmem_map_lookup(packet_saves, "entity_id"); wmem_map_insert(entity_id_record, entity_id, "painting"); return 0; } @@ -71,7 +71,7 @@ DISSECT_PROTOCOL(sync_entity_data) { 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 *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); @@ -83,15 +83,34 @@ DISSECT_PROTOCOL(sync_entity_data) { proto_item_prepend_text(item, "Entity Type "); return 0; } - gchar *sync_id = wmem_map_lookup(packet_saves, "sync_id"); - gchar *end; + char *sync_id = wmem_map_lookup(packet_saves, "sync_id"); + char *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); + char *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; +} + +DISSECT_PROTOCOL(display_protocol_version) { + if (!tree) return 0; + char *protocol_version_str = wmem_map_lookup(packet_saves, "protocol_version"); + char *end; + uint32_t protocol_version = strtoll(protocol_version_str, &end, 10); + char **java_versions = get_mapped_java_versions(protocol_version); + proto_item *item; + if (java_versions == NULL || java_versions[0] == NULL) { + item = proto_tree_add_string(tree, hf_generated, tvb, 0, 0, "Unknown Protocol Version"); + } else { + char *java_version = g_strjoinv(", ", java_versions); + g_strfreev(java_versions); + item = proto_tree_add_string(tree, hf_generated, tvb, 0, 0, java_version); + } + proto_item_set_generated(item); + proto_item_prepend_text(item, "Game Version "); + return 0; } \ No newline at end of file diff --git a/protocol/schema/functions.h b/protocol/schema/functions.h index 75371d6..947e884 100644 --- a/protocol/schema/functions.h +++ b/protocol/schema/functions.h @@ -23,4 +23,6 @@ DISSECT_PROTOCOL(record_entity_id_painting); DISSECT_PROTOCOL(sync_entity_data); +DISSECT_PROTOCOL(display_protocol_version); + #endif //MC_DISSECTOR_FUNCTIONS_H diff --git a/protocol/schema/schema.c b/protocol/schema/schema.c index eb47963..951694d 100644 --- a/protocol/schema/schema.c +++ b/protocol/schema/schema.c @@ -38,7 +38,7 @@ extern char *pref_protocol_data_dir; void destroy_protocol(protocol_dissector_set *dissector_set) { wmem_destroy_allocator(dissector_set->allocator); - wmem_free(wmem_epan_scope(), dissector_set); + dissector_set->valid = false; } // PROTOCOL SUB-DISSECTORS --------------------------------------------------------------------------------------------- @@ -1056,6 +1056,7 @@ COMPOSITE_PROTOCOL_DEFINE(func) { 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) + FUNC_PROTOCOL(display_protocol_version, dissect_display_protocol_version) if (this_dissector->dissect_protocol == NULL) { wmem_free(allocator, this_dissector); @@ -1257,6 +1258,11 @@ uint32_t map_name_to_state(char *name) { if (strcmp(name, "configuration") == 0) return CONFIGURATION; if (strcmp(name, "configuration_client") == 0) return CONFIGURATION; if (strcmp(name, "configuration_server") == 0) return 16 + CONFIGURATION; + if (strcmp(name, "handshaking") == 0) return 16 + HANDSHAKE; + if (strcmp(name, "handshaking_server") == 0) return 16 + HANDSHAKE; + if (strcmp(name, "status") == 0) return STATUS; + if (strcmp(name, "status_client") == 0) return STATUS; + if (strcmp(name, "status_server") == 0) return 16 + STATUS; return ~0u; } @@ -1279,8 +1285,7 @@ char *map_state_to_name(uint32_t state) { } } -protocol_dissector_set *create_protocol(uint32_t protocol_version) { - cJSON *protocol_source = get_protocol_source(protocol_version); +protocol_dissector_set *create_protocol_with_json(cJSON *protocol_source, uint32_t protocol_version) { if (protocol_source == NULL) return NULL; protocol_dissector_set *set = wmem_alloc(wmem_epan_scope(), sizeof(protocol_dissector_set)); set->protocol_version = protocol_version; @@ -1293,6 +1298,7 @@ protocol_dissector_set *create_protocol(uint32_t protocol_version) { set->state_to_next = wmem_map_new(set->allocator, g_direct_hash, g_direct_equal); set->state_to_next_side = wmem_map_new(set->allocator, g_direct_hash, g_direct_equal); set->special_mark = wmem_map_new(set->allocator, g_direct_hash, g_direct_equal); + set->valid = true; cJSON *now = protocol_source->child; while (now != NULL) { uint32_t state = map_name_to_state(now->string); @@ -1300,4 +1306,8 @@ protocol_dissector_set *create_protocol(uint32_t protocol_version) { now = now->next; } return set; +} + +protocol_dissector_set *create_protocol(uint32_t protocol_version) { + return create_protocol_with_json(get_protocol_source(protocol_version), protocol_version); } \ No newline at end of file diff --git a/protocol/schema/schema.h b/protocol/schema/schema.h index 7a6dcde..5981c6d 100644 --- a/protocol/schema/schema.h +++ b/protocol/schema/schema.h @@ -31,6 +31,8 @@ struct protocol_dissector_set_struct { wmem_map_t *readable_names; wmem_allocator_t *allocator; + + bool valid; }; #define DISSECT_ERROR (1 << 31) @@ -39,6 +41,8 @@ uint32_t map_name_to_state(char *name); char *map_state_to_name(uint32_t state); +protocol_dissector_set *create_protocol_with_json(cJSON *protocol_source, uint32_t protocol_version); + protocol_dissector_set *create_protocol(uint32_t protocol_version); void destroy_protocol(protocol_dissector_set *dissector_set); diff --git a/protocol/storage/storage.c b/protocol/storage/storage.c index 61c0f4e..f9a6ae1 100644 --- a/protocol/storage/storage.c +++ b/protocol/storage/storage.c @@ -3,7 +3,6 @@ // #include "storage.h" -#include "protocol/schema/schema.h" extern char *pref_protocol_data_dir; @@ -27,12 +26,12 @@ void ensure_cached_##name() { \ #define DATA_CACHED_UINT(name) \ wmem_map_t *cached_##name = NULL; \ -void *get_cached_##name(guint version) { \ +void *get_cached_##name(uint32_t version) { \ if (cached_##name == NULL) \ return NULL; \ return wmem_map_lookup(cached_##name, GUINT_TO_POINTER(version)); \ } \ -void set_cached_##name(guint version, void *value) { \ +void set_cached_##name(uint32_t version, void *value) { \ if (cached_##name == NULL) \ cached_##name = wmem_map_new(wmem_epan_scope(), g_direct_hash, g_direct_equal); \ wmem_map_insert(cached_##name, GUINT_TO_POINTER(version), value); \ @@ -68,12 +67,15 @@ JSON_CACHED(settings, "settings.json") JSON_CACHED(versions, "java_edition/versions.json") +DATA_CACHED_UINT(protocol) + DATA_CACHED_UINT(entity_sync_data) DATA_CACHED_STR(registry_data) -wmem_map_t *index_mappings; -wmem_map_t *protocol_mappings; +wmem_map_t *index_mappings = NULL; +wmem_map_t *protocol_mappings = NULL; +protocol_dissector_set *initial_set = NULL; wmem_map_t *read_csv(char *path) { wmem_map_t *csv = wmem_map_new(wmem_epan_scope(), g_direct_hash, g_direct_equal); @@ -156,11 +158,21 @@ gboolean clean_json(gpointer key _U_, gpointer value, gpointer user_data _U_) { return true; } +gboolean clean_protocol(gpointer key _U_, gpointer value, gpointer user_data _U_) { + destroy_protocol(value); + return true; +} + void clear_storage() { CLEAR_CACHED_JSON(settings) CLEAR_CACHED_JSON(versions) CLEAR_CACHED_DATA(entity_sync_data, clean_json) CLEAR_CACHED_DATA(registry_data, clean_json) + CLEAR_CACHED_DATA(protocol, clean_protocol) + if (initial_set != NULL) { + destroy_protocol(initial_set); + initial_set = NULL; + } } char **get_mapped_java_versions(uint32_t protocol_version) { @@ -337,4 +349,33 @@ bool is_compatible_protocol_data() { ensure_cached_settings(); cJSON *version = cJSON_GetObjectItem(cached_settings, "version"); return version != NULL && g_strcmp0(version->valuestring, PROTOCOL_DATA_VERSION) == 0; +} + +protocol_dissector_set *get_initial_protocol() { + if (initial_set != NULL) return initial_set; + char *file = g_build_filename(pref_protocol_data_dir, "java_edition", "initial.json", NULL); + + char *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); + if (json == NULL) + ws_log("MC-Dissector", LOG_LEVEL_WARNING, "Cannot parse file %s: %s", file, cJSON_GetErrorPtr()); + g_free(file); + + initial_set = create_protocol_with_json(json, ~0u); + return initial_set; +} + +protocol_dissector_set *get_protocol_set(uint32_t protocol_version) { + protocol_dissector_set *cached = get_cached_protocol(protocol_version); + if (cached != NULL) return cached; + cached = create_protocol(protocol_version); + set_cached_protocol(protocol_version, cached); + return cached; } \ No newline at end of file diff --git a/protocol/storage/storage.h b/protocol/storage/storage.h index 24c4897..213ed52 100644 --- a/protocol/storage/storage.h +++ b/protocol/storage/storage.h @@ -7,6 +7,7 @@ #include "cJSON.h" #include "mc_dissector.h" +#include "protocol/schema/schema.h" void clear_storage(); @@ -30,6 +31,10 @@ cJSON *get_registry(uint32_t protocol_version, char *registry); char *get_registry_data(uint32_t protocol_version, char *registry, uint32_t index); +protocol_dissector_set *get_initial_protocol(); + +protocol_dissector_set *get_protocol_set(uint32_t protocol_version); + bool get_settings_flag(char *name); bool is_compatible_protocol_data(); diff --git a/protocol_je/je_dissect.c b/protocol_je/je_dissect.c index 27361e6..c7fb620 100644 --- a/protocol_je/je_dissect.c +++ b/protocol_je/je_dissect.c @@ -8,8 +8,8 @@ #include "je_dissect.h" #include "je_protocol.h" -extern int hf_packet_length_je; -extern int hf_packet_data_length_je; +extern int hf_packet_length; +extern int hf_packet_data_length; dissector_handle_t mcje_handle; @@ -21,50 +21,26 @@ void proto_reg_handoff_mcje() { void sub_dissect_je(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, mc_frame_data *frame_data, mc_protocol_context *ctx, bool is_server, bool visited) { - if (is_server) { - switch (frame_data->server_state) { - case HANDSHAKE: - if (!visited && is_invalid(handle_server_handshake_switch(tvb, ctx))) - return; - if (tree) - handle_server_handshake(tree, pinfo, tvb); + switch (is_server ? frame_data->server_state : frame_data->client_state) { + case HANDSHAKE: + case STATUS: + if (!visited && is_invalid(try_switch_initial(tvb, pinfo, ctx, !is_server))) return; - case PING: - if (tree) - handle_server_slp(tree, tvb); - return; - case LOGIN: - case TRANSFER: - case PLAY: - case CONFIGURATION: - if (!visited && is_invalid(try_switch_state(tvb, ctx, false))) - return; - if (tree) - handle_protocol(tree, pinfo, tvb, ctx, frame_data->server_state, false); - return; - default: - col_add_str(pinfo->cinfo, COL_INFO, "[Invalid State]"); - return; - } - } else { - switch (frame_data->client_state) { - case PING: - if (tree) - handle_client_slp(tree, pinfo, tvb); - return; - case LOGIN: - case TRANSFER: - case PLAY: - case CONFIGURATION: - if (!visited && is_invalid(try_switch_state(tvb, ctx, true))) - return; - if (tree) - handle_protocol(tree, pinfo, tvb, ctx, frame_data->client_state, true); - return; - default: - col_add_str(pinfo->cinfo, COL_INFO, "[Invalid State]"); + if (tree) + handle_initial(tree, pinfo, tvb, ctx, frame_data->server_state, !is_server); + return; + case LOGIN: + case TRANSFER: + case PLAY: + case CONFIGURATION: + if (!visited && is_invalid(try_switch_state(tvb, ctx, !is_server))) return; - } + if (tree) + handle_protocol(tree, pinfo, tvb, ctx, frame_data->server_state, !is_server); + return; + default: + col_add_str(pinfo->cinfo, COL_INFO, "[Invalid State]"); + return; } } @@ -74,7 +50,8 @@ void mark_invalid(packet_info *pinfo) { ctx->client_state = ctx->server_state = INVALID; } -void dissect_je_core(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int32_t offset, int32_t packet_len_len, int32_t 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); @@ -83,7 +60,7 @@ void dissect_je_core(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int32_ if (tree) { proto_item *ti = proto_tree_add_item(tree, proto_mcje, tvb, 0, -1, FALSE); mcje_tree = proto_item_add_subtree(ti, ett_mc); - proto_tree_add_uint(mcje_tree, hf_packet_length_je, tvb, offset - packet_len_len, packet_len_len, len); + proto_tree_add_uint(mcje_tree, hf_packet_length, tvb, offset - packet_len_len, packet_len_len, len); proto_item_append_text( ti, ", Client State: %s, Server State: %s", STATE_NAME[frame_data->client_state], STATE_NAME[frame_data->server_state] @@ -170,7 +147,8 @@ int dissect_je_conv(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree _U_, voi col_set_str(pinfo->cinfo, COL_PROTOCOL, MCJE_SHORT_NAME); 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"); + col_set_str(pinfo->cinfo, COL_INFO, + "[Invalid] Protocol data is not compatible with the current plugin version"); return (int32_t) tvb_captured_length(tvb); } if (frame_data->client_state == INVALID || frame_data->server_state == INVALID) { @@ -193,7 +171,8 @@ int dissect_je_conv(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree _U_, voi 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; - uint8_t **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; diff --git a/protocol_je/je_protocol.c b/protocol_je/je_protocol.c index ecd0607..bdcb28b 100644 --- a/protocol_je/je_protocol.c +++ b/protocol_je/je_protocol.c @@ -10,186 +10,16 @@ #include "utils/nbt.h" extern int hf_invalid_data; -extern int hf_ignored_packet_je; +extern int hf_ignored_packet; extern int hf_packet_id_je; extern int hf_packet_name_je; -extern int hf_unknown_packet_je; -extern int hf_protocol_version_je; -extern int hf_server_address_je; -extern int hf_next_state_je; -extern int hf_ping_time_je; -extern int hf_server_status_je; -extern int hf_legacy_slp_payload; +extern int hf_unknown_packet; -int handle_server_handshake_switch(tvbuff_t *tvb, mc_protocol_context *ctx) { - 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_HANDSHAKE) { - gint protocol_version; - read = read_var_int(tvb, p, &protocol_version); - if (is_invalid(read)) - return INVALID_DATA; - p += read; - gint str_len; - read = read_var_int(tvb, p, &str_len); - if (is_invalid(read)) - return INVALID_DATA; - p += read + str_len + 2; - gint next_state; - read = read_var_int(tvb, p, &next_state); - if (is_invalid(read)) - return INVALID_DATA; - if (next_state < 1 || next_state > 3) - return INVALID_DATA; - - ctx->client_state = ctx->server_state = next_state + 1; - - ctx->protocol_version = protocol_version; - wmem_map_insert(ctx->global_data, "protocol_version", GUINT_TO_POINTER(protocol_version)); - - char **java_versions = get_mapped_java_versions(protocol_version); - if (java_versions[0] == NULL) { - ctx->client_state = ctx->server_state = PROTOCOL_NOT_FOUND; - return INVALID_DATA; - } - ctx->data_version = get_data_version(java_versions[0]); - wmem_map_insert(ctx->global_data, "data_version", GUINT_TO_POINTER(ctx->data_version)); - if (ctx->data_version >= 3567) - wmem_map_insert(ctx->global_data, "nbt_any_type", (void *) 1); - - 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) - return 0; - return INVALID_DATA; -} - -void handle_server_handshake(proto_tree *packet_tree, packet_info *pinfo, tvbuff_t *tvb) { - 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; - } - proto_tree_add_uint(packet_tree, hf_packet_id_je, tvb, 0, read, packet_id); - if (packet_id == PACKET_ID_HANDSHAKE) { - proto_tree_add_string_format_value( - packet_tree, hf_packet_name_je, tvb, 0, read, - "set_protocol", "Server Handshake" - ); - - gint protocol_version; - read = read_var_int(tvb, p, &protocol_version); - if (is_invalid(read)) { - proto_tree_add_string(packet_tree, hf_protocol_version_je, tvb, p, -1, "Invalid Protocol Version"); - return; - } - char **java_versions = get_mapped_java_versions(protocol_version); - if (java_versions == NULL || java_versions[0] == NULL) { - proto_tree_add_string(packet_tree, hf_protocol_version_je, tvb, p, read, "Unknown Protocol Version"); - } else { - char *java_version = g_strjoinv(",", java_versions); - g_strfreev(java_versions); - proto_tree_add_string_format_value( - packet_tree, hf_protocol_version_je, tvb, p, read, "", - "%d (%s)", protocol_version, java_version - ); - } - p += read; - - guint8 *server_address; - read = read_buffer(tvb, p, &server_address, pinfo->pool); - if (is_invalid(read)) { - proto_tree_add_string(packet_tree, hf_server_address_je, tvb, p, -1, "Invalid Server Address"); - return; - } - guint16 server_port = tvb_get_uint16(tvb, p + read, ENC_BIG_ENDIAN); - read += 2; - proto_tree_add_string_format_value( - packet_tree, hf_server_address_je, tvb, p, read, "", - "%s:%d", server_address, server_port - ); - p += read; - - gint next_state; - read = read_var_int(tvb, p, &next_state); - if (is_invalid(read)) { - proto_tree_add_string(packet_tree, hf_next_state_je, tvb, p, -1, "Invalid Next State"); - return; - } - proto_tree_add_string(packet_tree, hf_next_state_je, tvb, p, read, STATE_NAME[next_state + 1]); - } else if (packet_id == PACKET_ID_LEGACY_SERVER_LIST_PING) { - proto_tree_add_string_format_value( - packet_tree, hf_packet_name_je, tvb, 0, read, - "legacy_server_list_ping", "Legacy Server List Ping" - ); - guint8 payload = tvb_get_uint8(tvb, p); - proto_tree_add_uint(packet_tree, hf_legacy_slp_payload, tvb, p, 1, payload); - } else - proto_tree_add_string(packet_tree, hf_packet_name_je, tvb, 0, 1, "Unknown Packet ID"); -} - -void handle_server_slp(proto_tree *packet_tree, tvbuff_t *tvb) { - 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; - } - - proto_tree_add_uint(packet_tree, hf_packet_id_je, tvb, 0, read, packet_id); - if (packet_id == PACKET_ID_SERVER_PING_START) - proto_tree_add_string(packet_tree, hf_packet_name_je, tvb, 0, read, "Server Ping Start"); - else if (packet_id == PACKET_ID_SERVER_PING) { - proto_tree_add_string(packet_tree, hf_packet_name_je, tvb, 0, read, "Server Ping"); - proto_tree_add_int64(packet_tree, hf_ping_time_je, tvb, p, 8, tvb_get_int64(tvb, p, ENC_BIG_ENDIAN)); - } else - proto_tree_add_string(packet_tree, hf_packet_name_je, tvb, 0, read, "Unknown Packet ID"); -} - -void handle_client_slp(proto_tree *packet_tree, packet_info *pinfo, tvbuff_t *tvb) { - 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; - } - - proto_tree_add_uint(packet_tree, hf_packet_id_je, tvb, 0, read, packet_id); - if (packet_id == PACKET_ID_CLIENT_SERVER_INFO) { - proto_tree_add_string(packet_tree, hf_packet_name_je, tvb, 0, read, "Client Server Info"); - guint8 *server_info; - read = read_buffer(tvb, p, &server_info, pinfo->pool); - if (is_invalid(read)) { - proto_tree_add_string(packet_tree, hf_invalid_data, tvb, p, -1, "Invalid Server Info"); - return; - } - proto_tree_add_string(packet_tree, hf_server_status_je, tvb, p, read, *(char **) &server_info); - } else if (packet_id == PACKET_ID_CLIENT_PING) { - proto_tree_add_string(packet_tree, hf_packet_name_je, tvb, 0, read, "Client Ping"); - proto_tree_add_int64(packet_tree, hf_ping_time_je, tvb, p, 8, tvb_get_int64(tvb, p, ENC_BIG_ENDIAN)); - } else - proto_tree_add_string(packet_tree, hf_packet_name_je, tvb, 0, read, "Unknown Packet ID"); -} - -void handle_protocol( - proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb, mc_protocol_context *ctx, je_state state, bool is_client +void handle_with_set( + proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb, protocol_dissector_set *set, je_state state, 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; - } - uint32_t now_state = is_client ? state : state + 16; + uint32_t now_state = je_state_to_protocol_set_state(state, is_client); int32_t packet_id; int32_t len = read_var_int(tvb, 0, &packet_id); if (is_invalid(len)) { @@ -198,15 +28,15 @@ void handle_protocol( } proto_tree_add_uint(tree, hf_packet_id_je, tvb, 0, len, packet_id); - uint32_t count = (uint64_t) wmem_map_lookup(ctx->dissector_set->count_by_state, (void *) (uint64_t) now_state); + uint32_t count = (uint64_t) wmem_map_lookup(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"); + proto_tree_add_string(tree, hf_unknown_packet, tvb, 0, 1, "Unknown Packet ID"); return; } - char **key = wmem_map_lookup(ctx->dissector_set->registry_keys, (void *) (uint64_t) now_state); - char **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); + char **key = wmem_map_lookup(set->registry_keys, (void *) (uint64_t) now_state); + char **name = wmem_map_lookup(set->readable_names, (void *) (uint64_t) now_state); + protocol_dissector **d = wmem_map_lookup(set->dissectors_by_state, (void *) (uint64_t) now_state); proto_tree_add_string_format_value( tree, hf_packet_name_je, tvb, 0, len, key[packet_id], "%s (%s)", name[packet_id], key[packet_id] @@ -222,7 +52,7 @@ void handle_protocol( uint32_t length = tvb_reported_length(tvb); if (ignore) - proto_tree_add_string(tree, hf_ignored_packet_je, tvb, len, (int32_t) length - len, "Ignored by user"); + proto_tree_add_string(tree, hf_ignored_packet, tvb, len, (int32_t) length - len, "Ignored by user"); else { wmem_allocator_t *temp_alloc = wmem_allocator_new(WMEM_ALLOCATOR_SIMPLE); wmem_map_t *packet_save = wmem_map_new(temp_alloc, g_str_hash, g_str_equal); @@ -239,6 +69,97 @@ void handle_protocol( } } +void handle_initial( + proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb, mc_protocol_context *ctx, je_state state, bool is_client +) { + protocol_dissector_set *initial_set = get_initial_protocol(); + if (initial_set == NULL) { + proto_tree_add_string(tree, hf_invalid_data, tvb, 0, 1, "Can't find initial protocol set"); + ctx->client_state = ctx->server_state = PROTOCOL_NOT_FOUND; + return; + } + handle_with_set(tree, pinfo, tvb, initial_set, state, is_client); +} + +void handle_protocol( + proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb, mc_protocol_context *ctx, je_state state, 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; + } + if (!ctx->dissector_set->valid) { + proto_tree_add_string(tree, hf_invalid_data, tvb, 0, 1, "Protocol dissector is freed"); + ctx->client_state = ctx->server_state = INVALID; + return; + } + + handle_with_set(tree, pinfo, tvb, ctx->dissector_set, state, is_client); +} + +int try_switch_initial(tvbuff_t *tvb, packet_info *pinfo, mc_protocol_context *ctx, bool is_client) { + protocol_dissector_set *initial_set = get_initial_protocol(); + if (initial_set == NULL) return INVALID_DATA; + int32_t packet_id; + int32_t len = read_var_int(tvb, 0, &packet_id); + if (is_invalid(len)) return INVALID_DATA; + uint32_t now_state = is_client ? ctx->client_state : ctx->server_state + 16; + wmem_map_t *special_mark = wmem_map_lookup(initial_set->special_mark, (void *) (uint64_t) now_state); + if (wmem_map_contains(special_mark, (void *) (uint64_t) packet_id)) { + char *mark = wmem_map_lookup(special_mark, (void *) (uint64_t) packet_id); + if (strcmp(mark, "intention") == 0) { + protocol_dissector **d = wmem_map_lookup(initial_set->dissectors_by_state, (void *) (uint64_t) now_state); + wmem_allocator_t *temp_alloc = wmem_allocator_new(WMEM_ALLOCATOR_SIMPLE); + wmem_map_t *packet_save = wmem_map_new(temp_alloc, g_str_hash, g_str_equal); + int32_t sub_len = d[packet_id]->dissect_protocol( + NULL, pinfo, tvb, len, temp_alloc, d[packet_id], "Packet Data", packet_save, NULL + ); + if (sub_len + len != tvb_reported_length(tvb) && sub_len != DISSECT_ERROR) { + wmem_destroy_allocator(temp_alloc); + return INVALID_DATA; + } + char *protocol_version_str = wmem_map_lookup(packet_save, "protocol_version"); + char *intention_str = wmem_map_lookup(packet_save, "intention"); + if (intention_str == NULL || protocol_version_str == NULL) { + wmem_destroy_allocator(temp_alloc); + ctx->client_state = ctx->server_state = PROTOCOL_NOT_FOUND; + return INVALID_DATA; + } + char *end; + uint32_t protocol_version = strtoll(protocol_version_str, &end, 10); + ctx->protocol_version = protocol_version; + wmem_map_insert(ctx->global_data, "protocol_version", (void *) (uint64_t) protocol_version); + int next_state = -1; + if (strcmp(intention_str, "Status") == 0) next_state = STATUS; + if (strcmp(intention_str, "Login") == 0) next_state = LOGIN; + if (strcmp(intention_str, "Transfer") == 0) next_state = TRANSFER; + wmem_destroy_allocator(temp_alloc); + if (next_state == -1) { + ctx->client_state = ctx->server_state = PROTOCOL_NOT_FOUND; + return INVALID_DATA; + } + ctx->client_state = ctx->server_state = next_state; + char **java_versions = get_mapped_java_versions(protocol_version); + if (java_versions == NULL || java_versions[0] == NULL) { + ctx->client_state = ctx->server_state = PROTOCOL_NOT_FOUND; + return INVALID_DATA; + } + ctx->data_version = get_data_version(java_versions[0]); + g_strfreev(java_versions); + wmem_map_insert(ctx->global_data, "data_version", (void *) (uint64_t) ctx->data_version); + if (ctx->data_version >= 3567) + wmem_map_insert(ctx->global_data, "nbt_any_type", (void *) 1); + if (next_state == STATUS) + return 0; + ctx->dissector_set = get_protocol_set(protocol_version); + if (ctx->dissector_set == NULL) + ctx->client_state = ctx->server_state = PROTOCOL_NOT_FOUND; + } + } + return 0; +} + 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; @@ -277,7 +198,7 @@ int try_switch_state(tvbuff_t *tvb, mc_protocol_context *ctx, bool is_client) { } char *registry_name; int32_t offset = len; - len = read_buffer(tvb, offset, (uint8_t **) ®istry_name, wmem_file_scope()); + len = read_buffer(tvb, offset, (uint8_t * *) & registry_name, wmem_file_scope()); if (is_invalid(len)) return INVALID_DATA; int64_t length = g_utf8_strlen(registry_name, 400); int64_t split_pos = length - 1; @@ -294,7 +215,7 @@ int try_switch_state(tvbuff_t *tvb, mc_protocol_context *ctx, bool is_client) { bool is_new_nbt = wmem_map_lookup(ctx->global_data, "nbt_any_type"); for (int i = 0; i < count; i++) { char *name; - len = read_buffer(tvb, offset, (uint8_t **) &name, wmem_file_scope()); + len = read_buffer(tvb, offset, (uint8_t * *) & name, wmem_file_scope()); if (is_invalid(len)) { wmem_free(wmem_file_scope(), data); return INVALID_DATA; diff --git a/protocol_je/je_protocol.h b/protocol_je/je_protocol.h index f24d487..0bf0b2b 100644 --- a/protocol_je/je_protocol.h +++ b/protocol_je/je_protocol.h @@ -8,23 +8,14 @@ #include #include "protocol/protocol_data.h" -#define PACKET_ID_HANDSHAKE 0x00 -#define PACKET_ID_LEGACY_SERVER_LIST_PING 0xFE -#define PACKET_ID_SERVER_PING_START 0x00 -#define PACKET_ID_SERVER_PING 0x01 -#define PACKET_ID_CLIENT_SERVER_INFO 0x00 -#define PACKET_ID_CLIENT_PING 0x01 - -int handle_server_handshake_switch(tvbuff_t *tvb, mc_protocol_context *ctx); - -void handle_server_handshake(proto_tree *packet_tree, packet_info *pinfo, tvbuff_t *tvb); - -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 try_switch_initial(tvbuff_t *tvb, packet_info *pinfo, mc_protocol_context *ctx, bool is_client); int try_switch_state(tvbuff_t *tvb, mc_protocol_context *ctx, bool is_client); +void handle_initial( + proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb, mc_protocol_context *ctx, je_state state, bool is_client +); + void handle_protocol( proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb, mc_protocol_context *ctx, je_state state, bool is_client ); diff --git a/protocol_je/je_registers.c b/protocol_je/je_registers.c index 1bc74fd..eb0c8a0 100644 --- a/protocol_je/je_registers.c +++ b/protocol_je/je_registers.c @@ -36,18 +36,12 @@ int hf_uuid = -1; int hf_generated = -1; int hf_invalid_data = -1; int hf_parsing_error = -1; -int hf_ignored_packet_je = -1; -int hf_packet_length_je = -1; -int hf_packet_data_length_je = -1; +int hf_ignored_packet = -1; +int hf_packet_length = -1; +int hf_packet_data_length = -1; int hf_packet_id_je = -1; int hf_packet_name_je = -1; -int hf_unknown_packet_je = -1; -int hf_protocol_version_je = -1; -int hf_server_address_je = -1; -int hf_next_state_je = -1; -int hf_ping_time_je = -1; -int hf_server_status_je = -1; -int hf_legacy_slp_payload = -1; +int hf_unknown_packet = -1; #define DEFINE_HF(name, desc, key, type, dis) {&name, {desc, key, FT_##type, BASE_##dis, NULL, 0x0, NULL, HFILL}}, @@ -78,18 +72,12 @@ void proto_register_mcje() { DEFINE_HF(hf_generated, "(generated)", "mc.generated", STRING, NONE) DEFINE_HF(hf_invalid_data, "[INVALID]", "mc.invalid_data", STRING, NONE) DEFINE_HF(hf_parsing_error, "[PARSING ERROR]", "mc.parsing_error", STRING, NONE) - DEFINE_HF(hf_ignored_packet_je, "Ignored Packet", "mc.ignored_packet", STRING, NONE) - DEFINE_HF(hf_packet_length_je, "Packet Length", "mc.packet_length", UINT32, DEC) - DEFINE_HF(hf_packet_data_length_je, "Packet Data Length", "mc.packet_data_length", UINT32, DEC) + DEFINE_HF(hf_ignored_packet, "Ignored Packet", "mc.ignored_packet", STRING, NONE) + DEFINE_HF(hf_packet_length, "Packet Length", "mc.packet_length", UINT32, DEC) + DEFINE_HF(hf_packet_data_length, "Packet Data Length", "mc.packet_data_length", UINT32, DEC) DEFINE_HF(hf_packet_id_je, "Packet ID", "mcje.packet_id", UINT8, HEX) DEFINE_HF(hf_packet_name_je, "Packet Name", "mcje.packet_name", STRING, NONE) - DEFINE_HF(hf_unknown_packet_je, "Packet Name", "mc.unknown_packet", STRING, NONE) - DEFINE_HF(hf_protocol_version_je, "Protocol Version", "mcje.protocol_version", STRING, NONE) - DEFINE_HF(hf_server_address_je, "Server Address", "mcje.server_address", STRING, NONE) - DEFINE_HF(hf_next_state_je, "Next State", "mcje.next_state", STRING, NONE) - DEFINE_HF(hf_ping_time_je, "Ping Time", "mcje.ping_time", INT64, DEC) - DEFINE_HF(hf_server_status_je, "Server Status", "mcje.server_status", STRING, NONE) - DEFINE_HF(hf_legacy_slp_payload, "Legacy SLP Payload", "mcje.legacy_slp_payload", UINT8, DEC) + DEFINE_HF(hf_unknown_packet, "Unknown Packet", "mc.unknown_packet", STRING, NONE) }; proto_register_field_array(proto_mcje, hf_je, array_length(hf_je));