基於VC6.0的抓取TCP/IP資料包的C++實現

max18發表於2012-09-05
#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;
}
漢化版的vc貌似都沒有mstcpip.h檔案

內容如下,將內容儲存為MSTCPIP.H

然後放到Microsoft Visual Studio\VC98\Include這個資料夾下面即可

// Copyright (C) Microsoft Corporation, 1996-1999
#if _MSC_VER > 1000
#pragma once
#endif

/* Argument structure for SIO_KEEPALIVE_VALS */

struct tcp_keepalive {
    u_long onoff;
    u_long keepalivetime;
    u_long keepaliveinterval;
};

// New WSAIoctl Options

#define SIO_RCVALL            _WSAIOW(IOC_VENDOR,1)
#define SIO_RCVALL_MCAST      _WSAIOW(IOC_VENDOR,2)
#define SIO_RCVALL_IGMPMCAST _WSAIOW(IOC_VENDOR,3)
#define SIO_KEEPALIVE_VALS    _WSAIOW(IOC_VENDOR,4)
#define SIO_ABSORB_RTRALERT   _WSAIOW(IOC_VENDOR,5)
#define SIO_UCAST_IF          _WSAIOW(IOC_VENDOR,6)
#define SIO_LIMIT_BROADCASTS _WSAIOW(IOC_VENDOR,7)
#define SIO_INDEX_BIND        _WSAIOW(IOC_VENDOR,8)
#define SIO_INDEX_MCASTIF     _WSAIOW(IOC_VENDOR,9)
#define SIO_INDEX_ADD_MCAST   _WSAIOW(IOC_VENDOR,10)
#define SIO_INDEX_DEL_MCAST   _WSAIOW(IOC_VENDOR,11)


相關文章