[Wireshark] 11.7. 向解析树中添加信息

1,724 阅读9分钟

11.7.1. TreeItem

<lua_class_TreeItem,TreeItem>>s 表示显示在Wireshark的数据包详情面板( packet details pane上的信息, 在Tshark上则是数据包详情界面(packet details view) ,一个 TreeItem 代表树上的一个节点,同时它也可以作为一个包含子节点列表的子树(subtree)。一个子树的子节点可以有零个或多个姊妹节点,这些姊妹节点也就是该子树的其他子节点;

在解析、启发式解析、后置解析的过程中,一个根(root) <lua_class_TreeItem ,TreeItem>>作为函数回调的第三个参数传递给解析器(e.g., myproto.dissector(tvbuf,pktinfo,root));

为了提高性能,在某些情况下 ,项并没有被真正的添加到树中。例如当数据包当前并没有在 Wireshark 的可视窗口面板(visible window pane)被展示/检索出来, 或者 Tshark 没有启用 -V 开关。不过 “添加( add)” 类型的 TreeItem 方法仍然可以被调用,并且仍可以返回一个 TreeItem 对象- 但信息(info)并没有被真正的添加到树中;

因此,你通常不需要关心是否有一个真正的树存在, 不过如果你出于某些理由非要知道的话,你可以使用TreeItem.visible 属性获取器来检索状态;

11.7.1.1. treeitem:add_packet_field(protofield, [tvbrange], encoding, [label])

向该树项(TreeItem)添加一个一个给定的 ProtoField 对象的新子树, 返回一个新的子 TreeItem

不同于 TreeItem:add()TreeItem:add_le() ,该方法中的 ProtoField 参数是非可选的,即必要的,而且也不能是一个 Proto 对象. 相反,该方法的第一个参数只能使用 ProtoField 来从传入的 TvbRange 中确定提取的字段类型, 并在GUI的数据包字节面板( Packet Bytes pane)中高亮相关字节(如果有GUI的话),,等等;

如果没有指定 TvbRange , 则不会有字节被高亮显示,字段的值也将无法确定。在这种情况下, ProtoField 必须被定义/创建为没有长度的类型,否则就会发生错误。然而,出于向后兼容的缘故,encoding 参数仍然必须要制定;

不同于 TreeItem:add()TreeItem:add_le() ,,该方法可以通过设置 ENC_BIG_ENDIAN 或者ENC_LITTLE_ENDIAN. encoding 参数,来决定是执行big-endian还是little-endian解码;

该方法的签名如下:

     tree_item:add_packet_field(proto_field [,tvbrange], encoding, ...)

在1.11.3版本的 Wireshark 中,该方法被修改为不仅仅返回一个子 TreeItem

一个子 TreeItem 是该方法的第一个返回值,此外它还将返回提取到的字段值 (即,一个数字, UInt64, Address, 等等). 如果它不能从 TvbRange 中提取到值,则仍返回一个子 TreeItem,而第二个返回值则为nil;

在1.11.3版本的 Wireshark 中,该方法的另一个新特性是能够从 TvbRange 的字符串编码中提取原生数字(native numberProtoFields,用于基于ASCII和类似的字符串的编码。例如,可以从一个包含ASCII字符串 "123 "的 TvbRange 中提取一个 ftypes.UINT32 类型的 ProtoField,无论是在树中还是在这个函数的第二个返回值中,它都将正确地将ASCII解码为数字123。要做到这一点,你必须将此函数的编码参数设置为适当的字符串ENC_ * 值,并与 ENC_STRING 值进行比特化处理(见init.lua)。ENC_STRING 被保证为唯一的位标志,因此它也可以直接添加而不是按位或(bitwise-or'ed)。只有单字节的ASCII数字字符串编码类型可用于此,如ENC_ASCIIENC_UTF_8

例如, 一个叫“tvb”的 Tvb中含有一个字符串“123” :

     -- this is done earlier in the script
     local myfield = ProtoField.new("Transaction ID", "myproto.trans_id", ftypes.UINT16)
​
     -- this is done inside a dissector, post-dissector, or heuristic function
     -- child will be the created child tree, and value will be the number 123 or nil on failure
     local child, value = tree:add_packet_field(myfield, tvb:range(0,3), ENC_UTF_8 + ENC_STRING)
  • 参数

    • protofield

      要添加到树中的 ProtoField 字段对象;

    • tvbrange(可选)

      该树项所覆盖/代表的数据包中的 TvbRange 字节数;

    • encoding

      该字段在 TvbRange 中的编码方式;

    • label (可选)

      一个或多个要追加到所创建的 TreeItem 上的字符串;

  • 返回值

    • 一个新的子 TreeItem, 该字段提取到的值,没有则为nil,以及偏移量,没有则为nil;

11.7.1.2. treeitem:add([protofield], [tvbrange], [value], [label])

向该树项中添加一个新的子项,返回一个新的 TreeItem

如果 Protofield 代表一个数值(int, uint 或 float),那么它将被视为大端序数(网络顺序)值;

这个方法有一个复杂的形式。'treeitem:add([protofield,] [tvbrange,] value], label)',这样,如果第一个参数是ProtoFieldProto,第二个参数是 TvbRange,并且第三个参数也被给定了,那么第三个参数就是 value;但是如果第二个参数不是一个 TvbRange,那么它就是 value(而不是把第二个参数填成'nil',这对该方法是无效的)。如果第一个参数是一个非 ProtoField和一个非 Proto,那么这个参数既可以是 TvbRange,也可以是一个 label,而 value 是不使用的;

11.7.2. 示例

    local proto_foo = Proto("foo", "Foo Protocol")
    proto_foo.fields.bytes = ProtoField.bytes("foo.bytes", "Byte array")
    proto_foo.fields.u16 = ProtoField.uint16("foo.u16", "Unsigned short", base.HEX)
​
    function proto_foo.dissector(buf, pinfo, tree)
            -- ignore packets less than 4 bytes long
            if buf:len() < 4 then return end
​
            -- ##############################################
            -- # Assume buf(0,4) == {0x00, 0x01, 0x00, 0x02}
            -- ##############################################
​
            local t = tree:add( proto_foo, buf() )
​
            -- Adds a byte array that shows as: "Byte array: 00010002"
            t:add( proto_foo.fields.bytes, buf(0,4) )
​
            -- Adds a byte array that shows as "Byte array: 313233"
            -- (the ASCII char code of each character in "123")
            t:add( proto_foo.fields.bytes, buf(0,4), "123" )
​
            -- Adds a tree item that shows as: "Unsigned short: 0x0001"
            t:add( proto_foo.fields.u16, buf(0,2) )
​
            -- Adds a tree item that shows as: "Unsigned short: 0x0064"
            t:add( proto_foo.fields.u16, buf(0,2), 100 )
​
            -- Adds a tree item that shows as: "Unsigned short: 0x0064 ( big endian )"
            t:add( proto_foo.fields.u16, buf(1,2), 100, nil, "(", nil, "big", 999, nil, "endian", nil, ")" )
​
            -- LITTLE ENDIAN: Adds a tree item that shows as: "Unsigned short: 0x0100"
            t:add_le( proto_foo.fields.u16, buf(0,2) )
​
            -- LITTLE ENDIAN: Adds a tree item that shows as: "Unsigned short: 0x6400"
            t:add_le( proto_foo.fields.u16, buf(0,2), 100 )
​
            -- LITTLE ENDIAN: Adds a tree item that shows as: "Unsigned short: 0x6400 ( little endian )"
            t:add_le( proto_foo.fields.u16, buf(1,2), 100, nil, "(", nil, "little", 999, nil, "endian", nil, ")" )
    end
​
    udp_table = DissectorTable.get("udp.port")
    udp_table:add(7777, proto_foo)
  • 参数

    • protofield (可选)

      一个要添加到树中的 ProtoField 字段或一个 Proto 协议对象;

    • tvbrange (可选)

      该树项所覆盖/代表的数据包中的 TvbRange 字节数;

    • value (可选)

      字段的值,取代 ProtoField/Proto 中字段的值;

    • label (可选)

      一个或多个字符串,用于树项的标签,取代 ProtoField/Proto 的标签;

  • 返回值

    • 一个新的子 TreeItem

11.7.2.1. treeitem:add_le([protofield], [tvbrange], [value], [label])

向该树项中添加一个新的子项,返回一个新的 TreeItem

如果 Protofield 代表一个数值(int, uint 或 float),那么它将被视为小端序数值;

这个方法有一个复杂的形式。'treeitem:add([protofield,] [tvbrange,] value], label)',这样,如果第一个参数是ProtoFieldProto,第二个参数是 TvbRange,并且第三个参数也被给定了,那么第三个参数就是 value;但是如果第二个参数不是一个 TvbRange,那么它就是 value(而不是把第二个参数填成'nil',这对该方法是无效的)。如果第一个参数是一个非 ProtoField和一个非 Proto,那么这个参数既可以是 TvbRange,也可以是一个 label,而 value 是不使用的;

  • 参数

    • protofield (可选)

      一个要添加到树中的 ProtoField 字段或一个 Proto 协议对象;

    • tvbrange (可选)

      该树项所覆盖/代表的数据包中的 TvbRange 字节数;

    • value (可选)

      字段的值,取代 ProtoField/Proto 中的字段值;

    • label (可选)

      一个或多个字符串,用于树项的标签,取代 ProtoField/Proto 的标签;

  • 返回值

    • 一个新的子 TreeItem

11.7.2.2. treeitem:set_text(text)

设置标签的文本;

之前,使用此方法不返回任何东西,但自从 1.11.3 版本开始,它会返回一个相同的树项,以允许链式调用;

  • 参数

    • text

      要使用的文本;

  • 返回值

    • 一个相同的树项;

11.7.2.3. treeitem:append_text(text)

在标签上添加文本;

之前,使用此方法不返回任何东西,但自从 1.11.3 版本开始,它会返回一个相同的树项,以允许链式调用;

  • 参数

    • text

      用来添加的文本;

  • 返回值

    • 一个相同的树项;

11.7.2.4. treeitem:prepend_text(text)

在标签的前部添加文本;

之前,使用此方法不返回任何东西,但自从 1.11.3 版本开始,它会返回一个相同的树项,以允许链式调用;

  • 参数

    • text

      用来添加的文本;

  • 返回值

    • 一个相同的树项;

11.7.2.5. treeitem:add_expert_info([group], [severity], [text])

设置项目的专家标志,并将专家信息添加到数据包中;

这个函数不会为一个协议创建一个真正的可过滤的专家信息。相反,你应该使用TreeItem.add_proto_expert_info() 来达成这个目的;

ps:这个函数只是为了向后兼容而提供,不应该在新的Lua代码中使用。它可能在未来被删除。你应该只使用TreeItem.add_proto_expert_info()

  • 参数

    • group (可选)

      可以是: PI_CHECKSUM, PI_SEQUENCE, PI_RESPONSE_CODE, PI_REQUEST_CODE, PI_UNDECODED, PI_REASSEMBLE, PI_MALFORMEDPI_DEBUG.

    • severity (可选)

      可以是: PI_CHAT, PI_NOTE, PI_WARN, 或 PI_ERROR.

    • text (可选)

      专家信息要展示的文本;

  • 返回值

    • 一个相同的树项;

11.7.2.6. treeitem:add_proto_expert_info(expert, [text])

设置树项的专家标志,并将专家信息添加到数据包中;

  • 参数

    • expert

      需要添加到树中的 ProtoExpert 对象;

    • text (可选)

      专家信息要展示的文本 (默认使用注册文本);

  • 返回值

    • 一个相同的树项;

11.7.2.7. treeitem:add_tvb_expert_info(expert, tvb, [text])

设置该树项的专家标志,并向数据包添加与数据包中 TvbTvbRange 相关的字节 ;

  • 参数

    • expert

      需要添加到树中的 ProtoExpert 对象;

    • tvb

      与专家信息相关的 Tvb 或 TvbRange 对象字节;

    • text (可选)

      专家信息要展示的文本 (默认使用注册文本);

  • 返回值

    • 一个相同的树项;

11.7.2.8. treeitem:set_generated([bool])

TreeItem 标记为一个生成字段(generated field)(有数据推断但不包含在数据包中);

之前,使用此方法不返回任何东西,但自从 1.11.3 版本开始,它会返回一个相同的树项,以允许链式调用;

  • 参数

    • bool (optional)

      一个 Lua 的布尔型,如果为 Ture 则将 TreeItem 标记为生成字段,否则将其清除(默认为Ture)

  • 返回值

    • 一个相同的树项;

11.7.2.9. treeitem:set_hidden([bool])

TreeItem 标记为隐藏字段(既不显示也不在过滤器中使用);已废弃

之前,使用此方法不返回任何东西,但自从 1.11.3 版本开始,它会返回一个相同的树项,以允许链式调用;

  • 参数

    • bool (optional)

      一个 Lua 的布尔型,如果为 Ture 则将 TreeItem 标记为生成字段,否则将其清除(默认为Ture)

  • 返回值

    • 一个相同的树项;

11.7.2.10. treeitem:set_len(len)

TreeItem 已经被创建之后,在 tvb 的内部设置其长度;

之前,使用此方法不返回任何东西,但自从 1.11.3 版本开始,它会返回一个相同的树项,以允许链式调用;

  • 参数

    • len

      要使用的长度;

  • 返回值

    • 一个相同的树项;

11.7.2.11. treeitem:referenced(protofield)

检查一个 ProtoFieldDissector 是否被一个过滤器/Tap/UI引用;

如果该方法返回 False,意味着这个字段(或Dissector)不需要被解析,可以安全地跳过。通过跳过一个字段而不是解析它,解析器通常会运行得更快,因为 Wireshark 在不需要这个字段时不会做额外的解析工作;

你可以把它和 TreeItem.visible 属性结合起来使用。当 TreeItem 是可见的,该方法将总是返回 TRUE。当它不可见并且字段没有被引用时,你可以通过不解析字段来加快解析速度,因为显示或过滤时将不需要它;

该方法需要一个参数,可以是一个 ProtoFieldDissector

当你需要决定是否调用一个子 Dissector 时,Dissector 形式很有用。

  • 参数

    • protofield

      需要检查是否被引用的 ProtoFieldDissector ;

  • 返回值

    • 表示该 ProtoField/Dissector 是否被引用的布尔值;

11.7.2.12. treeitem:__tostring()

返回一个 TreeItem 的调试信息字符串;

11.7.2.13. treeitem.text

模式:仅用于检索或赋值(Mode: Retrieve or assign);

设置或获取该 TreeItem 的 显示字符串 (string);

当作为获取器时,如果该 TreeItem 没有显示字符串,则返回nil;

11.7.2.14. treeitem.visible

模式:仅用于检索(Mode: Retrieve only)

获取该 TreeItem 的子树的状态 (boolean);

11.7.2.15. treeitem.generated

模式:仅用于检索或赋值(Mode: Retrieve or assign);

设置或获取该 TreeItem 的 生成状态 (boolean);

11.7.2.16. treeitem.hidden

模式:仅用于检索或赋值(Mode: Retrieve or assign);

设置/获取 TreeItem的隐藏状态 (boolean).

11.7.2.17. treeitem.len

模式:仅用于检索或赋值(Mode: Retrieve or assign);

TreeItem以及被创建后, 设置/获取 TreeItemtvb 内部的长度;