使用lua给wireshark编写uTP的Dissector

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的参数一致。

  1. xx_protocol.dissector = function(buffer,pinfo,tree)
  2. --定义这个协议的解析函数,最后会将这个函数注册到wireshark用来解析数据的表中。这个函数的三个参数很重要,是wireshark引擎在调用该函数是会传入,
  3. --buffer就是我们要分析的数据,
  4. --pinfo记录了前面分析过协议留下的信息,
  5. --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:

  1. do
  2. -- Desc: uTP Protocol lua version
  3. -- Author: WangYao, [email protected]
  4. -- Date: 2011/10/19
  5. -- protol name
  6. local p_utp = Proto("utp", "Micro Transport Protocol");
  7. -- protocol fields
  8. local f_version = ProtoField.uint8("utp.version", "Version", base.DEC,
  9. {[1]="V1"}, 0x0F)
  10. local f_type = ProtoField.uint8("utp.type", "Type", base.DEC,
  11. {[0]="ST_DATA", [1]="ST_FIN", [2]="ST_STATE", [3]="ST_RESET", [4]="ST_SYN"}, 0xF0)
  12. local f_next_extension_type = ProtoField.uint8("utp.next_extension_type", "Next Extension Type", base.DEC,
  13. {[0]="No Extension", [1]="Selective acks", [2]="Extension bits"})
  14. local f_extension_len = ProtoField.uint8("utp.extension_len", "Extension Length", base.DEC)
  15. local f_extension_bitmask = ProtoField.bytes("utp.extension_bitmask", "Extension Bitmask", base.NONE)
  16. local f_connection_id = ProtoField.uint16("utp.connection_id", "Connection_ID", base.DEC)
  17. local f_timestamp_microseconds = ProtoField.uint32("utp.timestamp_microseconds", "timestamp_microseconds", base.DEC)
  18. local f_timestamp_difference_microseconds = ProtoField.uint32("utp.timestamp_difference_microseconds", "timestamp_difference_microseconds", base.DEC)
  19. local f_wnd_size = ProtoField.uint32("utp.wnd_size", "wnd_size", base.DEC)
  20. local f_seq_nr = ProtoField.uint16("utp.seq_nr", "seq_nr", base.DEC)
  21. local f_ack_nr = ProtoField.uint16("utp.ack_nr", "ack_nr", base.DEC)
  22. 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}
  23. -- other dissector
  24. local data_dis = Dissector.get("data")
  25. local bittorrent_dissector = Dissector.get("bittorrent.tcp")
  26. -- utp dissector, return OFFSET
  27. local function utp_dissector(buf,pkt,root)
  28. local buf_len = buf:len()
  29. local offset = 0
  30. -- check pack len
  31. if buf_len < 20 then return 0 end
  32. -- get fields
  33. local v_version = buf(offset, 1)
  34. local v_type = buf(offset, 1)
  35. offset = offset + 1
  36. local v_next_extension_type = buf(offset, 1)
  37. offset = offset + 1
  38. local v_connection_id = buf(offset, 2)
  39. offset = offset + 2
  40. local v_timestamp_microseconds = buf(offset, 4)
  41. offset = offset + 4
  42. local v_timestamp_difference_microseconds = buf(offset, 4)
  43. offset = offset + 4
  44. local v_wnd_size = buf(offset, 4)
  45. offset = offset + 4
  46. local v_seq_nr = buf(offset, 2)
  47. offset = offset + 2
  48. local v_ack_nr = buf(offset, 2)
  49. offset = offset + 2
  50. -- check uTP
  51. local i_version = bit.band(v_version:uint(), 0x0F)
  52. -- local i_type = bit.band(bit.rshift(v_type:uint(), 4), 0x0F)
  53. local i_type = bit.rshift(bit.band(v_type:uint(), 0xF0), 4)
  54. if( (i_version~=1) or (i_type~=0 and i_type~=1 and i_type~=2 and i_type~=3 and i_type~=4))
  55. then return 0 end
  56. local subtree = root:add(p_utp, buf(),"Micro Transport Protocol")
  57. -- just add header
  58. subtree:add(buf(0,0),"uTP Header: ")
  59. subtree:add(f_version, v_version)
  60. subtree:add(f_type, v_type)
  61. subtree:add(f_next_extension_type, v_next_extension_type)
  62. subtree:add(f_connection_id, v_connection_id)
  63. subtree:add(f_timestamp_microseconds, v_timestamp_microseconds)
  64. subtree:add(f_timestamp_difference_microseconds, v_timestamp_difference_microseconds)
  65. subtree:add(f_wnd_size, v_wnd_size)
  66. subtree:add(f_seq_nr, v_seq_nr)
  67. subtree:add(f_ack_nr, v_ack_nr)
  68. -- add pkt info
  69. pkt.cols.protocol = "uTP"
  70. if(i_type==0) then
  71. pkt.cols.info = "uTP ST_DATA"
  72. elseif(i_type==1) then
  73. pkt.cols.info = "uTP ST_FIN"
  74. elseif(i_type==2) then
  75. pkt.cols.info = "uTP ST_STATE"
  76. elseif(i_type==3) then
  77. pkt.cols.info = "uTP ST_RESET"
  78. elseif(i_type==4) then
  79. pkt.cols.info = "uTP ST_SYN"
  80. else
  81. pkt.cols.info = "uTP UNKNOW"
  82. end
  83. while(v_next_extension_type:uint()~=0) do
  84. -- add extension tree
  85. local extendtree = subtree:add(p_utp, buf(offset, buf_len-offset):tvb(),"Extension")
  86. if(v_next_extension_type:uint()==0) then
  87. extendtree:append_text(": NO Extension")
  88. elseif(v_next_extension_type:uint()==1) then
  89. extendtree:append_text(": Selective acks")
  90. elseif(v_next_extension_type:uint()==2) then
  91. extendtree:append_text(": Extension bits")
  92. end
  93. v_next_extension_type = buf(offset, 1)
  94. offset = offset + 1
  95. extendtree:add(f_next_extension_type, v_next_extension_type)
  96. local v_extension_len = buf(offset, 1)
  97. offset = offset + 1
  98. extendtree:add(f_extension_len, v_extension_len)
  99. local i_extension_len = v_extension_len:int()
  100. local v_extension_bitmask = buf(offset, i_extension_len)
  101. offset = offset + i_extension_len
  102. extendtree:add(f_extension_bitmask, v_extension_bitmask)
  103. end
  104. return offset
  105. end
  106. -- check packet is bittorrent? header legal
  107. local function check_bittorrent(buf)
  108. local len = buf:len()
  109. local pack_len = buf(0,4)
  110. local pack_type
  111. if(len<4) then
  112. return false
  113. elseif(buf(0,1):uint()==19 and len==68) then --handshake
  114. return true
  115. elseif(len==4) then --keepalive
  116. if(pack_len:uint()==0) then return true
  117. else return false
  118. end
  119. else
  120. pack_type = buf(4,1)
  121. --choke, unchoke, interested, not interested, have all, have none
  122. 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
  123. if(pack_len:uint()==1) then return true
  124. else return false
  125. end
  126. --request, cancel, reject
  127. elseif(pack_type:uint()==6 or pack_type:uint()==8 or pack_type:uint()==0x10) then
  128. if(pack_len:uint()==13) then return true
  129. else return false
  130. end
  131. --port
  132. elseif(pack_type:uint()==9) then
  133. if(pack_len:uint()==3) then return true
  134. else return false
  135. end
  136. --have, suggest, allowed fast
  137. elseif(pack_type:uint()==4 or pack_type:uint()==0x0D or pack_type:uint()==0x11) then
  138. if(pack_len:uint()==5) then return true
  139. else return false
  140. end
  141. --bitfield, extend
  142. elseif(pack_type:uint()==5 or pack_type:uint()==0x14) then
  143. if(pack_len:uint()<1024) then return true
  144. else return false
  145. end
  146. --piece, max than 16K
  147. elseif(pack_type:uint()==7) then
  148. if(pack_len:uint()>=16384) then return true
  149. else return false
  150. end
  151. else
  152. return false
  153. end
  154. end
  155. return false
  156. end
  157. -- protocol dissector, include bittorrent
  158. function p_utp.dissector(buf,pkt,root)
  159. local len = buf:len()
  160. local offset = utp_dissector(buf, pkt, root)
  161. if len>offset and offset>0 then
  162. -- call bittorrent dissector
  163. -- pass split PIECE pack
  164. if check_bittorrent(buf(offset, len-offset)) then
  165. bittorrent_dissector:call(buf(offset, len-offset):tvb(), pkt, root)
  166. else
  167. data_dis:call(buf(offset,len-offset):tvb(), pkt, root)
  168. end
  169. elseif offset==0 then
  170. -- call data dissector
  171. data_dis:call(buf,pkt,root)
  172. end
  173. end
  174. -- add to DissectorTable
  175. local udp_table = DissectorTable.get("udp.port")
  176. -- udp_table:add(4135, p_utp)
  177. udp_table:add(10000, p_utp)
  178. 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

时间: 2024-10-18 12:12:57

使用lua给wireshark编写uTP的Dissector的相关文章

用Lua写Wireshark插件

Create Wireshark Dissector by Lua 东方瀞[email protected] 1. Why Wireshark dissector Wireshark supports thousands of protocols now. But there are still some new protocols not supported and private protocols are not either. Fortunately, we can write diss

快速掌握Lua 5.3 —— 编写提供给Lua使用的C库函数的技巧 (2)

Q:什么是"registry"? A:有时候,我们需要在程序中使用一些非局部的变量.在C中我们可以使用全局变量或是静态变量来实现,而在为Lua编写C库的过程中,使用以上类型的变量并不是一个好的方式.首先,这些变量中无法存储Lua的值.其次,这些变量如果在多个Lua状态机中被使用,则很可能造成非预期的结果. 一个替代方案是,将这些值存储在Lua的全局变量中.这种方式解决了上面提到的两个问题,Lua全局变量可以存储任何Lua的值,同时每一个Lua状态机都有自己独立的一套全局变量.但这依旧不

Lua的模块编写与module函数

本文转载于:http://www.benmutou.com/archives/1786 1.编写一个简单的模块 Lua的模块是什么东西呢?通常我们可以理解为是一个table,这个table里有一些变量.一些函数… 等等,这不就是我们所熟悉的类吗? 没错,和类很像(实际上我说不出它们的区别). 我们来看看一个简单的模块,新建一个文件,命名为game.lua,代码如下: game = {} function game.play() print("那么,开始吧"); end function

Wireshark使用drcom_2011.lua插件协助分析drcom协议

drcom_2011.lua是来源于Google code上的一个开源项目中的一个插件,感谢网络大神的分享 需要使用drcom_2011.lua分析drcom协议的话,需要把drcom_2011.lua放到wireshark安装目录下(例如C:\Program Files\Wireshark), 然后打开安装目录的init.lua(用高级一些的文件编辑器打开可以看到分行信息),在最后一行加入dofile("drcom_2011.lua"),保存. 然后重启wireshark,在筛选器那

lua package编写

之前因为工作的需要学习了lua,在使用的过程中发现Lua挺好用的,故决定把这门语言好好学习一下.这段时间一直在学习Lua,也一直在使用Lua,但是因为工作忙的关系,都没有时间把这些学习的心得记录下来.趁着现在国庆放假期间,把上个月的学习心得记录一下,方便自己后续的查找与回顾(谁叫自己的记忆力已经大不如前了,有些知识长时间不用,就会生疏了). 好了,废话不多说,总结的内容大致有如下方面: 1) lua package的编写,会以自己编写的简单的loger模块为例进行介绍: 2) 在lua pack

Lua语言在Wireshark中使用(转)

1.       检查Wireshark的版本是否支持Lua 打开Wireshark,点击“HelpàAbout Wireshark”菜单,查看弹出的对话框,如果有“with Lua 5.1”表示支持Lua语言扩展,如果有“without Lua”表示不支持Lua扩展. 2.       启用LUA 在全局配置文件中启用LUA的方法是从init.lua文件中删除disable_lua这一行.该文件可以通过点击“HelpàAbout Wireshark”,在弹出的对话框中找到“FoldersàGl

【wireshark】Wireshark原理分析与二次开发系列

1.版权声明 本系列文章是本人花了很多心血写成,wireshark本是开源软件,本人也乐于技术知识和经验的分享,更是欣赏和推崇开源精神,因此任何看到本文的人都可以随意转载,但只有一个要求: 在大段甚至全文引用本系列文章内容的情况下,需要保留本人网名(赵子清)和本博客地址的全部或一部分(http://www.cnblogs.com/zzqcn). 2.引言 Wireshark是一款优秀的开源协议分析软件,多年来,全球无数开发者为Wireshark编写了数千种协议的解析插件(版本1.12.6已有15

在Unity3d中解析Lua脚本的方法

由于近期项目中提出了热更新的需求,因此本周末在Lua的陪伴下度过.对Lua与Unity3d的搭配使用,仅仅达到了一个初窥门径的程度,记录一二于此.水平有限,欢迎批评指正. 网络上关于Lua脚本和Unity3d的配合使用的资料不多,例子工程大多相同.大概了解到针对性的插件有uLua.UniLua.KopiLua三种.试用了前两种,抛开效率与安全性不说,感觉uLua试用起来比较简单,本文只介绍uLua的使用步骤. uLua的原理是在Unity3d中解析字符串形式的Lua脚本,让Lua与C#相互传递参

51CTO专访淘宝清无:漫谈Nginx服务器与Lua语言

http://os.51cto.com/art/201112/307610.htm 说到Web服务器,也许你第一时间会想到Apache,也许你会想到Nginx.虽然说Apache依然是Web服务器的老大,但是在全球前 1000大Web服务器当中,22.4%使用NGINX.这些服务器包括诸如Facebook.Hulu和WordPress之类的网络巨头使用的服务 器.在今年刚刚结束的O'Reilly Velocity China 2011会议上,51CTO编辑有幸采访到了目前就职淘宝的王晓哲.在<淘