[绝冬城]Sniff C++实现源码解析

本文档详细介绍了使用C++编写网络嗅探器的实现过程,包括将网卡设置为混杂模式,捕获数据包,分析数据包。通过定义不同的结构体来解析IP、TCP、UDP和ICMP头,并展示了如何初始化和处理接收到的数据包。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

/*

    by 雪天翔

    2007.9

*/

 

/*

  1、把网卡置于混杂模式

  2、捕获数据包

  3、分析数据包

*/

 

// 定义各种结构体

typedef struct _PROTN2T

{

    int  proto ;

    char *pprototext ;

}PROTN2T ;

                    

#define PROTO_NUM  11

 

/* The IP header */

typedef struct _IPHEADER {

        unsigned char  header_len:4;

        unsigned char  version:4;  

        unsigned char  tos;            // type of service

        unsigned short total_len;      // length of the packet

        unsigned short ident;          // unique identifier

        unsigned short flags;         

        unsigned char  ttl;           

        unsigned char  proto;          // protocol ( IP , TCP, UDP etc)

        unsigned short checksum;      

        unsigned int   sourceIP;

        unsigned int   destIP;

 

}IPHEADER;

 

#define UDP_HEAD_LEN 8   /* UDP head length */

 

#define PSEUDO_HEAD_LEN 12  /* Pseudo head length */

 

#define ICMP_HEAD_LEN 4  /* ICMP head length */

 

struct TCPPacketHead {

    WORD SourPort;

    WORD DestPort;

    DWORD SeqNo;

    DWORD AckNo;

    BYTE HLen;

    BYTE Flag;

    WORD WndSize;

    WORD ChkSum;

    WORD UrgPtr;

};

 

struct ICMPPacketHead {

    BYTE Type;

    BYTE Code;

    WORD ChkSum;

};

 

struct UDPPacketHead {

    WORD SourPort;

    WORD DestPort;

    WORD Len;

    WORD ChkSum;

};

//定义成员变量

    DWORD  m_ipsource     ; //本机IP地址 (IN_ADDR)

    DWORD  m_iphostsource ; // same IP in host format

    DWORD  m_iphost;

    DWORD  m_ipcheckedhost;

    SOCKET m_s            ;

    DWORD  m_threadID     ;

    BOOL   m_Multihomed   ;

    BOOL   m_Local        ;

    CDWordArray m_IPArr   ; //IP队列

 

    friend UINT threadFunc ( LPVOID p ) ;

   

typedef struct _PROTN2T

{

    int  proto ;

    char *pprototext ;

}PROTN2T ;

                    

#define PROTO_NUM  11

 

/* The IP header */

typedef struct _IPHEADER {

        unsigned char  header_len:4;

        unsigned char  version:4;  

        unsigned char  tos;            // type of service

        unsigned short total_len;      // length of the packet

        unsigned short ident;          // unique identifier

        unsigned short flags;         

        unsigned char  ttl;           

        unsigned char  proto;          // protocol ( IP , TCP, UDP etc)

        unsigned short checksum;      

        unsigned int   sourceIP;

        unsigned int   destIP;

 

}IPHEADER;

 

  

#define UDP_HEAD_LEN 8   /* UDP head length */

 

#define PSEUDO_HEAD_LEN 12  /* Pseudo head length */

 

#define ICMP_HEAD_LEN 4  /* ICMP head length */

 

struct TCPPacketHead {

    WORD SourPort;

    WORD DestPort;

    DWORD SeqNo;

    DWORD AckNo;

    BYTE HLen;

    BYTE Flag;

    WORD WndSize;

    WORD ChkSum;

    WORD UrgPtr;

};

 

struct ICMPPacketHead {

    BYTE Type;

    BYTE Code;

    WORD ChkSum;

};

 

struct UDPPacketHead {

    WORD SourPort;

    WORD DestPort;

    WORD Len;

    WORD ChkSum;

};

 

//初始化代码

BOOL CIpmonDlg::OnInitDialog()

{

    CDialog::OnInitDialog();

   

    CHAR       szHostName[128] = {0};  //主机名

    HOSTENT*   pHost = NULL;           //主机HOSTENT信息

    /*

    struct hostent {

           char FAR *       h_name;    //主机名

           char FAR * FAR * h_aliases; //一个以空指针结尾的可选主机名队列

           short            h_addrtype;   //返回地址的类型,对于Windows Sockets,这个域始终为PF_INET

           short            h_length;  //每个地址的长度(字节数),对应于PF_INET域应该为4

           char FAR * FAR * h_addr_list;  //主机地址列表

           };

    */

    CHAR*      pszIp = NULL;

    int        iNum = 0;

    if(AfxSocketInit(NULL)==FALSE)  //初始化socket

    {

       AfxMessageBox("Sorry, socket load error!");

       return FALSE;

    }

 

    if(gethostname(szHostName, 128)==0) //获取主机名

    {     

       pHost = gethostbyname(szHostName); //通过主机名获取主机网络信息

       if(pHost != NULL)

       {

              pszIp = inet_ntoa(*(in_addr*)pHost->h_addr_list[iNum]);

                /* //The inet_ntoa function converts an (Ipv4) Internet network address

                                          // into a string in Internet standard dotted format.

                  char FAR * inet_ntoa(

                       struct   in_addr in  //Structure that represents

                                            //an Internet host address.

                  );

                */

              m_ipsource = inet_addr(pszIp);

              // inet_addr 用途和 inet_ntoa 相反

       }

       else AfxMessageBox("pHost = NULL!");

    }

    else AfxMessageBox("can't find host name!");

 

    //  ListView initialize

 

    DWORD dwStyle=GetWindowLong(m_ctrList.GetSafeHwnd(),GWL_STYLE);

    dwStyle&=~LVS_TYPEMASK;

    dwStyle|=LVS_REPORT;

    SetWindowLong(m_ctrList.GetSafeHwnd(),GWL_STYLE,dwStyle);

 

    m_ctrList.InsertColumn(0,"数据",LVCFMT_LEFT,525);

    m_ctrList.InsertColumn(0,"大小",LVCFMT_LEFT,80);

    m_ctrList.InsertColumn(0,"端口",LVCFMT_LEFT,40);

    m_ctrList.InsertColumn(0,"目的地址",LVCFMT_LEFT,100);

    m_ctrList.InsertColumn(0,"端口",LVCFMT_LEFT,40);

    m_ctrList.InsertColumn(0,"源地址",LVCFMT_LEFT,100);

    m_ctrList.InsertColumn(0,"协议",LVCFMT_LEFT,50);

   

    ::SendMessage(m_ctrList.m_hWnd, LVM_SETEXTENDEDLISTVIEWSTYLE,

       LVS_EX_FULLROWSELECT, LVS_EX_FULLROWSELECT);

 

 

    // 读取本机所有IP地址

    DWORD dwSize = 0 ;

    GetIpAddrTable( NULL , &dwSize, FALSE ) ; //IPhelper中的函数

    /* //先读出该结构的大小

    DWORD GetIpAddrTable(

          PMIB_IPADDRTABLE pIpAddrTable,  // buffer for mapping table

          PULONG pdwSize,                 // size of buffer

          BOOL bOrder                     // sort the table

    );

    */

    PMIB_IPADDRTABLE pIpAddrTable = (PMIB_IPADDRTABLE )new BYTE [ dwSize ] ;

    if( pIpAddrTable )

    {

       if( GetIpAddrTable( (PMIB_IPADDRTABLE)pIpAddrTable,   // // buffer for IP table

                         &dwSize,                // size of buffer

                         FALSE                  // sort by IP address

                         ) == NO_ERROR )

       {

       /*  存储了IP地址入口的表

       typedef struct _MIB_IPADDRTABLE {

                       DWORD         dwNumEntries;    // number of entries in the table

                       MIB_IPADDRROW table[ANY_SIZE]; // array of IP address entries

                       } MIB_IPADDRTABLE, *PMIB_IPADDRTABLE;

       */

           if(  pIpAddrTable->dwNumEntries > 2 ) // Second is MS TCP loopback IP ( 127.0.0.1 )

           { //如果IP地址大于2

              m_Multihomed = TRUE ;

              char szIP[16];

              for( int i = 0 ; i < (int)pIpAddrTable->dwNumEntries ; i++ )

              {  //逐个读出IP地址

                  in_addr ina ;

                  ina.S_un.S_addr = pIpAddrTable->table[i].dwAddr ;

                  char *pIP = inet_ntoa( ina ) ;

                  strcpy( szIP , pIP ) ;

                  if( stricmp( szIP , "127.0.0.1" ) ) //127.0.0.1做对比

                     m_IPArr.Add(pIpAddrTable->table[i].dwAddr) ; //存储入CDWORDARRAY队列

              }

           }

       }

       delete [] pIpAddrTable ;

    }

 

    return TRUE;  // return TRUE  unles

}

 

void CIpmonDlg::OnLookUp()  //点击查看按钮

{

    // TODO: Add your control notification handler code here

    char        szErr [ 50 ] , szHostName[MAX_PATH];

    DWORD       dwErr ;

    SOCKADDR_IN sa;

 

    gethostname(szHostName, sizeof(szHostName)) ;  //获取本机名

    m_iphostsource = m_ipsource ;  //赋值本机ip地址(IN_ADDR)

   

 

    m_ipcheckedhost = ntohl(m_iphost) ;

    /* The ntohl function converts a u_long from TCP/IP network

     order to host byte order (which is little-endian on Intel processors).

    

      u_long ntohl(

             u_long netlong  //32-bit number in TCP/IP network byte order

    );

    Return Values :

           The ntohl function always returns a value in host byte order.

           If the netlong parameter was already in host byte order,

           then no operation is performed

    */

 

       if( 0 == m_threadID )

       {

           SetDlgItemText(IDC_LOOKUP,"停止查看!" );

       }

       else

       {

           if( m_threadID )

           {

                PostThreadMessage(m_threadID,WM_CLOSE,0,0) ;

               SetDlgItemText(IDC_LOOKUP,"开始查看!");

              m_start.EnableWindow(FALSE) ;

           }

           return ;

       }

        DWORD dwBufferLen[10] ;

       DWORD dwBufferInLen= 1 ;

       DWORD dwBytesReturned = 0 ;

       m_s = socket( AF_INET , SOCK_RAW , IPPROTO_IP ) ;

       /*

         当调用WSAIoctl函数控制Socket模式的时候,有一些需要注意的事项。为了能够

          Socket接收网络上所有的IP包,传给WSAIoctl函数的Socket句柄必须设置成

          AF_INET地址族,SOCK_RAWSocket类型和IPPROTO_IP协议。而且这个Socket应该显式

          的绑定到本地的一个端口而不能是INADDR_ANY

       */

       if( INVALID_SOCKET == m_s )

       {

           dwErr = WSAGetLastError() ;

           sprintf( szErr , "Error socket() = %ld " , dwErr ) ;

           AfxMessageBox( szErr ) ;

           closesocket( m_s ) ;

           return ;

 

       }

       int rcvtimeo = 5000 ; //套接字超时选项

       //设置超时

        if( setsockopt( m_s , SOL_SOCKET , SO_RCVTIMEO , (const char *)&rcvtimeo ,

                        sizeof(rcvtimeo) ) == SOCKET_ERROR)

        /*  设置套接字选项

        int setsockopt(

            SOCKET s,                

            int level,  //Level at which the option is defined;

                        //the supported levels include SOL_SOCKET and IPPROTO_TCP             

            int optname, //Socket option for which the value is to be set            

            const char FAR *optval, //Pointer to the buffer in which the value

                                    //for the requested option is supplied. 

            int optlen  //Size of the optval buffer             

        );

        */

       {

           dwErr = WSAGetLastError() ;

           sprintf( szErr , "Error WSAIoctl = %ld " , dwErr ) ;

           AfxMessageBox( szErr ) ;

           closesocket( m_s ) ;

           return ;

       }

       sa.sin_family = AF_INET;

       sa.sin_port = htons(7000);

       //htons  converts a u_short from host to TCP/IP network byte order

       sa.sin_addr.s_addr= m_iphostsource;   //设置好一个SOCKADDR_IN

        if (bind(m_s,(PSOCKADDR)&sa, sizeof(sa)) == SOCKET_ERROR)

       {

           dwErr = WSAGetLastError() ;

           sprintf( szErr , "Error bind() = %ld " , dwErr ) ;

           AfxMessageBox( szErr ) ;

           closesocket( m_s ) ;

           return ;

       }

        if( SOCKET_ERROR != WSAIoctl( m_s, SIO_RCVALL , &dwBufferInLen, sizeof(dwBufferInLen),            

                                      &dwBufferLen, sizeof(dwBufferLen),

                                  &dwBytesReturned , NULL , NULL ) )

        /* controls the mode of a socket.控制socket模式

        //Enables a socket to receive all IP packets on the network

        //所选择的操作代码用于是socket接收所有网络信息

          int WSAIoctl(

              SOCKET s,

              DWORD dwIoControlCode,  //Control code of operation to perform.

              LPVOID lpvInBuffer,  //Pointer to the input buffer.

              DWORD cbInBuffer,    //Size of the input buffer.

              LPVOID lpvOutBuffer, //Pointer to the output buffer.

              DWORD cbOutBuffer,   //Size of the output buffer.

              LPDWORD lpcbBytesReturned, //Pointer to actual number of bytes of output

              LPWSAOVERLAPPED lpOverlapped, //Pointer to a WSAOVERLAPPED structure

              LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine

              //Pointer to the completion routine called when the operation has been completed

          );

        */

            AfxBeginThread( threadFunc , (LPVOID)this );

       else

       {

           dwErr = WSAGetLastError() ;

           sprintf( szErr , "Error WSAIoctl = %ld " , dwErr ) ;

           AfxMessageBox( szErr ) ;

           closesocket( m_s ) ;

            return ;

       }

}

 

UINT threadFunc ( LPVOID p )

{

    CIpmonDlg *pDlg = static_cast<CIpmonDlg *>(p) ;

    char  buf [1000] , *bufwork ;

    MSG   msg ;

    int   iRet ;

    DWORD dwErr ;

    char  *pSource , *pDest ;

    IPHEADER *pIpHeader ;

    in_addr ina ;

    char   szSource [16] , szDest[16] , szErr [ 50 ];

    char *pLastBuf = NULL ;

 

    int    HdrLen, totallen;

    WORD   sourport, destport;

 

    struct TCPPacketHead *pTCPHead;

    struct ICMPPacketHead    *pICMPHead;

    struct UDPPacketHead *pUDPHead;

    BYTE                 *pdata = NULL;

 

    /*---------------------------------------------------------------------*/

 

    PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE)  ; // Force to make the queue

    /*

      BOOL PeekMessage(

           LPMSG lpMsg,         // message information

           HWND hWnd,           // handle to window

           UINT wMsgFilterMin,  // first message

           UINT wMsgFilterMax,  // last message

           UINT wRemoveMsg      // removal options

      );

    */

    pDlg->m_threadID = GetCurrentThreadId() ;

   

    while( TRUE )

    {

        //检测队列中是否有WM_CLOSE消息

        if( PeekMessage( &msg , 0 , WM_CLOSE,WM_CLOSE,PM_NOREMOVE ) )

       {

            closesocket( pDlg->m_s ) ;

            pDlg->m_threadID = 0 ;

           pDlg->m_start.EnableWindow(TRUE) ;

           break ;

       }

       memset( buf , 0 , sizeof(buf) ) ;

       iRet =     recv( pDlg->m_s , buf , sizeof( buf ) , 0 ) ;//接收至buf

       if( iRet == SOCKET_ERROR )

       {

           dwErr = WSAGetLastError() ;

           sprintf( szErr , "Error recv() = %ld " , dwErr ) ;

           continue ;

       }

       else

           if( *buf )

           {  

              bufwork   = buf ;

               pIpHeader = (IPHEADER *)bufwork ; //强制转换为IPHEADER结构

                WORD iLen = ntohs(pIpHeader->total_len) ; //包的长度

                //The ntohs function converts a u_short

                //from TCP/IP network byte order to host byte order

              while( TRUE )

              {

                  if( iLen <= iRet ) //iRet为返回的包的长度

                  {

                         ina.S_un.S_addr = pIpHeader->sourceIP ; //开始设置in_addr

                             //SourceIP为源IP地址

                         pSource = inet_ntoa( ina ) ; //char  *pSource , *pDest ;

                         strcpy( szSource , pSource ) ;

                         //char   szSource [16] , szDest[16] , szErr [ 50 ];

                         ina.S_un.S_addr = pIpHeader->destIP ; //目的 IP地址

                         pDest = inet_ntoa( ina ) ;

                         strcpy( szDest , pDest ) ;

                         CString str, strProto, strSourPort, strDestPort, strData, strSize;

 

 

                         strProto = get_proto_name( pIpHeader->proto );

                        

                         /*-------------------zhuwei add(2002.11.9)-----------------------------*/

                         HdrLen = pIpHeader->header_len&0xf;

                         HdrLen *= 4;

                         totallen = ntohs(pIpHeader->total_len);

                         totallen-=HdrLen;

                         switch(pIpHeader->proto) //switch 各种协议

                         {

                         case IPPROTO_ICMP:

                            {

                                pICMPHead=(struct ICMPPacketHead *)(buf+HdrLen);

                                //strL4.Format(" type:%d code:%d/n",pICMPHead->Type,pICMPHead->Code);

                                strSourPort = "-";

                                strDestPort = "-";

                                pdata=((BYTE *)pICMPHead)+ICMP_HEAD_LEN;

                                totallen -= ICMP_HEAD_LEN;

                                break;

                            }

                         case IPPROTO_TCP:

                            {

                                pTCPHead=(struct TCPPacketHead *)(buf+HdrLen);

                                sourport = ntohs(pTCPHead->SourPort);

                                destport = ntohs(pTCPHead->DestPort);

                                //strL4.Format(" sour port:%d,dest port:%d",sourport,destport);

                                strSourPort.Format("%d",sourport);

                                strDestPort.Format("%d",destport);

                                HdrLen = (pTCPHead->HLen)>>4;  //in fact only 4 bits

                                HdrLen *= 4;

                                pdata=((BYTE *)pTCPHead)+HdrLen;

                                totallen -= HdrLen;

                                break;

                            }

                         case IPPROTO_UDP:

                            {

                                pUDPHead=(struct UDPPacketHead *)(buf+HdrLen);

                                sourport = ntohs(pUDPHead->SourPort);

                                destport = ntohs(pUDPHead->DestPort);

                                //strL4.Format(" sour port:%d,dest port:%d",sourport,destport);

                                strSourPort.Format("%d",sourport);

                                strDestPort.Format("%d",destport);

                                pdata=((BYTE *)pUDPHead)+UDP_HEAD_LEN;

                                totallen -= UDP_HEAD_LEN;

                                break;

                            }

                         }

 

                         if(pIpHeader->proto == IPPROTO_ICMP)

                            strData.Format("type:%d code:%d data:%s",pICMPHead->Type,pICMPHead->Code,pdata);

                         else strData.Format("  %s",pdata);

 

                         strSize.Format("%d",totallen);

                         pDlg->AddData(strProto,szSource,strSourPort,szDest,strDestPort,strSize,strData);

                    

                     if( iLen < iRet )

                     {

                         iRet -= iLen ;

                         bufwork  += iLen ;

                          pIpHeader = (IPHEADER *)bufwork ;

                     }

                     else

                         break ; // pIpHeader->total_len == iRet and go out

                  }

                  else

                  { // read last part of buf. I wrote it , but always recv() read exactly

                      // the lenght of the packet

                     int iLast = iLen - iRet ;

                     pLastBuf = new char [ iLen ] ;

                     int iReaden = iRet ;

                     memcpy( pLastBuf , bufwork , iReaden ) ;

                     iRet =     recv( pDlg->m_s , pLastBuf + iReaden , iLast , 0 ) ;

                     if( iRet == SOCKET_ERROR )

                     {

                         dwErr = WSAGetLastError() ;

                         sprintf( szErr , "Error recv() = %ld " , dwErr ) ;

                         break ;

                     }

                     else

                     {

                         bufwork = pLastBuf ;

                         pIpHeader = (IPHEADER *)bufwork ;

                         if( iRet == iLast )

                            iRet = iLen ;

                         else

                         { // read all last data

                            iReaden += iRet ;

                            iLast -= iRet ;

                            while( TRUE )

                            {

                                iRet = recv( pDlg->m_s , pLastBuf +iReaden , iLast , 0 ) ;

                                if( iRet == SOCKET_ERROR )

                                {

                                   dwErr = WSAGetLastError() ;

                                   sprintf( szErr , "Error recv() = %ld " , dwErr ) ;

                                   break ;

                                }

                                else

                                {

                                    iReaden += iRet ;

                                    iLast -= iRet ;

                                    if( iLast <= 0 )

                                       break ;

                                }  

                            } // while

                         }

                     }

                  }  

              }   // while

              if( pLastBuf )

                  delete [ ] pLastBuf ;

           }

           else

           {

              AfxMessageBox( "No data on network" ) ;

              continue ;

           }

    }

 

    return TRUE ;

}

 

void CIpmonDlg::OnOK()

{

    // TODO: Add extra validation here

    if( NULL != m_threadID )

        PostThreadMessage(m_threadID,WM_CLOSE,0,0) ;

    if( m_IPArr.GetSize() )

        m_IPArr.RemoveAll() ;

    CDialog::OnOK();

}

 

void CIpmonDlg::AddData(CString s0,CString s1, CString s2, CString s3, CString s4, CString s5, CString s6)

{

    int index;

 

    index = m_ctrList.InsertItem(0,s0);

    m_ctrList.SetItem(index,1,LVIF_TEXT,s1, 0, 0, 0,0);

    m_ctrList.SetItem(index,2,LVIF_TEXT,s2, 0, 0, 0,0);

    m_ctrList.SetItem(index,3,LVIF_TEXT,s3, 0, 0, 0,0);

    m_ctrList.SetItem(index,4,LVIF_TEXT,s4, 0, 0, 0,0);

    m_ctrList.SetItem(index,5,LVIF_TEXT,s5, 0, 0, 0,0);

    m_ctrList.SetItem(index,6,LVIF_TEXT,s6, 0, 0, 0,0);

}

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值