diff --git a/tools/dissectors/hf-domain.lua b/tools/dissectors/hf-domain.lua new file mode 100644 index 0000000000..093026bc92 --- /dev/null +++ b/tools/dissectors/hf-domain.lua @@ -0,0 +1,23 @@ +-- create the domain protocol +p_hf_domain = Proto("hf-domain", "HF Domain Protocol") + +-- domain packet fields +local f_domain_id = ProtoField.guid("hf_domain.domain_id", "Domain ID") +local f_domain_local_id = ProtoField.uint16("hf_domain.domain_local_id", "Domain Local ID") + +p_hf_domain.fields = { + f_domain_id, f_domain_local_id +} + +function p_hf_domain.dissector(buf, pinfo, tree) + pinfo.cols.protocol = p_hf_domain.name + + domain_subtree = tree:add(p_hf_domain, buf()) + + local i = 0 + + domain_subtree:add(f_domain_id, buf(i, 16)) + i = i + 16 + + domain_subtree:add_le(f_domain_local_id, buf(i, 2)) +end diff --git a/tools/dissectors/hf-entity.lua b/tools/dissectors/hf-entity.lua index f4de5a995d..51daa3497d 100644 --- a/tools/dissectors/hf-entity.lua +++ b/tools/dissectors/hf-entity.lua @@ -4,11 +4,21 @@ p_hf_entity = Proto("hf-entity", "HF Entity Protocol") -- entity packet fields local f_entity_sequence_number = ProtoField.uint16("hf_entity.sequence_number", "Sequence Number") local f_entity_timestamp = ProtoField.uint64("hf_entity.timestamp", "Timestamp") -local f_octal_code_bytes = ProtoField.uint8("hf_entity.octal_code_bytes", "Octal Code Bytes") +local f_octal_code_three_bit_sections = ProtoField.uint8("hf_entity.octal_code_three_bit_sections", "Octal Code Three Bit Sections") +local f_octal_code = ProtoField.bytes("hf_entity.octal_code", "Octal Code") local f_entity_id = ProtoField.guid("hf_entity.entity_id", "Entity ID") +local f_last_edited = ProtoField.uint64("hf_entity.last_edited", "Last Edited") +local f_coded_property_type = ProtoField.bytes("hf_entity.coded_property_type", "Coded Property Type") +local f_property_type = ProtoField.uint32("hf_entity.property_type", "Property Type") +local f_coded_update_delta = ProtoField.bytes("hf_entity.f_coded_update_delta", "Coded Update Delta") +local f_update_delta = ProtoField.uint32("hf_entity.update_delta", "Update Delta") p_hf_entity.fields = { - f_entity_sequence_number, f_entity_timestamp, f_octal_code_bytes, f_entity_id + f_entity_sequence_number, f_entity_timestamp, + f_octal_code_three_bit_sections, f_octal_code, + f_last_edited, f_entity_id, + f_coded_property_type, f_property_type, + f_coded_update_delta, f_update_delta } function p_hf_entity.dissector(buf, pinfo, tree) @@ -16,21 +26,72 @@ function p_hf_entity.dissector(buf, pinfo, tree) entity_subtree = tree:add(p_hf_entity, buf()) - i = 0 + local i = 0 entity_subtree:add_le(f_entity_sequence_number, buf(i, 2)) i = i + 2 - entity_subtree:add_le(f_entity_timestamp, buf(i, 4)) - i = i + 4 + entity_subtree:add_le(f_entity_timestamp, buf(i, 8)) + i = i + 8 - -- figure out the number of bytes the octal code takes - local octal_code_bytes = buf(i, 1):le_uint() - entity_subtree:add_le(f_octal_code_bytes, buf(i, 1)) + -- figure out the number of three bit sections in the octal code + local octal_code_three_bit_sections = buf(i, 1):le_uint() + entity_subtree:add_le(f_octal_code_three_bit_sections, buf(i, 1)) + i = i + 1 - -- skip over the octal code - i = i + 1 + octal_code_bytes + -- read the bytes for the octal code + local octal_code_bytes = math.ceil((octal_code_three_bit_sections * 3) / 8) + entity_subtree:add_le(f_octal_code, buf(i, octal_code_bytes)) + i = i + octal_code_bytes + + -- read the last edited timestamp + entity_subtree:add_le(f_last_edited, buf(i, 8)) + i = i + 8 -- read the entity ID entity_subtree:add(f_entity_id, buf(i, 16)) + i = i + 16 + + -- figure out the property type and the size of the coded value + local property_type, coded_property_bytes = number_of_coded_bytes(buf(i)) + entity_subtree:add(f_coded_property_type, buf(i, coded_property_bytes)) + entity_subtree:add(f_property_type, property_type) + i = i + coded_property_bytes + + -- figure out the update delta and the size of the coded value + local update_delta, coded_update_delta_bytes = number_of_coded_bytes(buf(i)) + entity_subtree:add(f_coded_update_delta, buf(i, coded_update_delta_bytes)) + entity_subtree:add(f_update_delta, update_delta) + i = i + coded_update_delta_bytes +end + +function number_of_coded_bytes(buf) + local coded_buffer = buf(0, 4):le_uint() -- max 64 bit value means max 10 header bits + + -- first figure out the total number of bytes for the coded value based + -- on the bits in the header + local total_coded_bytes = 1 + + for bit = 0, 10, 1 do + local header_bit = bit32.extract(coded_buffer, bit) + + if header_bit == 1 then + total_coded_bytes = total_coded_bytes + 1 + else + break + end + end + + -- pull out the bits and write them to our decoded value + local decoded_value = 0 + local decoded_position = 0 + local total_bits = total_coded_bytes * 8 + + for bit = total_coded_bytes, total_bits - 1, 1 do + local value_bit = bit32.extract(coded_buffer, total_bits - bit - 1) + decoded_value = bit32.replace(decoded_value, value_bit, decoded_position) + decoded_position = decoded_position + 1 + end + + return decoded_value, total_coded_bytes end diff --git a/tools/dissectors/hfudt.lua b/tools/dissectors/hfudt.lua index 9d2df801b2..c8b1d9feee 100644 --- a/tools/dissectors/hfudt.lua +++ b/tools/dissectors/hfudt.lua @@ -118,6 +118,10 @@ local packet_types = { [54] = "AssetGetInfoReply" } +local unsourced_packet_types = { + ["DomainList"] = true +} + function p_hfudt.dissector(buf, pinfo, tree) -- make sure this isn't a STUN packet - those don't follow HFUDT format @@ -230,54 +234,63 @@ function p_hfudt.dissector(buf, pinfo, tree) -- if the message bit is set, handle the second word if message_bit == 1 then - payload_offset = 12 + payload_offset = 12 - local second_word = buf(4, 4):le_uint() + local second_word = buf(4, 4):le_uint() - -- read message position from upper 2 bits - local message_position = bit32.rshift(second_word, 30) - local position = subtree:add(f_message_position, message_position) + -- read message position from upper 2 bits + local message_position = bit32.rshift(second_word, 30) + local position = subtree:add(f_message_position, message_position) - if message_positions[message_position] ~= nil then - -- if we know this position then add the name - position:append_text(" (".. message_positions[message_position] .. ")") - end + if message_positions[message_position] ~= nil then + -- if we know this position then add the name + position:append_text(" (".. message_positions[message_position] .. ")") + end - -- read message number from lower 30 bits - subtree:add(f_message_number, bit32.band(second_word, 0x3FFFFFFF)) + -- read message number from lower 30 bits + subtree:add(f_message_number, bit32.band(second_word, 0x3FFFFFFF)) - -- read the message part number - subtree:add(f_message_part_number, buf(8, 4):le_uint()) + -- read the message part number + subtree:add(f_message_part_number, buf(8, 4):le_uint()) end -- read the type local packet_type = buf(payload_offset, 1):le_uint() local ptype = subtree:add_le(f_type, buf(payload_offset, 1)) - if packet_types[packet_type] ~= nil then - subtree:add(f_type_text, packet_types[packet_type]) + local packet_type_text = packet_types[packet_type] + if packet_type_text ~= nil then + subtree:add(f_type_text, packet_type_text) -- if we know this packet type then add the name - ptype:append_text(" (".. packet_types[packet_type] .. ")") + ptype:append_text(" (".. packet_type_text .. ")") end - + -- read the version subtree:add_le(f_version, buf(payload_offset + 1, 1)) - -- read node local ID - local sender_id = buf(payload_offset + 2, 2) - subtree:add_le(f_sender_id, sender_id) + local i = payload_offset + 2 - local i = payload_offset + 4 + if unsourced_packet_types[packet_type_text] == nil then + -- read node local ID + local sender_id = buf(payload_offset + 2, 2) + subtree:add_le(f_sender_id, sender_id) + i = i + 2 - -- read HMAC MD5 hash - subtree:add(f_hmac_hash, buf(i, 16)) - i = i + 16 + -- read HMAC MD5 hash + subtree:add(f_hmac_hash, buf(i, 16)) + i = i + 16 + end + + -- Domain packets + if packet_type_text == "DomainList" then + Dissector.get("hf-domain"):call(buf(i):tvb(), pinfo, tree) + end -- AvatarData or BulkAvatarDataPacket - if packet_types[packet_type] == "AvatarData" or packet_types[packet_type] == "BulkAvatarDataPacket" then + if packet_type_text == "AvatarData" or packet_type_text == "BulkAvatarData" then Dissector.get("hf-avatar"):call(buf(i):tvb(), pinfo, tree) end - if packet_types[packet_type] == "EntityEdit" then + if packet_type_text == "EntityEdit" then Dissector.get("hf-entity"):call(buf(i):tvb(), pinfo, tree) end end