抓取TCP/IP数据包的C++实现

#include <winsock2.h>
#include <windows.h>
#include <mstcpip.h>

#pragma comment(lib,"Ws2_32.lib")

#include <iostream>
using namespace std;

//IP首部
typedef struct tIPPackHead
{
      enum PROTOCOL_TYPE{
          PROTOCOL_TCP = 6,
          PROTOCOL_UDP = 17,
          PROTOCOL_ICMP = 1,
          PROTOCOL_IGMP = 2    
      };
      inline unsigned HeadLen() const
      {
          //首部长度单位为4bytes。因此乘4
          return (ver_hlen & 0x0F) << 2;
      }
      inline unsigned PackLen() const
      {
          return wPacketLen;
      }
      BYTE ver_hlen;      //IP协议版本和IP首部长度。高4位为版本,低4位为首部的长度(单位为4bytes)
      BYTE byTOS;       //服务类型
      WORD wPacketLen; //IP包总长度。包括首部,单位为byte。[Big endian]
      WORD wSequence;    //序号,一般每个IP包的序号递增。[Big endian]
      WORD wMarkFragPoi;  
      BYTE byTTL;         //生存时间  
      BYTE byProtocolType; //协议类型,见PROTOCOL_TYPE定义
      WORD wHeadCheckSum;    //IP首部校验和[Big endian]
      DWORD dwIPSrc;         //源地址
      DWORD dwIPDes;         //目的地址
} IP_PK_HEAD;


int DecodeIP(char *buf, int len);

int DecodeIP(char *buf, int len)
{
      int n = len;

      if( n >= sizeof(IP_PK_HEAD) )
      {
          IP_PK_HEAD iphead;
          memcpy( &iphead, buf, sizeof(iphead) );

          //以下三个为Big Endian字节顺序,转换成主机字节顺序
          iphead.wPacketLen = ntohs( iphead.wPacketLen );
          iphead.wSequence = ntohs( iphead.wSequence );
          iphead.wHeadCheckSum = ntohs( iphead.wHeadCheckSum );

          in_addr src,dst;
          src.S_un.S_addr = iphead.dwIPSrc;
          dst.S_un.S_addr = iphead.dwIPDes;

          char strsrc[20],strdst[20];
          strcpy(strsrc, inet_ntoa(src));
          strcpy( strdst , inet_ntoa(dst));

          printf( "IP数据包: ver=%d,hlen=%d,protocol=%d,pklen=%d,seq=%d,src=%s,dst=%s _fcksavedurl=%s,dst=%s",
              iphead.ver_hlen >> 4,
              (iphead.ver_hlen & 0x0F) << 2,
              iphead.byProtocolType,
              iphead.wPacketLen,
              iphead.wSequence,
              strsrc,
              strdst );
      }

      return 0;
}

void AutoWSACleanup()
{
      ::WSACleanup();
}

int main()
{
      //初始化winsock库,使用2.2版本
      u_short wVersionRequested = 0x0202;
      WSADATA wsaData;
      if( SOCKET_ERROR == WSAStartup( wVersionRequested, &wsaData ) )
      {        
          cout << WSAGetLastError();
          return 0;
      }
      atexit( AutoWSACleanup );

      //创建SOCKET
      SOCKET h = socket( AF_INET, SOCK_RAW, IPPROTO_IP);
      if( h == INVALID_SOCKET )
      {
          cout << WSAGetLastError();
          return 0;
      }

      //获取本机地址
      char FAR name[128];  
      if( -1 == gethostname(name, sizeof(name)) )
      {
          closesocket( h );
          cout << WSAGetLastError();
          return 0;
      }

      struct hostent FAR * pHostent;
      pHostent = gethostbyname(name);

      //绑定本地地址到SOCKET句柄
      sockaddr_in addr;
      addr.sin_family = AF_INET;
      addr.sin_addr = *(in_addr*)pHostent->h_addr; //IP
      addr.sin_port = 0; //端口,IP层端口可随意填
      if( SOCKET_ERROR == bind( h,(sockaddr *)&addr,sizeof(addr) ) )
      {
          closesocket( h );
          cout << WSAGetLastError();
          return 0;
      }

      //设置该SOCKET为接收所有流经绑定的IP的网卡的所有数据,包括接收和发送的数据包
      //该函数在mstcpip.h里面,详见MSDN帮助
      u_long sioarg = 1;
      DWORD wt=0;
      if( SOCKET_ERROR == WSAIoctl( h, SIO_RCVALL , &sioarg,sizeof(sioarg),NULL,0,&wt,NULL,NULL ) )
      {
          closesocket( h );
          cout << WSAGetLastError();
          return 0;
      }

      //我们只需要接收数据,因此设置为阻塞IO,使用最简单的IO模型
      u_long bioarg =    0;
      if( SOCKET_ERROR == ioctlsocket( h, FIONBIO , &bioarg ) )
      {
          closesocket( h );
          cout << WSAGetLastError();
          return 0;
      }

      //开始接收数据
      //因为前面已经设置为阻塞IO,recv在接收到数据前不会返回。
      //当返回<=0时表示接收失败,退出循环
      //可以在另一个线程执行此循环,主线程closesocket可以使recv失败而结束循环
      char buf[102400];
      int len = 0;
      do
      {
          len = recv( h, buf, sizeof(buf),0);
          if( len > 0 )
          {
              DecodeIP( buf, len );
          }
      }while( len > 0 );

      closesocket( h );

      return 0;
}

上一篇: MSDN 在线资料Win32 api   下一篇: msn 最近更新 显示 第三方BLOG

提交疑问

回顶部