Winpcap笔记3之打开适配器并捕获数据包

上一讲中知道了如何获取适配的信息,这一将我们讲写一个程序蒋每一个通过适配器的数据包打印出来。

打开设备的函数是pcap_open().函数原型是

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

pcap_rmatauth

{

  int type.

char *username;;//Zero-terminated string containing the username that has to be used on the remote machine for authentication

char *password;

}

snaplen:snaplen 制定要捕获数据包中的哪些部分。 在一些操作系统中 (比如 xBSD 和 Win32), 驱动可以被配置成只捕获数据包的初始化部分: 这样可以减少应用程序间复制数据的量,从而提高捕获效率。本例中,我们将值定为65535,它比我们能遇到的最大的MTU还要大。因此,我们确信我们总能收到完整的数据包。

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

PCAP_OPENFLAG_PROMISCUOUS:1,它定义了适配器(网卡)是否进入混杂模式(promiscuous mode)。

    PCAP_OPENFLAG_DATATX_UDP:2,它定义了数据传输(假如是远程抓包)是否用UDP协议来处理。

PCAP_OPENFLAG_NOCAPTURE_RPCAP:4,它定义了远程探测器是否捕获它自己产生的数据包。

to_ms 指定读取数据的超时时间,以毫秒计(1s=1000ms)。在适配器上进行读取操作(比如用 pcap_dispatch()pcap_next_ex()) 都会在 to_ms 毫秒时间内响应,即使在网络上没有可用的数据包。 在统计模式下,to_ms 还可以用来定义统计的时间间隔。 将 to_ms 设置为0意味着没有超时,那么如果没有数据包到达的话,读操作将永远不会返回。 如果设置成-1,则情况恰好相反,无论有没有数据包到达,读操作都会立即返回。

read_timeout:以毫秒为单位。read timeout被用来设置在遇到一个数据包的时候读操作不必立即返回,而是等待一段时间,让更多的数据包到来后从OS内核一次读多个数据包。并非所有的平台都支持read timeout;在不支持read timeout的平台上它将被忽略。

auth:一个指向’struct pcap_rmtauth’的指针,保存当一个用户登录到某个远程机器上时的必要信息。假如不是远程抓包,该指针被设置为NULL。

errbuf:一个指向用户申请的缓冲区的指针,存放当该函数出错时的错误信息。

返回值是一个’pcap_t’指针,它可以作为下一步调用(例如pcap_compile()等)的参数,并且指定了一个已经打开的Winpcap会话。在遇到问题的情况下,它返回NULL并且’errbuf’变量保存了错误信息。

函数1:

int pcap_loop(  pcap_t*           p,

int                   cnt,

pcap_hander    callback,

u_char*           user

)

收集一群数据包。pcap_loop()与pcap_dispatch()类似,但是它会一直保持读数据包的操作直到cnt包被处理或者发生了错误。当有活动的读超时(read timeout)时它并不返回。然而,对pcap_open_live()指定一个非0的读超时(read timeout),当发生超时的时候调用pcap_dispatch()来接收并处理到来的所有数据包更好。Cnt指明了返回之前要处理数据包的最大数目。如果cnt为负值,pcap_loop()将一直循环(直到发生错误才停止)。如果出错时返回-1;如果cnt用完时返回0;如果在任何包被处理前调用pcap_breakloop()来中止循环将返回-2。所以,如果程序中使用了pcap_breakloop(),必须准确的来判断返回值是-1还是-2,而不能简单的判断<0。

函数2:

hypedef void (* pcap_handler)(u_char* user,

const struct pcap_pkthdr* pkt_header,

const u_char* pkt_data)

接收数据包的回调函数原型。当用户程序使用pcap_dispatch()或者pcap_loop(),数据包以这种回调的方法传给应用程序。用户参数是用户自己定义的包含捕获会话状态的参数,它必须跟pcap_dispatch()和pcap_loop()的参数相一致。pkt_hader是与抓包驱动有关的头。pkt_data指向包里的数据,包括协议头。

结构体1:

struct pcap_pkthdr {

struct timeval ts;

bpf_u_int32 caplen;

bpf_u_int32 len;

}

ts:时间戳

struct timeval {
        long    tv_sec;         /* seconds */
        long    tv_usec;        /* and microseconds */
};

cpalen:当前分组的长度

len:数据包的长度

/*
* 截获数据包的试验。先打印出所有网络适配器的列表,然后选择
* 想在哪个适配器上截获数据包。然后通过pcap_loop()函数将截获
* 的数据包传给回调函数packet_handler()处理。

* 通过该程序初步了解了使用winpcap截获数据包的步骤以及一些在
* 截获数据包时非常重要的函数和结构体。
*/

 1 //打开适配器捕获数据包
 2 #include "pcap.h"
 3
 4 /* packet handler 函数原型 */
 5 void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data);
 6
 7 int main()
 8 {
 9     pcap_if_t *alldevs;
10     pcap_if_t *d;
11     int inum;
12     int i = 0;
13     pcap_t *adhandle;
14     char errbuf[PCAP_ERRBUF_SIZE];
15
16     /* 获取本机设备列表 */
17     if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf) == -1)
18     {
19         fprintf(stderr, "Error in pcap_findalldevs: %s\n", errbuf);
20         exit(1);
21     }
22
23     /* 打印列表 */
24     for (d = alldevs; d; d = d->next)
25     {
26         printf("%d. %s", ++i, d->name);
27         if (d->description)
28             printf(" (%s)\n", d->description);
29         else
30             printf(" (No description available)\n");
31     }
32
33     if (i == 0)
34     {
35         printf("\nNo interfaces found! Make sure WinPcap is installed.\n");
36         return -1;
37     }
38
39     printf("Enter the interface number (1-%d):", i);
40     scanf("%d", &inum);
41
42     if (inum < 1 || inum > i)
43     {
44         printf("\nInterface number out of range.\n");
45         /* 释放设备列表 */
46         pcap_freealldevs(alldevs);
47         return -1;
48     }
49
50     /* 跳转到选中的适配器 */
51     for (d = alldevs, i = 0; i < inum - 1; d = d->next, i++);
52
53     /* 打开设备 */
54     if ((adhandle = pcap_open(d->name,          // 设备名
55         65536,            // 65535保证能捕获到不同数据链路层上的每个数据包的全部内容
56         PCAP_OPENFLAG_PROMISCUOUS,    // 混杂模式
57         1000,             // 读取超时时间
58         NULL,             // 远程机器验证
59         errbuf            // 错误缓冲池
60         )) == NULL)
61     {
62         fprintf(stderr, "\nUnable to open the adapter. %s is not supported by WinPcap\n", d->name);
63         /* 释放设备列表 */
64         pcap_freealldevs(alldevs);
65         return -1;
66     }
67
68     printf("\nlistening on %s...\n", d->description);
69
70     /* 释放设备列表 */
71     pcap_freealldevs(alldevs);
72
73     /* 开始捕获 */
74     pcap_loop(adhandle, 0, packet_handler, NULL);
75
76     return 0;
77 }
78
79
80 /* 每次捕获到数据包时,libpcap都会自动调用这个回调函数 */
81 void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data)
82 {
83     struct tm *ltime;
84     char timestr[16];
85     time_t local_tv_sec;
86
87     /* 将时间戳转换成可识别的格式 */
88     local_tv_sec = header->ts.tv_sec;
89     ltime = localtime(&local_tv_sec);
90     strftime(timestr, sizeof timestr, "%H:%M:%S", ltime);
91
92     printf("%s,%.6d len:%d\n", timestr, header->ts.tv_usec, header->len);
93
94 }

当适配器被打开,捕获工作就可以用 pcap_dispatch()pcap_loop()进行。 这两个函数非常的相似,区别就是 pcap_ dispatch() 当超时时间到了(timeout expires)就返回 (尽管不能保证) ,而 pcap_loop() 不会因此而返回,只有当 cnt 数据包被捕获,所以,pcap_loop()会在一小段时间内,阻塞网络的利用。pcap_loop()对于我们这个简单的范例来说,可以满足需求,不过, pcap_dispatch() 函数一般用于比较复杂的程序中。

这两个函数都有一个 回调 参数, packet_handler指向一个可以接收数据包的函数。 这个函数会在收到每个新的数据包并收到一个通用状态时被libpcap所调用 ( 与函数 pcap_loop()pcap_dispatch() 中的 user 参数相似),数据包的首部一般有一些诸如时间戳,数据包长度的信息,还有包含了协议首部的实际数据。 注意:冗余校验码CRC不再支持,因为帧到达适配器,并经过校验确认以后,适配器就会将CRC删除,与此同时,大部分适配器会直接丢弃CRC错误的数据包,所以,WinPcap没法捕获到它们。

上面的程序将每一个数据包的时间戳和长度从 pcap_pkthdr 的首部解析出来,并打印在屏幕上。

请注意,使用 pcap_loop() 函数可能会遇到障碍,主要因为它直接由数据包捕获驱动所调用。因此,用户程序是不能直接控制它的。另一个实现方法(也是提高可读性的方法),是使用 pcap_next_ex() 函数。有关这个函数的使用,我们将在下一讲为您展示。 (不用回调方法捕获数据包).

时间: 2024-10-12 13:37:33

Winpcap笔记3之打开适配器并捕获数据包的相关文章

winPcap_5_打开适配器并捕获数据包

知道如何获取适配器的信息了,那我们就开始一项更具意义的工作,打开适配器并捕获数据包.编写一个程序,将每一个通过适配器的数据包打印出来. 打开设备的函数是 pcap_open(). (Open a generic source in order to capture / send (WinPcap only) traffic.) pcap_t* pcap_open ( const char * source, int snaplen, int flags, int read_timeout, st

Winpcap笔记4之不用回调函数捕获数据包

函数1: pcap_next_ex(pcap_t*                       p, struct pcap_pkthdr**   pkt_header, const u_char*             pkt_data ) 从一个网络接口或离线捕获方式(例如读文件)读取一个数据包.该函数被用来重新获得下一个可用的数据包,没有使用libpcap提供的传统的回调方法.pcap_next_ex用指向头和下一个被捕获的数据包的指针为pkt_header和pkt_data参数赋值.

打开适配器并捕获数据包

得到适配器的具体信息就可以抓取信息了. 抓取信息之前应该介绍一个核心的函数:pcap_open_live() (在之前的版本用的是pcap_open()这个函数) pcap_t* pcap_open_live(char* device, int snaplen, int promisc, int to_ms, char* ebuf) 原文是这样描述的 pcap_t* pcap_open_live(char* device, int snaplen, int promisc, int to_ms,

winPcap_6_不用回调方法捕获数据包

用 pcap_next_ex() 函数代替 _5_ 中的 pcap_loop()函数: pcap_loop()函数是基于回调的原理来进行数据捕获,这是一种精妙的方法,并且在某些场合中,它是一种很好的选择. 然而,处理回调有时候并不实用 -- 它会增加程序的复杂度,特别是在拥有多线程的C++程序中. 可以通过直接调用pcap_next_ex() 函数来获得一个数据包 -- 只有当编程人员使用了 pcap_next_ex() 函数才能收到数据包. 这个函数的参数和捕获回调函数的参数是一样的 -- 它

转 Android智能手机上捕获数据包

如何在Android智能手机上捕获数据包? 本文由CSDN-蚍蜉撼青松[主页:http://blog.csdn.net/howeverpf]原创,转载请注明出处! 当前Android系统越来越流行,无论是对于安卓应用的开发人员,还是对于网络安全的研究人员,都有可能需要掌握捕获Android应用通信数据包的方法.根据技术手段不同,常用的抓包方法分两类,一类是通过Android智能移动终端所接入的上层网络设备或线路获取数据流,另一类则是直接在Android移动终端上监听数据流.本文主要探讨第二类方法

不用回调方法捕获数据包

这次将用 pcap_next_ex() 函数代替上一次的 pcap_loop()函数. pcap_loop()函数是基于回调的原理来进行数据捕获,这是一种精妙的方法,并且在某些场合中,它是一种很好的选择. 然而,处理回调有时候并不实用 -- 它会增加程序的复杂度,特别是在拥有多线程的C++程序中. 可以通过直接调用pcap_next_ex() 函数来获得一个数据包 -- 只有当编程人员使用了 pcap_next_ex() 函数才能收到数据包. 这个函数的参数和捕获回调函数的参数是一样的 -- 它

libnids TCP数据流重组,显示TCP连接过程的程序总无法捕获数据包解决办法:

法一: 指定可用网卡: nids_params.device="lo"; 法二: nids.h中有这么一段: struct nids_chksum_ctl { u_int netaddr; u_int mask; u_int action; u_int reserved; }; extern void nids_register_chksum_ctl(struct nids_chksum_ctl *,int); 这段是相关与计算校验和的,比较新的网卡驱动会自动计算校验和,我们要做的就是

了解捕获收据包的原程序

先调试Microsoft Visual Studio 2010 . 项目-->**属性(alt+F7)配置属性-->清单工具-->输入和输出-->嵌入清单-->否 项目-->**属性(alt+F7)配置属性-->C/C++-->常规-->附加包含目录--> 项目-->**属性(alt+F7)配置属性-->链接器-->常规-->附加库目录--> 项目-->**属性(alt+F7)配置属性-->链接器--&g

winpcap 发送数据包

第一:打开VS2010,创建一个新的项目,再对VS做一些设置.如下: 项目-->**属性(alt+F7)配置属性-->清单工具-->输入和输出-->嵌入清单-->否 项目-->**属性(alt+F7)配置属性-->C/C++-->常规-->附加包含目录--> 项目-->**属性(alt+F7)配置属性-->链接器-->常规-->附加库目录--> 项目-->**属性(alt+F7)配置属性-->链接器--&