using System; using System.Collections.Generic; using System.Text; using System.IO; namespace CommonLib.IO.File { /// /// Pcap 包捕获读取器。兼容 Tcpdump 及 Ethereal。 /// public class PacketCaptureReader { #region Fields private const uint MAGIC = 0xA1B2C3D4; private readonly LinkLayerType _LinkLayerType; private readonly int _MaxPacketLength; private readonly Stream _BaseStream; private readonly BinaryReader m_Reader; private readonly int _TimeZone; private readonly int _CaptureTimestamp; #endregion #region Constructors /// /// 构造一个 Pcap 包捕获读取器。 /// /// 要读取的基础流 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 #region Properties /// /// 主版本号,总是为 2 /// public short VersionMajor { get { return 2; } } /// /// 子版本号,总是为 4 /// public short VersionMinjor { get { return 4; } } /// /// 时区,该字段没有使用 /// public int TimeZone { get { return _TimeZone; } } /// /// 捕获时的时间戳,该字段没有使用 /// public int CaptureTimestamp { get { return _CaptureTimestamp; } } /// /// 基础流 /// public Stream BaseStream { get { return _BaseStream; } } /// /// 数据链路类型 /// public LinkLayerType LinkLaterType { get { return _LinkLayerType; } } /// /// 最大包大小 /// public int MaxPacketLength { get { return _MaxPacketLength; } } #endregion /// /// 读取下一个捕获包 /// /// 读取的捕获包,如果已经到达尾端,返回 null 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); } } }