分享

tshark批量切流实践和思考

 朝花夕拾and 2017-07-29

总结一下tshark进行切流的方法:

  在wireshark中我们使用Follow TCP Stream可以看到左上方的过滤条件,如下图


图1

  其中的数字89所代表的含义是,该pcap文件中流编号为89的那条流。那么这个编号是怎么来的?唯一一条流是由源IP,目的IP,源端口,目的端口以及传输层协议五元组来确定的,至于wireshark是怎么确认一条流的,我查看了stackoverflow等论坛的解释,均给出的是这个编号是由是源IP,目的IP,源端口,目的端口四元组计算得来的。

  既然知道流的编号,那么我们就可以根据这个编号将相应符合条件的流切出来的,具体shell脚本如下:

tshark -r $LINE -T fields -e tcp.stream|sort -n | uniq -c | awk -F ' ' '{if ($2>=0)print $2 }' >tcp_stream_number.txt

  $LINE 代表pcap文件名,-T和-e组合使用表示打印wireshark中相应的字段(使用方法见tshark –h,如图2),本例中表示输出tcp.stream字段,即流号。因为是针对每一个报文都要输出该报文对应的流号,因此需要做排序,去重的工作。将最后的所有的流号按照大小顺序输入到tcp_stream_number.txt文件中。

 

图2

 

[plain] view plain copy
  1. tshark -r $LINE -Y 'tcp.stream eq $(($tcpnumber)) ' -w$filedic/$streamname.pcap  

  $LINE 代表pcap文件名,$tcpnumber表示从tcp_stream_number.txt文件中读出的每一行的内容,$(($tcpnumber))转换成数字,$filedic,$streamname分别表示文件目录和文件名,上述的命令表示从$LINE报文中提取流。

  Streamname可以通过如下命令获得,即使用流号+五元组进行命名,方便批量的进行处理, tcp.flags & 0x02)and !(tcp.ack & 0xFFFFFFFF)表示取流的第一个报文,sed s/[[:space:]]/_/g表示将空格替换为下划线。

[plain] view plain copy
  1. streamname=`tshark -r $LINE -Y 'tcp.stream eq $(($tcpnumber)) and (tcp.flags & 0x02)and !(tcp.ack & 0xFFFFFFFF)' -T fields -e tcp.stream -e ip.src -e tcp.srcport -e ip.dst -e tcp.dstport -e ip.proto | sed s/[[:space:]]/_/g`  

  附上切流的脚本:

[plain] view plain copy
  1. #!/bin/bash  
  2. find protocol -name '*.pcap' > pcapfilename.txt  
  3. while read LINE  
  4.     do  
  5.          echo $LINE  
  6.          temp=${LINE%.*}  
  7.          filedic='myhttps/'${temp}  
  8.          echo $filedic  
  9.          mkdir -p $filedic  
  10.          #if ($2>=0)消除首行的空格, > 每次覆盖前一次的内容  
  11.          tshark -r $LINE -T fields -e tcp.stream |sort -n | uniq -c | awk -F ' ' '{if ($2>=0)print $2 }' > tcp_stream_number.txt  
  12.          while read tcpnumber  
  13.             do   
  14.             #sed替换空格为下划线,tcp.flags,tcp.ack取首包的名称,$(($tcpnumber)),字符串转数字  
  15.             streamname=`tshark -r $LINE -Y 'tcp.stream eq $(($tcpnumber)) and (tcp.flags & 0x02)and !(tcp.ack & 0xFFFFFFFF)' -T fields -e tcp.stream -e ip.src -e tcp.srcport -e ip.dst -e tcp.dstport -e ip.proto | sed s/[[:space:]]/_/g`  
  16.             #判断变量是否为空  
  17.             if [ ! $streamname ]  
  18.             then  
  19.                 echo 'IS NULL'  
  20.             else  
  21.                 echo $streamname  
  22.                 tshark -r $LINE -Y 'tcp.stream eq $(($tcpnumber))' -w $filedic/$streamname.pcap  
  23.             fi  
  24.         done <>
  25. done <>

  其实该方法的缺点也很明显,主要包括以下两个方面的原因:

  1、对于每个包,要遍历每一条流,循环次数较多,遇到P2P的报文简直就是灾难。

  2、每一条流是重新写文件导出的,文件读写速度比较慢,在文件读写期间我没有办法进行后续的循环的,因此我在进程里面查看的时候,如下图。


  177号流写的不是那么快,后续的程序就需要等待,浪费时间。我记得Node.js里面最擅长结局这种情况,通过回调实现异步,Linux太清楚是如何实现的,如有了解,可以交流下。

  针对速度比较慢的情况,提速的话包括以下三种:

  1、对于每一个包,只循环一次。这个想法是我们团队的SM给我的启示。就是通过C语言对pcap进行解包,按照五元组生成流号,按照相同的流号,对每个包进行归类,即写文件。这样的话只遍历一边数据包就可以了。

  2、C语言的异步方式,这个就请各位大神指教了。

  3、Shell脚本多线程方式,这个是提速的通用办法。

  以上的提速办法由于时间关系,我也还没有去实现,欢迎大家相互交流。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多