现在的位置: 首页 > 综合 > 正文

sniff嗅探器设计与实现

2013年08月10日 ⁄ 综合 ⁄ 共 8234字 ⁄ 字号 评论关闭

呵呵,很老得技术了, 不过自己这两天写了一个,大伙见笑了。

Sniff的实现主要分为三步:

1、将网卡设置为混杂模式

2、捕获IP数据包

3、分析IP数据包

以下是实现

///////////////////////////////////////////////////////////////////////////////////

       MySniff.h

///////////////////////////////////////////////////////////////////////////////////

#include <winsock2.h>
#include <iostream>
#include <string.h>
#include <ws2tcpip.h>
#include <mstcpip.h>

using namespace std;

class MySniff
{
public:
 MySniff(void);
 ~MySniff(void);
public:
 int InitSniff();  //监听初始化函数
 int ListenFunction(); //监听函数
 void ReleaseSocket(); // 释放Socket函数
 void IpAnalyse(char *buf);   //IP数据包分析函数
private:
 SOCKET m_socket;  //用于监听的socket
 WSADATA m_wsaData;  //用于初始化网络编程的变量
 HOSTENT* m_hostent;  //用于存放本机的IP地址列表
 struct sockaddr_in m_sockAddr; //用于监听的IP地址
};

/**************************************************************
 *数据类型:ProtoStruct
 *主要功能:定义了协议与协议名称得结构体,便于根据协议获得协议
 *   协议名称
 **************************************************************/
typedef struct _ProtoStruct
{
 int proto;  //协议标识
 string protoText; //协议名称
}ProtoStruct;

/**************************************************************
 *数据类型:IpHeader
 *主要功能:定义了对应于IP数据报报头的数据结构,当对接收的IP数
 *   据进行强制类型转换后,可以取出与之对应的数据
 **************************************************************/
typedef struct _IpHeader
{
 unsigned char verAndHeader_len; //版本及首部长度
 unsigned char serverType;   //数据报类型
 unsigned short totalLen;   //数据包大小
 unsigned short ident;    //数据报标识
 unsigned short flags;    //标志及片偏移
 unsigned char ttl;    //生存时间
 unsigned char proto;    //协议
 unsigned short checkSum;   //首部校验和
 unsigned int sourceIp;   //源地址
 unsigned int destIp;    //目的地址
}IpHeader;

/**************************************************************
 *数据类型:TcpHeader
 *主要功能:定义了对应于TIP数据报报头的数据结构,当对接收的TIP数
 *   据进行强制类型转换后,可以取出与之对应的数据
 **************************************************************/
typedef struct _TcpHeader
{
 unsigned short sourPort; //源端口
 unsigned short desPort;  //目的端口
 unsigned int   seqNo;  //序号
 unsigned int   askNo;  //确认号
 unsigned char  offset;  //数据偏移,数据起始处距离报文段起始处有多远
 unsigned char  controtBit; //控制比特位
 unsigned short wndSize;  //窗口大小,用于控制对方发送的数据量
 unsigned short chkSum;  //检验和
 unsigned short urgPtr;  //紧急指针
}TcpHeader;

/**************************************************************
 *数据类型:UdpHeader
 *主要功能:定义了对应于UDP数据报报头的数据结构,当对接收的UDP数
 *   据进行强制类型转换后,可以取出与之对应的数据
 **************************************************************/
typedef struct _UdpHeader
{
 unsigned short sourProt; //源端口
 unsigned short destPort;  //目的端口
 unsigned short len;   //UDP数据报长度
 unsigned chkSum;   //检验和
}UdpHeader;

/**************************************************************
 *数据类型:TcmpHeader
 *主要功能:定义了对应于TCMP数据报报头的数据结构,当对接收的
 *   TCMP数据进行强制类型转换后,可以取出与之对应的数据
 **************************************************************/
typedef struct _IcmpHeader
{
 unsigned char type;  //报文类型
 unsigned char code;  //代码
 unsigned short chkSum; //检验和
}IcmpHeader;

//定义UDP头部长度
#define UDP_HEAD_LEN 8
//定义ICMP头部长度
#define ICMP_HEAD_LEN 4

/*********************************End of File***************************************/

//////////////////////////////////////////////////////////////////////////////////////////

        MySniff.cpp

//////////////////////////////////////////////////////////////////////////////////////////

#include "MySinff.h"

ProtoStruct myProtos[12] =
{
 { IPPROTO_IP   , "IP" },
 { IPPROTO_ICMP , "ICMP" }, 
 { IPPROTO_IGMP , "IGMP" },
 { IPPROTO_GGP  , "GGP" }, 
 { IPPROTO_TCP  , "TCP" }, 
 { IPPROTO_PUP  , "PUP" }, 
 { IPPROTO_UDP  , "UDP" }, 
 { IPPROTO_IDP  , "IDP" }, 
 { IPPROTO_ND   , "NP"  }, 
 { IPPROTO_RAW  , "RAW" }, 
 { IPPROTO_MAX  , "MAX" },
 { NULL , "" }
};

string GetProto(int proto);

MySniff::MySniff(void)
{
}

MySniff::~MySniff(void)
{
}

/********************************************************************************
* 函数介绍:本函数用于完成监听初始化功能,主要包括注册DLL,初始化socket
* 输入参数:无
* 输出参数:无
* 返回值  :初始化成功标志,或初始化失败的错误类型
*********************************************************************************/
int MySniff::InitSniff()
{
 if(WSAStartup(MAKEWORD(2,2),&m_wsaData) == SOCKET_ERROR)
 {
  ReleaseSocket();
  return -1;
 }
 
 if((m_socket = socket(AF_INET, SOCK_RAW, IPPROTO_IP)) == SOCKET_ERROR)
 {
  ReleaseSocket();
  return -2;
 }

 int rcvTime = 5000;
 if(setsockopt(m_socket, SOL_SOCKET, SO_RCVTIMEO, (const char*)&rcvTime, sizeof(rcvTime)) == SOCKET_ERROR)
 {
  return -3;
 }

 char flag[256];
 setsockopt(m_socket, IPPROTO_IP, IP_HDRINCL, (char*)&flag, sizeof(flag));

 char localName[50];
 gethostname(localName, sizeof(localName));
 struct hostent *myHost;
 myHost = gethostbyname(localName);
 m_sockAddr.sin_family = AF_INET;
 m_sockAddr.sin_addr = *(in_addr *)myHost->h_addr_list[0];
 m_sockAddr.sin_port = htons(8080); 
 if(bind(m_socket, (struct sockaddr*)&m_sockAddr, sizeof(m_sockAddr)) == SOCKET_ERROR)
 {
  return -4;
 }

 unsigned long dwValue = 1;
 ioctlsocket(m_socket, SIO_RCVALL, &dwValue);
 return 0;
}

/*****************************************************
 *函数功能: 关闭用于监听的socket,释放socket资源
 *输入参数: 无
 *输出参数: 无
 *返回值:   无
 *****************************************************/
void MySniff::ReleaseSocket()
{
 shutdown(m_socket, SD_BOTH);
 closesocket(m_socket);
 WSACleanup();
}

/*****************************************************
 *函数功能: 监听函数,完成监听功能,即截获IP数据报并完成
    数据报类型分析,以及数据分析。
 *输入参数: 无
 *输出参数: 无
 *返回值:   是否成功,若失败返回失败原因
 *****************************************************/
int MySniff::ListenFunction()
{
 char buf[65535];
 IpHeader *ipHeader;    //存放IP数据包包头的结构变量
 
 in_addr ipAddr;     //地址类型的变量
 unsigned short headerLen, totalLen;  //数据包得报头长度和数据包总长度 

 unsigned short sourPort, destPort;
 string strSourIp, strDestIp;  //源IP地址,目的IP地址
 string strSourPort, strDestPort; //源端口地址,目的端口地址
 char *data;       //指向协议数据包数据的指针
 string strProto;     //协议名称
 int ret = 0;

 while(true)
 {
//  memset(buf, 0, 1024);
  totalLen = 0;
  ret = recv(m_socket, buf, sizeof(buf), 0);
  if(ret == SOCKET_ERROR)
  {
   continue;
  }
  char *workBuf = buf;
  ipHeader = (IpHeader *)workBuf;    //强制转换IP数据包头

  ipAddr.S_un.S_addr = ipHeader->sourceIp; //获取源IP地址
  strSourIp = inet_ntoa(ipAddr);    //将获取的源IP地址转化为字符串形式
  ipAddr.S_un.S_addr = ipHeader->destIp;  //获取目的IP地址
  strDestIp = inet_ntoa(ipAddr);    //将获取的目的IP地址转化为字符串形式
  
  unsigned char proto = ipHeader->proto;
  strProto = GetProto(proto);
       
  headerLen = ipHeader->verAndHeader_len&0xf;
  headerLen = headerLen * 4;
  totalLen = ntohs(ipHeader->totalLen);
  totalLen = totalLen - headerLen;
  switch(proto)
  {
  case IPPROTO_ICMP:
   {
    IcmpHeader *icmpHeader;   //存放ICMP协议数据包包头的结构变量
    icmpHeader = (IcmpHeader *)(workBuf + headerLen);
    strSourPort = "-";
    strDestPort = "-";
    char *nowData = ((char*)icmpHeader) + ICMP_HEAD_LEN; //将data指向ICMP数据包的数据部分
    totalLen -= ICMP_HEAD_LEN;   //得到ICMP数据包的数据部分的总长度
    data = new char[totalLen+1];
//    memcpy(data, nowData, totalLen);
    break;
   }
  case IPPROTO_TCP:
   {
    TcpHeader *tcpHeader;   //存放TCP协议数据包包头的结构变量
    tcpHeader = (TcpHeader *)(workBuf + headerLen);

    sourPort = ntohs(tcpHeader->sourPort);
    destPort = ntohs(tcpHeader->desPort);

    headerLen = ((tcpHeader->offset)>>4)&0xf;
    headerLen = headerLen * 4;
 
    char *nowData = ((char*)tcpHeader) + headerLen;
    totalLen -= headerLen;    //得到TCP数据包的数据部分的总长度
    data = new char[totalLen+1];
//    memcpy(data, nowData, totalLen);
    break;
   }
  case IPPROTO_UDP:
   {
    UdpHeader *udpHeader;   //存放UDP协议数据包包头的结构变量
    udpHeader = (UdpHeader *)(workBuf + headerLen);
    
    sourPort = ntohs(udpHeader->sourProt);
    destPort = ntohs(udpHeader->destPort);
 
    char *nowData = ((char*)udpHeader) + UDP_HEAD_LEN;
    totalLen -= UDP_HEAD_LEN;   //得到UDP数据包的数据部分的总长度   
    data = new char[totalLen+1];
//    memcpy(data, nowData, totalLen);
    break;
   }
  }//end switch;

  cout << strProto.c_str() << "/t" << strSourIp.c_str() << "/t" << strDestIp.c_str()
    << "/t" << sourPort << "/t" << destPort << "/t" << ret << "/t" <<totalLen << endl;
//  cout << data << endl;
 }
 return 0;
}

/*****************************************************
 *函数功能: 根据指定协议类型,获取协议名称
 *输入参数:
    int proto 协议类型
 *输出参数: 无
 *返回值:   协议对应的协议名称
 *****************************************************/
string GetProto(int proto)
{
 bool bFound = false ;
 for( int i = 0 ; i < 11 ; i++ )
 {
  if( myProtos[i].proto == proto )
  {
   bFound = true ;
   break ;
  } 
 }
 if( bFound )
  return myProtos[i].protoText ;
 return myProtos[11].protoText ;
}

/*********************************End of File***************************************/

 

///////////////////////////////////////////////////////////////////////////////////////////////

      Sniff.cpp

////////////////////////////////////////////////////////////////////////////////////////////////

#include "MySinff.h"
#include <windows.h>
#include <process.h>

int main()
{
 MySniff mySniff;
 if(mySniff.InitSniff() != 0)
 {
  cout << "init sniff error!" << endl;
 }
 else
 {
  mySniff.ListenFunction();
 }
 char ch;
 cin >> ch;
 return 0;
}

抱歉!评论已关闭.