首页 > 打开适配器并捕获数据包

打开适配器并捕获数据包

      由前两节的铺垫,我们已经知道如何获取本地适配器的信息了,接下来我们来学习一下如何打开适配器并捕获数据包,听起来相当诱惑,那么咱们立刻进入主题吧!在贴源码之前先介绍一个将要用到的很重要的函数--pcap_open(),下面是pcap_open()在remote-ex.h中的声明:

pcap_t *pcap_open(const char *source, int snaplen, int flags, int read_timeout, struct pcap_rmtauth *auth, char *errbuf);

      第一个参数不用多说,它表示的是设备的名称。在获取适配器链表后,通过返回数据域name即可知道设备的名称。

      第二个参数制定要捕获数据包中的哪些部分。技术文档中介绍说,在一些操作系统中,驱动可以被配置成只捕获数据包的初始化部分,它的好处就是可以减少应用程序间复制数量的量,从而提高捕获效率。下面将要给出的实例程序中设为65535。我们知道对于使用以太网的局域网来说,最大传输单元为1500字节,那么设为65535则能保证收到完整的数据包。

      第三个参数是最重要的一个值,它用来指示适配器是否需要设置成混杂模式,这里引用一下技术文档中对设置混杂模式的说明:

一般情况下,适配器只接收发给它自己的数据包, 而那些在其他机器之间通讯的数据包,将会被丢弃。 相反,如果适配器是混杂模式,那么不管这个数据包是不是发给我的,我都会去捕获。也就是说,我会去捕获所有的数据包。 这意味着在一个共享媒介(比如总线型以太网),WinPcap能捕获其他主机的所有的数据包。 大多数用于数据捕获的应用程序都会将适配器设置成混杂模式,所以,我们也会在下面的范例中,使用混杂模式。

      它的意思就是说设置混杂模式可以捕获到所有经过适配器的数据包,不论是不是发给机器本身的。PCAP_OPENFLAG_PROMISCUOUS这个值就是设置成混杂模式的意思。

      第四个参数表示的是读取数据的超时时间,单位是毫秒。意思就是说会在read_timeout时间内对适配器的读取操作进行响应,不管有没有读到数据。这里有两个特殊的值需要说明一下,如果将时间设置为0意味着没有超时,那么如果没有数据到达的话,读操作就永远不会返回;如果设置为-1则恰恰相反,不论有没有读到数据都会立即返回。

      第五个参数之前提到过,它表示的是连接远程用户的验证信息,由于我们不需要连接到远程用户,这里置为NULL。

      第六个参数是错误信息缓冲,如果该函数在调用过程中出错则会将出错信息保存在缓冲中。

      函数的返回值是一个pcap_t的指针类型,查看声明处我们可以发现pcap_t实际上是pcap结构体,而文档上说明它是一个已打开的捕捉实例的描述符。这个结构体对用户来说是不透明的(我们查看pcap的声明处是找不到的),它通过wpcap.dll提供的函数,维护了它的内容。

      下面我们来看一下这个程序的代码!

#define HAVE_REMOTE

#include



/* packet handler 函数原型 */

void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data);



int main()

{

pcap_if_t *alldevs;

pcap_if_t *d;

int inum;

int i=0;

pcap_t *adhandle;

char errbuf[PCAP_ERRBUF_SIZE];



/* 获取本机设备列表 */

if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf) == -1)

{

fprintf(stderr,"Error in pcap_findalldevs: %s ", errbuf);

exit(1);

}



/* 打印列表 */

for(d=alldevs; d; d=d->next)

{

printf("%d. %s", ++i, d->name);

if (d->description)

printf(" (%s) ", d->description);

else

printf(" (No description available) ");

}



if(i==0)

{

printf(" No interfaces found! Make sure WinPcap is installed. ");

return -1;

}



printf("Enter the interface number (1-%d):",i);

scanf("%d", &inum);



if(inum < 1 || inum > i)

{

printf(" Interface number out of range. ");

/* 释放设备列表 */

pcap_freealldevs(alldevs);

return -1;

}



/* 跳转到选中的适配器 */

for(d=alldevs, i=0; i< inum-1 ; d=d->next, i++);



/* 打开设备 */

if ( (adhandle= pcap_open(d->name, // 设备名

65535, // 65535保证能捕获到不同数据链路层上的每个数据包的全部内容

PCAP_OPENFLAG_PROMISCUOUS, // 混杂模式

1000, // 读取超时时间

NULL, // 远程机器验证

errbuf // 错误缓冲池

) ) == NULL)

{

fprintf(stderr," Unable to open the adapter. %s is not supported by WinPcap ", d->name);

/* 释放设备列表 */

pcap_freealldevs(alldevs);

return -1;

}



printf(" listening on %s... ", d->description);



/* 释放设备列表 */

pcap_freealldevs(alldevs);



/* 开始捕获 */

pcap_loop(adhandle, 0, packet_handler, NULL);



return 0;

}





/* 每次捕获到数据包时,libpcap都会自动调用这个回调函数 */

void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data)

{

struct tm *ltime;

char timestr[16];

time_t local_tv_sec;



/* 将时间戳转换成可识别的格式 */

local_tv_sec = header->ts.tv_sec;

ltime=localtime(&local_tv_sec);

strftime( timestr, sizeof timestr, "%H:%M:%S", ltime);



printf("%s,%.6ld len:%d ", timestr, header->ts.tv_usec, header->len);



}

      打开设备后我们就可以进行捕获了,这里我们用到的函数是pcap_loop(),下面是pcap_loop()函数的声明:

int pcap_loop  ( pcap_t *  p,  

int cnt,

pcap_handler callback,

u_char * user

)

      引用一下文档里面对于pcap_loop()函数的介绍:

Collect a group of packets.

pcap_loop() is similar to pcap_dispatch() except it keeps reading packets until cnt packets are processed or an error occurs. It does not return when live read timeouts occur. Rather, specifying a non-zero read timeout to pcap_open_live() and then calling pcap_dispatch() allows the reception and processing of any packets that arrive when the timeout occurs. A negative cnt causes pcap_loop() to loop forever (or at least until an error occurs). -1 is returned on an error; 0 is returned if cnt is exhausted; -2 is returned if the loop terminated due to a call to pcap_breakloop() before any packets were processed. If your application uses pcap_breakloop(), make sure that you explicitly check for -1 and -2, rather than just checking for a return value < 0.

      大致就是说pcap_loop()函数是用来捕获一组数据分组的。pcap_loop()函数跟pcap_dispath()函数很类似,唯一不同之处就是pcap_loop()会一直读数据直到cnt数据被处理或者出现错误。不论读取时间是否超时它都不返回。当然有一种特殊情况,就是在调用pcap_open_live()函数时指定非0的读取超时时间,调用pcap_dispath()函数可以在超时发生时对读到的数据进行接收和处理。将cnt设为正数可以使pcap_loop()一直循环(或至少到错误发生之前)。返回-1则出错;返回0则说明cnt被耗尽;返回-2则是由于在数据被处理之前调用pcap_breakloop()来中断循环。如果你的应用程序使用了pcap_breakloop()函数,你需要对返回值-1和-2进行详细的检查,而不是只检查<0的情况。(如果翻译有误还请指正!!!)

      文档里说得很详细,看得也是一头雾水,也不知道究竟在说些什么。简单来讲就是说,pcap_loop()只有当cnt数据包被捕获时才会返回,即它会在一小段时间内阻塞网络的利用。pcap_loop()函数的第三个参数很重要,它是一个回调函数的函数指针,即pcap_loop()函数返回时会自动调用这个回调函数。这个回调函数的参数类型是规定好的:

typedef void (*pcap_handler)(u_char *, const struct pcap_pkthdr *,

const u_char *);

      这个程序当中我们只用到了第二个参数,将每一个数据包的时间戳和长度从它的首部当中解析出来,并打印在屏幕上。细节的东西就不赘述了,看一下运行的结果:

      输入1并按回车,开始捕获数据并打印:

转载于:https://www.cnblogs.com/blacksword/archive/2012/03/10/2389153.html

更多相关:

  • 为了开发需要,我决定使用最新libpcap源码包安装。在Unix环境下安装libpcap库,需要 c编译器,flex,bison等,安装Ubuntu系统时,没有这些包。安装flex需要m4编译环境,否则会提示“GNU M4 is required”错误。 1.安装系统依赖包 sudo apt-get install gc...

  • 本文是西门子开放式TCP通信的第2篇,上一篇我们讲了使用西门子1200PLC作为TCP服务器的程序编写,可以点击下方链接阅读:【公众号dotNet工控上位机:thinger_swj】基于Socket访问西门子PLC系列教程(一)在完成上述步骤后,接下来就是编写上位机软件与PLC之间进行通信。上位机UI界面设计如下图所示:从上图可以看出...

  • 我有一个大型数据集,列出了在全国不同地区销售的竞争对手产品。我希望通过使用这些新数据帧名称中的列值的迭代过程,根据区域将该数据帧分成几个其他区域,以便我可以分别处理每个数据帧-例如根据价格对每个地区的信息进行排序,以了解每个地区的市场情况。我给出了以下数据的简化版本:Competitor Region ProductA Product...

  • 作为一名IT从业者,我来回答一下这个问题。首先,对于具有Java编程基础的人来说,学习Python的初期并不会遇到太大的障碍,但是要结合自己的发展规划来制定学习规划,尤其要重视学习方向的选择。Java与Python都是比较典型的全场景编程语言,相比于Java语言来说,当前Python语言在大数据、人工智能领域的应用更为广泛一些,而且大...

  • 这段时间通过学习相关的知识,最大的变化就是看待事物更加喜欢去了解事物后面的本质,碰到问题后解决问题思路也发生了改变。举个具体的例子,我在学习数据分析,将来会考虑从事这方面的工作,需要掌握的相关专业知识这个问题暂且按下不表,那哪些具体的问题是我需要了解的呢,以下简单罗列:1、了解数据分析师这个岗位在各个地区的需求情况?2、数据分析师的薪...

  • 这一节将开始学习python的一个核心数据分析支持库---pandas,它是python数据分析实践与实战的必备高级工具。对于使用 Python 进行数据分析来说,pandas 几乎是无人不知,无人不晓的。今天,我们就来认识认识数据分析界鼎鼎大名的 pandas。目录一. pandas主要数据结构 SeriesDataFrame二...

  • 草色新雨中, 松声晚窗里。之前我们学习 Power Query 都是用鼠标就完成了很多复杂的操作。虽然 PowerQuery 已经将大部分常用功能内置成到功能区。基本能完成我们大部分的报表自动化功能。但是总有些复杂的或者个性化的问题是开发团队没有预先想到的,这时我们就需要学习 M 语言。一、M 语言在哪里?M语言的函数公式有三个地...

  • 前言从2020年3月份开始,计划写一系列文档--《小白从零开始学编程》,记录自己从0开始学习的一些东西。第一个系列:python,计划从安装、环境搭建、基本语法、到利用Django和Flask两个当前最热的web框架完成一个小的项目第二个系列:可能会选择Go语言,也可能会选择Vue.js。具体情况待定,拭目以待吧。。。基本概念表达式表...

  • 1.1函数1.1.1什么是函数函数就是程序实现模块化的基本单元,一般实现某一功能的集合。函数名:就相当于是程序代码集合的名称参数:就是函数运算时需要参与运算的值被称作为参数函数体:程序的某个功能,进行一系列的逻辑运算return 返回值:函数的返回值能表示函数的运行结果或运行状态。1.1.2函数的作用函数是组织好的,可重复使用的,用来...

  • 原标题:基于Python建立深度神经网络!你学会了嘛?图1 神经网络构造的例子(符号说明:上标[l]表示与第l层;上标(i)表示第i个例子;下标i表示矢量第i项)单层神经网络图2 单层神经网络示例神经元模型是先计算一个线性函数(z=Wx+b),接着再计算一个激活函数。一般来说,神经元模型的输出值是a=g(Wx+b),其中g是激活函数(...

  • 在学习MySQL的时候你会发现,它有非常多的函数,在学习的时候没有侧重。小编刚开始学习的时候也会有这个感觉。不过,经过一段时间的学习之后,小编发现尽管函数有很多,但是常用的却只有那几个。今天小编就把常用的函数汇总一下,为大家能够能好的学习MySQL中的函数。MySQL常使用的函数大概有四类。时间函数、数学函数、字符函数、控制函数。让我...