aboutsummaryrefslogtreecommitdiffstats
path: root/epan/dissectors/packet-raknet.c
diff options
context:
space:
mode:
authorPHO <pho@cielonegro.org>2016-10-03 09:22:35 +0900
committerAnders Broman <a.broman58@gmail.com>2016-10-12 03:57:03 +0000
commitc06189f7c6e6e428d914bfabdd96e5de42a2400d (patch)
treeba15bdfcf65047c6c50c94f48cbcfe4b70c99030 /epan/dissectors/packet-raknet.c
parent1cd22559a8a907263f1d032e8066482b22f8fbe3 (diff)
raknet, mcpe: Improve dissectors
packet-raknet.c now correctly dissects the following offline messages: * ID_UNCONNECTED_PING * ID_UNCONNECTED_PING_OPEN_CONNECTIONS * ID_OPEN_CONNECTION_REQUEST_1 * ID_OPEN_CONNECTION_REPLY_1 * ID_OPEN_CONNECTION_REQUEST_2 * ID_OPEN_CONNECTION_REPLY_2 * ID_OUT_OF_BAND_INTERNAL * ID_CONNECTION_ATTEMPT_FAILED * ID_ALREADY_CONNECTED * ID_NO_FREE_INCOMING_CONNECTIONS * ID_CONNECTION_BANNED * ID_INCOMPATIBLE_PROTOCOL_VERSION * ID_IP_RECENTLY_CONNECTED * ID_UNCONNECTED_PONG packet-raknet.c now correctly dissects the following system messages: * ID_CONNECTED_PING * ID_CONNECTED_PONG * ID_CONNECTION_REQUEST * ID_CONNECTION_REQUEST_ACCEPTED * ID_NEW_INCOMING_CONNECTION packet-raknet.h exports the following functions: * raknet_add_udp_dissector() * raknet_delete_udp_dissector() * raknet_conversation_set_dissector() packet-raknet.c now dissects message flags, reliability, reliable message number and so on. It now reassembles fragmented packets, supports heuristics, supports dissecting combined packets, and gives up dissecting messages when they are encrypted. packet-raknet.c now calls subdissectors with a tvbuff buffer only having a message ID and payload. It first tries to locate a subdissector based on the port, and then tries heuristic dissectors if any. packet-mcpe.c is updated so that it uses the new raknet interface, and it now correctly dissects the following game packets: * 0x01 Login * 0x03 Server to Client Handshake * 0x06 Batch packet-mcpe.c now supports heuristics, and gives up dissecting packets in a conversation once it sees a "Server to Client Handshake" packet because everything, including packet ID, are encrypted after that. Change-Id: I92c0b3ff0f18d22d4513bb014aeb4ea6475fb06c Reviewed-on: https://code.wireshark.org/review/18044 Petri-Dish: Alexis La Goutte <alexis.lagoutte@gmail.com> Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org> Reviewed-by: Anders Broman <a.broman58@gmail.com>
Diffstat (limited to 'epan/dissectors/packet-raknet.c')
-rw-r--r--epan/dissectors/packet-raknet.c1978
1 files changed, 1721 insertions, 257 deletions
diff --git a/epan/dissectors/packet-raknet.c b/epan/dissectors/packet-raknet.c
index 1fe2b8e0a8..d075329ffd 100644
--- a/epan/dissectors/packet-raknet.c
+++ b/epan/dissectors/packet-raknet.c
@@ -28,406 +28,854 @@
*/
#include "config.h"
-#include <epan/packet.h>
+#include <epan/conversation.h>
+#include <epan/exceptions.h>
#include <epan/expert.h>
+#include <epan/packet.h>
+#include <epan/reassemble.h>
+#include <epan/to_str.h>
+#include <epan/wmem/wmem.h>
+
+#include "packet-raknet.h"
/*
- * RAKNET Protocol Constants.
+ * RakNet Protocol Constants.
*/
-#define RAKNET_MAGIC 0x00ffff00fefefefefdfdfdfd12345678
-#define RAKNET_SECURITY_AND_COOKIE 0x043f57fefd
+#define RAKNET_OFFLINE_MESSAGE_DATA_ID "\x00\xff\xff\x00\xfe\xfe\xfe\xfe\xfd\xfd\xfd\xfd\x12\x34\x56\x78"
+#define RAKNET_CHALLENGE_LENGTH 64
+#define RAKNET_ANSWER_LENGTH 128
+#define RAKNET_PROOF_LENGTH 32
+#define RAKNET_IDENTITY_LENGTH 160
+#define RAKNET_NUMBER_OF_INTERNAL_IDS 10
static int proto_raknet = -1;
static gint ett_raknet = -1; /* Should this node be expanded */
+static gint ett_raknet_system_address = -1;
+static gint ett_raknet_packet_type = -1;
+static gint ett_raknet_packet_number_range = -1;
+static gint ett_raknet_message = -1;
+static gint ett_raknet_message_flags = -1;
+static gint ett_raknet_system_message = -1;
/*
* Dissectors
*/
-static dissector_table_t raknet_dissector_table;
-static expert_field ei_raknet_uknown_id = EI_INIT;
+static dissector_handle_t raknet_handle = NULL;
+static dissector_table_t raknet_offline_message_dissectors = NULL;
+static dissector_table_t raknet_system_message_dissectors = NULL;
+static dissector_table_t raknet_port_dissectors = NULL;
+static heur_dissector_list_t raknet_heur_subdissectors = NULL;
+
+/*
+ * Expert fields
+ */
+static expert_field ei_raknet_unknown_message_id = EI_INIT;
+static expert_field ei_raknet_encrypted_message = EI_INIT;
+static expert_field ei_raknet_subdissector_failed = EI_INIT;
/*
* First byte gives us the packet id
*/
-static int hf_raknet_packet_id = -1;
+static int hf_raknet_offline_message_id = -1;
/*
* General fields (fields that are in >1 packet types.
*/
-static int hf_raknet_general_client_id = -1;
-static int hf_raknet_general_elapsed_time = -1;
-static int hf_raknet_general_magic = -1;
-static int hf_raknet_general_mtu_size = -1;
-static int hf_raknet_general_raknet_proto_ver = -1;
-static int hf_raknet_general_security = -1;
-static int hf_raknet_general_server_id = -1;
-static int hf_raknet_general_udp_port = -1;
+static int hf_raknet_client_guid = -1;
+static int hf_raknet_timestamp = -1;
+static int hf_raknet_offline_message_data_id = -1;
+static int hf_raknet_mtu_size = -1;
+static int hf_raknet_raknet_proto_ver = -1;
+static int hf_raknet_server_guid = -1;
+static int hf_raknet_ip_version = -1;
+static int hf_raknet_ipv4_address = -1;
+static int hf_raknet_ipv6_address = -1;
+static int hf_raknet_port = -1;
+
/*
* Fields specific to a packet id type
*/
-static int hf_raknet_0x05_null_padding = -1;
-static int hf_raknet_0x06_server_security = -1;
-static int hf_raknet_0x07_cookie = -1;
+static int hf_raknet_null_padding = -1;
+static int hf_raknet_use_encryption = -1;
+static int hf_raknet_server_public_key = -1;
+static int hf_raknet_cookie = -1;
+static int hf_raknet_client_wrote_challenge = -1;
+static int hf_raknet_client_challenge = -1;
+static int hf_raknet_client_address = -1;
+static int hf_raknet_server_address = -1;
+static int hf_raknet_server_answer = -1;
static int hf_raknet_0x1C_server_id_str_len = -1;
static int hf_raknet_0x1C_server_id_str = -1;
+static int hf_raknet_packet_type = -1;
+static int hf_raknet_packet_is_for_connected = -1;
+static int hf_raknet_packet_is_ACK = -1;
+static int hf_raknet_packet_has_B_and_AS = -1;
+static int hf_raknet_packet_is_NAK = -1;
+static int hf_raknet_packet_is_pair = -1;
+static int hf_raknet_packet_is_continuous_send = -1;
+static int hf_raknet_packet_needs_B_and_AS = -1;
+static int hf_raknet_AS = -1;
+static int hf_raknet_NACK_record_count = -1;
+static int hf_raknet_packet_number_range = -1;
+static int hf_raknet_range_max_equal_to_min = -1;
+static int hf_raknet_packet_number_min = -1;
+static int hf_raknet_packet_number_max = -1;
+static int hf_raknet_packet_number = -1;
+static int hf_raknet_message = -1;
+static int hf_raknet_message_flags = -1;
+static int hf_raknet_message_reliability = -1;
+static int hf_raknet_message_has_split_packet = -1;
+static int hf_raknet_payload_length = -1;
+static int hf_raknet_reliable_message_number = -1;
+static int hf_raknet_message_sequencing_index = -1;
+static int hf_raknet_message_ordering_index = -1;
+static int hf_raknet_message_ordering_channel = -1;
+static int hf_raknet_split_packet_count = -1;
+static int hf_raknet_split_packet_id = -1;
+static int hf_raknet_split_packet_index = -1;
+static int hf_raknet_split_packet = -1;
+static int hf_raknet_system_message = -1;
+static int hf_raknet_system_message_id = -1;
+static int hf_raknet_client_proof = -1;
+static int hf_raknet_use_client_key = -1;
+static int hf_raknet_client_identity = -1;
+static int hf_raknet_password = -1;
+static int hf_raknet_system_index = -1;
+static int hf_raknet_internal_address = -1;
+
+/*
+ * Frame reassembly
+ */
+static reassembly_table raknet_reassembly_table;
+
+static gint ett_raknet_fragment = -1;
+static gint ett_raknet_fragments = -1;
+static gint hf_raknet_fragment = -1;
+static gint hf_raknet_fragment_count = -1;
+static gint hf_raknet_fragment_error = -1;
+static gint hf_raknet_fragment_multiple_tails = -1;
+static gint hf_raknet_fragment_overlap = -1;
+static gint hf_raknet_fragment_overlap_conflicts = -1;
+static gint hf_raknet_fragment_too_long_fragment = -1;
+static gint hf_raknet_fragments = -1;
+static gint hf_raknet_reassembled_in = -1;
+static gint hf_raknet_reassembled_length = -1;
+
+static const fragment_items raknet_frag_items = {
+ /* Fragment subtrees */
+ &ett_raknet_fragment,
+ &ett_raknet_fragments,
+ /* Fragment fields */
+ &hf_raknet_fragments,
+ &hf_raknet_fragment,
+ &hf_raknet_fragment_overlap,
+ &hf_raknet_fragment_overlap_conflicts,
+ &hf_raknet_fragment_multiple_tails,
+ &hf_raknet_fragment_too_long_fragment,
+ &hf_raknet_fragment_error,
+ &hf_raknet_fragment_count,
+ /* Reassembled in field */
+ &hf_raknet_reassembled_in,
+ /* Reassembled length field */
+ &hf_raknet_reassembled_length,
+ /* Reassembled data field */
+ NULL,
+ /* Tag */
+ "Message fragments"
+};
/*
- * Forward declaration.
+ * Session state
+ */
+typedef struct raknet_session_state {
+ gboolean use_encryption;
+ dissector_handle_t subdissector;
+} raknet_session_state_t;
+
+/*
+ * Reliability strings
+ * Ref: ..RakNet/Source/PacketPriority.h
+ *
+ * Note that ACK receipts will not be transmitted to the wire. See
+ * ReliabilityLayer::WriteToBitStreamFromInternalPacket()
+ */
+#define raknet_reliability_VALUE_STRING_LIST(VS) \
+ VS( RAKNET_UNRELIABLE , 0, "unreliable" ) \
+ VS( RAKNET_UNRELIABLE_SEQUENCED, 1, "unreliable sequenced" ) \
+ VS( RAKNET_RELIABLE , 2, "reliable" ) \
+ VS( RAKNET_RELIABLE_ORDERED , 3, "reliable ordered" ) \
+ VS( RAKNET_RELIABLE_SEQUENCED , 4, "reliable sequenced" )
+
+typedef VALUE_STRING_ENUM(raknet_reliability) raknet_reliability_t;
+VALUE_STRING_ARRAY(raknet_reliability);
+
+/*
+ * Forward declarations.
*/
void proto_register_raknet(void);
void proto_reg_handoff_raknet(void);
-static proto_tree *init_raknet(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint *offset);
+static proto_tree *init_raknet_offline_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint *offset);
+/*
+ * Initialization.
+ */
+static void
+raknet_reassemble_init(void)
+{
+ reassembly_table_init(&raknet_reassembly_table,
+ &addresses_ports_reassembly_table_functions);
+}
-struct raknet_handler_entry {
- value_string vs;
- dissector_t dissector_fp;
-};
-
-static int
-raknet_dissect_0x00(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
- void *data _U_)
+static void
+raknet_reassemble_cleanup(void)
{
- proto_tree *sub_tree;
- gint item_size;
- gint offset;
+ reassembly_table_destroy(&raknet_reassembly_table);
+}
- sub_tree = init_raknet(tvb, pinfo, tree, &offset);
- if (sub_tree != NULL) {
+/*
+ * Called by dissectors for protocols that run atop RakNet/UDP.
+ */
+void
+raknet_add_udp_dissector(guint32 port, const dissector_handle_t handle) {
+ /*
+ * Register ourselves as the handler for that port number
+ * over TCP.
+ */
+ dissector_add_uint("udp.port", port, raknet_handle);
- item_size = 8;
- proto_tree_add_item(sub_tree, hf_raknet_general_elapsed_time, tvb,
- offset, item_size, ENC_BIG_ENDIAN);
- offset += item_size;
+ /*
+ * And register them in *our* table for that port.
+ */
+ dissector_add_uint("raknet.port", port, handle);
+}
- item_size = 16;
- proto_tree_add_item(sub_tree, hf_raknet_general_magic, tvb, offset,
- item_size, ENC_NA);
- }
- return tvb_reported_length(tvb);
+void
+raknet_delete_udp_dissector(guint32 port, const dissector_handle_t handle) {
+ dissector_delete_uint("udp.port", port, raknet_handle);
+ dissector_delete_uint("raknet.port", port, handle);
}
-static int
-raknet_dissect_0x01(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
- void *data _U_)
-{
- proto_tree *sub_tree;
- gint item_size;
- gint offset;
+static raknet_session_state_t*
+raknet_get_session_state(packet_info *pinfo) {
+ conversation_t* conversation;
+ raknet_session_state_t* state;
- sub_tree = init_raknet(tvb, pinfo, tree, &offset);
+ conversation = find_or_create_conversation(pinfo);
+ state = (raknet_session_state_t*)conversation_get_proto_data(conversation, proto_raknet);
- if (sub_tree != NULL) {
+ if (state == NULL) {
+ state = (raknet_session_state_t*)wmem_alloc(wmem_file_scope(), sizeof(raknet_session_state_t));
+ state->use_encryption = FALSE;
+ state->subdissector = NULL;
+ conversation_add_proto_data(conversation, proto_raknet, state);
+ }
- item_size = 8;
- proto_tree_add_item(sub_tree, hf_raknet_general_elapsed_time, tvb,
- offset, item_size, ENC_BIG_ENDIAN);
- offset += item_size;
+ return state;
+}
- item_size = 16;
- proto_tree_add_item(sub_tree, hf_raknet_general_magic, tvb, offset,
- item_size, ENC_NA);
+void
+raknet_conversation_set_dissector(packet_info *pinfo, const dissector_handle_t handle) {
+ raknet_session_state_t *state;
+
+ state = raknet_get_session_state(pinfo);
+ state->subdissector = handle;
+}
+
+static void
+raknet_dissect_system_address(proto_tree *tree, int hf, tvbuff_t *tvb, gint *offset) {
+ proto_item *ti;
+ proto_tree *sub_tree;
+ guint8 ip_version;
+ guint32 v4_addr;
+ guint16 port;
+ address addr;
+ gchar *addr_str;
+
+ ip_version = tvb_get_guint8(tvb, *offset);
+ switch (ip_version) {
+ case 4:
+ /*
+ * IPv4 addresses are bit-inverted to prevent routers from
+ * changing them. See ..RakNet/Source/BitStream.h
+ * (BitStream::Write)
+ */
+ v4_addr = ~tvb_get_ipv4(tvb, *offset + 1);
+ port = tvb_get_ntohs(tvb, *offset + 1 + 4);
+
+ set_address(&addr, AT_IPv4, sizeof(v4_addr), &v4_addr);
+ addr_str = address_to_display(wmem_packet_scope(), &addr);
+
+ ti = proto_tree_add_string_format_value(tree, hf, tvb, *offset, 1 + 4 + 2,
+ "", "%s:%" G_GUINT16_FORMAT, addr_str, port);
+ sub_tree = proto_item_add_subtree(ti, ett_raknet_system_address);
+ proto_tree_add_item(sub_tree, hf_raknet_ip_version, tvb, *offset, 1, ENC_NA);
+ proto_tree_add_ipv4(sub_tree, hf_raknet_ipv4_address, tvb, *offset + 1, 4, v4_addr);
+ proto_tree_add_item(sub_tree, hf_raknet_port, tvb, *offset + 1 + 4, 2, ENC_BIG_ENDIAN);
+ *offset += 1 + 4 + 2;
+ break;
+ case 6:
+ addr_str = tvb_ip6_to_str(tvb, *offset + 1);
+ port = tvb_get_ntohs(tvb, *offset + 1 + 16);
+
+ ti = proto_tree_add_string_format_value(tree, hf, tvb, *offset, 1 + 16 + 2,
+ "", "[%s]:%" G_GUINT16_FORMAT, addr_str, port);
+ sub_tree = proto_item_add_subtree(ti, ett_raknet_system_address);
+ proto_tree_add_item(sub_tree, hf_raknet_ip_version, tvb, *offset, 1, ENC_NA);
+ proto_tree_add_item(sub_tree, hf_raknet_ipv6_address, tvb, *offset + 1, 16, ENC_NA);
+ proto_tree_add_item(sub_tree, hf_raknet_port, tvb, *offset + 1 + 16, 2, ENC_BIG_ENDIAN);
+ *offset += 1 + 16 + 2;
+ break;
+ default:
+ THROW(ReportedBoundsError);
}
- return tvb_reported_length(tvb);
}
static int
-raknet_dissect_0x02(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
- void *data _U_)
+raknet_dissect_unconnected_ping(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
+ void *data _U_)
{
proto_tree *sub_tree;
- gint item_size;
gint offset;
- sub_tree = init_raknet(tvb, pinfo, tree, &offset);
-
- if (sub_tree != NULL) {
+ sub_tree = init_raknet_offline_message(tvb, pinfo, tree, &offset);
+ if (sub_tree) {
+ gint item_size;
item_size = 8;
- proto_tree_add_item(sub_tree, hf_raknet_general_elapsed_time, tvb,
+ proto_tree_add_item(sub_tree, hf_raknet_timestamp, tvb,
offset, item_size, ENC_BIG_ENDIAN);
offset += item_size;
item_size = 16;
- proto_tree_add_item(sub_tree, hf_raknet_general_magic, tvb, offset,
+ proto_tree_add_item(sub_tree, hf_raknet_offline_message_data_id, tvb, offset,
item_size, ENC_NA);
+ offset += item_size;
+
+ item_size = 8;
+ proto_tree_add_item(sub_tree, hf_raknet_client_guid, tvb,
+ offset, item_size, ENC_NA);
+ offset += item_size;
}
+
return tvb_reported_length(tvb);
}
static int
-raknet_dissect_0x05(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
- void *data _U_)
+raknet_dissect_open_connection_request_1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
+ void *data _U_)
{
proto_tree *sub_tree;
- gint item_size;
gint offset;
- sub_tree = init_raknet(tvb, pinfo, tree, &offset);
-
- if (sub_tree != NULL) {
+ sub_tree = init_raknet_offline_message(tvb, pinfo, tree, &offset);
+ if (sub_tree) {
+ gint item_size;
item_size = 16;
- proto_tree_add_item(sub_tree, hf_raknet_general_magic, tvb, offset,
+ proto_tree_add_item(sub_tree, hf_raknet_offline_message_data_id, tvb, offset,
item_size, ENC_NA);
offset += item_size;
item_size = 1;
- proto_tree_add_item(sub_tree, hf_raknet_general_raknet_proto_ver, tvb,
+ proto_tree_add_item(sub_tree, hf_raknet_raknet_proto_ver, tvb,
offset, item_size, ENC_BIG_ENDIAN);
offset += item_size;
item_size = -1; /* -1 read to end of tvb buffer */
- proto_tree_add_item(sub_tree, hf_raknet_0x05_null_padding, tvb, offset,
+ proto_tree_add_item(sub_tree, hf_raknet_null_padding, tvb, offset,
item_size, ENC_NA);
}
+
return tvb_reported_length(tvb);
}
static int
-raknet_dissect_0x06(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
- void *data _U_)
+raknet_dissect_open_connection_reply_1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
+ void *data _U_)
{
proto_tree *sub_tree;
- gint item_size;
gint offset;
- sub_tree = init_raknet(tvb, pinfo, tree, &offset);
-
- if (sub_tree != NULL) {
+ sub_tree = init_raknet_offline_message(tvb, pinfo, tree, &offset);
+ if (sub_tree) {
+ gint item_size;
+ raknet_session_state_t* state;
item_size = 16;
- proto_tree_add_item(sub_tree, hf_raknet_general_magic, tvb, offset,
+ proto_tree_add_item(sub_tree, hf_raknet_offline_message_data_id, tvb, offset,
item_size, ENC_NA);
offset += item_size;
item_size = 8;
- proto_tree_add_item(sub_tree, hf_raknet_general_server_id, tvb, offset,
- item_size, ENC_BIG_ENDIAN);
+ proto_tree_add_item(sub_tree, hf_raknet_server_guid, tvb, offset,
+ item_size, ENC_NA);
offset += item_size;
+ state = raknet_get_session_state(pinfo);
+ state->use_encryption = tvb_get_guint8(tvb, offset) ? TRUE : FALSE;
+
item_size = 1;
- proto_tree_add_item(sub_tree, hf_raknet_0x06_server_security, tvb,
- offset, item_size, ENC_BIG_ENDIAN);
+ proto_tree_add_item(sub_tree, hf_raknet_use_encryption, tvb,
+ offset, item_size, ENC_NA);
offset += item_size;
+ if (state->use_encryption) {
+ item_size = 4;
+ proto_tree_add_item(sub_tree, hf_raknet_cookie, tvb,
+ offset, item_size, ENC_BIG_ENDIAN);
+ offset += item_size;
+
+ item_size = 64;
+ proto_tree_add_item(sub_tree, hf_raknet_server_public_key, tvb,
+ offset, item_size, ENC_NA);
+ offset += item_size;
+ }
+
item_size = 2;
- proto_tree_add_item(sub_tree, hf_raknet_general_mtu_size, tvb, offset,
+ proto_tree_add_item(sub_tree, hf_raknet_mtu_size, tvb, offset,
item_size, ENC_BIG_ENDIAN);
+ offset += item_size;
}
+
return tvb_reported_length(tvb);
}
static int
-raknet_dissect_0x07(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
- void *data _U_)
+raknet_dissect_open_connection_request_2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
+ void *data _U_)
{
proto_tree *sub_tree;
- gint item_size;
gint offset;
- sub_tree = init_raknet(tvb, pinfo, tree, &offset);
-
- if (sub_tree != NULL) {
+ sub_tree = init_raknet_offline_message(tvb, pinfo, tree, &offset);
+ if (sub_tree) {
+ gint item_size;
+ raknet_session_state_t* state;
item_size = 16;
- proto_tree_add_item(sub_tree, hf_raknet_general_magic, tvb, offset,
+ proto_tree_add_item(sub_tree, hf_raknet_offline_message_data_id, tvb, offset,
item_size, ENC_NA);
offset += item_size;
- item_size = 1;
- proto_tree_add_item(sub_tree, hf_raknet_general_security, tvb, offset,
- item_size, ENC_BIG_ENDIAN);
- offset += item_size;
-
- item_size = 4;
- proto_tree_add_item(sub_tree, hf_raknet_0x07_cookie, tvb, offset,
- item_size, ENC_BIG_ENDIAN);
- offset += item_size;
+ state = raknet_get_session_state(pinfo);
+ if (state->use_encryption) {
+ gboolean client_wrote_challenge;
+
+ item_size = 4;
+ proto_tree_add_item(sub_tree, hf_raknet_cookie, tvb, offset,
+ item_size, ENC_BIG_ENDIAN);
+ offset += item_size;
+
+ client_wrote_challenge = tvb_get_guint8(tvb, offset) ? TRUE : FALSE;
+ item_size = 1;
+ proto_tree_add_item(sub_tree, hf_raknet_client_wrote_challenge, tvb, offset,
+ item_size, ENC_NA);
+ offset += item_size;
+
+ if (client_wrote_challenge) {
+ item_size = RAKNET_CHALLENGE_LENGTH;
+ proto_tree_add_item(sub_tree, hf_raknet_client_challenge, tvb,
+ offset, item_size, ENC_NA);
+ offset += item_size;
+ }
+ }
- item_size = 2;
- proto_tree_add_item(sub_tree, hf_raknet_general_udp_port, tvb, offset,
- item_size, ENC_BIG_ENDIAN);
- offset += item_size;
+ raknet_dissect_system_address(sub_tree, hf_raknet_server_address, tvb, &offset);
item_size = 2;
- proto_tree_add_item(sub_tree, hf_raknet_general_mtu_size, tvb, offset,
+ proto_tree_add_item(sub_tree, hf_raknet_mtu_size, tvb, offset,
item_size, ENC_BIG_ENDIAN);
offset += item_size;
item_size = 8;
- proto_tree_add_item(sub_tree, hf_raknet_general_client_id, tvb, offset,
- item_size, ENC_BIG_ENDIAN);
+ proto_tree_add_item(sub_tree, hf_raknet_client_guid, tvb, offset,
+ item_size, ENC_NA);
+ offset += item_size;
}
+
return tvb_reported_length(tvb);
}
static int
-raknet_dissect_0x08(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
- void *data _U_)
+raknet_dissect_open_connection_reply_2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
+ void *data _U_)
{
proto_tree *sub_tree;
- gint item_size;
gint offset;
- sub_tree = init_raknet(tvb, pinfo, tree, &offset);
-
- if (sub_tree != NULL) {
+ sub_tree = init_raknet_offline_message(tvb, pinfo, tree, &offset);
+ if (sub_tree) {
+ gint item_size;
+ gboolean use_encryption;
item_size = 16;
- proto_tree_add_item(sub_tree, hf_raknet_general_magic, tvb, offset,
+ proto_tree_add_item(sub_tree, hf_raknet_offline_message_data_id, tvb, offset,
item_size, ENC_NA);
offset += item_size;
item_size = 8;
- proto_tree_add_item(sub_tree, hf_raknet_general_server_id, tvb, offset,
- item_size, ENC_BIG_ENDIAN);
- offset += item_size;
-
- item_size = 1;
- proto_tree_add_item(sub_tree, hf_raknet_general_security, tvb, offset,
- item_size, ENC_BIG_ENDIAN);
+ proto_tree_add_item(sub_tree, hf_raknet_server_guid, tvb, offset,
+ item_size, ENC_NA);
offset += item_size;
- item_size = 4;
- proto_tree_add_item(sub_tree, hf_raknet_0x07_cookie, tvb, offset,
- item_size, ENC_BIG_ENDIAN);
- offset += item_size;
+ raknet_dissect_system_address(sub_tree, hf_raknet_client_address, tvb, &offset);
item_size = 2;
- proto_tree_add_item(sub_tree, hf_raknet_general_udp_port, tvb, offset,
+ proto_tree_add_item(sub_tree, hf_raknet_mtu_size, tvb, offset,
item_size, ENC_BIG_ENDIAN);
offset += item_size;
- item_size = 2;
- proto_tree_add_item(sub_tree, hf_raknet_general_mtu_size, tvb, offset,
- item_size, ENC_BIG_ENDIAN);
- offset += item_size;
+ use_encryption = tvb_get_guint8(tvb, offset) ? TRUE : FALSE;
item_size = 1;
- proto_tree_add_item(sub_tree, hf_raknet_general_security, tvb, offset,
- item_size, ENC_BIG_ENDIAN);
+ proto_tree_add_item(sub_tree, hf_raknet_use_encryption, tvb, offset,
+ item_size, ENC_NA);
+ offset += item_size;
+
+ if (use_encryption) {
+ item_size = RAKNET_ANSWER_LENGTH;
+ proto_tree_add_item(sub_tree, hf_raknet_server_answer, tvb, offset,
+ item_size, ENC_NA);
+ offset += item_size;
+ }
}
+
return tvb_reported_length(tvb);
}
static int
-raknet_dissect_0x19(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
- void *data _U_)
+raknet_dissect_incompatible_protocol_version(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
+ void *data _U_)
{
proto_tree *sub_tree;
- gint item_size;
gint offset;
- sub_tree = init_raknet(tvb, pinfo, tree, &offset);
-
- if (sub_tree != NULL) {
+ sub_tree = init_raknet_offline_message(tvb, pinfo, tree, &offset);
+ if (sub_tree) {
+ gint item_size;
item_size = 1;
- proto_tree_add_item(sub_tree, hf_raknet_general_raknet_proto_ver, tvb,
+ proto_tree_add_item(sub_tree, hf_raknet_raknet_proto_ver, tvb,
offset, item_size, ENC_BIG_ENDIAN);
offset += item_size;
item_size = 16;
- proto_tree_add_item(sub_tree, hf_raknet_general_magic, tvb, offset,
+ proto_tree_add_item(sub_tree, hf_raknet_offline_message_data_id, tvb, offset,
item_size, ENC_NA);
offset += item_size;
item_size = 8;
- proto_tree_add_item(sub_tree, hf_raknet_general_server_id, tvb, offset,
- item_size, ENC_BIG_ENDIAN);
+ proto_tree_add_item(sub_tree, hf_raknet_server_guid, tvb, offset,
+ item_size, ENC_NA);
}
+
return tvb_reported_length(tvb);
}
static int
-raknet_dissect_0x1C(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
- void *data _U_)
+raknet_dissect_connection_failed(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
+ void *data _U_)
{
proto_tree *sub_tree;
- gint item_size;
- gint str_size;
gint offset;
- sub_tree = init_raknet(tvb, pinfo, tree, &offset);
+ sub_tree = init_raknet_offline_message(tvb, pinfo, tree, &offset);
+ if (sub_tree) {
+ gint item_size;
+
+ item_size = 16;
+ proto_tree_add_item(sub_tree, hf_raknet_offline_message_data_id, tvb, offset,
+ item_size, ENC_NA);
+ offset += item_size;
+
+ item_size = 8;
+ proto_tree_add_item(sub_tree, hf_raknet_server_guid, tvb, offset,
+ item_size, ENC_NA);
+ offset += item_size;
+ }
+
+ return tvb_reported_length(tvb);
+}
+
+static int
+raknet_dissect_unconnected_pong(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
+ void *data _U_)
+{
+ proto_tree *sub_tree;
+ gint offset;
- if (sub_tree != NULL) {
+ sub_tree = init_raknet_offline_message(tvb, pinfo, tree, &offset);
+ if (sub_tree) {
+ gint item_size;
+ guint32 str_size;
item_size = 8;
- proto_tree_add_item(sub_tree, hf_raknet_general_elapsed_time, tvb,
+ proto_tree_add_item(sub_tree, hf_raknet_timestamp, tvb,
offset, item_size, ENC_BIG_ENDIAN);
offset += item_size;
item_size = 8;
- proto_tree_add_item(sub_tree, hf_raknet_general_server_id, tvb, offset,
- item_size, ENC_BIG_ENDIAN);
+ proto_tree_add_item(sub_tree, hf_raknet_server_guid, tvb, offset,
+ item_size, ENC_NA);
offset += item_size;
item_size = 16;
- proto_tree_add_item(sub_tree, hf_raknet_general_magic, tvb, offset,
+ proto_tree_add_item(sub_tree, hf_raknet_offline_message_data_id, tvb, offset,
item_size, ENC_NA);
offset += item_size;
/* raknet precedes strings with a short (2 bytes) holding string length. */
- str_size = tvb_get_ntohs(tvb, offset);
item_size = 2;
- proto_tree_add_item(sub_tree, hf_raknet_0x1C_server_id_str_len, tvb,
- offset, item_size, ENC_BIG_ENDIAN);
+ proto_tree_add_item_ret_uint(sub_tree, hf_raknet_0x1C_server_id_str_len, tvb,
+ offset, item_size, ENC_BIG_ENDIAN, &str_size);
offset += item_size;
proto_tree_add_item(sub_tree, hf_raknet_0x1C_server_id_str, tvb, offset,
str_size, ENC_NA|ENC_ASCII);
}
+
+ return tvb_reported_length(tvb);
+}
+
+static int
+raknet_dissect_connected_ping(tvbuff_t *tvb, packet_info *pinfo _U_,
+ proto_tree *tree, void* data _U_)
+{
+ if (tree) {
+ gint item_size;
+ gint offset = 1;
+
+ item_size = 8;
+ proto_tree_add_item(tree, hf_raknet_timestamp, tvb,
+ offset, item_size, ENC_BIG_ENDIAN);
+ offset += item_size;
+ }
+ return tvb_reported_length(tvb);
+}
+
+static int
+raknet_dissect_connected_pong(tvbuff_t *tvb, packet_info *pinfo _U_,
+ proto_tree *tree, void* data _U_)
+{
+ if (tree) {
+ gint item_size;
+ gint offset = 1;
+
+ item_size = 8;
+ proto_tree_add_item(tree, hf_raknet_timestamp, tvb,
+ offset, item_size, ENC_BIG_ENDIAN);
+ offset += item_size;
+
+ item_size = 8;
+ proto_tree_add_item(tree, hf_raknet_timestamp, tvb,
+ offset, item_size, ENC_BIG_ENDIAN);
+ offset += item_size;
+ }
+ return tvb_reported_length(tvb);
+}
+
+static int
+raknet_dissect_connection_request(tvbuff_t *tvb, packet_info *pinfo _U_,
+ proto_tree *tree, void* data _U_)
+{
+ if (tree) {
+ gint item_size;
+ gint offset = 1;
+ gboolean use_encryption;
+
+ item_size = 8;
+ proto_tree_add_item(tree, hf_raknet_client_guid, tvb, offset,
+ item_size, ENC_NA);
+ offset += item_size;
+
+ item_size = 8;
+ proto_tree_add_item(tree, hf_raknet_timestamp, tvb,
+ offset, item_size, ENC_BIG_ENDIAN);
+ offset += item_size;
+
+ use_encryption = tvb_get_guint8(tvb, offset) ? TRUE : FALSE;
+
+ item_size = 1;
+ proto_tree_add_item(tree, hf_raknet_use_encryption, tvb, offset,
+ item_size, ENC_NA);
+ offset += item_size;
+
+ if (use_encryption) {
+ gboolean use_client_key;
+
+ item_size = RAKNET_PROOF_LENGTH;
+ proto_tree_add_item(tree, hf_raknet_client_proof, tvb, offset,
+ item_size, ENC_NA);
+ offset += item_size;
+
+ use_client_key = tvb_get_guint8(tvb, offset) ? TRUE : FALSE;
+
+ item_size = 1;
+ proto_tree_add_item(tree, hf_raknet_use_client_key, tvb, offset,
+ item_size, ENC_NA);
+ offset += item_size;
+
+ if (use_client_key) {
+ item_size = RAKNET_IDENTITY_LENGTH;
+ proto_tree_add_item(tree, hf_raknet_client_identity, tvb, offset,
+ item_size, ENC_NA);
+ offset += item_size;
+ }
+ }
+
+ item_size = tvb_captured_length_remaining(tvb, offset);
+ proto_tree_add_item(tree, hf_raknet_password, tvb, offset,
+ item_size, ENC_NA);
+ }
+ return tvb_reported_length(tvb);
+}
+
+static int
+raknet_dissect_connection_request_accepted(tvbuff_t *tvb, packet_info *pinfo _U_,
+ proto_tree *tree, void* data _U_)
+{
+ if (tree) {
+ gint item_size;
+ gint offset = 1;
+ gint i;
+
+ raknet_dissect_system_address(tree, hf_raknet_client_address, tvb, &offset);
+
+ item_size = 2;
+ proto_tree_add_item(tree, hf_raknet_system_index, tvb, offset,
+ item_size, ENC_BIG_ENDIAN);
+ offset += item_size;
+
+ for (i = 0; i < RAKNET_NUMBER_OF_INTERNAL_IDS; i++) {
+ raknet_dissect_system_address(tree, hf_raknet_internal_address, tvb, &offset);
+ }
+
+ item_size = 8;
+ proto_tree_add_item(tree, hf_raknet_timestamp, tvb,
+ offset, item_size, ENC_BIG_ENDIAN);
+ offset += item_size;
+
+ item_size = 8;
+ proto_tree_add_item(tree, hf_raknet_timestamp, tvb,
+ offset, item_size, ENC_BIG_ENDIAN);
+ offset += item_size;
+ }
+ return tvb_reported_length(tvb);
+}
+
+static int
+raknet_dissect_new_incoming_connection(tvbuff_t *tvb, packet_info *pinfo _U_,
+ proto_tree *tree, void* data _U_)
+{
+ if (tree) {
+ gint item_size;
+ gint offset = 1;
+ gint i;
+
+ raknet_dissect_system_address(tree, hf_raknet_server_address, tvb, &offset);
+
+ for (i = 0; i < RAKNET_NUMBER_OF_INTERNAL_IDS; i++) {
+ raknet_dissect_system_address(tree, hf_raknet_internal_address, tvb, &offset);
+ }
+
+ item_size = 8;
+ proto_tree_add_item(tree, hf_raknet_timestamp, tvb,
+ offset, item_size, ENC_BIG_ENDIAN);
+ offset += item_size;
+
+ item_size = 8;
+ proto_tree_add_item(tree, hf_raknet_timestamp, tvb,
+ offset, item_size, ENC_BIG_ENDIAN);
+ offset += item_size;
+ }
return tvb_reported_length(tvb);
}
/*
* Protocol definition and handlers.
*/
-static const struct raknet_handler_entry raknet_handler[] = {
+struct raknet_handler_entry {
+ value_string vs;
+ dissector_t dissector_fp;
+};
+
+static const struct raknet_handler_entry raknet_offline_message_handlers[] = {
/*
* Ref: ..RakNet/Source/MessageIdentifiers.h
+ * Ref: ..RakNet/Source/RakPeer.cpp (ProcessOfflineNetworkPacket)
*/
- { { 0x0, "ID_CONNECTED_PING" },
- raknet_dissect_0x00 },
- { { 0x1, "ID_UNCONNECTED_PING" },
- raknet_dissect_0x01 },
- { { 0x2, "ID_UNCONNECTED_PING_OPEN_CONNECTIONS" },
- raknet_dissect_0x02 },
- { { 0x5, "ID_OPEN_CONNECTION_REQUEST_1" },
- raknet_dissect_0x05 },
- { { 0x6, "ID_OPEN_CONNECTION_REPLY_1" },
- raknet_dissect_0x06 },
- { { 0x7, "ID_OPEN_CONNECTION_REQUEST_2" },
- raknet_dissect_0x07 },
- { { 0x8, "ID_OPEN_CONNECTION_REPLY_2" },
- raknet_dissect_0x08 },
- { { 0x19, "ID_INCOMPATIBLE_PROTOCOL_VERSION" },
- raknet_dissect_0x19 },
- { { 0x1C, "ID_UNCONNECTED_PONG" },
- raknet_dissect_0x1C },
+ { { 0x1, "Unconnected Ping" },
+ raknet_dissect_unconnected_ping },
+ { { 0x2, "Unconnected Ping Open Connections" },
+ raknet_dissect_unconnected_ping },
+ { { 0x5, "Open Connection Request 1" },
+ raknet_dissect_open_connection_request_1 },
+ { { 0x6, "Open Connection Reply 1" },
+ raknet_dissect_open_connection_reply_1 },
+ { { 0x7, "Open Connection Request 2" },
+ raknet_dissect_open_connection_request_2 },
+ { { 0x8, "Open Connection Reply 2" },
+ raknet_dissect_open_connection_reply_2 },
+ { { 0xD, "Out Of Band Internal" },
+ raknet_dissect_connection_failed },
+ { { 0x11, "Connection Attempt Failed" },
+ raknet_dissect_connection_failed },
+ { { 0x12, "Already Connected" },
+ raknet_dissect_connection_failed },
+ { { 0x14, "No Free Incoming Connections" },
+ raknet_dissect_connection_failed },
+ { { 0x17, "Connection Banned" },
+ raknet_dissect_connection_failed },
+ { { 0x19, "Incompatible Protocol Version" },
+ raknet_dissect_incompatible_protocol_version },
+ { { 0x1A, "IP Recently Connected" },
+ raknet_dissect_connection_failed },
+ { { 0x1C, "Unconnected Pong" },
+ raknet_dissect_unconnected_pong },
};
-#define RAKNET_PACKET_ID_COUNT \
- (sizeof(raknet_handler) / sizeof(raknet_handler[0]))
+static const struct raknet_handler_entry raknet_system_message_handlers[] = {
+ /*
+ * Ref: ..RakNet/Source/MessageIdentifiers.h
+ * Ref: ..RakNet/Source/RakPeer.cpp (RakPeer::RunUpdateCycle)
+ */
+ { { 0x00, "Connected Ping" },
+ raknet_dissect_connected_ping },
+ { { 0x03, "Connected Pong" },
+ raknet_dissect_connected_pong },
+ { { 0x09, "Connection Request" },
+ raknet_dissect_connection_request },
+ { { 0x10, "Connection Request Accepted" },
+ raknet_dissect_connection_request_accepted },
+ { { 0x13, "New Incoming Connection" },
+ raknet_dissect_new_incoming_connection },
+};
/*
- * Look up packet id to packet name, value_string is wireshark type.
+ * Look up table from message ID to name.
*/
-static value_string packet_names[RAKNET_PACKET_ID_COUNT+1];
+static value_string raknet_offline_message_names[array_length(raknet_offline_message_handlers)+1];
+static value_string raknet_system_message_names[array_length(raknet_system_message_handlers)+1];
static void
-raknet_init_packet_names(void)
+raknet_init_message_names(void)
{
unsigned int i;
- for (i = 0; i < RAKNET_PACKET_ID_COUNT; i++) {
- packet_names[i].value = raknet_handler[i].vs.value;
- packet_names[i].strptr = raknet_handler[i].vs.strptr;
+ for (i = 0; i < array_length(raknet_offline_message_handlers); i++) {
+ raknet_offline_message_names[i].value = raknet_offline_message_handlers[i].vs.value;
+ raknet_offline_message_names[i].strptr = raknet_offline_message_handlers[i].vs.strptr;
}
- packet_names[RAKNET_PACKET_ID_COUNT].value = 0;
- packet_names[RAKNET_PACKET_ID_COUNT].strptr = NULL;
+ raknet_offline_message_names[array_length(raknet_offline_message_handlers)].value = 0;
+ raknet_offline_message_names[array_length(raknet_offline_message_handlers)].strptr = NULL;
+
+ for (i = 0; i < array_length(raknet_system_message_handlers); i++) {
+ raknet_system_message_names[i].value = raknet_system_message_handlers[i].vs.value;
+ raknet_system_message_names[i].strptr = raknet_system_message_handlers[i].vs.strptr;
+ }
+ raknet_system_message_names[array_length(raknet_system_message_handlers)].value = 0;
+ raknet_system_message_names[array_length(raknet_system_message_handlers)].strptr = NULL;
}
/*
@@ -436,11 +884,11 @@ raknet_init_packet_names(void)
* Offset is updated for the caller.
*/
static proto_tree *
-init_raknet(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint *offset)
+init_raknet_offline_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint *offset)
{
proto_tree *sub_tree;
proto_item *ti;
- guint8 packet_id;
+ guint8 message_id;
*offset = 0;
@@ -450,23 +898,614 @@ init_raknet(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint *offset)
ti = proto_tree_add_item(tree, proto_raknet, tvb, 0, -1, ENC_NA);
sub_tree = proto_item_add_subtree(ti, ett_raknet);
- packet_id = tvb_get_guint8(tvb, *offset);
- proto_tree_add_item(sub_tree, hf_raknet_packet_id, tvb, *offset,
+ message_id = tvb_get_guint8(tvb, *offset);
+ proto_tree_add_item(sub_tree, hf_raknet_offline_message_id, tvb, *offset,
1, ENC_BIG_ENDIAN);
*offset += 1;
- col_add_fstr(pinfo->cinfo, COL_INFO, "%s",
- val_to_str(packet_id, packet_names, "Unknown (%#x)"));
+ col_add_str(pinfo->cinfo, COL_INFO,
+ val_to_str(message_id, raknet_offline_message_names, "Unknown offline message: %#x"));
/*
* Append description to the raknet item.
*/
- proto_item_append_text(ti, ", Packet id %#x", packet_id);
-
+ proto_item_append_text(ti, ", Offline message ID %#x", message_id);
return sub_tree;
}
+static int
+raknet_dissect_ACK(tvbuff_t *tvb, packet_info *pinfo,
+ proto_tree *tree, void* data)
+{
+ gint item_size;
+ gint offset = 0;
+ proto_tree *sub_tree;
+ guint32 count;
+ guint32 i;
+
+ if (*(gboolean*)data) {
+ col_add_str(pinfo->cinfo, COL_INFO, "ACK");
+ }
+ else {
+ col_add_str(pinfo->cinfo, COL_INFO, "NAK");
+ }
+
+ item_size = 2;
+ proto_tree_add_item_ret_uint(tree, hf_raknet_NACK_record_count, tvb,
+ offset, item_size, ENC_BIG_ENDIAN, &count);
+ offset += item_size;
+
+ for (i = 0; i < count; i++) {
+ proto_item *ti;
+ guint32 max;
+ guint32 min;
+
+ if (i == 0) {
+ col_append_str(pinfo->cinfo, COL_INFO, " ");
+ }
+ else {
+ col_append_str(pinfo->cinfo, COL_INFO, ", ");
+ }
+
+ if (tvb_get_guint8(tvb, offset)) { /* maxEqualToMin */
+ min = tvb_get_guint24(tvb, offset + 1, ENC_LITTLE_ENDIAN);
+
+ col_append_fstr(pinfo->cinfo, COL_INFO, "#%" G_GUINT32_FORMAT, min);
+
+ item_size = 1 + 3;
+ ti = proto_tree_add_string_format_value(tree, hf_raknet_packet_number_range, tvb,
+ offset, 1 + 3, "",
+ "%" G_GUINT32_FORMAT " .. %" G_GUINT32_FORMAT,
+ min, min);
+ sub_tree = proto_item_add_subtree(ti, ett_raknet_packet_number_range);
+
+ item_size = 1;
+ proto_tree_add_item(sub_tree, hf_raknet_range_max_equal_to_min, tvb,
+ offset, item_size, ENC_NA);
+ offset += item_size;
+
+ item_size = 3;
+ proto_tree_add_item(sub_tree, hf_raknet_packet_number_min, tvb,
+ offset, item_size, ENC_LITTLE_ENDIAN);
+ offset += item_size;
+ }
+ else {
+ min = tvb_get_guint24(tvb, offset + 1 , ENC_LITTLE_ENDIAN);
+ max = tvb_get_guint24(tvb, offset + 1 + 3, ENC_LITTLE_ENDIAN);
+
+ col_append_fstr(pinfo->cinfo, COL_INFO,
+ "#%" G_GUINT32_FORMAT "..%" G_GUINT32_FORMAT,
+ min, max);
+
+ item_size = 1 + 3 + 3;
+ ti = proto_tree_add_string_format_value(tree, hf_raknet_packet_number_range, tvb,
+ offset, 1 + 3 + 3, "",
+ "%" G_GUINT32_FORMAT " .. %" G_GUINT32_FORMAT, min, max);
+ sub_tree = proto_item_add_subtree(ti, ett_raknet_packet_number_range);
+
+ item_size = 1;
+ proto_tree_add_item(sub_tree, hf_raknet_range_max_equal_to_min, tvb,
+ offset, item_size, ENC_NA);
+ offset += item_size;
+
+ item_size = 3;
+ proto_tree_add_item(sub_tree, hf_raknet_packet_number_min, tvb,
+ offset, item_size, ENC_LITTLE_ENDIAN);
+ offset += item_size;
+
+ item_size = 3;
+ proto_tree_add_item(sub_tree, hf_raknet_packet_number_max, tvb,
+ offset, item_size, ENC_LITTLE_ENDIAN);
+ offset += item_size;
+ }
+ }
+
+ return tvb_captured_length(tvb);
+}
+
+static int
+raknet_dissect_common_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *raknet_tree, void *data)
+{
+ gint item_size;
+ gint offset = 0;
+ gboolean *has_multiple_messages;
+ proto_item *ti;
+ proto_item *raknet_ti;
+ proto_item *msg_ti;
+ proto_tree *msg_tree;
+ guint64 msg_flags;
+ guint32 payload_bits;
+ guint32 payload_octets;
+ raknet_reliability_t reliability;
+ gboolean has_split_packet;
+ guint8 message_id;
+ gint message_size;
+ proto_tree *payload_tree;
+ tvbuff_t* next_tvb;
+ gboolean next_tvb_is_subset;
+ dissector_handle_t next_dissector;
+ gint dissected;
+ heur_dtbl_entry_t *hdtbl_entry;
+ const int* flag_flds[] = {
+ &hf_raknet_message_reliability,
+ &hf_raknet_message_has_split_packet,
+ NULL
+ };
+
+ has_multiple_messages = (gboolean*)data;
+ raknet_ti = proto_tree_get_parent(raknet_tree);
+
+ msg_ti = proto_tree_add_item(raknet_tree, hf_raknet_message, tvb, offset, -1, ENC_NA);
+ msg_tree = proto_item_add_subtree(msg_ti, ett_raknet_message);
+ proto_item_append_text(msg_ti, ", ");
+
+ item_size = 1;
+ proto_tree_add_bitmask_ret_uint64(msg_tree, tvb, offset, hf_raknet_message_flags,
+ ett_raknet_message_flags, flag_flds, ENC_NA, &msg_flags);
+ offset += item_size;
+
+ item_size = 2;
+ ti = proto_tree_add_item_ret_uint(msg_tree, hf_raknet_payload_length, tvb,
+ offset, item_size, ENC_BIG_ENDIAN, &payload_bits);
+ offset += item_size;
+ payload_octets = payload_bits / 8 + (payload_bits % 8 > 0); /* ceil(bits / 8) */
+ proto_item_append_text(ti, " bits (%" G_GUINT32_FORMAT " octets)", payload_octets);
+
+ reliability = (raknet_reliability_t)((msg_flags >> 5) & 0x07);
+ has_split_packet = (msg_flags >> 4) & 0x01 ? TRUE : FALSE;
+
+ if (reliability == RAKNET_RELIABLE ||
+ reliability == RAKNET_RELIABLE_SEQUENCED ||
+ reliability == RAKNET_RELIABLE_ORDERED ) {
+
+ item_size = 3;
+ proto_tree_add_item(msg_tree, hf_raknet_reliable_message_number, tvb,
+ offset, item_size, ENC_LITTLE_ENDIAN);
+ offset += item_size;
+ }
+
+ if (reliability == RAKNET_UNRELIABLE_SEQUENCED ||
+ reliability == RAKNET_RELIABLE_SEQUENCED) {
+
+ item_size = 3;
+ proto_tree_add_item(msg_tree, hf_raknet_message_sequencing_index, tvb,
+ offset, item_size, ENC_LITTLE_ENDIAN);
+ offset += item_size;
+ }
+
+ if (reliability == RAKNET_UNRELIABLE_SEQUENCED ||
+ reliability == RAKNET_RELIABLE_SEQUENCED ||
+ reliability == RAKNET_RELIABLE_ORDERED) {
+
+ item_size = 3;
+ proto_tree_add_item(msg_tree, hf_raknet_message_ordering_index, tvb,
+ offset, item_size, ENC_LITTLE_ENDIAN);
+ offset += item_size;
+
+ item_size = 1;
+ proto_tree_add_item(msg_tree, hf_raknet_message_ordering_channel, tvb,
+ offset, item_size, ENC_NA);
+ offset += item_size;
+ }
+
+ if (has_split_packet) {
+ gboolean save_fragmented;
+ guint32 split_packet_count;
+ guint32 split_packet_id;
+ guint32 split_packet_index;
+ fragment_head *frag_msg;
+
+ item_size = 4;
+ proto_tree_add_item_ret_uint(msg_tree, hf_raknet_split_packet_count, tvb,
+ offset, item_size, ENC_BIG_ENDIAN, &split_packet_count);
+ offset += item_size;
+
+ item_size = 2;
+ proto_tree_add_item_ret_uint(msg_tree, hf_raknet_split_packet_id, tvb,
+ offset, item_size, ENC_BIG_ENDIAN, &split_packet_id);
+ offset += item_size;
+
+ item_size = 4;
+ proto_tree_add_item_ret_uint(msg_tree, hf_raknet_split_packet_index, tvb,
+ offset, item_size, ENC_BIG_ENDIAN, &split_packet_index);
+ offset += item_size;
+
+ /*
+ * Reassemble the fragmented packet.
+ */
+ save_fragmented = pinfo->fragmented;
+ pinfo->fragmented = TRUE;
+
+ frag_msg =
+ fragment_add_seq_check(&raknet_reassembly_table,
+ tvb, offset, pinfo,
+ split_packet_id,
+ NULL,
+ split_packet_index,
+ payload_octets,
+ split_packet_index != split_packet_count - 1);
+
+ next_tvb =
+ process_reassembled_data(tvb, offset, pinfo, "Reassembled packet",
+ frag_msg, &raknet_frag_items, NULL, msg_tree);
+
+ pinfo->fragmented = save_fragmented;
+
+ if (next_tvb) {
+ /*
+ * Reassembly done. Dissect the message as normal.
+ */
+ wmem_strbuf_t *strbuf;
+
+ strbuf = wmem_strbuf_new(wmem_packet_scope(), "");
+ wmem_strbuf_append_printf(strbuf,
+ "{Message fragment %" G_GUINT32_FORMAT "/%" G_GUINT32_FORMAT "; Reassembled} ",
+ split_packet_index + 1, split_packet_count);
+
+ proto_item_append_text(msg_ti, "%s", wmem_strbuf_get_str(strbuf));
+ col_add_str(pinfo->cinfo, COL_INFO, wmem_strbuf_get_str(strbuf));
+ col_set_fence(pinfo->cinfo, COL_INFO);
+
+ next_tvb_is_subset = FALSE;
+ }
+ else {
+ wmem_strbuf_t *strbuf;
+
+ strbuf = wmem_strbuf_new(wmem_packet_scope(), "");
+ wmem_strbuf_append_printf(strbuf,
+ "{Message fragment %" G_GUINT32_FORMAT "/%" G_GUINT32_FORMAT "}",
+ split_packet_index + 1, split_packet_count);
+
+ proto_item_append_text(msg_ti, "%s", wmem_strbuf_get_str(strbuf));
+ col_add_str(pinfo->cinfo, COL_INFO, wmem_strbuf_get_str(strbuf));
+
+ ti = proto_tree_add_item(msg_tree, hf_raknet_split_packet, tvb, offset,
+ payload_octets, ENC_NA);
+ proto_item_append_text(ti, " (%u octets)", payload_octets);
+ }
+ }
+ else {
+ next_tvb = tvb_new_subset_length(tvb, offset, payload_octets);
+ next_tvb_is_subset = TRUE;
+ }
+
+ /*
+ * At this point we can finally check if the packet has multiple
+ * messages.
+ */
+ if (! *has_multiple_messages) {
+ *has_multiple_messages =
+ tvb_reported_length_remaining(tvb, offset) > (gint)payload_octets
+ ? TRUE : FALSE;
+ }
+
+ /*
+ * And we finally have the actual size of message.
+ */
+ message_size = offset + payload_octets;
+
+ if (!next_tvb) {
+ /*
+ * It was an incomplete message fragment.
+ */
+ proto_item_set_len(msg_ti, message_size);
+ if (raknet_ti) {
+ proto_item_set_len(raknet_ti, proto_item_get_len(raknet_ti) + message_size);
+ }
+ return message_size;
+ }
+
+ message_id = tvb_get_guint8(next_tvb, 0);
+
+ /*
+ * Now we want to dissect this message. First we search for a
+ * dissector from our system message dissector table.
+ */
+ next_dissector =
+ dissector_get_uint_handle(raknet_system_message_dissectors, message_id);
+
+ if (next_dissector) {
+ /*
+ * We have a subdissector. The protocol of the message is
+ * still RakNet (e.g. 0x09 ID_CONNECTION_REQUEST) so we always
+ * insert it into our tree.
+ */
+ ti = proto_tree_add_item(msg_tree, hf_raknet_system_message, next_tvb, 0, -1, ENC_NA);
+ payload_tree = proto_item_add_subtree(ti, ett_raknet_system_message);
+
+ proto_item_append_text(ti, " (%s)",
+ val_to_str(message_id, raknet_system_message_names, "Unknown ID: %#x"));
+
+ proto_item_append_text(msg_ti, "ID %#x (%s)", message_id,
+ val_to_str(message_id, raknet_system_message_names, "Unknown"));
+
+ col_add_str(pinfo->cinfo, COL_INFO,
+ val_to_str(message_id, raknet_system_message_names, "Unknown system message ID: %#x"));
+
+ proto_tree_add_item(payload_tree, hf_raknet_system_message_id,
+ next_tvb, 0, 1, ENC_NA);
+
+ dissected =
+ call_dissector_only(next_dissector, next_tvb, pinfo, payload_tree, data);
+
+ proto_item_set_len(msg_ti, message_size);
+ if (raknet_ti) {
+ proto_item_set_len(raknet_ti, proto_item_get_len(raknet_ti) + message_size);
+ }
+
+ if (dissected >= 0) {
+ return message_size;
+ }
+ else {
+ return dissected;
+ }
+ }
+
+ /*
+ * It seems not to be a system message so use a dissector set for
+ * this conversation if any.
+ */
+ next_dissector =
+ raknet_get_session_state(pinfo)->subdissector;
+
+ /*
+ * And of course we don't know the name of message.
+ */
+ proto_item_append_text(msg_ti, "ID %#x", message_id);
+
+ /*
+ * The message belongs to a sub-protocol of RakNet so let it place
+ * its own protocol layer, but only if the packet has only one
+ * message.
+ */
+ if (*has_multiple_messages) {
+ payload_tree = msg_tree;
+ }
+ else {
+ payload_tree = proto_tree_get_root(raknet_tree);
+ }
+
+ if (next_dissector) {
+ dissected =
+ call_dissector_only(next_dissector, next_tvb, pinfo, payload_tree, data);
+
+ if (dissected > 0) {
+ goto FIX_UP_AND_RETURN;
+ }
+ else {
+ expert_add_info(pinfo, msg_tree, &ei_raknet_subdissector_failed);
+ }
+ }
+
+ /*
+ * No dissectors set for this conversation. Look up a dissector
+ * from the port table.
+ */
+ next_dissector =
+ dissector_get_uint_handle(raknet_port_dissectors, pinfo->match_uint);
+
+ if (next_dissector) {
+ dissected =
+ call_dissector_only(next_dissector, next_tvb, pinfo, payload_tree, data);
+
+ if (dissected > 0) {
+ goto FIX_UP_AND_RETURN;
+ }
+ else {
+ expert_add_info(pinfo, msg_tree, &ei_raknet_subdissector_failed);
+ }
+ }
+
+ /*
+ * We don't have a subdissector or we have one but id didn't
+ * dissect the message. Try heuristic subdissectors.
+ */
+ dissected =
+ dissector_try_heuristic(raknet_heur_subdissectors, next_tvb, pinfo, payload_tree,
+ &hdtbl_entry, data);
+ if (!dissected) {
+ col_add_fstr(pinfo->cinfo, COL_INFO, "Unknown message ID: %#x", message_id);
+
+ ti = proto_tree_add_expert(msg_tree, pinfo, &ei_raknet_unknown_message_id, next_tvb,
+ 0, 1);
+ proto_item_append_text(ti, " %#x", message_id);
+ }
+
+ FIX_UP_AND_RETURN:
+ /*
+ * Fix up the top-level item so that it doesn't include stuff for
+ * sub-protocols. In order to do this there must not be multiple
+ * messages in the packet, and the message must have been
+ * reassembled from fragments.
+ */
+ if (!*has_multiple_messages && next_tvb_is_subset) {
+ proto_item_set_len(msg_ti, message_size - payload_octets);
+ if (raknet_ti) {
+ proto_item_set_len(raknet_ti, proto_item_get_len(raknet_ti) + message_size - payload_octets);
+ }
+ }
+ else {
+ proto_item_set_len(msg_ti, message_size);
+ if (raknet_ti) {
+ proto_item_set_len(raknet_ti, proto_item_get_len(raknet_ti) + message_size);
+ }
+ }
+ return message_size;
+}
+
+static int
+raknet_dissect_connected_message(tvbuff_t *tvb, packet_info *pinfo,
+ proto_tree *root_tree, void* data _U_)
+{
+ raknet_session_state_t* state;
+ proto_item *ti;
+ proto_tree *raknet_tree;
+ gint item_size;
+ gint offset = 0;
+ guint8 msg_type;
+
+ state = raknet_get_session_state(pinfo);
+ if (state->use_encryption) {
+ /*
+ * RakNet uses ChaCha stream cipher to encrypt messages, which
+ * is currently not supported by this dissector.
+ */
+ col_add_str(pinfo->cinfo, COL_INFO, "Encrypted message");
+
+ item_size = tvb_reported_length_remaining(tvb, offset);
+ ti = proto_tree_add_expert(root_tree, pinfo, &ei_raknet_encrypted_message, tvb,
+ offset, item_size);
+ proto_item_append_text(ti, " (%d octets)", item_size);
+ return tvb_captured_length(tvb);
+ }
+
+ msg_type = tvb_get_guint8(tvb, offset);
+
+ if (!(msg_type & (1 << 7))) { /* !isValid */
+ /*
+ * No suitable dissector was registered for this offline
+ * message.
+ */
+ col_add_fstr(pinfo->cinfo, COL_INFO, "Unknown offline message ID: %#x", msg_type);
+ ti = proto_tree_add_expert(root_tree, pinfo, &ei_raknet_unknown_message_id, tvb,
+ 0, 1);
+ proto_item_append_text(ti, " %#x", msg_type);
+ return tvb_captured_length(tvb);
+ }
+ else if (msg_type & (1 << 6)) { /* isACK */
+ const int *ack_flds[] = {
+ &hf_raknet_packet_is_for_connected,
+ &hf_raknet_packet_is_ACK,
+ &hf_raknet_packet_has_B_and_AS,
+ NULL
+ };
+
+ ti = proto_tree_add_item(root_tree, proto_raknet, tvb, 0, -1, ENC_NA);
+ proto_item_append_text(ti, ", ACK");
+ raknet_tree = proto_item_add_subtree(ti, ett_raknet);
+
+ item_size = 1;
+ proto_tree_add_bitmask(raknet_tree, tvb, offset, hf_raknet_packet_type,
+ ett_raknet_packet_type, ack_flds, ENC_NA);
+ offset += item_size;
+
+ if (msg_type & (1 << 5)) { /* hasBAndAS */
+ item_size = 4;
+ ti = proto_tree_add_item(raknet_tree, hf_raknet_AS, tvb, offset,
+ item_size, ENC_BIG_ENDIAN);
+ offset += item_size;
+ }
+
+ if (raknet_tree) {
+ gboolean is_ACK = TRUE;
+ return raknet_dissect_ACK(tvb_new_subset_remaining(tvb, offset),
+ pinfo, raknet_tree, &is_ACK);
+ }
+ else {
+ return tvb_captured_length(tvb);
+ }
+ }
+ else if (msg_type & (1 << 5)) { /* isNAK */
+ const int* nak_flds[] = {
+ &hf_raknet_packet_is_for_connected,
+ &hf_raknet_packet_is_ACK,
+ &hf_raknet_packet_is_NAK,
+ NULL
+ };
+
+ ti = proto_tree_add_item(root_tree, proto_raknet, tvb, 0, -1, ENC_NA);
+ proto_item_append_text(ti, ", NAK");
+ raknet_tree = proto_item_add_subtree(ti, ett_raknet);
+
+ item_size = 1;
+ proto_tree_add_bitmask(raknet_tree, tvb, offset, hf_raknet_packet_type,
+ ett_raknet_packet_type, nak_flds, ENC_NA);
+ offset += item_size;
+
+ if (raknet_tree) {
+ gboolean is_ACK = FALSE;
+ return raknet_dissect_ACK(tvb_new_subset_remaining(tvb, offset),
+ pinfo, raknet_tree, &is_ACK);
+ }
+ else {
+ return tvb_captured_length(tvb);
+ }
+ }
+ else {
+ /*
+ * This is the trickiest part as it's neither ACK nor NAK. The
+ * length of its RakNet header varies, and its payload can
+ * even be fragmented so we might have to reassemble them.
+ */
+ guint32 packet_number;
+ gboolean has_multiple_messages = FALSE;
+ const int* common_flds[] = {
+ &hf_raknet_packet_is_for_connected,
+ &hf_raknet_packet_is_ACK,
+ &hf_raknet_packet_is_NAK,
+ &hf_raknet_packet_is_pair,
+ &hf_raknet_packet_is_continuous_send,
+ &hf_raknet_packet_needs_B_and_AS,
+ NULL
+ };
+
+ ti = proto_tree_add_item(root_tree, proto_raknet, tvb, 0, 0, ENC_NA);
+ raknet_tree = proto_item_add_subtree(ti, ett_raknet);
+
+ item_size = 1;
+ proto_tree_add_bitmask(raknet_tree, tvb, offset, hf_raknet_packet_type,
+ ett_raknet_packet_type, common_flds, ENC_NA);
+ offset += item_size;
+
+ item_size = 3;
+ proto_tree_add_item_ret_uint(raknet_tree, hf_raknet_packet_number, tvb,
+ offset, item_size, ENC_LITTLE_ENDIAN, &packet_number);
+ offset += item_size;
+
+ proto_item_append_text(ti, ", Message #%" G_GUINT32_FORMAT, packet_number);
+ col_add_fstr(pinfo->cinfo, COL_INFO, "#%" G_GUINT32_FORMAT ": ", packet_number);
+ col_set_fence(pinfo->cinfo, COL_INFO);
+
+ /*
+ * Set the length of the top-level item to the size of packet
+ * header as we don't know the correct size yet. The common
+ * message dissector will later resize it.
+ */
+ proto_item_set_len(ti, offset);
+
+ while (TRUE) {
+ int dissected;
+
+ dissected = raknet_dissect_common_message(tvb_new_subset_remaining(tvb, offset), pinfo,
+ raknet_tree, &has_multiple_messages);
+ if (dissected >= 0) {
+ offset += dissected;
+
+ if (tvb_reported_length_remaining(tvb, offset) > 0) {
+ /*
+ * More messages are in the packet.
+ */
+ col_append_fstr(pinfo->cinfo, COL_INFO, ", ");
+ col_set_fence(pinfo->cinfo, COL_INFO);
+ continue;
+ }
+ else {
+ /*
+ * It's the end of packet.
+ */
+ break;
+ }
+ }
+ else {
+ return dissected;
+ }
+ }
+
+ return tvb_captured_length(tvb);
+ }
+}
+
/*
* Decode the tvb buffer.
*
@@ -474,83 +1513,138 @@ init_raknet(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint *offset)
* are built using the RakNet libs.
*/
static int
-dissect_raknet(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
+dissect_raknet(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
{
- guint8 packet_id;
+ guint8 message_id;
+ gint dissected;
- col_set_str(pinfo->cinfo, COL_PROTOCOL, "RAKNET");
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, "RakNet");
col_clear(pinfo->cinfo, COL_INFO);
- packet_id = tvb_get_guint8(tvb, 0);
+ message_id = tvb_get_guint8(tvb, 0);
- if (!dissector_try_uint_new(raknet_dissector_table, packet_id, tvb,
- pinfo, tree, TRUE, NULL)) {
- proto_tree_add_expert(tree, pinfo, &ei_raknet_uknown_id, tvb,
- 0, 1);
+ dissected = dissector_try_uint_new(raknet_offline_message_dissectors, message_id, tvb,
+ pinfo, tree, TRUE, data);
+ if (!dissected) {
+ raknet_dissect_connected_message(tvb, pinfo, tree, data);
}
+
return tvb_captured_length(tvb);
}
+/*
+ * Applications using RakNet do not always use a fixed port, but since
+ * every RakNet sessions start with offline messages we can do
+ * heuristics to detect such sessions.
+ */
+static gboolean
+test_raknet_heur(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree _U_, void* data _U_)
+{
+ if (tvb_strneql(tvb, 1 + 8, RAKNET_OFFLINE_MESSAGE_DATA_ID, strlen(RAKNET_OFFLINE_MESSAGE_DATA_ID)) == 0) {
+ /* ID_UNCONNECTED_PING */
+ return TRUE;
+ }
+ else if (tvb_strneql(tvb, 1, RAKNET_OFFLINE_MESSAGE_DATA_ID, strlen(RAKNET_OFFLINE_MESSAGE_DATA_ID)) == 0) {
+ /* ID_OPEN_CONNECTION_REQUEST_1 */
+ return TRUE;
+ }
+ else if (tvb_strneql(tvb, 1 + 8 + 8, RAKNET_OFFLINE_MESSAGE_DATA_ID, strlen(RAKNET_OFFLINE_MESSAGE_DATA_ID)) == 0) {
+ /* ID_UNCONNECTED_PONG */
+ return TRUE;
+ }
+ else {
+ return FALSE;
+ }
+}
+
+static gboolean
+dissect_raknet_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
+{
+ if (test_raknet_heur(tvb, pinfo, tree, data)) {
+ conversation_t* conversation;
+
+ conversation = find_or_create_conversation(pinfo);
+ conversation_set_dissector(conversation, raknet_handle);
+
+ return call_dissector_only(raknet_handle, tvb, pinfo, tree, data) > 0;
+ }
+ else {
+ return FALSE;
+ }
+}
+
void
proto_register_raknet(void)
{
static hf_register_info hf[] = {
/*
- * Packet ID field.
+ * Offline Message ID field.
*/
- { &hf_raknet_packet_id,
- { "RAKNET Packet ID", "raknet.id",
+ { &hf_raknet_offline_message_id,
+ { "RakNet Offline Message ID", "raknet.offline.message.id",
FT_UINT8, BASE_HEX,
- VALS(packet_names), 0x0,
+ VALS(raknet_offline_message_names), 0x0,
NULL, HFILL }
},
/*
* General fields (fields in >1 packet).
*/
- { &hf_raknet_general_client_id,
- { "RAKNET Client ID", "raknet.client_id",
- FT_UINT64, BASE_HEX,
+ { &hf_raknet_client_guid,
+ { "RakNet Client GUID", "raknet.client.guid",
+ FT_BYTES, BASE_NONE,
NULL, 0x0,
NULL, HFILL }
},
- { &hf_raknet_general_elapsed_time,
- { "RAKNET time since start (ms)", "raknet.elapsed_time",
+ { &hf_raknet_timestamp,
+ { "RakNet Time since start (ms)", "raknet.timestamp",
FT_UINT64, BASE_DEC,
NULL, 0x0,
NULL, HFILL }
},
- { &hf_raknet_general_magic,
- { "RAKNET magic", "raknet.con_pingopen_magic",
+ { &hf_raknet_offline_message_data_id,
+ { "RakNet Offline message data ID", "raknet.offline_message.data_id",
FT_BYTES, BASE_NONE,
NULL, 0x0,
NULL, HFILL }
},
- { &hf_raknet_general_mtu_size,
- { "RAKNET MTU size", "raknet.MTU_size",
+ { &hf_raknet_mtu_size,
+ { "RakNet MTU size", "raknet.MTU",
FT_UINT16, BASE_DEC,
NULL, 0x0,
NULL, HFILL }
},
- { &hf_raknet_general_raknet_proto_ver,
- { "RAKNET RakNet protocol version", "raknet.proto_ver",
+ { &hf_raknet_raknet_proto_ver,
+ { "RakNet RakNet protocol version", "raknet.proto_ver",
FT_UINT8, BASE_DEC,
NULL, 0x0,
NULL, HFILL }
},
- { &hf_raknet_general_server_id,
- { "RAKNET Server ID", "raknet.server_id",
- FT_UINT64, BASE_HEX,
+ { &hf_raknet_server_guid,
+ { "RakNet Server GUID", "raknet.server_id",
+ FT_BYTES, BASE_NONE,
NULL, 0x0,
NULL, HFILL }
},
- { &hf_raknet_general_security,
- { "RAKNET security", "raknet.security",
+ { &hf_raknet_ip_version,
+ { "RakNet IP Version", "raknet.ip.version",
FT_UINT8, BASE_DEC,
NULL, 0x0,
NULL, HFILL }
},
- { &hf_raknet_general_udp_port,
- { "RAKNET UDP port", "raknet.UDP_port",
+ { &hf_raknet_ipv4_address,
+ { "RakNet IPv4 Address", "raknet.ip.v4_address",
+ FT_IPv4, BASE_NONE,
+ NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_raknet_ipv6_address,
+ { "RakNet IPv6 Address", "raknet.ip.v6_address",
+ FT_IPv6, BASE_NONE,
+ NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_raknet_port,
+ { "RakNet Port", "raknet.port",
FT_UINT16, BASE_DEC,
NULL, 0x0,
NULL, HFILL }
@@ -558,45 +1652,360 @@ proto_register_raknet(void)
/*
* Packet ID 0x05
*/
- { &hf_raknet_0x05_null_padding,
- { "RAKNET Null padding", "raknet.null_padding",
- FT_BYTES, BASE_NONE,
+ { &hf_raknet_null_padding,
+ { "RakNet Null padding", "raknet.null_padding",
+ FT_NONE, BASE_NONE,
NULL, 0x0,
NULL, HFILL }
},
/*
* Packet ID 0x06
*/
- { &hf_raknet_0x06_server_security,
- { "RAKNET Server security", "raknet.server_security",
- FT_UINT8, BASE_DEC,
+ { &hf_raknet_use_encryption,
+ { "RakNet Use encryption", "raknet.use_encryption",
+ FT_BOOLEAN, BASE_NONE,
+ NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_raknet_server_public_key,
+ { "RakNet Server public key", "raknet.server.public_key",
+ FT_BYTES, BASE_NONE,
NULL, 0x0,
NULL, HFILL }
},
/*
* Packet ID 0x07
*/
- { &hf_raknet_0x07_cookie,
- { "RAKNET cookie", "raknet.cookie",
+ { &hf_raknet_cookie,
+ { "RakNet cookie", "raknet.cookie",
FT_UINT32, BASE_HEX,
NULL, 0x0,
NULL, HFILL }
},
+ { &hf_raknet_client_wrote_challenge,
+ { "RakNet Client wrote challenge", "raknet.client.wrote_challenge",
+ FT_BOOLEAN, BASE_NONE,
+ NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_raknet_client_challenge,
+ { "RakNet Client challenge", "raknet.client.challenge",
+ FT_BYTES, BASE_NONE,
+ NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_raknet_client_address,
+ { "RakNet Client address", "raknet.client.address",
+ FT_STRING, BASE_NONE,
+ NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_raknet_server_address,
+ { "RakNet Server address", "raknet.server.address",
+ FT_STRING, BASE_NONE,
+ NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_raknet_server_answer,
+ { "RakNet Server answer", "raknet.server.answer",
+ FT_BYTES, BASE_NONE,
+ NULL, 0x0,
+ NULL, HFILL }
+ },
/*
* Packet ID 0x1C
*/
{ &hf_raknet_0x1C_server_id_str_len,
- { "RAKNET Server ID string len", "raknet.server_id_str_len",
+ { "RakNet Server ID string len", "raknet.server_id_str_len",
FT_UINT16, BASE_DEC,
NULL, 0x0,
NULL, HFILL }
},
{ &hf_raknet_0x1C_server_id_str,
- { "RAKNET Server ID string", "raknet.server_id_str",
+ { "RakNet Server ID string", "raknet.server_id_str",
FT_STRING, BASE_NONE,
NULL, 0x0,
NULL, HFILL }
- }
+ },
+ { &hf_raknet_packet_type,
+ { "RakNet Packet type", "raknet.packet.type",
+ FT_UINT8, BASE_HEX,
+ NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_raknet_packet_is_for_connected,
+ { "is for connected peer", "raknet.packet.is_for_connected",
+ FT_BOOLEAN, 8,
+ NULL, 0x80,
+ NULL, HFILL }
+ },
+ { &hf_raknet_packet_is_ACK,
+ { "is ACK", "raknet.packet.is_ACK",
+ FT_BOOLEAN, 8,
+ NULL, 0x40,
+ NULL, HFILL }
+ },
+ { &hf_raknet_packet_has_B_and_AS,
+ { "has B and AS", "raknet.packet.has_B_and_AS",
+ FT_BOOLEAN, 8,
+ NULL, 0x20,
+ NULL, HFILL }
+ },
+ { &hf_raknet_packet_is_NAK,
+ { "is NAK", "raknet.packet.is_NAK",
+ FT_BOOLEAN, 8,
+ NULL, 0x20,
+ NULL, HFILL }
+ },
+ { &hf_raknet_packet_is_pair,
+ { "is pair", "raknet.packet.is_pair",
+ FT_BOOLEAN, 8,
+ NULL, 0x10,
+ NULL, HFILL }
+ },
+ { &hf_raknet_packet_is_continuous_send,
+ { "is continuous send", "raknet.packet.is_continuous_send",
+ FT_BOOLEAN, 8,
+ NULL, 0x8,
+ NULL, HFILL }
+ },
+ { &hf_raknet_packet_needs_B_and_AS,
+ { "needs B and AS", "raknet.packet.needs_B_and_AS",
+ FT_BOOLEAN, 8,
+ NULL, 0x4,
+ NULL, HFILL }
+ },
+ { &hf_raknet_AS,
+ { "RakNet Data arrival rate", "raknet.AS",
+ FT_FLOAT, BASE_NONE,
+ NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_raknet_NACK_record_count,
+ { "RakNet ACK/NAK record count", "raknet.NACK.record_count",
+ FT_UINT16, BASE_DEC,
+ NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_raknet_packet_number_range,
+ { "RakNet Packet sequence number range", "raknet.range.packet_number",
+ FT_STRING, BASE_NONE,
+ NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_raknet_range_max_equal_to_min,
+ { "RakNet Range max equals to min", "raknet.range.max_equals_to_min",
+ FT_BOOLEAN, BASE_NONE,
+ NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_raknet_packet_number_min,
+ { "RakNet Packet sequence number min", "raknet.range.packet_number.min",
+ FT_UINT24, BASE_DEC,
+ NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_raknet_packet_number_max,
+ { "RakNet Packet sequence number max", "raknet.range.packet_number.max",
+ FT_UINT24, BASE_DEC,
+ NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_raknet_packet_number,
+ { "RakNet Packet sequence number", "raknet.packet_number",
+ FT_UINT24, BASE_DEC,
+ NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_raknet_message,
+ { "RakNet Message", "raknet.message",
+ FT_NONE, BASE_NONE,
+ NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_raknet_message_flags,
+ { "RakNet Message flags", "raknet.message.flags",
+ FT_UINT8, BASE_HEX,
+ NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_raknet_message_reliability,
+ { "reliability", "raknet.message.reliability",
+ FT_UINT8, BASE_DEC,
+ VALS(raknet_reliability), 0xE0,
+ NULL, HFILL }
+ },
+ { &hf_raknet_message_has_split_packet,
+ { "has split packet", "raknet.message.has_split_packet",
+ FT_BOOLEAN, 8,
+ NULL, 0x10,
+ NULL, HFILL }
+ },
+ { &hf_raknet_payload_length,
+ { "RakNet Payload length", "raknet.payload.length",
+ FT_UINT16, BASE_DEC,
+ NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_raknet_reliable_message_number,
+ { "RakNet Reliable message number", "raknet.reliable.number",
+ FT_UINT24, BASE_DEC,
+ NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_raknet_message_sequencing_index,
+ { "RakNet Message sequencing index", "raknet.sequencing.index",
+ FT_UINT24, BASE_DEC,
+ NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_raknet_message_ordering_index,
+ { "RakNet Message ordering index", "raknet.ordering.index",
+ FT_UINT24, BASE_DEC,
+ NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_raknet_message_ordering_channel,
+ { "RakNet Message ordering channel", "raknet.ordering.channel",
+ FT_UINT8, BASE_DEC,
+ NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_raknet_split_packet_count,
+ { "RakNet Split packet count", "raknet.split.count",
+ FT_UINT32, BASE_DEC,
+ NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_raknet_split_packet_id,
+ { "RakNet Split packet ID", "raknet.split.id",
+ FT_UINT16, BASE_DEC,
+ NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_raknet_split_packet_index,
+ { "RakNet Split packet index", "raknet.split.index",
+ FT_UINT32, BASE_DEC,
+ NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_raknet_split_packet,
+ { "RakNet Split packet", "raknet.split.packet",
+ FT_NONE, BASE_NONE,
+ NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_raknet_system_message,
+ { "RakNet System message", "raknet.system.message",
+ FT_NONE, BASE_NONE,
+ NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_raknet_system_message_id,
+ { "RakNet System Message ID", "raknet.system.message.id",
+ FT_UINT8, BASE_HEX,
+ VALS(raknet_system_message_names), 0x0,
+ NULL, HFILL }
+ },
+ { &hf_raknet_client_proof,
+ { "RakNet Client proof of key", "raknet.client.proof",
+ FT_BYTES, BASE_NONE,
+ NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_raknet_use_client_key,
+ { "RakNet Use client key", "raknet.use_client_key",
+ FT_BOOLEAN, BASE_NONE,
+ NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_raknet_client_identity,
+ { "RakNet Client identity", "raknet.client.identity",
+ FT_BYTES, BASE_NONE,
+ NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_raknet_password,
+ { "RakNet Password", "raknet.password",
+ FT_BYTES, BASE_NONE,
+ NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_raknet_system_index,
+ { "RakNet System index", "raknet.system.index",
+ FT_UINT16, BASE_DEC,
+ NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_raknet_internal_address,
+ { "RakNet Internal address", "raknet.internal.address",
+ FT_STRING, BASE_NONE,
+ NULL, 0x0,
+ NULL, HFILL }
+ },
+ /*
+ * Fragmented packets
+ */
+ { &hf_raknet_fragment,
+ { "Message fragment", "raknet.fragment",
+ FT_FRAMENUM, BASE_NONE,
+ NULL, 0x00,
+ NULL, HFILL }
+ },
+ { &hf_raknet_fragment_count,
+ { "Message fragment count", "raknet.fragment.count",
+ FT_UINT32, BASE_DEC,
+ NULL, 0x00,
+ NULL, HFILL }
+ },
+ { &hf_raknet_fragment_error,
+ { "Message defragmentation error", "raknet.fragment.error",
+ FT_FRAMENUM, BASE_NONE,
+ NULL, 0x00,
+ NULL, HFILL }
+ },
+ { &hf_raknet_fragment_multiple_tails,
+ { "Message has multiple tail fragments", "raknet.fragment.multiple_tails",
+ FT_BOOLEAN, BASE_NONE,
+ NULL, 0x00,
+ NULL, HFILL }
+ },
+ { &hf_raknet_fragment_overlap,
+ { "Message fragment overlap", "raknet.fragment.overlap",
+ FT_BOOLEAN, BASE_NONE,
+ NULL, 0x00,
+ NULL, HFILL }
+ },
+ { &hf_raknet_fragment_overlap_conflicts,
+ { "Message fragment overlapping with conflicting data", "raknet.fragment.overlap.conflicts",
+ FT_BOOLEAN, BASE_NONE,
+ NULL, 0x00,
+ NULL, HFILL }
+ },
+ { &hf_raknet_fragment_too_long_fragment,
+ { "Message fragment too long", "raknet.fragment.too_long",
+ FT_BOOLEAN, BASE_NONE,
+ NULL, 0x00,
+ NULL, HFILL }
+ },
+ { &hf_raknet_fragments,
+ { "Message fragments", "raknet.fragments",
+ FT_NONE, BASE_NONE,
+ NULL, 0x00,
+ NULL, HFILL }
+ },
+ { &hf_raknet_reassembled_in,
+ { "Reassembled message in frame", "raknet.reassembled.in",
+ FT_FRAMENUM, BASE_NONE,
+ NULL, 0x00,
+ NULL, HFILL }
+ },
+ { &hf_raknet_reassembled_length,
+ { "Reassembled message length", "raknet.reassembled.length",
+ FT_UINT32, BASE_DEC,
+ NULL, 0x00,
+ NULL, HFILL }
+ },
};
/*
@@ -604,37 +2013,55 @@ proto_register_raknet(void)
*/
static gint *ett[] = {
&ett_raknet,
+ &ett_raknet_system_address,
+ &ett_raknet_packet_type,
+ &ett_raknet_packet_number_range,
+ &ett_raknet_message,
+ &ett_raknet_message_flags,
+ &ett_raknet_system_message,
+ &ett_raknet_fragment,
+ &ett_raknet_fragments,
};
/*
* Set up expert info.
*/
static ei_register_info ei[] = {
- { &ei_raknet_uknown_id, { "raknet.unknown.id", PI_UNDECODED, PI_ERROR,
- "RakNet unknown or not implemented packet id",
- EXPFILL }
- }
+ { &ei_raknet_unknown_message_id,
+ { "raknet.unknown.id", PI_UNDECODED, PI_WARN,
+ "RakNet unknown message ID",
+ EXPFILL }
+ },
+ { &ei_raknet_encrypted_message,
+ { "raknet.encrypted", PI_DECRYPTION, PI_NOTE,
+ "RakNet encrypted message",
+ EXPFILL }
+ },
+ { &ei_raknet_subdissector_failed,
+ { "raknet.subdissector.failed", PI_MALFORMED, PI_NOTE,
+ "RakNet message subdissector failed, trying the next candidate or heuristics",
+ EXPFILL }
+ },
};
expert_module_t *expert_raknet;
/*
* Init data structs.
*/
- raknet_init_packet_names();
-
+ raknet_init_message_names();
/*
- * Register the protocol with wireshark.
+ * Register the protocol with Wireshark.
*/
proto_raknet = proto_register_protocol (
- "RAKNET game libs", /* name */
- "RAKNET", /* short name */
- "raknet" /* abbrev */
+ "RakNet game networking protocol", /* name */
+ "RakNet", /* short name */
+ "raknet" /* abbrev */
);
/*
- * Register expert support.
- */
+ * Register expert support.
+ */
expert_raknet = expert_register_protocol(proto_raknet);
expert_register_field_array(expert_raknet, ei, array_length(ei));
@@ -644,13 +2071,39 @@ proto_register_raknet(void)
proto_register_field_array(proto_raknet, hf, array_length(hf));
proto_register_subtree_array(ett, array_length(ett));
- raknet_dissector_table =
- register_dissector_table("raknet.packet_id", "RakNet libs packet ids",
+ /*
+ * Register init/cleanup routines.
+ */
+ register_init_routine(raknet_reassemble_init);
+ register_cleanup_routine(raknet_reassemble_cleanup);
+
+ /*
+ * For internal use only
+ */
+ raknet_handle =
+ register_dissector("raknet", dissect_raknet, proto_raknet);
+
+ raknet_offline_message_dissectors =
+ register_dissector_table("raknet.offline.message.id", "RakNet offline messages",
+ proto_raknet, FT_UINT8, BASE_HEX);
+
+ raknet_system_message_dissectors =
+ register_dissector_table("raknet.system.message.id", "RakNet system messages",
proto_raknet, FT_UINT8, BASE_HEX);
+
+ /*
+ * External protocols may register their port to this table via
+ * "raknet_add_udp_dissector()".
+ */
+ raknet_port_dissectors =
+ register_dissector_table("raknet.port", "Port for protocols on top of RakNet",
+ proto_raknet, FT_UINT16, BASE_DEC);
+
/*
- * Raknet subdissector for use by external protocols.
+ * ...and their heuristic dissector to this table.
*/
- register_dissector("raknet", dissect_raknet, proto_raknet);
+ raknet_heur_subdissectors =
+ register_heur_dissector_list("raknet", proto_raknet);
}
void
@@ -659,13 +2112,24 @@ proto_reg_handoff_raknet(void)
dissector_handle_t raknet_handle_tmp;
unsigned int i;
- for (i = 0; i < RAKNET_PACKET_ID_COUNT; i++) {
+ for (i = 0; i < array_length(raknet_offline_message_handlers); i++) {
raknet_handle_tmp =
- create_dissector_handle(raknet_handler[i].dissector_fp,
- proto_raknet);
- dissector_add_uint("raknet.packet_id", raknet_handler[i].vs.value,
+ create_dissector_handle(raknet_offline_message_handlers[i].dissector_fp,
+ proto_raknet);
+ dissector_add_uint("raknet.offline.message.id", raknet_offline_message_handlers[i].vs.value,
raknet_handle_tmp);
}
+
+ for (i = 0; i < array_length(raknet_system_message_handlers); i++) {
+ raknet_handle_tmp =
+ create_dissector_handle(raknet_system_message_handlers[i].dissector_fp,
+ proto_raknet);
+ dissector_add_uint("raknet.system.message.id", raknet_system_message_handlers[i].vs.value,
+ raknet_handle_tmp);
+ }
+
+ heur_dissector_add("udp", dissect_raknet_heur,
+ "RakNet over UDP", "raknet_udp", proto_raknet, HEURISTIC_ENABLE);
}
/*