您的位置:首页 > 编程语言 > Lua

使用lua给wireshark编写uTP的Dissector

2014-11-04 11:34 621 查看
lonelycastle做uTP的实验,使用wireshark捕包,但是最初没有找到wireshark下的uTP的dissector,每次都需要比对文档,这样做实验理解报文含义,效率非常低。作为程序猿就想写一个uTP的dissector来实现这些工作。说干就干,查了一下发现wireshark可以使用lua来实现dissector,这样就简单过了,不用编写C的dissector了。本身是lua盲,又不了解wireshark的dissector开发,中间遇到了很多问题,还好逻辑比较简单,折腾了一个晚上就搞定了;-)

BTW: 后来发现wireshark中已经有了bt-utp这个dissector,但是没有判断PIECE分包。

1. 如何定义小于1个字节的field
>> 查了一下User Guide,发现可以在创建ProtoField的时候,使用mask参数就可以了。
2. 如何取小于1个字节field的值
>> 这个需要位操作进行处理,具体见参考文献1。主要是bit.band, bit.bor, bit.bxor, bit.rshift, bit.lshift等。注意右移位是bit.rshift,而不是bit.brshift。
3. 如何调用其他Dissector
>> Dissector.get()获得系统中已经有的dissector;DissectorTable.get()获得系统中已经有的dissector table,再调用get_dissector()获得最终的dissector。
>> 获得dissector后,就可以直接调用call,call的参数跟dissector function的参数一致。

xx_protocol.dissector = function(buffer,pinfo,tree)

--定义这个协议的解析函数,最后会将这个函数注册到wireshark用来解析数据的表中。这个函数的三个参数很重要,是wireshark引擎在调用该函数是会传入,

--buffer就是我们要分析的数据,

--pinfo记录了前面分析过协议留下的信息,

--tree是用来在详细框中添加我们信息的结构。

4. 如何设置报文信息
>>直接修改pkt.cols.info,其中pkt是dissector function传入的参数,具体见参考文献4.

5. 如何处理一个应用报文跨多个uTP报文
>>在BitTorrent中,PIECE报文比较大,会跨多个uTP报文,这个时候需要判断出第一个PIECE报文,进行解析,后面的PIECE报文不需要解析,如果解析就会导致出错。这里是使用一个检查函数,判断每种type下,协议中数据长度是否满足限制来实现的。

具体如何运行这里就不多说了,直接在init.lua中最后增加dofile就可以,注意要首先把lua_disable关上,debian用户需要保证root也可以在wireshark中运行lua。调试的时候可以看wireshark的报错信息。

示例代码如下,BitTorrent的解析调用了wireshark内部已有的bittorrent.tcp dissector:

do

-- Desc: uTP Protocol lua version

-- Author: WangYao, ipconfigme@gmail.com

-- Date: 2011/10/19

-- protol name

local p_utp = Proto("utp", "Micro Transport Protocol");

-- protocol fields

local f_version = ProtoField.uint8("utp.version", "Version", base.DEC,

{[1]="V1"}, 0x0F)

local f_type = ProtoField.uint8("utp.type", "Type", base.DEC,

{[0]="ST_DATA", [1]="ST_FIN", [2]="ST_STATE", [3]="ST_RESET", [4]="ST_SYN"}, 0xF0)

local f_next_extension_type = ProtoField.uint8("utp.next_extension_type", "Next Extension Type", base.DEC,

{[0]="No Extension", [1]="Selective acks", [2]="Extension bits"})

local f_extension_len = ProtoField.uint8("utp.extension_len", "Extension Length", base.DEC)

local f_extension_bitmask = ProtoField.bytes("utp.extension_bitmask", "Extension Bitmask", base.NONE)

local f_connection_id = ProtoField.uint16("utp.connection_id", "Connection_ID", base.DEC)

local f_timestamp_microseconds = ProtoField.uint32("utp.timestamp_microseconds", "timestamp_microseconds", base.DEC)

local f_timestamp_difference_microseconds = ProtoField.uint32("utp.timestamp_difference_microseconds", "timestamp_difference_microseconds", base.DEC)

local f_wnd_size = ProtoField.uint32("utp.wnd_size", "wnd_size", base.DEC)

local f_seq_nr = ProtoField.uint16("utp.seq_nr", "seq_nr", base.DEC)

local f_ack_nr = ProtoField.uint16("utp.ack_nr", "ack_nr", base.DEC)

p_utp.fields = {f_version, f_type, f_next_extension_type, f_extension_len, f_extension_bitmask, f_connection_id, f_timestamp_microseconds, f_timestamp_difference_microseconds, f_wnd_size, f_seq_nr, f_ack_nr}

-- other dissector

local data_dis = Dissector.get("data")

local bittorrent_dissector = Dissector.get("bittorrent.tcp")

-- utp dissector, return OFFSET

local function utp_dissector(buf,pkt,root)

local buf_len = buf:len()

local offset = 0

-- check pack len

if buf_len < 20 then return 0 end

-- get fields

local v_version = buf(offset, 1)

local v_type = buf(offset, 1)

offset = offset + 1

local v_next_extension_type = buf(offset, 1)

offset = offset + 1

local v_connection_id = buf(offset, 2)

offset = offset + 2

local v_timestamp_microseconds = buf(offset, 4)

offset = offset + 4

local v_timestamp_difference_microseconds = buf(offset, 4)

offset = offset + 4

local v_wnd_size = buf(offset, 4)

offset = offset + 4

local v_seq_nr = buf(offset, 2)

offset = offset + 2

local v_ack_nr = buf(offset, 2)

offset = offset + 2

-- check uTP

local i_version = bit.band(v_version:uint(), 0x0F)

-- local i_type = bit.band(bit.rshift(v_type:uint(), 4), 0x0F)

local i_type = bit.rshift(bit.band(v_type:uint(), 0xF0), 4)

if( (i_version~=1) or (i_type~=0 and i_type~=1 and i_type~=2 and i_type~=3 and i_type~=4))

then return 0 end

local subtree = root:add(p_utp, buf(),"Micro Transport Protocol")

-- just add header

subtree:add(buf(0,0),"uTP Header: ")

subtree:add(f_version, v_version)

subtree:add(f_type, v_type)

subtree:add(f_next_extension_type, v_next_extension_type)

subtree:add(f_connection_id, v_connection_id)

subtree:add(f_timestamp_microseconds, v_timestamp_microseconds)

subtree:add(f_timestamp_difference_microseconds, v_timestamp_difference_microseconds)

subtree:add(f_wnd_size, v_wnd_size)

subtree:add(f_seq_nr, v_seq_nr)

subtree:add(f_ack_nr, v_ack_nr)

-- add pkt info

pkt.cols.protocol = "uTP"

if(i_type==0) then

pkt.cols.info = "uTP ST_DATA"

elseif(i_type==1) then

pkt.cols.info = "uTP ST_FIN"

elseif(i_type==2) then

pkt.cols.info = "uTP ST_STATE"

elseif(i_type==3) then

pkt.cols.info = "uTP ST_RESET"

elseif(i_type==4) then

pkt.cols.info = "uTP ST_SYN"

else

pkt.cols.info = "uTP UNKNOW"

end

while(v_next_extension_type:uint()~=0) do

-- add extension tree

local extendtree = subtree:add(p_utp, buf(offset, buf_len-offset):tvb(),"Extension")

if(v_next_extension_type:uint()==0) then

extendtree:append_text(": NO Extension")

elseif(v_next_extension_type:uint()==1) then

extendtree:append_text(": Selective acks")

elseif(v_next_extension_type:uint()==2) then

extendtree:append_text(": Extension bits")

end

v_next_extension_type = buf(offset, 1)

offset = offset + 1

extendtree:add(f_next_extension_type, v_next_extension_type)

local v_extension_len = buf(offset, 1)

offset = offset + 1

extendtree:add(f_extension_len, v_extension_len)

local i_extension_len = v_extension_len:int()

local v_extension_bitmask = buf(offset, i_extension_len)

offset = offset + i_extension_len

extendtree:add(f_extension_bitmask, v_extension_bitmask)

end

return offset

end

-- check packet is bittorrent? header legal

local function check_bittorrent(buf)

local len = buf:len()

local pack_len = buf(0,4)

local pack_type

if(len<4) then

return false

elseif(buf(0,1):uint()==19 and len==68) then --handshake

return true

elseif(len==4) then --keepalive

if(pack_len:uint()==0) then return true

else return false

end

else

pack_type = buf(4,1)

--choke, unchoke, interested, not interested, have all, have none

if(pack_type:uint()==0 or pack_type:uint()==1 or pack_type:uint()==2 or pack_type:uint()==3 or pack_type:uint()==0x0E or pack_type:uint()==0x0F) then

if(pack_len:uint()==1) then return true

else return false

end

--request, cancel, reject

elseif(pack_type:uint()==6 or pack_type:uint()==8 or pack_type:uint()==0x10) then

if(pack_len:uint()==13) then return true

else return false

end

--port

elseif(pack_type:uint()==9) then

if(pack_len:uint()==3) then return true

else return false

end

--have, suggest, allowed fast

elseif(pack_type:uint()==4 or pack_type:uint()==0x0D or pack_type:uint()==0x11) then

if(pack_len:uint()==5) then return true

else return false

end

--bitfield, extend

elseif(pack_type:uint()==5 or pack_type:uint()==0x14) then

if(pack_len:uint()<1024) then return true

else return false

end

--piece, max than 16K

elseif(pack_type:uint()==7) then

if(pack_len:uint()>=16384) then return true

else return false

end

else

return false

end

end

return false

end

-- protocol dissector, include bittorrent

function p_utp.dissector(buf,pkt,root)

local len = buf:len()

local offset = utp_dissector(buf, pkt, root)

if len>offset and offset>0 then

-- call bittorrent dissector

-- pass split PIECE pack

if check_bittorrent(buf(offset, len-offset)) then

bittorrent_dissector:call(buf(offset, len-offset):tvb(), pkt, root)

else

data_dis:call(buf(offset,len-offset):tvb(), pkt, root)

end

elseif offset==0 then

-- call data dissector

data_dis:call(buf,pkt,root)

end

end

-- add to DissectorTable

local udp_table = DissectorTable.get("udp.port")

-- udp_table:add(4135, p_utp)

udp_table:add(10000, p_utp)

end

参考
http://www.wowwiki.com/Lua_functions
http://bittorrent.org/beps/bep_0000.html
http://wiki.wireshark.org/Lua/Dissectors
http://sharkfest.wireshark.org/sharkfest.09/DT06_Bjorlykke_Lua%20Scripting%20in%20Wireshark.pdf
http://lua-bitstring.googlecode.com/svn-history/r62/wiki/ExplainFastDissect.wiki
http://www.wireshark.org/download/docs/user-guide-a4.pdf
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: