如何在 Wireshark 中使用 Lua 字段提取器?

How to use Lua field extractor in Wireshark?

我有这样的协议
"Packet" - 一系列消息
{标题}{内容}{标题}{内容}...

"Head" - 1 个字节
位 1-7:消息长度
位 8:是否为真消息

这是一个udp通信,我必须使用第8位来确定是否需要跳过消息。
以下是我的玩具解析器,我面临的问题是如何提取布尔值帮助我做出决定。

TOY_proto = Proto("TOY", "TOY Protocol")

local isSkip = ProtoField.new("Is Skip?", "mytoy.isSkip", ftypes.BOOLEAN, {"Yes", "No"}, 8, 0x01)
local msgLen = ProroField.new("Message Length", "mytoy.msgLen", ftypes.UINT8, nil, base.DEC, 0xFE)

TOY_proto.fields = {isSkip, msgLen}

local isSkip_Field = Field.new("mytoy.isSkip")
local function getIsSkip()
    return isSkip_Field()()
end
local msgLen_Field = Field.new("mytoy.msgLen")
local function getMsgLen()
    return msgLen_Field()()
end

function TOY_proto.dissector(tvbuf, pktinfo, root)
    pktinfo.cols.protocol = "TOY"
    local pktlen = tvbuf:reported_length_remaining()
    local pos = 0

    while pos < pktlen do
        local headTree = tree:add("Head")
        headTree:add_le(isSkip, tvbuf:range(pos,1))
        headTree:add_le(msgLen, tvbuf:range(pos,1))
        if getIsSkip() then
            pos = pos + getMsgLen()
        else
            -- do something else
        end
    end
end
udp_table = DissectorTable.get("udp.port")
udp_table:add(6628, TOY_proto)

问题是在第一个循环中,每个变量都正确,但是在第一个循环之后,getIsSkip() 和 getMsgLen() 返回的值始终不变。

当你这样做时:

return isSkip_Field()()

你真正做的在逻辑上等同于:

-- extract the FieldInfo object using the Field object "isSkip_Field"
local tempFieldInfo = isSkip_Field()

-- get the Lua boolean value of the FieldInfo object
local tempValue = tempFieldInfo()

-- return it
return tempValue

我提到上面的内容是为了解释为什么你会得到你在这个答案后面得到的东西......

当您调用字段提取器时(即,您调用一个 Field 对象来获取一个 FieldInfo 对象),您实际上 每个 FieldInfo 那个 Field's type that exists in that packet at the time the extractor is invoked. Your packet contains multiple "messages" of your protocol, so in each loop you get back the previous loops' FieldInfo 对象的对象以及当前对象,对于同一个数据包。

换句话说,当您的脚本执行时:

return isSkip_Field()()

...第一次对于数据包,它取回一个 FieldInfo 对象,调用它,并得到布尔值。当它运行第二次时,对isSkip_Field()的调用实际上返回了两个FieldInfo个对象,但是它丢弃了第二个,因为代码在逻辑上是相当于我在这个答案的顶部写的代码,而不是只调用第一个实例,它当然 rteturns 与第一个循环迭代相同的布尔值;当它 运行 第三次处理同一个数据包时,它返回了三个 FieldInfo 对象,丢弃了第二个对象,称为第一个,等等

所以你真正想要做的是 select 正确的 FieldInfo 对象每次循环迭代 - 即最近(最后)一个。您可以通过以下两种方式之一执行此操作:(1) 使用 Lua select() 函数,或 (2) 将返回的 FieldInfo 对象放入 table 并检索最后一个条目。

例如,这样做:

local isSkip_Field = Field.new("mytoy.isSkip")
local function getIsSkip(num)
    return select(num, isSkip_Field())()
end
local msgLen_Field = Field.new("mytoy.msgLen")
local function getMsgLen(num)
    return select(num, msgLen_Field())()
end

function TOY_proto.dissector(tvbuf, pktinfo, root)
    pktinfo.cols.protocol = "TOY"
    local pktlen = tvbuf:reported_length_remaining()
    local pos = 0

    local num = 1
    while pos < pktlen do
        local headTree = tree:add("Head")
        headTree:add_le(isSkip, tvbuf:range(pos,1))
        headTree:add_le(msgLen, tvbuf:range(pos,1))
        if getIsSkip(num) then
            pos = pos + getMsgLen(num)
        else
            -- do something else
        end
        num = num + 1
    end
end

...或者这个:

local isSkip_Field = Field.new("mytoy.isSkip")
local function getIsSkip()
    local tbl = { isSkip_Field() }
    return tbl[#tbl]()
end
local msgLen_Field = Field.new("mytoy.msgLen")
local function getMsgLen()
    local tbl = { msgLen_Field() }
    return tbl[#tbl]()
end

function TOY_proto.dissector(tvbuf, pktinfo, root)
    pktinfo.cols.protocol = "TOY"
    local pktlen = tvbuf:reported_length_remaining()
    local pos = 0

    while pos < pktlen do
        local headTree = tree:add("Head")
        headTree:add_le(isSkip, tvbuf:range(pos,1))
        headTree:add_le(msgLen, tvbuf:range(pos,1))
        if getIsSkip() then
            pos = pos + getMsgLen()
        else
            -- do something else
        end
    end
end

...或者如果有很多字段,这可能会更好:

local isSkip_Field = Field.new("mytoy.isSkip")
local msgLen_Field = Field.new("mytoy.msgLen")

local function getFieldValue(field)
    local tbl = { field() }
    return tbl[#tbl]()
end

function TOY_proto.dissector(tvbuf, pktinfo, root)
    pktinfo.cols.protocol = "TOY"
    local pktlen = tvbuf:reported_length_remaining()
    local pos = 0

    while pos < pktlen do
        local headTree = tree:add("Head")
        headTree:add_le(isSkip, tvbuf:range(pos,1))
        headTree:add_le(msgLen, tvbuf:range(pos,1))
        if getFieldValue(isSkip_Field) then
            pos = pos + getFieldValue(msgLen_Field)
        else
            -- do something else
        end
    end
end