• 使用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, ipconfigme@gmail.com
    4.     -- Date: 2011/10/19
    5.     
    6.     -- protol name
    7.     local p_utp = Proto("utp", "Micro Transport Protocol");
    8.     -- protocol fields
    9.     local f_version = ProtoField.uint8("utp.version", "Version", base.DEC,
    10.     {[1]="V1"}, 0x0F)
    11.     local f_type = ProtoField.uint8("utp.type", "Type", base.DEC, 
    12.     {[0]="ST_DATA", [1]="ST_FIN", [2]="ST_STATE", [3]="ST_RESET", [4]="ST_SYN"}, 0xF0)
    13.     local f_next_extension_type = ProtoField.uint8("utp.next_extension_type", "Next Extension Type", base.DEC, 
    14.     {[0]="No Extension", [1]="Selective acks", [2]="Extension bits"})
    15.     local f_extension_len = ProtoField.uint8("utp.extension_len", "Extension Length", base.DEC)
    16.     local f_extension_bitmask = ProtoField.bytes("utp.extension_bitmask", "Extension Bitmask", base.NONE)
    17.     local f_connection_id = ProtoField.uint16("utp.connection_id", "Connection_ID", base.DEC)
    18.     local f_timestamp_microseconds = ProtoField.uint32("utp.timestamp_microseconds", "timestamp_microseconds", base.DEC)
    19.     local f_timestamp_difference_microseconds = ProtoField.uint32("utp.timestamp_difference_microseconds", "timestamp_difference_microseconds", base.DEC)
    20.     local f_wnd_size = ProtoField.uint32("utp.wnd_size", "wnd_size", base.DEC)
    21.     local f_seq_nr = ProtoField.uint16("utp.seq_nr", "seq_nr", base.DEC)
    22.     local f_ack_nr = ProtoField.uint16("utp.ack_nr", "ack_nr", base.DEC)
    23.     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}
    24.     -- other dissector
    25.     local data_dis = Dissector.get("data")
    26.     local bittorrent_dissector = Dissector.get("bittorrent.tcp")
    27.     -- utp dissector, return OFFSET
    28.     local function utp_dissector(buf,pkt,root)
    29.         local buf_len = buf:len()
    30.         local offset = 0
    31.         -- check pack len
    32.         if buf_len < 20 then return 0 end
    33.         -- get fields
    34.         local v_version = buf(offset, 1)
    35.         local v_type = buf(offset, 1)
    36.         offset = offset + 1
    37.         local v_next_extension_type = buf(offset, 1)
    38.         offset = offset + 1
    39.         local v_connection_id = buf(offset, 2)
    40.         offset = offset + 2
    41.         local v_timestamp_microseconds = buf(offset, 4)
    42.         offset = offset + 4
    43.         local v_timestamp_difference_microseconds = buf(offset, 4)
    44.         offset = offset + 4
    45.         local v_wnd_size = buf(offset, 4)
    46.         offset = offset + 4
    47.         local v_seq_nr = buf(offset, 2)
    48.         offset = offset + 2
    49.         local v_ack_nr = buf(offset, 2)
    50.         offset = offset + 2
    51.         -- check uTP
    52.         local i_version = bit.band(v_version:uint(), 0x0F)
    53.         -- local i_type = bit.band(bit.rshift(v_type:uint(), 4), 0x0F)
    54.         local i_type = bit.rshift(bit.band(v_type:uint(), 0xF0), 4)
    55.         if( (i_version~=1) or (i_type~=0 and i_type~=1 and i_type~=2 and i_type~=3 and i_type~=4))
    56.             then return 0 end
    57.         local subtree = root:add(p_utp, buf(),"Micro Transport Protocol")
    58.         -- just add header
    59.         subtree:add(buf(0,0),"uTP Header: ") 
    60.         subtree:add(f_version, v_version)
    61.         subtree:add(f_type, v_type)
    62.         subtree:add(f_next_extension_type, v_next_extension_type)
    63.         subtree:add(f_connection_id, v_connection_id)
    64.         subtree:add(f_timestamp_microseconds, v_timestamp_microseconds)
    65.         subtree:add(f_timestamp_difference_microseconds, v_timestamp_difference_microseconds)
    66.         subtree:add(f_wnd_size, v_wnd_size)
    67.         subtree:add(f_seq_nr, v_seq_nr)
    68.         subtree:add(f_ack_nr, v_ack_nr)
    69.         -- add pkt info
    70.         pkt.cols.protocol = "uTP"
    71.         if(i_type==0) then
    72.             pkt.cols.info = "uTP ST_DATA"
    73.         elseif(i_type==1) then
    74.             pkt.cols.info = "uTP ST_FIN"
    75.         elseif(i_type==2) then
    76.             pkt.cols.info = "uTP ST_STATE"
    77.         elseif(i_type==3) then
    78.             pkt.cols.info = "uTP ST_RESET"
    79.         elseif(i_type==4) then
    80.             pkt.cols.info = "uTP ST_SYN"
    81.         else
    82.             pkt.cols.info = "uTP UNKNOW"
    83.         end
    84.         while(v_next_extension_type:uint()~=0) do
    85.             -- add extension tree
    86.             local extendtree = subtree:add(p_utp, buf(offset, buf_len-offset):tvb(),"Extension")
    87.             if(v_next_extension_type:uint()==0) then
    88.                 extendtree:append_text(": NO Extension")
    89.             elseif(v_next_extension_type:uint()==1) then
    90.                 extendtree:append_text(": Selective acks")
    91.             elseif(v_next_extension_type:uint()==2) then
    92.                 extendtree:append_text(": Extension bits")
    93.             end
    94.             v_next_extension_type = buf(offset, 1)
    95.             offset = offset + 1
    96.             extendtree:add(f_next_extension_type, v_next_extension_type)
    97.             local v_extension_len = buf(offset, 1)
    98.             offset = offset + 1
    99.             extendtree:add(f_extension_len, v_extension_len)
    100.             local i_extension_len = v_extension_len:int()
    101.             local v_extension_bitmask = buf(offset, i_extension_len)
    102.             offset = offset + i_extension_len
    103.             extendtree:add(f_extension_bitmask, v_extension_bitmask)
    104.         end
    105.         return offset 
    106.     end
    107.     -- check packet is bittorrent? header legal
    108.     local function check_bittorrent(buf)
    109.         local len = buf:len()
    110.         local pack_len = buf(0,4)
    111.         local pack_type
    112.         if(len<4) then
    113.             return false
    114.         elseif(buf(0,1):uint()==19 and len==68) then --handshake
    115.             return true
    116.         elseif(len==4) then --keepalive
    117.             if(pack_len:uint()==0) then return true
    118.             else return false
    119.             end
    120.         else
    121.             pack_type = buf(4,1)
    122.             --choke, unchoke, interested, not interested, have all, have none
    123.             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
    124.                 if(pack_len:uint()==1) then return true
    125.                 else return false
    126.                 end
    127.             --request, cancel, reject
    128.             elseif(pack_type:uint()==6 or pack_type:uint()==8 or pack_type:uint()==0x10) then
    129.                 if(pack_len:uint()==13) then return true
    130.                 else return false
    131.                 end
    132.             --port
    133.             elseif(pack_type:uint()==9) then
    134.                 if(pack_len:uint()==3) then return true
    135.                 else return false
    136.                 end
    137.             --have, suggest, allowed fast
    138.             elseif(pack_type:uint()==4 or pack_type:uint()==0x0D or pack_type:uint()==0x11) then
    139.                 if(pack_len:uint()==5) then return true
    140.                 else return false
    141.                 end
    142.             --bitfield, extend
    143.             elseif(pack_type:uint()==5 or pack_type:uint()==0x14) then
    144.                 if(pack_len:uint()<1024) then return true
    145.                 else return false
    146.                 end
    147.             --piece, max than 16K
    148.             elseif(pack_type:uint()==7) then
    149.                 if(pack_len:uint()>=16384) then return true
    150.                 else return false
    151.                 end
    152.             else
    153.                 return false
    154.             end
    155.         end
    156.         return false
    157.     end
    158.     -- protocol dissector, include bittorrent
    159.     function p_utp.dissector(buf,pkt,root) 
    160.         local len = buf:len()
    161.         local offset = utp_dissector(buf, pkt, root)
    162.         if len>offset and offset>0 then
    163.             -- call bittorrent dissector
    164.             -- pass split PIECE pack
    165.             if check_bittorrent(buf(offset, len-offset)) then
    166.                 bittorrent_dissector:call(buf(offset, len-offset):tvb(), pkt, root)
    167.             else
    168.                 data_dis:call(buf(offset,len-offset):tvb(), pkt, root)
    169.             end
    170.         elseif offset==0 then
    171.             -- call data dissector
    172.             data_dis:call(buf,pkt,root)
    173.         end
    174.     end
    175.     -- add to DissectorTable
    176.     local udp_table = DissectorTable.get("udp.port")
    177.     -- udp_table:add(4135, p_utp) 
    178.     udp_table:add(10000, p_utp) 
    179. end
     
     
    参考
     
  • 相关阅读:
    Linux下查找大文件以及目录
    Linux 下定时备份数据库以及删除缓存
    java中main方法的 (String []args)
    RabbitMQ消息队列(二):”Hello, World“
    maven 多模块项目
    java 接口的作用和好处
    Centos下使用压缩包安装MySQL5.7
    修复mysql:[ERROR] Native table ‘performance_schema’
    连接Mysql提示Can’t connect to local MySQL server through socket的解决方法
    centos6下无法使用lsof命令"-bash: lsof: command not found"
  • 原文地址:https://www.cnblogs.com/lvdongjie/p/4073241.html
Copyright © 2020-2023  润新知