[知识整理]使用RawSocket 抓包

    曾经写过一个远程网络抓包工具,为啥原远程抓了?在解决现网问题,或者统计数据,需要快速准确的抓取特点的网络吧。我们应用都是windows机器,经常需要抓XX服务某A机到XX服务B机的网络包,定位机器、查部署情况、IP地址、负载配置、同时操作多台设备等等都特别耗时,因为有了这个工具的设计初衷。于是开始设计使用调用Winpcap组件实现去抓,后来发现生产环境很多机器并未安装,同时winpcap 也无法支持silence方式安装。

   所以不得不想其他方案,这里就想到了RawSocket了,通过RawSocket 获取全量网络包,让后实现winpcap相同的filter 功能,将RawSocket 数据量保持为标准的pcap格式文件,问题得到完美的解决。

代码实现如下:

1. rawsocket

   1:    public class RawSocket
   2:      {
   3:          private Socket _socket;
   4:          private IPAddress _address;
   5:          public Action<TcpPacket> OnTcpPacketCapture;
   6:          public Action<byte[], int> OnRawDataCapure;
   7:          public RawSocket(IPAddress address)
   8:          {
   9:              _address = address;
  10:              _socket = new Socket(AddressFamily.InterNetwork, SocketType.Raw, ProtocolType.IP);
  11:              _socket.Bind(new IPEndPoint(address, 0));
  12:          }
  13:   
  14:          public bool Capture()
  15:          {
  16:              bool isOk = true;
  17:              try
  18:              {
  19:                  _socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.HeaderIncluded, 1);
  20:                  byte[] inBytes = new byte[] { 1, 0, 0, 0 };
  21:                  byte[] outBytes = new byte[] { 0, 0, 0, 0 };
  22:                  _socket.IOControl(IOControlCode.ReceiveAll, inBytes, outBytes);
  23:                  if (0 != outBytes[0] + outBytes[1] + outBytes[2] + outBytes[3]) { isOk = false; }
  24:              }
  25:              catch (SocketException)
  26:              {
  27:                  isOk = false;
  28:              }
  29:   
  30:              if (isOk)
  31:              {
  32:                  while (true)
  33:                  {
  34:                      //以太网MTU 最大为1500
  35:                      byte[] buffer = new byte[1500];
  36:   
  37:                      int count = _socket.Receive(buffer, SocketFlags.None);
  38:   
  39:                      if (OnRawDataCapure != null)
  40:                          OnRawDataCapure(buffer, count);
  41:   
  42:                      if (OnTcpPacketCapture != null)
  43:                      {
  44:                          IPPacket ip = new IPPacket(buffer,0,count);
  45:                          Console.WriteLine(ip);
  46:                          if (ip.Protocol == IPProtocolType.TCP)
  47:                          {
  48:                              TcpPacket tcp = new TcpPacket(ip);
  49:                              OnTcpPacketCapture(tcp);
  50:                          }
  51:                      }
  52:                  }
  53:              }
  54:   
  55:              return isOk;
  56:          }
  57:   
  58:          public void Stop()
  59:          {
  60:              if (_socket != null)
  61:              {
  62:                  _socket.Shutdown(SocketShutdown.Both);
  63:                  _socket.Close();
  64:              }
  65:          }
  66:      }
  89:      class SocketData
  90:      {
  91:          public Socket Socket { get; set; }
  92:          public Byte[] Data { get; set; }
  93:      }
  94:      public class DataBuffer
  95:      {
  96:          public byte[] RawBuffer;
  97:          public int RawStart;
  98:          public int RawCount;
  99:   
 100:          private byte[] buffer;
 101:          private int start;
 102:          private int end;
 103:          public int Length { get { return end - start; } }
 104:          public byte this[int index] { get { return buffer[start + index]; } }
 105:   
 106:          public DataBuffer(byte[] data)
 107:              : this(data, 0, data.Length) { }
 108:   
 109:          public DataBuffer(byte[] data, int start, int count)
 110:          {
 111:             this.RawBuffer= this.buffer = data;
 112:             this.RawStart= this.start = start;
 113:             this.RawCount = count;
 114:              this.end = start + count;
 115:          }
 116:   
 117:          public void SetPosition(int position)
 118:          {
 119:              this.start += position;
 120:          }
 121:   
 122:          public byte[] Data
 123:          {
 124:              get
 125:              {
 126:                  byte[] data = new byte[this.Length];
 127:                  Array.Copy(this.buffer, this.start, data, 0, data.Length);
 128:                  return data;
 129:              }
 130:          }
 131:      }
 132:   
 133:      public class IPPacket
 134:      {
 135:          public int Version; //版本号
 136:          public int HeadLen; //头长度
 137:          public int DiffServices; //区分服务
 138:          public int DataLen;//数据长度
 139:          public int Identification; //标志
 140:          public int Flag; //标识 3bit
 141:          public int Excursion;//片偏移 13bit
 142:          public byte TTL;//生存周期
 143:          public IPProtocolType Protocol; //协议
 144:          public int CheckSum; //校验和
 145:          public IPAddress SrcAddr; //源地址
 146:          public IPAddress DestAddr; //目标地址
 147:          public byte[] option; //选项
 148:          public DataBuffer Data; //IP Payload
 149:   
 150:          public IPPacket(byte[] data) : this(new DataBuffer(data)) { }
 151:          public IPPacket(byte[] data, int start, int count) : this(new DataBuffer(data, start, count)) { }
 152:   
 153:          public IPPacket(DataBuffer data)
 154:          {
 155:              Version = (data[0] & 0xF0) >> 4;
 156:              HeadLen = (int)(data[0] & 0x0F) * 4;
 157:              DiffServices = (int)data[1];
 158:              DataLen = ((int)data[2] << 8) + (int)data[3];
 159:              Identification = ((int)data[5] << 8) + (int)data[5];
 160:              Flag = data[6] >> 5;
 161:              Excursion = (((int)data[6] & 0x1F) << 8) + (int)data[7];
 162:              TTL = data[8];
 163:              Protocol = (IPProtocolType)data[9];
 164:              CheckSum = ((int)data[10] << 8) + (int)data[11];
 165:   
 166:              byte[] addr = new byte[4];
 167:              for (int i = 0; i < 4; i++)
 168:                  addr[i] = data[12 + i];
 169:              SrcAddr = new IPAddress(addr);
 170:   
 171:              addr = new byte[4];
 172:              for (int i = 0; i < 4; i++)
 173:                  addr[i] = data[16 + i];
 174:              DestAddr = new IPAddress(addr);
 175:   
 176:              //option
 177:              if (HeadLen > 20)
 178:              {
 179:                  option = new byte[HeadLen - 20];
 180:                  for (int i = 0; i < option.Length; i++)
 181:                      option[i] = data[20 + i]; //会包括填充部分
 182:              }
 183:   
 184:              data.SetPosition(HeadLen);
 185:              Data = data;
 186:          }
 187:   
 188:          public override string ToString()
 189:          {
 190:              StringBuilder sb = new StringBuilder();
 191:              sb.AppendFormat("SrcAddr:{0} DestAddr={1}\r\n", SrcAddr.ToString(), DestAddr.ToString());
 192:              sb.AppendFormat("CheckSum: {0} Protocol:{1}\r\n", CheckSum, Protocol.ToString());
 193:              sb.AppendFormat("Version: {0} HeadLen:{1}\r\n", Version, HeadLen);
 194:              sb.AppendFormat("DataLen: {0} DiffServices:{1}\r\n", DataLen, DiffServices);
 195:              return sb.ToString();
 196:          }
 197:      }
 198:   
 199:      public class TcpPacket
 200:      {
 201:          public int SrcPort = 0;//源端口
 202:          public int DestPort = 0;//目标端口
 203:          public uint SequenceNo = 0;//序号
 204:          public uint NextSeqNo = 0;//确认号
 205:          public int HeadLen = 0;//头长度
 206:          public int Flag = 0;//控制位
 207:          public int WindowSize = 0;//窗口
 208:          public int CheckSum = 0;//校验和
 209:          public int UrgPtr = 0;//紧急指针
 210:          public byte[] option;//选项
 211:          public IPPacket IPPacket;
 212:          public DataBuffer Data;
 213:          public byte[] Body { get { return Data.Data; } }
 214:   
 215:          public TcpPacket(byte[] data) : this(new IPPacket(new DataBuffer(data))) { }
 216:          public TcpPacket(byte[] data, int start, int count) : this(new IPPacket(new DataBuffer(data, start, count))) { }
 217:   
 218:          public TcpPacket(IPPacket packet)
 219:          {
 220:              if (packet.Protocol != IPProtocolType.TCP)
 221:                  throw new NotSupportedException(string.Format("TcpPacket not support {0}", packet.Protocol));
 222:              this.IPPacket = packet;
 223:   
 224:              DataBuffer data = packet.Data;
 225:              SrcPort = ((int)data[0] << 8) + (int)data[1];
 226:              DestPort = ((int)data[2] << 8) + (int)data[3];
 227:   
 228:              SequenceNo = ((uint)data[7] << 24) + ((uint)data[6] << 16) + ((uint)data[5] << 8) + ((uint)data[4]);
 229:              NextSeqNo = ((uint)data[11] << 24) + ((uint)data[10] << 16) + ((uint)data[9] << 8) + ((uint)data[8]);
 230:   
 231:              HeadLen = ((data[12] & 0xF0) >> 4)*4;
 232:              //6bit保留位
 233:              Flag = (data[13] & 0x3F);
 234:              WindowSize = ((int)data[14] << 8) + (int)data[15];
 235:              CheckSum = ((int)data[16] << 8) + (int)data[17];
 236:              UrgPtr = ((int)data[18] << 8) + (int)data[19];
 237:              //option
 238:              if (HeadLen > 20)
 239:              {
 240:                  option = new byte[HeadLen - 20];
 241:                  for (int i = 0; i < option.Length; i++)
 242:                      option[i] = data[20 + i]; //会包括填充部分
 243:              }
 244:              
 245:              data.SetPosition(this.HeadLen);
 246:              Data = data;
 247:          }
 248:   
 249:          public override string ToString()
 250:          {
 251:              StringBuilder sb = new StringBuilder();
 252:              sb.AppendFormat("SrcPort:{0} DestPort={1}\r\n", SrcPort, DestPort);
 253:              sb.AppendFormat("SequenceNo:{0} NextSeqNo={1}\r\n", SequenceNo, NextSeqNo);
 254:              sb.AppendFormat("HeadLen:{0} Flag={1}\r\n", HeadLen, Flag);
 255:              sb.AppendFormat("WindowSize:{0} CheckSum={1}\r\n", WindowSize, CheckSum);
 256:              return sb.ToString();
 257:          }
 258:      }
 259:   
 260:      public enum IPProtocolType : byte
 261:      {
 262:          /// <summary> Dummy protocol for TCP. </summary>
 263:          IP = 0,
 264:          /// <summary> IPv6 Hop-by-Hop options. </summary>
 265:          HOPOPTS = 0,
 266:          /// <summary> Internet Control Message Protocol. </summary>
 267:          ICMP = 1,
 268:          /// <summary> Internet Group Management Protocol.</summary>
 269:          IGMP = 2,
 270:          /// <summary> IPIP tunnels (older KA9Q tunnels use 94). </summary>
 271:          IPIP = 4,
 272:          /// <summary> Transmission Control Protocol. </summary>
 273:          TCP = 6,
 274:          /// <summary> Exterior Gateway Protocol. </summary>
 275:          EGP = 8,
 276:          /// <summary> PUP protocol. </summary>
 277:          PUP = 12,
 278:          /// <summary> User Datagram Protocol. </summary>
 279:          UDP = 17,
 280:          /// <summary> XNS IDP protocol. </summary>
 281:          IDP = 22,
 282:          /// <summary> SO Transport Protocol Class 4. </summary>
 283:          TP = 29,
 284:          /// <summary> IPv6 header. </summary>
 285:          IPV6 = 41,
 286:          /// <summary> IPv6 routing header. </summary>
 287:          ROUTING = 43,
 288:          /// <summary> IPv6 fragmentation header. </summary>
 289:          FRAGMENT = 44,
 290:          /// <summary> Reservation Protocol. </summary>
 291:          RSVP = 46,
 292:          /// <summary> General Routing Encapsulation. </summary>
 293:          GRE = 47,
 294:          /// <summary> encapsulating security payload. </summary>
 295:          ESP = 50,
 296:          /// <summary> authentication header. </summary>
 297:          AH = 51,
 298:          /// <summary> ICMPv6. </summary>
 299:          ICMPV6 = 58,
 300:          /// <summary> IPv6 no next header. </summary>
 301:          NONE = 59,
 302:          /// <summary> IPv6 destination options. </summary>
 303:          DSTOPTS = 60,
 304:          /// <summary> Multicast Transport Protocol. </summary>
 305:          MTP = 92,
 306:          /// <summary> Encapsulation Header. </summary>
 307:          ENCAP = 98,
 308:          /// <summary> Protocol Independent Multicast. </summary>
 309:          PIM = 103,
 310:          /// <summary> Compression Header Protocol. </summary>
 311:          COMP = 108,
 312:          /// <summary> Raw IP packets. </summary>
 313:          RAW = 255,
 314:          /// <summary> IP protocol mask.</summary>
 315:          MASK = 0xff
 316:      }
 

2. PcapDumper 用户保存pcap文件格式:

   1:   public class PcapDumper
   2:      {
   3:          private PcapStream context;
   4:          public PcapDumper(Stream stream)
   5:          {
   6:              context = new PcapStream(stream);
   7:              PcapHeader header = new PcapHeader();
   8:              header.Writer(context);
   9:              stream.Flush();
  10:          }
  11:   
  12:          public void Write(byte[] buffer, int offset, int count)
  13:          {
  14:              RecordPacket record = new RecordPacket(buffer, offset, count);
  15:              record.Write(context);
  16:          }
  17:   
  18:          public void Write(TcpPacket packet)
  19:          {
  20:              Write(packet.IPPacket.Data.RawBuffer, packet.IPPacket.Data.RawStart, packet.IPPacket.Data.RawCount);
  21:          }
  22:   
  23:          public void Write(IPPacket packet)
  24:          {
  25:              Write(packet.Data.RawBuffer, packet.Data.RawStart, packet.Data.RawCount);
  26:          }
  27:   
  28:          public void Flush()
  29:          {
  30:              context.Flush();
  31:          }
  32:      }
  33:   
  34:      public class PcapHeader
  35:      {
  36:          //for intel x86 save as litle-endian 
  37:          public uint MagicNumber = 0xa1b2c3d4;// native byte ordering. magic number
  38:          public ushort VersionMajor = 0x2; //current 2.4
  39:          public ushort VersionMinor = 0x4;
  40:          public uint TimeZone = 0;//timeezone 实际上没有被使用过
  41:          public uint SigFigs = 0;//useless
  42:          public uint Snaplen = 65535;//maxlen just set the max
  43:          public uint Network = 1;//Ethernet
  44:   
  45:          public void Writer(PcapStream stream)
  46:          {
  47:              stream.Write(MagicNumber);
  48:              stream.Write(VersionMajor);
  49:              stream.Write(VersionMinor);
  50:              stream.Write(TimeZone);
  51:              stream.Write(SigFigs);
  52:              stream.Write(Snaplen);
  53:              stream.Write(Network);
  54:          }
  55:      }
  56:   
  57:   
  58:      public class RecordPacket
  59:      {
  60:          private DateTime unixTime = new DateTime(1970, 1, 1);
  61:          private int EntherNetLen = 14;//srcIP+dstIP+ verion 14b 头
  62:          private int offset;
  63:          private int count;
  64:          private byte[] buffer;
  65:   
  66:          public RecordPacket(byte[] buffer, int offset, int count)
  67:          {
  68:              DateTime time = DateTime.UtcNow;
  69:              TimeSec = (uint)((time - unixTime).TotalSeconds);
  70:              TimeMicroSec = (uint)time.Millisecond * 1000;
  71:              CapLen = Len = (uint)count + 14;
  72:              this.offset = offset;
  73:              this.count = count;
  74:              this.buffer = buffer;
  75:          }
  76:   
  77:          public uint TimeSec;         /* timestamp seconds */
  78:          public uint TimeMicroSec;        /* timestamp microseconds */
  79:          public uint CapLen;       /* number of octets of packet saved in file */
  80:          public uint Len;       /* actual length of packet */
  81:   
  82:          public void Write(PcapStream stream)
  83:          {
  84:              stream.Write(TimeSec);
  85:              stream.Write(TimeMicroSec);
  86:              stream.Write(CapLen);
  87:              stream.Write(Len);
  88:              stream.Write((ulong)1, 6);
  89:              stream.Write((ulong)2, 6); //这两个应该是链路mac地址,随便代替就行
  90:              stream.Write(8);
  91:              stream.Write(0);//IP 0x08
  92:              stream.Write(buffer, offset, count);
  93:          }
  94:      }
  95:   
  96:      public class PcapStream
  97:      {
  98:          private byte[] tempBuffer = new byte[8];
  99:          private Stream stream;
 100:          public PcapStream(Stream stream)
 101:          {
 102:              this.stream = stream;
 103:          }
 104:   
 105:          public void Flush()
 106:          {
 107:              stream.Flush();
 108:          }
 109:   
 110:          public void Write(ushort v)
 111:          {
 112:              Write(v, 2);
 113:          }
 114:   
 115:          public void Write(uint v)
 116:          {
 117:              Write(v, 4);
 118:          }
 119:   
 120:          public void Write(ulong v)
 121:          {
 122:              Write(v, 8);
 123:          }
 124:   
 125:          public void Write(ulong v, int numbytes)
 126:          {
 127:              ulong val = v;
 128:              for (int x = 0; x < numbytes; x++)
 129:              {
 130:                  tempBuffer[x] = (byte)(val & 0xff);
 131:                  val >>= 8;
 132:              }
 133:              stream.Write(tempBuffer, 0, numbytes);
 134:          }
 135:   
 136:          public void Write(byte value)
 137:          {
 138:              stream.WriteByte(value);
 139:          }
 140:   
 141:          public void Write(byte[] buffer, int offset, int count)
 142:          {
 143:              stream.Write(buffer, offset, count);
 144:          }
 145:   
 146:          public void Write(byte[] buffer)
 147:          {
 148:              stream.Write(buffer, 0, buffer.Length);
 149:          }
 150:      }
 151:  }
 152:   
 153:  /// 参考资料:http://wiki.wireshark.org/Development/LibpcapFileFormat
 154:  //magic_number: used to detect the file format itself and the byte ordering. The writing application writes 0xa1b2c3d4 with it's native byte ordering format into this field. The reading application will read either 0xa1b2c3d4 (identical) or 0xd4c3b2a1 (swapped). If the reading application reads the swapped 0xd4c3b2a1 value, it knows that all the following fields will have to be swapped too.
 155:  //version_major, version_minor: the version number of this file format (current version is 2.4)
 156:  //thiszone: the correction time in seconds between GMT (UTC) and the local timezone of the following packet header timestamps. Examples: If the timestamps are in GMT (UTC), thiszone is simply 0. If the timestamps are in Central European time (Amsterdam, Berlin, ...) which is GMT + 1:00, thiszone must be -3600. In practice, time stamps are always in GMT, so thiszone is always 0.
 157:  //sigfigs: in theory, the accuracy of time stamps in the capture; in practice, all tools set it to 0
 158:  //snaplen: the "snapshot length" for the capture (typically 65535 or even more, but might be limited by the user), see: incl_len vs. orig_len below
 159:  //network: link-layer header type, specifying the type of headers at the beginning of the packet (e.g. 1 for Ethernet, see tcpdump.org's link-layer header types page for details); this can be various types such as 802.11, 802.11 with various radio information, PPP, Token Ring, FDDI, etc.
 160:  //0            BSD       loopback devices, except for later OpenBSD
 161:  //1            Ethernet, and Linux loopback devices 
 162:  //6            802.5 Token Ring
 163:  //7            ARCnet
 164:  //8            SLIP
 165:  //9            PPP
 166:  //10          FDDI
 167:  //100        LLC/SNAP-encapsulated ATM
 168:  //101        raw IP, with no link
 169:  //102        BSD/OS SLIP
 170:  //103        BSD/OS PPP
 171:  //104        Cisco HDLC
 172:  //105        802.11
 173:  //108        later OpenBSD loopback devices (with the AF_value in network byte order)
 174:  //113               special Linux cooked capture
 175:  //114               LocalTalk
 176:   
 177:  //ts_sec: the date and time when this packet was captured. This value is in seconds since January 1, 1970 00:00:00 GMT; this is also known as a UN*X time_t. You can use the ANSI C time() function from time.h to get this value, but you might use a more optimized way to get this timestamp value. If this timestamp isn't based on GMT (UTC), use thiszone from the global header for adjustments.
 178:  //ts_usec: the microseconds when this packet was captured, as an offset to ts_sec.  Beware: this value shouldn't reach 1 second (1 000 000), in this case ts_sec must be increased instead!
 179:  //incl_len: the number of bytes of packet data actually captured and saved in the file. This value should never become larger than orig_len or the snaplen value of the global header.
 180:  //orig_len: the length of the packet as it appeared on the network when it was captured. If incl_len and orig_len differ, the actually saved packet size was limited by snaplen.

3. 最后是Filter功能:

   1:   class PcapFilter
   2:      {
   3:          private const string CONST_AND = "and";
   4:          private const string CONST_OR = "or";
   5:          private const string CONST_HOST = "host";
   6:          private const string CONST_TCP = "tcp";
   7:          private const string CONST_PORT = "port";
   8:   
   9:          private string filter;
  10:          private Func<TcpPacket, bool> filterAction = (packet) => { return true; };
  11:          private List<Func<TcpPacket, bool>> _funcs=new List<Func<TcpPacket,bool>>();
  12:          private bool _isAnd = false;
  13:   
  14:          public PcapFilter(string filter)
  15:          {
  16:              if (!string.IsNullOrEmpty(filter))
  17:              {
  18:                  this.filter = filter.Trim().ToLower();
  19:                  if (!string.IsNullOrEmpty(this.filter))
  20:                      TryParserFilter();
  21:              }
  22:          }
  23:   
  24:          private void TryParserFilter()
  25:          {
  26:              string[] sp = filter.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
  27:              sp = sp.Where(p => p.Trim().Length > 0).ToArray();
  28:   
  29:              if (sp.Where(p => p == CONST_OR || p == CONST_AND).Count() > 1)
  30:                  throw new NotSupportedException("only support one or/and");
  31:   
  32:              TokenState ns = TokenState.Name;
  33:              string name = string.Empty;
  34:   
  35:              for (int i=0;i<sp.Length;i++)
  36:              {
  37:                  if (ns == TokenState.Name)
  38:                  {
  39:                      if (sp[i] == CONST_TCP && sp[i + 1] == CONST_PORT)
  40:                      {
  41:                          name = CONST_TCP;
  42:                          i++;
  43:                          ns = TokenState.Value;
  44:                      }
  45:                      else if (sp[i] == CONST_HOST)
  46:                      {
  47:                          name = CONST_HOST;
  48:                          ns = TokenState.Value;
  49:                      }
  50:                      else
  51:                          throw new NotSupportedException();
  52:                  }
  53:                  else if (ns == TokenState.Operation)
  54:                  {
  55:                      if (sp[i] == CONST_AND)
  56:                          _isAnd = true;
  57:                      else
  58:                          _isAnd = false;
  59:                      ns = TokenState.Name;
  60:                  }
  61:                  else if (ns == TokenState.Value)
  62:                  {
  63:                      ParseAction(name, sp[i]);
  64:                      ns = TokenState.Operation;
  65:                  }
  66:              }
  67:   
  68:              filterAction=(packet)=>
  69:                  {
  70:                      if (_funcs.Count > 0)
  71:                      {
  72:                          if (_funcs.Count == 1)
  73:                              return _funcs[0](packet);
  74:                          else
  75:                          { 
  76:                          if(_isAnd)
  77:                              return _funcs[0](packet) && _funcs[1](packet);
  78:                          }
  79:                      }
  80:                      return true;
  81:                  };
  82:          }
  83:   
  84:          private void ParseAction(string name, string value)
  85:          {
  86:              if (name == CONST_HOST)
  87:              {
  88:                  IPAddress ip = IPAddress.Parse(value);
  89:                  _funcs.Add(new Func<TcpPacket, bool>((pachet) =>
  90:                      {
  91:                          return pachet.IPPacket.SrcAddr.Equals(ip) || pachet.IPPacket.DestAddr.Equals(ip);
  92:                      }));
  93:              }
  94:              else
  95:              {
  96:                  int port = Convert.ToInt32(value);
  97:                  _funcs.Add(new Func<TcpPacket, bool>((packet) =>
  98:                      {
  99:                          return packet.SrcPort == port || packet.DestPort == port;
 100:                      }));
 101:              }
 102:          }
 103:   
 104:          public bool IsFilter(TcpPacket packet)
 105:          {
 106:              return filterAction(packet);
 107:          }
 108:      }
 109:   
 110:      enum TokenState
 111:      { 
 112:          Name,
 113:          Value,
 114:          Operation,
 115:      }

转载于:https://www.cnblogs.com/lulu/archive/2013/06/10/3130830.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值