--
+-- Wireshark documentation:
+-- https://web.archive.org/web/20170711121726/https://www.wireshark.org/docs/wsdg_html_chunked/lua_module_Proto.html
+-- https://web.archive.org/web/20170711121844/https://www.wireshark.org/docs/wsdg_html_chunked/lua_module_Tree.html
+-- https://web.archive.org/web/20170711121917/https://www.wireshark.org/docs/wsdg_html_chunked/lua_module_Tvb.html
+
+
-- Table of Contents:
--- Part 1: Client command dissectors (TOSERVER_*)
--- Part 2: Server command dissectors (TOCLIENT_*)
--- Part 3: Wrapper protocol subdissectors
--- Part 4: Wrapper protocol main dissector
--- Part 5: Utility functions
+-- Part 1: Utility functions
+-- Part 2: Client command dissectors (TOSERVER_*)
+-- Part 3: Server command dissectors (TOCLIENT_*)
+-- Part 4: Wrapper protocol subdissectors
+-- Part 5: Wrapper protocol main dissector
+-- Part 6: Utility functions part 2
+
+
+-----------------------
+-- Part 1 --
+-- Utility functions --
+-----------------------
+
+-- Creates two ProtoFields to hold a length and variable-length text content
+-- lentype must be either "uint16" or "uint32"
+function minetest_field_helper(lentype, name, abbr)
+ local f_textlen = ProtoField[lentype](name .. "len", abbr .. " (length)", base.DEC)
+ local f_text = ProtoField.string(name, abbr)
+ return f_textlen, f_text
+end
--------------------------------------------
--- Part 1 --
+-- Part 2 --
-- Client command dissectors (TOSERVER_*) --
--------------------------------------------
minetest_client_obsolete = {}
-- TOSERVER_INIT
-minetest_client_commands[0x02] = { "INIT", 2 }
do
- local f_ser_fmt = ProtoField.uint8("minetest.client.init_ser_version",
+ local abbr = "minetest.client.init_"
+
+ local f_ser_fmt = ProtoField.uint8(abbr.."ser_version",
"Maximum serialization format version", base.DEC)
- local f_player_name = ProtoField.stringz("minetest.client.init_player_name", "Player Name")
- local f_password = ProtoField.stringz("minetest.client.init_password", "Password")
- local f_version = ProtoField.uint16("minetest.client.init_version", "Version", base.DEC)
-
- minetest_client_commands[0x10] = {
- "INIT_LEGACY", -- Command name
- 53, -- Minimum message length including code
- { f_ser_fmt, -- List of fields [optional]
- f_player_name,
- f_password,
- f_version },
- function(buffer, pinfo, tree, t) -- Dissector function [optional]
+ local f_comp_modes = ProtoField.uint16(abbr.."compression",
+ "Supported compression modes", base.DEC, { [0] = "No compression" })
+ local f_proto_min = ProtoField.uint16(abbr.."proto_min", "Minimum protocol version", base.DEC)
+ local f_proto_max = ProtoField.uint16(abbr.."_proto_max", "Maximum protocol version", base.DEC)
+ local f_player_namelen, f_player_name =
+ minetest_field_helper("uint16", abbr.."player_name", "Player Name")
+
+ minetest_client_commands[0x02] = {
+ "INIT", -- Command name
+ 11, -- Minimum message length including code
+ { f_ser_fmt, -- List of fields [optional]
+ f_comp_modes,
+ f_proto_min,
+ f_proto_max,
+ f_player_namelen,
+ f_player_name },
+ function(buffer, pinfo, tree, t) -- Dissector function [optional]
t:add(f_ser_fmt, buffer(2,1))
- t:add(f_player_name, buffer(3,20))
- t:add(f_password, buffer(23,28))
- t:add(f_version, buffer(51,2))
+ t:add(f_comp_modes, buffer(3,2))
+ t:add(f_proto_min, buffer(5,2))
+ t:add(f_proto_max, buffer(7,2))
+ minetest_decode_helper_ascii(buffer, t, "uint16", 9, f_player_namelen, f_player_name)
end
}
end
+-- TOSERVER_INIT_LEGACY (obsolete)
+
+minetest_client_commands[0x10] = { "INIT_LEGACY", 53 }
+minetest_client_obsolete[0x10] = true
+
-- TOSERVER_INIT2
-minetest_client_commands[0x11] = { "INIT2", 2 }
+do
+ local f_langlen, f_lang =
+ minetest_field_helper("uint16", "minetest.client.init2_language", "Language Code")
+
+ minetest_client_commands[0x11] = {
+ "INIT2",
+ 2,
+ { f_langlen,
+ f_lang },
+ function(buffer, pinfo, tree, t)
+ minetest_decode_helper_ascii(buffer, t, "uint16", 2, f_langlen, f_lang)
+ end
+ }
+end
+
+-- TOSERVER_MODCHANNEL_JOIN
+
+minetest_client_commands[0x17] = { "MODCHANNEL_JOIN", 2 }
+
+-- TOSERVER_MODCHANNEL_LEAVE
+
+minetest_client_commands[0x18] = { "MODCHANNEL_LEAVE", 2 }
+
+-- TOSERVER_MODCHANNEL_MSG
+
+minetest_client_commands[0x19] = { "MODCHANNEL_MSG", 2 }
-- TOSERVER_GETBLOCK (obsolete)
-- TOSERVER_PLAYERPOS
do
- local f_x = ProtoField.int32("minetest.client.playerpos_x", "Position X", base.DEC)
- local f_y = ProtoField.int32("minetest.client.playerpos_y", "Position Y", base.DEC)
- local f_z = ProtoField.int32("minetest.client.playerpos_z", "Position Z", base.DEC)
- local f_speed_x = ProtoField.int32("minetest.client.playerpos_speed_x", "Speed X", base.DEC)
- local f_speed_y = ProtoField.int32("minetest.client.playerpos_speed_y", "Speed Y", base.DEC)
- local f_speed_z = ProtoField.int32("minetest.client.playerpos_speed_z", "Speed Z", base.DEC)
- local f_pitch = ProtoField.int32("minetest.client.playerpos_pitch", "Pitch", base.DEC)
- local f_yaw = ProtoField.int32("minetest.client.playerpos_yaw", "Yaw", base.DEC)
+ local abbr = "minetest.client.playerpos_"
+
+ local f_x = ProtoField.int32(abbr.."x", "Position X", base.DEC)
+ local f_y = ProtoField.int32(abbr.."y", "Position Y", base.DEC)
+ local f_z = ProtoField.int32(abbr.."z", "Position Z", base.DEC)
+ local f_speed_x = ProtoField.int32(abbr.."speed_x", "Speed X", base.DEC)
+ local f_speed_y = ProtoField.int32(abbr.."speed_y", "Speed Y", base.DEC)
+ local f_speed_z = ProtoField.int32(abbr.."speed_z", "Speed Z", base.DEC)
+ local f_pitch = ProtoField.int32(abbr.."pitch", "Pitch", base.DEC)
+ local f_yaw = ProtoField.int32(abbr.."yaw", "Yaw", base.DEC)
+ local f_key_pressed = ProtoField.bytes(abbr.."key_pressed", "Pressed keys")
+ local f_fov = ProtoField.uint8(abbr.."fov", "FOV", base.DEC)
+ local f_wanted_range = ProtoField.uint8(abbr.."wanted_range", "Requested view range", base.DEC)
minetest_client_commands[0x23] = {
"PLAYERPOS", 34,
- { f_x, f_y, f_z, f_speed_x, f_speed_y, f_speed_z, f_pitch, f_yaw },
+ { f_x, f_y, f_z, f_speed_x, f_speed_y, f_speed_z, f_pitch, f_yaw,
+ f_key_pressed, f_fov, f_wanted_range },
function(buffer, pinfo, tree, t)
t:add(f_x, buffer(2,4))
t:add(f_y, buffer(6,4))
t:add(f_speed_z, buffer(22,4))
t:add(f_pitch, buffer(26,4))
t:add(f_yaw, buffer(30,4))
+ t:add(f_key_pressed, buffer(34,4))
+ t:add(f_fov, buffer(38,1))
+ t:add(f_wanted_range, buffer(39,1))
end
}
end
end
-- TOSERVER_DELETEDBLOCKS
--- TODO: Test this
do
local f_count = ProtoField.uint8("minetest.client.deletedblocks_count", "Count", base.DEC)
minetest_client_commands[0x26] = { "ADDNODE_FROM_INVENTORY", 2 }
minetest_client_obsolete[0x26] = true
--- TOSERVER_CLICK_OBJECT
--- TODO: Test this
-
-do
- local vs_button = {
- [0] = "left",
- [1] = "right"
- }
-
- local f_button = ProtoField.uint8("minetest.client.click_object_button", "Button", base.DEC, vs_button)
- local f_blockpos_x = ProtoField.int16("minetest.client.click_object_blockpos_x", "Block position X", base.DEC)
- local f_blockpos_y = ProtoField.int16("minetest.client.click_object_blockpos_y", "Block position Y", base.DEC)
- local f_blockpos_z = ProtoField.int16("minetest.client.click_object_blockpos_z", "Block position Z", base.DEC)
- local f_id = ProtoField.int16("minetest.client.click_object_id", "ID", base.DEC)
- local f_item = ProtoField.uint16("minetest.client.click_object_item", "Item", base.DEC)
-
- minetest_client_commands[0x27] = {
- "CLICK_OBJECT", 13,
- { f_button, f_blockpos_x, f_blockpos_y, f_blockpos_z, f_id, f_item },
- function(buffer, pinfo, tree, t)
- t:add(f_button, buffer(2,1))
- t:add(f_blockpos_x, buffer(3,2))
- t:add(f_blockpos_y, buffer(5,2))
- t:add(f_blockpos_z, buffer(7,2))
- t:add(f_id, buffer(9,2))
- t:add(f_item, buffer(11,2))
- end
- }
-end
-
--- TOSERVER_GROUND_ACTION
+-- TOSERVER_CLICK_OBJECT (obsolete)
-do
- local vs_action = {
- [0] = "Start digging",
- [1] = "Place block",
- [2] = "Stop digging",
- [3] = "Digging completed"
- }
+minetest_client_commands[0x27] = { "CLICK_OBJECT", 2 }
+minetest_client_obsolete[0x27] = true
- local f_action = ProtoField.uint8("minetest.client.ground_action", "Action", base.DEC, vs_action)
- local f_nodepos_undersurface_x = ProtoField.int16(
- "minetest.client.ground_action_nodepos_undersurface_x",
- "Node position (under surface) X")
- local f_nodepos_undersurface_y = ProtoField.int16(
- "minetest.client.ground_action_nodepos_undersurface_y",
- "Node position (under surface) Y")
- local f_nodepos_undersurface_z = ProtoField.int16(
- "minetest.client.ground_action_nodepos_undersurface_z",
- "Node position (under surface) Z")
- local f_nodepos_abovesurface_x = ProtoField.int16(
- "minetest.client.ground_action_nodepos_abovesurface_x",
- "Node position (above surface) X")
- local f_nodepos_abovesurface_y = ProtoField.int16(
- "minetest.client.ground_action_nodepos_abovesurface_y",
- "Node position (above surface) Y")
- local f_nodepos_abovesurface_z = ProtoField.int16(
- "minetest.client.ground_action_nodepos_abovesurface_z",
- "Node position (above surface) Z")
- local f_item = ProtoField.uint16("minetest.client.ground_action_item", "Item")
+-- TOSERVER_GROUND_ACTION (obsolete)
- minetest_client_commands[0x28] = {
- "GROUND_ACTION", 17,
- { f_action,
- f_nodepos_undersurface_x,
- f_nodepos_undersurface_y,
- f_nodepos_undersurface_z,
- f_nodepos_abovesurface_x,
- f_nodepos_abovesurface_y,
- f_nodepos_abovesurface_z,
- f_item },
- function(buffer, pinfo, tree, t)
- t:add(f_action, buffer(2,1))
- t:add(f_nodepos_undersurface_x, buffer(3,2))
- t:add(f_nodepos_undersurface_y, buffer(5,2))
- t:add(f_nodepos_undersurface_z, buffer(7,2))
- t:add(f_nodepos_abovesurface_x, buffer(9,2))
- t:add(f_nodepos_abovesurface_y, buffer(11,2))
- t:add(f_nodepos_abovesurface_z, buffer(13,2))
- t:add(f_item, buffer(15,2))
- end
- }
-end
+minetest_client_commands[0x28] = { "GROUND_ACTION", 2 }
+minetest_client_obsolete[0x28] = true
-- TOSERVER_RELEASE (obsolete)
minetest_client_commands[0x29] = { "RELEASE", 2 }
minetest_client_obsolete[0x29] = true
--- TOSERVER_SIGNTEXT (old signs)
--- TODO: Test this or mark obsolete
+-- TOSERVER_SIGNTEXT (obsolete)
-do
- local f_blockpos_x = ProtoField.int16("minetest.client.signtext_blockpos_x", "Block position X", base.DEC)
- local f_blockpos_y = ProtoField.int16("minetest.client.signtext_blockpos_y", "Block position Y", base.DEC)
- local f_blockpos_z = ProtoField.int16("minetest.client.signtext_blockpos_z", "Block position Z", base.DEC)
- local f_id = ProtoField.int16("minetest.client.signtext_id", "ID", base.DEC)
- local f_textlen = ProtoField.uint16("minetest.client.signtext_textlen", "Text length", base.DEC)
- local f_text = ProtoField.string("minetest.client.signtext_text", "Text")
-
- minetest_client_commands[0x30] = {
- "SIGNTEXT", 12,
- { f_blockpos_x, f_blockpos_y, f_blockpos_z, f_id, f_textlen, f_text },
- function(buffer, pinfo, tree, t)
- t:add(f_blockpos_x, buffer(2,2))
- t:add(f_blockpos_y, buffer(4,2))
- t:add(f_blockpos_z, buffer(6,2))
- t:add(f_id, buffer(8,2))
- t:add(f_textlen, buffer(10,2))
- local textlen = buffer(10,2):uint()
- if minetest_check_length(buffer, 12 + textlen, t) then
- t:add(f_text, buffer, buffer(12,textlen))
- end
- end
- }
-end
+minetest_client_commands[0x30] = { "SIGNTEXT", 2 }
+minetest_client_obsolete[0x30] = true
-- TOSERVER_INVENTORY_ACTION
}
end
--- TOSERVER_SIGNNODETEXT
+-- TOSERVER_SIGNNODETEXT (obsolete)
-do
- local f_pos_x = ProtoField.int16("minetest.client.signnodetext_pos_x", "Block position X", base.DEC)
- local f_pos_y = ProtoField.int16("minetest.client.signnodetext_pos_y", "Block position Y", base.DEC)
- local f_pos_z = ProtoField.int16("minetest.client.signnodetext_pos_z", "Block position Z", base.DEC)
- local f_textlen = ProtoField.uint16("minetest.client.signnodetext_textlen", "Text length", base.DEC)
- local f_text = ProtoField.string("minetest.client.signnodetext_text", "Text")
-
- minetest_client_commands[0x33] = {
- "SIGNNODETEXT", 10,
- { f_pos_x, f_pos_y, f_pos_z, f_textlen, f_text },
- function(buffer, pinfo, tree, t)
- t:add(f_pos_x, buffer(2,2))
- t:add(f_pos_y, buffer(4,2))
- t:add(f_pos_z, buffer(6,2))
- t:add(f_textlen, buffer(8,2))
- local textlen = buffer(8,2):uint()
- if minetest_check_length(buffer, 10 + textlen, t) then
- t:add(f_text, buffer(10, textlen))
- end
- end
- }
-end
+minetest_client_commands[0x33] = { "SIGNNODETEXT", 2 }
+minetest_client_obsolete[0x33] = true
--- TOSERVER_CLICK_ACTIVEOBJECT
-do
- local vs_button = {
- [0] = "left",
- [1] = "right"
- }
+-- TOSERVER_CLICK_ACTIVEOBJECT (obsolete)
- local f_button = ProtoField.uint8("minetest.client.click_activeobject_button", "Button", base.DEC, vs_button)
- local f_id = ProtoField.uint16("minetest.client.click_activeobject_id", "ID", base.DEC)
- local f_item = ProtoField.uint16("minetest.client.click_activeobject_item", "Item", base.DEC)
-
- minetest_client_commands[0x34] = {
- "CLICK_ACTIVEOBJECT", 7,
- { f_button, f_id, f_item },
- function(buffer, pinfo, tree, t)
- t:add(f_button, buffer(2,1))
- t:add(f_id, buffer(3,2))
- t:add(f_item, buffer(5,2))
- end
- }
-end
+minetest_client_commands[0x34] = { "CLICK_ACTIVEOBJECT", 2 }
+minetest_client_obsolete[0x34] = true
-- TOSERVER_DAMAGE
}
end
--- TOSERVER_PASSWORD
-
-do
- local f_old_password = ProtoField.string("minetest.client.password_old", "Old password")
- local f_new_password = ProtoField.string("minetest.client.password_new", "New password")
+-- TOSERVER_PASSWORD (obsolete)
- minetest_client_commands[0x36] = {
- "PASSWORD", 58,
- { f_old_password, f_new_password },
- function(buffer, pinfo, tree, t)
- t:add(f_old_password, buffer(2,28))
- t:add(f_new_password, buffer(30,28))
- end
- }
-end
+minetest_client_commands[0x36] = { "CLICK_ACTIVEOBJECT", 2 }
+minetest_client_obsolete[0x36] = true
-- TOSERVER_PLAYERITEM
end
-- TOSERVER_RESPAWN
+
minetest_client_commands[0x38] = { "RESPAWN", 2 }
-minetest_client_commands[0x39] = { "INTERACT", 2 }
+-- TOSERVER_INTERACT
+
+do
+ local abbr = "minetest.client.interact_"
+ local vs_action = {
+ [0] = "Start digging",
+ [1] = "Stop digging",
+ [2] = "Digging completed",
+ [3] = "Place block or item",
+ [4] = "Use item",
+ [5] = "Activate held item",
+ }
+ local vs_pointed_type = {
+ [0] = "Nothing",
+ [1] = "Node",
+ [2] = "Object",
+ }
+
+ local f_action = ProtoField.uint8(abbr.."action", "Action", base.DEC, vs_action)
+ local f_item = ProtoField.uint16(abbr.."item", "Item Index", base.DEC)
+ local f_plen = ProtoField.uint32(abbr.."plen", "Length of pointed thing", base.DEC)
+ local f_pointed_version = ProtoField.uint8(abbr.."pointed_version",
+ "Pointed Thing Version", base.DEC)
+ local f_pointed_type = ProtoField.uint8(abbr.."pointed_version",
+ "Pointed Thing Type", base.DEC, vs_pointed_type)
+ local f_pointed_under_x = ProtoField.int16(abbr.."pointed_under_x",
+ "Node position (under surface) X")
+ local f_pointed_under_y = ProtoField.int16(abbr.."pointed_under_y",
+ "Node position (under surface) Y")
+ local f_pointed_under_z = ProtoField.int16(abbr.."pointed_under_z",
+ "Node position (under surface) Z")
+ local f_pointed_above_x = ProtoField.int16(abbr.."pointed_above_x",
+ "Node position (above surface) X")
+ local f_pointed_above_y = ProtoField.int16(abbr.."pointed_above_y",
+ "Node position (above surface) Y")
+ local f_pointed_above_z = ProtoField.int16(abbr.."pointed_above_z",
+ "Node position (above surface) Z")
+ local f_pointed_object_id = ProtoField.int16(abbr.."pointed_object_id",
+ "Object ID")
+ -- mising: additional playerpos data just like in TOSERVER_PLAYERPOS
+
+ minetest_client_commands[0x39] = {
+ "INTERACT", 11,
+ { f_action,
+ f_item,
+ f_plen,
+ f_pointed_version,
+ f_pointed_type,
+ f_pointed_under_x,
+ f_pointed_under_y,
+ f_pointed_under_z,
+ f_pointed_above_x,
+ f_pointed_above_y,
+ f_pointed_above_z,
+ f_pointed_object_id },
+ function(buffer, pinfo, tree, t)
+ t:add(f_action, buffer(2,1))
+ t:add(f_item, buffer(3,2))
+ t:add(f_plen, buffer(5,4))
+ local plen = buffer(5,4):uint()
+ if minetest_check_length(buffer, 9 + plen, t) then
+ t:add(f_pointed_version, buffer(9,1))
+ t:add(f_pointed_type, buffer(10,1))
+ local ptype = buffer(10,1):uint()
+ if ptype == 1 then -- Node
+ t:add(f_pointed_under_x, buffer(11,2))
+ t:add(f_pointed_under_y, buffer(13,2))
+ t:add(f_pointed_under_z, buffer(15,2))
+ t:add(f_pointed_above_x, buffer(17,2))
+ t:add(f_pointed_above_x, buffer(19,2))
+ t:add(f_pointed_above_x, buffer(21,2))
+ elseif ptype == 2 then -- Object
+ t:add(f_pointed_object_id, buffer(11,2))
+ end
+ end
+ end
+ }
+end
+
+-- ...
+
minetest_client_commands[0x3a] = { "REMOVED_SOUNDS", 2 }
minetest_client_commands[0x3b] = { "NODEMETA_FIELDS", 2 }
minetest_client_commands[0x3c] = { "INVENTORY_FIELDS", 2 }
minetest_client_commands[0x40] = { "REQUEST_MEDIA", 2 }
minetest_client_commands[0x41] = { "RECEIVED_MEDIA", 2 }
+
+-- TOSERVER_BREATH (obsolete)
+
minetest_client_commands[0x42] = { "BREATH", 2 }
-minetest_client_commands[0x43] = { "CLIENT_READY", 2 }
+minetest_client_obsolete[0x42] = true
+
+-- TOSERVER_CLIENT_READY
+
+do
+ local abbr = "minetest.client.client_ready_"
+ local f_major = ProtoField.uint8(abbr.."major","Version Major")
+ local f_minor = ProtoField.uint8(abbr.."minor","Version Minor")
+ local f_patch = ProtoField.uint8(abbr.."patch","Version Patch")
+ local f_reserved = ProtoField.uint8(abbr.."reserved","Reserved")
+ local f_versionlen, f_version =
+ minetest_field_helper("uint16", abbr.."version", "Full Version String")
+ local f_formspec_ver = ProtoField.uint16(abbr.."formspec_version",
+ "Formspec API version")
+
+ minetest_client_commands[0x43] = {
+ "CLIENT_READY",
+ 8,
+ { f_major, f_minor, f_patch, f_reserved, f_versionlen,
+ f_version, f_formspec_ver },
+ function(buffer, pinfo, tree, t)
+ t:add(f_major, buffer(2,1))
+ t:add(f_minor, buffer(3,1))
+ t:add(f_patch, buffer(4,1))
+ t:add(f_reserved, buffer(5,1))
+ local off = minetest_decode_helper_ascii(buffer, t, "uint16", 6,
+ f_versionlen, f_version)
+ if off and minetest_check_length(buffer, off + 2, t) then
+ t:add(f_formspec_ver, buffer(off,2))
+ end
+ end
+ }
+end
+
+-- ...
+
minetest_client_commands[0x50] = { "FIRST_SRP", 2 }
minetest_client_commands[0x51] = { "SRP_BYTES_A", 2 }
minetest_client_commands[0x52] = { "SRP_BYTES_M", 2 }
--------------------------------------------
--- Part 2 --
+-- Part 3 --
-- Server command dissectors (TOCLIENT_*) --
--------------------------------------------
minetest_server_commands = {}
minetest_server_obsolete = {}
--- TOCLIENT_INIT
+-- TOCLIENT_HELLO
-minetest_server_commands[0x02] = {"HELLO", 2}
-minetest_server_commands[0x03] = {"AUTH_ACCEPT", 2}
-minetest_server_commands[0x04] = {"ACCEPT_SUDO_MODE", 2}
-minetest_server_commands[0x05] = {"DENY_SUDO_MODE", 2}
-minetest_server_commands[0x0A] = {"ACCESS_DENIED", 2}
+do
+ local abbr = "minetest.server.hello_"
+
+ local f_ser_fmt = ProtoField.uint8(abbr.."ser_version",
+ "Deployed serialization format version", base.DEC)
+ local f_comp_mode = ProtoField.uint16(abbr.."compression",
+ "Deployed compression mode", base.DEC, { [0] = "No compression" })
+ local f_proto = ProtoField.uint16(abbr.."proto",
+ "Deployed protocol version", base.DEC)
+ local f_auth_methods = ProtoField.bytes(abbr.."auth_modes",
+ "Supported authentication modes")
+ local f_legacy_namelen, f_legacy_name = minetest_field_helper("uint16",
+ abbr.."legacy_name", "Legacy player name for hashing")
+
+ minetest_server_commands[0x02] = {
+ "HELLO",
+ 13,
+ { f_ser_fmt, f_comp_mode, f_proto, f_auth_methods,
+ f_legacy_namelen, f_legacy_name },
+ function(buffer, pinfo, tree, t)
+ t:add(f_ser_fmt, buffer(2,1))
+ t:add(f_comp_mode, buffer(3,2))
+ t:add(f_proto, buffer(5,2))
+ t:add(f_auth_methods, buffer(7,4))
+ minetest_decode_helper_ascii(buffer, t, "uint16", 11, f_legacy_namelen, f_legacy_name)
+ end
+ }
+end
+
+-- TOCLIENT_AUTH_ACCEPT
do
- local f_version = ProtoField.uint8("minetest.server.init_version", "Deployed version", base.DEC)
- local f_pos_x = ProtoField.int16("minetest.server.init_pos_x", "Position X", base.DEC)
- local f_pos_y = ProtoField.int16("minetest.server.init_pos_y", "Position Y", base.DEC)
- local f_pos_z = ProtoField.int16("minetest.server.init_pos_x", "Position Z", base.DEC)
- local f_map_seed = ProtoField.uint64("minetest.server.init_map_seed", "Map seed", base.DEC)
-
- minetest_server_commands[0x10] = {
- "INIT", 17,
- { f_version, f_pos_x, f_pos_y, f_pos_z, f_map_seed },
+ local abbr = "minetest.server.auth_accept_"
+
+ local f_player_x = ProtoField.float(abbr.."player_x", "Player position X")
+ local f_player_y = ProtoField.float(abbr.."player_y", "Player position Y")
+ local f_player_z = ProtoField.float(abbr.."player_z", "Player position Z")
+ local f_map_seed = ProtoField.uint64(abbr.."map_seed", "Map seed")
+ local f_send_interval = ProtoField.float(abbr.."send_interval",
+ "Recommended send interval")
+ local f_sudo_auth_methods = ProtoField.bytes(abbr.."sudo_auth_methods",
+ "Supported auth methods for sudo mode")
+
+ minetest_server_commands[0x03] = {
+ "AUTH_ACCEPT",
+ 30,
+ { f_player_x, f_player_y, f_player_z, f_map_seed,
+ f_send_interval, f_sudo_auth_methods },
function(buffer, pinfo, tree, t)
- t:add(f_version, buffer(2,1))
- t:add(f_pos_x, buffer(3,2))
- t:add(f_pos_y, buffer(5,2))
- t:add(f_pos_z, buffer(7,2))
- t:add(f_map_seed, buffer(9,8))
+ t:add(f_player_x, buffer(2,4))
+ t:add(f_player_y, buffer(6,4))
+ t:add(f_player_z, buffer(10,4))
+ t:add(f_map_seed, buffer(14,8))
+ t:add(f_send_interval, buffer(22,4))
+ t:add(f_sudo_auth_methods, buffer(26,4))
end
}
end
+-- ...
+
+minetest_server_commands[0x04] = {"ACCEPT_SUDO_MODE", 2}
+minetest_server_commands[0x05] = {"DENY_SUDO_MODE", 2}
+minetest_server_commands[0x0A] = {"ACCESS_DENIED", 2}
+
+-- TOCLIENT_INIT (obsolete)
+
+minetest_server_commands[0x10] = { "INIT", 2 }
+minetest_server_obsolete[0x10] = true
+
-- TOCLIENT_BLOCKDATA
do
minetest_server_commands[0x23] = { "PLAYERPOS", 2 }
minetest_server_obsolete[0x23] = true
--- TOCLIENT_PLAYERINFO
+-- TOCLIENT_PLAYERINFO (obsolete)
-do
- local f_count = ProtoField.uint16("minetest.server.playerinfo_count", "Count", base.DEC)
- local f_player = ProtoField.bytes("minetest.server.playerinfo_player", "Player", base.NONE)
- local f_peer_id = ProtoField.uint16("minetest.server.playerinfo_peer_id", "Peer ID", base.DEC)
- local f_name = ProtoField.string("minetest.server.playerinfo_name", "Name")
-
- minetest_server_commands[0x24] = {
- "PLAYERINFO", 2,
- { f_count, f_player, f_peer_id, f_name },
- function(buffer, pinfo, tree, t)
- local count = 0
- local pos, index
- for pos = 2, buffer:len() - 22, 22 do -- does lua have integer division?
- count = count + 1
- end
- t:add(f_count, count):set_generated()
- t:set_len(2 + 22 * count)
- pinfo.cols.info:append(" * " .. count)
- for index = 0, count - 1 do
- local pos = 2 + 22 * index
- local t2 = t:add(f_player, buffer(pos, 22))
- t2:set_text("Player, ID: " .. buffer(pos, 2):uint()
- .. ", Name: " .. buffer(pos + 2, 20):string())
- t2:add(f_peer_id, buffer(pos, 2))
- t2:add(f_name, buffer(pos + 2, 20))
- end
- end
- }
-end
+minetest_server_commands[0x24] = { "PLAYERINFO", 2 }
+minetest_server_obsolete[0x24] = true
-- TOCLIENT_OPT_BLOCK_NOT_FOUND (obsolete)
}
end
--- TOCLIENT_OBJECTDATA
-
-do
- local f_player_count = ProtoField.uint16("minetest.server.objectdata_player_count",
- "Count of player positions", base.DEC)
- local f_player = ProtoField.bytes("minetest.server.objectdata_player", "Player position")
- local f_peer_id = ProtoField.uint16("minetest.server.objectdata_player_peer_id", "Peer ID")
- local f_x = ProtoField.int32("minetest.server.objectdata_player_x", "Position X", base.DEC)
- local f_y = ProtoField.int32("minetest.server.objectdata_player_y", "Position Y", base.DEC)
- local f_z = ProtoField.int32("minetest.server.objectdata_player_z", "Position Z", base.DEC)
- local f_speed_x = ProtoField.int32("minetest.server.objectdata_player_speed_x", "Speed X", base.DEC)
- local f_speed_y = ProtoField.int32("minetest.server.objectdata_player_speed_y", "Speed Y", base.DEC)
- local f_speed_z = ProtoField.int32("minetest.server.objectdata_player_speed_z", "Speed Z", base.DEC)
- local f_pitch = ProtoField.int32("minetest.server.objectdata_player_pitch", "Pitch", base.DEC)
- local f_yaw = ProtoField.int32("minetest.server.objectdata_player_yaw", "Yaw", base.DEC)
- local f_block_count = ProtoField.uint16("minetest.server.objectdata_block_count",
- "Count of blocks", base.DEC)
-
- minetest_server_commands[0x28] = {
- "OBJECTDATA", 6,
- { f_player_count, f_player, f_peer_id, f_x, f_y, f_z,
- f_speed_x, f_speed_y, f_speed_z,f_pitch, f_yaw,
- f_block_count },
- function(buffer, pinfo, tree, t)
- local t2, index, pos
-
- local player_count_pos = 2
- local player_count = buffer(player_count_pos, 2):uint()
- t:add(f_player_count, buffer(player_count_pos, 2))
-
- local block_count_pos = player_count_pos + 2 + 34 * player_count
- if not minetest_check_length(buffer, block_count_pos + 2, t) then
- return
- end
-
- for index = 0, player_count - 1 do
- pos = player_count_pos + 2 + 34 * index
- t2 = t:add(f_player, buffer(pos, 34))
- t2:set_text("Player position, ID: " .. buffer(pos, 2):uint())
- t2:add(f_peer_id, buffer(pos, 2))
- t2:add(f_x, buffer(pos + 2, 4))
- t2:add(f_y, buffer(pos + 6, 4))
- t2:add(f_z, buffer(pos + 10, 4))
- t2:add(f_speed_x, buffer(pos + 14, 4))
- t2:add(f_speed_y, buffer(pos + 18, 4))
- t2:add(f_speed_z, buffer(pos + 22, 4))
- t2:add(f_pitch, buffer(pos + 26, 4))
- t2:add(f_yaw, buffer(pos + 30, 4))
- end
-
- local block_count = buffer(block_count_pos, 2):uint()
- t:add(f_block_count, buffer(block_count_pos, 2))
+-- TOCLIENT_OBJECTDATA (obsolete)
- -- TODO: dissect blocks.
- -- NOTE: block_count > 0 is obsolete. (?)
-
- pinfo.cols.info:append(" * " .. (player_count + block_count))
- end
- }
-end
+minetest_server_commands[0x28] = { "OBJECTDATA", 2 }
+minetest_server_obsolete[0x28] = true
-- TOCLIENT_TIME_OF_DAY
do
local f_time = ProtoField.uint16("minetest.server.time_of_day", "Time", base.DEC)
+ local f_time_speed = ProtoField.float("minetest.server.time_speed", "Time Speed", base.DEC)
minetest_server_commands[0x29] = {
"TIME_OF_DAY", 4,
- { f_time },
+ { f_time, f_time_speed },
function(buffer, pinfo, tree, t)
t:add(f_time, buffer(2,2))
+ t:add(f_time_speed, buffer(4,4))
end
}
end
+-- TOCLIENT_CSM_RESTRICTION_FLAGS
+
+minetest_server_commands[0x2a] = { "CSM_RESTRICTION_FLAGS", 2 }
+
+-- TOCLIENT_PLAYER_SPEED
+
+minetest_server_commands[0x2b] = { "PLAYER_SPEED", 2 }
+
-- TOCLIENT_CHAT_MESSAGE
do
- local f_length = ProtoField.uint16("minetest.server.chat_message_length", "Length", base.DEC)
- local f_message = ProtoField.string("minetest.server.chat_message", "Message")
+ local abbr = "minetest.server.chat_message_"
+ local vs_type = {
+ [0] = "Raw",
+ [1] = "Normal",
+ [2] = "Announce",
+ [3] = "System",
+ }
- minetest_server_commands[0x30] = {
- "CHAT_MESSAGE", 4,
- { f_length, f_message },
+ local f_version = ProtoField.uint8(abbr.."version", "Version")
+ local f_type = ProtoField.uint8(abbr.."type", "Message Type", base.DEC, vs_type)
+ local f_senderlen, f_sender = minetest_field_helper("uint16", abbr.."sender",
+ "Message sender")
+ local f_messagelen, f_message = minetest_field_helper("uint16", abbr:sub(1,-2),
+ "Message")
+
+ minetest_server_commands[0x2f] = {
+ "CHAT_MESSAGE", 8,
+ { f_version, f_type, f_senderlen, f_sender,
+ f_messagelen, f_message },
function(buffer, pinfo, tree, t)
- t:add(f_length, buffer(2,2))
- local textlen = buffer(2,2):uint()
- if minetest_check_length(buffer, 4 + textlen*2, t) then
- t:add(f_message, minetest_convert_utf16(buffer(4, textlen*2), "Converted chat message"))
+ t:add(f_version, buffer(2,1))
+ t:add(f_type, buffer(3,1))
+ local off = 4
+ off = minetest_decode_helper_utf16(buffer, t, "uint16", off, f_senderlen, f_sender)
+ if off then
+ off = minetest_decode_helper_utf16(buffer, t, "uint16", off, f_messagelen, f_message)
end
end
}
end
+-- TOCLIENT_CHAT_MESSAGE_OLD (obsolete)
+
+minetest_server_commands[0x30] = { "CHAT_MESSAGE_OLD", 2 }
+minetest_server_obsolete[0x30] = true
+
-- TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD
do
-- TOCLIENT_HP
do
- local f_hp = ProtoField.uint8("minetest.server.hp", "Hitpoints", base.DEC)
+ local f_hp = ProtoField.uint16("minetest.server.hp", "Hitpoints", base.DEC)
minetest_server_commands[0x33] = {
- "HP", 3,
+ "HP", 4,
{ f_hp },
function(buffer, pinfo, tree, t)
- t:add(f_hp, buffer(2,1))
+ t:add(f_hp, buffer(2,2))
end
}
end
-- TOCLIENT_MOVE_PLAYER
do
- local f_x = ProtoField.int32("minetest.server.move_player_x", "Position X", base.DEC)
- local f_y = ProtoField.int32("minetest.server.move_player_y", "Position Y", base.DEC)
- local f_z = ProtoField.int32("minetest.server.move_player_z", "Position Z", base.DEC)
- local f_pitch = ProtoField.int32("minetest.server.move_player_pitch", "Pitch", base.DEC)
- local f_yaw = ProtoField.int32("minetest.server.move_player_yaw", "Yaw", base.DEC)
- local f_garbage = ProtoField.bytes("minetest.server.move_player_garbage", "Garbage")
+ local abbr = "minetest.server.move_player_"
+
+ local f_x = ProtoField.float(abbr.."x", "Position X")
+ local f_y = ProtoField.float(abbr.."y", "Position Y")
+ local f_z = ProtoField.float(abbr.."z", "Position Z")
+ local f_pitch = ProtoField.float(abbr.."_pitch", "Pitch")
+ local f_yaw = ProtoField.float(abbr.."yaw", "Yaw")
minetest_server_commands[0x34] = {
- "MOVE_PLAYER", 18, -- actually 22, but see below
+ "MOVE_PLAYER", 22,
{ f_x, f_y, f_z, f_pitch, f_yaw, f_garbage },
function(buffer, pinfo, tree, t)
t:add(f_x, buffer(2, 4))
t:add(f_y, buffer(6, 4))
t:add(f_z, buffer(10, 4))
-
- -- Compatibility note:
- -- Up to 2011-08-23, there was a bug in Minetest that
- -- caused the server to serialize the pitch and yaw
- -- with 2 bytes each instead of 4, creating a
- -- malformed message.
- if buffer:len() >= 22 then
- t:add(f_pitch, buffer(14, 4))
- t:add(f_yaw, buffer(18, 4))
- else
- t:add(f_garbage, buffer(14, 4))
- t:add_expert_info(PI_MALFORMED, PI_WARN, "Malformed pitch and yaw, possibly caused by a serialization bug in Minetest")
- end
+ t:add(f_pitch, buffer(14, 4))
+ t:add(f_yaw, buffer(18, 4))
end
}
end
--- TOCLIENT_ACCESS_DENIED
+-- TOCLIENT_ACCESS_DENIED_LEGACY
do
local f_reason_length = ProtoField.uint16("minetest.server.access_denied_reason_length", "Reason length", base.DEC)
local f_reason = ProtoField.string("minetest.server.access_denied_reason", "Reason")
minetest_server_commands[0x35] = {
- "ACCESS_DENIED", 4,
+ "ACCESS_DENIED_LEGACY", 4,
{ f_reason_length, f_reason },
function(buffer, pinfo, tree, t)
t:add(f_reason_length, buffer(2,2))
}
end
--- TOCLIENT_PLAYERITEM
+-- TOCLIENT_FOV
-do
- local f_count = ProtoField.uint16(
- "minetest.server.playeritem_count",
- "Count of players", base.DEC)
- local f_player = ProtoField.bytes(
- "minetest.server.playeritem_player",
- "Player")
- local f_peer_id = ProtoField.uint16(
- "minetest.server.playeritem_peer_id",
- "Peer ID", base.DEC)
- local f_item_length = ProtoField.uint16(
- "minetest.server.playeritem_item_length",
- "Item information length", base.DEC)
- local f_item = ProtoField.string(
- "minetest.server.playeritem_item",
- "Item information")
-
- minetest_server_commands[0x36] = {
- "PLAYERITEM", 4,
- { f_count, f_player, f_peer_id, f_item_length, f_item },
- function(buffer, pinfo, tree, t)
- local count, index, pos, item_length
-
- count = buffer(2,2):uint()
- pinfo.cols.info:append(" * " .. count)
- t:add(f_count, buffer(2,2))
-
- pos = 4
- for index = 0, count - 1 do
- if not minetest_check_length(buffer, pos + 4, t) then
- return
- end
- item_length = buffer(pos + 2, 2):uint()
- if not minetest_check_length(buffer, pos + 4 + item_length, t) then
- return
- end
-
- local t2 = t:add(f_player, buffer(pos, 4 + item_length))
- t2:set_text("Player, ID: " .. buffer(pos, 2):uint())
- t2:add(f_peer_id, buffer(pos, 2))
- t2:add(f_item_length, buffer(pos + 2, 2))
- t2:add(f_item, buffer(pos + 4, item_length))
-
- pos = pos + 4 + item_length
- end
- end
- }
-end
+minetest_server_commands[0x36] = { "FOV", 2 }
-- TOCLIENT_DEATHSCREEN
do
- local vs_set_camera_point_target = {
- [0] = "False",
- [1] = "True"
- }
-
- local f_set_camera_point_target = ProtoField.uint8(
+ local f_set_camera_point_target = ProtoField.bool(
"minetest.server.deathscreen_set_camera_point_target",
- "Set camera point target", base.DEC, vs_set_camera_point_target)
+ "Set camera point target")
local f_camera_point_target_x = ProtoField.int32(
"minetest.server.deathscreen_camera_point_target_x",
"Camera point target X", base.DEC)
}
end
+-- TOCLIENT_MEDIA
+
minetest_server_commands[0x38] = {"MEDIA", 2}
+
+-- TOCLIENT_TOOLDEF (obsolete)
+
minetest_server_commands[0x39] = {"TOOLDEF", 2}
+minetest_server_obsolete[0x39] = true
+
+-- TOCLIENT_NODEDEF
+
minetest_server_commands[0x3a] = {"NODEDEF", 2}
+
+-- TOCLIENT_CRAFTITEMDEF (obsolete)
+
minetest_server_commands[0x3b] = {"CRAFTITEMDEF", 2}
+minetest_server_obsolete[0x3b] = true
+
+-- ...
+
minetest_server_commands[0x3c] = {"ANNOUNCE_MEDIA", 2}
minetest_server_commands[0x3d] = {"ITEMDEF", 2}
minetest_server_commands[0x3f] = {"PLAY_SOUND", 2}
minetest_server_commands[0x45] = {"MOVEMENT", 2}
minetest_server_commands[0x46] = {"SPAWN_PARTICLE", 2}
minetest_server_commands[0x47] = {"ADD_PARTICLE_SPAWNER", 2}
+
+-- TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY (obsolete)
+
minetest_server_commands[0x48] = {"DELETE_PARTICLESPAWNER_LEGACY", 2}
+minetest_server_obsolete[0x48] = true
+
+-- ...
+
minetest_server_commands[0x49] = {"HUDADD", 2}
minetest_server_commands[0x4a] = {"HUDRM", 2}
minetest_server_commands[0x4b] = {"HUDCHANGE", 2}
minetest_server_commands[0x53] = {"DELETE_PARTICLESPAWNER", 2}
minetest_server_commands[0x54] = {"CLOUD_PARAMS", 2}
minetest_server_commands[0x55] = {"FADE_SOUND", 2}
-minetest_server_commands[0x61] = {"SRP_BYTES_S_B", 2}
+
+-- TOCLIENT_UPDATE_PLAYER_LIST
+
+do
+ local abbr = "minetest.server.update_player_list_"
+ local vs_type = {
+ [0] = "Init",
+ [1] = "Add",
+ [2] = "Remove",
+ }
+
+ local f_type = ProtoField.uint8(abbr.."type", "Type", base.DEC, vs_type)
+ local f_count = ProtoField.uint16(abbr.."count", "Number of players", base.DEC)
+ local f_name = ProtoField.string(abbr.."name", "Name")
+
+ minetest_server_commands[0x56] = {
+ "UPDATE_PLAYER_LIST",
+ 5,
+ { f_type, f_count, f_name },
+ function(buffer, pinfo, tree, t)
+ t:add(f_type, buffer(2,1))
+ t:add(f_count, buffer(3,2))
+ local count = buffer(3,2):uint()
+ local off = 5
+ for i = 1, count do
+ if not minetest_check_length(buffer, off + 2, t) then
+ return
+ end
+ off = minetest_decode_helper_ascii(buffer, t, "uint16", off, nil, f_name)
+ if not off then
+ return
+ end
+ end
+ end
+ }
+end
+
+-- ...
+
+minetest_server_commands[0x57] = {"MODCHANNEL_MSG", 2}
+minetest_server_commands[0x58] = {"MODCHANNEL_SIGNAL", 2}
+minetest_server_commands[0x59] = {"NODEMETA_CHANGED", 2}
+minetest_server_commands[0x5a] = {"SET_SUN", 2}
+minetest_server_commands[0x5b] = {"SET_MOON", 2}
+minetest_server_commands[0x5c] = {"SET_STARS", 2}
+minetest_server_commands[0x60] = {"SRP_BYTES_S_B", 2}
+minetest_server_commands[0x61] = {"FORMSPEC_PREPEND", 2}
------------------------------------
--- Part 3 --
+-- Part 4 --
-- Wrapper protocol subdissectors --
------------------------------------
this_peer = "Client"
other_peer = "Server"
empty_message_info = "Empty message / Connect"
- commands = minetest_client_commands -- defined in Part 1
- obsolete = minetest_client_obsolete -- defined in Part 1
+ commands = minetest_client_commands -- defined in Part 2
+ obsolete = minetest_client_obsolete -- defined in Part 2
else
proto_name = "minetest.server"
this_peer = "Server"
other_peer = "Client"
empty_message_info = "Empty message"
- commands = minetest_server_commands -- defined in Part 2
- obsolete = minetest_server_obsolete -- defined in Part 2
+ commands = minetest_server_commands -- defined in Part 3
+ obsolete = minetest_server_obsolete -- defined in Part 3
end
-- Create the protocol object.
for code, command_info in pairs(commands) do
local command_fields = command_info[3]
if command_fields ~= nil then
- local index, field
for index, field in ipairs(command_fields) do
+ assert(field ~= nil)
table.insert(proto.fields, field)
end
end
-------------------------------------
--- Part 4 --
+-- Part 5 --
-- Wrapper protocol main dissector --
-------------------------------------
------------------------
--- Part 5 --
--- Utility functions --
------------------------
+------------------------------
+-- Part 6 --
+-- Utility functions part 2 --
+------------------------------
-- Checks if a (sub-)Tvb is long enough to be further dissected.
-- If it is long enough, sets the dissector tree item length to min_len
t:set_len(min_len)
return true
- -- Tvb:reported_length_remaining() has been added in August 2011
- -- and is not yet widely available, disable for the time being
- -- TODO: uncomment at a later date
- -- TODO: when uncommenting this, also re-check if other parts of
+ -- TODO: check if other parts of
-- the dissector could benefit from reported_length_remaining
- --elseif tvb:reported_length_remaining() >= min_len then
- -- t:add_expert_info(PI_UNDECODED, PI_INFO, "Only part of this packet was captured, unable to decode.")
- -- return false
+ elseif tvb:reported_length_remaining() >= min_len then
+ t:add_expert_info(PI_UNDECODED, PI_INFO, "Only part of this packet was captured, unable to decode.")
+ return false
else
t:add_expert_info(PI_MALFORMED, PI_ERROR, "Message is too short")
hex = ""
for pos = 0, tvb:len() - 2, 2 do
char = tvb(pos, 2):uint()
- if (char >= 0x20) and (char <= 0x7e) then
+ if (char >= 0x20 and char <= 0x7e) or char == 0x0a then
hex = hex .. string.format(" %02x", char)
else
hex = hex .. " 3F"
end
end
+-- Decodes a variable-length string as ASCII text
+-- t_textlen, t_text should be the ProtoFields created by minetest_field_helper
+-- alternatively t_text can be a ProtoField.string and t_textlen can be nil
+-- lentype must be the type of the length field (as passed to minetest_field_helper)
+-- returns nil if length check failed
+function minetest_decode_helper_ascii(tvb, t, lentype, offset, f_textlen, f_text)
+ local n = ({uint16 = 2, uint32 = 4})[lentype]
+ assert(n)
+
+ if f_textlen then
+ t:add(f_textlen, tvb(offset, n))
+ end
+ local textlen = tvb(offset, n):uint()
+ if minetest_check_length(tvb, offset + n + textlen, t) then
+ t:add(f_text, tvb(offset + n, textlen))
+ return offset + n + textlen
+ end
+end
+
+-- Decodes a variable-length string as UTF-16 text
+-- (see minetest_decode_helper_ascii)
+function minetest_decode_helper_utf16(tvb, t, lentype, offset, f_textlen, f_text)
+ local n = ({uint16 = 2, uint32 = 4})[lentype]
+ assert(n)
+
+ if f_textlen then
+ t:add(f_textlen, tvb(offset, n))
+ end
+ local textlen = tvb(offset, n):uint() * 2
+ if minetest_check_length(tvb, offset + n + textlen, t) then
+ t:add(f_text, minetest_convert_utf16(tvb(offset + n, textlen), "UTF-16 text"))
+ return offset + n + textlen
+ end
+end