计算机网络课程设计--基于winpcap实现简单的抓包

来源:互联网 发布:java数组为空和为null 编辑:程序博客网 时间:2024/05/17 09:30

这篇博客主要记录如何通过winpcap实现网络抓包。首先我们简单介绍一下这次主要用到的函数:

pcap_t *pcap_open(const char *source, int snaplen, int flags, int read_timeout, struct pcap_rmtauth *auth, char *errbuf);
该方法打开一个网络适配器,三个参数的解释如下:

第一个参数:适配器名称,是数据的来源

第二个参数:制定要捕获数据包中的哪些部分。技术文档中介绍说,在一些操作系统中,驱动可以被配置成只捕获数据包的初始化部分,它的好处就是可以减少应用程序间

复制数量的量,从而提高捕获效率。下面将要给出的实例程序中设为65535。我们知道对于使用以太网的局域网来说,最大传输单元为1500字节,那么设为65535则能保证

收到完整的数据包。

第三个参数是最重要的一个值,它用来指示适配器是否需要设置成混杂模式,简单的说,就是所有流经这个网卡的数据都会被捕获,无论是不是发给这个网卡的,大多数捕获程序都会选择混杂模式,当然你也可以选择单一模式。

混杂模式:PCAP_OPENFLAG_PROMISCUOUS

第四个参数表示的是读取数据的超时时间,单位是毫秒。意思就是说会在read_timeout时间内对适配器的读取操作进行响应,不管有没有读到数据。这里有两个特殊的值需

要说明一下,如果将时间设置为0意味着没有超时,那么如果没有数据到达的话,读操作就永远不会返回;如果设置为-1则恰恰相反,不论有没有读到数据都会立即返回。

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

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

函数的返回值是一个pcap_t的指针类型,查看声明处我们可以发现pcap_t实际上是pcap结构体,而文档上说明它是一个已打开的捕捉实例的描述符。

代码:

#define HAVE_REMOTE#include <pcap.h>/* 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\n", errbuf);        exit(1);    }    /* 打印列表 */    for(d=alldevs; d; d=d->next)    {        printf("%d. %s", ++i, d->name);        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;    }    printf("Enter the interface number (1-%d):",i);    scanf("%d", &inum);    if(inum < 1 || inum > i)    {        printf("\nInterface number out of range.\n");        /* 释放设备列表 */        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,"\nUnable to open the adapter. %s is not supported by WinPcap\n", d->name);        /* 释放设备列表 */        pcap_freealldevs(alldevs);        return -1;    }    printf("\nlistening on %s...\n", d->description);    /* 释放设备列表 */    pcap_freealldevs(alldevs);    /* 开始捕获 */    pcap_loop(adhandle, 0, packet_handler, NULL);    return 0;}
pcap_loop函数API:

int pcap_loop  ( pcap_t *  p,    int  cnt,    pcap_handler  callback,    u_char *  user    ) 
这个函数就是用来捕获数据包的,而且是通过回调函数的方法进行捕获,第三个参数就是回调函数。

packet_handler:

/* 每次捕获到数据包时,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\n", timestr, header->ts.tv_usec, header->len);}
相当于把数据包里面的时间戳,长度显示出来。





0 0
原创粉丝点击