打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
混杂模式下对网卡IP包的抓取

代码段中TRACE是调试的时候使用的删掉对代码没有影响,只是在写代码过程中方便查看结果和调试。首先填充的是SOCKADDR_IN结构体,该结构体包换了IP地址、端口号、地址簇等信息。都要进行填充。同时要注意的网络字节和本机字节的转换。使用WSASocket创建套接字,

 SOCKET WSAAPI WSASocket ( int af, int type, int protocol,LPPROTOCOL_INFO lpProtocolInfo, Group g, int iFlags);

  af:地址族描述。目前仅支持AF_INET格式,亦即ARPA Internet地址格式。

  type:新套接口的类型描述。

  protocol:套接口使用的特定协议,如果调用者不愿指定协议则定为0。

  lpProtocolInfo:一个指向PROTOCOL_INFO结构的指针,该结构定义所创建套接口的特性。如果本参数非零,则前三个参数(af, type, protocol)被忽略。

  g:套接口组的描述字。

iFlags:套接口属性描述。

通过使用setsockopt()设置时候亲自对IP头进行处理。

int PASCAL FAR setsockopt( SOCKET s, int level, intoptname,const char FAR *optval, int optlen);

  s:标识一个套接口的描述字。

  level:选项定义的层次;目前仅支持SOL_SOCKET和IPPROTO_TCP层次。

  optname:需设置的选项。

  optval:指针,指向存放选项值的缓冲区

optlen:optval缓冲区长度。

使用Bind将套接字和ip、端口绑定到一起

   设置网卡为混杂模式,可以使用SWAIoctl()函数。

在无限循环中,使用recv接收数据,recv(Sniffsock,buff,sizeof(buf),0);

将buf转化为转化为ip结构,然后对ip结构中数据处理,使用sprintf_s()对数据进行格式化,转化成char*,然后使用CListCtrl的SetItemText将数据打印上相应的子项目中。 

运行结果:


网络环境的初始化:

首先,第一点就是对网络环境的初始化。在MFC中一般是在程序初始化中InitInstance中进行的。

在头文件包含#include #pragmacommemt(lib,”ws2_32.lib”);必要的时候还要包含#include

在InitInstance()中调用

WORD wVersionRequested;

    WSADATA wsaDate;

    int err;

    wVersionRequested=MAKEWORD(2,2);

    err=WSAStartup(wVersionRequested,&wsaDate);

    if (err!=0)

    {

        return FALSE;

    }

    if (LOBYTE(wVersionRequested)!=2||HIBYTE(wVersionRequested)!=2)

    {

        WSACleanup();

        return FALSE;

    }

LOBYTE和HTBYTE宏对DWORD进行操作取得器版本号信息,MAKEWORD()可知道将两个BYTE合并成一个WORD

注意不要要忘了在退出时重载ExitInstance调用WSACleanup();关闭。

一旦一个应用程序或者DLL调用WSAStartup成功,他可以执行其他需要的WindowsSockets 调用,当要结束使用Winsock.dll服务,必须调用WSACleanup来释放应用程序使用Winsock.dll的资源。 

 

2第一步中基本完成了对网络环境的初始化,然后对界面进行初始化,程序是个对话框程序,在程序中OnInitDialog()中对程序的界面初始化,Dialog中包含一个CListCtrl、一个IPAddressCtrl、两个button按钮的简单界面。同时将获取本机IP也在此初始化。

char name[255];

    char* ip;

    m_bCheckStatus=false;//用来确定是否终止截包

    m_HostIP=(CIPAddressCtrl*)GetDlgItem(IDC_HOSTIP);//创建ip控件对象

    m_List=(CListCtrl*)GetDlgItem(IDC_LIST1);//创建列表框对象

    //取得本地主机名和本地ip

    if(gethostname(name,sizeof(name))==0)

    {

        if ((pHostEnt=gethostbyname(name))!=NULL)

        {

             ip=inet_ntoa(*(in_addr*)pHostEnt->h_addr_list[0]);

        }

    }

    //将ip设置在ip控件上

    m_HostIP->SetWindowText((LPCTSTR)ip);

    //初始化列表框

    m_List->SetExtendedStyle(LVS_EX_GRIDLINES|LVS_EX_FULLROWSELECT|LVS_EX_ONECLICKACTIVATE);

    m_List->InsertColumn(0,"目标IP",LVCFMT_LEFT,120);

    m_List->InsertColumn(1,"数据包长度",LVCFMT_LEFT,80);

    m_List->InsertColumn(2,"IP校验和",LVCFMT_LEFT,80);

    m_List->InsertColumn(3,"正确",LVCFMT_LEFT,40);

使用GetDlgItem()获得ID的对象指针(注意转化类型)。

取得本地ip,gethostname取得本机名,然后通过gethostbyname根据本机名取得IP。并且保存在HOSTENT(hostentry)的结构体中。

struct hostent

{

  char *h_name;//地址的正式名字

  char **h_aliases; //空字节,地址的预备名的指针

  int h_addrtype; //地址类型,一般为AF_INET

  int h_length; //地址的比特长度

  char **h_addr_list;//主机的网络地址指针,注意这是网络字节序通过inet_ntoa()转化成ascii字节序,返回char*;

  };

#define h_addr h_addr_list[0]

通过CIPAdressCtrl的setwindowtext()将char*字符串设置到IP控件中。

CListCtrl的成员函数声明

  DWORD SetExtendedStyle(DWORD dwNewStyle );  

使用InsertColumn()创建行用InsertItem();创建列,setitemtext()设置子项文本,界面初始化完毕。 

 

3.实现按钮的拦截包功能

需要设置一个线程专门进行拦截包处理,因为如果主线程进行拦截包的话会是界面无法响应,因为主线程阻塞。但是要考虑到的是将线程函数设置为静态函数或者全局函数,因为如果你把线程处理函数设置成成员函数的话,会隐含的传入this参数,会使编译器报错。可是屏蔽了this指针问题又来了。线程函数里面要处理和使用对话框对象的成员数据和成员函数。我们可以知道线程函数可以传入一个LPVOID参数,所以将this指针作为参数传给线程函数,这样就两个问题都解决了。同时为了简单的思想线程的启动和关闭,使用了一个bool类型的变量,根据变量来控制线程的启动和停止。代码如下: 

void CIPTestDlg::OnBnClickedGetpackage()

   //TODO: 在此添加控件通知处理程序代码   

     m_bCheckStatus=true;

     AfxBeginThread(CIPTestDlg::ThreadProc,this);

UINT CIPTestDlg::ThreadProc(LPVOID pParam)

  

     CIPTestDlg* pDlg=(CIPTestDlg*)pParam;//ThreadProc设置成静态函数,无this指针,通过线程参数传入   

     int i=0;//表示列表的行数

     SOCKADDR_IN addr_in;//填充SOCKADDR_IN结构体

     addr_in.sin_addr=*(in_addr*)(pDlg->pHostEnt)->h_addr_list[0];

     addr_in.sin_family=AF_INET;

     addr_in.sin_port=htons(9999);

     BOOL flag=TRUE; 

     SOCKET SinfferSock=WSASocket(AF_INET,SOCK_RAW,IPPROTO_IP,NULL,0,WSA_FLAG_OVERLAPPED);//创建套接字

     setsockopt(SinfferSock,IPPROTO_IP,IP_HDRINCL,(char*)&flag,sizeof(flag));//设置sock选项使其可以设置

     bind(SinfferSock,(sockaddr*)&addr_in,sizeof(addr_in));//绑定套接字

     //设置网卡为混杂模式

     DWORD dwBufferLen[10];

     DWORD dwBufferInLen=1;

     DWORD dwBytesReturned=0;

WSAIoctl(SinfferSock,SIO_RCVALL,&dwBufferInLen,sizeof(dwBufferInLen),&dwBufferLen,sizeof(dwBufferLen),&dwBytesReturned,NULL,NULL);

     //接收数据

     char buf[102400];

     int len =0;

     do

     {

         if (pDlg->m_bCheckStatus==false)

         {

              closesocket(SinfferSock);

              break;

         }

         len recv(SinfferSock, buf, sizeof(buf),0);       

         if( len >0 )

         {

              IP ip;

              ip=*(IP*)buf;

              TRACE("IP源地址:%s\r\n",inet_ntoa(*(in_addr*)&ip.SrcAddr));

              TRACE("IP目标地址:%s\r\n",inet_ntoa(*(in_addr*)&ip.DstAddr));

              TRACE("数据包长度:%d\r\n\r\n\r\n",ntohs(ip.TotalLen));

 

              char* DesIP=inet_ntoa(*(in_addr*)&ip.DstAddr);

              //将int数值类型通过sprintf转化为字符串类型

              u_short usize=ntohs(ip.TotalLen);

              char csize[255]={0};

              sprintf_s(csize,255,"%d",usize);          

              char cipsize[255]={0};

              unsigned int len=checksum(sizeof(IP),(u_short*)&ip);//调用ip校验函数

              sprintf_s(cipsize,255,"%d",len);        

              //在CListCtrl中设置相应数据

              (pDlg->m_List)->InsertItem(i,(LPCTSTR)DesIP);//设置目标IP

              (pDlg->m_List)->SetItemText(i,1,(LPCTSTR)csize);//设置相应目标IP的数据包大小

              (pDlg->m_List)->SetItemText(i,2,(LPCTSTR)cipsize);//设置相应目标IP的ip校验值

              i++;

         }

     }while( len >0 );

     return 0;

 

代码段中TRACE是调试的时候使用的删掉对代码没有影响,只是在写代码过程中方便查看结果和调试。首先填充的是SOCKADDR_IN结构体,该结构体包换了IP地址、端口号、地址簇等信息。都要进行填充。同时要注意的网络字节和本机字节的转换。使用WSASocket创建套接字,

 SOCKET WSAAPI WSASocket ( int af, int type, int protocol,LPPROTOCOL_INFO lpProtocolInfo, Group g, int iFlags);

  af:地址族描述。目前仅支持AF_INET格式,亦即ARPA Internet地址格式。

  type:新套接口的类型描述。

  protocol:套接口使用的特定协议,如果调用者不愿指定协议则定为0。

  lpProtocolInfo:一个指向PROTOCOL_INFO结构的指针,该结构定义所创建套接口的特性。如果本参数非零,则前三个参数(af, type, protocol)被忽略。

  g:套接口组的描述字。

iFlags:套接口属性描述。

通过使用setsockopt()设置时候亲自对IP头进行处理。

int PASCAL FAR setsockopt( SOCKET s, int level, intoptname,const char FAR *optval, int optlen);

  s:标识一个套接口的描述字。

  level:选项定义的层次;目前仅支持SOL_SOCKET和IPPROTO_TCP层次。

  optname:需设置的选项。

  optval:指针,指向存放选项值的缓冲区

optlen:optval缓冲区长度。

使用Bind将套接字和ip、端口绑定到一起

   设置网卡为混杂模式,可以使用SWAIoctl()函数。

在无限循环中,使用recv接收数据,recv(Sniffsock,buff,sizeof(buf),0);

将buf转化为转化为ip结构,然后对ip结构中数据处理,使用sprintf_s()对数据进行格式化,转化成char*,然后使用CListCtrl的SetItemText将数据打印上相应的子项目中。 

运行结果:


 


本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
C语言安全文件传输程序设计。
Linux c 获取网络接口IP地址
基本UDP套接口编程 - fanqiang.com
本地网络编程
Windows API 教程(九) 网络编程
Linux编程常用的函数(八) 网络编程
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服