本篇博文重点介绍如何基于Lua语言去编写wireshark插件。
接口 | 说明 |
---|---|
proto:__call (name,desc) | 创建Proto对象。name和desc分别是对象的名称和描述,前者可用于过滤器等 |
proto.name | get名称 |
proto.fields | get/set字段 |
proto.prefs | get配置项 |
proto.init | 初始化,无参数 |
proto.dissector | 解析函数,3个参数tvb,pinfo,tree,分别是报文内容,报文信息和解析树结构 |
proto:register_heuristic (listname, func) | 为Proto注册一个启发式解析器,被调用时,参数func将被传入与dissector方法相同的3个参数 |
local NAME1 = "red"
local PORT = 5004
local RTP_PROTO_TYPE = 106
local red = Proto(NAME1, "Red Protocol")
表示协议字段,一般用于解析字段后往解析树上添加节点。根据字段类型不同,其接口可以分为两大类。
整型:
• ProtoField.{type} (abbr, [name], [desc],[base], [valuestring], [mask])
type包括:uint8, uint16, uint24, uint32, uint64, framenum
其他类型
• ProtoField.{type} (abbr, [name], [desc])
type包括:float, double, string, stringz, bytes, bool, ipv4, ipv6, ether,oid, guid
这些接口都会返回一个新的字段对象。方括号内是可选字段,花括号内是可替换的类型字段。
如下图的例子,
-- create fields of red
fields_M = ProtoField.uint8 (NAME1 .. ".M", "M", base.HEX,Payload_type,0x80)
fields_pt = ProtoField.uint8 (NAME1 .. ".PT", "PT", base.DEC,Payload_type,0x7F)
fields_seqno = ProtoField.uint16(NAME1 .. ".seqno", "Sequence number")
fields_h264bytes = ProtoField.bytes(NAME1 .. ".bytes", "H264Data")
fields_fec = ProtoField.bytes(NAME1 .. ".fec", "FEC Payload")
接口 | 说明 |
---|---|
tvb:__tostring() | 将报文数据转化为字符串,可用于调试 |
tvb:reported_len() | get tvb的(not captured)长度 |
tvb:len() | get tvb的(captured)长度 |
tvb:reported_length_remaining() | 获取当前tvb的剩余长度,如果偏移值大于报文长度,则返回-1 |
tvb:offset() | 返回原始偏移 |
接口 | 说明 |
---|---|
pinfo.len pinfo.caplen | get报文长度 |
pinfo.abs_ts | get报文捕获时间 |
pinfo.number | get报文编号 |
pinfo.src pinfo.dst | get/set报文的源地址、目的地址 |
pinfo.columns pinfo.cols | get报文列表列(界面) |
-- show protocol name in protocol column
pinfo.cols.protocol = red.name
接口 | 说明 |
---|---|
DissectorTable.get(name) | get名为name的解析表的引用 |
dissectortable:add(pattern, dissector) | 将Proto或Dissector对象添加到解析表,即注册。pattern可以是整型值,整型值范围或字符串,这取决于当前解析表的类型 |
dissectortable:remove(pattern, dissector) | 将满足pattern的一个或一组Proto、Dissector对象从解析表中删除 |
-- create a new dissector
local NAME = "red"
local PORT = 5004
local red = Proto(NAME, "Red Protocol")
-- dissect packet
function red.dissector (tvb, pinfo, tree)
end
-- register this dissector
DissectorTable.get("udp.port"):add(PORT, red)
local version_str = string.match(_VERSION, "%d+[.]%d*")
local version_num = version_str and tonumber(version_str) or 5.1
local bit = (version_num >= 5.2) and require("bit32") or require("bit")
-- create a new dissector to decode rtp private payload
local NAME1 = "red"
local PORT = 5004
local RTP_PROTO_TYPE = 106
local red = Proto(NAME1, "Red Protocol")
-- create fields of red
fields_M = ProtoField.uint8 (NAME1 .. ".M", "M", base.HEX,Payload_type,0x80)
fields_pt = ProtoField.uint8 (NAME1 .. ".PT", "PT", base.DEC,Payload_type,0x7F)
fields_seqno = ProtoField.uint16(NAME1 .. ".seqno", "Sequence number")
fields_h264bytes = ProtoField.bytes(NAME1 .. ".bytes", "H264Data")
fields_fec = ProtoField.bytes(NAME1 .. ".fec", "FEC Payload")
red.fields = { fields_M, fields_pt, fields_seqno, fields_h264bytes,fields_fec }
local RTP_dis = Dissector.get("rtp")
local H264_dis = Dissector.get("h264")
local Data_dis = Dissector.get("data")
-- dissect packet
function red.dissector(tvb, pinfo, tree)
length = tvb:len()
if length == 0 then return end
-- decode private header
local subtree = tree:add(red, tvb(0,3))
subtree:add(fields_M, tvb(0,1))
subtree:add(fields_pt, tvb(0,1))
subtree:add(fields_seqno, tvb(1,2))
-- show protocol name in protocol column
pinfo.cols.protocol = red.name
local fec_id = tvb(0,1):uint()
local fec_type = bit.band(fec_id,0x7F)
if fec_type == 109 then
tree:add(fields_fec,tvb(3))
else
H264_dis:call(tvb(3):tvb(), pinfo, tree)
end
end
--decode first layer as rtp
local udp_dissector_table = DissectorTable.get("udp.port")
udp_dissector_table:set(PORT,RTP_dis)
-- register this dissector
-- DissectorTable.get("rtp.pt"):add(PORT, red)
--decode private protocol layer 3-bytes private datas + standard h264
local rtp_dissector_table = DissectorTable.get("rtp.pt")
rtp_dissector_table:set(RTP_PROTO_TYPE,red)