存档在 2011年3月

利用Python来解析Pcap包

2011年3月23日

Tcpdump可以将网络中传送的数据包的“头”完全截获下来提供分析。它支持针对网络层、协议、主机、网络或端口的过滤,并提供and、or、not等逻辑语句来帮助你去掉无用的信息。

3

这个我在截取的一段Tcpdump的数据包。通常可以采用wireshark来对Tcpdump数据包进行分析。

1

3

从图中大概可以看出每一个tcpdump的数据里面有很多的包,每一个包都有包的head部分和Data部分。其中head部分包括网卡的地址,ip的地址,端口地址,发送时间等等很多信息。在我的工作中需要将包的发送时间、它的目的IP以及发送的数据保存起来。这就需要对tcpdump数据进行分析,提取出有用的信息。

在网上有一个C#版本做的解析Pcap数据包的资料,很有参考价值。读写 cap 文件的 C# 代码(兼容 tcpdump 及 Wireshark)

它的关键代码

#region Constructors
      /// <summary>
      /// 构造一个 Pcap 包捕获读取器。
      /// </summary>
      /// <param name="baseStream">要读取的基础流</param>
      public PacketCaptureReader(Stream baseStream)
      {
          if (baseStream == null)
throw new ArgumentNullException("baseStream");
          if (!baseStream.CanRead)
throw new ArgumentException("传入的流必须为可读。", "baseStream");
          _BaseStream = baseStream;
          m_Reader = new BinaryReader(_BaseStream);
          if (m_Reader.ReadUInt32() != MAGIC)
              throw new FormatException("无效的 PCAP 格式。");
          short versionMajor = m_Reader.ReadInt16();
          short versionMinjor = m_Reader.ReadInt16();
          if (versionMajor != 2 || VersionMinjor != 4)
          {
              throw new FormatException(
string.Format("无法处理的 PCAP 版本 {0}.{1}", versionMajor, versionMinjor));
          }
          _TimeZone = m_Reader.ReadInt32();
          _CaptureTimestamp = m_Reader.ReadInt32();
          _MaxPacketLength = m_Reader.ReadInt32();
          _LinkLayerType = (LinkLayerType)m_Reader.ReadInt32();
      }

      #endregion

      /// <summary>
      /// 读取下一个捕获包
      /// </summary>
      /// <returns>读取的捕获包,如果已经到达尾端,返回 null</returns>
      public PacketCapture Read()
      {
          if (_BaseStream.Position == _BaseStream.Length) return null;
          UnixTime timestamp = new UnixTime(m_Reader.ReadInt32());
          int millseconds = m_Reader.ReadInt32();
          if (millseconds > 1000000)
              throw new InvalidDataException("读取到无效的数据格式。");
          int len = m_Reader.ReadInt32();
          int rawLen = m_Reader.ReadInt32();
          if (len > rawLen)
              throw new InvalidDataException("读取到无效的数据格式。");
          byte[] buff = m_Reader.ReadBytes(len);
          return new PacketCapture(buff, rawLen, timestamp, millseconds);
      }

从中可以看出 每一个tcpdump数据里面都有一个数据格式的head信息,通过读取该部分判断这个数据包的格式。剩下的部分就是我需要的数据包内容了。

我的python代码如下

   1: #!/usr/bin/python2.5

   2: # -*- coding: utf-8 -*-#

   3: import struct

   4: import os

   5: import re

   6: import sys

   7: import time

   8: import socket

   9: def Pcap_check(infile):

  10:     c = infile.read(24)

  11:     if not c:

  12:         return c

  13:     (a,b,cx,d,e,f,g)=struct.unpack('<Ihhiiii',c)

  14:     if a!= 0xA1B2C3D4:

  15:         return False

  16:     print "versionMajor:",b

  17:     print "VersionMinjor:",cx

  18:     print "_TimeZone:",d

  19:     print "_CaptureTimestamp",e

  20:     print "_MaxPacketLength:",f

  21:     print "_LinkLayerType:",g

  22:     return True

  23: def Pcap_read(infile):

  24:     c = infile.read(16)

  25:     if not c:

  26:         return ('',0,c)

  27:     (timestamp,millseconds,len,rawlen)=struct.unpack('<IIII',c)

  28:     timeStruct=time.gmtime(timestamp)

  29:     currentTime=(timeStruct.tm_hour*3600+timeStruct.tm_min*60+

  30:                 timeStruct.tm_sec)*1000+millseconds/1000

  31:     c=infile.read(34)

  32:     source,dest=struct.unpack('<26xII',c)

  33:     source=socket.inet_ntoa(c[26:30])

  34:     dest=socket.inet_ntoa(c[30:])

  35:     infile.read(8)

  36:     c=infile.read(len-8-34)

  37:     return (dest,currentTime,c)

参考资料:读写 cap 文件的 C# 代码(兼容 tcpdump 及 Wireshark)http://www.cnblogs.com/zealic/archive/2008/05/04/1182420.html

tcpdump+python编写的流量监控的脚本 http://blog.csdn.net/kobeyan/archive/2009/07/13/4344192.aspx

dpkt下载地址:http://code.google.com/p/dpkt/downloads/list

pcap下载地址:http://code.google.com/p/pypcap/