-- LiveShowSoftware SPIT-Protocol spit_proto = Proto("spit", "LiveShowSoftware SPIT") spit_sad_proto = Proto("spit_sad", "LiveShowSoftware SPIT SAD") -- Define fields (add more as needed) local f_hVer = ProtoField.uint32("spit.version", "Version") local f_hNum = ProtoField.uint8("spit.msgCount", "MsgCount") local f_hLen = ProtoField.uint32("spit.len", "Length") local f_hSerId = ProtoField.string("spit.serverId", "ServerID") local f_hCliId = ProtoField.string("spit.clientId", "ClientID") local f_hType = ProtoField.uint8("spit.msgType", "MsgType") local f_pLen = ProtoField.uint32("spit.paylen", "Length") local f_pSession = ProtoField.string("spit.key", "Spit Session") local f_pKey = ProtoField.string("spit.key", "Spit Key") local f_pSadKey = ProtoField.string("spit.sadKey", "Spit SAD Key") local f_pServerDevName = ProtoField.string("spit.serverDevName", "Server Device Name") local f_pClientDevName = ProtoField.string("spit.clientDevName", "Client Device Name") local f_pClientName = ProtoField.string("spit.clientName", "Client Name") local f_pLoginName = ProtoField.string("spit.loginName", "Login Name") local f_pLoginPassword = ProtoField.string("spit.loginPassword", "Login Password") local f_pServerName = ProtoField.string("spit.serverName", "Server Name") local f_pServerIp = ProtoField.string("spit.serverIp", "Server IP") local f_pServerPort = ProtoField.uint16("spit.serverIp", "Server Port") local f_pSrvParam = ProtoField.string("spit.serverParam", "Server Paramter") local f_pStepTime = ProtoField.string("spit.stepTime", "Step Time") local f_pConnected = ProtoField.string("spit.connected", "Connected") local f_pProjectId = ProtoField.string("spit.projectId", "Project ID") local f_pProjectName = ProtoField.string("spit.projectName", "Project Name") local f_pObjectId = ProtoField.string("spit.ObjectId", "Object ID") local f_pObjectName = ProtoField.string("spit.ObjectName", "Object Name") local f_pTypeId = ProtoField.string("spit.TypeId", "Type ID") local f_pTypeName = ProtoField.string("spit.TypeName", "Type Name") local f_pTypeGroupName = ProtoField.string("spit.TypeGroupName", "Type Group Name") local f_pObjectsFrames = ProtoField.uint64("spit.ObjectFrames", "Object Frames") local f_pValue = ProtoField.uint64("spit.Value", "Value") local f_pValueFlag = ProtoField.uint8("spit.ValueFlag", "ValueFlag") local f_pConfirm = ProtoField.uint8("spit.confirmed", "Confirmation") local f_pFixed = ProtoField.uint8("spit.fixed", "Fixed") local f_pAssigned = ProtoField.uint8("spit.assigned", "Action assigned") local f_pSrvRemote = ProtoField.uint8("spit.serverRemote", "Server Remote") local f_pProjIndep = ProtoField.uint8("spit.projectIndipendent", "Project Indipendent") local f_pValueUse = ProtoField.uint8("spit.valueUse", "Value Use") local f_pFrameStart = ProtoField.uint64("spit.frameStart", "Frame Start") local f_pFrameLength = ProtoField.uint64("spit.frameLength", "Frame Length") local f_pFrameFadeIn = ProtoField.uint64("spit.fadeInLength", "Fade In Length") local f_pFrameFadeOut = ProtoField.uint64("spit.fadeOutLength", "Fade Out Length") local f_pValueFactor = ProtoField.uint32("spit.valueFactor", "Value Factor") local f_pFramesPerSec = ProtoField.uint32("spit.framesPerSec", "Frames per second") local f_pTrack = ProtoField.uint32("spit.track", "Track") local f_pRemark = ProtoField.string("spit.remark", "Remack") local f_pDelay = ProtoField.uint64("spit.delay", "Delay") local f_pDuration = ProtoField.uint64("spit.duration", "Duration") local f_pPlayerId = ProtoField.string("spit.PlayerId", "Player ID") local f_pPlayerName = ProtoField.string("spit.PlayerName", "Player Name") local f_pPlayerType = ProtoField.uint8("spit.PlayerType", "Player Type") local f_pPlayerRunning = ProtoField.uint8("spit.PlayerRunning", "Player Running") local f_pPlayerFrames = ProtoField.uint64("spit.PlayerFrame", "Player Frames") local f_pPlayerPrePos = ProtoField.uint8("spit.PlayerPrePos", "Player Preposition") local sessionInfos = {} spit_proto.fields = { f_pSession, f_pKey, f_pSadKey, f_pServerDevName, f_hVer, f_hNum, f_hLen, f_hSerId, f_hCliId, f_hType, f_pLen, f_pClientDevName, f_pClientName, f_pLoginName, f_pLoginPassword, f_pServerName, f_pServerIp, f_pServerPort, f_pSrvParam, f_pStepTime, f_pConnected, f_pProjectId, f_pProjectName, f_pObjectId, f_pObjectName, f_pTypeId, f_pTypeName, f_pTypeGroupName, f_pObjectsFrames, f_pValue, f_pValueFlag, f_pConfirm, f_pFixed, f_pAssigned, f_pSrvRemote, f_pProjIndep, f_pValueUse, f_pFrameStart, f_pFrameLength, f_pFrameFadeIn, f_pFrameFadeOut, f_pValueFactor, f_pFramesPerSec, f_pTrack, f_pRemark, f_pDelay, f_pDuration, f_pPlayerId, f_pPlayerName, f_pPlayerType, f_pPlayerRunning, f_pPlayerFrames, f_pPlayerPrePos } function extractSession(buffer, pinfo) local serverHash = buffer(16,41):string() local clientHash = buffer(57,41):string() return string.format("%s - %s", sessionInfos[serverHash], sessionInfos[clientHash]) end function extractVersionString(buffer) local vBytes = buffer(7,4):bytes() local vStr = "" for i = 0, 3 do local byte = vBytes:get_index(i) local high_nibble = bit.rshift(byte, 4) local low_nibble = bit.band(byte, 0x0F) vStr = vStr .. tostring(high_nibble) .. tostring(low_nibble) end return vStr end -- Heuristic dissector function function spit_proto.dissector(buffer, pinfo, tree) if buffer:len() < 6 then return false end if buffer(0,6):string() ~= "#spit#" then return false end pinfo.cols.protocol = "SPIT" local subtree = tree:add(spit_proto, buffer(), "SPIT Protocol Data") local hTree = subtree:add("Header") hTree:add(f_hVer, buffer(7,4)):set_text("Version: " .. extractVersionString(buffer)) hTree:add(f_hNum, buffer(11,1)) local hLen = buffer(12,4):le_uint() subtree:add(f_hLen, buffer(12,4)):set_text("Length: " .. hLen) hTree:add(f_hSerId, buffer(16,41)) hTree:add(f_hCliId, buffer(57,41)) local type = buffer(98,1):uint() hTree:add(f_hType, buffer(98,1)) local pTree = subtree:add("Payload") local pLen = buffer(99,4):le_uint() pTree:add(f_pLen, buffer(99,4)):set_text("Pyload Length: " .. pLen) local info_text = "Type: " .. type if type == 1 then -- Connect pTree:add(f_pClientDevName, buffer(103,64)) pTree:add(f_pClientName, buffer(167,64)) pTree:add(f_pLoginName, buffer(231,64)) pTree:add(f_pLoginPassword, buffer(295,64)) pTree:add(f_pServerIp, buffer(359,40)) pTree:add(f_pServerPort, buffer(399,2)) local clientName = buffer(167,64):string() local clientHash = buffer(57,41):string() sessionInfos[clientName] = clientHash -- e.g. 70866c9b-af1c-4765-a17e-8b45c93f3aca sessionInfos[clientHash] = clientName -- sessionInfos[tostring(pinfo.src)] = clientName info_text = string.format("Connect Req | Client: %s (%s) | ADDR: %s:%s", clientName, clientHash, buffer(359,40):string(), buffer(399,2):uint()) elseif type == 2 then -- Connect Response pTree:add(f_pServerDevName, buffer(103,64)) pTree:add(f_pServerName, buffer(167,64)) pTree:add(f_pStepTime, buffer(231,4)) pTree:add(f_pConnected, buffer(235,1)) local serverName = buffer(167,64):string() local serverHash = buffer(16,41):string() sessionInfos[serverName] = serverHash -- e.g. 405c7100-64e8-435d-8a7b-00c5629f9ccf sessionInfos[serverHash] = serverName sessionInfos[tostring(pinfo.src)] = serverName info_text = string.format("Connect Res | Server: %s (%s) ", serverName, serverHash) elseif type == 3 then pTree:add(f_pSession, extractSession(buffer, pinfo)) info_text = string.format("Disconnect") elseif type == 8 then info_text = string.format("Watchdog") elseif type == 9 then info_text = string.format("Watchdog Ans") elseif type == 11 then -- Report Porject pTree:add(f_pSession, extractSession(buffer, pinfo)) pTree:add(f_pProjectId, buffer(103,41)) pTree:add(f_pProjectName, buffer(144,64)) pTree:add(f_pFramesPerSec, buffer(208,4)) info_text = string.format("%s -> %s | Report Project | Project: %s / %s", sessionInfos[tostring(pinfo.src)], sessionInfos[tostring(pinfo.dst)], buffer(103,41):string(), buffer(144,64):string()) elseif type == 13 then -- Close Porject pTree:add(f_pSession, extractSession(buffer, pinfo)) pTree:add(f_pProjectId, buffer(103,41)) info_text = string.format("Close Project | Project: %s", buffer(103,64):string()) elseif type == 15 then pTree:add(f_pSession, extractSession(buffer, pinfo)) info_text = string.format("Request Project Transfer") elseif type == 16 then pTree:add(f_pSession, extractSession(buffer, pinfo)) info_text = string.format("Start Project Transfer") elseif type == 17 then pTree:add(f_pSession, extractSession(buffer, pinfo)) info_text = string.format("End Project Transfer") elseif type == 21 then -- Report Type pTree:add(f_pSession, extractSession(buffer, pinfo)) pTree:add(f_pConfirm, buffer(103,1)) pTree:add(f_pTypeId, buffer(104,41)) pTree:add(f_pFixed, buffer(145,1)) pTree:add(f_pSrvRemote, buffer(146,1)) pTree:add(f_pProjIndep, buffer(147,1)) pTree:add(f_pTypeGroupName, buffer(148,39)) pTree:add(f_pTypeName, buffer(187,64)) pTree:add(f_pDelay, buffer(251,8)) pTree:add(f_pDuration, buffer(259,8)) local group = buffer(148,39):string() local name = buffer(187,64):string() local id = buffer(104,41):string() info_text = string.format("%s -> %s | Report SPIT Type: %s.%s (%s)", sessionInfos[tostring(pinfo.src)], sessionInfos[tostring(pinfo.dst)], group, name, id) elseif type == 23 then pTree:add(f_pSession, extractSession(buffer, pinfo)) pTree:add(f_pTypeId, buffer(103,41)) info_text = string.format("Remove SPIT Type") elseif type == 31 then -- Report Object pTree:add(f_pSession, extractSession(buffer, pinfo)) pTree:add(f_pConfirm, buffer(103,1)) pTree:add(f_pObjectId, buffer(104,41)) pTree:add(f_pFixed, buffer(145,1)) pTree:add(f_pSrvRemote, buffer(146,1)) pTree:add(f_pObjectName, buffer(147,64)) pTree:add(f_pTypeId, buffer(211,41)) pTree:add(f_pSrvParam, buffer(252,64)) pTree:add(f_pFrameStart, buffer(316,8)) pTree:add(f_pFrameLength, buffer(324,8)) pTree:add(f_pFrameFadeIn, buffer(332,8)) pTree:add(f_pFrameFadeOut, buffer(340,8)) local valueFactor = buffer(348,4):le_uint() pTree:add(f_pValueFactor, buffer(348,4)):set_text("Value Factor" .. valueFactor) pTree:add(f_pValueUse, buffer(349,1)) pTree:add(f_pTrack, buffer(350,4)) pTree:add(f_pRemark, buffer(354,64)) pTree:add(f_pDelay, buffer(418,8)) pTree:add(f_pDuration, buffer(426,8)) pTree:add(f_pAssigned, buffer(435,1)) local name = buffer(147,64):string() local tId = buffer(211,41):string() local oId = buffer(104,41):string() info_text = string.format("%s -> %s | Report SPIT Object: %s (%s / %s)", sessionInfos[tostring(pinfo.src)], sessionInfos[tostring(pinfo.dst)], name, oId, tId) elseif type == 33 then pTree:add(f_pSession, extractSession(buffer, pinfo)) pTree:add(f_pObjectId, buffer(103,41)) info_text = string.format("Remove SPIT Object") elseif type == 37 then pTree:add(f_pSession, extractSession(buffer, pinfo)) pTree:add(f_pPlayerId, buffer(103,41)) pTree:add(f_pPlayerName, buffer(144,64)) pTree:add(f_pPlayerType, buffer(208,1)) pTree:add(f_pPlayerRunning, buffer(209,1)) pTree:add(f_pPlayerFrames, buffer(210,8)) info_text = string.format("Play SPIT Start") elseif type == 38 then -- Play Spit object pTree:add(f_pSession, extractSession(buffer, pinfo)) pTree:add(f_pPlayerId, buffer(103,41)) pTree:add(f_pObjectId, buffer(144,41)) pTree:add(f_pObjectsFrames, buffer(185,8)) pTree:add(f_pPlayerPrePos, buffer(193,1)) pTree:add(f_pValue, buffer(194,4)) pTree:add(f_pValueFlag, buffer(198,1)) local oId = buffer(144,41):string() info_text = string.format("%s -> %s | Play SPIT Object: %s", sessionInfos[tostring(pinfo.src)], sessionInfos[tostring(pinfo.dst)], oId) elseif type == 39 then pTree:add(f_pSession, extractSession(buffer, pinfo)) pTree:add(f_pPlayerId, buffer(103,41)) info_text = string.format("Play SPIT End") elseif type == 40 then pTree:add(f_pSession, extractSession(buffer, pinfo)) pTree:add(f_pObjectId, buffer(103,41)) pTree:add(f_pObjectsFrames, buffer(144,8)) pTree:add(f_pValue, buffer(152,4)) info_text = string.format("Report Play Status") else info_text = string.format("ERROR Unknown") end pinfo.cols['info'] = info_text return true -- We handled this packet end function split(str, delim) local result = {} local delim_len = delim local s = 1 while true do local e, next_e = string.find(str, delim, s) if not e then table.insert(result, string.sub(str, s)) break end table.insert(result, string.sub(str, s, e - 1)) s = next_e + 1 end return result end -- Heuristic dissector function function spit_sad_proto.dissector(buffer, pinfo, tree) if buffer:len() < 14 then return false end if buffer(0,14):string() ~= "#SAD##,##spit#" then return false end pinfo.cols.protocol = "SPIT-SAD" local info_text = "SAD" if buffer:len() > 16 then local payload = buffer(0,buffer:len()):string() local parts = split(payload, "#,#") local subtree = tree:add(spit_sad_proto, buffer(), "Discovery Data") subtree:add(f_pSadKey, parts[1]) -- 1 #SAD# subtree:add(f_pKey, parts[2]) -- 2 #spit# subtree:add(f_pServerName, parts[3]) -- 3 liveShowSPIT subtree:add(f_hSerId , parts[4]) -- 4 405c7100-64e8-435d-8a7b-00c5629f9ccf subtree:add(f_pServerDevName, parts[5]) -- 5 P17gen1 subtree:add(f_pServerPort, parts[6]) -- 6 15120 subtree:add(f_pServerIp, parts[7]) -- 7 172.16.17.56 subtree:add(f_pProjectName, parts[9]) -- 9 CatasWatchProject info_text = string.format("SPIT-SAD Discover Data | Client: %s Porject: %s ", parts[4], parts[9]) else info_text = string.format("SPIT-SAD Discover") end pinfo.cols['info'] = info_text return true -- We handled this packet end -- Register as a heuristic UDP dissector spit_proto:register_heuristic("udp", spit_proto.dissector) spit_sad_proto:register_heuristic("udp", spit_sad_proto.dissector) -- local f_pFramesPerSec = ProtoField.uint32("spit.framesPerSec", "Frames per second") -- local f_pTrack = ProtoField.uint32("spit.track", "Track") -- local f_pObjectsFrames = ProtoField.uint64("spit.ObjectFrames", "Object Frames") -- local f_pValue = ProtoField.uint64("spit.Value", "Value") -- local f_pFrameStart = ProtoField.uint64("spit.frameStart", "Frame Start") -- local f_pFrameLength = ProtoField.uint64("spit.frameLength", "Frame Length") -- local f_pFrameFadeIn = ProtoField.uint64("spit.fadeInLength", "Fade In Length") -- local f_pFrameFadeOut = ProtoField.uint64("spit.fadeOutLength", "Fade Out Length") -- local f_pDelay = ProtoField.uint64("spit.delay", "Delay") -- local f_pDuration = ProtoField.uint64("spit.duration", "Duration") -- local f_pPlayerFrames = ProtoField.uint64("spit.PlayerFrame", "Player Frames")