--[[ Copyright (C) 2024 Christopher Maynard This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. --]] ------------------------------------------------------------------------- --[[ iec60870post.lua IEC60870 Postdissector. https://ask.wireshark.org/question/34066/extract-dissected-fields-from-a-capture-with-lua-console/ --]] local iec60870_post_info = { version = "1.1", author = "Christopher Maynard", description = "IEC60870 Postdissector" } set_plugin_info(iec60870_post_info) local iec60870_post = Proto("IEC60870Post", "IEC60870 Postdissector") local num = Field.new("frame.number") local asdu = Field.new("iec60870_asdu") local typeid = Field.new("iec60870_asdu.typeid") local ioa = Field.new("iec60870_asdu.ioa") local float = Field.new("iec60870_asdu.float") local cp56time = Field.new("iec60870_asdu.cp56time") local frame_visited = {} function iec60870_post.dissector(tvbuf, pinfo, tree) local asdu_ex = {asdu()} local typeid_ex = {typeid()} local ioa_ex = {ioa()} local float_ex = {float()} local cp56time_ex = {cp56time()} if frame_visited[num().value] == true or asdu_ex == nil or typeid_ex == nil then return end for i in pairs(asdu_ex) do local asdu_start_off = asdu_ex[i].offset local asdu_end_off = asdu_start_off + asdu_ex[i].len for j in pairs(typeid_ex) do local typeid_start_off = typeid_ex[j].offset local typeid_end_off = typeid_start_off + typeid_ex[j].len if asdu_ex[i].source == typeid_ex[j].source and asdu_start_off == typeid_start_off and typeid_ex[j].value == 36 then local result = nil for k in pairs(ioa_ex) do local ioa_start_off = ioa_ex[k].offset local ioa_end_off = ioa_start_off + ioa_ex[k].len if asdu_ex[i].source == ioa_ex[k].source and ioa_start_off >= asdu_start_off and ioa_end_off <= asdu_end_off then for l in pairs(float_ex) do local float_start_off = float_ex[l].offset local float_end_off = float_start_off + float_ex[l].len if asdu_ex[i].source == float_ex[l].source and float_start_off > typeid_start_off and float_start_off == ioa_end_off then if result == nil then result = tostring(num().value) .. ") TypeId: " .. typeid_ex[j].value .. "\n" end result = result .. "\tIOA: " .. ioa_ex[k].value .. "\n" result = result .. "\tFloat: " .. float_ex[l].value .. "\n" --[ for m in pairs(cp56time_ex) do local cp56time_start_off = cp56time_ex[m].offset local cp56time_end_off = cp56time_start_off + cp56time_ex[m].len if asdu_ex[i].source == cp56time_ex[m].source and cp56time_start_off > ioa_end_off and cp56time_end_off <= (ioa_start_off + 8 + cp56time_ex[m].len) then result = result .. "\tCP56Time: " .. cp56time_ex[m].display .. "\n" end end --]] end end end end if result ~= nil then print(result) end end end end frame_visited[num().value] = true end register_postdissector(iec60870_post)