···616616-- DB SERVER DISSECTION LOGIC
617617-- ============================================================================
618618619619+-- Helper to calculate the full byte length of a DB message starting at `offset`.
620620+-- Returns:
621621+-- > 0: The total byte length of the complete message.
622622+-- < 0: The number of missing bytes needed to complete the message (returns -missing).
623623+-- 0: Not a valid DB message or parse error.
624624+local function get_db_msg_len(buf, offset)
625625+ local len = buf:len()
626626+ local available = len - offset
627627+628628+ if available < 5 then return -(5 - available) end
629629+630630+ local tag = buf(offset, 1):uint()
631631+ local magic = buf(offset+1, 4):uint()
632632+633633+ if tag == 0x11 and magic == 0x00000001 then
634634+ return 5
635635+ end
636636+637637+ if tag ~= 0x11 or magic ~= 0x872349ae then
638638+ return 0
639639+ end
640640+641641+ local cur = offset + 5
642642+643643+ local function read_field()
644644+ local a = len - cur
645645+ if a < 1 then return false, (1 - a) end
646646+ local ftag = buf(cur, 1):uint()
647647+ if ftag == 0x0f then
648648+ if a < 2 then return false, (2 - a) end
649649+ local val = buf(cur+1, 1):uint()
650650+ cur = cur + 2
651651+ return true, val
652652+ elseif ftag == 0x10 then
653653+ if a < 3 then return false, (3 - a) end
654654+ local val = buf(cur+1, 2):uint()
655655+ cur = cur + 3
656656+ return true, val
657657+ elseif ftag == 0x11 then
658658+ if a < 5 then return false, (5 - a) end
659659+ local val = buf(cur+1, 4):uint()
660660+ cur = cur + 5
661661+ return true, val
662662+ elseif ftag == 0x14 then
663663+ if a < 5 then return false, (5 - a) end
664664+ local blen = buf(cur+1, 4):uint()
665665+ if a < 5 + blen then return false, (5 + blen - a) end
666666+ cur = cur + 5 + blen
667667+ return true, nil
668668+ elseif ftag == 0x26 then
669669+ if a < 5 then return false, (5 - a) end
670670+ local chars = buf(cur+1, 4):uint()
671671+ local blen = chars * 2
672672+ if a < 5 + blen then return false, (5 + blen - a) end
673673+ cur = cur + 5 + blen
674674+ return true, nil
675675+ else
676676+ return false, nil
677677+ end
678678+ end
679679+680680+ local ok, val = read_field() -- Tx ID
681681+ if not ok then return val and -val or 0 end
682682+683683+ ok, val = read_field() -- Msg Type
684684+ if not ok then return val and -val or 0 end
685685+686686+ ok, val = read_field() -- Arg Count
687687+ if not ok then return val and -val or 0 end
688688+ local arg_count = val
689689+690690+ local a = len - cur
691691+ if a < 1 then return -(1 - a) end
692692+ if buf(cur, 1):uint() == 0x14 then
693693+ ok, val = read_field()
694694+ if not ok then return val and -val or 0 end
695695+ end
696696+697697+ for i = 1, arg_count do
698698+ ok, val = read_field()
699699+ if not ok then return val and -val or 0 end
700700+ end
701701+702702+ return cur - offset
703703+end
704704+619705local function dissect_db_tcp(buf, pkt, root, length)
620706 local off = 0
621707 local found_db = false
···624710625711 local src_port = pkt.src_port
626712 local dst_port = pkt.dst_port
627627- local is_static_pdjl_port = (src_port == 12523 or dst_port == 12523 or src_port == 1051 or dst_port == 1051 or src_port == 1052 or dst_port == 1052)
628713 local stream_id = get_stream_key(pkt)
629714630630- -- Check for continuation at the start of the TCP segment
631631- -- If this stream has been marked as PDJL before, or is on a static port, we check for continuation
632632- if (is_static_pdjl_port or pdjl_streams[stream_id]) and length > 0 then
633633- local tag = buf(0, 1):uint()
634634- local val = length >= 5 and buf(1, 4):uint() or 0
635635- if not (tag == 0x11 and (val == 0x872349ae or val == 0x00000001)) then
636636- -- Not a new message start, find the next magic header if it exists in this same packet
637637- local next_msg = -1
638638- for i = 1, length - 5 do
639639- if buf(i, 1):uint() == 0x11 and buf(i+1, 4):uint() == 0x872349ae then
640640- next_msg = i
641641- break
642642- end
643643- end
644644-645645- local cont_len = (next_msg == -1) and length or next_msg
646646- local pdjl_tree = root:add(p_djl, buf(0, cont_len))
647647- pdjl_tree:set_text("Pro DJ Link (Blob Chunk)")
648648- table.insert(db_types, "Blob Continuation")
649649- found_db = true
650650- off = cont_len
651651- pkt.cols.protocol = "Pro DJ Link (DB)"
652652-653653- -- Mark this stream as PDJL even if we haven't seen the magic yet
654654- pdjl_streams[stream_id] = true
715715+ while off < length do
716716+ local available = length - off
717717+ if available < 5 then
718718+ pkt.desegment_offset = off
719719+ pkt.desegment_len = 5 - available
720720+ return true
655721 end
656656- end
657722658658- while off + 5 <= length do
659723 local tag = buf(off, 1):uint()
660724 local magic_or_val = buf(off+1, 4):uint()
661725662726 if tag == 0x11 and (magic_or_val == 0x872349ae or magic_or_val == 0x00000001) then
663663- -- Mark this stream as PDJL since it contains the magic or greeting
664727 pdjl_streams[stream_id] = true
665728729729+ local msg_len = get_db_msg_len(buf, off)
730730+ if msg_len < 0 then
731731+ pkt.desegment_offset = off
732732+ pkt.desegment_len = -msg_len
733733+ return true
734734+ elseif msg_len == 0 then
735735+ break -- parse error, stop processing
736736+ end
737737+666738 if magic_or_val == 0x872349ae then
667739 if not found_db then
668740 pkt.cols.protocol = "Pro DJ Link (DB)"
669741 found_db = true
670742 end
671743672672- local msg_tree = root:add(p_djl, buf(off, 0)) -- Set length later
744744+ local msg_tree = root:add(p_djl, buf(off, msg_len))
673745 msg_tree:add(f_db_magic, buf(off+1, 4))
674746675747 local current = off + 5
676748677749 -- Transaction ID
678750 local tx_id = 0
679679- if length - current >= 5 then
751751+ if msg_len - (current - off) >= 5 then
680752 local bytes_read, val = dissect_db_field(buf, current, msg_tree, nil, "Transaction ID")
681753 tx_id = val or 0
682754 local tx_str = (tx_id == 0xfffffffe) and "Setup/Teardown" or string.format("0x%08x", tx_id)
683755684684- -- Only add to the summary list if it's a new unique ID for this packet
685756 local already_added = false
686757 for _, v in ipairs(tx_ids) do
687758 if v == tx_str then already_added = true break end
···695766696767 -- Message Type
697768 local m_type = 0
698698- if length - current >= 3 then
769769+ if msg_len - (current - off) >= 3 then
699770 local bytes_read, val, m_type_item = dissect_db_field(buf, current, msg_tree, nil, "Message Type")
700771 m_type = val or 0
701772 local m_type_str = DB_MSG_TYPES[m_type] or string.format("Unknown(0x%04x)", m_type)
702773703703- -- Specific label for Device Disconnect when tx_id is Setup/Teardown
704774 if m_type == 0x0100 and tx_id == 0xfffffffe then
705775 m_type_str = "Device Disconnect"
706776 if m_type_item then
···716786717787 -- Arg Count
718788 local arg_count = 0
719719- if length - current >= 2 then
789789+ if msg_len - (current - off) >= 2 then
720790 local bytes_read, val = dissect_db_field(buf, current, msg_tree, nil, "Arg Count")
721791 arg_count = val or 0
722792 current = bytes_read
723793 end
724794725795 -- Arg Tag Blob (usually 12 bytes)
726726- if length - current >= 5 and buf(current, 1):uint() == 0x14 then
796796+ if msg_len - (current - off) >= 5 and buf(current, 1):uint() == 0x14 then
727797 local tag_len = buf(current+1, 4):uint()
728728- if length - current >= 5 + tag_len then
798798+ if msg_len - (current - off) >= 5 + tag_len then
729799 msg_tree:add(f_db_tag_blob, buf(current+5, tag_len))
730800 current = current + 5 + tag_len
731801 end
···733803734804 -- Arguments
735805 for i = 1, arg_count do
736736- if current >= length then break end
806806+ if current >= off + msg_len then break end
737807 local prev_current = current
738808 local bytes_read, val = dissect_db_field(buf, current, msg_tree, m_type, i)
739809···766836 end
767837768838 -- Special handling for trailing binary data in blob responses
769769- if (m_type == 0x4002 or m_type == 0x4602 or m_type == 0x4702 or m_type == 0x4e02 or m_type == 0x4a02 or m_type == 0x4402 or m_type == 0x4f02) and current < length then
839839+ if (m_type == 0x4002 or m_type == 0x4602 or m_type == 0x4702 or m_type == 0x4e02 or m_type == 0x4a02 or m_type == 0x4402 or m_type == 0x4f02) and current < off + msg_len then
770840 local label = get_arg_label(m_type, 4) or "Blob Data"
771771- local remaining = length - current
841841+ local remaining = (off + msg_len) - current
772842 msg_tree:add(f_db_field_bin, buf(current, remaining)):set_text(label .. ": [" .. remaining .. " bytes]")
773843 current = current + remaining
774844 end
775845776776- msg_tree:set_len(current - off)
777777- off = current
846846+ msg_tree:set_len(msg_len)
847847+ off = off + msg_len
778848 elseif magic_or_val == 0x00000001 then
779849 if not found_db then
780850 pkt.cols.protocol = "Pro DJ Link (DB)"