Last active
September 11, 2015 21:43
-
-
Save birarda/85d9fa19cfdf9db2c4bd to your computer and use it in GitHub Desktop.
High Fidelity Wireshark Dissector
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- require bit so we can look at the HFUDT bitfields | |
require ("bit") | |
-- create the HFUDT protocol | |
p_hfudt = Proto("hfudt", "HFUDT Protocol") | |
-- create fields shared between packets in HFUDT | |
local f_data = ProtoField.string("hfudt.data", "Data", FT_STRING) | |
-- create the fields for data packets in HFUDT | |
local f_length = ProtoField.uint16("hfudt.length", "Length", base.DEC) | |
local f_control_bit = ProtoField.uint8("hfudt.control", "Control Bit", base.DEC) | |
local f_reliable_bit = ProtoField.uint8("hfudt.reliable", "Reliability Bit", base.DEC) | |
local f_message_bit = ProtoField.uint8("hfudt.message", "Message Bit", base.DEC) | |
local f_sequence_number = ProtoField.uint32("hfudt.sequence_number", "Sequence Number", base.DEC) | |
local f_message_position = ProtoField.uint8("hfudt.message_position", "Message Position", base.DEC) | |
local f_message_number = ProtoField.uint32("hfudt.message_number", "Message Number", base.DEC) | |
local f_type = ProtoField.uint8("hfudt.type", "Type", base.DEC) | |
local f_version = ProtoField.uint8("hfudt.version", "Version", base.DEC) | |
-- create the fields for control packets in HFUDT | |
local f_control_type = ProtoField.uint16("hfudt.control_type", "Control Type", base.DEC) | |
local f_ack_sequence_number = ProtoField.uint32("hfudt.ack_sequence_number", "ACKed Sequence Number", base.DEC) | |
local f_control_sub_sequence = ProtoField.uint32("hfudt.control_sub_sequence", "Control Sub-Sequence Number", base.DEC) | |
p_hfudt.fields = { | |
f_length, | |
f_control_bit, f_reliable_bit, f_message_bit, f_sequence_number, f_type, f_version, | |
f_message_position, f_message_number, | |
f_control_type, f_control_sub_sequence, f_ack_sequence_number, | |
f_data | |
} | |
p_hfudt.prefs["udp_port"] = Pref.uint("UDP Port", 40102, "UDP Port for HFUDT Packets (udt::Socket bound port)") | |
local control_types = { | |
[0] = { "ACK", "Acknowledgement" }, | |
[1] = { "ACK2", "Acknowledgement of acknowledgement" }, | |
[2] = { "LightACK", "Light Acknowledgement" }, | |
[3] = { "NAK", "Loss report (NAK)" }, | |
[4] = { "TimeoutNAK", "Loss report re-transmission (TimeoutNAK)" }, | |
[5] = { "Handshake", "Handshake" }, | |
[6] = { "HandshakeACK", "Acknowledgement of Handshake" } | |
} | |
local message_positions = { | |
[0] = "ONLY", | |
[1] = "LAST", | |
[2] = "FIRST", | |
[3] = "MIDDLE" | |
} | |
function p_hfudt.dissector (buf, pinfo, root) | |
-- make sure this isn't a STUN packet - those don't follow HFUDT format | |
if pinfo.dst == Address.ip("stun.highfidelity.io") then return end | |
-- validate that the packet length is at least the minimum control packet size | |
if buf:len() < 4 then return end | |
-- create a subtree for HFUDT | |
subtree = root:add(p_hfudt, buf(0)) | |
-- set the packet length | |
subtree:add(f_length, buf:len()) | |
-- pull out the entire first word | |
local first_word = buf(0, 4):le_uint() | |
-- pull out the control bit and add it to the subtree | |
local control_bit = bit.rshift(first_word, 31) | |
subtree:add(f_control_bit, control_bit) | |
local data_length = 0 | |
if control_bit == 1 then | |
-- dissect the control packet | |
pinfo.cols.protocol = p_hfudt.name .. " Control" | |
-- remove the control bit and shift to the right to get the type value | |
local shifted_type = bit.rshift(bit.lshift(first_word, 1), 17) | |
local type = subtree:add(f_control_type, shifted_type) | |
if control_types[shifted_type] ~= nil then | |
-- if we know this type then add the name | |
type:append_text(" (".. control_types[shifted_type][1] .. ")") | |
end | |
if shifted_type == 0 or shifted_type == 1 then | |
-- this has a sub-sequence number | |
local second_word = buf(4, 4):le_uint() | |
subtree:add(f_control_sub_sequence, bit.band(second_word, 1073741823)) | |
local data_index = 8 | |
if shifted_type == 0 then | |
-- if this is an ACK let's read out the sequence number | |
local sequence_number = buf(8, 4):le_uint() | |
subtree:add(f_ack_sequence_number, bit.band(sequence_number, 1073741823)) | |
data_index = data_index + 4 | |
end | |
data_length = buf:len() - data_index | |
-- set the data from whatever is left in the packet | |
subtree:add(f_data, buf(data_index, data_length)) | |
elseif shifted_type == 2 then | |
-- this is a Light ACK let's read out the sequence number | |
local sequence_number = buf(4, 4):le_uint() | |
subtree:add(f_ack_sequence_number, bit.band(sequence_number, 1073741823)) | |
data_length = buf:len() - 4 | |
-- set the data from whatever is left in the packet | |
subtree:add(f_data, buf(4, data_length)) | |
else | |
data_length = buf:len() - 4 | |
-- no sub-sequence number, just read the data | |
subtree:add(f_data, buf(4, data_length)) | |
end | |
else | |
-- dissect the data packet | |
pinfo.cols.protocol = p_hfudt.name | |
-- set the reliability bit | |
subtree:add(f_reliable_bit, bit.rshift(first_word, 30)) | |
local message_bit = bit.band(0x01, bit.rshift(first_word, 29)) | |
-- set the message bit | |
subtree:add(f_message_bit, message_bit) | |
-- read the sequence number | |
subtree:add(f_sequence_number, bit.band(first_word, 0x1FFFFFFF)) | |
local payload_offset = 4 | |
-- if the message bit is set, handle the second word | |
if message_bit == 1 then | |
payload_offset = 8 | |
local second_word = buf(4, 4):le_uint() | |
-- read message position from upper 2 bits | |
local message_position = bit.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 | |
-- read message number from lower 30 bits | |
subtree:add(f_message_number, bit.band(second_word, 0x3FFFFFFF)) | |
end | |
-- read the type | |
subtree:add(f_type, buf(payload_offset, 1):le_uint()) | |
-- read the version | |
subtree:add(f_version, buf(payload_offset + 1, 1):le_uint()) | |
data_length = buf:len() - (payload_offset + 2) | |
-- pull the data that is the rest of the packet | |
subtree:add(f_data, buf(payload_offset + 2, data_length)) | |
end | |
-- return the size of the header | |
return buf:len() | |
end | |
function p_hfudt.init() | |
local udp_dissector_table = DissectorTable.get("udp.port") | |
udp_dissector_table:add(p_hfudt.prefs["udp_port"], p_hfudt) | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment