版权信息:
本文来自internet,转载这里供网络编程爱好者学习和研究使用,请尊重作者的劳动成果。未经授权而在商业上使用原作者的文章属侵权行为,后果由使用者自负,本人不承担任何法律责任。
今天在阅读Winpcap Manual的时候发现一句话:
“This means that on shared media (like non-switched Ethernet), WinPcap will be able to capture the packets of other hosts.”
我理解为:如果在通过没有交换功能的集线器连接的网络上,只要把网卡设置为混杂(promiscuous)模式,winpcap能够捕获到其他主机通信的数据包。如果是具有交换功能的集线器连接的网络winpcap还能管用吗?这个在后边的实习中将会进行试验。
试验程序2:
/*
* 截获数据包的试验。先打印出所有网络适配器的列表,然后选择
* 想在哪个适配器上截获数据包。然后通过pcap_loop()函数将截获
* 的数据包传给回调函数packet_handler()处理。
* 通过该程序初步了解了使用winpcap截获数据包的步骤以及一些在
* 截获数据包时非常重要的函数和结构体。
* 2006-1-26
*/
#include <pcap.h>
#include <remote-ext.h>
/* Prototype of the 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];
/* Retrieve the devices list on the local machine */
if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf) == -1)
{
fprintf(stderr, "Error in pcap_findalldevs: %s/n", errbuf);
exit(1);
}
/* Print the list */
for (d = alldevs; d; d = d->next)
{
/* Print name */
printf("%d. %s", ++ i, d->name);
/* Print description */
if (d->description)
{
printf(" (%s)/n", d->description);
}
else
{
printf(" (No description available)/n");
}
}
if (i == 0)
{
printf("/nNo interfaces found! Make sure Winpcap is installed./n");
return -1;
}
/* Select an adapter */
printf("Enter the interface number (1 - %d):", i);
scanf("%d", &inum);
if (inum < 1 || inum > i)
{
printf("/nInterface number out of range./n");
/* Free the device list */
pcap_freealldevs(alldevs);
return -1;
}
/* Jump to the selected adapter */
for (d = alldevs, i = 0; i < inum - 1; d = d->next, ++ i);
/*Open the device */
if ((adhandle = pcap_open(d->name, /* name of the device */
65536, /* portion of the packet to capture */
/* 65535 guarantees that the whole packet will be captured on all the link layers */
PCAP_OPENFLAG_PROMISCUOUS, /* promiscuous mode */
1000, /* read timeout */
NULL, /* authentication on the remote machine */
errbuf /* error buffer */
)) == NULL)
{
fprintf(stderr, "/nnable to open the adapter. %s is not supported by Winpcap/n", d->name);
/* Free the devices list */
pcap_freealldevs(alldevs);
return -1;
}
printf("/nlistening on %s.../n", d->description);
/* At this point, we don’t need any more the device list. Free it */
pcap_freealldevs(alldevs);
/* start the capture */
pcap_loop(adhandle, 0, packet_handler, NULL);
return 1;
}
/* Callback function invoked by libpcap for every incoming packet */
void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data) {
struct tm *ltime;
char timestr[16];
/* convert the timestamp to readable format */
ltime = localtime(&header->ts.tv_sec);
strftime(timestr, sizeof(timestr), "%H:%M:%S", ltime);
printf("%s, %.6d len:%d/n", timestr, header->ts.tv_usec, header->len);
}
函数1:
pcap_t *pcap_open(const char * source,
int snaplen,
int flags, [Page]
int read_timeout,
struct pcap_rmtauth * auth,
char * errbuf
)
为捕获/发送数据打开一个普通的源。pcap_open()能够替代所有的pcap_open_xxx()函数,它隐藏了不同的pcap_open_xxx()之间的差异,所以程序员不必使用不同的open函数。
source:的是包含要打开的源名称的以’/0’结尾的字符串。源名称得包含新的源规范语法(Source Specification Syntax),并且它不能为NULL。为了方便的使用源语法,请记住:(1)pcap_findalldevs_ex()返回的适配器(网卡)可以直接被pcap_open()使用;(2)万一用户想传递他自己的源字符串给pcap_open(),pcap_createsrcstr()可以创建正确的源标识。
snaplen:需要保留的数据包的长度。对每一个过滤器接收到的数据包,第一个‘snaplen’字节的内容将被保存到缓冲区,并且传递给用户程序。例如,snaplen等于100,那么仅仅每一个数据包的第一个100字节的内容被保存。简言之就是从每一个包的开头到snaplen的那段内容将被保存。
flags:保存一些由于抓包需要的标志。Winpcap定义了三种标志:
l PCAP_OPENFLAG_PROMISCUOUS:1,它定义了适配器(网卡)是否进入混杂模式(promiscuous mode)。
l PCAP_OPENFLAG_DATATX_UDP:2,它定义了数据传输(假如是远程抓包)是否用UDP协议来处理。
l PCAP_OPENFLAG_NOCAPTURE_RPCAP:4,它定义了远程探测器是否捕获它自己产生的数据包。
read_timeout:以毫秒为单位。read timeout被用来设置在遇到一个数据包的时候读操作不必立即返回,而是等待一段时间,让更多的数据包到来后从OS内核一次读多个数据包。并非所有的平台都支持read timeout;在不支持read timeout的平台上它将被忽略。
auth:一个指向’struct pcap_rmtauth’的指针,保存当一个用户登录到某个远程机器上时的必要信息。假如不是远程抓包,该指针被设置为NULL。
errbuf:一个指向用户申请的缓冲区的指针,存放当该函数出错时的错误信息。
返回值是一个’pcap_t’指针,它可以作为下一步调用(例如pcap_compile()等)的参数,并且指定了一个已经打开的Winpcap会话。在遇到问题的情况下,它返回NULL并且’errbuf’变量保存了错误信息。
函数2:
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。
函数3:
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:时间戳
cpalen:当前分组的长度
len:数据包的长度
本篇文章来源于 中国协议分析网|www.cnpaf.net 原文链接:http://www.cnpaf.net/Class/winpcap/200610/16293.html